mirror of
https://github.com/DrBeef/JKXR.git
synced 2025-05-01 05:51:50 +00:00
commit0c85ac4704
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sat Apr 15 18:47:10 2023 +0200 Menu updates commit35b89acc87
Author: Simon <simonbrown77@googlemail.com> Date: Sat Apr 15 12:32:35 2023 +0100 Support for changeable fresh rate commit539bfa8956
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sat Apr 15 00:02:59 2023 +0200 Ensure proper menu defaults on the very first start commit216a225aa6
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Fri Apr 14 22:41:24 2023 +0200 Fix storing of force crosshair option commit48c2486aad
Merge:a72ca45
fcb9169
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Fri Apr 14 22:23:24 2023 +0200 Merge remote-tracking branch 'origin/main' into contributions commita72ca459c5
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Fri Apr 14 22:19:47 2023 +0200 Intern all default values; Remove no longer needed configuration files commit32c4e6eac1
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Fri Apr 14 20:59:41 2023 +0200 Ensure weapon adjustment is applied when resetting to defaults commitfcb9169955
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Fri Apr 14 18:58:32 2023 +0200 Increased default force motion trigger commit2433ae4110
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Fri Apr 14 18:55:56 2023 +0200 Change Force Crosshair commit4ab6a6024a
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Fri Apr 14 17:01:16 2023 +0200 Fixed player knockback.... hopefully commit7deeee7a6f
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Fri Apr 14 17:01:00 2023 +0200 Increased Force Power Visibility commit1fdcb7c48f
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Fri Apr 14 15:16:34 2023 +0200 Changed Brightness Range and Default commitfada09a0bb
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Thu Apr 13 20:38:13 2023 +0200 Fix remote turret on-screen help commit82af313786
Merge:7680cb1
d13176c
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Thu Apr 13 18:59:46 2023 +0200 Merge branch 'main' into contributions commitd13176c9ba
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Thu Apr 13 13:29:49 2023 +0200 New Quick Save / Load Video commit7680cb1288
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Wed Apr 12 22:26:44 2023 +0200 Fix use action when controlling droid; fix droid view help commit4d90595139
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Wed Apr 12 18:21:10 2023 +0200 Fencing Speed on Pico default commit37d5ac4184
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Wed Apr 12 18:12:07 2023 +0200 Changes to TBDC Different menu text + added vanilla mode commitd6e40ead64
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Wed Apr 12 17:44:29 2023 +0200 Set Fencing Speed back to Default (by Default) commit3f7d116e25
Merge:7424628
c7c66e4
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Wed Apr 12 14:50:26 2023 +0200 Merge branch 'main' of https://github.com/DrBeef/JKXR commit7424628a5d
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Wed Apr 12 14:50:23 2023 +0200 Updated Weapons + Shader fix for FX mod commitc7c66e46a7
Author: Simon <simonbrown77@googlemail.com> Date: Wed Apr 12 08:37:36 2023 +0100 Revert "Arrange quick save icons horizontally" This reverts commit20f8fff3fe
. Also make the icons white commitfa54045159
Author: Simon <simonbrown77@googlemail.com> Date: Tue Apr 11 21:02:29 2023 +0100 Update .gitignore commit20f8fff3fe
Author: Simon <simonbrown77@googlemail.com> Date: Tue Apr 11 21:00:09 2023 +0100 Arrange quick save icons horizontally commitd3dcac8f9d
Author: Simon <simonbrown77@googlemail.com> Date: Tue Apr 11 20:58:56 2023 +0100 Save game crash fix in JKO commit6314561b52
Author: Simon <simonbrown77@googlemail.com> Date: Tue Apr 11 08:49:42 2023 +0100 Switch selector on offhand using offhand thumbstick commit3b2ffd7289
Author: Simon <simonbrown77@googlemail.com> Date: Tue Apr 11 08:39:32 2023 +0100 Attempted fix for save game crash - Not really a proper fix, but might at least workaround it commitc135eefa05
Author: Simon <simonbrown77@googlemail.com> Date: Tue Apr 11 08:38:54 2023 +0100 Fixed save/load icon image size commitf51270a294
Merge:a2ff16b
e243d0b
Author: Simon <simonbrown77@googlemail.com> Date: Mon Apr 10 19:42:11 2023 +0100 Merge branch 'main' of https://github.com/DrBeef/JKXR commita2ff16b576
Author: Simon <simonbrown77@googlemail.com> Date: Mon Apr 10 19:42:06 2023 +0100 Quick Save/Load in Selector Haven't been able to test yet! commite243d0bdfa
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Mon Apr 10 18:29:18 2023 +0200 Update README.md commitb9d0314a6a
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sun Apr 9 19:38:32 2023 +0200 Make getting into AT-ST easier commitd121206f83
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sat Apr 8 22:49:28 2023 +0200 Tune touch gesture distance; Improve use interaction in 3rd person. commit260d501776
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sat Apr 8 22:34:59 2023 +0200 Fix and improve weapon adjustment helper axes commita6318867bb
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Thu Apr 6 20:35:02 2023 +0200 Update README.md commit4a1d90e729
Merge:425db0f
821a56d
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Thu Apr 6 19:12:07 2023 +0200 Merge branch 'main' into contributions commit821a56d4b9
Author: Simon Brown <simonbrown77@googlemail.com> Date: Thu Apr 6 17:24:20 2023 +0100 Update README.md commit67b7d26de8
Merge:b407932
ccd63d4
Author: Simon Brown <simonbrown77@googlemail.com> Date: Thu Apr 6 16:54:01 2023 +0100 Merge pull request #4 from DrBeef/TBDC TBDC Scales in Code commitb407932bb2
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Thu Apr 6 17:43:26 2023 +0200 Update README.md commit174c3ce96c
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Thu Apr 6 17:33:33 2023 +0200 Update README.md commite9af8e87c2
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Thu Apr 6 17:23:36 2023 +0200 Update README.md commitccd63d4eec
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Thu Apr 6 16:57:36 2023 +0200 Forced for Extended Menu commitd6b3e8eb65
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Thu Apr 6 16:55:02 2023 +0200 TBDC Scales in Code commita5f3adf725
Author: Simon Brown <simonbrown77@googlemail.com> Date: Thu Apr 6 15:04:07 2023 +0100 Update README.md commit316c2a2904
Merge:387c34b
90b694f
Author: Simon Brown <simonbrown77@googlemail.com> Date: Thu Apr 6 10:02:01 2023 +0100 Merge pull request #2 from DrBeef/TBDC Team Beef Directors Cut commit387c34b53e
Author: Simon <simonbrown77@googlemail.com> Date: Thu Apr 6 09:59:18 2023 +0100 Update Beef Crawl commita271b61ac7
Author: Simon <simonbrown77@googlemail.com> Date: Thu Apr 6 09:58:18 2023 +0100 Switch to use Bummser's NPC file if TBDC is disabled commita2f1644d72
Author: Simon <simonbrown77@googlemail.com> Date: Thu Apr 6 08:39:02 2023 +0100 Update version to 1.0.0 for release commitf785fdc393
Author: Simon <simonbrown77@googlemail.com> Date: Thu Apr 6 08:00:11 2023 +0100 update github banner Update README.md Update README.md Update README.md Update README.md Update README.md Added Team Beef Patreon banner commit90b694ff60
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Wed Apr 5 22:21:41 2023 +0200 Last Cleanup commit70468332d6
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Wed Apr 5 22:19:45 2023 +0200 TBDC Cleanup commit6660e8c984
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Wed Apr 5 21:58:00 2023 +0200 Credits / NPC Scale commite1b03fdcc6
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Wed Apr 5 21:57:07 2023 +0200 Fixing Quick Save commit95950f2390
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Wed Apr 5 20:08:10 2023 +0200 Updated ratios per difficulty commitd6235ef199
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Wed Apr 5 00:30:35 2023 +0200 Darkened Menu GFX commita3fdb460c4
Author: Simon <simonbrown77@googlemail.com> Date: Tue Apr 4 23:03:31 2023 +0100 Prevent crash when throwing Saber seems it is indexing the g2 model surface that doesn't exist, might be something to do with the new hilt and the old hilt being in the save. Not sure, but this stops it crashing. commit4c751fcb59
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Tue Apr 4 23:59:12 2023 +0200 Y Close Datapad commita1216665c8
Merge:1939a26
d841464
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Tue Apr 4 23:48:20 2023 +0200 Merge pull request #1 from DrBeef/main Main -> TDBC commit1939a26542
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Tue Apr 4 23:37:41 2023 +0200 TBDC Laser Saber deflections Guns balancing. commitd841464924
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Tue Apr 4 21:59:31 2023 +0200 Update help resources and menu commit425db0f108
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Tue Apr 4 21:59:31 2023 +0200 Update help resources and menu commit3c895d27de
Merge:fe9e12a
c3819fa
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Tue Apr 4 21:05:48 2023 +0200 Merge branch 'main' into contributions commitc3819fa407
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Mon Apr 3 00:36:57 2023 +0200 Demo folder assets fix commitfe9e12a3f9
Merge:d79f57b
2b255ac
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Mon Apr 3 22:55:29 2023 +0200 Merge branch 'main' into contributions commit2b255ac3ea
Author: Simon <simonbrown77@googlemail.com> Date: Mon Apr 3 21:26:39 2023 +0100 Improved version string commit62284414d0
Author: Simon <simonbrown77@googlemail.com> Date: Mon Apr 3 21:26:20 2023 +0100 Ensure intro vid can be skipped without having to press trigger first commit65674abe2a
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Mon Apr 3 21:36:35 2023 +0200 Fix Controller Location Buzz for Quick Save / Load commitba2e726a79
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Mon Apr 3 00:36:57 2023 +0200 Demo folder assets fix commit7175c872a9
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Mon Apr 3 00:36:46 2023 +0200 Knockback settings TBDC commitcc7e73d04a
Author: Simon <simonbrown77@googlemail.com> Date: Sun Apr 2 22:59:47 2023 +0100 Update beef_crawl.tga commitdd71a05e36
Author: Simon <simonbrown77@googlemail.com> Date: Sun Apr 2 22:51:49 2023 +0100 Put version at the bottom of the main menu commitcb52d310c1
Author: Grant Bagwell <general@grantbagwell.co.uk> Date: Sun Apr 2 23:18:28 2023 +0200 TBDC Weapons commitac71f24e78
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sun Apr 2 18:43:10 2023 +0200 Updated control scheme picture commit3f5c767e8d
Author: Simon <simonbrown77@googlemail.com> Date: Sun Apr 2 19:42:42 2023 +0100 Update AndroidManifest.xml commit64ab392fc5
Author: Simon <simonbrown77@googlemail.com> Date: Sun Apr 2 19:42:39 2023 +0100 JKA: Some CVAR change to increase performance commitd43de53e8a
Author: Simon <simonbrown77@googlemail.com> Date: Sun Apr 2 19:41:50 2023 +0100 Added missed saber blocking check might explain why some people find JKA a bit easy if it is auto-blocking in 1st person commit8b23e255d8
Author: Simon <simonbrown77@googlemail.com> Date: Sun Apr 2 19:41:16 2023 +0100 Update open xr headers commitd79f57ba2d
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sun Apr 2 18:43:10 2023 +0200 Updated control scheme picture commite3524e8e48
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sat Apr 1 18:48:42 2023 +0200 Add use haptic feedback; Fix use in 3rd person mode commit05fc4d5ab4
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sat Apr 1 12:07:13 2023 +0200 Fix menu haptics commiteec46c183d
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sat Apr 1 18:48:42 2023 +0200 Add use haptic feedback; Fix use in 3rd person mode commitfe9891f8db
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sat Apr 1 12:07:13 2023 +0200 Fix menu haptics commit21483d0d5a
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sat Apr 1 11:25:11 2023 +0200 Make weapon adjustment mode independent for each weapon; Optimize loading of weapon adjustments commitbaec8832ab
Merge:82706df
52fcc8a
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Sat Apr 1 11:15:25 2023 +0200 Merge branch 'main' into contributions commit52fcc8a49e
Author: Simon <simonbrown77@googlemail.com> Date: Sat Apr 1 09:47:48 2023 +0100 Revert "Removed the no-backface-culling for weapons as it is no longer needed" This reverts commitb899b99178
. commit5e66ebf6fc
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Fri Mar 31 15:40:54 2023 +0200 Allow to skip cinematics also by triggers commit587277fa7f
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Fri Mar 31 14:52:40 2023 +0200 Fix use/crouch buttons on switched control schemes commit82706df34f
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Fri Mar 31 15:40:54 2023 +0200 Allow to skip cinematics also by triggers commit1111766032
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Fri Mar 31 14:52:40 2023 +0200 Fix use/crouch buttons on switched control schemes commit822d1ddbba
Merge:a1a7d54
5f56cf4
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Fri Mar 31 08:43:50 2023 +0200 Merge branch 'main' into contributions commit5f56cf48fc
Author: Simon <simonbrown77@googlemail.com> Date: Thu Mar 30 22:16:37 2023 +0100 Camera shake fix part 2 commit3dd7833cd0
Author: Simon <simonbrown77@googlemail.com> Date: Thu Mar 30 22:06:18 2023 +0100 Disable camera shake when charging a weapon's alt fire commit6202017b6a
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Thu Mar 30 21:52:44 2023 +0200 Fix virtual gun stock commit6d49f87150
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Thu Mar 30 19:26:36 2023 +0200 Do not check angle on non-facing triggers commit926c64c691
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Thu Mar 30 17:54:33 2023 +0200 Add angle check for triggers touched by hand commit78f7d9bcfc
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Wed Mar 29 22:59:27 2023 +0200 JKA mod menu warning commit4219f996e9
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Wed Mar 29 22:42:11 2023 +0200 JKO mod menu warning commitb899b99178
Author: Simon <simonbrown77@googlemail.com> Date: Thu Mar 30 21:45:10 2023 +0100 Removed the no-backface-culling for weapons as it is no longer needed used only for hand models now commit9877859676
Author: Simon <simonbrown77@googlemail.com> Date: Thu Mar 30 21:44:36 2023 +0100 Update to the VC+Elin weapons pack includes a sweet new saber hilt commita1a7d541fa
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Thu Mar 30 21:52:44 2023 +0200 Fix virtual gun stock commit15d932c75f
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Thu Mar 30 19:26:36 2023 +0200 Do not check angle on non-facing triggers commit402277e717
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Thu Mar 30 17:54:33 2023 +0200 Add angle check for triggers touched by hand commit9b22378c88
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Thu Mar 30 17:52:26 2023 +0200 Add special delay for re-triggering security cameras commitc4cc218f8b
Author: Simon <simonbrown77@googlemail.com> Date: Wed Mar 29 22:44:50 2023 +0100 Turn the stun baton into an "always active" weapon movement still triggers the sound, but it will always shock an enemy when it makes contact commita4e99c20f9
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Wed Mar 29 22:59:27 2023 +0200 JKA mod menu warning commit442a1fc8e2
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Wed Mar 29 22:42:11 2023 +0200 JKO mod menu warning commit02261c57f0
Merge:3c64fa7
51c703a
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Wed Mar 29 20:51:42 2023 +0200 Merge branch 'contributions' of github.com:DrBeef/JKXR into contributions commit3c64fa7e3e
Author: Simon <simonbrown77@googlemail.com> Date: Tue Mar 28 23:19:29 2023 +0100 Lowered Stun Baton trigger velocity commit43192a355d
Author: Simon <simonbrown77@googlemail.com> Date: Tue Mar 28 23:03:17 2023 +0100 Move beef_crawl back into the game specific assets as we will be fixing the JKO one on release, but updating JKA commit94e82c2da3
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Tue Mar 28 23:21:28 2023 +0200 Fix subtitles rendering; Fix rendering of other centered texts commit40128567be
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Tue Mar 28 18:02:08 2023 +0200 Add help to menu commit4f1b6b5f07
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Tue Mar 28 17:36:13 2023 +0200 Split vr asset packs to avoid duplicates commit51c703a481
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Tue Mar 28 23:21:28 2023 +0200 Fix subtitles rendering; Fix rendering of other centered texts commit04a539f890
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Tue Mar 28 18:02:08 2023 +0200 Add help to menu commitd9126738d3
Author: Petr Bartos <petr.bartos@plus4u.net> Date: Tue Mar 28 17:36:13 2023 +0200 Split vr asset packs to avoid duplicates commit62b9a0bfab
Author: Simon <simonbrown77@googlemail.com> Date: Tue Mar 28 13:52:45 2023 +0100 Hide force power aura when item selector is shown commit0a9206642e
Author: Simon <simonbrown77@googlemail.com> Date: Tue Mar 28 13:52:23 2023 +0100 Slight adjustment to muzzle position based on whether scoped/two-handed commitf452b9cf06
Author: Simon <simonbrown77@googlemail.com> Date: Tue Mar 28 13:51:49 2023 +0100 Slight tweak to NPC Combat commit20de6ec478
Author: Simon <simonbrown77@googlemail.com> Date: Tue Mar 28 13:50:54 2023 +0100 Added simple readme and license commit77672f612b
Author: Simon <simonbrown77@googlemail.com> Date: Tue Mar 28 07:20:22 2023 +0100 Updated website link to be the patreon commit2a1cd0e6e7
Author: Simon <simonbrown77@googlemail.com> Date: Tue Mar 28 07:20:10 2023 +0100 Don't send roll to the server, this might be causing gradual roll drift commit1b22652e5c
Author: Simon <simonbrown77@googlemail.com> Date: Mon Mar 27 21:38:46 2023 +0100 Fixed aiming of bowcaster and demp alt fire commit895b09041f
Author: Simon <simonbrown77@googlemail.com> Date: Mon Mar 27 21:38:25 2023 +0100 JKA - Ensure UseVR Position is only true when in first person commit3897531544
Author: Simon <simonbrown77@googlemail.com> Date: Mon Mar 27 21:38:17 2023 +0100 JKO - Ensure UseVR Position is only true when in first person commit3b5121e349
Author: Simon <simonbrown77@googlemail.com> Date: Mon Mar 27 21:37:49 2023 +0100 Render Special Effects on hand/weapon when force power is activated for protection etc commit50db9039df
Author: Simon <simonbrown77@googlemail.com> Date: Sun Mar 26 16:33:52 2023 +0100 Separate no copy file flag for JK3 commit1968a7d8ba
Author: Simon <simonbrown77@googlemail.com> Date: Sun Mar 26 16:33:22 2023 +0100 Always use right hand as saber home commit74dcd955d2
Author: Simon <simonbrown77@googlemail.com> Date: Sun Mar 26 16:32:49 2023 +0100 Fix crash in JKA commit1e4692d04a
Author: Simon <simonbrown77@googlemail.com> Date: Sun Mar 26 16:32:16 2023 +0100 Update z_Crusty_and_Elin_vr_weapons.pk3 commit134dec8264
Author: Simon <simonbrown77@googlemail.com> Date: Sun Mar 26 16:31:53 2023 +0100 Fix possible crash on JK2 commitf6dc432f6a
Author: Simon <simonbrown77@googlemail.com> Date: Sat Mar 25 15:36:01 2023 +0000 Copy mods to jk2demo if it exists to resolve the issue with mods not being picked up from the base folder
3638 lines
96 KiB
C++
3638 lines
96 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 1999 - 2005, Id Software, Inc.
|
|
Copyright (C) 2000 - 2013, Raven Software, Inc.
|
|
Copyright (C) 2001 - 2013, Activision, Inc.
|
|
Copyright (C) 2013 - 2015, OpenJK contributors
|
|
|
|
This file is part of the OpenJK source code.
|
|
|
|
OpenJK is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License version 2 as
|
|
published by the Free Software Foundation.
|
|
|
|
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, see <http://www.gnu.org/licenses/>.
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "cg_local.h"
|
|
#include "cg_media.h"
|
|
#include "FxScheduler.h"
|
|
#include "../game/wp_saber.h"
|
|
#include "../game/g_local.h"
|
|
#include "../game/anims.h"
|
|
#include <bg_local.h>
|
|
#include <JKXR/VrClientInfo.h>
|
|
|
|
extern void CG_LightningBolt( centity_t *cent, vec3_t origin );
|
|
|
|
#define PHASER_HOLDFRAME 2
|
|
int cgi_UI_GetMenuInfo(char *menuFile,int *x,int *y);
|
|
extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath );
|
|
const char *CG_DisplayBoxedText(int iBoxX, int iBoxY, int iBoxWidth, int iBoxHeight,
|
|
const char *psText, int iFontHandle, float fScale,
|
|
const vec4_t v4Color);
|
|
|
|
/*
|
|
=================
|
|
CG_RegisterWeapon
|
|
|
|
The server says this item is used on this level
|
|
=================
|
|
*/
|
|
void CG_RegisterWeapon( int weaponNum ) {
|
|
weaponInfo_t *weaponInfo;
|
|
gitem_t *item, *ammo;
|
|
char path[MAX_QPATH];
|
|
vec3_t mins, maxs;
|
|
int i;
|
|
|
|
weaponInfo = &cg_weapons[weaponNum];
|
|
|
|
// error checking
|
|
if ( weaponNum == 0 ) {
|
|
return;
|
|
}
|
|
|
|
if ( weaponNum >= WP_NUM_WEAPONS ) {
|
|
return;
|
|
}
|
|
|
|
if ( weaponInfo->registered ) {
|
|
return;
|
|
}
|
|
|
|
// clear out the memory we use
|
|
memset( weaponInfo, 0, sizeof( *weaponInfo ) );
|
|
weaponInfo->registered = qtrue;
|
|
|
|
// find the weapon in the item list
|
|
for ( item = bg_itemlist + 1 ; item->classname ; item++ ) {
|
|
if ( item->giType == IT_WEAPON && item->giTag == weaponNum ) {
|
|
weaponInfo->item = item;
|
|
break;
|
|
}
|
|
}
|
|
// if we couldn't find which weapon this is, give us an error
|
|
if ( !item->classname ) {
|
|
CG_Error( "Couldn't find item for weapon %s\nNeed to update Items.dat!", weaponData[weaponNum].classname);
|
|
}
|
|
CG_RegisterItemVisuals( item - bg_itemlist );
|
|
|
|
// set up in view weapon model
|
|
weaponInfo->weaponModel = cgi_R_RegisterModel( weaponData[weaponNum].weaponMdl );
|
|
{//in case the weaponmodel isn't _w, precache the _w.glm
|
|
char weaponModel[64];
|
|
|
|
Q_strncpyz (weaponModel, weaponData[weaponNum].weaponMdl, sizeof(weaponModel));
|
|
if (char *spot = strstr(weaponModel, ".md3") )
|
|
{
|
|
*spot = 0;
|
|
spot = strstr(weaponModel, "_w");//i'm using the in view weapon array instead of scanning the item list, so put the _w back on
|
|
if (!spot)
|
|
{
|
|
Q_strcat (weaponModel, sizeof(weaponModel), "_w");
|
|
}
|
|
Q_strcat (weaponModel, sizeof(weaponModel), ".glm"); //and change to ghoul2
|
|
}
|
|
gi.G2API_PrecacheGhoul2Model( weaponModel ); // correct way is item->world_model
|
|
}
|
|
|
|
if ( weaponInfo->weaponModel == NULL_HANDLE )
|
|
{
|
|
CG_Error( "Couldn't find weapon model %s\n", weaponData[weaponNum].classname);
|
|
return;
|
|
}
|
|
|
|
// calc midpoint for rotation
|
|
cgi_R_ModelBounds( weaponInfo->weaponModel, mins, maxs );
|
|
for ( i = 0 ; i < 3 ; i++ ) {
|
|
weaponInfo->weaponMidpoint[i] = mins[i] + 0.5 * ( maxs[i] - mins[i] );
|
|
}
|
|
|
|
// setup the shader we will use for the icon
|
|
if (weaponData[weaponNum].weaponIcon[0])
|
|
{
|
|
weaponInfo->weaponIcon = cgi_R_RegisterShaderNoMip( weaponData[weaponNum].weaponIcon);
|
|
weaponInfo->weaponIconNoAmmo = cgi_R_RegisterShaderNoMip( va("%s_na",weaponData[weaponNum].weaponIcon));
|
|
}
|
|
|
|
for ( ammo = bg_itemlist + 1 ; ammo->classname ; ammo++ ) {
|
|
if ( ammo->giType == IT_AMMO && ammo->giTag == weaponData[weaponNum].ammoIndex) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( ammo->classname && ammo->world_model ) {
|
|
weaponInfo->ammoModel = cgi_R_RegisterModel( ammo->world_model );
|
|
}
|
|
|
|
for (i=0; i< weaponData[weaponNum].numBarrels; i++) {
|
|
Q_strncpyz( path, weaponData[weaponNum].weaponMdl, sizeof(path) );
|
|
COM_StripExtension( path, path, sizeof(path) );
|
|
if (i)
|
|
{
|
|
//char crap[50];
|
|
//Com_sprintf(crap, sizeof(crap), "_barrel%d.md3", i+1 );
|
|
//strcat ( path, crap );
|
|
Q_strcat( path, sizeof(path), va("_barrel%d.md3", i+1) );
|
|
}
|
|
else
|
|
Q_strcat( path, sizeof(path), "_barrel.md3" );
|
|
weaponInfo->barrelModel[i] = cgi_R_RegisterModel( path );
|
|
}
|
|
|
|
|
|
// set up the world model for the weapon
|
|
weaponInfo->weaponWorldModel = cgi_R_RegisterModel( item->world_model );
|
|
if ( !weaponInfo->weaponWorldModel) {
|
|
weaponInfo->weaponWorldModel = weaponInfo->weaponModel;
|
|
}
|
|
|
|
// set up the hand that holds the in view weapon - assuming we have one
|
|
Q_strncpyz( path, weaponData[weaponNum].weaponMdl, sizeof(path) );
|
|
COM_StripExtension( path, path, sizeof(path) );
|
|
Q_strcat( path, sizeof(path), "_hand.md3" );
|
|
weaponInfo->handsModel = cgi_R_RegisterModel( path );
|
|
|
|
if ( !weaponInfo->handsModel ) {
|
|
weaponInfo->handsModel = cgi_R_RegisterModel( "models/weapons2/briar_pistol/briar_pistol_hand.md3" );
|
|
}
|
|
|
|
// register the sounds for the weapon
|
|
if (weaponData[weaponNum].firingSnd[0]) {
|
|
weaponInfo->firingSound = cgi_S_RegisterSound( weaponData[weaponNum].firingSnd );
|
|
}
|
|
if (weaponData[weaponNum].altFiringSnd[0]) {
|
|
weaponInfo->altFiringSound = cgi_S_RegisterSound( weaponData[weaponNum].altFiringSnd );
|
|
}
|
|
if (weaponData[weaponNum].stopSnd[0]) {
|
|
weaponInfo->stopSound = cgi_S_RegisterSound( weaponData[weaponNum].stopSnd );
|
|
}
|
|
if (weaponData[weaponNum].chargeSnd[0]) {
|
|
weaponInfo->chargeSound = cgi_S_RegisterSound( weaponData[weaponNum].chargeSnd );
|
|
}
|
|
if (weaponData[weaponNum].altChargeSnd[0]) {
|
|
weaponInfo->altChargeSound = cgi_S_RegisterSound( weaponData[weaponNum].altChargeSnd );
|
|
}
|
|
if (weaponData[weaponNum].selectSnd[0]) {
|
|
weaponInfo->selectSound = cgi_S_RegisterSound( weaponData[weaponNum].selectSnd );
|
|
}
|
|
|
|
// give us missile models if we should
|
|
if (weaponData[weaponNum].missileMdl[0]) {
|
|
weaponInfo->missileModel = cgi_R_RegisterModel(weaponData[weaponNum].missileMdl );
|
|
}
|
|
if (weaponData[weaponNum].alt_missileMdl[0]) {
|
|
weaponInfo->alt_missileModel = cgi_R_RegisterModel(weaponData[weaponNum].alt_missileMdl );
|
|
}
|
|
if (weaponData[weaponNum].missileSound[0]) {
|
|
weaponInfo->missileSound = cgi_S_RegisterSound( weaponData[weaponNum].missileSound );
|
|
}
|
|
if (weaponData[weaponNum].alt_missileSound[0]) {
|
|
weaponInfo->alt_missileSound = cgi_S_RegisterSound( weaponData[weaponNum].alt_missileSound );
|
|
}
|
|
if (weaponData[weaponNum].missileHitSound[0]) {
|
|
weaponInfo->missileHitSound = cgi_S_RegisterSound( weaponData[weaponNum].missileHitSound );
|
|
}
|
|
if (weaponData[weaponNum].altmissileHitSound[0]) {
|
|
weaponInfo->altmissileHitSound = cgi_S_RegisterSound( weaponData[weaponNum].altmissileHitSound );
|
|
}
|
|
if ( weaponData[weaponNum].mMuzzleEffect[0] )
|
|
{
|
|
weaponData[weaponNum].mMuzzleEffectID = theFxScheduler.RegisterEffect( weaponData[weaponNum].mMuzzleEffect );
|
|
}
|
|
if ( weaponData[weaponNum].mAltMuzzleEffect[0] )
|
|
{
|
|
weaponData[weaponNum].mAltMuzzleEffectID = theFxScheduler.RegisterEffect( weaponData[weaponNum].mAltMuzzleEffect );
|
|
}
|
|
|
|
//fixme: don't really need to copy these, should just use directly
|
|
// give ourselves the functions if we can
|
|
if (weaponData[weaponNum].func)
|
|
{
|
|
weaponInfo->missileTrailFunc = (void (QDECL *)(struct centity_s *,const struct weaponInfo_s *))weaponData[weaponNum].func;
|
|
}
|
|
if (weaponData[weaponNum].altfunc)
|
|
{
|
|
weaponInfo->alt_missileTrailFunc = (void (QDECL *)(struct centity_s *,const struct weaponInfo_s *))weaponData[weaponNum].altfunc;
|
|
}
|
|
|
|
switch ( weaponNum ) //extra client only stuff
|
|
{
|
|
case WP_SABER:
|
|
//saber/force FX
|
|
theFxScheduler.RegisterEffect( "spark" );
|
|
theFxScheduler.RegisterEffect( "blood_sparks" );
|
|
theFxScheduler.RegisterEffect( "force_touch" );
|
|
theFxScheduler.RegisterEffect( "saber_block" );
|
|
theFxScheduler.RegisterEffect( "saber_cut" );
|
|
theFxScheduler.RegisterEffect( "blaster/smoke_bolton" );
|
|
theFxScheduler.RegisterEffect( "saber/fizz" );
|
|
theFxScheduler.RegisterEffect( "saber/boil" );
|
|
|
|
cgs.effects.forceHeal = theFxScheduler.RegisterEffect( "force/heal" );
|
|
cgs.effects.forceInvincibility = theFxScheduler.RegisterEffect( "force/invin" );
|
|
cgs.effects.forceConfusion = theFxScheduler.RegisterEffect( "force/confusion" );
|
|
cgs.effects.forceLightning = theFxScheduler.RegisterEffect( "force/lightning" );
|
|
cgs.effects.forceLightningWide = theFxScheduler.RegisterEffect( "force/lightningwide" );
|
|
|
|
cgs.media.HUDSaberStyleFast = cgi_R_RegisterShader( "gfx/hud/saber_stylesFast" );
|
|
cgs.media.HUDSaberStyleMed = cgi_R_RegisterShader( "gfx/hud/saber_stylesMed" );
|
|
cgs.media.HUDSaberStyleStrong = cgi_R_RegisterShader( "gfx/hud/saber_stylesStrong" );
|
|
|
|
//saber sounds
|
|
cgi_S_RegisterSound( "sound/weapons/saber/saberon.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/saber/enemy_saber_on.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/saber/saberonquick.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/saber/saberoff.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/saber/enemy_saber_off.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/saber/saberspinoff.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/saber/saberoffquick.wav" );
|
|
for ( i = 1; i < 4; i++ )
|
|
{
|
|
cgi_S_RegisterSound( va( "sound/weapons/saber/saberbounce%d.wav", i ) );
|
|
}
|
|
for ( i = 1; i < 4; i++ )
|
|
{
|
|
cgi_S_RegisterSound( va( "sound/weapons/saber/saberhit%d.wav", i ) );
|
|
}
|
|
for ( i = 1; i < 4; i++ )
|
|
{
|
|
cgi_S_RegisterSound( va( "sound/weapons/saber/saberhitwall%d.wav", i ) );
|
|
}
|
|
for ( i = 1; i < 10; i++ )
|
|
{
|
|
cgi_S_RegisterSound( va( "sound/weapons/saber/saberblock%d.wav", i ) );
|
|
}
|
|
for ( i = 1; i < 6; i++ )
|
|
{
|
|
cgi_S_RegisterSound( va( "sound/weapons/saber/saberhum%d.wav", i ) );
|
|
}
|
|
for ( i = 1; i < 10; i++ )
|
|
{
|
|
cgi_S_RegisterSound( va( "sound/weapons/saber/saberhup%d.wav", i ) );
|
|
}
|
|
for ( i = 1; i < 4; i++ )
|
|
{
|
|
cgi_S_RegisterSound( va( "sound/weapons/saber/saberspin%d.wav", i ) );
|
|
}
|
|
cgi_S_RegisterSound( "sound/weapons/saber/saber_catch.wav" );
|
|
for ( i = 1; i < 4; i++ )
|
|
{
|
|
cgi_S_RegisterSound( va( "sound/weapons/saber/bounce%d.wav", i ) );
|
|
}
|
|
cgi_S_RegisterSound( "sound/weapons/saber/hitwater.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/saber/boiling.wav" );
|
|
for ( i = 1; i < 4; i++ )
|
|
{
|
|
cgi_S_RegisterSound( va( "sound/weapons/saber/rainfizz%d.wav", i ) );
|
|
}
|
|
|
|
//force sounds
|
|
cgi_S_RegisterSound( "sound/weapons/force/heal.mp3" );
|
|
cgi_S_RegisterSound( "sound/weapons/force/speed.mp3" );
|
|
cgi_S_RegisterSound( "sound/weapons/force/speedloop.mp3" );
|
|
for ( i = 1; i < 5; i++ )
|
|
{
|
|
cgi_S_RegisterSound( va( "sound/weapons/force/heal%d.mp3", i ) );
|
|
}
|
|
cgi_S_RegisterSound( "sound/weapons/force/lightning.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/force/lightning2.wav" );
|
|
for ( i = 1; i < 4; i++ )
|
|
{
|
|
cgi_S_RegisterSound( va( "sound/weapons/force/lightninghit%d.wav", i ) );
|
|
}
|
|
cgi_S_RegisterSound( "sound/weapons/force/push.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/force/pull.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/force/jump.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/force/jumpbuild.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/force/grip.mp3" );
|
|
|
|
//saber graphics
|
|
cgs.media.saberBlurShader = cgi_R_RegisterShader("gfx/effects/sabers/saberBlur");
|
|
cgs.media.yellowDroppedSaberShader = cgi_R_RegisterShader("gfx/effects/yellow_glow");
|
|
cgi_R_RegisterShader( "gfx/effects/saberDamageGlow" );
|
|
cgi_R_RegisterShader( "gfx/effects/solidWhite_cull" );
|
|
cgi_R_RegisterShader( "gfx/effects/forcePush" );
|
|
cgi_R_RegisterShader( "gfx/effects/saberFlare" );
|
|
cgs.media.redSaberGlowShader = cgi_R_RegisterShader( "gfx/effects/sabers/red_glow" );
|
|
cgs.media.redSaberCoreShader = cgi_R_RegisterShader( "gfx/effects/sabers/red_line" );
|
|
cgs.media.orangeSaberGlowShader = cgi_R_RegisterShader( "gfx/effects/sabers/orange_glow" );
|
|
cgs.media.orangeSaberCoreShader = cgi_R_RegisterShader( "gfx/effects/sabers/orange_line" );
|
|
cgs.media.yellowSaberGlowShader = cgi_R_RegisterShader( "gfx/effects/sabers/yellow_glow" );
|
|
cgs.media.yellowSaberCoreShader = cgi_R_RegisterShader( "gfx/effects/sabers/yellow_line" );
|
|
cgs.media.greenSaberGlowShader = cgi_R_RegisterShader( "gfx/effects/sabers/green_glow" );
|
|
cgs.media.greenSaberCoreShader = cgi_R_RegisterShader( "gfx/effects/sabers/green_line" );
|
|
cgs.media.blueSaberGlowShader = cgi_R_RegisterShader( "gfx/effects/sabers/blue_glow" );
|
|
cgs.media.blueSaberCoreShader = cgi_R_RegisterShader( "gfx/effects/sabers/blue_line" );
|
|
cgs.media.purpleSaberGlowShader = cgi_R_RegisterShader( "gfx/effects/sabers/purple_glow" );
|
|
cgs.media.purpleSaberCoreShader = cgi_R_RegisterShader( "gfx/effects/sabers/purple_line" );
|
|
|
|
cgs.media.forceCoronaShader = cgi_R_RegisterShaderNoMip( "gfx/hud/force_swirl" );
|
|
break;
|
|
|
|
case WP_BRYAR_PISTOL:
|
|
cgs.effects.bryarShotEffect = theFxScheduler.RegisterEffect( "bryar/shot" );
|
|
theFxScheduler.RegisterEffect( "bryar/NPCshot" );
|
|
cgs.effects.bryarPowerupShotEffect = theFxScheduler.RegisterEffect( "bryar/crackleShot" );
|
|
cgs.effects.bryarWallImpactEffect = theFxScheduler.RegisterEffect( "bryar/wall_impact" );
|
|
cgs.effects.bryarWallImpactEffect2 = theFxScheduler.RegisterEffect( "bryar/wall_impact2" );
|
|
cgs.effects.bryarWallImpactEffect3 = theFxScheduler.RegisterEffect( "bryar/wall_impact3" );
|
|
cgs.effects.bryarFleshImpactEffect = theFxScheduler.RegisterEffect( "bryar/flesh_impact" );
|
|
|
|
// Note....these are temp shared effects
|
|
theFxScheduler.RegisterEffect( "blaster/deflect" );
|
|
theFxScheduler.RegisterEffect( "blaster/smoke_bolton" ); // note: this will be called game side
|
|
break;
|
|
|
|
case WP_BLASTER:
|
|
cgs.effects.blasterShotEffect = theFxScheduler.RegisterEffect( "blaster/shot" );
|
|
theFxScheduler.RegisterEffect( "blaster/NPCshot" );
|
|
// cgs.effects.blasterOverchargeEffect = theFxScheduler.RegisterEffect( "blaster/overcharge" );
|
|
cgs.effects.blasterWallImpactEffect = theFxScheduler.RegisterEffect( "blaster/wall_impact" );
|
|
cgs.effects.blasterFleshImpactEffect = theFxScheduler.RegisterEffect( "blaster/flesh_impact" );
|
|
theFxScheduler.RegisterEffect( "blaster/deflect" );
|
|
theFxScheduler.RegisterEffect( "blaster/smoke_bolton" ); // note: this will be called game side
|
|
break;
|
|
|
|
case WP_DISRUPTOR:
|
|
theFxScheduler.RegisterEffect( "disruptor/wall_impact" );
|
|
theFxScheduler.RegisterEffect( "disruptor/flesh_impact" );
|
|
theFxScheduler.RegisterEffect( "disruptor/alt_miss" );
|
|
theFxScheduler.RegisterEffect( "disruptor/alt_hit" );
|
|
theFxScheduler.RegisterEffect( "disruptor/line_cap" );
|
|
theFxScheduler.RegisterEffect( "disruptor/death_smoke" );
|
|
|
|
cgi_R_RegisterShader( "gfx/effects/redLine" );
|
|
cgi_R_RegisterShader( "gfx/misc/whiteline2" );
|
|
cgi_R_RegisterShader( "gfx/effects/smokeTrail" );
|
|
cgi_R_RegisterShader( "gfx/effects/burn" );
|
|
|
|
cgi_R_RegisterShaderNoMip( "gfx/2d/crop_charge" );
|
|
|
|
// zoom sounds
|
|
cgi_S_RegisterSound( "sound/weapons/disruptor/zoomstart.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/disruptor/zoomend.wav" );
|
|
cgs.media.disruptorZoomLoop = cgi_S_RegisterSound( "sound/weapons/disruptor/zoomloop.wav" );
|
|
|
|
// Disruptor gun zoom interface
|
|
cgs.media.disruptorMask = cgi_R_RegisterShader( "gfx/2d/cropCircle2");
|
|
cgs.media.disruptorInsert = cgi_R_RegisterShader( "gfx/2d/cropCircle");
|
|
cgs.media.disruptorLight = cgi_R_RegisterShader( "gfx/2d/cropCircleGlow" );
|
|
cgs.media.disruptorInsertTick = cgi_R_RegisterShader( "gfx/2d/insertTick" );
|
|
break;
|
|
|
|
case WP_BOWCASTER:
|
|
cgs.effects.bowcasterShotEffect = theFxScheduler.RegisterEffect( "bowcaster/shot" );
|
|
cgs.effects.bowcasterBounceEffect = theFxScheduler.RegisterEffect( "bowcaster/bounce" );
|
|
cgs.effects.bowcasterImpactEffect = theFxScheduler.RegisterEffect( "bowcaster/explosion" );
|
|
theFxScheduler.RegisterEffect( "bowcaster/deflect" );
|
|
break;
|
|
|
|
case WP_REPEATER:
|
|
theFxScheduler.RegisterEffect( "repeater/muzzle_smoke" );
|
|
theFxScheduler.RegisterEffect( "repeater/projectile" );
|
|
theFxScheduler.RegisterEffect( "repeater/alt_projectile" );
|
|
theFxScheduler.RegisterEffect( "repeater/wall_impact" );
|
|
// theFxScheduler.RegisterEffect( "repeater/alt_wall_impact2" );
|
|
// theFxScheduler.RegisterEffect( "repeater/flesh_impact" );
|
|
theFxScheduler.RegisterEffect( "repeater/concussion" );
|
|
break;
|
|
|
|
case WP_DEMP2:
|
|
theFxScheduler.RegisterEffect( "demp2/projectile" );
|
|
theFxScheduler.RegisterEffect( "demp2/wall_impact" );
|
|
theFxScheduler.RegisterEffect( "demp2/flesh_impact" );
|
|
theFxScheduler.RegisterEffect( "demp2/altDetonate" );
|
|
cgi_R_RegisterModel( "models/items/sphere.md3" );
|
|
cgi_R_RegisterShader( "gfx/effects/demp2shell" );
|
|
break;
|
|
|
|
case WP_ATST_MAIN:
|
|
theFxScheduler.RegisterEffect( "atst/shot" );
|
|
theFxScheduler.RegisterEffect( "atst/wall_impact" );
|
|
theFxScheduler.RegisterEffect( "atst/flesh_impact" );
|
|
theFxScheduler.RegisterEffect( "atst/droid_impact" );
|
|
break;
|
|
|
|
case WP_ATST_SIDE:
|
|
// For the ALT fire
|
|
theFxScheduler.RegisterEffect( "atst/side_alt_shot" );
|
|
theFxScheduler.RegisterEffect( "atst/side_alt_explosion" );
|
|
|
|
// For the regular fire
|
|
theFxScheduler.RegisterEffect( "atst/side_main_shot" );
|
|
theFxScheduler.RegisterEffect( "atst/side_main_impact" );
|
|
break;
|
|
|
|
case WP_FLECHETTE:
|
|
cgs.effects.flechetteShotEffect = theFxScheduler.RegisterEffect( "flechette/shot" );
|
|
cgs.effects.flechetteAltShotEffect = theFxScheduler.RegisterEffect( "flechette/alt_shot" );
|
|
cgs.effects.flechetteShotDeathEffect = theFxScheduler.RegisterEffect( "flechette/wall_impact" ); // shot death
|
|
cgs.effects.flechetteFleshImpactEffect = theFxScheduler.RegisterEffect( "flechette/flesh_impact" );
|
|
cgs.effects.flechetteRicochetEffect = theFxScheduler.RegisterEffect( "flechette/ricochet" );
|
|
|
|
// theFxScheduler.RegisterEffect( "flechette/explosion" );
|
|
theFxScheduler.RegisterEffect( "flechette/alt_blow" );
|
|
break;
|
|
|
|
case WP_ROCKET_LAUNCHER:
|
|
theFxScheduler.RegisterEffect( "rocket/shot" );
|
|
theFxScheduler.RegisterEffect( "rocket/explosion" );
|
|
|
|
cgi_R_RegisterShaderNoMip( "gfx/2d/wedge" );
|
|
cgi_R_RegisterShaderNoMip( "gfx/2d/lock" );
|
|
|
|
cgi_S_RegisterSound( "sound/weapons/rocket/lock.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/rocket/tick.wav" );
|
|
break;
|
|
|
|
case WP_THERMAL:
|
|
cgs.media.grenadeBounce1 = cgi_S_RegisterSound( "sound/weapons/thermal/bounce1.wav" );
|
|
cgs.media.grenadeBounce2 = cgi_S_RegisterSound( "sound/weapons/thermal/bounce2.wav" );
|
|
|
|
cgi_S_RegisterSound( "sound/weapons/thermal/thermloop.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/thermal/warning.wav" );
|
|
theFxScheduler.RegisterEffect( "thermal/explosion" );
|
|
theFxScheduler.RegisterEffect( "thermal/shockwave" );
|
|
break;
|
|
|
|
case WP_TRIP_MINE:
|
|
theFxScheduler.RegisterEffect( "tripMine/explosion" );
|
|
theFxScheduler.RegisterEffect( "tripMine/laser" );
|
|
theFxScheduler.RegisterEffect( "tripMine/laserImpactGlow" );
|
|
theFxScheduler.RegisterEffect( "tripMine/glowBit" );
|
|
|
|
cgs.media.tripMineStickSound = cgi_S_RegisterSound( "sound/weapons/laser_trap/stick.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/laser_trap/warning.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/laser_trap/hum_loop.wav" );
|
|
break;
|
|
|
|
case WP_DET_PACK:
|
|
theFxScheduler.RegisterEffect( "detpack/explosion.efx" );
|
|
|
|
cgs.media.detPackStickSound = cgi_S_RegisterSound( "sound/weapons/detpack/stick.wav" );
|
|
cgi_R_RegisterModel( "models/weapons2/detpack/detpack.md3" );
|
|
cgi_S_RegisterSound( "sound/weapons/detpack/warning.wav" );
|
|
cgi_S_RegisterSound( "sound/weapons/explosions/explode5.wav" );
|
|
break;
|
|
|
|
case WP_EMPLACED_GUN:
|
|
theFxScheduler.RegisterEffect( "emplaced/shot" );
|
|
theFxScheduler.RegisterEffect( "emplaced/shotNPC" );
|
|
theFxScheduler.RegisterEffect( "emplaced/wall_impact" );
|
|
cgi_R_RegisterShader( "models/map_objects/imp_mine/turret_chair_dmg" );
|
|
cgi_R_RegisterShader( "models/map_objects/imp_mine/turret_chair_on" );
|
|
|
|
cgs.media.emplacedHealthBarShader = cgi_R_RegisterShaderNoMip( "gfx/hud/atst_health_frame" );
|
|
cgs.media.ladyLuckHealthShader = cgi_R_RegisterShaderNoMip( "gfx/hud/ladyluck_health_frame" );
|
|
cgs.media.turretComputerOverlayShader = cgi_R_RegisterShaderNoMip( "gfx/hud/generic_target" );
|
|
cgs.media.turretCrossHairShader = cgi_R_RegisterShaderNoMip( "gfx/2d/panel_crosshair" );
|
|
break;
|
|
|
|
case WP_MELEE:
|
|
//TEMP
|
|
cgi_S_RegisterSound( "sound/weapons/melee/punch1.mp3" );
|
|
cgi_S_RegisterSound( "sound/weapons/melee/punch2.mp3" );
|
|
cgi_S_RegisterSound( "sound/weapons/melee/punch3.mp3" );
|
|
cgi_S_RegisterSound( "sound/weapons/melee/punch4.mp3" );
|
|
break;
|
|
|
|
case WP_STUN_BATON:
|
|
cgi_R_RegisterShader( "gfx/effects/stunPass" );
|
|
theFxScheduler.RegisterEffect( "stunBaton/flesh_impact" );
|
|
//TEMP
|
|
cgi_S_RegisterSound( "sound/weapons/melee/punch1.mp3" );
|
|
cgi_S_RegisterSound( "sound/weapons/melee/punch2.mp3" );
|
|
cgi_S_RegisterSound( "sound/weapons/melee/punch3.mp3" );
|
|
cgi_S_RegisterSound( "sound/weapons/melee/punch4.mp3" );
|
|
cgi_S_RegisterSound( "sound/weapons/baton/fire" );
|
|
break;
|
|
|
|
case WP_TURRET:
|
|
theFxScheduler.RegisterEffect( "turret/shot" );
|
|
theFxScheduler.RegisterEffect( "turret/wall_impact" );
|
|
theFxScheduler.RegisterEffect( "turret/flesh_impact" );
|
|
break;
|
|
|
|
case WP_BLASTER_PISTOL: // enemy version
|
|
cgs.effects.bryarShotEffect = theFxScheduler.RegisterEffect( "bryar/shot" );
|
|
cgs.effects.bryarPowerupShotEffect = theFxScheduler.RegisterEffect( "bryar/crackleShot" );
|
|
cgs.effects.bryarWallImpactEffect = theFxScheduler.RegisterEffect( "bryar/wall_impact" );
|
|
cgs.effects.bryarFleshImpactEffect = theFxScheduler.RegisterEffect( "bryar/flesh_impact" );
|
|
// Note....these are temp shared effects
|
|
theFxScheduler.RegisterEffect( "blaster/deflect" );
|
|
theFxScheduler.RegisterEffect( "blaster/smoke_bolton" ); // note: this will be called game side
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
CG_RegisterItemVisuals
|
|
|
|
The server says this item is used on this level
|
|
=================
|
|
*/
|
|
void CG_RegisterItemVisuals( int itemNum ) {
|
|
itemInfo_t *itemInfo;
|
|
gitem_t *item;
|
|
|
|
itemInfo = &cg_items[ itemNum ];
|
|
if ( itemInfo->registered ) {
|
|
return;
|
|
}
|
|
|
|
item = &bg_itemlist[ itemNum ];
|
|
|
|
memset( itemInfo, 0, sizeof( *itemInfo ) );
|
|
itemInfo->registered = qtrue;
|
|
|
|
itemInfo->models = cgi_R_RegisterModel( item->world_model );
|
|
|
|
if ( item->icon && item->icon[0] )
|
|
{
|
|
itemInfo->icon = cgi_R_RegisterShaderNoMip( item->icon );
|
|
}
|
|
else
|
|
{
|
|
itemInfo->icon = -1;
|
|
}
|
|
|
|
if ( item->giType == IT_WEAPON )
|
|
{
|
|
CG_RegisterWeapon( item->giTag );
|
|
}
|
|
|
|
// some ammo types are actually the weapon, like in the case of explosives
|
|
if ( item->giType == IT_AMMO )
|
|
{
|
|
switch( item->giTag )
|
|
{
|
|
case AMMO_THERMAL:
|
|
CG_RegisterWeapon( WP_THERMAL );
|
|
break;
|
|
case AMMO_TRIPMINE:
|
|
CG_RegisterWeapon( WP_TRIP_MINE );
|
|
break;
|
|
case AMMO_DETPACK:
|
|
CG_RegisterWeapon( WP_DET_PACK );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if ( item->giType == IT_HOLDABLE )
|
|
{
|
|
// This should be set up to actually work.
|
|
switch( item->giTag )
|
|
{
|
|
case INV_SEEKER:
|
|
cgi_S_RegisterSound("sound/chars/seeker/misc/fire.wav");
|
|
cgi_S_RegisterSound( "sound/chars/seeker/misc/hiss.wav");
|
|
theFxScheduler.RegisterEffect( "env/small_explode");
|
|
|
|
CG_RegisterWeapon( WP_BLASTER );
|
|
break;
|
|
|
|
case INV_SENTRY:
|
|
CG_RegisterWeapon( WP_TURRET );
|
|
cgi_S_RegisterSound( "sound/player/use_sentry" );
|
|
break;
|
|
|
|
case INV_ELECTROBINOCULARS:
|
|
// Binocular interface
|
|
cgs.media.binocularCircle = cgi_R_RegisterShader( "gfx/2d/binCircle" );
|
|
cgs.media.binocularMask = cgi_R_RegisterShader( "gfx/2d/binMask" );
|
|
cgs.media.binocularArrow = cgi_R_RegisterShader( "gfx/2d/binSideArrow" );
|
|
cgs.media.binocularTri = cgi_R_RegisterShader( "gfx/2d/binTopTri" );
|
|
cgs.media.binocularStatic = cgi_R_RegisterShader( "gfx/2d/binocularWindow" );
|
|
cgs.media.binocularOverlay = cgi_R_RegisterShader( "gfx/2d/binocularNumOverlay" );
|
|
break;
|
|
|
|
case INV_LIGHTAMP_GOGGLES:
|
|
// LA Goggles Shaders
|
|
cgs.media.laGogglesStatic = cgi_R_RegisterShader( "gfx/2d/lagogglesWindow" );
|
|
cgs.media.laGogglesMask = cgi_R_RegisterShader( "gfx/2d/amp_mask" );
|
|
cgs.media.laGogglesSideBit = cgi_R_RegisterShader( "gfx/2d/side_bit" );
|
|
cgs.media.laGogglesBracket = cgi_R_RegisterShader( "gfx/2d/bracket" );
|
|
cgs.media.laGogglesArrow = cgi_R_RegisterShader( "gfx/2d/bracket2" );
|
|
break;
|
|
|
|
case INV_BACTA_CANISTER:
|
|
for ( int i = 1; i < 5; i++ )
|
|
{
|
|
cgi_S_RegisterSound( va( "sound/weapons/force/heal%d.mp3", i ));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
========================================================================================
|
|
|
|
VIEW WEAPON
|
|
|
|
========================================================================================
|
|
*/
|
|
|
|
/*
|
|
=================
|
|
CG_MapTorsoToWeaponFrame
|
|
|
|
animations MUST match the defined pattern!
|
|
the weapon hand animation has 3 anims,
|
|
6 frames of attack
|
|
4 frames of drop
|
|
5 frames of raise
|
|
|
|
if the torso anim does not match these lengths, it will not animate correctly!
|
|
=================
|
|
*/
|
|
extern qboolean ValidAnimFileIndex ( int index );
|
|
int CG_MapTorsoToWeaponFrame( const clientInfo_t *ci, int frame, int animNum, int weaponNum, int firing )
|
|
{
|
|
// we should use the animNum to map a weapon frame instead of relying on the torso frame
|
|
if ( !ValidAnimFileIndex( ci->animFileIndex ) )
|
|
{
|
|
return 0;
|
|
}
|
|
animation_t *animations = level.knownAnimFileSets[ci->animFileIndex].animations;
|
|
int ret=0;
|
|
|
|
switch( animNum )
|
|
{
|
|
case TORSO_WEAPONREADY1:
|
|
case TORSO_WEAPONREADY2:
|
|
case TORSO_WEAPONREADY3:
|
|
case TORSO_WEAPONREADY4:
|
|
case TORSO_WEAPONREADY5:
|
|
case TORSO_WEAPONREADY6:
|
|
case TORSO_WEAPONREADY7:
|
|
case TORSO_WEAPONREADY8:
|
|
case TORSO_WEAPONREADY9:
|
|
case TORSO_WEAPONREADY10:
|
|
case TORSO_WEAPONREADY11:
|
|
case TORSO_WEAPONREADY12:
|
|
ret = 0;
|
|
break;
|
|
|
|
case TORSO_DROPWEAP1:
|
|
if ( frame >= animations[animNum].firstFrame && frame < animations[animNum].firstFrame + 5 )
|
|
{
|
|
ret = frame - animations[animNum].firstFrame + 6;
|
|
}
|
|
else
|
|
{
|
|
// assert(0);
|
|
}
|
|
break;
|
|
|
|
case TORSO_RAISEWEAP1:
|
|
if ( frame >= animations[animNum].firstFrame && frame < animations[animNum].firstFrame + 4 )
|
|
{
|
|
ret = frame - animations[animNum].firstFrame + 6 + 5;
|
|
}
|
|
else
|
|
{
|
|
// assert(0);
|
|
}
|
|
break;
|
|
|
|
case BOTH_ATTACK1:
|
|
case BOTH_ATTACK2:
|
|
case BOTH_ATTACK3:
|
|
case BOTH_ATTACK4:
|
|
if ( frame >= animations[animNum].firstFrame && frame < animations[animNum].firstFrame + 6 )
|
|
{
|
|
ret = 1 + ( frame - animations[animNum].firstFrame );
|
|
}
|
|
else
|
|
{
|
|
// assert(0);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
CG_CalculateWeaponPosition
|
|
==============
|
|
*/
|
|
void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles )
|
|
{
|
|
float scale;
|
|
int delta;
|
|
float fracsin;
|
|
|
|
VectorCopy( cg.refdef.vieworg, origin );
|
|
VectorCopy( cg.refdefViewAngles, angles );
|
|
|
|
// on odd legs, invert some angles
|
|
if ( cg.bobcycle & 1 ) {
|
|
scale = -cg.xyspeed;
|
|
} else {
|
|
scale = cg.xyspeed;
|
|
}
|
|
|
|
// gun angles from bobbing
|
|
angles[ROLL] += scale * cg.bobfracsin * 0.0075;
|
|
angles[YAW] += scale * cg.bobfracsin * 0.01;
|
|
angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.0075;
|
|
|
|
// drop the weapon when landing
|
|
delta = cg.time - cg.landTime;
|
|
if ( delta < LAND_DEFLECT_TIME ) {
|
|
origin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME;
|
|
} else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
|
|
origin[2] += cg.landChange*0.25 *
|
|
(LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME;
|
|
}
|
|
|
|
#if 0
|
|
// drop the weapon when stair climbing
|
|
delta = cg.time - cg.stepTime;
|
|
if ( delta < STEP_TIME/2 ) {
|
|
origin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2);
|
|
} else if ( delta < STEP_TIME ) {
|
|
origin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2);
|
|
}
|
|
#endif
|
|
|
|
// idle drift
|
|
scale = /*cg.xyspeed + */40;
|
|
fracsin = sin( cg.time * 0.001 );
|
|
angles[ROLL] += scale * fracsin * 0.01;
|
|
angles[YAW] += scale * fracsin * 0.01;
|
|
angles[PITCH] += (scale * 0.5f ) * fracsin * 0.01;
|
|
}
|
|
|
|
static vr_weapon_adjustment_t* LoadWeaponAdjustment( int weapon ) {
|
|
char cvar_name[64];
|
|
vr_weapon_adjustment_t *adjustment = &vr->weaponadjustment[weapon];
|
|
if (!adjustment->loaded) {
|
|
Com_sprintf(cvar_name, sizeof(cvar_name), "vr_weapon_adjustment_%i", weapon);
|
|
char* weapon_adjustment = cgi_Cvar_Get(cvar_name);
|
|
if (strlen(weapon_adjustment) > 0) {
|
|
sscanf(weapon_adjustment, "%f,%f,%f,%f,%f,%f,%f",
|
|
&adjustment->scale,
|
|
&adjustment->offset[0],
|
|
&adjustment->offset[1],
|
|
&adjustment->offset[2],
|
|
&adjustment->angles[PITCH],
|
|
&adjustment->angles[YAW],
|
|
&adjustment->angles[ROLL]);
|
|
} else {
|
|
adjustment->scale = 1.0f;
|
|
adjustment->offset[0] = 0.0f;
|
|
adjustment->offset[1] = 0.0f;
|
|
adjustment->offset[2] = 0.0f;
|
|
adjustment->angles[PITCH] = 0.0f;
|
|
adjustment->angles[YAW] = 0.0f;
|
|
adjustment->angles[ROLL] = 0.0f;
|
|
}
|
|
adjustment->loaded = true;
|
|
}
|
|
return adjustment;
|
|
}
|
|
|
|
static float CG_CalculateWeaponPositionAndScale( playerState_t *ps, vec3_t origin, vec3_t angles ) {
|
|
|
|
if (cg.renderingThirdPerson)
|
|
{
|
|
CG_CalculateWeaponPosition(origin, angles);
|
|
return 1.0f;
|
|
}
|
|
|
|
BG_CalculateVRWeaponPosition(origin, angles);
|
|
|
|
vr_weapon_adjustment_t *adjustment = LoadWeaponAdjustment(ps->weapon);
|
|
|
|
vec3_t offset;
|
|
VectorScale(adjustment->offset, adjustment->scale, offset);
|
|
|
|
vec3_t adjust;
|
|
VectorCopy(adjustment->angles, adjust);
|
|
if (!vr->right_handed)
|
|
{
|
|
//yaw needs to go in the other direction as left handed model is reversed
|
|
adjust[YAW] *= -1.0f;
|
|
}
|
|
|
|
//Adjust angles for weapon models that aren't aligned very well
|
|
matrix4x4 m1, m2, m3;
|
|
vec3_t zero;
|
|
VectorClear(zero);
|
|
Matrix4x4_CreateFromEntity(m1, angles, zero, 1.0);
|
|
Matrix4x4_CreateFromEntity(m2, adjust, zero, 1.0);
|
|
Matrix4x4_Concat(m3, m1, m2);
|
|
Matrix4x4_ConvertToEntity(m3, angles, zero);
|
|
|
|
//Now move weapon closer to proper origin
|
|
vec3_t forward, right, up;
|
|
AngleVectors( angles, forward, right, up );
|
|
VectorMA( origin, offset[2], forward, origin );
|
|
VectorMA( origin, offset[1], up, origin );
|
|
if (vr->right_handed) {
|
|
VectorMA(origin, offset[0], right, origin);
|
|
} else {
|
|
VectorMA(origin, -offset[0], right, origin);
|
|
}
|
|
|
|
return adjustment->scale;
|
|
}
|
|
|
|
/*
|
|
======================
|
|
CG_MachinegunSpinAngle
|
|
======================
|
|
*/
|
|
/*
|
|
#define SPIN_SPEED 0.9
|
|
#define COAST_TIME 1000
|
|
static float CG_MachinegunSpinAngle( centity_t *cent ) {
|
|
int delta;
|
|
float angle;
|
|
float speed;
|
|
|
|
delta = cg.time - cent->pe.barrelTime;
|
|
if ( cent->pe.barrelSpinning ) {
|
|
angle = cent->pe.barrelAngle + delta * SPIN_SPEED;
|
|
} else {
|
|
if ( delta > COAST_TIME ) {
|
|
delta = COAST_TIME;
|
|
}
|
|
|
|
speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME );
|
|
angle = cent->pe.barrelAngle + delta * speed;
|
|
}
|
|
|
|
if ( cent->pe.barrelSpinning == !(cent->currentState.eFlags & EF_FIRING) ) {
|
|
cent->pe.barrelTime = cg.time;
|
|
cent->pe.barrelAngle = AngleNormalize360( angle );
|
|
cent->pe.barrelSpinning = !!(cent->currentState.eFlags & EF_FIRING);
|
|
}
|
|
|
|
return angle;
|
|
}
|
|
*/
|
|
/*
|
|
Ghoul2 Insert Start
|
|
*/
|
|
// set up the appropriate ghoul2 info to a refent
|
|
void CG_SetGhoul2InfoRef( refEntity_t *ent, refEntity_t *s1)
|
|
{
|
|
ent->ghoul2 = s1->ghoul2;
|
|
VectorCopy( s1->modelScale, ent->modelScale);
|
|
ent->radius = s1->radius;
|
|
VectorCopy( s1->angles, ent->angles);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
static void CG_DoMuzzleFlash( centity_t *cent, vec3_t org, vec3_t dir, weaponData_t *wData )
|
|
{
|
|
// Handle muzzle flashes, really this could just be a qboolean instead of a time.......
|
|
if ( cent->muzzleFlashTime > 0 )
|
|
{
|
|
if (cg.stereoView == STEREO_RIGHT) {
|
|
cent->muzzleFlashTime = 0;
|
|
}
|
|
|
|
const char *effect = NULL;
|
|
|
|
// CG_PositionEntityOnTag( &flash, &gun, gun.hModel, "tag_flash");
|
|
|
|
// Try and get a default muzzle so we have one to fall back on
|
|
if ( wData->mMuzzleEffect[0] )
|
|
{
|
|
effect = &wData->mMuzzleEffect[0];
|
|
}
|
|
|
|
if ( cent->altFire )
|
|
{
|
|
// We're alt-firing, so see if we need to override with a custom alt-fire effect
|
|
if ( wData->mAltMuzzleEffect[0] )
|
|
{
|
|
effect = &wData->mAltMuzzleEffect[0];
|
|
}
|
|
}
|
|
|
|
if (/*( cent->currentState.eFlags & EF_FIRING || cent->currentState.eFlags & EF_ALT_FIRING ) &&*/ effect )
|
|
{
|
|
vec3_t up={0,0,1}, ax[3];
|
|
|
|
VectorCopy( dir, ax[0] );
|
|
|
|
CrossProduct( up, ax[0], ax[1] );
|
|
CrossProduct( ax[0], ax[1], ax[2] );
|
|
|
|
if (( cent->gent && cent->gent->NPC ) || cg.renderingThirdPerson )
|
|
{
|
|
theFxScheduler.PlayEffect( effect, org, dir );
|
|
}
|
|
else
|
|
{
|
|
// We got an effect and we're firing, so let 'er rip.
|
|
theFxScheduler.PlayEffect( effect, cent->currentState.clientNum );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash", NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Ghoul2 Insert End
|
|
*/
|
|
|
|
/*
|
|
==============
|
|
CG_AddViewWeapon
|
|
|
|
Add the weapon, and flash for the player's view
|
|
==============
|
|
*/
|
|
extern int PM_TorsoAnimForFrame( gentity_t *ent, int torsoFrame );
|
|
extern float CG_ForceSpeedFOV( float infov );
|
|
|
|
void CG_AddViewWeapon( playerState_t *ps )
|
|
{
|
|
refEntity_t hand;
|
|
refEntity_t gun;
|
|
refEntity_t flash;
|
|
vec3_t angles;
|
|
const weaponInfo_t *weapon;
|
|
weaponData_t *wData;
|
|
centity_t *cent;
|
|
float fovOffset, leanOffset;
|
|
float cgFov = (cg_fovViewmodel.integer) ? cg_fovViewmodel.integer : cg_fov.integer;
|
|
int i;
|
|
|
|
if (cgFov < 1)
|
|
cgFov = 1;
|
|
else if (cgFov > 130)
|
|
cgFov = 130;
|
|
|
|
// no gun if in third person view
|
|
if ( cg.renderingThirdPerson )
|
|
return;
|
|
|
|
if ( ps->pm_type == PM_INTERMISSION )
|
|
return;
|
|
|
|
cent = &cg_entities[ps->clientNum];
|
|
|
|
if ( ps->eFlags & EF_LOCKED_TO_WEAPON )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( cent->gent && cent->gent->client && cent->gent->client->ps.forcePowersActive&(1<<FP_LIGHTNING) )
|
|
{//doing the electrocuting
|
|
vec3_t tAng, fxDir, temp;
|
|
VectorSet( tAng, cent->pe.torso.pitchAngle, cent->pe.torso.yawAngle, 0 );
|
|
|
|
VectorCopy( cent->gent->client->renderInfo.handLPoint, temp );
|
|
VectorMA( temp, -5, cg.refdef.viewaxis[0], temp );
|
|
if ( cent->gent->client->ps.forcePowerLevel[FP_LIGHTNING] > FORCE_LEVEL_2 )
|
|
{//arc
|
|
vec3_t fxAxis[3];
|
|
AnglesToAxis( tAng, fxAxis );
|
|
theFxScheduler.PlayEffect( cgs.effects.forceLightningWide, temp, fxAxis );
|
|
}
|
|
else
|
|
{//line
|
|
AngleVectors( tAng, fxDir, NULL, NULL );
|
|
theFxScheduler.PlayEffect( cgs.effects.forceLightning, temp, fxDir );
|
|
}
|
|
}
|
|
// allow the gun to be completely removed
|
|
if ( !cg_drawGun.integer || cg.zoomMode )
|
|
{
|
|
vec3_t origin;
|
|
|
|
// special hack for lightning guns...
|
|
VectorCopy( cg.refdef.vieworg, origin );
|
|
VectorMA( origin, -10, cg.refdef.viewaxis[2], origin );
|
|
VectorMA( origin, 16, cg.refdef.viewaxis[0], origin );
|
|
// Doesn't look like we'll have lightning style guns. Clean this crap up when we are sure about this.
|
|
// CG_LightningBolt( cent, origin );
|
|
|
|
// We should still do muzzle flashes though...
|
|
CG_RegisterWeapon( ps->weapon );
|
|
weapon = &cg_weapons[ps->weapon];
|
|
wData = &weaponData[ps->weapon];
|
|
|
|
CG_DoMuzzleFlash( cent, origin, cg.refdef.viewaxis[0], wData );
|
|
|
|
// If we don't update this, the muzzle flash point won't even be updated properly
|
|
VectorCopy( origin, cent->gent->client->renderInfo.muzzlePoint );
|
|
VectorCopy( cg.refdef.viewaxis[0], cent->gent->client->renderInfo.muzzleDir );
|
|
|
|
cent->gent->client->renderInfo.mPCalcTime = cg.time;
|
|
return;
|
|
}
|
|
|
|
// don't draw if testing a gun model
|
|
if ( cg.testGun )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// drop gun lower at higher fov
|
|
float actualFOV;
|
|
gentity_t *player = &g_entities[0];
|
|
if ( (cg.snap->ps.forcePowersActive&(1<<FP_SPEED)) && player->client->ps.forcePowerDuration[FP_SPEED] )//cg.renderingThirdPerson &&
|
|
{
|
|
actualFOV = CG_ForceSpeedFOV(cg_fov.value);
|
|
actualFOV = (cg_fovViewmodel.integer) ? actualFOV + (cg_fovViewmodel.integer - cg_fov.integer) : actualFOV;
|
|
}
|
|
else
|
|
{
|
|
actualFOV = (cg.overrides.active&CG_OVERRIDE_FOV) ? cg.overrides.fov : cg_fov.value;
|
|
}
|
|
|
|
if ( cg_fovViewmodelAdjust.integer && actualFOV > 80 )
|
|
{
|
|
fovOffset = -0.1 * ( actualFOV - 80 );
|
|
}
|
|
else
|
|
{
|
|
fovOffset = 0;
|
|
}
|
|
|
|
if ( ps->leanofs != 0 )
|
|
{
|
|
//add leaning offset
|
|
leanOffset = ps->leanofs * 0.25f;
|
|
fovOffset += fabs((double)ps->leanofs) * -0.1f;
|
|
}
|
|
else
|
|
{
|
|
leanOffset = 0;
|
|
}
|
|
|
|
CG_RegisterWeapon( ps->weapon );
|
|
weapon = &cg_weapons[ps->weapon];
|
|
wData = &weaponData[ps->weapon];
|
|
|
|
memset (&hand, 0, sizeof(hand));
|
|
|
|
if ( ps->weapon == WP_STUN_BATON )
|
|
{
|
|
cgi_S_AddLoopingSound( cent->currentState.number,
|
|
cent->lerpOrigin,
|
|
vec3_origin,
|
|
weapon->firingSound );
|
|
}
|
|
|
|
if ( ps->weapon == WP_NONE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (strcmp(cgi_Cvar_Get("vr_control_scheme"), "99") == 0) {
|
|
vec3_t origin;
|
|
vec3_t startForward, startRight, startUp;
|
|
vec3_t endForward, endRight, endUp;
|
|
vec3_t _angles;
|
|
BG_CalculateVRWeaponPosition( origin, _angles );
|
|
|
|
vec3_t forward, right, up;
|
|
AngleVectors(_angles, forward, right, up);
|
|
|
|
trace_t trace;
|
|
VectorMA(origin, -10, forward, startForward);
|
|
VectorMA(origin, 256, forward, endForward);
|
|
static vec3_t RED = {1.0f,0.0f,0.0f};
|
|
FX_AddLine( startForward, endForward, 0.1f, 1.0f, 0.0f,
|
|
1.0f, 0.0f, 0.0f,
|
|
RED, RED, 0.0f,
|
|
120, cgi_R_RegisterShader( "gfx/misc/whiteline2" ),
|
|
FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
|
|
|
VectorMA(origin, -10, right, startRight);
|
|
VectorMA(origin, 10, right, endRight);
|
|
vec3_t BLUE = {0.0f,0.0f,1.0f};
|
|
FX_AddLine( startRight, endRight, 0.1f, 1.0f, 0.0f,
|
|
1.0f, 0.0f, 0.0f,
|
|
BLUE, BLUE, 0.0f,
|
|
120, cgi_R_RegisterShader( "gfx/misc/whiteline2" ),
|
|
FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
|
|
|
VectorMA(origin, -10, up, startUp);
|
|
VectorMA(origin, 10, up, endUp);
|
|
vec3_t GREEN = {0.0f,1.0f,0.0f};
|
|
FX_AddLine( startUp, endUp, 0.1f, 1.0f, 0.0f,
|
|
1.0f, 0.0f, 0.0f,
|
|
GREEN, GREEN, 0.0f,
|
|
120, cgi_R_RegisterShader( "gfx/misc/whiteline2" ),
|
|
FX_SIZE_LINEAR | FX_ALPHA_LINEAR );
|
|
|
|
CG_CenterPrint(vr->weaponadjustment_info, 240);
|
|
|
|
}
|
|
|
|
// set up gun position
|
|
float scale = CG_CalculateWeaponPositionAndScale( ps, hand.origin, angles );
|
|
|
|
if (vr->in_vehicle)
|
|
{
|
|
//Shunt the origin up if we are in a vehicle to avoid blinding the player with a muzzle flash
|
|
VectorMA( hand.origin, 2.0f * cg_worldScale.value, cg.refdef.viewaxis[2], hand.origin );
|
|
}
|
|
|
|
// VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin );
|
|
// VectorMA( hand.origin, (cg_gun_y.value+leanOffset), cg.refdef.viewaxis[1], hand.origin );
|
|
// VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin );
|
|
|
|
AnglesToAxis( angles, hand.axis );
|
|
|
|
//scale the whole model (hand and weapon)
|
|
for ( int i = 0; i < 3; i++ ) {
|
|
VectorScale( hand.axis[i], (vr->right_handed || i != 1 ) ? scale : -scale, hand.axis[i] );
|
|
}
|
|
|
|
//Gotta move this forward but test for now
|
|
VectorCopy( hand.origin, hand.lightingOrigin );
|
|
|
|
/* if ( cg_fovViewmodel.integer )
|
|
{
|
|
float fracDistFOV = tanf( cg.refdef.fov_x * ( M_PI/180 ) * 0.5f );
|
|
float fracWeapFOV = ( 1.0f / fracDistFOV ) * tanf( cgFov * ( M_PI/180 ) * 0.5f );
|
|
VectorScale( hand.axis[0], fracWeapFOV, hand.axis[0] );
|
|
}
|
|
*/
|
|
// map torso animations to weapon animations
|
|
if ( cg_gun_frame.integer )
|
|
{
|
|
// development tool
|
|
hand.frame = hand.oldframe = cg_gun_frame.integer;
|
|
hand.backlerp = 0;
|
|
}
|
|
else
|
|
{
|
|
// get clientinfo for animation map
|
|
const clientInfo_t *ci = ¢->gent->client->clientInfo;
|
|
int torsoAnim = cent->gent->client->ps.torsoAnim;//pe.torso.animationNumber;
|
|
float currentFrame;
|
|
int startFrame,endFrame,flags;
|
|
float animSpeed;
|
|
if (cent->gent->lowerLumbarBone>=0&& gi.G2API_GetBoneAnimIndex(¢->gent->ghoul2[cent->gent->playerModel], cent->gent->lowerLumbarBone, cg.time, ¤tFrame, &startFrame, &endFrame, &flags, &animSpeed,0) )
|
|
{
|
|
hand.oldframe = CG_MapTorsoToWeaponFrame( ci,floor(currentFrame), torsoAnim, cent->currentState.weapon, ( cent->currentState.eFlags & EF_FIRING ) );
|
|
hand.frame = CG_MapTorsoToWeaponFrame( ci,ceil(currentFrame), torsoAnim, cent->currentState.weapon, ( cent->currentState.eFlags & EF_FIRING ) );
|
|
hand.backlerp=1.0f-(currentFrame-floor(currentFrame));
|
|
if ( cg_debugAnim.integer == 1 && cent->currentState.clientNum == 0 )
|
|
{
|
|
Com_Printf( "Torso frame %d to %d makes Weapon frame %d to %d\n", cent->pe.torso.oldFrame, cent->pe.torso.frame, hand.oldframe, hand.frame );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// assert(0); // no idea what to do here
|
|
hand.oldframe=0;
|
|
hand.frame=0;
|
|
hand.backlerp=0.0f;
|
|
}
|
|
}
|
|
|
|
// add the weapon
|
|
memset (&gun, 0, sizeof(gun));
|
|
|
|
gun.hModel = weapon->weaponModel;
|
|
if (!gun.hModel)
|
|
{
|
|
return;
|
|
}
|
|
|
|
AnglesToAxis( angles, gun.axis );
|
|
CG_PositionEntityOnTag( &gun, &hand, weapon->handsModel, "tag_weapon");
|
|
|
|
gun.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_VRVIEWMODEL;
|
|
|
|
|
|
//---------
|
|
// OK, we are making an assumption here that if we have the phaser that it is always on....
|
|
//FIXME: if saberInFlight, need to draw empty hand guiding it
|
|
if ( cent->gent && cent->gent->client && cent->currentState.weapon == WP_SABER )
|
|
{
|
|
vec3_t org_, axis_[3];
|
|
|
|
CG_GetTagWorldPosition( &gun, "tag_flash", org_, axis_ );
|
|
if ( cent->gent->client->ps.saberActive && cent->gent->client->ps.saberLength < cent->gent->client->ps.saberLengthMax )
|
|
{
|
|
cent->gent->client->ps.saberLength += cg.frametime*0.03;
|
|
if ( cent->gent->client->ps.saberLength > cent->gent->client->ps.saberLengthMax )
|
|
{
|
|
cent->gent->client->ps.saberLength = cent->gent->client->ps.saberLengthMax;
|
|
}
|
|
}
|
|
// FX_Saber( org_, axis_[0], cent->gent->client->ps.saberLength, 2.0 + Q_flrand(-1.0f, 1.0f) * 0.2f, cent->gent->client->ps.saberColor );
|
|
VectorCopy( axis_[0], cent->gent->client->renderInfo.muzzleDir );
|
|
}
|
|
//---------
|
|
|
|
// CG_AddRefEntityWithPowerups( &gun, cent->currentState.powerups, cent->gent );
|
|
cgi_R_AddRefEntityToScene( &gun );
|
|
|
|
/* if ( ps->weapon == WP_STUN_BATON )
|
|
{
|
|
gun.shaderRGBA[0] = gun.shaderRGBA[1] = gun.shaderRGBA[2] = 25;
|
|
|
|
gun.customShader = cgi_R_RegisterShader( "gfx/effects/stunPass" );
|
|
gun.renderfx = RF_RGB_TINT | RF_FIRST_PERSON | RF_DEPTHHACK;
|
|
cgi_R_AddRefEntityToScene( &gun );
|
|
}
|
|
*/
|
|
// add the spinning barrel[s]
|
|
for (i = 0; (i < wData->numBarrels); i++)
|
|
{
|
|
refEntity_t barrel;
|
|
memset( &barrel, 0, sizeof( barrel ) );
|
|
barrel.hModel = weapon->barrelModel[i];
|
|
|
|
//VectorCopy( parent->lightingOrigin, barrel.lightingOrigin );
|
|
//barrel.shadowPlane = parent->shadowPlane;
|
|
barrel.renderfx = gun.renderfx;
|
|
angles[YAW] = 0;
|
|
angles[PITCH] = 0;
|
|
// if ( ps->weapon == WP_TETRION_DISRUPTOR) {
|
|
// angles[ROLL] = CG_MachinegunSpinAngle( cent );
|
|
// } else {
|
|
angles[ROLL] = 0;//CG_MachinegunSpinAngle( cent );
|
|
// }
|
|
|
|
AnglesToAxis( angles, barrel.axis );
|
|
if (!i)
|
|
{
|
|
CG_PositionRotatedEntityOnTag( &barrel, &hand, weapon->handsModel, "tag_barrel", NULL );
|
|
} else
|
|
{
|
|
CG_PositionRotatedEntityOnTag( &barrel, &hand, weapon->handsModel, va("tag_barrel%d",i+1), NULL );
|
|
}
|
|
|
|
cgi_R_AddRefEntityToScene( &barrel );
|
|
}
|
|
|
|
memset (&flash, 0, sizeof(flash));
|
|
|
|
// Seems like we should always do this in case we have an animating muzzle flash....that way we can always store the correct muzzle dir, etc.
|
|
CG_PositionEntityOnTag( &flash, &gun, gun.hModel, "tag_flash");
|
|
|
|
CG_DoMuzzleFlash( cent, flash.origin, flash.axis[0], wData );
|
|
|
|
if ( cent->gent && cent->gent->client )
|
|
{
|
|
VectorCopy(flash.origin, cent->gent->client->renderInfo.muzzlePoint);
|
|
VectorCopy(flash.axis[0], cent->gent->client->renderInfo.muzzleDir);
|
|
// VectorNormalize( cent->gent->client->renderInfo.muzzleDir );
|
|
cent->gent->client->renderInfo.mPCalcTime = cg.time;
|
|
|
|
CG_LightningBolt( cent, flash.origin );
|
|
}
|
|
|
|
// Do special charge bits
|
|
//-----------------------
|
|
if (( ps->weaponstate == WEAPON_CHARGING_ALT && ps->weapon == WP_BRYAR_PISTOL )
|
|
|| ( ps->weapon == WP_BOWCASTER && ps->weaponstate == WEAPON_CHARGING )
|
|
|| ( ps->weapon == WP_DEMP2 && ps->weaponstate == WEAPON_CHARGING_ALT ))
|
|
{
|
|
int shader = 0;
|
|
float val = 0.0f, scale = 1.0f;
|
|
vec3_t WHITE = {1.0f,1.0f,1.0f};
|
|
|
|
if ( ps->weapon == WP_BRYAR_PISTOL )
|
|
{
|
|
// Hardcoded max charge time of 1 second
|
|
val = ( cg.time - ps->weaponChargeTime ) * 0.001f;
|
|
shader = cgi_R_RegisterShader( "gfx/effects/bryarFrontFlash" );
|
|
}
|
|
else if ( ps->weapon == WP_BOWCASTER )
|
|
{
|
|
// Hardcoded max charge time of 1 second
|
|
val = ( cg.time - ps->weaponChargeTime ) * 0.001f;
|
|
shader = cgi_R_RegisterShader( "gfx/effects/greenFrontFlash" );
|
|
}
|
|
else if ( ps->weapon == WP_DEMP2 )
|
|
{
|
|
// Hardcoded max charge time of 1 second
|
|
val = ( cg.time - ps->weaponChargeTime ) * 0.001f;
|
|
shader = cgi_R_RegisterShader( "gfx/misc/lightningFlash" );
|
|
scale = 1.75f;
|
|
}
|
|
|
|
|
|
if ( val < 0.0f )
|
|
{
|
|
val = 0.0f;
|
|
}
|
|
else if ( val > 1.0f )
|
|
{
|
|
val = 1.0f;
|
|
}
|
|
|
|
val += Q_flrand(0.0f, 1.0f) * 0.5f;
|
|
|
|
FX_AddSprite( flash.origin, NULL, NULL, 3.0f * val * scale, 0.0f, 0.7f, 0.7f, WHITE, WHITE, Q_flrand(0.0f, 1.0f) * 360, 0.0f, 1.0f, shader, FX_USE_ALPHA | FX_DEPTH_HACK );
|
|
}
|
|
|
|
// Check if the heavy repeater is finishing up a sustained burst
|
|
//-------------------------------
|
|
if ( ps->weapon == WP_REPEATER && ps->weaponstate == WEAPON_FIRING )
|
|
{
|
|
if ( cent->gent && cent->gent->client && cent->gent->client->ps.weaponstate != WEAPON_FIRING )
|
|
{
|
|
int ct = 0;
|
|
|
|
// the more continuous shots we've got, the more smoke we spawn
|
|
if ( cent->gent->client->ps.weaponShotCount > 60 ) {
|
|
ct = 5;
|
|
}
|
|
else if ( cent->gent->client->ps.weaponShotCount > 35 ) {
|
|
ct = 3;
|
|
}
|
|
else if ( cent->gent->client->ps.weaponShotCount > 15 ) {
|
|
ct = 1;
|
|
}
|
|
|
|
for ( i = 0; i < ct; i++ )
|
|
{
|
|
theFxScheduler.PlayEffect( "repeater/muzzle_smoke", cent->currentState.clientNum );
|
|
}
|
|
|
|
cent->gent->client->ps.weaponShotCount = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============================================================================
|
|
|
|
WEAPON SELECTION
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
/*
|
|
===================
|
|
CG_WeaponCheck
|
|
===================
|
|
*/
|
|
int CG_WeaponCheck( int weaponIndex )
|
|
{
|
|
int value;
|
|
|
|
if ( weaponIndex == WP_SABER || weaponIndex == WP_STUN_BATON )
|
|
{
|
|
return qtrue;
|
|
}
|
|
|
|
value = weaponData[weaponIndex].energyPerShot < weaponData[weaponIndex].altEnergyPerShot
|
|
? weaponData[weaponIndex].energyPerShot
|
|
: weaponData[weaponIndex].altEnergyPerShot;
|
|
|
|
if( !cg.snap )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
// check how much energy(ammo) it takes to fire this weapon against how much ammo we have
|
|
if ( value > cg.snap->ps.ammo[weaponData[weaponIndex].ammoIndex] )
|
|
{
|
|
value = qfalse;
|
|
}
|
|
else
|
|
{
|
|
value = qtrue;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
/*
|
|
===================
|
|
CG_DrawMoveSpeedIcon
|
|
===================
|
|
*/
|
|
void CG_DrawMoveSpeedIcon(void) {
|
|
if ((cg.zoomMode != 0) || !(cg_drawHUD.integer)) {
|
|
return;
|
|
}
|
|
|
|
if ((cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD)) {
|
|
return;
|
|
}
|
|
|
|
if (cg.moveSpeedSelect != vr->move_speed)
|
|
{
|
|
cg.moveSpeedSelect = vr->move_speed;
|
|
cg.moveSpeedSelectTime = cg.time;
|
|
}
|
|
|
|
if (((cg.moveSpeedSelectTime+WEAPON_SELECT_TIME)>cg.time)) {
|
|
cgi_R_SetColor(colorTable[CT_WHITE]);
|
|
CG_DrawPic(96, 64, 48, 64, cgs.media.iconMoveSpeed[cg.moveSpeedSelect]);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===================
|
|
CG_DrawIconBackground
|
|
===================
|
|
*/
|
|
void CG_DrawIconBackground(void)
|
|
{
|
|
int height,xAdd,x2,y2,t;
|
|
int prongLeftX,prongRightX;
|
|
qhandle_t background;
|
|
|
|
if (( cg.zoomMode != 0 ) || !( cg_drawHUD.integer ))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((cg.snap->ps.viewEntity>0&&cg.snap->ps.viewEntity<ENTITYNUM_WORLD))
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
if (!cgi_UI_GetMenuInfo("iconbackground",&x2,&y2))
|
|
{
|
|
return;
|
|
}
|
|
|
|
prongLeftX =x2+37;
|
|
prongRightX =x2+544;
|
|
|
|
if (((cg.inventorySelectTime+WEAPON_SELECT_TIME)>cg.time) || (cgs.media.currentBackground == ICON_INVENTORY)) // Display inventory background?
|
|
{
|
|
background = cgs.media.inventoryIconBackground;
|
|
}
|
|
else if (((cg.weaponSelectTime+WEAPON_SELECT_TIME)>cg.time) || (cgs.media.currentBackground == ICON_WEAPONS)) // Display weapon background?
|
|
{
|
|
background = cgs.media.weaponIconBackground;
|
|
}
|
|
else // Display force background?
|
|
{
|
|
background = cgs.media.forceIconBackground;
|
|
}
|
|
|
|
if ((cg.iconSelectTime+WEAPON_SELECT_TIME)<cg.time) // Time is up for the HUD to display
|
|
{
|
|
if (cg.iconHUDActive) // The time is up, but we still need to move the prongs back to their original position
|
|
{
|
|
t = cg.time - (cg.iconSelectTime+WEAPON_SELECT_TIME);
|
|
cg.iconHUDPercent = t/ 130.0f;
|
|
cg.iconHUDPercent = 1 - cg.iconHUDPercent;
|
|
|
|
if (cg.iconHUDPercent<0)
|
|
{
|
|
cg.iconHUDActive = qfalse;
|
|
cg.iconHUDPercent=0;
|
|
}
|
|
|
|
xAdd = (int) 8*cg.iconHUDPercent;
|
|
|
|
height = (int) (60.0f*cg.iconHUDPercent);
|
|
CG_DrawPic( x2+60, y2+30, 460, -height, background); // Top half
|
|
CG_DrawPic( x2+60, y2+30-2,460, height, background); // Bottom half
|
|
|
|
}
|
|
else
|
|
{
|
|
xAdd = 0;
|
|
}
|
|
|
|
cgi_R_SetColor( colorTable[CT_WHITE] );
|
|
CG_DrawPic( prongLeftX+xAdd, y2-10, 40, 80, cgs.media.weaponProngsOff);
|
|
CG_DrawPic( prongRightX-xAdd, y2-10, -40, 80, cgs.media.weaponProngsOff);
|
|
|
|
return;
|
|
}
|
|
|
|
prongLeftX =x2+37;
|
|
prongRightX =x2+544;
|
|
|
|
if (!cg.iconHUDActive)
|
|
{
|
|
t = cg.time - cg.iconSelectTime;
|
|
cg.iconHUDPercent = t/ 130.0f;
|
|
|
|
// Calc how far into opening sequence we are
|
|
if (cg.iconHUDPercent>1)
|
|
{
|
|
cg.iconHUDActive = qtrue;
|
|
cg.iconHUDPercent=1;
|
|
}
|
|
else if (cg.iconHUDPercent<0)
|
|
{
|
|
cg.iconHUDPercent=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cg.iconHUDPercent=1;
|
|
}
|
|
|
|
cgi_R_SetColor( colorTable[CT_WHITE] );
|
|
height = (int) (60.0f*cg.iconHUDPercent);
|
|
CG_DrawPic( x2+60, y2+30, 460, -height, background); // Top half
|
|
CG_DrawPic( x2+60, y2+30-2,460, height, background); // Bottom half
|
|
|
|
|
|
// And now for the prongs
|
|
if ((cg.inventorySelectTime+WEAPON_SELECT_TIME)>cg.time)
|
|
{
|
|
cgs.media.currentBackground = ICON_INVENTORY;
|
|
background = cgs.media.inventoryProngsOn;
|
|
}
|
|
else if ((cg.weaponSelectTime+WEAPON_SELECT_TIME)>cg.time)
|
|
{
|
|
cgs.media.currentBackground = ICON_WEAPONS;
|
|
background = cgs.media.weaponProngsOn;
|
|
}
|
|
else
|
|
{
|
|
cgs.media.currentBackground = ICON_FORCE;
|
|
background = cgs.media.forceProngsOn;
|
|
}
|
|
|
|
|
|
// Side Prongs
|
|
cgi_R_SetColor( colorTable[CT_WHITE]);
|
|
xAdd = (int) 8*cg.iconHUDPercent;
|
|
CG_DrawPic( prongLeftX+xAdd, y2-10, 40, 80, background);
|
|
CG_DrawPic( prongRightX-xAdd, y2-10, -40, 80, background);
|
|
}
|
|
|
|
int cgi_UI_GetItemText(char *menuFile,char *itemName, char *text);
|
|
|
|
char *weaponDesc[13] =
|
|
{
|
|
"SABER_DESC",
|
|
"BLASTER_PISTOL_DESC",
|
|
"BLASTER_RIFLE_DESC",
|
|
"DISRUPTOR_RIFLE_DESC",
|
|
"BOWCASTER_DESC",
|
|
"HEAVYREPEATER_DESC",
|
|
"DEMP2_DESC",
|
|
"FLECHETTE_DESC",
|
|
"MERR_SONN_DESC",
|
|
"THERMAL_DETONATOR_DESC",
|
|
"TRIP_MINE_DESC",
|
|
"DET_PACK_DESC",
|
|
"STUN_BATON_DESC",
|
|
};
|
|
|
|
|
|
/*
|
|
===================
|
|
CG_DrawDataPadWeaponSelect
|
|
===================
|
|
*/
|
|
void CG_DrawDataPadWeaponSelect( void )
|
|
{
|
|
int i;
|
|
int bits;
|
|
int count;
|
|
int smallIconSize,bigIconSize;
|
|
int holdX,x,y,pad;
|
|
int sideLeftIconCnt,sideRightIconCnt;
|
|
int sideMax,holdCount,iconCnt;
|
|
vec4_t calcColor;
|
|
char text[1024]={0};
|
|
vec4_t textColor = { .875f, .718f, .121f, 1.0f };
|
|
|
|
// showing weapon select clears pickup item display, but not the blend blob
|
|
cg.itemPickupTime = 0;
|
|
|
|
bits = cg.snap->ps.stats[ STAT_WEAPONS ];
|
|
|
|
// count the number of weapons owned
|
|
count = 0;
|
|
for ( i = 1 ; i < 16 ; i++ )
|
|
{
|
|
if ( bits & ( 1 << i ) )
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (count == 0) // If no weapons, don't display
|
|
{
|
|
return;
|
|
}
|
|
|
|
sideMax = 3; // Max number of icons on the side
|
|
|
|
// Calculate how many icons will appear to either side of the center one
|
|
holdCount = count - 1; // -1 for the center icon
|
|
if (holdCount == 0) // No icons to either side
|
|
{
|
|
sideLeftIconCnt = 0;
|
|
sideRightIconCnt = 0;
|
|
}
|
|
else if (count > (2*sideMax)) // Go to the max on each side
|
|
{
|
|
sideLeftIconCnt = sideMax;
|
|
sideRightIconCnt = sideMax;
|
|
}
|
|
else // Less than max, so do the calc
|
|
{
|
|
sideLeftIconCnt = holdCount/2;
|
|
sideRightIconCnt = holdCount - sideLeftIconCnt;
|
|
}
|
|
|
|
// This seems to be a problem is datapad comes up too early
|
|
if (cg.DataPadWeaponSelect<FIRST_WEAPON)
|
|
{
|
|
cg.DataPadWeaponSelect = FIRST_WEAPON;
|
|
}
|
|
else if (cg.DataPadWeaponSelect>MAX_PLAYER_WEAPONS)
|
|
{
|
|
cg.DataPadWeaponSelect = MAX_PLAYER_WEAPONS;
|
|
}
|
|
|
|
i = cg.DataPadWeaponSelect - 1;
|
|
if (i<1)
|
|
{
|
|
i = 13;
|
|
}
|
|
|
|
smallIconSize = 40;
|
|
bigIconSize = 80;
|
|
pad = 8;
|
|
|
|
x = 320;
|
|
y = 300;
|
|
|
|
// Background
|
|
memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t));
|
|
calcColor[3] = .60f;
|
|
cgi_R_SetColor( calcColor);
|
|
|
|
// Left side ICONS
|
|
cgi_R_SetColor( calcColor);
|
|
// Work backwards from current icon
|
|
holdX = x - ((bigIconSize/2) + pad + smallIconSize);
|
|
//height = smallIconSize * cg.iconHUDPercent;
|
|
|
|
for (iconCnt=1;iconCnt<(sideLeftIconCnt+1);i--)
|
|
{
|
|
if (i<1)
|
|
{
|
|
i = 13;
|
|
}
|
|
|
|
if ( !(bits & ( 1 << i ))) // Does he have this weapon?
|
|
{
|
|
continue;
|
|
}
|
|
|
|
++iconCnt; // Good icon
|
|
|
|
if (weaponData[i].weaponIcon[0])
|
|
{
|
|
weaponInfo_t *weaponInfo;
|
|
CG_RegisterWeapon( i );
|
|
weaponInfo = &cg_weapons[i];
|
|
|
|
if (!CG_WeaponCheck(i))
|
|
{
|
|
CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, weaponInfo->weaponIconNoAmmo );
|
|
}
|
|
else
|
|
{
|
|
CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, weaponInfo->weaponIcon );
|
|
}
|
|
|
|
holdX -= (smallIconSize+pad);
|
|
}
|
|
}
|
|
|
|
// Current Center Icon
|
|
//height = bigIconSize * cg.iconHUDPercent;
|
|
cgi_R_SetColor(NULL);
|
|
|
|
// char buffer[256];
|
|
// cgi_UI_GetItemText("datapadWeaponsMenu",va("weapondesc%d",cg.DataPadWeaponSelect+1),buffer);
|
|
|
|
if (weaponData[cg.DataPadWeaponSelect].weaponIcon[0])
|
|
{
|
|
weaponInfo_t *weaponInfo;
|
|
CG_RegisterWeapon( cg.DataPadWeaponSelect );
|
|
weaponInfo = &cg_weapons[cg.DataPadWeaponSelect];
|
|
|
|
if (!CG_WeaponCheck(cg.DataPadWeaponSelect))
|
|
{
|
|
CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2))+10, bigIconSize, bigIconSize, weaponInfo->weaponIconNoAmmo );
|
|
}
|
|
else
|
|
{
|
|
CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2))+10, bigIconSize, bigIconSize, weaponInfo->weaponIcon );
|
|
}
|
|
}
|
|
|
|
i = cg.DataPadWeaponSelect + 1;
|
|
if (i> 13)
|
|
{
|
|
i = 1;
|
|
}
|
|
|
|
// Right side ICONS
|
|
// Work forwards from current icon
|
|
cgi_R_SetColor( calcColor);
|
|
holdX = x + (bigIconSize/2) + pad;
|
|
//height = smallIconSize * cg.iconHUDPercent;
|
|
for (iconCnt=1;iconCnt<(sideRightIconCnt+1);i++)
|
|
{
|
|
if (i>13)
|
|
{
|
|
i = 1;
|
|
}
|
|
|
|
if ( !(bits & ( 1 << i ))) // Does he have this weapon?
|
|
{
|
|
continue;
|
|
}
|
|
|
|
++iconCnt; // Good icon
|
|
|
|
if (weaponData[i].weaponIcon[0])
|
|
{
|
|
weaponInfo_t *weaponInfo;
|
|
CG_RegisterWeapon( i );
|
|
weaponInfo = &cg_weapons[i];
|
|
// No ammo for this weapon?
|
|
if (!CG_WeaponCheck(i))
|
|
{
|
|
CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, weaponInfo->weaponIconNoAmmo );
|
|
}
|
|
else
|
|
{
|
|
CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, weaponInfo->weaponIcon );
|
|
}
|
|
|
|
|
|
holdX += (smallIconSize+pad);
|
|
}
|
|
}
|
|
|
|
// draw the weapon description
|
|
x= 40;
|
|
y= 70;
|
|
|
|
cgi_SP_GetStringTextString( va("INGAME_%s",weaponDesc[cg.DataPadWeaponSelect-1]), text, sizeof(text) );
|
|
|
|
if (text[0])
|
|
{
|
|
CG_DisplayBoxedText(70,50,500,300,text,
|
|
cgs.media.qhFontSmall,
|
|
0.7f,
|
|
textColor
|
|
);
|
|
}
|
|
|
|
/* CG_DisplayBoxedText(70,50,500,300,weaponDesc[cg.DataPadWeaponSelect-1],
|
|
cgs.media.qhFontSmall,
|
|
0.7f,
|
|
colorTable[CT_WHITE]
|
|
);
|
|
*/
|
|
|
|
cgi_R_SetColor( NULL );
|
|
}
|
|
|
|
/*
|
|
===================
|
|
CG_DrawDataPadIconBackground
|
|
===================
|
|
*/
|
|
void CG_DrawDataPadIconBackground(int backgroundType)
|
|
{
|
|
int height,xAdd,x2,y2;
|
|
int prongLeftX,prongRightX;
|
|
qhandle_t background;
|
|
|
|
x2 = 0;
|
|
y2 = 295;
|
|
|
|
prongLeftX =x2+97;
|
|
prongRightX =x2+544;
|
|
|
|
if (backgroundType == ICON_INVENTORY) // Display inventory background?
|
|
{
|
|
background = cgs.media.inventoryIconBackground;
|
|
}
|
|
else if (backgroundType == ICON_WEAPONS) // Display weapon background?
|
|
{
|
|
background = cgs.media.weaponIconBackground;
|
|
}
|
|
else // Display force background?
|
|
{
|
|
background = cgs.media.forceIconBackground;
|
|
}
|
|
|
|
/* if ((cg.iconDataPadSelectTime+WEAPON_SELECT_TIME)<cg.time) // Time is up for the HUD to display
|
|
{
|
|
if (cg.iconDataPadHUDActive) // The time is up, but we still need to move the prongs back to their original position
|
|
{
|
|
t = cg.time - (cg.iconDataPadSelectTime+WEAPON_SELECT_TIME);
|
|
cg.iconDataPadHUDPercent = t/ 130.0f;
|
|
cg.iconDataPadHUDPercent = 1 - cg.iconDataPadHUDPercent;
|
|
|
|
if (cg.iconDataPadHUDPercent<0)
|
|
{
|
|
cg.iconDataPadHUDActive = qfalse;
|
|
cg.iconDataPadHUDPercent=0;
|
|
}
|
|
|
|
xAdd = (int) 8*cg.iconDataPadHUDPercent;
|
|
|
|
height = (int) (60.0f*cg.iconDataPadHUDPercent);
|
|
CG_DrawPic( x2+60, y2+30, 460, -height, background); // Top half
|
|
CG_DrawPic( x2+60, y2+30-2,460, height, background); // Bottom half
|
|
|
|
}
|
|
else
|
|
{
|
|
xAdd = 0;
|
|
}
|
|
|
|
cgi_R_SetColor( colorTable[CT_WHITE] );
|
|
CG_DrawPic( prongLeftX+xAdd, y2-10, 40, 80, cgs.media.weaponProngsOff);
|
|
CG_DrawPic( prongRightX-xAdd, y2-10, -40, 80, cgs.media.weaponProngsOff);
|
|
|
|
return;
|
|
}
|
|
*/
|
|
|
|
prongLeftX =x2+97;
|
|
prongRightX =x2+544;
|
|
/*
|
|
if (!cg.iconDataPadHUDActive)
|
|
{
|
|
t = cg.time - cg.iconDataPadSelectTime;
|
|
cg.iconDataPadHUDPercent = t/ 130.0f;
|
|
|
|
// Calc how far into opening sequence we are
|
|
if (cg.iconDataPadHUDPercent>1)
|
|
{
|
|
cg.iconDataPadHUDActive = qtrue;
|
|
cg.iconDataPadHUDPercent=1;
|
|
}
|
|
else if (cg.iconDataPadHUDPercent<0)
|
|
{
|
|
cg.iconDataPadHUDPercent=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cg.iconDataPadHUDPercent=1;
|
|
}
|
|
*/
|
|
cgi_R_SetColor( colorTable[CT_WHITE] );
|
|
// height = (int) (60.0f*cg.iconDataPadHUDPercent);
|
|
height = (int) 60.0f;
|
|
CG_DrawPic( x2+110, y2+30, 410, -height, background); // Top half
|
|
CG_DrawPic( x2+110, y2+30-2,410, height, background); // Bottom half
|
|
|
|
// And now for the prongs
|
|
if (backgroundType==ICON_INVENTORY)
|
|
{
|
|
cgs.media.currentDataPadIconBackground = ICON_INVENTORY;
|
|
background = cgs.media.inventoryProngsOn;
|
|
}
|
|
else if (backgroundType==ICON_WEAPONS)
|
|
{
|
|
cgs.media.currentDataPadIconBackground = ICON_WEAPONS;
|
|
background = cgs.media.weaponProngsOn;
|
|
}
|
|
else
|
|
{
|
|
cgs.media.currentDataPadIconBackground = ICON_FORCE;
|
|
background = cgs.media.forceProngsOn;
|
|
}
|
|
|
|
// Side Prongs
|
|
cgi_R_SetColor( colorTable[CT_WHITE]);
|
|
// xAdd = (int) 8*cg.iconDataPadHUDPercent;
|
|
xAdd = (int) 8;
|
|
CG_DrawPic( prongLeftX+xAdd, y2-10, 40, 80, background);
|
|
CG_DrawPic( prongRightX-xAdd, y2-10, -40, 80, background);
|
|
}
|
|
|
|
/*
|
|
===============
|
|
SetWeaponSelectTime
|
|
===============
|
|
*/
|
|
void SetWeaponSelectTime(void)
|
|
{
|
|
|
|
if (((cg.inventorySelectTime + WEAPON_SELECT_TIME) > cg.time) || // The Inventory HUD was currently active to just swap it out with Force HUD
|
|
((cg.forcepowerSelectTime + WEAPON_SELECT_TIME) > cg.time)) // The Force HUD was currently active to just swap it out with Force HUD
|
|
{
|
|
cg.inventorySelectTime = 0;
|
|
cg.forcepowerSelectTime = 0;
|
|
cg.weaponSelectTime = cg.time + 130.0f;
|
|
}
|
|
else
|
|
{
|
|
cg.weaponSelectTime = cg.time;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===================
|
|
CG_DrawWeaponSelect
|
|
===================
|
|
*/
|
|
void CG_DrawWeaponSelect( void )
|
|
{
|
|
int i;
|
|
int bits;
|
|
int count;
|
|
int smallIconSize,bigIconSize;
|
|
int holdX,x,y,x2,y2,pad;
|
|
int sideLeftIconCnt,sideRightIconCnt;
|
|
int sideMax,holdCount,iconCnt;
|
|
//int height;
|
|
vec4_t calcColor;
|
|
vec4_t textColor = { .875f, .718f, .121f, 1.0f };
|
|
|
|
if (!cgi_UI_GetMenuInfo("weaponselecthud",&x2,&y2))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((cg.weaponSelectTime+WEAPON_SELECT_TIME)<cg.time) // Time is up for the HUD to display
|
|
{
|
|
return;
|
|
}
|
|
|
|
// don't display if dead
|
|
if ( cg.predicted_player_state.stats[STAT_HEALTH] <= 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
cg.iconSelectTime = cg.weaponSelectTime;
|
|
|
|
// showing weapon select clears pickup item display, but not the blend blob
|
|
//cg.itemPickupTime = 0;
|
|
|
|
bits = cg.snap->ps.stats[ STAT_WEAPONS ];
|
|
|
|
// count the number of weapons owned
|
|
count = 0;
|
|
for ( i = 1 ; i < 16 ; i++ )
|
|
{
|
|
if ( bits & ( 1 << i ) )
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (count == 0) // If no weapons, don't display
|
|
{
|
|
return;
|
|
}
|
|
|
|
sideMax = 3; // Max number of icons on the side
|
|
|
|
// Calculate how many icons will appear to either side of the center one
|
|
holdCount = count - 1; // -1 for the center icon
|
|
if (holdCount == 0) // No icons to either side
|
|
{
|
|
sideLeftIconCnt = 0;
|
|
sideRightIconCnt = 0;
|
|
}
|
|
else if (count > (2*sideMax)) // Go to the max on each side
|
|
{
|
|
sideLeftIconCnt = sideMax;
|
|
sideRightIconCnt = sideMax;
|
|
}
|
|
else // Less than max, so do the calc
|
|
{
|
|
sideLeftIconCnt = holdCount/2;
|
|
sideRightIconCnt = holdCount - sideLeftIconCnt;
|
|
}
|
|
|
|
i = cg.weaponSelect - 1;
|
|
if (i<1)
|
|
{
|
|
i = 13;
|
|
}
|
|
|
|
smallIconSize = 40;
|
|
bigIconSize = 80;
|
|
pad = 12;
|
|
|
|
x = 320;
|
|
y = 410;
|
|
|
|
// Background
|
|
memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t));
|
|
calcColor[3] = .60f;
|
|
cgi_R_SetColor( calcColor);
|
|
|
|
// Left side ICONS
|
|
cgi_R_SetColor( calcColor);
|
|
// Work backwards from current icon
|
|
holdX = x - ((bigIconSize/2) + pad + smallIconSize);
|
|
//height = smallIconSize * cg.iconHUDPercent;
|
|
|
|
for (iconCnt=1;iconCnt<(sideLeftIconCnt+1);i--)
|
|
{
|
|
if (i<1)
|
|
{
|
|
i = 13;
|
|
}
|
|
|
|
if ( !(bits & ( 1 << i ))) // Does he have this weapon?
|
|
{
|
|
continue;
|
|
}
|
|
|
|
++iconCnt; // Good icon
|
|
|
|
if (weaponData[i].weaponIcon[0])
|
|
{
|
|
weaponInfo_t *weaponInfo;
|
|
CG_RegisterWeapon( i );
|
|
weaponInfo = &cg_weapons[i];
|
|
|
|
if (!CG_WeaponCheck(i))
|
|
{
|
|
CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, weaponInfo->weaponIconNoAmmo );
|
|
}
|
|
else
|
|
{
|
|
CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, weaponInfo->weaponIcon );
|
|
}
|
|
|
|
holdX -= (smallIconSize+pad);
|
|
}
|
|
}
|
|
|
|
// Current Center Icon
|
|
//height = bigIconSize * cg.iconHUDPercent;
|
|
cgi_R_SetColor(NULL);
|
|
if (weaponData[cg.weaponSelect].weaponIcon[0])
|
|
{
|
|
weaponInfo_t *weaponInfo;
|
|
CG_RegisterWeapon( cg.weaponSelect );
|
|
weaponInfo = &cg_weapons[cg.weaponSelect];
|
|
|
|
if (!CG_WeaponCheck(cg.weaponSelect))
|
|
{
|
|
CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2))+10, bigIconSize, bigIconSize, weaponInfo->weaponIconNoAmmo );
|
|
}
|
|
else
|
|
{
|
|
CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2))+10, bigIconSize, bigIconSize, weaponInfo->weaponIcon );
|
|
}
|
|
}
|
|
|
|
i = cg.weaponSelect + 1;
|
|
if (i> 13)
|
|
{
|
|
i = 1;
|
|
}
|
|
|
|
// Right side ICONS
|
|
// Work forwards from current icon
|
|
cgi_R_SetColor( calcColor);
|
|
holdX = x + (bigIconSize/2) + pad;
|
|
//height = smallIconSize * cg.iconHUDPercent;
|
|
for (iconCnt=1;iconCnt<(sideRightIconCnt+1);i++)
|
|
{
|
|
if (i>13)
|
|
{
|
|
i = 1;
|
|
}
|
|
|
|
if ( !(bits & ( 1 << i ))) // Does he have this weapon?
|
|
{
|
|
continue;
|
|
}
|
|
|
|
++iconCnt; // Good icon
|
|
|
|
if (weaponData[i].weaponIcon[0])
|
|
{
|
|
weaponInfo_t *weaponInfo;
|
|
CG_RegisterWeapon( i );
|
|
weaponInfo = &cg_weapons[i];
|
|
// No ammo for this weapon?
|
|
if (!CG_WeaponCheck(i))
|
|
{
|
|
CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, weaponInfo->weaponIconNoAmmo );
|
|
}
|
|
else
|
|
{
|
|
CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, weaponInfo->weaponIcon );
|
|
}
|
|
|
|
|
|
holdX += (smallIconSize+pad);
|
|
}
|
|
}
|
|
|
|
gitem_t *item = cg_weapons[ cg.weaponSelect ].item;
|
|
|
|
// draw the selected name
|
|
if ( item && item->classname && item->classname[0] )
|
|
{
|
|
char text[1024];
|
|
|
|
if ( cgi_SP_GetStringTextString( va("INGAME_%s",item->classname), text, sizeof( text )))
|
|
{
|
|
int w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 1.0f);
|
|
int x = ( SCREEN_WIDTH - w ) / 2;
|
|
int y = (SCREEN_HEIGHT - 24);
|
|
CG_AdjustFrom640Int(&x, &y, NULL, NULL);
|
|
cgi_R_Font_DrawString(x, y, text, textColor, cgs.media.qhFontSmall, -1, FONT_SCALE);
|
|
}
|
|
}
|
|
|
|
cgi_R_SetColor( NULL );
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
CG_WeaponSelectable
|
|
===============
|
|
*/
|
|
qboolean CG_WeaponSelectable( int i, int original, qboolean dpMode )
|
|
{
|
|
int usage_for_weap;
|
|
|
|
if (i > MAX_PLAYER_WEAPONS)
|
|
{
|
|
#ifndef FINAL_BUILD
|
|
Com_Printf("CG_WeaponSelectable() passed illegal index of %d!\n",i);
|
|
#endif
|
|
return qfalse;
|
|
}
|
|
|
|
if ( cg.weaponSelectTime + 200 > cg.time )
|
|
{//TEMP standard weapon cycle debounce for E3 because G2 can't keep up with fast weapon changes
|
|
return qfalse;
|
|
}
|
|
|
|
//FIXME: this doesn't work below, can still cycle too fast!
|
|
if ( original == WP_SABER && cg.weaponSelectTime + 500 > cg.time )
|
|
{//when sqitch to lightsaber, have to stay there for at least half a second!
|
|
return qfalse;
|
|
}
|
|
|
|
if (( weaponData[i].ammoIndex != AMMO_NONE ) && !dpMode )
|
|
{//weapon uses ammo, see if we have any
|
|
usage_for_weap = weaponData[i].energyPerShot < weaponData[i].altEnergyPerShot
|
|
? weaponData[i].energyPerShot
|
|
: weaponData[i].altEnergyPerShot;
|
|
|
|
if ( cg.snap->ps.ammo[weaponData[i].ammoIndex] - usage_for_weap < 0 )
|
|
{
|
|
if ( i != WP_DET_PACK ) // detpack can be switched to...should possibly check if there are any stuck to a wall somewhere?
|
|
{
|
|
// This weapon doesn't have enough ammo to shoot either the main or the alt-fire
|
|
return qfalse;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(cg.snap->ps.stats[ STAT_WEAPONS ] & ( 1 << i )))
|
|
{
|
|
// Don't have this weapon to start with.
|
|
return qfalse;
|
|
}
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
void CG_ToggleATSTWeapon( void )
|
|
{
|
|
if ( cg.weaponSelect == WP_ATST_MAIN )
|
|
{
|
|
cg.weaponSelect = WP_ATST_SIDE;
|
|
}
|
|
else
|
|
{
|
|
cg.weaponSelect = WP_ATST_MAIN;
|
|
}
|
|
// cg.weaponSelectTime = cg.time;
|
|
SetWeaponSelectTime();
|
|
}
|
|
|
|
void CG_PlayerLockedWeaponSpeech( int jumping )
|
|
{
|
|
extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType );
|
|
static int speechDebounceTime = 0;
|
|
if ( !in_camera )
|
|
{//not in a cinematic
|
|
if ( speechDebounceTime < cg.time )
|
|
{//spoke more than 3 seconds ago
|
|
if ( !Q3_TaskIDPending( &g_entities[0], TID_CHAN_VOICE ) )
|
|
{//not waiting on a scripted sound to finish
|
|
if( !jumping )
|
|
{
|
|
if( Q_flrand(0.0f, 1.0f) > 0.5 )
|
|
{
|
|
G_SoundOnEnt( player, CHAN_VOICE, va( "sound/chars/kyle/09kyk015.wav" ));
|
|
}
|
|
else
|
|
{
|
|
G_SoundOnEnt( player, CHAN_VOICE, va( "sound/chars/kyle/09kyk016.wav" ));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
G_SoundOnEnt( player, CHAN_VOICE, va( "sound/chars/kyle/16kyk007.wav" ));
|
|
}
|
|
speechDebounceTime = cg.time + 3000;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
===============
|
|
CG_NextWeapon_f
|
|
===============
|
|
*/
|
|
void CG_NextWeapon_f( void ) {
|
|
int i;
|
|
int original;
|
|
|
|
if ( !cg.snap ) {
|
|
return;
|
|
}
|
|
/*
|
|
if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
|
|
return;
|
|
}
|
|
*/
|
|
|
|
if( g_entities[0].flags & FL_LOCK_PLAYER_WEAPONS )
|
|
{
|
|
CG_PlayerLockedWeaponSpeech( qfalse );
|
|
return;
|
|
}
|
|
|
|
if( g_entities[0].client && g_entities[0].client->NPC_class == CLASS_ATST )
|
|
{
|
|
CG_ToggleATSTWeapon();
|
|
return;
|
|
}
|
|
|
|
if ( cg.snap->ps.eFlags & EF_LOCKED_TO_WEAPON )
|
|
{
|
|
// can't do any sort of weapon switching when in the emplaced gun
|
|
return;
|
|
}
|
|
|
|
if ( cg.snap->ps.viewEntity )
|
|
{
|
|
// yeah, probably need a better check here
|
|
if ( g_entities[cg.snap->ps.viewEntity].client && ( g_entities[cg.snap->ps.viewEntity].client->NPC_class == CLASS_R5D2
|
|
|| g_entities[cg.snap->ps.viewEntity].client->NPC_class == CLASS_R2D2
|
|
|| g_entities[cg.snap->ps.viewEntity].client->NPC_class == CLASS_MOUSE ))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
original = cg.weaponSelect;
|
|
|
|
for ( i = 0 ; i <= MAX_PLAYER_WEAPONS ; i++ )
|
|
{
|
|
cg.weaponSelect++;
|
|
|
|
if ( cg.weaponSelect < FIRST_WEAPON || cg.weaponSelect > MAX_PLAYER_WEAPONS) {
|
|
cg.weaponSelect = FIRST_WEAPON;
|
|
}
|
|
|
|
if ( CG_WeaponSelectable( cg.weaponSelect, original, qfalse ) )
|
|
{
|
|
// cg.weaponSelectTime = cg.time;
|
|
SetWeaponSelectTime();
|
|
return;
|
|
}
|
|
}
|
|
|
|
cg.weaponSelect = original;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CG_DPNextWeapon_f
|
|
===============
|
|
*/
|
|
void CG_DPNextWeapon_f( void ) {
|
|
int i;
|
|
int original;
|
|
|
|
if ( !cg.snap ) {
|
|
return;
|
|
}
|
|
/*
|
|
if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
|
|
return;
|
|
}
|
|
*/
|
|
|
|
original = cg.DataPadWeaponSelect;
|
|
|
|
for ( i = 0 ; i <= MAX_PLAYER_WEAPONS ; i++ )
|
|
{
|
|
cg.DataPadWeaponSelect++;
|
|
|
|
if ( cg.DataPadWeaponSelect < FIRST_WEAPON || cg.DataPadWeaponSelect > MAX_PLAYER_WEAPONS) {
|
|
cg.DataPadWeaponSelect = FIRST_WEAPON;
|
|
}
|
|
|
|
if ( CG_WeaponSelectable( cg.DataPadWeaponSelect, original, qtrue ) )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
cg.DataPadWeaponSelect = original;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CG_DPPrevWeapon_f
|
|
===============
|
|
*/
|
|
void CG_DPPrevWeapon_f( void )
|
|
{
|
|
int i;
|
|
int original;
|
|
|
|
if ( !cg.snap )
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
if ( cg.snap->ps.pm_flags & PMF_FOLLOW )
|
|
{
|
|
return;
|
|
}
|
|
*/
|
|
|
|
original = cg.DataPadWeaponSelect;
|
|
|
|
for ( i = 0 ; i <= MAX_PLAYER_WEAPONS ; i++ )
|
|
{
|
|
cg.DataPadWeaponSelect--;
|
|
if ( cg.DataPadWeaponSelect < FIRST_WEAPON || cg.DataPadWeaponSelect > MAX_PLAYER_WEAPONS)
|
|
{
|
|
cg.DataPadWeaponSelect = MAX_PLAYER_WEAPONS;
|
|
}
|
|
|
|
if ( CG_WeaponSelectable( cg.DataPadWeaponSelect, original, qtrue ) )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
cg.DataPadWeaponSelect = original;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CG_PrevWeapon_f
|
|
===============
|
|
*/
|
|
void CG_PrevWeapon_f( void ) {
|
|
int i;
|
|
int original;
|
|
|
|
if ( !cg.snap ) {
|
|
return;
|
|
}
|
|
/*
|
|
if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
|
|
return;
|
|
}
|
|
*/
|
|
|
|
if( g_entities[0].flags & FL_LOCK_PLAYER_WEAPONS )
|
|
{
|
|
CG_PlayerLockedWeaponSpeech( qfalse );
|
|
return;
|
|
}
|
|
|
|
if( g_entities[0].client && g_entities[0].client->NPC_class == CLASS_ATST )
|
|
{
|
|
CG_ToggleATSTWeapon();
|
|
return;
|
|
}
|
|
|
|
if ( cg.snap->ps.eFlags & EF_LOCKED_TO_WEAPON )
|
|
{
|
|
// can't do any sort of weapon switching when in the emplaced gun
|
|
return;
|
|
}
|
|
|
|
if ( cg.snap->ps.viewEntity )
|
|
{
|
|
// yeah, probably need a better check here
|
|
if ( g_entities[cg.snap->ps.viewEntity].client && ( g_entities[cg.snap->ps.viewEntity].client->NPC_class == CLASS_R5D2
|
|
|| g_entities[cg.snap->ps.viewEntity].client->NPC_class == CLASS_R2D2
|
|
|| g_entities[cg.snap->ps.viewEntity].client->NPC_class == CLASS_MOUSE ))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
original = cg.weaponSelect;
|
|
|
|
for ( i = 0 ; i <= MAX_PLAYER_WEAPONS ; i++ ) {
|
|
cg.weaponSelect--;
|
|
if ( cg.weaponSelect < FIRST_WEAPON || cg.weaponSelect > MAX_PLAYER_WEAPONS) {
|
|
cg.weaponSelect = MAX_PLAYER_WEAPONS;
|
|
}
|
|
|
|
if ( CG_WeaponSelectable( cg.weaponSelect, original, qfalse ) )
|
|
{
|
|
SetWeaponSelectTime();
|
|
// cg.weaponSelectTime = cg.time;
|
|
return;
|
|
}
|
|
}
|
|
|
|
cg.weaponSelect = original;
|
|
}
|
|
|
|
/*
|
|
void CG_ChangeWeapon( int num )
|
|
|
|
Meant to be called from the normal game, so checks the game-side weapon inventory data
|
|
*/
|
|
void CG_ChangeWeapon( int num )
|
|
{
|
|
gentity_t *player = &g_entities[0];
|
|
|
|
if ( num < WP_NONE || num >= WP_NUM_WEAPONS )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( player->flags & FL_LOCK_PLAYER_WEAPONS )
|
|
{
|
|
CG_PlayerLockedWeaponSpeech( qfalse );
|
|
return;
|
|
}
|
|
|
|
if ( player->client != NULL && !(player->client->ps.stats[STAT_WEAPONS] & ( 1 << num )) )
|
|
{
|
|
return; // don't have the weapon
|
|
}
|
|
|
|
// because we don't have an empty hand model for the thermal, don't allow selecting that weapon if it has no ammo
|
|
if ( num == WP_THERMAL )
|
|
{
|
|
if ( cg.snap->ps.ammo[AMMO_THERMAL] <= 0 )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
// because we don't have an empty hand model for the thermal, don't allow selecting that weapon if it has no ammo
|
|
if ( num == WP_TRIP_MINE )
|
|
{
|
|
if ( cg.snap->ps.ammo[AMMO_TRIPMINE] <= 0 )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
SetWeaponSelectTime();
|
|
// cg.weaponSelectTime = cg.time;
|
|
cg.weaponSelect = num;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
CG_Weapon_f
|
|
===============
|
|
*/
|
|
void CG_Weapon_f( void )
|
|
{
|
|
int num;
|
|
|
|
if ( cg.weaponSelectTime + 200 > cg.time )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( !cg.snap ) {
|
|
return;
|
|
}
|
|
/*
|
|
if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) {
|
|
return;
|
|
}
|
|
*/
|
|
|
|
if( g_entities[0].flags & FL_LOCK_PLAYER_WEAPONS )
|
|
{
|
|
CG_PlayerLockedWeaponSpeech( qfalse );
|
|
return;
|
|
}
|
|
|
|
if( g_entities[0].client && g_entities[0].client->NPC_class == CLASS_ATST )
|
|
{
|
|
CG_ToggleATSTWeapon();
|
|
return;
|
|
}
|
|
|
|
if ( cg.snap->ps.eFlags & EF_LOCKED_TO_WEAPON )
|
|
{
|
|
// can't do any sort of weapon switching when in the emplaced gun
|
|
return;
|
|
}
|
|
|
|
if ( cg.snap->ps.viewEntity )
|
|
{
|
|
// yeah, probably need a better check here
|
|
if ( g_entities[cg.snap->ps.viewEntity].client && ( g_entities[cg.snap->ps.viewEntity].client->NPC_class == CLASS_R5D2
|
|
|| g_entities[cg.snap->ps.viewEntity].client->NPC_class == CLASS_R2D2
|
|
|| g_entities[cg.snap->ps.viewEntity].client->NPC_class == CLASS_MOUSE ))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
num = atoi( CG_Argv( 1 ) );
|
|
|
|
if ( num < WP_NONE || num >= WP_NUM_WEAPONS ) {
|
|
return;
|
|
}
|
|
|
|
if ( num == WP_SABER )
|
|
{//lightsaber
|
|
if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) )
|
|
{//don't have saber, try stun baton
|
|
num = WP_STUN_BATON;
|
|
}
|
|
else if ( num == cg.snap->ps.weapon )
|
|
{//already have it up, let's try to toggle it
|
|
if ( !in_camera )
|
|
{//player can't activate/deactivate saber when in a cinematic
|
|
//can't toggle it if not holding it and not controlling it or dead
|
|
if ( cg.predicted_player_state.stats[STAT_HEALTH] > 0 && (!cg_entities[0].currentState.saberInFlight || (&g_entities[cg_entities[0].gent->client->ps.saberEntityNum] != NULL && g_entities[cg_entities[0].gent->client->ps.saberEntityNum].s.pos.trType == TR_LINEAR) ) )
|
|
{//it's either in-hand or it's under telekinetic control
|
|
if ( cg_entities[0].currentState.saberActive )
|
|
{
|
|
cg_entities[0].gent->client->ps.saberActive = qfalse;
|
|
if ( cg_entities[0].currentState.saberInFlight )
|
|
{//play it on the saber
|
|
cgi_S_UpdateEntityPosition( cg_entities[0].gent->client->ps.saberEntityNum, g_entities[cg_entities[0].gent->client->ps.saberEntityNum].currentOrigin );
|
|
cgi_S_StartSound (NULL, cg_entities[0].gent->client->ps.saberEntityNum, CHAN_AUTO, cgi_S_RegisterSound( "sound/weapons/saber/saberoff.wav" ) );
|
|
}
|
|
else
|
|
{
|
|
cgi_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgi_S_RegisterSound( "sound/weapons/saber/saberoff.wav" ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cg_entities[0].gent->client->ps.saberActive = qtrue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( num >= WP_THERMAL && num <= WP_DET_PACK ) // these weapons cycle
|
|
{
|
|
int weap, i = 0;
|
|
|
|
if ( cg.snap->ps.weapon >= WP_THERMAL && cg.snap->ps.weapon <= WP_DET_PACK )
|
|
{
|
|
// already in cycle range so start with next cycle item
|
|
weap = cg.snap->ps.weapon + 1;
|
|
}
|
|
else
|
|
{
|
|
// not in cycle range, so start with thermal detonator
|
|
weap = WP_THERMAL;
|
|
}
|
|
|
|
// prevent an endless loop
|
|
while ( i <= 4 )
|
|
{
|
|
if ( weap > WP_DET_PACK )
|
|
{
|
|
weap = WP_THERMAL;
|
|
}
|
|
|
|
if ( cg.snap->ps.ammo[weaponData[weap].ammoIndex] > 0 || weap == WP_DET_PACK )
|
|
{
|
|
if ( CG_WeaponSelectable( weap, cg.snap->ps.weapon, qfalse ) )
|
|
{
|
|
num = weap;
|
|
break;
|
|
}
|
|
}
|
|
|
|
weap++;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) {
|
|
return; // don't have the weapon
|
|
}
|
|
|
|
SetWeaponSelectTime();
|
|
// cg.weaponSelectTime = cg.time;
|
|
cg.weaponSelect = num;
|
|
}
|
|
|
|
|
|
void Cmd_UseInventory_f(gentity_t *ent);
|
|
|
|
extern float cg_zoomFov; //from cg_view.cpp
|
|
|
|
void CG_ExitScope_f( )
|
|
{
|
|
if ( cg.zoomMode )
|
|
{
|
|
G_SoundOnEnt( pm->gent, CHAN_AUTO, "sound/weapons/disruptor/zoomend.wav" );
|
|
// already zooming, so must be wanting to turn it off
|
|
cg.zoomMode = 0;
|
|
cg.zoomTime = cg.time;
|
|
cg.zoomLocked = qfalse;
|
|
}
|
|
}
|
|
|
|
void CG_EnterScope_f( )
|
|
{
|
|
if ( cg.zoomMode == 0 || cg.zoomMode == 3 )
|
|
{
|
|
G_SoundOnEnt( pm->gent, CHAN_AUTO, "sound/weapons/disruptor/zoomstart.wav" );
|
|
// not already zooming, so do it now
|
|
if (cg.weaponSelect == WP_DISRUPTOR) {
|
|
cg.zoomMode = 2;
|
|
cg_zoomFov = 80.0f;
|
|
cg.zoomLocked = qfalse;
|
|
} else {
|
|
//Our specially created E11 Blaster scope
|
|
cg.zoomMode = 4;
|
|
cg_zoomFov = 30.0f;
|
|
cg.zoomLocked = qtrue;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CG_ToggleSaber_f( )
|
|
{
|
|
player->client->ps.saberActive = (qboolean)!player->client->ps.saberActive;
|
|
if (!player->client->ps.saberActive)
|
|
{
|
|
G_SoundOnEnt( player, CHAN_WEAPON, "sound/weapons/saber/saberoff.wav" );
|
|
}
|
|
}
|
|
|
|
//Selects the currently selected thing (if one _is_ selected)
|
|
void CG_ItemSelectorSelect_f( void )
|
|
{
|
|
cg.itemSelectorTime = 0;
|
|
cgi_Cvar_Set("timescale", "1.0");
|
|
|
|
if (cg.itemSelectorSelection == ST_NONE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (cg.itemSelectorType == ST_WEAPON) // weapons
|
|
{
|
|
if (cg.weaponSelect == cg.itemSelectorSelection)
|
|
{
|
|
return;
|
|
}
|
|
|
|
cg.weaponSelectTime = cg.time;
|
|
cg.weaponSelect = cg.itemSelectorSelection;
|
|
}
|
|
else if (cg.itemSelectorType == ST_GADGET) // gadgets
|
|
{
|
|
cg.inventorySelectTime = cg.time;
|
|
cg.inventorySelect = cg.itemSelectorSelection;
|
|
|
|
//Immediately use the selected inventory item
|
|
if (player)
|
|
{
|
|
Cmd_UseInventory_f(player);
|
|
}
|
|
}
|
|
else if (cg.itemSelectorType == ST_FIGHTING_STYLE) //fighting style
|
|
{
|
|
cgi_SendConsoleCommand(va( "setSaberLevel %i\n", cg.itemSelectorSelection + 1));
|
|
}
|
|
else if (cg.itemSelectorType == ST_FORCE_POWER)
|
|
{
|
|
if (cg.forcepowerSelect == cg.itemSelectorSelection)
|
|
{
|
|
return;
|
|
}
|
|
|
|
cg.forcepowerSelectTime = cg.time;
|
|
cg.forcepowerSelect = cg.itemSelectorSelection;
|
|
}
|
|
else if (cg.itemSelectorType == ST_QUICK_SAVE) {
|
|
if (cg.itemSelectorSelection == 0) {
|
|
cgi_SendConsoleCommand("save quik*\n");
|
|
CG_CenterPrint("Quick Saved", 240);
|
|
} else {
|
|
cgi_SendConsoleCommand("load quik\n");
|
|
}
|
|
}
|
|
|
|
//reset ready for next time
|
|
cg.itemSelectorSelection = ST_NONE;
|
|
}
|
|
|
|
void CG_ItemSelectorNext_f( void )
|
|
{
|
|
if (cg.itemSelectorType >= ST_FORCE_POWER)
|
|
{
|
|
cg.itemSelectorType = (cg.itemSelectorType == ST_FORCE_POWER) ? ST_QUICK_SAVE : ST_FORCE_POWER;
|
|
return;
|
|
}
|
|
|
|
centity_t *cent = &cg_entities[cg.snap->ps.clientNum];
|
|
|
|
//Only show the stance selection if using saber and in third person
|
|
int selectors = ((cent->gent->client->ps.forcePowersKnown & ( 1 << FP_SABER_OFFENSE )) &&
|
|
cent->currentState.weapon == WP_SABER && cg_thirdPerson.integer) ? 3 : 2;
|
|
cg.itemSelectorType = (cg.itemSelectorType+1) % selectors;
|
|
cg.itemSelectorTime = cg.time;
|
|
}
|
|
|
|
void CG_ItemSelectorPrev_f( void )
|
|
{
|
|
if (cg.itemSelectorType >= ST_FORCE_POWER)
|
|
{
|
|
cg.itemSelectorType = (cg.itemSelectorType == ST_FORCE_POWER) ? ST_QUICK_SAVE : ST_FORCE_POWER;
|
|
return;
|
|
}
|
|
|
|
centity_t *cent = &cg_entities[cg.snap->ps.clientNum];
|
|
|
|
//Only show the stance selection if using saber and in third person
|
|
int selectors = ((cent->gent->client->ps.forcePowersKnown & ( 1 << FP_SABER_OFFENSE )) &&
|
|
cent->currentState.weapon == WP_SABER && cg_thirdPerson.integer) ? 3 : 2;
|
|
if (--cg.itemSelectorType < 0)
|
|
cg.itemSelectorType = selectors-1;
|
|
cg.itemSelectorTime = cg.time;
|
|
}
|
|
|
|
extern int force_icons[NUM_FORCE_POWERS];
|
|
extern int inv_icons[INV_MAX];
|
|
qboolean CG_InventorySelectable( int index);
|
|
qboolean ForcePower_Valid(int index);
|
|
|
|
void CG_DrawItemSelector( void )
|
|
{
|
|
if (cg.predicted_player_state.stats[STAT_HEALTH] <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (cg.itemSelectorTime == 0)
|
|
{
|
|
cg.itemSelectorTime = cg.time;
|
|
|
|
if (vr->item_selector == 2)
|
|
{
|
|
cg.itemSelectorType = ST_FORCE_POWER;
|
|
VectorCopy(vr->offhandposition[0], cg.itemSelectorOrigin);
|
|
VectorCopy(vr->offhandoffset, cg.itemSelectorOffset);
|
|
}
|
|
else {
|
|
cg.itemSelectorType = ST_WEAPON;
|
|
VectorCopy(vr->weaponposition, cg.itemSelectorOrigin);
|
|
VectorCopy(vr->weaponoffset, cg.itemSelectorOffset);
|
|
}
|
|
}
|
|
|
|
float dist = 10.0f;
|
|
float radius = 4.4f;
|
|
float scale = 0.05f;
|
|
|
|
float frac = (cg.time - cg.itemSelectorTime) / 20.0f;
|
|
if (frac > 1.0f)
|
|
{
|
|
frac = 1.0f;
|
|
}
|
|
cgi_Cvar_Set("timescale", "0.22");
|
|
|
|
vec3_t controllerOrigin, controllerAngles, controllerOffset, selectorOrigin;
|
|
if (cg.itemSelectorType >= ST_FORCE_POWER)
|
|
{
|
|
BG_CalculateVROffHandPosition(controllerOrigin, controllerAngles);
|
|
VectorSubtract(vr->offhandposition[0], cg.itemSelectorOrigin, controllerOffset);
|
|
}
|
|
else
|
|
{
|
|
BG_CalculateVRWeaponPosition(controllerOrigin, controllerAngles);
|
|
VectorSubtract(vr->weaponposition, cg.itemSelectorOrigin, controllerOffset);
|
|
}
|
|
|
|
vec3_t wheelAngles, wheelOrigin, beamOrigin, wheelForward, wheelRight, wheelUp;
|
|
vec3_t angles;
|
|
VectorClear(angles);
|
|
angles[YAW] = vr->hmdorientation[YAW];
|
|
BG_CalculateVRPositionInWorld(cg.itemSelectorOrigin, cg.itemSelectorOffset, angles, wheelOrigin, wheelAngles);
|
|
|
|
AngleVectors(wheelAngles, wheelForward, wheelRight, wheelUp);
|
|
VectorCopy(controllerOrigin, wheelOrigin);
|
|
|
|
VectorCopy(wheelOrigin, beamOrigin);
|
|
VectorMA(wheelOrigin, (dist * frac), wheelForward, wheelOrigin);
|
|
VectorCopy(wheelOrigin, selectorOrigin);
|
|
|
|
vec3_t pos;
|
|
memset(&pos, 0, sizeof pos);
|
|
{
|
|
pos[0] = (sinf(DEG2RAD(wheelAngles[YAW] - controllerAngles[YAW])) / sinf(DEG2RAD(22.5f)));
|
|
pos[1] = ((wheelAngles[PITCH] - controllerAngles[PITCH]) / 22.5f);
|
|
|
|
float len = VectorLength(pos);
|
|
if (len > 1.0f)
|
|
{
|
|
pos[0] *= (1.0f / len);
|
|
pos[1] *= (1.0f / len);
|
|
}
|
|
}
|
|
|
|
VectorMA(selectorOrigin, radius * pos[0], wheelRight, selectorOrigin);
|
|
VectorMA(selectorOrigin, radius * pos[1], wheelUp, selectorOrigin);
|
|
|
|
centity_t *cent = &cg_entities[cg.snap->ps.clientNum];
|
|
|
|
refEntity_t beam;
|
|
beam.shaderRGBA[3] = 0xff;
|
|
int count;
|
|
switch (cg.itemSelectorType)
|
|
{
|
|
case ST_WEAPON: //weapons
|
|
if (vr->in_vehicle)
|
|
count = 2;
|
|
else
|
|
count = WP_MELEE;
|
|
beam.shaderRGBA[0] = 0xff;
|
|
beam.shaderRGBA[1] = 0xae;
|
|
beam.shaderRGBA[2] = 0x40;
|
|
break;
|
|
case ST_GADGET: //gadgets
|
|
count = INV_GOODIE_KEY;
|
|
beam.shaderRGBA[0] = 0x00;
|
|
beam.shaderRGBA[1] = 0xff;
|
|
beam.shaderRGBA[2] = 0x00;
|
|
break;
|
|
case ST_FIGHTING_STYLE: //fighting style
|
|
count = 3;
|
|
beam.shaderRGBA[0] = 0xff;
|
|
beam.shaderRGBA[1] = 0xff;
|
|
beam.shaderRGBA[2] = 0xff;
|
|
break;
|
|
case ST_FORCE_POWER: // force powers
|
|
count = MAX_SHOWPOWERS;
|
|
beam.shaderRGBA[0] = 0x00;
|
|
beam.shaderRGBA[1] = 0x00;
|
|
beam.shaderRGBA[2] = 0xff;
|
|
break;
|
|
case ST_QUICK_SAVE:
|
|
count = 2;
|
|
beam.shaderRGBA[0] = 0xff;
|
|
beam.shaderRGBA[1] = 0xff;
|
|
beam.shaderRGBA[2] = 0xff;
|
|
break;
|
|
}
|
|
|
|
VectorCopy(beamOrigin, beam.oldorigin);
|
|
VectorCopy(selectorOrigin, beam.origin );
|
|
beam.customShader = cgi_R_RegisterShader( "gfx/misc/whiteline2" );
|
|
beam.reType = RT_LINE;
|
|
beam.radius = 0.3f;
|
|
|
|
cgi_R_AddRefEntityToScene( &beam );
|
|
|
|
|
|
if (cg.itemSelectorType == ST_WEAPON) // weapons
|
|
{
|
|
if (cg.weaponSelect != WP_NONE &&
|
|
cg.weaponSelect != WP_MELEE) {
|
|
refEntity_t sprite;
|
|
memset(&sprite, 0, sizeof(sprite));
|
|
VectorCopy(wheelOrigin, sprite.origin);
|
|
sprite.reType = RT_SPRITE;
|
|
sprite.customShader = cg_weapons[cg.weaponSelect].weaponIcon;
|
|
sprite.radius = 1.8f;
|
|
memset(sprite.shaderRGBA, 0xff, 4);
|
|
cgi_R_AddRefEntityToScene(&sprite);
|
|
}
|
|
}
|
|
else if (cg.itemSelectorType == ST_FIGHTING_STYLE) // fighting style
|
|
{
|
|
//For the fighting style show the active one in the middle
|
|
int level = cent->gent->client->ps.saberAnimLevel;
|
|
if (cent->gent->client->ps.forcePowersKnown & (1 << FP_SABER_OFFENSE) &&
|
|
level > FORCE_LEVEL_0) {
|
|
refEntity_t sprite;
|
|
memset(&sprite, 0, sizeof(sprite));
|
|
VectorCopy(wheelOrigin, sprite.origin);
|
|
sprite.reType = RT_SPRITE;
|
|
switch (level) {
|
|
case FORCE_LEVEL_1:
|
|
sprite.customShader = cgs.media.HUDSaberStyleFast;
|
|
break;
|
|
case FORCE_LEVEL_2:
|
|
sprite.customShader = cgs.media.HUDSaberStyleMed;
|
|
break;
|
|
case FORCE_LEVEL_3:
|
|
sprite.customShader = cgs.media.HUDSaberStyleStrong;
|
|
break;
|
|
}
|
|
|
|
sprite.radius = 1.8f;
|
|
memset(sprite.shaderRGBA, 0xff, 4);
|
|
cgi_R_AddRefEntityToScene(&sprite);
|
|
}
|
|
}
|
|
else if (cg.itemSelectorType == ST_FORCE_POWER) // force powers
|
|
{
|
|
if (cent->gent->client->ps.forcePowersKnown != 0) {
|
|
refEntity_t sprite;
|
|
memset(&sprite, 0, sizeof(sprite));
|
|
VectorCopy(wheelOrigin, sprite.origin);
|
|
sprite.reType = RT_SPRITE;
|
|
sprite.customShader = force_icons[showPowers[cg.forcepowerSelect]];
|
|
sprite.radius = 1.8f;
|
|
memset(sprite.shaderRGBA, 0xff, 4);
|
|
cgi_R_AddRefEntityToScene(&sprite);
|
|
}
|
|
}
|
|
|
|
for (int s = -1; s < 2; s += 2) {
|
|
refEntity_t sprite;
|
|
memset(&sprite, 0, sizeof(sprite));
|
|
vec3_t right;
|
|
AngleVectors(wheelAngles, NULL, right, NULL);
|
|
float offset = ((float) s * 6.0f) + (((float) s * 0.3f) *
|
|
sinf(DEG2RAD(AngleNormalize360(cg.time - cg.itemSelectorTime))));
|
|
VectorMA(wheelOrigin, offset, right, sprite.origin);
|
|
sprite.reType = RT_SPRITE;
|
|
sprite.customShader = cgs.media.binocularArrow;
|
|
sprite.radius = 0.6f;
|
|
sprite.rotation = 180.0f * ((s - 1.0f) / 2.0f);
|
|
memset(sprite.shaderRGBA, 0xff, 4);
|
|
cgi_R_AddRefEntityToScene(&sprite);
|
|
}
|
|
|
|
const char *info = CG_ConfigString( CS_SERVERINFO );
|
|
const char *mapname = Info_ValueForKey( info, "mapname" );
|
|
|
|
qboolean selected = qfalse;
|
|
for (int index = 0; index < count; ++index)
|
|
{
|
|
int itemId = index;
|
|
if (cg.itemSelectorType == 0) {
|
|
if (vr->in_vehicle)
|
|
{
|
|
itemId = WP_ATST_MAIN + index;
|
|
}
|
|
else
|
|
{
|
|
itemId = index + 1; // We need to ignore WP_NONE for weapons
|
|
if (itemId == count)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
bool selectable;
|
|
switch (cg.itemSelectorType)
|
|
{
|
|
case ST_WEAPON: //weapons
|
|
selectable = vr->in_vehicle || // both ATST weapons are always selectable
|
|
(CG_WeaponSelectable(itemId, cg.weaponSelect, qfalse) && cg.snap->ps.ammo[weaponData[itemId].ammoIndex]);
|
|
break;
|
|
case ST_GADGET: //gadgets
|
|
selectable = CG_InventorySelectable(itemId) && inv_icons[itemId];
|
|
break;
|
|
case ST_FIGHTING_STYLE: //fighting style
|
|
{
|
|
if (cent->gent->client->ps.forcePowersKnown & ( 1 << FP_SABER_OFFENSE )) {
|
|
selectable = itemId < cent->gent->client->ps.forcePowerLevel[FP_SABER_OFFENSE];
|
|
} else {
|
|
selectable = false;
|
|
}
|
|
}
|
|
break;
|
|
case ST_FORCE_POWER: // force powers
|
|
selectable = ForcePower_Valid(itemId);
|
|
break;
|
|
case ST_QUICK_SAVE:
|
|
selectable = true;
|
|
break;
|
|
}
|
|
|
|
if (selectable) {
|
|
//first calculate wheel slot position
|
|
vec3_t angles, iconOrigin, iconBackground, iconForeground;
|
|
VectorClear(angles);
|
|
angles[YAW] = wheelAngles[YAW];
|
|
angles[PITCH] = wheelAngles[PITCH];
|
|
angles[ROLL] =
|
|
(float)(360 / (count - ((cg.itemSelectorType == ST_WEAPON && !vr->in_vehicle) ? 1 : 0))) * index;
|
|
vec3_t forward, up;
|
|
AngleVectors(angles, forward, NULL, up);
|
|
|
|
VectorMA(wheelOrigin, (radius * frac), up, iconOrigin);
|
|
VectorMA(iconOrigin, 0.2f, forward, iconBackground);
|
|
VectorMA(iconOrigin, -0.2f, forward, iconForeground);
|
|
|
|
{
|
|
vec3_t diff;
|
|
VectorSubtract(selectorOrigin, iconOrigin, diff);
|
|
float length = VectorLength(diff);
|
|
if (length <= 1.0f &&
|
|
frac == 1.0f &&
|
|
selectable) {
|
|
if (cg.itemSelectorSelection != itemId) {
|
|
cg.itemSelectorSelection = itemId;
|
|
|
|
cgi_HapticEvent("selector_icon", 0, vr->right_handed ?
|
|
((cg.itemSelectorType >= ST_FORCE_POWER) ? 2 : 1) : ((cg.itemSelectorType >= ST_FORCE_POWER) ? 1 : 2), 100, 0, 0);
|
|
}
|
|
|
|
selected = qtrue;
|
|
}
|
|
}
|
|
|
|
if (cg.itemSelectorSelection == itemId) {
|
|
refEntity_t sprite;
|
|
memset(&sprite, 0, sizeof(sprite));
|
|
VectorCopy(iconOrigin, sprite.origin);
|
|
sprite.origin[2] += 2.5f + (0.5f * sinf(DEG2RAD(
|
|
AngleNormalize360(cg.time - cg.itemSelectorTime))));
|
|
sprite.reType = RT_SPRITE;
|
|
sprite.customShader = cgs.media.binocularArrow;
|
|
sprite.radius = 0.6f;
|
|
sprite.rotation = -90.0f;
|
|
sprite.shaderRGBA[0] = 255;
|
|
sprite.shaderRGBA[1] = 255;
|
|
sprite.shaderRGBA[2] = 255;
|
|
sprite.shaderRGBA[3] = 255;
|
|
cgi_R_AddRefEntityToScene(&sprite);
|
|
}
|
|
|
|
{
|
|
refEntity_t sprite;
|
|
memset(&sprite, 0, sizeof(sprite));
|
|
|
|
float sRadius = 1.3f;
|
|
|
|
VectorCopy(iconOrigin, sprite.origin);
|
|
sprite.reType = RT_SPRITE;
|
|
switch (cg.itemSelectorType)
|
|
{
|
|
case ST_WEAPON: //weapons
|
|
sprite.customShader = cg_weapons[itemId].weaponIcon;
|
|
break;
|
|
case ST_GADGET: //gadgets
|
|
sprite.customShader = inv_icons[itemId];
|
|
break;
|
|
case ST_FIGHTING_STYLE: //fighting style
|
|
switch ( itemId )
|
|
{
|
|
case 0://FORCE_LEVEL_1:
|
|
sprite.customShader = cgs.media.HUDSaberStyleFast;
|
|
break;
|
|
case 1://FORCE_LEVEL_2:
|
|
sprite.customShader = cgs.media.HUDSaberStyleMed;
|
|
break;
|
|
case 2://FORCE_LEVEL_3:
|
|
sprite.customShader = cgs.media.HUDSaberStyleStrong;
|
|
break;
|
|
}
|
|
break;
|
|
case ST_FORCE_POWER: // force powers
|
|
sprite.customShader = force_icons[showPowers[itemId]];
|
|
break;
|
|
case ST_QUICK_SAVE:
|
|
sprite.customShader = itemId == 0 ? cgs.media.iconSave : cgs.media.iconLoad;
|
|
break;
|
|
}
|
|
|
|
sprite.radius =
|
|
sRadius * (cg.itemSelectorSelection == itemId ? 1.3f : 0.6f);
|
|
sprite.shaderRGBA[0] = 255;
|
|
sprite.shaderRGBA[1] = 255;
|
|
sprite.shaderRGBA[2] = 255;
|
|
sprite.shaderRGBA[3] = 255;
|
|
cgi_R_AddRefEntityToScene(&sprite);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!selected)
|
|
{
|
|
cg.itemSelectorSelection = ST_NONE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===================
|
|
CG_OutOfAmmoChange
|
|
|
|
The current weapon has just run out of ammo
|
|
===================
|
|
*/
|
|
void CG_OutOfAmmoChange( void ) {
|
|
int i;
|
|
int original;
|
|
|
|
if ( cg.weaponSelectTime + 200 > cg.time )
|
|
return;
|
|
|
|
if( g_entities[0].client && g_entities[0].client->NPC_class == CLASS_ATST )
|
|
{
|
|
CG_ToggleATSTWeapon();
|
|
return;
|
|
}
|
|
|
|
original = cg.weaponSelect;
|
|
|
|
for ( i = WP_ROCKET_LAUNCHER; i > 0 ; i-- )
|
|
{
|
|
// We don't want the emplaced, melee, or explosive devices here
|
|
if ( original != i && CG_WeaponSelectable( i, original, qfalse ) )
|
|
{
|
|
SetWeaponSelectTime();
|
|
cg.weaponSelect = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( cg_autoswitch.integer != 1 )
|
|
{
|
|
// didn't have that, so try these. Start with thermal...
|
|
for ( i = WP_THERMAL; i <= WP_DET_PACK; i++ )
|
|
{
|
|
// We don't want the emplaced, or melee here
|
|
if ( original != i && CG_WeaponSelectable( i, original, qfalse ) )
|
|
{
|
|
if ( i == WP_DET_PACK && cg.snap->ps.ammo[weaponData[i].ammoIndex] <= 0 )
|
|
{
|
|
// crap, no point in switching to this
|
|
}
|
|
else
|
|
{
|
|
SetWeaponSelectTime();
|
|
cg.weaponSelect = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// try stun baton as a last ditch effort
|
|
if ( CG_WeaponSelectable( WP_STUN_BATON, original, qfalse ))
|
|
{
|
|
SetWeaponSelectTime();
|
|
cg.weaponSelect = WP_STUN_BATON;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
===================================================================================================
|
|
|
|
WEAPON EVENTS
|
|
|
|
===================================================================================================
|
|
*/
|
|
|
|
/*
|
|
================
|
|
CG_FireWeapon
|
|
|
|
Caused by an EV_FIRE_WEAPON event
|
|
================
|
|
*/
|
|
void CG_FireWeapon( centity_t *cent, qboolean alt_fire )
|
|
{
|
|
entityState_t *ent;
|
|
//weaponInfo_t *weap;
|
|
|
|
ent = ¢->currentState;
|
|
if ( ent->weapon == WP_NONE ) {
|
|
return;
|
|
}
|
|
if ( ent->weapon >= WP_NUM_WEAPONS ) {
|
|
CG_Error( "CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS" );
|
|
return;
|
|
}
|
|
//weap = &cg_weapons[ ent->weapon ];
|
|
|
|
// mark the entity as muzzle flashing, so when it is added it will
|
|
// append the flash to the weapon model
|
|
cent->muzzleFlashTime = cg.time;
|
|
cent->altFire = alt_fire;
|
|
|
|
// lightning type guns only does this this on initial press
|
|
if ( ent->weapon == WP_SABER )
|
|
{
|
|
if ( cent->pe.lightningFiring )
|
|
{
|
|
/* if ( ent->weapon == WP_DREADNOUGHT )
|
|
{
|
|
cgi_FF_EnsureFX( fffx_Laser3 );
|
|
}
|
|
*/
|
|
return;
|
|
}
|
|
}
|
|
|
|
//Are we the player?
|
|
if (cent->gent->client->ps.clientNum == 0)
|
|
{
|
|
int position = vr->weapon_stabilised ? 4 : (vr->right_handed ? 1 : 2);
|
|
|
|
//Haptics
|
|
switch (ent->weapon) {
|
|
case WP_SABER:
|
|
cgi_HapticEvent("chainsaw_fire", position, 0, 40, 0, 0);
|
|
break;
|
|
case WP_BRYAR_PISTOL:
|
|
case WP_BOWCASTER:
|
|
case WP_BLASTER:
|
|
case WP_ATST_MAIN:
|
|
cgi_HapticEvent("machinegun_fire", position, 0, (ent->weapon == WP_BRYAR_PISTOL) ? 60 : 100, 0, 0);
|
|
break;
|
|
case WP_BLASTER_PISTOL:
|
|
cgi_HapticEvent("shotgun_fire", position, 0, 100, 0, 0);
|
|
break;
|
|
case WP_THERMAL:
|
|
case WP_DET_PACK:
|
|
case WP_TRIP_MINE:
|
|
cgi_HapticEvent("handgrenade_fire", position, 0, 80, 0, 0);
|
|
break;
|
|
case WP_ROCKET_LAUNCHER:
|
|
case WP_ATST_SIDE:
|
|
cgi_HapticEvent("rocket_fire", position, 0, 100, 0, 0);
|
|
break;
|
|
case WP_DISRUPTOR:
|
|
cgi_HapticEvent("RTCWQuest:fire_sniper", position, 0, 100, 0, 0);
|
|
break;
|
|
case WP_FLECHETTE:
|
|
case WP_REPEATER:
|
|
cgi_HapticEvent("plasmagun_fire", position, 0, 100, 0, 0);
|
|
break;
|
|
case WP_DEMP2:
|
|
case WP_EMPLACED_GUN:
|
|
cgi_HapticEvent("bfg_fire", position, 0, 100, 0, 0);
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
CG_BounceEffect
|
|
|
|
Caused by an EV_BOUNCE | EV_BOUNCE_HALF event
|
|
=================
|
|
*/
|
|
void CG_BounceEffect( centity_t *cent, int weapon, vec3_t origin, vec3_t normal )
|
|
{
|
|
switch( weapon )
|
|
{
|
|
case WP_THERMAL:
|
|
if ( rand() & 1 ) {
|
|
cgi_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeBounce1 );
|
|
} else {
|
|
cgi_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeBounce2 );
|
|
}
|
|
break;
|
|
|
|
case WP_BOWCASTER:
|
|
theFxScheduler.PlayEffect( cgs.effects.bowcasterBounceEffect, origin, normal );
|
|
break;
|
|
|
|
case WP_FLECHETTE:
|
|
theFxScheduler.PlayEffect( "flechette/ricochet", origin, normal );
|
|
break;
|
|
|
|
default:
|
|
if ( rand() & 1 ) {
|
|
cgi_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeBounce1 );
|
|
} else {
|
|
cgi_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.grenadeBounce2 );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
void CG_MissileStick( centity_t *cent, int weapon, vec3_t position )
|
|
//----------------------------------------------------------------------
|
|
{
|
|
sfxHandle_t snd = 0;
|
|
|
|
switch( weapon )
|
|
{
|
|
case WP_FLECHETTE:
|
|
snd = cgs.media.flechetteStickSound;
|
|
break;
|
|
|
|
case WP_DET_PACK:
|
|
snd = cgs.media.detPackStickSound;
|
|
break;
|
|
|
|
case WP_TRIP_MINE:
|
|
snd = cgs.media.tripMineStickSound;
|
|
break;
|
|
}
|
|
|
|
if ( snd )
|
|
{
|
|
cgi_S_StartSound( NULL, cent->currentState.number, CHAN_AUTO, snd );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
CG_MissileHitWall
|
|
|
|
Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing
|
|
=================
|
|
*/
|
|
void CG_MissileHitWall( centity_t *cent, int weapon, vec3_t origin, vec3_t dir, qboolean altFire )
|
|
{
|
|
int parm;
|
|
|
|
switch( weapon )
|
|
{
|
|
case WP_BRYAR_PISTOL:
|
|
if ( altFire )
|
|
{
|
|
parm = 0;
|
|
|
|
if ( cent->gent )
|
|
{
|
|
parm += cent->gent->count;
|
|
}
|
|
|
|
FX_BryarAltHitWall( origin, dir, parm );
|
|
}
|
|
else
|
|
{
|
|
FX_BryarHitWall( origin, dir );
|
|
}
|
|
break;
|
|
|
|
case WP_BLASTER:
|
|
FX_BlasterWeaponHitWall( origin, dir );
|
|
break;
|
|
|
|
case WP_BOWCASTER:
|
|
FX_BowcasterHitWall( origin, dir );
|
|
break;
|
|
|
|
case WP_REPEATER:
|
|
if ( altFire )
|
|
{
|
|
FX_RepeaterAltHitWall( origin, dir );
|
|
}
|
|
else
|
|
{
|
|
FX_RepeaterHitWall( origin, dir );
|
|
}
|
|
break;
|
|
|
|
case WP_DEMP2:
|
|
if ( altFire )
|
|
{
|
|
}
|
|
else
|
|
{
|
|
FX_DEMP2_HitWall( origin, dir );
|
|
}
|
|
break;
|
|
|
|
case WP_FLECHETTE:
|
|
if ( altFire )
|
|
{
|
|
theFxScheduler.PlayEffect( "flechette/alt_blow", origin, dir );
|
|
}
|
|
else
|
|
{
|
|
FX_FlechetteWeaponHitWall( origin, dir );
|
|
}
|
|
break;
|
|
|
|
case WP_ROCKET_LAUNCHER:
|
|
FX_RocketHitWall( origin, dir );
|
|
break;
|
|
|
|
case WP_THERMAL:
|
|
theFxScheduler.PlayEffect( "thermal/explosion", origin, dir );
|
|
theFxScheduler.PlayEffect( "thermal/shockwave", origin );
|
|
break;
|
|
|
|
case WP_EMPLACED_GUN:
|
|
FX_EmplacedHitWall( origin, dir );
|
|
break;
|
|
|
|
case WP_ATST_MAIN:
|
|
FX_ATSTMainHitWall( origin, dir );
|
|
break;
|
|
|
|
case WP_ATST_SIDE:
|
|
if ( altFire )
|
|
{
|
|
theFxScheduler.PlayEffect( "atst/side_alt_explosion", origin, dir );
|
|
}
|
|
else
|
|
{
|
|
theFxScheduler.PlayEffect( "atst/side_main_impact", origin, dir );
|
|
}
|
|
break;
|
|
|
|
case WP_TRIP_MINE:
|
|
theFxScheduler.PlayEffect( "tripmine/explosion", origin, dir );
|
|
break;
|
|
|
|
case WP_DET_PACK:
|
|
theFxScheduler.PlayEffect( "detpack/explosion", origin, dir );
|
|
break;
|
|
|
|
case WP_TURRET:
|
|
theFxScheduler.PlayEffect( "turret/wall_impact", origin, dir );
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
CG_MissileHitPlayer
|
|
-------------------------
|
|
*/
|
|
|
|
void CG_MissileHitPlayer( centity_t *cent, int weapon, vec3_t origin, vec3_t dir, qboolean altFire )
|
|
{
|
|
gentity_t *other = NULL;
|
|
qboolean humanoid = qtrue;
|
|
|
|
if ( cent->gent )
|
|
{
|
|
other = &g_entities[cent->gent->s.otherEntityNum];
|
|
if( other->client )
|
|
{
|
|
class_t npc_class = other->client->NPC_class;
|
|
// check for all droids, maybe check for certain monsters if they're considered non-humanoid..?
|
|
if ( npc_class == CLASS_SEEKER || npc_class == CLASS_PROBE || npc_class == CLASS_MOUSE ||
|
|
npc_class == CLASS_GONK || npc_class == CLASS_R2D2 || npc_class == CLASS_R5D2 ||
|
|
npc_class == CLASS_PROTOCOL || npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 ||
|
|
npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY )
|
|
{
|
|
humanoid = qfalse;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch( weapon )
|
|
{
|
|
case WP_BRYAR_PISTOL:
|
|
if ( altFire )
|
|
{
|
|
FX_BryarAltHitPlayer( origin, dir, humanoid );
|
|
}
|
|
else
|
|
{
|
|
FX_BryarHitPlayer( origin, dir, humanoid );
|
|
}
|
|
break;
|
|
|
|
case WP_BLASTER:
|
|
FX_BlasterWeaponHitPlayer( origin, dir, humanoid );
|
|
break;
|
|
|
|
case WP_BOWCASTER:
|
|
FX_BowcasterHitPlayer( origin, dir, humanoid );
|
|
break;
|
|
|
|
case WP_REPEATER:
|
|
if ( altFire )
|
|
{
|
|
FX_RepeaterAltHitPlayer( origin, dir, humanoid );
|
|
}
|
|
else
|
|
{
|
|
FX_RepeaterHitPlayer( origin, dir, humanoid );
|
|
}
|
|
break;
|
|
|
|
case WP_DEMP2:
|
|
if ( !altFire )
|
|
{
|
|
FX_DEMP2_HitPlayer( origin, dir, humanoid );
|
|
}
|
|
|
|
// Do a full body effect here for some more feedback
|
|
if ( other && other->client )
|
|
{
|
|
other->s.powerups |= ( 1 << PW_SHOCKED );
|
|
other->client->ps.powerups[PW_SHOCKED] = cg.time + 1000;
|
|
}
|
|
break;
|
|
|
|
case WP_FLECHETTE:
|
|
if ( altFire )
|
|
{
|
|
theFxScheduler.PlayEffect( "flechette/alt_blow", origin, dir );
|
|
}
|
|
else
|
|
{
|
|
FX_FlechetteWeaponHitPlayer( origin, dir, humanoid );
|
|
}
|
|
break;
|
|
|
|
case WP_ROCKET_LAUNCHER:
|
|
FX_RocketHitPlayer( origin, dir, humanoid );
|
|
break;
|
|
|
|
case WP_THERMAL:
|
|
theFxScheduler.PlayEffect( "thermal/explosion", origin, dir );
|
|
theFxScheduler.PlayEffect( "thermal/shockwave", origin );
|
|
break;
|
|
|
|
case WP_EMPLACED_GUN:
|
|
FX_EmplacedHitWall( origin, dir );
|
|
break;
|
|
|
|
case WP_TRIP_MINE:
|
|
theFxScheduler.PlayEffect( "tripmine/explosion", origin, dir );
|
|
break;
|
|
|
|
case WP_DET_PACK:
|
|
theFxScheduler.PlayEffect( "detpack/explosion", origin, dir );
|
|
break;
|
|
|
|
case WP_TURRET:
|
|
theFxScheduler.PlayEffect( "turret/flesh_impact", origin, dir );
|
|
break;
|
|
|
|
case WP_ATST_MAIN:
|
|
FX_EmplacedHitWall( origin, dir );
|
|
break;
|
|
|
|
case WP_ATST_SIDE:
|
|
if ( altFire )
|
|
{
|
|
theFxScheduler.PlayEffect( "atst/side_alt_explosion", origin, dir );
|
|
}
|
|
else
|
|
{
|
|
theFxScheduler.PlayEffect( "atst/side_main_impact", origin, dir );
|
|
}
|
|
break;
|
|
}
|
|
}
|