Compare commits

..

81 commits

Author SHA1 Message Date
Yamagi
3a1863f625 Update the CHANGELOG. 2025-04-02 11:22:25 +02:00
Yamagi
c7a4b27bf6 Fix (potential) problematic use cases of qboolean.
xatrix had only one potential problematic use case, putting an int into
qboolean. It would have worked if qboolean is a bool, but better do it
right. No functional change intended.
2025-03-15 17:58:12 +01:00
Yamagi
8878216828 Fix build with C23 by reusing the predefined bool type. 2025-03-01 12:48:49 +01:00
Yamagi
dcc5a1f616 Follow yquake2 and don't force a C standard in Makefile and CMakeLists.
This reverts 869b18c.
2025-03-01 12:47:50 +01:00
Yamagi
869b18c329 Force C standard to gnu99 in cmake builds.
The Makefiles forces gnu99 since ages. Additionally gcc15 started to
default to C23 and our code doesn't (yet) build with it. Reported in
issue #20.
2025-02-22 11:29:42 +01:00
Yamagi
0a7e3c9c78 Add a Win64 workflow file. 2025-02-09 11:34:53 +01:00
Yamagi
693e82ffa4 Add a Linux/aarch64 workflow file. 2025-02-09 11:34:17 +01:00
Yamagi
b9cac9410e Rename the Linux/x86_64 workflow file.
This is a preparation of an upcoming Linux/aarch64 build. While here
switch back to Ubuntu 22.04 as builder, we should use the same Ubuntu
version everywhere.
2025-02-09 11:33:45 +01:00
Yamagi
787de54da5 Update CI to use 4 CPUs on Linux and Windows. 2025-02-09 10:55:51 +01:00
Yamagi
6a2d5125f6 There's no need to run brew upgrade. 2024-08-12 18:21:51 +02:00
Yamagi
b8a45290a2 Add CI workflows for Linux, MacOS and Windows.
This is equivalent to the CI workflows added to the yquake2 main
repository. The workflows are triggered on commit, for new pull
requests and when the pull request branch is updated. The CI is
mostly for providing users with up to date test builds.
2024-08-12 18:03:50 +02:00
Yamagi
38cc7813dd Modernize the README.
Convert to markdown and follow the same style as the yquake2 main
repository. Use it's resources were appropriate.
2024-08-12 18:01:46 +02:00
Yamagi
a5f933ba03 Update CHANGELOG for 1.10. 2023-11-04 14:08:05 +01:00
Yamagi
95852c466c Normalize arm64 to aarch 64 on not MacOS and Windows.
This makes sure that 64 bit and 32 bit aren't endig up as `arm`, making
it possible to load 32 bit savegames on 64 bit binaries and vise versa.
This is a theoretical issue with ctf, because the mod doesn't support
savegames.

For MacOS just use what the system calls itself.

Closes #18.
2023-11-04 14:05:02 +01:00
Yamagi
4bbda4cd98 Update the CHANGELOG for 1.09. 2022-12-03 17:14:30 +01:00
Yamagi
48c30c68a3
Merge pull request #17 from Dremor8484/Dremor8484-ctf-doublebarrelshotgun-aimfix
Update weapon.c
2022-12-03 17:13:23 +01:00
Dremor8484
c99c53d4b6
Update weapon.c
the aimfix was working only on half of the attack, since the supershotgun shoots 2 times (half bullets left, half bullets right)

to carefully test it i tried to comment out 1 of the 2 shots while also keep yaw change to 0
in 1 case the bullets hit around the crossair, in the other case the bullets were not centered around the crossair.

i added the same fix to the shot that did not have it, and it worked.

i tested it out with yaw-5 and yaw+5 with both shots shooting at the same time and the bullets appeared to gather into 2 distinct clusters one left side of crossair, one right side of crossair like 2 eyes on the wall
2022-12-03 15:50:57 +01:00
Yamagi
554590fca9
Merge pull request #16 from Dremor8484/Dremor8484-ctf-doublebarrelshotgun-aimfix
Update weapon.c
2022-06-11 16:59:34 +02:00
Dremor8484
ab58bc5a37
Update weapon.c
ctf-doublebarrelshotgun-aimfix
2022-06-10 19:27:04 +02:00
Yamagi
606a52ddf4
Merge pull request #14 from tommyrot/fix_wrong_team_announced
Fix wrong team announce on flag return
2022-04-11 08:44:13 +02:00
tommyrot
7932c76d16 Fix wrong team being announced when the blue flag is returned after it gets destroyed. 2022-03-25 03:13:53 +01:00
Yamagi
55b80715ac Add a warning that the CMakeLists.txt is unmaintained. 2021-07-23 08:28:35 +02:00
Yamagi
2e2e1945e8 Revert "Retire unmaintained CMakeLists.txt."
It turned out that there're some special cases not (yet) covered by the
Makefile. Crossbuilding in specialized chroot environments are one
example.
2021-07-23 08:27:27 +02:00
Yamagi
5e4fc5a0ed Retire unmaintained CMakeLists.txt.
I added the CMakeLists.txt 6 or 7 years ago so I could load the code
into Jetbrains Clion. I have moved to another editor years ago and the
cmake stuff is effectively unmaintained since then. We kept it around
in case that we'll do a MSVC port, but that's unlikely at this point.
Since bugreport and problems with the CMakeLists.txt keep coming up,
finally retire them. They can be resurrected from the git history if
we'll ever need them again.

Part of yquake2/yquake2#725.
2021-06-29 10:49:51 +02:00
Yamagi
72b78e39ca Update the CHANGELOG for 1.08. 2021-06-14 16:33:32 +02:00
Yamagi
ff3a920d20
Merge pull request #13 from 0lvin/master
Fix function prototypes
2021-01-27 08:29:04 +01:00
Denis Pauk
5f7038c407 Fix function prototypes 2021-01-26 21:23:52 +02:00
Daniel Gibson
928066d37d Fix architecture detection on Windows in Makefile
$PROCESSOR_ARCHITECTURE seems to contain the architecture of the host,
but we need the architecture the current MinGW shell is targeting.
$MINGW_CHOST seems to be just that, and on my system it's either
i686-w64-mingw32 (mingw32.exe) or x86_64-w64-mingw32 (mingw64.exe)
(No idea what it looks like for Windows on ARM...)
2021-01-14 02:35:04 +01:00
Yamagi
f31b3264d5
Merge pull request #12 from micwoj92/patch-1
fix some typos in comments
2020-06-02 08:46:24 +02:00
micwoj92
23d0f705c6
fix some typos in comments 2020-05-21 03:07:15 +02:00
Yamagi
26019096ee Resolve oversight in last commit. 2020-04-21 13:52:24 +02:00
Yamagi
1531bcebb7 Bring Makefile on par with yquake2:
* Make CFLAGS and LDFLAGS overrideable
* Correct architecture and operating system detection.
* Enforce FPU mode.
* Implement DEBUG.
* Pass LDFLAGS after the objects.

Closes #9, closes #10.
2020-04-21 13:33:00 +02:00
Yamagi
fad0152c6b
Merge pull request #11 from mjr4077au/Client_AimFixWithCVAR
Implement accurate-aiming CVAR in ctf game code.
2020-04-21 12:51:37 +02:00
Mitchell Richters
8e92749a8b Implement accurate-aiming CVAR in ctf game code. 2020-04-21 07:44:11 +10:00
Yamagi
16198d78be Update the CHANGELOG for 1.07. 2020-02-24 17:01:11 +01:00
Yamagi
befa16b12f Add a simple .gitignore. 2020-02-24 17:00:09 +01:00
Yamagi
71574de589 Limit the fix against black debris to gibs, debris, monsters.
Pushing all entities slightly away from non-horizontal may let items to
slide to unreachable locations, or let monsters getting stuck.

This is part of yquake2/xatrix#50
2020-02-22 15:27:22 +01:00
Yamagi
2ffb440a66
Merge pull request #8 from i-amdroid/macos-build-fix
Fixed macos building.
2020-01-01 13:27:31 +01:00
Andrey Yurtaev
d209850ef7 Fixed macos building. 2019-12-21 04:30:16 +03:00
Yamagi Burmeister
cf0471a367 Push entitie slightly away from non horizontal surfaces.
Otherwise the entities origin might be in the surface, which causes it
to be rendered in full black.
2019-06-15 17:43:42 +02:00
Yamagi Burmeister
8c58273867 Put -lm into the global LDFLAGS and not into the linker command.
This is more inline with what we're doing in the other addons. And -lm
is a library that's linked unconditionally.
2019-05-13 17:11:45 +02:00
Yamagi
4f8b49daf3
Merge pull request #4 from smcv/libm
Link ctf game.so to math library
2019-05-13 17:04:59 +02:00
Yamagi Burmeister
821872c798 Build a .dylib for OS X. 2019-05-09 18:28:10 +02:00
Yamagi
15a25d8daa
Merge pull request #3 from smcv/source-date-epoch
Use SOURCE_DATE_EPOCH for reproducible build
2019-05-09 18:19:09 +02:00
Yamagi
0e35097cd0
Merge pull request #2 from smcv/spelling
Fix some spelling mistakes detected by Debian's Lintian tool
2019-05-09 18:18:36 +02:00
Yamagi Burmeister
d7457925db Don't allow 'give health 0' or even less.
Giving the player < -1 health and increasing it to something
above 0 without closing the console breaks the player state.
2019-04-27 19:20:18 +02:00
Yamagi Burmeister
c13036df55 Update the CHANGELOG for 1.06. 2019-02-04 14:36:05 +01:00
Yamagi Burmeister
08a9c4fdc1 Import Q_strlcpy() and replace several dangerous strncpy() with it. 2018-10-25 19:37:41 +02:00
Yamagi Burmeister
1e37bf132d Switch some annoying and wrang GCC warnings off. 2018-10-25 19:34:12 +02:00
Yamagi Burmeister
2d6dd4117d Call strcasecmp() and not Quake IIs home made version.
The home made version is crap and not const correct.
2018-10-25 19:31:06 +02:00
Yamagi Burmeister
b67a392cb6 Split the gibs per frame limit between gibs and debris.
The gibs and debris per frame must be limited to prevent server mem
map overflows. Until now debris and gibs were handled the same, the
debris spawned by rockets and grenates could prevent the actual gibs
of the killed monster from spawning.

