set sv_jumpspeedcap_min "" "lower bound on the baseline velocity of a jump; final velocity will be >= (jumpheight * min + jumpheight)"
set sv_jumpspeedcap_max "" "upper bound on the baseline velocity of a jump; final velocity will be <= (jumpheight * max + jumpheight)"
set sv_jumpspeedcap_max_disable_on_ramps 0 "disable upper baseline velocity bound on ramps to preserve the old rampjump style"
+set sv_track_canjump 0 "track if the player released the jump key between 2 jumps to decide if they are able to jump or not"
seta sv_precacheplayermodels 1
seta sv_precacheweapons 0
set g_physics_xonotic_stopspeed 100
set g_physics_xonotic_airaccelerate 2
set g_physics_xonotic_airstopaccelerate 3
+set g_physics_xonotic_track_canjump 0
// ========
// Nexuiz
set g_physics_nexuiz_stopspeed 100
set g_physics_nexuiz_airaccelerate 5.5
set g_physics_nexuiz_airstopaccelerate 0
+set g_physics_nexuiz_track_canjump 0
// =======
// Quake
set g_physics_quake_stopspeed 100
set g_physics_quake_airaccelerate 106.66666666666666666666
set g_physics_quake_airstopaccelerate 0
+set g_physics_quake_track_canjump 1
// ========
// Warsow
set g_physics_warsow_stopspeed 100
set g_physics_warsow_airaccelerate 1
set g_physics_warsow_airstopaccelerate 2.5
+set g_physics_warsow_track_canjump 0
// ========
// DeFrag
set g_physics_defrag_stopspeed 100
set g_physics_defrag_airaccelerate 1
set g_physics_defrag_airstopaccelerate 2.5
+set g_physics_defrag_track_canjump 0
// =========
// Quake 3
set g_physics_quake3_stopspeed 100
set g_physics_quake3_airaccelerate 1
set g_physics_quake3_airstopaccelerate 0
+set g_physics_quake3_track_canjump 1
// ========
// Vecxis
set g_physics_vecxis_stopspeed 100
set g_physics_vecxis_airaccelerate 5.5
set g_physics_vecxis_airstopaccelerate 0
+set g_physics_vecxis_track_canjump 0
// =========
// Quake 2
set g_physics_quake2_stopspeed 100
set g_physics_quake2_airaccelerate 1
set g_physics_quake2_airstopaccelerate 0
+set g_physics_quake2_track_canjump 1
// =======
// Bones
set g_physics_bones_stopspeed 100
set g_physics_bones_airaccelerate 1
set g_physics_bones_airstopaccelerate 2.5
+set g_physics_bones_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 400
+sv_track_canjump 0
sv_jumpspeedcap_max 0.35
sv_jumpspeedcap_max_disable_on_ramps 1
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 1
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 1
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max 0.38
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 1
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 320
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
sv_jumpspeedcap_max ""
sv_jumpspeedcap_max_disable_on_ramps 0
g_teleport_maxspeed 0
+sv_track_canjump 0
--- /dev/null
+# Doxyfile 1.8.10
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "Xonotic"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = YES
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = YES
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING = qc=C qh=C inc=C
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = YES
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd,
+# *.vhdl, *.ucf, *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.qc *.qh *.inc
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS = _
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = YES
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 2
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = svg
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = YES
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 500
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
$(RM) qccversion.*
echo This file intentionally left blank. > $@
-FILES_CSPROGS = $(shell find client lib common warpzonelib csqcmodellib -type f -not -name fteqcc.log -not -name qc.asm)
+FILES_CSPROGS = $(shell find lib common client -type f)
../csprogs.dat: $(FILES_CSPROGS) $(QCCVERSIONFILE)
@echo make[1]: Entering directory \`$(PWD)/client\'
cd client && $(QCC) $(QCCFLAGS) -DCSQC
-FILES_PROGS = $(shell find server lib common warpzonelib csqcmodellib -type f -not -name fteqcc.log -not -name qc.asm)
+FILES_PROGS = $(shell find lib common server -type f)
../progs.dat: $(FILES_PROGS) $(QCCVERSIONFILE)
@echo make[1]: Entering directory \`$(PWD)/server\'
cd server && $(QCC) $(QCCFLAGS) -DSVQC
-FILES_MENU = $(shell find menu lib common warpzonelib -type f -not -name fteqcc.log -not -name qc.asm)
+FILES_MENU = $(shell find lib common menu -type f)
../menu.dat: $(FILES_MENU) $(QCCVERSIONFILE)
@echo make[1]: Entering directory \`$(PWD)/menu\'
cd menu && $(QCC) $(QCCFLAGS) -DMENUQC
#ifndef CLIENT_ALL_H
#define CLIENT_ALL_H
+#include "../common/util.qh"
+
+#include "../common/effects/all.qh"
+#include "../common/models/all.qh"
+#include "../common/sounds/all.qh"
+
#include "autocvars.qh"
#include "defs.qh"
#include "main.qh"
#include "miscfunctions.qh"
-#include "../dpdefs/csprogsdefs.qh"
-
-#include "../common/models/all.qh"
-#include "../common/sounds/all.qh"
-
#endif
#include "announcer.qh"
-#include "_all.qh"
#include "../common/notifications.qh"
#include "../common/stats.qh"
-#include "../common/util.qh"
bool announcer_1min;
bool announcer_5min;
-#ifndef ANNOUNCER_H
-#define ANNOUNCER_H
+#ifndef CLIENT_ANNOUNCER_H
+#define CLIENT_ANNOUNCER_H
void Announcer();
#include "bgmscript.qh"
-#include "_all.qh"
-
-#include "../common/util.qh"
#define CONSTANT_SPEED_DECAY
-#ifndef BGMSCRIPT_H
-#define BGMSCRIPT_H
+#ifndef CLIENT_BGMSCRIPT_H
+#define CLIENT_BGMSCRIPT_H
entityclass(BGMScript);
class(BGMScript) .string bgmscript;
+++ /dev/null
-#include "../_all.qh"
-
-#include "../../common/command/all.qc"
-
-#include "cl_cmd.qc"
+++ /dev/null
-#ifndef CLIENT_COMMANDS_ALL_H
-#define CLIENT_COMMANDS_ALL_H
-
-#include "../../common/command/all.qh"
-
-#include "cl_cmd.qh"
-
-#endif
+++ /dev/null
-// ==============================================
-// CSQC client commands code, written by Samual
-// Last updated: December 28th, 2011
-// ==============================================
-
-#include "../../common/command/command.qh"
-#include "cl_cmd.qh"
-
-#include "../autocvars.qh"
-#include "../defs.qh"
-#include "../hud.qh"
-#include "../hud_config.qh"
-#include "../main.qh"
-#include "../mapvoting.qh"
-#include "../miscfunctions.qh"
-
-#include "../mutators/events.qh"
-
-#include "../../common/mapinfo.qh"
-
-#include "../../common/command/generic.qh"
-
-void DrawDebugModel(entity this)
-{
- if(time - floor(time) > 0.5)
- {
- PolyDrawModel(self);
- self.drawmask = 0;
- }
- else
- {
- self.renderflags = 0;
- self.drawmask = MASK_NORMAL;
- }
-}
-
-
-// =======================
-// Command Sub-Functions
-// =======================
-
-void LocalCommand_blurtest(int request)
-{
- // Simple command to work with postprocessing temporarily... possibly completely pointless, the glsl shader is used for a real feature now...
- // Anyway, to enable it, just compile the client with -DBLURTEST and then you can use the command.
-
- #ifdef BLURTEST
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- blurtest_time0 = time;
- blurtest_time1 = time + stof(argv(1));
- blurtest_radius = stof(argv(2));
- blurtest_power = stof(argv(3));
- LOG_INFO("Enabled blurtest\n");
- return;
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO("\nUsage:^3 cl_cmd blurtest\n");
- LOG_INFO(" No arguments required.\n");
- return;
- }
- }
- #else
- if(request)
- {
- LOG_INFO("Blurtest is not enabled on this client.\n");
- return;
- }
- #endif
-}
-
-void LocalCommand_boxparticles(int request, int argc)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- if (argc == 9)
- {
- int effect = _particleeffectnum(argv(1));
- if (effect >= 0)
- {
- int index = stoi(argv(2));
- entity own;
- if(index <= 0)
- own = entitybyindex(-index);
- else
- own = findfloat(world, entnum, index);
- vector org_from = stov(argv(3));
- vector org_to = stov(argv(4));
- vector dir_from = stov(argv(5));
- vector dir_to = stov(argv(6));
- int countmultiplier = stoi(argv(7));
- int flags = stoi(argv(8));
- boxparticles(effect, own, org_from, org_to, dir_from, dir_to, countmultiplier, flags);
- return;
- }
- }
- }
-
- default:
- LOG_INFO("Incorrect parameters for ^2boxparticles^7\n");
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO("\nUsage:^3 lv_cmd boxparticles effectname own org_from org_to, dir_from, dir_to, countmultiplier, flags\n");
- LOG_INFO(" 'effectname' is the name of a particle effect in effectinfo.txt\n");
- LOG_INFO(" 'own' is the entity number of the owner (negative for csqc ent, positive for svqc ent)\n");
- LOG_INFO(" 'org_from' is the starting origin of the box\n");
- LOG_INFO(" 'org_to' is the ending origin of the box\n");
- LOG_INFO(" 'dir_from' is the minimum velocity\n");
- LOG_INFO(" 'dir_to' is the maximum velocity\n");
- LOG_INFO(" 'countmultiplier' defines a multiplier for the particle count (affects count only, not countabsolute or trailspacing)\n");
- LOG_INFO(" 'flags' can contain:\n");
- LOG_INFO(" 1 to respect globals particles_alphamin, particles_alphamax (set right before via prvm_globalset client)\n");
- LOG_INFO(" 2 to respect globals particles_colormin, particles_colormax (set right before via prvm_globalset client)\n");
- LOG_INFO(" 4 to respect globals particles_fade (set right before via prvm_globalset client)\n");
- LOG_INFO(" 128 to draw a trail, not a box\n");
- return;
- }
- }
-}
-
-void LocalCommand_create_scrshot_ent(int request)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- string filename = strcat(MapInfo_Map_bspname, "_scrshot_ent.txt");
- int fh = fopen(filename, FILE_WRITE);
-
- if(fh >= 0)
- {
- fputs(fh, "{\n");
- fputs(fh, strcat("\"classname\" \"info_autoscreenshot\"\n"));
- fputs(fh, strcat("\"origin\" \"", strcat(ftos(view_origin.x), " ", ftos(view_origin.y), " ", ftos(view_origin.z)), "\"\n"));
- fputs(fh, strcat("\"angles\" \"", strcat(ftos(view_angles.x), " ", ftos(view_angles.y), " ", ftos(view_angles.z)), "\"\n"));
- fputs(fh, "}\n");
-
- LOG_INFO("Completed screenshot entity dump in ^2data/data/", MapInfo_Map_bspname, "_scrshot_ent.txt^7.\n");
-
- fclose(fh);
- }
- else
- {
- LOG_INFO("^1Error: ^7Could not dump to file!\n");
- }
- return;
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO("\nUsage:^3 cl_cmd create_scrshot_ent\n");
- LOG_INFO(" No arguments required.\n");
- return;
- }
- }
-}
-
-void LocalCommand_debugmodel(int request, int argc)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- string modelname = argv(1);
- entity debugmodel_entity;
-
- debugmodel_entity = spawn();
- precache_model(modelname);
- _setmodel(debugmodel_entity, modelname);
- setorigin(debugmodel_entity, view_origin);
- debugmodel_entity.angles = view_angles;
- debugmodel_entity.draw = DrawDebugModel;
- debugmodel_entity.classname = "debugmodel";
-
- return;
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO("\nUsage:^3 cl_cmd debugmodel model\n");
- LOG_INFO(" Where 'model' is a string of the model name to use for the debug model.\n");
- return;
- }
- }
-}
-
-void LocalCommand_handlevote(int request, int argc)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- int vote_selection;
- string vote_string;
-
- if(InterpretBoolean(argv(1)))
- {
- vote_selection = 2;
- vote_string = "yes";
- }
- else
- {
- vote_selection = 1;
- vote_string = "no";
- }
-
- if(vote_selection)
- {
- if(uid2name_dialog) // handled by "uid2name" option
- {
- vote_active = 0;
- vote_prev = 0;
- vote_change = -9999;
- localcmd(strcat("setreport cl_allow_uid2name ", ftos(vote_selection - 1), "\n"));
- uid2name_dialog = 0;
- }
- else { localcmd(strcat("cmd vote ", vote_string, "\n")); }
-
- return;
- }
- }
-
- default:
- LOG_INFO("Incorrect parameters for ^2handlevote^7\n");
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO("\nUsage:^3 cl_cmd handlevote vote\n");
- LOG_INFO(" Where 'vote' is the selection for either the current poll or uid2name.\n");
- return;
- }
- }
-}
-
-void LocalCommand_hud(int request, int argc)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- switch(argv(1))
- {
- case "configure":
- {
- cvar_set("_hud_configure", ftos(!autocvar__hud_configure));
- return;
- }
-
- case "quickmenu":
- {
- if(QuickMenu_IsOpened())
- QuickMenu_Close();
- else
- QuickMenu_Open(argv(2), argv(3)); // mode, submenu
- return;
- }
-
- case "minigame":
- {
- if(HUD_MinigameMenu_IsOpened())
- HUD_MinigameMenu_Close();
- else
- HUD_MinigameMenu_Open();
- return;
- }
-
- case "save":
- {
- if(argv(2))
- {
- HUD_Panel_ExportCfg(argv(2));
- return;
- }
- else
- {
- break; // go to usage, we're missing the paramater needed here.
- }
- }
-
- case "scoreboard_columns_set":
- {
- Cmd_HUD_SetFields(argc);
- return;
- }
-
- case "scoreboard_columns_help":
- {
- Cmd_HUD_Help();
- return;
- }
-
- case "radar":
- {
- if(argv(2))
- HUD_Radar_Show_Maximized(InterpretBoolean(argv(2)),0);
- else
- HUD_Radar_Show_Maximized(!hud_panel_radar_maximized,0);
- return;
- }
-
- case "clickradar":
- {
- HUD_Radar_Show_Maximized(!hud_panel_radar_mouse,1);
- return;
- }
- }
- }
-
- default:
- LOG_INFO("Incorrect parameters for ^2hud^7\n");
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO("\nUsage:^3 cl_cmd hud action [configname | radartoggle | layout]\n");
- LOG_INFO(" Where 'action' is the command to complete,\n");
- LOG_INFO(" 'configname' is the name to save to for \"save\" action,\n");
- LOG_INFO(" 'radartoggle' is to control hud_panel_radar_maximized for \"radar\" action,\n");
- LOG_INFO(" and 'layout' is how to organize the scoreboard columns for the set action.\n");
- LOG_INFO(" quickmenu [[default | file | \"\"] submenu]\n");
- LOG_INFO(" Called without options (or with "") loads either the default quickmenu or a quickmenu file if hud_panel_quickmenu_file is set to a valid filename.\n");
- LOG_INFO(" Submenu option allows to open quickmenu directly in a submenu, it requires to specify 'default', 'file' or '\"\"' option.\n");
- LOG_INFO(" Full list of commands here: \"configure, minigame, save, scoreboard_columns_help, scoreboard_columns_set, radar.\"\n");
- return;
- }
- }
-}
-
-void LocalCommand_localprint(int request, int argc)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- if(argv(1))
- {
- centerprint_hud(argv(1));
- return;
- }
- }
-
- default:
- LOG_INFO("Incorrect parameters for ^2localprint^7\n");
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO("\nUsage:^3 cl_cmd localprint \"message\"\n");
- LOG_INFO(" 'message' is the centerprint message to send to yourself.\n");
- return;
- }
- }
-}
-
-void LocalCommand_mv_download(int request, int argc)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- if(argv(1))
- {
- Cmd_MapVote_MapDownload(argc);
- return;
- }
- }
-
- default:
- LOG_INFO("Incorrect parameters for ^2mv_download^7\n");
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO("\nUsage:^3 cl_cmd mv_download mapid\n");
- LOG_INFO(" Where 'mapid' is the id number of the map to request an image of on the map vote selection menu.\n");
- return;
- }
- }
-}
-
-void LocalCommand_find(int request, int argc)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- entity client;
-
- for(client = world; (client = find(client, classname, argv(1))); )
- LOG_INFO(etos(client), "\n");
-
- return;
- }
-
- default:
- LOG_INFO("Incorrect parameters for ^2find^7\n");
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO("\nUsage:^3 cl_cmd find classname\n");
- LOG_INFO(" Where 'classname' is the classname to search for.\n");
- return;
- }
- }
-}
-
-void LocalCommand_sendcvar(int request, int argc)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- if(argv(1))
- {
- // W_FixWeaponOrder will trash argv, so save what we need.
- string thiscvar = strzone(argv(1));
- string s = cvar_string(thiscvar);
-
- if(thiscvar == "cl_weaponpriority")
- s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 1);
- else if(substring(thiscvar, 0, 17) == "cl_weaponpriority" && strlen(thiscvar) == 18)
- s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 0);
-
- localcmd("cmd sentcvar ", thiscvar, " \"", s, "\"\n");
- strunzone(thiscvar);
- return;
- }
- }
-
- default:
- LOG_INFO("Incorrect parameters for ^2sendcvar^7\n");
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO("\nUsage:^3 cl_cmd sendcvar <cvar>\n");
- LOG_INFO(" Where 'cvar' is the cvar plus arguments to send to the server.\n");
- return;
- }
- }
-}
-
-/* use this when creating a new command, making sure to place it in alphabetical order... also,
-** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
-void LocalCommand_(int request)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
-
- return;
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- print("\nUsage:^3 cl_cmd \n");
- print(" No arguments required.\n");
- return;
- }
- }
-}
-*/
-
-
-// ==================================
-// Macro system for client commands
-// ==================================
-
-// Normally do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define CLIENT_COMMANDS(request,arguments) \
- CLIENT_COMMAND("blurtest", LocalCommand_blurtest(request), "Feature for testing blur postprocessing") \
- CLIENT_COMMAND("boxparticles", LocalCommand_boxparticles(request, arguments), "Spawn particles manually") \
- CLIENT_COMMAND("create_scrshot_ent", LocalCommand_create_scrshot_ent(request), "Create an entity at this location for automatic screenshots") \
- CLIENT_COMMAND("debugmodel", LocalCommand_debugmodel(request, arguments), "Spawn a debug model manually") \
- CLIENT_COMMAND("handlevote", LocalCommand_handlevote(request, arguments), "System to handle selecting a vote or option") \
- CLIENT_COMMAND("hud", LocalCommand_hud(request, arguments), "Commands regarding/controlling the HUD system") \
- CLIENT_COMMAND("localprint", LocalCommand_localprint(request, arguments), "Create your own centerprint sent to yourself") \
- CLIENT_COMMAND("find", LocalCommand_find(request, arguments), "Search through entities for matching classname") \
- CLIENT_COMMAND("mv_download", LocalCommand_mv_download(request, arguments), "Retrieve mapshot picture from the server") \
- CLIENT_COMMAND("sendcvar", LocalCommand_sendcvar(request, arguments), "Send a cvar to the server (like weaponpriority)") \
- /* nothing */
-
-void LocalCommand_macro_help()
-{
- #define CLIENT_COMMAND(name,function,description) \
- { if(strtolower(description) != "") { LOG_INFO(" ^2", name, "^7: ", description, "\n"); } }
-
- CLIENT_COMMANDS(0, 0);
- #undef CLIENT_COMMAND
-
- return;
-}
-
-bool LocalCommand_macro_command(int argc)
-{
- #define CLIENT_COMMAND(name,function,description) \
- { if(name == strtolower(argv(0))) { function; return true; } }
-
- CLIENT_COMMANDS(CMD_REQUEST_COMMAND, argc);
- #undef CLIENT_COMMAND
-
- return false;
-}
-
-bool LocalCommand_macro_usage(int argc)
-{
- #define CLIENT_COMMAND(name,function,description) \
- { if(name == strtolower(argv(1))) { function; return true; } }
-
- CLIENT_COMMANDS(CMD_REQUEST_USAGE, argc);
- #undef CLIENT_COMMAND
-
- return false;
-}
-
-void LocalCommand_macro_write_aliases(int fh)
-{
- #define CLIENT_COMMAND(name,function,description) \
- { if(strtolower(description) != "") { CMD_Write_Alias("qc_cmd_cl", name, description); } }
-
- CLIENT_COMMANDS(0, 0);
- #undef CLIENT_COMMAND
-
- return;
-}
-
-
-// =========================================
-// Main Function Called By Engine (cl_cmd)
-// =========================================
-// If this function exists, client code handles gamecommand instead of the engine code.
-
-void GameCommand(string command)
-{
- int argc = tokenize_console(command);
-
- // Guide for working with argc arguments by example:
- // argc: 1 - 2 - 3 - 4
- // argv: 0 - 1 - 2 - 3
- // cmd vote - master - login - password
- string s = strtolower(argv(0));
- if (s == "help")
- {
- if(argc == 1)
- {
- LOG_INFO("\nClient console commands:\n");
- LocalCommand_macro_help();
-
- LOG_INFO("\nGeneric commands shared by all programs:\n");
- GenericCommand_macro_help();
-
- LOG_INFO("\nUsage:^3 cl_cmd COMMAND...^7, where possible commands are listed above.\n");
- LOG_INFO("For help about a specific command, type cl_cmd help COMMAND\n");
-
- return;
- }
- else if(GenericCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
- {
- return;
- }
- else if(LocalCommand_macro_usage(argc)) // now try for normal commands too
- {
- return;
- }
- }
- // continue as usual and scan for normal commands
- if (GenericCommand(command)// handled by common/command/generic.qc
- || LocalCommand_macro_command(argc) // handled by one of the above LocalCommand_* functions
- || MUTATOR_CALLHOOK(CSQC_ConsoleCommand, s, argc, command) // handled by a mutator
- ) return;
-
- // nothing above caught the command, must be invalid
- LOG_INFO(((command != "") ? strcat("Unknown client command \"", command, "\"") : "No command provided"), ". For a list of supported commands, try cl_cmd help.\n");
-
- return;
-}
-
-
-// ===================================
-// Macro system for console commands
-// ===================================
-
-// These functions are here specifically to add special + - commands to the game, and are not really normal commands.
-// Please add client commands to the function above this, as this is only for special reasons.
-#define CONSOLE_COMMANDS_NORMAL() \
- CONSOLE_COMMAND("+showscores", { scoreboard_showscores = true; }) \
- CONSOLE_COMMAND("-showscores", { scoreboard_showscores = false; }) \
- CONSOLE_COMMAND("+showaccuracy", { scoreboard_showaccuracy = true; }) \
- CONSOLE_COMMAND("-showaccuracy", { scoreboard_showaccuracy = false; }) \
- /* nothing */
-
-#define CONSOLE_COMMANDS_MOVEMENT() \
- CONSOLE_COMMAND("+forward", { ++camera_direction.x; }) \
- CONSOLE_COMMAND("-forward", { --camera_direction.x; }) \
- CONSOLE_COMMAND("+back", { --camera_direction.x; }) \
- CONSOLE_COMMAND("-back", { ++camera_direction.x; }) \
- CONSOLE_COMMAND("+moveup", { ++camera_direction.z; }) \
- CONSOLE_COMMAND("-moveup", { --camera_direction.z; }) \
- CONSOLE_COMMAND("+movedown", { --camera_direction.z; }) \
- CONSOLE_COMMAND("-movedown", { ++camera_direction.z; }) \
- CONSOLE_COMMAND("+moveright", { --camera_direction.y; }) \
- CONSOLE_COMMAND("-moveright", { ++camera_direction.y; }) \
- CONSOLE_COMMAND("+moveleft", { ++camera_direction.y; }) \
- CONSOLE_COMMAND("-moveleft", { --camera_direction.y; }) \
- CONSOLE_COMMAND("+roll_right", { ++camera_roll; }) \
- CONSOLE_COMMAND("-roll_right", { --camera_roll; }) \
- CONSOLE_COMMAND("+roll_left", { --camera_roll; }) \
- CONSOLE_COMMAND("-roll_left", { ++camera_roll; }) \
- /* nothing */
-
-void ConsoleCommand_macro_init()
-{
- // first init normal commands
- #define CONSOLE_COMMAND(name,execution) \
- { registercommand(name); }
-
- CONSOLE_COMMANDS_NORMAL();
- #undef CONSOLE_COMMAND
-
- // then init movement commands
- #ifndef CAMERATEST
- if(isdemo())
- {
- #endif
- #define CONSOLE_COMMAND(name,execution) \
- { registercommand(name); }
-
- CONSOLE_COMMANDS_MOVEMENT();
- #undef CONSOLE_COMMAND
- #ifndef CAMERATEST
- }
- #endif
-}
-
-bool ConsoleCommand_macro_normal(string s, int argc)
-{
- #define CONSOLE_COMMAND(name,execution) \
- { if (name == s) { { execution } return true; } }
-
- CONSOLE_COMMANDS_NORMAL();
- #undef CONSOLE_COMMAND
-
- return false;
-}
-
-bool ConsoleCommand_macro_movement(string s, int argc)
-{
- if(camera_active)
- {
- #define CONSOLE_COMMAND(name,execution) \
- { if (name == s) { { execution } return true; } }
-
- CONSOLE_COMMANDS_MOVEMENT();
- #undef CONSOLE_COMMAND
- }
-
- return false;
-}
-
-
-// ======================================================
-// Main Function Called By Engine (registered commands)
-// ======================================================
-// Used to parse commands in the console that have been registered with the "registercommand" function
-
-bool CSQC_ConsoleCommand(string command)
-{
- int argc = tokenize_console(command);
- string s = strtolower(argv(0));
- // Return value should be true if CSQC handled the command, otherwise return false to have the engine handle it.
- return (ConsoleCommand_macro_normal(s, argc)
- || ConsoleCommand_macro_movement(s, argc)
- );
-}
+++ /dev/null
-#ifndef CL_CMD_H
-#define CL_CMD_H
-// ==============================================
-// CSQC client commands code, written by Samual
-// Last updated: December 17th, 2011
-// ==============================================
-
-void Cmd_HUD_SetFields(int);
-void Cmd_HUD_Help();
-
-// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
-void LocalCommand_macro_write_aliases(int fh);
-#endif
--- /dev/null
+#include "../../common/command/all.qc"
+
+#include "cl_cmd.qc"
--- /dev/null
+#ifndef CLIENT_COMMANDS_ALL_H
+#define CLIENT_COMMANDS_ALL_H
+
+#include "../../common/commands/all.qh"
+
+#include "cl_cmd.qh"
+
+#endif
--- /dev/null
+// ==============================================
+// CSQC client commands code, written by Samual
+// Last updated: December 28th, 2011
+// ==============================================
+
+#include "../../common/command/command.qh"
+#include "cl_cmd.qh"
+
+#include "../autocvars.qh"
+#include "../defs.qh"
+#include "../hud.qh"
+#include "../hud_config.qh"
+#include "../main.qh"
+#include "../mapvoting.qh"
+#include "../miscfunctions.qh"
+
+#include "../mutators/events.qh"
+
+#include "../../common/mapinfo.qh"
+
+#include "../../common/command/generic.qh"
+
+void DrawDebugModel(entity this)
+{
+ if(time - floor(time) > 0.5)
+ {
+ PolyDrawModel(self);
+ self.drawmask = 0;
+ }
+ else
+ {
+ self.renderflags = 0;
+ self.drawmask = MASK_NORMAL;
+ }
+}
+
+
+// =======================
+// Command Sub-Functions
+// =======================
+
+void LocalCommand_blurtest(int request)
+{
+ // Simple command to work with postprocessing temporarily... possibly completely pointless, the glsl shader is used for a real feature now...
+ // Anyway, to enable it, just compile the client with -DBLURTEST and then you can use the command.
+
+ #ifdef BLURTEST
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ blurtest_time0 = time;
+ blurtest_time1 = time + stof(argv(1));
+ blurtest_radius = stof(argv(2));
+ blurtest_power = stof(argv(3));
+ LOG_INFO("Enabled blurtest\n");
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO("\nUsage:^3 cl_cmd blurtest\n");
+ LOG_INFO(" No arguments required.\n");
+ return;
+ }
+ }
+ #else
+ if(request)
+ {
+ LOG_INFO("Blurtest is not enabled on this client.\n");
+ return;
+ }
+ #endif
+}
+
+void LocalCommand_boxparticles(int request, int argc)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ if (argc == 9)
+ {
+ int effect = _particleeffectnum(argv(1));
+ if (effect >= 0)
+ {
+ int index = stoi(argv(2));
+ entity own;
+ if(index <= 0)
+ own = entitybyindex(-index);
+ else
+ own = findfloat(world, entnum, index);
+ vector org_from = stov(argv(3));
+ vector org_to = stov(argv(4));
+ vector dir_from = stov(argv(5));
+ vector dir_to = stov(argv(6));
+ int countmultiplier = stoi(argv(7));
+ int flags = stoi(argv(8));
+ boxparticles(effect, own, org_from, org_to, dir_from, dir_to, countmultiplier, flags);
+ return;
+ }
+ }
+ }
+
+ default:
+ LOG_INFO("Incorrect parameters for ^2boxparticles^7\n");
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO("\nUsage:^3 lv_cmd boxparticles effectname own org_from org_to, dir_from, dir_to, countmultiplier, flags\n");
+ LOG_INFO(" 'effectname' is the name of a particle effect in effectinfo.txt\n");
+ LOG_INFO(" 'own' is the entity number of the owner (negative for csqc ent, positive for svqc ent)\n");
+ LOG_INFO(" 'org_from' is the starting origin of the box\n");
+ LOG_INFO(" 'org_to' is the ending origin of the box\n");
+ LOG_INFO(" 'dir_from' is the minimum velocity\n");
+ LOG_INFO(" 'dir_to' is the maximum velocity\n");
+ LOG_INFO(" 'countmultiplier' defines a multiplier for the particle count (affects count only, not countabsolute or trailspacing)\n");
+ LOG_INFO(" 'flags' can contain:\n");
+ LOG_INFO(" 1 to respect globals particles_alphamin, particles_alphamax (set right before via prvm_globalset client)\n");
+ LOG_INFO(" 2 to respect globals particles_colormin, particles_colormax (set right before via prvm_globalset client)\n");
+ LOG_INFO(" 4 to respect globals particles_fade (set right before via prvm_globalset client)\n");
+ LOG_INFO(" 128 to draw a trail, not a box\n");
+ return;
+ }
+ }
+}
+
+void LocalCommand_create_scrshot_ent(int request)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ string filename = strcat(MapInfo_Map_bspname, "_scrshot_ent.txt");
+ int fh = fopen(filename, FILE_WRITE);
+
+ if(fh >= 0)
+ {
+ fputs(fh, "{\n");
+ fputs(fh, strcat("\"classname\" \"info_autoscreenshot\"\n"));
+ fputs(fh, strcat("\"origin\" \"", strcat(ftos(view_origin.x), " ", ftos(view_origin.y), " ", ftos(view_origin.z)), "\"\n"));
+ fputs(fh, strcat("\"angles\" \"", strcat(ftos(view_angles.x), " ", ftos(view_angles.y), " ", ftos(view_angles.z)), "\"\n"));
+ fputs(fh, "}\n");
+
+ LOG_INFO("Completed screenshot entity dump in ^2data/data/", MapInfo_Map_bspname, "_scrshot_ent.txt^7.\n");
+
+ fclose(fh);
+ }
+ else
+ {
+ LOG_INFO("^1Error: ^7Could not dump to file!\n");
+ }
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO("\nUsage:^3 cl_cmd create_scrshot_ent\n");
+ LOG_INFO(" No arguments required.\n");
+ return;
+ }
+ }
+}
+
+void LocalCommand_debugmodel(int request, int argc)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ string modelname = argv(1);
+ entity debugmodel_entity;
+
+ debugmodel_entity = spawn();
+ precache_model(modelname);
+ _setmodel(debugmodel_entity, modelname);
+ setorigin(debugmodel_entity, view_origin);
+ debugmodel_entity.angles = view_angles;
+ debugmodel_entity.draw = DrawDebugModel;
+ debugmodel_entity.classname = "debugmodel";
+
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO("\nUsage:^3 cl_cmd debugmodel model\n");
+ LOG_INFO(" Where 'model' is a string of the model name to use for the debug model.\n");
+ return;
+ }
+ }
+}
+
+void LocalCommand_handlevote(int request, int argc)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ int vote_selection;
+ string vote_string;
+
+ if(InterpretBoolean(argv(1)))
+ {
+ vote_selection = 2;
+ vote_string = "yes";
+ }
+ else
+ {
+ vote_selection = 1;
+ vote_string = "no";
+ }
+
+ if(vote_selection)
+ {
+ if(uid2name_dialog) // handled by "uid2name" option
+ {
+ vote_active = 0;
+ vote_prev = 0;
+ vote_change = -9999;
+ localcmd(strcat("setreport cl_allow_uid2name ", ftos(vote_selection - 1), "\n"));
+ uid2name_dialog = 0;
+ }
+ else { localcmd(strcat("cmd vote ", vote_string, "\n")); }
+
+ return;
+ }
+ }
+
+ default:
+ LOG_INFO("Incorrect parameters for ^2handlevote^7\n");
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO("\nUsage:^3 cl_cmd handlevote vote\n");
+ LOG_INFO(" Where 'vote' is the selection for either the current poll or uid2name.\n");
+ return;
+ }
+ }
+}
+
+bool QuickMenu_IsOpened();
+void QuickMenu_Close();
+bool QuickMenu_Open(string mode, string submenu);
+
+bool HUD_MinigameMenu_IsOpened();
+void HUD_MinigameMenu_Close();
+void HUD_MinigameMenu_Open();
+
+void HUD_Radar_Show_Maximized(bool doshow, bool clickable);
+
+void LocalCommand_hud(int request, int argc)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ switch(argv(1))
+ {
+ case "configure":
+ {
+ cvar_set("_hud_configure", ftos(!autocvar__hud_configure));
+ return;
+ }
+
+ case "quickmenu":
+ {
+ if(QuickMenu_IsOpened())
+ QuickMenu_Close();
+ else
+ QuickMenu_Open(argv(2), argv(3)); // mode, submenu
+ return;
+ }
+
+ case "minigame":
+ {
+ if(HUD_MinigameMenu_IsOpened())
+ HUD_MinigameMenu_Close();
+ else
+ HUD_MinigameMenu_Open();
+ return;
+ }
+
+ case "save":
+ {
+ if(argv(2))
+ {
+ HUD_Panel_ExportCfg(argv(2));
+ return;
+ }
+ else
+ {
+ break; // go to usage, we're missing the paramater needed here.
+ }
+ }
+
+ case "scoreboard_columns_set":
+ {
+ Cmd_HUD_SetFields(argc);
+ return;
+ }
+
+ case "scoreboard_columns_help":
+ {
+ Cmd_HUD_Help();
+ return;
+ }
+
+ case "radar":
+ {
+ if(argv(2))
+ HUD_Radar_Show_Maximized(InterpretBoolean(argv(2)),0);
+ else
+ HUD_Radar_Show_Maximized(!hud_panel_radar_maximized,0);
+ return;
+ }
+
+ case "clickradar":
+ {
+ HUD_Radar_Show_Maximized(!hud_panel_radar_mouse,1);
+ return;
+ }
+ }
+ }
+
+ default:
+ LOG_INFO("Incorrect parameters for ^2hud^7\n");
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO("\nUsage:^3 cl_cmd hud action [configname | radartoggle | layout]\n");
+ LOG_INFO(" Where 'action' is the command to complete,\n");
+ LOG_INFO(" 'configname' is the name to save to for \"save\" action,\n");
+ LOG_INFO(" 'radartoggle' is to control hud_panel_radar_maximized for \"radar\" action,\n");
+ LOG_INFO(" and 'layout' is how to organize the scoreboard columns for the set action.\n");
+ LOG_INFO(" quickmenu [[default | file | \"\"] submenu]\n");
+ LOG_INFO(" Called without options (or with "") loads either the default quickmenu or a quickmenu file if hud_panel_quickmenu_file is set to a valid filename.\n");
+ LOG_INFO(" Submenu option allows to open quickmenu directly in a submenu, it requires to specify 'default', 'file' or '\"\"' option.\n");
+ LOG_INFO(" Full list of commands here: \"configure, minigame, save, scoreboard_columns_help, scoreboard_columns_set, radar.\"\n");
+ return;
+ }
+ }
+}
+
+void LocalCommand_localprint(int request, int argc)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ if(argv(1))
+ {
+ centerprint_hud(argv(1));
+ return;
+ }
+ }
+
+ default:
+ LOG_INFO("Incorrect parameters for ^2localprint^7\n");
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO("\nUsage:^3 cl_cmd localprint \"message\"\n");
+ LOG_INFO(" 'message' is the centerprint message to send to yourself.\n");
+ return;
+ }
+ }
+}
+
+void LocalCommand_mv_download(int request, int argc)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ if(argv(1))
+ {
+ Cmd_MapVote_MapDownload(argc);
+ return;
+ }
+ }
+
+ default:
+ LOG_INFO("Incorrect parameters for ^2mv_download^7\n");
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO("\nUsage:^3 cl_cmd mv_download mapid\n");
+ LOG_INFO(" Where 'mapid' is the id number of the map to request an image of on the map vote selection menu.\n");
+ return;
+ }
+ }
+}
+
+void LocalCommand_find(int request, int argc)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ entity client;
+
+ for(client = world; (client = find(client, classname, argv(1))); )
+ LOG_INFO(etos(client), "\n");
+
+ return;
+ }
+
+ default:
+ LOG_INFO("Incorrect parameters for ^2find^7\n");
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO("\nUsage:^3 cl_cmd find classname\n");
+ LOG_INFO(" Where 'classname' is the classname to search for.\n");
+ return;
+ }
+ }
+}
+
+void LocalCommand_sendcvar(int request, int argc)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ if(argv(1))
+ {
+ // W_FixWeaponOrder will trash argv, so save what we need.
+ string thiscvar = strzone(argv(1));
+ string s = cvar_string(thiscvar);
+
+ if(thiscvar == "cl_weaponpriority")
+ s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 1);
+ else if(substring(thiscvar, 0, 17) == "cl_weaponpriority" && strlen(thiscvar) == 18)
+ s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 0);
+
+ localcmd("cmd sentcvar ", thiscvar, " \"", s, "\"\n");
+ strunzone(thiscvar);
+ return;
+ }
+ }
+
+ default:
+ LOG_INFO("Incorrect parameters for ^2sendcvar^7\n");
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO("\nUsage:^3 cl_cmd sendcvar <cvar>\n");
+ LOG_INFO(" Where 'cvar' is the cvar plus arguments to send to the server.\n");
+ return;
+ }
+ }
+}
+
+/* use this when creating a new command, making sure to place it in alphabetical order... also,
+** ADD ALL NEW COMMANDS TO commands.cfg WITH PROPER ALIASES IN THE SAME FASHION!
+void LocalCommand_(int request)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ print("\nUsage:^3 cl_cmd \n");
+ print(" No arguments required.\n");
+ return;
+ }
+ }
+}
+*/
+
+
+// ==================================
+// Macro system for client commands
+// ==================================
+
+// Normally do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
+#define CLIENT_COMMANDS(request,arguments) \
+ CLIENT_COMMAND("blurtest", LocalCommand_blurtest(request), "Feature for testing blur postprocessing") \
+ CLIENT_COMMAND("boxparticles", LocalCommand_boxparticles(request, arguments), "Spawn particles manually") \
+ CLIENT_COMMAND("create_scrshot_ent", LocalCommand_create_scrshot_ent(request), "Create an entity at this location for automatic screenshots") \
+ CLIENT_COMMAND("debugmodel", LocalCommand_debugmodel(request, arguments), "Spawn a debug model manually") \
+ CLIENT_COMMAND("handlevote", LocalCommand_handlevote(request, arguments), "System to handle selecting a vote or option") \
+ CLIENT_COMMAND("hud", LocalCommand_hud(request, arguments), "Commands regarding/controlling the HUD system") \
+ CLIENT_COMMAND("localprint", LocalCommand_localprint(request, arguments), "Create your own centerprint sent to yourself") \
+ CLIENT_COMMAND("find", LocalCommand_find(request, arguments), "Search through entities for matching classname") \
+ CLIENT_COMMAND("mv_download", LocalCommand_mv_download(request, arguments), "Retrieve mapshot picture from the server") \
+ CLIENT_COMMAND("sendcvar", LocalCommand_sendcvar(request, arguments), "Send a cvar to the server (like weaponpriority)") \
+ /* nothing */
+
+void LocalCommand_macro_help()
+{
+ #define CLIENT_COMMAND(name,function,description) \
+ { if(strtolower(description) != "") { LOG_INFO(" ^2", name, "^7: ", description, "\n"); } }
+
+ CLIENT_COMMANDS(0, 0);
+ #undef CLIENT_COMMAND
+
+ return;
+}
+
+bool LocalCommand_macro_command(int argc)
+{
+ #define CLIENT_COMMAND(name,function,description) \
+ { if(name == strtolower(argv(0))) { function; return true; } }
+
+ CLIENT_COMMANDS(CMD_REQUEST_COMMAND, argc);
+ #undef CLIENT_COMMAND
+
+ return false;
+}
+
+bool LocalCommand_macro_usage(int argc)
+{
+ #define CLIENT_COMMAND(name,function,description) \
+ { if(name == strtolower(argv(1))) { function; return true; } }
+
+ CLIENT_COMMANDS(CMD_REQUEST_USAGE, argc);
+ #undef CLIENT_COMMAND
+
+ return false;
+}
+
+void LocalCommand_macro_write_aliases(int fh)
+{
+ #define CLIENT_COMMAND(name,function,description) \
+ { if(strtolower(description) != "") { CMD_Write_Alias("qc_cmd_cl", name, description); } }
+
+ CLIENT_COMMANDS(0, 0);
+ #undef CLIENT_COMMAND
+
+ return;
+}
+
+
+// =========================================
+// Main Function Called By Engine (cl_cmd)
+// =========================================
+// If this function exists, client code handles gamecommand instead of the engine code.
+
+void GameCommand(string command)
+{
+ int argc = tokenize_console(command);
+
+ // Guide for working with argc arguments by example:
+ // argc: 1 - 2 - 3 - 4
+ // argv: 0 - 1 - 2 - 3
+ // cmd vote - master - login - password
+ string s = strtolower(argv(0));
+ if (s == "help")
+ {
+ if(argc == 1)
+ {
+ LOG_INFO("\nClient console commands:\n");
+ LocalCommand_macro_help();
+
+ LOG_INFO("\nGeneric commands shared by all programs:\n");
+ GenericCommand_macro_help();
+
+ LOG_INFO("\nUsage:^3 cl_cmd COMMAND...^7, where possible commands are listed above.\n");
+ LOG_INFO("For help about a specific command, type cl_cmd help COMMAND\n");
+
+ return;
+ }
+ else if(GenericCommand_macro_usage(argc)) // Instead of trying to call a command, we're going to see detailed information about it
+ {
+ return;
+ }
+ else if(LocalCommand_macro_usage(argc)) // now try for normal commands too
+ {
+ return;
+ }
+ }
+ // continue as usual and scan for normal commands
+ if (GenericCommand(command)// handled by common/command/generic.qc
+ || LocalCommand_macro_command(argc) // handled by one of the above LocalCommand_* functions
+ || MUTATOR_CALLHOOK(CSQC_ConsoleCommand, s, argc, command) // handled by a mutator
+ ) return;
+
+ // nothing above caught the command, must be invalid
+ LOG_INFO(((command != "") ? strcat("Unknown client command \"", command, "\"") : "No command provided"), ". For a list of supported commands, try cl_cmd help.\n");
+
+ return;
+}
+
+
+// ===================================
+// Macro system for console commands
+// ===================================
+
+// These functions are here specifically to add special + - commands to the game, and are not really normal commands.
+// Please add client commands to the function above this, as this is only for special reasons.
+#define CONSOLE_COMMANDS_NORMAL() \
+ CONSOLE_COMMAND("+showscores", { scoreboard_showscores = true; }) \
+ CONSOLE_COMMAND("-showscores", { scoreboard_showscores = false; }) \
+ CONSOLE_COMMAND("+showaccuracy", { scoreboard_showaccuracy = true; }) \
+ CONSOLE_COMMAND("-showaccuracy", { scoreboard_showaccuracy = false; }) \
+ /* nothing */
+
+#define CONSOLE_COMMANDS_MOVEMENT() \
+ CONSOLE_COMMAND("+forward", { ++camera_direction.x; }) \
+ CONSOLE_COMMAND("-forward", { --camera_direction.x; }) \
+ CONSOLE_COMMAND("+back", { --camera_direction.x; }) \
+ CONSOLE_COMMAND("-back", { ++camera_direction.x; }) \
+ CONSOLE_COMMAND("+moveup", { ++camera_direction.z; }) \
+ CONSOLE_COMMAND("-moveup", { --camera_direction.z; }) \
+ CONSOLE_COMMAND("+movedown", { --camera_direction.z; }) \
+ CONSOLE_COMMAND("-movedown", { ++camera_direction.z; }) \
+ CONSOLE_COMMAND("+moveright", { --camera_direction.y; }) \
+ CONSOLE_COMMAND("-moveright", { ++camera_direction.y; }) \
+ CONSOLE_COMMAND("+moveleft", { ++camera_direction.y; }) \
+ CONSOLE_COMMAND("-moveleft", { --camera_direction.y; }) \
+ CONSOLE_COMMAND("+roll_right", { ++camera_roll; }) \
+ CONSOLE_COMMAND("-roll_right", { --camera_roll; }) \
+ CONSOLE_COMMAND("+roll_left", { --camera_roll; }) \
+ CONSOLE_COMMAND("-roll_left", { ++camera_roll; }) \
+ /* nothing */
+
+void ConsoleCommand_macro_init()
+{
+ // first init normal commands
+ #define CONSOLE_COMMAND(name,execution) \
+ { registercommand(name); }
+
+ CONSOLE_COMMANDS_NORMAL();
+ #undef CONSOLE_COMMAND
+
+ // then init movement commands
+ #ifndef CAMERATEST
+ if(isdemo())
+ {
+ #endif
+ #define CONSOLE_COMMAND(name,execution) \
+ { registercommand(name); }
+
+ CONSOLE_COMMANDS_MOVEMENT();
+ #undef CONSOLE_COMMAND
+ #ifndef CAMERATEST
+ }
+ #endif
+}
+
+bool ConsoleCommand_macro_normal(string s, int argc)
+{
+ #define CONSOLE_COMMAND(name,execution) \
+ { if (name == s) { { execution } return true; } }
+
+ CONSOLE_COMMANDS_NORMAL();
+ #undef CONSOLE_COMMAND
+
+ return false;
+}
+
+bool ConsoleCommand_macro_movement(string s, int argc)
+{
+ if(camera_active)
+ {
+ #define CONSOLE_COMMAND(name,execution) \
+ { if (name == s) { { execution } return true; } }
+
+ CONSOLE_COMMANDS_MOVEMENT();
+ #undef CONSOLE_COMMAND
+ }
+
+ return false;
+}
+
+
+// ======================================================
+// Main Function Called By Engine (registered commands)
+// ======================================================
+// Used to parse commands in the console that have been registered with the "registercommand" function
+
+bool CSQC_ConsoleCommand(string command)
+{
+ int argc = tokenize_console(command);
+ string s = strtolower(argv(0));
+ // Return value should be true if CSQC handled the command, otherwise return false to have the engine handle it.
+ return (ConsoleCommand_macro_normal(s, argc)
+ || ConsoleCommand_macro_movement(s, argc)
+ );
+}
--- /dev/null
+#ifndef CLIENT_COMMANDS_CL_CMD_H
+#define CLIENT_COMMANDS_CL_CMD_H
+// ==============================================
+// CSQC client commands code, written by Samual
+// Last updated: December 17th, 2011
+// ==============================================
+
+void Cmd_HUD_SetFields(int);
+void Cmd_HUD_Help();
+
+// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
+void LocalCommand_macro_write_aliases(int fh);
+#endif
#include "controlpoint.qh"
-#include "gibs.qh"
+
#include "teamradar.qh"
#include "../common/movetypes/movetypes.qh"
+.vector colormod;
.float alpha;
.int count;
.float pain_finished;
-#ifndef CONTROLPOINT_H
-#define CONTROLPOINT_H
+#ifndef CLIENT_CONTROLPOINT_H
+#define CLIENT_CONTROLPOINT_H
const vector CPICON_MIN = '-32 -32 -9';
const vector CPICON_MAX = '32 32 25';
-#ifndef CSQC_CONSTANTS
-#define CSQC_CONSTANTS
-
-// MenuQC redefines world, change define it here to be safe
-#define world world
+#ifndef CLIENT_CSQC_CONSTANTS
+#define CLIENT_CSQC_CONSTANTS
// Mask Constants (set .drawmask on entities; use R_AddEntities to add all entities based on mask)
const int MASK_ENGINE = 1;
-#include "_all.qh"
-
-#include "gibs.qh"
+#include "mutators/events.qh"
#include "player_skeleton.qh"
-
#include "weapons/projectile.qh"
-
#include "../common/animdecide.qh"
-#include "../common/csqcmodel_settings.qh"
-#include "../common/effects/effects.qh"
-#include "../common/teams.qh"
-#include "../common/triggers/trigger/viewloc.qh"
-
-#include "mutators/events.qh"
-
-#include "../csqcmodellib/cl_model.qh"
-#include "../csqcmodellib/cl_player.qh"
-#include "../csqcmodellib/interpolate.qh"
-
+#include "../common/movetypes/movetypes.qh"
+#include "../common/viewloc.qh"
+#include "../lib/csqcmodel/cl_model.qh"
+#include "../lib/csqcmodel/cl_player.qh"
+#include "../lib/csqcmodel/interpolate.qh"
.float death_time;
.int modelflags;
if(self.tag_entity && wasfreed(self.tag_entity))
self.tag_entity = world;
- if(self.viewloc && wasfreed(self.viewloc))
- self.viewloc = world;
-
- if(self.viewloc.entnum != self.tag_networkviewloc)
- self.viewloc = findfloat(world, entnum, self.tag_networkviewloc);
+ viewloc_SetTags();
MUTATOR_CALLHOOK(TagIndex_Update, self);
#include "damage.qh"
-#include "_all.qh"
#include "gibs.qh"
-
-#include "../common/vehicles/all.qh"
-
-#include "../common/constants.qh"
#include "../common/deathtypes/all.qh"
-#include "../common/effects/effects.qh"
#include "../common/movetypes/movetypes.qh"
-#include "../common/util.qh"
-
+#include "../common/vehicles/all.qh"
#include "../common/weapons/all.qh"
.entity tag_entity;
-#ifndef DAMAGE_H
-#define DAMAGE_H
+#ifndef CLIENT_DAMAGE_H
+#define CLIENT_DAMAGE_H
.float total_damages; // number of effects which currently are attached to a player
#include "effects.qh"
-#include "_all.qh"
/*
.vector fx_start;
-#ifndef EFFECTS_H
-#define EFFECTS_H
+#ifndef CLIENT_EFFECTS_H
+#define CLIENT_EFFECTS_H
void Net_ReadArc();
#include "generator.qh"
+#include "teamradar.qh"
+#include "../common/movetypes/movetypes.qh"
+
+.float alpha;
+.float scale;
.int count;
.float max_health;
-#ifndef GENERATOR_H
-#define GENERATOR_H
+#ifndef CLIENT_GENERATOR_H
+#define CLIENT_GENERATOR_H
const vector GENERATOR_MIN = '-52 -52 -14';
const vector GENERATOR_MAX = '52 52 75';
#include "gibs.qh"
-#include "_all.qh"
#include "rubble.qh"
-
-#include "../common/constants.qh"
#include "../common/movetypes/movetypes.qh"
-#include "../common/util.qh"
.float scale;
.float alpha;
-#ifndef GIBS_H
-#define GIBS_H
+#ifndef CLIENT_GIBS_H
+#define CLIENT_GIBS_H
.vector colormod;
#include "hook.qh"
-#include "_all.qh"
-#include "hud.qh"
-
-#include "../common/teams.qh"
-
-#include "../csqcmodellib/interpolate.qh"
-
-#include "../warpzonelib/common.qh"
+#include "../lib/csqcmodel/interpolate.qh"
+#include "../lib/warpzone/common.qh"
entityclass(Hook);
class(Hook) .float HookType; // ENT_CLIENT_*
-#ifndef HOOK_H
-#define HOOK_H
+#ifndef CLIENT_HOOK_H
+#define CLIENT_HOOK_H
void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float theAlpha, float drawflag, vector vieworg);
#include "hud.qh"
-#include "_all.qh"
#include "hud_config.qh"
#include "mapvoting.qh"
#include "scoreboard.qh"
#include "teamradar.qh"
#include "t_items.qh"
-
-#include "../dpdefs/keycodes.qh"
-
#include "../common/buffs/all.qh"
-#include "../common/constants.qh"
#include "../common/deathtypes/all.qh"
#include "../common/items/all.qc"
#include "../common/mapinfo.qh"
-#include "../common/nades/all.qh"
-
#include "../common/mutators/mutator/waypoints/all.qh"
-#include "../server/mutators/gamemode_ctf.qh"
-
+#include "../common/nades/all.qh"
#include "../common/stats.qh"
-
-#include "../csqcmodellib/cl_player.qh"
+#include "../lib/csqcmodel/cl_player.qh"
+#include "../server/mutators/gamemode_ctf.qh"
/*
==================
*/
-// draw the background/borders
-#define HUD_Panel_DrawBg(theAlpha) do { \
- if(panel.current_panel_bg != "0" && panel.current_panel_bg != "") \
- draw_BorderPicture(panel_pos - '1 1 0' * panel_bg_border, panel.current_panel_bg, panel_size + '1 1 0' * 2 * panel_bg_border, panel_bg_color, panel_bg_alpha * theAlpha, '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER));\
-} while(0)
-
//basically the same code of draw_ButtonPicture and draw_VertButtonPicture for the menu
void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag)
{
reset_centerprint_messages();
if (time > hud_configure_cp_generation_time)
{
- if(HUD_PANEL(CENTERPRINT) == highlightedPanel)
+ if(highlightedPanel == HUD_PANEL(CENTERPRINT))
{
float r;
r = random();
// cache the panel order into the panel_order array
if(autocvar__hud_panelorder != hud_panelorder_prev) {
- for(i = 0; i < HUD_PANEL_NUM; ++i)
+ for(i = 0; i < hud_panels_COUNT; ++i)
panel_order[i] = -1;
string s = "";
int p_num;
bool warning = false;
int argc = tokenize_console(autocvar__hud_panelorder);
- if (argc > HUD_PANEL_NUM)
+ if (argc > hud_panels_COUNT)
warning = true;
//first detect wrong/missing panel numbers
- for(i = 0; i < HUD_PANEL_NUM; ++i) {
+ for(i = 0; i < hud_panels_COUNT; ++i) {
p_num = stoi(argv(i));
- if (p_num >= 0 && p_num < HUD_PANEL_NUM) { //correct panel number?
+ if (p_num >= 0 && p_num < hud_panels_COUNT) { //correct panel number?
if (panel_order[p_num] == -1) //found for the first time?
s = strcat(s, ftos(p_num), " ");
panel_order[p_num] = 1; //mark as found
else
warning = true;
}
- for(i = 0; i < HUD_PANEL_NUM; ++i) {
+ for(i = 0; i < hud_panels_COUNT; ++i) {
if (panel_order[i] == -1) {
warning = true;
s = strcat(s, ftos(i), " "); //add missing panel number
//now properly set panel_order
tokenize_console(s);
- for(i = 0; i < HUD_PANEL_NUM; ++i) {
+ for(i = 0; i < hud_panels_COUNT; ++i) {
panel_order[i] = stof(argv(i));
}
}
hud_draw_maximized = 0;
// draw panels in the order specified by panel_order array
- for(i = HUD_PANEL_NUM - 1; i >= 0; --i)
- HUD_Panel_Draw(hud_panel[panel_order[i]]);
+ for(i = hud_panels_COUNT - 1; i >= 0; --i)
+ HUD_Panel_Draw(hud_panels[panel_order[i]]);
hud_draw_maximized = 1; // panels that may be maximized must check this var
// draw maximized panels on top
-#ifndef HUD_H
-#define HUD_H
+#ifndef CLIENT_HUD_H
+#define CLIENT_HUD_H
#include "../common/weapons/all.qh"
-const int HUD_PANEL_MAX = 24;
-entity hud_panel[HUD_PANEL_MAX];
-const int HUD_PANEL_FIRST = 0;
-int HUD_PANEL_NUM;
-int HUD_PANEL_LAST;
+bool HUD_Radar_Clickable();
+void HUD_Radar_Mouse();
-int panel_order[HUD_PANEL_MAX];
+REGISTRY(hud_panels, 24)
+REGISTER_REGISTRY(Registerhud_panels)
+
+#define REGISTER_HUD_PANEL(id, draw_func, name, showflags) \
+ void draw_func(); \
+ REGISTER(Registerhud_panels, HUD_PANEL, hud_panels, id, m_id, new(hud_panel)) { \
+ this.panel_id = this.m_id; \
+ this.panel_draw = draw_func; \
+ this.panel_name = #name; \
+ this.panel_showflags = showflags; \
+ }
+
+#define HUD_PANEL(NAME) HUD_PANEL_##NAME
+
+// draw the background/borders
+#define HUD_Panel_DrawBg(theAlpha) do { \
+ if(panel.current_panel_bg != "0" && panel.current_panel_bg != "") \
+ draw_BorderPicture(panel_pos - '1 1 0' * panel_bg_border, panel.current_panel_bg, panel_size + '1 1 0' * 2 * panel_bg_border, panel_bg_color, panel_bg_alpha * theAlpha, '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER));\
+} while(0)
+
+int panel_order[hud_panels_MAX];
string hud_panelorder_prev;
bool hud_draw_maximized;
bool chat_panel_modified;
bool radar_panel_modified;
+float HUD_Radar_InputEvent(float bInputType, float nPrimary, float nSecondary);
void HUD_Radar_Hide_Maximized();
void HUD_Reset (void);
void HUD_ItemsTime();
-#define HUD_PANELS(HUD_PANEL) \
- HUD_PANEL(WEAPONS , HUD_Weapons , weapons, PANEL_SHOW_MAINGAME ) \
- HUD_PANEL(AMMO , HUD_Ammo , ammo, PANEL_SHOW_MAINGAME ) \
- HUD_PANEL(POWERUPS , HUD_Powerups , powerups, PANEL_SHOW_MAINGAME ) \
- HUD_PANEL(HEALTHARMOR , HUD_HealthArmor , healtharmor, PANEL_SHOW_MAINGAME ) \
- HUD_PANEL(NOTIFY , HUD_Notify , notify, PANEL_SHOW_ALWAYS ) \
- HUD_PANEL(TIMER , HUD_Timer , timer, PANEL_SHOW_ALWAYS ) \
- HUD_PANEL(RADAR , HUD_Radar , radar, PANEL_SHOW_MAINGAME ) \
- HUD_PANEL(SCORE , HUD_Score , score, PANEL_SHOW_ALWAYS ) \
- HUD_PANEL(RACETIMER , HUD_RaceTimer , racetimer, PANEL_SHOW_MAINGAME ) \
- HUD_PANEL(VOTE , HUD_Vote , vote, PANEL_SHOW_ALWAYS ) \
- HUD_PANEL(MODICONS , HUD_ModIcons , modicons, PANEL_SHOW_MAINGAME ) \
- HUD_PANEL(PRESSEDKEYS , HUD_PressedKeys , pressedkeys, PANEL_SHOW_MAINGAME ) \
- HUD_PANEL(CHAT , HUD_Chat , chat, PANEL_SHOW_ALWAYS ) \
- HUD_PANEL(ENGINEINFO , HUD_EngineInfo , engineinfo, PANEL_SHOW_ALWAYS ) \
- HUD_PANEL(INFOMESSAGES , HUD_InfoMessages , infomessages, PANEL_SHOW_MAINGAME ) \
- HUD_PANEL(PHYSICS , HUD_Physics , physics, PANEL_SHOW_MAINGAME ) \
- HUD_PANEL(CENTERPRINT , HUD_CenterPrint , centerprint, PANEL_SHOW_MAINGAME ) \
- HUD_PANEL(MINIGAME_BOARD, HUD_MinigameBoard ,minigameboard, PANEL_SHOW_MINIGAME ) \
- HUD_PANEL(MINIGAME_STATUS,HUD_MinigameStatus,minigamestatus,PANEL_SHOW_MINIGAME ) \
- HUD_PANEL(MINIGAME_HELP, HUD_MinigameHelp ,minigamehelp, PANEL_SHOW_MINIGAME ) \
- HUD_PANEL(MINIGAME_MENU, HUD_MinigameMenu ,minigamemenu, PANEL_SHOW_ALWAYS ) \
- HUD_PANEL(MAPVOTE , MapVote_Draw ,mapvote, PANEL_SHOW_ALWAYS ) \
- HUD_PANEL(ITEMSTIME , HUD_ItemsTime ,itemstime, PANEL_SHOW_MAINGAME ) \
- HUD_PANEL(QUICKMENU , HUD_QuickMenu , quickmenu, PANEL_SHOW_MAINGAME ) \
- // always add new panels to the end of list
-
-
-#define HUD_PANEL(NAME, draw_func, name, showflags) \
- int HUD_PANEL_##NAME; \
- void draw_func(void); \
- void RegisterHUD_Panel_##NAME() { \
- HUD_PANEL_LAST = HUD_PANEL_##NAME = HUD_PANEL_NUM; \
- entity hud_panelent = spawn(); \
- hud_panel[HUD_PANEL_##NAME] = hud_panelent; \
- hud_panelent.classname = "hud_panel"; \
- hud_panelent.panel_name = #name; \
- hud_panelent.panel_id = HUD_PANEL_##NAME; \
- hud_panelent.panel_draw = draw_func; \
- hud_panelent.panel_showflags = showflags; \
- HUD_PANEL_NUM++; \
- } \
- ACCUMULATE_FUNCTION(RegisterHUD_Panels, RegisterHUD_Panel_##NAME)
-
-HUD_PANELS(HUD_PANEL)
-#undef HUD_PANEL
-
-#define HUD_PANEL(NAME) hud_panel[HUD_PANEL_##NAME]
-
+REGISTER_HUD_PANEL(WEAPONS, HUD_Weapons, weapons, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(AMMO, HUD_Ammo, ammo, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(POWERUPS, HUD_Powerups, powerups, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(HEALTHARMOR, HUD_HealthArmor, healtharmor, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(NOTIFY, HUD_Notify, notify, PANEL_SHOW_ALWAYS )
+REGISTER_HUD_PANEL(TIMER, HUD_Timer, timer, PANEL_SHOW_ALWAYS )
+REGISTER_HUD_PANEL(RADAR, HUD_Radar, radar, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(SCORE, HUD_Score, score, PANEL_SHOW_ALWAYS )
+REGISTER_HUD_PANEL(RACETIMER, HUD_RaceTimer, racetimer, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(VOTE, HUD_Vote, vote, PANEL_SHOW_ALWAYS )
+REGISTER_HUD_PANEL(MODICONS, HUD_ModIcons, modicons, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(PRESSEDKEYS, HUD_PressedKeys, pressedkeys, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(CHAT, HUD_Chat, chat, PANEL_SHOW_ALWAYS )
+REGISTER_HUD_PANEL(ENGINEINFO, HUD_EngineInfo, engineinfo, PANEL_SHOW_ALWAYS )
+REGISTER_HUD_PANEL(INFOMESSAGES, HUD_InfoMessages, infomessages, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(PHYSICS, HUD_Physics, physics, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(CENTERPRINT, HUD_CenterPrint, centerprint, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(MINIGAME_BOARD, HUD_MinigameBoard, minigameboard, PANEL_SHOW_MINIGAME)
+REGISTER_HUD_PANEL(MINIGAME_STATUS, HUD_MinigameStatus, minigamestatus, PANEL_SHOW_MINIGAME)
+REGISTER_HUD_PANEL(MINIGAME_HELP, HUD_MinigameHelp, minigamehelp, PANEL_SHOW_MINIGAME)
+REGISTER_HUD_PANEL(MINIGAME_MENU, HUD_MinigameMenu, minigamemenu, PANEL_SHOW_ALWAYS )
+REGISTER_HUD_PANEL(MAPVOTE, MapVote_Draw, mapvote, PANEL_SHOW_ALWAYS )
+REGISTER_HUD_PANEL(ITEMSTIME, HUD_ItemsTime, itemstime, PANEL_SHOW_MAINGAME)
+REGISTER_HUD_PANEL(QUICKMENU, HUD_QuickMenu, quickmenu, PANEL_SHOW_MAINGAME)
+// always add new panels to the end of list
// Because calling lots of functions in QC apparently cuts fps in half on many machines:
// ----------------------
#include "hud_config.qh"
-#include "_all.qh"
#include "hud.qh"
-#include "../common/constants.qh"
-
-#include "../dpdefs/keycodes.qh"
-
-
#define HUD_Write(s) fputs(fh, s)
// q: quoted, n: not quoted
#define HUD_Write_Cvar_n(cvar) HUD_Write(strcat("seta ", cvar, " ", cvar_string(cvar), "\n"))
HUD_Write("\n");
// common cvars for all panels
- int i;
- for (i = 0; i < HUD_PANEL_NUM; ++i)
+ for (int i = 0; i < hud_panels_COUNT; ++i)
{
- panel = hud_panel[i];
+ panel = hud_panels[i];
HUD_Write_PanelCvar_n("");
HUD_Write_PanelCvar_q("_pos");
HUD_Write_PanelCvar_q("_bg_alpha");
HUD_Write_PanelCvar_q("_bg_border");
HUD_Write_PanelCvar_q("_bg_padding");
- switch(i) {
+ switch(panel) {
case HUD_PANEL_WEAPONS:
HUD_Write_PanelCvar_q("_accuracy");
HUD_Write_PanelCvar_q("_label");
vector myCenter, targCenter;
vector myTarget = myPos;
int i;
- for (i = 0; i < HUD_PANEL_NUM; ++i) {
- panel = hud_panel[i];
+ for (i = 0; i < hud_panels_COUNT; ++i) {
+ panel = hud_panels[i];
if(panel == HUD_PANEL(MAPVOTE)) continue;
if(panel == highlightedPanel) continue;
HUD_Panel_UpdatePosSize();
vector dist;
float ratio = mySize.x/mySize.y;
int i;
- for (i = 0; i < HUD_PANEL_NUM; ++i) {
- panel = hud_panel[i];
+ for (i = 0; i < hud_panels_COUNT; ++i) {
+ panel = hud_panels[i];
if(panel == HUD_PANEL(MAPVOTE)) continue;
if(panel == highlightedPanel) continue;
HUD_Panel_UpdatePosSize();
}
void HUD_Panel_EnableMenu();
-entity tab_panels[HUD_PANEL_MAX];
+entity tab_panels[hud_panels_MAX];
entity tab_panel;
vector tab_panel_pos;
float tab_backward;
void reset_tab_panels()
{
int i;
- for(i = 0; i < HUD_PANEL_NUM; ++i)
+ for(i = 0; i < hud_panels_COUNT; ++i)
tab_panels[i] = world;
}
float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary)
k=0;
while(++k)
{
- for(i = 0; i < HUD_PANEL_NUM; ++i)
+ for(i = 0; i < hud_panels_COUNT; ++i)
{
- panel = hud_panel[i];
+ panel = hud_panels[i];
if(panel == HUD_PANEL(MAPVOTE))
continue;
if (panel == tab_panels[i] || panel == starting_panel)
float HUD_Panel_Check_Mouse_Pos(float allow_move)
{
int i, j = 0;
- while(j < HUD_PANEL_NUM)
+ while(j < hud_panels_COUNT)
{
i = panel_order[j];
j += 1;
- panel = hud_panel[i];
+ panel = hud_panels[i];
if(panel == HUD_PANEL(MAPVOTE)) continue;
HUD_Panel_UpdatePosSize();
int i;
int place = -1;
// find out where in the array our current id is, save into place
- for(i = 0; i < HUD_PANEL_NUM; ++i)
+ for(i = 0; i < hud_panels_COUNT; ++i)
{
if(panel_order[i] == id)
{
}
// place last if we didn't find a place for it yet (probably new panel, or screwed up cvar)
if(place == -1)
- place = HUD_PANEL_NUM - 1;
+ place = hud_panels_COUNT - 1;
// move all ids up by one step in the array until "place"
for(i = place; i > 0; --i)
// let's save them into the cvar by some strcat trickery
string s = "";
- for(i = 0; i < HUD_PANEL_NUM; ++i)
+ for(i = 0; i < hud_panels_COUNT; ++i)
{
s = strcat(s, ftos(panel_order[i]), " ");
}
{
int i, j = 0;
- while(j < HUD_PANEL_NUM)
+ while(j < hud_panels_COUNT)
{
i = panel_order[j];
j += 1;
- panel = hud_panel[i];
+ panel = hud_panels[i];
if(panel == HUD_PANEL(MAPVOTE))
continue;
HUD_Panel_UpdatePosSize();
// move
if(allow_move && mousepos.x > panel_pos.x && mousepos.y > panel_pos.y && mousepos.x < panel_pos.x + panel_size.x && mousepos.y < panel_pos.y + panel_size.y)
{
- highlightedPanel = hud_panel[i];
+ highlightedPanel = hud_panels[i];
HUD_Panel_FirstInDrawQ(i);
highlightedAction = 1;
panel_click_distance = mousepos - panel_pos;
// resize from topleft border
else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
{
- highlightedPanel = hud_panel[i];
+ highlightedPanel = hud_panels[i];
HUD_Panel_FirstInDrawQ(i);
highlightedAction = 2;
resizeCorner = 1;
// resize from topright border
else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
{
- highlightedPanel = hud_panel[i];
+ highlightedPanel = hud_panels[i];
HUD_Panel_FirstInDrawQ(i);
highlightedAction = 2;
resizeCorner = 2;
// resize from bottomleft border
else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + panel_size.y + border)
{
- highlightedPanel = hud_panel[i];
+ highlightedPanel = hud_panels[i];
HUD_Panel_FirstInDrawQ(i);
highlightedAction = 2;
resizeCorner = 3;
// resize from bottomright border
else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + panel_size.y + border)
{
- highlightedPanel = hud_panel[i];
+ highlightedPanel = hud_panels[i];
HUD_Panel_FirstInDrawQ(i);
highlightedAction = 2;
resizeCorner = 4;
if(autocvar_hud_cursormode)
setcursormode(1);
hudShiftState = 0;
- for(i = HUD_PANEL_NUM - 1; i >= 0; --i)
- hud_panel[panel_order[i]].update_time = time;
+ for(i = hud_panels_COUNT - 1; i >= 0; --i)
+ hud_panels[panel_order[i]].update_time = time;
}
// NOTE this check is necessary because _menu_alpha isn't updated the frame the menu gets enabled
-#ifndef HUD_CONFIG_H
-#define HUD_CONFIG_H
+#ifndef CLIENT_HUD_CONFIG_H
+#define CLIENT_HUD_CONFIG_H
const int S_MOUSE1 = 1;
const int S_MOUSE2 = 2;
#include "laser.qh"
-#include "_all.qh"
-#include "hook.qh"
-
-#include "../common/buffs/all.qh"
-
-#include "../csqcmodellib/cl_model.qh"
-#include "../csqcmodellib/interpolate.qh"
+#include "../lib/csqcmodel/interpolate.qh"
// a laser goes from origin in direction angles
// it has color 'colormod'
-#ifndef LASER_H
-#define LASER_H
+#ifndef CLIENT_LASER_H
+#define CLIENT_LASER_H
void Ent_Laser();
#include "main.qh"
-#include "_all.qh"
#include "controlpoint.qh"
#include "damage.qh"
#include "laser.qh"
#include "mapvoting.qh"
#include "modeleffects.qh"
+#include "mutators/events.qh"
#include "particles.qh"
+#include "quickmenu.qh"
#include "scoreboard.qh"
#include "shownames.qh"
#include "tuba.qh"
#include "t_items.qh"
#include "wall.qh"
-
-#include "../common/vehicles/all.qh"
-
-#include "mutators/events.qh"
-
#include "weapons/projectile.qh"
-
-#include "../common/buffs/all.qh"
#include "../common/deathtypes/all.qh"
-#include "../common/effects/effects.qh"
+#include "../common/items/all.qh"
#include "../common/mapinfo.qh"
-#include "../common/monsters/all.qh"
-#include "../common/nades/all.qh"
+#include "../common/minigames/cl_minigames.qh"
+#include "../common/minigames/cl_minigames_hud.qh"
#include "../common/net_notice.qh"
-#include "../common/notifications.qh"
-#include "../common/stats.qh"
-#include "../common/teams.qh"
-
-#include "../common/items/all.qh"
-
-#include "../common/mutators/base.qh"
-
-#include "../common/weapons/all.qh"
-
-#include "../csqcmodellib/cl_model.qh"
-#include "../csqcmodellib/interpolate.qh"
-
#include "../common/triggers/include.qh"
-
#include "../common/turrets/cl_turrets.qh"
-
-#include "../warpzonelib/client.qh"
+#include "../common/vehicles/all.qh"
+#include "../lib/csqcmodel/cl_model.qh"
+#include "../lib/csqcmodel/interpolate.qh"
+#include "../lib/warpzone/client.qh"
// --------------------------------------------------------------------------
// BEGIN REQUIRED CSQC FUNCTIONS
// needs to be done so early because of the constants they create
static_init();
- CALL_ACCUMULATED_FUNCTION(RegisterHUD_Panels);
// precaches
-#ifndef MAIN_H
-#define MAIN_H
+#ifndef CLIENT_MAIN_H
+#define CLIENT_MAIN_H
#include "../common/constants.qh"
#include "mapvoting.qh"
-#include "_all.qh"
#include "hud.qh"
#include "scoreboard.qh"
#include "../common/mapinfo.qh"
-#include "../common/util.qh"
-
-#include "../dpdefs/keycodes.qh"
int mv_num_maps;
-#ifndef MAPVOTING_H
-#define MAPVOTING_H
+#ifndef CLIENT_MAPVOTING_H
+#define CLIENT_MAPVOTING_H
#include "../common/constants.qh"
void MapVote_Draw();
#include "miscfunctions.qh"
-#include "_all.qh"
#include "hud.qh"
#include "../common/command/generic.qh"
#include "../common/teams.qh"
-#include "../common/util.qh"
-#include "../csqcmodellib/cl_model.qh"
+#include "../lib/csqcmodel/cl_model.qh"
void AuditLists()
-#ifndef MISCFUNCTIONS_H
-#define MISCFUNCTIONS_H
+#ifndef CLIENT_MISCFUNCTIONS_H
+#define CLIENT_MISCFUNCTIONS_H
entity players;
entity teams;
#include "modeleffects.qh"
-#include "_all.qh"
.float cnt;
.float scale;
-#ifndef MODELEFFECTS_H
-#define MODELEFFECTS_H
+#ifndef CLIENT_MODELEFFECTS_H
+#define CLIENT_MODELEFFECTS_H
entityclass(ModelEffect);
class(ModelEffect) .float frame1time;
#include "particles.qh"
-#include "_all.qh"
#include "../common/stats.qh"
-#include "../common/util.qh"
-#include "../warpzonelib/common.qh"
+#include "../lib/warpzone/common.qh"
void Net_ReadVortexBeamParticle()
{
-#ifndef PARTICLES_H
-#define PARTICLES_H
+#ifndef CLIENT_PARTICLES_H
+#define CLIENT_PARTICLES_H
.int dphitcontentsmask;
entityclass(PointParticles);
#include "player_skeleton.qh"
-#include "../common/csqcmodel_settings.qh"
+#include "mutators/events.qh"
+#include "../lib/csqcmodel/cl_player.qh"
+#include "../lib/warpzone/anglestransform.qh"
-#include "../warpzonelib/anglestransform.qh"
+.vector v_angle;
class(Skeleton) .float skeleton_info_modelindex;
class(Skeleton) .float skeleton_info_skin;
-#ifndef PLAYER_SKELETON
-#define PLAYER_SKELETON
-
-#include "../common/util.qh"
+#ifndef CLIENT_PLAYER_SKELETON
+#define CLIENT_PLAYER_SKELETON
void free_skeleton_from_frames(entity e);
void skeleton_from_frames(entity e, float is_dead);
-#include "../common/util-pre.qh"
-#include "../dpdefs/csprogsdefs.qh"
-#include "../common/util-post.qh"
-
#include "../lib/_all.inc"
+#include "_all.qh"
#include "announcer.qc"
#include "bgmscript.qc"
#include "view.qc"
#include "wall.qc"
-#include "command/all.qc"
+#include "commands/all.qc"
#include "weapons/projectile.qc" // TODO
#include "../common/animdecide.qc"
-#include "../common/effects/effects.qc"
#include "../common/effects/effectinfo.qc"
#include "../common/mapinfo.qc"
#include "../common/movetypes/include.qc"
#include "../common/buffs/all.qc"
#include "../common/deathtypes/all.qc"
+#include "../common/effects/all.qc"
+#include "../common/gamemodes/all.qc"
#include "../common/items/all.qc"
#include "../common/monsters/all.qc"
#include "../common/mutators/all.qc"
#include "../common/triggers/include.qc"
-#include "../csqcmodellib/cl_model.qc"
-#include "../csqcmodellib/cl_player.qc"
-#include "../csqcmodellib/interpolate.qc"
+#include "../lib/csqcmodel/cl_model.qc"
+#include "../lib/csqcmodel/cl_player.qc"
+#include "../lib/csqcmodel/interpolate.qc"
#include "../server/mutators/mutator_multijump.qc"
-#include "../warpzonelib/anglestransform.qc"
-#include "../warpzonelib/client.qc"
-#include "../warpzonelib/common.qc"
-#include "../warpzonelib/util_server.qc"
+#include "../lib/warpzone/anglestransform.qc"
+#include "../lib/warpzone/client.qc"
+#include "../lib/warpzone/common.qc"
+#include "../lib/warpzone/util_server.qc"
#if BUILD_MOD
#include "../../mod/client/progs.inc"
-#include "_all.qh"
+#include "quickmenu.qh"
+#include "hud.qh"
#include "hud_config.qh"
-
-#include "../dpdefs/keycodes.qh"
+#include "mapvoting.qh"
// QUICKMENU_MAXLINES must be <= 10
const int QUICKMENU_MAXLINES = 10;
--- /dev/null
+#ifndef CLIENT_QUICKMENU_H
+#define CLIENT_QUICKMENU_H
+
+bool QuickMenu_InputEvent(float bInputType, float nPrimary, float nSecondary);
+bool QuickMenu_IsOpened();
+void QuickMenu_Mouse();
+
+#endif
-#ifndef RUBBLE_H
-#define RUBBLE_H
+#ifndef CLIENT_RUBBLE_H
+#define CLIENT_RUBBLE_H
entityclass(Rubble);
class(Rubble) .float creationtime;
void RubbleLimit(string cname, float limit, void() deleteproc);
#include "scoreboard.qh"
-#include "_all.qh"
+#include "quickmenu.qh"
#include "hud.qh"
#include "../common/constants.qh"
#include "../common/minigames/cl_minigames.qh"
#include "../common/stats.qh"
#include "../common/teams.qh"
-#include "../common/util.qh"
float scoreboard_alpha_bg;
float scoreboard_alpha_fg;
-#ifndef SCOREBOARD_H
-#define SCOREBOARD_H
+#ifndef CLIENT_SCOREBOARD_H
+#define CLIENT_SCOREBOARD_H
float xmin, xmax, ymin, ymax, sbwidth;
#include "shownames.qh"
-#include "_all.qh"
#include "hud.qh"
#include "../common/constants.qh"
#include "../common/mapinfo.qh"
#include "../common/teams.qh"
-#include "../common/util.qh"
-#include "../csqcmodellib/cl_model.qh"
+#include "../lib/csqcmodel/cl_model.qh"
// self.isactive = player is in range and coordinates/status (health and armor) are up to date
// self.origin = player origin TODO: should maybe move this so it's the origin of the shownames tag already in SSQC for culling?
-#ifndef SHOWNAMES_H
-#define SHOWNAMES_H
+#ifndef CLIENT_SHOWNAMES_H
+#define CLIENT_SHOWNAMES_H
entityclass(ShowNames);
class(ShowNames) .float healthvalue;
-#include "_all.qh"
#include "../common/buffs/all.qh"
#include "../common/movetypes/movetypes.qh"
-#include "../common/util.qh"
#include "../common/weapons/all.qh"
-#include "../csqcmodellib/cl_model.qh"
-#include "../csqcmodellib/common.qh"
+#include "../lib/csqcmodel/cl_model.qh"
+#include "../lib/csqcmodel/common.qh"
#include "../server/t_items.qc"
#include "teamradar.qh"
-#include "_all.qh"
#include "hud.qh"
-#include "../common/util.qh"
+#include "../common/mutators/mutator/waypoints/all.qh"
-#include "../csqcmodellib/interpolate.qh"
+#include "../lib/csqcmodel/interpolate.qh"
vector teamradar_3dcoord_to_texcoord(vector in)
{
-#ifndef TEAMRADAR_H
-#define TEAMRADAR_H
+#ifndef CLIENT_TEAMRADAR_H
+#define CLIENT_TEAMRADAR_H
const int MAX_TEAMRADAR_TIMES = 32;
#include "tuba.qh"
-#include "_all.qh"
#include "../common/constants.qh"
-#include "../common/util.qh"
#define TUBA_STARTNOTE(i, n) W_Sound(strcat("tuba", (i ? ftos(i) : ""), "_loopnote", ftos(n)))
-#ifndef TUBA_H
-#define TUBA_H
+#ifndef CLIENT_TUBA_H
+#define CLIENT_TUBA_H
void Ent_TubaNote(bool isNew);
void Tuba_Precache();
-#include "_all.qh"
#include "announcer.qh"
#include "hook.qh"
#include "mapvoting.qh"
#include "scoreboard.qh"
#include "shownames.qh"
+#include "quickmenu.qh"
#include "mutators/events.qh"
#include "../common/constants.qh"
#include "../common/mapinfo.qh"
+#include "../common/gamemodes/all.qh"
#include "../common/nades/all.qh"
#include "../common/stats.qh"
#include "../common/triggers/target/music.qh"
#include "../common/teams.qh"
-#include "../common/util.qh"
+#include "../common/vehicles/all.qh"
#include "../common/weapons/all.qh"
+#include "../common/viewloc.qh"
+#include "../common/minigames/cl_minigames.qh"
+#include "../common/minigames/cl_minigames_hud.qh"
-#include "../csqcmodellib/cl_player.qh"
+#include "../lib/csqcmodel/cl_player.qh"
-#include "../warpzonelib/client.qh"
-#include "../warpzonelib/common.qh"
+#include "../lib/warpzone/client.qh"
+#include "../lib/warpzone/common.qh"
entity porto;
vector polyline[16];
entity e;
float fov;
float f;
- int i;
vector vf_size, vf_min;
float a;
if(myteam != prev_myteam)
{
myteamcolors = colormapPaletteColor(myteam, 1);
- for(i = 0; i < HUD_PANEL_NUM; ++i)
- hud_panel[i].update_time = time;
+ FOREACH(hud_panels, true, LAMBDA(it.update_time = time));
prev_myteam = myteam;
}
#include "wall.qh"
-#include "_all.qh"
#include "bgmscript.qh"
-#include "../common/util.qh"
-#include "../csqcmodellib/interpolate.qh"
+#include "../lib/csqcmodel/interpolate.qh"
.float alpha;
.float scale;
-#ifndef WALL_H
-#define WALL_H
+#ifndef CLIENT_WALL_H
+#define CLIENT_WALL_H
entityclass(Wall);
class(Wall) .float lip;
#include "../autocvars.qh"
#include "../defs.qh"
#include "../main.qh"
+#include "../mutators/events.qh"
#include "../../common/constants.qh"
#include "../../common/nades/all.qh"
#include "../../common/movetypes/movetypes.qh"
-#include "../../common/util.qh"
-#include "../../csqcmodellib/interpolate.qh"
+#include "../../lib/csqcmodel/interpolate.qh"
-#include "../../warpzonelib/anglestransform.qh"
+#include "../../lib/warpzone/anglestransform.qh"
.float alpha;
.float scale;
-#ifndef PROJECTILE_H
-#define PROJECTILE_H
+#ifndef CLIENT_WEAPONS_PROJECTILE_H
+#define CLIENT_WEAPONS_PROJECTILE_H
entityclass(Projectile);
class(Projectile) .int traileffect;
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "animdecide.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
+#include "animdecide.qh"
+
+#include "monsters/all.qh"
+
+#if defined(SVQC)
#include "util.qh"
- #include "animdecide.qh"
#include "../server/defs.qh"
#endif
#if defined(CSQC)
- #include "../../dpdefs/csprogsdefs.qh"
#include "../../client/defs.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
#endif
#include "all.qh"
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
#include "util.qh"
#include "campaign_common.qh"
#endif
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
#include "campaign_common.qh"
#include "mapinfo.qh"
#endif
#ifndef COMMON_COMMANDS_ALL_H
#define COMMON_COMMANDS_ALL_H
+#include "command.qh"
+REGISTRY(GENERIC_COMMANDS, 50)
+REGISTER_REGISTRY(RegisterGENERIC_COMMANDS)
+REGISTRY_SORT(GENERIC_COMMANDS, m_name, 0)
+
+#define GENERIC_COMMAND(id, description) \
+ CLASS(genericcommand_##id, Command) \
+ ATTRIB(genericcommand_##id, m_name, string, #id); \
+ ATTRIB(genericcommand_##id, m_description, string, description); \
+ ENDCLASS(genericcommand_##id) \
+ REGISTER(RegisterGENERIC_COMMANDS, CMD_G, GENERIC_COMMANDS, id, m_id, NEW(genericcommand_##id)); \
+ METHOD(genericcommand_##id, m_invokecmd, void(int request, int arguments, string command))
+
+STATIC_INIT(GENERIC_COMMANDS_aliases) {
+ FOREACH(GENERIC_COMMANDS, true, LAMBDA(localcmd(sprintf("alias %1$s \"%2$s %1$s ${* ?}\"\n", it.m_name, "qc_cmd_svmenu"))));
+}
+
#include "generic.qh"
#include "markup.qh"
#include "rpn.qh"
#ifndef COMMAND_H
#define COMMAND_H
-// =========================================================
-// Shared declarations for all commands, written by Samual
-// Last updated: December 13th, 2011
-// =========================================================
-
-// identifiers for subfunction requests by the command code structure
const int CMD_REQUEST_COMMAND = 1;
const int CMD_REQUEST_USAGE = 2;
+
+CLASS(Command, Object)
+ ATTRIB(Command, m_name, string, string_null);
+ ATTRIB(Command, m_description, string, string_null);
+ METHOD(Command, m_invokecmd, void(int request, int arguments, string command)) { }
+ENDCLASS(Command)
+
#endif
-#include "command.qh"
-#include "generic.qh"
+#include "all.qh"
#include "markup.qh"
#include "rpn.qh"
#endif
#ifdef CSQC
- #include "../../client/command/cl_cmd.qh"
+ #include "../../client/commands/cl_cmd.qh"
#endif
#ifdef SVQC
}
}
-void GenericCommand_dumpcommands(float request)
+GENERIC_COMMAND(dumpcommands, "Dump all commands on the program to *_cmd_dump.txt")
{
switch(request)
{
}
}
-#ifndef MENUQC
-void effectinfo_dump(int fh, bool alsoprint);
-#endif
-void GenericCommand_dumpeffectinfo(float request)
-{
- switch (request) {
- case CMD_REQUEST_COMMAND: {
- #ifndef MENUQC
- string filename = argv(1);
- bool alsoprint = false;
- if (filename == "") {
- filename = "effectinfo_dump.txt";
- alsoprint = false;
- } else if (filename == "-") {
- filename = "effectinfo_dump.txt";
- alsoprint = true;
- }
- int fh = fopen(filename, FILE_WRITE);
- if (fh >= 0) {
- effectinfo_dump(fh, alsoprint);
- LOG_INFOF("Dumping effectinfo... File located at ^2data/data/%s^7.\n", filename);
- LOG_INFOF("Reload with ^2cl_particles_reloadeffects data/%s^7.\n", filename);
- fclose(fh);
- } else {
- LOG_WARNINGF("Could not open file '%s'!\n", filename);
- }
- #else
- LOG_INFO(_("Effectinfo dump command only works with cl_cmd and sv_cmd.\n"));
- #endif
- return;
- }
- default:
- case CMD_REQUEST_USAGE: {
- LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpeffectinfo [filename]"));
- LOG_INFO(" Where 'filename' is the file to write (default is effectinfo_dump.txt),\n");
- LOG_INFO(" if supplied with '-' output to console as well as default,\n");
- LOG_INFO(" if left blank, it will only write to default.\n");
- return;
- }
- }
-}
-STATIC_INIT(dumpeffectinfo) { localcmd("alias dumpeffectinfo \"qc_cmd_svcl dumpeffectinfo ${* ?}\"\n"); }
-
-void GenericCommand_dumpitems(float request)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- Dump_Items();
- return;
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- LOG_INFOF("\nUsage:^3 %s dumpitems", GetProgramCommandPrefix());
- return;
- }
- }
-}
-
-void GenericCommand_dumpnotifs(float request)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- #ifndef MENUQC
- float fh, alsoprint = false;
- string filename = argv(1);
-
- if(filename == "")
- {
- filename = "notifications_dump.cfg";
- alsoprint = false;
- }
- else if(filename == "-")
- {
- filename = "notifications_dump.cfg";
- alsoprint = true;
- }
- fh = fopen(filename, FILE_WRITE);
-
- if(fh >= 0)
- {
- Dump_Notifications(fh, alsoprint);
- LOG_INFOF("Dumping notifications... File located in ^2data/data/%s^7.\n", filename);
- fclose(fh);
- }
- else
- {
- LOG_INFOF("^1Error: ^7Could not open file '%s'!\n", filename);
- }
- #else
- LOG_INFO(_("Notification dump command only works with cl_cmd and sv_cmd.\n"));
- #endif
- return;
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpnotifs [filename]"));
- LOG_INFO(" Where 'filename' is the file to write (default is notifications_dump.cfg),\n");
- LOG_INFO(" if supplied with '-' output to console as well as default,\n");
- LOG_INFO(" if left blank, it will only write to default.\n");
- return;
- }
- }
-}
-
-void GenericCommand_dumpweapons(float request) // WEAPONTODO: make this work with other progs than just server
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- #ifdef SVQC
- wep_config_file = -1;
- wep_config_alsoprint = -1;
- string filename = argv(1);
-
- if(filename == "")
- {
- filename = "weapons_dump.cfg";
- wep_config_alsoprint = false;
- }
- else if(filename == "-")
- {
- filename = "weapons_dump.cfg";
- wep_config_alsoprint = true;
- }
- wep_config_file = fopen(filename, FILE_WRITE);
-
- if(wep_config_file >= 0)
- {
- Dump_Weapon_Settings();
- LOG_INFO(sprintf("Dumping weapons... File located in ^2data/data/%s^7.\n", filename));
- fclose(wep_config_file);
- wep_config_file = -1;
- wep_config_alsoprint = -1;
- }
- else
- {
- LOG_INFO(sprintf("^1Error: ^7Could not open file '%s'!\n", filename));
- }
- #else
- LOG_INFO(_("Weapons dump command only works with sv_cmd.\n"));
- #endif
- return;
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpweapons [filename]"));
- LOG_INFO(" Where 'filename' is the file to write (default is weapons_dump.cfg),\n");
- LOG_INFO(" if supplied with '-' output to console as well as default,\n");
- LOG_INFO(" if left blank, it will only write to default.\n");
- return;
- }
- }
-}
-
-void GenericCommand_dumpturrets(float request)
-{
- switch(request)
- {
- case CMD_REQUEST_COMMAND:
- {
- #ifdef SVQC
- tur_config_file = -1;
- tur_config_alsoprint = -1;
- string filename = argv(1);
-
- if(filename == "")
- {
- filename = "turrets_dump.cfg";
- tur_config_alsoprint = FALSE;
- }
- else if(filename == "-")
- {
- filename = "turrets_dump.cfg";
- tur_config_alsoprint = TRUE;
- }
- tur_config_file = fopen(filename, FILE_WRITE);
-
- if(tur_config_file >= 0)
- {
- Dump_Turret_Settings();
- LOG_INFO(sprintf("Dumping turrets... File located in ^2data/data/%s^7.\n", filename));
- fclose(tur_config_file);
- tur_config_file = -1;
- tur_config_alsoprint = -1;
- }
- else
- {
- LOG_INFO(sprintf("^1Error: ^7Could not open file '%s'!\n", filename));
- }
- #else
- LOG_INFO(_("Turrets dump command only works with sv_cmd.\n"));
- #endif
- return;
- }
-
- default:
- case CMD_REQUEST_USAGE:
- {
- LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpturrets [filename]"));
- LOG_INFO(" Where 'filename' is the file to write (default is turrets_dump.cfg),\n");
- LOG_INFO(" if supplied with '-' output to console as well as default,\n");
- LOG_INFO(" if left blank, it will only write to default.\n");
- return;
- }
- }
-}
-
void GenericCommand_maplist(float request, float argc)
{
switch(request)
}
*/
-// ==================================
-// Macro system for server commands
-// ==================================
-
// Do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;)
-#define GENERIC_COMMANDS(request,arguments,command) \
- GENERIC_COMMAND("addtolist", GenericCommand_addtolist(request, arguments), "Add a string to a cvar") \
- GENERIC_COMMAND("dumpcommands", GenericCommand_dumpcommands(request), "Dump all commands on the program to *_cmd_dump.txt") \
- GENERIC_COMMAND("dumpeffectinfo", GenericCommand_dumpeffectinfo(request), "Dump all effectinfo to effectinfo_dump.txt") \
- GENERIC_COMMAND("dumpitems", GenericCommand_dumpitems(request), "Dump all items to the console") \
- GENERIC_COMMAND("dumpnotifs", GenericCommand_dumpnotifs(request), "Dump all notifications into notifications_dump.txt") \
- GENERIC_COMMAND("dumpturrets", GenericCommand_dumpturrets(request), "Dump all turrets into turrets_dump.txt") \
- GENERIC_COMMAND("dumpweapons", GenericCommand_dumpweapons(request), "Dump all weapons into weapons_dump.txt") \
- GENERIC_COMMAND("maplist", GenericCommand_maplist(request, arguments), "Automatic control of maplist") \
- GENERIC_COMMAND("nextframe", GenericCommand_nextframe(request, arguments, command), "Execute the given command next frame of this VM") \
- GENERIC_COMMAND("qc_curl", GenericCommand_qc_curl(request, arguments), "Queries a URL") \
- GENERIC_COMMAND("removefromlist", GenericCommand_removefromlist(request, arguments), "Remove a string from a cvar") \
- GENERIC_COMMAND("restartnotifs", GenericCommand_restartnotifs(request), "Re-initialize all notifications") \
- GENERIC_COMMAND("rpn", GenericCommand_rpn(request, arguments, command), "RPN calculator") \
- GENERIC_COMMAND("settemp", GenericCommand_settemp(request, arguments), "Temporarily set a value to a cvar which is restored later") \
- GENERIC_COMMAND("settemp_restore", GenericCommand_settemp_restore(request, arguments), "Restore all cvars set by settemp command") \
- GENERIC_COMMAND("runtest", GenericCommand_runtest(request, arguments), "Run unit tests") \
- /* nothing */
+GENERIC_COMMAND(addtolist, "Add a string to a cvar") { GenericCommand_addtolist(request, arguments); }
+GENERIC_COMMAND(maplist, "Automatic control of maplist") { GenericCommand_maplist(request, arguments); }
+GENERIC_COMMAND(nextframe, "Execute the given command next frame of this VM") { GenericCommand_nextframe(request, arguments, command); }
+GENERIC_COMMAND(qc_curl, "Queries a URL") { GenericCommand_qc_curl(request, arguments); }
+GENERIC_COMMAND(removefromlist, "Remove a string from a cvar") { GenericCommand_removefromlist(request, arguments); }
+GENERIC_COMMAND(restartnotifs, "Re-initialize all notifications") { GenericCommand_restartnotifs(request); }
+GENERIC_COMMAND(rpn, "RPN calculator") { GenericCommand_rpn(request, arguments, command); }
+GENERIC_COMMAND(settemp, "Temporarily set a value to a cvar which is restored later") { GenericCommand_settemp(request, arguments); }
+GENERIC_COMMAND(settemp_restore, "Restore all cvars set by settemp command") { GenericCommand_settemp_restore(request, arguments); }
+GENERIC_COMMAND(runtest, "Run unit tests") { GenericCommand_runtest(request, arguments); }
void GenericCommand_macro_help()
{
- #define GENERIC_COMMAND(name,function,description) \
- { LOG_INFO(" ^2", name, "^7: ", description, "\n"); }
-
- GENERIC_COMMANDS(0, 0, "");
- #undef GENERIC_COMMAND
-
- return;
+ FOREACH(GENERIC_COMMANDS, true, LAMBDA(LOG_INFOF(" ^2%s^7: %s\n", it.m_name, it.m_description)));
}
float GenericCommand_macro_command(float argc, string command)
{
- #define GENERIC_COMMAND(name,function,description) \
- { if(name == strtolower(argv(0))) { function; return true; } }
-
- GENERIC_COMMANDS(CMD_REQUEST_COMMAND, argc, command);
- #undef GENERIC_COMMAND
-
+ string c = strtolower(argv(0));
+ FOREACH(GENERIC_COMMANDS, it.m_name == c, LAMBDA(
+ it.m_invokecmd(CMD_REQUEST_COMMAND, argc, command);
+ return true;
+ ));
return false;
}
float GenericCommand_macro_usage(float argc)
{
- #define GENERIC_COMMAND(name,function,description) \
- { if(name == strtolower(argv(1))) { function; return true; } }
-
- GENERIC_COMMANDS(CMD_REQUEST_USAGE, argc, "");
- #undef GENERIC_COMMAND
-
+ string c = strtolower(argv(1));
+ FOREACH(GENERIC_COMMANDS, it.m_name == c, LAMBDA(
+ it.m_invokecmd(CMD_REQUEST_USAGE, argc, "");
+ return true;
+ ));
return false;
}
void GenericCommand_macro_write_aliases(float fh)
{
- #define GENERIC_COMMAND(name,function,description) \
- { CMD_Write_Alias("qc_cmd_svmenu", name, description); }
-
- GENERIC_COMMANDS(0, 0, "");
- #undef GENERIC_COMMAND
-
- return;
+ FOREACH(GENERIC_COMMANDS, true, LAMBDA(CMD_Write_Alias("qc_cmd_svmenu", it.m_name, it.m_description)));
}
--- /dev/null
+// Global list of effects, networked to CSQC by ID to save bandwidth and to use client particle numbers (allows mismatching effectinfos to some degree)
+// Not too concerned about the order of this list, just keep the weapon effects together!
+
+#include "../teams.qh"
+
+// EFFECT(istrail, EFFECT_NAME, "effectinfo_string")
+EFFECT(0, EXPLOSION_SMALL, "explosion_small")
+EFFECT(0, EXPLOSION_MEDIUM, "explosion_medium")
+EFFECT(0, EXPLOSION_BIG, "explosion_big")
+
+EFFECT(0, SMOKE_SMALL, "smoke_small")
+EFFECT(0, SMOKE_LARGE, "smoke_large")
+
+
+
+EFFECT(0, BLASTER_IMPACT, "laser_impact")
+EFFECT(0, BLASTER_MUZZLEFLASH, "laser_muzzleflash")
+
+EFFECT(0, SHOTGUN_IMPACT, "shotgun_impact")
+EFFECT(0, SHOTGUN_MUZZLEFLASH, "shotgun_muzzleflash")
+
+EFFECT(0, ARC_BEAM, "arc_beam")
+EFFECT(0, ARC_BEAM_HEAL, "arc_beam_heal")
+EFFECT(0, ARC_BEAM_HEAL_IMPACT, "arc_beam_healimpact")
+EFFECT(0, ARC_BEAM_HEAL_IMPACT2, "healray_impact")
+EFFECT(0, ARC_LIGHTNING, "arc_lightning")
+EFFECT(0, ARC_LIGHTNING2, "electro_lightning")
+
+EFFECT(0, MACHINEGUN_IMPACT, "machinegun_impact")
+EFFECT(0, MACHINEGUN_MUZZLEFLASH, "uzi_muzzleflash")
+
+EFFECT(0, GRENADE_EXPLODE, "grenade_explode")
+EFFECT(0, GRENADE_MUZZLEFLASH, "grenadelauncher_muzzleflash")
+
+EFFECT(0, ELECTRO_BALLEXPLODE, "electro_ballexplode")
+EFFECT(0, ELECTRO_COMBO, "electro_combo")
+EFFECT(0, ELECTRO_IMPACT, "electro_impact")
+EFFECT(0, ELECTRO_MUZZLEFLASH, "electro_muzzleflash")
+
+EFFECT(0, CRYLINK_IMPACT, "crylink_impactbig")
+EFFECT(0, CRYLINK_IMPACT2, "crylink_impact")
+EFFECT(0, CRYLINK_JOINEXPLODE, "crylink_joinexplode")
+EFFECT(0, CRYLINK_MUZZLEFLASH, "crylink_muzzleflash")
+
+EFFECT(0, VORTEX_BEAM, "nex_beam")
+EFFECT(0, VORTEX_BEAM_OLD, "TE_TEI_G3")
+EFFECT(0, VORTEX_IMPACT, "nex_impact")
+EFFECT(0, VORTEX_MUZZLEFLASH, "nex_muzzleflash")
+
+EFFECT(1, VAPORIZER_RED, "TE_TEI_G3RED")
+EFFECT(1, VAPORIZER_HIT_RED, "TE_TEI_G3RED_HIT")
+EFFECT(1, VAPORIZER_BLUE, "TE_TEI_G3BLUE")
+EFFECT(1, VAPORIZER_HIT_BLUE, "TE_TEI_G3BLUE_HIT")
+EFFECT(1, VAPORIZER_YELLOW, "TE_TEI_G3YELLOW")
+EFFECT(1, VAPORIZER_HIT_YELLOW, "TE_TEI_G3YELLOW_HIT")
+EFFECT(1, VAPORIZER_PINK, "TE_TEI_G3PINK")
+EFFECT(1, VAPORIZER_HIT_PINK, "TE_TEI_G3PINK_HIT")
+EFFECT(1, VAPORIZER_NEUTRAL, "TE_TEI_G3")
+EFFECT(1, VAPORIZER_HIT_NEUTRAL, "TE_TEI_G3_HIT")
+entity EFFECT_VAPORIZER(int teamid)
+{
+ switch (teamid) {
+ case NUM_TEAM_1: return EFFECT_VAPORIZER_RED;
+ case NUM_TEAM_2: return EFFECT_VAPORIZER_BLUE;
+ case NUM_TEAM_3: return EFFECT_VAPORIZER_YELLOW;
+ case NUM_TEAM_4: return EFFECT_VAPORIZER_PINK;
+ default: return EFFECT_VAPORIZER_NEUTRAL;
+ }
+}
+entity EFFECT_VAPORIZER_HIT(int teamid)
+{
+ switch (teamid) {
+ case NUM_TEAM_1: return EFFECT_VAPORIZER_HIT_RED;
+ case NUM_TEAM_2: return EFFECT_VAPORIZER_HIT_BLUE;
+ case NUM_TEAM_3: return EFFECT_VAPORIZER_HIT_YELLOW;
+ case NUM_TEAM_4: return EFFECT_VAPORIZER_HIT_PINK;
+ default: return EFFECT_VAPORIZER_HIT_NEUTRAL;
+ }
+}
+
+EFFECT(0, RIFLE_IMPACT, "machinegun_impact")
+EFFECT(0, RIFLE_MUZZLEFLASH, "rifle_muzzleflash")
+EFFECT(1, RIFLE, "tr_rifle")
+EFFECT(1, RIFLE_WEAK, "tr_rifle_weak")
+
+EFFECT(0, HAGAR_BOUNCE, "hagar_bounce")
+EFFECT(0, HAGAR_EXPLODE, "hagar_explode")
+EFFECT(0, HAGAR_MUZZLEFLASH, "hagar_muzzleflash")
+EFFECT(1, HAGAR_ROCKET, "tr_hagar")
+
+EFFECT(0, ROCKET_EXPLODE, "rocket_explode")
+EFFECT(0, ROCKET_GUIDE, "rocket_guide")
+EFFECT(0, ROCKET_MUZZLEFLASH, "rocketlauncher_muzzleflash")
+
+EFFECT(0, HOOK_EXPLODE, "hookbomb_explode")
+EFFECT(0, HOOK_IMPACT, "grapple_impact")
+EFFECT(0, HOOK_MUZZLEFLASH, "grapple_muzzleflash")
+
+EFFECT(0, SEEKER_MUZZLEFLASH, "seeker_muzzleflash")
+
+EFFECT(0, FLAK_BOUNCE, "flak_bounce")
+
+EFFECT(1, FIREBALL, "fireball")
+EFFECT(0, FIREBALL_BFGDAMAGE, "fireball_bfgdamage")
+EFFECT(0, FIREBALL_EXPLODE, "fireball_explode")
+EFFECT(0, FIREBALL_LASER, "fireball_laser")
+EFFECT(0, FIREBALL_MUZZLEFLASH, "fireball_muzzleflash")
+EFFECT(0, FIREBALL_PRE_MUZZLEFLASH, "fireball_preattack_muzzleflash")
+
+
+
+EFFECT(0, RAPTOR_CANNON_IMPACT, "raptor_cannon_impact")
+EFFECT(0, RAPTOR_BOMB_IMPACT, "raptor_bomb_impact")
+EFFECT(0, RAPTOR_BOMB_SPREAD, "raptor_bomb_spread")
+EFFECT(0, RAPTOR_MUZZLEFLASH, "raptor_cannon_muzzleflash")
+
+EFFECT(0, RACER_BOOSTER, "wakizashi_booster_smoke")
+EFFECT(0, RACER_IMPACT, "wakizashi_gun_impact")
+EFFECT(0, RACER_MUZZLEFLASH, "wakizashi_gun_muzzleflash")
+EFFECT(0, RACER_ROCKETLAUNCH, "wakizashi_rocket_launch")
+EFFECT(0, RACER_ROCKET_EXPLODE, "wakizashi_rocket_launch")
+EFFECT(1, RACER_ROCKET_TRAIL, "wakizashi_rocket_thrust")
+
+EFFECT(0, SPIDERBOT_ROCKETLAUNCH, "spiderbot_rocket_launch")
+EFFECT(1, SPIDERBOT_ROCKET_TRAIL, "spiderbot_rocket_thrust")
+EFFECT(0, SPIDERBOT_ROCKET_EXPLODE, "spiderbot_rocket_explode")
+EFFECT(0, SPIDERBOT_MINIGUN_IMPACT, "spiderbot_minigun_impact")
+EFFECT(0, SPIDERBOT_MINIGUN_MUZZLEFLASH, "spiderbot_minigun_muzzleflash")
+
+EFFECT(0, BUMBLEBEE_HEAL_MUZZLEFLASH, "healray_muzzleflash")
+EFFECT(0, BUMBLEBEE_HEAL_IMPACT, "healray_impact")
+
+EFFECT(0, BIGPLASMA_IMPACT, "bigplasma_impact")
+EFFECT(0, BIGPLASMA_MUZZLEFLASH, "bigplasma_muzzleflash")
+
+EFFECT(0, TELEPORT, "teleport")
+
+EFFECT(0, SPAWNPOINT_RED, "spawn_point_red")
+EFFECT(0, SPAWN_RED, "spawn_event_red")
+EFFECT(0, SPAWNPOINT_BLUE, "spawn_point_blue")
+EFFECT(0, SPAWN_BLUE, "spawn_event_blue")
+EFFECT(0, SPAWNPOINT_YELLOW, "spawn_point_yellow")
+EFFECT(0, SPAWN_YELLOW, "spawn_event_yellow")
+EFFECT(0, SPAWNPOINT_PINK, "spawn_point_pink")
+EFFECT(0, SPAWN_PINK, "spawn_event_pink")
+EFFECT(0, SPAWNPOINT_NEUTRAL, "spawn_point_neutral")
+EFFECT(0, SPAWN_NEUTRAL, "spawn_event_neutral")
+
+EFFECT(0, NADE_EXPLODE_RED, "nade_red_explode")
+EFFECT(0, NADE_EXPLODE_BLUE, "nade_blue_explode")
+EFFECT(0, NADE_EXPLODE_YELLOW, "nade_yellow_explode")
+EFFECT(0, NADE_EXPLODE_PINK, "nade_pink_explode")
+EFFECT(0, NADE_EXPLODE_NEUTRAL, "nade_neutral_explode")
+entity EFFECT_NADE_EXPLODE(int teamid)
+{
+ switch (teamid) {
+ case NUM_TEAM_1: return EFFECT_NADE_EXPLODE_RED;
+ case NUM_TEAM_2: return EFFECT_NADE_EXPLODE_BLUE;
+ case NUM_TEAM_3: return EFFECT_NADE_EXPLODE_YELLOW;
+ case NUM_TEAM_4: return EFFECT_NADE_EXPLODE_PINK;
+ default: return EFFECT_NADE_EXPLODE_NEUTRAL;
+ }
+}
+
+EFFECT(1, NADE_TRAIL_RED, "nade_red")
+EFFECT(1, NADE_TRAIL_BLUE, "nade_blue")
+EFFECT(1, NADE_TRAIL_YELLOW, "nade_yellow")
+EFFECT(1, NADE_TRAIL_PINK, "nade_pink")
+EFFECT(1, NADE_TRAIL_NEUTRAL, "nade_neutral")
+entity EFFECT_NADE_TRAIL(int teamid)
+{
+ switch (teamid) {
+ case NUM_TEAM_1: return EFFECT_NADE_TRAIL_RED;
+ case NUM_TEAM_2: return EFFECT_NADE_TRAIL_BLUE;
+ case NUM_TEAM_3: return EFFECT_NADE_TRAIL_YELLOW;
+ case NUM_TEAM_4: return EFFECT_NADE_TRAIL_PINK;
+ default: return EFFECT_NADE_TRAIL_NEUTRAL;
+ }
+}
+
+EFFECT(1, NADE_TRAIL_BURN_RED, "nade_red_burn")
+EFFECT(1, NADE_TRAIL_BURN_BLUE, "nade_blue_burn")
+EFFECT(1, NADE_TRAIL_BURN_YELLOW, "nade_yellow_burn")
+EFFECT(1, NADE_TRAIL_BURN_PINK, "nade_pink_burn")
+EFFECT(1, NADE_TRAIL_BURN_NEUTRAL, "nade_neutral_burn")
+entity EFFECT_NADE_TRAIL_BURN(int teamid)
+{
+ switch (teamid) {
+ case NUM_TEAM_1: return EFFECT_NADE_TRAIL_BURN_RED;
+ case NUM_TEAM_2: return EFFECT_NADE_TRAIL_BURN_BLUE;
+ case NUM_TEAM_3: return EFFECT_NADE_TRAIL_BURN_YELLOW;
+ case NUM_TEAM_4: return EFFECT_NADE_TRAIL_BURN_PINK;
+ default: return EFFECT_NADE_TRAIL_BURN_NEUTRAL;
+ }
+}
+
+EFFECT(0, ICEORGLASS, "iceorglass")
+EFFECT(0, ICEFIELD, "icefield")
+EFFECT(0, FIREFIELD, "firefield")
+EFFECT(0, HEALING, "healing_fx")
+EFFECT(1, LASER_BEAM_FAST, "nex242_misc_laser_beam_fast")
+EFFECT(0, RESPAWN_GHOST, "respawn_ghost")
+
+EFFECT(0, FLAG_TOUCH_RED, "redflag_touch")
+EFFECT(0, FLAG_TOUCH_BLUE, "blueflag_touch")
+EFFECT(0, FLAG_TOUCH_YELLOW, "yellowflag_touch")
+EFFECT(0, FLAG_TOUCH_PINK, "pinkflag_touch")
+EFFECT(0, FLAG_TOUCH_NEUTRAL, "neutralflag_touch")
+entity EFFECT_FLAG_TOUCH(int teamid)
+{
+ switch (teamid) {
+ case NUM_TEAM_1: return EFFECT_FLAG_TOUCH_RED;
+ case NUM_TEAM_2: return EFFECT_FLAG_TOUCH_BLUE;
+ case NUM_TEAM_3: return EFFECT_FLAG_TOUCH_YELLOW;
+ case NUM_TEAM_4: return EFFECT_FLAG_TOUCH_PINK;
+ default: return EFFECT_FLAG_TOUCH_NEUTRAL;
+ }
+}
+
+EFFECT(1, PASS_RED, "red_pass")
+EFFECT(1, PASS_BLUE, "blue_pass")
+EFFECT(1, PASS_YELLOW, "yellow_pass")
+EFFECT(1, PASS_PINK, "pink_pass")
+EFFECT(1, PASS_NEUTRAL, "neutral_pass")
+
+EFFECT(0, CAP_RED, "red_cap")
+EFFECT(0, CAP_BLUE, "blue_cap")
+EFFECT(0, CAP_YELLOW, "yellow_cap")
+EFFECT(0, CAP_PINK, "pink_cap")
+EFFECT(0, CAP_NEUTRAL, "neutral_cap")
+entity EFFECT_CAP(int teamid)
+{
+ switch (teamid) {
+ case NUM_TEAM_1: return EFFECT_CAP_RED;
+ case NUM_TEAM_2: return EFFECT_CAP_BLUE;
+ case NUM_TEAM_3: return EFFECT_CAP_YELLOW;
+ case NUM_TEAM_4: return EFFECT_CAP_PINK;
+ default: return EFFECT_CAP_NEUTRAL;
+ }
+}
+
+EFFECT(0, ITEM_PICKUP, "item_pickup")
+EFFECT(0, ITEM_RESPAWN, "item_respawn")
+
+EFFECT(0, ONS_GENERATOR_DAMAGED, "torch_small")
+EFFECT(0, ONS_GENERATOR_GIB, "onslaught_generator_gib_explode")
+EFFECT(0, ONS_GENERATOR_EXPLODE, "onslaught_generator_smallexplosion")
+EFFECT(0, ONS_GENERATOR_EXPLODE2, "onslaught_generator_finalexplosion")
+
+
+
+EFFECT(0, LASER_DEADLY, "laser_deadly")
+EFFECT(1, FLAC_TRAIL, "TR_SEEKER")
+EFFECT(1, SEEKER_TRAIL, "TR_SEEKER")
+EFFECT(1, FIREMINE, "firemine")
+EFFECT(0, BALL_SPARKS, "kaball_sparks")
+EFFECT(0, ELECTRIC_SPARKS, "electricity_sparks")
+EFFECT(0, SPARKS, "sparks")
+EFFECT(0, RAGE, "rage")
+EFFECT(0, SMOKING, "smoking")
+EFFECT(0, SMOKE_RING, "smoke_ring")
+EFFECT(0, JUMPPAD, "jumppad_activate")
+EFFECT(1, BULLET, "tr_bullet")
+EFFECT(0, EF_FLAME, "EF_FLAME")
+EFFECT(0, EF_STARDUST, "EF_STARDUST")
+EFFECT(0, TE_EXPLOSION, "TE_EXPLOSION")
+EFFECT(1, TR_NEXUIZPLASMA, "TR_NEXUIZPLASMA")
+EFFECT(1, TR_CRYLINKPLASMA, "TR_CRYLINKPLASMA")
+EFFECT(1, TR_ROCKET, "TR_ROCKET")
+EFFECT(1, TR_GRENADE, "TR_GRENADE")
+EFFECT(1, TR_BLOOD, "TR_BLOOD")
+EFFECT(1, TR_WIZSPIKE, "TR_WIZSPIKE")
+EFFECT(1, TR_SLIGHTBLOOD, "TR_SLIGHTBLOOD")
+EFFECT(1, TR_KNIGHTSPIKE, "TR_KNIGHTSPIKE")
+EFFECT(1, TR_VORESPIKE, "TR_VORESPIKE")
+EFFECT(0, TE_SPARK, "TE_SPARK")
+
+EFFECT(1, ROCKETMINSTA_LASER_RED, "rocketminsta_laser_red")
+EFFECT(1, ROCKETMINSTA_LASER_BLUE, "rocketminsta_laser_blue")
+EFFECT(1, ROCKETMINSTA_LASER_YELLOW, "rocketminsta_laser_yellow")
+EFFECT(1, ROCKETMINSTA_LASER_PINK, "rocketminsta_laser_pink")
+EFFECT(1, ROCKETMINSTA_LASER_NEUTRAL, "rocketminsta_laser_neutral")
+entity EFFECT_ROCKETMINSTA_LASER(int teamid)
+{
+ entity e;
+ switch (teamid) {
+ case NUM_TEAM_1: e = EFFECT_ROCKETMINSTA_LASER_RED; break;
+ case NUM_TEAM_2: e = EFFECT_ROCKETMINSTA_LASER_BLUE; break;
+ case NUM_TEAM_3: e = EFFECT_ROCKETMINSTA_LASER_YELLOW; break;
+ case NUM_TEAM_4: e = EFFECT_ROCKETMINSTA_LASER_PINK; break;
+ default: e = EFFECT_ROCKETMINSTA_LASER_NEUTRAL; break;
+ }
+ if (particleeffectnum(e) < 0 || Team_TeamToNumber(teamid) == -1) { e = EFFECT_TR_NEXUIZPLASMA; }
+ return e;
+}
--- /dev/null
+#include "all.qh"
+
+#ifdef CSQC
+void Read_Effect(bool is_new)
+{
+ int net_name = (Effects_COUNT >= 255) ? ReadShort() : ReadByte();
+
+ entity eff = Effects[net_name];
+
+ vector v, vel = '0 0 0';
+ int eff_cnt = 1;
+ bool eff_trail = eff.eent_eff_trail;
+ v_x = ReadCoord();
+ v_y = ReadCoord();
+ v_z = ReadCoord();
+
+ bool use_vel = ReadByte();
+ if(use_vel)
+ {
+ vel_x = ReadCoord();
+ vel_y = ReadCoord();
+ vel_z = ReadCoord();
+ }
+
+ if(!eff_trail)
+ eff_cnt = ReadByte();
+
+ if(is_new)
+ {
+ if(eff_trail)
+ WarpZone_TrailParticles(world, particleeffectnum(eff), v, vel);
+ else
+ pointparticles(particleeffectnum(eff), v, vel, eff_cnt);
+ }
+}
+#endif
+
+#ifdef SVQC
+bool Net_Write_Effect(entity this, entity client, int sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_EFFECT);
+ (Effects_COUNT >= 255)
+ ? WriteShort(MSG_ENTITY, self.m_id)
+ : WriteByte(MSG_ENTITY, self.m_id);
+ WriteCoord(MSG_ENTITY, self.eent_net_location_x);
+ WriteCoord(MSG_ENTITY, self.eent_net_location_y);
+ WriteCoord(MSG_ENTITY, self.eent_net_location_z);
+
+ // attempt to save a tiny bit more bandwidth by not sending velocity if it isn't set
+ if(self.eent_net_velocity)
+ {
+ WriteByte(MSG_ENTITY, true);
+ WriteCoord(MSG_ENTITY, self.eent_net_velocity_x);
+ WriteCoord(MSG_ENTITY, self.eent_net_velocity_y);
+ WriteCoord(MSG_ENTITY, self.eent_net_velocity_z);
+ }
+ else { WriteByte(MSG_ENTITY, false); }
+
+ if(!self.eent_eff_trail) { WriteByte(MSG_ENTITY, self.eent_net_count); }
+ return true;
+}
+
+void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
+{
+ if(!eff) { return; }
+ if(!eff.eent_eff_trail && !eff_cnt) { return; } // effect has no count!
+ entity net_eff = spawn();
+ net_eff.owner = eff;
+ net_eff.classname = "net_effect";
+ //net_eff.eent_broadcast = broadcast;
+ net_eff.m_id = eff.m_id;
+ net_eff.eent_net_velocity = eff_vel;
+ net_eff.eent_net_location = eff_loc;
+ net_eff.eent_net_count = eff_cnt;
+ net_eff.eent_eff_trail = eff.eent_eff_trail;
+
+ net_eff.think = SUB_Remove;
+ net_eff.nextthink = time + 0.2; // don't need to keep this long
+
+ Net_LinkEntity(net_eff, false, 0, Net_Write_Effect);
+}
+
+void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt)
+{
+ // problem with this is, we might not have all the available effects for it
+ FOREACH(Effects, it.eent_eff_name == eff_name, LAMBDA(
+ Send_Effect(it, eff_loc, eff_vel, eff_cnt);
+ return;
+ ));
+ // revert to engine handling
+ pointparticles(_particleeffectnum(eff_name), eff_loc, eff_vel, eff_cnt);
+}
+#endif
--- /dev/null
+#ifndef EFFECTS_ALL_H
+#define EFFECTS_ALL_H
+
+#include "effect.qh"
+
+#ifdef CSQC
+void Read_Effect(bool is_new);
+#elif defined(SVQC)
+void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt);
+void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt);
+#endif
+
+REGISTRY(Effects, BIT(8))
+REGISTER_REGISTRY(RegisterEffects)
+#define EFFECT(istrail, name, realname) \
+ REGISTER(RegisterEffects, EFFECT, Effects, name, m_id, Create_Effect_Entity(realname, istrail));
+
+void RegisterEffects_First()
+{
+ #ifdef SVQC
+ #define dedi (server_is_dedicated ? "a dedicated " : "")
+ #else
+ #define dedi ""
+ #endif
+
+ LOG_TRACEF("Beginning effect initialization on %s%s program...\n", dedi, PROGNAME);
+ #undef dedi
+}
+
+void RegisterEffects_Done()
+{
+ LOG_TRACE("Effects initialization successful!\n");
+}
+
+// NOW we actually activate the declarations
+ACCUMULATE_FUNCTION(RegisterEffects, RegisterEffects_First)
+EFFECT(0, Null, string_null)
+#include "all.inc"
+ACCUMULATE_FUNCTION(RegisterEffects, RegisterEffects_Done)
+
+#endif
--- /dev/null
+#ifndef EFFECT_H
+#define EFFECT_H
+
+#define particleeffectnum(e) _particleeffectnum(e.eent_eff_name)
+
+.int m_id;
+.string eent_eff_name;
+.int eent_eff_trail;
+
+.vector eent_net_location;
+.vector eent_net_velocity;
+.int eent_net_count;
+
+entity Create_Effect_Entity(string eff_name, bool eff_trail)
+{
+ entity this = new(effect_entity);
+ this.eent_eff_name = eff_name;
+ this.eent_eff_trail = eff_trail;
+ return this;
+}
+
+#endif
#undef WRITE
}
+GENERIC_COMMAND(dumpeffectinfo, "Dump all effectinfo to effectinfo_dump.txt")
+{
+ switch (request) {
+ case CMD_REQUEST_COMMAND: {
+ string filename = argv(1);
+ bool alsoprint = false;
+ if (filename == "") {
+ filename = "effectinfo_dump.txt";
+ alsoprint = false;
+ } else if (filename == "-") {
+ filename = "effectinfo_dump.txt";
+ alsoprint = true;
+ }
+ int fh = fopen(filename, FILE_WRITE);
+ if (fh >= 0) {
+ effectinfo_dump(fh, alsoprint);
+ LOG_INFOF("Dumping effectinfo... File located at ^2data/data/%s^7.\n", filename);
+ LOG_INFOF("Reload with ^2cl_particles_reloadeffects data/%s^7.\n", filename);
+ fclose(fh);
+ } else {
+ LOG_WARNINGF("Could not open file '%s'!\n", filename);
+ }
+ return;
+ }
+ default:
+ case CMD_REQUEST_USAGE: {
+ LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpeffectinfo [filename]"));
+ LOG_INFO(" Where 'filename' is the file to write (default is effectinfo_dump.txt),\n");
+ LOG_INFO(" if supplied with '-' output to console as well as default,\n");
+ LOG_INFO(" if left blank, it will only write to default.\n");
+ return;
+ }
+ }
+}
+
REGISTRY(EffectInfos, BIT(9))
REGISTER_REGISTRY(RegisterEffectInfos)
+++ /dev/null
-// Global list of effects, networked to CSQC by ID to save bandwidth and to use client particle numbers (allows mismatching effectinfos to some degree)
-// Not too concerned about the order of this list, just keep the weapon effects together!
-
-// EFFECT(istrail, EFFECT_NAME, "effectinfo_string")
-EFFECT(0, EXPLOSION_SMALL, "explosion_small")
-EFFECT(0, EXPLOSION_MEDIUM, "explosion_medium")
-EFFECT(0, EXPLOSION_BIG, "explosion_big")
-
-EFFECT(0, SMOKE_SMALL, "smoke_small")
-EFFECT(0, SMOKE_LARGE, "smoke_large")
-
-
-
-EFFECT(0, BLASTER_IMPACT, "laser_impact")
-EFFECT(0, BLASTER_MUZZLEFLASH, "laser_muzzleflash")
-
-EFFECT(0, SHOTGUN_IMPACT, "shotgun_impact")
-EFFECT(0, SHOTGUN_MUZZLEFLASH, "shotgun_muzzleflash")
-
-EFFECT(0, ARC_BEAM, "arc_beam")
-EFFECT(0, ARC_BEAM_HEAL, "arc_beam_heal")
-EFFECT(0, ARC_BEAM_HEAL_IMPACT, "arc_beam_healimpact")
-EFFECT(0, ARC_BEAM_HEAL_IMPACT2, "healray_impact")
-EFFECT(0, ARC_LIGHTNING, "arc_lightning")
-EFFECT(0, ARC_LIGHTNING2, "electro_lightning")
-
-EFFECT(0, MACHINEGUN_IMPACT, "machinegun_impact")
-EFFECT(0, MACHINEGUN_MUZZLEFLASH, "uzi_muzzleflash")
-
-EFFECT(0, GRENADE_EXPLODE, "grenade_explode")
-EFFECT(0, GRENADE_MUZZLEFLASH, "grenadelauncher_muzzleflash")
-
-EFFECT(0, ELECTRO_BALLEXPLODE, "electro_ballexplode")
-EFFECT(0, ELECTRO_COMBO, "electro_combo")
-EFFECT(0, ELECTRO_IMPACT, "electro_impact")
-EFFECT(0, ELECTRO_MUZZLEFLASH, "electro_muzzleflash")
-
-EFFECT(0, CRYLINK_IMPACT, "crylink_impactbig")
-EFFECT(0, CRYLINK_IMPACT2, "crylink_impact")
-EFFECT(0, CRYLINK_JOINEXPLODE, "crylink_joinexplode")
-EFFECT(0, CRYLINK_MUZZLEFLASH, "crylink_muzzleflash")
-
-EFFECT(0, VORTEX_BEAM, "nex_beam")
-EFFECT(0, VORTEX_BEAM_OLD, "TE_TEI_G3")
-EFFECT(0, VORTEX_IMPACT, "nex_impact")
-EFFECT(0, VORTEX_MUZZLEFLASH, "nex_muzzleflash")
-
-EFFECT(1, VAPORIZER_RED, "TE_TEI_G3RED")
-EFFECT(1, VAPORIZER_HIT_RED, "TE_TEI_G3RED_HIT")
-EFFECT(1, VAPORIZER_BLUE, "TE_TEI_G3BLUE")
-EFFECT(1, VAPORIZER_HIT_BLUE, "TE_TEI_G3BLUE_HIT")
-EFFECT(1, VAPORIZER_YELLOW, "TE_TEI_G3YELLOW")
-EFFECT(1, VAPORIZER_HIT_YELLOW, "TE_TEI_G3YELLOW_HIT")
-EFFECT(1, VAPORIZER_PINK, "TE_TEI_G3PINK")
-EFFECT(1, VAPORIZER_HIT_PINK, "TE_TEI_G3PINK_HIT")
-EFFECT(1, VAPORIZER_NEUTRAL, "TE_TEI_G3")
-EFFECT(1, VAPORIZER_HIT_NEUTRAL, "TE_TEI_G3_HIT")
-entity EFFECT_VAPORIZER(int teamid)
-{
- switch (teamid) {
- case NUM_TEAM_1: return EFFECT_VAPORIZER_RED;
- case NUM_TEAM_2: return EFFECT_VAPORIZER_BLUE;
- case NUM_TEAM_3: return EFFECT_VAPORIZER_YELLOW;
- case NUM_TEAM_4: return EFFECT_VAPORIZER_PINK;
- default: return EFFECT_VAPORIZER_NEUTRAL;
- }
-}
-entity EFFECT_VAPORIZER_HIT(int teamid)
-{
- switch (teamid) {
- case NUM_TEAM_1: return EFFECT_VAPORIZER_HIT_RED;
- case NUM_TEAM_2: return EFFECT_VAPORIZER_HIT_BLUE;
- case NUM_TEAM_3: return EFFECT_VAPORIZER_HIT_YELLOW;
- case NUM_TEAM_4: return EFFECT_VAPORIZER_HIT_PINK;
- default: return EFFECT_VAPORIZER_HIT_NEUTRAL;
- }
-}
-
-EFFECT(0, RIFLE_IMPACT, "machinegun_impact")
-EFFECT(0, RIFLE_MUZZLEFLASH, "rifle_muzzleflash")
-EFFECT(1, RIFLE, "tr_rifle")
-EFFECT(1, RIFLE_WEAK, "tr_rifle_weak")
-
-EFFECT(0, HAGAR_BOUNCE, "hagar_bounce")
-EFFECT(0, HAGAR_EXPLODE, "hagar_explode")
-EFFECT(0, HAGAR_MUZZLEFLASH, "hagar_muzzleflash")
-EFFECT(1, HAGAR_ROCKET, "tr_hagar")
-
-EFFECT(0, ROCKET_EXPLODE, "rocket_explode")
-EFFECT(0, ROCKET_GUIDE, "rocket_guide")
-EFFECT(0, ROCKET_MUZZLEFLASH, "rocketlauncher_muzzleflash")
-
-EFFECT(0, HOOK_EXPLODE, "hookbomb_explode")
-EFFECT(0, HOOK_IMPACT, "grapple_impact")
-EFFECT(0, HOOK_MUZZLEFLASH, "grapple_muzzleflash")
-
-EFFECT(0, SEEKER_MUZZLEFLASH, "seeker_muzzleflash")
-
-EFFECT(0, FLAK_BOUNCE, "flak_bounce")
-
-EFFECT(1, FIREBALL, "fireball")
-EFFECT(0, FIREBALL_BFGDAMAGE, "fireball_bfgdamage")
-EFFECT(0, FIREBALL_EXPLODE, "fireball_explode")
-EFFECT(0, FIREBALL_LASER, "fireball_laser")
-EFFECT(0, FIREBALL_MUZZLEFLASH, "fireball_muzzleflash")
-EFFECT(0, FIREBALL_PRE_MUZZLEFLASH, "fireball_preattack_muzzleflash")
-
-
-
-EFFECT(0, RAPTOR_CANNON_IMPACT, "raptor_cannon_impact")
-EFFECT(0, RAPTOR_BOMB_IMPACT, "raptor_bomb_impact")
-EFFECT(0, RAPTOR_BOMB_SPREAD, "raptor_bomb_spread")
-EFFECT(0, RAPTOR_MUZZLEFLASH, "raptor_cannon_muzzleflash")
-
-EFFECT(0, RACER_BOOSTER, "wakizashi_booster_smoke")
-EFFECT(0, RACER_IMPACT, "wakizashi_gun_impact")
-EFFECT(0, RACER_MUZZLEFLASH, "wakizashi_gun_muzzleflash")
-EFFECT(0, RACER_ROCKETLAUNCH, "wakizashi_rocket_launch")
-EFFECT(0, RACER_ROCKET_EXPLODE, "wakizashi_rocket_launch")
-EFFECT(1, RACER_ROCKET_TRAIL, "wakizashi_rocket_thrust")
-
-EFFECT(0, SPIDERBOT_ROCKETLAUNCH, "spiderbot_rocket_launch")
-EFFECT(1, SPIDERBOT_ROCKET_TRAIL, "spiderbot_rocket_thrust")
-EFFECT(0, SPIDERBOT_ROCKET_EXPLODE, "spiderbot_rocket_explode")
-EFFECT(0, SPIDERBOT_MINIGUN_IMPACT, "spiderbot_minigun_impact")
-EFFECT(0, SPIDERBOT_MINIGUN_MUZZLEFLASH, "spiderbot_minigun_muzzleflash")
-
-EFFECT(0, BUMBLEBEE_HEAL_MUZZLEFLASH, "healray_muzzleflash")
-EFFECT(0, BUMBLEBEE_HEAL_IMPACT, "healray_impact")
-
-EFFECT(0, BIGPLASMA_IMPACT, "bigplasma_impact")
-EFFECT(0, BIGPLASMA_MUZZLEFLASH, "bigplasma_muzzleflash")
-
-EFFECT(0, TELEPORT, "teleport")
-
-EFFECT(0, SPAWNPOINT_RED, "spawn_point_red")
-EFFECT(0, SPAWN_RED, "spawn_event_red")
-EFFECT(0, SPAWNPOINT_BLUE, "spawn_point_blue")
-EFFECT(0, SPAWN_BLUE, "spawn_event_blue")
-EFFECT(0, SPAWNPOINT_YELLOW, "spawn_point_yellow")
-EFFECT(0, SPAWN_YELLOW, "spawn_event_yellow")
-EFFECT(0, SPAWNPOINT_PINK, "spawn_point_pink")
-EFFECT(0, SPAWN_PINK, "spawn_event_pink")
-EFFECT(0, SPAWNPOINT_NEUTRAL, "spawn_point_neutral")
-EFFECT(0, SPAWN_NEUTRAL, "spawn_event_neutral")
-
-EFFECT(0, NADE_EXPLODE_RED, "nade_red_explode")
-EFFECT(0, NADE_EXPLODE_BLUE, "nade_blue_explode")
-EFFECT(0, NADE_EXPLODE_YELLOW, "nade_yellow_explode")
-EFFECT(0, NADE_EXPLODE_PINK, "nade_pink_explode")
-EFFECT(0, NADE_EXPLODE_NEUTRAL, "nade_neutral_explode")
-entity EFFECT_NADE_EXPLODE(int teamid)
-{
- switch (teamid) {
- case NUM_TEAM_1: return EFFECT_NADE_EXPLODE_RED;
- case NUM_TEAM_2: return EFFECT_NADE_EXPLODE_BLUE;
- case NUM_TEAM_3: return EFFECT_NADE_EXPLODE_YELLOW;
- case NUM_TEAM_4: return EFFECT_NADE_EXPLODE_PINK;
- default: return EFFECT_NADE_EXPLODE_NEUTRAL;
- }
-}
-
-EFFECT(1, NADE_TRAIL_RED, "nade_red")
-EFFECT(1, NADE_TRAIL_BLUE, "nade_blue")
-EFFECT(1, NADE_TRAIL_YELLOW, "nade_yellow")
-EFFECT(1, NADE_TRAIL_PINK, "nade_pink")
-EFFECT(1, NADE_TRAIL_NEUTRAL, "nade_neutral")
-entity EFFECT_NADE_TRAIL(int teamid)
-{
- switch (teamid) {
- case NUM_TEAM_1: return EFFECT_NADE_TRAIL_RED;
- case NUM_TEAM_2: return EFFECT_NADE_TRAIL_BLUE;
- case NUM_TEAM_3: return EFFECT_NADE_TRAIL_YELLOW;
- case NUM_TEAM_4: return EFFECT_NADE_TRAIL_PINK;
- default: return EFFECT_NADE_TRAIL_NEUTRAL;
- }
-}
-
-EFFECT(1, NADE_TRAIL_BURN_RED, "nade_red_burn")
-EFFECT(1, NADE_TRAIL_BURN_BLUE, "nade_blue_burn")
-EFFECT(1, NADE_TRAIL_BURN_YELLOW, "nade_yellow_burn")
-EFFECT(1, NADE_TRAIL_BURN_PINK, "nade_pink_burn")
-EFFECT(1, NADE_TRAIL_BURN_NEUTRAL, "nade_neutral_burn")
-entity EFFECT_NADE_TRAIL_BURN(int teamid)
-{
- switch (teamid) {
- case NUM_TEAM_1: return EFFECT_NADE_TRAIL_BURN_RED;
- case NUM_TEAM_2: return EFFECT_NADE_TRAIL_BURN_BLUE;
- case NUM_TEAM_3: return EFFECT_NADE_TRAIL_BURN_YELLOW;
- case NUM_TEAM_4: return EFFECT_NADE_TRAIL_BURN_PINK;
- default: return EFFECT_NADE_TRAIL_BURN_NEUTRAL;
- }
-}
-
-EFFECT(0, ICEORGLASS, "iceorglass")
-EFFECT(0, ICEFIELD, "icefield")
-EFFECT(0, FIREFIELD, "firefield")
-EFFECT(0, HEALING, "healing_fx")
-EFFECT(1, LASER_BEAM_FAST, "nex242_misc_laser_beam_fast")
-EFFECT(0, RESPAWN_GHOST, "respawn_ghost")
-
-EFFECT(0, FLAG_TOUCH_RED, "redflag_touch")
-EFFECT(0, FLAG_TOUCH_BLUE, "blueflag_touch")
-EFFECT(0, FLAG_TOUCH_YELLOW, "yellowflag_touch")
-EFFECT(0, FLAG_TOUCH_PINK, "pinkflag_touch")
-EFFECT(0, FLAG_TOUCH_NEUTRAL, "neutralflag_touch")
-entity EFFECT_FLAG_TOUCH(int teamid)
-{
- switch (teamid) {
- case NUM_TEAM_1: return EFFECT_FLAG_TOUCH_RED;
- case NUM_TEAM_2: return EFFECT_FLAG_TOUCH_BLUE;
- case NUM_TEAM_3: return EFFECT_FLAG_TOUCH_YELLOW;
- case NUM_TEAM_4: return EFFECT_FLAG_TOUCH_PINK;
- default: return EFFECT_FLAG_TOUCH_NEUTRAL;
- }
-}
-
-EFFECT(1, PASS_RED, "red_pass")
-EFFECT(1, PASS_BLUE, "blue_pass")
-EFFECT(1, PASS_YELLOW, "yellow_pass")
-EFFECT(1, PASS_PINK, "pink_pass")
-EFFECT(1, PASS_NEUTRAL, "neutral_pass")
-
-EFFECT(0, CAP_RED, "red_cap")
-EFFECT(0, CAP_BLUE, "blue_cap")
-EFFECT(0, CAP_YELLOW, "yellow_cap")
-EFFECT(0, CAP_PINK, "pink_cap")
-EFFECT(0, CAP_NEUTRAL, "neutral_cap")
-entity EFFECT_CAP(int teamid)
-{
- switch (teamid) {
- case NUM_TEAM_1: return EFFECT_CAP_RED;
- case NUM_TEAM_2: return EFFECT_CAP_BLUE;
- case NUM_TEAM_3: return EFFECT_CAP_YELLOW;
- case NUM_TEAM_4: return EFFECT_CAP_PINK;
- default: return EFFECT_CAP_NEUTRAL;
- }
-}
-
-EFFECT(0, ITEM_PICKUP, "item_pickup")
-EFFECT(0, ITEM_RESPAWN, "item_respawn")
-
-EFFECT(0, ONS_GENERATOR_DAMAGED, "torch_small")
-EFFECT(0, ONS_GENERATOR_GIB, "onslaught_generator_gib_explode")
-EFFECT(0, ONS_GENERATOR_EXPLODE, "onslaught_generator_smallexplosion")
-EFFECT(0, ONS_GENERATOR_EXPLODE2, "onslaught_generator_finalexplosion")
-
-
-
-EFFECT(0, LASER_DEADLY, "laser_deadly")
-EFFECT(1, FLAC_TRAIL, "TR_SEEKER")
-EFFECT(1, SEEKER_TRAIL, "TR_SEEKER")
-EFFECT(1, FIREMINE, "firemine")
-EFFECT(0, BALL_SPARKS, "kaball_sparks")
-EFFECT(0, ELECTRIC_SPARKS, "electricity_sparks")
-EFFECT(0, SPARKS, "sparks")
-EFFECT(0, RAGE, "rage")
-EFFECT(0, SMOKING, "smoking")
-EFFECT(0, SMOKE_RING, "smoke_ring")
-EFFECT(0, JUMPPAD, "jumppad_activate")
-EFFECT(1, BULLET, "tr_bullet")
-EFFECT(0, EF_FLAME, "EF_FLAME")
-EFFECT(0, EF_STARDUST, "EF_STARDUST")
-EFFECT(0, TE_EXPLOSION, "TE_EXPLOSION")
-EFFECT(1, TR_NEXUIZPLASMA, "TR_NEXUIZPLASMA")
-EFFECT(1, TR_CRYLINKPLASMA, "TR_CRYLINKPLASMA")
-EFFECT(1, TR_ROCKET, "TR_ROCKET")
-EFFECT(1, TR_GRENADE, "TR_GRENADE")
-EFFECT(1, TR_BLOOD, "TR_BLOOD")
-EFFECT(1, TR_WIZSPIKE, "TR_WIZSPIKE")
-EFFECT(1, TR_SLIGHTBLOOD, "TR_SLIGHTBLOOD")
-EFFECT(1, TR_KNIGHTSPIKE, "TR_KNIGHTSPIKE")
-EFFECT(1, TR_VORESPIKE, "TR_VORESPIKE")
-EFFECT(0, TE_SPARK, "TE_SPARK")
-
-EFFECT(1, ROCKETMINSTA_LASER_RED, "rocketminsta_laser_red")
-EFFECT(1, ROCKETMINSTA_LASER_BLUE, "rocketminsta_laser_blue")
-EFFECT(1, ROCKETMINSTA_LASER_YELLOW, "rocketminsta_laser_yellow")
-EFFECT(1, ROCKETMINSTA_LASER_PINK, "rocketminsta_laser_pink")
-EFFECT(1, ROCKETMINSTA_LASER_NEUTRAL, "rocketminsta_laser_neutral")
-entity EFFECT_ROCKETMINSTA_LASER(int teamid)
-{
- entity e;
- switch (teamid) {
- case NUM_TEAM_1: e = EFFECT_ROCKETMINSTA_LASER_RED; break;
- case NUM_TEAM_2: e = EFFECT_ROCKETMINSTA_LASER_BLUE; break;
- case NUM_TEAM_3: e = EFFECT_ROCKETMINSTA_LASER_YELLOW; break;
- case NUM_TEAM_4: e = EFFECT_ROCKETMINSTA_LASER_PINK; break;
- default: e = EFFECT_ROCKETMINSTA_LASER_NEUTRAL; break;
- }
- if (particleeffectnum(e) < 0 || Team_TeamToNumber(teamid) == -1) { e = EFFECT_TR_NEXUIZPLASMA; }
- return e;
-}
+++ /dev/null
-#ifdef CSQC
-void Read_Effect(bool is_new)
-{
- int net_name = (Effects_COUNT >= 255) ? ReadShort() : ReadByte();
-
- entity eff = Effects[net_name];
-
- vector v, vel = '0 0 0';
- int eff_cnt = 1;
- bool eff_trail = eff.eent_eff_trail;
- v_x = ReadCoord();
- v_y = ReadCoord();
- v_z = ReadCoord();
-
- bool use_vel = ReadByte();
- if(use_vel)
- {
- vel_x = ReadCoord();
- vel_y = ReadCoord();
- vel_z = ReadCoord();
- }
-
- if(!eff_trail)
- eff_cnt = ReadByte();
-
- if(is_new)
- {
- if(eff_trail)
- WarpZone_TrailParticles(world, particleeffectnum(eff), v, vel);
- else
- pointparticles(particleeffectnum(eff), v, vel, eff_cnt);
- }
-}
-#endif
-
-#ifdef SVQC
-bool Net_Write_Effect(entity this, entity client, int sf)
-{
- WriteByte(MSG_ENTITY, ENT_CLIENT_EFFECT);
- (Effects_COUNT >= 255)
- ? WriteShort(MSG_ENTITY, self.m_id)
- : WriteByte(MSG_ENTITY, self.m_id);
- WriteCoord(MSG_ENTITY, self.eent_net_location_x);
- WriteCoord(MSG_ENTITY, self.eent_net_location_y);
- WriteCoord(MSG_ENTITY, self.eent_net_location_z);
-
- // attempt to save a tiny bit more bandwidth by not sending velocity if it isn't set
- if(self.eent_net_velocity)
- {
- WriteByte(MSG_ENTITY, true);
- WriteCoord(MSG_ENTITY, self.eent_net_velocity_x);
- WriteCoord(MSG_ENTITY, self.eent_net_velocity_y);
- WriteCoord(MSG_ENTITY, self.eent_net_velocity_z);
- }
- else { WriteByte(MSG_ENTITY, false); }
-
- if(!self.eent_eff_trail) { WriteByte(MSG_ENTITY, self.eent_net_count); }
- return true;
-}
-
-void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
-{
- if(!eff) { return; }
- if(!eff.eent_eff_trail && !eff_cnt) { return; } // effect has no count!
- entity net_eff = spawn();
- net_eff.owner = eff;
- net_eff.classname = "net_effect";
- //net_eff.eent_broadcast = broadcast;
- net_eff.m_id = eff.m_id;
- net_eff.eent_net_velocity = eff_vel;
- net_eff.eent_net_location = eff_loc;
- net_eff.eent_net_count = eff_cnt;
- net_eff.eent_eff_trail = eff.eent_eff_trail;
-
- net_eff.think = SUB_Remove;
- net_eff.nextthink = time + 0.2; // don't need to keep this long
-
- Net_LinkEntity(net_eff, false, 0, Net_Write_Effect);
-}
-
-void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt)
-{
- // problem with this is, we might not have all the available effects for it
- FOREACH(Effects, it.eent_eff_name == eff_name, LAMBDA(
- Send_Effect(it, eff_loc, eff_vel, eff_cnt);
- return;
- ));
- // revert to engine handling
- pointparticles(_particleeffectnum(eff_name), eff_loc, eff_vel, eff_cnt);
-}
-#endif
+++ /dev/null
-#ifndef P_EFFECTS_H
-#define P_EFFECTS_H
-
-#ifdef CSQC
-void Read_Effect(bool is_new);
-#elif defined(SVQC)
-void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt);
-void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt);
-#endif
-
-#define particleeffectnum(e) _particleeffectnum(e.eent_eff_name)
-
-REGISTRY(Effects, BIT(8))
-REGISTER_REGISTRY(RegisterEffects)
-#define EFFECT(istrail, name, realname) \
- REGISTER(RegisterEffects, EFFECT, Effects, name, m_id, Create_Effect_Entity(realname, istrail));
-
-.int m_id;
-.string eent_eff_name;
-.int eent_eff_trail;
-
-.vector eent_net_location;
-.vector eent_net_velocity;
-.int eent_net_count;
-
-entity Create_Effect_Entity(string eff_name, bool eff_trail)
-{
- entity this = new(effect_entity);
- this.eent_eff_name = eff_name;
- this.eent_eff_trail = eff_trail;
- return this;
-}
-
-void RegisterEffects_First()
-{
- #ifdef SVQC
- #define dedi (server_is_dedicated ? "a dedicated " : "")
- #else
- #define dedi ""
- #endif
-
- LOG_TRACEF("Beginning effect initialization on %s%s program...\n", dedi, PROGNAME);
- #undef dedi
-}
-
-void RegisterEffects_Done()
-{
- LOG_TRACE("Effects initialization successful!\n");
-}
-
-// NOW we actually activate the declarations
-ACCUMULATE_FUNCTION(RegisterEffects, RegisterEffects_First)
-EFFECT(0, Null, string_null)
-#include "effects.inc"
-ACCUMULATE_FUNCTION(RegisterEffects, RegisterEffects_Done)
-
-#endif
--- /dev/null
+#include "gamemode/nexball/nexball.qc"
--- /dev/null
+#include "all.qh"
+
+#define IMPLEMENTATION
+#include "all.inc"
+#undef IMPLEMENTATION
--- /dev/null
+#ifndef GAMEMODES_ALL_H
+#define GAMEMODES_ALL_H
+
+#include "all.inc"
+
+#endif
--- /dev/null
+#include "nexball.qh"
+
+#ifdef IMPLEMENTATION
+#ifdef SVQC
+float autocvar_g_nexball_basketball_bouncefactor;
+float autocvar_g_nexball_basketball_bouncestop;
+float autocvar_g_nexball_basketball_carrier_highspeed;
+bool autocvar_g_nexball_basketball_meter;
+float autocvar_g_nexball_basketball_meter_maxpower;
+float autocvar_g_nexball_basketball_meter_minpower;
+float autocvar_g_nexball_delay_collect;
+float autocvar_g_nexball_delay_goal;
+float autocvar_g_nexball_delay_start;
+float autocvar_g_nexball_football_bouncefactor;
+float autocvar_g_nexball_football_bouncestop;
+bool autocvar_g_nexball_radar_showallplayers;
+bool autocvar_g_nexball_sound_bounce;
+int autocvar_g_nexball_trail_color;
+
+float autocvar_g_nexball_safepass_turnrate;
+float autocvar_g_nexball_safepass_maxdist;
+float autocvar_g_nexball_safepass_holdtime;
+float autocvar_g_nexball_viewmodel_scale;
+float autocvar_g_nexball_tackling;
+vector autocvar_g_nexball_viewmodel_offset;
+
+void basketball_touch();
+void football_touch();
+void ResetBall();
+const int NBM_NONE = 0;
+const int NBM_FOOTBALL = 2;
+const int NBM_BASKETBALL = 4;
+float nexball_mode;
+
+float OtherTeam(float t) //works only if there are two teams on the map!
+{
+ entity e;
+ e = find(world, classname, "nexball_team");
+ if(e.team == t)
+ e = find(e, classname, "nexball_team");
+ return e.team;
+}
+
+const float ST_NEXBALL_GOALS = 1;
+const float SP_NEXBALL_GOALS = 4;
+const float SP_NEXBALL_FAULTS = 5;
+void nb_ScoreRules(float teams)
+{
+ ScoreRules_basics(teams, 0, 0, true);
+ ScoreInfo_SetLabel_TeamScore( ST_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore( SP_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER);
+ ScoreRules_basics_end();
+}
+
+void LogNB(string mode, entity actor)
+{
+ string s;
+ if(!autocvar_sv_eventlog)
+ return;
+ s = strcat(":nexball:", mode);
+ if(actor != world)
+ s = strcat(s, ":", ftos(actor.playerid));
+ GameLogEcho(s);
+}
+
+void ball_restart(void)
+{SELFPARAM();
+ if(self.owner)
+ DropBall(self, self.owner.origin, '0 0 0');
+ ResetBall();
+}
+
+void nexball_setstatus(void)
+{SELFPARAM();
+ self.items &= ~IT_KEY1;
+ if(self.ballcarried)
+ {
+ if(self.ballcarried.teamtime && (self.ballcarried.teamtime < time))
+ {
+ bprint("The ", Team_ColoredFullName(self.team), " held the ball for too long.\n");
+ setself(self.ballcarried);
+ DropBall(self, self.owner.origin, '0 0 0');
+ ResetBall();
+ setself(this);
+ }
+ else
+ self.items |= IT_KEY1;
+ }
+}
+
+void relocate_nexball(void)
+{SELFPARAM();
+ tracebox(self.origin, BALL_MINS, BALL_MAXS, self.origin, true, self);
+ if(trace_startsolid)
+ {
+ vector o;
+ o = self.origin;
+ if(!move_out_of_solid(self))
+ objerror("could not get out of solid at all!");
+ LOG_INFO("^1NOTE: this map needs FIXING. ", self.classname, " at ", vtos(o - '0 0 1'));
+ LOG_INFO(" needs to be moved out of solid, e.g. by '", ftos(self.origin.x - o.x));
+ LOG_INFO(" ", ftos(self.origin.y - o.y));
+ LOG_INFO(" ", ftos(self.origin.z - o.z), "'\n");
+ self.origin = o;
+ }
+}
+
+void DropOwner(void)
+{SELFPARAM();
+ entity ownr;
+ ownr = self.owner;
+ DropBall(self, ownr.origin, ownr.velocity);
+ makevectors(ownr.v_angle.y * '0 1 0');
+ ownr.velocity += ('0 0 0.75' - v_forward) * 1000;
+ ownr.flags &= ~FL_ONGROUND;
+}
+
+void GiveBall(entity plyr, entity ball)
+{SELFPARAM();
+ entity ownr;
+
+ if((ownr = ball.owner))
+ {
+ ownr.effects &= ~autocvar_g_nexball_basketball_effects_default;
+ ownr.ballcarried = world;
+ if(ownr.metertime)
+ {
+ ownr.metertime = 0;
+ ownr.weaponentity.state = WS_READY;
+ }
+ WaypointSprite_Kill(ownr.waypointsprite_attachedforcarrier);
+ }
+ else
+ {
+ WaypointSprite_Kill(ball.waypointsprite_attachedforcarrier);
+ }
+
+ //setattachment(ball, plyr, "");
+ setorigin(ball, plyr.origin + plyr.view_ofs);
+
+ if(ball.team != plyr.team)
+ ball.teamtime = time + autocvar_g_nexball_basketball_delay_hold_forteam;
+
+ ball.owner = ball.pusher = plyr; //"owner" is set to the player carrying, "pusher" to the last player who touched it
+ ball.team = plyr.team;
+ plyr.ballcarried = ball;
+ ball.nb_dropper = plyr;
+
+ plyr.effects |= autocvar_g_nexball_basketball_effects_default;
+ ball.effects &= ~autocvar_g_nexball_basketball_effects_default;
+
+ ball.velocity = '0 0 0';
+ ball.movetype = MOVETYPE_NONE;
+ ball.touch = func_null;
+ ball.effects |= EF_NOSHADOW;
+ ball.scale = 1; // scale down.
+
+ WaypointSprite_AttachCarrier(WP_NbBall, plyr, RADARICON_FLAGCARRIER);
+ WaypointSprite_UpdateRule(plyr.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
+
+ if(autocvar_g_nexball_basketball_delay_hold)
+ {
+ ball.think = DropOwner;
+ ball.nextthink = time + autocvar_g_nexball_basketball_delay_hold;
+ }
+
+ plyr.weaponentity.weapons = plyr.weapons;
+ plyr.weaponentity.switchweapon = plyr.weapon;
+ plyr.weapons = WEPSET(NEXBALL);
+ setself(plyr);
+ Weapon w = WEP_NEXBALL;
+ w.wr_resetplayer(w);
+ plyr.switchweapon = WEP_NEXBALL.m_id;
+ W_SwitchWeapon(WEP_NEXBALL.m_id);
+ setself(this);
+}
+
+void DropBall(entity ball, vector org, vector vel)
+{
+ ball.effects |= autocvar_g_nexball_basketball_effects_default;
+ ball.effects &= ~EF_NOSHADOW;
+ ball.owner.effects &= ~autocvar_g_nexball_basketball_effects_default;
+
+ setattachment(ball, world, "");
+ setorigin(ball, org);
+ ball.movetype = MOVETYPE_BOUNCE;
+ ball.flags &= ~FL_ONGROUND;
+ ball.scale = ball_scale;
+ ball.velocity = vel;
+ ball.nb_droptime = time;
+ ball.touch = basketball_touch;
+ ball.think = ResetBall;
+ ball.nextthink = min(time + autocvar_g_nexball_delay_idle, ball.teamtime);
+
+ if(ball.owner.metertime)
+ {
+ ball.owner.metertime = 0;
+ ball.owner.weaponentity.state = WS_READY;
+ }
+
+ WaypointSprite_Kill(ball.owner.waypointsprite_attachedforcarrier);
+ WaypointSprite_Spawn(WP_NbBall, 0, 0, ball, '0 0 64', world, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER); // no health bar please
+ WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
+
+ ball.owner.ballcarried = world;
+ ball.owner = world;
+}
+
+void InitBall(void)
+{SELFPARAM();
+ if(gameover) return;
+ self.flags &= ~FL_ONGROUND;
+ self.movetype = MOVETYPE_BOUNCE;
+ if(self.classname == "nexball_basketball")
+ self.touch = basketball_touch;
+ else if(self.classname == "nexball_football")
+ self.touch = football_touch;
+ self.cnt = 0;
+ self.think = ResetBall;
+ self.nextthink = time + autocvar_g_nexball_delay_idle + 3;
+ self.teamtime = 0;
+ self.pusher = world;
+ self.team = false;
+ _sound(self, CH_TRIGGER, self.noise1, VOL_BASE, ATTEN_NORM);
+ WaypointSprite_Ping(self.waypointsprite_attachedforcarrier);
+ LogNB("init", world);
+}
+
+void ResetBall(void)
+{SELFPARAM();
+ if(self.cnt < 2) // step 1
+ {
+ if(time == self.teamtime)
+ bprint("The ", Team_ColoredFullName(self.team), " held the ball for too long.\n");
+
+ self.touch = func_null;
+ self.movetype = MOVETYPE_NOCLIP;
+ self.velocity = '0 0 0'; // just in case?
+ if(!self.cnt)
+ LogNB("resetidle", world);
+ self.cnt = 2;
+ self.nextthink = time;
+ }
+ else if(self.cnt < 4) // step 2 and 3
+ {
+// dprint("Step ", ftos(self.cnt), ": Calculated velocity: ", vtos(self.spawnorigin - self.origin), ", time: ", ftos(time), "\n");
+ self.velocity = (self.spawnorigin - self.origin) * (self.cnt - 1); // 1 or 0.5 second movement
+ self.nextthink = time + 0.5;
+ self.cnt += 1;
+ }
+ else // step 4
+ {
+// dprint("Step 4: time: ", ftos(time), "\n");
+ if(vlen(self.origin - self.spawnorigin) > 10) // should not happen anymore
+ LOG_TRACE("The ball moved too far away from its spawn origin.\nOffset: ",
+ vtos(self.origin - self.spawnorigin), " Velocity: ", vtos(self.velocity), "\n");
+ self.velocity = '0 0 0';
+ setorigin(self, self.spawnorigin); // make sure it's positioned correctly anyway
+ self.movetype = MOVETYPE_NONE;
+ self.think = InitBall;
+ self.nextthink = max(time, game_starttime) + autocvar_g_nexball_delay_start;
+ }
+}
+
+void football_touch(void)
+{SELFPARAM();
+ if(other.solid == SOLID_BSP)
+ {
+ if(time > self.lastground + 0.1)
+ {
+ _sound(self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
+ self.lastground = time;
+ }
+ if(vlen(self.velocity) && !self.cnt)
+ self.nextthink = time + autocvar_g_nexball_delay_idle;
+ return;
+ }
+ if (!IS_PLAYER(other))
+ return;
+ if(other.health < 1)
+ return;
+ if(!self.cnt)
+ self.nextthink = time + autocvar_g_nexball_delay_idle;
+
+ self.pusher = other;
+ self.team = other.team;
+
+ if(autocvar_g_nexball_football_physics == -1) // MrBougo try 1, before decompiling Rev's original
+ {
+ if(vlen(other.velocity))
+ self.velocity = other.velocity * 1.5 + '0 0 1' * autocvar_g_nexball_football_boost_up;
+ }
+ else if(autocvar_g_nexball_football_physics == 1) // MrBougo's modded Rev style: partially independant of the height of the aiming point
+ {
+ makevectors(other.v_angle);
+ self.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + '0 0 1' * autocvar_g_nexball_football_boost_up;
+ }
+ else if(autocvar_g_nexball_football_physics == 2) // 2nd mod try: totally independant. Really playable!
+ {
+ makevectors(other.v_angle.y * '0 1 0');
+ self.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
+ }
+ else // Revenant's original style (from the original mod's disassembly, acknowledged by Revenant)
+ {
+ makevectors(other.v_angle);
+ self.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
+ }
+ self.avelocity = -250 * v_forward; // maybe there is a way to make it look better?
+}
+
+void basketball_touch(void)
+{SELFPARAM();
+ if(other.ballcarried)
+ {
+ football_touch();
+ return;
+ }
+ if(!self.cnt && IS_PLAYER(other) && !other.frozen && !other.deadflag && (other != self.nb_dropper || time > self.nb_droptime + autocvar_g_nexball_delay_collect))
+ {
+ if(other.health <= 0)
+ return;
+ LogNB("caught", other);
+ GiveBall(other, self);
+ }
+ else if(other.solid == SOLID_BSP)
+ {
+ _sound(self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
+ if(vlen(self.velocity) && !self.cnt)
+ self.nextthink = min(time + autocvar_g_nexball_delay_idle, self.teamtime);
+ }
+}
+
+void GoalTouch(void)
+{SELFPARAM();
+ entity ball;
+ float isclient, pscore, otherteam;
+ string pname;
+
+ if(gameover) return;
+ if((self.spawnflags & GOAL_TOUCHPLAYER) && other.ballcarried)
+ ball = other.ballcarried;
+ else
+ ball = other;
+ if(ball.classname != "nexball_basketball")
+ if(ball.classname != "nexball_football")
+ return;
+ if((!ball.pusher && self.team != GOAL_OUT) || ball.cnt)
+ return;
+ EXACTTRIGGER_TOUCH;
+
+
+ if(nb_teams == 2)
+ otherteam = OtherTeam(ball.team);
+ else
+ otherteam = 0;
+
+ if((isclient = IS_CLIENT(ball.pusher)))
+ pname = ball.pusher.netname;
+ else
+ pname = "Someone (?)";
+
+ if(ball.team == self.team) //owngoal (regular goals)
+ {
+ LogNB("owngoal", ball.pusher);
+ bprint("Boo! ", pname, "^7 scored a goal against their own team!\n");
+ pscore = -1;
+ }
+ else if(self.team == GOAL_FAULT)
+ {
+ LogNB("fault", ball.pusher);
+ if(nb_teams == 2)
+ bprint(Team_ColoredFullName(otherteam), " gets a point due to ", pname, "^7's silliness.\n");
+ else
+ bprint(Team_ColoredFullName(ball.team), " loses a point due to ", pname, "^7's silliness.\n");
+ pscore = -1;
+ }
+ else if(self.team == GOAL_OUT)
+ {
+ LogNB("out", ball.pusher);
+ if((self.spawnflags & GOAL_TOUCHPLAYER) && ball.owner)
+ bprint(pname, "^7 went out of bounds.\n");
+ else
+ bprint("The ball was returned.\n");
+ pscore = 0;
+ }
+ else //score
+ {
+ LogNB(strcat("goal:", ftos(self.team)), ball.pusher);
+ bprint("Goaaaaal! ", pname, "^7 scored a point for the ", Team_ColoredFullName(ball.team), ".\n");
+ pscore = 1;
+ }
+
+ _sound(ball, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NONE);
+
+ if(ball.team && pscore)
+ {
+ if(nb_teams == 2 && pscore < 0)
+ TeamScore_AddToTeam(otherteam, ST_NEXBALL_GOALS, -pscore);
+ else
+ TeamScore_AddToTeam(ball.team, ST_NEXBALL_GOALS, pscore);
+ }
+ if(isclient)
+ {
+ if(pscore > 0)
+ PlayerScore_Add(ball.pusher, SP_NEXBALL_GOALS, pscore);
+ else if(pscore < 0)
+ PlayerScore_Add(ball.pusher, SP_NEXBALL_FAULTS, -pscore);
+ }
+
+ if(ball.owner) // Happens on spawnflag GOAL_TOUCHPLAYER
+ DropBall(ball, ball.owner.origin, ball.owner.velocity);
+
+ WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);
+
+ ball.cnt = 1;
+ ball.think = ResetBall;
+ if(ball.classname == "nexball_basketball")
+ ball.touch = football_touch; // better than func_null: football control until the ball gets reset
+ ball.nextthink = time + autocvar_g_nexball_delay_goal * (self.team != GOAL_OUT);
+}
+
+//=======================//
+// team ents //
+//=======================//
+spawnfunc(nexball_team)
+{
+ if(!g_nexball)
+ {
+ remove(self);
+ return;
+ }
+ self.team = self.cnt + 1;
+}
+
+void nb_spawnteam(string teamname, float teamcolor)
+{
+ LOG_TRACE("^2spawned team ", teamname, "\n");
+ entity e;
+ e = spawn();
+ e.classname = "nexball_team";
+ e.netname = teamname;
+ e.cnt = teamcolor;
+ e.team = e.cnt + 1;
+ nb_teams += 1;
+}
+
+void nb_spawnteams(void)
+{
+ bool t_red = false, t_blue = false, t_yellow = false, t_pink = false;
+ entity e;
+ for(e = world; (e = find(e, classname, "nexball_goal"));)
+ {
+ switch(e.team)
+ {
+ case NUM_TEAM_1:
+ if(!t_red)
+ {
+ nb_spawnteam("Red", e.team-1) ;
+ t_red = true;
+ }
+ break;
+ case NUM_TEAM_2:
+ if(!t_blue)
+ {
+ nb_spawnteam("Blue", e.team-1) ;
+ t_blue = true;
+ }
+ break;
+ case NUM_TEAM_3:
+ if(!t_yellow)
+ {
+ nb_spawnteam("Yellow", e.team-1);
+ t_yellow = true;
+ }
+ break;
+ case NUM_TEAM_4:
+ if(!t_pink)
+ {
+ nb_spawnteam("Pink", e.team-1) ;
+ t_pink = true;
+ }
+ break;
+ }
+ }
+}
+
+void nb_delayedinit(void)
+{
+ if(find(world, classname, "nexball_team") == world)
+ nb_spawnteams();
+ nb_ScoreRules(nb_teams);
+}
+
+
+//=======================//
+// spawnfuncs //
+//=======================//
+
+void SpawnBall(void)
+{SELFPARAM();
+ if(!g_nexball) { remove(self); return; }
+
+// balls += 4; // using the remaining bits to count balls will leave more than the max edict count, so it's fine
+
+ if(self.model == "")
+ {
+ self.model = "models/nexball/ball.md3";
+ self.scale = 1.3;
+ }
+
+ precache_model(self.model);
+ _setmodel(self, self.model);
+ setsize(self, BALL_MINS, BALL_MAXS);
+ ball_scale = self.scale;
+
+ relocate_nexball();
+ self.spawnorigin = self.origin;
+
+ self.effects = self.effects | EF_LOWPRECISION;
+
+ if(cvar(strcat("g_", self.classname, "_trail"))) //nexball_basketball :p
+ {
+ self.glow_color = autocvar_g_nexball_trail_color;
+ self.glow_trail = true;
+ }
+
+ self.movetype = MOVETYPE_FLY;
+
+ if(!autocvar_g_nexball_sound_bounce)
+ self.noise = "";
+ else if(self.noise == "")
+ self.noise = SND(NB_BOUNCE);
+ //bounce sound placeholder (FIXME)
+ if(self.noise1 == "")
+ self.noise1 = SND(NB_DROP);
+ //ball drop sound placeholder (FIXME)
+ if(self.noise2 == "")
+ self.noise2 = SND(NB_STEAL);
+ //stealing sound placeholder (FIXME)
+ if(self.noise) precache_sound(self.noise);
+ precache_sound(self.noise1);
+ precache_sound(self.noise2);
+
+ WaypointSprite_AttachCarrier(WP_NbBall, self, RADARICON_FLAGCARRIER); // the ball's team is not set yet, no rule update needed
+
+ self.reset = ball_restart;
+ self.think = InitBall;
+ self.nextthink = game_starttime + autocvar_g_nexball_delay_start;
+}
+
+spawnfunc(nexball_basketball)
+{
+ nexball_mode |= NBM_BASKETBALL;
+ self.classname = "nexball_basketball";
+ if (!(balls & BALL_BASKET))
+ {
+ /*
+ CVTOV(g_nexball_basketball_effects_default);
+ CVTOV(g_nexball_basketball_delay_hold);
+ CVTOV(g_nexball_basketball_delay_hold_forteam);
+ CVTOV(g_nexball_basketball_teamsteal);
+ */
+ autocvar_g_nexball_basketball_effects_default = autocvar_g_nexball_basketball_effects_default & BALL_EFFECTMASK;
+ }
+ if(!self.effects)
+ self.effects = autocvar_g_nexball_basketball_effects_default;
+ self.solid = SOLID_TRIGGER;
+ balls |= BALL_BASKET;
+ self.bouncefactor = autocvar_g_nexball_basketball_bouncefactor;
+ self.bouncestop = autocvar_g_nexball_basketball_bouncestop;
+ SpawnBall();
+}
+
+spawnfunc(nexball_football)
+{
+ nexball_mode |= NBM_FOOTBALL;
+ self.classname = "nexball_football";
+ self.solid = SOLID_TRIGGER;
+ balls |= BALL_FOOT;
+ self.bouncefactor = autocvar_g_nexball_football_bouncefactor;
+ self.bouncestop = autocvar_g_nexball_football_bouncestop;
+ SpawnBall();
+}
+
+float nb_Goal_Customize()
+{SELFPARAM();
+ entity e, wp_owner;
+ e = WaypointSprite_getviewentity(other);
+ wp_owner = self.owner;
+ if(SAME_TEAM(e, wp_owner)) { return false; }
+
+ return true;
+}
+
+void SpawnGoal(void)
+{SELFPARAM();
+ if(!g_nexball) { remove(self); return; }
+
+ EXACTTRIGGER_INIT;
+
+ if(self.team != GOAL_OUT && Team_TeamToNumber(self.team) != -1)
+ {
+ entity wp = WaypointSprite_SpawnFixed(WP_NbGoal, (self.absmin + self.absmax) * 0.5, self, sprite, RADARICON_NONE);
+ wp.colormod = ((self.team) ? Team_ColorRGB(self.team) : '1 0.5 0');
+ self.sprite.customizeentityforclient = nb_Goal_Customize;
+ }
+
+ self.classname = "nexball_goal";
+ if(self.noise == "")
+ self.noise = "ctf/respawn.wav";
+ precache_sound(self.noise);
+ self.touch = GoalTouch;
+}
+
+spawnfunc(nexball_redgoal)
+{
+ self.team = NUM_TEAM_1;
+ SpawnGoal();
+}
+spawnfunc(nexball_bluegoal)
+{
+ self.team = NUM_TEAM_2;
+ SpawnGoal();
+}
+spawnfunc(nexball_yellowgoal)
+{
+ self.team = NUM_TEAM_3;
+ SpawnGoal();
+}
+spawnfunc(nexball_pinkgoal)
+{
+ self.team = NUM_TEAM_4;
+ SpawnGoal();
+}
+
+spawnfunc(nexball_fault)
+{
+ self.team = GOAL_FAULT;
+ if(self.noise == "")
+ self.noise = SND(TYPEHIT);
+ SpawnGoal();
+}
+
+spawnfunc(nexball_out)
+{
+ self.team = GOAL_OUT;
+ if(self.noise == "")
+ self.noise = SND(TYPEHIT);
+ SpawnGoal();
+}
+
+//
+//Spawnfuncs preserved for compatibility
+//
+
+spawnfunc(ball)
+{
+ spawnfunc_nexball_football(this);
+}
+spawnfunc(ball_football)
+{
+ spawnfunc_nexball_football(this);
+}
+spawnfunc(ball_basketball)
+{
+ spawnfunc_nexball_basketball(this);
+}
+// The "red goal" is defended by blue team. A ball in there counts as a point for red.
+spawnfunc(ball_redgoal)
+{
+ spawnfunc_nexball_bluegoal(this); // I blame Revenant
+}
+spawnfunc(ball_bluegoal)
+{
+ spawnfunc_nexball_redgoal(this); // but he didn't mean to cause trouble :p
+}
+spawnfunc(ball_fault)
+{
+ spawnfunc_nexball_fault(this);
+}
+spawnfunc(ball_bound)
+{
+ spawnfunc_nexball_out(this);
+}
+
+//=======================//
+// Weapon code //
+//=======================//
+
+
+void W_Nexball_Think()
+{SELFPARAM();
+ //dprint("W_Nexball_Think\n");
+ //vector new_dir = steerlib_arrive(self.enemy.origin, 2500);
+ vector new_dir = normalize(self.enemy.origin + '0 0 50' - self.origin);
+ vector old_dir = normalize(self.velocity);
+ float _speed = vlen(self.velocity);
+ vector new_vel = normalize(old_dir + (new_dir * autocvar_g_nexball_safepass_turnrate)) * _speed;
+ //vector new_vel = (new_dir * autocvar_g_nexball_safepass_turnrate
+
+ self.velocity = new_vel;
+
+ self.nextthink = time;
+}
+
+void W_Nexball_Touch(void)
+{SELFPARAM();
+ entity ball, attacker;
+ attacker = self.owner;
+ //self.think = func_null;
+ //self.enemy = world;
+
+ PROJECTILE_TOUCH;
+ if(attacker.team != other.team || autocvar_g_nexball_basketball_teamsteal)
+ if((ball = other.ballcarried) && !other.frozen && !other.deadflag && (IS_PLAYER(attacker)))
+ {
+ other.velocity = other.velocity + normalize(self.velocity) * other.damageforcescale * autocvar_g_balance_nexball_secondary_force;
+ other.flags &= ~FL_ONGROUND;
+ if(!attacker.ballcarried)
+ {
+ LogNB("stole", attacker);
+ _sound(other, CH_TRIGGER, ball.noise2, VOL_BASE, ATTEN_NORM);
+
+ if(SAME_TEAM(attacker, other) && time > attacker.teamkill_complain)
+ {
+ attacker.teamkill_complain = time + 5;
+ attacker.teamkill_soundtime = time + 0.4;
+ attacker.teamkill_soundsource = other;
+ }
+
+ GiveBall(attacker, other.ballcarried);
+ }
+ }
+ remove(self);
+}
+
+void W_Nexball_Attack(float t)
+{SELFPARAM();
+ entity ball;
+ float mul, mi, ma;
+ if(!(ball = self.ballcarried))
+ return;
+
+ W_SetupShot(self, false, 4, SND(NB_SHOOT1), CH_WEAPON_A, 0);
+ tracebox(w_shotorg, BALL_MINS, BALL_MAXS, w_shotorg, MOVE_WORLDONLY, world);
+ if(trace_startsolid)
+ {
+ if(self.metertime)
+ self.metertime = 0; // Shot failed, hide the power meter
+ return;
+ }
+
+ //Calculate multiplier
+ if(t < 0)
+ mul = 1;
+ else
+ {
+ mi = autocvar_g_nexball_basketball_meter_minpower;
+ ma = max(mi, autocvar_g_nexball_basketball_meter_maxpower); // avoid confusion
+ //One triangle wave period with 1 as max
+ mul = 2 * (t % g_nexball_meter_period) / g_nexball_meter_period;
+ if(mul > 1)
+ mul = 2 - mul;
+ mul = mi + (ma - mi) * mul; // range from the minimal power to the maximal power
+ }
+
+ DropBall(ball, w_shotorg, W_CalculateProjectileVelocity(self.velocity, w_shotdir * autocvar_g_balance_nexball_primary_speed * mul, false));
+
+
+ //TODO: use the speed_up cvar too ??
+}
+
+vector trigger_push_calculatevelocity(vector org, entity tgt, float ht);
+
+void W_Nexball_Attack2(void)
+{SELFPARAM();
+ if(self.ballcarried.enemy)
+ {
+ entity _ball = self.ballcarried;
+ W_SetupShot(self, false, 4, SND(NB_SHOOT1), CH_WEAPON_A, 0);
+ DropBall(_ball, w_shotorg, trigger_push_calculatevelocity(_ball.origin, _ball.enemy, 32));
+ _ball.think = W_Nexball_Think;
+ _ball.nextthink = time;
+ return;
+ }
+
+ if(!autocvar_g_nexball_tackling)
+ return;
+
+ W_SetupShot(self, false, 2, SND(NB_SHOOT2), CH_WEAPON_A, 0);
+ entity missile = spawn();
+
+ missile.owner = self;
+ missile.classname = "ballstealer";
+
+ missile.movetype = MOVETYPE_FLY;
+ PROJECTILE_MAKETRIGGER(missile);
+
+ //setmodel(missile, "models/elaser.mdl"); // precision set below
+ setsize(missile, '0 0 0', '0 0 0');
+ setorigin(missile, w_shotorg);
+
+ W_SetupProjVelocity_Basic(missile, autocvar_g_balance_nexball_secondary_speed, 0);
+ missile.angles = vectoangles(missile.velocity);
+ missile.touch = W_Nexball_Touch;
+ missile.think = SUB_Remove;
+ missile.nextthink = time + autocvar_g_balance_nexball_secondary_lifetime; //FIXME: use a distance instead?
+
+ missile.effects = EF_BRIGHTFIELD | EF_LOWPRECISION;
+ missile.flags = FL_PROJECTILE;
+
+ CSQCProjectile(missile, true, PROJECTILE_ELECTRO, true);
+}
+
+float ball_customize()
+{SELFPARAM();
+ if(!self.owner)
+ {
+ self.effects &= ~EF_FLAME;
+ self.scale = 1;
+ self.customizeentityforclient = func_null;
+ return true;
+ }
+
+ if(other == self.owner)
+ {
+ self.scale = autocvar_g_nexball_viewmodel_scale;
+ if(self.enemy)
+ self.effects |= EF_FLAME;
+ else
+ self.effects &= ~EF_FLAME;
+ }
+ else
+ {
+ self.effects &= ~EF_FLAME;
+ self.scale = 1;
+ }
+
+ return true;
+}
+
+ METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, bool fire1, bool fire2))
+ {
+ if(fire1)
+ if(weapon_prepareattack(thiswep, actor, false, autocvar_g_balance_nexball_primary_refire))
+ if(autocvar_g_nexball_basketball_meter)
+ {
+ if(self.ballcarried && !self.metertime)
+ self.metertime = time;
+ else
+ weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+ }
+ else
+ {
+ W_Nexball_Attack(-1);
+ weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+ }
+ if(fire2)
+ if(weapon_prepareattack(thiswep, actor, true, autocvar_g_balance_nexball_secondary_refire))
+ {
+ W_Nexball_Attack2();
+ weapon_thinkf(actor, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
+ }
+
+ if(!fire1 && self.metertime && self.ballcarried)
+ {
+ W_Nexball_Attack(time - self.metertime);
+ // DropBall or stealing will set metertime back to 0
+ weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
+ }
+ }
+ METHOD(BallStealer, wr_setup, void(BallStealer thiswep))
+ {
+ //weapon_setup(WEP_PORTO.m_id);
+ }
+ METHOD(BallStealer, wr_checkammo1, bool(BallStealer thiswep))
+ {
+ return true;
+ }
+ METHOD(BallStealer, wr_checkammo2, bool(BallStealer thiswep))
+ {
+ return true;
+ }
+
+MUTATOR_HOOKFUNCTION(nexball_BallDrop)
+{SELFPARAM();
+ if(self.ballcarried && g_nexball)
+ DropBall(self.ballcarried, self.origin, self.velocity);
+
+ return 0;
+}
+
+MUTATOR_HOOKFUNCTION(nexball_PlayerPreThink)
+{SELFPARAM();
+ makevectors(self.v_angle);
+ if(nexball_mode & NBM_BASKETBALL)
+ {
+ if(self.ballcarried)
+ {
+ // 'view ball'
+ self.ballcarried.velocity = self.velocity;
+ self.ballcarried.customizeentityforclient = ball_customize;
+
+ setorigin(self.ballcarried, self.origin + self.view_ofs +
+ v_forward * autocvar_g_nexball_viewmodel_offset.x +
+ v_right * autocvar_g_nexball_viewmodel_offset.y +
+ v_up * autocvar_g_nexball_viewmodel_offset.z);
+
+ // 'safe passing'
+ if(autocvar_g_nexball_safepass_maxdist)
+ {
+ if(self.ballcarried.wait < time && self.ballcarried.enemy)
+ {
+ //centerprint(self, sprintf("Lost lock on %s", self.ballcarried.enemy.netname));
+ self.ballcarried.enemy = world;
+ }
+
+
+ //tracebox(self.origin + self.view_ofs, '-2 -2 -2', '2 2 2', self.origin + self.view_ofs + v_forward * autocvar_g_nexball_safepass_maxdist);
+ crosshair_trace(self);
+ if( trace_ent &&
+ IS_CLIENT(trace_ent) &&
+ trace_ent.deadflag == DEAD_NO &&
+ trace_ent.team == self.team &&
+ vlen(trace_ent.origin - self.origin) <= autocvar_g_nexball_safepass_maxdist )
+ {
+
+ //if(self.ballcarried.enemy != trace_ent)
+ // centerprint(self, sprintf("Locked to %s", trace_ent.netname));
+ self.ballcarried.enemy = trace_ent;
+ self.ballcarried.wait = time + autocvar_g_nexball_safepass_holdtime;
+
+
+ }
+ }
+ }
+ else
+ {
+ if(self.weaponentity.weapons)
+ {
+ self.weapons = self.weaponentity.weapons;
+ Weapon w = WEP_NEXBALL;
+ w.wr_resetplayer(w);
+ self.switchweapon = self.weaponentity.switchweapon;
+ W_SwitchWeapon(self.switchweapon);
+
+ self.weaponentity.weapons = '0 0 0';
+ }
+ }
+
+ }
+
+ nexball_setstatus();
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nexball_PlayerSpawn)
+{SELFPARAM();
+ self.weaponentity.weapons = '0 0 0';
+
+ if(nexball_mode & NBM_BASKETBALL)
+ self.weapons |= WEPSET(NEXBALL);
+ else
+ self.weapons = '0 0 0';
+
+ return false;
+}
+
+.float stat_sv_airspeedlimit_nonqw;
+.float stat_sv_maxspeed;
+
+MUTATOR_HOOKFUNCTION(nexball_PlayerPhysics)
+{SELFPARAM();
+ if(self.ballcarried)
+ {
+ self.stat_sv_airspeedlimit_nonqw *= autocvar_g_nexball_basketball_carrier_highspeed;
+ self.stat_sv_maxspeed *= autocvar_g_nexball_basketball_carrier_highspeed;
+ }
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nexball_ForbidThrowing)
+{SELFPARAM();
+ if(self.weapon == WEP_NEXBALL.m_id)
+ return true;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nexball_FilterItem)
+{SELFPARAM();
+ if(self.classname == "droppedweapon")
+ if(self.weapon == WEP_NEXBALL.m_id)
+ return true;
+
+ return false;
+}
+
+MUTATOR_DEFINITION(gamemode_nexball)
+{
+ MUTATOR_HOOK(PlayerDies, nexball_BallDrop, CBC_ORDER_ANY);
+ MUTATOR_HOOK(MakePlayerObserver, nexball_BallDrop, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ClientDisconnect, nexball_BallDrop, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerSpawn, nexball_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerPreThink, nexball_PlayerPreThink, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerPhysics, nexball_PlayerPhysics, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidThrowCurrentWeapon, nexball_ForbidThrowing, CBC_ORDER_ANY);
+ MUTATOR_HOOK(FilterItem, nexball_FilterItem, CBC_ORDER_ANY);
+
+ MUTATOR_ONADD
+ {
+ g_nexball_meter_period = autocvar_g_nexball_meter_period;
+ if(g_nexball_meter_period <= 0)
+ g_nexball_meter_period = 2; // avoid division by zero etc. due to silly users
+ g_nexball_meter_period = rint(g_nexball_meter_period * 32) / 32; //Round to 1/32ths to send as a byte multiplied by 32
+ addstat(STAT_NB_METERSTART, AS_FLOAT, metertime);
+
+ // General settings
+ /*
+ CVTOV(g_nexball_football_boost_forward); //100
+ CVTOV(g_nexball_football_boost_up); //200
+ CVTOV(g_nexball_delay_idle); //10
+ CVTOV(g_nexball_football_physics); //0
+ */
+ radar_showennemies = autocvar_g_nexball_radar_showallplayers;
+
+ InitializeEntity(world, nb_delayedinit, INITPRIO_GAMETYPE);
+ WEP_NEXBALL.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ WEP_NEXBALL.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+ // we actually cannot roll back nb_delayedinit here
+ // BUT: we don't need to! If this gets called, adding always
+ // succeeds.
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ LOG_INFO("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif
+#endif
--- /dev/null
+#ifndef GAMEMODE_NEXBALL_H
+#define GAMEMODE_NEXBALL_H
+
+#include "weapon.qc"
+
+#ifdef SVQC
+MUTATOR_DECLARATION(gamemode_nexball);
+
+//EF_BRIGHTFIELD|EF_BRIGHTLIGHT|EF_DIMLIGHT|EF_BLUE|EF_RED|EF_FLAME
+const float BALL_EFFECTMASK = 1229;
+const vector BALL_MINS = '-16 -16 -16'; // The model is 24*24*24
+const vector BALL_MAXS = '16 16 16';
+const vector BALL_ATTACHORG = '3 0 16';
+const float BALL_FOOT = 1;
+const float BALL_BASKET = 2;
+//spawnflags
+const float GOAL_TOUCHPLAYER = 1;
+//goal types
+const float GOAL_FAULT = -1;
+const float GOAL_OUT = -2;
+
+void DropBall(entity ball, vector org, vector vel);
+float autocvar_g_nexball_football_boost_forward;
+float autocvar_g_nexball_football_boost_up;
+float autocvar_g_nexball_football_physics;
+float autocvar_g_nexball_delay_idle;
+float autocvar_g_nexball_basketball_delay_hold;
+float autocvar_g_nexball_basketball_delay_hold_forteam;
+float autocvar_g_nexball_basketball_effects_default;
+float autocvar_g_nexball_basketball_teamsteal;
+float autocvar_g_nexball_meter_period;
+
+float balls;
+float ball_scale;
+float nb_teams;
+
+.entity nb_dropper;
+.float nb_droptime;
+
+.float teamtime;
+#endif
+#endif
--- /dev/null
+#ifndef GAMEMODE_NEXBALL_WEAPON_H
+#define GAMEMODE_NEXBALL_WEAPON_H
+
+CLASS(BallStealer, PortoLaunch)
+/* flags */ ATTRIB(BallStealer, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* impulse */ ATTRIB(BallStealer, impulse, int, 0);
+/* refname */ ATTRIB(BallStealer, netname, string, "ballstealer");
+/* wepname */ ATTRIB(BallStealer, message, string, _("Ball Stealer"));
+ENDCLASS(BallStealer)
+REGISTER_WEAPON(NEXBALL, NEW(BallStealer));
+
+#endif
#include "item/jetpack.qc"
#include "item/pickup.qc"
#include "item/powerup.qc"
-#include "../../server/mutators/mutator_instagib_items.qc"
#ifndef ITEMS_ALL_H
#define ITEMS_ALL_H
+#include "../command/all.qh"
+
#include "item.qh"
REGISTRY(Items, BIT(5))
/** If you register a new item, make sure to add it to all.inc */
#define REGISTER_ITEM(id, class) REGISTER(RegisterItems, ITEM, Items, id, m_id, NEW(class))
+REGISTRY_SORT(Items, m_name, 0)
+STATIC_INIT(Items) { FOREACH(Items, true, LAMBDA(it.m_id = i)); }
+
void Dump_Items();
+GENERIC_COMMAND(dumpitems, "Dump all items to the console") {
+ switch (request) {
+ case CMD_REQUEST_COMMAND: {
+ Dump_Items();
+ return;
+ }
+ default:
+ case CMD_REQUEST_USAGE: {
+ LOG_INFOF("\nUsage:^3 %s dumpitems", GetProgramCommandPrefix());
+ return;
+ }
+ }
+}
+
#ifndef MENUQC
string Item_Model(string item_mdl);
#endif
#ifndef GAMEITEM_H
#define GAMEITEM_H
+
+const int IT_UNLIMITED_WEAPON_AMMO = 1; // when this bit is set, using a weapon does not reduce ammo. Checkpoints can give this powerup.
+const int IT_UNLIMITED_SUPERWEAPONS = 2; // when this bit is set, superweapons don't expire. Checkpoints can give this powerup.
+const int IT_CTF_SHIELDED = 4; // set for the flag shield
+const int IT_USING_JETPACK = 8; // confirmation that button is pressed
+const int IT_JETPACK = 16; // actual item
+const int IT_FUEL_REGEN = 32; // fuel regeneration trigger
+// where is 64... ?
+const int IT_FUEL = 128;
+// -Wdouble-declaration
+#define IT_SHELLS 256
+// -Wdouble-declaration
+#define IT_NAILS 512
+// -Wdouble-declaration
+#define IT_ROCKETS 1024
+// -Wdouble-declaration
+#define IT_CELLS 2048
+const int IT_SUPERWEAPON = 4096;
+const int IT_STRENGTH = 8192;
+const int IT_INVINCIBLE = 16384;
+const int IT_HEALTH = 32768;
+const int IT_PLASMA = 65536;
+
+// shared value space (union):
+ // for items:
+ // -Wdouble-declaration
+ #define IT_KEY1 131072
+ // -Wdouble-declaration
+ #define IT_KEY2 262144
+// end
+
+const int IT_5HP = 524288;
+const int IT_25HP = 1048576;
+const int IT_ARMOR_SHARD = 2097152;
+const int IT_ARMOR = 4194304;
+
+// item masks
+const int IT_AMMO = 3968; // IT_FUEL | IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS | IT_PLASMA;
+const int IT_PICKUPMASK = 51; // IT_FUEL_REGEN | IT_JETPACK | IT_UNLIMITED_AMMO; // strength and invincible are handled separately
+const int IT_UNLIMITED_AMMO = 3; // IT_UNLIMITED_SUPERWEAPONS | IT_UNLIMITED_WEAPON_AMMO;
+
#define ITEM_HANDLE(signal, ...) __Item_Send_##signal(__VA_ARGS__)
/** If you register a new item, make sure to add it to all.inc */
CLASS(GameItem, Object)
#include "powerup.qh"
-#include "../../../server/t_items.qh"
#ifndef SVQC
.int m_itemid;
#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
#include "../client/defs.qh"
#include "util.qh"
#include "buffs/all.qh"
#include "mapinfo.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
#include "util.qh"
#include "buffs/all.qh"
#include "monsters/all.qh"
#ifndef CL_MINIGAMES_H
#define CL_MINIGAMES_H
-#include "../../dpdefs/keycodes.qh"
-
// Get a square in the center of the avaliable area
// \note macro to pass by reference pos and mySize
#define minigame_hud_fitsqare(pos, mySize) \
+#include "cl_minigames_hud.qh"
#include "minigames.qh"
-#include "../../client/mapvoting.qh"
// whether the mouse is over the given panel
bool HUD_mouse_over(entity somepanel)
--- /dev/null
+#ifndef CL_MINIGAMES_HUD_H
+#define CL_MINIGAMES_HUD_H
+
+float HUD_Minigame_InputEvent(float bInputType, float nPrimary, float nSecondary);
+void HUD_Minigame_Mouse();
+
+#endif
const float C4_TURN_PLACE = 0x0100; // player has to place a piece on the board
const float C4_TURN_WIN = 0x0200; // player has won
const float C4_TURN_DRAW = 0x0400; // no moves are possible
-const float C4_TURN_TYPE = 0x0f00; // turn type mask
const float C4_TURN_TEAM1 = 0x0001;
const float C4_TURN_TEAM2 = 0x0002;
const int PP_TILE_SIZE = 7;
+.int cnt;
+
.int pp_team1_score;
.int pp_team2_score;
-REGISTER_MINIGAME(snake, "Snake");
+REGISTER_MINIGAME(snake, "Snake"); // SNAAAAKE
const float SNAKE_TURN_MOVE = 0x0100; // the snake is moving, player must control it
-const float SNAKE_TURN_LOSS = 0x0200; // they did it?!
-const float SNAKE_TURN_WAIT = 0x0400; // the snake is waiting for the player to make their first move and begin the game
+const float SNAKE_TURN_WIN = 0x0200; // multiplayer victory
+const float SNAKE_TURN_LOSS = 0x0400; // they did it?!
const float SNAKE_TURN_TYPE = 0x0f00; // turn type mask
+const int SNAKE_TURN_TEAM = 0x000f; // turn team mask
+
const int SNAKE_SF_PLAYERSCORE = MINIG_SF_CUSTOM;
const int SNAKE_LET_CNT = 15;
const int SNAKE_TILE_SIZE = 15;
+const int SNAKE_TEAMS = 6;
+
bool autocvar_sv_minigames_snake_wrap = false;
float autocvar_sv_minigames_snake_delay_initial = 0.7;
float autocvar_sv_minigames_snake_delay_multiplier = 50;
float autocvar_sv_minigames_snake_delay_min = 0.1;
+int autocvar_sv_minigames_snake_lives = 3;
.int snake_score;
-.entity snake_head;
.float snake_delay;
-.float snake_nextmove;
.vector snake_dir;
+.entity snake_next, snake_last, snake_prev;
+
+.bool snake_tail;
+
+.int snake_lives[SNAKE_TEAMS + 1];
+
+.int snake_lost_teams;
+
+bool snake_alone(entity minig)
+{
+ int headcount = 0;
+ entity e = world;
+ while ( ( e = findentity(e,owner,minig) ) )
+ if ( e.classname == "minigame_board_piece" && e.cnt == 1 )
+ ++headcount;
+
+ return headcount <= 1;
+}
+
// find same game piece given its tile name
entity snake_find_piece(entity minig, string tile)
{
}
// find same game piece given its cnt
-entity snake_find_cnt(entity minig, int tile)
+entity snake_find_cnt(entity minig, int steam, int tile)
{
entity e = world;
while ( ( e = findentity(e,owner,minig) ) )
- if ( e.classname == "minigame_board_piece" && e.cnt == tile )
+ if ( e.classname == "minigame_board_piece" && e.cnt == tile && e.team == steam )
return e;
return world;
}
return 0 <= number && number < SNAKE_NUM_CNT && 0 <= letter && letter < SNAKE_LET_CNT;
}
+entity snake_find_head(entity minig, int steam)
+{
+ entity e = world;
+ while ( ( e = findentity(e,owner,minig) ) )
+ if ( e.classname == "minigame_board_piece" && e.cnt == 1 && e.team == steam )
+ return e;
+ return world;
+}
+
void snake_new_mouse(entity minigame)
{
RandomSelection_Init();
}
entity piece = msle_spawn(minigame,"minigame_board_piece");
- piece.team = 1;
+ piece.team = 0;
piece.netname = strzone(RandomSelection_chosen_string);
minigame_server_sendflags(piece,MINIG_SF_ALL);
minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
}
-void snake_move_head(entity minigame);
+entity snake_get_player(entity minigame, int pteam);
+int snake_winning_team(entity minigame)
+{
+ int winning_team = 0;
+ for(int i = 1; i <= SNAKE_TEAMS; ++i)
+ {
+ entity pl = snake_get_player(minigame, i);
+ if(pl && minigame.snake_lives[i] > 0)
+ {
+ if(winning_team)
+ return 0;
+ winning_team = i;
+ }
+ }
+
+ return winning_team;
+}
+
+void snake_check_winner(entity minigame)
+{
+ if(snake_alone(minigame) && !minigame.snake_lost_teams)
+ return;
+
+ int winner = snake_winning_team(minigame);
+
+ int alivecnt = 0;
+ for(int i = 1; i <= SNAKE_TEAMS; ++i)
+ {
+ entity pl = snake_get_player(minigame, i);
+ if(pl && minigame.snake_lives[i] > 0)
+ ++alivecnt;
+ }
+
+ if(!alivecnt)
+ {
+ minigame.minigame_flags = SNAKE_TURN_LOSS;
+ minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+ return;
+ }
+
+ if(winner)
+ {
+ minigame.minigame_flags = SNAKE_TURN_WIN | winner;
+ minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+ }
+}
+
+void snake_move_head(entity minigame, entity head);
void snake_head_think()
{
entity minigame = self.owner;
if(minigame.minigame_flags & SNAKE_TURN_MOVE)
- snake_move_head(minigame);
+ snake_move_head(minigame, self);
- self.nextthink = time + minigame.snake_delay;
+ snake_check_winner(minigame);
+
+ self.nextthink = time + self.snake_delay;
}
-void snake_setup_pieces(entity minigame)
+void minigame_setup_snake(entity minigame, int pteam)
{
- int targnum = bound(1, floor(random() * SNAKE_NUM_CNT), SNAKE_NUM_CNT - 1);
- int targlet = bound(1, floor(random() * SNAKE_LET_CNT), SNAKE_LET_CNT - 1);
+ RandomSelection_Init();
+ int i, j;
+ for(i = 1; i < SNAKE_LET_CNT - 1; ++i)
+ for(j = 1; j < SNAKE_NUM_CNT - 1; ++j)
+ {
+ string pos = minigame_tile_buildname(i, j);
+ if(!snake_find_piece(minigame, pos))
+ RandomSelection_Add(world, 0, pos, 1, 1);
+ }
entity piece = msle_spawn(minigame,"minigame_board_piece");
- piece.team = 1; // init default team?
- piece.netname = strzone(minigame_tile_buildname(targlet,targnum));
+ piece.team = pteam;
+ piece.netname = strzone(RandomSelection_chosen_string);
piece.cnt = 1;
+ piece.snake_next = world;
+ piece.snake_prev = world;
+ piece.snake_last = piece;
piece.think = snake_head_think;
+ piece.snake_delay = autocvar_sv_minigames_snake_delay_initial;
piece.nextthink = time + 0.1;
minigame_server_sendflags(piece,MINIG_SF_ALL);
+}
- minigame.snake_head = piece;
-
+void snake_setup_pieces(entity minigame)
+{
snake_new_mouse(minigame);
minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
}
-void snake_add_score(entity minigame, int thescore)
+entity snake_get_player(entity minigame, int pteam)
+{
+ entity e;
+#ifdef SVQC
+ for(e = minigame.minigame_players; e; e = e.list_next)
+#elif defined(CSQC)
+ e = world;
+ while( (e = findentity(e,owner,minigame)) )
+ if ( e.classname == "minigame_player" )
+#endif
+ if(e.team == pteam)
+ return e;
+ return world;
+}
+
+void snake_add_score(entity minigame, int pteam, int thescore)
{
#ifdef SVQC
if(!minigame)
return;
- if(minigame.minigame_players)
+ entity pl = snake_get_player(minigame, pteam);
+ if(pl)
{
- minigame.minigame_players.snake_score += thescore;
- minigame.minigame_players.SendFlags |= SNAKE_SF_PLAYERSCORE;
+ pl.snake_score += thescore;
+ pl.SendFlags |= SNAKE_SF_PLAYERSCORE;
}
#endif
}
-void snake_move_body(entity minigame, bool ate_mouse)
+void snake_move_body(entity minigame, entity head, bool ate_mouse)
{
- entity tail = world;
- string tailpos = string_null;
- vector taildir = '0 0 0';
-
- int i, pieces = 0;
- for(i = (SNAKE_NUM_CNT * SNAKE_LET_CNT); i >= 2; --i)
+ for(entity e = head.snake_last; e; e = e.snake_prev)
{
- entity piece = snake_find_cnt(minigame, i);
- entity nextpiece = snake_find_cnt(minigame, i - 1);
- if(!piece)
- continue;
+ if(!e || e == head) { break; }
- pieces++;
+ entity nextpiece = e.snake_prev; // can be head
- if(!tail)
- {
- tail = piece;
- tailpos = piece.netname;
- taildir = piece.snake_dir;
- }
-
- if(piece.netname) { strunzone(piece.netname); }
- piece.netname = strzone(nextpiece.netname);
- piece.snake_dir = nextpiece.snake_dir;
- minigame_server_sendflags(piece, MINIG_SF_ALL);
+ if(e.netname) { strunzone(e.netname); }
+ e.netname = strzone(nextpiece.netname);
+ e.snake_dir = nextpiece.snake_dir;
+ minigame_server_sendflags(e, MINIG_SF_UPDATE);
}
- // just a head
- if(!pieces)
+ if(ate_mouse)
{
- tail = minigame.snake_head;
- tailpos = minigame.snake_head.netname;
- taildir = minigame.snake_head.snake_dir;
- }
+ entity tail = head.snake_last;
+
+ tail.snake_tail = false;
- if(tail && ate_mouse)
- {
int newcnt = tail.cnt + 1;
- minigame.snake_delay = max(autocvar_sv_minigames_snake_delay_min, autocvar_sv_minigames_snake_delay_initial - (newcnt / autocvar_sv_minigames_snake_delay_multiplier));
- snake_add_score(minigame, 1);
+ head.snake_delay = max(autocvar_sv_minigames_snake_delay_min, autocvar_sv_minigames_snake_delay_initial - (newcnt / autocvar_sv_minigames_snake_delay_multiplier));
+ snake_add_score(minigame, head.team, 1);
entity piece = msle_spawn(minigame,"minigame_board_piece");
piece.cnt = newcnt;
- piece.team = 1;
- piece.snake_dir = taildir;
- piece.netname = strzone(tailpos);
- minigame_server_sendflags(piece,MINIG_SF_ALL);
+ piece.team = head.team;
+ piece.snake_prev = tail;
+ piece.snake_dir = tail.snake_dir;
+ piece.snake_next = world;
+ piece.snake_tail = true;
+ piece.netname = strzone(tail.netname);
- minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+ tail.snake_next = piece;
+ head.snake_last = piece;
+
+ minigame_server_sendflags(piece,MINIG_SF_UPDATE);
+
+ //minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
}
}
-void snake_move_head(entity minigame)
+void snake_eat_team(entity minigame, int pteam)
{
- entity head = minigame.snake_head;
+ entity head = snake_find_head(minigame, pteam);
+ if(!head) { return; }
+
+ minigame.snake_lives[pteam] -= 1;
+
+ entity pl = snake_get_player(minigame, pteam);
+#ifdef SVQC
+ pl.SendFlags |= SNAKE_SF_PLAYERSCORE;
+#endif
+
+ head.nextthink = time + 1; // make sure they don't to eat us somehow
+
+ entity e = world;
+ while ( ( e = findentity(e,owner,minigame) ) )
+ if ( e.classname == "minigame_board_piece" && e.cnt && e.team == pteam )
+ {
+ if(e.netname) { strunzone(e.netname); }
+ remove(e);
+ }
+
+ if(minigame.snake_lives[pteam] <= 0)
+ minigame.snake_lost_teams |= BIT(pteam);
+
+ if(pl && minigame.snake_lives[pteam] > 0)
+ minigame_setup_snake(minigame, pteam);
+}
+
+void snake_move_head(entity minigame, entity head)
+{
+ if(!head.snake_dir_x && !head.snake_dir_y)
+ return; // nope!
+
string newpos;
if(autocvar_sv_minigames_snake_wrap)
- newpos = minigame_relative_tile(head.netname, minigame.snake_dir_x, minigame.snake_dir_y, SNAKE_NUM_CNT, SNAKE_LET_CNT);
+ newpos = minigame_relative_tile(head.netname, head.snake_dir_x, head.snake_dir_y, SNAKE_NUM_CNT, SNAKE_LET_CNT);
else
{
int myx = minigame_tile_letter(head.netname);
int myy = minigame_tile_number(head.netname);
- myx += minigame.snake_dir_x;
- myy += minigame.snake_dir_y;
+ myx += head.snake_dir_x;
+ myy += head.snake_dir_y;
newpos = minigame_tile_buildname(myx, myy);
}
- if(!snake_valid_tile(newpos) || (snake_find_piece(minigame, newpos)).cnt)
+ entity hit = snake_find_piece(minigame, newpos);
+
+ if(!snake_valid_tile(newpos) || (hit && hit.cnt && hit.team == head.team))
{
- minigame.minigame_flags = SNAKE_TURN_LOSS;
- minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+ if(snake_alone(minigame))
+ {
+ minigame.minigame_flags = SNAKE_TURN_LOSS;
+ minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+ }
+ else
+ {
+ snake_add_score(minigame, head.team, -1);
+ snake_eat_team(minigame, head.team);
+ }
+
return;
}
- bool ate_mouse = false;
- entity piece = snake_find_piece(minigame, newpos);
- if(piece && !piece.cnt)
- ate_mouse = true;
+ bool ate_mouse = (hit && !hit.cnt);
// move the body first, then set the new head position?
- snake_move_body(minigame, ate_mouse);
+ snake_move_body(minigame, head, ate_mouse);
+
+ if(head.netname) { strunzone(head.netname); }
+ head.netname = strzone(newpos);
+ minigame_server_sendflags(head,MINIG_SF_UPDATE);
+
+ // above check makes sure it's not our team
+ if(hit.cnt)
+ {
+ snake_eat_team(minigame, hit.team);
+ snake_add_score(minigame, head.team, 1);
+ }
if(ate_mouse)
{
- if(piece.netname) { strunzone(piece.netname); }
- remove(piece);
+ if(hit.netname) { strunzone(hit.netname); }
+ remove(hit);
snake_new_mouse(minigame);
}
-
- if(head.netname) { strunzone(head.netname); }
- head.netname = strzone(newpos);
- minigame_server_sendflags(head,MINIG_SF_ALL);
}
// make a move
void snake_move(entity minigame, entity player, string dxs, string dys )
{
- if ( (minigame.minigame_flags & SNAKE_TURN_MOVE) || (minigame.minigame_flags & SNAKE_TURN_WAIT) )
+ if ( minigame.minigame_flags & SNAKE_TURN_MOVE )
if ( dxs || dys )
{
//if ( snake_valid_tile(pos) )
//if ( snake_find_piece(minigame, pos) )
{
+ entity head = snake_find_head(minigame, player.team);
+ if(!head)
+ return; // their head is already dead
+
int dx = ((dxs) ? bound(-1, stof(dxs), 1) : 0);
int dy = ((dys) ? bound(-1, stof(dys), 1) : 0);
- int myl = minigame_tile_letter(minigame.snake_head.netname);
- int myn = minigame_tile_number(minigame.snake_head.netname);
+ int myl = minigame_tile_letter(head.netname);
+ int myn = minigame_tile_number(head.netname);
- entity head = snake_find_piece(minigame, minigame_tile_buildname(myl + dx, myn + dy));
- if(head && head.cnt == 2)
+ entity check_piece = snake_find_piece(minigame, minigame_tile_buildname(myl + dx, myn + dy));
+ if(check_piece && check_piece.cnt == 2)
return; // nope!
- if(minigame.minigame_flags & SNAKE_TURN_WAIT)
- minigame.snake_nextmove = time;
- minigame.minigame_flags = SNAKE_TURN_MOVE;
- minigame.snake_dir_x = dx;
- minigame.snake_dir_y = dy;
- minigame.snake_dir_z = 0;
- minigame.snake_head.snake_dir = minigame.snake_dir;
- minigame_server_sendflags(minigame.snake_head,MINIG_SF_UPDATE);
+ if(head.snake_dir == '0 0 0')
+ head.nextthink = time; // TODO: make sure this can't be exploited!
+ head.snake_dir_x = dx;
+ head.snake_dir_y = dy;
+ head.snake_dir_z = 0;
+ minigame_server_sendflags(head,MINIG_SF_UPDATE);
minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
}
}
case "start":
{
snake_setup_pieces(minigame);
- minigame.snake_delay = autocvar_sv_minigames_snake_delay_initial;
- minigame.minigame_flags = SNAKE_TURN_WAIT;
+ minigame.minigame_flags = SNAKE_TURN_MOVE;
+ minigame.snake_lost_teams = 0;
+
+ if(SNAKE_TEAMS > 1)
+ {
+ for(int i = 1; i <= SNAKE_TEAMS; ++i)
+ minigame.snake_lives[i] = autocvar_sv_minigames_snake_lives;
+ }
+ else
+ minigame.snake_lives[1] = 1;
+
return true;
}
case "end":
if(e.netname) { strunzone(e.netname); }
remove(e);
}
- minigame.snake_head = world;
return false;
}
case "join":
{
int pl_num = minigame_count_players(minigame);
- // Don't allow more than 1 player
- // not sure if this should be a multiplayer game (might get crazy)
- if(pl_num >= 1) { return false; }
+ if(pl_num >= SNAKE_TEAMS) { return false; }
- // Team 1 by default
- return 1;
+ int t = 1; // Team 1 by default
+
+ for(int i = 1; i <= SNAKE_TEAMS; ++i)
+ {
+ entity e = snake_get_player(minigame, i);
+ if(!e)
+ {
+ t = i;
+ break;
+ }
+ }
+
+ if(!snake_find_head(minigame, t) && !(minigame.snake_lost_teams & BIT(t)))
+ {
+ entity pl = ...(1,entity);
+ if(pl)
+ {
+ //pl.snake_lives = ((SNAKE_TEAMS > 1) ? autocvar_sv_minigames_snake_lives : 1);
+ // send score anyway, lives are set
+ pl.SendFlags |= SNAKE_SF_PLAYERSCORE;
+ }
+ minigame_setup_snake(minigame, t);
+ }
+
+ return t;
}
case "cmd":
{
int sf = ...(1,int);
if ( sent.classname == "minigame_board_piece" && (sf & MINIG_SF_UPDATE) )
{
+ int letter = minigame_tile_letter(sent.netname);
+ int number = minigame_tile_number(sent.netname);
+
+ WriteByte(MSG_ENTITY,letter);
+ WriteByte(MSG_ENTITY,number);
+
WriteByte(MSG_ENTITY,sent.cnt);
- WriteCoord(MSG_ENTITY,sent.snake_dir_x);
- WriteCoord(MSG_ENTITY,sent.snake_dir_y);
+ WriteByte(MSG_ENTITY,sent.snake_tail);
+
+ int dx = sent.snake_dir_x;
+ int dy = sent.snake_dir_y;
+ if(dx == -1) dx = 2;
+ if(dy == -1) dy = 2;
+ WriteByte(MSG_ENTITY,dx);
+ WriteByte(MSG_ENTITY,dy);
}
else if ( sent.classname == "minigame_player" && (sf & SNAKE_SF_PLAYERSCORE ) )
{
WriteLong(MSG_ENTITY,sent.snake_score);
+ WriteByte(MSG_ENTITY,max(0, minigame.snake_lives[sent.team]));
}
else if ( sent.classname == "minigame" && (sf & MINIG_SF_UPDATE ) )
{
bool snake_wrap;
+vector snake_teamcolor(int steam)
+{
+ switch(steam)
+ {
+ case 1: return '1 0 0';
+ case 2: return '0 0 1';
+ case 3: return '1 1 0';
+ case 4: return '1 0 1';
+ case 5: return '0 1 0';
+ case 6: return '0 1 1';
+ }
+
+ return '1 1 1';
+}
+
// Required function, draw the game board
void snake_hud_board(vector pos, vector mySize)
{
vector tile_size = minigame_hud_denormalize_size('1 1 0' / SNAKE_TILE_SIZE,pos,mySize);
vector tile_pos;
- entity tail = world;
- int i;
- for(i = (SNAKE_NUM_CNT * SNAKE_LET_CNT); i >= 2; --i)
- {
- entity piece = snake_find_cnt(active_minigame, i);
- if(piece)
- {
- tail = piece;
- break;
- }
- }
-
entity e;
FOREACH_MINIGAME_ENTITY(e)
{
{
tile_pos = minigame_tile_pos(e.netname,SNAKE_NUM_CNT,SNAKE_LET_CNT);
tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
+
+ vector tile_color = snake_teamcolor(e.team);
+
string thepiece = "snake/mouse";
if(e.cnt)
thepiece = "snake/body";
- if(tail && e.cnt == tail.cnt)
+ if(e.snake_tail)
thepiece = "snake/tail";
if(e.cnt == 1)
{
int dy = minigame_tile_number(e.netname) + e.snake_dir_y * 2;
entity mouse = snake_find_piece(active_minigame, minigame_tile_buildname(dx, dy));
thepiece = "snake/head";
- if(mouse && !mouse.cnt)
+ if(mouse && mouse.team != e.team)
{
float myang = 0;
int myx = minigame_tile_letter(e.netname);
my_pos = minigame_hud_denormalize(my_pos,pos,mySize);
drawrotpic(my_pos, myang, minigame_texture("snake/tongue"),
- tile_size, tile_size/2, '1 1 1',
+ tile_size, tile_size/2, tile_color,
panel_fg_alpha, DRAWFLAG_NORMAL );
}
}
- if(e.cnt == 1 || e.cnt == tail.cnt)
+ if(e.cnt == 1 || e.snake_tail)
{
vector thedir = e.snake_dir;
float theang = 0;
- if(e.cnt == tail.cnt)
+ if(e.snake_tail)
{
int thex = minigame_tile_letter(e.netname);
int they = minigame_tile_number(e.netname);
- entity t = snake_find_cnt(active_minigame, e.cnt - 1);
+ entity t = snake_find_cnt(active_minigame, e.team, e.cnt - 1);
int tx = minigame_tile_letter(t.netname);
int ty = minigame_tile_number(t.netname);
theang = M_PI*3/2;
drawrotpic(tile_pos, theang, minigame_texture(thepiece),
- tile_size, tile_size/2, '1 1 1',
+ tile_size, tile_size/2, tile_color,
panel_fg_alpha, DRAWFLAG_NORMAL );
}
else
{
minigame_drawpic_centered( tile_pos,
minigame_texture(thepiece),
- tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
+ tile_size, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
}
}
}
- if ( active_minigame.minigame_flags & SNAKE_TURN_LOSS )
+ if ( (active_minigame.minigame_flags & SNAKE_TURN_LOSS) || (active_minigame.minigame_flags & SNAKE_TURN_WIN) || (active_minigame.snake_lives[minigame_self.team] <= 0) )
{
- int scores = 0;
- FOREACH_MINIGAME_ENTITY(e)
- if(e.classname == "minigame_player")
- scores = e.snake_score;
+ int scores = minigame_self.snake_score;
vector winfs = hud_fontsize*2;
- string scores_text;
+ string scores_text, victory_text;
+ victory_text = "Game over!";
scores_text = strcat("Score: ", ftos(scores));
+
+ if(active_minigame.minigame_flags & SNAKE_TURN_WIN)
+ if((active_minigame.minigame_flags & SNAKE_TURN_TEAM) == minigame_self.team)
+ victory_text = "You win!";
+ if(active_minigame.snake_lives[minigame_self.team] <= 0)
+ victory_text = "You ran out of lives!";
vector win_pos = pos+eY*(mySize_y-winfs_y)/2;
vector win_sz;
win_sz = minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
- sprintf("Game over! %s", scores_text),
+ sprintf("%s %s", victory_text, scores_text),
winfs, 0, DRAWFLAG_NORMAL, 0.5);
drawfill(win_pos-eY*hud_fontsize_y,win_sz+2*eY*hud_fontsize_y,'0.3 0.3 1',0.8,DRAWFLAG_ADDITIVE);
minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
- sprintf("Game over! %s", scores_text),
+ sprintf("%s %s", victory_text, scores_text),
winfs, panel_fg_alpha, DRAWFLAG_NORMAL, 0.5);
}
}
vector ts;
ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
-
+
pos_y += ts_y;
mySize_y -= ts_y;
-
+
vector player_fontsize = hud_fontsize * 1.75;
- ts_y = ( mySize_y - 2*player_fontsize_y ) / 2;
+ ts_y = ( mySize_y - 2*player_fontsize_y ) / SNAKE_TEAMS;
ts_x = mySize_x;
vector mypos;
vector tile_size = '48 48 0';
mypos = pos;
+ if ( minigame_self.team > 1 )
+ mypos_y += player_fontsize_y + (ts_y * (minigame_self.team - 1));
drawfill(mypos,eX*mySize_x+eY*player_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
mypos_y += player_fontsize_y;
drawfill(mypos,eX*mySize_x+eY*tile_size_y,'1 1 1',0.25,DRAWFLAG_ADDITIVE);
if ( e.classname == "minigame_player" )
{
mypos = pos;
+ if ( e.team > 1 )
+ mypos_y += player_fontsize_y + (ts_y * (e.team - 1));
minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
GetPlayerName(e.minigame_playerslot-1),
player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
-
+
+ vector tile_color = snake_teamcolor(e.team);
+
mypos_y += player_fontsize_y;
- //drawpic( mypos,
- // minigame_texture("snake/piece"),
- // tile_size, '1 0 0', panel_fg_alpha, DRAWFLAG_NORMAL );
-
- //mypos_x += tile_size_x;
+ drawpic( mypos,
+ minigame_texture("snake/head"),
+ tile_size * 0.7, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
+
+ mypos_x += tile_size_x;
drawstring(mypos,ftos(e.snake_score),tile_size,
'0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ mypos_x += tile_size_x;
+
+ drawstring(mypos,strcat("1UP: ", ftos(active_minigame.snake_lives[e.team])),tile_size * 0.6,
+ '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
}
}
}
{
if ( turnflags & SNAKE_TURN_LOSS )
return _("Game over!");
+
+ if ( turnflags & SNAKE_TURN_WIN )
+ {
+ if ( (turnflags&SNAKE_TURN_TEAM) != minigame_self.team )
+ return _("You ran out of lives!");
+ return _("You win!");
+ }
+
+ if(active_minigame.snake_lives[minigame_self.team] <= 0)
+ return _("You ran out of lives!");
- if ( turnflags & SNAKE_TURN_WAIT )
+ if ( (snake_find_head(active_minigame, minigame_self.team)).snake_dir == '0 0 0' )
return _("Press an arrow key to begin the game");
if ( turnflags & SNAKE_TURN_MOVE )
{
if(sf & MINIG_SF_UPDATE)
{
+ int letter = ReadByte();
+ int number = ReadByte();
+ if(sent.netname) { strunzone(sent.netname); }
+ sent.netname = strzone(minigame_tile_buildname(letter, number));
+
sent.cnt = ReadByte();
- sent.snake_dir_x = ReadCoord();
- sent.snake_dir_y = ReadCoord();
+ sent.snake_tail = ReadByte();
+
+ int dx = ReadByte();
+ int dy = ReadByte();
+
+ if(dx == 2) dx = -1;
+ if(dy == 2) dy = -1;
+
+ sent.snake_dir_x = dx;
+ sent.snake_dir_y = dy;
sent.snake_dir_z = 0;
- if(sent.cnt == 1)
- minigame.snake_head = sent; // hax
}
}
else if ( sent.classname == "minigame_player" && (sf & SNAKE_SF_PLAYERSCORE ) )
{
sent.snake_score = ReadLong();
+ minigame.snake_lives[sent.team] = ReadByte();
}
return false;
return 0;
minigame_rmplayer(player.active_minigame,player);
}
-
- int mgteam = minigame_session.minigame_event(minigame_session,"join",player);
+ entity player_pointer = spawn();
+ int mgteam = minigame_session.minigame_event(minigame_session,"join",player,player_pointer);
if ( mgteam )
{
- entity player_pointer = spawn();
player_pointer.classname = "minigame_player";
player_pointer.owner = minigame_session;
player_pointer.minigame_players = player;
minigame_resend(minigame_session);
}
+ else { remove(player_pointer); }
GameLogEcho(strcat(":minigame:join",(mgteam?"":"fail"),":",minigame_session.netname,":",
ftos(num_for_edict(player)),":",player.netname));
#ifndef MODELS_ALL_H
#define MODELS_ALL_H
-#define setmodel(e, m) _setmodel((e), (m).model_str())
+#include "model.qh"
REGISTRY(Models, BIT(9))
REGISTER_REGISTRY(RegisterModels)
-CLASS(Model, Object)
- ATTRIB(Model, m_id, int, 0)
- ATTRIB(Model, model_str, string(), func_null)
- CONSTRUCTOR(Model, string() path)
- {
- CONSTRUCT(Model);
- this.model_str = path;
- }
- METHOD(Model, model_precache, void(entity this)) {
- string s = this.model_str();
- if (s != "" && s != "null" && !fexists(s)) {
- LOG_WARNINGF("Missing model: \"%s\"\n", s);
- return;
- }
- LOG_TRACEF("precache_model(\"%s\")\n", s);
- precache_model(s);
- }
-ENDCLASS(Model)
-
#define MODEL(name, path) \
string MDL_##name##_get() { return path; } \
REGISTER(RegisterModels, MDL, Models, name, m_id, NEW(Model, MDL_##name##_get))
--- /dev/null
+#ifndef MODEL_H
+#define MODEL_H
+
+#define setmodel(e, m) _setmodel((e), (m).model_str())
+
+CLASS(Model, Object)
+ ATTRIB(Model, m_id, int, 0)
+ ATTRIB(Model, model_str, string(), func_null)
+ CONSTRUCTOR(Model, string() path)
+ {
+ CONSTRUCT(Model);
+ this.model_str = path;
+ }
+ METHOD(Model, model_precache, void(entity this)) {
+ string s = this.model_str();
+ if (s != "" && s != "null" && !fexists(s)) {
+ LOG_WARNINGF("Missing model: \"%s\"\n", s);
+ return;
+ }
+ LOG_TRACEF("precache_model(\"%s\")\n", s);
+ precache_model(s);
+ }
+ENDCLASS(Model)
+
+#endif
#ifndef MONSTER_H
#define MONSTER_H
+#ifdef SVQC
+#include "sv_monsters.qh"
+#include "../../server/g_damage.qh"
+#include "../../server/bot/bot.qh"
+#include "../../server/weapons/common.qh"
+#include "../../server/weapons/tracing.qh"
+#include "../../server/weapons/weaponsystem.qh"
+#include "../mutators/mutator/waypoints/waypointsprites.qh"
+#include "../../lib/warpzone/server.qh"
+#endif
+
// special spawn flags
const int MONSTER_RESPAWN_DEATHPOINT = 16; // re-spawn where we died
const int MONSTER_TYPE_FLY = 32;
}
#include "../../weapons/all.qh"
+#include "../../items/all.qc"
CLASS(MageSpike, PortoLaunch)
/* flags */ ATTRIB(MageSpike, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
M_Mage_Attack_Spike_Explode();
}
+.float wait;
+
// copied from W_Seeker_Think
void M_Mage_Attack_Spike_Think()
{SELFPARAM();
}
#endif
#ifdef SVQC
+ .float speed;
+ spawnfunc(item_health_large);
METHOD(Mage, mr_setup, bool(Monster thismon))
{
SELFPARAM();
}
}
+#include "../../../server/csqceffects.qh"
+
void M_Shambler_Attack_Lightning_Explode()
{SELFPARAM();
entity head;
CSQCProjectile(gren, true, PROJECTILE_SHAMBLER_LIGHTNING, true);
}
+.int state;
+
float M_Shambler_Attack(float attack_type, entity targ)
{SELFPARAM();
switch(attack_type)
}
#endif
#ifdef SVQC
+ spawnfunc(item_health_mega);
+ .float animstate_endtime;
METHOD(Shambler, mr_setup, bool(Shambler thismon))
{
SELFPARAM();
M_Spider_Attack_Web_Explode();
}
+void adaptor_think2use_hittype_splash();
+
void M_Spider_Attack_Web()
{SELFPARAM();
monster_makevectors(self.enemy);
}
#endif
#ifdef SVQC
+ spawnfunc(item_health_medium);
METHOD(Spider, mr_setup, bool(Spider thismon))
{
SELFPARAM();
}
#endif
#ifdef SVQC
+ spawnfunc(item_cells);
METHOD(Wyvern, mr_setup, bool(Wyvern thismon))
{
SELFPARAM();
const float zombie_anim_spawn = 30;
*/
+.vector moveto;
+
void M_Zombie_Attack_Leap_Touch()
{SELFPARAM();
if (self.health <= 0)
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
#include "../util.qh"
#include "all.qh"
#include "sv_monsters.qh"
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../warpzonelib/common.qh"
+ #include "../../lib/warpzone/common.qh"
#include "../constants.qh"
#include "../teams.qh"
#include "../util.qh"
#include "../../server/command/common.qh"
#include "../../server/command/cmd.qh"
#include "../triggers/triggers.qh"
- #include "../../csqcmodellib/sv_model.qh"
+ #include "../../lib/csqcmodel/sv_model.qh"
#include "../../server/round_handler.qh"
#endif
void Monster_Sound(.string samplefield, float sound_delay, float delaytoo, float chan);
+/** number of monsters spawned with mobspawn command */
+int totalspawned;
+
// monster sounds
.float msound_delay; // temporary antilag system
#define ALLMONSTERSOUNDS \
#include "../physics.qh"
#if defined(CSQC)
- #include "../../dpdefs/csprogsdefs.qh"
#include "../../client/defs.qh"
#include "../stats.qh"
#include "../util.qh"
#include "movetypes.qh"
- #include "../../csqcmodellib/common.qh"
+ #include "../../lib/csqcmodel/common.qh"
#include "../../server/t_items.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
#include "mutator/casings.qc"
#include "mutator/damagetext.qc"
+#include "mutator/instagib/instagib.qc"
#include "mutator/itemstime.qc"
#include "mutator/waypoints/waypointsprites.qc"
+#include "all.qh"
+
+#define IMPLEMENTATION
#include "all.inc"
+#undef IMPLEMENTATION
--- /dev/null
+#ifndef MUTATORS_ALL_H
+#define MUTATORS_ALL_H
+
+#include "all.inc"
+
+#endif
}
ENDCLASS(Mutator)
-const int MAX_MUTATORS = 20;
+const int MAX_MUTATORS = 30;
Mutator loaded_mutators[MAX_MUTATORS];
bool Mutator_Add(Mutator mut)
#define MUTATOR_HOOK(cb, func, order) do { \
MUTATOR_ONADD { \
if (!CallbackChain_Add(HOOK_##cb, CALLBACK_##func, order)) { \
- LOG_INFO("HOOK FAILED: ", #cb, ":", #func, "\n"); \
+ LOG_INFO("HOOK FAILED: ", #cb, ":", #func, "\n"); \
return true; \
} \
} \
+#ifdef IMPLEMENTATION
+
#include "../../util.qh"
#ifdef CSQC
}
#endif
+#endif
+#ifndef MUTATOR_DAMAGETEXT_H
+#define MUTATOR_DAMAGETEXT_H
+
+#ifdef MENUQC
+#include "../../../menu/xonotic/tab.qc"
+#endif
+
+#endif
+
+#ifdef IMPLEMENTATION
REGISTER_MUTATOR(damagetext, true);
#if defined(CSQC) || defined(MENUQC)
#endif
#ifdef MENUQC
-#include "../../../menu/xonotic/tab.qc"
CLASS(XonoticDamageTextSettings, XonoticTab)
#include "../../../menu/gamesettings.qh"
REGISTER_SETTINGS(damagetext, NEW(XonoticDamageTextSettings));
}
ENDCLASS(XonoticDamageTextSettings)
#endif
+#endif
--- /dev/null
+#ifndef MUTATOR_INSTAGIB_H
+#define MUTATOR_INSTAGIB_H
+
+#include "items.qc"
+
+#endif
+
+#ifdef IMPLEMENTATION
+#ifdef SVQC
+
+#include "../../../../server/cl_client.qh"
+#include "../../../buffs/all.qh"
+
+#include "../../../items/all.qc"
+
+REGISTER_MUTATOR(mutator_instagib, cvar("g_instagib") && !g_nexball);
+
+spawnfunc(item_minst_cells)
+{
+ if (!g_instagib) { remove(self); return; }
+ if (!self.ammo_cells) self.ammo_cells = autocvar_g_instagib_ammo_drop;
+ StartItemA(ITEM_VaporizerCells);
+}
+
+void instagib_invisibility()
+{SELFPARAM();
+ self.strength_finished = autocvar_g_balance_powerup_strength_time;
+ StartItemA(ITEM_Invisibility);
+}
+
+void instagib_extralife()
+{SELFPARAM();
+ self.max_health = 1;
+ StartItemA(ITEM_ExtraLife);
+}
+
+void instagib_speed()
+{SELFPARAM();
+ self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
+ StartItemA(ITEM_Speed);
+}
+
+.float instagib_nextthink;
+.float instagib_needammo;
+void instagib_stop_countdown(entity e)
+{
+ if (!e.instagib_needammo)
+ return;
+ Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_INSTAGIB_FINDAMMO);
+ e.instagib_needammo = false;
+}
+void instagib_ammocheck()
+{SELFPARAM();
+ if(time < self.instagib_nextthink)
+ return;
+ if(!IS_PLAYER(self))
+ return; // not a player
+
+ if(self.deadflag || gameover)
+ instagib_stop_countdown(self);
+ else if (self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO) || (self.flags & FL_GODMODE))
+ instagib_stop_countdown(self);
+ else if(autocvar_g_rm && autocvar_g_rm_laser)
+ {
+ if(!self.instagib_needammo)
+ {
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_INSTAGIB_DOWNGRADE);
+ self.instagib_needammo = true;
+ }
+ }
+ else
+ {
+ self.instagib_needammo = true;
+ if (self.health <= 5)
+ {
+ Damage(self, self, self, 5, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_INSTAGIB_TERMINATED);
+ }
+ else if (self.health <= 10)
+ {
+ Damage(self, self, self, 5, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_1);
+ }
+ else if (self.health <= 20)
+ {
+ Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_2);
+ }
+ else if (self.health <= 30)
+ {
+ Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_3);
+ }
+ else if (self.health <= 40)
+ {
+ Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_4);
+ }
+ else if (self.health <= 50)
+ {
+ Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_5);
+ }
+ else if (self.health <= 60)
+ {
+ Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_6);
+ }
+ else if (self.health <= 70)
+ {
+ Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_7);
+ }
+ else if (self.health <= 80)
+ {
+ Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_8);
+ }
+ else if (self.health <= 90)
+ {
+ Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_INSTAGIB_FINDAMMO);
+ Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
+ Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_9);
+ }
+ else
+ {
+ Send_Notification(NOTIF_ONE_ONLY, self, MSG_MULTI, MULTI_INSTAGIB_FINDAMMO);
+ Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
+ }
+ }
+ self.instagib_nextthink = time + 1;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, MatchEnd)
+{
+ entity head;
+ FOR_EACH_PLAYER(head)
+ instagib_stop_countdown(head);
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterDropItem)
+{
+ other.monster_loot = spawnfunc_item_minst_cells;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterSpawn)
+{SELFPARAM();
+ // always refill ammo
+ if(self.monsterid == MON_MAGE.monsterid)
+ self.skin = 1;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, BotShouldAttack)
+{
+ if (checkentity.items & ITEM_Invisibility.m_itemid)
+ return true;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, MakePlayerObserver)
+{SELFPARAM();
+ instagib_stop_countdown(self);
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerSpawn)
+{SELFPARAM();
+ self.effects |= EF_FULLBRIGHT;
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPreThink)
+{
+ instagib_ammocheck();
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerRegen)
+{
+ // no regeneration in instagib
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPowerups)
+{SELFPARAM();
+ if (!(self.effects & EF_FULLBRIGHT))
+ self.effects |= EF_FULLBRIGHT;
+
+ if (self.items & ITEM_Invisibility.m_itemid)
+ {
+ play_countdown(self.strength_finished, SND(POWEROFF));
+ if (time > self.strength_finished)
+ {
+ self.alpha = default_player_alpha;
+ self.exteriorweaponentity.alpha = default_weapon_alpha;
+ self.items &= ~ITEM_Invisibility.m_itemid;
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
+ }
+ }
+ else
+ {
+ if (time < self.strength_finished)
+ {
+ self.alpha = autocvar_g_instagib_invis_alpha;
+ self.exteriorweaponentity.alpha = autocvar_g_instagib_invis_alpha;
+ self.items |= ITEM_Invisibility.m_itemid;
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_INVISIBILITY, self.netname);
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
+ }
+ }
+
+ if (self.items & ITEM_Speed.m_itemid)
+ {
+ play_countdown(self.invincible_finished, SND(POWEROFF));
+ if (time > self.invincible_finished)
+ {
+ self.items &= ~ITEM_Speed.m_itemid;
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SPEED);
+ }
+ }
+ else
+ {
+ if (time < self.invincible_finished)
+ {
+ self.items |= ITEM_Speed.m_itemid;
+ Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SPEED, self.netname);
+ Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SPEED);
+ }
+ }
+ return false;
+}
+
+.float stat_sv_maxspeed;
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPhysics)
+{SELFPARAM();
+ if(self.items & ITEM_Speed.m_itemid)
+ self.stat_sv_maxspeed = self.stat_sv_maxspeed * autocvar_g_instagib_speed_highspeed;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_SplitHealthArmor)
+{
+ damage_save = 0;
+ damage_take = frag_damage;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, ForbidThrowCurrentWeapon)
+{
+ // weapon dropping on death handled by FilterItem
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_Calculate)
+{
+ if(autocvar_g_friendlyfire == 0 && SAME_TEAM(frag_target, frag_attacker) && IS_PLAYER(frag_target) && IS_PLAYER(frag_attacker))
+ frag_damage = 0;
+
+ if(IS_PLAYER(frag_target))
+ {
+ if(frag_deathtype == DEATH_FALL.m_id)
+ frag_damage = 0; // never count fall damage
+
+ if(!autocvar_g_instagib_damagedbycontents)
+ switch(DEATH_ENT(frag_deathtype))
+ {
+ case DEATH_DROWN:
+ case DEATH_SLIME:
+ case DEATH_LAVA:
+ frag_damage = 0;
+ break;
+ }
+
+ if(IS_PLAYER(frag_attacker))
+ if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
+ {
+ if(frag_target.armorvalue)
+ {
+ frag_target.armorvalue -= 1;
+ frag_damage = 0;
+ frag_target.damage_dealt += 1;
+ frag_attacker.damage_dealt += 1; // TODO: change this to a specific hitsound for armor hit
+ Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_target.armorvalue);
+ }
+ }
+
+ if(IS_PLAYER(frag_attacker) && DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
+ {
+ if(frag_deathtype & HITTYPE_SECONDARY)
+ {
+ if(!autocvar_g_instagib_blaster_keepdamage)
+ frag_damage = frag_mirrordamage = 0;
+
+ if(frag_target != frag_attacker)
+ {
+ if(frag_damage <= 0 && frag_target.health > 0) { Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE); }
+ if(!autocvar_g_instagib_blaster_keepforce)
+ frag_force = '0 0 0';
+ }
+ }
+ }
+ }
+
+ if(IS_PLAYER(frag_attacker))
+ if(frag_mirrordamage > 0)
+ {
+ // just lose extra LIVES, don't kill the player for mirror damage
+ if(frag_attacker.armorvalue > 0)
+ {
+ frag_attacker.armorvalue -= 1;
+ Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_attacker.armorvalue);
+ frag_attacker.damage_dealt += frag_mirrordamage;
+ }
+ frag_mirrordamage = 0;
+ }
+
+ if((frag_target.buffs & BUFF_INVISIBLE.m_itemid) || (frag_target.items & ITEM_Invisibility.m_itemid))
+ yoda = 1;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, SetStartItems)
+{
+ start_health = warmup_start_health = 100;
+ start_armorvalue = warmup_start_armorvalue = 0;
+
+ start_ammo_shells = warmup_start_ammo_shells = 0;
+ start_ammo_nails = warmup_start_ammo_nails = 0;
+ start_ammo_cells = warmup_start_ammo_cells = cvar("g_instagib_ammo_start");
+ start_ammo_plasma = warmup_start_ammo_plasma = 0;
+ start_ammo_rockets = warmup_start_ammo_rockets = 0;
+ start_ammo_fuel = warmup_start_ammo_fuel = 0;
+
+ start_weapons = warmup_start_weapons = WEPSET(VAPORIZER);
+ start_items |= IT_UNLIMITED_SUPERWEAPONS;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, FilterItem)
+{SELFPARAM();
+ if(self.classname == "item_cells")
+ return true; // no normal cells?
+
+ if(self.weapon == WEP_VAPORIZER.m_id && self.classname == "droppedweapon")
+ {
+ self.ammo_cells = autocvar_g_instagib_ammo_drop;
+ return false;
+ }
+
+ if(self.weapon == WEP_DEVASTATOR.m_id || self.weapon == WEP_VORTEX.m_id)
+ {
+ entity e = spawn();
+ setorigin(e, self.origin);
+ e.noalign = self.noalign;
+ e.cnt = self.cnt;
+ e.team = self.team;
+ WITH(entity, self, e, spawnfunc_item_minst_cells(e));
+ return true;
+ }
+
+ if(self.flags & FL_POWERUP)
+ return false;
+
+ if(self.ammo_cells > autocvar_g_instagib_ammo_drop && self.classname != "item_minst_cells")
+ self.ammo_cells = autocvar_g_instagib_ammo_drop;
+
+ if(self.ammo_cells && !self.weapon)
+ return false;
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, CustomizeWaypoint)
+{SELFPARAM();
+ entity e = WaypointSprite_getviewentity(other);
+
+ // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
+ // but only apply this to real players, not to spectators
+ if((self.owner.flags & FL_CLIENT) && (self.owner.items & ITEM_Invisibility.m_itemid) && (e == other))
+ if(DIFF_TEAM(self.owner, e))
+ return true;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDies)
+{
+ if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
+ frag_damage = 1000; // always gib if it was a vaporizer death
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, ItemTouch)
+{SELFPARAM();
+ if(self.ammo_cells)
+ {
+ // play some cool sounds ;)
+ if (IS_CLIENT(other))
+ {
+ if(other.health <= 5)
+ Send_Notification(NOTIF_ONE, other, MSG_ANNCE, ANNCE_INSTAGIB_LASTSECOND);
+ else if(other.health < 50)
+ Send_Notification(NOTIF_ONE, other, MSG_ANNCE, ANNCE_INSTAGIB_NARROWLY);
+ }
+
+ if(other.health < 100)
+ other.health = 100;
+
+ return MUT_ITEMTOUCH_CONTINUE;
+ }
+
+ if(self.max_health)
+ {
+ other.armorvalue = bound(other.armorvalue, 999, other.armorvalue + autocvar_g_instagib_extralives);
+ Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_EXTRALIVES);
+ return MUT_ITEMTOUCH_PICKUP;
+ }
+
+ return MUT_ITEMTOUCH_CONTINUE;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, OnEntityPreSpawn)
+{SELFPARAM();
+ if (!autocvar_g_powerups) { return false; }
+ // Can't use .itemdef here
+ if (!(self.classname == "item_strength" || self.classname == "item_invincible" || self.classname == "item_health_mega"))
+ return false;
+
+ entity e = spawn();
+
+ float r = random();
+ if (r < 0.3)
+ e.think = instagib_invisibility;
+ else if (r < 0.6)
+ e.think = instagib_extralife;
+ else
+ e.think = instagib_speed;
+
+ e.nextthink = time + 0.1;
+ e.spawnflags = self.spawnflags;
+ e.noalign = self.noalign;
+ setorigin(e, self.origin);
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsString)
+{
+ ret_string = strcat(ret_string, ":instagib");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, BuildMutatorsPrettyString)
+{
+ ret_string = strcat(ret_string, ", instagib");
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(mutator_instagib, SetModname)
+{
+ modname = "instagib";
+ return true;
+}
+
+#endif
+#endif
--- /dev/null
+#include "../../../items/all.qh"
+#include "../../../items/item/ammo.qh"
+#include "../../../items/item/powerup.qh"
+
+float instagib_respawntime_ammo = 45;
+float instagib_respawntimejitter_ammo = 0;
+GETTER(float, instagib_respawntime_ammo)
+GETTER(float, instagib_respawntimejitter_ammo)
+
+#ifndef MENUQC
+MODEL(VaporizerCells_ITEM, Item_Model("a_cells.md3"));
+#endif
+
+REGISTER_ITEM(VaporizerCells, Ammo) {
+#ifndef MENUQC
+ this.m_model = MDL_VaporizerCells_ITEM;
+#endif
+ this.m_sound = "misc/itempickup.wav";
+ this.m_name = "Vaporizer Ammo";
+ this.m_icon = "ammo_supercells";
+#ifdef SVQC
+ this.m_botvalue = 100;
+ this.m_itemid = IT_CELLS;
+ this.m_respawntime = GET(instagib_respawntime_ammo);
+ this.m_respawntimejitter = GET(instagib_respawntimejitter_ammo);
+#endif
+}
+
+#ifndef MENUQC
+MODEL(ExtraLife_ITEM, Item_Model("g_h100.md3"));
+#endif
+
+REGISTER_ITEM(ExtraLife, Powerup) {
+#ifndef MENUQC
+ this.m_model = MDL_ExtraLife_ITEM;
+#endif
+ this.m_sound = "misc/megahealth.wav";
+ this.m_name = "Extra life";
+ this.m_icon = "item_mega_health";
+ this.m_color = '1 0 0';
+ this.m_waypoint = _("Extra life");
+ this.m_waypointblink = 2;
+ this.m_itemid = IT_NAILS;
+}
+
+#ifndef MENUQC
+MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
+#endif
+
+REGISTER_ITEM(Invisibility, Powerup) {
+#ifndef MENUQC
+ this.m_model = MDL_Invisibility_ITEM;
+#endif
+ this.m_sound = "misc/powerup.wav";
+ this.m_name = "Invisibility";
+ this.m_icon = "strength";
+ this.m_color = '0 0 1';
+ this.m_waypoint = _("Invisibility");
+ this.m_waypointblink = 2;
+ this.m_itemid = IT_STRENGTH;
+}
+
+#ifndef MENUQC
+MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
+#endif
+
+REGISTER_ITEM(Speed, Powerup) {
+#ifndef MENUQC
+ this.m_model = MDL_Speed_ITEM;
+#endif
+ this.m_sound = "misc/powerup_shield.wav";
+ this.m_name = "Speed";
+ this.m_icon = "shield";
+ this.m_color = '1 0 1';
+ this.m_waypoint = _("Speed");
+ this.m_waypointblink = 2;
+ this.m_itemid = IT_INVINCIBLE;
+}
+#ifdef IMPLEMENTATION
REGISTER_MUTATOR(itemstime, true);
#ifdef SVQC
}
#endif
+#endif
#include "waypointsprites.qh"
+#ifdef IMPLEMENTATION
+
REGISTER_MUTATOR(waypointsprites, true);
#ifdef SVQC
WaypointSprite_DetachCarrier(self);
}
#endif
+#endif
#if defined(CSQC)
- #include "../../dpdefs/csprogsdefs.qh"
#include "../../client/defs.qh"
#include "all.qh"
#include "../buffs/all.qh"
#include "../movetypes/movetypes.qh"
#include "../../client/main.qh"
- #include "../../csqcmodellib/cl_model.qh"
+ #include "../../lib/csqcmodel/cl_model.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
#include "../constants.qh"
#include "../../server/constants.qh"
#include "../turrets/sv_turrets.qh"
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
#include "constants.qh"
#include "teams.qh"
#include "../server/autocvars.qh"
#ifndef NOTIFICATIONS_H
#define NOTIFICATIONS_H
+#include "command/all.qh"
+
#include "constants.qh"
#include "teams.qh"
#include "util.qh"
void Dump_Notifications(float fh, float alsoprint);
+
+GENERIC_COMMAND(dumpnotifs, "Dump all notifications into notifications_dump.txt")
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ #ifndef MENUQC
+ float fh, alsoprint = false;
+ string filename = argv(1);
+
+ if(filename == "")
+ {
+ filename = "notifications_dump.cfg";
+ alsoprint = false;
+ }
+ else if(filename == "-")
+ {
+ filename = "notifications_dump.cfg";
+ alsoprint = true;
+ }
+ fh = fopen(filename, FILE_WRITE);
+
+ if(fh >= 0)
+ {
+ Dump_Notifications(fh, alsoprint);
+ LOG_INFOF("Dumping notifications... File located in ^2data/data/%s^7.\n", filename);
+ fclose(fh);
+ }
+ else
+ {
+ LOG_INFOF("^1Error: ^7Could not open file '%s'!\n", filename);
+ }
+ #else
+ LOG_INFO(_("Notification dump command only works with cl_cmd and sv_cmd.\n"));
+ #endif
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpnotifs [filename]"));
+ LOG_INFO(" Where 'filename' is the file to write (default is notifications_dump.cfg),\n");
+ LOG_INFO(" if supplied with '-' output to console as well as default,\n");
+ LOG_INFO(" if left blank, it will only write to default.\n");
+ return;
+ }
+ }
+}
+
#ifdef NOTIFICATIONS_DEBUG
void Debug_Notification(string input);
#endif
#include "physics.qh"
-#include "triggers/trigger/swamp.qh"
-#include "triggers/trigger/jumppads.qh"
+#include "triggers/include.qh"
#include "viewloc.qh"
#ifdef SVQC
// client side physics
bool Physics_Valid(string thecvar)
{
- if(!autocvar_g_physics_clientselect) { return false; }
-
- string l = strcat(" ", autocvar_g_physics_clientselect_options, " ");
-
- if(strstrofs(l, strcat(" ", thecvar, " "), 0) >= 0)
- return true;
-
- return false;
+ return autocvar_g_physics_clientselect && strhasword(autocvar_g_physics_clientselect_options, thecvar);
}
float Physics_ClientOption(entity pl, string option)
addstat(STAT_JETPACK_MAXSPEED_SIDE, AS_FLOAT, stat_jetpack_maxspeed_side);
// hack to fix track_canjump
- addstat(STAT_MOVEVARS_TRACK_CANJUMP, AS_INT, cvar_cl_movement_track_canjump);
+ addstat(STAT_MOVEVARS_CL_TRACK_CANJUMP, AS_INT, cvar_cl_movement_track_canjump);
+ addstat(STAT_MOVEVARS_TRACK_CANJUMP, AS_INT, stat_sv_track_canjump);
// double jump
addstat(STAT_DOUBLEJUMP, AS_INT, stat_doublejump);
self.stat_sv_airstopaccelerate = Physics_ClientOption(self, "airstopaccelerate");
self.stat_sv_jumpvelocity = Physics_ClientOption(self, "jumpvelocity");
+ self.stat_sv_track_canjump = Physics_ClientOption(self, "track_canjump");
+
self.stat_gameplayfix_upvelocityclearsonground = UPWARD_VELOCITY_CLEARS_ONGROUND;
}
#endif
if (!IS_ONGROUND(self))
return IS_JUMP_HELD(self);
- if (PHYS_TRACK_CANJUMP(self))
+ bool track_jump = PHYS_CL_TRACK_CANJUMP(self);
+ if(PHYS_TRACK_CANJUMP(self))
+ track_jump = true;
+
+ if (track_jump)
if (IS_JUMP_HELD(self))
return true;
#define PHYS_JUMPSPEEDCAP_MAX cvar_string("cl_jumpspeedcap_max")
#define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS getstati(STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS)
+ #define PHYS_CL_TRACK_CANJUMP(s) getstati(STAT_MOVEVARS_CL_TRACK_CANJUMP)
#define PHYS_TRACK_CANJUMP(s) getstati(STAT_MOVEVARS_TRACK_CANJUMP)
#define PHYS_ACCELERATE getstatf(STAT_MOVEVARS_ACCELERATE)
#define PHYS_AIRACCEL_QW(s) getstatf(STAT_MOVEVARS_AIRACCEL_QW)
.float stat_nostep;
.float stat_jumpstep;
+ .bool stat_sv_track_canjump;
+
#define PHYS_INPUT_ANGLES(s) s.v_angle
#define PHYS_WORLD_ANGLES(s) s.angles
#define PHYS_JUMPSPEEDCAP_MAX autocvar_sv_jumpspeedcap_max
#define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS autocvar_sv_jumpspeedcap_max_disable_on_ramps
- #define PHYS_TRACK_CANJUMP(s) s.cvar_cl_movement_track_canjump
+ #define PHYS_CL_TRACK_CANJUMP(s) s.cvar_cl_movement_track_canjump
+ #define PHYS_TRACK_CANJUMP(s) s.stat_sv_track_canjump
#define PHYS_ACCELERATE self.stat_sv_accelerate
#define PHYS_AIRACCEL_QW(s) s.stat_sv_airaccel_qw
#define PHYS_AIRACCEL_QW_STRETCHFACTOR(s) self.stat_sv_airaccel_qw_stretchfactor
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
#include "constants.qh"
#include "util.qh"
#include "weapons/all.qh"
// Global list of sounds
// TODO: remove uses of _sound
+#include "../teams.qh"
string W_Sound(string w_snd);
SOUND(ARC_FIRE, W_Sound("arc_fire"));
#ifndef SOUNDS_ALL_H
#define SOUNDS_ALL_H
-#include "../teams.qh"
+#include "sound.qh"
-// Play all sounds via sound7, for access to the extra channels.
-// Otherwise, channels 8 to 15 would be blocked for a weird QW feature.
-#ifdef SVQC
- #define _sound(e, c, s, v, a) do { \
- entity __e = e; \
- if (!sound_allowed(MSG_BROADCAST, __e)) break; \
- sound7(__e, c, s, v, a, 0, 0); \
- } while (0)
-#else
- #define _sound(e, c, s, v, a) sound7(e, c, s, v, a, 0, 0)
-#endif
-#define sound(e, c, s, v, a) _sound(e, c, s.sound_str(), v, a)
-// Used in places where a string is required
-#define SND(id) (SND_##id.sound_str())
-
-REGISTRY(Sounds, BIT(8))
+REGISTRY(Sounds, BITS(8))
REGISTER_REGISTRY(RegisterSounds)
-CLASS(Sound, Object)
- ATTRIB(Sound, m_id, int, 0)
- ATTRIB(Sound, sound_str, string(), func_null)
- CONSTRUCTOR(Sound, string() path)
- {
- CONSTRUCT(Sound);
- this.sound_str = path;
- }
- METHOD(Sound, sound_precache, void(entity this)) {
- string s = this.sound_str();
- if (s && s != "" && !fexists(strcat("sound/", s))) {
- LOG_WARNINGF("Missing sound: \"%s\"\n", s);
- return;
- }
- LOG_TRACEF("precache_sound(\"%s\")\n", s);
- precache_sound(s);
- }
-ENDCLASS(Sound)
-
#define SOUND(name, path) \
string SND_##name##_get() { return path; } \
REGISTER(RegisterSounds, SND, Sounds, name, m_id, NEW(Sound, SND_##name##_get))
+// Used in places where a string is required
+#define SND(id) (SND_##id.sound_str())
+
STATIC_INIT(RegisterSounds_precache) {
FOREACH(Sounds, true, LAMBDA({
it.sound_precache(it);
--- /dev/null
+#ifndef SOUND_H
+#define SOUND_H
+
+// Play all sounds via sound7, for access to the extra channels.
+// Otherwise, channels 8 to 15 would be blocked for a weird QW feature.
+#ifdef SVQC
+ #define _sound(e, c, s, v, a) do { \
+ entity __e = e; \
+ if (!sound_allowed(MSG_BROADCAST, __e)) break; \
+ sound7(__e, c, s, v, a, 0, 0); \
+ } while (0)
+#else
+ #define _sound(e, c, s, v, a) sound7(e, c, s, v, a, 0, 0)
+#endif
+#define sound(e, c, s, v, a) _sound(e, c, s.sound_str(), v, a)
+
+CLASS(Sound, Object)
+ ATTRIB(Sound, m_id, int, 0)
+ ATTRIB(Sound, sound_str, string(), func_null)
+ CONSTRUCTOR(Sound, string() path)
+ {
+ CONSTRUCT(Sound);
+ this.sound_str = path;
+ }
+ METHOD(Sound, sound_precache, void(entity this)) {
+ string s = this.sound_str();
+ if (s && s != "" && !fexists(strcat("sound/", s))) {
+ LOG_WARNINGF("Missing sound: \"%s\"\n", s);
+ return;
+ }
+ LOG_TRACEF("precache_sound(\"%s\")\n", s);
+ precache_sound(s);
+ }
+ENDCLASS(Sound)
+
+#endif
const int STAT_MOVEVARS_FRICTION_SLICK = 191;
const int STAT_MOVEVARS_FRICTION_ONLAND = 192;
const int STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS = 193;
-// 194 empty?
+const int STAT_MOVEVARS_TRACK_CANJUMP = 194;
// 195 empty?
const int STAT_DOUBLEJUMP = 196;
-const int STAT_MOVEVARS_TRACK_CANJUMP = 197;
+const int STAT_MOVEVARS_CL_TRACK_CANJUMP = 197;
const int STAT_MULTIJUMP_ADD = 198;
const int STAT_MULTIJUMP_SPEED = 199;
const int STAT_MULTIJUMP = 200;
#ifdef SVQC
-#include "../../../server/_all.qh"
-
#include "../../../server/g_subs.qh"
#include "../../../server/g_damage.qh"
#include "../../../server/bot/bot.qh"
#include "../../../common/csqcmodel_settings.qh"
-#include "../../../csqcmodellib/sv_model.qh"
+#include "../../../lib/csqcmodel/sv_model.qh"
#include "../../../server/weapons/common.qh"
.entity sprite;
#if defined(CSQC)
- #include "../../../client/_all.qh"
#include "../../buffs/all.qh"
- #include "../../../csqcmodellib/interpolate.qh"
+ #include "../../../lib/csqcmodel/interpolate.qh"
#include "../../../client/main.qh"
- #include "../../../csqcmodellib/cl_model.qh"
+ #include "../../../lib/csqcmodel/cl_model.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
#endif
#define SUB_LTIME move_ltime
#define SUB_FLAGS move_flags
+.vector move_origin;
+
void SUB_SETORIGIN(entity s, vector v)
{SELFPARAM();
s.move_origin = v;
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../../server/_all.qh"
#include "../../constants.qh"
#include "../../../server/constants.qh"
#include "../../../server/defs.qh"
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../../server/_all.qh"
#include "../../util.qh"
#include "../../../server/defs.qh"
#endif
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../server/_all.qh"
- #include "../../warpzonelib/common.qh"
- #include "../../warpzonelib/util_server.qh"
- #include "../../warpzonelib/server.qh"
+ #include "../../lib/warpzone/common.qh"
+ #include "../../lib/warpzone/util_server.qh"
+ #include "../../lib/warpzone/server.qh"
#include "../constants.qh"
#include "../triggers/subs.qh"
#include "../util.qh"
// TODO: split target_push and put it in the target folder
#ifdef SVQC
-#include "../../../server/_all.qh"
#include "jumppads.qh"
#include "../../movetypes/movetypes.qh"
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../../server/_all.qh"
#include "../../util.qh"
#include "../../../server/defs.qh"
#include "secret.qh"
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../../server/_all.qh"
- #include "../../../warpzonelib/util_server.qh"
+ #include "../../../lib/warpzone/util_server.qh"
#include "../../weapons/all.qh"
#include "../../../server/defs.qh"
#include "../../deathtypes/all.qh"
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../../dpdefs/progsdefs.qh"
- #include "../../../warpzonelib/util_server.qh"
+ #include "../../../lib/warpzone/util_server.qh"
#include "../../../server/defs.qh"
#endif
#ifndef TURRETS_ALL_H
#define TURRETS_ALL_H
+#include "../command/all.qh"
+#include "config.qh"
+
#include "turret.qh"
REGISTRY(Turrets, BIT(5))
REGISTER_REGISTRY(RegisterTurrets)
+
+
+GENERIC_COMMAND(dumpturrets, "Dump all turrets into turrets_dump.txt")
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ #ifdef SVQC
+ tur_config_file = -1;
+ tur_config_alsoprint = -1;
+ string filename = argv(1);
+
+ if(filename == "")
+ {
+ filename = "turrets_dump.cfg";
+ tur_config_alsoprint = FALSE;
+ }
+ else if(filename == "-")
+ {
+ filename = "turrets_dump.cfg";
+ tur_config_alsoprint = TRUE;
+ }
+ tur_config_file = fopen(filename, FILE_WRITE);
+
+ if(tur_config_file >= 0)
+ {
+ Dump_Turret_Settings();
+ LOG_INFO(sprintf("Dumping turrets... File located in ^2data/data/%s^7.\n", filename));
+ fclose(tur_config_file);
+ tur_config_file = -1;
+ tur_config_alsoprint = -1;
+ }
+ else
+ {
+ LOG_INFO(sprintf("^1Error: ^7Could not open file '%s'!\n", filename));
+ }
+ #else
+ LOG_INFO(_("Turrets dump command only works with sv_cmd.\n"));
+ #endif
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpturrets [filename]"));
+ LOG_INFO(" Where 'filename' is the file to write (default is turrets_dump.cfg),\n");
+ LOG_INFO(" if supplied with '-' output to console as well as default,\n");
+ LOG_INFO(" if left blank, it will only write to default.\n");
+ return;
+ }
+ }
+}
+
+
const int TUR_FIRST = 1;
#define TUR_LAST (Turrets_COUNT - 1)
+++ /dev/null
-#ifndef UTIL_POST_H
-#define UTIL_POST_H
-
-[[alias("self")]] entity __self;
-
-// Can't wrap with do-while as block may contain continue or break
-#define WITH(type, name, value, block) { \
- type __with_save = (name); \
- name = (value); \
- LAMBDA(block) \
- name = __with_save; \
-} do { } while (0)
-
-// Transition from global 'self' to local 'this'
-
-// Step 1: auto oldself
-#if 1
-#define SELFPARAM() noref entity this = __self
-#define setself(s) (__self = s)
-#define self __self
-#endif
-
-// Step 2: check SELFPARAM() is present for functions that use self
-#if 0
-#define SELFPARAM() [[alias("__self")]] noref entity this = __self
-#define setself(s) (__self = s)
-#define self this
-#endif
-
-// Step 3: const self
-#if 0
-#define SELFPARAM() noref const entity this = __self
-entity setself(entity e) { return self = e; }
-entity getself() { return self; }
-#define self getself()
-#endif
-
-// Step 4: enable when possible
-// TODO: Remove SELFPARAM in favor of a parameter
-#if 0
-#define SELFPARAM() noref const entity this = __self
-#define self this
-#endif
-
-#define spawn() new(entity)
-
-#endif
+++ /dev/null
-#ifndef UTIL_PRE_H
-#define UTIL_PRE_H
-
-#ifndef NOCOMPAT
- #define COMPAT_NO_MOD_IS_XONOTIC
-#endif
-
-#ifndef QCC_SUPPORT_ACCUMULATE
- #ifdef GMQCC
- #define QCC_SUPPORT_ACCUMULATE
- #endif
-#endif
-
-#ifndef QCC_SUPPORT_NIL
- #ifdef GMQCC
- #define QCC_SUPPORT_NIL 1
- #endif
-#endif
-
-#ifndef QCC_SUPPORT_INT
- #define int float
-
- #define stoi(s) stof(s)
- #define stob(s) stof(s)
- #define itos(i) ftos(i)
-#else
- #define stoi(s) ((int) stof(s))
- #define stob(s) ((bool) stof(s))
- #define itos(i) ftos(i)
-#endif
-
-#define FOREACH_ARRAY(arr, start, end, cond, body) do { \
- for (int i = start; i < end; ++i) { \
- const noref entity it = arr[i]; \
- if (cond) { body } \
- } \
-} while(0)
-
-#define FOREACH_LIST(list, next, cond, body) do { \
- noref int i = 0; \
- for (entity it = list##_first; it; (it = it.next, ++i)) { \
- if (cond) { body } \
- } \
-} while(0)
-
-#define FOREACH(list, cond, body) FOREACH_LIST(list, enemy, cond, body)
-
-#ifdef GMQCC
- #define EVAL(...) __VA_ARGS__
-
- #define OVERLOAD_(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
- #define OVERLOAD(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
-#else
- #define EMPTY()
- #define DEFER(id) id EMPTY()
-
- #define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
- #define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
- #define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
- #define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
- #define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
- #define EVAL5(...) __VA_ARGS__
-
- #define OVERLOAD___(F,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,n,...) F##_##n
- #define OVERLOAD__(F, ...) OVERLOAD___(F,##__VA_ARGS__,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
- #define OVERLOAD_(...) DEFER(OVERLOAD__(__VA_ARGS__))
- #define OVERLOAD(F, ...) OVERLOAD_(F,##__VA_ARGS__)(__VA_ARGS__)
-#endif
-
-#define LAMBDA(...) { __VA_ARGS__ ; }
-
-#define MAP(f, ...) EVAL(OVERLOAD(MAP, f, __VA_ARGS__))
-#define MAP_2(f, it) f(it)
-#define MAP_3(f, it, ...) f(it)MAP_2(f, __VA_ARGS__)
-#define MAP_4(f, it, ...) f(it)MAP_3(f, __VA_ARGS__)
-#define MAP_5(f, it, ...) f(it)MAP_4(f, __VA_ARGS__)
-#define MAP_6(f, it, ...) f(it)MAP_5(f, __VA_ARGS__)
-#define MAP_7(f, it, ...) f(it)MAP_6(f, __VA_ARGS__)
-#define MAP_8(f, it, ...) f(it)MAP_7(f, __VA_ARGS__)
-#define MAP_9(f, it, ...) f(it)MAP_8(f, __VA_ARGS__)
-#define MAP_10(f, it, ...) f(it)MAP_9(f, __VA_ARGS__)
-#define MAP_11(f, it, ...) f(it)MAP_10(f, __VA_ARGS__)
-#define MAP_12(f, it, ...) f(it)MAP_11(f, __VA_ARGS__)
-#define MAP_13(f, it, ...) f(it)MAP_12(f, __VA_ARGS__)
-#define MAP_14(f, it, ...) f(it)MAP_13(f, __VA_ARGS__)
-#define MAP_15(f, it, ...) f(it)MAP_14(f, __VA_ARGS__)
-#define MAP_16(f, it, ...) f(it)MAP_15(f, __VA_ARGS__)
-#define MAP_17(f, it, ...) f(it)MAP_16(f, __VA_ARGS__)
-#define MAP_18(f, it, ...) f(it)MAP_17(f, __VA_ARGS__)
-#define MAP_19(f, it, ...) f(it)MAP_18(f, __VA_ARGS__)
-#define MAP_20(f, it, ...) f(it)MAP_19(f, __VA_ARGS__)
-
-#define IDENTITY(it) it
-
-#define UNWORDS(...) MAP(IDENTITY, __VA_ARGS__)
-
-#define APPLY(f, ...) f(__VA_ARGS__)
-
-#ifdef SVQC
- #define SV(f, ...) f(__VA_ARGS__)
-#else
- #define SV(f, ...)
-#endif
-
-#ifdef CSQC
- #define CL(f, ...) f(__VA_ARGS__)
-#else
- #define CL(f, ...)
-#endif
-
-#define IF(cond, f, ...) cond(f, __VA_ARGS__)
-
-#define GET(name) name##get
-#define GETTER(type, name) type GET(name)() { return name; }
-
-#endif
#include "util.qh"
#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
#include "../client/defs.qh"
#include "constants.qh"
#include "../client/mutators/events.qh"
#include "deathtypes/all.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
#include "constants.qh"
#include "../server/autocvars.qh"
#include "../server/defs.qh"
return sprintf("%.*f", decimals, number);
}
-vector colormapPaletteColor(float c, bool isPants)
-{
- switch (c)
- {
- case 0: return '1.000000 1.000000 1.000000';
- case 1: return '1.000000 0.333333 0.000000';
- case 2: return '0.000000 1.000000 0.501961';
- case 3: return '0.000000 1.000000 0.000000';
- case 4: return '1.000000 0.000000 0.000000';
- case 5: return '0.000000 0.666667 1.000000';
- case 6: return '0.000000 1.000000 1.000000';
- case 7: return '0.501961 1.000000 0.000000';
- case 8: return '0.501961 0.000000 1.000000';
- case 9: return '1.000000 0.000000 1.000000';
- case 10: return '1.000000 0.000000 0.501961';
- case 11: return '0.000000 0.000000 1.000000';
- case 12: return '1.000000 1.000000 0.000000';
- case 13: return '0.000000 0.333333 1.000000';
- case 14: return '1.000000 0.666667 0.000000';
- case 15:
- if (isPants)
- return
- '1 0 0' * (0.502 + 0.498 * sin(time / 2.7182818285 + 0.0000000000))
- + '0 1 0' * (0.502 + 0.498 * sin(time / 2.7182818285 + 2.0943951024))
- + '0 0 1' * (0.502 + 0.498 * sin(time / 2.7182818285 + 4.1887902048));
- else
- return
- '1 0 0' * (0.502 + 0.498 * sin(time / 3.1415926536 + 5.2359877560))
- + '0 1 0' * (0.502 + 0.498 * sin(time / 3.1415926536 + 3.1415926536))
- + '0 0 1' * (0.502 + 0.498 * sin(time / 3.1415926536 + 1.0471975512));
- default: return '0.000 0.000 0.000';
- }
-}
-
// Databases (hash tables)
const float DB_BUCKETS = 8192;
void db_save(float db, string pFilename)
bool fexists(string f);
-vector colormapPaletteColor(float c, float isPants);
-
// unzone the string, and return it as tempstring. Safe to be called on string_null
string fstrunzone(string s);
#include "sv_vehicles.qh"
-#include "../effects/effects.qh"
#if 0
bool vehicle_send(entity to, int sf)
#include "racer_weapon.qc"
#ifdef SVQC
-#include "../../effects/effects.qh"
#include "../../triggers/trigger/impulse.qh"
bool autocvar_g_vehicle_racer;
vehicles_projectile(EFFECT_RAPTOR_MUZZLEFLASH.eent_eff_name, SND(LASERGUN_FIRE),
org, normalize(dir + randomvec() * autocvar_g_vehicle_raptor_cannon_spread) * autocvar_g_vehicle_raptor_cannon_speed,
autocvar_g_vehicle_raptor_cannon_damage, autocvar_g_vehicle_raptor_cannon_radius, autocvar_g_vehicle_raptor_cannon_force, 0,
- DEATH_VH_RAPT_CANNON.m_id, PROJECTILE_RAPTORCANNON, 0, true, true, veh ? veh : player);
+ DEATH_VH_RAPT_CANNON.m_id, PROJECTILE_RAPTORCANNON, 0, true, true, player);
weapon_thinkf(player, WFRAME_FIRE1, 0, w_ready);
}
}
#include "util.qh"
#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
#include "../client/defs.qh"
#include "constants.qh"
#elif defined(MENUQC)
#include "weapon/arc.qc"
#include "weapon/hmg.qc"
#include "weapon/rpc.qc"
-
-#include "../../server/mutators/gamemode_nexball_weapon.qc"
#include "all.qh"
#if defined(CSQC)
- #include "../../dpdefs/csprogsdefs.qh"
#include "../../client/defs.qh"
#include "../constants.qh"
#include "../stats.qh"
- #include "../../warpzonelib/anglestransform.qh"
- #include "../../warpzonelib/common.qh"
- #include "../../warpzonelib/client.qh"
+ #include "../../lib/warpzone/anglestransform.qh"
+ #include "../../lib/warpzone/common.qh"
+ #include "../../lib/warpzone/client.qh"
#include "../util.qh"
#include "../buffs/all.qh"
#include "../../client/autocvars.qh"
#include "../deathtypes/all.qh"
- #include "../../csqcmodellib/interpolate.qh"
+ #include "../../lib/csqcmodel/interpolate.qh"
#include "../movetypes/movetypes.qh"
#include "../../client/main.qh"
- #include "../../csqcmodellib/cl_model.qh"
+ #include "../../lib/csqcmodel/cl_model.qh"
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../warpzonelib/anglestransform.qh"
- #include "../../warpzonelib/common.qh"
- #include "../../warpzonelib/util_server.qh"
- #include "../../warpzonelib/server.qh"
+ #include "../../lib/warpzone/anglestransform.qh"
+ #include "../../lib/warpzone/common.qh"
+ #include "../../lib/warpzone/util_server.qh"
+ #include "../../lib/warpzone/server.qh"
#include "../constants.qh"
#include "../stats.qh"
#include "../teams.qh"
#include "../../server/mutators/mutators_include.qh"
#include "../mapinfo.qh"
#include "../../server/command/common.qh"
- #include "../../csqcmodellib/sv_model.qh"
+ #include "../../lib/csqcmodel/sv_model.qh"
#include "../../server/portals.qh"
#include "../../server/g_hook.qh"
#endif
#ifndef WEAPONS_ALL_H
#define WEAPONS_ALL_H
+#include "../command/all.qh"
+#include "config.qh"
+
// weapon sets
typedef vector WepSet;
#define WEPSET(id) WepSet_FromWeapon(WEP_##id.m_id)
REGISTER_REGISTRY(RegisterWeapons)
entity get_weaponinfo(int id);
+
+GENERIC_COMMAND(dumpweapons, "Dump all weapons into weapons_dump.txt") // WEAPONTODO: make this work with other progs than just server
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ #ifdef SVQC
+ wep_config_file = -1;
+ wep_config_alsoprint = -1;
+ string filename = argv(1);
+
+ if(filename == "")
+ {
+ filename = "weapons_dump.cfg";
+ wep_config_alsoprint = false;
+ }
+ else if(filename == "-")
+ {
+ filename = "weapons_dump.cfg";
+ wep_config_alsoprint = true;
+ }
+ wep_config_file = fopen(filename, FILE_WRITE);
+
+ if(wep_config_file >= 0)
+ {
+ Dump_Weapon_Settings();
+ LOG_INFO(sprintf("Dumping weapons... File located in ^2data/data/%s^7.\n", filename));
+ fclose(wep_config_file);
+ wep_config_file = -1;
+ wep_config_alsoprint = -1;
+ }
+ else
+ {
+ LOG_INFO(sprintf("^1Error: ^7Could not open file '%s'!\n", filename));
+ }
+ #else
+ LOG_INFO(_("Weapons dump command only works with sv_cmd.\n"));
+ #endif
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ LOG_INFO(strcat("\nUsage:^3 ", GetProgramCommandPrefix(), " dumpweapons [filename]"));
+ LOG_INFO(" Where 'filename' is the file to write (default is weapons_dump.cfg),\n");
+ LOG_INFO(" if supplied with '-' output to console as well as default,\n");
+ LOG_INFO(" if left blank, it will only write to default.\n");
+ return;
+ }
+ }
+}
+
#define REGISTER_WEAPON(id, inst) \
- /* WepSet WEPSET_##id; */ \
- REGISTER(RegisterWeapons, WEP, Weapons, id, m_id, inst)
+ /* WepSet WEPSET_##id; */ \
+ REGISTER(RegisterWeapons, WEP, Weapons, id, m_id, inst)
// create cvars for weapon settings
#define WEP_ADD_CVAR_NONE(wepname,name) [[last]] float autocvar_g_balance_##wepname##_##name;
#define WEP_ADD_CVAR_PRI(wepname,name) WEP_ADD_CVAR_NONE(wepname, primary_##name)
#define WEP_ADD_CVAR_SEC(wepname,name) WEP_ADD_CVAR_NONE(wepname, secondary_##name)
#define WEP_ADD_CVAR_BOTH(wepname,name) \
- WEP_ADD_CVAR_PRI(wepname, name) \
- WEP_ADD_CVAR_SEC(wepname, name)
+ WEP_ADD_CVAR_PRI(wepname, name) \
+ WEP_ADD_CVAR_SEC(wepname, name)
#define WEP_ADD_CVAR(wepid,wepname,mode,name) WEP_ADD_CVAR_##mode(wepname, name)
// create properties for weapon settings
#define WEP_ADD_PROP(wepid,wepname,type,prop,name) \
- .type prop; \
- [[last]] type autocvar_g_balance_##wepname##_##name;
+ .type prop; \
+ [[last]] type autocvar_g_balance_##wepname##_##name;
// read cvars from weapon settings
#define WEP_CVAR(wepname,name) autocvar_g_balance_##wepname##_##name
entity get_weaponinfo(int id)
{
- if (id >= WEP_FIRST && id <= WEP_LAST) {
- Weapon w = Weapons[id];
- if (w) return w;
- }
- return WEP_Null;
+ if (id >= WEP_FIRST && id <= WEP_LAST) {
+ Weapon w = Weapons[id];
+ if (w) return w;
+ }
+ return WEP_Null;
}
// TODO: remove after 0.8.2. Retains impulse number compatibility because 0.8.1 clients don't reload the weapons.cfg
STATIC_INIT(register_weapons_done)
{
- for (int i = 0; i < Weapons_COUNT; ++i) {
- Weapon it = Weapons[i];
- it.m_id = i;
- WepSet set = WepSet_FromWeapon(it.m_id);
- WEPSET_ALL |= set;
- if ((it.spawnflags) & WEP_FLAG_SUPERWEAPON) WEPSET_SUPERWEAPONS |= set;
- it.weapon = it.m_id;
- it.weapons = set;
- #ifdef CSQC
- it.wr_init(it);
- #endif
- int imp = WEP_IMPULSE_BEGIN + it.m_id - 1;
- if (imp <= WEP_IMPULSE_END)
- localcmd(sprintf("alias weapon_%s \"impulse %d\"\n", it.netname, imp));
- else
- LOG_TRACEF(_("Impulse limit exceeded, weapon will not be directly accessible: %s\n"), it.netname);
- }
- weaponorder_byid = "";
- for (int i = Weapons_MAX - 1; i >= 1; --i)
- if (Weapons[i])
- weaponorder_byid = strcat(weaponorder_byid, " ", ftos(i));
- weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1));
+ FOREACH(Weapons, true, LAMBDA(
+ it.m_id = i;
+ WepSet set = WepSet_FromWeapon(it.m_id);
+ WEPSET_ALL |= set;
+ if ((it.spawnflags) & WEP_FLAG_SUPERWEAPON) WEPSET_SUPERWEAPONS |= set;
+ it.weapon = it.m_id;
+ it.weapons = set;
+ int imp = WEP_IMPULSE_BEGIN + it.m_id - 1;
+ if (imp <= WEP_IMPULSE_END)
+ localcmd(sprintf("alias weapon_%s \"impulse %d\"\n", it.netname, imp));
+ else
+ LOG_TRACEF(_("Impulse limit exceeded, weapon will not be directly accessible: %s\n"), it.netname);
+ ));
+ #ifdef CSQC
+ FOREACH(Weapons, true, LAMBDA(it.wr_init(it)));
+ #endif
+ weaponorder_byid = "";
+ for (int i = Weapons_MAX - 1; i >= 1; --i)
+ if (Weapons[i])
+ weaponorder_byid = strcat(weaponorder_byid, " ", ftos(i));
+ weaponorder_byid = strzone(substring(weaponorder_byid, 1, strlen(weaponorder_byid) - 1));
}
#endif
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
#include "../util.qh"
#include "config.qh"
#include "all.qh"
#ifndef WEAPONS_CONFIG_H
#define WEAPONS_CONFIG_H
+#ifdef SVQC
// ==========================
// Balance Config Generator
// ==========================
#define WEP_CONFIG_WRITE_PROPS(wepid,wepname,type,prop,name) WEP_CONFIG_WRITE_PROPS_##type(wepname,name)
#endif
+#endif
+++ /dev/null
-/*
- * Copyright (c) 2011 Rudolf PolzerCSQCModel_InterpolateAnimation_2To4_PreNote
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "../client/defs.qh"
- #include "../common/util.qh"
- #include "../common/animdecide.qh"
- #include "interpolate.qh"
- #include "../common/csqcmodel_settings.qh"
- #include "common.qh"
- #include "cl_model.qh"
- #include "cl_player.qh"
- #elif defined(MENUQC)
- #elif defined(SVQC)
- #endif
-
-float autocvar_cl_lerpanim_maxdelta_framegroups = 0.1;
-float autocvar_cl_nolerp = 0;
-
-.float csqcmodel_lerpfrac;
-.float csqcmodel_lerpfrac2;
-.float csqcmodel_lerpfractime;
-.float csqcmodel_lerpfrac2time;
-
-void CSQCModel_InterpolateAnimation_2To4_PreNote(int sf)
-{SELFPARAM();
- if(sf & CSQCMODEL_PROPERTY_FRAME)
- {
- self.frame3 = self.frame;
- self.frame3time = self.frame1time;
- }
- if(sf & CSQCMODEL_PROPERTY_FRAME2)
- {
- self.frame4 = self.frame2;
- self.frame4time = self.frame2time;
- }
- if(sf & CSQCMODEL_PROPERTY_LERPFRAC)
- {
- self.csqcmodel_lerpfrac2 = self.csqcmodel_lerpfrac;
- self.csqcmodel_lerpfrac2time = self.csqcmodel_lerpfractime;
- self.lerpfrac = self.csqcmodel_lerpfrac;
- }
-}
-void CSQCModel_InterpolateAnimation_1To2_PreNote(int sf)
-{SELFPARAM();
- if(sf & CSQCMODEL_PROPERTY_FRAME)
- {
- self.frame2 = self.frame;
- self.frame2time = self.frame1time;
- }
-}
-void CSQCModel_InterpolateAnimation_PreNote(int sf)
-{
-#ifdef CSQCMODEL_HAVE_TWO_FRAMES
- CSQCModel_InterpolateAnimation_2To4_PreNote(sf);
-#else
- CSQCModel_InterpolateAnimation_1To2_PreNote(sf);
-#endif
-}
-
-void CSQCModel_InterpolateAnimation_2To4_Note(int sf, float set_times)
-{SELFPARAM();
- if(sf & CSQCMODEL_PROPERTY_FRAME)
- {
- if(set_times)
- self.frame1time = time;
- }
- if(sf & CSQCMODEL_PROPERTY_FRAME2)
- {
- if(set_times)
- self.frame2time = time;
- }
- if(sf & CSQCMODEL_PROPERTY_LERPFRAC)
- {
- self.csqcmodel_lerpfrac = self.lerpfrac;
- if(set_times)
- self.csqcmodel_lerpfractime = time;
- }
-}
-void CSQCModel_InterpolateAnimation_1To2_Note(int sf, float set_times)
-{SELFPARAM();
- if(sf & CSQCMODEL_PROPERTY_FRAME)
- {
- if(set_times)
- self.frame1time = time;
- }
-}
-void CSQCModel_InterpolateAnimation_Note(int sf)
-{
-#ifdef CSQCMODEL_HAVE_TWO_FRAMES
- CSQCModel_InterpolateAnimation_2To4_Note(sf, true);
-#else
- CSQCModel_InterpolateAnimation_1To2_Note(sf, true);
-#endif
-}
-
-void CSQCModel_InterpolateAnimation_2To4_Do()
-{SELFPARAM();
- if(autocvar_cl_nolerp || (autocvar_cl_lerpanim_maxdelta_framegroups == 0))
- {
- self.lerpfrac = self.csqcmodel_lerpfrac;
- self.lerpfrac3 = 0;
- self.lerpfrac4 = 0;
- }
- else
- {
- float l13, l24, llf;
- float l24_13;
-
- if(self.frame3time == 0) // if frame1/3 were not previously displayed, only frame1 can make sense
- l13 = 1;
- else
- l13 = bound(0, (time - self.frame1time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
-
- if(self.frame4time == 0) // if frame2/4 were not previously displayed, only frame2 can make sense
- l24 = 1;
- else
- l24 = bound(0, (time - self.frame2time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
-
- if(self.csqcmodel_lerpfrac2time == 0) // if there is no old lerpfrac (newly displayed model), only lerpfrac makes sense
- llf = 1;
- else
- llf = bound(0, (time - self.csqcmodel_lerpfractime) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
-
- l24_13 = self.csqcmodel_lerpfrac * llf + self.csqcmodel_lerpfrac2 * (1 - llf);
-
- self.lerpfrac = l24 * l24_13;
- self.lerpfrac4 = (1 - l24) * l24_13;
- self.lerpfrac3 = (1 - l13) * (1 - l24_13);
-
- if(l24_13 == 0) // if frames 2/4 are not displayed, clear their frametime
- {
- self.frame2time = 0;
- self.frame4time = 0;
- }
-
- if(l24_13 == 1) // if frames 1/3 are not displayed, clear their frametime
- {
- self.frame1time = 0;
- self.frame3time = 0;
- }
- }
-}
-void CSQCModel_InterpolateAnimation_1To2_Do()
-{SELFPARAM();
- if(autocvar_cl_nolerp || (autocvar_cl_lerpanim_maxdelta_framegroups == 0))
- {
- self.lerpfrac = 0;
- }
- else
- {
- if(self.frame2time == 0) // if frame2 was not previously displayed, only frame1 can make sense
- self.lerpfrac = 0;
- else
- self.lerpfrac = 1 - bound(0, (time - self.frame1time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
- }
-}
-void CSQCModel_InterpolateAnimation_Do()
-{
-#ifdef CSQCMODEL_HAVE_TWO_FRAMES
- CSQCModel_InterpolateAnimation_2To4_Do();
-#else
- CSQCModel_InterpolateAnimation_1To2_Do();
-#endif
-}
-
-void CSQCModel_Draw()
-{SELFPARAM();
- // some nice flags for CSQCMODEL_IF and the hooks
- bool isplayer = (self.entnum >= 1 && self.entnum <= maxclients);
- noref bool islocalplayer = (self.entnum == player_localnum + 1);
- noref bool isnolocalplayer = (isplayer && (self.entnum != player_localnum + 1));
-
- // we don't do this for the local player as that one is already handled
- // by CSQCPlayer_SetCamera()
- if(!CSQCPlayer_IsLocalPlayer())
- InterpolateOrigin_Do();
-
- CSQCModel_InterpolateAnimation_Do();
-
- { CSQCMODEL_HOOK_PREDRAW }
-
- // inherit draw flags easily
- entity root = self;
- while(root.tag_entity)
- root = root.tag_entity;
- if(self != root)
- {
- self.renderflags &= ~(RF_EXTERNALMODEL | RF_VIEWMODEL);
- self.renderflags |= (root.renderflags & (RF_EXTERNALMODEL | RF_VIEWMODEL));
- }
-
- // we're drawn, now teleporting is over
- self.csqcmodel_teleported = 0;
-}
-
-void CSQCModel_Read(bool isnew)
-{SELFPARAM();
- int sf = ReadInt24_t();
-
- // some nice flags for CSQCMODEL_IF and the hooks
- bool isplayer = (self.entnum >= 1 && self.entnum <= maxclients);
- bool islocalplayer = (self.entnum == player_localnum + 1);
- noref bool isnolocalplayer = (isplayer && (self.entnum != player_localnum + 1));
-
- self.classname = "csqcmodel";
- self.iflags |= IFLAG_ORIGIN; // interpolate origin too
- self.iflags |= IFLAG_ANGLES; // interpolate angles too
- self.iflags |= IFLAG_VELOCITY | IFLAG_AUTOVELOCITY; // let's calculate velocity automatically
-
- { CSQCMODEL_HOOK_PREUPDATE }
-
- CSQCPlayer_PreUpdate();
- InterpolateOrigin_Undo();
- CSQCModel_InterpolateAnimation_PreNote(sf);
-
-#define CSQCMODEL_IF(cond) if(cond) {
-#define CSQCMODEL_ENDIF }
-#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
- if(sf & flag) \
- self.f = r();
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
- if(sf & flag) \
- self.f = (r() + mi) / s;
- ALLPROPERTIES
-#undef CSQCMODEL_PROPERTY_SCALED
-#undef CSQCMODEL_PROPERTY
-#undef CSQCMODEL_ENDIF
-#undef CSQCMODEL_IF
-
- if(sf & CSQCMODEL_PROPERTY_MODELINDEX)
- {
- vector pmin = self.mins, pmax = self.maxs;
- setmodelindex(self, self.modelindex); // this retrieves the .model key and sets mins/maxs/absmin/absmax
- setsize(self, pmin, pmax);
- }
-
- if(sf & CSQCMODEL_PROPERTY_TELEPORTED)
- {
- self.iflags |= IFLAG_TELEPORTED;
- self.csqcmodel_teleported = 1;
- }
-
- CSQCModel_InterpolateAnimation_Note(sf);
- InterpolateOrigin_Note();
- CSQCPlayer_PostUpdate();
-
- { CSQCMODEL_HOOK_POSTUPDATE }
-
-#ifdef CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
- InterpolateOrigin_Do();
- CSQCModel_InterpolateAnimation_Do();
-#endif
-
- // relink
- setorigin(self, self.origin);
-
- // set obvious render flags
- if(self.entnum == player_localentnum)
- self.renderflags |= RF_EXTERNALMODEL;
- else
- self.renderflags &= ~RF_EXTERNALMODEL;
-
- // draw it
- self.drawmask = MASK_NORMAL;
- self.predraw = CSQCModel_Draw;
-}
-
-entity CSQCModel_server2csqc(float pl)
-{
- return findfloat(world, entnum, pl); // FIXME optimize this using an array
-}
+++ /dev/null
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#ifndef CL_MODEL_H
-#define CL_MODEL_H
-
-#include "common.qh"
-
-void CSQCModel_Read(bool isnew);
-
-#define CSQCMODEL_IF(cond)
-#define CSQCMODEL_ENDIF
-#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
- .t f;
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
- ALLPROPERTIES
-#undef CSQCMODEL_PROPERTY_SCALED
-#undef CSQCMODEL_PROPERTY
-#undef CSQCMODEL_ENDIF
-#undef CSQCMODEL_IF
-
-entity CSQCModel_server2csqc(float pl);
-.float csqcmodel_teleported;
-
-// this is exported for custom frame animation code. Use with care.
-// to update frames, first call this:
-void CSQCModel_InterpolateAnimation_2To4_PreNote(int sf);
-void CSQCModel_InterpolateAnimation_1To2_PreNote(int sf);
-// then update frame, frame1time (and possibly frame2, frame2time, lerpfrac)
-// if set_times is not set, caller is responsible for frame1time, frame2time, csqcmodel_lerpfractime!
-void CSQCModel_InterpolateAnimation_2To4_Note(int sf, float set_times);
-void CSQCModel_InterpolateAnimation_1To2_Note(int sf, float set_times);
-// to retrieve animation state, call this
-void CSQCModel_InterpolateAnimation_2To4_Do();
-void CSQCModel_InterpolateAnimation_1To2_Do();
-// will overwrite lerpfrac, lerpfrac3, lerpfrac4, and possibly clear frame*time if they are undisplayed according to lerpfracs
-#endif
+++ /dev/null
-/*
- * Copyright (c) 2011 Rudolf Polzer
- * Copyright (c) 2015 Micah Talkiewicz
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "../client/defs.qh"
- #include "../common/constants.qh"
- #include "../common/stats.qh"
- #include "../common/util.qh"
- #include "interpolate.qh"
- #include "../client/main.qh"
- #include "common.qh"
- #include "cl_model.qh"
- #include "cl_player.qh"
- #include "../common/triggers/trigger/viewloc.qh"
- #include "../common/viewloc.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
-
-float autocvar_cl_movement_errorcompensation = 0;
-int autocvar_cl_movement = 1;
-
-// engine stuff
-float pmove_onground; // weird engine flag we shouldn't really use but have to for now
-
-vector csqcplayer_origin, csqcplayer_velocity;
-float csqcplayer_sequence;
-int player_pmflags;
-float csqcplayer_moveframe;
-vector csqcplayer_predictionerroro;
-vector csqcplayer_predictionerrorv;
-float csqcplayer_predictionerrortime;
-float csqcplayer_predictionerrorfactor;
-
-vector CSQCPlayer_GetPredictionErrorO()
-{
- if(time >= csqcplayer_predictionerrortime)
- return '0 0 0';
- return csqcplayer_predictionerroro * (csqcplayer_predictionerrortime - time) * csqcplayer_predictionerrorfactor;
-}
-
-vector CSQCPlayer_GetPredictionErrorV()
-{
- if(time >= csqcplayer_predictionerrortime)
- return '0 0 0';
- return csqcplayer_predictionerrorv * (csqcplayer_predictionerrortime - time) * csqcplayer_predictionerrorfactor;
-}
-
-void CSQCPlayer_SetPredictionError(vector o, vector v, float onground_diff)
-{
- // error too big to compensate, we LIKELY hit a teleport or a
- // jumppad, or it's a jump time disagreement that'll get fixed
- // next frame
-
- // FIXME we sometimes have disagreement in order of jump velocity. Do not act on them!
- /*
- // commented out as this one did not help
- if(onground_diff)
- {
- printf("ONGROUND MISMATCH: %d x=%v v=%v\n", onground_diff, o, v);
- return;
- }
- */
- if(vlen(o) > 32 || vlen(v) > 192)
- {
- //printf("TOO BIG: x=%v v=%v\n", o, v);
- return;
- }
-
- if(!autocvar_cl_movement_errorcompensation)
- {
- csqcplayer_predictionerrorfactor = 0;
- return;
- }
-
- csqcplayer_predictionerroro = CSQCPlayer_GetPredictionErrorO() + o;
- csqcplayer_predictionerrorv = CSQCPlayer_GetPredictionErrorV() + v;
- csqcplayer_predictionerrorfactor = autocvar_cl_movement_errorcompensation / ticrate;
- csqcplayer_predictionerrortime = time + 1.0 / csqcplayer_predictionerrorfactor;
-}
-
-void CSQCPlayer_Unpredict()
-{SELFPARAM();
- if(csqcplayer_status == CSQCPLAYERSTATUS_UNPREDICTED)
- return;
- if(csqcplayer_status != CSQCPLAYERSTATUS_PREDICTED)
- error("Cannot unpredict in current status");
- self.origin = csqcplayer_origin;
- self.velocity = csqcplayer_velocity;
- csqcplayer_moveframe = csqcplayer_sequence+1; //+1 because the recieved frame has the move already done (server side)
- self.flags = player_pmflags;
-}
-
-void CSQCPlayer_SetMinsMaxs()
-{SELFPARAM();
- if(self.flags & FL_DUCKED)
- {
- self.mins = PL_CROUCH_MIN;
- self.maxs = PL_CROUCH_MAX;
- self.view_ofs = PL_CROUCH_VIEW_OFS;
- }
- else
- {
- self.mins = PL_MIN;
- self.maxs = PL_MAX;
- self.view_ofs = PL_VIEW_OFS;
- }
-}
-
-void CSQCPlayer_SavePrediction()
-{SELFPARAM();
- player_pmflags = self.flags;
- csqcplayer_origin = self.origin;
- csqcplayer_velocity = self.velocity;
- csqcplayer_sequence = servercommandframe;
- csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
-}
-
-void CSQC_ClientMovement_PlayerMove_Frame();
-
-void PM_Movement_Move()
-{SELFPARAM();
- runstandardplayerphysics(self);
-#ifdef CSQC
- self.flags =
- ((self.pmove_flags & PMF_DUCKED) ? FL_DUCKED : 0) |
- (!(self.pmove_flags & PMF_JUMP_HELD) ? FL_JUMPRELEASED : 0) |
- ((self.pmove_flags & PMF_ONGROUND) ? FL_ONGROUND : 0);
-#endif
-}
-
-void CSQCPlayer_Physics(void)
-{
- switch(autocvar_cl_movement)
- {
- case 1: CSQC_ClientMovement_PlayerMove_Frame(); break;
- case 2: PM_Movement_Move(); break;
- }
-}
-
-void CSQCPlayer_PredictTo(float endframe, float apply_error)
-{SELFPARAM();
- CSQCPlayer_Unpredict();
- if(apply_error)
- {
- self.origin += CSQCPlayer_GetPredictionErrorO();
- self.velocity += CSQCPlayer_GetPredictionErrorV();
- }
- CSQCPlayer_SetMinsMaxs();
-
- csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
-
-#if 0
- // we don't need this
- // darkplaces makes servercommandframe == 0 in these cases anyway
- if (getstatf(STAT_HEALTH) <= 0)
- {
- csqcplayer_moveframe = clientcommandframe;
- getinputstate(csqcplayer_moveframe-1);
- LOG_INFO("the Weird code path got hit\n");
- return;
- }
-#endif
-
- if(csqcplayer_moveframe >= endframe)
- {
- getinputstate(csqcplayer_moveframe - 1);
- }
- else
- {
- do
- {
- if (!getinputstate(csqcplayer_moveframe))
- break;
- CSQCPlayer_Physics();
- CSQCPlayer_SetMinsMaxs();
- csqcplayer_moveframe++;
- }
- while(csqcplayer_moveframe < endframe);
- }
-
- //add in anything that was applied after (for low packet rate protocols)
- input_angles = view_angles;
-}
-
-bool CSQCPlayer_IsLocalPlayer()
-{SELFPARAM();
- return (self == csqcplayer);
-}
-
-void CSQCPlayer_SetViewLocation()
-{
- viewloc_SetViewLocation();
-}
-
-void CSQCPlayer_SetCamera()
-{SELFPARAM();
- vector v0;
- v0 = pmove_vel; // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
-
- if(csqcplayer)
- {
- setself(csqcplayer);
-
- if(servercommandframe == 0 || clientcommandframe == 0)
- {
- InterpolateOrigin_Do();
- self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
-
- // get crouch state from the server
- if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
- self.flags &= ~FL_DUCKED;
- else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
- self.flags |= FL_DUCKED;
-
- // get onground state from the server
- if(pmove_onground)
- self.flags |= FL_ONGROUND;
- else
- self.flags &= ~FL_ONGROUND;
-
- CSQCPlayer_SetMinsMaxs();
-
- // override it back just in case
- self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
-
- // set velocity
- self.velocity = v0;
- }
- else
- {
- float flg = self.iflags;
- self.iflags &= ~(IFLAG_ORIGIN | IFLAG_ANGLES);
- InterpolateOrigin_Do();
- self.iflags = flg;
-
- if(csqcplayer_status == CSQCPLAYERSTATUS_FROMSERVER)
- {
- vector o, v;
- o = self.origin;
- v = v0;
- csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
- CSQCPlayer_PredictTo(servercommandframe + 1, false);
- CSQCPlayer_SetPredictionError(self.origin - o, self.velocity - v, pmove_onground - !!(self.flags & FL_ONGROUND));
- self.origin = o;
- self.velocity = v;
-
- // get crouch state from the server
- if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
- self.flags &= ~FL_DUCKED;
- else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
- self.flags |= FL_DUCKED;
-
- // get onground state from the server
- if(pmove_onground)
- self.flags |= FL_ONGROUND;
- else
- self.flags &= ~FL_ONGROUND;
-
- CSQCPlayer_SavePrediction();
- }
- CSQCPlayer_PredictTo(clientcommandframe + 1, true);
-
-#ifdef CSQCMODEL_SERVERSIDE_CROUCH
- // get crouch state from the server (LAG)
- if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
- self.flags &= ~FL_DUCKED;
- else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
- self.flags |= FL_DUCKED;
-#endif
-
- CSQCPlayer_SetMinsMaxs();
-
- self.angles_y = input_angles.y;
- }
-
- // relink
- setorigin(self, self.origin);
-
- setself(this);
- }
-
- entity view = CSQCModel_server2csqc(player_localentnum);
-
- if(view && view != csqcplayer)
- {
- WITH(entity, self, view, InterpolateOrigin_Do());
- view.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
- }
-
- if(view)
- {
- int refdefflags = 0;
-
- if(view.csqcmodel_teleported)
- refdefflags |= REFDEFFLAG_TELEPORTED;
-
- if(input_buttons & 4)
- refdefflags |= REFDEFFLAG_JUMPING;
-
- // note: these two only work in WIP2, but are harmless in WIP1
- if(getstati(STAT_HEALTH) <= 0)
- refdefflags |= REFDEFFLAG_DEAD;
-
- if(intermission)
- refdefflags |= REFDEFFLAG_INTERMISSION;
-
- V_CalcRefdef(view, refdefflags);
- }
- else
- {
- // FIXME by CSQC spec we have to do this:
- // but it breaks chase cam
- /*
- setproperty(VF_ORIGIN, pmove_org + '0 0 1' * getstati(STAT_VIEWHEIGHT));
- setproperty(VF_ANGLES, view_angles);
- */
- }
-
- { CSQCPLAYER_HOOK_POSTCAMERASETUP }
-}
-
-void CSQCPlayer_Remove()
-{
- csqcplayer = world;
- cvar_settemp("cl_movement_replay", "1");
-}
-
-float CSQCPlayer_PreUpdate()
-{SELFPARAM();
- if(self != csqcplayer)
- return 0;
- if(csqcplayer_status != CSQCPLAYERSTATUS_FROMSERVER)
- CSQCPlayer_Unpredict();
- return 1;
-}
-
-float CSQCPlayer_PostUpdate()
-{SELFPARAM();
- if(self.entnum != player_localnum + 1)
- return 0;
- csqcplayer = self;
- csqcplayer_status = CSQCPLAYERSTATUS_FROMSERVER;
- cvar_settemp("cl_movement_replay", "0");
- self.entremove = CSQCPlayer_Remove;
- return 1;
-}
+++ /dev/null
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#ifndef CL_PLAYER_H
-#define CL_PLAYER_H
-
-entity csqcplayer;
-float csqcplayer_status;
-const int CSQCPLAYERSTATUS_UNPREDICTED = 0;
-const int CSQCPLAYERSTATUS_FROMSERVER = 1;
-const int CSQCPLAYERSTATUS_PREDICTED = 2;
-
-// only ever READ these!
-.int pmove_flags;
-const int PMF_JUMP_HELD = 1;
-//const int PMF_DUCKED = 4;
-//const int PMF_ONGROUND = 8;
-
-const int FL_DUCKED = 524288;
-
-void CSQCPlayer_SetCamera();
-float CSQCPlayer_PreUpdate();
-float CSQCPlayer_PostUpdate();
-float CSQCPlayer_IsLocalPlayer();
-#endif
+++ /dev/null
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#ifndef CSQCMODELLIB_COMMON_H
-#define CSQCMODELLIB_COMMON_H
-
-#include "../common/csqcmodel_settings.qh"
-
-noref string csqcmodel_license = "\
-Copyright (c) 2011 Rudolf Polzer\
-\
-Permission is hereby granted, free of charge, to any person obtaining a copy\
-of this software and associated documentation files (the \"Software\"), to\
-deal in the Software without restriction, including without limitation the\
-rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\
-sell copies of the Software, and to permit persons to whom the Software is\
-furnished to do so, subject to the following conditions:\
-\
-The above copyright notice and this permission notice shall be included in\
-all copies or substantial portions of the Software.\
-\
-THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\
-IN THE SOFTWARE.\
-";
-
-.vector glowmod;
-.vector view_ofs;
-.int frame;
-.float frame1time;
-.int frame2;
-.float frame2time;
-.float lerpfrac;
-
-const int CSQCMODEL_PROPERTY_FRAME = 8388608;
-const int CSQCMODEL_PROPERTY_TELEPORTED = 4194304; // the "teleport bit" cancelling interpolation
-const int CSQCMODEL_PROPERTY_MODELINDEX = 2097152;
-const int CSQCMODEL_PROPERTY_ORIGIN = 1048576;
-const int CSQCMODEL_PROPERTY_YAW = 524288;
-const int CSQCMODEL_PROPERTY_PITCHROLL = 262144;
-const int CSQCMODEL_PROPERTY_FRAME2 = 131072;
-const int CSQCMODEL_PROPERTY_LERPFRAC = 65536;
-const int CSQCMODEL_PROPERTY_SIZE = 32768;
-
-#define ALLPROPERTIES_COMMON \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_FRAME, int, ReadByte, WriteByte, frame) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_MODELINDEX, int, ReadShort, WriteShort, modelindex) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_x) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_y) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_z) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_x) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_y) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_z) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_x) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_y) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_z) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_PITCHROLL, float, ReadAngle, WriteAngle, angles_x) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_YAW, float, ReadAngle, WriteAngle, angles_y) \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_PITCHROLL, float, ReadAngle, WriteAngle, angles_z) \
- CSQCMODEL_EXTRAPROPERTIES
-
-#ifdef CSQCMODEL_HAVE_TWO_FRAMES
-.float frame3;
-.float frame3time;
-.float lerpfrac3;
-.float frame4;
-.float frame4time;
-.float lerpfrac4;
-#define ALLPROPERTIES ALLPROPERTIES_COMMON \
- CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_FRAME2, int, ReadByte, WriteByte, frame2) \
- CSQCMODEL_PROPERTY_SCALED(CSQCMODEL_PROPERTY_LERPFRAC, float, ReadByte, WriteByte, lerpfrac, 255, 0, 255)
-#else
-#define ALLPROPERTIES ALLPROPERTIES_COMMON
-#endif
-#endif
+++ /dev/null
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "../client/defs.qh"
- #include "../warpzonelib/anglestransform.qh"
- #include "../client/autocvars.qh"
- #include "interpolate.qh"
- #include "cl_model.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
-
-.vector iorigin1, iorigin2;
-.vector ivelocity1, ivelocity2;
-.vector iforward1, iforward2;
-.vector iup1, iup2;
-.vector ivforward1, ivforward2;
-.vector ivup1, ivup2;
-.float itime1, itime2;
-void InterpolateOrigin_Reset()
-{SELFPARAM();
- self.iflags &= ~IFLAG_INTERNALMASK;
- self.itime1 = self.itime2 = 0;
-}
-void InterpolateOrigin_Note()
-{SELFPARAM();
- float dt;
- int f0;
-
- dt = time - self.itime2;
-
- f0 = self.iflags;
- if(self.iflags & IFLAG_PREVALID)
- self.iflags |= IFLAG_VALID;
- else
- self.iflags |= IFLAG_PREVALID;
-
- if(self.iflags & IFLAG_ORIGIN)
- {
- self.iorigin1 = self.iorigin2;
- self.iorigin2 = self.origin;
- }
-
- if(self.iflags & IFLAG_AUTOANGLES)
- if(self.iorigin2 != self.iorigin1)
- self.angles = vectoangles(self.iorigin2 - self.iorigin1);
-
- if(self.iflags & IFLAG_AUTOVELOCITY)
- if(self.itime2 != self.itime1)
- self.velocity = (self.iorigin2 - self.iorigin1) * (1.0 / (self.itime2 - self.itime1));
-
- if(self.iflags & IFLAG_ANGLES)
- {
- fixedmakevectors(self.angles);
- if(f0 & IFLAG_VALID)
- {
- self.iforward1 = self.iforward2;
- self.iup1 = self.iup2;
- }
- else
- {
- self.iforward1 = v_forward;
- self.iup1 = v_up;
- }
- self.iforward2 = v_forward;
- self.iup2 = v_up;
- }
-
- if(self.iflags & IFLAG_V_ANGLE)
- {
- fixedmakevectors(self.v_angle);
- if(f0 & IFLAG_VALID)
- {
- self.ivforward1 = self.ivforward2;
- self.ivup1 = self.ivup2;
- }
- else
- {
- self.ivforward1 = v_forward;
- self.ivup1 = v_up;
- }
- self.ivforward2 = v_forward;
- self.ivup2 = v_up;
- }
- else if(self.iflags & IFLAG_V_ANGLE_X)
- {
- self.ivforward1_x = self.ivforward2_x;
- self.ivforward2_x = self.v_angle.x;
- }
-
- if(self.iflags & IFLAG_VELOCITY)
- {
- self.ivelocity1 = self.ivelocity2;
- self.ivelocity2 = self.velocity;
- }
-
- if(self.iflags & IFLAG_TELEPORTED)
- {
- self.iflags &= ~IFLAG_TELEPORTED;
- self.itime1 = self.itime2 = time; // don't lerp
- }
- else if(vlen(self.iorigin2 - self.iorigin1) > 1000)
- {
- self.itime1 = self.itime2 = time; // don't lerp
- }
- else if((self.iflags & IFLAG_VELOCITY) && (vlen(self.ivelocity2 - self.ivelocity1) > 1000))
- {
- self.itime1 = self.itime2 = time; // don't lerp
- }
- else if(dt >= 0.2)
- {
- self.itime1 = self.itime2 = time;
- }
- else
- {
- self.itime1 = serverprevtime;
- self.itime2 = time;
- }
-}
-void InterpolateOrigin_Do()
-{SELFPARAM();
- vector forward, up;
- if(self.itime1 && self.itime2 && self.itime1 != self.itime2)
- {
- float f;
- f = bound(0, (time - self.itime1) / (self.itime2 - self.itime1), 1 + autocvar_cl_lerpexcess);
- if(self.iflags & IFLAG_ORIGIN)
- setorigin(self, (1 - f) * self.iorigin1 + f * self.iorigin2);
- if(self.iflags & IFLAG_ANGLES)
- {
- forward = (1 - f) * self.iforward1 + f * self.iforward2;
- up = (1 - f) * self.iup1 + f * self.iup2;
- self.angles = fixedvectoangles2(forward, up);
- }
- if(self.iflags & IFLAG_V_ANGLE)
- {
- forward = (1 - f) * self.ivforward1 + f * self.ivforward2;
- up = (1 - f) * self.ivup1 + f * self.ivup2;
- self.v_angle = fixedvectoangles2(forward, up);
- }
- else if(self.iflags & IFLAG_V_ANGLE_X)
- self.v_angle_x = (1 - f) * self.ivforward1_x + f * self.ivforward2_x;
- if(self.iflags & IFLAG_VELOCITY)
- self.velocity = (1 - f) * self.ivelocity1 + f * self.ivelocity2;
- }
-}
-void InterpolateOrigin_Undo()
-{SELFPARAM();
- if(self.iflags & IFLAG_ORIGIN)
- setorigin(self, self.iorigin2);
- if(self.iflags & IFLAG_ANGLES)
- self.angles = fixedvectoangles2(self.iforward2, self.iup2);
- if(self.iflags & IFLAG_V_ANGLE)
- self.v_angle = fixedvectoangles2(self.ivforward2, self.ivup2);
- else if(self.iflags & IFLAG_V_ANGLE_X)
- self.v_angle_x = self.ivforward2_x;
- if(self.iflags & IFLAG_VELOCITY)
- self.velocity = self.ivelocity2;
-}
-
+++ /dev/null
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-#ifndef INTERPOLATE_H
-#define INTERPOLATE_H
-
-.int iflags;
-const int IFLAG_VELOCITY = 1;
-const int IFLAG_ANGLES = 2;
-const int IFLAG_AUTOANGLES = 4;
-const int IFLAG_VALID = 8;
-const int IFLAG_PREVALID = 16;
-const int IFLAG_TELEPORTED = 32;
-const int IFLAG_AUTOVELOCITY = 64;
-const int IFLAG_V_ANGLE = 128;
-const int IFLAG_V_ANGLE_X = 256;
-const int IFLAG_ORIGIN = 512;
-#define IFLAG_INTERNALMASK (IFLAG_VALID | IFLAG_PREVALID)
-
-// call this BEFORE reading an entity update
-void InterpolateOrigin_Undo();
-
-// call this AFTER receiving an entity update
-void InterpolateOrigin_Note();
-
-// call this when the entity got teleported, before InterpolateOrigin_Note
-void InterpolateOrigin_Reset();
-
-// call this BEFORE drawing
-void InterpolateOrigin_Do();
-
-// in case we interpolate that:
-.vector v_angle;
-#endif
+++ /dev/null
-#ifndef CSQCMODELLIB_SETTINGS_H
-#define CSQCMODELLIB_SETTINGS_H
-// define this if svqc code wants to use .frame2 and .lerpfrac
-//#define CSQCMODEL_HAVE_TWO_FRAMES
-
-// don't define this ever
-//#define CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
-
-// add properties you want networked to CSQC here
-#define CSQCMODEL_EXTRAPROPERTIES \
- /* CSQCMODEL_PROPERTY(1, float, ReadShort, WriteShort, colormap) */ \
- /* CSQCMODEL_PROPERTY(2, float, ReadInt24_t, WriteInt24_t, effects) */
-
-// add hook function calls here
-#define CSQCMODEL_HOOK_PREUPDATE
-#define CSQCMODEL_HOOK_POSTUPDATE
-#define CSQCMODEL_HOOK_PREDRAW
-#define CSQCPLAYER_HOOK_POSTCAMERASETUP
-
-// force updates of player entities that often even if unchanged
-#define CSQCPLAYER_FORCE_UPDATES 0.25
-
-// mod must define:
-//vector PL_MIN = ...;
-//vector PL_MAX = ...;
-//vector PL_VIEW_OFS = ...;
-//vector PL_CROUCH_MIN = ...;
-//vector PL_CROUCH_MAX = ...;
-//vector PL_CROUCH_VIEW_OFS = ...;
-#endif
+++ /dev/null
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../common/constants.qh"
- #include "../common/util.qh"
- #include "../common/animdecide.qh"
- #include "../server/constants.qh"
- #include "../server/defs.qh"
- #include "common.qh"
- #include "sv_model.qh"
-#endif
-
-// generic CSQC model code
-
-bool CSQCModel_Send(entity to, int sf)
-{SELFPARAM();
- // some nice flags for CSQCMODEL_IF
- float isplayer = (IS_CLIENT(self));
- float islocalplayer = (self == to);
- float isnolocalplayer = (isplayer && (self != to));
-
- unused_float = isplayer;
- unused_float = islocalplayer;
- unused_float = isnolocalplayer;
-
- WriteByte(MSG_ENTITY, ENT_CLIENT_MODEL);
- WriteInt24_t(MSG_ENTITY, sf);
-
-#define CSQCMODEL_IF(cond) if(cond) {
-#define CSQCMODEL_ENDIF }
-#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
- if(sf & flag) \
- { \
- w(MSG_ENTITY, self.csqcmodel_##f); \
- }
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
- ALLPROPERTIES
-#undef CSQCMODEL_PROPERTY_SCALED
-#undef CSQCMODEL_PROPERTY
-#undef CSQCMODEL_ENDIF
-#undef CSQCMODEL_IF
-
- return true;
-}
-
-#ifdef CSQCPLAYER_FORCE_UPDATES
-.float csqcmodel_nextforcedupdate;
-#endif
-void CSQCModel_CheckUpdate(entity e)
-{
- // some nice flags for CSQCMODEL_IF
- float isplayer = (IS_CLIENT(e));
- float islocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
- float isnolocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
-
- unused_float = isplayer;
- unused_float = islocalplayer;
- unused_float = isnolocalplayer;
-
-#ifdef CSQCPLAYER_FORCE_UPDATES
- if(isplayer && time > e.csqcmodel_nextforcedupdate)
- {
- e.SendFlags |= CSQCMODEL_PROPERTY_ORIGIN;
- e.csqcmodel_nextforcedupdate = time + CSQCPLAYER_FORCE_UPDATES * (0.5 + random()); // ensure about 4 origin sends per sec
- }
-#endif
-
- if(e.effects & EF_RESTARTANIM_BIT)
- {
- e.SendFlags |= CSQCMODEL_PROPERTY_FRAME | CSQCMODEL_PROPERTY_FRAME2; // full anim resend please
- e.effects &= ~EF_RESTARTANIM_BIT;
- }
-
- if(e.effects & EF_TELEPORT_BIT)
- {
- e.SendFlags |= CSQCMODEL_PROPERTY_TELEPORTED; // no interpolation please
- e.effects &= ~EF_TELEPORT_BIT;
- }
-
-#define CSQCMODEL_IF(cond) if(cond) {
-#define CSQCMODEL_ENDIF }
-#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
- { \
- t tmp = e.f; \
- if(tmp != e.csqcmodel_##f) \
- { \
- e.csqcmodel_##f = tmp; \
- e.SendFlags |= flag; \
- } \
- }
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
- { \
- t tmp = rint(bound(mi, s * e.f, ma) - mi); \
- if(tmp != e.csqcmodel_##f) \
- { \
- e.csqcmodel_##f = tmp; \
- e.SendFlags |= flag; \
- } \
- }
- ALLPROPERTIES
-#undef CSQCMODEL_PROPERTY_SCALED
-#undef CSQCMODEL_PROPERTY
-#undef CSQCMODEL_ENDIF
-#undef CSQCMODEL_IF
-}
-
-void CSQCModel_LinkEntity(entity e)
-{
- e.SendEntity = CSQCModel_Send;
- e.SendFlags = 0xFFFFFF;
- CSQCModel_CheckUpdate(e);
-}
-
-void CSQCModel_UnlinkEntity(entity e)
-{
- e.SendEntity = func_null;
-}
+++ /dev/null
-/*
- * Copyright (c) 2011 Rudolf Polzer
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #ifndef SV_MODEL_H
- #define SV_MODEL_H
-
- #include "common.qh"
-
-// generic CSQC model code
-
-void CSQCModel_CheckUpdate(entity e);
-void CSQCModel_LinkEntity(entity e);
-void CSQCModel_UnlinkEntity(entity e);
-
-#define CSQCMODEL_IF(cond)
-#define CSQCMODEL_ENDIF
-#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
- .t f; \
- .t csqcmodel_##f;
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
- ALLPROPERTIES
-#undef CSQCMODEL_PROPERTY_SCALED
-#undef CSQCMODEL_PROPERTY
-#undef CSQCMODEL_ENDIF
-#undef CSQCMODEL_IF
-#endif
-#include "bool.qh"
+#ifndef NOCOMPAT
+ #define COMPAT_NO_MOD_IS_XONOTIC
+#endif
+
+#include "compiler.qh"
+
+#ifndef QCC_SUPPORT_INT
+ #define int float
+#endif
+
+#ifndef QCC_SUPPORT_BOOL
+ #define bool float
+#endif
-#include "../warpzonelib/mathlib.qc"
+#if defined(CSQC)
+ #include "../dpdefs/csprogsdefs.qh"
+ #include "../dpdefs/keycodes.qh"
+#elif defined(SVQC)
+ #include "../server/sys-pre.qh"
+ #include "../dpdefs/progsdefs.qh"
+ #include "../dpdefs/dpextensions.qh"
+ #include "../server/sys-post.qh"
+#elif defined(MENUQC)
+ #include "../dpdefs/menudefs.qh"
+ #include "../dpdefs/keycodes.qh"
+#endif
+
+#include "warpzone/mathlib.qc"
#include "accumulate.qh"
#include "bits.qh"
+#include "bool.qh"
+#include "color.qh"
#include "counting.qh"
#include "cvar.qh"
#include "defer.qh"
#include "draw.qh"
#include "file.qh"
+#include "functional.qh"
#include "i18n.qh"
+#include "int.qh"
+#include "iter.qh"
#include "lazy.qh"
#include "log.qh"
#include "math.qh"
+#include "misc.qh"
#include "net.qh"
#include "nil.qh"
#include "noise.qc"
#include "random.qc"
#include "registry.qh"
#include "replicate.qh"
-#include "sort.qh"
+#include "self.qh"
#include "sortlist.qc"
+#include "sort.qh"
#include "spawnfunc.qh"
#include "static.qh"
#include "string.qh"
#define BOOL_H
#ifndef QCC_SUPPORT_BOOL
- #define bool float
-
// Boolean Constants
const int true = 1;
const int false = 0;
--- /dev/null
+#ifndef COLOR_H
+#define COLOR_H
+
+#define colormapPaletteColor(c, isPants) colormapPaletteColor_(c, isPants, time)
+vector colormapPaletteColor_(int c, bool isPants, float t)
+{
+ switch (c) {
+ case 0: return '1.000000 1.000000 1.000000';
+ case 1: return '1.000000 0.333333 0.000000';
+ case 2: return '0.000000 1.000000 0.501961';
+ case 3: return '0.000000 1.000000 0.000000';
+ case 4: return '1.000000 0.000000 0.000000';
+ case 5: return '0.000000 0.666667 1.000000';
+ case 6: return '0.000000 1.000000 1.000000';
+ case 7: return '0.501961 1.000000 0.000000';
+ case 8: return '0.501961 0.000000 1.000000';
+ case 9: return '1.000000 0.000000 1.000000';
+ case 10: return '1.000000 0.000000 0.501961';
+ case 11: return '0.000000 0.000000 1.000000';
+ case 12: return '1.000000 1.000000 0.000000';
+ case 13: return '0.000000 0.333333 1.000000';
+ case 14: return '1.000000 0.666667 0.000000';
+ case 15:
+ if (isPants)
+ return
+ '1 0 0' * (0.502 + 0.498 * sin(t / 2.7182818285 + 0.0000000000))
+ + '0 1 0' * (0.502 + 0.498 * sin(t / 2.7182818285 + 2.0943951024))
+ + '0 0 1' * (0.502 + 0.498 * sin(t / 2.7182818285 + 4.1887902048));
+ else
+ return
+ '1 0 0' * (0.502 + 0.498 * sin(t / 3.1415926536 + 5.2359877560))
+ + '0 1 0' * (0.502 + 0.498 * sin(t / 3.1415926536 + 3.1415926536))
+ + '0 0 1' * (0.502 + 0.498 * sin(t / 3.1415926536 + 1.0471975512));
+ default: return '0.000 0.000 0.000';
+ }
+}
+
+#endif
--- /dev/null
+#ifndef COMPILER_H
+#define COMPILER_H
+
+#ifndef QCC_SUPPORT_ACCUMULATE
+ #ifdef GMQCC
+ #define QCC_SUPPORT_ACCUMULATE
+ #endif
+#endif
+
+#ifndef QCC_SUPPORT_NIL
+ #ifdef GMQCC
+ #define QCC_SUPPORT_NIL
+ #endif
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2011 Rudolf PolzerCSQCModel_InterpolateAnimation_2To4_PreNote
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "cl_model.qh"
+
+#include "cl_player.qh"
+#include "common.qh"
+#include "interpolate.qh"
+#include "../../client/defs.qh"
+#include "../../common/animdecide.qh"
+#include "../../common/csqcmodel_settings.qh"
+#include "../../common/util.qh"
+
+float autocvar_cl_lerpanim_maxdelta_framegroups = 0.1;
+float autocvar_cl_nolerp = 0;
+
+.float csqcmodel_lerpfrac;
+.float csqcmodel_lerpfrac2;
+.float csqcmodel_lerpfractime;
+.float csqcmodel_lerpfrac2time;
+
+void CSQCModel_InterpolateAnimation_2To4_PreNote(int sf)
+{SELFPARAM();
+ if(sf & CSQCMODEL_PROPERTY_FRAME)
+ {
+ self.frame3 = self.frame;
+ self.frame3time = self.frame1time;
+ }
+ if(sf & CSQCMODEL_PROPERTY_FRAME2)
+ {
+ self.frame4 = self.frame2;
+ self.frame4time = self.frame2time;
+ }
+ if(sf & CSQCMODEL_PROPERTY_LERPFRAC)
+ {
+ self.csqcmodel_lerpfrac2 = self.csqcmodel_lerpfrac;
+ self.csqcmodel_lerpfrac2time = self.csqcmodel_lerpfractime;
+ self.lerpfrac = self.csqcmodel_lerpfrac;
+ }
+}
+void CSQCModel_InterpolateAnimation_1To2_PreNote(int sf)
+{SELFPARAM();
+ if(sf & CSQCMODEL_PROPERTY_FRAME)
+ {
+ self.frame2 = self.frame;
+ self.frame2time = self.frame1time;
+ }
+}
+void CSQCModel_InterpolateAnimation_PreNote(int sf)
+{
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+ CSQCModel_InterpolateAnimation_2To4_PreNote(sf);
+#else
+ CSQCModel_InterpolateAnimation_1To2_PreNote(sf);
+#endif
+}
+
+void CSQCModel_InterpolateAnimation_2To4_Note(int sf, float set_times)
+{SELFPARAM();
+ if(sf & CSQCMODEL_PROPERTY_FRAME)
+ {
+ if(set_times)
+ self.frame1time = time;
+ }
+ if(sf & CSQCMODEL_PROPERTY_FRAME2)
+ {
+ if(set_times)
+ self.frame2time = time;
+ }
+ if(sf & CSQCMODEL_PROPERTY_LERPFRAC)
+ {
+ self.csqcmodel_lerpfrac = self.lerpfrac;
+ if(set_times)
+ self.csqcmodel_lerpfractime = time;
+ }
+}
+void CSQCModel_InterpolateAnimation_1To2_Note(int sf, float set_times)
+{SELFPARAM();
+ if(sf & CSQCMODEL_PROPERTY_FRAME)
+ {
+ if(set_times)
+ self.frame1time = time;
+ }
+}
+void CSQCModel_InterpolateAnimation_Note(int sf)
+{
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+ CSQCModel_InterpolateAnimation_2To4_Note(sf, true);
+#else
+ CSQCModel_InterpolateAnimation_1To2_Note(sf, true);
+#endif
+}
+
+void CSQCModel_InterpolateAnimation_2To4_Do()
+{SELFPARAM();
+ if(autocvar_cl_nolerp || (autocvar_cl_lerpanim_maxdelta_framegroups == 0))
+ {
+ self.lerpfrac = self.csqcmodel_lerpfrac;
+ self.lerpfrac3 = 0;
+ self.lerpfrac4 = 0;
+ }
+ else
+ {
+ float l13, l24, llf;
+ float l24_13;
+
+ if(self.frame3time == 0) // if frame1/3 were not previously displayed, only frame1 can make sense
+ l13 = 1;
+ else
+ l13 = bound(0, (time - self.frame1time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
+
+ if(self.frame4time == 0) // if frame2/4 were not previously displayed, only frame2 can make sense
+ l24 = 1;
+ else
+ l24 = bound(0, (time - self.frame2time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
+
+ if(self.csqcmodel_lerpfrac2time == 0) // if there is no old lerpfrac (newly displayed model), only lerpfrac makes sense
+ llf = 1;
+ else
+ llf = bound(0, (time - self.csqcmodel_lerpfractime) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
+
+ l24_13 = self.csqcmodel_lerpfrac * llf + self.csqcmodel_lerpfrac2 * (1 - llf);
+
+ self.lerpfrac = l24 * l24_13;
+ self.lerpfrac4 = (1 - l24) * l24_13;
+ self.lerpfrac3 = (1 - l13) * (1 - l24_13);
+
+ if(l24_13 == 0) // if frames 2/4 are not displayed, clear their frametime
+ {
+ self.frame2time = 0;
+ self.frame4time = 0;
+ }
+
+ if(l24_13 == 1) // if frames 1/3 are not displayed, clear their frametime
+ {
+ self.frame1time = 0;
+ self.frame3time = 0;
+ }
+ }
+}
+void CSQCModel_InterpolateAnimation_1To2_Do()
+{SELFPARAM();
+ if(autocvar_cl_nolerp || (autocvar_cl_lerpanim_maxdelta_framegroups == 0))
+ {
+ self.lerpfrac = 0;
+ }
+ else
+ {
+ if(self.frame2time == 0) // if frame2 was not previously displayed, only frame1 can make sense
+ self.lerpfrac = 0;
+ else
+ self.lerpfrac = 1 - bound(0, (time - self.frame1time) / autocvar_cl_lerpanim_maxdelta_framegroups, 1);
+ }
+}
+void CSQCModel_InterpolateAnimation_Do()
+{
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+ CSQCModel_InterpolateAnimation_2To4_Do();
+#else
+ CSQCModel_InterpolateAnimation_1To2_Do();
+#endif
+}
+
+void CSQCModel_Draw()
+{SELFPARAM();
+ // some nice flags for CSQCMODEL_IF and the hooks
+ bool isplayer = (self.entnum >= 1 && self.entnum <= maxclients);
+ noref bool islocalplayer = (self.entnum == player_localnum + 1);
+ noref bool isnolocalplayer = (isplayer && (self.entnum != player_localnum + 1));
+
+ // we don't do this for the local player as that one is already handled
+ // by CSQCPlayer_SetCamera()
+ if(!CSQCPlayer_IsLocalPlayer())
+ InterpolateOrigin_Do();
+
+ CSQCModel_InterpolateAnimation_Do();
+
+ { CSQCMODEL_HOOK_PREDRAW }
+
+ // inherit draw flags easily
+ entity root = self;
+ while(root.tag_entity)
+ root = root.tag_entity;
+ if(self != root)
+ {
+ self.renderflags &= ~(RF_EXTERNALMODEL | RF_VIEWMODEL);
+ self.renderflags |= (root.renderflags & (RF_EXTERNALMODEL | RF_VIEWMODEL));
+ }
+
+ // we're drawn, now teleporting is over
+ self.csqcmodel_teleported = 0;
+}
+
+void CSQCModel_Read(bool isnew)
+{SELFPARAM();
+ int sf = ReadInt24_t();
+
+ // some nice flags for CSQCMODEL_IF and the hooks
+ bool isplayer = (self.entnum >= 1 && self.entnum <= maxclients);
+ bool islocalplayer = (self.entnum == player_localnum + 1);
+ noref bool isnolocalplayer = (isplayer && (self.entnum != player_localnum + 1));
+
+ self.classname = "csqcmodel";
+ self.iflags |= IFLAG_ORIGIN; // interpolate origin too
+ self.iflags |= IFLAG_ANGLES; // interpolate angles too
+ self.iflags |= IFLAG_VELOCITY | IFLAG_AUTOVELOCITY; // let's calculate velocity automatically
+
+ { CSQCMODEL_HOOK_PREUPDATE }
+
+ CSQCPlayer_PreUpdate();
+ InterpolateOrigin_Undo();
+ CSQCModel_InterpolateAnimation_PreNote(sf);
+
+#define CSQCMODEL_IF(cond) if(cond) {
+#define CSQCMODEL_ENDIF }
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+ if(sf & flag) \
+ self.f = r();
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
+ if(sf & flag) \
+ self.f = (r() + mi) / s;
+ ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+
+ if(sf & CSQCMODEL_PROPERTY_MODELINDEX)
+ {
+ vector pmin = self.mins, pmax = self.maxs;
+ setmodelindex(self, self.modelindex); // this retrieves the .model key and sets mins/maxs/absmin/absmax
+ setsize(self, pmin, pmax);
+ }
+
+ if(sf & CSQCMODEL_PROPERTY_TELEPORTED)
+ {
+ self.iflags |= IFLAG_TELEPORTED;
+ self.csqcmodel_teleported = 1;
+ }
+
+ CSQCModel_InterpolateAnimation_Note(sf);
+ InterpolateOrigin_Note();
+ CSQCPlayer_PostUpdate();
+
+ { CSQCMODEL_HOOK_POSTUPDATE }
+
+#ifdef CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
+ InterpolateOrigin_Do();
+ CSQCModel_InterpolateAnimation_Do();
+#endif
+
+ // relink
+ setorigin(self, self.origin);
+
+ // set obvious render flags
+ if(self.entnum == player_localentnum)
+ self.renderflags |= RF_EXTERNALMODEL;
+ else
+ self.renderflags &= ~RF_EXTERNALMODEL;
+
+ // draw it
+ self.drawmask = MASK_NORMAL;
+ self.predraw = CSQCModel_Draw;
+}
+
+entity CSQCModel_server2csqc(float pl)
+{
+ return findfloat(world, entnum, pl); // FIXME optimize this using an array
+}
--- /dev/null
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef LIB_CSQCMODEL_CL_MODEL_H
+#define LIB_CSQCMODEL_CL_MODEL_H
+
+#include "common.qh"
+
+void CSQCModel_Read(bool isnew);
+
+#define CSQCMODEL_IF(cond)
+#define CSQCMODEL_ENDIF
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+ .t f;
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
+ ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+
+entity CSQCModel_server2csqc(float pl);
+.float csqcmodel_teleported;
+
+// this is exported for custom frame animation code. Use with care.
+// to update frames, first call this:
+void CSQCModel_InterpolateAnimation_2To4_PreNote(int sf);
+void CSQCModel_InterpolateAnimation_1To2_PreNote(int sf);
+// then update frame, frame1time (and possibly frame2, frame2time, lerpfrac)
+// if set_times is not set, caller is responsible for frame1time, frame2time, csqcmodel_lerpfractime!
+void CSQCModel_InterpolateAnimation_2To4_Note(int sf, float set_times);
+void CSQCModel_InterpolateAnimation_1To2_Note(int sf, float set_times);
+// to retrieve animation state, call this
+void CSQCModel_InterpolateAnimation_2To4_Do();
+void CSQCModel_InterpolateAnimation_1To2_Do();
+// will overwrite lerpfrac, lerpfrac3, lerpfrac4, and possibly clear frame*time if they are undisplayed according to lerpfracs
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ * Copyright (c) 2015 Micah Talkiewicz
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "cl_player.qh"
+
+#include "cl_model.qh"
+#include "common.qh"
+#include "interpolate.qh"
+#include "../../client/defs.qh"
+#include "../../client/main.qh"
+#include "../../common/constants.qh"
+#include "../../common/stats.qh"
+#include "../../common/triggers/trigger/viewloc.qh"
+#include "../../common/util.qh"
+#include "../../common/viewloc.qh"
+
+float autocvar_cl_movement_errorcompensation = 0;
+int autocvar_cl_movement = 1;
+
+// engine stuff
+float pmove_onground; // weird engine flag we shouldn't really use but have to for now
+
+vector csqcplayer_origin, csqcplayer_velocity;
+float csqcplayer_sequence;
+int player_pmflags;
+float csqcplayer_moveframe;
+vector csqcplayer_predictionerroro;
+vector csqcplayer_predictionerrorv;
+float csqcplayer_predictionerrortime;
+float csqcplayer_predictionerrorfactor;
+
+vector CSQCPlayer_GetPredictionErrorO()
+{
+ if(time >= csqcplayer_predictionerrortime)
+ return '0 0 0';
+ return csqcplayer_predictionerroro * (csqcplayer_predictionerrortime - time) * csqcplayer_predictionerrorfactor;
+}
+
+vector CSQCPlayer_GetPredictionErrorV()
+{
+ if(time >= csqcplayer_predictionerrortime)
+ return '0 0 0';
+ return csqcplayer_predictionerrorv * (csqcplayer_predictionerrortime - time) * csqcplayer_predictionerrorfactor;
+}
+
+void CSQCPlayer_SetPredictionError(vector o, vector v, float onground_diff)
+{
+ // error too big to compensate, we LIKELY hit a teleport or a
+ // jumppad, or it's a jump time disagreement that'll get fixed
+ // next frame
+
+ // FIXME we sometimes have disagreement in order of jump velocity. Do not act on them!
+ /*
+ // commented out as this one did not help
+ if(onground_diff)
+ {
+ printf("ONGROUND MISMATCH: %d x=%v v=%v\n", onground_diff, o, v);
+ return;
+ }
+ */
+ if(vlen(o) > 32 || vlen(v) > 192)
+ {
+ //printf("TOO BIG: x=%v v=%v\n", o, v);
+ return;
+ }
+
+ if(!autocvar_cl_movement_errorcompensation)
+ {
+ csqcplayer_predictionerrorfactor = 0;
+ return;
+ }
+
+ csqcplayer_predictionerroro = CSQCPlayer_GetPredictionErrorO() + o;
+ csqcplayer_predictionerrorv = CSQCPlayer_GetPredictionErrorV() + v;
+ csqcplayer_predictionerrorfactor = autocvar_cl_movement_errorcompensation / ticrate;
+ csqcplayer_predictionerrortime = time + 1.0 / csqcplayer_predictionerrorfactor;
+}
+
+void CSQCPlayer_Unpredict()
+{SELFPARAM();
+ if(csqcplayer_status == CSQCPLAYERSTATUS_UNPREDICTED)
+ return;
+ if(csqcplayer_status != CSQCPLAYERSTATUS_PREDICTED)
+ error("Cannot unpredict in current status");
+ self.origin = csqcplayer_origin;
+ self.velocity = csqcplayer_velocity;
+ csqcplayer_moveframe = csqcplayer_sequence+1; //+1 because the recieved frame has the move already done (server side)
+ self.flags = player_pmflags;
+}
+
+void CSQCPlayer_SetMinsMaxs()
+{SELFPARAM();
+ if(self.flags & FL_DUCKED)
+ {
+ self.mins = PL_CROUCH_MIN;
+ self.maxs = PL_CROUCH_MAX;
+ self.view_ofs = PL_CROUCH_VIEW_OFS;
+ }
+ else
+ {
+ self.mins = PL_MIN;
+ self.maxs = PL_MAX;
+ self.view_ofs = PL_VIEW_OFS;
+ }
+}
+
+void CSQCPlayer_SavePrediction()
+{SELFPARAM();
+ player_pmflags = self.flags;
+ csqcplayer_origin = self.origin;
+ csqcplayer_velocity = self.velocity;
+ csqcplayer_sequence = servercommandframe;
+ csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
+}
+
+void CSQC_ClientMovement_PlayerMove_Frame();
+
+void PM_Movement_Move()
+{SELFPARAM();
+ runstandardplayerphysics(self);
+#ifdef CSQC
+ self.flags =
+ ((self.pmove_flags & PMF_DUCKED) ? FL_DUCKED : 0) |
+ (!(self.pmove_flags & PMF_JUMP_HELD) ? FL_JUMPRELEASED : 0) |
+ ((self.pmove_flags & PMF_ONGROUND) ? FL_ONGROUND : 0);
+#endif
+}
+
+void CSQCPlayer_Physics(void)
+{
+ switch(autocvar_cl_movement)
+ {
+ case 1: CSQC_ClientMovement_PlayerMove_Frame(); break;
+ case 2: PM_Movement_Move(); break;
+ }
+}
+
+void CSQCPlayer_PredictTo(float endframe, float apply_error)
+{SELFPARAM();
+ CSQCPlayer_Unpredict();
+ if(apply_error)
+ {
+ self.origin += CSQCPlayer_GetPredictionErrorO();
+ self.velocity += CSQCPlayer_GetPredictionErrorV();
+ }
+ CSQCPlayer_SetMinsMaxs();
+
+ csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
+
+#if 0
+ // we don't need this
+ // darkplaces makes servercommandframe == 0 in these cases anyway
+ if (getstatf(STAT_HEALTH) <= 0)
+ {
+ csqcplayer_moveframe = clientcommandframe;
+ getinputstate(csqcplayer_moveframe-1);
+ LOG_INFO("the Weird code path got hit\n");
+ return;
+ }
+#endif
+
+ if(csqcplayer_moveframe >= endframe)
+ {
+ getinputstate(csqcplayer_moveframe - 1);
+ }
+ else
+ {
+ do
+ {
+ if (!getinputstate(csqcplayer_moveframe))
+ break;
+ CSQCPlayer_Physics();
+ CSQCPlayer_SetMinsMaxs();
+ csqcplayer_moveframe++;
+ }
+ while(csqcplayer_moveframe < endframe);
+ }
+
+ //add in anything that was applied after (for low packet rate protocols)
+ input_angles = view_angles;
+}
+
+bool CSQCPlayer_IsLocalPlayer()
+{SELFPARAM();
+ return (self == csqcplayer);
+}
+
+void CSQCPlayer_SetViewLocation()
+{
+ viewloc_SetViewLocation();
+}
+
+void CSQCPlayer_SetCamera()
+{SELFPARAM();
+ vector v0;
+ v0 = pmove_vel; // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
+
+ if(csqcplayer)
+ {
+ setself(csqcplayer);
+
+ if(servercommandframe == 0 || clientcommandframe == 0)
+ {
+ InterpolateOrigin_Do();
+ self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
+
+ // get crouch state from the server
+ if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
+ self.flags &= ~FL_DUCKED;
+ else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
+ self.flags |= FL_DUCKED;
+
+ // get onground state from the server
+ if(pmove_onground)
+ self.flags |= FL_ONGROUND;
+ else
+ self.flags &= ~FL_ONGROUND;
+
+ CSQCPlayer_SetMinsMaxs();
+
+ // override it back just in case
+ self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
+
+ // set velocity
+ self.velocity = v0;
+ }
+ else
+ {
+ float flg = self.iflags;
+ self.iflags &= ~(IFLAG_ORIGIN | IFLAG_ANGLES);
+ InterpolateOrigin_Do();
+ self.iflags = flg;
+
+ if(csqcplayer_status == CSQCPLAYERSTATUS_FROMSERVER)
+ {
+ vector o, v;
+ o = self.origin;
+ v = v0;
+ csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
+ CSQCPlayer_PredictTo(servercommandframe + 1, false);
+ CSQCPlayer_SetPredictionError(self.origin - o, self.velocity - v, pmove_onground - !!(self.flags & FL_ONGROUND));
+ self.origin = o;
+ self.velocity = v;
+
+ // get crouch state from the server
+ if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
+ self.flags &= ~FL_DUCKED;
+ else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
+ self.flags |= FL_DUCKED;
+
+ // get onground state from the server
+ if(pmove_onground)
+ self.flags |= FL_ONGROUND;
+ else
+ self.flags &= ~FL_ONGROUND;
+
+ CSQCPlayer_SavePrediction();
+ }
+ CSQCPlayer_PredictTo(clientcommandframe + 1, true);
+
+#ifdef CSQCMODEL_SERVERSIDE_CROUCH
+ // get crouch state from the server (LAG)
+ if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
+ self.flags &= ~FL_DUCKED;
+ else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
+ self.flags |= FL_DUCKED;
+#endif
+
+ CSQCPlayer_SetMinsMaxs();
+
+ self.angles_y = input_angles.y;
+ }
+
+ // relink
+ setorigin(self, self.origin);
+
+ setself(this);
+ }
+
+ entity view = CSQCModel_server2csqc(player_localentnum);
+
+ if(view && view != csqcplayer)
+ {
+ WITH(entity, self, view, InterpolateOrigin_Do());
+ view.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
+ }
+
+ if(view)
+ {
+ int refdefflags = 0;
+
+ if(view.csqcmodel_teleported)
+ refdefflags |= REFDEFFLAG_TELEPORTED;
+
+ if(input_buttons & 4)
+ refdefflags |= REFDEFFLAG_JUMPING;
+
+ // note: these two only work in WIP2, but are harmless in WIP1
+ if(getstati(STAT_HEALTH) <= 0)
+ refdefflags |= REFDEFFLAG_DEAD;
+
+ if(intermission)
+ refdefflags |= REFDEFFLAG_INTERMISSION;
+
+ V_CalcRefdef(view, refdefflags);
+ }
+ else
+ {
+ // FIXME by CSQC spec we have to do this:
+ // but it breaks chase cam
+ /*
+ setproperty(VF_ORIGIN, pmove_org + '0 0 1' * getstati(STAT_VIEWHEIGHT));
+ setproperty(VF_ANGLES, view_angles);
+ */
+ }
+
+ { CSQCPLAYER_HOOK_POSTCAMERASETUP }
+}
+
+void CSQCPlayer_Remove()
+{
+ csqcplayer = world;
+ cvar_settemp("cl_movement_replay", "1");
+}
+
+float CSQCPlayer_PreUpdate()
+{SELFPARAM();
+ if(self != csqcplayer)
+ return 0;
+ if(csqcplayer_status != CSQCPLAYERSTATUS_FROMSERVER)
+ CSQCPlayer_Unpredict();
+ return 1;
+}
+
+float CSQCPlayer_PostUpdate()
+{SELFPARAM();
+ if(self.entnum != player_localnum + 1)
+ return 0;
+ csqcplayer = self;
+ csqcplayer_status = CSQCPLAYERSTATUS_FROMSERVER;
+ cvar_settemp("cl_movement_replay", "0");
+ self.entremove = CSQCPlayer_Remove;
+ return 1;
+}
--- /dev/null
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef LIB_CSQCMODEL_CL_PLAYER_H
+#define LIB_CSQCMODEL_CL_PLAYER_H
+
+entity csqcplayer;
+float csqcplayer_status;
+const int CSQCPLAYERSTATUS_UNPREDICTED = 0;
+const int CSQCPLAYERSTATUS_FROMSERVER = 1;
+const int CSQCPLAYERSTATUS_PREDICTED = 2;
+
+// only ever READ these!
+.int pmove_flags;
+const int PMF_JUMP_HELD = 1;
+//const int PMF_DUCKED = 4;
+//const int PMF_ONGROUND = 8;
+
+const int FL_DUCKED = 524288;
+
+void CSQCPlayer_SetCamera();
+float CSQCPlayer_PreUpdate();
+float CSQCPlayer_PostUpdate();
+float CSQCPlayer_IsLocalPlayer();
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef LIB_CSQCMODEL_COMMON_H
+#define LIB_CSQCMODEL_COMMON_H
+
+#include "../../common/csqcmodel_settings.qh"
+
+noref string csqcmodel_license = "\
+Copyright (c) 2011 Rudolf Polzer\
+\
+Permission is hereby granted, free of charge, to any person obtaining a copy\
+of this software and associated documentation files (the \"Software\"), to\
+deal in the Software without restriction, including without limitation the\
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\
+sell copies of the Software, and to permit persons to whom the Software is\
+furnished to do so, subject to the following conditions:\
+\
+The above copyright notice and this permission notice shall be included in\
+all copies or substantial portions of the Software.\
+\
+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\
+IN THE SOFTWARE.\
+";
+
+.vector glowmod;
+.vector view_ofs;
+.int frame;
+.float frame1time;
+.int frame2;
+.float frame2time;
+.float lerpfrac;
+
+const int CSQCMODEL_PROPERTY_FRAME = 8388608;
+const int CSQCMODEL_PROPERTY_TELEPORTED = 4194304; // the "teleport bit" cancelling interpolation
+const int CSQCMODEL_PROPERTY_MODELINDEX = 2097152;
+const int CSQCMODEL_PROPERTY_ORIGIN = 1048576;
+const int CSQCMODEL_PROPERTY_YAW = 524288;
+const int CSQCMODEL_PROPERTY_PITCHROLL = 262144;
+const int CSQCMODEL_PROPERTY_FRAME2 = 131072;
+const int CSQCMODEL_PROPERTY_LERPFRAC = 65536;
+const int CSQCMODEL_PROPERTY_SIZE = 32768;
+
+#define ALLPROPERTIES_COMMON \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_FRAME, int, ReadByte, WriteByte, frame) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_MODELINDEX, int, ReadShort, WriteShort, modelindex) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_x) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_y) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_z) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_x) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_y) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_z) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_x) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_y) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_z) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_PITCHROLL, float, ReadAngle, WriteAngle, angles_x) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_YAW, float, ReadAngle, WriteAngle, angles_y) \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_PITCHROLL, float, ReadAngle, WriteAngle, angles_z) \
+ CSQCMODEL_EXTRAPROPERTIES
+
+#ifdef CSQCMODEL_HAVE_TWO_FRAMES
+.float frame3;
+.float frame3time;
+.float lerpfrac3;
+.float frame4;
+.float frame4time;
+.float lerpfrac4;
+#define ALLPROPERTIES ALLPROPERTIES_COMMON \
+ CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_FRAME2, int, ReadByte, WriteByte, frame2) \
+ CSQCMODEL_PROPERTY_SCALED(CSQCMODEL_PROPERTY_LERPFRAC, float, ReadByte, WriteByte, lerpfrac, 255, 0, 255)
+#else
+#define ALLPROPERTIES ALLPROPERTIES_COMMON
+#endif
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "interpolate.qh"
+
+#if defined(CSQC)
+// #include "../../client/defs.qh"
+// #include "../warpzone/anglestransform.qh"
+// #include "../../client/autocvars.qh"
+// #include "cl_model.qh"
+#elif defined(MENUQC)
+#elif defined(SVQC)
+#endif
+
+.vector iorigin1, iorigin2;
+.vector ivelocity1, ivelocity2;
+.vector iforward1, iforward2;
+.vector iup1, iup2;
+.vector ivforward1, ivforward2;
+.vector ivup1, ivup2;
+.float itime1, itime2;
+void InterpolateOrigin_Reset()
+{SELFPARAM();
+ self.iflags &= ~IFLAG_INTERNALMASK;
+ self.itime1 = self.itime2 = 0;
+}
+void InterpolateOrigin_Note()
+{SELFPARAM();
+ float dt;
+ int f0;
+
+ dt = time - self.itime2;
+
+ f0 = self.iflags;
+ if(self.iflags & IFLAG_PREVALID)
+ self.iflags |= IFLAG_VALID;
+ else
+ self.iflags |= IFLAG_PREVALID;
+
+ if(self.iflags & IFLAG_ORIGIN)
+ {
+ self.iorigin1 = self.iorigin2;
+ self.iorigin2 = self.origin;
+ }
+
+ if(self.iflags & IFLAG_AUTOANGLES)
+ if(self.iorigin2 != self.iorigin1)
+ self.angles = vectoangles(self.iorigin2 - self.iorigin1);
+
+ if(self.iflags & IFLAG_AUTOVELOCITY)
+ if(self.itime2 != self.itime1)
+ self.velocity = (self.iorigin2 - self.iorigin1) * (1.0 / (self.itime2 - self.itime1));
+
+ if(self.iflags & IFLAG_ANGLES)
+ {
+ fixedmakevectors(self.angles);
+ if(f0 & IFLAG_VALID)
+ {
+ self.iforward1 = self.iforward2;
+ self.iup1 = self.iup2;
+ }
+ else
+ {
+ self.iforward1 = v_forward;
+ self.iup1 = v_up;
+ }
+ self.iforward2 = v_forward;
+ self.iup2 = v_up;
+ }
+
+ if(self.iflags & IFLAG_V_ANGLE)
+ {
+ fixedmakevectors(self.v_angle);
+ if(f0 & IFLAG_VALID)
+ {
+ self.ivforward1 = self.ivforward2;
+ self.ivup1 = self.ivup2;
+ }
+ else
+ {
+ self.ivforward1 = v_forward;
+ self.ivup1 = v_up;
+ }
+ self.ivforward2 = v_forward;
+ self.ivup2 = v_up;
+ }
+ else if(self.iflags & IFLAG_V_ANGLE_X)
+ {
+ self.ivforward1_x = self.ivforward2_x;
+ self.ivforward2_x = self.v_angle.x;
+ }
+
+ if(self.iflags & IFLAG_VELOCITY)
+ {
+ self.ivelocity1 = self.ivelocity2;
+ self.ivelocity2 = self.velocity;
+ }
+
+ if(self.iflags & IFLAG_TELEPORTED)
+ {
+ self.iflags &= ~IFLAG_TELEPORTED;
+ self.itime1 = self.itime2 = time; // don't lerp
+ }
+ else if(vlen(self.iorigin2 - self.iorigin1) > 1000)
+ {
+ self.itime1 = self.itime2 = time; // don't lerp
+ }
+ else if((self.iflags & IFLAG_VELOCITY) && (vlen(self.ivelocity2 - self.ivelocity1) > 1000))
+ {
+ self.itime1 = self.itime2 = time; // don't lerp
+ }
+ else if(dt >= 0.2)
+ {
+ self.itime1 = self.itime2 = time;
+ }
+ else
+ {
+ self.itime1 = serverprevtime;
+ self.itime2 = time;
+ }
+}
+void InterpolateOrigin_Do()
+{SELFPARAM();
+ vector forward, up;
+ if(self.itime1 && self.itime2 && self.itime1 != self.itime2)
+ {
+ float f;
+ f = bound(0, (time - self.itime1) / (self.itime2 - self.itime1), 1 + autocvar_cl_lerpexcess);
+ if(self.iflags & IFLAG_ORIGIN)
+ setorigin(self, (1 - f) * self.iorigin1 + f * self.iorigin2);
+ if(self.iflags & IFLAG_ANGLES)
+ {
+ forward = (1 - f) * self.iforward1 + f * self.iforward2;
+ up = (1 - f) * self.iup1 + f * self.iup2;
+ self.angles = fixedvectoangles2(forward, up);
+ }
+ if(self.iflags & IFLAG_V_ANGLE)
+ {
+ forward = (1 - f) * self.ivforward1 + f * self.ivforward2;
+ up = (1 - f) * self.ivup1 + f * self.ivup2;
+ self.v_angle = fixedvectoangles2(forward, up);
+ }
+ else if(self.iflags & IFLAG_V_ANGLE_X)
+ self.v_angle_x = (1 - f) * self.ivforward1_x + f * self.ivforward2_x;
+ if(self.iflags & IFLAG_VELOCITY)
+ self.velocity = (1 - f) * self.ivelocity1 + f * self.ivelocity2;
+ }
+}
+void InterpolateOrigin_Undo()
+{SELFPARAM();
+ if(self.iflags & IFLAG_ORIGIN)
+ setorigin(self, self.iorigin2);
+ if(self.iflags & IFLAG_ANGLES)
+ self.angles = fixedvectoangles2(self.iforward2, self.iup2);
+ if(self.iflags & IFLAG_V_ANGLE)
+ self.v_angle = fixedvectoangles2(self.ivforward2, self.ivup2);
+ else if(self.iflags & IFLAG_V_ANGLE_X)
+ self.v_angle_x = self.ivforward2_x;
+ if(self.iflags & IFLAG_VELOCITY)
+ self.velocity = self.ivelocity2;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef LIB_CSQCMODEL_INTERPOLATE_H
+#define LIB_CSQCMODEL_INTERPOLATE_H
+
+.int iflags;
+const int IFLAG_VELOCITY = 1;
+const int IFLAG_ANGLES = 2;
+const int IFLAG_AUTOANGLES = 4;
+const int IFLAG_VALID = 8;
+const int IFLAG_PREVALID = 16;
+const int IFLAG_TELEPORTED = 32;
+const int IFLAG_AUTOVELOCITY = 64;
+const int IFLAG_V_ANGLE = 128;
+const int IFLAG_V_ANGLE_X = 256;
+const int IFLAG_ORIGIN = 512;
+#define IFLAG_INTERNALMASK (IFLAG_VALID | IFLAG_PREVALID)
+
+// call this BEFORE reading an entity update
+void InterpolateOrigin_Undo();
+
+// call this AFTER receiving an entity update
+void InterpolateOrigin_Note();
+
+// call this when the entity got teleported, before InterpolateOrigin_Note
+void InterpolateOrigin_Reset();
+
+// call this BEFORE drawing
+void InterpolateOrigin_Do();
+
+// in case we interpolate that:
+.vector v_angle;
+#endif
--- /dev/null
+#ifndef LIB_CSQCMODEL_SETTINGS_H
+#define LIB_CSQCMODEL_SETTINGS_H
+// define this if svqc code wants to use .frame2 and .lerpfrac
+//#define CSQCMODEL_HAVE_TWO_FRAMES
+
+// don't define this ever
+//#define CSQCMODEL_SUPPORT_GETTAGINFO_BEFORE_DRAW
+
+// add properties you want networked to CSQC here
+#define CSQCMODEL_EXTRAPROPERTIES \
+ /* CSQCMODEL_PROPERTY(1, float, ReadShort, WriteShort, colormap) */ \
+ /* CSQCMODEL_PROPERTY(2, float, ReadInt24_t, WriteInt24_t, effects) */
+
+// add hook function calls here
+#define CSQCMODEL_HOOK_PREUPDATE
+#define CSQCMODEL_HOOK_POSTUPDATE
+#define CSQCMODEL_HOOK_PREDRAW
+#define CSQCPLAYER_HOOK_POSTCAMERASETUP
+
+// force updates of player entities that often even if unchanged
+#define CSQCPLAYER_FORCE_UPDATES 0.25
+
+// mod must define:
+//vector PL_MIN = ...;
+//vector PL_MAX = ...;
+//vector PL_VIEW_OFS = ...;
+//vector PL_CROUCH_MIN = ...;
+//vector PL_CROUCH_MAX = ...;
+//vector PL_CROUCH_VIEW_OFS = ...;
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include "sv_model.qh"
+
+#include "common.qh"
+#include "../../common/animdecide.qh"
+#include "../../common/constants.qh"
+#include "../../common/util.qh"
+#include "../../server/constants.qh"
+#include "../../server/defs.qh"
+
+// generic CSQC model code
+
+bool CSQCModel_Send(entity to, int sf)
+{SELFPARAM();
+ // some nice flags for CSQCMODEL_IF
+ float isplayer = (IS_CLIENT(self));
+ float islocalplayer = (self == to);
+ float isnolocalplayer = (isplayer && (self != to));
+
+ unused_float = isplayer;
+ unused_float = islocalplayer;
+ unused_float = isnolocalplayer;
+
+ WriteByte(MSG_ENTITY, ENT_CLIENT_MODEL);
+ WriteInt24_t(MSG_ENTITY, sf);
+
+#define CSQCMODEL_IF(cond) if(cond) {
+#define CSQCMODEL_ENDIF }
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+ if(sf & flag) \
+ { \
+ w(MSG_ENTITY, self.csqcmodel_##f); \
+ }
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
+ ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+
+ return true;
+}
+
+#ifdef CSQCPLAYER_FORCE_UPDATES
+.float csqcmodel_nextforcedupdate;
+#endif
+void CSQCModel_CheckUpdate(entity e)
+{
+ // some nice flags for CSQCMODEL_IF
+ float isplayer = (IS_CLIENT(e));
+ float islocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
+ float isnolocalplayer = isplayer; // we set BOTH to 1 here as we need the sendflags
+
+ unused_float = isplayer;
+ unused_float = islocalplayer;
+ unused_float = isnolocalplayer;
+
+#ifdef CSQCPLAYER_FORCE_UPDATES
+ if(isplayer && time > e.csqcmodel_nextforcedupdate)
+ {
+ e.SendFlags |= CSQCMODEL_PROPERTY_ORIGIN;
+ e.csqcmodel_nextforcedupdate = time + CSQCPLAYER_FORCE_UPDATES * (0.5 + random()); // ensure about 4 origin sends per sec
+ }
+#endif
+
+ if(e.effects & EF_RESTARTANIM_BIT)
+ {
+ e.SendFlags |= CSQCMODEL_PROPERTY_FRAME | CSQCMODEL_PROPERTY_FRAME2; // full anim resend please
+ e.effects &= ~EF_RESTARTANIM_BIT;
+ }
+
+ if(e.effects & EF_TELEPORT_BIT)
+ {
+ e.SendFlags |= CSQCMODEL_PROPERTY_TELEPORTED; // no interpolation please
+ e.effects &= ~EF_TELEPORT_BIT;
+ }
+
+#define CSQCMODEL_IF(cond) if(cond) {
+#define CSQCMODEL_ENDIF }
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+ { \
+ t tmp = e.f; \
+ if(tmp != e.csqcmodel_##f) \
+ { \
+ e.csqcmodel_##f = tmp; \
+ e.SendFlags |= flag; \
+ } \
+ }
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
+ { \
+ t tmp = rint(bound(mi, s * e.f, ma) - mi); \
+ if(tmp != e.csqcmodel_##f) \
+ { \
+ e.csqcmodel_##f = tmp; \
+ e.SendFlags |= flag; \
+ } \
+ }
+ ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+}
+
+void CSQCModel_LinkEntity(entity e)
+{
+ e.SendEntity = CSQCModel_Send;
+ e.SendFlags = 0xFFFFFF;
+ CSQCModel_CheckUpdate(e);
+}
+
+void CSQCModel_UnlinkEntity(entity e)
+{
+ e.SendEntity = func_null;
+}
--- /dev/null
+/*
+ * Copyright (c) 2011 Rudolf Polzer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#ifndef LIB_CSQCMODEL_SV_MODEL_H
+#define LIB_CSQCMODEL_SV_MODEL_H
+
+#include "common.qh"
+
+// generic CSQC model code
+
+void CSQCModel_CheckUpdate(entity e);
+void CSQCModel_LinkEntity(entity e);
+void CSQCModel_UnlinkEntity(entity e);
+
+#define CSQCMODEL_IF(cond)
+#define CSQCMODEL_ENDIF
+#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
+ .t f; \
+ .t csqcmodel_##f;
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
+ ALLPROPERTIES
+#undef CSQCMODEL_PROPERTY_SCALED
+#undef CSQCMODEL_PROPERTY
+#undef CSQCMODEL_ENDIF
+#undef CSQCMODEL_IF
+#endif
#ifndef MENUQC
#ifndef DEFER_H
#define DEFER_H
+
#include "oo.qh"
+#include "self.qh"
entityclass(Defer);
class(Defer) .entity owner;
--- /dev/null
+#ifndef FUNCTIONAL_H
+#define FUNCTIONAL_H
+
+#define MAP(f, ...) EVAL(OVERLOAD(MAP, f, __VA_ARGS__))
+#define MAP_2(f, it) f(it)
+#define MAP_3(f, it, ...) f(it)MAP_2(f, __VA_ARGS__)
+#define MAP_4(f, it, ...) f(it)MAP_3(f, __VA_ARGS__)
+#define MAP_5(f, it, ...) f(it)MAP_4(f, __VA_ARGS__)
+#define MAP_6(f, it, ...) f(it)MAP_5(f, __VA_ARGS__)
+#define MAP_7(f, it, ...) f(it)MAP_6(f, __VA_ARGS__)
+#define MAP_8(f, it, ...) f(it)MAP_7(f, __VA_ARGS__)
+#define MAP_9(f, it, ...) f(it)MAP_8(f, __VA_ARGS__)
+#define MAP_10(f, it, ...) f(it)MAP_9(f, __VA_ARGS__)
+#define MAP_11(f, it, ...) f(it)MAP_10(f, __VA_ARGS__)
+#define MAP_12(f, it, ...) f(it)MAP_11(f, __VA_ARGS__)
+#define MAP_13(f, it, ...) f(it)MAP_12(f, __VA_ARGS__)
+#define MAP_14(f, it, ...) f(it)MAP_13(f, __VA_ARGS__)
+#define MAP_15(f, it, ...) f(it)MAP_14(f, __VA_ARGS__)
+#define MAP_16(f, it, ...) f(it)MAP_15(f, __VA_ARGS__)
+#define MAP_17(f, it, ...) f(it)MAP_16(f, __VA_ARGS__)
+#define MAP_18(f, it, ...) f(it)MAP_17(f, __VA_ARGS__)
+#define MAP_19(f, it, ...) f(it)MAP_18(f, __VA_ARGS__)
+#define MAP_20(f, it, ...) f(it)MAP_19(f, __VA_ARGS__)
+
+#define IDENTITY(it) it
+
+#define UNWORDS(...) MAP(IDENTITY, __VA_ARGS__)
+
+#define APPLY(f, ...) f(__VA_ARGS__)
+
+#ifdef SVQC
+ #define SV(f, ...) f(__VA_ARGS__)
+#else
+ #define SV(f, ...)
+#endif
+
+#ifdef CSQC
+ #define CL(f, ...) f(__VA_ARGS__)
+#else
+ #define CL(f, ...)
+#endif
+
+#define IF(cond, f, ...) cond(f, __VA_ARGS__)
+
+#endif
--- /dev/null
+#ifndef INT_H
+#define INT_H
+
+#ifndef QCC_SUPPORT_INT
+ #define stoi(s) stof(s)
+ #define stob(s) stof(s)
+ #define itos(i) ftos(i)
+#else
+ #define stoi(s) ((int) stof(s))
+ #define stob(s) ((bool) stof(s))
+ #define itos(i) ftos(i)
+#endif
+
+#endif
--- /dev/null
+#ifndef ITER_H
+#define ITER_H
+
+#define FOREACH_ARRAY(arr, start, end, cond, body) do { \
+ for (int i = start; i < end; ++i) { \
+ const noref entity it = arr[i]; \
+ if (cond) { body } \
+ } \
+} while(0)
+
+#define FOREACH_LIST(list, next, cond, body) do { \
+ noref int i = 0; \
+ for (entity it = list##_first; it; (it = it.next, ++i)) { \
+ if (cond) { body } \
+ } \
+} while(0)
+
+#define FOREACH(list, cond, body) FOREACH_LIST(list, enemy, cond, body)
+
+#endif
--- /dev/null
+#ifndef MISC_H
+#define MISC_H
+
+#ifdef GMQCC
+ #define EVAL(...) __VA_ARGS__
+
+ #define OVERLOAD_(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
+ #define OVERLOAD(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
+#else
+ #define EMPTY()
+ #define DEFER(id) id EMPTY()
+
+ #define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
+ #define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
+ #define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
+ #define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
+ #define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
+ #define EVAL5(...) __VA_ARGS__
+
+ #define OVERLOAD___(F,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,n,...) F##_##n
+ #define OVERLOAD__(F, ...) OVERLOAD___(F,##__VA_ARGS__,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
+ #define OVERLOAD_(...) DEFER(OVERLOAD__(__VA_ARGS__))
+ #define OVERLOAD(F, ...) OVERLOAD_(F,##__VA_ARGS__)(__VA_ARGS__)
+#endif
+
+#define GET(name) name##get
+#define GETTER(type, name) type GET(name)() { return name; }
+
+#define LAMBDA(...) { __VA_ARGS__ ; }
+
+// Can't wrap with do-while as block may contain continue or break
+#define WITH(type, name, value, block) { \
+ type __with_save = (name); \
+ name = (value); \
+ LAMBDA(block) \
+ name = __with_save; \
+} do { } while (0)
+
+#endif
#ifndef NIL_H
#define NIL_H
-#if QCC_SUPPORT_NIL
+#ifdef QCC_SUPPORT_NIL
#define func_null nil
#define string_null nil
#else
#ifndef OO_H
#define OO_H
+#include "misc.qh"
#include "nil.qh"
#ifdef MENUQC
#define class(name) [[class(name)]]
#define new(class) ((class) __spawn(#class, __FILE__, __LINE__))
#endif
+#define spawn() new(entity)
// Classes have a `spawn##cname(entity)` constructor
// The parameter is used across [[accumulate]] functions
* @param fld The field to store the current count into
* @param inst An expression to create a new instance, invoked for every registration
*/
-#define REGISTER(initfunc, ns, array, id, fld, inst) \
- entity ns##_##id; \
- REGISTER_INIT(ns, id) { } \
- REGISTER_INIT_POST(ns, id) { } \
- .entity enemy; /* internal next pointer */ \
- void Register_##ns##_##id() { \
+#define REGISTER(initfunc, ns, array, id, fld, inst) \
+ entity ns##_##id; \
+ REGISTER_INIT(ns, id) { } \
+ REGISTER_INIT_POST(ns, id) { } \
+ void Register_##ns##_##id() { \
if (array##_COUNT >= array##_MAX) LOG_FATALF("Registry capacity exceeded (%s)", ftos(array##_MAX)); \
- entity this = inst; \
- ns##_##id = this; \
- this.fld = array##_COUNT; \
- array[array##_COUNT++] = this; \
- if (!array##_first) array##_first = this; \
- if ( array##_last) array##_last.enemy = this; \
- array##_last = this; \
- Register_##ns##_##id##_init(this); \
- Register_##ns##_##id##_init_post(this); \
- } \
- ACCUMULATE_FUNCTION(initfunc, Register_##ns##_##id) \
+ entity this = inst; \
+ ns##_##id = this; \
+ this.fld = array##_COUNT; \
+ array[array##_COUNT++] = this; \
+ if (!array##_first) array##_first = this; \
+ if ( array##_last) array##_last.REGISTRY_NEXT = this; \
+ array##_last = this; \
+ Register_##ns##_##id##_init(this); \
+ Register_##ns##_##id##_init_post(this); \
+ } \
+ ACCUMULATE_FUNCTION(initfunc, Register_##ns##_##id) \
REGISTER_INIT(ns, id)
-#define REGISTRY_SORT(id, field, skip) \
- void _REGISTRY_SWAP_##id(int i, int j, entity pass) { \
- i += skip; j += skip; \
- entity e = id[i]; \
- id[i] = id[j]; \
- id[j] = e; \
- } \
- float _REGISTRY_CMP_##id(int i, int j, entity pass) { \
- i += skip; j += skip; \
- string a = id[i].field; \
- string b = id[j].field; \
- return strcasecmp(a, b); \
- } \
- STATIC_INIT(Registry_sort_##id) { \
+/** internal next pointer */
+#define REGISTRY_NEXT enemy
+.entity REGISTRY_NEXT;
+
+#define REGISTRY_SORT(id, field, skip) \
+ void _REGISTRY_SWAP_##id(int i, int j, entity pass) { \
+ i += skip; j += skip; \
+ \
+ entity a = id[i], b = id[j]; \
+ id[i] = b; \
+ id[j] = a; \
+ \
+ entity a_next = a.REGISTRY_NEXT, b_next = b.REGISTRY_NEXT; \
+ a.REGISTRY_NEXT = b_next; \
+ b.REGISTRY_NEXT = a_next; \
+ \
+ if (i == 0) id##_first = b; \
+ else id[i - 1].REGISTRY_NEXT = b; \
+ \
+ if (j == 0) id##_first = a; \
+ else id[j - 1].REGISTRY_NEXT = a; \
+ } \
+ float _REGISTRY_CMP_##id(int i, int j, entity pass) { \
+ i += skip; j += skip; \
+ string a = id[i].field; \
+ string b = id[j].field; \
+ return strcasecmp(a, b); \
+ } \
+ STATIC_INIT(Registry_sort_##id) { \
heapsort(id##_COUNT - (skip), _REGISTRY_SWAP_##id, _REGISTRY_CMP_##id, NULL); \
}
--- /dev/null
+#ifndef SELF_H
+#define SELF_H
+
+// Transition from global 'self' to local 'this'
+
+[[alias("self")]] entity __self;
+
+// Step 1: auto oldself
+#if 1
+#define SELFPARAM() noref entity this = __self
+#define setself(s) (__self = s)
+#define self __self
+#endif
+
+// Step 2: check SELFPARAM() is present for functions that use self
+#if 0
+#define SELFPARAM() [[alias("__self")]] noref entity this = __self
+#define setself(s) (__self = s)
+#define self this
+#endif
+
+// Step 3: const self
+#if 0
+#define SELFPARAM() noref const entity this = __self
+entity setself(entity e) { return self = e; }
+entity getself() { return self; }
+#define self getself()
+#endif
+
+// Step 4: enable when possible
+// TODO: Remove SELFPARAM in favor of a parameter
+#if 0
+#define SELFPARAM() noref const entity this = __self
+#define self this
+#endif
+
+#endif
#ifndef TEST_H
#define TEST_H
-#include "../common/util.qh"
-
#define TEST_Check(cond) do { if(!(cond)) TEST_Fail(#cond); } while(0)
void TEST_OK();
#ifndef URLLIB_H
#define URLLIB_H
-#include "../common/util.qh"
-
// URI handles
const int URI_GET_DISCARD = 0;
const int URI_GET_IPBAN = 1;
--- /dev/null
+The code in this directory is dual-licensed MIT and GPLv2 "or any later version".
+
+
+
+MIT license:
+
+Copyright (c) 2010 Rudolf Polzer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+
+
+GPL v2:
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, 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 Lesser 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.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General
+Public License instead of this License.
--- /dev/null
+Open issues:
+- grep for TODO and FIXME
+- when shot origin is inside warpzone, vortex shot fails (and is even drawn in totally wrong direction). WHY? Possibly v_forward got lost?
+
+Weapon support:
+
+- blaster: YES
+- shotgun: YES
+- machinegun: YES
+- mortar: YES
+- electro: YES
+- crylink: YES
+- vortex: YES
+- hagar: YES
+- devastator: YES (except for trail bug)
+- porto: YES (bwahahahaha)
+- hlac: YES
+- vaporizer: YES
+- rifle: YES
+- fireball: YES (BFG effect cannot work through warpzones by design, so it's not available through warpzones)
+- hook: YES
+
+- shockwave: NO (does not support warpzones currently)
+- tuba: NO (sound)
--- /dev/null
+#include "anglestransform.qh"
+
+#ifdef POSITIVE_PITCH_IS_DOWN
+vector fixedvectoangles(vector a)
+{
+ vector ang;
+ ang = vectoangles(a);
+ ang.x = -ang.x;
+ return ang;
+}
+vector fixedvectoangles2(vector a, vector b)
+{
+ vector ang;
+ ang = vectoangles2(a, b);
+ ang.x = -ang.x;
+ return ang;
+}
+#else
+void fixedmakevectors(vector a)
+{
+ // a makevectors that actually inverts vectoangles
+ a.x = -a.x;
+ makevectors(a);
+}
+#endif
+
+// angles transforms
+// angles in fixedmakevectors/fixedvectoangles space
+vector AnglesTransform_Apply(vector transform, vector v)
+{
+ fixedmakevectors(transform);
+ return v_forward * v.x
+ + v_right * (-v.y)
+ + v_up * v.z;
+}
+
+vector AnglesTransform_Multiply(vector t1, vector t2)
+{
+ vector m_forward, m_up;
+ fixedmakevectors(t2); m_forward = v_forward; m_up = v_up;
+ m_forward = AnglesTransform_Apply(t1, m_forward); m_up = AnglesTransform_Apply(t1, m_up);
+ return fixedvectoangles2(m_forward, m_up);
+}
+
+vector AnglesTransform_Invert(vector transform)
+{
+ vector i_forward, i_up;
+ fixedmakevectors(transform);
+ // we want angles that turn v_forward into '1 0 0', v_right into '0 1 0' and v_up into '0 0 1'
+ // but these are orthogonal unit vectors!
+ // so to invert, we can simply fixedvectoangles the TRANSPOSED matrix
+ // TODO is this always -transform?
+ i_forward.x = v_forward.x;
+ i_forward.y = -v_right.x;
+ i_forward.z = v_up.x;
+ i_up.x = v_forward.z;
+ i_up.y = -v_right.z;
+ i_up.z = v_up.z;
+ return fixedvectoangles2(i_forward, i_up);
+}
+
+vector AnglesTransform_TurnDirectionFR(vector transform)
+{
+ // turn 180 degrees around v_up
+ // changes in-direction to out-direction
+ //fixedmakevectors(transform);
+ //return fixedvectoangles2(-1 * v_forward, 1 * v_up);
+ transform.x = -transform.x;
+ transform.y = 180 + transform.y;
+ transform.z = -transform.z;
+ // pitch: -s +c
+ // yaw: -s -c
+ // roll: -s +c
+ return transform;
+}
+
+vector AnglesTransform_TurnDirectionFU(vector transform)
+{
+ // turn 180 degrees around v_up
+ // changes in-direction to out-direction
+ //fixedmakevectors(transform);
+ //return fixedvectoangles2(-1 * v_forward, 1 * v_up);
+ transform.x = -transform.x;
+ transform.y = 180 + transform.y;
+ transform.z = 180 - transform.z;
+ return transform;
+}
+
+vector AnglesTransform_RightDivide(vector to_transform, vector from_transform)
+{
+ return AnglesTransform_Multiply(to_transform, AnglesTransform_Invert(from_transform));
+}
+
+vector AnglesTransform_LeftDivide(vector from_transform, vector to_transform)
+{
+ return AnglesTransform_Multiply(AnglesTransform_Invert(from_transform), to_transform);
+}
+
+vector AnglesTransform_Normalize(vector t, float minimize_roll)
+{
+ float need_flip;
+ // first, bring all angles in their range...
+ t.x = t.x - 360 * rint(t.x / 360);
+ t.y = t.y - 360 * rint(t.y / 360);
+ t.z = t.z - 360 * rint(t.z / 360);
+ if(minimize_roll)
+ need_flip = (t.z > 90 || t.z <= -90);
+ else
+ need_flip = (t.x > 90 || t.x < -90); // for pitch we prefer to allow exactly -90 degrees for looking straight down
+ if(need_flip)
+ {
+ if(t.x >= 0) t.x = 180 - t.x; else t.x = -180 - t.x;
+ if(t.y > 0) t.y -= 180; else t.y += 180;
+ if(t.z > 0) t.z -= 180; else t.z += 180;
+ }
+ return t;
+}
+
+vector AnglesTransform_CancelRoll(vector t)
+{
+ const float epsilon = 30;
+ float f;
+
+ // constraints:
+ // forward vector (NOT SO important)
+ // right vector, up vector: screen rotation (MORE important)
+ // choose best match among all pitch-yaw only rotations
+
+ // FIXME find a better method
+
+ f = fabs(t.x - (-90)) / epsilon;
+ if(f < 1)
+ {
+ //t_x = -90;
+ t.y += t.z;
+ t.z = 0;
+ }
+ else
+ {
+ f = fabs(t.x - 90) / epsilon;
+ if(f < 1)
+ {
+ //t_x = 90;
+ t.y -= t.z;
+ t.z = 0;
+ }
+ }
+ return t;
+}
+
+#ifdef POSITIVE_PITCH_IS_DOWN
+vector AnglesTransform_ApplyToAngles(vector transform, vector v)
+{
+ v.x = -v.x;
+ v = AnglesTransform_Multiply(transform, v);
+ v.x = -v.x;
+ return v;
+}
+vector AnglesTransform_ApplyToVAngles(vector transform, vector v)
+{
+ v = AnglesTransform_Multiply(transform, v);
+ return v;
+}
+vector AnglesTransform_FromAngles(vector v)
+{
+ v.x = -v.x;
+ return v;
+}
+vector AnglesTransform_ToAngles(vector v)
+{
+ v.x = -v.x;
+ return v;
+}
+vector AnglesTransform_FromVAngles(vector v)
+{
+ return v;
+}
+vector AnglesTransform_ToVAngles(vector v)
+{
+ return v;
+}
+#else
+vector AnglesTransform_ApplyToAngles(vector transform, vector v)
+{
+ v = AnglesTransform_Multiply(transform, v);
+ return v;
+}
+vector AnglesTransform_ApplyToVAngles(vector transform, vector v)
+{
+ v.x = -v.x;
+ v = AnglesTransform_Multiply(transform, v);
+ v.x = -v.x;
+ return v;
+}
+vector AnglesTransform_FromAngles(vector v)
+{
+ return v;
+}
+vector AnglesTransform_ToAngles(vector v)
+{
+ return v;
+}
+vector AnglesTransform_FromVAngles(vector v)
+{
+ v.x = -v.x;
+ return v;
+}
+vector AnglesTransform_ToVAngles(vector v)
+{
+ v.x = -v.x;
+ return v;
+}
+#endif
+
+vector AnglesTransform_Multiply_GetPostShift(vector t0, vector st0, vector t1, vector st1)
+{
+ // we want the result of:
+ // t0 * (t1 * p + st1) + st0
+ // t0 * t1 * p + t0 * st1 + st0
+ return st0 + AnglesTransform_Apply(t0, st1);
+}
+vector AnglesTransform_PrePostShift_GetPostShift(vector sf, vector t, vector st)
+{
+ return st - AnglesTransform_Apply(t, sf);
+}
--- /dev/null
+#ifndef LIB_WARPZONE_ANGLETRANSFORM_H
+#define LIB_WARPZONE_ANGLETRANSFORM_H
+
+#define POSITIVE_PITCH_IS_DOWN
+
+#ifdef POSITIVE_PITCH_IS_DOWN
+#define fixedmakevectors makevectors
+vector fixedvectoangles(vector a);
+vector fixedvectoangles2(vector a, vector b);
+#else
+void fixedmakevectors(vector a);
+#define fixedvectoangles2 vectoangles2
+#define fixedvectoangles vectoangles
+#endif
+
+vector AnglesTransform_Apply(vector transform, vector v);
+vector AnglesTransform_Multiply(vector t1, vector t2); // A B
+vector AnglesTransform_Invert(vector transform);
+vector AnglesTransform_TurnDirectionFU(vector transform);
+vector AnglesTransform_TurnDirectionFR(vector transform);
+vector AnglesTransform_RightDivide(vector to_transform, vector from_transform); // A B^-1
+vector AnglesTransform_LeftDivide(vector from_transform, vector to_transform); // A^-1 B
+
+vector AnglesTransform_Normalize(vector t, float minimize_roll); // makes sure all angles are in their range: yaw in -180..180, pitch in -90..90, roll in -180..180 (or if minimize_roll is set, pitch in -180..180, roll in -90..90)
+
+vector AnglesTransform_ApplyToAngles(vector transform, vector v);
+vector AnglesTransform_ApplyToVAngles(vector transform, vector v);
+vector AnglesTransform_FromAngles(vector v);
+vector AnglesTransform_ToAngles(vector v);
+vector AnglesTransform_FromVAngles(vector v);
+vector AnglesTransform_ToVAngles(vector v);
+
+// transformed = original * transform + postshift
+vector AnglesTransform_Multiply_GetPostShift(vector sf0, vector st0, vector t1, vector st1);
+vector AnglesTransform_PrePostShift_GetPostShift(vector sf, vector t, vector st);
+#endif
--- /dev/null
+#include "client.qh"
+#include "common.qh"
+
+#if defined(CSQC)
+ #include "../../client/autocvars.qh"
+ #include "../csqcmodel/cl_model.qh"
+#elif defined(MENUQC)
+#elif defined(SVQC)
+#endif
+
+void WarpZone_Fade_PreDraw()
+{SELFPARAM();
+ vector org;
+ org = getpropertyvec(VF_ORIGIN);
+ if(!checkpvs(org, self)) // this makes sense as long as we don't support recursive warpzones
+ self.alpha = 0;
+ else if(self.warpzone_fadestart)
+ self.alpha = bound(0, (self.warpzone_fadeend - vlen(org - self.origin - 0.5 * (self.mins + self.maxs))) / (self.warpzone_fadeend - self.warpzone_fadestart), 1);
+ else
+ self.alpha = 1;
+ //printf("%v <-> %v\n", view_origin, self.origin + 0.5 * (self.mins + self.maxs));
+ if(self.alpha <= 0)
+ self.drawmask = 0;
+ else
+ self.drawmask = MASK_NORMAL;
+}
+
+void WarpZone_Read(float isnew)
+{SELFPARAM();
+ warpzone_warpzones_exist = 1;
+ if (!self.enemy)
+ {
+ self.enemy = spawn();
+ self.enemy.classname = "warpzone_from";
+ }
+ self.classname = "trigger_warpzone";
+
+ int f = ReadByte();
+ self.warpzone_isboxy = (f & 1);
+ if(f & 4)
+ {
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ }
+ else
+ self.origin = '0 0 0';
+ self.modelindex = ReadShort();
+ self.mins_x = ReadCoord();
+ self.mins_y = ReadCoord();
+ self.mins_z = ReadCoord();
+ self.maxs_x = ReadCoord();
+ self.maxs_y = ReadCoord();
+ self.maxs_z = ReadCoord();
+ self.scale = ReadByte() / 16;
+ self.enemy.oldorigin_x = ReadCoord();
+ self.enemy.oldorigin_y = ReadCoord();
+ self.enemy.oldorigin_z = ReadCoord();
+ self.enemy.avelocity_x = ReadCoord();
+ self.enemy.avelocity_y = ReadCoord();
+ self.enemy.avelocity_z = ReadCoord();
+ self.oldorigin_x = ReadCoord();
+ self.oldorigin_y = ReadCoord();
+ self.oldorigin_z = ReadCoord();
+ self.avelocity_x = ReadCoord();
+ self.avelocity_y = ReadCoord();
+ self.avelocity_z = ReadCoord();
+
+ if(f & 2)
+ {
+ self.warpzone_fadestart = ReadShort();
+ self.warpzone_fadeend = max(self.warpzone_fadestart + 1, ReadShort());
+ }
+ else
+ {
+ self.warpzone_fadestart = 0;
+ self.warpzone_fadeend = 0;
+ }
+
+ // common stuff
+ WarpZone_SetUp(self, self.enemy.oldorigin, self.enemy.avelocity, self.oldorigin, self.avelocity);
+
+ // link me
+ //setmodel(self, self.model);
+ setorigin(self, self.origin);
+ setsize(self, self.mins, self.maxs);
+
+ // how to draw
+ // engine currently wants this
+ self.predraw = WarpZone_Fade_PreDraw;
+}
+
+void WarpZone_Camera_Read(float isnew)
+{SELFPARAM();
+ warpzone_cameras_exist = 1;
+ self.classname = "func_warpzone_camera";
+
+ int f = ReadByte();
+ if(f & 4)
+ {
+ self.origin_x = ReadCoord();
+ self.origin_y = ReadCoord();
+ self.origin_z = ReadCoord();
+ }
+ else
+ self.origin = '0 0 0';
+ self.modelindex = ReadShort();
+ self.mins_x = ReadCoord();
+ self.mins_y = ReadCoord();
+ self.mins_z = ReadCoord();
+ self.maxs_x = ReadCoord();
+ self.maxs_y = ReadCoord();
+ self.maxs_z = ReadCoord();
+ self.scale = ReadByte() / 16;
+ self.oldorigin_x = ReadCoord();
+ self.oldorigin_y = ReadCoord();
+ self.oldorigin_z = ReadCoord();
+ self.avelocity_x = ReadCoord();
+ self.avelocity_y = ReadCoord();
+ self.avelocity_z = ReadCoord();
+
+ if(f & 2)
+ {
+ self.warpzone_fadestart = ReadShort();
+ self.warpzone_fadeend = max(self.warpzone_fadestart + 1, ReadShort());
+ }
+ else
+ {
+ self.warpzone_fadestart = 0;
+ self.warpzone_fadeend = 0;
+ }
+
+ // common stuff
+ WarpZone_Camera_SetUp(self, self.oldorigin, self.avelocity);
+
+ // engine currently wants this
+ self.drawmask = MASK_NORMAL;
+
+ // link me
+ //setmodel(self, self.model);
+ setorigin(self, self.origin);
+ setsize(self, self.mins, self.maxs);
+
+ // how to draw
+ // engine currently wants this
+ self.predraw = WarpZone_Fade_PreDraw;
+}
+
+void CL_RotateMoves(vector ang) = #638;
+void WarpZone_Teleported_Read(float isnew)
+{SELFPARAM();
+ vector v;
+ self.classname = "warpzone_teleported";
+ v.x = ReadCoord();
+ v.y = ReadCoord();
+ v.z = ReadCoord();
+ if(!isnew)
+ return;
+ self.warpzone_transform = v;
+ setproperty(VF_CL_VIEWANGLES, WarpZone_TransformVAngles(self, getpropertyvec(VF_CL_VIEWANGLES)));
+ if(checkextension("DP_CSQC_ROTATEMOVES"))
+ CL_RotateMoves(v);
+ //CL_RotateMoves('0 90 0');
+}
+
+float warpzone_fixingview;
+float warpzone_fixingview_drawexteriormodel;
+
+void WarpZone_View_Outside()
+{
+ if(!warpzone_fixingview)
+ return;
+ warpzone_fixingview = 0;
+ cvar_set("r_drawexteriormodel", ftos(warpzone_fixingview_drawexteriormodel));
+}
+
+void WarpZone_View_Inside()
+{
+ if(autocvar_chase_active)
+ {
+ WarpZone_View_Outside();
+ return;
+ }
+ if(warpzone_fixingview)
+ return;
+ warpzone_fixingview = 1;
+ warpzone_fixingview_drawexteriormodel = cvar("r_drawexteriormodel");
+ cvar_set("r_drawexteriormodel", "0");
+}
+
+vector WarpZone_FixNearClip(vector o, vector c0, vector c1, vector c2, vector c3)
+{
+ vector mi, ma;
+ entity e;
+ float pd;
+
+ mi.x = min(o.x, c0_x, c1_x, c2_x, c3_x);
+ ma.x = max(o.x, c0_x, c1_x, c2_x, c3_x);
+ mi.y = min(o.y, c0_y, c1_y, c2_y, c3_y);
+ ma.y = max(o.y, c0_y, c1_y, c2_y, c3_y);
+ mi.z = min(o.z, c0_z, c1_z, c2_z, c3_z);
+ ma.z = max(o.z, c0_z, c1_z, c2_z, c3_z);
+
+ e = WarpZone_Find(mi, ma);
+ if(e)
+ {
+ if(WarpZone_PlaneDist(e, o) < 0)
+ return '0 0 0';
+ // can't really be, though, but if it is, this is not my warpzone, but a random different one in the same mins/maxs
+ pd = min(
+ WarpZone_PlaneDist(e, c0),
+ WarpZone_PlaneDist(e, c1),
+ WarpZone_PlaneDist(e, c2),
+ WarpZone_PlaneDist(e, c3)
+ );
+ if(pd < 0)
+ return e.warpzone_forward * -pd;
+ }
+
+ return '0 0 0';
+}
+
+void WarpZone_FixPMove()
+{
+ entity e;
+ e = WarpZone_Find(pmove_org, pmove_org);
+ if(e)
+ {
+ pmove_org = WarpZone_TransformOrigin(e, pmove_org);
+ input_angles = WarpZone_TransformVAngles(e, input_angles);
+ }
+}
+
+#ifndef KEEP_ROLL
+float autocvar_cl_rollkillspeed = 10;
+#endif
+void WarpZone_FixView()
+{
+ entity e;
+ vector org, ang, nearclip, corner0, corner1, corner2, corner3, o;
+ float f;
+
+ warpzone_save_view_origin = org = getpropertyvec(VF_ORIGIN);
+ warpzone_save_view_angles = ang = getpropertyvec(VF_ANGLES);
+
+ e = WarpZone_Find(org, org);
+ if(e)
+ {
+ org = WarpZone_TransformOrigin(e, org);
+ ang = WarpZone_TransformVAngles(e, ang);
+ WarpZone_View_Inside();
+ }
+ else
+ WarpZone_View_Outside();
+
+#ifndef KEEP_ROLL
+ float rick;
+ if(autocvar_cl_rollkillspeed)
+ f = max(0, (1 - frametime * autocvar_cl_rollkillspeed));
+ else
+ f = 0;
+
+ rick = getproperty(VF_CL_VIEWANGLES_Z);
+ rick *= f;
+ setproperty(VF_CL_VIEWANGLES_Z, rick);
+ ang.z *= f;
+#endif
+
+ setproperty(VF_ORIGIN, org);
+ setproperty(VF_ANGLES, ang);
+
+ nearclip = '0 0 1' * (cvar("r_nearclip") * 1.125);
+ corner0 = cs_unproject('0 0 0' + nearclip);
+ corner1 = cs_unproject('1 0 0' * cvar("vid_conwidth") + nearclip);
+ corner2 = cs_unproject('0 1 0' * cvar("vid_conheight") + nearclip);
+ corner3 = cs_unproject('1 0 0' * cvar("vid_conwidth") + '0 1 0' * cvar("vid_conheight") + nearclip);
+ o = WarpZone_FixNearClip(org, corner0, corner1, corner2, corner3);
+ if(o != '0 0 0')
+ setproperty(VF_ORIGIN, org + o);
+}
+
+void WarpZone_Init()
+{
+}
+
+void WarpZone_Shutdown()
+{
+ WarpZone_View_Outside();
+}
--- /dev/null
+#ifndef LIB_WARPZONE_CLIENT_H
+#define LIB_WARPZONE_CLIENT_H
+
+void WarpZone_Read(float bIsNewEntity);
+void WarpZone_Camera_Read(float bIsNewEntity);
+void WarpZone_Teleported_Read(float bIsNewEntity);
+
+void WarpZone_FixPMove();
+void WarpZone_FixView();
+
+void WarpZone_Init();
+void WarpZone_Shutdown();
+
+vector warpzone_save_view_origin;
+vector warpzone_save_view_angles;
+#endif
--- /dev/null
+#include "common.qh"
+
+#if defined(CSQC)
+ #include "../../server/t_items.qh"
+#elif defined(MENUQC)
+#elif defined(SVQC)
+ #include "../../common/weapons/all.qh"
+#endif
+
+void WarpZone_Accumulator_Clear(entity acc)
+{
+ acc.warpzone_transform = '0 0 0';
+ acc.warpzone_shift = '0 0 0';
+}
+void WarpZone_Accumulator_AddTransform(entity acc, vector t, vector s)
+{
+ vector tr, st;
+ tr = AnglesTransform_Multiply(t, acc.warpzone_transform);
+ st = AnglesTransform_Multiply_GetPostShift(t, s, acc.warpzone_transform, acc.warpzone_shift);
+ acc.warpzone_transform = tr;
+ acc.warpzone_shift = st;
+}
+void WarpZone_Accumulator_Add(entity acc, entity wz)
+{
+ WarpZone_Accumulator_AddTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
+}
+void WarpZone_Accumulator_AddInverseTransform(entity acc, vector t, vector s)
+{
+ vector tt, ss;
+ tt = AnglesTransform_Invert(t);
+ ss = AnglesTransform_PrePostShift_GetPostShift(s, tt, '0 0 0');
+ WarpZone_Accumulator_AddTransform(acc, tt, ss);
+ // yes, this probably can be done simpler... but this way is "obvious" :)
+}
+void WarpZone_Accumulator_AddInverse(entity acc, entity wz)
+{
+ WarpZone_Accumulator_AddInverseTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
+}
+
+.vector(vector, vector) camera_transform;
+float autocvar_cl_warpzone_usetrace = 1;
+vector WarpZone_camera_transform(vector org, vector ang)
+{SELFPARAM();
+ vector vf, vr, vu;
+ if(self.warpzone_fadestart)
+ if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400)
+ return org;
+ // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
+ // unneeded on client, on server this helps a lot
+ vf = v_forward;
+ vr = v_right;
+ vu = v_up;
+ org = WarpZone_TransformOrigin(self, org);
+ vf = WarpZone_TransformVelocity(self, vf);
+ vr = WarpZone_TransformVelocity(self, vr);
+ vu = WarpZone_TransformVelocity(self, vu);
+ if(autocvar_cl_warpzone_usetrace)
+ traceline(self.warpzone_targetorigin, org, MOVE_NOMONSTERS, world);
+ else
+ trace_endpos = self.warpzone_targetorigin;
+ v_forward = vf;
+ v_right = vr;
+ v_up = vu;
+ return org;
+}
+
+void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang)
+{
+ e.warpzone_transform = AnglesTransform_RightDivide(other_ang, AnglesTransform_TurnDirectionFR(my_ang));
+ e.warpzone_shift = AnglesTransform_PrePostShift_GetPostShift(my_org, e.warpzone_transform, other_org);
+ e.warpzone_origin = my_org;
+ e.warpzone_targetorigin = other_org;
+ e.warpzone_angles = my_ang;
+ e.warpzone_targetangles = other_ang;
+ fixedmakevectors(my_ang); e.warpzone_forward = v_forward;
+ fixedmakevectors(other_ang); e.warpzone_targetforward = v_forward;
+ e.camera_transform = WarpZone_camera_transform;
+}
+
+vector WarpZone_Camera_camera_transform(vector org, vector ang)
+{SELFPARAM();
+ // a fixed camera view
+ if(self.warpzone_fadestart)
+ if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400)
+ return org;
+ // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
+ // unneeded on client, on server this helps a lot
+ trace_endpos = self.warpzone_origin;
+ makevectors(self.warpzone_angles);
+ return self.warpzone_origin;
+}
+
+void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang) // we assume that e.oldorigin and e.avelocity point to view origin and direction
+{
+ e.warpzone_origin = my_org;
+ e.warpzone_angles = my_ang;
+ e.camera_transform = WarpZone_Camera_camera_transform;
+}
+
+.entity enemy;
+
+vector WarpZoneLib_BoxTouchesBrush_mins;
+vector WarpZoneLib_BoxTouchesBrush_maxs;
+entity WarpZoneLib_BoxTouchesBrush_ent;
+entity WarpZoneLib_BoxTouchesBrush_ignore;
+float WarpZoneLib_BoxTouchesBrush_Recurse()
+{
+ float s;
+ entity se;
+ float f;
+
+ tracebox('0 0 0', WarpZoneLib_BoxTouchesBrush_mins, WarpZoneLib_BoxTouchesBrush_maxs, '0 0 0', MOVE_NOMONSTERS, WarpZoneLib_BoxTouchesBrush_ignore);
+#ifdef CSQC
+ if (trace_networkentity)
+ {
+ LOG_TRACE("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush\n");
+ // we cannot continue, as a player blocks us...
+ // so, abort
+ return 0;
+ }
+#endif
+ if (!trace_ent)
+ return 0;
+ if (trace_ent == WarpZoneLib_BoxTouchesBrush_ent)
+ return 1;
+
+ se = trace_ent;
+ s = se.solid;
+ se.solid = SOLID_NOT;
+ f = WarpZoneLib_BoxTouchesBrush_Recurse();
+ se.solid = s;
+
+ return f;
+}
+
+float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
+{
+ float f, s;
+
+ if(!e.modelindex || e.warpzone_isboxy)
+ return 1;
+
+ s = e.solid;
+ e.solid = SOLID_BSP;
+ WarpZoneLib_BoxTouchesBrush_mins = mi;
+ WarpZoneLib_BoxTouchesBrush_maxs = ma;
+ WarpZoneLib_BoxTouchesBrush_ent = e;
+ WarpZoneLib_BoxTouchesBrush_ignore = ig;
+ f = WarpZoneLib_BoxTouchesBrush_Recurse();
+ e.solid = s;
+
+ return f;
+}
+
+entity WarpZone_Find(vector mi, vector ma)
+{
+ // if we are near any warpzone planes - MOVE AWAY (work around nearclip)
+ entity e;
+ if(!warpzone_warpzones_exist)
+ return world;
+ for(e = world; (e = find(e, classname, "trigger_warpzone")); )
+ if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world))
+ return e;
+ return world;
+}
+
+void WarpZone_MakeAllSolid()
+{
+ entity e;
+ if(!warpzone_warpzones_exist)
+ return;
+ for(e = world; (e = find(e, classname, "trigger_warpzone")); )
+ e.solid = SOLID_BSP;
+}
+
+void WarpZone_MakeAllOther()
+{
+ entity e;
+ if(!warpzone_warpzones_exist)
+ return;
+ for(e = world; (e = find(e, classname, "trigger_warpzone")); )
+ e.solid = SOLID_TRIGGER;
+}
+
+void WarpZone_Trace_InitTransform()
+{
+ if(!WarpZone_trace_transform)
+ {
+ WarpZone_trace_transform = spawn();
+ WarpZone_trace_transform.classname = "warpzone_trace_transform";
+ }
+ WarpZone_Accumulator_Clear(WarpZone_trace_transform);
+}
+void WarpZone_Trace_AddTransform(entity wz)
+{
+ WarpZone_Accumulator_Add(WarpZone_trace_transform, wz);
+}
+
+void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent, entity zone, WarpZone_trace_callback_t cb)
+{
+ float nomonsters_adjusted;
+ float frac, sol, i;
+ float contentshack;
+ vector o0, e0;
+ entity wz;
+ vector vf, vr, vu;
+
+ WarpZone_trace_forent = forent;
+ WarpZone_trace_firstzone = world;
+ WarpZone_trace_lastzone = world;
+ WarpZone_Trace_InitTransform();
+ if(!warpzone_warpzones_exist)
+ {
+ if(nomonsters == MOVE_NOTHING)
+ {
+ trace_endpos = end;
+ trace_fraction = 1;
+ if(cb)
+ cb(org, trace_endpos, end);
+ return;
+ }
+ else
+ {
+ tracebox(org, mi, ma, end, nomonsters, WarpZone_trace_forent);
+ if(cb)
+ cb(org, trace_endpos, end);
+ return;
+ }
+ }
+
+ vf = v_forward;
+ vr = v_right;
+ vu = v_up;
+ o0 = org;
+ e0 = end;
+
+ switch(nomonsters)
+ {
+ case MOVE_WORLDONLY:
+ case MOVE_NOTHING:
+ nomonsters_adjusted = MOVE_NOMONSTERS;
+ break;
+ default:
+ nomonsters_adjusted = nomonsters;
+ break;
+ }
+ if((contentshack = (WarpZone_trace_forent.dphitcontentsmask && !(WarpZone_trace_forent.dphitcontentsmask & DPCONTENTS_SOLID))))
+ BITSET_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
+
+ // if starting in warpzone, first transform
+ wz = WarpZone_Find(org + mi, org + ma);
+ if(wz)
+ {
+ WarpZone_trace_firstzone = wz;
+ WarpZone_trace_lastzone = wz;
+ if(zone && wz != zone)
+ {
+ // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
+ sol = 1;
+ trace_fraction = 0;
+ trace_endpos = org;
+ goto fail;
+ }
+ WarpZone_Trace_AddTransform(wz);
+ org = WarpZone_TransformOrigin(wz, org);
+ end = WarpZone_TransformOrigin(wz, end);
+ }
+ WarpZone_MakeAllSolid();
+ sol = -1;
+ frac = 0;
+ i = 16;
+ for (;;)
+ {
+ if(--i < 1)
+ {
+ LOG_TRACE("Too many warpzones in sequence, aborting trace.\n");
+ trace_ent = world;
+ break;
+ }
+ tracebox(org, mi, ma, end, nomonsters_adjusted, WarpZone_trace_forent);
+ if(cb)
+ cb(org, trace_endpos, end);
+ if(sol < 0)
+ sol = trace_startsolid;
+
+ frac = trace_fraction = frac + (1 - frac) * trace_fraction;
+ if(trace_fraction >= 1)
+ break;
+ if(trace_ent.classname != "trigger_warpzone")
+ {
+ if((nomonsters == MOVE_NOTHING) || ((nomonsters == MOVE_WORLDONLY) && trace_ent) || (contentshack && (trace_dphitcontents & WarpZone_trace_forent.dphitcontentsmask) == DPCONTENTS_SOLID))
+ {
+ // continue the trace, ignoring this hit (we only care for warpzones)
+ org = trace_endpos + normalize(end - org);
+ continue;
+ // we cannot do an inverted trace here, as we do care for further warpzones inside that "solid" to be found
+ // otherwise, players could block entrances that way
+ }
+ break;
+ }
+ if(trace_ent == wz)
+ {
+ // FIXME can this check be removed? Do we really need it?
+ LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace\n");
+ trace_ent = world;
+ break;
+ }
+ wz = trace_ent;
+ if(!WarpZone_trace_firstzone)
+ WarpZone_trace_firstzone = wz;
+ WarpZone_trace_lastzone = wz;
+ if(zone && wz != zone)
+ break;
+ WarpZone_Trace_AddTransform(wz);
+ // we hit a warpzone... so, let's perform the trace after the warp again
+ org = WarpZone_TransformOrigin(wz, trace_endpos);
+ end = WarpZone_TransformOrigin(wz, end);
+
+ // we got warped, so let's step back a bit
+ tracebox(org, mi, ma, org + normalize(org - end) * 32, nomonsters_adjusted, WarpZone_trace_forent);
+ org = trace_endpos;
+ }
+ WarpZone_MakeAllOther();
+:fail
+ if(contentshack)
+ BITCLR_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
+ trace_startsolid = sol;
+ v_forward = vf;
+ v_right = vr;
+ v_up = vu;
+}
+
+void WarpZone_TraceBox(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent)
+{
+ WarpZone_TraceBox_ThroughZone(org, mi, ma, end, nomonsters, forent, world, WarpZone_trace_callback_t_null);
+}
+
+void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
+{
+ WarpZone_TraceBox(org, '0 0 0', '0 0 0', end, nomonsters, forent);
+}
+
+void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZone_trace_callback_t cb)
+{
+ float g, dt, i;
+ vector vf, vr, vu, v0, o0;
+ entity wz;
+
+ o0 = e.origin;
+ v0 = e.velocity;
+ g = cvar("sv_gravity") * e.gravity;
+
+ WarpZone_trace_forent = forent;
+ WarpZone_trace_firstzone = world;
+ WarpZone_trace_lastzone = world;
+ WarpZone_Trace_InitTransform();
+ WarpZone_tracetoss_time = 0;
+ if(!warpzone_warpzones_exist)
+ {
+ tracetoss(e, WarpZone_trace_forent);
+ if(cb)
+ cb(e.origin, trace_endpos, trace_endpos);
+ dt = vlen(e.origin - o0) / vlen(e.velocity);
+ WarpZone_tracetoss_time += dt;
+ e.velocity_z -= dt * g;
+ WarpZone_tracetoss_velocity = e.velocity;
+ e.velocity = v0;
+ return;
+ }
+
+ vf = v_forward;
+ vr = v_right;
+ vu = v_up;
+
+ // if starting in warpzone, first transform
+ wz = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs);
+ if(wz)
+ {
+ WarpZone_trace_firstzone = wz;
+ WarpZone_trace_lastzone = wz;
+ if(zone && wz != zone)
+ {
+ // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
+
+ WarpZone_tracetoss_time = 0;
+ trace_endpos = o0;
+ goto fail;
+ }
+ WarpZone_Trace_AddTransform(wz);
+ setorigin(e, WarpZone_TransformOrigin(wz, e.origin));
+ e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
+ }
+ WarpZone_MakeAllSolid();
+ i = 16;
+ for (;;)
+ {
+ if(--i < 1)
+ {
+ LOG_TRACE("Too many warpzones in sequence, aborting trace.\n");
+ trace_ent = world;
+ break;
+ }
+ tracetoss(e, WarpZone_trace_forent);
+ if(cb)
+ cb(e.origin, trace_endpos, trace_endpos);
+ dt = vlen(trace_endpos - e.origin) / vlen(e.velocity);
+ WarpZone_tracetoss_time += dt;
+ e.origin = trace_endpos;
+ e.velocity_z -= dt * g;
+ if(trace_fraction >= 1)
+ break;
+ if(trace_ent.classname != "trigger_warpzone")
+ break;
+ if(trace_ent == wz)
+ {
+ // FIXME can this check be removed? Do we really need it?
+ LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace\n");
+ trace_ent = world;
+ break;
+ }
+ wz = trace_ent;
+ if(!WarpZone_trace_firstzone)
+ WarpZone_trace_firstzone = wz;
+ WarpZone_trace_lastzone = wz;
+ if(zone && wz != zone)
+ break;
+ WarpZone_Trace_AddTransform(wz);
+ // we hit a warpzone... so, let's perform the trace after the warp again
+ e.origin = WarpZone_TransformOrigin(wz, e.origin);
+ e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
+
+ // we got warped, so let's step back a bit
+ e.velocity = -e.velocity;
+ tracetoss(e, WarpZone_trace_forent);
+ dt = vlen(trace_endpos - e.origin) / vlen(e.velocity);
+ WarpZone_tracetoss_time -= dt;
+ e.origin = trace_endpos;
+ e.velocity = -e.velocity;
+ }
+ WarpZone_MakeAllOther();
+:fail
+ WarpZone_tracetoss_velocity = e.velocity;
+ v_forward = vf;
+ v_right = vr;
+ v_up = vu;
+ // restore old entity data (caller just uses trace_endpos, WarpZone_tracetoss_velocity and the transform)
+ e.velocity = v0;
+ e.origin = o0;
+}
+
+void WarpZone_TraceToss(entity e, entity forent)
+{
+ WarpZone_TraceToss_ThroughZone(e, forent, world, WarpZone_trace_callback_t_null);
+}
+
+entity WarpZone_TrailParticles_trace_callback_own;
+float WarpZone_TrailParticles_trace_callback_eff;
+void WarpZone_TrailParticles_trace_callback(vector from, vector endpos, vector to)
+{
+ trailparticles(WarpZone_TrailParticles_trace_callback_own, WarpZone_TrailParticles_trace_callback_eff, from, endpos);
+}
+
+void WarpZone_TrailParticles(entity own, float eff, vector org, vector end)
+{
+ WarpZone_TrailParticles_trace_callback_own = own;
+ WarpZone_TrailParticles_trace_callback_eff = eff;
+ WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_trace_callback);
+}
+
+#ifdef CSQC
+float WarpZone_TrailParticles_trace_callback_f;
+float WarpZone_TrailParticles_trace_callback_flags;
+void WarpZone_TrailParticles_WithMultiplier_trace_callback(vector from, vector endpos, vector to)
+{
+ boxparticles(WarpZone_TrailParticles_trace_callback_eff, WarpZone_TrailParticles_trace_callback_own, from, endpos, WarpZone_TrailParticles_trace_callback_own.velocity, WarpZone_TrailParticles_trace_callback_own.velocity, WarpZone_TrailParticles_trace_callback_f, WarpZone_TrailParticles_trace_callback_flags);
+}
+
+void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, int boxflags)
+{
+ WarpZone_TrailParticles_trace_callback_own = own;
+ WarpZone_TrailParticles_trace_callback_eff = eff;
+ WarpZone_TrailParticles_trace_callback_f = f;
+ WarpZone_TrailParticles_trace_callback_flags = boxflags | PARTICLES_DRAWASTRAIL;
+ WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_WithMultiplier_trace_callback);
+}
+#endif
+
+float WarpZone_PlaneDist(entity wz, vector v)
+{
+ return (v - wz.warpzone_origin) * wz.warpzone_forward;
+}
+
+float WarpZone_TargetPlaneDist(entity wz, vector v)
+{
+ return (v - wz.warpzone_targetorigin) * wz.warpzone_targetforward;
+}
+
+vector WarpZone_TransformOrigin(entity wz, vector v)
+{
+ return wz.warpzone_shift + AnglesTransform_Apply(wz.warpzone_transform, v);
+}
+
+vector WarpZone_TransformVelocity(entity wz, vector v)
+{
+ return AnglesTransform_Apply(wz.warpzone_transform, v);
+}
+
+vector WarpZone_TransformAngles(entity wz, vector v)
+{
+ return AnglesTransform_ApplyToAngles(wz.warpzone_transform, v);
+}
+
+vector WarpZone_TransformVAngles(entity wz, vector ang)
+{
+#ifdef KEEP_ROLL
+ float roll;
+ roll = ang.z;
+ ang.z = 0;
+#endif
+
+ ang = AnglesTransform_ApplyToVAngles(wz.warpzone_transform, ang);
+
+#ifdef KEEP_ROLL
+ ang = AnglesTransform_Normalize(ang, true);
+ ang = AnglesTransform_CancelRoll(ang);
+ ang.z = roll;
+#else
+ ang = AnglesTransform_Normalize(ang, false);
+#endif
+
+ return ang;
+}
+
+vector WarpZone_UnTransformOrigin(entity wz, vector v)
+{
+ return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v - wz.warpzone_shift);
+}
+
+vector WarpZone_UnTransformVelocity(entity wz, vector v)
+{
+ return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v);
+}
+
+vector WarpZone_UnTransformAngles(entity wz, vector v)
+{
+ return AnglesTransform_ApplyToAngles(AnglesTransform_Invert(wz.warpzone_transform), v);
+}
+
+vector WarpZone_UnTransformVAngles(entity wz, vector ang)
+{
+ float roll;
+
+ roll = ang.z;
+ ang.z = 0;
+
+ ang = AnglesTransform_ApplyToVAngles(AnglesTransform_Invert(wz.warpzone_transform), ang);
+ ang = AnglesTransform_Normalize(ang, true);
+ ang = AnglesTransform_CancelRoll(ang);
+
+ ang.z = roll;
+ return ang;
+}
+
+vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org)
+{
+ vector nearest;
+ nearest.x = bound(mi.x, org.x, ma.x);
+ nearest.y = bound(mi.y, org.y, ma.y);
+ nearest.z = bound(mi.z, org.z, ma.z);
+ return nearest;
+}
+
+bool WarpZoneLib_BadEntity(entity e)
+{
+ string myclassname = e.classname;
+ if (e.instanceOfObject) return true;
+ switch(myclassname)
+ {
+ case "deathtype":
+ case "weaponentity":
+ case "exteriorweaponentity":
+ case "csqc_score_team":
+ case "pingplreport":
+ case "ent_client_scoreinfo":
+ case "saved_cvar_value":
+ case "accuracy":
+ case "entcs_sender":
+ case "entcs_receiver":
+ case "clientinit":
+ case "sprite_waypoint":
+ case "waypoint":
+ case "gibsplash":
+ //case "net_linked": // actually some real entities are linked without classname, fail
+ case "":
+ return true;
+ }
+
+ if(startsWith(myclassname, "msg_"))
+ return true;
+
+ if(startsWith(myclassname, "target_"))
+ return true;
+
+ if(startsWith(myclassname, "info_"))
+ return true;
+
+ return false;
+}
+
+.float WarpZone_findradius_hit;
+.entity WarpZone_findradius_next;
+void WarpZone_FindRadius_Recurse(vector org, float rad, vector org0, vector transform, vector shift, float needlineofsight)
+// blast origin of current search original blast origin how to untransform (victim to blast system)
+{
+ vector org_new;
+ vector org0_new;
+ vector shift_new, transform_new;
+ vector p;
+ entity e, e0;
+ entity wz;
+ if(rad <= 0)
+ return;
+ e0 = findradius(org, rad);
+ wz = world;
+
+ for(e = e0; e; e = e.chain)
+ {
+ if(WarpZoneLib_BadEntity(e))
+ continue;
+ p = WarpZoneLib_NearestPointOnBox(e.origin + e.mins, e.origin + e.maxs, org0);
+ if(needlineofsight)
+ {
+ traceline(org, p, MOVE_NOMONSTERS, e);
+ if(trace_fraction < 1)
+ continue;
+ }
+ if(!e.WarpZone_findradius_hit || vlen(e.WarpZone_findradius_dist) > vlen(org0 - p))
+ {
+ e.WarpZone_findradius_nearest = p;
+ e.WarpZone_findradius_dist = org0 - p;
+ e.WarpZone_findradius_findorigin = org;
+ e.WarpZone_findradius_findradius = rad;
+ if(e.classname == "warpzone_refsys")
+ {
+ // ignore, especially: do not overwrite the refsys parameters
+ }
+ else if(e.classname == "trigger_warpzone")
+ {
+ e.WarpZone_findradius_next = wz;
+ wz = e;
+ e.WarpZone_findradius_hit = 1;
+ e.enemy.WarpZone_findradius_dist = '0 0 0'; // we don't want to go through this zone ever again
+ e.enemy.WarpZone_findradius_hit = 1;
+ }
+ else
+ {
+ e.warpzone_transform = transform;
+ e.warpzone_shift = shift;
+ e.WarpZone_findradius_hit = 1;
+ }
+ }
+ }
+ for(e = wz; e; e = e.WarpZone_findradius_next)
+ {
+ if(WarpZoneLib_BadEntity(e))
+ continue;
+
+ org0_new = WarpZone_TransformOrigin(e, org);
+ traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
+ org_new = trace_endpos;
+
+ transform_new = AnglesTransform_Multiply(e.warpzone_transform, transform);
+ shift_new = AnglesTransform_Multiply_GetPostShift(e.warpzone_transform, e.warpzone_shift, transform, shift);
+ WarpZone_FindRadius_Recurse(
+ org_new,
+ bound(0, rad - vlen(org_new - org0_new), rad - 8),
+ org0_new,
+ transform_new, shift_new,
+ needlineofsight);
+ e.WarpZone_findradius_hit = 0;
+ e.enemy.WarpZone_findradius_hit = 0;
+ }
+}
+entity WarpZone_FindRadius(vector org, float rad, float needlineofsight)
+{
+ entity e0, e;
+ WarpZone_FindRadius_Recurse(org, rad, org, '0 0 0', '0 0 0', needlineofsight);
+ e0 = findchainfloat(WarpZone_findradius_hit, 1);
+ for(e = e0; e; e = e.chain)
+ e.WarpZone_findradius_hit = 0;
+ return e0;
+}
+
+.entity WarpZone_refsys;
+void WarpZone_RefSys_GC()
+{SELFPARAM();
+ // garbage collect unused reference systems
+ self.nextthink = time + 1;
+ if(self.owner.WarpZone_refsys != self)
+ remove(self);
+}
+void WarpZone_RefSys_CheckCreate(entity me)
+{
+ if(me.WarpZone_refsys.owner != me)
+ {
+ me.WarpZone_refsys = spawn();
+ me.WarpZone_refsys.classname = "warpzone_refsys";
+ me.WarpZone_refsys.owner = me;
+ me.WarpZone_refsys.think = WarpZone_RefSys_GC;
+ me.WarpZone_refsys.nextthink = time + 1;
+ WarpZone_Accumulator_Clear(me.WarpZone_refsys);
+ }
+}
+void WarpZone_RefSys_Clear(entity me)
+{
+ if(me.WarpZone_refsys)
+ {
+ remove(me.WarpZone_refsys);
+ me.WarpZone_refsys = world;
+ }
+}
+void WarpZone_RefSys_AddTransform(entity me, vector t, vector s)
+{
+ if(t != '0 0 0' || s != '0 0 0')
+ {
+ WarpZone_RefSys_CheckCreate(me);
+ WarpZone_Accumulator_AddTransform(me.WarpZone_refsys, t, s);
+ }
+}
+void WarpZone_RefSys_Add(entity me, entity wz)
+{
+ WarpZone_RefSys_AddTransform(me, wz.warpzone_transform, wz.warpzone_shift);
+}
+void WarpZone_RefSys_AddInverseTransform(entity me, vector t, vector s)
+{
+ if(t != '0 0 0' || s != '0 0 0')
+ {
+ WarpZone_RefSys_CheckCreate(me);
+ WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, t, s);
+ }
+}
+void WarpZone_RefSys_AddInverse(entity me, entity wz)
+{
+ WarpZone_RefSys_AddInverseTransform(me, wz.warpzone_transform, wz.warpzone_shift);
+}
+.vector WarpZone_refsys_incremental_shift;
+.vector WarpZone_refsys_incremental_transform;
+void WarpZone_RefSys_AddIncrementally(entity me, entity ref)
+{
+ //vector t, s;
+ if(me.WarpZone_refsys_incremental_transform == ref.WarpZone_refsys.warpzone_transform)
+ if(me.WarpZone_refsys_incremental_shift == ref.WarpZone_refsys.warpzone_shift)
+ return;
+ WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, me.WarpZone_refsys_incremental_transform, me.WarpZone_refsys_incremental_shift);
+ WarpZone_Accumulator_Add(me.WarpZone_refsys, ref.WarpZone_refsys);
+ me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
+ me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
+}
+void WarpZone_RefSys_BeginAddingIncrementally(entity me, entity ref)
+{
+ me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
+ me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
+}
+vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
+{
+ if(from.WarpZone_refsys)
+ org = WarpZone_UnTransformOrigin(from.WarpZone_refsys, org);
+ if(to.WarpZone_refsys)
+ org = WarpZone_TransformOrigin(to.WarpZone_refsys, org);
+ return org;
+}
+vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
+{
+ if(from.WarpZone_refsys)
+ vel = WarpZone_UnTransformVelocity(from.WarpZone_refsys, vel);
+ if(to.WarpZone_refsys)
+ vel = WarpZone_TransformVelocity(to.WarpZone_refsys, vel);
+ return vel;
+}
+vector WarpZone_RefSys_TransformAngles(entity from, entity to, vector ang)
+{
+ if(from.WarpZone_refsys)
+ ang = WarpZone_UnTransformAngles(from.WarpZone_refsys, ang);
+ if(to.WarpZone_refsys)
+ ang = WarpZone_TransformAngles(to.WarpZone_refsys, ang);
+ return ang;
+}
+vector WarpZone_RefSys_TransformVAngles(entity from, entity to, vector ang)
+{
+ if(from.WarpZone_refsys)
+ ang = WarpZone_UnTransformVAngles(from.WarpZone_refsys, ang);
+ if(to.WarpZone_refsys)
+ ang = WarpZone_TransformVAngles(to.WarpZone_refsys, ang);
+ return ang;
+}
+void WarpZone_RefSys_Copy(entity me, entity from)
+{
+ if(from.WarpZone_refsys)
+ {
+ WarpZone_RefSys_CheckCreate(me);
+ me.WarpZone_refsys.warpzone_shift = from.WarpZone_refsys.warpzone_shift;
+ me.WarpZone_refsys.warpzone_transform = from.WarpZone_refsys.warpzone_transform;
+ }
+ else
+ WarpZone_RefSys_Clear(me);
+}
+entity WarpZone_RefSys_SpawnSameRefSys(entity me)
+{
+ entity e;
+ e = spawn();
+ WarpZone_RefSys_Copy(e, me);
+ return e;
+}
+
+float WarpZoneLib_ExactTrigger_Touch()
+{SELFPARAM();
+ return !WarpZoneLib_BoxTouchesBrush(other.absmin, other.absmax, self, other);
+}
+
+
+void WarpZoneLib_MoveOutOfSolid_Expand(entity e, vector by)
+{
+ float eps = 0.0625;
+ tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
+ if (trace_startsolid)
+ return;
+ if (trace_fraction < 1)
+ {
+ // hit something
+ // adjust origin in the other direction...
+ setorigin(e,e.origin - by * (1 - trace_fraction));
+ }
+}
+
+float WarpZoneLib_MoveOutOfSolid(entity e)
+{
+ vector o, m0, m1;
+
+ o = e.origin;
+ traceline(o, o, MOVE_WORLDONLY, e);
+ if (trace_startsolid)
+ return false;
+
+ tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
+ if (!trace_startsolid)
+ return true;
+
+ m0 = e.mins;
+ m1 = e.maxs;
+ e.mins = '0 0 0';
+ e.maxs = '0 0 0';
+ WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m0_x);
+ e.mins_x = m0_x;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m1_x);
+ e.maxs_x = m1_x;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m0_y);
+ e.mins_y = m0_y;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m1_y);
+ e.maxs_y = m1_y;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m0_z);
+ e.mins_z = m0_z;
+ WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m1_z);
+ e.maxs_z = m1_z;
+ setorigin(e, e.origin);
+
+ tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
+ if (trace_startsolid)
+ {
+ setorigin(e, o);
+ return false;
+ }
+
+ return true;
+}
--- /dev/null
+#ifndef LIB_WARPZONE_COMMON_H
+#define LIB_WARPZONE_COMMON_H
+
+// uncomment this if your mod uses the roll angle in fixangle
+// #define KEEP_ROLL
+
+float warpzone_warpzones_exist;
+float warpzone_cameras_exist;
+
+.float warpzone_isboxy;
+.vector warpzone_shift;
+.vector warpzone_origin;
+.vector warpzone_angles;
+.vector warpzone_forward;
+.vector warpzone_targetorigin;
+.vector warpzone_targetangles;
+.vector warpzone_targetforward;
+.vector warpzone_transform;
+.float warpzone_fadestart;
+.float warpzone_fadeend;
+void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang);
+void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang);
+
+float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig);
+vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org);
+
+entity WarpZone_Find(vector mi, vector ma);
+void WarpZone_MakeAllSolid();
+void WarpZone_MakeAllOther();
+
+#define MOVE_NOTHING -1
+entity WarpZone_trace_forent; // temp, callback is allowed to change it
+typedef void(vector start, vector hit, vector end) WarpZone_trace_callback_t; // called on every elementary trace
+var WarpZone_trace_callback_t WarpZone_trace_callback_t_null;
+entity WarpZone_trace_transform; // transform accumulator during a trace
+entity WarpZone_trace_firstzone; // first warpzone hit by a trace (can differ from the requested zone in case of _ThroughZone, the trace is aborted then)
+entity WarpZone_trace_lastzone; // first warpzone hit by a trace (can differ from the requested zone in case of _ThroughZone, the trace is aborted then)
+vector WarpZone_tracetoss_velocity; // ending velocity of a tracetoss (post-transform)
+float WarpZone_tracetoss_time; // duration of toss (approximate)
+void WarpZone_TraceBox(vector org, vector min, vector max, vector end, float nomonsters, entity forent);
+void WarpZone_TraceBox_ThroughZone(vector org, vector min, vector max, vector end, float nomonsters, entity forent, entity zone, WarpZone_trace_callback_t cb);
+void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent);
+void WarpZone_TraceToss(entity e, entity forent);
+void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZone_trace_callback_t cb);
+void WarpZone_TrailParticles(entity own, float eff, vector org, vector end);
+#ifdef CSQC
+void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, float boxflags);
+#endif
+
+.vector WarpZone_findradius_dist;
+.vector WarpZone_findradius_nearest;
+// also set: warpzone parameters, so WarpZone_TransformOrigin can transform vectors from blast's to victim's system
+.vector WarpZone_findradius_findorigin;
+.float WarpZone_findradius_findradius;
+entity WarpZone_FindRadius(vector org, float radius, float needlineofsight);
+
+float WarpZone_PlaneDist(entity wz, vector v);
+float WarpZone_TargetPlaneDist(entity wz, vector v);
+vector WarpZone_TransformOrigin(entity wz, vector v);
+vector WarpZone_TransformVelocity(entity wz, vector v);
+vector WarpZone_TransformAngles(entity wz, vector v);
+vector WarpZone_TransformVAngles(entity wz, vector v);
+vector WarpZone_UnTransformOrigin(entity wz, vector v);
+vector WarpZone_UnTransformVelocity(entity wz, vector v);
+vector WarpZone_UnTransformAngles(entity wz, vector v);
+vector WarpZone_UnTransformVAngles(entity wz, vector v);
+
+// reference systems (chained warpzone transforms)
+void WarpZone_RefSys_Clear(entity me); // R := id
+void WarpZone_RefSys_Add(entity me, entity wz); // me.R := wz me.R
+void WarpZone_RefSys_AddInverse(entity me, entity wz); // me.R := wz^-1 me.R
+void WarpZone_RefSys_AddTransform(entity me, vector t, vector s); // me.R := [t s] me.R
+void WarpZone_RefSys_AddInverseTransform(entity me, vector t, vector s); // me.R := [t s]^-1 me.R
+
+// makes this reference system track ref's changes
+// NOTE: this is ONLY sensible if WarpZone_RefSys_Add is no longer called on "me" while doing this
+// To achieve this, make sure no touch events on warpzone are raised by this entity
+// or set a movetype that causes no warpzoning (e.g. MOVETYPE_NONE, MOVETYPE_FOLLOW)
+void WarpZone_RefSys_AddIncrementally(entity me, entity ref); // me.R := ref.R me.Rref^-1 me.R; me.Rref := ref.R
+void WarpZone_RefSys_BeginAddingIncrementally(entity me, entity ref); // me.Rref := ref.R
+
+vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org); // return to.R from.R^-1 org
+vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel); // return to.R from.R^-1 vel
+vector WarpZone_RefSys_TransformAngles(entity from, entity to, vector ang); // return to.R from.R^-1 ang
+vector WarpZone_RefSys_TransformVAngles(entity from, entity to, vector ang); // return to.R from.R^-1 ang
+void WarpZone_RefSys_Copy(entity me, entity from); // to.R := from.R
+entity WarpZone_RefSys_SpawnSameRefSys(entity me); // spawn().R = me.R
+
+#ifndef BITCLR
+# define BITCLR(a,b) ((a) - ((a) & (b)))
+#endif
+#ifndef BITSET
+# define BITSET(a,b) ((a) | (b))
+#endif
+#ifndef BITXOR
+# define BITXOR(a,b) (((a) | (b)) - ((a) & (b)))
+#endif
+#ifndef BITCLR_ASSIGN
+# define BITCLR_ASSIGN(a,b) ((a) = (a) - ((a) & (b)))
+#endif
+#ifndef BITSET_ASSIGN
+# define BITSET_ASSIGN(a,b) ((a) |= (b))
+#endif
+#ifndef BITXOR_ASSIGN
+# define BITXOR_ASSIGN(a,b) ((a) = ((a) | (b)) - ((a) & (b)))
+#endif
+float WarpZoneLib_MoveOutOfSolid(entity e);
+#define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
+
+float WarpZoneLib_ExactTrigger_Touch();
+void WarpZoneLib_ExactTrigger_Init();
+
+// WARNING: this kills the trace globals
+#define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
+#define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
+#endif
--- /dev/null
+#include "mathlib.qh"
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+#endif
+
+int fpclassify(float x)
+{
+ if(isnan(x))
+ return FP_NAN;
+ if(isinf(x))
+ return FP_INFINITE;
+ if(x == 0)
+ return FP_ZERO;
+ return FP_NORMAL;
+}
+bool isfinite(float x)
+{
+ return !(isnan(x) || isinf(x));
+}
+bool isinf(float x)
+{
+ return (x != 0) && (x + x == x);
+}
+bool isnan(float x)
+{
+ float y;
+ y = x;
+ return (x != y);
+}
+bool isnormal(float x)
+{
+ return isfinite(x);
+}
+bool signbit(float x)
+{
+ return (x < 0);
+}
+
+float acosh(float x)
+{
+ return log(x + sqrt(x*x - 1));
+}
+float asinh(float x)
+{
+ return log(x + sqrt(x*x + 1));
+}
+float atanh(float x)
+{
+ return 0.5 * log((1+x) / (1-x));
+}
+float cosh(float x)
+{
+ return 0.5 * (exp(x) + exp(-x));
+}
+float sinh(float x)
+{
+ return 0.5 * (exp(x) - exp(-x));
+}
+float tanh(float x)
+{
+ return sinh(x) / cosh(x);
+}
+
+float exp(float x)
+{
+ return pow(M_E, x);
+}
+float exp2(float x)
+{
+ return pow(2, x);
+}
+float expm1(float x)
+{
+ return exp(x) - 1;
+}
+
+vector frexp(float x)
+{
+ vector v;
+ v.z = 0;
+ v.y = ilogb(x) + 1;
+ v.x = x / exp2(v.y);
+ return v;
+}
+int ilogb(float x)
+{
+ return floor(log2(fabs(x)));
+}
+float ldexp(float x, int e)
+{
+ return x * pow(2, e);
+}
+float logn(float x, float base)
+{
+ return log(x) / log(base);
+}
+float log10(float x)
+{
+ return log(x) * M_LOG10E;
+}
+float log1p(float x)
+{
+ return log(x + 1);
+}
+float log2(float x)
+{
+ return log(x) * M_LOG2E;
+}
+float logb(float x)
+{
+ return floor(log2(fabs(x)));
+}
+vector modf(float f)
+{
+ return '1 0 0' * (f - trunc(f)) + '0 1 0' * trunc(f);
+}
+
+float scalbn(float x, int n)
+{
+ return x * pow(2, n);
+}
+
+float cbrt(float x)
+{
+ return copysign(pow(fabs(x), 1.0/3.0), x);
+}
+float hypot(float x, float y)
+{
+ return sqrt(x*x + y*y);
+}
+
+float erf(float x)
+{
+ // approximation taken from wikipedia
+ float y;
+ y = x*x;
+ return copysign(sqrt(1 - exp(-y * (1.273239544735163 + 0.14001228868667 * y) / (1 + 0.14001228868667 * y))), x);
+}
+float erfc(float x)
+{
+ return 1.0 - erf(x);
+}
+vector lgamma(float x)
+{
+ // TODO improve accuracy
+ if(!isfinite(x))
+ return fabs(x) * '1 0 0' + copysign(1, x) * '0 1 0';
+ if(x < 1 && x == floor(x))
+ return nan("gamma") * '1 1 1';
+ if(x < 0.1)
+ {
+ vector v;
+ v = lgamma(1.0 - x);
+ // reflection formula:
+ // gamma(1-z) * gamma(z) = pi / sin(pi*z)
+ // lgamma(1-z) + lgamma(z) = log(pi) - log(sin(pi*z))
+ // sign of gamma(1-z) = sign of gamma(z) * sign of sin(pi*z)
+ v.z = sin(M_PI * x);
+ v.x = log(M_PI) - log(fabs(v.z)) - v.x;
+ if(v.z < 0)
+ v.y = -v.y;
+ v.z = 0;
+ return v;
+ }
+ if(x < 1.1)
+ return lgamma(x + 1) - log(x) * '1 0 0';
+ x -= 1;
+ return (0.5 * log(2 * M_PI * x) + x * (log(x) - 1)) * '1 0 0' + '0 1 0';
+}
+float tgamma(float x)
+{
+ vector v;
+ v = lgamma(x);
+ return exp(v.x) * v.y;
+}
+
+/**
+ * Pythonic mod:
+ * TODO: %% operator?
+ *
+ * 1 % 2 == 1
+ * -1 % 2 == 1
+ * 1 % -2 == -1
+ * -1 % -2 == -1
+ */
+float pymod(float x, float y)
+{
+ return x - y * floor(x / y);
+}
+
+float nearbyint(float x)
+{
+ return rint(x);
+}
+float trunc(float x)
+{
+ return (x>=0) ? floor(x) : ceil(x);
+}
+
+float fmod(float x, float y)
+{
+ return x - y * trunc(x / y);
+}
+float remainder(float x, float y)
+{
+ return x - y * rint(x / y);
+}
+vector remquo(float x, float y)
+{
+ vector v;
+ v.z = 0;
+ v.y = rint(x / y);
+ v.x = x - y * v.y;
+ return v;
+}
+
+float copysign(float x, float y)
+{
+ return fabs(x) * ((y>0) ? 1 : -1);
+}
+float nan(string tag)
+{
+ return sqrt(-1);
+}
+float nextafter(float x, float y)
+{
+ // TODO very crude
+ if(x == y)
+ return nan("nextafter");
+ if(x > y)
+ return -nextafter(-x, -y);
+ // now we know that x < y
+ // so we need the next number > x
+ float d, a, b;
+ d = max(fabs(x), 0.00000000000000000000001);
+ a = x + d;
+ do
+ {
+ d *= 0.5;
+ b = a;
+ a = x + d;
+ }
+ while(a != x);
+ return b;
+}
+float nexttoward(float x, float y)
+{
+ return nextafter(x, y);
+}
+
+float fdim(float x, float y)
+{
+ return max(x-y, 0);
+}
+float fmax(float x, float y)
+{
+ return max(x, y);
+}
+float fmin(float x, float y)
+{
+ return min(x, y);
+}
+float fma(float x, float y, float z)
+{
+ return x * y + z;
+}
+
+int isgreater(float x, float y)
+{
+ return x > y;
+}
+int isgreaterequal(float x, float y)
+{
+ return x >= y;
+}
+int isless(float x, float y)
+{
+ return x < y;
+}
+int islessequal(float x, float y)
+{
+ return x <= y;
+}
+int islessgreater(float x, float y)
+{
+ return x < y || x > y;
+}
+int isunordered(float x, float y)
+{
+ return !(x < y || x == y || x > y);
+}
+
+vector cross(vector a, vector b)
+{
+ return
+ '1 0 0' * (a.y * b.z - a.z * b.y)
+ + '0 1 0' * (a.z * b.x - a.x * b.z)
+ + '0 0 1' * (a.x * b.y - a.y * b.x);
+}
--- /dev/null
+#ifndef LIB_WARPZONE_MATHLIB_H
+#define LIB_WARPZONE_MATHLIB_H
+
+// <math.h>
+
+// The commented-out functions need no implementation because DarkPlaces offers
+// them as builtins. They are listed here anyway for completeness sake.
+
+const int FP_NAN = 0;
+const int FP_INFINITE = 1;
+const int FP_ZERO = 2;
+const int FP_SUBNORMAL = 3;
+const int FP_NORMAL = 4;
+int fpclassify(float x);
+bool isfinite(float x);
+bool isinf(float x);
+bool isnan(float x);
+bool isnormal(float x);
+bool signbit(float x);
+
+//float acos(float x);
+//float asin(float x);
+//float atan(float x);
+//float atan2(float y, float x);
+//float cos(float x);
+//float sin(float x);
+//float tan(float x);
+
+float acosh(float x);
+float asinh(float x);
+float atanh(float x);
+float cosh(float x);
+float sinh(float x);
+float tanh(float x);
+
+float exp(float x);
+float exp2(float x);
+float expm1(float x);
+
+vector frexp(float x); // returns mantissa as _x, exponent as _y
+int ilogb(float x);
+float ldexp(float x, int e);
+//float log(float x);
+float logn(float x, float base);
+float log10(float x);
+float log1p(float x);
+float log2(float x);
+float logb(float x);
+vector modf(float f); // fraction as _x, integer as _y
+
+float scalbn(float x, int n);
+
+float cbrt(float x);
+//float fabs(float x);
+float hypot(float x, float y);
+//float pow(float x, float y);
+//float sqrt(float x, float y);
+
+float erf(float x);
+float erfc(float x);
+vector lgamma(float x); // value in _x, sign in _y
+float tgamma(float x);
+
+/**
+ * Pythonic mod:
+ * TODO: %% operator?
+ *
+ * 1 % 2 == 1
+ * -1 % 2 == 1
+ * 1 % -2 == -1
+ * -1 % -2 == -1
+ */
+float pymod(float x, float y);
+
+//float ceil(float x);
+//float floor(float x);
+float nearbyint(float x);
+//float rint(float x);
+//float round(float x);
+float trunc(float x);
+
+float fmod(float x, float y);
+float remainder(float x, float y);
+vector remquo(float x, float y);
+
+float copysign(float x, float y);
+float nan(string tag);
+float nextafter(float x, float y);
+float nexttoward(float x, float y);
+
+float fdim(float x, float y);
+float fmax(float x, float y);
+float fmin(float x, float y);
+float fma(float x, float y, float z);
+
+int isgreater(float x, float y);
+int isgreaterequal(float x, float y);
+int isless(float x, float y);
+int islessequal(float x, float y);
+int islessgreater(float x, float y);
+int isunordered(float x, float y);
+
+const float M_E = 2.7182818284590452354; /* e */
+const float M_LOG2E = 1.4426950408889634074; /* log_2 e */
+const float M_LOG10E = 0.43429448190325182765; /* log_10 e */
+const float M_LN2 = 0.69314718055994530942; /* log_e 2 */
+const float M_LN10 = 2.30258509299404568402; /* log_e 10 */
+// -Wdouble-declaration
+#define M_PI 3.14159265358979323846 /* pi */
+const float M_PI_2 = 1.57079632679489661923; /* pi/2 */
+const float M_PI_4 = 0.78539816339744830962; /* pi/4 */
+const float M_1_PI = 0.31830988618379067154; /* 1/pi */
+const float M_2_PI = 0.63661977236758134308; /* 2/pi */
+const float M_2_SQRTPI = 1.12837916709551257390; /* 2/sqrt(pi) */
+const float M_SQRT2 = 1.41421356237309504880; /* sqrt(2) */
+const float M_SQRT1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
+
+// Non-<math.h> stuff follows here.
+vector cross(vector a, vector b);
+
+#endif
--- /dev/null
+#include "server.qh"
+
+#include "common.qh"
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+ #include "../../common/constants.qh"
+ #include "../../common/triggers/subs.qh"
+ #include "../../common/util.qh"
+ #include "../../server/command/common.qh"
+ #include "../../server/constants.qh"
+ #include "../../server/defs.qh"
+#endif
+
+#ifdef WARPZONELIB_KEEPDEBUG
+#define WARPZONELIB_REMOVEHACK
+#endif
+
+// for think function
+.vector warpzone_save_origin;
+.vector warpzone_save_angles;
+.vector warpzone_save_eorigin;
+.vector warpzone_save_eangles;
+
+// for all entities
+.vector warpzone_oldorigin, warpzone_oldvelocity, warpzone_oldangles;
+.float warpzone_teleport_time;
+.float warpzone_teleport_finishtime;
+.entity warpzone_teleport_zone;
+
+void WarpZone_StoreProjectileData(entity e)
+{
+ e.warpzone_oldorigin = e.origin;
+ e.warpzone_oldvelocity = e.velocity;
+ e.warpzone_oldangles = e.angles;
+}
+
+void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity)
+{
+ setorigin (player, to); // NOTE: this also aborts the move, when this is called by touch
+ player.oldorigin = to; // for DP's unsticking
+ player.angles = to_angles;
+ player.fixangle = true;
+ player.velocity = to_velocity;
+
+ BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
+
+ if(IS_PLAYER(player))
+ BITCLR_ASSIGN(player.flags, FL_ONGROUND);
+
+ WarpZone_PostTeleportPlayer_Callback(player);
+}
+
+bool WarpZone_Teleported_Send(entity to, int sf)
+{SELFPARAM();
+ WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_TELEPORTED);
+ WriteCoord(MSG_ENTITY, self.angles.x);
+ WriteCoord(MSG_ENTITY, self.angles.y);
+ WriteCoord(MSG_ENTITY, self.angles.z);
+ return true;
+}
+
+float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
+{
+ vector o0, a0, v0, o1, a1, v1, o10;
+
+ o0 = player.origin + player.view_ofs;
+ v0 = player.velocity;
+ a0 = player.angles;
+
+ o10 = o1 = WarpZone_TransformOrigin(wz, o0);
+ v1 = WarpZone_TransformVelocity(wz, v0);
+ if (!IS_NOT_A_CLIENT(player))
+ a1 = WarpZone_TransformVAngles(wz, player.v_angle);
+ else
+ a1 = WarpZone_TransformAngles(wz, a0);
+
+ if(f0 != 0 || f1 != 0)
+ {
+ // retry last move but behind the warpzone!
+ // we must first go back as far as we can, then forward again, to not cause double touch events!
+
+ tracebox(o1 - player.view_ofs + v1 * frametime * f1, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f0, MOVE_WORLDONLY, player);
+ {
+ entity own;
+ own = player.owner;
+ player.owner = world;
+ tracebox(trace_endpos, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f1, MOVE_NORMAL, player); // this should get us through the warpzone
+ player.owner = own;
+ }
+ o1 = trace_endpos + player.view_ofs;
+
+ float d, dv, md;
+ md = max(vlen(player.mins), vlen(player.maxs));
+ d = WarpZone_TargetPlaneDist(wz, o1);
+ dv = WarpZone_TargetPlaneDist(wz, v1);
+ if(d < 0)
+ o1 = o1 - v1 * (d / dv);
+ }
+
+ // put him out of solid
+ tracebox(o1 - player.view_ofs, player.mins, player.maxs, o1 - player.view_ofs, MOVE_NOMONSTERS, player);
+ if(trace_startsolid)
+ {
+ setorigin(player, o1 - player.view_ofs);
+ if(WarpZoneLib_MoveOutOfSolid(player))
+ {
+ o1 = player.origin + player.view_ofs;
+ setorigin(player, o0 - player.view_ofs);
+ }
+ else
+ {
+ LOG_INFO("would have to put player in solid, won't do that\n");
+ setorigin(player, o0 - player.view_ofs);
+ return 0;
+ }
+ }
+
+ // do the teleport
+ WarpZone_RefSys_Add(player, wz);
+ WarpZone_TeleportPlayer(wz, player, o1 - player.view_ofs, a1, v1);
+ WarpZone_StoreProjectileData(player);
+ player.warpzone_teleport_time = time;
+ player.warpzone_teleport_finishtime = time;
+ player.warpzone_teleport_zone = wz;
+
+ // prevent further teleports back
+ float dt = (o1 - o10) * v1 * (1 / (v1 * v1));
+ if(dt < sys_frametime)
+ player.warpzone_teleport_finishtime += sys_frametime - dt;
+
+#ifndef WARPZONE_USE_FIXANGLE
+ if(IS_VEHICLE(player) && player.owner)
+ player = player.owner; // hax
+ if(IS_PLAYER(player))
+ {
+ // instead of fixangle, send the transform to the client for smoother operation
+ player.fixangle = false;
+
+ entity ts = spawn();
+ setmodel(ts, MDL_Null);
+ ts.SendEntity = WarpZone_Teleported_Send;
+ ts.SendFlags = 0xFFFFFF;
+ ts.drawonlytoclient = player;
+ ts.think = SUB_Remove;
+ ts.nextthink = time + 1;
+ ts.owner = player;
+ ts.enemy = wz;
+ ts.effects = EF_NODEPTHTEST;
+ ts.classname = "warpzone_teleported";
+ ts.angles = wz.warpzone_transform;
+ }
+#endif
+
+ return 1;
+}
+
+void WarpZone_Touch (void)
+{SELFPARAM();
+ if(other.classname == "trigger_warpzone")
+ return;
+
+ if(time <= other.warpzone_teleport_finishtime) // already teleported this frame
+ return;
+
+ // FIXME needs a better check to know what is safe to teleport and what not
+ if(other.movetype == MOVETYPE_NONE || other.movetype == MOVETYPE_FOLLOW || other.tag_entity)
+ return;
+
+ if(WarpZoneLib_ExactTrigger_Touch())
+ return;
+
+ if(WarpZone_PlaneDist(self, other.origin + other.view_ofs) >= 0) // wrong side of the trigger_warpzone (don't teleport yet)
+ return;
+
+ float f;
+ // number of frames we need to go back:
+ // dist = 16*sqrt(2) qu
+ // dist ~ 24 qu
+ // 24 qu = v*t
+ // 24 qu = v*frametime*n
+ // n = 24 qu/(v*frametime)
+ // for clients go only one frame though, may be too irritating otherwise
+ // but max 0.25 sec = 0.25/frametime frames
+ // 24/(0.25/frametime)
+ // 96*frametime
+ float d;
+ d = 24 + max(vlen(other.mins), vlen(other.maxs));
+ if(IS_NOT_A_CLIENT(other))
+ f = -d / bound(frametime * d * 1, frametime * vlen(other.velocity), d);
+ else
+ f = -1;
+ if(WarpZone_Teleport(self, other, f, 0))
+ {
+ string save1, save2;
+ activator = other;
+
+ save1 = self.target; self.target = string_null;
+ save2 = self.target3; self.target3 = string_null;
+ SUB_UseTargets();
+ if (!self.target) self.target = save1;
+ if (!self.target3) self.target3 = save2;
+
+ setself(self.enemy);
+ save1 = self.target; self.target = string_null;
+ save2 = self.target2; self.target2 = string_null;
+ SUB_UseTargets();
+ if (!self.target) self.target = save1;
+ if (!self.target2) self.target2 = save2;
+ setself(this);
+ }
+ else
+ {
+ LOG_TRACE("WARPZONE FAIL AHAHAHAHAH))\n");
+ }
+}
+
+bool WarpZone_Send(entity to, int sendflags)
+{SELFPARAM();
+ WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE);
+
+ // we must send this flag for clientside to match properly too
+ int f = 0;
+ if(self.warpzone_isboxy)
+ BITSET_ASSIGN(f, 1);
+ if(self.warpzone_fadestart)
+ BITSET_ASSIGN(f, 2);
+ if(self.origin != '0 0 0')
+ BITSET_ASSIGN(f, 4);
+ WriteByte(MSG_ENTITY, f);
+
+ // we need THESE to render the warpzone (and cull properly)...
+ if(f & 4)
+ {
+ WriteCoord(MSG_ENTITY, self.origin.x);
+ WriteCoord(MSG_ENTITY, self.origin.y);
+ WriteCoord(MSG_ENTITY, self.origin.z);
+ }
+
+ WriteShort(MSG_ENTITY, self.modelindex);
+ WriteCoord(MSG_ENTITY, self.mins.x);
+ WriteCoord(MSG_ENTITY, self.mins.y);
+ WriteCoord(MSG_ENTITY, self.mins.z);
+ WriteCoord(MSG_ENTITY, self.maxs.x);
+ WriteCoord(MSG_ENTITY, self.maxs.y);
+ WriteCoord(MSG_ENTITY, self.maxs.z);
+ WriteByte(MSG_ENTITY, bound(1, self.scale * 16, 255));
+
+ // we need THESE to calculate the proper transform
+ WriteCoord(MSG_ENTITY, self.warpzone_origin.x);
+ WriteCoord(MSG_ENTITY, self.warpzone_origin.y);
+ WriteCoord(MSG_ENTITY, self.warpzone_origin.z);
+ WriteCoord(MSG_ENTITY, self.warpzone_angles.x);
+ WriteCoord(MSG_ENTITY, self.warpzone_angles.y);
+ WriteCoord(MSG_ENTITY, self.warpzone_angles.z);
+ WriteCoord(MSG_ENTITY, self.warpzone_targetorigin.x);
+ WriteCoord(MSG_ENTITY, self.warpzone_targetorigin.y);
+ WriteCoord(MSG_ENTITY, self.warpzone_targetorigin.z);
+ WriteCoord(MSG_ENTITY, self.warpzone_targetangles.x);
+ WriteCoord(MSG_ENTITY, self.warpzone_targetangles.y);
+ WriteCoord(MSG_ENTITY, self.warpzone_targetangles.z);
+
+ if(f & 2)
+ {
+ WriteShort(MSG_ENTITY, self.warpzone_fadestart);
+ WriteShort(MSG_ENTITY, self.warpzone_fadeend);
+ }
+
+ return true;
+}
+
+bool WarpZone_Camera_Send(entity to, int sendflags)
+{SELFPARAM();
+ int f = 0;
+ WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_CAMERA);
+
+ if(self.warpzone_fadestart)
+ BITSET_ASSIGN(f, 2);
+ if(self.origin != '0 0 0')
+ BITSET_ASSIGN(f, 4);
+ WriteByte(MSG_ENTITY, f);
+
+ // we need THESE to render the warpzone (and cull properly)...
+ if(f & 4)
+ {
+ WriteCoord(MSG_ENTITY, self.origin.x);
+ WriteCoord(MSG_ENTITY, self.origin.y);
+ WriteCoord(MSG_ENTITY, self.origin.z);
+ }
+
+ WriteShort(MSG_ENTITY, self.modelindex);
+ WriteCoord(MSG_ENTITY, self.mins.x);
+ WriteCoord(MSG_ENTITY, self.mins.y);
+ WriteCoord(MSG_ENTITY, self.mins.z);
+ WriteCoord(MSG_ENTITY, self.maxs.x);
+ WriteCoord(MSG_ENTITY, self.maxs.y);
+ WriteCoord(MSG_ENTITY, self.maxs.z);
+ WriteByte(MSG_ENTITY, bound(1, self.scale * 16, 255));
+
+ // we need THESE to calculate the proper transform
+ WriteCoord(MSG_ENTITY, self.enemy.origin.x);
+ WriteCoord(MSG_ENTITY, self.enemy.origin.y);
+ WriteCoord(MSG_ENTITY, self.enemy.origin.z);
+ WriteCoord(MSG_ENTITY, self.enemy.angles.x);
+ WriteCoord(MSG_ENTITY, self.enemy.angles.y);
+ WriteCoord(MSG_ENTITY, self.enemy.angles.z);
+
+ if(f & 2)
+ {
+ WriteShort(MSG_ENTITY, self.warpzone_fadestart);
+ WriteShort(MSG_ENTITY, self.warpzone_fadeend);
+ }
+
+ return true;
+}
+
+#ifdef WARPZONELIB_KEEPDEBUG
+float WarpZone_CheckProjectileImpact(entity player)
+{SELFPARAM();
+ vector o0, v0;
+
+ o0 = player.origin + player.view_ofs;
+ v0 = player.velocity;
+
+ // if we teleported shortly before, abort
+ if(time <= player.warpzone_teleport_finishtime + 0.1)
+ return 0;
+
+ // if player hit a warpzone, abort
+ entity wz;
+ wz = WarpZone_Find(o0 + player.mins, o0 + player.maxs);
+ if(!wz)
+ return 0;
+
+#ifdef WARPZONELIB_REMOVEHACK
+ LOG_INFO("impactfilter found something - and it no longer gets handled correctly - please tell divVerent whether anything behaves broken now\n");
+#else
+ LOG_INFO("impactfilter found something - and it even gets handled correctly - please tell divVerent that this code apparently gets triggered again\n");
+#endif
+ LOG_INFO("Entity type: ", player.classname, "\n");
+ LOG_INFO("Origin: ", vtos(player.origin), "\n");
+ LOG_INFO("Velocity: ", vtos(player.velocity), "\n");
+
+#ifdef WARPZONELIB_REMOVEHACK
+ return 0;
+#else
+ // retry previous move
+ setorigin(player, player.warpzone_oldorigin);
+ player.velocity = player.warpzone_oldvelocity;
+ if(WarpZone_Teleport(wz, player, 0, 1))
+ {
+ entity oldself;
+ string save1, save2;
+
+ oldself = self;
+ self = wz;
+ other = player;
+ activator = player;
+
+ save1 = self.target; self.target = string_null;
+ save2 = self.target3; self.target3 = string_null;
+ SUB_UseTargets();
+ if (!self.target) self.target = save1;
+ if (!self.target3) self.target3 = save2;
+
+ self = self.enemy;
+ save1 = self.target; self.target = string_null;
+ save2 = self.target2; self.target2 = string_null;
+ SUB_UseTargets();
+ if (!self.target) self.target = save1;
+ if (!self.target2) self.target2 = save2;
+ self = oldself;
+ }
+ else
+ {
+ setorigin(player, o0 - player.view_ofs);
+ player.velocity = v0;
+ }
+
+ return +1;
+#endif
+}
+#endif
+
+float WarpZone_Projectile_Touch()
+{SELFPARAM();
+ if(other.classname == "trigger_warpzone")
+ return true;
+
+ // no further impacts if we teleported this frame!
+ // this is because even if we did teleport, the engine still may raise
+ // touch events for the previous location
+ // engine now aborts moves on teleport, so this SHOULD not happen any more
+ // but if this is called from TouchAreaGrid of the projectile moving,
+ // then this won't do
+ if(time == self.warpzone_teleport_time)
+ return true;
+
+#ifdef WARPZONELIB_KEEPDEBUG
+ // this SEEMS to not happen at the moment, but if it did, it would be more reliable
+ {
+ float save_dpstartcontents;
+ float save_dphitcontents;
+ float save_dphitq3surfaceflags;
+ string save_dphittexturename;
+ float save_allsolid;
+ float save_startsolid;
+ float save_fraction;
+ vector save_endpos;
+ vector save_plane_normal;
+ float save_plane_dist;
+ entity save_ent;
+ float save_inopen;
+ float save_inwater;
+ save_dpstartcontents = trace_dpstartcontents;
+ save_dphitcontents = trace_dphitcontents;
+ save_dphitq3surfaceflags = trace_dphitq3surfaceflags;
+ save_dphittexturename = trace_dphittexturename;
+ save_allsolid = trace_allsolid;
+ save_startsolid = trace_startsolid;
+ save_fraction = trace_fraction;
+ save_endpos = trace_endpos;
+ save_plane_normal = trace_plane_normal;
+ save_plane_dist = trace_plane_dist;
+ save_ent = trace_ent;
+ save_inopen = trace_inopen;
+ save_inwater = trace_inwater;
+ float f;
+ if((f = WarpZone_CheckProjectileImpact(self)) != 0)
+ return (f > 0);
+ trace_dpstartcontents = save_dpstartcontents;
+ trace_dphitcontents = save_dphitcontents;
+ trace_dphitq3surfaceflags = save_dphitq3surfaceflags;
+ trace_dphittexturename = save_dphittexturename;
+ trace_allsolid = save_allsolid;
+ trace_startsolid = save_startsolid;
+ trace_fraction = save_fraction;
+ trace_endpos = save_endpos;
+ trace_plane_normal = save_plane_normal;
+ trace_plane_dist = save_plane_dist;
+ trace_ent = save_ent;
+ trace_inopen = save_inopen;
+ trace_inwater = save_inwater;
+ }
+#endif
+
+ if(WarpZone_Projectile_Touch_ImpactFilter_Callback())
+ return true;
+
+ return false;
+}
+
+void WarpZone_InitStep_FindOriginTarget()
+{SELFPARAM();
+ if(self.killtarget != "")
+ {
+ self.aiment = find(world, targetname, self.killtarget);
+ if(self.aiment == world)
+ {
+ error("Warp zone with nonexisting killtarget");
+ return;
+ }
+ self.killtarget = string_null;
+ }
+}
+
+void WarpZonePosition_InitStep_FindTarget()
+{SELFPARAM();
+ if(self.target == "")
+ {
+ error("Warp zone position with no target");
+ return;
+ }
+ self.enemy = find(world, targetname, self.target);
+ if(self.enemy == world)
+ {
+ error("Warp zone position with nonexisting target");
+ return;
+ }
+ if(self.enemy.aiment)
+ {
+ // already is positioned
+ error("Warp zone position targeting already oriented warpzone");
+ return;
+ }
+ self.enemy.aiment = self;
+}
+
+void WarpZoneCamera_Think(void)
+{SELFPARAM();
+ if(self.warpzone_save_origin != self.origin
+ || self.warpzone_save_angles != self.angles
+ || self.warpzone_save_eorigin != self.enemy.origin
+ || self.warpzone_save_eangles != self.enemy.angles)
+ {
+ WarpZone_Camera_SetUp(self, self.enemy.origin, self.enemy.angles);
+ self.warpzone_save_origin = self.origin;
+ self.warpzone_save_angles = self.angles;
+ self.warpzone_save_eorigin = self.enemy.origin;
+ self.warpzone_save_eangles = self.enemy.angles;
+ }
+ self.nextthink = time;
+}
+
+void WarpZoneCamera_InitStep_FindTarget()
+{SELFPARAM();
+ entity e;
+ float i;
+ if(self.target == "")
+ {
+ error("Camera with no target");
+ return;
+ }
+ self.enemy = world;
+ for(e = world, i = 0; (e = find(e, targetname, self.target)); )
+ if(random() * ++i < 1)
+ self.enemy = e;
+ if(self.enemy == world)
+ {
+ error("Camera with nonexisting target");
+ return;
+ }
+ warpzone_cameras_exist = 1;
+ WarpZone_Camera_SetUp(self, self.enemy.origin, self.enemy.angles);
+ self.SendFlags = 0xFFFFFF;
+ if(self.spawnflags & 1)
+ {
+ self.think = WarpZoneCamera_Think;
+ self.nextthink = time;
+ }
+ else
+ self.nextthink = 0;
+}
+
+void WarpZone_InitStep_UpdateTransform()
+{SELFPARAM();
+ vector org, ang, norm, point;
+ float area;
+ vector tri, a, b, c, n;
+ float i_s, i_t, n_t;
+ string tex;
+
+ org = self.origin;
+ if(org == '0 0 0')
+ org = 0.5 * (self.mins + self.maxs);
+
+ norm = point = '0 0 0';
+ area = 0;
+ for(i_s = 0; ; ++i_s)
+ {
+ tex = getsurfacetexture(self, i_s);
+ if (!tex)
+ break; // this is beyond the last one
+ if(tex == "textures/common/trigger" || tex == "trigger")
+ continue;
+ n_t = getsurfacenumtriangles(self, i_s);
+ for(i_t = 0; i_t < n_t; ++i_t)
+ {
+ tri = getsurfacetriangle(self, i_s, i_t);
+ a = getsurfacepoint(self, i_s, tri.x);
+ b = getsurfacepoint(self, i_s, tri.y);
+ c = getsurfacepoint(self, i_s, tri.z);
+ n = cross(c - a, b - a);
+ area = area + vlen(n);
+ norm = norm + n;
+ point = point + vlen(n) * (a + b + c);
+ }
+ }
+ if(area > 0)
+ {
+ norm = norm * (1 / area);
+ point = point * (1 / (3 * area));
+ if(vlen(norm) < 0.99)
+ {
+ LOG_INFO("trigger_warpzone near ", vtos(self.aiment.origin), " is nonplanar. BEWARE.\n");
+ area = 0; // no autofixing in this case
+ }
+ norm = normalize(norm);
+ }
+
+ ang = '0 0 0';
+ if(self.aiment)
+ {
+ org = self.aiment.origin;
+ ang = self.aiment.angles;
+ if(area > 0)
+ {
+ org = org - ((org - point) * norm) * norm; // project to plane
+ makevectors(ang);
+ if(norm * v_forward < 0)
+ {
+ LOG_INFO("Position target of trigger_warpzone near ", vtos(self.aiment.origin), " points into trigger_warpzone. BEWARE.\n");
+ norm = -1 * norm;
+ }
+ ang = vectoangles2(norm, v_up); // keep rotation, but turn exactly against plane
+ ang.x = -ang.x;
+ if(norm * v_forward < 0.99)
+ LOG_INFO("trigger_warpzone near ", vtos(self.aiment.origin), " has been turned to match plane orientation (", vtos(self.aiment.angles), " -> ", vtos(ang), "\n");
+ if(vlen(org - self.aiment.origin) > 0.5)
+ LOG_INFO("trigger_warpzone near ", vtos(self.aiment.origin), " has been moved to match the plane (", vtos(self.aiment.origin), " -> ", vtos(org), ").\n");
+ }
+ }
+ else if(area > 0)
+ {
+ org = point;
+ ang = vectoangles(norm);
+ ang.x = -ang.x;
+ }
+ else
+ error("cannot infer origin/angles for this warpzone, please use a killtarget or a trigger_warpzone_position");
+
+ self.warpzone_origin = org;
+ self.warpzone_angles = ang;
+}
+
+void WarpZone_InitStep_ClearTarget()
+{SELFPARAM();
+ if(self.enemy)
+ self.enemy.enemy = world;
+ self.enemy = world;
+}
+
+entity warpzone_first; .entity warpzone_next;
+void WarpZone_InitStep_FindTarget()
+{SELFPARAM();
+ float i;
+ entity e, e2;
+
+ if(self.enemy)
+ return;
+
+ // this way only one of the two ents needs to target
+ if(self.target != "")
+ {
+ self.enemy = self; // so the if(!e.enemy) check also skips self, saves one IF
+
+ e2 = world;
+ for(e = world, i = 0; (e = find(e, targetname, self.target)); )
+ if(!e.enemy)
+ if(e.classname == self.classname) // possibly non-warpzones may use the same targetname!
+ if(random() * ++i < 1)
+ e2 = e;
+ if(!e2)
+ {
+ self.enemy = world;
+ error("Warpzone with non-existing target");
+ return;
+ }
+ self.enemy = e2;
+ e2.enemy = self;
+ }
+}
+
+void WarpZone_Think();
+void WarpZone_InitStep_FinalizeTransform()
+{SELFPARAM();
+ if(!self.enemy || self.enemy.enemy != self)
+ {
+ error("Invalid warp zone detected. Killed.");
+ return;
+ }
+
+ warpzone_warpzones_exist = 1;
+ WarpZone_SetUp(self, self.warpzone_origin, self.warpzone_angles, self.enemy.warpzone_origin, self.enemy.warpzone_angles);
+ self.touch = WarpZone_Touch;
+ self.SendFlags = 0xFFFFFF;
+ if(self.spawnflags & 1)
+ {
+ self.think = WarpZone_Think;
+ self.nextthink = time;
+ }
+ else
+ self.nextthink = 0;
+}
+
+float warpzone_initialized;
+//entity warpzone_first;
+entity warpzone_position_first;
+entity warpzone_camera_first;
+.entity warpzone_next;
+spawnfunc(misc_warpzone_position)
+{
+ // "target", "angles", "origin"
+ self.warpzone_next = warpzone_position_first;
+ warpzone_position_first = self;
+}
+spawnfunc(trigger_warpzone_position)
+{
+ spawnfunc_misc_warpzone_position(this);
+}
+spawnfunc(trigger_warpzone)
+{
+ // warp zone entities must have:
+ // "killtarget" pointing to a target_position with a direction arrow
+ // that points AWAY from the warp zone, and that is inside
+ // the warp zone trigger
+ // "target" pointing to an identical warp zone at another place in
+ // the map, with another killtarget to designate its
+ // orientation
+
+ if(!self.scale)
+ self.scale = self.modelscale;
+ if(!self.scale)
+ self.scale = 1;
+ string m;
+ m = self.model;
+ WarpZoneLib_ExactTrigger_Init();
+ if(m != "")
+ {
+ precache_model(m);
+ _setmodel(self, m); // no precision needed
+ }
+ setorigin(self, self.origin);
+ if(self.scale)
+ setsize(self, self.mins * self.scale, self.maxs * self.scale);
+ else
+ setsize(self, self.mins, self.maxs);
+ self.SendEntity = WarpZone_Send;
+ self.SendFlags = 0xFFFFFF;
+ BITSET_ASSIGN(self.effects, EF_NODEPTHTEST);
+ self.warpzone_next = warpzone_first;
+ warpzone_first = self;
+}
+spawnfunc(func_camera)
+{
+ if(!self.scale)
+ self.scale = self.modelscale;
+ if(!self.scale)
+ self.scale = 1;
+ if(self.model != "")
+ {
+ precache_model(self.model);
+ _setmodel(self, self.model); // no precision needed
+ }
+ setorigin(self, self.origin);
+ if(self.scale)
+ setsize(self, self.mins * self.scale, self.maxs * self.scale);
+ else
+ setsize(self, self.mins, self.maxs);
+ if(!self.solid)
+ self.solid = SOLID_BSP;
+ else if(self.solid < 0)
+ self.solid = SOLID_NOT;
+ self.SendEntity = WarpZone_Camera_Send;
+ self.SendFlags = 0xFFFFFF;
+ self.warpzone_next = warpzone_camera_first;
+ warpzone_camera_first = self;
+}
+void WarpZones_Reconnect()
+{SELFPARAM();
+ for(setself(warpzone_first); self; setself(self.warpzone_next))
+ WarpZone_InitStep_ClearTarget();
+ for(setself(warpzone_first); self; setself(self.warpzone_next))
+ WarpZone_InitStep_FindTarget();
+ for(setself(warpzone_camera_first); self; setself(self.warpzone_next))
+ WarpZoneCamera_InitStep_FindTarget();
+ for(setself(warpzone_first); self; setself(self.warpzone_next))
+ WarpZone_InitStep_FinalizeTransform();
+ setself(this);
+}
+
+void WarpZone_Think()
+{SELFPARAM();
+ if(self.warpzone_save_origin != self.origin
+ || self.warpzone_save_angles != self.angles
+ || self.warpzone_save_eorigin != self.enemy.origin
+ || self.warpzone_save_eangles != self.enemy.angles)
+ {
+ WarpZone_InitStep_UpdateTransform();
+ setself(self.enemy);
+ WarpZone_InitStep_UpdateTransform();
+ setself(this);
+ WarpZone_InitStep_FinalizeTransform();
+ setself(self.enemy);
+ WarpZone_InitStep_FinalizeTransform();
+ setself(this);
+ self.warpzone_save_origin = self.origin;
+ self.warpzone_save_angles = self.angles;
+ self.warpzone_save_eorigin = self.enemy.origin;
+ self.warpzone_save_eangles = self.enemy.angles;
+ }
+ self.nextthink = time;
+}
+
+void WarpZone_StartFrame()
+{SELFPARAM();
+ entity e;
+ if(warpzone_initialized == 0)
+ {
+ warpzone_initialized = 1;
+ for(setself(warpzone_first); self; setself(self.warpzone_next))
+ WarpZone_InitStep_FindOriginTarget();
+ for(setself(warpzone_position_first); self; setself(self.warpzone_next))
+ WarpZonePosition_InitStep_FindTarget();
+ for(setself(warpzone_first); self; setself(self.warpzone_next))
+ WarpZone_InitStep_UpdateTransform();
+ setself(this);
+ WarpZones_Reconnect();
+ WarpZone_PostInitialize_Callback();
+ }
+
+ entity oldother;
+ oldother = other;
+ for(e = world; (e = nextent(e)); )
+ {
+ if(warpzone_warpzones_exist) { WarpZone_StoreProjectileData(e); }
+
+ if(IS_REAL_CLIENT(e))
+ {
+ if(e.solid == SOLID_NOT) // not spectating?
+ if(e.movetype == MOVETYPE_NOCLIP || e.movetype == MOVETYPE_FLY || e.movetype == MOVETYPE_FLY_WORLDONLY) // not spectating? (this is to catch observers)
+ {
+ other = e; // player
+
+ // warpzones
+ if(warpzone_warpzones_exist) {
+ setself(WarpZone_Find(e.origin + e.mins, e.origin + e.maxs));
+ if(self)
+ if(!WarpZoneLib_ExactTrigger_Touch())
+ if(WarpZone_PlaneDist(self, e.origin + e.view_ofs) <= 0)
+ WarpZone_Teleport(self, e, -1, 0); } // NOT triggering targets by this!
+
+ // teleporters
+ setself(Teleport_Find(e.origin + e.mins, e.origin + e.maxs));
+ if(self)
+ if(!WarpZoneLib_ExactTrigger_Touch())
+ Simple_TeleportPlayer(self, other); // NOT triggering targets by this!
+ }
+ }
+
+ if(IS_NOT_A_CLIENT(e))
+ {
+ if(warpzone_warpzones_exist)
+ for (; (e = nextent(e)); )
+ WarpZone_StoreProjectileData(e);
+ break;
+ }
+ }
+ setself(this);
+ other = oldother;
+}
+
+.float warpzone_reconnecting;
+float visible_to_some_client(entity ent)
+{
+ entity e;
+ for(e = nextent(world); !IS_NOT_A_CLIENT(e); e = nextent(e))
+ if(IS_PLAYER(e) && IS_REAL_CLIENT(e))
+ if(checkpvs(e.origin + e.view_ofs, ent))
+ return 1;
+ return 0;
+}
+void trigger_warpzone_reconnect_use()
+{SELFPARAM();
+ entity e;
+ e = self;
+ // NOTE: this matches for target, not targetname, but of course
+ // targetname must be set too on the other entities
+ for(setself(warpzone_first); self; setself(self.warpzone_next))
+ self.warpzone_reconnecting = ((e.target == "" || self.target == e.target) && !((e.spawnflags & 1) && (visible_to_some_client(self) || visible_to_some_client(self.enemy))));
+ for(setself(warpzone_camera_first); self; setself(self.warpzone_next))
+ self.warpzone_reconnecting = ((e.target == "" || self.target == e.target) && !((e.spawnflags & 1) && visible_to_some_client(self)));
+ for(setself(warpzone_first); self; setself(self.warpzone_next))
+ if(self.warpzone_reconnecting)
+ WarpZone_InitStep_ClearTarget();
+ for(setself(warpzone_first); self; setself(self.warpzone_next))
+ if(self.warpzone_reconnecting)
+ WarpZone_InitStep_FindTarget();
+ for(setself(warpzone_camera_first); self; setself(self.warpzone_next))
+ if(self.warpzone_reconnecting)
+ WarpZoneCamera_InitStep_FindTarget();
+ for(setself(warpzone_first); self; setself(self.warpzone_next))
+ if(self.warpzone_reconnecting || self.enemy.warpzone_reconnecting)
+ WarpZone_InitStep_FinalizeTransform();
+ setself(e);
+}
+
+spawnfunc(trigger_warpzone_reconnect)
+{
+ self.use = trigger_warpzone_reconnect_use;
+}
+
+spawnfunc(target_warpzone_reconnect)
+{
+ spawnfunc_trigger_warpzone_reconnect(this); // both names make sense here :(
+}
+
+void WarpZone_PlayerPhysics_FixVAngle(void)
+{SELFPARAM();
+#ifndef WARPZONE_DONT_FIX_VANGLE
+ if(IS_REAL_CLIENT(self))
+ if(self.v_angle.z <= 360) // if not already adjusted
+ if(time - self.ping * 0.001 < self.warpzone_teleport_time)
+ {
+ self.v_angle = WarpZone_TransformVAngles(self.warpzone_teleport_zone, self.v_angle);
+ self.v_angle_z += 720; // mark as adjusted
+ }
+#endif
+}
--- /dev/null
+#ifndef LIB_WARPZONE_SERVER_H
+#define LIB_WARPZONE_SERVER_H
+
+void WarpZone_StartFrame();
+float WarpZone_Projectile_Touch();
+
+// THESE must be defined by calling QC code:
+void WarpZone_PostTeleportPlayer_Callback(entity pl);
+float WarpZone_Projectile_Touch_ImpactFilter_Callback();
+
+// server must also define a float called ENT_CLIENT_WARPZONE for the initial byte of WarpZone entities
+//const float ENT_CLIENT_WARPZONE;
+//const float ENT_CLIENT_WARPZONE_CAMERA;
+
+void WarpZone_PlayerPhysics_FixVAngle(void);
+
+void WarpZone_PostInitialize_Callback(void);
+#endif
--- /dev/null
+#include "util_server.qh"
+
+#include "common.qh"
+
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+ #include "../csqcmodel/sv_model.qh"
+#endif
+#include "common.qh"
+
+void WarpZoneLib_ExactTrigger_Init()
+{SELFPARAM();
+ vector mi, ma;
+ if (self.movedir == '0 0 0')
+ if (self.angles != '0 0 0')
+ {
+ makevectors (self.angles);
+ self.movedir = v_forward;
+ }
+ if(self.model == "")
+ {
+ // It's a box! No need to match with exacttriggers.
+ self.warpzone_isboxy = 1;
+ }
+ else
+ {
+ mi = self.mins;
+ ma = self.maxs;
+ precache_model(self.model);
+ _setmodel(self, self.model);
+ // let mapper-set mins/maxs override the model's bounds if set
+ if(mi != '0 0 0' || ma != '0 0 0')
+ {
+ // It's a box! No need to match with exacttriggers.
+ self.mins = mi;
+ self.maxs = ma;
+ self.warpzone_isboxy = 1;
+ }
+ }
+ setorigin(self, self.origin);
+ if(self.scale)
+ setsize(self, self.mins * self.scale, self.maxs * self.scale);
+ else
+ setsize(self, self.mins, self.maxs);
+ self.movetype = MOVETYPE_NONE;
+ self.solid = SOLID_TRIGGER;
+ self.model = "";
+}
--- /dev/null
+#ifndef LIB_WARPZONE_UTIL_SERVER_H
+#define LIB_WARPZONE_UTIL_SERVER_H
+
+float WarpZoneLib_MoveOutOfSolid(entity e);
+float WarpZoneLib_ExactTrigger_Touch();
+#ifdef SVQC
+void WarpZoneLib_ExactTrigger_Init();
+#endif
+#endif
-#ifndef CLIENT_ALL_H
-#define CLIENT_ALL_H
+#ifndef MENU_ALL_H
+#define MENU_ALL_H
-#include "../dpdefs/menudefs.qh"
-#include "../dpdefs/keycodes.qh"
+#include "draw.qh"
+#include "xonotic/util.qh"
#endif
#ifndef ANIM_ANIMATION_H
#define ANIM_ANIMATION_H
-#include "../oo/base.qh"
void setterDummy(entity, float);
CLASS(Animation, Object)
METHOD(Animation, configureAnimation, void(entity, entity, void(entity, float), float, float, float, float));
#ifndef ANIM_ANIMHOST_H
#define ANIM_ANIMHOST_H
-#include "../oo/base.qh"
CLASS(AnimHost, Object)
METHOD(AnimHost, addAnim, void(entity, entity));
METHOD(AnimHost, removeAnim, void(entity, entity));
entity e;
string s;
- for(i = 0, e = world; (e = nextent(e)); )
+ for(i = 0, e = NULL; (e = nextent(e)); )
if(e.classname != "vtbl" && e.name != "")
{
s = e.name;
#ifndef GAMESETTINGS_H
#define GAMESETTINGS_H
+#include "xonotic/tab.qc"
+
REGISTRY(Settings, BIT(3))
REGISTER_REGISTRY(RegisterSettings)
#define REGISTER_SETTINGS(id, impl) \
#ifndef ITEM_H
#define ITEM_H
#include "skin.qh"
-#include "oo/base.qh"
CLASS(Item, Object)
METHOD(Item, draw, void(entity));
METHOD(Item, keyDown, float(entity, float, float, float));
vector fs;
animating = 0;
- front = world;
+ front = NULL;
for(e = me.firstChild; e; e = e.nextSibling)
if(e.ModalController_state)
{
ATTRIB(Slider, value, float, 0)
ATTRIB(Slider, animated, float, 1)
ATTRIB(Slider, sliderValue, float, 0)
- ATTRIB(Slider, sliderAnim, entity, world)
+ ATTRIB(Slider, sliderAnim, entity, NULL)
ATTRIB(Slider, valueMin, float, 0)
ATTRIB(Slider, valueMax, float, 0)
ATTRIB(Slider, valueStep, float, 0)
if(me.sliderAnim.isFinished(me.sliderAnim))
{
anim.removeObjAnim(anim, me);
- me.sliderAnim = world;
+ me.sliderAnim = NULL;
}
me.setText(me, me.valueToText(me, me.value));
entity it;
entity best;
- best = world;
+ best = NULL;
it = root;
while(it.instanceOfContainer)
best = it;
else if(menu_tooltips == 2 && (it.cvarName || it.onClickCommand))
best = it;
- it = world;
+ it = NULL;
}
else if(it.instanceOfModalController)
it = it.focusedChild;
if (!menu_tooltips)
{
// don't return immediately, fade out the active tooltip first
- if (menuTooltipItem == world)
+ if (menuTooltipItem == NULL)
return;
- it = world;
+ it = NULL;
menu_tooltips_old = menu_tooltips;
}
else
if(f < 0.01)
it = m_findtooltipitem(main, pos);
else
- it = world;
+ it = NULL;
}
fontsize = '1 0 0' * (SKINFONTSIZE_TOOLTIP / conwidth) + '0 1 0' * (SKINFONTSIZE_TOOLTIP / conheight);
if(menuTooltipAlpha == 0)
{
menuTooltipState = 0;
- menuTooltipItem = world;
+ menuTooltipItem = NULL;
}
break;
}
- if(menuTooltipItem == world)
+ if(menuTooltipItem == NULL)
{
if (menuTooltipText)
{
if(menu_tooltips != menu_tooltips_old)
{
if (menu_tooltips != 0 && menu_tooltips_old != 0)
- menuTooltipItem = world; // reload tooltip next frame
+ menuTooltipItem = NULL; // reload tooltip next frame
menu_tooltips_old = menu_tooltips;
}
else if(menuTooltipOrigin.x < 0) // unallocated?
#include "draw.qh"
#include "skin.qh"
-#include "oo/base.qh"
-
#include "xonotic/util.qh"
#include "../common/constants.qh"
+++ /dev/null
-#ifndef BASE_H
-#define BASE_H
-
-#include "../../common/util.qh"
-#include "../../dpdefs/keycodes.qh"
-
-#define world NULL
-
-#endif
#ifndef CLASSES_H
#define CLASSES_H
-#include "base.qh"
#include "../classes.inc"
#define IMPLEMENTATION
-#include "../common/util-pre.qh"
-#include "../dpdefs/menudefs.qh"
-#include "../dpdefs/keycodes.qh"
-#include "../common/util-post.qh"
-
#include "../lib/_all.inc"
+#define world NULL
+
#include "oo/classes.qc"
#include "draw.qc"
t = cvar_type(me.cvarName);
me.cvarType = "";
float needsForcing;
- if(strstrofs(strcat(" ", autocvar_menu_forced_saved_cvars, " "), strcat(" ", me.cvarName, " "), 0) >= 0)
+ if(strhasword(autocvar_menu_forced_saved_cvars, me.cvarName))
{
me.cvarType = strcat(me.cvarType, ", ", _("forced to be saved to config.cfg"));
needsForcing = 0;
}
- else if(strstrofs(strcat(" ", autocvar_menu_reverted_nonsaved_cvars, " "), strcat(" ", me.cvarName, " "), 0) >= 0)
+ else if(strhasword(autocvar_menu_reverted_nonsaved_cvars, me.cvarName))
{
// Currently claims to be saved, but won't be on next startup.
me.cvarType = strcat(me.cvarType, ", ", _("will not be saved"));
v = cvar_string(k);
d = cvar_defstring(k);
t = cvar_type(k);
- if(strstrofs(strcat(" ", autocvar_menu_forced_saved_cvars, " "), strcat(" ", k, " "), 0) >= 0)
+ if(strhasword(autocvar_menu_forced_saved_cvars, k))
theAlpha = SKINALPHA_CVARLIST_SAVED;
- else if(strstrofs(strcat(" ", autocvar_menu_reverted_nonsaved_cvars, " "), strcat(" ", k, " "), 0) >= 0)
+ else if(strhasword(autocvar_menu_reverted_nonsaved_cvars, k))
theAlpha = SKINALPHA_CVARLIST_TEMPORARY;
else if(t & CVAR_TYPEFLAG_SAVED)
theAlpha = SKINALPHA_CVARLIST_SAVED;
{
if (scan == K_MOUSE3 || ((shift & S_CTRL) && scan == K_SPACE))
{
- CvarList_Revert_Click(world, me);
+ CvarList_Revert_Click(NULL, me);
return 1;
}
else if(scan == K_ENTER)
{
me.cvarValueBox.setText(me.cvarValueBox, me.cvarDefault);
me.cvarValueBox.cursorPos = strlen(me.cvarDefault);
- if(strstrofs(strcat(" ", autocvar_menu_forced_saved_cvars, " "), strcat(" ", me.cvarName, " "), 0) >= 0)
+ if(strhasword(autocvar_menu_forced_saved_cvars, me.cvarName))
{
cvar_set("menu_forced_saved_cvars", substring(strreplace(strcat(" ", me.cvarName, " "), " ", strcat(" ", autocvar_menu_forced_saved_cvars, " ")), 1, -2));
if (autocvar_menu_reverted_nonsaved_cvars == "")
// to press buttons while browsing with only the keyboard
if (shift & S_CTRL)
{
- toggleSlideShow_Click(world, me);
+ toggleSlideShow_Click(NULL, me);
return 1;
}
return SUPER(XonoticScreenshotViewerDialog).keyDown(me, key, ascii, shift);
if(me.dialogToShow)
{
- DialogOpenButton_Click_withCoords(world, me.dialogToShow, '0 0 0', eX * conwidth + eY * conheight);
+ DialogOpenButton_Click_withCoords(NULL, me.dialogToShow, '0 0 0', eX * conwidth + eY * conheight);
me.dialogToShow = NULL;
}
}
else
me.filterString = string_null;
- ScreenshotList_Refresh_Click(world, me);
+ ScreenshotList_Refresh_Click(NULL, me);
}
void ScreenshotList_Filter_Would_Change(entity box, entity me)
else
{
error(sprintf("RetrieveCategoryEnt(%d): Improper category number!\n", catnum));
- return world;
+ return NULL;
}
}
ATTRIB(XonoticSoundList, itemAbsSize, vector, '0 0 0')
ATTRIB(XonoticSoundList, filterString, string, string_null)
- ATTRIB(XonoticSoundList, playlist, entity, world)
+ ATTRIB(XonoticSoundList, playlist, entity, NULL)
ENDCLASS(XonoticSoundList)
entity makeXonoticSoundList();
#include "util.qh"
+
+#include "../item.qc"
+
#include "../menu.qh"
-#include "../oo/base.qh"
#include "../../common/campaign_common.qh"
#include "../../common/constants.qh"
#include "../../common/mapinfo.qh"
float GL_CheckExtension(string ext)
{
- return (strstrofs(strcat(" ", cvar_string("gl_info_extensions"), " "), strcat(" ", ext, " "), 0) >= 0);
+ return strhasword(cvar_string("gl_info_extensions"), ext);
}
float GL_Have_TextureCompression()
#include "defs.qh"
#include "miscfunctions.qh"
-#include "../dpdefs/progsdefs.qh"
-#include "../dpdefs/dpextensions.qh"
+#include "../common/effects/all.qh"
#include "../common/models/all.qh"
#include "../common/sounds/all.qh"
#include "defs.qh"
#include "miscfunctions.qh"
-#include "../dpdefs/progsdefs.qh"
-#include "../dpdefs/dpextensions.qh"
#include "command/common.qh"
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
#include "../common/vehicles/all.qh"
#include "antilag.qh"
#endif
--- /dev/null
+#include "aim.qc"
+#include "bot.qc"
+#include "navigation.qc"
+#include "scripting.qc"
+#include "waypoints.qc"
+
+#include "havocbot/_all.inc"
#include "aim.qh"
-#include "../_all.qh"
#include "bot.qh"
+#include "../weapons/weaponsystem.qh"
+
#include "../mutators/mutators_include.qh"
// traces multiple trajectories to find one that will impact the target
#include "bot.qh"
-#include "../_all.qh"
#include "aim.qh"
#include "navigation.qh"
#include "havocbot/havocbot.qh"
#include "havocbot/scripting.qh"
+#include "../teamplay.qh"
+
#include "../antilag.qh"
#include "../autocvars.qh"
#include "../campaign.qh"
#include "../../common/weapons/all.qh"
-#include "../../csqcmodellib/sv_model.qh"
-
-#include "../../dpdefs/dpextensions.qh"
-#include "../../dpdefs/progsdefs.qh"
+#include "../../lib/csqcmodel/sv_model.qh"
-#include "../../warpzonelib/common.qh"
-#include "../../warpzonelib/util_server.qh"
+#include "../../lib/warpzone/common.qh"
+#include "../../lib/warpzone/util_server.qh"
entity bot_spawn()
{SELFPARAM();
--- /dev/null
+#include "havocbot.qc"
+#include "role_keyhunt.qc"
+#include "roles.qc"
#include "havocbot.qh"
-#include "../../_all.qh"
#include "../aim.qh"
#include "../bot.qh"
#include "../waypoints.qh"
#include "../../../common/constants.qh"
+#include "../../../common/items/all.qh"
#include "../../../common/triggers/trigger/jumppads.qh"
-#include "../../../warpzonelib/common.qh"
+#include "../../../lib/warpzone/common.qh"
+
+.float speed;
void havocbot_ai()
{SELFPARAM();
#include "role_keyhunt.qh"
-#include "../../_all.qh"
#include "havocbot.qh"
-#include "../../_all.qh"
#include "havocbot.qh"
#include "role_keyhunt.qh"
#include "navigation.qh"
-#include "../_all.qh"
#include "bot.qh"
#include "waypoints.qh"
#include "../t_items.qh"
+#include "../../common/items/all.qh"
+
#include "../../common/constants.qh"
#include "../../common/triggers/trigger/jumppads.qh"
+.float speed;
+
void bot_debug(string input)
{
switch(autocvar_bot_debug)
#include "scripting.qh"
-#include "../_all.qh"
#include "bot.qh"
+.int state;
+
.float bot_cmdqueuebuf_allocated;
.float bot_cmdqueuebuf;
.float bot_cmdqueuebuf_start;
#include "waypoints.qh"
-#include "../_all.qh"
#include "bot.qh"
#include "navigation.qh"
#include "../../common/constants.qh"
-#include "../../warpzonelib/util_server.qh"
+#include "../../lib/warpzone/common.qh"
+#include "../../lib/warpzone/util_server.qh"
// create a new spawnfunc_waypoint and automatically link it to other waypoints, and link
// them back to it as well
#include "cheats.qh"
-#include "_all.qh"
#include "g_damage.qh"
#include "race.qh"
#include "../common/constants.qh"
#include "../common/deathtypes/all.qh"
-#include "../common/effects/effects.qh"
#include "../common/util.qh"
#include "../common/monsters/all.qh"
#include "../common/triggers/func/breakable.qh"
-#include "../csqcmodellib/sv_model.qh"
+#include "../lib/csqcmodel/sv_model.qh"
-#include "../warpzonelib/anglestransform.qh"
-#include "../warpzonelib/util_server.qh"
+#include "../lib/warpzone/anglestransform.qh"
+#include "../lib/warpzone/util_server.qh"
void CopyBody(float keepvelocity);
#include "bot/navigation.qh"
#include "../common/vehicles/all.qh"
+#include "../common/triggers/teleporters.qh"
#include "weapons/hitplot.qh"
#include "weapons/weaponsystem.qh"
#include "../common/monsters/sv_monsters.qh"
-#include "../warpzonelib/server.qh"
+#include "../lib/warpzone/server.qh"
void send_CSQC_teamnagger() {
-#include "_all.qh"
#include "round_handler.qh"
#include "bot/waypoints.qh"
#include "../common/minigames/sv_minigames.qh"
#include "../common/weapons/all.qh"
+#include "../common/vehicles/sv_vehicles.qh"
-/*
+#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
+
+.entity vehicle;
+
+/**
* Impulse map:
*
* 0 reserved (no input)
#include "cl_player.qh"
-#include "_all.qh"
#include "bot/bot.qh"
#include "cheats.qh"
#include "../common/deathtypes/all.qh"
#include "../common/triggers/subs.qh"
#include "../common/playerstats.qh"
-#include "../csqcmodellib/sv_model.qh"
+#include "../lib/csqcmodel/sv_model.qh"
#include "../common/minigames/sv_minigames.qh"
+#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
+#include "../common/triggers/include.qh"
+
#include "weapons/weaponstats.qh"
#include "../common/animdecide.qh"
#include "../../common/command/command.qh"
#include "banning.qh"
-#include "../_all.qh"
#include "common.qh"
#include "../../common/command/command.qh"
#include "cmd.qh"
-#include "../_all.qh"
#include "common.qh"
#include "vote.qh"
#include "../../common/deathtypes/all.qh"
#include "../../common/mapinfo.qh"
#include "../../common/notifications.qh"
+#include "../../common/physics.qh"
#include "../../common/teams.qh"
#include "../../common/util.qh"
+#include "../../common/triggers/triggers.qh"
+
+#include "../../common/minigames/sv_minigames.qh"
#include "../../common/monsters/all.qc"
#include "../../common/monsters/spawn.qh"
#include "../../common/monsters/sv_monsters.qh"
-#include "../../warpzonelib/common.qh"
+#include "../../lib/warpzone/common.qh"
void ClientKill_TeamChange (float targetteam); // 0 = don't change, -1 = auto, -2 = spec
.float cmd_floodcount;
.float lms_spectate_warning;
-// number of monsters spawned with mobspawn command
-float totalspawned;
-
string MapVote_Suggest(string m);
// used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
#include "../../common/command/command.qh"
#include "common.qh"
-#include "../_all.qh"
#include "../scores.qh"
+#include "../../common/monsters/all.qh"
#include "../../common/notifications.qh"
+#include "../../lib/warpzone/common.qh"
// ====================================================
#include "../../common/command/command.qh"
#include "getreplies.qh"
-#include "../_all.qh"
#include "../race.qh"
#include "../../common/command/command.qh"
#include "radarmap.qh"
-#include "../_all.qh"
#include "../g_world.qh"
+#include "../g_subs.qh"
#include "../../common/util.qh"
-#include "../../csqcmodellib/sv_model.qh"
+#include "../../lib/csqcmodel/sv_model.qh"
// ===============================================
// Generates radar map images for use in the HUD
#include "../../common/command/command.qh"
#include "sv_cmd.qh"
-#include "../_all.qh"
#include "banning.qh"
#include "cmd.qh"
#include "../../common/command/command.qh"
#include "vote.qh"
-#include "../_all.qh"
#include "common.qh"
#include "controlpoint.qh"
+#include "command/common.qh"
+
+.bool iscaptured;
+
bool cpicon_send(entity this, entity to, int sf)
{
WriteByte(MSG_ENTITY, ENT_CLIENT_CONTROLPOINT_ICON);
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
#include "../common/constants.qh"
#endif
#include "ent_cs.qh"
-#include "_all.qh"
+
+#include "mutators/gamemode_ca.qh"
float entcs_customize()
{
#include "g_damage.qh"
-#include "_all.qh"
+#include "bot/bot.qh"
#include "g_hook.qh"
#include "mutators/mutators_include.qh"
#include "scores.qh"
#include "spawnpoints.qh"
#include "t_items.qh"
#include "../common/vehicles/all.qh"
+#include "../common/items/all.qc"
+#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
#include "weapons/accuracy.qh"
#include "weapons/csqcprojectile.qh"
#include "weapons/selection.qh"
#include "../common/teams.qh"
#include "../common/util.qh"
#include "../common/weapons/all.qh"
-#include "../csqcmodellib/sv_model.qh"
-#include "../warpzonelib/common.qh"
+#include "../lib/csqcmodel/sv_model.qh"
+#include "../lib/warpzone/common.qh"
bool Damage_DamageInfo_SendEntity(entity this, entity to, int sf)
{
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../warpzonelib/common.qh"
+ #include "../lib/warpzone/common.qh"
#include "../common/constants.qh"
#include "../common/teams.qh"
#include "../common/util.qh"
#include "mutators/mutators_include.qh"
#include "../common/turrets/sv_turrets.qh"
#include "../common/vehicles/all.qh"
- #include "../csqcmodellib/sv_model.qh"
+ #include "../lib/csqcmodel/sv_model.qh"
#include "../common/playerstats.qh"
#include "g_hook.qh"
#include "scores.qh"
#include "g_hook.qh"
-#include "_all.qh"
#include "weapons/common.qh"
+#include "weapons/csqcprojectile.qh"
#include "weapons/weaponsystem.qh"
#include "weapons/selection.qh"
#include "weapons/tracing.qh"
#include "../common/constants.qh"
#include "../common/util.qh"
#include "../common/weapons/all.qh"
-#include "../warpzonelib/common.qh"
-#include "../warpzonelib/server.qh"
+#include "../lib/warpzone/common.qh"
+#include "../lib/warpzone/server.qh"
+
+.int state;
/*============================================
-#include "_all.qh"
void train_next();
const float LOOP = 1;
+.float speed;
+
const float DNOSHADOW = 2;
const float DFOLLOW = 4;
.float light_lev;
-#include "_all.qh"
+#include "g_subs.qh"
#include "../common/triggers/subs.qh"
+#include "../common/triggers/triggers.qh"
-#include "../client/bgmscript.qh"
+entityclass(BGMScript);
+class(BGMScript) .string bgmscript;
+class(BGMScript) .float bgmscriptattack;
+class(BGMScript) .float bgmscriptdecay;
+class(BGMScript) .float bgmscriptsustain;
+class(BGMScript) .float bgmscriptrelease;
#include "../common/constants.qh"
-#include "../csqcmodellib/sv_model.qh"
+#include "../lib/csqcmodel/sv_model.qh"
.float modelscale;
#include "g_subs.qh"
-#include "_all.qh"
#include "antilag.qh"
#include "command/common.qh"
-#include "../warpzonelib/common.qh"
+#include "../lib/warpzone/common.qh"
+#include "../common/triggers/subs.qh"
spawnfunc(info_null)
{
#include "g_violence.qh"
-#include "_all.qh"
+
+.int state;
bool Violence_GibSplash_SendEntity(entity this, entity to, int sf)
{
#include "g_world.qh"
-#include "_all.qh"
#include "anticheat.qh"
#include "antilag.qh"
#include "../common/buffs/all.qh"
#include "../common/constants.qh"
#include "../common/deathtypes/all.qh"
-#include "../common/effects/effects.qh"
#include "../common/mapinfo.qh"
#include "../common/monsters/all.qh"
#include "../common/monsters/sv_monsters.qh"
#include "../common/vehicles/all.qh"
#include "../common/notifications.qh"
+#include "../common/physics.qh"
#include "../common/playerstats.qh"
#include "../common/stats.qh"
#include "../common/teams.qh"
+#include "../common/triggers/trigger/secret.qh"
#include "../common/util.qh"
#include "../common/items/all.qh"
#include "../common/weapons/all.qh"
// needs to be done so early because of the constants they create
static_init();
- CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid));
#include "ipban.qh"
-#include "_all.qh"
#include "autocvars.qh"
#include "command/banning.qh"
#include "defs.qh"
#include "../common/constants.qh"
#include "../common/util.qh"
-#include "../dpdefs/dpextensions.qh"
-#include "../dpdefs/progsdefs.qh"
/*
* Protocol of online ban list:
#include "item_key.qh"
-#include "_all.qh"
#include "../common/triggers/subs.qh"
#include "../common/monsters/all.qh"
#include "../common/notifications.qh"
#include "../common/util.qh"
-#include "../warpzonelib/util_server.qh"
+#include "../lib/warpzone/util_server.qh"
/*
TODO:
#include "mapvoting.qh"
-#include "_all.qh"
#include "g_world.qh"
#include "command/cmd.qh"
#include "miscfunctions.qh"
-#include "_all.qh"
#include "antilag.qh"
#include "command/common.qh"
#include "constants.qh"
#include "../common/util.qh"
#include "../common/turrets/sv_turrets.qh"
#include "../common/weapons/all.qh"
-#include "../csqcmodellib/sv_model.qh"
-#include "../warpzonelib/anglestransform.qh"
-#include "../warpzonelib/server.qh"
+#include "../common/vehicles/sv_vehicles.qh"
+#include "../common/vehicles/vehicle.qh"
+#include "../common/items/all.qc"
+#include "../lib/csqcmodel/sv_model.qh"
+#include "../lib/warpzone/anglestransform.qh"
+#include "../lib/warpzone/server.qh"
void crosshair_trace(entity pl)
{
#include "../round_handler.qh"
#include "../scores.qh"
#include "../scores_rules.qh"
+#include "../teamplay.qh"
#include "../bot/bot.qh"
#include "../bot/navigation.qh"
#include "../../common/stats.qh"
#include "../../common/teams.qh"
-#include "../../warpzonelib/server.qh"
-#include "../../warpzonelib/util_server.qh"
+#include "../../lib/warpzone/server.qh"
+#include "../../lib/warpzone/util_server.qh"
.float lastground;
float total_players;
#include "gamemode_assault.qh"
-#include "../_all.qh"
#include "gamemode.qh"
}
// destructible walls that can be used to trigger target_objective_decrease
+spawnfunc(func_breakable);
spawnfunc(func_assault_destructible)
{
if (!g_assault) { remove(self); return; }
#include "gamemode_ca.qh"
-#include "../_all.qh"
#include "gamemode.qh"
#include "gamemode_ctf.qh"
-#include "../_all.qh"
#include "gamemode.qh"
#ifdef SVQC
#include "../../common/vehicles/all.qh"
+#include "../teamplay.qh"
#endif
-#include "../../warpzonelib/common.qh"
+#include "../../lib/warpzone/common.qh"
void ctf_FakeTimeLimit(entity e, float t)
{
// compatibility for quake maps
spawnfunc(team_CTF_redflag) { spawnfunc_item_flag_team1(this); }
spawnfunc(team_CTF_blueflag) { spawnfunc_item_flag_team2(this); }
+spawnfunc(info_player_team1);
spawnfunc(team_CTF_redplayer) { spawnfunc_info_player_team1(this); }
-spawnfunc(team_CTF_blueplayer) { spawnfunc_info_player_team2(this); }
spawnfunc(team_CTF_redspawn) { spawnfunc_info_player_team1(this); }
+spawnfunc(info_player_team2);
+spawnfunc(team_CTF_blueplayer) { spawnfunc_info_player_team2(this); }
spawnfunc(team_CTF_bluespawn) { spawnfunc_info_player_team2(this); }
void team_CTF_neutralflag() { SELFPARAM(); spawnfunc_item_flag_neutral(self); }
#include "gamemode_cts.qh"
-#include "../_all.qh"
#include "gamemode.qh"
+#include "gamemode.qh"
+
MUTATOR_HOOKFUNCTION(dm_CountFrags)
{
// announce remaining frags
#include "gamemode_domination.qh"
-#include "../_all.qh"
#include "gamemode.qh"
+#include "../teamplay.qh"
+
void dom_EventLog(string mode, float team_before, entity actor) // use an alias for easy changing and quick editing later
{
if(autocvar_sv_eventlog)
WaypointSprite_SpawnFixed(WP_DomNeut, self.origin + '0 0 32', self, sprite, RADARICON_DOMPOINT);
}
-float total_controlpoints, redowned, blueowned, yellowowned, pinkowned;
+float total_controlpoints;
void Domination_count_controlpoints()
{
entity e;
#include "gamemode_freezetag.qh"
-#include "../_all.qh"
#include "gamemode.qh"
#include "gamemode_invasion.qh"
-#include "../_all.qh"
#include "gamemode.qh"
#include "../../common/monsters/spawn.qh"
#include "../../common/monsters/sv_monsters.qh"
+#include "../teamplay.qh"
+
spawnfunc(invasion_spawnpoint)
{
if(!g_invasion) { remove(self); return; }
#include "gamemode_keepaway.qh"
-#include "../_all.qh"
#include "gamemode.qh"
return 0;
}
+.float stat_sv_airspeedlimit_nonqw;
+.float stat_sv_maxspeed;
+
MUTATOR_HOOKFUNCTION(ka_PlayerPhysics)
{SELFPARAM();
if(self.ballcarried)
#include "gamemode_keyhunt.qh"
-#include "../_all.qh"
#include "gamemode.qh"
#include "gamemode_lms.qh"
-#include "../_all.qh"
#include "gamemode.qh"
+++ /dev/null
-#include "gamemode_nexball.qh"
-#include "../_all.qh"
-
-#include "gamemode.qh"
-
-float autocvar_g_nexball_basketball_bouncefactor;
-float autocvar_g_nexball_basketball_bouncestop;
-float autocvar_g_nexball_basketball_carrier_highspeed;
-bool autocvar_g_nexball_basketball_meter;
-float autocvar_g_nexball_basketball_meter_maxpower;
-float autocvar_g_nexball_basketball_meter_minpower;
-float autocvar_g_nexball_delay_collect;
-float autocvar_g_nexball_delay_goal;
-float autocvar_g_nexball_delay_start;
-float autocvar_g_nexball_football_bouncefactor;
-float autocvar_g_nexball_football_bouncestop;
-bool autocvar_g_nexball_radar_showallplayers;
-bool autocvar_g_nexball_sound_bounce;
-int autocvar_g_nexball_trail_color;
-
-float autocvar_g_nexball_safepass_turnrate;
-float autocvar_g_nexball_safepass_maxdist;
-float autocvar_g_nexball_safepass_holdtime;
-float autocvar_g_nexball_viewmodel_scale;
-float autocvar_g_nexball_tackling;
-vector autocvar_g_nexball_viewmodel_offset;
-
-void basketball_touch();
-void football_touch();
-void ResetBall();
-const float NBM_NONE = 0;
-const float NBM_FOOTBALL = 2;
-const float NBM_BASKETBALL = 4;
-float nexball_mode;
-
-float OtherTeam(float t) //works only if there are two teams on the map!
-{
- entity e;
- e = find(world, classname, "nexball_team");
- if(e.team == t)
- e = find(e, classname, "nexball_team");
- return e.team;
-}
-
-const float ST_NEXBALL_GOALS = 1;
-const float SP_NEXBALL_GOALS = 4;
-const float SP_NEXBALL_FAULTS = 5;
-void nb_ScoreRules(float teams)
-{
- ScoreRules_basics(teams, 0, 0, true);
- ScoreInfo_SetLabel_TeamScore( ST_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore( SP_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
- ScoreInfo_SetLabel_PlayerScore(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER);
- ScoreRules_basics_end();
-}
-
-void LogNB(string mode, entity actor)
-{
- string s;
- if(!autocvar_sv_eventlog)
- return;
- s = strcat(":nexball:", mode);
- if(actor != world)
- s = strcat(s, ":", ftos(actor.playerid));
- GameLogEcho(s);
-}
-
-void ball_restart(void)
-{SELFPARAM();
- if(self.owner)
- DropBall(self, self.owner.origin, '0 0 0');
- ResetBall();
-}
-
-void nexball_setstatus(void)
-{SELFPARAM();
- self.items &= ~IT_KEY1;
- if(self.ballcarried)
- {
- if(self.ballcarried.teamtime && (self.ballcarried.teamtime < time))
- {
- bprint("The ", Team_ColoredFullName(self.team), " held the ball for too long.\n");
- setself(self.ballcarried);
- DropBall(self, self.owner.origin, '0 0 0');
- ResetBall();
- setself(this);
- }
- else
- self.items |= IT_KEY1;
- }
-}
-
-void relocate_nexball(void)
-{SELFPARAM();
- tracebox(self.origin, BALL_MINS, BALL_MAXS, self.origin, true, self);
- if(trace_startsolid)
- {
- vector o;
- o = self.origin;
- if(!move_out_of_solid(self))
- objerror("could not get out of solid at all!");
- LOG_INFO("^1NOTE: this map needs FIXING. ", self.classname, " at ", vtos(o - '0 0 1'));
- LOG_INFO(" needs to be moved out of solid, e.g. by '", ftos(self.origin.x - o.x));
- LOG_INFO(" ", ftos(self.origin.y - o.y));
- LOG_INFO(" ", ftos(self.origin.z - o.z), "'\n");
- self.origin = o;
- }
-}
-
-void DropOwner(void)
-{SELFPARAM();
- entity ownr;
- ownr = self.owner;
- DropBall(self, ownr.origin, ownr.velocity);
- makevectors(ownr.v_angle.y * '0 1 0');
- ownr.velocity += ('0 0 0.75' - v_forward) * 1000;
- ownr.flags &= ~FL_ONGROUND;
-}
-
-void GiveBall(entity plyr, entity ball)
-{SELFPARAM();
- entity ownr;
-
- if((ownr = ball.owner))
- {
- ownr.effects &= ~autocvar_g_nexball_basketball_effects_default;
- ownr.ballcarried = world;
- if(ownr.metertime)
- {
- ownr.metertime = 0;
- ownr.weaponentity.state = WS_READY;
- }
- WaypointSprite_Kill(ownr.waypointsprite_attachedforcarrier);
- }
- else
- {
- WaypointSprite_Kill(ball.waypointsprite_attachedforcarrier);
- }
-
- //setattachment(ball, plyr, "");
- setorigin(ball, plyr.origin + plyr.view_ofs);
-
- if(ball.team != plyr.team)
- ball.teamtime = time + autocvar_g_nexball_basketball_delay_hold_forteam;
-
- ball.owner = ball.pusher = plyr; //"owner" is set to the player carrying, "pusher" to the last player who touched it
- ball.team = plyr.team;
- plyr.ballcarried = ball;
- ball.nb_dropper = plyr;
-
- plyr.effects |= autocvar_g_nexball_basketball_effects_default;
- ball.effects &= ~autocvar_g_nexball_basketball_effects_default;
-
- ball.velocity = '0 0 0';
- ball.movetype = MOVETYPE_NONE;
- ball.touch = func_null;
- ball.effects |= EF_NOSHADOW;
- ball.scale = 1; // scale down.
-
- WaypointSprite_AttachCarrier(WP_NbBall, plyr, RADARICON_FLAGCARRIER);
- WaypointSprite_UpdateRule(plyr.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
-
- if(autocvar_g_nexball_basketball_delay_hold)
- {
- ball.think = DropOwner;
- ball.nextthink = time + autocvar_g_nexball_basketball_delay_hold;
- }
-
- plyr.weaponentity.weapons = plyr.weapons;
- plyr.weaponentity.switchweapon = plyr.weapon;
- plyr.weapons = WEPSET(NEXBALL);
- setself(plyr);
- Weapon w = WEP_NEXBALL;
- w.wr_resetplayer(w);
- plyr.switchweapon = WEP_NEXBALL.m_id;
- W_SwitchWeapon(WEP_NEXBALL.m_id);
- setself(this);
-}
-
-void DropBall(entity ball, vector org, vector vel)
-{
- ball.effects |= autocvar_g_nexball_basketball_effects_default;
- ball.effects &= ~EF_NOSHADOW;
- ball.owner.effects &= ~autocvar_g_nexball_basketball_effects_default;
-
- setattachment(ball, world, "");
- setorigin(ball, org);
- ball.movetype = MOVETYPE_BOUNCE;
- ball.flags &= ~FL_ONGROUND;
- ball.scale = ball_scale;
- ball.velocity = vel;
- ball.nb_droptime = time;
- ball.touch = basketball_touch;
- ball.think = ResetBall;
- ball.nextthink = min(time + autocvar_g_nexball_delay_idle, ball.teamtime);
-
- if(ball.owner.metertime)
- {
- ball.owner.metertime = 0;
- ball.owner.weaponentity.state = WS_READY;
- }
-
- WaypointSprite_Kill(ball.owner.waypointsprite_attachedforcarrier);
- WaypointSprite_Spawn(WP_NbBall, 0, 0, ball, '0 0 64', world, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER); // no health bar please
- WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
-
- ball.owner.ballcarried = world;
- ball.owner = world;
-}
-
-void InitBall(void)
-{SELFPARAM();
- if(gameover) return;
- self.flags &= ~FL_ONGROUND;
- self.movetype = MOVETYPE_BOUNCE;
- if(self.classname == "nexball_basketball")
- self.touch = basketball_touch;
- else if(self.classname == "nexball_football")
- self.touch = football_touch;
- self.cnt = 0;
- self.think = ResetBall;
- self.nextthink = time + autocvar_g_nexball_delay_idle + 3;
- self.teamtime = 0;
- self.pusher = world;
- self.team = false;
- _sound(self, CH_TRIGGER, self.noise1, VOL_BASE, ATTEN_NORM);
- WaypointSprite_Ping(self.waypointsprite_attachedforcarrier);
- LogNB("init", world);
-}
-
-void ResetBall(void)
-{SELFPARAM();
- if(self.cnt < 2) // step 1
- {
- if(time == self.teamtime)
- bprint("The ", Team_ColoredFullName(self.team), " held the ball for too long.\n");
-
- self.touch = func_null;
- self.movetype = MOVETYPE_NOCLIP;
- self.velocity = '0 0 0'; // just in case?
- if(!self.cnt)
- LogNB("resetidle", world);
- self.cnt = 2;
- self.nextthink = time;
- }
- else if(self.cnt < 4) // step 2 and 3
- {
-// dprint("Step ", ftos(self.cnt), ": Calculated velocity: ", vtos(self.spawnorigin - self.origin), ", time: ", ftos(time), "\n");
- self.velocity = (self.spawnorigin - self.origin) * (self.cnt - 1); // 1 or 0.5 second movement
- self.nextthink = time + 0.5;
- self.cnt += 1;
- }
- else // step 4
- {
-// dprint("Step 4: time: ", ftos(time), "\n");
- if(vlen(self.origin - self.spawnorigin) > 10) // should not happen anymore
- LOG_TRACE("The ball moved too far away from its spawn origin.\nOffset: ",
- vtos(self.origin - self.spawnorigin), " Velocity: ", vtos(self.velocity), "\n");
- self.velocity = '0 0 0';
- setorigin(self, self.spawnorigin); // make sure it's positioned correctly anyway
- self.movetype = MOVETYPE_NONE;
- self.think = InitBall;
- self.nextthink = max(time, game_starttime) + autocvar_g_nexball_delay_start;
- }
-}
-
-void football_touch(void)
-{SELFPARAM();
- if(other.solid == SOLID_BSP)
- {
- if(time > self.lastground + 0.1)
- {
- _sound(self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
- self.lastground = time;
- }
- if(vlen(self.velocity) && !self.cnt)
- self.nextthink = time + autocvar_g_nexball_delay_idle;
- return;
- }
- if (!IS_PLAYER(other))
- return;
- if(other.health < 1)
- return;
- if(!self.cnt)
- self.nextthink = time + autocvar_g_nexball_delay_idle;
-
- self.pusher = other;
- self.team = other.team;
-
- if(autocvar_g_nexball_football_physics == -1) // MrBougo try 1, before decompiling Rev's original
- {
- if(vlen(other.velocity))
- self.velocity = other.velocity * 1.5 + '0 0 1' * autocvar_g_nexball_football_boost_up;
- }
- else if(autocvar_g_nexball_football_physics == 1) // MrBougo's modded Rev style: partially independant of the height of the aiming point
- {
- makevectors(other.v_angle);
- self.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + '0 0 1' * autocvar_g_nexball_football_boost_up;
- }
- else if(autocvar_g_nexball_football_physics == 2) // 2nd mod try: totally independant. Really playable!
- {
- makevectors(other.v_angle.y * '0 1 0');
- self.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
- }
- else // Revenant's original style (from the original mod's disassembly, acknowledged by Revenant)
- {
- makevectors(other.v_angle);
- self.velocity = other.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
- }
- self.avelocity = -250 * v_forward; // maybe there is a way to make it look better?
-}
-
-void basketball_touch(void)
-{SELFPARAM();
- if(other.ballcarried)
- {
- football_touch();
- return;
- }
- if(!self.cnt && IS_PLAYER(other) && !other.frozen && !other.deadflag && (other != self.nb_dropper || time > self.nb_droptime + autocvar_g_nexball_delay_collect))
- {
- if(other.health <= 0)
- return;
- LogNB("caught", other);
- GiveBall(other, self);
- }
- else if(other.solid == SOLID_BSP)
- {
- _sound(self, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NORM);
- if(vlen(self.velocity) && !self.cnt)
- self.nextthink = min(time + autocvar_g_nexball_delay_idle, self.teamtime);
- }
-}
-
-void GoalTouch(void)
-{SELFPARAM();
- entity ball;
- float isclient, pscore, otherteam;
- string pname;
-
- if(gameover) return;
- if((self.spawnflags & GOAL_TOUCHPLAYER) && other.ballcarried)
- ball = other.ballcarried;
- else
- ball = other;
- if(ball.classname != "nexball_basketball")
- if(ball.classname != "nexball_football")
- return;
- if((!ball.pusher && self.team != GOAL_OUT) || ball.cnt)
- return;
- EXACTTRIGGER_TOUCH;
-
-
- if(nb_teams == 2)
- otherteam = OtherTeam(ball.team);
- else
- otherteam = 0;
-
- if((isclient = IS_CLIENT(ball.pusher)))
- pname = ball.pusher.netname;
- else
- pname = "Someone (?)";
-
- if(ball.team == self.team) //owngoal (regular goals)
- {
- LogNB("owngoal", ball.pusher);
- bprint("Boo! ", pname, "^7 scored a goal against their own team!\n");
- pscore = -1;
- }
- else if(self.team == GOAL_FAULT)
- {
- LogNB("fault", ball.pusher);
- if(nb_teams == 2)
- bprint(Team_ColoredFullName(otherteam), " gets a point due to ", pname, "^7's silliness.\n");
- else
- bprint(Team_ColoredFullName(ball.team), " loses a point due to ", pname, "^7's silliness.\n");
- pscore = -1;
- }
- else if(self.team == GOAL_OUT)
- {
- LogNB("out", ball.pusher);
- if((self.spawnflags & GOAL_TOUCHPLAYER) && ball.owner)
- bprint(pname, "^7 went out of bounds.\n");
- else
- bprint("The ball was returned.\n");
- pscore = 0;
- }
- else //score
- {
- LogNB(strcat("goal:", ftos(self.team)), ball.pusher);
- bprint("Goaaaaal! ", pname, "^7 scored a point for the ", Team_ColoredFullName(ball.team), ".\n");
- pscore = 1;
- }
-
- _sound(ball, CH_TRIGGER, self.noise, VOL_BASE, ATTEN_NONE);
-
- if(ball.team && pscore)
- {
- if(nb_teams == 2 && pscore < 0)
- TeamScore_AddToTeam(otherteam, ST_NEXBALL_GOALS, -pscore);
- else
- TeamScore_AddToTeam(ball.team, ST_NEXBALL_GOALS, pscore);
- }
- if(isclient)
- {
- if(pscore > 0)
- PlayerScore_Add(ball.pusher, SP_NEXBALL_GOALS, pscore);
- else if(pscore < 0)
- PlayerScore_Add(ball.pusher, SP_NEXBALL_FAULTS, -pscore);
- }
-
- if(ball.owner) // Happens on spawnflag GOAL_TOUCHPLAYER
- DropBall(ball, ball.owner.origin, ball.owner.velocity);
-
- WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);
-
- ball.cnt = 1;
- ball.think = ResetBall;
- if(ball.classname == "nexball_basketball")
- ball.touch = football_touch; // better than func_null: football control until the ball gets reset
- ball.nextthink = time + autocvar_g_nexball_delay_goal * (self.team != GOAL_OUT);
-}
-
-//=======================//
-// team ents //
-//=======================//
-spawnfunc(nexball_team)
-{
- if(!g_nexball)
- {
- remove(self);
- return;
- }
- self.team = self.cnt + 1;
-}
-
-void nb_spawnteam(string teamname, float teamcolor)
-{
- LOG_TRACE("^2spawned team ", teamname, "\n");
- entity e;
- e = spawn();
- e.classname = "nexball_team";
- e.netname = teamname;
- e.cnt = teamcolor;
- e.team = e.cnt + 1;
- nb_teams += 1;
-}
-
-void nb_spawnteams(void)
-{
- bool t_red = false, t_blue = false, t_yellow = false, t_pink = false;
- entity e;
- for(e = world; (e = find(e, classname, "nexball_goal"));)
- {
- switch(e.team)
- {
- case NUM_TEAM_1:
- if(!t_red)
- {
- nb_spawnteam("Red", e.team-1) ;
- t_red = true;
- }
- break;
- case NUM_TEAM_2:
- if(!t_blue)
- {
- nb_spawnteam("Blue", e.team-1) ;
- t_blue = true;
- }
- break;
- case NUM_TEAM_3:
- if(!t_yellow)
- {
- nb_spawnteam("Yellow", e.team-1);
- t_yellow = true;
- }
- break;
- case NUM_TEAM_4:
- if(!t_pink)
- {
- nb_spawnteam("Pink", e.team-1) ;
- t_pink = true;
- }
- break;
- }
- }
-}
-
-void nb_delayedinit(void)
-{
- if(find(world, classname, "nexball_team") == world)
- nb_spawnteams();
- nb_ScoreRules(nb_teams);
-}
-
-
-//=======================//
-// spawnfuncs //
-//=======================//
-
-void SpawnBall(void)
-{SELFPARAM();
- if(!g_nexball) { remove(self); return; }
-
-// balls += 4; // using the remaining bits to count balls will leave more than the max edict count, so it's fine
-
- if(self.model == "")
- {
- self.model = "models/nexball/ball.md3";
- self.scale = 1.3;
- }
-
- precache_model(self.model);
- _setmodel(self, self.model);
- setsize(self, BALL_MINS, BALL_MAXS);
- ball_scale = self.scale;
-
- relocate_nexball();
- self.spawnorigin = self.origin;
-
- self.effects = self.effects | EF_LOWPRECISION;
-
- if(cvar(strcat("g_", self.classname, "_trail"))) //nexball_basketball :p
- {
- self.glow_color = autocvar_g_nexball_trail_color;
- self.glow_trail = true;
- }
-
- self.movetype = MOVETYPE_FLY;
-
- if(!autocvar_g_nexball_sound_bounce)
- self.noise = "";
- else if(self.noise == "")
- self.noise = SND(NB_BOUNCE);
- //bounce sound placeholder (FIXME)
- if(self.noise1 == "")
- self.noise1 = SND(NB_DROP);
- //ball drop sound placeholder (FIXME)
- if(self.noise2 == "")
- self.noise2 = SND(NB_STEAL);
- //stealing sound placeholder (FIXME)
- if(self.noise) precache_sound(self.noise);
- precache_sound(self.noise1);
- precache_sound(self.noise2);
-
- WaypointSprite_AttachCarrier(WP_NbBall, self, RADARICON_FLAGCARRIER); // the ball's team is not set yet, no rule update needed
-
- self.reset = ball_restart;
- self.think = InitBall;
- self.nextthink = game_starttime + autocvar_g_nexball_delay_start;
-}
-
-spawnfunc(nexball_basketball)
-{
- nexball_mode |= NBM_BASKETBALL;
- self.classname = "nexball_basketball";
- if (!(balls & BALL_BASKET))
- {
- /*
- CVTOV(g_nexball_basketball_effects_default);
- CVTOV(g_nexball_basketball_delay_hold);
- CVTOV(g_nexball_basketball_delay_hold_forteam);
- CVTOV(g_nexball_basketball_teamsteal);
- */
- autocvar_g_nexball_basketball_effects_default = autocvar_g_nexball_basketball_effects_default & BALL_EFFECTMASK;
- }
- if(!self.effects)
- self.effects = autocvar_g_nexball_basketball_effects_default;
- self.solid = SOLID_TRIGGER;
- balls |= BALL_BASKET;
- self.bouncefactor = autocvar_g_nexball_basketball_bouncefactor;
- self.bouncestop = autocvar_g_nexball_basketball_bouncestop;
- SpawnBall();
-}
-
-spawnfunc(nexball_football)
-{
- nexball_mode |= NBM_FOOTBALL;
- self.classname = "nexball_football";
- self.solid = SOLID_TRIGGER;
- balls |= BALL_FOOT;
- self.bouncefactor = autocvar_g_nexball_football_bouncefactor;
- self.bouncestop = autocvar_g_nexball_football_bouncestop;
- SpawnBall();
-}
-
-float nb_Goal_Customize()
-{SELFPARAM();
- entity e, wp_owner;
- e = WaypointSprite_getviewentity(other);
- wp_owner = self.owner;
- if(SAME_TEAM(e, wp_owner)) { return false; }
-
- return true;
-}
-
-void SpawnGoal(void)
-{SELFPARAM();
- if(!g_nexball) { remove(self); return; }
-
- EXACTTRIGGER_INIT;
-
- if(self.team != GOAL_OUT && Team_TeamToNumber(self.team) != -1)
- {
- entity wp = WaypointSprite_SpawnFixed(WP_NbGoal, (self.absmin + self.absmax) * 0.5, self, sprite, RADARICON_NONE);
- wp.colormod = ((self.team) ? Team_ColorRGB(self.team) : '1 0.5 0');
- self.sprite.customizeentityforclient = nb_Goal_Customize;
- }
-
- self.classname = "nexball_goal";
- if(self.noise == "")
- self.noise = "ctf/respawn.wav";
- precache_sound(self.noise);
- self.touch = GoalTouch;
-}
-
-spawnfunc(nexball_redgoal)
-{
- self.team = NUM_TEAM_1;
- SpawnGoal();
-}
-spawnfunc(nexball_bluegoal)
-{
- self.team = NUM_TEAM_2;
- SpawnGoal();
-}
-spawnfunc(nexball_yellowgoal)
-{
- self.team = NUM_TEAM_3;
- SpawnGoal();
-}
-spawnfunc(nexball_pinkgoal)
-{
- self.team = NUM_TEAM_4;
- SpawnGoal();
-}
-
-spawnfunc(nexball_fault)
-{
- self.team = GOAL_FAULT;
- if(self.noise == "")
- self.noise = SND(TYPEHIT);
- SpawnGoal();
-}
-
-spawnfunc(nexball_out)
-{
- self.team = GOAL_OUT;
- if(self.noise == "")
- self.noise = SND(TYPEHIT);
- SpawnGoal();
-}
-
-//
-//Spawnfuncs preserved for compatibility
-//
-
-spawnfunc(ball)
-{
- spawnfunc_nexball_football(this);
-}
-spawnfunc(ball_football)
-{
- spawnfunc_nexball_football(this);
-}
-spawnfunc(ball_basketball)
-{
- spawnfunc_nexball_basketball(this);
-}
-// The "red goal" is defended by blue team. A ball in there counts as a point for red.
-spawnfunc(ball_redgoal)
-{
- spawnfunc_nexball_bluegoal(this); // I blame Revenant
-}
-spawnfunc(ball_bluegoal)
-{
- spawnfunc_nexball_redgoal(this); // but he didn't mean to cause trouble :p
-}
-spawnfunc(ball_fault)
-{
- spawnfunc_nexball_fault(this);
-}
-spawnfunc(ball_bound)
-{
- spawnfunc_nexball_out(this);
-}
-
-//=======================//
-// Weapon code //
-//=======================//
-
-
-void W_Nexball_Think()
-{SELFPARAM();
- //dprint("W_Nexball_Think\n");
- //vector new_dir = steerlib_arrive(self.enemy.origin, 2500);
- vector new_dir = normalize(self.enemy.origin + '0 0 50' - self.origin);
- vector old_dir = normalize(self.velocity);
- float _speed = vlen(self.velocity);
- vector new_vel = normalize(old_dir + (new_dir * autocvar_g_nexball_safepass_turnrate)) * _speed;
- //vector new_vel = (new_dir * autocvar_g_nexball_safepass_turnrate
-
- self.velocity = new_vel;
-
- self.nextthink = time;
-}
-
-void W_Nexball_Touch(void)
-{SELFPARAM();
- entity ball, attacker;
- attacker = self.owner;
- //self.think = func_null;
- //self.enemy = world;
-
- PROJECTILE_TOUCH;
- if(attacker.team != other.team || autocvar_g_nexball_basketball_teamsteal)
- if((ball = other.ballcarried) && !other.frozen && !other.deadflag && (IS_PLAYER(attacker)))
- {
- other.velocity = other.velocity + normalize(self.velocity) * other.damageforcescale * autocvar_g_balance_nexball_secondary_force;
- other.flags &= ~FL_ONGROUND;
- if(!attacker.ballcarried)
- {
- LogNB("stole", attacker);
- _sound(other, CH_TRIGGER, ball.noise2, VOL_BASE, ATTEN_NORM);
-
- if(SAME_TEAM(attacker, other) && time > attacker.teamkill_complain)
- {
- attacker.teamkill_complain = time + 5;
- attacker.teamkill_soundtime = time + 0.4;
- attacker.teamkill_soundsource = other;
- }
-
- GiveBall(attacker, other.ballcarried);
- }
- }
- remove(self);
-}
-
-void W_Nexball_Attack(float t)
-{SELFPARAM();
- entity ball;
- float mul, mi, ma;
- if(!(ball = self.ballcarried))
- return;
-
- W_SetupShot(self, false, 4, SND(NB_SHOOT1), CH_WEAPON_A, 0);
- tracebox(w_shotorg, BALL_MINS, BALL_MAXS, w_shotorg, MOVE_WORLDONLY, world);
- if(trace_startsolid)
- {
- if(self.metertime)
- self.metertime = 0; // Shot failed, hide the power meter
- return;
- }
-
- //Calculate multiplier
- if(t < 0)
- mul = 1;
- else
- {
- mi = autocvar_g_nexball_basketball_meter_minpower;
- ma = max(mi, autocvar_g_nexball_basketball_meter_maxpower); // avoid confusion
- //One triangle wave period with 1 as max
- mul = 2 * (t % g_nexball_meter_period) / g_nexball_meter_period;
- if(mul > 1)
- mul = 2 - mul;
- mul = mi + (ma - mi) * mul; // range from the minimal power to the maximal power
- }
-
- DropBall(ball, w_shotorg, W_CalculateProjectileVelocity(self.velocity, w_shotdir * autocvar_g_balance_nexball_primary_speed * mul, false));
-
-
- //TODO: use the speed_up cvar too ??
-}
-
-void W_Nexball_Attack2(void)
-{SELFPARAM();
- if(self.ballcarried.enemy)
- {
- entity _ball = self.ballcarried;
- W_SetupShot(self, false, 4, SND(NB_SHOOT1), CH_WEAPON_A, 0);
- DropBall(_ball, w_shotorg, trigger_push_calculatevelocity(_ball.origin, _ball.enemy, 32));
- _ball.think = W_Nexball_Think;
- _ball.nextthink = time;
- return;
- }
-
- if(!autocvar_g_nexball_tackling)
- return;
-
- W_SetupShot(self, false, 2, SND(NB_SHOOT2), CH_WEAPON_A, 0);
- entity missile = spawn();
-
- missile.owner = self;
- missile.classname = "ballstealer";
-
- missile.movetype = MOVETYPE_FLY;
- PROJECTILE_MAKETRIGGER(missile);
-
- //setmodel(missile, "models/elaser.mdl"); // precision set below
- setsize(missile, '0 0 0', '0 0 0');
- setorigin(missile, w_shotorg);
-
- W_SetupProjVelocity_Basic(missile, autocvar_g_balance_nexball_secondary_speed, 0);
- missile.angles = vectoangles(missile.velocity);
- missile.touch = W_Nexball_Touch;
- missile.think = SUB_Remove;
- missile.nextthink = time + autocvar_g_balance_nexball_secondary_lifetime; //FIXME: use a distance instead?
-
- missile.effects = EF_BRIGHTFIELD | EF_LOWPRECISION;
- missile.flags = FL_PROJECTILE;
-
- CSQCProjectile(missile, true, PROJECTILE_ELECTRO, true);
-}
-
-float ball_customize()
-{SELFPARAM();
- if(!self.owner)
- {
- self.effects &= ~EF_FLAME;
- self.scale = 1;
- self.customizeentityforclient = func_null;
- return true;
- }
-
- if(other == self.owner)
- {
- self.scale = autocvar_g_nexball_viewmodel_scale;
- if(self.enemy)
- self.effects |= EF_FLAME;
- else
- self.effects &= ~EF_FLAME;
- }
- else
- {
- self.effects &= ~EF_FLAME;
- self.scale = 1;
- }
-
- return true;
-}
-
- METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, bool fire1, bool fire2))
- {
- if(fire1)
- if(weapon_prepareattack(thiswep, actor, false, autocvar_g_balance_nexball_primary_refire))
- if(autocvar_g_nexball_basketball_meter)
- {
- if(self.ballcarried && !self.metertime)
- self.metertime = time;
- else
- weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
- }
- else
- {
- W_Nexball_Attack(-1);
- weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
- }
- if(fire2)
- if(weapon_prepareattack(thiswep, actor, true, autocvar_g_balance_nexball_secondary_refire))
- {
- W_Nexball_Attack2();
- weapon_thinkf(actor, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
- }
-
- if(!fire1 && self.metertime && self.ballcarried)
- {
- W_Nexball_Attack(time - self.metertime);
- // DropBall or stealing will set metertime back to 0
- weapon_thinkf(actor, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
- }
- }
- METHOD(BallStealer, wr_setup, void(BallStealer thiswep))
- {
- //weapon_setup(WEP_PORTO.m_id);
- }
- METHOD(BallStealer, wr_checkammo1, bool(BallStealer thiswep))
- {
- return true;
- }
- METHOD(BallStealer, wr_checkammo2, bool(BallStealer thiswep))
- {
- return true;
- }
-
-MUTATOR_HOOKFUNCTION(nexball_BallDrop)
-{SELFPARAM();
- if(self.ballcarried && g_nexball)
- DropBall(self.ballcarried, self.origin, self.velocity);
-
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(nexball_PlayerPreThink)
-{SELFPARAM();
- makevectors(self.v_angle);
- if(nexball_mode & NBM_BASKETBALL)
- {
- if(self.ballcarried)
- {
- // 'view ball'
- self.ballcarried.velocity = self.velocity;
- self.ballcarried.customizeentityforclient = ball_customize;
-
- setorigin(self.ballcarried, self.origin + self.view_ofs +
- v_forward * autocvar_g_nexball_viewmodel_offset.x +
- v_right * autocvar_g_nexball_viewmodel_offset.y +
- v_up * autocvar_g_nexball_viewmodel_offset.z);
-
- // 'safe passing'
- if(autocvar_g_nexball_safepass_maxdist)
- {
- if(self.ballcarried.wait < time && self.ballcarried.enemy)
- {
- //centerprint(self, sprintf("Lost lock on %s", self.ballcarried.enemy.netname));
- self.ballcarried.enemy = world;
- }
-
-
- //tracebox(self.origin + self.view_ofs, '-2 -2 -2', '2 2 2', self.origin + self.view_ofs + v_forward * autocvar_g_nexball_safepass_maxdist);
- crosshair_trace(self);
- if( trace_ent &&
- IS_CLIENT(trace_ent) &&
- trace_ent.deadflag == DEAD_NO &&
- trace_ent.team == self.team &&
- vlen(trace_ent.origin - self.origin) <= autocvar_g_nexball_safepass_maxdist )
- {
-
- //if(self.ballcarried.enemy != trace_ent)
- // centerprint(self, sprintf("Locked to %s", trace_ent.netname));
- self.ballcarried.enemy = trace_ent;
- self.ballcarried.wait = time + autocvar_g_nexball_safepass_holdtime;
-
-
- }
- }
- }
- else
- {
- if(self.weaponentity.weapons)
- {
- self.weapons = self.weaponentity.weapons;
- Weapon w = WEP_NEXBALL;
- w.wr_resetplayer(w);
- self.switchweapon = self.weaponentity.switchweapon;
- W_SwitchWeapon(self.switchweapon);
-
- self.weaponentity.weapons = '0 0 0';
- }
- }
-
- }
-
- nexball_setstatus();
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nexball_PlayerSpawn)
-{SELFPARAM();
- self.weaponentity.weapons = '0 0 0';
-
- if(nexball_mode & NBM_BASKETBALL)
- self.weapons |= WEPSET(NEXBALL);
- else
- self.weapons = '0 0 0';
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nexball_PlayerPhysics)
-{SELFPARAM();
- if(self.ballcarried)
- {
- self.stat_sv_airspeedlimit_nonqw *= autocvar_g_nexball_basketball_carrier_highspeed;
- self.stat_sv_maxspeed *= autocvar_g_nexball_basketball_carrier_highspeed;
- }
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nexball_ForbidThrowing)
-{SELFPARAM();
- if(self.weapon == WEP_NEXBALL.m_id)
- return true;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nexball_FilterItem)
-{SELFPARAM();
- if(self.classname == "droppedweapon")
- if(self.weapon == WEP_NEXBALL.m_id)
- return true;
-
- return false;
-}
-
-MUTATOR_DEFINITION(gamemode_nexball)
-{
- MUTATOR_HOOK(PlayerDies, nexball_BallDrop, CBC_ORDER_ANY);
- MUTATOR_HOOK(MakePlayerObserver, nexball_BallDrop, CBC_ORDER_ANY);
- MUTATOR_HOOK(ClientDisconnect, nexball_BallDrop, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerSpawn, nexball_PlayerSpawn, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerPreThink, nexball_PlayerPreThink, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerPhysics, nexball_PlayerPhysics, CBC_ORDER_ANY);
- MUTATOR_HOOK(ForbidThrowCurrentWeapon, nexball_ForbidThrowing, CBC_ORDER_ANY);
- MUTATOR_HOOK(FilterItem, nexball_FilterItem, CBC_ORDER_ANY);
-
- MUTATOR_ONADD
- {
- g_nexball_meter_period = autocvar_g_nexball_meter_period;
- if(g_nexball_meter_period <= 0)
- g_nexball_meter_period = 2; // avoid division by zero etc. due to silly users
- g_nexball_meter_period = rint(g_nexball_meter_period * 32) / 32; //Round to 1/32ths to send as a byte multiplied by 32
- addstat(STAT_NB_METERSTART, AS_FLOAT, metertime);
-
- // General settings
- /*
- CVTOV(g_nexball_football_boost_forward); //100
- CVTOV(g_nexball_football_boost_up); //200
- CVTOV(g_nexball_delay_idle); //10
- CVTOV(g_nexball_football_physics); //0
- */
- radar_showennemies = autocvar_g_nexball_radar_showallplayers;
-
- InitializeEntity(world, nb_delayedinit, INITPRIO_GAMETYPE);
- WEP_NEXBALL.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
- }
-
- MUTATOR_ONROLLBACK_OR_REMOVE
- {
- WEP_NEXBALL.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
- // we actually cannot roll back nb_delayedinit here
- // BUT: we don't need to! If this gets called, adding always
- // succeeds.
- }
-
- MUTATOR_ONREMOVE
- {
- LOG_INFO("This is a game type and it cannot be removed at runtime.");
- return -1;
- }
-
- return 0;
-}
+++ /dev/null
-#ifndef GAMEMODE_NEXBALL_H
-#define GAMEMODE_NEXBALL_H
-
-//EF_BRIGHTFIELD|EF_BRIGHTLIGHT|EF_DIMLIGHT|EF_BLUE|EF_RED|EF_FLAME
-const float BALL_EFFECTMASK = 1229;
-const vector BALL_MINS = '-16 -16 -16'; // The model is 24*24*24
-const vector BALL_MAXS = '16 16 16';
-const vector BALL_ATTACHORG = '3 0 16';
-const float BALL_FOOT = 1;
-const float BALL_BASKET = 2;
-//spawnflags
-const float GOAL_TOUCHPLAYER = 1;
-//goal types
-const float GOAL_FAULT = -1;
-const float GOAL_OUT = -2;
-
-void DropBall(entity ball, vector org, vector vel);
-float autocvar_g_nexball_football_boost_forward;
-float autocvar_g_nexball_football_boost_up;
-float autocvar_g_nexball_football_physics;
-float autocvar_g_nexball_delay_idle;
-float autocvar_g_nexball_basketball_delay_hold;
-float autocvar_g_nexball_basketball_delay_hold_forteam;
-float autocvar_g_nexball_basketball_effects_default;
-float autocvar_g_nexball_basketball_teamsteal;
-float autocvar_g_nexball_meter_period;
-
-float balls;
-float ball_scale;
-float nb_teams;
-
-.entity nb_dropper;
-.float nb_droptime;
-
-.float teamtime;
-#endif
+++ /dev/null
-#ifndef GAMEMODE_NEXBALL_WEAPON_H
-#define GAMEMODE_NEXBALL_WEAPON_H
-
-CLASS(BallStealer, PortoLaunch)
-/* flags */ ATTRIB(BallStealer, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
-/* impulse */ ATTRIB(BallStealer, impulse, int, 0);
-/* refname */ ATTRIB(BallStealer, netname, string, "ballstealer");
-/* wepname */ ATTRIB(BallStealer, message, string, _("Ball Stealer"));
-ENDCLASS(BallStealer)
-REGISTER_WEAPON(NEXBALL, NEW(BallStealer));
-
-#endif
-#include "../_all.qh"
#include "gamemode.qh"
#include "../controlpoint.qh"
#include "../generator.qh"
+void FixSize(entity e);
+
// =======================
// CaptureShield Functions
// =======================
Send_Effect(EFFECT_RAGE, self.origin + 10 * randomvec(), '0 0 -1', 1);
}
+void onslaught_controlpoint_icon_link(entity e, void() spawnproc);
+
void ons_ControlPoint_Icon_Spawn(entity cp, entity player)
{
entity e = spawn();
#include "gamemode_race.qh"
-#include "../_all.qh"
#include "gamemode.qh"
-#include "../_all.qh"
#include "gamemode.qh"
#include "../../common/monsters/all.qh"
-#include "../../warpzonelib/anglestransform.qh"
-#include "../../warpzonelib/server.qh"
-#include "../../warpzonelib/util_server.qh"
+#include "../../lib/warpzone/anglestransform.qh"
+#include "../../lib/warpzone/server.qh"
+#include "../../lib/warpzone/util_server.qh"
#endif
-#include "../_all.qh"
#include "mutator.qh"
+#include "../../common/deathtypes/all.qh"
+#include "../g_hook.qh"
+
REGISTER_MUTATOR(bh, cvar("g_breakablehook"));
bool autocvar_g_breakablehook; // allow toggling mid match?
#include "../../common/triggers/target/music.qh"
#include "mutator_buffs.qh"
-#include "../_all.qh"
#include "mutator.qh"
+#include "../../common/gamemodes/all.qh"
#include "../../common/buffs/all.qh"
entity buff_FirstFromFlags(int _buffs)
return false;
}
+.float stat_sv_maxspeed;
+.float stat_sv_airspeedlimit_nonqw;
+.float stat_sv_jumpvelocity;
+
MUTATOR_HOOKFUNCTION(buffs_PlayerPhysics)
{SELFPARAM();
if(self.buffs & BUFF_SPEED.m_itemid)
-#include "../_all.qh"
#include "mutator.qh"
#ifdef SVQC
#include "mutator_dodging.qh"
-#include "../_all.qh"
#include "mutator.qh"
#include "../../common/animdecide.qh"
+#include "../../common/physics.qh"
.float cvar_cl_dodging_timeout;
+++ /dev/null
-#include "../_all.qh"
-
-#include "mutator.qh"
-
-#include "../cl_client.qh"
-#include "../../common/buffs/all.qh"
-
-#include "../../common/items/all.qc"
-
-spawnfunc(item_minst_cells)
-{
- if (!g_instagib) { remove(self); return; }
- if (!self.ammo_cells) self.ammo_cells = autocvar_g_instagib_ammo_drop;
- StartItemA(ITEM_VaporizerCells);
-}
-
-void instagib_invisibility()
-{SELFPARAM();
- self.strength_finished = autocvar_g_balance_powerup_strength_time;
- StartItemA(ITEM_Invisibility);
-}
-
-void instagib_extralife()
-{SELFPARAM();
- self.max_health = 1;
- StartItemA(ITEM_ExtraLife);
-}
-
-void instagib_speed()
-{SELFPARAM();
- self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
- StartItemA(ITEM_Speed);
-}
-
-.float instagib_nextthink;
-.float instagib_needammo;
-void instagib_stop_countdown(entity e)
-{
- if (!e.instagib_needammo)
- return;
- Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_INSTAGIB_FINDAMMO);
- e.instagib_needammo = false;
-}
-void instagib_ammocheck()
-{SELFPARAM();
- if(time < self.instagib_nextthink)
- return;
- if(!IS_PLAYER(self))
- return; // not a player
-
- if(self.deadflag || gameover)
- instagib_stop_countdown(self);
- else if (self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO) || (self.flags & FL_GODMODE))
- instagib_stop_countdown(self);
- else if(autocvar_g_rm && autocvar_g_rm_laser)
- {
- if(!self.instagib_needammo)
- {
- Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_INSTAGIB_DOWNGRADE);
- self.instagib_needammo = true;
- }
- }
- else
- {
- self.instagib_needammo = true;
- if (self.health <= 5)
- {
- Damage(self, self, self, 5, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
- Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_INSTAGIB_TERMINATED);
- }
- else if (self.health <= 10)
- {
- Damage(self, self, self, 5, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
- Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_1);
- }
- else if (self.health <= 20)
- {
- Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
- Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_2);
- }
- else if (self.health <= 30)
- {
- Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
- Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_3);
- }
- else if (self.health <= 40)
- {
- Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
- Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_4);
- }
- else if (self.health <= 50)
- {
- Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
- Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_5);
- }
- else if (self.health <= 60)
- {
- Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
- Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_6);
- }
- else if (self.health <= 70)
- {
- Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
- Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_7);
- }
- else if (self.health <= 80)
- {
- Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
- Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_8);
- }
- else if (self.health <= 90)
- {
- Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_INSTAGIB_FINDAMMO);
- Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
- Send_Notification(NOTIF_ONE, self, MSG_ANNCE, ANNCE_NUM_9);
- }
- else
- {
- Send_Notification(NOTIF_ONE_ONLY, self, MSG_MULTI, MULTI_INSTAGIB_FINDAMMO);
- Damage(self, self, self, 10, DEATH_NOAMMO.m_id, self.origin, '0 0 0');
- }
- }
- self.instagib_nextthink = time + 1;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_MatchEnd)
-{
- entity head;
- FOR_EACH_PLAYER(head)
- instagib_stop_countdown(head);
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_MonsterLoot)
-{
- other.monster_loot = spawnfunc_item_minst_cells;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_MonsterSpawn)
-{SELFPARAM();
- // always refill ammo
- if(self.monsterid == MON_MAGE.monsterid)
- self.skin = 1;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_BotShouldAttack)
-{
- if (checkentity.items & ITEM_Invisibility.m_itemid)
- return true;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_MakePlayerObserver)
-{SELFPARAM();
- instagib_stop_countdown(self);
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerSpawn)
-{SELFPARAM();
- self.effects |= EF_FULLBRIGHT;
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerPreThink)
-{
- instagib_ammocheck();
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerRegen)
-{
- // no regeneration in instagib
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerPowerups)
-{SELFPARAM();
- if (!(self.effects & EF_FULLBRIGHT))
- self.effects |= EF_FULLBRIGHT;
-
- if (self.items & ITEM_Invisibility.m_itemid)
- {
- play_countdown(self.strength_finished, SND(POWEROFF));
- if (time > self.strength_finished)
- {
- self.alpha = default_player_alpha;
- self.exteriorweaponentity.alpha = default_weapon_alpha;
- self.items &= ~ITEM_Invisibility.m_itemid;
- Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
- }
- }
- else
- {
- if (time < self.strength_finished)
- {
- self.alpha = autocvar_g_instagib_invis_alpha;
- self.exteriorweaponentity.alpha = autocvar_g_instagib_invis_alpha;
- self.items |= ITEM_Invisibility.m_itemid;
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_INVISIBILITY, self.netname);
- Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
- }
- }
-
- if (self.items & ITEM_Speed.m_itemid)
- {
- play_countdown(self.invincible_finished, SND(POWEROFF));
- if (time > self.invincible_finished)
- {
- self.items &= ~ITEM_Speed.m_itemid;
- Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SPEED);
- }
- }
- else
- {
- if (time < self.invincible_finished)
- {
- self.items |= ITEM_Speed.m_itemid;
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SPEED, self.netname);
- Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SPEED);
- }
- }
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerPhysics)
-{SELFPARAM();
- if(self.items & ITEM_Speed.m_itemid)
- self.stat_sv_maxspeed = self.stat_sv_maxspeed * autocvar_g_instagib_speed_highspeed;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_SplitHealthArmor)
-{
- damage_save = 0;
- damage_take = frag_damage;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_ForbidThrowing)
-{
- // weapon dropping on death handled by FilterItem
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerDamage)
-{
- if(autocvar_g_friendlyfire == 0 && SAME_TEAM(frag_target, frag_attacker) && IS_PLAYER(frag_target) && IS_PLAYER(frag_attacker))
- frag_damage = 0;
-
- if(IS_PLAYER(frag_target))
- {
- if(frag_deathtype == DEATH_FALL.m_id)
- frag_damage = 0; // never count fall damage
-
- if(!autocvar_g_instagib_damagedbycontents)
- switch(DEATH_ENT(frag_deathtype))
- {
- case DEATH_DROWN:
- case DEATH_SLIME:
- case DEATH_LAVA:
- frag_damage = 0;
- break;
- }
-
- if(IS_PLAYER(frag_attacker))
- if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
- {
- if(frag_target.armorvalue)
- {
- frag_target.armorvalue -= 1;
- frag_damage = 0;
- frag_target.damage_dealt += 1;
- frag_attacker.damage_dealt += 1; // TODO: change this to a specific hitsound for armor hit
- Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_target.armorvalue);
- }
- }
-
- if(IS_PLAYER(frag_attacker) && DEATH_ISWEAPON(frag_deathtype, WEP_BLASTER))
- {
- if(frag_deathtype & HITTYPE_SECONDARY)
- {
- if(!autocvar_g_instagib_blaster_keepdamage)
- frag_damage = frag_mirrordamage = 0;
-
- if(frag_target != frag_attacker)
- {
- if(frag_damage <= 0 && frag_target.health > 0) { Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_SECONDARY_NODAMAGE); }
- if(!autocvar_g_instagib_blaster_keepforce)
- frag_force = '0 0 0';
- }
- }
- }
- }
-
- if(IS_PLAYER(frag_attacker))
- if(frag_mirrordamage > 0)
- {
- // just lose extra LIVES, don't kill the player for mirror damage
- if(frag_attacker.armorvalue > 0)
- {
- frag_attacker.armorvalue -= 1;
- Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_INSTAGIB_LIVES_REMAINING, frag_attacker.armorvalue);
- frag_attacker.damage_dealt += frag_mirrordamage;
- }
- frag_mirrordamage = 0;
- }
-
- if((frag_target.buffs & BUFF_INVISIBLE.m_itemid) || (frag_target.items & ITEM_Invisibility.m_itemid))
- yoda = 1;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_SetStartItems)
-{
- start_health = warmup_start_health = 100;
- start_armorvalue = warmup_start_armorvalue = 0;
-
- start_ammo_shells = warmup_start_ammo_shells = 0;
- start_ammo_nails = warmup_start_ammo_nails = 0;
- start_ammo_cells = warmup_start_ammo_cells = cvar("g_instagib_ammo_start");
- start_ammo_plasma = warmup_start_ammo_plasma = 0;
- start_ammo_rockets = warmup_start_ammo_rockets = 0;
- start_ammo_fuel = warmup_start_ammo_fuel = 0;
-
- start_weapons = warmup_start_weapons = WEPSET(VAPORIZER);
- start_items |= IT_UNLIMITED_SUPERWEAPONS;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_FilterItem)
-{SELFPARAM();
- if(self.classname == "item_cells")
- return true; // no normal cells?
-
- if(self.weapon == WEP_VAPORIZER.m_id && self.classname == "droppedweapon")
- {
- self.ammo_cells = autocvar_g_instagib_ammo_drop;
- return false;
- }
-
- if(self.weapon == WEP_DEVASTATOR.m_id || self.weapon == WEP_VORTEX.m_id)
- {
- entity e = spawn();
- setorigin(e, self.origin);
- e.noalign = self.noalign;
- e.cnt = self.cnt;
- e.team = self.team;
- WITH(entity, self, e, spawnfunc_item_minst_cells(e));
- return true;
- }
-
- if(self.flags & FL_POWERUP)
- return false;
-
- if(self.ammo_cells > autocvar_g_instagib_ammo_drop && self.classname != "item_minst_cells")
- self.ammo_cells = autocvar_g_instagib_ammo_drop;
-
- if(self.ammo_cells && !self.weapon)
- return false;
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_CustomizeWaypoint)
-{SELFPARAM();
- entity e = WaypointSprite_getviewentity(other);
-
- // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
- // but only apply this to real players, not to spectators
- if((self.owner.flags & FL_CLIENT) && (self.owner.items & ITEM_Invisibility.m_itemid) && (e == other))
- if(DIFF_TEAM(self.owner, e))
- return true;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_PlayerDies)
-{
- if(DEATH_ISWEAPON(frag_deathtype, WEP_VAPORIZER))
- frag_damage = 1000; // always gib if it was a vaporizer death
-
- return FALSE;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_ItemTouch)
-{SELFPARAM();
- if(self.ammo_cells)
- {
- // play some cool sounds ;)
- if (IS_CLIENT(other))
- {
- if(other.health <= 5)
- Send_Notification(NOTIF_ONE, other, MSG_ANNCE, ANNCE_INSTAGIB_LASTSECOND);
- else if(other.health < 50)
- Send_Notification(NOTIF_ONE, other, MSG_ANNCE, ANNCE_INSTAGIB_NARROWLY);
- }
-
- if(other.health < 100)
- other.health = 100;
-
- return MUT_ITEMTOUCH_CONTINUE;
- }
-
- if(self.max_health)
- {
- other.armorvalue = bound(other.armorvalue, 999, other.armorvalue + autocvar_g_instagib_extralives);
- Send_Notification(NOTIF_ONE, other, MSG_CENTER, CENTER_EXTRALIVES);
- return MUT_ITEMTOUCH_PICKUP;
- }
-
- return MUT_ITEMTOUCH_CONTINUE;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_OnEntityPreSpawn)
-{SELFPARAM();
- if (!autocvar_g_powerups) { return false; }
- // Can't use .itemdef here
- if (!(self.classname == "item_strength" || self.classname == "item_invincible" || self.classname == "item_health_mega"))
- return false;
-
- entity e = spawn();
-
- float r = random();
- if (r < 0.3)
- e.think = instagib_invisibility;
- else if (r < 0.6)
- e.think = instagib_extralife;
- else
- e.think = instagib_speed;
-
- e.nextthink = time + 0.1;
- e.spawnflags = self.spawnflags;
- e.noalign = self.noalign;
- setorigin(e, self.origin);
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":instagib");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", instagib");
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(instagib_SetModname)
-{
- modname = "instagib";
- return true;
-}
-
-MUTATOR_DEFINITION(mutator_instagib)
-{
- MUTATOR_HOOK(MatchEnd, instagib_MatchEnd, CBC_ORDER_ANY);
- MUTATOR_HOOK(MonsterDropItem, instagib_MonsterLoot, CBC_ORDER_ANY);
- MUTATOR_HOOK(MonsterSpawn, instagib_MonsterSpawn, CBC_ORDER_ANY);
- MUTATOR_HOOK(BotShouldAttack, instagib_BotShouldAttack, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerPhysics, instagib_PlayerPhysics, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerSpawn, instagib_PlayerSpawn, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerDamage_Calculate, instagib_PlayerDamage, CBC_ORDER_ANY);
- MUTATOR_HOOK(MakePlayerObserver, instagib_MakePlayerObserver, CBC_ORDER_ANY);
- MUTATOR_HOOK(SetStartItems, instagib_SetStartItems, CBC_ORDER_ANY);
- MUTATOR_HOOK(ItemTouch, instagib_ItemTouch, CBC_ORDER_ANY);
- MUTATOR_HOOK(FilterItem, instagib_FilterItem, CBC_ORDER_ANY);
- MUTATOR_HOOK(CustomizeWaypoint, instagib_CustomizeWaypoint, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerDies, instagib_PlayerDies, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerDamage_SplitHealthArmor, instagib_SplitHealthArmor, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerPowerups, instagib_PlayerPowerups, CBC_ORDER_ANY);
- MUTATOR_HOOK(ForbidThrowCurrentWeapon, instagib_ForbidThrowing, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerPreThink, instagib_PlayerPreThink, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerRegen, instagib_PlayerRegen, CBC_ORDER_ANY);
- MUTATOR_HOOK(OnEntityPreSpawn, instagib_OnEntityPreSpawn, CBC_ORDER_ANY);
- MUTATOR_HOOK(BuildMutatorsString, instagib_BuildMutatorsString, CBC_ORDER_ANY);
- MUTATOR_HOOK(BuildMutatorsPrettyString, instagib_BuildMutatorsPrettyString, CBC_ORDER_ANY);
- MUTATOR_HOOK(SetModname, instagib_SetModname, CBC_ORDER_ANY);
-
- return false;
-}
+++ /dev/null
-#include "../../common/items/item.qh"
-
-float instagib_respawntime_ammo = 45;
-float instagib_respawntimejitter_ammo = 0;
-GETTER(float, instagib_respawntime_ammo)
-GETTER(float, instagib_respawntimejitter_ammo)
-
-#ifndef MENUQC
-MODEL(VaporizerCells_ITEM, Item_Model("a_cells.md3"));
-#endif
-
-REGISTER_ITEM(VaporizerCells, Ammo) {
-#ifndef MENUQC
- this.m_model = MDL_VaporizerCells_ITEM;
-#endif
- this.m_sound = "misc/itempickup.wav";
- this.m_name = "Vaporizer Ammo";
- this.m_icon = "ammo_supercells";
-#ifdef SVQC
- this.m_botvalue = 100;
- this.m_itemid = IT_CELLS;
- this.m_respawntime = GET(instagib_respawntime_ammo);
- this.m_respawntimejitter = GET(instagib_respawntimejitter_ammo);
-#endif
-}
-
-#ifndef MENUQC
-MODEL(ExtraLife_ITEM, Item_Model("g_h100.md3"));
-#endif
-
-REGISTER_ITEM(ExtraLife, Powerup) {
-#ifndef MENUQC
- this.m_model = MDL_ExtraLife_ITEM;
-#endif
- this.m_sound = "misc/megahealth.wav";
- this.m_name = "Extra life";
- this.m_icon = "item_mega_health";
- this.m_color = '1 0 0';
- this.m_waypoint = _("Extra life");
- this.m_waypointblink = 2;
- this.m_itemid = IT_NAILS;
-}
-
-#ifndef MENUQC
-MODEL(Invisibility_ITEM, Item_Model("g_strength.md3"));
-#endif
-
-REGISTER_ITEM(Invisibility, Powerup) {
-#ifndef MENUQC
- this.m_model = MDL_Invisibility_ITEM;
-#endif
- this.m_sound = "misc/powerup.wav";
- this.m_name = "Invisibility";
- this.m_icon = "strength";
- this.m_color = '0 0 1';
- this.m_waypoint = _("Invisibility");
- this.m_waypointblink = 2;
- this.m_itemid = IT_STRENGTH;
-}
-
-#ifndef MENUQC
-MODEL(Speed_ITEM, Item_Model("g_invincible.md3"));
-#endif
-
-REGISTER_ITEM(Speed, Powerup) {
-#ifndef MENUQC
- this.m_model = MDL_Speed_ITEM;
-#endif
- this.m_sound = "misc/powerup_shield.wav";
- this.m_name = "Speed";
- this.m_icon = "shield";
- this.m_color = '1 0 1';
- this.m_waypoint = _("Speed");
- this.m_waypointblink = 2;
- this.m_itemid = IT_INVINCIBLE;
-}
-#include "../_all.qh"
#include "mutator.qh"
-#include "../_all.qh"
#include "mutator.qh"
-#include "../_all.qh"
#include "mutator.qh"
#ifdef SVQC
- #include "../_all.qh"
#include "mutator.qh"
#include "../antilag.qh"
#endif
+#include "../../common/physics.qh"
.int multijump_count;
.bool multijump_ready;
#include "mutator_nades.qh"
-#include "../_all.qh"
#include "mutator.qh"
#include "gamemode_keyhunt.qh"
#include "gamemode_freezetag.qh"
#include "../../common/nades/all.qh"
+#include "../../common/gamemodes/all.qh"
#include "../../common/monsters/spawn.qh"
#include "../../common/monsters/sv_monsters.qh"
+#include "../g_subs.qh"
.float nade_time_primed;
-#include "../_all.qh"
#include "mutator.qh"
-#include "../_all.qh"
#include "mutator.qh"
#include "mutator_overkill.qh"
-#include "../_all.qh"
#include "mutator.qh"
-#include "../_all.qh"
#include "mutator.qh"
-#include "../_all.qh"
#include "mutator.qh"
-#include "../_all.qh"
#include "mutator.qh"
-#include "../_all.qh"
#include "mutator.qh"
+#include "../../common/deathtypes/all.qh"
+#include "../round_handler.qh"
+
REGISTER_MUTATOR(rm, cvar("g_instagib"));
MUTATOR_HOOKFUNCTION(rm, PlayerDamage_Calculate)
-#include "../_all.qh"
#include "mutator.qh"
-#include "../_all.qh"
#include "mutator.qh"
-#include "../_all.qh"
#include "mutator.qh"
-#include "../_all.qh"
#include "mutator.qh"
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
#include "mutators_include.qh"
#include "../../common/mapinfo.qh"
#endif
CHECK_MUTATOR_ADD("g_spawn_near_teammate", mutator_spawn_near_teammate, teamplay);
CHECK_MUTATOR_ADD("g_physical_items", mutator_physical_items, 1);
CHECK_MUTATOR_ADD("g_touchexplode", mutator_touchexplode, 1);
- CHECK_MUTATOR_ADD("g_instagib", mutator_instagib, !g_nexball);
CHECK_MUTATOR_ADD("g_invincible_projectiles", mutator_invincibleprojectiles, 1);
CHECK_MUTATOR_ADD("g_new_toys", mutator_new_toys, !cvar("g_instagib") && !cvar("g_overkill"));
CHECK_MUTATOR_ADD("g_nix", mutator_nix, !cvar("g_instagib") && !cvar("g_overkill"));
MUTATOR_DECLARATION(gamemode_freezetag);
MUTATOR_DECLARATION(gamemode_keepaway);
MUTATOR_DECLARATION(gamemode_ctf);
-MUTATOR_DECLARATION(gamemode_nexball);
MUTATOR_DECLARATION(gamemode_onslaught);
MUTATOR_DECLARATION(gamemode_domination);
MUTATOR_DECLARATION(gamemode_lms);
MUTATOR_DECLARATION(mutator_physical_items);
MUTATOR_DECLARATION(mutator_vampire);
MUTATOR_DECLARATION(mutator_superspec);
-MUTATOR_DECLARATION(mutator_instagib);
MUTATOR_DECLARATION(mutator_touchexplode);
MUTATOR_DECLARATION(mutator_pinata);
MUTATOR_DECLARATION(mutator_midair);
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../../dpdefs/progsdefs.qh"
- #include "../../dpdefs/dpextensions.qh"
- #include "../../warpzonelib/anglestransform.qh"
- #include "../../warpzonelib/common.qh"
- #include "../../warpzonelib/util_server.qh"
- #include "../../warpzonelib/server.qh"
+ #include "../../lib/warpzone/anglestransform.qh"
+ #include "../../lib/warpzone/common.qh"
+ #include "../../lib/warpzone/util_server.qh"
+ #include "../../lib/warpzone/server.qh"
#include "../../common/constants.qh"
#include "../../common/stats.qh"
#include "../../common/teams.qh"
#include "../command/cmd.qh"
#include "../command/sv_cmd.qh"
#include "../../common/csqcmodel_settings.qh"
- #include "../../csqcmodellib/common.qh"
- #include "../../csqcmodellib/sv_model.qh"
+ #include "../../lib/csqcmodel/common.qh"
+ #include "../../lib/csqcmodel/sv_model.qh"
#include "../anticheat.qh"
#include "../cheats.qh"
#include "../../common/playerstats.qh"
#include "gamemode_keepaway.qc"
#include "gamemode_keyhunt.qc"
#include "gamemode_lms.qc"
-#include "gamemode_nexball.qc"
#include "gamemode_onslaught.qc"
#include "gamemode_race.qc"
#include "gamemode_tdm.qc"
#include "mutator_campcheck.qc"
#include "mutator_dodging.qc"
#include "mutator_hook.qc"
-#include "mutator_instagib.qc"
#include "mutator_invincibleproj.qc"
#include "mutator_melee_only.qc"
#include "mutator_midair.qc"
#include "gamemode_keepaway.qh"
#include "gamemode_keyhunt.qh"
#include "gamemode_lms.qh"
-#include "gamemode_nexball.qh"
#include "gamemode_onslaught.qh"
#include "gamemode_race.qh"
-#include "../_all.qh"
#include "mutator.qh"
--- /dev/null
+#define DEBUGPATHING
+
+#include "costs.qc"
+#include "expandnode.qc"
+#include "main.qc"
+#include "movenode.qc"
+#include "path_waypoint.qc"
+#include "utility.qc"
+#ifdef DEBUGPATHING
+ #include "debug.qc"
+#endif
path.nextthink = time;
}
-
void pathlib_showsquare2(entity node ,vector ncolor,float align)
{
-#include "../_all.qh"
#include "pathlib.qh"
#include "utility.qh"
n.nextthink = time;
}
+#ifdef DEBUGPATHING
+void pathlib_showpath(entity start);
+void pathlib_showpath2(entity path);
+#endif
+
+void pathlib_showsquare(vector where,float goodsquare,float _lifetime);
+void pathlib_showsquare2(entity node ,vector ncolor,float align);
+
entity pathlib_mknode(vector where,entity parent)
{
entity node;
-#include "../_all.qh"
#include "pathlib.qh"
#include "utility.qh"
+.vector pos1, pos2;
+
vector pathlib_wateroutnode(vector start,vector end, float doedge)
{SELFPARAM();
vector surface;
const vector PLIB_RIGHT = '1 0 0';
//#define PLIB_LEFT '-1 0 0'
-#define DEBUGPATHING
#ifdef DEBUGPATHING
void pathlib_showpath(entity start);
void pathlib_showpath2(entity path);
var float pathlib_wpp_waypointcallback(entity wp, entity wp_prev);
-#ifdef DEBUGPATHING
- #include "debug.qc"
-#endif
-
#endif
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
#include "defs.qh"
#include "playerdemo.qh"
#endif
#include "portals.qh"
-#include "_all.qh"
#include "g_hook.qh"
#include "mutators/mutators_include.qh"
#include "../common/triggers/subs.qh"
#include "../common/util.qh"
#include "../common/weapons/all.qh"
-#include "../csqcmodellib/sv_model.qh"
-#include "../warpzonelib/anglestransform.qh"
-#include "../warpzonelib/util_server.qh"
+#include "../lib/csqcmodel/sv_model.qh"
+#include "../lib/warpzone/anglestransform.qh"
+#include "../lib/warpzone/util_server.qh"
+#include "../lib/warpzone/common.qh"
+#include "../common/vehicles/vehicle.qh"
+#include "../common/vehicles/sv_vehicles.qh"
#define PORTALS_ARE_NOT_SOLID
-#include "../common/util-pre.qh"
-#include "sys-pre.qh"
-#include "../dpdefs/progsdefs.qh"
-#include "../dpdefs/dpextensions.qh"
-#include "sys-post.qh"
-#include "../common/util-post.qh"
-
#include "../lib/_all.inc"
+#include "_all.qh"
#include "anticheat.qc"
#include "antilag.qc"
#include "t_quake3.qc"
#include "t_quake.qc"
-#include "bot/aim.qc"
-#include "bot/bot.qc"
-#include "bot/navigation.qc"
-#include "bot/scripting.qc"
-#include "bot/waypoints.qc"
-
-#include "bot/havocbot/havocbot.qc"
-#include "bot/havocbot/role_keyhunt.qc"
-#include "bot/havocbot/roles.qc"
+#include "bot/_all.inc"
#include "command/all.qc"
#include "mutators/mutators_include.qc"
#include "mutators/mutators.qc"
-#include "pathlib/costs.qc"
-#include "pathlib/expandnode.qc"
-#include "pathlib/main.qc"
-#include "pathlib/movenode.qc"
-#include "pathlib/path_waypoint.qc"
-#include "pathlib/utility.qc"
+#include "pathlib/_all.inc"
#include "weapons/accuracy.qc"
#include "weapons/common.qc"
#include "../common/animdecide.qc"
#include "../common/campaign_file.qc"
#include "../common/campaign_setup.qc"
-#include "../common/effects/effects.qc"
#include "../common/effects/effectinfo.qc"
#include "../common/mapinfo.qc"
#include "../common/monsters/spawn.qc"
#include "../common/deathtypes/all.qc"
#include "../common/buffs/all.qc"
+#include "../common/effects/all.qc"
+#include "../common/gamemodes/all.qc"
#include "../common/items/all.qc"
#include "../common/monsters/all.qc"
#include "../common/mutators/all.qc"
#include "../common/turrets/targettrigger.qc"
#include "../common/weapons/config.qc"
-#include "../csqcmodellib/sv_model.qc"
+#include "../lib/csqcmodel/sv_model.qc"
-#include "../warpzonelib/anglestransform.qc"
-#include "../warpzonelib/common.qc"
-#include "../warpzonelib/server.qc"
-#include "../warpzonelib/util_server.qc"
+#include "../lib/warpzone/anglestransform.qc"
+#include "../lib/warpzone/common.qc"
+#include "../lib/warpzone/server.qc"
+#include "../lib/warpzone/util_server.qc"
#if BUILD_MOD
#include "../../mod/server/progs.inc"
#include "race.qh"
-#include "_all.qh"
#include "cl_client.qh"
#include "portals.qh"
#include "../common/deathtypes/all.qh"
#include "../common/notifications.qh"
#include "../common/mapinfo.qh"
-#include "../warpzonelib/util_server.qh"
+#include "../common/triggers/subs.qh"
+#include "../lib/warpzone/util_server.qh"
+#include "../lib/warpzone/common.qh"
+#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
void W_Porto_Fail(float failhard);
#include "round_handler.qh"
-#include "_all.qh"
#include "command/vote.qh"
#include "../common/util.qh"
#include "scores.qh"
-#include "_all.qh"
#include "command/common.qh"
#include "mutators/mutators_include.qh"
#include "scores_rules.qh"
-#include "_all.qh"
#include "cl_client.qh"
#include "scores.qh"
#include "spawnpoints.qh"
-#include "_all.qh"
#include "mutators/mutators_include.qh"
#include "g_world.qh"
#include "race.qh"
#include "../common/constants.qh"
#include "../common/teams.qh"
+#include "../common/triggers/subs.qh"
#include "../common/util.qh"
-#include "../warpzonelib/util_server.qh"
+#include "../lib/warpzone/common.qh"
+#include "../lib/warpzone/util_server.qh"
bool SpawnPoint_Send(entity this, entity to, int sf)
{
#if defined(CSQC)
#elif defined(MENUQC)
#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
#endif
/**
-#include "_all.qh"
#include "anticheat.qh"
#include "g_hook.qh"
#include "../common/vehicles/all.qh"
#include "../common/weapons/all.qh"
-#include "../csqcmodellib/sv_model.qh"
+#include "../lib/csqcmodel/sv_model.qh"
-#include "../warpzonelib/common.qh"
-#include "../warpzonelib/server.qh"
+#include "../lib/warpzone/common.qh"
+#include "../lib/warpzone/server.qh"
.float lastground;
+.int state;
void CreatureFrame (void)
{SELFPARAM();
#include "../common/items/all.qc"
#if defined(SVQC)
- #include "_all.qh"
#include "bot/bot.qh"
#include "bot/waypoints.qh"
#include "../common/weapons/all.qh"
- #include "../warpzonelib/util_server.qh"
+ #include "../lib/warpzone/util_server.qh"
#endif
#ifdef CSQC
#ifndef T_ITEMS_H
#define T_ITEMS_H
-// constants
-const int IT_UNLIMITED_WEAPON_AMMO = 1; // when this bit is set, using a weapon does not reduce ammo. Checkpoints can give this powerup.
-const int IT_UNLIMITED_SUPERWEAPONS = 2; // when this bit is set, superweapons don't expire. Checkpoints can give this powerup.
-const int IT_CTF_SHIELDED = 4; // set for the flag shield
-const int IT_USING_JETPACK = 8; // confirmation that button is pressed
-const int IT_JETPACK = 16; // actual item
-const int IT_FUEL_REGEN = 32; // fuel regeneration trigger
-// where is 64... ?
-const int IT_FUEL = 128;
-// -Wdouble-declaration
-#define IT_SHELLS 256
-// -Wdouble-declaration
-#define IT_NAILS 512
-// -Wdouble-declaration
-#define IT_ROCKETS 1024
-// -Wdouble-declaration
-#define IT_CELLS 2048
-const int IT_SUPERWEAPON = 4096;
-const int IT_STRENGTH = 8192;
-const int IT_INVINCIBLE = 16384;
-const int IT_HEALTH = 32768;
-const int IT_PLASMA = 65536;
-
-// shared value space (union):
- // for items:
- // -Wdouble-declaration
- #define IT_KEY1 131072
- // -Wdouble-declaration
- #define IT_KEY2 262144
-// end
-
-const int IT_5HP = 524288;
-const int IT_25HP = 1048576;
-const int IT_ARMOR_SHARD = 2097152;
-const int IT_ARMOR = 4194304;
-
-// item masks
-const int IT_AMMO = 3968; // IT_FUEL | IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS | IT_PLASMA;
-const int IT_PICKUPMASK = 51; // IT_FUEL_REGEN | IT_JETPACK | IT_UNLIMITED_AMMO; // strength and invincible are handled separately
-const int IT_UNLIMITED_AMMO = 3; // IT_UNLIMITED_SUPERWEAPONS | IT_UNLIMITED_WEAPON_AMMO;
-
const int AMMO_COUNT = 4; // amount of ammo types to show in the inventory panel
// item networking
.float fade_start;
.float fade_end;
+#ifdef SVQC
+void StartItemA (entity a);
+#endif
+
#ifdef CSQC
float autocvar_cl_animate_items = 1;
-#include "_all.qh"
#include "../common/weapons/all.qh"
-#include "_all.qh"
#include "../common/weapons/all.qh"
#include "../common/buffs/all.qh"
spawnfunc(item_armor_shard) { spawnfunc_item_armor_small(this); }
spawnfunc(item_enviro) { spawnfunc_item_invincible(this); }
+.float wait;
+.float delay;
+
// weapon remove ent from df
void target_init_verify()
{
#include "teamplay.qh"
-#include "_all.qh"
#include "cl_client.qh"
#include "race.qh"
#include "mutators/mutators_include.qh"
#include "../common/deathtypes/all.qh"
+#include "../common/gamemodes/all.qh"
#include "../common/teams.qh"
void TeamchangeFrags(entity e)
// # of bots on those teams
float cb1, cb2, cb3, cb4;
+int redowned, blueowned, yellowowned, pinkowned;
+
//float audit_teams_time;
void TeamchangeFrags(entity e);
#include "accuracy.qh"
-#include "../_all.qh"
#include "../mutators/mutators_include.qh"
#include "../../common/constants.qh"
#include "common.qh"
-#include "../_all.qh"
#include "../t_items.qh"
#include "../../common/constants.qh"
#include "../../common/notifications.qh"
#include "../../common/util.qh"
#include "../../common/weapons/all.qh"
+#include "../../common/items/all.qc"
void W_GiveWeapon (entity e, float wep)
{SELFPARAM();
#include "csqcprojectile.qh"
-#include "../_all.qh"
#include "../t_items.qh"
#include "hitplot.qh"
-#include "../_all.qh"
#include "../antilag.qh"
+#include "../g_subs.qh"
#include "../../common/weapons/all.qh"
vector W_HitPlotUnnormalizedUntransform(vector screenforward, vector screenright, vector screenup, vector v)
void W_HitPlotOpen(entity player)
{
- if(autocvar_g_hitplots || strstrofs(strcat(" ", autocvar_g_hitplots_individuals, " "), strcat(" ", player.netaddress, " "), 0) >= 0)
+ if(autocvar_g_hitplots || strhasword(autocvar_g_hitplots_individuals, player.netaddress))
{
player.hitplotfh = fopen(strcat("hits-", matchid, "-", player.netaddress, "-", ftos(player.playerid), ".plot"), FILE_WRITE);
fputs(player.hitplotfh, strcat("#name ", player.netname, "\n"));
#include "selection.qh"
-#include "../_all.qh"
#include "weaponsystem.qh"
#include "../t_items.qh"
#include "../../common/constants.qh"
#include "../../common/util.qh"
+#include "../../common/items/item.qh"
#include "../../common/weapons/all.qh"
+#include "../../common/mutators/mutator/waypoints/waypointsprites.qh"
// switch between weapons
void Send_WeaponComplain(entity e, float wpn, float type)
#include "spawning.qh"
-#include "../_all.qh"
#include "weaponsystem.qh"
#include "../mutators/mutators_include.qh"
#include "throwing.qh"
-#include "../_all.qh"
#include "weaponsystem.qh"
#include "../mutators/mutators_include.qh"
#include "../t_items.qh"
#include "../g_damage.qh"
+#include "../../common/items/item.qh"
#include "../../common/mapinfo.qh"
#include "../../common/notifications.qh"
+#include "../../common/triggers/subs.qh"
#include "../../common/util.qh"
#include "../../common/weapons/all.qh"
#include "tracing.qh"
-#include "../_all.qh"
#include "accuracy.qh"
#include "common.qh"
#include "hitplot.qh"
+#include "weaponsystem.qh"
#include "../g_damage.qh"
#include "../g_subs.qh"
#include "../../common/weapons/all.qh"
-#include "../../warpzonelib/common.qh"
+#include "../../lib/warpzone/common.qh"
// this function calculates w_shotorg and w_shotdir based on the weapon model
// offset, trueaim and antilag, and won't put w_shotorg inside a wall.
#include "weaponstats.qh"
-#include "../_all.qh"
#include "../g_world.qh"
#include "weaponsystem.qh"
-#include "../_all.qh"
#include "selection.qh"
#include "../../common/notifications.qh"
#include "../../common/util.qh"
#include "../../common/weapons/all.qh"
-#include "../../csqcmodellib/sv_model.qh"
+#include "../../lib/csqcmodel/sv_model.qh"
/*
===========================================================================
===========================================================================
*/
+.int state;
+
.float weapon_frametime;
float W_WeaponRateFactor()
cd ..
declare -a NOWARN=(
- '-Wno-field-redeclared'
- '-Wno-unused-variable'
- '-Wno-implicit-function-pointer'
+ -Wno-field-redeclared
+ -Wno-unused-variable
+ -Wno-implicit-function-pointer
)
declare -a FEATURES=(
- '-DVEHICLES_ENABLED=1'
- '-DVEHICLES_USE_ODE=0'
+ -DVEHICLES_ENABLED=1
+ -DVEHICLES_USE_ODE=0
)
declare QCC=../../../gmqcc/gmqcc
+declare -a QCC_FLAGS=(
+ -std=gmqcc
+ -Wall -Werror
+ -fftepp -fftepp-predefs -Wcpp
+ -futf8
+ -freturn-assignments
+ -frelaxed-switch
+ -O3
+)
+
function check() {
- declare -l base="$1"
- declare -la predefs=("${!2}")
- find "$base" -type f -name '*.qc' -print0 | sort -z | while IFS= read -r -d '' file; do
+ declare -l base="${1}"
+ declare -la predefs=("-D${2}" "lib/_all.inc" "${base}/_all.qh")
+ find "$base" -type f -name '*.qc' -print0 | sort -z | while read -r -d '' file; do
echo "$file"
- ${QCC} -std=gmqcc -fftepp -fftepp-predefs -Werror -Wall "${NOWARN[@]}" "${FEATURES[@]}" -futf8 -O3 "${predefs[@]}" "$file" >/dev/null
+ ${QCC} "${QCC_FLAGS[@]}" "${NOWARN[@]}" "${FEATURES[@]}" "${predefs[@]}" "$file" >/dev/null
done
}
-clientdefs=("-DCSQC" "common/util-pre.qh" "dpdefs/csprogsdefs.qh")
-check "client" clientdefs[@]
-
-serverdefs=("-DSVQC" "common/util-pre.qh" "server/sys-pre.qh" "dpdefs/progsdefs.qh" "dpdefs/dpextensions.qh" "server/sys-post.qh" "server/defs.qh" "server/autocvars.qh")
-check "server" serverdefs[@]
-
-menudefs=("-DMENUQC" "common/util-pre.qh" "dpdefs/menudefs.qh")
-check "menu" menudefs[@]
+check client CSQC
+check server SVQC
+check menu MENUQC
+++ /dev/null
-The code in this directory is dual-licensed MIT and GPLv2 "or any later version".
-
-
-
-MIT license:
-
-Copyright (c) 2010 Rudolf Polzer
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-
-
-GPL v2:
-
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, 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 Lesser 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.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General
-Public License instead of this License.
+++ /dev/null
-Open issues:
-- grep for TODO and FIXME
-- when shot origin is inside warpzone, vortex shot fails (and is even drawn in totally wrong direction). WHY? Possibly v_forward got lost?
-
-Weapon support:
-
-- blaster: YES
-- shotgun: YES
-- machinegun: YES
-- mortar: YES
-- electro: YES
-- crylink: YES
-- vortex: YES
-- hagar: YES
-- devastator: YES (except for trail bug)
-- porto: YES (bwahahahaha)
-- hlac: YES
-- vaporizer: YES
-- rifle: YES
-- fireball: YES (BFG effect cannot work through warpzones by design, so it's not available through warpzones)
-- hook: YES
-
-- shockwave: NO (does not support warpzones currently)
-- tuba: NO (sound)
+++ /dev/null
-#include "anglestransform.qh"
-
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/progsdefs.qh"
- #include "../dpdefs/dpextensions.qh"
-#endif
-
-#ifdef POSITIVE_PITCH_IS_DOWN
-vector fixedvectoangles(vector a)
-{
- vector ang;
- ang = vectoangles(a);
- ang.x = -ang.x;
- return ang;
-}
-vector fixedvectoangles2(vector a, vector b)
-{
- vector ang;
- ang = vectoangles2(a, b);
- ang.x = -ang.x;
- return ang;
-}
-#else
-void fixedmakevectors(vector a)
-{
- // a makevectors that actually inverts vectoangles
- a.x = -a.x;
- makevectors(a);
-}
-#endif
-
-// angles transforms
-// angles in fixedmakevectors/fixedvectoangles space
-vector AnglesTransform_Apply(vector transform, vector v)
-{
- fixedmakevectors(transform);
- return v_forward * v.x
- + v_right * (-v.y)
- + v_up * v.z;
-}
-
-vector AnglesTransform_Multiply(vector t1, vector t2)
-{
- vector m_forward, m_up;
- fixedmakevectors(t2); m_forward = v_forward; m_up = v_up;
- m_forward = AnglesTransform_Apply(t1, m_forward); m_up = AnglesTransform_Apply(t1, m_up);
- return fixedvectoangles2(m_forward, m_up);
-}
-
-vector AnglesTransform_Invert(vector transform)
-{
- vector i_forward, i_up;
- fixedmakevectors(transform);
- // we want angles that turn v_forward into '1 0 0', v_right into '0 1 0' and v_up into '0 0 1'
- // but these are orthogonal unit vectors!
- // so to invert, we can simply fixedvectoangles the TRANSPOSED matrix
- // TODO is this always -transform?
- i_forward.x = v_forward.x;
- i_forward.y = -v_right.x;
- i_forward.z = v_up.x;
- i_up.x = v_forward.z;
- i_up.y = -v_right.z;
- i_up.z = v_up.z;
- return fixedvectoangles2(i_forward, i_up);
-}
-
-vector AnglesTransform_TurnDirectionFR(vector transform)
-{
- // turn 180 degrees around v_up
- // changes in-direction to out-direction
- //fixedmakevectors(transform);
- //return fixedvectoangles2(-1 * v_forward, 1 * v_up);
- transform.x = -transform.x;
- transform.y = 180 + transform.y;
- transform.z = -transform.z;
- // pitch: -s +c
- // yaw: -s -c
- // roll: -s +c
- return transform;
-}
-
-vector AnglesTransform_TurnDirectionFU(vector transform)
-{
- // turn 180 degrees around v_up
- // changes in-direction to out-direction
- //fixedmakevectors(transform);
- //return fixedvectoangles2(-1 * v_forward, 1 * v_up);
- transform.x = -transform.x;
- transform.y = 180 + transform.y;
- transform.z = 180 - transform.z;
- return transform;
-}
-
-vector AnglesTransform_RightDivide(vector to_transform, vector from_transform)
-{
- return AnglesTransform_Multiply(to_transform, AnglesTransform_Invert(from_transform));
-}
-
-vector AnglesTransform_LeftDivide(vector from_transform, vector to_transform)
-{
- return AnglesTransform_Multiply(AnglesTransform_Invert(from_transform), to_transform);
-}
-
-vector AnglesTransform_Normalize(vector t, float minimize_roll)
-{
- float need_flip;
- // first, bring all angles in their range...
- t.x = t.x - 360 * rint(t.x / 360);
- t.y = t.y - 360 * rint(t.y / 360);
- t.z = t.z - 360 * rint(t.z / 360);
- if(minimize_roll)
- need_flip = (t.z > 90 || t.z <= -90);
- else
- need_flip = (t.x > 90 || t.x < -90); // for pitch we prefer to allow exactly -90 degrees for looking straight down
- if(need_flip)
- {
- if(t.x >= 0) t.x = 180 - t.x; else t.x = -180 - t.x;
- if(t.y > 0) t.y -= 180; else t.y += 180;
- if(t.z > 0) t.z -= 180; else t.z += 180;
- }
- return t;
-}
-
-vector AnglesTransform_CancelRoll(vector t)
-{
- const float epsilon = 30;
- float f;
-
- // constraints:
- // forward vector (NOT SO important)
- // right vector, up vector: screen rotation (MORE important)
- // choose best match among all pitch-yaw only rotations
-
- // FIXME find a better method
-
- f = fabs(t.x - (-90)) / epsilon;
- if(f < 1)
- {
- //t_x = -90;
- t.y += t.z;
- t.z = 0;
- }
- else
- {
- f = fabs(t.x - 90) / epsilon;
- if(f < 1)
- {
- //t_x = 90;
- t.y -= t.z;
- t.z = 0;
- }
- }
- return t;
-}
-
-#ifdef POSITIVE_PITCH_IS_DOWN
-vector AnglesTransform_ApplyToAngles(vector transform, vector v)
-{
- v.x = -v.x;
- v = AnglesTransform_Multiply(transform, v);
- v.x = -v.x;
- return v;
-}
-vector AnglesTransform_ApplyToVAngles(vector transform, vector v)
-{
- v = AnglesTransform_Multiply(transform, v);
- return v;
-}
-vector AnglesTransform_FromAngles(vector v)
-{
- v.x = -v.x;
- return v;
-}
-vector AnglesTransform_ToAngles(vector v)
-{
- v.x = -v.x;
- return v;
-}
-vector AnglesTransform_FromVAngles(vector v)
-{
- return v;
-}
-vector AnglesTransform_ToVAngles(vector v)
-{
- return v;
-}
-#else
-vector AnglesTransform_ApplyToAngles(vector transform, vector v)
-{
- v = AnglesTransform_Multiply(transform, v);
- return v;
-}
-vector AnglesTransform_ApplyToVAngles(vector transform, vector v)
-{
- v.x = -v.x;
- v = AnglesTransform_Multiply(transform, v);
- v.x = -v.x;
- return v;
-}
-vector AnglesTransform_FromAngles(vector v)
-{
- return v;
-}
-vector AnglesTransform_ToAngles(vector v)
-{
- return v;
-}
-vector AnglesTransform_FromVAngles(vector v)
-{
- v.x = -v.x;
- return v;
-}
-vector AnglesTransform_ToVAngles(vector v)
-{
- v.x = -v.x;
- return v;
-}
-#endif
-
-vector AnglesTransform_Multiply_GetPostShift(vector t0, vector st0, vector t1, vector st1)
-{
- // we want the result of:
- // t0 * (t1 * p + st1) + st0
- // t0 * t1 * p + t0 * st1 + st0
- return st0 + AnglesTransform_Apply(t0, st1);
-}
-vector AnglesTransform_PrePostShift_GetPostShift(vector sf, vector t, vector st)
-{
- return st - AnglesTransform_Apply(t, sf);
-}
+++ /dev/null
-#ifndef ANGLETRANSFORM_H
-#define ANGLETRANSFORM_H
-
-#define POSITIVE_PITCH_IS_DOWN
-
-#ifdef POSITIVE_PITCH_IS_DOWN
-#define fixedmakevectors makevectors
-vector fixedvectoangles(vector a);
-vector fixedvectoangles2(vector a, vector b);
-#else
-void fixedmakevectors(vector a);
-#define fixedvectoangles2 vectoangles2
-#define fixedvectoangles vectoangles
-#endif
-
-vector AnglesTransform_Apply(vector transform, vector v);
-vector AnglesTransform_Multiply(vector t1, vector t2); // A B
-vector AnglesTransform_Invert(vector transform);
-vector AnglesTransform_TurnDirectionFU(vector transform);
-vector AnglesTransform_TurnDirectionFR(vector transform);
-vector AnglesTransform_RightDivide(vector to_transform, vector from_transform); // A B^-1
-vector AnglesTransform_LeftDivide(vector from_transform, vector to_transform); // A^-1 B
-
-vector AnglesTransform_Normalize(vector t, float minimize_roll); // makes sure all angles are in their range: yaw in -180..180, pitch in -90..90, roll in -180..180 (or if minimize_roll is set, pitch in -180..180, roll in -90..90)
-
-vector AnglesTransform_ApplyToAngles(vector transform, vector v);
-vector AnglesTransform_ApplyToVAngles(vector transform, vector v);
-vector AnglesTransform_FromAngles(vector v);
-vector AnglesTransform_ToAngles(vector v);
-vector AnglesTransform_FromVAngles(vector v);
-vector AnglesTransform_ToVAngles(vector v);
-
-// transformed = original * transform + postshift
-vector AnglesTransform_Multiply_GetPostShift(vector sf0, vector st0, vector t1, vector st1);
-vector AnglesTransform_PrePostShift_GetPostShift(vector sf, vector t, vector st);
-#endif
+++ /dev/null
-#include "client.qh"
-#include "common.qh"
-
-#if defined(CSQC)
- #include "../client/autocvars.qh"
- #include "../csqcmodellib/cl_model.qh"
- #include "../dpdefs/csprogsdefs.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
-
-void WarpZone_Fade_PreDraw()
-{SELFPARAM();
- vector org;
- org = getpropertyvec(VF_ORIGIN);
- if(!checkpvs(org, self)) // this makes sense as long as we don't support recursive warpzones
- self.alpha = 0;
- else if(self.warpzone_fadestart)
- self.alpha = bound(0, (self.warpzone_fadeend - vlen(org - self.origin - 0.5 * (self.mins + self.maxs))) / (self.warpzone_fadeend - self.warpzone_fadestart), 1);
- else
- self.alpha = 1;
- //printf("%v <-> %v\n", view_origin, self.origin + 0.5 * (self.mins + self.maxs));
- if(self.alpha <= 0)
- self.drawmask = 0;
- else
- self.drawmask = MASK_NORMAL;
-}
-
-void WarpZone_Read(float isnew)
-{SELFPARAM();
- warpzone_warpzones_exist = 1;
- if (!self.enemy)
- {
- self.enemy = spawn();
- self.enemy.classname = "warpzone_from";
- }
- self.classname = "trigger_warpzone";
-
- int f = ReadByte();
- self.warpzone_isboxy = (f & 1);
- if(f & 4)
- {
- self.origin_x = ReadCoord();
- self.origin_y = ReadCoord();
- self.origin_z = ReadCoord();
- }
- else
- self.origin = '0 0 0';
- self.modelindex = ReadShort();
- self.mins_x = ReadCoord();
- self.mins_y = ReadCoord();
- self.mins_z = ReadCoord();
- self.maxs_x = ReadCoord();
- self.maxs_y = ReadCoord();
- self.maxs_z = ReadCoord();
- self.scale = ReadByte() / 16;
- self.enemy.oldorigin_x = ReadCoord();
- self.enemy.oldorigin_y = ReadCoord();
- self.enemy.oldorigin_z = ReadCoord();
- self.enemy.avelocity_x = ReadCoord();
- self.enemy.avelocity_y = ReadCoord();
- self.enemy.avelocity_z = ReadCoord();
- self.oldorigin_x = ReadCoord();
- self.oldorigin_y = ReadCoord();
- self.oldorigin_z = ReadCoord();
- self.avelocity_x = ReadCoord();
- self.avelocity_y = ReadCoord();
- self.avelocity_z = ReadCoord();
-
- if(f & 2)
- {
- self.warpzone_fadestart = ReadShort();
- self.warpzone_fadeend = max(self.warpzone_fadestart + 1, ReadShort());
- }
- else
- {
- self.warpzone_fadestart = 0;
- self.warpzone_fadeend = 0;
- }
-
- // common stuff
- WarpZone_SetUp(self, self.enemy.oldorigin, self.enemy.avelocity, self.oldorigin, self.avelocity);
-
- // link me
- //setmodel(self, self.model);
- setorigin(self, self.origin);
- setsize(self, self.mins, self.maxs);
-
- // how to draw
- // engine currently wants this
- self.predraw = WarpZone_Fade_PreDraw;
-}
-
-void WarpZone_Camera_Read(float isnew)
-{SELFPARAM();
- warpzone_cameras_exist = 1;
- self.classname = "func_warpzone_camera";
-
- int f = ReadByte();
- if(f & 4)
- {
- self.origin_x = ReadCoord();
- self.origin_y = ReadCoord();
- self.origin_z = ReadCoord();
- }
- else
- self.origin = '0 0 0';
- self.modelindex = ReadShort();
- self.mins_x = ReadCoord();
- self.mins_y = ReadCoord();
- self.mins_z = ReadCoord();
- self.maxs_x = ReadCoord();
- self.maxs_y = ReadCoord();
- self.maxs_z = ReadCoord();
- self.scale = ReadByte() / 16;
- self.oldorigin_x = ReadCoord();
- self.oldorigin_y = ReadCoord();
- self.oldorigin_z = ReadCoord();
- self.avelocity_x = ReadCoord();
- self.avelocity_y = ReadCoord();
- self.avelocity_z = ReadCoord();
-
- if(f & 2)
- {
- self.warpzone_fadestart = ReadShort();
- self.warpzone_fadeend = max(self.warpzone_fadestart + 1, ReadShort());
- }
- else
- {
- self.warpzone_fadestart = 0;
- self.warpzone_fadeend = 0;
- }
-
- // common stuff
- WarpZone_Camera_SetUp(self, self.oldorigin, self.avelocity);
-
- // engine currently wants this
- self.drawmask = MASK_NORMAL;
-
- // link me
- //setmodel(self, self.model);
- setorigin(self, self.origin);
- setsize(self, self.mins, self.maxs);
-
- // how to draw
- // engine currently wants this
- self.predraw = WarpZone_Fade_PreDraw;
-}
-
-void CL_RotateMoves(vector ang) = #638;
-void WarpZone_Teleported_Read(float isnew)
-{SELFPARAM();
- vector v;
- self.classname = "warpzone_teleported";
- v.x = ReadCoord();
- v.y = ReadCoord();
- v.z = ReadCoord();
- if(!isnew)
- return;
- self.warpzone_transform = v;
- setproperty(VF_CL_VIEWANGLES, WarpZone_TransformVAngles(self, getpropertyvec(VF_CL_VIEWANGLES)));
- if(checkextension("DP_CSQC_ROTATEMOVES"))
- CL_RotateMoves(v);
- //CL_RotateMoves('0 90 0');
-}
-
-float warpzone_fixingview;
-float warpzone_fixingview_drawexteriormodel;
-
-void WarpZone_View_Outside()
-{
- if(!warpzone_fixingview)
- return;
- warpzone_fixingview = 0;
- cvar_set("r_drawexteriormodel", ftos(warpzone_fixingview_drawexteriormodel));
-}
-
-void WarpZone_View_Inside()
-{
- if(autocvar_chase_active)
- {
- WarpZone_View_Outside();
- return;
- }
- if(warpzone_fixingview)
- return;
- warpzone_fixingview = 1;
- warpzone_fixingview_drawexteriormodel = cvar("r_drawexteriormodel");
- cvar_set("r_drawexteriormodel", "0");
-}
-
-vector WarpZone_FixNearClip(vector o, vector c0, vector c1, vector c2, vector c3)
-{
- vector mi, ma;
- entity e;
- float pd;
-
- mi.x = min(o.x, c0_x, c1_x, c2_x, c3_x);
- ma.x = max(o.x, c0_x, c1_x, c2_x, c3_x);
- mi.y = min(o.y, c0_y, c1_y, c2_y, c3_y);
- ma.y = max(o.y, c0_y, c1_y, c2_y, c3_y);
- mi.z = min(o.z, c0_z, c1_z, c2_z, c3_z);
- ma.z = max(o.z, c0_z, c1_z, c2_z, c3_z);
-
- e = WarpZone_Find(mi, ma);
- if(e)
- {
- if(WarpZone_PlaneDist(e, o) < 0)
- return '0 0 0';
- // can't really be, though, but if it is, this is not my warpzone, but a random different one in the same mins/maxs
- pd = min(
- WarpZone_PlaneDist(e, c0),
- WarpZone_PlaneDist(e, c1),
- WarpZone_PlaneDist(e, c2),
- WarpZone_PlaneDist(e, c3)
- );
- if(pd < 0)
- return e.warpzone_forward * -pd;
- }
-
- return '0 0 0';
-}
-
-void WarpZone_FixPMove()
-{
- entity e;
- e = WarpZone_Find(pmove_org, pmove_org);
- if(e)
- {
- pmove_org = WarpZone_TransformOrigin(e, pmove_org);
- input_angles = WarpZone_TransformVAngles(e, input_angles);
- }
-}
-
-#ifndef KEEP_ROLL
-float autocvar_cl_rollkillspeed = 10;
-#endif
-void WarpZone_FixView()
-{
- entity e;
- vector org, ang, nearclip, corner0, corner1, corner2, corner3, o;
- float f;
-
- warpzone_save_view_origin = org = getpropertyvec(VF_ORIGIN);
- warpzone_save_view_angles = ang = getpropertyvec(VF_ANGLES);
-
- e = WarpZone_Find(org, org);
- if(e)
- {
- org = WarpZone_TransformOrigin(e, org);
- ang = WarpZone_TransformVAngles(e, ang);
- WarpZone_View_Inside();
- }
- else
- WarpZone_View_Outside();
-
-#ifndef KEEP_ROLL
- float rick;
- if(autocvar_cl_rollkillspeed)
- f = max(0, (1 - frametime * autocvar_cl_rollkillspeed));
- else
- f = 0;
-
- rick = getproperty(VF_CL_VIEWANGLES_Z);
- rick *= f;
- setproperty(VF_CL_VIEWANGLES_Z, rick);
- ang.z *= f;
-#endif
-
- setproperty(VF_ORIGIN, org);
- setproperty(VF_ANGLES, ang);
-
- nearclip = '0 0 1' * (cvar("r_nearclip") * 1.125);
- corner0 = cs_unproject('0 0 0' + nearclip);
- corner1 = cs_unproject('1 0 0' * cvar("vid_conwidth") + nearclip);
- corner2 = cs_unproject('0 1 0' * cvar("vid_conheight") + nearclip);
- corner3 = cs_unproject('1 0 0' * cvar("vid_conwidth") + '0 1 0' * cvar("vid_conheight") + nearclip);
- o = WarpZone_FixNearClip(org, corner0, corner1, corner2, corner3);
- if(o != '0 0 0')
- setproperty(VF_ORIGIN, org + o);
-}
-
-void WarpZone_Init()
-{
-}
-
-void WarpZone_Shutdown()
-{
- WarpZone_View_Outside();
-}
+++ /dev/null
-#ifndef CLIENT_H
-#define CLIENT_H
-
-void WarpZone_Read(float bIsNewEntity);
-void WarpZone_Camera_Read(float bIsNewEntity);
-void WarpZone_Teleported_Read(float bIsNewEntity);
-
-void WarpZone_FixPMove();
-void WarpZone_FixView();
-
-void WarpZone_Init();
-void WarpZone_Shutdown();
-
-vector warpzone_save_view_origin;
-vector warpzone_save_view_angles;
-#endif
+++ /dev/null
-#include "common.qh"
-
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
- #include "../server/t_items.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../common/weapons/all.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../dpdefs/progsdefs.qh"
-#endif
-
-void WarpZone_Accumulator_Clear(entity acc)
-{
- acc.warpzone_transform = '0 0 0';
- acc.warpzone_shift = '0 0 0';
-}
-void WarpZone_Accumulator_AddTransform(entity acc, vector t, vector s)
-{
- vector tr, st;
- tr = AnglesTransform_Multiply(t, acc.warpzone_transform);
- st = AnglesTransform_Multiply_GetPostShift(t, s, acc.warpzone_transform, acc.warpzone_shift);
- acc.warpzone_transform = tr;
- acc.warpzone_shift = st;
-}
-void WarpZone_Accumulator_Add(entity acc, entity wz)
-{
- WarpZone_Accumulator_AddTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
-}
-void WarpZone_Accumulator_AddInverseTransform(entity acc, vector t, vector s)
-{
- vector tt, ss;
- tt = AnglesTransform_Invert(t);
- ss = AnglesTransform_PrePostShift_GetPostShift(s, tt, '0 0 0');
- WarpZone_Accumulator_AddTransform(acc, tt, ss);
- // yes, this probably can be done simpler... but this way is "obvious" :)
-}
-void WarpZone_Accumulator_AddInverse(entity acc, entity wz)
-{
- WarpZone_Accumulator_AddInverseTransform(acc, wz.warpzone_transform, wz.warpzone_shift);
-}
-
-.vector(vector, vector) camera_transform;
-float autocvar_cl_warpzone_usetrace = 1;
-vector WarpZone_camera_transform(vector org, vector ang)
-{SELFPARAM();
- vector vf, vr, vu;
- if(self.warpzone_fadestart)
- if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400)
- return org;
- // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
- // unneeded on client, on server this helps a lot
- vf = v_forward;
- vr = v_right;
- vu = v_up;
- org = WarpZone_TransformOrigin(self, org);
- vf = WarpZone_TransformVelocity(self, vf);
- vr = WarpZone_TransformVelocity(self, vr);
- vu = WarpZone_TransformVelocity(self, vu);
- if(autocvar_cl_warpzone_usetrace)
- traceline(self.warpzone_targetorigin, org, MOVE_NOMONSTERS, world);
- else
- trace_endpos = self.warpzone_targetorigin;
- v_forward = vf;
- v_right = vr;
- v_up = vu;
- return org;
-}
-
-void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang)
-{
- e.warpzone_transform = AnglesTransform_RightDivide(other_ang, AnglesTransform_TurnDirectionFR(my_ang));
- e.warpzone_shift = AnglesTransform_PrePostShift_GetPostShift(my_org, e.warpzone_transform, other_org);
- e.warpzone_origin = my_org;
- e.warpzone_targetorigin = other_org;
- e.warpzone_angles = my_ang;
- e.warpzone_targetangles = other_ang;
- fixedmakevectors(my_ang); e.warpzone_forward = v_forward;
- fixedmakevectors(other_ang); e.warpzone_targetforward = v_forward;
- e.camera_transform = WarpZone_camera_transform;
-}
-
-vector WarpZone_Camera_camera_transform(vector org, vector ang)
-{SELFPARAM();
- // a fixed camera view
- if(self.warpzone_fadestart)
- if(vlen(org - self.origin - 0.5 * (self.mins + self.maxs)) > self.warpzone_fadeend + 400)
- return org;
- // don't transform if zone faded out (plus 400qu safety margin for typical speeds and latencies)
- // unneeded on client, on server this helps a lot
- trace_endpos = self.warpzone_origin;
- makevectors(self.warpzone_angles);
- return self.warpzone_origin;
-}
-
-void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang) // we assume that e.oldorigin and e.avelocity point to view origin and direction
-{
- e.warpzone_origin = my_org;
- e.warpzone_angles = my_ang;
- e.camera_transform = WarpZone_Camera_camera_transform;
-}
-
-.entity enemy;
-
-vector WarpZoneLib_BoxTouchesBrush_mins;
-vector WarpZoneLib_BoxTouchesBrush_maxs;
-entity WarpZoneLib_BoxTouchesBrush_ent;
-entity WarpZoneLib_BoxTouchesBrush_ignore;
-float WarpZoneLib_BoxTouchesBrush_Recurse()
-{
- float s;
- entity se;
- float f;
-
- tracebox('0 0 0', WarpZoneLib_BoxTouchesBrush_mins, WarpZoneLib_BoxTouchesBrush_maxs, '0 0 0', MOVE_NOMONSTERS, WarpZoneLib_BoxTouchesBrush_ignore);
-#ifdef CSQC
- if (trace_networkentity)
- {
- LOG_TRACE("hit a network ent, cannot continue WarpZoneLib_BoxTouchesBrush\n");
- // we cannot continue, as a player blocks us...
- // so, abort
- return 0;
- }
-#endif
- if (!trace_ent)
- return 0;
- if (trace_ent == WarpZoneLib_BoxTouchesBrush_ent)
- return 1;
-
- se = trace_ent;
- s = se.solid;
- se.solid = SOLID_NOT;
- f = WarpZoneLib_BoxTouchesBrush_Recurse();
- se.solid = s;
-
- return f;
-}
-
-float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
-{
- float f, s;
-
- if(!e.modelindex || e.warpzone_isboxy)
- return 1;
-
- s = e.solid;
- e.solid = SOLID_BSP;
- WarpZoneLib_BoxTouchesBrush_mins = mi;
- WarpZoneLib_BoxTouchesBrush_maxs = ma;
- WarpZoneLib_BoxTouchesBrush_ent = e;
- WarpZoneLib_BoxTouchesBrush_ignore = ig;
- f = WarpZoneLib_BoxTouchesBrush_Recurse();
- e.solid = s;
-
- return f;
-}
-
-entity WarpZone_Find(vector mi, vector ma)
-{
- // if we are near any warpzone planes - MOVE AWAY (work around nearclip)
- entity e;
- if(!warpzone_warpzones_exist)
- return world;
- for(e = world; (e = find(e, classname, "trigger_warpzone")); )
- if(WarpZoneLib_BoxTouchesBrush(mi, ma, e, world))
- return e;
- return world;
-}
-
-void WarpZone_MakeAllSolid()
-{
- entity e;
- if(!warpzone_warpzones_exist)
- return;
- for(e = world; (e = find(e, classname, "trigger_warpzone")); )
- e.solid = SOLID_BSP;
-}
-
-void WarpZone_MakeAllOther()
-{
- entity e;
- if(!warpzone_warpzones_exist)
- return;
- for(e = world; (e = find(e, classname, "trigger_warpzone")); )
- e.solid = SOLID_TRIGGER;
-}
-
-void WarpZone_Trace_InitTransform()
-{
- if(!WarpZone_trace_transform)
- {
- WarpZone_trace_transform = spawn();
- WarpZone_trace_transform.classname = "warpzone_trace_transform";
- }
- WarpZone_Accumulator_Clear(WarpZone_trace_transform);
-}
-void WarpZone_Trace_AddTransform(entity wz)
-{
- WarpZone_Accumulator_Add(WarpZone_trace_transform, wz);
-}
-
-void WarpZone_TraceBox_ThroughZone(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent, entity zone, WarpZone_trace_callback_t cb)
-{
- float nomonsters_adjusted;
- float frac, sol, i;
- float contentshack;
- vector o0, e0;
- entity wz;
- vector vf, vr, vu;
-
- WarpZone_trace_forent = forent;
- WarpZone_trace_firstzone = world;
- WarpZone_trace_lastzone = world;
- WarpZone_Trace_InitTransform();
- if(!warpzone_warpzones_exist)
- {
- if(nomonsters == MOVE_NOTHING)
- {
- trace_endpos = end;
- trace_fraction = 1;
- if(cb)
- cb(org, trace_endpos, end);
- return;
- }
- else
- {
- tracebox(org, mi, ma, end, nomonsters, WarpZone_trace_forent);
- if(cb)
- cb(org, trace_endpos, end);
- return;
- }
- }
-
- vf = v_forward;
- vr = v_right;
- vu = v_up;
- o0 = org;
- e0 = end;
-
- switch(nomonsters)
- {
- case MOVE_WORLDONLY:
- case MOVE_NOTHING:
- nomonsters_adjusted = MOVE_NOMONSTERS;
- break;
- default:
- nomonsters_adjusted = nomonsters;
- break;
- }
- if((contentshack = (WarpZone_trace_forent.dphitcontentsmask && !(WarpZone_trace_forent.dphitcontentsmask & DPCONTENTS_SOLID))))
- BITSET_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
-
- // if starting in warpzone, first transform
- wz = WarpZone_Find(org + mi, org + ma);
- if(wz)
- {
- WarpZone_trace_firstzone = wz;
- WarpZone_trace_lastzone = wz;
- if(zone && wz != zone)
- {
- // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
- sol = 1;
- trace_fraction = 0;
- trace_endpos = org;
- goto fail;
- }
- WarpZone_Trace_AddTransform(wz);
- org = WarpZone_TransformOrigin(wz, org);
- end = WarpZone_TransformOrigin(wz, end);
- }
- WarpZone_MakeAllSolid();
- sol = -1;
- frac = 0;
- i = 16;
- for (;;)
- {
- if(--i < 1)
- {
- LOG_TRACE("Too many warpzones in sequence, aborting trace.\n");
- trace_ent = world;
- break;
- }
- tracebox(org, mi, ma, end, nomonsters_adjusted, WarpZone_trace_forent);
- if(cb)
- cb(org, trace_endpos, end);
- if(sol < 0)
- sol = trace_startsolid;
-
- frac = trace_fraction = frac + (1 - frac) * trace_fraction;
- if(trace_fraction >= 1)
- break;
- if(trace_ent.classname != "trigger_warpzone")
- {
- if((nomonsters == MOVE_NOTHING) || ((nomonsters == MOVE_WORLDONLY) && trace_ent) || (contentshack && (trace_dphitcontents & WarpZone_trace_forent.dphitcontentsmask) == DPCONTENTS_SOLID))
- {
- // continue the trace, ignoring this hit (we only care for warpzones)
- org = trace_endpos + normalize(end - org);
- continue;
- // we cannot do an inverted trace here, as we do care for further warpzones inside that "solid" to be found
- // otherwise, players could block entrances that way
- }
- break;
- }
- if(trace_ent == wz)
- {
- // FIXME can this check be removed? Do we really need it?
- LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace\n");
- trace_ent = world;
- break;
- }
- wz = trace_ent;
- if(!WarpZone_trace_firstzone)
- WarpZone_trace_firstzone = wz;
- WarpZone_trace_lastzone = wz;
- if(zone && wz != zone)
- break;
- WarpZone_Trace_AddTransform(wz);
- // we hit a warpzone... so, let's perform the trace after the warp again
- org = WarpZone_TransformOrigin(wz, trace_endpos);
- end = WarpZone_TransformOrigin(wz, end);
-
- // we got warped, so let's step back a bit
- tracebox(org, mi, ma, org + normalize(org - end) * 32, nomonsters_adjusted, WarpZone_trace_forent);
- org = trace_endpos;
- }
- WarpZone_MakeAllOther();
-:fail
- if(contentshack)
- BITCLR_ASSIGN(WarpZone_trace_forent.dphitcontentsmask, DPCONTENTS_SOLID);
- trace_startsolid = sol;
- v_forward = vf;
- v_right = vr;
- v_up = vu;
-}
-
-void WarpZone_TraceBox(vector org, vector mi, vector ma, vector end, float nomonsters, entity forent)
-{
- WarpZone_TraceBox_ThroughZone(org, mi, ma, end, nomonsters, forent, world, WarpZone_trace_callback_t_null);
-}
-
-void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent)
-{
- WarpZone_TraceBox(org, '0 0 0', '0 0 0', end, nomonsters, forent);
-}
-
-void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZone_trace_callback_t cb)
-{
- float g, dt, i;
- vector vf, vr, vu, v0, o0;
- entity wz;
-
- o0 = e.origin;
- v0 = e.velocity;
- g = cvar("sv_gravity") * e.gravity;
-
- WarpZone_trace_forent = forent;
- WarpZone_trace_firstzone = world;
- WarpZone_trace_lastzone = world;
- WarpZone_Trace_InitTransform();
- WarpZone_tracetoss_time = 0;
- if(!warpzone_warpzones_exist)
- {
- tracetoss(e, WarpZone_trace_forent);
- if(cb)
- cb(e.origin, trace_endpos, trace_endpos);
- dt = vlen(e.origin - o0) / vlen(e.velocity);
- WarpZone_tracetoss_time += dt;
- e.velocity_z -= dt * g;
- WarpZone_tracetoss_velocity = e.velocity;
- e.velocity = v0;
- return;
- }
-
- vf = v_forward;
- vr = v_right;
- vu = v_up;
-
- // if starting in warpzone, first transform
- wz = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs);
- if(wz)
- {
- WarpZone_trace_firstzone = wz;
- WarpZone_trace_lastzone = wz;
- if(zone && wz != zone)
- {
- // we are in ANOTHER warpzone. This is bad. Make a zero length trace and return.
-
- WarpZone_tracetoss_time = 0;
- trace_endpos = o0;
- goto fail;
- }
- WarpZone_Trace_AddTransform(wz);
- setorigin(e, WarpZone_TransformOrigin(wz, e.origin));
- e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
- }
- WarpZone_MakeAllSolid();
- i = 16;
- for (;;)
- {
- if(--i < 1)
- {
- LOG_TRACE("Too many warpzones in sequence, aborting trace.\n");
- trace_ent = world;
- break;
- }
- tracetoss(e, WarpZone_trace_forent);
- if(cb)
- cb(e.origin, trace_endpos, trace_endpos);
- dt = vlen(trace_endpos - e.origin) / vlen(e.velocity);
- WarpZone_tracetoss_time += dt;
- e.origin = trace_endpos;
- e.velocity_z -= dt * g;
- if(trace_fraction >= 1)
- break;
- if(trace_ent.classname != "trigger_warpzone")
- break;
- if(trace_ent == wz)
- {
- // FIXME can this check be removed? Do we really need it?
- LOG_TRACE("I transformed into the same zone again, wtf, aborting the trace\n");
- trace_ent = world;
- break;
- }
- wz = trace_ent;
- if(!WarpZone_trace_firstzone)
- WarpZone_trace_firstzone = wz;
- WarpZone_trace_lastzone = wz;
- if(zone && wz != zone)
- break;
- WarpZone_Trace_AddTransform(wz);
- // we hit a warpzone... so, let's perform the trace after the warp again
- e.origin = WarpZone_TransformOrigin(wz, e.origin);
- e.velocity = WarpZone_TransformVelocity(wz, e.velocity);
-
- // we got warped, so let's step back a bit
- e.velocity = -e.velocity;
- tracetoss(e, WarpZone_trace_forent);
- dt = vlen(trace_endpos - e.origin) / vlen(e.velocity);
- WarpZone_tracetoss_time -= dt;
- e.origin = trace_endpos;
- e.velocity = -e.velocity;
- }
- WarpZone_MakeAllOther();
-:fail
- WarpZone_tracetoss_velocity = e.velocity;
- v_forward = vf;
- v_right = vr;
- v_up = vu;
- // restore old entity data (caller just uses trace_endpos, WarpZone_tracetoss_velocity and the transform)
- e.velocity = v0;
- e.origin = o0;
-}
-
-void WarpZone_TraceToss(entity e, entity forent)
-{
- WarpZone_TraceToss_ThroughZone(e, forent, world, WarpZone_trace_callback_t_null);
-}
-
-entity WarpZone_TrailParticles_trace_callback_own;
-float WarpZone_TrailParticles_trace_callback_eff;
-void WarpZone_TrailParticles_trace_callback(vector from, vector endpos, vector to)
-{
- trailparticles(WarpZone_TrailParticles_trace_callback_own, WarpZone_TrailParticles_trace_callback_eff, from, endpos);
-}
-
-void WarpZone_TrailParticles(entity own, float eff, vector org, vector end)
-{
- WarpZone_TrailParticles_trace_callback_own = own;
- WarpZone_TrailParticles_trace_callback_eff = eff;
- WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_trace_callback);
-}
-
-#ifdef CSQC
-float WarpZone_TrailParticles_trace_callback_f;
-float WarpZone_TrailParticles_trace_callback_flags;
-void WarpZone_TrailParticles_WithMultiplier_trace_callback(vector from, vector endpos, vector to)
-{
- boxparticles(WarpZone_TrailParticles_trace_callback_eff, WarpZone_TrailParticles_trace_callback_own, from, endpos, WarpZone_TrailParticles_trace_callback_own.velocity, WarpZone_TrailParticles_trace_callback_own.velocity, WarpZone_TrailParticles_trace_callback_f, WarpZone_TrailParticles_trace_callback_flags);
-}
-
-void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, int boxflags)
-{
- WarpZone_TrailParticles_trace_callback_own = own;
- WarpZone_TrailParticles_trace_callback_eff = eff;
- WarpZone_TrailParticles_trace_callback_f = f;
- WarpZone_TrailParticles_trace_callback_flags = boxflags | PARTICLES_DRAWASTRAIL;
- WarpZone_TraceBox_ThroughZone(org, '0 0 0', '0 0 0', end, MOVE_NOMONSTERS, world, world, WarpZone_TrailParticles_WithMultiplier_trace_callback);
-}
-#endif
-
-float WarpZone_PlaneDist(entity wz, vector v)
-{
- return (v - wz.warpzone_origin) * wz.warpzone_forward;
-}
-
-float WarpZone_TargetPlaneDist(entity wz, vector v)
-{
- return (v - wz.warpzone_targetorigin) * wz.warpzone_targetforward;
-}
-
-vector WarpZone_TransformOrigin(entity wz, vector v)
-{
- return wz.warpzone_shift + AnglesTransform_Apply(wz.warpzone_transform, v);
-}
-
-vector WarpZone_TransformVelocity(entity wz, vector v)
-{
- return AnglesTransform_Apply(wz.warpzone_transform, v);
-}
-
-vector WarpZone_TransformAngles(entity wz, vector v)
-{
- return AnglesTransform_ApplyToAngles(wz.warpzone_transform, v);
-}
-
-vector WarpZone_TransformVAngles(entity wz, vector ang)
-{
-#ifdef KEEP_ROLL
- float roll;
- roll = ang.z;
- ang.z = 0;
-#endif
-
- ang = AnglesTransform_ApplyToVAngles(wz.warpzone_transform, ang);
-
-#ifdef KEEP_ROLL
- ang = AnglesTransform_Normalize(ang, true);
- ang = AnglesTransform_CancelRoll(ang);
- ang.z = roll;
-#else
- ang = AnglesTransform_Normalize(ang, false);
-#endif
-
- return ang;
-}
-
-vector WarpZone_UnTransformOrigin(entity wz, vector v)
-{
- return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v - wz.warpzone_shift);
-}
-
-vector WarpZone_UnTransformVelocity(entity wz, vector v)
-{
- return AnglesTransform_Apply(AnglesTransform_Invert(wz.warpzone_transform), v);
-}
-
-vector WarpZone_UnTransformAngles(entity wz, vector v)
-{
- return AnglesTransform_ApplyToAngles(AnglesTransform_Invert(wz.warpzone_transform), v);
-}
-
-vector WarpZone_UnTransformVAngles(entity wz, vector ang)
-{
- float roll;
-
- roll = ang.z;
- ang.z = 0;
-
- ang = AnglesTransform_ApplyToVAngles(AnglesTransform_Invert(wz.warpzone_transform), ang);
- ang = AnglesTransform_Normalize(ang, true);
- ang = AnglesTransform_CancelRoll(ang);
-
- ang.z = roll;
- return ang;
-}
-
-vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org)
-{
- vector nearest;
- nearest.x = bound(mi.x, org.x, ma.x);
- nearest.y = bound(mi.y, org.y, ma.y);
- nearest.z = bound(mi.z, org.z, ma.z);
- return nearest;
-}
-
-bool WarpZoneLib_BadEntity(entity e)
-{
- string myclassname = e.classname;
- if (e.instanceOfObject) return true;
- switch(myclassname)
- {
- case "deathtype":
- case "weaponentity":
- case "exteriorweaponentity":
- case "csqc_score_team":
- case "pingplreport":
- case "ent_client_scoreinfo":
- case "saved_cvar_value":
- case "accuracy":
- case "entcs_sender":
- case "entcs_receiver":
- case "clientinit":
- case "sprite_waypoint":
- case "waypoint":
- case "gibsplash":
- //case "net_linked": // actually some real entities are linked without classname, fail
- case "":
- return true;
- }
-
- if(startsWith(myclassname, "msg_"))
- return true;
-
- if(startsWith(myclassname, "target_"))
- return true;
-
- if(startsWith(myclassname, "info_"))
- return true;
-
- return false;
-}
-
-.float WarpZone_findradius_hit;
-.entity WarpZone_findradius_next;
-void WarpZone_FindRadius_Recurse(vector org, float rad, vector org0, vector transform, vector shift, float needlineofsight)
-// blast origin of current search original blast origin how to untransform (victim to blast system)
-{
- vector org_new;
- vector org0_new;
- vector shift_new, transform_new;
- vector p;
- entity e, e0;
- entity wz;
- if(rad <= 0)
- return;
- e0 = findradius(org, rad);
- wz = world;
-
- for(e = e0; e; e = e.chain)
- {
- if(WarpZoneLib_BadEntity(e))
- continue;
- p = WarpZoneLib_NearestPointOnBox(e.origin + e.mins, e.origin + e.maxs, org0);
- if(needlineofsight)
- {
- traceline(org, p, MOVE_NOMONSTERS, e);
- if(trace_fraction < 1)
- continue;
- }
- if(!e.WarpZone_findradius_hit || vlen(e.WarpZone_findradius_dist) > vlen(org0 - p))
- {
- e.WarpZone_findradius_nearest = p;
- e.WarpZone_findradius_dist = org0 - p;
- e.WarpZone_findradius_findorigin = org;
- e.WarpZone_findradius_findradius = rad;
- if(e.classname == "warpzone_refsys")
- {
- // ignore, especially: do not overwrite the refsys parameters
- }
- else if(e.classname == "trigger_warpzone")
- {
- e.WarpZone_findradius_next = wz;
- wz = e;
- e.WarpZone_findradius_hit = 1;
- e.enemy.WarpZone_findradius_dist = '0 0 0'; // we don't want to go through this zone ever again
- e.enemy.WarpZone_findradius_hit = 1;
- }
- else
- {
- e.warpzone_transform = transform;
- e.warpzone_shift = shift;
- e.WarpZone_findradius_hit = 1;
- }
- }
- }
- for(e = wz; e; e = e.WarpZone_findradius_next)
- {
- if(WarpZoneLib_BadEntity(e))
- continue;
-
- org0_new = WarpZone_TransformOrigin(e, org);
- traceline(e.warpzone_targetorigin, org0_new, MOVE_NOMONSTERS, e);
- org_new = trace_endpos;
-
- transform_new = AnglesTransform_Multiply(e.warpzone_transform, transform);
- shift_new = AnglesTransform_Multiply_GetPostShift(e.warpzone_transform, e.warpzone_shift, transform, shift);
- WarpZone_FindRadius_Recurse(
- org_new,
- bound(0, rad - vlen(org_new - org0_new), rad - 8),
- org0_new,
- transform_new, shift_new,
- needlineofsight);
- e.WarpZone_findradius_hit = 0;
- e.enemy.WarpZone_findradius_hit = 0;
- }
-}
-entity WarpZone_FindRadius(vector org, float rad, float needlineofsight)
-{
- entity e0, e;
- WarpZone_FindRadius_Recurse(org, rad, org, '0 0 0', '0 0 0', needlineofsight);
- e0 = findchainfloat(WarpZone_findradius_hit, 1);
- for(e = e0; e; e = e.chain)
- e.WarpZone_findradius_hit = 0;
- return e0;
-}
-
-.entity WarpZone_refsys;
-void WarpZone_RefSys_GC()
-{SELFPARAM();
- // garbage collect unused reference systems
- self.nextthink = time + 1;
- if(self.owner.WarpZone_refsys != self)
- remove(self);
-}
-void WarpZone_RefSys_CheckCreate(entity me)
-{
- if(me.WarpZone_refsys.owner != me)
- {
- me.WarpZone_refsys = spawn();
- me.WarpZone_refsys.classname = "warpzone_refsys";
- me.WarpZone_refsys.owner = me;
- me.WarpZone_refsys.think = WarpZone_RefSys_GC;
- me.WarpZone_refsys.nextthink = time + 1;
- WarpZone_Accumulator_Clear(me.WarpZone_refsys);
- }
-}
-void WarpZone_RefSys_Clear(entity me)
-{
- if(me.WarpZone_refsys)
- {
- remove(me.WarpZone_refsys);
- me.WarpZone_refsys = world;
- }
-}
-void WarpZone_RefSys_AddTransform(entity me, vector t, vector s)
-{
- if(t != '0 0 0' || s != '0 0 0')
- {
- WarpZone_RefSys_CheckCreate(me);
- WarpZone_Accumulator_AddTransform(me.WarpZone_refsys, t, s);
- }
-}
-void WarpZone_RefSys_Add(entity me, entity wz)
-{
- WarpZone_RefSys_AddTransform(me, wz.warpzone_transform, wz.warpzone_shift);
-}
-void WarpZone_RefSys_AddInverseTransform(entity me, vector t, vector s)
-{
- if(t != '0 0 0' || s != '0 0 0')
- {
- WarpZone_RefSys_CheckCreate(me);
- WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, t, s);
- }
-}
-void WarpZone_RefSys_AddInverse(entity me, entity wz)
-{
- WarpZone_RefSys_AddInverseTransform(me, wz.warpzone_transform, wz.warpzone_shift);
-}
-.vector WarpZone_refsys_incremental_shift;
-.vector WarpZone_refsys_incremental_transform;
-void WarpZone_RefSys_AddIncrementally(entity me, entity ref)
-{
- //vector t, s;
- if(me.WarpZone_refsys_incremental_transform == ref.WarpZone_refsys.warpzone_transform)
- if(me.WarpZone_refsys_incremental_shift == ref.WarpZone_refsys.warpzone_shift)
- return;
- WarpZone_Accumulator_AddInverseTransform(me.WarpZone_refsys, me.WarpZone_refsys_incremental_transform, me.WarpZone_refsys_incremental_shift);
- WarpZone_Accumulator_Add(me.WarpZone_refsys, ref.WarpZone_refsys);
- me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
- me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
-}
-void WarpZone_RefSys_BeginAddingIncrementally(entity me, entity ref)
-{
- me.WarpZone_refsys_incremental_shift = ref.WarpZone_refsys.warpzone_shift;
- me.WarpZone_refsys_incremental_transform = ref.WarpZone_refsys.warpzone_transform;
-}
-vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org)
-{
- if(from.WarpZone_refsys)
- org = WarpZone_UnTransformOrigin(from.WarpZone_refsys, org);
- if(to.WarpZone_refsys)
- org = WarpZone_TransformOrigin(to.WarpZone_refsys, org);
- return org;
-}
-vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel)
-{
- if(from.WarpZone_refsys)
- vel = WarpZone_UnTransformVelocity(from.WarpZone_refsys, vel);
- if(to.WarpZone_refsys)
- vel = WarpZone_TransformVelocity(to.WarpZone_refsys, vel);
- return vel;
-}
-vector WarpZone_RefSys_TransformAngles(entity from, entity to, vector ang)
-{
- if(from.WarpZone_refsys)
- ang = WarpZone_UnTransformAngles(from.WarpZone_refsys, ang);
- if(to.WarpZone_refsys)
- ang = WarpZone_TransformAngles(to.WarpZone_refsys, ang);
- return ang;
-}
-vector WarpZone_RefSys_TransformVAngles(entity from, entity to, vector ang)
-{
- if(from.WarpZone_refsys)
- ang = WarpZone_UnTransformVAngles(from.WarpZone_refsys, ang);
- if(to.WarpZone_refsys)
- ang = WarpZone_TransformVAngles(to.WarpZone_refsys, ang);
- return ang;
-}
-void WarpZone_RefSys_Copy(entity me, entity from)
-{
- if(from.WarpZone_refsys)
- {
- WarpZone_RefSys_CheckCreate(me);
- me.WarpZone_refsys.warpzone_shift = from.WarpZone_refsys.warpzone_shift;
- me.WarpZone_refsys.warpzone_transform = from.WarpZone_refsys.warpzone_transform;
- }
- else
- WarpZone_RefSys_Clear(me);
-}
-entity WarpZone_RefSys_SpawnSameRefSys(entity me)
-{
- entity e;
- e = spawn();
- WarpZone_RefSys_Copy(e, me);
- return e;
-}
-
-float WarpZoneLib_ExactTrigger_Touch()
-{SELFPARAM();
- return !WarpZoneLib_BoxTouchesBrush(other.absmin, other.absmax, self, other);
-}
-
-
-void WarpZoneLib_MoveOutOfSolid_Expand(entity e, vector by)
-{
- float eps = 0.0625;
- tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
- if (trace_startsolid)
- return;
- if (trace_fraction < 1)
- {
- // hit something
- // adjust origin in the other direction...
- setorigin(e,e.origin - by * (1 - trace_fraction));
- }
-}
-
-float WarpZoneLib_MoveOutOfSolid(entity e)
-{
- vector o, m0, m1;
-
- o = e.origin;
- traceline(o, o, MOVE_WORLDONLY, e);
- if (trace_startsolid)
- return false;
-
- tracebox(o, e.mins, e.maxs, o, MOVE_WORLDONLY, e);
- if (!trace_startsolid)
- return true;
-
- m0 = e.mins;
- m1 = e.maxs;
- e.mins = '0 0 0';
- e.maxs = '0 0 0';
- WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m0_x);
- e.mins_x = m0_x;
- WarpZoneLib_MoveOutOfSolid_Expand(e, '1 0 0' * m1_x);
- e.maxs_x = m1_x;
- WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m0_y);
- e.mins_y = m0_y;
- WarpZoneLib_MoveOutOfSolid_Expand(e, '0 1 0' * m1_y);
- e.maxs_y = m1_y;
- WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m0_z);
- e.mins_z = m0_z;
- WarpZoneLib_MoveOutOfSolid_Expand(e, '0 0 1' * m1_z);
- e.maxs_z = m1_z;
- setorigin(e, e.origin);
-
- tracebox(e.origin, e.mins, e.maxs, e.origin, MOVE_WORLDONLY, e);
- if (trace_startsolid)
- {
- setorigin(e, o);
- return false;
- }
-
- return true;
-}
+++ /dev/null
-#ifndef WARPZONELIB_COMMON_H
-#define WARPZONELIB_COMMON_H
-
-// uncomment this if your mod uses the roll angle in fixangle
-// #define KEEP_ROLL
-
-float warpzone_warpzones_exist;
-float warpzone_cameras_exist;
-
-.float warpzone_isboxy;
-.vector warpzone_shift;
-.vector warpzone_origin;
-.vector warpzone_angles;
-.vector warpzone_forward;
-.vector warpzone_targetorigin;
-.vector warpzone_targetangles;
-.vector warpzone_targetforward;
-.vector warpzone_transform;
-.float warpzone_fadestart;
-.float warpzone_fadeend;
-void WarpZone_SetUp(entity e, vector my_org, vector my_ang, vector other_org, vector other_ang);
-void WarpZone_Camera_SetUp(entity e, vector my_org, vector my_ang);
-
-float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig);
-vector WarpZoneLib_NearestPointOnBox(vector mi, vector ma, vector org);
-
-entity WarpZone_Find(vector mi, vector ma);
-void WarpZone_MakeAllSolid();
-void WarpZone_MakeAllOther();
-
-#define MOVE_NOTHING -1
-entity WarpZone_trace_forent; // temp, callback is allowed to change it
-typedef void(vector start, vector hit, vector end) WarpZone_trace_callback_t; // called on every elementary trace
-var WarpZone_trace_callback_t WarpZone_trace_callback_t_null;
-entity WarpZone_trace_transform; // transform accumulator during a trace
-entity WarpZone_trace_firstzone; // first warpzone hit by a trace (can differ from the requested zone in case of _ThroughZone, the trace is aborted then)
-entity WarpZone_trace_lastzone; // first warpzone hit by a trace (can differ from the requested zone in case of _ThroughZone, the trace is aborted then)
-vector WarpZone_tracetoss_velocity; // ending velocity of a tracetoss (post-transform)
-float WarpZone_tracetoss_time; // duration of toss (approximate)
-void WarpZone_TraceBox(vector org, vector min, vector max, vector end, float nomonsters, entity forent);
-void WarpZone_TraceBox_ThroughZone(vector org, vector min, vector max, vector end, float nomonsters, entity forent, entity zone, WarpZone_trace_callback_t cb);
-void WarpZone_TraceLine(vector org, vector end, float nomonsters, entity forent);
-void WarpZone_TraceToss(entity e, entity forent);
-void WarpZone_TraceToss_ThroughZone(entity e, entity forent, entity zone, WarpZone_trace_callback_t cb);
-void WarpZone_TrailParticles(entity own, float eff, vector org, vector end);
-#ifdef CSQC
-void WarpZone_TrailParticles_WithMultiplier(entity own, float eff, vector org, vector end, float f, float boxflags);
-#endif
-
-.vector WarpZone_findradius_dist;
-.vector WarpZone_findradius_nearest;
-// also set: warpzone parameters, so WarpZone_TransformOrigin can transform vectors from blast's to victim's system
-.vector WarpZone_findradius_findorigin;
-.float WarpZone_findradius_findradius;
-entity WarpZone_FindRadius(vector org, float radius, float needlineofsight);
-
-float WarpZone_PlaneDist(entity wz, vector v);
-float WarpZone_TargetPlaneDist(entity wz, vector v);
-vector WarpZone_TransformOrigin(entity wz, vector v);
-vector WarpZone_TransformVelocity(entity wz, vector v);
-vector WarpZone_TransformAngles(entity wz, vector v);
-vector WarpZone_TransformVAngles(entity wz, vector v);
-vector WarpZone_UnTransformOrigin(entity wz, vector v);
-vector WarpZone_UnTransformVelocity(entity wz, vector v);
-vector WarpZone_UnTransformAngles(entity wz, vector v);
-vector WarpZone_UnTransformVAngles(entity wz, vector v);
-
-// reference systems (chained warpzone transforms)
-void WarpZone_RefSys_Clear(entity me); // R := id
-void WarpZone_RefSys_Add(entity me, entity wz); // me.R := wz me.R
-void WarpZone_RefSys_AddInverse(entity me, entity wz); // me.R := wz^-1 me.R
-void WarpZone_RefSys_AddTransform(entity me, vector t, vector s); // me.R := [t s] me.R
-void WarpZone_RefSys_AddInverseTransform(entity me, vector t, vector s); // me.R := [t s]^-1 me.R
-
-// makes this reference system track ref's changes
-// NOTE: this is ONLY sensible if WarpZone_RefSys_Add is no longer called on "me" while doing this
-// To achieve this, make sure no touch events on warpzone are raised by this entity
-// or set a movetype that causes no warpzoning (e.g. MOVETYPE_NONE, MOVETYPE_FOLLOW)
-void WarpZone_RefSys_AddIncrementally(entity me, entity ref); // me.R := ref.R me.Rref^-1 me.R; me.Rref := ref.R
-void WarpZone_RefSys_BeginAddingIncrementally(entity me, entity ref); // me.Rref := ref.R
-
-vector WarpZone_RefSys_TransformOrigin(entity from, entity to, vector org); // return to.R from.R^-1 org
-vector WarpZone_RefSys_TransformVelocity(entity from, entity to, vector vel); // return to.R from.R^-1 vel
-vector WarpZone_RefSys_TransformAngles(entity from, entity to, vector ang); // return to.R from.R^-1 ang
-vector WarpZone_RefSys_TransformVAngles(entity from, entity to, vector ang); // return to.R from.R^-1 ang
-void WarpZone_RefSys_Copy(entity me, entity from); // to.R := from.R
-entity WarpZone_RefSys_SpawnSameRefSys(entity me); // spawn().R = me.R
-
-#ifndef BITCLR
-# define BITCLR(a,b) ((a) - ((a) & (b)))
-#endif
-#ifndef BITSET
-# define BITSET(a,b) ((a) | (b))
-#endif
-#ifndef BITXOR
-# define BITXOR(a,b) (((a) | (b)) - ((a) & (b)))
-#endif
-#ifndef BITCLR_ASSIGN
-# define BITCLR_ASSIGN(a,b) ((a) = (a) - ((a) & (b)))
-#endif
-#ifndef BITSET_ASSIGN
-# define BITSET_ASSIGN(a,b) ((a) |= (b))
-#endif
-#ifndef BITXOR_ASSIGN
-# define BITXOR_ASSIGN(a,b) ((a) = ((a) | (b)) - ((a) & (b)))
-#endif
-float WarpZoneLib_MoveOutOfSolid(entity e);
-#define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
-
-float WarpZoneLib_ExactTrigger_Touch();
-void WarpZoneLib_ExactTrigger_Init();
-
-// WARNING: this kills the trace globals
-#define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
-#define EXACTTRIGGER_INIT WarpZoneLib_ExactTrigger_Init()
-#endif
+++ /dev/null
-#include "mathlib.qh"
-#if defined(CSQC)
- #include "../dpdefs/csprogsdefs.qh"
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../dpdefs/dpextensions.qh"
- #include "../dpdefs/progsdefs.qh"
-#endif
-
-int fpclassify(float x)
-{
- if(isnan(x))
- return FP_NAN;
- if(isinf(x))
- return FP_INFINITE;
- if(x == 0)
- return FP_ZERO;
- return FP_NORMAL;
-}
-bool isfinite(float x)
-{
- return !(isnan(x) || isinf(x));
-}
-bool isinf(float x)
-{
- return (x != 0) && (x + x == x);
-}
-bool isnan(float x)
-{
- float y;
- y = x;
- return (x != y);
-}
-bool isnormal(float x)
-{
- return isfinite(x);
-}
-bool signbit(float x)
-{
- return (x < 0);
-}
-
-float acosh(float x)
-{
- return log(x + sqrt(x*x - 1));
-}
-float asinh(float x)
-{
- return log(x + sqrt(x*x + 1));
-}
-float atanh(float x)
-{
- return 0.5 * log((1+x) / (1-x));
-}
-float cosh(float x)
-{
- return 0.5 * (exp(x) + exp(-x));
-}
-float sinh(float x)
-{
- return 0.5 * (exp(x) - exp(-x));
-}
-float tanh(float x)
-{
- return sinh(x) / cosh(x);
-}
-
-float exp(float x)
-{
- return pow(M_E, x);
-}
-float exp2(float x)
-{
- return pow(2, x);
-}
-float expm1(float x)
-{
- return exp(x) - 1;
-}
-
-vector frexp(float x)
-{
- vector v;
- v.z = 0;
- v.y = ilogb(x) + 1;
- v.x = x / exp2(v.y);
- return v;
-}
-int ilogb(float x)
-{
- return floor(log2(fabs(x)));
-}
-float ldexp(float x, int e)
-{
- return x * pow(2, e);
-}
-float logn(float x, float base)
-{
- return log(x) / log(base);
-}
-float log10(float x)
-{
- return log(x) * M_LOG10E;
-}
-float log1p(float x)
-{
- return log(x + 1);
-}
-float log2(float x)
-{
- return log(x) * M_LOG2E;
-}
-float logb(float x)
-{
- return floor(log2(fabs(x)));
-}
-vector modf(float f)
-{
- return '1 0 0' * (f - trunc(f)) + '0 1 0' * trunc(f);
-}
-
-float scalbn(float x, int n)
-{
- return x * pow(2, n);
-}
-
-float cbrt(float x)
-{
- return copysign(pow(fabs(x), 1.0/3.0), x);
-}
-float hypot(float x, float y)
-{
- return sqrt(x*x + y*y);
-}
-
-float erf(float x)
-{
- // approximation taken from wikipedia
- float y;
- y = x*x;
- return copysign(sqrt(1 - exp(-y * (1.273239544735163 + 0.14001228868667 * y) / (1 + 0.14001228868667 * y))), x);
-}
-float erfc(float x)
-{
- return 1.0 - erf(x);
-}
-vector lgamma(float x)
-{
- // TODO improve accuracy
- if(!isfinite(x))
- return fabs(x) * '1 0 0' + copysign(1, x) * '0 1 0';
- if(x < 1 && x == floor(x))
- return nan("gamma") * '1 1 1';
- if(x < 0.1)
- {
- vector v;
- v = lgamma(1.0 - x);
- // reflection formula:
- // gamma(1-z) * gamma(z) = pi / sin(pi*z)
- // lgamma(1-z) + lgamma(z) = log(pi) - log(sin(pi*z))
- // sign of gamma(1-z) = sign of gamma(z) * sign of sin(pi*z)
- v.z = sin(M_PI * x);
- v.x = log(M_PI) - log(fabs(v.z)) - v.x;
- if(v.z < 0)
- v.y = -v.y;
- v.z = 0;
- return v;
- }
- if(x < 1.1)
- return lgamma(x + 1) - log(x) * '1 0 0';
- x -= 1;
- return (0.5 * log(2 * M_PI * x) + x * (log(x) - 1)) * '1 0 0' + '0 1 0';
-}
-float tgamma(float x)
-{
- vector v;
- v = lgamma(x);
- return exp(v.x) * v.y;
-}
-
-/**
- * Pythonic mod:
- * TODO: %% operator?
- *
- * 1 % 2 == 1
- * -1 % 2 == 1
- * 1 % -2 == -1
- * -1 % -2 == -1
- */
-float pymod(float x, float y)
-{
- return x - y * floor(x / y);
-}
-
-float nearbyint(float x)
-{
- return rint(x);
-}
-float trunc(float x)
-{
- return (x>=0) ? floor(x) : ceil(x);
-}
-
-float fmod(float x, float y)
-{
- return x - y * trunc(x / y);
-}
-float remainder(float x, float y)
-{
- return x - y * rint(x / y);
-}
-vector remquo(float x, float y)
-{
- vector v;
- v.z = 0;
- v.y = rint(x / y);
- v.x = x - y * v.y;
- return v;
-}
-
-float copysign(float x, float y)
-{
- return fabs(x) * ((y>0) ? 1 : -1);
-}
-float nan(string tag)
-{
- return sqrt(-1);
-}
-float nextafter(float x, float y)
-{
- // TODO very crude
- if(x == y)
- return nan("nextafter");
- if(x > y)
- return -nextafter(-x, -y);
- // now we know that x < y
- // so we need the next number > x
- float d, a, b;
- d = max(fabs(x), 0.00000000000000000000001);
- a = x + d;
- do
- {
- d *= 0.5;
- b = a;
- a = x + d;
- }
- while(a != x);
- return b;
-}
-float nexttoward(float x, float y)
-{
- return nextafter(x, y);
-}
-
-float fdim(float x, float y)
-{
- return max(x-y, 0);
-}
-float fmax(float x, float y)
-{
- return max(x, y);
-}
-float fmin(float x, float y)
-{
- return min(x, y);
-}
-float fma(float x, float y, float z)
-{
- return x * y + z;
-}
-
-int isgreater(float x, float y)
-{
- return x > y;
-}
-int isgreaterequal(float x, float y)
-{
- return x >= y;
-}
-int isless(float x, float y)
-{
- return x < y;
-}
-int islessequal(float x, float y)
-{
- return x <= y;
-}
-int islessgreater(float x, float y)
-{
- return x < y || x > y;
-}
-int isunordered(float x, float y)
-{
- return !(x < y || x == y || x > y);
-}
-
-vector cross(vector a, vector b)
-{
- return
- '1 0 0' * (a.y * b.z - a.z * b.y)
- + '0 1 0' * (a.z * b.x - a.x * b.z)
- + '0 0 1' * (a.x * b.y - a.y * b.x);
-}
+++ /dev/null
-#ifndef MATHLIB_H
-#define MATHLIB_H
-
-// <math.h>
-
-// The commented-out functions need no implementation because DarkPlaces offers
-// them as builtins. They are listed here anyway for completeness sake.
-
-const int FP_NAN = 0;
-const int FP_INFINITE = 1;
-const int FP_ZERO = 2;
-const int FP_SUBNORMAL = 3;
-const int FP_NORMAL = 4;
-int fpclassify(float x);
-bool isfinite(float x);
-bool isinf(float x);
-bool isnan(float x);
-bool isnormal(float x);
-bool signbit(float x);
-
-//float acos(float x);
-//float asin(float x);
-//float atan(float x);
-//float atan2(float y, float x);
-//float cos(float x);
-//float sin(float x);
-//float tan(float x);
-
-float acosh(float x);
-float asinh(float x);
-float atanh(float x);
-float cosh(float x);
-float sinh(float x);
-float tanh(float x);
-
-float exp(float x);
-float exp2(float x);
-float expm1(float x);
-
-vector frexp(float x); // returns mantissa as _x, exponent as _y
-int ilogb(float x);
-float ldexp(float x, int e);
-//float log(float x);
-float logn(float x, float base);
-float log10(float x);
-float log1p(float x);
-float log2(float x);
-float logb(float x);
-vector modf(float f); // fraction as _x, integer as _y
-
-float scalbn(float x, int n);
-
-float cbrt(float x);
-//float fabs(float x);
-float hypot(float x, float y);
-//float pow(float x, float y);
-//float sqrt(float x, float y);
-
-float erf(float x);
-float erfc(float x);
-vector lgamma(float x); // value in _x, sign in _y
-float tgamma(float x);
-
-/**
- * Pythonic mod:
- * TODO: %% operator?
- *
- * 1 % 2 == 1
- * -1 % 2 == 1
- * 1 % -2 == -1
- * -1 % -2 == -1
- */
-float pymod(float x, float y);
-
-//float ceil(float x);
-//float floor(float x);
-float nearbyint(float x);
-//float rint(float x);
-//float round(float x);
-float trunc(float x);
-
-float fmod(float x, float y);
-float remainder(float x, float y);
-vector remquo(float x, float y);
-
-float copysign(float x, float y);
-float nan(string tag);
-float nextafter(float x, float y);
-float nexttoward(float x, float y);
-
-float fdim(float x, float y);
-float fmax(float x, float y);
-float fmin(float x, float y);
-float fma(float x, float y, float z);
-
-int isgreater(float x, float y);
-int isgreaterequal(float x, float y);
-int isless(float x, float y);
-int islessequal(float x, float y);
-int islessgreater(float x, float y);
-int isunordered(float x, float y);
-
-const float M_E = 2.7182818284590452354; /* e */
-const float M_LOG2E = 1.4426950408889634074; /* log_2 e */
-const float M_LOG10E = 0.43429448190325182765; /* log_10 e */
-const float M_LN2 = 0.69314718055994530942; /* log_e 2 */
-const float M_LN10 = 2.30258509299404568402; /* log_e 10 */
-// -Wdouble-declaration
-#define M_PI 3.14159265358979323846 /* pi */
-const float M_PI_2 = 1.57079632679489661923; /* pi/2 */
-const float M_PI_4 = 0.78539816339744830962; /* pi/4 */
-const float M_1_PI = 0.31830988618379067154; /* 1/pi */
-const float M_2_PI = 0.63661977236758134308; /* 2/pi */
-const float M_2_SQRTPI = 1.12837916709551257390; /* 2/sqrt(pi) */
-const float M_SQRT2 = 1.41421356237309504880; /* sqrt(2) */
-const float M_SQRT1_2 = 0.70710678118654752440; /* 1/sqrt(2) */
-
-// Non-<math.h> stuff follows here.
-vector cross(vector a, vector b);
-
-#endif
+++ /dev/null
-#include "server.qh"
-
-#include "common.qh"
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../common/constants.qh"
- #include "../common/triggers/subs.qh"
- #include "../common/util.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../dpdefs/progsdefs.qh"
- #include "../server/command/common.qh"
- #include "../server/constants.qh"
- #include "../server/defs.qh"
-#endif
-
-#ifdef WARPZONELIB_KEEPDEBUG
-#define WARPZONELIB_REMOVEHACK
-#endif
-
-// for think function
-.vector warpzone_save_origin;
-.vector warpzone_save_angles;
-.vector warpzone_save_eorigin;
-.vector warpzone_save_eangles;
-
-// for all entities
-.vector warpzone_oldorigin, warpzone_oldvelocity, warpzone_oldangles;
-.float warpzone_teleport_time;
-.float warpzone_teleport_finishtime;
-.entity warpzone_teleport_zone;
-
-void WarpZone_StoreProjectileData(entity e)
-{
- e.warpzone_oldorigin = e.origin;
- e.warpzone_oldvelocity = e.velocity;
- e.warpzone_oldangles = e.angles;
-}
-
-void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity)
-{
- setorigin (player, to); // NOTE: this also aborts the move, when this is called by touch
- player.oldorigin = to; // for DP's unsticking
- player.angles = to_angles;
- player.fixangle = true;
- player.velocity = to_velocity;
-
- BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
-
- if(IS_PLAYER(player))
- BITCLR_ASSIGN(player.flags, FL_ONGROUND);
-
- WarpZone_PostTeleportPlayer_Callback(player);
-}
-
-bool WarpZone_Teleported_Send(entity to, int sf)
-{SELFPARAM();
- WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_TELEPORTED);
- WriteCoord(MSG_ENTITY, self.angles.x);
- WriteCoord(MSG_ENTITY, self.angles.y);
- WriteCoord(MSG_ENTITY, self.angles.z);
- return true;
-}
-
-float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
-{
- vector o0, a0, v0, o1, a1, v1, o10;
-
- o0 = player.origin + player.view_ofs;
- v0 = player.velocity;
- a0 = player.angles;
-
- o10 = o1 = WarpZone_TransformOrigin(wz, o0);
- v1 = WarpZone_TransformVelocity(wz, v0);
- if (!IS_NOT_A_CLIENT(player))
- a1 = WarpZone_TransformVAngles(wz, player.v_angle);
- else
- a1 = WarpZone_TransformAngles(wz, a0);
-
- if(f0 != 0 || f1 != 0)
- {
- // retry last move but behind the warpzone!
- // we must first go back as far as we can, then forward again, to not cause double touch events!
-
- tracebox(o1 - player.view_ofs + v1 * frametime * f1, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f0, MOVE_WORLDONLY, player);
- {
- entity own;
- own = player.owner;
- player.owner = world;
- tracebox(trace_endpos, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f1, MOVE_NORMAL, player); // this should get us through the warpzone
- player.owner = own;
- }
- o1 = trace_endpos + player.view_ofs;
-
- float d, dv, md;
- md = max(vlen(player.mins), vlen(player.maxs));
- d = WarpZone_TargetPlaneDist(wz, o1);
- dv = WarpZone_TargetPlaneDist(wz, v1);
- if(d < 0)
- o1 = o1 - v1 * (d / dv);
- }
-
- // put him out of solid
- tracebox(o1 - player.view_ofs, player.mins, player.maxs, o1 - player.view_ofs, MOVE_NOMONSTERS, player);
- if(trace_startsolid)
- {
- setorigin(player, o1 - player.view_ofs);
- if(WarpZoneLib_MoveOutOfSolid(player))
- {
- o1 = player.origin + player.view_ofs;
- setorigin(player, o0 - player.view_ofs);
- }
- else
- {
- LOG_INFO("would have to put player in solid, won't do that\n");
- setorigin(player, o0 - player.view_ofs);
- return 0;
- }
- }
-
- // do the teleport
- WarpZone_RefSys_Add(player, wz);
- WarpZone_TeleportPlayer(wz, player, o1 - player.view_ofs, a1, v1);
- WarpZone_StoreProjectileData(player);
- player.warpzone_teleport_time = time;
- player.warpzone_teleport_finishtime = time;
- player.warpzone_teleport_zone = wz;
-
- // prevent further teleports back
- float dt = (o1 - o10) * v1 * (1 / (v1 * v1));
- if(dt < sys_frametime)
- player.warpzone_teleport_finishtime += sys_frametime - dt;
-
-#ifndef WARPZONE_USE_FIXANGLE
- if(IS_VEHICLE(player) && player.owner)
- player = player.owner; // hax
- if(IS_PLAYER(player))
- {
- // instead of fixangle, send the transform to the client for smoother operation
- player.fixangle = false;
-
- entity ts = spawn();
- setmodel(ts, MDL_Null);
- ts.SendEntity = WarpZone_Teleported_Send;
- ts.SendFlags = 0xFFFFFF;
- ts.drawonlytoclient = player;
- ts.think = SUB_Remove;
- ts.nextthink = time + 1;
- ts.owner = player;
- ts.enemy = wz;
- ts.effects = EF_NODEPTHTEST;
- ts.classname = "warpzone_teleported";
- ts.angles = wz.warpzone_transform;
- }
-#endif
-
- return 1;
-}
-
-void WarpZone_Touch (void)
-{SELFPARAM();
- if(other.classname == "trigger_warpzone")
- return;
-
- if(time <= other.warpzone_teleport_finishtime) // already teleported this frame
- return;
-
- // FIXME needs a better check to know what is safe to teleport and what not
- if(other.movetype == MOVETYPE_NONE || other.movetype == MOVETYPE_FOLLOW || other.tag_entity)
- return;
-
- if(WarpZoneLib_ExactTrigger_Touch())
- return;
-
- if(WarpZone_PlaneDist(self, other.origin + other.view_ofs) >= 0) // wrong side of the trigger_warpzone (don't teleport yet)
- return;
-
- float f;
- // number of frames we need to go back:
- // dist = 16*sqrt(2) qu
- // dist ~ 24 qu
- // 24 qu = v*t
- // 24 qu = v*frametime*n
- // n = 24 qu/(v*frametime)
- // for clients go only one frame though, may be too irritating otherwise
- // but max 0.25 sec = 0.25/frametime frames
- // 24/(0.25/frametime)
- // 96*frametime
- float d;
- d = 24 + max(vlen(other.mins), vlen(other.maxs));
- if(IS_NOT_A_CLIENT(other))
- f = -d / bound(frametime * d * 1, frametime * vlen(other.velocity), d);
- else
- f = -1;
- if(WarpZone_Teleport(self, other, f, 0))
- {
- string save1, save2;
- activator = other;
-
- save1 = self.target; self.target = string_null;
- save2 = self.target3; self.target3 = string_null;
- SUB_UseTargets();
- if (!self.target) self.target = save1;
- if (!self.target3) self.target3 = save2;
-
- setself(self.enemy);
- save1 = self.target; self.target = string_null;
- save2 = self.target2; self.target2 = string_null;
- SUB_UseTargets();
- if (!self.target) self.target = save1;
- if (!self.target2) self.target2 = save2;
- setself(this);
- }
- else
- {
- LOG_TRACE("WARPZONE FAIL AHAHAHAHAH))\n");
- }
-}
-
-bool WarpZone_Send(entity to, int sendflags)
-{SELFPARAM();
- WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE);
-
- // we must send this flag for clientside to match properly too
- int f = 0;
- if(self.warpzone_isboxy)
- BITSET_ASSIGN(f, 1);
- if(self.warpzone_fadestart)
- BITSET_ASSIGN(f, 2);
- if(self.origin != '0 0 0')
- BITSET_ASSIGN(f, 4);
- WriteByte(MSG_ENTITY, f);
-
- // we need THESE to render the warpzone (and cull properly)...
- if(f & 4)
- {
- WriteCoord(MSG_ENTITY, self.origin.x);
- WriteCoord(MSG_ENTITY, self.origin.y);
- WriteCoord(MSG_ENTITY, self.origin.z);
- }
-
- WriteShort(MSG_ENTITY, self.modelindex);
- WriteCoord(MSG_ENTITY, self.mins.x);
- WriteCoord(MSG_ENTITY, self.mins.y);
- WriteCoord(MSG_ENTITY, self.mins.z);
- WriteCoord(MSG_ENTITY, self.maxs.x);
- WriteCoord(MSG_ENTITY, self.maxs.y);
- WriteCoord(MSG_ENTITY, self.maxs.z);
- WriteByte(MSG_ENTITY, bound(1, self.scale * 16, 255));
-
- // we need THESE to calculate the proper transform
- WriteCoord(MSG_ENTITY, self.warpzone_origin.x);
- WriteCoord(MSG_ENTITY, self.warpzone_origin.y);
- WriteCoord(MSG_ENTITY, self.warpzone_origin.z);
- WriteCoord(MSG_ENTITY, self.warpzone_angles.x);
- WriteCoord(MSG_ENTITY, self.warpzone_angles.y);
- WriteCoord(MSG_ENTITY, self.warpzone_angles.z);
- WriteCoord(MSG_ENTITY, self.warpzone_targetorigin.x);
- WriteCoord(MSG_ENTITY, self.warpzone_targetorigin.y);
- WriteCoord(MSG_ENTITY, self.warpzone_targetorigin.z);
- WriteCoord(MSG_ENTITY, self.warpzone_targetangles.x);
- WriteCoord(MSG_ENTITY, self.warpzone_targetangles.y);
- WriteCoord(MSG_ENTITY, self.warpzone_targetangles.z);
-
- if(f & 2)
- {
- WriteShort(MSG_ENTITY, self.warpzone_fadestart);
- WriteShort(MSG_ENTITY, self.warpzone_fadeend);
- }
-
- return true;
-}
-
-bool WarpZone_Camera_Send(entity to, int sendflags)
-{SELFPARAM();
- int f = 0;
- WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_CAMERA);
-
- if(self.warpzone_fadestart)
- BITSET_ASSIGN(f, 2);
- if(self.origin != '0 0 0')
- BITSET_ASSIGN(f, 4);
- WriteByte(MSG_ENTITY, f);
-
- // we need THESE to render the warpzone (and cull properly)...
- if(f & 4)
- {
- WriteCoord(MSG_ENTITY, self.origin.x);
- WriteCoord(MSG_ENTITY, self.origin.y);
- WriteCoord(MSG_ENTITY, self.origin.z);
- }
-
- WriteShort(MSG_ENTITY, self.modelindex);
- WriteCoord(MSG_ENTITY, self.mins.x);
- WriteCoord(MSG_ENTITY, self.mins.y);
- WriteCoord(MSG_ENTITY, self.mins.z);
- WriteCoord(MSG_ENTITY, self.maxs.x);
- WriteCoord(MSG_ENTITY, self.maxs.y);
- WriteCoord(MSG_ENTITY, self.maxs.z);
- WriteByte(MSG_ENTITY, bound(1, self.scale * 16, 255));
-
- // we need THESE to calculate the proper transform
- WriteCoord(MSG_ENTITY, self.enemy.origin.x);
- WriteCoord(MSG_ENTITY, self.enemy.origin.y);
- WriteCoord(MSG_ENTITY, self.enemy.origin.z);
- WriteCoord(MSG_ENTITY, self.enemy.angles.x);
- WriteCoord(MSG_ENTITY, self.enemy.angles.y);
- WriteCoord(MSG_ENTITY, self.enemy.angles.z);
-
- if(f & 2)
- {
- WriteShort(MSG_ENTITY, self.warpzone_fadestart);
- WriteShort(MSG_ENTITY, self.warpzone_fadeend);
- }
-
- return true;
-}
-
-#ifdef WARPZONELIB_KEEPDEBUG
-float WarpZone_CheckProjectileImpact(entity player)
-{SELFPARAM();
- vector o0, v0;
-
- o0 = player.origin + player.view_ofs;
- v0 = player.velocity;
-
- // if we teleported shortly before, abort
- if(time <= player.warpzone_teleport_finishtime + 0.1)
- return 0;
-
- // if player hit a warpzone, abort
- entity wz;
- wz = WarpZone_Find(o0 + player.mins, o0 + player.maxs);
- if(!wz)
- return 0;
-
-#ifdef WARPZONELIB_REMOVEHACK
- LOG_INFO("impactfilter found something - and it no longer gets handled correctly - please tell divVerent whether anything behaves broken now\n");
-#else
- LOG_INFO("impactfilter found something - and it even gets handled correctly - please tell divVerent that this code apparently gets triggered again\n");
-#endif
- LOG_INFO("Entity type: ", player.classname, "\n");
- LOG_INFO("Origin: ", vtos(player.origin), "\n");
- LOG_INFO("Velocity: ", vtos(player.velocity), "\n");
-
-#ifdef WARPZONELIB_REMOVEHACK
- return 0;
-#else
- // retry previous move
- setorigin(player, player.warpzone_oldorigin);
- player.velocity = player.warpzone_oldvelocity;
- if(WarpZone_Teleport(wz, player, 0, 1))
- {
- entity oldself;
- string save1, save2;
-
- oldself = self;
- self = wz;
- other = player;
- activator = player;
-
- save1 = self.target; self.target = string_null;
- save2 = self.target3; self.target3 = string_null;
- SUB_UseTargets();
- if (!self.target) self.target = save1;
- if (!self.target3) self.target3 = save2;
-
- self = self.enemy;
- save1 = self.target; self.target = string_null;
- save2 = self.target2; self.target2 = string_null;
- SUB_UseTargets();
- if (!self.target) self.target = save1;
- if (!self.target2) self.target2 = save2;
- self = oldself;
- }
- else
- {
- setorigin(player, o0 - player.view_ofs);
- player.velocity = v0;
- }
-
- return +1;
-#endif
-}
-#endif
-
-float WarpZone_Projectile_Touch()
-{SELFPARAM();
- if(other.classname == "trigger_warpzone")
- return true;
-
- // no further impacts if we teleported this frame!
- // this is because even if we did teleport, the engine still may raise
- // touch events for the previous location
- // engine now aborts moves on teleport, so this SHOULD not happen any more
- // but if this is called from TouchAreaGrid of the projectile moving,
- // then this won't do
- if(time == self.warpzone_teleport_time)
- return true;
-
-#ifdef WARPZONELIB_KEEPDEBUG
- // this SEEMS to not happen at the moment, but if it did, it would be more reliable
- {
- float save_dpstartcontents;
- float save_dphitcontents;
- float save_dphitq3surfaceflags;
- string save_dphittexturename;
- float save_allsolid;
- float save_startsolid;
- float save_fraction;
- vector save_endpos;
- vector save_plane_normal;
- float save_plane_dist;
- entity save_ent;
- float save_inopen;
- float save_inwater;
- save_dpstartcontents = trace_dpstartcontents;
- save_dphitcontents = trace_dphitcontents;
- save_dphitq3surfaceflags = trace_dphitq3surfaceflags;
- save_dphittexturename = trace_dphittexturename;
- save_allsolid = trace_allsolid;
- save_startsolid = trace_startsolid;
- save_fraction = trace_fraction;
- save_endpos = trace_endpos;
- save_plane_normal = trace_plane_normal;
- save_plane_dist = trace_plane_dist;
- save_ent = trace_ent;
- save_inopen = trace_inopen;
- save_inwater = trace_inwater;
- float f;
- if((f = WarpZone_CheckProjectileImpact(self)) != 0)
- return (f > 0);
- trace_dpstartcontents = save_dpstartcontents;
- trace_dphitcontents = save_dphitcontents;
- trace_dphitq3surfaceflags = save_dphitq3surfaceflags;
- trace_dphittexturename = save_dphittexturename;
- trace_allsolid = save_allsolid;
- trace_startsolid = save_startsolid;
- trace_fraction = save_fraction;
- trace_endpos = save_endpos;
- trace_plane_normal = save_plane_normal;
- trace_plane_dist = save_plane_dist;
- trace_ent = save_ent;
- trace_inopen = save_inopen;
- trace_inwater = save_inwater;
- }
-#endif
-
- if(WarpZone_Projectile_Touch_ImpactFilter_Callback())
- return true;
-
- return false;
-}
-
-void WarpZone_InitStep_FindOriginTarget()
-{SELFPARAM();
- if(self.killtarget != "")
- {
- self.aiment = find(world, targetname, self.killtarget);
- if(self.aiment == world)
- {
- error("Warp zone with nonexisting killtarget");
- return;
- }
- self.killtarget = string_null;
- }
-}
-
-void WarpZonePosition_InitStep_FindTarget()
-{SELFPARAM();
- if(self.target == "")
- {
- error("Warp zone position with no target");
- return;
- }
- self.enemy = find(world, targetname, self.target);
- if(self.enemy == world)
- {
- error("Warp zone position with nonexisting target");
- return;
- }
- if(self.enemy.aiment)
- {
- // already is positioned
- error("Warp zone position targeting already oriented warpzone");
- return;
- }
- self.enemy.aiment = self;
-}
-
-void WarpZoneCamera_Think(void)
-{SELFPARAM();
- if(self.warpzone_save_origin != self.origin
- || self.warpzone_save_angles != self.angles
- || self.warpzone_save_eorigin != self.enemy.origin
- || self.warpzone_save_eangles != self.enemy.angles)
- {
- WarpZone_Camera_SetUp(self, self.enemy.origin, self.enemy.angles);
- self.warpzone_save_origin = self.origin;
- self.warpzone_save_angles = self.angles;
- self.warpzone_save_eorigin = self.enemy.origin;
- self.warpzone_save_eangles = self.enemy.angles;
- }
- self.nextthink = time;
-}
-
-void WarpZoneCamera_InitStep_FindTarget()
-{SELFPARAM();
- entity e;
- float i;
- if(self.target == "")
- {
- error("Camera with no target");
- return;
- }
- self.enemy = world;
- for(e = world, i = 0; (e = find(e, targetname, self.target)); )
- if(random() * ++i < 1)
- self.enemy = e;
- if(self.enemy == world)
- {
- error("Camera with nonexisting target");
- return;
- }
- warpzone_cameras_exist = 1;
- WarpZone_Camera_SetUp(self, self.enemy.origin, self.enemy.angles);
- self.SendFlags = 0xFFFFFF;
- if(self.spawnflags & 1)
- {
- self.think = WarpZoneCamera_Think;
- self.nextthink = time;
- }
- else
- self.nextthink = 0;
-}
-
-void WarpZone_InitStep_UpdateTransform()
-{SELFPARAM();
- vector org, ang, norm, point;
- float area;
- vector tri, a, b, c, n;
- float i_s, i_t, n_t;
- string tex;
-
- org = self.origin;
- if(org == '0 0 0')
- org = 0.5 * (self.mins + self.maxs);
-
- norm = point = '0 0 0';
- area = 0;
- for(i_s = 0; ; ++i_s)
- {
- tex = getsurfacetexture(self, i_s);
- if (!tex)
- break; // this is beyond the last one
- if(tex == "textures/common/trigger" || tex == "trigger")
- continue;
- n_t = getsurfacenumtriangles(self, i_s);
- for(i_t = 0; i_t < n_t; ++i_t)
- {
- tri = getsurfacetriangle(self, i_s, i_t);
- a = getsurfacepoint(self, i_s, tri.x);
- b = getsurfacepoint(self, i_s, tri.y);
- c = getsurfacepoint(self, i_s, tri.z);
- n = cross(c - a, b - a);
- area = area + vlen(n);
- norm = norm + n;
- point = point + vlen(n) * (a + b + c);
- }
- }
- if(area > 0)
- {
- norm = norm * (1 / area);
- point = point * (1 / (3 * area));
- if(vlen(norm) < 0.99)
- {
- LOG_INFO("trigger_warpzone near ", vtos(self.aiment.origin), " is nonplanar. BEWARE.\n");
- area = 0; // no autofixing in this case
- }
- norm = normalize(norm);
- }
-
- ang = '0 0 0';
- if(self.aiment)
- {
- org = self.aiment.origin;
- ang = self.aiment.angles;
- if(area > 0)
- {
- org = org - ((org - point) * norm) * norm; // project to plane
- makevectors(ang);
- if(norm * v_forward < 0)
- {
- LOG_INFO("Position target of trigger_warpzone near ", vtos(self.aiment.origin), " points into trigger_warpzone. BEWARE.\n");
- norm = -1 * norm;
- }
- ang = vectoangles2(norm, v_up); // keep rotation, but turn exactly against plane
- ang.x = -ang.x;
- if(norm * v_forward < 0.99)
- LOG_INFO("trigger_warpzone near ", vtos(self.aiment.origin), " has been turned to match plane orientation (", vtos(self.aiment.angles), " -> ", vtos(ang), "\n");
- if(vlen(org - self.aiment.origin) > 0.5)
- LOG_INFO("trigger_warpzone near ", vtos(self.aiment.origin), " has been moved to match the plane (", vtos(self.aiment.origin), " -> ", vtos(org), ").\n");
- }
- }
- else if(area > 0)
- {
- org = point;
- ang = vectoangles(norm);
- ang.x = -ang.x;
- }
- else
- error("cannot infer origin/angles for this warpzone, please use a killtarget or a trigger_warpzone_position");
-
- self.warpzone_origin = org;
- self.warpzone_angles = ang;
-}
-
-void WarpZone_InitStep_ClearTarget()
-{SELFPARAM();
- if(self.enemy)
- self.enemy.enemy = world;
- self.enemy = world;
-}
-
-entity warpzone_first; .entity warpzone_next;
-void WarpZone_InitStep_FindTarget()
-{SELFPARAM();
- float i;
- entity e, e2;
-
- if(self.enemy)
- return;
-
- // this way only one of the two ents needs to target
- if(self.target != "")
- {
- self.enemy = self; // so the if(!e.enemy) check also skips self, saves one IF
-
- e2 = world;
- for(e = world, i = 0; (e = find(e, targetname, self.target)); )
- if(!e.enemy)
- if(e.classname == self.classname) // possibly non-warpzones may use the same targetname!
- if(random() * ++i < 1)
- e2 = e;
- if(!e2)
- {
- self.enemy = world;
- error("Warpzone with non-existing target");
- return;
- }
- self.enemy = e2;
- e2.enemy = self;
- }
-}
-
-void WarpZone_Think();
-void WarpZone_InitStep_FinalizeTransform()
-{SELFPARAM();
- if(!self.enemy || self.enemy.enemy != self)
- {
- error("Invalid warp zone detected. Killed.");
- return;
- }
-
- warpzone_warpzones_exist = 1;
- WarpZone_SetUp(self, self.warpzone_origin, self.warpzone_angles, self.enemy.warpzone_origin, self.enemy.warpzone_angles);
- self.touch = WarpZone_Touch;
- self.SendFlags = 0xFFFFFF;
- if(self.spawnflags & 1)
- {
- self.think = WarpZone_Think;
- self.nextthink = time;
- }
- else
- self.nextthink = 0;
-}
-
-float warpzone_initialized;
-//entity warpzone_first;
-entity warpzone_position_first;
-entity warpzone_camera_first;
-.entity warpzone_next;
-spawnfunc(misc_warpzone_position)
-{
- // "target", "angles", "origin"
- self.warpzone_next = warpzone_position_first;
- warpzone_position_first = self;
-}
-spawnfunc(trigger_warpzone_position)
-{
- spawnfunc_misc_warpzone_position(this);
-}
-spawnfunc(trigger_warpzone)
-{
- // warp zone entities must have:
- // "killtarget" pointing to a target_position with a direction arrow
- // that points AWAY from the warp zone, and that is inside
- // the warp zone trigger
- // "target" pointing to an identical warp zone at another place in
- // the map, with another killtarget to designate its
- // orientation
-
- if(!self.scale)
- self.scale = self.modelscale;
- if(!self.scale)
- self.scale = 1;
- string m;
- m = self.model;
- WarpZoneLib_ExactTrigger_Init();
- if(m != "")
- {
- precache_model(m);
- _setmodel(self, m); // no precision needed
- }
- setorigin(self, self.origin);
- if(self.scale)
- setsize(self, self.mins * self.scale, self.maxs * self.scale);
- else
- setsize(self, self.mins, self.maxs);
- self.SendEntity = WarpZone_Send;
- self.SendFlags = 0xFFFFFF;
- BITSET_ASSIGN(self.effects, EF_NODEPTHTEST);
- self.warpzone_next = warpzone_first;
- warpzone_first = self;
-}
-spawnfunc(func_camera)
-{
- if(!self.scale)
- self.scale = self.modelscale;
- if(!self.scale)
- self.scale = 1;
- if(self.model != "")
- {
- precache_model(self.model);
- _setmodel(self, self.model); // no precision needed
- }
- setorigin(self, self.origin);
- if(self.scale)
- setsize(self, self.mins * self.scale, self.maxs * self.scale);
- else
- setsize(self, self.mins, self.maxs);
- if(!self.solid)
- self.solid = SOLID_BSP;
- else if(self.solid < 0)
- self.solid = SOLID_NOT;
- self.SendEntity = WarpZone_Camera_Send;
- self.SendFlags = 0xFFFFFF;
- self.warpzone_next = warpzone_camera_first;
- warpzone_camera_first = self;
-}
-void WarpZones_Reconnect()
-{SELFPARAM();
- for(setself(warpzone_first); self; setself(self.warpzone_next))
- WarpZone_InitStep_ClearTarget();
- for(setself(warpzone_first); self; setself(self.warpzone_next))
- WarpZone_InitStep_FindTarget();
- for(setself(warpzone_camera_first); self; setself(self.warpzone_next))
- WarpZoneCamera_InitStep_FindTarget();
- for(setself(warpzone_first); self; setself(self.warpzone_next))
- WarpZone_InitStep_FinalizeTransform();
- setself(this);
-}
-
-void WarpZone_Think()
-{SELFPARAM();
- if(self.warpzone_save_origin != self.origin
- || self.warpzone_save_angles != self.angles
- || self.warpzone_save_eorigin != self.enemy.origin
- || self.warpzone_save_eangles != self.enemy.angles)
- {
- WarpZone_InitStep_UpdateTransform();
- setself(self.enemy);
- WarpZone_InitStep_UpdateTransform();
- setself(this);
- WarpZone_InitStep_FinalizeTransform();
- setself(self.enemy);
- WarpZone_InitStep_FinalizeTransform();
- setself(this);
- self.warpzone_save_origin = self.origin;
- self.warpzone_save_angles = self.angles;
- self.warpzone_save_eorigin = self.enemy.origin;
- self.warpzone_save_eangles = self.enemy.angles;
- }
- self.nextthink = time;
-}
-
-void WarpZone_StartFrame()
-{SELFPARAM();
- entity e;
- if(warpzone_initialized == 0)
- {
- warpzone_initialized = 1;
- for(setself(warpzone_first); self; setself(self.warpzone_next))
- WarpZone_InitStep_FindOriginTarget();
- for(setself(warpzone_position_first); self; setself(self.warpzone_next))
- WarpZonePosition_InitStep_FindTarget();
- for(setself(warpzone_first); self; setself(self.warpzone_next))
- WarpZone_InitStep_UpdateTransform();
- setself(this);
- WarpZones_Reconnect();
- WarpZone_PostInitialize_Callback();
- }
-
- entity oldother;
- oldother = other;
- for(e = world; (e = nextent(e)); )
- {
- if(warpzone_warpzones_exist) { WarpZone_StoreProjectileData(e); }
-
- if(IS_REAL_CLIENT(e))
- {
- if(e.solid == SOLID_NOT) // not spectating?
- if(e.movetype == MOVETYPE_NOCLIP || e.movetype == MOVETYPE_FLY || e.movetype == MOVETYPE_FLY_WORLDONLY) // not spectating? (this is to catch observers)
- {
- other = e; // player
-
- // warpzones
- if(warpzone_warpzones_exist) {
- setself(WarpZone_Find(e.origin + e.mins, e.origin + e.maxs));
- if(self)
- if(!WarpZoneLib_ExactTrigger_Touch())
- if(WarpZone_PlaneDist(self, e.origin + e.view_ofs) <= 0)
- WarpZone_Teleport(self, e, -1, 0); } // NOT triggering targets by this!
-
- // teleporters
- setself(Teleport_Find(e.origin + e.mins, e.origin + e.maxs));
- if(self)
- if(!WarpZoneLib_ExactTrigger_Touch())
- Simple_TeleportPlayer(self, other); // NOT triggering targets by this!
- }
- }
-
- if(IS_NOT_A_CLIENT(e))
- {
- if(warpzone_warpzones_exist)
- for (; (e = nextent(e)); )
- WarpZone_StoreProjectileData(e);
- break;
- }
- }
- setself(this);
- other = oldother;
-}
-
-.float warpzone_reconnecting;
-float visible_to_some_client(entity ent)
-{
- entity e;
- for(e = nextent(world); !IS_NOT_A_CLIENT(e); e = nextent(e))
- if(IS_PLAYER(e) && IS_REAL_CLIENT(e))
- if(checkpvs(e.origin + e.view_ofs, ent))
- return 1;
- return 0;
-}
-void trigger_warpzone_reconnect_use()
-{SELFPARAM();
- entity e;
- e = self;
- // NOTE: this matches for target, not targetname, but of course
- // targetname must be set too on the other entities
- for(setself(warpzone_first); self; setself(self.warpzone_next))
- self.warpzone_reconnecting = ((e.target == "" || self.target == e.target) && !((e.spawnflags & 1) && (visible_to_some_client(self) || visible_to_some_client(self.enemy))));
- for(setself(warpzone_camera_first); self; setself(self.warpzone_next))
- self.warpzone_reconnecting = ((e.target == "" || self.target == e.target) && !((e.spawnflags & 1) && visible_to_some_client(self)));
- for(setself(warpzone_first); self; setself(self.warpzone_next))
- if(self.warpzone_reconnecting)
- WarpZone_InitStep_ClearTarget();
- for(setself(warpzone_first); self; setself(self.warpzone_next))
- if(self.warpzone_reconnecting)
- WarpZone_InitStep_FindTarget();
- for(setself(warpzone_camera_first); self; setself(self.warpzone_next))
- if(self.warpzone_reconnecting)
- WarpZoneCamera_InitStep_FindTarget();
- for(setself(warpzone_first); self; setself(self.warpzone_next))
- if(self.warpzone_reconnecting || self.enemy.warpzone_reconnecting)
- WarpZone_InitStep_FinalizeTransform();
- setself(e);
-}
-
-spawnfunc(trigger_warpzone_reconnect)
-{
- self.use = trigger_warpzone_reconnect_use;
-}
-
-spawnfunc(target_warpzone_reconnect)
-{
- spawnfunc_trigger_warpzone_reconnect(this); // both names make sense here :(
-}
-
-void WarpZone_PlayerPhysics_FixVAngle(void)
-{SELFPARAM();
-#ifndef WARPZONE_DONT_FIX_VANGLE
- if(IS_REAL_CLIENT(self))
- if(self.v_angle.z <= 360) // if not already adjusted
- if(time - self.ping * 0.001 < self.warpzone_teleport_time)
- {
- self.v_angle = WarpZone_TransformVAngles(self.warpzone_teleport_zone, self.v_angle);
- self.v_angle_z += 720; // mark as adjusted
- }
-#endif
-}
+++ /dev/null
-#ifndef SERVER_H
-#define SERVER_H
-
-void WarpZone_StartFrame();
-float WarpZone_Projectile_Touch();
-
-// THESE must be defined by calling QC code:
-void WarpZone_PostTeleportPlayer_Callback(entity pl);
-float WarpZone_Projectile_Touch_ImpactFilter_Callback();
-
-// server must also define a float called ENT_CLIENT_WARPZONE for the initial byte of WarpZone entities
-//const float ENT_CLIENT_WARPZONE;
-//const float ENT_CLIENT_WARPZONE_CAMERA;
-
-void WarpZone_PlayerPhysics_FixVAngle(void);
-
-void WarpZone_PostInitialize_Callback(void);
-#endif
+++ /dev/null
-#include "util_server.qh"
-
-#include "common.qh"
-
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
- #include "../csqcmodellib/sv_model.qh"
- #include "../dpdefs/dpextensions.qh"
- #include "../dpdefs/progsdefs.qh"
-#endif
-#include "common.qh"
-
-void WarpZoneLib_ExactTrigger_Init()
-{SELFPARAM();
- vector mi, ma;
- if (self.movedir == '0 0 0')
- if (self.angles != '0 0 0')
- {
- makevectors (self.angles);
- self.movedir = v_forward;
- }
- if(self.model == "")
- {
- // It's a box! No need to match with exacttriggers.
- self.warpzone_isboxy = 1;
- }
- else
- {
- mi = self.mins;
- ma = self.maxs;
- precache_model(self.model);
- _setmodel(self, self.model);
- // let mapper-set mins/maxs override the model's bounds if set
- if(mi != '0 0 0' || ma != '0 0 0')
- {
- // It's a box! No need to match with exacttriggers.
- self.mins = mi;
- self.maxs = ma;
- self.warpzone_isboxy = 1;
- }
- }
- setorigin(self, self.origin);
- if(self.scale)
- setsize(self, self.mins * self.scale, self.maxs * self.scale);
- else
- setsize(self, self.mins, self.maxs);
- self.movetype = MOVETYPE_NONE;
- self.solid = SOLID_TRIGGER;
- self.model = "";
-}
+++ /dev/null
-#ifndef UTIL_SERVER_H
-#define UTIL_SERVER_H
-
-float WarpZoneLib_MoveOutOfSolid(entity e);
-float WarpZoneLib_ExactTrigger_Touch();
-#ifdef SVQC
-void WarpZoneLib_ExactTrigger_Init();
-#endif
-#endif