Initial commit

This commit is contained in:
unknown 2022-02-08 13:42:28 -05:00
commit b26ca6a026
58 changed files with 34564 additions and 0 deletions

View file

@ -0,0 +1,88 @@
name: Compile QuakeC and Publish Release
on: [push]
jobs:
Compile-QC:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Clone Repository
working-directory: ./tools
run: |
sudo -i
./qc-compiler-lin.sh
echo "QC COMPILE STATUS - ${{ job.status }}."
- name: Zip Progs
working-directory: ./build
run: |
zip -r -j pc-nzp-qc.zip pc/*
zip -r -j psp-nzp-qc.zip psp/*
zip -r -j nx-nzp-qc.zip nx/*
zip -r -j vita-nzp-qc.zip vita/*
- name: Generate Build Date
id: date
run: echo "::set-output name=date::$(date +'%Y-%m-%d-%H-%M-%S')"
- name: Delete Old Release
uses: dev-drprasad/delete-tag-and-release@v0.2.0
with:
delete_release: true
tag_name: bleeding-edge
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: bleeding-edge
release_name: Automated Release ${{ steps.date.outputs.date }}
body: |
This is a **bleeding edge** NZ:P QuakeC release, stability is not guarenteed and you may need to grab an updated asset release if this update depends on new models/textures/etc.
To install:
- Grab the .ZIP archive for your desired platform below (*-nzp-qc.zip)
- Extract the contents of the .ZIP archive to your nzp folder (Example: copy `progs.dat` and `progs.lno` to `PSP/GAME/nzportable/nzp`).
draft: true
prerelease: false
- name: Upload NX QC
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./build/nx-nzp-qc.zip
asset_name: nx-nzp-qc.zip
asset_content_type: application/zip
- name: Upload PC QC
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./build/pc-nzp-qc.zip
asset_name: pc-nzp-qc.zip
asset_content_type: application/zip
- name: Upload PSP QC
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./build/psp-nzp-qc.zip
asset_name: psp-nzp-qc.zip
asset_content_type: application/zip
- name: Upload VITA QC
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./build/vita-nzp-qc.zip
asset_name: vita-nzp-qc.zip
asset_content_type: application/zip
- name: Publish Release
uses: StuYarrow/publish-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
id: ${{ steps.create_release.outputs.id }}

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
build/*
bin/fteqcc.log

87
LICENSE Normal file
View file

@ -0,0 +1,87 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
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

26
README.md Normal file
View file

@ -0,0 +1,26 @@
# Nazi Zombies: Portable QuakeC
## About
This is the QuakeC portion of the NZ:P source code. QuakeC is responsible for most game-related code such as weapon logic, ai, and Perks. You can read more about QuakeC on the [Wikipedia page](https://en.wikipedia.org/wiki/QuakeC). NZ:P makes use of CSQC for PC/FTE.
## Project Structure
Here is a brief explanation for each of the (sub)directories in this repository:
* `bin`: Command line binaries for [FTEQCC](https://www.fteqcc.org/) + the ini configuration file.
* `progs`: `*.src` files, a list of QuakeC source files each platform is dependent on.
* `source`:
* `client`: FTE-exclusive CSQC, used for the HUD, achievements, and other server->client requests.
* `server`: Game code relevant to all platforms, contains most expected logic.
* `shared`: Definitions for weapon stats and some utility functions shared by both the `client` and `server`.
* `tools`: Build scripts to compile the QuakeC into `.dat` and `.lno` files.
## Updating
While it's usually recommended to stay on the QuakeC version provided with your build of NZ:P, you may want to update it to the current development builds to test new features and changes. To do this, navigate to the [Releases](https://github.com/nzp-team/quakec/releases/tag/bleeding-edge) page and follow the instructions there for downloading and installing.
## Building (Beginner Friendly)
There are no prerequisites or dependancies needed to build QuakeC other than a working Windows or Linux-based machine (MacOS is **not** natively supported, but you can use [WINE](https://www.winehq.org/)).
Before you can build the NZ:P QuakeC, you must either [download](https://github.com/nzp-team/quakec/archive/refs/heads/main.zip) this repository (easy) or [clone it](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) (for developers).
To build, simply navigate to the `tools` directory and run the `qc-compiler-*` script for your platform. If unfamiliar with executing shell (`.sh`) scripts on Linux systems, give this [itsFOSS article](https://itsfoss.com/run-shell-script-linux/) a read.
After having done this, a `build` directory will have been created, and inside of it will be more directories named after every platform. Copy the contents of the platform directories into your `nzp` game directory. (Example: copy `progs.dat` and `progs.lno` from `build/psp` to `PSP/GAME/nzportable/nzp`).

BIN
bin/fteqcc-cli-lin Normal file

Binary file not shown.

BIN
bin/fteqcc-cli-win.exe Normal file

Binary file not shown.

216
bin/fteqcc.ini Normal file
View file

@ -0,0 +1,216 @@
optimisation t default # c = a*b is performed in one operation rather than two, and can
# cause older decompilers to fail.
optimisation i default # if (!a) was traditionally compiled in two statements. This optimisation
# does it in one, but can cause some decompilers to get confused.
optimisation p default # In the original qcc, function parameters were specified as a vector
# store even for floats. This fixes that.
optimisation c default # This optimisation strips out the names of constants (but not strings)
# from your progs, resulting in smaller files. It makes decompilers
# leave out names or fabricate numerical ones.
optimisation cs default # This optimisation strips out the names of string constants from
# your progs. However, this can break addons, so don't use it in
# those cases.
optimisation d default # This will merge definitions of constants which are the same value.
# Pay extra attention to assignment to constant warnings.
optimisation s default # This will compact the string table that is stored in the progs.
# It will be considerably smaller with this.
optimisation l default # Strips out local names and definitions. Most decompiles will break
# on this.
optimisation n default # This strips out the names of functions which are never called.
# Doesn't make much of an impact though.
optimisation f default # This strips out the filenames of the progs. This can confuse the
# really old decompilers, but is nothing to the more recent ones.
optimisation u default # Removes the entries of unreferenced variables. Doesn't make a
# difference in well maintained code.
optimisation r default # Optimises the pr_globals count by overlapping temporaries. In
# QC, every multiplication, division or operation in general produces
# a temporary variable. This optimisation prevents excess, and in
# the case of Hexen2's gamecode, reduces the count by 50k. This
# is the most important optimisation, ever.
optimisation a default # 5*6 actually emits an operation into the progs. This prevents
# that happening, effectivly making the compiler see 30
optimisation pf default # Strip out stuff wasted used in function calls and strings to the
# precache_file builtin (which is actually a stub in quake).
optimisation ro default # Functions ending in a return statement do not need a done statement
# at the end of the function. This can confuse some decompilers,
# making functions appear larger than they were.
optimisation cj default # This optimisation plays an effect mostly with nested if/else statements,
# instead of jumping to an unconditional jump statement, it'll jump
# to the final destination instead. This will bewilder decompilers.
optimisation sf default # Strips out the 'defs' of functions that were only ever called
# directly. This does not affect saved games. This can affect FTE_MULTIPROGS.
optimisation lo default # Store all locals in a single section of the pr_globals. Vastly
# reducing it. This effectivly does the job of overlaptemps.
# However, locals are no longer automatically initialised to 0 (and
# never were in the case of recursion, but at least then its the
# same type).
# If locals appear uninitialised, fteqcc will disable this optimisation
# for the affected functions, you can optionally get a warning about
# these locals using: #pragma warning enable F302
optimisation vc default # Where a function is called with just a vector, this causes the
# function call to store three floats instead of one vector. This
# can save a good number of pr_globals where those vectors contain
# many duplicate coordinates but do not match entirly.
optimisation cf default # Strip class field names. This will harm debugging and can result
# in 'gibberish' names appearing in saved games. Has no effect on
# engines other than FTEQW, which will not recognise these anyway.
keyword asm true # Disables the 'asm' keyword. Use the writeasm flag to see an example
# of the asm.
keyword break true # Disables the 'break' keyword.
keyword case true # Disables the 'case' keyword.
keyword class true # Disables the 'class' keyword.
keyword const true # Disables the 'const' keyword.
keyword continue true # Disables the 'continue' keyword.
keyword default true # Disables the 'default' keyword.
keyword entity true # Disables the 'entity' keyword.
keyword enum true # Disables the 'enum' keyword.
keyword enumflags true # Disables the 'enumflags' keyword.
keyword extern true # Disables the 'extern' keyword. Use only on functions inside addons.
keyword float true # Disables the 'float' keyword. (Disables the float keyword without
# 'local' preceeding it)
keyword for true # Disables the 'for' keyword. Syntax: for(assignment; while; increment)
# {codeblock;}
keyword goto true # Disables the 'goto' keyword.
keyword int true # Disables the 'int' keyword.
keyword integer true # Disables the 'integer' keyword.
keyword noref true # Disables the 'noref' keyword.
keyword unused false # Disables the 'unused' keyword. 'unused' means that the variable
# is unused, you're aware that its unused, and you'd rather not
# know about all the warnings this results in.
keyword used false # Disables the 'used' keyword. 'used' means that the variable is
# used even if the qcc can't see how - thus preventing it from ever
# being stripped.
keyword static true # Disables the 'static' keyword. 'static' means that a variable
# has altered scope. On globals, the variable is visible only to
# the current .qc file. On locals, the variable's value does not
# change between calls to the function. On class variables, specifies
# that the field is a scoped global instead of a local. On class
# functions, specifies that 'this' is expected to be invalid and
# that the function will access any memembers via it.
keyword nonstatic true # Disables the 'nonstatic' keyword. 'nonstatic' acts upon globals+functions,
# reverting the defaultstatic pragma on a per-variable basis. For
# use by people who prefer to keep their APIs explicit.
keyword ignore false # Disables the 'ignore' keyword. 'ignore' is expected to typically
# be hidden behind a 'csqconly' define, and in such a context can
# be used to conditionally compile functions a little more gracefully.
# The opposite of the 'used' keyword. These variables/functions/members
# are ALWAYS stripped, and effectively ignored.
keyword nosave true # Disables the 'nosave' keyword.
keyword inline true # Disables the 'inline' keyword.
keyword strip true # Disables the 'strip' keyword.
keyword shared true # Disables the 'shared' keyword.
keyword state false # Disables the 'state' keyword.
keyword optional true # Disables the 'optional' keyword.
keyword inout false # Disables the 'inout' keyword.
keyword string true # Disables the 'string' keyword.
keyword struct true # Disables the 'struct' keyword.
keyword switch true # Disables the 'switch' keyword.
keyword thinktime false # Disables the 'thinktime' keyword which is used in HexenC
keyword until false # Disables the 'until' keyword which is used in HexenC
keyword loop false # Disables the 'loop' keyword which is used in HexenC
keyword typedef true # Disables the 'typedef' keyword.
keyword union true # Disables the 'union' keyword.
keyword var true # Disables the 'var' keyword.
keyword vector true # Disables the 'vector' keyword.
keyword wrap true # Disables the 'wrap' keyword.
keyword weak true # Disables the 'weak' keyword.
flag kce true # If you want keywords to NOT be disabled when they a variable by
# the same name is defined, check here.
flag parms false # if PARM0 PARM1 etc should be defined by the compiler. These are
# useful if you make use of the asm keyword for function calls,
# or you wish to create your own variable arguments. This is an
# easy way to break decompilers.
flag autoproto false # Causes compilation to take two passes instead of one. The first
# pass, only the definitions are read. The second pass actually
# compiles your code. This means you never have to remember to prototype
# functions again.
flag wasm false # Writes out a qc.asm which contains all your functions but in assembler.
# This is a great way to look for bugs in fteqcc, but can also be
# used to see exactly what your functions turn into, and thus how
# to optimise statements better.
flag annotate false # Annotate source code with assembler statements on compile (requires
# gui).
flag nullemptystr false # Empty string immediates will have the raw value 0 instead of 1.
flag ifstring false # Causes if(string) to behave identically to if(string!=) This is
# most useful with addons of course, but also has adverse effects
# with FRIK_FILE's fgets, where it becomes impossible to determin
# the end of the file. In such a case, you can still use asm {IF
# string 2;RETURN} to detect eof and leave the function.
flag iffloat false # Fixes certain floating point logic.
flag ifvector true # Fixes conditional vector logic.
flag vectorlogic true # Fixes conditional vector logic.
flag brokenarray false # Treat references to arrays as references to the first index of
# said array, to replicate an old fteqcc bug.
flag rootconstructor false # When enabled, the root constructor should be called first like
# in c++.
flag acc false # Reacc is a pascall like compiler. It was released before the Quake
# source was released. This flag has a few effects. It sorts all
# qc files in the current directory into alphabetical order to compile
# them. It also allows Reacc global/field distinctions, as well
# as allows ¦ as EOF. Whilst case insensitivity and lax type checking
# are supported by reacc, they are seperate compiler flags in fteqcc.
flag caseinsens false # Causes fteqcc to become case insensitive whilst compiling names.
# It's generally not advised to use this as it compiles a little
# more slowly and provides little benefit. However, it is required
# for full reacc support.
flag lax false # Disables many errors (generating warnings instead) when function
# calls or operations refer to two normally incompatible types.
# This is required for reacc support, and can also allow certain
# (evil) mods to compile that were originally written for frikqcc.
flag hashonly false # Allows use of only #constant for precompiler constants, allows
# certain preqcc using mods to compile
flag lo false # This changes the behaviour of your code. It generates additional
# if operations to early-out in if statements. With this flag, the
# line if (0 && somefunction()) will never call the function. It
# can thus be considered an optimisation. However, due to the change
# of behaviour, it is not considered so by fteqcc. Note that due
# to inprecisions with floats, this flag can cause runaway loop
# errors within the player walk and run functions (without iffloat
# also enabled). This code is advised:
# player_stand1:
# if (self.velocity_x || self.velocity_y)
# player_run
# if (!(self.velocity_x || self.velocity_y))
flag msvcstyle false # Generates warning and error messages in a format that msvc understands,
# to facilitate ide integration.
flag debugmacros false # Print out the contents of macros that are expanded. This can help
# look inside macros that are expanded and is especially handy if
# people are using preprocessor hacks.
flag filetimes false # Recompiles the progs only if the file times are modified.
flag fastarrays false # Generates extra instructions inside array handling functions to
# detect engine and use extension opcodes only in supporting engines.
# Adds a global which is set by the engine if the engine supports
# the extra opcodes. Note that this applies to all arrays or none.
flag assumeint false # Numerical constants are assumed to be integers, instead of floats.
flag subscope false # Restrict the scope of locals to the block they are actually defined
# within, as in C.
flag verbose false # Lots of extra compiler messages.
flag typeexplicit false # All type conversions must be explicit or directly supported by
# instruction set.
flag noboundchecks false # Disable array index checks, speeding up array access but can result
# in your code misbehaving.
flag qccx false # WARNING: This syntax makes mods inherantly engine specific.
# Do NOT use unless you know what you're doing.This is provided
# for compatibility only
# Any entity hacks will be unsupported in FTEQW, DP, and others,
# resulting in engine crashes if the code in question is executed.
flag embedsrc false # Write the sourcecode into the output file.
showall off # Show all keyword options in the gui
compileonstart off # Recompile on GUI startup
log off # Write out a compile log
enginebinary fteglqw.exe # Location of the engine binary to run. Change this to something
# else to run a different engine, but not all support debugging.
basedir ../.. # The base directory of the game that contains your sub directory
engineargs "-window -nohome -game game"
# The engine commandline to use when debugging. You'll likely want
# to ensure this contains -window as well as the appropriate -game
# argument.
srcfile progs.src # The progs.src file to load to find ordering of other qc files.
src # Additional subdir to read qc files from. Typically blank (ie:
# the working directory).
extramargins off # Enables line number and folding margins.
hexen2 off # Enable the extra tweaks needed for compatibility with hexen2 engines.
extendedopcodes off # Utilise an extended instruction set, providing support for pointers
# and faster arrays and other speedups.
parameters # Other additional parameters that are not supported by the gui.
# Likely including -DFOO

11
progs/fte-client.src Normal file
View file

@ -0,0 +1,11 @@
../../build/pc/csprogs.dat
../source/client/defs/fte.qc
../source/shared/defs/custom.qc
../source/shared/sound_enhanced.qc
../source/shared/weapon_defines.qc
../source/client/defs/custom.qc
../source/client/menu.qc
../source/client/achievements.qc
../source/client/hud.qc
../source/client/main.qc

37
progs/fte-server.src Normal file
View file

@ -0,0 +1,37 @@
../../build/pc/qwprogs.dat
../source/server/defs/fte.qc
../source/shared/defs/custom.qc
../source/shared/weapon_defines.qc
../source/server/defs/custom.qc
../source/server/clientfuncs.qc
../source/server/dummies/generic.qc
../source/server/rounds.qc
../source/server/nzdparser.qc
../source/server/main.qc
../source/server/player.qc
../source/server/damage.qc
../source/server/entities/sub_functions.qc
../source/server/entities/sounds.qc
../source/server/entities/triggers.qc
../source/server/entities/map_entities.qc
../source/server/entities/lights.qc
../source/server/entities/doors.qc
../source/server/entities/window.qc
../source/server/entities/machines.qc
../source/server/weapons/frames_core.qc
../source/server/weapons/weapon_core.qc
../source/server/entities/powerups.qc
../source/server/ai/pathfind_code.qc
../source/server/ai/ai_core.qc
../source/server/ai/fte/waypoints_core.qc
../source/server/ai/zombie_core.qc
../source/server/ai/crawler_core.qc
../source/server/ai/dog_core.qc
../source/server/items.qc

40
progs/nx.src Normal file
View file

@ -0,0 +1,40 @@
../../build/nx/progs.dat
#pragma warning disable Q208
../source/server/defs/nx.qc
../source/shared/defs/custom.qc
../source/shared/weapon_defines.qc
../source/server/defs/custom.qc
../source/server/clientfuncs.qc
../source/server/dummies/vitanx.qc
../source/server/dummies/generic.qc
../source/server/rounds.qc
../source/server/nzdparser.qc
../source/server/main.qc
../source/server/player.qc
../source/server/damage.qc
../source/server/entities/sub_functions.qc
../source/server/entities/sounds.qc
../source/server/entities/triggers.qc
../source/server/entities/map_entities.qc
../source/server/entities/lights.qc
../source/server/entities/doors.qc
../source/server/entities/window.qc
../source/server/entities/machines.qc
../source/server/weapons/frames_core.qc
../source/server/weapons/weapon_core.qc
../source/server/entities/powerups.qc
../source/server/ai/ai_core.qc
../source/server/ai/standard/waypoints_func.qc
../source/server/ai/standard/waypoints_core.qc
../source/server/ai/zombie_core.qc
../source/server/ai/crawler_core.qc
../source/server/ai/dog_core.qc
../source/server/items.qc

40
progs/psp.src Normal file
View file

@ -0,0 +1,40 @@
../../build/psp/progs.dat
#pragma warning disable Q208
../source/server/defs/psp.qc
../source/shared/defs/custom.qc
../source/shared/weapon_defines.qc
../source/server/defs/custom.qc
../source/server/clientfuncs.qc
../source/server/psp_specifics.qc
../source/server/dummies/generic.qc
../source/server/rounds.qc
../source/server/nzdparser.qc
../source/server/main.qc
../source/server/player.qc
../source/server/damage.qc
../source/server/entities/sub_functions.qc
../source/server/entities/sounds.qc
../source/server/entities/triggers.qc
../source/server/entities/map_entities.qc
../source/server/entities/lights.qc
../source/server/entities/doors.qc
../source/server/entities/window.qc
../source/server/entities/machines.qc
../source/server/weapons/frames_core.qc
../source/server/weapons/weapon_core.qc
../source/server/entities/powerups.qc
../source/server/ai/ai_core.qc
../source/server/ai/standard/waypoints_func.qc
../source/server/ai/standard/waypoints_core.qc
../source/server/ai/zombie_core.qc
../source/server/ai/crawler_core.qc
../source/server/ai/dog_core.qc
../source/server/items.qc

40
progs/vita.src Normal file
View file

@ -0,0 +1,40 @@
../../build/vita/progs.dat
#pragma warning disable Q208
../source/server/defs/vita.qc
../source/shared/defs/custom.qc
../source/shared/weapon_defines.qc
../source/server/defs/custom.qc
../source/server/clientfuncs.qc
../source/server/dummies/vitanx.qc
../source/server/dummies/generic.qc
../source/server/rounds.qc
../source/server/nzdparser.qc
../source/server/main.qc
../source/server/player.qc
../source/server/damage.qc
../source/server/entities/sub_functions.qc
../source/server/entities/sounds.qc
../source/server/entities/triggers.qc
../source/server/entities/map_entities.qc
../source/server/entities/lights.qc
../source/server/entities/doors.qc
../source/server/entities/window.qc
../source/server/entities/machines.qc
../source/server/weapons/frames_core.qc
../source/server/weapons/weapon_core.qc
../source/server/entities/powerups.qc
../source/server/ai/ai_core.qc
../source/server/ai/standard/waypoints_func.qc
../source/server/ai/standard/waypoints_core.qc
../source/server/ai/zombie_core.qc
../source/server/ai/crawler_core.qc
../source/server/ai/dog_core.qc
../source/server/items.qc

View file

@ -0,0 +1,175 @@
/*
client/achievements.qc
main achievement code
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
/*
Thanks to everyone who submitted Achievement ideas in 2019!
- Derped_Crusader
- TheSmashers
- Chyll
- mrFlamist
- mario135790
- Mission
- RedneckHax0r
- Revnova
- EpicFoxx64
- Detwyler_
- DisrespectfulOtter
- xnick2222x
- greg
- Omar Alejandro
- Cosmicrush
- blubs
- Bernerd
*/
void(float id, string graphic, string name, string description) Achievement_Create =
{
if (id >= MAX_ACHIEVEMENTS)
return;
achievements[id].img = strcat("gfx/achievement/", graphic, ".tga");
achievements[id].name = name;
achievements[id].description = description;
}
void() Achievement_Save =
{
local float file, i;
// re-write the achievement file
file = fopen("ach.dat", FILE_WRITE);
for (i = 0; i < MAX_ACHIEVEMENTS; i++) {
fputs(file, strcat(ftos(achievements[i].unlocked), "\n"));
fputs(file, strcat(ftos(achievements[i].progress), "\n"));
}
fclose(file);
}
void() Achievement_Load =
{
float file, i;
string val;
file = fopen("ach.dat", FILE_READ);
if (file == -1) {
fclose(file);
file = fopen("ach.dat", FILE_WRITE);
for (i = 0; i < MAX_ACHIEVEMENTS * 2; i++) {
fputs(file, "0\n");
}
fclose(file);
file = fopen("ach.dat", FILE_READ);
}
for (i = 0; i < MAX_ACHIEVEMENTS; i++) {
val = fgets(file);
achievements[i].unlocked = stof(val);
val = fgets(file);
achievements[i].progress = stof(val);
}
fclose(file);
}
void() Achievement_Init =
{
Achievement_Create(0, "ready", "Ready..", "Reach Round 5");
Achievement_Create(1, "steady", "Steady..", "Reach Round 10");
Achievement_Create(2, "go_hell_no", "Go? Hell No...", "Reach Round 15");
Achievement_Create(3, "where_legs_go", "Where Did Legs Go?", "Turn a Zombie into a Crawler");
Achievement_Create(4, "the_f_bomb", "The F Bomb", "Use the Nuke Power-Up to kill a single Zombie");
Achievement_Create(5, "no_perks_no_problem", "No Perks? No Problem", "Survive an entire Round without Perks past Round 15 or higher");
Achievement_Create(6, "dipsomaniac", "Dipsomaniac", "Hold all Perk-A-Colas at once in a single Game");
Achievement_Create(7, "oops", "Oops!", "Die from fall damage");
Achievement_Create(8, "abstinence_program", "Abstinence Program", "Survive to Round 10 without taking any enemy damage");
Achievement_Create(9, "pro_gamer_move", "Pro-Gamer Move", "Die on Round 1 with no Ammo remaining");
Achievement_Create(10, "spinning_plates", "Spinning Plates", "Keep entry points Barricaded all the way to Round 10");
Achievement_Create(11, "unlucky", "Unlucky", "Have the Mystery Box move 10 times");
Achievement_Create(12, "the_collector", "The Collector", "Buy every weapon off the wall in a single Game");
Achievement_Create(13, "barrels_o_fun", "Barrels o' Fun", "In Nacht der Untoten, kill 15 Zombies with Explosive Barrels");
Achievement_Create(14, "its_a_trap", "It's a Trap!", "In Kino der Toten, kill 5 Crawlers with the use of 1 Trap");
Achievement_Create(15, "uplink", "Up-Link", "In Kino der Toten, teleport to the Pack-A-Punch 5 times in a single Game");
Achievement_Create(16, "undone", "Undone", "Survive a total of 150 Rounds on Nacht der Untoten");
Achievement_Create(17, "moviegoer", "Moviegoer", "Play 10 total Matches on Kino der Toten");
Achievement_Create(18, "cmere_cupcake", "C'mere, Cupcake!", "Kill yourself with your own Grenade");
Achievement_Create(19, "orbital_strike", "Orbital Strike", "Kill 5 Zombies at once, with the Panzerschreck, while in the air");
Achievement_Create(20, "long_name", "A House Divided, Multiplied, then Subtracted", "In Nacht der Untoten, reach Round 10 without going upstairs & without fixing Barriers, then go upstairs & allow those Barriers to be Destroyed");
Achievement_Create(21, "colt_hearted_killer", "Colt-Hearted Killer", "Reach Round 10 using only the Colt M1911");
Achievement_Create(22, "cache_and_carry", "Cannot Cache and Carry", "Collected a Max Ammo power-up whilst already being at fully ammo capacity");
Achievement_Create(23, "divide_and_conquer", "Divide and Conquer", "Turn all Zombies into Crawlers in a single Round");
Achievement_Create(24, "tough_luck", "Tough Luck!", "Die before reaching Round 5");
Achievement_Create(25, "gregg", "All Are One with Gregg!", "???");
Achievement_Create(26, "slasher", "Slasher", "Perform 100 total Melee kills");
Achievement_Create(27, "made_by_children", "Made by Children", "Get a Zombie stuck for 5 minutes");
Achievement_Create(28, "increase_firepower", "Increase your Firepower!", "Use the Pack-A-Punch for the first time");
Achievement_Create(29, "kraut_tongue", "Kraut Got Your Tongue?", "Get 25 Headshots");
Achievement_Create(30, "mindblowing", "Mindblowing", "Get 250 Headshots");
Achievement_Create(31, "thanks_explosions", "Big Thanks to Explosions", "Kill 10 Zombies with a single Grenade");
Achievement_Create(32, "mbox_maniac", "Mystery Box Manaic", "Use the Mystery Box 20 times in a single Game");
Achievement_Create(33, "instant_help", "Instant Help", "Get 100 total Kills with the Insta-Kill Power-Up");
Achievement_Create(34, "blow_the_bank", "Blow the Bank", "Earn 1,000,000 Points");
Achievement_Create(35, "why_wait", "..Why Are We Waiting?", "Stand Still for 2 minutes");
Achievement_Create(36, "one_clip", "One Clip", "Survive a Round using the MG42 and without Reloading");
Achievement_Create(37, "2021", "Twenty-Twenty-One", "Land 20 Headshots, with 20 Bullets, with one Clip");
Achievement_Create(38, "warmed_up", "Getting Warmed Up", "Earn 10 Achievements");
Achievement_Create(39, "half_way", "About Half-Way", "Earn 20 Achievements");
Achievement_Create(40, "75_percent", "I mean.. 75% is Passing", "Earn 30 Achievements");
Achievement_Create(41, "over_achiever", "Over-Achiever", "Earn all 42 Achievements");
Achievement_Load();
achievement_pages = ceil(MAX_ACHIEVEMENTS/3);
current_achievement_page = 1;
active_achievement = -1;
}
void(float id) Achievement_Unlock =
{
local float file, i;
achievements[id].unlocked = 1;
// tell the HUD to start drawing
active_achievement = id;
Achievement_Save();
}
void(float id, float pg) Achievement_UpdateProgress =
{
achievements[id].progress = pg;
Achievement_Save();
}

View file

@ -0,0 +1,219 @@
/*
client/defs/custom.qc
Various globals that are used in this FTEQW example are defined
here, they are not used by the engine itself.
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#pragma warning disable Q302
#define true 1
#define false 0
vector cursor_pos; /* Current mouse cursor position, updated in csqc_inputevent */
float g_width, g_height; /* Globals for screen width and height */
float walk;
//Menu stuff
float in_menu; //what menu are we in
float time_in_menu;
entity player;
entity vmodel;
entity v2model;
entity mzlflash;
entity dummy;
float weapon;
float tracercounter;
.float rate;
.vector targetpos;
vector vmodel_targetpos;
vector v2model_targetpos;
vector vmodel_currentpos;
vector v2model_currentpos;
vector vmodel_velocity;
vector v2model_velocity;
vector vmodel_avelocity;
vector v2model_avelocity;
vector vmodel_muzzleoffset;
vector v2model_muzzleoffset;
const float MENU_NONE = 0;
const float MENU_MAIN = 1;
const float MENU_SINGLE = 2;
const float MENU_MULTI = 4;
const float MENU_SETTINGS = 8;
const float MENU_ABOUT = 16;
const float MENU_JOIN = 32;
const float MENU_PAUSE = 64;
const float MENU_IGS = 128;
const float MENU_RES = 256;
const float MENU_GSETTINGS = 512;
const float MENU_CSETTINGS = 1024;
const float MENU_CUSTOMS = 2048;
const float MENU_ACHIEVEMENTS = 4096;
const float MENU_CONSETTINGS = 8192;
const float MENU_AUDSETTINGS = 16384;
float useprint_type;
float useprint_weapon;
float useprint_cost;
float useprint_time;
string scrolltext;
float stext;
float scrollopacity;
float scrollheight;
float HUD_Change_time;
float Hitmark_time;
float crosshair_spread_time;
float zoom_2_time;
float broadcast_time;
float broadcast_type;
float weaponframetime;
float weapon2frametime;
float oldweaponframe;
float oldweapon2frame;
float curweaponframe;
float curweapon2frame;
float interpolating;
float interpolating2;
float rounds;
float perks;
float rounds_change;
float playerpoints[4]; // player point holders, player 1 points are index 0, player 2 at 1...
float playerkills[4]; // player kill holders, player 1 points are index 0, player 2 at 1...
string playernames[4]; // player name holders, player 1 name at index 0, player 2 at 1...
float player_count;
float score_show;
#define MAX_ACHIEVEMENTS 42
var struct achievementlist_t
{
string img;
float unlocked;
string name;
string description;
float progress;
} achievements[MAX_ACHIEVEMENTS];
float active_achievement;
float current_achievement_page;
float achievement_pages;
float K_LEFTDOWN, K_RIGHTDOWN, K_BACKDOWN, K_FORWARDDOWN;
#define P_JUG 1
#define P_DOUBLE 2
#define P_SPEED 4
#define P_REVIVE 8
#define P_FLOP 16
#define P_STAMIN 32
vector TEXT_LIGHTBLUE = [(2/255), (118/255), (181/255)];
vector TEXT_ORANGE = [(235/255), (189/255), 0];
vector TEXT_GREEN = [0, (230/255), (34/255)];
vector TEXT_RED = [1, 0, 0];
float fade_time;
float fade_type;
float menu_initialized;
float customs_interact;
vector camang; // used for punches
//world text
string chaptertitle;
string location;
string date;
string person;
//custom hud
string huddir;
//this just cleans up settings a bit..
#define S_ENABLED "Enabled"
#define S_DISABLED "Disabled"
float wasigs;
//controls
#define MAX_BINDS 14
float editBind[MAX_BINDS];
string buttonBind[MAX_BINDS];
string tempBind[MAX_BINDS];
// resolution
#define MAX_43 3
#define MAX_54 1
#define MAX_1610 5
#define MAX_169 10
#define MAX_219 2
float aspectratio;
float fullscreenval;
float active_swidth;
float active_sheight;
float screen_width_43[MAX_43];
float screen_height_43[MAX_43];
float screen_width_54[MAX_54];
float screen_height_54[MAX_54];
float screen_width_1610[MAX_1610];
float screen_height_1610[MAX_1610];
float screen_width_169[MAX_169];
float screen_height_169[MAX_169];
float screen_width_219[MAX_219];
float screen_height_219[MAX_219];
//controller buttons
/*
reference:
0: A
1: B
2: X
3: Y
4: DPAD UP
5: DPAD DOWN
6: DPAD LEFT
7: DPAD RIGHT
*/
float GPActive[32];
string build_datetime;
#define VERSION_STRING "v1.0"

2114
source/client/defs/fte.qc Normal file

File diff suppressed because it is too large Load diff

1430
source/client/hud.qc Normal file

File diff suppressed because it is too large Load diff

1091
source/client/main.qc Normal file

File diff suppressed because it is too large Load diff

1932
source/client/menu.qc Normal file

File diff suppressed because it is too large Load diff

748
source/server/ai/ai_core.qc Normal file
View file

@ -0,0 +1,748 @@
/*
server/ai/ai_core.qc
ai stuff
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
void(float what) play_sound_z;
void() path_corner_touch =
{
self.origin_z = self.origin_z + 32;
setorigin(self, self.origin);
self.classname = "path_corner";
self.movetype = MOVETYPE_NONE;
self.solid = SOLID_NOT;
self.touch = SUB_Null;
setsize(self, '0 0 0 ', '0 0 0');
if(!self.target)
{
if (self.spawnflags & 1)
return;
bprint(PRINT_HIGH, "path_corner with name: ");
bprint(PRINT_HIGH, self.targetname);
bprint(PRINT_HIGH, " has no target!\n");
}
}
//We want the path corner to drop to the ground and then we set it up 32 units so it's exact
void() path_corner =
{
self.classname = "path_corner_set";
self.movetype = MOVETYPE_BOUNCE;
self.solid = SOLID_BBOX;
self.touch = path_corner_touch;
setsize(self, '0 0 0 ', '0 0 0');
};
void removeZombie();
void() Respawn =
{
Current_Zombies--;
removeZombie();
};
entity(entity blarg) find_new_enemy =
{
local entity player;
local entity closest;
local float bestdist;
local float dist;
bestdist = 10000;
closest = 0;
// FIXME - change to hellhound for old/unreleased Demo map support?
if(self.classname == "ai_zombie" || self.classname == "ai_dog") {
player = find(world,classname,"monkey");
if(player) {
return player;
}
player = find(world,classname,"player");
///////////////////////////////
if(!player) {
return world;
}
//////////////////////////////
while(player) {
if (player.downed == true) {
return world;
}
dist = vlen(self.origin - player.origin);
if (dist < bestdist) {
closest = player;
bestdist = dist;
}
player = find(player,classname,"player");
}
return closest;
}
if (self.classname != "wunder")
bprint(PRINT_HIGH, "Error: Find_New_Enemy returns world! \n");
return world;
};
float() avoid_zombies =
{
local entity ent;
ent = findradius(self.origin,23);//22.67
makevectors(self.angles);
float left_amount, right_amount;
left_amount = right_amount = 0;
while(ent)
{
if(ent.classname == "ai_zombie" && ent != self)
{
local vector vec_b;
local float dot;
//vec_b = normalize(self.origin - ent.origin);
//dot = v_right * vec_b;
//dot = self.angles_y - (dot > 0.5) ? 90 : 270;
vec_b = (self.origin - ent.origin);
dot = (v_right_x * vec_b_x) + (v_right_y * vec_b_y);//dot product
if(dot > 0)// on right
right_amount++;
else// on left
left_amount++;
}
ent = ent.chain;
}
if(left_amount + right_amount == 0)
return 0;
return (left_amount > right_amount) ? 15 : -15;
};
float() push_away_zombies =
{
local entity ent;
ent = findradius(self.origin,11);
float return_value;
return_value = 0;
while(ent)
{
if(ent.classname == "ai_zombie" && ent != self)
{
vector push;
push = ent.origin - self.origin;
push_z = 0;
push = normalize(push) * 10;
ent.velocity += push;
return_value = 1;
}
ent = ent.chain;
}
return return_value;
}
void(float dist, vector vec) do_walk_to_vec =
{
if(dist == 0)
return;
self.ideal_yaw = vectoyaw(vec - self.origin);
if(self.outside == false)
{
push_away_zombies();
//self.ideal_yaw += avoid_zombies(); //no longer relevant since our direction doesn't care about our yaw any more
}
ChangeYaw();
vector new_velocity;
float len;
len = vlen(self.origin - vec);
if(dist > len)//if we're moving past our goal position
{
dist = len;
}
//This movement method is moving directly towards the goal, regardless of where our yaw is facing (fixes several issues)
new_velocity = normalize(vec - self.origin) * dist * 10;
new_velocity_z = self.velocity_z;
self.velocity = new_velocity;
};
void(float dist) do_walk =
{
do_walk_to_vec(dist,self.goalentity.origin);
};
void(float dist) walk_to_window =
{
do_walk_to_vec(dist,self.goalorigin);
};
// unused
void(vector org, float scale) interpolateToVector =
{
self.origin_x += (org_x - self.origin_x) * scale;
self.origin_y += (org_y - self.origin_y) * scale;
setorigin(self,self.origin);
self.zoom = 1;//value to let engine know to not check for collisions
}
float(vector where) nearby =
{
if(self.classname == "ai_zombie")
{
float xdist;
float ydist;
float zdist;
xdist = fabs(self.origin_x - where_x);
ydist = fabs(self.origin_y - where_y);
zdist = fabs(self.origin_z - where_z);
if(xdist < 4 && ydist < 4)//horizontal distance is fairly close
{
if(zdist < 50)//vertical distance just has to be arbitrarily close
{
return 1;
}
}
return 0;
}
/*else if(self.classname == "ai_hellhound")
{
if(vlen(self.origin - what.origin) < 35)
{
if(vlen(self.origin - what.origin) < 6)
{
return 1;
}
else
{
interpolateToVector(what.origin,0.25);
}
}
}*/
return 0;
};
void(float dist) Window_Walk =
{
if(self.reload_delay < time)
Respawn();
if(self.hop_step == 0)//following path corners
{
if(self.goalentity == world)
{
if((!self.target) && (self.outside == TRUE))
{
bprint(PRINT_HIGH, "Error: Outside zombie spawn point has no target.\n");
Respawn();
}
self.goalentity = find(world,targetname, self.target);
if(!self.goalentity)
{
bprint(PRINT_HIGH, "Error: Outside zombie spawn point target does not exist.\n");
Respawn();
}
}
if(self.goalentity.classname == "path_corner" && nearby(self.goalentity.origin))
{
if (self.goalentity.spawnflags & 1) //this path corner sets zombie on inside.
{
self.outside = FALSE;
self.goalentity = world;
self.enemy = find_new_enemy(self);
self.th_walk();
return;
}
self.reload_delay = time + 30;
self.goalentity = find(world,targetname,self.goalentity.target);
//Assumption is that when the zombie is outside, we can always walk from one path_corner to the next in a straight line, any devation should be corrected by the mapper
}
do_walk(dist);
if(self.goalentity.classname == "window")
{
if(!self.goalentity.box1owner)
{
//self.used = WBOX1;
self.goalentity.box1owner = self;
self.goalorigin = self.goalentity.box1;
self.hop_step = 3;
self.reload_delay = time + 30;
}
else if(!self.goalentity.box2owner)
{
//self.used = WBOX2;
self.goalentity.box2owner = self;
self.goalorigin = self.goalentity.box2;
self.hop_step = 3;
self.reload_delay = time + 30;
}
else if(!self.goalentity.box3owner)
{
//self.used = WBOX3;
self.goalentity.box3owner = self;
self.goalorigin = self.goalentity.box3;
self.hop_step = 3;
self.reload_delay = time + 30;
}
else if(vlen(self.origin - self.goalentity.origin) < 150)
{
//we don't claim the idlebox
//self.used = WIDLEBOX;
self.goalorigin = self.goalentity.idlebox;
self.hop_step = 1;
self.reload_delay = time + 30;
}
//else we continue walking to window until we either find one that's good, or we are close enough to chase idle_spot
}
}
else if(self.hop_step == 1)//walking to the window's idle location
{
if(nearby(self.goalorigin))
{
self.hop_step = 2;
self.reload_delay = time + 30;
self.th_idle();
}
else
{
walk_to_window(dist);
}
}
else if(self.hop_step == 2)//we're at idle box, waiting for a window attack box to be free...
{
if(!self.goalentity.box1owner)
{
//self.used = WBOX1;
self.goalentity.box1owner = self;
self.goalorigin = self.goalentity.box1;
self.hop_step = 3;
self.reload_delay = time + 30;
self.th_walk();
}
else if(!self.goalentity.box2owner)
{
//self.used = WBOX2;
self.goalentity.box2owner = self;
self.goalorigin = self.goalentity.box2;
self.hop_step = 3;
self.reload_delay = time + 30;
self.th_walk();
}
else if(!self.goalentity.box3owner)
{
//self.used = WBOX3;
self.goalentity.box3owner = self;
self.goalorigin = self.goalentity.box3;
self.hop_step = 3;
self.reload_delay = time + 30;
self.th_walk();
}
}
else if(self.hop_step == 3)//walking to window attack box
{
if(nearby(self.goalorigin))
{
self.hop_step = 4;
self.reload_delay = time + 30;
self.th_idle();
}
else
{
walk_to_window(dist);
}
}
else if(self.hop_step == 4)//attacking box
{
if(self.chase_time < time)
{
if(self.angles_z != self.goalentity.angles_z)
{
self.ideal_yaw = self.goalentity.angles_z;
ChangeYaw();
return;
}
if(self.goalentity.health > 0)
{
self.reload_delay = time + 30;
self.th_melee();
if(rounds <= 5)
self.chase_time = time + 1.5;
else
self.chase_time = time + 0.75;
return;
}
}
if(self.goalentity.health <= 0)
{
self.outside = 2;
self.chase_time = 0;
self.hop_step = 0;
}
else return;
}
};
//
// kind of a shoddy fix, but essentially what we do to fix
// issues with zomb ents colliding with each other during hopping
// is make sure we wait a bit longer before freeing the window for
// another usage.
//
void() free_window =
{
self.usedent = world;
}
void(float dist) Window_Hop =
{
if(self.hop_step == 0) {
if(self.goalentity.box1owner == self) {//we're at center box.
self.hop_step = 4;
} else {
self.hop_step = 1;//wait for box1 to be free so we can claim it and walk to it.
self.th_idle();
}
}
if(self.hop_step == 1) {//waiting idly for box1 to be free, when free, we will claim it.
if(!self.goalentity.box1owner || self.goalentity.box1owner == self) {
self.goalentity.box1owner = self;
if(self.goalentity.box2owner == self)
self.goalentity.box2owner = world;
if(self.goalentity.box3owner == self)
self.goalentity.box3owner = world;
//self.used = WBOX1;
self.goalorigin = self.goalentity.box1;
self.hop_step = 2;
self.th_walk();
}
}
if(self.hop_step == 2) {//we've claimed it, walk to box1
if(nearby(self.goalorigin)) {
self.hop_step = 4;
self.angles = self.goalentity.angles;
} else {
walk_to_window(dist);
}
}
if(self.hop_step == 4 && self.chase_time < time) {//we're at this step because we already own box1, so don't even check if window is busy...
if(!self.goalentity.usedent) {
self.hop_step = 5;
self.angles = self.goalentity.angles;
self.goalentity.box1owner = world;//free box1
self.goalentity.usedent = self;//we own the window
//don't need to set goalorigin here
//self.used = WWINDOW;
self.chase_time = 0;
self.th_windowhop();
return;
} else {
self.tries++;
self.chase_time = time + 0.2;
if(self.tries > 10) {
// wait enough time before freeing window, to give time for zomb to move.
self.goalentity.think = free_window;
self.goalentity.nextthink = time + 0.5;
//self.goalentity.usedent = world;//free up the window if we've been waiting to hop
}
}
}
if(self.hop_step == 6) {
self.outside = FALSE;
//self.goalentity.usedent = world;//free up the window, we're done hopping it
//self.used = 0;
self.goalentity.think = free_window;
self.goalentity.nextthink = time + 0.5;
self.goalentity = world;
self.enemy = find_new_enemy(self);
//self.th_die();
self.th_walk();
}
}
float() TryWalkToEnemy =
{
//was tracebox
float TraceResult;
TraceResult = tracemove(self.origin,VEC_HULL_MIN,VEC_HULL_MAX,self.enemy.origin,TRUE,self);
if(TraceResult == 1) {
self.goalentity = self.enemy;
self.chase_time = time + 7;
return 1;
} else {
return 0;
}
};
#ifndef PC
float() SetUpGoalDummy =
{
self.goaldummy.origin = Get_Waypoint_Near(self);
setorigin(self.goaldummy,self.goaldummy.origin);
self.goalentity = self.goaldummy;
if (!self.goalentity)
bprint(PRINT_HIGH, "Could not find waypoint for zombie\n");
return 1; //because we can't actually know if it was good or not... yet
};
#endif
void() PathfindToEnemy =
{
float path_result;
float path_failure;
//just to stop any warns.
path_failure = 0;
#ifndef PC
path_result = Do_Pathfind_psp(self, self.enemy);
#else
path_result = Do_Pathfind(self, self.enemy);
#endif
//FIXME - further test if this can equate to 0 in FTE..
if (path_result >= 1) {
#ifndef PC
self.goaldummy.origin = Get_First_Waypoint(self, self.origin, VEC_HULL_MIN, VEC_HULL_MAX);
setorigin(self.goaldummy, self.goaldummy.origin);
path_failure = path_result;
#else
self.goalway = path_result;
setorigin(self.goaldummy,waypoints[self.goalway].org);
path_failure = self.goalway;
#endif
self.goalentity = self.goaldummy;
self.chase_time = time + 7;
} else if (path_failure == -1) {
self.goalentity = self.enemy;
self.chase_time = time + 6;
} else {
#ifdef PC
bprint(PRINT_HIGH, "FirstPathfind Failure\n");
#endif
}
}
void() NextPathfindToEnemy {
// same as PathfindToEnemy on non-FTE platforms
#ifndef PC
float path_success;
path_success = Do_Pathfind_psp(self,self.enemy);
if(path_success ==1) {
self.goaldummy.origin = Get_Next_Waypoint(self,self.origin,VEC_HULL_MIN,VEC_HULL_MAX);
setorigin(self.goaldummy,self.goaldummy.origin);
self.goalentity = self.goaldummy;
self.chase_time = time + 7;
} else if(path_success == -1){
self.goalentity = self.enemy;
self.chase_time = time + 6;
} else {
bprint(PRINT_HIGH, "NextPathfind Failure\n"); // this lags like hell
}
#else
self.way_cur++;
if (self.way_cur < 40 && self.way_path[self.way_cur] != -1) {
self.goalway = self.way_path[self.way_cur];
setorigin(self.goaldummy,waypoints[self.goalway-1].org);
} else {
self.way_cur = 0;
}
#endif
}
#ifdef PC
float(vector start, vector min, vector max, vector end, float nomonsters, entity forent) tracemove
{
//was tracebox
traceline(start,end,nomonsters,forent);
if(trace_ent == forent || trace_endpos == end) {
return 1;
} else {
return 0;
}
}
#endif
void(float dist) Inside_Walk = {
if(self.enemy_timeout < time || self.enemy == world) {
self.enemy_timeout = time + 5;
local entity oldEnemy;
oldEnemy = self.enemy;
self.enemy = find_new_enemy(self);
}
//================Check for proximity to player ===========
if(vlen(self.enemy.origin - self.origin) < 60) {
if(self.enemy.classname == "monkey") {
self.th_idle();
}
if(self.attack_delay < time) {
self.attack_delay = time + 1 + (1 * random());
self.th_melee();
self.goalentity = self.enemy;
self.chase_time = time + 5;
}
return;
}
if(vlen(self.enemy.origin - self.origin) < 600) {//50 feet
if(self.goalentity == self.enemy && self.chase_enemy_time > time) {
return;
}
if(TryWalkToEnemy())
{
self.chase_enemy_time = time + 0.5;
return;
}
}
if(self.goalentity == self.enemy) {
self.goalentity = self.goaldummy;
self.chase_time = 0;
}
//============= No Target ====================
if(self.goalentity == world) {//not sure when this would ever occur... but whatever.
self.goalentity = self.goaldummy;
}
//============ GoalDummy is Target ============
if(self.goalentity == self.goaldummy) {
if(nearby(self.goaldummy.origin)) {
#ifndef PC
NextPathfindToEnemy();
#else
PathfindToEnemy();
#endif
}
if(self.chase_time < time) {
if(self.goaldummy.origin != world.origin && tracemove(self.origin,VEC_HULL_MIN,VEC_HULL_MAX,self.goalentity.origin,TRUE,self) == 1) {
self.chase_time = time + 7;
} else {
PathfindToEnemy();
}
}
}
}
.float droptime;
void(float dist) Zombie_Walk = {
//Resetting velocity from last frame (except for vertical)
self.velocity_x = 0;
self.velocity_y = 0;
//self.flags = self.flags | FL_PARTIALGROUND;
//check_onfire();
if (!(self.flags & FL_ONGROUND)) {
if (!self.droptime) {
self.droptime = time + 1;
} else if (self.droptime < time) {
self.droptime = 0;
//bprint(PRINT_HIGH, "not on ground\n");
self.th_fall();
return;
}
}
if(self.outside == TRUE) {
//handle special walk case for walking to org
Window_Walk(dist);
return;
}
if(self.outside == 2) {
//play_sound_z(2);
Window_Hop(dist);
//handle special walk case for walking to org
return;
}
if(self.outside == FALSE) {
if(self.goalentity == self.enemy) {
if(vlen(self.origin - self.enemy.origin) < 60) {
return;
}
}
}
do_walk(dist);
}
void() Zombie_AI = {
//dist = 0;
float dist = 0;
self.flags = self.flags | FL_PARTIALGROUND;
//check_onfire();
if(self.outside == TRUE) {
play_sound_z(2);
//self.calc_time = time + (0.3 * random());
//Window_Walk(dist);
return;
} else if(self.outside == 2) {
play_sound_z(2);
//Window_Hop(0);
return;
} else if(self.outside == FALSE) {
play_sound_z(2);
//self.calc_time = time + (0.25 + (0.15 * random()));
Inside_Walk(dist);
}
}
//This function ensures that only one zombie's ai is done at a time, brings down lag significantly
void() Do_Zombie_AI = {
local entity z;
z = find(lastzombie,aistatus,"1");
if(z == world) {
z = find(world,aistatus,"1");
if(z == world) {
return;//no zombies alive.
}
}
local entity oself;
oself = self;
self = z;
//if(z.classname == "ai_zombie")//removed because only zombies atm
Zombie_AI();
self = oself;
lastzombie = z;
}

View file

@ -0,0 +1,274 @@
/*
server/ai/crawler_core.qc
crawler things
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
//========================= Crawling ===========================
void() zombie_crawl1;
void() crawlerify1;
void() Crawler_Walk_Setup
{
zombie_crawl1();
}
void() crawler_footstep
{
if(self.laststep == 1)
{
self.laststep = 0;
sound(self,CHAN_VOICE,"sounds/zombie/sc0.wav",1,ATTN_NORM);
}
else
{
self.laststep = 1;
sound(self,CHAN_VOICE,"sounds/zombie/sc1.wav",1,ATTN_NORM);
}
}
//14-28
void() zombie_crawl1 =[ 0, zombie_crawl2 ] {Zombie_Walk(2.955);SetZombieHitBox(CRAWLER_BBOX);/*if(freeze_time < time)*/ self.frame = 14;Zombie_Think();};
void() zombie_crawl2 =[ 1, zombie_crawl3 ] {Zombie_Walk(3.841); self.frame = 15;Zombie_Think();};
void() zombie_crawl3 =[ 2, zombie_crawl4 ] {Zombie_Walk(0.886); self.frame = 16;Zombie_Think();};
void() zombie_crawl4 =[ 3, zombie_crawl5 ] {Zombie_Walk(1.871); self.frame = 17;Zombie_Think();};
void() zombie_crawl5 =[ 4, zombie_crawl6 ] {Zombie_Walk(3.25); self.frame = 18;Zombie_Think();};
void() zombie_crawl6 =[ 5, zombie_crawl7 ] {Zombie_Walk(1.314); self.frame = 19;Zombie_Think();};
void() zombie_crawl7 =[ 6, zombie_crawl8 ] {Zombie_Walk(0.908); self.frame = 20;Zombie_Think();crawler_footstep();};//footstep
void() zombie_crawl8 =[ 7, zombie_crawl9 ] {Zombie_Walk(0.776); self.frame = 21;Zombie_Think();};
void() zombie_crawl9 =[ 8, zombie_crawl10 ] {Zombie_Walk(0.698); self.frame = 22;Zombie_Think();};
void() zombie_crawl10 =[ 9, zombie_crawl11 ] {Zombie_Walk(0.641); self.frame = 23;Zombie_Think();};
void() zombie_crawl11 =[ 10, zombie_crawl12 ] {Zombie_Walk(0.588); self.frame = 24;Zombie_Think();};
void() zombie_crawl12 =[ 11, zombie_crawl13 ] {Zombie_Walk(0.295); self.frame = 25;Zombie_Think();};
void() zombie_crawl13 =[ 12, zombie_crawl14 ] {Zombie_Walk(1.182); self.frame = 26;Zombie_Think();};
void() zombie_crawl14 =[ 13, zombie_crawl15 ] {Zombie_Walk(0.492); self.frame = 27;Zombie_Think();};
void() zombie_crawl15 =[ 14, Crawler_Walk_Setup ] {Zombie_Walk(2.856); self.frame = 28;Zombie_Think();crawler_footstep();};//footstep
//====================== Zombie To Crawler =======================
//0-4
void() crawlerify1 =[ 0, crawlerify2 ] {SetZombieHitBox(CRAWLER_BBOX); self.frame = 0;Zombie_Think();};
void() crawlerify2 =[ 1, crawlerify3 ] {self.frame = 1;Zombie_Think();};
void() crawlerify3 =[ 2, crawlerify4 ] {self.frame = 2;Zombie_Think();};
void() crawlerify4 =[ 3, crawlerify5 ] {self.frame = 3;Zombie_Think();crawler_footstep();crawler_footstep();};//hit floor
void() crawlerify5 =[ 4, Crawler_Walk_Setup ] {self.frame = 4;Zombie_Think();if(self.health <= 0) self.th_die();};//need to check for death since a grenade will not kill a zombie, only make him a crawler
//====================== Crawler Idle ==============================
//4-13
void() crawler_idle1 =[ 0, crawler_idle2 ] {SetZombieHitBox(CRAWLER_BBOX);Zombie_Walk(0); self.frame = 4;Zombie_Think();};
void() crawler_idle2 =[ 1, crawler_idle3 ] {Zombie_Walk(0); self.frame = 5;Zombie_Think();};
void() crawler_idle3 =[ 2, crawler_idle4 ] {Zombie_Walk(0); self.frame = 6;Zombie_Think();};
void() crawler_idle4 =[ 3, crawler_idle5 ] {Zombie_Walk(0); self.frame = 7;Zombie_Think();};
void() crawler_idle5 =[ 4, crawler_idle6 ] {Zombie_Walk(0); self.frame = 8;Zombie_Think();};
void() crawler_idle6 =[ 5, crawler_idle7 ] {Zombie_Walk(0); self.frame = 9;Zombie_Think();};
void() crawler_idle7 =[ 6, crawler_idle8 ] {Zombie_Walk(0); self.frame = 10;Zombie_Think();};
void() crawler_idle8 =[ 7, crawler_idle9 ] {Zombie_Walk(0); self.frame = 11;Zombie_Think();};
void() crawler_idle9 =[ 8, crawler_idle10 ] {Zombie_Walk(0); self.frame = 12;Zombie_Think();};
void() crawler_idle10 =[ 9, crawler_idle1 ] {Zombie_Walk(0); self.frame = 13;Zombie_Think();};
//===================== Crawler Attack ===========================
//29-36
void() crawler_atk1 =[ 0, crawler_atk2] {SetZombieHitBox(CRAWLER_BBOX);self.frame = 29;Zombie_Think();};
void() crawler_atk2 =[ 1, crawler_atk3] {self.frame = 30;Zombie_Think();};
void() crawler_atk3 =[ 2, crawler_atk4] {self.frame = 31;Zombie_Think();};
void() crawler_atk4 =[ 3, crawler_atk5] {self.frame = 32;zombie_attack2();Zombie_Think();};
void() crawler_atk5 =[ 4, crawler_atk6] {self.frame = 33;Zombie_Think();};
void() crawler_atk6 =[ 5, crawler_atk7] {self.frame = 34;Zombie_Think();};
void() crawler_atk7 =[ 6, crawler_atk8] {self.frame = 35;Zombie_Think();};
void() crawler_atk8 =[ 7, zombie_decide] {self.frame = 36;Zombie_Think();};
//====================== Crawler Delay Attack ==============================
//4-13
void(float which) crawler_attack_choose =
{
self.angles_y = vectoyaw(self.enemy.origin - self.origin);
if(which != 1)
{
if(random() > 0.2)
{
return;
}
}
if(vlen(self.enemy.origin - self.origin) > 60)//too far, cancel attack
{
zombie_decide();
return;
}
play_sound_z(1);
crawler_atk1();
};
void() crawler_da1 =[ 0, crawler_da2 ] {SetZombieHitBox(CRAWLER_BBOX);crawler_attack_choose(0); self.frame = 4;Zombie_Think();};
void() crawler_da2 =[ 1, crawler_da3 ] {crawler_attack_choose(0); self.frame = 5;Zombie_Think();};
void() crawler_da3 =[ 2, crawler_da4 ] {crawler_attack_choose(0); self.frame = 6;Zombie_Think();};
void() crawler_da4 =[ 3, crawler_da5 ] {crawler_attack_choose(0); self.frame = 7;Zombie_Think();};
void() crawler_da5 =[ 4, crawler_da6 ] {crawler_attack_choose(0); self.frame = 8;Zombie_Think();};
void() crawler_da6 =[ 5, crawler_da7 ] {crawler_attack_choose(0); self.frame = 9;Zombie_Think();};
void() crawler_da7 =[ 6, crawler_da8 ] {crawler_attack_choose(0); self.frame = 10;Zombie_Think();};
void() crawler_da8 =[ 7, crawler_da9 ] {crawler_attack_choose(0); self.frame = 11;Zombie_Think();};
void() crawler_da9 =[ 8, crawler_da10 ] {crawler_attack_choose(0); self.frame = 12;Zombie_Think();};
void() crawler_da10 =[ 9, crawler_da1 ] {crawler_attack_choose(0); self.frame = 13;Zombie_Think();};
//====================== Crawler Death ============================
//37-39
void() crawler_die1 =[ 0, crawler_die2] {SetZombieHitBox(CRAWLER_BBOX);self.frame = 37;};
void() crawler_die2 =[ 1, crawler_die3] {self.frame = 38;};
void() crawler_die3 =[ 2, SUB_Null] {self.iszomb = 0; self.frame = 39;self.nextthink = time + 3;self.think = removeZombie; addmoney(other, 60, true); if (crawler_num > 0) {crawler_num = crawler_num - 1;}};
//======================== Climb Over Barricade ====================
//40-70
void() crawler_climbBarricade1 =[ 0, crawler_climbBarricade2] {self.movetype = MOVETYPE_STEP;self.zoom = 1;self.frame = 40;Zombie_Think();};
void() crawler_climbBarricade2 =[ 1, crawler_climbBarricade3] {self.frame = 41; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade3 =[ 2, crawler_climbBarricade4] {self.frame = 42; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade4 =[ 3, crawler_climbBarricade5] {self.frame = 43; moveforwardalittle(1);Zombie_Think();};
void() crawler_climbBarricade5 =[ 4, crawler_climbBarricade6] {self.frame = 44; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade6 =[ 5, crawler_climbBarricade7] {self.frame = 45; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade7 =[ 6, crawler_climbBarricade8] {self.frame = 46; moveforwardalittle(1);Zombie_Think();};
void() crawler_climbBarricade8 =[ 7, crawler_climbBarricade9] {self.frame = 47; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade9 =[ 8, crawler_climbBarricade10] {self.frame = 48; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade10 =[ 9, crawler_climbBarricade11] {self.frame = 49; moveforwardalittle(1);Zombie_Think();};
void() crawler_climbBarricade11 =[ 10, crawler_climbBarricade12] {self.frame = 50; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade12 =[ 11, crawler_climbBarricade13] {self.frame = 51; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade13 =[ 12, crawler_climbBarricade14] {self.frame = 52; moveforwardalittle(1);Zombie_Think();};
void() crawler_climbBarricade14 =[ 13, crawler_climbBarricade15] {self.frame = 53; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade15 =[ 14, crawler_climbBarricade16] {self.frame = 54; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade16 =[ 15, crawler_climbBarricade17] {self.frame = 55; moveforwardalittle(1);Zombie_Think();};
void() crawler_climbBarricade17 =[ 16, crawler_climbBarricade18] {self.frame = 56; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade18 =[ 17, crawler_climbBarricade19] {self.frame = 57; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade19 =[ 18, crawler_climbBarricade20] {self.frame = 58; moveforwardalittle(1);Zombie_Think();};
void() crawler_climbBarricade20 =[ 19, crawler_climbBarricade21] {self.frame = 59; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade21 =[ 20, crawler_climbBarricade22] {self.frame = 60; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade22 =[ 21, crawler_climbBarricade23] {self.frame = 61; moveforwardalittle(1);Zombie_Think();};
void() crawler_climbBarricade23 =[ 22, crawler_climbBarricade24] {self.frame = 62; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade24 =[ 23, crawler_climbBarricade25] {self.frame = 63; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade25 =[ 24, crawler_climbBarricade26] {self.frame = 64; moveforwardalittle(1);Zombie_Think();};
void() crawler_climbBarricade26 =[ 25, crawler_climbBarricade27] {self.frame = 65; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade27 =[ 26, crawler_climbBarricade28] {self.frame = 66; moveforwardalittle(0);Zombie_Think();};
void() crawler_climbBarricade28 =[ 27, crawler_climbBarricade29] {self.frame = 67; moveforwardalittle(1);Zombie_Think();};
void() crawler_climbBarricade29 =[ 28, crawler_climbBarricade30] {self.frame = 68; moveforwardalittle(1);Zombie_Think();};
void() crawler_climbBarricade30 =[ 29, crawler_climbBarricade31] {self.frame = 69; moveforwardalittle(1);Zombie_Think();};
void() crawler_climbBarricade31 =[ 30, SUB_Null] {self.frame = 70; self.movetype = MOVETYPE_WALK; self.zoom = 1;self.state = 0;self.hop_step = 6; self.th_walk();Zombie_Think();};
//======================== Crawler Fall =============================
//71 - 77
void() crawler_fall1 =[ 0, crawler_fall2] {SetZombieHitBox(CRAWLER_BBOX);self.fall = TRUE;CheckLand();self.frame=71;Zombie_Think();};
void() crawler_fall2 =[ 1, crawler_fall3] {self.fall = TRUE;CheckLand();self.frame=72;Zombie_Think();};
void() crawler_fall3 =[ 2, crawler_fall4] {self.fall = TRUE;CheckLand();self.frame=73;Zombie_Think();};
void() crawler_fall4 =[ 3, crawler_fall5] {self.fall = TRUE;CheckLand();self.frame=74;Zombie_Think();};
void() crawler_fall5 =[ 4, crawler_fall6] {self.fall = TRUE;CheckLand();self.frame=75;Zombie_Think();};
void() crawler_fall6 =[ 5, crawler_fall7] {self.fall = TRUE;CheckLand();self.frame=76;Zombie_Think();};
void() crawler_fall7 =[ 6, crawler_fall1] {self.fall = TRUE;CheckLand();self.frame=77;Zombie_Think();};
//======================== Crawler Land ============================
//77-86
void() crawler_land1 =[ 0, crawler_land2] {SetZombieHitBox(CRAWLER_BBOX);self.frame=77;Zombie_Think();};
void() crawler_land2 =[ 1, crawler_land3] {self.frame=78;Zombie_Think();};
void() crawler_land3 =[ 2, crawler_land4] {self.frame=79;Zombie_Think();};
void() crawler_land4 =[ 3, crawler_land5] {self.frame=80;Zombie_Think();};
void() crawler_land5 =[ 4, crawler_land6] {self.frame=81;Zombie_Think();};
void() crawler_land6 =[ 5, crawler_land7] {self.frame=82;Zombie_Think();};
void() crawler_land7 =[ 6, crawler_land8] {self.frame=83;Zombie_Think();};
void() crawler_land8 =[ 7, crawler_land9] {self.frame=84;Zombie_Think();};
void() crawler_land9 =[ 8, crawler_land10] {self.frame=85;Zombie_Think();};
void() crawler_land10 =[ 9, Crawler_Walk_Setup] {self.frame=86;Zombie_Think();};
//======================== Crawler Rip Board =======================
//103-126
void() crawler_rip_board1 =[ 0, crawler_rip_board2] {SetZombieHitBox(CRAWLER_BBOX);self.frame=103;Zombie_Think();};
void() crawler_rip_board2 =[ 1, crawler_rip_board3] {self.frame=104;Zombie_Think();};
void() crawler_rip_board3 =[ 2, crawler_rip_board4] {self.frame=105;Zombie_Think();};
void() crawler_rip_board4 =[ 3, crawler_rip_board5] {self.frame=106;Zombie_Think();};
void() crawler_rip_board5 =[ 4, crawler_rip_board6] {self.frame=107;Zombie_Think();};
void() crawler_rip_board6 =[ 5, crawler_rip_board7] {self.frame=108;Zombie_Think();};
void() crawler_rip_board7 =[ 6, crawler_rip_board8] {self.frame=109;Zombie_Think();};
void() crawler_rip_board8 =[ 7, crawler_rip_board9] {self.frame=110;Zombie_Think();};
void() crawler_rip_board9 =[ 8, crawler_rip_board10] {self.frame=111;Zombie_Think();};
void() crawler_rip_board10 =[ 9, crawler_rip_board11] {self.frame=112;Zombie_Think();};
void() crawler_rip_board11 =[ 10, crawler_rip_board12] {self.frame=113;Zombie_Think();};
void() crawler_rip_board12 =[ 11, crawler_rip_board13] {self.frame=114;Zombie_Think();};
void() crawler_rip_board13 =[ 12, crawler_rip_board14] {self.frame=115;zombie_attack2();};
void() crawler_rip_board14 =[ 13, crawler_rip_board15] {self.frame=116;Zombie_Think();};
void() crawler_rip_board15 =[ 14, crawler_rip_board16] {self.frame=117;Zombie_Think();};
void() crawler_rip_board16 =[ 15, crawler_rip_board17] {self.frame=118;Zombie_Think();};
void() crawler_rip_board17 =[ 16, crawler_rip_board18] {self.frame=119;Zombie_Think();};
void() crawler_rip_board18 =[ 17, crawler_rip_board19] {self.frame=120;Zombie_Think();};
void() crawler_rip_board19 =[ 18, crawler_rip_board20] {self.frame=121;Zombie_Think();};
void() crawler_rip_board20 =[ 19, crawler_rip_board21] {self.frame=122;Zombie_Think();};
void() crawler_rip_board21 =[ 20, crawler_rip_board22] {self.frame=123;Zombie_Think();};
void() crawler_rip_board22 =[ 21, crawler_rip_board23] {self.frame=124;Zombie_Think();};
void() crawler_rip_board23 =[ 22, crawler_rip_board24] {self.frame=125;Zombie_Think();};
void() crawler_rip_board24 =[ 23, zombie_decide] {self.frame=126;Zombie_Think();};
void(entity who) makeCrawler =
{
if(who.state == 1)
{
who.crawling = 2;
return;
}
who.crawling = 2;//this means we haven't technically initiated it, but we're going to...
who.th_die = Zombie_Death;
who.th_walk = Crawler_Walk_Setup;
who.th_melee = zombie_attack;
who.th_idle = crawler_idle1;
who.th_windowhop = crawler_climbBarricade1;
who.th_fall = crawler_fall1;
who.th_land = crawler_land1;
//who.th_jump = zombie_jump1;
//who.th_grabledge = zombie_grabledge1;
//who.th_diewunder = die_wunder1;
setmodel(who,"models/ai/zcbod.mdl");
if(who.head.deadflag)
{
setmodel(who.head,"models/ai/zchead.mdl");
//updateLimb (who, 0, world);
}
if(who.larm.deadflag)
{
setmodel(who.larm,"models/ai/zclarm.mdl");
//updateLimb (who, 1, world);
}
if(who.rarm.deadflag)
{
setmodel(who.rarm,"models/ai/zcrarm.mdl");
//updateLimb (who, 2, world);
}
who.crawling = 1;
setsize(who,'-8 -8 -32','8 8 -15');
local entity oself;
oself = self;
self = who;
crawlerify1();
self = oself;
crawler_num = crawler_num + 1;
}

View file

@ -0,0 +1,374 @@
/*
server/ai/dog_core.qc
dog things
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
void() Dog_Think;
void() Dog_Death;
// DOG RUN
// 0-6
$frame dogrun1 dogrun2 dogrun3 dogrun4 dogrun5 dogrun6 dogrun7
void() dog_runanim =[ $dogrun1, dog_runanim2 ] {Dog_Think();Zombie_Walk(25);self.frame = 0;};
void() dog_runanim2 =[ $dogrun2, dog_runanim3 ] {Dog_Think();Zombie_Walk(15);self.frame = 1;};
void() dog_runanim3 =[ $dogrun3, dog_runanim4 ] {Dog_Think();Zombie_Walk(15);self.frame = 2;};
void() dog_runanim4 =[ $dogrun4, dog_runanim5 ] {Dog_Think();Zombie_Walk(15);self.frame = 3;};
void() dog_runanim5 =[ $dogrun5, dog_runanim6 ] {Dog_Think();Zombie_Walk(15);self.frame = 4;};
void() dog_runanim6 =[ $dogrun6, dog_runanim7 ] {Dog_Think();Zombie_Walk(15);self.frame = 5;};
void() dog_runanim7 =[ $dogrun7, dog_runanim ] {Dog_Think();Zombie_Walk(15);self.frame = 6;};
// DOG WALK
// 7-18
$frame dogwalk1 dogwalk2 dogwalk3 dogwalk4 dogwalk5 dogwalk6 dogwalk7 dogwalk8 dogwalk9 dogwalk10 dogwalk11 dogwalk12
void() dog_walkanim =[ $dogwalk1, dog_walkanim2 ] {Dog_Think();Zombie_Walk(8);self.frame = 7;};
void() dog_walkanim2 =[ $dogwalk2, dog_walkanim3 ] {Dog_Think();Zombie_Walk(8);self.frame = 8;};
void() dog_walkanim3 =[ $dogwalk3, dog_walkanim4 ] {Dog_Think();Zombie_Walk(8);self.frame = 9;};
void() dog_walkanim4 =[ $dogwalk4, dog_walkanim5 ] {Dog_Think();Zombie_Walk(8);self.frame = 10;};
void() dog_walkanim5 =[ $dogwalk5, dog_walkanim6 ] {Dog_Think();Zombie_Walk(8);self.frame = 11;};
void() dog_walkanim6 =[ $dogwalk6, dog_walkanim7 ] {Dog_Think();Zombie_Walk(8);self.frame = 12;};
void() dog_walkanim7 =[ $dogwalk7, dog_walkanim8 ] {Dog_Think();Zombie_Walk(8);self.frame = 13;};
void() dog_walkanim8 =[ $dogwalk8, dog_walkanim9 ] {Dog_Think();Zombie_Walk(8);self.frame = 14;};
void() dog_walkanim9 =[ $dogwalk9, dog_walkanim10 ] {Dog_Think();Zombie_Walk(8);self.frame = 15;};
void() dog_walkanim10 =[ $dogwalk10, dog_walkanim11 ] {Dog_Think();Zombie_Walk(8);self.frame = 16;};
void() dog_walkanim11 =[ $dogwalk11, dog_walkanim12 ] {Dog_Think();Zombie_Walk(8);self.frame = 17;};
void() dog_walkanim12 =[ $dogwalk12, dog_walkanim ] {Dog_Think();Zombie_Walk(8);self.frame = 18;};
// DOG IDLE
// 19-24
$frame dogstand1 dogstand2 dogstand3 dogstand4 dogstand5 dogstand6
void() dog_idleanim =[ $dogstand1, dog_idleanim2 ] {self.frame = 19;};
void() dog_idleanim2 =[ $dogstand2, dog_idleanim3 ] {self.frame = 20;};
void() dog_idleanim3 =[ $dogstand3, dog_idleanim4 ] {self.frame = 21;};
void() dog_idleanim4 =[ $dogstand4, dog_idleanim5 ] {self.frame = 22;};
void() dog_idleanim5 =[ $dogstand5, dog_idleanim6 ] {self.frame = 23;};
void() dog_idleanim6 =[ $dogstand6, dog_idleanim ] {self.frame = 24;};
// DOG MELEE
// 25-34
$frame dogmelee1 dogmelee2 dogmelee3 dogmelee4 dogmelee5 dogmelee6 dogmelee7 dogmelee8 dogmelee9 dogmelee10
void() dog_meleeanim =[ $dogmelee1, dog_meleeanim2 ] {Zombie_Walk(0);self.frame = 25;};
void() dog_meleeanim2 =[ $dogmelee2, dog_meleeanim3 ] {Zombie_Walk(0);self.frame = 26;};
void() dog_meleeanim3 =[ $dogmelee3, dog_meleeanim4 ] {Zombie_Walk(0);self.frame = 27;};
void() dog_meleeanim4 =[ $dogmelee4, dog_meleeanim5 ] {Zombie_Walk(0);self.frame = 28;};
void() dog_meleeanim5 =[ $dogmelee5, dog_meleeanim6 ] {Zombie_Walk(0);self.frame = 29;};
void() dog_meleeanim6 =[ $dogmelee6, dog_meleeanim7 ] {Zombie_Walk(0);zombie_attack2();self.frame = 30;};
void() dog_meleeanim7 =[ $dogmelee7, dog_meleeanim8 ] {Zombie_Walk(0);self.frame = 31;};
void() dog_meleeanim8 =[ $dogmelee8, dog_meleeanim9 ] {Zombie_Walk(0);self.frame = 32;};
void() dog_meleeanim9 =[ $dogmelee9, dog_meleeanim10 ] {Zombie_Walk(0);self.frame = 33;};
void() dog_meleeanim10 =[ $dogmelee10, dog_runanim ] {Zombie_Walk(0);self.frame = 34;};
// DOG DEATH
// 35 - 36
$frame dogdeath1 dogdeath2
void() dog_deathanim =[ $dogdeath1, dog_deathanim2 ] {self.frame = 35;};
void() dog_deathanim2 =[ $dogdeath2, SUB_Null ] {self.nextthink = time + 3; self.think = removeZombie; self.frame = 36;};
// DOG WAFFE DEATH
// 37-46
$frame dogwunder1 dogwunder2 dogwunder3 dogwunder4 dogwunder5 dogwunder6 dogwunder7 dogwunder8 dogwunder9 dogwunder10
void() die_dog_wunder1 =[ $dogwunder1, die_dog_wunder2 ] {Zombie_Walk(0);Zombie_Tesla_Light();self.frame = 37;};
void() die_dog_wunder2 =[ $dogwunder2, die_dog_wunder3 ] {Zombie_Walk(0);self.frame = 38;};
void() die_dog_wunder3 =[ $dogwunder3, die_dog_wunder4 ] {Zombie_Walk(0);self.frame = 39;};
void() die_dog_wunder4 =[ $dogwunder4, die_dog_wunder5 ] {Zombie_Walk(0);self.frame = 40;};
void() die_dog_wunder5 =[ $dogwunder5, die_dog_wunder6 ] {Zombie_Walk(0);self.frame = 41;};
void() die_dog_wunder6 =[ $dogwunder6, die_dog_wunder7 ] {Zombie_Walk(0);Zombie_Find_Tesla_Target();self.frame = 42;};
void() die_dog_wunder7 =[ $dogwunder7, die_dog_wunder8 ] {Zombie_Walk(0);self.frame = 43;};
void() die_dog_wunder8 =[ $dogwunder8, die_dog_wunder9 ] {Zombie_Walk(0);self.frame = 44;};
void() die_dog_wunder9 =[ $dogwunder9, die_dog_wunder10 ] {Zombie_Walk(0);self.frame = 45;};
void() die_dog_wunder10 =[ $dogwunder10, die_dog_wunder10 ] {Zombie_Walk(0);self.frame = 46;self.health = 0; self.th_die();};
// DOG LIGHTNING SPAWN
// 1-13
$frame dls1 dls2 dls3 dls4 dls5 dls6 dls7 dls8 dls9 dls10 dls11 dls12 dls13
void() dog_lightninganim =[ $dls1, dog_lightninganim2 ] {self.frame = 1;};
void() dog_lightninganim2 =[ $dls2, dog_lightninganim3 ] {self.frame = 2;};
void() dog_lightninganim3 =[ $dls3, dog_lightninganim4 ] {self.frame = 3;};
void() dog_lightninganim4 =[ $dls4, dog_lightninganim5 ] {self.frame = 4;};
void() dog_lightninganim5 =[ $dls5, dog_lightninganim6 ] {self.frame = 5;};
void() dog_lightninganim6 =[ $dls6, dog_lightninganim7 ] {self.frame = 6;};
void() dog_lightninganim7 =[ $dls7, dog_lightninganim8 ] {self.frame = 7;};
void() dog_lightninganim8 =[ $dls8, dog_lightninganim9 ] {self.frame = 8;};
void() dog_lightninganim9 =[ $dls9, dog_lightninganim10 ] {self.frame = 9;};
void() dog_lightninganim10 =[ $dls10, dog_lightninganim11 ] {self.frame = 10;};
void() dog_lightninganim11 =[ $dls11, dog_lightninganim12 ] {self.frame = 11;};
void() dog_lightninganim12 =[ $dls12, dog_lightninganim13 ] {self.frame = 12;};
void() dog_lightninganim13 =[ $dls13, SUB_Null ] {self.frame = 13; remove(self);};
// DOG EXPLODE SPRITE
// 1-5
$frame des1 des2 des3 des4 des5 des6
void() dog_explodeanim =[ $des1, dog_explodeanim2 ] {self.frame = 1;};
void() dog_explodeanim2 =[ $des2, dog_explodeanim3 ] {self.frame = 2;};
void() dog_explodeanim3 =[ $des3, dog_explodeanim4 ] {self.frame = 3;};
void() dog_explodeanim4 =[ $des4, dog_explodeanim5 ] {self.frame = 4;};
void() dog_explodeanim5 =[ $des5, dog_explodeanim6 ] {self.frame = 5;};
void() dog_explodeanim6 =[ $des5, SUB_Null ] {remove(self);};
void() Dog_Walk_Setup =
{
if (self.walktype == 1)
dog_walkanim();
else
dog_runanim();
};
// decide our walktype based on player distance
void() Dog_Think =
{
// FIXME - crash
self.walktype = 2;
/*
if(vlen(self.enemy.origin - self.origin) < 300)
self.walktype = 2;
else
self.walktype = 1;*/
}
float dogCount;
void() Dog_Death =
{
self.aistatus = "0";
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
self.takedamage = DAMAGE_NO;
sound(self,CHAN_WEAPON,"sounds/null.wav",1,ATTN_NORM);
self.usedent = world;
self.health = 0;
Remaining_Zombies = Remaining_Zombies - 1;
dogCount -= 1;
play_sound_z(3);
//Gotta' make sure we set it back down instead of glitching it up, yo'
if(self.s_time > 0 && sounds_playing > 0)
{
sounds_playing --;
self.s_time = 0;
}
if (rounds == dogRound)
{
if (!Remaining_Zombies)
Spawn_Powerup(self.origin + '0 0 12', 1);
}
float r = random();
// explode chance
if (r < 0.75) {
self.frame = 0;
setmodel (self, "models/sprites/explosion.spr");
sound (self, CHAN_WEAPON, "sounds/weapons/grenade/explode.wav", 1, ATTN_NORM);
dog_explodeanim();
} else {
dog_deathanim();
}
};
void(entity where) spawn_a_dogB =
{
local entity sdog;//USED FOR WHAT TO SPAWN
sdog = getFreeZombieEnt(self);
if(sdog == world)
{
return;
}
sdog.origin = where.origin;
sdog.frame = 0;
sdog.target = where.target;
sdog.solid = SOLID_CORPSE;
sdog.movetype = MOVETYPE_WALK;
setmodel(sdog, "models/ai/dog.mdl");
sdog.hop_step = 0;
sdog.gravity = 1.0;
sdog.mins = '-8 -8 -32';//-16 16 -32
sdog.maxs = '8 8 30';//16 16 40
setsize (sdog, sdog.mins, sdog.maxs);
if(pointcontents(sdog.origin - '0 0 36') == -2)
{
while(pointcontents (sdog.origin - '0 0 36') == -2)
{
sdog.origin = sdog.origin + '0 0 1';
setorigin(sdog,sdog.origin );
}
}
sdog.classname = "ai_dog";
sdog.aistatus = "1";
setorigin (sdog.goaldummy, '0 0 0');
sdog.origin_z = sdog.origin_z + 1;
sdog.takedamage = DAMAGE_YES;
setorigin(sdog, sdog.origin);
sdog.flags = sdog.flags | FL_PARTIALGROUND | FL_MONSTER;
sdog.spawnflags = where.spawnflags;
sdog.spawnflags = sdog.spawnflags | 1;
sdog.ideal_yaw = sdog.angles_y;
sdog.yaw_speed = 20;
sdog.health = z_health;
sdog.th_die = Dog_Death;
sdog.th_walk = Dog_Walk_Setup;
sdog.outside = FALSE;
sdog.iszomb = 1;
sdog.th_melee = dog_meleeanim;
sdog.th_idle = dog_idleanim;
sdog.th_diewunder = die_dog_wunder1;
SetZombieWalk(sdog);
sdog.walktype = 5;
sdog.reload_delay = 30 + time;//save floats, equals respawn time.
local entity old_self;
old_self = self;
self = sdog;
//droptofloor();
self.th_walk();
self = old_self;
};
void() dogsprite_think =
{
self.frame++;
if (self.frame >= 3)
self.frame = 0;
// suicide timer!
if(self.ltime < time) {
spawn_a_dogB(self.owner);
remove(self);
}
self.nextthink = time + 0.05;
}
void(entity where) spawn_dog_lightning =
{
local entity tempe;
local entity doglight;
local entity dogsprite;
// lightning model
doglight = spawn();
setmodel(doglight, "models/ai/dog_lightning.mdl");
setorigin(doglight, where.origin - '0 0 20');
tempe = self;
self = doglight;
dog_lightninganim();
self = tempe;
// lightning sprite
dogsprite = spawn();
setmodel(dogsprite, "models/sprites/lightning.spr");
setorigin(dogsprite, where.origin);
dogsprite.owner = where;
dogsprite.think = dogsprite_think;
dogsprite.nextthink = time + 0.05;
dogsprite.ltime = time + 1.3; // we use ltime here to be out remove timer,
// since using frames interrupts think()
}
float() spawn_a_dogA =
{
local float pcount;
local entity thing, szombie;
local float FAIL;
FAIL = false;
pcount = 0;
szombie = getFreeZombieEnt(self);
if(szombie == world || dogCount >= (2 * (player_count + 1)))
{
return 0;
}
lastspawn = find(lastspawn, classname, "spawn_dog");
while (random() < 0.4)
{
lastspawn = find(lastspawn, classname, "spawn_dog");
}
while(lastspawn)
{
thing = findradius(lastspawn.origin, 60);
while (thing)
{
pcount = 0;
if (thing.classname == "ai_dog")
{
pcount = 1;
break;
}
thing = thing.chain;
}
if (!pcount && random() < 0.6)
{
//spawn_a_dogB(lastspawn);
spawn_dog_lightning(lastspawn);
dogCount++;
spawn_delay = time + 2;
return true;
}
lastspawn = find(lastspawn, classname, "spawn_dog");
}
return 0; //no free locations fround
};
void() spawn_dog =
{
precache_model("models/ai/dog.mdl");
precache_model("models/ai/dog_lightning.mdl");
precache_model("models/sprites/lightning.spr");
precache_model("models/sprites/explosion.spr");
precache_sound("sounds/rounds/droundend.wav");
precache_sound("sounds/rounds/droundstart.wav");
setsize(self, '0 0 0', '0 0 0');
if (self.spawnflags & INACTIVE)
{
if (cvar("developer"))
setmodel(self, "models/player.mdl");
self.classname = "spawn_dog_in";
}
else
{
if (cvar("developer"))
setmodel(self, "models/ai/dog.mdl");
self.classname = "spawn_dog";
}
self.solid = SOLID_NOT;
};

View file

@ -0,0 +1,828 @@
/*
server/ai/fte/waypoints_core.qc
pc waypointing
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
void() creator_way_touch =
{
if (cvar("waypoint_mode")) {
if (other.classname != "player") {
return;
}
current_way = self;
}
}
void () Create_New_Waypoint =
{
float way_count;
float tempf;
entity tempe;
entity new_way;
way_count = -1;
tempe = find (world, classname, "waypoint");
while (tempe) {
tempf = stof(tempe.waynum);
if (tempf > way_count) {
way_count = tempf;
}
tempe = find (tempe, classname, "waypoint");
}
new_way = spawn();
setorigin(new_way, self.origin);
//new_way.flags = FL_ITEM;
new_way.solid = SOLID_TRIGGER;
setmodel(new_way, "models/way/normal_way.spr");
new_way.classname = "waypoint";
new_way.waynum = ftos(way_count + 1);
new_way.targetname = strzone(new_way.targetname);
bprint (PRINT_HIGH, "Created waypoint ");
bprint (PRINT_HIGH, new_way.waynum);
bprint (PRINT_HIGH, "\n");
new_way.touch = creator_way_touch;
}
void () Make_Special_Waypoint =
{
if (self.classname != "player" || !active_way) {
return;
}
if (active_way.targetname != "") {//Toggling it back off
setmodel(active_way, "models/way/current_way.spr");
active_way.targetname = "";
bprint (PRINT_HIGH, "Waypoint ");
bprint (PRINT_HIGH, active_way.waynum);
bprint (PRINT_HIGH, " is no longer a special waypoint\n");
return;
}
if (active_way) {
if(self.active_door == world) {
bprint (PRINT_HIGH, "Error: no door selected!\n");
return;
}
if(self.active_door.wayTarget == "") {
bprint (PRINT_HIGH, "Error: Door has no wayTarget value!\n");
return;
}
setmodel(active_way, "models/way/current_way_door.spr");
active_way.targetname = self.active_door.wayTarget;
bprint (PRINT_HIGH, "special waypoint ");
bprint (PRINT_HIGH, active_way.waynum);
bprint (PRINT_HIGH, " named ");
bprint (PRINT_HIGH, active_way.targetname);
bprint (PRINT_HIGH, "\n");
}
}
void () Move_Waypoint =
{
if (!active_way)
return;
setorigin (active_way, self.origin);
bprint (PRINT_HIGH, "Moved waypoint ");
bprint (PRINT_HIGH, active_way.waynum);
bprint (PRINT_HIGH, "\n");
}
void () Select_Waypoint =
{
if (self.classname != "player")
return;
if (!current_way)
return;
entity tempe;
if (current_way == active_way)
active_way = world;
else
active_way = current_way;
tempe = find (world, classname, "waypoint");
while (tempe)
{
if (tempe.targetname != "")
setmodel(tempe, "models/way/normal_way_door.spr");
else
setmodel(tempe, "models/way/normal_way.spr");
tempe = find (tempe, classname, "waypoint");
}
if (active_way)
{
if (active_way.targetname != "")
setmodel(active_way, "models/way/current_way_door.spr");
else
setmodel(active_way, "models/way/current_way.spr");
bprint (PRINT_HIGH, "Selected waypoint ");
bprint (PRINT_HIGH, active_way.waynum);
if(active_way.targetname != "")
{
bprint (PRINT_HIGH, ", special tag ");
bprint (PRINT_HIGH, active_way.targetname);
}
bprint (PRINT_HIGH, "\n");
float i;
for (i = 0; i < MAX_WAY_TARGETS; i++) {
tempe = find (world, waynum, active_way.targets[i]);
if (tempe) {
if (tempe.targetname != "")
setmodel(tempe, "models/way/last_way_door.spr");
else
setmodel(tempe, "models/way/last_way.spr");
} else {
active_way.targets[i] = "";
}
}
}
}
void() Remove_Waypoint =
{
entity tempe;
float i;
if (!active_way)
return;
tempe = find (world, classname, "waypoint");
while (tempe) {
for (i = 0; i < MAX_WAY_TARGETS; i++) {
if (tempe.targets[i] == active_way.waynum) {
tempe.targets[i] = "";
}
}
tempe = find (tempe, classname, "waypoint");
}
bprint(PRINT_HIGH, "Removed waypoint ");
bprint(PRINT_HIGH, active_way.waynum);
bprint(PRINT_HIGH, "\n");
remove (active_way);
}
float Waypoint_Linked_To(entity from, entity to) {
float i;
for (i = 0; i < MAX_WAY_TARGETS; i++) {
if (from.waynum == to.targets[i]) {
bprint(PRINT_HIGH, "These waypoints are already linked!\n");
return 1;
}
}
return 0;
}
float Link (entity from, entity to) {
float i;
entity tempe;
for (i = 0; i < MAX_WAY_TARGETS; i++) {
tempe = find (world, waynum, from.targets[i]);
if (tempe == world || tempe == to) {
from.targets[i] = to.waynum;
bprint(PRINT_HIGH, "Linked waypoint ");
bprint(PRINT_HIGH, to.waynum);
bprint(PRINT_HIGH, " to ");
bprint(PRINT_HIGH, from.waynum);
bprint(PRINT_HIGH, "\n");
if (to.targetname != "") {
setmodel(to, "models/way/last_way_door.spr");
} else {
setmodel(to, "models/way/last_way.spr");
}
return 1;
}
}
return 0;
}
void () Link_Waypoints =
{
if (self.classname != "player")
return;
if (!current_way)
return;
if (!active_way)
return;
if (current_way == active_way)
return;
if (Waypoint_Linked_To(current_way, active_way)) {
bprint(PRINT_HIGH, "These waypoints are already linked!\n");
return;
}
float i;
entity tempe;
for (i = 0; i < MAX_WAY_TARGETS; i++) {
#ifdef PC
tempe = findfloat (world, waynum, active_way.targets[i]);
#else
tempe = find (world, waynum, active_way.targets[i]);
#endif
if (tempe == world) {
if (Link(active_way, current_way)) {
return;
}
}
}
bprint(PRINT_HIGH, "no targets remaining!\n");
}
void() Dual_Link_Waypoints =
{
if (self.classname != "player" || !current_way || !active_way || current_way == active_way) {
return;
}
float result1,result2;
result1 = Waypoint_Linked_To(current_way,active_way);
result2 = Waypoint_Linked_To(active_way,current_way);
if(result1 && result2) {
bprint(PRINT_HIGH, "Both waypoints already linked!\n");
return;
}
if(!result1)
{
if (Link(current_way,active_way)) {
bprint(PRINT_HIGH, strcat("Linked waypoint ", strcat(current_way.waynum, strcat(" to ",strcat(active_way.waynum, "\n")))));
} else {
bprint(PRINT_HIGH, strcat("ERROR: Could not link waypoint ", strcat(current_way.waynum, strcat(" to ", strcat(active_way.waynum, "\n")))));
}
}
if(!result2)
{
if (Link(active_way,current_way)) {
bprint(PRINT_HIGH, strcat("Linked waypoint ", strcat(active_way.waynum, strcat(" to ", strcat(current_way.waynum, "\n")))));
} else {
bprint(PRINT_HIGH, strcat("ERROR: Could not link waypoint ", strcat(active_way.waynum, strcat(" to ", strcat(current_way.waynum, "\n")))));
}
}
}
//alter auto_link_waypoints to iterate through the closest waypoints from closest to furthest
// on the innermost loop, we find the next closest waypoint that is further away from the last closest waypoint, and we use that!
void() Auto_Link_Waypoints =
{
entity tempe1, tempe2;
tempe1 = find(world,classname,"waypoint");
while(tempe1 != world)
{
tempe2 = find(world,classname,"waypoint");
while(tempe2 != world)
{
if(tempe1 == tempe2)
{
tempe2 = find(tempe2,classname,"waypoint");
continue;
}
if(tracemove(tempe1.origin,VEC_HULL_MIN,VEC_HULL_MAX,tempe2.origin,TRUE,self))
{
Link(tempe1,tempe2);
}
tempe2 = find(tempe2,classname,"waypoint");
}
tempe1 = find(tempe1,classname,"waypoint");
}
}
//alter auto_link_waypoints to iterate through the closest waypoints from closest to furthest
// on the innermost loop, we find the next closest waypoint that is further away from the last closest waypoint, and we use that!
void() Remove_Links =
{
entity tempe;
tempe = find(world,classname,"waypoint");
while(tempe != world)
{
float i;
for (i = 0; i < MAX_WAY_TARGETS; i = i + 1) {
if (tempe.targetname != "")
setmodel(tempe, "models/way/normal_way_door.spr");
else
setmodel(tempe, "models/way/normal_way.spr");
tempe.targets[i] = "";
}
tempe = find(tempe,classname,"waypoint");
}
}
void() Save_Waypoints
{
float file;
string h;
float i;
entity tempe;
h = strcat(mappath, ".way");
file = fopen (h, FILE_WRITE);
dprint (strcat("Saving waypoints ", strcat(h, "\n")));
local entity dway;
//fputs(file, "begin\n");
dway = find(world, classname, "waypoint");
while (dway)
{
fputs(file,"waypoint\n");
fputs(file,"{\n");
fputs(file, strcat(" id: ", strcat(dway.waynum, "\n")));
fputs(file, strcat(" origin: ", strcat(vtos(dway.origin), "\n")));
if (dway.targetname != "") {
fputs(file, strcat(" door: ", strcat(dway.targetname, "\n")));
}
fputs(file, " targets:\n");
fputs(file, " [\n");
for (i = 0; i < MAX_WAY_TARGETS; i++) {
if (dway.targets[i] != "") {
#ifdef PC
tempe = findfloat (world, waynum, dway.targets[i]);
#else
tempe = find (world, waynum, dway.targets[i]);
#endif
if (tempe != world) {
fputs(file, strcat(" ", strcat(dway.targets[i], "\n")));
} else {
tempe = find (world, waynum, dway.targets[i]);
if (tempe != world) {
fputs(file, strcat(" ", strcat(dway.targets[i], "\n")));
}
}
}
}
fputs(file, " ]\n");
fputs(file,"}\n");
dway = find(dway, classname, "waypoint");
if (dway)
fputs(file,"\n");
}
fclose(file);
}
void (vector here, float which, string special, string trg, string trg2, string trg3, string trg4, string trg5, string trg6, string trg7, string trg8) Create_Waypoint =
{
entity new_way;
new_way = spawn();
setorigin(new_way, here);
//new_way.flags = FL_ITEM;
new_way.solid = SOLID_TRIGGER;
if (cvar("waypoint_mode"))
setmodel(new_way, "models/way/normal_way.spr");
new_way.classname = "waypoint";
new_way.waynum = ftos(which);
dprint ("Created waypoint ");
dprint (new_way.waynum);
dprint ("\n");
if (special != "")
{
if (!cvar("waypoint_mode"))
new_way.classname = "waypoint_s";
if (cvar("waypoint_mode"))
setmodel(new_way, "models/way/normal_way_door.spr");
new_way.targetname = special;
dprint ("Special waypoint ");
dprint (new_way.targetname);
dprint ("\n");
//current_special++;
}
new_way.targets[0] = trg;
new_way.targets[1] = trg2;
new_way.targets[2] = trg3;
new_way.targets[3] = trg4;
new_way.targets[4] = trg5;
new_way.targets[5] = trg6;
new_way.targets[6] = trg7;
new_way.targets[7] = trg8;
new_way.touch = creator_way_touch;
}
float waypoints_loaded;
void() Load_Waypoints
{
float file, point;
string h;
float targetcount, loop;
entity new_way;
h = strcat(mappath, ".way");
file = fopen (h, FILE_READ);
if (file == -1)
{
dprint("Error: file not found \n");
return;
}
new_way = spawn();
targetcount = 0;
point = 0;
loop = 1;
while (loop)
{
string line;
line = fgets(file);
if not (line) {
bprint(PRINT_HIGH, "End of file\n");
loop = 0;
break;
}
h = strtrim(line);
//bprint(PRINT_HIGH, strcat(h, "\n"));
if (h == "") {
continue;
}
switch (point) {
case 0:
if (h == "waypoint") {
new_way = spawn();
new_way.solid = SOLID_TRIGGER;
new_way.model = "models/way/normal_way.spr";
setmodel(new_way, "models/way/normal_way.spr");
new_way.classname = "waypoint";
new_way.touch = creator_way_touch;
point = 1;
targetcount = 0;
} else if (h == "Waypoint") {
bprint(PRINT_HIGH, "Identified .way as legacy..\n");
point = 99;
Load_Waypoints_Legacy();
loop = 0;
break;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown point ", strcat(h, "\n")));
}
break;
case 1:
if (h == "{") {
point = 2;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(h, " expected {\n")));
}
break;
case 2:
tokenize(h);
string value, variable;
variable = strtrim(argv(0));
value = strtrim(argv(2));
//bprint(PRINT_HIGH, strcat(variable, "\n"));
switch (variable) {
case "origin":
print(strcat(value, "\n"));
new_way.origin = stov(value);
setorigin(new_way, new_way.origin);
break;
case "id":
new_way.waynum = value;
break;
case "door":
new_way.targetname = value;
setmodel(new_way, "models/way/normal_way_door.spr");
break;
case "targets":
point = 3;
break;
case "}":
point = 0;
break;
default:
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(variable, "\n")));
break;
}
break;
case 3:
if (h == "[") {
point = 4;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(h, " expected [\n")));
}
break;
case 4:
if (targetcount >= MAX_WAY_TARGETS) {
bprint(PRINT_HIGH, "Error: Target count too high for waypoint\n");
} else if (h == "]") {
point = 2;
} else {
bprint(PRINT_HIGH, strcat(strcat("WAYPOINT TARGET: ", strcat(strcat(ftos(targetcount), " "), h)), "\n"));
new_way.targets[targetcount] = h;
targetcount++;
}
break;
}
}
fclose(file);
waypoints_loaded = 1;
}
void() Load_Waypoints_Legacy
{
float file, which;
string h, special, trg, trg2, trg3, trg4, trg5, trg6, trg7, trg8;
local vector where;
h = strcat(mappath, ".way");
file = fopen (h, FILE_READ);
if (file == -1)
{
dprint("Error: file not found \n");
return;
}
while (1)
{
dprint("Loading waypoint\n");
// the first line is just a comment, ignore it
h = fgets(file);
if (h != "Waypoint")
{
bprint(PRINT_HIGH, "Last waypoint\n");
fclose(file);
return;
}
h = fgets(file);
h = fgets(file);
h = substring(h, 9, 20);
where = stov(h);
h = (fgets(file));
h = substring(h, 5, 20);
which = stof(h);
h = (fgets(file));
special = substring(h, 10, 20);
h = (fgets(file));
trg = substring(h, 9, 20);
h = (fgets(file));
trg2 = substring(h, 10, 20);
h = (fgets(file));
trg3 = substring(h, 10, 20);
h = (fgets(file));
trg4 = substring(h, 10, 20);
h = (fgets(file));
trg5 = substring(h, 10, 20);
h = (fgets(file));
trg6 = substring(h, 10, 20);
h = (fgets(file));
trg7 = substring(h, 10, 20);
h = (fgets(file));
trg8 = substring(h, 10, 20);
#ifndef PC
Create_Waypoint(where, which, special, trg, trg2, trg3, trg4, trg5, trg6, trg7, trg8);
#else
waypoint_ai waypoint;
waypoint = waypoints[which];
waypoints[which].id = which;
waypoints[which].org = where;
waypoints[which].targetdoor = special;
waypoints[which].target_id[0] = stof(trg);
waypoints[which].target_id[1] = stof(trg2);
waypoints[which].target_id[2] = stof(trg3);
waypoints[which].target_id[3] = stof(trg4);
waypoints[which].target_id[4] = stof(trg5);
waypoints[which].target_id[5] = stof(trg6);
waypoints[which].target_id[6] = stof(trg7);
waypoints[which].target_id[7] = stof(trg8);
#endif
h = (fgets(file));
h = (fgets(file));
}
}
void VisualizePathfind() {
if (self.classname != "player")
return;
if (!current_way)
return;
if (!active_way)
return;
if (current_way == active_way)
return;
Pathfind(self, stof(active_way.waynum), stof(current_way.waynum));
}
.float waypoint_delay;
//Waypoint logic functions
void () Waypoint_Functions =
{
// naievil -- archaic
/*
switch (self.impulse) {
case 100:
Create_New_Waypoint();
break;
case 101:
Make_Special_Waypoint();
break;
case 102:
Select_Waypoint();
break;
case 103:
Move_Waypoint();
break;
case 104:
Link_Waypoints ();
break;
case 105:
Dual_Link_Waypoints();
break;
case 106:
Save_Waypoints();
break;
case 107:
Load_Waypoints();
break;
case 108:
Load_Waypoints_Legacy();
break;
case 109:
Remove_Waypoint();
//VisualizePathfind();
break;
case 110:
Auto_Link_Waypoints();
break;
case 111:
Remove_Links();
break;
}
self.impulse = 0;
*/
switch (self.impulse) {
case 23:
Save_Waypoints();
break;
case 22:
if (!waypoints_loaded)
Load_Waypoints();
break;
case 110:
Move_Waypoint();
break;
}
self.impulse = 0;
// Match what we display on the screen
if (self.button0 && self.waypoint_delay < time) {
Create_New_Waypoint();
self.waypoint_delay = time + 1;
}
if (self.button7 && self.waypoint_delay < time) {
Select_Waypoint();
self.waypoint_delay = time + 0.25;
}
if (self.button8 && self.waypoint_delay < time) {
Link_Waypoints ();
self.waypoint_delay = time + 0.5;
}
if (self.button6 && self.waypoint_delay < time) {
Remove_Waypoint();
self.waypoint_delay = time + 0.5;
}
if (self.button5 && self.waypoint_delay < time) {
Make_Special_Waypoint();
self.waypoint_delay = time + 1;
}
};
void () Waypoint_Logic =
{
if (!waypoint_mode) {
waypoint_mode = 1;
entity zent;
zent = find (world, classname, "ai_zombie");
while (zent)
{
remove (zent);
zent = find (zent, classname, "ai_zombie");
}
zent = find (world, classname, "door_nzp_cost");
while (zent)
{
zent.solid = SOLID_NOT;
zent.touch = SUB_Null;
zent = find (zent, classname, "door_nzp_cost");
}
zent = find (world, classname, "door_nzp");
while (zent)
{
zent.solid = SOLID_NOT;
zent.touch = SUB_Null;
zent.solid = SOLID_NOT;
zent = find (zent, classname, "door_nzp");
}
zent = find (world, classname, "window");
while (zent)
{
zent.solid = SOLID_NOT;
zent.touch = SUB_Null;
zent = find (zent, classname, "window");
}
}
Waypoint_Functions();
};

View file

@ -0,0 +1,469 @@
/*
server/ai/pathfind_core.qc
generic waypoint pathfinding
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
void() Load_Waypoints_Legacy;
float Distance (vector from, vector to) {
return vlen(from - to);
}
float HeuristicCostEstimate (float start_way, float end_way)
{
//for now we will just look the distance between.
return Distance(waypoints[start_way].org, waypoints[end_way].org);
}
void ReconstructPath(entity z, float start_way, float end_way) {
}
float open_first;
float open;
float closed_init;
float closed;
float closed_first;
void SV_WP_ClearSet()
{
float i;
for (i = 0; i < MAX_WAYPOINTS; i = i + 1)
{
waypoints[i].set = 0;
}
}
float IsActive(float way) {
if (waypoints[way].targetdoor != "") {
entity door;
door = find(world, wayTarget, waypoints[way].targetdoor);
if (door != world) {
if (door.state == STATE_BOTTOM) {
return 0;
}
}
}
return 1;
}
void SV_WP_SetAdd(float wp, float isopen)
{
if (isopen)
{
// we only get added here from none, so no cleanup required
// gotta check if last entry was removed before this call
if (waypoints[open_first].set == SET_CLOSED)
{
//Con_Printf("Empty set: %i is new first\n", wp);
open_first = wp;
waypoints[wp].prev = wp;
}
else
{
waypoints[wp].prev = open;
waypoints[open].next = wp;
}
waypoints[wp].next = wp;
waypoints[wp].set = SET_OPEN;
open = wp;
}
else
{
// even if wp is the only one in the set, it doesn't really matter
if (wp == open_first)
open_first = waypoints[wp].next;
if (wp == open)
open = waypoints[wp].prev;
// update links so open set doesn't get fucked
waypoints[waypoints[wp].prev].next = waypoints[wp].next;
waypoints[waypoints[wp].next].prev = waypoints[wp].prev;
if (!closed_init)
{
closed_first = wp;
waypoints[wp].prev = wp;
closed_init = true;
}
else
{
waypoints[closed].next = wp;
waypoints[wp].prev = closed;
}
waypoints[wp].next = wp;
waypoints[wp].set = SET_CLOSED;
closed = wp;
}
}
float Pathfind (entity z, float s_wp, float e_wp) {
float current;
float i, j;
float bestf;
if (s_wp == e_wp) {
return 2;
}
SV_WP_ClearSet();
open_first = s_wp;
open = s_wp;
waypoints[s_wp].next = s_wp;
waypoints[s_wp].prev = s_wp;
waypoints[s_wp].set = SET_OPEN;
waypoints[s_wp].g = 0;
waypoints[s_wp].f = HeuristicCostEstimate(s_wp, e_wp);
waypoints[s_wp].step = s_wp;
current = s_wp;
closed_init = false;
// while openset is not empty
while (waypoints[open_first].set == SET_OPEN) {
i = open_first;
bestf = 320000;
//print("Current ", ftos(current), "\n");
// go from first open to last, pick the one with lowest f
do {
if (waypoints[i].f < bestf) {
current = i;
bestf = waypoints[i].f;
}
i = waypoints[i].next;
} while (i != open);
// mark node as visited
//print("Removing ", ftos(current), " from open\n");
SV_WP_SetAdd(current, false);
// we found a result, loop back with pathlength
if (current == e_wp) {
j = i = current;
// walk constructed path backwards
// keep 2 next steps with us
//print("Result\n");
//print(ftos(current), "\n");
while (waypoints[current].step != current)
{
j = i;
i = current;
current = waypoints[current].step;
}
// go to the furthest one on the path that we can actually see
if (tracemove(waypoints[s_wp].org,VEC_HULL_MIN,VEC_HULL_MAX,waypoints[i].org,TRUE,z))
{
//VectorCopy(waypoints[i].origin, res);
//print("Giving third wp ", ftos(i), "\n");
return i;
}
else if (tracemove(waypoints[s_wp].org,VEC_HULL_MIN,VEC_HULL_MAX,waypoints[j].org,TRUE,z))
{
//VectorCopy(waypoints[j].origin, res);
//print("Giving second wp ", ftos(j), "\n");
return j;
}
else
{
//VectorCopy(waypoints[current].origin, res);
//print("Giving first wp ", ftos(current), "\n");
return current;
}
}
// check neighbours to add to openset
for (j = 0; j < MAX_WAY_TARGETS; j++)
{
i = waypoints[current].target_id[j];
if (waypoints[i].set != SET_CLOSED && i != current && IsActive(i))
{
bestf = waypoints[current].g + HeuristicCostEstimate(i, current);
if (waypoints[i].set == SET_NONE || bestf < waypoints[i].g)
{
waypoints[i].step = current;
waypoints[i].g = bestf;
waypoints[i].f = bestf + HeuristicCostEstimate(i, e_wp);
if (waypoints[i].set == SET_NONE)
{
//print("Adding ", ftos(i), " into open\n");
SV_WP_SetAdd(i, true);
}
}
}
}
}
print("Waypointing failed\n");
return -1;
}
float Do_Pathfind(entity from, entity to) {
float i;
float TraceResult;
float dist, best_dist, best, best_target;
best = 0;
best_target = 0;
dist = 0;
best_dist = 100000000;
#ifndef PSP
for (i = 0; i < MAX_WAYPOINTS; i = i + 1) {
if (IsActive(i)) {
TraceResult = tracemove (from.origin, VEC_HULL_MIN, VEC_HULL_MAX, waypoints[i].org, TRUE ,from);
if (TraceResult) {
dist = Distance(waypoints[i].org, from.origin);
if(dist < best_dist) {
best_dist = dist;
best = i;
}
}
}
}
dist = 0;
best_dist = 100000000;
for (i = 0; i < MAX_WAYPOINTS; i = i + 1) {
if (IsActive(i)) {
TraceResult = tracemove (to.origin, VEC_HULL_MIN, VEC_HULL_MAX, waypoints[i].org, TRUE ,to);
if (TraceResult) {
dist = Distance(waypoints[i].org, to.origin);
if(dist < best_dist) {
best_dist = dist;
best_target = i;
}
}
}
}
//print("Starting waypoint: ", ftos(best)," Ending waypoint: ", ftos(best_target), "\n");
return Pathfind(from, best, best_target);
#else
return 0;
#endif
}
void CalcDistances() {
float i, s;
for (i = 1; i < MAX_WAYPOINTS; i++) {
waypoint_ai way;
way = waypoints[i];
if (way.id > 0) {
for (s = 0; s < MAX_WAY_TARGETS; s++) {
float targ;
targ = way.target_id[s];
if (targ > 0) {
way.dist[s] = Distance(way.org, waypoints[targ].org);
}
}
}
}
}
void creator_way_touch();
void LoadWaypointData() {
float file, point;
string h;
float targetcount, loop, waycount;
entity new_way;
h = strcat(mappath, ".way");
file = fopen (h, FILE_READ);
if (file == -1)
{
dprint("Error: file not found \n");
return;
}
float i, s;
#ifndef PSP
for (i = 0; i < MAX_WAYPOINTS; i = i + 1) {
waypoint_ai way;
way = waypoints[i];
way.org = '0 0 0';
way.id = 0;
way.g = 0;
way.f = 0;
way.set = 0;
way.targetdoor = "";
for (s = 0; s < MAX_WAY_TARGETS; s = s + 1) {
way.target_id[s] = 0;
way.dist[s] = 0;
}
}
#endif
new_way = spawn();
point = 0;
waycount = 0;
targetcount = 0;
loop = 1;
while (loop)
{
string line;
line = fgets(file);
if not (line) {
//bprint(PRINT_HIGH, "End of file\n");
loop = 0;
break;
}
h = strtrim(line);
//print(h, "\n");
if (h == "") {
continue;
}
switch (point) {
case 0:
if (h == "waypoint") {
new_way = spawn();
new_way.solid = SOLID_TRIGGER;
setmodel(new_way, "models/way/normal_way.spr");
new_way.classname = "waypoint";
new_way.touch = creator_way_touch;
point = 1;
targetcount = 0;
} else if (h == "Waypoint") {
bprint(PRINT_HIGH, "Identified .way as legacy..\n");
point = 99;
Load_Waypoints_Legacy();
} else {
bprint(PRINT_HIGH, strcat("Error: unknown point ", strcat(h, "\n")));
}
break;
case 1:
if (h == "{") {
point = 2;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(h, " expected {\n")));
}
break;
case 2:
tokenize(h);
string value, variable;
variable = strtrim(argv(0));
value = strtrim(argv(2));
switch (variable) {
case "origin":
setorigin(new_way, stov(value));
break;
case "id":
new_way.waynum = value;
break;
case "door":
new_way.targetname = value;
break;
case "targets":
point = 3;
break;
case "}":
float id = stof(new_way.waynum);
waypoint_ai waypoint;
waypoint = waypoints[id];
waypoints[id].id = id;
waypoints[id].org = new_way.origin;
waypoints[id].targetdoor = new_way.targetname;
for (i = 0; i < MAX_WAY_TARGETS; i++) {
waypoints[id].target_id[i] = stof(new_way.targets[i]);
}
if (!cvar("waypoint_mode")) {
remove(new_way);
}
point = 0;
break;
default:
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(variable, "\n")));
break;
}
break;
case 3:
if (h == "[") {
point = 4;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(h, " expected [\n")));
}
break;
case 4:
if (targetcount >= MAX_WAY_TARGETS) {
bprint(PRINT_HIGH, "Error: Target count too high for waypoint\n");
} else if (h == "]") {
point = 2;
} else {
new_way.targets[targetcount] = h;
targetcount++;
}
break;
}
}
if (new_way) {
if (!cvar("waypoint_mode")) {
remove(new_way);
}
}
fclose(file);
#ifndef PSP
CalcDistances();
#endif
}

View file

@ -0,0 +1,117 @@
/*
server/ai/standard/waypoints_core.qc
non-pc waypoint impulsing
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
float waypoint_action;
void () Waypoint_Functions =
{
switch (self.impulse)
{
case 15:
Make_Special_Waypoint();
break;
case 10:
Move_Waypoint();
break;
case 18:
Remove_Waypoint ();
break;
case 21:
Link_Waypoints ();
break;
case 20:
Dual_Link_Waypoints();
break;
case 22:
Auto_Link_Waypoints();
break;
case 101:
Save_Waypoints();
break;
case 102:
Load_Waypoints();
break;
}
if(self.button8 && !self.semi)
{
self.semi = true;
Dual_Link_Waypoints();
waypoint_action = waypoint_action + 1;
}
if (self.button0 && !self.semi)
{
Create_New_Waypoint();
waypoint_action = waypoint_action + 1;
self.semi = true;
}
if (self.button7 && !self.semiuse)
{
Select_Waypoint();
waypoint_action = waypoint_action + 1;
self.semiuse = true;
}
if(self.button4 && !self.semiuse)
{
self.semiuse = true;
waypoint_action = waypoint_action + 1;
Move_Waypoint();
}
if(self.button6 && !self.semiuse)
{
Remove_Waypoint ();
waypoint_action = waypoint_action + 1;
self.semiuse = true;
}
if(self.button5 && !self.semiuse)
{
Make_Special_Waypoint();
waypoint_action = waypoint_action + 1;
self.semiuse = true;
}
if(!self.button0 && !self.button7 && !self.button4 && !self.button5 && !self.button6 && !self.button8)
{
self.semiuse = false;
self.semi = false;
}
self.impulse = 0;
};
void () Waypoint_Logic =
{
if (waypoint_action > 20) {
if (cvar("autosave_waypoint"))
Save_Waypoints();
waypoint_action = 0;
}
Waypoint_Functions();
};

View file

@ -0,0 +1,907 @@
/*
server/ai/standard/waypoints_func.qc
non-pc waypointing
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
//float current_special;
entity active_way, current_way;
float (entity way1, entity way2) progs_Link_Waypoints =
{
if (way1 == world)
return 0;
if (way2 == world)
return 0;
if (way2 == way1)
return 0;
if(
way1.target == way2.waynum ||
way1.target2 == way2.waynum ||
way1.target3 == way2.waynum ||
way1.target4 == way2.waynum ||
way1.target5 == way2.waynum ||
way1.target6 == way2.waynum ||
way1.target7 == way2.waynum ||
way1.target8 == way2.waynum
)
{
//bprint(PRINT_HIGH, "These waypoints are already linked!\n");
return 2;//already linked
}
if (way1.target == "")
{
way1.target = way2.waynum;
way1.target = strzone(way1.target);
}
else if (way1.target2 == "")
{
way1.target2 = way2.waynum;
way1.target2 = strzone(way1.target2);
}
else if (way1.target3 == "")
{
way1.target3 = way2.waynum;
way1.target3 = strzone(way1.target3);
}
else if (way1.target4 == "")
{
way1.target4 = way2.waynum;
way1.target4 = strzone(way1.target4);
}
else if (way1.target5 == "")
{
way1.target5 = way2.waynum;
way1.target5 = strzone(way1.target5);
}
else if (way1.target6 == "")
{
way1.target6 = way2.waynum;
way1.target6 = strzone(way1.target6);
}
else if (way1.target7 == "")
{
way1.target7 = way2.waynum;
way1.target7 = strzone(way1.target7);
}
else if (way1.target8 == "")
{
way1.target8 = way2.waynum;
way1.target8 = strzone(way1.target8);
}
else
{
//bprint(PRINT_HIGH, "no targets remaining!\n");
return -1;//no targets
}
return 1;
}
//alter auto_link_waypoints to iterate through the closest waypoints from closest to furthest
// on the innermost loop, we find the next closest waypoint that is further away from the last closest waypoint, and we use that!
void() Auto_Link_Waypoints =
{
entity tempe1, tempe2;
tempe1 = find(world,classname,"waypoint");
while(tempe1 != world)
{
tempe2 = find(world,classname,"waypoint");
while(tempe2 != world)
{
if(tempe1 == tempe2)
{
tempe2 = find(tempe2,classname,"waypoint");
continue;
}
if(tracemove(tempe1.origin,VEC_HULL_MIN,VEC_HULL_MAX,tempe2.origin,TRUE,self))
{
progs_Link_Waypoints(tempe1,tempe2);
}
tempe2 = find(tempe2,classname,"waypoint");
}
tempe1 = find(tempe1,classname,"waypoint");
}
}
void() Remove_Waypoint =
{
entity tempe;
if (!active_way)
return;
tempe = find (world, classname, "waypoint");
while (tempe)
{
if (tempe.targetname != "")
setmodel(tempe, "models/way/normal_way_door.spr");
else
setmodel(tempe, "models/way/normal_way.spr"); //restore the original one, shall we
tempe = find (tempe, classname, "waypoint");
}
tempe = find (world, target, active_way.waynum);
if (tempe)
tempe.target = "";
tempe = find (world, target2, active_way.waynum);
if (tempe)
tempe.target2 = "";
tempe = find (world, target3, active_way.waynum);
if (tempe)
tempe.target3 = "";
tempe = find (world, target4, active_way.waynum);
if (tempe)
tempe.target4 = "";
tempe = find (world, target5, active_way.waynum);
if (tempe)
tempe.target5 = "";
tempe = find (world, target6, active_way.waynum);
if (tempe)
tempe.target6 = "";
tempe = find (world, target7, active_way.waynum);
if (tempe)
tempe.target7 = "";
tempe = find (world, target8, active_way.waynum);
if (tempe)
tempe.target8 = "";
//if (active_way.targetname != "")
// current_special--;
bprint (PRINT_HIGH, "Removed waypoint ");
bprint (PRINT_HIGH, active_way.waynum);
bprint (PRINT_HIGH, "\n");
strunzone (active_way.classname);
strunzone (active_way.targetname);
strunzone (active_way.waynum);
strunzone (active_way.target);
strunzone (active_way.target2);
strunzone (active_way.target3);
strunzone (active_way.target4);
strunzone (active_way.target5);
strunzone (active_way.target6);
strunzone (active_way.target7);
strunzone (active_way.target8);
remove (active_way);
}
void() creator_way_touch =
{
if (cvar("waypoint_mode"))
{
if (other.classname != "player")
return;
current_way = self;
}
}
void () Create_New_Waypoint =
{
float way_count;
float tempf;
entity tempe;
entity new_way;
string temps;
new_way = spawn();
setorigin(new_way, self.origin);
//new_way.flags = FL_ITEM;
new_way.solid = SOLID_TRIGGER;
setmodel(new_way, "models/way/normal_way.spr");
new_way.classname = "waypoint";
tempe = find (world, classname, "waypoint");
while (tempe)
{
tempf = stof (tempe.waynum);
if (tempf > way_count)
way_count = tempf;
tempe = find (tempe, classname, "waypoint");
}
temps = ftos(way_count + 1);
new_way.waynum = temps;
new_way.waynum = strzone(new_way.waynum);
new_way.targetname = strzone(new_way.targetname);
bprint (PRINT_HIGH, "Created waypoint ");
bprint (PRINT_HIGH, new_way.waynum);
bprint (PRINT_HIGH, "\n");
new_way.touch = creator_way_touch;
}
void () Move_Waypoint =
{
if (!active_way)
return;
setorigin (active_way, self.origin);
bprint(PRINT_HIGH, "Moved waypoint ");
bprint(PRINT_HIGH, active_way.waynum);
bprint(PRINT_HIGH, "\n");
}
void() Dual_Link_Waypoints =
{
if (self.classname != "player")
return;
if (!current_way)
return;
if (!active_way)
return;
if (current_way == active_way)
return;
local float result1,result2;
result1 = progs_Link_Waypoints(current_way,active_way);
result2 = progs_Link_Waypoints(active_way,current_way);
if(result1 == 2 && result2 == 2)
{
bprint(PRINT_HIGH, "Both waypoints already linked!\n");
}
if(result1 == 1)
{
bprint(PRINT_HIGH, " Linked waypoint ");
bprint(PRINT_HIGH, current_way.waynum);
bprint(PRINT_HIGH, " to ");
bprint(PRINT_HIGH, active_way.waynum);
bprint(PRINT_HIGH, "\n");
}
if(result2 == 1)
{
bprint(PRINT_HIGH, " Linked waypoint ");
bprint(PRINT_HIGH, active_way.waynum);
bprint(PRINT_HIGH, " to ");
bprint(PRINT_HIGH, current_way.waynum);
bprint(PRINT_HIGH, "\n");
}
if(result1 == 2 && result2 != 2)//if both are already linked, we only want the simple message above, not detailed one
{
bprint(PRINT_HIGH, " Waypoint ");
bprint(PRINT_HIGH, current_way.waynum);
bprint(PRINT_HIGH, " already linked to ");
bprint(PRINT_HIGH, active_way.waynum);
bprint(PRINT_HIGH, "\n");
}
if(result2 == 2 && result1 != 2)//if both are already linked, we only want the simple message above, not detailed one
{
bprint(PRINT_HIGH, " Waypoint ");
bprint(PRINT_HIGH, active_way.waynum);
bprint(PRINT_HIGH, " already linked to ");
bprint(PRINT_HIGH, current_way.waynum);
bprint(PRINT_HIGH, "\n");
}
if(result1 == -1)
{
bprint(PRINT_HIGH, " Waypoint ");
bprint(PRINT_HIGH, current_way.waynum);
bprint(PRINT_HIGH, " has no open targets remaining\n");
}
if(result2 == -1)
{
bprint(PRINT_HIGH, " Waypoint ");
bprint(PRINT_HIGH, active_way.waynum);
bprint(PRINT_HIGH, " has no open targets remaining!\n");
}
if(result1 == 1 && result2 == 1)
{
bprint(PRINT_HIGH, "Both waypoints linked succesfully!\n");
}
if (current_way.targetname != "")
setmodel(current_way, "models/way/last_way_door.spr");
else
setmodel(current_way, "models/way/last_way.spr");
if (active_way.targetname != "")
setmodel(active_way, "models/way/current_way_door.spr");
else
setmodel(active_way, "models/way/current_way.spr");
}
void () Link_Waypoints =
{
if (self.classname != "player")
return;
if (!current_way)
return;
if (!active_way)
return;
if (current_way == active_way)
return;
if(
active_way.target == current_way.waynum ||
active_way.target2 == current_way.waynum ||
active_way.target3 == current_way.waynum ||
active_way.target4 == current_way.waynum ||
active_way.target5 == current_way.waynum ||
active_way.target6 == current_way.waynum ||
active_way.target7 == current_way.waynum ||
active_way.target8 == current_way.waynum
)
{
bprint(PRINT_HIGH, "These waypoints are already linked!\n");
return;
}
if (active_way.target == "")
{
active_way.target = current_way.waynum;
active_way.target = strzone(active_way.target);
}
else if (active_way.target2 == "")
{
active_way.target2 = current_way.waynum;
active_way.target2 = strzone(active_way.target2);
}
else if (active_way.target3 == "")
{
active_way.target3 = current_way.waynum;
active_way.target3 = strzone(active_way.target3);
}
else if (active_way.target4 == "")
{
active_way.target4 = current_way.waynum;
active_way.target4 = strzone(active_way.target4);
}
else if (active_way.target5 == "")
{
active_way.target5 = current_way.waynum;
active_way.target5 = strzone(active_way.target5);
}
else if (active_way.target6 == "")
{
active_way.target6 = current_way.waynum;
active_way.target6 = strzone(active_way.target6);
}
else if (active_way.target7 == "")
{
active_way.target7 = current_way.waynum;
active_way.target7 = strzone(active_way.target7);
}
else if (active_way.target8)
{
active_way.target8 = current_way.waynum;
active_way.target8 = strzone(active_way.target8);
}
else
{
bprint(PRINT_HIGH, "no targets remaining!\n");
return;
}
bprint(PRINT_HIGH, "Linked waypoint ");
bprint (PRINT_HIGH, current_way.waynum);
bprint(PRINT_HIGH, " to ");
bprint (PRINT_HIGH, active_way.waynum);
bprint(PRINT_HIGH, "\n");
if (current_way.targetname != "")
setmodel(current_way, "models/way/last_way_door.spr");
else
setmodel(current_way, "models/way/last_way.spr");
}
void () Select_Waypoint =
{
if (self.classname != "player")
return;
if (!current_way)
return;
entity tempe;
if (current_way == active_way)
active_way = world;
else
active_way = current_way;
tempe = find (world, classname, "waypoint");
while (tempe)
{
if (tempe.targetname != "")
setmodel(tempe, "models/way/normal_way_door.spr");
else
setmodel(tempe, "models/way/normal_way.spr");
tempe = find (tempe, classname, "waypoint");
}
if (active_way)
{
if (active_way.targetname != "")
setmodel(active_way, "models/way/current_way_door.spr");
else
setmodel(active_way, "models/way/current_way.spr");
bprint(PRINT_HIGH, "Selected waypoint ");
bprint(PRINT_HIGH, active_way.waynum);
if(active_way.targetname != "")
{
bprint(PRINT_HIGH, ", special tag ");
bprint(PRINT_HIGH, active_way.targetname);
}
bprint(PRINT_HIGH, "\n");
if(active_way.target != "")
{
tempe = find (world, waynum, active_way.target);
if (tempe)
{
if (tempe.targetname != "")
setmodel(tempe, "models/way/last_way_door.spr");
else
setmodel(tempe, "models/way/last_way.spr");
bprint(PRINT_HIGH, active_way.target);
bprint(PRINT_HIGH, "\n");
}
else
{
active_way.target = "";
}
}
if(active_way.target2 != "")
{
tempe = find (world, waynum, active_way.target2);
if (tempe)
{
if (tempe.targetname != "")
setmodel(tempe, "models/way/last_way_door.spr");
else
setmodel(tempe, "models/way/last_way.spr");
bprint(PRINT_HIGH, active_way.target2);
bprint(PRINT_HIGH, "\n");
}
else
{
active_way.target2 = "";
}
}
if(active_way.target3 != "")
{
tempe = find (world, waynum, active_way.target3);
if (tempe)
{
if (tempe.targetname != "")
setmodel(tempe, "models/way/last_way_door.spr");
else
setmodel(tempe, "models/way/last_way.spr");
bprint(PRINT_HIGH, tempe.target3);
bprint(PRINT_HIGH, "\n");
}
else
{
active_way.target3 = "";
}
}
if(active_way.target4 != "")
{
tempe = find (world, waynum, active_way.target4);
if (tempe)
{
if (tempe.targetname != "")
setmodel(tempe, "models/way/last_way_door.spr");
else
setmodel(tempe, "models/way/last_way.spr");
bprint(PRINT_HIGH, active_way.target4);
bprint(PRINT_HIGH, "\n");
}
else
{
active_way.target4 = "";
}
}
if(active_way.target5 != "")
{
tempe = find (world, waynum, active_way.target5);
if (tempe)
{
if (tempe.targetname != "")
setmodel(tempe, "models/way/last_way_door.spr");
else
setmodel(tempe, "models/way/last_way.spr");
bprint(PRINT_HIGH, active_way.target5);
bprint(PRINT_HIGH, "\n");
}
else
{
active_way.target5 = "";
}
}
if(active_way.target6 != "")
{
tempe = find (world, waynum, active_way.target6);
if (tempe)
{
if (tempe.targetname != "")
setmodel(tempe, "models/way/last_way_door.spr");
else
setmodel(tempe, "models/way/last_way.spr");
bprint(PRINT_HIGH, "\n");
}
else
{
active_way.target6 = "";
}
}
if(active_way.target7 != "")
{
tempe = find (world, waynum, active_way.target7);
if (tempe)
{
if (tempe.targetname != "")
setmodel(tempe, "models/way/last_way_door.spr");
else
setmodel(tempe, "models/way/last_way.spr");
bprint(PRINT_HIGH, active_way.target7);
bprint(PRINT_HIGH, "\n");
}
else
{
active_way.target7 = "";
}
}
if(active_way.target8 != "")
{
tempe = find (world, waynum, active_way.target8);
if (tempe)
{
if (tempe.targetname != "")
setmodel(tempe, "models/way/last_way_door.spr");
else
setmodel(tempe, "models/way/last_way.spr");
bprint(PRINT_HIGH, active_way.target8);
bprint(PRINT_HIGH, "\n");
}
else
{
active_way.target8 = "";
}
}
}
}
entity() closestDoor =
{
local float bestdist,dist;
bestdist = 10000;
dist = 0;
local entity d,best;
d = find(world,classname,"door_nzp");
while(d)
{
bprint(PRINT_HIGH, "Door! ");
dist = vlen(self.origin - d.pos1);//door origin is world, so use pos1 for start pos
bprint(PRINT_HIGH, ftos(bestdist));
bprint(PRINT_HIGH, ", ");
bprint(PRINT_HIGH, ftos(dist));
bprint(PRINT_HIGH, "\n");
if(dist < bestdist)
{
bestdist = dist;
best = d;
}
bprint(PRINT_HIGH, "\n");
d = find(d,classname,"door_nzp");
}
return best;
}
void () Make_Special_Waypoint =
{
if (self.classname != "player")
return;
if (!active_way)
return;
if (active_way.targetname != "")//Toggling it back off
{
setmodel(active_way, "models/way/current_way.spr");
active_way.targetname = "";
bprint(PRINT_HIGH, "Waypoint ");
bprint(PRINT_HIGH, active_way.waynum);
bprint(PRINT_HIGH, " is no longer a special waypoint\n");
return;
}
if (active_way)
{
strunzone(active_way.targetname);
//local entity nearDoor;
//nearDoor = closestDoor();
if(self.active_door == world)
{
bprint(PRINT_HIGH, "Error: no door selected!\n");
return;
}
if(self.active_door.wayTarget == "")
{
bprint(PRINT_HIGH, "Error: Door has no wayTarget value!\n");
return;
}
setmodel(active_way, "models/way/current_way_door.spr");
active_way.targetname = self.active_door.wayTarget;
//active_way.targetname = ftos(current_special);
//active_way.targetname = strzone(active_way.targetname);
//active_way.targetname = strcat("d", active_way.targetname);
//active_way.targetname = strzone(active_way.targetname);
bprint(PRINT_HIGH, "special waypoint ");
bprint (PRINT_HIGH, active_way.waynum);
bprint(PRINT_HIGH, " named ");
bprint (PRINT_HIGH, active_way.targetname);
bprint(PRINT_HIGH, "\n");
//current_special++;
}
}
void (vector here, float which, string special, string trg, string trg2, string trg3, string trg4, string trg5, string trg6, string trg7, string trg8) Create_Waypoint =
{
entity new_way;
new_way = spawn();
setorigin(new_way, here);
//new_way.flags = FL_ITEM;
new_way.solid = SOLID_TRIGGER;
if (cvar("waypoint_mode"))
setmodel(new_way, "models/way/normal_way.spr");
new_way.classname = "waypoint";
new_way.classname = strzone(new_way.classname);
new_way.waynum = ftos(which);
new_way.waynum = strzone(new_way.waynum);
dprint ("Created waypoint ");
dprint (new_way.waynum);
dprint ("\n");
if (special != "")
{
if (!cvar("waypoint_mode"))
new_way.classname = "waypoint_s";
if (cvar("waypoint_mode"))
setmodel(new_way, "models/way/normal_way_door.spr");
new_way.targetname = special;
new_way.targetname = strzone(new_way.targetname);
dprint ("Special waypoint ");
dprint (new_way.targetname);
dprint ("\n");
//current_special++;
}
if (trg)
{
new_way.target = trg;
new_way.target = strzone(new_way.target);
dprint ("Waypoint target ");
dprint (new_way.target);
dprint ("\n");
}
if (trg2)
{
new_way.target2 = trg2;
new_way.target2 = strzone(new_way.target2);
dprint ("Waypoint target2 ");
dprint (new_way.target2);
dprint ("\n");
}
if (trg3)
{
new_way.target3 = trg3;
new_way.target3 = strzone(new_way.target3);
dprint ("Waypoint target3 ");
dprint (new_way.target3);
dprint ("\n");
}
if (trg4)
{
new_way.target4 = trg4;
new_way.target4 = strzone(new_way.target4);
dprint ("Waypoint target4 ");
dprint (new_way.target4);
dprint ("\n");
}
if (trg5)
{
new_way.target5 = trg5;
new_way.target5 = strzone(new_way.target5);
dprint ("Waypoint target5 ");
dprint (new_way.target5);
dprint ("\n");
}
if (trg6)
{
new_way.target6 = trg6;
new_way.target6 = strzone(new_way.target6);
dprint ("Waypoint target6 ");
dprint (new_way.target6);
dprint ("\n");
}
if (trg7)
{
new_way.target7 = trg7;
new_way.target7 = strzone(new_way.target7);
dprint ("Waypoint target7 ");
dprint (new_way.target7);
dprint ("\n");
}
if (trg8)
{
new_way.target8 = trg8;
new_way.target8 = strzone(new_way.target8);
dprint ("Waypoint target8 ");
dprint (new_way.target8);
dprint ("\n");
}
new_way.touch = creator_way_touch;
}
string tempstest;
void() Save_Waypoints
{
local float file;
string h;
h = strcat(mappath, ".way");
file = fopen (h, FILE_WRITE);
local entity dway;
//fputs(file, "begin\n");
dway = find(world, classname, "waypoint");
while (dway)
{
dprint ("Saving waypoints\n");
fputs(file,"Waypoint\n");
fputs(file,"{\norigin = ");
tempstest = vtos(dway.origin);
tempstest = strzone(tempstest);
fputs(file,tempstest);
strunzone (tempstest);
fputs(file,"\nid = ");
fputs(file,dway.waynum);
fputs(file,"\nspecial = ");
fputs(file,dway.targetname);
fputs(file,"\ntarget = ");
fputs(file,dway.target);
fputs(file,"\ntarget2 = ");
fputs(file,dway.target2);
fputs(file,"\ntarget3 = ");
fputs(file,dway.target3);
fputs(file,"\ntarget4 = ");
fputs(file,dway.target4);
fputs(file,"\ntarget5 = ");
fputs(file,dway.target5);
fputs(file,"\ntarget6 = ");
fputs(file,dway.target6);
fputs(file,"\ntarget7 = ");
fputs(file,dway.target7);
fputs(file,"\ntarget8 = ");
fputs(file,dway.target8);
fputs(file,"\n");
fputs(file,"}\n");
dway = find(dway, classname, "waypoint");
if (dway)
fputs(file,"\n");
}
fclose(file);
}
void() Load_Waypoints
{
float file, which;
string h, special, trg, trg2, trg3, trg4, trg5, trg6, trg7, trg8;
local vector where;
h = strcat(mappath, ".way");
file = fopen (h, FILE_READ);
if (file == -1)
{
dprint("Error: file not found \n");
return;
}
while (1)
{
dprint("Loading waypoint\n");
// the first line is just a comment, ignore it
h = fgets(file);
if (h != "Waypoint")
{
bprint(PRINT_HIGH, "Last waypoint\n");
fclose(file);
return;
}
h = fgets(file);
h = fgets(file);
h = substring(h, 9, 20);
where = stov(h);
h = (fgets(file));
h = substring(h, 5, 20);
which = stof(h);
h = (fgets(file));
special = substring(h, 10, 20);
special = strzone(special);
h = (fgets(file));
trg = substring(h, 9, 20);
trg = strzone(trg);
h = (fgets(file));
trg2 = substring(h, 10, 20);
trg2 = strzone(trg2);
h = (fgets(file));
trg3 = substring(h, 10, 20);
trg3 = strzone(trg3);
h = (fgets(file));
trg4 = substring(h, 10, 20);
trg4 = strzone(trg4);
h = (fgets(file));
trg5 = substring(h, 10, 20);
trg5 = strzone(trg5);
h = (fgets(file));
trg6 = substring(h, 10, 20);
trg6 = strzone(trg6);
h = (fgets(file));
trg7 = substring(h, 10, 20);
trg7 = strzone(trg7);
h = (fgets(file));
trg8 = substring(h, 10, 20);
trg8 = strzone(trg8);
Create_Waypoint(where, which, special, trg, trg2, trg3, trg4, trg5, trg6, trg7, trg8);
strunzone (trg);
strunzone (trg2);
strunzone (trg3);
strunzone (trg4);
strunzone (trg5);
strunzone (trg6);
strunzone (trg7);
strunzone (trg8);
h = (fgets(file));
h = (fgets(file));
}
}

View file

@ -0,0 +1,828 @@
/*
server/ai/pathfind_core.qc
generic waypoints
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
void() creator_way_touch =
{
if (cvar("waypoint_mode")) {
if (other.classname != "player") {
return;
}
current_way = self;
}
}
void () Create_New_Waypoint =
{
float way_count;
float tempf;
entity tempe;
entity new_way;
way_count = -1;
tempe = find (world, classname, "waypoint");
while (tempe) {
tempf = stof(tempe.waynum);
if (tempf > way_count) {
way_count = tempf;
}
tempe = find (tempe, classname, "waypoint");
}
new_way = spawn();
setorigin(new_way, self.origin);
//new_way.flags = FL_ITEM;
new_way.solid = SOLID_TRIGGER;
setmodel(new_way, "models/way/normal_way.spr");
new_way.classname = "waypoint";
new_way.waynum = ftos(way_count + 1);
new_way.targetname = strzone(new_way.targetname);
bprint (PRINT_HIGH, "Created waypoint ");
bprint (PRINT_HIGH, new_way.waynum);
bprint (PRINT_HIGH, "\n");
new_way.touch = creator_way_touch;
}
void () Make_Special_Waypoint =
{
if (self.classname != "player" || !active_way) {
return;
}
if (active_way.targetname != "") {//Toggling it back off
setmodel(active_way, "models/way/current_way.spr");
active_way.targetname = "";
bprint (PRINT_HIGH, "Waypoint ");
bprint (PRINT_HIGH, active_way.waynum);
bprint (PRINT_HIGH, " is no longer a special waypoint\n");
return;
}
if (active_way) {
if(self.active_door == world) {
bprint (PRINT_HIGH, "Error: no door selected!\n");
return;
}
if(self.active_door.wayTarget == "") {
bprint (PRINT_HIGH, "Error: Door has no wayTarget value!\n");
return;
}
setmodel(active_way, "models/way/current_way_door.spr");
active_way.targetname = self.active_door.wayTarget;
bprint (PRINT_HIGH, "special waypoint ");
bprint (PRINT_HIGH, active_way.waynum);
bprint (PRINT_HIGH, " named ");
bprint (PRINT_HIGH, active_way.targetname);
bprint (PRINT_HIGH, "\n");
}
}
void () Move_Waypoint =
{
if (!active_way)
return;
setorigin (active_way, self.origin);
bprint (PRINT_HIGH, "Moved waypoint ");
bprint (PRINT_HIGH, active_way.waynum);
bprint (PRINT_HIGH, "\n");
}
void () Select_Waypoint =
{
if (self.classname != "player")
return;
if (!current_way)
return;
entity tempe;
if (current_way == active_way)
active_way = world;
else
active_way = current_way;
tempe = find (world, classname, "waypoint");
while (tempe)
{
if (tempe.targetname != "")
setmodel(tempe, "models/way/normal_way_door.spr");
else
setmodel(tempe, "models/way/normal_way.spr");
tempe = find (tempe, classname, "waypoint");
}
if (active_way)
{
if (active_way.targetname != "")
setmodel(active_way, "models/way/current_way_door.spr");
else
setmodel(active_way, "models/way/current_way.spr");
bprint (PRINT_HIGH, "Selected waypoint ");
bprint (PRINT_HIGH, active_way.waynum);
if(active_way.targetname != "")
{
bprint (PRINT_HIGH, ", special tag ");
bprint (PRINT_HIGH, active_way.targetname);
}
bprint (PRINT_HIGH, "\n");
float i;
for (i = 0; i < MAX_WAY_TARGETS; i++) {
tempe = find (world, waynum, active_way.targets[i]);
if (tempe) {
if (tempe.targetname != "")
setmodel(tempe, "models/way/last_way_door.spr");
else
setmodel(tempe, "models/way/last_way.spr");
} else {
active_way.targets[i] = "";
}
}
}
}
void() Remove_Waypoint =
{
entity tempe;
float i;
if (!active_way)
return;
tempe = find (world, classname, "waypoint");
while (tempe) {
for (i = 0; i < MAX_WAY_TARGETS; i++) {
if (tempe.targets[i] == active_way.waynum) {
tempe.targets[i] = "";
}
}
tempe = find (tempe, classname, "waypoint");
}
bprint(PRINT_HIGH, "Removed waypoint ");
bprint(PRINT_HIGH, active_way.waynum);
bprint(PRINT_HIGH, "\n");
remove (active_way);
}
float Waypoint_Linked_To(entity from, entity to) {
float i;
for (i = 0; i < MAX_WAY_TARGETS; i++) {
if (from.waynum == to.targets[i]) {
bprint(PRINT_HIGH, "These waypoints are already linked!\n");
return 1;
}
}
return 0;
}
float Link (entity from, entity to) {
float i;
entity tempe;
for (i = 0; i < MAX_WAY_TARGETS; i++) {
tempe = find (world, waynum, from.targets[i]);
if (tempe == world || tempe == to) {
from.targets[i] = to.waynum;
bprint(PRINT_HIGH, "Linked waypoint ");
bprint(PRINT_HIGH, to.waynum);
bprint(PRINT_HIGH, " to ");
bprint(PRINT_HIGH, from.waynum);
bprint(PRINT_HIGH, "\n");
if (to.targetname != "") {
setmodel(to, "models/way/last_way_door.spr");
} else {
setmodel(to, "models/way/last_way.spr");
}
return 1;
}
}
return 0;
}
void () Link_Waypoints =
{
if (self.classname != "player")
return;
if (!current_way)
return;
if (!active_way)
return;
if (current_way == active_way)
return;
if (Waypoint_Linked_To(current_way, active_way)) {
bprint(PRINT_HIGH, "These waypoints are already linked!\n");
return;
}
float i;
entity tempe;
for (i = 0; i < MAX_WAY_TARGETS; i++) {
#ifdef PC
tempe = findfloat (world, waynum, active_way.targets[i]);
#else
tempe = find (world, waynum, active_way.targets[i]);
#endif
if (tempe == world) {
if (Link(active_way, current_way)) {
return;
}
}
}
bprint(PRINT_HIGH, "no targets remaining!\n");
}
void() Dual_Link_Waypoints =
{
if (self.classname != "player" || !current_way || !active_way || current_way == active_way) {
return;
}
float result1,result2;
result1 = Waypoint_Linked_To(current_way,active_way);
result2 = Waypoint_Linked_To(active_way,current_way);
if(result1 && result2) {
bprint(PRINT_HIGH, "Both waypoints already linked!\n");
return;
}
if(!result1)
{
if (Link(current_way,active_way)) {
bprint(PRINT_HIGH, strcat("Linked waypoint ", strcat(current_way.waynum, strcat(" to ",strcat(active_way.waynum, "\n")))));
} else {
bprint(PRINT_HIGH, strcat("ERROR: Could not link waypoint ", strcat(current_way.waynum, strcat(" to ", strcat(active_way.waynum, "\n")))));
}
}
if(!result2)
{
if (Link(active_way,current_way)) {
bprint(PRINT_HIGH, strcat("Linked waypoint ", strcat(active_way.waynum, strcat(" to ", strcat(current_way.waynum, "\n")))));
} else {
bprint(PRINT_HIGH, strcat("ERROR: Could not link waypoint ", strcat(active_way.waynum, strcat(" to ", strcat(current_way.waynum, "\n")))));
}
}
}
//alter auto_link_waypoints to iterate through the closest waypoints from closest to furthest
// on the innermost loop, we find the next closest waypoint that is further away from the last closest waypoint, and we use that!
void() Auto_Link_Waypoints =
{
entity tempe1, tempe2;
tempe1 = find(world,classname,"waypoint");
while(tempe1 != world)
{
tempe2 = find(world,classname,"waypoint");
while(tempe2 != world)
{
if(tempe1 == tempe2)
{
tempe2 = find(tempe2,classname,"waypoint");
continue;
}
if(tracemove(tempe1.origin,VEC_HULL_MIN,VEC_HULL_MAX,tempe2.origin,TRUE,self))
{
Link(tempe1,tempe2);
}
tempe2 = find(tempe2,classname,"waypoint");
}
tempe1 = find(tempe1,classname,"waypoint");
}
}
//alter auto_link_waypoints to iterate through the closest waypoints from closest to furthest
// on the innermost loop, we find the next closest waypoint that is further away from the last closest waypoint, and we use that!
void() Remove_Links =
{
entity tempe;
tempe = find(world,classname,"waypoint");
while(tempe != world)
{
float i;
for (i = 0; i < MAX_WAY_TARGETS; i = i + 1) {
if (tempe.targetname != "")
setmodel(tempe, "models/way/normal_way_door.spr");
else
setmodel(tempe, "models/way/normal_way.spr");
tempe.targets[i] = "";
}
tempe = find(tempe,classname,"waypoint");
}
}
void() Save_Waypoints
{
float file;
string h;
float i;
entity tempe;
h = strcat(mappath, ".way");
file = fopen (h, FILE_WRITE);
dprint (strcat("Saving waypoints ", strcat(h, "\n")));
local entity dway;
//fputs(file, "begin\n");
dway = find(world, classname, "waypoint");
while (dway)
{
fputs(file,"waypoint\n");
fputs(file,"{\n");
fputs(file, strcat(" id: ", strcat(dway.waynum, "\n")));
fputs(file, strcat(" origin: ", strcat(vtos(dway.origin), "\n")));
if (dway.targetname != "") {
fputs(file, strcat(" door: ", strcat(dway.targetname, "\n")));
}
fputs(file, " targets:\n");
fputs(file, " [\n");
for (i = 0; i < MAX_WAY_TARGETS; i++) {
if (dway.targets[i] != "") {
#ifdef PC
tempe = findfloat (world, waynum, dway.targets[i]);
#else
tempe = find (world, waynum, dway.targets[i]);
#endif
if (tempe != world) {
fputs(file, strcat(" ", strcat(dway.targets[i], "\n")));
} else {
tempe = find (world, waynum, dway.targets[i]);
if (tempe != world) {
fputs(file, strcat(" ", strcat(dway.targets[i], "\n")));
}
}
}
}
fputs(file, " ]\n");
fputs(file,"}\n");
dway = find(dway, classname, "waypoint");
if (dway)
fputs(file,"\n");
}
fclose(file);
}
void (vector here, float which, string special, string trg, string trg2, string trg3, string trg4, string trg5, string trg6, string trg7, string trg8) Create_Waypoint =
{
entity new_way;
new_way = spawn();
setorigin(new_way, here);
//new_way.flags = FL_ITEM;
new_way.solid = SOLID_TRIGGER;
if (cvar("waypoint_mode"))
setmodel(new_way, "models/way/normal_way.spr");
new_way.classname = "waypoint";
new_way.waynum = ftos(which);
dprint ("Created waypoint ");
dprint (new_way.waynum);
dprint ("\n");
if (special != "")
{
if (!cvar("waypoint_mode"))
new_way.classname = "waypoint_s";
if (cvar("waypoint_mode"))
setmodel(new_way, "models/way/normal_way_door.spr");
new_way.targetname = special;
dprint ("Special waypoint ");
dprint (new_way.targetname);
dprint ("\n");
//current_special++;
}
new_way.targets[0] = trg;
new_way.targets[1] = trg2;
new_way.targets[2] = trg3;
new_way.targets[3] = trg4;
new_way.targets[4] = trg5;
new_way.targets[5] = trg6;
new_way.targets[6] = trg7;
new_way.targets[7] = trg8;
new_way.touch = creator_way_touch;
}
float waypoints_loaded;
void() Load_Waypoints
{
float file, point;
string h;
float targetcount, loop;
entity new_way;
h = strcat(mappath, ".way");
file = fopen (h, FILE_READ);
if (file == -1)
{
dprint("Error: file not found \n");
return;
}
new_way = spawn();
targetcount = 0;
point = 0;
loop = 1;
while (loop)
{
string line;
line = fgets(file);
if not (line) {
bprint(PRINT_HIGH, "End of file\n");
loop = 0;
break;
}
h = strtrim(line);
//bprint(PRINT_HIGH, strcat(h, "\n"));
if (h == "") {
continue;
}
switch (point) {
case 0:
if (h == "waypoint") {
new_way = spawn();
new_way.solid = SOLID_TRIGGER;
new_way.model = "models/way/normal_way.spr";
setmodel(new_way, "models/way/normal_way.spr");
new_way.classname = "waypoint";
new_way.touch = creator_way_touch;
point = 1;
targetcount = 0;
} else if (h == "Waypoint") {
bprint(PRINT_HIGH, "Identified .way as legacy..\n");
point = 99;
Load_Waypoints_Legacy();
loop = 0;
break;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown point ", strcat(h, "\n")));
}
break;
case 1:
if (h == "{") {
point = 2;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(h, " expected {\n")));
}
break;
case 2:
tokenize(h);
string value, variable;
variable = strtrim(argv(0));
value = strtrim(argv(2));
//bprint(PRINT_HIGH, strcat(variable, "\n"));
switch (variable) {
case "origin":
print(strcat(value, "\n"));
new_way.origin = stov(value);
setorigin(new_way, new_way.origin);
break;
case "id":
new_way.waynum = value;
break;
case "door":
new_way.targetname = value;
setmodel(new_way, "models/way/normal_way_door.spr");
break;
case "targets":
point = 3;
break;
case "}":
point = 0;
break;
default:
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(variable, "\n")));
break;
}
break;
case 3:
if (h == "[") {
point = 4;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(h, " expected [\n")));
}
break;
case 4:
if (targetcount >= MAX_WAY_TARGETS) {
bprint(PRINT_HIGH, "Error: Target count too high for waypoint\n");
} else if (h == "]") {
point = 2;
} else {
bprint(PRINT_HIGH, strcat(strcat("WAYPOINT TARGET: ", strcat(strcat(ftos(targetcount), " "), h)), "\n"));
new_way.targets[targetcount] = h;
targetcount++;
}
break;
}
}
fclose(file);
waypoints_loaded = 1;
}
void() Load_Waypoints_Legacy
{
float file, which;
string h, special, trg, trg2, trg3, trg4, trg5, trg6, trg7, trg8;
local vector where;
h = strcat(mappath, ".way");
file = fopen (h, FILE_READ);
if (file == -1)
{
dprint("Error: file not found \n");
return;
}
while (1)
{
dprint("Loading waypoint\n");
// the first line is just a comment, ignore it
h = fgets(file);
if (h != "Waypoint")
{
bprint(PRINT_HIGH, "Last waypoint\n");
fclose(file);
return;
}
h = fgets(file);
h = fgets(file);
h = substring(h, 9, 20);
where = stov(h);
h = (fgets(file));
h = substring(h, 5, 20);
which = stof(h);
h = (fgets(file));
special = substring(h, 10, 20);
h = (fgets(file));
trg = substring(h, 9, 20);
h = (fgets(file));
trg2 = substring(h, 10, 20);
h = (fgets(file));
trg3 = substring(h, 10, 20);
h = (fgets(file));
trg4 = substring(h, 10, 20);
h = (fgets(file));
trg5 = substring(h, 10, 20);
h = (fgets(file));
trg6 = substring(h, 10, 20);
h = (fgets(file));
trg7 = substring(h, 10, 20);
h = (fgets(file));
trg8 = substring(h, 10, 20);
#ifndef PC
Create_Waypoint(where, which, special, trg, trg2, trg3, trg4, trg5, trg6, trg7, trg8);
#else
waypoint_ai waypoint;
waypoint = waypoints[which];
waypoints[which].id = which;
waypoints[which].org = where;
waypoints[which].targetdoor = special;
waypoints[which].target_id[0] = stof(trg);
waypoints[which].target_id[1] = stof(trg2);
waypoints[which].target_id[2] = stof(trg3);
waypoints[which].target_id[3] = stof(trg4);
waypoints[which].target_id[4] = stof(trg5);
waypoints[which].target_id[5] = stof(trg6);
waypoints[which].target_id[6] = stof(trg7);
waypoints[which].target_id[7] = stof(trg8);
#endif
h = (fgets(file));
h = (fgets(file));
}
}
void VisualizePathfind() {
if (self.classname != "player")
return;
if (!current_way)
return;
if (!active_way)
return;
if (current_way == active_way)
return;
Pathfind(self, stof(active_way.waynum), stof(current_way.waynum));
}
.float waypoint_delay;
//Waypoint logic functions
void () Waypoint_Functions =
{
// naievil -- archaic
/*
switch (self.impulse) {
case 100:
Create_New_Waypoint();
break;
case 101:
Make_Special_Waypoint();
break;
case 102:
Select_Waypoint();
break;
case 103:
Move_Waypoint();
break;
case 104:
Link_Waypoints ();
break;
case 105:
Dual_Link_Waypoints();
break;
case 106:
Save_Waypoints();
break;
case 107:
Load_Waypoints();
break;
case 108:
Load_Waypoints_Legacy();
break;
case 109:
Remove_Waypoint();
//VisualizePathfind();
break;
case 110:
Auto_Link_Waypoints();
break;
case 111:
Remove_Links();
break;
}
self.impulse = 0;
*/
switch (self.impulse) {
case 23:
Save_Waypoints();
break;
case 22:
if (!waypoints_loaded)
Load_Waypoints();
break;
case 110:
Move_Waypoint();
break;
}
self.impulse = 0;
// Match what we display on the screen
if (self.button0 && self.waypoint_delay < time) {
Create_New_Waypoint();
self.waypoint_delay = time + 1;
}
if (self.button7 && self.waypoint_delay < time) {
Select_Waypoint();
self.waypoint_delay = time + 0.25;
}
if (self.button8 && self.waypoint_delay < time) {
Link_Waypoints ();
self.waypoint_delay = time + 0.5;
}
if (self.button6 && self.waypoint_delay < time) {
Remove_Waypoint();
self.waypoint_delay = time + 0.5;
}
if (self.button5 && self.waypoint_delay < time) {
Make_Special_Waypoint();
self.waypoint_delay = time + 1;
}
};
void () Waypoint_Logic =
{
if (!waypoint_mode) {
waypoint_mode = 1;
entity zent;
zent = find (world, classname, "ai_zombie");
while (zent)
{
remove (zent);
zent = find (zent, classname, "ai_zombie");
}
zent = find (world, classname, "door_nzp_cost");
while (zent)
{
zent.solid = SOLID_NOT;
zent.touch = SUB_Null;
zent = find (zent, classname, "door_nzp_cost");
}
zent = find (world, classname, "door_nzp");
while (zent)
{
zent.solid = SOLID_NOT;
zent.touch = SUB_Null;
zent.solid = SOLID_NOT;
zent = find (zent, classname, "door_nzp");
}
zent = find (world, classname, "window");
while (zent)
{
zent.solid = SOLID_NOT;
zent.touch = SUB_Null;
zent = find (zent, classname, "window");
}
}
Waypoint_Functions();
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,542 @@
/*
server/clientfuncs.qc
used to communicate between server and client
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
void SetUpdate(entity client, float type, float val1, float val2, float val3)
{
#ifndef PSP
#ifndef NX
if (type != 2)
{
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_UPDATE);
WriteByte(MSG_MULTICAST, type); // UT_HUD
WriteByte(MSG_MULTICAST, val1);
WriteByte(MSG_MULTICAST, val2);
WriteByte(MSG_MULTICAST, val3); // misc flags/vars for later if needed
msg_entity = client;
multicast('0 0 0', MULTICAST_ONE);
}
else
{
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_UPDATE);
WriteByte(MSG_MULTICAST, type); // UT_ROUNDS_CHANGE
WriteByte(MSG_MULTICAST, val1);
WriteByte(MSG_MULTICAST, val2);
WriteByte(MSG_MULTICAST, val3); // misc flags/vars for later if needed
multicast('0 0 0', MULTICAST_ALL);
}
#endif
#endif
}
#ifndef PSP
#ifndef NX
void(entity to, float type, float cost, float weapon) useprint = {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_USEPRINT);
WriteByte(MSG_MULTICAST, type);
WriteShort(MSG_MULTICAST, cost);
WriteByte(MSG_MULTICAST, weapon);
msg_entity = to;
multicast('0 0 0', MULTICAST_ONE);
}
#endif
#endif
void(vector org) CallExplosion = {
#ifndef PC
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
#else
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_EXPLOSION);
WriteCoord(MSG_MULTICAST, org_x);
WriteCoord(MSG_MULTICAST, org_y);
WriteCoord(MSG_MULTICAST, org_z);
multicast('0 0 0', MULTICAST_ALL);
#endif
}
void NotifyNewRound(float to) {
#ifndef PSP
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_NEWROUND);
WriteByte(MSG_MULTICAST, to);
multicast('0 0 0', MULTICAST_ALL);
#endif
#endif
}
void SetRound(entity client, float to) {
#ifndef PSP
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_SETROUND);
WriteByte(MSG_MULTICAST, to);
msg_entity = client;
multicast('0 0 0', MULTICAST_ONE);
#endif
#endif
}
void SetPerk(entity client, float to)
{
#ifndef PSP
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_PERK);
WriteLong(MSG_MULTICAST, to);
msg_entity = client;
multicast('0 0 0', MULTICAST_ONE);
#endif
#endif
}
void(float to) SwitchWeapon =
{
#ifndef PSP
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_WEAPONCHANGE);
WriteByte(MSG_MULTICAST, to);
msg_entity = self;
multicast('0 0 0', MULTICAST_ONE);
// hotfix for weapon2models not reseting
self.weapon2model = GetWeapon2Model(to);
#endif
#endif
}
void(string to, float skin) UpdateVmodel =
{
#ifndef PSP
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_UPDATEVMODEL);
WriteString(MSG_MULTICAST, to);
WriteByte(MSG_MULTICAST, skin);
msg_entity = self;
multicast('0 0 0', MULTICAST_ONE);
#endif
#endif
}
void(string to, float skin) UpdateV2model =
{
#ifndef PSP
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_UPDATEV2MODEL);
WriteString(MSG_MULTICAST, to);
WriteByte(MSG_MULTICAST, skin);
msg_entity = self;
multicast('0 0 0', MULTICAST_ONE);
#endif
#endif
}
void(float broadcast_time, float type) BroadcastMessage =
{
#ifndef PSP
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_BROADCAST);
WriteByte(MSG_MULTICAST, broadcast_time);
WriteByte(MSG_MULTICAST, type);
multicast('0 0 0', MULTICAST_ALL);
#endif
#endif
}
void(float playernum, float points, float am, float kills, string name, entity person) UpdatePlayerPoints =
{
#ifndef PSP
#ifndef NX
if (player_count == 0) {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_POINTUPDATE);
WriteByte(MSG_MULTICAST, playernum);
WriteLong(MSG_MULTICAST, points);
WriteLong(MSG_MULTICAST, am);
WriteLong(MSG_MULTICAST, kills);
WriteString(MSG_MULTICAST, name);
msg_entity = person;
multicast('0 0 0', MULTICAST_ONE);
}
else {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_POINTUPDATE);
WriteByte(MSG_MULTICAST, playernum);
WriteLong(MSG_MULTICAST, points);
WriteLong(MSG_MULTICAST, am);
WriteLong(MSG_MULTICAST, kills);
WriteString(MSG_MULTICAST, name);
multicast('0 0 0', MULTICAST_ALL);
}
#endif
#endif
}
void(float count) UpdatePlayerCount = {
#ifndef PSP
#ifndef NX
if (count == 0)
return;
else {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_PLAYERUPDATE);
WriteByte(MSG_MULTICAST, count);
multicast('0 0 0', MULTICAST_ALL);
}
#endif
#endif
}
void(float newtime, float newtype, entity change) PromptLevelChange =
{
#ifndef PSP
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_BLACKOUT);
WriteByte(MSG_MULTICAST, newtime);
WriteByte(MSG_MULTICAST, newtype);
msg_entity = change;
multicast('0 0 0', MULTICAST_ONE);
#endif
#endif
}
void(entity who) UpdatePunchangle =
{
// naievil -- shit logic lol...but result looks clean as fuck...
#ifndef PSP
#ifndef NX
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_PUNCHANGLE);
WriteCoord(MSG_MULTICAST, who.punchangle_x);
WriteCoord(MSG_MULTICAST, who.punchangle_y);
WriteCoord(MSG_MULTICAST, who.punchangle_z);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
vector tempv = who.punchangle;
if (fabs(who.punchangle_x) > 0.01) {
if (who.punchangle_x >= 0.05*tempv_x)
who.punchangle_x -= 0.05*tempv_x;
else if (who.punchangle_x <= -0.05*tempv_x)
who.punchangle_x -= 0.05*tempv_x;
else
who.punchangle_x = 0;
} else
who.punchangle_x = 0;
if (fabs(who.punchangle_y) > 0.01) {
if (who.punchangle_y >= 0.05*tempv_y)
who.punchangle_y -= 0.05*tempv_y;
else if (who.punchangle_y <= -0.05*tempv_y)
who.punchangle_y -= 0.05*tempv_y;
else
who.punchangle_y = 0;
} else
who.punchangle_y = 0;
if (fabs(who.punchangle_z) > 0.01) {
if (who.punchangle_z >= 0.05*tempv_z)
who.punchangle_z -= 0.05*tempv_z;
else if (who.punchangle_z <= -0.05*tempv_z)
who.punchangle_z -= 0.05*tempv_z;
else
who.punchangle_z = 0;
} else
who.punchangle_z = 0;
#endif
#endif
}
#ifndef PSP
#ifndef NX
void(string h, float h2, entity who) pushHUD = {
if (player_count == 0) {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_HUDUPDATE);
WriteString(MSG_MULTICAST, h);
WriteByte(MSG_MULTICAST, h2);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
} else {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_WEAPONUPDATE);
WriteString(MSG_MULTICAST, h);
WriteByte(MSG_MULTICAST, h2);
multicast('0 0 0', MULTICAST_ALL);
}
}
void (float wepnum, string wepname, string wvmodel, float mag, float reserve, string ads, float min, float max, string flash, float flashsize, string v2, float isd, entity who) sendCustomWeapon = {
if (player_count == 0) {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_WEAPONUPDATE);
WriteByte(MSG_MULTICAST, wepnum);
WriteString(MSG_MULTICAST, wepname);
WriteString(MSG_MULTICAST, wvmodel);
WriteByte(MSG_MULTICAST, mag);
WriteByte(MSG_MULTICAST, reserve);
WriteString(MSG_MULTICAST, ads);
WriteByte(MSG_MULTICAST, min);
WriteByte(MSG_MULTICAST, max);
WriteString(MSG_MULTICAST, flash);
WriteByte(MSG_MULTICAST, flashsize);
WriteString(MSG_MULTICAST, v2);
WriteByte(MSG_MULTICAST, isd);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
} else {
WriteByte(MSG_ALL, SVC_CGAMEPACKET);
WriteByte(MSG_ALL, EVENT_WEAPONUPDATE);
WriteByte(MSG_ALL, wepnum);
WriteString(MSG_ALL, wepname);
WriteString(MSG_ALL, wvmodel);
WriteByte(MSG_ALL, mag);
WriteByte(MSG_ALL, reserve);
WriteString(MSG_ALL, ads);
WriteByte(MSG_ALL, min);
WriteByte(MSG_ALL, max);
WriteString(MSG_ALL, flash);
WriteByte(MSG_ALL, flashsize);
WriteString(MSG_ALL, v2);
WriteByte(MSG_ALL, isd);
}
}
void(string msg, entity who) ScrollText = {
if (player_count == 0) {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_SCROLLTEXT);
WriteString(MSG_MULTICAST, msg);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
} else {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_SCROLLTEXT);
WriteString(MSG_MULTICAST, msg);
multicast('0 0 0', MULTICAST_ALL);
}
}
void(string chaptertitle, string location, string date, string person, entity who) WorldText = {
if (player_count == 0) {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_WORLDDATA);
WriteString(MSG_MULTICAST, chaptertitle);
WriteString(MSG_MULTICAST, location);
WriteString(MSG_MULTICAST, date);
WriteString(MSG_MULTICAST, person);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
} else {
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_WORLDDATA);
WriteString(MSG_MULTICAST, chaptertitle);
WriteString(MSG_MULTICAST, location);
WriteString(MSG_MULTICAST, date);
WriteString(MSG_MULTICAST, person);
multicast('0 0 0', MULTICAST_ALL);
}
}
#endif
#endif
#ifndef NX
void (float achievement_id, optional entity who) GiveAchievement =
{
#ifdef PSP
// temp
if (achievement_id > 4)
return;
#endif // PSP
// this is an achievement specific to an individual
if ((who && who != world) || player_count == 0) {
if (player_count == 0) who = find(world, classname, "player");
#ifdef PSP
achievement(who, achievement_id);
#else
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_ACHIEVEMENT);
WriteByte(MSG_MULTICAST, achievement_id);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
#endif // PSP
} else {
#ifdef PSP
entity players;
players = find(world, classname, "player");
while(players != world) {
achievement(players, achievement_id);
players = find(players, classname, "player");
}
#else
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_ACHIEVEMENT);
WriteByte(MSG_MULTICAST, achievement_id);
multicast('0 0 0', MULTICAST_ALL);
#endif // PSP
}
}
void (float achievement_id, float progress_value, optional entity who) UpdateAchievementProgress =
{
#ifdef PSP
// temp
if (achievement_id > 4)
return;
#endif // PSP
// this is a progress update specific to an individual
if ((who && who != world) || player_count == 0) {
if (player_count == 0) who = find(world, classname, "player");
#ifdef PSP
//achievement_progress(who, achievement_id, progress_value);
#else
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_ACHIEVEMENTPROGRESS);
WriteByte(MSG_MULTICAST, achievement_id);
WriteFloat(MSG_MULTICAST, progress_value);
msg_entity = who;
multicast('0 0 0', MULTICAST_ONE);
#endif // PSP
} else {
#ifdef PSP
entity players;
players = find(world, classname, "player");
while(players != world) {
//achievement_progress(players, achievement_id, progress_value);
players = find(players, classname, "player");
}
#else
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EVENT_ACHIEVEMENTPROGRESS);
WriteByte(MSG_MULTICAST, achievement_id);
WriteFloat(MSG_MULTICAST, progress_value);
multicast('0 0 0', MULTICAST_ALL);
#endif // PSP
}
}
#endif // NX
// *****************************************
// Unrelated to engine, but custom functions
// *****************************************
float(entity who, entity target) isFacing =
{
float who_angle = who.angles_y;
float target_angle = target.angles_y;
float difference_angle = target_angle - who_angle;
#ifdef PSP
if (difference_angle < -45) {
difference_angle += 360;
}
#endif
// 180 = directly facing each other, 30 degree buffer.
if (difference_angle <= 210 && difference_angle >= 150)
return true;
return false;
}
float() crandom =
{
return 2*(random() - 0.5);
}
void WeaponSwitch(entity player) {
float wep, cmag, cmag2, cammo;
wep = other.weapon;
other.weapon = other.secondaryweapon;
other.secondaryweapon = wep;
cmag = other.currentmag;
other.currentmag = other.secondarymag;
other.secondarymag = cmag;
cmag2 = other.currentmag2;
other.currentmag2 = other.secondarymag2;
other.secondarymag2 = cmag2;
cammo = other.currentammo;
other.currentammo = other.secondaryammo;
other.secondaryammo = cammo;
entity tempe = self;
self = player;
SwitchWeapon(other.weapon);
self = tempe;
}
void(entity person, float expamt, float doublepoint) addmoney =
{
if (person.classname != "player" || person.downed)
return;
if (expamt > 0 && doublepoint == TRUE && x2_finished > time) {
expamt *= 2;
person.score += expamt;
}
person.points += expamt;
UpdatePlayerPoints(person.playernum, person.points, expamt, person.kills, person.netname, person);
};

570
source/server/damage.qc Normal file
View file

@ -0,0 +1,570 @@
/*
server/clientfuncs.qc
used for any sort of down, hit, etc that the player or entity
experiences
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifndef NX
void (float achievement_id, optional entity who) GiveAchievement;
#endif // NX
void() EndGame_Restart =
{
localcmd("restart");
}
// Fade to black function, creates another think for restart
void() EndGame_FadePrompt =
{
PromptLevelChange(time + 6, 2, self);
#ifdef PC
self.think = EndGame_Restart;
#else
self.think = Soft_Restart;
#endif
self.nextthink = time + 5;
}
//Actual endgame function, all zombies die, music plays
void() EndGame =
{
local entity oldself;
local entity who;
self.health = 0;
self.origin = '0 0 0';
setorigin (self, self.origin);
self.velocity = '0 0 0';
sound (self, CHAN_AUTO, "sounds/music/end.wav", 1, ATTN_NORM);
oldself = self;
who = find(world,classname,"ai_zombie");
while(who != world)
{
if(who.health)
{
self = who;
self.th_die();
self = oldself;
}
who = find(who,classname,"ai_zombie");
}
self.think = EndGame_FadePrompt;
self.nextthink = time + 33;
}
// removes revive icon from downed player heads, used as a recursive think function
void() remove_revive =
{
if (self.owner.beingrevived)
setmodel (self, "models/sprites/revive_white.spr");
else
setmodel (self, "models/sprites/revive.spr");
if (!self.owner.downed || self.owner.isspec)
SUB_Remove ();
else {
self.think = remove_revive;
self.nextthink = time + 0.1;
}
}
// when dead and other players exist and are alive, throw user into spectate mode
void() startspectate =
{
if (!self.downed)
return;
if (self.beingrevived)
{
self.think = startspectate;
self.nextthink = time + 0.1;
return;
}
self.downedloop = 0;
self.beingrevived = false;
self.model = "";
setmodel(self, self.model);
self.health = 100;
self.weaponmodel = "";
self.weapon2model = "";
self.downed = 0;
self.frame = 0;
UpdateVmodel(self.weaponmodel, GetWepSkin(self.weapon));
UpdateV2model(self.weapon2model, GetWepSkin(self.weapon));
SpectatorSpawn();
}
// searches for players that are alive given which clients have which playernumbers
// Returns 1 if there IS someone in the world that's not downed
float() PollPlayersAlive =
{
float i, gotalive;
entity playerent;
gotalive = 0;
for (i = 1; i <= 4; i++)
{
playerent = findfloat(world, playernum, i);
if (playerent) {
if (!playerent.downed && !playerent.isspec) {
gotalive = 1;
break;
}
}
}
return gotalive;
}
// Endgamesetup -- think function for setting up the death of everyone
void() EndGameSetup =
{
game_over = true;
self.health = 10;
self.think = EndGame;
self.nextthink = time + 5;
self.weapon = 0;
self.currentammo = 0;
self.currentmag = 0;
self.weaponmodel = "";
self.weapon2model = "";
self.animend = SUB_Null;
self.perks = 0;
self.isspec = true;
SetPerk(self, self.perks);
SwitchWeapon(0);
addmoney(self, -self.points, 0);
addmoney(self, self.score, 0);
return;
}
// rec_downed is used as a recursive loop where we consistently check to see if ALL players are downed
// if they aren't dead, we keep looping until our OWN death (45 seconds, so 450 loops)
void() rec_downed =
{
self.downedloop++;
if (self.downedloop == 450) {
startspectate();
return;
}
float gotalive = PollPlayersAlive();
if (!gotalive && !self.progress_bar) {
EndGameSetup();
return;
}
self.think = rec_downed;
self.nextthink = time + 0.1;
}
void() GetDown =
{
float startframe;
float endframe;
local string modelname;
if (rounds <= 1 && self.currentmag == 0 && self.currentmag2 == 0 && self.currentammo == 0 && self.secondarymag == 0 &&
self.secondarymag2 == 0 && self.secondaryammo == 0) {
GiveAchievement(9, self);
}
playdown();
switch(self.stance) {
case 2:
self.new_ofs_z = self.view_ofs_z - 42;
self.stance = 0;
break;
case 1:
self.new_ofs_z = self.view_ofs_z - 24;
self.stance = 0;
break;
default: break;
}
// remove third weapon
self.thirdweapon = 0;
self.velocity = '-80 0 -80'; // Stop any old movement
self.zoom = 0;
self.downed = true;
self.dive_delay = 0;
self.movetype = MOVETYPE_NONE;
float gotalive = PollPlayersAlive();
if ((coop && !gotalive) || (!coop && !(self.perks & P_REVIVE))) {
EndGameSetup();
return;
} else {
self.health = 19;
}
if ((self.perks & P_REVIVE) && !coop) {
self.progress_bar = 10 + time;
self.progress_bar_time = 10;
self.progress_bar_percent = 1;
self.downed = true;
}
self.points = 10*rint((self.points*0.95)/10);
addmoney(self, 0, true); // used to call a broadcast
BroadcastMessage(time + 3, 2);
self.perks = 0;
self.weaponbk = self.weapon;
self.currentammobk = self.currentammo;
self.currentmagbk = self.currentmag;
self.currentmagbk2 = self.currentmag2;
if (self.weapon == W_BIATCH || self.secondaryweapon == W_BIATCH || self.progress_bar_percent > 0) {
self.weapon = W_BIATCH;
self.currentammo = 12;
self.currentmag = 6;
self.currentmag2 = 6;
} else {
self.weapon = W_COLT;
self.currentammo = 16;
self.currentmag = 8;
}
modelname = GetWeaponModel(self.weapon, 0);
self.weaponmodel = modelname;
SwitchWeapon(self.weapon);
startframe = GetFrame(self.weapon,TAKE_OUT_START);
endframe = GetFrame(self.weapon,TAKE_OUT_END);
Set_W_Frame (startframe, endframe, 0, 0, 0, SUB_Null, modelname, false, S_BOTH);
local entity revive;
revive = spawn ();
revive.owner = self;
revive.movetype = MOVETYPE_NONE;
revive.solid = SOLID_NOT;
revive.think = remove_revive;
revive.nextthink = time + 0.1;
setmodel (revive, "models/sprites/revive.spr");
revive.origin = self.origin + VEC_VIEW_OFS;
setorigin (revive, revive.origin);
SetPerk(self, 0);
self.think = rec_downed;
self.nextthink = time + 0.1;
}
void () GetUp =
{
local string modelname;
float startframe;
float endframe;
playgetup(); // animation
self.new_ofs_z = self.view_ofs_z + 42;
self.stance = 2;
self.health = 100;
self.downedloop = 0; // used for death timing vs endgame
self.downed = 0;
self.classname = "player";
if (self.weaponbk)
{
self.weapon = self.weaponbk;
self.currentammo = self.currentammobk;
self.currentmag = self.currentmagbk;
self.currentmag2 = self.currentmagbk2;
}
modelname = GetWeaponModel(self.weapon, 0);
self.weaponmodel = modelname;
SwitchWeapon(self.weapon);
self.weapon2model = GetWeapon2Model(self.weapon);
self.movetype = MOVETYPE_WALK;
startframe = GetFrame(self.weapon,TAKE_OUT_START);
endframe = GetFrame(self.weapon,TAKE_OUT_END);
Set_W_Frame (startframe, endframe, 0, 0, 0, SUB_Null, modelname, false, S_BOTH);
};
// poll checking whether to see if our revive invoke is active
void(entity ent) CheckRevive =
{
if (self.invoke_revive) {
GetUp();
self.invoke_revive = 0;
}
}
void(entity attacker, float d_style) DieHandler =
{
float t;
t = random();
if (self.classname == "ai_zombie" || self.classname == "ai_dog") {
self.th_die();
}
if (attacker.classname == "player") {
attacker.kills++;
if (d_style == S_HEADSHOT) {
addmoney(attacker, 100, true);
total_powerup_points = total_powerup_points + 100;
attacker.headshots++;
} else if (d_style == S_NORMAL) {
addmoney(attacker, 60, true);
total_powerup_points = total_powerup_points + 60;
}
else if (d_style == S_KNIFE){
addmoney(attacker, 130, true);
total_powerup_points = total_powerup_points + 130;
} else if (d_style == S_TESLA) {
addmoney(attacker, 50, true);
total_powerup_points = total_powerup_points + 50;
}
}
}
void(entity victim,entity attacker, float damage, float d_style) DamageHandler = {
// don't do any attacking during nuke delay
if (d_style == S_ZOMBIE && nuke_powerup_active > time)
return;
// Abstinence Program
victim.ach_tracker_abst = 1;
entity old_self;
if (victim.classname == "ai_zombie" || victim.classname == "ai_dog") {
if (attacker.classname == "player" && (victim.health - damage)> 0) {
addmoney(attacker, 10, 1);
}
victim.health = victim.health - damage;
if (d_style == S_EXPLOSIVE) {
if (victim.health < z_health*0.5)
{
if (victim.crawling != TRUE && !(victim.health <= 0) && crawler_num < 5 && victim.classname != "ai_dog")
{
makeCrawler(victim);
#ifndef NX
GiveAchievement(3, attacker);
#endif
}
else
{
if (attacker.classname == "player" && (victim.health - damage) > 0)
addmoney(attacker, 10, 1);
}
}
// MOTO - explosives seem to work fine without, but with will cause counter and QC errors..
//else
// victim.th_die();
if (victim.health <= 0)
addmoney(attacker, 60, 1);
}
if (victim.health <= 0 || instakill_finished) {
old_self = self;
self = victim;
DieHandler(attacker, d_style);
self = old_self;
}
} else if (victim.classname == "player" && !victim.downed) {
if (victim.flags & FL_GODMODE) {
return;
}
if (victim.perks & P_JUG)
damage = ceil(damage*0.5);
victim.health = victim.health - damage;
victim.health_delay = time + 2;
// shake the camera on impact
local vector distance;
distance = attacker.angles - victim.angles;
// just to prevent radical punchangles
while(distance_x > 10 || distance_x < -10) {
distance_x /= 2;
}
while(distance_y > 10 || distance_y < -10) {
distance_y /= 2;
}
// apply
victim.punchangle_x = distance_x;
victim.punchangle_y = distance_y;
// play hurt sound
sound (self, CHAN_AUTO, "sounds/player/pain4.wav", 1, ATTN_NORM);
if (victim.health <= 20)
{
old_self = self;
self = victim;
GetDown();
self = old_self;
}
}
}
/*
============
CanDamage
Returns true if the inflictor can directly damage the target. Used for
explosions and melee attacks.
============
*/
float(entity targ, entity inflictor) CanDamage =
{
if (targ.flags == FL_GODMODE)
return FALSE;
// bmodels need special checking because their origin is 0,0,0
if (targ.movetype == MOVETYPE_PUSH)
{
traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self);
if (trace_fraction == 1)
return TRUE;
if (trace_ent == targ)
return TRUE;
return FALSE;
}
traceline(inflictor.origin, targ.origin, TRUE, self);
if (trace_fraction == 1)
return TRUE;
traceline(inflictor.origin, targ.origin + '15 15 0', TRUE, self);
if (trace_fraction == 1)
return TRUE;
traceline(inflictor.origin, targ.origin + '-15 -15 0', TRUE, self);
if (trace_fraction == 1)
return TRUE;
traceline(inflictor.origin, targ.origin + '-15 15 0', TRUE, self);
if (trace_fraction == 1)
return TRUE;
traceline(inflictor.origin, targ.origin + '15 -15 0', TRUE, self);
if (trace_fraction == 1)
return TRUE;
return FALSE;
};
void(entity inflictor, entity attacker, float damage2, float mindamage, float radius) DamgageExplode =
{
float final_damage;
entity ent;
float multi, r;
ent = findradius(inflictor.origin, radius);
while (ent != world)
{
if(ent.classname == "player")
{
if (ent.perks & P_FLOP)
final_damage = 0;
else
{
final_damage = radius - vlen(inflictor.origin - ent.origin);
if(final_damage < 0)
continue;
if (final_damage > radius * 0.6)
final_damage = 100;
if (final_damage < other.health)
{
addmoney(self, 10, 0);
}
else if (final_damage > other.health)
{
addmoney(self, 60, 0);
}
else
{
final_damage /= radius;
final_damage *= 60;
}
DamageHandler (attacker, attacker, final_damage, S_EXPLOSIVE);
}
}
else if (ent.takedamage && ent.classname != "ai_zombie_head" && ent.classname != "ai_zombie_larm" && ent.classname != "ai_zombie_rarm")
{
// verify we aren't doin anything with a bmodel
if (ent.solid == SOLID_BSP || ent.movetype == MOVETYPE_PUSH)
return;
if (mapname == "ndu" && ent.classname == "ai_zombie" && inflictor.classname == "explosive_barrel") {
ach_tracker_barr++;
if (ach_tracker_barr >= 15) {
GiveAchievement(13);
}
}
r = rounds;
multi = 1.07;
while(r > 0)
{
multi *= 1.05;
r --;
}
if (mindamage == 75)
final_damage = (200 * multi) + 185;
else
final_damage = (mindamage + damage2)/2;
if (final_damage > 0)
{
/* ndaekill = true; */
if (CanDamage (ent, inflictor))
DamageHandler (ent, attacker, final_damage, S_EXPLOSIVE);
/* kill = false; */
}
}
ent = ent.chain;
}
};

View file

@ -0,0 +1,501 @@
/*
server/defs/custom.qc
put custom server-only globals and fields here
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifndef PSP
#ifndef NX
#pragma target FTE
#endif
#endif
#define true 1
#define false 0
#define FL_JUMPRELEASED 4096
// achievement tracking
.float ach_tracker_npnp;
.float ach_tracker_abst;
float ach_tracker_spin;
float ach_tracker_luck;
.float ach_tracker_coll;
float ach_tracker_col2;
float ach_tracker_barr;
float framecount;
float deathmatch;
float coop;
.vector oldvelocity;
.float lastsound_time;
.float isspec;
string mappath;
.float playernum;
.float ads_toggle;
float player_count;
entity pl1;
.string fog; // used for hacking in changing fog from world.fog for legacy maps
entity local_client;
.float stance;
.float stancereset;
.float changestance;
.vector new_ofs;
//money
.float points;
.float cost;
.float cost2;
void(entity person, float expamt , float doublepoint) addmoney;
//stats
.float score;
.float kills;
.float headshots;
#ifdef PC
.float facingenemy;
#endif
//doors
.float state;
#define STATE_TOP 0
#define STATE_BOTTOM 1
#define STATE_UP 2
#define STATE_DOWN 3
.float /*worldtype,*/ delay, wait, lip, /*light_lev,*/ speed, style/*, skill*/;
entity activator;
.float requirespower;
//player funcs
#ifdef PC
.float zoom;
#endif
float sprint_max_time = 4.0;
.float sprinting;
.float weaponskin;
.float secondaryweaponskin;
.float thirdweaponskin;
.float stamina;
.float sprint_timer;
.float sprint_duration;
.float sprint_timer_stopped;
.float sprint_start_time;
.float sprint_stop_time;
.float sprint_rest_time;
void() W_SprintStop;
.float into_sprint;
.float dive;
.float dive_delay;
.float damagetimer;
.vector movement;
//Weaponsystem defines
void SwitchWeapon(float to);
void GetUp();
void Weapon_Logic();
.float downed;
.float fire_delay;
.float fire_delay2;
.float reload_delay;
.float reload_delay2;
.float switch_delay;
.float health_delay;
.float progress_bar;
.float progress_bar_time;
.float progress_bar_percent;
.float weaponbk;
.float currentmag;
.float currentmag2;
.float currentmagbk;
.float currentmagbk2;
.float currentammobk;
.float secondaryammo;
.float thirdammo;
.float semi;
.float semi2;
.float semiuse;
.float semiswitch;
.float semireload;
.float secondarymag;
.float secondarymag2;
.float secondaryweapon;
.float thirdmag;
.float thirdmag2;
.float thirdweapon;
.float NeedLoad;
.string weapon2model;
.float weapon2frame;
.float reloadinterupted;
.float hitcount;
.float weaponnum; // 0 for weapon one, 1 for second weapon...we invert value for easy comparison, a third gun would need to be hardwired
//Reviving
.float invoke_revive;
.float reviving;
.float revived;
.float beingrevived;
.float downedloop;
#define S_LEFT 0
#define S_RIGHT 1
#define S_BOTH 2
//Knife
.float semiknife;
.float knife_delay;
.float bowie;
//Grenades
.float grenades;
.float pri_grenade_state;
.float bk_nade;
.float grenade_delay;
.float secondary_grenades;
.float primary_grenades;
.float throw_delay;
//weapon frames
void Set_W_Frame (float startframe, float endframe, float duration, float funccalledin, float animtype, void(optional float t) endanimfunc, string set_model, float dontstartnew, float side);
.float weapon_animduration;
.float weapon2_animduration;
.float weapon_anim_type;
.float weapon2_anim_type;
.float anim_weapon_time;
.float anim_weapon2_time;
.float weaponframe_end;
.float weapon2frame_end;
.float callfuncat;
.float callfuncat2;
.float new_anim_stop;
.float new_anim2_stop;
.float anim_reversed;
.float anim2_reversed;
.void() animend;
.void(optional float t) animend2;
//Null functions
void() SUB_Null = {};
void() SUB_Null2 = {};
#define VEC_HULL_MIN '-16 -16 -32'
#define VEC_HULL_MAX '16 16 40'
#define VEC_HULL2_MIN '-32 -32 -24'
#define VEC_HULL2_MAX '32 32 64'
#define VEC_VIEW_OFS '0 0 32'
#ifdef PSP
#define MAX_ZOMB 12
#else
#define MAX_ZOMB 24
#endif
vector trace_plane_normal;
// AI definitions
//Used for global one-zombie-at-a-time type ai
void Do_Zombie_AI();
.string aistatus;
entity lastzombie;
float zombie_spawn_delay; // time before spawning, in seconds.
float zombie_spawn_timer; // the actual timer for spawn delay
//Other AI definitions
.vector box1, box2, box3;//used for windows and zombies
.vector idlebox;
.vector hop_spot;//used for windows (zombies hop to these)
.vector goalorigin;
.float teslacount;
.float iszomb;
.float onfire;
.entity firer;
float crawler_num;
//==== Reference Vars ====
#define WWINDOW 1
#define WBOX1 2
#define WBOX2 4
#define WBOX3 8
#define WIDLEBOX 16
//========================
//we're using usedent for who is currently hopping the window
//Used for windows to keep track of what zombies are at windows
.entity box1owner, box2owner, box3owner;
.entity usedent;
//.float used;//used for the window boxes//not anymore
.float outside;//used for knowing if a zomibe has hopped window yet
.float chase_enemy_time;
.float chase_time;
.float enemy_timeout;
//.float pathing;
.float calc_time; //used as a delay thing (so zombie ai doesn't run 100% of the time
.string target2;
.string target3;
.string target4;
.string target5;
.string target6;
.string target7;
.string target8;
.string wayTarget;
.entity active_door;//Set in waypoint mode
.string targetname;//the name of an entitys
entity lastspawn;//last spawn point used by spawning code
.entity goaldummy; //Used to store the origin of the zombies target
.float goalway; //Used to store the origin of the zombies target
.float walktype;//decides animations and moving speeds for zombies
.void() th_walk;
//.void() th_run;
.void() th_die;
.void() th_melee;
.void() th_idle;
.void() th_windowhop;
.void() th_diewunder;
.void() th_fall;
.void() th_falling;
.void() th_land;
.void() th_jump;
.void() th_grabledge;
.float tries;
.float hop_step;//KEEPS TRACK OF WHERE WE ARE ON THE HOPPING PART
float INACTIVE = 1;
float tracemove(vector start, vector min, vector max, vector end, float nomonsters, entity forent);
.float way_path[40];
.float way_cur;
.float sound_time;
.float s_time;
float sounds_playing;
.float fall;
//.vector lastOrg;//Zombie's last origin, for checking stuckness
//.float OrgStuckCount;
.float crawling;
.float washit;
.float hitamount;
.float laststep;
void(entity who) makeCrawler;
.float state;//used to delay making a crawler, ex) when zombie is rising from ground or climbing over barrier, turn zombie into a crawler afterwards
void() spawnAllZombEnts;
void() set_z_health;
float() spawn_a_zombieA;
float gotdog;
float dogRound;
float dogWave;
float z_health;
.float bleedingtime;
.float time_to_die;
float crandom();
// Door
.string killtarget;
.void() think1;
.vector finaldest;
.vector pos1, pos2/*, mangle*/;
.vector finalangle;
.float distance;
.float sequence;
.entity active_door;
.string door_model_target;
.string door_model_name;
//Perk and Power system
float isPowerOn;
.float isBuying; // naievil -- used for checking if a perk is being consumed, limits glitching
.float perks;
.float perk_delay;
.float revivesoda;
.float collected;
.float boxstatus;
.entity boxweapon;
.float spins;
.float papState;
float BoxWeapons[25];
entity boxLocations[32];
float boxCount;
vector boxOrigin;
#ifndef PSP
//powerups
.float x2_icon;
.float insta_icon;
#endif
.string powerup_vo;
float instakill_finished;
float insta_blink;
float x2_finished;
float x2_blink;
float total_windows_down;
float total_powerup_points;
float powerup_activate;
float nuke_powerup_active;
float nuke_powerups_activated;
float nuke_powerup_spawndelay;
//rounds
float roundinit;
float roundtype;
float Current_Zombies;
float Total_Zombies;
float Remaining_Zombies;
float Delay_Time;
float spawn_time;
float round_changetime;
float game_over;
float blink_return;
float delay_at_round;
float spawn_delay;
float maxreward;
float totalreward;
float totalpowerups;
float sounds_playing;
float rounds;
float rounds_change;
//Waypoints
void () Waypoint_Logic;
entity current_way;
float waypoint_mode;
entity active_way;
#define MAX_WAY_TARGETS 10
.string waynum;
.string targets[MAX_WAY_TARGETS];
//pathfinds
#define MAX_WAYPOINTS 256 //max waypoints
void LoadWaypointData();
typedef struct
{
vector org;
float id;
float g, f;
float next, prev;
float step;
float target_id [MAX_WAY_TARGETS]; // Targets array number
string targetdoor; //special tag is required for the closed waypoints
float dist [MAX_WAY_TARGETS]; // Distance to the next waypoints
float set;
} waypoint_ai;
#define SET_NONE 0
#define SET_OPEN 1
#define SET_CLOSED 2
#ifdef PC
waypoint_ai waypoints[MAX_WAYPOINTS];
// fog
string world_fog;
// lights
#define EF_PURPLELIGHT 256 // fte already has some effect styles defined...
#endif
#define UT_HUD 1
#define UT_ROUNDS_CHANGE 2
#define UT_HM 3
#define UT_ZOOM2 4
#define UT_CROSSHAIR 5
//Misc patch definitions
.string teddyremovetarget;
.float oldz; // used for fall damage that does not truly work correctly
.float sprint_delay;
//soft restart stuff for doors
.string oldmodel;
.vector oldorigin;
.float oldstate;
.float state;
.float isopen;
//world
.string chaptertitle;
.string location;
.string date;
.string person;
.string song;
//altered game elements
float G_STARTPOINTS;
float G_STARTROUND;
float G_PRONEPOINTS;
float G_STARTWEAPON[3];
float G_WORLDTEXT;
float G_PERKS;
float G_PERKPOWER;
//song easter egg
float sndTriggerCnt;
float sndActivCnt;
.float activated;
//teleporter
.entity tele_target;
.float mode;
.float cooldown;
.float isLinked;
.float waitLink;
.float tpTimer;
.float isTimed;
.entity host;
// GIBBING
#ifdef PC
.entity larm;
.entity rarm;
.entity head;
.vector bbmins, bbmaxs;
.float currentHitBoxSetup;
#endif
// PC Fog force
.float PC_fog;
// hl stuff
#ifdef PC
.float rendermode;
.float renderamt;
.vector rendercolor;
#endif

1667
source/server/defs/fte.qc Normal file

File diff suppressed because it is too large Load diff

666
source/server/defs/nx.qc Normal file
View file

@ -0,0 +1,666 @@
/*
defs.qc
global definitions
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
/*
==============================================================================
SOURCE FOR GLOBALVARS_T C STRUCTURE
==============================================================================
*/
#define NX
//
// system globals
//
entity self;
entity other;
entity world;
float time;
float frametime;
float force_retouch;
string mapname;
float deathmatch;
float coop;
float teamplay;
float serverflags;
float rounds;
float rounds_change;
float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16;
vector v_forward, v_up, v_right;
float trace_allsolid;
float trace_startsolid;
float trace_fraction;
vector trace_endpos;
vector trace_plane_normal;
float trace_plane_dist;
entity trace_ent;
float trace_inopen;
float trace_inwater;
entity msg_entity; // destination of single entity writes
void() main; // only for testing
void() StartFrame;
void() EndFrame;
void() PlayerPreThink;
void() PlayerPostThink;
void() ClientKill;
void() ClientConnect;
void() PutClientInServer;
void() ClientDisconnect;
void() SetNewParms;
void() SetChangeParms;
void end_sys_globals;
.float modelindex;
.vector absmin, absmax;
.float ltime;
.float movetype;
.float solid;
.vector origin;
.vector oldorigin;
.vector velocity;
.vector angles;
.vector avelocity;
.vector punchangle;
.string classname;
.string model;
.float frame;
.float skin;
.float effects;
.vector mins, maxs;
.vector size;
.void() touch;
.void() use;
.void() think;
.void() blocked;
.float nextthink;
.entity groundentity;
.float health;
.float points;
.float kills;
.float weapon;
.string weaponmodel;
.string weapon2model;
.float weaponframe;
.float weapon2frame;
.float currentammo;
.float currentmag;
.float zoom;
.float weaponskin;
.float weapon2skin;
.float primary_grenades;
.float secondary_grenades;
.float grenades;
.float perks;
.float takedamage;
.entity chain;
.float deadflag;
.vector view_ofs;
.float button0;
.float button1;
.float button2;
.float button3;
.float button4;
.float button5;
.float button6;
.float button7;
.float button8;
.float impulse;
.float fixangle;
.vector v_angle;
.float idealpitch; // Naievil -- new
.string netname;
.entity enemy;
.float flags;
.float colormap;
.float team;
.float max_health;
.float teleport_time;
.float armortype;
.float armorvalue;
.float waterlevel;
.float watertype;
.float ideal_yaw;
.float yaw_speed;
.entity aiment;
.entity head;
.entity larm;
.entity rarm;
.entity goalentity;
.float spawnflags;
.string target;
.string targetname;
.float dmg_take;
.float dmg_save;
.float progress_bar;
.entity dmg_inflictor;
.entity owner;
.vector movedir;
.string message;
.float sounds;
.string noise, noise1, noise2, noise3;
.float x2_icon;
.float insta_icon;
.string Weapon_Name_Touch;
.vector ADS_Offset;
.vector Flash_Offset;
.float Flash_Size;
.float currentmag2;
.float maxspeed;
.float renderGrayscale;
void end_sys_fields;
/*
==============================================================================
VARS NOT REFERENCED BY C CODE
==============================================================================
*/
//
// constants
//
float FALSE = 0;
float TRUE = 1;
// edict.flags
float FL_FLY = 1;
float FL_SWIM = 2;
float FL_CLIENT = 8; // set for all client edicts
float FL_INWATER = 16; // for enter / leave water splash
float FL_MONSTER = 32;
float FL_GODMODE = 64; // player cheat
float FL_NOTARGET = 128; // player cheat
float FL_ITEM = 256; // extra wide size for bonus items
float FL_ONGROUND = 512; // standing on something
float FL_PARTIALGROUND = 1024; // not all corners are valid
float FL_WATERJUMP = 2048; // player jumping out of water
float FL_JUMPRELEASED = 4096; // for jump debouncing
// edict.movetype values
float MOVETYPE_NONE = 0; // never moves
//float MOVETYPE_ANGLENOCLIP = 1;
//float MOVETYPE_ANGLECLIP = 2;
float MOVETYPE_WALK = 3; // players only
float MOVETYPE_STEP = 4; // discrete, not real time unless fall
float MOVETYPE_FLY = 5;
float MOVETYPE_TOSS = 6; // gravity
float MOVETYPE_PUSH = 7; // no clip to world, push and crush
float MOVETYPE_NOCLIP = 8;
float MOVETYPE_FLYMISSILE = 9; // fly with extra size against monsters
float MOVETYPE_BOUNCE = 10;
float MOVETYPE_BOUNCEMISSILE = 11; // bounce with extra size
// edict.solid values
float SOLID_NOT = 0; // no interaction with other objects
float SOLID_TRIGGER = 1; // touch on edge, but not blocking
float SOLID_BBOX = 2; // touch on edge, block
float SOLID_SLIDEBOX = 3; // touch on edge, but not an onground
float SOLID_BSP = 4; // bsp clip, touch on edge, block
float DEAD_NO = 0;
float DEAD_DYING = 1;
float DEAD_DEAD = 2;
float DEAD_RESPAWNABLE = 3;
// takedamage values
float DAMAGE_NO = 0;
float DAMAGE_YES = 1;
float DAMAGE_AIM = 2;
// point content values
float CONTENT_EMPTY = -1;
float CONTENT_SOLID = -2;
float CONTENT_WATER = -3;
float CONTENT_SLIME = -4;
float CONTENT_LAVA = -5;
float CONTENT_SKY = -6;
float STATE_TOP = 0;
float STATE_BOTTOM = 1;
float STATE_UP = 2;
float STATE_DOWN = 3;
vector VEC_ORIGIN = '0 0 0';
// protocol bytes
float SVC_TEMPENTITY = 23;
float SVC_KILLEDMONSTER = 27;
float SVC_FOUNDSECRET = 28;
float SVC_INTERMISSION = 30;
float SVC_FINALE = 31;
float SVC_CDTRACK = 32;
float SVC_SELLSCREEN = 33;
float SVC_SMALLKICK = 34;
float SVC_BIGKICK = 35;
float SVC_MUZZLEFLASH = 39;
// sound channels
// channel 0 never willingly overrides
// other channels (1-7) allways override a playing sound on that channel
float CHAN_AUTO = 0;
float CHAN_WEAPON = 1;
float CHAN_VOICE = 2;
float CHAN_ITEM = 3;
float CHAN_BODY = 4;
float CHAN_NO_PHS_ADD = 8; // ie: CHAN_BODY+CHAN_NO_PHS_ADD
float ATTN_NONE = 0;
float ATTN_NORM = 1;
float ATTN_IDLE = 2;
float ATTN_STATIC = 3;
// entity effects
#define EF_BLUE 1
#define EF_MUZZLEFLASH 2
#define EF_BRIGHTLIGHT 4
#define EF_RED 8
#define EF_ORANGELIGHT 16
#define EF_GREEN 32
#define EF_LIGHT 64
#define EF_NODRAW 128
#define EF_BRIGHTFIELD 256
#define EF_FULLBRIGHT 512
#define EF_DARKLIGHT 1024
#define EF_DARKFIELD 2048
#define EF_PURPLELIGHT 4096
#define EF_RAYRED 8196
#define EF_RAYGREEN 16384
// messages
float MSG_BROADCAST = 0; // unreliable to all
float MSG_ONE = 1; // reliable to one (msg_entity)
float MSG_ALL = 2; // reliable to all
float MSG_INIT = 3; // write to the init string
float MSG_MULTICAST = 4; // for multicast() call
// message levels
float PRINT_LOW = 0; // pickup messages
float PRINT_MEDIUM = 1; // death messages
float PRINT_HIGH = 2; // critical messages
float PRINT_CHAT = 3; // also goes to chat console
// multicast sets
float MULTICAST_ALL = 0; // every client
float MULTICAST_PHS = 1; // within hearing
float MULTICAST_PVS = 2; // within sight
float MULTICAST_ALL_R = 3; // every client, reliable
float MULTICAST_PHS_R = 4; // within hearing, reliable
float MULTICAST_PVS_R = 5; // within sight, reliable
//================================================
//
// globals
//
string string_null; // null string, nothing should be held here
entity activator; // the entity that activated a trigger or brush
float framecount;
//
// cvars checked each frame
//
float teamplay;
float deathmatch;
//================================================
//
// world fields (FIXME: make globals)
//
.string wad;
.string map;
.float worldtype; // 0=medieval 1=metal 2=base
//================================================
.string killtarget;
//
// quakeed fields
//
.float light_lev; // not used by game, but parsed by light util
.float style;
//
// monster ai
//
.void() th_stand;
.void() th_walk;
.void() th_run;
.void() th_missile;
.void() th_melee;
.void(entity attacker, float damage) th_pain;
.void() th_die;
.entity oldenemy; // mad at this player before taking damage
.float speed;
.float lefty;
.float search_time;
.float attack_state;
float AS_STRAIGHT = 1;
float AS_SLIDING = 2;
float AS_MELEE = 3;
float AS_MISSILE = 4;
//
// player only fields
//
.float voided;
.float walkframe;
// Zoid Additions
.float gravity; // Gravity Multiplier (0 to 1.0)
.float attack_finished;
.float pain_finished;
.float invincible_finished;
.float invisible_finished;
.float super_damage_finished;
.float radsuit_finished;
.float invincible_time, invincible_sound;
.float invisible_time, invisible_sound;
.float super_time, super_sound;
.float rad_time;
.float fly_sound;
.float axhitme;
.float show_hostile; // set to time+0.2 whenever a client fires a
// weapon or takes damage. Used to alert
// monsters that otherwise would let the player go
.float jump_flag; // player jump flag
.float swim_flag; // player swimming sound flag
.float air_finished; // when time > air_finished, start drowning
.float bubble_count; // keeps track of the number of bubbles
.string deathtype; // keeps track of how the player died
//
// object stuff
//
.string mdl;
.vector mangle; // angle at start
.vector oldorigin; // only used by secret door
.float t_length, t_width;
//
// doors, etc
//
.vector dest, dest1, dest2;
.float wait; // time from firing to restarting
.float delay; // time from activation to firing
.entity trigger_field; // door's trigger entity
.string noise4;
//
// monsters
//
.float pausetime;
.entity movetarget;
//
// doors
//
.float aflag;
.float dmg; // damage done by door when hit
//
// misc
//
.float cnt; // misc flag
//
// subs
//
.void() think1;
.vector finaldest, finalangle;
//
// triggers
//
.float count; // for counting triggers
//
// plats / doors / buttons
//
.float lip;
.float state;
.vector pos1, pos2; // top and bottom positions
.float height;
//
// sounds
//
.float waitmin, waitmax;
.float distance;
.float volume;
.float sprintflag;
//
// builtin functions
//
void(vector ang) makevectors = #1; // sets v_forward, etc globals
void(entity e, vector o) setorigin = #2;
void(entity e, string m) setmodel = #3; // set movetype and solid first
void(entity e, vector min, vector max) setsize = #4;
void() break = #6;
float() random = #7; // returns 0 - 1
void(entity e, float chan, string samp, float vol, float atten) sound = #8;
vector(vector v) normalize = #9;
void(string e) error = #10;
void(string e) objerror = #11;
float(vector v) vlen = #12;
float(vector v) vectoyaw = #13;
entity() spawn = #14;
void(entity e) remove = #15;
void(vector v1, vector v2, float nomonsters, entity forent) traceline = #16;
entity() checkclient = #17; // returns a client to look for
entity(entity start, .string fld, string match) find = #18;
string(string s) precache_sound = #19;
string(string s) precache_model = #20;
void(entity client, string s)stuffcmd = #21;
entity(vector org, float rad) findradius = #22;
void(float level, string s) bprint = #23;
void(entity client, float level, string s) sprint = #24;
void(string s) dprint = #25;
string(float f) ftos = #26;
string(vector v) vtos = #27;
void() coredump = #28; // prints all edicts
void() traceon = #29; // turns statment trace on
void() traceoff = #30;
void(entity e) eprint = #31; // prints an entire edict
float(float yaw, float dist) walkmove = #32; // returns TRUE or FALSE
float(entity zombie, float which, entity limb) updateLimb = #33;
float(float yaw, float dist) droptofloor = #34; // TRUE if landed on floor
void(float style, string value) lightstyle = #35;
float(float v) rint = #36; // round to nearest int
float(float v) floor = #37; // largest integer <= v
float(float v) ceil = #38; // smallest integer >= v
float(entity e) checkbottom = #40; // true if self is on ground
float(vector v) pointcontents = #41; // returns a CONTENT_*
float(float f) fabs = #43;
vector(entity e, float speed) aim = #44; // returns the shooting vector
float(string s) cvar = #45; // return cvar.value
void(string s) localcmd = #46; // put string into local que
entity(entity e) nextent = #47; // for looping through all ents
void() ChangeYaw = #49; // turn towards self.ideal_yaw
vector(vector v) vectoangles = #51;
void(float to, float f) WriteByte = #52;
void(float to, float f) WriteChar = #53;
void(float to, float f) WriteShort = #54;
void(float to, float f) WriteLong = #55;
void(float to, float f) WriteCoord = #56;
void(float to, float f) WriteAngle = #57;
void(float to, string s) WriteString = #58;
void(float to, entity s) WriteEntity = #59;
void(float step) movetogoal = #67;
string(string s) precache_file = #68; // no effect except for -copy
void(entity e) makestatic = #69;
void(string s) changelevel = #70;
void(string var, string val) cvar_set = #72; // sets cvar.value
void(entity client, string s) centerprint = #73; // sprint, but in middle
void(vector pos, string samp, float vol, float atten) ambientsound = #74;
string(string s) precache_model2 = #75; // registered version only
string(string s) precache_sound2 = #76; // registered version only
string(string s) precache_file2 = #77; // registered version only
void(entity e) setspawnparms = #78; // set parm1... to the
void(entity killer, entity killee) logfrag = #79; // add to stats
string(entity e, string key) infokey = #80; // get a key value (world = serverinfo)
float(string s) stof = #81; // convert string to float
void(vector where, float set) multicast = #82;
vector(entity what) Get_Waypoint_Near = #83;
float(entity zombie, entity target) Do_Pathfind_psp = #84;
void(string s) Open_Waypoint = #85;
vector(entity zombie,vector start,vector min, vector max) Get_Next_Waypoint = #86;
void(entity client, float type, float cost, float weapon) useprint = #87;
vector(entity zombie,vector start,vector min, vector max) Get_First_Waypoint = #88;
entity (entity start, .float field, float match) findfloat = #98;
// New NZP custom ones
float(string filename, float mode) fopen = #110;
void(float fhandle) fclose = #111;
string(float fhandle) fgets = #112;
void(float fhandle, string s) fputs = #113;
float(string s) strlen = #114;
string(string s1, string s2) strcat = #115;
string(string s, float start, float length) substring = #116;
vector(string s) stov = #117;
string(string s) strzone = #118;
string(string s) strunzone = #119;
string(string s) strtrim = #120;
float(string s) tokenize = #130; // Was #441
string(float num) argv = #131; // Was #442
float(entity targ, entity inflictor) CanDamage;
#define FILE_READ 0
#define FILE_APPEND 1
#define FILE_WRITE 2
#define SVC_WEAPONFIRE 35
#define SVC_HITMARK 36
#define SVC_LIMBUPDATE 51 // naievil -- keep me
#define SVC_BSPDECAL 50 // naievil -- keep me
#define SVC_ACHIEVEMENT 52
#define VEC_ORIGIN '0 0 0'
//Standard Quake View Offset
//vector VEC_VIEW_OFS = '0 0 22';
//Half Life View Offset is 64
//64 units above ground, for our purposes it's, 64 - (how low bounding box goes)
vector VEC_VIEW_OFS = '0 0 32';
//Standard Quake Hull
//vector VEC_HULL_MIN = '-16 -16 -24';
//vector VEC_HULL_MAX = '16 16 32';
//Half Life 1 Hull Sizes ADDED BY BLUBS, COMMENTED ORIGINAL QUAKE BBOX SIZS OUT
#define VEC_HULL_MIN '-16 -16 -32'
#define VEC_HULL_MAX '16 16 40'
#define VEC_HULL2_MIN '-32 -32 -24'
#define VEC_HULL2_MAX '32 32 64'
.string fog;
//string world_fog;
.float button3;
.float button4;
.float button5;
.float button6;
.float button7;
.float button8;
.float x2_icon; // double points icon
.float insta_icon;
.vector Flash_Offset;
.float Flash_Size;
.string Weapon_Name;
.float currentHitBoxSetup;
.vector bbmins, bbmaxs; // Used for zombie hitboxes
.entity head;
.entity larm;
.entity rarm;
#define SOLID_CORPSE 5 // bsp clip, touch on edge, block
#define TE_EXPLOSION 3
#define TE_GUNSHOT 2
entity windows[32];
float wincnt;
.float recoil_delay;
float pow(float base, float n) = {
float temp = base;
if (n == 0) {
return 1;
} else {
while (n > 0) {
temp = temp * base;
n = n - 1;
}
return temp;
}
return 0;
};
void enableGrayscale(void) = {
self.renderGrayscale = 1;
}
void disableGrayscale(void) = {
self.renderGrayscale = 0;
}

541
source/server/defs/psp.qc Normal file
View file

@ -0,0 +1,541 @@
/*
+----+
|Defs|
+----+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
| Scratch Http://www.admdev.com/scratch |
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
| This contains necessary definitions from the original V1.06 defs.qc file. |
| This includes some basic constants, the built in function definitions, and |
| some variable's used by the Quake Engine internally. |
| Certain lines in this file are hardcoded into Quake engine, and -must- be |
| present and unchanged, in the order they are shown. Otherwise Quake will |
| refuse to run. |
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
*/
#define PSP
// These lines CANNOT be altered/moved
entity self;
entity other;
entity world;
float time;
float frametime;
float force_retouch; // force all entities to touch triggers
string mapname;
float deathmatch;
float coop;
float teamplay;
float serverflags; // propagated from level to level, used to
float rounds;
float rounds_change;
float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16;
vector v_forward, v_up, v_right; // set by makevectors()
float trace_allsolid;
float trace_startsolid;
float trace_fraction;
vector trace_endpos;
vector trace_plane_normal;
float trace_plane_dist;
entity trace_ent;
float trace_inopen;
float trace_inwater;
entity msg_entity; // destination of single entity writes
void() main; // only for testing
void() StartFrame;
void() EndFrame;
void() PlayerPreThink;
void() PlayerPostThink;
void() ClientKill;
void() ClientConnect;
void() PutClientInServer; // call after setting the parm1... parms
void() ClientDisconnect;
void() SetNewParms; // called when a client first connects to
void() SetChangeParms; // call to set parms for self so they can
void() ParseClientCommand; // special command calls
string CMD_STRING;
void() Soft_Restart;
void end_sys_globals; // flag for structure dumping
.float modelindex; // *** model index in the precached list
.vector absmin, absmax; // *** origin + mins / maxs
.float ltime; // local time for entity
.float movetype;
.float solid;
.vector origin; // ***
.vector oldorigin; // ***
.vector velocity;
.vector angles;
.vector avelocity;
.vector punchangle; // temp angle adjust from damage or recoil
.string classname; // spawn function
.string model;
.float frame;
.float skin;
.float iframetime;
.float effects;
.vector mins, maxs; // bounding box extents reletive to origin
.vector size; // maxs - mins
.void() touch;
.void() use;
.void() think;
.void() blocked; // for doors or plats, called when can't push other
.float nextthink;
.entity groundentity;
.float health;
.float points;
.float kills;
.float weapon; // one of the W_COLT, etc flags
.string weaponmodel;
.string weapon2model;
.float weaponframe;
.float weapon2frame;
.float currentammo;
.float currentmag;
.float zoom;
.float weaponskin;
.float weapon2skin;
.float primary_grenades;
.float secondary_grenades;
.float grenades;
.float perks; // bit flags
.float takedamage;
.entity chain;
.float deadflag;
.vector view_ofs; // add to origin to get eye point
.float button0; //
.float button1; //
.float button2; //
.float button3; //
.float button4; //
.float button5; //
.float button6; //
.float button7; //
.float button8; //
.float impulse; // weapon changes
.float fixangle;
.vector v_angle; // view / targeting angle for players
.float idealpitch; // calculated pitch angle for lookup up slopes
.string netname;
.entity enemy;
.float flags;
.float colormap;
.float team;
.float max_health; // players maximum health is stored here
.float teleport_time; // don't back up
.float waterlevel; // 0 = not in, 1 = feet, 2 = wast, 3 = eyes
.float watertype; // a contents value
.float ideal_yaw;
.float yaw_speed;
.entity aiment;
.entity head;
.entity larm;
.entity rarm;
.entity goalentity; // a movetarget or an enemy
//.entity goalorigin; // a movetarget location
.float spawnflags;
.string target;
.string targetname;
.float bleed_out;
.float progress_bar;
.entity dmg_inflictor;
.entity owner; // who launched a missile
.vector movedir; // mostly for doors, but also used for waterjump
.string message; // trigger messages
.float sounds; // either a cd track number or sound number
.string noise, noise1, noise2, noise3; // contains names of wavs to play
.float x2_icon; // double points icon
.float insta_icon;
.vector ADS_Offset;
.vector Flash_Offset;
.float Flash_Size;
.string Weapon_Name;
.string Weapon_Name_Touch;
.float currentmag2;
.float maxspeed;
.float facingenemy;
void end_sys_fields; // flag for structure dumping
// End. Lines below this MAY be altered, to some extent
// Built In functions
void(vector ang) makevectors = #1; // sets v_forward, etc globals
void(entity e, vector o) setorigin = #2;
void(entity e, string m) setmodel = #3; // set movetype and solid first
void(entity e, vector min, vector max) setsize = #4;
void() break = #6;
float() random = #7; // returns 0 - 1
void(entity e, float chan, string samp, float vol, float atten) sound = #8;
vector(vector v) normalize = #9;
void(string e) error = #10;
void(string e) objerror = #11;
float(vector v) vlen = #12;
float(vector v) vectoyaw = #13;
entity() spawn = #14;
void(entity e) remove = #15;
void(vector v1, vector v2, float nomonsters, entity forent) traceline = #16;
entity() checkclient = #17; // returns a client to look for
entity(entity start, .string fld, string match) find = #18;
string(string s) precache_sound = #19;
string(string s) precache_model = #20;
void(entity client, string s)stuffcmd = #21;
entity(vector org, float rad) findradius = #22;
void(string s) dprint = #25;
string(float f) ftos = #26;
string(vector v) vtos = #27;
void() coredump = #28; // prints all edicts
void() traceon = #29; // turns statment trace on
void() traceoff = #30;
void(entity e) eprint = #31; // prints an entire edict
float(float yaw, float dist) walkmove = #32; // returns TRUE or FALSE
float(entity zombie, float which, entity limb) updateLimb = #33;
float(float yaw, float dist) droptofloor = #34; // TRUE if landed on floor
void(float style, string value) lightstyle = #35;
float(float v) rint = #36; // round to nearest int
float(float v) floor = #37; // largest integer <= v
float(float v) ceil = #38; // smallest integer >= v
float(entity e) checkbottom = #40; // true if self is on ground
float(vector v) pointcontents = #41; // returns a CONTENT_*
float(float f) fabs = #43;
vector(entity e, float speed) aim = #44; // returns the shooting vector
float(string s) cvar = #45; // return cvar.value
void(string s) localcmd = #46; // put string into local que
entity(entity e) nextent = #47; // for looping through all ents
void() ChangeYaw = #49; // turn towards self.ideal_yaw
float(string name) getSoundLen = #50;
vector(vector v) vectoangles = #51;
void(float to, float f) WriteByte = #52;
void(float to, float f) WriteChar = #53;
void(float to, float f) WriteShort = #54;
void(float to, float f) WriteLong = #55;
void(float to, float f) WriteCoord = #56;
void(float to, float f) WriteAngle = #57;
void(float to, string s) WriteString = #58;
void(float to, entity s) WriteEntity = #59;
string(entity s) etos = #65;
void(float step) movetogoal = #67;
string(string s) precache_file = #68; // no effect except for -copy
void(entity e) makestatic = #69;
void(string s) changelevel = #70;
void(float step, vector origin) movetoorigin = #71;
void(string var, string val) cvar_set = #72; // sets cvar.value
void(entity client, string s) centerprint = #73; // sprint, but in middle
void(entity client, string s, string s) centerprint2 = #73;
void(entity client, string s, string s, string s) centerprint3 = #73;
void(entity client, string s, string s, string s, string s) centerprint4 = #73;
void(entity client, string s, string s, string s, string s, string s) centerprint5 = #73;
void(entity client, string s, string s, string s, string s, string s, string s) centerprint6 = #73;
void(entity client, string s, string s, string s, string s, string s, string s, string s) centerprint7 = #73;
void(vector pos, string samp, float vol, float atten) ambientsound = #74;
string(string s) precache_model2 = #75; // registered version only
string(string s) precache_sound2 = #76; // registered version only
string(string s) precache_file2 = #77; // registered version only
void(entity e) setspawnparms = #78; // set parm1... to the
void(vector start, vector min, vector max, vector end, float nomonsters, entity forent) tracebox = #90;
float(vector start, vector min, vector max, vector end, float nomonsters, entity forent) tracemove = #99;
entity (entity start, .float field, float match) findfloat = #98;
float(string s) stof = #81; // 2001-09-20 QuakeC string manipulation by FrikaC
vector(entity what) Get_Waypoint_Near = #83;
float(entity zombie, entity target) Do_Pathfind_psp = #84;
void(string s) Open_Waypoint = #85;
vector(entity zombie,vector start,vector min, vector max) Get_Next_Waypoint = #86;
void(entity client, float type, float cost, float weapon) useprint = #87;
vector(entity zombie,vector start,vector min, vector max) Get_First_Waypoint = #88;
void(string s) Close_Waypoint = #89;
void(entity plr, float achievement) achievement = #79;
void(string trackname) songegg = #500;
void() nzp_maxammo = #501;
/*
type 0 = clear
type 1 = buy door
type 2 = buy debris
type 3 = Buy ammo
type 4 = buy weapon
type 5 = repair window
type 6 = use box
type 7 = use trap
type 8 = require power
*/
// 2001-09-20 QuakeC file access by FrikaC start
float(string filename, float mode) fopen = #110;
void(float fhandle) fclose = #111;
string(float fhandle) fgets = #112;
void(float fhandle, string s) fputs = #113;
// 2001-09-20 QuakeC file access by FrikaC end
// 2001-09-20 QuakeC string manipulation by FrikaC start
float(string s) strlen = #114;
string(string s1, string s2) strcat = #115;
string(string s, float start, float length) substring = #116;
vector(string s) stov = #117;
string(string s) strzone = #118;
string(string s) strunzone = #119;
string(string s) strtrim = #120;
// 2001-09-20 QuakeC string manipulation by FrikaC end
// 2001-11-15 DarkPlaces general builtin functions by Lord Havoc start
float(string s) tokenize = #441;
string(float num) argv = #442;
// 2001-11-15 DarkPlaces general builtin functions by Lord Havoc end
//
// constants
//
#define FALSE 0
#define TRUE 1
// edict.flags
#define FL_FLY 1
#define FL_SWIM 2
#define FL_CLIENT 8 // set for all client edicts
#define FL_INWATER 16 // for enter / leave water splash
#define FL_MONSTER 32
#define FL_GODMODE 64 // player cheat
#define FL_NOTARGET 128 // player cheat
#define FL_ITEM 256 // extra wide size for bonus items
#define FL_ONGROUND 512 // standing on something
#define FL_PARTIALGROUND 1024 // not all corners are valid
#define FL_WATERJUMP 2048 // player jumping out of water
//#define FL_JUMPRELEASED 4096 // for jump debouncing
// edict.movetype values
#define MOVETYPE_NONE 0 // never moves
#define MOVETYPE_ANGLENOCLIP 1
#define MOVETYPE_ANGLECLIP 2
#define MOVETYPE_WALK 3 // players only
#define MOVETYPE_STEP 4 // discrete, not real time unless fall
#define MOVETYPE_FLY 5
#define MOVETYPE_TOSS 6 // gravity
#define MOVETYPE_PUSH 7 // no clip to world, push and crush
#define MOVETYPE_NOCLIP 8
#define MOVETYPE_FLYMISSILE 9 // fly with extra size against monsters
#define MOVETYPE_BOUNCE 10
#define MOVETYPE_BOUNCEMISSILE 11 // bounce with extra size
#define MOVETYPE_FOLLOW 12
// edict.solid values
#define SOLID_NOT 0 // no interaction with other objects
#define SOLID_TRIGGER 1 // touch on edge, but not blocking
#define SOLID_BBOX 2 // touch on edge, block
#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground
#define SOLID_BSP 4 // bsp clip, touch on edge, block
#define SOLID_CORPSE 5 // bsp clip, touch on edge, block
// range values
#define RANGE_MELEE 0
#define RANGE_NEAR 1
#define RANGE_MID 2
#define RANGE_FAR 3
// deadflag values
#define DEAD_NO 0
#define DEAD_DYING 1
#define DEAD_DEAD 2
#define DEAD_RESPAWNABLE 3
// takedamage values
#define DAMAGE_NO 0
#define DAMAGE_YES 1
#define DAMAGE_AIM 2
#define DAMAGE_NOMARKER 3
/*.void() th_stand;
.void() th_walk;
.void() th_run;
.void(entity attacker, float damage) th_pain;*/
.void() th_die;
//.void() th_missile;
.void() th_melee;
// point content values
#define CONTENT_EMPTY -1
#define CONTENT_SOLID -2
#define CONTENT_WATER -3
#define CONTENT_SLIME -4
#define CONTENT_LAVA -5
#define CONTENT_SKY -6
#define VEC_ORIGIN '0 0 0'
//Standard Quake View Offset
//vector VEC_VIEW_OFS = '0 0 22';
//Half Life View Offset is 64
//64 units above ground, for our purposes it's, 64 - (how low bounding box goes)
//vector VEC_VIEW_OFS = '0 0 32';
//Standard Quake Hull
//vector VEC_HULL_MIN = '-16 -16 -24';
//vector VEC_HULL_MAX = '16 16 32';
//Half Life 1 Hull Sizes ADDED BY BLUBS, COMMENTED ORIGINAL QUAKE BBOX SIZS OUT
#define VEC_HULL_MIN '-16 -16 -32'
#define VEC_HULL_MAX '16 16 40'
#define VEC_HULL2_MIN '-32 -32 -24'
#define VEC_HULL2_MAX '32 32 64'
// protocol bytes
#define SVC_BAD 0
#define SVC_NOP 1
#define SVC_DISCONNECT 2
#define SVC_UPDATESTAT 3
#define SVC_VERSION 4
#define SVC_SETVIEW 5
#define SVC_SOUND 6
#define SVC_TIME 7
#define SVC_PRINT 8
#define SVC_STUFFTEXT 9
#define SVC_SETANGLE 10
#define SVC_SERVERINFO 11
#define SVC_LIGHTSTYLE 12
#define SVC_UPDATENAME 13
#define SVC_UPDATEPOINTS 14
#define SVC_CLIENTDATA 15
#define SVC_STOPSOUND 16
#define SVC_PARTICLE 18
#define SVC_DAMAGE 19
#define SVC_SPAWNSTATIC 20
#define SVC_SPAWNBINARY 21
#define SVC_SPAWNBASELINE 22
#define SVC_TEMPENTITY 23
#define SVC_SETPAUSE 24
#define SVC_SIGNONNUM 25
#define SVC_CENTERPRINT 26
#define SVC_SPAWNSTATICSOUND 29 // 1998-08-08 Complete SVC list by Zhenga
#define SVC_INTERMISSION 30
#define SVC_FINALE 31
#define SVC_CDTRACK 32
#define SVC_SELLSCREEN 33
#define SVC_CUTSCENE 34 // 1998-08-08 Complete SVC list by Zhenga
#define SVC_WEAPONFIRE 35
#define SVC_HITMARK 36
#define SVC_USEPRINT 38
#define TE_SPIKE 0
#define TE_SUPERSPIKE 1
#define TE_GUNSHOT 2
#define TE_EXPLOSION 3
#define TE_TAREXPLOSION 4
#define TE_LIGHTNING1 5
#define TE_LIGHTNING2 6
#define TE_WIZSPIKE 7
#define TE_KNIGHTSPIKE 8
#define TE_LIGHTNING3 9
#define TE_LAVASPLASH 10
#define TE_TELEPORT 11
#define TE_RAYSPLASHGREEN 14
#define TE_RAYSPLASHRED 15
// sound channels
// channel 0 never willingly overrides
// other channels (1-7) allways override a playing sound on that channel
#define CHAN_AUTO 0
#define CHAN_WEAPON 1
#define CHAN_VOICE 2
#define CHAN_ITEM 3
#define CHAN_BODY 4
//Player uses channel 5 for all weapon reload sfx
#define ATTN_NONE 0
#define ATTN_NORM 1
#define ATTN_IDLE 2
#define ATTN_STATIC 3
// update types
#define UPDATE_GENERAL 0
#define UPDATE_STATIC 1
#define UPDATE_BINARY 2
#define UPDATE_TEMP 3
// entity effects
#define EF_BLUE 1
#define EF_MUZZLEFLASH 2
#define EF_BRIGHTLIGHT 4
#define EF_RED 8
#define EF_ORANGELIGHT 16
#define EF_GREEN 32
#define EF_LIGHT 64
#define EF_NODRAW 128
#define EF_BRIGHTFIELD 256
#define EF_FULLBRIGHT 512
#define EF_DARKLIGHT 1024
#define EF_DARKFIELD 2048
#define EF_PURPLELIGHT 4096
#define EF_RAYRED 8196
#define EF_RAYGREEN 16384
// messages
#define MSG_BROADCAST 0 // unreliable to all
#define MSG_ONE 1 // reliable to one (msg_entity)
#define MSG_ALL 2 // reliable to all
#define MSG_INIT 3 // write to the init string
#define AS_STRAIGHT 1
#define AS_SLIDING 2
#define AS_MELEE 3
#define AS_MISSILE 4
// Quake assumes these are defined.
//.string wad, map;
.float /*worldtype,*/ delay, wait, lip, /*light_lev,*/ speed, style/*, skill*/;
.string killtarget;
.void() think1;
.vector finaldest;
.vector pos1, pos2/*, mangle*/;
void(vector o, vector d, float color, float count) particle = #48;// start a particle effect
void(string s) bprint_psp = #23;
void(entity client, string s) sprint_psp = #24;
// End
void(string s) println = {bprint_psp(s);} //just when brain decided to think this is c
void(float ignore, string s) bprint = {bprint_psp(s);};
void(entity client, float type, string s) sprint = {sprint_psp(client, s);};
void(string s) print = {bprint_psp(s);};
//doors
.float state;
#define STATE_TOP 0
#define STATE_BOTTOM 1
#define STATE_UP 2
#define STATE_DOWN 3
string mappath;
#define PRINT_HIGH 0
.float isspec;
#define FILE_READ 0
#define FILE_APPEND 1
#define FILE_WRITE 2
#define MOVE_HITMODEL 0 // must be different for this engine!
.float recoil_delay;
.float gravity;
.float renderamt;
.float rendermode;
.vector rendercolor;
.string mapversion;
.float ammo;
void(string com) SV_ParseClientCommand;
.float currentHitBoxSetup;
.vector bbmins, bbmaxs; // Used for zombie hitboxes
.float achievements;

668
source/server/defs/vita.qc Normal file
View file

@ -0,0 +1,668 @@
/*
defs.qc
global definitions
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
/*
==============================================================================
SOURCE FOR GLOBALVARS_T C STRUCTURE
==============================================================================
*/
#define NX
#define VITA
//
// system globals
//
entity self;
entity other;
entity world;
float time;
float frametime;
float force_retouch;
string mapname;
float deathmatch;
float coop;
float teamplay;
float serverflags;
float rounds;
float rounds_change;
float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16;
vector v_forward, v_up, v_right;
float trace_allsolid;
float trace_startsolid;
float trace_fraction;
vector trace_endpos;
vector trace_plane_normal;
float trace_plane_dist;
entity trace_ent;
float trace_inopen;
float trace_inwater;
entity msg_entity; // destination of single entity writes
void() main; // only for testing
void() StartFrame;
void() EndFrame;
void() PlayerPreThink;
void() PlayerPostThink;
void() ClientKill;
void() ClientConnect;
void() PutClientInServer;
void() ClientDisconnect;
void() SetNewParms;
void() SetChangeParms;
void end_sys_globals;
.float modelindex;
.vector absmin, absmax;
.float ltime;
.float movetype;
.float solid;
.vector origin;
.vector oldorigin;
.vector velocity;
.vector angles;
.vector avelocity;
.vector punchangle;
.string classname;
.string model;
.float frame;
.float skin;
.float effects;
.vector mins, maxs;
.vector size;
.void() touch;
.void() use;
.void() think;
.void() blocked;
.float nextthink;
.entity groundentity;
.float health;
.float points;
.float kills;
.float weapon;
.string weaponmodel;
.string weapon2model;
.float weaponframe;
.float weapon2frame;
.float currentammo;
.float currentmag;
.float zoom;
.float weaponskin;
.float weapon2skin;
.float primary_grenades;
.float secondary_grenades;
.float grenades;
.float perks;
.float takedamage;
.entity chain;
.float deadflag;
.vector view_ofs;
.float button0;
.float button1;
.float button2;
.float button3;
.float button4;
.float button5;
.float button6;
.float button7;
.float button8;
.float impulse;
.float fixangle;
.vector v_angle;
.float idealpitch; // Naievil -- new
.string netname;
.entity enemy;
.float flags;
.float colormap;
.float team;
.float max_health;
.float teleport_time;
.float armortype;
.float armorvalue;
.float waterlevel;
.float watertype;
.float ideal_yaw;
.float yaw_speed;
.entity aiment;
.entity head;
.entity larm;
.entity rarm;
.entity goalentity;
.float spawnflags;
.string target;
.string targetname;
.float dmg_take;
.float dmg_save;
.float progress_bar;
.entity dmg_inflictor;
.entity owner;
.vector movedir;
.string message;
.float sounds;
.string noise, noise1, noise2, noise3;
.float x2_icon;
.float insta_icon;
.string Weapon_Name_Touch;
.vector ADS_Offset;
.vector Flash_Offset;
.float Flash_Size;
.float currentmag2;
.float maxspeed;
.float renderGrayscale;
void end_sys_fields;
/*
==============================================================================
VARS NOT REFERENCED BY C CODE
==============================================================================
*/
//
// constants
//
float FALSE = 0;
float TRUE = 1;
// edict.flags
float FL_FLY = 1;
float FL_SWIM = 2;
float FL_CLIENT = 8; // set for all client edicts
float FL_INWATER = 16; // for enter / leave water splash
float FL_MONSTER = 32;
float FL_GODMODE = 64; // player cheat
float FL_NOTARGET = 128; // player cheat
float FL_ITEM = 256; // extra wide size for bonus items
float FL_ONGROUND = 512; // standing on something
float FL_PARTIALGROUND = 1024; // not all corners are valid
float FL_WATERJUMP = 2048; // player jumping out of water
float FL_JUMPRELEASED = 4096; // for jump debouncing
// edict.movetype values
float MOVETYPE_NONE = 0; // never moves
//float MOVETYPE_ANGLENOCLIP = 1;
//float MOVETYPE_ANGLECLIP = 2;
float MOVETYPE_WALK = 3; // players only
float MOVETYPE_STEP = 4; // discrete, not real time unless fall
float MOVETYPE_FLY = 5;
float MOVETYPE_TOSS = 6; // gravity
float MOVETYPE_PUSH = 7; // no clip to world, push and crush
float MOVETYPE_NOCLIP = 8;
float MOVETYPE_FLYMISSILE = 9; // fly with extra size against monsters
float MOVETYPE_BOUNCE = 10;
float MOVETYPE_BOUNCEMISSILE = 11; // bounce with extra size
// edict.solid values
float SOLID_NOT = 0; // no interaction with other objects
float SOLID_TRIGGER = 1; // touch on edge, but not blocking
float SOLID_BBOX = 2; // touch on edge, block
float SOLID_SLIDEBOX = 3; // touch on edge, but not an onground
float SOLID_BSP = 4; // bsp clip, touch on edge, block
float DEAD_NO = 0;
float DEAD_DYING = 1;
float DEAD_DEAD = 2;
float DEAD_RESPAWNABLE = 3;
// takedamage values
float DAMAGE_NO = 0;
float DAMAGE_YES = 1;
float DAMAGE_AIM = 2;
// point content values
float CONTENT_EMPTY = -1;
float CONTENT_SOLID = -2;
float CONTENT_WATER = -3;
float CONTENT_SLIME = -4;
float CONTENT_LAVA = -5;
float CONTENT_SKY = -6;
float STATE_TOP = 0;
float STATE_BOTTOM = 1;
float STATE_UP = 2;
float STATE_DOWN = 3;
vector VEC_ORIGIN = '0 0 0';
// protocol bytes
float SVC_TEMPENTITY = 23;
float SVC_KILLEDMONSTER = 27;
float SVC_FOUNDSECRET = 28;
float SVC_INTERMISSION = 30;
float SVC_FINALE = 31;
float SVC_CDTRACK = 32;
float SVC_SELLSCREEN = 33;
float SVC_SMALLKICK = 34;
float SVC_BIGKICK = 35;
float SVC_MUZZLEFLASH = 39;
// sound channels
// channel 0 never willingly overrides
// other channels (1-7) allways override a playing sound on that channel
float CHAN_AUTO = 0;
float CHAN_WEAPON = 1;
float CHAN_VOICE = 2;
float CHAN_ITEM = 3;
float CHAN_BODY = 4;
float CHAN_NO_PHS_ADD = 8; // ie: CHAN_BODY+CHAN_NO_PHS_ADD
float ATTN_NONE = 0;
float ATTN_NORM = 1;
float ATTN_IDLE = 2;
float ATTN_STATIC = 3;
// entity effects
#define EF_BLUE 1
#define EF_MUZZLEFLASH 2
#define EF_BRIGHTLIGHT 4
#define EF_RED 8
#define EF_ORANGELIGHT 16
#define EF_GREEN 32
#define EF_LIGHT 64
#define EF_NODRAW 128
#define EF_BRIGHTFIELD 256
#define EF_FULLBRIGHT 512
#define EF_DARKLIGHT 1024
#define EF_DARKFIELD 2048
#define EF_PURPLELIGHT 4096
#define EF_RAYRED 8196
#define EF_RAYGREEN 16384
// messages
float MSG_BROADCAST = 0; // unreliable to all
float MSG_ONE = 1; // reliable to one (msg_entity)
float MSG_ALL = 2; // reliable to all
float MSG_INIT = 3; // write to the init string
float MSG_MULTICAST = 4; // for multicast() call
// message levels
float PRINT_LOW = 0; // pickup messages
float PRINT_MEDIUM = 1; // death messages
float PRINT_HIGH = 2; // critical messages
float PRINT_CHAT = 3; // also goes to chat console
// multicast sets
float MULTICAST_ALL = 0; // every client
float MULTICAST_PHS = 1; // within hearing
float MULTICAST_PVS = 2; // within sight
float MULTICAST_ALL_R = 3; // every client, reliable
float MULTICAST_PHS_R = 4; // within hearing, reliable
float MULTICAST_PVS_R = 5; // within sight, reliable
//================================================
//
// globals
//
string string_null; // null string, nothing should be held here
entity activator; // the entity that activated a trigger or brush
float framecount;
//
// cvars checked each frame
//
float teamplay;
float deathmatch;
//================================================
//
// world fields (FIXME: make globals)
//
.string wad;
.string map;
.float worldtype; // 0=medieval 1=metal 2=base
//================================================
.string killtarget;
//
// quakeed fields
//
.float light_lev; // not used by game, but parsed by light util
.float style;
//
// monster ai
//
.void() th_stand;
.void() th_walk;
.void() th_run;
.void() th_missile;
.void() th_melee;
.void(entity attacker, float damage) th_pain;
.void() th_die;
.entity oldenemy; // mad at this player before taking damage
.float speed;
.float lefty;
.float search_time;
.float attack_state;
float AS_STRAIGHT = 1;
float AS_SLIDING = 2;
float AS_MELEE = 3;
float AS_MISSILE = 4;
//
// player only fields
//
.float voided;
.float walkframe;
// Zoid Additions
.float gravity; // Gravity Multiplier (0 to 1.0)
.float attack_finished;
.float pain_finished;
.float invincible_finished;
.float invisible_finished;
.float super_damage_finished;
.float radsuit_finished;
.float invincible_time, invincible_sound;
.float invisible_time, invisible_sound;
.float super_time, super_sound;
.float rad_time;
.float fly_sound;
.float axhitme;
.float show_hostile; // set to time+0.2 whenever a client fires a
// weapon or takes damage. Used to alert
// monsters that otherwise would let the player go
.float jump_flag; // player jump flag
.float swim_flag; // player swimming sound flag
.float air_finished; // when time > air_finished, start drowning
.float bubble_count; // keeps track of the number of bubbles
.string deathtype; // keeps track of how the player died
//
// object stuff
//
.string mdl;
.vector mangle; // angle at start
.vector oldorigin; // only used by secret door
.float t_length, t_width;
//
// doors, etc
//
.vector dest, dest1, dest2;
.float wait; // time from firing to restarting
.float delay; // time from activation to firing
.entity trigger_field; // door's trigger entity
.string noise4;
//
// monsters
//
.float pausetime;
.entity movetarget;
//
// doors
//
.float aflag;
.float dmg; // damage done by door when hit
//
// misc
//
.float cnt; // misc flag
//
// subs
//
.void() think1;
.vector finaldest, finalangle;
//
// triggers
//
.float count; // for counting triggers
//
// plats / doors / buttons
//
.float lip;
.float state;
.vector pos1, pos2; // top and bottom positions
.float height;
//
// sounds
//
.float waitmin, waitmax;
.float distance;
.float volume;
.float sprintflag;
//
// builtin functions
//
void(vector ang) makevectors = #1; // sets v_forward, etc globals
void(entity e, vector o) setorigin = #2;
void(entity e, string m) setmodel = #3; // set movetype and solid first
void(entity e, vector min, vector max) setsize = #4;
void() break = #6;
float() random = #7; // returns 0 - 1
void(entity e, float chan, string samp, float vol, float atten) sound = #8;
vector(vector v) normalize = #9;
void(string e) error = #10;
void(string e) objerror = #11;
float(vector v) vlen = #12;
float(vector v) vectoyaw = #13;
entity() spawn = #14;
void(entity e) remove = #15;
void(vector v1, vector v2, float nomonsters, entity forent) traceline = #16;
entity() checkclient = #17; // returns a client to look for
entity(entity start, .string fld, string match) find = #18;
string(string s) precache_sound = #19;
string(string s) precache_model = #20;
void(entity client, string s)stuffcmd = #21;
entity(vector org, float rad) findradius = #22;
void(float level, string s) bprint = #23;
void(entity client, float level, string s) sprint = #24;
void(string s) dprint = #25;
string(float f) ftos = #26;
string(vector v) vtos = #27;
void() coredump = #28; // prints all edicts
void() traceon = #29; // turns statment trace on
void() traceoff = #30;
void(entity e) eprint = #31; // prints an entire edict
float(float yaw, float dist) walkmove = #32; // returns TRUE or FALSE
float(entity zombie, float which, entity limb) updateLimb = #33;
float(float yaw, float dist) droptofloor = #34; // TRUE if landed on floor
void(float style, string value) lightstyle = #35;
float(float v) rint = #36; // round to nearest int
float(float v) floor = #37; // largest integer <= v
float(float v) ceil = #38; // smallest integer >= v
float(entity e) checkbottom = #40; // true if self is on ground
float(vector v) pointcontents = #41; // returns a CONTENT_*
float(float f) fabs = #43;
vector(entity e, float speed) aim = #44; // returns the shooting vector
float(string s) cvar = #45; // return cvar.value
void(string s) localcmd = #46; // put string into local que
entity(entity e) nextent = #47; // for looping through all ents
void() ChangeYaw = #49; // turn towards self.ideal_yaw
vector(vector v) vectoangles = #51;
void(float to, float f) WriteByte = #52;
void(float to, float f) WriteChar = #53;
void(float to, float f) WriteShort = #54;
void(float to, float f) WriteLong = #55;
void(float to, float f) WriteCoord = #56;
void(float to, float f) WriteAngle = #57;
void(float to, string s) WriteString = #58;
void(float to, entity s) WriteEntity = #59;
void(float step) movetogoal = #67;
string(string s) precache_file = #68; // no effect except for -copy
void(entity e) makestatic = #69;
void(string s) changelevel = #70;
void(string var, string val) cvar_set = #72; // sets cvar.value
void(entity client, string s) centerprint = #73; // sprint, but in middle
void(vector pos, string samp, float vol, float atten) ambientsound = #74;
string(string s) precache_model2 = #75; // registered version only
string(string s) precache_sound2 = #76; // registered version only
string(string s) precache_file2 = #77; // registered version only
void(entity e) setspawnparms = #78; // set parm1... to the
void(entity killer, entity killee) logfrag = #79; // add to stats
string(entity e, string key) infokey = #80; // get a key value (world = serverinfo)
float(string s) stof = #81; // convert string to float
void(vector where, float set) multicast = #82;
vector(entity what) Get_Waypoint_Near = #83;
float(entity zombie, entity target) Do_Pathfind_psp = #84;
void(string s) Open_Waypoint = #85;
vector(entity zombie,vector start,vector min, vector max) Get_Next_Waypoint = #86;
void(entity client, float type, float cost, float weapon) useprint = #87;
vector(entity zombie,vector start,vector min, vector max) Get_First_Waypoint = #88;
entity (entity start, .float field, float match) findfloat = #98;
// New NZP custom ones
float(string filename, float mode) fopen = #110;
void(float fhandle) fclose = #111;
string(float fhandle) fgets = #112;
void(float fhandle, string s) fputs = #113;
float(string s) strlen = #114;
string(string s1, string s2) strcat = #115;
string(string s, float start, float length) substring = #116;
vector(string s) stov = #117;
string(string s) strzone = #118;
string(string s) strunzone = #119;
string(string s) strtrim = #120;
float(string s) tokenize = #130; // Was #441
string(float num) argv = #131; // Was #442
void(float intensity_small, float intensity_large, float duration) rumble = #132;
float(entity targ, entity inflictor) CanDamage;
#define FILE_READ 0
#define FILE_APPEND 1
#define FILE_WRITE 2
#define SVC_WEAPONFIRE 35
#define SVC_HITMARK 36
#define SVC_LIMBUPDATE 51 // naievil -- keep me
#define SVC_BSPDECAL 50 // naievil -- keep me
#define SVC_ACHIEVEMENT 52
#define VEC_ORIGIN '0 0 0'
//Standard Quake View Offset
//vector VEC_VIEW_OFS = '0 0 22';
//Half Life View Offset is 64
//64 units above ground, for our purposes it's, 64 - (how low bounding box goes)
vector VEC_VIEW_OFS = '0 0 32';
//Standard Quake Hull
//vector VEC_HULL_MIN = '-16 -16 -24';
//vector VEC_HULL_MAX = '16 16 32';
//Half Life 1 Hull Sizes ADDED BY BLUBS, COMMENTED ORIGINAL QUAKE BBOX SIZS OUT
#define VEC_HULL_MIN '-16 -16 -32'
#define VEC_HULL_MAX '16 16 40'
#define VEC_HULL2_MIN '-32 -32 -24'
#define VEC_HULL2_MAX '32 32 64'
.string fog;
//string world_fog;
.float button3;
.float button4;
.float button5;
.float button6;
.float button7;
.float button8;
.float x2_icon; // double points icon
.float insta_icon;
.vector Flash_Offset;
.float Flash_Size;
.string Weapon_Name;
.float currentHitBoxSetup;
.vector bbmins, bbmaxs; // Used for zombie hitboxes
.entity head;
.entity larm;
.entity rarm;
#define SOLID_CORPSE 5 // bsp clip, touch on edge, block
#define TE_EXPLOSION 3
#define TE_GUNSHOT 2
entity windows[32];
float wincnt;
.float recoil_delay;
float pow(float base, float n) = {
float temp = base;
if (n == 0) {
return 1;
} else {
while (n > 0) {
temp = temp * base;
n = n - 1;
}
return temp;
}
return 0;
};
void enableGrayscale(void) = {
self.renderGrayscale = 1;
}
void disableGrayscale(void) = {
self.renderGrayscale = 0;
}

View file

@ -0,0 +1,89 @@
/*
server/dummies/generic.qc
generic (all platform) dummys
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
// Triggers
void() trigger_relay = {remove(self);};
void() trigger_changelevel = {remove(self);};
void() trigger_counter = {remove(self);};
void() trigger_secret = {remove(self);};
void() trigger_setskill = {remove(self);};
void() trigger_monsterjump = {remove(self);};
void() trigger_onlyregistered = {remove(self);};
void() trigger_push = {remove(self);};
void() trigger_hurt = {remove(self);};
// Player Starts
void() info_player_start = {};
void() info_player_start2 = {};
void() info_player_deathmatch = {};
void() info_player_coop = {};
void() info_player_tank = {};
void() info_player_nikolai = {};
void() info_player_doctor = {};
void() info_player_takeo = {};
void() zapper1 = {remove(self);};
void() zapper2 = {remove(self);};
void() item_switch = {remove(self);};
void() zap_light = {remove(self);};
void() info_end = {remove(self);};
//// beta removal
void() monster_dog = {remove(self);};
void() item_pap = {remove(self);};
//void() item_juggernog = {remove(self);};
//void() item_flopper = {remove(self);};
//void() item_douple = {remove(self);};
//void() item_speed = {remove(self);};
//void() item_revive = {remove(self);};
void() palm_tree_closed = {remove(self);};
void() func_model = {remove(self);};
void() wooden_crate = {remove(self);};
void() change_frame;
void() change_frame2 =
{
self.frame++;
self.think = change_frame;
self.nextthink = time + 1;
}
void() change_frame =
{
self.frame++;
self.think = change_frame2;
self.nextthink = time + 1;
}
#ifdef PSP
void LoadWaypointData() = {};
#endif
// Old Demo defs
.float fogdogs;
.float MaxRange;
void() trigger_teleport = {remove(self);};
void() tigger_mainframe = {remove(self);}; //lol this typo is in their old fgd too, apparently.
void() trigger_teleport_area = {remove(self);};

View file

@ -0,0 +1,157 @@
/*
server/dummies/generic.qc
dummys for vita and nx
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
// Dummys that should be here
void GiveAchievement(float achievement_id, optional entity who) = {};
void print(string s) = {};
float tracemove(vector start, vector min, vector max, vector end, float nomonsters, entity forent) = {return 0;};
void(vector o, vector d, float color, float count) particle = {};
#define MOVE_HITMODEL 0
void() LoadWaypointData = {};
void() Soft_Restart = {
/*
entity who, oldself, doors, box, revive, endgame;
self = find(world,classname,"player");
oldself = self;
//remove all zombies
who = find(world,classname,"ai_zombie");
while(who != world)
{
if(who.health)
{
self = who;
self.th_die();
remove(self); //so dead bodies don't remain
self = oldself;
}
who = find(who,classname,"ai_zombie");
}
//repair all windows
for(float i = 0; i < wincnt; i++) {
if (windows[i].health != -10) {
windows[i].health = 6;
windows[i].frame = 0;
}
}
//close doors
doors = findfloat(world, isopen, 1);
while (doors) {
if (doors.isopen)
reclose_door(doors);
doors = findfloat(world, isopen, 1);
}
//revert mystery box
box = find(world, classname, "mystery");
if (box) {
box.boxstatus = 0;
box.frame = 0;
box.goaldummy.frame = 0;
boxCount = 0;
box.origin = boxOrigin;
//self = box;
if (box.boxweapon)
remove(box.boxweapon);
//mystery_box();
//self = oldself;
}
//reset quick revive
revive = find(world, classname, "perk_revive");
if (revive) {
setmodel(revive, "models/machines/quick_revive.mdl");
oldself.revivesoda = 0;
}
//reset buyable ending
endgame = find(world, classname, "func_ending");
if (endgame) {
endgame.activated = false;
}
//reset teleporters
local entity tp;
tp = find(world, classname, "func_teleporter_entrance");
if (tp) {
tp.activated = false;
tp.isLinked = false;
tp.cooldown = false;
tp.waitLink = false;
tp.think = SUB_Null;
}
local entity power;
power = find(world, classname, "power_switch");
if(power) {
isPowerOn = false;
power.frame = 0;
}
self = oldself;
self.downed = 0;
game_over = false;
rounds = 0;
self.score = 0;
self.points = 0;
self.secondaryweapon = 0;
InitRounds();
self.isspec = false;
PutClientInServer();
*/
}
void () CL_SendWeaponFire =
{
float return_time;
vector Wep_Recoil;
Wep_Recoil = GetWeaponRecoil(self.weapon);
msg_entity = self;
WriteByte(MSG_ONE, SVC_WEAPONFIRE);
return_time = getWeaponRecoilReturn(self.weapon);
WriteLong(MSG_ONE, return_time);
WriteCoord (MSG_ONE, Wep_Recoil_x);
WriteCoord (MSG_ONE, Wep_Recoil_y);
WriteCoord (MSG_ONE, Wep_Recoil_z);
//self.punchangle = Wep_Recoil;
self.recoil_delay = 60/return_time + time;
}

View file

@ -0,0 +1,696 @@
/*
server/entities/doors.qc
Doors are similar to buttons, but can spawn a fat trigger field
around them to open without a touch, and they link together to
form simultanious double/quad doors.
Door.owner is the master door. If there is only one door, it
points to itself. If multiple doors, all will point to a single
one.
Door.enemy chains from the master door through all doors linked
in the chain.
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
/*
code for show that you need money EDITASAP
*/
float DOOR_START_OPEN = 1;
float DOOR_DONT_LINK = 4;
float DOOR_DEBRIS = 8;
float DOOR_SILVER_KEY = 16;
float DOOR_TOGGLE = 32;
float DOOR_POWER = 64;
entity activator;
.float delay;
.string killtarget;
.void() think1;
.vector finaldest;
.float dmg;
.entity trigger_field;
.float wait;
.float speed;
.vector pos1;
.vector pos2;
string string_null;
.float cost;
.float attack_delay;
.float lip;
void() print_need_power =
{
if(other.classname == "player" && !other.downed)
{
/*if (self.owner.message)
centerprint(other, self.owner.message);
else
centerprint(other, "Power must be activated first");*/
useprint (other, 8, 0, 0);
}
};
/*
=============================================================================
THINK FUNCTIONS
=============================================================================
*/
void() door_go_down;
void() door_go_up;
void() door_blocked =
{
DamageHandler (other, self, self.dmg, S_NORMAL);
// if a door has a negative wait, it would never come back if blocked,
// so let it just squash the object to death real fast
if (self.wait >= 0)
{
if (self.state == STATE_DOWN)
door_go_up ();
else
door_go_down ();
}
};
void() door_hit_top =
{
self.state = STATE_TOP;
if ((self.classname == "door_nzp_cost" || self.classname == "door_nzp" || self.classname == "door_open"))
{
//remove (self.owner.trigger_field); //moto - what does this do lol
if (!(self.spawnflags & 128))
setmodel(self, "");
self.isopen = 1;
return;//so we dont have to reopen doors
}
if (self.spawnflags & DOOR_TOGGLE)
return; // don't come down automatically
self.think = door_go_down;
self.nextthink = self.ltime + self.wait;
};
void() door_hit_bottom =
{
self.state = STATE_BOTTOM;
};
void() door_go_down =
{
if ((self.classname == "door_nzp_cost" || self.classname == "door_nzp" || self.classname == "door_open"))
{
if (!(self.spawnflags & 128))
setmodel(self, "");
self.isopen = 1;
return;//so we dont have to reopen doors
}
if (self.max_health)
{
self.takedamage = DAMAGE_YES;
self.health = self.max_health;
}
self.state = STATE_DOWN;
if (self.spawnflags & 256)
SUB_CalcAngleMove(self.pos1, self.speed, door_hit_bottom);
else
SUB_CalcMove (self.pos1, self.speed, door_hit_bottom);
};
void() door_go_up =
{
if (self.state == STATE_UP)
return; // allready going up
if (self.state == STATE_TOP)
{ // reset top wait time
self.nextthink = self.ltime + self.wait;
return;
}
self.state = STATE_UP;
if (self.spawnflags & 256)
SUB_CalcAngleMove(self.pos2, self.speed, door_hit_top);
else
SUB_CalcMove (self.pos2, self.speed, door_hit_top);
#ifndef PC
Open_Waypoint(self.wayTarget);
#endif
SUB_UseTargets();
};
/*
=============================================================================
ACTIVATION FUNCTIONS
=============================================================================
*/
void() door_fire =
{
local entity oself;
local entity starte;
if (isPowerOn == FALSE)
{
if (self.spawnflags & DOOR_POWER )
{
if(other.classname == "player" && !other.downed)
{
/*if (self.message)
centerprint(other, self.message);
else
centerprint(other, "Power must be activated first");*/
useprint (other, 8, 0, 0);
return;
}
}
}
self.message = string_null; // no more message
oself = self;
if (self.door_model_target)
{
entity tempe = find(world, classname, "func_door_model");
if (tempe != world) {
///door_model_name, self.door_model_target
if (tempe.door_model_name == self.door_model_target) {
setmodel(tempe, "");
remove(tempe);
} else {
bprint(PRINT_HIGH, "Could not find door_model_name: ");
bprint(PRINT_HIGH, self.door_model_target);
bprint(PRINT_HIGH, "\n");
}
}
}
if (self.spawnflags & DOOR_TOGGLE)
{
if (self.state == STATE_UP || self.state == STATE_TOP)
{
starte = self;
do
{
door_go_down ();
self = self.enemy;
} while ( (self != starte) && (self != world) );
self = oself;
return;
}
}
// trigger all paired doors
starte = self;
do
{
door_go_up ();
//self.isopen = true;
self = self.enemy;
} while ( (self != starte) && (self != world) );
self = oself;
SUB_UseTargets();
};
void() cost_door =
{
if (self.state == STATE_TOP || self.state == STATE_UP)
return;
if (isPowerOn == FALSE)
{
if (self.spawnflags & DOOR_POWER )
{
if(other.classname == "player" && !other.downed)
{
/*if (self.message)
centerprint(other, self.message);
else
centerprint(other, "Power must be activated first");*/
useprint (other, 8, 0, 0);
return;
}
}
}
if (other.button7)
{
if (other.points >= self.cost)
{
door_fire();
sound(self, 0,"sounds/misc/ching.wav", 1, 1);
sound(self, CHAN_ITEM,"sounds/misc/buy.wav", 1, 1);
switch(self.sounds)
{
case 1:
sound(self, CHAN_ITEM,"sounds/misc/wood_door.wav", 1, 1);
break;
case 2:
sound(self, CHAN_ITEM,"sounds/misc/debris.wav", 1, 1);
break;
default:
break;
}
addmoney(other, self.cost*-1, 0);
self.solid = SOLID_NOT;
//centerprint (other, "");
//useprint (other, 0, 0, 0);
//other.total_bought = other.total_bought + 1;
}
else
{
if(other.classname == "player" && !other.downed)
{
centerprint (other, "You do not have enough points\n");
other.semiuse = 1;
}
}
}
else if (!other.button7)
{
if(other.classname == "player" && !other.downed)
{
/*if (!self.message)
centerprint3(other, "press use to open door for ", b = ftos (self.cost), " points\n");
else
centerprint (other, self.message);*/
if (self.spawnflags & DOOR_DEBRIS)
useprint (other, 2, self.cost, 0);
else
useprint (other, 1, self.cost, 0);
return;
}
}
};
void() door_use =
{
local entity oself;
oself = self;
self = self.owner;
if (self.cost)
cost_door();
else
door_fire ();
self = oself;
};
void() door_trigger_touch =
{
if(other.classname != "player")
{
return;
}
if(cvar("waypoint_mode"))
{
if(other.active_door != self.owner)
{
bprint(PRINT_HIGH, "Current Door for special waypoints set to ");
bprint(PRINT_HIGH, self.owner.wayTarget);
bprint(PRINT_HIGH, "\n");
other.active_door = self.owner;
}
return;
}
if (other.health <= 20)
return;
activator = other;
self = self.owner;
door_use ();
};
void() door_killed =
{
local entity oself;
oself = self;
self = self.owner;
self.health = self.max_health;
self.takedamage = DAMAGE_NO; // will be reset upon return
door_use ();
self = oself;
};
/*
================
door_touch
Prints messages and opens key doors
================
*/
void() door_touch =
{
if (other.classname != "player")
return;
if (other.button7)
{
return;
}
if (self.owner.message != "")
{
centerprint (other, self.owner.message);
}
if (isPowerOn == FALSE)
{
if (self.owner.spawnflags & DOOR_POWER)
{
self.touch = print_need_power;
return;
}
}
self.touch = SUB_Null;
if (self.enemy)
self.enemy.touch = SUB_Null; // get paired door
door_use ();
};
/*
=============================================================================
SPAWNING FUNCTIONS
=============================================================================
*/
entity(vector fmins, vector fmaxs) spawn_field =
{
local entity trigger;
local vector t1, t2;
trigger = spawn();
trigger.movetype = MOVETYPE_NONE;
trigger.solid = SOLID_TRIGGER;
trigger.owner = self;
trigger.touch = door_trigger_touch;
setorigin(trigger, self.origin);
t1 = fmins;
t2 = fmaxs;
setsize (trigger, t1/* - '15 15 8'*/, t2/* + '15 15 8'*/);
return (trigger);
};
float (entity e1, entity e2) EntitiesTouching =
{
if (e1.mins_x > e2.maxs_x)
return FALSE;
if (e1.mins_y > e2.maxs_y)
return FALSE;
if (e1.mins_z > e2.maxs_z)
return FALSE;
if (e1.maxs_x < e2.mins_x)
return FALSE;
if (e1.maxs_y < e2.mins_y)
return FALSE;
if (e1.maxs_z < e2.mins_z)
return FALSE;
return TRUE;
};
/*
=============
LinkDoors
=============
*/
void() LinkDoors =
{
local entity t, starte;
local vector cmins, cmaxs;
if (self.enemy)
return; // already linked by another door
if (self.spawnflags & 4)
{
self.owner = self.enemy = self;
return; // don't want to link this door
}
cmins = self.mins;
cmaxs = self.maxs;
starte = self;
t = self;
do
{
self.owner = starte; // master door
if (self.health)
starte.health = self.health;
if (self.targetname)
starte.targetname = self.targetname;
if (self.message != "")
starte.message = self.message;
t = find (t, classname, self.classname);
if (!t)
{
self.enemy = starte; // make the chain a loop
// shootable, fired, or key doors just needed the owner/enemy links,
// they don't spawn a field
self = self.owner;
if (self.health)
return;
if (self.targetname)
return;
self.owner.trigger_field = spawn_field(cmins, cmaxs);
return;
}
if (EntitiesTouching(self,t))
{
if (t.enemy)
objerror ("cross connected doors");
self.enemy = t;
self = t;
if (t.mins_x < cmins_x)
cmins_x = t.mins_x;
if (t.mins_y < cmins_y)
cmins_y = t.mins_y;
if (t.mins_z < cmins_z)
cmins_z = t.mins_z;
if (t.maxs_x > cmaxs_x)
cmaxs_x = t.maxs_x;
if (t.maxs_y > cmaxs_y)
cmaxs_y = t.maxs_y;
if (t.maxs_z > cmaxs_z)
cmaxs_z = t.maxs_z;
}
} while (1 );
};
/*
=====================
SPECIAL DOORS
thease doors can be opened by money or when power is on
=====================
*/
void() func_door_model =
{
place_model();
}
void() func_door =
{
SetMovedir ();
self.max_health = self.health;
self.solid = SOLID_BSP;
self.movetype = MOVETYPE_PUSH;
setorigin (self, self.origin);
setmodel (self, self.model);
self.classname = "door";
self.blocked = door_blocked;
self.use = door_use;
if (!self.speed)
self.speed = 100;
if (!self.wait)
self.wait = 3;
if (!self.lip)
self.lip = 8;
if (!self.dmg)
self.dmg = 2;
self.pos1 = self.origin;
self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
// but spawn in the open position
if (self.spawnflags & DOOR_START_OPEN)
{
setorigin (self, self.pos2);
self.pos2 = self.pos1;
self.pos1 = self.origin;
}
self.state = STATE_BOTTOM;
if (self.health)
{
self.takedamage = DAMAGE_YES;
self.th_die = door_killed;
}
self.touch = door_touch;
// LinkDoors can't be done until all of the doors have been spawned, so
// the sizes can be detected properly.
self.think = LinkDoors;
self.nextthink = self.ltime + 0.1;
};
void() func_door_nzp =
{
#ifdef PSP
if (!self.renderamt)
self.renderamt = 255;
if (!self.rendermode)
self.rendermode = 4;
if (!self.rendercolor)
self.rendercolor = '0 0 0';
if (!self.mapversion)
self.mapversion = 0;
if (!self.ammo)
self.ammo = 0; //thease are just here because they can be sp there is no error message. serve no real purpose
#endif
// naievil (FIXME) ^^^^ hl rendermodes, mapversion
makevectors(self.angles);
SetMovedir ();
self.target2 = self.target;
self.target3 = self.target;
self.target4 = self.target;
self.target5 = self.target;
self.target6 = self.target;
self.target7 = self.target;
self.target8 = self.target;
self.max_health = self.health;
self.solid = SOLID_BSP;
self.movetype = MOVETYPE_PUSH;
self.oldmodel = self.model;
self.oldorigin = self.origin;
self.oldstate = self.state;
setorigin (self, self.origin);
setmodel (self, self.model);
self.blocked = door_blocked;
self.use = door_use;
if (self.cost)
{
self.classname = "door_nzp_cost";
// total_buy = total_buy +1;
}
else
self.classname = "door_nzp";
if (!self.speed)
self.speed = 100;
if (!self.wait)
self.wait = 3;
if (!self.lip)
self.lip = 8;
if (!self.dmg)
self.dmg = 2;
// only rotate on the Y axis.. potentially change?
if (self.spawnflags & 256) {
self.pos1 = self.angles;
self.pos2 = self.pos1;
self.pos2_y = self.pos1_y + self.distance;
} else {
self.pos1 = self.origin;
self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip);
}
// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
// but spawn in the open position
if (self.spawnflags & DOOR_START_OPEN)
{
setorigin (self, self.pos2);
self.pos2 = self.pos1;
self.pos1 = self.origin;
}
self.state = STATE_BOTTOM;
if (self.health)
{
self.takedamage = DAMAGE_YES;
self.th_die = door_killed;
}
self.touch = door_touch;
// LinkDoors can't be done until all of the doors have been spawned, so
// the sizes can be detected properly.
self.think = LinkDoors;
self.nextthink = self.ltime + 0.1;
};

View file

@ -0,0 +1,118 @@
/*
server/entities/lights.qc
Spawns and handles Quake's lights and torches
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
float START_OFF = 1; // Light on/off spawnflag
void() Light_setup; // Definition from Lights.qc
void(string modelname) Precache_Set = // Precache model, and set myself to it
{
precache_model(modelname);
setmodel(self, modelname);
};
void() light = // Basic Light
{
Light_setup(); // Setup Light
}
void() light_fluoro = // Light with hum ambient
{
Light_setup(); // Setup Light
};
void() light_environment = // Basic Light
{
makestatic(self); // Static entity. Never changes.
}
void() light_fluorospark = // Light with buzz ambient
{
Light_setup(); // Setup Light
};
void() light_globe = // Light with visible globe
{
Precache_Set("progs/s_light.spr"); // Set model
makestatic(self); // Static entity. Never changes.
}
void() light_torch_small_walltorch = // Light with visible wall torch
{
Precache_Set("progs/flame.mdl"); // Set model
makestatic(self); // Static entity. Never changes.
};
void() light_flame_small_yellow = // Light with small flame & fire sound
{
Precache_Set("progs/flame2.mdl"); // Set model
makestatic(self); // Static entity. Never changes.
};
void() light_flame_large_yellow = // Light with larger flame & fire sound
{
Precache_Set("progs/flame2.mdl"); // Set model
self.frame = 1; // Switch to second frame (large)
makestatic(self); // Static entity. Never changes.
};
void() light_flame_small_white = // Light with small flame & fire sound
{
Precache_Set("progs/flame2.mdl"); // Set model
makestatic(self); // Static entity. Never changes.
};
void() Light_setup = // Set light on or off, as per spawnflags
{
if (self.style < 32) {
return;
} // Dont switch other styles.
if (self.spawnflags & START_OFF)
lightstyle(self.style, "a"); // If light starts off, set it off.
else
lightstyle(self.style, "m"); // If light starts ON, turn in ON. Simple :)
}
void() LightStyles_setup =
{
// Setup light animation tables. 'a' is total darkness, 'z' is maxbright.
lightstyle(0,"m"); // Style 0: Normal
lightstyle(1,"mmnmmommommnonmmonqnmmo"); // Style 1: Flicker
lightstyle(2,"abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); // Style 2: Slow Strong Pulse
lightstyle(3,"mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); // Style 3: Candle
lightstyle(4,"mamamamamama"); // Style 4: Fast Strobe
lightstyle(5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj"); // Style 5: Gentle Pulse
lightstyle(6,"nmonqnmomnmomomno"); // Style 6: Flicker 2
lightstyle(7,"mmmaaaabcdefgmmmmaaaammmaamm"); // Style 7: Candle 2
lightstyle(8,"mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); // Style 8: Candle 3
lightstyle(9,"aaaaaaaazzzzzzzz"); // Style 9: Slow Strobe
lightstyle(10,"mmamammmmammamamaaamammma"); // Style 10: Fluro
lightstyle(11,"abcdefghijklmnopqrrqponmlkjihgfedcba"); // Style 11: Slow Pulse (no black)
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,576 @@
/*
server/entities/powerups.qc
powerup logic
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
.float zombie_drop_id;
.float flashtime;
.float flash_step;
// the powerup's model
string(float type) getPowerupModel =
{
switch(type) {
case 1: return "models/pu/maxammo!.mdl"; break;
case 2: return "models/pu/x2!.mdl"; break;
case 3: return "models/pu/instakill!.mdl"; break;
case 4: return "models/pu/nuke!.mdl"; break;
case 5: return "models/pu/carpenter!.mdl"; break;
case 6: return "models/pu/perkbottle!.mdl"; break;
default: return ""; break;
}
}
// the powerup's pick up voice clip
string(float type) getPowerupVO =
{
switch(type) {
case 1: return "sounds/pu/maxammo.wav"; break;
case 2: return "sounds/pu/double_points.wav"; break;
case 3: return "sounds/pu/insta_kill.wav"; break;
case 4: return "sounds/pu/nuke.wav"; break;
case 5: return "sounds/pu/carpenter.wav"; break;
default: return ""; break;
}
}
void() maxammo =
{
entity tempe, temp;
tempe = find (world, classname, "player");
while (tempe)
{
if (!tempe.downed)
{
if (tempe.weapon)
{
tempe.currentammo = getWeaponAmmo(tempe.weapon);
if (!tempe.currentmag)
{
temp = self;
self = tempe;
W_Reload(S_BOTH);
self = temp;
}
}
if (tempe.secondaryweapon)
tempe.secondaryammo = getWeaponAmmo(tempe.secondaryweapon);
tempe.primary_grenades = 4;
if (tempe.grenades & 2)
tempe.secondary_grenades = 2;
}
#ifdef PC
ScrollText("MAX AMMO!", tempe);
#endif
#ifdef PSP
nzp_maxammo();
#endif
tempe = find (tempe, classname, "player");
}
}
void() nuke_finalize =
{
entity players;
// give 'The F Bomb'
#ifndef NX
if (self.kills == 1) {
GiveAchievement(4);
}
#endif
// award points
players = find(world,classname,"player");
while(players)
{
addmoney(players, 400*nuke_powerups_activated, 1);
players = find(players,classname,"player");
}
nuke_powerup_active = false;
}
void() do_nuke_kill =
{
// back up ourselves
entity oldself;
oldself = self;
// switch to goaldummy, is goaldummy world?
if (self.goaldummy == world) {
nuke_finalize();
remove(self);
return;
} else {
self = self.goaldummy;
}
// kill a target
self.th_die();
// restore self
self = oldself;
// increment kills
self.kills++;
// find new target
self.goaldummy = findfloat(self.goaldummy, iszomb, 1);
self.nextthink = (rint((random() * 6) + 1)/10) + time; // random number from 0.1 to 0.7
}
void() nuke =
{
// if there's already one active, just increment the point multiplier
if (nuke_powerup_active == true) {
nuke_powerups_activated++;
return;
}
// mark nuke as being active, to prevent zombie damage and spawning.
nuke_powerup_active = true;
nuke_powerup_spawndelay = time + 3;
nuke_powerups_activated = 1;
// create our watcher entity
entity nuke_watcher;
nuke_watcher = spawn();
nuke_watcher.goaldummy = findfloat(world, iszomb, 1);
nuke_watcher.think = do_nuke_kill;
nuke_watcher.nextthink = (rint((random() * 6) + 1)/10) + time; // random number from 0.1 to 0.7
}
void() carpenter =
{
local entity oldself;
local entity who;
oldself = self;
who = find(world,classname,"window");
while(who != world)
{
if(who.health < 6 && who.health != -10)//-10 is for boardless windows
{
self = who;
window_carpenter_1 ();
who.health = 6;
self = oldself;
}
who = find(who,classname,"window");
}
who = find(world,classname,"player");
while(who)
{
addmoney(who, 200, 1);
who = find(who,classname,"player");
}
total_windows_down = 0;
}
void(entity who) give_perkdrop_logic =
{
// Return here if we already have all of the Perks
if ((who.perks & P_REVIVE) && (who.perks & P_JUG) && (who.perks & P_SPEED) && (who.perks & P_DOUBLE) &&
(who.perks & P_FLOP) && (who.perks & P_STAMIN) && (who.perks & P_DEAD) && (who.perks & P_MULE)) {
return;
}
local float perk;
perk = 0;
while(perk == 0) {
local float num;
num = rint((random() * 7)) + 1;
switch(num) {
case 1:
if (!(who.perks & P_JUG)) {
perk = 1;
}
break;
case 2:
if (!(who.perks & P_DOUBLE)) {
perk = 2;
}
break;
case 3:
if (!(who.perks & P_SPEED)) {
perk = 4;
}
break;
case 4:
if (!(who.perks & P_REVIVE)) {
perk = 8;
}
break;
case 5:
if (!(who.perks & P_FLOP)) {
perk = 16;
}
break;
case 6:
if (!(who.perks & P_STAMIN)) {
perk = 32;
}
break;
case 7:
if (!(who.perks & P_DEAD)) {
perk = 64;
}
break;
case 8:
if (!(who.perks & P_MULE)) {
perk = 128;
}
break;
default: break;
}
who.perks = who.perks | perk;
}
SetPerk(who, who.perks);
}
void() give_perk =
{
// Individual Power-Up
if (self.style == 1) {
give_perkdrop_logic(other);
}
// OUR Power-Up
else {
local entity who;
who = find(world, classname, "player");
while(who) {
give_perkdrop_logic(who);
who = find(who, classname, "player");
}
}
}
void() powerup_flash =
{
if(self.flash_step == 0)
{
self.flash_step = 1;
self.flashtime = time + 3;
self.nextthink = time + 0.6;
}
else if(self.flash_step == 1)
{
self.nextthink = time + 0.6;
if(self.flashtime < time)
{
self.flash_step = 2;
self.nextthink = time + 0.3;
self.flashtime = time + 3;
}
}
else if(self.flash_step == 2)
{
self.nextthink = time + 0.3;
if(self.flashtime < time)
{
self.flash_step = 3;
self.nextthink = time + 0.15;
self.flashtime = time + 3;
}
}
else if(self.flash_step == 3)
{
self.nextthink = time + 0.15;
if(self.flashtime < time)
{
// moto - we used to setmodel blank here too, but it caused errors with the sprite.
remove(self.owner);
remove(self);
return;
}
}
if(self.model == "") {
setmodel(self, getPowerupModel(self.zombie_drop_id));
} else {
setmodel(self,"");
}
};
void() powerup_play_sound =
{
// play the VO clip if its not the perk bottle
if (self.zombie_drop_id != 6)
sound(self, CHAN_VOICE, self.powerup_vo, 1, ATTN_NONE);
// finally, remove the (invisible/inactive) powerup.
remove(self);
}
void() powerup_touch =
{
local float t;
t = random();
if(other.classname == "player")
{
// pickup sound
sound(self.owner,CHAN_VOICE,"sounds/pu/pickup.wav",1,ATTN_NONE);
// add a slight delay before VO play
self.think = powerup_play_sound;
self.nextthink = time + 1;
// hide powerup until we remove (after sound)
setmodel(self, "");
self.effects = 0;
self.touch = SUB_Null;
remove(self.owner);
// slight screen flash
stuffcmd(other, "bf\n");
// powerup effects
switch(self.zombie_drop_id) {
// max ammo
case 1:
maxammo();
break;
// double points
case 2:
x2_finished = time + 30;
other.x2_icon = true;
break;
// insta kill
case 3:
instakill_finished = time + 30;
other.insta_icon = true;
break;
// nuke
case 4:
nuke();
break;
// carpenter
case 5:
carpenter();
break;
// free perk
case 6:
give_perk();
break;
// broken!
default:
centerprint(other, strcat("INVALID POWER-UP ID: ", ftos(self.zombie_drop_id)));
break;
}
}
};
void() sparkle_think =
{
local float f;
f = self.frame;
local float r;
while(f == self.frame)
{
r = random();
r = ((r > 0.2) ? 1 : 0) + ((r > 0.4) ? 1 : 0) + ((r > 0.6) ? 1 : 0) + ((r > 0.8) ? 1 : 0);
f = r;
}
self.frame = f;
self.think = sparkle_think;
self.nextthink = time + 0.1;
if(self.calc_time <= time)
{
sound(self,CHAN_VOICE,"sounds/pu/powerup.wav",0.6,ATTN_NORM);
self.calc_time = time + 2.998;
}
};
//
// GetPowerupID()
// Returns a powerup id, checks if the game allows for
// one and if requirements for said powerup are met.
//
float() GetPowerupID =
{
float found;
float carpenter_able;
float perk_able;
float id;
id = carpenter_able = perk_able = 0;
// Check if we can get a carpenter or a free perk drop
if (total_windows_down >= 5)
carpenter_able = true;
if (rounds >= 15)
perk_able = true;
float total_powerups = 5; // nuke, insta, 2x, maxammo, carpenter, free perk
// Start ID loop
found = false;
while(found == false) {
float t = random();
// loop through all IDs
for (float i = 0; i < total_powerups + 1; i++) {
// check if the ID we got was viable
if (t > (i/total_powerups)) {
switch(i) {
case 1:
found = true;
id = i;
break;
case 2:
found = true;
id = i;
break;
case 3:
found = true;
id = i;
break;
case 4:
found = true;
id = i;
break;
case 5:
if (carpenter_able) {
found = true;
id = i;
}
break;
case 6:
/*if (perk_able) {
found = true;
id = i;
}*/
break;
default:
break;
}
}
}
}
return id;
}
float last_pu;
void(vector where, float type) Spawn_Powerup =
{
entity new_powerup;
float id;
new_powerup = spawn();
new_powerup.origin = where;
setorigin(new_powerup, new_powerup.origin);
new_powerup.solid = SOLID_TRIGGER;
new_powerup.classname = "item_powerup";
setsize (new_powerup, VEC_HULL_MIN, VEC_HULL_MAX);
new_powerup.movetype = MOVETYPE_NONE;
Light_Green(new_powerup);
//=================== Sparkle Effects =====================
entity twlt_Sparkle;
twlt_Sparkle = spawn();
new_powerup.owner = twlt_Sparkle; //just a reference so power up can delete the sparkle later on
setorigin(twlt_Sparkle,where);
#ifndef PC
setmodel(twlt_Sparkle,"models/sprites/sprkle.spr");
#endif
twlt_Sparkle.think = sparkle_think;
twlt_Sparkle.nextthink = time + 0.1;
sound(twlt_Sparkle,CHAN_VOICE,"sounds/pu/powerup.wav",0.6,ATTN_NORM);
sound(new_powerup,CHAN_AUTO,"sounds/pu/drop.wav",1,ATTN_NONE);
//========================================================
// Specific Power-Ups (for dogs)
if (type) {
setmodel(new_powerup, getPowerupModel(type));
new_powerup.zombie_drop_id = type;
new_powerup.powerup_vo = getPowerupVO(type);
} else {
// Grab a powerup ID
id = GetPowerupID();
// Should perk drops be individual?
if (id == 6) {
// Yes!
if (random() > (1/2)) {
// Set Style and make light Blue to symbolize it is an individual drop
// TODO: Make a sprite too??
new_powerup.style = 1;
Light_None(new_powerup);
Light_Blue(new_powerup);
}
// No!
else {
// failsafe
new_powerup.style = 0;
}
}
// finally, assign the id and model to our id.
setmodel(new_powerup, getPowerupModel(id));
new_powerup.zombie_drop_id = id;
new_powerup.powerup_vo = getPowerupVO(id);
}
last_pu = new_powerup.zombie_drop_id;
new_powerup.touch = powerup_touch;
new_powerup.think = powerup_flash;
new_powerup.nextthink = time + 21;
totalpowerups++;
}

View file

@ -0,0 +1,131 @@
/*
server/entities/sounds.qc
Sound Entities for Maps
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#define AMBIENT_SOUND_STATIC 0 // medium radius attenuation
#define AMBIENT_SOUND_EVERYWHERE 1
#define AMBIENT_SOUND_SMALLRADIUS 2
#define AMBIENT_SOUND_MEDIUMRADIUS 4
#define AMBIENT_SOUND_LARGERADIUS 8
#define AMBIENT_SOUND_START_SILENT 16
#define AMBIENT_SOUND_NOT_LOOPING 32
void() ambient_use =
{
// volume can only be between 0 - 1 in quake (maybe FTE supports higher.. not sure)
if (self.health > 1)
self.health = 1;
if (self.team == 1) {
if (self.spawnflags & AMBIENT_SOUND_NOT_LOOPING) {
sound(self, CHAN_VOICE, self.message, self.health, self.stance);
}
else {
sound(self, CHAN_VOICE, self.message, self.health, self.stance);
ambientsound(self.origin, self.message, self.health, self.stance);
}
self.team = 0;
}
else
{
if (self.spawnflags & AMBIENT_SOUND_NOT_LOOPING) {
sound (self, CHAN_VOICE, self.message, 0, self.stance);
}
else {
sound (self, CHAN_VOICE, self.message, 0, self.stance);
ambientsound (self.origin, self.message, 0, self.stance);
}
self.team = 1;
}
self.use = SUB_Null;
};
void () ambient_generic =
{
local string link;
// moto - FIXME: typically this is set to upper-case but NX and PSP lack strtoupper(); assume lower-case!
link = self.message;
if (link == "nolink") {
if (substring(self.message, 0, 1) == "*")
self.message = substring(self.message , 1, strlen(self.message));
if (substring(self.message , 0, 1) == "!" || substring(self.message , 0, 1) == "*") {
remove(self);
return;
}
else
precache_sound(self.message);
}
else {
// append sounds/ if absent
if (substring(self.message, 0, 7) != "sounds/")
self.message = strcat("sounds/", self.message);
// always assume .wav extension..
precache_sound(self.message);
}
if (self.spawnflags & AMBIENT_SOUND_SMALLRADIUS)
self.stance = ATTN_IDLE;
else if (self.spawnflags & AMBIENT_SOUND_MEDIUMRADIUS)
self.stance = ATTN_STATIC;
else if (self.spawnflags & AMBIENT_SOUND_LARGERADIUS)
self.stance = ATTN_NORM;
else if (self.spawnflags & AMBIENT_SOUND_EVERYWHERE)
self.stance = ATTN_NONE;
else
self.stance = ATTN_STATIC;
if (self.health == 0) // final vol
self.health = 1;
if (self.spawnflags & AMBIENT_SOUND_START_SILENT)
self.team = 1;
else
ambientsound(self.origin, self.message, self.health, self.stance);
self.use = ambient_use;
};
//
// ambient_bgm() conversion
//
void() ambient_bgm =
{
// play everywhere
self.spawnflags = 1;
// sound to loop
self.message = self.noise2;
// call ambient_generic()
ambient_generic();
}

View file

@ -0,0 +1,367 @@
/*
server/entities/sub_functions.qc
entity/server utility subroutines
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
/*
==============================
SUB_UseTargets
the global "activator" should be set to the entity that initiated the firing.
If self.delay is set, a DelayedUse entity will be created that will actually
do the SUB_UseTargets after that many seconds have passed.
Centerprints any self.message to the activator.
Removes all entities with a targetname that match self.killtarget,
and removes them, so some events can remove other triggers.
Search for (string)targetname in all entities that
match (string)self.target and call their .use function
==============================
*/
void() SUB_UseTargets;
void(vector tdest, float tspeed, void() func) SUB_CalcMove;
void() SUB_CalcMoveDone;
void() DelayThink =
{
activator = self.enemy;
SUB_UseTargets ();
remove(self);
};
void() SUB_UseTargets =
{
local entity t, stemp, otemp, act;
float tempcount, temptotal, breakthis;
string tempstring;
tempstring = "";
temptotal = 0;
tempcount = 0;
breakthis = false;
if (self.target2)
tempcount = tempcount + 1;
if (self.target3)
tempcount = tempcount + 1;
if (self.target4)
tempcount = tempcount + 1;
if (self.target5)
tempcount = tempcount + 1;
if (self.target6)
tempcount = tempcount + 1;
if (self.target7)
tempcount = tempcount + 1;
if (self.target8)
tempcount = tempcount + 1;
while(tempcount > temptotal)
{
temptotal = temptotal + 1;
if (temptotal == 1)
tempstring = self.target;
if (temptotal == 2)
tempstring = self.target2;
if (temptotal == 3)
tempstring = self.target3;
if (temptotal == 4)
tempstring = self.target4;
if (temptotal == 5)
tempstring = self.target5;
if (temptotal == 6)
tempstring = self.target6;
if (temptotal == 7)
tempstring = self.target7;
if (temptotal == 8)
tempstring = self.target8;
//
// check for a delay
//
if (self.delay)
{
// create a temp object to fire at a later time
t = spawn();
t.classname = "DelayedUse";
t.nextthink = time + self.delay;
t.think = DelayThink;
t.enemy = activator;
t.message = self.message;
t.killtarget = self.killtarget;
t.target = self.target;
t.target2 = self.target2;
t.target3 = self.target3;
t.target4 = self.target4;
t.target5 = self.target5;
t.target6 = self.target6;
t.target7 = self.target7;
t.target8 = self.target8;
return;
}
//
// print the message
//
if (activator.classname == "player" && self.message != "")
{
centerprint (activator, self.message);
}
//
// kill the killtagets
//
if (self.killtarget)
{
t = world;
do
{
t = find (t, targetname, self.killtarget);
if (!t)
breakthis = true;
remove (t);
} while (!breakthis);
}
//
// fire targets
//
if (tempstring)
{
act = activator;
t = find (world, targetname, tempstring);
breakthis = 0;
while (!breakthis)
{
if (!t)
{
breakthis = true;
}
stemp = self;
otemp = other;
self = t;
other = stemp;
if (t.classname == "spawn_zombie_in")
{
t.classname = "spawn_zombie";
}
if (t.classname == "waypoint_s")
{
t.classname = "waypoint_s";
}
if (t.classname == "spawn_dog_in")
t.classname = "spawn_dog";
if (self.use != SUB_Null)
{
if (self.use)
self.use();
}
self = stemp;
other = otemp;
activator = act;
t = find (t, targetname, tempstring);
}
}
}
};
/*
=============
SUB_CalcAngleMove
calculate self.avelocity and self.nextthink to reach destangle from
self.angles rotating
The calling function should make sure self.think is valid
===============
*/
void SUB_CalcAngleMove (vector destangle, float tspeed, void() func);
void(entity ent, vector destangle, float tspeed, void() func) SUB_CalcAngleMoveEnt =
{
local entity stemp;
stemp = self;
self = ent;
SUB_CalcAngleMove (destangle, tspeed, func);
self = stemp;
};
void SUB_CalcAngleMoveDone (void)
{
// After rotating, set angle to exact final angle
self.angles = self.finalangle;
self.avelocity = '0 0 0';
self.nextthink = -1;
if (self.think1)
self.think1 ();
}
void SUB_CalcAngleMove (vector destangle, float tspeed, void() func)
{
vector delta;
float traveltime;
if (!tspeed)
objerror ("No speed is defined!");
delta = destangle - self.angles;
traveltime = vlen (delta) / tspeed;
self.avelocity = delta * (1 / traveltime);
self.think1 = func;
self.finalangle = destangle;
self.think = SUB_CalcAngleMoveDone;
self.nextthink = self.ltime + traveltime;
}
/*
=============
SUB_CalcMove
calculate self.velocity and self.nextthink to reach dest from
self.origin traveling at speed
===============
*/
void(entity ent, vector tdest, float tspeed, void() func) SUB_CalcMoveEnt =
{
local entity stemp;
stemp = self;
self = ent;
SUB_CalcMove (tdest, tspeed, func);
self = stemp;
};
void(vector tdest, float tspeed, void() func) SUB_CalcMove =
{
local vector vdestdelta;
local float len, traveltime;
if (!tspeed)
objerror("No speed is defined!");
self.think1 = func;
self.finaldest = tdest;
self.think = SUB_CalcMoveDone;
if (tdest == self.origin)
{
self.velocity = '0 0 0';
self.nextthink = self.ltime + 0.1;
return;
}
// set destdelta to the vector needed to move
vdestdelta = tdest - self.origin;
// calculate length of vector
len = vlen (vdestdelta);
// divide by speed to get time to reach dest
traveltime = len / tspeed;
if (traveltime < 0.1)
{
self.velocity = '0 0 0';
self.nextthink = self.ltime + 0.1;
return;
}
// set nextthink to trigger a think when dest is reached
self.nextthink = self.ltime + traveltime;
// scale the destdelta vector by the time spent traveling to get velocity
self.velocity = vdestdelta * (1/traveltime); // qcc won't take vec/float
};
/*
============
After moving, set origin to exact final destination
============
*/
void() SUB_CalcMoveDone =
{
setorigin(self, self.finaldest);
self.velocity = '0 0 0';
self.nextthink = -1;
if (self.think1)
self.think1();
};
#ifdef PC
//
// HalfLife_DoRender()
// Adds some support for HL rendermodes to FTE, made by
// autonomous1 for 'quakelife'
//
// Do *some* of the half-life render stuff.
void () HalfLife_DoRender =
{
local vector osize, omins, omaxs, oabsmin, oabsmax;
if (self.rendercolor != '0 0 0') {} // ADDME
if (self.rendermode > 0)
if (self.renderamt > 0) {
self.alpha = self.renderamt/255;
if (self.alpha == 0)
self.alpha = .01;
}
else {
self.rendermode = 2;
}
if (self.rendermode == 2) {
self.alpha = self.renderamt/255;
if (self.alpha == 0) {
//self.alpha = 0.01;
osize = self.size;
omins = self.mins;
omaxs = self.maxs;
oabsmin = self.absmin;
oabsmax = self.absmax;
if (self.solid == SOLID_BSP) {
self.solid = SOLID_BBOX;
}
//setmodel(self, string_null);
self.size = osize;
self.mins = omins;
self.maxs = omaxs;
self.absmin = oabsmin;
self.absmax = oabsmax;
//setorigin(self, self.origin);
}
}
};
#endif

View file

@ -0,0 +1,344 @@
/*
server/entities/triggers.qc
Misc. Trigger functions
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#define SPAWNFLAG_NOMESSAGE 1
#define SPAWNFLAG_NOTOUCH 1
// the wait time has passed, so set back up for another activation
void() multi_wait =
{
if (self.max_health)
{
self.health = self.max_health;
self.takedamage = DAMAGE_YES;
self.solid = SOLID_BBOX;
}
};
// the trigger was just touched/killed/used
// self.enemy should be set to the activator so it can be held through a delay
// so wait for the delay time before firing
void() multi_trigger =
{
if (self.nextthink > time)
{
return; // already been triggered
}
if (self.noise)
sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM);
// don't trigger again until reset
self.takedamage = DAMAGE_NO;
activator = self.enemy;
SUB_UseTargets();
if (self.wait > 0)
{
self.think = multi_wait;
self.nextthink = time + self.wait;
}
else
{
// we can't just remove(self) here, because this is a touch function
// called while C code is looping through area links...
self.touch = SUB_Null;
self.nextthink = time + 0.1;
self.think = SUB_Remove;
}
};
void() multi_killed =
{
// motolegacy - FIXME
//self.enemy = damage_attacker;
multi_trigger();
};
void() multi_use =
{
self.enemy = activator;
multi_trigger();
};
void() multi_touch =
{
if (other.classname != "player")
return;
// if the trigger has an angles field, check player's facing direction
if (self.movedir != '0 0 0')
{
makevectors (other.angles);
if (v_forward * self.movedir < 0)
return; // not facing the right way
}
self.enemy = other;
multi_trigger();
};
void() SetMovedir =
{
if (self.angles == '0 -1 0')
self.movedir = '0 0 1';
else if (self.angles == '0 -2 0')
self.movedir = '0 0 -1';
else
{
makevectors (self.angles);
self.movedir = v_forward;
}
self.angles = '0 0 0';
};
void() InitTrigger =
{
// trigger angles are used for one-way touches. An angle of 0 is assumed
// to mean no restrictions, so use a yaw of 360 instead.
if (self.angles != '0 0 0')
SetMovedir ();
self.solid = SOLID_TRIGGER;
setmodel (self, self.model); // set size and link into world
self.movetype = MOVETYPE_NONE;
self.modelindex = 0;
self.model = "";
};
#ifndef PSP
entity last_act_trigger;
void() trigger_activator_touch =
{
other.cost = other.cost +1; //hack, we can only touch one of thease at the time
if (other.classname != "player" || last_act_trigger == self || other.cost > 1)
return;
last_act_trigger = self;
entity t;
float tempcount, temptotal,breakthis;
string tempstring;
temptotal = 0;
breakthis = 0;
tempcount = 1;
tempstring = "";
t = world;
do
{
t = find (t, classname, "spawn_zombie");
if (!t)
{
breakthis = 1;
}
if (t.classname == "spawn_zombie")
{
t.classname = "spawn_zombie_away";
/*if (cvar("developer"))
setmodel(t, "progs/player.mdl");*/
}
} while (!breakthis);
if (self.target2)
tempcount =+ 1;
if (self.target3)
tempcount =+ 1;
if (self.target4)
tempcount =+ 1;
if (self.target5)
tempcount =+ 1;
if (self.target6)
tempcount =+ 1;
if (self.target7)
tempcount =+ 1;
if (self.target8)
tempcount =+ 1;
if (self.target2)
tempcount = tempcount + 1;
if (self.target3)
tempcount = tempcount + 1;
if (self.target4)
tempcount = tempcount + 1;
if (self.target5)
tempcount = tempcount + 1;
if (self.target6)
tempcount = tempcount + 1;
if (self.target7)
tempcount = tempcount + 1;
if (self.target8)
tempcount = tempcount + 1;
while(tempcount > temptotal)
{
temptotal = temptotal + 1;
if (temptotal == 1)
tempstring = self.target;
if (temptotal == 2)
tempstring = self.target2;
if (temptotal == 3)
tempstring = self.target3;
if (temptotal == 4)
tempstring = self.target4;
if (temptotal == 5)
tempstring = self.target5;
if (temptotal == 6)
tempstring = self.target6;
if (temptotal == 7)
tempstring = self.target7;
if (temptotal == 8)
tempstring = self.target8;
if (tempstring)
{
t = find (world, targetname, tempstring);
breakthis = 0;
while (!breakthis)
{
if (!t)
{
breakthis = true;
}
if (t.classname == "spawn_zombie_away")
{
t.classname = "spawn_zombie";
/*if (cvar("developer"))
setmodel(t, "progs/ai/zfull.mdl");*/
}
t = find (t, targetname, tempstring);
}
}
}
}
void() trigger_activator =
{
InitTrigger ();
self.touch = trigger_activator_touch;
}
#endif
void() use_wall_weapon =
{
if (self.enemy)
return;
entity newent;
newent = spawn();
newent.movetype = MOVETYPE_NONE; // so it doesn't get pushed by anything
newent.solid=SOLID_NOT;
newent.classname = "wall_weapon";
setorigin(newent, self.origin);
setmodel (newent, GetWeaponModel(self.sequence + 1, 1));
setsize (newent, VEC_HULL2_MIN, VEC_HULL2_MAX);
newent.angles = self.angles;
self.enemy = newent;
}
void() weapon_wall =
{
precache_model ("models/misc/chalk.mdl");
setmodel (self, "models/misc/chalk.mdl");
self.skin = 0;
setsize (self, VEC_HULL2_MIN, VEC_HULL2_MAX);
self.frame = self.sequence;
self.use = use_wall_weapon;
self.classname = "weapon_wall";
//self.effects = EF_WEPLIGHT;
}
/* ===================
Custom Teddy Triggers
===================*/
void() teddy_react =
{
local entity t;
if (self.spawnflags & 1) {
t = find (world, teddyremovetarget, self.target);
if (t)
remove(t);
}
remove(self); //this was present in the patch, i like it.
}
/*
Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time.
If "delay" is set, the trigger waits some time after activating before firing.
"wait" : Seconds between triggerings. (.2 default)
If notouch is set, the trigger is only fired by other entities, not by touching.
NOTOUCH has been obsoleted by trigger_relay!
set "message" to text string
*/
void() trigger_multiple =
{
if (!self.wait)
self.wait = 0.2;
self.use = multi_use;
InitTrigger ();
if(self.health)
{
if (self.spawnflags & SPAWNFLAG_NOTOUCH)
objerror("health and notouch don't make sense\n");
self.max_health = self.health;
self.th_die = multi_killed;
self.takedamage = DAMAGE_YES;
self.solid = SOLID_BBOX;
setorigin(self, self.origin); // make sure it links into the world
}
else
{
if (!(self.spawnflags & SPAWNFLAG_NOTOUCH))
{
self.touch = multi_touch;
}
}
};
/*
Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching
"targetname". If "health" is set, the trigger must be killed to activate.
If notouch is set, the trigger is only fired by other entities, not by touching.
if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0.
set "message" to text string
*/
void() trigger_once =
{
self.wait = -1;
trigger_multiple();
}

View file

@ -0,0 +1,379 @@
/*
server/entities/window.qc
barricades
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
.float rebuild_time;
void() spawn_boxes =
{
makevectors(self.angles);
self.box1 = self.origin + (v_forward * -30) + (v_up * -32);
self.box2 = self.box1 + (v_right * 30);
self.box3 = self.box1 + (v_right * -30);
self.idlebox = self.box1 + (v_forward * -30);
self.hop_spot = self.origin + v_forward * 40;
self.hop_spot_z -= 30;//We want this to be a little bit above the ground still
};
void() screen_shake =
{
local float r,s,zoom_factor;
r = crandom();
s = random();
if (self.enemy.zoom == 2 || self.enemy.zoom == 1)
zoom_factor = 0.5;
else
zoom_factor = 1;
#ifdef PSP
self.enemy.punchangle_y = r * 8 * zoom_factor;
self.enemy.punchangle_x = (4 + (s * 4)) * zoom_factor;
#else
self.enemy.punchangle_y = r * 4 * zoom_factor;
self.enemy.punchangle_x = (4 + (s * 2)) * zoom_factor;
#endif
};
void() Window_repaired =
{
if (maxreward > totalreward)
{
sound(self, 0,"sounds/misc/ching.wav", 1, 0);
addmoney(self.enemy, 10, 1);
totalreward = totalreward + 10;
}
screen_shake();
self.enemy = world;
};
void() Barricade_hit_window =
{
sound(self, 0, self.oldmodel, 1, 0);
}
void(void() next) checkForSpeed = {
if (!(other.perks & P_SPEED))
return;
next();
}
//////////////////////////////////////////////////////////////////////////////////////////// ANIMATIONS
//0-6
//7-13
//14-20
//21-27
//28-34
//35-41
void() window_anim1_1 =[ 1, window_anim1_2 ] {self.frame = 0;self.nextthink = time + 0.05;};
void() window_anim1_2 =[ 2, window_anim1_3 ] {self.frame = 1;self.nextthink = time + 0.05;};
void() window_anim1_3 =[ 3, window_anim1_4 ] {self.frame = 2;self.nextthink = time + 0.05;};
void() window_anim1_4 =[ 4, window_anim1_5 ] {self.frame = 3;self.nextthink = time + 0.05;};
void() window_anim1_5 =[ 5, window_anim1_6 ] {self.frame = 4;self.nextthink = time + 0.05;};
void() window_anim1_6 =[ 6, window_anim1_7 ] {self.frame = 5;self.nextthink = time + 0.05;};
void() window_anim1_7 =[ 7, SUB_Null ] {self.frame = 6;self.nextthink = time + 0.05;};
void() window_anim2_1 =[ 1, window_anim2_2 ] {self.frame = 7;self.nextthink = time + 0.05;};
void() window_anim2_2 =[ 2, window_anim2_3 ] {self.frame = 8;self.nextthink = time + 0.05;};
void() window_anim2_3 =[ 3, window_anim2_4 ] {self.frame = 9;self.nextthink = time + 0.05;};
void() window_anim2_4 =[ 4, window_anim2_5 ] {self.frame = 10;self.nextthink = time + 0.05;};
void() window_anim2_5 =[ 5, window_anim2_6 ] {self.frame = 11;self.nextthink = time + 0.05;};
void() window_anim2_6 =[ 6, window_anim2_7 ] {self.frame = 12;self.nextthink = time + 0.05;};
void() window_anim2_7 =[ 7, SUB_Null ] {self.frame = 13;self.nextthink = time + 0.05;};
void() window_anim3_1 =[ 1, window_anim3_2 ] {self.frame = 14;self.nextthink = time + 0.05;};
void() window_anim3_2 =[ 2, window_anim3_3 ] {self.frame = 15;self.nextthink = time + 0.05;};
void() window_anim3_3 =[ 3, window_anim3_4 ] {self.frame = 16;self.nextthink = time + 0.05;};
void() window_anim3_4 =[ 4, window_anim3_5 ] {self.frame = 17;self.nextthink = time + 0.05;};
void() window_anim3_5 =[ 5, window_anim3_6 ] {self.frame = 18;self.nextthink = time + 0.05;};
void() window_anim3_6 =[ 6, window_anim3_7 ] {self.frame = 19;self.nextthink = time + 0.05;};
void() window_anim3_7 =[ 7, SUB_Null ] {self.frame = 20;self.nextthink = time + 0.05;};
void() window_anim4_1 =[ 1, window_anim4_2 ] {self.frame = 21;self.nextthink = time + 0.05;};
void() window_anim4_2 =[ 2, window_anim4_3 ] {self.frame = 22;self.nextthink = time + 0.05;};
void() window_anim4_3 =[ 3, window_anim4_4 ] {self.frame = 23;self.nextthink = time + 0.05;};
void() window_anim4_4 =[ 4, window_anim4_5 ] {self.frame = 24;self.nextthink = time + 0.05;};
void() window_anim4_5 =[ 5, window_anim4_6 ] {self.frame = 25;self.nextthink = time + 0.05;};
void() window_anim4_6 =[ 6, window_anim4_7 ] {self.frame = 26;self.nextthink = time + 0.05;};
void() window_anim4_7 =[ 7, SUB_Null ] {self.frame = 27;self.nextthink = time + 0.05;};
void() window_anim5_1 =[ 1, window_anim5_2 ] {self.frame = 28;self.nextthink = time + 0.05;};
void() window_anim5_2 =[ 2, window_anim5_3 ] {self.frame = 29;self.nextthink = time + 0.05;};
void() window_anim5_3 =[ 3, window_anim5_4 ] {self.frame = 30;self.nextthink = time + 0.05;};
void() window_anim5_4 =[ 4, window_anim5_5 ] {self.frame = 31;self.nextthink = time + 0.05;};
void() window_anim5_5 =[ 5, window_anim5_6 ] {self.frame = 32;self.nextthink = time + 0.05;};
void() window_anim5_6 =[ 6, window_anim5_7 ] {self.frame = 33;self.nextthink = time + 0.05;};
void() window_anim5_7 =[ 7, SUB_Null ] {self.frame = 34;self.nextthink = time + 0.05;};
void() window_anim6_1 =[ 1, window_anim6_2 ] {self.frame = 35;self.nextthink = time + 0.05;};
void() window_anim6_2 =[ 2, window_anim6_3 ] {self.frame = 36;self.nextthink = time + 0.05;};
void() window_anim6_3 =[ 3, window_anim6_4 ] {self.frame = 37;self.nextthink = time + 0.05;};
void() window_anim6_4 =[ 4, window_anim6_5 ] {self.frame = 38;self.nextthink = time + 0.05;};
void() window_anim6_5 =[ 5, window_anim6_6 ] {self.frame = 39;self.nextthink = time + 0.05;};
void() window_anim6_6 =[ 6, window_anim6_7 ] {self.frame = 40;self.nextthink = time + 0.05;};
void() window_anim6_7 =[ 7, SUB_Null ] {self.frame = 41;self.nextthink = time + 0.05;};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//speed cola repair
//81-88
void() window_srepair1_1 =[ 1, window_srepair1_2 ] {self.frame = 81;};
void() window_srepair1_2 =[ 2, window_srepair1_4 ] {self.frame = 84;};
void() window_srepair1_4 =[ 3, window_srepair1_5 ] {self.frame = 87;Barricade_hit_window();};
void() window_srepair1_5 =[ 4, SUB_Null ] {self.frame = 88; Window_repaired();};
//73-80
void() window_srepair2_1 =[ 1, window_srepair2_2 ] {self.frame = 73;};
void() window_srepair2_2 =[ 2, window_srepair2_4 ] {self.frame = 75;};
void() window_srepair2_4 =[ 3, window_srepair2_5 ] {self.frame = 79;Barricade_hit_window();};
void() window_srepair2_5 =[ 4, SUB_Null ] {self.frame = 80; Window_repaired();};
//65-72
void() window_srepair3_1 =[ 1, window_srepair3_2 ] {self.frame = 65;};
void() window_srepair3_2 =[ 2, window_srepair3_4 ] {self.frame = 67;};
void() window_srepair3_4 =[ 3, window_srepair3_5 ] {self.frame = 71;Barricade_hit_window();};
void() window_srepair3_5 =[ 4, SUB_Null ] {self.frame = 72; Window_repaired();};
//57-64
void() window_srepair4_1 =[ 1, window_srepair4_2 ] {self.frame = 57;};
void() window_srepair4_2 =[ 2, window_srepair4_4 ] {self.frame = 69;};
void() window_srepair4_4 =[ 3, window_srepair4_5 ] {self.frame = 63;Barricade_hit_window();};
void() window_srepair4_5 =[ 4, SUB_Null ] {self.frame = 64; Window_repaired();};
//49-56
void() window_srepair5_1 =[ 1, window_srepair5_2 ] {self.frame = 49;};
void() window_srepair5_2 =[ 2, window_srepair5_4 ] {self.frame = 51;};
void() window_srepair5_4 =[ 3, window_srepair5_5 ] {self.frame = 55;Barricade_hit_window();};
void() window_srepair5_5 =[ 4, SUB_Null ] {self.frame = 56; Window_repaired();};
//41-48
void() window_srepair6_1 =[ 1, window_srepair6_2 ] {self.frame = 41;};
void() window_srepair6_2 =[ 2, window_srepair6_4 ] {self.frame = 43;};
void() window_srepair6_4 =[ 3, window_srepair6_5 ] {self.frame = 47;Barricade_hit_window();};
void() window_srepair6_5 =[ 4, SUB_Null ] {self.frame = 48; Window_repaired();};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void() window_repair1_1 =[ 1, window_repair1_2 ] {self.frame = 81;};
void() window_repair1_2 =[ 2, window_repair1_3 ] {self.frame = 82;};
void() window_repair1_3 =[ 3, window_repair1_4 ] {self.frame = 83;};
void() window_repair1_4 =[ 4, window_repair1_5 ] {self.frame = 84;};
void() window_repair1_5 =[ 5, window_repair1_6 ] {self.frame = 85;};
void() window_repair1_6 =[ 6, window_repair1_7 ] {self.frame = 86;};
void() window_repair1_7 =[ 7, window_repair1_8 ] {self.frame = 87;Barricade_hit_window();};
void() window_repair1_8 =[ 8, SUB_Null ] {self.frame = 88; Window_repaired();};
void() window_repair2_1 =[ 1, window_repair2_2 ] {self.frame = 73;};
void() window_repair2_2 =[ 2, window_repair2_3 ] {self.frame = 74;};
void() window_repair2_3 =[ 3, window_repair2_4 ] {self.frame = 75;};
void() window_repair2_4 =[ 4, window_repair2_5 ] {self.frame = 76;};
void() window_repair2_5 =[ 5, window_repair2_6 ] {self.frame = 77;};
void() window_repair2_6 =[ 6, window_repair2_7 ] {self.frame = 78;};
void() window_repair2_7 =[ 7, window_repair2_8 ] {self.frame = 79;Barricade_hit_window();};
void() window_repair2_8 =[ 8, SUB_Null ] {self.frame = 80; Window_repaired();};
void() window_repair3_1 =[ 1, window_repair3_2 ] {self.frame = 65;};
void() window_repair3_2 =[ 2, window_repair3_3 ] {self.frame = 66;};
void() window_repair3_3 =[ 3, window_repair3_4 ] {self.frame = 67;};
void() window_repair3_4 =[ 4, window_repair3_5 ] {self.frame = 68;};
void() window_repair3_5 =[ 5, window_repair3_6 ] {self.frame = 69;};
void() window_repair3_6 =[ 6, window_repair3_7 ] {self.frame = 70;};
void() window_repair3_7 =[ 7, window_repair3_8 ] {self.frame = 71;Barricade_hit_window();};
void() window_repair3_8 =[ 8, SUB_Null ] {self.frame = 72; Window_repaired();};
void() window_repair4_1 =[ 1, window_repair4_2 ] {self.frame = 57;};
void() window_repair4_2 =[ 2, window_repair4_3 ] {self.frame = 58;};
void() window_repair4_3 =[ 3, window_repair4_4 ] {self.frame = 59;};
void() window_repair4_4 =[ 4, window_repair4_5 ] {self.frame = 60;};
void() window_repair4_5 =[ 5, window_repair4_6 ] {self.frame = 61;};
void() window_repair4_6 =[ 6, window_repair4_7 ] {self.frame = 62;};
void() window_repair4_7 =[ 7, window_repair4_8 ] {self.frame = 63;Barricade_hit_window();};
void() window_repair4_8 =[ 8, SUB_Null ] {self.frame = 64; Window_repaired();};
void() window_repair5_1 =[ 1, window_repair5_2 ] {self.frame = 49;};
void() window_repair5_2 =[ 2, window_repair5_3 ] {self.frame = 50;};
void() window_repair5_3 =[ 3, window_repair5_4 ] {self.frame = 51;};
void() window_repair5_4 =[ 4, window_repair5_5 ] {self.frame = 52;};
void() window_repair5_5 =[ 5, window_repair5_6 ] {self.frame = 53;};
void() window_repair5_6 =[ 6, window_repair5_7 ] {self.frame = 54;};
void() window_repair5_7 =[ 7, window_repair5_8 ] {self.frame = 55;Barricade_hit_window();};
void() window_repair5_8 =[ 8, SUB_Null ] {self.frame = 56; Window_repaired();};
void() window_repair6_1 =[ 1, window_repair6_2 ] {self.frame = 41;};
void() window_repair6_2 =[ 2, window_repair6_3 ] {self.frame = 42;};
void() window_repair6_3 =[ 3, window_repair6_4 ] {self.frame = 43;};
void() window_repair6_4 =[ 4, window_repair6_5 ] {self.frame = 44;};
void() window_repair6_5 =[ 5, window_repair6_6 ] {self.frame = 45;};
void() window_repair6_6 =[ 6, window_repair6_7 ] {self.frame = 46;};
void() window_repair6_7 =[ 7, window_repair6_8 ] {self.frame = 47;Barricade_hit_window();};
void() window_repair6_8 =[ 8, SUB_Null ] {self.frame = 48; Window_repaired();};
void() window_carpenter_1 =[ 1, window_carpenter_2 ] {self.frame = 47;sound(self, 0, self.oldmodel, 1, 1);};
void() window_carpenter_2 =[ 2, window_carpenter_3 ] {self.frame = 48;};
void() window_carpenter_3 =[ 3, window_carpenter_4 ] {self.frame = 55;sound(self, 1, self.oldmodel, 1, 1);};
void() window_carpenter_4 =[ 4, window_carpenter_5 ] {self.frame = 56;};
void() window_carpenter_5 =[ 5, window_carpenter_6 ] {self.frame = 63;sound(self, 2, self.oldmodel, 1, 1);};
void() window_carpenter_6 =[ 6, window_carpenter_7 ] {self.frame = 64;};
void() window_carpenter_7 =[ 7, window_carpenter_8 ] {self.frame = 71;sound(self, 0, self.oldmodel, 1, 1);};
void() window_carpenter_8 =[ 8, window_carpenter_9 ] {self.frame = 72;};
void() window_carpenter_9 =[ 7, window_carpenter_10 ] {self.frame = 79;sound(self, 1, self.oldmodel, 1, 1);};
void() window_carpenter_10 =[ 8, window_carpenter_11 ] {self.frame = 80;};
void() window_carpenter_11 =[ 7, window_carpenter_12 ] {self.frame = 87;sound(self, 2, self.oldmodel, 1, 1);};
void() window_carpenter_12 =[ 8, SUB_Null ] {self.frame = 88;};
void() Window_Damage =
{
if(self.health == 0)
return;
sound(self, CHAN_VOICE, self.aistatus, 1, 0);
self.health = self.health - 1;
if(self.health == 5)
{
window_anim1_1();
total_windows_down = total_windows_down + 1;
}
else if(self.health == 4)
window_anim2_1();
else if(self.health == 3)
window_anim3_1();
else if(self.health == 2)
window_anim4_1();
else if(self.health == 1)
window_anim5_1();
else if(self.health == 0)
window_anim6_1();
ach_tracker_spin = 1;
};
void() Rebuild_Anims =
{
if(self.health == 5)
{
if (other.perks & P_SPEED)
window_srepair1_1();
else
window_repair1_1();
total_windows_down = total_windows_down - 1;
}
else if(self.health == 4)
{
if (other.perks & P_SPEED)
window_srepair2_1();
else
window_repair2_1();
}
else if(self.health == 3)
{
if (other.perks & P_SPEED)
window_srepair3_1();
else
window_repair3_1();
}
else if(self.health == 2)
{
if (other.perks & P_SPEED)
window_srepair4_1();
else
window_repair4_1();
}
else if(self.health == 1)
{
if (other.perks & P_SPEED)
window_srepair5_1();
else
window_repair5_1();
}
else if(self.health == 0)
{
if (other.perks & P_SPEED)
window_srepair6_1();
else
window_repair6_1();
}
};
void() window_touch =
{
if(other.classname == "player" && !other.downed && self.health != -10)
{
if(self.health < 6)
{
useprint (other, 5, 0, 0);
if(other.button7)
{
if(self.rebuild_time < time)
{
self.enemy = other;
Rebuild_Anims();
self.health = self.health + 1;
self.rebuild_time = time + 0.75;
}
}
}
}
};
void() item_barricade =
{
if (self.spawnflags & 1) {
self.health = -10; // Window is deactivated, to only hop over it
} else {
if (!self.model)
self.model = "models/misc/window.mdl";
if (!self.oldmodel)
self.oldmodel = "sounds/misc/barricade.wav";
if (!self.aistatus)
self.aistatus = "sounds/misc/barricade_destroy.wav";
precache_model(self.model);
precache_sound(self.oldmodel);
precache_sound(self.aistatus);
}
self.classname = "window";
self.touch = window_touch;
self.solid = SOLID_TRIGGER;
if (self.health != -10) {
self.health = 6;
setmodel(self, self.model);
}
setsize(self, '-20 -20 -64', '20 20 16');
setorigin(self, self.origin);
spawn_boxes();
#ifndef PC
windows[wincnt] = self;
wincnt++;
#endif
};
void() item_cover = {item_barricade();};

3
source/server/items.qc Normal file
View file

@ -0,0 +1,3 @@
//
// Items.qc - all the definitions for item spawn functions as well as other functions related to them
//

521
source/server/main.qc Normal file
View file

@ -0,0 +1,521 @@
/*
server/main.qc
mostly functions that will be called from the engine and are
expected to exist
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
void() LightStyles_setup;
void() SUB_Remove = {remove(self);}
//called when starting server/loading the map
void() main =
{
localcmd("echo Server starting...\n");
}
//called for each frame that QC runs
float zombie_cleaned_w;
void() StartFrame =
{
deathmatch = cvar("deathmatch");
//coop = cvar("coop");
framecount = framecount + 1;
if (waypoint_mode) {
if (!zombie_cleaned_w) {
entity zent;
zent = find (world, classname, "ai_zombie");
while (zent)
{
/*
if (zent.head)
remove (zent.head);
if (zent.larm)
remove (zent.larm);
if (zent.rarm)
remove (zent.rarm);
*/
remove (zent);
zent = find (zent, classname, "ai_zombie");
}
zombie_cleaned_w = true;
zent = find (world, classname, "waypoint");
while (zent)
{
if (zent.targetname)
setmodel(zent, "models/way/normal_way_door.spr");
else
setmodel(zent, "models/way/normal_way.spr");
zent = find (zent, classname, "waypoint");
}
zent = find (world, classname, "door_nzp_cost");
while (zent)
{
zent.solid = SOLID_NOT;
zent.touch = SUB_Null;
zent = find (zent, classname, "door_nzp_cost");
}
zent = find (world, classname, "door_nzp");
while (zent)
{
zent.solid = SOLID_NOT;
zent.touch = SUB_Null;
zent.solid = SOLID_NOT;
zent = find (zent, classname, "door_nzp");
}
zent = find (world, classname, "window");
while (zent)
{
zent.solid = SOLID_NOT;
zent.touch = SUB_Null;
zent = find (zent, classname, "window");
}
}
return;
}
if (roundinit) {
Round_Core();
Do_Zombie_AI ();
} else {
entity SpawnedIn;
SpawnedIn = find(world, classname, "player");
if (SpawnedIn) {
entity getdog = find(world, classname, "spawn_dog");
if (getdog)
gotdog = 1;
else
gotdog = 0;
updateDogRound();
InitRounds();
}
}
}
string(string s) precache_model = #20;
void() precaches =
{
precache_model ("models/player.mdl");
#ifndef PSP
#ifndef NX
if (world.song != "")
precache_sound (world.song);
#endif
#endif
//
// Models
//
// sprites
precache_model ("models/sprites/revive.spr");
precache_model ("models/sprites/revive_white.spr");
precache_model ("models/sprites/sprkle.spr");
precache_model ("models/sprites/lightning.spr");
precache_model ("models/way/current_way.spr");
precache_model ("models/way/current_way_door.spr");
precache_model ("models/way/last_way.spr");
precache_model ("models/way/last_way_door.spr");
precache_model ("models/way/normal_way.spr");
precache_model ("models/way/normal_way_door.spr");
precache_model ("models/way/way_jump.spr");
precache_model ("models/way/way_land.spr");
// zombie
precache_model ("models/ai/zfull.mdl");
precache_model ("models/ai/zlarm.mdl");
precache_model ("models/ai/zrarm.mdl");
precache_model ("models/ai/zbod.mdl");
precache_model ("models/ai/zhead.mdl");
// zombie crawler
precache_model ("models/ai/zcfull.mdl");
precache_model ("models/ai/zcbod.mdl");
precache_model ("models/ai/zclarm.mdl");
precache_model ("models/ai/zcrarm.mdl");
precache_model ("models/ai/zchead.mdl");
// powerups
precache_model ("models/pu/maxammo!.mdl");
precache_model ("models/pu/x2!.mdl");
precache_model ("models/pu/instakill!.mdl");
precache_model ("models/pu/nuke!.mdl");
precache_model ("models/pu/carpenter!.mdl");
precache_model ("models/pu/perkbottle!.mdl");
// start weapons
precache_model ("models/weapons/m1911/v_colt.mdl");
precache_model ("models/weapons/m1911/g_colt.mdl");
precache_model ("models/weapons/knife/v_knife.mdl");
precache_model ("models/weapons/grenade/v_grenade.mdl");
precache_model ("models/weapons/grenade/g_grenade.mdl");
precache_model ("models/weapons/grenade/g_betty.mdl");
precache_model ("models/weapons/grenade/v_betty.mdl");
precache_model ("models/weapons/morphine/v_morphine.mdl");
//
// Sounds
//
// player-made
precache_sound("sounds/player/footstep1.wav");
precache_sound("sounds/player/footstep2.wav");
precache_sound("sounds/player/footstep3.wav");
precache_sound("sounds/player/footstep4.wav");
precache_sound("sounds/player/footstep5.wav");
precache_sound("sounds/player/jump.wav");
precache_sound("sounds/player/land.wav");
precache_sound("sounds/player/pain4.wav");
// weapons
precache_sound("sounds/weapons/colt/magin.wav");
precache_sound("sounds/weapons/colt/magout.wav");
precache_sound("sounds/weapons/colt/shoot.wav");
precache_sound("sounds/weapons/colt/slide.wav");
precache_sound("sounds/weapons/papfire.wav");
// grenade
precache_sound("sounds/weapons/grenade/prime.wav");
precache_sound("sounds/weapons/grenade/throw.wav");
precache_sound("sounds/weapons/grenade/explode.wav");
// melee
precache_sound("sounds/weapons/knife/knife_hitbod.wav");
precache_sound("sounds/weapons/knife/knife.wav");
precache_sound("sounds/weapons/knife/knife_hit.wav");
// tunes
precache_sound("sounds/rounds/eround.wav");
precache_sound("sounds/rounds/nround.wav");
precache_sound("sounds/rounds/splash.wav");
precache_sound("sounds/music/end.wav");
// misc
precache_sound("sounds/misc/buy.wav");
precache_sound("sounds/misc/wood_door.wav");
precache_sound("sounds/misc/debris.wav");
precache_sound("sounds/misc/denybuy.wav");
precache_sound("sounds/misc/what.wav");
// power-ups
precache_sound ("sounds/pu/pickup.wav");
precache_sound ("sounds/pu/carpenter.wav");
precache_sound ("sounds/pu/maxammo.wav");
precache_sound ("sounds/pu/double_points.wav");
precache_sound ("sounds/pu/insta_kill.wav");
precache_sound ("sounds/pu/nuke.wav");
precache_sound ("sounds/pu/byebye.wav");
precache_sound ("sounds/pu/powerup.wav");
precache_sound ("sounds/pu/drop.wav");
// zombie walk
precache_sound ("sounds/zombie/w0.wav");
precache_sound ("sounds/zombie/w1.wav");
precache_sound ("sounds/zombie/w2.wav");
precache_sound ("sounds/zombie/w3.wav");
precache_sound ("sounds/zombie/w4.wav");
precache_sound ("sounds/zombie/w5.wav");
precache_sound ("sounds/zombie/w6.wav");
precache_sound ("sounds/zombie/w7.wav");
precache_sound ("sounds/zombie/w8.wav");
precache_sound ("sounds/zombie/w9.wav");
// zombie run
precache_sound ("sounds/zombie/r0.wav");
precache_sound ("sounds/zombie/r1.wav");
precache_sound ("sounds/zombie/r2.wav");
precache_sound ("sounds/zombie/r3.wav");
precache_sound ("sounds/zombie/r4.wav");
precache_sound ("sounds/zombie/r5.wav");
precache_sound ("sounds/zombie/r6.wav");
precache_sound ("sounds/zombie/r7.wav");
precache_sound ("sounds/zombie/r8.wav");
precache_sound ("sounds/zombie/r9.wav");
// zombie swipe
precache_sound ("sounds/zombie/a0.wav");
precache_sound ("sounds/zombie/a1.wav");
precache_sound ("sounds/zombie/a2.wav");
precache_sound ("sounds/zombie/a3.wav");
precache_sound ("sounds/zombie/a4.wav");
precache_sound ("sounds/zombie/a5.wav");
precache_sound ("sounds/zombie/a6.wav");
precache_sound ("sounds/zombie/a7.wav");
// zombie death
precache_sound ("sounds/zombie/d0.wav");
precache_sound ("sounds/zombie/d1.wav");
precache_sound ("sounds/zombie/d2.wav");
precache_sound ("sounds/zombie/d3.wav");
precache_sound ("sounds/zombie/d4.wav");
precache_sound ("sounds/zombie/d5.wav");
precache_sound ("sounds/zombie/d6.wav");
precache_sound ("sounds/zombie/d7.wav");
// zombie taunt
precache_sound ("sounds/zombie/t0.wav");
precache_sound ("sounds/zombie/t1.wav");
precache_sound ("sounds/zombie/t2.wav");
precache_sound ("sounds/zombie/t3.wav");
precache_sound ("sounds/zombie/t4.wav");
// zombie footsteps
precache_sound ("sounds/zombie/s0.wav");
precache_sound ("sounds/zombie/s1.wav");
precache_sound ("sounds/zombie/sc0.wav");
precache_sound ("sounds/zombie/sc1.wav");
// null
precache_sound("sounds/null.wav");
#ifdef PC
// Moto -- FIXME: compile FTE to remove this engine sound request
precache_sound ("demon/dland2.wav");
#endif
}
//called when map loaded
void() worldspawn =
{
precaches();
LightStyles_setup();
#ifdef PC
clientstat(STAT_CURRENTMAG, EV_FLOAT, currentmag);
clientstat(STAT_CURRENTMAG2, EV_FLOAT, currentmag2);
clientstat(STAT_POINTS, EV_FLOAT, points);
clientstat(STAT_WEAPON2FRAME, EV_FLOAT, weapon2frame);
clientstat(STAT_WEAPON2MODEL, EV_STRING, weapon2model);
clientstat(STAT_GRENADES, EV_FLOAT, primary_grenades);
clientstat(STAT_SECGRENADES, EV_FLOAT, secondary_grenades);
clientstat(STAT_PROGRESSBAR, EV_FLOAT, progress_bar_percent);
clientstat(STAT_WEAPONDURATION, EV_FLOAT, weapon_animduration);
clientstat(STAT_WEAPON2DURATION, EV_FLOAT, weapon2_animduration);
clientstat(STAT_WEAPONZOOM, EV_FLOAT, zoom);
clientstat(STAT_INSTA, EV_FLOAT, insta_icon);
clientstat(STAT_X2, EV_FLOAT, x2_icon);
clientstat(STAT_SPECTATING, EV_FLOAT, isspec);
clientstat(STAT_PLAYERNUM, EV_FLOAT, playernum); // literally useless but will be kept in case
clientstat(STAT_PLAYERSTANCE, EV_FLOAT, stance);
clientstat(STAT_FACINGENEMY, EV_FLOAT, facingenemy);
clientstat(STAT_VIEWZOOM, EV_FLOAT, viewzoom);
#endif
mappath = strcat("maps/", mapname);
mappath = strzone(mappath);
LoadWaypointData();
//set game elements
G_STARTPOINTS = 500;
G_STARTROUND = 1;
G_PRONEPOINTS = 0;
G_STARTWEAPON[0] = W_COLT;
G_STARTWEAPON[1] = 8;
G_STARTWEAPON[2] = 32;
G_WORLDTEXT = 1;
G_PERKS = 0;
G_PERKPOWER = 0;
load_nzd();
}
void() SpectatorConnect =
{
bprint(PRINT_HIGH, self.netname);
bprint(PRINT_HIGH, " has joined the spectators.\n");
}
void() RelinkZombies =
{
entity ent,ent2;
local float i;
local vector min, max;
//warn
ent = ent2 = world;
while ((ent = find (ent, classname, "ai_zombie")))
{
if(ent.currentHitBoxSetup == 0)//empty bbox, we don't care to update
continue;
makevectors (ent.angles);
for(i = 0; i < 3; i++)
{
if(i == 0)
ent2 = ent.head;
if(i == 1)
ent2 = ent.larm;
if(i == 2)
ent2 = ent.rarm;
if (ent2)
{
//setorigin (ent.head, ent.origin + v_right * ent.head.view_ofs_x + v_forward * ent.head.view_ofs_y + v_up * ent.head.view_ofs_z);
setorigin (ent2, ent.origin);
//fixme, move angles set and frame set to below the continue, we only want to update origin (maybe angles too?)
ent2.angles = ent.angles;
if(ent2.deadflag)
ent2.frame = ent.frame;
//if(OnlyOrigin)
// continue;
min = ent2.bbmins + (v_right * ent2.view_ofs_x) + (v_forward * ent2.view_ofs_y) + (v_up * ent2.view_ofs_z);
max = ent2.bbmaxs + (v_right * ent2.view_ofs_x) + (v_forward * ent2.view_ofs_y) + (v_up * ent2.view_ofs_z);
if(min_x > max_x) { min_x += max_x; max_x = min_x - max_x; min_x -= max_x; }
if(min_y > max_y) { min_y += max_y; max_y = min_y - max_y; min_y -= max_y; }
if(min_z > max_z) { min_z += max_z; max_z = min_z - max_z; min_z -= max_z; }
setsize(ent2,min,max);
}
}
}
}
void() EndFrame =
{
RelinkZombies();
};
//
// a large switch statement to convert asset paths made for
// older versions of nzp to the new standard
// TODO: add strlower or similar to all platforms.
//
string(string asset) convert_old_asset_path =
{
switch(asset) {
case "progs/Sprites/lamp_glow.spr":
return "models/sprites/lamp_glow.spr";
case "progs/Sprites/lamp_glow2.spr":
return "models/sprites/lamp_glow2.spr";
case "progs/Sprites/lamp_glow3.spr":
return "models/sprites/lamp_glow.spr";
case "progs/Props/Kino_boxes2.mdl":
case "progs/props/kino_boxes2.mdl":
return "models/props/Kino_boxes2.mdl";
case "progs/props/kino_boxes3.mdl":
return "models/props/Kino_boxes3.mdl";
case "progs/Props/Kino_boxes4.mdl":
case "progs/props/kino_boxes4.mdl":
return "models/props/Kino_boxes4.mdl";
case "progs/props/Kino_box.mdl":
case "progs/props/kino_box.mdl":
case "progs/Props/Kino_box.mdl":
return "models/props/Kino_box.mdl";
case "progs/Props/table_dinner.mdl":
return "models/props/table_dinner.mdl";
case "progs/Props/table_sq.mdl":
return "models/props/table_sq.mdl";
case "progs/Props/Kino_table.mdl":
case "progs/props/kino_table.mdl":
return "models/props/Kino_table.mdl";
case "progs/props/kino_couch.mdl":
return "models/props/kino_couch.mdl";
case "progs/Props/metal_chair.mdl":
return "models/props/metal_chair.mdl";
case "progs/Props/sandbags.mdl":
case "progs/props/sandbags.mdl":
return "models/props/sandbags.mdl";
case "progs/Props/shelf.mdl":
case "progs/props/shelf.mdl":
return "models/props/shelf.mdl";
case "progs/Props/dummy.mdl":
case "progs/props/dummy.mdl":
return "models/props/dummy.mdl";
case "progs/props/stand.mdl":
return "models/props/stand.mdl";
case "progs/Props/radio.mdl":
return "models/props/radio.mdl";
case "progs/Props/radiator.mdl":
return "models/props/radiator.mdl";
case "progs/Props/lamp_ndu.mdl":
case "progs/props/lamp_ndu.mdl":
return "models/props/lamp_ndu.mdl";
case "progs/Props/piano.mdl":
return "models/props/piano.mdl";
case "progs/props/teleporter.mdl":
return "models/props/teleporter.mdl";
case "progs/props/chandelier.mdl":
return "models/props/chandelier.mdl";
case "progs/props/vanity_table.mdl":
return "models/props/vanity_table.mdl";
case "progs/props/trash_con.mdl":
return "models/props/trash_con.mdl";
case "progs/props/kino_chairset.mdl":
return "models/props/kino_chairset.mdl";
case "progs/props/Kino_lounge.mdl":
return "models/props/Kino_lounge.mdl";
case "progs/props/kino_stageprop.mdl":
return "models/props/kino_stageprop.mdl";
case "progs/props/mainframe_pad.mdl":
return "models/props/mainframe_pad.mdl";
case "progs/Gmodels/g_mp40.mdl":
case "progs/gmodels/g_mp40.mdl":
return "models/weapons/mp40/g_mp40.mdl";
case "progs/gmodels/g_thomp.mdl":
return "models/weapons/thomp/g_thomp.mdl";
case "progs/Gmodels/g_betty.mdl":
case "progs/gmodels/g_betty.mdl":
return "models/weapons/grenade/g_betty.mdl";
case "progs/GModels/g_fg.mdl":
return "models/weapons/fg/g_fg.mdl";
case "progs/gmodels/g_m1.mdl":
return "models/weapons/garand/g_m1.mdl";
case "progs/gmodels/g_trench.mdl":
return "models/weapons/trench/g_trench.mdl";
case "progs/gmodels/g_bar.mdl":
return "models/weapons/bar/g_bar.mdl";
case "progs/gmodels/g_grenade.mdl":
return "models/weapons/grenade/g_grenade.mdl";
case "progs/gmodels/g_gewehr.mdl":
return "models/weapons/gewehr/g_gewehr.mdl";
case "progs/gmodels/g_bowie.mdl":
return "models/weapons/knife/g_bowie.mdl";
case "progs/gmodels/g_type.mdl":
return "models/weapons/type/g_type.mdl";
case "progs/gmodels/g_stg.mdl":
return "models/weapons/stg/g_stg.mdl";
case "models/misc/lightning.spr":
return "models/sprites/lightning.spr";
default: return asset;
}
return asset;
};

378
source/server/nzdparser.qc Normal file
View file

@ -0,0 +1,378 @@
/*
server/nzdparser.qc
parses NZData files for map variety
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
//custom weapon search
void(string weaponFile) nzd_defineweapon = {
float f, p, l, fnum, wepnum, framenum, fsnd;
string line;
fnum = 0;
framenum = 0;
fsnd = 0;
line = strcat(strcat("data/maps/", weaponFile), ".cw");
f = fopen(line, FILE_READ);
if (f == -1) { //no custom weapons
return;
}
wepnum = currentWeaponTracker - 1;
p = 0;
l = 1;
while(l) {
string li;
li = fgets(f);
if not (li) {
l = 0;
break;
}
line = strtrim(li);
if (line == "")
continue;
switch(p) {
case 0:
wepnum += 1;
currentWeaponTracker = wepnum;
if (line == "weapon")
p = 1;
break;
case 1:
if (line == "{")
p = 2;
else
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(line, " expected {\n")));
break;
case 2:
tokenize(line);
string v, vari;
vari = strtrim(argv(0));
v = strtrim(argv(2));
switch(vari) {
case "name":
CustomWeapons[wepnum].name = v;
break;
case "mag":
CustomWeapons[wepnum].magSize = stof(v);
break;
case "reserve":
CustomWeapons[wepnum].reserveSize = stof(v);
break;
case "vmodel":
CustomWeapons[wepnum].vmodel = v;
break;
case "vmodel2":
CustomWeapons[wepnum].vmodel2 = v;
break;
case "gmodel":
CustomWeapons[wepnum].gmodel = v;
break;
case "ads":
CustomWeapons[wepnum].adsofs = stov(v);
break;
case "firetype":
CustomWeapons[wepnum].firetype = stof(v);
break;
case "ispap":
CustomWeapons[wepnum].ispap = stof(v);
break;
case "nonpap":
CustomWeapons[wepnum].nonpap = stof(v);
break;
case "pap":
CustomWeapons[wepnum].papWpn = stof(v);
break;
case "dmg":
CustomWeapons[wepnum].damage = stof(v);
break;
case "shotcount":
CustomWeapons[wepnum].shotcount = stof(v);
break;
case "bodypen":
CustomWeapons[wepnum].bodypen = stof(v);
break;
case "penetration":
CustomWeapons[wepnum].penetration = stof(v);
break;
case "spread":
CustomWeapons[wepnum].spread = stof(v);
break;
case "fdelay":
CustomWeapons[wepnum].fdelay = stof(v);
break;
case "rdelay":
CustomWeapons[wepnum].rdelay = stof(v);
break;
case "walkspeed":
CustomWeapons[wepnum].walkspeed = stof(v);
break;
case "firesound":
CustomWeapons[wepnum].firesound = v;
break;
case "skin":
CustomWeapons[wepnum].skin = stof(v);
break;
case "recoil":
CustomWeapons[wepnum].recoil = stof(v);
break;
case "crossmin":
CustomWeapons[wepnum].crossmin = stof(v);
break;
case "crossmax":
CustomWeapons[wepnum].crossmax = stof(v);
break;
case "lowmag":
CustomWeapons[wepnum].lowmag = stof(v);
break;
case "lowreserve":
CustomWeapons[wepnum].lowreserve = stof(v);
break;
case "flash":
CustomWeapons[wepnum].flash = stov(v);
break;
case "flashsize":
CustomWeapons[wepnum].flashsize = stof(v);
}
#ifdef PC
/*sendCustomWeapon(wepnum, CustomWeapons[wepnum].name, CustomWeapons[wepnum].magSize,
CustomWeapons[wepnum].reserveSize, CustomWeapons[wepnum].vmodel, CustomWeapons[wepnum].vmodel2,
CustomWeapons[wepnum].gmodel, CustomWeapons[wepnum].isDual, CustomWeapons[wepnum].firetype,
CustomWeapons[wepnum].nonpap, CustomWeapons[wepnum].pap, CustomWeapons[wepnum].ispap,
CustomWeapons[wepnum].damage, CustomWeapons[wepnum].shotcount, CustomWeapons[wepnum].bodypen,
CustomWeapons[wepnum].penetration, CustomWeapons[wepnum].spread, CustomWeapons[wepnum].fdelay,
CustomWeapons[wepnum].rdelay, CustomWeapons[wepnum].walkspeed, CustomWeapons[wepnum].firesound,
CustomWeapons[wepnum].skin, CustomWeapons[wepnum].recoil, CustomWeapons[wepnum].crossmin,
CustomWeapons[wepnum].crossmax, CustomWeapons[wepnum].lowmag, CustomWeapons[wepnum].lowreserve,
CustomWeapons[wepnum].flash, CustomWeapons[wepnum].flashsize, CustomWeapons[wepnum].papWpn,
CustomWeapons[wepnum].adsofs);*/
#endif
break;
case 3:
if (line == "[") {
p = 4;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(line, " expected [\n")));
}
break;
case 4:
if (line == "]") {
p = 2;
} else {
switch(wepnum) {
/*case 0: W_C1FRAMES[fnum] = stof(line); break;
case 1: W_C2FRAMES[fnum] = stof(line); break;
case 2: W_C3FRAMES[fnum] = stof(line); break;
case 3: W_C4FRAMES[fnum] = stof(line); break;*/
}
fnum++;
}
break;
case 5:
if (line == "[") {
p = 6;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(line, " expected [\n")));
}
break;
case 6:
if (line == "]") {
p = 2;
} else {
switch(wepnum) {
/*case 0: W_C1XSNDFRAME[framenum] = stof(line); break;
case 1: W_C2XSNDFRAME[framenum] = stof(line); break;
case 2: W_C3XSNDFRAME[framenum] = stof(line); break;
case 3: W_C4XSNDFRAME[framenum] = stof(line); break;*/
}
framenum++;
}
break;
case 7:
if (line == "[") {
p = 8;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(line, " expected [\n")));
}
break;
case 8:
if (line == "]") {
p = 2;
} else {
switch(wepnum) {
/*case 0: W_C1XTRASND[fsnd] = line; break;
case 1: W_C2XTRASND[fsnd] = line; break;
case 2: W_C3XTRASND[fsnd] = line; break;
case 3: W_C4XTRASND[fsnd] = line; break;*/
}
fsnd++;
}
break;
}
}
fclose(f);
}
//basically copying the waypoint code.. yikes
void() load_nzd = {
#ifndef NX
float file, point;
string h;
float loop;
float wepdata = 0;
h = strcat(mappath, ".nzd");
file = fopen (h, FILE_READ);
if (file == -1)
{
if (cvar("developer"))
dprint(".NZD file not found, using default settings..\n");
return;
}
point = 0;
loop = 1;
while(loop) {
string line;
line = fgets(file);
if not (line) {
bprint(PRINT_HIGH, "End of file\n");
loop = 0;
break;
}
h = strtrim(line);
//print(h, "\n");
if (h == "") {
continue;
}
switch (point) {
case 0:
//switch-ception!
switch(h) {
case "mech": point = 1; break;
default: bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(h, "\n")));
}
break;
case 1:
if (h == "{") {
point = 2;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(h, " expected {\n")));
}
break;
case 2:
tokenize(h);
string value, variable;
variable = strtrim(argv(0));
value = strtrim(argv(2));
switch (variable) {
case "proneperkpoints":
G_PRONEPOINTS = stof(value);
break;
case "spawnpoints":
G_STARTPOINTS = stof(value);
break;
case "round":
G_STARTROUND = stof(value);
break;
case "worldtext":
G_WORLDTEXT = stof(value);
break;
case "perkpower":
G_PERKPOWER = stof(value);
break;
case "includeweapon":
nzd_defineweapon(value);
break;
case "hud":
G_HUD = value;
break;
case "hudhor":
G_HUDHOR = stof(value);
break;
case "wep":
point = 3;
break;
case "perk":
point = 5;
break;
case "}":
loop = 0;
break;
default:
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(h, " expected }\n")));
break;
}
break;
case 3:
if (h == "[") {
point = 4;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(h, " expected [\n")));
}
break;
case 4:
if (h == "]") {
point = 2;
} else {
G_STARTWEAPON[wepdata] = stof(h);
wepdata++;
}
break;
case 5:
if (h == "[") {
point = 6;
} else {
bprint(PRINT_HIGH, strcat("Error: unknown variable ", strcat(h, " expected [\n")));
}
break;
case 6:
if (h == "]") {
point = 2;
} else {
G_PERKS = G_PERKS | stof(h);
}
break;
}
}
fclose(file);
#endif
}

810
source/server/player.qc Normal file
View file

@ -0,0 +1,810 @@
/*
server/nzdparser.qc
Various stuff done for the player, including per-frame functions
like PlayerPreThink and PlayerPostThink, also client specific
stuff like PutClientInServer etc.
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
void(entity e) Light_None;
// player animations
void() playdown =[ 1, playdown1 ] {self.frame = 32;}
void() playdown1 =[ 2, playdown2 ] {self.frame = 33;}
void() playdown2 =[ 2, playdown3 ] {self.frame = 34;}
void() playdown3 =[ 2, playdown4 ] {self.frame = 35;}
void() playdown4 =[ 2, playdown5 ] {self.frame = 36;}
void() playdown5 =[ 2, playdown5 ] {self.frame = 37;}
//
void() playreload =[ 1, playreload1 ] {self.frame = 11;}
void() playreload1 =[ 2, playreload2 ] {self.frame = 12;}
void() playreload2 =[ 3, playreload3 ] {self.frame = 13;}
void() playreload3 =[ 4, playreload4 ] {self.frame = 14;}
void() playreload4 =[ 5, playreload5 ] {self.frame = 15;}
void() playreload5 =[ 6, playreload6 ] {self.frame = 16;}
void() playreload6 =[ 7, playreload7 ] {self.frame = 17;}
void() playreload7 =[ 8, playreload8 ] {self.frame = 18;}
void() playreload8 =[ 9, playreload9 ] {self.frame = 19;}
void() playreload9 =[ 10, playreload10 ] {self.frame = 20;}
void() playreload10 =[ 11, playreload11 ] {self.frame = 21;}
void() playreload11 =[ 12, playreload12 ] {self.frame = 22;}
void() playreload12 =[ 13, playreload13 ] {self.frame = 23;}
void() playreload13 =[ 14, playreload13 ] {self.frame = 24;}
//
void() playdownfire =[ 1, playdownfire1 ] {self.frame = 38;}
void() playdownfire1 =[ 2, playdownfire1 ] {self.frame = 39;}
//
void() playaim =[ 1, playaim1 ] {self.frame = 8;} // naievil -- player aimin anim
void() playaim1 =[ 2, playaim1 ] {self.frame = 9;} // naievil -- second player aimin anim
//
void() playout =[ 1, playout1 ] {self.frame = 10;} // naievil -- player aim out anim
void() playout1 =[ 2, playout1 ] {self.frame = 11;} // naievil -- second player aim out anim
//
void() playrun1 =[ 1, playrun2 ] {self.frame = 25;}
void() playrun2 =[ 2, playrun3 ] {self.frame = 26;}
void() playrun3 =[ 3, playrun4 ] {self.frame = 27;}
void() playrun4 =[ 4, playrun5 ] {self.frame = 28;}
void() playrun5 =[ 5, playrun6 ] {self.frame = 29;}
void() playrun6 =[ 6, playrun7 ] {self.frame = 30;}
void() playrun7 =[ 7, playrun8 ] {self.frame = 31;}
void() playrun8 =[ 8, playrun9 ] {self.frame = 25;}
void() playrun9 =[ 9, playrun10 ] {self.frame = 26;}
void() playrun10 =[ 10, playrun11 ] {self.frame = 27;}
void() playrun11 =[ 11, playrun12 ] {self.frame = 28;}
void() playrun12 =[ 12, playrun13 ] {self.frame = 29;}
void() playrun13 =[ 13, playrun14 ] {self.frame = 30;}
void() playrun14 =[ 14, playrun15 ] {self.frame = 25;}
void() playrun15 =[ 15, playrun16 ] {self.frame = 26;}
void() playrun16 =[ 16, playrun17 ] {self.frame = 27;}
void() playrun17 =[ 17, playrun18 ] {self.frame = 28;}
void() playrun18 =[ 18, playrun19 ] {self.frame = 29;}
void() playrun19 =[ 19, playrun20 ] {self.frame = 30;}
void() playrun20 =[ 20, playrun21 ] {self.frame = 31;}
void() playrun21 =[ 21, playrun22 ] {self.frame = 25;}
void() playrun22 =[ 22, playrun23 ] {self.frame = 26;}
void() playrun23 =[ 23, playrun24 ] {self.frame = 27;}
void() playrun24 =[ 24, playrun25 ] {self.frame = 28;}
void() playrun25 =[ 25, playrun26 ] {self.frame = 29;}
void() playrun26 =[ 26, playrun27 ] {self.frame = 30;}
void() playrun27 =[ 27, playrun28 ] {self.frame = 25;}
void() playrun28 =[ 28, playrun29 ] {self.frame = 26;}
void() playrun29 =[ 29, playrun30 ] {self.frame = 27;}
void() playrun30 =[ 30, playrun31 ] {self.frame = 28;}
void() playrun31 =[ 31, playrun32 ] {self.frame = 29;}
void() playrun32 =[ 32, playrun33 ] {self.frame = 30;}
void() playrun33 =[ 33, playrun33 ] {self.frame = 31;}
//
void() playwalk =[ 1, playwalk1 ] {if (self.velocity) { self.frame = 0; }}
void() playwalk1 =[ 2, playwalk2 ] {if (self.velocity) { self.frame = 1; }}
void() playwalk2 =[ 3, playwalk3 ] {if (self.velocity) { self.frame = 2; }}
void() playwalk3 =[ 4, playwalk4 ] {if (self.velocity) { self.frame = 3; }}
void() playwalk4 =[ 5, playwalk5 ] {if (self.velocity) { self.frame = 4; }}
void() playwalk5 =[ 6, playwalk6 ] {if (self.velocity) { self.frame = 5; }}
void() playwalk6 =[ 7, playwalk7 ] {if (self.velocity) { self.frame = 6; }}
void() playwalk7 =[ 8, playwalk8 ] {if (self.velocity) { self.frame = 7; }}
void() playwalk8 =[ 9, playwalk8 ] {if (self.velocity) { self.frame = 8; }}
//
void() playgetup =[ 1, playgetup1 ] {self.frame = 38;}
void() playgetup1 =[ 2, playgetup2 ] {self.frame = 39;}
void() playgetup2 =[ 3, playgetup3 ] {self.frame = 40;}
void() playgetup3 =[ 4, playgetup4 ] {self.frame = 41;}
void() playgetup4 =[ 5, playgetup5 ] {self.frame = 42;}
void() playgetup5 =[ 6, playgetup6 ] {self.frame = 43;}
void() playgetup6 =[ 7, playgetup7 ] {self.frame = 44;}
void() playgetup7 =[ 8, playgetup8 ] {self.frame = 45;}
void() playgetup8 =[ 9, playgetup9 ] {self.frame = 46;}
void() playgetup9 =[ 10, playgetup10 ] {self.frame = 47;}
void() playgetup10 =[ 11, playgetup10 ] {self.frame = 48;}
#define forward 0
#define backward 1
#define left 2
#define right 3
#define all_move -1
float(float dir) checkMovement =
{
makevectors(self.movement);
string a = vtos(self.movement);
float x, y;
tokenize(a);
x = stof(argv(0));
y = stof(argv(1));
switch(dir) {
case forward:
if (x > 0)
return 1;
break;
case backward:
if (x < 0)
return 1;
break;
case right:
if (y > 0)
return 1;
break;
case left:
if (y < 0)
return 1;
break;
case all_move:
if (x || y)
return 1;
break;
default:
return 0;
}
}
void() PlayerJump =
{
if (!(self.flags & FL_ONGROUND)
|| !(self.flags & FL_JUMPRELEASED)
|| self.downed
|| self.dive ) {
return;
}
self.flags = self.flags - (self.flags & FL_JUMPRELEASED);
sound(self, CHAN_VOICE, "sounds/player/jump.wav", 1, 1.75);
if (self.button2)
self.button2 = 0;
self.oldz = self.origin_z;
self.velocity_z = 230;
}
void(float override) JumpCheck =
{
#ifndef PC
override = 0;
#endif
if(self.button2 || override) {
if (self.downed)
return;
if (self.stance == 2) {
// naievil -- stop sprinting if we jump, which is a real mechanic from the game that we never implemented
if (self.sprinting) {
W_SprintStop();
}
PlayerJump();
} else if (self.view_ofs_z == self.new_ofs_z && (self.flags & FL_ONGROUND)) {
switch(self.stance) {
case 0:
self.new_ofs_z = self.view_ofs_z + 42;
self.stance = 2;
break;
case 1:
self.new_ofs_z = self.view_ofs_z + 24;
self.stance = 2;
break;
default: break;
}
}
} else
self.flags = self.flags | FL_JUMPRELEASED;
}
void() PlayerPreThink =
{
if (self.downed) {
self.maxspeed = 30;
} else {
self.maxspeed = 175;
if (self.sprinting) {
#ifdef PC
if (self.viewzoom > 0.9)
self.viewzoom -= 0.015;
else if (self.viewzoom < 0.9)
self.viewzoom = 0.9;
// viewbob when running
self.punchangle_x = 1*sin(time*15);
#endif
playrun1();
self.maxspeed *= 1.66;
} else if (!self.sprinting && !self.zoom) {
#ifdef PC
if (self.viewzoom < 1)
self.viewzoom += 0.015;
else
self.viewzoom = 1;
if (checkMovement(-1))
self.punchangle_x = 0.25*sin(time*15);
#endif
} else if (self.zoom != 3) {
self.maxspeed *= 0.5;
} if (self.damagetimer > time) {
self.maxspeed *= 0.5;
}
switch(self.stance) {
case 1:
self.maxspeed *= 0.5;
break;
case 0:
self.maxspeed *= 0.25;
break;
}
#ifdef PC
if (checkMovement(backward)) {
self.maxspeed *= 0.7;
} else if (checkMovement(left) || checkMovement(right)) {
self.maxspeed *= 0.8;
}
#endif
self.maxspeed *= GetWeaponWalkSpeed(self.perks, self.weapon);
}
if(self.isspec != 0 && !self.downed)
{
if(self.button0)
{
self.aiment = find(self.aiment, classname, "player");
if(self.aiment != world)
{
sprint(self, PRINT_HIGH, "Now spectating ");
sprint(self, PRINT_HIGH, self.aiment.netname);
sprint(self, PRINT_HIGH, "\n");
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
}
else
{
sprint(self, PRINT_HIGH, "Freefly spectate\n");
self.movetype = MOVETYPE_FLY;
}
}
if(self.aiment != world)
{
self.origin = self.aiment.origin;
self.angles = self.aiment.v_angle;
self.velocity = self.aiment.velocity;
self.fixangle = TRUE;
}
return;
}
if (cvar("waypoint_mode")) {
Waypoint_Logic();
} else {
Weapon_Logic();
}
JumpCheck(0);
// refuel/cool m2
if (self.ltime < time) {
if (self.currentmag == 0 && !self.cooldown) {
self.cooldown = true;
}
if (self.cooldown && self.currentmag > 20)
self.cooldown = false;
if (self.weapon == W_M2 || self.weapon == W_FIW && self.currentmag < getWeaponMag(self.weapon))
self.currentmag += 1;
self.ltime = time + 0.1;
}
};
void() PlayerPostThink =
{
if(self.isspec)
return;
//landsound
if((self.oldvelocity_z < -10) && (self.flags & FL_ONGROUND))
{
if(self.oldvelocity_z < -270)
sound(self, CHAN_BODY, "sounds/player/land.wav", 1, 1.75);
self.lastsound_time = time - 0.15;
}
#ifdef PC
//footsteps
if((vlen(self.velocity) > 100) &&(( time - self.lastsound_time > 0.4) || (time - self.lastsound_time > 0.3 && self.sprinting)) && (self.flags & FL_ONGROUND))
{
local float movelen = vlen(input_movevalues);
if(movelen > 300)
{
if (!self.sprinting)
playwalk();
local float ran = random();
if(ran > 0.8)
sound(self, CHAN_BODY, "sounds/player/footstep1.wav", 0.8, 2.5);
else if(ran > 0.6)
sound(self, CHAN_BODY, "sounds/player/footstep2.wav", 0.8, 2.5);
else if(ran > 0.4)
sound(self, CHAN_BODY, "sounds/player/footstep3.wav", 0.8, 2.5);
else if(ran > 0.2)
sound(self, CHAN_BODY, "sounds/player/footstep4.wav", 0.8, 2.5);
else
sound(self, CHAN_BODY, "sounds/player/footstep5.wav", 0.8, 2.5);
self.lastsound_time = time;
}
}
#endif
if (self.health_delay < time && self.health != self.max_health && !self.downed)
{
self.health = self.health + 5;
if (self.max_health < self.health)
self.health = self.max_health;
}
if (self.progress_bar) {
if (self.progress_bar < time) {
if (self.downed)
GetUp();
if (self.reviving)
self.revived = 1;
self.progress_bar = 0;
self.progress_bar_time = 0;
self.progress_bar_percent = 0;
} else {
float remaining = self.progress_bar - time;
self.progress_bar_percent = invertfloat((remaining / self.progress_bar_time));
}
}
if (self.sprinting) {
self.sprint_timer = self.sprint_duration + (time - self.sprint_start_time);
#ifndef PC
if (!self.velocity || self.stance != 2) {
W_SprintStop();
}
#else
if (!self.velocity || !checkMovement(0) || self.stance != 2) { //moto (FIXME) -- move me!
W_SprintStop();
}
#endif
if (self.perks & P_STAMIN) {
if (self.sprint_timer > sprint_max_time * 2) {
W_SprintStop();
}
}
else
{
if (self.sprint_timer > sprint_max_time) {
W_SprintStop();
}
}
} else if (self.sprint_duration > 0.0) {
self.sprint_rest_time = (time - self.sprint_stop_time);
}
self.oldvelocity = self.velocity;
// Perform a traceline to keep track of entities directly
// in front of the player.
#ifndef NX
vector source;
makevectors (self.v_angle);
source = self.origin + self.view_ofs;
traceline (source, source + v_forward*800*1.2, 0, self);
// use .head here to avoid expanding ent struct
self.head = trace_ent;
// check whether we're looking at an entity separately to communicate
// with the client more reasonably
if (trace_ent.classname == "ai_zombie" || trace_ent.classname == "ai_zombie_head"
|| trace_ent.classname == "ai_zombie_rarm" ||trace_ent.classname == "ai_zombie_larm"
|| trace_ent.classname == "ai_dog")
self.facingenemy = true;
else
self.facingenemy = false;
#endif
};
void() ClientKill = {};
//called when a client connects to the server
void() ClientConnect =
{
#ifdef PC
// Maintain old FGD values and just convert them to new ones
//
if (world.fog) {
// Force fog on PC
if (!world.PC_fog) {
// Don't execute more than once
if (!world_fog) {
string fog_start_end, fog_R, fog_B, fog_G;
// Tokenize our fog
tokenize(world.fog);
// Get values and transmute it a bit if necessary
// Originally: start | end | R | G | B
fog_start_end = ftos(((stof(argv(0))) / stof(argv(1))) / 3.5);
fog_R = ftos(stof(argv(2))/255);
fog_G = ftos(stof(argv(3))/255);
fog_B = ftos(stof(argv(4))/255);
// Restore into our world.fog
world_fog = strcat(fog_start_end, " ", fog_R, " ", fog_G, " ", fog_B);
}
localcmd(strcat("fog ", world_fog));
}
}
#endif
if(cvar("developer") || player_count > 1) {
bprint(PRINT_HIGH, self.netname); //print player name
bprint(PRINT_HIGH, " connected.\n");
}
};
void() PollPlayerPoints =
{
float i, breakpoint;
entity pollent;
breakpoint = 0;
for (i = 1; i <= 4 && !breakpoint; i++)
{
pollent = findfloat(world, playernum, i);
if (pollent == world) {
breakpoint = 1;
break;
}
UpdatePlayerPoints(i, pollent.points, pollent.kills, 0, pollent.netname, pollent);
}
}
void() PlayerSpawn =
{
local entity spawnpoint;
local_client = self;
spawnpoint = find(world, classname, "info_player_start");
self.isspec = FALSE;
self.classname = "player";
self.solid = SOLID_BBOX;
setmodel(self, "models/player.mdl");
self.movetype = MOVETYPE_WALK;
self.max_health = self.health = 100;
//custom weapon stuff (we want to put this here so we can send the info to the client with an entity)
// DISGUSTING.
//nzd_defineweapon(self);
//centerprint(self, CustomWeapons[0].vmodel);
entity who = find(world,classname,"player");
while(who != self && !self.playernum)
{
if(who)
{
coop = 1;
player_count++;
break;
}
}
switch(player_count) {
default: spawnpoint = find(world, classname, "info_player_start"); if (!spawnpoint) {spawnpoint = find(world, classname, "info_player_start");} break;
case 1: spawnpoint = find(world, classname, "info_player_nikolai"); if (!spawnpoint) {spawnpoint = find(world, classname, "info_player_start");} break;
case 2: spawnpoint = find(world, classname, "info_player_takeo"); if (!spawnpoint) {spawnpoint = find(world, classname, "info_player_start");} break;
case 3: spawnpoint = find(world, classname, "info_player_doctor"); if (!spawnpoint) {spawnpoint = find(world, classname, "info_player_start");} break;
}
if (self.playernum) {
switch(self.playernum) {
default: spawnpoint = find(world, classname, "info_player_start"); if (!spawnpoint) {spawnpoint = find(world, classname, "info_player_start");} break;
case 1: spawnpoint = find(world, classname, "info_player_nikolai"); if (!spawnpoint) {spawnpoint = find(world, classname, "info_player_start");} break;
case 2: spawnpoint = find(world, classname, "info_player_takeo"); if (!spawnpoint) {spawnpoint = find(world, classname, "info_player_start");} break;
case 3: spawnpoint = find(world, classname, "info_player_doctor"); if (!spawnpoint) {spawnpoint = find(world, classname, "info_player_start");} break;
}
}
self.origin = spawnpoint.origin + [0,0,1];
self.angles = spawnpoint.angles;
self.fixangle = TRUE;
setsize(self, [-16, -16, -32], [16, 16, 40]);
self.view_ofs = VEC_VIEW_OFS; // naievil -- set view_ofs to 32 to maintain half life (64) sizes
self.stance = 2;
self.new_ofs_z = self.view_ofs_z;
self.oldz = self.origin_z;
self.currentammo = G_STARTWEAPON[2];
self.currentmag = G_STARTWEAPON[1];
self.weapon = G_STARTWEAPON[0];
self.grenades = self.grenades | 1; // add frag grenades to player inventory
if (rounds)
self.primary_grenades = 2;
else
self.primary_grenades = 0; // start off without grenades
self.pri_grenade_state = 0; // defines that frag grenades are for player first, not betty
self.secondary_grenades = -1; // shows that we both don't have betties AND shouldn't draw the image onscreen
if (!self.points)
addmoney(self, G_STARTPOINTS, 0);
self.weaponmodel = GetWeaponModel(self.weapon, 0);// Give weapon model
self.weapon2model = GetWeapon2Model(self.weapon);
SwitchWeapon(self.weapon);
self.stamina = 3;
self.reviving = 0;
self.weaponnum = 0;
self.perks = G_PERKS;
SetPerk(self, self.perks);
//self.zoom = 1; // This is to fix an aimin bug for the kar scope
if (!self.playernum) {
self.playernum = player_count + 1;
if (self.playernum == 1)
pl1 = self;
}
if (rounds < 1) {
sound(self, CHAN_AUTO, "sounds/rounds/splash.wav", 1, ATTN_NONE);
}
PromptLevelChange(self.nextthink + 3, 1, self);
UpdatePlayerCount(player_count);
#ifdef PC
PollPlayerPoints();
UpdateV2model("", 0);
stuffcmd(self, "cl_gunx 8;cl_guny 16;cl_gunz 25\n");
SetRound(self, G_STARTROUND);
self.viewzoom = 1;
self.weapon_animduration = getWeaponDelay(self.weapon, FIRE);
if (G_WORLDTEXT)
WorldText(world.chaptertitle, world.location, world.date, world.person, self);
#else
self.Weapon_Name = GetWeaponName(self.weapon);
self.Flash_Offset = GetWeaponFlash_Offset(self.weapon);
self.Flash_Size = GetWeaponFlash_Size(self.weapon);
#endif
if (G_STARTROUND != 1) {
rounds = G_STARTROUND - 1;
}
#ifndef PSP
//pushHUD(G_HUD, G_HUDHOR, self); //FIXME - breaks mp!
#endif
};
void() SpectatorSpawn =
{
local entity spawnpoint;
spawnpoint = find(world, classname, "info_player_start");
self.isspec = TRUE;
self.classname = "spectator";
self.solid = SOLID_NOT;
setmodel(self, "");
self.movetype = MOVETYPE_FLY;
self.origin = spawnpoint.origin + [0,0,1];
self.fixangle = TRUE;
setsize(self, [-16, -16, -24], [16, 16, 32]);
self.view_ofs = '0 0 22';
self.aiment = world;
};
//called when a client loads a map
void() PutClientInServer =
{
if(cvar("developer") || player_count > 1) {
bprint(PRINT_HIGH, self.netname);
bprint(PRINT_HIGH, " has joined the game.\n");
}
if (spawn_time > time || !rounds)
PlayerSpawn();
// TEMPORARY
#ifdef PC
else
SpectatorSpawn();
#endif
};
//called when client disconnects from the server
void() ClientDisconnect =
{
bprint(PRINT_HIGH, self.netname);
bprint(PRINT_HIGH, " has left the game.\n");
player_count--;
UpdatePlayerCount(player_count);
};
void() SetNewParms =
{
};
void() SetChangeParms =
{
};
void(string com) SV_ParseClientCommand =
{
if(com == "joingame")
{
if(self.isspec)
{
bprint(PRINT_HIGH, self.netname);
bprint(PRINT_HIGH, " has joined the game.\n");
PlayerSpawn();
}
else
sprint(self, PRINT_HIGH, "You're already in game!\n");
}
else if(com == "specgame")
{
if(self.isspec)
return;
else
{
coop = 1;
/*SpectatorSpawn();
bprint(PRINT_HIGH, self.netname); //print player name
bprint(PRINT_HIGH, " has joined the spectators.\n");*/
PlayerSpawn();
}
}
else if(com == "pause")
{
static float paused;
paused = !paused;
#ifdef PC
setpause(paused);
#endif
}
else if (com == "noclip")
{
#ifndef PC
entity benis = self;
other = find(world, classname, "player");
self = other;
#endif
if (self.movetype == MOVETYPE_WALK)
self.movetype = MOVETYPE_NOCLIP;
else
self.movetype = MOVETYPE_WALK;
#ifndef PC
localcmd(com);
self = benis;
#endif
}
else
{
tokenize(com);
switch(argv(0))
{
case "give":
entity tempe = self;
other = find(world, classname, "player");
self = other;
float wep = stof(argv(1));
if (wep) {
if (!self.secondaryweapon) {
WeaponSwitch(self);
}
float startframe, endframe;
string modelname;
self.weapon = wep;
self.currentammo = getWeaponAmmo(wep);
self.currentmag = getWeaponMag(wep);
if (IsDualWeapon(wep)) {
self.currentmag2 = self.currentmag;
}
self.weaponskin = GetWepSkin(self.weapon);
startframe = GetFrame(self.weapon,TAKE_OUT_START);
endframe = GetFrame(self.weapon,TAKE_OUT_END);
modelname = GetWeaponModel(wep, 0);
SwitchWeapon(wep);
Set_W_Frame (startframe, endframe, 0, 0, 0, SUB_Null, modelname, false, S_BOTH);
self.reload_delay2 = self.fire_delay2 = self.reload_delay = self.fire_delay = 0;
#ifndef PC
self.Weapon_Name = GetWeaponName(self.weapon);
#endif
}
break;
case "god":
if (!(self.flags & FL_GODMODE))
self.flags = self.flags | FL_GODMODE;
else
self.flags = self.flags & (~FL_GODMODE);
break;
case "nextround":
rounds++;
break;
case "prevround":
rounds--;
break;
case "addmoney":
entity tempe1 = self;
other = find(world, classname, "player");
self = other;
addmoney(self, stof(argv(1)), 1);
self = tempe1;
break;
default:
#ifndef PC
bprint(PRINT_HIGH, "Command not found in QC\n");
#endif
break;
}
}
};
#ifdef PC
void() SV_RunClientCommand =
{
runstandardplayerphysics(self);
}
#endif

View file

@ -0,0 +1,183 @@
/*
server/psp_specifics.qc
stuff only for psp, remove later
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
void() Do_Zombie_A = {};
void() func_door_nzp;
void() mystery_box;
entity windows[32];
float wincnt;
void () CL_SendWeaponFire =
{
float return_time;
vector Wep_Recoil;
Wep_Recoil = GetWeaponRecoil(self.weapon);
msg_entity = self;
WriteByte(MSG_ONE, SVC_WEAPONFIRE);
return_time = getWeaponRecoilReturn(self.weapon);
WriteLong(MSG_ONE, return_time);
WriteCoord (MSG_ONE, Wep_Recoil_x);
WriteCoord (MSG_ONE, Wep_Recoil_y);
WriteCoord (MSG_ONE, Wep_Recoil_z);
//self.punchangle = Wep_Recoil;
self.recoil_delay = 60/return_time + time;
}
void() trigger_activator = {};
void() ParseClientCommand = {SV_ParseClientCommand(CMD_STRING);}
void() PutClientInServer;
void() InitRounds;
//moto -- put this here because it keeps soft_restart somewhat clean..
void(entity door) reclose_door = {
entity oldself;
oldself = self;
self = door;
setmodel(self, self.oldmodel);
self.solid = SOLID_BSP;
setorigin(self, self.oldorigin);
self.isopen = 0;
func_door_nzp();
//Close_Waypoint(self.wayTarget);
self = oldself;
}
void() Soft_Restart = {
entity who, oldself, doors, box, revive, endgame;
self = find(world,classname,"player");
oldself = self;
//remove all zombies
who = find(world,classname,"ai_zombie");
while(who != world)
{
if(who.health)
{
self = who;
self.th_die();
// hide bodies
setmodel(self, "");
if (self.head)
setmodel(self.head, "");
if (self.larm)
setmodel(self.larm, "");
if (self.rarm)
setmodel(self.rarm, "");
self = oldself;
}
who = find(who,classname,"ai_zombie");
}
//repair all windows
for(float i = 0; i < wincnt; i++) {
if (windows[i].health != -10) {
windows[i].health = 6;
windows[i].frame = 0;
}
}
//close doors
doors = findfloat(world, isopen, 1);
while (doors) {
if (doors.isopen)
reclose_door(doors);
doors = findfloat(world, isopen, 1);
}
//revert mystery box
box = find(world, classname, "mystery");
if (box) {
box.boxstatus = 0;
box.frame = 0;
box.goaldummy.frame = 0;
boxCount = 0;
box.origin = boxOrigin;
//self = box;
if (box.boxweapon)
remove(box.boxweapon);
//mystery_box();
//self = oldself;
}
//reset quick revive
revive = find(world, classname, "perk_revive");
if (revive) {
setmodel(revive, revive.model);
oldself.revivesoda = 0;
}
//reset buyable ending
endgame = find(world, classname, "func_ending");
if (endgame) {
endgame.activated = false;
}
//reset teleporters
local entity tp;
tp = find(world, classname, "func_teleporter_entrance");
if (tp) {
tp.activated = false;
tp.isLinked = false;
tp.cooldown = false;
tp.waitLink = false;
tp.think = SUB_Null;
}
local entity power;
power = find(world, classname, "power_switch");
if(power) {
isPowerOn = false;
power.frame = 0;
}
self = oldself;
self.downed = 0;
game_over = false;
rounds = 0;
self.score = 0;
self.points = 0;
self.secondaryweapon = 0;
InitRounds();
self.isspec = false;
PutClientInServer();
}

340
source/server/rounds.qc Normal file
View file

@ -0,0 +1,340 @@
/*
server/rounds.qc
wave logic
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
float() spawn_a_dogA;
void() Spawn_Enemy =
{
// temporarily prevent spawning
if (nuke_powerup_spawndelay > time)
return;
if (roundtype == 1)
{
if (spawn_a_zombieA())
{
Current_Zombies = Current_Zombies + 1;
}
}
else if (roundtype == 2)
{
if (spawn_a_dogA())
{
Current_Zombies = Current_Zombies + 1;
}
}
}
float(float a, float b) qc_max =
{
if (a < b)
return b;
return a;
}
float() getZombieTotal = {
if (roundtype == 1) {
float count, multiplier, plrcnt;
count = 24;
plrcnt = player_count + 1;
multiplier = qc_max(rounds/5, 1);
if (rounds >= 10)
multiplier *= rounds * 0.15;
if (plrcnt == 1)
count += rint((0.5 * 6) * multiplier);
else
count += rint((plrcnt * 6) * multiplier);
if (rounds < 2)
count = floor(count * 0.25);
else if (rounds < 3)
count = floor(count * 0.30);
else if (rounds < 4)
count = floor(count * 0.50);
else if (rounds < 5)
count = floor(count * 0.70);
else if (rounds < 6)
count = floor(count * 0.90);
return count;
} else { //dogs
// 2 waves
if (rounds <= 14)
return 6 * (player_count + 1);
return 8 * (player_count + 1);
}
return 0;
}
void(string s) playSoundAtPlayers =
{
local entity p;
p = find(world,classname,"player");
while(p)
{
sound(p,CHAN_AUTO,s,1,ATTN_NONE);
p = find(p,classname,"player");
}
}
void() updateDogRound =
{
float r = random();
if (r < 0.33) {
dogRound = rounds + 5;
} else if (r < 0.66) {
dogRound = rounds + 6;
} else {
dogRound = rounds + 7;
}
}
void() EndRound =
{
rounds_change = 4;
SetUpdate(self, UT_ROUNDS_CHANGE, rounds_change, 0, 0);
if (gotdog && rounds == dogRound) {
playSoundAtPlayers("sounds/rounds/droundend.wav");
dogWave = false;
} else {
playSoundAtPlayers("sounds/rounds/eround.wav");
}
round_changetime = time + 5;
// No Perks? No Problem & Abstinence Program
if (rounds >= 10) {
entity players;
players = find(world, classname, "player");
while(players != world) {
if (players.ach_tracker_npnp == 0) {
GiveAchievement(5, players);
}
if (players.ach_tracker_abst == 0) {
GiveAchievement(8, players);
}
players.ach_tracker_npnp = 0;
players = find(players, classname, "player");
}
}
}
void() PlayerSpawn;
void() NewRound =
{
entity who = find(world,classname,"spectator");
while(who != world)
{
if(who.isspec)
{
self = who;
PlayerSpawn();
break;
}
}
entity tempe;
round_changetime = 0;
spawn_time = time + 5;
sounds_playing = 0;//just in case it ever somehow glitches
if (delay_at_round > 0.08)
{
delay_at_round = delay_at_round*0.95;
if (delay_at_round < 0.08)
delay_at_round = 0.08;
}
if (rounds != 0)
{
if (gotdog && rounds == (dogRound - 1)) {
playSoundAtPlayers("sounds/rounds/droundstart.wav");
dogWave = true;
} else {
playSoundAtPlayers("sounds/rounds/nround.wav");
}
rounds_change = 6;
SetUpdate(self, UT_ROUNDS_CHANGE, rounds_change, 0, 0);
blink_return = time + 2;
}
// if we just had a dog round, set the next
if (gotdog && rounds == dogRound) {
updateDogRound();
}
rounds = rounds + 1;
NotifyNewRound(rounds);
tempe = find(world, classname, "player");
while (tempe)
{
if(tempe.grenades & 1)
{
tempe.primary_grenades = tempe.primary_grenades + 2;
if (tempe.primary_grenades > 4)
tempe.primary_grenades = 4;
}
if(tempe.grenades & 2)
{
tempe.secondary_grenades = tempe.secondary_grenades + 2;
if (tempe.secondary_grenades > 2)
tempe.secondary_grenades = 2;
}
tempe = find(tempe, classname, "player");
}
set_z_health();
maxreward = 50 * rounds;
if (maxreward > 500)
maxreward = 500;
totalreward = 0;
Current_Zombies = 0;
spawn_delay = 0;
totalpowerups = 0;
powerup_activate = powerup_activate*1.14;
if (rounds == dogRound && gotdog) {
roundtype = 2;
localcmd("fog 0.25\n");
} else {
roundtype = 1;
if (world.fog) {
#ifdef PSP
localcmd(strcat("fog ", world.fog));
#else
#ifdef PC
localcmd(strcat("fog ", world_fog));
#endif
#endif
}
}
Remaining_Zombies = Total_Zombies = getZombieTotal();
#ifndef NX
switch(rounds) {
case 5: GiveAchievement(0); break;
case 10: GiveAchievement(1); break;
case 15: GiveAchievement(2); break;
default: break;
}
#endif // NX
// Set up delay for zombie spawning
local float spawndelay;
spawndelay = zombie_spawn_delay;
if (spawndelay > 0.08) {
zombie_spawn_delay *= 0.95;
} else {
zombie_spawn_delay = 0.08;
}
// 2 seconds by default
if (rounds == 1)
zombie_spawn_delay = 2;
// Actually start the timer
zombie_spawn_timer = 2 + time;
if (rounds >= 10 && ach_tracker_spin == 0) {
GiveAchievement(10);
}
}
void() Round_Core =
{
if (game_over)
return;
if (round_changetime <= (time + 2) && !rounds && round_changetime) {
rounds_change = 2;
}
if (round_changetime <= (time + 2) && rounds && round_changetime) {
rounds_change = 5;
}
if (blink_return && blink_return < time && rounds_change == 6)
{
blink_return = time + 3;
rounds_change = 7;
}
if (blink_return && blink_return < time && rounds_change == 7)
{
blink_return = 0;
rounds_change = 0;
}
if (round_changetime >= time)
return;
if (round_changetime)
{
roundtype = 1;
NewRound();
return;
}
if (Total_Zombies > Current_Zombies && spawn_time < time)
{
Spawn_Enemy();
}
if (Remaining_Zombies < 1 && !Delay_Time)
{
Delay_Time = time + 2;
rounds_change = 3;
}
else if (Delay_Time && Delay_Time < time)
{
Delay_Time = 0;
EndRound();
}
SetUpdate(self, UT_ROUNDS_CHANGE, rounds_change, 0, 0);
}
void() InitRounds =
{
roundtype = 1;
delay_at_round = 2/0.95;
totalpowerups = 0;
powerup_activate = 2000/1.14;
spawnAllZombEnts();
round_changetime = time + 3.5;
rounds_change = 1;
roundinit = 1;
SetUpdate(self, UT_ROUNDS_CHANGE, rounds_change, 0, 0);
}

View file

@ -0,0 +1,233 @@
/*
server/weapons/frames_core.qc
advanced viewmodel frame iteration
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
void() ContinueRun =
{
float startframe;
float endframe;
string modelname;
startframe = GetFrame(self.weapon,SPRINT_START);
endframe = GetFrame(self.weapon,SPRINT_END);
if(!startframe && !endframe)
{
startframe = GetFrame(self.weapon,SPRINT_IN_END);
endframe = GetFrame(self.weapon,SPRINT_IN_END);
}
if (!self.downed) {
modelname = GetWeaponModel(self.weapon, 0);
} else
modelname = "";
Set_W_Frame (startframe, endframe, 0, 0, SPRINT, ContinueRun, modelname, false, S_BOTH);
}
void () W2_Frame_Update =
{
local void temp(optional float t);
// note: call whenever weapon frames are called!
if (self.anim_weapon2_time > time)
return; //don't call every frame, if it is the animations will play too fast
#ifndef PC
if (self.weapon == W_KAR_SCOPE || self.weapon == W_HEADCRACKER) {
self.weapon2frame = self.weaponframe;
return;
}
#endif
self.anim_weapon2_time = time + self.weapon2_animduration;
if (self.weapon2frame != self.weapon2frame_end && !self.anim2_reversed)
{ // continue an animation
if (self.anim2_reversed) {
self.weapon2frame = self.weapon2frame - 1;
} else {
self.weapon2frame = self.weapon2frame + 1;
}
if (self.callfuncat2)
{
if (self.weapon2frame == self.callfuncat2)
{
if (self.animend2)
{
temp = self.animend2;
self.animend2 = SUB_Null2;
if (temp)
temp(S_LEFT);
}
}
}
PlayWeaponSound(self.weapon, self.weapon2_anim_type, FALSE, self.weapon2frame);
return;
}
else
{
self.weapon2frame = self.weapon2frame_end = self.weapon2frame = GetFrame(self.weapon,BASE_FRAME);
self.new_anim2_stop = FALSE;
self.weapon2_anim_type = 0;
self.weapon2_animduration = 0;
self.callfuncat2 = 0;
temp = self.animend2;
self.animend2 = SUB_Null;
if (temp)
temp(S_LEFT);
}
};
void () W_Frame_Update =
{
local void temp(optional float t);
// note: call whenever weapon frames are called!
if (self.anim_weapon_time > time)
return; //don't call every frame, if it is the animations will play too fast
W2_Frame_Update();
self.anim_weapon_time = time + self.weapon_animduration;
if (self.weaponframe != self.weaponframe_end && !self.anim_reversed)
{ // continue an animation
if (self.anim_reversed) {
self.weaponframe = self.weaponframe - 1;
} else {
self.weaponframe = self.weaponframe + 1;
}
if (self.weaponmodel == "models/weapons/kar/v_kar.mdl" && (self.weapon == W_KAR_SCOPE || self.weapon == W_HEADCRACKER))
{
self.weapon2model = "models/weapons/kar/v_karscope.mdl";
self.weapon2frame = self.weaponframe;
//self.weapon2skin = self.weaponskin;
}
else if (self.weaponmodel == "progs/VModels/v_knife.mdl" || self.weaponmodel == "models/machines/v_perk.mdl") {
self.weapon2model = "";
UpdateV2model(self.weapon2model, 0);
}
if (self.callfuncat)
{
if (self.weaponframe == self.callfuncat)
{
if (self.animend)
{
temp = self.animend;
self.animend = SUB_Null;
if (temp)
temp(S_RIGHT);
}
}
}
PlayWeaponSound(self.weapon, self.weapon_anim_type, FALSE, self.weaponframe);
return;
}
else
{
self.weaponframe_end = self.weaponframe = GetFrame(self.weapon,BASE_FRAME);
self.new_anim_stop = FALSE;
self.weapon_anim_type = 0;
self.weapon_animduration = 0;
self.callfuncat = 0;
temp = self.animend;
self.animend = SUB_Null;
if (temp)
temp(S_RIGHT);
}
};
void Set_W_Frame (float startframe, float endframe, float duration, float funccalledin, float animtype, void(optional float t) endanimfunc, string set_model, float dontstartnew, float side) =
{
float math, reversed;
if (startframe >= endframe) {
reversed = true;
} else {
reversed = false;
}
math = 0;
if (duration) {
math = duration / (fabs(endframe - startframe) + 1);
} else {
math = 0.1;
}
if (side == S_RIGHT || side == S_BOTH) {
self.weaponframe = startframe;
self.weaponframe_end = endframe;
self.animend = endanimfunc;
self.callfuncat = funccalledin;
self.weapon_anim_type = animtype;
self.new_anim_stop = dontstartnew;
self.weapon_animduration = math;
self.anim_reversed = reversed;
}
if (side == S_LEFT || side == S_BOTH) {
self.weapon2frame = startframe;
self.weapon2frame_end = endframe;
self.weapon2_anim_type = animtype;
self.new_anim2_stop = dontstartnew;
self.weapon2_animduration = math;
self.anim2_reversed = reversed;
if (side != S_BOTH) {
self.animend2 = endanimfunc;
self.callfuncat2 = funccalledin;
}
}
if ((startframe != endframe) && !(self.zoom == 2)) { // naievil -- latter used for checkhold
if (side == S_LEFT) {
self.weapon2model = set_model;
UpdateV2model(self.weapon2model, GetWepSkin(self.weapon));
} else {
self.weaponmodel = set_model;
if (set_model != "models/machines/v_perk.mdl")
UpdateVmodel(self.weaponmodel, GetWepSkin(self.weapon));
else
UpdateVmodel(self.weaponmodel, self.weaponskin);
if (set_model == "progs/VModels/v_nade.mdl" || set_model == "progs/VModels/v_betty.mdl") {
self.weapon2model = "";
UpdateV2model(self.weapon2model, 0);
} else if (self.weapon == W_KAR_SCOPE) {
self.weapon2model = "models/weapons/kar/v_karscope.mdl";
UpdateV2model(self.weapon2model, 0);
} else if (IsDualWeapon(self.weapon)) {
self.weapon2model = GetLeftWeaponModel(self.weapon);
UpdateV2model(self.weapon2model, 0);
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,221 @@
/*
shared/defs/custom.qc
shared definitions
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
const float EVENT_WEAPONCHANGE = 9;
const float EVENT_PISTOLFIRE = 10;
const float EVENT_USEPRINT = 11;
const float EVENT_NEWROUND = 12;
const float EVENT_SETROUND = 13;
const float EVENT_UPDATEVMODEL = 20;
const float EVENT_UPDATEV2MODEL = 21;
const float EVENT_PERK = 22;
const float EVENT_UPDATE = 23;
const float EVENT_BROADCAST = 24;
const float EVENT_POINTUPDATE = 25;
const float EVENT_BLACKOUT = 26;
const float EVENT_PUNCHANGLE = 27;
const float EVENT_SCROLLTEXT = 28;
const float EVENT_WORLDDATA = 29;
const float EVENT_ACHIEVEMENT = 30;
const float EVENT_PLAYERUPDATE = 31;
const float EVENT_WEAPONUPDATE = 32;
const float EVENT_HUDUPDATE = 33;
const float EVENT_EXPLOSION = 34;
const float EVENT_BLOOD = 35;
const float EVENT_ACHIEVEMENTPROGRESS = 36;
// Define our PC version if we don't have NX or PSP
#ifndef NX
#ifndef PSP
#define PC
#endif
#endif
//nzp weapon defines
//id list
#define W_NOWEP 0
#define W_COLT 1
#define W_KAR 2
#define W_THOMPSON 3
#define W_357 4
#define W_BAR 5
#define W_BK 6
#define W_BROWNING 7
#define W_DB 8
#define W_FG 9
#define W_GEWEHR 10
#define W_KAR_SCOPE 11
#define W_M1 12
#define W_M1A1 13
#define W_M2 14
#define W_MP40 15
#define W_MG 16
#define W_PANZER 17
#define W_PPSH 18
#define W_PTRS 19
#define W_RAY 20
#define W_SAWNOFF 21
#define W_STG 22
#define W_TRENCH 23
#define W_TYPE 24
#define W_BOWIE 25
#define W_GRENADE 26
#define W_BETTY 27
#define W_BIATCH 28
#define W_KILLU 29 //357
#define W_COMPRESSOR 30 // Gewehr
#define W_M1000 31 //garand
//#define W_KOLLIDER 32
#define W_PORTER 33 // Ray
#define W_WIDDER 34 // M1A1
#define W_FIW 35 //upgraded flamethrower
#define W_ARMAGEDDON 36 //Kar
#define W_WUNDER 37
#define W_GIBS 38 // thompson
#define W_SAMURAI 39 //Type
#define W_AFTERBURNER 40 //mp40
#define W_SPATZ 41 // stg
#define W_SNUFF 42 // sawn off
#define W_BORE 43 // double barrel
#define W_IMPELLER 44 //fg
#define W_BARRACUDA 45 //mg42
#define W_ACCELERATOR 46 //M1919 browning
#define W_GUT 47 //trench
#define W_REAPER 48 //ppsh
#define W_HEADCRACKER 49 //scoped kar
#define W_LONGINUS 50 //panzer
#define W_PENETRATOR 51 //ptrs
#define W_WIDOW 52 //bar
//#define W_KRAUS 53 //ballistic
#define W_MP5 54
#define W_M14 55
#define W_TESLA 56
#define W_DG3 57
//Custom Weapons
//FIXME - use array?
#define W_CUSTOM1 70
#define W_CUSTOM2 71
#define W_CUSTOM3 72
#define W_CUSTOM4 73
#define BASE_FRAME 1
#define FIRE_START 2
#define FIRE_END 3
#define RELOAD_START 4
#define RELOAD_END 5
#define SPRINT_IN_START 12
#define SPRINT_IN_END 13
#define SPRINT_START 10
#define SPRINT_END 11
#define SPRINT_OUT_START 14
#define SPRINT_OUT_END 15
#define TAKE_OUT_START 16
#define TAKE_OUT_END 17
#define PUT_OUT_START 18
#define PUT_OUT_END 19
#define RELOAD_CANCEL 20
#define AIM_IN_START 30
#define AIM_IN_END 31
#define AIM_LOOP 33
#define AIM_OUT_START 34
#define AIM_OUT_END 35
#define AIM_FIRE_START 36
#define AIM_FIRE_END 37
//Animation types
#define RELOAD 1
#define GRENADE 2
#define FIRE 3
#define SWITCHWEP 4
#define KNIFE 5
#define ZOOM 6
#define SPRINT 7
#define PERK 8
#define KNIFE2 9
#define REVIVE 10
#define S_HEADSHOT 1
#define S_KNIFE 2
#define S_NORMAL 3
#define S_ZOMBIE 4
#define S_EXPLOSIVE 5
#define S_ZAPPER 6
#define S_TESLA 7
//Perk types
#define P_JUG 1
#define P_DOUBLE 2
#define P_SPEED 4
#define P_REVIVE 8
#define P_FLOP 16
#define P_STAMIN 32
#define P_DEAD 64
#define P_MULE 128
#define STAT_VIEWZOOM 21
#define STAT_CURRENTMAG 50
#define STAT_CURRENTMAG2 51
#define STAT_POINTS 52
#define STAT_WEAPON2FRAME 53
#define STAT_WEAPON2MODEL 54
#define STAT_GRENADES 55
#define STAT_SECGRENADES 56
#define STAT_PROGRESSBAR 57
#define STAT_WEAPONDURATION 58
#define STAT_WEAPON2DURATION 59
#define STAT_WEAPONZOOM 60
#define STAT_INSTA 61
#define STAT_X2 62
#define STAT_SPECTATING 63
#define STAT_PLAYERNUM 64
#define STAT_PLAYERSTANCE 65
#define STAT_FACINGENEMY 66
//
// invert float takes in float value between 0 and 1, inverts position
// eg: 0.1 returns 0.9, 0.34 returns 0.66
float invertfloat(float input) {
if (input <= 0 || input >= 1)
return input; // out of boundaries
return (1 - input);
}
//elements
#ifndef NX
string G_HUD;
float G_HUDHOR;
#endif
// custom weapon defs
// now 90% slimmed down
float currentWeaponTracker;

View file

@ -0,0 +1,52 @@
/*
shared/sound_enhanced.qc
mainly serves as a QC middleground for sound to adjust volume per
channel.
Copyright (C) 2021 NZ:P Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#define CHAN_MUSIC 1
#define CHAN_SFX 2
#ifndef PSP
#ifndef NX
void(string soundname, optional float channel, optional float volume) localsound_enhanced =
{
if (!volume)
volume = 1;
switch(channel) {
case 1: volume *= cvar("snd_channel1volume"); break;
case 2: volume *= cvar("snd_channel2volume"); break;
case 3: volume *= cvar("snd_channel3volume"); break;
case 4: volume *= cvar("snd_channel4volume"); break;
case 5: volume *= cvar("snd_channel5volume"); break;
case 6: volume *= cvar("snd_channel6volume"); break;
default: break;
}
localsound(soundname, channel, volume);
}
#endif
#endif

File diff suppressed because it is too large Load diff

36
tools/qc-compiler-lin.sh Normal file
View file

@ -0,0 +1,36 @@
#!/usr/bin/env bash
cd ../
# create build directories
mkdir -p build/{pc,psp,nx,vita}
cd bin/
echo ""
echo "===================="
echo " compiling FTE CCQC "
echo "===================="
echo ""
./fteqcc-cli-lin -srcfile ../progs/fte-client.src
echo ""
echo "===================="
echo " compiling FTE SSQC "
echo "===================="
echo ""
./fteqcc-cli-lin -srcfile ../progs/fte-server.src
echo ""
echo "===================="
echo " compiling PSP QC "
echo "===================="
echo ""
./fteqcc-cli-lin -srcfile ../progs/psp.src
echo ""
echo "===================="
echo " compiling NX-QS QC "
echo "===================="
echo ""
./fteqcc-cli-lin -srcfile ../progs/nx.src
echo ""
echo "===================="
echo " compiling VITA QC "
echo "===================="
echo ""
./fteqcc-cli-lin -srcfile ../progs/vita.src

39
tools/qc-compiler-win.bat Normal file
View file

@ -0,0 +1,39 @@
@ECHO OFF
CD ../
REM ****** create build directories ******
MKDIR build\pc\ 2>nul
MKDIR build\psp\ 2>nul
MKDIR build\nx\ 2>nul
MKDIR build\vita\ 2>nul
CD bin/
echo.
echo ====================
echo compiling FTE CCQC
echo ====================
echo.
fteqcc-cli-win.exe -srcfile ../progs/fte-client.src
echo.
echo ====================
echo compiling FTE SSQC
echo ====================
echo.
fteqcc-cli-win.exe -srcfile ../progs/fte-server.src
echo.
echo ====================
echo compiling PSP QC
echo ====================
echo.
fteqcc-cli-win.exe -srcfile ../progs/psp.src
echo.
echo ====================
echo compiling NX-QS QC
echo ====================
echo.
fteqcc-cli-win.exe -srcfile ../progs/nx.src
echo.
echo ====================
echo compiling VITA QC
echo ====================
echo.
fteqcc-cli-win.exe -srcfile ../progs/vita.src
pause