Before this change 20 entities were spawned at max. Now up tp 40
enties can be spawned. This needs some testings.
2018-10-07 12:02:20 +02:00
Simon McVittie
f5449a9185 Link ctf game.so to math library
It uses sqrt() and similar functions.

Signed-off-by: Simon McVittie <smcv@debian.org>
2018-07-21 11:41:34 +01:00
Simon McVittie
3e82fe1ef2 Use SOURCE_DATE_EPOCH for reproducible build
Similar to https://github.com/yquake2/yquake2/pull/142 in the yquake2
engine/base game.

Signed-off-by: Simon McVittie <smcv@debian.org>
2018-07-21 11:39:13 +01:00
Simon McVittie
097dd56e35 Fix some spelling mistakes detected by Debian's Lintian tool
Signed-off-by: Simon McVittie <smcv@debian.org>
2018-07-21 11:33:41 +01:00
Yamagi Burmeister
ca0e44b2a4 Replace strcasecmp() by Q_strcasecmp() for better MSVC compaibility.
This was suggest by @ajbonner in xatrix issue #11.
2018-03-23 15:55:43 +01:00
Yamagi Burmeister
5447354a76 Fix a potential crash in ai_run_melee() and ai_run_missile().
This was found and fixed by Maraakate.
2017-09-07 18:12:41 +02:00
Yamagi Burmeister
6f1b2f101f Enforce static linkage of libgcc on Windows. 2017-06-16 13:48:58 +02:00
Yamagi Burmeister
327cea19f5 Update the CHANGELOG for 1.04. 2017-05-25 11:47:56 +02:00
Yamagi Burmeister
df29a29633 Reorder conditionals to please unoptimizing compilers
This was requested by Maraakate. This is likely a noop, since even
early compilers from th 1970th supported simple optimiziations like
this.
2016-12-20 15:22:57 +01:00
Yamagi Burmeister
b475a527c9 Change edict_s->show_hostile from qboolean to int and add casts
This variable is used as an integer. Defining it as a qbooblean is
just wrong. Add some explicit float -> int casts while at it.
2016-12-18 09:27:56 +01:00
Yamagi Burmeister
eadb063611 Rename teleport_time to last_sound time
teleport_time has nothing to do with teleports, it's just the time
since the last player sound. Rename it accordingly. This was suggest
by maraakate in yquake2 issue #162.
2016-12-18 09:26:51 +01:00
Yamagi Burmeister
d8d33d4353 Fix monsters ignoring the player under certain circumstances
In ai_checkattack() is a check against AI_SOUND_TARGET. If the player
made a noice and the the monster noticed this noise it's true. If
that noice was more than 5 seconds ago the monster forgets that event
and continues with it's search for the player. Otherwise it informs
the surrounding monsters that something interesting has happened and
then returns false. So the problem is: Even if the monster heard the
player and can see him, it aborts at this point.

Fix this by adding an additional visibility check. Do the sound
checking only if the player is not visible, otherwise just continue.

This was reported by shoober420 and debbuged by maraakate. This fix
was DanielGibons idea. This commit fixes yquake2 issue #162.
2016-12-18 09:25:42 +01:00
Yamagi Burmeister
b71b80d790 Generate game.dylib on OS X. Fixes #148. 2016-08-14 16:31:46 +02:00
Yamagi Burmeister
8439d43508 Update the CHANGELOG 2016-06-25 10:32:41 +02:00
Yamagi Burmeister
adb307b197 Switch from an arch whitelist to an "all archs are supported" approach. 2016-06-11 09:53:38 +02:00
Yamagi Burmeister
8cef59c4c8 Make gibs and debris SOLID_BBOX so they move on entities. 2016-04-29 17:47:19 +02:00
Martin Hauke
a089f4c747 Fix CMake support 2016-03-17 09:02:00 +01:00
Yamagi Burmeister
8a40cd5e9f Reset gibsthisframe and lastgibframe at map change
Without this change the conditionals at g_misc.c:199 and 381 wouldn't
trigger until level.framenum reach it's previous value, resulting in
much to few debris or gibs being thrown. This fixes #104.

Many thanks to maraakate for the analysis and the idea how to fix it.
2015-10-24 13:14:31 +02:00
Yamagi Burmeister
0516300a11 Update CHANGELOG 2015-09-07 17:15:12 +02:00
Yamagi Burmeister
36ed53346e fix a divinely dumbassed mistake of global 'i' and 'corners' variables
Submitted by: Ozkan Sezer
2015-08-31 18:54:02 +02:00
Yamagi Burmeister
70c9889d16 Info_RemoveKey: use memmove instead of strcpy for overlapping memory areas.
Submitted by: Ozkan Sezer
2015-08-31 18:53:18 +02:00
Yamagi Burmeister
445f266843 SV_Physics_Pusher: fix the 'memory corrupted' check
Submitted by: Ozkan Sezer
2015-08-31 18:48:27 +02:00
Yamagi Burmeister
ee24659ba4 fix several printf format string errors in games' code
Submitted by: Ozkan Sezer
2015-08-31 18:46:49 +02:00
Yamagi Burmeister
a65b93192c Removed unused prototype to GetGameApi()
Submitted by: Ozkan Sezer
2015-08-31 18:44:19 +02:00
Yamagi Burmeister
dffca8fc79 Add CMake support 2015-08-23 19:17:53 +02:00
Daniel Gibson
988afce481 Fix bug with high velocities in vents in 32bit builds, fix MingW build
See https://github.com/yquake2/yquake2/issues/71
and https://github.com/yquake2/xatrix/issues/4

In ClientThink(), the float value ent->velocity[i]*8 is saved into
a short and if the value is too big for a short, in 32bit gcc builds
the short is set to SHRT_MIN, resulting in the player being pressed
down instead of up.
Now we put the result in a 32bit int first (which should be big enough)
and assign the int to the short. This still overflows, but with -fwrapv
at least in a defined way (most probably the same way the original
binaries did).

The Makefile now sets $CC to gcc for MingW builds, this should fix
https://github.com/yquake2/xatrix/issues/3

And while I was at it, when the game lib is loaded, it prints the date
it was built, this is especially interesting for our Win32 binaries.
2015-05-17 18:45:26 +02:00
Daniel Gibson
e2b397d92c One entity shooting another should work even if friendly fire is off
In rogue's RHANGAR1 the turret didn't blow up the ceiling when friendly fire
was off, because in ClientTeam() both entities were set to "" (no team),
but OnSameTeam() just did a strcmp() instead of checking this special
case (no team).
We check this now and thus it works. Hooray.
I also refactored ClientTeam() to take the buffer instead of using a
static one and to be static (it's only called by OnSameTeam() anyway).
2014-11-30 18:02:32 +01:00
Yamagi Burmeister
ca84136e65 Use the correct flavors of abs() 2014-08-03 11:16:08 +02:00
Yamagi Burmeister
017bc7276f Rewrite COM_FileExtention()
COM_FileExtension() was parsing strings from beginning to end, bailing
out as soon as '.' was found and treating everything thereafter as the
file extension. That behavior caused problem with relatives pathes like
models/monsters/tank/../ctank/skin.pcx. The new implementation uses
strrchr() to determine the last '.'.
2014-07-30 21:39:58 +02:00
Yamagi Burmeister
5caf9c980f Remove the now unneeded mkdir.exe 2014-02-14 13:19:13 +01:00
Yamagi Burmeister
6286419315 Port the Makefile to our new Windows build environment 2014-02-14 11:47:30 +01:00
29 changed files with 872 additions and 277 deletions

45
.github/workflows/linux_aarch64.yml vendored Normal file
View file

@ -0,0 +1,45 @@
name: Testbuild for Linux (aarch64)
run-name: testbuild_linux_aarch64
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_ubuntu_aarch64:
runs-on: ubuntu-22.04-arm
strategy:
fail-fast: false
matrix:
include:
- env: ubuntu
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
run: |
# Public runners come with 4 CPUs.
make -j4
- name: Create testbuild package
run: |
# Create release directory tree
mkdir -p publish/quake2-ctf-linux_aarch64-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-ctf-linux_aarch64-${{github.sha}}/
# Copy misc assets
cp LICENSE publish/quake2-ctf-linux_aarch64-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-ctf-linux_aarch64-${{github.sha}}/misc/docs/README.txt
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-ctf-linux_aarch64-${{github.sha}}
path: publish/
if-no-files-found: error

45
.github/workflows/linux_x86_64.yml vendored Normal file
View file

@ -0,0 +1,45 @@
name: Testbuild for Linux (x86_64)
run-name: testbuild_linux_x86_64
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_ubuntu_x86_64:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
include:
- env: ubuntu
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
run: |
# Public runners come with 4 CPUs.
make -j4
- name: Create testbuild package
run: |
# Create release directory tree
mkdir -p publish/quake2-ctf-linux_x86_64-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-ctf-linux_x86_64-${{github.sha}}/
# Copy misc assets
cp LICENSE publish/quake2-ctf-linux_x86_64-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-ctf-linux_x86_64-${{github.sha}}/misc/docs/README.txt
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-ctf-linux_x86_64-${{github.sha}}
path: publish/
if-no-files-found: error

49
.github/workflows/macos.yml vendored Normal file
View file

@ -0,0 +1,49 @@
name: Testbuild for MacOS
run-name: testbuild_macos
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_macos_aarch64:
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
include:
- env: macos
steps:
- name: Install build dependencies
run: |
brew update
brew install make
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
run: |
# Public runners come with 3 CPUs.
gmake -j3
- name: Create testbuild package
run: |
# Create release directory tree
mkdir -p publish/quake2-ctf-macos-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-ctf-macos-${{github.sha}}/
# Copy misc assets
cp LICENSE publish/quake2-ctf-macos-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-ctf-macos-${{github.sha}}/misc/docs/README.txt
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-ctf-macos-${{github.sha}}
path: publish/
if-no-files-found: error

56
.github/workflows/win32.yml vendored Normal file
View file

@ -0,0 +1,56 @@
name: Testbuild for Win32
run-name: testbuild_win32
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_mingw_x86_32:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- { sys: mingw32, env: i686 }
steps:
- uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.sys}}
update: true
install: >-
git
make
mingw-w64-${{matrix.env}}-gcc
mingw-w64-${{matrix.env}}-make
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
shell: msys2 {0}
run: |
# Public runners come with 4 CPUs.
make -j4
- name: Create testbuild package
shell: msys2 {0}
run: |
# Create release directory tree
mkdir -p publish/quake2-ctf-win32-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-ctf-win32-${{github.sha}}/
# Copy misc assets
cp LICENSE publish/quake2-ctf-win32-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-ctf-win32-${{github.sha}}/misc/docs/README.txt
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-ctf-win32-${{github.sha}}
path: publish/
if-no-files-found: error

