Merge branch 'opfor' into opforfixed

This commit is contained in:
Andrey Akhmichin 2023-09-19 23:19:43 +05:00
commit 804c0ab03d
9 changed files with 591 additions and 977 deletions

View File

@ -1,356 +0,0 @@
/* NEON implementation of sin, cos, exp and log
Inspired by Intel Approximate Math library, and based on the
corresponding algorithms of the cephes math library
*/
/* Copyright (C) 2011 Julien Pommier
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
(this is the zlib license)
*/
#include <arm_neon.h>
typedef float32x4_t v4sf; // vector of 4 float
typedef uint32x4_t v4su; // vector of 4 uint32
typedef int32x4_t v4si; // vector of 4 uint32
#define s4f_x(s4f) vgetq_lane_f32(s4f, 0)
#define s4f_y(s4f) vgetq_lane_f32(s4f, 1)
#define s4f_z(s4f) vgetq_lane_f32(s4f, 2)
#define s4f_w(s4f) vgetq_lane_f32(s4f, 3)
#define c_inv_mant_mask ~0x7f800000u
#define c_cephes_SQRTHF 0.707106781186547524
#define c_cephes_log_p0 7.0376836292E-2
#define c_cephes_log_p1 - 1.1514610310E-1
#define c_cephes_log_p2 1.1676998740E-1
#define c_cephes_log_p3 - 1.2420140846E-1
#define c_cephes_log_p4 + 1.4249322787E-1
#define c_cephes_log_p5 - 1.6668057665E-1
#define c_cephes_log_p6 + 2.0000714765E-1
#define c_cephes_log_p7 - 2.4999993993E-1
#define c_cephes_log_p8 + 3.3333331174E-1
#define c_cephes_log_q1 -2.12194440e-4
#define c_cephes_log_q2 0.693359375
/* natural logarithm computed for 4 simultaneous float
return NaN for x <= 0
*/
inline v4sf log_ps(v4sf x) {
v4sf one = vdupq_n_f32(1);
x = vmaxq_f32(x, vdupq_n_f32(0)); /* force flush to zero on denormal values */
v4su invalid_mask = vcleq_f32(x, vdupq_n_f32(0));
v4si ux = vreinterpretq_s32_f32(x);
v4si emm0 = vshrq_n_s32(ux, 23);
/* keep only the fractional part */
ux = vandq_s32(ux, vdupq_n_s32(c_inv_mant_mask));
ux = vorrq_s32(ux, vreinterpretq_s32_f32(vdupq_n_f32(0.5f)));
x = vreinterpretq_f32_s32(ux);
emm0 = vsubq_s32(emm0, vdupq_n_s32(0x7f));
v4sf e = vcvtq_f32_s32(emm0);
e = vaddq_f32(e, one);
/* part2:
if( x < SQRTHF ) {
e -= 1;
x = x + x - 1.0;
} else { x = x - 1.0; }
*/
v4su mask = vcltq_f32(x, vdupq_n_f32(c_cephes_SQRTHF));
v4sf tmp = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(x), mask));
x = vsubq_f32(x, one);
e = vsubq_f32(e, vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(one), mask)));
x = vaddq_f32(x, tmp);
v4sf z = vmulq_f32(x,x);
v4sf y = vdupq_n_f32(c_cephes_log_p0);
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p1));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p2));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p3));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p4));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p5));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p6));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p7));
y = vmulq_f32(y, x);
y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p8));
y = vmulq_f32(y, x);
y = vmulq_f32(y, z);
tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q1));
y = vaddq_f32(y, tmp);
tmp = vmulq_f32(z, vdupq_n_f32(0.5f));
y = vsubq_f32(y, tmp);
tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q2));
x = vaddq_f32(x, y);
x = vaddq_f32(x, tmp);
x = vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(x), invalid_mask)); // negative arg will be NAN
return x;
}
#define c_exp_hi 88.3762626647949f
#define c_exp_lo -88.3762626647949f
#define c_cephes_LOG2EF 1.44269504088896341
#define c_cephes_exp_C1 0.693359375
#define c_cephes_exp_C2 -2.12194440e-4
#define c_cephes_exp_p0 1.9875691500E-4
#define c_cephes_exp_p1 1.3981999507E-3
#define c_cephes_exp_p2 8.3334519073E-3
#define c_cephes_exp_p3 4.1665795894E-2
#define c_cephes_exp_p4 1.6666665459E-1
#define c_cephes_exp_p5 5.0000001201E-1
/* exp() computed for 4 float at once */
inline v4sf exp_ps(v4sf x) {
v4sf tmp, fx;
v4sf one = vdupq_n_f32(1);
x = vminq_f32(x, vdupq_n_f32(c_exp_hi));
x = vmaxq_f32(x, vdupq_n_f32(c_exp_lo));
/* express exp(x) as exp(g + n*log(2)) */
fx = vmlaq_f32(vdupq_n_f32(0.5f), x, vdupq_n_f32(c_cephes_LOG2EF));
/* perform a floorf */
tmp = vcvtq_f32_s32(vcvtq_s32_f32(fx));
/* if greater, substract 1 */
v4su mask = vcgtq_f32(tmp, fx);
mask = vandq_u32(mask, vreinterpretq_u32_f32(one));
fx = vsubq_f32(tmp, vreinterpretq_f32_u32(mask));
tmp = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C1));
v4sf z = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C2));
x = vsubq_f32(x, tmp);
x = vsubq_f32(x, z);
static const float cephes_exp_p[6] = { c_cephes_exp_p0, c_cephes_exp_p1, c_cephes_exp_p2, c_cephes_exp_p3, c_cephes_exp_p4, c_cephes_exp_p5 };
v4sf y = vld1q_dup_f32(cephes_exp_p+0);
v4sf c1 = vld1q_dup_f32(cephes_exp_p+1);
v4sf c2 = vld1q_dup_f32(cephes_exp_p+2);
v4sf c3 = vld1q_dup_f32(cephes_exp_p+3);
v4sf c4 = vld1q_dup_f32(cephes_exp_p+4);
v4sf c5 = vld1q_dup_f32(cephes_exp_p+5);
y = vmulq_f32(y, x);
z = vmulq_f32(x,x);
y = vaddq_f32(y, c1);
y = vmulq_f32(y, x);
y = vaddq_f32(y, c2);
y = vmulq_f32(y, x);
y = vaddq_f32(y, c3);
y = vmulq_f32(y, x);
y = vaddq_f32(y, c4);
y = vmulq_f32(y, x);
y = vaddq_f32(y, c5);
y = vmulq_f32(y, z);
y = vaddq_f32(y, x);
y = vaddq_f32(y, one);
/* build 2^n */
int32x4_t mm;
mm = vcvtq_s32_f32(fx);
mm = vaddq_s32(mm, vdupq_n_s32(0x7f));
mm = vshlq_n_s32(mm, 23);
v4sf pow2n = vreinterpretq_f32_s32(mm);
y = vmulq_f32(y, pow2n);
return y;
}
#define c_minus_cephes_DP1 -0.78515625
#define c_minus_cephes_DP2 -2.4187564849853515625e-4
#define c_minus_cephes_DP3 -3.77489497744594108e-8
#define c_sincof_p0 -1.9515295891E-4
#define c_sincof_p1 8.3321608736E-3
#define c_sincof_p2 -1.6666654611E-1
#define c_coscof_p0 2.443315711809948E-005
#define c_coscof_p1 -1.388731625493765E-003
#define c_coscof_p2 4.166664568298827E-002
#define c_cephes_FOPI 1.27323954473516 // 4 / M_PI
/* evaluation of 4 sines & cosines at once.
The code is the exact rewriting of the cephes sinf function.
Precision is excellent as long as x < 8192 (I did not bother to
take into account the special handling they have for greater values
-- it does not return garbage for arguments over 8192, though, but
the extra precision is missing).
Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the
surprising but correct result.
Note also that when you compute sin(x), cos(x) is available at
almost no extra price so both sin_ps and cos_ps make use of
sincos_ps..
*/
inline void sincos_ps(v4sf x, v4sf *ysin, v4sf *ycos) { // any x
v4sf y;
v4su emm2;
v4su sign_mask_sin, sign_mask_cos;
sign_mask_sin = vcltq_f32(x, vdupq_n_f32(0));
x = vabsq_f32(x);
/* scale by 4/Pi */
y = vmulq_n_f32(x, c_cephes_FOPI);
/* store the integer part of y in mm0 */
emm2 = vcvtq_u32_f32(y);
/* j=(j+1) & (~1) (see the cephes sources) */
emm2 = vaddq_u32(emm2, vdupq_n_u32(1));
emm2 = vandq_u32(emm2, vdupq_n_u32(~1));
y = vcvtq_f32_u32(emm2);
/* get the polynom selection mask
there is one polynom for 0 <= x <= Pi/4
and another one for Pi/4<x<=Pi/2
Both branches will be computed.
*/
v4su poly_mask = vtstq_u32(emm2, vdupq_n_u32(2));
/* The magic pass: "Extended precision modular arithmetic"
x = ((x - y * DP1) - y * DP2) - y * DP3; */
x = vfmaq_n_f32(x, y, c_minus_cephes_DP1);
x = vfmaq_n_f32(x, y, c_minus_cephes_DP2);
x = vfmaq_n_f32(x, y, c_minus_cephes_DP3);
sign_mask_sin = veorq_u32(sign_mask_sin, vtstq_u32(emm2, vdupq_n_u32(4)));
sign_mask_cos = vtstq_u32(vsubq_u32(emm2, vdupq_n_u32(2)), vdupq_n_u32(4));
/* Evaluate the first polynom (0 <= x <= Pi/4) in y1,
and the second polynom (Pi/4 <= x <= 0) in y2 */
v4sf z = vmulq_f32(x,x);
v4sf y1, y2;
y1 = vfmaq_n_f32(vdupq_n_f32(c_coscof_p1), z, c_coscof_p0);
y2 = vfmaq_n_f32(vdupq_n_f32(c_sincof_p1), z, c_sincof_p0);
y1 = vfmaq_f32(vdupq_n_f32(c_coscof_p2), y1, z);
y2 = vfmaq_f32(vdupq_n_f32(c_sincof_p2), y2, z);
y1 = vmulq_f32(y1, z);
y2 = vmulq_f32(y2, z);
y1 = vmulq_f32(y1, z);
y1 = vfmsq_n_f32(y1, z, 0.5f);
y2 = vfmaq_f32(x, y2, x);
y1 = vaddq_f32(y1, vdupq_n_f32(1));
/* select the correct result from the two polynoms */
v4sf ys = vbslq_f32(poly_mask, y1, y2);
v4sf yc = vbslq_f32(poly_mask, y2, y1);
*ysin = vbslq_f32(sign_mask_sin, vnegq_f32(ys), ys);
*ycos = vbslq_f32(sign_mask_cos, yc, vnegq_f32(yc));
}
inline v4sf sin_ps(v4sf x) {
v4sf ysin, ycos;
sincos_ps(x, &ysin, &ycos);
return ysin;
}
inline v4sf cos_ps(v4sf x) {
v4sf ysin, ycos;
sincos_ps(x, &ysin, &ycos);
return ycos;
}
static const float asinf_lut[7] = {
1.5707961728,
-0.2145852647,
0.0887556286,
-0.0488025043,
0.0268999482,
-0.0111462294,
0.0022959648
};
inline void asincos_ps(float32x4_t x, float32x4_t* yasin, float32x4_t* yacos)
{
float32x4_t one = vdupq_n_f32(1);
float32x4_t negone = vdupq_n_f32(-1);
float32x4_t lut[7];
float32x4_t xv[5];
float32x4_t sat = vdupq_n_f32(0.9999999f);
float32x4_t m_pi_2 = vdupq_n_f32(1.570796326);
for (int i = 0; i <= 6; i++)
lut[i] = vdupq_n_f32(asinf_lut[i]);
uint32x4_t sign_mask_asin = vcltq_f32(x, vdupq_n_f32(0));
x = vabsq_f32(x);
uint32x4_t saturate = vcgeq_f32(x, one);
x = vbslq_f32(saturate, sat, x);
float32x4_t y = vsubq_f32(one, x);
y = vsqrtq_f32(y);
xv[0] = vmulq_f32(x, x);
for (int i = 1; i < 5; i++)
xv[i] = vmulq_f32(xv[i - 1], x);
float32x4_t a0 = vaddq_f32(lut[0], vmulq_f32(lut[1], x));
float32x4_t a1 = vaddq_f32(vmulq_f32(lut[2], xv[0]), vmulq_f32(lut[3], xv[1]));
float32x4_t a2 = vaddq_f32(vmulq_f32(lut[4], xv[2]), vmulq_f32(lut[5], xv[3]));
float32x4_t a3 = vmulq_f32(lut[6], xv[4]);
float32x4_t phx = vaddq_f32(vaddq_f32(a0, vaddq_f32(a1, a2)), a3);
float32x4_t arcsinx = vmulq_f32(y, phx);
arcsinx = vsubq_f32(m_pi_2, arcsinx);
float32x4_t arcnsinx = vmulq_f32(negone, arcsinx);
arcsinx = vbslq_f32(sign_mask_asin, arcnsinx, arcsinx);
*yasin = arcsinx;
*yacos = vsubq_f32(m_pi_2, arcsinx);
}
inline float32x4_t asin_ps(float32x4_t x)
{
float32x4_t yasin, yacos;
asincos_ps(x, &yasin, &yacos);
return yasin;
}
inline float32x4_t acos_ps(float32x4_t x)
{
float32x4_t yasin, yacos;
asincos_ps(x, &yasin, &yacos);
return yacos;
}