56
.github/workflows/win64.yml vendored Normal file
View file

@ -0,0 +1,56 @@
name: Testbuild for Win64
run-name: testbuild_win64
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_mingw_x86_64:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- { sys: mingw64, env: x86_64 }
steps:
- uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.sys}}
update: true
install: >-
git
make
mingw-w64-${{matrix.env}}-gcc
mingw-w64-${{matrix.env}}-make
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
shell: msys2 {0}
run: |
# Public runners come with 4 CPUs.
make -j4
- name: Create testbuild package
shell: msys2 {0}
run: |
# Create release directory tree
mkdir -p publish/quake2-ctf-win64-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-ctf-win64-${{github.sha}}/
# Copy misc assets
cp LICENSE publish/quake2-ctf-win64-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-ctf-win64-${{github.sha}}/misc/docs/README.txt
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-ctf-win64-${{github.sha}}
path: publish/
if-no-files-found: error

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
build/
release/

View file

@ -1,3 +1,35 @@
Three Wave Capture The Flag 1.10 to 1.11
- Fix build in C23 mode.
Three Wave Capture The Flag 1.09 to 1.10
- Fix build on ARM Macs.
Three Wave Capture The Flag 1.08 to 1.09
- Several small bugfixes.
Three Wave Capture The Flag 1.07 to 1.08
- Several small bugfixes.
Three Wave Capture The Flag 1.06 to 1.07
- Several small bugfixes.
Three Wave Capture The Flag 1.05 to 1.06
- Small bugfixes.
- Better compatibility with the current Windows build environment.
Three Wave Capture The Flag 1.04 to 1.05
- Some bugfixes to monster AI, mostly to keep the source
in sync with baseq2 and the other addons.
Three Wave Capture The Flag 1.03 to 1.04
- Fix CMake support
- Make gibs and debris SOLID_BBOX so they move on entities.
- Switch from an arch whitelist to an "all archs are supported"
approach.
Three Wave Capture The Flag 1.02 to 1.03
- Add CMake as an optional build system.
- Fix bug with high velocities in vents in 32bit builds.
Three Wave Capture The Flag 1.01 to 1.02
- Port "Three Wave Capture The Flag" to Mac OS X

76
CMakeLists.txt Normal file
View file

@ -0,0 +1,76 @@
cmake_minimum_required(VERSION 3.0)
# Print a message that using the Makefiles is recommended.
message(NOTICE: " The CMakeLists.txt is unmaintained. Use the Makefile if possible.")
# Enforce "Debug" as standard build type
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
endif(NOT CMAKE_BUILD_TYPE)
# CMake project configuration
project(yquake2-ctf)
# Enforce compiler flags (GCC / Clang compatible, yquake2
# won't build with another compiler anyways)
# -Wall -> More warnings
# -fno-strict-aliasing -> Quake 2 is far away from strict aliasing
# -fwrapv -> Make signed integer overflows defined
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fno-strict-aliasing -fwrapv")
# Use -O2 as maximum optimization level. -O3 has it's problems with yquake2.
string(REPLACE "-O3" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
# Linker Flags
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
list(APPEND CtfLinkerFlags "-lm")
else()
list(APPEND CtfLinkerFlags "-lm -rdynamic")
endif()
set(Ctf-Source
src/menu/menu.c
src/monster/move.c
src/player/client.c
src/player/hud.c
src/player/trail.c
src/player/view.c
src/player/weapon.c
src/shared/shared.c
src/g_ai.c
src/g_chase.c
src/g_cmds.c
src/g_combat.c
src/g_ctf.c
src/g_func.c
src/g_items.c
src/g_main.c
src/g_misc.c
src/g_monster.c
src/g_phys.c
src/g_save.c
src/g_spawn.c
src/g_svcmds.c
src/g_target.c
src/g_trigger.c
src/g_utils.c
src/g_weapon.c
)
set(Ctf-Header
src/header/ctf.h
src/header/game.h
src/header/local.h
src/header/menu.h
src/header/shared.h
src/monster/player.h
)
# Build the ctf dynamic library
add_library(game SHARED ${Ctf-Source} ${Ctf-Header})
set_target_properties(game PROPERTIES
PREFIX ""
LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/Debug
LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/Release
)
target_link_libraries(game ${CtfLinkerFlags})

213
Makefile Normal file → Executable file
View file

@ -6,72 +6,161 @@
# #
# Dependencies: #
# - None, but you need a Quake II to play. #
# While in theorie every one should work #
# Yamagi Quake II ist recommended. #
# While in theory every one should work #
# Yamagi Quake II is recommended. #
# #
# Platforms: #
# - FreeBSD #
# - Linux #
# - Mac OS X #
# - OpenBSD #
# - Windows #
# ----------------------------------------------------- #
# Detect the OS
ifdef SystemRoot
OSTYPE := Windows
YQ2_OSTYPE ?= Windows
else
OSTYPE := $(shell uname -s)
YQ2_OSTYPE ?= $(shell uname -s)
endif
# Special case for MinGW
ifneq (,$(findstring MINGW,$(YQ2_OSTYPE)))
YQ2_OSTYPE := Windows
endif
# Detect the architecture
ifeq ($(OSTYPE), Windows)
# At this time only i386 is supported on Windows
ARCH := i386
ifeq ($(YQ2_OSTYPE), Windows)
ifdef MINGW_CHOST
ifeq ($(MINGW_CHOST), x86_64-w64-mingw32)
YQ2_ARCH ?= x86_64
else # i686-w64-mingw32
YQ2_ARCH ?= i386
endif
else # windows, but MINGW_CHOST not defined
ifdef PROCESSOR_ARCHITEW6432
# 64 bit Windows
YQ2_ARCH ?= $(PROCESSOR_ARCHITEW6432)
else
# Some platforms call it "amd64" and some "x86_64"
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/amd64/x86_64/)
# 32 bit Windows
YQ2_ARCH ?= $(PROCESSOR_ARCHITECTURE)
endif
endif # windows but MINGW_CHOST not defined
else
ifneq ($(YQ2_OSTYPE), Darwin)
# Normalize some abiguous YQ2_ARCH strings
YQ2_ARCH ?= $(shell uname -m | sed -e 's/i.86/i386/' -e 's/amd64/x86_64/' -e 's/arm64/aarch64/' -e 's/^arm.*/arm/')
else
YQ2_ARCH ?= $(shell uname -m)
endif
endif
# Refuse all other platforms as a firewall against PEBKAC
# (You'll need some #ifdef for your unsupported plattform!)
ifeq ($(findstring $(ARCH), i386 x86_64 sparc64),)
$(error arch $(ARCH) is currently not supported)
# On Windows / MinGW $(CC) is undefined by default.
ifeq ($(YQ2_OSTYPE),Windows)
CC ?= gcc
endif
# Detect the compiler
ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
COMPILER := clang
COMPILERVER := $(shell $(CC) -dumpversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/')
else ifeq ($(shell $(CC) -v 2>&1 | grep -c -E "(gcc version|gcc-Version)"), 1)
COMPILER := gcc
COMPILERVER := $(shell $(CC) -dumpversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/')
else
COMPILER := unknown
endif
# ----------
# Base CFLAGS.
#
# -O2 are enough optimizations.
#
# -fno-strict-aliasing since the source doesn't comply
# with strict aliasing rules and it's next to impossible
# to get it there...
#
# -fomit-frame-pointer since the framepointer is mostly
# useless for debugging Quake II and slows things down.
#
# -g to build allways with debug symbols. Please do not
# change this, since it's our only chance to debug this
# crap when random crashes happen!
#
# -fPIC for position independend code.
#
# -MMD to generate header dependencies.
ifeq ($(OSTYPE), Darwin)
CFLAGS := -O2 -fno-strict-aliasing -fomit-frame-pointer \
-Wall -pipe -g -arch i386 -arch x86_64
# Base CFLAGS. These may be overridden by the environment.
# Highest supported optimizations are -O2, higher levels
# will likely break this crappy code.
ifdef DEBUG
CFLAGS ?= -O0 -g -Wall -pipe
else
CFLAGS := -O2 -fno-strict-aliasing -fomit-frame-pointer \
-Wall -pipe -g -MMD
CFLAGS ?= -O2 -Wall -pipe -fomit-frame-pointer
endif
# Always needed are:
# -fno-strict-aliasing since the source doesn't comply
# with strict aliasing rules and it's next to impossible
# to get it there...
# -fwrapv for defined integer wrapping. MSVC6 did this
# and the game code requires it.
override CFLAGS += -fno-strict-aliasing -fwrapv
# -MMD to generate header dependencies. Unsupported by
# the Clang shipped with OS X.
ifneq ($(YQ2_OSTYPE), Darwin)
override CFLAGS += -MMD
endif
# OS X architecture.
ifeq ($(YQ2_OSTYPE), Darwin)
override CFLAGS += -arch $(YQ2_ARCH)
endif
# ----------
# Switch off some annoying warnings.
ifeq ($(COMPILER), clang)
# -Wno-missing-braces because otherwise clang complains
# about totally valid 'vec3_t bla = {0}' constructs.
CFLAGS += -Wno-missing-braces
else ifeq ($(COMPILER), gcc)
# GCC 8.0 or higher.
ifeq ($(shell test $(COMPILERVER) -ge 80000; echo $$?),0)
# -Wno-format-truncation and -Wno-format-overflow
# because GCC spams about 50 false positives.
CFLAGS += -Wno-format-truncation -Wno-format-overflow
endif
endif
# ----------
# Defines the operating system and architecture
override CFLAGS += -DYQ2OSTYPE=\"$(YQ2_OSTYPE)\" -DYQ2ARCH=\"$(YQ2_ARCH)\"
# ----------
# For reproducible builds, look here for details:
# https://reproducible-builds.org/specs/source-date-epoch/
ifdef SOURCE_DATE_EPOCH
CFLAGS += -DBUILD_DATE=\"$(shell date --utc --date="@${SOURCE_DATE_EPOCH}" +"%b %_d %Y" | sed -e 's/ /\\ /g')\"
endif
# ----------
# Using the default x87 float math on 32bit x86 causes rounding trouble
# -ffloat-store could work around that, but the better solution is to
# just enforce SSE - every x86 CPU since Pentium3 supports that
# and this should even improve the performance on old CPUs
ifeq ($(YQ2_ARCH), i386)
override CFLAGS += -msse -mfpmath=sse
endif
# Force SSE math on x86_64. All sane compilers should do this
# anyway, just to protect us from broken Linux distros.
ifeq ($(YQ2_ARCH), x86_64)
override CFLAGS += -mfpmath=sse
endif
# ----------
# Base LDFLAGS.
ifeq ($(OSTYPE), Darwin)
LDFLAGS := -shared -arch i386 -arch x86_64
LDFLAGS ?=
# It's a shared library.
override LDFLAGS += -shared
# Required libraries
ifeq ($(YQ2_OSTYPE), Darwin)
override LDFLAGS += -arch $(YQ2_ARCH)
else ifeq ($(YQ2_OSTYPE), Windows)
override LDFLAGS += -static-libgcc
else
LDFLAGS := -shared
override LDFLAGS += -lm
endif
# ----------
@ -80,7 +169,7 @@ endif
all: ctf
# ----------
# When make is invoked by "make VERBOSE=1" print
# the compiler and linker commands.
@ -96,45 +185,39 @@ endif
.PHONY : all clean ctf
# ----------
# Cleanup
ifeq ($(OSTYPE), Windows)
clean:
@echo "===> CLEAN"
@-rmdir /S /Q release build
else
clean:
@echo "===> CLEAN"
${Q}rm -Rf build release
endif
# ----------
# The ctf game
ifeq ($(OSTYPE), Windows)
ifeq ($(YQ2_OSTYPE), Windows)
ctf:
@echo "===> Building game.dll"
$(Q)tools/mkdir.exe -p release
$(Q)mkdir -p release
$(MAKE) release/game.dll
build/%.o: %.c
@echo "===> CC $<"
$(Q)tools/mkdir.exe -p $(@D)
$(Q)$(CC) -c $(CFLAGS) -o $@ $<
else ifeq ($(YQ2_OSTYPE), Darwin)
ctf:
@echo "===> Building game.dylib"
${Q}mkdir -p release
$(MAKE) release/game.dylib
else
ctf:
@echo "===> Building game.so"
$(Q)mkdir -p release
$(MAKE) release/game.so
release/game.so : CFLAGS += -fPIC
endif
build/%.o: %.c
@echo "===> CC $<"
$(Q)mkdir -p $(@D)
$(Q)$(CC) -c $(CFLAGS) -o $@ $<
release/game.so : CFLAGS += -fPIC
endif
# ----------
CTF_OBJS_ = \
@ -163,7 +246,7 @@ CTF_OBJS_ = \
src/player/trail.o \
src/player/view.o \
src/player/weapon.o \
src/shared/shared.o
src/shared/shared.o
# ----------
@ -182,14 +265,18 @@ CTF_DEPS= $(CTF_OBJS:.o=.d)
# ----------
ifeq ($(OSTYPE), Windows)
ifeq ($(YQ2_OSTYPE), Windows)
release/game.dll : $(CTF_OBJS)
@echo "===> LD $@"
$(Q)$(CC) $(LDFLAGS) -o $@ $(CTF_OBJS)
$(Q)$(CC) -o $@ $(CTF_OBJS) $(LDFLAGS)
else ifeq ($(YQ2_OSTYPE), Darwin)
release/game.dylib : $(CTF_OBJS)
@echo "===> LD $@"
${Q}$(CC) -o $@ $(CTF_OBJS) $(LDFLAGS)
else
release/game.so : $(CTF_OBJS)
@echo "===> LD $@"
$(Q)$(CC) $(LDFLAGS) -o $@ $(CTF_OBJS)
$(Q)$(CC) -o $@ $(CTF_OBJS) $(LDFLAGS)
endif
# ----------

32
README
View file

@ -1,32 +0,0 @@
This is a 64 bit clean and bugfixed version of id Software's Quake II
addon pack "Capture The Flag", developed by David 'Zoid' Kirsch. Hundred
of type errors and strange constructs were fixed, thus this version
should run much more stable than the old SDK version. While it may work
with every Quake II client, the "Yamagi Quake II" client is highly
recommended. For more Information visit http://www.yamagi.org/quake2.
Installation for FreeBSD, Linux and OpenBSD:
--------------------------------------------
1. Type "make" or "gmake" to compile the game.so.
2. Copy release/game.so to the ctf/ subfolder of your Quake II
installation. The CTF gamedata is part of the 3.20 point release.
3. Start the game with "./quake2 +set game ctf".
Installation for OS X:
----------------------
1. Copy game.dll from the zip-archive to ctf/.
2. Start the game with "quake2 +set game ctf"
If you want to compile 'ctf' for OS X from source, please take a look at
the "Installation" section of the README of the Yamagi Quake II client.
In the same file the integration into an app-bundle is explained.
Installation for Windows:
-------------------------
1. Copy the game.dll to the ctf\ subfolder of your Quake II
installation. The CTF gamedata is part of the 3.20 point release.
2. Start the game with "quake2.exe +set game ctf".
If you want to compile 'ctf' for Windows from source, please take a
look at the "Installation" section of the README of the Yamagi Quake
II client. There's descripted how to setup the build environment.

66
README.md Normal file
View file

@ -0,0 +1,66 @@
# Three Wave Capture The Flag for Yamagi Quake II
Three Wave Capture The Flag for Yamagi Quake II is a bugfixed version of
the official CTF addon for Quake II. It's based upon the Quake II source
code release and and is licensed under GPL version 2:
* [LICENSE](https://github.com/yquake2/ctf/blob/master/LICENSE)
Several bugs were fixed. The addon is intended to be used with Yamagi
Quake II, but it's also fully backward compatible with the last Quake II
pointrelease 3.20 and may work with other source ports.
Officially supported operating systems are:
* FreeBSD
* Linux
* Windows
Beside theses Three Wave Capture The Flag for Yamagi Quake II has
community support for MacOS and most other unixoid operating systems,
including NetBSD, OpenBSD and Solaris.
## Development
Three Wave Capture The Flag for Yamagi Quake II is a community driven
project and lives from community involvement. Please report bugs in our
issue tracker:
* [Issue Tracker](https://github.com/yquake2/ctf/issues)
We are always open to code contributions, no matter if they are small
bugfixes or bigger features. However, Yamagi Quake II is a conservative
project with big focus on stability and backward compatibility. We don't
accept breaking changes. When in doubt please open an issue and ask if a
contribution in welcome before putting too much work into it. Open a
pull request to submit code:
* [Pull Requests](https://github.com/yquake2/ctf/pulls)
Also have a look at our contributors guide:
* [Contributors Guide](https://github.com/yquake2/yquake2/blob/master/doc/080_contributing.md)
## Documentation
Yamagi Quake II has rather extensive documentation covering all relevant
areas from installation and configuration to package building. Have a
look at the documentation index:
* [Documentation Index](https://github.com/yquake2/yquake2/blob/master/doc/010_index.md)
## Releases
Three Wave Capture The Flag for Yamagi Quake II releases at an irregular
schedule. The official releases with source code tarballs and prebuild
Windows binaries can be found at the homepage:
* [Homepage](https://www.yamagi.org/quake2/)
Our CI builds **unsupported** Linux, MacOS and Windows binaries at every
commit. The artifacts can be found here:
* [Github Actions](https://github.com/yquake2/ctf/actions)

View file

@ -404,7 +404,7 @@ FoundTarget(edict_t *self)
level.sight_entity->light_level = 128;
}
self->show_hostile = level.time + 1; /* wake up other monsters */
self->show_hostile = (int)level.time + 1; /* wake up other monsters */
VectorCopy(self->enemy->s.origin, self->monsterinfo.last_sighting);
self->monsterinfo.trail_time = level.time;
@ -577,7 +577,7 @@ FindTarget(edict_t *self)
if (r == RANGE_NEAR)
{
if ((client->show_hostile < level.time) && !infront(self, client))
if ((client->show_hostile < (int)level.time) && !infront(self, client))
{
return false;
}
@ -810,8 +810,11 @@ ai_run_melee(edict_t *self)
if (FacingIdeal(self))
{
self->monsterinfo.melee(self);
self->monsterinfo.attack_state = AS_STRAIGHT;
if (self->monsterinfo.melee)
{
self->monsterinfo.melee(self);
self->monsterinfo.attack_state = AS_STRAIGHT;
}
}
}
@ -827,8 +830,11 @@ ai_run_missile(edict_t *self)
if (FacingIdeal(self))
{
self->monsterinfo.attack(self);
self->monsterinfo.attack_state = AS_STRAIGHT;
if (self->monsterinfo.attack)
{
self->monsterinfo.attack(self);
self->monsterinfo.attack_state = AS_STRAIGHT;
}
}
}
@ -882,9 +888,9 @@ ai_checkattack(edict_t *self, float dist)
return false;
}
if (self->monsterinfo.aiflags & AI_SOUND_TARGET)
if ((self->monsterinfo.aiflags & AI_SOUND_TARGET) && !visible(self, self->goalentity))
{
if ((level.time - self->enemy->teleport_time) > 5.0)
if ((level.time - self->enemy->last_sound_time) > 5.0)
{
if (self->goalentity == self->enemy)
{
@ -908,7 +914,7 @@ ai_checkattack(edict_t *self, float dist)
}
else
{
self->show_hostile = level.time + 1;
self->show_hostile = (int)level.time + 1;
return false;
}
}
@ -980,7 +986,7 @@ ai_checkattack(edict_t *self, float dist)
}
}
self->show_hostile = level.time + 1; /* wake up other monsters */
self->show_hostile = (int)level.time + 1; /* wake up other monsters */
/* check knowledge of enemy */
enemy_vis = visible(self, self->enemy);

View file

@ -27,11 +27,10 @@
#include "header/local.h"
#include "monster/player.h"
char *
ClientTeam(edict_t *ent)
static char *
ClientTeam(edict_t *ent, char* value)
{
char *p;
static char value[512];
value[0] = 0;
@ -68,10 +67,10 @@ OnSameTeam(edict_t *ent1, edict_t *ent2)
return false;
}
strcpy(ent1Team, ClientTeam(ent1));
strcpy(ent2Team, ClientTeam(ent2));
ClientTeam(ent1, ent1Team);
ClientTeam(ent2, ent2Team);
if (strcmp(ent1Team, ent2Team) == 0)
if (ent1Team[0] != '\0' && strcmp(ent1Team, ent2Team) == 0)
{
return true;
}
@ -230,6 +229,7 @@ Cmd_Give_f(edict_t *ent)
if (gi.argc() == 3)
{
ent->health = atoi(gi.argv(2));
ent->health = ent->health < 1 ? 1 : ent->health;
}
else
{

View file

@ -731,7 +731,7 @@ CTFFragBonuses(edict_t *targ, edict_t *inflictor, edict_t *attacker)
flag carrier */
attacker->client->resp.score += CTF_CARRIER_DANGER_PROTECT_BONUS;
gi.bprintf(PRINT_MEDIUM,
"%s defends %s's flag carrier against an agressive enemy\n",
"%s defends %s's flag carrier against an aggressive enemy\n",
attacker->client->pers.netname,
CTFTeamName(attacker->client->resp.ctf_team));
@ -1718,8 +1718,7 @@ CTFGrappleDrawCable(edict_t *self)
AngleVectors(self->owner->client->v_angle, f, r, NULL);
VectorSet(offset, 16, 16, self->owner->viewheight - 8);
P_ProjectSource(self->owner->client, self->owner->s.origin,
offset, f, r, start);
P_ProjectSource(self->owner, offset, f, r, start);
VectorSubtract(start, self->owner->s.origin, offset);
@ -1903,7 +1902,7 @@ CTFGrappleFire(edict_t *ent, vec3_t g_offset, int damage, int effect)
AngleVectors(ent->client->v_angle, forward, right, NULL);
VectorSet(offset, 24, 8, ent->viewheight - 8 + 2);
VectorAdd(offset, g_offset, offset);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
VectorScale(forward, -2, ent->client->kick_origin);
ent->client->kick_angles[0] = -1;
@ -3621,7 +3620,7 @@ CTFWinElection(void)
gi.bprintf(PRINT_HIGH, "%s has become an admin.\n",
ctfgame.etarget->client->pers.netname);
gi.cprintf(ctfgame.etarget, PRINT_HIGH,
"Type 'admin' to access the adminstration menu.\n");
"Type 'admin' to access the administration menu.\n");
break;
case ELECT_MAP:
@ -3723,7 +3722,7 @@ CTFReady(edict_t *ent)
if (ent->client->resp.ready)
{
gi.cprintf(ent, PRINT_HIGH, "You have already commited.\n");
gi.cprintf(ent, PRINT_HIGH, "You have already committed.\n");
return;
}
@ -3758,8 +3757,8 @@ CTFReady(edict_t *ent)
if (!j && t1 && t2)
{
/* everyone has commited */
gi.bprintf(PRINT_CHAT, "All players have commited. Match starting\n");
/* everyone has committed */
gi.bprintf(PRINT_CHAT, "All players have committed. Match starting\n");
ctfgame.match = MATCH_PREGAME;
ctfgame.matchtime = level.time + matchstarttime->value;
ctfgame.countdown = false;
@ -3785,7 +3784,7 @@ CTFNotReady(edict_t *ent)
if (!ent->client->resp.ready)
{
gi.cprintf(ent, PRINT_HIGH, "You haven't commited.\n");
gi.cprintf(ent, PRINT_HIGH, "You haven't committed.\n");
return;
}
@ -5013,7 +5012,7 @@ CTFAdmin_Reset(edict_t *ent, pmenuhnd_t *p)
PMenu_Close(ent);
/* go back to normal mode */
gi.bprintf(PRINT_CHAT, "Match mode has been terminated, reseting to normal game.\n");
gi.bprintf(PRINT_CHAT, "Match mode has been terminated, resetting to normal game.\n");
ctfgame.match = MATCH_NONE;
gi.cvar_set("competition", "1");
CTFResetAllPlayers();
@ -5082,7 +5081,7 @@ CTFAdmin(edict_t *ent)
ent->client->resp.admin = true;
gi.bprintf(PRINT_HIGH, "%s has become an admin.\n",
ent->client->pers.netname);
gi.cprintf(ent, PRINT_HIGH, "Type 'admin' to access the adminstration menu.\n");
gi.cprintf(ent, PRINT_HIGH, "Type 'admin' to access the administration menu.\n");
}
if (!ent->client->resp.admin)

View file

@ -77,6 +77,8 @@ cvar_t *flood_waitdelay;
cvar_t *sv_maplist;
cvar_t *aimfix;
void SpawnEntities(char *mapname, char *entities, char *spawnpoint);
void ClientThink(edict_t *ent, usercmd_t *cmd);
qboolean ClientConnect(edict_t *ent, char *userinfo);
@ -279,7 +281,7 @@ EndDMLevel(void)
ent = G_Find(NULL, FOFS(classname), "target_changelevel");
if (!ent)
{
{
/* the map designer didn't include a changelevel,
so create a fake ent that goes back to the same level */
BeginIntermission(CreateTargetChangeLevel(level.mapname));
@ -384,6 +386,9 @@ ExitLevel(void)
ent->health = ent->client->pers.max_health;
}
}
gibsthisframe = 0;
debristhisframe = 0;
}
/*
@ -398,6 +403,9 @@ G_RunFrame(void)
level.framenum++;
level.time = level.framenum * FRAMETIME;
gibsthisframe = 0;
debristhisframe = 0;
/* choose a client for monsters to target this frame */
AI_SetSightClient();

View file

@ -1,7 +1,7 @@
#include "header/local.h"
int gibsthisframe = 0;
int lastgibframe = 0;
int debristhisframe;
int gibsthisframe;
/*
* QUAKED func_group (0 0 0) ?
@ -139,15 +139,9 @@ ThrowGib(edict_t *self, char *gibname, int damage, int type)
vec3_t size;
float vscale;
if (level.framenum > lastgibframe)
{
gibsthisframe = 0;
lastgibframe = level.framenum;
}
gibsthisframe++;
if (gibsthisframe > 20)
if (gibsthisframe > MAX_GIBS)
{
return;
}
@ -161,11 +155,12 @@ ThrowGib(edict_t *self, char *gibname, int damage, int type)
gib->s.origin[2] = origin[2] + crandom() * size[2];
gi.setmodel(gib, gibname);
gib->solid = SOLID_NOT;
gib->solid = SOLID_BBOX;
gib->s.effects |= EF_GIB;
gib->flags |= FL_NO_KNOCKBACK;
gib->takedamage = DAMAGE_YES;
gib->die = gib_die;
gib->health = 250;
if (type == GIB_ORGANIC)
{
@ -205,7 +200,7 @@ ThrowHead(edict_t *self, char *gibname, int damage, int type)
self->s.modelindex2 = 0;
gi.setmodel(self, gibname);
self->solid = SOLID_NOT;
self->solid = SOLID_BBOX;
self->s.effects |= EF_GIB;
self->s.effects &= ~EF_FLIES;
self->s.sound = 0;
@ -262,7 +257,7 @@ ThrowClientHead(edict_t *self, int damage)
VectorSet(self->maxs, 16, 16, 16);
self->takedamage = DAMAGE_NO;
self->solid = SOLID_NOT;
self->solid = SOLID_BBOX;
self->s.effects = EF_GIB;
self->s.sound = 0;
self->flags |= FL_NO_KNOCKBACK;
@ -293,15 +288,9 @@ ThrowDebris(edict_t *self, char *modelname, float speed, vec3_t origin)
edict_t *chunk;
vec3_t v;
if (level.framenum > lastgibframe)
{
gibsthisframe = 0;
lastgibframe = level.framenum;
}
debristhisframe++;
gibsthisframe++;
if (gibsthisframe > 20)
if (debristhisframe > MAX_DEBRIS)
{
return;
}
@ -314,7 +303,7 @@ ThrowDebris(edict_t *self, char *modelname, float speed, vec3_t origin)
v[2] = 100 + 100 * crandom();
VectorMA(self->velocity, speed, v, chunk->velocity);
chunk->movetype = MOVETYPE_BOUNCE;
chunk->solid = SOLID_NOT;
chunk->solid = SOLID_BBOX;
chunk->avelocity[0] = random() * 600;
chunk->avelocity[1] = random() * 600;
chunk->avelocity[2] = random() * 600;
@ -325,6 +314,7 @@ ThrowDebris(edict_t *self, char *modelname, float speed, vec3_t origin)
chunk->classname = "debris";
chunk->takedamage = DAMAGE_YES;
chunk->die = debris_die;
chunk->health = 250;
gi.linkentity(chunk);
}
@ -344,7 +334,7 @@ BecomeExplosion1(edict_t *self)
{
CTFResetFlag(CTF_TEAM2); /* this will free self! */
gi.bprintf(PRINT_HIGH, "The %s flag has returned!\n",
CTFTeamName(CTF_TEAM1));
CTFTeamName(CTF_TEAM2));
return;
}
@ -972,7 +962,7 @@ void
SP_func_explosive(edict_t *self)
{
if (deathmatch->value)
{
{
/* auto-remove for deathmatch */
G_FreeEdict(self);
return;
@ -1147,7 +1137,7 @@ void
SP_misc_explobox(edict_t *self)
{
if (deathmatch->value)
{
{
/* auto-remove for deathmatch */
G_FreeEdict(self);
return;
@ -1438,7 +1428,7 @@ void
SP_misc_deadsoldier(edict_t *ent)
{
if (deathmatch->value)
{
{
/* auto-remove for deathmatch */
G_FreeEdict(ent);
return;
@ -1744,7 +1734,7 @@ void
SP_misc_gib_arm(edict_t *ent)
{
gi.setmodel(ent, "models/objects/gibs/arm/tris.md2");
ent->solid = SOLID_NOT;
ent->solid = SOLID_BBOX;
ent->s.effects |= EF_GIB;
ent->takedamage = DAMAGE_YES;
ent->die = gib_die;
@ -1767,7 +1757,7 @@ void
SP_misc_gib_leg(edict_t *ent)
{
gi.setmodel(ent, "models/objects/gibs/leg/tris.md2");
ent->solid = SOLID_NOT;
ent->solid = SOLID_BBOX;
ent->s.effects |= EF_GIB;
ent->takedamage = DAMAGE_YES;
ent->die = gib_die;
@ -1790,7 +1780,7 @@ void
SP_misc_gib_head(edict_t *ent)
{
gi.setmodel(ent, "models/objects/gibs/head/tris.md2");
ent->solid = SOLID_NOT;
ent->solid = SOLID_BBOX;
ent->s.effects |= EF_GIB;
ent->takedamage = DAMAGE_YES;
ent->die = gib_die;
@ -2136,7 +2126,7 @@ teleporter_touch(edict_t *self, edict_t *other, cplane_t *plane,
/* set angles */
for (i = 0; i < 3; i++)
{
other->client->ps.pmove.delta_angles[i] =
other->client->ps.pmove.delta_angles[i] =
ANGLE2SHORT(dest->s.angles[i] - other->client->resp.cmd_angles[i]);
}

View file

@ -144,7 +144,7 @@ SV_Impact(edict_t *e1, trace_t *trace)
/*
* Slide off of the impacting object
* returns the blocked flags (1 = floor,
* returns the blocked flags (1 = floor,
* 2 = step / wall)
*/
#define STOP_EPSILON 0.1
@ -229,14 +229,14 @@ SV_FlyMove(edict_t *ent, float time, int mask)
trace = gi.trace(ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
if (trace.allsolid)
{
{
/* entity is trapped in another solid */
VectorCopy(vec3_origin, ent->velocity);
return 3;
}
if (trace.fraction > 0)
{
{
/* actually covered some distance */
VectorCopy(trace.endpos, ent->s.origin);
VectorCopy(ent->velocity, original_velocity);
@ -278,7 +278,7 @@ SV_FlyMove(edict_t *ent, float time, int mask)
/* cliped to another plane */
if (numplanes >= MAX_CLIP_PLANES)
{
{
/* this shouldn't really happen */
VectorCopy(vec3_origin, ent->velocity);
return 3;
@ -310,13 +310,13 @@ SV_FlyMove(edict_t *ent, float time, int mask)
}
if (i != numplanes)
{
{
/* go along this plane */
VectorCopy(new_velocity, ent->velocity);
}
else
{
/* go along the crease */
if (numplanes != 2)
{
@ -329,7 +329,7 @@ SV_FlyMove(edict_t *ent, float time, int mask)
VectorScale(dir, d, ent->velocity);
}
/* if original velocity is against the original velocity,
/* if original velocity is against the original velocity,
stop dead to avoid tiny occilations in sloping corners */
if (DotProduct(ent->velocity, primal_velocity) <= 0)
{
@ -497,6 +497,22 @@ retry:
VectorCopy(trace.endpos, ent->s.origin);
gi.linkentity(ent);
/* Push slightly away from non-horizontal surfaces,
prevent origin stuck in the plane which causes
the entity to be rendered in full black. */
if (trace.plane.type != 2)
{
/* Limit the fix to gibs, debris and dead monsters.
Everything else may break existing maps. Items
may slide to unreachable locations, monsters may
get stuck, etc. */
if (((strncmp(ent->classname, "monster_", 8) == 0) && ent->health < 1) ||
(strcmp(ent->classname, "debris") == 0) || (ent->s.effects & EF_GIB))
{
VectorAdd(ent->s.origin, trace.plane.normal, ent->s.origin);
}
}
if (trace.fraction != 1.0)
{
SV_Impact(ent, &trace);
@ -543,7 +559,7 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
vec3_t org, org2, move2, forward, right, up;
vec3_t realmins, realmaxs;
/* clamp the move to 1/8 units, so the position will
/* clamp the move to 1/8 units, so the position will
be accurate for client side prediction */
for (i = 0; i < 3; i++)
{
@ -644,7 +660,7 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
VectorAdd(check->s.origin, move, check->s.origin);
if (check->client)
{
{
check->client->ps.pmove.delta_angles[YAW] += amove[YAW];
}
@ -665,13 +681,13 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
block = SV_TestEntityPosition(check);
if (!block)
{
{
/* pushed ok */
gi.linkentity(check);
continue;
}
/* if it is ok to leave in the old position, do it
/* if it is ok to leave in the old position, do it
this is only relevent for riding entities, not pushed */
VectorSubtract(check->s.origin, move, check->s.origin);
block = SV_TestEntityPosition(check);
@ -686,7 +702,7 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
/* save off the obstacle so we can call the block function */
obstacle = check;
/* move back any entities we already moved
/* move back any entities we already moved
go backwards, so if the same entity was pushed/
twice, it goes back to the original position */
for (p = pushed_p - 1; p >= pushed; p--)
@ -715,7 +731,7 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
}
/*
* Bmodel objects don't interact with each
* Bmodel objects don't interact with each
* other, but push all box objects
*/
void
@ -730,8 +746,8 @@ SV_Physics_Pusher(edict_t *ent)
return;
}
/* make sure all team slaves can move before commiting any moves
or calling any think functions if the move is blocked, all
/* make sure all team slaves can move before commiting any moves
or calling any think functions if the move is blocked, all
moved objects will be backed out */
pushed_p = pushed;
@ -739,7 +755,7 @@ SV_Physics_Pusher(edict_t *ent)
{
if (part->velocity[0] || part->velocity[1] || part->velocity[2] ||
part->avelocity[0] || part->avelocity[1] || part->avelocity[2])
{
{
/* object is moving */
VectorScale(part->velocity, FRAMETIME, move);
VectorScale(part->avelocity, FRAMETIME, amove);
@ -751,9 +767,9 @@ SV_Physics_Pusher(edict_t *ent)
}
}
if (pushed_p > &pushed[MAX_EDICTS])
if (pushed_p > &pushed[MAX_EDICTS-1])
{
gi.error(ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted");
gi.error("pushed_p > &pushed[MAX_EDICTS-1], memory corrupted");
}
if (part)
@ -767,8 +783,8 @@ SV_Physics_Pusher(edict_t *ent)
}
}
/* if the pusher has a "blocked" function, call it
otherwise, just stay in place until the obstacle
/* if the pusher has a "blocked" function, call it
otherwise, just stay in place until the obstacle
is gone */
if (part->blocked)
{
@ -1036,7 +1052,7 @@ SV_Physics_Step(edict_t *ent)
}
/* add gravity except:
flying monsters
flying monsters
swimming monsters who are in the water */
if (!wasonground)
{

View file

@ -28,6 +28,10 @@
#include "header/local.h"
#ifndef BUILD_DATE
#define BUILD_DATE __DATE__
#endif
field_t fields[] = {
{"classname", FOFS(classname), F_LSTRING},
{"origin", FOFS(s.origin), F_VECTOR},
@ -141,7 +145,7 @@ void
InitGame(void)
{
gi.dprintf("Game is starting up.\n");
gi.dprintf("Game is ctf.\n");
gi.dprintf("Game is ctf built on %s.\n", GAMEVERSION, BUILD_DATE);
gun_x = gi.cvar("gun_x", "0", 0);
gun_y = gi.cvar("gun_y", "0", 0);
@ -157,7 +161,7 @@ InitGame(void)
/* latched vars */
sv_cheats = gi.cvar("cheats", "0", CVAR_SERVERINFO | CVAR_LATCH);
gi.cvar("gamename", GAMEVERSION, CVAR_SERVERINFO | CVAR_LATCH);
gi.cvar("gamedate", __DATE__, CVAR_SERVERINFO | CVAR_LATCH);
gi.cvar("gamedate", BUILD_DATE, CVAR_SERVERINFO | CVAR_LATCH);
maxclients = gi.cvar("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
deathmatch = gi.cvar("deathmatch", "0", CVAR_LATCH);
coop = gi.cvar("coop", "0", CVAR_LATCH);
@ -200,6 +204,9 @@ InitGame(void)
/* dm map list */
sv_maplist = gi.cvar("sv_maplist", "", 0);
/* others */
aimfix = gi.cvar("aimfix", "0", CVAR_ARCHIVE);
/* items */
InitItems();
@ -493,7 +500,7 @@ WriteGame(char *filename, qboolean autosave)
}
memset(str, 0, sizeof(str));
strcpy(str, __DATE__);
strcpy(str, BUILD_DATE);
fwrite(str, sizeof(str), 1, f);
game.autosaved = autosave;
@ -526,7 +533,7 @@ ReadGame(char *filename)
fread(str, sizeof(str), 1, f);
if (strcmp(str, __DATE__))
if (strcmp(str, BUILD_DATE))
{
fclose(f);
gi.error("Savegame from an older version.\n");

View file

@ -813,11 +813,11 @@ SP_worldspawn(edict_t *ent)
if (ent->message && ent->message[0])
{
gi.configstring(CS_NAME, ent->message);
strncpy(level.level_name, ent->message, sizeof(level.level_name));
Q_strlcpy(level.level_name, ent->message, sizeof(level.level_name));
}
else
{
strncpy(level.level_name, level.mapname, sizeof(level.level_name));
Q_strlcpy(level.level_name, level.mapname, sizeof(level.level_name));
}
if (st.sky && st.sky[0])

View file

@ -168,11 +168,11 @@ SV_FilterPacket(char *from)
{
if ((in & ipfilters[i].mask) == ipfilters[i].compare)
{
return (int)filterban->value;
return (filterban->value != 0);
}
}
return (int)!filterban->value;
return (filterban->value == 0);
}
void

View file

@ -121,7 +121,7 @@ SP_target_speaker(edict_t *ent)
}
else
{
strncpy(buffer, st.noise, sizeof(buffer));
Q_strlcpy(buffer, st.noise, sizeof(buffer));
}
ent->noise_index = gi.soundindex(buffer);

View file

@ -26,10 +26,10 @@
/*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
*
* THIS FILE IS _VERY_ FRAGILE AND THERE'S NOTHING IN IT THAT CAN OR
* MUST BE CHANGED. IT'S MOST LIKELY A VERY GOOD IDEA TO CLOSE THE
* EDITOR NOW AND NEVER LOOK BACK. OTHERWISE YOU MAY SCREW UP EVERYTHING!
* EDITOR NOW AND NEVER LOOK BACK. OTHERWISE YOU MAY SCREW UP EVERYTHING!
*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
@ -209,7 +209,5 @@ typedef struct
int max_edicts;
} game_export_t;
game_export_t *GetGameApi(game_import_t *import);
#endif /* CTF_GAME_H */

View file

@ -29,7 +29,7 @@
#include "shared.h"
/* define GAME_INCLUDE so that game.h does not define the
/* define GAME_INCLUDE so that game.h does not define the
short, server-visible gclient_t and edict_t structures,
because we define the full size ones in this file */
#define GAME_INCLUDE
@ -110,6 +110,10 @@ typedef enum
AMMO_SLUGS
} ammo_t;
/* Maximum debris / gibs per frame */
#define MAX_GIBS 20
#define MAX_DEBRIS 20
/* deadflag */
#define DEAD_NO 0
#define DEAD_DYING 1
@ -259,8 +263,8 @@ typedef struct gitem_s
char *precaches; /* string of all models, sounds, and images this item will use */
} gitem_t;
/* this structure is left intact through an entire game
it should be initialized at dll load time, and read/written to
/* this structure is left intact through an entire game
it should be initialized at dll load time, and read/written to
the server.ssv file for savegames */
typedef struct
{
@ -271,7 +275,7 @@ typedef struct
gclient_t *clients; /* [maxclients] */
/* can't store spawnpoint in level, because
/* can't store spawnpoint in level, because
it would get overwritten by the savegame restore */
char spawnpoint[512]; /* needed for coop respawns */
@ -288,7 +292,7 @@ typedef struct
qboolean autosaved;
} game_locals_t;
/* this structure is cleared as each map is entered
/* this structure is cleared as each map is entered
it is read/written to the level.sav file for savegames */
typedef struct
{
@ -333,8 +337,8 @@ typedef struct
int power_cubes; /* ugly necessity for coop */
} level_locals_t;
/* spawn_temp_t is only used to hold entity field values that
can be set from the editor, but aren't actualy present
/* spawn_temp_t is only used to hold entity field values that
can be set from the editor, but aren't actualy present
in edict_t during gameplay */
typedef struct
{
@ -446,6 +450,10 @@ extern spawn_temp_t st;
extern int sm_meat_index;
extern int snd_fry;
extern int debristhisframe;
extern int gibsthisframe;
/* means of death */
#define MOD_UNKNOWN 0
#define MOD_BLASTER 1
@ -533,6 +541,8 @@ extern cvar_t *flood_waitdelay;
extern cvar_t *sv_maplist;
extern cvar_t *aimfix;
#define world (&g_edicts[0])
/* item spawnflags */
@ -543,7 +553,7 @@ extern cvar_t *sv_maplist;
#define DROPPED_PLAYER_ITEM 0x00020000
#define ITEM_TARGETS_USED 0x00040000
/* fields are needed for spawning from the entity string
/* fields are needed for spawning from the entity string
and saving / loading games */
#define FFL_SPAWNTEMP 1
@ -752,7 +762,7 @@ void DeathmatchScoreboardMessage(edict_t *client, edict_t *killer);
/* g_pweapon.c */
void PlayerNoise(edict_t *who, vec3_t where, int type);
void P_ProjectSource(gclient_t *client, vec3_t point, vec3_t distance,
void P_ProjectSource(edict_t *ent, vec3_t distance,
vec3_t forward, vec3_t right, vec3_t result);
void Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
int FRAME_IDLE_LAST, int FRAME_DEACTIVATE_LAST, int *pause_frames,
@ -793,7 +803,7 @@ typedef struct
char netname[16];
int hand;
qboolean connected; /* a loadgame will leave valid entities that
qboolean connected; /* a loadgame will leave valid entities that
just don't have a connection yet */
/* values saved and restored from edicts when changing levels */
@ -842,7 +852,7 @@ typedef struct
int helpchanged;
} client_respawn_t;
/* this structure is cleared on each PutClientInServer(),
/* this structure is cleared on each PutClientInServer(),
except for 'client->pers' */
struct gclient_s
{
@ -872,7 +882,7 @@ struct gclient_s
gitem_t *newweapon;
/* sum up damage over an entire frame, so
/* sum up damage over an entire frame, so
shotgun blasts give a single big kick */
int damage_armor; /* damage absorbed by armor */
int damage_parmor; /* damage absorbed by power armor */
@ -941,9 +951,9 @@ struct gclient_s
struct edict_s
{
entity_state_t s;
struct gclient_s *client; /* NULL if not a player
the server expects the first part
of gclient_s to be a player_state_t
struct gclient_s *client; /* NULL if not a player
the server expects the first part
of gclient_s to be a player_state_t
but the rest of it is opaque */
qboolean inuse;
@ -1000,7 +1010,7 @@ struct edict_s
vec3_t avelocity;
int mass;
float air_finished;
float gravity; /* per entity gravity multiplier (1.0 is normal)
float gravity; /* per entity gravity multiplier (1.0 is normal)
use for lowgrav artifact, flares */
edict_t *goalentity;
@ -1029,7 +1039,7 @@ struct edict_s
int max_health;
int gib_health;
int deadflag;
qboolean show_hostile;
int show_hostile;
float powerarmor_time;
@ -1065,7 +1075,7 @@ struct edict_s
float delay; /* before firing targets */
float random;
float teleport_time;
float last_sound_time;
int watertype;
int waterlevel;

View file

@ -36,8 +36,21 @@
#include <stdlib.h>
#include <time.h>
typedef unsigned char byte;
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L // C23 or newer
typedef bool qboolean;
#else
#ifdef true
#undef true
#endif
#ifdef false
#undef false
#endif
typedef enum {false, true} qboolean;
#endif
typedef unsigned char byte;
#ifndef NULL
#define NULL ((void *)0)
@ -202,6 +215,8 @@ void Com_PageInMemory(byte *buffer, int size);
int Q_stricmp(const char *s1, const char *s2);
int Q_strcasecmp(char *s1, char *s2);
int Q_strncasecmp(char *s1, char *s2, int n);
int Q_strlcpy(char *dst, const char *src, int size);
int Q_strlcat(char *dst, const char *src, int size);
/* ============================================= */

View file

@ -527,7 +527,7 @@ SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist)
}
/* try other directions */
if (((rand() & 3) & 1) || (abs(deltay) > abs(deltax)))
if (((rand() & 3) & 1) || (fabsf(deltay) > fabsf(deltax)))
{
tdir = d[1];
d[1] = d[2];

View file

@ -22,7 +22,7 @@
* Interface between client <-> game and client calculations.
*
* =======================================================================
*/
*/
#include "../header/local.h"
#include "../monster/player.h"
@ -76,11 +76,11 @@ SP_info_player_coop(edict_t *self)
/*
* QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32)
* The deathmatch intermission point will be at one of these
* Use 'angles' instead of 'angle', so you can set pitch or
* Use 'angles' instead of 'angle', so you can set pitch or
* roll as well as yaw. 'pitch yaw roll'
*/
void
SP_info_player_intermission(void)
SP_info_player_intermission(edict_t *ent)
{
}
@ -89,7 +89,7 @@ SP_info_player_intermission(void)
void
player_pain(edict_t *self, edict_t *other, float kick, int damage)
{
/* player pain is handled at the
/* player pain is handled at the
end of the frame in P_DamageFeedback */
}
@ -521,7 +521,7 @@ player_die(edict_t *self, edict_t *inflictor, edict_t *attacker,
memset(self->client->pers.inventory, 0, sizeof(self->client->pers.inventory));
if (self->health < -40)
{
{
/* gib */
gi.sound(self, CHAN_BODY, gi.soundindex(
"misc/udeath.wav"), 1, ATTN_NORM, 0);
@ -586,7 +586,7 @@ player_die(edict_t *self, edict_t *inflictor, edict_t *attacker,
/* ======================================================================= */
/*
* This is only called when the game
* This is only called when the game
* first initializes in single player,
* but is called after each death and
* level change in deathmatch
@ -731,7 +731,7 @@ PlayersRangeFromSpot(edict_t *spot)
}
/*
* go to a random point, but NOT the two
* go to a random point, but NOT the two
* points closest to other players
*/
edict_t *
@ -824,7 +824,7 @@ SelectFarthestDeathmatchSpawnPoint(void)
return bestspot;
}
/* if there is a player just spawned on
/* if there is a player just spawned on
each and every start spot we have no
choice to turn one into a telefrag meltdown */
spot = G_Find(NULL, FOFS(classname), "info_player_deathmatch");
@ -880,7 +880,7 @@ SelectCoopSpawnPoint(edict_t *ent)
}
if (Q_stricmp(game.spawnpoint, target) == 0)
{
{
/* this is a coop spawn point for one of the clients here */
index--;
@ -942,7 +942,7 @@ SelectSpawnPoint(edict_t *ent, vec3_t origin, vec3_t angles)
if (!spot)
{
if (!game.spawnpoint[0])
{
{
/* there wasn't a spawnpoint without a target, so use any */
spot = G_Find(spot, FOFS(classname), "info_player_start");
}
@ -1062,7 +1062,7 @@ respawn(edict_t *self)
/* ============================================================== */
/*
* Called when a player connects
* Called when a player connects
* to a server or respawns in
* a deathmatch.
*/
@ -1225,7 +1225,7 @@ PutClientInServer(edict_t *ent)
}
if (!KillBox(ent))
{
{
/* could't spawn in? */
}
@ -1237,7 +1237,7 @@ PutClientInServer(edict_t *ent)
}
/*
* A client has just connected to
* A client has just connected to
* the server in deathmatch mode,
* so clear everything out before
* starting them.
@ -1288,13 +1288,13 @@ ClientBegin(edict_t *ent)
return;
}
/* if there is already a body waiting for
/* if there is already a body waiting for
us (a loadgame), just take it, otherwise
spawn one from scratch */
if (ent->inuse == true)
{
/* the client has cleared the client side viewangles upon
connecting to the server, which is different than the
/* the client has cleared the client side viewangles upon
connecting to the server, which is different than the
state when the game is saved, so we need to compensate
with deltaangles */
for (i = 0; i < 3; i++)
@ -1305,7 +1305,7 @@ ClientBegin(edict_t *ent)
}
else
{
/* a spawn point will completely reinitialize the entity
/* a spawn point will completely reinitialize the entity
except for the persistant data that was initialized at
ClientConnect() time */
G_InitEdict(ent);
@ -1513,9 +1513,9 @@ ClientDisconnect(edict_t *ent)
edict_t *pm_passent;
/*
/*
* pmove doesn't need to know about
* passent and contentmask
* passent and contentmask
*/
trace_t
PM_trace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
@ -1620,7 +1620,10 @@ ClientThink(edict_t *ent, usercmd_t *ucmd)
for (i = 0; i < 3; i++)
{
pm.s.origin[i] = ent->s.origin[i] * 8;
pm.s.velocity[i] = ent->velocity[i] * 8;
/* save to an int first, in case the short overflows
* so we get defined behavior (at least with -fwrapv) */
int tmpVel = ent->velocity[i] * 8;
pm.s.velocity[i] = tmpVel;
}
if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s)))
@ -1724,7 +1727,7 @@ ClientThink(edict_t *ent, usercmd_t *ucmd)
client->buttons = ucmd->buttons;
client->latched_buttons |= client->buttons & ~client->oldbuttons;
/* save light level the player is
/* save light level the player is
standing on for monster sighting AI */
ent->light_level = ucmd->lightlevel;

View file

@ -33,10 +33,12 @@ static byte is_silenced;
void weapon_grenade_fire(edict_t *ent, qboolean held);
void
P_ProjectSource(gclient_t *client, vec3_t point, vec3_t distance,
P_ProjectSource(edict_t *ent, vec3_t distance,
vec3_t forward, vec3_t right, vec3_t result)
{
vec3_t _distance;
gclient_t *client = ent->client;
float *point = ent->s.origin;
vec3_t _distance;
VectorCopy(distance, _distance);
@ -50,6 +52,21 @@ P_ProjectSource(gclient_t *client, vec3_t point, vec3_t distance,
}
G_ProjectSource(point, _distance, forward, right, result);
// Berserker: fix - now the projectile hits exactly where the scope is pointing.
if (aimfix->value)
{
vec3_t start, end;
VectorSet(start, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] + ent->viewheight);
VectorMA(start, 8192, forward, end);
trace_t tr = gi.trace(start, NULL, NULL, end, ent, MASK_SHOT);
if (tr.fraction < 1)
{
VectorSubtract(tr.endpos, result, forward);
VectorNormalize(forward);
}
}
}
/*
@ -119,7 +136,7 @@ PlayerNoise(edict_t *who, vec3_t where, int type)
VectorCopy(where, noise->s.origin);
VectorSubtract(where, noise->maxs, noise->absmin);
VectorAdd(where, noise->maxs, noise->absmax);
noise->teleport_time = level.time;
noise->last_sound_time = level.time;
gi.linkentity(noise);
}
@ -659,7 +676,7 @@ weapon_grenade_fire(edict_t *ent, qboolean held)
VectorSet(offset, 8, 8, ent->viewheight - 8);
AngleVectors(ent->client->v_angle, forward, right, NULL);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
timer = ent->client->grenade_time - level.time;
speed = GRENADE_MINSPEED + (GRENADE_TIMER -
@ -848,7 +865,7 @@ weapon_grenadelauncher_fire(edict_t *ent)
VectorSet(offset, 8, 8, ent->viewheight - 8);
AngleVectors(ent->client->v_angle, forward, right, NULL);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
VectorScale(forward, -2, ent->client->kick_origin);
ent->client->kick_angles[0] = -1;
@ -913,7 +930,7 @@ Weapon_RocketLauncher_Fire(edict_t *ent)
ent->client->kick_angles[0] = -1;
VectorSet(offset, 8, 8, ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
fire_rocket(ent, start, forward, damage, 650, damage_radius, radius_damage);
/* send muzzle flash */
@ -966,7 +983,7 @@ Blaster_Fire(edict_t *ent, vec3_t g_offset, int damage,
AngleVectors(ent->client->v_angle, forward, right, NULL);
VectorSet(offset, 24, 8, ent->viewheight - 8);
VectorAdd(offset, g_offset, offset);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
VectorScale(forward, -2, ent->client->kick_origin);
ent->client->kick_angles[0] = -1;
@ -1200,7 +1217,7 @@ Machinegun_Fire(edict_t *ent)
VectorAdd(ent->client->v_angle, ent->client->kick_angles, angles);
AngleVectors(angles, forward, right, NULL);
VectorSet(offset, 0, 8, ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
fire_bullet(ent, start, forward, damage, kick,
DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD,
MOD_MACHINEGUN);
@ -1367,8 +1384,7 @@ Chaingun_Fire(edict_t *ent)
r = 7 + crandom() * 4;
u = crandom() * 4;
VectorSet(offset, 0, r, u + ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset,
forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
fire_bullet(ent, start, forward, damage, kick,
DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD,
@ -1427,7 +1443,7 @@ weapon_shotgun_fire(edict_t *ent)
ent->client->kick_angles[0] = -2;
VectorSet(offset, 0, 8, ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
if (is_quad)
{
@ -1487,7 +1503,7 @@ weapon_supershotgun_fire(edict_t *ent)
ent->client->kick_angles[0] = -2;
VectorSet(offset, 0, 8, ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
if (is_quad)
{
@ -1499,10 +1515,35 @@ weapon_supershotgun_fire(edict_t *ent)
v[YAW] = ent->client->v_angle[YAW] - 5;
v[ROLL] = ent->client->v_angle[ROLL];
AngleVectors(v, forward, NULL, NULL);
if (aimfix->value)
{
AngleVectors(v, forward, right, NULL);
VectorScale(forward, -2, ent->client->kick_origin);
ent->client->kick_angles[0] = -2;
VectorSet(offset, 0, 8, ent->viewheight - 8);
P_ProjectSource(ent, offset, forward, right, start);
}
fire_shotgun(ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD,
DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT / 2, MOD_SSHOTGUN);
v[YAW] = ent->client->v_angle[YAW] + 5;
AngleVectors(v, forward, NULL, NULL);
if (aimfix->value)
{
AngleVectors(v, forward, right, NULL);
VectorScale(forward, -2, ent->client->kick_origin);
ent->client->kick_angles[0] = -2;
VectorSet(offset, 0, 8, ent->viewheight - 8);
P_ProjectSource(ent, offset, forward, right, start);
}
fire_shotgun(ent, start, forward, damage, kick,
DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD,
DEFAULT_SSHOTGUN_COUNT / 2, MOD_SSHOTGUN);
@ -1573,7 +1614,7 @@ weapon_railgun_fire(edict_t *ent)
ent->client->kick_angles[0] = -3;
VectorSet(offset, 0, 7, ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
fire_rail(ent, start, forward, damage, kick);
/* send muzzle flash */
@ -1663,7 +1704,7 @@ weapon_bfg_fire(edict_t *ent)
ent->client->v_dmg_time = level.time + DAMAGE_TIME;
VectorSet(offset, 8, 8, ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
fire_bfg(ent, start, forward, damage, 400, damage_radius);
ent->client->ps.gunframe++;

View file

@ -319,11 +319,8 @@ anglemod(float a)
return a;
}
int i;
vec3_t corners[2];
/*
* This is the slow, general version
/*
* This is the slow, general version
*/
int
BoxOnPlaneSide2(vec3_t emins, vec3_t emaxs, struct cplane_s *p)
@ -441,7 +438,7 @@ BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, struct cplane_s *p)
p->normal[2] * emaxs[2];
break;
default:
dist1 = dist2 = 0;
dist1 = dist2 = 0;
break;
}
@ -666,31 +663,17 @@ COM_StripExtension(char *in, char *out)
*out = 0;
}
char *
COM_FileExtension(char *in)
const char *
COM_FileExtension(const char *in)
{
static char exten[8];
int i;
const char *ext = strrchr(in, '.');
while (*in && *in != '.')
{
in++;
}
if (!*in)
if (!ext || ext == in)
{
return "";
}
in++;
for (i = 0; i < 7 && *in; i++, in++)
{
exten[i] = *in;
}
exten[i] = 0;
return exten;
return ext + 1;
}
void
@ -774,7 +757,7 @@ COM_DefaultExtension(char *path, const char *extension)
qboolean bigendien;
/* can't just use function pointers, or dll linkage can
/* can't just use function pointers, or dll linkage can
mess up when qcommon is included in multiple places */
short (*_BigShort)(short l);
short (*_LittleShort)(short l);
@ -786,37 +769,37 @@ float (*_LittleFloat)(float l);
short
BigShort(short l)
{
return _BigShort(l);
return _BigShort(l);
}
short
LittleShort(short l)
{return
_LittleShort(l);
{return
_LittleShort(l);
}
int
BigLong(int l)
{
return _BigLong(l);
return _BigLong(l);
}
int
LittleLong(int l)
{
return _LittleLong(l);
return _LittleLong(l);
}
float
BigFloat(float l)
{
return _BigFloat(l);
return _BigFloat(l);
}
float
LittleFloat(float l)
{
return _LittleFloat(l);
return _LittleFloat(l);
}
short
@ -907,7 +890,7 @@ Swap_Init(void)
}
/*
* does a varargs printf into a temp buffer, so I don't
* does a varargs printf into a temp buffer, so I don't
* need to have varargs versions of all text functions.
*/
char *
@ -1089,6 +1072,43 @@ Q_strcasecmp(char *s1, char *s2)
return Q_strncasecmp(s1, s2, 99999);
}
int
Q_strlcpy(char *dst, const char *src, int size)
{
const char *s = src;
while (*s)
{
if (size > 1)
{
*dst++ = *s;
size--;
}
s++;
}
if (size > 0)
{
*dst = '\0';
}
return s - src;
}
int
Q_strlcat(char *dst, const char *src, int size)
{
char *d = dst;
while (size > 0 && *d)
{
size--;
d++;
}
return (d - dst) + Q_strlcpy(d, src, size);
}
void
Com_sprintf(char *dest, int size, char *fmt, ...)
{
@ -1127,7 +1147,7 @@ char *
Info_ValueForKey(char *s, char *key)
{
char pkey[512];
static char value[2][512]; /* use two buffers so compares
static char value[2][512]; /* use two buffers so compares
work without stomping on each other */
static int valueindex;
char *o;
@ -1237,7 +1257,7 @@ Info_RemoveKey(char *s, char *key)
if (!strcmp(key, pkey))
{
strcpy(start, s); /* remove this part */
memmove(start, s, strlen(s) + 1); /* remove this part */
return;
}

Binary file not shown.