View File

@ -100,10 +100,11 @@ int CHudSayText::Draw( float flTime )
int y = Y_START;
#if USE_VGUI
if( ( gViewPort && gViewPort->AllowedToPrintText() == FALSE ) || !m_HUD_saytext->value )
if( ( gViewPort && gViewPort->AllowedToPrintText() == FALSE ) )
return 1;
#endif
if ( !m_HUD_saytext->value )
return 1;
// make sure the scrolltime is within reasonable bounds, to guard against the clock being reset
flScrollTime = Q_min( flScrollTime, flTime + m_HUD_saytext_time->value );
@ -173,8 +174,6 @@ void CHudSayText::SayTextPrint( const char *pszBuf, int iBufSize, int clientInde
ConsolePrint( pszBuf );
return;
}
#else
ConsolePrint( pszBuf );
#endif
int i;

View File

@ -10,12 +10,6 @@
#include "const.h"
#include "com_model.h"
#include "studio_util.h"
#include "build.h"
#if XASH_ARMv8
#define XASH_SIMD_NEON 1
#include <arm_neon.h>
#include "neon_mathfun.h"
#endif
/*
====================
@ -23,59 +17,8 @@ AngleMatrix
====================
*/
#if XASH_SIMD_NEON
const uint32x4_t AngleMatrix_sign0 = vreinterpretq_f32_u32(vsetq_lane_u32(0x80000000, vdupq_n_u32(0), 0));
const uint32x4_t AngleMatrix_sign1 = vreinterpretq_f32_u32(vsetq_lane_u32(0x80000000, vdupq_n_u32(0), 1));
const uint32x4_t AngleMatrix_sign2 = vreinterpretq_f32_u32(vsetq_lane_u32(0x80000000, vdupq_n_u32(0), 2));
#endif
void AngleMatrix( const float *angles, float (*matrix)[4] )
{
#if XASH_SIMD_NEON
float32x4x3_t out_reg;
float32x4_t angles_reg = {};
memcpy(&angles_reg, angles, sizeof(float) * 3);
float32x4x2_t sp_sy_sr_0_cp_cy_cr_1;
sincos_ps(vmulq_n_f32(angles_reg, (M_PI * 2 / 360)), &sp_sy_sr_0_cp_cy_cr_1.val[0], &sp_sy_sr_0_cp_cy_cr_1.val[1]);
float32x4x2_t sp_sr_cp_cr_sy_0_cy_1 = vuzpq_f32(sp_sy_sr_0_cp_cy_cr_1.val[0], sp_sy_sr_0_cp_cy_cr_1.val[1]);
float32x4x2_t sp_cp_sy_cy_sr_cr_0_1 = vzipq_f32(sp_sy_sr_0_cp_cy_cr_1.val[0], sp_sy_sr_0_cp_cy_cr_1.val[1]);
float32x4_t _0_sr_cr_0 = vextq_f32(sp_sy_sr_0_cp_cy_cr_1.val[0], sp_cp_sy_cy_sr_cr_0_1.val[1], 3);
float32x4_t cp_cr_sr_0 = vcombine_f32(vget_high_f32(sp_sr_cp_cr_sy_0_cy_1.val[0]), vget_high_f32(sp_sy_sr_0_cp_cy_cr_1.val[0]));
float32x4_t cy_sy_sy_0 = vcombine_f32(vrev64_f32(vget_high_f32(sp_cp_sy_cy_sr_cr_0_1.val[0])), vget_low_f32(sp_sr_cp_cr_sy_0_cy_1.val[1]));
float32x4_t sy_cy_cy_1 = vcombine_f32(vget_high_f32(sp_cp_sy_cy_sr_cr_0_1.val[0]), vget_high_f32(sp_sr_cp_cr_sy_0_cy_1.val[1]));
float32x4_t _0_srsp_crsp_0 = vmulq_laneq_f32(_0_sr_cr_0, sp_sy_sr_0_cp_cy_cr_1.val[0], 0); // *sp
out_reg.val[0] = vmulq_laneq_f32(_0_srsp_crsp_0, sp_sy_sr_0_cp_cy_cr_1.val[1], 1); // *cy
out_reg.val[1] = vmulq_laneq_f32(_0_srsp_crsp_0, sp_sy_sr_0_cp_cy_cr_1.val[0], 1); // *sy
cy_sy_sy_0 = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(cy_sy_sy_0), AngleMatrix_sign1));
sy_cy_cy_1 = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(sy_cy_cy_1), AngleMatrix_sign2));
out_reg.val[0] = vfmaq_f32(out_reg.val[0], cp_cr_sr_0, cy_sy_sy_0);
out_reg.val[1] = vfmaq_f32(out_reg.val[1], cp_cr_sr_0, sy_cy_cy_1);
float32x4_t cp_cr_0_1 = vcombine_f32(vget_high_f32(sp_sr_cp_cr_sy_0_cy_1.val[0]), vget_high_f32(sp_cp_sy_cy_sr_cr_0_1.val[1]));
float32x4_t _1_cp_cr_0 = vextq_f32(cp_cr_0_1, cp_cr_0_1, 3);
out_reg.val[2] = vmulq_f32(sp_sr_cp_cr_sy_0_cy_1.val[0], _1_cp_cr_0);
out_reg.val[2] = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(out_reg.val[2]), AngleMatrix_sign0));
memcpy(matrix, &out_reg, sizeof(float) * 3 * 4);
/*
matrix[0][0] = cp*cy;
matrix[0][1] = sr*sp*cy-cr*sy;
matrix[0][2] = cr*sp*cy+sr*sy;
matrix[0][3] = 0.0;
matrix[1][0] = cp*sy;
matrix[1][1] = sr*sp*sy+cr*cy;
matrix[1][2] = cr*sp*sy-sr*cy;
matrix[1][3] = 0.0;
matrix[2][0] = -sp*1;
matrix[2][1] = sr*cp;
matrix[2][2] = cp*cr;
matrix[2][3] = cr*0;
*/
#else
float angle;
float sr, sp, sy, cr, cp, cy;
@ -102,7 +45,6 @@ void AngleMatrix( const float *angles, float (*matrix)[4] )
matrix[0][3] = 0.0f;
matrix[1][3] = 0.0f;
matrix[2][3] = 0.0f;
#endif
}
/*
@ -113,13 +55,6 @@ VectorCompare
*/
int VectorCompare( const float *v1, const float *v2 )
{
#if XASH_SIMD_NEON
// is this really works?
float32x4_t v1_reg = {}, v2_reg = {};
memcpy(&v1_reg, v1, sizeof(float) * 3);
memcpy(&v2_reg, v2, sizeof(float) * 3);
return !vaddvq_u32(vceqq_f32(v1_reg, v2_reg));
#else
int i;
for( i = 0; i < 3; i++ )
@ -127,7 +62,6 @@ int VectorCompare( const float *v1, const float *v2 )
return 0;
return 1;
#endif
}
/*
@ -138,23 +72,9 @@ CrossProduct
*/
void CrossProduct( const float *v1, const float *v2, float *cross )
{
#if XASH_SIMD_NEON
float32x4_t v1_reg = {}, v2_reg = {};
memcpy(&v1_reg, v1, sizeof(float) * 3);
memcpy(&v2_reg, v2, sizeof(float) * 3);
float32x4_t yzxy_a = vextq_f32(vextq_f32(v1_reg, v1_reg, 3), v1_reg, 2); // [aj, ak, ai, aj]
float32x4_t yzxy_b = vextq_f32(vextq_f32(v2_reg, v2_reg, 3), v2_reg, 2); // [bj, bk, bi, bj]
float32x4_t zxyy_a = vextq_f32(yzxy_a, yzxy_a, 1); // [ak, ai, aj, aj]
float32x4_t zxyy_b = vextq_f32(yzxy_b, yzxy_b, 1); // [bk, ai, bj, bj]
float32x4_t cross_reg = vfmsq_f32(vmulq_f32(yzxy_a, zxyy_b), zxyy_a, yzxy_b); // [ajbk-akbj, akbi-aibk, aibj-ajbi, 0]
memcpy(cross, &cross_reg, sizeof(float) * 3);
#else
cross[0] = v1[1] * v2[2] - v1[2] * v2[1];
cross[1] = v1[2] * v2[0] - v1[0] * v2[2];
cross[2] = v1[0] * v2[1] - v1[1] * v2[0];
#endif
}
/*
@ -165,26 +85,9 @@ VectorTransform
*/
void VectorTransform( const float *in1, float in2[3][4], float *out )
{
#if XASH_SIMD_NEON
float32x4_t in1_reg = {};
memcpy(&in1_reg, &in1, sizeof(float) * 3);
float32x4x4_t in_t;
memcpy(&in_t, &in2, sizeof(float) * 3 * 4);
//memset(&in_t.val[3], 0, sizeof(in_t.val[3]));
in_t = vld4q_f32((const float*)&in_t);
float32x4_t out_reg = in_t.val[3];
out_reg = vfmaq_laneq_f32(out_reg, in_t.val[0], in1_reg, 0);
out_reg = vfmaq_laneq_f32(out_reg, in_t.val[1], in1_reg, 1);
out_reg = vfmaq_laneq_f32(out_reg, in_t.val[2], in1_reg, 2);
memcpy(out, &out_reg, sizeof(float) * 3);
#else
out[0] = DotProduct(in1, in2[0]) + in2[0][3];
out[1] = DotProduct(in1, in2[1]) + in2[1][3];
out[2] = DotProduct(in1, in2[2]) + in2[2][3];
#endif
}
/*
@ -195,29 +98,6 @@ ConcatTransforms
*/
void ConcatTransforms( float in1[3][4], float in2[3][4], float out[3][4] )
{
#if XASH_SIMD_NEON
float32x4x3_t in1_reg, in2_reg;
memcpy(&in1_reg, in1, sizeof(float) * 3 * 4);
memcpy(&in2_reg, in2, sizeof(float) * 3 * 4);
float32x4x3_t out_reg = {};
out_reg.val[0] = vcopyq_laneq_f32(out_reg.val[0], 3, in1_reg.val[0], 3); // out[0][3] = in[0][3]
out_reg.val[0] = vfmaq_laneq_f32(out_reg.val[0], in2_reg.val[0], in1_reg.val[0], 0); // out[0][n] += in2[0][n] * in1[0][0]
out_reg.val[0] = vfmaq_laneq_f32(out_reg.val[0], in2_reg.val[1], in1_reg.val[0], 1); // out[0][n] += in2[1][n] * in1[0][1]
out_reg.val[0] = vfmaq_laneq_f32(out_reg.val[0], in2_reg.val[2], in1_reg.val[0], 2); // out[0][n] += in2[2][n] * in1[0][2]
out_reg.val[1] = vcopyq_laneq_f32(out_reg.val[1], 3, in1_reg.val[1], 3);
out_reg.val[1] = vfmaq_laneq_f32(out_reg.val[1], in2_reg.val[0], in1_reg.val[1], 0);
out_reg.val[1] = vfmaq_laneq_f32(out_reg.val[1], in2_reg.val[1], in1_reg.val[1], 1);
out_reg.val[1] = vfmaq_laneq_f32(out_reg.val[1], in2_reg.val[2], in1_reg.val[1], 2);
out_reg.val[2] = vcopyq_laneq_f32(out_reg.val[2], 3, in1_reg.val[2], 3);
out_reg.val[2] = vfmaq_laneq_f32(out_reg.val[2], in2_reg.val[0], in1_reg.val[2], 0);
out_reg.val[2] = vfmaq_laneq_f32(out_reg.val[2], in2_reg.val[1], in1_reg.val[2], 1);
out_reg.val[2] = vfmaq_laneq_f32(out_reg.val[2], in2_reg.val[2], in1_reg.val[2], 2);
memcpy(&out, &out_reg, sizeof(out));
#else
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
in1[0][2] * in2[2][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
@ -242,7 +122,6 @@ void ConcatTransforms( float in1[3][4], float in2[3][4], float out[3][4] )
in1[2][2] * in2[2][2];
out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
in1[2][2] * in2[2][3] + in1[2][3];
#endif
}
// angles index are not the same as ROLL, PITCH, YAW
@ -253,36 +132,8 @@ AngleQuaternion
====================
*/
#if XASH_SIMD_NEON
const float32x4_t AngleQuaternion_sign2 = vzipq_f32(vdupq_n_u32(0x80000000), vdupq_n_u32(0x00000000)).val[0]; // { 0x80000000, 0x00000000, 0x80000000, 0x00000000 };
#endif
void AngleQuaternion( float *angles, vec4_t quaternion )
{
#if XASH_SIMD_NEON
float32x4_t angles_reg = {};
memcpy(&angles_reg, angles, sizeof(float) * 3);
float32x4x2_t sr_sp_sy_0_cr_cp_cy_1;
sincos_ps(vmulq_n_f32(angles_reg, 0.5), &sr_sp_sy_0_cr_cp_cy_1.val[0], &sr_sp_sy_0_cr_cp_cy_1.val[1]);
float32x4x2_t sr_sy_cr_cy_sp_0_cp_1 = vuzpq_f32(sr_sp_sy_0_cr_cp_cy_1.val[0], sr_sp_sy_0_cr_cp_cy_1.val[1]);
float32x4_t cp_cp_cp_cp = vdupq_laneq_f32(sr_sp_sy_0_cr_cp_cy_1.val[1], 1);
float32x4_t sp_sp_sp_sp = vdupq_laneq_f32(sr_sp_sy_0_cr_cp_cy_1.val[0], 1);
float32x4_t sr_sy_cr_cy = sr_sy_cr_cy_sp_0_cp_1.val[0];
float32x4_t sy_cr_cy_sr = vextq_f32(sr_sy_cr_cy_sp_0_cp_1.val[0], sr_sy_cr_cy_sp_0_cp_1.val[0], 1);
float32x4_t cr_cy_sr_sy = vextq_f32(sr_sy_cr_cy_sp_0_cp_1.val[0], sr_sy_cr_cy_sp_0_cp_1.val[0], 2);
float32x4_t cy_sr_sy_cr = vextq_f32(sr_sy_cr_cy_sp_0_cp_1.val[0], sr_sy_cr_cy_sp_0_cp_1.val[0], 3);
float32x4_t sp_sp_sp_sp_signed = veorq_u32(sp_sp_sp_sp, AngleQuaternion_sign2);
float32x4_t left = vmulq_f32(vmulq_f32(sr_sy_cr_cy, cp_cp_cp_cp), cy_sr_sy_cr);
float32x4_t out_reg = vfmaq_f32(left, vmulq_f32(cr_cy_sr_sy, sp_sp_sp_sp_signed), sy_cr_cy_sr);
memcpy(quaternion, &out_reg, sizeof(float) * 4);
//quaternion[0] = sr * cp * cy - cr * sp * sy; // X
//quaternion[1] = sy * cp * sr + cy * sp * cr; // Y
//quaternion[2] = cr * cp * sy - sr * sp * cy; // Z
//quaternion[3] = cy * cp * cr + sy * sp * sr; // W
#else
float angle;
float sr, sp, sy, cr, cp, cy;
@ -301,7 +152,6 @@ void AngleQuaternion( float *angles, vec4_t quaternion )
quaternion[1] = cr * sp * cy + sr * cp * sy; // Y
quaternion[2] = cr * cp * sy - sr * sp * cy; // Z
quaternion[3] = cr * cp * cy + sr * sp * sy; // W
#endif
}
/*
@ -312,37 +162,6 @@ QuaternionSlerp
*/
void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt )
{
#if XASH_SIMD_NEON
float32x4_t p_reg = {}, q_reg = {};
memcpy(&p_reg, p, sizeof(float) * 4);
memcpy(&q_reg, q, sizeof(float) * 4);
// q = (cos(a/2), xsin(a/2), ysin(a/2), zsin(a/2))
// cos(a-b) = cosacosb+sinasinb
const uint32x4_t signmask = vdupq_n_u32(0x80000000);
const float32x4_t one_minus_epsilon = vdupq_n_f32(1.0f - 0.00001f);
float32x4_t vcosom = vdupq_n_f32(DotProduct(p, q));
uint32x4_t sign = vandq_u32(vreinterpretq_u32_f32(vcosom), signmask);
q_reg = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(p_reg), sign));
vcosom = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(vcosom), sign));
float x[4] = {(1.0f - t), t, 1, 0}; // cosom -> 1, sinom -> 0, sinx ~ x
float32x4_t x_reg;
memcpy(&x_reg, x, sizeof(float) * 4);
// if ((1.0 - cosom) > 0.000001) x = sin(x * omega)
uint32x4_t cosom_less_then_one = vcltq_f32(vcosom, one_minus_epsilon);
float32x4_t vomega = acos_ps(vcosom);
x_reg = vbslq_f32(cosom_less_then_one, x_reg, sin_ps(vmulq_f32(x_reg, vomega)));
// qt = (x[0] * p + x[1] * q) / x[2];
float32x4_t qt_reg = vmulq_laneq_f32(p_reg, x_reg, 0);
qt_reg = vfmaq_laneq_f32(qt_reg, q_reg, x_reg, 1);
qt_reg = vdivq_f32(qt_reg, vdupq_laneq_f32(x_reg, 2)); // vdivq_laneq_f32 ?
memcpy(qt, &qt_reg, sizeof(float) * 4);
#else
int i;
float omega, cosom, sinom, sclp, sclq;
@ -397,7 +216,6 @@ void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt )
qt[i] = sclp * p[i] + sclq * qt[i];
}
}
#endif
}
/*
@ -406,60 +224,8 @@ QuaternionMatrix
====================
*/
#if XASH_SIMD_NEON
const uint32x4_t QuaternionMatrix_sign1 = vsetq_lane_u32(0x80000000, vdupq_n_u32(0x00000000), 0); // { 0x80000000, 0x00000000, 0x00000000, 0x00000000 };
const uint32x4_t QuaternionMatrix_sign2 = vsetq_lane_u32(0x80000000, vdupq_n_u32(0x00000000), 1); // { 0x00000000, 0x80000000, 0x00000000, 0x00000000 };
const uint32x4_t QuaternionMatrix_sign3 = vsetq_lane_u32(0x00000000, vdupq_n_u32(0x80000000), 2); // { 0x80000000, 0x80000000, 0x00000000, 0x80000000 };
const float32x4_t matrix3x4_identity_0 = vsetq_lane_f32(1, vdupq_n_f32(0), 0); // { 1, 0, 0, 0 }
const float32x4_t matrix3x4_identity_1 = vsetq_lane_f32(1, vdupq_n_f32(0), 1); // { 0, 1, 0, 0 }
const float32x4_t matrix3x4_identity_2 = vsetq_lane_f32(1, vdupq_n_f32(0), 2); // { 0, 0, 1, 0 }
#endif
void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] )
{
#if XASH_SIMD_NEON
float32x4_t quaternion_reg;
memcpy(&quaternion_reg, quaternion, sizeof(float) * 4);
float32x4_t q1032 = vrev64q_f32(quaternion_reg);
float32x4_t q1032_signed = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(q1032), QuaternionMatrix_sign1));
float32x4_t q2301 = vextq_f32(quaternion_reg, quaternion_reg, 2);
float32x4_t q2301_signed = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(q2301), QuaternionMatrix_sign3));
float32x4_t q3210 = vrev64q_f32(q2301);
float32x4_t q3210_signed = vreinterpretq_f32_u32(veorq_u32(vreinterpretq_u32_f32(q3210), QuaternionMatrix_sign2));
float32x4x3_t out_reg;
out_reg.val[0] = vmulq_laneq_f32(q2301_signed, quaternion_reg, 2);
out_reg.val[0] = vfmaq_laneq_f32(out_reg.val[0], q1032_signed, quaternion_reg, 1);
out_reg.val[0] = vfmaq_n_f32(matrix3x4_identity_0, out_reg.val[0], 2.0f);
out_reg.val[1] = vmulq_laneq_f32(q3210_signed, quaternion_reg, 2);
out_reg.val[1] = vfmsq_laneq_f32(out_reg.val[1], q1032_signed, quaternion_reg, 0);
out_reg.val[1] = vfmaq_n_f32(matrix3x4_identity_1, out_reg.val[1], 2.0f);
out_reg.val[2] = vmulq_laneq_f32(q3210_signed, quaternion_reg, 1);
out_reg.val[2] = vfmaq_laneq_f32(out_reg.val[2], q2301_signed, quaternion_reg, 0);
out_reg.val[2] = vfmsq_n_f32(matrix3x4_identity_2, out_reg.val[2], 2.0f);
memcpy(matrix, &out_reg, sizeof(float) * 3 * 4);
/*
matrix[0][0] = 1.0 + 2.0 * ( quaternion[1] * -quaternion[1] + -quaternion[2] * quaternion[2] );
matrix[0][1] = 0.0 + 2.0 * ( quaternion[1] * quaternion[0] + -quaternion[3] * quaternion[2] );
matrix[0][2] = 0.0 + 2.0 * ( quaternion[1] * quaternion[3] + quaternion[0] * quaternion[2] );
matrix[0][3] = 0.0 + 2.0 * ( quaternion[1] * quaternion[2] + -quaternion[1] * quaternion[2] );
matrix[1][0] = 0.0 + 2.0 * ( -quaternion[0] * -quaternion[1] + quaternion[3] * quaternion[2] );
matrix[1][1] = 1.0 + 2.0 * ( -quaternion[0] * quaternion[0] + -quaternion[2] * quaternion[2] );
matrix[1][2] = 0.0 + 2.0 * ( -quaternion[0] * quaternion[3] + quaternion[1] * quaternion[2] );
matrix[1][3] = 0.0 + 2.0 * ( -quaternion[0] * quaternion[2] + quaternion[0] * quaternion[2] );
matrix[2][0] = 0.0 + 2.0 * ( -quaternion[0] * -quaternion[2] + -quaternion[3] * quaternion[1] );
matrix[2][1] = 0.0 + 2.0 * ( -quaternion[0] * -quaternion[3] + quaternion[2] * quaternion[1] );
matrix[2][2] = 1.0 + 2.0 * ( -quaternion[0] * quaternion[0] + -quaternion[1] * quaternion[1] );
matrix[2][3] = 0.0 + 2.0 * ( -quaternion[0] * -quaternion[1] + -quaternion[0] * quaternion[1] );
*/
#else
matrix[0][0] = 1.0f - 2.0f * quaternion[1] * quaternion[1] - 2.0f * quaternion[2] * quaternion[2];
matrix[1][0] = 2.0f * quaternion[0] * quaternion[1] + 2.0f * quaternion[3] * quaternion[2];
matrix[2][0] = 2.0f * quaternion[0] * quaternion[2] - 2.0f * quaternion[3] * quaternion[1];
@ -471,7 +237,6 @@ void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] )
matrix[0][2] = 2.0f * quaternion[0] * quaternion[2] + 2.0f * quaternion[3] * quaternion[1];
matrix[1][2] = 2.0f * quaternion[1] * quaternion[2] - 2.0f * quaternion[3] * quaternion[0];
matrix[2][2] = 1.0f - 2.0f * quaternion[0] * quaternion[0] - 2.0f * quaternion[1] * quaternion[1];
#endif
}
/*

View File

@ -933,7 +933,7 @@ void CBigMomma::StartTask( Task_t *pTask )
TaskComplete();
break;
case TASK_WAIT_NODE:
m_flWaitFinished = gpGlobals->time + GetNodeDelay();
m_flWait = gpGlobals->time + GetNodeDelay();
if( m_hTargetEnt->pev->spawnflags & SF_INFOBM_WAIT )
ALERT( at_aiconsole, "BM: Wait at node %s forever\n", STRING( pev->netname ) );
else

View File

@ -7,18 +7,19 @@
#include "monsters.h"
#include "player.h"
#include "soundent.h"
#include "decals.h"
class CMortarShell : public CGrenade
{
public:
void Precache();
void BurnThink();
void MortarExplodeTouch(CBaseEntity *pOther);
void EXPORT BurnThink();
void EXPORT MortarExplodeTouch(CBaseEntity *pOther);
void Spawn();
void FlyThink();
void EXPORT FlyThink();
int Save(CSave &save);
int Restore(CRestore &restore);
static CMortarShell *CreateMortarShell(Vector p_VecOrigin, Vector p_VecAngles, CBaseEntity *pOwner, int velocity);
static CMortarShell *CreateMortarShell(Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, int velocity);
static TYPEDESCRIPTION m_SaveData[];
int m_iTrail;
@ -48,114 +49,123 @@ void CMortarShell::Precache()
void CMortarShell::Spawn()
{
Precache();
SET_MODEL(ENT(pev), "models/mortarshell.mdl");
UTIL_SetSize(pev, g_vecZero, g_vecZero);
pev->solid = SOLID_BBOX;
pev->movetype = MOVETYPE_BOUNCE;
pev->solid = SOLID_BBOX;
SET_MODEL(edict(), "models/mortarshell.mdl");
UTIL_SetSize(pev, g_vecZero, g_vecZero);
UTIL_SetOrigin(pev, pev->origin);
pev->classname = MAKE_STRING("mortar_shell");
SetThink(&CMortarShell::BurnThink);
SetTouch(&CMortarShell::MortarExplodeTouch);
pev->dmg = gSkillData.plrDmgRPG*2;
pev->nextthink = gpGlobals->time + 0.1;
UTIL_MakeVectors(pev->angles);
pev->velocity = -(gpGlobals->v_forward * m_velocity);
pev->gravity = 1;
pev->dmg = gSkillData.plrDmgRPG * 2;
pev->nextthink = gpGlobals->time + 0.01;
m_flIgniteTime = gpGlobals->time;
m_iSoundedOff = FALSE;
}
void CMortarShell::MortarExplodeTouch(CBaseEntity *pOther)
{
pev->enemy = pOther->edict();
const Vector direction = pev->velocity.Normalize();
const Vector vecSpot = pev->origin - direction * 32;
TraceResult tr;
Vector vecSpot;
UTIL_TraceLine(vecSpot, vecSpot + direction * 64, ignore_monsters, edict(), &tr);
pev->model = iStringNull;//invisible
pev->solid = SOLID_NOT;// intangible
pev->model = 0;
pev->solid = SOLID_NOT;
pev->takedamage = DAMAGE_NO;
vecSpot = pev->origin + Vector( 0, 0, 8 );
UTIL_TraceLine( vecSpot, vecSpot + Vector( 0, 0, -40 ), ignore_monsters, dont_ignore_glass, ENT(pev), &tr );
// Pull out of the wall a bit
if( tr.flFraction != 1.0 )
if (tr.flFraction != 1.0f)
{
pev->origin = tr.vecEndPos + ( tr.vecPlaneNormal * ( pev->dmg - 24 ) * 0.6 );
pev->origin = 0.6f * ((pev->dmg - 24.0f) * tr.vecPlaneNormal) + tr.vecEndPos;
}
int iContents = UTIL_PointContents( pev->origin );
const int contents = UTIL_PointContents(pev->origin);
MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, pev->origin );
WRITE_BYTE( TE_EXPLOSION ); // This makes a dynamic light and the explosion sprites/sound
WRITE_COORD( pev->origin.x ); // Send to PAS because of the sound
WRITE_COORD( pev->origin.y );
WRITE_COORD( pev->origin.z );
if( iContents != CONTENTS_WATER )
{
WRITE_SHORT( g_sModelIndexFireball );
}
MESSAGE_BEGIN(MSG_PAS, SVC_TEMPENTITY, pev->origin);
WRITE_BYTE(TE_EXPLOSION);
WRITE_COORD(pev->origin.x);
WRITE_COORD(pev->origin.y);
WRITE_COORD(pev->origin.z);
if (contents == CONTENTS_WATER)
WRITE_SHORT(g_sModelIndexWExplosion);
else
{
WRITE_SHORT( g_sModelIndexWExplosion );
}
WRITE_BYTE( (pev->dmg - 50) * 5); // scale * 10
WRITE_BYTE( 10 ); // framerate
WRITE_BYTE( TE_EXPLFLAG_NONE );
WRITE_SHORT(g_sModelIndexFireball);
WRITE_BYTE(static_cast<int>((pev->dmg - 50.0) * 5.0));
WRITE_BYTE(10);
WRITE_BYTE(TE_EXPLFLAG_NONE);
MESSAGE_END();
CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 );
entvars_t *pevOwner;
if( pev->owner )
pevOwner = VARS( pev->owner );
CSoundEnt::InsertSound(bits_SOUND_COMBAT, pev->origin, 1024, 3.0);
entvars_t* pOwner = VARS(pev->owner);
pev->owner = NULL;
RadiusDamage(pev, pOwner, pev->dmg, CLASS_NONE, 64);
if (RANDOM_FLOAT(0, 1) >= 0.5)
UTIL_DecalTrace(&tr, DECAL_SCORCH2);
else
pevOwner = NULL;
UTIL_DecalTrace(&tr, DECAL_SCORCH1);
pev->owner = NULL; // can't traceline attack owner if this is set
RadiusDamage( pev, pevOwner, pev->dmg, CLASS_NONE, DMG_BLAST );
if( RANDOM_FLOAT( 0, 1 ) < 0.5 )
{
UTIL_DecalTrace( &tr, 11 );
}
else
{
UTIL_DecalTrace( &tr, 12 );
}
switch( RANDOM_LONG( 0, 2 ) )
switch (RANDOM_LONG(0, 2))
{
case 0:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/debris1.wav", 0.55, ATTN_NORM );
EMIT_SOUND(edict(), CHAN_VOICE, "weapons/debris1.wav", 0.55, ATTN_NORM);
break;
case 1:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/debris2.wav", 0.55, ATTN_NORM );
EMIT_SOUND(edict(), CHAN_VOICE, "weapons/debris2.wav", 0.55, ATTN_NORM);
break;
case 2:
EMIT_SOUND( ENT( pev ), CHAN_VOICE, "weapons/debris3.wav", 0.55, ATTN_NORM );
EMIT_SOUND(edict(), CHAN_VOICE, "weapons/debris3.wav", 0.55, ATTN_NORM);
break;
}
pev->effects |= EF_NODRAW;
SetThink( &CGrenade::Smoke );
SetThink(&CMortarShell::Smoke);
pev->velocity = g_vecZero;
pev->nextthink = gpGlobals->time + 0.3;
if( iContents != CONTENTS_WATER )
if (contents != CONTENTS_WATER)
{
int sparkCount = RANDOM_LONG( 0, 3 );
for( int i = 0; i < sparkCount; i++ )
Create( "spark_shower", pev->origin, tr.vecPlaneNormal, NULL );
const int sparkCount = RANDOM_LONG(0, 3);
for (int i = 0; i < sparkCount; ++i)
{
CBaseEntity::Create("spark_shower", pev->origin, tr.vecPlaneNormal);
}
}
}
void CMortarShell::BurnThink()
{
UTIL_VecToAngles(pev->velocity);
pev->angles = pev->velocity;
pev->angles = UTIL_VecToAngles(pev->velocity);
pev->angles.x -= 90;
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin);
WRITE_BYTE(110);
WRITE_BYTE(TE_SPRITE_SPRAY);
WRITE_COORD(pev->origin.x);
WRITE_COORD(pev->origin.y);
WRITE_COORD(pev->origin.z);
@ -168,8 +178,10 @@ void CMortarShell::BurnThink()
WRITE_BYTE(120);
MESSAGE_END();
if(!((m_flIgniteTime + 0.2) >= gpGlobals->time))
if (gpGlobals->time > m_flIgniteTime + 0.2)
{
SetThink(&CMortarShell::FlyThink);
}
pev->nextthink = gpGlobals->time + 0.01;
}
@ -177,36 +189,35 @@ void CMortarShell::BurnThink()
void CMortarShell::FlyThink()
{
pev->angles = UTIL_VecToAngles(pev->velocity);
pev->angles.x -= 90;
pev->angles.x -= 90.0f;
if(pev->velocity.z < 20 && !m_iSoundedOff)
if(pev->velocity.z < 20.0f && !m_iSoundedOff)
{
m_iSoundedOff = TRUE;
EMIT_SOUND_DYN(ENT(pev), 2, "weapons/ofmortar.wav", 1, 0, 0, 100);
EMIT_SOUND(ENT(pev), CHAN_VOICE, "weapons/ofmortar.wav", RANDOM_FLOAT(0.8, 0.9), ATTN_NONE);
}
pev->nextthink = gpGlobals->time + 0.1;
}
CMortarShell *CMortarShell::CreateMortarShell(Vector p_VecOrigin, Vector p_VecAngles, CBaseEntity *pOwner, int velocity)
CMortarShell *CMortarShell::CreateMortarShell(Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, int velocity)
{
CMortarShell *rocket = GetClassPtr( (CMortarShell *)NULL );
rocket->Spawn();
CMortarShell *pShell = GetClassPtr( (CMortarShell *)NULL );
UTIL_SetOrigin(pShell->pev, vecOrigin);
rocket->pev->gravity = 1;
UTIL_SetOrigin( rocket->pev, p_VecOrigin );
rocket->pev->angles = UTIL_VecToAngles(p_VecAngles);
UTIL_MakeVectors(p_VecAngles);
rocket->pev->velocity = rocket->pev->velocity - gpGlobals->v_forward * velocity;
if (pOwner)
rocket->pev->owner = ENT(pOwner->pev);
pShell->pev->angles = vecAngles;
pShell->m_velocity = velocity;
return rocket;
pShell->Spawn();
pShell->pev->owner = pOwner->edict();
return pShell;
}
#define SF_MORTAR_ACTIVE (1 << 0)
#define SF_MORTAR_LINE_OF_SIGHT (1 << 4)
#define SF_MORTAR_CAN_CONTROL (1 << 5)
#define SF_MORTAR_CONTROLLABLE (1 << 5)
class COp4Mortar : public CBaseMonster
{
@ -224,44 +235,56 @@ public:
void EXPORT MortarThink();
static TYPEDESCRIPTION m_SaveData[];
int ObjectCaps() { return 0; }
void PlaySound();
float m_FireDelay;
BOOL m_tracking;
float m_minRange;
float m_maxRange;
float m_lastupdate;
float m_zeroYaw;
float m_lastFire;
float m_trackDelay;
float m_flExplodeTime;
int m_hmax;
int m_hmin;
int d_x;
int d_y;
float m_lastupdate;
int m_direction;
Vector m_start;
Vector m_end;
int m_velocity;
int m_hmin;
int m_hmax;
float m_fireLast;
float m_maxRange;
float m_minRange;
int m_iEnemyType;
int m_iUpdateTime;
float m_fireDelay;
float m_trackDelay;
BOOL m_tracking;
float m_zeroYaw;
Vector m_vGunAngle;
Vector m_vIdealGunVector;
Vector m_vIdealGunAngle;
float m_lastTimePlayedSound;
};
LINK_ENTITY_TO_CLASS(op4mortar, COp4Mortar)
TYPEDESCRIPTION COp4Mortar::m_SaveData[] =
{
DEFINE_FIELD( COp4Mortar, m_tracking, FIELD_BOOLEAN ),
DEFINE_FIELD( COp4Mortar, m_FireDelay, FIELD_FLOAT ),
DEFINE_FIELD( COp4Mortar, m_minRange, FIELD_FLOAT),
DEFINE_FIELD( COp4Mortar, m_maxRange, FIELD_FLOAT ),
DEFINE_FIELD( COp4Mortar, m_lastFire, FIELD_FLOAT),
DEFINE_FIELD( COp4Mortar, m_trackDelay, FIELD_FLOAT ),
DEFINE_FIELD( COp4Mortar, m_hmax, FIELD_INTEGER ),
DEFINE_FIELD( COp4Mortar, m_hmin, FIELD_INTEGER ),
DEFINE_FIELD( COp4Mortar, m_velocity, FIELD_INTEGER ),
DEFINE_FIELD( COp4Mortar, m_iEnemyType, FIELD_INTEGER ),
DEFINE_FIELD( COp4Mortar, m_vGunAngle, FIELD_VECTOR ),
DEFINE_FIELD(COp4Mortar, d_x, FIELD_INTEGER),
DEFINE_FIELD(COp4Mortar, d_y, FIELD_INTEGER),
DEFINE_FIELD(COp4Mortar, m_lastupdate, FIELD_FLOAT),
DEFINE_FIELD(COp4Mortar, m_direction, FIELD_INTEGER),
DEFINE_FIELD(COp4Mortar, m_start, FIELD_VECTOR),
DEFINE_FIELD(COp4Mortar, m_end, FIELD_VECTOR),
DEFINE_FIELD(COp4Mortar, m_velocity, FIELD_INTEGER),
DEFINE_FIELD(COp4Mortar, m_hmin, FIELD_INTEGER),
DEFINE_FIELD(COp4Mortar, m_hmax, FIELD_INTEGER),
DEFINE_FIELD(COp4Mortar, m_fireLast, FIELD_FLOAT),
DEFINE_FIELD(COp4Mortar, m_maxRange, FIELD_FLOAT),
DEFINE_FIELD(COp4Mortar, m_minRange, FIELD_FLOAT),
DEFINE_FIELD(COp4Mortar, m_iEnemyType, FIELD_INTEGER),
DEFINE_FIELD(COp4Mortar, m_fireDelay, FIELD_FLOAT),
DEFINE_FIELD(COp4Mortar, m_trackDelay, FIELD_FLOAT),
DEFINE_FIELD(COp4Mortar, m_tracking, FIELD_BOOLEAN),
DEFINE_FIELD(COp4Mortar, m_zeroYaw, FIELD_FLOAT),
DEFINE_FIELD(COp4Mortar, m_vGunAngle, FIELD_VECTOR),
DEFINE_FIELD(COp4Mortar, m_vIdealGunVector, FIELD_VECTOR),
DEFINE_FIELD(COp4Mortar, m_vIdealGunAngle, FIELD_VECTOR),
};
IMPLEMENT_SAVERESTORE( COp4Mortar, CBaseMonster )
@ -277,85 +300,120 @@ void COp4Mortar::Precache()
void COp4Mortar::Spawn()
{
float angle;
Precache();
UTIL_SetOrigin(pev, pev->origin);
SET_MODEL(ENT(pev), "models/mortar.mdl");
UTIL_SetOrigin(pev, pev->origin);
SET_MODEL(edict(), "models/mortar.mdl");
pev->health = 1;
pev->sequence = LookupSequence("idle");
ResetSequenceInfo();
pev->frame = 0;
pev->framerate = 1;
m_tracking = FALSE;
m_lastupdate = gpGlobals->time + 0.5;
m_vGunAngle = Vector(0,0,0);
m_iUpdateTime = 0;
if(m_FireDelay < 0.5)
m_FireDelay = 5;
if (m_fireDelay < 0.5)
m_fireDelay = 5;
if(m_minRange == 0)
if (m_minRange == 0)
m_minRange = 128;
if(m_maxRange == 0)
m_maxRange = 3072;
if (m_maxRange == 0)
m_maxRange = 2048;
InitBoneControllers();
angle = pev->angles.y + 180;
m_zeroYaw = UTIL_AngleMod(angle);
m_vGunAngle = g_vecZero;
m_lastupdate = gpGlobals->time;
m_zeroYaw = UTIL_AngleMod(pev->angles.y + 180.0);
m_fireLast = gpGlobals->time;
m_trackDelay = gpGlobals->time;
m_hEnemy = NULL;
if (pev->spawnflags & SF_MORTAR_ACTIVE)
SetThink(&COp4Mortar::MortarThink);
else
SetThink(NULL);
pev->nextthink = gpGlobals->time + 0.01;
SetThink(&COp4Mortar::MortarThink);
}
m_flExplodeTime = gpGlobals->time + 5;
pev->nextthink = gpGlobals->time + 0.1;
void COp4Mortar::PlaySound()
{
if (gpGlobals->time > m_lastTimePlayedSound + 0.12f)
{
EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/pl_grate1.wav", 1.0f, ATTN_NORM);
m_lastTimePlayedSound = gpGlobals->time + 0.12f;
}
}
void COp4Mortar::UpdatePosition(float direction, int controller)
{
if(m_vGunAngle.y > 90)
m_vGunAngle.y = 90;
if(m_vGunAngle.y < -90)
m_vGunAngle.y = -90;
if(m_vGunAngle.x > 90)
m_vGunAngle.x = 90;
if(m_vGunAngle.x < 0)
m_vGunAngle.x = 0;
if(controller == 1)
m_vGunAngle.y += direction/2;
else
m_vGunAngle.x += direction/2;
if(m_iUpdateTime >= 15)
if (gpGlobals->time - m_lastupdate >= 0.06)
{
EMIT_SOUND_DYN(ENT(pev), 2, "player/pl_grate1.wav", 1, 0.8, 0, 100);
m_iUpdateTime = 0;
switch (controller)
{
case 0:
d_x = 3 * direction;
break;
case 1:
d_y = 3 * direction;
break;
}
m_vGunAngle.x = d_x + m_vGunAngle.x;
m_vGunAngle.y = d_y + m_vGunAngle.y;
if (m_hmin > m_vGunAngle.y)
{
m_vGunAngle.y = m_hmin;
d_y = 0;
}
if (m_vGunAngle.y > m_hmax)
{
m_vGunAngle.y = m_hmax;
d_y = 0;
}
if (m_vGunAngle.x < 10)
{
m_vGunAngle.x = 10;
d_x = 0;
}
else if (m_vGunAngle.x > 90)
{
m_vGunAngle.x = 90;
d_x = 0;
}
if (0 != d_x || 0 != d_y)
{
PlaySound();
}
SetBoneController(0, m_vGunAngle.x);
SetBoneController(1, m_vGunAngle.y);
d_x = 0;
d_y = 0;
m_lastupdate = gpGlobals->time;
}
SetBoneController(1, m_vGunAngle.y);
SetBoneController(0, m_vGunAngle.x);
m_lastupdate = gpGlobals->time + 0.1;
m_iUpdateTime++;
}
void COp4Mortar::MortarThink()
{
Vector pos, angle, vecTarget;
const float flInterval = StudioFrameAdvance();
if(m_fSequenceFinished)
if (m_fSequenceFinished)
{
if(pev->sequence != LookupSequence("idle"))
if (pev->sequence != LookupSequence("idle"))
{
pev->frame = 0;
pev->sequence = LookupSequence("idle");
@ -363,55 +421,75 @@ void COp4Mortar::MortarThink()
}
}
DispatchAnimEvents();
StudioFrameAdvance();
DispatchAnimEvents(flInterval);
//GlowShellUpdate();
pev->nextthink = gpGlobals->time + 0.1;
if(pev->spawnflags & SF_MORTAR_ACTIVE)
if ((pev->spawnflags & SF_MORTAR_ACTIVE) != 0)
{
if(m_hEnemy == 0 || !m_hEnemy->IsAlive())
if (!m_hEnemy)
{
m_hEnemy = FindTarget();
}
}
if(m_hEnemy != 0)
{
vecTarget = Vector( m_hEnemy->pev->origin.x, m_hEnemy->pev->origin.y, m_hEnemy->pev->absmax.z);
CBaseEntity* pEnemy = m_hEnemy;
if((pev->origin - m_hEnemy->pev->origin).Length() <= m_maxRange)
if (pEnemy)
{
GetAttachment(0, pos, angle);
const float distance = (pEnemy->pev->origin - pev->origin).Length();
m_vIdealGunVector = VecCheckThrow(pev, pos, vecTarget, 700, 1);
m_vIdealGunVector.x =- m_vIdealGunVector.x;
m_vIdealGunVector.y =- m_vIdealGunVector.y;
m_vIdealGunAngle = UTIL_VecToAngles(m_vIdealGunVector);
m_trackDelay = gpGlobals->time;
}
AIUpdatePosition();
}
if(m_hEnemy != 0 && gpGlobals->time - m_lastFire > 5 && (m_hEnemy->pev->origin - pev->origin).Length() > 710)
{
EMIT_SOUND_DYN(ENT(pev), 2, "weapons/mortarhit.wav", 1, 0.8, 0, 100);
UTIL_ScreenShake(pev->origin, 12, 100, 2, 1000);
float speed = m_vIdealGunVector.Length();
angle = m_vIdealGunAngle;
if(speed > 0)
{
if(CMortarShell::CreateMortarShell(pev->origin, angle, this, floor(speed)))
if (pEnemy->IsAlive() && m_minRange <= distance && distance <= m_maxRange)
{
pev->frame = 0;
pev->sequence = LookupSequence("fire");
ResetSequenceInfo();
m_lastFire = gpGlobals->time;
if (gpGlobals->time - m_trackDelay > 0.5)
{
Vector vecPos, vecAngle;
GetAttachment(0, vecPos, vecAngle);
m_vIdealGunVector = VecCheckThrow(pev, vecPos, pEnemy->pev->origin, m_velocity / 2);
m_vIdealGunAngle = UTIL_VecToAngles(m_vIdealGunVector);
m_trackDelay = gpGlobals->time;
}
AIUpdatePosition();
const float idealDistance = m_vIdealGunVector.Length();
if (idealDistance > 1.0)
{
if (gpGlobals->time - m_fireLast > m_fireDelay)
{
EMIT_SOUND(edict(), CHAN_VOICE, "weapons/mortarhit.wav", VOL_NORM, ATTN_NORM);
UTIL_ScreenShake(pev->origin, 12.0, 100.0, 2.0, 1000.0);
Vector vecPos, vecAngle;
GetAttachment(0, vecPos, vecAngle);
vecAngle = m_vGunAngle;
vecAngle.y = UTIL_AngleMod(pev->angles.y + m_vGunAngle.y);
if (CMortarShell::CreateMortarShell(vecPos, vecAngle, this, idealDistance))
{
pev->sequence = LookupSequence("fire");
pev->frame = 0;
ResetSequenceInfo();
}
m_fireLast = gpGlobals->time;
}
}
else
{
m_fireLast = gpGlobals->time;
}
}
else
{
m_hEnemy = NULL;
}
}
}
@ -419,32 +497,102 @@ void COp4Mortar::MortarThink()
CBaseEntity *COp4Mortar::FindTarget()
{
CBaseEntity *pPlayer;
Vector BarretEnd;
Vector BarretAngle;
Vector targetPosition;
TraceResult tr;
CBaseEntity *pIdealTarget = NULL;
CBaseEntity* pPlayerTarget = UTIL_FindEntityByClassname(NULL, "player");
if((pPlayer = UTIL_FindEntityByClassname(0, "player")) == NULL )
return NULL;
if (!pPlayerTarget)
return pPlayerTarget;
m_pLink = 0;
m_pLink = NULL;
GetAttachment(0, BarretEnd, BarretAngle);
CBaseEntity* pIdealTarget = NULL;
float flIdealDist = m_maxRange;
float dist = (pPlayer->pev->origin - pev->origin).Length();
Vector barrelEnd, barrelAngle;
GetAttachment(0, barrelEnd, barrelAngle);
if(pPlayer->IsAlive())
if (pPlayerTarget->IsAlive())
{
if(m_maxRange >= dist)
{
targetPosition = pPlayer->pev->origin + pev->view_ofs;
UTIL_TraceLine(BarretEnd, targetPosition, ignore_monsters, dont_ignore_glass, ENT(pev), &tr);
const float distance = (pPlayerTarget->pev->origin - pev->origin).Length();
if((!(pev->spawnflags & SF_MORTAR_LINE_OF_SIGHT) || tr.pHit == ENT(pPlayer->pev)) && !m_iEnemyType)
if (distance >= m_minRange && m_maxRange >= distance)
{
TraceResult tr;
UTIL_TraceLine(barrelEnd, pPlayerTarget->pev->origin + pPlayerTarget->pev->view_ofs, dont_ignore_monsters, edict(), &tr);
if ((pev->spawnflags & SF_MORTAR_LINE_OF_SIGHT) == 0 || tr.pHit == pPlayerTarget->pev->pContainingEntity)
{
pIdealTarget = pPlayer;
if (0 == m_iEnemyType)
return pPlayerTarget;
flIdealDist = distance;
pIdealTarget = pPlayerTarget;
}
}
}
const Vector maxRange(m_maxRange, m_maxRange, m_maxRange);
CBaseEntity* pList[100];
const int count = UTIL_EntitiesInBox(pList, ARRAYSIZE(pList), pev->origin - maxRange, pev->origin + maxRange, FL_MONSTER | FL_CLIENT);
for (int i = 0; i < count; ++i)
{
CBaseEntity* pEntity = pList[i];
if (this == pEntity)
continue;
if ((pEntity->pev->spawnflags & SF_MONSTER_PRISONER) != 0)
continue;
if (pEntity->pev->health <= 0)
continue;
CBaseMonster* pMonster = pEntity->MyMonsterPointer();
if (!pMonster)
continue;
if (pMonster->IRelationship(pPlayerTarget) != R_AL)
continue;
if ((pEntity->pev->flags & FL_NOTARGET) != 0)
continue;
if (!FVisible(pEntity))
continue;
if (pEntity->IsPlayer() && (pev->spawnflags & SF_MORTAR_ACTIVE) != 0)
{
if (pMonster->FInViewCone(this))
{
pev->spawnflags &= ~SF_MORTAR_ACTIVE;
}
}
}
for (CBaseEntity* pEntity = m_pLink; pEntity; pEntity = pEntity->m_pLink)
{
const float distance = (pEntity->pev->origin - pev->origin).Length();
if (distance >= m_minRange && m_maxRange >= distance && (!pIdealTarget || flIdealDist > distance))
{
TraceResult tr;
UTIL_TraceLine(barrelEnd, pEntity->pev->origin + pEntity->pev->view_ofs, dont_ignore_monsters, edict(), &tr);
if ((pev->spawnflags & SF_MORTAR_LINE_OF_SIGHT) != 0)
{
if (tr.pHit == pEntity->edict())
{
flIdealDist = distance;
}
if (tr.pHit == pEntity->edict())
pIdealTarget = pEntity;
}
else
{
flIdealDist = distance;
pIdealTarget = pEntity;
}
}
}
@ -459,40 +607,40 @@ int COp4Mortar::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, floa
void COp4Mortar::KeyValue(KeyValueData *pvkd)
{
if(strcmp(pvkd->szKeyName, "m_hmax"))
if(FStrEq(pvkd->szKeyName, "h_max"))
{
m_hmax = atoi(pvkd->szValue);
pvkd->fHandled = 1;
pvkd->fHandled = TRUE;
}
else if(strcmp(pvkd->szKeyName, "m_hmin"))
else if(FStrEq(pvkd->szKeyName, "h_min"))
{
m_hmin = atoi(pvkd->szValue);
pvkd->fHandled = 1;
pvkd->fHandled = TRUE;
}
else if(strcmp(pvkd->szKeyName, "mortar_velocity"))
else if(FStrEq(pvkd->szKeyName, "mortar_velocity"))
{
m_velocity = atoi(pvkd->szValue);
pvkd->fHandled = 1;
pvkd->fHandled = TRUE;
}
else if(strcmp(pvkd->szKeyName, "mindist"))
else if(FStrEq(pvkd->szKeyName, "mindist"))
{
m_minRange = atoi(pvkd->szValue);
pvkd->fHandled = 1;
pvkd->fHandled = TRUE;
}
else if(strcmp(pvkd->szKeyName, "maxdist"))
else if(FStrEq(pvkd->szKeyName, "maxdist"))
{
m_maxRange = atoi(pvkd->szValue);
pvkd->fHandled = 1;
pvkd->fHandled = TRUE;
}
else if(strcmp(pvkd->szKeyName, "enemytype"))
else if(FStrEq(pvkd->szKeyName, "enemytype"))
{
m_iEnemyType = atoi(pvkd->szValue);
pvkd->fHandled = 1;
pvkd->fHandled = TRUE;
}
else if(strcmp(pvkd->szKeyName, "firedelay"))
else if(FStrEq(pvkd->szKeyName, "firedelay"))
{
m_FireDelay = atoi(pvkd->szValue);
pvkd->fHandled = 1;
m_fireDelay = atoi(pvkd->szValue);
pvkd->fHandled = TRUE;
}
else
{
@ -502,58 +650,109 @@ void COp4Mortar::KeyValue(KeyValueData *pvkd)
void COp4Mortar::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
SetThink(NULL);
if((pev->spawnflags & SF_MORTAR_CAN_CONTROL) && (pActivator->pev->origin - pev->origin).Length() < 170)
if (useType == USE_TOGGLE && (!pActivator || pActivator->IsPlayer()))
{
EMIT_SOUND_DYN(ENT(pev), 2, "weapons/mortarhit.wav", 1, 0, 0, 100);
UTIL_ScreenShake(pev->origin, 12, 100, 2, 1000);
Vector pos, angle;
GetAttachment(0, pos, angle);
angle = m_vGunAngle;
float anglemod = pev->angles.y + m_vGunAngle.y;
angle.y = UTIL_AngleMod(anglemod);
if((CMortarShell::CreateMortarShell(pos, angle, this, 2000 - (m_vGunAngle.x * 12.25))) != NULL)
if ((pev->spawnflags & SF_MORTAR_ACTIVE) == 0 && (pev->spawnflags & SF_MORTAR_CONTROLLABLE) != 0)
{
pev->frame = 0;
pev->sequence = LookupSequence("fire");
ResetSequenceInfo();
//Player fired a mortar
EMIT_SOUND(edict(), CHAN_VOICE, "weapons/mortarhit.wav", VOL_NORM, ATTN_NONE);
UTIL_ScreenShake(pev->origin, 12.0, 100.0, 2.0, 1000.0);
Vector pos, angle;
GetAttachment(0, pos, angle);
angle = m_vGunAngle;
angle.y = UTIL_AngleMod(pev->angles.y + m_vGunAngle.y);
if (CMortarShell::CreateMortarShell(pos, angle, pActivator ? pActivator : this, m_velocity))
{
pev->sequence = LookupSequence("fire");
pev->frame = 0;
ResetSequenceInfo();
}
return;
}
}
//Toggle AI active state
if (ShouldToggle(useType, (pev->spawnflags & SF_MORTAR_ACTIVE) != 0))
{
pev->spawnflags ^= SF_MORTAR_ACTIVE;
m_fireLast = 0;
m_hEnemy = NULL;
}
}
void COp4Mortar::AIUpdatePosition()
{
if(m_hEnemy != 0 && (m_hEnemy->pev->origin - pev->origin).Length() < 710)
return;
if(m_vIdealGunAngle.x == 270 && m_vIdealGunAngle.y == 0)
if (fabs(m_vGunAngle.x - m_vIdealGunAngle.x) >= 3.0)
{
m_vIdealGunAngle.x = 0;
m_vIdealGunAngle.y = 0;
const float angle = UTIL_AngleDiff(m_vGunAngle.x, m_vIdealGunAngle.x);
if (angle != 0)
{
const float absolute = fabs(angle);
if (absolute <= 3.0)
d_x = static_cast<int>(-absolute);
else
d_x = angle > 0 ? -3 : 3;
}
}
if(m_vIdealGunAngle.x <= 0)
m_vIdealGunAngle.x = 0;
const float yawAngle = UTIL_AngleMod(m_zeroYaw + m_vGunAngle.y);
if(m_vIdealGunAngle.x > 90)
m_vIdealGunAngle.x = 90;
if (fabs(yawAngle - m_vIdealGunAngle.y) >= 3.0)
{
const float angle = UTIL_AngleDiff(yawAngle, m_vIdealGunAngle.y);
if(m_vIdealGunAngle.y > 165 && m_vIdealGunAngle.y < 270)
m_vIdealGunAngle.y = -90;
if (angle != 0)
{
const float absolute = fabs(angle);
if (absolute <= 3.0)
d_y = static_cast<int>(-absolute);
else
d_y = angle > 0 ? -3 : 3;
}
}
else if(m_vIdealGunAngle.y > 90 && m_vIdealGunAngle.y < 165)
m_vIdealGunAngle.y = 90;
m_vGunAngle.x += d_x;
m_vGunAngle.y += d_y;
if (m_hmin > m_vGunAngle.y)
{
m_vGunAngle.y = m_hmin;
d_y = 0;
}
SetBoneController(0, m_vIdealGunAngle.x);
SetBoneController(1, m_vIdealGunAngle.y);
if (m_vGunAngle.y > m_hmax)
{
m_vGunAngle.y = m_hmax;
d_y = 0;
}
m_vGunAngle = m_vIdealGunAngle;
if (m_vGunAngle.x < 10.0)
{
m_vGunAngle.x = 10.0;
d_x = 0;
}
else if (m_vGunAngle.x > 90.0)
{
m_vGunAngle.x = 90.0;
d_x = 0;
}
if (0 != d_x || 0 != d_y)
{
PlaySound();
}
SetBoneController(0, m_vGunAngle.x);
SetBoneController(1, m_vGunAngle.y);
d_y = 0;
d_x = 0;
}
//========================================================
@ -571,9 +770,9 @@ public:
int ObjectCaps() { return FCAP_CONTINUOUS_USE; }
static TYPEDESCRIPTION m_SaveData[];
float m_direction;
float m_lastpush;
int m_direction;
int m_controller;
float m_lastpush;
};
LINK_ENTITY_TO_CLASS(func_op4mortarcontroller, COp4MortarController)
@ -620,7 +819,7 @@ void COp4MortarController::KeyValue(KeyValueData *pvkd)
if(FStrEq(pvkd->szKeyName, "mortar_axis"))
{
m_controller = atoi(pvkd->szValue);
pvkd->fHandled = 1;
pvkd->fHandled = TRUE;
}
else
CBaseToggle::KeyValue(pvkd);

View File

@ -31,16 +31,6 @@
#define SPRING_DAMPING 0.1f
#define ROPE_IGNORE_SAMPLES 4 // integrator may be hanging if less than
//#define SetAbsOrigin(x) pev->origin = x;
#define SetAbsAngles(x) pev->angles = x;
#define SetAbsVelociy(x) pev->velocity = x;
#define SetNextThink(x) pev->nextthink = x;
#define SetEffects(x) pev->effects = x;
#define SetSolidType(x) pev->solid = x;
#define AddFlags(x) pev->flags |= x;
#define SetMoveType(x) pev->movetype = x;
#define AddEffectsFlags(x) pev->effects |= x;
/**
* Data for a single rope joint.
*/
@ -74,17 +64,22 @@ public:
static CRopeSample* CreateSample();
RopeSampleData* GetData() {
if (swapped)
return &data2;
else
return &data;
RopeSampleData& GetData()
{
return data;
}
RopeSampleData* GetData2() {
RopeSampleData& GetSourceData() {
if (swapped)
return &data;
return data2;
else
return &data2;
return data;
}
RopeSampleData& GetTargetData() {
if (swapped)
return data;
else
return data2;
}
void Swap()
@ -92,6 +87,11 @@ public:
swapped = !swapped;
}
void ResetSwap()
{
swapped = FALSE;
}
private:
RopeSampleData data;
RopeSampleData data2;
@ -257,7 +257,7 @@ void CRope::Activate()
void CRope::InitRope()
{
AddFlags( FL_ALWAYSTHINK );
pev->flags |= FL_ALWAYSTHINK;
for( int uiSample = 0; uiSample < m_NumSamples; ++uiSample )
{
@ -334,7 +334,7 @@ void CRope::InitRope()
InitializeRopeSim();
SetThink(&CRope::RopeThink);
SetNextThink( gpGlobals->time + 0.01 );
pev->nextthink = gpGlobals->time + 0.01;
}
void CRope::RopeThink()
@ -364,7 +364,7 @@ void CRope::RopeThink()
Creak();
}
SetNextThink( gpGlobals->time + 0.001 );
pev->nextthink = gpGlobals->time + 0.001;
}
void CRope::InitializeRopeSim()
@ -376,26 +376,26 @@ void CRope::InitializeRopeSim()
CRopeSegment* pSegment = seg[ uiSeg ];
CRopeSample* pSample = pSegment->GetSample();
RopeSampleData *data = pSample->GetData();
RopeSampleData& data = pSample->GetData();
data->mPosition = pSegment->pev->origin;
data.mPosition = pSegment->pev->origin;
data->mVelocity = g_vecZero;
data->mForce = g_vecZero;
data->mMassReciprocal = 1;
data->mApplyExternalForce = false;
data->mExternalForce = g_vecZero;
data.mVelocity = g_vecZero;
data.mForce = g_vecZero;
data.mMassReciprocal = 1;
data.mApplyExternalForce = false;
data.mExternalForce = g_vecZero;
Vector vecOrigin, vecAngles;
pSegment->GetAttachment( 0, vecOrigin, vecAngles );
data->restLength = ( pSegment->pev->origin - vecOrigin ).Length();
data.restLength = ( pSegment->pev->origin - vecOrigin ).Length();
}
{
//Zero out the anchored segment's mass so it stays in place.
CRopeSample *pSample = m_Samples[ 0 ];
pSample->GetData()->mMassReciprocal = 0;
pSample->GetData().mMassReciprocal = 0;
}
CRopeSegment* pSegment = seg[ m_iSegments - 1 ];
@ -414,19 +414,19 @@ void CRope::InitializeRopeSim()
CRopeSample* pSample = m_Samples[ m_NumSamples - 1 ];
RopeSampleData *data = pSample->GetData();
RopeSampleData& data = pSample->GetData();
data->mPosition = vecOrigin;
data.mPosition = vecOrigin;
m_LastEndPos = vecOrigin;
data->mVelocity = g_vecZero;
data.mVelocity = g_vecZero;
data->mForce = g_vecZero;
data.mForce = g_vecZero;
data->mMassReciprocal = 0.2;
data.mMassReciprocal = 0.2;
data->mApplyExternalForce = false;
data.mApplyExternalForce = false;
int uiNumSegs = ROPE_IGNORE_SAMPLES;
@ -453,6 +453,7 @@ void CRope::RunSimOnSamples()
int uiIndex = 0;
bool swapped = false;
while( true )
{
++uiIndex;
@ -472,13 +473,15 @@ void CRope::RunSimOnSamples()
{
m_Samples[i]->Swap();
}
swapped = !swapped;
}
//CRopeSample **swap = ppSampleSource;
//ppSampleSource = ppSampleTarget;
//ppSampleTarget = swap;
//std::swap( ppSampleSource, ppSampleTarget );
if (swapped)
{
for (int i=0; i<m_NumSamples; ++i)
{
m_Samples[i]->ResetSwap();
}
}
mLastTime = gpGlobals->time;
@ -503,12 +506,12 @@ void CRope::ComputeForces( CRopeSample** ppSystem )
int uiIndex;
for( uiIndex = 0; uiIndex < m_NumSamples; ++uiIndex )
{
ComputeSampleForce( *ppSystem[ uiIndex ]->GetData() );
ComputeSampleForce( ppSystem[ uiIndex ]->GetSourceData() );
}
for( uiIndex = 0; uiIndex < m_iSegments; ++uiIndex )
{
ComputeSpringForce( *ppSystem[ uiIndex ]->GetData(), *ppSystem[ uiIndex+1 ]->GetData() );
ComputeSpringForce( ppSystem[ uiIndex ]->GetSourceData(), ppSystem[ uiIndex+1 ]->GetSourceData() );
}
}
@ -576,16 +579,16 @@ void CRope::RK4Integrate( const float flDeltaTime )
for( int uiIndex = 0; uiIndex < m_NumSamples; ++uiIndex, ++pTemp1, ++pTemp2 )
{
RopeSampleData *data = m_Samples[ uiIndex ]->GetData();
RopeSampleData& data = m_Samples[ uiIndex ]->GetSourceData();
pTemp2->mForce = data->mMassReciprocal * data->mForce * flDeltas[ 0 ];
pTemp2->mVelocity = data->mVelocity * flDeltas[ 0 ];
pTemp2->restLength = data->restLength;
pTemp2->mForce = data.mMassReciprocal * data.mForce * flDeltas[ 0 ];
pTemp2->mVelocity = data.mVelocity * flDeltas[ 0 ];
pTemp2->restLength = data.restLength;
pTemp1->mMassReciprocal = data->mMassReciprocal;
pTemp1->mVelocity = data->mVelocity + pTemp2->mForce;
pTemp1->mPosition = data->mPosition + pTemp2->mVelocity;
pTemp1->restLength = data->restLength;
pTemp1->mMassReciprocal = data.mMassReciprocal;
pTemp1->mVelocity = data.mVelocity + pTemp2->mForce;
pTemp1->mPosition = data.mPosition + pTemp2->mVelocity;
pTemp1->restLength = data.restLength;
}
ComputeForces( g_pTempList[ 0 ] );
@ -598,16 +601,16 @@ void CRope::RK4Integrate( const float flDeltaTime )
for( int uiIndex = 0; uiIndex < m_NumSamples; ++uiIndex, ++pTemp1, ++pTemp2 )
{
RopeSampleData *data = m_Samples[ uiIndex ]->GetData();
RopeSampleData& data = m_Samples[ uiIndex ]->GetSourceData();
pTemp2->mForce = data->mMassReciprocal * pTemp1->mForce * flDeltas[ uiStep - 1 ];
pTemp2->mForce = data.mMassReciprocal * pTemp1->mForce * flDeltas[ uiStep - 1 ];
pTemp2->mVelocity = pTemp1->mVelocity * flDeltas[ uiStep - 1 ];
pTemp2->restLength = data->restLength;
pTemp2->restLength = data.restLength;
pTemp1->mMassReciprocal = data->mMassReciprocal;
pTemp1->mVelocity = data->mVelocity + pTemp2->mForce;
pTemp1->mPosition = data->mPosition + pTemp2->mVelocity;
pTemp1->restLength = data->restLength;
pTemp1->mMassReciprocal = data.mMassReciprocal;
pTemp1->mVelocity = data.mVelocity + pTemp2->mForce;
pTemp1->mPosition = data.mPosition + pTemp2->mVelocity;
pTemp1->restLength = data.restLength;
}
ComputeForces( g_pTempList[ 0 ] );
@ -619,9 +622,9 @@ void CRope::RK4Integrate( const float flDeltaTime )
for( int uiIndex = 0; uiIndex < m_NumSamples; ++uiIndex, ++pTemp1, ++pTemp2 )
{
RopeSampleData *data = m_Samples[ uiIndex ]->GetData();
RopeSampleData& data = m_Samples[ uiIndex ]->GetSourceData();
pTemp2->mForce = data->mMassReciprocal * pTemp1->mForce * flDeltas[ 3 ];
pTemp2->mForce = data.mMassReciprocal * pTemp1->mForce * flDeltas[ 3 ];
pTemp2->mVelocity = pTemp1->mVelocity * flDeltas[ 3 ];
}
@ -634,16 +637,16 @@ void CRope::RK4Integrate( const float flDeltaTime )
for( int uiIndex = 0; uiIndex < m_NumSamples; ++uiIndex, ++pTemp1, ++pTemp2, ++pTemp3, ++pTemp4 )
{
RopeSampleData *pSource = m_Samples[ uiIndex ]->GetData();
RopeSampleData *pTarget = m_Samples[ uiIndex ]->GetData2();
RopeSampleData& pSource = m_Samples[ uiIndex ]->GetSourceData();
RopeSampleData& pTarget = m_Samples[ uiIndex ]->GetTargetData();
const Vector vecPosChange = 1.0f / 6.0f * ( pTemp1->mVelocity + ( pTemp2->mVelocity + pTemp3->mVelocity ) * 2 + pTemp4->mVelocity );
const Vector vecVelChange = 1.0f / 6.0f * ( pTemp1->mForce + ( pTemp2->mForce + pTemp3->mForce ) * 2 + pTemp4->mForce );
pTarget->mPosition = pSource->mPosition + ( vecPosChange );//* flDeltaTime );
pTarget.mPosition = pSource.mPosition + ( vecPosChange );//* flDeltaTime );
pTarget->mVelocity = pSource->mVelocity + ( vecVelChange );//* flDeltaTime );
pTarget.mVelocity = pSource.mVelocity + ( vecVelChange );//* flDeltaTime );
}
}
@ -686,30 +689,31 @@ void CRope::TraceModels( CRopeSegment** ppPrimarySegs, CRopeSegment** ppHiddenSe
Vector vecAngles;
GetAlignmentAngles(
m_Samples[ 0 ]->GetData()->mPosition,
m_Samples[ 1 ]->GetData()->mPosition,
m_Samples[ 0 ]->GetData().mPosition,
m_Samples[ 1 ]->GetData().mPosition,
vecAngles );
( *ppPrimarySegs )->SetAbsAngles( vecAngles );
( *ppPrimarySegs )->pev->angles = vecAngles;
}
TraceResult tr;
if( mObjectAttached )
{
for( int uiSeg = 1; uiSeg < m_iSegments; ++uiSeg )
for( unsigned int uiSeg = 1; uiSeg < m_iSegments; ++uiSeg )
{
CRopeSample* pSample = m_Samples[ uiSeg ];
Vector vecDist = pSample->GetData()->mPosition - ppHiddenSegs[ uiSeg ]->pev->origin;
Vector vecDist = pSample->GetData().mPosition - ppHiddenSegs[ uiSeg ]->pev->origin;
vecDist = vecDist.Normalize();
// HACK: this code relies on integer underflow. uiSeg must be unsigned!
const float flTraceDist = ( uiSeg - mAttachedObjectsSegment + 2 ) < 5 ? 50 : 10;
const Vector vecTraceDist = vecDist * flTraceDist;
const Vector vecEnd = pSample->GetData()->mPosition + vecTraceDist;
const Vector vecEnd = pSample->GetData().mPosition + vecTraceDist;
UTIL_TraceLine( ppHiddenSegs[ uiSeg ]->pev->origin, vecEnd, ignore_monsters, edict(), &tr );
@ -728,17 +732,17 @@ void CRope::TraceModels( CRopeSegment** ppPrimarySegs, CRopeSegment** ppHiddenSe
Vector vecNormal = tr.vecPlaneNormal.Normalize() * 20000.0;
RopeSampleData *data = ppPrimarySegs[ uiSeg ]->GetSample()->GetData();
RopeSampleData& data = ppPrimarySegs[ uiSeg ]->GetSample()->GetData();
data->mApplyExternalForce = true;
data.mApplyExternalForce = true;
data->mExternalForce = vecNormal;
data.mExternalForce = vecNormal;
data->mVelocity = g_vecZero;
data.mVelocity = g_vecZero;
}
else
{
Vector vecOrigin = pSample->GetData()->mPosition;
Vector vecOrigin = pSample->GetData().mPosition;
TruncateEpsilon( vecOrigin );
@ -748,16 +752,16 @@ void CRope::TraceModels( CRopeSegment** ppPrimarySegs, CRopeSegment** ppHiddenSe
}
else
{
for( int uiSeg = 1; uiSeg < m_iSegments; ++uiSeg )
for( unsigned int uiSeg = 1; uiSeg < m_iSegments; ++uiSeg )
{
UTIL_TraceLine(
ppHiddenSegs[ uiSeg ]->pev->origin,
m_Samples[ uiSeg ]->GetData()->mPosition,
m_Samples[ uiSeg ]->GetData().mPosition,
ignore_monsters, edict(), &tr );
if( tr.flFraction == 1.0 )
{
Vector vecOrigin = m_Samples[ uiSeg ]->GetData()->mPosition;
Vector vecOrigin = m_Samples[ uiSeg ]->GetData().mPosition;
TruncateEpsilon( vecOrigin );
@ -774,9 +778,9 @@ void CRope::TraceModels( CRopeSegment** ppPrimarySegs, CRopeSegment** ppHiddenSe
ppPrimarySegs[ uiSeg ]->SetAbsOrigin( vecOrigin );
ppPrimarySegs[ uiSeg ]->GetSample()->GetData()->mApplyExternalForce = true;
ppPrimarySegs[ uiSeg ]->GetSample()->GetData().mApplyExternalForce = true;
ppPrimarySegs[ uiSeg ]->GetSample()->GetData()->mExternalForce = vecNormal * 40000.0;
ppPrimarySegs[ uiSeg ]->GetSample()->GetData().mExternalForce = vecNormal * 40000.0;
}
}
}
@ -790,26 +794,26 @@ void CRope::TraceModels( CRopeSegment** ppPrimarySegs, CRopeSegment** ppHiddenSe
GetAlignmentAngles( pSegment->pev->origin, pSegment2->pev->origin, vecAngles );
pSegment->SetAbsAngles( vecAngles );
pSegment->pev->angles = vecAngles;
}
if( m_iSegments > 1 )
{
CRopeSample *pSample = m_Samples[ m_NumSamples - 1 ];
UTIL_TraceLine( m_LastEndPos, pSample->GetData()->mPosition, ignore_monsters, edict(), &tr );
UTIL_TraceLine( m_LastEndPos, pSample->GetData().mPosition, ignore_monsters, edict(), &tr );
if( tr.flFraction == 1.0 )
{
m_LastEndPos = pSample->GetData()->mPosition;
m_LastEndPos = pSample->GetData().mPosition;
}
else
{
m_LastEndPos = tr.vecEndPos;
pSample->GetData()->mApplyExternalForce = true;
pSample->GetData().mApplyExternalForce = true;
pSample->GetData()->mExternalForce = tr.vecPlaneNormal.Normalize() * 40000.0;
pSample->GetData().mExternalForce = tr.vecPlaneNormal.Normalize() * 40000.0;
}
CRopeSegment *pSegment = ppPrimarySegs[ m_NumSamples - 2 ];
@ -818,7 +822,7 @@ void CRope::TraceModels( CRopeSegment** ppPrimarySegs, CRopeSegment** ppHiddenSe
GetAlignmentAngles( pSegment->pev->origin, m_LastEndPos, vecAngles );
pSegment->SetAbsAngles( vecAngles );
pSegment->pev->angles = vecAngles;
}
}
@ -829,22 +833,22 @@ void CRope::SetRopeSegments( const int uiNumSegments,
{
TraceModels( ppPrimarySegs, ppHiddenSegs );
ppPrimarySegs[ 0 ]->SetSolidType( SOLID_TRIGGER );
ppPrimarySegs[ 0 ]->SetEffects( 0 );
ppPrimarySegs[ 0 ]->pev->solid = SOLID_TRIGGER;
ppPrimarySegs[ 0 ]->pev->effects = 0;
ppHiddenSegs[ 0 ]->SetSolidType( SOLID_NOT );
ppHiddenSegs[ 0 ]->SetEffects( EF_NODRAW );
ppHiddenSegs[ 0 ]->pev->solid = SOLID_NOT;
ppHiddenSegs[ 0 ]->pev->effects = EF_NODRAW;
for( int uiIndex = 1; uiIndex < uiNumSegments; ++uiIndex )
{
CRopeSegment* pPrim = ppPrimarySegs[ uiIndex ];
CRopeSegment* pHidden = ppHiddenSegs[ uiIndex ];
pPrim->SetSolidType( SOLID_TRIGGER );
pPrim->SetEffects( 0 );
pPrim->pev->solid = SOLID_TRIGGER;
pPrim->pev->effects = 0;
pHidden->SetSolidType( SOLID_NOT );
pHidden->SetEffects( EF_NODRAW );
pHidden->pev->solid = SOLID_NOT;
pHidden->pev->effects = EF_NODRAW;
Vector vecOrigin = pPrim->pev->origin;
@ -974,7 +978,7 @@ Vector CRope::GetAttachedObjectsVelocity() const
if( !mObjectAttached )
return g_vecZero;
return seg[ mAttachedObjectsSegment ]->GetSample()->GetData()->mVelocity;
return seg[ mAttachedObjectsSegment ]->GetSample()->GetData().mVelocity;
}
void CRope::ApplyForceFromPlayer( const Vector& vecForce )
@ -1002,11 +1006,11 @@ void CRope::ApplyForceToSegment( const Vector& vecForce, const int uiSegment )
{
//Apply force to the last sample.
RopeSampleData *data = m_Samples[ uiSegment - 1 ]->GetData();
RopeSampleData& data = m_Samples[ uiSegment - 1 ]->GetData();
data->mExternalForce = data->mExternalForce + vecForce;
data.mExternalForce = data.mExternalForce + vecForce;
data->mApplyExternalForce = true;
data.mApplyExternalForce = true;
}
}
@ -1043,7 +1047,7 @@ bool CRope::ShouldCreak() const
{
CRopeSample* pSample = seg[ mAttachedObjectsSegment ]->GetSample();
if( pSample->GetData()->mVelocity.Length() > 20.0 )
if( pSample->GetData().mVelocity.Length() > 20.0 )
return RANDOM_LONG( 1, 5 ) == 1;
}
@ -1093,7 +1097,7 @@ float CRope::GetRopeLength() const
Vector CRope::GetRopeOrigin() const
{
return m_Samples[ 0 ]->GetData()->mPosition;
return m_Samples[ 0 ]->GetData().mPosition;
}
bool CRope::IsValidSegmentIndex( const int uiSegment ) const
@ -1106,7 +1110,7 @@ Vector CRope::GetSegmentOrigin( const int uiSegment ) const
if( !IsValidSegmentIndex( uiSegment ) )
return g_vecZero;
return m_Samples[ uiSegment ]->GetData()->mPosition;
return m_Samples[ uiSegment ]->GetData().mPosition;
}
Vector CRope::GetSegmentAttachmentPoint( const int uiSegment ) const
@ -1142,8 +1146,8 @@ Vector CRope::GetSegmentDirFromOrigin( const int uiSegmentIndex ) const
//There is one more sample than there are segments, so this is fine.
const Vector vecResult =
m_Samples[ uiSegmentIndex + 1 ]->GetData()->mPosition -
m_Samples[ uiSegmentIndex ]->GetData()->mPosition;
m_Samples[ uiSegmentIndex + 1 ]->GetData().mPosition -
m_Samples[ uiSegmentIndex ]->GetData().mPosition;
return vecResult.Normalize();
}
@ -1156,7 +1160,7 @@ Vector CRope::GetAttachedObjectsPosition() const
Vector vecResult;
if( mAttachedObjectsSegment < m_iSegments )
vecResult = m_Samples[ mAttachedObjectsSegment ]->GetData()->mPosition;
vecResult = m_Samples[ mAttachedObjectsSegment ]->GetData().mPosition;
vecResult = vecResult +
( mAttachedObjectsOffset * GetSegmentDirFromOrigin( mAttachedObjectsSegment ) );
@ -1194,7 +1198,7 @@ void CRopeSample::Spawn()
{
pev->classname = MAKE_STRING( "rope_sample" );
AddEffectsFlags( EF_NODRAW );
pev->effects |= EF_NODRAW;
}
CRopeSample* CRopeSample::CreateSample()
@ -1238,14 +1242,14 @@ void CRopeSegment::Spawn()
SET_MODEL( edict(), STRING( mModelName ) );
SetMoveType( MOVETYPE_NOCLIP );
SetSolidType( SOLID_TRIGGER );
SetEffects( EF_NODRAW );
pev->movetype = MOVETYPE_NOCLIP;
pev->solid = SOLID_TRIGGER;
pev->effects = EF_NODRAW;
SetAbsOrigin( pev->origin );
UTIL_SetSize( pev, Vector( -30, -30, -30 ), Vector( 30, 30, 30 ) );
SetNextThink( gpGlobals->time + 0.5 );
pev->nextthink = gpGlobals->time + 0.5;
}
void CRopeSegment::Touch( CBaseEntity* pOther )
@ -1267,9 +1271,9 @@ void CRopeSegment::Touch( CBaseEntity* pOther )
{
if( mCanBeGrabbed )
{
RopeSampleData *data = m_Sample->GetData();
RopeSampleData& data = m_Sample->GetData();
pOther->pev->origin = data->mPosition;
pOther->pev->origin = data.mPosition;
pPlayer->SetOnRopeState( true );
pPlayer->SetRope( GetMasterRope() );
@ -1280,9 +1284,9 @@ void CRopeSegment::Touch( CBaseEntity* pOther )
if( vecVelocity.Length() > 0.5 )
{
//Apply some external force to move the rope. - Solokiller
data->mApplyExternalForce = true;
data.mApplyExternalForce = true;
data->mExternalForce = data->mExternalForce + vecVelocity * 750;
data.mExternalForce = data.mExternalForce + vecVelocity * 750;
}
if( GetMasterRope()->IsSoundAllowed() )
@ -1326,7 +1330,7 @@ CRopeSegment* CRopeSegment::CreateSegment( CRopeSample* pSample, string_t iszMod
pSegment->mCauseDamage = false;
pSegment->mCanBeGrabbed = true;
pSegment->mDefaultMass = pSample->GetData()->mMassReciprocal;
pSegment->mDefaultMass = pSample->GetData().mMassReciprocal;
pSegment->SetMasterRope(rope);
return pSegment;
@ -1334,9 +1338,9 @@ CRopeSegment* CRopeSegment::CreateSegment( CRopeSample* pSample, string_t iszMod
void CRopeSegment::ApplyExternalForce( const Vector& vecForce )
{
m_Sample->GetData()->mApplyExternalForce = true;
m_Sample->GetData().mApplyExternalForce = true;
m_Sample->GetData()->mExternalForce = m_Sample->GetData()->mExternalForce + vecForce;
m_Sample->GetData().mExternalForce = m_Sample->GetData().mExternalForce + vecForce;
}
void CRopeSegment::SetCauseDamageOnTouch( const bool bCauseDamage )

View File

@ -280,7 +280,7 @@ void CSporelauncher::Reload(void)
m_fInSpecialReload = 2;
// Play reload sound.
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/splauncher_reload.wav", 1, ATTN_NORM, 0, 100);
EMIT_SOUND(m_pPlayer->edict(), CHAN_ITEM, "weapons/splauncher_reload.wav", 0.7f, ATTN_NORM);
SendWeaponAnim(SPLAUNCHER_RELOAD_LOAD);
@ -328,12 +328,12 @@ void CSporelauncher::WeaponIdle(void)
{
int iAnim;
float flRand = UTIL_SharedRandomFloat(m_pPlayer->random_seed, 0, 1);
if (flRand <= 0.4)
if (flRand <= 0.75f)
{
iAnim = SPLAUNCHER_IDLE;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f;
}
else if (flRand <= 0.8)
else if (flRand <= 0.95f)
{
iAnim = SPLAUNCHER_IDLE2;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 4.0f;
@ -342,6 +342,7 @@ void CSporelauncher::WeaponIdle(void)
{
iAnim = SPLAUNCHER_FIDGET;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 4.0f;
EMIT_SOUND(m_pPlayer->edict(), CHAN_ITEM, "weapons/splauncher_pet.wav", 0.7f, ATTN_NORM);
}
SendWeaponAnim(iAnim);

View File

@ -37,6 +37,8 @@
#include "pm_shared.h"
#include "hltv.h"
#include "ropes.h"
// #define DUCKFIX
extern DLL_GLOBAL ULONG g_ulModelIndexPlayer;

View File

@ -17,7 +17,7 @@
#define PLAYER_H
#include "pm_materials.h"
#include "ropes.h"
class CRope;
#define PLAYER_FATAL_FALL_SPEED 1024// approx 60 feet
#define PLAYER_MAX_SAFE_FALL_SPEED 580// approx 20 feet