diff --git a/CODE-mp/Default.SUP b/CODE-mp/Default.SUP new file mode 100644 index 0000000..e0d55e7 --- /dev/null +++ b/CODE-mp/Default.SUP @@ -0,0 +1,3 @@ +//SUPPRESSIONPROJ:Default +//VERSION:5.00 +//ENABLE:Yes diff --git a/CODE-mp/Final/jk2/winquake.res b/CODE-mp/Final/jk2/winquake.res deleted file mode 100644 index 9bc4bc4..0000000 Binary files a/CODE-mp/Final/jk2/winquake.res and /dev/null differ diff --git a/CODE-mp/Release/jk2/winquake.res b/CODE-mp/Release/jk2/winquake.res deleted file mode 100644 index 9bc4bc4..0000000 Binary files a/CODE-mp/Release/jk2/winquake.res and /dev/null differ diff --git a/CODE-mp/Splines/Splines.dsp b/CODE-mp/Splines/Splines.dsp new file mode 100644 index 0000000..e8c2789 --- /dev/null +++ b/CODE-mp/Splines/Splines.dsp @@ -0,0 +1,156 @@ +# Microsoft Developer Studio Project File - Name="Splines" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=Splines - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Splines.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Splines.mak" CFG="Splines - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Splines - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "Splines - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/General/code/Splines", GAAAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Splines - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "Splines - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GR /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "Splines - Win32 Release" +# Name "Splines - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\math_angles.cpp +# End Source File +# Begin Source File + +SOURCE=.\math_matrix.cpp +# End Source File +# Begin Source File + +SOURCE=.\math_quaternion.cpp +# End Source File +# Begin Source File + +SOURCE=.\math_vector.cpp +# End Source File +# Begin Source File + +SOURCE=.\q_parse.cpp +# End Source File +# Begin Source File + +SOURCE=.\q_shared.cpp +# End Source File +# Begin Source File + +SOURCE=.\splines.cpp +# End Source File +# Begin Source File + +SOURCE=.\util_str.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\math_angles.h +# End Source File +# Begin Source File + +SOURCE=.\math_matrix.h +# End Source File +# Begin Source File + +SOURCE=.\math_quaternion.h +# End Source File +# Begin Source File + +SOURCE=.\math_vector.h +# End Source File +# Begin Source File + +SOURCE=.\q_shared.h +# End Source File +# Begin Source File + +SOURCE=.\splines.h +# End Source File +# Begin Source File + +SOURCE=.\util_list.h +# End Source File +# Begin Source File + +SOURCE=.\util_str.h +# End Source File +# End Group +# End Target +# End Project diff --git a/CODE-mp/Splines/math_angles.cpp b/CODE-mp/Splines/math_angles.cpp new file mode 100644 index 0000000..5da1510 --- /dev/null +++ b/CODE-mp/Splines/math_angles.cpp @@ -0,0 +1,129 @@ +#include "q_shared.h" +#include + +angles_t ang_zero( 0.0f, 0.0f, 0.0f ); + +void toAngles( mat3_t &src, angles_t &dst ) { + double theta; + double cp; + double sp; + + sp = src[ 0 ][ 2 ]; + + // cap off our sin value so that we don't get any NANs + if ( sp > 1.0 ) { + sp = 1.0; + } else if ( sp < -1.0 ) { + sp = -1.0; + } + + theta = -asin( sp ); + cp = cos( theta ); + + if ( cp > 8192 * FLT_EPSILON ) { + dst.pitch = theta * 180 / M_PI; + dst.yaw = atan2( src[ 0 ][ 1 ], src[ 0 ][ 0 ] ) * 180 / M_PI; + dst.roll = atan2( src[ 1 ][ 2 ], src[ 2 ][ 2 ] ) * 180 / M_PI; + } else { + dst.pitch = theta * 180 / M_PI; + dst.yaw = -atan2( src[ 1 ][ 0 ], src[ 1 ][ 1 ] ) * 180 / M_PI; + dst.roll = 0; + } +} + +void toAngles( quat_t &src, angles_t &dst ) { + mat3_t temp; + + toMatrix( src, temp ); + toAngles( temp, dst ); +} + +void toAngles( idVec3_t &src, angles_t &dst ) { + dst.pitch = src[ 0 ]; + dst.yaw = src[ 1 ]; + dst.roll = src[ 2 ]; +} + +void angles_t::toVectors( idVec3_t *forward, idVec3_t *right, idVec3_t *up ) { + float angle; + static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs + + angle = yaw * ( M_PI * 2 / 360 ); + sy = sin( angle ); + cy = cos( angle ); + + angle = pitch * ( M_PI * 2 / 360 ); + sp = sin( angle ); + cp = cos( angle ); + + angle = roll * ( M_PI * 2 / 360 ); + sr = sin( angle ); + cr = cos( angle ); + + if ( forward ) { + forward->set( cp * cy, cp * sy, -sp ); + } + + if ( right ) { + right->set( -sr * sp * cy + cr * sy, -sr * sp * sy + -cr * cy, -sr * cp ); + } + + if ( up ) { + up->set( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp ); + } +} + +idVec3_t angles_t::toForward( void ) { + float angle; + static float sp, sy, cp, cy; // static to help MS compiler fp bugs + + angle = yaw * ( M_PI * 2 / 360 ); + sy = sin( angle ); + cy = cos( angle ); + + angle = pitch * ( M_PI * 2 / 360 ); + sp = sin( angle ); + cp = cos( angle ); + + return idVec3_t( cp * cy, cp * sy, -sp ); +} + +/* +================= +Normalize360 + +returns angles normalized to the range [0 <= angle < 360] +================= +*/ +angles_t& angles_t::Normalize360( void ) { + pitch = (360.0 / 65536) * ( ( int )( pitch * ( 65536 / 360.0 ) ) & 65535 ); + yaw = (360.0 / 65536) * ( ( int )( yaw * ( 65536 / 360.0 ) ) & 65535 ); + roll = (360.0 / 65536) * ( ( int )( roll * ( 65536 / 360.0 ) ) & 65535 ); + + return *this; +} + + +/* +================= +Normalize180 + +returns angles normalized to the range [-180 < angle <= 180] +================= +*/ +angles_t& angles_t::Normalize180( void ) { + Normalize360(); + + if ( pitch > 180.0 ) { + pitch -= 360.0; + } + + if ( yaw > 180.0 ) { + yaw -= 360.0; + } + + if ( roll > 180.0 ) { + roll -= 360.0; + } + return *this; +} diff --git a/CODE-mp/Splines/math_angles.h b/CODE-mp/Splines/math_angles.h new file mode 100644 index 0000000..fdf1bfa --- /dev/null +++ b/CODE-mp/Splines/math_angles.h @@ -0,0 +1,174 @@ +#ifndef __MATH_ANGLES_H__ +#define __MATH_ANGLES_H__ + +#include +#include + +#include "math_vector.h" + +class mat3_t; +class quat_t; +class idVec3_t; +typedef idVec3_t &vec3_p; + +class angles_t { +public: + float pitch; + float yaw; + float roll; + + angles_t(); + angles_t( float pitch, float yaw, float roll ); + angles_t( const idVec3_t &vec ); + + friend void toAngles( idVec3_t &src, angles_t &dst ); + friend void toAngles( quat_t &src, angles_t &dst ); + friend void toAngles( mat3_t &src, angles_t &dst ); + + operator vec3_p(); + + float operator[]( int index ) const; + float& operator[]( int index ); + + void set( float pitch, float yaw, float roll ); + + void operator=( angles_t const &a ); + void operator=( idVec3_t const &a ); + + friend angles_t operator+( const angles_t &a, const angles_t &b ); + angles_t &operator+=( angles_t const &a ); + angles_t &operator+=( idVec3_t const &a ); + + friend angles_t operator-( angles_t &a, angles_t &b ); + angles_t &operator-=( angles_t &a ); + + friend angles_t operator*( const angles_t &a, float b ); + friend angles_t operator*( float a, const angles_t &b ); + angles_t &operator*=( float a ); + + friend int operator==( angles_t &a, angles_t &b ); + + friend int operator!=( angles_t &a, angles_t &b ); + + void toVectors( idVec3_t *forward, idVec3_t *right = NULL, idVec3_t *up = NULL ); + idVec3_t toForward( void ); + + angles_t &Zero( void ); + + angles_t &Normalize360( void ); + angles_t &Normalize180( void ); +}; + +extern angles_t ang_zero; + +inline angles_t::angles_t() {} + +inline angles_t::angles_t( float pitch, float yaw, float roll ) { + this->pitch = pitch; + this->yaw = yaw; + this->roll = roll; +} + +inline angles_t::angles_t( const idVec3_t &vec ) { + this->pitch = vec.x; + this->yaw = vec.y; + this->roll = vec.z; +} + +inline float angles_t::operator[]( int index ) const { + assert( ( index >= 0 ) && ( index < 3 ) ); + return ( &pitch )[ index ]; +} + +inline float& angles_t::operator[]( int index ) { + assert( ( index >= 0 ) && ( index < 3 ) ); + return ( &pitch )[ index ]; +} + +inline angles_t::operator vec3_p( void ) { + return *( idVec3_t * )&pitch; +} + +inline void angles_t::set( float pitch, float yaw, float roll ) { + this->pitch = pitch; + this->yaw = yaw; + this->roll = roll; +} + +inline void angles_t::operator=( angles_t const &a ) { + pitch = a.pitch; + yaw = a.yaw; + roll = a.roll; +} + +inline void angles_t::operator=( idVec3_t const &a ) { + pitch = a[ 0 ]; + yaw = a[ 1 ]; + roll = a[ 2 ]; +} + +inline angles_t operator+( const angles_t &a, const angles_t &b ) { + return angles_t( a.pitch + b.pitch, a.yaw + b.yaw, a.roll + b.roll ); +} + +inline angles_t& angles_t::operator+=( angles_t const &a ) { + pitch += a.pitch; + yaw += a.yaw; + roll += a.roll; + + return *this; +} + +inline angles_t& angles_t::operator+=( idVec3_t const &a ) { + pitch += a.x; + yaw += a.y; + roll += a.z; + + return *this; +} + +inline angles_t operator-( angles_t &a, angles_t &b ) { + return angles_t( a.pitch - b.pitch, a.yaw - b.yaw, a.roll - b.roll ); +} + +inline angles_t& angles_t::operator-=( angles_t &a ) { + pitch -= a.pitch; + yaw -= a.yaw; + roll -= a.roll; + + return *this; +} + +inline angles_t operator*( const angles_t &a, float b ) { + return angles_t( a.pitch * b, a.yaw * b, a.roll * b ); +} + +inline angles_t operator*( float a, const angles_t &b ) { + return angles_t( a * b.pitch, a * b.yaw, a * b.roll ); +} + +inline angles_t& angles_t::operator*=( float a ) { + pitch *= a; + yaw *= a; + roll *= a; + + return *this; +} + +inline int operator==( angles_t &a, angles_t &b ) { + return ( ( a.pitch == b.pitch ) && ( a.yaw == b.yaw ) && ( a.roll == b.roll ) ); +} + +inline int operator!=( angles_t &a, angles_t &b ) { + return ( ( a.pitch != b.pitch ) || ( a.yaw != b.yaw ) || ( a.roll != b.roll ) ); +} + +inline angles_t& angles_t::Zero( void ) { + pitch = 0.0f; + yaw = 0.0f; + roll = 0.0f; + + return *this; +} + +#endif /* !__MATH_ANGLES_H__ */ diff --git a/CODE-mp/Splines/math_matrix.cpp b/CODE-mp/Splines/math_matrix.cpp new file mode 100644 index 0000000..b02b6ac --- /dev/null +++ b/CODE-mp/Splines/math_matrix.cpp @@ -0,0 +1,113 @@ +#include "q_shared.h" + +mat3_t mat3_default( idVec3_t( 1, 0, 0 ), idVec3_t( 0, 1, 0 ), idVec3_t( 0, 0, 1 ) ); + +void toMatrix( quat_t const &src, mat3_t &dst ) { + float wx, wy, wz; + float xx, yy, yz; + float xy, xz, zz; + float x2, y2, z2; + + x2 = src.x + src.x; + y2 = src.y + src.y; + z2 = src.z + src.z; + + xx = src.x * x2; + xy = src.x * y2; + xz = src.x * z2; + + yy = src.y * y2; + yz = src.y * z2; + zz = src.z * z2; + + wx = src.w * x2; + wy = src.w * y2; + wz = src.w * z2; + + dst[ 0 ][ 0 ] = 1.0f - ( yy + zz ); + dst[ 0 ][ 1 ] = xy - wz; + dst[ 0 ][ 2 ] = xz + wy; + + dst[ 1 ][ 0 ] = xy + wz; + dst[ 1 ][ 1 ] = 1.0f - ( xx + zz ); + dst[ 1 ][ 2 ] = yz - wx; + + dst[ 2 ][ 0 ] = xz - wy; + dst[ 2 ][ 1 ] = yz + wx; + dst[ 2 ][ 2 ] = 1.0f - ( xx + yy ); +} + +void toMatrix( angles_t const &src, mat3_t &dst ) { + float angle; + static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs + + angle = src.yaw * ( M_PI * 2.0f / 360.0f ); + sy = sin( angle ); + cy = cos( angle ); + + angle = src.pitch * ( M_PI * 2.0f / 360.0f ); + sp = sin( angle ); + cp = cos( angle ); + + angle = src.roll * ( M_PI * 2.0f / 360.0f ); + sr = sin( angle ); + cr = cos( angle ); + + dst[ 0 ].set( cp * cy, cp * sy, -sp ); + dst[ 1 ].set( sr * sp * cy + cr * -sy, sr * sp * sy + cr * cy, sr * cp ); + dst[ 2 ].set( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp ); +} + +void toMatrix( idVec3_t const &src, mat3_t &dst ) { + angles_t sup = src; + toMatrix(sup, dst); +} + +void mat3_t::ProjectVector( const idVec3_t &src, idVec3_t &dst ) const { + dst.x = src * mat[ 0 ]; + dst.y = src * mat[ 1 ]; + dst.z = src * mat[ 2 ]; +} + +void mat3_t::UnprojectVector( const idVec3_t &src, idVec3_t &dst ) const { + dst = mat[ 0 ] * src.x + mat[ 1 ] * src.y + mat[ 2 ] * src.z; +} + +void mat3_t::Transpose( mat3_t &matrix ) { + int i; + int j; + + for( i = 0; i < 3; i++ ) { + for( j = 0; j < 3; j++ ) { + matrix[ i ][ j ] = mat[ j ][ i ]; + } + } +} + +void mat3_t::Transpose( void ) { + float temp; + int i; + int j; + + for( i = 0; i < 3; i++ ) { + for( j = i + 1; j < 3; j++ ) { + temp = mat[ i ][ j ]; + mat[ i ][ j ] = mat[ j ][ i ]; + mat[ j ][ i ] = temp; + } + } +} + +mat3_t mat3_t::Inverse( void ) const { + mat3_t inv( *this ); + + inv.Transpose(); + + return inv; +} + +void mat3_t::Clear( void ) { + mat[0].set( 1, 0, 0 ); + mat[1].set( 0, 1, 0 ); + mat[2].set( 0, 0, 1 ); +} diff --git a/CODE-mp/Splines/math_matrix.h b/CODE-mp/Splines/math_matrix.h new file mode 100644 index 0000000..38a077d --- /dev/null +++ b/CODE-mp/Splines/math_matrix.h @@ -0,0 +1,202 @@ +#ifndef __MATH_MATRIX_H__ +#define __MATH_MATRIX_H__ + +#include +#include "math_vector.h" + +#ifndef ID_INLINE +#ifdef _WIN32 +#define ID_INLINE __inline +#else +#define ID_INLINE inline +#endif +#endif + +class quat_t; +class angles_t; + +class mat3_t { +public: + idVec3_t mat[ 3 ]; + + mat3_t(); + mat3_t( float src[ 3 ][ 3 ] ); + mat3_t( idVec3_t const &x, idVec3_t const &y, idVec3_t const &z ); + mat3_t( const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz ); + + friend void toMatrix( quat_t const &src, mat3_t &dst ); + friend void toMatrix( angles_t const &src, mat3_t &dst ); + friend void toMatrix( idVec3_t const &src, mat3_t &dst ); + + idVec3_t operator[]( int index ) const; + idVec3_t &operator[]( int index ); + + idVec3_t operator*( const idVec3_t &vec ) const; + mat3_t operator*( const mat3_t &a ) const; + mat3_t operator*( float a ) const; + mat3_t operator+( mat3_t const &a ) const; + mat3_t operator-( mat3_t const &a ) const; + + friend idVec3_t operator*( const idVec3_t &vec, const mat3_t &mat ); + friend mat3_t operator*( float a, mat3_t const &b ); + + mat3_t &operator*=( float a ); + mat3_t &operator+=( mat3_t const &a ); + mat3_t &operator-=( mat3_t const &a ); + + void Clear( void ); + + void ProjectVector( const idVec3_t &src, idVec3_t &dst ) const; + void UnprojectVector( const idVec3_t &src, idVec3_t &dst ) const; + + void OrthoNormalize( void ); + void Transpose( mat3_t &matrix ); + void Transpose( void ); + mat3_t Inverse( void ) const; + void Identity( void ); + + friend void InverseMultiply( const mat3_t &inv, const mat3_t &b, mat3_t &dst ); + friend mat3_t SkewSymmetric( idVec3_t const &src ); +}; + +ID_INLINE mat3_t::mat3_t() { +} + +ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) { + memcpy( mat, src, sizeof( src ) ); +} + +ID_INLINE mat3_t::mat3_t( idVec3_t const &x, idVec3_t const &y, idVec3_t const &z ) { + mat[ 0 ].x = x.x; mat[ 0 ].y = x.y; mat[ 0 ].z = x.z; + mat[ 1 ].x = y.x; mat[ 1 ].y = y.y; mat[ 1 ].z = y.z; + mat[ 2 ].x = z.x; mat[ 2 ].y = z.y; mat[ 2 ].z = z.z; +} + +ID_INLINE mat3_t::mat3_t( const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz ) { + mat[ 0 ].x = xx; mat[ 0 ].y = xy; mat[ 0 ].z = xz; + mat[ 1 ].x = yx; mat[ 1 ].y = yy; mat[ 1 ].z = yz; + mat[ 2 ].x = zx; mat[ 2 ].y = zy; mat[ 2 ].z = zz; +} + +ID_INLINE idVec3_t mat3_t::operator[]( int index ) const { + assert( ( index >= 0 ) && ( index < 3 ) ); + return mat[ index ]; +} + +ID_INLINE idVec3_t& mat3_t::operator[]( int index ) { + assert( ( index >= 0 ) && ( index < 3 ) ); + return mat[ index ]; +} + +ID_INLINE idVec3_t mat3_t::operator*( const idVec3_t &vec ) const { + return idVec3_t( + mat[ 0 ].x * vec.x + mat[ 1 ].x * vec.y + mat[ 2 ].x * vec.z, + mat[ 0 ].y * vec.x + mat[ 1 ].y * vec.y + mat[ 2 ].y * vec.z, + mat[ 0 ].z * vec.x + mat[ 1 ].z * vec.y + mat[ 2 ].z * vec.z ); +} + +ID_INLINE mat3_t mat3_t::operator*( const mat3_t &a ) const { + return mat3_t( + mat[0].x * a[0].x + mat[0].y * a[1].x + mat[0].z * a[2].x, + mat[0].x * a[0].y + mat[0].y * a[1].y + mat[0].z * a[2].y, + mat[0].x * a[0].z + mat[0].y * a[1].z + mat[0].z * a[2].z, + mat[1].x * a[0].x + mat[1].y * a[1].x + mat[1].z * a[2].x, + mat[1].x * a[0].y + mat[1].y * a[1].y + mat[1].z * a[2].y, + mat[1].x * a[0].z + mat[1].y * a[1].z + mat[1].z * a[2].z, + mat[2].x * a[0].x + mat[2].y * a[1].x + mat[2].z * a[2].x, + mat[2].x * a[0].y + mat[2].y * a[1].y + mat[2].z * a[2].y, + mat[2].x * a[0].z + mat[2].y * a[1].z + mat[2].z * a[2].z ); +} + +ID_INLINE mat3_t mat3_t::operator*( float a ) const { + return mat3_t( + mat[0].x * a, mat[0].y * a, mat[0].z * a, + mat[1].x * a, mat[1].y * a, mat[1].z * a, + mat[2].x * a, mat[2].y * a, mat[2].z * a ); +} + +ID_INLINE mat3_t mat3_t::operator+( mat3_t const &a ) const { + return mat3_t( + mat[0].x + a[0].x, mat[0].y + a[0].y, mat[0].z + a[0].z, + mat[1].x + a[1].x, mat[1].y + a[1].y, mat[1].z + a[1].z, + mat[2].x + a[2].x, mat[2].y + a[2].y, mat[2].z + a[2].z ); +} + +ID_INLINE mat3_t mat3_t::operator-( mat3_t const &a ) const { + return mat3_t( + mat[0].x - a[0].x, mat[0].y - a[0].y, mat[0].z - a[0].z, + mat[1].x - a[1].x, mat[1].y - a[1].y, mat[1].z - a[1].z, + mat[2].x - a[2].x, mat[2].y - a[2].y, mat[2].z - a[2].z ); +} + +ID_INLINE idVec3_t operator*( const idVec3_t &vec, const mat3_t &mat ) { + return idVec3_t( + mat[ 0 ].x * vec.x + mat[ 1 ].x * vec.y + mat[ 2 ].x * vec.z, + mat[ 0 ].y * vec.x + mat[ 1 ].y * vec.y + mat[ 2 ].y * vec.z, + mat[ 0 ].z * vec.x + mat[ 1 ].z * vec.y + mat[ 2 ].z * vec.z ); +} + +ID_INLINE mat3_t operator*( float a, mat3_t const &b ) { + return mat3_t( + b[0].x * a, b[0].y * a, b[0].z * a, + b[1].x * a, b[1].y * a, b[1].z * a, + b[2].x * a, b[2].y * a, b[2].z * a ); +} + +ID_INLINE mat3_t &mat3_t::operator*=( float a ) { + mat[0].x *= a; mat[0].y *= a; mat[0].z *= a; + mat[1].x *= a; mat[1].y *= a; mat[1].z *= a; + mat[2].x *= a; mat[2].y *= a; mat[2].z *= a; + + return *this; +} + +ID_INLINE mat3_t &mat3_t::operator+=( mat3_t const &a ) { + mat[0].x += a[0].x; mat[0].y += a[0].y; mat[0].z += a[0].z; + mat[1].x += a[1].x; mat[1].y += a[1].y; mat[1].z += a[1].z; + mat[2].x += a[2].x; mat[2].y += a[2].y; mat[2].z += a[2].z; + + return *this; +} + +ID_INLINE mat3_t &mat3_t::operator-=( mat3_t const &a ) { + mat[0].x -= a[0].x; mat[0].y -= a[0].y; mat[0].z -= a[0].z; + mat[1].x -= a[1].x; mat[1].y -= a[1].y; mat[1].z -= a[1].z; + mat[2].x -= a[2].x; mat[2].y -= a[2].y; mat[2].z -= a[2].z; + + return *this; +} + +ID_INLINE void mat3_t::OrthoNormalize( void ) { + mat[ 0 ].Normalize(); + mat[ 2 ].Cross( mat[ 0 ], mat[ 1 ] ); + mat[ 2 ].Normalize(); + mat[ 1 ].Cross( mat[ 2 ], mat[ 0 ] ); + mat[ 1 ].Normalize(); +} + +ID_INLINE void mat3_t::Identity( void ) { + mat[ 0 ].x = 1.f; mat[ 0 ].y = 0.f; mat[ 0 ].z = 0.f; + mat[ 1 ].x = 0.f; mat[ 1 ].y = 1.f; mat[ 1 ].z = 0.f; + mat[ 2 ].x = 0.f; mat[ 2 ].y = 0.f; mat[ 2 ].z = 1.f; +} + +ID_INLINE void InverseMultiply( const mat3_t &inv, const mat3_t &b, mat3_t &dst ) { + dst[0].x = inv[0].x * b[0].x + inv[1].x * b[1].x + inv[2].x * b[2].x; + dst[0].y = inv[0].x * b[0].y + inv[1].x * b[1].y + inv[2].x * b[2].y; + dst[0].z = inv[0].x * b[0].z + inv[1].x * b[1].z + inv[2].x * b[2].z; + dst[1].x = inv[0].y * b[0].x + inv[1].y * b[1].x + inv[2].y * b[2].x; + dst[1].y = inv[0].y * b[0].y + inv[1].y * b[1].y + inv[2].y * b[2].y; + dst[1].z = inv[0].y * b[0].z + inv[1].y * b[1].z + inv[2].y * b[2].z; + dst[2].x = inv[0].z * b[0].x + inv[1].z * b[1].x + inv[2].z * b[2].x; + dst[2].y = inv[0].z * b[0].y + inv[1].z * b[1].y + inv[2].z * b[2].y; + dst[2].z = inv[0].z * b[0].z + inv[1].z * b[1].z + inv[2].z * b[2].z; +} + +ID_INLINE mat3_t SkewSymmetric( idVec3_t const &src ) { + return mat3_t( 0.0f, -src.z, src.y, src.z, 0.0f, -src.x, -src.y, src.x, 0.0f ); +} + +extern mat3_t mat3_default; + +#endif /* !__MATH_MATRIX_H__ */ diff --git a/CODE-mp/Splines/math_quaternion.cpp b/CODE-mp/Splines/math_quaternion.cpp new file mode 100644 index 0000000..6e27eca --- /dev/null +++ b/CODE-mp/Splines/math_quaternion.cpp @@ -0,0 +1,57 @@ +#include "math_quaternion.h" +#include "math_matrix.h" + +void toQuat( idVec3_t &src, quat_t &dst ) { + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; + dst.w = 0.0f; +} + +void toQuat( angles_t &src, quat_t &dst ) { + mat3_t temp; + + toMatrix( src, temp ); + toQuat( temp, dst ); +} + +void toQuat( mat3_t &src, quat_t &dst ) { + float trace; + float s; + int i; + int j; + int k; + + static int next[ 3 ] = { 1, 2, 0 }; + + trace = src[ 0 ][ 0 ] + src[ 1 ][ 1 ] + src[ 2 ][ 2 ]; + if ( trace > 0.0f ) { + s = ( float )sqrt( trace + 1.0f ); + dst.w = s * 0.5f; + s = 0.5f / s; + + dst.x = ( src[ 2 ][ 1 ] - src[ 1 ][ 2 ] ) * s; + dst.y = ( src[ 0 ][ 2 ] - src[ 2 ][ 0 ] ) * s; + dst.z = ( src[ 1 ][ 0 ] - src[ 0 ][ 1 ] ) * s; + } else { + i = 0; + if ( src[ 1 ][ 1 ] > src[ 0 ][ 0 ] ) { + i = 1; + } + if ( src[ 2 ][ 2 ] > src[ i ][ i ] ) { + i = 2; + } + + j = next[ i ]; + k = next[ j ]; + + s = ( float )sqrt( ( src[ i ][ i ] - ( src[ j ][ j ] + src[ k ][ k ] ) ) + 1.0f ); + dst[ i ] = s * 0.5f; + + s = 0.5f / s; + + dst.w = ( src[ k ][ j ] - src[ j ][ k ] ) * s; + dst[ j ] = ( src[ j ][ i ] + src[ i ][ j ] ) * s; + dst[ k ] = ( src[ k ][ i ] + src[ i ][ k ] ) * s; + } +} diff --git a/CODE-mp/Splines/math_quaternion.h b/CODE-mp/Splines/math_quaternion.h new file mode 100644 index 0000000..4792ba7 --- /dev/null +++ b/CODE-mp/Splines/math_quaternion.h @@ -0,0 +1,169 @@ +#ifndef __MATH_QUATERNION_H__ +#define __MATH_QUATERNION_H__ + +#include +#include + +class idVec3_t; +class angles_t; +class mat3_t; + +class quat_t { +public: + float x; + float y; + float z; + float w; + + quat_t(); + quat_t( float x, float y, float z, float w ); + + friend void toQuat( idVec3_t &src, quat_t &dst ); + friend void toQuat( angles_t &src, quat_t &dst ); + friend void toQuat( mat3_t &src, quat_t &dst ); + + float *vec4( void ); + + float operator[]( int index ) const; + float &operator[]( int index ); + + void set( float x, float y, float z, float w ); + + void operator=( quat_t a ); + + friend quat_t operator+( quat_t a, quat_t b ); + quat_t &operator+=( quat_t a ); + + friend quat_t operator-( quat_t a, quat_t b ); + quat_t &operator-=( quat_t a ); + + friend quat_t operator*( quat_t a, float b ); + friend quat_t operator*( float a, quat_t b ); + quat_t &operator*=( float a ); + + friend int operator==( quat_t a, quat_t b ); + friend int operator!=( quat_t a, quat_t b ); + + float Length( void ); + quat_t &Normalize( void ); + + quat_t operator-(); +}; + +inline quat_t::quat_t() { +} + +inline quat_t::quat_t( float x, float y, float z, float w ) { + this->x = x; + this->y = y; + this->z = z; + this->w = w; +} + +inline float *quat_t::vec4( void ) { + return &x; +} + +inline float quat_t::operator[]( int index ) const { + assert( ( index >= 0 ) && ( index < 4 ) ); + return ( &x )[ index ]; +} + +inline float& quat_t::operator[]( int index ) { + assert( ( index >= 0 ) && ( index < 4 ) ); + return ( &x )[ index ]; +} + +inline void quat_t::set( float x, float y, float z, float w ) { + this->x = x; + this->y = y; + this->z = z; + this->w = w; +} + +inline void quat_t::operator=( quat_t a ) { + x = a.x; + y = a.y; + z = a.z; + w = a.w; +} + +inline quat_t operator+( quat_t a, quat_t b ) { + return quat_t( a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w ); +} + +inline quat_t& quat_t::operator+=( quat_t a ) { + x += a.x; + y += a.y; + z += a.z; + w += a.w; + + return *this; +} + +inline quat_t operator-( quat_t a, quat_t b ) { + return quat_t( a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w ); +} + +inline quat_t& quat_t::operator-=( quat_t a ) { + x -= a.x; + y -= a.y; + z -= a.z; + w -= a.w; + + return *this; +} + +inline quat_t operator*( quat_t a, float b ) { + return quat_t( a.x * b, a.y * b, a.z * b, a.w * b ); +} + +inline quat_t operator*( float a, quat_t b ) { + return b * a; +} + +inline quat_t& quat_t::operator*=( float a ) { + x *= a; + y *= a; + z *= a; + w *= a; + + return *this; +} + +inline int operator==( quat_t a, quat_t b ) { + return ( ( a.x == b.x ) && ( a.y == b.y ) && ( a.z == b.z ) && ( a.w == b.w ) ); +} + +inline int operator!=( quat_t a, quat_t b ) { + return ( ( a.x != b.x ) || ( a.y != b.y ) || ( a.z != b.z ) && ( a.w != b.w ) ); +} + +inline float quat_t::Length( void ) { + float length; + + length = x * x + y * y + z * z + w * w; + return ( float )sqrt( length ); +} + +inline quat_t& quat_t::Normalize( void ) { + float length; + float ilength; + + length = this->Length(); + if ( length ) { + ilength = 1 / length; + x *= ilength; + y *= ilength; + z *= ilength; + w *= ilength; + } + + return *this; +} + +inline quat_t quat_t::operator-() { + return quat_t( -x, -y, -z, -w ); +} + +#endif /* !__MATH_QUATERNION_H__ */ diff --git a/CODE-mp/Splines/math_vector.cpp b/CODE-mp/Splines/math_vector.cpp new file mode 100644 index 0000000..8c3b1bb --- /dev/null +++ b/CODE-mp/Splines/math_vector.cpp @@ -0,0 +1,123 @@ +//#include "../game/q_shared.h" +#include "math_vector.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h + +#define LERP_DELTA 1e-6 + +idVec3_t vec_zero( 0.0f, 0.0f, 0.0f ); + +Bounds boundsZero; + +float idVec3_t::toYaw( void ) { + float yaw; + + if ( ( y == 0 ) && ( x == 0 ) ) { + yaw = 0; + } else { + yaw = atan2( y, x ) * 180 / M_PI; + if ( yaw < 0 ) { + yaw += 360; + } + } + + return yaw; +} + +float idVec3_t::toPitch( void ) { + float forward; + float pitch; + + if ( ( x == 0 ) && ( y == 0 ) ) { + if ( z > 0 ) { + pitch = 90; + } else { + pitch = 270; + } + } else { + forward = ( float )idSqrt( x * x + y * y ); + pitch = atan2( z, forward ) * 180 / M_PI; + if ( pitch < 0 ) { + pitch += 360; + } + } + + return pitch; +} + +/* +angles_t idVec3_t::toAngles( void ) { + float forward; + float yaw; + float pitch; + + if ( ( x == 0 ) && ( y == 0 ) ) { + yaw = 0; + if ( z > 0 ) { + pitch = 90; + } else { + pitch = 270; + } + } else { + yaw = atan2( y, x ) * 180 / M_PI; + if ( yaw < 0 ) { + yaw += 360; + } + + forward = ( float )idSqrt( x * x + y * y ); + pitch = atan2( z, forward ) * 180 / M_PI; + if ( pitch < 0 ) { + pitch += 360; + } + } + + return angles_t( -pitch, yaw, 0 ); +} +*/ + +idVec3_t LerpVector( idVec3_t &w1, idVec3_t &w2, const float t ) { + float omega, cosom, sinom, scale0, scale1; + + cosom = w1 * w2; + if ( ( 1.0 - cosom ) > LERP_DELTA ) { + omega = acos( cosom ); + sinom = sin( omega ); + scale0 = sin( ( 1.0 - t ) * omega ) / sinom; + scale1 = sin( t * omega ) / sinom; + } else { + scale0 = 1.0 - t; + scale1 = t; + } + + return ( w1 * scale0 + w2 * scale1 ); +} + +/* +============= +idVec3_t::string + +This is just a convenience function +for printing vectors +============= +*/ +char *idVec3_t::string( void ) { + static int index = 0; + static char str[ 8 ][ 36 ]; + char *s; + + // use an array so that multiple toString's won't collide + s = str[ index ]; + index = (index + 1)&7; + + sprintf( s, "%.2f %.2f %.2f", x, y, z ); + + return s; +} diff --git a/CODE-mp/Splines/math_vector.h b/CODE-mp/Splines/math_vector.h new file mode 100644 index 0000000..0350de1 --- /dev/null +++ b/CODE-mp/Splines/math_vector.h @@ -0,0 +1,553 @@ +#ifndef __MATH_VECTOR_H__ +#define __MATH_VECTOR_H__ + +#if defined(_WIN32) +#pragma warning(disable : 4244) +#endif + +#include +#include + +//#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]) +//#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) +//#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) +//#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) +//#define VectorCopy(a,b) ((b).x=(a).x,(b).y=(a).y,(b).z=(a).z]) + +//#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s)) +#define __VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s)) +//#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0]) + +#define DotProduct4(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]+(x)[3]*(y)[3]) +#define VectorSubtract4(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3]) +#define VectorAdd4(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3]) +#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) +#define VectorScale4(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s),(o)[3]=(v)[3]*(s)) +#define VectorMA4(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s),(o)[3]=(v)[3]+(b)[3]*(s)) + + +//#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0) +#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) +//#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z)) +#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) + +#define SnapVector(v) {v[0]=(int)v[0];v[1]=(int)v[1];v[2]=(int)v[2];} + + +//#include "util_heap.h" + +#ifndef EQUAL_EPSILON +#define EQUAL_EPSILON 0.001 +#endif + +float Q_fabs( float f ); + +#ifndef ID_INLINE +#ifdef _WIN32 +#define ID_INLINE __inline +#else +#define ID_INLINE inline +#endif +#endif + +// if this is defined, vec3 will take four elements, which may allow +// easier SIMD optimizations +//#define FAT_VEC3 +//#ifdef __ppc__ +//#pragma align(16) +//#endif + +class angles_t; +#ifdef __ppc__ +// Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction, +// runs *much* faster than calling sqrt(). We'll use two Newton-Raphson +// refinement steps to get bunch more precision in the 1/sqrt() value for very little cost. +// We'll then multiply 1/sqrt times the original value to get the sqrt. +// This is about 12.4 times faster than sqrt() and according to my testing (not exhaustive) +// it returns fairly accurate results (error below 1.0e-5 up to 100000.0 in 0.1 increments). + +static inline float idSqrt(float x) { + const float half = 0.5; + const float one = 1.0; + float B, y0, y1; + + // This'll NaN if it hits frsqrte. Handle both +0.0 and -0.0 + if (fabs(x) == 0.0) + return x; + B = x; + +#ifdef __GNUC__ + asm("frsqrte %0,%1" : "=f" (y0) : "f" (B)); +#else + y0 = __frsqrte(B); +#endif + /* First refinement step */ + + y1 = y0 + half*y0*(one - B*y0*y0); + + /* Second refinement step -- copy the output of the last step to the input of this step */ + + y0 = y1; + y1 = y0 + half*y0*(one - B*y0*y0); + + /* Get sqrt(x) from x * 1/sqrt(x) */ + return x * y1; +} +#else +static inline double idSqrt(double x) { + return sqrt(x); +} +#endif + + +//class idVec3_t : public idHeap { +class idVec3_t { +public: +#ifndef FAT_VEC3 + float x,y,z; +#else + float x,y,z,dist; +#endif + +#ifndef FAT_VEC3 + idVec3_t() {}; +#else + idVec3_t() {dist = 0.0f;}; +#endif + idVec3_t( const float x, const float y, const float z ); + + operator float *(); + + float operator[]( const int index ) const; + float &operator[]( const int index ); + + void set( const float x, const float y, const float z ); + + idVec3_t operator-() const; + + idVec3_t &operator=( const idVec3_t &a ); + + float operator*( const idVec3_t &a ) const; + idVec3_t operator*( const float a ) const; + friend idVec3_t operator*( float a, idVec3_t b ); + + idVec3_t operator+( const idVec3_t &a ) const; + idVec3_t operator-( const idVec3_t &a ) const; + + idVec3_t &operator+=( const idVec3_t &a ); + idVec3_t &operator-=( const idVec3_t &a ); + idVec3_t &operator*=( const float a ); + + int operator==( const idVec3_t &a ) const; + int operator!=( const idVec3_t &a ) const; + + idVec3_t Cross( const idVec3_t &a ) const; + idVec3_t &Cross( const idVec3_t &a, const idVec3_t &b ); + + float Length( void ) const; + float Normalize( void ); + + void Zero( void ); + void Snap( void ); + void SnapTowards( const idVec3_t &to ); + + float toYaw( void ); + float toPitch( void ); + angles_t toAngles( void ); + friend idVec3_t LerpVector( const idVec3_t &w1, const idVec3_t &w2, const float t ); + + char *string( void ); +}; + +extern idVec3_t vec_zero; + +ID_INLINE idVec3_t::idVec3_t( const float x, const float y, const float z ) { + this->x = x; + this->y = y; + this->z = z; +#ifdef FAT_VEC3 + this->dist = 0.0f; +#endif +} + +ID_INLINE float idVec3_t::operator[]( const int index ) const { + return ( &x )[ index ]; +} + +ID_INLINE float &idVec3_t::operator[]( const int index ) { + return ( &x )[ index ]; +} + +ID_INLINE idVec3_t::operator float *( void ) { + return &x; +} + +ID_INLINE idVec3_t idVec3_t::operator-() const { + return idVec3_t( -x, -y, -z ); +} + +ID_INLINE idVec3_t &idVec3_t::operator=( const idVec3_t &a ) { + x = a.x; + y = a.y; + z = a.z; + + return *this; +} + +ID_INLINE void idVec3_t::set( const float x, const float y, const float z ) { + this->x = x; + this->y = y; + this->z = z; +} + +ID_INLINE idVec3_t idVec3_t::operator-( const idVec3_t &a ) const { + return idVec3_t( x - a.x, y - a.y, z - a.z ); +} + +ID_INLINE float idVec3_t::operator*( const idVec3_t &a ) const { + return x * a.x + y * a.y + z * a.z; +} + +ID_INLINE idVec3_t idVec3_t::operator*( const float a ) const { + return idVec3_t( x * a, y * a, z * a ); +} + +ID_INLINE idVec3_t operator*( const float a, const idVec3_t b ) { + return idVec3_t( b.x * a, b.y * a, b.z * a ); +} + +ID_INLINE idVec3_t idVec3_t::operator+( const idVec3_t &a ) const { + return idVec3_t( x + a.x, y + a.y, z + a.z ); +} + +ID_INLINE idVec3_t &idVec3_t::operator+=( const idVec3_t &a ) { + x += a.x; + y += a.y; + z += a.z; + + return *this; +} + +ID_INLINE idVec3_t &idVec3_t::operator-=( const idVec3_t &a ) { + x -= a.x; + y -= a.y; + z -= a.z; + + return *this; +} + +ID_INLINE idVec3_t &idVec3_t::operator*=( const float a ) { + x *= a; + y *= a; + z *= a; + + return *this; +} + +ID_INLINE int idVec3_t::operator==( const idVec3_t &a ) const { + if ( Q_fabs( x - a.x ) > EQUAL_EPSILON ) { + return false; + } + + if ( Q_fabs( y - a.y ) > EQUAL_EPSILON ) { + return false; + } + + if ( Q_fabs( z - a.z ) > EQUAL_EPSILON ) { + return false; + } + + return true; +} + +ID_INLINE int idVec3_t::operator!=( const idVec3_t &a ) const { + if ( Q_fabs( x - a.x ) > EQUAL_EPSILON ) { + return true; + } + + if ( Q_fabs( y - a.y ) > EQUAL_EPSILON ) { + return true; + } + + if ( Q_fabs( z - a.z ) > EQUAL_EPSILON ) { + return true; + } + + return false; +} + +ID_INLINE idVec3_t idVec3_t::Cross( const idVec3_t &a ) const { + return idVec3_t( y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x ); +} + +ID_INLINE idVec3_t &idVec3_t::Cross( const idVec3_t &a, const idVec3_t &b ) { + x = a.y * b.z - a.z * b.y; + y = a.z * b.x - a.x * b.z; + z = a.x * b.y - a.y * b.x; + + return *this; +} + +ID_INLINE float idVec3_t::Length( void ) const { + float length; + + length = x * x + y * y + z * z; + return ( float )idSqrt( length ); +} + +ID_INLINE float idVec3_t::Normalize( void ) { + float length; + float ilength; + + length = this->Length(); + if ( length ) { + ilength = 1.0f / length; + x *= ilength; + y *= ilength; + z *= ilength; + } + + return length; +} + +ID_INLINE void idVec3_t::Zero( void ) { + x = 0.0f; + y = 0.0f; + z = 0.0f; +} + +ID_INLINE void idVec3_t::Snap( void ) { + x = float( int( x ) ); + y = float( int( y ) ); + z = float( int( z ) ); +} + +/* +====================== +SnapTowards + +Round a vector to integers for more efficient network +transmission, but make sure that it rounds towards a given point +rather than blindly truncating. This prevents it from truncating +into a wall. +====================== +*/ +ID_INLINE void idVec3_t::SnapTowards( const idVec3_t &to ) { + if ( to.x <= x ) { + x = float( int( x ) ); + } else { + x = float( int( x ) + 1 ); + } + + if ( to.y <= y ) { + y = float( int( y ) ); + } else { + y = float( int( y ) + 1 ); + } + + if ( to.z <= z ) { + z = float( int( z ) ); + } else { + z = float( int( z ) + 1 ); + } +} + +//=============================================================== + +class Bounds { +public: + idVec3_t b[2]; + + Bounds(); + Bounds( const idVec3_t &mins, const idVec3_t &maxs ); + + void Clear(); + void Zero(); + float Radius(); // radius from origin, not from center + idVec3_t Center(); + void AddPoint( const idVec3_t &v ); + void AddBounds( const Bounds &bb ); + bool IsCleared(); + bool ContainsPoint( const idVec3_t &p ); + bool IntersectsBounds( const Bounds &b2 ); // touching is NOT intersecting +}; + +extern Bounds boundsZero; + +ID_INLINE Bounds::Bounds(){ +} + +ID_INLINE bool Bounds::IsCleared() { + return b[0][0] > b[1][0]; +} + +ID_INLINE bool Bounds::ContainsPoint( const idVec3_t &p ) { + if ( p[0] < b[0][0] || p[1] < b[0][1] || p[2] < b[0][2] + || p[0] > b[1][0] || p[1] > b[1][1] || p[2] > b[1][2] ) { + return false; + } + return true; +} + +ID_INLINE bool Bounds::IntersectsBounds( const Bounds &b2 ) { + if ( b2.b[1][0] < b[0][0] || b2.b[1][1] < b[0][1] || b2.b[1][2] < b[0][2] + || b2.b[0][0] > b[1][0] || b2.b[0][1] > b[1][1] || b2.b[0][2] > b[1][2] ) { + return false; + } + return true; +} + +ID_INLINE Bounds::Bounds( const idVec3_t &mins, const idVec3_t &maxs ) { + b[0] = mins; + b[1] = maxs; +} + +ID_INLINE idVec3_t Bounds::Center() { + return idVec3_t( ( b[1][0] + b[0][0] ) * 0.5f, ( b[1][1] + b[0][1] ) * 0.5f, ( b[1][2] + b[0][2] ) * 0.5f ); +} + +ID_INLINE void Bounds::Clear() { + b[0][0] = b[0][1] = b[0][2] = 99999; + b[1][0] = b[1][1] = b[1][2] = -99999; +} + +ID_INLINE void Bounds::Zero() { + b[0][0] = b[0][1] = b[0][2] = + b[1][0] = b[1][1] = b[1][2] = 0; +} + +ID_INLINE void Bounds::AddPoint( const idVec3_t &v ) { + if ( v[0] < b[0][0]) { + b[0][0] = v[0]; + } + if ( v[0] > b[1][0]) { + b[1][0] = v[0]; + } + if ( v[1] < b[0][1] ) { + b[0][1] = v[1]; + } + if ( v[1] > b[1][1]) { + b[1][1] = v[1]; + } + if ( v[2] < b[0][2] ) { + b[0][2] = v[2]; + } + if ( v[2] > b[1][2]) { + b[1][2] = v[2]; + } +} + + +ID_INLINE void Bounds::AddBounds( const Bounds &bb ) { + if ( bb.b[0][0] < b[0][0]) { + b[0][0] = bb.b[0][0]; + } + if ( bb.b[0][1] < b[0][1]) { + b[0][1] = bb.b[0][1]; + } + if ( bb.b[0][2] < b[0][2]) { + b[0][2] = bb.b[0][2]; + } + + if ( bb.b[1][0] > b[1][0]) { + b[1][0] = bb.b[1][0]; + } + if ( bb.b[1][1] > b[1][1]) { + b[1][1] = bb.b[1][1]; + } + if ( bb.b[1][2] > b[1][2]) { + b[1][2] = bb.b[1][2]; + } +} + +ID_INLINE float Bounds::Radius( ) { + int i; + float total; + float a, aa; + + total = 0; + for (i=0 ; i<3 ; i++) { + a = (float)fabs( b[0][i] ); + aa = (float)fabs( b[1][i] ); + if ( aa > a ) { + a = aa; + } + total += a * a; + } + + return (float)idSqrt( total ); +} + +//=============================================================== + + +class idVec2_t { +public: + float x; + float y; + + operator float *(); + float operator[]( int index ) const; + float &operator[]( int index ); +}; + +ID_INLINE float idVec2_t::operator[]( int index ) const { + return ( &x )[ index ]; +} + +ID_INLINE float& idVec2_t::operator[]( int index ) { + return ( &x )[ index ]; +} + +ID_INLINE idVec2_t::operator float *( void ) { + return &x; +} + +class vec4_t : public idVec3_t { +public: +#ifndef FAT_VEC3 + float dist; +#endif + vec4_t(); + ~vec4_t() {}; + + vec4_t( float x, float y, float z, float dist ); + float operator[]( int index ) const; + float &operator[]( int index ); +}; + +ID_INLINE vec4_t::vec4_t() {} +ID_INLINE vec4_t::vec4_t( float x, float y, float z, float dist ) { + this->x = x; + this->y = y; + this->z = z; + this->dist = dist; +} + +ID_INLINE float vec4_t::operator[]( int index ) const { + return ( &x )[ index ]; +} + +ID_INLINE float& vec4_t::operator[]( int index ) { + return ( &x )[ index ]; +} + + +class idVec5_t : public idVec3_t { +public: + float s; + float t; + float operator[]( int index ) const; + float &operator[]( int index ); +}; + + +ID_INLINE float idVec5_t::operator[]( int index ) const { + return ( &x )[ index ]; +} + +ID_INLINE float& idVec5_t::operator[]( int index ) { + return ( &x )[ index ]; +} + +#endif /* !__MATH_VECTOR_H__ */ diff --git a/CODE-mp/Splines/mssccprj.scc b/CODE-mp/Splines/mssccprj.scc new file mode 100644 index 0000000..a2ee319 --- /dev/null +++ b/CODE-mp/Splines/mssccprj.scc @@ -0,0 +1,5 @@ +SCC = This is a Source Code Control file + +[Splines.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\jk2sof2MP" +SCC_Project_Name = "$/General/code/Splines", GAAAAAAA diff --git a/CODE-mp/Splines/q_parse.cpp b/CODE-mp/Splines/q_parse.cpp new file mode 100644 index 0000000..6413d82 --- /dev/null +++ b/CODE-mp/Splines/q_parse.cpp @@ -0,0 +1,514 @@ +// q_parse.c -- support for parsing text files + +#include "q_shared.h" + +/* +============================================================================ + +PARSING + +============================================================================ +*/ + +// multiple character punctuation tokens +static const char *punctuation[] = { + "+=", "-=", "*=", "/=", "&=", "|=", "++", "--", + "&&", "||", "<=", ">=", "==", "!=", + NULL +}; + +typedef struct { + char token[MAX_TOKEN_CHARS]; + int lines; + qboolean ungetToken; + char parseFile[MAX_QPATH]; +} parseInfo_t; + +#define MAX_PARSE_INFO 16 +static parseInfo_t parseInfo[MAX_PARSE_INFO]; +static int parseInfoNum; +static parseInfo_t *pi = &parseInfo[0]; + +/* +=================== +Com_BeginParseSession +=================== +*/ +void Com_BeginParseSession( const char *filename ) { + if ( parseInfoNum == MAX_PARSE_INFO - 1 ) { + Com_Error( ERR_FATAL, "Com_BeginParseSession: session overflow" ); + } + parseInfoNum++; + pi = &parseInfo[parseInfoNum]; + + pi->lines = 1; + Q_strncpyz( pi->parseFile, filename, sizeof( pi->parseFile ) ); +} + +/* +=================== +Com_EndParseSession +=================== +*/ +void Com_EndParseSession( void ) { + if ( parseInfoNum == 0 ) { + Com_Error( ERR_FATAL, "Com_EndParseSession: session underflow" ); + } + parseInfoNum--; + pi = &parseInfo[parseInfoNum]; +} + +/* +=================== +Com_GetCurrentParseLine +=================== +*/ +int Com_GetCurrentParseLine( void ) { + return pi->lines; +} + +/* +=================== +Com_ScriptError + +Prints the script name and line number in the message +=================== +*/ +void Com_ScriptError( const char *msg, ... ) { + va_list argptr; + char string[32000]; + + va_start( argptr, msg ); + vsprintf( string, msg,argptr ); + va_end( argptr ); + + Com_Error( ERR_DROP, "File %s, line %i: %s", pi->parseFile, pi->lines, string ); +} + +void Com_ScriptWarning( const char *msg, ... ) { + va_list argptr; + char string[32000]; + + va_start( argptr, msg ); + vsprintf( string, msg,argptr ); + va_end( argptr ); + + Com_Printf( "File %s, line %i: %s", pi->parseFile, pi->lines, string ); +} + + +/* +=================== +Com_UngetToken + +Calling this will make the next Com_Parse return +the current token instead of advancing the pointer +=================== +*/ +void Com_UngetToken( void ) { + if ( pi->ungetToken ) { + Com_ScriptError( "UngetToken called twice" ); + } + pi->ungetToken = qtrue; +} + + +static const char *SkipWhitespace( const char (*data), qboolean *hasNewLines ) { + int c; + + while( (c = *data) <= ' ') { + if( !c ) { + return NULL; + } + if( c == '\n' ) { + pi->lines++; + *hasNewLines = qtrue; + } + data++; + } + + return data; +} + +/* +============== +Com_ParseExt + +Parse a token out of a string +Will never return NULL, just empty strings. +An empty string will only be returned at end of file. + +If "allowLineBreaks" is qtrue then an empty +string will be returned if the next token is +a newline. +============== +*/ +static char *Com_ParseExt( const char *(*data_p), qboolean allowLineBreaks ) { + int c = 0, len; + qboolean hasNewLines = qfalse; + const char *data; + const char **punc; + + if ( !data_p ) { + Com_Error( ERR_FATAL, "Com_ParseExt: NULL data_p" ); + } + + data = *data_p; + len = 0; + pi->token[0] = 0; + + // make sure incoming data is valid + if ( !data ) { + *data_p = NULL; + return pi->token; + } + + // skip any leading whitespace + while ( 1 ) { + // skip whitespace + data = SkipWhitespace( data, &hasNewLines ); + if ( !data ) { + *data_p = NULL; + return pi->token; + } + if ( hasNewLines && !allowLineBreaks ) { + *data_p = data; + return pi->token; + } + + c = *data; + + // skip double slash comments + if ( c == '/' && data[1] == '/' ) { + while (*data && *data != '\n') { + data++; + } + continue; + } + + // skip /* */ comments + if ( c=='/' && data[1] == '*' ) { + while ( *data && ( *data != '*' || data[1] != '/' ) ) { + if( *data == '\n' ) { + pi->lines++; + } + data++; + } + if ( *data ) { + data += 2; + } + continue; + } + + // a real token to parse + break; + } + + // handle quoted strings + if ( c == '\"' ) { + data++; + while( 1 ) { + c = *data++; + if ( ( c=='\\' ) && ( *data == '\"' ) ) { + // allow quoted strings to use \" to indicate the " character + data++; + } else if ( c=='\"' || !c ) { + pi->token[len] = 0; + *data_p = ( char * ) data; + return pi->token; + } else if( *data == '\n' ) { + pi->lines++; + } + if ( len < MAX_TOKEN_CHARS - 1 ) { + pi->token[len] = c; + len++; + } + } + } + + // check for a number + // is this parsing of negative numbers going to cause expression problems + if ( ( c >= '0' && c <= '9' ) || ( c == '-' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) || + ( c == '.' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) ) { + do { + + if (len < MAX_TOKEN_CHARS - 1) { + pi->token[len] = c; + len++; + } + data++; + + c = *data; + } while ( ( c >= '0' && c <= '9' ) || c == '.' ); + + // parse the exponent + if ( c == 'e' || c == 'E' ) { + if (len < MAX_TOKEN_CHARS - 1) { + pi->token[len] = c; + len++; + } + data++; + c = *data; + + if ( c == '-' || c == '+' ) { + if (len < MAX_TOKEN_CHARS - 1) { + pi->token[len] = c; + len++; + } + data++; + c = *data; + } + + do { + if (len < MAX_TOKEN_CHARS - 1) { + pi->token[len] = c; + len++; + } + data++; + + c = *data; + } while ( c >= '0' && c <= '9' ); + } + + if (len == MAX_TOKEN_CHARS) { + len = 0; + } + pi->token[len] = 0; + + *data_p = ( char * ) data; + return pi->token; + } + + // check for a regular word + // we still allow forward and back slashes in name tokens for pathnames + // and also colons for drive letters + if ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' || c == '/' || c == '\\' ) { + do { + if (len < MAX_TOKEN_CHARS - 1) { + pi->token[len] = c; + len++; + } + data++; + + c = *data; + } while ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' + || ( c >= '0' && c <= '9' ) || c == '/' || c == '\\' || c == ':' || c == '.' ); + + if (len == MAX_TOKEN_CHARS) { + len = 0; + } + pi->token[len] = 0; + + *data_p = ( char * ) data; + return pi->token; + } + + // check for multi-character punctuation token + for ( punc = punctuation ; *punc ; punc++ ) { + int l; + int j; + + l = strlen( *punc ); + for ( j = 0 ; j < l ; j++ ) { + if ( data[j] != (*punc)[j] ) { + break; + } + } + if ( j == l ) { + // a valid multi-character punctuation + memcpy( pi->token, *punc, l ); + pi->token[l] = 0; + data += l; + *data_p = (char *)data; + return pi->token; + } + } + + // single character punctuation + pi->token[0] = *data; + pi->token[1] = 0; + data++; + *data_p = (char *)data; + + return pi->token; +} + +/* +=================== +Com_Parse +=================== +*/ +const char *Com_Parse( const char *(*data_p) ) { + if ( pi->ungetToken ) { + pi->ungetToken = qfalse; + return pi->token; + } + return Com_ParseExt( data_p, qtrue ); +} + +/* +=================== +Com_ParseOnLine +=================== +*/ +const char *Com_ParseOnLine( const char *(*data_p) ) { + if ( pi->ungetToken ) { + pi->ungetToken = qfalse; + return pi->token; + } + return Com_ParseExt( data_p, qfalse ); +} + + + +/* +================== +Com_MatchToken +================== +*/ +void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning ) { + const char *token; + + token = Com_Parse( buf_p ); + if ( strcmp( token, match ) ) { + if (warning) { + Com_ScriptWarning( "MatchToken: %s != %s", token, match ); + } else { + Com_ScriptError( "MatchToken: %s != %s", token, match ); + } + } +} + + +/* +================= +Com_SkipBracedSection + +The next token should be an open brace. +Skips until a matching close brace is found. +Internal brace depths are properly skipped. +================= +*/ +void Com_SkipBracedSection( const char *(*program) ) { + const char *token; + int depth; + + depth = 0; + do { + token = Com_Parse( program ); + if( token[1] == 0 ) { + if( token[0] == '{' ) { + depth++; + } + else if( token[0] == '}' ) { + depth--; + } + } + } while( depth && *program ); +} + +/* +================= +Com_SkipRestOfLine +================= +*/ +void Com_SkipRestOfLine ( const char *(*data) ) { + const char *p; + int c; + + p = *data; + while ( (c = *p++) != 0 ) { + if ( c == '\n' ) { + pi->lines++; + break; + } + } + + *data = p; +} + +/* +==================== +Com_ParseRestOfLine +==================== +*/ +const char *Com_ParseRestOfLine( const char *(*data_p) ) { + static char line[MAX_TOKEN_CHARS]; + const char *token; + + line[0] = 0; + while( 1 ) { + token = Com_ParseOnLine( data_p ); + if ( !token[0] ) { + break; + } + if ( line[0] ) { + Q_strcat( line, sizeof(line), " " ); + } + Q_strcat( line, sizeof(line), token ); + } + + return line; +} + + +float Com_ParseFloat( const char *(*buf_p) ) { + const char *token; + + token = Com_Parse( buf_p ); + if ( !token[0] ) { + return 0; + } + return atof( token ); +} + +int Com_ParseInt( const char *(*buf_p) ) { + const char *token; + + token = Com_Parse( buf_p ); + if ( !token[0] ) { + return 0; + } + return atoi( token ); +} + + + +void Com_Parse1DMatrix( const char *(*buf_p), int x, float *m ) { + const char *token; + int i; + + Com_MatchToken( buf_p, "(" ); + + for (i = 0 ; i < x ; i++) { + token = Com_Parse(buf_p); + m[i] = atof(token); + } + + Com_MatchToken( buf_p, ")" ); +} + +void Com_Parse2DMatrix( const char *(*buf_p), int y, int x, float *m ) { + int i; + + Com_MatchToken( buf_p, "(" ); + + for (i = 0 ; i < y ; i++) { + Com_Parse1DMatrix (buf_p, x, m + i * x); + } + + Com_MatchToken( buf_p, ")" ); +} + +void Com_Parse3DMatrix( const char *(*buf_p), int z, int y, int x, float *m ) { + int i; + + Com_MatchToken( buf_p, "(" ); + + for (i = 0 ; i < z ; i++) { + Com_Parse2DMatrix (buf_p, y, x, m + i * x*y); + } + + Com_MatchToken( buf_p, ")" ); +} + diff --git a/CODE-mp/Splines/q_shared.cpp b/CODE-mp/Splines/q_shared.cpp new file mode 100644 index 0000000..23757ea --- /dev/null +++ b/CODE-mp/Splines/q_shared.cpp @@ -0,0 +1,955 @@ +// q_shared.c -- stateless support routines that are included in each code dll +#include "q_shared.h" + +/* +============================================================================ + +GROWLISTS + +============================================================================ +*/ + +// malloc / free all in one place for debugging +extern "C" void *Com_Allocate( int bytes ); +extern "C" void Com_Dealloc( void *ptr ); + +void Com_InitGrowList( growList_t *list, int maxElements ) { + list->maxElements = maxElements; + list->currentElements = 0; + list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) ); +} + +int Com_AddToGrowList( growList_t *list, void *data ) { + void **old; + + if ( list->currentElements != list->maxElements ) { + list->elements[list->currentElements] = data; + return list->currentElements++; + } + + // grow, reallocate and move + old = list->elements; + + if ( list->maxElements < 0 ) { + Com_Error( ERR_FATAL, "Com_AddToGrowList: maxElements = %i", list->maxElements ); + } + + if ( list->maxElements == 0 ) { + // initialize the list to hold 100 elements + Com_InitGrowList( list, 100 ); + return Com_AddToGrowList( list, data ); + } + + list->maxElements *= 2; + + Com_DPrintf( "Resizing growlist to %i maxElements\n", list->maxElements ); + + list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) ); + + if ( !list->elements ) { + Com_Error( ERR_DROP, "Growlist alloc failed" ); + } + + memcpy( list->elements, old, list->currentElements * sizeof( void * ) ); + + Com_Dealloc( old ); + + return Com_AddToGrowList( list, data ); +} + +void *Com_GrowListElement( const growList_t *list, int index ) { + if ( index < 0 || index >= list->currentElements ) { + Com_Error( ERR_DROP, "Com_GrowListElement: %i out of range of %i", + index, list->currentElements ); + } + return list->elements[index]; +} + +int Com_IndexForGrowListElement( const growList_t *list, const void *element ) { + int i; + + for ( i = 0 ; i < list->currentElements ; i++ ) { + if ( list->elements[i] == element ) { + return i; + } + } + return -1; +} + +//============================================================================ + + +float Com_Clamp( float min, float max, float value ) { + if ( value < min ) { + return min; + } + if ( value > max ) { + return max; + } + return value; +} + +/* +============ +Com_StringContains +============ +*/ +const char *Com_StringContains( const char *str1, const char *str2, int casesensitive) { + int len, i, j; + + len = strlen(str1) - strlen(str2); + for (i = 0; i <= len; i++, str1++) { + for (j = 0; str2[j]; j++) { + if (casesensitive) { + if (str1[j] != str2[j]) { + break; + } + } + else { + if (toupper(str1[j]) != toupper(str2[j])) { + break; + } + } + } + if (!str2[j]) { + return str1; + } + } + return NULL; +} + +/* +============ +Com_Filter +============ +*/ +int Com_Filter( const char *filter, const char *name, int casesensitive) +{ + char buf[MAX_TOKEN_CHARS]; + const char *ptr; + int i, found; + + while(*filter) { + if (*filter == '*') { + filter++; + for (i = 0; *filter; i++) { + if (*filter == '*' || *filter == '?') break; + buf[i] = *filter; + filter++; + } + buf[i] = '\0'; + if (strlen(buf)) { + ptr = Com_StringContains(name, buf, casesensitive); + if (!ptr) return qfalse; + name = ptr + strlen(buf); + } + } + else if (*filter == '?') { + filter++; + name++; + } + else if (*filter == '[' && *(filter+1) == '[') { + filter++; + } + else if (*filter == '[') { + filter++; + found = qfalse; + while(*filter && !found) { + if (*filter == ']' && *(filter+1) != ']') break; + if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) { + if (casesensitive) { + if (*name >= *filter && *name <= *(filter+2)) found = qtrue; + } + else { + if (toupper(*name) >= toupper(*filter) && + toupper(*name) <= toupper(*(filter+2))) found = qtrue; + } + filter += 3; + } + else { + if (casesensitive) { + if (*filter == *name) found = qtrue; + } + else { + if (toupper(*filter) == toupper(*name)) found = qtrue; + } + filter++; + } + } + if (!found) return qfalse; + while(*filter) { + if (*filter == ']' && *(filter+1) != ']') break; + filter++; + } + filter++; + name++; + } + else { + if (casesensitive) { + if (*filter != *name) return qfalse; + } + else { + if (toupper(*filter) != toupper(*name)) return qfalse; + } + filter++; + name++; + } + } + return qtrue; +} + + +/* +================ +Com_HashString + +================ +*/ +int Com_HashString( const char *fname ) { + int i; + long hash; + char letter; + + hash = 0; + i = 0; + while (fname[i] != '\0') { + letter = tolower(fname[i]); + if (letter =='.') break; // don't include extension + if (letter =='\\') letter = '/'; // damn path names + hash+=(long)(letter)*(i+119); + i++; + } + hash &= (FILE_HASH_SIZE-1); + return hash; +} + + +/* +============ +Com_SkipPath +============ +*/ +char *Com_SkipPath (char *pathname) +{ + char *last; + + last = pathname; + while (*pathname) + { + if (*pathname=='/') + last = pathname+1; + pathname++; + } + return last; +} + +/* +============ +Com_StripExtension +============ +*/ +void Com_StripExtension( const char *in, char *out ) { + while ( *in && *in != '.' ) { + *out++ = *in++; + } + *out = 0; +} + + +/* +================== +Com_DefaultExtension +================== +*/ +void Com_DefaultExtension (char *path, int maxSize, const char *extension ) { + char oldPath[MAX_QPATH]; + char *src; + +// +// if path doesn't have a .EXT, append extension +// (extension should include the .) +// + src = path + strlen(path) - 1; + + while (*src != '/' && src != path) { + if ( *src == '.' ) { + return; // it has an extension + } + src--; + } + + Q_strncpyz( oldPath, path, sizeof( oldPath ) ); + Com_sprintf( path, maxSize, "%s%s", oldPath, extension ); +} + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +// can't just use function pointers, or dll linkage can +// mess up when qcommon is included in multiple places +static short (*_BigShort) (short l); +static short (*_LittleShort) (short l); +static int (*_BigLong) (int l); +static int (*_LittleLong) (int l); +static float (*_BigFloat) (float l); +static float (*_LittleFloat) (float l); + +short BigShort(short l){return _BigShort(l);} +short LittleShort(short l) {return _LittleShort(l);} +int BigLong (int l) {return _BigLong(l);} +int LittleLong (int l) {return _LittleLong(l);} +float BigFloat (float l) {return _BigFloat(l);} +float LittleFloat (float l) {return _LittleFloat(l);} + +short ShortSwap (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short ShortNoSwap (short l) +{ + return l; +} + +int LongSwap (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LongNoSwap (int l) +{ + return l; +} + +float FloatSwap (float f) +{ + union + { + float f; + byte b[4]; + } dat1, dat2; + + + dat1.f = f; + dat2.b[0] = dat1.b[3]; + dat2.b[1] = dat1.b[2]; + dat2.b[2] = dat1.b[1]; + dat2.b[3] = dat1.b[0]; + return dat2.f; +} + +float FloatNoSwap (float f) +{ + return f; +} + +/* +================ +Swap_Init +================ +*/ +void Swap_Init (void) +{ + byte swaptest[2] = {1,0}; + +// set the byte swapping variables in a portable manner + if ( *(short *)swaptest == 1) + { + _BigShort = ShortSwap; + _LittleShort = ShortNoSwap; + _BigLong = LongSwap; + _LittleLong = LongNoSwap; + _BigFloat = FloatSwap; + _LittleFloat = FloatNoSwap; + } + else + { + _BigShort = ShortNoSwap; + _LittleShort = ShortSwap; + _BigLong = LongNoSwap; + _LittleLong = LongSwap; + _BigFloat = FloatNoSwap; + _LittleFloat = FloatSwap; + } + +} + +/* +=============== +Com_ParseInfos +=============== +*/ +int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] ) { + const char *token; + int count; + char key[MAX_TOKEN_CHARS]; + + count = 0; + + while ( 1 ) { + token = Com_Parse( &buf ); + if ( !token[0] ) { + break; + } + if ( strcmp( token, "{" ) ) { + Com_Printf( "Missing { in info file\n" ); + break; + } + + if ( count == max ) { + Com_Printf( "Max infos exceeded\n" ); + break; + } + + infos[count][0] = 0; + while ( 1 ) { + token = Com_Parse( &buf ); + if ( !token[0] ) { + Com_Printf( "Unexpected end of info file\n" ); + break; + } + if ( !strcmp( token, "}" ) ) { + break; + } + Q_strncpyz( key, token, sizeof( key ) ); + + token = Com_ParseOnLine( &buf ); + if ( !token[0] ) { + token = ""; + } + Info_SetValueForKey( infos[count], key, token ); + } + count++; + } + + return count; +} + + + +/* +============================================================================ + + LIBRARY REPLACEMENT FUNCTIONS + +============================================================================ +*/ + +int Q_isprint( int c ) +{ + if ( c >= 0x20 && c <= 0x7E ) + return ( 1 ); + return ( 0 ); +} + +int Q_islower( int c ) +{ + if (c >= 'a' && c <= 'z') + return ( 1 ); + return ( 0 ); +} + +int Q_isupper( int c ) +{ + if (c >= 'A' && c <= 'Z') + return ( 1 ); + return ( 0 ); +} + +int Q_isalpha( int c ) +{ + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + return ( 1 ); + return ( 0 ); +} + +char* Q_strrchr( const char* string, int c ) +{ + char cc = c; + char *s; + char *sp=(char *)0; + + s = (char*)string; + + while (*s) + { + if (*s == cc) + sp = s; + s++; + } + if (cc == 0) + sp = s; + + return sp; +} + +/* +============= +Q_strncpyz + +Safe strncpy that ensures a trailing zero +============= +*/ +void Q_strncpyz( char *dest, const char *src, int destsize ) { + if ( !src ) { + Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" ); + } + if ( destsize < 1 ) { + Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" ); + } + + strncpy( dest, src, destsize-1 ); + dest[destsize-1] = 0; +} + +int Q_stricmpn (const char *s1, const char *s2, int n) { + int c1, c2; + + do { + c1 = *s1++; + c2 = *s2++; + + if (!n--) { + return 0; // strings are equal until end point + } + + if (c1 != c2) { + if (c1 >= 'a' && c1 <= 'z') { + c1 -= ('a' - 'A'); + } + if (c2 >= 'a' && c2 <= 'z') { + c2 -= ('a' - 'A'); + } + if (c1 != c2) { + return c1 < c2 ? -1 : 1; + } + } + } while (c1); + + return 0; // strings are equal +} + +int Q_strncmp (const char *s1, const char *s2, int n) { + int c1, c2; + + do { + c1 = *s1++; + c2 = *s2++; + + if (!n--) { + return 0; // strings are equal until end point + } + + if (c1 != c2) { + return c1 < c2 ? -1 : 1; + } + } while (c1); + + return 0; // strings are equal +} + +int Q_stricmp (const char *s1, const char *s2) { + return Q_stricmpn (s1, s2, 99999); +} + + +char *Q_strlwr( char *s1 ) { + char *s; + + s = s1; + while ( *s ) { + *s = tolower(*s); + s++; + } + return s1; +} + +char *Q_strupr( char *s1 ) { + char *s; + + s = s1; + while ( *s ) { + *s = toupper(*s); + s++; + } + return s1; +} + + +// never goes past bounds or leaves without a terminating 0 +void Q_strcat( char *dest, int size, const char *src ) { + int l1; + + l1 = strlen( dest ); + if ( l1 >= size ) { + Com_Error( ERR_FATAL, "Q_strcat: already overflowed" ); + } + Q_strncpyz( dest + l1, src, size - l1 ); +} + + +int Q_PrintStrlen( const char *string ) { + int len; + const char *p; + + if( !string ) { + return 0; + } + + len = 0; + p = string; + while( *p ) { + if( Q_IsColorString( p ) ) { + p += 2; + continue; + } + p++; + len++; + } + + return len; +} + + +char *Q_CleanStr( char *string ) { + char* d; + char* s; + int c; + + s = string; + d = string; + while ((c = *s) != 0 ) { + if ( Q_IsColorString( s ) ) { + s++; + } + else if ( c >= 0x20 && c <= 0x7E ) { + *d++ = c; + } + s++; + } + *d = '\0'; + + return string; +} + + +void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) { + int len; + va_list argptr; + char bigbuffer[32000]; // big, but small enough to fit in PPC stack + + va_start (argptr,fmt); + len = vsprintf (bigbuffer,fmt,argptr); + va_end (argptr); + if ( len >= sizeof( bigbuffer ) ) { + Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" ); + } + if (len >= size) { + Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size); + } + Q_strncpyz (dest, bigbuffer, size ); +} + + +/* +============ +va + +does a varargs printf into a temp buffer, so I don't need to have +varargs versions of all text functions. +FIXME: make this buffer size safe someday +============ +*/ +char * QDECL va( char *format, ... ) { + va_list argptr; + static char string[2][32000]; // in case va is called by nested functions + static int index = 0; + char *buf; + + buf = string[index & 1]; + index++; + + va_start (argptr, format); + vsprintf (buf, format,argptr); + va_end (argptr); + + return buf; +} + + +/* +===================================================================== + + INFO STRINGS + +===================================================================== +*/ + +/* +=============== +Info_ValueForKey + +Searches the string for the given +key and returns the associated value, or an empty string. +FIXME: overflow check? +=============== +*/ +char *Info_ValueForKey( const char *s, const char *key ) { + char pkey[MAX_INFO_KEY]; + static char value[2][MAX_INFO_VALUE]; // use two buffers so compares + // work without stomping on each other + static int valueindex = 0; + char *o; + + if ( !s || !key ) { + return ""; + } + + if ( strlen( s ) >= MAX_INFO_STRING ) { + Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" ); + } + + valueindex ^= 1; + if (*s == '\\') + s++; + while (1) + { + o = pkey; + while (*s != '\\') + { + if (!*s) + return ""; + *o++ = *s++; + } + *o = 0; + s++; + + o = value[valueindex]; + + while (*s != '\\' && *s) + { + *o++ = *s++; + } + *o = 0; + + if (!Q_stricmp (key, pkey) ) + return value[valueindex]; + + if (!*s) + break; + s++; + } + + return ""; +} + + +/* +=================== +Info_NextPair + +Used to itterate through all the key/value pairs in an info string +=================== +*/ +void Info_NextPair( const char *(*head), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ) { + char *o; + const char *s; + + s = *head; + + if ( *s == '\\' ) { + s++; + } + key[0] = 0; + value[0] = 0; + + o = key; + while ( *s != '\\' ) { + if ( !*s ) { + *o = 0; + *head = s; + return; + } + *o++ = *s++; + } + *o = 0; + s++; + + o = value; + while ( *s != '\\' && *s ) { + *o++ = *s++; + } + *o = 0; + + *head = s; +} + + +/* +=================== +Info_RemoveKey +=================== +*/ +void Info_RemoveKey( char *s, const char *key ) { + char *start; + char pkey[MAX_INFO_KEY]; + char value[MAX_INFO_VALUE]; + char *o; + + if ( strlen( s ) >= MAX_INFO_STRING ) { + Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" ); + } + + if (strchr (key, '\\')) { + return; + } + + while (1) + { + start = s; + if (*s == '\\') + s++; + o = pkey; + while (*s != '\\') + { + if (!*s) + return; + *o++ = *s++; + } + *o = 0; + s++; + + o = value; + while (*s != '\\' && *s) + { + if (!*s) + return; + *o++ = *s++; + } + *o = 0; + + if (!strcmp (key, pkey) ) + { + strcpy (start, s); // remove this part + return; + } + + if (!*s) + return; + } + +} + + +/* +================== +Info_Validate + +Some characters are illegal in info strings because they +can mess up the server's parsing +================== +*/ +qboolean Info_Validate( const char *s ) { + if ( strchr( s, '\"' ) ) { + return qfalse; + } + if ( strchr( s, ';' ) ) { + return qfalse; + } + return qtrue; +} + +/* +================== +Info_SetValueForKey + +Changes or adds a key/value pair +================== +*/ +void Info_SetValueForKey( char *s, const char *key, const char *value ) { + char newi[MAX_INFO_STRING]; + + if ( strlen( s ) >= MAX_INFO_STRING ) { + Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" ); + } + + if (strchr (key, '\\') || strchr (value, '\\')) + { + Com_Printf ("Can't use keys or values with a \\\n"); + return; + } + + if (strchr (key, ';') || strchr (value, ';')) + { + Com_Printf ("Can't use keys or values with a semicolon\n"); + return; + } + + if (strchr (key, '\"') || strchr (value, '\"')) + { + Com_Printf ("Can't use keys or values with a \"\n"); + return; + } + + Info_RemoveKey (s, key); + if (!value || !strlen(value)) + return; + + Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value); + + if (strlen(newi) + strlen(s) > MAX_INFO_STRING) + { + Com_Printf ("Info string length exceeded\n"); + return; + } + + strcat (s, newi); +} + +//==================================================================== + + +/* +=============== +ParseHex +=============== +*/ +int ParseHex( const char *text ) { + int value; + int c; + + value = 0; + while ( ( c = *text++ ) != 0 ) { + if ( c >= '0' && c <= '9' ) { + value = value * 16 + c - '0'; + continue; + } + if ( c >= 'a' && c <= 'f' ) { + value = value * 16 + 10 + c - 'a'; + continue; + } + if ( c >= 'A' && c <= 'F' ) { + value = value * 16 + 10 + c - 'A'; + continue; + } + } + + return value; +} diff --git a/CODE-mp/Splines/q_shared.h b/CODE-mp/Splines/q_shared.h new file mode 100644 index 0000000..5f381ab --- /dev/null +++ b/CODE-mp/Splines/q_shared.h @@ -0,0 +1,789 @@ +#ifndef __Q_SHARED_H +#define __Q_SHARED_H + +// q_shared.h -- included first by ALL program modules. +// these are the definitions that have no dependance on +// central system services, and can be used by any part +// of the program without any state issues. + +// A user mod should never modify this file + +// incursion of DOOM code into the Q3A codebase +//#define Q3_VERSION "DOOM 0.01" + +// alignment macros for SIMD +#define ALIGN_ON +#define ALIGN_OFF + +#ifdef _WIN32 + +#pragma warning(disable : 4018) // signed/unsigned mismatch +#pragma warning(disable : 4032) +#pragma warning(disable : 4051) +#pragma warning(disable : 4057) // slightly different base types +#pragma warning(disable : 4100) // unreferenced formal parameter +#pragma warning(disable : 4115) +#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4136) +#pragma warning(disable : 4201) +#pragma warning(disable : 4214) +#pragma warning(disable : 4244) +#pragma warning(disable : 4305) // truncation from const double to float +#pragma warning(disable : 4310) // cast truncates constant value +#pragma warning(disable : 4514) +#pragma warning(disable : 4711) // selected for automatic inline expansion +#pragma warning(disable : 4220) // varargs matches remaining parameters + +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef WIN32 // mac doesn't have malloc.h +#include // for _alloca() +#endif +#ifdef _WIN32 + +//#pragma intrinsic( memset, memcpy ) + +#endif + + +// this is the define for determining if we have an asm version of a C function +#if (defined _M_IX86 || defined __i386__) && !defined __sun__ && !defined __LCC__ +#define id386 1 +#else +#define id386 0 +#endif + +// for windows fastcall option + +#define QDECL + +//======================= WIN32 DEFINES ================================= + +#ifdef WIN32 + +#define MAC_STATIC + +#undef QDECL +#define QDECL __cdecl + +// buildstring will be incorporated into the version string +#ifdef NDEBUG +#ifdef _M_IX86 +#define CPUSTRING "win-x86" +#elif defined _M_ALPHA +#define CPUSTRING "win-AXP" +#endif +#else +#ifdef _M_IX86 +#define CPUSTRING "win-x86-debug" +#elif defined _M_ALPHA +#define CPUSTRING "win-AXP-debug" +#endif +#endif + + +#define PATH_SEP '\\' + +#endif + +//======================= MAC OS X SERVER DEFINES ===================== + +#if defined(__MACH__) && defined(__APPLE__) + +#define MAC_STATIC + +#ifdef __ppc__ +#define CPUSTRING "MacOSXS-ppc" +#elif defined __i386__ +#define CPUSTRING "MacOSXS-i386" +#else +#define CPUSTRING "MacOSXS-other" +#endif + +#define PATH_SEP '/' + +#define GAME_HARD_LINKED +#define CGAME_HARD_LINKED +#define UI_HARD_LINKED +#define _alloca alloca + +#undef ALIGN_ON +#undef ALIGN_OFF +#define ALIGN_ON #pragma align(16) +#define ALIGN_OFF #pragma align() + +#ifdef __cplusplus + extern "C" { +#endif + +void *osxAllocateMemory(long size); +void osxFreeMemory(void *pointer); + +#ifdef __cplusplus + } +#endif + +#endif + +//======================= MAC DEFINES ================================= + +#ifdef __MACOS__ + +#define MAC_STATIC static + +#define CPUSTRING "MacOS-PPC" + +#define PATH_SEP ':' + +void Sys_PumpEvents( void ); + +#endif + +#ifdef __MRC__ + +#define MAC_STATIC + +#define CPUSTRING "MacOS-PPC" + +#define PATH_SEP ':' + +void Sys_PumpEvents( void ); + +#undef QDECL +#define QDECL __cdecl + +#define _alloca alloca +#endif + +//======================= LINUX DEFINES ================================= + +// the mac compiler can't handle >32k of locals, so we +// just waste space and make big arrays static... +#ifdef __linux__ + +// bk001205 - from Makefile +#define stricmp strcasecmp + +#define MAC_STATIC // bk: FIXME + +#ifdef __i386__ +#define CPUSTRING "linux-i386" +#elif defined __axp__ +#define CPUSTRING "linux-alpha" +#else +#define CPUSTRING "linux-other" +#endif + +#define PATH_SEP '/' + +// bk001205 - try +#ifdef Q3_STATIC +#define GAME_HARD_LINKED +#define CGAME_HARD_LINKED +#define UI_HARD_LINKED +#define BOTLIB_HARD_LINKED +#endif + +#endif + +//============================================================= + + + +typedef enum {qfalse, qtrue} qboolean; + +typedef unsigned char byte; + +#define EQUAL_EPSILON 0.001 + +typedef int qhandle_t; +typedef int sfxHandle_t; +typedef int fileHandle_t; +typedef int clipHandle_t; + +typedef enum { + INVALID_JOINT = -1 +} jointHandle_t; + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define MAX_QINT 0x7fffffff +#define MIN_QINT (-MAX_QINT-1) + +#ifndef max +#define max( x, y ) ( ( ( x ) > ( y ) ) ? ( x ) : ( y ) ) +#define min( x, y ) ( ( ( x ) < ( y ) ) ? ( x ) : ( y ) ) +#endif + +#ifndef sign +#define sign( f ) ( ( f > 0 ) ? 1 : ( ( f < 0 ) ? -1 : 0 ) ) +#endif + +// angle indexes +#define PITCH 0 // up / down +#define YAW 1 // left / right +#define ROLL 2 // fall over + +// the game guarantees that no string from the network will ever +// exceed MAX_STRING_CHARS +#define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString +#define MAX_STRING_TOKENS 256 // max tokens resulting from Cmd_TokenizeString +#define MAX_TOKEN_CHARS 1024 // max length of an individual token + +#define MAX_INFO_STRING 1024 +#define MAX_INFO_KEY 1024 +#define MAX_INFO_VALUE 1024 + + +#define MAX_QPATH 64 // max length of a quake game pathname +#define MAX_OSPATH 128 // max length of a filesystem pathname + +#define MAX_NAME_LENGTH 32 // max length of a client name + +// paramters for command buffer stuffing +typedef enum { + EXEC_NOW, // don't return until completed, a VM should NEVER use this, + // because some commands might cause the VM to be unloaded... + EXEC_INSERT, // insert at current position, but don't run yet + EXEC_APPEND // add to end of the command buffer (normal case) +} cbufExec_t; + + +// +// these aren't needed by any of the VMs. put in another header? +// +#define MAX_MAP_AREA_BYTES 32 // bit vector of area visibility + +#undef ERR_FATAL // malloc.h on unix + +// parameters to the main Error routine +typedef enum { + ERR_NONE, + ERR_FATAL, // exit the entire game with a popup window + ERR_DROP, // print to console and disconnect from game + ERR_DISCONNECT, // don't kill server + ERR_NEED_CD // pop up the need-cd dialog +} errorParm_t; + + +// font rendering values used by ui and cgame + +#define PROP_GAP_WIDTH 3 +#define PROP_SPACE_WIDTH 8 +#define PROP_HEIGHT 27 +#define PROP_SMALL_SIZE_SCALE 0.75 + +#define BLINK_DIVISOR 200 +#define PULSE_DIVISOR 75 + +#define UI_LEFT 0x00000000 // default +#define UI_CENTER 0x00000001 +#define UI_RIGHT 0x00000002 +#define UI_FORMATMASK 0x00000007 +#define UI_SMALLFONT 0x00000010 +#define UI_BIGFONT 0x00000020 // default +#define UI_GIANTFONT 0x00000040 +#define UI_DROPSHADOW 0x00000800 +#define UI_BLINK 0x00001000 +#define UI_INVERSE 0x00002000 +#define UI_PULSE 0x00004000 + + +/* +============================================================== + +MATHLIB + +============================================================== +*/ +#ifdef __cplusplus // so we can include this in C code +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 +#define SIDE_CROSS 3 + +#define Q_PI 3.14159265358979323846 +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +#include "math_vector.h" +#include "math_angles.h" +#include "math_matrix.h" +#include "math_quaternion.h" + +class idVec3_t; // for defining vectors +typedef idVec3_t &vec3_p; // for passing vectors as function arguments +typedef const idVec3_t &vec3_c; // for passing vectors as const function arguments + +class angles_t; // for defining angle vectors +typedef angles_t &angles_p; // for passing angles as function arguments +typedef const angles_t &angles_c; // for passing angles as const function arguments + +class mat3_t; // for defining matrices +typedef mat3_t &mat3_p; // for passing matrices as function arguments +typedef const mat3_t &mat3_c; // for passing matrices as const function arguments + + + +#define NUMVERTEXNORMALS 162 +extern idVec3_t bytedirs[NUMVERTEXNORMALS]; + +// all drawing is done to a 640*480 virtual screen size +// and will be automatically scaled to the real resolution +#define SCREEN_WIDTH 640 +#define SCREEN_HEIGHT 480 + +#define TINYCHAR_WIDTH (SMALLCHAR_WIDTH) +#define TINYCHAR_HEIGHT (SMALLCHAR_HEIGHT/2) + +#define SMALLCHAR_WIDTH 8 +#define SMALLCHAR_HEIGHT 16 + +#define BIGCHAR_WIDTH 16 +#define BIGCHAR_HEIGHT 16 + +#define GIANTCHAR_WIDTH 32 +#define GIANTCHAR_HEIGHT 48 + +extern vec4_t colorBlack; +extern vec4_t colorRed; +extern vec4_t colorGreen; +extern vec4_t colorBlue; +extern vec4_t colorYellow; +extern vec4_t colorMagenta; +extern vec4_t colorCyan; +extern vec4_t colorWhite; +extern vec4_t colorLtGrey; +extern vec4_t colorMdGrey; +extern vec4_t colorDkGrey; + +#define Q_COLOR_ESCAPE '^' +#define Q_IsColorString(p) ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE ) + +#define COLOR_BLACK '0' +#define COLOR_RED '1' +#define COLOR_GREEN '2' +#define COLOR_YELLOW '3' +#define COLOR_BLUE '4' +#define COLOR_CYAN '5' +#define COLOR_MAGENTA '6' +#define COLOR_WHITE '7' +#define ColorIndex(c) ( ( (c) - '0' ) & 7 ) + +#define S_COLOR_BLACK "^0" +#define S_COLOR_RED "^1" +#define S_COLOR_GREEN "^2" +#define S_COLOR_YELLOW "^3" +#define S_COLOR_BLUE "^4" +#define S_COLOR_CYAN "^5" +#define S_COLOR_MAGENTA "^6" +#define S_COLOR_WHITE "^7" + +extern vec4_t g_color_table[8]; + +#define MAKERGB( v, r, g, b ) v[0]=r;v[1]=g;v[2]=b +#define MAKERGBA( v, r, g, b, a ) v[0]=r;v[1]=g;v[2]=b;v[3]=a + +#define DEG2RAD( a ) ( ( (a) * M_PI ) / 180.0F ) +#define RAD2DEG( a ) ( ( (a) * 180.0f ) / M_PI ) + +struct cplane_s; + +extern idVec3_t vec3_origin; +extern vec4_t vec4_origin; +extern mat3_t axisDefault; + +#define nanmask (255<<23) + +#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) + +float Q_fabs( float f ); +float Q_rsqrt( float f ); // reciprocal square root + +#define SQRTFAST( x ) ( 1.0f / Q_rsqrt( x ) ) + +signed char ClampChar( int i ); +signed short ClampShort( int i ); + +// this isn't a real cheap function to call! +int DirToByte( const idVec3_t &dir ); +void ByteToDir( int b, vec3_p dir ); + +#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]) +#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) +#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) +#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) +//#define VectorCopy(a,b) ((b).x=(a).x,(b).y=(a).y,(b).z=(a).z]) + +#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s)) +#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s)) +#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0]) + +#define DotProduct4(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]+(x)[3]*(y)[3]) +#define VectorSubtract4(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3]) +#define VectorAdd4(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3]) +#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) +#define VectorScale4(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s),(o)[3]=(v)[3]*(s)) +#define VectorMA4(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s),(o)[3]=(v)[3]+(b)[3]*(s)) + + +#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0) +#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) +#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z)) +#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) + +#define SnapVector(v) {v[0]=(int)v[0];v[1]=(int)v[1];v[2]=(int)v[2];} + +float NormalizeColor( vec3_c in, vec3_p out ); + +int VectorCompare( vec3_c v1, vec3_c v2 ); +float VectorLength( vec3_c v ); +float Distance( vec3_c p1, vec3_c p2 ); +float DistanceSquared( vec3_c p1, vec3_c p2 ); +float VectorNormalize (vec3_p v); // returns vector length +void VectorNormalizeFast(vec3_p v); // does NOT return vector length, uses rsqrt approximation +float VectorNormalize2( vec3_c v, vec3_p out ); +void VectorInverse (vec3_p v); +void VectorRotate( vec3_c in, mat3_c matrix, vec3_p out ); +void VectorPolar(vec3_p v, float radius, float theta, float phi); +void VectorSnap(vec3_p v); +void Vector53Copy( const idVec5_t &in, vec3_p out); +void Vector5Scale( const idVec5_t &v, float scale, idVec5_t &out); +void Vector5Add( const idVec5_t &va, const idVec5_t &vb, idVec5_t &out); +void VectorRotate3( vec3_c vIn, vec3_c vRotation, vec3_p out); +void VectorRotate3Origin(vec3_c vIn, vec3_c vRotation, vec3_c vOrigin, vec3_p out); + + +int Q_log2(int val); + +int Q_rand( int *seed ); +float Q_random( int *seed ); +float Q_crandom( int *seed ); + +#define random() ((rand () & 0x7fff) / ((float)0x7fff)) +#define crandom() (2.0 * (random() - 0.5)) + +float Q_rint( float in ); + +void vectoangles( vec3_c value1, angles_p angles); +void AnglesToAxis( angles_c angles, mat3_p axis ); + +void AxisCopy( mat3_c in, mat3_p out ); +qboolean AxisRotated( mat3_c in ); // assumes a non-degenerate axis + +int SignbitsForNormal( vec3_c normal ); +int BoxOnPlaneSide( const Bounds &b, struct cplane_s *p ); + +float AngleMod(float a); +float LerpAngle (float from, float to, float frac); +float AngleSubtract( float a1, float a2 ); +void AnglesSubtract( angles_c v1, angles_c v2, angles_p v3 ); + +float AngleNormalize360 ( float angle ); +float AngleNormalize180 ( float angle ); +float AngleDelta ( float angle1, float angle2 ); + +qboolean PlaneFromPoints( vec4_t &plane, vec3_c a, vec3_c b, vec3_c c ); +void ProjectPointOnPlane( vec3_p dst, vec3_c p, vec3_c normal ); +void RotatePointAroundVector( vec3_p dst, vec3_c dir, vec3_c point, float degrees ); +void RotateAroundDirection( mat3_p axis, float yaw ); +void MakeNormalVectors( vec3_c forward, vec3_p right, vec3_p up ); +// perpendicular vector could be replaced by this + +int PlaneTypeForNormal( vec3_c normal ); + +void MatrixMultiply( mat3_c in1, mat3_c in2, mat3_p out ); +void MatrixInverseMultiply( mat3_c in1, mat3_c in2, mat3_p out ); // in2 is transposed during multiply +void MatrixTransformVector( vec3_c in, mat3_c matrix, vec3_p out ); +void MatrixProjectVector( vec3_c in, mat3_c matrix, vec3_p out ); // Places the vector into a new coordinate system. +void AngleVectors( angles_c angles, vec3_p forward, vec3_p right, vec3_p up); +void PerpendicularVector( vec3_p dst, vec3_c src ); + +float TriangleArea( vec3_c a, vec3_c b, vec3_c c ); +#endif // __cplusplus + +//============================================= + +float Com_Clamp( float min, float max, float value ); + +#define FILE_HASH_SIZE 1024 +int Com_HashString( const char *fname ); + +char *Com_SkipPath( char *pathname ); + +// it is ok for out == in +void Com_StripExtension( const char *in, char *out ); + +// "extension" should include the dot: ".map" +void Com_DefaultExtension( char *path, int maxSize, const char *extension ); + +int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] ); + +/* +===================================================================================== + +SCRIPT PARSING + +===================================================================================== +*/ + +// this just controls the comment printing, it doesn't actually load a file +void Com_BeginParseSession( const char *filename ); +void Com_EndParseSession( void ); + +int Com_GetCurrentParseLine( void ); + +// Will never return NULL, just empty strings. +// An empty string will only be returned at end of file. +// ParseOnLine will return empty if there isn't another token on this line + +// this funny typedef just means a moving pointer into a const char * buffer +const char *Com_Parse( const char *(*data_p) ); +const char *Com_ParseOnLine( const char *(*data_p) ); +const char *Com_ParseRestOfLine( const char *(*data_p) ); + +void Com_UngetToken( void ); + +#ifdef __cplusplus +void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning = qfalse ); +#else +void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning ); +#endif + +void Com_ScriptError( const char *msg, ... ); +void Com_ScriptWarning( const char *msg, ... ); + +void Com_SkipBracedSection( const char *(*program) ); +void Com_SkipRestOfLine( const char *(*data) ); + +float Com_ParseFloat( const char *(*buf_p) ); +int Com_ParseInt( const char *(*buf_p) ); + +void Com_Parse1DMatrix( const char *(*buf_p), int x, float *m ); +void Com_Parse2DMatrix( const char *(*buf_p), int y, int x, float *m ); +void Com_Parse3DMatrix( const char *(*buf_p), int z, int y, int x, float *m ); + +//===================================================================================== +#ifdef __cplusplus + extern "C" { +#endif + +void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...); + + +// mode parm for FS_FOpenFile +typedef enum { + FS_READ, + FS_WRITE, + FS_APPEND, + FS_APPEND_SYNC +} fsMode_t; + +typedef enum { + FS_SEEK_CUR, + FS_SEEK_END, + FS_SEEK_SET +} fsOrigin_t; + +//============================================= + +int Q_isprint( int c ); +int Q_islower( int c ); +int Q_isupper( int c ); +int Q_isalpha( int c ); + +// portable case insensitive compare +int Q_stricmp (const char *s1, const char *s2); +int Q_strncmp (const char *s1, const char *s2, int n); +int Q_stricmpn (const char *s1, const char *s2, int n); +char *Q_strlwr( char *s1 ); +char *Q_strupr( char *s1 ); +char *Q_strrchr( const char* string, int c ); + +// buffer size safe library replacements +void Q_strncpyz( char *dest, const char *src, int destsize ); +void Q_strcat( char *dest, int size, const char *src ); + +// strlen that discounts Quake color sequences +int Q_PrintStrlen( const char *string ); +// removes color sequences from string +char *Q_CleanStr( char *string ); + +int Com_Filter( const char *filter, const char *name, int casesensitive ); +const char *Com_StringContains( const char *str1, const char *str2, int casesensitive ); + + +//============================================= + +short BigShort(short l); +short LittleShort(short l); +int BigLong (int l); +int LittleLong (int l); +float BigFloat (float l); +float LittleFloat (float l); + +void Swap_Init (void); +char * QDECL va(char *format, ...); + +#ifdef __cplusplus + } +#endif + + +//============================================= +#ifdef __cplusplus +// +// mapfile parsing +// +typedef struct ePair_s { + char *key; + char *value; +} ePair_t; + +typedef struct mapSide_s { + char material[MAX_QPATH]; + vec4_t plane; + vec4_t textureVectors[2]; +} mapSide_t; + +typedef struct { + int numSides; + mapSide_t **sides; +} mapBrush_t; + +typedef struct { + idVec3_t xyz; + float st[2]; +} patchVertex_t; + +typedef struct { + char material[MAX_QPATH]; + int width, height; + patchVertex_t *patchVerts; +} mapPatch_t; + +typedef struct { + char modelName[MAX_QPATH]; + float matrix[16]; +} mapModel_t; + +typedef struct mapPrimitive_s { + int numEpairs; + ePair_t **ePairs; + + // only one of these will be non-NULL + mapBrush_t *brush; + mapPatch_t *patch; + mapModel_t *model; +} mapPrimitive_t; + +typedef struct mapEntity_s { + int numPrimitives; + mapPrimitive_t **primitives; + + int numEpairs; + ePair_t **ePairs; +} mapEntity_t; + +typedef struct { + int numEntities; + mapEntity_t **entities; +} mapFile_t; + + +// the order of entities, brushes, and sides will be maintained, the +// lists won't be swapped on each load or save +mapFile_t *ParseMapFile( const char *text ); +void FreeMapFile( mapFile_t *mapFile ); +void WriteMapFile( const mapFile_t *mapFile, FILE *f ); + +// key names are case-insensitive +const char *ValueForMapEntityKey( const mapEntity_t *ent, const char *key ); +float FloatForMapEntityKey( const mapEntity_t *ent, const char *key ); +qboolean GetVectorForMapEntityKey( const mapEntity_t *ent, const char *key, idVec3_t &vec ); + +typedef struct { + idVec3_t xyz; + idVec2_t st; + idVec3_t normal; + idVec3_t tangents[2]; + byte smoothing[4]; // colors for silhouette smoothing +} drawVert_t; + +typedef struct { + int width, height; + drawVert_t *verts; +} drawVertMesh_t; + +// Tesselate a map patch into smoothed, drawable vertexes +// MaxError of around 4 is reasonable +drawVertMesh_t *SubdivideMapPatch( const mapPatch_t *patch, float maxError ); +#endif // __cplusplus + +//========================================= + +#ifdef __cplusplus + extern "C" { +#endif + +void QDECL Com_Error( int level, const char *error, ... ); +void QDECL Com_Printf( const char *msg, ... ); +void QDECL Com_DPrintf( const char *msg, ... ); + +#ifdef __cplusplus + } +#endif + + +typedef struct { + qboolean frameMemory; + int currentElements; + int maxElements; // will reallocate and move when exceeded + void **elements; +} growList_t; + +// you don't need to init the growlist if you don't mind it growing and moving +// the list as it expands +void Com_InitGrowList( growList_t *list, int maxElements ); +int Com_AddToGrowList( growList_t *list, void *data ); +void *Com_GrowListElement( const growList_t *list, int index ); +int Com_IndexForGrowListElement( const growList_t *list, const void *element ); + + +// +// key / value info strings +// +char *Info_ValueForKey( const char *s, const char *key ); +void Info_RemoveKey( char *s, const char *key ); +void Info_SetValueForKey( char *s, const char *key, const char *value ); +qboolean Info_Validate( const char *s ); +void Info_NextPair( const char *(*s), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ); + +// get cvar defs, collision defs, etc +//#include "../shared/interface.h" + +// get key code numbers for events +//#include "../shared/keycodes.h" + +#ifdef __cplusplus +// get the polygon winding functions +//#include "../shared/windings.h" + +// get the flags class +//#include "../shared/idflags.h" +#endif // __cplusplus + +#endif // __Q_SHARED_H + diff --git a/CODE-mp/Splines/splines.cpp b/CODE-mp/Splines/splines.cpp new file mode 100644 index 0000000..bb6c4af --- /dev/null +++ b/CODE-mp/Splines/splines.cpp @@ -0,0 +1,1226 @@ + +//#include "stdafx.h" +//#include "qe3.h" + +#include "q_shared.h" +#include "splines.h" + +extern "C" { +int FS_Write( const void *buffer, int len, fileHandle_t h ); +int FS_ReadFile( const char *qpath, void **buffer ); +void FS_FreeFile( void *buffer ); +fileHandle_t FS_FOpenFileWrite( const char *filename ); +void FS_FCloseFile( fileHandle_t f ); +} + +float Q_fabs( float f ) { + int tmp = * ( int * ) &f; + tmp &= 0x7FFFFFFF; + return * ( float * ) &tmp; +} + + +//#include "../shared/windings.h" +//#include "../qcommon/qcommon.h" +//#include "../sys/sys_public.h" +//#include "../game/game_entity.h" + +idCameraDef splineList; +idCameraDef *g_splineList = &splineList; + +idVec3_t idSplineList::zero(0,0,0); + +void glLabeledPoint(idVec3_t &color, idVec3_t &point, float size, const char *label) { + qglColor3fv(color); + qglPointSize(size); + qglBegin(GL_POINTS); + qglVertex3fv(point); + qglEnd(); + idVec3_t v = point; + v.x += 1; + v.y += 1; + v.z += 1; + qglRasterPos3fv (v); + qglCallLists (strlen(label), GL_UNSIGNED_BYTE, label); +} + + +void glBox(idVec3_t &color, idVec3_t &point, float size) { + idVec3_t mins(point); + idVec3_t maxs(point); + mins[0] -= size; + mins[1] += size; + mins[2] -= size; + maxs[0] += size; + maxs[1] -= size; + maxs[2] += size; + qglColor3fv(color); + qglBegin(GL_LINE_LOOP); + qglVertex3f(mins[0],mins[1],mins[2]); + qglVertex3f(maxs[0],mins[1],mins[2]); + qglVertex3f(maxs[0],maxs[1],mins[2]); + qglVertex3f(mins[0],maxs[1],mins[2]); + qglEnd(); + qglBegin(GL_LINE_LOOP); + qglVertex3f(mins[0],mins[1],maxs[2]); + qglVertex3f(maxs[0],mins[1],maxs[2]); + qglVertex3f(maxs[0],maxs[1],maxs[2]); + qglVertex3f(mins[0],maxs[1],maxs[2]); + qglEnd(); + + qglBegin(GL_LINES); + qglVertex3f(mins[0],mins[1],mins[2]); + qglVertex3f(mins[0],mins[1],maxs[2]); + qglVertex3f(mins[0],maxs[1],maxs[2]); + qglVertex3f(mins[0],maxs[1],mins[2]); + qglVertex3f(maxs[0],mins[1],mins[2]); + qglVertex3f(maxs[0],mins[1],maxs[2]); + qglVertex3f(maxs[0],maxs[1],maxs[2]); + qglVertex3f(maxs[0],maxs[1],mins[2]); + qglEnd(); + +} + +void splineTest() { + //g_splineList->load("p:/doom/base/maps/test_base1.camera"); +} + +void splineDraw() { + //g_splineList->addToRenderer(); +} + + +//extern void D_DebugLine( const idVec3_t &color, const idVec3_t &start, const idVec3_t &end ); + +void debugLine(idVec3_t &color, float x, float y, float z, float x2, float y2, float z2) { + //idVec3_t from(x, y, z); + //idVec3_t to(x2, y2, z2); + //D_DebugLine(color, from, to); +} + +void idSplineList::addToRenderer() { + + if (controlPoints.Num() == 0) { + return; + } + + idVec3_t mins, maxs; + idVec3_t yellow(1.0, 1.0, 0); + idVec3_t white(1.0, 1.0, 1.0); + int i; + + for(i = 0; i < controlPoints.Num(); i++) { + VectorCopy(*controlPoints[i], mins); + VectorCopy(mins, maxs); + mins[0] -= 8; + mins[1] += 8; + mins[2] -= 8; + maxs[0] += 8; + maxs[1] -= 8; + maxs[2] += 8; + debugLine( yellow, mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2]); + debugLine( yellow, maxs[0], mins[1], mins[2], maxs[0], maxs[1], mins[2]); + debugLine( yellow, maxs[0], maxs[1], mins[2], mins[0], maxs[1], mins[2]); + debugLine( yellow, mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2]); + + debugLine( yellow, mins[0], mins[1], maxs[2], maxs[0], mins[1], maxs[2]); + debugLine( yellow, maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2]); + debugLine( yellow, maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2]); + debugLine( yellow, mins[0], maxs[1], maxs[2], mins[0], mins[1], maxs[2]); + + } + + int step = 0; + idVec3_t step1; + for(i = 3; i < controlPoints.Num(); i++) { + for (float tension = 0.0f; tension < 1.001f; tension += 0.1f) { + float x = 0; + float y = 0; + float z = 0; + for (int j = 0; j < 4; j++) { + x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension); + y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension); + z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension); + } + if (step == 0) { + step1[0] = x; + step1[1] = y; + step1[2] = z; + step = 1; + } else { + debugLine( white, step1[0], step1[1], step1[2], x, y, z); + step = 0; + } + + } + } +} + +void idSplineList::buildSpline() { + //int start = Sys_Milliseconds(); + clearSpline(); + for(int i = 3; i < controlPoints.Num(); i++) { + for (float tension = 0.0f; tension < 1.001f; tension += granularity) { + float x = 0; + float y = 0; + float z = 0; + for (int j = 0; j < 4; j++) { + x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension); + y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension); + z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension); + } + splinePoints.Append(new idVec3_t(x, y, z)); + } + } + dirty = false; + //Com_Printf("Spline build took %f seconds\n", (float)(Sys_Milliseconds() - start) / 1000); +} + + +void idSplineList::draw(bool editMode) { + int i; + vec4_t yellow(1, 1, 0, 1); + + if (controlPoints.Num() == 0) { + return; + } + + if (dirty) { + buildSpline(); + } + + + qglColor3fv(controlColor); + qglPointSize(5); + + qglBegin(GL_POINTS); + for (i = 0; i < controlPoints.Num(); i++) { + qglVertex3fv(*controlPoints[i]); + } + qglEnd(); + + if (editMode) { + for(i = 0; i < controlPoints.Num(); i++) { + glBox(activeColor, *controlPoints[i], 4); + } + } + + //Draw the curve + qglColor3fv(pathColor); + qglBegin(GL_LINE_STRIP); + int count = splinePoints.Num(); + for (i = 0; i < count; i++) { + qglVertex3fv(*splinePoints[i]); + } + qglEnd(); + + if (editMode) { + qglColor3fv(segmentColor); + qglPointSize(3); + qglBegin(GL_POINTS); + for (i = 0; i < count; i++) { + qglVertex3fv(*splinePoints[i]); + } + qglEnd(); + } + if (count > 0) { + //assert(activeSegment >=0 && activeSegment < count); + if (activeSegment >=0 && activeSegment < count) { + glBox(activeColor, *splinePoints[activeSegment], 6); + glBox(yellow, *splinePoints[activeSegment], 8); + } + } + +} + +float idSplineList::totalDistance() { + + if (controlPoints.Num() == 0) { + return 0.0; + } + + if (dirty) { + buildSpline(); + } + + float dist = 0.0; + idVec3_t temp; + int count = splinePoints.Num(); + for(int i = 1; i < count; i++) { + temp = *splinePoints[i-1]; + temp -= *splinePoints[i]; + dist += temp.Length(); + } + return dist; +} + +void idSplineList::initPosition(long bt, long totalTime) { + + if (dirty) { + buildSpline(); + } + + if (splinePoints.Num() == 0) { + return; + } + + baseTime = bt; + time = totalTime; + + // calc distance to travel ( this will soon be broken into time segments ) + splineTime.Clear(); + splineTime.Append(bt); + double dist = totalDistance(); + double distSoFar = 0.0; + idVec3_t temp; + int count = splinePoints.Num(); + //for(int i = 2; i < count - 1; i++) { + for(int i = 1; i < count; i++) { + temp = *splinePoints[i-1]; + temp -= *splinePoints[i]; + distSoFar += temp.Length(); + double percent = distSoFar / dist; + percent *= totalTime; + splineTime.Append(percent + bt); + } + assert(splineTime.Num() == splinePoints.Num()); + activeSegment = 0; +} + + + +float idSplineList::calcSpline(int step, float tension) { + switch(step) { + case 0: return (pow(1 - tension, 3)) / 6; + case 1: return (3 * pow(tension, 3) - 6 * pow(tension, 2) + 4) / 6; + case 2: return (-3 * pow(tension, 3) + 3 * pow(tension, 2) + 3 * tension + 1) / 6; + case 3: return pow(tension, 3) / 6; + } + return 0.0; +} + + + +void idSplineList::updateSelection(const idVec3_t &move) { + if (selected) { + dirty = true; + VectorAdd(*selected, move, *selected); + } +} + + +void idSplineList::setSelectedPoint(idVec3_t *p) { + if (p) { + p->Snap(); + for(int i = 0; i < controlPoints.Num(); i++) { + if (*p == *controlPoints[i]) { + selected = controlPoints[i]; + } + } + } else { + selected = NULL; + } +} + +const idVec3_t *idSplineList::getPosition(long t) { + static idVec3_t interpolatedPos; + //static long lastTime = -1; + + int count = splineTime.Num(); + if (count == 0) { + return &zero; + } + + Com_Printf("Time: %d\n", t); + assert(splineTime.Num() == splinePoints.Num()); + + while (activeSegment < count) { + if (splineTime[activeSegment] >= t) { + if (activeSegment > 0 && activeSegment < count - 1) { + double timeHi = splineTime[activeSegment + 1]; + double timeLo = splineTime[activeSegment - 1]; + double percent = (timeHi - t) / (timeHi - timeLo); + // pick two bounding points + idVec3_t v1 = *splinePoints[activeSegment-1]; + idVec3_t v2 = *splinePoints[activeSegment+1]; + v2 *= (1.0 - percent); + v1 *= percent; + v2 += v1; + interpolatedPos = v2; + return &interpolatedPos; + } + return splinePoints[activeSegment]; + } else { + activeSegment++; + } + } + return splinePoints[count-1]; +} + +void idSplineList::parse(const char *(*text) ) { + const char *token; + //Com_MatchToken( text, "{" ); + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !Q_stricmp (token, "}") ) { + break; + } + + do { + // if token is not a brace, it is a key for a key/value pair + if ( !token[0] || !Q_stricmp (token, "(") || !Q_stricmp(token, "}")) { + break; + } + + Com_UngetToken(); + idStr key = Com_ParseOnLine(text); + const char *token = Com_Parse(text); + if (Q_stricmp(key.c_str(), "granularity") == 0) { + granularity = atof(token); + } else if (Q_stricmp(key.c_str(), "name") == 0) { + name = token; + } + token = Com_Parse(text); + + } while (1); + + if ( !Q_stricmp (token, "}") ) { + break; + } + + Com_UngetToken(); + // read the control point + idVec3_t point; + Com_Parse1DMatrix( text, 3, point ); + addPoint(point.x, point.y, point.z); + } while (1); + + //Com_UngetToken(); + //Com_MatchToken( text, "}" ); + dirty = true; +} + +void idSplineList::write(fileHandle_t file, const char *p) { + idStr s = va("\t\t%s {\n", p); + FS_Write(s.c_str(), s.length(), file); + //s = va("\t\tname %s\n", name.c_str()); + //FS_Write(s.c_str(), s.length(), file); + s = va("\t\t\tgranularity %f\n", granularity); + FS_Write(s.c_str(), s.length(), file); + int count = controlPoints.Num(); + for (int i = 0; i < count; i++) { + s = va("\t\t\t( %f %f %f )\n", controlPoints[i]->x, controlPoints[i]->y, controlPoints[i]->z); + FS_Write(s.c_str(), s.length(), file); + } + s = "\t\t}\n"; + FS_Write(s.c_str(), s.length(), file); +} + + +void idCameraDef::getActiveSegmentInfo(int segment, idVec3_t &origin, idVec3_t &direction, float *fov) { +#if 0 + if (!cameraSpline.validTime()) { + buildCamera(); + } + double d = (double)segment / numSegments(); + getCameraInfo(d * totalTime * 1000, origin, direction, fov); +#endif +/* + if (!cameraSpline.validTime()) { + buildCamera(); + } + origin = *cameraSpline.getSegmentPoint(segment); + + + idVec3_t temp; + + int numTargets = getTargetSpline()->controlPoints.Num(); + int count = cameraSpline.splineTime.Num(); + if (numTargets == 0) { + // follow the path + if (cameraSpline.getActiveSegment() < count - 1) { + temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1]; + } + } else if (numTargets == 1) { + temp = *getTargetSpline()->controlPoints[0]; + } else { + temp = *getTargetSpline()->getSegmentPoint(segment); + } + + temp -= origin; + temp.Normalize(); + direction = temp; +*/ +} + +bool idCameraDef::getCameraInfo(long time, idVec3_t &origin, idVec3_t &direction, float *fv) { + + + if ((time - startTime) / 1000 > totalTime) { + return false; + } + + + for (int i = 0; i < events.Num(); i++) { + if (time >= startTime + events[i]->getTime() && !events[i]->getTriggered()) { + events[i]->setTriggered(true); + if (events[i]->getType() == idCameraEvent::EVENT_TARGET) { + setActiveTargetByName(events[i]->getParam()); + getActiveTarget()->start(startTime + events[i]->getTime()); + //Com_Printf("Triggered event switch to target: %s\n",events[i]->getParam()); + } else if (events[i]->getType() == idCameraEvent::EVENT_TRIGGER) { + //idEntity *ent = NULL; + //ent = level.FindTarget( ent, events[i]->getParam()); + //if (ent) { + // ent->signal( SIG_TRIGGER ); + // ent->ProcessEvent( &EV_Activate, world ); + //} + } else if (events[i]->getType() == idCameraEvent::EVENT_FOV) { + //*fv = fov = atof(events[i]->getParam()); + } else if (events[i]->getType() == idCameraEvent::EVENT_STOP) { + return false; + } + } + } + + origin = *cameraPosition->getPosition(time); + + *fv = fov.getFOV(time); + + idVec3_t temp = origin; + + int numTargets = targetPositions.Num(); + if (numTargets == 0) { +/* + // follow the path + if (cameraSpline.getActiveSegment() < count - 1) { + temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1]; + if (temp == origin) { + int index = cameraSpline.getActiveSegment() + 2; + while (temp == origin && index < count - 1) { + temp = *cameraSpline.splinePoints[index++]; + } + } + } +*/ + } else { + temp = *getActiveTarget()->getPosition(time); + } + + temp -= origin; + temp.Normalize(); + direction = temp; + + return true; +} + +bool idCameraDef::waitEvent(int index) { + //for (int i = 0; i < events.Num(); i++) { + // if (events[i]->getSegment() == index && events[i]->getType() == idCameraEvent::EVENT_WAIT) { + // return true; + // } + //} + return false; +} + + +#define NUM_CCELERATION_SEGS 10 +#define CELL_AMT 5 + +void idCameraDef::buildCamera() { + int i; + //int lastSwitch = 0; + idList waits; + idList targets; + + totalTime = baseTime; + cameraPosition->setTime(totalTime * 1000); + // we have a base time layout for the path and the target path + // now we need to layer on any wait or speed changes + for (i = 0; i < events.Num(); i++) { + //idCameraEvent *ev = events[i]; + events[i]->setTriggered(false); + switch (events[i]->getType()) { + case idCameraEvent::EVENT_TARGET : { + targets.Append(i); + break; + } + case idCameraEvent::EVENT_WAIT : { + waits.Append(atof(events[i]->getParam())); + cameraPosition->addVelocity(events[i]->getTime(), atof(events[i]->getParam()) * 1000, 0); + break; + } + case idCameraEvent::EVENT_TARGETWAIT : { + //targetWaits.Append(i); + break; + } + case idCameraEvent::EVENT_SPEED : { +/* + // take the average delay between up to the next five segments + float adjust = atof(events[i]->getParam()); + int index = events[i]->getSegment(); + total = 0; + count = 0; + + // get total amount of time over the remainder of the segment + for (j = index; j < cameraSpline.numSegments() - 1; j++) { + total += cameraSpline.getSegmentTime(j + 1) - cameraSpline.getSegmentTime(j); + count++; + } + + // multiply that by the adjustment + double newTotal = total * adjust; + // what is the difference.. + newTotal -= total; + totalTime += newTotal / 1000; + + // per segment difference + newTotal /= count; + int additive = newTotal; + + // now propogate that difference out to each segment + for (j = index; j < cameraSpline.numSegments(); j++) { + cameraSpline.addSegmentTime(j, additive); + additive += newTotal; + } + break; +*/ + } + default: break; // FIXME: what about other idCameraEvent? + } + } + + + for (i = 0; i < waits.Num(); i++) { + totalTime += waits[i]; + } + + // on a new target switch, we need to take time to this point ( since last target switch ) + // and allocate it across the active target, then reset time to this point + long timeSoFar = 0; + long total = (int)(totalTime * 1000); + for (i = 0; i < targets.Num(); i++) { + long t; + if (i < targets.Num() - 1) { + t = events[targets[i+1]]->getTime(); + } else { + t = total - timeSoFar; + } + // t is how much time to use for this target + setActiveTargetByName(events[targets[i]]->getParam()); + getActiveTarget()->setTime(t); + timeSoFar += t; + } + + +} + +void idCameraDef::startCamera(long t) { + buildCamera(); + cameraPosition->start(t); + //for (int i = 0; i < targetPositions.Num(); i++) { + // targetPositions[i]-> + //} + startTime = t; + cameraRunning = true; +} + + +void idCameraDef::parse(const char *(*text) ) { + + const char *token; + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !Q_stricmp (token, "}") ) { + break; + } + + if (Q_stricmp(token, "time") == 0) { + baseTime = Com_ParseFloat(text); + } + + if (Q_stricmp(token, "camera_fixed") == 0) { + cameraPosition = new idFixedPosition(); + cameraPosition->parse(text); + } + + if (Q_stricmp(token, "camera_interpolated") == 0) { + cameraPosition = new idInterpolatedPosition(); + cameraPosition->parse(text); + } + + if (Q_stricmp(token, "camera_spline") == 0) { + cameraPosition = new idSplinePosition(); + cameraPosition->parse(text); + } + + if (Q_stricmp(token, "target_fixed") == 0) { + idFixedPosition *pos = new idFixedPosition(); + pos->parse(text); + targetPositions.Append(pos); + } + + if (Q_stricmp(token, "target_interpolated") == 0) { + idInterpolatedPosition *pos = new idInterpolatedPosition(); + pos->parse(text); + targetPositions.Append(pos); + } + + if (Q_stricmp(token, "target_spline") == 0) { + idSplinePosition *pos = new idSplinePosition(); + pos->parse(text); + targetPositions.Append(pos); + } + + if (Q_stricmp(token, "fov") == 0) { + fov.parse(text); + } + + if (Q_stricmp(token, "event") == 0) { + idCameraEvent *event = new idCameraEvent(); + event->parse(text); + addEvent(event); + } + + + } while (1); + + Com_UngetToken(); + Com_MatchToken( text, "}" ); + +} + +qboolean idCameraDef::load(const char *filename) { + char *buf; + const char *buf_p; + //int length = + FS_ReadFile( filename, (void **)&buf ); + if ( !buf ) { + return qfalse; + } + + clear(); + Com_BeginParseSession( filename ); + buf_p = buf; + parse(&buf_p); + Com_EndParseSession(); + FS_FreeFile( buf ); + + return qtrue; +} + +void idCameraDef::save(const char *filename) { + fileHandle_t file = FS_FOpenFileWrite(filename); + if (file) { + int i; + idStr s = "cameraPathDef { \n"; + FS_Write(s.c_str(), s.length(), file); + s = va("\ttime %f\n", baseTime); + FS_Write(s.c_str(), s.length(), file); + + cameraPosition->write(file, va("camera_%s",cameraPosition->typeStr())); + + for (i = 0; i < numTargets(); i++) { + targetPositions[i]->write(file, va("target_%s", targetPositions[i]->typeStr())); + } + + for (i = 0; i < events.Num(); i++) { + events[i]->write(file, "event"); + } + + fov.write(file, "fov"); + + s = "}\n"; + FS_Write(s.c_str(), s.length(), file); + } + FS_FCloseFile(file); +} + +int idCameraDef::sortEvents(const void *p1, const void *p2) { + idCameraEvent *ev1 = (idCameraEvent*)(p1); + idCameraEvent *ev2 = (idCameraEvent*)(p2); + + if (ev1->getTime() > ev2->getTime()) { + return -1; + } + if (ev1->getTime() < ev2->getTime()) { + return 1; + } + return 0; +} + +void idCameraDef::addEvent(idCameraEvent *event) { + events.Append(event); + //events.Sort(&sortEvents); + +} +void idCameraDef::addEvent(idCameraEvent::eventType t, const char *param, long time) { + addEvent(new idCameraEvent(t, param, time)); + buildCamera(); +} + + +const char *idCameraEvent::eventStr[] = { + "NA", + "WAIT", + "TARGETWAIT", + "SPEED", + "TARGET", + "SNAPTARGET", + "FOV", + "SCRIPT", + "TRIGGER", + "STOP" +}; + +void idCameraEvent::parse(const char *(*text) ) { + const char *token; + Com_MatchToken( text, "{" ); + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !strcmp (token, "}") ) { + break; + } + + // here we may have to jump over brush epairs ( only used in editor ) + do { + // if token is not a brace, it is a key for a key/value pair + if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { + break; + } + + Com_UngetToken(); + idStr key = Com_ParseOnLine(text); + const char *token = Com_Parse(text); + if (Q_stricmp(key.c_str(), "type") == 0) { + type = static_cast(atoi(token)); + } else if (Q_stricmp(key.c_str(), "param") == 0) { + paramStr = token; + } else if (Q_stricmp(key.c_str(), "time") == 0) { + time = atoi(token); + } + token = Com_Parse(text); + + } while (1); + + if ( !strcmp (token, "}") ) { + break; + } + + } while (1); + + Com_UngetToken(); + Com_MatchToken( text, "}" ); +} + +void idCameraEvent::write(fileHandle_t file, const char *name) { + idStr s = va("\t%s {\n", name); + FS_Write(s.c_str(), s.length(), file); + s = va("\t\ttype %d\n", static_cast(type)); + FS_Write(s.c_str(), s.length(), file); + s = va("\t\tparam %s\n", paramStr.c_str()); + FS_Write(s.c_str(), s.length(), file); + s = va("\t\ttime %d\n", time); + FS_Write(s.c_str(), s.length(), file); + s = "\t}\n"; + FS_Write(s.c_str(), s.length(), file); +} + + +const char *idCameraPosition::positionStr[] = { + "Fixed", + "Interpolated", + "Spline", +}; + + + +const idVec3_t *idInterpolatedPosition::getPosition(long t) { + static idVec3_t interpolatedPos; + + float velocity = getVelocity(t); + float timePassed = t - lastTime; + lastTime = t; + + // convert to seconds + timePassed /= 1000; + + float distToTravel = timePassed *= velocity; + + idVec3_t temp = startPos; + temp -= endPos; + float distance = temp.Length(); + + distSoFar += distToTravel; + float percent = (float)(distSoFar) / distance; + + if (percent > 1.0) { + percent = 1.0; + } else if (percent < 0.0) { + percent = 0.0; + } + + // the following line does a straigt calc on percentage of time + // float percent = (float)(startTime + time - t) / time; + + idVec3_t v1 = startPos; + idVec3_t v2 = endPos; + v1 *= (1.0 - percent); + v2 *= percent; + v1 += v2; + interpolatedPos = v1; + return &interpolatedPos; +} + + +void idCameraFOV::parse(const char *(*text) ) { + const char *token; + Com_MatchToken( text, "{" ); + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !strcmp (token, "}") ) { + break; + } + + // here we may have to jump over brush epairs ( only used in editor ) + do { + // if token is not a brace, it is a key for a key/value pair + if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { + break; + } + + Com_UngetToken(); + idStr key = Com_ParseOnLine(text); + const char *token = Com_Parse(text); + if (Q_stricmp(key.c_str(), "fov") == 0) { + fov = atof(token); + } else if (Q_stricmp(key.c_str(), "startFOV") == 0) { + startFOV = atof(token); + } else if (Q_stricmp(key.c_str(), "endFOV") == 0) { + endFOV = atof(token); + } else if (Q_stricmp(key.c_str(), "time") == 0) { + time = atoi(token); + } + token = Com_Parse(text); + + } while (1); + + if ( !strcmp (token, "}") ) { + break; + } + + } while (1); + + Com_UngetToken(); + Com_MatchToken( text, "}" ); +} + +bool idCameraPosition::parseToken(const char *key, const char *(*text)) { + const char *token = Com_Parse(text); + if (Q_stricmp(key, "time") == 0) { + time = atol(token); + return true; + } else if (Q_stricmp(key, "type") == 0) { + type = static_cast(atoi(token)); + return true; + } else if (Q_stricmp(key, "velocity") == 0) { + long t = atol(token); + token = Com_Parse(text); + long d = atol(token); + token = Com_Parse(text); + float s = atof(token); + addVelocity(t, d, s); + return true; + } else if (Q_stricmp(key, "baseVelocity") == 0) { + baseVelocity = atof(token); + return true; + } else if (Q_stricmp(key, "name") == 0) { + name = token; + return true; + } else if (Q_stricmp(key, "time") == 0) { + time = atoi(token); + return true; + } + Com_UngetToken(); + return false; +} + + + +void idFixedPosition::parse(const char *(*text) ) { + const char *token; + Com_MatchToken( text, "{" ); + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !strcmp (token, "}") ) { + break; + } + + // here we may have to jump over brush epairs ( only used in editor ) + do { + // if token is not a brace, it is a key for a key/value pair + if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { + break; + } + + Com_UngetToken(); + idStr key = Com_ParseOnLine(text); + + const char *token = Com_Parse(text); + if (Q_stricmp(key.c_str(), "pos") == 0) { + Com_UngetToken(); + Com_Parse1DMatrix( text, 3, pos ); + } else { + Com_UngetToken(); + idCameraPosition::parseToken(key.c_str(), text); + } + token = Com_Parse(text); + + } while (1); + + if ( !strcmp (token, "}") ) { + break; + } + + } while (1); + + Com_UngetToken(); + Com_MatchToken( text, "}" ); +} + +void idInterpolatedPosition::parse(const char *(*text) ) { + const char *token; + Com_MatchToken( text, "{" ); + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !strcmp (token, "}") ) { + break; + } + + // here we may have to jump over brush epairs ( only used in editor ) + do { + // if token is not a brace, it is a key for a key/value pair + if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { + break; + } + + Com_UngetToken(); + idStr key = Com_ParseOnLine(text); + + const char *token = Com_Parse(text); + if (Q_stricmp(key.c_str(), "startPos") == 0) { + Com_UngetToken(); + Com_Parse1DMatrix( text, 3, startPos ); + } else if (Q_stricmp(key.c_str(), "endPos") == 0) { + Com_UngetToken(); + Com_Parse1DMatrix( text, 3, endPos ); + } else { + Com_UngetToken(); + idCameraPosition::parseToken(key.c_str(), text); + } + token = Com_Parse(text); + + } while (1); + + if ( !strcmp (token, "}") ) { + break; + } + + } while (1); + + Com_UngetToken(); + Com_MatchToken( text, "}" ); +} + + +void idSplinePosition::parse(const char *(*text) ) { + const char *token; + Com_MatchToken( text, "{" ); + do { + token = Com_Parse( text ); + + if ( !token[0] ) { + break; + } + if ( !strcmp (token, "}") ) { + break; + } + + // here we may have to jump over brush epairs ( only used in editor ) + do { + // if token is not a brace, it is a key for a key/value pair + if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) { + break; + } + + Com_UngetToken(); + idStr key = Com_ParseOnLine(text); + + const char *token = Com_Parse(text); + if (Q_stricmp(key.c_str(), "target") == 0) { + target.parse(text); + } else { + Com_UngetToken(); + idCameraPosition::parseToken(key.c_str(), text); + } + token = Com_Parse(text); + + } while (1); + + if ( !strcmp (token, "}") ) { + break; + } + + } while (1); + + Com_UngetToken(); + Com_MatchToken( text, "}" ); +} + + + +void idCameraFOV::write(fileHandle_t file, const char *p) { + idStr s = va("\t%s {\n", p); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\tfov %f\n", fov); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\tstartFOV %f\n", startFOV); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\tendFOV %f\n", endFOV); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\ttime %i\n", time); + FS_Write(s.c_str(), s.length(), file); + + s = "\t}\n"; + FS_Write(s.c_str(), s.length(), file); +} + + +void idCameraPosition::write(fileHandle_t file, const char *p) { + + idStr s = va("\t\ttime %i\n", time); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\ttype %i\n", static_cast(type)); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\tname %s\n", name.c_str()); + FS_Write(s.c_str(), s.length(), file); + + s = va("\t\tbaseVelocity %f\n", baseVelocity); + FS_Write(s.c_str(), s.length(), file); + + for (int i = 0; i < velocities.Num(); i++) { + s = va("\t\tvelocity %i %i %f\n", velocities[i]->startTime, velocities[i]->time, velocities[i]->speed); + FS_Write(s.c_str(), s.length(), file); + } + +} + +void idFixedPosition::write(fileHandle_t file, const char *p) { + idStr s = va("\t%s {\n", p); + FS_Write(s.c_str(), s.length(), file); + idCameraPosition::write(file, p); + s = va("\t\tpos ( %f %f %f )\n", pos.x, pos.y, pos.z); + FS_Write(s.c_str(), s.length(), file); + s = "\t}\n"; + FS_Write(s.c_str(), s.length(), file); +} + +void idInterpolatedPosition::write(fileHandle_t file, const char *p) { + idStr s = va("\t%s {\n", p); + FS_Write(s.c_str(), s.length(), file); + idCameraPosition::write(file, p); + s = va("\t\tstartPos ( %f %f %f )\n", startPos.x, startPos.y, startPos.z); + FS_Write(s.c_str(), s.length(), file); + s = va("\t\tendPos ( %f %f %f )\n", endPos.x, endPos.y, endPos.z); + FS_Write(s.c_str(), s.length(), file); + s = "\t}\n"; + FS_Write(s.c_str(), s.length(), file); +} + +void idSplinePosition::write(fileHandle_t file, const char *p) { + idStr s = va("\t%s {\n", p); + FS_Write(s.c_str(), s.length(), file); + idCameraPosition::write(file, p); + target.write(file, "target"); + s = "\t}\n"; + FS_Write(s.c_str(), s.length(), file); +} + +void idCameraDef::addTarget(const char *name, idCameraPosition::positionType type) { + //const char *text = (name == NULL) ? va("target0%d", numTargets()+1) : name; // TTimo: unused + idCameraPosition *pos = newFromType(type); + if (pos) { + pos->setName(name); + targetPositions.Append(pos); + activeTarget = numTargets()-1; + if (activeTarget == 0) { + // first one + addEvent(idCameraEvent::EVENT_TARGET, name, 0); + } + } +} + + + +idCameraDef camera; + +extern "C" { +qboolean loadCamera(const char *name) { + camera.clear(); + return static_cast(camera.load(name)); +} + +qboolean getCameraInfo(int time, float *origin, float*angles) { + idVec3_t dir, org; + org[0] = origin[0]; + org[1] = origin[1]; + org[2] = origin[2]; + float fov = 90; + if (camera.getCameraInfo(time, org, dir, &fov)) { + origin[0] = org[0]; + origin[1] = org[1]; + origin[2] = org[2]; + angles[1] = atan2 (dir[1], dir[0])*180/3.14159; + angles[0] = asin (dir[2])*180/3.14159; + return qtrue; + } + return qfalse; +} + +void startCamera(int time) { + camera.startCamera(time); +} + +} + + diff --git a/CODE-mp/Splines/splines.h b/CODE-mp/Splines/splines.h new file mode 100644 index 0000000..5454aff --- /dev/null +++ b/CODE-mp/Splines/splines.h @@ -0,0 +1,1061 @@ +#ifndef __SPLINES_H +#define __SPLINES_H + +extern "C" { +#ifdef Q3RADIANT +#include "../qgl.h" +#else +#include "../renderer/qgl.h" +#endif +} +#include "util_list.h" +#include "util_str.h" +#include "math_vector.h" + +typedef int fileHandle_t; + +extern void glBox(idVec3_t &color, idVec3_t &point, float size); +extern void glLabeledPoint(idVec3_t &color, idVec3_t &point, float size, const char *label); + +static vec4_t blue(0, 0, 1, 1); +static vec4_t red(1, 0, 0, 1); + +class idPointListInterface { +public: + idPointListInterface() { + selectedPoints.Clear(); + } + virtual ~idPointListInterface() {} + + virtual int numPoints() { + return 0; + } + + virtual void addPoint(const float x, const float y, const float z) {} + virtual void addPoint(const idVec3_t &v) {} + virtual void removePoint(int index) {} + virtual idVec3_t *getPoint(int index) { return NULL; } + + int selectPointByRay(float ox, float oy, float oz, float dx, float dy, float dz, bool single) { + idVec3_t origin(ox, oy, oz); + idVec3_t dir(dx, dy, dz); + return selectPointByRay(origin, dir, single); + } + + int selectPointByRay(const idVec3_t origin, const idVec3_t direction, bool single) { + int i, besti, count; + float d, bestd; + idVec3_t temp, temp2; + + // find the point closest to the ray + besti = -1; + bestd = 8; + count = numPoints(); + + for (i=0; i < count; i++) { + temp = *getPoint(i); + temp2 = temp; + temp -= origin; + d = DotProduct(temp, direction); + __VectorMA (origin, d, direction, temp); + temp2 -= temp; + d = temp2.Length(); + if (d <= bestd) { + bestd = d; + besti = i; + } + } + + if (besti >= 0) { + selectPoint(besti, single); + } + + return besti; + } + + int isPointSelected(int index) { + int count = selectedPoints.Num(); + for (int i = 0; i < count; i++) { + if (selectedPoints[i] == index) { + return i; + } + } + return -1; + } + + int selectPoint(int index, bool single) { + if (index >= 0 && index < numPoints()) { + if (single) { + deselectAll(); + } else { + if (isPointSelected(index) >= 0) { + selectedPoints.Remove(index); + } + } + return selectedPoints.Append(index); + } + return -1; + } + + void selectAll() { + selectedPoints.Clear(); + for (int i = 0; i < numPoints(); i++) { + selectedPoints.Append(i); + } + } + + void deselectAll() { + selectedPoints.Clear(); + } + + int numSelectedPoints(); + + idVec3_t *getSelectedPoint(int index) { + assert(index >= 0 && index < numSelectedPoints()); + return getPoint(selectedPoints[index]); + } + + virtual void updateSelection(float x, float y, float z) { + idVec3_t move(x, y, z); + updateSelection(move); + } + + virtual void updateSelection(const idVec3_t &move) { + int count = selectedPoints.Num(); + for (int i = 0; i < count; i++) { + *getPoint(selectedPoints[i]) += move; + } + } + + void drawSelection() { + int count = selectedPoints.Num(); + for (int i = 0; i < count; i++) { + glBox(red, *getPoint(selectedPoints[i]), 4); + } + } + +protected: + idList selectedPoints; + +}; + + +class idSplineList { + +public: + + idSplineList() { + clear(); + } + + idSplineList(const char *p) { + clear(); + name = p; + }; + + ~idSplineList() { + clear(); + }; + + void clearControl() { + for (int i = 0; i < controlPoints.Num(); i++) { + delete controlPoints[i]; + } + controlPoints.Clear(); + } + + void clearSpline() { + for (int i = 0; i < splinePoints.Num(); i++) { + delete splinePoints[i]; + } + splinePoints.Clear(); + } + + void parse(const char *(*text)); + void write(fileHandle_t file, const char *name); + + void clear() { + clearControl(); + clearSpline(); + splineTime.Clear(); + selected = NULL; + dirty = true; + activeSegment = 0; + granularity = 0.025; + pathColor.set(1.0, 0.5, 0.0); + controlColor.set(0.7, 0.0, 1.0); + segmentColor.set(0.0, 0.0, 1.0); + activeColor.set(1.0, 0.0, 0.0); + } + + void initPosition(long startTime, long totalTime); + const idVec3_t *getPosition(long time); + + + void draw(bool editMode); + void addToRenderer(); + + void setSelectedPoint(idVec3_t *p); + idVec3_t *getSelectedPoint() { + return selected; + } + + void addPoint(const idVec3_t &v) { + controlPoints.Append(new idVec3_t(v)); + dirty = true; + } + + void addPoint(float x, float y, float z) { + controlPoints.Append(new idVec3_t(x, y, z)); + dirty = true; + } + + void updateSelection(const idVec3_t &move); + + void startEdit() { + editMode = true; + } + + void stopEdit() { + editMode = false; + } + + void buildSpline(); + + void setGranularity(float f) { + granularity = f; + } + + float getGranularity() { + return granularity; + } + + int numPoints() { + return controlPoints.Num(); + } + + idVec3_t *getPoint(int index) { + assert(index >= 0 && index < controlPoints.Num()); + return controlPoints[index]; + } + + idVec3_t *getSegmentPoint(int index) { + assert(index >= 0 && index < splinePoints.Num()); + return splinePoints[index]; + } + + + void setSegmentTime(int index, int time) { + assert(index >= 0 && index < splinePoints.Num()); + splineTime[index] = time; + } + + double getSegmentTime(int index) { + assert(index >= 0 && index < splinePoints.Num()); + return splineTime[index]; + } + void addSegmentTime(int index, int time) { + assert(index >= 0 && index < splinePoints.Num()); + splineTime[index] += time; + } + + float totalDistance(); + + static idVec3_t zero; + + int getActiveSegment() { + return activeSegment; + } + + void setActiveSegment(int i) { + //assert(i >= 0 && (splinePoints.Num() > 0 && i < splinePoints.Num())); + activeSegment = i; + } + + int numSegments() { + return splinePoints.Num(); + } + + void setColors(idVec3_t &path, idVec3_t &segment, idVec3_t &control, idVec3_t &active) { + pathColor = path; + segmentColor = segment; + controlColor = control; + activeColor = active; + } + + const char *getName() { + return name.c_str(); + } + + void setName(const char *p) { + name = p; + } + + bool validTime() { + if (dirty) { + buildSpline(); + } + // gcc doesn't allow static casting away from bools + // why? I've no idea... + return (bool)(splineTime.Num() > 0 && splineTime.Num() == splinePoints.Num()); + } + + void setTime(long t) { + time = t; + } + + void setBaseTime(long t) { + baseTime = t; + } + +protected: + idStr name; + float calcSpline(int step, float tension); + idList controlPoints; + idList splinePoints; + idList splineTime; + idVec3_t *selected; + idVec3_t pathColor, segmentColor, controlColor, activeColor; + float granularity; + bool editMode; + bool dirty; + int activeSegment; + long baseTime; + long time; + friend class idCamera; +}; + +// time in milliseconds +// velocity where 1.0 equal rough walking speed +struct idVelocity { + idVelocity(long start, long duration, float s) { + startTime = start; + time = duration; + speed = s; + } + long startTime; + long time; + float speed; +}; + +// can either be a look at or origin position for a camera +// +class idCameraPosition : public idPointListInterface { +public: + + virtual void clear() { + editMode = false; + for (int i = 0; i < velocities.Num(); i++) { + delete velocities[i]; + velocities[i] = NULL; + } + velocities.Clear(); + } + + idCameraPosition(const char *p) { + name = p; + } + + idCameraPosition() { + time = 0; + name = "position"; + } + + idCameraPosition(long t) { + time = t; + } + + virtual ~idCameraPosition() { + clear(); + } + + + // this can be done with RTTI syntax but i like the derived classes setting a type + // makes serialization a bit easier to see + // + enum positionType { + FIXED = 0x00, + INTERPOLATED, + SPLINE, + POSITION_COUNT + }; + + + virtual void start(long t) { + startTime = t; + } + + long getTime() { + return time; + } + + virtual void setTime(long t) { + time = t; + } + + float getVelocity(long t) { + long check = t - startTime; + for (int i = 0; i < velocities.Num(); i++) { + if (check >= velocities[i]->startTime && check <= velocities[i]->startTime + velocities[i]->time) { + return velocities[i]->speed; + } + } + return baseVelocity; + } + + void addVelocity(long start, long duration, float speed) { + velocities.Append(new idVelocity(start, duration, speed)); + } + + virtual const idVec3_t *getPosition(long t) { + assert(true); + return NULL; + } + + virtual void draw(bool editMode) {}; + + virtual void parse(const char *(*text)) {}; + virtual void write(fileHandle_t file, const char *name); + virtual bool parseToken(const char *key, const char *(*text)); + + const char *getName() { + return name.c_str(); + } + + void setName(const char *p) { + name = p; + } + + virtual void startEdit() { + editMode = true; + } + + virtual void stopEdit() { + editMode = false; + } + + virtual void draw() {}; + + const char *typeStr() { + return positionStr[static_cast(type)]; + } + + void calcVelocity(float distance) { + float secs = (float)time / 1000; + baseVelocity = distance / secs; + } + +protected: + static const char* positionStr[POSITION_COUNT]; + long startTime; + long time; + idCameraPosition::positionType type; + idStr name; + bool editMode; + idList velocities; + float baseVelocity; +}; + +class idFixedPosition : public idCameraPosition { +public: + + void init() { + pos.Zero(); + type = idCameraPosition::FIXED; + } + + idFixedPosition() : idCameraPosition() { + init(); + } + + idFixedPosition(idVec3_t p) : idCameraPosition() { + init(); + pos = p; + } + + virtual void addPoint(const idVec3_t &v) { + pos = v; + } + + virtual void addPoint(const float x, const float y, const float z) { + pos.set(x, y, z); + } + + + ~idFixedPosition() { + } + + virtual const idVec3_t *getPosition(long t) { + return &pos; + } + + void parse(const char *(*text)); + void write(fileHandle_t file, const char *name); + + virtual int numPoints() { + return 1; + } + + virtual idVec3_t *getPoint(int index) { + if (index != 0) { + assert(true); + }; + return &pos; + } + + virtual void draw(bool editMode) { + glLabeledPoint(blue, pos, (editMode) ? 5 : 3, "Fixed point"); + } + +protected: + idVec3_t pos; +}; + +class idInterpolatedPosition : public idCameraPosition { +public: + + void init() { + type = idCameraPosition::INTERPOLATED; + first = true; + startPos.Zero(); + endPos.Zero(); + } + + idInterpolatedPosition() : idCameraPosition() { + init(); + } + + idInterpolatedPosition(idVec3_t start, idVec3_t end, long time) : idCameraPosition(time) { + init(); + startPos = start; + endPos = end; + } + + ~idInterpolatedPosition() { + } + + virtual const idVec3_t *getPosition(long t); + + void parse(const char *(*text)); + void write(fileHandle_t file, const char *name); + + virtual int numPoints() { + return 2; + } + + virtual idVec3_t *getPoint(int index) { + assert(index >= 0 && index < 2); + if (index == 0) { + return &startPos; + } + return &endPos; + } + + virtual void addPoint(const float x, const float y, const float z) { + if (first) { + startPos.set(x, y, z); + first = false; + } else { + endPos.set(x, y, z); + first = true; + } + } + + virtual void addPoint(const idVec3_t &v) { + if (first) { + startPos = v; + first = false; + } else { + endPos = v; + first = true; + } + } + + virtual void draw(bool editMode) { + glLabeledPoint(blue, startPos, (editMode) ? 5 : 3, "Start interpolated"); + glLabeledPoint(blue, endPos, (editMode) ? 5 : 3, "End interpolated"); + qglBegin(GL_LINES); + qglVertex3fv(startPos); + qglVertex3fv(endPos); + qglEnd(); + } + + virtual void start(long t) { + idCameraPosition::start(t); + lastTime = startTime; + distSoFar = 0.0; + idVec3_t temp = startPos; + temp -= endPos; + calcVelocity(temp.Length()); + } + +protected: + bool first; + idVec3_t startPos; + idVec3_t endPos; + long lastTime; + float distSoFar; +}; + +class idSplinePosition : public idCameraPosition { +public: + + void init() { + type = idCameraPosition::SPLINE; + } + + idSplinePosition() : idCameraPosition() { + init(); + } + + idSplinePosition(long time) : idCameraPosition(time) { + init(); + } + + ~idSplinePosition() { + } + + virtual void start(long t) { + idCameraPosition::start(t); + target.initPosition(t, time); + calcVelocity(target.totalDistance()); + } + + virtual const idVec3_t *getPosition(long t) { + return target.getPosition(t); + } + + //virtual const idVec3_t *getPosition(long t) const { + + void addControlPoint(idVec3_t &v) { + target.addPoint(v); + } + + void parse(const char *(*text)); + void write(fileHandle_t file, const char *name); + + virtual int numPoints() { + return target.numPoints(); + } + + virtual idVec3_t *getPoint(int index) { + return target.getPoint(index); + } + + virtual void addPoint(const idVec3_t &v) { + target.addPoint(v); + } + + virtual void addPoint(const float x, const float y, const float z) { + target.addPoint(x, y, z); + } + + virtual void draw(bool editMode) { + target.draw(editMode); + } + + virtual void updateSelection(const idVec3_t &move) { + idCameraPosition::updateSelection(move); + target.buildSpline(); + } + +protected: + idSplineList target; +}; + +class idCameraFOV { +public: + + idCameraFOV() { + time = 0; + fov = 90; + } + + idCameraFOV(int v) { + time = 0; + fov = v; + } + + idCameraFOV(int s, int e, long t) { + startFOV = s; + endFOV = e; + time = t; + } + + + ~idCameraFOV(){} + + void setFOV(float f) { + fov = f; + } + + float getFOV(long t) { + if (time) { + assert(startTime); + float percent = t / startTime; + float temp = startFOV - endFOV; + temp *= percent; + fov = startFOV + temp; + } + return fov; + } + + void start(long t) { + startTime = t; + } + + void parse(const char *(*text)); + void write(fileHandle_t file, const char *name); + +protected: + float fov; + float startFOV; + float endFOV; + int startTime; + int time; +}; + + + + +class idCameraEvent { +public: + enum eventType { + EVENT_NA = 0x00, + EVENT_WAIT, + EVENT_TARGETWAIT, + EVENT_SPEED, + EVENT_TARGET, + EVENT_SNAPTARGET, + EVENT_FOV, + EVENT_SCRIPT, + EVENT_TRIGGER, + EVENT_STOP, + EVENT_COUNT + }; + + static const char* eventStr[EVENT_COUNT]; + + idCameraEvent() { + paramStr = ""; + type = EVENT_NA; + time = 0; + } + + idCameraEvent(eventType t, const char *param, long n) { + type = t; + paramStr = param; + time = n; + } + + ~idCameraEvent() {}; + + eventType getType() { + return type; + } + + const char *typeStr() { + return eventStr[static_cast(type)]; + } + + const char *getParam() { + return paramStr.c_str(); + } + + long getTime() { + return time; + } + + void setTime(long n) { + time = n; + } + + void parse(const char *(*text)); + void write(fileHandle_t file, const char *name); + + void setTriggered(bool b) { + triggered = b; + } + + bool getTriggered() { + return triggered; + } + +protected: + eventType type; + idStr paramStr; + long time; + bool triggered; + +}; + +class idCameraDef { +public: + + void clear() { + currentCameraPosition = 0; + cameraRunning = false; + lastDirection.Zero(); + baseTime = 30; + activeTarget = 0; + name = "camera01"; + fov.setFOV(90); + int i; + for (i = 0; i < targetPositions.Num(); i++) { + delete targetPositions[i]; + } + for (i = 0; i < events.Num(); i++) { + delete events[i]; + } + delete cameraPosition; + cameraPosition = NULL; + events.Clear(); + targetPositions.Clear(); + } + + idCameraPosition *startNewCamera(idCameraPosition::positionType type) { + clear(); + if (type == idCameraPosition::SPLINE) { + cameraPosition = new idSplinePosition(); + } else if (type == idCameraPosition::INTERPOLATED) { + cameraPosition = new idInterpolatedPosition(); + } else { + cameraPosition = new idFixedPosition(); + } + return cameraPosition; + } + + idCameraDef() { + clear(); + } + + ~idCameraDef() { + clear(); + } + + void addEvent(idCameraEvent::eventType t, const char *param, long time); + + void addEvent(idCameraEvent *event); + + static int sortEvents(const void *p1, const void *p2); + + int numEvents() { + return events.Num(); + } + + idCameraEvent *getEvent(int index) { + assert(index >= 0 && index < events.Num()); + return events[index]; + } + + void parse(const char *(*text)); + qboolean load(const char *filename); + void save(const char *filename); + + void buildCamera(); + + //idSplineList *getcameraPosition() { + // return &cameraPosition; + //} + + static idCameraPosition *newFromType(idCameraPosition::positionType t) { + switch (t) { + case idCameraPosition::FIXED : return new idFixedPosition(); + case idCameraPosition::INTERPOLATED : return new idInterpolatedPosition(); + case idCameraPosition::SPLINE : return new idSplinePosition(); + default: + break; + }; + return NULL; + } + + void addTarget(const char *name, idCameraPosition::positionType type); + + idCameraPosition *getActiveTarget() { + if (targetPositions.Num() == 0) { + addTarget(NULL, idCameraPosition::FIXED); + } + return targetPositions[activeTarget]; + } + + idCameraPosition *getActiveTarget(int index) { + if (targetPositions.Num() == 0) { + addTarget(NULL, idCameraPosition::FIXED); + return targetPositions[0]; + } + return targetPositions[index]; + } + + int numTargets() { + return targetPositions.Num(); + } + + + void setActiveTargetByName(const char *name) { + for (int i = 0; i < targetPositions.Num(); i++) { + if (Q_stricmp(name, targetPositions[i]->getName()) == 0) { + setActiveTarget(i); + return; + } + } + } + + void setActiveTarget(int index) { + assert(index >= 0 && index < targetPositions.Num()); + activeTarget = index; + } + + void setRunning(bool b) { + cameraRunning = b; + } + + void setBaseTime(float f) { + baseTime = f; + } + + float getBaseTime() { + return baseTime; + } + + float getTotalTime() { + return totalTime; + } + + void startCamera(long t); + void stopCamera() { + cameraRunning = true; + } + void getActiveSegmentInfo(int segment, idVec3_t &origin, idVec3_t &direction, float *fv); + + bool getCameraInfo(long time, idVec3_t &origin, idVec3_t &direction, float *fv); + bool getCameraInfo(long time, float *origin, float *direction, float *fv) { + idVec3_t org, dir; + org[0] = origin[0]; + org[1] = origin[1]; + org[2] = origin[2]; + dir[0] = direction[0]; + dir[1] = direction[1]; + dir[2] = direction[2]; + bool b = getCameraInfo(time, org, dir, fv); + origin[0] = org[0]; + origin[1] = org[1]; + origin[2] = org[2]; + direction[0] = dir[0]; + direction[1] = dir[1]; + direction[2] = dir[2]; + return b; + } + + void draw(bool editMode) { + // gcc doesn't allow casting away from bools + // why? I've no idea... + if (cameraPosition) { + cameraPosition->draw((bool)((editMode || cameraRunning) && cameraEdit)); + int count = targetPositions.Num(); + for (int i = 0; i < count; i++) { + targetPositions[i]->draw((bool)((editMode || cameraRunning) && i == activeTarget && !cameraEdit)); + } + } + } + +/* + int numSegments() { + if (cameraEdit) { + return cameraPosition.numSegments(); + } + return getTargetSpline()->numSegments(); + } + + int getActiveSegment() { + if (cameraEdit) { + return cameraPosition.getActiveSegment(); + } + return getTargetSpline()->getActiveSegment(); + } + + void setActiveSegment(int i) { + if (cameraEdit) { + cameraPosition.setActiveSegment(i); + } else { + getTargetSpline()->setActiveSegment(i); + } + } +*/ + int numPoints() { + if (cameraEdit) { + return cameraPosition->numPoints(); + } + return getActiveTarget()->numPoints(); + } + + const idVec3_t *getPoint(int index) { + if (cameraEdit) { + return cameraPosition->getPoint(index); + } + return getActiveTarget()->getPoint(index); + } + + void stopEdit() { + editMode = false; + if (cameraEdit) { + cameraPosition->stopEdit(); + } else { + getActiveTarget()->stopEdit(); + } + } + + void startEdit(bool camera) { + cameraEdit = camera; + if (camera) { + cameraPosition->startEdit(); + for (int i = 0; i < targetPositions.Num(); i++) { + targetPositions[i]->stopEdit(); + } + } else { + getActiveTarget()->startEdit(); + cameraPosition->stopEdit(); + } + editMode = true; + } + + bool waitEvent(int index); + + const char *getName() { + return name.c_str(); + } + + void setName(const char *p) { + name = p; + } + + idCameraPosition *getPositionObj() { + if (cameraPosition == NULL) { + cameraPosition = new idFixedPosition(); + } + return cameraPosition; + } + +protected: + idStr name; + int currentCameraPosition; + idVec3_t lastDirection; + bool cameraRunning; + idCameraPosition *cameraPosition; + idList targetPositions; + idList events; + idCameraFOV fov; + int activeTarget; + float totalTime; + float baseTime; + long startTime; + + bool cameraEdit; + bool editMode; +}; + +extern bool g_splineMode; + +extern idCameraDef *g_splineList; + + +#endif diff --git a/CODE-mp/Splines/util_list.h b/CODE-mp/Splines/util_list.h new file mode 100644 index 0000000..90d162b --- /dev/null +++ b/CODE-mp/Splines/util_list.h @@ -0,0 +1,325 @@ +#ifndef __UTIL_LIST_H__ +#define __UTIL_LIST_H__ + +#include +#include + +template< class type > +class idList { +private: + int m_num; + int m_size; + int m_granularity; + type *m_list; + +public: + idList( int granularity = 16 ); + ~idList(); + void Clear( void ); + int Num( void ); + void SetNum( int num ); + void SetGranularity( int granularity ); + void Condense( void ); + int Size( void ); + void Resize( int size ); + type operator[]( int index ) const; + type &operator[]( int index ); + int Append( type const & obj ); + int AddUnique( type const & obj ); + type *Find( type const & obj, int *index = NULL ); + bool RemoveIndex( int index ); + bool Remove( type const & obj ); + typedef int cmp_t(const void *, const void *); + void Sort( cmp_t *compare ); +}; + +/* +================ +idList::idList( int ) +================ +*/ +template< class type > +inline idList::idList( int granularity ) { + assert( granularity > 0 ); + + m_list = NULL; + m_granularity = granularity; + Clear(); +} + +/* +================ +idList::~idList +================ +*/ +template< class type > +inline idList::~idList() { + Clear(); +} + +/* +================ +idList::Clear +================ +*/ +template< class type > +inline void idList::Clear( void ) { + if ( m_list ) { + delete[] m_list; + } + + m_list = NULL; + m_num = 0; + m_size = 0; +} + +/* +================ +idList::Num +================ +*/ +template< class type > +inline int idList::Num( void ) { + return m_num; +} + +/* +================ +idList::SetNum +================ +*/ +template< class type > +inline void idList::SetNum( int num ) { + assert( num >= 0 ); + if ( num > m_size ) { + // resize it up to the closest level of granularity + Resize( ( ( num + m_granularity - 1 ) / m_granularity ) * m_granularity ); + } + m_num = num; +} + +/* +================ +idList::SetGranularity +================ +*/ +template< class type > +inline void idList::SetGranularity( int granularity ) { + int newsize; + + assert( granularity > 0 ); + m_granularity = granularity; + + if ( m_list ) { + // resize it to the closest level of granularity + newsize = ( ( m_num + m_granularity - 1 ) / m_granularity ) * m_granularity; + if ( newsize != m_size ) { + Resize( newsize ); + } + } +} + +/* +================ +idList::Condense + +Resizes the array to exactly the number of elements it contains +================ +*/ +template< class type > +inline void idList::Condense( void ) { + if ( m_list ) { + if ( m_num ) { + Resize( m_num ); + } else { + Clear(); + } + } +} + +/* +================ +idList::Size +================ +*/ +template< class type > +inline int idList::Size( void ) { + return m_size; +} + +/* +================ +idList::Resize +================ +*/ +template< class type > +inline void idList::Resize( int size ) { + type *temp; + int i; + + assert( size > 0 ); + + if ( size <= 0 ) { + Clear(); + return; + } + + temp = m_list; + m_size = size; + if ( m_size < m_num ) { + m_num = m_size; + } + + m_list = new type[ m_size ]; + for( i = 0; i < m_num; i++ ) { + m_list[ i ] = temp[ i ]; + } + + if ( temp ) { + delete[] temp; + } +} + +/* +================ +idList::operator[] const +================ +*/ +template< class type > +inline type idList::operator[]( int index ) const { + assert( index >= 0 ); + assert( index < m_num ); + + return m_list[ index ]; +} + +/* +================ +idList::operator[] +================ +*/ +template< class type > +inline type &idList::operator[]( int index ) { + assert( index >= 0 ); + assert( index < m_num ); + + return m_list[ index ]; +} + +/* +================ +idList::Append +================ +*/ +template< class type > +inline int idList::Append( type const & obj ) { + if ( !m_list ) { + Resize( m_granularity ); + } + + if ( m_num == m_size ) { + Resize( m_size + m_granularity ); + } + + m_list[ m_num ] = obj; + m_num++; + + return m_num - 1; +} + +/* +================ +idList::AddUnique +================ +*/ +template< class type > +inline int idList::AddUnique( type const & obj ) { + int index; + + if ( !Find( obj, &index ) ) { + index = Append( obj ); + } + + return index; +} + +/* +================ +idList::Find +================ +*/ +template< class type > +inline type *idList::Find( type const & obj, int *index ) { + int i; + + for( i = 0; i < m_num; i++ ) { + if ( m_list[ i ] == obj ) { + if ( index ) { + *index = i; + } + return &m_list[ i ]; + } + } + + return NULL; +} + +/* +================ +idList::RemoveIndex +================ +*/ +template< class type > +inline bool idList::RemoveIndex( int index ) { + int i; + + if ( !m_list || !m_num ) { + return false; + } + + assert( index >= 0 ); + assert( index < m_num ); + + if ( ( index < 0 ) || ( index >= m_num ) ) { + return false; + } + + m_num--; + for( i = index; i < m_num; i++ ) { + m_list[ i ] = m_list[ i + 1 ]; + } + + return true; +} + +/* +================ +idList::Remove +================ +*/ +template< class type > +inline bool idList::Remove( type const & obj ) { + int index; + + if ( Find( obj, &index ) ) { + return RemoveIndex( index ); + } + + return false; +} + +/* +================ +idList::Sort +================ +*/ +template< class type > +inline void idList::Sort( cmp_t *compare ) { + if ( !m_list ) { + return; + } + + qsort( ( void * )m_list, ( size_t )m_num, sizeof( type ), compare ); +} + +#endif /* !__UTIL_LIST_H__ */ diff --git a/CODE-mp/Splines/util_str.cpp b/CODE-mp/Splines/util_str.cpp new file mode 100644 index 0000000..f68ce6d --- /dev/null +++ b/CODE-mp/Splines/util_str.cpp @@ -0,0 +1,598 @@ +//need to rewrite this + +#include "util_str.h" +#include +#include +#include +#include + +#ifdef _WIN32 +#pragma warning(disable : 4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data +#pragma warning(disable : 4710) // function 'blah' not inlined +#endif + +static const int STR_ALLOC_GRAN = 20; + +char *idStr::tolower + ( + char *s1 + ) + + { + char *s; + + s = s1; + while( *s ) + { + *s = ::tolower( *s ); + s++; + } + + return s1; + } + +char *idStr::toupper + ( + char *s1 + ) + + { + char *s; + + s = s1; + while( *s ) + { + *s = ::toupper( *s ); + s++; + } + + return s1; + } + +int idStr::icmpn + ( + const char *s1, + const char *s2, + int n + ) + + { + int c1; + int c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( !n-- ) + { + // idStrings are equal until end point + return 0; + } + + if ( c1 != c2 ) + { + if ( c1 >= 'a' && c1 <= 'z' ) + { + c1 -= ( 'a' - 'A' ); + } + + if ( c2 >= 'a' && c2 <= 'z' ) + { + c2 -= ( 'a' - 'A' ); + } + + if ( c1 < c2 ) + { + // strings less than + return -1; + } + else if ( c1 > c2 ) + { + // strings greater than + return 1; + } + } + } + while( c1 ); + + // strings are equal + return 0; + } + +int idStr::icmp + ( + const char *s1, + const char *s2 + ) + + { + int c1; + int c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( c1 != c2 ) + { + if ( c1 >= 'a' && c1 <= 'z' ) + { + c1 -= ( 'a' - 'A' ); + } + + if ( c2 >= 'a' && c2 <= 'z' ) + { + c2 -= ( 'a' - 'A' ); + } + + if ( c1 < c2 ) + { + // strings less than + return -1; + } + else if ( c1 > c2 ) + { + // strings greater than + return 1; + } + } + } + while( c1 ); + + // strings are equal + return 0; + } + +int idStr::cmpn + ( + const char *s1, + const char *s2, + int n + ) + + { + int c1; + int c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( !n-- ) + { + // strings are equal until end point + return 0; + } + + if ( c1 < c2 ) + { + // strings less than + return -1; + } + else if ( c1 > c2 ) + { + // strings greater than + return 1; + } + } + while( c1 ); + + // strings are equal + return 0; + } + +int idStr::cmp + ( + const char *s1, + const char *s2 + ) + + { + int c1; + int c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( c1 < c2 ) + { + // strings less than + return -1; + } + else if ( c1 > c2 ) + { + // strings greater than + return 1; + } + } + while( c1 ); + + // strings are equal + return 0; + } + +/* +============ +IsNumeric + +Checks a string to see if it contains only numerical values. +============ +*/ +bool idStr::isNumeric + ( + const char *str + ) + + { + int len; + int i; + bool dot; + + if ( *str == '-' ) + { + str++; + } + + dot = false; + len = strlen( str ); + for( i = 0; i < len; i++ ) + { + if ( !isdigit( str[ i ] ) ) + { + if ( ( str[ i ] == '.' ) && !dot ) + { + dot = true; + continue; + } + return false; + } + } + + return true; + } + +idStr operator+ + ( + const idStr& a, + const float b + ) + + { + char text[ 20 ]; + + idStr result( a ); + + sprintf( text, "%f", b ); + result.append( text ); + + return result; + } + +idStr operator+ + ( + const idStr& a, + const int b + ) + + { + char text[ 20 ]; + + idStr result( a ); + + sprintf( text, "%d", b ); + result.append( text ); + + return result; + } + +idStr operator+ + ( + const idStr& a, + const unsigned b + ) + + { + char text[ 20 ]; + + idStr result( a ); + + sprintf( text, "%u", b ); + result.append( text ); + + return result; + } + +idStr& idStr::operator+= + ( + const float a + ) + + { + char text[ 20 ]; + + sprintf( text, "%f", a ); + append( text ); + + return *this; + } + +idStr& idStr::operator+= + ( + const int a + ) + + { + char text[ 20 ]; + + sprintf( text, "%d", a ); + append( text ); + + return *this; + } + +idStr& idStr::operator+= + ( + const unsigned a + ) + + { + char text[ 20 ]; + + sprintf( text, "%u", a ); + append( text ); + + return *this; + } + +void idStr::CapLength + ( + int newlen + ) + + { + assert ( m_data ); + + if ( length() <= newlen ) + return; + + EnsureDataWritable (); + + m_data->data[newlen] = 0; + m_data->len = newlen; + } + +void idStr::EnsureDataWritable + ( + void + ) + + { + assert ( m_data ); + strdata *olddata; + int len; + + if ( !m_data->refcount ) + return; + + olddata = m_data; + len = length(); + + m_data = new strdata; + + EnsureAlloced ( len + 1, false ); + strncpy ( m_data->data, olddata->data, len+1 ); + m_data->len = len; + + olddata->DelRef (); + } + +void idStr::EnsureAlloced (int amount, bool keepold) { + + if ( !m_data ) { + m_data = new strdata(); + } + + // Now, let's make sure it's writable + EnsureDataWritable (); + + char *newbuffer; + bool wasalloced = ( m_data->alloced != 0 ); + + if ( amount < m_data->alloced ) { + return; + } + + assert ( amount ); + if ( amount == 1 ) { + m_data->alloced = 1; + } else { + int newsize, mod; + mod = amount % STR_ALLOC_GRAN; + if ( !mod ) { + newsize = amount; + } else { + newsize = amount + STR_ALLOC_GRAN - mod; + } + m_data->alloced = newsize; + } + + newbuffer = new char[m_data->alloced]; + if ( wasalloced && keepold ) { + strcpy ( newbuffer, m_data->data ); + } + + if ( m_data->data ) { + delete [] m_data->data; + } + m_data->data = newbuffer; +} + +void idStr::BackSlashesToSlashes + ( + void + ) + + { + int i; + + EnsureDataWritable (); + + for ( i=0; i < m_data->len; i++ ) + { + if ( m_data->data[i] == '\\' ) + m_data->data[i] = '/'; + } + } + +void idStr::snprintf + ( + char *dst, + int size, + const char *fmt, + ... + ) + + { + char buffer[0x10000]; + int len; + va_list argptr; + + va_start (argptr,fmt); + len = vsprintf (buffer,fmt,argptr); + va_end (argptr); + + assert ( len < size ); + + strncpy (dst, buffer, size-1); + } + +#ifdef _WIN32 +#pragma warning(disable : 4189) // local variable is initialized but not referenced +#endif + +/* +================= +TestStringClass + +This is a fairly rigorous test of the idStr class's functionality. +Because of the fairly global and subtle ramifications of a bug occuring +in this class, it should be run after any changes to the class. +Add more tests as functionality is changed. Tests should include +any possible bounds violation and NULL data tests. +================= +*/ +void TestStringClass + ( + void + ) + + { + char ch; // ch == ? + idStr *t; // t == ? + idStr a; // a.len == 0, a.data == "\0" + idStr b; // b.len == 0, b.data == "\0" + idStr c( "test" ); // c.len == 4, c.data == "test\0" + idStr d( c ); // d.len == 4, d.data == "test\0" + idStr e( reinterpret_cast(NULL) ); + // e.len == 0, e.data == "\0" ASSERT! + int i; // i == ? + + i = a.length(); // i == 0 + i = c.length(); // i == 4 + + // TTimo: not used +// const char *s1 = a.c_str(); // s1 == "\0" +// const char *s2 = c.c_str(); // s2 == "test\0" + + t = new idStr(); // t->len == 0, t->data == "\0" + delete t; // t == ? + + b = "test"; // b.len == 4, b.data == "test\0" + t = new idStr( "test" ); // t->len == 4, t->data == "test\0" + delete t; // t == ? + + a = c; // a.len == 4, a.data == "test\0" +// a = ""; + a = NULL; // a.len == 0, a.data == "\0" ASSERT! + a = c + d; // a.len == 8, a.data == "testtest\0" + a = c + "wow"; // a.len == 7, a.data == "testwow\0" + a = c + reinterpret_cast(NULL); + // a.len == 4, a.data == "test\0" ASSERT! + a = "this" + d; // a.len == 8, a.data == "thistest\0" + a = reinterpret_cast(NULL) + d; + // a.len == 4, a.data == "test\0" ASSERT! + a += c; // a.len == 8, a.data == "testtest\0" + a += "wow"; // a.len == 11, a.data == "testtestwow\0" + a += reinterpret_cast(NULL); + // a.len == 11, a.data == "testtestwow\0" ASSERT! + + a = "test"; // a.len == 4, a.data == "test\0" + ch = a[ 0 ]; // ch == 't' + ch = a[ -1 ]; // ch == 0 ASSERT! + ch = a[ 1000 ]; // ch == 0 ASSERT! + ch = a[ 0 ]; // ch == 't' + ch = a[ 1 ]; // ch == 'e' + ch = a[ 2 ]; // ch == 's' + ch = a[ 3 ]; // ch == 't' + ch = a[ 4 ]; // ch == '\0' ASSERT! + ch = a[ 5 ]; // ch == '\0' ASSERT! + + a[ 1 ] = 'b'; // a.len == 4, a.data == "tbst\0" + a[ -1 ] = 'b'; // a.len == 4, a.data == "tbst\0" ASSERT! + a[ 0 ] = '0'; // a.len == 4, a.data == "0bst\0" + a[ 1 ] = '1'; // a.len == 4, a.data == "01st\0" + a[ 2 ] = '2'; // a.len == 4, a.data == "012t\0" + a[ 3 ] = '3'; // a.len == 4, a.data == "0123\0" + a[ 4 ] = '4'; // a.len == 4, a.data == "0123\0" ASSERT! + a[ 5 ] = '5'; // a.len == 4, a.data == "0123\0" ASSERT! + a[ 7 ] = '7'; // a.len == 4, a.data == "0123\0" ASSERT! + + a = "test"; // a.len == 4, a.data == "test\0" + b = "no"; // b.len == 2, b.data == "no\0" + + i = ( a == b ); // i == 0 + i = ( a == c ); // i == 1 + + i = ( a == "blow" ); // i == 0 + i = ( a == "test" ); // i == 1 + i = ( a == NULL ); // i == 0 ASSERT! + + i = ( "test" == b ); // i == 0 + i = ( "test" == a ); // i == 1 + i = ( NULL == a ); // i == 0 ASSERT! + + i = ( a != b ); // i == 1 + i = ( a != c ); // i == 0 + + i = ( a != "blow" ); // i == 1 + i = ( a != "test" ); // i == 0 + i = ( a != NULL ); // i == 1 ASSERT! + + i = ( "test" != b ); // i == 1 + i = ( "test" != a ); // i == 0 + i = ( NULL != a ); // i == 1 ASSERT! + + a = "test"; // a.data == "test" + b = a; // b.data == "test" + + a = "not"; // a.data == "not", b.data == "test" + + a = b; // a.data == b.data == "test" + + a += b; // a.data == "testtest", b.data = "test" + + a = b; + + a[1] = '1'; // a.data = "t1st", b.data = "test" + } + +#ifdef _WIN32 +#pragma warning(default : 4189) // local variable is initialized but not referenced +#pragma warning(disable : 4514) // unreferenced inline function has been removed +#endif diff --git a/CODE-mp/Splines/util_str.h b/CODE-mp/Splines/util_str.h new file mode 100644 index 0000000..0a6c00f --- /dev/null +++ b/CODE-mp/Splines/util_str.h @@ -0,0 +1,796 @@ +//need to rewrite this + +#ifndef __UTIL_STR_H__ +#define __UTIL_STR_H__ + +#include +#include +#include + +#ifdef _WIN32 +#pragma warning(disable : 4710) // function 'blah' not inlined +#endif + +void TestStringClass (); + +class strdata + { + public: + strdata () : len( 0 ), refcount ( 0 ), data ( NULL ), alloced ( 0 ) {} + ~strdata () + { + if ( data ) + delete [] data; + } + + void AddRef () { refcount++; } + bool DelRef () // True if killed + { + refcount--; + if ( refcount < 0 ) + { + delete this; + return true; + } + + return false; + } + + int len; + int refcount; + char *data; + int alloced; + }; + +class idStr { +protected: + strdata *m_data; + void EnsureAlloced ( int, bool keepold = true ); + void EnsureDataWritable (); + +public: + ~idStr(); + idStr(); + idStr( const char *text ); + idStr( const idStr& string ); + idStr( const idStr string, int start, int end ); + idStr( const char ch ); + idStr( const int num ); + idStr( const float num ); + idStr( const unsigned num ); + int length( void ) const; + int allocated( void ) const; + const char * c_str( void ) const; + + void append( const char *text ); + void append( const idStr& text ); + char operator[]( int index ) const; + char& operator[]( int index ); + + void operator=( const idStr& text ); + void operator=( const char *text ); + + friend idStr operator+( const idStr& a, const idStr& b ); + friend idStr operator+( const idStr& a, const char *b ); + friend idStr operator+( const char *a, const idStr& b ); + + friend idStr operator+( const idStr& a, const float b ); + friend idStr operator+( const idStr& a, const int b ); + friend idStr operator+( const idStr& a, const unsigned b ); + friend idStr operator+( const idStr& a, const bool b ); + friend idStr operator+( const idStr& a, const char b ); + + idStr& operator+=( const idStr& a ); + idStr& operator+=( const char *a ); + idStr& operator+=( const float a ); + idStr& operator+=( const char a ); + idStr& operator+=( const int a ); + idStr& operator+=( const unsigned a ); + idStr& operator+=( const bool a ); + + friend bool operator==( const idStr& a, const idStr& b ); + friend bool operator==( const idStr& a, const char *b ); + friend bool operator==( const char *a, const idStr& b ); + + friend bool operator!=( const idStr& a, const idStr& b ); + friend bool operator!=( const idStr& a, const char *b ); + friend bool operator!=( const char *a, const idStr& b ); + + operator const char * () const; + operator const char * (); + + int icmpn( const char *text, int n ) const; + int icmpn( const idStr& text, int n ) const; + int icmp( const char *text ) const; + int icmp( const idStr& text ) const; + int cmpn( const char *text, int n ) const; + int cmpn( const idStr& text, int n ) const; + int cmp( const char *text ) const; + int cmp( const idStr& text ) const; + + void tolower( void ); + void toupper( void ); + + static char *tolower( char *s1 ); + static char *toupper( char *s1 ); + + static int icmpn( const char *s1, const char *s2, int n ); + static int icmp( const char *s1, const char *s2 ); + static int cmpn( const char *s1, const char *s2, int n ); + static int cmp( const char *s1, const char *s2 ); + + static void snprintf ( char *dst, int size, const char *fmt, ... ); + + static bool isNumeric( const char *str ); + bool isNumeric( void ) const; + + void CapLength ( int ); + + void BackSlashesToSlashes (); + +}; + +inline idStr::~idStr() + { + if ( m_data ) + { + m_data->DelRef (); + m_data = NULL; + } + } + +inline idStr::idStr() : m_data ( NULL ) + { + EnsureAlloced ( 1 ); + m_data->data[ 0 ] = 0; + } + +inline idStr::idStr + ( + const char *text + ) : m_data ( NULL ) + + { + int len; + + assert( text ); + + if ( text ) + { + len = strlen( text ); + EnsureAlloced ( len + 1 ); + strcpy( m_data->data, text ); + m_data->len = len; + } + else + { + EnsureAlloced ( 1 ); + m_data->data[ 0 ] = 0; + m_data->len = 0; + } + } + +inline idStr::idStr + ( + const idStr& text + ) : m_data ( NULL ) + + { + m_data = text.m_data; + m_data->AddRef (); + } + +inline idStr::idStr + ( + const idStr text, + int start, + int end + ) : m_data ( NULL ) + + { + int i; + int len; + + if ( end > text.length() ) + { + end = text.length(); + } + + if ( start > text.length() ) + { + start = text.length(); + } + + len = end - start; + if ( len < 0 ) + { + len = 0; + } + + EnsureAlloced ( len + 1 ); + + for( i = 0; i < len; i++ ) + { + m_data->data[ i ] = text[ start + i ]; + } + + m_data->data[ len ] = 0; + m_data->len = len; + } + +inline idStr::idStr + ( + const char ch + ) : m_data ( NULL ) + + { + EnsureAlloced ( 2 ); + + m_data->data[ 0 ] = ch; + m_data->data[ 1 ] = 0; + m_data->len = 1; + } + +inline idStr::idStr + ( + const float num + ) : m_data ( NULL ) + + { + char text[ 32 ]; + int len; + + sprintf( text, "%.3f", num ); + len = strlen( text ); + EnsureAlloced( len + 1 ); + strcpy( m_data->data, text ); + m_data->len = len; + } + +inline idStr::idStr + ( + const int num + ) : m_data ( NULL ) + + { + char text[ 32 ]; + int len; + + sprintf( text, "%d", num ); + len = strlen( text ); + EnsureAlloced( len + 1 ); + strcpy( m_data->data, text ); + m_data->len = len; + } + +inline idStr::idStr + ( + const unsigned num + ) : m_data ( NULL ) + + { + char text[ 32 ]; + int len; + + sprintf( text, "%u", num ); + len = strlen( text ); + EnsureAlloced( len + 1 ); + strcpy( m_data->data, text ); + m_data->len = len; + } + +inline int idStr::length( void ) const + { + return ( m_data != NULL ) ? m_data->len : 0; + } + +inline int idStr::allocated( void ) const + { + return ( m_data != NULL ) ? m_data->alloced + sizeof( *m_data ) : 0; + } + +inline const char *idStr::c_str( void ) const + { + assert( m_data ); + + return m_data->data; + } + +inline void idStr::append + ( + const char *text + ) + + { + int len; + + assert( text ); + + if ( text ) + { + len = length() + strlen( text ); + EnsureAlloced( len + 1 ); + + strcat( m_data->data, text ); + m_data->len = len; + } + } + +inline void idStr::append + ( + const idStr& text + ) + + { + int len; + + len = length() + text.length(); + EnsureAlloced ( len + 1 ); + + strcat ( m_data->data, text.c_str () ); + m_data->len = len; + } + +inline char idStr::operator[]( int index ) const + { + assert ( m_data ); + + if ( !m_data ) + return 0; + + // don't include the '/0' in the test, because technically, it's out of bounds + assert( ( index >= 0 ) && ( index < m_data->len ) ); + + // In release mode, give them a null character + // don't include the '/0' in the test, because technically, it's out of bounds + if ( ( index < 0 ) || ( index >= m_data->len ) ) + { + return 0; + } + + return m_data->data[ index ]; + } + +inline char& idStr::operator[] + ( + int index + ) + + { + // Used for result for invalid indices + static char dummy = 0; + assert ( m_data ); + + // We don't know if they'll write to it or not + // if it's not a const object + EnsureDataWritable (); + + if ( !m_data ) + return dummy; + + // don't include the '/0' in the test, because technically, it's out of bounds + assert( ( index >= 0 ) && ( index < m_data->len ) ); + + // In release mode, let them change a safe variable + // don't include the '/0' in the test, because technically, it's out of bounds + if ( ( index < 0 ) || ( index >= m_data->len ) ) + { + return dummy; + } + + return m_data->data[ index ]; + } + +inline void idStr::operator= + ( + const idStr& text + ) + + { + // adding the reference before deleting our current reference prevents + // us from deleting our string if we are copying from ourself + text.m_data->AddRef(); + m_data->DelRef(); + m_data = text.m_data; + } + +inline void idStr::operator= + ( + const char *text + ) + + { + int len; + + assert( text ); + + if ( !text ) + { + // safe behaviour if NULL + EnsureAlloced ( 1, false ); + m_data->data[0] = 0; + m_data->len = 0; + return; + } + + if ( !m_data ) + { + len = strlen ( text ); + EnsureAlloced( len + 1, false ); + strcpy ( m_data->data, text ); + m_data->len = len; + return; + } + + if ( text == m_data->data ) + return; // Copying same thing. Punt. + + // If we alias and I don't do this, I could corrupt other strings... This + // will get called with EnsureAlloced anyway + EnsureDataWritable (); + + // Now we need to check if we're aliasing.. + if ( text >= m_data->data && text <= m_data->data + m_data->len ) + { + // Great, we're aliasing. We're copying from inside ourselves. + // This means that I don't have to ensure that anything is alloced, + // though I'll assert just in case. + int diff = text - m_data->data; + int i; + + assert ( strlen ( text ) < (unsigned) m_data->len ); + + for ( i = 0; text[i]; i++ ) + { + m_data->data[i] = text[i]; + } + + m_data->data[i] = 0; + + m_data->len -= diff; + + return; + } + + len = strlen( text ); + EnsureAlloced ( len + 1, false ); + strcpy( m_data->data, text ); + m_data->len = len; + } + +inline idStr operator+ + ( + const idStr& a, + const idStr& b + ) + + { + idStr result( a ); + + result.append( b ); + + return result; + } + +inline idStr operator+ + ( + const idStr& a, + const char *b + ) + + { + idStr result( a ); + + result.append( b ); + + return result; + } + +inline idStr operator+ + ( + const char *a, + const idStr& b + ) + + { + idStr result( a ); + + result.append( b ); + + return result; + } + +inline idStr operator+ + ( + const idStr& a, + const bool b + ) + + { + idStr result( a ); + + result.append( b ? "true" : "false" ); + + return result; + } + +inline idStr operator+ + ( + const idStr& a, + const char b + ) + + { + char text[ 2 ]; + + text[ 0 ] = b; + text[ 1 ] = 0; + + return a + text; + } + +inline idStr& idStr::operator+= + ( + const idStr& a + ) + + { + append( a ); + return *this; + } + +inline idStr& idStr::operator+= + ( + const char *a + ) + + { + append( a ); + return *this; + } + +inline idStr& idStr::operator+= + ( + const char a + ) + + { + char text[ 2 ]; + + text[ 0 ] = a; + text[ 1 ] = 0; + append( text ); + + return *this; + } + +inline idStr& idStr::operator+= + ( + const bool a + ) + + { + append( a ? "true" : "false" ); + return *this; + } + +inline bool operator== + ( + const idStr& a, + const idStr& b + ) + + { + return ( !strcmp( a.c_str(), b.c_str() ) ); + } + +inline bool operator== + ( + const idStr& a, + const char *b + ) + + { + assert( b ); + if ( !b ) + { + return false; + } + return ( !strcmp( a.c_str(), b ) ); + } + +inline bool operator== + ( + const char *a, + const idStr& b + ) + + { + assert( a ); + if ( !a ) + { + return false; + } + return ( !strcmp( a, b.c_str() ) ); + } + +inline bool operator!= + ( + const idStr& a, + const idStr& b + ) + + { + return !( a == b ); + } + +inline bool operator!= + ( + const idStr& a, + const char *b + ) + + { + return !( a == b ); + } + +inline bool operator!= + ( + const char *a, + const idStr& b + ) + + { + return !( a == b ); + } + +inline int idStr::icmpn + ( + const char *text, + int n + ) const + + { + assert( m_data ); + assert( text ); + + return idStr::icmpn( m_data->data, text, n ); + } + +inline int idStr::icmpn + ( + const idStr& text, + int n + ) const + + { + assert( m_data ); + assert( text.m_data ); + + return idStr::icmpn( m_data->data, text.m_data->data, n ); + } + +inline int idStr::icmp + ( + const char *text + ) const + + { + assert( m_data ); + assert( text ); + + return idStr::icmp( m_data->data, text ); + } + +inline int idStr::icmp + ( + const idStr& text + ) const + + { + assert( c_str () ); + assert( text.c_str () ); + + return idStr::icmp( c_str () , text.c_str () ); + } + +inline int idStr::cmp + ( + const char *text + ) const + + { + assert( m_data ); + assert( text ); + + return idStr::cmp( m_data->data, text ); + } + +inline int idStr::cmp + ( + const idStr& text + ) const + + { + assert( c_str () ); + assert( text.c_str () ); + + return idStr::cmp( c_str () , text.c_str () ); + } + +inline int idStr::cmpn + ( + const char *text, + int n + ) const + + { + assert( c_str () ); + assert( text ); + + return idStr::cmpn( c_str () , text, n ); + } + +inline int idStr::cmpn + ( + const idStr& text, + int n + ) const + + { + assert( c_str () ); + assert( text.c_str () ); + + return idStr::cmpn( c_str () , text.c_str () , n ); + } + +inline void idStr::tolower + ( + void + ) + + { + assert( m_data ); + + EnsureDataWritable (); + + idStr::tolower( m_data->data ); + } + +inline void idStr::toupper + ( + void + ) + + { + assert( m_data ); + + EnsureDataWritable (); + + idStr::toupper( m_data->data ); + } + +inline bool idStr::isNumeric + ( + void + ) const + + { + assert( m_data ); + return idStr::isNumeric( m_data->data ); + } + +inline idStr::operator const char *() { + return c_str(); +} + +inline idStr::operator const char * + ( + void + ) const + + { + return c_str (); + } + +#endif \ No newline at end of file diff --git a/CODE-mp/Splines/vssver.scc b/CODE-mp/Splines/vssver.scc new file mode 100644 index 0000000..04239f0 Binary files /dev/null and b/CODE-mp/Splines/vssver.scc differ diff --git a/CODE-mp/WinDed.dsp b/CODE-mp/WinDed.dsp new file mode 100644 index 0000000..9d25ba2 --- /dev/null +++ b/CODE-mp/WinDed.dsp @@ -0,0 +1,811 @@ +# Microsoft Developer Studio Project File - Name="WinDed" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=WinDed - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "WinDed.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "WinDed.mak" CFG="WinDed - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "WinDed - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "WinDed - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/General/code", EAAAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "WinDed - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEDICATED" /D "BOTLIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib Winmm.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "WinDed - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEDICATED" /D "_JK2" /D "BOTLIB" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib Winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "WinDed - Win32 Release" +# Name "WinDed - Win32 Debug" +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\qcommon\chash.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_load.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_local.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_patch.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_patch.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_polylib.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_polylib.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_public.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_test.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_trace.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cmd.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\CNetProfile.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\common.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cvar.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\disablewarnings.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\files.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\game_version.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\GenericParser2.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\GenericParser2.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\hstring.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\hstring.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\huffman.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\INetProfile.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\md4.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\MiniHeap.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\msg.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\net_chan.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\q_math.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\q_shared.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\qcommon.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\qfiles.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\RoffSystem.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\RoffSystem.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\sstring.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\strip.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\strip.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\tags.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\unzip.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\unzip.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\vm.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\vm_interpreted.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\vm_local.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\vm_x86.cpp +# End Source File +# End Group +# Begin Group "Ghoul2" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\ghoul2\G2.h +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_API.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_bolts.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_bones.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_gore.h +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_local.h +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_misc.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_surfaces.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\ghoul2_shared.h +# End Source File +# End Group +# Begin Group "Server" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\server\server.h +# End Source File +# Begin Source File + +SOURCE=.\server\sv_bot.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_ccmds.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_client.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_game.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_init.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_net_chan.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_snapshot.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_world.cpp +# End Source File +# End Group +# Begin Group "Null" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\null\null_client.cpp +# End Source File +# Begin Source File + +SOURCE=.\null\null_glimp.cpp +# End Source File +# Begin Source File + +SOURCE=.\null\null_input.cpp +# End Source File +# Begin Source File + +SOURCE=.\null\null_renderer.cpp +# End Source File +# Begin Source File + +SOURCE=.\null\null_snddma.cpp +# End Source File +# Begin Source File + +SOURCE=.\null\win_main.cpp +# End Source File +# End Group +# Begin Group "Renderer" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\renderer\matcomp.c +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_backend.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_ghoul2.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_image.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_init.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_mesh.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_model.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_shader.cpp +# End Source File +# End Group +# Begin Group "Win32" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\win32\win_net.cpp +# End Source File +# Begin Source File + +SOURCE=.\win32\win_shared.cpp +# End Source File +# End Group +# Begin Group "botlib" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\botlib\aasfile.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_bsp.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_bspq3.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_cluster.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_cluster.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_debug.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_debug.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_def.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_entity.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_entity.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_file.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_file.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_funcs.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_main.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_move.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_move.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_optimize.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_optimize.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_reach.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_reach.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_route.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_route.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_routealt.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_routealt.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_sample.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_sample.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_char.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_chat.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_gen.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_goal.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_move.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_weap.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_weight.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_weight.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ea.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_interface.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_interface.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_crc.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_crc.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_libvar.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_libvar.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_log.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_log.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_memory.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_memory.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_precomp.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_precomp.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_script.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_script.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_struct.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_struct.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_utils.h +# End Source File +# End Group +# Begin Group "headers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\game\anims.h +# End Source File +# Begin Source File + +SOURCE=.\game\be_aas.h +# End Source File +# Begin Source File + +SOURCE=.\game\be_ai_char.h +# End Source File +# Begin Source File + +SOURCE=.\game\be_ai_chat.h +# End Source File +# Begin Source File + +SOURCE=.\game\be_ai_gen.h +# End Source File +# Begin Source File + +SOURCE=.\game\be_ai_goal.h +# End Source File +# Begin Source File + +SOURCE=.\game\be_ai_move.h +# End Source File +# Begin Source File + +SOURCE=.\game\be_ai_weap.h +# End Source File +# Begin Source File + +SOURCE=.\game\be_ea.h +# End Source File +# Begin Source File + +SOURCE=.\game\bg_public.h +# End Source File +# Begin Source File + +SOURCE=.\game\bg_weapons.h +# End Source File +# Begin Source File + +SOURCE=.\game\botlib.h +# End Source File +# Begin Source File + +SOURCE=.\cgame\cg_public.h +# End Source File +# Begin Source File + +SOURCE=.\client\client.h +# End Source File +# Begin Source File + +SOURCE=.\encryption\encryption.h +# End Source File +# Begin Source File + +SOURCE=.\game\g_public.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\glext.h +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jconfig.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jerror.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jmorecfg.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jpegint.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jpeglib.h" +# End Source File +# Begin Source File + +SOURCE=.\ui\keycodes.h +# End Source File +# Begin Source File + +SOURCE=.\client\keys.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\matcomp.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\mdx_format.h +# End Source File +# Begin Source File + +SOURCE=.\png\png.h +# End Source File +# Begin Source File + +SOURCE=.\game\q_math.c +# End Source File +# Begin Source File + +SOURCE=.\game\q_shared.c +# End Source File +# Begin Source File + +SOURCE=.\game\q_shared.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\qgl.h +# End Source File +# Begin Source File + +SOURCE=.\client\snd_public.h +# End Source File +# Begin Source File + +SOURCE=.\strings\str_server.h +# End Source File +# Begin Source File + +SOURCE=.\game\surfaceflags.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_font.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_local.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_public.h +# End Source File +# Begin Source File + +SOURCE=.\cgame\tr_types.h +# End Source File +# Begin Source File + +SOURCE=.\ui\ui_public.h +# End Source File +# Begin Source File + +SOURCE=.\win32\win_local.h +# End Source File +# End Group +# End Target +# End Project diff --git a/CODE-mp/WinDed.plg b/CODE-mp/WinDed.plg new file mode 100644 index 0000000..c4fac35 --- /dev/null +++ b/CODE-mp/WinDed.plg @@ -0,0 +1,119 @@ + + +
+

Build Log

+

+--------------------Configuration: WinDed - Win32 Debug-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSPB2B.tmp" with contents +[ +/nologo /MLd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEDICATED" /D "_JK2" /D "BOTLIB" /Fo"Debug/" /Fd"Debug/" /FD /GZ /c +"C:\projects\jk2\CODE-mp\null\null_glimp.cpp" +"C:\projects\jk2\CODE-mp\null\null_renderer.cpp" +"C:\projects\jk2\CODE-mp\null\null_snddma.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSPB2B.tmp" +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSPB2C.tmp" with contents +[ +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib Winmm.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug/WinDed.pdb" /debug /machine:I386 /out:"Debug/WinDed.exe" /pdbtype:sept +".\Debug\cm_load.obj" +".\Debug\cm_patch.obj" +".\Debug\cm_polylib.obj" +".\Debug\cm_test.obj" +".\Debug\cm_trace.obj" +".\Debug\cmd.obj" +".\Debug\CNetProfile.obj" +".\Debug\common.obj" +".\Debug\cvar.obj" +".\Debug\files.obj" +".\Debug\GenericParser2.obj" +".\Debug\hstring.obj" +".\Debug\huffman.obj" +".\Debug\md4.obj" +".\Debug\msg.obj" +".\Debug\net_chan.obj" +".\Debug\q_math.obj" +".\Debug\q_shared.obj" +".\Debug\RoffSystem.obj" +".\Debug\strip.obj" +".\Debug\unzip.obj" +".\Debug\vm.obj" +".\Debug\vm_interpreted.obj" +".\Debug\vm_x86.obj" +".\Debug\G2_API.obj" +".\Debug\G2_bolts.obj" +".\Debug\G2_bones.obj" +".\Debug\G2_misc.obj" +".\Debug\G2_surfaces.obj" +".\Debug\sv_bot.obj" +".\Debug\sv_ccmds.obj" +".\Debug\sv_client.obj" +".\Debug\sv_game.obj" +".\Debug\sv_init.obj" +".\Debug\sv_main.obj" +".\Debug\sv_net_chan.obj" +".\Debug\sv_snapshot.obj" +".\Debug\sv_world.obj" +".\Debug\null_client.obj" +".\Debug\null_glimp.obj" +".\Debug\null_input.obj" +".\Debug\null_renderer.obj" +".\Debug\null_snddma.obj" +".\Debug\win_main.obj" +".\Debug\matcomp.obj" +".\Debug\tr_backend.obj" +".\Debug\tr_ghoul2.obj" +".\Debug\tr_image.obj" +".\Debug\tr_init.obj" +".\Debug\tr_main.obj" +".\Debug\tr_mesh.obj" +".\Debug\tr_model.obj" +".\Debug\tr_shader.obj" +".\Debug\win_net.obj" +".\Debug\win_shared.obj" +".\Debug\be_aas_bspq3.obj" +".\Debug\be_aas_cluster.obj" +".\Debug\be_aas_debug.obj" +".\Debug\be_aas_entity.obj" +".\Debug\be_aas_file.obj" +".\Debug\be_aas_main.obj" +".\Debug\be_aas_move.obj" +".\Debug\be_aas_optimize.obj" +".\Debug\be_aas_reach.obj" +".\Debug\be_aas_route.obj" +".\Debug\be_aas_routealt.obj" +".\Debug\be_aas_sample.obj" +".\Debug\be_ai_char.obj" +".\Debug\be_ai_chat.obj" +".\Debug\be_ai_gen.obj" +".\Debug\be_ai_goal.obj" +".\Debug\be_ai_move.obj" +".\Debug\be_ai_weap.obj" +".\Debug\be_ai_weight.obj" +".\Debug\be_ea.obj" +".\Debug\be_interface.obj" +".\Debug\l_crc.obj" +".\Debug\l_libvar.obj" +".\Debug\l_log.obj" +".\Debug\l_memory.obj" +".\Debug\l_precomp.obj" +".\Debug\l_script.obj" +".\Debug\l_struct.obj" +] +Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSPB2C.tmp" +

Output Window

+Compiling... +null_glimp.cpp +null_renderer.cpp +null_snddma.cpp +Generating Code... +Linking... + + + +

Results

+WinDed.exe - 0 error(s), 0 warning(s) +
+ + diff --git a/CODE-mp/botlib/be_aas_def.h b/CODE-mp/botlib/be_aas_def.h index 378df12..ba8b340 100644 --- a/CODE-mp/botlib/be_aas_def.h +++ b/CODE-mp/botlib/be_aas_def.h @@ -16,7 +16,7 @@ #define AAS_DEBUG // these are also in q_shared.h - argh (rjr) -#define MAX_CLIENTS 64 +#define MAX_CLIENTS 32 #define MAX_MODELS 256 // these are sent over the net as 8 bits #define MAX_SOUNDS 256 // so they cannot be blindly increased diff --git a/CODE-mp/botlib/l_script.cpp b/CODE-mp/botlib/l_script.cpp index 599793b..fa8cc93 100644 --- a/CODE-mp/botlib/l_script.cpp +++ b/CODE-mp/botlib/l_script.cpp @@ -885,7 +885,7 @@ int PS_ReadToken(script_t *script, token_t *token) //if there is a name else if ((*script->script_p >= 'a' && *script->script_p <= 'z') || (*script->script_p >= 'A' && *script->script_p <= 'Z') || - *script->script_p == '_') + *script->script_p == '_' || *script->script_p == '@') { if (!PS_ReadName(script, token)) return 0; } //end if diff --git a/CODE-mp/botlib/mssccprj.scc b/CODE-mp/botlib/mssccprj.scc new file mode 100644 index 0000000..122048b --- /dev/null +++ b/CODE-mp/botlib/mssccprj.scc @@ -0,0 +1,5 @@ +SCC = This is a Source Code Control file + +[botlib.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\jk2sof2MP" +SCC_Project_Name = "$/General/code/botlib", ACAAAAAA diff --git a/CODE-mp/botlib/vssver.scc b/CODE-mp/botlib/vssver.scc new file mode 100644 index 0000000..6f32c47 Binary files /dev/null and b/CODE-mp/botlib/vssver.scc differ diff --git a/CODE-mp/buildvms.bat b/CODE-mp/buildvms.bat new file mode 100644 index 0000000..00d402b --- /dev/null +++ b/CODE-mp/buildvms.bat @@ -0,0 +1,8 @@ +set include= +cd game +call game +cd ..\cgame +call cgame +cd ..\ui +call ui +cd .. diff --git a/CODE-mp/cgame/JK2_cgame.def b/CODE-mp/cgame/JK2_cgame.def new file mode 100644 index 0000000..01861ba --- /dev/null +++ b/CODE-mp/cgame/JK2_cgame.def @@ -0,0 +1,3 @@ +EXPORTS + vmMain + dllEntry diff --git a/CODE-mp/cgame/JK2_cgame.plg b/CODE-mp/cgame/JK2_cgame.plg new file mode 100644 index 0000000..c6da4a7 --- /dev/null +++ b/CODE-mp/cgame/JK2_cgame.plg @@ -0,0 +1,150 @@ + + +
+

Build Log

+

+--------------------Configuration: JK2cgame - Win32 Final JK2-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP31.tmp" with contents +[ +/nologo /G6 /ML /W4 /GX /O2 /I ".." /I "./../game" /D "NDEBUG" /D "_WINDOWS" /D "MISSIONPACK" /D "WIN32" /D "_JK2" /D "FINAL_BUILD" /Fp"../Final/JK2cgame/JK2_cgame.pch" /YX /Fo"../Final/JK2cgame/" /Fd"../Final/JK2cgame/" /FD /c +"C:\projects\jk2\CODE-mp\game\bg_misc.c" +"C:\projects\jk2\CODE-mp\game\bg_panimate.c" +"C:\projects\jk2\CODE-mp\game\bg_pmove.c" +"C:\projects\jk2\CODE-mp\game\bg_saber.c" +"C:\projects\jk2\CODE-mp\game\bg_slidemove.c" +"C:\projects\jk2\CODE-mp\game\bg_weapons.c" +"C:\projects\jk2\CODE-mp\cgame\cg_consolecmds.c" +"C:\projects\jk2\CODE-mp\cgame\cg_draw.c" +"C:\projects\jk2\CODE-mp\cgame\cg_drawtools.c" +"C:\projects\jk2\CODE-mp\cgame\cg_effects.c" +"C:\projects\jk2\CODE-mp\cgame\cg_ents.c" +"C:\projects\jk2\CODE-mp\cgame\cg_event.c" +"C:\projects\jk2\CODE-mp\cgame\cg_info.c" +"C:\projects\jk2\CODE-mp\cgame\cg_light.c" +"C:\projects\jk2\CODE-mp\cgame\cg_localents.c" +"C:\projects\jk2\CODE-mp\cgame\cg_main.c" +"C:\projects\jk2\CODE-mp\cgame\cg_marks.c" +"C:\projects\jk2\CODE-mp\cgame\cg_newDraw.c" +"C:\projects\jk2\CODE-mp\cgame\cg_players.c" +"C:\projects\jk2\CODE-mp\cgame\cg_playerstate.c" +"C:\projects\jk2\CODE-mp\cgame\cg_predict.c" +"C:\projects\jk2\CODE-mp\cgame\cg_saga.c" +"C:\projects\jk2\CODE-mp\cgame\cg_scoreboard.c" +"C:\projects\jk2\CODE-mp\cgame\cg_servercmds.c" +"C:\projects\jk2\CODE-mp\cgame\cg_snapshot.c" +"C:\projects\jk2\CODE-mp\cgame\cg_syscalls.c" +"C:\projects\jk2\CODE-mp\cgame\cg_turret.c" +"C:\projects\jk2\CODE-mp\cgame\cg_view.c" +"C:\projects\jk2\CODE-mp\cgame\cg_weaponinit.c" +"C:\projects\jk2\CODE-mp\cgame\cg_weapons.c" +"C:\projects\jk2\CODE-mp\cgame\fx_blaster.c" +"C:\projects\jk2\CODE-mp\cgame\fx_bowcaster.c" +"C:\projects\jk2\CODE-mp\cgame\fx_bryarpistol.c" +"C:\projects\jk2\CODE-mp\cgame\fx_demp2.c" +"C:\projects\jk2\CODE-mp\cgame\fx_disruptor.c" +"C:\projects\jk2\CODE-mp\cgame\fx_flechette.c" +"C:\projects\jk2\CODE-mp\cgame\fx_force.c" +"C:\projects\jk2\CODE-mp\cgame\fx_heavyrepeater.c" +"C:\projects\jk2\CODE-mp\cgame\fx_rocketlauncher.c" +] +Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP31.tmp" +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP32.tmp" with contents +[ +/nologo /base:"0x30000000" /subsystem:windows /dll /incremental:no /pdb:"../Final/cgamex86.pdb" /map:"../Final/JK2cgame/cgamex86.map" /machine:I386 /def:".\JK2_cgame.def" /out:"../Final/cgamex86.dll" /implib:"../Final/cgamex86.lib" +"\projects\jk2\CODE-mp\Final\JK2cgame\bg_misc.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\bg_panimate.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\bg_pmove.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\bg_saber.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\bg_slidemove.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\bg_weapons.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_consolecmds.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_draw.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_drawtools.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_effects.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_ents.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_event.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_info.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_light.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_localents.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_main.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_marks.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_newDraw.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_players.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_playerstate.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_predict.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_saga.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_scoreboard.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_servercmds.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_snapshot.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_syscalls.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_turret.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_view.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_weaponinit.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\cg_weapons.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\fx_blaster.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\fx_bowcaster.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\fx_bryarpistol.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\fx_demp2.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\fx_disruptor.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\fx_flechette.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\fx_force.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\fx_heavyrepeater.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\fx_rocketlauncher.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\q_math.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\q_shared.obj" +"\projects\jk2\CODE-mp\Final\JK2cgame\ui_shared.obj" +] +Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP32.tmp" +

Output Window

+Compiling... +bg_misc.c +bg_panimate.c +bg_pmove.c +bg_saber.c +bg_slidemove.c +bg_weapons.c +cg_consolecmds.c +cg_draw.c +cg_drawtools.c +cg_effects.c +cg_ents.c +cg_event.c +cg_info.c +cg_light.c +cg_localents.c +cg_main.c +cg_marks.c +cg_newDraw.c +cg_players.c +cg_playerstate.c +cg_predict.c +cg_saga.c +cg_scoreboard.c +cg_servercmds.c +cg_snapshot.c +cg_syscalls.c +cg_turret.c +cg_view.c +cg_weaponinit.c +cg_weapons.c +fx_blaster.c +fx_bowcaster.c +fx_bryarpistol.c +fx_demp2.c +fx_disruptor.c +fx_flechette.c +fx_force.c +fx_heavyrepeater.c +fx_rocketlauncher.c +Linking... + Creating library ../Final/cgamex86.lib and object ../Final/cgamex86.exp + + + +

Results

+cgamex86.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/CODE-mp/cgame/animtable.h b/CODE-mp/cgame/animtable.h index f0b7a9d..8810019 100644 --- a/CODE-mp/cgame/animtable.h +++ b/CODE-mp/cgame/animtable.h @@ -1231,7 +1231,6 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(FACE_SMILE), //# ENUM2STRING(FACE_FROWN), //# ENUM2STRING(FACE_DEAD), //# - ENUM2STRING(FACE_GALAK), //# This has to be last for Galak Mech to talk //must be terminated NULL,-1 diff --git a/CODE-mp/cgame/cg_consolecmds.c b/CODE-mp/cgame/cg_consolecmds.c index eaaae63..3f1f386 100644 --- a/CODE-mp/cgame/cg_consolecmds.c +++ b/CODE-mp/cgame/cg_consolecmds.c @@ -411,11 +411,8 @@ static consoleCommand_t commands[] = { { "nextskin", CG_TestModelNextSkin_f }, { "prevskin", CG_TestModelPrevSkin_f }, { "viewpos", CG_Viewpos_f }, - { "datapad", CG_ScoresDown_f }, //SP compatibility for default.cfg { "+scores", CG_ScoresDown_f }, { "-scores", CG_ScoresUp_f }, -// { "+zoom", CG_ZoomDown_f }, -// { "-zoom", CG_ZoomUp_f }, { "sizeup", CG_SizeUp_f }, { "sizedown", CG_SizeDown_f }, { "weapnext", CG_NextWeapon_f }, diff --git a/CODE-mp/cgame/cg_draw.c b/CODE-mp/cgame/cg_draw.c index 08d0202..3df5c33 100644 --- a/CODE-mp/cgame/cg_draw.c +++ b/CODE-mp/cgame/cg_draw.c @@ -30,24 +30,24 @@ char teamChat2[256]; char *showPowersName[] = { - "Heal",//FP_HEAL - "Jump",//FP_LEVITATION - "Speed",//FP_SPEED - "Push",//FP_PUSH - "Pull",//FP_PULL - "Mind Trick",//FP_TELEPTAHY - "Grip",//FP_GRIP - "Lightning",//FP_LIGHTNING - "Dark Rage",//FP_RAGE - "Protect",//FP_PROTECT - "Absorb",//FP_ABSORB - "Team Heal",//FP_TEAM_HEAL - "Team Replenish",//FP_TEAM_FORCE - "Drain",//FP_DRAIN - "Sight",//FP_SEE - "Saber Attack",//FP_SABERATTACK - "Saber Defend",//FP_SABERDEFEND - "Saber Throw",//FP_SABERTHROW + "HEAL2",//FP_HEAL + "JUMP2",//FP_LEVITATION + "SPEED2",//FP_SPEED + "PUSH2",//FP_PUSH + "PULL2",//FP_PULL + "MINDTRICK2",//FP_TELEPTAHY + "GRIP2",//FP_GRIP + "LIGHTNING2",//FP_LIGHTNING + "DARK_RAGE2",//FP_RAGE + "PROTECT2",//FP_PROTECT + "ABSORB2",//FP_ABSORB + "TEAM_HEAL2",//FP_TEAM_HEAL + "TEAM_REPLENISH2",//FP_TEAM_FORCE + "DRAIN2",//FP_DRAIN + "SEEING2",//FP_SEE + "SABER_OFFENSE2",//FP_SABERATTACK + "SABER_DEFENSE2",//FP_SABERDEFEND + "SABER_THROW2",//FP_SABERTHROW NULL }; @@ -1055,6 +1055,53 @@ CG_DrawHUD void CG_DrawHUD(centity_t *cent) { menuDef_t *menuHUD = NULL; + const char *scoreStr = NULL; + int scoreBias; + char scoreBiasStr[16]; + + if (cg_hudFiles.integer) + { + int x = 0; + int y = SCREEN_HEIGHT-80; + char ammoString[64]; + int weapX = x; + + UI_DrawProportionalString( x+16, y+40, va( "%i", cg.snap->ps.stats[STAT_HEALTH] ), + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_HUD_RED] ); + + UI_DrawProportionalString( x+18+14, y+40+14, va( "%i", cg.snap->ps.stats[STAT_ARMOR] ), + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_HUD_GREEN] ); + + if (cg.snap->ps.weapon == WP_SABER) + { + if (cg.snap->ps.fd.saberDrawAnimLevel == FORCE_LEVEL_3) + { + Com_sprintf(ammoString, sizeof(ammoString), "STRONG"); + weapX += 16; + } + else if (cg.snap->ps.fd.saberDrawAnimLevel == FORCE_LEVEL_2) + { + Com_sprintf(ammoString, sizeof(ammoString), "MEDIUM"); + weapX += 16; + } + else + { + Com_sprintf(ammoString, sizeof(ammoString), "FAST"); + } + } + else + { + Com_sprintf(ammoString, sizeof(ammoString), "%i", cg.snap->ps.ammo[weaponData[cent->currentState.weapon].ammoIndex]); + } + + UI_DrawProportionalString( SCREEN_WIDTH-(weapX+16+32), y+40, va( "%s", ammoString ), + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_HUD_ORANGE] ); + + UI_DrawProportionalString( SCREEN_WIDTH-(x+18+14+32), y+40+14, va( "%i", cg.snap->ps.fd.forcePower), + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_ICON_BLUE] ); + + return; + } if (cgs.gametype >= GT_TEAM) { // tint the hud items based on team @@ -1086,6 +1133,41 @@ void CG_DrawHUD(centity_t *cent) CG_DrawHUDLeftFrame2(0,SCREEN_HEIGHT-80); } + //scoreStr = va("Score: %i", cgs.clientinfo[cg.snap->ps.clientNum].score); + if (0 && cgs.gametype < GT_TEAM ) + { // This is a teamless mode, draw the score bias. + scoreBias = cg.snap->ps.persistant[PERS_SCORE] - cgs.scores1; + if (scoreBias == 0) + { // We are the leader! + if (cgs.scores2 <= 0) + { // Nobody to be ahead of yet. + Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), ""); + } + else + { + scoreBias = cg.snap->ps.persistant[PERS_SCORE] - cgs.scores2; + if (scoreBias == 0) + { + Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), " (Tie)"); + } + else + { + Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), " (+%d)", scoreBias); + } + } + } + else // if (scoreBias < 0) + { // We are behind! + Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), " (%d)", scoreBias); + } + scoreStr = va("Score: %i%s", cg.snap->ps.persistant[PERS_SCORE], scoreBiasStr); + } + else + { // Don't draw a bias. + scoreStr = va("Score: %i", cg.snap->ps.persistant[PERS_SCORE]); + } + UI_DrawScaledProportionalString(SCREEN_WIDTH-124/*(strlen(scoreStr)*20.5)*/, SCREEN_HEIGHT-23, scoreStr, UI_RIGHT|UI_DROPSHADOW, colorTable[CT_WHITE], 0.7); + menuHUD = Menus_FindByName("righthud"); if (menuHUD) { @@ -1276,7 +1358,7 @@ void CG_DrawForceSelect( void ) if ( showPowersName[cg.forceSelect] ) { - UI_DrawProportionalString(320, y + 33, showPowersName[cg.forceSelect], UI_CENTER | UI_SMALLFONT, colorTable[CT_ICON_BLUE]); + UI_DrawProportionalString(320, y + 30, CG_GetStripEdString("INGAME", showPowersName[cg.forceSelect]), UI_CENTER | UI_SMALLFONT, colorTable[CT_ICON_BLUE]); } } @@ -1408,6 +1490,7 @@ void CG_DrawInvenSelect( void ) height = bigIconSize * cg.iconHUDPercent; if (cgs.media.invenIcons[cg.itemSelect]) { + int itemNdex; trap_R_SetColor(NULL); CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2))+10, bigIconSize, bigIconSize, cgs.media.invenIcons[cg.itemSelect] ); addX = (float) bigIconSize * .75; @@ -1415,11 +1498,20 @@ void CG_DrawInvenSelect( void ) /*CG_DrawNumField ((x-(bigIconSize/2)) + addX, y, 2, cg.snap->ps.inventory[cg.inventorySelect], 6, 12, NUM_FONT_SMALL,qfalse);*/ - if (bg_itemlist[BG_GetItemIndexByTag(cg.itemSelect, IT_HOLDABLE)].pickup_name) + itemNdex = BG_GetItemIndexByTag(cg.itemSelect, IT_HOLDABLE); + if (bg_itemlist[itemNdex].classname) { - vec4_t textColor = { .312f, .75f, .621f, 1.0f }; - - UI_DrawProportionalString(320, y+48, bg_itemlist[BG_GetItemIndexByTag(cg.itemSelect, IT_HOLDABLE)].pickup_name, UI_CENTER | UI_SMALLFONT, textColor); + vec4_t textColor = { .312f, .75f, .621f, 1.0f }; + char text[1024]; + + if ( trap_SP_GetStringTextString( va("INGAME_%s",bg_itemlist[itemNdex].classname), text, sizeof( text ))) + { + UI_DrawProportionalString(320, y+45, text, UI_CENTER | UI_SMALLFONT, textColor); + } + else + { + UI_DrawProportionalString(320, y+45, bg_itemlist[itemNdex].classname, UI_CENTER | UI_SMALLFONT, textColor); + } } } @@ -1514,17 +1606,19 @@ void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team ) hcolor[3] = alpha; if ( team == TEAM_RED ) { hcolor[0] = 1; - hcolor[1] = 0; - hcolor[2] = 0; + hcolor[1] = .2f; + hcolor[2] = .2f; } else if ( team == TEAM_BLUE ) { - hcolor[0] = 0; - hcolor[1] = 0; + hcolor[0] = .2f; + hcolor[1] = .2f; hcolor[2] = 1; } else { return; } - trap_R_SetColor( hcolor ); - CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar ); +// trap_R_SetColor( hcolor ); + + CG_FillRect ( x, y, w, h, hcolor ); +// CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar ); trap_R_SetColor( NULL ); } @@ -1558,17 +1652,22 @@ static float CG_DrawMiniScoreboard ( float y ) Q_strcat ( temp, MAX_QPATH, " Blue: " ); Q_strcat ( temp, MAX_QPATH, cgs.scores2==SCORE_NOT_PRESENT?"-":(va("%i",cgs.scores2)) ); - CG_Text_Paint( 630 - CG_Text_Width ( temp, 0.75f, FONT_SMALL ), y, 0.75f, colorWhite, temp, 0, 0, 0, FONT_SMALL ); + CG_Text_Paint( 630 - CG_Text_Width ( temp, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, temp, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM ); y += 15; } else { + /* strcpy ( temp, "1st: " ); Q_strcat ( temp, MAX_QPATH, cgs.scores1==SCORE_NOT_PRESENT?"-":(va("%i",cgs.scores1)) ); + Q_strcat ( temp, MAX_QPATH, " 2nd: " ); Q_strcat ( temp, MAX_QPATH, cgs.scores2==SCORE_NOT_PRESENT?"-":(va("%i",cgs.scores2)) ); - CG_Text_Paint( 630 - CG_Text_Width ( temp, 0.75f, FONT_SMALL ), y, 0.75f, colorWhite, temp, 0, 0, 0, FONT_SMALL ); + + CG_Text_Paint( 630 - CG_Text_Width ( temp, 0.7f, FONT_SMALL ), y, 0.7f, colorWhite, temp, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM ); y += 15; + */ + //rww - no longer doing this. Since the attacker now shows who is first, we print the score there. } @@ -1599,21 +1698,60 @@ static float CG_DrawEnemyInfo ( float y ) if ( cgs.gametype == GT_JEDIMASTER ) { - title = "Jedi Master"; + //title = "Jedi Master"; + title = CG_GetStripEdString("INGAMETEXT", "MASTERY7"); clientNum = cgs.jediMaster; if ( clientNum < 0 ) { - return y; + //return y; +// title = "Get Saber!"; + title = CG_GetStripEdString("INGAMETEXT", "GET_SABER"); + + + size = ICON_SIZE * 1.25; + y += 5; + + CG_DrawPic( 640 - size - 12, y, size, size, cgs.media.weaponIcons[WP_SABER] ); + + y += size; + + /* + CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, ci->name, 0, 0, 0, FONT_MEDIUM ); + y += 15; + */ + + CG_Text_Paint( 630 - CG_Text_Width ( title, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, title, 0, 0, 0, FONT_MEDIUM ); + + return y + BIGCHAR_HEIGHT + 2; } } else if ( cg.snap->ps.duelInProgress ) { - title = "Dueling"; +// title = "Dueling"; + title = CG_GetStripEdString("INGAMETEXT", "DUELING"); clientNum = cg.snap->ps.duelIndex; } + else if ( cgs.gametype == GT_TOURNAMENT && cgs.clientinfo[cg.snap->ps.clientNum].team != TEAM_SPECTATOR) + { +// title = "Dueling"; + title = CG_GetStripEdString("INGAMETEXT", "DUELING"); + if (cg.snap->ps.clientNum == cgs.duelist1) + { + clientNum = cgs.duelist2; + } + else if (cg.snap->ps.clientNum == cgs.duelist2) + { + clientNum = cgs.duelist1; + } + else + { + return y; + } + } else { + /* title = "Attacker"; clientNum = cg.predictedPlayerState.persistant[PERS_ATTACKER]; @@ -1627,10 +1765,36 @@ static float CG_DrawEnemyInfo ( float y ) cg.attackerTime = 0; return y; } + */ + //As of current, we don't want to draw the attacker. Instead, draw whoever is in first place. + if (cgs.duelWinner < 0 || cgs.duelWinner >= MAX_CLIENTS) + { + return y; + } + + + title = va("%s: %i",CG_GetStripEdString("INGAMETEXT", "LEADER"), cgs.scores1); + + /* + if (cgs.scores1 == 1) + { + title = va("%i kill", cgs.scores1); + } + else + { + title = va("%i kills", cgs.scores1); + } + */ + clientNum = cgs.duelWinner; } ci = &cgs.clientinfo[ clientNum ]; + if (!ci || !ci->modelIcon) + { + return y; + } + size = ICON_SIZE * 1.25; y += 5; @@ -1638,10 +1802,10 @@ static float CG_DrawEnemyInfo ( float y ) y += size; - CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 0.75f, FONT_SMALL ), y, 0.75f, colorWhite, ci->name, 0, 0, 0, FONT_SMALL ); + CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, ci->name, 0, 0, 0, FONT_MEDIUM ); y += 15; - CG_Text_Paint( 630 - CG_Text_Width ( title, 0.75f, FONT_SMALL ), y, 0.75f, colorWhite, title, 0, 0, 0, FONT_SMALL ); + CG_Text_Paint( 630 - CG_Text_Width ( title, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, title, 0, 0, 0, FONT_MEDIUM ); return y + BIGCHAR_HEIGHT + 2; } @@ -1910,6 +2074,63 @@ static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) { } +static void CG_DrawPowerupIcons(int y) +{ + int j; + int ico_size = 64; + //int y = ico_size/2; + gitem_t *item; + + if (!cg.snap) + { + return; + } + + y += 16; + + for (j = 0; j <= PW_NUM_POWERUPS; j++) + { + if (cg.snap->ps.powerups[j] > cg.time) + { + int secondsleft = (cg.snap->ps.powerups[j] - cg.time)/1000; + + item = BG_FindItemForPowerup( j ); + + if (item) + { + int icoShader = 0; + if (cgs.gametype == GT_CTY && (j == PW_REDFLAG || j == PW_BLUEFLAG)) + { + if (j == PW_REDFLAG) + { + icoShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_ys" ); + } + else + { + icoShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_ys" ); + } + } + else + { + icoShader = trap_R_RegisterShader( item->icon ); + } + + CG_DrawPic( (640-(ico_size*1.1)), y, ico_size, ico_size, icoShader ); + + y += ico_size; + + if (j != PW_REDFLAG && j != PW_BLUEFLAG && secondsleft < 999) + { + UI_DrawProportionalString((640-(ico_size*1.1))+(ico_size/2), y-8, va("%i", secondsleft), UI_CENTER | UI_BIGFONT | UI_DROPSHADOW, colorTable[CT_WHITE]); + } + + y += (ico_size/3); + } + } + } +} + + /* ===================== CG_DrawUpperRight @@ -1937,6 +2158,8 @@ static void CG_DrawUpperRight( void ) { y = CG_DrawEnemyInfo ( y ); y = CG_DrawMiniScoreboard ( y ); + + CG_DrawPowerupIcons(y); } /* @@ -1944,6 +2167,7 @@ static void CG_DrawUpperRight( void ) { CG_DrawReward =================== */ +#ifdef JK2AWARDS static void CG_DrawReward( void ) { float *color; int i, count; @@ -2010,6 +2234,7 @@ static void CG_DrawReward( void ) { } trap_R_SetColor( NULL ); } +#endif /* @@ -2087,12 +2312,12 @@ static void CG_DrawDisconnect( void ) { int w; // bk010215 - FIXME char message[1024]; if (cg.mMapChange) - { - s = "Server Changing Maps"; + { + s = CG_GetStripEdString("INGAMETEXT", "SERVER_CHANGING_MAPS"); // s = "Server Changing Maps"; w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; CG_DrawBigString( 320 - w/2, 100, s, 1.0F); - s = "Please wait..."; + s = CG_GetStripEdString("INGAMETEXT", "PLEASE_WAIT"); // s = "Please wait..."; w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; CG_DrawBigString( 320 - w/2, 200, s, 1.0F); return; @@ -2107,7 +2332,7 @@ static void CG_DrawDisconnect( void ) { } // also add text in center of screen - s = "Connection Interrupted"; // bk 010215 - FIXME + s = CG_GetStripEdString("INGAMETEXT", "CONNECTION_INTERRUPTED"); // s = "Connection Interrupted"; // bk 010215 - FIXME w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; CG_DrawBigString( 320 - w/2, 100, s, 1.0F); @@ -2355,6 +2580,11 @@ static void CG_DrawCrosshair( vec3_t worldPoint, int chEntValid ) { return; } + if (cg.snap->ps.fallingToDeath) + { + return; + } + if ( cg.predictedPlayerState.zoomMode != 0 ) {//not while scoped return; @@ -2604,6 +2834,11 @@ static void CG_DrawHolocronIcons(void) return; } + if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR) + { + return; + } + while (i < NUM_FORCE_POWERS) { if (cg.snap->ps.holocronBits & (1 << forcePowerSorted[i])) @@ -2654,6 +2889,11 @@ static void CG_DrawActivePowers(void) return; } + if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR) + { + return; + } + while (i < NUM_FORCE_POWERS) { if ((cg.snap->ps.fd.forcePowersActive & (1 << forcePowerSorted[i])) && @@ -2695,6 +2935,11 @@ static void CG_DrawRocketLocking( int lockEntNum, int lockTime ) return; } + if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR) + { + return; + } + //We can't check to see in pmove if players are on the same team, so we resort //to just not drawing the lock if a teammate is the locked on ent if (cg.snap->ps.rocketLockIndex >= 0 && @@ -2702,7 +2947,10 @@ static void CG_DrawRocketLocking( int lockEntNum, int lockTime ) { if (cgs.clientinfo[cg.snap->ps.rocketLockIndex].team == cgs.clientinfo[cg.snap->ps.clientNum].team) { - return; + if (cgs.gametype >= GT_TEAM) + { + return; + } } } @@ -3020,13 +3268,44 @@ static void CG_DrawCrosshairNames( void ) { CG_DrawSpectator ================= */ -static void CG_DrawSpectator(void) { - CG_DrawBigString(320 - 9 * 8, 440, "SPECTATOR", 1.0F); - if ( cgs.gametype == GT_TOURNAMENT ) { - CG_DrawBigString(320 - 15 * 8, 460, "waiting to play", 1.0F); +static void CG_DrawSpectator(void) +{ + const char* s; + s = CG_GetStripEdString("INGAMETEXT", "SPECTATOR"); + if (cgs.gametype == GT_TOURNAMENT && + cgs.duelist1 != -1 && + cgs.duelist2 != -1) + { + char text[1024]; + int size = 64; + + Com_sprintf(text, sizeof(text), "%s %s %s", cgs.clientinfo[cgs.duelist1].name, CG_GetStripEdString("INGAMETEXT", "SPECHUD_VERSUS"), cgs.clientinfo[cgs.duelist2].name); + CG_Text_Paint ( 320 - CG_Text_Width ( text, 1.0f, 3 ) / 2, 420, 1.0f, colorWhite, text, 0, 0, 0, 3 ); + + + if (cgs.clientinfo[cgs.duelist1].modelIcon && + cgs.clientinfo[cgs.duelist2].modelIcon) + { + trap_R_SetColor( colorTable[CT_WHITE] ); + CG_DrawPic( 10, SCREEN_HEIGHT-(size*1.5), size, size, cgs.clientinfo[cgs.duelist1].modelIcon ); + CG_DrawPic( SCREEN_WIDTH-size-10, SCREEN_HEIGHT-(size*1.5), size, size, cgs.clientinfo[cgs.duelist2].modelIcon ); + } } - else if ( cgs.gametype >= GT_TEAM ) { - CG_DrawBigString(320 - 39 * 8, 460, "press ESC and use the JOIN menu to play", 1.0F); + else + { + CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, 3 ) / 2, 420, 1.0f, colorWhite, s, 0, 0, 0, 3 ); + } + + if ( cgs.gametype == GT_TOURNAMENT ) + { + s = CG_GetStripEdString("INGAMETEXT", "WAITING_TO_PLAY"); // "waiting to play"; + CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, 3 ) / 2, 440, 1.0f, colorWhite, s, 0, 0, 0, 3 ); + } + else //if ( cgs.gametype >= GT_TEAM ) + { + //s = "press ESC and use the JOIN menu to play"; + s = CG_GetStripEdString("INGAMETEXT", "SPEC_CHOOSEJOIN"); + CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, 3 ) / 2, 440, 1.0f, colorWhite, s, 0, 0, 0, 3 ); } } @@ -3036,8 +3315,10 @@ CG_DrawVote ================= */ static void CG_DrawVote(void) { - char *s; + const char *s; int sec; + char sYes[20]; + char sNo[20]; if ( !cgs.voteTime ) { return; @@ -3053,10 +3334,14 @@ static void CG_DrawVote(void) { if ( sec < 0 ) { sec = 0; } - s = va("VOTE(%i):%s yes:%i no:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo); - CG_DrawSmallString( 0, 58, s, 1.0F ); - s = "or press ESC then click Vote"; - CG_DrawSmallString( 0, 58 + SMALLCHAR_HEIGHT + 2, s, 1.0F ); + + trap_SP_GetStringTextString("MENUS0_YES", sYes, sizeof(sYes) ); + trap_SP_GetStringTextString("MENUS0_NO", sNo, sizeof(sNo) ); + + s = va("VOTE(%i):%s %s:%i %s:%i", sec, cgs.voteString, sYes, cgs.voteYes, sNo, cgs.voteNo); + CG_DrawSmallString( 4, 58, s, 1.0F ); + s = CG_GetStripEdString("INGAMETEXT", "OR_PRESS_ESC_THEN_CLICK_VOTE"); // s = "or press ESC then click Vote"; + CG_DrawSmallString( 4, 58 + SMALLCHAR_HEIGHT + 2, s, 1.0F ); } /* @@ -3129,7 +3414,7 @@ static void CG_DrawTeamVote(void) { s = va("TEAMVOTE(%i):%s yes:%i no:%i", sec, cgs.teamVoteString[cs_offset], cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] ); } - CG_DrawSmallString( 0, 90, s, 1.0F ); + CG_DrawSmallString( 4, 90, s, 1.0F ); } static qboolean CG_DrawScoreboard() { @@ -3220,34 +3505,28 @@ static void CG_DrawIntermission( void ) { CG_DrawFollow ================= */ -static qboolean CG_DrawFollow( void ) { - float x; - vec4_t color; - const char *name; +static qboolean CG_DrawFollow( void ) +{ + const char *s; - if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) { + if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) + { return qfalse; } - color[0] = 1; - color[1] = 1; - color[2] = 1; - color[3] = 1; +// s = "following"; + s = CG_GetStripEdString("INGAMETEXT", "FOLLOWING"); + CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, FONT_MEDIUM ) / 2, 60, 1.0f, colorWhite, s, 0, 0, 0, FONT_MEDIUM ); - CG_DrawBigString( 320 - 9 * 8, 24, "following", 1.0F ); - - name = cgs.clientinfo[ cg.snap->ps.clientNum ].name; - - x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( name ) ); - - CG_DrawStringExt( x, 40, name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); + s = cgs.clientinfo[ cg.snap->ps.clientNum ].name; + CG_Text_Paint ( 320 - CG_Text_Width ( s, 2.0f, FONT_MEDIUM ) / 2, 80, 2.0f, colorWhite, s, 0, 0, 0, FONT_MEDIUM ); return qtrue; } +#if 0 static void CG_DrawTemporaryStats() { //placeholder for testing (draws ammo and force power) -#if 0 char s[512]; if (!cg.snap) @@ -3270,8 +3549,8 @@ static void CG_DrawTemporaryStats() sprintf(s, "Armor: %i", cg.snap->ps.stats[STAT_ARMOR]); CG_DrawBigString(8, SCREEN_HEIGHT-112, s, 1.0f); -#endif } +#endif /* ================= @@ -3328,7 +3607,8 @@ static void CG_DrawWarmup( void ) { } if ( sec < 0 ) { - s = "Waiting for players"; +// s = "Waiting for players"; + s = CG_GetStripEdString("INGAMETEXT", "WAITING_FOR_PLAYERS"); w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; CG_DrawBigString(320 - w / 2, 24, s, 1.0F); cg.warmupCount = 0; @@ -3364,16 +3644,16 @@ static void CG_DrawWarmup( void ) { } else if ( cgs.gametype == GT_TEAM ) { s = "Team FFA"; } else if ( cgs.gametype == GT_SAGA ) { - s = "Saga"; + s = "N/A"; } else if ( cgs.gametype == GT_CTF ) { s = "Capture the Flag"; } else if ( cgs.gametype == GT_CTY ) { - s = "Capture the Ysalimari"; + s = "Capture the Ysalamiri"; } else { s = ""; } - w = CG_Text_Width(s, 0.6f, FONT_MEDIUM); - CG_Text_Paint(320 - w / 2, 90, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE,FONT_MEDIUM); + w = CG_Text_Width(s, 1.5f, FONT_MEDIUM); + CG_Text_Paint(320 - w / 2, 90, 1.5f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE,FONT_MEDIUM); } sec = ( sec - cg.time ) / 1000; @@ -3381,7 +3661,8 @@ static void CG_DrawWarmup( void ) { cg.warmup = 0; sec = 0; } - s = va( "Starts in: %i", sec + 1 ); +// s = va( "Starts in: %i", sec + 1 ); + s = va( "%s: %i",CG_GetStripEdString("INGAMETEXT", "STARTS_IN"), sec + 1 ); if ( sec != cg.warmupCount ) { cg.warmupCount = sec; switch ( sec ) { @@ -3402,24 +3683,24 @@ static void CG_DrawWarmup( void ) { switch ( cg.warmupCount ) { case 0: cw = 28; - scale = 0.54f; + scale = 1.25f; break; case 1: cw = 24; - scale = 0.51f; + scale = 1.15f; break; case 2: cw = 20; - scale = 0.48f; + scale = 1.05f; break; default: cw = 16; - scale = 0.45f; + scale = 0.9f; break; } - w = CG_Text_Width(s, scale, FONT_MEDIUM); - CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM); + w = CG_Text_Width(s, scale, FONT_MEDIUM); + CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM); } //================================================================================== @@ -3439,60 +3720,6 @@ void CG_DrawTimedMenus() { } } -static void CG_DrawPowerupIcons() -{ - int j; - int ico_size = 64; - int y = ico_size/2; - gitem_t *item; - - if (!cg.snap) - { - return; - } - - for (j = 0; j <= PW_NUM_POWERUPS; j++) - { - if (cg.snap->ps.powerups[j] > cg.time) - { - int secondsleft = (cg.snap->ps.powerups[j] - cg.time)/1000; - - item = BG_FindItemForPowerup( j ); - - if (item) - { - int icoShader = 0; - if (cgs.gametype == GT_CTY && (j == PW_REDFLAG || j == PW_BLUEFLAG)) - { - if (j == PW_REDFLAG) - { - icoShader = trap_R_RegisterShader( "gfx/hud/mpi_rflag_ys" ); - } - else - { - icoShader = trap_R_RegisterShader( "gfx/hud/mpi_bflag_ys" ); - } - } - else - { - icoShader = trap_R_RegisterShader( item->icon ); - } - - CG_DrawPic( (640-(ico_size*1.5)), y, ico_size, ico_size, icoShader ); - - y += ico_size; - - if (j != PW_REDFLAG && j != PW_BLUEFLAG && secondsleft < 999) - { - UI_DrawProportionalString((640-(ico_size*1.5))+(ico_size/2), y-8, va("%i", secondsleft), UI_CENTER | UI_SMALLFONT | UI_DROPSHADOW, colorTable[CT_WHITE]); - } - - y += (ico_size/3); - } - } - } -} - void CG_DrawFlagStatus() { int myFlagTakenShader = 0; @@ -3517,26 +3744,26 @@ void CG_DrawFlagStatus() { if (team == TEAM_RED) { - myFlagTakenShader = trap_R_RegisterShader( "gfx/hud/mpi_rflag_x" ); - theirFlagShader = trap_R_RegisterShader( "gfx/hud/mpi_bflag_ys" ); + myFlagTakenShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_x" ); + theirFlagShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_ys" ); } else { - myFlagTakenShader = trap_R_RegisterShader( "gfx/hud/mpi_bflag_x" ); - theirFlagShader = trap_R_RegisterShader( "gfx/hud/mpi_rflag_ys" ); + myFlagTakenShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_x" ); + theirFlagShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_ys" ); } } else { if (team == TEAM_RED) { - myFlagTakenShader = trap_R_RegisterShader( "gfx/hud/mpi_rflag_x" ); - theirFlagShader = trap_R_RegisterShader( "gfx/hud/mpi_bflag" ); + myFlagTakenShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_x" ); + theirFlagShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag" ); } else { - myFlagTakenShader = trap_R_RegisterShader( "gfx/hud/mpi_bflag_x" ); - theirFlagShader = trap_R_RegisterShader( "gfx/hud/mpi_rflag" ); + myFlagTakenShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_x" ); + theirFlagShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag" ); } } @@ -3572,6 +3799,9 @@ int cgYsalTime = 0; int cgYsalFadeTime = 0; float cgYsalFadeVal = 0; +qboolean gCGHasFallVector = qfalse; +vec3_t gCGFallVector; + /* ================= CG_Draw2D @@ -3593,6 +3823,29 @@ static void CG_Draw2D( void ) { return; } + if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR) + { + cgRageTime = 0; + cgRageFadeTime = 0; + cgRageFadeVal = 0; + + cgRageRecTime = 0; + cgRageRecFadeTime = 0; + cgRageRecFadeVal = 0; + + cgAbsorbTime = 0; + cgAbsorbFadeTime = 0; + cgAbsorbFadeVal = 0; + + cgProtectTime = 0; + cgProtectFadeTime = 0; + cgProtectFadeVal = 0; + + cgYsalTime = 0; + cgYsalFadeTime = 0; + cgYsalFadeVal = 0; + } + if ( cg_draw2D.integer == 0 ) { return; } @@ -3602,381 +3855,384 @@ static void CG_Draw2D( void ) { return; } - if (cg.snap->ps.fd.forcePowersActive & (1 << FP_RAGE)) + if (cgs.clientinfo[cg.snap->ps.clientNum].team != TEAM_SPECTATOR) { - if (!cgRageTime) + if (cg.snap->ps.fd.forcePowersActive & (1 << FP_RAGE)) { - cgRageTime = cg.time; - } - - rageTime = (float)(cg.time - cgRageTime); - - rageTime /= 9000; - - if (rageTime < 0) - { - rageTime = 0; - } - if (rageTime > 0.15) - { - rageTime = 0.15; - } - - hcolor[3] = rageTime; - hcolor[0] = 0.7; - hcolor[1] = 0; - hcolor[2] = 0; - - if (!cg.renderingThirdPerson) - { - CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); - } - - cgRageFadeTime = 0; - cgRageFadeVal = 0; - } - else if (cgRageTime) - { - if (!cgRageFadeTime) - { - cgRageFadeTime = cg.time; - cgRageFadeVal = 0.15; - } - - rageTime = cgRageFadeVal; - - cgRageFadeVal -= (cg.time - cgRageFadeTime)*0.000005; - - if (rageTime < 0) - { - rageTime = 0; - } - if (rageTime > 0.15) - { - rageTime = 0.15; - } - - if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time) - { - float checkRageRecTime = rageTime; - - if (checkRageRecTime < 0.15) + if (!cgRageTime) { - checkRageRecTime = 0.15; + cgRageTime = cg.time; } - - hcolor[3] = checkRageRecTime; - hcolor[0] = rageTime*4; - if (hcolor[0] < 0.2) + + rageTime = (float)(cg.time - cgRageTime); + + rageTime /= 9000; + + if (rageTime < 0) { - hcolor[0] = 0.2; + rageTime = 0; } - hcolor[1] = 0.2; - hcolor[2] = 0.2; - } - else - { + if (rageTime > 0.15) + { + rageTime = 0.15; + } + hcolor[3] = rageTime; hcolor[0] = 0.7; hcolor[1] = 0; hcolor[2] = 0; - } - - if (!cg.renderingThirdPerson && rageTime) - { - CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); - } - else - { - if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time) + + if (!cg.renderingThirdPerson) { - hcolor[3] = 0.15; - hcolor[0] = 0.2; - hcolor[1] = 0.2; - hcolor[2] = 0.2; CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); } - cgRageTime = 0; + + cgRageFadeTime = 0; + cgRageFadeVal = 0; } - } - else if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time) - { - if (!cgRageRecTime) + else if (cgRageTime) { - cgRageRecTime = cg.time; + if (!cgRageFadeTime) + { + cgRageFadeTime = cg.time; + cgRageFadeVal = 0.15; + } + + rageTime = cgRageFadeVal; + + cgRageFadeVal -= (cg.time - cgRageFadeTime)*0.000005; + + if (rageTime < 0) + { + rageTime = 0; + } + if (rageTime > 0.15) + { + rageTime = 0.15; + } + + if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time) + { + float checkRageRecTime = rageTime; + + if (checkRageRecTime < 0.15) + { + checkRageRecTime = 0.15; + } + + hcolor[3] = checkRageRecTime; + hcolor[0] = rageTime*4; + if (hcolor[0] < 0.2) + { + hcolor[0] = 0.2; + } + hcolor[1] = 0.2; + hcolor[2] = 0.2; + } + else + { + hcolor[3] = rageTime; + hcolor[0] = 0.7; + hcolor[1] = 0; + hcolor[2] = 0; + } + + if (!cg.renderingThirdPerson && rageTime) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + else + { + if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time) + { + hcolor[3] = 0.15; + hcolor[0] = 0.2; + hcolor[1] = 0.2; + hcolor[2] = 0.2; + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + cgRageTime = 0; + } } - - rageRecTime = (float)(cg.time - cgRageRecTime); - - rageRecTime /= 9000; - - if (rageRecTime < 0.15)//0) + else if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time) { - rageRecTime = 0.15;//0; + if (!cgRageRecTime) + { + cgRageRecTime = cg.time; + } + + rageRecTime = (float)(cg.time - cgRageRecTime); + + rageRecTime /= 9000; + + if (rageRecTime < 0.15)//0) + { + rageRecTime = 0.15;//0; + } + if (rageRecTime > 0.15) + { + rageRecTime = 0.15; + } + + hcolor[3] = rageRecTime; + hcolor[0] = 0.2; + hcolor[1] = 0.2; + hcolor[2] = 0.2; + + if (!cg.renderingThirdPerson) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + + cgRageRecFadeTime = 0; + cgRageRecFadeVal = 0; } - if (rageRecTime > 0.15) + else if (cgRageRecTime) { - rageRecTime = 0.15; + if (!cgRageRecFadeTime) + { + cgRageRecFadeTime = cg.time; + cgRageRecFadeVal = 0.15; + } + + rageRecTime = cgRageRecFadeVal; + + cgRageRecFadeVal -= (cg.time - cgRageRecFadeTime)*0.000005; + + if (rageRecTime < 0) + { + rageRecTime = 0; + } + if (rageRecTime > 0.15) + { + rageRecTime = 0.15; + } + + hcolor[3] = rageRecTime; + hcolor[0] = 0.2; + hcolor[1] = 0.2; + hcolor[2] = 0.2; + + if (!cg.renderingThirdPerson && rageRecTime) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + else + { + cgRageRecTime = 0; + } } - - hcolor[3] = rageRecTime; - hcolor[0] = 0.2; - hcolor[1] = 0.2; - hcolor[2] = 0.2; - - if (!cg.renderingThirdPerson) - { - CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); - } - - cgRageRecFadeTime = 0; - cgRageRecFadeVal = 0; - } - else if (cgRageRecTime) - { - if (!cgRageRecFadeTime) - { - cgRageRecFadeTime = cg.time; - cgRageRecFadeVal = 0.15; - } - - rageRecTime = cgRageRecFadeVal; - cgRageRecFadeVal -= (cg.time - cgRageRecFadeTime)*0.000005; - - if (rageRecTime < 0) + if (cg.snap->ps.fd.forcePowersActive & (1 << FP_ABSORB)) { - rageRecTime = 0; + if (!cgAbsorbTime) + { + cgAbsorbTime = cg.time; + } + + absorbTime = (float)(cg.time - cgAbsorbTime); + + absorbTime /= 9000; + + if (absorbTime < 0) + { + absorbTime = 0; + } + if (absorbTime > 0.15) + { + absorbTime = 0.15; + } + + hcolor[3] = absorbTime/2; + hcolor[0] = 0; + hcolor[1] = 0; + hcolor[2] = 0.7; + + if (!cg.renderingThirdPerson) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + + cgAbsorbFadeTime = 0; + cgAbsorbFadeVal = 0; } - if (rageRecTime > 0.15) + else if (cgAbsorbTime) { - rageRecTime = 0.15; + if (!cgAbsorbFadeTime) + { + cgAbsorbFadeTime = cg.time; + cgAbsorbFadeVal = 0.15; + } + + absorbTime = cgAbsorbFadeVal; + + cgAbsorbFadeVal -= (cg.time - cgAbsorbFadeTime)*0.000005; + + if (absorbTime < 0) + { + absorbTime = 0; + } + if (absorbTime > 0.15) + { + absorbTime = 0.15; + } + + hcolor[3] = absorbTime/2; + hcolor[0] = 0; + hcolor[1] = 0; + hcolor[2] = 0.7; + + if (!cg.renderingThirdPerson && absorbTime) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + else + { + cgAbsorbTime = 0; + } } - - hcolor[3] = rageRecTime; - hcolor[0] = 0.2; - hcolor[1] = 0.2; - hcolor[2] = 0.2; - - if (!cg.renderingThirdPerson && rageRecTime) - { - CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); - } - else - { - cgRageRecTime = 0; - } - } - - if (cg.snap->ps.fd.forcePowersActive & (1 << FP_ABSORB)) - { - if (!cgAbsorbTime) - { - cgAbsorbTime = cg.time; - } - - absorbTime = (float)(cg.time - cgAbsorbTime); - - absorbTime /= 9000; - - if (absorbTime < 0) - { - absorbTime = 0; - } - if (absorbTime > 0.15) - { - absorbTime = 0.15; - } - - hcolor[3] = absorbTime/2; - hcolor[0] = 0; - hcolor[1] = 0; - hcolor[2] = 0.7; - - if (!cg.renderingThirdPerson) - { - CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); - } - - cgAbsorbFadeTime = 0; - cgAbsorbFadeVal = 0; - } - else if (cgAbsorbTime) - { - if (!cgAbsorbFadeTime) - { - cgAbsorbFadeTime = cg.time; - cgAbsorbFadeVal = 0.15; - } - - absorbTime = cgAbsorbFadeVal; - cgAbsorbFadeVal -= (cg.time - cgAbsorbFadeTime)*0.000005; - - if (absorbTime < 0) + if (cg.snap->ps.fd.forcePowersActive & (1 << FP_PROTECT)) { - absorbTime = 0; + if (!cgProtectTime) + { + cgProtectTime = cg.time; + } + + protectTime = (float)(cg.time - cgProtectTime); + + protectTime /= 9000; + + if (protectTime < 0) + { + protectTime = 0; + } + if (protectTime > 0.15) + { + protectTime = 0.15; + } + + hcolor[3] = protectTime/2; + hcolor[0] = 0; + hcolor[1] = 0.7; + hcolor[2] = 0; + + if (!cg.renderingThirdPerson) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + + cgProtectFadeTime = 0; + cgProtectFadeVal = 0; } - if (absorbTime > 0.15) + else if (cgProtectTime) { - absorbTime = 0.15; + if (!cgProtectFadeTime) + { + cgProtectFadeTime = cg.time; + cgProtectFadeVal = 0.15; + } + + protectTime = cgProtectFadeVal; + + cgProtectFadeVal -= (cg.time - cgProtectFadeTime)*0.000005; + + if (protectTime < 0) + { + protectTime = 0; + } + if (protectTime > 0.15) + { + protectTime = 0.15; + } + + hcolor[3] = protectTime/2; + hcolor[0] = 0; + hcolor[1] = 0.7; + hcolor[2] = 0; + + if (!cg.renderingThirdPerson && protectTime) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + else + { + cgProtectTime = 0; + } } - - hcolor[3] = absorbTime/2; - hcolor[0] = 0; - hcolor[1] = 0; - hcolor[2] = 0.7; - - if (!cg.renderingThirdPerson && absorbTime) - { - CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); - } - else - { - cgAbsorbTime = 0; - } - } - - if (cg.snap->ps.fd.forcePowersActive & (1 << FP_PROTECT)) - { - if (!cgProtectTime) - { - cgProtectTime = cg.time; - } - - protectTime = (float)(cg.time - cgProtectTime); - - protectTime /= 9000; - - if (protectTime < 0) - { - protectTime = 0; - } - if (protectTime > 0.15) - { - protectTime = 0.15; - } - - hcolor[3] = protectTime/2; - hcolor[0] = 0; - hcolor[1] = 0.7; - hcolor[2] = 0; - - if (!cg.renderingThirdPerson) - { - CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); - } - - cgProtectFadeTime = 0; - cgProtectFadeVal = 0; - } - else if (cgProtectTime) - { - if (!cgProtectFadeTime) - { - cgProtectFadeTime = cg.time; - cgProtectFadeVal = 0.15; - } - - protectTime = cgProtectFadeVal; - cgProtectFadeVal -= (cg.time - cgProtectFadeTime)*0.000005; - - if (protectTime < 0) + if (cg.snap->ps.rocketLockIndex != MAX_CLIENTS && (cg.time - cg.snap->ps.rocketLockTime) > 0) { - protectTime = 0; + CG_DrawRocketLocking( cg.snap->ps.rocketLockIndex, cg.snap->ps.rocketLockTime ); } - if (protectTime > 0.15) - { - protectTime = 0.15; - } - - hcolor[3] = protectTime/2; - hcolor[0] = 0; - hcolor[1] = 0.7; - hcolor[2] = 0; - - if (!cg.renderingThirdPerson && protectTime) - { - CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); - } - else - { - cgProtectTime = 0; - } - } - - if (cg.snap->ps.rocketLockIndex != MAX_CLIENTS && (cg.time - cg.snap->ps.rocketLockTime) > 0) - { - CG_DrawRocketLocking( cg.snap->ps.rocketLockIndex, cg.snap->ps.rocketLockTime ); - } - - if (BG_HasYsalimari(cgs.gametype, &cg.snap->ps)) - { - if (!cgYsalTime) - { - cgYsalTime = cg.time; - } - - ysalTime = (float)(cg.time - cgYsalTime); - - ysalTime /= 9000; - - if (ysalTime < 0) - { - ysalTime = 0; - } - if (ysalTime > 0.15) - { - ysalTime = 0.15; - } - - hcolor[3] = ysalTime/2; - hcolor[0] = 0.7; - hcolor[1] = 0.7; - hcolor[2] = 0; - - if (!cg.renderingThirdPerson) - { - CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); - } - - cgYsalFadeTime = 0; - cgYsalFadeVal = 0; - } - else if (cgYsalTime) - { - if (!cgYsalFadeTime) - { - cgYsalFadeTime = cg.time; - cgYsalFadeVal = 0.15; - } - - ysalTime = cgYsalFadeVal; - cgYsalFadeVal -= (cg.time - cgYsalFadeTime)*0.000005; - - if (ysalTime < 0) + if (BG_HasYsalamiri(cgs.gametype, &cg.snap->ps)) { - ysalTime = 0; + if (!cgYsalTime) + { + cgYsalTime = cg.time; + } + + ysalTime = (float)(cg.time - cgYsalTime); + + ysalTime /= 9000; + + if (ysalTime < 0) + { + ysalTime = 0; + } + if (ysalTime > 0.15) + { + ysalTime = 0.15; + } + + hcolor[3] = ysalTime/2; + hcolor[0] = 0.7; + hcolor[1] = 0.7; + hcolor[2] = 0; + + if (!cg.renderingThirdPerson) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + + cgYsalFadeTime = 0; + cgYsalFadeVal = 0; } - if (ysalTime > 0.15) + else if (cgYsalTime) { - ysalTime = 0.15; - } - - hcolor[3] = ysalTime/2; - hcolor[0] = 0.7; - hcolor[1] = 0.7; - hcolor[2] = 0; - - if (!cg.renderingThirdPerson && ysalTime) - { - CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); - } - else - { - cgYsalTime = 0; + if (!cgYsalFadeTime) + { + cgYsalFadeTime = cg.time; + cgYsalFadeVal = 0.15; + } + + ysalTime = cgYsalFadeVal; + + cgYsalFadeVal -= (cg.time - cgYsalFadeTime)*0.000005; + + if (ysalTime < 0) + { + ysalTime = 0; + } + if (ysalTime > 0.15) + { + ysalTime = 0.15; + } + + hcolor[3] = ysalTime/2; + hcolor[0] = 0.7; + hcolor[1] = 0.7; + hcolor[2] = 0; + + if (!cg.renderingThirdPerson && ysalTime) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + else + { + cgYsalTime = 0; + } } } @@ -4060,7 +4316,9 @@ static void CG_Draw2D( void ) { if (cg_drawStatus.integer) { - CG_DrawPowerupIcons(); + //Powerups now done with upperright stuff + //CG_DrawPowerupIcons(); + CG_DrawFlagStatus(); } @@ -4081,7 +4339,7 @@ static void CG_Draw2D( void ) { { fallTime = (float)(cg.time - cg.snap->ps.fallingToDeath); - fallTime /= FALL_FADE_TIME; + fallTime /= (FALL_FADE_TIME/2); if (fallTime < 0) { @@ -4098,6 +4356,20 @@ static void CG_Draw2D( void ) { hcolor[2] = 0; CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + + if (!gCGHasFallVector) + { + VectorCopy(cg.snap->ps.origin, gCGFallVector); + gCGHasFallVector = qtrue; + } + } + else + { + if (gCGHasFallVector) + { + gCGHasFallVector = qfalse; + VectorClear(gCGFallVector); + } } CG_DrawVote(); diff --git a/CODE-mp/cgame/cg_draw.mrg b/CODE-mp/cgame/cg_draw.mrg new file mode 100644 index 0000000..e5b6c10 --- /dev/null +++ b/CODE-mp/cgame/cg_draw.mrg @@ -0,0 +1,4453 @@ +// Copyright (C) 1999-2000 Id Software, Inc. +// +// cg_draw.c -- draw all of the graphical elements during +// active (after loading) gameplay + +#include "cg_local.h" + +#include "../ui/ui_shared.h" + +qboolean CG_WorldCoordToScreenCoordFloat(vec3_t worldCoord, float *x, float *y); +qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ); + +// used for scoreboard +extern displayContextDef_t cgDC; +menuDef_t *menuScoreboard = NULL; +vec4_t bluehudtint = {0.5, 0.5, 1.0, 1.0}; +vec4_t redhudtint = {1.0, 0.5, 0.5, 1.0}; +float *hudTintColor; + +int sortedTeamPlayers[TEAM_MAXOVERLAY]; +int numSortedTeamPlayers; + +int lastvalidlockdif; + +extern float zoomFov; //this has to be global client-side + +char systemChat[256]; +char teamChat1[256]; +char teamChat2[256]; + +char *showPowersName[] = +{ + "HEAL2",//FP_HEAL + "JUMP2",//FP_LEVITATION + "SPEED2",//FP_SPEED + "PUSH2",//FP_PUSH + "PULL2",//FP_PULL + "MINDTRICK2",//FP_TELEPTAHY + "GRIP2",//FP_GRIP + "LIGHTNING2",//FP_LIGHTNING + "DARK_RAGE2",//FP_RAGE + "PROTECT2",//FP_PROTECT + "ABSORB2",//FP_ABSORB + "TEAM_HEAL2",//FP_TEAM_HEAL + "TEAM_REPLENISH2",//FP_TEAM_FORCE + "DRAIN2",//FP_DRAIN + "SEEING2",//FP_SEE + "SABER_OFFENSE2",//FP_SABERATTACK + "SABER_DEFENSE2",//FP_SABERDEFEND + "SABER_THROW2",//FP_SABERTHROW + NULL +}; + + +int MenuFontToHandle(int iMenuFont) +{ + switch (iMenuFont) + { + case FONT_SMALL: return cgDC.Assets.qhSmallFont; + case FONT_MEDIUM: return cgDC.Assets.qhMediumFont; + case FONT_LARGE: return cgDC.Assets.qhBigFont; + } + + return cgDC.Assets.qhMediumFont; +} + +int CG_Text_Width(const char *text, float scale, int iMenuFont) +{ + int iFontIndex = MenuFontToHandle(iMenuFont); + + return trap_R_Font_StrLenPixels(text, iFontIndex, scale); +} + +int CG_Text_Height(const char *text, float scale, int iMenuFont) +{ + int iFontIndex = MenuFontToHandle(iMenuFont); + + return trap_R_Font_HeightPixels(iFontIndex, scale); +} + +#include "../qcommon/qfiles.h" // for STYLE_BLINK etc +void CG_Text_Paint(float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style, int iMenuFont) +{ + int iStyleOR = 0; + int iFontIndex = MenuFontToHandle(iMenuFont); + + switch (style) + { + case ITEM_TEXTSTYLE_NORMAL: iStyleOR = 0;break; // JK2 normal text + case ITEM_TEXTSTYLE_BLINK: iStyleOR = STYLE_BLINK;break; // JK2 fast blinking + case ITEM_TEXTSTYLE_PULSE: iStyleOR = STYLE_BLINK;break; // JK2 slow pulsing + case ITEM_TEXTSTYLE_SHADOWED: iStyleOR = (int)STYLE_DROPSHADOW;break; // JK2 drop shadow ( need a color for this ) + case ITEM_TEXTSTYLE_OUTLINED: iStyleOR = (int)STYLE_DROPSHADOW;break; // JK2 drop shadow ( need a color for this ) + case ITEM_TEXTSTYLE_OUTLINESHADOWED: iStyleOR = (int)STYLE_DROPSHADOW;break; // JK2 drop shadow ( need a color for this ) + case ITEM_TEXTSTYLE_SHADOWEDMORE: iStyleOR = (int)STYLE_DROPSHADOW;break; // JK2 drop shadow ( need a color for this ) + } + + trap_R_Font_DrawString( x, // int ox + y, // int oy + text, // const char *text + color, // paletteRGBA_c c + iStyleOR | iFontIndex, // const int iFontHandle + !limit?-1:limit, // iCharLimit (-1 = none) + scale // const float scale = 1.0f + ); +} + +/* +qboolean CG_WorldCoordToScreenCoord(vec3_t worldCoord, int *x, int *y) + + Take any world coord and convert it to a 2D virtual 640x480 screen coord +*/ +/* +qboolean CG_WorldCoordToScreenCoordFloat(vec3_t worldCoord, float *x, float *y) +{ + int xcenter, ycenter; + vec3_t local, transformed; + +// xcenter = cg.refdef.width / 2;//gives screen coords adjusted for resolution +// ycenter = cg.refdef.height / 2;//gives screen coords adjusted for resolution + + //NOTE: did it this way because most draw functions expect virtual 640x480 coords + // and adjust them for current resolution + xcenter = 640 / 2;//gives screen coords in virtual 640x480, to be adjusted when drawn + ycenter = 480 / 2;//gives screen coords in virtual 640x480, to be adjusted when drawn + + VectorSubtract (worldCoord, cg.refdef.vieworg, local); + + transformed[0] = DotProduct(local,vright); + transformed[1] = DotProduct(local,vup); + transformed[2] = DotProduct(local,vfwd); + + // Make sure Z is not negative. + if(transformed[2] < 0.01) + { + return qfalse; + } + // Simple convert to screen coords. + float xzi = xcenter / transformed[2] * (90.0/cg.refdef.fov_x); + float yzi = ycenter / transformed[2] * (90.0/cg.refdef.fov_y); + + *x = xcenter + xzi * transformed[0]; + *y = ycenter - yzi * transformed[1]; + + return qtrue; +} + +qboolean CG_WorldCoordToScreenCoord( vec3_t worldCoord, int *x, int *y ) +{ + float xF, yF; + qboolean retVal = CG_WorldCoordToScreenCoordFloat( worldCoord, &xF, &yF ); + *x = (int)xF; + *y = (int)yF; + return retVal; +} +*/ + +/* +================ +CG_DrawZoomMask + +================ +*/ +static void CG_DrawZoomMask( void ) +{ + vec4_t color1; + float level; + static qboolean flip = qtrue; + +// int ammo = cg_entities[0].gent->client->ps.ammo[weaponData[cent->currentState.weapon].ammoIndex]; + float cx, cy; +// int val[5]; + float max, fi; + + // Check for Binocular specific zooming since we'll want to render different bits in each case + if ( cg.predictedPlayerState.zoomMode == 2 ) + { + int val, i; + float off; + + // zoom level + level = (float)(80.0f - cg.predictedPlayerState.zoomFov) / 80.0f; + + // ...so we'll clamp it + if ( level < 0.0f ) + { + level = 0.0f; + } + else if ( level > 1.0f ) + { + level = 1.0f; + } + + // Using a magic number to convert the zoom level to scale amount + level *= 162.0f; + + // draw blue tinted distortion mask, trying to make it as small as is necessary to fill in the viewable area + trap_R_SetColor( colorTable[CT_WHITE] ); + CG_DrawPic( 34, 48, 570, 362, cgs.media.binocularStatic ); + + // Black out the area behind the numbers + trap_R_SetColor( colorTable[CT_BLACK]); + CG_DrawPic( 212, 367, 200, 40, cgs.media.whiteShader ); + + // Numbers should be kind of greenish + color1[0] = 0.2f; + color1[1] = 0.4f; + color1[2] = 0.2f; + color1[3] = 0.3f; + trap_R_SetColor( color1 ); + + // Draw scrolling numbers, use intervals 10 units apart--sorry, this section of code is just kind of hacked + // up with a bunch of magic numbers..... + val = ((int)((cg.refdefViewAngles[YAW] + 180) / 10)) * 10; + off = (cg.refdefViewAngles[YAW] + 180) - val; + + for ( i = -10; i < 30; i += 10 ) + { + val -= 10; + + if ( val < 0 ) + { + val += 360; + } + + // we only want to draw the very far left one some of the time, if it's too far to the left it will + // poke outside the mask. + if (( off > 3.0f && i == -10 ) || i > -10 ) + { + // draw the value, but add 200 just to bump the range up...arbitrary, so change it if you like + CG_DrawNumField( 155 + i * 10 + off * 10, 374, 3, val + 200, 24, 14, NUM_FONT_CHUNKY, qtrue ); + CG_DrawPic( 245 + (i-1) * 10 + off * 10, 376, 6, 6, cgs.media.whiteShader ); + } + } + + CG_DrawPic( 212, 367, 200, 28, cgs.media.binocularOverlay ); + + color1[0] = sin( cg.time * 0.01f ) * 0.5f + 0.5f; + color1[0] = color1[0] * color1[0]; + color1[1] = color1[0]; + color1[2] = color1[0]; + color1[3] = 1.0f; + + trap_R_SetColor( color1 ); + + CG_DrawPic( 82, 94, 16, 16, cgs.media.binocularCircle ); + + // Flickery color + color1[0] = 0.7f + crandom() * 0.1f; + color1[1] = 0.8f + crandom() * 0.1f; + color1[2] = 0.7f + crandom() * 0.1f; + color1[3] = 1.0f; + trap_R_SetColor( color1 ); + + CG_DrawPic( 0, 0, 640, 480, cgs.media.binocularMask ); + + CG_DrawPic( 4, 282 - level, 16, 16, cgs.media.binocularArrow ); + + // The top triangle bit randomly flips + if ( flip ) + { + CG_DrawPic( 330, 60, -26, -30, cgs.media.binocularTri ); + } + else + { + CG_DrawPic( 307, 40, 26, 30, cgs.media.binocularTri ); + } + + if ( random() > 0.98f && ( cg.time & 1024 )) + { + flip = !flip; + } + } + else if ( cg.predictedPlayerState.zoomMode) + { + // disruptor zoom mode + level = (float)(50.0f - zoomFov) / 50.0f;//(float)(80.0f - zoomFov) / 80.0f; + + // ...so we'll clamp it + if ( level < 0.0f ) + { + level = 0.0f; + } + else if ( level > 1.0f ) + { + level = 1.0f; + } + + // Using a magic number to convert the zoom level to a rotation amount that correlates more or less with the zoom artwork. + level *= 103.0f; + + // Draw target mask + trap_R_SetColor( colorTable[CT_WHITE] ); + CG_DrawPic( 0, 0, 640, 480, cgs.media.disruptorMask ); + + // apparently 99.0f is the full zoom level + if ( level >= 99 ) + { + // Fully zoomed, so make the rotating insert pulse + color1[0] = 1.0f; + color1[1] = 1.0f; + color1[2] = 1.0f; + color1[3] = 0.7f + sin( cg.time * 0.01f ) * 0.3f; + + trap_R_SetColor( color1 ); + } + + // Draw rotating insert + CG_DrawRotatePic2( 320, 240, 640, 480, -level, cgs.media.disruptorInsert ); + + // Increase the light levels under the center of the target +// CG_DrawPic( 198, 118, 246, 246, cgs.media.disruptorLight ); + + // weirdness.....converting ammo to a base five number scale just to be geeky. +/* val[0] = ammo % 5; + val[1] = (ammo / 5) % 5; + val[2] = (ammo / 25) % 5; + val[3] = (ammo / 125) % 5; + val[4] = (ammo / 625) % 5; + + color1[0] = 0.2f; + color1[1] = 0.55f + crandom() * 0.1f; + color1[2] = 0.5f + crandom() * 0.1f; + color1[3] = 1.0f; + trap_R_SetColor( color1 ); + + for ( int t = 0; t < 5; t++ ) + { + cx = 320 + sin( (t*10+45)/57.296f ) * 192; + cy = 240 + cos( (t*10+45)/57.296f ) * 192; + + CG_DrawRotatePic2( cx, cy, 24, 38, 45 - t * 10, trap_R_RegisterShader( va("gfx/2d/char%d",val[4-t] ))); + } +*/ + //max = ( cg_entities[0].gent->health / 100.0f ); + + max = cg.snap->ps.ammo[weaponData[WP_DISRUPTOR].ammoIndex] / (float)ammoData[weaponData[WP_DISRUPTOR].ammoIndex].max; + if ( max > 1.0f ) + { + max = 1.0f; + } + + color1[0] = (1.0f - max) * 2.0f; + color1[1] = max * 1.5f; + color1[2] = 0.0f; + color1[3] = 1.0f; + + // If we are low on health, make us flash + if ( max < 0.15f && ( cg.time & 512 )) + { + VectorClear( color1 ); + } + + if ( color1[0] > 1.0f ) + { + color1[0] = 1.0f; + } + + if ( color1[1] > 1.0f ) + { + color1[1] = 1.0f; + } + + trap_R_SetColor( color1 ); + + max *= 58.0f; + + for (fi = 18.5f; fi <= 18.5f + max; fi+= 3 ) // going from 15 to 45 degrees, with 5 degree increments + { + cx = 320 + sin( (fi+90.0f)/57.296f ) * 190; + cy = 240 + cos( (fi+90.0f)/57.296f ) * 190; + + CG_DrawRotatePic2( cx, cy, 12, 24, 90 - fi, cgs.media.disruptorInsertTick ); + } + + if ( cg.predictedPlayerState.weaponstate == WEAPON_CHARGING_ALT ) + { + trap_R_SetColor( colorTable[CT_WHITE] ); + + // draw the charge level + max = ( cg.time - cg.predictedPlayerState.weaponChargeTime ) / ( 50.0f * 30.0f ); // bad hardcodedness 50 is disruptor charge unit and 30 is max charge units allowed. + + if ( max > 1.0f ) + { + max = 1.0f; + } + + trap_R_DrawStretchPic(257, 435, 134*max, 34, 0, 0, max, 1, cgs.media.disruptorChargeShader); + } +// trap_R_SetColor( colorTable[CT_WHITE] ); +// CG_DrawPic( 0, 0, 640, 480, cgs.media.disruptorMask ); + + } +} + + +/* +================ +CG_Draw3DModel + +================ +*/ +void CG_Draw3DModel( float x, float y, float w, float h, qhandle_t model, qhandle_t skin, vec3_t origin, vec3_t angles ) { + refdef_t refdef; + refEntity_t ent; + + if ( !cg_draw3dIcons.integer || !cg_drawIcons.integer ) { + return; + } + + memset( &refdef, 0, sizeof( refdef ) ); + + memset( &ent, 0, sizeof( ent ) ); + AnglesToAxis( angles, ent.axis ); + VectorCopy( origin, ent.origin ); + ent.hModel = model; + ent.customSkin = skin; + ent.renderfx = RF_NOSHADOW; // no stencil shadows + + refdef.rdflags = RDF_NOWORLDMODEL; + + AxisClear( refdef.viewaxis ); + + refdef.fov_x = 30; + refdef.fov_y = 30; + + refdef.x = x; + refdef.y = y; + refdef.width = w; + refdef.height = h; + + refdef.time = cg.time; + + trap_R_ClearScene(); + trap_R_AddRefEntityToScene( &ent ); + trap_R_RenderScene( &refdef ); +} + +/* +================ +CG_DrawHead + +Used for both the status bar and the scoreboard +================ +*/ +void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ) +{ + clientInfo_t *ci; + + ci = &cgs.clientinfo[ clientNum ]; + + CG_DrawPic( x, y, w, h, ci->modelIcon ); + + // if they are deferred, draw a cross out + if ( ci->deferred ) + { + CG_DrawPic( x, y, w, h, cgs.media.deferShader ); + } +} + +/* +================ +CG_DrawFlagModel + +Used for both the status bar and the scoreboard +================ +*/ +void CG_DrawFlagModel( float x, float y, float w, float h, int team, qboolean force2D ) { + qhandle_t cm; + float len; + vec3_t origin, angles; + vec3_t mins, maxs; + qhandle_t handle; + + if ( !force2D && cg_draw3dIcons.integer ) { + + VectorClear( angles ); + + cm = cgs.media.redFlagModel; + + // offset the origin y and z to center the flag + trap_R_ModelBounds( cm, mins, maxs ); + + origin[2] = -0.5 * ( mins[2] + maxs[2] ); + origin[1] = 0.5 * ( mins[1] + maxs[1] ); + + // calculate distance so the flag nearly fills the box + // assume heads are taller than wide + len = 0.5 * ( maxs[2] - mins[2] ); + origin[0] = len / 0.268; // len / tan( fov/2 ) + + angles[YAW] = 60 * sin( cg.time / 2000.0 );; + + if( team == TEAM_RED ) { + handle = cgs.media.redFlagModel; + } else if( team == TEAM_BLUE ) { + handle = cgs.media.blueFlagModel; + } else if( team == TEAM_FREE ) { + handle = cgs.media.neutralFlagModel; + } else { + return; + } + CG_Draw3DModel( x, y, w, h, handle, 0, origin, angles ); + } else if ( cg_drawIcons.integer ) { + gitem_t *item; + + if( team == TEAM_RED ) { + item = BG_FindItemForPowerup( PW_REDFLAG ); + } else if( team == TEAM_BLUE ) { + item = BG_FindItemForPowerup( PW_BLUEFLAG ); + } else if( team == TEAM_FREE ) { + item = BG_FindItemForPowerup( PW_NEUTRALFLAG ); + } else { + return; + } + if (item) { + CG_DrawPic( x, y, w, h, cg_items[ ITEM_INDEX(item) ].icon ); + } + } +} + +/* +================ +DrawAmmo +================ +*/ +void DrawAmmo() +{ + int x, y; + + x = SCREEN_WIDTH-80; + y = SCREEN_HEIGHT-80; + +} + +/* +================ +CG_DrawHUDLeftFrame1 +================ +*/ +void CG_DrawHUDLeftFrame1(int x,int y) +{ + // Inner gray wire frame + trap_R_SetColor( hudTintColor ); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDInnerLeft ); +} + +/* +================ +CG_DrawHUDLeftFrame2 +================ +*/ +void CG_DrawHUDLeftFrame2(int x,int y) +{ + // Inner gray wire frame + trap_R_SetColor( hudTintColor ); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDLeftFrame ); // Metal frame +} + +/* +================ +DrawHealthArmor +================ +*/ +void DrawHealthArmor(int x,int y) +{ + vec4_t calcColor; + float armorPercent,hold,healthPercent; + playerState_t *ps; + + int healthAmt; + int armorAmt; + + ps = &cg.snap->ps; + + healthAmt = ps->stats[STAT_HEALTH]; + armorAmt = ps->stats[STAT_ARMOR]; + + if (healthAmt > ps->stats[STAT_MAX_HEALTH]) + { + healthAmt = ps->stats[STAT_MAX_HEALTH]; + } + + if (armorAmt > 100) + { + armorAmt = 100; + } + + trap_R_SetColor( colorTable[CT_WHITE] ); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDLeftFrame ); // Circular black background + + // Outer Armor circular + memcpy(calcColor, colorTable[CT_GREEN], sizeof(vec4_t)); + + hold = armorAmt-(ps->stats[STAT_MAX_HEALTH]/2); + armorPercent = (float) hold/(ps->stats[STAT_MAX_HEALTH]/2); + if (armorPercent <0) + { + armorPercent = 0; + } + calcColor[0] *= armorPercent; + calcColor[1] *= armorPercent; + calcColor[2] *= armorPercent; + trap_R_SetColor( calcColor); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDArmor1 ); + + // Inner Armor circular + if (armorPercent>0) + { + armorPercent = 1; + } + else + { + armorPercent = (float) armorAmt/(ps->stats[STAT_MAX_HEALTH]/2); + } + memcpy(calcColor, colorTable[CT_GREEN], sizeof(vec4_t)); + calcColor[0] *= armorPercent; + calcColor[1] *= armorPercent; + calcColor[2] *= armorPercent; + trap_R_SetColor( calcColor); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDArmor2 ); // Inner Armor circular + + if (ps->stats[STAT_ARMOR]) // Is there armor? Draw the HUD Armor TIC + { + // Make tic flash if inner armor is at 50% (25% of full armor) + if (armorPercent<.5) // Do whatever the flash timer says + { + if (cg.HUDTickFlashTime < cg.time) // Flip at the same time + { + cg.HUDTickFlashTime = cg.time + 100; + if (cg.HUDArmorFlag) + { + cg.HUDArmorFlag = qfalse; + } + else + { + cg.HUDArmorFlag = qtrue; + } + } + } + else + { + cg.HUDArmorFlag=qtrue; + } + } + else // No armor? Don't show it. + { + cg.HUDArmorFlag=qfalse; + } + + memcpy(calcColor, colorTable[CT_RED], sizeof(vec4_t)); + healthPercent = (float) healthAmt/ps->stats[STAT_MAX_HEALTH]; + calcColor[0] *= healthPercent; + calcColor[1] *= healthPercent; + calcColor[2] *= healthPercent; + trap_R_SetColor( calcColor); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDHealth ); + + // Make tic flash if health is at 20% of full + if (healthPercent>.20) + { + cg.HUDHealthFlag=qtrue; + } + else + { + if (cg.HUDTickFlashTime < cg.time) // Flip at the same time + { + cg.HUDTickFlashTime = cg.time + 100; + + if ((armorPercent>0) && (armorPercent<.5)) // Keep the tics in sync if flashing + { + cg.HUDHealthFlag=cg.HUDArmorFlag; + } + else + { + if (cg.HUDHealthFlag) + { + cg.HUDHealthFlag = qfalse; + } + else + { + cg.HUDHealthFlag = qtrue; + } + } + } + } + + // Draw the ticks + if (cg.HUDHealthFlag) + { + trap_R_SetColor( colorTable[CT_RED] ); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDHealthTic ); + } + + if (cg.HUDArmorFlag) + { + trap_R_SetColor( colorTable[CT_GREEN] ); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDArmorTic ); // + } + + trap_R_SetColor(hudTintColor); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDLeftStatic ); // + + trap_R_SetColor( colorTable[CT_RED] ); + CG_DrawNumField (x + 16, y + 40, 3, ps->stats[STAT_HEALTH], 14, 18, + NUM_FONT_SMALL,qfalse); + + trap_R_SetColor( colorTable[CT_GREEN] ); + CG_DrawNumField (x + 18 + 14, y + 40 + 14, 3, ps->stats[STAT_ARMOR], 14, 18, + NUM_FONT_SMALL,qfalse); + + trap_R_SetColor(hudTintColor ); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDLeft ); // Metal frame +} + +/* +================ +CG_DrawHealth +================ +*/ +void CG_DrawHealth(int x,int y) +{ + vec4_t calcColor; + float healthPercent; + playerState_t *ps; + int healthAmt; + + ps = &cg.snap->ps; + + healthAmt = ps->stats[STAT_HEALTH]; + + if (healthAmt > ps->stats[STAT_MAX_HEALTH]) + { + healthAmt = ps->stats[STAT_MAX_HEALTH]; + } + + memcpy(calcColor, colorTable[CT_HUD_RED], sizeof(vec4_t)); + healthPercent = (float) healthAmt/ps->stats[STAT_MAX_HEALTH]; + calcColor[0] *= healthPercent; + calcColor[1] *= healthPercent; + calcColor[2] *= healthPercent; + trap_R_SetColor( calcColor); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDHealth ); + + // Draw the ticks + if (cg.HUDHealthFlag) + { + trap_R_SetColor( colorTable[CT_HUD_RED] ); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDHealthTic ); + } + + trap_R_SetColor( colorTable[CT_HUD_RED] ); + CG_DrawNumField (x + 16, y + 40, 3, ps->stats[STAT_HEALTH], 6, 12, + NUM_FONT_SMALL,qfalse); + +} + +/* +================ +CG_DrawArmor +================ +*/ +void CG_DrawArmor(int x,int y) +{ + vec4_t calcColor; + float armorPercent,hold; + playerState_t *ps; + int armor; + + ps = &cg.snap->ps; + + // Outer Armor circular + memcpy(calcColor, colorTable[CT_HUD_GREEN], sizeof(vec4_t)); + + armor =ps->stats[STAT_ARMOR]; + + if (armor> ps->stats[STAT_MAX_HEALTH]) + { + armor = ps->stats[STAT_MAX_HEALTH]; + } + + hold = armor-(ps->stats[STAT_MAX_HEALTH]/2); + armorPercent = (float) hold/(ps->stats[STAT_MAX_HEALTH]/2); + if (armorPercent <0) + { + armorPercent = 0; + } + calcColor[0] *= armorPercent; + calcColor[1] *= armorPercent; + calcColor[2] *= armorPercent; + trap_R_SetColor( calcColor); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDArmor1 ); + + // Inner Armor circular + if (armorPercent>0) + { + armorPercent = 1; + } + else + { + armorPercent = (float) ps->stats[STAT_ARMOR]/(ps->stats[STAT_MAX_HEALTH]/2); + } + memcpy(calcColor, colorTable[CT_HUD_GREEN], sizeof(vec4_t)); + calcColor[0] *= armorPercent; + calcColor[1] *= armorPercent; + calcColor[2] *= armorPercent; + trap_R_SetColor( calcColor); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDArmor2 ); // Inner Armor circular + + if (ps->stats[STAT_ARMOR]) // Is there armor? Draw the HUD Armor TIC + { + // Make tic flash if inner armor is at 50% (25% of full armor) + if (armorPercent<.5) // Do whatever the flash timer says + { + if (cg.HUDTickFlashTime < cg.time) // Flip at the same time + { + cg.HUDTickFlashTime = cg.time + 100; + if (cg.HUDArmorFlag) + { + cg.HUDArmorFlag = qfalse; + } + else + { + cg.HUDArmorFlag = qtrue; + } + } + } + else + { + cg.HUDArmorFlag=qtrue; + } + } + else // No armor? Don't show it. + { + cg.HUDArmorFlag=qfalse; + } + + if (cg.HUDArmorFlag) + { + trap_R_SetColor( colorTable[CT_HUD_GREEN] ); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDArmorTic ); + } + + trap_R_SetColor( colorTable[CT_HUD_GREEN] ); + CG_DrawNumField (x + 18 + 14, y + 40 + 14, 3, ps->stats[STAT_ARMOR], 6, 12, + NUM_FONT_SMALL,qfalse); + +} + +/* +================ +CG_DrawHUDRightFrame1 +================ +*/ +void CG_DrawHUDRightFrame1(int x,int y) +{ + trap_R_SetColor( hudTintColor ); + // Inner gray wire frame + CG_DrawPic( x, y, 80, 80, cgs.media.HUDInnerRight ); // +} + +/* +================ +CG_DrawHUDRightFrame2 +================ +*/ +void CG_DrawHUDRightFrame2(int x,int y) +{ + trap_R_SetColor( hudTintColor ); + CG_DrawPic( x, y, 80, 80, cgs.media.HUDRightFrame ); // Metal frame +} + +/* +================ +CG_DrawAmmo +================ +*/ +static void CG_DrawAmmo(centity_t *cent,int x,int y) +{ + playerState_t *ps; + int numColor_i; + int i; + vec4_t calcColor; + float value,inc,percent; + + ps = &cg.snap->ps; + + if (!cent->currentState.weapon ) // We don't have a weapon right now + { + return; + } + + if ( cent->currentState.weapon == WP_SABER ) + { + trap_R_SetColor( colorTable[CT_WHITE] ); + // don't need to draw ammo, but we will draw the current saber style in this window + switch ( cg.predictedPlayerState.fd.saberDrawAnimLevel ) + { + case 1://FORCE_LEVEL_1: + CG_DrawPic( x, y, 80, 40, cgs.media.HUDSaberStyle1 ); + break; + case 2://FORCE_LEVEL_2: + CG_DrawPic( x, y, 80, 40, cgs.media.HUDSaberStyle2 ); + break; + case 3://FORCE_LEVEL_3: + CG_DrawPic( x, y, 80, 40, cgs.media.HUDSaberStyle3 ); + break; + } + return; + } + else + { + value = ps->ammo[weaponData[cent->currentState.weapon].ammoIndex]; + } + + if (value < 0) // No ammo + { + return; + } + + + // + // ammo + // +/* if (cg.oldammo < value) + { + cg.oldAmmoTime = cg.time + 200; + } + + cg.oldammo = value; +*/ + // Firing or reloading? +/* if (( pm->ps->weaponstate == WEAPON_FIRING + && cg.predictedPlayerState.weaponTime > 100 )) + { + numColor_i = CT_LTGREY; + } */ + // Overcharged? +// else if ( cent->gent->s.powerups & ( 1 << PW_WEAPON_OVERCHARGE ) ) +// { +// numColor_i = CT_WHITE; +// } +// else +// { +// if ( value > 0 ) +// { +// if (cg.oldAmmoTime > cg.time) +// { +// numColor_i = CT_YELLOW; +// } +// else +// { +// numColor_i = CT_HUD_ORANGE; +// } +// } +// else +// { +// numColor_i = CT_RED; +// } +// } + + numColor_i = CT_HUD_ORANGE; + + trap_R_SetColor( colorTable[numColor_i] ); + CG_DrawNumField (x + 30, y + 26, 3, value, 6, 12, NUM_FONT_SMALL,qfalse); + + +//cg.snap->ps.ammo[weaponData[cg.snap->ps.weapon].ammoIndex] + + inc = (float) ammoData[weaponData[cent->currentState.weapon].ammoIndex].max / MAX_TICS; + value =ps->ammo[weaponData[cent->currentState.weapon].ammoIndex]; + + for (i=MAX_TICS-1;i>=0;i--) + { + + if (value <= 0) // partial tic + { + memcpy(calcColor, colorTable[CT_BLACK], sizeof(vec4_t)); + } + else if (value < inc) // partial tic + { + memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t)); + percent = value / inc; + calcColor[0] *= percent; + calcColor[1] *= percent; + calcColor[2] *= percent; + } + else + { + memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t)); + } + + trap_R_SetColor( calcColor); + CG_DrawPic( x + ammoTicPos[i].x, + y + ammoTicPos[i].y, + ammoTicPos[i].width, + ammoTicPos[i].height, + ammoTicPos[i].tic ); + + value -= inc; + } + +} + +/* +================ +CG_DrawForcePower +================ +*/ +void CG_DrawForcePower(int x,int y) +{ + int i; + vec4_t calcColor; + float value,inc,percent; + + inc = (float) 100 / MAX_TICS; + value = cg.snap->ps.fd.forcePower; + + for (i=MAX_TICS-1;i>=0;i--) + { + + if (value <= 0) // partial tic + { + memcpy(calcColor, colorTable[CT_BLACK], sizeof(vec4_t)); + } + else if (value < inc) // partial tic + { + memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t)); + percent = value / inc; + calcColor[0] *= percent; + calcColor[1] *= percent; + calcColor[2] *= percent; + } + else + { + memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t)); + } + + trap_R_SetColor( calcColor); + CG_DrawPic( x + forceTicPos[i].x, + y + forceTicPos[i].y, + forceTicPos[i].width, + forceTicPos[i].height, + forceTicPos[i].tic ); + + value -= inc; + } +} + +/* +================ +CG_DrawHUD +================ +*/ +void CG_DrawHUD(centity_t *cent) +{ + menuDef_t *menuHUD = NULL; + const char *scoreStr = NULL; + int scoreBias; + char scoreBiasStr[16]; + + if (cg_hudFiles.integer) + { + int x = 0; + int y = SCREEN_HEIGHT-80; + char ammoString[64]; + int weapX = x; + + UI_DrawProportionalString( x+16, y+40, va( "%i", cg.snap->ps.stats[STAT_HEALTH] ), + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_HUD_RED] ); + + UI_DrawProportionalString( x+18+14, y+40+14, va( "%i", cg.snap->ps.stats[STAT_ARMOR] ), + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_HUD_GREEN] ); + + if (cg.snap->ps.weapon == WP_SABER) + { + if (cg.snap->ps.fd.saberDrawAnimLevel == FORCE_LEVEL_3) + { + Com_sprintf(ammoString, sizeof(ammoString), "STRONG"); + weapX += 16; + } + else if (cg.snap->ps.fd.saberDrawAnimLevel == FORCE_LEVEL_2) + { + Com_sprintf(ammoString, sizeof(ammoString), "MEDIUM"); + weapX += 16; + } + else + { + Com_sprintf(ammoString, sizeof(ammoString), "FAST"); + } + } + else + { + Com_sprintf(ammoString, sizeof(ammoString), "%i", cg.snap->ps.ammo[weaponData[cent->currentState.weapon].ammoIndex]); + } + + UI_DrawProportionalString( SCREEN_WIDTH-(weapX+16+32), y+40, va( "%s", ammoString ), + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_HUD_ORANGE] ); + + UI_DrawProportionalString( SCREEN_WIDTH-(x+18+14+32), y+40+14, va( "%i", cg.snap->ps.fd.forcePower), + UI_SMALLFONT|UI_DROPSHADOW, colorTable[CT_ICON_BLUE] ); + + return; + } + + if (cgs.gametype >= GT_TEAM) + { // tint the hud items based on team + if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) + hudTintColor = redhudtint; + else if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) + hudTintColor = bluehudtint; + else // If we're not on a team for whatever reason, leave things as they are. + hudTintColor = colorTable[CT_WHITE]; + } + else + { // tint the hud items white (dont' tint) + hudTintColor = colorTable[CT_WHITE]; + } + + menuHUD = Menus_FindByName("lefthud"); + if (menuHUD) + { + CG_DrawHUDLeftFrame1(menuHUD->window.rect.x,menuHUD->window.rect.y); + CG_DrawArmor(menuHUD->window.rect.x,menuHUD->window.rect.y); + CG_DrawHealth(menuHUD->window.rect.x,menuHUD->window.rect.y); + CG_DrawHUDLeftFrame2(menuHUD->window.rect.x,menuHUD->window.rect.y); + } + else + { //Apparently we failed to get proper coordinates from the menu, so resort to manually inputting them. + CG_DrawHUDLeftFrame1(0,SCREEN_HEIGHT-80); + CG_DrawArmor(0,SCREEN_HEIGHT-80); + CG_DrawHealth(0,SCREEN_HEIGHT-80); + CG_DrawHUDLeftFrame2(0,SCREEN_HEIGHT-80); + } + + //scoreStr = va("Score: %i", cgs.clientinfo[cg.snap->ps.clientNum].score); + if (0 && cgs.gametype < GT_TEAM ) + { // This is a teamless mode, draw the score bias. + scoreBias = cg.snap->ps.persistant[PERS_SCORE] - cgs.scores1; + if (scoreBias == 0) + { // We are the leader! + if (cgs.scores2 <= 0) + { // Nobody to be ahead of yet. + Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), ""); + } + else + { + scoreBias = cg.snap->ps.persistant[PERS_SCORE] - cgs.scores2; + if (scoreBias == 0) + { + Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), " (Tie)"); + } + else + { + Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), " (+%d)", scoreBias); + } + } + } + else // if (scoreBias < 0) + { // We are behind! + Com_sprintf(scoreBiasStr, sizeof(scoreBiasStr), " (%d)", scoreBias); + } + scoreStr = va("Score: %i%s", cg.snap->ps.persistant[PERS_SCORE], scoreBiasStr); + } + else + { // Don't draw a bias. + scoreStr = va("Score: %i", cg.snap->ps.persistant[PERS_SCORE]); + } + UI_DrawScaledProportionalString(SCREEN_WIDTH-124/*(strlen(scoreStr)*20.5)*/, SCREEN_HEIGHT-23, scoreStr, UI_RIGHT|UI_DROPSHADOW, colorTable[CT_WHITE], 0.7); + + menuHUD = Menus_FindByName("righthud"); + if (menuHUD) + { + CG_DrawHUDRightFrame1(menuHUD->window.rect.x,menuHUD->window.rect.y); + CG_DrawForcePower(menuHUD->window.rect.x,menuHUD->window.rect.y); + CG_DrawAmmo(cent,menuHUD->window.rect.x,menuHUD->window.rect.y); + CG_DrawHUDRightFrame2(menuHUD->window.rect.x,menuHUD->window.rect.y); + + } + else + { //Apparently we failed to get proper coordinates from the menu, so resort to manually inputting them. + CG_DrawHUDRightFrame1(SCREEN_WIDTH-80,SCREEN_HEIGHT-80); + CG_DrawForcePower(SCREEN_WIDTH-80,SCREEN_HEIGHT-80); + CG_DrawAmmo(cent,SCREEN_WIDTH-80,SCREEN_HEIGHT-80); + CG_DrawHUDRightFrame2(SCREEN_WIDTH-80,SCREEN_HEIGHT-80); + } +} + +#define MAX_SHOWPOWERS NUM_FORCE_POWERS + +qboolean ForcePower_Valid(int i) +{ + if (i == FP_LEVITATION || + i == FP_SABERATTACK || + i == FP_SABERDEFEND || + i == FP_SABERTHROW) + { + return qfalse; + } + + if (cg.snap->ps.fd.forcePowersKnown & (1 << i)) + { + return qtrue; + } + + return qfalse; +} + +/* +=================== +CG_DrawForceSelect +=================== +*/ +void CG_DrawForceSelect( void ) +{ + int i; + int count; + int smallIconSize,bigIconSize; + int holdX,x,y,x2,y2,pad,length; + int sideLeftIconCnt,sideRightIconCnt; + int sideMax,holdCount,iconCnt; + + + x2 = 0; + y2 = 0; + + // don't display if dead + if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) + { + return; + } + + if ((cg.forceSelectTime+WEAPON_SELECT_TIME)ps.fd.forcePowerSelected; + return; + } + + if (!cg.snap->ps.fd.forcePowersKnown) + { + return; + } + + // count the number of powers owned + count = 0; + + for (i=0;i < NUM_FORCE_POWERS;++i) + { + if (ForcePower_Valid(i)) + { + count++; + } + } + + if (count == 0) // If no force powers, 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; + } + + smallIconSize = 30; + bigIconSize = 60; + pad = 12; + + x = 320; + y = 425; + + // Background + length = (sideLeftIconCnt * smallIconSize) + (sideLeftIconCnt*pad) + + bigIconSize + (sideRightIconCnt * smallIconSize) + (sideRightIconCnt*pad) + 12; + + i = BG_ProperForceIndex(cg.forceSelect) - 1; + if (i < 0) + { + i = MAX_SHOWPOWERS; + } + + trap_R_SetColor(NULL); + // Work backwards from current icon + holdX = x - ((bigIconSize/2) + pad + smallIconSize); + for (iconCnt=1;iconCnt<(sideLeftIconCnt+1);i--) + { + if (i < 0) + { + i = MAX_SHOWPOWERS; + } + + if (!ForcePower_Valid(forcePowerSorted[i])) // Does he have this power? + { + continue; + } + + ++iconCnt; // Good icon + + if (cgs.media.forcePowerIcons[forcePowerSorted[i]]) + { + CG_DrawPic( holdX, y, smallIconSize, smallIconSize, cgs.media.forcePowerIcons[forcePowerSorted[i]] ); + holdX -= (smallIconSize+pad); + } + } + + if (ForcePower_Valid(cg.forceSelect)) + { + // Current Center Icon + if (cgs.media.forcePowerIcons[cg.forceSelect]) + { + CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2)), bigIconSize, bigIconSize, cgs.media.forcePowerIcons[cg.forceSelect] ); //only cache the icon for display + } + } + + i = BG_ProperForceIndex(cg.forceSelect) + 1; + if (i>MAX_SHOWPOWERS) + { + i = 0; + } + + // Work forwards from current icon + holdX = x + (bigIconSize/2) + pad; + for (iconCnt=1;iconCnt<(sideRightIconCnt+1);i++) + { + if (i>MAX_SHOWPOWERS) + { + i = 0; + } + + if (!ForcePower_Valid(forcePowerSorted[i])) // Does he have this power? + { + continue; + } + + ++iconCnt; // Good icon + + if (cgs.media.forcePowerIcons[forcePowerSorted[i]]) + { + CG_DrawPic( holdX, y, smallIconSize, smallIconSize, cgs.media.forcePowerIcons[forcePowerSorted[i]] ); //only cache the icon for display + holdX += (smallIconSize+pad); + } + } + + if ( showPowersName[cg.forceSelect] ) + { + UI_DrawProportionalString(320, y + 30, CG_GetStripEdString("INGAME", showPowersName[cg.forceSelect]), UI_CENTER | UI_SMALLFONT, colorTable[CT_ICON_BLUE]); + } +} + +/* +=================== +CG_DrawInventorySelect +=================== +*/ +void CG_DrawInvenSelect( void ) +{ + int i; + int sideMax,holdCount,iconCnt; + int smallIconSize,bigIconSize; + int sideLeftIconCnt,sideRightIconCnt; + int count; + int holdX,x,y,y2,pad; + int height; + float addX; + + // don't display if dead + if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) + { + return; + } + + if ((cg.invenSelectTime+WEAPON_SELECT_TIME)ps.stats[STAT_HOLDABLE_ITEM] || !cg.snap->ps.stats[STAT_HOLDABLE_ITEMS]) + { + return; + } + + if (cg.itemSelect == -1) + { + cg.itemSelect = bg_itemlist[cg.snap->ps.stats[STAT_HOLDABLE_ITEM]].giTag; + } + +//const int bits = cg.snap->ps.stats[ STAT_ITEMS ]; + + // count the number of items owned + count = 0; + for ( i = 0 ; i < HI_NUM_HOLDABLE ; i++ ) + { + if (/*CG_InventorySelectable(i) && inv_icons[i]*/ + (cg.snap->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << i)) ) + { + count++; + } + } + + if (!count) + { + y2 = 0; //err? + UI_DrawProportionalString(320, y2 + 22, "EMPTY INVENTORY", UI_CENTER | UI_SMALLFONT, colorTable[CT_ICON_BLUE]); + 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.itemSelect - 1; + if (i<0) + { + i = HI_NUM_HOLDABLE-1; + } + + smallIconSize = 40; + bigIconSize = 80; + pad = 16; + + x = 320; + y = 410; + + // Left side ICONS + // Work backwards from current icon + holdX = x - ((bigIconSize/2) + pad + smallIconSize); + height = smallIconSize * cg.iconHUDPercent; + addX = (float) smallIconSize * .75; + + for (iconCnt=0;iconCntps.stats[STAT_HOLDABLE_ITEMS] & (1 << i)) || i == cg.itemSelect ) + { + continue; + } + + ++iconCnt; // Good icon + + if (cgs.media.invenIcons[i]) + { + trap_R_SetColor(NULL); + CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, cgs.media.invenIcons[i] ); + + trap_R_SetColor(colorTable[CT_ICON_BLUE]); + /*CG_DrawNumField (holdX + addX, y + smallIconSize, 2, cg.snap->ps.inventory[i], 6, 12, + NUM_FONT_SMALL,qfalse); + */ + + holdX -= (smallIconSize+pad); + } + } + + // Current Center Icon + height = bigIconSize * cg.iconHUDPercent; + if (cgs.media.invenIcons[cg.itemSelect]) + { + int itemNdex; + trap_R_SetColor(NULL); + CG_DrawPic( x-(bigIconSize/2), (y-((bigIconSize-smallIconSize)/2))+10, bigIconSize, bigIconSize, cgs.media.invenIcons[cg.itemSelect] ); + addX = (float) bigIconSize * .75; + trap_R_SetColor(colorTable[CT_ICON_BLUE]); + /*CG_DrawNumField ((x-(bigIconSize/2)) + addX, y, 2, cg.snap->ps.inventory[cg.inventorySelect], 6, 12, + NUM_FONT_SMALL,qfalse);*/ + + itemNdex = BG_GetItemIndexByTag(cg.itemSelect, IT_HOLDABLE); + if (bg_itemlist[itemNdex].classname) + { + vec4_t textColor = { .312f, .75f, .621f, 1.0f }; + char text[1024]; + + if ( trap_SP_GetStringTextString( va("INGAME_%s",bg_itemlist[itemNdex].classname), text, sizeof( text ))) + { + UI_DrawProportionalString(320, y+45, text, UI_CENTER | UI_SMALLFONT, textColor); + } + else + { + UI_DrawProportionalString(320, y+45, bg_itemlist[itemNdex].classname, UI_CENTER | UI_SMALLFONT, textColor); + } + } + } + + i = cg.itemSelect + 1; + if (i> HI_NUM_HOLDABLE-1) + { + i = 0; + } + + // Right side ICONS + // Work forwards from current icon + holdX = x + (bigIconSize/2) + pad; + height = smallIconSize * cg.iconHUDPercent; + addX = (float) smallIconSize * .75; + for (iconCnt=0;iconCnt HI_NUM_HOLDABLE-1) + { + i = 0; + } + + if ( !(cg.snap->ps.stats[STAT_HOLDABLE_ITEMS] & (1 << i)) || i == cg.itemSelect ) + { + continue; + } + + ++iconCnt; // Good icon + + if (cgs.media.invenIcons[i]) + { + trap_R_SetColor(NULL); + CG_DrawPic( holdX, y+10, smallIconSize, smallIconSize, cgs.media.invenIcons[i] ); + + trap_R_SetColor(colorTable[CT_ICON_BLUE]); + /*CG_DrawNumField (holdX + addX, y + smallIconSize, 2, cg.snap->ps.inventory[i], 6, 12, + NUM_FONT_SMALL,qfalse);*/ + + holdX += (smallIconSize+pad); + } + } +} + +/* +================ +CG_DrawStats + +================ +*/ +static void CG_DrawStats( void ) +{ + centity_t *cent; +/* playerState_t *ps; + vec3_t angles; +// vec3_t origin; + + if ( cg_drawStatus.integer == 0 ) { + return; + } +*/ + cent = &cg_entities[cg.snap->ps.clientNum]; +/* ps = &cg.snap->ps; + + VectorClear( angles ); + + // Do start + if (!cg.interfaceStartupDone) + { + CG_InterfaceStartup(); + } + + cgi_UI_MenuPaintAll();*/ + + CG_DrawHUD(cent); + /*CG_DrawArmor(cent); + CG_DrawHealth(cent); + CG_DrawAmmo(cent); + + CG_DrawTalk(cent);*/ +} + + +/* +================ +CG_DrawTeamBackground + +================ +*/ +void CG_DrawTeamBackground( int x, int y, int w, int h, float alpha, int team ) +{ + vec4_t hcolor; + + hcolor[3] = alpha; + if ( team == TEAM_RED ) { + hcolor[0] = 1; + hcolor[1] = .2f; + hcolor[2] = .2f; + } else if ( team == TEAM_BLUE ) { + hcolor[0] = .2f; + hcolor[1] = .2f; + hcolor[2] = 1; + } else { + return; + } +// trap_R_SetColor( hcolor ); + + CG_FillRect ( x, y, w, h, hcolor ); +// CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar ); + trap_R_SetColor( NULL ); +} + + +/* +=========================================================================================== + + UPPER RIGHT CORNER + +=========================================================================================== +*/ + +/* +================ +CG_DrawMiniScoreboard +================ +*/ +static float CG_DrawMiniScoreboard ( float y ) +{ + char temp[MAX_QPATH]; + + if ( !cg_drawScores.integer ) + { + return y; + } + + if ( cgs.gametype >= GT_TEAM ) + { + strcpy ( temp, "Red: " ); + Q_strcat ( temp, MAX_QPATH, cgs.scores1==SCORE_NOT_PRESENT?"-":(va("%i",cgs.scores1)) ); + Q_strcat ( temp, MAX_QPATH, " Blue: " ); + Q_strcat ( temp, MAX_QPATH, cgs.scores2==SCORE_NOT_PRESENT?"-":(va("%i",cgs.scores2)) ); + + CG_Text_Paint( 630 - CG_Text_Width ( temp, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, temp, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM ); + y += 15; + } + else + { + /* + strcpy ( temp, "1st: " ); + Q_strcat ( temp, MAX_QPATH, cgs.scores1==SCORE_NOT_PRESENT?"-":(va("%i",cgs.scores1)) ); + + Q_strcat ( temp, MAX_QPATH, " 2nd: " ); + Q_strcat ( temp, MAX_QPATH, cgs.scores2==SCORE_NOT_PRESENT?"-":(va("%i",cgs.scores2)) ); + + CG_Text_Paint( 630 - CG_Text_Width ( temp, 0.7f, FONT_SMALL ), y, 0.7f, colorWhite, temp, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM ); + y += 15; + */ + //rww - no longer doing this. Since the attacker now shows who is first, we print the score there. + } + + + return y; +} + +/* +================ +CG_DrawEnemyInfo +================ +*/ +static float CG_DrawEnemyInfo ( float y ) +{ + float size; + int clientNum; + const char *title; + clientInfo_t *ci; + + if ( !cg_drawEnemyInfo.integer ) + { + return y; + } + + if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) + { + return y; + } + + if ( cgs.gametype == GT_JEDIMASTER ) + { + title = "Jedi Master"; + clientNum = cgs.jediMaster; + + if ( clientNum < 0 ) + { + //return y; + title = "Get Saber!"; + + size = ICON_SIZE * 1.25; + y += 5; + + CG_DrawPic( 640 - size - 12, y, size, size, cgs.media.weaponIcons[WP_SABER] ); + + y += size; + + /* + CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, ci->name, 0, 0, 0, FONT_MEDIUM ); + y += 15; + */ + + CG_Text_Paint( 630 - CG_Text_Width ( title, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, title, 0, 0, 0, FONT_MEDIUM ); + + return y + BIGCHAR_HEIGHT + 2; + } + } + else if ( cg.snap->ps.duelInProgress ) + { + title = "Dueling"; + clientNum = cg.snap->ps.duelIndex; + } + else if ( cgs.gametype == GT_TOURNAMENT && cgs.clientinfo[cg.snap->ps.clientNum].team != TEAM_SPECTATOR) + { + title = "Dueling"; + if (cg.snap->ps.clientNum == cgs.duelist1) + { + clientNum = cgs.duelist2; + } + else if (cg.snap->ps.clientNum == cgs.duelist2) + { + clientNum = cgs.duelist1; + } + else + { + return y; + } + } + else + { + /* + title = "Attacker"; + clientNum = cg.predictedPlayerState.persistant[PERS_ATTACKER]; + + if ( clientNum < 0 || clientNum >= MAX_CLIENTS || clientNum == cg.snap->ps.clientNum ) + { + return y; + } + + if ( cg.time - cg.attackerTime > ATTACKER_HEAD_TIME ) + { + cg.attackerTime = 0; + return y; + } + */ + //As of current, we don't want to draw the attacker. Instead, draw whoever is in first place. + if (cgs.duelWinner < 0 || cgs.duelWinner >= MAX_CLIENTS) + { + return y; + } + + + title = va("%s: %i",CG_GetStripEdString("INGAMETEXT", "LEADER"), cgs.scores1); + + /* + if (cgs.scores1 == 1) + { + title = va("%i kill", cgs.scores1); + } + else + { + title = va("%i kills", cgs.scores1); + } + */ + clientNum = cgs.duelWinner; + } + + ci = &cgs.clientinfo[ clientNum ]; + + if (!ci || !ci->modelIcon) + { + return y; + } + + size = ICON_SIZE * 1.25; + y += 5; + + CG_DrawPic( 640 - size - 5, y, size, size, ci->modelIcon ); + + y += size; + + CG_Text_Paint( 630 - CG_Text_Width ( ci->name, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, ci->name, 0, 0, 0, FONT_MEDIUM ); + + y += 15; + CG_Text_Paint( 630 - CG_Text_Width ( title, 0.7f, FONT_MEDIUM ), y, 0.7f, colorWhite, title, 0, 0, 0, FONT_MEDIUM ); + + return y + BIGCHAR_HEIGHT + 2; +} + +/* +================== +CG_DrawSnapshot +================== +*/ +static float CG_DrawSnapshot( float y ) { + char *s; + int w; + + s = va( "time:%i snap:%i cmd:%i", cg.snap->serverTime, + cg.latestSnapshotNum, cgs.serverCommandSequence ); + w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + + CG_DrawBigString( 635 - w, y + 2, s, 1.0F); + + return y + BIGCHAR_HEIGHT + 4; +} + +/* +================== +CG_DrawFPS +================== +*/ +#define FPS_FRAMES 4 +static float CG_DrawFPS( float y ) { + char *s; + int w; + static int previousTimes[FPS_FRAMES]; + static int index; + int i, total; + int fps; + static int previous; + int t, frameTime; + + // don't use serverTime, because that will be drifting to + // correct for internet lag changes, timescales, timedemos, etc + t = trap_Milliseconds(); + frameTime = t - previous; + previous = t; + + previousTimes[index % FPS_FRAMES] = frameTime; + index++; + if ( index > FPS_FRAMES ) { + // average multiple frames together to smooth changes out a bit + total = 0; + for ( i = 0 ; i < FPS_FRAMES ; i++ ) { + total += previousTimes[i]; + } + if ( !total ) { + total = 1; + } + fps = 1000 * FPS_FRAMES / total; + + s = va( "%ifps", fps ); + w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + + CG_DrawBigString( 635 - w, y + 2, s, 1.0F); + } + + return y + BIGCHAR_HEIGHT + 4; +} + +/* +================= +CG_DrawTimer +================= +*/ +static float CG_DrawTimer( float y ) { + char *s; + int w; + int mins, seconds, tens; + int msec; + + msec = cg.time - cgs.levelStartTime; + + seconds = msec / 1000; + mins = seconds / 60; + seconds -= mins * 60; + tens = seconds / 10; + seconds -= tens * 10; + + s = va( "%i:%i%i", mins, tens, seconds ); + w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + + CG_DrawBigString( 635 - w, y + 2, s, 1.0F); + + return y + BIGCHAR_HEIGHT + 4; +} + + +/* +================= +CG_DrawTeamOverlay +================= +*/ + +static float CG_DrawTeamOverlay( float y, qboolean right, qboolean upper ) { + int x, w, h, xx; + int i, j, len; + const char *p; + vec4_t hcolor; + int pwidth, lwidth; + int plyrs; + char st[16]; + clientInfo_t *ci; + gitem_t *item; + int ret_y, count; + + if ( !cg_drawTeamOverlay.integer ) { + return y; + } + + if ( cg.snap->ps.persistant[PERS_TEAM] != TEAM_RED && cg.snap->ps.persistant[PERS_TEAM] != TEAM_BLUE ) { + return y; // Not on any team + } + + plyrs = 0; + + // max player name width + pwidth = 0; + count = (numSortedTeamPlayers > 8) ? 8 : numSortedTeamPlayers; + for (i = 0; i < count; i++) { + ci = cgs.clientinfo + sortedTeamPlayers[i]; + if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) { + plyrs++; + len = CG_DrawStrlen(ci->name); + if (len > pwidth) + pwidth = len; + } + } + + if (!plyrs) + return y; + + if (pwidth > TEAM_OVERLAY_MAXNAME_WIDTH) + pwidth = TEAM_OVERLAY_MAXNAME_WIDTH; + + // max location name width + lwidth = 0; + for (i = 1; i < MAX_LOCATIONS; i++) { + p = CG_ConfigString(CS_LOCATIONS + i); + if (p && *p) { + len = CG_DrawStrlen(p); + if (len > lwidth) + lwidth = len; + } + } + + if (lwidth > TEAM_OVERLAY_MAXLOCATION_WIDTH) + lwidth = TEAM_OVERLAY_MAXLOCATION_WIDTH; + + w = (pwidth + lwidth + 4 + 7) * TINYCHAR_WIDTH; + + if ( right ) + x = 640 - w; + else + x = 0; + + h = plyrs * TINYCHAR_HEIGHT; + + if ( upper ) { + ret_y = y + h; + } else { + y -= h; + ret_y = y; + } + + if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED ) { + hcolor[0] = 1.0f; + hcolor[1] = 0.0f; + hcolor[2] = 0.0f; + hcolor[3] = 0.33f; + } else { // if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_BLUE ) + hcolor[0] = 0.0f; + hcolor[1] = 0.0f; + hcolor[2] = 1.0f; + hcolor[3] = 0.33f; + } + trap_R_SetColor( hcolor ); + CG_DrawPic( x, y, w, h, cgs.media.teamStatusBar ); + trap_R_SetColor( NULL ); + + for (i = 0; i < count; i++) { + ci = cgs.clientinfo + sortedTeamPlayers[i]; + if ( ci->infoValid && ci->team == cg.snap->ps.persistant[PERS_TEAM]) { + + hcolor[0] = hcolor[1] = hcolor[2] = hcolor[3] = 1.0; + + xx = x + TINYCHAR_WIDTH; + + CG_DrawStringExt( xx, y, + ci->name, hcolor, qfalse, qfalse, + TINYCHAR_WIDTH, TINYCHAR_HEIGHT, TEAM_OVERLAY_MAXNAME_WIDTH); + + if (lwidth) { + p = CG_ConfigString(CS_LOCATIONS + ci->location); + if (!p || !*p) + p = "unknown"; + len = CG_DrawStrlen(p); + if (len > lwidth) + len = lwidth; + +// xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth + +// ((lwidth/2 - len/2) * TINYCHAR_WIDTH); + xx = x + TINYCHAR_WIDTH * 2 + TINYCHAR_WIDTH * pwidth; + CG_DrawStringExt( xx, y, + p, hcolor, qfalse, qfalse, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, + TEAM_OVERLAY_MAXLOCATION_WIDTH); + } + + CG_GetColorForHealth( ci->health, ci->armor, hcolor ); + + Com_sprintf (st, sizeof(st), "%3i %3i", ci->health, ci->armor); + + xx = x + TINYCHAR_WIDTH * 3 + + TINYCHAR_WIDTH * pwidth + TINYCHAR_WIDTH * lwidth; + + CG_DrawStringExt( xx, y, + st, hcolor, qfalse, qfalse, + TINYCHAR_WIDTH, TINYCHAR_HEIGHT, 0 ); + + // draw weapon icon + xx += TINYCHAR_WIDTH * 3; + + if ( cg_weapons[ci->curWeapon].weaponIcon ) { + CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, + cg_weapons[ci->curWeapon].weaponIcon ); + } else { + CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, + cgs.media.deferShader ); + } + + // Draw powerup icons + if (right) { + xx = x; + } else { + xx = x + w - TINYCHAR_WIDTH; + } + for (j = 0; j <= PW_NUM_POWERUPS; j++) { + if (ci->powerups & (1 << j)) { + + item = BG_FindItemForPowerup( j ); + + if (item) { + CG_DrawPic( xx, y, TINYCHAR_WIDTH, TINYCHAR_HEIGHT, + trap_R_RegisterShader( item->icon ) ); + if (right) { + xx -= TINYCHAR_WIDTH; + } else { + xx += TINYCHAR_WIDTH; + } + } + } + } + + y += TINYCHAR_HEIGHT; + } + } + + return ret_y; +//#endif +} + + +static void CG_DrawPowerupIcons(int y) +{ + int j; + int ico_size = 64; + //int y = ico_size/2; + gitem_t *item; + + if (!cg.snap) + { + return; + } + + y += 16; + + for (j = 0; j <= PW_NUM_POWERUPS; j++) + { + if (cg.snap->ps.powerups[j] > cg.time) + { + int secondsleft = (cg.snap->ps.powerups[j] - cg.time)/1000; + + item = BG_FindItemForPowerup( j ); + + if (item) + { + int icoShader = 0; + if (cgs.gametype == GT_CTY && (j == PW_REDFLAG || j == PW_BLUEFLAG)) + { + if (j == PW_REDFLAG) + { + icoShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_ys" ); + } + else + { + icoShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_ys" ); + } + } + else + { + icoShader = trap_R_RegisterShader( item->icon ); + } + + CG_DrawPic( (640-(ico_size*1.1)), y, ico_size, ico_size, icoShader ); + + y += ico_size; + + if (j != PW_REDFLAG && j != PW_BLUEFLAG && secondsleft < 999) + { + UI_DrawProportionalString((640-(ico_size*1.1))+(ico_size/2), y-8, va("%i", secondsleft), UI_CENTER | UI_BIGFONT | UI_DROPSHADOW, colorTable[CT_WHITE]); + } + + y += (ico_size/3); + } + } + } +} + + +/* +===================== +CG_DrawUpperRight + +===================== +*/ +static void CG_DrawUpperRight( void ) { + float y; + + y = 0; + + if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 1 ) { + y = CG_DrawTeamOverlay( y, qtrue, qtrue ); + } + if ( cg_drawSnapshot.integer ) { + y = CG_DrawSnapshot( y ); + } + if ( cg_drawFPS.integer ) { + y = CG_DrawFPS( y ); + } + if ( cg_drawTimer.integer ) { + y = CG_DrawTimer( y ); + } + + y = CG_DrawEnemyInfo ( y ); + + y = CG_DrawMiniScoreboard ( y ); + + CG_DrawPowerupIcons(y); +} + +/* +=================== +CG_DrawReward +=================== +*/ +#ifdef JK2AWARDS +static void CG_DrawReward( void ) { + float *color; + int i, count; + float x, y; + char buf[32]; + + if ( !cg_drawRewards.integer ) { + return; + } + + color = CG_FadeColor( cg.rewardTime, REWARD_TIME ); + if ( !color ) { + if (cg.rewardStack > 0) { + for(i = 0; i < cg.rewardStack; i++) { + cg.rewardSound[i] = cg.rewardSound[i+1]; + cg.rewardShader[i] = cg.rewardShader[i+1]; + cg.rewardCount[i] = cg.rewardCount[i+1]; + } + cg.rewardTime = cg.time; + cg.rewardStack--; + color = CG_FadeColor( cg.rewardTime, REWARD_TIME ); + trap_S_StartLocalSound(cg.rewardSound[0], CHAN_ANNOUNCER); + } else { + return; + } + } + + trap_R_SetColor( color ); + + /* + count = cg.rewardCount[0]/10; // number of big rewards to draw + + if (count) { + y = 4; + x = 320 - count * ICON_SIZE; + for ( i = 0 ; i < count ; i++ ) { + CG_DrawPic( x, y, (ICON_SIZE*2)-4, (ICON_SIZE*2)-4, cg.rewardShader[0] ); + x += (ICON_SIZE*2); + } + } + + count = cg.rewardCount[0] - count*10; // number of small rewards to draw + */ + + if ( cg.rewardCount[0] >= 10 ) { + y = 56; + x = 320 - ICON_SIZE/2; + CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] ); + Com_sprintf(buf, sizeof(buf), "%d", cg.rewardCount[0]); + x = ( SCREEN_WIDTH - SMALLCHAR_WIDTH * CG_DrawStrlen( buf ) ) / 2; + CG_DrawStringExt( x, y+ICON_SIZE, buf, color, qfalse, qtrue, + SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, 0 ); + } + else { + + count = cg.rewardCount[0]; + + y = 56; + x = 320 - count * ICON_SIZE/2; + for ( i = 0 ; i < count ; i++ ) { + CG_DrawPic( x, y, ICON_SIZE-4, ICON_SIZE-4, cg.rewardShader[0] ); + x += ICON_SIZE; + } + } + trap_R_SetColor( NULL ); +} +#endif + + +/* +=============================================================================== + +LAGOMETER + +=============================================================================== +*/ + +#define LAG_SAMPLES 128 + + +typedef struct { + int frameSamples[LAG_SAMPLES]; + int frameCount; + int snapshotFlags[LAG_SAMPLES]; + int snapshotSamples[LAG_SAMPLES]; + int snapshotCount; +} lagometer_t; + +lagometer_t lagometer; + +/* +============== +CG_AddLagometerFrameInfo + +Adds the current interpolate / extrapolate bar for this frame +============== +*/ +void CG_AddLagometerFrameInfo( void ) { + int offset; + + offset = cg.time - cg.latestSnapshotTime; + lagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1) ] = offset; + lagometer.frameCount++; +} + +/* +============== +CG_AddLagometerSnapshotInfo + +Each time a snapshot is received, log its ping time and +the number of snapshots that were dropped before it. + +Pass NULL for a dropped packet. +============== +*/ +void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) { + // dropped packet + if ( !snap ) { + lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1; + lagometer.snapshotCount++; + return; + } + + // add this snapshot's info + lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->ping; + lagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->snapFlags; + lagometer.snapshotCount++; +} + +/* +============== +CG_DrawDisconnect + +Should we draw something differnet for long lag vs no packets? +============== +*/ +static void CG_DrawDisconnect( void ) { + float x, y; + int cmdNum; + usercmd_t cmd; + const char *s; + int w; // bk010215 - FIXME char message[1024]; + + if (cg.mMapChange) + { + s = CG_GetStripEdString("INGAMETEXT", "SERVER_CHANGING_MAPS"); // s = "Server Changing Maps"; + w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + CG_DrawBigString( 320 - w/2, 100, s, 1.0F); + + s = CG_GetStripEdString("INGAMETEXT", "PLEASE_WAIT"); // s = "Please wait..."; + w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + CG_DrawBigString( 320 - w/2, 200, s, 1.0F); + return; + } + + // draw the phone jack if we are completely past our buffers + cmdNum = trap_GetCurrentCmdNumber() - CMD_BACKUP + 1; + trap_GetUserCmd( cmdNum, &cmd ); + if ( cmd.serverTime <= cg.snap->ps.commandTime + || cmd.serverTime > cg.time ) { // special check for map_restart // bk 0102165 - FIXME + return; + } + + // also add text in center of screen + s = CG_GetStripEdString("INGAMETEXT", "CONNECTION_INTERRUPTED"); // s = "Connection Interrupted"; // bk 010215 - FIXME + w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + CG_DrawBigString( 320 - w/2, 100, s, 1.0F); + + // blink the icon + if ( ( cg.time >> 9 ) & 1 ) { + return; + } + + x = 640 - 48; + y = 480 - 48; + + CG_DrawPic( x, y, 48, 48, trap_R_RegisterShader("gfx/2d/net.tga" ) ); +} + + +#define MAX_LAGOMETER_PING 900 +#define MAX_LAGOMETER_RANGE 300 + +/* +============== +CG_DrawLagometer +============== +*/ +static void CG_DrawLagometer( void ) { + int a, x, y, i; + float v; + float ax, ay, aw, ah, mid, range; + int color; + float vscale; + + if ( !cg_lagometer.integer || cgs.localServer ) { + CG_DrawDisconnect(); + return; + } + + // + // draw the graph + // + x = 640 - 48; + y = 480 - 144; + + trap_R_SetColor( NULL ); + CG_DrawPic( x, y, 48, 48, cgs.media.lagometerShader ); + + ax = x; + ay = y; + aw = 48; + ah = 48; + + color = -1; + range = ah / 3; + mid = ay + range; + + vscale = range / MAX_LAGOMETER_RANGE; + + // draw the frame interpoalte / extrapolate graph + for ( a = 0 ; a < aw ; a++ ) { + i = ( lagometer.frameCount - 1 - a ) & (LAG_SAMPLES - 1); + v = lagometer.frameSamples[i]; + v *= vscale; + if ( v > 0 ) { + if ( color != 1 ) { + color = 1; + trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] ); + } + if ( v > range ) { + v = range; + } + trap_R_DrawStretchPic ( ax + aw - a, mid - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader ); + } else if ( v < 0 ) { + if ( color != 2 ) { + color = 2; + trap_R_SetColor( g_color_table[ColorIndex(COLOR_BLUE)] ); + } + v = -v; + if ( v > range ) { + v = range; + } + trap_R_DrawStretchPic( ax + aw - a, mid, 1, v, 0, 0, 0, 0, cgs.media.whiteShader ); + } + } + + // draw the snapshot latency / drop graph + range = ah / 2; + vscale = range / MAX_LAGOMETER_PING; + + for ( a = 0 ; a < aw ; a++ ) { + i = ( lagometer.snapshotCount - 1 - a ) & (LAG_SAMPLES - 1); + v = lagometer.snapshotSamples[i]; + if ( v > 0 ) { + if ( lagometer.snapshotFlags[i] & SNAPFLAG_RATE_DELAYED ) { + if ( color != 5 ) { + color = 5; // YELLOW for rate delay + trap_R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] ); + } + } else { + if ( color != 3 ) { + color = 3; + trap_R_SetColor( g_color_table[ColorIndex(COLOR_GREEN)] ); + } + } + v = v * vscale; + if ( v > range ) { + v = range; + } + trap_R_DrawStretchPic( ax + aw - a, ay + ah - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader ); + } else if ( v < 0 ) { + if ( color != 4 ) { + color = 4; // RED for dropped snapshots + trap_R_SetColor( g_color_table[ColorIndex(COLOR_RED)] ); + } + trap_R_DrawStretchPic( ax + aw - a, ay + ah - range, 1, range, 0, 0, 0, 0, cgs.media.whiteShader ); + } + } + + trap_R_SetColor( NULL ); + + if ( cg_nopredict.integer || cg_synchronousClients.integer ) { + CG_DrawBigString( ax, ay, "snc", 1.0 ); + } + + CG_DrawDisconnect(); +} + + + +/* +=============================================================================== + +CENTER PRINTING + +=============================================================================== +*/ + + +/* +============== +CG_CenterPrint + +Called for important messages that should stay in the center of the screen +for a few moments +============== +*/ +void CG_CenterPrint( const char *str, int y, int charWidth ) { + char *s; + + Q_strncpyz( cg.centerPrint, str, sizeof(cg.centerPrint) ); + + cg.centerPrintTime = cg.time; + cg.centerPrintY = y; + cg.centerPrintCharWidth = charWidth; + + // count the number of lines for centering + cg.centerPrintLines = 1; + s = cg.centerPrint; + while( *s ) { + if (*s == '\n') + cg.centerPrintLines++; + s++; + } +} + + +/* +=================== +CG_DrawCenterString +=================== +*/ +static void CG_DrawCenterString( void ) { + char *start; + int l; + int x, y, w; + int h; + float *color; + const float scale = 1.0; //0.5 + + if ( !cg.centerPrintTime ) { + return; + } + + color = CG_FadeColor( cg.centerPrintTime, 1000 * cg_centertime.value ); + if ( !color ) { + return; + } + + trap_R_SetColor( color ); + + start = cg.centerPrint; + + y = cg.centerPrintY - cg.centerPrintLines * BIGCHAR_HEIGHT / 2; + + while ( 1 ) { + char linebuffer[1024]; + + for ( l = 0; l < 50; l++ ) { + if ( !start[l] || start[l] == '\n' ) { + break; + } + linebuffer[l] = start[l]; + } + linebuffer[l] = 0; + + w = CG_Text_Width(linebuffer, scale, FONT_MEDIUM); + h = CG_Text_Height(linebuffer, scale, FONT_MEDIUM); + x = (SCREEN_WIDTH - w) / 2; + CG_Text_Paint(x, y + h, scale, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM); + y += h + 6; + + while ( *start && ( *start != '\n' ) ) { + start++; + } + if ( !*start ) { + break; + } + start++; + } + + trap_R_SetColor( NULL ); +} + + + +/* +================================================================================ + +CROSSHAIR + +================================================================================ +*/ + + +/* +================= +CG_DrawCrosshair +================= +*/ +static void CG_DrawCrosshair( vec3_t worldPoint, int chEntValid ) { + float w, h; + qhandle_t hShader; + float f; + float x, y; + + if ( !cg_drawCrosshair.integer ) + { + return; + } + + if (cg.snap->ps.fallingToDeath) + { + return; + } + + if ( cg.predictedPlayerState.zoomMode != 0 ) + {//not while scoped + return; + } + + if ( cg_crosshairHealth.integer ) + { + vec4_t hcolor; + + CG_ColorForHealth( hcolor ); + trap_R_SetColor( hcolor ); + } + else + { + //set color based on what kind of ent is under crosshair + if ( cg.crosshairClientNum >= ENTITYNUM_WORLD ) + { + trap_R_SetColor( NULL ); + } + else if (chEntValid && (cg_entities[cg.crosshairClientNum].currentState.number < MAX_CLIENTS || cg_entities[cg.crosshairClientNum].currentState.shouldtarget)) + { + vec4_t ecolor = {0,0,0,0}; + centity_t *crossEnt = &cg_entities[cg.crosshairClientNum]; + + if ( crossEnt->currentState.number < MAX_CLIENTS ) + { + if (cgs.gametype >= GT_TEAM && + cgs.clientinfo[crossEnt->currentState.number].team == cgs.clientinfo[cg.snap->ps.clientNum].team ) + { + //Allies are green + ecolor[0] = 0.0;//R + ecolor[1] = 1.0;//G + ecolor[2] = 0.0;//B + } + else + { + //Enemies are red + ecolor[0] = 1.0;//R + ecolor[1] = 0.0;//G + ecolor[2] = 0.0;//B + } + + if (cg.snap->ps.duelInProgress) + { + if (crossEnt->currentState.number != cg.snap->ps.duelIndex) + { //grey out crosshair for everyone but your foe if you're in a duel + ecolor[0] = 0.4; + ecolor[1] = 0.4; + ecolor[2] = 0.4; + } + } + else if (crossEnt->currentState.bolt1) + { //this fellow is in a duel. We just checked if we were in a duel above, so + //this means we aren't and he is. Which of course means our crosshair greys out over him. + ecolor[0] = 0.4; + ecolor[1] = 0.4; + ecolor[2] = 0.4; + } + } + else if (crossEnt->currentState.shouldtarget) + { + //VectorCopy( crossEnt->startRGBA, ecolor ); + if ( !ecolor[0] && !ecolor[1] && !ecolor[2] ) + { + // We really don't want black, so set it to yellow + ecolor[0] = 1.0F;//R + ecolor[1] = 0.8F;//G + ecolor[2] = 0.3F;//B + } + + if (crossEnt->currentState.owner == cg.snap->ps.clientNum || + (cgs.gametype >= GT_TEAM && crossEnt->currentState.teamowner == cgs.clientinfo[cg.snap->ps.clientNum].team)) + { + ecolor[0] = 0.0;//R + ecolor[1] = 1.0;//G + ecolor[2] = 0.0;//B + } + else if (crossEnt->currentState.teamowner == 16 || + (cgs.gametype >= GT_TEAM && crossEnt->currentState.teamowner && crossEnt->currentState.teamowner != cgs.clientinfo[cg.snap->ps.clientNum].team)) + { + ecolor[0] = 1.0;//R + ecolor[1] = 0.0;//G + ecolor[2] = 0.0;//B + } + } + + ecolor[3] = 1.0; + + trap_R_SetColor( ecolor ); + } + } + + w = h = cg_crosshairSize.value; + + // pulse the size of the crosshair when picking up items + f = cg.time - cg.itemPickupBlendTime; + if ( f > 0 && f < ITEM_BLOB_TIME ) { + f /= ITEM_BLOB_TIME; + w *= ( 1 + f ); + h *= ( 1 + f ); + } + + if ( worldPoint && VectorLength( worldPoint ) ) + { + if ( !CG_WorldCoordToScreenCoordFloat( worldPoint, &x, &y ) ) + {//off screen, don't draw it + return; + } + x -= 320; + y -= 240; + } + else + { + x = cg_crosshairX.integer; + y = cg_crosshairY.integer; + } + + hShader = cgs.media.crosshairShader[ cg_drawCrosshair.integer % NUM_CROSSHAIRS ]; + + trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * (640 - w), + y + cg.refdef.y + 0.5 * (480 - h), + w, h, 0, 0, 1, 1, hShader ); +} + +qboolean CG_WorldCoordToScreenCoordFloat(vec3_t worldCoord, float *x, float *y) +{ + int xcenter, ycenter; + vec3_t local, transformed; + vec3_t vfwd; + vec3_t vright; + vec3_t vup; + float xzi; + float yzi; + +// xcenter = cg.refdef.width / 2;//gives screen coords adjusted for resolution +// ycenter = cg.refdef.height / 2;//gives screen coords adjusted for resolution + + //NOTE: did it this way because most draw functions expect virtual 640x480 coords + // and adjust them for current resolution + xcenter = 640 / 2;//gives screen coords in virtual 640x480, to be adjusted when drawn + ycenter = 480 / 2;//gives screen coords in virtual 640x480, to be adjusted when drawn + + AngleVectors (cg.refdefViewAngles, vfwd, vright, vup); + + VectorSubtract (worldCoord, cg.refdef.vieworg, local); + + transformed[0] = DotProduct(local,vright); + transformed[1] = DotProduct(local,vup); + transformed[2] = DotProduct(local,vfwd); + + // Make sure Z is not negative. + if(transformed[2] < 0.01) + { + return qfalse; + } + + xzi = xcenter / transformed[2] * (90.0/cg.refdef.fov_x); + yzi = ycenter / transformed[2] * (90.0/cg.refdef.fov_y); + + *x = xcenter + xzi * transformed[0]; + *y = ycenter - yzi * transformed[1]; + + return qtrue; +} + +qboolean CG_WorldCoordToScreenCoord( vec3_t worldCoord, int *x, int *y ) +{ + float xF, yF; + qboolean retVal = CG_WorldCoordToScreenCoordFloat( worldCoord, &xF, &yF ); + *x = (int)xF; + *y = (int)yF; + return retVal; +} + +/* +==================== +CG_SaberClashFlare +==================== +*/ +int g_saberFlashTime = 0; +vec3_t g_saberFlashPos = {0, 0, 0}; +void CG_SaberClashFlare( void ) +{ + int t, maxTime = 150; + vec3_t dif; + vec3_t color; + int x,y; + float v, len; + trace_t tr; + + t = cg.time - g_saberFlashTime; + + if ( t <= 0 || t >= maxTime ) + { + return; + } + + // Don't do clashes for things that are behind us + VectorSubtract( g_saberFlashPos, cg.refdef.vieworg, dif ); + + if ( DotProduct( dif, cg.refdef.viewaxis[0] ) < 0.2 ) + { + return; + } + + CG_Trace( &tr, cg.refdef.vieworg, NULL, NULL, g_saberFlashPos, -1, CONTENTS_SOLID ); + + if ( tr.fraction < 1.0f ) + { + return; + } + + len = VectorNormalize( dif ); + + // clamp to a known range + if ( len > 800 ) + { + len = 800; + } + + v = ( 1.0f - ((float)t / maxTime )) * ((1.0f - ( len / 800.0f )) * 2.0f + 0.35f); + + CG_WorldCoordToScreenCoord( g_saberFlashPos, &x, &y ); + + VectorSet( color, 0.8f, 0.8f, 0.8f ); + trap_R_SetColor( color ); + + CG_DrawPic( x - ( v * 300 ), y - ( v * 300 ), + v * 600, v * 600, + trap_R_RegisterShader( "gfx/effects/saberFlare" )); +} + +//-------------------------------------------------------------- +static void CG_DrawHolocronIcons(void) +//-------------------------------------------------------------- +{ + int icon_size = 40; + int i = 0; + int startx = 10; + int starty = 10;//SCREEN_HEIGHT - icon_size*3; + + int endx = icon_size; + int endy = icon_size; + + if (cg.snap->ps.zoomMode) + { //don't display over zoom mask + return; + } + + if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR) + { + return; + } + + while (i < NUM_FORCE_POWERS) + { + if (cg.snap->ps.holocronBits & (1 << forcePowerSorted[i])) + { + CG_DrawPic( startx, starty, endx, endy, cgs.media.forcePowerIcons[forcePowerSorted[i]]); + starty += (icon_size+2); //+2 for spacing + if ((starty+icon_size) >= SCREEN_HEIGHT-80) + { + starty = 10;//SCREEN_HEIGHT - icon_size*3; + startx += (icon_size+2); + } + } + + i++; + } +} + +static qboolean CG_IsDurationPower(int power) +{ + if (power == FP_HEAL || + power == FP_SPEED || + power == FP_TELEPATHY || + power == FP_RAGE || + power == FP_PROTECT || + power == FP_ABSORB || + power == FP_SEE) + { + return qtrue; + } + + return qfalse; +} + +//-------------------------------------------------------------- +static void CG_DrawActivePowers(void) +//-------------------------------------------------------------- +{ + int icon_size = 40; + int i = 0; + int startx = icon_size*2+16; + int starty = SCREEN_HEIGHT - icon_size*2; + + int endx = icon_size; + int endy = icon_size; + + if (cg.snap->ps.zoomMode) + { //don't display over zoom mask + return; + } + + if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR) + { + return; + } + + while (i < NUM_FORCE_POWERS) + { + if ((cg.snap->ps.fd.forcePowersActive & (1 << forcePowerSorted[i])) && + CG_IsDurationPower(forcePowerSorted[i])) + { + CG_DrawPic( startx, starty, endx, endy, cgs.media.forcePowerIcons[forcePowerSorted[i]]); + startx += (icon_size+2); //+2 for spacing + if ((startx+icon_size) >= SCREEN_WIDTH-80) + { + startx = icon_size*2+16; + starty += (icon_size+2); + } + } + + i++; + } + + //additionally, draw an icon force force rage recovery + if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time) + { + CG_DrawPic( startx, starty, endx, endy, cgs.media.rageRecShader); + } +} + +//-------------------------------------------------------------- +static void CG_DrawRocketLocking( int lockEntNum, int lockTime ) +//-------------------------------------------------------------- +{ + int cx, cy; + vec3_t org; + static int oldDif = 0; + centity_t *cent = &cg_entities[lockEntNum]; + vec4_t color={0.0f,0.0f,0.0f,0.0f}; + int dif = ( cg.time - cg.snap->ps.rocketLockTime ) / ( 1200.0f / /*8.0f*/16.0f ); + int i; + + if (!cg.snap->ps.rocketLockTime) + { + return; + } + + if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR) + { + return; + } + + //We can't check to see in pmove if players are on the same team, so we resort + //to just not drawing the lock if a teammate is the locked on ent + if (cg.snap->ps.rocketLockIndex >= 0 && + cg.snap->ps.rocketLockIndex < MAX_CLIENTS) + { + if (cgs.clientinfo[cg.snap->ps.rocketLockIndex].team == cgs.clientinfo[cg.snap->ps.clientNum].team) + { + if (cgs.gametype >= GT_TEAM) + { + return; + } + } + } + + if (cg.snap->ps.rocketLockTime != -1) + { + lastvalidlockdif = dif; + } + else + { + dif = lastvalidlockdif; + } + + if ( !cent ) + { + return; + } + + VectorCopy( cent->lerpOrigin, org ); + + if ( CG_WorldCoordToScreenCoord( org, &cx, &cy )) + { + // we care about distance from enemy to eye, so this is good enough + float sz = Distance( cent->lerpOrigin, cg.refdef.vieworg ) / 1024.0f; + + if ( sz > 1.0f ) + { + sz = 1.0f; + } + else if ( sz < 0.0f ) + { + sz = 0.0f; + } + + sz = (1.0f - sz) * (1.0f - sz) * 32 + 6; + + cy += sz * 0.5f; + + if ( dif < 0 ) + { + oldDif = 0; + return; + } + else if ( dif > 8 ) + { + dif = 8; + } + + // do sounds + if ( oldDif != dif ) + { + if ( dif == 8 ) + { + trap_S_StartSound( org, 0, CHAN_AUTO, trap_S_RegisterSound( "sound/weapons/rocket/lock.wav" )); + } + else + { + trap_S_StartSound( org, 0, CHAN_AUTO, trap_S_RegisterSound( "sound/weapons/rocket/tick.wav" )); + } + } + + oldDif = dif; + + for ( i = 0; i < dif; i++ ) + { + color[0] = 1.0f; + color[1] = 0.0f; + color[2] = 0.0f; + color[3] = 0.1f * i + 0.2f; + + trap_R_SetColor( color ); + + // our slices are offset by about 45 degrees. + CG_DrawRotatePic( cx - sz, cy - sz, sz, sz, i * 45.0f, trap_R_RegisterShaderNoMip( "gfx/2d/wedge" )); + } + + // we are locked and loaded baby + if ( dif == 8 ) + { + color[0] = color[1] = color[2] = sin( cg.time * 0.05f ) * 0.5f + 0.5f; + color[3] = 1.0f; // this art is additive, so the alpha value does nothing + + trap_R_SetColor( color ); + + CG_DrawPic( cx - sz, cy - sz * 2, sz * 2, sz * 2, trap_R_RegisterShaderNoMip( "gfx/2d/lock" )); + } + } +} + +/* +================= +CG_ScanForCrosshairEntity +================= +*/ +static void CG_ScanForCrosshairEntity( void ) { + trace_t trace; + vec3_t start, end; + int content; + + if ( cg_dynamicCrosshair.integer ) + { + vec3_t d_f, d_rt, d_up; + /* + if ( cg.snap->ps.weapon == WP_NONE || + cg.snap->ps.weapon == WP_SABER || + cg.snap->ps.weapon == WP_STUN_BATON) + { + VectorCopy( cg.refdef.vieworg, start ); + AngleVectors( cg.refdefViewAngles, d_f, d_rt, d_up ); + } + else + */ + //For now we still want to draw the crosshair in relation to the player's world coordinates + //even if we have a melee weapon/no weapon. + { + if (cg.snap && cg.snap->ps.weapon == WP_EMPLACED_GUN && cg.snap->ps.emplacedIndex) + { + vec3_t pitchConstraint; + + VectorCopy(cg.refdefViewAngles, pitchConstraint); + + if (cg.renderingThirdPerson) + { + VectorCopy(cg.predictedPlayerState.viewangles, pitchConstraint); + } + else + { + VectorCopy(cg.refdefViewAngles, pitchConstraint); + } + + if (pitchConstraint[PITCH] > 40) + { + pitchConstraint[PITCH] = 40; + } + + AngleVectors( pitchConstraint, d_f, d_rt, d_up ); + } + else + { + vec3_t pitchConstraint; + + if (cg.renderingThirdPerson) + { + VectorCopy(cg.predictedPlayerState.viewangles, pitchConstraint); + } + else + { + VectorCopy(cg.refdefViewAngles, pitchConstraint); + } + + AngleVectors( pitchConstraint, d_f, d_rt, d_up ); + } + CG_CalcMuzzlePoint(cg.snap->ps.clientNum, start); + } + + //FIXME: increase this? Increase when zoom in? + VectorMA( start, 4096, d_f, end );//was 8192 + } + else + { + VectorCopy( cg.refdef.vieworg, start ); + VectorMA( start, 131072, cg.refdef.viewaxis[0], end ); + } + + CG_Trace( &trace, start, vec3_origin, vec3_origin, end, + cg.snap->ps.clientNum, CONTENTS_SOLID|CONTENTS_BODY ); + + if (trace.entityNum < MAX_CLIENTS) + { + if (CG_IsMindTricked(cg_entities[trace.entityNum].currentState.trickedentindex, + cg_entities[trace.entityNum].currentState.trickedentindex2, + cg_entities[trace.entityNum].currentState.trickedentindex3, + cg_entities[trace.entityNum].currentState.trickedentindex4, + cg.snap->ps.clientNum)) + { + if (cg.crosshairClientNum == trace.entityNum) + { + cg.crosshairClientNum = ENTITYNUM_NONE; + cg.crosshairClientTime = 0; + } + + CG_DrawCrosshair(trace.endpos, 0); + + return; //this entity is mind-tricking the current client, so don't render it + } + } + + if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR) + { + if (trace.entityNum < /*MAX_CLIENTS*/ENTITYNUM_WORLD) + { + CG_DrawCrosshair(trace.endpos, 1); + } + else + { + CG_DrawCrosshair(trace.endpos, 0); + } + } + +// if ( trace.entityNum >= MAX_CLIENTS ) { +// return; +// } + + // if the player is in fog, don't show it + content = trap_CM_PointContents( trace.endpos, 0 ); + if ( content & CONTENTS_FOG ) { + return; + } + + if ( trace.entityNum >= MAX_CLIENTS ) { + cg.crosshairClientNum = trace.entityNum; + cg.crosshairClientTime = cg.time; + return; + } + + // update the fade timer + cg.crosshairClientNum = trace.entityNum; + cg.crosshairClientTime = cg.time; +} + + +/* +===================== +CG_DrawCrosshairNames +===================== +*/ +static void CG_DrawCrosshairNames( void ) { + float *color; + vec4_t tcolor; + char *name; + int baseColor; + + if ( !cg_drawCrosshair.integer ) { + return; + } + + // scan the known entities to see if the crosshair is sighted on one + CG_ScanForCrosshairEntity(); + + if ( !cg_drawCrosshairNames.integer ) { + return; + } + //rww - still do the trace, our dynamic crosshair depends on it + + if (cg.crosshairClientNum >= MAX_CLIENTS) + { + return; + } + + // draw the name of the player being looked at + color = CG_FadeColor( cg.crosshairClientTime, 1000 ); + if ( !color ) { + trap_R_SetColor( NULL ); + return; + } + + name = cgs.clientinfo[ cg.crosshairClientNum ].name; + + if (cgs.gametype >= GT_TEAM) + { + if (cgs.clientinfo[cg.crosshairClientNum].team == TEAM_RED) + { + baseColor = CT_RED; + } + else + { + baseColor = CT_BLUE; + } + + /* + //For now instead of team-based we'll make it oriented based on which team we're on + if (cgs.clientinfo[cg.crosshairClientNum].team == cgs.clientinfo[cg.snap->ps.clientNum].team) + { + baseColor = CT_GREEN; + } + else + { + baseColor = CT_RED; + } + */ + } + else + { + //baseColor = CT_WHITE; + baseColor = CT_RED; //just make it red in nonteam modes since everyone is hostile and crosshair will be red on them too + } + + if (cg.snap->ps.duelInProgress) + { + if (cg.crosshairClientNum != cg.snap->ps.duelIndex) + { //grey out crosshair for everyone but your foe if you're in a duel + baseColor = CT_BLACK; + } + } + else if (cg_entities[cg.crosshairClientNum].currentState.bolt1) + { //this fellow is in a duel. We just checked if we were in a duel above, so + //this means we aren't and he is. Which of course means our crosshair greys out over him. + baseColor = CT_BLACK; + } + + tcolor[0] = colorTable[baseColor][0]; + tcolor[1] = colorTable[baseColor][1]; + tcolor[2] = colorTable[baseColor][2]; + tcolor[3] = color[3]*0.5f; + + UI_DrawProportionalString(320, 170, name, UI_CENTER, tcolor); + + trap_R_SetColor( NULL ); +} + + +//============================================================================== + +/* +================= +CG_DrawSpectator +================= +*/ +static void CG_DrawSpectator(void) +{ + const char* s; + s = CG_GetStripEdString("INGAMETEXT", "SPECTATOR"); + if (cgs.gametype == GT_TOURNAMENT && + cgs.duelist1 != -1 && + cgs.duelist2 != -1) + { + char text[1024]; + int size = 64; + + Com_sprintf(text, sizeof(text), "%s %s %s", cgs.clientinfo[cgs.duelist1].name, CG_GetStripEdString("INGAMETEXT", "SPECHUD_VERSUS"), cgs.clientinfo[cgs.duelist2].name); + CG_Text_Paint ( 320 - CG_Text_Width ( text, 1.0f, 3 ) / 2, 420, 1.0f, colorWhite, text, 0, 0, 0, 3 ); + + + if (cgs.clientinfo[cgs.duelist1].modelIcon && + cgs.clientinfo[cgs.duelist2].modelIcon) + { + trap_R_SetColor( colorTable[CT_WHITE] ); + CG_DrawPic( 10, SCREEN_HEIGHT-(size*1.5), size, size, cgs.clientinfo[cgs.duelist1].modelIcon ); + CG_DrawPic( SCREEN_WIDTH-size-10, SCREEN_HEIGHT-(size*1.5), size, size, cgs.clientinfo[cgs.duelist2].modelIcon ); + } + } + else + { + CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, 3 ) / 2, 420, 1.0f, colorWhite, s, 0, 0, 0, 3 ); + } + + if ( cgs.gametype == GT_TOURNAMENT ) + { + s = CG_GetStripEdString("INGAMETEXT", "WAITING_TO_PLAY"); // "waiting to play"; + CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, 3 ) / 2, 440, 1.0f, colorWhite, s, 0, 0, 0, 3 ); + } + else //if ( cgs.gametype >= GT_TEAM ) + { + //s = "press ESC and use the JOIN menu to play"; + s = CG_GetStripEdString("INGAMETEXT", "SPEC_CHOOSEJOIN"); + CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, 3 ) / 2, 440, 1.0f, colorWhite, s, 0, 0, 0, 3 ); + } +} + +/* +================= +CG_DrawVote +================= +*/ +static void CG_DrawVote(void) { + const char *s; + int sec; + char sYes[20]; + char sNo[20]; + + if ( !cgs.voteTime ) { + return; + } + + // play a talk beep whenever it is modified + if ( cgs.voteModified ) { + cgs.voteModified = qfalse; +// trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); + } + + sec = ( VOTE_TIME - ( cg.time - cgs.voteTime ) ) / 1000; + if ( sec < 0 ) { + sec = 0; + } + + trap_SP_GetStringTextString("MENUS0_YES", sYes, sizeof(sYes) ); + trap_SP_GetStringTextString("MENUS0_NO", sNo, sizeof(sNo) ); + + s = va("VOTE(%i):%s %s:%i %s:%i", sec, cgs.voteString, sYes, cgs.voteYes, sNo, cgs.voteNo); + CG_DrawSmallString( 4, 58, s, 1.0F ); + s = CG_GetStripEdString("INGAMETEXT", "OR_PRESS_ESC_THEN_CLICK_VOTE"); // s = "or press ESC then click Vote"; + CG_DrawSmallString( 4, 58 + SMALLCHAR_HEIGHT + 2, s, 1.0F ); +} + +/* +================= +CG_DrawTeamVote +================= +*/ +static void CG_DrawTeamVote(void) { + char *s; + int sec, cs_offset; + + if ( cgs.clientinfo->team == TEAM_RED ) + cs_offset = 0; + else if ( cgs.clientinfo->team == TEAM_BLUE ) + cs_offset = 1; + else + return; + + if ( !cgs.teamVoteTime[cs_offset] ) { + return; + } + + // play a talk beep whenever it is modified + if ( cgs.teamVoteModified[cs_offset] ) { + cgs.teamVoteModified[cs_offset] = qfalse; +// trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); + } + + sec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[cs_offset] ) ) / 1000; + if ( sec < 0 ) { + sec = 0; + } + if (strstr(cgs.teamVoteString[cs_offset], "leader")) + { + int i = 0; + + while (cgs.teamVoteString[cs_offset][i] && cgs.teamVoteString[cs_offset][i] != ' ') + { + i++; + } + + if (cgs.teamVoteString[cs_offset][i] == ' ') + { + int voteIndex = 0; + char voteIndexStr[256]; + + i++; + + while (cgs.teamVoteString[cs_offset][i]) + { + voteIndexStr[voteIndex] = cgs.teamVoteString[cs_offset][i]; + voteIndex++; + i++; + } + voteIndexStr[voteIndex] = 0; + + voteIndex = atoi(voteIndexStr); + + s = va("TEAMVOTE(%i):(Make %s the new team leader) yes:%i no:%i", sec, cgs.clientinfo[voteIndex].name, + cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] ); + } + else + { + s = va("TEAMVOTE(%i):%s yes:%i no:%i", sec, cgs.teamVoteString[cs_offset], + cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] ); + } + } + else + { + s = va("TEAMVOTE(%i):%s yes:%i no:%i", sec, cgs.teamVoteString[cs_offset], + cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[cs_offset] ); + } + CG_DrawSmallString( 4, 90, s, 1.0F ); +} + +static qboolean CG_DrawScoreboard() { + return CG_DrawOldScoreboard(); +#if 0 + static qboolean firstTime = qtrue; + float fade, *fadeColor; + + if (menuScoreboard) { + menuScoreboard->window.flags &= ~WINDOW_FORCED; + } + if (cg_paused.integer) { + cg.deferredPlayerLoading = 0; + firstTime = qtrue; + return qfalse; + } + + // should never happen in Team Arena + if (cgs.gametype == GT_SINGLE_PLAYER && cg.predictedPlayerState.pm_type == PM_INTERMISSION ) { + cg.deferredPlayerLoading = 0; + firstTime = qtrue; + return qfalse; + } + + // don't draw scoreboard during death while warmup up + if ( cg.warmup && !cg.showScores ) { + return qfalse; + } + + if ( cg.showScores || cg.predictedPlayerState.pm_type == PM_DEAD || cg.predictedPlayerState.pm_type == PM_INTERMISSION ) { + fade = 1.0; + fadeColor = colorWhite; + } else { + fadeColor = CG_FadeColor( cg.scoreFadeTime, FADE_TIME ); + if ( !fadeColor ) { + // next time scoreboard comes up, don't print killer + cg.deferredPlayerLoading = 0; + cg.killerName[0] = 0; + firstTime = qtrue; + return qfalse; + } + fade = *fadeColor; + } + + + if (menuScoreboard == NULL) { + if ( cgs.gametype >= GT_TEAM ) { + menuScoreboard = Menus_FindByName("teamscore_menu"); + } else { + menuScoreboard = Menus_FindByName("score_menu"); + } + } + + if (menuScoreboard) { + if (firstTime) { + CG_SetScoreSelection(menuScoreboard); + firstTime = qfalse; + } + Menu_Paint(menuScoreboard, qtrue); + } + + // load any models that have been deferred + if ( ++cg.deferredPlayerLoading > 10 ) { + CG_LoadDeferredPlayers(); + } + + return qtrue; +#endif +} + +/* +================= +CG_DrawIntermission +================= +*/ +static void CG_DrawIntermission( void ) { +// int key; + //if (cg_singlePlayer.integer) { + // CG_DrawCenterString(); + // return; + //} + cg.scoreFadeTime = cg.time; + cg.scoreBoardShowing = CG_DrawScoreboard(); +} + +/* +================= +CG_DrawFollow +================= +*/ +static qboolean CG_DrawFollow( void ) +{ + const char *s; + + if ( !(cg.snap->ps.pm_flags & PMF_FOLLOW) ) + { + return qfalse; + } + + s = "following"; + CG_Text_Paint ( 320 - CG_Text_Width ( s, 1.0f, FONT_MEDIUM ) / 2, 60, 1.0f, colorWhite, s, 0, 0, 0, FONT_MEDIUM ); + + s = cgs.clientinfo[ cg.snap->ps.clientNum ].name; + CG_Text_Paint ( 320 - CG_Text_Width ( s, 2.0f, FONT_MEDIUM ) / 2, 80, 2.0f, colorWhite, s, 0, 0, 0, FONT_MEDIUM ); + + return qtrue; +} + +#if 0 +static void CG_DrawTemporaryStats() +{ //placeholder for testing (draws ammo and force power) + char s[512]; + + if (!cg.snap) + { + return; + } + + sprintf(s, "Force: %i", cg.snap->ps.fd.forcePower); + + CG_DrawBigString(SCREEN_WIDTH-164, SCREEN_HEIGHT-128, s, 1.0f); + + sprintf(s, "Ammo: %i", cg.snap->ps.ammo[weaponData[cg.snap->ps.weapon].ammoIndex]); + + CG_DrawBigString(SCREEN_WIDTH-164, SCREEN_HEIGHT-112, s, 1.0f); + + sprintf(s, "Health: %i", cg.snap->ps.stats[STAT_HEALTH]); + + CG_DrawBigString(8, SCREEN_HEIGHT-128, s, 1.0f); + + sprintf(s, "Armor: %i", cg.snap->ps.stats[STAT_ARMOR]); + + CG_DrawBigString(8, SCREEN_HEIGHT-112, s, 1.0f); +} +#endif + +/* +================= +CG_DrawAmmoWarning +================= +*/ +static void CG_DrawAmmoWarning( void ) { +#if 0 + const char *s; + int w; + + if (!cg_drawStatus.integer) + { + return; + } + + if ( cg_drawAmmoWarning.integer == 0 ) { + return; + } + + if ( !cg.lowAmmoWarning ) { + return; + } + + if ( cg.lowAmmoWarning == 2 ) { + s = "OUT OF AMMO"; + } else { + s = "LOW AMMO WARNING"; + } + w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + CG_DrawBigString(320 - w / 2, 64, s, 1.0F); +#endif +} + + + +/* +================= +CG_DrawWarmup +================= +*/ +static void CG_DrawWarmup( void ) { + int w; + int sec; + int i; + float scale; + clientInfo_t *ci1, *ci2; + int cw; + const char *s; + + sec = cg.warmup; + if ( !sec ) { + return; + } + + if ( sec < 0 ) { + s = "Waiting for players"; + w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + CG_DrawBigString(320 - w / 2, 24, s, 1.0F); + cg.warmupCount = 0; + return; + } + + if (cgs.gametype == GT_TOURNAMENT) { + // find the two active players + ci1 = NULL; + ci2 = NULL; + for ( i = 0 ; i < cgs.maxclients ; i++ ) { + if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_FREE ) { + if ( !ci1 ) { + ci1 = &cgs.clientinfo[i]; + } else { + ci2 = &cgs.clientinfo[i]; + } + } + } + + if ( ci1 && ci2 ) { + s = va( "%s vs %s", ci1->name, ci2->name ); + w = CG_Text_Width(s, 0.6f, FONT_MEDIUM); + CG_Text_Paint(320 - w / 2, 60, 0.6f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE,FONT_MEDIUM); + } + } else { + if ( cgs.gametype == GT_FFA ) { + s = "Free For All"; + } else if ( cgs.gametype == GT_HOLOCRON ) { + s = "Holocron FFA"; + } else if ( cgs.gametype == GT_JEDIMASTER ) { + s = "Jedi Master"; + } else if ( cgs.gametype == GT_TEAM ) { + s = "Team FFA"; + } else if ( cgs.gametype == GT_SAGA ) { + s = "N/A"; + } else if ( cgs.gametype == GT_CTF ) { + s = "Capture the Flag"; + } else if ( cgs.gametype == GT_CTY ) { + s = "Capture the Ysalamiri"; + } else { + s = ""; + } + w = CG_Text_Width(s, 1.5f, FONT_MEDIUM); + CG_Text_Paint(320 - w / 2, 90, 1.5f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE,FONT_MEDIUM); + } + + sec = ( sec - cg.time ) / 1000; + if ( sec < 0 ) { + cg.warmup = 0; + sec = 0; + } + s = va( "Starts in: %i", sec + 1 ); + if ( sec != cg.warmupCount ) { + cg.warmupCount = sec; + switch ( sec ) { + case 0: + trap_S_StartLocalSound( cgs.media.count1Sound, CHAN_ANNOUNCER ); + break; + case 1: + trap_S_StartLocalSound( cgs.media.count2Sound, CHAN_ANNOUNCER ); + break; + case 2: + trap_S_StartLocalSound( cgs.media.count3Sound, CHAN_ANNOUNCER ); + break; + default: + break; + } + } + scale = 0.45f; + switch ( cg.warmupCount ) { + case 0: + cw = 28; + scale = 1.25f; + break; + case 1: + cw = 24; + scale = 1.15f; + break; + case 2: + cw = 20; + scale = 1.05f; + break; + default: + cw = 16; + scale = 0.9f; + break; + } + + w = CG_Text_Width(s, scale, FONT_MEDIUM); + CG_Text_Paint(320 - w / 2, 125, scale, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM); +} + +//================================================================================== +/* +================= +CG_DrawTimedMenus +================= +*/ +void CG_DrawTimedMenus() { + if (cg.voiceTime) { + int t = cg.time - cg.voiceTime; + if ( t > 2500 ) { + Menus_CloseByName("voiceMenu"); + trap_Cvar_Set("cl_conXOffset", "0"); + cg.voiceTime = 0; + } + } +} + +void CG_DrawFlagStatus() +{ + int myFlagTakenShader = 0; + int theirFlagShader = 0; + int team = 0; + int startDrawPos = 2; + int ico_size = 32; + + if (!cg.snap) + { + return; + } + + if (cgs.gametype != GT_CTF && cgs.gametype != GT_CTY) + { + return; + } + + team = cg.snap->ps.persistant[PERS_TEAM]; + + if (cgs.gametype == GT_CTY) + { + if (team == TEAM_RED) + { + myFlagTakenShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_x" ); + theirFlagShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_ys" ); + } + else + { + myFlagTakenShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_x" ); + theirFlagShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_ys" ); + } + } + else + { + if (team == TEAM_RED) + { + myFlagTakenShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_x" ); + theirFlagShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag" ); + } + else + { + myFlagTakenShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_x" ); + theirFlagShader = trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag" ); + } + } + + if (CG_YourTeamHasFlag()) + { + CG_DrawPic( startDrawPos, 365, ico_size, ico_size, theirFlagShader ); + startDrawPos += ico_size+2; + } + + if (CG_OtherTeamHasFlag()) + { + CG_DrawPic( startDrawPos, 365, ico_size, ico_size, myFlagTakenShader ); + } +} + +int cgRageTime = 0; +int cgRageFadeTime = 0; +float cgRageFadeVal = 0; + +int cgRageRecTime = 0; +int cgRageRecFadeTime = 0; +float cgRageRecFadeVal = 0; + +int cgAbsorbTime = 0; +int cgAbsorbFadeTime = 0; +float cgAbsorbFadeVal = 0; + +int cgProtectTime = 0; +int cgProtectFadeTime = 0; +float cgProtectFadeVal = 0; + +int cgYsalTime = 0; +int cgYsalFadeTime = 0; +float cgYsalFadeVal = 0; + +qboolean gCGHasFallVector = qfalse; +vec3_t gCGFallVector; + +/* +================= +CG_Draw2D +================= +*/ +static void CG_Draw2D( void ) { + float inTime = cg.invenSelectTime+WEAPON_SELECT_TIME; + float wpTime = cg.weaponSelectTime+WEAPON_SELECT_TIME; + float bestTime; + int drawSelect = 0; + float fallTime, rageTime, rageRecTime, absorbTime, protectTime, ysalTime; + vec4_t hcolor; + + if (cgs.orderPending && cg.time > cgs.orderTime) { + CG_CheckOrderPending(); + } + // if we are taking a levelshot for the menu, don't draw anything + if ( cg.levelShot ) { + return; + } + + if (cgs.clientinfo[cg.snap->ps.clientNum].team == TEAM_SPECTATOR) + { + cgRageTime = 0; + cgRageFadeTime = 0; + cgRageFadeVal = 0; + + cgRageRecTime = 0; + cgRageRecFadeTime = 0; + cgRageRecFadeVal = 0; + + cgAbsorbTime = 0; + cgAbsorbFadeTime = 0; + cgAbsorbFadeVal = 0; + + cgProtectTime = 0; + cgProtectFadeTime = 0; + cgProtectFadeVal = 0; + + cgYsalTime = 0; + cgYsalFadeTime = 0; + cgYsalFadeVal = 0; + } + + if ( cg_draw2D.integer == 0 ) { + return; + } + + if ( cg.snap->ps.pm_type == PM_INTERMISSION ) { + CG_DrawIntermission(); + return; + } + + if (cgs.clientinfo[cg.snap->ps.clientNum].team != TEAM_SPECTATOR) + { + if (cg.snap->ps.fd.forcePowersActive & (1 << FP_RAGE)) + { + if (!cgRageTime) + { + cgRageTime = cg.time; + } + + rageTime = (float)(cg.time - cgRageTime); + + rageTime /= 9000; + + if (rageTime < 0) + { + rageTime = 0; + } + if (rageTime > 0.15) + { + rageTime = 0.15; + } + + hcolor[3] = rageTime; + hcolor[0] = 0.7; + hcolor[1] = 0; + hcolor[2] = 0; + + if (!cg.renderingThirdPerson) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + + cgRageFadeTime = 0; + cgRageFadeVal = 0; + } + else if (cgRageTime) + { + if (!cgRageFadeTime) + { + cgRageFadeTime = cg.time; + cgRageFadeVal = 0.15; + } + + rageTime = cgRageFadeVal; + + cgRageFadeVal -= (cg.time - cgRageFadeTime)*0.000005; + + if (rageTime < 0) + { + rageTime = 0; + } + if (rageTime > 0.15) + { + rageTime = 0.15; + } + + if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time) + { + float checkRageRecTime = rageTime; + + if (checkRageRecTime < 0.15) + { + checkRageRecTime = 0.15; + } + + hcolor[3] = checkRageRecTime; + hcolor[0] = rageTime*4; + if (hcolor[0] < 0.2) + { + hcolor[0] = 0.2; + } + hcolor[1] = 0.2; + hcolor[2] = 0.2; + } + else + { + hcolor[3] = rageTime; + hcolor[0] = 0.7; + hcolor[1] = 0; + hcolor[2] = 0; + } + + if (!cg.renderingThirdPerson && rageTime) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + else + { + if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time) + { + hcolor[3] = 0.15; + hcolor[0] = 0.2; + hcolor[1] = 0.2; + hcolor[2] = 0.2; + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + cgRageTime = 0; + } + } + else if (cg.snap->ps.fd.forceRageRecoveryTime > cg.time) + { + if (!cgRageRecTime) + { + cgRageRecTime = cg.time; + } + + rageRecTime = (float)(cg.time - cgRageRecTime); + + rageRecTime /= 9000; + + if (rageRecTime < 0.15)//0) + { + rageRecTime = 0.15;//0; + } + if (rageRecTime > 0.15) + { + rageRecTime = 0.15; + } + + hcolor[3] = rageRecTime; + hcolor[0] = 0.2; + hcolor[1] = 0.2; + hcolor[2] = 0.2; + + if (!cg.renderingThirdPerson) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + + cgRageRecFadeTime = 0; + cgRageRecFadeVal = 0; + } + else if (cgRageRecTime) + { + if (!cgRageRecFadeTime) + { + cgRageRecFadeTime = cg.time; + cgRageRecFadeVal = 0.15; + } + + rageRecTime = cgRageRecFadeVal; + + cgRageRecFadeVal -= (cg.time - cgRageRecFadeTime)*0.000005; + + if (rageRecTime < 0) + { + rageRecTime = 0; + } + if (rageRecTime > 0.15) + { + rageRecTime = 0.15; + } + + hcolor[3] = rageRecTime; + hcolor[0] = 0.2; + hcolor[1] = 0.2; + hcolor[2] = 0.2; + + if (!cg.renderingThirdPerson && rageRecTime) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + else + { + cgRageRecTime = 0; + } + } + + if (cg.snap->ps.fd.forcePowersActive & (1 << FP_ABSORB)) + { + if (!cgAbsorbTime) + { + cgAbsorbTime = cg.time; + } + + absorbTime = (float)(cg.time - cgAbsorbTime); + + absorbTime /= 9000; + + if (absorbTime < 0) + { + absorbTime = 0; + } + if (absorbTime > 0.15) + { + absorbTime = 0.15; + } + + hcolor[3] = absorbTime/2; + hcolor[0] = 0; + hcolor[1] = 0; + hcolor[2] = 0.7; + + if (!cg.renderingThirdPerson) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + + cgAbsorbFadeTime = 0; + cgAbsorbFadeVal = 0; + } + else if (cgAbsorbTime) + { + if (!cgAbsorbFadeTime) + { + cgAbsorbFadeTime = cg.time; + cgAbsorbFadeVal = 0.15; + } + + absorbTime = cgAbsorbFadeVal; + + cgAbsorbFadeVal -= (cg.time - cgAbsorbFadeTime)*0.000005; + + if (absorbTime < 0) + { + absorbTime = 0; + } + if (absorbTime > 0.15) + { + absorbTime = 0.15; + } + + hcolor[3] = absorbTime/2; + hcolor[0] = 0; + hcolor[1] = 0; + hcolor[2] = 0.7; + + if (!cg.renderingThirdPerson && absorbTime) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + else + { + cgAbsorbTime = 0; + } + } + + if (cg.snap->ps.fd.forcePowersActive & (1 << FP_PROTECT)) + { + if (!cgProtectTime) + { + cgProtectTime = cg.time; + } + + protectTime = (float)(cg.time - cgProtectTime); + + protectTime /= 9000; + + if (protectTime < 0) + { + protectTime = 0; + } + if (protectTime > 0.15) + { + protectTime = 0.15; + } + + hcolor[3] = protectTime/2; + hcolor[0] = 0; + hcolor[1] = 0.7; + hcolor[2] = 0; + + if (!cg.renderingThirdPerson) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + + cgProtectFadeTime = 0; + cgProtectFadeVal = 0; + } + else if (cgProtectTime) + { + if (!cgProtectFadeTime) + { + cgProtectFadeTime = cg.time; + cgProtectFadeVal = 0.15; + } + + protectTime = cgProtectFadeVal; + + cgProtectFadeVal -= (cg.time - cgProtectFadeTime)*0.000005; + + if (protectTime < 0) + { + protectTime = 0; + } + if (protectTime > 0.15) + { + protectTime = 0.15; + } + + hcolor[3] = protectTime/2; + hcolor[0] = 0; + hcolor[1] = 0.7; + hcolor[2] = 0; + + if (!cg.renderingThirdPerson && protectTime) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + else + { + cgProtectTime = 0; + } + } + + if (cg.snap->ps.rocketLockIndex != MAX_CLIENTS && (cg.time - cg.snap->ps.rocketLockTime) > 0) + { + CG_DrawRocketLocking( cg.snap->ps.rocketLockIndex, cg.snap->ps.rocketLockTime ); + } + + if (BG_HasYsalamiri(cgs.gametype, &cg.snap->ps)) + { + if (!cgYsalTime) + { + cgYsalTime = cg.time; + } + + ysalTime = (float)(cg.time - cgYsalTime); + + ysalTime /= 9000; + + if (ysalTime < 0) + { + ysalTime = 0; + } + if (ysalTime > 0.15) + { + ysalTime = 0.15; + } + + hcolor[3] = ysalTime/2; + hcolor[0] = 0.7; + hcolor[1] = 0.7; + hcolor[2] = 0; + + if (!cg.renderingThirdPerson) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + + cgYsalFadeTime = 0; + cgYsalFadeVal = 0; + } + else if (cgYsalTime) + { + if (!cgYsalFadeTime) + { + cgYsalFadeTime = cg.time; + cgYsalFadeVal = 0.15; + } + + ysalTime = cgYsalFadeVal; + + cgYsalFadeVal -= (cg.time - cgYsalFadeTime)*0.000005; + + if (ysalTime < 0) + { + ysalTime = 0; + } + if (ysalTime > 0.15) + { + ysalTime = 0.15; + } + + hcolor[3] = ysalTime/2; + hcolor[0] = 0.7; + hcolor[1] = 0.7; + hcolor[2] = 0; + + if (!cg.renderingThirdPerson && ysalTime) + { + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + } + else + { + cgYsalTime = 0; + } + } + } + + if (cg.snap->ps.rocketLockIndex != MAX_CLIENTS && (cg.time - cg.snap->ps.rocketLockTime) > 0) + { + CG_DrawRocketLocking( cg.snap->ps.rocketLockIndex, cg.snap->ps.rocketLockTime ); + } + + if (cg.snap->ps.holocronBits) + { + CG_DrawHolocronIcons(); + } + if (cg.snap->ps.fd.forcePowersActive || cg.snap->ps.fd.forceRageRecoveryTime > cg.time) + { + CG_DrawActivePowers(); + } + + // Draw this before the text so that any text won't get clipped off + CG_DrawZoomMask(); + +/* + if (cg.cameraMode) { + return; + } +*/ + if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) { + CG_DrawSpectator(); + CG_DrawCrosshair(NULL, 0); + CG_DrawCrosshairNames(); + } else { + // don't draw any status if dead or the scoreboard is being explicitly shown + if ( !cg.showScores && cg.snap->ps.stats[STAT_HEALTH] > 0 ) { + + if ( /*cg_drawStatus.integer*/0 ) { + //Reenable if stats are drawn with menu system again + Menu_PaintAll(); + CG_DrawTimedMenus(); + } + + //CG_DrawTemporaryStats(); + + CG_DrawAmmoWarning(); + + CG_DrawCrosshairNames(); + + if (cg_drawStatus.integer) + { + CG_DrawIconBackground(); + } + + if (inTime > wpTime) + { + drawSelect = 1; + bestTime = cg.invenSelectTime; + } + else //only draw the most recent since they're drawn in the same place + { + drawSelect = 2; + bestTime = cg.weaponSelectTime; + } + + if (cg.forceSelectTime > bestTime) + { + drawSelect = 3; + } + + switch(drawSelect) + { + case 1: + CG_DrawInvenSelect(); + break; + case 2: + CG_DrawWeaponSelect(); + break; + case 3: + CG_DrawForceSelect(); + break; + default: + break; + } + + if (cg_drawStatus.integer) + { + //Powerups now done with upperright stuff + //CG_DrawPowerupIcons(); + + CG_DrawFlagStatus(); + } + + CG_SaberClashFlare(); + + if (cg_drawStatus.integer) + { + CG_DrawStats(); + } + + //Do we want to use this system again at some point? + //CG_DrawReward(); + } + + } + + if (cg.snap->ps.fallingToDeath) + { + fallTime = (float)(cg.time - cg.snap->ps.fallingToDeath); + + fallTime /= (FALL_FADE_TIME/2); + + if (fallTime < 0) + { + fallTime = 0; + } + if (fallTime > 1) + { + fallTime = 1; + } + + hcolor[3] = fallTime; + hcolor[0] = 0; + hcolor[1] = 0; + hcolor[2] = 0; + + CG_DrawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*SCREEN_HEIGHT, hcolor); + + if (!gCGHasFallVector) + { + VectorCopy(cg.snap->ps.origin, gCGFallVector); + gCGHasFallVector = qtrue; + } + } + else + { + if (gCGHasFallVector) + { + gCGHasFallVector = qfalse; + VectorClear(gCGFallVector); + } + } + + CG_DrawVote(); + CG_DrawTeamVote(); + + CG_DrawLagometer(); + + if (!cg_paused.integer) { + CG_DrawUpperRight(); + } + + if ( !CG_DrawFollow() ) { + CG_DrawWarmup(); + } + + // don't draw center string if scoreboard is up + cg.scoreBoardShowing = CG_DrawScoreboard(); + if ( !cg.scoreBoardShowing) { + CG_DrawCenterString(); + } +} + + +static void CG_DrawTourneyScoreboard() { +} + +/* +===================== +CG_DrawActive + +Perform all drawing needed to completely fill the screen +===================== +*/ +void CG_DrawActive( stereoFrame_t stereoView ) { + float separation; + vec3_t baseOrg; + + // optionally draw the info screen instead + if ( !cg.snap ) { + CG_DrawInformation(); + return; + } + + // optionally draw the tournement scoreboard instead + if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR && + ( cg.snap->ps.pm_flags & PMF_SCOREBOARD ) ) { + CG_DrawTourneyScoreboard(); + return; + } + + switch ( stereoView ) { + case STEREO_CENTER: + separation = 0; + break; + case STEREO_LEFT: + separation = -cg_stereoSeparation.value / 2; + break; + case STEREO_RIGHT: + separation = cg_stereoSeparation.value / 2; + break; + default: + separation = 0; + CG_Error( "CG_DrawActive: Undefined stereoView" ); + } + + + // clear around the rendered view if sized down + CG_TileClear(); + + // offset vieworg appropriately if we're doing stereo separation + VectorCopy( cg.refdef.vieworg, baseOrg ); + if ( separation != 0 ) { + VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg ); + } + + // draw 3D view + trap_R_RenderScene( &cg.refdef ); + + // restore original viewpoint if running stereo + if ( separation != 0 ) { + VectorCopy( baseOrg, cg.refdef.vieworg ); + } + + // draw status bar and other floating elements + CG_Draw2D(); +} + + + diff --git a/CODE-mp/cgame/cg_drawtools.c b/CODE-mp/cgame/cg_drawtools.c index 4280ae8..73091b0 100644 --- a/CODE-mp/cgame/cg_drawtools.c +++ b/CODE-mp/cgame/cg_drawtools.c @@ -624,6 +624,48 @@ void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t CG_Text_Paint(x, y, 1.0, color, str, 0, 0, iStyle, iMenuFont); } +void UI_DrawScaledProportionalString( int x, int y, const char* str, int style, vec4_t color, float scale) +{ + // having all these different style defines (1 for UI, one for CG, and now one for the re->font stuff) + // is dumb, but for now... + // + int iStyle = 0; + + switch (style & (UI_LEFT|UI_CENTER|UI_RIGHT)) + { + default: + case UI_LEFT: + { + // nada... + } + break; + + case UI_CENTER: + { + x -= CG_Text_Width(str, scale, FONT_MEDIUM) / 2; + } + break; + + case UI_RIGHT: + { + x -= CG_Text_Width(str, scale, FONT_MEDIUM) / 2; + } + break; + } + + if (style & UI_DROPSHADOW) + { + iStyle = ITEM_TEXTSTYLE_SHADOWED; + } + else + if ( style & (UI_BLINK|UI_PULSE) ) + { + iStyle = ITEM_TEXTSTYLE_BLINK; + } + + CG_Text_Paint(x, y, scale, color, str, 0, 0, iStyle, FONT_MEDIUM); +} + diff --git a/CODE-mp/cgame/cg_ents.c b/CODE-mp/cgame/cg_ents.c index 332db51..fb23235 100644 --- a/CODE-mp/cgame/cg_ents.c +++ b/CODE-mp/cgame/cg_ents.c @@ -493,7 +493,7 @@ static void CG_General( centity_t *cent ) { vec3_t beamOrg; mdxaBone_t matrix; - if (cent->currentState.modelGhoul2 == 999) + if (cent->currentState.modelGhoul2 == 127) { //not ready to be drawn or initialized.. return; } @@ -1056,10 +1056,13 @@ Ghoul2 Insert End VectorScale( ent.oldorigin, tempLength, ent.oldorigin ); ent.endTime = cent->dustTrailTime; + + /* ent.renderfx |= RF_DISINTEGRATE2; ent.customShader = cgs.media.disruptorShader; trap_R_AddRefEntityToScene( &ent ); + */ ent.renderfx &= ~(RF_DISINTEGRATE2); ent.renderfx |= (RF_DISINTEGRATE1); @@ -1881,7 +1884,9 @@ Ghoul2 Insert End if (s1->weapon != WP_SABER && s1->weapon != G2_MODEL_PART) { - if ( cent->currentState.eFlags | EF_ALT_FIRING ) + //if ( cent->currentState.eFlags | EF_ALT_FIRING ) + //rww - why was this like this? + if ( cent->currentState.eFlags & EF_ALT_FIRING ) { ent.hModel = weapon->altMissileModel; } @@ -2418,6 +2423,8 @@ void CG_AddPacketEntities( void ) { //rww - update the g2 pointer BEFORE the weapons, otherwise bad things could happen //FIXME: These two pointers seem to differ sometimes, they shouldn't, should they? + //the one on predictedPlayerEntity also seems to often be invalid, so it can't be + //reliably checked and cleared. cg.predictedPlayerEntity.ghoul2 = cg_entities[ cg.snap->ps.clientNum].ghoul2; CG_CheckPlayerG2Weapons(ps, &cg.predictedPlayerEntity); BG_PlayerStateToEntityState( ps, &cg.predictedPlayerEntity.currentState, qfalse ); diff --git a/CODE-mp/cgame/cg_event.c b/CODE-mp/cgame/cg_event.c index 0ea7602..134311a 100644 --- a/CODE-mp/cgame/cg_event.c +++ b/CODE-mp/cgame/cg_event.c @@ -25,40 +25,56 @@ Also called by scoreboard drawing const char *CG_PlaceString( int rank ) { static char str[64]; char *s, *t; + // number extenstions, eg 1st, 2nd, 3rd, 4th etc. + // note that the rules are different for french, but by changing the required strip strings they seem to work + char sST[10]; + char sND[10]; + char sRD[10]; + char sTH[10]; + char sTiedFor[64]; // german is much longer, super safe... + + trap_SP_GetStringTextString("INGAMETEXT_NUMBER_ST",sST, sizeof(sST) ); + trap_SP_GetStringTextString("INGAMETEXT_NUMBER_ND",sND, sizeof(sND) ); + trap_SP_GetStringTextString("INGAMETEXT_NUMBER_RD",sRD, sizeof(sRD) ); + trap_SP_GetStringTextString("INGAMETEXT_NUMBER_TH",sTH, sizeof(sTH) ); + trap_SP_GetStringTextString("INGAMETEXT_TIED_FOR" ,sTiedFor,sizeof(sTiedFor) ); + strcat(sTiedFor," "); // save worrying about translators adding spaces or not if ( rank & RANK_TIED_FLAG ) { rank &= ~RANK_TIED_FLAG; - t = "Tied for "; + t = sTiedFor;//"Tied for "; } else { t = ""; } if ( rank == 1 ) { - s = "1st";//S_COLOR_BLUE "1st" S_COLOR_WHITE; // draw in blue + s = va("1%s",sST);//S_COLOR_BLUE "1st" S_COLOR_WHITE; // draw in blue } else if ( rank == 2 ) { - s = "2nd";//S_COLOR_RED "2nd" S_COLOR_WHITE; // draw in red + s = va("2%s",sND);//S_COLOR_RED "2nd" S_COLOR_WHITE; // draw in red } else if ( rank == 3 ) { - s = "3rd";//S_COLOR_YELLOW "3rd" S_COLOR_WHITE; // draw in yellow + s = va("3%s",sRD);//S_COLOR_YELLOW "3rd" S_COLOR_WHITE; // draw in yellow } else if ( rank == 11 ) { - s = "11th"; + s = va("11%s",sTH); } else if ( rank == 12 ) { - s = "12th"; + s = va("12%s",sTH); } else if ( rank == 13 ) { - s = "13th"; + s = va("13%s",sTH); } else if ( rank % 10 == 1 ) { - s = va("%ist", rank); + s = va("%i%s", rank,sST); } else if ( rank % 10 == 2 ) { - s = va("%ind", rank); + s = va("%i%s", rank,sND); } else if ( rank % 10 == 3 ) { - s = va("%ird", rank); + s = va("%i%s", rank,sRD); } else { - s = va("%ith", rank); + s = va("%i%s", rank,sTH); } Com_sprintf( str, sizeof( str ), "%s%s", t, s ); return str; } +qboolean CG_ThereIsAMaster(void); + /* ============= CG_Obituary @@ -163,6 +179,14 @@ static void CG_Obituary( entityState_t *ent ) { else message = "SUICIDE_ELECTROCUTED_MALE"; break; + case MOD_FALLING: + if ( gender == GENDER_FEMALE ) + message = "SUICIDE_FALLDEATH_FEMALE"; + else if ( gender == GENDER_NEUTER ) + message = "SUICIDE_FALLDEATH_GENDERLESS"; + else + message = "SUICIDE_FALLDEATH_MALE"; + break; default: if ( gender == GENDER_FEMALE ) message = "SUICIDE_GENERICDEATH_FEMALE"; @@ -203,29 +227,50 @@ clientkilled: if ( attacker == cg.snap->ps.clientNum ) { char *s; - if ( cgs.gametype < GT_TEAM ) { + if ( cgs.gametype < GT_TEAM && cgs.gametype != GT_TOURNAMENT ) { if (cgs.gametype == GT_JEDIMASTER && attacker < MAX_CLIENTS && !ent->isJediMaster && - !cg.snap->ps.isJediMaster) + !cg.snap->ps.isJediMaster && + CG_ThereIsAMaster()) { char part1[512]; char part2[512]; - const char *kmsg1 = CG_GetStripEdString("INGAMETEXT", "KILLED_MESSAGE"); - strcpy(part1, kmsg1); - kmsg1 = CG_GetStripEdString("INGAMETEXT", "JMKILLED_NOTJM"); + trap_SP_GetStringTextString("INGAMETEXT_KILLED_MESSAGE", part1, sizeof(part1)); + trap_SP_GetStringTextString("INGAMETEXT_JMKILLED_NOTJM", part2, sizeof(part2)); + s = va("%s %s\n%s\n", part1, targetName, part2); + } + else if (cgs.gametype == GT_JEDIMASTER && + attacker < MAX_CLIENTS && + !ent->isJediMaster && + !cg.snap->ps.isJediMaster) + { //no JM, saber must be out + char part1[512]; + trap_SP_GetStringTextString("INGAMETEXT_KILLED_MESSAGE", part1, sizeof(part1)); + /* + kmsg1 = "for 0 points.\nGo for the saber!"; strcpy(part2, kmsg1); s = va("%s %s %s\n", part1, targetName, part2); + */ + s = va("%s %s\n", part1, targetName); } else { - s = va("%s %s.\n%s place with %i.", (char *)CG_GetStripEdString("INGAMETEXT", "KILLED_MESSAGE"), targetName, - CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ), + char sPlaceWith[256]; + char sKilledStr[256]; + trap_SP_GetStringTextString("INGAMETEXT_PLACE_WITH", sPlaceWith, sizeof(sPlaceWith)); + trap_SP_GetStringTextString("INGAMETEXT_KILLED_MESSAGE", sKilledStr, sizeof(sKilledStr)); + + s = va("%s %s.\n%s %s %i.", sKilledStr, targetName, + CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ), + sPlaceWith, cg.snap->ps.persistant[PERS_SCORE] ); } } else { - s = va("%s %s", (char *)CG_GetStripEdString("INGAMETEXT", "KILLED_MESSAGE"), targetName ); + char sKilledStr[256]; + trap_SP_GetStringTextString("INGAMETEXT_KILLED_MESSAGE", sKilledStr, sizeof(sKilledStr)); + s = va("%s %s", sKilledStr, targetName ); } if (!(cg_singlePlayerActive.integer && cg_cameraOrbit.integer)) { CG_CenterPrint( s, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); @@ -427,6 +472,9 @@ static void CG_UseItem( centity_t *cent ) { break; case HI_SEEKER: + trap_S_StartSound (NULL, es->number, CHAN_AUTO, cgs.media.deploySeeker ); + break; + case HI_SHIELD: case HI_DATAPAD: case HI_SENTRY_GUN: @@ -480,7 +528,8 @@ static void CG_ItemPickup( int itemNum ) { bg_itemlist[itemNum].giTag != WP_DET_PACK && bg_itemlist[itemNum].giTag != WP_THERMAL && bg_itemlist[itemNum].giTag != WP_ROCKET_LAUNCHER && - bg_itemlist[itemNum].giTag > cg.snap->ps.weapon) + bg_itemlist[itemNum].giTag > cg.snap->ps.weapon && + cg.snap->ps.weapon != WP_SABER) { if (!cg.snap->ps.emplacedIndex) { @@ -491,7 +540,8 @@ static void CG_ItemPickup( int itemNum ) { } else if ( cg_autoswitch.integer == 2) { //autoselect if better - if (bg_itemlist[itemNum].giTag > cg.snap->ps.weapon) + if (bg_itemlist[itemNum].giTag > cg.snap->ps.weapon && + cg.snap->ps.weapon != WP_SABER) { if (!cg.snap->ps.emplacedIndex) { @@ -500,6 +550,7 @@ static void CG_ItemPickup( int itemNum ) { cg.weaponSelect = bg_itemlist[itemNum].giTag; } } + /* else if ( cg_autoswitch.integer == 3) { //autoselect if better and not using the saber as a weapon if (bg_itemlist[itemNum].giTag > cg.snap->ps.weapon && @@ -512,15 +563,24 @@ static void CG_ItemPickup( int itemNum ) { cg.weaponSelect = bg_itemlist[itemNum].giTag; } } + */ + //No longer required - just not switching ever if using saber } //rww - print pickup messages - if (bg_itemlist[itemNum].pickup_name && bg_itemlist[itemNum].pickup_name[0] && + if (bg_itemlist[itemNum].classname && bg_itemlist[itemNum].classname[0] && (bg_itemlist[itemNum].giType != IT_TEAM || (bg_itemlist[itemNum].giTag != PW_REDFLAG && bg_itemlist[itemNum].giTag != PW_BLUEFLAG)) ) { //don't print messages for flags, they have their own pickup event broadcasts - const char *strText = CG_GetStripEdString("INGAMETEXT", "PICKUPLINE"); + char text[1024]; - Com_Printf("%s %s\n", strText, bg_itemlist[itemNum].pickup_name); + if ( trap_SP_GetStringTextString( va("INGAME_%s",bg_itemlist[itemNum].classname), text, sizeof( text ))) + { + Com_Printf("%s %s\n", CG_GetStripEdString("INGAMETEXT", "PICKUPLINE"), text); + } + else + { + Com_Printf("%s %s\n", CG_GetStripEdString("INGAMETEXT", "PICKUPLINE"), bg_itemlist[itemNum].classname); + } } } @@ -867,6 +927,40 @@ void DoFall(centity_t *cent, entityState_t *es, int clientNum) cg.landTime = cg.time; } } + +int CG_InClientBitflags(entityState_t *ent, int client) +{ + int checkIn; + int sub = 0; + + if (client > 47) + { + checkIn = ent->trickedentindex4; + sub = 48; + } + else if (client > 31) + { + checkIn = ent->trickedentindex3; + sub = 32; + } + else if (client > 15) + { + checkIn = ent->trickedentindex2; + sub = 16; + } + else + { + checkIn = ent->trickedentindex; + } + + if (checkIn & (1 << (client-sub))) + { + return 1; + } + + return 0; +} + /* ============== CG_EntityEvent @@ -936,6 +1030,8 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { cl_ent->trickAlphaTime = 0; cl_ent->ghoul2weapon = NULL; cl_ent->weapon = WP_NONE; + cl_ent->teamPowerEffectTime = 0; + cl_ent->teamPowerType = 0; } break; @@ -1036,7 +1132,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { { //starting the duel if (es->eventParm == 2) { - CG_CenterPrint( "BEGIN", 120, GIANTCHAR_WIDTH*2 ); + CG_CenterPrint( CG_GetStripEdString("SVINGAME", "BEGIN_DUEL"), 120, GIANTCHAR_WIDTH*2 ); trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER ); } else @@ -1135,7 +1231,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { const char *strText = CG_GetStripEdString("INGAMETEXT", "PICKUPLINE"); //Com_Printf("%s %s\n", strText, showPowersName[index]); - CG_CenterPrint( va("%s %s\n", strText, showPowersName[index]), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); + CG_CenterPrint( va("%s %s\n", strText, CG_GetStripEdString("INGAME",showPowersName[index])), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); } //Show the player their force selection bar in case picking the holocron up changed the current selection @@ -1178,7 +1274,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { } item = &bg_itemlist[ index ]; - if ( item->giType != IT_POWERUP && item->giType != IT_TEAM) { + if ( /*item->giType != IT_POWERUP && */item->giType != IT_TEAM) { if (item->pickup_sound && item->pickup_sound[0]) { trap_S_StartSound (NULL, es->number, CHAN_AUTO, trap_S_RegisterSound( item->pickup_sound ) ); @@ -1421,6 +1517,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { if (cg.snap->ps.clientNum == es->number) { trap_S_StartLocalSound(cgs.media.happyMusic, CHAN_LOCAL); + CGCam_SetMusicMult(0.3, 5000); } } break; @@ -1499,6 +1596,69 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { } } break; + case EV_PREDEFSOUND: + DEBUGNAME("EV_PREDEFSOUND"); + { + int sID = -1; + + switch (es->eventParm) + { + case PDSOUND_PROTECTHIT: + sID = trap_S_RegisterSound("sound/weapons/force/protecthit.mp3"); + break; + case PDSOUND_PROTECT: + sID = trap_S_RegisterSound("sound/weapons/force/protect.mp3"); + break; + case PDSOUND_ABSORBHIT: + sID = trap_S_RegisterSound("sound/weapons/force/absorbhit.mp3"); + break; + case PDSOUND_ABSORB: + sID = trap_S_RegisterSound("sound/weapons/force/absorb.mp3"); + break; + case PDSOUND_FORCEJUMP: + sID = trap_S_RegisterSound("sound/weapons/force/jump.mp3"); + break; + case PDSOUND_FORCEGRIP: + sID = trap_S_RegisterSound("sound/weapons/force/grip.mp3"); + break; + default: + break; + } + + if (sID != 1) + { + trap_S_StartSound(es->origin, es->number, CHAN_AUTO, sID); + } + } + break; + + case EV_TEAM_POWER: + DEBUGNAME("EV_TEAM_POWER"); + { + int clnum = 0; + + while (clnum < MAX_CLIENTS) + { + if (CG_InClientBitflags(es, clnum)) + { + if (es->eventParm == 1) + { //eventParm 1 is heal + trap_S_StartSound (NULL, clnum, CHAN_AUTO, cgs.media.teamHealSound ); + cg_entities[clnum].teamPowerEffectTime = cg.time + 1000; + cg_entities[clnum].teamPowerType = 1; + } + else + { //eventParm 2 is force regen + trap_S_StartSound (NULL, clnum, CHAN_AUTO, cgs.media.teamRegenSound ); + cg_entities[clnum].teamPowerEffectTime = cg.time + 1000; + cg_entities[clnum].teamPowerType = 0; + } + } + clnum++; + } + } + break; + case EV_SCREENSHAKE: DEBUGNAME("EV_SCREENSHAKE"); if (!es->modelindex || cg.predictedPlayerState.clientNum == es->modelindex-1) @@ -1700,6 +1860,13 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { DEBUGNAME("EV_DESTROY_GHOUL2_INSTANCE"); if (cg_entities[es->eventParm].ghoul2 && trap_G2_HaveWeGhoul2Models(cg_entities[es->eventParm].ghoul2)) { + if (es->eventParm < MAX_CLIENTS) + { //You try to do very bad thing! +#ifdef _DEBUG + Com_Printf("WARNING: Tried to kill a client ghoul2 instance with a server event!\n"); +#endif + break; + } trap_G2API_CleanGhoul2Models(&(cg_entities[es->eventParm].ghoul2)); } break; @@ -1719,7 +1886,12 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { { trap_Cvar_Set("ui_rankChange", va("%i", es->eventParm)); - trap_OpenUIMenu(3); + trap_Cvar_Set("ui_myteam", va("%i", es->bolt2)); + + if (!( trap_Key_GetCatcher() & KEYCATCH_UI ) && !es->bolt1) + { + trap_OpenUIMenu(3); + } } break; @@ -1729,6 +1901,12 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { trap_Cvar_Set("ui_freeSaber", va("%i", es->eventParm)); break; + case EV_SET_FORCE_DISABLE: + DEBUGNAME("EV_SET_FORCE_DISABLE"); + + trap_Cvar_Set("ui_forcePowerDisable", va("%i", es->eventParm)); + break; + // // missile impacts // @@ -2045,6 +2223,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { if (es->eventParm && es->number == cg.snap->ps.clientNum) { trap_S_StartLocalSound(cgs.media.dramaticFailure, CHAN_LOCAL); + CGCam_SetMusicMult(0.3, 5000); } break; @@ -2077,7 +2256,10 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_FORCE_DRAINED: DEBUGNAME("EV_FORCE_DRAINED"); ByteToDir( es->eventParm, dir ); - FX_ForceDrained(position, dir); + //FX_ForceDrained(position, dir); + trap_S_StartSound (NULL, es->owner, CHAN_AUTO, cgs.media.drainSound ); + cg_entities[es->owner].teamPowerEffectTime = cg.time + 1000; + cg_entities[es->owner].teamPowerType = 2; break; case EV_GIB_PLAYER: @@ -2139,7 +2321,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_TESTLINE: DEBUGNAME("EV_TESTLINE"); - CG_TestLine(es->origin, es->origin2, es->trickedentindex, es->weapon, 1); + CG_TestLine(es->origin, es->origin2, es->time2, es->weapon, 1); break; case EV_BODY_QUEUE_COPY: diff --git a/CODE-mp/cgame/cg_info.c b/CODE-mp/cgame/cg_info.c index 323dcdf..57e1250 100644 --- a/CODE-mp/cgame/cg_info.c +++ b/CODE-mp/cgame/cg_info.c @@ -7,39 +7,11 @@ #define MAX_LOADING_PLAYER_ICONS 16 #define MAX_LOADING_ITEM_ICONS 26 -static int loadingPlayerIconCount; -static int loadingItemIconCount; -static qhandle_t loadingPlayerIcons[MAX_LOADING_PLAYER_ICONS]; -static qhandle_t loadingItemIcons[MAX_LOADING_ITEM_ICONS]; +//static int loadingPlayerIconCount; +//static qhandle_t loadingPlayerIcons[MAX_LOADING_PLAYER_ICONS]; void CG_LoadBar(void); -/* -=================== -CG_DrawLoadingIcons -=================== -*/ -static void CG_DrawLoadingIcons( void ) { - int n; - int x, y; - - for( n = 0; n < loadingPlayerIconCount; n++ ) { - x = 16 + n * 78; - y = 324-40; - CG_DrawPic( x, y, 64, 64, loadingPlayerIcons[n] ); - } - - for( n = 0; n < loadingItemIconCount; n++ ) { - y = 400-40; - if( n >= 13 ) { - y += 40; - } - x = 16 + n % 13 * 48; - CG_DrawPic( x, y, 32, 32, loadingItemIcons[n] ); - } -} - - /* ====================== CG_LoadingString @@ -61,12 +33,8 @@ void CG_LoadingItem( int itemNum ) { gitem_t *item; item = &bg_itemlist[itemNum]; - - if ( item->icon && loadingItemIconCount < MAX_LOADING_ITEM_ICONS ) { - loadingItemIcons[loadingItemIconCount++] = trap_R_RegisterShaderNoMip( item->icon ); - } - CG_LoadingString( item->pickup_name ); + CG_LoadingString( CG_GetStripEdString("INGAME",item->classname) ); } /* @@ -76,13 +44,14 @@ CG_LoadingClient */ void CG_LoadingClient( int clientNum ) { const char *info; - char *skin; char personality[MAX_QPATH]; - char model[MAX_QPATH]; - char iconName[MAX_QPATH]; info = CG_ConfigString( CS_PLAYERS + clientNum ); +/* + char model[MAX_QPATH]; + char iconName[MAX_QPATH]; + char *skin; if ( loadingPlayerIconCount < MAX_LOADING_PLAYER_ICONS ) { Q_strncpyz( model, Info_ValueForKey( info, "model" ), sizeof( model ) ); skin = Q_strrchr( model, '/' ); @@ -107,7 +76,7 @@ void CG_LoadingClient( int clientNum ) { loadingPlayerIconCount++; } } - +*/ Q_strncpyz( personality, Info_ValueForKey( info, "n" ), sizeof(personality) ); Q_CleanStr( personality ); @@ -128,6 +97,7 @@ CG_DrawInformation Draw all the status / pacifier stuff during level loading ==================== */ +#define UI_INFOFONT (UI_BIGFONT) void CG_DrawInformation( void ) { const char *s; const char *info; @@ -156,11 +126,13 @@ void CG_DrawInformation( void ) { // the first 150 rows are reserved for the client connection // screen to write into if ( cg.infoScreenText[0] ) { - UI_DrawProportionalString( 320, 128-32, va("Loading... %s", cg.infoScreenText), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + const char *psLoading = CG_GetStripEdString("MENUS3", "LOADING_MAPNAME"); + UI_DrawProportionalString( 320, 128-32, va(/*"Loading... %s"*/ psLoading, cg.infoScreenText), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); } else { - UI_DrawProportionalString( 320, 128-32, "Awaiting snapshot...", - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + const char *psAwaitingSnapshot = CG_GetStripEdString("MENUS3", "AWAITING_SNAPSHOT"); + UI_DrawProportionalString( 320, 128-32, /*"Awaiting snapshot..."*/psAwaitingSnapshot, + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); } // draw info string information @@ -174,14 +146,15 @@ void CG_DrawInformation( void ) { Q_strncpyz(buf, Info_ValueForKey( info, "sv_hostname" ), 1024); Q_CleanStr(buf); UI_DrawProportionalString( 320, y, buf, - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; // pure server s = Info_ValueForKey( sysInfo, "sv_pure" ); if ( s[0] == '1' ) { - UI_DrawProportionalString( 320, y, "Pure Server", - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + const char *psPure = CG_GetStripEdString("INGAMETEXT", "PURE_SERVER"); + UI_DrawProportionalString( 320, y, psPure, + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } @@ -189,7 +162,7 @@ void CG_DrawInformation( void ) { s = CG_ConfigString( CS_MOTD ); if ( s[0] ) { UI_DrawProportionalString( 320, y, s, - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } @@ -201,15 +174,15 @@ void CG_DrawInformation( void ) { s = CG_ConfigString( CS_MESSAGE ); if ( s[0] ) { UI_DrawProportionalString( 320, y, s, - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } // cheats warning s = Info_ValueForKey( sysInfo, "sv_cheats" ); if ( s[0] == '1' ) { - UI_DrawProportionalString( 320, y, va("%s", (char *)CG_GetStripEdString("INGAMETEXT", "CHEATSAREENABLED")), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( 320, y, CG_GetStripEdString("INGAMETEXT", "CHEATSAREENABLED"), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } @@ -234,34 +207,34 @@ void CG_DrawInformation( void ) { s = "Team FFA"; break; case GT_SAGA: - s = "Saga"; + s = "N/A"; break; case GT_CTF: s = "Capture The Flag"; break; case GT_CTY: - s = "Capture The Ysalimari"; + s = "Capture The Ysalamiri"; break; default: s = "Unknown Gametype"; break; } UI_DrawProportionalString( 320, y, s, - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; value = atoi( Info_ValueForKey( info, "timelimit" ) ); if ( value ) { - UI_DrawProportionalString( 320, y, va( "%s %i", (char *)CG_GetStripEdString("INGAMETEXT", "TIMELIMIT"), value ), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( 320, y, va( "%s %i", CG_GetStripEdString("INGAMETEXT", "TIMELIMIT"), value ), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } if (cgs.gametype < GT_CTF ) { value = atoi( Info_ValueForKey( info, "fraglimit" ) ); if ( value ) { - UI_DrawProportionalString( 320, y, va( "%s %i", (char *)CG_GetStripEdString("INGAMETEXT", "FRAGLIMIT"), value ), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( 320, y, va( "%s %i", CG_GetStripEdString("INGAMETEXT", "FRAGLIMIT"), value ), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } @@ -269,8 +242,8 @@ void CG_DrawInformation( void ) { { value = atoi( Info_ValueForKey( info, "duel_fraglimit" ) ); if ( value ) { - UI_DrawProportionalString( 320, y, va( "%s %i", (char *)CG_GetStripEdString("INGAMETEXT", "WINLIMIT"), value ), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( 320, y, va( "%s %i", CG_GetStripEdString("INGAMETEXT", "WINLIMIT"), value ), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } } @@ -279,8 +252,8 @@ void CG_DrawInformation( void ) { if (cgs.gametype >= GT_CTF) { value = atoi( Info_ValueForKey( info, "capturelimit" ) ); if ( value ) { - UI_DrawProportionalString( 320, y, va( "%s %i", (char *)CG_GetStripEdString("INGAMETEXT", "CAPTURELIMIT"), value ), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( 320, y, va( "%s %i", CG_GetStripEdString("INGAMETEXT", "CAPTURELIMIT"), value ), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } } @@ -289,8 +262,8 @@ void CG_DrawInformation( void ) { { value = atoi( Info_ValueForKey( info, "g_forceBasedTeams" ) ); if ( value ) { - UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "FORCEBASEDTEAMS") ), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_DrawProportionalString( 320, y, CG_GetStripEdString("INGAMETEXT", "FORCEBASEDTEAMS"), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } } @@ -299,29 +272,108 @@ void CG_DrawInformation( void ) { value = atoi( Info_ValueForKey( info, "g_maxForceRank" ) ); if ( value && !valueNOFP ) { - UI_DrawProportionalString( 320, y, va( "%s %i", (char *)CG_GetStripEdString("INGAMETEXT", "MAXFORCERANK"), value ), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + char fmStr[1024]; + + trap_SP_GetStringTextString("INGAMETEXT_MAXFORCERANK",fmStr, sizeof(fmStr)); + + UI_DrawProportionalString( 320, y, va( "%s %s", fmStr, CG_GetStripEdString("INGAMETEXT", forceMasteryLevels[value]) ), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } else if (!valueNOFP) { - UI_DrawProportionalString( 320, y, va( "%s 20", (char *)CG_GetStripEdString("INGAMETEXT", "MAXFORCERANK") ), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + char fmStr[1024]; + trap_SP_GetStringTextString("INGAMETEXT_MAXFORCERANK",fmStr, sizeof(fmStr)); + + UI_DrawProportionalString( 320, y, va( "%s %s", fmStr, (char *)CG_GetStripEdString("INGAMETEXT", forceMasteryLevels[7]) ), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } - value = atoi( Info_ValueForKey( info, "g_weaponDisable" ) ); + if (cgs.gametype == GT_TOURNAMENT) + { + value = atoi( Info_ValueForKey( info, "g_duelWeaponDisable" ) ); + } + else + { + value = atoi( Info_ValueForKey( info, "g_weaponDisable" ) ); + } if ( cgs.gametype != GT_JEDIMASTER && value ) { UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "SABERONLYSET") ), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } if ( valueNOFP ) { UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "NOFPSET") ), - UI_CENTER|UI_SMALLFONT|UI_DROPSHADOW, colorWhite ); + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); y += PROP_HEIGHT; } + + + // Display the rules based on type + y += PROP_HEIGHT; + switch ( cgs.gametype ) { + case GT_FFA: + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_FFA_1")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + break; + case GT_HOLOCRON: + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_HOLO_1")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_HOLO_2")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + break; + case GT_JEDIMASTER: + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_JEDI_1")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_JEDI_2")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + break; + case GT_SINGLE_PLAYER: + break; + case GT_TOURNAMENT: + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_DUEL_1")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_DUEL_2")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + break; + case GT_TEAM: + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_TEAM_1")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_TEAM_2")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + break; + case GT_SAGA: + break; + case GT_CTF: + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_CTF_1")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_CTF_2")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + break; + case GT_CTY: + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_CTY_1")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + UI_DrawProportionalString( 320, y, va( "%s", (char *)CG_GetStripEdString("INGAMETEXT", "RULES_CTY_2")), + UI_CENTER|UI_INFOFONT|UI_DROPSHADOW, colorWhite ); + y += PROP_HEIGHT; + break; + default: + break; + } } /* @@ -331,20 +383,24 @@ CG_LoadBar */ void CG_LoadBar(void) { - int x,y,i,xLength,height,pad; - - y = 442; - pad = 5; - x = 202 + pad; - height = 12; - xLength = 21; + const int numticks = 9, tickwidth = 40, tickheight = 8; + const int tickpadx = 20, tickpady = 12; + const int capwidth = 8; + const int barwidth = numticks*tickwidth+tickpadx*2+capwidth*2, barleft = ((640-barwidth)/2); + const int barheight = tickheight + tickpady*2, bartop = 480-barheight; + const int capleft = barleft+tickpadx, tickleft = capleft+capwidth, ticktop = bartop+tickpady; trap_R_SetColor( colorWhite ); - CG_DrawPic(166,428,640-(164*2), 32, cgs.media.loadBarLEDSurround); + // Draw background + CG_DrawPic(barleft, bartop, barwidth, barheight, cgs.media.loadBarLEDSurround); - for (i=0;i < cg.loadLCARSStage;i++) - { - CG_DrawPic(x + (i*pad) + (i*xLength),y, 32, 8, cgs.media.loadBarLED); - } + // Draw left cap (backwards) + CG_DrawPic(tickleft, ticktop, -capwidth, tickheight, cgs.media.loadBarLEDCap); + + // Draw bar + CG_DrawPic(tickleft, ticktop, tickwidth*cg.loadLCARSStage, tickheight, cgs.media.loadBarLED); + + // Draw right cap + CG_DrawPic(tickleft+tickwidth*cg.loadLCARSStage, ticktop, capwidth, tickheight, cgs.media.loadBarLEDCap); } diff --git a/CODE-mp/cgame/cg_local.h b/CODE-mp/cgame/cg_local.h index a48cab4..00db1a8 100644 --- a/CODE-mp/cgame/cg_local.h +++ b/CODE-mp/cgame/cg_local.h @@ -78,7 +78,6 @@ #define DEFAULT_MODEL "kyle" #define DEFAULT_TEAM_MODEL "kyle" -#define DEFAULT_TEAM_HEAD "kyle" #define DEFAULT_FORCEPOWERS "5-1-000000000000000000" //"rank-side-heal.lev.speed.push.pull.tele.grip.lightning.rage.protect.absorb.teamheal.teamforce.drain.see" @@ -234,6 +233,9 @@ typedef struct centity_s { int trickAlpha; int trickAlphaTime; + + int teamPowerEffectTime; + qboolean teamPowerType; //0 regen, 1 heal, 2 drain } centity_t; @@ -482,8 +484,8 @@ typedef struct { // gameplay char modelName[MAX_QPATH]; char skinName[MAX_QPATH]; - char headModelName[MAX_QPATH]; - char headSkinName[MAX_QPATH]; +// char headModelName[MAX_QPATH]; +// char headSkinName[MAX_QPATH]; char forcePowers[MAX_QPATH]; char redTeam[MAX_TEAMNAME]; char blueTeam[MAX_TEAMNAME]; @@ -506,8 +508,8 @@ typedef struct { qhandle_t torsoModel; qhandle_t torsoSkin; - qhandle_t headModel; - qhandle_t headSkin; + //qhandle_t headModel; + //qhandle_t headSkin; qboolean ATST; @@ -874,20 +876,22 @@ extern forceTicPos_t ammoTicPos[]; typedef struct cgscreffects_s { - float FOV; - float FOV2; + float FOV; + float FOV2; - float shake_intensity; - int shake_duration; - int shake_start; + float shake_intensity; + int shake_duration; + int shake_start; - float music_volume_mulitplier; - int music_volume_time; + float music_volume_multiplier; + int music_volume_time; + qboolean music_volume_set; } cgscreffects_t; extern cgscreffects_t cgScreenEffects; void CGCam_Shake( float intensity, int duration ); +void CGCam_SetMusicMult( float multiplier, int duration ); // all of the model, shader, and sound references that are // loaded at gamestate time are stored in cgMedia_t @@ -898,6 +902,7 @@ typedef struct { qhandle_t whiteShader; qhandle_t loadBarLED; + qhandle_t loadBarLEDCap; qhandle_t loadBarLEDSurround; qhandle_t bryarFrontFlash; @@ -990,6 +995,8 @@ typedef struct { // Pain view shader qhandle_t viewPainShader; + qhandle_t viewPainShader_Shields; + qhandle_t viewPainShader_ShieldsAndHealth; // powerup shaders qhandle_t quadShader; @@ -1006,6 +1013,8 @@ typedef struct { qhandle_t playerShieldDamage; qhandle_t forceSightBubble; + qhandle_t forceShell; + qhandle_t sightShell; // Disruptor zoom graphics qhandle_t disruptorMask; @@ -1035,6 +1044,15 @@ typedef struct { qhandle_t heartShader; + // All the player shells + qhandle_t ysaliredShader; + qhandle_t ysaliblueShader; + qhandle_t ysalimariShader; + qhandle_t boonShader; + qhandle_t endarkenmentShader; + qhandle_t enlightenmentShader; + qhandle_t invulnerabilityShader; + #ifdef JK2AWARDS // medals shown during gameplay qhandle_t medalImpressive; @@ -1057,6 +1075,9 @@ typedef struct { sfxHandle_t grenadeBounce1; sfxHandle_t grenadeBounce2; + sfxHandle_t teamHealSound; + sfxHandle_t teamRegenSound; + sfxHandle_t teleInSound; sfxHandle_t teleOutSound; sfxHandle_t respawnSound; @@ -1089,6 +1110,7 @@ typedef struct { sfxHandle_t watrOutSound; sfxHandle_t watrUnSound; + sfxHandle_t deploySeeker; sfxHandle_t medkitSound; // teamplay sounds @@ -1111,6 +1133,8 @@ typedef struct { sfxHandle_t redTookYsalSound; sfxHandle_t blueTookYsalSound; + sfxHandle_t drainSound; + //music blips sfxHandle_t happyMusic; sfxHandle_t dramaticFailure; @@ -1288,6 +1312,7 @@ typedef struct { int dmflags; int teamflags; int fraglimit; + int duel_fraglimit; int capturelimit; int timelimit; int maxclients; @@ -1311,6 +1336,9 @@ typedef struct { int scores1, scores2; // from configstrings int jediMaster; + int duelWinner; + int duelist1; + int duelist2; int redflag, blueflag; // flag status from configstrings int flagStatus; @@ -1430,6 +1458,8 @@ extern vmCvar_t cg_simpleItems; extern vmCvar_t cg_fov; extern vmCvar_t cg_zoomFov; +extern vmCvar_t cg_swingAngles; + extern vmCvar_t cg_saberContact; extern vmCvar_t cg_saberTrail; @@ -1469,6 +1499,7 @@ extern vmCvar_t cg_teamChatsOnly; extern vmCvar_t cg_noVoiceChats; extern vmCvar_t cg_noVoiceText; extern vmCvar_t cg_scorePlum; +extern vmCvar_t cg_hudFiles; extern vmCvar_t cg_smoothClients; extern vmCvar_t pmove_fixed; extern vmCvar_t pmove_msec; @@ -1495,6 +1526,8 @@ extern vmCvar_t cg_enableBreath; extern vmCvar_t cg_singlePlayerActive; extern vmCvar_t cg_recordSPDemo; extern vmCvar_t cg_recordSPDemoName; + +extern vmCvar_t ui_myteam; /* Ghoul2 Insert Start */ @@ -1589,6 +1622,7 @@ void CG_ColorForHealth( vec4_t hcolor ); void CG_GetColorForHealth( int health, int armor, vec4_t hcolor ); void UI_DrawProportionalString( int x, int y, const char* str, int style, vec4_t color ); +void UI_DrawScaledProportionalString( int x, int y, const char* str, int style, vec4_t color, float scale); void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ); void CG_DrawSides(float x, float y, float w, float h, float size); void CG_DrawTopBottom(float x, float y, float w, float h, float size); @@ -1619,6 +1653,7 @@ void CG_SelectNextPlayer(void); float CG_GetValue(int ownerDraw); qboolean CG_OwnerDrawVisible(int flags); void CG_RunMenuScript(char **args); +qboolean CG_DeferMenuScript(char **args); void CG_ShowResponseHead(void); void CG_SetPrintString(int type, const char *p); void CG_InitTeamChat(void); @@ -2057,7 +2092,7 @@ void trap_FX_PlayBoltedEffectID( int id, sharedBoltInterface_t *fxObj ); void trap_FX_AddScheduledEffects( void ); int trap_FX_InitSystem( void ); // called in CG_Init to purge the fx system. qboolean trap_FX_FreeSystem( void ); // ditches all active effects; -void trap_FX_AdjustTime( int time ); +void trap_FX_AdjustTime( int time, vec3_t vieworg, vec3_t viewaxis[3] ); void trap_FX_AddPoly( addpolyArgStruct_t *p ); void trap_FX_AddBezier( addbezierArgStruct_t *p ); diff --git a/CODE-mp/cgame/cg_main.c b/CODE-mp/cgame/cg_main.c index 0e2d745..56c70fe 100644 --- a/CODE-mp/cgame/cg_main.c +++ b/CODE-mp/cgame/cg_main.c @@ -409,6 +409,8 @@ vmCvar_t cg_simpleItems; vmCvar_t cg_fov; vmCvar_t cg_zoomFov; +vmCvar_t cg_swingAngles; + vmCvar_t cg_saberContact; vmCvar_t cg_saberTrail; @@ -485,6 +487,8 @@ vmCvar_t cg_singlePlayerActive; vmCvar_t cg_recordSPDemo; vmCvar_t cg_recordSPDemoName; +vmCvar_t ui_myteam; + typedef struct { vmCvar_t *vmCvar; char *cvarName; @@ -547,6 +551,8 @@ static cvarTable_t cvarTable[] = { // bk001129 { &cg_tracerWidth, "cg_tracerwidth", "1", CVAR_CHEAT }, { &cg_tracerLength, "cg_tracerlength", "100", CVAR_CHEAT }, + { &cg_swingAngles, "cg_swingAngles", "1", 0 }, + { &cg_saberContact, "cg_saberContact", "1", 0 }, { &cg_saberTrail, "cg_saberTrail", "1", 0 }, @@ -562,7 +568,7 @@ static cvarTable_t cvarTable[] = { // bk001129 { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_CHEAT }, { &cg_thirdPersonPitchOffset, "cg_thirdPersonPitchOffset", "0", CVAR_CHEAT }, { &cg_thirdPersonVertOffset, "cg_thirdPersonVertOffset", "16", CVAR_CHEAT }, - { &cg_thirdPersonCameraDamp, "cg_thirdPersonCameraDamp", "0.3", CVAR_CHEAT }, + { &cg_thirdPersonCameraDamp, "cg_thirdPersonCameraDamp", "0.3", 0 }, { &cg_thirdPersonTargetDamp, "cg_thirdPersonTargetDamp", "0.5", CVAR_CHEAT }, { &cg_thirdPersonHorzOffset, "cg_thirdPersonHorzOffset", "0", CVAR_CHEAT }, @@ -592,8 +598,8 @@ static cvarTable_t cvarTable[] = { // bk001129 { &cg_currentSelectedPlayer, "cg_currentSelectedPlayer", "0", CVAR_ARCHIVE}, { &cg_currentSelectedPlayerName, "cg_currentSelectedPlayerName", "", CVAR_ARCHIVE}, { &cg_singlePlayer, "ui_singlePlayerActive", "0", CVAR_USERINFO}, - { &cg_enableDust, "g_enableDust", "0", CVAR_SERVERINFO}, - { &cg_enableBreath, "g_enableBreath", "0", CVAR_SERVERINFO}, + { &cg_enableDust, "g_enableDust", "0", 0}, + { &cg_enableBreath, "g_enableBreath", "0", 0}, { &cg_singlePlayerActive, "ui_singlePlayerActive", "0", CVAR_USERINFO}, { &cg_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE}, { &cg_recordSPDemoName, "ui_recordSPDemoName", "", CVAR_ARCHIVE}, @@ -604,6 +610,7 @@ static cvarTable_t cvarTable[] = { // bk001129 { &cg_timescaleFadeSpeed, "cg_timescaleFadeSpeed", "0", 0}, { &cg_timescale, "timescale", "1", 0}, { &cg_scorePlum, "cg_scorePlums", "1", CVAR_USERINFO | CVAR_ARCHIVE}, + { &cg_hudFiles, "cg_hudFiles", "0", CVAR_USERINFO | CVAR_ARCHIVE}, { &cg_smoothClients, "cg_smoothClients", "0", CVAR_USERINFO | CVAR_ARCHIVE}, { &cg_cameraMode, "com_cameraMode", "0", CVAR_CHEAT}, @@ -614,6 +621,9 @@ static cvarTable_t cvarTable[] = { // bk001129 { &cg_smallFont, "ui_smallFont", "0.25", CVAR_ARCHIVE}, { &cg_bigFont, "ui_bigFont", "0.4", CVAR_ARCHIVE}, { &cg_trueLightning, "cg_trueLightning", "0.0", CVAR_ARCHIVE}, + + { &ui_myteam, "ui_myteam", "0", CVAR_ROM|CVAR_INTERNAL}, + // { &cg_pmove_fixed, "cg_pmove_fixed", "0", CVAR_USERINFO | CVAR_ARCHIVE } /* Ghoul2 Insert Start @@ -648,15 +658,16 @@ void CG_RegisterCvars( void ) { forceModelModificationCount = cg_forceModel.modificationCount; trap_Cvar_Register(NULL, "model", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE ); - trap_Cvar_Register(NULL, "headmodel", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE ); + //trap_Cvar_Register(NULL, "headmodel", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE ); trap_Cvar_Register(NULL, "team_model", DEFAULT_TEAM_MODEL, CVAR_USERINFO | CVAR_ARCHIVE ); - trap_Cvar_Register(NULL, "team_headmodel", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE ); + //trap_Cvar_Register(NULL, "team_headmodel", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE ); trap_Cvar_Register(NULL, "forcepowers", DEFAULT_FORCEPOWERS, CVAR_USERINFO | CVAR_ARCHIVE ); // Cvars uses for transferring data between client and server trap_Cvar_Register(NULL, "ui_about_gametype", "0", CVAR_ROM|CVAR_INTERNAL ); trap_Cvar_Register(NULL, "ui_about_fraglimit", "0", CVAR_ROM|CVAR_INTERNAL ); trap_Cvar_Register(NULL, "ui_about_capturelimit", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register(NULL, "ui_about_duellimit", "0", CVAR_ROM|CVAR_INTERNAL ); trap_Cvar_Register(NULL, "ui_about_timelimit", "0", CVAR_ROM|CVAR_INTERNAL ); trap_Cvar_Register(NULL, "ui_about_maxclients", "0", CVAR_ROM|CVAR_INTERNAL ); trap_Cvar_Register(NULL, "ui_about_dmflags", "0", CVAR_ROM|CVAR_INTERNAL ); @@ -940,9 +951,10 @@ static void CG_RegisterSounds( void ) { trap_S_RegisterSound( "sound/weapons/saber/saberhitwall3" ); trap_S_RegisterSound("sound/weapons/saber/saberhit.wav"); + cgs.media.teamHealSound = trap_S_RegisterSound("sound/weapons/force/teamheal.wav"); + cgs.media.teamRegenSound = trap_S_RegisterSound("sound/weapons/force/teamforce.wav"); + trap_S_RegisterSound("sound/weapons/force/heal.wav"); - trap_S_RegisterSound("sound/weapons/force/teamheal.wav"); - trap_S_RegisterSound("sound/weapons/force/teamforce.wav"); trap_S_RegisterSound("sound/weapons/force/speed.wav"); trap_S_RegisterSound("sound/weapons/force/see.wav"); trap_S_RegisterSound("sound/weapons/force/rage.wav"); @@ -950,12 +962,10 @@ static void CG_RegisterSounds( void ) { trap_S_RegisterSound("sound/weapons/force/lightninghit.wav"); trap_S_RegisterSound("sound/weapons/force/drain.wav"); trap_S_RegisterSound("sound/weapons/force/jumpbuild.wav"); - trap_S_RegisterSound("sound/weapons/force/jump.wav"); trap_S_RegisterSound("sound/weapons/force/distract.wav"); trap_S_RegisterSound("sound/weapons/force/distractstop.wav"); trap_S_RegisterSound("sound/weapons/force/pull.wav"); trap_S_RegisterSound("sound/weapons/force/push.wav"); - trap_S_RegisterSound("sound/weapons/force/grip.mp3"); if (cg_buildScript.integer) { @@ -982,7 +992,8 @@ static void CG_RegisterSounds( void ) { trap_S_RegisterSound("sound/chars/turret/startup.wav"); trap_S_RegisterSound("sound/chars/turret/shutdown.wav"); trap_S_RegisterSound("sound/chars/turret/move.wav"); - trap_S_RegisterSound("sound/player/suitenergy.wav"); + trap_S_RegisterSound("sound/player/pickuphealth.wav"); + trap_S_RegisterSound("sound/player/pickupshield.wav"); trap_S_RegisterSound("sound/effects/glassbreak1.wav"); @@ -991,6 +1002,13 @@ static void CG_RegisterSounds( void ) { trap_S_RegisterSound("sound/weapons/force/speedloop.wav"); + trap_S_RegisterSound("sound/weapons/force/protecthit.mp3"); //PDSOUND_PROTECTHIT + trap_S_RegisterSound("sound/weapons/force/protect.mp3"); //PDSOUND_PROTECT + trap_S_RegisterSound("sound/weapons/force/absorbhit.mp3"); //PDSOUND_ABSORBHIT + trap_S_RegisterSound("sound/weapons/force/absorb.mp3"); //PDSOUND_ABSORB + trap_S_RegisterSound("sound/weapons/force/jump.mp3"); //PDSOUND_FORCEJUMP + trap_S_RegisterSound("sound/weapons/force/grip.mp3"); //PDSOUND_FORCEGRIP + if ( cgs.gametype >= GT_TEAM || cg_buildScript.integer ) { #ifdef JK2AWARDS @@ -1016,6 +1034,8 @@ static void CG_RegisterSounds( void ) { } } + cgs.media.drainSound = trap_S_RegisterSound("sound/weapons/force/drained.mp3"); + cgs.media.happyMusic = trap_S_RegisterSound("music/goodsmall.mp3"); cgs.media.dramaticFailure = trap_S_RegisterSound("music/badsmall.mp3"); @@ -1132,6 +1152,7 @@ static void CG_RegisterSounds( void ) { cg.loadLCARSStage = 2; // FIXME: only needed with item + cgs.media.deploySeeker = trap_S_RegisterSound ("sound/chars/seeker/misc/hiss"); cgs.media.medkitSound = trap_S_RegisterSound ("sound/items/use_bacta.wav"); cgs.media.winnerSound = trap_S_RegisterSound( "sound/chars/mothma/misc/40MOM006" ); @@ -1318,6 +1339,8 @@ static void CG_RegisterGraphics( void ) { cgs.media.playerShieldDamage = trap_R_RegisterShader("gfx/misc/personalshield"); cgs.media.forceSightBubble = trap_R_RegisterShader("gfx/misc/sightbubble"); + cgs.media.forceShell = trap_R_RegisterShader("powerups/forceshell"); + cgs.media.sightShell = trap_R_RegisterShader("powerups/sightshell"); cgs.media.itemHoloModel = trap_R_RegisterModel("models/map_objects/mp/holo.md3"); @@ -1353,19 +1376,16 @@ static void CG_RegisterGraphics( void ) { cgs.media.blueFlagModel = trap_R_RegisterModel( "models/flags/b_flag_ysal.md3" ); } - trap_R_RegisterShader( "gfx/hud/mpi_rflag_x" ); - trap_R_RegisterShader( "gfx/hud/mpi_bflag_x" ); + trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_x" ); + trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_x" ); - trap_R_RegisterShader( "gfx/hud/mpi_rflag_ys" ); - trap_R_RegisterShader( "gfx/hud/mpi_bflag_ys" ); + trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag_ys" ); + trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag_ys" ); - trap_R_RegisterShader( "gfx/hud/mpi_rflag" ); - trap_R_RegisterShader( "gfx/hud/mpi_bflag" ); + trap_R_RegisterShaderNoMip( "gfx/hud/mpi_rflag" ); + trap_R_RegisterShaderNoMip( "gfx/hud/mpi_bflag" ); - if (cg_buildScript.integer) - { - trap_R_RegisterShader("gfx/2d/net.tga"); - } + trap_R_RegisterShaderNoMip("gfx/2d/net.tga"); cgs.media.flagPoleModel = trap_R_RegisterModel( "models/flag2/flagpole.md3" ); cgs.media.flagFlapModel = trap_R_RegisterModel( "models/flag2/flagflap3.md3" ); @@ -1394,12 +1414,24 @@ static void CG_RegisterGraphics( void ) { cgs.media.redQuadShader = trap_R_RegisterShader("powerups/blueflag" ); cgs.media.teamStatusBar = trap_R_RegisterShader( "gfx/2d/colorbar.tga" ); } + else if ( cgs.gametype == GT_JEDIMASTER ) + { + cgs.media.teamRedShader = trap_R_RegisterShader( "sprites/team_red" ); + } cgs.media.armorModel = 0;//trap_R_RegisterModel( "models/powerups/armor/armor_yel.md3" ); cgs.media.armorIcon = 0;//trap_R_RegisterShaderNoMip( "icons/iconr_yellow" ); cgs.media.heartShader = trap_R_RegisterShaderNoMip( "ui/assets/statusbar/selectedhealth.tga" ); + cgs.media.ysaliredShader = trap_R_RegisterShader( "powerups/ysaliredshell"); + cgs.media.ysaliblueShader = trap_R_RegisterShader( "powerups/ysaliblueshell"); + cgs.media.ysalimariShader = trap_R_RegisterShader( "powerups/ysalimarishell"); + cgs.media.boonShader = trap_R_RegisterShader( "powerups/boonshell"); + cgs.media.endarkenmentShader = trap_R_RegisterShader( "powerups/endarkenmentshell"); + cgs.media.enlightenmentShader = trap_R_RegisterShader( "powerups/enlightenmentshell"); + cgs.media.invulnerabilityShader = trap_R_RegisterShader( "powerups/invulnerabilityshell"); + #ifdef JK2AWARDS cgs.media.medalImpressive = trap_R_RegisterShaderNoMip( "medal_impressive" ); cgs.media.medalExcellent = trap_R_RegisterShaderNoMip( "medal_excellent" ); @@ -1454,7 +1486,10 @@ Ghoul2 Insert End cgs.media.shadowMarkShader = trap_R_RegisterShader( "markShadow" ); cgs.media.wakeMarkShader = trap_R_RegisterShader( "wake" ); cgs.media.bloodMarkShader = trap_R_RegisterShader( "bloodMark" ); - cgs.media.viewPainShader = trap_R_RegisterShader( "gfx/misc/borgeyeflare" ); + + cgs.media.viewPainShader = trap_R_RegisterShader( "gfx/misc/borgeyeflare" ); + cgs.media.viewPainShader_Shields = trap_R_RegisterShader( "gfx/mp/dmgshader_shields" ); + cgs.media.viewPainShader_ShieldsAndHealth = trap_R_RegisterShader( "gfx/mp/dmgshader_shieldsandhealth" ); // register the inline models cgs.numInlineModels = trap_CM_NumInlineModels(); @@ -1545,9 +1580,12 @@ Ghoul2 Insert End const char *CG_GetStripEdString(char *refSection, char *refName) { - static char text[1024]={0}; - trap_SP_GetStringTextString(va("%s_%s", refSection, refName), text, sizeof(text)); - return text; + static char text[2][1024]={0}; //just incase it's nested + static int index = 0; + + index ^= 1; + trap_SP_GetStringTextString(va("%s_%s", refSection, refName), text[index], sizeof(text[0])); + return text[index]; } @@ -2057,7 +2095,7 @@ static qhandle_t CG_FeederItemImage(float feederID, int index) { return 0; } -static void CG_FeederSelection(float feederID, int index) { +static qboolean CG_FeederSelection(float feederID, int index) { if ( cgs.gametype >= GT_TEAM ) { int i, count; int team = (feederID == FEEDER_REDTEAM_LIST) ? TEAM_RED : TEAM_BLUE; @@ -2073,6 +2111,8 @@ static void CG_FeederSelection(float feederID, int index) { } else { cg.selectedScore = index; } + + return qtrue; } static float CG_Cvar_Get(const char *cvar) { @@ -2159,6 +2199,7 @@ void CG_LoadHudMenu() cgDC.getValue = &CG_GetValue; cgDC.ownerDrawVisible = &CG_OwnerDrawVisible; cgDC.runScript = &CG_RunMenuScript; + cgDC.deferScript = &CG_DeferMenuScript; cgDC.getTeamColor = &CG_GetTeamColor; cgDC.setCVar = trap_Cvar_Set; cgDC.getCVarString = trap_Cvar_VariableStringBuffer; @@ -2345,6 +2386,7 @@ Ghoul2 Insert End cgs.media.whiteShader = trap_R_RegisterShader( "white" ); cgs.media.loadBarLED = trap_R_RegisterShaderNoMip( "gfx/hud/load_tick" ); + cgs.media.loadBarLEDCap = trap_R_RegisterShaderNoMip( "gfx/hud/load_tick_cap" ); cgs.media.loadBarLEDSurround= trap_R_RegisterShaderNoMip( "gfx/hud/mp_levelload" ); //rww - precache HUD weapon icons here @@ -2438,9 +2480,9 @@ Ghoul2 Insert End cgs.media.HUDLeftStatic = cgs.media.HUDLeftFrame;//trap_R_RegisterShaderNoMip( "gfx/hud/static_test" ); cgs.media.HUDLeft = cgs.media.HUDInnerLeft;//trap_R_RegisterShaderNoMip( "gfx/hud/hudleft" ); - cgs.media.HUDSaberStyle1 = trap_R_RegisterShader( "gfx/hud/saber_styles1" ); - cgs.media.HUDSaberStyle2 = trap_R_RegisterShader( "gfx/hud/saber_styles2" ); - cgs.media.HUDSaberStyle3 = trap_R_RegisterShader( "gfx/hud/saber_styles3" ); + cgs.media.HUDSaberStyle1 = trap_R_RegisterShader( "gfx/hud/saber_stylesFast" ); + cgs.media.HUDSaberStyle2 = trap_R_RegisterShader( "gfx/hud/saber_stylesMed" ); + cgs.media.HUDSaberStyle3 = trap_R_RegisterShader( "gfx/hud/saber_stylesStrong" ); cgs.media.HUDRightFrame = trap_R_RegisterShaderNoMip("gfx/hud/hudrightframe"); cgs.media.HUDInnerRight = trap_R_RegisterShaderNoMip( "gfx/hud/hudright_innerframe" ); diff --git a/CODE-mp/cgame/cg_media.h b/CODE-mp/cgame/cg_media.h new file mode 100644 index 0000000..e69de29 diff --git a/CODE-mp/cgame/cg_newDraw.c b/CODE-mp/cgame/cg_newDraw.c index 7543b4c..baaf620 100644 --- a/CODE-mp/cgame/cg_newDraw.c +++ b/CODE-mp/cgame/cg_newDraw.c @@ -133,233 +133,6 @@ void CG_SelectPrevPlayer(void) { } -static void CG_DrawPlayerArmorIcon( rectDef_t *rect, qboolean draw2D ) { - centity_t *cent; - playerState_t *ps; - vec3_t angles; - vec3_t origin; - - if ( cg_drawStatus.integer == 0 ) { - return; - } - - cent = &cg_entities[cg.snap->ps.clientNum]; - ps = &cg.snap->ps; - - if ( draw2D || ( !cg_draw3dIcons.integer && cg_drawIcons.integer) ) { // bk001206 - parentheses - CG_DrawPic( rect->x, rect->y + rect->h/2 + 1, rect->w, rect->h, cgs.media.armorIcon ); - } else if (cg_draw3dIcons.integer) { - VectorClear( angles ); - origin[0] = 90; - origin[1] = 0; - origin[2] = -10; - angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0; - - CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cgs.media.armorModel, 0, origin, angles ); - } - -} - -static void CG_DrawPlayerArmorValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { - char num[16]; - int value; - centity_t *cent; - playerState_t *ps; - - cent = &cg_entities[cg.snap->ps.clientNum]; - ps = &cg.snap->ps; - - value = ps->stats[STAT_ARMOR]; - - - if (shader) { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } else { - Com_sprintf (num, sizeof(num), "%i", value); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle, FONT_MEDIUM); - } -} - -static void CG_DrawPlayerAmmoIcon( rectDef_t *rect, qboolean draw2D ) { - centity_t *cent; - playerState_t *ps; - vec3_t angles; - vec3_t origin; - - cent = &cg_entities[cg.snap->ps.clientNum]; - ps = &cg.snap->ps; - - if ( draw2D || (!cg_draw3dIcons.integer && cg_drawIcons.integer) ) { // bk001206 - parentheses - qhandle_t icon; - icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon; - if ( icon ) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, icon ); - } - } else if (cg_draw3dIcons.integer) { - if ( cent->currentState.weapon && cg_weapons[ cent->currentState.weapon ].ammoModel ) { - VectorClear( angles ); - origin[0] = 70; - origin[1] = 0; - origin[2] = 0; - angles[YAW] = 90 + 20 * sin( cg.time / 1000.0 ); - CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, cg_weapons[ cent->currentState.weapon ].ammoModel, 0, origin, angles ); - } - } -} - -static void CG_DrawPlayerAmmoValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { - char num[16]; - int value; - centity_t *cent; - playerState_t *ps; - - cent = &cg_entities[cg.snap->ps.clientNum]; - ps = &cg.snap->ps; - - if ( cent->currentState.weapon ) - { - value = ps->ammo[weaponData[cent->currentState.weapon].ammoIndex]; - if ( value > -1 ) { - if (shader) { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } else { - Com_sprintf (num, sizeof(num), "%i", value); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle, FONT_MEDIUM); - } - } - } - -} - - -static void CG_DrawPlayerForceValue(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { - char num[16]; - int value; - centity_t *cent; - playerState_t *ps; - - cent = &cg_entities[cg.snap->ps.clientNum]; - ps = &cg.snap->ps; - - if ( cent->currentState.weapon ) - { - value = ps->fd.forcePower; - if ( value > -1 ) - { - if (shader) - { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } - else - { - Com_sprintf (num, sizeof(num), "%i", value); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle, FONT_MEDIUM); - } - } - } - -} - - -static void CG_DrawPlayerHead(rectDef_t *rect, qboolean draw2D) { - vec3_t angles; - float size, stretch; - float frac; - float x = rect->x; - - VectorClear( angles ); - - if ( cg.damageTime && cg.time - cg.damageTime < DAMAGE_TIME ) { - frac = (float)(cg.time - cg.damageTime ) / DAMAGE_TIME; - size = rect->w * 1.25 * ( 1.5 - frac * 0.5 ); - - stretch = size - rect->w * 1.25; - // kick in the direction of damage - x -= stretch * 0.5 + cg.damageX * stretch * 0.5; - - cg.headStartYaw = 180 + cg.damageX * 45; - - cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI ); - cg.headEndPitch = 5 * cos( crandom()*M_PI ); - - cg.headStartTime = cg.time; - cg.headEndTime = cg.time + 100 + random() * 2000; - } else { - if ( cg.time >= cg.headEndTime ) { - // select a new head angle - cg.headStartYaw = cg.headEndYaw; - cg.headStartPitch = cg.headEndPitch; - cg.headStartTime = cg.headEndTime; - cg.headEndTime = cg.time + 100 + random() * 2000; - - cg.headEndYaw = 180 + 20 * cos( crandom()*M_PI ); - cg.headEndPitch = 5 * cos( crandom()*M_PI ); - } - - size = rect->w * 1.25; - } - - // if the server was frozen for a while we may have a bad head start time - if ( cg.headStartTime > cg.time ) { - cg.headStartTime = cg.time; - } - - frac = ( cg.time - cg.headStartTime ) / (float)( cg.headEndTime - cg.headStartTime ); - frac = frac * frac * ( 3 - 2 * frac ); - angles[YAW] = cg.headStartYaw + ( cg.headEndYaw - cg.headStartYaw ) * frac; - angles[PITCH] = cg.headStartPitch + ( cg.headEndPitch - cg.headStartPitch ) * frac; - - CG_DrawHead( x, rect->y, rect->w, rect->h, cg.snap->ps.clientNum, angles ); -} - -static void CG_DrawSelectedPlayerHealth( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - clientInfo_t *ci; - int value; - char num[16]; - - ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - if (ci) { - if (shader) { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } else { - Com_sprintf (num, sizeof(num), "%i", ci->health); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle, FONT_MEDIUM); - } - } -} - -static void CG_DrawSelectedPlayerArmor( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - clientInfo_t *ci; - int value; - char num[16]; - ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - if (ci) { - if (ci->armor > 0) { - if (shader) { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } else { - Com_sprintf (num, sizeof(num), "%i", ci->armor); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle, FONT_MEDIUM); - } - } - } -} - qhandle_t CG_StatusHandle(int task) { qhandle_t h = cgs.media.assaultShader; switch (task) { @@ -391,442 +164,6 @@ qhandle_t CG_StatusHandle(int task) { return h; } -static void CG_DrawSelectedPlayerStatus( rectDef_t *rect ) { - clientInfo_t *ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - if (ci) { - qhandle_t h; - if (cgs.orderPending) { - // blink the icon - if ( cg.time > cgs.orderTime - 2500 && (cg.time >> 9 ) & 1 ) { - return; - } - h = CG_StatusHandle(cgs.currentOrder); - } else { - h = CG_StatusHandle(ci->teamTask); - } - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, h ); - } -} - - -static void CG_DrawPlayerStatus( rectDef_t *rect ) { - clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum]; - if (ci) { - qhandle_t h = CG_StatusHandle(ci->teamTask); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, h); - } -} - - -static void CG_DrawSelectedPlayerName( rectDef_t *rect, float scale, vec4_t color, qboolean voice, int textStyle) { - clientInfo_t *ci; - ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]); - if (ci) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, ci->name, 0, 0, textStyle, FONT_MEDIUM); - } -} - -static void CG_DrawSelectedPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) { - clientInfo_t *ci; - ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - if (ci) { - const char *p = CG_ConfigString(CS_LOCATIONS + ci->location); - if (!p || !*p) { - p = "unknown"; - } - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle, FONT_MEDIUM); - } -} - -static void CG_DrawPlayerLocation( rectDef_t *rect, float scale, vec4_t color, int textStyle ) { - clientInfo_t *ci = &cgs.clientinfo[cg.snap->ps.clientNum]; - if (ci) { - const char *p = CG_ConfigString(CS_LOCATIONS + ci->location); - if (!p || !*p) { - p = "unknown"; - } - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, p, 0, 0, textStyle, FONT_MEDIUM); - } -} - - - -static void CG_DrawSelectedPlayerWeapon( rectDef_t *rect ) { - clientInfo_t *ci; - - ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - if (ci) { - if ( cg_weapons[ci->curWeapon].weaponIcon ) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_weapons[ci->curWeapon].weaponIcon ); - } else { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader); - } - } -} - -static void CG_DrawPlayerScore( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - char num[16]; - int value = cg.snap->ps.persistant[PERS_SCORE]; - - if (shader) { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } else { - Com_sprintf (num, sizeof(num), "%i", value); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle, FONT_MEDIUM); - } -} - -static void CG_DrawPlayerItem( rectDef_t *rect, float scale, qboolean draw2D) { - int value; - vec3_t origin, angles; - - value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM]; - if ( value ) { - CG_RegisterItemVisuals( value ); - - if (qtrue) { - CG_RegisterItemVisuals( value ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon ); - } else { - VectorClear( angles ); - origin[0] = 90; - origin[1] = 0; - origin[2] = -10; - angles[YAW] = ( cg.time & 2047 ) * 360 / 2048.0; - CG_Draw3DModel(rect->x, rect->y, rect->w, rect->h, cg_items[ value ].models[0], 0, origin, angles ); - } - } - -} - - -static void CG_DrawSelectedPlayerPowerup( rectDef_t *rect, qboolean draw2D ) { - clientInfo_t *ci; - int j; - float x, y; - - ci = cgs.clientinfo + sortedTeamPlayers[CG_GetSelectedPlayer()]; - if (ci) { - x = rect->x; - y = rect->y; - - for (j = 0; j < PW_NUM_POWERUPS; j++) { - if (ci->powerups & (1 << j)) { - gitem_t *item; - item = BG_FindItemForPowerup( j ); - if (item) { - CG_DrawPic( x, y, rect->w, rect->h, trap_R_RegisterShader( item->icon ) ); - x += 3; - y += 3; - return; - } - } - } - - } -} - - -static void CG_DrawSelectedPlayerHead( rectDef_t *rect, qboolean draw2D, qboolean voice ) { - clipHandle_t cm; - clientInfo_t *ci; - float len; - vec3_t origin; - vec3_t mins, maxs, angles; - - - ci = cgs.clientinfo + ((voice) ? cgs.currentVoiceClient : sortedTeamPlayers[CG_GetSelectedPlayer()]); - - if (ci) { - if ( cg_draw3dIcons.integer ) { - cm = ci->headModel; - if ( !cm ) { - return; - } - - // offset the origin y and z to center the head - trap_R_ModelBounds( cm, mins, maxs ); - - origin[2] = -0.5 * ( mins[2] + maxs[2] ); - origin[1] = 0.5 * ( mins[1] + maxs[1] ); - - // calculate distance so the head nearly fills the box - // assume heads are taller than wide - len = 0.7 * ( maxs[2] - mins[2] ); - origin[0] = len / 0.268; // len / tan( fov/2 ) - - // allow per-model tweaking - VectorAdd( origin, ci->headOffset, origin ); - - angles[PITCH] = 0; - angles[YAW] = 180; - angles[ROLL] = 0; - - CG_Draw3DModel( rect->x, rect->y, rect->w, rect->h, ci->headModel, ci->headSkin, origin, angles ); - } else if ( cg_drawIcons.integer ) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, ci->modelIcon ); - } - - // if they are deferred, draw a cross out - if ( ci->deferred ) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.deferShader ); - } - } - -} - - -static void CG_DrawPlayerHealth(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - playerState_t *ps; - int value; - char num[16]; - - ps = &cg.snap->ps; - - value = ps->stats[STAT_HEALTH]; - - if (shader) { - trap_R_SetColor( color ); - CG_DrawPic(rect->x, rect->y, rect->w, rect->h, shader); - trap_R_SetColor( NULL ); - } else { - Com_sprintf (num, sizeof(num), "%i", value); - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + (rect->w - value) / 2, rect->y + rect->h, scale, color, num, 0, 0, textStyle, FONT_MEDIUM); - } -} - - -static void CG_DrawRedScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - int value; - char num[16]; - if ( cgs.scores1 == SCORE_NOT_PRESENT ) { - Com_sprintf (num, sizeof(num), "-"); - } - else { - Com_sprintf (num, sizeof(num), "%i", cgs.scores1); - } - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle, FONT_MEDIUM); -} - -static void CG_DrawBlueScore(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - int value; - char num[16]; - - if ( cgs.scores2 == SCORE_NOT_PRESENT ) { - Com_sprintf (num, sizeof(num), "-"); - } - else { - Com_sprintf (num, sizeof(num), "%i", cgs.scores2); - } - value = CG_Text_Width(num, scale, 0); - CG_Text_Paint(rect->x + rect->w - value, rect->y + rect->h, scale, color, num, 0, 0, textStyle, FONT_MEDIUM); -} - -// FIXME: team name support -static void CG_DrawRedName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_redTeamName.string , 0, 0, textStyle, FONT_MEDIUM); -} - -static void CG_DrawBlueName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cg_blueTeamName.string, 0, 0, textStyle, FONT_MEDIUM); -} - -static void CG_DrawBlueFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) { - int i; - for ( i = 0 ; i < cgs.maxclients ; i++ ) { - if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle, FONT_MEDIUM); - return; - } - } -} - -static void CG_DrawBlueFlagStatus(rectDef_t *rect, qhandle_t shader) { - if (cgs.gametype != GT_CTF && cgs.gametype != GT_CTY) { - return; - } - if (shader) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - } else { - gitem_t *item = BG_FindItemForPowerup( PW_BLUEFLAG ); - if (item) { - vec4_t color = {0, 0, 1, 1}; - trap_R_SetColor(color); - if( cgs.blueflag >= 0 && cgs.blueflag <= 2 ) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.blueflag] ); - } else { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] ); - } - trap_R_SetColor(NULL); - } - } -} - -static void CG_DrawBlueFlagHead(rectDef_t *rect) { - int i; - for ( i = 0 ; i < cgs.maxclients ; i++ ) { - if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_RED && cgs.clientinfo[i].powerups & ( 1<< PW_BLUEFLAG )) { - vec3_t angles; - VectorClear( angles ); - angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );; - CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles ); - return; - } - } -} - -static void CG_DrawRedFlagName(rectDef_t *rect, float scale, vec4_t color, int textStyle ) { - int i; - for ( i = 0 ; i < cgs.maxclients ; i++ ) { - if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, cgs.clientinfo[i].name, 0, 0, textStyle, FONT_MEDIUM); - return; - } - } -} - -static void CG_DrawRedFlagStatus(rectDef_t *rect, qhandle_t shader) { - if (cgs.gametype != GT_CTF && cgs.gametype != GT_CTY) { - return; - } - if (shader) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - } else { - gitem_t *item = BG_FindItemForPowerup( PW_REDFLAG ); - if (item) { - vec4_t color = {1, 0, 0, 1}; - trap_R_SetColor(color); - if( cgs.redflag >= 0 && cgs.redflag <= 2) { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[cgs.redflag] ); - } else { - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.flagShaders[0] ); - } - trap_R_SetColor(NULL); - } - } -} - -static void CG_DrawRedFlagHead(rectDef_t *rect) { - int i; - for ( i = 0 ; i < cgs.maxclients ; i++ ) { - if ( cgs.clientinfo[i].infoValid && cgs.clientinfo[i].team == TEAM_BLUE && cgs.clientinfo[i].powerups & ( 1<< PW_REDFLAG )) { - vec3_t angles; - VectorClear( angles ); - angles[YAW] = 180 + 20 * sin( cg.time / 650.0 );; - CG_DrawHead( rect->x, rect->y, rect->w, rect->h, 0,angles ); - return; - } - } -} - -static void CG_DrawCTFPowerUp(rectDef_t *rect) -{ -// int value; - - if (cgs.gametype < GT_CTF) { - return; - } -/* - value = cg.snap->ps.stats[STAT_PERSISTANT_POWERUP]; - if ( value ) { - CG_RegisterItemVisuals( value ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_items[ value ].icon ); - } - */ -} - - - -static void CG_DrawTeamColor(rectDef_t *rect, vec4_t color) { - CG_DrawTeamBackground(rect->x, rect->y, rect->w, rect->h, color[3], cg.snap->ps.persistant[PERS_TEAM]); -} - -static void CG_DrawAreaPowerUp(rectDef_t *rect, int align, float special, float scale, vec4_t color) { - char num[16]; - int sorted[MAX_POWERUPS]; - int sortedTime[MAX_POWERUPS]; - int i, j, k; - int active; - playerState_t *ps; - int t; - gitem_t *item; - float f; - rectDef_t r2; - float *inc; - r2.x = rect->x; - r2.y = rect->y; - r2.w = rect->w; - r2.h = rect->h; - - inc = (align == HUD_VERTICAL) ? &r2.y : &r2.x; - - ps = &cg.snap->ps; - - if ( ps->stats[STAT_HEALTH] <= 0 ) { - return; - } - - // sort the list by time remaining - active = 0; - for ( i = 0 ; i < MAX_POWERUPS ; i++ ) { - if ( !ps->powerups[ i ] ) { - continue; - } - t = ps->powerups[ i ] - cg.time; - // ZOID--don't draw if the power up has unlimited time (999 seconds) - // This is true of the CTF flags - if ( t <= 0 || t >= 999000) { - continue; - } - - // insert into the list - for ( j = 0 ; j < active ; j++ ) { - if ( sortedTime[j] >= t ) { - for ( k = active - 1 ; k >= j ; k-- ) { - sorted[k+1] = sorted[k]; - sortedTime[k+1] = sortedTime[k]; - } - break; - } - } - sorted[j] = i; - sortedTime[j] = t; - active++; - } - - // draw the icons and timers - for ( i = 0 ; i < active ; i++ ) { - item = BG_FindItemForPowerup( sorted[i] ); - - if (item) { - t = ps->powerups[ sorted[i] ]; - if ( t - cg.time >= POWERUP_BLINKS * POWERUP_BLINK_TIME ) { - trap_R_SetColor( NULL ); - } else { - vec4_t modulate; - - f = (float)( t - cg.time ) / POWERUP_BLINK_TIME; - f -= (int)f; - modulate[0] = modulate[1] = modulate[2] = modulate[3] = f; - trap_R_SetColor( modulate ); - } - - CG_DrawPic( r2.x, r2.y, r2.w * .75, r2.h, trap_R_RegisterShader( item->icon ) ); - - Com_sprintf (num, sizeof(num), "%i", sortedTime[i] / 1000); - CG_Text_Paint(r2.x + (r2.w * .75) + 3 , r2.y + r2.h, scale, color, num, 0, 0, 0, FONT_MEDIUM); - *inc += r2.w + special; - } - - } - trap_R_SetColor( NULL ); - -} float CG_GetValue(int ownerDraw) { centity_t *cent; @@ -986,32 +323,8 @@ qboolean CG_OwnerDrawVisible(int flags) { } - -static void CG_DrawPlayerHasFlag(rectDef_t *rect, qboolean force2D) { - int adj = (force2D) ? 0 : 2; - if( cg.predictedPlayerState.powerups[PW_REDFLAG] ) { - CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_RED, force2D); - } else if( cg.predictedPlayerState.powerups[PW_BLUEFLAG] ) { - CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_BLUE, force2D); - } else if( cg.predictedPlayerState.powerups[PW_NEUTRALFLAG] ) { - CG_DrawFlagModel( rect->x + adj, rect->y + adj, rect->w - adj, rect->h - adj, TEAM_FREE, force2D); - } -} - -static void CG_DrawAreaSystemChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, systemChat, 0, 0, 0, FONT_MEDIUM); -} - -static void CG_DrawAreaTeamChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color,teamChat1, 0, 0, 0, FONT_MEDIUM); -} - -static void CG_DrawAreaChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, teamChat2, 0, 0, 0, FONT_MEDIUM); -} - const char *CG_GetKillerText(void) { - const char *s = ""; + static const char *s = ""; if ( cg.killerName[0] ) { s = va("%s %s", CG_GetStripEdString("INGAMETEXT", "KILLEDBY"), cg.killerName ); } @@ -1019,38 +332,15 @@ const char *CG_GetKillerText(void) { } -static void CG_DrawKiller(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - // fragged by ... line - if ( cg.killerName[0] ) { - int x = rect->x + rect->w / 2; - CG_Text_Paint(x - CG_Text_Width(CG_GetKillerText(), scale, 0) / 2, rect->y + rect->h, scale, color, CG_GetKillerText(), 0, 0, textStyle, FONT_MEDIUM); - } - -} - - -static void CG_DrawCapFragLimit(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { - int limit = (cgs.gametype >= GT_CTF) ? cgs.capturelimit : cgs.fraglimit; - CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", limit),0, 0, textStyle, FONT_MEDIUM); -} - -static void CG_Draw1stPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { - if (cgs.scores1 != SCORE_NOT_PRESENT) { - CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores1),0, 0, textStyle, FONT_MEDIUM); - } -} - -static void CG_Draw2ndPlace(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle) { - if (cgs.scores2 != SCORE_NOT_PRESENT) { - CG_Text_Paint(rect->x, rect->y, scale, color, va("%2i", cgs.scores2),0, 0, textStyle, FONT_MEDIUM); - } -} - const char *CG_GetGameStatusText(void) { - const char *s = ""; + static const char *s = ""; if ( cgs.gametype < GT_TEAM) { - if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) { - s = va("%s place with %i",CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ),cg.snap->ps.persistant[PERS_SCORE] ); + if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) + { + char sPlaceWith[256]; + trap_SP_GetStringTextString("INGAMETEXT_PLACE_WITH", sPlaceWith, sizeof(sPlaceWith)); + + s = va("%s %s %i",CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ), sPlaceWith, cg.snap->ps.persistant[PERS_SCORE] ); } } else { if ( cg.teamScores[0] == cg.teamScores[1] ) { @@ -1064,10 +354,6 @@ const char *CG_GetGameStatusText(void) { return s; } -static void CG_DrawGameStatus(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GetGameStatusText(), 0, 0, textStyle, FONT_MEDIUM); -} - const char *CG_GameTypeString(void) { if ( cgs.gametype == GT_FFA ) { return "Free For All"; @@ -1078,17 +364,14 @@ const char *CG_GameTypeString(void) { } else if ( cgs.gametype == GT_TEAM ) { return "Team FFA"; } else if ( cgs.gametype == GT_SAGA ) { - return "Saga"; + return "N/A"; } else if ( cgs.gametype == GT_CTF ) { return "Capture the Flag"; } else if ( cgs.gametype == GT_CTY ) { - return "Capture the Ysalimari"; + return "Capture the Ysalamiri"; } return ""; } -static void CG_DrawGameType(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader, int textStyle ) { - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, CG_GameTypeString(), 0, 0, textStyle, FONT_MEDIUM); -} extern int MenuFontToHandle(int iMenuFont); @@ -1709,6 +992,10 @@ void CG_ShowResponseHead(void) { void CG_RunMenuScript(char **args) { } +qboolean CG_DeferMenuScript (char **args) +{ + return qfalse; +} void CG_GetTeamColor(vec4_t *color) { if (cg.snap->ps.persistant[PERS_TEAM] == TEAM_RED) { diff --git a/CODE-mp/cgame/cg_playeranimate.c b/CODE-mp/cgame/cg_playeranimate.c new file mode 100644 index 0000000..e69de29 diff --git a/CODE-mp/cgame/cg_players.c b/CODE-mp/cgame/cg_players.c index ca43789..43b259a 100644 --- a/CODE-mp/cgame/cg_players.c +++ b/CODE-mp/cgame/cg_players.c @@ -64,235 +64,6 @@ CLIENT INFO ============================================================================= */ -/* -========================== -CG_FileExists -========================== -*/ -static qboolean CG_FileExists(const char *filename) { - int len; - fileHandle_t f; - - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - if (len>0) { - trap_FS_FCloseFile(f); - return qtrue; - } - return qfalse; -} - -/* -========================== -CG_FindClientModelFile -========================== -*/ -static qboolean CG_FindClientModelFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *base, const char *ext ) { - char *team, *charactersFolder; - int i; - - if ( cgs.gametype >= GT_TEAM ) { - switch ( ci->team ) { - case TEAM_BLUE: { - team = "blue"; - break; - } - default: { - team = "red"; - break; - } - } - } - else { - team = "default"; - } - charactersFolder = ""; - while(1) { - for ( i = 0; i < 2; i++ ) { - if ( i == 0 && teamName && *teamName ) { - // "models/players/characters/james/stroggs/lower_lily_red.skin" - Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, team, ext ); - } - else { - // "models/players/characters/james/lower_lily_red.skin" - Com_sprintf( filename, length, "models/players/%s%s/%s_%s_%s.%s", charactersFolder, modelName, base, skinName, team, ext ); - } - if ( CG_FileExists( filename ) ) { - return qtrue; - } - if ( cgs.gametype >= GT_TEAM ) { - if ( i == 0 && teamName && *teamName ) { - // "models/players/characters/james/stroggs/lower_red.skin" - Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, team, ext ); - } - else { - // "models/players/characters/james/lower_red.skin" - Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, team, ext ); - } - } - else { - if ( i == 0 && teamName && *teamName ) { - // "models/players/characters/james/stroggs/lower_lily.skin" - Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", charactersFolder, modelName, teamName, base, skinName, ext ); - } - else { - // "models/players/characters/james/lower_lily.skin" - Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", charactersFolder, modelName, base, skinName, ext ); - } - } - if ( CG_FileExists( filename ) ) { - return qtrue; - } - if ( !teamName || !*teamName ) { - break; - } - } - // if tried the heads folder first - if ( charactersFolder[0] ) { - break; - } - charactersFolder = "characters/"; - } - - return qfalse; -} - -/* -========================== -CG_FindClientHeadFile -========================== -*/ -static qboolean CG_FindClientHeadFile( char *filename, int length, clientInfo_t *ci, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) { - char *team, *headsFolder; - int i; - - if ( cgs.gametype >= GT_TEAM ) { - switch ( ci->team ) { - case TEAM_BLUE: { - team = "blue"; - break; - } - default: { - team = "red"; - break; - } - } - } - else { - team = "default"; - } - - if ( headModelName[0] == '*' ) { - headsFolder = "heads/"; - headModelName++; - } - else { - headsFolder = ""; - } - while(1) { - for ( i = 0; i < 2; i++ ) { - if ( i == 0 && teamName && *teamName ) { - Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext ); - } - else { - Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext ); - } - if ( CG_FileExists( filename ) ) { - return qtrue; - } - if ( cgs.gametype >= GT_TEAM ) { - if ( i == 0 && teamName && *teamName ) { - Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, team, ext ); - } - else { - Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, team, ext ); - } - } - else { - if ( i == 0 && teamName && *teamName ) { - Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext ); - } - else { - Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext ); - } - } - if ( CG_FileExists( filename ) ) { - return qtrue; - } - if ( !teamName || !*teamName ) { - break; - } - } - // if tried the heads folder first - if ( headsFolder[0] ) { - break; - } - headsFolder = "heads/"; - } - - return qfalse; -} - -/* -========================== -CG_RegisterClientSkin -========================== -*/ -static qboolean CG_RegisterClientSkin( clientInfo_t *ci, const char *teamName, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName ) { - char filename[MAX_QPATH]; - - /* - Com_sprintf( filename, sizeof( filename ), "models/players/%s/%slower_%s.skin", modelName, teamName, skinName ); - ci->legsSkin = trap_R_RegisterSkin( filename ); - if (!ci->legsSkin) { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%slower_%s.skin", modelName, teamName, skinName ); - ci->legsSkin = trap_R_RegisterSkin( filename ); - if (!ci->legsSkin) { - Com_Printf( "Leg skin load failure: %s\n", filename ); - } - } - - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/%supper_%s.skin", modelName, teamName, skinName ); - ci->torsoSkin = trap_R_RegisterSkin( filename ); - if (!ci->torsoSkin) { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%supper_%s.skin", modelName, teamName, skinName ); - ci->torsoSkin = trap_R_RegisterSkin( filename ); - if (!ci->torsoSkin) { - Com_Printf( "Torso skin load failure: %s\n", filename ); - } - } - */ - if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "lower", "skin" ) ) { - ci->legsSkin = trap_R_RegisterSkin( filename ); - } - if (!ci->legsSkin) { - Com_Printf( "Leg skin load failure: %s\n", filename ); - } - - if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "upper", "skin" ) ) { - ci->torsoSkin = trap_R_RegisterSkin( filename ); - } - if (!ci->torsoSkin) { - Com_Printf( "Torso skin load failure: %s\n", filename ); - } - - if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headModelName, headSkinName, "head", "skin" ) ) { - ci->headSkin = trap_R_RegisterSkin( filename ); - } - if (!ci->headSkin) { - Com_Printf( "Head skin load failure: %s\n", filename ); - } - - // if any skins failed to load - if ( !ci->legsSkin || !ci->torsoSkin || !ci->headSkin ) { - return qfalse; - } - - // Model icon for drawing the portrait on screen - ci->modelIcon = trap_R_RegisterShaderNoMip ( va ( "models/players/%s/icon_%s", modelName, skinName ) ); - - return qtrue; -} /* ========================== @@ -332,7 +103,7 @@ qboolean CG_NeedAnimSequence(int anim) CG_RegisterClientModelname ========================== */ -static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName, const char *teamName, int clientNum ) { +static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName, const char *teamName, int clientNum ) { int handle; char afilename[MAX_QPATH]; char /**GLAName,*/ *slash; @@ -350,9 +121,7 @@ retryModel: if (badModel) { modelName = "kyle"; - headModelName = "kyle"; skinName = "default"; - headSkinName = "default"; Com_Printf("WARNING: Attempted to load an unsupported multiplayer model! (bad or missing bone, or missing animation sequence)\n"); badModel = qfalse; @@ -644,6 +413,7 @@ void CG_LoadClientInfo( clientInfo_t *ci ) { ci->deferred = qfalse; + /* if (ci->team == TEAM_SPECTATOR) { // reset any existing players and bodies, because they might be in bad @@ -663,6 +433,7 @@ void CG_LoadClientInfo( clientInfo_t *ci ) { return; } + */ teamname[0] = 0; if( cgs.gametype >= GT_TEAM) { @@ -676,10 +447,10 @@ void CG_LoadClientInfo( clientInfo_t *ci ) { strcat( teamname, "/" ); } modelloaded = qtrue; - if ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname, clientNum ) ) { - if ( cg_buildScript.integer && ci->team != TEAM_SPECTATOR ) { - CG_Error( "CG_RegisterClientModelname( %s, %s, %s, %s %s ) failed", ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname ); - } + if ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName, teamname, clientNum ) ) { + //CG_Error( "CG_RegisterClientModelname( %s, %s, %s, %s %s ) failed", ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname ); + //rww - DO NOT error out here! Someone could just type in a nonsense model name and crash everyone's client. + //Give it a chance to load default model for this client instead. // fall back to default team name if( cgs.gametype >= GT_TEAM) { @@ -689,11 +460,11 @@ void CG_LoadClientInfo( clientInfo_t *ci ) { } else { Q_strncpyz(teamname, DEFAULT_REDTEAM_NAME, sizeof(teamname) ); } - if ( !CG_RegisterClientModelname( ci, DEFAULT_TEAM_MODEL, ci->skinName, DEFAULT_TEAM_HEAD, ci->skinName, teamname, -1 ) ) { + if ( !CG_RegisterClientModelname( ci, DEFAULT_TEAM_MODEL, ci->skinName, teamname, -1 ) ) { CG_Error( "DEFAULT_TEAM_MODEL / skin (%s/%s) failed to register", DEFAULT_TEAM_MODEL, ci->skinName ); } } else { - if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default", DEFAULT_MODEL, "default", teamname, -1 ) ) { + if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default", teamname, -1 ) ) { CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL ); } } @@ -830,8 +601,8 @@ static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) { to->legsSkin = from->legsSkin; to->torsoModel = from->torsoModel; to->torsoSkin = from->torsoSkin; - to->headModel = from->headModel; - to->headSkin = from->headSkin; + //to->headModel = from->headModel; + //to->headSkin = from->headSkin; to->modelIcon = from->modelIcon; to->newAnims = from->newAnims; @@ -877,8 +648,8 @@ static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) { } if ( !Q_stricmp( ci->modelName, match->modelName ) && !Q_stricmp( ci->skinName, match->skinName ) - && !Q_stricmp( ci->headModelName, match->headModelName ) - && !Q_stricmp( ci->headSkinName, match->headSkinName ) +// && !Q_stricmp( ci->headModelName, match->headModelName ) +// && !Q_stricmp( ci->headSkinName, match->headSkinName ) && !Q_stricmp( ci->blueTeam, match->blueTeam ) && !Q_stricmp( ci->redTeam, match->redTeam ) && (cgs.gametype < GT_TEAM || ci->team == match->team) @@ -920,8 +691,8 @@ static void CG_SetDeferredClientInfo( clientInfo_t *ci ) { } if ( Q_stricmp( ci->skinName, match->skinName ) || Q_stricmp( ci->modelName, match->modelName ) || - Q_stricmp( ci->headModelName, match->headModelName ) || - Q_stricmp( ci->headSkinName, match->headSkinName ) || +// Q_stricmp( ci->headModelName, match->headModelName ) || +// Q_stricmp( ci->headSkinName, match->headSkinName ) || (cgs.gametype >= GT_TEAM && ci->team != match->team) ) { continue; } @@ -1097,6 +868,7 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { } // head model +/* v = Info_ValueForKey( configstring, "hmodel" ); if ( cg_forceModel.integer ) { // forcemodel makes everyone use a single model @@ -1139,7 +911,7 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { *slash = 0; } } - +*/ // force powers v = Info_ValueForKey( configstring, "forcepowers" ); Q_strncpyz( newInfo.forcePowers, v, sizeof( newInfo.forcePowers ) ); @@ -1151,12 +923,12 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { if (newInfo.team == TEAM_RED) { strcpy(newInfo.skinName, "red"); - strcpy(newInfo.headSkinName, "red"); +// strcpy(newInfo.headSkinName, "red"); } if (newInfo.team == TEAM_BLUE) { strcpy(newInfo.skinName, "blue"); - strcpy(newInfo.headSkinName, "blue"); +// strcpy(newInfo.headSkinName, "blue"); } } @@ -1168,7 +940,11 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { forceDefer = trap_MemoryRemaining() < 4000000; // if we are defering loads, just have it pick the first valid - if ( forceDefer || ( cg_deferPlayers.integer && !cg_buildScript.integer && !cg.loading ) ) { + if (cg.snap && cg.snap->ps.clientNum == clientNum && !forceDefer) + { //rww - don't defer your own client info ever, unless really low on memory + CG_LoadClientInfo( &newInfo ); + } + else if ( forceDefer || ( cg_deferPlayers.integer && !cg_buildScript.integer && !cg.loading ) ) { // keep whatever they had if it won't violate team skins CG_SetDeferredClientInfo( &newInfo ); // if we are low on memory, leave them with this model @@ -1250,6 +1026,7 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { */ //It should catch this next update anyway. We just set all ghoul2weapon's to NULL above. } + /* else if (ci->team == TEAM_SPECTATOR && cg_entities[clientNum].ghoul2 && trap_G2_HaveWeGhoul2Models(cg_entities[clientNum].ghoul2)) { //this shouldn't actually happen now because we are not trying to register models for spectators. But just in case. trap_G2API_CleanGhoul2Models(&cg_entities[clientNum].ghoul2); @@ -1258,6 +1035,7 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { trap_G2API_DuplicateGhoul2Instance(ci->ghoul2Model, &cg_entities[clientNum].ghoul2); } } + */ } @@ -1330,6 +1108,19 @@ qboolean CG_InRoll( centity_t *cent ) return qfalse; } +qboolean CG_InRollAnim( centity_t *cent ) +{ + switch ( (cent->currentState.legsAnim&~ANIM_TOGGLEBIT) ) + { + case BOTH_ROLL_F: + case BOTH_ROLL_B: + case BOTH_ROLL_R: + case BOTH_ROLL_L: + return qtrue; + } + return qfalse; +} + /* =============== CG_SetLerpFrameAnimation @@ -1342,6 +1133,7 @@ static void CG_SetLerpFrameAnimation( centity_t *cent, clientInfo_t *ci, lerpFra float animSpeed; int flags=BONE_ANIM_OVERRIDE_FREEZE; int oldAnim = -1; + int blendTime = 150; if (cent->currentState.number < MAX_CLIENTS && cent->currentState.teamowner && @@ -1542,15 +1334,28 @@ static void CG_SetLerpFrameAnimation( centity_t *cent, clientInfo_t *ci, lerpFra if (!cent->isATST) { - if (BG_FlippingAnim(newAnimation) || BG_InDeathAnim(newAnimation)) + if (/*BG_FlippingAnim(newAnimation) ||*/ BG_InDeathAnim(newAnimation)) { flags &= ~BONE_ANIM_BLEND; } else if ( oldAnim != -1 && - (BG_FlippingAnim(oldAnim) || BG_InDeathAnim(oldAnim)) ) + (/*BG_FlippingAnim(oldAnim) ||*/ BG_InDeathAnim(oldAnim)) ) { flags &= ~BONE_ANIM_BLEND; } + + if (flags & BONE_ANIM_BLEND) + { + if (BG_FlippingAnim(newAnimation)) + { + blendTime = 200; + } + else if ( oldAnim != -1 && + (BG_FlippingAnim(oldAnim)) ) + { + blendTime = 200; + } + } } animSpeed *= animSpeedMult; @@ -1570,27 +1375,28 @@ static void CG_SetLerpFrameAnimation( centity_t *cent, clientInfo_t *ci, lerpFra if (torsoOnly) { - trap_G2API_SetBoneAnim(cent->ghoul2, 0, "pelvis", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, lf->frameTime, -1, atstBlend); + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "pelvis", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, atstBlend); } else { - trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, lf->frameTime, -1, atstBlend); + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, atstBlend); } } else { if (torsoOnly) { - trap_G2API_SetBoneAnim(cent->ghoul2, 0, "upper_lumbar", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, lf->frameTime, -1, 150); + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "upper_lumbar", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed,cg.time, -1, blendTime); cgs.clientinfo[cent->currentState.number].torsoAnim = newAnimation; } else { - trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, lf->frameTime, -1, 150); + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, blendTime); cgs.clientinfo[cent->currentState.number].torsoAnim = newAnimation; cgs.clientinfo[cent->currentState.number].legsAnim = newAnimation; } + /* if ((cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) == newAnimation && !BG_FlippingAnim( cent->currentState.legsAnim ) && !BG_SpinningSaberAnim( cent->currentState.legsAnim ) && @@ -1603,8 +1409,20 @@ static void CG_SetLerpFrameAnimation( centity_t *cent, clientInfo_t *ci, lerpFra !BG_SaberInSpecial(cent->currentState.saberMove) && !BG_SaberInSpecialAttack(cent->currentState.torsoAnim) && !BG_SaberInSpecialAttack(cent->currentState.legsAnim) ) + */ + if (cg.snap && cg.snap->ps.clientNum == cent->currentState.number) + { //go ahead and use the predicted state if you can. + if ((cg.predictedPlayerState.torsoAnim&~ANIM_TOGGLEBIT) == newAnimation) + { + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, blendTime); + } + } + else { - trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, lf->frameTime, -1, 150); + if ((cent->currentState.torsoAnim&~ANIM_TOGGLEBIT) == newAnimation) + { + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", anim->firstFrame, anim->firstFrame + anim->numFrames, flags, animSpeed, cg.time, -1, blendTime); + } } } } @@ -1670,7 +1488,7 @@ int CG_InWalkingAnim(int animNum) if (anim == BOTH_WALL_RUN_RIGHT || anim == BOTH_WALL_RUN_LEFT) { - return 9; + return 8; } if (anim >= BOTH_WALK1 && @@ -1831,9 +1649,9 @@ static void CG_RunLerpFrame( centity_t *cent, clientInfo_t *ci, lerpFrame_t *lf, { int flags = BONE_ANIM_OVERRIDE_FREEZE; //|BONE_ANIM_BLEND; float animSpeed = 1.0f; - trap_G2API_SetBoneAnim(cent->ghoul2, 0, "upper_lumbar", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, lf->frameTime, -1, 150); - trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, lf->frameTime, -1, 150); - trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, lf->frameTime, -1, 150); + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "upper_lumbar", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150); + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "model_root", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150); + trap_G2API_SetBoneAnim(cent->ghoul2, 0, "Motion", cent->currentState.forceFrame, cent->currentState.forceFrame+1, flags, animSpeed, cg.time, -1, 150); lf->animationNumber = 0; } @@ -1858,7 +1676,36 @@ static void CG_RunLerpFrame( centity_t *cent, clientInfo_t *ci, lerpFrame_t *lf, { int addFinalFrame = CG_InWalkingAnim(lf->animationNumber); //9; - if (addFinalFrame && !cent->isATST) + if (!cent->isATST && + ((lf->animationNumber&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_RIGHT || (lf->animationNumber&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_LEFT) && + addFinalFrame) + { + if ( lf->frame >= (lf->animation->firstFrame+2) && + lf->oldFrame < (lf->animation->firstFrame+2)) + { + CG_FootStep(cent, ci, lf->animationNumber); + } + else if ( lf->frame >= (lf->animation->firstFrame+addFinalFrame) && + lf->oldFrame < (lf->animation->firstFrame+addFinalFrame)) + { + CG_FootStep(cent, ci, lf->animationNumber); + } + else if ( lf->frame >= (lf->animation->firstFrame+12) && + lf->oldFrame < (lf->animation->firstFrame+12)) + { + CG_FootStep(cent, ci, lf->animationNumber); + } + else if ( lf->frame >= (lf->animation->firstFrame+16) && + lf->oldFrame < (lf->animation->firstFrame+16)) + { + CG_FootStep(cent, ci, lf->animationNumber); + } + else if (lf->oldFrame > lf->frame && lf->frame > (lf->animation->firstFrame+1)) + { //missed one + CG_FootStep(cent, ci, lf->animationNumber); + } + } + else if (addFinalFrame && !cent->isATST) { if ( lf->frame >= (lf->animation->firstFrame+3) && lf->oldFrame < (lf->animation->firstFrame+3)) @@ -2197,128 +2044,6 @@ static void CG_AddPainTwitch( centity_t *cent, vec3_t torsoAngles ) { } -/* -=============== -CG_PlayerAngles - -Handles seperate torso motion - - legs pivot based on direction of movement - - head always looks exactly at cent->lerpAngles - - if motion < 20 degrees, show in head only - if < 45 degrees, also show in torso -=============== -*/ - -static void CG_PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) { - vec3_t legsAngles, torsoAngles, headAngles; - float dest; - static int movementOffsets[8] = { 0, 22, 45, -22, 0, 22, -45, -22 }; - vec3_t velocity; - float speed; - int dir, clientNum; - clientInfo_t *ci; - - VectorCopy( cent->lerpAngles, headAngles ); - headAngles[YAW] = AngleMod( headAngles[YAW] ); - VectorClear( legsAngles ); - VectorClear( torsoAngles ); - - // --------- yaw ------------- - - // allow yaw to drift a bit - if ((( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != BOTH_STAND1) || - ( cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT ) != WeaponReadyAnim[cent->currentState.weapon] ) { - // if not standing still, always point all in the same direction - cent->pe.torso.yawing = qtrue; // always center - cent->pe.torso.pitching = qtrue; // always center - cent->pe.legs.yawing = qtrue; // always center - } - - // adjust legs for movement dir - if ( cent->currentState.eFlags & EF_DEAD ) { - // don't let dead bodies twitch - dir = 0; - } else { - dir = cent->currentState.angles2[YAW]; - if ( dir < 0 || dir > 7 ) { - CG_Error( "Bad player movement angle" ); - } - } - legsAngles[YAW] = headAngles[YAW] + movementOffsets[ dir ]; - torsoAngles[YAW] = headAngles[YAW] + 0.25 * movementOffsets[ dir ]; - - // torso - CG_SwingAngles( torsoAngles[YAW], 25, 90, /*cg_swingSpeed.value*/ 0.3, ¢->pe.torso.yawAngle, ¢->pe.torso.yawing ); - CG_SwingAngles( legsAngles[YAW], 40, 90, /*cg_swingSpeed.value*/ 0.3, ¢->pe.legs.yawAngle, ¢->pe.legs.yawing ); - - torsoAngles[YAW] = cent->pe.torso.yawAngle; - legsAngles[YAW] = cent->pe.legs.yawAngle; - - // --------- pitch ------------- - - // only show a fraction of the pitch angle in the torso - if ( headAngles[PITCH] > 180 ) { - dest = (-360 + headAngles[PITCH]) * 0.75f; - } else { - dest = headAngles[PITCH] * 0.75f; - } - CG_SwingAngles( dest, 15, 30, 0.1f, ¢->pe.torso.pitchAngle, ¢->pe.torso.pitching ); - torsoAngles[PITCH] = cent->pe.torso.pitchAngle; - - // - clientNum = cent->currentState.clientNum; - if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) { - ci = &cgs.clientinfo[ clientNum ]; - if ( ci->fixedtorso ) { - torsoAngles[PITCH] = 0.0f; - } - } - - // --------- roll ------------- - - - // lean towards the direction of travel - VectorCopy( cent->currentState.pos.trDelta, velocity ); - speed = VectorNormalize( velocity ); - if ( speed ) { - vec3_t axis[3]; - float side; - - speed *= 0.05f; - - AnglesToAxis( legsAngles, axis ); - side = speed * DotProduct( velocity, axis[1] ); - legsAngles[ROLL] -= side; - - side = speed * DotProduct( velocity, axis[0] ); - legsAngles[PITCH] += side; - } - - // - clientNum = cent->currentState.clientNum; - if ( clientNum >= 0 && clientNum < MAX_CLIENTS ) { - ci = &cgs.clientinfo[ clientNum ]; - if ( ci->fixedlegs ) { - legsAngles[YAW] = torsoAngles[YAW]; - legsAngles[PITCH] = 0.0f; - legsAngles[ROLL] = 0.0f; - } - } - - // pain twitch - CG_AddPainTwitch( cent, torsoAngles ); - - // pull the angles back out of the hierarchial chain - AnglesSubtract( headAngles, torsoAngles, headAngles ); - AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); - AnglesToAxis( legsAngles, legs ); - AnglesToAxis( torsoAngles, torso ); - AnglesToAxis( headAngles, head ); -} - typedef struct boneAngleParms_s { void *ghoul2; int modelIndex; @@ -2393,6 +2118,7 @@ void CG_G2ClientSpineAngles( centity_t *cent, vec3_t viewAngles, const vec3_t an !BG_InDeathAnim(cent->currentState.legsAnim) && !BG_InDeathAnim(cent->currentState.torsoAnim) && !CG_InRoll(cent) && + !CG_InRollAnim(cent) && !BG_SaberInSpecial(cent->currentState.saberMove) && !BG_SaberInSpecialAttack(cent->currentState.torsoAnim) && !BG_SaberInSpecialAttack(cent->currentState.legsAnim) && @@ -2423,13 +2149,29 @@ void CG_G2ClientSpineAngles( centity_t *cent, vec3_t viewAngles, const vec3_t an //trap_G2API_GetBoltMatrix( cent->ghoul2, 0, cgs.clientinfo[cent->currentState.number].bolt_motion, &boltMatrix, vec3_origin, cent->lerpOrigin, cg.time, /*cgs.gameModels*/0, cent->modelScale); trap_G2API_GetBoltMatrix_NoReconstruct( cent->ghoul2, 0, cgs.clientinfo[cent->currentState.number].bolt_motion, &boltMatrix, vec3_origin, cent->lerpOrigin, cg.time, /*cgs.gameModels*/0, cent->modelScale); - trap_G2API_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_X, motionFwd ); + // trap_G2API_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_X, motionFwd ); + //trap_G2API_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_Y, motionFwd ); + trap_G2API_GiveMeVectorFromMatrix( &boltMatrix, NEGATIVE_Y, motionFwd ); vectoangles( motionFwd, motionAngles ); for ( ang = 0; ang < 3; ang++ ) { viewAngles[ang] = AngleNormalize180( viewAngles[ang] - AngleNormalize180( motionAngles[ang] ) ); } + + //Using NEGATIVE_Y and subtractinging 90 seems to magically fix our horrible contortion issues. + //SP actually just uses NEGATIVE_Y without this. Unfortunately we have some sort of worthless + //chunk of code in our GBM function that rotates the entire matrix 90 degrees before returning + //a "proper" direction. SP does not have this. And I am not even going to consider changing it at + //this point to match. + //Com_Printf("Comp: %f %f %f\n", viewAngles[0], viewAngles[1], viewAngles[2]); + + if (viewAngles[YAW] < -90) + { + viewAngles[YAW] += 360; + } + + viewAngles[YAW] -= 90; } //distribute the angles differently up the spine //NOTE: each of these distributions must add up to 1.0f @@ -2674,7 +2416,14 @@ static void CG_G2PlayerAngles( centity_t *cent, vec3_t legs[3], vec3_t legsAngle } else { - CG_SwingAngles( legsAngles[YAW], 40, 90, /*cg_swingSpeed.value*/ 0.3, ¢->pe.legs.yawAngle, ¢->pe.legs.yawing ); + if (!cg_swingAngles.integer) + { + cent->pe.legs.yawAngle = legsAngles[YAW]; + } + else + { + CG_SwingAngles( legsAngles[YAW], 40, 90, /*cg_swingSpeed.value*/ 0.3, ¢->pe.legs.yawAngle, ¢->pe.legs.yawing ); + } } legsAngles[YAW] = cent->pe.legs.yawAngle; @@ -2829,43 +2578,6 @@ static void CG_HasteTrail( centity_t *cent ) { smoke->leType = LE_SCALE_FADE; } -/* -=============== -CG_BreathPuffs -=============== -*/ -static void CG_BreathPuffs( centity_t *cent, refEntity_t *head) { - clientInfo_t *ci; - vec3_t up, origin; - int contents; - -// ci = &cgs.clientinfo[ cent->currentState.number ]; // NOTENOTE number was id's code, did they mean clientNum? - ci = &cgs.clientinfo[ cent->currentState.clientNum ]; - - if (!cg_enableBreath.integer) { - return; - } - if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson) { - return; - } - if ( cent->currentState.eFlags & EF_DEAD ) { - return; - } - contents = trap_CM_PointContents( head->origin, 0 ); - if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) { - return; - } - if ( ci->breathPuffTime > cg.time ) { - return; - } - - VectorSet( up, 0, 0, 8 ); - VectorMA(head->origin, 8, head->axis[0], origin); - VectorMA(origin, -4, head->axis[2], origin); - CG_SmokePuff( origin, up, 16, 1, 1, 1, 0.66f, 1500, cg.time, cg.time + 400, LEF_PUFF_DONT_SCALE, cgs.media.shotgunSmokePuffShader ); - ci->breathPuffTime = cg.time + 2000; -} - /* =============== CG_DustTrail @@ -2922,6 +2634,7 @@ static void CG_DustTrail( centity_t *cent ) { CG_TrailItem =============== */ +#if 0 static void CG_TrailItem( centity_t *cent, qhandle_t hModel ) { refEntity_t ent; vec3_t angles; @@ -2941,6 +2654,7 @@ static void CG_TrailItem( centity_t *cent, qhandle_t hModel ) { ent.hModel = hModel; trap_R_AddRefEntityToScene( &ent ); } +#endif /* @@ -3098,6 +2812,7 @@ CG_PlayerFloatSprite Same as above but allows custom RGBA values =============== */ +#if 0 static void CG_PlayerFloatSpriteRGBA( centity_t *cent, qhandle_t shader, vec4_t rgba ) { int rf; refEntity_t ent; @@ -3121,71 +2836,8 @@ static void CG_PlayerFloatSpriteRGBA( centity_t *cent, qhandle_t shader, vec4_t ent.shaderRGBA[3] = rgba[3]; trap_R_AddRefEntityToScene( &ent ); } - - - -/* -=============== -CG_PlayerSprites - -Float sprites over the player's head -=============== -*/ -static void CG_PlayerSprites( centity_t *cent ) { -#if 0 - int team; - - if ( cent->currentState.eFlags & EF_CONNECTION ) { - CG_PlayerFloatSprite( cent, cgs.media.connectionShader ); - return; - } - - if ( cent->currentState.eFlags & EF_TALK ) { - CG_PlayerFloatSprite( cent, cgs.media.balloonShader ); - return; - } - - if ( cent->currentState.eFlags & EF_AWARD_IMPRESSIVE ) { - CG_PlayerFloatSprite( cent, cgs.media.medalImpressive ); - return; - } - - if ( cent->currentState.eFlags & EF_AWARD_EXCELLENT ) { - CG_PlayerFloatSprite( cent, cgs.media.medalExcellent ); - return; - } - - if ( cent->currentState.eFlags & EF_AWARD_GAUNTLET ) { - CG_PlayerFloatSprite( cent, cgs.media.medalGauntlet ); - return; - } - - if ( cent->currentState.eFlags & EF_AWARD_DEFEND ) { - CG_PlayerFloatSprite( cent, cgs.media.medalDefend ); - return; - } - - if ( cent->currentState.eFlags & EF_AWARD_ASSIST ) { - CG_PlayerFloatSprite( cent, cgs.media.medalAssist ); - return; - } - - if ( cent->currentState.eFlags & EF_AWARD_CAP ) { - CG_PlayerFloatSprite( cent, cgs.media.medalCapture ); - return; - } - - team = cgs.clientinfo[ cent->currentState.clientNum ].team; - if ( !(cent->currentState.eFlags & EF_DEAD) && - cg.snap->ps.persistant[PERS_TEAM] == team && - cgs.gametype >= GT_TEAM) { - if (cg_drawFriend.integer) { - CG_PlayerFloatSprite( cent, cgs.media.friendShader ); - } - return; - } #endif -} + /* =============== @@ -3429,13 +3081,6 @@ void CG_ForceGripEffect( vec3_t org ) ex->refEntity.customShader = cgs.media.redSaberGlowShader;//trap_R_RegisterShader( "gfx/effects/forcePush" ); } -static void CG_ForcePushBodyBlur( centity_t *cent, vec3_t origin, vec3_t tempAngles ) -{ - vec3_t eyePos; - - VectorCopy(cent->lerpOrigin, eyePos); - eyePos[2] += 16; -} /* =============== @@ -3757,84 +3402,78 @@ void CG_CreateSaberMarks( vec3_t start, vec3_t end, vec3_t normal ) markPoly_t *mark; markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf; - float radius = 0.3f + random() * 0.3f; + float radius = 0.65f; + + if ( !cg_addMarks.integer ) + { + return; + } VectorSubtract( end, start, axis[1] ); + VectorNormalize( axis[1] ); - // We probably don't want to create a ton of small marks, so bias towards doing larger ones - if ( 1)// VectorNormalize( axis[1] ) > 1.0f )// || rand() & 3 ) + // create the texture axis + VectorCopy( normal, axis[0] ); + CrossProduct( axis[1], axis[0], axis[2] ); + + // create the full polygon that we'll project + for ( i = 0 ; i < 3 ; i++ ) + { // stretch a bit more in the direction that we are traveling in... debateable as to whether this makes things better or worse + originalPoints[0][i] = start[i] - radius * axis[1][i] - radius * axis[2][i]; + originalPoints[1][i] = end[i] + radius * axis[1][i] - radius * axis[2][i]; + originalPoints[2][i] = end[i] + radius * axis[1][i] + radius * axis[2][i]; + originalPoints[3][i] = start[i] - radius * axis[1][i] + radius * axis[2][i]; + } + + VectorScale( normal, -1, projection ); + + // get the fragments + numFragments = trap_CM_MarkFragments( 4, (const float (*)[3])originalPoints, + projection, MAX_MARK_POINTS, markPoints[0], MAX_MARK_FRAGMENTS, markFragments ); + + + for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) { - VectorNormalize( axis[1] ); - // create the texture axis - VectorCopy( normal, axis[0] ); - CrossProduct( axis[1], axis[0], axis[2] ); - - // create the full polygon that we'll project - for ( i = 0 ; i < 3 ; i++ ) + // we have an upper limit on the complexity of polygons that we store persistantly + if ( mf->numPoints > MAX_VERTS_ON_POLY ) { - // stretch a bit more in the direction that we are traveling in... - // debateable as to whether this makes things better or worse - originalPoints[0][i] = start[i] - radius * axis[1][i] - radius * axis[2][i] * 1.3f; - originalPoints[1][i] = end[i] + radius * axis[1][i] - radius * axis[2][i] * 1.3f; - originalPoints[2][i] = end[i] + radius * axis[1][i] + radius * axis[2][i] * 1.3f; - originalPoints[3][i] = start[i] - radius * axis[1][i] + radius * axis[2][i] * 1.3f; + mf->numPoints = MAX_VERTS_ON_POLY; } - VectorScale( normal, -1, projection ); - - // get the fragments - numFragments = trap_CM_MarkFragments( 4, (const float (*)[3])originalPoints, - projection, MAX_MARK_POINTS, markPoints[0], MAX_MARK_FRAGMENTS, markFragments ); - -// colors[0] = colors[1] = colors[2] = colors[3] = 255; - - for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) + for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) { - // we have an upper limit on the complexity of polygons that we store persistantly - if ( mf->numPoints > MAX_VERTS_ON_POLY ) - { - mf->numPoints = MAX_VERTS_ON_POLY; - } + vec3_t delta; - for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) - { - vec3_t delta; + // Set up our texture coords, this may need some work + VectorCopy( markPoints[mf->firstPoint + j], v->xyz ); + VectorAdd( end, start, mid ); + VectorScale( mid, 0.5f, mid ); + VectorSubtract( v->xyz, mid, delta ); - // Set up our texture coords, this may need some work - VectorCopy( markPoints[mf->firstPoint + j], v->xyz ); - VectorAdd( end, start, mid ); - VectorScale( mid, 0.5f, mid ); - VectorSubtract( v->xyz, mid, delta ); - - v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * (0.15f + crandom() * 0.14f); - v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * (0.1f + crandom() * 0.05f); -// *(int *)v->modulate = *(int *)colors; - } - - // save it persistantly, do burn first - mark = CG_AllocMark(); - mark->time = cg.time; - mark->alphaFade = qtrue; - mark->markShader = cgs.media.rivetMarkShader; - mark->poly.numVerts = mf->numPoints; - mark->color[0] = mark->color[1] = mark->color[2] = mark->color[3] = 255; - memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); - - //FIXME: This part looks totally messed up. I don't know exactly what's causing it. - - // And now do a glow pass - // by moving the start time back, we can hack it to fade out way before the burn does - mark = CG_AllocMark(); - mark->time = cg.time - 8500; - mark->alphaFade = qfalse; - mark->markShader = trap_R_RegisterShader("gfx/effects/saberDamageGlow" ); - mark->poly.numVerts = mf->numPoints; - mark->color[0] = 255; - mark->color[1] = 130 + sin( cg.time * 0.03f ) * 36.0f;//80 + random() * 96.0f; - mark->color[2] = 10; - mark->color[3] = 10;//= random()*15.0f; - memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); + v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * (0.05f + random() * 0.03f); + v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * (0.15f + random() * 0.05f); } + + // save it persistantly, do burn first + mark = CG_AllocMark(); + mark->time = cg.time; + mark->alphaFade = qtrue; + mark->markShader = cgs.media.rivetMarkShader; + mark->poly.numVerts = mf->numPoints; + mark->color[0] = mark->color[1] = mark->color[2] = mark->color[3] = 255; + memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); + + // And now do a glow pass + // by moving the start time back, we can hack it to fade out way before the burn does + mark = CG_AllocMark(); + mark->time = cg.time - 8500; + mark->alphaFade = qfalse; + mark->markShader = trap_R_RegisterShader("gfx/effects/saberDamageGlow" ); + mark->poly.numVerts = mf->numPoints; + mark->color[0] = 215 + random() * 40.0f; + mark->color[1] = 96 + random() * 32.0f; + mark->color[2] = mark->color[3] = random()*15.0f; + memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); } } @@ -4047,8 +3686,8 @@ Ghoul2 Insert Start // Hmmm, no impact this frame, but we have an old point // Let's put the mark there, we should use an endcap mark to close the line, but we // can probably just get away with a round mark - // CG_ImpactMark( cgs.media.rivetMarkShader, client->saberTrail.oldPos[i], client->saberTrail.oldNormal[i], - // 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, 1.1f, qfalse ); +// CG_ImpactMark( cgs.media.rivetMarkShader, client->saberTrail.oldPos[i], client->saberTrail.oldNormal[i], +// 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, 1.1f, qfalse ); } // we aren't impacting, so turn off our mark tracking mechanism @@ -4316,13 +3955,9 @@ int CG_IsMindTricked(int trickIndex1, int trickIndex2, int trickIndex3, int tric #define SPEED_TRAIL_DISTANCE 6 -void CG_DrawYsalimariSphere(centity_t *cent, vec3_t origin, vec3_t colors) +void CG_DrawPlayerSphere(centity_t *cent, vec3_t origin, float scale, int shader) { refEntity_t ent; - int alpha; - float scale; - vec3_t sphereAngles; - float addSum = 0; // Don't draw the shield when the player is dead. if (cent->currentState.eFlags & EF_DEAD) @@ -4333,191 +3968,23 @@ void CG_DrawYsalimariSphere(centity_t *cent, vec3_t origin, vec3_t colors) memset( &ent, 0, sizeof( ent ) ); VectorCopy( origin, ent.origin ); - ent.origin[2] -= 32.0; + ent.origin[2] += 9.0; - VectorCopy(cent->lerpAngles, sphereAngles); - sphereAngles[PITCH] = 0; - - AnglesToAxis( sphereAngles, ent.axis ); - - alpha = 255.0 * ((100) / 1750.0) + Q_irand(0, 16); - if (alpha>255) - alpha=255; - - //Slowly pulse the scale up and down - - addSum = (((cg.time / 12) & 255) * (M_PI * 2) / 255)/8; - - if (addSum >= 0.4) - { - addSum = (0.4 - (addSum - 0.4)); - } - scale = 0.9; - - addSum *= 0.2; - - scale += addSum; - - VectorScale( ent.axis[0], scale, ent.axis[0] ); - VectorScale( ent.axis[1], scale, ent.axis[1] ); - VectorScale( ent.axis[2], scale, ent.axis[2] ); - - ent.hModel = trap_R_RegisterModel ( "models/map_objects/mp/sphere.md3" );//cgs.media.explosionModel; - ent.customShader = trap_R_RegisterShader( "powerups/ysalimarishell" );//cgs.media.halfShieldShader; - ent.renderfx = (RF_RGB_TINT|RF_FORCE_ENT_ALPHA); - if (colors[0] != -1) - { - ent.shaderRGBA[0] = colors[0]; - } - else - { - ent.shaderRGBA[0] = alpha; - } - - if (colors[1] != -1) - { - ent.shaderRGBA[1] = colors[1]; - } - else - { - ent.shaderRGBA[1] = alpha; - } - - if (colors[2] != -1) - { - ent.shaderRGBA[2] = colors[2]; - } - else - { - ent.shaderRGBA[2] = alpha; - } - - ent.shaderRGBA[3] = 20;//50; - trap_R_AddRefEntityToScene( &ent ); - - //Add a second inner-core that pulses at a different speed - addSum = (((cg.time / 8) & 255) * (M_PI * 2) / 255)/8; - - if (addSum >= 0.4) - { - addSum = (0.4 - (addSum - 0.4)); - } - scale = 0.9; - - addSum *= 0.2; - - scale += addSum; - - VectorScale( ent.axis[0], scale, ent.axis[0] ); - VectorScale( ent.axis[1], scale, ent.axis[1] ); - VectorScale( ent.axis[2], scale, ent.axis[2] ); - - ent.shaderRGBA[3] = 20; - trap_R_AddRefEntityToScene( &ent ); -} - -void CG_DrawCustomSphere(centity_t *cent, vec3_t origin, vec3_t colors, float xScale, float yScale, float zScale, float timeScale, int custShader, int forceAlpha) -{ - refEntity_t ent; - int alpha; - vec3_t sphereAngles; - float addSum = 0; - - // Don't draw the shield when the player is dead. - if (cent->currentState.eFlags & EF_DEAD) - { + VectorSubtract(cg.refdef.vieworg, ent.origin, ent.axis[0]); + if (VectorNormalize(ent.axis[0]) <= 0.1f) + { // Entity is right on vieworg. quit. return; } - memset( &ent, 0, sizeof( ent ) ); + VectorCopy(cg.refdef.viewaxis[2], ent.axis[2]); + CrossProduct(ent.axis[0], ent.axis[2], ent.axis[1]); - VectorCopy( origin, ent.origin ); - ent.origin[2] -= 32.0; + VectorScale(ent.axis[0], scale, ent.axis[0]); + VectorScale(ent.axis[1], scale, ent.axis[1]); + VectorScale(ent.axis[2], -scale, ent.axis[2]); - VectorCopy(cent->lerpAngles, sphereAngles); - sphereAngles[PITCH] = 0; - - addSum = (((cg.time / 4) & 255) * (M_PI * 2) / 255)/6; - addSum *= 350; - sphereAngles[YAW] = addSum; - - AnglesToAxis( sphereAngles, ent.axis ); - - alpha = 255.0 * ((100) / 1750.0) + Q_irand(0, 16); - if (alpha>255) - alpha=255; - - //Slowly pulse the scale up and down - if (!timeScale) - { - addSum = 0; - } - else - { - addSum = (((cg.time / (int)timeScale) & 255) * (M_PI * 2) / 255)/8; - - if (addSum >= 0.4) - { - addSum = (0.4 - (addSum - 0.4)); - } - - addSum *= 0.2; - } - - xScale += addSum; - yScale += addSum; - zScale += addSum; - - VectorScale( ent.axis[0], xScale, ent.axis[0] ); - VectorScale( ent.axis[1], yScale, ent.axis[1] ); - VectorScale( ent.axis[2], zScale, ent.axis[2] ); - - ent.hModel = trap_R_RegisterModel ( "models/map_objects/mp/sphere.md3" );//cgs.media.explosionModel; - - if (custShader) - { - ent.customShader = custShader; - } - else - { - ent.customShader = trap_R_RegisterShader( "powerups/ysalimarishell" );//cgs.media.halfShieldShader; - } - ent.renderfx = (RF_RGB_TINT|RF_FORCE_ENT_ALPHA); - if (colors[0] != -1) - { - ent.shaderRGBA[0] = colors[0]; - } - else - { - ent.shaderRGBA[0] = alpha; - } - - if (colors[1] != -1) - { - ent.shaderRGBA[1] = colors[1]; - } - else - { - ent.shaderRGBA[1] = alpha; - } - - if (colors[2] != -1) - { - ent.shaderRGBA[2] = colors[2]; - } - else - { - ent.shaderRGBA[2] = alpha; - } - - if (forceAlpha) - { - ent.shaderRGBA[3] = forceAlpha; - } - else - { - ent.shaderRGBA[3] = 255; - } + ent.hModel = cgs.media.halfShieldModel; + ent.customShader = shader; trap_R_AddRefEntityToScene( &ent ); } @@ -4638,6 +4105,26 @@ void CG_AddRandomLightning(vec3_t start, vec3_t end) extern char *forceHolocronModels[]; +qboolean CG_ThereIsAMaster(void) +{ + int i = 0; + centity_t *cent; + + while (i < MAX_CLIENTS) + { + cent = &cg_entities[i]; + + if (cent && cent->currentState.isJediMaster) + { + return qtrue; + } + + i++; + } + + return qfalse; +} + /* =============== CG_Player @@ -4647,7 +4134,6 @@ void CG_Player( centity_t *cent ) { clientInfo_t *ci; refEntity_t legs; refEntity_t torso; - refEntity_t head; int clientNum; int renderfx; qboolean shadow = qfalse; @@ -4668,6 +4154,7 @@ void CG_Player( centity_t *cent ) { int doAlpha = 0; int effectTimeLayer = 0; qboolean gotLHandMatrix = qfalse; + qboolean g2HasWeapon = qfalse; if (cgQueueLoad) { @@ -4694,9 +4181,28 @@ void CG_Player( centity_t *cent ) { if (!cent->ghoul2) { //not ready yet? +#ifdef _DEBUG + Com_Printf("WARNING: Client %i has a null ghoul2 instance\n", cent->currentState.number); +#endif + if (cgs.clientinfo[cent->currentState.number].ghoul2Model && + trap_G2_HaveWeGhoul2Models(cgs.clientinfo[cent->currentState.number].ghoul2Model)) + { +#ifdef _DEBUG + Com_Printf("Clientinfo instance was valid, duplicating for cent\n"); +#endif + trap_G2API_DuplicateGhoul2Instance(cgs.clientinfo[cent->currentState.number].ghoul2Model, ¢->ghoul2); + cg_entities[cent->currentState.number].ghoul2 = cent->ghoul2; + } return; } + g2HasWeapon = trap_G2API_HasGhoul2ModelOnIndex(&(cent->ghoul2), 1); + + if (!g2HasWeapon) + { //force a redup of the weapon instance onto the client instance + cent->ghoul2weapon = NULL; + } + if (cent->torsoBolt && !(cent->currentState.eFlags & EF_DEAD)) { //he's alive and has a limb missing still, reattach it and reset the weapon CG_ReattachLimb(cent); @@ -4708,7 +4214,7 @@ void CG_Player( centity_t *cent ) { cg_entities[cent->currentState.number].isATST = cent->isATST; if (CG_RegisterClientModelname(&cgs.clientinfo[cent->currentState.number], cgs.clientinfo[cent->currentState.number].modelName, cgs.clientinfo[cent->currentState.number].skinName, - cgs.clientinfo[cent->currentState.number].headModelName, cgs.clientinfo[cent->currentState.number].headSkinName, cgs.clientinfo[cent->currentState.number].teamName, cent->currentState.number)) + cgs.clientinfo[cent->currentState.number].teamName, cent->currentState.number)) { cent->isATST = 1; cg_entities[cent->currentState.number].isATST = cent->isATST; @@ -4721,7 +4227,7 @@ void CG_Player( centity_t *cent ) { cg_entities[cent->currentState.number].isATST = cent->isATST; if (CG_RegisterClientModelname(&cgs.clientinfo[cent->currentState.number], cgs.clientinfo[cent->currentState.number].modelName, cgs.clientinfo[cent->currentState.number].skinName, - cgs.clientinfo[cent->currentState.number].headModelName, cgs.clientinfo[cent->currentState.number].headSkinName, cgs.clientinfo[cent->currentState.number].teamName, cent->currentState.number)) + cgs.clientinfo[cent->currentState.number].teamName, cent->currentState.number)) { cent->isATST = 0; cg_entities[cent->currentState.number].isATST = cent->isATST; @@ -4881,6 +4387,25 @@ void CG_Player( centity_t *cent ) { } } + if (cgs.gametype == GT_JEDIMASTER && cg_drawFriend.integer && + cent->currentState.number != cg.snap->ps.clientNum) // Don't show a sprite above a player's own head in 3rd person. + { // If the view is either a spectator or on the same team as this character, show a symbol above their head. + if ((cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR || cg.snap->ps.persistant[PERS_TEAM] == team) && + !(cent->currentState.eFlags & EF_DEAD)) + { + if (CG_ThereIsAMaster()) + { + if (!cg.snap->ps.isJediMaster) + { + if (!cent->currentState.isJediMaster) + { + CG_PlayerFloatSprite( cent, cgs.media.teamRedShader); + } + } + } + } + } + if (cent->isATST) { goto doEssentialOne; @@ -4999,7 +4524,6 @@ doEssentialOne: ScaleModelAxis(&legs); memset( &torso, 0, sizeof(torso) ); - memset( &head, 0, sizeof(head) ); if (cent->isATST) { @@ -5013,6 +4537,15 @@ doEssentialOne: cent->frame_minus2_refreshed = 0; } + if (cent->frame_minus1.ghoul2 != cent->ghoul2) + { + cent->frame_minus1_refreshed = 0; + } + if (cent->frame_minus2.ghoul2 != cent->ghoul2) + { + cent->frame_minus2_refreshed = 0; + } + VectorCopy(cent->currentState.pos.trDelta, tDir); distVelBase = SPEED_TRAIL_DISTANCE*(VectorNormalize(tDir)*0.004); @@ -5077,11 +4610,9 @@ doEssentialTwo: goto doEssentialThree; } - //rww - in low framerate situations we may only play the effect once every large duration and depending - //on the effect this could make it barely visible. So we'll play the effect multiple times per frame - //judging by the amount of time that's passed since the last frame, thus maintaining the same rate in - //high framerate situations and compensating by layering the effect multiple times in a single frame in - //low framerate situations + //rww - render effects multiple times to compensate for low framerate? This won't do much because + //the effect still gets rendered in this frame and expires, possibly before the next frame. So + //it is disabled for now (setting effectTimeLayer to 0 after one play) if (cent->trailTime < cg.time) { cent->trailTime = cg.time; @@ -5097,63 +4628,6 @@ doEssentialTwo: cent->trailTime = cg.time + 300; - //If you've tricked this client. - if (CG_IsMindTricked(cg.snap->ps.fd.forceMindtrickTargetIndex, - cg.snap->ps.fd.forceMindtrickTargetIndex2, - cg.snap->ps.fd.forceMindtrickTargetIndex3, - cg.snap->ps.fd.forceMindtrickTargetIndex4, - cent->currentState.number)) - { - if (cent->ghoul2) - { - vec3_t efOrg; - vec3_t tAng, fxAng; - vec3_t axis[3]; - int effectTimeLayerC = effectTimeLayer; - sharedBoltInterface_t fxObj; - - //VectorSet( tAng, 0, cent->pe.torso.yawAngle, 0 ); - VectorSet( tAng, cent->turAngles[PITCH], cent->turAngles[YAW], cent->turAngles[ROLL] ); - - trap_G2API_GetBoltMatrix(cent->ghoul2, 0, cgs.clientinfo[cent->currentState.number].bolt_head, &boltMatrix, tAng, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale); - - trap_G2API_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, efOrg); - trap_G2API_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_Y, fxAng); - - axis[0][0] = boltMatrix.matrix[0][0]; - axis[0][1] = boltMatrix.matrix[1][0]; - axis[0][2] = boltMatrix.matrix[2][0]; - - axis[1][0] = boltMatrix.matrix[0][1]; - axis[1][1] = boltMatrix.matrix[1][1]; - axis[1][2] = boltMatrix.matrix[2][1]; - - axis[2][0] = boltMatrix.matrix[0][2]; - axis[2][1] = boltMatrix.matrix[1][2]; - axis[2][2] = boltMatrix.matrix[2][2]; - - VectorCopy(/*efOrg*/cent->lerpOrigin, fxObj.origin); - VectorCopy(/*fxAng*/tAng, fxObj.angles); - VectorCopy(cent->modelScale, fxObj.scale); - fxObj.ghoul2 = cent->ghoul2; - fxObj.isValid = 1; - fxObj.modelNum = 0; - fxObj.boltNum = cgs.clientinfo[cent->currentState.number].bolt_head; - fxObj.entNum = cent->currentState.number; - - while (effectTimeLayerC > 0) - { - trap_FX_PlayEntityEffectID(trap_FX_RegisterEffect("force/confusion.efx"), efOrg, axis, cent->boltInfo, cent->currentState.number); - - //FIXME: Due to the horrible inefficiency involved in the current effect bolt process an effect with as many particles as this won't - //work too happily. It also doesn't look a lot better due to the lag between origin updates with the effect bolt. If those issues - //are ever resolved it should be switched over to BoltedEffect. - //trap_FX_PlayBoltedEffectID(trap_FX_RegisterEffect("force/confusion.efx"), &fxObj); - effectTimeLayerC -= 50; - } - } - } - if (cent->currentState.activeForcePass > FORCE_LEVEL_3) { int effectTimeLayerL = effectTimeLayer; @@ -5194,7 +4668,7 @@ doEssentialTwo: trap_FX_PlayEntityEffectID(cgs.effects.forceDrain, efOrg, axis, cent->boltInfo, cent->currentState.number); } - effectTimeLayerL -= 50; + effectTimeLayerL = 0;//-= 50; } /* @@ -5243,7 +4717,7 @@ doEssentialTwo: trap_FX_PlayEntityEffectID(cgs.effects.forceLightning, efOrg, axis, cent->boltInfo, cent->currentState.number); } - effectTimeLayerL -= 50; + effectTimeLayerL = 0;//-= 50; } /* @@ -5312,6 +4786,8 @@ doEssentialTwo: efOrg[1] -= boltDir[1]*4; efOrg[2] -= boltDir[2]*4; + efOrg[2] += 8; + VectorCopy(efOrg, cent->grip_arm.origin); VectorCopy(cent->grip_arm.origin, cent->grip_arm.lightingOrigin); @@ -5355,9 +4831,10 @@ doEssentialTwo: } } - if (cent->currentState.weapon == WP_STUN_BATON && (cent->currentState.eFlags & EF_FIRING)) - { //note: This is a stupid placeholder so that it's at least the same as SP - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, trap_S_RegisterSound("sound/weapons/saber/saberhum1") ); + if (cent->currentState.weapon == WP_STUN_BATON && cent->currentState.number == cg.snap->ps.clientNum) + { + trap_S_AddLoopingSound( cent->currentState.number, cg.refdef.vieworg, vec3_origin, + trap_S_RegisterSound( "sound/weapons/baton/idle.wav" ) ); } //NOTE: All effects that should be visible during mindtrick should go above here @@ -5378,6 +4855,110 @@ doEssentialTwo: } } + if (cent->teamPowerEffectTime > cg.time) + { + vec4_t preCol; + int preRFX; + + preRFX = legs.renderfx; + + legs.renderfx |= RF_RGB_TINT; + legs.renderfx |= RF_FORCE_ENT_ALPHA; + + preCol[0] = legs.shaderRGBA[0]; + preCol[1] = legs.shaderRGBA[1]; + preCol[2] = legs.shaderRGBA[2]; + preCol[3] = legs.shaderRGBA[3]; + + if (cent->teamPowerType == 1) + { //heal + legs.shaderRGBA[0] = 0; + legs.shaderRGBA[1] = 255; + legs.shaderRGBA[2] = 0; + } + else if (cent->teamPowerType == 0) + { //regen + legs.shaderRGBA[0] = 0; + legs.shaderRGBA[1] = 0; + legs.shaderRGBA[2] = 255; + } + else + { //drain + legs.shaderRGBA[0] = 255; + legs.shaderRGBA[1] = 0; + legs.shaderRGBA[2] = 0; + } + + legs.shaderRGBA[3] = ((cent->teamPowerEffectTime - cg.time)/8); + + legs.customShader = trap_R_RegisterShader( "powerups/ysalimarishell" ); + trap_R_AddRefEntityToScene(&legs); + + legs.customShader = 0; + legs.renderfx = preRFX; + legs.shaderRGBA[0] = preCol[0]; + legs.shaderRGBA[1] = preCol[1]; + legs.shaderRGBA[2] = preCol[2]; + legs.shaderRGBA[3] = preCol[3]; + } + + //If you've tricked this client. + if (CG_IsMindTricked(cg.snap->ps.fd.forceMindtrickTargetIndex, + cg.snap->ps.fd.forceMindtrickTargetIndex2, + cg.snap->ps.fd.forceMindtrickTargetIndex3, + cg.snap->ps.fd.forceMindtrickTargetIndex4, + cent->currentState.number)) + { + if (cent->ghoul2) + { + vec3_t efOrg; + vec3_t tAng, fxAng; + vec3_t axis[3]; + int effectTimeLayerC = effectTimeLayer; + sharedBoltInterface_t fxObj; + + //VectorSet( tAng, 0, cent->pe.torso.yawAngle, 0 ); + VectorSet( tAng, cent->turAngles[PITCH], cent->turAngles[YAW], cent->turAngles[ROLL] ); + + trap_G2API_GetBoltMatrix(cent->ghoul2, 0, cgs.clientinfo[cent->currentState.number].bolt_head, &boltMatrix, tAng, cent->lerpOrigin, cg.time, cgs.gameModels, cent->modelScale); + + trap_G2API_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, efOrg); + trap_G2API_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_Y, fxAng); + + axis[0][0] = boltMatrix.matrix[0][0]; + axis[0][1] = boltMatrix.matrix[1][0]; + axis[0][2] = boltMatrix.matrix[2][0]; + + axis[1][0] = boltMatrix.matrix[0][1]; + axis[1][1] = boltMatrix.matrix[1][1]; + axis[1][2] = boltMatrix.matrix[2][1]; + + axis[2][0] = boltMatrix.matrix[0][2]; + axis[2][1] = boltMatrix.matrix[1][2]; + axis[2][2] = boltMatrix.matrix[2][2]; + + VectorCopy(/*efOrg*/cent->lerpOrigin, fxObj.origin); + VectorCopy(/*fxAng*/tAng, fxObj.angles); + VectorCopy(cent->modelScale, fxObj.scale); + fxObj.ghoul2 = cent->ghoul2; + fxObj.isValid = 1; + fxObj.modelNum = 0; + fxObj.boltNum = cgs.clientinfo[cent->currentState.number].bolt_head; + fxObj.entNum = cent->currentState.number; + + while (effectTimeLayerC > 0) + { + trap_FX_PlayEntityEffectID(trap_FX_RegisterEffect("force/confusion.efx"), efOrg, axis, cent->boltInfo, cent->currentState.number); + + //FIXME: Due to the horrible inefficiency involved in the current effect bolt process an effect with as many particles as this won't + //work too happily. It also doesn't look a lot better due to the lag between origin updates with the effect bolt. If those issues + //are ever resolved it should be switched over to BoltedEffect. + //trap_FX_PlayBoltedEffectID(trap_FX_RegisterEffect("force/confusion.efx"), &fxObj); + effectTimeLayerC = 0;//-= 50; + } + } + } + if (cgs.gametype == GT_HOLOCRON && cent->currentState.time2 && (cg.renderingThirdPerson || cg.snap->ps.clientNum != cent->currentState.number)) { int i = 0; @@ -5524,70 +5105,45 @@ doEssentialTwo: } } - if ( (cent->currentState.powerups & (1 << PW_YSALIMARI)) || + if ((cent->currentState.powerups & (1 << PW_YSALAMIRI)) || (cgs.gametype == GT_CTY && ((cent->currentState.powerups & (1 << PW_REDFLAG)) || (cent->currentState.powerups & (1 << PW_BLUEFLAG)))) ) { - vec3_t efColors; - if (cgs.gametype == GT_CTY && (cent->currentState.powerups & (1 << PW_REDFLAG))) { - efColors[0] = 255; - efColors[1] = 50; - efColors[2] = -1; + CG_DrawPlayerSphere(cent, cent->lerpOrigin, 1.4, cgs.media.ysaliredShader ); } else if (cgs.gametype == GT_CTY && (cent->currentState.powerups & (1 << PW_BLUEFLAG))) { - efColors[0] = 50; - efColors[1] = 50; - efColors[2] = 255; + CG_DrawPlayerSphere(cent, cent->lerpOrigin, 1.4, cgs.media.ysaliblueShader ); } else { - efColors[0] = 255; - efColors[1] = 255; - efColors[2] = -1; + CG_DrawPlayerSphere(cent, cent->lerpOrigin, 1.4, cgs.media.ysalimariShader ); } - CG_DrawYsalimariSphere(cent, cent->lerpOrigin, efColors); } if (cent->currentState.powerups & (1 << PW_FORCE_BOON)) { - vec3_t efColors; - efColors[0] = -1; - efColors[1] = -1; - efColors[2] = 255; - CG_DrawYsalimariSphere(cent, cent->lerpOrigin, efColors); + CG_DrawPlayerSphere(cent, cent->lerpOrigin, 2.0, cgs.media.boonShader ); } if (cent->currentState.powerups & (1 << PW_FORCE_ENLIGHTENED_DARK)) { - vec3_t efColors; - efColors[0] = 255; - efColors[1] = -1; - efColors[2] = -1; - CG_DrawYsalimariSphere(cent, cent->lerpOrigin, efColors); + CG_DrawPlayerSphere(cent, cent->lerpOrigin, 2.0, cgs.media.endarkenmentShader ); } else if (cent->currentState.powerups & (1 << PW_FORCE_ENLIGHTENED_LIGHT)) { - vec3_t efColors; - efColors[0] = 255; - efColors[1] = 255; - efColors[2] = 255; - CG_DrawYsalimariSphere(cent, cent->lerpOrigin, efColors); + CG_DrawPlayerSphere(cent, cent->lerpOrigin, 2.0, cgs.media.enlightenmentShader ); } if (cent->currentState.eFlags & EF_INVULNERABLE) { - vec3_t efColors; - efColors[0] = 0; - efColors[1] = 255; - efColors[2] = 0; - CG_DrawYsalimariSphere(cent, cent->lerpOrigin, efColors); + CG_DrawPlayerSphere(cent, cent->lerpOrigin, 1.4, cgs.media.invulnerabilityShader ); } stillDoSaber: if (cent->currentState.weapon == WP_SABER && !cent->currentState.shouldtarget) { - if (!cent->currentState.saberInFlight) + if (!cent->currentState.saberInFlight && !(cent->currentState.eFlags & EF_DEAD)) { if (cg.snap->ps.clientNum == cent->currentState.number) { @@ -5605,9 +5161,10 @@ stillDoSaber: { if (cent->currentState.eFlags & EF_DEAD) { - if (cent->ghoul2 && cent->currentState.saberInFlight && trap_G2API_HasGhoul2ModelOnIndex(&(cent->ghoul2), 1)) + if (cent->ghoul2 && cent->currentState.saberInFlight && g2HasWeapon) { //special case, kill the saber on a freshly dead player if another source says to. trap_G2API_RemoveGhoul2Model(&(cent->ghoul2), 1); + g2HasWeapon = qfalse; } } //return; @@ -5620,9 +5177,10 @@ stillDoSaber: saberEnt = &cg_entities[cent->currentState.saberEntityNum]; - if (/*!cent->bolt4 &&*/ trap_G2API_HasGhoul2ModelOnIndex(&(cent->ghoul2), 1)) + if (/*!cent->bolt4 &&*/ g2HasWeapon) { //saber is in flight, do not have it as a standard weapon model trap_G2API_RemoveGhoul2Model(&(cent->ghoul2), 1); + g2HasWeapon = qfalse; //cent->bolt4 = 1; @@ -5730,7 +5288,7 @@ stillDoSaber: saberEnt->currentState.modelGhoul2 = 1; CG_ManualEntityRender(saberEnt); saberEnt->bolt3 = 0; - saberEnt->currentState.modelGhoul2 = 999; + saberEnt->currentState.modelGhoul2 = 127; VectorCopy(saberEnt->lerpAngles, bladeAngles); bladeAngles[ROLL] = 0; @@ -5775,7 +5333,7 @@ stillDoSaber: saberEnt = &cg_entities[cent->currentState.saberEntityNum]; - if (/*cent->bolt4 && */!trap_G2API_HasGhoul2ModelOnIndex(&(cent->ghoul2), 1)) + if (/*cent->bolt4 && */!g2HasWeapon) { trap_G2API_CopySpecificGhoul2Model(g2WeaponInstances[WP_SABER], 0, cent->ghoul2, 1); @@ -5802,9 +5360,10 @@ stillDoSaber: if (cent->currentState.eFlags & EF_DEAD) { - if (cent->ghoul2 && cent->currentState.saberInFlight && trap_G2API_HasGhoul2ModelOnIndex(&(cent->ghoul2), 1)) + if (cent->ghoul2 && cent->currentState.saberInFlight && g2HasWeapon) { //special case, kill the saber on a freshly dead player if another source says to. trap_G2API_RemoveGhoul2Model(&(cent->ghoul2), 1); + g2HasWeapon = qfalse; } } @@ -5856,15 +5415,15 @@ stillDoSaber: subLen = 1020; } - legs.shaderRGBA[0] = 0; - legs.shaderRGBA[1] = 0; + legs.shaderRGBA[0] = 255 - subLen/4; + legs.shaderRGBA[1] = 255 - subLen/4; legs.shaderRGBA[2] = 255 - subLen/4; if (legs.shaderRGBA[2] < 1) legs.shaderRGBA[2] = 1; legs.renderfx &= ~RF_RGB_TINT; legs.renderfx &= ~RF_FORCE_ENT_ALPHA; - legs.customShader = cgs.media.forceSightBubble; + legs.customShader = cgs.media.forceShell; trap_R_AddRefEntityToScene( &legs ); @@ -5872,7 +5431,7 @@ stillDoSaber: legs.shaderRGBA[0] = 255 - subLen/8; legs.shaderRGBA[1] = 255 - subLen/8; - legs.shaderRGBA[2] = subLen/8; + legs.shaderRGBA[2] = 255 - subLen/8; if (legs.shaderRGBA[2] < 1) { @@ -6059,16 +5618,45 @@ doEssentialThree: trap_R_AddRefEntityToScene( &legs ); } + //For now, these two are using the old shield shader. This is just so that you + //can tell it apart from the JM/duel shaders, but it's still very obvious. + if (cent->currentState.forcePowersActive & (1 << FP_PROTECT)) + { //aborb is represented by green.. + legs.shaderRGBA[0] = 0; + legs.shaderRGBA[1] = 255; + legs.shaderRGBA[2] = 0; + legs.shaderRGBA[3] = 254; + + legs.renderfx &= ~RF_RGB_TINT; + legs.renderfx &= ~RF_FORCE_ENT_ALPHA; + legs.customShader = cgs.media.playerShieldDamage; + + trap_R_AddRefEntityToScene( &legs ); + } + if (cent->currentState.forcePowersActive & (1 << FP_ABSORB)) + { //aborb is represented by blue.. + legs.shaderRGBA[0] = 0; + legs.shaderRGBA[1] = 0; + legs.shaderRGBA[2] = 255; + legs.shaderRGBA[3] = 254; + + legs.renderfx &= ~RF_RGB_TINT; + legs.renderfx &= ~RF_FORCE_ENT_ALPHA; + legs.customShader = cgs.media.playerShieldDamage; + + trap_R_AddRefEntityToScene( &legs ); + } + if (cent->currentState.isJediMaster && cg.snap->ps.clientNum != cent->currentState.number) { - legs.shaderRGBA[0] = 50; - legs.shaderRGBA[1] = 50; + legs.shaderRGBA[0] = 100; + legs.shaderRGBA[1] = 100; legs.shaderRGBA[2] = 255; legs.renderfx &= ~RF_RGB_TINT; legs.renderfx &= ~RF_FORCE_ENT_ALPHA; legs.renderfx |= RF_NODEPTH; - legs.customShader = cgs.media.forceSightBubble; + legs.customShader = cgs.media.forceShell; trap_R_AddRefEntityToScene( &legs ); @@ -6122,7 +5710,7 @@ doEssentialThree: legs.renderfx &= ~RF_RGB_TINT; legs.renderfx &= ~RF_FORCE_ENT_ALPHA; - legs.customShader = cgs.media.forceSightBubble; + legs.customShader = cgs.media.sightShell; trap_R_AddRefEntityToScene( &legs ); } diff --git a/CODE-mp/cgame/cg_playerstate.c b/CODE-mp/cgame/cg_playerstate.c index 8dddf5f..766a89b 100644 --- a/CODE-mp/cgame/cg_playerstate.c +++ b/CODE-mp/cgame/cg_playerstate.c @@ -274,6 +274,7 @@ void CG_CheckChangedPredictableEvents( playerState_t *ps ) { pushReward ================== */ +#ifdef JK2AWARDS static void pushReward(sfxHandle_t sfx, qhandle_t shader, int rewardCount) { if (cg.rewardStack < (MAX_REWARDSTACK-1)) { cg.rewardStack++; @@ -282,6 +283,7 @@ static void pushReward(sfxHandle_t sfx, qhandle_t shader, int rewardCount) { cg.rewardCount[cg.rewardStack] = rewardCount; } } +#endif int cgAnnouncerTime = 0; //to prevent announce sounds from playing on top of each other @@ -406,8 +408,13 @@ void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) { } else if ( ps->persistant[PERS_RANK] == RANK_TIED_FLAG ) { //CG_AddBufferedSound(cgs.media.tiedLeadSound); } else if ( ( ops->persistant[PERS_RANK] & ~RANK_TIED_FLAG ) == 0 ) { - CG_AddBufferedSound(cgs.media.lostLeadSound); - cgAnnouncerTime = cg.time + 3000; + //rww - only bother saying this if you have more than 1 kill already. + //joining the server and hearing "the force is not with you" is silly. + if (ps->persistant[PERS_SCORE] > 0) + { + CG_AddBufferedSound(cgs.media.lostLeadSound); + cgAnnouncerTime = cg.time + 3000; + } } } } diff --git a/CODE-mp/cgame/cg_scoreboard.c b/CODE-mp/cgame/cg_scoreboard.c index fee3b2d..74d2204 100644 --- a/CODE-mp/cgame/cg_scoreboard.c +++ b/CODE-mp/cgame/cg_scoreboard.c @@ -2,7 +2,7 @@ // // cg_scoreboard -- draw the scoreboard on top of the game screen #include "cg_local.h" - +#include "../ui/ui_shared.h" #define SCOREBOARD_X (0) @@ -12,8 +12,8 @@ // Where the status bar starts, so we don't overwrite it #define SB_STATUSBAR 420 -#define SB_NORMAL_HEIGHT 40 -#define SB_INTER_HEIGHT 16 // interleaved height +#define SB_NORMAL_HEIGHT 25 +#define SB_INTER_HEIGHT 15 // interleaved height #define SB_MAXCLIENTS_NORMAL ((SB_STATUSBAR - SB_TOP) / SB_NORMAL_HEIGHT) #define SB_MAXCLIENTS_INTER ((SB_STATUSBAR - SB_TOP) / SB_INTER_HEIGHT - 1) @@ -30,14 +30,14 @@ #define SB_BOTICON_X (SCOREBOARD_X+32) #define SB_HEAD_X (SCOREBOARD_X+64) -#define SB_SCORELINE_X 64 +#define SB_SCORELINE_X 100 +#define SB_SCORELINE_WIDTH (640 - SB_SCORELINE_X * 2) -#define SB_RATING_WIDTH (6 * BIGCHAR_WIDTH) // width 6 -#define SB_SCORE_X (SB_SCORELINE_X + BIGCHAR_WIDTH) // width 6 -#define SB_RATING_X (SB_SCORELINE_X + 6 * BIGCHAR_WIDTH) // width 6 -#define SB_PING_X (SB_SCORELINE_X + 12 * BIGCHAR_WIDTH + 8) // width 5 -#define SB_TIME_X (SB_SCORELINE_X + 17 * BIGCHAR_WIDTH + 8) // width 5 -#define SB_NAME_X (SB_SCORELINE_X + 22 * BIGCHAR_WIDTH) // width 15 +#define SB_RATING_WIDTH 0 // (6 * BIGCHAR_WIDTH) +#define SB_NAME_X (SB_SCORELINE_X) +#define SB_SCORE_X (SB_SCORELINE_X + .55 * SB_SCORELINE_WIDTH) +#define SB_PING_X (SB_SCORELINE_X + .70 * SB_SCORELINE_WIDTH) +#define SB_TIME_X (SB_SCORELINE_X + .85 * SB_SCORELINE_WIDTH) // The new and improved score board // @@ -58,11 +58,21 @@ static qboolean localClient; // true if local client has been displayed CG_DrawScoreboard ================= */ -static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) { - char string[1024]; +static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, qboolean largeFormat ) +{ //vec3_t headAngles; clientInfo_t *ci; int iconx, headx; + float scale; + + if ( largeFormat ) + { + scale = 1.0f; + } + else + { + scale = 0.75f; + } if ( score->client < 0 || score->client >= cgs.maxclients ) { Com_Printf( "Bad score->client: %i\n", score->client ); @@ -84,59 +94,32 @@ static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, } } else if ( ci->powerups & ( 1 << PW_REDFLAG ) ) { if( largeFormat ) { - CG_DrawFlagModel( iconx, y*1.63, 32, 32, TEAM_RED, qfalse ); + CG_DrawFlagModel( iconx*cgs.screenXScale, y*cgs.screenYScale, 32*cgs.screenXScale, 32*cgs.screenYScale, TEAM_RED, qfalse ); } else { - CG_DrawFlagModel( iconx, y*1.63, 32, 32, TEAM_RED, qfalse ); + CG_DrawFlagModel( iconx*cgs.screenXScale, y*cgs.screenYScale, 32*cgs.screenXScale, 32*cgs.screenYScale, TEAM_RED, qfalse ); } } else if ( ci->powerups & ( 1 << PW_BLUEFLAG ) ) { if( largeFormat ) { - CG_DrawFlagModel( iconx, y*1.63, 32, 32, TEAM_BLUE, qfalse ); + CG_DrawFlagModel( iconx*cgs.screenXScale, y*cgs.screenYScale, 32*cgs.screenXScale, 32*cgs.screenYScale, TEAM_BLUE, qfalse ); } else { - CG_DrawFlagModel( iconx, y*1.63, 32, 32, TEAM_BLUE, qfalse ); + CG_DrawFlagModel( iconx*cgs.screenXScale, y*cgs.screenYScale, 32*cgs.screenXScale, 32*cgs.screenYScale, TEAM_BLUE, qfalse ); } } else { + // draw the wins / losses /* - if ( ci->botSkill > 0 && ci->botSkill <= 5 ) { - if ( cg_drawIcons.integer ) { - if( largeFormat ) { - CG_DrawPic( iconx, y - ( 32 - BIGCHAR_HEIGHT ) / 2, 32, 32, cgs.media.botSkillShaders[ ci->botSkill - 1 ] ); - } - else { - CG_DrawPic( iconx, y, 16, 16, cgs.media.botSkillShaders[ ci->botSkill - 1 ] ); - } - } - } else if ( ci->handicap < 100 ) { - Com_sprintf( string, sizeof( string ), "%i", ci->handicap ); - if ( cgs.gametype == GT_TOURNAMENT ) - CG_DrawSmallStringColor( iconx, y - SMALLCHAR_HEIGHT/2, string, color ); - else - CG_DrawSmallStringColor( iconx, y, string, color ); + if ( cgs.gametype == GT_TOURNAMENT ) + { + CG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, va("%i/%i", ci->wins, ci->losses ), color ); } */ - - // draw the wins / losses - if ( cgs.gametype == GT_TOURNAMENT ) { - Com_sprintf( string, sizeof( string ), "%i/%i", ci->wins, ci->losses ); - CG_DrawSmallStringColor( iconx, y + SMALLCHAR_HEIGHT/2, string, color ); - } - } - - // draw the score line - if ( score->ping == -1 ) { - Com_sprintf(string, sizeof(string), - " connecting %s", ci->name); - } else if ( ci->team == TEAM_SPECTATOR ) { - Com_sprintf(string, sizeof(string), - " SPECT %3i %4i %s", score->ping, score->time, ci->name); - } else { - Com_sprintf(string, sizeof(string), - "%5i %4i %4i %s", score->score, score->ping, score->time, ci->name); + //rww - in duel, we now show wins/losses in place of "frags". This is because duel now defaults to 1 kill per round. } // highlight your position - if ( score->client == cg.snap->ps.clientNum ) { + if ( score->client == cg.snap->ps.clientNum ) + { float hcolor[4]; int rank; @@ -167,22 +150,30 @@ static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, } hcolor[3] = fade * 0.7; - CG_FillRect( SB_SCORELINE_X + BIGCHAR_WIDTH + (SB_RATING_WIDTH / 2), y, - 640 - SB_SCORELINE_X - BIGCHAR_WIDTH, BIGCHAR_HEIGHT+12, hcolor ); + CG_FillRect( SB_SCORELINE_X - 5, y + 2, 640 - SB_SCORELINE_X * 2 + 10, largeFormat?SB_NORMAL_HEIGHT:SB_INTER_HEIGHT, hcolor ); } -// CG_DrawBigString( SB_SCORELINE_X + (SB_RATING_WIDTH / 2), y, string, fade ); + CG_Text_Paint (SB_NAME_X, y, 0.9f * scale, colorWhite, ci->name,0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); - //UI_DrawProportionalString(SB_SCORELINE_X + (SB_RATING_WIDTH/2), y, string, UI_DROPSHADOW, colorTable[CT_WHITE]); - UI_DrawProportionalString(SB_SCORE_X + (SB_RATING_WIDTH / 2), y, va("%i", score->score), UI_SMALLFONT | UI_DROPSHADOW, colorTable[CT_WHITE]); - UI_DrawProportionalString(SB_PING_X - (SB_RATING_WIDTH / 2), y, va("%i", score->ping), UI_SMALLFONT | UI_DROPSHADOW, colorTable[CT_WHITE]); - UI_DrawProportionalString(SB_TIME_X - (SB_RATING_WIDTH / 2), y, va("%i", score->time), UI_SMALLFONT | UI_DROPSHADOW, colorTable[CT_WHITE]); - UI_DrawProportionalString(SB_NAME_X - (SB_RATING_WIDTH / 2), y, ci->name, UI_SMALLFONT | UI_DROPSHADOW, colorTable[CT_WHITE]); + if ( ci->team != TEAM_SPECTATOR || cgs.gametype == GT_TOURNAMENT ) + { + if (cgs.gametype == GT_TOURNAMENT) + { + CG_Text_Paint (SB_SCORE_X, y, 1.0f * scale, colorWhite, va("%i/%i", ci->wins, ci->losses),0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_SMALL ); + } + else + { + CG_Text_Paint (SB_SCORE_X, y, 1.0f * scale, colorWhite, va("%i", score->score),0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_SMALL ); + } + } + CG_Text_Paint (SB_PING_X, y, 1.0f * scale, colorWhite, va("%i", score->ping),0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_SMALL ); + CG_Text_Paint (SB_TIME_X, y, 1.0f * scale, colorWhite, va("%i", score->time),0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_SMALL ); // add the "ready" marker for intermission exiting - if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) { - CG_DrawBigStringColor( iconx-64, y+6, "READY", color ); + if ( cg.snap->ps.stats[ STAT_CLIENTS_READY ] & ( 1 << score->client ) ) + { + CG_Text_Paint (SB_NAME_X - 64, y + 2, 0.7f * scale, colorWhite, CG_GetStripEdString("INGAMETEXT", "READY"),0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); } } @@ -191,7 +182,8 @@ static void CG_DrawClientScore( int y, score_t *score, float *color, float fade, CG_TeamScoreboard ================= */ -static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, int lineHeight ) { +static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, int lineHeight, qboolean countOnly ) +{ int i; score_t *score; float color[4]; @@ -210,7 +202,10 @@ static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, in continue; } - CG_DrawClientScore( y + lineHeight * count, score, color, fade, lineHeight == SB_NORMAL_HEIGHT ); + if ( !countOnly ) + { + CG_DrawClientScore( y + lineHeight * count, score, color, fade, lineHeight == SB_NORMAL_HEIGHT ); + } count++; } @@ -218,6 +213,28 @@ static int CG_TeamScoreboard( int y, team_t team, float fade, int maxClients, in return count; } +int CG_GetTeamCount(team_t team, int maxClients) +{ + int i = 0; + int count = 0; + clientInfo_t *ci; + score_t *score; + + for ( i = 0 ; i < cg.numScores && count < maxClients ; i++ ) + { + score = &cg.scores[i]; + ci = &cgs.clientinfo[ score->client ]; + + if ( team != ci->team ) + { + continue; + } + + count++; + } + + return count; +} /* ================= CG_DrawScoreboard @@ -266,21 +283,64 @@ qboolean CG_DrawOldScoreboard( void ) { fade = *fadeColor; } - // fragged by ... line - if ( cg.killerName[0] ) { - s = va("%s %s", CG_GetStripEdString("INGAMETEXT", "KILLEDBY"), cg.killerName ); - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + // or if in intermission and duel, prints the winner of the duel round + if (cgs.gametype == GT_TOURNAMENT && cgs.duelWinner != -1 && + cg.predictedPlayerState.pm_type == PM_INTERMISSION) + { + s = va("%s %s", cgs.clientinfo[cgs.duelWinner].name, CG_GetStripEdString("INGAMETEXT", "DUEL_WINS") ); + /*w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; x = ( SCREEN_WIDTH - w ) / 2; y = 40; CG_DrawBigString( x, y, s, fade ); + */ + x = ( SCREEN_WIDTH ) / 2; + y = 40; + CG_Text_Paint ( x - CG_Text_Width ( s, 1.0f, FONT_MEDIUM ) / 2, y, 1.0f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); + } + else if (cgs.gametype == GT_TOURNAMENT && cgs.duelist1 != -1 && cgs.duelist2 != -1 && + cg.predictedPlayerState.pm_type == PM_INTERMISSION) + { + s = va("%s %s %s", cgs.clientinfo[cgs.duelist1].name, CG_GetStripEdString("INGAMETEXT", "SPECHUD_VERSUS"), cgs.clientinfo[cgs.duelist2].name ); + /*w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + x = ( SCREEN_WIDTH - w ) / 2; + y = 40; + CG_DrawBigString( x, y, s, fade ); + */ + x = ( SCREEN_WIDTH ) / 2; + y = 40; + CG_Text_Paint ( x - CG_Text_Width ( s, 1.0f, FONT_MEDIUM ) / 2, y, 1.0f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); + } + else if ( cg.killerName[0] ) { + s = va("%s %s", CG_GetStripEdString("INGAMETEXT", "KILLEDBY"), cg.killerName ); + /*w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; + x = ( SCREEN_WIDTH - w ) / 2; + y = 40; + CG_DrawBigString( x, y, s, fade ); + */ + x = ( SCREEN_WIDTH ) / 2; + y = 40; + CG_Text_Paint ( x - CG_Text_Width ( s, 1.0f, FONT_MEDIUM ) / 2, y, 1.0f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); } // current rank if ( cgs.gametype < GT_TEAM) { - if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) { - s = va("%s place with %i", + if (cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR ) + { + char sPlace[256]; + char sOf[256]; + char sWith[256]; + + trap_SP_GetStringTextString("INGAMETEXT_PLACE", sPlace, sizeof(sPlace)); + trap_SP_GetStringTextString("INGAMETEXT_OF", sOf, sizeof(sOf)); + trap_SP_GetStringTextString("INGAMETEXT_WITH", sWith, sizeof(sWith)); + + s = va("%s %s (%s %i) %s %i", CG_PlaceString( cg.snap->ps.persistant[PERS_RANK] + 1 ), + sPlace, + sOf, + cg.numScores, + sWith, cg.snap->ps.persistant[PERS_SCORE] ); w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; x = ( SCREEN_WIDTH ) / 2; @@ -297,26 +357,31 @@ qboolean CG_DrawOldScoreboard( void ) { s = va("Blue leads %i to %i",cg.teamScores[1], cg.teamScores[0] ); } - w = CG_DrawStrlen( s ) * BIGCHAR_WIDTH; x = ( SCREEN_WIDTH ) / 2; y = 60; - //CG_DrawBigString( x, y, s, fade ); - UI_DrawProportionalString(x, y, s, UI_CENTER|UI_DROPSHADOW, colorTable[CT_WHITE]); + + CG_Text_Paint ( x - CG_Text_Width ( s, 1.0f, FONT_MEDIUM ) / 2, y, 1.0f, colorWhite, s, 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); } // scoreboard y = SB_HEADER; -// CG_DrawPic( SB_SCORE_X + (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardScore ); -// CG_DrawPic( SB_PING_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardPing ); -// CG_DrawPic( SB_TIME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardTime ); -// CG_DrawPic( SB_NAME_X - (SB_RATING_WIDTH / 2), y, 64, 32, cgs.media.scoreboardName ); + CG_DrawPic ( SB_SCORELINE_X - 40, y - 5, SB_SCORELINE_WIDTH + 80, 40, trap_R_RegisterShaderNoMip ( "gfx/menus/menu_buttonback.tga" ) ); - UI_DrawProportionalString(SB_SCORE_X + (SB_RATING_WIDTH / 2), y, "Score", UI_SMALLFONT | UI_DROPSHADOW, colorTable[CT_WHITE]); - UI_DrawProportionalString(SB_PING_X - (SB_RATING_WIDTH / 2), y, "Ping", UI_SMALLFONT | UI_DROPSHADOW, colorTable[CT_WHITE]); - UI_DrawProportionalString(SB_TIME_X - (SB_RATING_WIDTH / 2), y, "Time", UI_SMALLFONT | UI_DROPSHADOW, colorTable[CT_WHITE]); - UI_DrawProportionalString(SB_NAME_X - (SB_RATING_WIDTH / 2), y, "Name", UI_SMALLFONT | UI_DROPSHADOW, colorTable[CT_WHITE]); + CG_Text_Paint ( SB_NAME_X, y, 1.0f, colorWhite, "Name", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); + if (cgs.gametype == GT_TOURNAMENT) + { + char sWL[100]; + trap_SP_GetStringTextString("INGAMETEXT_W_L", sWL, sizeof(sWL)); + CG_Text_Paint ( SB_SCORE_X, y, 1.0f, colorWhite, sWL, 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); + } + else + { + CG_Text_Paint ( SB_SCORE_X, y, 1.0f, colorWhite, "Score", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); + } + CG_Text_Paint ( SB_PING_X, y, 1.0f, colorWhite, "Ping", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); + CG_Text_Paint ( SB_TIME_X, y, 1.0f, colorWhite, "Time", 0, 0, ITEM_TEXTSTYLE_OUTLINED, FONT_MEDIUM ); y = SB_TOP; @@ -329,12 +394,20 @@ qboolean CG_DrawOldScoreboard( void ) { } else { maxClients = SB_MAXCLIENTS_NORMAL; lineHeight = SB_NORMAL_HEIGHT; - topBorderSize = 16; - bottomBorderSize = 16; + topBorderSize = 8; + bottomBorderSize = 8; } localClient = qfalse; + + //I guess this should end up being able to display 19 clients at once. + //In a team game, if there are 9 or more clients on the team not in the lead, + //we only want to show 10 of the clients on the team in the lead, so that we + //have room to display the clients in the lead on the losing team. + + //I guess this can be accomplished simply by printing the first teams score with a maxClients + //value passed in related to how many players are on both teams. if ( cgs.gametype >= GT_TEAM ) { // // teamplay scoreboard @@ -342,34 +415,82 @@ qboolean CG_DrawOldScoreboard( void ) { y += lineHeight/2; if ( cg.teamScores[0] >= cg.teamScores[1] ) { - n1 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight ); - CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED ); + int team1MaxCl = CG_GetTeamCount(TEAM_RED, maxClients); + int team2MaxCl = CG_GetTeamCount(TEAM_BLUE, maxClients); + + if (team1MaxCl > 10 && (team1MaxCl+team2MaxCl) > maxClients) + { + team1MaxCl -= team2MaxCl; + //subtract as many as you have to down to 10, once we get there + //we just set it to 10 + + if (team1MaxCl < 10) + { + team1MaxCl = 10; + } + } + + team2MaxCl = (maxClients-team1MaxCl); //team2 can display however many is left over after team1's display + + n1 = CG_TeamScoreboard( y, TEAM_RED, fade, team1MaxCl, lineHeight, qtrue ); + CG_DrawTeamBackground( SB_SCORELINE_X - 5, y - topBorderSize, 640 - SB_SCORELINE_X * 2 + 10, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED ); + CG_TeamScoreboard( y, TEAM_RED, fade, team1MaxCl, lineHeight, qfalse ); y += (n1 * lineHeight) + BIGCHAR_HEIGHT; - maxClients -= n1; - n2 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight ); - CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE ); + + //maxClients -= n1; + + n2 = CG_TeamScoreboard( y, TEAM_BLUE, fade, team2MaxCl, lineHeight, qtrue ); + CG_DrawTeamBackground( SB_SCORELINE_X - 5, y - topBorderSize, 640 - SB_SCORELINE_X * 2 + 10, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE ); + CG_TeamScoreboard( y, TEAM_BLUE, fade, team2MaxCl, lineHeight, qfalse ); y += (n2 * lineHeight) + BIGCHAR_HEIGHT; - maxClients -= n2; + + //maxClients -= n2; + + maxClients -= (team1MaxCl+team2MaxCl); } else { - n1 = CG_TeamScoreboard( y, TEAM_BLUE, fade, maxClients, lineHeight ); - CG_DrawTeamBackground( 0, y - topBorderSize, 640, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE ); + int team1MaxCl = CG_GetTeamCount(TEAM_BLUE, maxClients); + int team2MaxCl = CG_GetTeamCount(TEAM_RED, maxClients); + + if (team1MaxCl > 10 && (team1MaxCl+team2MaxCl) > maxClients) + { + team1MaxCl -= team2MaxCl; + //subtract as many as you have to down to 10, once we get there + //we just set it to 10 + + if (team1MaxCl < 10) + { + team1MaxCl = 10; + } + } + + team2MaxCl = (maxClients-team1MaxCl); //team2 can display however many is left over after team1's display + + n1 = CG_TeamScoreboard( y, TEAM_BLUE, fade, team1MaxCl, lineHeight, qtrue ); + CG_DrawTeamBackground( SB_SCORELINE_X - 5, y - topBorderSize, 640 - SB_SCORELINE_X * 2 + 10, n1 * lineHeight + bottomBorderSize, 0.33f, TEAM_BLUE ); + CG_TeamScoreboard( y, TEAM_BLUE, fade, team1MaxCl, lineHeight, qfalse ); y += (n1 * lineHeight) + BIGCHAR_HEIGHT; - maxClients -= n1; - n2 = CG_TeamScoreboard( y, TEAM_RED, fade, maxClients, lineHeight ); - CG_DrawTeamBackground( 0, y - topBorderSize, 640, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED ); + + //maxClients -= n1; + + n2 = CG_TeamScoreboard( y, TEAM_RED, fade, team2MaxCl, lineHeight, qtrue ); + CG_DrawTeamBackground( SB_SCORELINE_X - 5, y - topBorderSize, 640 - SB_SCORELINE_X * 2 + 10, n2 * lineHeight + bottomBorderSize, 0.33f, TEAM_RED ); + CG_TeamScoreboard( y, TEAM_RED, fade, team2MaxCl, lineHeight, qfalse ); y += (n2 * lineHeight) + BIGCHAR_HEIGHT; - maxClients -= n2; + + //maxClients -= n2; + + maxClients -= (team1MaxCl+team2MaxCl); } - n1 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight ); + n1 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients, lineHeight, qfalse ); y += (n1 * lineHeight) + BIGCHAR_HEIGHT; } else { // // free for all scoreboard // - n1 = CG_TeamScoreboard( y, TEAM_FREE, fade, maxClients, lineHeight ); + n1 = CG_TeamScoreboard( y, TEAM_FREE, fade, maxClients, lineHeight, qfalse ); y += (n1 * lineHeight) + BIGCHAR_HEIGHT; - n2 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients - n1, lineHeight ); + n2 = CG_TeamScoreboard( y, TEAM_SPECTATOR, fade, maxClients - n1, lineHeight, qfalse ); y += (n2 * lineHeight) + BIGCHAR_HEIGHT; } @@ -383,124 +504,13 @@ qboolean CG_DrawOldScoreboard( void ) { } } -/* // load any models that have been deferred if ( ++cg.deferredPlayerLoading > 10 ) { CG_LoadDeferredPlayers(); } -*/ return qtrue; } //================================================================================ -/* -================ -CG_CenterGiantLine -================ -*/ -static void CG_CenterGiantLine( float y, const char *string ) { - float x; - vec4_t color; - - color[0] = 1; - color[1] = 1; - color[2] = 1; - color[3] = 1; - - x = 0.5 * ( 640 - GIANT_WIDTH * CG_DrawStrlen( string ) ); - - CG_DrawStringExt( x, y, string, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); -} - -/* -================= -CG_DrawTourneyScoreboard - -Draw the oversize scoreboard for tournements -================= -*/ -void CG_DrawOldTourneyScoreboard( void ) { - const char *s; - vec4_t color; - int min, tens, ones; - clientInfo_t *ci; - int y; - int i; - - // request more scores regularly - if ( cg.scoresRequestTime + 2000 < cg.time ) { - cg.scoresRequestTime = cg.time; - trap_SendClientCommand( "score" ); - } - - color[0] = 1; - color[1] = 1; - color[2] = 1; - color[3] = 1; - - // draw the dialog background - color[0] = color[1] = color[2] = 0; - color[3] = 1; - CG_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, color ); - - // print the mesage of the day - s = CG_ConfigString( CS_MOTD ); - if ( !s[0] ) { - s = "Scoreboard"; - } - - // print optional title - CG_CenterGiantLine( 8, s ); - - // print server time - ones = cg.time / 1000; - min = ones / 60; - ones %= 60; - tens = ones / 10; - ones %= 10; - s = va("%i:%i%i", min, tens, ones ); - - CG_CenterGiantLine( 64, s ); - - - // print the two scores - - y = 160; - if ( cgs.gametype >= GT_TEAM ) { - // - // teamplay scoreboard - // - CG_DrawStringExt( 8, y, "Red Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); - s = va("%i", cg.teamScores[0] ); - CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); - - y += 64; - - CG_DrawStringExt( 8, y, "Blue Team", color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); - s = va("%i", cg.teamScores[1] ); - CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); - } else { - // - // free for all scoreboard - // - for ( i = 0 ; i < MAX_CLIENTS ; i++ ) { - ci = &cgs.clientinfo[i]; - if ( !ci->infoValid ) { - continue; - } - if ( ci->team != TEAM_FREE ) { - continue; - } - - CG_DrawStringExt( 8, y, ci->name, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); - s = va("%i", ci->score ); - CG_DrawStringExt( 632 - GIANT_WIDTH * strlen(s), y, s, color, qtrue, qtrue, GIANT_WIDTH, GIANT_HEIGHT, 0 ); - y += 64; - } - } - - -} - diff --git a/CODE-mp/cgame/cg_servercmds.c b/CODE-mp/cgame/cg_servercmds.c index b4e81af..85ef985 100644 --- a/CODE-mp/cgame/cg_servercmds.c +++ b/CODE-mp/cgame/cg_servercmds.c @@ -46,9 +46,17 @@ CG_ParseScores ================= */ static void CG_ParseScores( void ) { - int i, powerups; + int i, powerups, readScores; cg.numScores = atoi( CG_Argv( 1 ) ); + + readScores = cg.numScores; + + if (readScores > MAX_CLIENT_SCORE_SEND) + { + readScores = MAX_CLIENT_SCORE_SEND; + } + if ( cg.numScores > MAX_CLIENTS ) { cg.numScores = MAX_CLIENTS; } @@ -57,7 +65,7 @@ static void CG_ParseScores( void ) { cg.teamScores[1] = atoi( CG_Argv( 3 ) ); memset( cg.scores, 0, sizeof( cg.scores ) ); - for ( i = 0 ; i < cg.numScores ; i++ ) { + for ( i = 0 ; i < readScores ; i++ ) { // cg.scores[i].client = atoi( CG_Argv( i * 14 + 4 ) ); cg.scores[i].score = atoi( CG_Argv( i * 14 + 5 ) ); @@ -129,10 +137,15 @@ void CG_ParseServerinfo( void ) { cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) ); cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) ); cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) ); + cgs.duel_fraglimit = atoi( Info_ValueForKey( info, "duel_fraglimit" ) ); cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) ); cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) ); cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) ); mapname = Info_ValueForKey( info, "mapname" ); + + //rww - You must do this one here, Info_ValueForKey always uses the same memory pointer. + trap_Cvar_Set ( "ui_about_mapname", mapname ); + Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname ); Q_strncpyz( cgs.redTeam, Info_ValueForKey( info, "g_redTeam" ), sizeof(cgs.redTeam) ); trap_Cvar_Set("g_redTeam", cgs.redTeam); @@ -141,11 +154,11 @@ void CG_ParseServerinfo( void ) { trap_Cvar_Set ( "ui_about_gametype", va("%i", cgs.gametype ) ); trap_Cvar_Set ( "ui_about_fraglimit", va("%i", cgs.fraglimit ) ); + trap_Cvar_Set ( "ui_about_duellimit", va("%i", cgs.duel_fraglimit ) ); trap_Cvar_Set ( "ui_about_capturelimit", va("%i", cgs.capturelimit ) ); trap_Cvar_Set ( "ui_about_timelimit", va("%i", cgs.timelimit ) ); trap_Cvar_Set ( "ui_about_maxclients", va("%i", cgs.maxclients ) ); trap_Cvar_Set ( "ui_about_dmflags", va("%i", cgs.dmflags ) ); - trap_Cvar_Set ( "ui_about_mapname", mapname ); trap_Cvar_Set ( "ui_about_hostname", Info_ValueForKey( info, "sv_hostname" ) ); trap_Cvar_Set ( "ui_about_needpass", Info_ValueForKey( info, "g_needpass" ) ); trap_Cvar_Set ( "ui_about_botminplayers", Info_ValueForKey ( info, "bot_minplayers" ) ); @@ -178,6 +191,7 @@ Called on load to set the initial values from configure strings void CG_SetConfigValues( void ) { const char *s; + const char *str; cgs.scores1 = atoi( CG_ConfigString( CS_SCORES1 ) ); cgs.scores2 = atoi( CG_ConfigString( CS_SCORES2 ) ); @@ -191,6 +205,38 @@ void CG_SetConfigValues( void ) // Track who the jedi master is cgs.jediMaster = atoi ( CG_ConfigString ( CS_CLIENT_JEDIMASTER ) ); + cgs.duelWinner = atoi ( CG_ConfigString ( CS_CLIENT_DUELWINNER ) ); + + str = CG_ConfigString(CS_CLIENT_DUELISTS); + + if (str && str[0]) + { + char buf[64]; + int c = 0; + int i = 0; + + while (str[i] && str[i] != '|') + { + buf[c] = str[i]; + c++; + i++; + } + buf[c] = 0; + + cgs.duelist1 = atoi ( buf ); + c = 0; + + i++; + while (str[i]) + { + buf[c] = str[i]; + c++; + i++; + } + buf[c] = 0; + + cgs.duelist2 = atoi ( buf ); + } } /* @@ -265,6 +311,34 @@ static void CG_ConfigStringModified( void ) { cgs.scores2 = atoi( str ); } else if ( num == CS_CLIENT_JEDIMASTER ) { cgs.jediMaster = atoi ( str ); + } else if ( num == CS_CLIENT_DUELWINNER ) { + cgs.duelWinner = atoi ( str ); + } else if ( num == CS_CLIENT_DUELISTS ) { + char buf[64]; + int c = 0; + int i = 0; + + while (str[i] && str[i] != '|') + { + buf[c] = str[i]; + c++; + i++; + } + buf[c] = 0; + + cgs.duelist1 = atoi ( buf ); + c = 0; + + i++; + while (str[i]) + { + buf[c] = str[i]; + c++; + i++; + } + buf[c] = 0; + + cgs.duelist2 = atoi ( buf ); } else if ( num == CS_LEVEL_START_TIME ) { cgs.levelStartTime = atoi( str ); } else if ( num == CS_VOTE_TIME ) { @@ -459,6 +533,8 @@ void CG_KillCEntityInstances() cg_entities[i].trickAlphaTime = 0; VectorClear(cg_entities[i].turAngles); cg_entities[i].weapon = 0; + cg_entities[i].teamPowerEffectTime = 0; + cg_entities[i].teamPowerType = 0; i++; } @@ -505,7 +581,7 @@ static void CG_MapRestart( void ) { // play the "fight" sound if this is a restart without warmup if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) { trap_S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER ); - CG_CenterPrint( "BEGIN", 120, GIANTCHAR_WIDTH*2 ); + CG_CenterPrint( CG_GetStripEdString("SVINGAME", "BEGIN_DUEL"), 120, GIANTCHAR_WIDTH*2 ); } if (cg_singlePlayerActive.integer) { trap_Cvar_Set("ui_matchStartTime", va("%i", cg.time)); @@ -546,7 +622,7 @@ typedef struct headModelVoiceChat_s } headModelVoiceChat_t; voiceChatList_t voiceChatLists[MAX_VOICEFILES]; -headModelVoiceChat_t headModelVoiceChat[MAX_HEADMODELS]; +//headModelVoiceChat_t headModelVoiceChat[MAX_HEADMODELS]; /* ================= @@ -740,13 +816,14 @@ CG_VoiceChatListForClient */ voiceChatList_t *CG_VoiceChatListForClient( int clientNum ) { clientInfo_t *ci; - int voiceChatNum, i, j, k, gender; - char filename[MAX_QPATH], headModelName[MAX_QPATH]; if ( clientNum < 0 || clientNum >= MAX_CLIENTS ) { clientNum = 0; } ci = &cgs.clientinfo[ clientNum ]; +/* + int voiceChatNum, i, j, k, gender; + char filename[MAX_QPATH], headModelName[MAX_QPATH]; for ( k = 0; k < 2; k++ ) { if ( k == 0 ) { @@ -821,6 +898,7 @@ voiceChatList_t *CG_VoiceChatListForClient( int clientNum ) { break; } } + */ // just return the first voice chat list return &voiceChatLists[0]; } @@ -996,6 +1074,77 @@ static void CG_RemoveChatEscapeChar( char *text ) { text[l] = '\0'; } +#define MAX_STRIPED_SV_STRING 1024 + +void CG_CheckSVStripEdRef(char *buf, const char *str) +{ //I don't really like doing this. But it utilizes the system that was already in place. + int i = 0; + int b = 0; + int strLen = 0; + qboolean gotStrip = qfalse; + + if (!str || !str[0]) + { + if (str) + { + strcpy(buf, str); + } + return; + } + + strcpy(buf, str); + + strLen = strlen(str); + + if (strLen >= MAX_STRIPED_SV_STRING) + { + return; + } + + while (i < strLen && str[i]) + { + gotStrip = qfalse; + + if (str[i] == '@' && (i+1) < strLen) + { + if (str[i+1] == '@' && (i+2) < strLen) + { + if (str[i+2] == '@' && (i+3) < strLen) + { //@@@ should mean to insert a striped reference here, so insert it into buf at the current place + char stripRef[MAX_STRIPED_SV_STRING]; + int r = 0; + + while (i < strLen && str[i] == '@') + { + i++; + } + + while (i < strLen && str[i] && str[i] != ' ' && str[i] != ':' && str[i] != '.' && str[i] != '\n') + { + stripRef[r] = str[i]; + r++; + i++; + } + stripRef[r] = 0; + + buf[b] = 0; + Q_strcat(buf, MAX_STRIPED_SV_STRING, CG_GetStripEdString("SVINGAME", stripRef)); + b = strlen(buf); + } + } + } + + if (!gotStrip) + { + buf[b] = str[i]; + b++; + } + i++; + } + + buf[b] = 0; +} + /* ================= CG_ServerCommand @@ -1039,8 +1188,75 @@ static void CG_ServerCommand( void ) { return; } + if ( !strcmp( cmd, "nfr" ) ) + { //"nfr" == "new force rank" (want a short string) + int doMenu = 0; + int setTeam = 0; + int newRank = 0; + + if (trap_Argc() < 3) + { +#ifdef _DEBUG + Com_Printf("WARNING: Invalid newForceRank string\n"); +#endif + return; + } + + newRank = atoi(CG_Argv(1)); + doMenu = atoi(CG_Argv(2)); + setTeam = atoi(CG_Argv(3)); + + trap_Cvar_Set("ui_rankChange", va("%i", newRank)); + + trap_Cvar_Set("ui_myteam", va("%i", setTeam)); + + if (!( trap_Key_GetCatcher() & KEYCATCH_UI ) && doMenu) + { + trap_OpenUIMenu(3); + } + + return; + } + + if ( !strcmp( cmd, "kg2" ) ) + { //Kill a ghoul2 instance in this slot. + //If it has been occupied since this message was sent somehow, the worst that can (should) happen + //is the instance will have to reinit with its current info. + int indexNum = 0; + int argNum = trap_Argc(); + int i = 1; + + if (argNum < 1) + { + return; + } + + while (i < argNum) + { + indexNum = atoi(CG_Argv(i)); + + if (cg_entities[indexNum].ghoul2 && trap_G2_HaveWeGhoul2Models(cg_entities[indexNum].ghoul2)) + { + if (indexNum < MAX_CLIENTS) + { //You try to do very bad thing! +#ifdef _DEBUG + Com_Printf("WARNING: Tried to kill a client ghoul2 instance with a kg2 command!\n"); +#endif + return; + } + trap_G2API_CleanGhoul2Models(&(cg_entities[indexNum].ghoul2)); + } + + i++; + } + + return; + } + if ( !strcmp( cmd, "cp" ) ) { - CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); + char strEd[MAX_STRIPED_SV_STRING]; + CG_CheckSVStripEdRef(strEd, CG_Argv(1)); + CG_CenterPrint( strEd, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); return; } @@ -1050,7 +1266,9 @@ static void CG_ServerCommand( void ) { } if ( !strcmp( cmd, "print" ) ) { - CG_Printf( "%s", CG_Argv(1) ); + char strEd[MAX_STRIPED_SV_STRING]; + CG_CheckSVStripEdRef(strEd, CG_Argv(1)); + CG_Printf( "%s", strEd ); return; } diff --git a/CODE-mp/cgame/cg_syscalls.asm b/CODE-mp/cgame/cg_syscalls.asm new file mode 100644 index 0000000..e01be71 --- /dev/null +++ b/CODE-mp/cgame/cg_syscalls.asm @@ -0,0 +1,171 @@ +code + +equ trap_Print -1 ; CG_PRINT +equ trap_Error -2 ; CG_ERROR +equ trap_Milliseconds -3 ; CG_MILLISECONDS +equ trap_Cvar_Register -4 ; CG_CVAR_REGISTER +equ trap_Cvar_Update -5 ; CG_CVAR_UPDATE +equ trap_Cvar_Set -6 ; CG_CVAR_SET +equ trap_Cvar_VariableStringBuffer -7 ; CG_CVAR_VARIABLESTRINGBUFFER +equ trap_Argc -8 ; CG_ARGC +equ trap_Argv -9 ; CG_ARGV +equ trap_Args -10 ; CG_ARGS +equ trap_FS_FOpenFile -11 ; CG_FS_FOPENFILE +equ trap_FS_Read -12 ; CG_FS_READ +equ trap_FS_Write -13 ; CG_FS_WRITE +equ trap_FS_FCloseFile -14 ; CG_FS_FCLOSEFILE +equ trap_SendConsoleCommand -15 ; CG_SENDCONSOLECOMMAND +equ trap_AddCommand -16 ; CG_ADDCOMMAND +equ trap_RemoveCommand -17 ; CG_REMOVECOMMAND +equ trap_SendClientCommand -18 ; CG_SENDCLIENTCOMMAND +equ trap_UpdateScreen -19 ; CG_UPDATESCREEN +equ trap_CM_LoadMap -20 ; CG_CM_LOADMAP +equ trap_CM_NumInlineModels -21 ; CG_CM_NUMINLINEMODELS +equ trap_CM_InlineModel -22 ; CG_CM_INLINEMODEL +equ trap_CM_TempBoxModel -23 ; CG_CM_TEMPBOXMODEL +equ trap_CM_TempCapsuleModel -24 ; CG_CM_TEMPCAPSULEMODEL +equ trap_CM_PointContents -25 ; CG_CM_POINTCONTENTS +equ trap_CM_TransformedPointContents -26 ; CG_CM_TRANSFORMEDPOINTCONTENTS +equ trap_CM_BoxTrace -27 ; CG_CM_BOXTRACE +equ trap_CM_CapsuleTrace -28 ; CG_CM_CAPSULETRACE +equ trap_CM_TransformedBoxTrace -29 ; CG_CM_TRANSFORMEDBOXTRACE +equ trap_CM_TransformedCapsuleTrace -30 ; CG_CM_TRANSFORMEDCAPSULETRACE +equ trap_CM_MarkFragments -31 ; CG_CM_MARKFRAGMENTS +equ trap_S_MuteSound -32 ; CG_S_MUTESOUND +equ trap_S_StartSound -33 ; CG_S_STARTSOUND +equ trap_S_StartLocalSound -34 ; CG_S_STARTLOCALSOUND +equ trap_S_ClearLoopingSounds -35 ; CG_S_CLEARLOOPINGSOUNDS +equ trap_S_AddLoopingSound -36 ; CG_S_ADDLOOPINGSOUND +equ trap_S_UpdateEntityPosition -37 ; CG_S_UPDATEENTITYPOSITION +equ trap_S_AddRealLoopingSound -38 ; CG_S_ADDREALLOOPINGSOUND +equ trap_S_StopLoopingSound -39 ; CG_S_STOPLOOPINGSOUND +equ trap_S_Respatialize -40 ; CG_S_RESPATIALIZE +equ trap_S_RegisterSound -41 ; CG_S_REGISTERSOUND +equ trap_S_StartBackgroundTrack -42 ; CG_S_STARTBACKGROUNDTRACK +equ trap_R_LoadWorldMap -43 ; CG_R_LOADWORLDMAP +equ trap_R_RegisterModel -44 ; CG_R_REGISTERMODEL +equ trap_R_RegisterSkin -45 ; CG_R_REGISTERSKIN +equ trap_R_RegisterShader -46 ; CG_R_REGISTERSHADER +equ trap_R_RegisterShaderNoMip -47 ; CG_R_REGISTERSHADERNOMIP +equ trap_R_RegisterFont -48 ; CG_R_REGISTERFONT +equ trap_R_Font_StrLenPixels -49 ; CG_R_FONT_STRLENPIXELS +equ trap_R_Font_StrLenChars -50 ; CG_R_FONT_STRLENCHARS +equ trap_R_Font_HeightPixels -51 ; CG_R_FONT_STRHEIGHTPIXELS +equ trap_R_Font_DrawString -52 ; CG_R_FONT_DRAWSTRING +equ trap_AnyLanguage_ReadCharFromString -53 ; CG_ANYLANGUAGE_READCHARFROMSTRING +equ trap_R_ClearScene -201 ; CG_R_CLEARSCENE +equ trap_R_AddRefEntityToScene -202 ; CG_R_ADDREFENTITYTOSCENE +equ trap_R_AddPolyToScene -203 ; CG_R_ADDPOLYTOSCENE +equ trap_R_AddPolysToScene -204 ; CG_R_ADDPOLYSTOSCENE +equ trap_R_LightForPoint -205 ; CG_R_LIGHTFORPOINT +equ trap_R_AddLightToScene -206 ; CG_R_ADDLIGHTTOSCENE +equ trap_R_AddAdditiveLightToScene -207 ; CG_R_ADDADDITIVELIGHTTOSCENE +equ trap_R_RenderScene -208 ; CG_R_RENDERSCENE +equ trap_R_SetColor -209 ; CG_R_SETCOLOR +equ trap_R_DrawStretchPic -210 ; CG_R_DRAWSTRETCHPIC +equ trap_R_ModelBounds -211 ; CG_R_MODELBOUNDS +equ trap_R_LerpTag -212 ; CG_R_LERPTAG +equ trap_R_DrawRotatePic -213 ; CG_R_DRAWROTATEPIC +equ trap_R_DrawRotatePic2 -214 ; CG_R_DRAWROTATEPIC2 +equ trap_R_RemapShader -215 ; CG_R_REMAP_SHADER +equ trap_R_GetLightStyle -216 ; CG_R_GET_LIGHT_STYLE +equ trap_R_SetLightStyle -217 ; CG_R_SET_LIGHT_STYLE +equ trap_R_GetBModelVerts -218 ; CG_R_GET_BMODEL_VERTS +equ trap_FX_AddLine -219 ; CG_FX_ADDLINE +equ trap_GetGlconfig -220 ; CG_GETGLCONFIG +equ trap_GetGameState -221 ; CG_GETGAMESTATE +equ trap_GetCurrentSnapshotNumber -222 ; CG_GETCURRENTSNAPSHOTNUMBER +equ trap_GetSnapshot -223 ; CG_GETSNAPSHOT +equ trap_GetServerCommand -224 ; CG_GETSERVERCOMMAND +equ trap_GetCurrentCmdNumber -225 ; CG_GETCURRENTCMDNUMBER +equ trap_GetUserCmd -226 ; CG_GETUSERCMD +equ trap_SetUserCmdValue -227 ; CG_SETUSERCMDVALUE +equ trap_SetClientForceAngle -228 ; CG_SETCLIENTFORCEANGLE +equ trap_SetClientTurnExtent -229 ; CG_SETCLIENTTURNEXTENT +equ trap_OpenUIMenu -230 ; CG_OPENUIMENU +equ trap_MemoryRemaining -233 ; CG_MEMORY_REMAINING +equ trap_Key_IsDown -234 ; CG_KEY_ISDOWN +equ trap_Key_GetCatcher -235 ; CG_KEY_GETCATCHER +equ trap_Key_SetCatcher -236 ; CG_KEY_SETCATCHER +equ trap_Key_GetKey -237 ; CG_KEY_GETKEY +equ trap_PC_AddGlobalDefine -238 ; CG_PC_ADD_GLOBAL_DEFINE +equ trap_PC_LoadSource -239 ; CG_PC_LOAD_SOURCE +equ trap_PC_FreeSource -240 ; CG_PC_FREE_SOURCE +equ trap_PC_ReadToken -241 ; CG_PC_READ_TOKEN +equ trap_PC_SourceFileAndLine -242 ; CG_PC_SOURCE_FILE_AND_LINE +equ trap_PC_LoadGlobalDefines -243 ; CG_PC_LOAD_GLOBAL_DEFINES +equ trap_PC_RemoveAllGlobalDefines -244 ; CG_PC_REMOVE_ALL_GLOBAL_DEFINES +equ trap_S_StopBackgroundTrack -245 ; CG_S_STOPBACKGROUNDTRACK +equ trap_RealTime -246 ; CG_REAL_TIME +equ trap_SnapVector -247 ; CG_SNAPVECTOR +equ trap_CIN_PlayCinematic -248 ; CG_CIN_PLAYCINEMATIC +equ trap_CIN_StopCinematic -249 ; CG_CIN_STOPCINEMATIC +equ trap_CIN_RunCinematic -250 ; CG_CIN_RUNCINEMATIC +equ trap_CIN_DrawCinematic -251 ; CG_CIN_DRAWCINEMATIC +equ trap_CIN_SetExtents -252 ; CG_CIN_SETEXTENTS +equ trap_GetEntityToken -253 ; CG_GET_ENTITY_TOKEN +equ trap_R_inPVS -254 ; CG_R_INPVS +equ trap_FX_RegisterEffect -255 ; CG_FX_REGISTER_EFFECT +equ trap_FX_PlaySimpleEffect -256 ; CG_FX_PLAY_SIMPLE_EFFECT +equ trap_FX_PlayEffect -257 ; CG_FX_PLAY_EFFECT +equ trap_FX_PlayEntityEffect -258 ; CG_FX_PLAY_ENTITY_EFFECT +equ trap_FX_PlaySimpleEffectID -259 ; CG_FX_PLAY_SIMPLE_EFFECT_ID +equ trap_FX_PlayEffectID -260 ; CG_FX_PLAY_EFFECT_ID +equ trap_FX_PlayEntityEffectID -261 ; CG_FX_PLAY_ENTITY_EFFECT_ID +equ trap_FX_PlayBoltedEffectID -262 ; CG_FX_PLAY_BOLTED_EFFECT_ID +equ trap_FX_AddScheduledEffects -263 ; CG_FX_ADD_SCHEDULED_EFFECTS +equ trap_FX_InitSystem -264 ; CG_FX_INIT_SYSTEM +equ trap_FX_FreeSystem -265 ; CG_FX_FREE_SYSTEM +equ trap_FX_AdjustTime -266 ; CG_FX_ADJUST_TIME +equ trap_FX_AddPoly -267 ; CG_FX_ADDPOLY +equ trap_FX_AddBezier -268 ; CG_FX_ADDBEZIER +equ trap_FX_AddPrimitive -269 ; CG_FX_ADDPRIMITIVE +equ trap_FX_AddSprite -270 ; CG_FX_ADDSPRITE +equ trap_SP_Print -271 ; CG_SP_PRINT +equ trap_SP_GetStringTextString -272 ; CG_SP_GETSTRINGTEXTSTRING +equ trap_SP_Register -273 ; CG_SP_REGISTER +equ trap_ROFF_Clean -274 ; CG_ROFF_CLEAN +equ trap_ROFF_UpdateEntities -275 ; CG_ROFF_UPDATE_ENTITIES +equ trap_ROFF_Cache -276 ; CG_ROFF_CACHE +equ trap_ROFF_Play -277 ; CG_ROFF_PLAY +equ trap_ROFF_Purge_Ent -278 ; CG_ROFF_PURGE_ENT +equ trap_G2_ListModelSurfaces -279 ; CG_G2_LISTSURFACES +equ trap_G2_ListModelBones -280 ; CG_G2_LISTBONES +equ trap_G2_SetGhoul2ModelIndexes -281 ; CG_G2_SETMODELS +equ trap_G2_HaveWeGhoul2Models -282 ; CG_G2_HAVEWEGHOULMODELS +equ trap_G2API_GiveMeVectorFromMatrix -283 ; CG_G2_GIVEMEVECTORFROMMATRIX +equ trap_G2API_GetBoltMatrix -284 ; CG_G2_GETBOLT +equ trap_G2API_GetBoltMatrix_NoReconstruct -285 ; CG_G2_GETBOLT_NOREC +equ trap_G2API_InitGhoul2Model -286 ; CG_G2_INITGHOUL2MODEL +equ trap_G2API_CleanGhoul2Models -287 ; CG_G2_CLEANMODELS +equ trap_G2API_SetBoneAngles -288 ; CG_G2_ANGLEOVERRIDE +equ trap_G2API_SetBoneAnim -289 ; CG_G2_PLAYANIM +equ trap_G2API_GetGLAName -290 ; CG_G2_GETGLANAME +equ trap_G2API_CopyGhoul2Instance -291 ; CG_G2_COPYGHOUL2INSTANCE +equ trap_G2API_CopySpecificGhoul2Model -292 ; CG_G2_COPYSPECIFICGHOUL2MODEL +equ trap_G2API_DuplicateGhoul2Instance -293 ; CG_G2_DUPLICATEGHOUL2INSTANCE +equ trap_G2API_HasGhoul2ModelOnIndex -294 ; CG_G2_HASGHOUL2MODELONINDEX +equ trap_G2API_RemoveGhoul2Model -295 ; CG_G2_REMOVEGHOUL2MODEL +equ trap_G2API_AddBolt -296 ; CG_G2_ADDBOLT +equ trap_G2API_SetBoltInfo -297 ; CG_G2_SETBOLTON +equ trap_G2API_SetRootSurface -298 ; CG_G2_SETROOTSURFACE +equ trap_G2API_SetSurfaceOnOff -299 ; CG_G2_SETSURFACEONOFF +equ trap_G2API_SetNewOrigin -300 ; CG_G2_SETNEWORIGIN +equ trap_CG_RegisterSharedMemory -301 ; CG_SET_SHARED_BUFFER + + +; hardcoded functions +equ memset -101 ; CGAME_MEMSET +equ memcpy -102 ; CGAME_MEMCPY +equ strncpy -103 ; CGAME_STRNCPY +equ sin -104 ; CGAME_SIN +equ cos -105 ; CGAME_COS +equ atan2 -106 ; CGAME_ATAN2 +equ sqrt -107 ; CGAME_SQRT +equ matrixmultiply -108 ; CGAME_MATRIXMULTIPLY +equ anglevectors -109 ; CGAME_ANGLEVECTORS +equ perpendicularvector -110 ; CGAME_PERPENDICULARVECTOR +equ floor -111 ; CGAME_FLOOR +equ ceil -112 ; CGAME_CEIL +equ acos -113 ; CGAME_ACOS +equ asin -114 ; CGAME_ASIN diff --git a/CODE-mp/cgame/cg_syscalls.c b/CODE-mp/cgame/cg_syscalls.c index f9ae526..4ffd644 100644 --- a/CODE-mp/cgame/cg_syscalls.c +++ b/CODE-mp/cgame/cg_syscalls.c @@ -553,9 +553,9 @@ qboolean trap_FX_FreeSystem( void ) return syscall( CG_FX_FREE_SYSTEM ); } -void trap_FX_AdjustTime( int time ) +void trap_FX_AdjustTime( int time, vec3_t vieworg, vec3_t viewaxis[3] ) { - syscall( CG_FX_ADJUST_TIME, time ); + syscall( CG_FX_ADJUST_TIME, time, vieworg, viewaxis ); } void trap_FX_AddPoly( addpolyArgStruct_t *p ) @@ -588,9 +588,9 @@ int trap_SP_GetStringTextString(const char *text, char *buffer, int bufferLength return syscall( CG_SP_GETSTRINGTEXTSTRING, text, buffer, bufferLength ); } -void trap_SP_Register(char *file ) +qboolean trap_SP_Register(char *file ) { - syscall( CG_SP_REGISTER,file ); + return syscall( CG_SP_REGISTER,file ); } qboolean trap_ROFF_Clean( void ) diff --git a/CODE-mp/cgame/cg_view.c b/CODE-mp/cgame/cg_view.c index 65935b3..3286e55 100644 --- a/CODE-mp/cgame/cg_view.c +++ b/CODE-mp/cgame/cg_view.c @@ -8,6 +8,10 @@ #include "cg_lights.h" #endif +#define MASK_CAMERACLIP (MASK_SOLID|CONTENTS_PLAYERCLIP) +#define CAMERA_SIZE 4 + + /* ============================================================================= @@ -212,8 +216,8 @@ static void CG_StepOffset( void ) { #define CAMERA_DAMP_INTERVAL 50 -static vec3_t cameramins = { -4, -4, -4 }; -static vec3_t cameramaxs = { 4, 4, 4 }; +static vec3_t cameramins = { -CAMERA_SIZE, -CAMERA_SIZE, -CAMERA_SIZE }; +static vec3_t cameramaxs = { CAMERA_SIZE, CAMERA_SIZE, CAMERA_SIZE }; vec3_t camerafwd, cameraup; vec3_t cameraFocusAngles, cameraFocusLoc; @@ -222,6 +226,9 @@ vec3_t cameraCurTarget={0,0,0}, cameraCurLoc={0,0,0}; vec3_t cameraOldLoc={0,0,0}, cameraNewLoc={0,0,0}; int cameraLastFrame=0; +float cameraLastYaw=0; +float cameraStiffFactor=0.0f; + /* =============== Notes on the camera viewpoint in and out... @@ -236,6 +243,9 @@ cg.refdefViewAngles =============== */ +extern qboolean gCGHasFallVector; +extern vec3_t gCGFallVector; + /* =============== CG_CalcTargetThirdPersonViewLocation @@ -252,7 +262,14 @@ static void CG_CalcIdealThirdPersonViewTarget(void) } // Initialize IdealTarget - VectorCopy(cg.refdef.vieworg, cameraFocusLoc); + if (gCGHasFallVector) + { + VectorCopy(gCGFallVector, cameraFocusLoc); + } + else + { + VectorCopy(cg.refdef.vieworg, cameraFocusLoc); + } // Add in the new viewheight cameraFocusLoc[2] += cg.snap->ps.viewheight; @@ -315,20 +332,22 @@ static void CG_ResetThirdPersonViewDamp(void) VectorCopy(cameraIdealTarget, cameraCurTarget); // First thing we do is trace from the first person viewpoint out to the new target location. - CG_Trace(&trace, cameraFocusLoc, cameramins, cameramaxs, cameraCurTarget, cg.snap->ps.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP); + CG_Trace(&trace, cameraFocusLoc, cameramins, cameramaxs, cameraCurTarget, cg.snap->ps.clientNum, MASK_CAMERACLIP); if (trace.fraction <= 1.0) { VectorCopy(trace.endpos, cameraCurTarget); } // Now we trace from the new target location to the new view location, to make sure there is nothing in the way. - CG_Trace(&trace, cameraCurTarget, cameramins, cameramaxs, cameraCurLoc, cg.snap->ps.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP); + CG_Trace(&trace, cameraCurTarget, cameramins, cameramaxs, cameraCurLoc, cg.snap->ps.clientNum, MASK_CAMERACLIP); if (trace.fraction <= 1.0) { VectorCopy(trace.endpos, cameraCurLoc); } cameraLastFrame = cg.time; + cameraLastYaw = cameraFocusAngles[YAW]; + cameraStiffFactor = 0.0f; } // This is called every frame. @@ -368,7 +387,7 @@ static void CG_UpdateThirdPersonTargetDamp(void) // Now we trace to see if the new location is cool or not. // First thing we do is trace from the first person viewpoint out to the new target location. - CG_Trace(&trace, cameraFocusLoc, cameramins, cameramaxs, cameraCurTarget, cg.snap->ps.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP); + CG_Trace(&trace, cameraFocusLoc, cameramins, cameramaxs, cameraCurTarget, cg.snap->ps.clientNum, MASK_CAMERACLIP); if (trace.fraction < 1.0) { VectorCopy(trace.endpos, cameraCurTarget); @@ -405,6 +424,12 @@ static void CG_UpdateThirdPersonCameraDamp(void) dampfactor = (1.0-cg_thirdPersonCameraDamp.value)*(pitch*pitch); dampfactor += cg_thirdPersonCameraDamp.value; + + // Now we also multiply in the stiff factor, so that faster yaw changes are stiffer. + if (cameraStiffFactor > 0.0f) + { // The cameraStiffFactor is how much of the remaining damp below 1 should be shaved off, i.e. approach 1 as stiffening increases. + dampfactor += (1.0-dampfactor)*cameraStiffFactor; + } } if (dampfactor>=1.0) @@ -431,10 +456,12 @@ static void CG_UpdateThirdPersonCameraDamp(void) } // Now we trace from the new target location to the new view location, to make sure there is nothing in the way. - CG_Trace(&trace, cameraCurTarget, cameramins, cameramaxs, cameraCurLoc, cg.snap->ps.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP); + CG_Trace(&trace, cameraCurTarget, cameramins, cameramaxs, cameraCurLoc, cg.snap->ps.clientNum, MASK_CAMERACLIP); + if (trace.fraction < 1.0) { VectorCopy( trace.endpos, cameraCurLoc ); + //FIXME: when the trace hits movers, it gets very very jaggy... ? /* //this doesn't actually help any @@ -475,6 +502,9 @@ static void CG_OffsetThirdPersonView( void ) { vec3_t diff; float thirdPersonHorzOffset = cg_thirdPersonHorzOffset.value; + float deltayaw; + + cameraStiffFactor = 0.0; // Set camera viewing direction. VectorCopy( cg.refdefViewAngles, cameraFocusAngles ); @@ -511,6 +541,26 @@ static void CG_OffsetThirdPersonView( void ) AngleVectors(cameraFocusAngles, camerafwd, NULL, cameraup); + deltayaw = fabs(cameraFocusAngles[YAW] - cameraLastYaw); + if (deltayaw > 180.0f) + { // Normalize this angle so that it is between 0 and 180. + deltayaw = fabs(deltayaw - 360.0f); + } + cameraStiffFactor = deltayaw / (float)(cg.time-cameraLastFrame); + if (cameraStiffFactor < 1.0) + { + cameraStiffFactor = 0.0; + } + else if (cameraStiffFactor > 2.5) + { + cameraStiffFactor = 0.75; + } + else + { // 1 to 2 scales from 0.0 to 0.5 + cameraStiffFactor = (cameraStiffFactor-1.0f)*0.5f; + } + cameraLastYaw = cameraFocusAngles[YAW]; + // Move the target to the new location. CG_UpdateThirdPersonTargetDamp(); CG_UpdateThirdPersonCameraDamp(); @@ -601,7 +651,7 @@ static void CG_OffsetThirdPersonView( void ) { // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything if (!cg_cameraMode.integer) { - CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID ); + CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_CAMERACLIP); if ( trace.fraction != 1.0 ) { VectorCopy( trace.endpos, view ); @@ -609,7 +659,7 @@ static void CG_OffsetThirdPersonView( void ) { // try another trace to this position, because a tunnel may have the ceiling // close enogh that this is poking out - CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID ); + CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_CAMERACLIP); VectorCopy( trace.endpos, view ); } } @@ -872,6 +922,16 @@ static int CG_CalcFov( void ) { float fov_x, fov_y; float f; int inwater; + float cgFov = cg_fov.value; + + if (cgFov < 1) + { + cgFov = 1; + } + if (cgFov > 97) + { + cgFov = 97; + } if ( cg.predictedPlayerState.pm_type == PM_INTERMISSION ) { // if in intermission, use a fixed value @@ -882,7 +942,7 @@ static int CG_CalcFov( void ) { // dmflag to prevent wide fov for all clients fov_x = 80;//90; } else { - fov_x = cg_fov.value; + fov_x = cgFov; if ( fov_x < 1 ) { fov_x = 1; } else if ( fov_x > 160 ) { @@ -900,9 +960,9 @@ static int CG_CalcFov( void ) { { zoomFov = 40.0f; } - else if (zoomFov > cg_fov.value) + else if (zoomFov > cgFov) { - zoomFov = cg_fov.value; + zoomFov = cgFov; } } @@ -922,9 +982,9 @@ static int CG_CalcFov( void ) { { zoomFov = MAX_ZOOM_FOV; } - else if (zoomFov > cg_fov.value) + else if (zoomFov > cgFov) { - zoomFov = cg_fov.value; + zoomFov = cgFov; } else { // Still zooming @@ -980,7 +1040,7 @@ static int CG_CalcFov( void ) { if (cg.predictedPlayerState.zoomMode) { - cg.zoomSensitivity = zoomFov/cg_fov.value; + cg.zoomSensitivity = zoomFov/cgFov; } else if ( !cg.zoomed ) { cg.zoomSensitivity = 1; @@ -1023,12 +1083,31 @@ static void CG_DamageBlendBlob( void ) VectorMA( ent.origin, cg.damageY * 8, cg.refdef.viewaxis[2], ent.origin ); ent.radius = cg.damageValue * 3 * ( 1.0 - ((float)t / maxTime) ); - ent.customShader = cgs.media.viewPainShader; - ent.shaderRGBA[0] = 180 * ( 1.0 - ((float)t / maxTime) ); - ent.shaderRGBA[1] = 50 * ( 1.0 - ((float)t / maxTime) ); - ent.shaderRGBA[2] = 50 * ( 1.0 - ((float)t / maxTime) ); - ent.shaderRGBA[3] = 255; + if (cg.snap->ps.damageType == 0) + { //pure health + ent.customShader = cgs.media.viewPainShader; + ent.shaderRGBA[0] = 180 * ( 1.0 - ((float)t / maxTime) ); + ent.shaderRGBA[1] = 50 * ( 1.0 - ((float)t / maxTime) ); + ent.shaderRGBA[2] = 50 * ( 1.0 - ((float)t / maxTime) ); + ent.shaderRGBA[3] = 255; + } + else if (cg.snap->ps.damageType == 1) + { //pure shields + ent.customShader = cgs.media.viewPainShader_Shields; + ent.shaderRGBA[0] = 50 * ( 1.0 - ((float)t / maxTime) ); + ent.shaderRGBA[1] = 180 * ( 1.0 - ((float)t / maxTime) ); + ent.shaderRGBA[2] = 50 * ( 1.0 - ((float)t / maxTime) ); + ent.shaderRGBA[3] = 255; + } + else + { //shields and health + ent.customShader = cgs.media.viewPainShader_ShieldsAndHealth; + ent.shaderRGBA[0] = 180 * ( 1.0 - ((float)t / maxTime) ); + ent.shaderRGBA[1] = 180 * ( 1.0 - ((float)t / maxTime) ); + ent.shaderRGBA[2] = 50 * ( 1.0 - ((float)t / maxTime) ); + ent.shaderRGBA[3] = 255; + } trap_R_AddRefEntityToScene( &ent ); } @@ -1132,6 +1211,11 @@ static int CG_CalcViewValues( void ) { cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] + ps->velocity[1] * ps->velocity[1] ); + if (cg.xyspeed > 270) + { + cg.xyspeed = 270; + } + VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); @@ -1306,16 +1390,63 @@ void CG_SE_UpdateShake( vec3_t origin, vec3_t angles ) VectorAdd( angles, moveDir, angles ); } +void CG_SE_UpdateMusic(void) +{ + if (cgScreenEffects.music_volume_multiplier < 0.1) + { + cgScreenEffects.music_volume_multiplier = 1.0; + return; + } + + if (cgScreenEffects.music_volume_time < cg.time) + { + if (cgScreenEffects.music_volume_multiplier != 1.0 || cgScreenEffects.music_volume_set) + { + char musMultStr[512]; + + cgScreenEffects.music_volume_multiplier += 0.1; + if (cgScreenEffects.music_volume_multiplier > 1.0) + { + cgScreenEffects.music_volume_multiplier = 1.0; + } + + Com_sprintf(musMultStr, sizeof(musMultStr), "%f", cgScreenEffects.music_volume_multiplier); + trap_Cvar_Set("s_musicMult", musMultStr); + + if (cgScreenEffects.music_volume_multiplier == 1.0) + { + cgScreenEffects.music_volume_set = qfalse; + } + else + { + cgScreenEffects.music_volume_time = cg.time + 200; + } + } + + return; + } + + if (!cgScreenEffects.music_volume_set) + { //if the volume_time is >= cg.time, we should have a volume multiplier set + char musMultStr[512]; + + Com_sprintf(musMultStr, sizeof(musMultStr), "%f", cgScreenEffects.music_volume_multiplier); + trap_Cvar_Set("s_musicMult", musMultStr); + cgScreenEffects.music_volume_set = qtrue; + } +} + /* ================= CG_CalcScreenEffects -Currently just for screen shaking +Currently just for screen shaking (and music volume management) ================= */ void CG_CalcScreenEffects(void) { CG_SE_UpdateShake(cg.refdef.vieworg, cg.refdefViewAngles); + CG_SE_UpdateMusic(); } void CGCam_Shake( float intensity, int duration ) @@ -1327,6 +1458,24 @@ void CGCam_Shake( float intensity, int duration ) cgScreenEffects.shake_duration = duration; cgScreenEffects.shake_start = cg.time; } + +void CGCam_SetMusicMult( float multiplier, int duration ) +{ + if (multiplier < 0.1f) + { + multiplier = 0.1f; + } + + if (multiplier > 1.0f) + { + multiplier = 1.0f; + } + + cgScreenEffects.music_volume_multiplier = multiplier; + cgScreenEffects.music_volume_time = cg.time + duration; + cgScreenEffects.music_volume_set = qfalse; +} + /* ================================ Screen Effect stuff ends here @@ -1346,6 +1495,11 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo cg.time = serverTime; cg.demoPlayback = demoPlayback; + if (cg.snap && ui_myteam.integer != cg.snap->ps.persistant[PERS_TEAM]) + { + trap_Cvar_Set ( "ui_myteam", va("%i", cg.snap->ps.persistant[PERS_TEAM]) ); + } + // update cvars CG_UpdateCvars(); @@ -1356,7 +1510,7 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo return; } - trap_FX_AdjustTime( cg.time ); + trap_FX_AdjustTime( cg.time, cg.refdef.vieworg, cg.refdef.viewaxis ); CG_RunLightStyles(); @@ -1403,7 +1557,7 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo cg.renderingThirdPerson = cg_thirdPerson.integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0); if (cg.snap->ps.stats[STAT_HEALTH] > 0 && (cg.predictedPlayerState.weapon == WP_SABER || cg.predictedPlayerState.usingATST || - cg.predictedPlayerState.forceHandExtend == HANDEXTEND_KNOCKDOWN)) + cg.predictedPlayerState.forceHandExtend == HANDEXTEND_KNOCKDOWN || cg.predictedPlayerState.fallingToDeath)) { cg.renderingThirdPerson = 1; } @@ -1431,7 +1585,7 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo } CG_AddViewWeapon( &cg.predictedPlayerState ); - if ( !cg.hyperspace ) + if ( !cg.hyperspace) { trap_FX_AddScheduledEffects(); } @@ -1455,6 +1609,18 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo // if there are any entities flagged as sound trackers and attached to other entities, update their sound pos CG_UpdateSoundTrackers(); + if (gCGHasFallVector) + { + vec3_t lookAng; + + VectorSubtract(cg.snap->ps.origin, cg.refdef.vieworg, lookAng); + VectorNormalize(lookAng); + vectoangles(lookAng, lookAng); + + VectorCopy(gCGFallVector, cg.refdef.vieworg); + AnglesToAxis(lookAng, cg.refdef.viewaxis); + } + // update audio positions trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater ); diff --git a/CODE-mp/cgame/cg_weaponinit.c b/CODE-mp/cgame/cg_weaponinit.c index e093687..96d60ab 100644 --- a/CODE-mp/cgame/cg_weaponinit.c +++ b/CODE-mp/cgame/cg_weaponinit.c @@ -80,6 +80,12 @@ void CG_RegisterWeapon( int weaponNum) { strcat( path, "_barrel.md3" ); weaponInfo->barrelModel = trap_R_RegisterModel( path ); } + else if (weaponNum == WP_STUN_BATON) + { //only weapon with more than 1 barrel.. + trap_R_RegisterModel("models/weapons2/stun_baton/baton_barrel.md3"); + trap_R_RegisterModel("models/weapons2/stun_baton/baton_barrel2.md3"); + trap_R_RegisterModel("models/weapons2/stun_baton/baton_barrel3.md3"); + } else { weaponInfo->barrelModel = 0; @@ -114,19 +120,22 @@ void CG_RegisterWeapon( int weaponNum) { weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/saber/saberhum.wav" ); // weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/melee/fstatck.wav" ); */ - trap_R_RegisterShader( "gfx/effects/stunPass" ); - - trap_R_RegisterShader( "gfx/effects/stunTest" ); + //trap_R_RegisterShader( "gfx/effects/stunPass" ); trap_FX_RegisterEffect( "stunBaton/flesh_impact" ); //TEMP trap_S_RegisterSound( "sound/weapons/melee/punch1.mp3" ); trap_S_RegisterSound( "sound/weapons/melee/punch2.mp3" ); trap_S_RegisterSound( "sound/weapons/melee/punch3.mp3" ); trap_S_RegisterSound( "sound/weapons/melee/punch4.mp3" ); + + trap_S_RegisterSound( "sound/weapons/baton/idle.wav" ); + weaponInfo->flashSound[0] = trap_S_RegisterSound( "sound/weapons/baton/fire.mp3" ); + weaponInfo->altFlashSound[0] = trap_S_RegisterSound( "sound/weapons/baton/fire.mp3" ); + break; case WP_SABER: MAKERGB( weaponInfo->flashDlightColor, 0.6f, 0.6f, 1.0f ); - weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/saber/saberhum.wav1" ); + weaponInfo->firingSound = trap_S_RegisterSound( "sound/weapons/saber/saberhum1.wav" ); weaponInfo->missileModel = trap_R_RegisterModel( "models/weapons2/saber/saber_w.glm" ); break; @@ -349,7 +358,7 @@ void CG_RegisterWeapon( int weaponNum) { weaponInfo->firingSound = NULL_SOUND; weaponInfo->chargeSound = NULL_SOUND; weaponInfo->muzzleEffect = trap_FX_RegisterEffect( "flechette/muzzle_flash" ); - weaponInfo->missileModel = NULL_HANDLE; + weaponInfo->missileModel = trap_R_RegisterModel("models/weapons2/golan_arms/projectileMain.md3"); weaponInfo->missileSound = NULL_SOUND; weaponInfo->missileDlight = 0; // weaponInfo->missileDlightColor = {0,0,0}; diff --git a/CODE-mp/cgame/cg_weapons.c b/CODE-mp/cgame/cg_weapons.c index 9247a6b..4249514 100644 --- a/CODE-mp/cgame/cg_weapons.c +++ b/CODE-mp/cgame/cg_weapons.c @@ -56,6 +56,11 @@ void CG_RegisterItemVisuals( int itemNum ) { { //in CTY the flag model is different itemInfo->models[0] = trap_R_RegisterModel( item->world_model[1] ); } + else if (item->giType == IT_WEAPON && + (item->giTag == WP_THERMAL || item->giTag == WP_TRIP_MINE || item->giTag == WP_DET_PACK)) + { + itemInfo->models[0] = trap_R_RegisterModel( item->world_model[1] ); + } else { itemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] ); @@ -111,6 +116,14 @@ VIEW WEAPON ======================================================================================== */ +#define WEAPON_FORCE_BUSY_HOLSTER + +#ifdef WEAPON_FORCE_BUSY_HOLSTER +//rww - this was done as a last resort. Forgive me. +static int cgWeapFrame = 0; +static int cgWeapFrameTime = 0; +#endif + /* ================= CG_MapTorsoToWeaponFrame @@ -119,6 +132,36 @@ CG_MapTorsoToWeaponFrame */ static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame, int animNum ) { animation_t *animations = bgGlobalAnimations; +#ifdef WEAPON_FORCE_BUSY_HOLSTER + if (cg.snap->ps.forceHandExtend != HANDEXTEND_NONE || cgWeapFrameTime > cg.time) + { //the reason for the after delay is so that it doesn't snap the weapon frame to the "idle" (0) frame + //for a very quick moment + if (cgWeapFrame < 6) + { + cgWeapFrame = 6; + cgWeapFrameTime = cg.time + 10; + } + + if (cgWeapFrameTime < cg.time && cgWeapFrame < 10) + { + cgWeapFrame++; + cgWeapFrameTime = cg.time + 10; + } + + if (cg.snap->ps.forceHandExtend != HANDEXTEND_NONE && + cgWeapFrame == 10) + { + cgWeapFrameTime = cg.time + 100; + } + + return cgWeapFrame; + } + else + { + cgWeapFrame = 0; + cgWeapFrameTime = 0; + } +#endif switch( animNum ) { @@ -135,7 +178,6 @@ static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame, int animNum ) return frame - animations[animNum].firstFrame + 6 + 4; } break; - case BOTH_ATTACK1: case BOTH_ATTACK2: case BOTH_ATTACK3: @@ -324,40 +366,6 @@ static void CG_LightningBolt( centity_t *cent, vec3_t origin ) { } -/* -====================== -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 = AngleMod( angle ); - cent->pe.barrelSpinning = !!(cent->currentState.eFlags & EF_FIRING); - } - - return angle; -} - - /* ======================== CG_AddWeaponWithPowerups @@ -453,6 +461,7 @@ Ghoul2 Insert Start cg.snap->ps.clientNum)) { CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups ); //don't draw the weapon if the player is invisible + /* if ( weaponNum == WP_STUN_BATON ) { gun.shaderRGBA[0] = gun.shaderRGBA[1] = gun.shaderRGBA[2] = 25; @@ -461,25 +470,75 @@ Ghoul2 Insert Start gun.renderfx = RF_RGB_TINT | RF_FIRST_PERSON | RF_DEPTHHACK; trap_R_AddRefEntityToScene( &gun ); } + */ } - // add the spinning barrel - if ( weapon->barrelModel ) { - memset( &barrel, 0, sizeof( barrel ) ); - VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); - barrel.shadowPlane = parent->shadowPlane; - barrel.renderfx = parent->renderfx; + if (weaponNum == WP_STUN_BATON) + { + int i = 0; - barrel.hModel = weapon->barrelModel; - angles[YAW] = 0; - angles[PITCH] = 0; - angles[ROLL] = 0; + while (i < 3) + { + memset( &barrel, 0, sizeof( barrel ) ); + VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); + barrel.shadowPlane = parent->shadowPlane; + barrel.renderfx = parent->renderfx; - AnglesToAxis( angles, barrel.axis ); + if (i == 0) + { + barrel.hModel = trap_R_RegisterModel("models/weapons2/stun_baton/baton_barrel.md3"); + } + else if (i == 1) + { + barrel.hModel = trap_R_RegisterModel("models/weapons2/stun_baton/baton_barrel2.md3"); + } + else + { + barrel.hModel = trap_R_RegisterModel("models/weapons2/stun_baton/baton_barrel3.md3"); + } + angles[YAW] = 0; + angles[PITCH] = 0; + angles[ROLL] = 0; - CG_PositionRotatedEntityOnTag( &barrel, parent/*&gun*/, /*weapon->weaponModel*/weapon->handsModel, "tag_barrel" ); + AnglesToAxis( angles, barrel.axis ); - CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups ); + if (i == 0) + { + CG_PositionRotatedEntityOnTag( &barrel, parent/*&gun*/, /*weapon->weaponModel*/weapon->handsModel, "tag_barrel" ); + } + else if (i == 1) + { + CG_PositionRotatedEntityOnTag( &barrel, parent/*&gun*/, /*weapon->weaponModel*/weapon->handsModel, "tag_barrel2" ); + } + else + { + CG_PositionRotatedEntityOnTag( &barrel, parent/*&gun*/, /*weapon->weaponModel*/weapon->handsModel, "tag_barrel3" ); + } + CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups ); + + i++; + } + } + else + { + // add the spinning barrel + if ( weapon->barrelModel ) { + memset( &barrel, 0, sizeof( barrel ) ); + VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); + barrel.shadowPlane = parent->shadowPlane; + barrel.renderfx = parent->renderfx; + + barrel.hModel = weapon->barrelModel; + angles[YAW] = 0; + angles[PITCH] = 0; + angles[ROLL] = 0; + + AnglesToAxis( angles, barrel.axis ); + + CG_PositionRotatedEntityOnTag( &barrel, parent/*&gun*/, /*weapon->weaponModel*/weapon->handsModel, "tag_barrel" ); + + CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups ); + } } } /* @@ -683,6 +742,16 @@ void CG_AddViewWeapon( playerState_t *ps ) { float fovOffset; vec3_t angles; weaponInfo_t *weapon; + float cgFov = cg_fov.value; + + if (cgFov < 1) + { + cgFov = 1; + } + if (cgFov > 97) + { + cgFov = 97; + } if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) { return; @@ -717,8 +786,8 @@ void CG_AddViewWeapon( playerState_t *ps ) { } // drop gun lower at higher fov - if ( cg_fov.integer > 90 ) { - fovOffset = -0.2 * ( cg_fov.integer - 90 ); + if ( cgFov > 90 ) { + fovOffset = -0.2 * ( cgFov - 90 ); } else { fovOffset = 0; } @@ -800,6 +869,11 @@ void CG_DrawIconBackground(void) return; } + if (cg_hudFiles.integer) + { //simple hud + return; + } + x2 = 30; y2 = SCREEN_HEIGHT-70; @@ -965,7 +1039,6 @@ void CG_DrawWeaponSelect( void ) { int i; int bits; int count; - char *name; int smallIconSize,bigIconSize; int holdX,x,y,pad; int sideLeftIconCnt,sideRightIconCnt; @@ -1177,15 +1250,16 @@ void CG_DrawWeaponSelect( void ) { // draw the selected name if ( cg_weapons[ cg.weaponSelect ].item ) { - name = cg_weapons[ cg.weaponSelect ].item->pickup_name; - if ( name ) + vec4_t textColor = { .875f, .718f, .121f, 1.0f }; + char text[1024]; + + if ( trap_SP_GetStringTextString( va("INGAME_%s",cg_weapons[ cg.weaponSelect ].item->classname), text, sizeof( text ))) { - vec4_t textColor = { .875f, .718f, .121f, 1.0f }; -// Just doing this for now...... -//#ifdef _DEBUG - //CG_DrawProportionalString(320, y + 48, name, CG_CENTER | CG_SMALLFONT, colorTable[CT_ICON_BLUE]); - UI_DrawProportionalString(320, y+48, name, UI_CENTER|UI_SMALLFONT, textColor); -//#endif + UI_DrawProportionalString(320, y+45, text, UI_CENTER|UI_SMALLFONT, textColor); + } + else + { + UI_DrawProportionalString(320, y+45, cg_weapons[ cg.weaponSelect ].item->classname, UI_CENTER|UI_SMALLFONT, textColor); } } diff --git a/CODE-mp/cgame/cgame.bat b/CODE-mp/cgame/cgame.bat new file mode 100644 index 0000000..7fda2fd --- /dev/null +++ b/CODE-mp/cgame/cgame.bat @@ -0,0 +1,102 @@ +del /q vm +mkdir vm +cd vm +set cc=lcc -DQ3_VM -DMISSIONPACK -DCGAME -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui %1 + +%cc% ../../game/bg_misc.c +@if errorlevel 1 goto quit +%cc% ../../game/bg_weapons.c +@if errorlevel 1 goto quit +%cc% ../../game/bg_panimate.c +@if errorlevel 1 goto quit +%cc% ../../game/bg_pmove.c +@if errorlevel 1 goto quit +%cc% ../../game/bg_slidemove.c +@if errorlevel 1 goto quit +%cc% ../../game/bg_lib.c +@if errorlevel 1 goto quit +%cc% ../../game/bg_saber.c +@if errorlevel 1 goto quit +%cc% ../../game/q_math.c +@if errorlevel 1 goto quit +%cc% ../../game/q_shared.c +@if errorlevel 1 goto quit +%cc% ../cg_consolecmds.c +@if errorlevel 1 goto quit +%cc% ../cg_draw.c +@if errorlevel 1 goto quit +%cc% ../cg_drawtools.c +@if errorlevel 1 goto quit +%cc% ../cg_effects.c +@if errorlevel 1 goto quit +%cc% ../cg_ents.c +@if errorlevel 1 goto quit +%cc% ../cg_event.c +@if errorlevel 1 goto quit +%cc% ../cg_info.c +@if errorlevel 1 goto quit +%cc% ../cg_light.c +@if errorlevel 1 goto quit +%cc% ../cg_localents.c +@if errorlevel 1 goto quit +%cc% ../cg_main.c +@if errorlevel 1 goto quit +%cc% ../cg_marks.c +@if errorlevel 1 goto quit +%cc% ../cg_players.c +@if errorlevel 1 goto quit +%cc% ../cg_playerstate.c +@if errorlevel 1 goto quit +%cc% ../cg_predict.c +@if errorlevel 1 goto quit +%cc% ../cg_saga.c +@if errorlevel 1 goto quit +%cc% ../cg_scoreboard.c +@if errorlevel 1 goto quit +%cc% ../cg_servercmds.c +@if errorlevel 1 goto quit +%cc% ../cg_snapshot.c +@if errorlevel 1 goto quit +%cc% ../cg_turret.c +@if errorlevel 1 goto quit +%cc% ../cg_view.c +@if errorlevel 1 goto quit +%cc% ../cg_weaponinit.c +@if errorlevel 1 goto quit +%cc% ../cg_weapons.c +@if errorlevel 1 goto quit +%cc% ../fx_blaster.c +@if errorlevel 1 goto quit +%cc% ../fx_bowcaster.c +@if errorlevel 1 goto quit +%cc% ../fx_bryarpistol.c +@if errorlevel 1 goto quit +%cc% ../fx_demp2.c +@if errorlevel 1 goto quit +%cc% ../fx_disruptor.c +@if errorlevel 1 goto quit +%cc% ../fx_flechette.c +@if errorlevel 1 goto quit +%cc% ../fx_heavyrepeater.c +@if errorlevel 1 goto quit +%cc% ../fx_rocketlauncher.c +@if errorlevel 1 goto quit +%cc% ../fx_force.c +@if errorlevel 1 goto quit +%cc% ../../ui/ui_shared.c +@if errorlevel 1 goto quit +%cc% ../cg_newDraw.c +@if errorlevel 1 goto quit + +sysmaker ../cg_public.h ../cg_syscalls.c ../cg_syscalls.asm +@if errorlevel 1 goto quit + +q3asm -f ../cgame +@if errorlevel 1 goto quit + +mkdir "..\..\base\vm" +copy *.map "..\..\base\vm" +copy *.qvm "..\..\base\vm" + +:quit +cd .. diff --git a/CODE-mp/cgame/cgame.q3asm b/CODE-mp/cgame/cgame.q3asm new file mode 100644 index 0000000..a88d978 --- /dev/null +++ b/CODE-mp/cgame/cgame.q3asm @@ -0,0 +1,44 @@ +-o "cgame" +cg_main +..\cg_syscalls +cg_consolecmds +cg_draw +cg_drawtools +cg_effects +cg_ents +cg_event +cg_info +cg_light +cg_localents +cg_marks +cg_players +cg_playerstate +cg_predict +cg_saga +cg_scoreboard +cg_servercmds +cg_snapshot +cg_turret +cg_view +cg_weaponinit +cg_weapons +fx_blaster +fx_bowcaster +fx_bryarpistol +fx_demp2 +fx_disruptor +fx_flechette +fx_heavyrepeater +fx_rocketlauncher +fx_force +bg_slidemove +bg_weapons +bg_panimate +bg_pmove +bg_lib +bg_misc +bg_saber +q_math +q_shared +ui_shared +cg_newDraw diff --git a/CODE-mp/cgame/mssccprj.scc b/CODE-mp/cgame/mssccprj.scc new file mode 100644 index 0000000..eede0df --- /dev/null +++ b/CODE-mp/cgame/mssccprj.scc @@ -0,0 +1,5 @@ +SCC = This is a Source Code Control file + +[JK2_cgame.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\jk2sof2MP" +SCC_Project_Name = "$/General/code/cgame", UPCAAAAA diff --git a/CODE-mp/cgame/tr_types.h b/CODE-mp/cgame/tr_types.h index 67283eb..23f12e8 100644 --- a/CODE-mp/cgame/tr_types.h +++ b/CODE-mp/cgame/tr_types.h @@ -264,6 +264,12 @@ typedef enum { ** being run right now. These are constant once the OpenGL ** subsystem is initialized. */ +typedef enum { + TC_NONE, + TC_S3TC, + TC_S3TC_DXT +} textureCompression_t; + typedef struct { char renderer_string[MAX_STRING_CHARS]; char vendor_string[MAX_STRING_CHARS]; @@ -273,22 +279,10 @@ typedef struct { int maxTextureSize; // queried from GL int maxActiveTextures; // multitexture ability - int tfSolidCompressed; - float tfSolidCompressedBPT; - int tfAlphaCompressed; - float tfAlphaCompressedBPT; - int tfSolidUncompressed; - float tfSolidUncompressedBPT; - int tfAlphaUncompressed; - float tfAlphaUncompressedBPT; - int tfLightmap; - float tfLightmapBPT; - int tfCinematic; // Specially for the Voodoo4 - glTexImage2D can only handle 16 bit - float tfCinematicBPT; - int colorBits, depthBits, stencilBits; qboolean deviceSupportsGamma; + textureCompression_t textureCompression; qboolean textureEnvAddAvailable; qboolean textureFilterAnisotropicAvailable; qboolean clampToEdgeAvailable; diff --git a/CODE-mp/cgame/vssver.scc b/CODE-mp/cgame/vssver.scc new file mode 100644 index 0000000..db0bad1 Binary files /dev/null and b/CODE-mp/cgame/vssver.scc differ diff --git a/CODE-mp/client/0_SH_Leak.cpp b/CODE-mp/client/0_SH_Leak.cpp new file mode 100644 index 0000000..c169fd3 --- /dev/null +++ b/CODE-mp/client/0_SH_Leak.cpp @@ -0,0 +1,409 @@ +#pragma warning( disable : 4786) +#include "client.h" + +#include +#include "..\smartheap\smrtheap.h" +#if !defined(__Q_SHARED_H) + #include "../game/q_shared.h" +#endif +#if !defined(_QCOMMON_H_) + #include "../qcommon/qcommon.h" +#endif +#include +#include + +using namespace std; + +#if MEM_DEBUG +#include "..\smartheap\heapagnt.h" + +static const int maxStack=2048; +static int TotalMem; +static int TotalBlocks; +static int nStack; +static char StackNames[maxStack][256]; +static int StackSize[maxStack]; +static int StackCount[maxStack]; +static int StackCache[48]; +static int StackCacheAt=0; +static int CheckpointSize[1000]; +static int CheckpointCount[1000]; + +#define _FASTRPT_ + +cvar_t *mem_leakfile; +cvar_t *mem_leakreport; + +MEM_BOOL MEM_CALLBACK MyMemReporter2(MEM_ERROR_INFO *info) +{ + static char buffer[10000]; + if (!info->objectCreationInfo) + return 1; + info=info->objectCreationInfo; + int idx=info->checkpoint; + if (idx<0||idx>=1000) + { + idx=0; + } + CheckpointCount[idx]++; + CheckpointSize[idx]+=info->argSize; +//return 1; + dbgMemFormatCall(info,buffer,9999); + if (strstr(buffer,"ntdll")) + return 1; + if (strstr(buffer,"CLBCATQ")) + return 1; + int i; + TotalBlocks++; + if (TotalBlocks%1000==0) + { + char mess[1000]; + sprintf(mess,"%d blocks processed\n",TotalBlocks); + OutputDebugString(mess); + } + for (i=strlen(buffer);i>0;i--) + { + if (buffer[i]=='\n') + break; + } + if (!i) + return 1; + buffer[i]=0; + char *buf=buffer; + while (*buf) + { + if (*buf=='\n') + { + buf++; + break; + } + buf++; + } + char *start=0; + while (*buf) + { + while (*buf==' ') + buf++; + start=buf; + while (*buf!=0&&*buf!='\n') + buf++; + if (*start) + { + if (*buf) + { + *buf=0; + buf++; + } + if (strlen(start)>255) + start[255]=0; + if (strstr(start,"std::")) + { +// start=0; + continue; + } + if (strstr(start,"Malloc")) + { + start=0; + continue; + } + if (strstr(start,"FS_LoadFile")) + { + start=0; + continue; + } + if (strstr(start,"CopyString")) + { + start=0; + continue; + } + break; + } + } + if (!start||!*start) + { + start="UNKNOWN"; + } + + for (i=0;i<48;i++) + { + if (StackCache[i]<0||StackCache[i]>=nStack) + continue; + if (!strcmpi(start,StackNames[StackCache[i]])) + break; + } + if (i<48) + { + StackSize[StackCache[i]]+=info->argSize; + StackCount[StackCache[i]]++; + } + else + { + for (i=0;iargSize; + StackCount[i]++; + StackCache[StackCacheAt]=i; + StackCacheAt++; + if (StackCacheAt>=48) + StackCacheAt=0; + } + else if (iargSize; + StackCount[i]=1; + nStack++; + } + else if (nStackargSize; + StackCount[maxStack-1]=1; + } + else + { + StackSize[maxStack-1]+=info->argSize; + StackCount[maxStack-1]++; + } + } + TotalMem+=info->argSize; + return 1; +} + +void SH_Checking_f(void); +#endif + +class Leakage +{ + MEM_POOL MyPool; + +public: + Leakage() + { + MyPool = MemInitDefaultPool(); +// MemPoolSetSmallBlockSize(MyPool, 16); + MemPoolSetSmallBlockAllocator(MyPool,MEM_SMALL_BLOCK_SH3); +#if MEM_DEBUG + dbgMemSetGuardSize(2); +#endif + EnableChecking(100000); + } + + void LeakReport(void) + { +#if MEM_DEBUG + + int i; + char mess[1000]; + int blocks=dbgMemTotalCount(); + int mem=dbgMemTotalSize()/1024; + sprintf(mess,"Final Memory Summary %d blocks %d K\n",blocks,mem); + OutputDebugString(mess); + for (i=0;i<1000;i++) + { + CheckpointSize[i]=0; + CheckpointCount[i]=0; + } + + TotalMem=0; + TotalBlocks=0; + nStack=0; + MemSetErrorHandler(MyMemReporter2); + dbgMemReportLeakage(NULL,1,1000); + MemSetErrorHandler(MemDefaultErrorHandler); + if (TotalBlocks) + { + // Sort by size. + Sleep(100); + OutputDebugString("**************************************\n"); + OutputDebugString("**********Memory Leak Report**********\n"); + OutputDebugString("*************** By Size **************\n"); + OutputDebugString("**************************************\n"); + sprintf(mess,"Actual leakage %d blocks %d K\n",TotalBlocks,TotalMem/1024); + OutputDebugString(mess); + multimap > sortit; + for (i=0;i >(-StackSize[i],pair(StackCount[i],StackNames[i]))); + multimap >::iterator j; + Sleep(5); + for (j=sortit.begin();j!=sortit.end();j++) + { + sprintf(mess,"%5d KB %6d cnt %s\n",-(*j).first/1024,(*j).second.first,(*j).second.second); + // if (!(-(*j).first/1024)) + // break; + Sleep(5); + OutputDebugString(mess); + } + + // Sort by count. + Sleep(100); + OutputDebugString("**************************************\n"); + OutputDebugString("**********Memory Leak Report**********\n"); + OutputDebugString("************** By Count **************\n"); + OutputDebugString("**************************************\n"); + sprintf(mess,"Actual leakage %d blocks %d K\n",TotalBlocks,TotalMem/1024); + OutputDebugString(mess); + sortit.clear(); + for (i=0;i >(-StackCount[i],pair(StackSize[i],StackNames[i]))); + Sleep(5); + for (j=sortit.begin();j!=sortit.end();j++) + { + sprintf(mess,"%5d KB %6d cnt %s\n",(*j).second.first/1024,-(*j).first,(*j).second.second); + // if (!(-(*j).first/1024)) + // break; + Sleep(5); + OutputDebugString(mess); + } + } + else + { + OutputDebugString("No Memory Leaks\n"); + } + + // Sort by size. + Sleep(5); + OutputDebugString("***************************************\n"); + OutputDebugString("By Tag, sort: size ********************\n"); + OutputDebugString("size(K) count name \n"); + OutputDebugString("-----------------------\n"); + Sleep(5); + multimap sorted; + for (i=0;i<1000;i++) + { + if (CheckpointCount[i]) + { + sorted.insert(pair(-CheckpointSize[i],i)); + } + } + multimap::iterator k; + for (k=sorted.begin();k!=sorted.end();k++) + { +// sprintf(mess,"%8d %8d %s\n",CheckpointSize[(*k).second]/1024,CheckpointCount[(*k).second],(*k).second>=2?tagDefs[(*k).second-2]:"unknown"); + sprintf(mess,"%8d %8d %s\n",CheckpointSize[(*k).second]/1024,CheckpointCount[(*k).second],"unknown"); + Sleep(5); + OutputDebugString(mess); + } + + // Sort by count. + Sleep(5); + OutputDebugString("***************************************\n"); + OutputDebugString("By Tag, sort: count *******************\n"); + OutputDebugString("size(K) count name \n"); + OutputDebugString("-----------------------\n"); + Sleep(5); + sorted.clear(); + for (i=0;i<1000;i++) + { + if (CheckpointCount[i]) + { + sorted.insert(pair(-CheckpointCount[i],i)); + } + } + for (k=sorted.begin();k!=sorted.end();k++) + { +// sprintf(mess,"%8d %8d %s\n",CheckpointSize[(*k).second]/1024,CheckpointCount[(*k).second],(*k).second>=2?tagDefs[(*k).second-2]:"unknown"); + sprintf(mess,"%8d %8d %s\n",CheckpointSize[(*k).second]/1024,CheckpointCount[(*k).second],"unknown"); + Sleep(5); + OutputDebugString(mess); + } +#endif + } + + ~Leakage() + { +#if MEM_DEBUG +#if 0 + if (mem_leakfile && mem_leakfile->integer) + { + dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_FILE,"leakage.out"); + dbgMemReportLeakage(NULL,1,1); + dbgMemSetDefaultErrorOutput(DBGMEM_OUTPUT_PROMPT,NULL); + } +#endif + if (mem_leakreport && mem_leakreport->integer) + { + LeakReport(); + } +#endif + } +#if MEM_DEBUG + + void EnableChecking(int x) + { + if (x) + { + dbgMemSetSafetyLevel(MEM_SAFETY_DEBUG); + dbgMemPoolSetCheckFrequency(MyPool, x); + dbgMemSetCheckFrequency(x); + dbgMemDeferFreeing(TRUE); + if (x>50000) + { + dbgMemSetDeferQueueLen(x+5000); + } + else + { + dbgMemSetDeferQueueLen(50000); + } + } + else + { + dbgMemSetSafetyLevel(MEM_SAFETY_SOME); + dbgMemDeferFreeing(FALSE); + } + + } +#endif + +}; + +static Leakage TheLeakage; + +#if MEM_DEBUG + +void MEM_Checking_f(void) +{ + if (Cmd_Argc() != 2) + { + Com_Printf ("mem_checking \n"); + return; + } + + if (atol(Cmd_Argv(1)) > 0 && atol(Cmd_Argv(1)) < 100) + { + Com_Printf ("mem_checking frequency is too low ( < 100 )\n"); + return; + } + + TheLeakage.EnableChecking(atol(Cmd_Argv(1))); +} + +void MEM_Report_f(void) +{ + TheLeakage.LeakReport(); +} + +/* +void myexit(void) +{ + TheLeakage.LeakReport(); +} +*/ + +void SH_Register(void) +{ + Cmd_AddCommand ("mem_checking", MEM_Checking_f); + Cmd_AddCommand ("mem_report", MEM_Report_f); + + mem_leakfile = Cvar_Get( "mem_leakfile", "1", 0 ); + mem_leakreport = Cvar_Get( "mem_leakreport", "1", 0 ); +// atexit(myexit); +} + +#endif diff --git a/CODE-mp/client/FXExport.cpp b/CODE-mp/client/FXExport.cpp index 0d28190..d9bd5ee 100644 --- a/CODE-mp/client/FXExport.cpp +++ b/CODE-mp/client/FXExport.cpp @@ -71,8 +71,8 @@ qboolean FX_FreeSystem( void ) return (qboolean)FX_Free(); } -void FX_AdjustTime( int time ) +void FX_AdjustTime_Pos( int time, vec3_t refdef_vieworg, vec3_t refdef_viewaxis[3] ) { - theFxHelper.AdjustTime(time); + theFxHelper.AdjustTime_Pos( time, refdef_vieworg, refdef_viewaxis ); } diff --git a/CODE-mp/client/FXExport.h b/CODE-mp/client/FXExport.h index 688feeb..131e120 100644 --- a/CODE-mp/client/FXExport.h +++ b/CODE-mp/client/FXExport.h @@ -18,7 +18,7 @@ void FX_AddScheduledEffects( void ); int FX_InitSystem( void ); // called in CG_Init to purge the fx system. qboolean FX_FreeSystem( void ); // ditches all active effects; -void FX_AdjustTime( int time ); +void FX_AdjustTime_Pos( int time, vec3_t refdef_vieworg, vec3_t refdef_viewaxis[3] ); #endif // FX_EXPORT_H_INC diff --git a/CODE-mp/client/FxPrimitives.cpp b/CODE-mp/client/FxPrimitives.cpp index 3815abc..589ec09 100644 --- a/CODE-mp/client/FxPrimitives.cpp +++ b/CODE-mp/client/FxPrimitives.cpp @@ -8,6 +8,8 @@ #include "FxScheduler.h" #endif +#include + void FX_AddPrimitive( CEffect **pEffect, CCloud *effectCloud, int killTime ); // Helper function @@ -90,8 +92,11 @@ CCloud::CCloud() : //mRefEnt.reType = RT_ENT_CHAIN; } +extern set OutstandClouds; + CCloud::~CCloud() { + OutstandClouds.erase(this); Die(); } @@ -326,7 +331,7 @@ bool CParticle::Cull() float len = VectorLengthSquared( dir ); // Can't be too close - if ( len < 24 * 24 ) + if ( len < 12 * 12 ) { return true; } @@ -846,7 +851,7 @@ bool COrientedParticle::Cull() float len = VectorLengthSquared( dir ); // Can't be too close - if ( len < 24 * 24 ) + if ( len < 16 * 16 ) { return true; } diff --git a/CODE-mp/client/FxScheduler.cpp b/CODE-mp/client/FxScheduler.cpp index 1577e4b..b8cc7ea 100644 --- a/CODE-mp/client/FxScheduler.cpp +++ b/CODE-mp/client/FxScheduler.cpp @@ -24,6 +24,9 @@ #include "../game/q_shared.h" #endif +#include +extern set OutstandClouds; + #endif // EFFECTSED @@ -96,7 +99,7 @@ void CFxScheduler::Clean(bool bRemoveTemplates /*= true*/, int idToPreserve /*= next = itr; next++; - if ((*itr)->mParent) + if ((*itr)->mParent&&OutstandClouds.find((*itr)->mParent)!=OutstandClouds.end()) { (*itr)->mParent->DecreasePending(); } @@ -704,10 +707,14 @@ int CFxScheduler::ParseEffect( const char *file, CGPGroup *base ) { type = CameraShake; } +/* + // NOTE: Pat requested that flashes be disabled in MP. Since fx files are shared with SP, this is the easiest way to accomplish that.... + // code will fall through and become type NONE....and therefore not parsed and added to the effect definition. else if ( !stricmp( grpName, "flash" )) { type = ScreenFlash; } +*/ else { type = None; @@ -1028,6 +1035,8 @@ int totalEffects = 0; // Return: // none //------------------------------------------------------ +extern cvar_t *cl_autolodscale; +extern int gCLTotalClientNum; void CFxScheduler::PlayEffect( int id, CFxBoltInterface *obj ) { SEffectTemplate *fx; @@ -1082,6 +1091,8 @@ void CFxScheduler::PlayEffect( int id, CFxBoltInterface *obj ) effectCloud = FX_AddCloud(); + float cullRange, effectDistSq = DistanceSquared( origin, theFxHelper.refdef.vieworg ); + // Loop through the primitives and schedule each bit for ( i = 0; i < fx->mPrimitiveCount; i++ ) { @@ -1095,6 +1106,23 @@ void CFxScheduler::PlayEffect( int id, CFxBoltInterface *obj ) } #endif + if ( prim->mCullRange ) + { + cullRange = prim->mCullRange; + if ( cl_autolodscale->integer ) + { + if ( gCLTotalClientNum >= 8 ) + { + cullRange *= 8.0f/gCLTotalClientNum; + } + } + if ( effectDistSq > cullRange ) // cull range has already been squared + { + // is too far away, so don't add this primitive group + continue; + } + } + count = prim->mSpawnCount.GetRoundedVal(); if ( prim->mCopy ) @@ -1571,6 +1599,8 @@ void CFxScheduler::PlayEffect( int id, vec3_t origin, vec3_t axis[3], const int effectCloud = FX_AddCloud(); + float cullRange, effectDistSq = DistanceSquared( origin, theFxHelper.refdef.vieworg ); + // Loop through the primitives and schedule each bit for ( i = 0; i < fx->mPrimitiveCount; i++ ) { @@ -1584,6 +1614,23 @@ void CFxScheduler::PlayEffect( int id, vec3_t origin, vec3_t axis[3], const int } #endif + if ( prim->mCullRange ) + { + cullRange = prim->mCullRange; + if ( cl_autolodscale->integer ) + { + if ( gCLTotalClientNum >= 8 ) + { + cullRange *= 8.0f/gCLTotalClientNum; + } + } + if ( effectDistSq > cullRange ) // cull range has already been squared + { + // is too far away, so don't add this primitive group + continue; + } + } + count = prim->mSpawnCount.GetRoundedVal(); if ( prim->mCopy ) @@ -1762,10 +1809,71 @@ void CFxScheduler::PlayEffect( const char *file, vec3_t origin, vec3_t forward ) // Return: // none //------------------------------------------------------ + +#if _JK2 +#define CHC + void CFxScheduler::AddScheduledEffects( void ) { TScheduledEffect::iterator itr, next; SScheduledEffect *schedEffect = 0; + + itr = mFxSchedule.begin(); + + while ( itr != mFxSchedule.end() ) + { + next = itr; + next++; + schedEffect = (*itr); + if ( *(*itr) <= theFxHelper.mTime ) + { + if ((*itr)->mParent && OutstandClouds.find((*itr)->mParent)!=OutstandClouds.end()) + { + // ok, are we spawning a bolt on effect or a normal one? + if ( (*itr)->mEntNum != -1 ) + { + // Find out where the entity currently is + vec3_t lerpOrigin; + +// VM_Call( cgvm, CG_GET_LERP_ORIGIN, (*itr)->mEntNum, lerpOrigin); + TCGVectorData *data = (TCGVectorData*)cl.mSharedMemory; + data->mEntityNum = (*itr)->mEntNum; + VM_Call( cgvm, CG_GET_LERP_ORIGIN ); + VectorCopy(data->mPoint, lerpOrigin); + + CreateEffect( (*itr)->mpTemplate, + lerpOrigin, (*itr)->mAxis, + theFxHelper.mTime - (*itr)->mStartTime, (*itr)->mParent ); + } + else + { + CreateEffect( (*itr)->mpTemplate, + (*itr)->mOrigin, (*itr)->mAxis, + theFxHelper.mTime - (*itr)->mStartTime, (*itr)->mParent ); + } + // Get 'em out of there. + if ((*itr)->mParent&&OutstandClouds.find((*itr)->mParent)!=OutstandClouds.end()) + { + (*itr)->mParent->DecreasePending(); + } + } + delete *itr; + mFxSchedule.erase(itr); + } + + itr = next; + } + // Add all active effects into the scene + FX_Add(); +} + +#else + +void CFxScheduler::AddScheduledEffects( void ) +{ + + TScheduledEffect::iterator itr, next; + SScheduledEffect *schedEffect = 0; #ifndef EFFECTSED vec3_t origin; vec3_t axis[3]; @@ -1792,7 +1900,7 @@ void CFxScheduler::AddScheduledEffects( void ) theFxHelper.mTime - (*itr)->mStartTime, (*itr)->mParent ); } else -#endif +#endif // CHC /*if ((*itr)->mBoltNum == -1)*/ if (1) {// ok, are we spawning a bolt on effect or a normal one? @@ -1813,7 +1921,7 @@ void CFxScheduler::AddScheduledEffects( void ) } else { -#endif +#endif // EFFECTSED CreateEffect( (*itr)->mpTemplate, (*itr)->mOrigin, (*itr)->mAxis, theFxHelper.mTime - (*itr)->mStartTime, (*itr)->mParent ); @@ -1907,6 +2015,8 @@ void CFxScheduler::AddScheduledEffects( void ) FX_Add(); } +#endif // #if1 + //------------------------------------------------------ // CreateEffect // Creates the specified fx taking into account the @@ -1930,7 +2040,6 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a trace_t tr; int emitterModel; CFxBoltInterface *fxBoltInterface = NULL; - VectorCopy(origin, origin_certain); if (effectCloud->IsBoltInterfaceValid()) @@ -2149,7 +2258,6 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a VectorSet( eRGB, fx->mRedEnd.GetVal(), fx->mGreenEnd.GetVal(), fx->mBlueEnd.GetVal() ); } } - // Now create the appropriate effect entity //------------------------ switch( fx->mType ) @@ -2157,7 +2265,6 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a //--------- case Particle: //--------- - FX_AddParticle( effectCloud, org, vel, accel, fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), fx->mAlphaStart.GetVal(), fx->mAlphaEnd.GetVal(), fx->mAlphaParm.GetVal(), @@ -2171,7 +2278,6 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a //--------- case Line: //--------- - FX_AddLine( effectCloud, org, org2, fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), fx->mAlphaStart.GetVal(), fx->mAlphaEnd.GetVal(), fx->mAlphaParm.GetVal(), @@ -2182,7 +2288,6 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a //--------- case Tail: //--------- - FX_AddTail( effectCloud, org, vel, accel, fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), fx->mLengthStart.GetVal(), fx->mLengthEnd.GetVal(), fx->mLengthParm.GetVal(), @@ -2196,7 +2301,6 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a //---------------- case Electricity: //---------------- - FX_AddElectricity( effectCloud, org, org2, fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), fx->mAlphaStart.GetVal(), fx->mAlphaEnd.GetVal(), fx->mAlphaParm.GetVal(), @@ -2207,7 +2311,6 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a //--------- case Cylinder: //--------- - FX_AddCylinder( effectCloud, org, ax[0], fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), fx->mSize2Start.GetVal(), fx->mSize2End.GetVal(), fx->mSize2Parm.GetVal(), @@ -2220,7 +2323,6 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a //--------- case Emitter: //--------- - // for chunk angles, you don't really need much control over the end result...you just want variation.. VectorSet( ang, fx->mAngle1.GetVal(), @@ -2259,7 +2361,6 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a /*CG_ImpactMark( fx->mMediaHandles.GetHandle(), org, ax[0], fx->mRotation.GetVal(), sRGB[0], sRGB[1], sRGB[2], fx->mAlphaStart.GetVal(), qtrue, fx->mSizeStart.GetVal(), qfalse );*/ - //VM_Call(cgvm, CG_IMPACT_MARK, fx->mMediaHandles.GetHandle(), org, ax[0], (int)fx->mRotation.GetVal(), // (int)sRGB[0], (int)sRGB[1], (int)sRGB[2], (int)fx->mAlphaStart.GetVal(), (int)fx->mSizeStart.GetVal()); TCGImpactMark *data = (TCGImpactMark *)cl.mSharedMemory; @@ -2280,7 +2381,6 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a //------------------- case OrientedParticle: //------------------- - FX_AddOrientedParticle( effectCloud, org, ax[0], vel, accel, fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), fx->mAlphaStart.GetVal(), fx->mAlphaEnd.GetVal(), fx->mAlphaParm.GetVal(), @@ -2294,21 +2394,18 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a //--------- case Sound: //--------- - theFxHelper.PlaySound( org, ENTITYNUM_NONE, CHAN_AUTO, fx->mMediaHandles.GetHandle() ); break; //--------- case FxRunner: //--------- - PlayEffect( fx->mPlayFxHandles.GetHandle(), org, ax ); break; //--------- case Light: //--------- - FX_AddLight( effectCloud, org, fx->mSizeStart.GetVal(), fx->mSizeEnd.GetVal(), fx->mSizeParm.GetVal(), sRGB, eRGB, fx->mRGBParm.GetVal(), fx->mLife.GetVal(), fx->mFlags ); @@ -2326,7 +2423,6 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, vec3_t origin, vec3_t a //-------------- case ScreenFlash: //-------------- - FX_AddFlash( effectCloud, org, sRGB, eRGB, fx->mRGBParm.GetVal(), fx->mLife.GetVal(), fx->mMediaHandles.GetHandle(), fx->mFlags ); diff --git a/CODE-mp/client/FxScheduler.h b/CODE-mp/client/FxScheduler.h index 2936854..42f64c5 100644 --- a/CODE-mp/client/FxScheduler.h +++ b/CODE-mp/client/FxScheduler.h @@ -204,6 +204,7 @@ public: CFxRange mSpawnDelay; CFxRange mSpawnCount; CFxRange mLife; + int mCullRange; CMediaHandles mMediaHandles; CMediaHandles mImpactFxHandles; diff --git a/CODE-mp/client/FxSystem.cpp b/CODE-mp/client/FxSystem.cpp index 40a3c22..a5f55a0 100644 --- a/CODE-mp/client/FxSystem.cpp +++ b/CODE-mp/client/FxSystem.cpp @@ -45,7 +45,7 @@ void SFxHelper::Print( const char *msg, ... ) } //------------------------------------------------------ -void SFxHelper::AdjustTime( int time ) +void SFxHelper::AdjustTime_Pos( int time, vec3_t refdef_vieworg, vec3_t refdef_viewaxis[3] ) { if ( fx_freeze.integer ) { @@ -53,6 +53,10 @@ void SFxHelper::AdjustTime( int time ) } else { + VectorCopy( refdef_vieworg, refdef.vieworg ); + VectorCopy( refdef_viewaxis[0], refdef.viewaxis[0] ); + VectorCopy( refdef_viewaxis[1], refdef.viewaxis[1] ); + VectorCopy( refdef_viewaxis[2], refdef.viewaxis[2] ); mOldTime = mTime; mTime = time; mFrameTime = mTime - mOldTime; diff --git a/CODE-mp/client/FxSystem.h b/CODE-mp/client/FxSystem.h index dccfa1f..09768fa 100644 --- a/CODE-mp/client/FxSystem.h +++ b/CODE-mp/client/FxSystem.h @@ -69,7 +69,7 @@ public: inline int GetFrameTime(void) { return mFrameTime; } void ReInit(void); - void AdjustTime( int time ); + void AdjustTime_Pos( int time, vec3_t refdef_vieworg, vec3_t refdef_viewaxis[3] ); // These functions are wrapped and used by the fx system in case it makes things a bit more portable void Print( const char *msg, ... ); diff --git a/CODE-mp/client/FxTemplate.cpp b/CODE-mp/client/FxTemplate.cpp index ae17ecb..566e47e 100644 --- a/CODE-mp/client/FxTemplate.cpp +++ b/CODE-mp/client/FxTemplate.cpp @@ -27,6 +27,7 @@ CPrimitiveTemplate::CPrimitiveTemplate() mFlags = mSpawnFlags = 0; mLife.SetRange( 1.0f, 1.0f ); + mCullRange = 0; mSpawnCount.SetRange( 1.0f, 1.0f ); mRadius.SetRange( 1.0f, 1.0f ); mHeight.SetRange( 1.0f, 1.0f ); @@ -77,6 +78,7 @@ void CPrimitiveTemplate::operator=(const CPrimitiveTemplate &that) mSpawnDelay = that.mSpawnDelay; mSpawnCount = that.mSpawnCount; mLife = that.mLife; + mCullRange = that.mCullRange; mMediaHandles = that.mMediaHandles; mImpactFxHandles = that.mImpactFxHandles; @@ -2197,6 +2199,11 @@ bool CPrimitiveTemplate::ParsePrimitive( CGPGroup *grp ) { ParseLife( val ); } + else if ( !stricmp( key, "cullrange" )) + { + mCullRange = atoi( val ); + mCullRange *= mCullRange; // Square + } else if ( !stricmp( key, "delay" )) { ParseDelay( val ); diff --git a/CODE-mp/client/FxUtil.cpp b/CODE-mp/client/FxUtil.cpp index c6deccd..3848b8e 100644 --- a/CODE-mp/client/FxUtil.cpp +++ b/CODE-mp/client/FxUtil.cpp @@ -1,5 +1,5 @@ #include "client.h" - +//#include "..\smartheap\smrtheap.h" #if !defined(FX_SCHEDULER_H_INC) #include "FxScheduler.h" #endif @@ -8,6 +8,10 @@ #include "../EffectsCoreInterface.h" #endif +#include + +set OutstandClouds; + vec3_t WHITE = {1.0f, 1.0f, 1.0f}; struct SEffectList @@ -275,8 +279,6 @@ void FX_AddPrimitive( CEffect **pEffect, CCloud *effectCloud, int killTime ) if (!effectCloud) { SEffectList *item = FX_GetValidEffect(); - - #ifdef EFFECTSED if (item == NULL) { @@ -290,9 +292,24 @@ void FX_AddPrimitive( CEffect **pEffect, CCloud *effectCloud, int killTime ) } else { - effectCloud->AddEffect(*pEffect); +/* dbgMemCheckAll(); + DBGMEM_PTR_INFO dbg1; + if(dbgMemPtrInfo((void *)effectCloud,&dbg1)) + { + assert(dbg1.isInUse); + } + DBGMEM_PTR_INFO dbg2; + if(dbgMemPtrInfo((void *)*pEffect,&dbg2)) + { + assert(dbg2.isInUse); + } +*/ + if (effectCloud&&OutstandClouds.find(effectCloud)!=OutstandClouds.end()) + { + effectCloud->AddEffect(*pEffect); + } +// dbgMemCheckAll(); } - (*pEffect)->SetKillTime(theFxHelper.mTime + killTime); activeFx++; @@ -301,12 +318,12 @@ void FX_AddPrimitive( CEffect **pEffect, CCloud *effectCloud, int killTime ) (*pEffect)->SetTimeEnd( theFxHelper.mTime + killTime ); } - CCloud *FX_AddCloud(void) { CCloud *cloud; cloud = new CCloud; + OutstandClouds.insert(cloud); FX_AddPrimitive((CEffect **)&cloud, 0, 99999); return cloud; diff --git a/CODE-mp/client/cl_cgame.cpp b/CODE-mp/client/cl_cgame.cpp index c01446c..ad01854 100644 --- a/CODE-mp/client/cl_cgame.cpp +++ b/CODE-mp/client/cl_cgame.cpp @@ -14,6 +14,10 @@ #include "../qcommon/ROFFSystem.h" #endif +#ifdef _DONETPROFILE_ +#include "../qcommon/INetProfile.h" +#endif + /* Ghoul2 Insert Start */ @@ -220,6 +224,24 @@ void CL_CgameError( const char *string ) { } +int gCLTotalClientNum = 0; +//keep track of the total number of clients +extern cvar_t *cl_autolodscale; +//if we want to do autolodscaling + +void CL_DoAutoLODScale(void) +{ + float finalLODScaleFactor = 0; + + if ( gCLTotalClientNum >= 8 ) + { + finalLODScaleFactor = (gCLTotalClientNum/-8.0f); + } + + + Cvar_Set( "r_autolodscalevalue", va("%f", finalLODScaleFactor) ); +} + /* ===================== CL_ConfigstringModified @@ -274,6 +296,36 @@ void CL_ConfigstringModified( void ) { cl.gameState.dataCount += len + 1; } + if (cl_autolodscale && cl_autolodscale->integer) + { + if (index >= CS_PLAYERS && + index < CS_CHARSKINS) + { //this means that a client was updated in some way. Go through and count the clients. + int clientCount = 0; + i = CS_PLAYERS; + + while (i < CS_CHARSKINS) + { + s = cl.gameState.stringData + cl.gameState.stringOffsets[ i ]; + + if (s && s[0]) + { + clientCount++; + } + + i++; + } + + gCLTotalClientNum = clientCount; + +#ifdef _DEBUG + Com_DPrintf("%i clients\n", gCLTotalClientNum); +#endif + + CL_DoAutoLODScale(); + } + } + if ( index == CS_SYSTEMINFO ) { // parse serverId and other cvars CL_SystemInfoChanged(); @@ -319,7 +371,7 @@ rescan: cmd = Cmd_Argv(0); if ( !strcmp( cmd, "disconnect" ) ) { - Com_Error (ERR_SERVERDISCONNECT,"Server disconnected\n"); + Com_Error (ERR_SERVERDISCONNECT, SP_GetStringTextString("SVINGAME_SERVER_DISCONNECTED"));//"Server disconnected\n"); } if ( !strcmp( cmd, "bcs0" ) ) { @@ -416,6 +468,9 @@ void CL_ShutdownCGame( void ) { VM_Call( cgvm, CG_SHUTDOWN ); VM_Free( cgvm ); cgvm = NULL; +#ifdef _DONETPROFILE_ + ClReadProf().ShowTotals(); +#endif } static int FloatAsInt( float f ) { @@ -435,6 +490,7 @@ The cgame module is making a system call */ #define VMA(x) VM_ArgPtr(args[x]) #define VMF(x) ((float *)args)[x] +extern bool RicksCrazyOnServer; int CL_CgameSystemCalls( int *args ) { switch( args[0] ) { case CG_PRINT: @@ -814,7 +870,7 @@ int CL_CgameSystemCalls( int *args ) { return FX_FreeSystem(); case CG_FX_ADJUST_TIME: - FX_AdjustTime(args[1]); + FX_AdjustTime_Pos(args[1],(float *)VMA(2),(vec3_t *)VMA(3)); return 0; case CG_FX_ADDPOLY: @@ -939,6 +995,7 @@ Ghoul2 Insert Start return G2API_GetBoltMatrix(*((CGhoul2Info_v *)args[1]), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); case CG_G2_INITGHOUL2MODEL: + RicksCrazyOnServer=false; return G2API_InitGhoul2Model((CGhoul2Info_v **)VMA(1), (const char *)VMA(2), args[3], (qhandle_t) args[4], (qhandle_t) args[5], args[6], args[7]); @@ -1047,8 +1104,7 @@ Ghoul2 Insert End break; case CG_SP_REGISTER: - SP_Register((const char *)VMA(1),SP_REGISTER_CLIENT); - return 0; + return !!SP_Register((const char *)VMA(1),SP_REGISTER_CLIENT); case CG_SET_SHARED_BUFFER: cl.mSharedMemory = ((char *)VMA(1)); @@ -1117,12 +1173,16 @@ void CL_InitCGame( void ) { re.EndRegistration(); // make sure everything is paged in - if (!Sys_LowPhysicalMemory()) { +// if (!Sys_LowPhysicalMemory()) + { Com_TouchMemory(); } // clear anything that got printed Con_ClearNotify (); +#ifdef _DONETPROFILE_ + ClReadProf().Reset(); +#endif } diff --git a/CODE-mp/client/cl_cin.cpp b/CODE-mp/client/cl_cin.cpp index af15cee..7877dc5 100644 --- a/CODE-mp/client/cl_cin.cpp +++ b/CODE-mp/client/cl_cin.cpp @@ -144,8 +144,6 @@ static int CIN_HandleForVideo(void) { } -extern int CL_ScaledMilliseconds(void); - //----------------------------------------------------------------------------- // RllSetupTable // @@ -594,27 +592,6 @@ static void ROQ_GenYUVTables( void ) *d++ = *b; \ a++; b++; } -/****************************************************************************** -* -* Function: -* -* Description: -* -******************************************************************************/ - -static unsigned short yuv_to_rgb( long y, long u, long v ) -{ - long r,g,b,YY = (long)(ROQ_YY_tab[(y)]); - - r = (YY + ROQ_VR_tab[v]) >> 9; - g = (YY + ROQ_UG_tab[u] + ROQ_VG_tab[v]) >> 8; - b = (YY + ROQ_UB_tab[u]) >> 9; - - if (r<0) r = 0; if (g<0) g = 0; if (b<0) b = 0; - if (r > 31) r = 31; if (g > 63) g = 63; if (b > 31) b = 31; - - return (unsigned short)((r<<11)+(g<<5)+(b)); -} /****************************************************************************** * @@ -990,7 +967,7 @@ redump: case ZA_SOUND_MONO: if (!cinTable[currentHandle].silent) { ssize = RllDecodeMonoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags); - S_RawSamples( ssize, 22050, 2, 1, (byte *)sbuf, 1.0f ); + S_RawSamples( ssize, 22050, 2, 1, (byte *)sbuf, s_volume->value ); } break; case ZA_SOUND_STEREO: @@ -1000,15 +977,14 @@ redump: s_rawend = s_soundtime; } ssize = RllDecodeStereoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags); - S_RawSamples( ssize, 22050, 2, 2, (byte *)sbuf, 1.0f ); + S_RawSamples( ssize, 22050, 2, 2, (byte *)sbuf, s_volume->value ); } break; case ROQ_QUAD_INFO: if (cinTable[currentHandle].numQuads == -1) { readQuadInfo( framedata ); setupQuad( 0, 0 ); - // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer - cinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = CL_ScaledMilliseconds()*com_timescale->value; + cinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = Sys_Milliseconds()*com_timescale->value; } if (cinTable[currentHandle].numQuads != 1) cinTable[currentHandle].numQuads = 0; break; @@ -1080,8 +1056,7 @@ redump: static void RoQ_init( void ) { - // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer - cinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = CL_ScaledMilliseconds()*com_timescale->value; + cinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = Sys_Milliseconds()*com_timescale->value; cinTable[currentHandle].RoQPlayed = 24; @@ -1213,13 +1188,11 @@ e_status CIN_RunCinematic (int handle) return cinTable[currentHandle].status; } - // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer - thisTime = CL_ScaledMilliseconds()*com_timescale->value; + thisTime = Sys_Milliseconds()*com_timescale->value; if (cinTable[currentHandle].shader && (abs(thisTime - cinTable[currentHandle].lastTime))>100) { cinTable[currentHandle].startTime += thisTime - cinTable[currentHandle].lastTime; } - // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer - cinTable[currentHandle].tfps = ((((CL_ScaledMilliseconds()*com_timescale->value) - cinTable[currentHandle].startTime)*3)/100); + cinTable[currentHandle].tfps = ((((Sys_Milliseconds()*com_timescale->value) - cinTable[currentHandle].startTime)*cinTable[currentHandle].roqFPS)/1000); start = cinTable[currentHandle].startTime; while( (cinTable[currentHandle].tfps != cinTable[currentHandle].numQuads) @@ -1227,9 +1200,8 @@ e_status CIN_RunCinematic (int handle) { RoQInterrupt(); if (start != cinTable[currentHandle].startTime) { - // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer - cinTable[currentHandle].tfps = ((((CL_ScaledMilliseconds()*com_timescale->value) - - cinTable[currentHandle].startTime)*3)/100); + cinTable[currentHandle].tfps = ((((Sys_Milliseconds()*com_timescale->value) + - cinTable[currentHandle].startTime)*cinTable[currentHandle].roqFPS)/1000); start = cinTable[currentHandle].startTime; } } @@ -1288,7 +1260,7 @@ int CIN_PlayCinematic( const char *arg, int x, int y, int w, int h, int systemBi cinTable[currentHandle].ROQSize = FS_FOpenFileRead (cinTable[currentHandle].fileName, &cinTable[currentHandle].iFile, qtrue); if (cinTable[currentHandle].ROQSize<=0) { - Com_Printf("cinematic failed to open %s\n", arg); + Com_DPrintf("cinematic failed to open %s\n", arg); cinTable[currentHandle].fileName[0] = 0; return -1; } diff --git a/CODE-mp/client/cl_console.cpp b/CODE-mp/client/cl_console.cpp index dd743eb..b83bf57 100644 --- a/CODE-mp/client/cl_console.cpp +++ b/CODE-mp/client/cl_console.cpp @@ -3,13 +3,11 @@ #include "client.h" #include "..\strings\con_text.h" #include "..\qcommon\strip.h" +#include "../qcommon/game_version.h" int g_console_field_width = 78; - -extern console_t con; - console_t con; cvar_t *con_conspeed; @@ -44,7 +42,7 @@ void Con_ToggleConsole_f (void) { Con_MessageMode_f ================ */ -void Con_MessageMode_f (void) { +void Con_MessageMode_f (void) { //yell chat_playerNum = -1; chat_team = qfalse; Field_Clear( &chatField ); @@ -58,7 +56,7 @@ void Con_MessageMode_f (void) { Con_MessageMode2_f ================ */ -void Con_MessageMode2_f (void) { +void Con_MessageMode2_f (void) { //team chat chat_playerNum = -1; chat_team = qtrue; Field_Clear( &chatField ); @@ -71,7 +69,7 @@ void Con_MessageMode2_f (void) { Con_MessageMode3_f ================ */ -void Con_MessageMode3_f (void) { +void Con_MessageMode3_f (void) { //target chat chat_playerNum = VM_Call( cgvm, CG_CROSSHAIR_PLAYER ); if ( chat_playerNum < 0 || chat_playerNum >= MAX_CLIENTS ) { chat_playerNum = -1; @@ -88,7 +86,7 @@ void Con_MessageMode3_f (void) { Con_MessageMode4_f ================ */ -void Con_MessageMode4_f (void) { +void Con_MessageMode4_f (void) { //attacker chat_playerNum = VM_Call( cgvm, CG_LAST_ATTACKER ); if ( chat_playerNum < 0 || chat_playerNum >= MAX_CLIENTS ) { chat_playerNum = -1; @@ -132,7 +130,7 @@ void Con_Dump_f (void) if (Cmd_Argc() != 2) { - Com_Printf(SP_GetStringText(CON_TEXT_DUMP_USAGE)); + Com_Printf (SP_GetStringText(CON_TEXT_DUMP_USAGE)); return; } @@ -141,7 +139,7 @@ void Con_Dump_f (void) f = FS_FOpenFileWrite( Cmd_Argv( 1 ) ); if (!f) { - Com_Printf ("ERROR: couldn't open.\n"); + Com_Printf (S_COLOR_RED"ERROR: couldn't open.\n"); return; } @@ -205,22 +203,31 @@ void Con_CheckResize (void) int i, j, width, oldwidth, oldtotallines, numlines, numchars; MAC_STATIC short tbuf[CON_TEXTSIZE]; - width = (SCREEN_WIDTH / SMALLCHAR_WIDTH) - 2; +// width = (SCREEN_WIDTH / SMALLCHAR_WIDTH) - 2; + width = (cls.glconfig.vidWidth / SMALLCHAR_WIDTH) - 2; if (width == con.linewidth) return; + if (width < 1) // video hasn't been initialized yet { + con.xadjust = 1; + con.yadjust = 1; width = DEFAULT_CONSOLE_WIDTH; con.linewidth = width; con.totallines = CON_TEXTSIZE / con.linewidth; for(i=0; i cls.glconfig.vidHeight ) lines = cls.glconfig.vidHeight; - // on wide screens, we will center the text - con.xadjust = 640.0f / cls.glconfig.vidWidth; - con.yadjust = 480.0f / cls.glconfig.vidHeight; - // draw the background y = (int) (frac * SCREEN_HEIGHT - 2); if ( y < 1 ) { diff --git a/CODE-mp/client/cl_input.cpp b/CODE-mp/client/cl_input.cpp index 46ae2d6..6a02598 100644 --- a/CODE-mp/client/cl_input.cpp +++ b/CODE-mp/client/cl_input.cpp @@ -418,7 +418,7 @@ void CL_KeyMove( usercmd_t *cmd ) { cmd->buttons &= ~BUTTON_WALKING; } else { cmd->buttons |= BUTTON_WALKING; - movespeed = 32; + movespeed = 46; } forward = 0; diff --git a/CODE-mp/client/cl_keys.cpp b/CODE-mp/client/cl_keys.cpp index 68def1b..1e69b06 100644 --- a/CODE-mp/client/cl_keys.cpp +++ b/CODE-mp/client/cl_keys.cpp @@ -1,5 +1,5 @@ #include "client.h" - +#include "../qcommon/strip.h" /* key up events are sent even if in console mode @@ -158,6 +158,381 @@ keyname_t keynames[] = {NULL,0} }; +//english printed keynames, for when we want what's printed to be different +//from the "technical" bind label +keyname_t keynames_e[] = +{ + {"TAB", K_TAB}, + {"ENTER", K_ENTER}, + {"ESCAPE", K_ESCAPE}, + {"SPACE", K_SPACE}, + {"BACKSPACE", K_BACKSPACE}, + {"UP", K_UPARROW}, + {"DOWN", K_DOWNARROW}, + {"LEFT", K_LEFTARROW}, + {"RIGHT", K_RIGHTARROW}, + + {"ALT", K_ALT}, + {"CTRL", K_CTRL}, + {"SHIFT", K_SHIFT}, + + {"COMMAND", K_COMMAND}, + + {"CAPSLOCK", K_CAPSLOCK}, + + + {"F1", K_F1}, + {"F2", K_F2}, + {"F3", K_F3}, + {"F4", K_F4}, + {"F5", K_F5}, + {"F6", K_F6}, + {"F7", K_F7}, + {"F8", K_F8}, + {"F9", K_F9}, + {"F10", K_F10}, + {"F11", K_F11}, + {"F12", K_F12}, + + {"INS", K_INS}, + {"DEL", K_DEL}, + {"PGDN", K_PGDN}, + {"PGUP", K_PGUP}, + {"HOME", K_HOME}, + {"END", K_END}, + + {"MOUSE1", K_MOUSE1}, + {"MOUSE2", K_MOUSE2}, + {"MOUSE3", K_MOUSE3}, + {"MOUSE4", K_MOUSE4}, + {"MOUSE5", K_MOUSE5}, + + {"MWHEELUP", K_MWHEELUP }, + {"MWHEELDOWN", K_MWHEELDOWN }, + + {"JOY1", K_JOY1}, + {"JOY2", K_JOY2}, + {"JOY3", K_JOY3}, + {"JOY4", K_JOY4}, + {"JOY5", K_JOY5}, + {"JOY6", K_JOY6}, + {"JOY7", K_JOY7}, + {"JOY8", K_JOY8}, + {"JOY9", K_JOY9}, + {"JOY10", K_JOY10}, + {"JOY11", K_JOY11}, + {"JOY12", K_JOY12}, + {"JOY13", K_JOY13}, + {"JOY14", K_JOY14}, + {"JOY15", K_JOY15}, + {"JOY16", K_JOY16}, + {"JOY17", K_JOY17}, + {"JOY18", K_JOY18}, + {"JOY19", K_JOY19}, + {"JOY20", K_JOY20}, + {"JOY21", K_JOY21}, + {"JOY22", K_JOY22}, + {"JOY23", K_JOY23}, + {"JOY24", K_JOY24}, + {"JOY25", K_JOY25}, + {"JOY26", K_JOY26}, + {"JOY27", K_JOY27}, + {"JOY28", K_JOY28}, + {"JOY29", K_JOY29}, + {"JOY30", K_JOY30}, + {"JOY31", K_JOY31}, + {"JOY32", K_JOY32}, + + {"AUX1", K_AUX1}, + {"AUX2", K_AUX2}, + {"AUX3", K_AUX3}, + {"AUX4", K_AUX4}, + {"AUX5", K_AUX5}, + {"AUX6", K_AUX6}, + {"AUX7", K_AUX7}, + {"AUX8", K_AUX8}, + {"AUX9", K_AUX9}, + {"AUX10", K_AUX10}, + {"AUX11", K_AUX11}, + {"AUX12", K_AUX12}, + {"AUX13", K_AUX13}, + {"AUX14", K_AUX14}, + {"AUX15", K_AUX15}, + {"AUX16", K_AUX16}, + + {"KP_HOME", K_KP_HOME }, + {"KP_UP", K_KP_UPARROW }, + {"KP_PGUP", K_KP_PGUP }, + {"KP_LEFT", K_KP_LEFTARROW }, + {"KP_5", K_KP_5 }, + {"KP_RIGHT", K_KP_RIGHTARROW }, + {"KP_END", K_KP_END }, + {"KP_DOWN", K_KP_DOWNARROW }, + {"KP_PGDN", K_KP_PGDN }, + {"KP_ENTER", K_KP_ENTER }, + {"KP_INS", K_KP_INS }, + {"KP_DEL", K_KP_DEL }, + {"KP_SLASH", K_KP_SLASH }, + {"KP_MINUS", K_KP_MINUS }, + {"KP_PLUS", K_KP_PLUS }, + {"KP_NUMLOCK", K_KP_NUMLOCK }, + {"KP_STAR", K_KP_STAR }, + {"KP_EQUALS", K_KP_EQUALS }, + + {"PAUSE", K_PAUSE}, + + {"SEMICOLON", ';'}, // because a raw semicolon seperates commands + + {NULL,0} +}; + +keyname_t keynames_d[] = //deutsch +{ + {"TAB", K_TAB}, + {"EINGABETASTE", K_ENTER}, + {"ESC", K_ESCAPE}, + {"LEERTASTE", K_SPACE}, + {"RÜCKTASTE", K_BACKSPACE}, + {"PFEILT.AUF", K_UPARROW}, + {"PFEILT.UNTEN", K_DOWNARROW}, + {"PFEILT.LINKS", K_LEFTARROW}, + {"PFEILT.RECHTS", K_RIGHTARROW}, + + {"ALT", K_ALT}, + {"STRG", K_CTRL}, + {"UMSCHALT", K_SHIFT}, + + {"FESTSTELLT", K_CAPSLOCK}, + + {"F1", K_F1}, + {"F2", K_F2}, + {"F3", K_F3}, + {"F4", K_F4}, + {"F5", K_F5}, + {"F6", K_F6}, + {"F7", K_F7}, + {"F8", K_F8}, + {"F9", K_F9}, + {"F10", K_F10}, + {"F11", K_F11}, + {"F12", K_F12}, + + {"EINFG", K_INS}, + {"ENTF", K_DEL}, + {"BILD-AB", K_PGDN}, + {"BILD-AUF", K_PGUP}, + {"POS1", K_HOME}, + {"ENDE", K_END}, + + {"MAUS1", K_MOUSE1}, + {"MAUS2", K_MOUSE2}, + {"MAUS3", K_MOUSE3}, + {"MAUS4", K_MOUSE4}, + {"MAUS5", K_MOUSE5}, + + {"MRADOBEN", K_MWHEELUP }, + {"MRADUNTEN", K_MWHEELDOWN }, + + {"JOY1", K_JOY1}, + {"JOY2", K_JOY2}, + {"JOY3", K_JOY3}, + {"JOY4", K_JOY4}, + {"JOY5", K_JOY5}, + {"JOY6", K_JOY6}, + {"JOY7", K_JOY7}, + {"JOY8", K_JOY8}, + {"JOY9", K_JOY9}, + {"JOY10", K_JOY10}, + {"JOY11", K_JOY11}, + {"JOY12", K_JOY12}, + {"JOY13", K_JOY13}, + {"JOY14", K_JOY14}, + {"JOY15", K_JOY15}, + {"JOY16", K_JOY16}, + {"JOY17", K_JOY17}, + {"JOY18", K_JOY18}, + {"JOY19", K_JOY19}, + {"JOY20", K_JOY20}, + {"JOY21", K_JOY21}, + {"JOY22", K_JOY22}, + {"JOY23", K_JOY23}, + {"JOY24", K_JOY24}, + {"JOY25", K_JOY25}, + {"JOY26", K_JOY26}, + {"JOY27", K_JOY27}, + {"JOY28", K_JOY28}, + {"JOY29", K_JOY29}, + {"JOY30", K_JOY30}, + {"JOY31", K_JOY31}, + {"JOY32", K_JOY32}, + + {"AUX1", K_AUX1}, + {"AUX2", K_AUX2}, + {"AUX3", K_AUX3}, + {"AUX4", K_AUX4}, + {"AUX5", K_AUX5}, + {"AUX6", K_AUX6}, + {"AUX7", K_AUX7}, + {"AUX8", K_AUX8}, + {"AUX9", K_AUX9}, + {"AUX10", K_AUX10}, + {"AUX11", K_AUX11}, + {"AUX12", K_AUX12}, + {"AUX13", K_AUX13}, + {"AUX14", K_AUX14}, + {"AUX15", K_AUX15}, + {"AUX16", K_AUX16}, + + {"ZB_POS1", K_KP_HOME }, + {"ZB_PFEILT.AUF", K_KP_UPARROW }, + {"ZB_BILD-AUF", K_KP_PGUP }, + {"ZB_PFEILT.LINKS", K_KP_LEFTARROW }, + {"ZB_5", K_KP_5 }, + {"ZB_PFEILT.RECHTS",K_KP_RIGHTARROW }, + {"ZB_ENDE", K_KP_END }, + {"ZB_PFEILT.UNTEN", K_KP_DOWNARROW }, + {"ZB_BILD-AB", K_KP_PGDN }, + {"ZB_ENTER", K_KP_ENTER }, + {"ZB_EINFG", K_KP_INS }, + {"ZB_ENTF", K_KP_DEL }, + {"ZB_SLASH", K_KP_SLASH }, + {"ZB_MINUS", K_KP_MINUS }, + {"ZB_PLUS", K_KP_PLUS }, + {"ZB_NUM", K_KP_NUMLOCK }, + {"ZB_*", K_KP_STAR }, + {"ZB_EQUALS", K_KP_EQUALS }, + + {"PAUSE", K_PAUSE}, + + {"COMMAND", K_COMMAND}, //mac + {NULL,0} +}; //end german + +keyname_t keynames_f[] = //french +{ + {"TAB", K_TAB}, + {"ENTREE", K_ENTER}, + {"ECHAP", K_ESCAPE}, + {"ESPACE", K_SPACE}, + {"RETOUR", K_BACKSPACE}, + {"HAUT", K_UPARROW}, + {"BAS", K_DOWNARROW}, + {"GAUCHE", K_LEFTARROW}, + {"DROITE", K_RIGHTARROW}, + + {"ALT", K_ALT}, + {"CTRL", K_CTRL}, + {"MAJ", K_SHIFT}, + + {"VERRMAJ", K_CAPSLOCK}, + + {"F1", K_F1}, + {"F2", K_F2}, + {"F3", K_F3}, + {"F4", K_F4}, + {"F5", K_F5}, + {"F6", K_F6}, + {"F7", K_F7}, + {"F8", K_F8}, + {"F9", K_F9}, + {"F10", K_F10}, + {"F11", K_F11}, + {"F12", K_F12}, + + {"INSER", K_INS}, + {"SUPPR", K_DEL}, + {"PGBAS", K_PGDN}, + {"PGHAUT", K_PGUP}, + {"ORIGINE", K_HOME}, + {"FIN", K_END}, + + {"SOURIS1", K_MOUSE1}, + {"SOURIS2", K_MOUSE2}, + {"SOURIS3", K_MOUSE3}, + {"SOURIS4", K_MOUSE4}, + {"SOURIS5", K_MOUSE5}, + + {"MOLETTEHT.", K_MWHEELUP }, + {"MOLETTEBAS", K_MWHEELDOWN }, + + {"JOY1", K_JOY1}, + {"JOY2", K_JOY2}, + {"JOY3", K_JOY3}, + {"JOY4", K_JOY4}, + {"JOY5", K_JOY5}, + {"JOY6", K_JOY6}, + {"JOY7", K_JOY7}, + {"JOY8", K_JOY8}, + {"JOY9", K_JOY9}, + {"JOY10", K_JOY10}, + {"JOY11", K_JOY11}, + {"JOY12", K_JOY12}, + {"JOY13", K_JOY13}, + {"JOY14", K_JOY14}, + {"JOY15", K_JOY15}, + {"JOY16", K_JOY16}, + {"JOY17", K_JOY17}, + {"JOY18", K_JOY18}, + {"JOY19", K_JOY19}, + {"JOY20", K_JOY20}, + {"JOY21", K_JOY21}, + {"JOY22", K_JOY22}, + {"JOY23", K_JOY23}, + {"JOY24", K_JOY24}, + {"JOY25", K_JOY25}, + {"JOY26", K_JOY26}, + {"JOY27", K_JOY27}, + {"JOY28", K_JOY28}, + {"JOY29", K_JOY29}, + {"JOY30", K_JOY30}, + {"JOY31", K_JOY31}, + {"JOY32", K_JOY32}, + + {"AUX1", K_AUX1}, + {"AUX2", K_AUX2}, + {"AUX3", K_AUX3}, + {"AUX4", K_AUX4}, + {"AUX5", K_AUX5}, + {"AUX6", K_AUX6}, + {"AUX7", K_AUX7}, + {"AUX8", K_AUX8}, + {"AUX9", K_AUX9}, + {"AUX10", K_AUX10}, + {"AUX11", K_AUX11}, + {"AUX12", K_AUX12}, + {"AUX13", K_AUX13}, + {"AUX14", K_AUX14}, + {"AUX15", K_AUX15}, + {"AUX16", K_AUX16}, + + {"PN_ORIGINE", K_KP_HOME }, + {"PN_HAUT", K_KP_UPARROW }, + {"PN_PGBAS", K_KP_PGUP }, + {"PN_GAUCHE", K_KP_LEFTARROW }, + {"PN_5", K_KP_5 }, + {"PN_DROITE", K_KP_RIGHTARROW }, + {"PN_FIN", K_KP_END }, + {"PN_BAS", K_KP_DOWNARROW }, + {"PN_PGBAS", K_KP_PGDN }, + {"PN_ENTR", K_KP_ENTER }, + {"PN_INSER", K_KP_INS }, + {"PN_SUPPR", K_KP_DEL }, + {"PN_SLASH", K_KP_SLASH }, + {"PN_MOINS", K_KP_MINUS }, + {"PN_PLUS", K_KP_PLUS }, + {"PN_VERRNUM", K_KP_NUMLOCK }, + {"PN_*", K_KP_STAR }, + {"PN_EQUALS", K_KP_EQUALS }, + + {"PAUSE", K_PAUSE}, + + {"COMMAND", K_COMMAND}, //mac + + {"POINT-VIRGULE", ';' }, // because a raw semicolon seperates commands + + {NULL,0} +}; //end french + /* ============================================================================= @@ -855,7 +1230,9 @@ Returns a string (either a single ascii char, a K_* name, or a 0x11 hex string) given keynum. =================== */ -char *Key_KeynumToString( int keynum ) { +extern cvar_t *sp_language; +char *Key_KeynumToString( int keynum, qboolean bTranslate ) //note: translate is only called for menu display not configs +{ keyname_t *kn; static char tinystr[5]; int i, j; @@ -875,8 +1252,21 @@ char *Key_KeynumToString( int keynum ) { return tinystr; } + kn=keynames; //init to english + if (bTranslate) { + if ( sp_language->integer == SP_LANGUAGE_GERMAN ) { + kn=keynames_d; //use german + } else if ( sp_language->integer == SP_LANGUAGE_FRENCH ) { + kn=keynames_f; //use french + } + else //rww - this is actually English and doesn't need to be "translated". + { //however, certain key names are too long to display right, this does the trick. + kn=keynames_e; + } + } + // check for a key string - for ( kn=keynames ; kn->name ; kn++ ) { + for ( ; kn->name ; kn++ ) { if (keynum == kn->keynum) { return kn->name; } @@ -1051,7 +1441,7 @@ void Key_WriteBindings( fileHandle_t f ) { for (i=0 ; i<256 ; i++) { if (keys[i].binding && keys[i].binding[0] ) { - FS_Printf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keys[i].binding); + FS_Printf (f, "bind %s \"%s\"\n", Key_KeynumToString(i, qfalse), keys[i].binding); } @@ -1070,7 +1460,7 @@ void Key_Bindlist_f( void ) { for ( i = 0 ; i < 256 ; i++ ) { if ( keys[i].binding && keys[i].binding[0] ) { - Com_Printf( "%s \"%s\"\n", Key_KeynumToString(i), keys[i].binding ); + Com_Printf( "%s \"%s\"\n", Key_KeynumToString(i, qfalse), keys[i].binding ); } } } @@ -1259,7 +1649,7 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) { if ( !kb ) { if (key >= 200) { Com_Printf ("%s is unbound, use controls menu to set.\n" - , Key_KeynumToString( key ) ); + , Key_KeynumToString( key, qfalse ) ); } } else if (kb[0] == '+') { int i; diff --git a/CODE-mp/client/cl_main.cpp b/CODE-mp/client/cl_main.cpp index 99123c7..3756a11 100644 --- a/CODE-mp/client/cl_main.cpp +++ b/CODE-mp/client/cl_main.cpp @@ -9,6 +9,10 @@ #include "..\ghoul2\G2_local.h" #endif +#ifdef _DONETPROFILE_ +#include "../qcommon/INetProfile.h" +#endif + cvar_t *cl_nodelta; cvar_t *cl_debugMove; @@ -55,6 +59,8 @@ cvar_t *cl_serverStatusResendTime; cvar_t *cl_trn; cvar_t *cl_framerate; +cvar_t *cl_autolodscale; + vec3_t cl_windVec; #ifdef USE_CD_KEY @@ -508,7 +514,13 @@ void CL_PlayDemo_f( void ) { if (!clc.demofile) { if (!Q_stricmp(arg, "(null)")) { - Com_Error( ERR_DROP, "No demo selected.", name); + extern cvar_t *sp_language; + switch (sp_language->integer) + { + case SP_LANGUAGE_GERMAN: Com_Error( ERR_DROP, "Kein demo ausgewählt." ); break; + case SP_LANGUAGE_FRENCH: Com_Error( ERR_DROP, "Aucun demo choisi." ); break; + default: Com_Error( ERR_DROP, "No demo selected." ); break; + } } else { @@ -579,11 +591,8 @@ void CL_NextDemo( void ) { CL_ShutdownAll ===================== */ -extern void CM_ShutdownShaderProperties(void); void CL_ShutdownAll(void) { - CM_ShutdownShaderProperties(); - // clear sounds S_DisableSounds(); // shutdown CGame @@ -611,6 +620,8 @@ ways a client gets into a game Also called by Com_Error ================= */ +extern void FixGhoul2InfoLeaks(bool,bool); + void CL_FlushMemory( void ) { // shutdown all the client stuff @@ -618,10 +629,11 @@ void CL_FlushMemory( void ) { // if not running a server clear the whole hunk if ( !com_sv_running->integer ) { + // clear collision map data + FixGhoul2InfoLeaks(true,false); + CM_ClearMap(); // clear the whole hunk Hunk_Clear(); - // clear collision map data - CM_ClearMap(); } else { // clear all the client data on the hunk @@ -645,6 +657,9 @@ void CL_MapLoading( void ) { return; } + // Set this to localhost. + Cvar_Set( "cl_currentServerAddress", "Localhost"); + Con_Close(); cls.keyCatchers = 0; @@ -743,9 +758,6 @@ void CL_Disconnect( qboolean showMainMenu ) { cls.state = CA_DISCONNECTED; - // allow cheats locally - Cvar_Set( "sv_cheats", "1" ); - // not connected to a pure server anymore cl_connectedToPureServer = qfalse; } @@ -806,12 +818,25 @@ void CL_RequestMotd( void ) { BigShort( cls.updateServer.port ) ); info[0] = 0; - Com_sprintf( cls.updateChallenge, sizeof( cls.updateChallenge ), "%i", rand() ); + // NOTE TTimo xoring against Com_Milliseconds, otherwise we may not have a true randomization + // only srand I could catch before here is tr_noise.c l:26 srand(1001) + // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=382 + // NOTE: the Com_Milliseconds xoring only affects the lower 16-bit word, + // but I decided it was enough randomization + Com_sprintf( cls.updateChallenge, sizeof( cls.updateChallenge ), "%i", ((rand() << 16) ^ rand()) ^ Com_Milliseconds()); + Info_SetValueForKey( info, "challenge", cls.updateChallenge ); Info_SetValueForKey( info, "renderer", cls.glconfig.renderer_string ); Info_SetValueForKey( info, "version", com_version->string ); + Info_SetValueForKey( info, "cputype", Cvar_VariableString("sys_cpustring") ); + Info_SetValueForKey( info, "mhz", Cvar_VariableString("sys_cpuspeed") ); + Info_SetValueForKey( info, "memory", Cvar_VariableString("sys_memory") ); + Info_SetValueForKey( info, "joystick", Cvar_VariableString("in_joystick") ); + Info_SetValueForKey( info, "colorbits", va("%d",cls.glconfig.colorBits) ); + + NET_OutOfBandPrint( NS_CLIENT, cls.updateServer, "getmotd \"%s\"\n", info ); } @@ -1003,6 +1028,11 @@ CL_Connect_f void CL_Connect_f( void ) { char *server; + if ( !Cvar_VariableValue("fs_restrict") && !Sys_CheckCD() ) + { + Com_Error( ERR_NEED_CD, SP_GetStringTextString("CON_TEXT_NEED_CD") ); //"Game CD not in drive" ); + } + if ( Cmd_Argc() != 2 ) { Com_Printf( "usage: connect [server]\n"); return; @@ -1166,7 +1196,6 @@ void CL_Vid_Restart_f( void ) { // don't let them loop during the restart S_StopAllSounds(); - S_BeginRegistration(); // CHC did this // shutdown the UI CL_ShutdownUI(); // shutdown the CGame @@ -1190,6 +1219,7 @@ void CL_Vid_Restart_f( void ) { // if not running a server clear the whole hunk if ( !com_sv_running->integer ) { + CM_ClearMap(); // clear the whole hunk Hunk_Clear(); } @@ -1440,19 +1470,34 @@ and determine if we need to download them ================= */ void CL_InitDownloads(void) { - - if ( cl_allowDownload->integer && - FS_ComparePaks( clc.downloadList, sizeof( clc.downloadList ) ) ) { - + char missingfiles[1024]; + + if ( !cl_allowDownload->integer ) + { + // autodownload is disabled on the client + // but it's possible that some referenced files on the server are missing + if (FS_ComparePaks( missingfiles, sizeof( missingfiles ), qfalse ) ) + { + // NOTE TTimo I would rather have that printed as a modal message box + // but at this point while joining the game we don't know wether we will successfully join or not + Com_Printf( "\nWARNING: You are missing some files referenced by the server:\n%s" + "You might not be able to join the game\n" + "Go to the setting menu to turn on autodownload, or get the file elsewhere\n\n", missingfiles ); + } + } + else if ( FS_ComparePaks( clc.downloadList, sizeof( clc.downloadList ) , qtrue ) ) { + + Com_Printf("Need paks: %s\n", clc.downloadList ); + if ( *clc.downloadList ) { // if autodownloading is not enabled on the server cls.state = CA_CONNECTED; CL_NextDownload(); return; } - - } + } + CL_DownloadsComplete(); } @@ -1464,7 +1509,7 @@ Resend a connect message if the last one has timed out ================= */ void CL_CheckForResend( void ) { - int port, i; + int port; char info[MAX_INFO_STRING]; char data[MAX_INFO_STRING]; @@ -1505,15 +1550,9 @@ void CL_CheckForResend( void ) { Info_SetValueForKey( info, "protocol", va("%i", PROTOCOL_VERSION ) ); Info_SetValueForKey( info, "qport", va("%i", port ) ); Info_SetValueForKey( info, "challenge", va("%i", clc.challenge ) ); - - strcpy(data, "connect "); + sprintf(data, "connect \"%s\"", info ); + NET_OutOfBandData( NS_CLIENT, clc.serverAddress, (unsigned char *)data, strlen(data) ); - for(i=0;i<(int)strlen(info);i++) { - data[8+i] = info[i]; // + (clc.challenge)&0x3; - } - data[8+i] = 0; - - NET_OutOfBandData( NS_CLIENT, clc.serverAddress, (unsigned char *)data, i+8 ); // the most current userinfo has been sent, so watch for any // newer changes to userinfo variables cvar_modifiedFlags &= ~CVAR_USERINFO; @@ -1732,6 +1771,79 @@ void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) { Com_Printf("%d servers parsed (total %d)\n", numservers, total); } +#ifndef MAX_STRIPED_SV_STRING +#define MAX_STRIPED_SV_STRING 1024 +#endif +static void CL_CheckSVStripEdRef(char *buf, const char *str) +{ //I don't really like doing this. But it utilizes the system that was already in place. + int i = 0; + int b = 0; + int strLen = 0; + qboolean gotStrip = qfalse; + + if (!str || !str[0]) + { + if (str) + { + strcpy(buf, str); + } + return; + } + + strcpy(buf, str); + + strLen = strlen(str); + + if (strLen >= MAX_STRIPED_SV_STRING) + { + return; + } + + while (i < strLen && str[i]) + { + gotStrip = qfalse; + + if (str[i] == '@' && (i+1) < strLen) + { + if (str[i+1] == '@' && (i+2) < strLen) + { + if (str[i+2] == '@' && (i+3) < strLen) + { //@@@ should mean to insert a striped reference here, so insert it into buf at the current place + char stripRef[MAX_STRIPED_SV_STRING]; + int r = 0; + + while (i < strLen && str[i] == '@') + { + i++; + } + + while (i < strLen && str[i] && str[i] != ' ' && str[i] != ':' && str[i] != '.' && str[i] != '\n') + { + stripRef[r] = str[i]; + r++; + i++; + } + stripRef[r] = 0; + + buf[b] = 0; + Q_strcat(buf, MAX_STRIPED_SV_STRING, SP_GetStringTextString(va("SVINGAME_%s", stripRef))); + b = strlen(buf); + } + } + } + + if (!gotStrip) + { + buf[b] = str[i]; + b++; + } + i++; + } + + buf[b] = 0; +} + + /* ================= CL_ConnectionlessPacket @@ -1768,7 +1880,7 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { // take this address as the new server address. This allows // a server proxy to hand off connections to multiple servers clc.serverAddress = from; - Com_DPrintf ("challenge: %d\n", clc.challenge); + Com_DPrintf ("challengeResponse: %d\n", clc.challenge); } return; } @@ -1833,15 +1945,20 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { } // echo request from server - if ( !Q_stricmp(c, "print") ) { + if ( !Q_stricmp(c, "print") ) + { + char sTemp[MAX_STRIPED_SV_STRING]; + s = MSG_ReadString( msg ); - Q_strncpyz( clc.serverMessage, s, sizeof( clc.serverMessage ) ); - Com_Printf( "%s", s ); + CL_CheckSVStripEdRef(sTemp, s); + Q_strncpyz( clc.serverMessage, sTemp, sizeof( clc.serverMessage ) ); + Com_Printf( "%s", sTemp ); return; } // echo request from server - if ( !Q_stricmp(c, "getserversResponse\\") ) { +// if ( !Q_stricmp(c, "getserversResponse\\") ) { + if ( !Q_strncmp(c, "getserversResponse", 18) ) { CL_ServersResponsePacket( from, msg ); return; } @@ -1924,8 +2041,9 @@ void CL_CheckTimeout( void ) { && cls.state >= CA_CONNECTED && cls.state != CA_CINEMATIC && cls.realtime - clc.lastPacketTime > cl_timeout->value*1000) { if (++cl.timeoutcount > 5) { // timeoutcount saves debugger - Com_Printf ("\nServer connection timed out.\n"); - Com_Error(ERR_DROP, "Server connection timed out."); + const char *psTimedOut = SP_GetStringTextString("SVINGAME_SERVER_CONNECTION_TIMED_OUT"); + Com_Printf ("\n%s\n",psTimedOut); + Com_Error(ERR_DROP, psTimedOut); //CL_Disconnect( qtrue ); return; } @@ -1968,12 +2086,16 @@ CL_Frame */ static unsigned int frameCount; static float avgFrametime=0.0; +extern void SP_CheckForLanguageUpdates(void); void CL_Frame ( int msec ) { if ( !com_cl_running->integer ) { return; } + SP_CheckForLanguageUpdates(); // will take zero time to execute unless language changes, then will reload strings. + // of course this still doesn't work for menus... + if ( cls.state == CA_DISCONNECTED && !( cls.keyCatchers & KEYCATCH_UI ) && !com_sv_running->integer ) { // if disconnected, bring up the menu @@ -2017,6 +2139,13 @@ void CL_Frame ( int msec ) { cls.realtime += cls.frametime; +#ifdef _DONETPROFILE_ + if(cls.state==CA_ACTIVE) + { + ClReadProf().IncTime(cls.frametime); + } +#endif + if ( cl_timegraph->integer ) { SCR_DebugGraph ( cls.realFrametime * 0.25, 0 ); } @@ -2244,7 +2373,6 @@ void CL_SetModel_f( void ) { arg = Cmd_Argv( 1 ); if (arg[0]) { Cvar_Set( "model", arg ); - Cvar_Set( "headmodel", arg ); } else { Cvar_VariableStringBuffer( "model", name, sizeof(name) ); Com_Printf("model is set to %s\n", name); @@ -2262,8 +2390,10 @@ Register_StringPackets */ void Register_StringPackets (void) { - SP_Register("con_text", SP_REGISTER_REQUIRED); - SP_Register("mp_ingame",SP_REGISTER_REQUIRED); + SP_Register("con_text", SP_REGISTER_REQUIRED); //reference is CON_TEXT + SP_Register("mp_ingame",SP_REGISTER_REQUIRED); //reference is INGAMETEXT + SP_Register("mp_svgame",SP_REGISTER_REQUIRED); //reference is SVINGAME + SP_Register("sp_ingame",SP_REGISTER_REQUIRED); //reference is INGAME , needed for item pickups } @@ -2311,7 +2441,7 @@ void CL_Init( void ) { cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", CVAR_ARCHIVE); cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "140", CVAR_ARCHIVE); - cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0); + cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", CVAR_ARCHIVE); cl_maxpackets = Cvar_Get ("cl_maxpackets", "30", CVAR_ARCHIVE ); cl_packetdup = Cvar_Get ("cl_packetdup", "1", CVAR_ARCHIVE ); @@ -2325,6 +2455,8 @@ void CL_Init( void ) { cl_framerate = Cvar_Get ("cl_framerate", "0", CVAR_TEMP); cl_allowDownload = Cvar_Get ("cl_allowDownload", "0", CVAR_ARCHIVE); + cl_autolodscale = Cvar_Get( "cl_autolodscale", "1", CVAR_ARCHIVE ); + cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0); #ifdef MACOS_X // In game video is REALLY slow in Mac OS X right now due to driver slowness @@ -2356,14 +2488,14 @@ void CL_Init( void ) { // userinfo - Cvar_Get ("name", "UnnamedPlayer", CVAR_USERINFO | CVAR_ARCHIVE ); - Cvar_Get ("rate", "3000", CVAR_USERINFO | CVAR_ARCHIVE ); + Cvar_Get ("name", "Padawan", CVAR_USERINFO | CVAR_ARCHIVE ); + Cvar_Get ("rate", "4000", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("snaps", "20", CVAR_USERINFO | CVAR_ARCHIVE ); - Cvar_Get ("model", "kyle", CVAR_USERINFO | CVAR_ARCHIVE ); - Cvar_Get ("headmodel", "kyle", CVAR_USERINFO | CVAR_ARCHIVE ); - Cvar_Get ("team_model", "kyle", CVAR_USERINFO | CVAR_ARCHIVE ); - Cvar_Get ("team_headmodel", "kyle", CVAR_USERINFO | CVAR_ARCHIVE ); - Cvar_Get ("forcepowers", "5-1-000000000000000000", CVAR_USERINFO | CVAR_ARCHIVE ); + Cvar_Get ("model", "kyle/default", CVAR_USERINFO | CVAR_ARCHIVE ); +// Cvar_Get ("headmodel", "kyle/default", CVAR_USERINFO | CVAR_ARCHIVE ); + Cvar_Get ("team_model", "kyle/default", CVAR_USERINFO | CVAR_ARCHIVE ); +// Cvar_Get ("team_headmodel", "kyle/default", CVAR_USERINFO | CVAR_ARCHIVE ); + Cvar_Get ("forcepowers", "7-1-032330000000001333", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("g_redTeam", "Empire", CVAR_SERVERINFO | CVAR_ARCHIVE); Cvar_Get ("g_blueTeam", "Rebellion", CVAR_SERVERINFO | CVAR_ARCHIVE); Cvar_Get ("color1", "4", CVAR_USERINFO | CVAR_ARCHIVE ); @@ -2438,13 +2570,13 @@ void CL_Shutdown( void ) { CL_Disconnect( qtrue ); + CL_ShutdownRef(); //must be before shutdown all so the images get dumped in RE_Shutdown + // RJ: added the shutdown all to close down the cgame (to free up some memory, such as in the fx system) CL_ShutdownAll(); S_Shutdown(); - CL_ShutdownRef(); - - CL_ShutdownUI(); + //CL_ShutdownUI(); Cmd_RemoveCommand ("cmd"); Cmd_RemoveCommand ("configstrings"); diff --git a/CODE-mp/client/cl_parse.cpp b/CODE-mp/client/cl_parse.cpp index 6600e0c..60eafef 100644 --- a/CODE-mp/client/cl_parse.cpp +++ b/CODE-mp/client/cl_parse.cpp @@ -3,6 +3,9 @@ #include "client.h" #include "..\qcommon\strip.h" #include "../ghoul2/g2_local.h" +#ifdef _DONETPROFILE_ +#include "../qcommon/INetProfile.h" +#endif char *svc_strings[256] = { "svc_bad", @@ -233,7 +236,7 @@ void CL_ParseSnapshot( msg_t *msg ) { // is too old, so we can't reconstruct it properly. Com_Printf ("Delta frame too old.\n"); } else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) { - Com_Printf ("Delta parseEntitiesNum too old.\n"); + Com_DPrintf ("Delta parseEntitiesNum too old.\n"); } else { newSnap.valid = qtrue; // valid delta parse } @@ -326,7 +329,8 @@ void CL_SystemInfoChanged( void ) { } s = Info_ValueForKey( systemInfo, "sv_cheats" ); - if ( atoi(s) == 0 ) { + if ( atoi(s) == 0 ) + { Cvar_SetCheatState(); } @@ -381,6 +385,11 @@ void CL_ParseGamestate( msg_t *msg ) { // wipe local client state CL_ClearState(); +#ifdef _DONETPROFILE_ + int startBytes,endBytes; + startBytes=msg->readcount; +#endif + // a gamestate always marks a server command sequence clc.serverCommandSequence = MSG_ReadLong( msg ); @@ -428,6 +437,11 @@ void CL_ParseGamestate( msg_t *msg ) { // read the checksum feed clc.checksumFeed = MSG_ReadLong( msg ); +#ifdef _DONETPROFILE_ + endBytes=msg->readcount; +// ClReadProf().AddField("svc_gamestate",endBytes-startBytes); +#endif + // parse serverId and other cvars CL_SystemInfoChanged(); @@ -555,9 +569,16 @@ void CL_ParseCommandString( msg_t *msg ) { int seq; int index; +#ifdef _DONETPROFILE_ + int startBytes,endBytes; + startBytes=msg->readcount; +#endif seq = MSG_ReadLong( msg ); s = MSG_ReadString( msg ); - +#ifdef _DONETPROFILE_ + endBytes=msg->readcount; + ClReadProf().AddField("svc_serverCommand",endBytes-startBytes); +#endif // see if we have already executed stored it off if ( clc.serverCommandSequence >= seq ) { return; diff --git a/CODE-mp/client/cl_ui.cpp b/CODE-mp/client/cl_ui.cpp index 3f7578f..d5530b5 100644 --- a/CODE-mp/client/cl_ui.cpp +++ b/CODE-mp/client/cl_ui.cpp @@ -641,7 +641,7 @@ Key_KeynumToStringBuf ==================== */ static void Key_KeynumToStringBuf( int keynum, char *buf, int buflen ) { - Q_strncpyz( buf, Key_KeynumToString( keynum ), buflen ); + Q_strncpyz( buf, Key_KeynumToString( keynum, qtrue ), buflen ); } /* @@ -1131,8 +1131,7 @@ int CL_UISystemCalls( int *args ) { #endif // USE_CD_KEY case UI_SP_REGISTER: - SP_Register((const char *)VMA(1),SP_REGISTER_MENU); - return 0; + return !!SP_Register((const char *)VMA(1),SP_REGISTER_MENU); case UI_SP_GETSTRINGTEXTSTRING: const char* text; diff --git a/CODE-mp/client/client.h b/CODE-mp/client/client.h index bb18265..9956a70 100644 --- a/CODE-mp/client/client.h +++ b/CODE-mp/client/client.h @@ -437,7 +437,7 @@ void IN_CenterView (void); void CL_VerifyCode( void ); float CL_KeyState (kbutton_t *key); -char *Key_KeynumToString (int keynum); +char *Key_KeynumToString( int keynum, qboolean bTranslate ); //note: translate is only called for menu display not configs // // cl_parse.c diff --git a/CODE-mp/client/snd_dma.cpp b/CODE-mp/client/snd_dma.cpp index bea9677..89aad1a 100644 --- a/CODE-mp/client/snd_dma.cpp +++ b/CODE-mp/client/snd_dma.cpp @@ -135,6 +135,7 @@ cvar_t *s_show; cvar_t *s_mixahead; cvar_t *s_mixPreStep; cvar_t *s_musicVolume; +cvar_t *s_musicMult; cvar_t *s_separation; cvar_t *s_doppler; cvar_t *s_CPUType; @@ -211,7 +212,11 @@ void S_Init( void ) { Com_Printf("\n------- sound initialization -------\n"); s_volume = Cvar_Get ("s_volume", "0.8", CVAR_ARCHIVE); - s_musicVolume = Cvar_Get ("s_musicvolume", "0.25", CVAR_ARCHIVE); + s_musicVolume = Cvar_Get ("s_musicvolume", "0.5", CVAR_ARCHIVE); + + //rww - multiply s_musicVolume by this value. Set in cgame when necessary. + s_musicMult = Cvar_Get ("s_musicMult", "1", 0); + s_separation = Cvar_Get ("s_separation", "0.5", CVAR_ARCHIVE); s_doppler = Cvar_Get ("s_doppler", "1", CVAR_ARCHIVE); s_khz = Cvar_Get ("s_khz", "22", CVAR_ARCHIVE); @@ -543,9 +548,7 @@ sfxHandle_t S_RegisterSound( const char *name) if ( sfx->bDefaultSound ) { // Suppress error for inline sounds if(Q_stricmp(sfx->sSoundName, DEFAULT_SOUND_NAME)){ -#ifdef _DEBUG - Com_Printf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->sSoundName ); -#endif + Com_DPrintf( S_COLOR_YELLOW "WARNING: could not find %s - using default\n", sfx->sSoundName ); } return 0; } @@ -2050,7 +2053,7 @@ static qboolean S_UpdateBackgroundTrack_Actual( MusicInfo_t *pMusicInfo ) int fileBytes; int r; - float fMasterVol = s_musicVolume->value; + float fMasterVol = (s_musicVolume->value*s_musicMult->value); static float musicVolume = 0.25f; @@ -2213,6 +2216,10 @@ cvar_t *s_soundpoolmegs = NULL; void SND_setup() { s_soundpoolmegs = Cvar_Get("s_soundpoolmegs", "25", CVAR_ARCHIVE); + if (Sys_LowPhysicalMemory() ) + { + Cvar_Set("s_soundpoolmegs", "0"); + } Com_Printf("Sound memory manager started\n"); } @@ -2373,7 +2380,7 @@ qboolean SND_RegisterAudio_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLev else { int iLoadedAudioBytes = Z_MemSize ( TAG_SND_RAWDATA ) + Z_MemSize( TAG_SND_MP3STREAMHDR ); - const int iMaxAudioBytes = (!Sys_LowPhysicalMemory() && s_soundpoolmegs) ? (s_soundpoolmegs->integer * 1024 * 1024) : 0; + const int iMaxAudioBytes = s_soundpoolmegs->integer * 1024 * 1024; for (int i=1; i iMaxAudioBytes || bDeleteEverythingNotUsedThisLevel) ; i++) // i=1 so we never page out default sound { diff --git a/CODE-mp/client/snd_mem.cpp b/CODE-mp/client/snd_mem.cpp index 39cbbb5..cd62307 100644 --- a/CODE-mp/client/snd_mem.cpp +++ b/CODE-mp/client/snd_mem.cpp @@ -219,11 +219,44 @@ void S_LoadSound_Finalize(wavinfo_t *info, sfx_t *sfx, byte *data) // // returns qfalse if failed to load, else fills in *pData // +extern cvar_t *com_buildScript; static qboolean S_LoadSound_FileLoadAndNameAdjuster(char *psFilename, byte **pData, int *piSize, int iNameStrlen) { char *psVoice = strstr(psFilename,"chars"); if (psVoice) { + // cache foreign voices... + // + if (com_buildScript->integer) + { + fileHandle_t hFile; + strncpy(psVoice,"chr_d",5); // same number of letters as "chars" + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache this file + if (!hFile) + { + strcpy(&psFilename[iNameStrlen-3],"mp3"); //not there try mp3 + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache this file + } + if (hFile) + { + FS_FCloseFile(hFile); + } + strcpy(&psFilename[iNameStrlen-3],"wav"); + + strncpy(psVoice,"chr_f",5); // same number of letters as "chars" + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cahce this file + if (!hFile) + { + strcpy(&psFilename[iNameStrlen-3],"mp3"); //not there try mp3 + FS_FOpenFileRead(psFilename, &hFile, qfalse); //cache this file + } + if (hFile) + { + FS_FCloseFile(hFile); + } + strncpy(psVoice,"chars",5); //put it back to chars + } + // account for foreign voices... // extern cvar_t* s_language; diff --git a/CODE-mp/client/vssver.scc b/CODE-mp/client/vssver.scc new file mode 100644 index 0000000..964e749 Binary files /dev/null and b/CODE-mp/client/vssver.scc differ diff --git a/CODE-mp/encryption/cpp_interface.cpp b/CODE-mp/encryption/cpp_interface.cpp index 128a8f5..1902e0f 100644 --- a/CODE-mp/encryption/cpp_interface.cpp +++ b/CODE-mp/encryption/cpp_interface.cpp @@ -258,8 +258,8 @@ bool cEncryptedFile::GetKey(char *KeyUser, char *KeyPassword) extern int Sys_GetProcessorId( void ); Connection->Print("Info: procId: 0x%x\r\n", Sys_GetProcessorId() ); -//#include "../qcommon/stv_version.h" -// Connection->Print("Info: Version '" Q3_VERSION " " __DATE__ "'\r\n"); +#include "../qcommon/game_version.h" + Connection->Print("Info: Version '" Q3_VERSION " " __DATE__ "'\r\n"); Connection->Print("\r\n"); while(!Connection->Handle()) diff --git a/CODE-mp/encryption/vssver.scc b/CODE-mp/encryption/vssver.scc new file mode 100644 index 0000000..c3b206d Binary files /dev/null and b/CODE-mp/encryption/vssver.scc differ diff --git a/CODE-mp/game/JK2_game.def b/CODE-mp/game/JK2_game.def new file mode 100644 index 0000000..ea649b4 --- /dev/null +++ b/CODE-mp/game/JK2_game.def @@ -0,0 +1,3 @@ +EXPORTS + dllEntry + vmMain diff --git a/CODE-mp/game/ai_main.c b/CODE-mp/game/ai_main.c index 95ad7d6..710cb22 100644 --- a/CODE-mp/game/ai_main.c +++ b/CODE-mp/game/ai_main.c @@ -552,6 +552,14 @@ void BotInputToUserCommand(bot_input_t *bi, usercmd_t *ucmd, int delta_angles[3] if (bi->actionflags & ACTION_FOLLOWME) ucmd->buttons |= BUTTON_FOLLOWME; #endif //0 + if (bi->weapon == WP_NONE) + { +#ifdef _DEBUG +// Com_Printf("WARNING: Bot tried to use WP_NONE!\n"); +#endif + bi->weapon = WP_BRYAR_PISTOL; + } + // ucmd->weapon = bi->weapon; //set the view angles @@ -1276,8 +1284,12 @@ void WPConstantRoutine(bot_state_t *bs) if (heightDif > 40 && (bs->cur_ps.fd.forcePowersKnown & (1 << FP_LEVITATION)) && (bs->cur_ps.fd.forceJumpCharge < (forceJumpStrength[bs->cur_ps.fd.forcePowerLevel[FP_LEVITATION]]-100) || bs->cur_ps.groundEntityNum == ENTITYNUM_NONE)) { - bs->forceJumpChargeTime = level.time + 300; - bs->beStill = level.time + 100; + bs->forceJumpChargeTime = level.time + 1000; + if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE && bs->jumpPrep < (level.time-300)) + { + bs->jumpPrep = level.time + 700; + } + bs->beStill = level.time + 300; bs->jumpTime = 0; if (bs->wpSeenTime < (level.time + 600)) @@ -1541,7 +1553,7 @@ int BotTrace_Jump(bot_state_t *bs, vec3_t traceto) mins[0] = -15; mins[1] = -15; - mins[2] = -15; + mins[2] = -18; maxs[0] = 15; maxs[1] = 15; maxs[2] = 32; @@ -1726,6 +1738,25 @@ int PassStandardEnemyChecks(bot_state_t *bs, gentity_t *en) return 0; } + if (g_gametype.integer == GT_JEDIMASTER && !en->client->ps.isJediMaster && !bs->cur_ps.isJediMaster) + { //rules for attacking non-JM in JM mode + vec3_t vs; + float vLen = 0; + + if (!g_friendlyFire.integer) + { //can't harm non-JM in JM mode if FF is off + return 0; + } + + VectorSubtract(bs->origin, en->client->ps.origin, vs); + vLen = VectorLength(vs); + + if (vLen > 350) + { + return 0; + } + } + /* if (en->client && en->client->pers.connected != CON_CONNECTED) { @@ -1992,6 +2023,8 @@ int PassLovedOneCheck(bot_state_t *bs, gentity_t *ent) return 1; } +qboolean G_ThereIsAMaster(void); + int ScanForEnemies(bot_state_t *bs) { vec3_t a; @@ -2000,6 +2033,7 @@ int ScanForEnemies(bot_state_t *bs) int bestindex; int i; float hasEnemyDist = 0; + qboolean noAttackNonJM = qfalse; closest = 999999; i = 0; @@ -2016,6 +2050,21 @@ int ScanForEnemies(bot_state_t *bs) return -1; } + if (g_gametype.integer == GT_JEDIMASTER) + { + if (G_ThereIsAMaster() && !bs->cur_ps.isJediMaster) + { + if (!g_friendlyFire.integer) + { + noAttackNonJM = qtrue; + } + else + { + closest = 128; //only get mad at people if they get close enough to you to anger you, or hurt you + } + } + } + while (i <= MAX_CLIENTS) { if (i != bs->client && g_entities[i].client && !OnSameTeam(&g_entities[bs->client], &g_entities[i]) && PassStandardEnemyChecks(bs, &g_entities[i]) && trap_InPVS(g_entities[i].client->ps.origin, bs->eye) && PassLovedOneCheck(bs, &g_entities[i])) @@ -2037,8 +2086,11 @@ int ScanForEnemies(bot_state_t *bs) { if (!hasEnemyDist || distcheck < (hasEnemyDist - 128)) { //if we have an enemy, only switch to closer if he is 128+ closer to avoid flipping out - closest = distcheck; - bestindex = i; + if (!noAttackNonJM || g_entities[i].client->ps.isJediMaster) + { + closest = distcheck; + bestindex = i; + } } } } @@ -2046,8 +2098,11 @@ int ScanForEnemies(bot_state_t *bs) { if (!hasEnemyDist || distcheck < (hasEnemyDist - 128)) { //if we have an enemy, only switch to closer if he is 128+ closer to avoid flipping out - closest = distcheck; - bestindex = i; + if (!noAttackNonJM || g_entities[i].client->ps.isJediMaster) + { + closest = distcheck; + bestindex = i; + } } } } @@ -2137,6 +2192,11 @@ int BotIsAChickenWuss(bot_state_t *bs) { int bWRange; + if (gLevelFlags & LEVELFLAG_IMUSTNTRUNAWAY) + { + return 0; + } + if (g_gametype.integer == GT_JEDIMASTER && !bs->cur_ps.isJediMaster) { //Then you may know no fear. //Well, unless he's strong. @@ -4839,6 +4899,17 @@ int BotTryAnotherWeapon(bot_state_t *bs) return 0; } +qboolean BotWeaponSelectable(bot_state_t *bs, int weapon) +{ + if (bs->cur_ps.ammo[weaponData[weapon].ammoIndex] >= weaponData[weapon].energyPerShot && + (bs->cur_ps.stats[STAT_WEAPONS] & (1 << weapon))) + { + return qtrue; + } + + return qfalse; +} + int BotSelectIdealWeapon(bot_state_t *bs) { int i; @@ -4871,7 +4942,7 @@ int BotSelectIdealWeapon(bot_state_t *bs) i++; } - if ( bs->currentEnemy && bs->frame_Enemy_Len < 512 && + if ( bs->currentEnemy && bs->frame_Enemy_Len < 300 && (bestweapon == WP_BRYAR_PISTOL || bestweapon == WP_BLASTER || bestweapon == WP_BOWCASTER) && (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_SABER)) ) { @@ -4879,6 +4950,42 @@ int BotSelectIdealWeapon(bot_state_t *bs) bestweight = 1; } + if ( bs->currentEnemy && bs->frame_Enemy_Len > 300 && + bs->currentEnemy->client && bs->currentEnemy->client->ps.weapon != WP_SABER && + (bestweapon == WP_SABER) ) + { //if the enemy is far away, and we have our saber selected, see if we have any good distance weapons instead + if (BotWeaponSelectable(bs, WP_DISRUPTOR)) + { + bestweapon = WP_DISRUPTOR; + bestweight = 1; + } + else if (BotWeaponSelectable(bs, WP_ROCKET_LAUNCHER)) + { + bestweapon = WP_ROCKET_LAUNCHER; + bestweight = 1; + } + else if (BotWeaponSelectable(bs, WP_BOWCASTER)) + { + bestweapon = WP_BOWCASTER; + bestweight = 1; + } + else if (BotWeaponSelectable(bs, WP_BLASTER)) + { + bestweapon = WP_BLASTER; + bestweight = 1; + } + else if (BotWeaponSelectable(bs, WP_REPEATER)) + { + bestweapon = WP_REPEATER; + bestweight = 1; + } + else if (BotWeaponSelectable(bs, WP_DEMP2)) + { + bestweapon = WP_DEMP2; + bestweight = 1; + } + } + if (bestweight != -1 && bs->cur_ps.weapon != bestweapon && bs->virtualWeapon != bestweapon) { bs->virtualWeapon = bestweapon; @@ -5937,6 +6044,7 @@ void StandardBotAI(bot_state_t *bs, float thinktime) } } + /* if (bs->currentEnemy && bs->currentEnemy->client && bs->cur_ps.weapon == WP_SABER && g_privateDuel.integer && @@ -5971,6 +6079,9 @@ void StandardBotAI(bot_state_t *bs, float thinktime) bs->beStill = level.time + 100; } } + */ + //Apparently this "allows you to cheese" when fighting against bots. I'm not sure why you'd want to con bots + //into an easy kill, since they're bots and all. But whatever. if (!bs->wpCurrent) { @@ -6605,6 +6716,11 @@ void StandardBotAI(bot_state_t *bs, float thinktime) } #endif + if (bs->jumpPrep > level.time) + { + bs->forceJumpChargeTime = 0; + } + if (bs->forceJumpChargeTime > level.time) { bs->jumpHoldTime = ((bs->forceJumpChargeTime - level.time)/2) + level.time; @@ -6621,7 +6737,17 @@ void StandardBotAI(bot_state_t *bs, float thinktime) if (bs->jumpHoldTime > level.time) { trap_EA_Jump(bs->client); - trap_EA_MoveForward(bs->client); + if (bs->wpCurrent) + { + if ((bs->wpCurrent->origin[2] - bs->origin[2]) < 64) + { + trap_EA_MoveForward(bs->client); + } + } + else + { + trap_EA_MoveForward(bs->client); + } if (g_entities[bs->client].client->ps.groundEntityNum == ENTITYNUM_NONE) { g_entities[bs->client].client->ps.pm_flags |= PMF_JUMP_HELD; @@ -6788,7 +6914,7 @@ void StandardBotAI(bot_state_t *bs, float thinktime) else { #endif - if (bot_forcepowers.integer) + if (bot_forcepowers.integer && !g_forcePowerDisable.integer) { trap_EA_ForcePower(bs->client); } diff --git a/CODE-mp/game/ai_main.h b/CODE-mp/game/ai_main.h index 01353d5..d504062 100644 --- a/CODE-mp/game/ai_main.h +++ b/CODE-mp/game/ai_main.h @@ -38,6 +38,7 @@ #define LEVELFLAG_NOPOINTPREDICTION 1 //don't take waypoint beyond current into account when adjusting path view angles #define LEVELFLAG_IGNOREINFALLBACK 2 //ignore enemies when in a fallback navigation routine +#define LEVELFLAG_IMUSTNTRUNAWAY 4 //don't be scared #define WP_KEEP_FLAG_DIST 128 @@ -241,6 +242,7 @@ typedef struct bot_state_s float duckTime; float jumpTime; float jumpHoldTime; + float jumpPrep; float forceJumping; float jDelay; diff --git a/CODE-mp/game/ai_util.c b/CODE-mp/game/ai_util.c index 5f312c7..6f66660 100644 --- a/CODE-mp/game/ai_util.c +++ b/CODE-mp/game/ai_util.c @@ -347,6 +347,11 @@ int BotDoChat(bot_state_t *bs, char *section, int always) return 0; } + if (trap_Cvar_VariableIntegerValue("sp_language")) + { //no chatting unless English. + return 0; + } + if (Q_irand(1, 10) > bs->chatFrequency && !always) { return 0; diff --git a/CODE-mp/game/ai_wpnav.c b/CODE-mp/game/ai_wpnav.c index 2686ac6..bbdbde9 100644 --- a/CODE-mp/game/ai_wpnav.c +++ b/CODE-mp/game/ai_wpnav.c @@ -210,7 +210,7 @@ void G_TestLine(vec3_t start, vec3_t end, int color, int time) te = G_TempEntity( start, EV_TESTLINE ); VectorCopy(start, te->s.origin); VectorCopy(end, te->s.origin2); - te->s.trickedentindex = time; + te->s.time2 = time; te->s.weapon = color; te->r.svFlags |= SVF_BROADCAST; } diff --git a/CODE-mp/game/anims.h b/CODE-mp/game/anims.h index a8b695b..45cc978 100644 --- a/CODE-mp/game/anims.h +++ b/CODE-mp/game/anims.h @@ -1231,7 +1231,6 @@ typedef enum //# animNumber_e FACE_SMILE, //# FACE_FROWN, //# FACE_DEAD, //# - FACE_GALAK, //# This has to be last for Galak Mech to talk //# #eol MAX_ANIMATIONS, diff --git a/CODE-mp/game/bg_misc.c b/CODE-mp/game/bg_misc.c index 97f2488..303069b 100644 --- a/CODE-mp/game/bg_misc.c +++ b/CODE-mp/game/bg_misc.c @@ -19,16 +19,19 @@ #endif #endif +//rww - not putting @ in front of these because +//we don't need them in a cgame striped lookup. +//Let me know if this causes problems, pat. char *forceMasteryLevels[NUM_FORCE_MASTERY_LEVELS] = { - "Uninitiated", // FORCE_MASTERY_UNINITIATED, - "@MASTERY1", //"Initiate", // FORCE_MASTERY_INITIATE, - "@MASTERY2", //"Padawan", // FORCE_MASTERY_PADAWAN, - "@MASTERY3", //"Disciple", // FORCE_MASTERY_DISCIPLE, - "@MASTERY4", //"Jedi", // FORCE_MASTERY_JEDI, - "@MASTERY5", //"Jedi Adept", // FORCE_MASTERY_JEDI_ADEPT, - "@MASTERY6", //"Jedi Master", // FORCE_MASTERY_JEDI_MASTER, - "@MASTERY7", //"Jedi Lord" // FORCE_MASTERY_JEDI_LORD, + "MASTERY0", //"Uninitiated", // FORCE_MASTERY_UNINITIATED, + "MASTERY1", //"Initiate", // FORCE_MASTERY_INITIATE, + "MASTERY2", //"Padawan", // FORCE_MASTERY_PADAWAN, + "MASTERY3", //"Jedi", // FORCE_MASTERY_JEDI, + "MASTERY4", //"Jedi Adept", // FORCE_MASTERY_JEDI_GUARDIAN, + "MASTERY5", //"Jedi Guardian", // FORCE_MASTERY_JEDI_ADEPT, + "MASTERY6", //"Jedi Knight", // FORCE_MASTERY_JEDI_KNIGHT, + "MASTERY7", //"Jedi Master" // FORCE_MASTERY_JEDI_MASTER, }; int forceMasteryPoints[NUM_FORCE_MASTERY_LEVELS] = @@ -36,13 +39,35 @@ int forceMasteryPoints[NUM_FORCE_MASTERY_LEVELS] = 0, // FORCE_MASTERY_UNINITIATED, 5, // FORCE_MASTERY_INITIATE, 10, // FORCE_MASTERY_PADAWAN, - 15, // FORCE_MASTERY_DISCIPLE, 20, // FORCE_MASTERY_JEDI, - 25, // FORCE_MASTERY_JEDI_ADEPT, - 30, // FORCE_MASTERY_JEDI_MASTER, - 40 // FORCE_MASTERY_JEDI_LORD, + 30, // FORCE_MASTERY_JEDI_GUARDIAN, + 50, // FORCE_MASTERY_JEDI_ADEPT, + 75, // FORCE_MASTERY_JEDI_KNIGHT, + 100 // FORCE_MASTERY_JEDI_MASTER, }; +int bgForcePowerCost[NUM_FORCE_POWERS][NUM_FORCE_POWER_LEVELS] = //0 == neutral +{ + { 0, 2, 4, 6 }, // Heal // FP_HEAL + { 0, 0, 2, 6 }, // Jump //FP_LEVITATION,//hold/duration + { 0, 2, 4, 6 }, // Speed //FP_SPEED,//duration + { 0, 1, 3, 6 }, // Push //FP_PUSH,//hold/duration + { 0, 1, 3, 6 }, // Pull //FP_PULL,//hold/duration + { 0, 4, 6, 8 }, // Mind Trick //FP_TELEPATHY,//instant + { 0, 1, 3, 6 }, // Grip //FP_GRIP,//hold/duration + { 0, 2, 5, 8 }, // Lightning //FP_LIGHTNING,//hold/duration + { 0, 4, 6, 8 }, // Dark Rage //FP_RAGE,//duration + { 0, 2, 5, 8 }, // Protection //FP_PROTECT,//duration + { 0, 1, 3, 6 }, // Absorb //FP_ABSORB,//duration + { 0, 1, 3, 6 }, // Team Heal //FP_TEAM_HEAL,//instant + { 0, 1, 3, 6 }, // Team Force //FP_TEAM_FORCE,//instant + { 0, 2, 4, 6 }, // Drain //FP_DRAIN,//hold/duration + { 0, 2, 5, 8 }, // Sight //FP_SEE,//duration + { 0, 1, 5, 8 }, // Saber Attack //FP_SABERATTACK, + { 0, 1, 5, 8 }, // Saber Defend //FP_SABERDEFEND, + { 0, 4, 6, 8 } // Saber Throw //FP_SABERTHROW, + //NUM_FORCE_POWERS +}; int forcePowerSorted[NUM_FORCE_POWERS] = { //rww - always use this order when drawing force powers for any reason @@ -135,6 +160,289 @@ int WeaponAttackAnim[WP_NUM_WEAPONS] = BOTH_ATTACK1//WP_TURRET, }; + +//The magical function to end all functions. +//This will take the force power string in powerOut and parse through it, then legalize +//it based on the supposed rank and spit it into powerOut, returning true if it was legal +//to begin with and false if not. +//fpDisabled is actually only expected (needed) from the server, because the ui disables +//force power selection anyway when force powers are disabled on the server. +qboolean BG_LegalizedForcePowers(char *powerOut, int maxRank, qboolean freeSaber, int teamForce, int gametype, int fpDisabled) +{ + char powerBuf[128]; + char readBuf[128]; + qboolean maintainsValidity = qtrue; + int powerLen = strlen(powerOut); + int i = 0; + int c = 0; + int allowedPoints = 0; + int usedPoints = 0; + int countDown = 0; + + int final_Side; + int final_Powers[NUM_FORCE_POWERS]; + + if (powerLen >= 128) + { //This should not happen. If it does, this is obviously a bogus string. + //They can have this string. Because I said so. + strcpy(powerBuf, "7-1-032330000000001333"); + maintainsValidity = qfalse; + } + else + { + strcpy(powerBuf, powerOut); //copy it as the original + } + + //first of all, print the max rank into the string as the rank + strcpy(powerOut, va("%i-", maxRank)); + + while (i < 128 && powerBuf[i] && powerBuf[i] != '-') + { + i++; + } + i++; + while (i < 128 && powerBuf[i] && powerBuf[i] != '-') + { + readBuf[c] = powerBuf[i]; + c++; + i++; + } + readBuf[c] = 0; + i++; + //at this point, readBuf contains the intended side + final_Side = atoi(readBuf); + + if (final_Side != FORCE_LIGHTSIDE && + final_Side != FORCE_DARKSIDE) + { //Not a valid side. You will be dark. Because I said so. (this is something that should never actually happen unless you purposely feed in an invalid config) + final_Side = FORCE_DARKSIDE; + maintainsValidity = qfalse; + } + + if (teamForce) + { //If we are under force-aligned teams, make sure we're on the right side. + if (final_Side != teamForce) + { + final_Side = teamForce; + //maintainsValidity = qfalse; + //Not doing this, for now. Let them join the team with their filtered powers. + } + } + + //Now we have established a valid rank, and a valid side. + //Read the force powers in, and cut them down based on the various rules supplied. + c = 0; + while (i < 128 && powerBuf[i] && powerBuf[i] != '\n' && c < NUM_FORCE_POWERS) + { + readBuf[0] = powerBuf[i]; + readBuf[1] = 0; + final_Powers[c] = atoi(readBuf); + c++; + i++; + } + + //final_Powers now contains all the stuff from the string + //Set the maximum allowed points used based on the max rank level, and count the points actually used. + allowedPoints = forceMasteryPoints[maxRank]; + + i = 0; + while (i < NUM_FORCE_POWERS) + { //if this power doesn't match the side we're on, then 0 it now. + if (final_Powers[i] && + forcePowerDarkLight[i] && + forcePowerDarkLight[i] != final_Side) + { + final_Powers[i] = 0; + //This is only likely to happen with g_forceBasedTeams. Let it slide. + //maintainsValidity = 0; + } + + if ( final_Powers[i] && + (fpDisabled & (1 << i)) ) + { //if this power is disabled on the server via said server option, then we don't get it. + final_Powers[i] = 0; + } + + i++; + } + + if (gametype < GT_TEAM) + { //don't bother with team powers then + final_Powers[FP_TEAM_HEAL] = 0; + final_Powers[FP_TEAM_FORCE] = 0; + } + + usedPoints = 0; + i = 0; + while (i < NUM_FORCE_POWERS) + { + countDown = 0; + + countDown = final_Powers[i]; + + while (countDown > 0) + { + usedPoints += bgForcePowerCost[i][countDown]; //[fp index][fp level] + //if this is jump, or we have a free saber and it's offense or defense, take the level back down on level 1 + if ( countDown == 1 && + ((i == FP_LEVITATION) || + (i == FP_SABERATTACK && freeSaber) || + (i == FP_SABERDEFEND && freeSaber)) ) + { + usedPoints -= bgForcePowerCost[i][countDown]; + } + countDown--; + } + + i++; + } + + if (usedPoints > allowedPoints) + { //Time to do the fancy stuff. (meaning, slowly cut parts off while taking a guess at what is most or least important in the config) + int attemptedCycles = 0; + int powerCycle = 2; + int minPow = 0; + + if (freeSaber) + { + minPow = 1; + } + + maintainsValidity = qfalse; + + while (usedPoints > allowedPoints) + { + c = 0; + + while (c < NUM_FORCE_POWERS && usedPoints > allowedPoints) + { + if (final_Powers[c] && final_Powers[c] < powerCycle) + { //kill in order of lowest powers, because the higher powers are probably more important + if (c == FP_SABERATTACK && + (final_Powers[FP_SABERDEFEND] > minPow || final_Powers[FP_SABERTHROW] > 0)) + { //if we're on saber attack, only suck it down if we have no def or throw either + int whichOne = FP_SABERTHROW; //first try throw + + if (!final_Powers[whichOne]) + { + whichOne = FP_SABERDEFEND; //if no throw, drain defense + } + + while (final_Powers[whichOne] > 0 && usedPoints > allowedPoints) + { + if ( final_Powers[whichOne] > 1 || + ( (whichOne != FP_SABERATTACK || !freeSaber) && + (whichOne != FP_SABERDEFEND || !freeSaber) ) ) + { //don't take attack or defend down on level 1 still, if it's free + usedPoints -= bgForcePowerCost[whichOne][final_Powers[whichOne]]; + final_Powers[whichOne]--; + } + else + { + break; + } + } + } + else + { + while (final_Powers[c] > 0 && usedPoints > allowedPoints) + { + if ( final_Powers[c] > 1 || + ((c != FP_LEVITATION) && + (c != FP_SABERATTACK || !freeSaber) && + (c != FP_SABERDEFEND || !freeSaber)) ) + { + usedPoints -= bgForcePowerCost[c][final_Powers[c]]; + final_Powers[c]--; + } + else + { + break; + } + } + } + } + + c++; + } + + powerCycle++; + attemptedCycles++; + + if (attemptedCycles > NUM_FORCE_POWERS) + { //I think this should be impossible. But just in case. + break; + } + } + + if (usedPoints > allowedPoints) + { //Still? Fine then.. we will kill all of your powers, except the freebies. + i = 0; + + while (i < NUM_FORCE_POWERS) + { + final_Powers[i] = 0; + if (i == FP_LEVITATION || + (i == FP_SABERATTACK && freeSaber) || + (i == FP_SABERDEFEND && freeSaber)) + { + final_Powers[i] = 1; + } + i++; + } + usedPoints = 0; + } + } + + if (final_Powers[FP_SABERATTACK] < 1) + { + final_Powers[FP_SABERDEFEND] = 0; + final_Powers[FP_SABERTHROW] = 0; + } + + if (freeSaber) + { + if (final_Powers[FP_SABERATTACK] < 1) + { + final_Powers[FP_SABERATTACK] = 1; + } + if (final_Powers[FP_SABERDEFEND] < 1) + { + final_Powers[FP_SABERDEFEND] = 1; + } + } + if (final_Powers[FP_LEVITATION] < 1) + { + final_Powers[FP_LEVITATION] = 1; + } + + if (fpDisabled) + { + final_Powers[FP_LEVITATION] = 1; + final_Powers[FP_SABERATTACK] = 3; + final_Powers[FP_SABERDEFEND] = 3; + final_Powers[FP_SABERTHROW] = 0; + } + + //We finally have all the force powers legalized and stored locally. + //Put them all into the string and return the result. We already have + //the rank there, so print the side and the powers now. + Q_strcat(powerOut, 128, va("%i-", final_Side)); + + i = strlen(powerOut); + c = 0; + while (c < NUM_FORCE_POWERS) + { + strcpy(readBuf, va("%i", final_Powers[c])); + powerOut[i] = readBuf[0]; + c++; + i++; + } + powerOut[i] = 0; + + return maintainsValidity; +} + /*QUAKED item_***** ( 0 0 0 ) (-16 -16 -16) (16 16 16) suspended DO NOT USE THIS CLASS, IT JUST HOLDS GENERAL INFORMATION. The suspended flag will allow items to hang in the air, otherwise they are dropped to the next surface. @@ -151,6 +459,14 @@ An item fires all of its targets when it is picked up. If the toucher can't car "count" override quantity or duration on most items. */ +/*QUAKED misc_shield_floor_unit (1 0 0) (-16 -16 0) (16 16 40) +#MODELNAME="/models/items/a_shield_converter.md3" +Gives shield energy when used. + +"count" - max charge value (default 50) +"chargerate" - rechage 1 point every this many milliseconds (default 3000) +*/ + gitem_t bg_itemlist[] = { { @@ -161,7 +477,7 @@ gitem_t bg_itemlist[] = 0, 0} , // world_model[2],[3] NULL, // view_model /* icon */ NULL, // icon -/* pickup */ NULL, // pickup_name +/* pickup */ //NULL, // pickup_name 0, // quantity 0, // giType (IT_*) 0, // giTag @@ -183,7 +499,7 @@ Instant shield pickup, restores 25 0, 0, 0}, /* view */ NULL, /* icon */ "gfx/mp/small_shield", -/* pickup */ "Shield Small", +/* pickup */// "Shield Small", 25, IT_ARMOR, 1, //special for shield - max on pickup is maxhealth*tag, thus small shield goes up to 100 shield @@ -201,7 +517,7 @@ Instant shield pickup, restores 100 0, 0, 0}, /* view */ NULL, /* icon */ "gfx/mp/large_shield", -/* pickup */ "Shield Large", +/* pickup */// "Shield Large", 100, IT_ARMOR, 2, //special for shield - max on pickup is maxhealth*tag, thus large shield goes up to 200 shield @@ -219,7 +535,7 @@ Instant medpack pickup, heals 25 0, 0, 0 }, /* view */ NULL, /* icon */ "gfx/hud/i_icon_medkit", -/* pickup */ "Medpack", +/* pickup */// "Medpack", 25, IT_HEALTH, 0, @@ -242,7 +558,7 @@ Instant medpack pickup, heals 25 0, 0, 0} , /* view */ NULL, /* icon */ "gfx/hud/i_icon_seeker", -/* pickup */ "Seeker Drone", +/* pickup */// "Seeker Drone", 120, IT_HOLDABLE, HI_SEEKER, @@ -260,7 +576,7 @@ Portable shield 0, 0, 0} , /* view */ NULL, /* icon */ "gfx/hud/i_icon_shieldwall", -/* pickup */ "Forcefield", +/* pickup */// "Forcefield", 120, IT_HOLDABLE, HI_SHIELD, @@ -272,13 +588,13 @@ Portable shield Bacta canister pickup, heals 25 on use */ { - "item_medpac", + "item_medpac", //should be item_bacta "sound/weapons/w_pkup.wav", { "models/map_objects/mp/bacta.md3", 0, 0, 0} , /* view */ NULL, /* icon */ "gfx/hud/i_icon_bacta", -/* pickup */ "Bacta Canister", +/* pickup */// "Bacta Canister", 25, IT_HOLDABLE, HI_MEDPAC, @@ -296,7 +612,7 @@ Do not place this. 0, 0, 0} , /* view */ NULL, /* icon */ NULL, -/* pickup */ "Datapad", +/* pickup */// "Datapad", 1, IT_HOLDABLE, HI_DATAPAD, @@ -314,7 +630,7 @@ These will be standard equipment on the player - DO NOT PLACE 0, 0, 0} , /* view */ NULL, /* icon */ "gfx/hud/i_icon_zoom", -/* pickup */ "Binoculars", +/* pickup */// "Binoculars", 60, IT_HOLDABLE, HI_BINOCULARS, @@ -332,7 +648,7 @@ Sentry gun inventory pickup. 0, 0, 0} , /* view */ NULL, /* icon */ "gfx/hud/i_icon_sentrygun", -/* pickup */ "Sentry Gun", +/* pickup */// "Sentry Gun", 120, IT_HOLDABLE, HI_SENTRY_GUN, @@ -350,7 +666,7 @@ Adds one rank to all Force powers temporarily. Only light jedi can use. 0, 0, 0} , /* view */ NULL, /* icon */ "gfx/hud/mpi_jlight", -/* pickup */ "Light Force Enlightenment", +/* pickup */// "Light Force Enlightenment", 25, IT_POWERUP, PW_FORCE_ENLIGHTENED_LIGHT, @@ -368,7 +684,7 @@ Adds one rank to all Force powers temporarily. Only dark jedi can use. 0, 0, 0} , /* view */ NULL, /* icon */ "gfx/hud/mpi_dklight", -/* pickup */ "Dark Force Enlightenment", +/* pickup */// "Dark Force Enlightenment", 25, IT_POWERUP, PW_FORCE_ENLIGHTENED_DARK, @@ -386,7 +702,7 @@ Unlimited Force Pool for a short time. 0, 0, 0} , /* view */ NULL, /* icon */ "gfx/hud/mpi_fboon", -/* pickup */ "Force Boon", +/* pickup */// "Force Boon", 25, IT_POWERUP, PW_FORCE_BOON, @@ -404,10 +720,10 @@ A small lizard carried on the player, which prevents the possessor from using an 0, 0, 0} , /* view */ NULL, /* icon */ "gfx/hud/mpi_ysamari", -/* pickup */ "Ysalimari", +/* pickup */// "Ysalamiri", 25, IT_POWERUP, - PW_YSALIMARI, + PW_YSALAMIRI, /* precache */ "", /* sounds */ "" }, @@ -426,8 +742,8 @@ Don't place this 0, 0, 0}, /* view */ "models/weapons2/stun_baton/baton.md3", /* icon */ "gfx/hud/w_icon_stunbaton", -/* pickup */ "Stun Baton", - 50, +/* pickup */// "Stun Baton", + 100, IT_WEAPON, WP_STUN_BATON, /* precache */ "", @@ -444,8 +760,8 @@ Don't place this 0, 0, 0}, /* view */ "models/weapons2/saber/saber_w.md3", /* icon */ "gfx/hud/w_icon_lightsaber", -/* pickup */ "Lightsaber", - 50, +/* pickup */// "Lightsaber", + 100, IT_WEAPON, WP_SABER, /* precache */ "", @@ -462,8 +778,8 @@ Don't place this 0, 0, 0}, /* view */ "models/weapons2/briar_pistol/briar_pistol.md3", /* icon */ "gfx/hud/w_icon_rifle", -/* pickup */ "Bryar Pistol", - 50, +/* pickup */// "Bryar Pistol", + 100, IT_WEAPON, WP_BRYAR_PISTOL, /* precache */ "", @@ -479,8 +795,8 @@ Don't place this 0, 0, 0}, /* view */ "models/weapons2/blaster_r/blaster.md3", /* icon */ "gfx/hud/w_icon_blaster", -/* pickup */ "E11 Blaster Rifle", - 50, +/* pickup */// "E11 Blaster Rifle", + 100, IT_WEAPON, WP_BLASTER, /* precache */ "", @@ -496,8 +812,8 @@ Don't place this 0, 0, 0}, /* view */ "models/weapons2/disruptor/disruptor.md3", /* icon */ "gfx/hud/w_icon_disruptor", -/* pickup */ "Tenloss Disruptor Rifle", - 50, +/* pickup */// "Tenloss Disruptor Rifle", + 100, IT_WEAPON, WP_DISRUPTOR, /* precache */ "", @@ -513,8 +829,8 @@ Don't place this 0, 0, 0}, /* view */ "models/weapons2/bowcaster/bowcaster.md3", /* icon */ "gfx/hud/w_icon_bowcaster", -/* pickup */ "Wookiee Bowcaster", - 50, +/* pickup */// "Wookiee Bowcaster", + 100, IT_WEAPON, WP_BOWCASTER, /* precache */ "", @@ -530,8 +846,8 @@ Don't place this 0, 0, 0}, /* view */ "models/weapons2/heavy_repeater/heavy_repeater.md3", /* icon */ "gfx/hud/w_icon_repeater", -/* pickup */ "Imperial Heavy Repeater", - 50, +/* pickup */// "Imperial Heavy Repeater", + 100, IT_WEAPON, WP_REPEATER, /* precache */ "", @@ -548,8 +864,8 @@ NOTENOTE This weapon is not yet complete. Don't place it. 0, 0, 0}, /* view */ "models/weapons2/demp2/demp2.md3", /* icon */ "gfx/hud/w_icon_demp2", -/* pickup */ "DEMP2", - 50, +/* pickup */// "DEMP2", + 100, IT_WEAPON, WP_DEMP2, /* precache */ "", @@ -565,8 +881,8 @@ NOTENOTE This weapon is not yet complete. Don't place it. 0, 0, 0}, /* view */ "models/weapons2/golan_arms/golan_arms.md3", /* icon */ "gfx/hud/w_icon_flechette", -/* pickup */ "Golan Arms Flechette", - 50, +/* pickup */// "Golan Arms Flechette", + 100, IT_WEAPON, WP_FLECHETTE, /* precache */ "", @@ -582,25 +898,75 @@ NOTENOTE This weapon is not yet complete. Don't place it. 0, 0, 0}, /* view */ "models/weapons2/merr_sonn/merr_sonn.md3", /* icon */ "gfx/hud/w_icon_merrsonn", -/* pickup */ "Merr-Sonn Missile System", - 50, +/* pickup */// "Merr-Sonn Missile System", + 3, IT_WEAPON, WP_ROCKET_LAUNCHER, /* precache */ "", /* sounds */ "" }, +/*QUAKED ammo_thermal (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +*/ + { + "ammo_thermal", + "sound/weapons/w_pkup.wav", + { "models/weapons2/thermal/thermal_pu.md3", + "models/weapons2/thermal/thermal_w.glm", 0, 0}, +/* view */ "models/weapons2/thermal/thermal.md3", +/* icon */ "gfx/hud/w_icon_thermal", +/* pickup */// "Thermal Detonators", + 4, + IT_AMMO, + AMMO_THERMAL, +/* precache */ "", +/* sounds */ "" + }, + +/*QUAKED ammo_tripmine (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +*/ + { + "ammo_tripmine", + "sound/weapons/w_pkup.wav", + { "models/weapons2/laser_trap/laser_trap_pu.md3", + "models/weapons2/laser_trap/laser_trap_w.glm", 0, 0}, +/* view */ "models/weapons2/laser_trap/laser_trap.md3", +/* icon */ "gfx/hud/w_icon_tripmine", +/* pickup */// "Trip Mines", + 3, + IT_AMMO, + AMMO_TRIPMINE, +/* precache */ "", +/* sounds */ "" + }, + +/*QUAKED ammo_detpack (.3 .3 1) (-16 -16 -16) (16 16 16) suspended +*/ + { + "ammo_detpack", + "sound/weapons/w_pkup.wav", + { "models/weapons2/detpack/det_pack_pu.md3", "models/weapons2/detpack/det_pack_proj.glm", "models/weapons2/detpack/det_pack_w.glm", 0}, +/* view */ "models/weapons2/detpack/det_pack.md3", +/* icon */ "gfx/hud/w_icon_detpack", +/* pickup */// "Det Packs", + 3, + IT_AMMO, + AMMO_DETPACK, +/* precache */ "", +/* sounds */ "" + }, + /*QUAKED weapon_thermal (.3 .3 1) (-16 -16 -16) (16 16 16) suspended */ { "weapon_thermal", "sound/weapons/w_pkup.wav", - { "models/weapons2/thermal/thermal_w.glm", - 0, 0, 0}, + { "models/weapons2/thermal/thermal_w.glm", "models/weapons2/thermal/thermal_pu.md3", + 0, 0 }, /* view */ "models/weapons2/thermal/thermal.md3", /* icon */ "gfx/hud/w_icon_thermal", -/* pickup */ "Thermal Detonator", - 1, +/* pickup */// "Thermal Detonator", + 4, IT_WEAPON, WP_THERMAL, /* precache */ "", @@ -612,12 +978,12 @@ NOTENOTE This weapon is not yet complete. Don't place it. { "weapon_trip_mine", "sound/weapons/w_pkup.wav", - { "models/weapons2/laser_trap/laser_trap_w.glm", - 0, 0, 0}, + { "models/weapons2/laser_trap/laser_trap_w.glm", "models/weapons2/laser_trap/laser_trap_pu.md3", + 0, 0}, /* view */ "models/weapons2/laser_trap/laser_trap.md3", /* icon */ "gfx/hud/w_icon_tripmine", -/* pickup */ "Trip Mine", - 1, +/* pickup */// "Trip Mine", + 3, IT_WEAPON, WP_TRIP_MINE, /* precache */ "", @@ -629,11 +995,11 @@ NOTENOTE This weapon is not yet complete. Don't place it. { "weapon_det_pack", "sound/weapons/w_pkup.wav", - { "models/weapons2/detpack/det_pack_proj.glm", "models/weapons2/detpack/det_pack_w.glm", 0, 0}, + { "models/weapons2/detpack/det_pack_proj.glm", "models/weapons2/detpack/det_pack_pu.md3", "models/weapons2/detpack/det_pack_w.glm", 0}, /* view */ "models/weapons2/detpack/det_pack.md3", /* icon */ "gfx/hud/w_icon_detpack", -/* pickup */ "Det Pack", - 1, +/* pickup */// "Det Pack", + 3, IT_WEAPON, WP_DET_PACK, /* precache */ "", @@ -649,7 +1015,7 @@ NOTENOTE This weapon is not yet complete. Don't place it. 0, 0, 0}, /* view */ "models/weapons2/blaster_r/blaster.md3", /* icon */ "gfx/hud/w_icon_blaster", -/* pickup */ "Emplaced Gun", +/* pickup */// "Emplaced Gun", 50, IT_WEAPON, WP_EMPLACED_GUN, @@ -666,7 +1032,7 @@ NOTENOTE This weapon is not yet complete. Don't place it. 0, 0, 0}, /* view */ "models/weapons2/blaster_r/blaster.md3", /* icon */ "gfx/hud/w_icon_blaster", -/* pickup */ "Turret Gun", +/* pickup */// "Turret Gun", 50, IT_WEAPON, WP_TURRET, @@ -688,7 +1054,7 @@ Don't place this 0, 0, 0}, /* view */ NULL, /* icon */ "gfx/hud/w_icon_blaster", -/* pickup */ "Force??", +/* pickup */// "Force??", 100, IT_AMMO, AMMO_FORCE, @@ -706,7 +1072,7 @@ Ammo for the Bryar and Blaster pistols. 0, 0, 0}, /* view */ NULL, /* icon */ "gfx/hud/i_icon_battery", -/* pickup */ "Blaster Pack", +/* pickup */// "Blaster Pack", 100, IT_AMMO, AMMO_BLASTER, @@ -724,7 +1090,7 @@ Ammo for Tenloss Disruptor, Wookie Bowcaster, and the Destructive Electro Magnet 0, 0, 0}, /* view */ NULL, /* icon */ "gfx/mp/ammo_power_cell", -/* pickup */ "Power Cell", +/* pickup */// "Power Cell", 100, IT_AMMO, AMMO_POWERCELL, @@ -742,7 +1108,7 @@ Ammo for Imperial Heavy Repeater and the Golan Arms Flechette 0, 0, 0}, /* view */ NULL, /* icon */ "gfx/mp/ammo_metallic_bolts", -/* pickup */ "Metallic Bolts", +/* pickup */// "Metallic Bolts", 100, IT_AMMO, AMMO_METAL_BOLTS, @@ -760,8 +1126,8 @@ Ammo for Merr-Sonn portable missile launcher 0, 0, 0}, /* view */ NULL, /* icon */ "gfx/mp/ammo_rockets", -/* pickup */ "Rockets", - 100, +/* pickup */// "Rockets", + 3, IT_AMMO, AMMO_ROCKETS, /* precache */ "", @@ -782,7 +1148,7 @@ Only in CTF games "models/flags/r_flag_ysal.md3", 0, 0 }, /* view */ NULL, /* icon */ "gfx/hud/mpi_rflag", -/* pickup */ "Red Flag", +/* pickup */// "Red Flag", 0, IT_TEAM, PW_REDFLAG, @@ -800,7 +1166,7 @@ Only in CTF games "models/flags/b_flag_ysal.md3", 0, 0 }, /* view */ NULL, /* icon */ "gfx/hud/mpi_bflag", -/* pickup */ "Blue Flag", +/* pickup */// "Blue Flag", 0, IT_TEAM, PW_BLUEFLAG, @@ -822,7 +1188,7 @@ Only in One Flag CTF games 0, 0, 0 }, /* view */ NULL, /* icon */ "icons/iconf_neutral1", -/* pickup */ "Neutral Flag", +/* pickup */// "Neutral Flag", 0, IT_TEAM, PW_NEUTRALFLAG, @@ -837,7 +1203,7 @@ Only in One Flag CTF games 0, 0, 0 }, /* view */ NULL, /* icon */ "icons/iconh_rorb", -/* pickup */ "Red Cube", +/* pickup */// "Red Cube", 0, IT_TEAM, 0, @@ -852,7 +1218,7 @@ Only in One Flag CTF games 0, 0, 0 }, /* view */ NULL, /* icon */ "icons/iconh_borb", -/* pickup */ "Blue Cube", +/* pickup */// "Blue Cube", 0, IT_TEAM, 0, @@ -866,7 +1232,28 @@ Only in One Flag CTF games int bg_numItems = sizeof(bg_itemlist) / sizeof(bg_itemlist[0]) - 1; -qboolean BG_HasYsalimari(int gametype, playerState_t *ps) +float vectoyaw( const vec3_t vec ) { + float yaw; + + if (vec[YAW] == 0 && vec[PITCH] == 0) { + yaw = 0; + } else { + if (vec[PITCH]) { + yaw = ( atan2( vec[YAW], vec[PITCH]) * 180 / M_PI ); + } else if (vec[YAW] > 0) { + yaw = 90; + } else { + yaw = 270; + } + if (yaw < 0) { + yaw += 360; + } + } + + return yaw; +} + +qboolean BG_HasYsalamiri(int gametype, playerState_t *ps) { if (gametype == GT_CTY && (ps->powerups[PW_REDFLAG] || ps->powerups[PW_BLUEFLAG])) @@ -874,7 +1261,7 @@ qboolean BG_HasYsalimari(int gametype, playerState_t *ps) return qtrue; } - if (ps->powerups[PW_YSALIMARI]) + if (ps->powerups[PW_YSALAMIRI]) { return qtrue; } @@ -884,7 +1271,7 @@ qboolean BG_HasYsalimari(int gametype, playerState_t *ps) qboolean BG_CanUseFPNow(int gametype, playerState_t *ps, int time, forcePowers_t power) { - if (BG_HasYsalimari(gametype, ps)) + if (BG_HasYsalamiri(gametype, ps)) { return qfalse; } @@ -982,11 +1369,11 @@ BG_FindItem =============== */ -gitem_t *BG_FindItem( const char *pickupName ) { +gitem_t *BG_FindItem( const char *classname ) { gitem_t *it; for ( it = bg_itemlist + 1 ; it->classname ; it++ ) { - if ( !Q_stricmp( it->pickup_name, pickupName ) ) + if ( !Q_stricmp( it->classname, classname) ) return it; } @@ -1210,6 +1597,11 @@ qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const play { return qfalse; } + if (!(ent->eFlags & EF_DROPPEDWEAPON) && (ps->stats[STAT_WEAPONS] & (1 << item->giTag)) && + item->giTag != WP_THERMAL && item->giTag != WP_TRIP_MINE && item->giTag != WP_DET_PACK) + { //weaponstay stuff.. if this isn't dropped, and you already have it, you don't get it. + return qfalse; + } return qtrue; // weapons are always picked up case IT_AMMO: @@ -1245,6 +1637,13 @@ qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const play return qtrue; case IT_POWERUP: + if (ps && (ps->powerups[PW_YSALAMIRI])) + { + if (item->giTag != PW_YSALAMIRI) + { + return qfalse; + } + } return qtrue; // powerups are always picked up case IT_TEAM: // team items, such as flags @@ -1330,7 +1729,11 @@ void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) result[2] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime; // FIXME: local gravity... break; default: - Com_Error( ERR_DROP, "BG_EvaluateTrajectory: unknown trType: %i", tr->trTime ); +#ifdef QAGAME + Com_Error( ERR_DROP, "BG_EvaluateTrajectory: [GAME SIDE] unknown trType: %i", tr->trType ); +#else + Com_Error( ERR_DROP, "BG_EvaluateTrajectory: [CLIENTGAME SIDE] unknown trType: %i", tr->trType ); +#endif break; } } @@ -1425,6 +1828,12 @@ char *eventnames[] = { "EV_DISRUPTOR_HIT", "EV_DISRUPTOR_ZOOMSOUND", + "EV_PREDEFSOUND", + + "EV_TEAM_POWER", + + "EV_SCREENSHAKE", + "EV_USE", // +Use key "EV_USE_ITEM0", @@ -1452,6 +1861,7 @@ char *eventnames[] = { "EV_PLAYER_TELEPORT_OUT", "EV_GRENADE_BOUNCE", // eventParm will be the soundindex + "EV_MISSILE_STICK", "EV_PLAY_EFFECT", "EV_PLAY_EFFECT_ID", //finally gave in and added it.. @@ -1498,6 +1908,7 @@ char *eventnames[] = { "EV_GIVE_NEW_RANK", "EV_SET_FREE_SABER", + "EV_SET_FORCE_DISABLE", "EV_WEAPON_CHARGE", "EV_WEAPON_CHARGE_ALT", @@ -1508,7 +1919,16 @@ char *eventnames[] = { "EV_TESTLINE", "EV_STOPLOOPINGSOUND", "EV_STARTLOOPINGSOUND", - "EV_TAUNT" + "EV_TAUNT", + + "EV_TAUNT_YES", + "EV_TAUNT_NO", + "EV_TAUNT_FOLLOWME", + "EV_TAUNT_GETFLAG", + "EV_TAUNT_GUARDBASE", + "EV_TAUNT_PATROL", + + "EV_BODY_QUEUE_COPY" }; diff --git a/CODE-mp/game/bg_panimate.c b/CODE-mp/game/bg_panimate.c index 5b331b8..047d269 100644 --- a/CODE-mp/game/bg_panimate.c +++ b/CODE-mp/game/bg_panimate.c @@ -659,6 +659,20 @@ qboolean BG_ParseAnimationFile(const char *filename) bgGlobalAnimations[animNum].initialLerp = ceil(1000.0f / fabs(fps)); } +#ifdef _DEBUG + //Check the array, and print the ones that have nothing in them. + for(i = 0; i < MAX_ANIMATIONS; i++) + { + if (animTable[i].name != NULL) // This animation reference exists. + { + if (bgGlobalAnimations[i].firstFrame <= 0 && bgGlobalAnimations[i].numFrames <=0) + { // This is an empty animation reference. + Com_Printf("***ANIMTABLE reference #%d (%s) is empty!\n", i, animTable[i].name); + } + } + } +#endif // _DEBUG + BGPAFtextLoaded = qtrue; return qtrue; } @@ -754,16 +768,6 @@ void PM_StartTorsoAnim( int anim ) { | anim; } -static void PM_ContinueTorsoAnim( int anim ) { - if ( ( pm->ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim ) { - return; - } - if ( pm->ps->torsoTimer > 0 ) { - return; // a high priority animation is running - } - PM_StartTorsoAnim( anim); -} - /* ------------------------- @@ -955,6 +959,9 @@ setAnimDone: // Imported from single-player, this function is mainly intended to make porting from SP easier. void PM_SetAnim(int setAnimParts,int anim,int setAnimFlags, int blendTime) { + assert( bgGlobalAnimations[anim].firstFrame != 0 || + bgGlobalAnimations[anim].numFrames != 0); + if (BG_InSpecialJump(anim)) { setAnimFlags |= SETANIM_FLAG_RESTART; diff --git a/CODE-mp/game/bg_pmove.c b/CODE-mp/game/bg_pmove.c index f412325..6c91279 100644 --- a/CODE-mp/game/bg_pmove.c +++ b/CODE-mp/game/bg_pmove.c @@ -12,6 +12,8 @@ pmove_t *pm; pml_t pml; +qboolean gPMDoSlowFall = qfalse; + // movement parameters float pm_stopspeed = 100.0f; float pm_duckScale = 0.50f; @@ -100,7 +102,7 @@ int forcePowerNeeded[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] = 20,//FP_SEE,//duration 0,//FP_SABERATTACK, 1,//FP_SABERDEFEND, - 10//FP_SABERTHROW, + 20//FP_SABERTHROW, //NUM_FORCE_POWERS }, { @@ -110,7 +112,7 @@ int forcePowerNeeded[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] = 20,//FP_PUSH,//hold/duration 20,//FP_PULL,//hold/duration 20,//FP_TELEPATHY,//instant - 30,//FP_GRIP,//hold/duration + 60,//FP_GRIP,//hold/duration 1,//FP_LIGHTNING,//hold/duration 50,//FP_RAGE,//duration 10,//FP_PROTECT,//duration @@ -121,7 +123,7 @@ int forcePowerNeeded[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] = 20,//FP_SEE,//duration 0,//FP_SABERATTACK, 0,//FP_SABERDEFEND, - 5//FP_SABERTHROW, + 20//FP_SABERTHROW, //NUM_FORCE_POWERS } }; @@ -157,6 +159,16 @@ int PM_GetSaberStance(void) return BOTH_SABERFAST_STANCE; } +qboolean PM_DoSlowFall(void) +{ + if ( ( (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_RIGHT || (pm->ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_LEFT ) && pm->ps->legsTimer > 500 ) + { + return qtrue; + } + + return qfalse; +} + /* =============== PM_AddEvent @@ -444,7 +456,7 @@ qboolean PM_ForceJumpingUp(void) return qfalse; } - if (BG_HasYsalimari(pm->gametype, pm->ps)) + if (BG_HasYsalamiri(pm->gametype, pm->ps)) { return qfalse; } @@ -498,6 +510,117 @@ static void PM_JumpForDir( void ) } } +void PM_SetPMViewAngle(playerState_t *ps, vec3_t angle, usercmd_t *ucmd) +{ + int i; + + // set the delta angle + for (i=0 ; i<3 ; i++) { + int cmdAngle; + + cmdAngle = ANGLE2SHORT(angle[i]); + ps->delta_angles[i] = cmdAngle - ucmd->angles[i]; + } + //VectorCopy( angle, ent->s.angles ); + VectorCopy (angle, ps->viewangles); +} + +qboolean PM_AdjustAngleForWallRun( playerState_t *ps, usercmd_t *ucmd, qboolean doMove ) +{ + if (( (ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_RIGHT || (ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_LEFT ) && ps->legsTimer > 500 ) + {//wall-running and not at end of anim + //stick to wall, if there is one + vec3_t rt, traceTo, mins, maxs, fwdAngles; + trace_t trace; + float dist, yawAdjust; + + VectorSet(mins, -15, -15, 0); + VectorSet(maxs, 15, 15, 24); + VectorSet(fwdAngles, 0, pm->ps->viewangles[YAW], 0); + + AngleVectors( fwdAngles, NULL, rt, NULL ); + if ( (ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_RIGHT ) + { + dist = 128; + yawAdjust = -90; + } + else + { + dist = -128; + yawAdjust = 90; + } + VectorMA( ps->origin, dist, rt, traceTo ); + + pm->trace( &trace, ps->origin, mins, maxs, traceTo, ps->clientNum, MASK_PLAYERSOLID ); + + if ( trace.fraction < 1.0f ) + {//still a wall there + //FIXME: don't pull around 90 turns + //FIXME: simulate stepping up steps here, somehow? + if ( (ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_RIGHT ) + { + ucmd->rightmove = 127; + } + else + { + ucmd->rightmove = -127; + } + if ( ucmd->upmove < 0 ) + { + ucmd->upmove = 0; + } + //make me face perpendicular to the wall + ps->viewangles[YAW] = vectoyaw( trace.plane.normal )+yawAdjust; + + //SetClientViewAngle( ent, ent->client->ps.viewangles ); + PM_SetPMViewAngle(ps, ps->viewangles, ucmd); + + ucmd->angles[YAW] = ANGLE2SHORT( ps->viewangles[YAW] ) - ps->delta_angles[YAW]; + if ( doMove ) + { + //push me forward + vec3_t fwd; + float zVel = ps->velocity[2]; + if ( ps->legsTimer > 500 ) + {//not at end of anim yet + float speed = 175; + + fwdAngles[YAW] = ps->viewangles[YAW]; + AngleVectors( fwdAngles, fwd, NULL, NULL ); + //FIXME: or MA? + if ( ucmd->forwardmove < 0 ) + {//slower + speed = 100; + } + else if ( ucmd->forwardmove > 0 ) + { + speed = 250;//running speed + } + VectorScale( fwd, speed, ps->velocity ); + } + ps->velocity[2] = zVel;//preserve z velocity + //pull me toward the wall, too + VectorMA( ps->velocity, dist, rt, ps->velocity ); + } + ucmd->forwardmove = 0; + return qtrue; + } + else if ( doMove ) + {//stop it + if ( (ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_RIGHT ) + { + PM_SetAnim(SETANIM_BOTH, BOTH_WALL_RUN_RIGHT_STOP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0); + } + else if ( (ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_WALL_RUN_LEFT ) + { + PM_SetAnim(SETANIM_BOTH, BOTH_WALL_RUN_LEFT_STOP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0); + } + } + } + + return qfalse; +} + /* ============= PM_CheckJump @@ -606,7 +729,6 @@ static qboolean PM_CheckJump( void ) { //start force jump pm->ps->fd.forcePowersActive |= (1<gent, CHAN_BODY, "sound/weapons/force/jump.wav" ); pm->ps->fd.forceJumpSound = 1; //play flip //FIXME: do this only when they stop the jump (below) or when they're just about to hit the peak of the jump @@ -788,7 +910,7 @@ static qboolean PM_CheckJump( void ) { VectorMA( pm->ps->velocity, JUMP_VELOCITY*2, forward, pm->ps->velocity ); //FIXME: kicking off wall anim? At least check what anim we're in? - PM_SetAnim(SETANIM_LEGS,BOTH_SWIMFORWARDSTART,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_RESTART, 150); + PM_SetAnim(SETANIM_LEGS,BOTH_FORCEJUMP1,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_RESTART, 150); }//else no surf close enough to push off of pm->cmd.upmove = 0; } @@ -797,7 +919,7 @@ static qboolean PM_CheckJump( void ) !(pm->ps->pm_flags&PMF_JUMP_HELD) /*&& WP_ForcePowerAvailable( pm->gent, FP_LEVITATION, 0 ) */ && pm->ps->weapon == WP_SABER && - !BG_HasYsalimari(pm->gametype, pm->ps) && + !BG_HasYsalamiri(pm->gametype, pm->ps) && BG_CanUseFPNow(pm->gametype, pm->ps, pm->cmd.serverTime, FP_LEVITATION) ) { @@ -985,7 +1107,6 @@ static qboolean PM_CheckJump( void ) pm->ps->fd.forceJumpZStart = pm->ps->origin[2];//so we don't take damage if we land at same height pm->ps->pm_flags |= PMF_JUMP_HELD;//PMF_JUMPING|PMF_SLOW_MO_FALL; pm->cmd.upmove = 0; - //G_SoundOnEnt( pm->gent, CHAN_BODY, "sound/weapons/force/jump.wav" ); //WP_ForcePowerDrain( pm->gent, FP_LEVITATION, 0 ); pm->ps->fd.forceJumpSound = 1; } @@ -996,13 +1117,12 @@ static qboolean PM_CheckJump( void ) int legsAnim = (pm->ps->legsAnim&~ANIM_TOGGLEBIT); if ( legsAnim == BOTH_WALL_RUN_LEFT || legsAnim == BOTH_WALL_RUN_RIGHT ) {//running on a wall - //FIXME: if already in a wall run, keep checking for a wall surf... maybe kick people? vec3_t right, traceto, mins, maxs, fwdAngles; trace_t trace; int anim = -1; - VectorSet(mins, pm->mins[0],pm->mins[0],0); - VectorSet(maxs, pm->maxs[0],pm->maxs[0],24); + VectorSet(mins, pm->mins[0], pm->mins[0], 0); + VectorSet(maxs, pm->maxs[0], pm->maxs[0], 24); VectorSet(fwdAngles, 0, pm->ps->viewangles[YAW], 0); AngleVectors( fwdAngles, NULL, right, NULL ); @@ -1011,7 +1131,7 @@ static qboolean PM_CheckJump( void ) { if ( pm->ps->legsTimer > 400 ) {//not at the end of the anim - float animLen = PM_AnimLength( 0, BOTH_WALL_RUN_LEFT ); + float animLen = PM_AnimLength( 0, (animNumber_t)BOTH_WALL_RUN_LEFT ); if ( pm->ps->legsTimer < animLen - 400 ) {//not at start of anim VectorMA( pm->ps->origin, -16, right, traceto ); @@ -1023,7 +1143,7 @@ static qboolean PM_CheckJump( void ) { if ( pm->ps->legsTimer > 400 ) {//not at the end of the anim - float animLen = PM_AnimLength( 0, BOTH_WALL_RUN_RIGHT ); + float animLen = PM_AnimLength( 0, (animNumber_t)BOTH_WALL_RUN_RIGHT ); if ( pm->ps->legsTimer < animLen - 400 ) {//not at start of anim VectorMA( pm->ps->origin, 16, right, traceto ); @@ -1033,11 +1153,11 @@ static qboolean PM_CheckJump( void ) } if ( anim != -1 ) { - int parts; - pm->trace( &trace, pm->ps->origin, mins, maxs, traceto, pm->ps->clientNum, CONTENTS_SOLID|CONTENTS_BODY ); if ( trace.fraction < 1.0f ) {//flip off wall + int parts = 0; + if ( anim == BOTH_WALL_RUN_LEFT_FLIP ) { pm->ps->velocity[0] *= 0.5f; @@ -1057,7 +1177,7 @@ static qboolean PM_CheckJump( void ) } PM_SetAnim( parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0 ); //FIXME: do damage to traceEnt, like above? - pm->ps->pm_flags |= PMF_JUMP_HELD;//PMF_JUMPING|PMF_SLOW_MO_FALL; + //pm->ps->pm_flags |= PMF_JUMPING|PMF_SLOW_MO_FALL; pm->cmd.upmove = 0; } } @@ -1395,10 +1515,18 @@ static void PM_AirMove( void ) { VectorNormalize (pml.forward); VectorNormalize (pml.right); - for ( i = 0 ; i < 2 ; i++ ) { - wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; + if ( gPMDoSlowFall ) + {//no air-control + VectorClear( wishvel ); + } + else + { + for ( i = 0 ; i < 2 ; i++ ) + { + wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove; + } + wishvel[2] = 0; } - wishvel[2] = 0; VectorCopy (wishvel, wishdir); wishspeed = VectorNormalize(wishdir); @@ -1702,7 +1830,7 @@ static int PM_TryRoll( void ) return 0; } - if (pm->ps->weapon != WP_SABER || BG_HasYsalimari(pm->gametype, pm->ps) || + if (pm->ps->weapon != WP_SABER || BG_HasYsalamiri(pm->gametype, pm->ps) || !BG_CanUseFPNow(pm->gametype, pm->ps, pm->cmd.serverTime, FP_LEVITATION)) { return 0; @@ -1810,10 +1938,30 @@ static void PM_CrashLand( void ) { } } + /* if (pm->ps->forceHandExtend == HANDEXTEND_NONE) { pm->ps->forceHandExtend = HANDEXTEND_WEAPONREADY; } + */ + if (pm->ps->weapon != WP_SABER) + { //saber handles its own anims + if (pm->ps->weapon == WP_DISRUPTOR && pm->ps->zoomMode == 1) + { + PM_StartTorsoAnim( TORSO_WEAPONREADY4 ); + } + else + { + if (pm->ps->weapon == WP_EMPLACED_GUN) + { + PM_StartTorsoAnim( BOTH_GUNSIT1 ); + } + else + { + PM_StartTorsoAnim( WeaponReadyAnim[pm->ps->weapon] ); + } + } + } //just a stupid hack to push us back into our "idle" stance if (!BG_InSpecialJump(pm->ps->legsAnim) || @@ -3058,7 +3206,8 @@ static void PM_Weapon( void ) { { //saber handles its own anims if (pm->ps->weapon == WP_DISRUPTOR && pm->ps->zoomMode == 1) { - PM_StartTorsoAnim( TORSO_WEAPONREADY4 ); + //PM_StartTorsoAnim( TORSO_WEAPONREADY4 ); + PM_StartTorsoAnim( TORSO_RAISEWEAP1); } else { @@ -3068,10 +3217,17 @@ static void PM_Weapon( void ) { } else { - PM_StartTorsoAnim( WeaponReadyAnim[pm->ps->weapon] ); + //PM_StartTorsoAnim( WeaponReadyAnim[pm->ps->weapon] ); + PM_StartTorsoAnim( TORSO_RAISEWEAP1); } } } + + //we now go into a weapon raise anim after every force hand extend. + //this is so that my holster-view-weapon-when-hand-extend stuff works. + pm->ps->weaponstate = WEAPON_RAISING; + pm->ps->weaponTime += 250; + pm->ps->forceHandExtend = HANDEXTEND_NONE; } else if (pm->ps->forceHandExtend != HANDEXTEND_NONE) @@ -3679,8 +3835,8 @@ void PM_AdjustAttackStates( pmove_t *pm ) // disruptor alt-fire should toggle the zoom mode, but only bother doing this for the player? if ( pm->ps->weapon == WP_DISRUPTOR && pm->ps->weaponstate == WEAPON_READY ) { - if ( !(pm->ps->eFlags & EF_ALT_FIRING) && (pm->cmd.buttons & BUTTON_ALT_ATTACK) && - pm->cmd.upmove <= 0 && !pm->cmd.forwardmove && !pm->cmd.rightmove) + if ( !(pm->ps->eFlags & EF_ALT_FIRING) && (pm->cmd.buttons & BUTTON_ALT_ATTACK) /*&& + pm->cmd.upmove <= 0 && !pm->cmd.forwardmove && !pm->cmd.rightmove*/) { // We just pressed the alt-fire key if ( !pm->ps->zoomMode ) @@ -3722,12 +3878,15 @@ void PM_AdjustAttackStates( pmove_t *pm ) pm->ps->zoomLocked = qtrue; } } + //This seemed like a good idea, but apparently it confuses people. So disabled for now. + /* else if (!(pm->ps->eFlags & EF_ALT_FIRING) && (pm->cmd.buttons & BUTTON_ALT_ATTACK) && (pm->cmd.upmove > 0 || pm->cmd.forwardmove || pm->cmd.rightmove)) { //if you try to zoom while moving, just convert it into a primary attack pm->cmd.buttons &= ~BUTTON_ALT_ATTACK; pm->cmd.buttons |= BUTTON_ATTACK; } + */ if (pm->cmd.upmove > 0 || pm->cmd.forwardmove || pm->cmd.rightmove) { @@ -3756,6 +3915,19 @@ void PM_AdjustAttackStates( pmove_t *pm ) amount = 0; } } + else if (pm->ps->weapon == WP_DISRUPTOR) //still perform certain checks, even if the weapon is not ready + { + if (pm->cmd.upmove > 0 || pm->cmd.forwardmove || pm->cmd.rightmove) + { + if (pm->ps->zoomMode == 1 && pm->ps->zoomLockTime < pm->cmd.serverTime) + { //check for == 1 so we can't turn binoculars off with disruptor alt fire + pm->ps->zoomMode = 0; + pm->ps->zoomTime = pm->ps->commandTime; + pm->ps->zoomLocked = qfalse; + PM_AddEvent(EV_DISRUPTOR_ZOOMSOUND); + } + } + } /* // set the firing flag for continuous beam weapons @@ -3812,12 +3984,17 @@ void PM_AdjustAttackStates( pmove_t *pm ) // disruptor should convert a main fire to an alt-fire if the gun is currently zoomed if ( pm->ps->weapon == WP_DISRUPTOR) { - if ( pm->cmd.buttons & BUTTON_ATTACK && pm->ps->zoomMode == 1) + if ( pm->cmd.buttons & BUTTON_ATTACK && pm->ps->zoomMode == 1 && pm->ps->zoomLocked) { // converting the main fire to an alt-fire pm->cmd.buttons |= BUTTON_ALT_ATTACK; pm->ps->eFlags |= EF_ALT_FIRING; } + else if ( pm->cmd.buttons & BUTTON_ALT_ATTACK && pm->ps->zoomMode == 1 && pm->ps->zoomLocked) + { + pm->cmd.buttons &= ~BUTTON_ALT_ATTACK; + pm->ps->eFlags &= ~EF_ALT_FIRING; + } } } @@ -4004,7 +4181,14 @@ void BG_AdjustClientSpeed(playerState_t *ps, usercmd_t *cmd, int svTime) if ( BG_InRoll( ps, ps->legsAnim ) && ps->speed > 200 ) { //can't roll unless you're able to move normally BG_CmdForRoll( ps->legsAnim, cmd ); - ps->speed = ps->legsTimer/1.5;//450; + if ((ps->legsAnim&~ANIM_TOGGLEBIT) == BOTH_ROLL_B) + { //backwards roll is pretty fast, should also be slower + ps->speed = ps->legsTimer/2.5; + } + else + { + ps->speed = ps->legsTimer/1.5;//450; + } if (ps->speed > 600) { ps->speed = 600; @@ -4024,6 +4208,8 @@ void trap_SnapVector( float *v ); void PmoveSingle (pmove_t *pmove) { pm = pmove; + gPMDoSlowFall = PM_DoSlowFall(); + // this counter lets us debug movement problems with a journal // by setting a conditional breakpoint fot the previous frame c_pmove++; @@ -4157,6 +4343,8 @@ void PmoveSingle (pmove_t *pmove) { pml.frametime = pml.msec * 0.001; + PM_AdjustAngleForWallRun(pm->ps, &pm->cmd, qtrue); + // update the viewangles PM_UpdateViewAngles( pm->ps, &pm->cmd ); @@ -4208,6 +4396,11 @@ void PmoveSingle (pmove_t *pmove) { return; // no movement at all } + if (gPMDoSlowFall) + { + pm->ps->gravity *= 0.5; + } + // set watertype, and waterlevel PM_SetWaterLevel(); pml.previous_waterlevel = pmove->waterlevel; @@ -4282,6 +4475,11 @@ void PmoveSingle (pmove_t *pmove) { // snap some parts of playerstate to save network bandwidth trap_SnapVector( pm->ps->velocity ); + + if (gPMDoSlowFall) + { + pm->ps->gravity *= 2; + } } diff --git a/CODE-mp/game/bg_public.h b/CODE-mp/game/bg_public.h index bcf28e5..eac0a4b 100644 --- a/CODE-mp/game/bg_public.h +++ b/CODE-mp/game/bg_public.h @@ -40,6 +40,8 @@ #define CROUCH_VIEWHEIGHT (CROUCH_MAXS_2+STANDARD_VIEWHEIGHT_OFFSET)//12 #define DEAD_VIEWHEIGHT -16 +#define MAX_CLIENT_SCORE_SEND 20 + // // config strings are a general means of communicating variable length strings // from the server to all connected clients. @@ -72,6 +74,8 @@ #define CS_ITEMS 27 // string of 0's and 1's that tell which items are present #define CS_CLIENT_JEDIMASTER 28 // current jedi master +#define CS_CLIENT_DUELWINNER 29 // current duel round winner - needed for printing at top of scoreboard +#define CS_CLIENT_DUELISTS 30 // client numbers for both current duelists. Needed for a number of client-side things. // these are also in be_aas_def.h - argh (rjr) #define CS_MODELS 32 @@ -199,16 +203,18 @@ typedef enum { FORCE_MASTERY_UNINITIATED, FORCE_MASTERY_INITIATE, FORCE_MASTERY_PADAWAN, - FORCE_MASTERY_DISCIPLE, FORCE_MASTERY_JEDI, + FORCE_MASTERY_JEDI_GUARDIAN, FORCE_MASTERY_JEDI_ADEPT, + FORCE_MASTERY_JEDI_KNIGHT, FORCE_MASTERY_JEDI_MASTER, - FORCE_MASTERY_JEDI_LORD, NUM_FORCE_MASTERY_LEVELS }; extern char *forceMasteryLevels[NUM_FORCE_MASTERY_LEVELS]; extern int forceMasteryPoints[NUM_FORCE_MASTERY_LEVELS]; +extern int bgForcePowerCost[NUM_FORCE_POWERS][NUM_FORCE_POWER_LEVELS]; + // pmove->pm_flags #define PMF_DUCKED 1 #define PMF_JUMP_HELD 2 @@ -404,7 +410,7 @@ typedef enum { PW_FORCE_ENLIGHTENED_LIGHT, PW_FORCE_ENLIGHTENED_DARK, PW_FORCE_BOON, - PW_YSALIMARI, + PW_YSALAMIRI, PW_NUM_POWERUPS @@ -451,6 +457,17 @@ typedef enum { #define EVENT_VALID_MSEC 300 +typedef enum +{ + PDSOUND_NONE, + PDSOUND_PROTECTHIT, + PDSOUND_PROTECT, + PDSOUND_ABSORBHIT, + PDSOUND_ABSORB, + PDSOUND_FORCEJUMP, + PDSOUND_FORCEGRIP +} pdSounds_t; + typedef enum { EV_NONE, @@ -498,6 +515,10 @@ typedef enum { EV_DISRUPTOR_HIT, EV_DISRUPTOR_ZOOMSOUND, + EV_PREDEFSOUND, + + EV_TEAM_POWER, + EV_SCREENSHAKE, EV_USE, // +Use key @@ -574,6 +595,7 @@ typedef enum { EV_GIVE_NEW_RANK, EV_SET_FREE_SABER, + EV_SET_FORCE_DISABLE, EV_WEAPON_CHARGE, EV_WEAPON_CHARGE_ALT, @@ -710,7 +732,7 @@ typedef struct gitem_s { char *view_model; char *icon; - char *pickup_name; // for printing on pickup +// char *pickup_name; // for printing on pickup int quantity; // for ammo how much, or duration of powerup itemType_t giType; // IT_* flags @@ -725,7 +747,9 @@ typedef struct gitem_s { extern gitem_t bg_itemlist[]; extern int bg_numItems; -gitem_t *BG_FindItem( const char *pickupName ); +float vectoyaw( const vec3_t vec ); + +gitem_t *BG_FindItem( const char *classname ); gitem_t *BG_FindItemForWeapon( weapon_t weapon ); gitem_t *BG_FindItemForPowerup( powerup_t pw ); gitem_t *BG_FindItemForHoldable( holdable_t pw ); @@ -964,6 +988,8 @@ typedef struct extern saberMoveData_t saberMoveData[LS_MOVE_MAX]; +qboolean BG_LegalizedForcePowers(char *powerOut, int maxRank, qboolean freeSaber, int teamForce, int gametype, int fpDisabled); + //BG anim utility functions: qboolean BG_InSpecialJump( int anim ); qboolean BG_InSaberStandAnim( int anim ); @@ -1000,7 +1026,7 @@ qboolean BG_ParseAnimationFile(const char *filename); int BG_GetItemIndexByTag(int tag, int type); -qboolean BG_HasYsalimari(int gametype, playerState_t *ps); +qboolean BG_HasYsalamiri(int gametype, playerState_t *ps); qboolean BG_CanUseFPNow(int gametype, playerState_t *ps, int time, forcePowers_t power); void *BG_Alloc ( int size ); diff --git a/CODE-mp/game/bg_saber.c b/CODE-mp/game/bg_saber.c index ec335dc..e6ad967 100644 --- a/CODE-mp/game/bg_saber.c +++ b/CODE-mp/game/bg_saber.c @@ -24,10 +24,12 @@ void BG_ForcePowerDrain( playerState_t *ps, forcePowers_t forcePower, int overri //take away the power int drain = overrideAmt; + /* if (ps->powerups[PW_FORCE_BOON]) { return; } + */ if ( !drain ) { @@ -1229,7 +1231,7 @@ void PM_WeaponLightsaber(void) pm->ps->weaponTime < 1 && pm->ps->saberCanThrow && pm->ps->fd.forcePower >= forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW] && - !BG_HasYsalimari(pm->gametype, pm->ps) && + !BG_HasYsalamiri(pm->gametype, pm->ps) && BG_CanUseFPNow(pm->gametype, pm->ps, pm->cmd.serverTime, FP_SABERTHROW) ) { //might as well just check for a saber throw right here @@ -1408,7 +1410,7 @@ void PM_WeaponLightsaber(void) if (pm->ps->saberBlocked != BLOCKED_ATK_BOUNCE && pm->ps->saberBlocked != BLOCKED_PARRY_BROKEN && pm->ps->weaponTime < 1) { - pm->ps->torsoTimer = SABER_BLOCK_DUR*2; + pm->ps->torsoTimer = SABER_BLOCK_DUR; pm->ps->weaponTime = pm->ps->torsoTimer; } @@ -1620,6 +1622,10 @@ weapChecks: /* if ( PM_HasAnimation( pm->gent, saberMoveData[newmove].animToUse ) ) */ + + assert( bgGlobalAnimations[saberMoveData[newmove].animToUse].firstFrame != 0 || + bgGlobalAnimations[saberMoveData[newmove].animToUse].numFrames != 0); + if (1) { anim = saberMoveData[newmove].animToUse; @@ -1712,6 +1718,11 @@ void PM_SetSaberMove(short newMove) pm->ps->saberAttackChainCount++; } + if (pm->ps->saberAttackChainCount > 16) + { //for the sake of being able to send the value over the net within a reasonable bit count + pm->ps->saberAttackChainCount = 16; + } + if ( pm->ps->fd.saberAnimLevel > FORCE_LEVEL_1 && !BG_SaberInIdle( newMove ) && !PM_SaberInParry( newMove ) && !PM_SaberInReflect( newMove ) && !BG_SaberInSpecial(newMove)) {//readies, parries and reflections have only 1 level diff --git a/CODE-mp/game/bg_weapons.c b/CODE-mp/game/bg_weapons.c index 1781f42..eeafe2b 100644 --- a/CODE-mp/game/bg_weapons.c +++ b/CODE-mp/game/bg_weapons.c @@ -52,7 +52,7 @@ weaponData_t weaponData[WP_NUM_WEAPONS] = 400, // int fireTime; // Amount of time between firings 8192, // int range; // Range of weapon 0, // int altEnergyPerShot; // Amount of energy used for alt-fire - 800, // int altFireTime; // Amount of time between alt-firings + 400, // int altFireTime; // Amount of time between alt-firings 8192, // int altRange; // Range of alt-fire 0, // int chargeSubTime; // ms interval for subtracting ammo during charge 0, // int altChargeSubTime; // above for secondary @@ -116,18 +116,18 @@ weaponData_t weaponData[WP_NUM_WEAPONS] = // "Tenloss Disruptor Rifle",// char classname[32]; // Spawning name AMMO_POWERCELL, // int ammoIndex; // Index to proper ammo slot 5, // int ammoLow; // Count when ammo is low - 4, // int energyPerShot; // Amount of energy used per shot + 5, // int energyPerShot; // Amount of energy used per shot 600, // int fireTime; // Amount of time between firings 8192, // int range; // Range of weapon - 10, // int altEnergyPerShot; // Amount of energy used for alt-fire + 6, // int altEnergyPerShot; // Amount of energy used for alt-fire 1300, // int altFireTime; // Amount of time between alt-firings 8192, // int altRange; // Range of alt-fire 0, // int chargeSubTime; // ms interval for subtracting ammo during charge - 0, // int altChargeSubTime; // above for secondary + 200, // int altChargeSubTime; // above for secondary 0, // int chargeSub; // amount to subtract during charge on each interval - 0, //int altChargeSub; // above for secondary + 3, //int altChargeSub; // above for secondary 0, // int maxCharge; // stop subtracting once charged for this many ms - 0 // int altMaxCharge; // above for secondary + 1700 // int altMaxCharge; // above for secondary }, { // WP_BOWCASTER // "Wookiee Bowcaster", // char classname[32]; // Spawning name @@ -139,11 +139,11 @@ weaponData_t weaponData[WP_NUM_WEAPONS] = 5, // int altEnergyPerShot; // Amount of energy used for alt-fire 750, // int altFireTime; // Amount of time between alt-firings 8192, // int altRange; // Range of alt-fire - 200, // int chargeSubTime; // ms interval for subtracting ammo during charge + 400, // int chargeSubTime; // ms interval for subtracting ammo during charge 0, // int altChargeSubTime; // above for secondary - 1, // int chargeSub; // amount to subtract during charge on each interval + 5, // int chargeSub; // amount to subtract during charge on each interval 0, //int altChargeSub; // above for secondary - 1500, // int maxCharge; // stop subtracting once charged for this many ms + 1700, // int maxCharge; // stop subtracting once charged for this many ms 0 // int altMaxCharge; // above for secondary }, { // WP_REPEATER @@ -151,7 +151,7 @@ weaponData_t weaponData[WP_NUM_WEAPONS] = AMMO_METAL_BOLTS, // int ammoIndex; // Index to proper ammo slot 5, // int ammoLow; // Count when ammo is low 1, // int energyPerShot; // Amount of energy used per shot - 50, // int fireTime; // Amount of time between firings + 100, // int fireTime; // Amount of time between firings 8192, // int range; // Range of weapon 8, // int altEnergyPerShot; // Amount of energy used for alt-fire 800, // int altFireTime; // Amount of time between alt-firings @@ -167,25 +167,25 @@ weaponData_t weaponData[WP_NUM_WEAPONS] = // "DEMP2", // char classname[32]; // Spawning name AMMO_POWERCELL, // int ammoIndex; // Index to proper ammo slot 5, // int ammoLow; // Count when ammo is low - 10, // int energyPerShot; // Amount of energy used per shot + 8, // int energyPerShot; // Amount of energy used per shot 500, // int fireTime; // Amount of time between firings 8192, // int range; // Range of weapon - 4, // int altEnergyPerShot; // Amount of energy used for alt-fire + 6, // int altEnergyPerShot; // Amount of energy used for alt-fire 900, // int altFireTime; // Amount of time between alt-firings 8192, // int altRange; // Range of alt-fire 0, // int chargeSubTime; // ms interval for subtracting ammo during charge - 700, // int altChargeSubTime; // above for secondary + 250, // int altChargeSubTime; // above for secondary 0, // int chargeSub; // amount to subtract during charge on each interval - 4, // int altChargeSub; // above for secondary + 3, // int altChargeSub; // above for secondary 0, // int maxCharge; // stop subtracting once charged for this many ms - 2200 // int altMaxCharge; // above for secondary + 2100 // int altMaxCharge; // above for secondary }, { // WP_FLECHETTE // "Golan Arms Flechette", // char classname[32]; // Spawning name AMMO_METAL_BOLTS, // int ammoIndex; // Index to proper ammo slot 5, // int ammoLow; // Count when ammo is low 10, // int energyPerShot; // Amount of energy used per shot - 550, // int fireTime; // Amount of time between firings + 700, // int fireTime; // Amount of time between firings 8192, // int range; // Range of weapon 15, // int altEnergyPerShot; // Amount of energy used for alt-fire 800, // int altFireTime; // Amount of time between alt-firings @@ -201,11 +201,11 @@ weaponData_t weaponData[WP_NUM_WEAPONS] = // "Merr-Sonn Missile System", // char classname[32]; // Spawning name AMMO_ROCKETS, // int ammoIndex; // Index to proper ammo slot 5, // int ammoLow; // Count when ammo is low - 20, // int energyPerShot; // Amount of energy used per shot - 600, // int fireTime; // Amount of time between firings + 1, // int energyPerShot; // Amount of energy used per shot + 900, // int fireTime; // Amount of time between firings 8192, // int range; // Range of weapon - 25, // int altEnergyPerShot; // Amount of energy used for alt-fire - 800, // int altFireTime; // Amount of time between alt-firings + 2, // int altEnergyPerShot; // Amount of energy used for alt-fire + 1200, // int altFireTime; // Amount of time between alt-firings 8192, // int altRange; // Range of alt-fire 0, // int chargeSubTime; // ms interval for subtracting ammo during charge 0, // int altChargeSubTime; // above for secondary @@ -308,7 +308,7 @@ ammoData_t ammoData[AMMO_MAX] = }, { // AMMO_ROCKETS // "", // char icon[32]; // Name of ammo icon file - 300 // int max; // Max amount player can hold of ammo + 25 // int max; // Max amount player can hold of ammo }, { // AMMO_EMPLACED // "", // char icon[32]; // Name of ammo icon file diff --git a/CODE-mp/game/g_active.c b/CODE-mp/game/g_active.c index 8c7227d..7a50337 100644 --- a/CODE-mp/game/g_active.c +++ b/CODE-mp/game/g_active.c @@ -65,6 +65,19 @@ void P_DamageFeedback( gentity_t *player ) { player->pain_debounce_time = level.time + 700; G_AddEvent( player, EV_PAIN, player->health ); client->ps.damageEvent++; + + if (client->damage_armor && !client->damage_blood) + { + client->ps.damageType = 1; //pure shields + } + else if (client->damage_armor) + { + client->ps.damageType = 2; //shields and health + } + else + { + client->ps.damageType = 0; //pure health + } } @@ -806,49 +819,6 @@ void ClientEvents( gentity_t *ent, int oldEventSequence ) { } -/* -============== -StuckInOtherClient -============== -*/ -static int StuckInOtherClient(gentity_t *ent) { - int i; - gentity_t *ent2; - - ent2 = &g_entities[0]; - for ( i = 0; i < MAX_CLIENTS; i++, ent2++ ) { - if ( ent2 == ent ) { - continue; - } - if ( !ent2->inuse ) { - continue; - } - if ( !ent2->client ) { - continue; - } - if ( ent2->health <= 0 ) { - continue; - } - // - if (ent2->r.absmin[0] > ent->r.absmax[0]) - continue; - if (ent2->r.absmin[1] > ent->r.absmax[1]) - continue; - if (ent2->r.absmin[2] > ent->r.absmax[2]) - continue; - if (ent2->r.absmax[0] < ent->r.absmin[0]) - continue; - if (ent2->r.absmax[1] < ent->r.absmin[1]) - continue; - if (ent2->r.absmax[2] < ent->r.absmin[2]) - continue; - return qtrue; - } - return qfalse; -} - -void BotTestSolid(vec3_t origin); - /* ============== SendPendingPredictableEvents @@ -1286,6 +1256,8 @@ void ClientThink_real( gentity_t *ent ) { player_die(ent, ent, ent, 100000, MOD_FALLING); respawn(ent); ent->client->ps.fallingToDeath = 0; + + G_MuteSound(ent->s.number, CHAN_VOICE); //stop screaming, because you are dead! } if (ent->client->ps.otherKillerTime > level.time && @@ -1293,6 +1265,7 @@ void ClientThink_real( gentity_t *ent ) { ent->client->ps.otherKillerDebounceTime < level.time) { ent->client->ps.otherKillerTime = 0; + ent->client->ps.otherKiller = ENTITYNUM_NONE; } else if (ent->client->ps.otherKillerTime > level.time && ent->client->ps.groundEntityNum == ENTITYNUM_NONE) @@ -1303,8 +1276,8 @@ void ClientThink_real( gentity_t *ent ) { } } - WP_ForcePowersUpdate( ent, ucmd ); //update any active force powers - WP_SaberPositionUpdate(ent, ucmd); //check the server-side saber point, do apprioriate server-side actions (effects are cs-only) +// WP_ForcePowersUpdate( ent, msec, ucmd); //update any active force powers +// WP_SaberPositionUpdate(ent, ucmd); //check the server-side saber point, do apprioriate server-side actions (effects are cs-only) if ((ent->client->pers.cmd.buttons & BUTTON_USE) && ent->client->ps.useDelay < level.time) { @@ -1734,7 +1707,7 @@ void SpectatorClientEndFrame( gentity_t *ent ) { // drop them to free spectators unless they are dedicated camera followers if ( ent->client->sess.spectatorClient >= 0 ) { ent->client->sess.spectatorState = SPECTATOR_FREE; - ClientBegin( ent->client - level.clients ); + ClientBegin( ent->client - level.clients, qtrue ); } } } diff --git a/CODE-mp/game/g_bot.c b/CODE-mp/game/g_bot.c index 889d0a3..a42679d 100644 --- a/CODE-mp/game/g_bot.c +++ b/CODE-mp/game/g_bot.c @@ -132,6 +132,7 @@ int G_GetMapTypeBits(char *type) if( *type ) { if( strstr( type, "ffa" ) ) { typeBits |= (1 << GT_FFA); + typeBits |= (1 << GT_TEAM); } if( strstr( type, "holocron" ) ) { typeBits |= (1 << GT_HOLOCRON); @@ -629,7 +630,7 @@ void G_CheckBotSpawn( void ) { if ( botSpawnQueue[n].spawnTime > level.time ) { continue; } - ClientBegin( botSpawnQueue[n].clientNum ); + ClientBegin( botSpawnQueue[n].clientNum, qfalse ); botSpawnQueue[n].spawnTime = 0; if( g_gametype.integer == GT_SINGLE_PLAYER ) { @@ -657,7 +658,7 @@ static void AddBotToSpawnQueue( int clientNum, int delay ) { } G_Printf( S_COLOR_YELLOW "Unable to delay spawn\n" ); - ClientBegin( clientNum ); + ClientBegin( clientNum, qfalse ); } @@ -718,7 +719,7 @@ static void G_AddBot( const char *name, float skill, const char *team, int delay char *s; char *botname; char *model; - char *headmodel; +// char *headmodel; char userinfo[MAX_INFO_STRING]; int preTeam = 0; @@ -764,7 +765,7 @@ static void G_AddBot( const char *name, float skill, const char *team, int delay key = "team_model"; Info_SetValueForKey( userinfo, key, model ); - key = "headmodel"; +/* key = "headmodel"; headmodel = Info_ValueForKey( botinfo, key ); if ( !*headmodel ) { headmodel = model; @@ -772,7 +773,7 @@ static void G_AddBot( const char *name, float skill, const char *team, int delay Info_SetValueForKey( userinfo, key, headmodel ); key = "team_headmodel"; Info_SetValueForKey( userinfo, key, headmodel ); - +*/ key = "gender"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { @@ -807,8 +808,9 @@ static void G_AddBot( const char *name, float skill, const char *team, int delay // have the server allocate a client slot clientNum = trap_BotAllocateClient(); if ( clientNum == -1 ) { - G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" ); - G_Printf( S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n" ); +// G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" ); +// G_Printf( S_COLOR_RED "Start server with more 'open' slots.\n" ); + trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "UNABLE_TO_ADD_BOT"))); return; } @@ -889,7 +891,7 @@ static void G_AddBot( const char *name, float skill, const char *team, int delay } if( delay == 0 ) { - ClientBegin( clientNum ); + ClientBegin( clientNum, qfalse ); return; } @@ -972,7 +974,7 @@ void Svcmd_BotList_f( void ) { for (i = 0; i < g_numBots; i++) { strcpy(name, Info_ValueForKey( g_botInfos[i], "name" )); if ( !*name ) { - strcpy(name, "UnnamedPlayer"); + strcpy(name, "Padawan"); } strcpy(funname, Info_ValueForKey( g_botInfos[i], "funname" )); if ( !*funname ) { diff --git a/CODE-mp/game/g_client.c b/CODE-mp/game/g_client.c index 227eef5..8da145f 100644 --- a/CODE-mp/game/g_client.c +++ b/CODE-mp/game/g_client.c @@ -69,7 +69,6 @@ void SP_info_player_intermission( gentity_t *ent ) { #define JMSABER_RESPAWN_TIME 20000 //in case it gets stuck somewhere no one can reach - void ThrowSaberToAttacker(gentity_t *self, gentity_t *attacker) { gentity_t *ent = &g_entities[self->client->ps.saberIndex]; @@ -78,7 +77,26 @@ void ThrowSaberToAttacker(gentity_t *self, gentity_t *attacker) if (!ent || ent->enemy != self) { //something has gone very wrong (this should never happen) - return; + //but in case it does.. find the saber manually +#ifdef _DEBUG + Com_Printf("Lost the saber! Attempting to use global pointer..\n"); +#endif + ent = gJMSaberEnt; + + if (!ent) + { +#ifdef _DEBUG + Com_Printf("The global pointer was NULL. This is a bad thing.\n"); +#endif + return; + } + +#ifdef _DEBUG + Com_Printf("Got it (%i). Setting enemy to client %i.\n", ent->s.number, self->s.number); +#endif + + ent->enemy = self; + self->client->ps.saberIndex = ent->s.number; } trap_SetConfigstring ( CS_CLIENT_JEDIMASTER, "-1" ); @@ -180,7 +198,7 @@ void JMSaberThink(gentity_t *ent) void JMSaberTouch(gentity_t *self, gentity_t *other, trace_t *trace) { int i = 0; - gentity_t *te; +// gentity_t *te; if (!other || !other->client || other->health < 1) { @@ -253,9 +271,12 @@ void JMSaberTouch(gentity_t *self, gentity_t *other, trace_t *trace) self->s.modelGhoul2 = 0; self->s.eType = ET_GENERAL; + /* te = G_TempEntity( vec3_origin, EV_DESTROY_GHOUL2_INSTANCE ); te->r.svFlags |= SVF_BROADCAST; te->s.eventParm = self->s.number; + */ + G_KillG2Queue(self->s.number); return; } @@ -291,6 +312,8 @@ void SP_info_jedimaster_start(gentity_t *ent) ent->r.contents = CONTENTS_TRIGGER; ent->clipmask = MASK_SOLID; + ent->isSaberEntity = qtrue; + ent->bounceCount = -5; ent->physicsObject = qtrue; @@ -621,6 +644,11 @@ void CopyToBodyQue( gentity_t *ent ) { gentity_t *body; int contents; + if (level.intermissiontime) + { + return; + } + trap_UnlinkEntity (ent); // if client is in a nodrop area, don't leave the body @@ -922,7 +950,7 @@ static void ClientCleanName( const char *in, char *out, int outSize ) { // don't allow empty names if( *p == 0 || colorlessLen == 0 ) { - Q_strncpyz( p, "UnnamedPlayer", outSize ); + Q_strncpyz( p, "Padawan", outSize ); } } @@ -1085,7 +1113,7 @@ void ClientUserinfoChanged( int clientNum ) { int teamTask, teamLeader, team, health; char *s; char model[MAX_QPATH]; - char headModel[MAX_QPATH]; + //char headModel[MAX_QPATH]; char forcePowers[MAX_QPATH]; char oldname[MAX_STRING_CHARS]; gclient_t *client; @@ -1148,10 +1176,10 @@ void ClientUserinfoChanged( int clientNum ) { // set model if( g_gametype.integer >= GT_TEAM ) { Q_strncpyz( model, Info_ValueForKey (userinfo, "team_model"), sizeof( model ) ); - Q_strncpyz( headModel, Info_ValueForKey (userinfo, "team_headmodel"), sizeof( headModel ) ); + //Q_strncpyz( headModel, Info_ValueForKey (userinfo, "team_headmodel"), sizeof( headModel ) ); } else { Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) ); - Q_strncpyz( headModel, Info_ValueForKey (userinfo, "headmodel"), sizeof( headModel ) ); + //Q_strncpyz( headModel, Info_ValueForKey (userinfo, "headmodel"), sizeof( headModel ) ); } Q_strncpyz( forcePowers, Info_ValueForKey (userinfo, "forcepowers"), sizeof( forcePowers ) ); @@ -1228,13 +1256,13 @@ void ClientUserinfoChanged( int clientNum ) { // send over a subset of the userinfo keys so other clients can // print scoreboards, display models, and play custom sounds if ( ent->r.svFlags & SVF_BOT ) { - s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d", - client->pers.netname, team, model, headModel, c1, c2, + s = va("n\\%s\\t\\%i\\model\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d", + client->pers.netname, team, model, c1, c2, client->pers.maxHealth, client->sess.wins, client->sess.losses, Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader ); } else { - s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\g_redteam\\%s\\g_blueteam\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d", - client->pers.netname, client->sess.sessionTeam, model, headModel, redTeam, blueTeam, c1, c2, + s = va("n\\%s\\t\\%i\\model\\%s\\g_redteam\\%s\\g_blueteam\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d", + client->pers.netname, client->sess.sessionTeam, model, redTeam, blueTeam, c1, c2, client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader); } @@ -1287,7 +1315,9 @@ char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) { value = Info_ValueForKey (userinfo, "password"); if ( g_password.string[0] && Q_stricmp( g_password.string, "none" ) && strcmp( g_password.string, value) != 0) { - return "Invalid password"; + static char sTemp[1024]; + Q_strncpyz(sTemp, G_GetStripEdString("SVINGAME","INVALID_PASSWORD"), sizeof (sTemp) ); + return sTemp;// return "Invalid password"; } } @@ -1344,6 +1374,8 @@ char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) { return NULL; } +void G_WriteClientSessionData( gclient_t *client ); + /* =========== ClientBegin @@ -1353,7 +1385,7 @@ to be placed into the level. This will happen every level load, and on transition between teams, but doesn't happen on respawns ============ */ -void ClientBegin( int clientNum ) { +void ClientBegin( int clientNum, qboolean allowTeamReset ) { gentity_t *ent; gclient_t *client; gentity_t *tent; @@ -1362,6 +1394,47 @@ void ClientBegin( int clientNum ) { ent = g_entities + clientNum; + if ((ent->r.svFlags & SVF_BOT) && g_gametype.integer >= GT_TEAM) + { + if (allowTeamReset) + { + const char *team = "Red"; + int preSess; + + //SetTeam(ent, ""); + ent->client->sess.sessionTeam = PickTeam(-1); + trap_GetUserinfo(clientNum, userinfo, MAX_INFO_STRING); + + if (ent->client->sess.sessionTeam == TEAM_SPECTATOR) + { + ent->client->sess.sessionTeam = TEAM_RED; + } + + if (ent->client->sess.sessionTeam == TEAM_RED) + { + team = "Red"; + } + else + { + team = "Blue"; + } + + Info_SetValueForKey( userinfo, "team", team ); + + trap_SetUserinfo( clientNum, userinfo ); + + ent->client->ps.persistant[ PERS_TEAM ] = ent->client->sess.sessionTeam; + + preSess = ent->client->sess.sessionTeam; + G_ReadSessionData( ent->client ); + ent->client->sess.sessionTeam = preSess; + G_WriteClientSessionData(ent->client); + ClientUserinfoChanged( clientNum ); + ClientBegin(clientNum, qfalse); + return; + } + } + client = level.clients + clientNum; if ( ent->r.linked ) { @@ -1480,6 +1553,7 @@ void ClientSpawn(gentity_t *ent) { forcedata_t savedForce; void *ghoul2save; int saveSaberNum = ENTITYNUM_NONE; + int wDisable = 0; index = ent - g_entities; client = ent->client; @@ -1638,7 +1712,16 @@ void ClientSpawn(gentity_t *ent) { } } - if (!g_weaponDisable.integer || !(g_weaponDisable.integer & (1 << WP_BRYAR_PISTOL))) + if (g_gametype.integer == GT_TOURNAMENT) + { + wDisable = g_duelWeaponDisable.integer; + } + else + { + wDisable = g_weaponDisable.integer; + } + + if (!wDisable || !(wDisable & (1 << WP_BRYAR_PISTOL))) { client->ps.stats[STAT_WEAPONS] |= ( 1 << WP_BRYAR_PISTOL ); } diff --git a/CODE-mp/game/g_cmds.c b/CODE-mp/game/g_cmds.c index eda581f..0169acc 100644 --- a/CODE-mp/game/g_cmds.c +++ b/CODE-mp/game/g_cmds.c @@ -32,6 +32,11 @@ void DeathmatchScoreboardMessage( gentity_t *ent ) { numSorted = level.numConnectedClients; + if (numSorted > MAX_CLIENT_SCORE_SEND) + { + numSorted = MAX_CLIENT_SCORE_SEND; + } + for (i=0 ; i < numSorted ; i++) { int ping; @@ -63,12 +68,15 @@ void DeathmatchScoreboardMessage( gentity_t *ent ) { perfect, cl->ps.persistant[PERS_CAPTURES]); j = strlen(entry); - if (stringlength + j > 1024) + if (stringlength + j > 1022) break; strcpy (string + stringlength, entry); stringlength += j; } + //still want to know the total # of clients + i = level.numConnectedClients; + trap_SendServerCommand( ent-g_entities, va("scores %i %i %i%s", i, level.teamScores[TEAM_RED], level.teamScores[TEAM_BLUE], string ) ); @@ -235,6 +243,17 @@ void Cmd_Give_f (gentity_t *ent) else give_all = qfalse; + if (give_all) + { + i = 0; + while (i < HI_NUM_HOLDABLE) + { + ent->client->ps.stats[STAT_HOLDABLE_ITEMS] |= (1 << i); + i++; + } + i = 0; + } + if (give_all || Q_stricmp( name, "health") == 0) { if (trap_Argc() == 3) { @@ -607,6 +626,8 @@ void SetTeam( gentity_t *ent, char *s ) { team = TEAM_BLUE; } else { // pick the team with the least number of players + //For now, don't do this. The legalize function will set powers properly now. + /* if (g_forceBasedTeams.integer) { if (ent->client->ps.fd.forceSide == FORCE_LIGHTSIDE) @@ -620,8 +641,9 @@ void SetTeam( gentity_t *ent, char *s ) { } else { + */ team = PickTeam( clientNum ); - } + //} } if ( g_teamForceBalance.integer ) { @@ -632,12 +654,15 @@ void SetTeam( gentity_t *ent, char *s ) { // We allow a spread of two if ( team == TEAM_RED && counts[TEAM_RED] - counts[TEAM_BLUE] > 1 ) { + //For now, don't do this. The legalize function will set powers properly now. + /* if (g_forceBasedTeams.integer && ent->client->ps.fd.forceSide == FORCE_DARKSIDE) { trap_SendServerCommand( ent->client->ps.clientNum, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "TOOMANYRED_SWITCH")) ); } else + */ { trap_SendServerCommand( ent->client->ps.clientNum, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "TOOMANYRED")) ); @@ -645,12 +670,15 @@ void SetTeam( gentity_t *ent, char *s ) { return; // ignore the request } if ( team == TEAM_BLUE && counts[TEAM_BLUE] - counts[TEAM_RED] > 1 ) { + //For now, don't do this. The legalize function will set powers properly now. + /* if (g_forceBasedTeams.integer && ent->client->ps.fd.forceSide == FORCE_LIGHTSIDE) { trap_SendServerCommand( ent->client->ps.clientNum, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "TOOMANYBLUE_SWITCH")) ); } else + */ { trap_SendServerCommand( ent->client->ps.clientNum, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "TOOMANYBLUE")) ); @@ -661,6 +689,8 @@ void SetTeam( gentity_t *ent, char *s ) { // It's ok, the team we are switching to has less or same number of players } + //For now, don't do this. The legalize function will set powers properly now. + /* if (g_forceBasedTeams.integer) { if (team == TEAM_BLUE && ent->client->ps.fd.forceSide != FORCE_LIGHTSIDE) @@ -674,6 +704,7 @@ void SetTeam( gentity_t *ent, char *s ) { return; } } + */ } else { // force them to spectators if there aren't any spots free @@ -742,7 +773,7 @@ void SetTeam( gentity_t *ent, char *s ) { // get and distribute relevent paramters ClientUserinfoChanged( clientNum ); - ClientBegin( clientNum ); + ClientBegin( clientNum, qfalse ); } /* @@ -818,34 +849,34 @@ void Cmd_ForceChanged_f( gentity_t *ent ) { char fpChStr[1024]; const char *buf; - int i = 0; - int ccount = 0; // Cmd_Kill_f(ent); if (ent->client->sess.sessionTeam == TEAM_SPECTATOR) { //if it's a spec, just make the changes now - trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "FORCEAPPLIED")) ); + //trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "FORCEAPPLIED")) ); + //No longer print it, as the UI calls this a lot. WP_InitForcePowers( ent ); - return; + goto argCheck; } buf = G_GetStripEdString("SVINGAME", "FORCEPOWERCHANGED"); strcpy(fpChStr, buf); - while (i < 1024 && fpChStr[i]) - { - if (ccount > 24 && fpChStr[i] == ' ') - { - fpChStr[i] = '\n'; - ccount = 0; - } - ccount++; - i++; - } - - trap_SendServerCommand( ent-g_entities, va("cp \"%s\n\"", fpChStr) ); + trap_SendServerCommand( ent-g_entities, va("print \"%s%s\n\"", S_COLOR_GREEN, fpChStr) ); ent->client->ps.fd.forceDoInit = 1; +argCheck: + if (trap_Argc() > 1) + { + char arg[MAX_TOKEN_CHARS]; + + trap_Argv( 1, arg, sizeof( arg ) ); + + if (arg && arg[0]) + { //if there's an arg, assume it's a combo team command from the UI. + Cmd_Team_f(ent); + } + } } /* @@ -1352,8 +1383,9 @@ static const char *gameNames[] = { "Duel", "Single Player", "Team FFA", - "Saga", - "Capture the Flag" + "N/A", + "Capture the Flag", + "Capture the Ysalamiri" }; /* @@ -1434,7 +1466,8 @@ void Cmd_CallVote_f( gentity_t *ent ) { if (!G_DoesMapSupportGametype(arg2, trap_Cvar_VariableIntegerValue("g_gametype"))) { - trap_SendServerCommand( ent-g_entities, "print \"You can't vote for this map, it isn't supported by the current gametype.\n\"" ); + //trap_SendServerCommand( ent-g_entities, "print \"You can't vote for this map, it isn't supported by the current gametype.\n\"" ); + trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStripEdString("SVINGAME", "NOVOTE_MAPNOTSUPPORTEDBYGAME")) ); return; } @@ -1939,19 +1972,22 @@ void Cmd_SaberAttackCycle_f(gentity_t *ent) { selectLevel = FORCE_LEVEL_1; } +/* +#ifndef FINAL_BUILD switch ( selectLevel ) { case FORCE_LEVEL_1: - trap_SendServerCommand( ent-g_entities, va("print \"Saber Attack Set: %sfast\n\"", S_COLOR_GREEN) ); + trap_SendServerCommand( ent-g_entities, va("print \"Lightsaber Combat Style: %sfast\n\"", S_COLOR_BLUE) ); break; case FORCE_LEVEL_2: - trap_SendServerCommand( ent-g_entities, va("print \"Saber Attack Set: %smedium\n\"", S_COLOR_YELLOW) ); + trap_SendServerCommand( ent-g_entities, va("print \"Lightsaber Combat Style: %smedium\n\"", S_COLOR_YELLOW) ); break; case FORCE_LEVEL_3: - trap_SendServerCommand( ent-g_entities, va("print \"Saber Attack Set: %sstrong\n\"", S_COLOR_RED) ); + trap_SendServerCommand( ent-g_entities, va("print \"Lightsaber Combat Style: %sstrong\n\"", S_COLOR_RED) ); break; } - +#endif +*/ if (ent->client->ps.weaponTime <= 0) { //not busy, set it now ent->client->ps.fd.saberAnimLevel = selectLevel; @@ -2381,7 +2417,8 @@ void ClientCommand( int clientNum ) { { if (Q_stricmp(cmd, "addbot") == 0) { //because addbot isn't a recognized command unless you're the server, but it is in the menus regardless - trap_SendServerCommand( clientNum, va("print \"You can only add bots as the server.\n\"" ) ); +// trap_SendServerCommand( clientNum, va("print \"You can only add bots as the server.\n\"" ) ); + trap_SendServerCommand( clientNum, va("print \"%s.\n\"", G_GetStripEdString("SVINGAME", "ONLY_ADD_BOTS_AS_SERVER"))); } else { diff --git a/CODE-mp/game/g_combat.c b/CODE-mp/game/g_combat.c index 91d0edc..ebd03f2 100644 --- a/CODE-mp/game/g_combat.c +++ b/CODE-mp/game/g_combat.c @@ -8,8 +8,6 @@ void BotDamageNotification(gclient_t *bot, gentity_t *attacker); //end rww -extern int protectHitSound; - void ThrowSaberToAttacker(gentity_t *self, gentity_t *attacker); void ObjectDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) @@ -738,6 +736,12 @@ void GibEntity( gentity_t *self, int killer ) { self->r.contents = 0; } +void BodyRid(gentity_t *ent) +{ + trap_UnlinkEntity( ent ); + ent->physicsObject = qfalse; +} + /* ================== body_die @@ -745,16 +749,49 @@ body_die */ void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) { // NOTENOTE No gibbing right now, this is star wars. - if(1) // if ( self->health > GIB_HEALTH ) + qboolean doDisint = qfalse; + + if (self->health < (GIB_HEALTH+1)) + { + self->health = GIB_HEALTH+1; + + if (self->client && (level.time - self->client->respawnTime) < 2000) + { + doDisint = qfalse; + } + else + { + doDisint = qtrue; + } + } + + if (self->client && (self->client->ps.eFlags & EF_DISINTEGRATION)) { return; } - if ( !g_blood.integer ) { - self->health = GIB_HEALTH+1; + else if (self->s.eFlags & EF_DISINTEGRATION) + { return; } - GibEntity( self, 0 ); + if (doDisint) + { + if (self->client) + { + self->client->ps.eFlags |= EF_DISINTEGRATION; + VectorCopy(self->client->ps.origin, self->client->ps.lastHitLoc); + } + else + { + self->s.eFlags |= EF_DISINTEGRATION; + VectorCopy(self->r.currentOrigin, self->s.origin2); + + //since it's the corpse entity, tell it to "remove" itself + self->think = BodyRid; + self->nextthink = level.time + 1000; + } + return; + } } @@ -1168,6 +1205,26 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, void G_CheckForDismemberment(gentity_t *ent, vec3_t point, int damage, int deathAnim); +gentity_t *G_GetJediMaster(void) +{ + int i = 0; + gentity_t *ent; + + while (i < MAX_CLIENTS) + { + ent = &g_entities[i]; + + if (ent && ent->inuse && ent->client && ent->client->ps.isJediMaster) + { + return ent; + } + + i++; + } + + return NULL; +} + /* ================== player_die @@ -1276,7 +1333,33 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int attacker->client->lastkilled_client = self->s.number; if ( attacker == self || OnSameTeam (self, attacker ) ) { - AddScore( attacker, self->r.currentOrigin, -1 ); + if (g_gametype.integer == GT_TOURNAMENT) + { //in duel, if you kill yourself, the person you are dueling against gets a kill for it + int otherClNum = -1; + if (level.sortedClients[0] == self->s.number) + { + otherClNum = level.sortedClients[1]; + } + else if (level.sortedClients[1] == self->s.number) + { + otherClNum = level.sortedClients[0]; + } + + if (otherClNum >= 0 && otherClNum < MAX_CLIENTS && + g_entities[otherClNum].inuse && g_entities[otherClNum].client && + otherClNum != attacker->s.number) + { + AddScore( &g_entities[otherClNum], self->r.currentOrigin, 1 ); + } + else + { + AddScore( attacker, self->r.currentOrigin, -1 ); + } + } + else + { + AddScore( attacker, self->r.currentOrigin, -1 ); + } if (g_gametype.integer == GT_JEDIMASTER) { if (self->client && self->client->ps.isJediMaster) @@ -1301,6 +1384,15 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int self->client->ps.isJediMaster = qfalse; } } + else + { + gentity_t *jmEnt = G_GetJediMaster(); + + if (jmEnt && jmEnt->client) + { + AddScore( jmEnt, self->r.currentOrigin, 1 ); + } + } } else { @@ -1343,7 +1435,34 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int ThrowSaberToAttacker(self, NULL); self->client->ps.isJediMaster = qfalse; } - AddScore( self, self->r.currentOrigin, -1 ); + + if (g_gametype.integer == GT_TOURNAMENT) + { //in duel, if you kill yourself, the person you are dueling against gets a kill for it + int otherClNum = -1; + if (level.sortedClients[0] == self->s.number) + { + otherClNum = level.sortedClients[1]; + } + else if (level.sortedClients[1] == self->s.number) + { + otherClNum = level.sortedClients[0]; + } + + if (otherClNum >= 0 && otherClNum < MAX_CLIENTS && + g_entities[otherClNum].inuse && g_entities[otherClNum].client && + otherClNum != self->s.number) + { + AddScore( &g_entities[otherClNum], self->r.currentOrigin, 1 ); + } + else + { + AddScore( self, self->r.currentOrigin, -1 ); + } + } + else + { + AddScore( self, self->r.currentOrigin, -1 ); + } } // Add team bonuses @@ -1494,8 +1613,8 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int // the body can still be gibbed self->die = body_die; - //rww - even though we have no gibbing, if you shoot the body it will disappear unless it doesn't take damage - self->takedamage = qfalse; + //It won't gib, it will disintegrate (because this is Star Wars). + self->takedamage = qtrue; // globally cycle through the different death animations i = ( i + 1 ) % 3; @@ -2004,6 +2123,26 @@ void G_CheckForDismemberment(gentity_t *ent, vec3_t point, int damage, int death G_Dismember(ent, boltPoint, hitLocUse, 90, 0, deathAnim); } +qboolean G_ThereIsAMaster(void) +{ + int i = 0; + gentity_t *ent; + + while (i < MAX_CLIENTS) + { + ent = &g_entities[i]; + + if (ent && ent->client && ent->client->ps.isJediMaster) + { + return qtrue; + } + + i++; + } + + return qfalse; +} + /* ============ T_Damage @@ -2059,6 +2198,10 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, { return; } + else if (attacker && attacker->client && mod != MOD_SABER) + { + return; + } } if (attacker && attacker->client && attacker->client->ps.duelInProgress) { @@ -2066,6 +2209,10 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, { return; } + else if (targ && targ->client && mod != MOD_SABER) + { + return; + } } if (targ && targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE))) @@ -2141,6 +2288,12 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel); VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity); + if (attacker && attacker->client && attacker != targ) + { + targ->client->ps.otherKiller = attacker->s.number; + targ->client->ps.otherKillerTime = level.time + 5000; + targ->client->ps.otherKillerDebounceTime = level.time + 100; + } // set the timer so that the other client can't cancel // out the movement immediately if ( !targ->client->ps.pm_time ) { @@ -2169,6 +2322,14 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, } } + if (g_gametype.integer == GT_JEDIMASTER && !g_friendlyFire.integer && + targ && targ->client && attacker && attacker->client && + targ != attacker && !targ->client->ps.isJediMaster && !attacker->client->ps.isJediMaster && + G_ThereIsAMaster()) + { + return; + } + if (targ->client && targ->s.shouldtarget && targ->s.teamowner && attacker && attacker->inuse && attacker->client && targ->s.owner >= 0 && targ->s.owner < MAX_CLIENTS) { @@ -2321,12 +2482,13 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, { int maxtake = take; - G_Sound(targ, CHAN_AUTO, protectHitSound); + //G_Sound(targ, CHAN_AUTO, protectHitSound); + G_PreDefSound(targ->client->ps.origin, PDSOUND_PROTECTHIT); if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_1) { famt = 1; - hamt = 0.5; + hamt = 0.40; if (maxtake > 100) { @@ -2336,7 +2498,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, else if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_2) { famt = 0.5; - hamt = 0.75; + hamt = 0.60; if (maxtake > 200) { @@ -2346,7 +2508,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, else if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_3) { famt = 0.25; - hamt = 1; + hamt = 0.80; if (maxtake > 400) { @@ -2358,6 +2520,10 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, { targ->client->ps.fd.forcePower -= maxtake*famt; } + else + { + targ->client->ps.fd.forcePower -= (maxtake*famt)/2; + } subamt = (maxtake*hamt)+(take-maxtake); if (targ->client->ps.fd.forcePower < 0) { @@ -2412,7 +2578,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, if (take) { if (targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE)) && (inflictor->client || attacker->client)) { - take /= (targ->client->ps.fd.forcePowerLevel[FP_RAGE]); + take /= (targ->client->ps.fd.forcePowerLevel[FP_RAGE]+1); } targ->health = targ->health - take; if ( targ->client ) { diff --git a/CODE-mp/game/g_items.c b/CODE-mp/game/g_items.c index 4a3f99d..bec9d22 100644 --- a/CODE-mp/game/g_items.c +++ b/CODE-mp/game/g_items.c @@ -32,8 +32,20 @@ extern gentity_t *droppedBlueFlag; #define MAX_SENTRY_DISTANCE 256 // For more than four players, adjust the respawn times, up to 1/4. -int adjustRespawnTime(float respawnTime) +int adjustRespawnTime(float preRespawnTime, int itemType, int itemTag) { + float respawnTime = preRespawnTime; + + if (itemType == IT_WEAPON) + { + if (itemTag == WP_THERMAL || + itemTag == WP_TRIP_MINE || + itemTag == WP_DET_PACK) + { //special case for these, use ammo respawn rate + respawnTime = RESPAWN_AMMO; + } + } + if (!g_adaptRespawn.integer) { return((int)respawnTime); @@ -670,6 +682,57 @@ void pas_think( gentity_t *ent ) vec3_t enemyDir, org; vec3_t frontAngles, backAngles; vec3_t desiredAngles; + int iEntityList[MAX_GENTITIES]; + int numListedEntities; + int i = 0; + qboolean clTrapped = qfalse; + vec3_t testMins, testMaxs; + + testMins[0] = ent->r.currentOrigin[0] + ent->r.mins[0]+4; + testMins[1] = ent->r.currentOrigin[1] + ent->r.mins[1]+4; + testMins[2] = ent->r.currentOrigin[2] + ent->r.mins[2]+4; + + testMaxs[0] = ent->r.currentOrigin[0] + ent->r.maxs[0]-4; + testMaxs[1] = ent->r.currentOrigin[1] + ent->r.maxs[1]-4; + testMaxs[2] = ent->r.currentOrigin[2] + ent->r.maxs[2]-4; + + numListedEntities = trap_EntitiesInBox( testMins, testMaxs, iEntityList, MAX_GENTITIES ); + + while (i < numListedEntities) + { + if (iEntityList[i] < MAX_CLIENTS) + { //client stuck inside me. go nonsolid. + int clNum = iEntityList[i]; + + numListedEntities = trap_EntitiesInBox( g_entities[clNum].r.absmin, g_entities[clNum].r.absmax, iEntityList, MAX_GENTITIES ); + + i = 0; + while (i < numListedEntities) + { + if (iEntityList[i] == ent->s.number) + { + clTrapped = qtrue; + break; + } + i++; + } + break; + } + + i++; + } + + if (clTrapped) + { + ent->r.contents = 0; + ent->s.fireflag = 0; + ent->nextthink = level.time + FRAMETIME; + return; + } + else + { + ent->r.contents = CONTENTS_SOLID; + } if (!g_entities[ent->boltpoint3].inuse || !g_entities[ent->boltpoint3].client || g_entities[ent->boltpoint3].client->sess.sessionTeam != ent->boltpoint2) @@ -679,7 +742,7 @@ void pas_think( gentity_t *ent ) return; } - G_RunObject(ent); +// G_RunObject(ent); if ( !ent->damage ) { @@ -822,7 +885,7 @@ void pas_think( gentity_t *ent ) { pas_fire( ent ); ent->s.fireflag = 1; - ent->attackDebounceTime = level.time + 100; + ent->attackDebounceTime = level.time + 200; } else { @@ -1055,6 +1118,13 @@ int Pickup_Powerup( gentity_t *ent, gentity_t *other ) { other->client->ps.powerups[ent->item->giTag] += quantity * 1000; + if (ent->item->giTag == PW_YSALAMIRI) + { + other->client->ps.powerups[PW_FORCE_ENLIGHTENED_LIGHT] = 0; + other->client->ps.powerups[PW_FORCE_ENLIGHTENED_DARK] = 0; + other->client->ps.powerups[PW_FORCE_BOON] = 0; + } + // give any nearby players a "denied" anti-reward for ( i = 0 ; i < level.maxclients ; i++ ) { vec3_t delta; @@ -1114,7 +1184,7 @@ int Pickup_Holdable( gentity_t *ent, gentity_t *other ) { G_LogWeaponItem(other->s.number, ent->item->giTag); - return adjustRespawnTime(RESPAWN_HOLDABLE); + return adjustRespawnTime(RESPAWN_HOLDABLE, ent->item->giType, ent->item->giTag); } @@ -1140,7 +1210,7 @@ int Pickup_Ammo (gentity_t *ent, gentity_t *other) Add_Ammo (other, ent->item->giTag, quantity); - return adjustRespawnTime(RESPAWN_AMMO); + return adjustRespawnTime(RESPAWN_AMMO, ent->item->giType, ent->item->giTag); } //====================================================================== @@ -1194,10 +1264,10 @@ int Pickup_Weapon (gentity_t *ent, gentity_t *other) { // team deathmatch has slow weapon respawns if ( g_gametype.integer == GT_TEAM ) { - return adjustRespawnTime(RESPAWN_TEAM_WEAPON); + return adjustRespawnTime(RESPAWN_TEAM_WEAPON, ent->item->giType, ent->item->giTag); } - return adjustRespawnTime(g_weaponRespawn.integer); + return adjustRespawnTime(g_weaponRespawn.integer, ent->item->giType, ent->item->giTag); } @@ -1231,7 +1301,7 @@ int Pickup_Health (gentity_t *ent, gentity_t *other) { return RESPAWN_MEGAHEALTH; } - return adjustRespawnTime(RESPAWN_HEALTH); + return adjustRespawnTime(RESPAWN_HEALTH, ent->item->giType, ent->item->giTag); } //====================================================================== @@ -1244,7 +1314,7 @@ int Pickup_Armor( gentity_t *ent, gentity_t *other ) other->client->ps.stats[STAT_ARMOR] = other->client->ps.stats[STAT_MAX_HEALTH] * ent->item->giTag; } - return adjustRespawnTime(RESPAWN_ARMOR); + return adjustRespawnTime(RESPAWN_ARMOR, ent->item->giType, ent->item->giTag); } //====================================================================== @@ -1372,6 +1442,28 @@ void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) { break; case IT_AMMO: respawn = Pickup_Ammo(ent, other); + if (ent->item->giTag == AMMO_THERMAL || ent->item->giTag == AMMO_TRIPMINE || ent->item->giTag == AMMO_DETPACK) + { + int weapForAmmo = 0; + + if (ent->item->giTag == AMMO_THERMAL) + { + weapForAmmo = WP_THERMAL; + } + else if (ent->item->giTag == AMMO_TRIPMINE) + { + weapForAmmo = WP_TRIP_MINE; + } + else + { + weapForAmmo = WP_DET_PACK; + } + + if (other && other->client && other->client->ps.ammo[weaponData[weapForAmmo].ammoIndex] > 0 ) + { + other->client->ps.stats[STAT_WEAPONS] |= (1 << weapForAmmo); + } + } // predict = qfalse; predict = qtrue; break; @@ -1419,7 +1511,7 @@ void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) { } // powerup pickups are global broadcasts - if ( ent->item->giType == IT_POWERUP || ent->item->giType == IT_TEAM) { + if ( /*ent->item->giType == IT_POWERUP ||*/ ent->item->giType == IT_TEAM) { // if we want the global sound to play if (!ent->speed) { gentity_t *te; @@ -1631,14 +1723,24 @@ free fall from their spawn points void FinishSpawningItem( gentity_t *ent ) { trace_t tr; vec3_t dest; + int wDisable = 0; // gitem_t *item; // VectorSet( ent->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS ); // VectorSet( ent->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS ); + if (g_gametype.integer == GT_TOURNAMENT) + { + wDisable = g_duelWeaponDisable.integer; + } + else + { + wDisable = g_weaponDisable.integer; + } + if (ent->item->giType == IT_WEAPON && - g_weaponDisable.integer && - (g_weaponDisable.integer & (1 << ent->item->giTag))) + wDisable && + (wDisable & (1 << ent->item->giTag))) { if (g_gametype.integer != GT_JEDIMASTER) { @@ -1678,6 +1780,33 @@ void FinishSpawningItem( gentity_t *ent ) { } } + if (g_gametype.integer == GT_HOLOCRON) + { + if (ent->item->giType == IT_POWERUP) + { + if (ent->item->giTag == PW_FORCE_ENLIGHTENED_LIGHT || + ent->item->giTag == PW_FORCE_ENLIGHTENED_DARK) + { + G_FreeEntity(ent); + return; + } + } + } + + if (g_forcePowerDisable.integer) + { //if force powers disabled, don't add force powerups + if (ent->item->giType == IT_POWERUP) + { + if (ent->item->giTag == PW_FORCE_ENLIGHTENED_LIGHT || + ent->item->giTag == PW_FORCE_ENLIGHTENED_DARK || + ent->item->giTag == PW_FORCE_BOON) + { + G_FreeEntity(ent); + return; + } + } + } + if (g_gametype.integer == GT_TOURNAMENT) { if ( ent->item->giType == IT_ARMOR || @@ -1806,11 +1935,11 @@ void G_CheckTeamItems( void ) { gitem_t *item; // check for the two flags - item = BG_FindItem( "Red Flag" ); + item = BG_FindItem( "team_CTF_redflag" ); if ( !item || !itemRegistered[ item - bg_itemlist ] ) { G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_redflag in map" ); } - item = BG_FindItem( "Blue Flag" ); + item = BG_FindItem( "team_CTF_blueflag" ); if ( !item || !itemRegistered[ item - bg_itemlist ] ) { G_Printf( S_COLOR_YELLOW "WARNING: No team_CTF_blueflag in map" ); } @@ -1940,6 +2069,15 @@ void G_BounceItem( gentity_t *ent, trace_t *trace ) { // cut the velocity to keep from bouncing forever VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta ); + if ((ent->s.weapon == WP_DET_PACK && ent->s.eType == ET_GENERAL && ent->physicsObject)) + { //detpacks only + if (ent->touch) + { + ent->touch(ent, &g_entities[trace->entityNum], trace); + return; + } + } + // check for stop if ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) { trace->endpos[2] += 1.0; // make sure it is off ground @@ -1952,6 +2090,15 @@ void G_BounceItem( gentity_t *ent, trace_t *trace ) { VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin); VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase ); ent->s.pos.trTime = level.time; + + if (ent->s.eType == ET_HOLOCRON || + (ent->s.shouldtarget && ent->s.eType == ET_GENERAL && ent->physicsObject)) + { //holocrons and sentry guns + if (ent->touch) + { + ent->touch(ent, &g_entities[trace->entityNum], trace); + } + } } diff --git a/CODE-mp/game/g_local.h b/CODE-mp/game/g_local.h index a12e610..e50a665 100644 --- a/CODE-mp/game/g_local.h +++ b/CODE-mp/game/g_local.h @@ -236,6 +236,8 @@ struct gentity_s { int bolt_Waist; int bolt_Motion; + qboolean isSaberEntity; + int damageRedirect; //if entity takes damage, redirect to.. int damageRedirectTo; //this entity number @@ -582,6 +584,8 @@ void G_Sound( gentity_t *ent, int channel, int soundIndex ); void G_SoundAtLoc( vec3_t loc, int channel, int soundIndex ); void G_EntitySound( gentity_t *ent, int channel, int soundIndex ); void TryUse( gentity_t *ent ); +void G_SendG2KillQueue(void); +void G_KillG2Queue(int entNum); void G_FreeEntity( gentity_t *e ); qboolean G_EntitiesFree( void ); @@ -598,8 +602,6 @@ extern void G_RunObject ( gentity_t *ent ); float *tv (float x, float y, float z); char *vtos( const vec3_t v ); -float vectoyaw( const vec3_t vec ); - void G_AddPredictableEvent( gentity_t *ent, int event, int eventParm ); void G_AddEvent( gentity_t *ent, int event, int eventParm ); void G_SetOrigin( gentity_t *ent, vec3_t origin ); @@ -784,7 +786,7 @@ const char *G_GetStripEdString(char *refSection, char *refName); char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ); void ClientUserinfoChanged( int clientNum ); void ClientDisconnect( int clientNum ); -void ClientBegin( int clientNum ); +void ClientBegin( int clientNum, qboolean allowTeamReset ); void ClientCommand( int clientNum ); // @@ -839,7 +841,8 @@ void BotInterbreedEndMatch( void ); qboolean G_DoesMapSupportGametype(const char *mapname, int gametype); const char *G_RefreshNextMap(int gametype, qboolean forced); -// w_saber.c +// w_force.c / w_saber.c +void G_PreDefSound(vec3_t org, int pdSound); qboolean HasSetSaberOnly(void); void WP_ForcePowerStop( gentity_t *self, forcePowers_t forcePower ); void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ); @@ -931,6 +934,7 @@ extern vmCvar_t g_forceRegenTime; extern vmCvar_t g_spawnInvulnerability; extern vmCvar_t g_forcePowerDisable; extern vmCvar_t g_weaponDisable; +extern vmCvar_t g_duelWeaponDisable; extern vmCvar_t g_fraglimit; extern vmCvar_t g_duel_fraglimit; extern vmCvar_t g_timelimit; @@ -1188,8 +1192,8 @@ int trap_GeneticParentsAndChildSelection(int numranks, float *ranks, int *paren void trap_SnapVector( float *v ); -void trap_SP_RegisterServer( const char *package ); -void trap_SP_Register(char *file ); +qboolean trap_SP_RegisterServer( const char *package ); +qboolean trap_SP_Register(char *file ); int trap_SP_GetStringTextString(const char *text, char *buffer, int bufferLength); qboolean trap_ROFF_Clean( void ); diff --git a/CODE-mp/game/g_main.c b/CODE-mp/game/g_main.c index 69bd059..42563f7 100644 --- a/CODE-mp/game/g_main.c +++ b/CODE-mp/game/g_main.c @@ -18,6 +18,8 @@ typedef struct { gentity_t g_entities[MAX_GENTITIES]; gclient_t g_clients[MAX_CLIENTS]; +qboolean gDuelExit = qfalse; + vmCvar_t g_gametype; vmCvar_t g_MaxHolocronCarry; vmCvar_t g_ff_objectives; @@ -31,6 +33,7 @@ vmCvar_t g_forceRegenTime; vmCvar_t g_spawnInvulnerability; vmCvar_t g_forcePowerDisable; vmCvar_t g_weaponDisable; +vmCvar_t g_duelWeaponDisable; vmCvar_t g_fraglimit; vmCvar_t g_duel_fraglimit; vmCvar_t g_timelimit; @@ -90,6 +93,9 @@ vmCvar_t g_dismember; vmCvar_t g_forceDodge; vmCvar_t g_timeouttospec; +int gDuelist1 = -1; +int gDuelist2 = -1; + // bk001129 - made static to avoid aliasing static cvarTable_t gameCvarTable[] = { // don't override the cheat state set by the system @@ -109,21 +115,22 @@ static cvarTable_t gameCvarTable[] = { { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse }, // change anytime vars - { &g_ff_objectives, "g_ff_objectives", "0", /*CVAR_SERVERINFO |*/ CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, + { &g_ff_objectives, "g_ff_objectives", "0", /*CVAR_SERVERINFO |*/ CVAR_NORESTART, 0, qtrue }, { &g_autoMapCycle, "g_autoMapCycle", "0", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, { &g_dmflags, "dmflags", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, - { &g_maxForceRank, "g_maxForceRank", "0", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH, 0, qfalse }, - { &g_forceBasedTeams, "g_forceBasedTeams", "0", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH, 0, qfalse }, - { &g_privateDuel, "g_privateDuel", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, + { &g_maxForceRank, "g_maxForceRank", "6", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_USERINFO | CVAR_LATCH, 0, qfalse }, + { &g_forceBasedTeams, "g_forceBasedTeams", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_USERINFO | CVAR_LATCH, 0, qfalse }, + { &g_privateDuel, "g_privateDuel", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, { &g_saberLocking, "g_saberLocking", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, - { &g_forceRegenTime, "g_forceRegenTime", "200", CVAR_ARCHIVE, 0, qtrue }, + { &g_forceRegenTime, "g_forceRegenTime", "200", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, { &g_spawnInvulnerability, "g_spawnInvulnerability", "3000", CVAR_ARCHIVE, 0, qtrue }, - { &g_forcePowerDisable, "g_forcePowerDisable", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, - { &g_weaponDisable, "g_weaponDisable", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, + { &g_forcePowerDisable, "g_forcePowerDisable", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH, 0, qtrue }, + { &g_weaponDisable, "g_weaponDisable", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH, 0, qtrue }, + { &g_duelWeaponDisable, "g_duelWeaponDisable", "1", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH, 0, qtrue }, { &g_fraglimit, "fraglimit", "20", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, { &g_duel_fraglimit, "duel_fraglimit", "10", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, @@ -164,7 +171,7 @@ static cvarTable_t gameCvarTable[] = { { &g_weaponRespawn, "g_weaponrespawn", "5", 0, 0, qtrue }, { &g_weaponTeamRespawn, "g_weaponTeamRespawn", "5", 0, 0, qtrue }, { &g_adaptRespawn, "g_adaptrespawn", "1", 0, 0, qtrue }, // Make weapons respawn faster with a lot of players. - { &g_forcerespawn, "g_forcerespawn", "20", 0, 0, qtrue }, + { &g_forcerespawn, "g_forcerespawn", "60", 0, 0, qtrue }, // One minute force respawn. Give a player enough time to reallocate force. { &g_inactivity, "g_inactivity", "0", 0, 0, qtrue }, { &g_debugMove, "g_debugMove", "0", 0, 0, qfalse }, { &g_debugDamage, "g_debugDamage", "0", 0, 0, qfalse }, @@ -188,8 +195,8 @@ static cvarTable_t gameCvarTable[] = { { &g_blueteam, "g_blueteam", "Rebellion", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO , 0, qtrue, qtrue }, { &g_singlePlayer, "ui_singlePlayerActive", "", 0, 0, qfalse, qfalse }, - { &g_enableDust, "g_enableDust", "0", CVAR_SERVERINFO, 0, qtrue, qfalse }, - { &g_enableBreath, "g_enableBreath", "0", CVAR_SERVERINFO, 0, qtrue, qfalse }, + { &g_enableDust, "g_enableDust", "0", 0, 0, qtrue, qfalse }, + { &g_enableBreath, "g_enableBreath", "0", 0, 0, qtrue, qfalse }, { &g_smoothClients, "g_smoothClients", "1", 0, 0, qfalse}, { &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO, 0, qfalse}, { &pmove_msec, "pmove_msec", "8", CVAR_SYSTEMINFO, 0, qfalse}, @@ -199,7 +206,7 @@ static cvarTable_t gameCvarTable[] = { { &g_dismember, "g_dismember", "0", 0, 0, qtrue }, { &g_forceDodge, "g_forceDodge", "1", 0, 0, qtrue }, - { &g_timeouttospec, "g_timeouttospec", "15", CVAR_ARCHIVE, 0, qfalse }, + { &g_timeouttospec, "g_timeouttospec", "70", CVAR_ARCHIVE, 0, qfalse }, }; // bk001129 - made static to avoid aliasing @@ -241,7 +248,7 @@ int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int a ClientDisconnect( arg0 ); return 0; case GAME_CLIENT_BEGIN: - ClientBegin( arg0 ); + ClientBegin( arg0, qtrue ); return 0; case GAME_CLIENT_COMMAND: ClientCommand( arg0 ); @@ -452,7 +459,7 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) { level.snd_fry = G_SoundIndex("sound/player/fry.wav"); // FIXME standing in lava / slime - trap_SP_RegisterServer("mp_svgame"); + //trap_SP_RegisterServer("mp_svgame"); if ( g_gametype.integer != GT_SINGLE_PLAYER && g_log.string[0] ) { if ( g_logSync.integer ) { @@ -525,6 +532,11 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) { trap_SetConfigstring ( CS_CLIENT_JEDIMASTER, "-1" ); } + trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("-1|-1") ); + trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("-1") ); + gDuelist1 = -1; + gDuelist2 = -1; + SaveRegisteredItems(); G_Printf ("-----------------------------------\n"); @@ -631,9 +643,9 @@ void AddTournamentPlayer( void ) { } // never change during intermission - if ( level.intermissiontime ) { - return; - } +// if ( level.intermissiontime ) { +// return; +// } nextInLine = NULL; @@ -724,6 +736,8 @@ void AdjustTournamentScores( void ) { if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) { level.clients[ clientNum ].sess.wins++; ClientUserinfoChanged( clientNum ); + + trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", clientNum ) ); } clientNum = level.sortedClients[1]; @@ -922,6 +936,18 @@ void CalculateRanks( void ) { trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) ); trap_SetConfigstring( CS_SCORES2, va("%i", level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE] ) ); } + + if (g_gametype.integer != GT_TOURNAMENT) + { //when not in duel, use this configstring to pass the index of the player currently in first place + if ( level.numConnectedClients >= 1 ) + { + trap_SetConfigstring ( CS_CLIENT_DUELWINNER, va("%i", level.sortedClients[0] ) ); + } + else + { + trap_SetConfigstring ( CS_CLIENT_DUELWINNER, "-1" ); + } + } } // see if it is time to end the level @@ -1023,6 +1049,8 @@ void FindIntermissionPoint( void ) { } +qboolean DuelLimitHit(void); + /* ================== BeginIntermission @@ -1038,7 +1066,17 @@ void BeginIntermission( void ) { // if in tournement mode, change the wins / losses if ( g_gametype.integer == GT_TOURNAMENT ) { + trap_SetConfigstring ( CS_CLIENT_DUELWINNER, "-1" ); + AdjustTournamentScores(); + if (DuelLimitHit()) + { + gDuelExit = qtrue; + } + else + { + gDuelExit = qfalse; + } } level.intermissiontime = level.time; @@ -1121,7 +1159,6 @@ void ExitLevel (void) { if (!DuelLimitHit()) { if ( !level.restarted ) { - RemoveTournamentLoser(); trap_SendConsoleCommand( EXEC_APPEND, "map_restart 0\n" ); level.restarted = qtrue; level.changemap = NULL; @@ -1130,10 +1167,6 @@ void ExitLevel (void) { return; } - //this means we hit the duel limit so reset the wins/losses - //but still push the loser to the back of the line, and retain the order for - //the map change - RemoveTournamentLoser(); DuelResetWinsLosses(); } @@ -1262,6 +1295,7 @@ void LogExit( const char *string ) { } } +qboolean gDidDuelStuff = qfalse; //gets reset on game reinit /* ================= @@ -1306,6 +1340,68 @@ void CheckIntermissionExit( void ) { } } + if ( g_gametype.integer == GT_TOURNAMENT && !gDidDuelStuff && + (level.time > level.intermissiontime + 2000) ) + { + gDidDuelStuff = qtrue; + + // if we are running a tournement map, kick the loser to spectator status, + // which will automatically grab the next spectator and restart + if (!DuelLimitHit()) + { + RemoveTournamentLoser(); + + AddTournamentPlayer(); + + if (level.numPlayingClients >= 2) + { + trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i", level.sortedClients[0], level.sortedClients[1] ) ); + trap_SetConfigstring ( CS_CLIENT_DUELWINNER, "-1" ); + + gDuelist1 = level.sortedClients[0]; + gDuelist2 = level.sortedClients[1]; + } + + return; + } + + //this means we hit the duel limit so reset the wins/losses + //but still push the loser to the back of the line, and retain the order for + //the map change + RemoveTournamentLoser(); + AddTournamentPlayer(); + if (level.numPlayingClients >= 2) + { + trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i", level.sortedClients[0], level.sortedClients[1] ) ); + trap_SetConfigstring ( CS_CLIENT_DUELWINNER, "-1" ); + + gDuelist1 = level.sortedClients[0]; + gDuelist2 = level.sortedClients[1]; + } + } + + if (g_gametype.integer == GT_TOURNAMENT && !gDuelExit) + { //in duel, we have different behaviour for between-round intermissions + if ( level.time > level.intermissiontime + 4000 ) + { //automatically go to next after 4 seconds + ExitLevel(); + return; + } + + for (i=0 ; i< g_maxclients.integer ; i++) + { //being in a "ready" state is not necessary here, so clear it for everyone + //yes, I also thinking holding this in a ps value uniquely for each player + //is bad and wrong, but it wasn't my idea. + cl = level.clients + i; + if ( cl->pers.connected != CON_CONNECTED ) + { + continue; + } + cl->ps.stats[STAT_CLIENTS_READY] = 0; + } + return; + } + // copy the readyMask to each player's stats so // it can be displayed on the scoreboard for (i=0 ; i< g_maxclients.integer ; i++) { @@ -1406,7 +1502,8 @@ void CheckExitRules( void ) { if ( g_timelimit.integer && !level.warmupTime ) { if ( level.time - level.startTime >= g_timelimit.integer*60000 ) { - trap_SendServerCommand( -1, "print \"Timelimit hit.\n\""); +// trap_SendServerCommand( -1, "print \"Timelimit hit.\n\""); + trap_SendServerCommand( -1, va("print \"%s.\n\"",G_GetStripEdString("SVINGAME", "TIMELIMIT_HIT"))); LogExit( "Timelimit hit." ); return; } @@ -1418,13 +1515,13 @@ void CheckExitRules( void ) { if ( g_gametype.integer < GT_CTF && g_fraglimit.integer ) { if ( level.teamScores[TEAM_RED] >= g_fraglimit.integer ) { - trap_SendServerCommand( -1, "print \"Red hit the kill limit.\n\"" ); + trap_SendServerCommand( -1, va("print \"Red %s\n\"", G_GetStripEdString("SVINGAME", "HIT_THE_KILL_LIMIT")) ); LogExit( "Kill limit hit." ); return; } if ( level.teamScores[TEAM_BLUE] >= g_fraglimit.integer ) { - trap_SendServerCommand( -1, "print \"Blue hit the kill limit.\n\"" ); + trap_SendServerCommand( -1, va("print \"Blue %s\n\"", G_GetStripEdString("SVINGAME", "HIT_THE_KILL_LIMIT")) ); LogExit( "Kill limit hit." ); return; } @@ -1441,6 +1538,7 @@ void CheckExitRules( void ) { if ( g_gametype.integer == GT_TOURNAMENT && g_duel_fraglimit.integer && cl->sess.wins >= g_duel_fraglimit.integer ) { LogExit( "Duel limit hit." ); + gDuelExit = qtrue; trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " hit the win limit.\n\"", cl->pers.netname ) ); return; @@ -1448,8 +1546,12 @@ void CheckExitRules( void ) { if ( cl->ps.persistant[PERS_SCORE] >= g_fraglimit.integer ) { LogExit( "Kill limit hit." ); - trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " hit the kill limit.\n\"", - cl->pers.netname ) ); + gDuelExit = qfalse; + trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " %s.\n\"", + cl->pers.netname, + G_GetStripEdString("SVINGAME", "HIT_THE_KILL_LIMIT") + ) + ); return; } } @@ -1481,7 +1583,6 @@ FUNCTIONS CALLED EVERY FRAME ======================================================================== */ - /* ============= CheckTournament @@ -1501,14 +1602,33 @@ void CheckTournament( void ) { // pull in a spectator if needed if ( level.numPlayingClients < 2 ) { AddTournamentPlayer(); + + if (level.numPlayingClients >= 2) + { + trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i", level.sortedClients[0], level.sortedClients[1] ) ); + gDuelist1 = level.sortedClients[0]; + gDuelist2 = level.sortedClients[1]; + } } - if (!g_warmup.integer) + if (level.numPlayingClients >= 2) + { + if (gDuelist1 == -1 || + gDuelist2 == -1) + { + trap_SetConfigstring ( CS_CLIENT_DUELISTS, va("%i|%i", level.sortedClients[0], level.sortedClients[1] ) ); + gDuelist1 = level.sortedClients[0]; + gDuelist2 = level.sortedClients[1]; + } + } + + //rww - It seems we have decided there will be no warmup in duel. + //if (!g_warmup.integer) { //don't care about any of this stuff then, just add people and leave me alone level.warmupTime = 0; return; } - +#if 0 // if we don't have two players, go back to "waiting for players" if ( level.numPlayingClients != 2 ) { if ( level.warmupTime != -1 ) { @@ -1552,6 +1672,7 @@ void CheckTournament( void ) { level.restarted = qtrue; return; } +#endif } else if ( g_gametype.integer != GT_SINGLE_PLAYER && level.warmupTime != 0 ) { int counts[TEAM_NUM_TEAMS]; qboolean notEnough = qfalse; @@ -1834,6 +1955,7 @@ G_RunFrame Advances the non-player objects in the world ================ */ + void G_RunFrame( int levelTime ) { int i; gentity_t *ent; @@ -1924,7 +2046,12 @@ int start, end; if ( i < MAX_CLIENTS ) { G_CheckClientTimeouts ( ent ); - + + if((!level.intermissiontime)&&!(ent->client->ps.pm_flags&PMF_FOLLOW)) + { + WP_ForcePowersUpdate(ent, &ent->client->pers.cmd ); + WP_SaberPositionUpdate(ent, &ent->client->pers.cmd); + } G_RunClient( ent ); continue; } @@ -1971,18 +2098,27 @@ end = trap_Milliseconds(); trap_Cvar_Set("g_listEntity", "0"); } + //At the end of the frame, send out the ghoul2 kill queue, if there is one + G_SendG2KillQueue(); + g_LastFrameTime = level.time; } const char *G_GetStripEdString(char *refSection, char *refName) { /* - char strText[MAX_STRING_CHARS]; - Com_sprintf(strText, MAX_STRING_CHARS, "%s_%s", refSection, refName); - return trap_SP_GetStringTextString(strText); - */ static char text[1024]={0}; trap_SP_GetStringTextString(va("%s_%s", refSection, refName), text, sizeof(text)); return text; + */ + + //Well, it would've been lovely doing it the above way, but it would mean mixing + //languages for the client depending on what the server is. So we'll mark this as + //a striped reference with @@@ and send the refname to the client, and when it goes + //to print it will get scanned for the striped reference indication and dealt with + //properly. + static char text[1024]={0}; + Com_sprintf(text, sizeof(text), "@@@%s", refName); + return text; } diff --git a/CODE-mp/game/g_misc.c b/CODE-mp/game/g_misc.c index 446a3c8..9e44cb2 100644 --- a/CODE-mp/game/g_misc.c +++ b/CODE-mp/game/g_misc.c @@ -515,7 +515,10 @@ void HolocronThink(gentity_t *ent) justthink: ent->nextthink = level.time + 50; - G_RunObject(ent); + if (ent->s.pos.trDelta[0] || ent->s.pos.trDelta[1] || ent->s.pos.trDelta[2]) + { + G_RunObject(ent); + } } void SP_misc_holocron(gentity_t *ent) @@ -574,13 +577,16 @@ void SP_misc_holocron(gentity_t *ent) { ent->count = NUM_FORCE_POWERS-1; } - +/* if (g_forcePowerDisable.integer && (g_forcePowerDisable.integer & (1 << ent->count))) { G_FreeEntity(ent); return; } +*/ + //No longer doing this, causing too many complaints about accidentally setting no force powers at all + //and starting a holocron game (making it basically just FFA) ent->enemy = NULL; @@ -803,19 +809,20 @@ void shield_power_converter_use( gentity_t *self, gentity_t *other, gentity_t *a } } -/*QUAKED misc_shield_floor_unit (1 0 0) (-16 -16 0) (16 16 32) -#MODELNAME="/models/items/a_shield_converter.md3" -Gives shield energy when used. - -"count" - max charge value (default 50) -"chargerate" - rechage 1 point every this many milliseconds (default 3000) -*/ +//QED comment is in bg_misc //------------------------------------------------------------ void SP_misc_shield_floor_unit( gentity_t *ent ) { vec3_t dest; trace_t tr; + if (g_gametype.integer != GT_CTF && + g_gametype.integer != GT_CTY) + { + G_FreeEntity( ent ); + return; + } + VectorSet( ent->r.mins, -16, -16, 0 ); VectorSet( ent->r.maxs, 16, 16, 40 ); @@ -844,6 +851,11 @@ void SP_misc_shield_floor_unit( gentity_t *ent ) ent->health = 60; } + if (!ent->model || !ent->model[0]) + { + ent->model = "/models/items/a_shield_converter.md3"; + } + ent->s.modelindex = G_ModelIndex( ent->model ); ent->s.eFlags = 0; @@ -948,7 +960,7 @@ void ammo_power_converter_use( gentity_t *self, gentity_t *other, gentity_t *act if (!self->s.loopSound) { - self->s.loopSound = G_SoundIndex("sound/player/suitenergy.wav"); + self->s.loopSound = G_SoundIndex("sound/player/pickupshield.wav"); } self->setTime = level.time + 100; @@ -1075,7 +1087,7 @@ void health_power_converter_use( gentity_t *self, gentity_t *other, gentity_t *a { if (!self->s.loopSound) { - self->s.loopSound = G_SoundIndex("sound/player/suitenergy.wav"); + self->s.loopSound = G_SoundIndex("sound/player/pickuphealth.wav"); } self->setTime = level.time + 100; diff --git a/CODE-mp/game/g_missile.c b/CODE-mp/game/g_missile.c index 3904bac..6e7f468 100644 --- a/CODE-mp/game/g_missile.c +++ b/CODE-mp/game/g_missile.c @@ -375,6 +375,8 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace ) { ent->s.weapon != WP_TRIP_MINE && ent->s.weapon != WP_DET_PACK && ent->s.weapon != WP_DEMP2 && + ent->methodOfDeath != MOD_REPEATER_ALT && + ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH && other->client->ps.saberBlockTime < level.time && WP_SaberCanBlock(other, ent->r.currentOrigin, 0, 0, qtrue, 0)) { //only block one projectile per 200ms (to prevent giant swarms of projectiles being blocked) @@ -387,9 +389,12 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace ) { VectorCopy(trace->plane.normal, te->s.angles); te->s.eventParm = 0; - if (other->client->ps.velocity[2] > 0 || + /*if (other->client->ps.velocity[2] > 0 || other->client->pers.cmd.forwardmove || other->client->pers.cmd.rightmove) + */ + if (other->client->ps.velocity[2] > 0 || + other->client->pers.cmd.forwardmove < 0) //now we only do it if jumping or running backward. Should be able to full-on charge. { otherDefLevel -= 1; if (otherDefLevel < 0) @@ -450,9 +455,11 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace ) { VectorCopy(trace->plane.normal, te->s.angles); te->s.eventParm = 0; - if (otherOwner->client->ps.velocity[2] > 0 || + /*if (otherOwner->client->ps.velocity[2] > 0 || otherOwner->client->pers.cmd.forwardmove || - otherOwner->client->pers.cmd.rightmove) + otherOwner->client->pers.cmd.rightmove)*/ + if (otherOwner->client->ps.velocity[2] > 0 || + otherOwner->client->pers.cmd.forwardmove < 0) //now we only do it if jumping or running backward. Should be able to full-on charge. { otherDefLevel -= 1; if (otherDefLevel < 0) @@ -646,7 +653,12 @@ void G_RunMissile( gentity_t *ent ) { ent->parent->client->hook = NULL; } - if (ent->s.weapon != G2_MODEL_PART) + if (ent->s.weapon == WP_SABER && ent->isSaberEntity) + { + G_RunThink( ent ); + return; + } + else if (ent->s.weapon != G2_MODEL_PART) { G_FreeEntity( ent ); return; diff --git a/CODE-mp/game/g_mover.c b/CODE-mp/game/g_mover.c index f68fb22..08a6f2c 100644 --- a/CODE-mp/game/g_mover.c +++ b/CODE-mp/game/g_mover.c @@ -40,7 +40,13 @@ gentity_t *G_TestEntityPosition( gentity_t *ent ) { mask = MASK_SOLID; } if ( ent->client ) { - trap_Trace( &tr, ent->client->ps.origin, ent->r.mins, ent->r.maxs, ent->client->ps.origin, ent->s.number, mask ); + vec3_t vMax; + VectorCopy(ent->r.maxs, vMax); + if (vMax[2] < 1) + { + vMax[2] = 1; + } + trap_Trace( &tr, ent->client->ps.origin, ent->r.mins, vMax, ent->client->ps.origin, ent->s.number, mask ); } else { trap_Trace( &tr, ent->s.pos.trBase, ent->r.mins, ent->r.maxs, ent->s.pos.trBase, ent->s.number, mask ); } @@ -146,7 +152,7 @@ qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, v // may have pushed them off an edge if ( check->s.groundEntityNum != pusher->s.number ) { - check->s.groundEntityNum = -1; + check->s.groundEntityNum = ENTITYNUM_NONE;//-1; } block = G_TestEntityPosition( check ); @@ -161,6 +167,15 @@ qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, v return qtrue; } + if (check->takedamage && !check->client && check->s.weapon && check->r.ownerNum < MAX_CLIENTS && + check->health < 500) + { + if (check->health > 0) + { + G_Damage(check, pusher, pusher, vec3_origin, check->r.currentOrigin, 999, 0, MOD_UNKNOWN); + } + return qfalse; + } // if it is ok to leave in the old position, do it // this is only relevent for riding entities, not pushed // Sliding trapdoors can cause this. @@ -722,19 +737,34 @@ void Blocked_Door( gentity_t *ent, gentity_t *other ) { Team_DroppedFlagThink( other ); return; } - G_TempEntity( other->s.origin, EV_ITEM_POP ); - G_FreeEntity( other ); + if (other->physicsObject && other->health && other->takedamage && other->inuse && !other->client) + { //it would otherwise just remove us, so do 99999 damage instead + G_Damage( other, ent, ent, NULL, NULL, 99999, DAMAGE_NO_ARMOR, MOD_CRUSH ); + } + else if (other->physicsObject && other->inuse && !other->client && other->s.weapon == WP_DET_PACK && other->think) + { //detpack is about to explode + return; + } + else if (other->isSaberEntity) + { + return; + } + else + { + G_TempEntity( other->s.origin, EV_ITEM_POP ); + G_FreeEntity( other ); + } return; } if ( ent->damage ) { if (ent->activator && ent->activator->inuse && ent->activator->client) { - G_Damage( other, ent->activator, ent->activator, NULL, NULL, ent->damage, DAMAGE_NO_ARMOR, MOD_CRUSH ); + G_Damage( other, ent->activator, ent->activator, NULL, NULL, ent->damage, DAMAGE_NO_ARMOR|DAMAGE_NO_PROTECTION, MOD_CRUSH ); } else { - G_Damage( other, ent, ent, NULL, NULL, ent->damage, DAMAGE_NO_ARMOR, MOD_CRUSH ); + G_Damage( other, ent, ent, NULL, NULL, ent->damage, DAMAGE_NO_ARMOR|DAMAGE_NO_PROTECTION, MOD_CRUSH ); } } if ( ent->spawnflags & 4 ) { diff --git a/CODE-mp/game/g_object.c b/CODE-mp/game/g_object.c index 6710aff..8718424 100644 --- a/CODE-mp/game/g_object.c +++ b/CODE-mp/game/g_object.c @@ -312,7 +312,7 @@ void G_RunObject( gentity_t *ent ) G_StopObjectMoving( ent ); } } - else + else if (ent->s.weapon != WP_SABER) { ent->s.apos.trType = TR_STATIONARY; pitch_roll_for_slope( ent, tr.plane.normal ); diff --git a/CODE-mp/game/g_public.h b/CODE-mp/game/g_public.h index 3823028..1595f45 100644 --- a/CODE-mp/game/g_public.h +++ b/CODE-mp/game/g_public.h @@ -224,6 +224,7 @@ typedef enum { G_COS, G_ATAN2, G_SQRT, + G_MATRIXMULTIPLY, G_ANGLEVECTORS, G_PERPENDICULARVECTOR, G_FLOOR, @@ -235,7 +236,6 @@ typedef enum { G_ACOS, G_ASIN, - G_MATRIXMULTIPLY, //END VM STUFF BOTLIB_SETUP = 200, // ( void ); diff --git a/CODE-mp/game/g_spawn.c b/CODE-mp/game/g_spawn.c index a8d005f..a21a752 100644 --- a/CODE-mp/game/g_spawn.c +++ b/CODE-mp/game/g_spawn.c @@ -800,7 +800,7 @@ void SP_worldspawn( void ) if ( g_restarted.integer ) { trap_Cvar_Set( "g_restarted", "0" ); level.warmupTime = 0; - } else if ( g_doWarmup.integer ) { // Turn it on + } else if ( g_doWarmup.integer && g_gametype.integer != GT_TOURNAMENT ) { // Turn it on level.warmupTime = -1; trap_SetConfigstring( CS_WARMUP, va("%i", level.warmupTime) ); G_LogPrintf( "Warmup:\n" ); diff --git a/CODE-mp/game/g_svcmds.c b/CODE-mp/game/g_svcmds.c index 76674cf..b3f751a 100644 --- a/CODE-mp/game/g_svcmds.c +++ b/CODE-mp/game/g_svcmds.c @@ -130,7 +130,7 @@ qboolean G_FilterPacket (char *from) { int i; unsigned in; - byte m[4]; + byte m[4] = {'\0','\0','\0','\0'}; char *p; i = 0; diff --git a/CODE-mp/game/g_syscalls.asm b/CODE-mp/game/g_syscalls.asm new file mode 100644 index 0000000..0a639b6 --- /dev/null +++ b/CODE-mp/game/g_syscalls.asm @@ -0,0 +1,228 @@ +code + +equ trap_Printf -1 ; G_PRINT +equ trap_Error -2 ; G_ERROR +equ trap_Milliseconds -3 ; G_MILLISECONDS +equ trap_Cvar_Register -4 ; G_CVAR_REGISTER +equ trap_Cvar_Update -5 ; G_CVAR_UPDATE +equ trap_Cvar_Set -6 ; G_CVAR_SET +equ trap_Cvar_VariableIntegerValue -7 ; G_CVAR_VARIABLE_INTEGER_VALUE +equ trap_Cvar_VariableStringBuffer -8 ; G_CVAR_VARIABLE_STRING_BUFFER +equ trap_Argc -9 ; G_ARGC +equ trap_Argv -10 ; G_ARGV +equ trap_FS_FOpenFile -11 ; G_FS_FOPEN_FILE +equ trap_FS_Read -12 ; G_FS_READ +equ trap_FS_Write -13 ; G_FS_WRITE +equ trap_FS_FCloseFile -14 ; G_FS_FCLOSE_FILE +equ trap_SendConsoleCommand -15 ; G_SEND_CONSOLE_COMMAND +equ trap_LocateGameData -16 ; G_LOCATE_GAME_DATA +equ trap_DropClient -17 ; G_DROP_CLIENT +equ trap_SendServerCommand -18 ; G_SEND_SERVER_COMMAND +equ trap_SetConfigstring -19 ; G_SET_CONFIGSTRING +equ trap_GetConfigstring -20 ; G_GET_CONFIGSTRING +equ trap_GetUserinfo -21 ; G_GET_USERINFO +equ trap_SetUserinfo -22 ; G_SET_USERINFO +equ trap_GetServerinfo -23 ; G_GET_SERVERINFO +equ trap_SetBrushModel -24 ; G_SET_BRUSH_MODEL +equ trap_Trace -25 ; G_TRACE +equ trap_PointContents -26 ; G_POINT_CONTENTS +equ trap_InPVS -27 ; G_IN_PVS +equ trap_InPVSIgnorePortals -28 ; G_IN_PVS_IGNORE_PORTALS +equ trap_AdjustAreaPortalState -29 ; G_ADJUST_AREA_PORTAL_STATE +equ trap_AreasConnected -30 ; G_AREAS_CONNECTED +equ trap_LinkEntity -31 ; G_LINKENTITY +equ trap_UnlinkEntity -32 ; G_UNLINKENTITY +equ trap_EntitiesInBox -33 ; G_ENTITIES_IN_BOX +equ trap_EntityContact -34 ; G_ENTITY_CONTACT +equ trap_BotAllocateClient -35 ; G_BOT_ALLOCATE_CLIENT +equ trap_BotFreeClient -36 ; G_BOT_FREE_CLIENT +equ trap_GetUsercmd -37 ; G_GET_USERCMD +equ trap_GetEntityToken -38 ; G_GET_ENTITY_TOKEN +equ trap_FS_GetFileList -39 ; G_FS_GETFILELIST +equ trap_DebugPolygonCreate -40 ; G_DEBUG_POLYGON_CREATE +equ trap_DebugPolygonDelete -41 ; G_DEBUG_POLYGON_DELETE +equ trap_RealTime -42 ; G_REAL_TIME +equ trap_SnapVector -43 ; G_SNAPVECTOR +equ trap_TraceCapsule -44 ; G_TRACECAPSULE +equ trap_EntityContactCapsule -45 ; G_ENTITY_CONTACTCAPSULE +equ trap_SP_RegisterServer -46 ; SP_REGISTER_SERVER_CMD +equ trap_SP_GetStringTextString -47 ; SP_GETSTRINGTEXTSTRING +equ trap_ROFF_Clean -48 ; G_ROFF_CLEAN +equ trap_ROFF_UpdateEntities -49 ; G_ROFF_UPDATE_ENTITIES +equ trap_ROFF_Cache -50 ; G_ROFF_CACHE +equ trap_ROFF_Play -51 ; G_ROFF_PLAY +equ trap_ROFF_Purge_Ent -52 ; G_ROFF_PURGE_ENT +equ trap_BotLibSetup -201 ; BOTLIB_SETUP +equ trap_BotLibShutdown -202 ; BOTLIB_SHUTDOWN +equ trap_BotLibVarSet -203 ; BOTLIB_LIBVAR_SET +equ trap_BotLibVarGet -204 ; BOTLIB_LIBVAR_GET +equ trap_BotLibDefine -205 ; BOTLIB_PC_ADD_GLOBAL_DEFINE +equ trap_BotLibStartFrame -206 ; BOTLIB_START_FRAME +equ trap_BotLibLoadMap -207 ; BOTLIB_LOAD_MAP +equ trap_BotLibUpdateEntity -208 ; BOTLIB_UPDATENTITY +equ trap_BotLibTest -209 ; BOTLIB_TEST +equ trap_BotGetSnapshotEntity -210 ; BOTLIB_GET_SNAPSHOT_ENTITY +equ trap_BotGetServerCommand -211 ; BOTLIB_GET_CONSOLE_MESSAGE +equ trap_BotUserCommand -212 ; BOTLIB_USER_COMMAND +equ trap_AAS_EntityInfo -304 ; BOTLIB_AAS_ENTITY_INFO +equ trap_AAS_Initialized -305 ; BOTLIB_AAS_INITIALIZED +equ trap_AAS_PresenceTypeBoundingBox -306 ; BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX +equ trap_AAS_Time -307 ; BOTLIB_AAS_TIME +equ trap_AAS_PointAreaNum -308 ; BOTLIB_AAS_POINT_AREA_NUM +equ trap_AAS_PointReachabilityAreaIndex -578 ; BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX +equ trap_AAS_TraceAreas -309 ; BOTLIB_AAS_TRACE_AREAS +equ trap_AAS_BBoxAreas -302 ; BOTLIB_AAS_BBOX_AREAS +equ trap_AAS_AreaInfo -303 ; BOTLIB_AAS_AREA_INFO +equ trap_AAS_PointContents -310 ; BOTLIB_AAS_POINT_CONTENTS +equ trap_AAS_NextBSPEntity -311 ; BOTLIB_AAS_NEXT_BSP_ENTITY +equ trap_AAS_ValueForBSPEpairKey -312 ; BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY +equ trap_AAS_VectorForBSPEpairKey -313 ; BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY +equ trap_AAS_FloatForBSPEpairKey -314 ; BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY +equ trap_AAS_IntForBSPEpairKey -315 ; BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY +equ trap_AAS_AreaReachability -316 ; BOTLIB_AAS_AREA_REACHABILITY +equ trap_AAS_AreaTravelTimeToGoalArea -317 ; BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA +equ trap_AAS_EnableRoutingArea -301 ; BOTLIB_AAS_ENABLE_ROUTING_AREA +equ trap_AAS_PredictRoute -577 ; BOTLIB_AAS_PREDICT_ROUTE +equ trap_AAS_AlternativeRouteGoals -576 ; BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL +equ trap_AAS_Swimming -318 ; BOTLIB_AAS_SWIMMING +equ trap_AAS_PredictClientMovement -319 ; BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT +equ trap_EA_Say -401 ; BOTLIB_EA_SAY +equ trap_EA_SayTeam -402 ; BOTLIB_EA_SAY_TEAM +equ trap_EA_Command -403 ; BOTLIB_EA_COMMAND +equ trap_EA_Action -404 ; BOTLIB_EA_ACTION +equ trap_EA_Gesture -405 ; BOTLIB_EA_GESTURE +equ trap_EA_Talk -406 ; BOTLIB_EA_TALK +equ trap_EA_Attack -407 ; BOTLIB_EA_ATTACK +equ trap_EA_Alt_Attack -408 ; BOTLIB_EA_ALT_ATTACK +equ trap_EA_ForcePower -409 ; BOTLIB_EA_FORCEPOWER +equ trap_EA_Use -410 ; BOTLIB_EA_USE +equ trap_EA_Respawn -411 ; BOTLIB_EA_RESPAWN +equ trap_EA_Crouch -412 ; BOTLIB_EA_CROUCH +equ trap_EA_MoveUp -413 ; BOTLIB_EA_MOVE_UP +equ trap_EA_MoveDown -414 ; BOTLIB_EA_MOVE_DOWN +equ trap_EA_MoveForward -415 ; BOTLIB_EA_MOVE_FORWARD +equ trap_EA_MoveBack -416 ; BOTLIB_EA_MOVE_BACK +equ trap_EA_MoveLeft -417 ; BOTLIB_EA_MOVE_LEFT +equ trap_EA_MoveRight -418 ; BOTLIB_EA_MOVE_RIGHT +equ trap_EA_SelectWeapon -419 ; BOTLIB_EA_SELECT_WEAPON +equ trap_EA_Jump -420 ; BOTLIB_EA_JUMP +equ trap_EA_DelayedJump -421 ; BOTLIB_EA_DELAYED_JUMP +equ trap_EA_Move -422 ; BOTLIB_EA_MOVE +equ trap_EA_View -423 ; BOTLIB_EA_VIEW +equ trap_EA_EndRegular -424 ; BOTLIB_EA_END_REGULAR +equ trap_EA_GetInput -425 ; BOTLIB_EA_GET_INPUT +equ trap_EA_ResetInput -426 ; BOTLIB_EA_RESET_INPUT +equ trap_BotLoadCharacter -501 ; BOTLIB_AI_LOAD_CHARACTER +equ trap_BotFreeCharacter -502 ; BOTLIB_AI_FREE_CHARACTER +equ trap_Characteristic_Float -503 ; BOTLIB_AI_CHARACTERISTIC_FLOAT +equ trap_Characteristic_BFloat -504 ; BOTLIB_AI_CHARACTERISTIC_BFLOAT +equ trap_Characteristic_Integer -505 ; BOTLIB_AI_CHARACTERISTIC_INTEGER +equ trap_Characteristic_BInteger -506 ; BOTLIB_AI_CHARACTERISTIC_BINTEGER +equ trap_Characteristic_String -507 ; BOTLIB_AI_CHARACTERISTIC_STRING +equ trap_BotAllocChatState -508 ; BOTLIB_AI_ALLOC_CHAT_STATE +equ trap_BotFreeChatState -509 ; BOTLIB_AI_FREE_CHAT_STATE +equ trap_BotQueueConsoleMessage -510 ; BOTLIB_AI_QUEUE_CONSOLE_MESSAGE +equ trap_BotRemoveConsoleMessage -511 ; BOTLIB_AI_REMOVE_CONSOLE_MESSAGE +equ trap_BotNextConsoleMessage -512 ; BOTLIB_AI_NEXT_CONSOLE_MESSAGE +equ trap_BotNumConsoleMessages -513 ; BOTLIB_AI_NUM_CONSOLE_MESSAGE +equ trap_BotInitialChat -514 ; BOTLIB_AI_INITIAL_CHAT +equ trap_BotNumInitialChats -570 ; BOTLIB_AI_NUM_INITIAL_CHATS +equ trap_BotReplyChat -515 ; BOTLIB_AI_REPLY_CHAT +equ trap_BotChatLength -516 ; BOTLIB_AI_CHAT_LENGTH +equ trap_BotEnterChat -517 ; BOTLIB_AI_ENTER_CHAT +equ trap_BotGetChatMessage -571 ; BOTLIB_AI_GET_CHAT_MESSAGE +equ trap_StringContains -518 ; BOTLIB_AI_STRING_CONTAINS +equ trap_BotFindMatch -519 ; BOTLIB_AI_FIND_MATCH +equ trap_BotMatchVariable -520 ; BOTLIB_AI_MATCH_VARIABLE +equ trap_UnifyWhiteSpaces -521 ; BOTLIB_AI_UNIFY_WHITE_SPACES +equ trap_BotReplaceSynonyms -522 ; BOTLIB_AI_REPLACE_SYNONYMS +equ trap_BotLoadChatFile -523 ; BOTLIB_AI_LOAD_CHAT_FILE +equ trap_BotSetChatGender -524 ; BOTLIB_AI_SET_CHAT_GENDER +equ trap_BotSetChatName -525 ; BOTLIB_AI_SET_CHAT_NAME +equ trap_BotResetGoalState -526 ; BOTLIB_AI_RESET_GOAL_STATE +equ trap_BotResetAvoidGoals -527 ; BOTLIB_AI_RESET_AVOID_GOALS +equ trap_BotRemoveFromAvoidGoals -572 ; BOTLIB_AI_REMOVE_FROM_AVOID_GOALS +equ trap_BotPushGoal -528 ; BOTLIB_AI_PUSH_GOAL +equ trap_BotPopGoal -529 ; BOTLIB_AI_POP_GOAL +equ trap_BotEmptyGoalStack -530 ; BOTLIB_AI_EMPTY_GOAL_STACK +equ trap_BotDumpAvoidGoals -531 ; BOTLIB_AI_DUMP_AVOID_GOALS +equ trap_BotDumpGoalStack -532 ; BOTLIB_AI_DUMP_GOAL_STACK +equ trap_BotGoalName -533 ; BOTLIB_AI_GOAL_NAME +equ trap_BotGetTopGoal -534 ; BOTLIB_AI_GET_TOP_GOAL +equ trap_BotGetSecondGoal -535 ; BOTLIB_AI_GET_SECOND_GOAL +equ trap_BotChooseLTGItem -536 ; BOTLIB_AI_CHOOSE_LTG_ITEM +equ trap_BotChooseNBGItem -537 ; BOTLIB_AI_CHOOSE_NBG_ITEM +equ trap_BotTouchingGoal -538 ; BOTLIB_AI_TOUCHING_GOAL +equ trap_BotItemGoalInVisButNotVisible -539 ; BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE +equ trap_BotGetLevelItemGoal -540 ; BOTLIB_AI_GET_LEVEL_ITEM_GOAL +equ trap_BotGetNextCampSpotGoal -568 ; BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL +equ trap_BotGetMapLocationGoal -569 ; BOTLIB_AI_GET_MAP_LOCATION_GOAL +equ trap_BotAvoidGoalTime -541 ; BOTLIB_AI_AVOID_GOAL_TIME +equ trap_BotSetAvoidGoalTime -574 ; BOTLIB_AI_SET_AVOID_GOAL_TIME +equ trap_BotInitLevelItems -542 ; BOTLIB_AI_INIT_LEVEL_ITEMS +equ trap_BotUpdateEntityItems -543 ; BOTLIB_AI_UPDATE_ENTITY_ITEMS +equ trap_BotLoadItemWeights -544 ; BOTLIB_AI_LOAD_ITEM_WEIGHTS +equ trap_BotFreeItemWeights -545 ; BOTLIB_AI_FREE_ITEM_WEIGHTS +equ trap_BotInterbreedGoalFuzzyLogic -566 ; BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC +equ trap_BotSaveGoalFuzzyLogic -546 ; BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC +equ trap_BotMutateGoalFuzzyLogic -567 ; BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC +equ trap_BotAllocGoalState -547 ; BOTLIB_AI_ALLOC_GOAL_STATE +equ trap_BotFreeGoalState -548 ; BOTLIB_AI_FREE_GOAL_STATE +equ trap_BotResetMoveState -549 ; BOTLIB_AI_RESET_MOVE_STATE +equ trap_BotAddAvoidSpot -575 ; BOTLIB_AI_ADD_AVOID_SPOT +equ trap_BotMoveToGoal -550 ; BOTLIB_AI_MOVE_TO_GOAL +equ trap_BotMoveInDirection -551 ; BOTLIB_AI_MOVE_IN_DIRECTION +equ trap_BotResetAvoidReach -552 ; BOTLIB_AI_RESET_AVOID_REACH +equ trap_BotResetLastAvoidReach -553 ; BOTLIB_AI_RESET_LAST_AVOID_REACH +equ trap_BotReachabilityArea -554 ; BOTLIB_AI_REACHABILITY_AREA +equ trap_BotMovementViewTarget -555 ; BOTLIB_AI_MOVEMENT_VIEW_TARGET +equ trap_BotPredictVisiblePosition -573 ; BOTLIB_AI_PREDICT_VISIBLE_POSITION +equ trap_BotAllocMoveState -556 ; BOTLIB_AI_ALLOC_MOVE_STATE +equ trap_BotFreeMoveState -557 ; BOTLIB_AI_FREE_MOVE_STATE +equ trap_BotInitMoveState -558 ; BOTLIB_AI_INIT_MOVE_STATE +equ trap_BotChooseBestFightWeapon -559 ; BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON +equ trap_BotGetWeaponInfo -560 ; BOTLIB_AI_GET_WEAPON_INFO +equ trap_BotLoadWeaponWeights -561 ; BOTLIB_AI_LOAD_WEAPON_WEIGHTS +equ trap_BotAllocWeaponState -562 ; BOTLIB_AI_ALLOC_WEAPON_STATE +equ trap_BotFreeWeaponState -563 ; BOTLIB_AI_FREE_WEAPON_STATE +equ trap_BotResetWeaponState -564 ; BOTLIB_AI_RESET_WEAPON_STATE +equ trap_GeneticParentsAndChildSelection -565 ; BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION +equ trap_PC_LoadSource -579 ; BOTLIB_PC_LOAD_SOURCE +equ trap_PC_FreeSource -580 ; BOTLIB_PC_FREE_SOURCE +equ trap_PC_ReadToken -581 ; BOTLIB_PC_READ_TOKEN +equ trap_PC_SourceFileAndLine -582 ; BOTLIB_PC_SOURCE_FILE_AND_LINE +equ trap_G2_ListModelBones -583 ; G_G2_LISTBONES +equ trap_G2_ListModelSurfaces -584 ; G_G2_LISTSURFACES +equ trap_G2_HaveWeGhoul2Models -585 ; G_G2_HAVEWEGHOULMODELS +equ trap_G2_SetGhoul2ModelIndexes -586 ; G_G2_SETMODELS +equ trap_G2API_GetBoltMatrix -587 ; G_G2_GETBOLT +equ trap_G2API_GetBoltMatrix_NoReconstruct -588 ; G_G2_GETBOLT_NOREC +equ trap_G2API_InitGhoul2Model -589 ; G_G2_INITGHOUL2MODEL +equ trap_G2API_AddBolt -590 ; G_G2_ADDBOLT +equ trap_G2API_SetBoltInfo -591 ; G_G2_SETBOLTINFO +equ trap_G2API_SetBoneAngles -592 ; G_G2_ANGLEOVERRIDE +equ trap_G2API_SetBoneAnim -593 ; G_G2_PLAYANIM +equ trap_G2API_GetGLAName -594 ; G_G2_GETGLANAME +equ trap_G2API_CopyGhoul2Instance -595 ; G_G2_COPYGHOUL2INSTANCE +equ trap_G2API_CopySpecificGhoul2Model -596 ; G_G2_COPYSPECIFICGHOUL2MODEL +equ trap_G2API_DuplicateGhoul2Instance -597 ; G_G2_DUPLICATEGHOUL2INSTANCE +equ trap_G2API_HasGhoul2ModelOnIndex -598 ; G_G2_HASGHOUL2MODELONINDEX +equ trap_G2API_RemoveGhoul2Model -599 ; G_G2_REMOVEGHOUL2MODEL +equ trap_G2API_CleanGhoul2Models -600 ; G_G2_CLEANMODELS + + +; hardcoded functions +equ memset -101 ; G_MEMSET +equ memcpy -102 ; G_MEMCPY +equ strncpy -103 ; G_STRNCPY +equ sin -104 ; G_SIN +equ cos -105 ; G_COS +equ atan2 -106 ; G_ATAN2 +equ sqrt -107 ; G_SQRT +equ matrixmultiply -108 ; G_MATRIXMULTIPLY +equ anglevectors -109 ; G_ANGLEVECTORS +equ perpendicularvector -110 ; G_PERPENDICULARVECTOR +equ floor -111 ; G_FLOOR +equ ceil -112 ; G_CEIL +equ acos -115 ; G_ACOS +equ asin -116 ; G_ASIN diff --git a/CODE-mp/game/g_syscalls.c b/CODE-mp/game/g_syscalls.c index 5ca8bac..4f94c6e 100644 --- a/CODE-mp/game/g_syscalls.c +++ b/CODE-mp/game/g_syscalls.c @@ -200,9 +200,9 @@ qboolean trap_EntityContactCapsule( const vec3_t mins, const vec3_t maxs, const return syscall( G_ENTITY_CONTACTCAPSULE, mins, maxs, ent ); } -void trap_SP_RegisterServer( const char *package ) +qboolean trap_SP_RegisterServer( const char *package ) { - syscall( SP_REGISTER_SERVER_CMD, package ); + return syscall( SP_REGISTER_SERVER_CMD, package ); } int trap_SP_GetStringTextString(const char *text, char *buffer, int bufferLength) diff --git a/CODE-mp/game/g_team.c b/CODE-mp/game/g_team.c index eab9498..70eb8b3 100644 --- a/CODE-mp/game/g_team.c +++ b/CODE-mp/game/g_team.c @@ -114,7 +114,21 @@ void PrintCTFMessage(int plIndex, int teamIndex, int ctfMessage) te->r.svFlags |= SVF_BROADCAST; te->s.eventParm = ctfMessage; te->s.trickedentindex = plIndex; - te->s.trickedentindex2 = teamIndex; + if (ctfMessage == CTFMESSAGE_PLAYER_CAPTURED_FLAG) + { + if (teamIndex == TEAM_RED) + { + te->s.trickedentindex2 = TEAM_BLUE; + } + else + { + te->s.trickedentindex2 = TEAM_RED; + } + } + else + { + te->s.trickedentindex2 = teamIndex; + } } /* diff --git a/CODE-mp/game/g_trigger.c b/CODE-mp/game/g_trigger.c index 3b46c46..09c82d4 100644 --- a/CODE-mp/game/g_trigger.c +++ b/CODE-mp/game/g_trigger.c @@ -454,7 +454,7 @@ void hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) { } // play sound - if ( !(self->spawnflags & 4) ) { + if ( !(self->spawnflags & 4) && self->damage != -1 ) { G_Sound( other, CHAN_AUTO, self->noise_index ); } @@ -477,13 +477,20 @@ void hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) { } else { + int dmg = self->damage; + + if (dmg == -1) + { //so fall-to-blackness triggers destroy evertyhing + dmg = 99999; + self->timestamp = 0; + } if (self->activator && self->activator->inuse && self->activator->client) { - G_Damage (other, self->activator, self->activator, NULL, NULL, self->damage, dflags, MOD_TRIGGER_HURT); + G_Damage (other, self->activator, self->activator, NULL, NULL, dmg, dflags|DAMAGE_NO_PROTECTION, MOD_TRIGGER_HURT); } else { - G_Damage (other, self, self, NULL, NULL, self->damage, dflags, MOD_TRIGGER_HURT); + G_Damage (other, self, self, NULL, NULL, dmg, dflags|DAMAGE_NO_PROTECTION, MOD_TRIGGER_HURT); } } } diff --git a/CODE-mp/game/g_utils.c b/CODE-mp/game/g_utils.c index 2791d8c..e708e67 100644 --- a/CODE-mp/game/g_utils.c +++ b/CODE-mp/game/g_utils.c @@ -405,29 +405,6 @@ void G_SetMovedir( vec3_t angles, vec3_t movedir ) { VectorClear( angles ); } - -float vectoyaw( const vec3_t vec ) { - float yaw; - - if (vec[YAW] == 0 && vec[PITCH] == 0) { - yaw = 0; - } else { - if (vec[PITCH]) { - yaw = ( atan2( vec[YAW], vec[PITCH]) * 180 / M_PI ); - } else if (vec[YAW] > 0) { - yaw = 90; - } else { - yaw = 270; - } - if (yaw < 0) { - yaw += 360; - } - } - - return yaw; -} - - void G_InitGentity( gentity_t *e ) { e->inuse = qtrue; e->classname = "noclass"; @@ -518,6 +495,50 @@ qboolean G_EntitiesFree( void ) { return qfalse; } +#define MAX_G2_KILL_QUEUE 64 + +int gG2KillIndex[MAX_G2_KILL_QUEUE]; +int gG2KillNum = 0; + +void G_SendG2KillQueue(void) +{ + char g2KillString[1024]; + int i = 0; + + if (!gG2KillNum) + { + return; + } + + Com_sprintf(g2KillString, 1024, "kg2"); + + while (i < gG2KillNum) + { + Q_strcat(g2KillString, 1024, va(" %i", gG2KillIndex[i])); + i++; + } + + trap_SendServerCommand(-1, g2KillString); + + //Clear the count because we just sent off the whole queue + gG2KillNum = 0; +} + +void G_KillG2Queue(int entNum) +{ + if (gG2KillNum >= MAX_G2_KILL_QUEUE) + { //This would be considered a Bad Thing. +#ifdef _DEBUG + Com_Printf("WARNING: Exceeded the MAX_G2_KILL_QUEUE count for this frame!\n"); +#endif + //Since we're out of queue slots, just send it now as a seperate command (eats more bandwidth, but we have no choice) + trap_SendServerCommand(-1, va("kg2 %i", entNum)); + return; + } + + gG2KillIndex[gG2KillNum] = entNum; + gG2KillNum++; +} /* ================= @@ -527,7 +548,15 @@ Marks the entity as free ================= */ void G_FreeEntity( gentity_t *ed ) { - gentity_t *te; + //gentity_t *te; + + if (ed->isSaberEntity) + { +#ifdef _DEBUG + Com_Printf("Tried to remove JM saber!\n"); +#endif + return; + } trap_UnlinkEntity (ed); // unlink from world @@ -541,9 +570,13 @@ void G_FreeEntity( gentity_t *ed ) { //now-removed entity if (ed->s.modelGhoul2) { //force all clients to accept an event to destroy this instance, right now + /* te = G_TempEntity( vec3_origin, EV_DESTROY_GHOUL2_INSTANCE ); te->r.svFlags |= SVF_BROADCAST; te->s.eventParm = ed->s.number; + */ + //Or not. Events can be dropped, so that would be a bad thing. + G_KillG2Queue(ed->s.number); } if (ed->s.eFlags & EF_SOUNDTRACKER) diff --git a/CODE-mp/game/g_weapon.c b/CODE-mp/game/g_weapon.c index 324a4c7..295567c 100644 --- a/CODE-mp/game/g_weapon.c +++ b/CODE-mp/game/g_weapon.c @@ -48,7 +48,7 @@ static vec3_t muzzle; // Heavy Repeater //---------- #define REPEATER_SPREAD 1.4f -#define REPEATER_DAMAGE 8 +#define REPEATER_DAMAGE 14 #define REPEATER_VELOCITY 1600 #define REPEATER_ALT_SIZE 3 // half of bbox size @@ -70,9 +70,9 @@ static vec3_t muzzle; // Golan Arms Flechette //--------- -#define FLECHETTE_SHOTS 6 +#define FLECHETTE_SHOTS 5 #define FLECHETTE_SPREAD 4.0f -#define FLECHETTE_DAMAGE 10//15 +#define FLECHETTE_DAMAGE 12//15 #define FLECHETTE_VEL 3500 #define FLECHETTE_SIZE 1 #define FLECHETTE_MINE_RADIUS_CHECK 256 @@ -810,6 +810,28 @@ static void WP_BowcasterMainFire( gentity_t *ent ) count--; } + //scale the damage down based on how many are about to be fired + if (count <= 1) + { + damage = 50; + } + else if (count == 2) + { + damage = 45; + } + else if (count == 3) + { + damage = 40; + } + else if (count == 4) + { + damage = 35; + } + else + { + damage = 30; + } + for (i = 0; i < count; i++ ) { // create a range of different velocities @@ -1075,7 +1097,10 @@ void DEMP2_AltRadiusDamage( gentity_t *ent ) // push the center of mass higher than the origin so players get knocked into the air more dir[2] += 12; - G_Damage( gent, myOwner, myOwner, dir, ent->r.currentOrigin, ent->damage, DAMAGE_DEATH_KNOCKBACK, ent->splashMethodOfDeath ); + if (gent != myOwner) + { + G_Damage( gent, myOwner, myOwner, dir, ent->r.currentOrigin, ent->damage, DAMAGE_DEATH_KNOCKBACK, ent->splashMethodOfDeath ); + } } // store the last fraction so that next time around we can test against those things that fall between that last point and where the current shockwave edge is @@ -1633,7 +1658,7 @@ THERMAL DETONATOR ====================================================================== */ -#define TD_DAMAGE 100 +#define TD_DAMAGE 70 //only do 70 on a direct impact #define TD_SPLASH_RAD 128 #define TD_SPLASH_DAM 90 #define TD_VELOCITY 900 @@ -1822,7 +1847,7 @@ void laserTrapExplode( gentity_t *self ) if (self->activator) { - G_RadiusDamage( self->r.currentOrigin, self->activator, self->splashDamage, self->splashRadius, self, MOD_UNKNOWN/*MOD_LT_SPLASH*/ ); + G_RadiusDamage( self->r.currentOrigin, self->activator, self->splashDamage, self->splashRadius, self, MOD_TRIP_MINE_SPLASH/*MOD_LT_SPLASH*/ ); } //FIXME: clear me from owner's list of tripmines? @@ -1978,7 +2003,7 @@ void laserTrapStick( gentity_t *ent, vec3_t endpos, vec3_t normal ) { ent->touch = touchLaserTrap; ent->think = laserTrapExplode; - ent->nextthink = level.time + 0;//LT_ALT_TIME; // How long 'til she blows + ent->nextthink = level.time + LT_ALT_TIME; // How long 'til she blows } } @@ -1997,8 +2022,8 @@ void CreateLaserTrap( gentity_t *laserTrap, vec3_t start, gentity_t *owner ) laserTrap->splashDamage = LT_SPLASH_DAM;//*2; laserTrap->splashRadius = LT_SPLASH_RAD;//*2; laserTrap->damage = LT_DAMAGE;//*DMG_VAR; - laserTrap->methodOfDeath = MOD_UNKNOWN;//MOD_TRIP_WIRE; - laserTrap->splashMethodOfDeath = MOD_UNKNOWN;//MOD_TRIP_WIRE; + laserTrap->methodOfDeath = MOD_TRIP_MINE_SPLASH;//MOD_TRIP_WIRE; + laserTrap->splashMethodOfDeath = MOD_TRIP_MINE_SPLASH;//MOD_TRIP_WIRE; laserTrap->s.eType = ET_GENERAL; laserTrap->r.svFlags = SVF_USE_CURRENT_ORIGIN; laserTrap->s.weapon = WP_TRIP_MINE; @@ -2116,21 +2141,11 @@ void WP_PlaceLaserTrap( gentity_t *ent, qboolean alt_fire ) //now make the new one CreateLaserTrap( laserTrap, start, ent ); - if (alt_fire) - { - laserTrap->splashRadius /= 2; - } //set player-created-specific fields laserTrap->setTime = level.time;//remember when we placed it - if ( alt_fire ) - {//explode after 2 second - //doesn't activate until it latches - //laserTrap->think = laserTrap; - //laserTrap->nextthink = level.time + LT_TIME; // How long 'til she blows - } - else + if (!alt_fire) {//tripwire laserTrap->count = 1; } @@ -2201,7 +2216,7 @@ void charge_stick (gentity_t *self, gentity_t *other, trace_t *trace) VectorClear(self->s.apos.trDelta); self->s.apos.trType = TR_STATIONARY; - G_RadiusDamage( self->r.currentOrigin, self->parent, self->splashDamage, self->splashRadius, self, MOD_UNKNOWN ); + G_RadiusDamage( self->r.currentOrigin, self->parent, self->splashDamage, self->splashRadius, self, MOD_DET_PACK_SPLASH ); VectorCopy(trace->plane.normal, v); VectorCopy(v, self->pos2); self->count = -1; @@ -2258,7 +2273,7 @@ void DetPackBlow(gentity_t *self) self->die = 0; self->takedamage = qfalse; - G_RadiusDamage( self->r.currentOrigin, self->parent, self->splashDamage, self->splashRadius, self, MOD_UNKNOWN ); + G_RadiusDamage( self->r.currentOrigin, self->parent, self->splashDamage, self->splashRadius, self, MOD_DET_PACK_SPLASH ); v[0] = 0; v[1] = 0; v[2] = 1; @@ -2309,8 +2324,8 @@ void drop_charge (gentity_t *self, vec3_t start, vec3_t dir) bolt->damage = 100; bolt->splashDamage = 200; bolt->splashRadius = 200; - bolt->methodOfDeath = MOD_UNKNOWN;//MOD_EXPLOSIVE; - bolt->splashMethodOfDeath = MOD_UNKNOWN;//MOD_EXPLOSIVE_SPLASH; + bolt->methodOfDeath = MOD_DET_PACK_SPLASH;//MOD_EXPLOSIVE; + bolt->splashMethodOfDeath = MOD_DET_PACK_SPLASH;//MOD_EXPLOSIVE_SPLASH; bolt->clipmask = MASK_SHOT; bolt->s.solid = 2; bolt->r.contents = MASK_SHOT; @@ -2321,8 +2336,10 @@ void drop_charge (gentity_t *self, vec3_t start, vec3_t dir) bolt->s.genericenemyindex = self->s.number+1024; //rww - so client prediction knows we own this and won't hit it - VectorSet( bolt->r.mins, -3, -3, -3 ); - VectorSet( bolt->r.maxs, 3, 3, 3 ); +// VectorSet( bolt->r.mins, -3, -3, -3 ); +// VectorSet( bolt->r.maxs, 3, 3, 3 ); + VectorSet( bolt->r.mins, -2, -2, -2 ); + VectorSet( bolt->r.maxs, 2, 2, 2 ); bolt->health = 1; bolt->takedamage = qtrue; @@ -2531,14 +2548,8 @@ void WP_FireStunBaton( gentity_t *ent, qboolean alt_fire ) // TEMP! G_Sound( tr_ent, CHAN_WEAPON, G_SoundIndex( va("sound/weapons/melee/punch%d", Q_irand(1, 4)) ) ); - if ( alt_fire ) - { - G_Damage( tr_ent, ent, ent, forward, tr.endpos, STUN_BATON_ALT_DAMAGE, DAMAGE_HALF_ABSORB, MOD_STUN_BATON ); - } - else - { - G_Damage( tr_ent, ent, ent, forward, tr.endpos, STUN_BATON_DAMAGE, (DAMAGE_NO_KNOCKBACK|DAMAGE_HALF_ABSORB), MOD_STUN_BATON ); - } + G_Damage( tr_ent, ent, ent, forward, tr.endpos, STUN_BATON_DAMAGE, (DAMAGE_NO_KNOCKBACK|DAMAGE_HALF_ABSORB), MOD_STUN_BATON ); + //alt-fire? if (tr_ent->client) { //if it's a player then use the shock effect diff --git a/CODE-mp/game/game.bat b/CODE-mp/game/game.bat new file mode 100644 index 0000000..8036ef4 --- /dev/null +++ b/CODE-mp/game/game.bat @@ -0,0 +1,99 @@ +del /q vm +mkdir vm +cd vm +set cc=lcc -A -DQ3_VM -DMISSIONPACK -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui %1 + +%cc% ../g_main.c +@if errorlevel 1 goto quit + +%cc% ../g_syscalls.c +@if errorlevel 1 goto quit + +%cc% ../bg_misc.c +@if errorlevel 1 goto quit +%cc% ../bg_lib.c +@if errorlevel 1 goto quit +%cc% ../bg_pmove.c +@if errorlevel 1 goto quit +%cc% ../bg_saber.c +@if errorlevel 1 goto quit +%cc% ../bg_slidemove.c +@if errorlevel 1 goto quit +%cc% ../bg_panimate.c +@if errorlevel 1 goto quit +%cc% ../bg_weapons.c +@if errorlevel 1 goto quit +%cc% ../q_math.c +@if errorlevel 1 goto quit +%cc% ../q_shared.c +@if errorlevel 1 goto quit + +%cc% ../ai_main.c +@if errorlevel 1 goto quit +%cc% ../ai_util.c +@if errorlevel 1 goto quit +%cc% ../ai_wpnav.c +@if errorlevel 1 goto quit + +%cc% ../g_active.c +@if errorlevel 1 goto quit + +%cc% ../g_arenas.c +@if errorlevel 1 goto quit +%cc% ../g_bot.c +@if errorlevel 1 goto quit +%cc% ../g_client.c +@if errorlevel 1 goto quit +%cc% ../g_cmds.c +@if errorlevel 1 goto quit +%cc% ../g_combat.c +@if errorlevel 1 goto quit +%cc% ../g_items.c +@if errorlevel 1 goto quit +%cc% ../g_log.c +@if errorlevel 1 goto quit +%cc% ../g_mem.c +@if errorlevel 1 goto quit +%cc% ../g_misc.c +@if errorlevel 1 goto quit +%cc% ../g_missile.c +@if errorlevel 1 goto quit +%cc% ../g_mover.c +@if errorlevel 1 goto quit +%cc% ../g_object.c +@if errorlevel 1 goto quit +%cc% ../g_saga.c +@if errorlevel 1 goto quit +%cc% ../g_session.c +@if errorlevel 1 goto quit +%cc% ../g_spawn.c +@if errorlevel 1 goto quit +%cc% ../g_svcmds.c +@if errorlevel 1 goto quit +%cc% ../g_target.c +@if errorlevel 1 goto quit +%cc% ../g_team.c +@if errorlevel 1 goto quit +%cc% ../g_trigger.c +@if errorlevel 1 goto quit +%cc% ../g_utils.c +@if errorlevel 1 goto quit +%cc% ../g_weapon.c +@if errorlevel 1 goto quit +%cc% ../w_force.c +@if errorlevel 1 goto quit +%cc% ../w_saber.c +@if errorlevel 1 goto quit + +sysmaker ../g_public.h ../g_syscalls.c ../g_syscalls.asm +@if errorlevel 1 goto quit + +q3asm -f ../game +@if errorlevel 1 goto quit + +mkdir "..\..\base\vm" +copy *.map "..\..\base\vm" +copy *.qvm "..\..\base\vm" + +:quit +cd .. diff --git a/CODE-mp/game/game.q3asm b/CODE-mp/game/game.q3asm new file mode 100644 index 0000000..a60a599 --- /dev/null +++ b/CODE-mp/game/game.q3asm @@ -0,0 +1,40 @@ +-o "jk2mpgame" + +g_main +ai_main +ai_util +ai_wpnav +bg_lib +bg_misc +bg_pmove +bg_panimate +bg_slidemove +bg_weapons +bg_saber +g_active +g_arenas +g_bot +g_client +g_cmds +g_combat +g_items +g_log +g_mem +g_misc +g_missile +g_mover +g_object +g_saga +g_session +g_spawn +g_svcmds +..\g_syscalls +g_target +g_team +g_trigger +g_utils +g_weapon +w_force +w_saber +q_math +q_shared diff --git a/CODE-mp/game/mssccprj.scc b/CODE-mp/game/mssccprj.scc new file mode 100644 index 0000000..5d4910b --- /dev/null +++ b/CODE-mp/game/mssccprj.scc @@ -0,0 +1,5 @@ +SCC = This is a Source Code Control file + +[JK2_game.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\jk2sof2MP" +SCC_Project_Name = "$/General/code/game", VPCAAAAA diff --git a/CODE-mp/game/q_math.c b/CODE-mp/game/q_math.c index b2f3ada..c91b719 100644 --- a/CODE-mp/game/q_math.c +++ b/CODE-mp/game/q_math.c @@ -595,6 +595,7 @@ float AngleSubtract( float a1, float a2 ) { float a; a = a1 - a2; + assert(fabs(a) < 3600); while ( a > 180 ) { a -= 360; } diff --git a/CODE-mp/game/q_shared.h b/CODE-mp/game/q_shared.h index 54eac5b..2c02b64 100644 --- a/CODE-mp/game/q_shared.h +++ b/CODE-mp/game/q_shared.h @@ -6,36 +6,8 @@ // q_shared.h -- included first by ALL program modules. // A user mod should never modify this file -#define Q3_VERSION "JK2MP: v0.56" - - #define MAX_TEAMNAME 32 -#ifdef _WIN32 - -#pragma warning(disable : 4018) // signed/unsigned mismatch -#pragma warning(disable : 4032) -#pragma warning(disable : 4051) -#pragma warning(disable : 4057) // slightly different base types -#pragma warning(disable : 4100) // unreferenced formal parameter -#pragma warning(disable : 4115) -#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence -#pragma warning(disable : 4127) // conditional expression is constant -#pragma warning(disable : 4136) -#pragma warning(disable : 4152) // nonstandard extension, function/data pointer conversion in expression -//#pragma warning(disable : 4201) -//#pragma warning(disable : 4214) -#pragma warning(disable : 4244) -#pragma warning(disable : 4142) // benign redefinition -//#pragma warning(disable : 4305) // truncation from const double to float -//#pragma warning(disable : 4310) // cast truncates constant value -//#pragma warning(disable: 4505) // unreferenced local function has been removed -#pragma warning(disable : 4514) -#pragma warning(disable : 4702) // unreachable code -#pragma warning(disable : 4711) // selected for automatic inline expansion -#pragma warning(disable : 4220) // varargs matches remaining parameters -#endif - #include "../qcommon/disablewarnings.h" /********************************************************************** @@ -306,6 +278,8 @@ static float LittleFloat (const float *l) { return FloatSwap(l); } //============================================================= +//============================================================= + typedef unsigned char byte; typedef unsigned short word; typedef unsigned long ulong; @@ -1287,7 +1261,7 @@ typedef enum { // // per-level limits // -#define MAX_CLIENTS 64 // absolute limit +#define MAX_CLIENTS 32 // absolute limit #define MAX_LOCATIONS 64 #define GENTITYNUM_BITS 10 // don't need to send any more @@ -1494,6 +1468,7 @@ typedef struct playerState_s { int damageYaw; int damagePitch; int damageCount; + int damageType; int painTime; // used for both game and client side to process the pain twitch - NOT sent across the network int painDirection; // NOT sent across the network @@ -1522,9 +1497,9 @@ typedef struct playerState_s { qboolean saberInFlight; qboolean saberActive; - short saberMove; - short saberBlocking; - short saberBlocked; + int saberMove; + int saberBlocking; + int saberBlocked; int saberLockTime; int saberLockEnemy; @@ -1886,7 +1861,7 @@ typedef struct entityState_s { qboolean saberInFlight; int saberEntityNum; - short saberMove; + int saberMove; int forcePowersActive; qboolean isJediMaster; @@ -1947,10 +1922,10 @@ typedef struct qtime_s { // server browser sources #define AS_LOCAL 0 -#define AS_MPLAYER 1 -#define AS_GLOBAL 2 -#define AS_FAVORITES 3 +#define AS_GLOBAL 1 +#define AS_FAVORITES 2 +#define AS_MPLAYER 3 // (Obsolete) // cinematic states typedef enum { @@ -2073,4 +2048,5 @@ enum { }; + #endif // __Q_SHARED_H diff --git a/CODE-mp/game/vssver.scc b/CODE-mp/game/vssver.scc new file mode 100644 index 0000000..57a67c5 Binary files /dev/null and b/CODE-mp/game/vssver.scc differ diff --git a/CODE-mp/game/w_force.c b/CODE-mp/game/w_force.c index 24f82bb..73cbd3d 100644 --- a/CODE-mp/game/w_force.c +++ b/CODE-mp/game/w_force.c @@ -11,20 +11,25 @@ int speedLoopSound = 0; int rageLoopSound = 0; -int protectHitSound = 0; -int protectActivateSound = 0; int protectLoopSound = 0; -int absorbHitSound = 0; -int absorbActivateSound = 0; int absorbLoopSound = 0; int seeLoopSound = 0; -int ysalimariLoopSound = 0; +int ysalamiriLoopSound = 0; #define FORCE_VELOCITY_DAMAGE 0 +void G_PreDefSound(vec3_t org, int pdSound) +{ + gentity_t *te; + + te = G_TempEntity( org, EV_PREDEFSOUND ); + te->s.eventParm = pdSound; + VectorCopy(org, te->s.origin); +} + qboolean InFront( vec3_t spot, vec3_t from, vec3_t fromAngles, float threshHold ) { vec3_t dir, forward, angles; @@ -135,22 +140,28 @@ void WP_InitForcePowers( gentity_t *ent ) { int i; int i_r; - int i_f; int maxRank = g_maxForceRank.integer; - int myRank = 0; - int usedRank = 0; qboolean warnClient = qfalse; qboolean warnClientLimit = qfalse; char userinfo[MAX_INFO_STRING]; - char forcePowers[MAX_QPATH]; + char forcePowers[256]; char readBuf[256]; int lastFPKnown = -1; + qboolean didEvent = qfalse; if (!maxRank) { //if server has no max rank, default to max (50) - maxRank = FORCE_MASTERY_JEDI_LORD; + maxRank = FORCE_MASTERY_JEDI_MASTER; } + /* + if (g_forcePowerDisable.integer) + { + maxRank = FORCE_MASTERY_UNINITIATED; + } + */ + //rww - don't do this + if ( !ent || !ent->client ) { return; @@ -174,31 +185,11 @@ void WP_InitForcePowers( gentity_t *ent ) rageLoopSound = G_SoundIndex("sound/weapons/force/rageloop.wav"); } - if (!absorbHitSound) - { - absorbHitSound = G_SoundIndex("sound/weapons/force/absorbhit.wav"); - } - - if (!absorbActivateSound) - { - absorbActivateSound = G_SoundIndex("sound/weapons/force/absorb.wav"); - } - if (!absorbLoopSound) { absorbLoopSound = G_SoundIndex("sound/weapons/force/absorbloop.wav"); } - if (!protectHitSound) - { - protectHitSound = G_SoundIndex("sound/weapons/force/protecthit.wav"); - } - - if (!protectActivateSound) - { - protectActivateSound = G_SoundIndex("sound/weapons/force/protect.wav"); - } - if (!protectLoopSound) { protectLoopSound = G_SoundIndex("sound/weapons/force/protectloop.wav"); @@ -209,9 +200,9 @@ void WP_InitForcePowers( gentity_t *ent ) seeLoopSound = G_SoundIndex("sound/weapons/force/seeloop.wav"); } - if (!ysalimariLoopSound) + if (!ysalamiriLoopSound) { - ysalimariLoopSound = G_SoundIndex("sound/player/nullifyloop.wav"); + ysalamiriLoopSound = G_SoundIndex("sound/player/nullifyloop.wav"); } i = 0; @@ -238,236 +229,70 @@ void WP_InitForcePowers( gentity_t *ent ) //rww - parse through the string manually and eat out all the appropriate data i = 0; - while (forcePowers[i]) + if (g_forceBasedTeams.integer) { - i_r = 0; - - while (forcePowers[i] && forcePowers[i] != '-' && i_r < 255) + if (ent->client->sess.sessionTeam == TEAM_RED) { - readBuf[i_r] = forcePowers[i]; - i_r++; - i++; + warnClient = !(BG_LegalizedForcePowers(forcePowers, maxRank, HasSetSaberOnly(), FORCE_DARKSIDE, g_gametype.integer, g_forcePowerDisable.integer)); } - readBuf[i_r] = '\0'; - if (i_r >= 255 || !forcePowers[i] || forcePowers[i] != '-') + else if (ent->client->sess.sessionTeam == TEAM_BLUE) { - ent->client->ps.fd.forceSide = 0; - goto validitycheck; + warnClient = !(BG_LegalizedForcePowers(forcePowers, maxRank, HasSetSaberOnly(), FORCE_LIGHTSIDE, g_gametype.integer, g_forcePowerDisable.integer)); } - ent->client->ps.fd.forceRank = atoi(readBuf); - - if (ent->client->ps.fd.forceRank > maxRank) + else { - ent->client->ps.fd.forceRank = maxRank; - warnClient = qtrue; + warnClient = !(BG_LegalizedForcePowers(forcePowers, maxRank, HasSetSaberOnly(), 0, g_gametype.integer, g_forcePowerDisable.integer)); } + } + else + { + warnClient = !(BG_LegalizedForcePowers(forcePowers, maxRank, HasSetSaberOnly(), 0, g_gametype.integer, g_forcePowerDisable.integer)); + } - if (ent->client->ps.fd.forceRank < 1) - { - ent->client->ps.fd.forceRank = 1; - } - - myRank = ent->client->ps.fd.forceRank; - - i_r = 0; - - i++; - - while (forcePowers[i] && forcePowers[i] != '-' && i_r < 255) - { - readBuf[i_r] = forcePowers[i]; - i_r++; - i++; - } - readBuf[i_r] = '\0'; - if (i_r >= 255 || !forcePowers[i] || forcePowers[i] != '-') - { - ent->client->ps.fd.forceSide = 0; - goto validitycheck; - } - ent->client->ps.fd.forceSide = atoi(readBuf); - i_r = 0; - - if (ent->client->ps.fd.forceSide != FORCE_LIGHTSIDE && - ent->client->ps.fd.forceSide != FORCE_DARKSIDE) - { - ent->client->ps.fd.forceSide = FORCE_LIGHTSIDE; - } - - if (g_forceBasedTeams.integer) - { - if (ent->client->sess.sessionTeam == TEAM_BLUE) - { - ent->client->ps.fd.forceSide = FORCE_LIGHTSIDE; - } - if (ent->client->sess.sessionTeam == TEAM_RED) - { - ent->client->ps.fd.forceSide = FORCE_DARKSIDE; - } - } - - i++; - - i_f = FP_HEAL; - - while (forcePowers[i] && i_f < NUM_FORCE_POWERS) - { - readBuf[0] = forcePowers[i]; - readBuf[1] = '\0'; - ent->client->ps.fd.forcePowerLevel[i_f] = atoi(readBuf); - - if (ent->client->ps.fd.forcePowerLevel[i_f] < 0) - { - ent->client->ps.fd.forcePowerLevel[i_f] = 0; - } - if (ent->client->ps.fd.forcePowerLevel[i_f] > FORCE_LEVEL_3) - { - ent->client->ps.fd.forcePowerLevel[i_f] = FORCE_LEVEL_3; - } - - //verify that we have valid selected powers in case the client tries to cheat and - //send us an invalid userinfo string for his force powers - if (forcePowerDarkLight[i_f] && forcePowerDarkLight[i_f] != ent->client->ps.fd.forceSide) - { - ent->client->ps.fd.forcePowerLevel[i_f] = 0; - } - - //NOTENOTE need to update minrank array taking new rank levels into account (0-7?) - //if (forcePowerMinRank[ent->client->ps.fd.forcePowerLevel[i_f]][i_f] && ent->client->ps.fd.forceRank < forcePowerMinRank[ent->client->ps.fd.forcePowerLevel[i_f]][i_f]) - if (0) - { - ent->client->ps.fd.forcePowerLevel[i_f] = 0; - } - - //NOTENOTE this needs to be redone taking new point system into account (instead of subtracting 1 point per rank) - //if (usedRank > myRank) - if (0) - { - ent->client->ps.fd.forcePowerLevel[i_f] = 0; - warnClient = qtrue; - } - else - { - usedRank += ent->client->ps.fd.forcePowerLevel[i_f]; - - if (ent->client->ps.fd.forcePowerLevel[i_f] && i_f == FP_LEVITATION) - { //free force jump point - usedRank -= 1; - } - - if (ent->client->ps.fd.forcePowerLevel[i_f] && i_f == FP_SABERATTACK && HasSetSaberOnly()) - { - usedRank -= 1; - } - - //NOTENOTE this needs to be redone taking new point system into account (instead of subtracting 1 point per rank) - //if (usedRank > myRank) - if (0) - { - int subRank = (usedRank - myRank); - - ent->client->ps.fd.forcePowerLevel[i_f] -= subRank; - - if (ent->client->ps.fd.forcePowerLevel[i_f] < 0) - { - ent->client->ps.fd.forcePowerLevel[i_f] = 0; - } - - warnClient = qtrue; - } - } - - if (ent->client->ps.fd.forcePowerLevel[i_f] > FORCE_LEVEL_0) - { - ent->client->ps.fd.forcePowersKnown |= (1 << i_f); - } - - if (ent->client->ps.fd.forcePowerSelected == -1 && - ent->client->ps.fd.forcePowerLevel[i_f] && - i_f != FP_SABERATTACK && i_f != FP_SABERDEFEND && i_f != FP_SABERTHROW && i_f != FP_LEVITATION) - { //select first power we come across.. unless it is an illegal power to select - ent->client->ps.fd.forcePowerSelected = i_f; - } - - i_f++; - i++; - } - - if (i_f < NUM_FORCE_POWERS) - { //info for all the powers wasn't there.. - ent->client->ps.fd.forceSide = 0; - goto validitycheck; - } + i_r = 0; + while (forcePowers[i] && forcePowers[i] != '-') + { + readBuf[i_r] = forcePowers[i]; + i_r++; i++; } + readBuf[i_r] = 0; + //THE RANK + ent->client->ps.fd.forceRank = atoi(readBuf); + i++; -validitycheck: - - // NOTENOTE IGNORE VALIDITYCHECK - -#if 0 - if (!ent->client->ps.fd.forceSide) - { //the client must have #4x0r3d their forcepower userinfo string - ent->client->ps.fd.forcePowersKnown = 0; - i = 0; - while (i < NUM_FORCE_POWERS) - { - ent->client->ps.fd.forcePowerLevel[i] = 0; - i++; - } - - ent->client->ps.fd.forceSide = FORCE_DARKSIDE; - ent->client->ps.fd.forceRank = 1; - ent->client->ps.fd.forcePowerSelected = 0; - - return; - } -#endif - - //Because we always want at least force jump level 1 - ent->client->ps.fd.forcePowersKnown |= (1 << FP_LEVITATION); - if (ent->client->ps.fd.forcePowerLevel[FP_LEVITATION] < FORCE_LEVEL_1) + i_r = 0; + while (forcePowers[i] && forcePowers[i] != '-') { - ent->client->ps.fd.forcePowerLevel[FP_LEVITATION] = FORCE_LEVEL_1; + readBuf[i_r] = forcePowers[i]; + i_r++; + i++; } + readBuf[i_r] = 0; + //THE SIDE + ent->client->ps.fd.forceSide = atoi(readBuf); + i++; - i = 0; - - if (g_forcePowerDisable.integer) + i_r = 0; + while (forcePowers[i] && forcePowers[i] != '\n' && + i_r < NUM_FORCE_POWERS) { - while (i < NUM_FORCE_POWERS) - { - if (g_forcePowerDisable.integer & (1 << i)) - { - if (ent->client->ps.fd.forcePowersKnown & (1 << i)) - { - if (i != FP_SABERATTACK && i != FP_LEVITATION && i != FP_SABERDEFEND) - { - ent->client->ps.fd.forcePowersKnown &= ~(1 << i); - ent->client->ps.fd.forcePowerLevel[i] = 0; - warnClientLimit = qtrue; - } - } - } - i++; - } - } + readBuf[0] = forcePowers[i]; + readBuf[1] = 0; - if (g_weaponDisable.integer && HasSetSaberOnly()) - { //if saber only make sure everyone has full saber force powers - /* - ent->client->ps.fd.forcePowersKnown |= (FP_SABERATTACK|FP_SABERDEFEND|FP_SABERTHROW); - ent->client->ps.fd.forcePowerLevel[FP_SABERATTACK] = FORCE_LEVEL_3; - ent->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] = FORCE_LEVEL_3; - ent->client->ps.fd.forcePowerLevel[FP_SABERTHROW] = FORCE_LEVEL_3; - */ - ent->client->ps.fd.forcePowersKnown |= FP_SABERATTACK; - - if (ent->client->ps.fd.forcePowerLevel[FP_SABERATTACK] < FORCE_LEVEL_1) + ent->client->ps.fd.forcePowerLevel[i_r] = atoi(readBuf); + if (ent->client->ps.fd.forcePowerLevel[i_r]) { - ent->client->ps.fd.forcePowerLevel[FP_SABERATTACK] = FORCE_LEVEL_1; + ent->client->ps.fd.forcePowersKnown |= (1 << i_r); } + else + { + ent->client->ps.fd.forcePowersKnown &= ~(1 << i_r); + } + i++; + i_r++; } + //THE POWERS if (HasSetSaberOnly()) { @@ -482,6 +307,19 @@ validitycheck: te->s.eventParm = 0; } + if (g_forcePowerDisable.integer) + { + gentity_t *te = G_TempEntity( vec3_origin, EV_SET_FORCE_DISABLE ); + te->r.svFlags |= SVF_BROADCAST; + te->s.eventParm = 1; + } + else + { + gentity_t *te = G_TempEntity( vec3_origin, EV_SET_FORCE_DISABLE ); + te->r.svFlags |= SVF_BROADCAST; + te->s.eventParm = 0; + } + //rww - It seems we currently want to always do this, even if the player isn't exceeding the max //rank, so.. if (g_gametype.integer == GT_TOURNAMENT) @@ -494,11 +332,15 @@ validitycheck: { //the client's rank is too high for the server and has been autocapped, so tell them if (g_gametype.integer != GT_HOLOCRON && g_gametype.integer != GT_JEDIMASTER) { +#ifdef EVENT_FORCE_RANK gentity_t *te = G_TempEntity( vec3_origin, EV_GIVE_NEW_RANK ); te->r.svFlags |= SVF_BROADCAST; te->s.trickedentindex = ent->s.number; te->s.eventParm = maxRank; + te->s.bolt1 = 0; +#endif + didEvent = qtrue; if (!(ent->r.svFlags & SVF_BOT) && g_gametype.integer != GT_TOURNAMENT) { @@ -512,10 +354,34 @@ validitycheck: ent->client->pers.teamState.state = TEAM_BEGIN; } } + +#ifdef EVENT_FORCE_RANK + te->s.bolt2 = ent->client->sess.sessionTeam; +#else + //Event isn't very reliable, I made it a string. This way I can send it to just one + //client also, as opposed to making a broadcast event. + trap_SendServerCommand(ent->s.number, va("nfr %i %i %i", maxRank, 1, ent->client->sess.sessionTeam)); + //Arg1 is new max rank, arg2 is non-0 if force menu should be shown, arg3 is the current team +#endif } ent->client->sess.setForce = qtrue; } + if (!didEvent) + { +#ifdef EVENT_FORCE_RANK + gentity_t *te = G_TempEntity( vec3_origin, EV_GIVE_NEW_RANK ); + + te->r.svFlags |= SVF_BROADCAST; + te->s.trickedentindex = ent->s.number; + te->s.eventParm = maxRank; + te->s.bolt1 = 1; + te->s.bolt2 = ent->client->sess.sessionTeam; +#else + trap_SendServerCommand(ent->s.number, va("nfr %i %i %i", maxRank, 0, ent->client->sess.sessionTeam)); +#endif + } + if (warnClientLimit) { //the server has one or more force powers disabled and the client is using them in his config //trap_SendServerCommand(ent-g_entities, va("print \"The server has one or more force powers that you have chosen disabled.\nYou will not be able to use the disable force power(s) while playing on this server.\n\"")); @@ -615,6 +481,10 @@ void WP_SpawnInitForcePowers( gentity_t *ent ) { ent->client->ps.fd.forcePowerLevel[FP_SABERATTACK] = FORCE_LEVEL_1; } + if (ent->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] < FORCE_LEVEL_1) + { + ent->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] = FORCE_LEVEL_1; + } } } @@ -670,7 +540,7 @@ int ForcePowerUsableOn(gentity_t *attacker, gentity_t *other, forcePowers_t forc return 0; } - if (other && other->client && BG_HasYsalimari(g_gametype.integer, &other->client->ps)) + if (other && other->client && BG_HasYsalamiri(g_gametype.integer, &other->client->ps)) { return 0; } @@ -730,7 +600,7 @@ qboolean WP_ForcePowerInUse( gentity_t *self, forcePowers_t forcePower ) qboolean WP_ForcePowerUsable( gentity_t *self, forcePowers_t forcePower ) { - if (BG_HasYsalimari(g_gametype.integer, &self->client->ps)) + if (BG_HasYsalamiri(g_gametype.integer, &self->client->ps)) { return qfalse; } @@ -828,7 +698,7 @@ int WP_AbsorbConversion(gentity_t *attacked, int atdAbsLevel, gentity_t *attacke } //play sound indicating that attack was absorbed - G_Sound(attacker, CHAN_AUTO, absorbHitSound); + G_PreDefSound(attacker->client->ps.origin, PDSOUND_ABSORBHIT); return getLevel; } @@ -1129,6 +999,31 @@ void ForceHeal( gentity_t *self ) // G_Sound( self, CHAN_VOICE, G_SoundIndex(va( "sound/weapons/force/heal%d.mp3", Q_irand( 1, 4 ) )) ); } +void WP_AddToClientBitflags(gentity_t *ent, int entNum) +{ + if (!ent) + { + return; + } + + if (entNum > 47) + { + ent->s.trickedentindex4 |= (1 << (entNum-48)); + } + else if (entNum > 31) + { + ent->s.trickedentindex3 |= (1 << (entNum-32)); + } + else if (entNum > 15) + { + ent->s.trickedentindex2 |= (1 << (entNum-16)); + } + else + { + ent->s.trickedentindex |= (1 << entNum); + } +} + void ForceTeamHeal( gentity_t *self ) { float radius = 256; @@ -1138,6 +1033,7 @@ void ForceTeamHeal( gentity_t *self ) int numpl = 0; int pl[MAX_CLIENTS]; int healthadd = 0; + gentity_t *te = NULL; if ( self->health <= 0 ) { @@ -1162,7 +1058,8 @@ void ForceTeamHeal( gentity_t *self ) { ent = &g_entities[i]; - if (ent && ent->client && self != ent && OnSameTeam(self, ent) && ent->client->ps.stats[STAT_HEALTH] < ent->client->ps.stats[STAT_MAX_HEALTH] && ent->client->ps.stats[STAT_HEALTH] > 0 && ForcePowerUsableOn(self, ent, FP_TEAM_HEAL)) + if (ent && ent->client && self != ent && OnSameTeam(self, ent) && ent->client->ps.stats[STAT_HEALTH] < ent->client->ps.stats[STAT_MAX_HEALTH] && ent->client->ps.stats[STAT_HEALTH] > 0 && ForcePowerUsableOn(self, ent, FP_TEAM_HEAL) && + trap_InPVS(self->client->ps.origin, ent->client->ps.origin)) { VectorSubtract(self->client->ps.origin, ent->client->ps.origin, a); @@ -1194,8 +1091,6 @@ void ForceTeamHeal( gentity_t *self ) healthadd = 25; } - BG_ForcePowerDrain( &self->client->ps, FP_TEAM_HEAL, forcePowerNeeded[self->client->ps.fd.forcePowerLevel[FP_TEAM_HEAL]][FP_TEAM_HEAL] ); - i = 0; while (i < numpl) @@ -1211,7 +1106,19 @@ void ForceTeamHeal( gentity_t *self ) g_entities[pl[i]].health = g_entities[pl[i]].client->ps.stats[STAT_HEALTH]; - G_Sound( &g_entities[pl[i]], CHAN_ITEM, G_SoundIndex("sound/weapons/force/teamheal.wav") ); + //At this point we know we got one, so add him into the collective event client bitflag + if (!te) + { + te = G_TempEntity( self->client->ps.origin, EV_TEAM_POWER); + te->s.eventParm = 1; //eventParm 1 is heal, eventParm 2 is force regen + + //since we had an extra check above, do the drain now because we got at least one guy + BG_ForcePowerDrain( &self->client->ps, FP_TEAM_HEAL, forcePowerNeeded[self->client->ps.fd.forcePowerLevel[FP_TEAM_HEAL]][FP_TEAM_HEAL] ); + } + + WP_AddToClientBitflags(te, pl[i]); + //Now cramming it all into one event.. doing this many g_sound events at once was a Bad Thing. + //G_Sound( &g_entities[pl[i]], CHAN_ITEM, G_SoundIndex("sound/weapons/force/teamheal.wav") ); } i++; } @@ -1226,6 +1133,7 @@ void ForceTeamForceReplenish( gentity_t *self ) int numpl = 0; int pl[MAX_CLIENTS]; int poweradd = 0; + gentity_t *te = NULL; if ( self->health <= 0 ) { @@ -1250,7 +1158,8 @@ void ForceTeamForceReplenish( gentity_t *self ) { ent = &g_entities[i]; - if (ent && ent->client && self != ent && OnSameTeam(self, ent) && ent->client->ps.fd.forcePower < 100 && ForcePowerUsableOn(self, ent, FP_TEAM_FORCE)) + if (ent && ent->client && self != ent && OnSameTeam(self, ent) && ent->client->ps.fd.forcePower < 100 && ForcePowerUsableOn(self, ent, FP_TEAM_FORCE) && + trap_InPVS(self->client->ps.origin, ent->client->ps.origin)) { VectorSubtract(self->client->ps.origin, ent->client->ps.origin, a); @@ -1293,7 +1202,17 @@ void ForceTeamForceReplenish( gentity_t *self ) { g_entities[pl[i]].client->ps.fd.forcePower = 100; } - G_Sound( &g_entities[pl[i]], CHAN_ITEM, G_SoundIndex("sound/weapons/force/teamforce.wav") ); + + //At this point we know we got one, so add him into the collective event client bitflag + if (!te) + { + te = G_TempEntity( self->client->ps.origin, EV_TEAM_POWER); + te->s.eventParm = 2; //eventParm 1 is heal, eventParm 2 is force regen + } + + WP_AddToClientBitflags(te, pl[i]); + //Now cramming it all into one event.. doing this many g_sound events at once was a Bad Thing. + //G_Sound( &g_entities[pl[i]], CHAN_ITEM, G_SoundIndex("sound/weapons/force/teamforce.wav") ); i++; } @@ -1449,7 +1368,7 @@ void ForceProtect( gentity_t *self ) self->client->ps.forceAllowDeactivateTime = level.time + 1500; WP_ForcePowerStart( self, FP_PROTECT, 0 ); - G_Sound( self, CHAN_BODY, protectActivateSound ); + G_PreDefSound(self->client->ps.origin, PDSOUND_PROTECT); G_Sound( self, TRACK_CHANNEL_3, protectLoopSound ); } @@ -1485,7 +1404,7 @@ void ForceAbsorb( gentity_t *self ) self->client->ps.forceAllowDeactivateTime = level.time + 1500; WP_ForcePowerStart( self, FP_ABSORB, 0 ); - G_Sound( self, CHAN_BODY, absorbActivateSound ); + G_PreDefSound(self->client->ps.origin, PDSOUND_ABSORB); G_Sound( self, TRACK_CHANNEL_3, absorbLoopSound ); } @@ -1587,7 +1506,7 @@ void ForceLightningDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec {//an enemy or object if (ForcePowerUsableOn(self, traceEnt, FP_LIGHTNING)) { - int dmg = Q_irand( 1, 3 ); + int dmg = Q_irand(1,2); //Q_irand( 1, 3 ); int modPowerLevel = -1; @@ -1803,7 +1722,7 @@ void ForceDrainDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec3_t if ( traceEnt && traceEnt->takedamage ) { - if ( traceEnt->client && self->client->ps.fd.forceDrainTime < level.time && traceEnt->client->ps.fd.forcePower ) + if ( traceEnt->client && (!OnSameTeam(self, traceEnt) || g_friendlyFire.integer) && self->client->ps.fd.forceDrainTime < level.time && traceEnt->client->ps.fd.forcePower ) {//an enemy or object if (ForcePowerUsableOn(self, traceEnt, FP_DRAIN)) { @@ -1902,6 +1821,7 @@ void ForceDrainDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec3_t tent = G_TempEntity( impactPoint, EV_FORCE_DRAINED); tent->s.eventParm = DirToByte(dir); + tent->s.owner = traceEnt->s.number; } } } @@ -2158,7 +2078,7 @@ int WP_GetVelocityForForceJump( gentity_t *self, vec3_t jumpVel, usercmd_t *ucmd G_MuteSound(self->client->ps.fd.killSoundEntIndex[TRACK_CHANNEL_1-50], CHAN_VOICE); - G_Sound( self, CHAN_AUTO, G_SoundIndex("sound/weapons/force/jump.wav") ); + G_PreDefSound(self->client->ps.origin, PDSOUND_FORCEJUMP); if (self->client->ps.fd.forceJumpCharge < JUMP_VELOCITY+40) { //give him at least a tiny boost from just a tap @@ -2223,9 +2143,6 @@ void ForceJump( gentity_t *self, usercmd_t *ucmd ) return; } - //G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" ); - //play sound here - self->client->fjDidJump = qtrue; forceJumpChargeInterval = forceJumpStrength[self->client->ps.fd.forcePowerLevel[FP_LEVITATION]]/(FORCE_JUMP_CHARGE_TIME/FRAMETIME); @@ -2337,6 +2254,12 @@ void ForceTelepathy(gentity_t *self) return; } + if (self->client->ps.powerups[PW_REDFLAG] || + self->client->ps.powerups[PW_BLUEFLAG]) + { //can't mindtrick while carrying the flag + return; + } + if (self->client->ps.forceAllowDeactivateTime < level.time && (self->client->ps.fd.forcePowersActive & (1 << FP_TELEPATHY)) ) { @@ -2453,6 +2376,11 @@ void ForceTelepathy(gentity_t *self) continue; } + if (!trap_InPVS(self->client->ps.origin, ent->client->ps.origin)) + { + continue; + } + WP_AddAsMindtricked(&self->client->ps.fd, ent->s.number); gotAtLeastOne = qtrue; } @@ -2592,6 +2520,11 @@ qboolean CanCounterThrow(gentity_t *self, qboolean pull) return 0; } + if (self->client->ps.groundEntityNum == ENTITYNUM_NONE) + { //you cannot counter a push/pull if you're in the air + return 0; + } + return 1; } @@ -2965,6 +2898,17 @@ void ForceThrow( gentity_t *self, qboolean pull ) pushPowerMod = pushPower; + if (push_list[x]->client->pers.cmd.forwardmove || + push_list[x]->client->pers.cmd.rightmove) + { //if you are moving, you get one less level of defense + otherPushPower--; + + if (otherPushPower < 0) + { + otherPushPower = 0; + } + } + if (otherPushPower && CanCounterThrow(push_list[x], pull)) { if ( pull ) @@ -3053,7 +2997,7 @@ void ForceThrow( gentity_t *self, qboolean pull ) VectorSubtract( thispush_org, self->client->ps.origin, pushDir ); } - if (modPowerLevel >= otherPushPower && push_list[x]->client) + if (modPowerLevel > otherPushPower && push_list[x]->client) { //int levDif = modPowerLevel - otherPushPower; @@ -3396,11 +3340,17 @@ void DoGripAction(gentity_t *self, forcePowers_t forcePower) return; } + if (self->client->ps.fd.forcePowerDebounce[FP_GRIP] < level.time) + { //2 damage per second while choking, resulting in 10 damage total (not including The Squeeze) + self->client->ps.fd.forcePowerDebounce[FP_GRIP] = level.time + 1000; + G_Damage(gripEnt, self, self, NULL, NULL, 2, DAMAGE_NO_ARMOR, MOD_FORCE_DARK); + } + if (gripLevel == FORCE_LEVEL_1) { gripEnt->client->ps.fd.forceGripBeingGripped = level.time + 1000; - if ((level.time - gripEnt->client->ps.fd.forceGripStarted) > 3500) + if ((level.time - gripEnt->client->ps.fd.forceGripStarted) > 5000) { WP_ForcePowerStop(self, forcePower); } @@ -3424,7 +3374,7 @@ void DoGripAction(gentity_t *self, forcePowers_t forcePower) gripEnt->client->ps.forceGripChangeMovetype = PM_FLOAT; - if ((level.time - gripEnt->client->ps.fd.forceGripStarted) > 2000 && !self->client->ps.fd.forceGripDamageDebounceTime) + if ((level.time - gripEnt->client->ps.fd.forceGripStarted) > 3000 && !self->client->ps.fd.forceGripDamageDebounceTime) { //if we managed to lift him into the air for 2 seconds, give him a crack self->client->ps.fd.forceGripDamageDebounceTime = 1; G_Damage(gripEnt, self, self, NULL, NULL, 20, DAMAGE_NO_ARMOR, MOD_FORCE_DARK); @@ -3439,7 +3389,7 @@ void DoGripAction(gentity_t *self, forcePowers_t forcePower) WP_ForcePowerStop(gripEnt, FP_GRIP); } } - else if ((level.time - gripEnt->client->ps.fd.forceGripStarted) > 3500) + else if ((level.time - gripEnt->client->ps.fd.forceGripStarted) > 4000) { WP_ForcePowerStop(self, forcePower); } @@ -3509,7 +3459,7 @@ void DoGripAction(gentity_t *self, forcePowers_t forcePower) gripEnt->client->ps.forceGripMoveInterval = level.time + 300; //only update velocity every 300ms, so as to avoid heavy bandwidth usage } - if ((level.time - gripEnt->client->ps.fd.forceGripStarted) > 2000 && !self->client->ps.fd.forceGripDamageDebounceTime) + if ((level.time - gripEnt->client->ps.fd.forceGripStarted) > 3000 && !self->client->ps.fd.forceGripDamageDebounceTime) { //if we managed to lift him into the air for 2 seconds, give him a crack self->client->ps.fd.forceGripDamageDebounceTime = 1; G_Damage(gripEnt, self, self, NULL, NULL, 40, DAMAGE_NO_ARMOR, MOD_FORCE_DARK); @@ -3629,7 +3579,7 @@ static void WP_UpdateMindtrickEnts(gentity_t *self) RemoveTrickedEnt(&self->client->ps.fd, i); } } - else if (BG_HasYsalimari(g_gametype.integer, &ent->client->ps)) + else if (BG_HasYsalamiri(g_gametype.integer, &ent->client->ps)) { RemoveTrickedEnt(&self->client->ps.fd, i); } @@ -3645,6 +3595,11 @@ static void WP_UpdateMindtrickEnts(gentity_t *self) { //everyone who we had tricked is no longer tricked, so stop the power WP_ForcePowerStop(self, FP_TELEPATHY); } + else if (self->client->ps.powerups[PW_REDFLAG] || + self->client->ps.powerups[PW_BLUEFLAG]) + { + WP_ForcePowerStop(self, FP_TELEPATHY); + } } static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd_t *cmd ) @@ -4290,6 +4245,10 @@ void HolocronUpdate(gentity_t *self) { self->client->ps.fd.forcePowerLevel[FP_SABERATTACK] = FORCE_LEVEL_1; } + if (self->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] < FORCE_LEVEL_1) + { + self->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] = FORCE_LEVEL_1; + } } } @@ -4306,11 +4265,21 @@ void JediMasterUpdate(gentity_t *self) self->client->ps.fd.forcePowersKnown |= (1 << i); self->client->ps.fd.forcePowerLevel[i] = FORCE_LEVEL_3; - if (i == FP_TEAM_HEAL || i == FP_TEAM_FORCE) - { + if (i == FP_TEAM_HEAL || i == FP_TEAM_FORCE || + i == FP_DRAIN || i == FP_ABSORB) + { //team powers are useless in JM, absorb is too because no one else has powers to absorb. Drain is just + //relatively useless in comparison, because its main intent is not to heal, but rather to cripple others + //by draining their force at the same time. And no one needs force in JM except the JM himself. self->client->ps.fd.forcePowersKnown &= ~(1 << i); self->client->ps.fd.forcePowerLevel[i] = 0; } + + if (i == FP_TELEPATHY) + { //this decision was made because level 3 mindtrick allows the JM to just hide too much, and no one else has force + //sight to counteract it. Since the JM himself is the focus of gameplay in this mode, having him hidden for large + //durations is indeed a bad thing. + self->client->ps.fd.forcePowerLevel[i] = FORCE_LEVEL_2; + } } else { @@ -4368,6 +4337,10 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) { self->client->ps.fd.saberAnimLevel = self->client->ps.fd.forcePowerLevel[FP_SABERATTACK]; } + else if (!self->client->ps.fd.saberAnimLevel) + { + self->client->ps.fd.saberAnimLevel = FORCE_LEVEL_1; + } if (!(self->client->ps.fd.forcePowersKnown & (1 << FP_LEVITATION))) { @@ -4419,7 +4392,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) if (self->client->pers.cmd.upmove && self->client->ps.fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1) { //force getup - G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/weapons/force/jump.wav") ); + G_PreDefSound(self->client->ps.origin, PDSOUND_FORCEJUMP); self->client->ps.forceDodgeAnim = 2; self->client->ps.forceHandExtendTime = level.time + 800;//1000; @@ -4461,7 +4434,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) prepower = self->client->ps.fd.forcePower; } - if (self && self->client && (BG_HasYsalimari(g_gametype.integer, &self->client->ps) || + if (self && self->client && (BG_HasYsalamiri(g_gametype.integer, &self->client->ps) || self->client->ps.fd.forceDeactivateAll)) { i = 0; @@ -4580,7 +4553,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) if (self->client->ps.fd.forceJumpSound) { - G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/weapons/force/jump.wav") ); + G_PreDefSound(self->client->ps.origin, PDSOUND_FORCEJUMP); self->client->ps.fd.forceJumpSound = 0; } @@ -4588,7 +4561,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) { if (self->client->ps.fd.forceGripSoundTime < level.time) { - G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/weapons/force/grip.mp3") ); + G_PreDefSound(self->client->ps.origin, PDSOUND_FORCEGRIP); self->client->ps.fd.forceGripSoundTime = level.time + 1000; } } @@ -4652,14 +4625,14 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) } /* - if ( (ucmd->buttons & BUTTON_FORCEJUMP) && !BG_HasYsalimari(g_gametype.integer, &self->client->ps) && BG_CanUseFPNow(g_gametype.integer, &self->client->ps, level.time, FP_LEVITATION) ) + if ( (ucmd->buttons & BUTTON_FORCEJUMP) && !BG_HasYsalamiri(g_gametype.integer, &self->client->ps) && BG_CanUseFPNow(g_gametype.integer, &self->client->ps, level.time, FP_LEVITATION) ) {//just charging up ForceJumpCharge( self, ucmd ); usingForce = qtrue; } */ #ifndef METROID_JUMP - else if ( /*!self->client->fjDidJump &&*/ (ucmd->upmove > 10) && (self->client->ps.pm_flags & PMF_JUMP_HELD) && self->client->ps.groundTime && (level.time - self->client->ps.groundTime) > 150 && !BG_HasYsalimari(g_gametype.integer, &self->client->ps) && BG_CanUseFPNow(g_gametype.integer, &self->client->ps, level.time, FP_LEVITATION)/*&& !self->client->ps.fd.forceJumpZStart*/ ) + else if ( /*!self->client->fjDidJump &&*/ (ucmd->upmove > 10) && (self->client->ps.pm_flags & PMF_JUMP_HELD) && self->client->ps.groundTime && (level.time - self->client->ps.groundTime) > 150 && !BG_HasYsalamiri(g_gametype.integer, &self->client->ps) && BG_CanUseFPNow(g_gametype.integer, &self->client->ps, level.time, FP_LEVITATION)/*&& !self->client->ps.fd.forceJumpZStart*/ ) {//just charging up ForceJumpCharge( self, ucmd ); usingForce = qtrue; @@ -4737,7 +4710,7 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) } if ( (ucmd->buttons & BUTTON_FORCEPOWER) /*&& - !BG_HasYsalimari(g_gametype.integer, &self->client->ps)*/ && + !BG_HasYsalamiri(g_gametype.integer, &self->client->ps)*/ && // WP_ForcePowerUsable(self, self->client->ps.fd.forcePowerSelected) && BG_CanUseFPNow(g_gametype.integer, &self->client->ps, level.time, self->client->ps.fd.forcePowerSelected)) { @@ -4795,7 +4768,11 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) { if (g_gametype.integer != GT_HOLOCRON || g_MaxHolocronCarry.value) { - if (self->client->ps.isJediMaster && g_gametype.integer == GT_JEDIMASTER) + if (self->client->ps.powerups[PW_FORCE_BOON]) + { + WP_ForcePowerRegenerate( self, 6 ); + } + else if (self->client->ps.isJediMaster && g_gametype.integer == GT_JEDIMASTER) { WP_ForcePowerRegenerate( self, 4 ); //jedi master regenerates 4 times as fast } @@ -4828,7 +4805,13 @@ powersetcheck: if (prepower && self->client->ps.fd.forcePower < prepower) { - self->client->ps.fd.forcePower = prepower; + int dif = ((prepower - self->client->ps.fd.forcePower)/2); + if (dif < 1) + { + dif = 1; + } + + self->client->ps.fd.forcePower = (prepower-dif); } } diff --git a/CODE-mp/game/w_saber.c b/CODE-mp/game/w_saber.c index a3710e6..5e59060 100644 --- a/CODE-mp/game/w_saber.c +++ b/CODE-mp/game/w_saber.c @@ -46,6 +46,7 @@ void SaberUpdateSelf(gentity_t *ent) ent->clipmask = 0; } else if (g_entities[ent->r.ownerNum].client->ps.weapon != WP_SABER || + (g_entities[ent->r.ownerNum].client->ps.pm_flags & PMF_FOLLOW) || g_entities[ent->r.ownerNum].health < 1 || g_entities[ent->r.ownerNum].client->ps.saberHolstered || !g_entities[ent->r.ownerNum].client->ps.fd.forcePowerLevel[FP_SABERATTACK]/* || @@ -57,7 +58,7 @@ void SaberUpdateSelf(gentity_t *ent) else { ent->r.contents = CONTENTS_LIGHTSABER; - ent->clipmask = MASK_SOLID | CONTENTS_LIGHTSABER; + ent->clipmask = MASK_PLAYERSOLID | CONTENTS_LIGHTSABER; } trap_LinkEntity(ent); @@ -90,7 +91,7 @@ void WP_SaberInitBladeData( gentity_t *ent ) saberent->r.svFlags = SVF_USE_CURRENT_ORIGIN; saberent->r.ownerNum = ent->s.number; - saberent->clipmask = MASK_SOLID | CONTENTS_LIGHTSABER; + saberent->clipmask = MASK_PLAYERSOLID | CONTENTS_LIGHTSABER; saberent->r.contents = CONTENTS_LIGHTSABER; VectorSet( saberent->r.mins, -8.0f, -8.0f, -8.0f ); @@ -112,6 +113,7 @@ void WP_SaberInitBladeData( gentity_t *ent ) saberHumSound = G_SoundIndex("sound/weapons/saber/saberhum1.wav"); } +#if 0 static void G_SwingAngles( float destination, float swingTolerance, float clampTolerance, float speed, float *angle, qboolean *swinging ) { float swing; @@ -167,6 +169,7 @@ static void G_SwingAngles( float destination, float swingTolerance, float clampT *angle = AngleMod( destination + (clampTolerance - 1) ); } } +#endif //NOTE: If C` is modified this function should be modified as well (and vice versa) void G_G2ClientSpineAngles( gentity_t *ent, vec3_t viewAngles, const vec3_t angles, vec3_t thoracicAngles, vec3_t ulAngles, vec3_t llAngles ) @@ -194,34 +197,59 @@ void G_G2ClientSpineAngles( gentity_t *ent, vec3_t viewAngles, const vec3_t angl trap_G2API_GetBoltMatrix_NoReconstruct( ent->client->ghoul2, 0, ent->bolt_Motion, &boltMatrix, vec3_origin, ent->client->ps.origin, level.time, /*cgs.gameModels*/0, vec3_origin); //trap_G2API_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_X, motionFwd ); + //POSITIVE_X: + /* motionFwd[0] = boltMatrix.matrix[0][0]; motionFwd[1] = boltMatrix.matrix[1][0]; motionFwd[2] = boltMatrix.matrix[2][0]; + */ + + + //NEGATIVE_Y: + motionFwd[0] = -boltMatrix.matrix[0][1]; + motionFwd[1] = -boltMatrix.matrix[1][1]; + motionFwd[2] = -boltMatrix.matrix[2][1]; vectoangles( motionFwd, motionAngles ); for ( ang = 0; ang < 3; ang++ ) { viewAngles[ang] = AngleNormalize180( viewAngles[ang] - AngleNormalize180( motionAngles[ang] ) ); } + + if (viewAngles[YAW] < -90) + { + viewAngles[YAW] += 360; + } + + viewAngles[YAW] -= 90; } //distribute the angles differently up the spine //NOTE: each of these distributions must add up to 1.0f - thoracicAngles[PITCH] = viewAngles[PITCH]*0.20f; - llAngles[PITCH] = viewAngles[PITCH]*0.40f; - ulAngles[PITCH] = viewAngles[PITCH]*0.40f; + thoracicAngles[PITCH] = 0;//viewAngles[PITCH]*0.20f; + llAngles[PITCH] = 0;//viewAngles[PITCH]*0.40f; + ulAngles[PITCH] = 0;//viewAngles[PITCH]*0.40f; + thoracicAngles[YAW] = viewAngles[YAW]*0.20f - (viewAngles[PITCH]*(viewAngles[YAW]*.020f)); + ulAngles[YAW] = viewAngles[YAW]*0.25f - (viewAngles[PITCH]*(viewAngles[YAW]*.0005f)); + llAngles[YAW] = viewAngles[YAW]*0.25f - (viewAngles[PITCH]*(viewAngles[YAW]*.0005f)); -// thoracicAngles[YAW] = viewAngles[YAW]*0.20f; -// ulAngles[YAW] = viewAngles[YAW]*0.35f; -// llAngles[YAW] = viewAngles[YAW]*0.45f; - thoracicAngles[YAW] = viewAngles[YAW]*0.20f; - ulAngles[YAW] = viewAngles[YAW]*0.25f; - llAngles[YAW] = viewAngles[YAW]*0.25f; + if (thoracicAngles[YAW] > 20) + { + thoracicAngles[YAW] = 20; + } + if (ulAngles[YAW] > 20) + { + ulAngles[YAW] = 20; + } + if (llAngles[YAW] > 20) + { + llAngles[YAW] = 20; + } thoracicAngles[ROLL] = viewAngles[ROLL]*0.20f; ulAngles[ROLL] = viewAngles[ROLL]*0.35f; llAngles[ROLL] = viewAngles[ROLL]*0.45f; - + for ( ang = 0; ang < 3; ang++ ) { if (ulAngles[ang] < 0) @@ -253,7 +281,8 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ float degrees_positive = 0; qboolean yawing = qfalse; vec3_t ulAngles, llAngles, viewAngles, angles, thoracicAngles = {0,0,0}; - + //float pitchViewAng; + //float yawViewAng; VectorCopy( ent->client->ps.viewangles, headAngles ); headAngles[YAW] = AngleMod( headAngles[YAW] ); @@ -282,10 +311,6 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ torsoAngles[YAW] = headAngles[YAW] + 0.25 * movementOffsets[ dir ]; - // torso -// G_SwingAngles( torsoAngles[YAW], 25, 90, /*cg_swingSpeed.value*/ 0.3, &ent->client->ps.viewangles[YAW], &yawing ); -// torsoAngles[YAW] = ent->client->ps.viewangles[YAW]; - // --------- pitch ------------- // only show a fraction of the pitch angle in the torso @@ -294,7 +319,11 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ } else { dest = headAngles[PITCH] * 0.75; } - G_SwingAngles( dest, 15, 30, 0.1, &ent->client->ps.viewangles[PITCH], &yawing ); + + //G_SwingAngles call disabled, at least for now. It isn't necessary on the server. +// pitchViewAng = ent->client->ps.viewangles[PITCH]; +// G_SwingAngles( dest, 15, 30, 0.1, &pitchViewAng, &yawing ); + torsoAngles[PITCH] = ent->client->ps.viewangles[PITCH]; // --------- roll ------------- @@ -345,6 +374,12 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ velPos[0] = ent->client->ps.origin[0] + velocity[0]; velPos[1] = ent->client->ps.origin[1] + velocity[1]; velPos[2] = ent->client->ps.origin[2] + velocity[2]; + + if (ent->client->ps.groundEntityNum == ENTITYNUM_NONE) + { //off the ground, no direction-based leg angles + VectorCopy(ent->client->ps.origin, velPos); + } + VectorSubtract(ent->client->ps.origin, velPos, velAng); if (!VectorCompare(velAng, vec3_origin)) @@ -399,7 +434,10 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ } } - G_SwingAngles( legsAngles[YAW], 40, 90, /*cg_swingSpeed.value*/ 0.3, &ent->client->ps.viewangles[YAW], &yawing ); + //G_SwingAngles call disabled, at least for now. It isn't necessary on the server. +// yawViewAng = ent->client->ps.viewangles[YAW]; +// G_SwingAngles( legsAngles[YAW], 40, 90, /*cg_swingSpeed.value*/ 0.3, &yawViewAng, &yawing ); + legsAngles[YAW] = ent->client->ps.viewangles[YAW]; legsAngles[ROLL] = 0; @@ -414,6 +452,12 @@ void G_G2PlayerAngles( gentity_t *ent, vec3_t legs[3], vec3_t legsAngles){ // trap_G2API_SetBoneAngles(ent->client->ghoul2, 0, "upper_lumbar", torsoAngles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 0, level.time); VectorCopy( ent->client->ps.viewangles, viewAngles ); + + if (viewAngles[PITCH] > 290) + { //keep the same general range as lerpAngles on the client so we can use the same spine correction + viewAngles[PITCH] -= 360; + } + viewAngles[YAW] = viewAngles[ROLL] = 0; viewAngles[PITCH] *= 0.5; @@ -980,11 +1024,9 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q if (doInterpolate) { //This didn't quite work out like I hoped. But it's better than nothing. Sort of. - vec3_t oldSaberStart, oldSaberEnd, saberDif, oldSaberDif, newOldAngles, newOldDif; - vec3_t mins, maxs; - float temp, ang; - float c, s; - int i = 0; + vec3_t oldSaberStart, oldSaberEnd, saberDif, oldSaberDif; + int traceTests = 0; + float trDif = 8; VectorCopy(self->client->lastSaberBase, oldSaberStart); VectorCopy(self->client->lastSaberTip, oldSaberEnd); @@ -992,57 +1034,49 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q VectorSubtract(saberStart, saberEnd, saberDif); VectorSubtract(oldSaberStart, oldSaberEnd, oldSaberDif); - saberEnd[0] = saberStart[0] - (saberDif[0]/2); - saberEnd[1] = saberStart[1] - (saberDif[1]/2); - saberEnd[2] = saberStart[2] - (saberDif[2]/2); + VectorNormalize(saberDif); + VectorNormalize(oldSaberDif); - oldSaberEnd[0] = oldSaberStart[0] - (oldSaberDif[0]/2); - oldSaberEnd[1] = oldSaberStart[1] - (oldSaberDif[1]/2); - oldSaberEnd[2] = oldSaberStart[2] - (oldSaberDif[2]/2); + saberEnd[0] = saberStart[0] - (saberDif[0]*trDif); + saberEnd[1] = saberStart[1] - (saberDif[1]*trDif); + saberEnd[2] = saberStart[2] - (saberDif[2]*trDif); + + oldSaberEnd[0] = oldSaberStart[0] - (oldSaberDif[0]*trDif); + oldSaberEnd[1] = oldSaberStart[1] - (oldSaberDif[1]*trDif); + oldSaberEnd[2] = oldSaberStart[2] - (oldSaberDif[2]*trDif); //G_TestLine(oldSaberEnd, saberEnd, 0x0000ff, 50); - VectorSubtract(saberEnd, oldSaberEnd, newOldDif); - VectorNormalize(newOldDif); - vectoangles(newOldDif, newOldAngles); + trap_Trace(&tr, saberEnd, NULL, NULL, saberStart, self->s.number, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER)); - ang = newOldAngles[YAW] * 0.0174533f; + trDif++; - // rotate - c = cos( ang ); - s = sin( ang ); - - if (SaberAttacking(self)) - { //increase trace thickness for attack - VectorSet( mins, -4, -4, -4 ); - VectorSet( maxs, 4, 4, 4 ); - } - else + while (tr.fraction == 1.0 && traceTests < 4 && tr.entityNum >= ENTITYNUM_NONE) { - VectorSet( mins, -1, -1, -1 ); - VectorSet( maxs, 1, 1, 1 ); + VectorCopy(self->client->lastSaberBase, oldSaberStart); + VectorCopy(self->client->lastSaberTip, oldSaberEnd); + + VectorSubtract(saberStart, saberEnd, saberDif); + VectorSubtract(oldSaberStart, oldSaberEnd, oldSaberDif); + + VectorNormalize(saberDif); + VectorNormalize(oldSaberDif); + + saberEnd[0] = saberStart[0] - (saberDif[0]*trDif); + saberEnd[1] = saberStart[1] - (saberDif[1]*trDif); + saberEnd[2] = saberStart[2] - (saberDif[2]*trDif); + + oldSaberEnd[0] = oldSaberStart[0] - (oldSaberDif[0]*trDif); + oldSaberEnd[1] = oldSaberStart[1] - (oldSaberDif[1]*trDif); + oldSaberEnd[2] = oldSaberStart[2] - (oldSaberDif[2]*trDif); + + //G_TestLine(oldSaberEnd, saberEnd, 0x0000ff, 50); + + trap_Trace(&tr, saberEnd, NULL, NULL, saberStart, self->s.number, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER)); + + traceTests++; + trDif += 8; } - - temp = c * mins[0] - s * mins[1]; - mins[1] = s * mins[0] + c * mins[1]; - mins[0] = temp; - - temp = c * maxs[0] - s * maxs[1]; - maxs[1] = s * maxs[0] + c * maxs[1]; - maxs[0] = temp; - - // ensure that maxs is greater than mins - for ( i = 0; i < 2; i++ ) - { - if ( maxs[i] < mins[i] ) - { - temp = maxs[i]; - maxs[i] = mins[i]; - mins[i] = temp; - } - } - - trap_Trace(&tr, saberEnd, mins, maxs, saberStart, self->s.number, (MASK_PLAYERSOLID|CONTENTS_LIGHTSABER)); } else { @@ -1085,6 +1119,10 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q VectorSubtract(saberEnd, saberStart, dir); VectorNormalize(dir); + //rww - I'm saying || tr.startsolid here, because otherwise your saber tends to skip positions and go through + //people, and the compensation traces start in their bbox too. Which results in the saber passing through people + //when you visually cut right through them. Which sucks. + if ((tr.fraction != 1 || tr.startsolid) && /*(!g_entities[tr.entityNum].client || !g_entities[tr.entityNum].client->ps.usingATST) &&*/ //g_entities[tr.entityNum].client && @@ -1144,7 +1182,16 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q if (dmg > 5) { if ((g_entities[tr.entityNum].client->ps.fd.forcePowerLevel[FP_SABERATTACK] - self->client->ps.fd.forcePowerLevel[FP_SABERATTACK]) > 1 && - Q_irand(1, 10) < 8) //used to be < 7 + Q_irand(1, 10) < 9) //used to be < 7 + { //Just got blocked by someone with a decently higher attack level, so enter into a lock (where they have the advantage due to a higher attack lev) + if (WP_SabersCheckLock(self, &g_entities[tr.entityNum])) + { + self->client->ps.saberBlocked = BLOCKED_NONE; + g_entities[tr.entityNum].client->ps.saberBlocked = BLOCKED_NONE; + return didHit; + } + } + else if (Q_irand(1, 10) < 3) { //Just got blocked by someone with a decently higher attack level, so enter into a lock (where they have the advantage due to a higher attack lev) if (WP_SabersCheckLock(self, &g_entities[tr.entityNum])) { @@ -1312,7 +1359,7 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q if (dmg > 5) { - if (Q_irand(1, 10) < 8) //used to be < 7 + if (Q_irand(1, 10) < 9) //used to be < 7 { if (WP_SabersCheckLock(self, otherOwner)) { @@ -1343,20 +1390,178 @@ qboolean CheckSaberDamage(gentity_t *self, vec3_t saberStart, vec3_t saberEnd, q return didHit; } -#define MIN_SABER_SLICE_DISTANCE 60 +#define MIN_SABER_SLICE_DISTANCE 50 #define MIN_SABER_SLICE_RETURN_DISTANCE 30 -#define SABER_THROWN_HIT_DAMAGE 40 -#define SABER_THROWN_RETURN_HIT_DAMAGE 20 +#define SABER_THROWN_HIT_DAMAGE 30 +#define SABER_THROWN_RETURN_HIT_DAMAGE 5 void thrownSaberTouch (gentity_t *saberent, gentity_t *other, trace_t *trace); +qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity_t *saberOwner, gentity_t *ent, int dist, int returning) +{ + vec3_t vecsub; + float veclen; + gentity_t *te; + + if (saberOwner && saberOwner->client && saberOwner->client->ps.saberAttackWound > level.time) + { + return qfalse; + } + + if (ent && ent->client && ent->inuse && ent->s.number != saberOwner->s.number && + ent->health > 0 && ent->takedamage && + trap_InPVS(ent->client->ps.origin, saberent->r.currentOrigin) && + ent->client->sess.sessionTeam != TEAM_SPECTATOR && + ent->client->pers.connected) + { + if (ent->inuse && ent->client && + ent->client->ps.duelInProgress && + ent->client->ps.duelIndex != saberOwner->s.number) + { + return qfalse; + } + + if (ent->inuse && ent->client && + saberOwner->client->ps.duelInProgress && + saberOwner->client->ps.duelIndex != ent->s.number) + { + return qfalse; + } + + VectorSubtract(saberent->r.currentOrigin, ent->client->ps.origin, vecsub); + veclen = VectorLength(vecsub); + + if (veclen < dist) + { + trace_t tr; + + trap_Trace(&tr, saberent->r.currentOrigin, NULL, NULL, ent->client->ps.origin, saberent->s.number, MASK_SHOT); + + /* + if (tr.startsolid || tr.allsolid) + { + if (!returning) + { //return to owner if startsolid + thrownSaberTouch(saberent, saberent, NULL); + } + + return qfalse; + } + */ + + if (tr.fraction == 1 || tr.entityNum == ent->s.number) + { //Slice them + if (!saberOwner->client->ps.isJediMaster && WP_SaberCanBlock(ent, tr.endpos, 0, MOD_SABER, qfalse, 8)) + { + te = G_TempEntity( tr.endpos, EV_SABER_BLOCK ); + VectorCopy(tr.endpos, te->s.origin); + VectorCopy(tr.plane.normal, te->s.angles); + if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2]) + { + te->s.angles[1] = 1; + } + te->s.eventParm = 1; + + if (!returning) + { //return to owner if blocked + thrownSaberTouch(saberent, saberent, NULL); + } + + saberOwner->client->ps.saberAttackWound = level.time + 500; + return qfalse; + } + else + { + vec3_t dir; + + VectorSubtract(tr.endpos, saberent->r.currentOrigin, dir); + VectorNormalize(dir); + + if (!dir[0] && !dir[1] && !dir[2]) + { + dir[1] = 1; + } + + if (saberOwner->client->ps.isJediMaster) + { //2x damage for the Jedi Master + G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, saberent->damage*2, 0, MOD_SABER); + } + else + { + G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, saberent->damage, 0, MOD_SABER); + } + + te = G_TempEntity( tr.endpos, EV_SABER_HIT ); + VectorCopy(tr.endpos, te->s.origin); + VectorCopy(tr.plane.normal, te->s.angles); + if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2]) + { + te->s.angles[1] = 1; + } + + te->s.eventParm = 1; + + if (!returning) + { //return to owner if blocked + thrownSaberTouch(saberent, saberent, NULL); + } + } + + saberOwner->client->ps.saberAttackWound = level.time + 500; + } + } + } + else if (ent && !ent->client && ent->inuse && ent->takedamage && ent->health > 0 && ent->s.number != saberOwner->s.number && + ent->s.number != saberent->s.number && trap_InPVS(ent->r.currentOrigin, saberent->r.currentOrigin)) + { + VectorSubtract(saberent->r.currentOrigin, ent->r.currentOrigin, vecsub); + veclen = VectorLength(vecsub); + + if (veclen < dist) + { + trace_t tr; + + trap_Trace(&tr, saberent->r.currentOrigin, NULL, NULL, ent->r.currentOrigin, saberent->s.number, MASK_SHOT); + + if (tr.fraction == 1 || tr.entityNum == ent->s.number) + { + vec3_t dir; + + VectorSubtract(tr.endpos, saberent->r.currentOrigin, dir); + VectorNormalize(dir); + + G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, 5, 0, MOD_SABER); + + te = G_TempEntity( tr.endpos, EV_SABER_HIT ); + VectorCopy(tr.endpos, te->s.origin); + VectorCopy(tr.plane.normal, te->s.angles); + if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2]) + { + te->s.angles[1] = 1; + } + + te->s.eventParm = 1; + + if (!returning) + { //return to owner if blocked + thrownSaberTouch(saberent, saberent, NULL); + } + + saberOwner->client->ps.saberAttackWound = level.time + 500; + } + } + } + + return qtrue; +} + void saberCheckRadiusDamage(gentity_t *saberent, int returning) { //we're going to cheat and damage players within the saber's radius, just for the sake of doing things more "efficiently" int i = 0; int dist = 0; - gentity_t *ent, *te; + gentity_t *ent; gentity_t *saberOwner = &g_entities[saberent->r.ownerNum]; if (returning && returning != 2) @@ -1382,137 +1587,13 @@ void saberCheckRadiusDamage(gentity_t *saberent, int returning) { ent = &g_entities[i]; - if (ent && ent->client && ent->inuse && ent->s.number != saberOwner->s.number && - ent->health > 0 && ent->takedamage && - trap_InPVS(ent->client->ps.origin, saberent->r.currentOrigin)) - { - vec3_t vecsub; - float veclen; - - if (ent->inuse && ent->client && - ent->client->ps.duelInProgress && - ent->client->ps.duelIndex != saberOwner->s.number) - { - i++; - continue; - } - - if (ent->inuse && ent->client && - saberOwner->client->ps.duelInProgress && - saberOwner->client->ps.duelIndex != ent->s.number) - { - i++; - continue; - } - - VectorSubtract(saberent->r.currentOrigin, ent->client->ps.origin, vecsub); - veclen = VectorLength(vecsub); - - if (veclen < dist) - { - trace_t tr; - - trap_Trace(&tr, saberent->r.currentOrigin, NULL, NULL, ent->client->ps.origin, saberent->s.number, MASK_SHOT); - - if (tr.fraction == 1 || tr.entityNum == ent->s.number) - { //Slice them - if (!saberOwner->client->ps.isJediMaster && WP_SaberCanBlock(ent, tr.endpos, 0, MOD_SABER, qfalse, 0)) - { - te = G_TempEntity( tr.endpos, EV_SABER_BLOCK ); - VectorCopy(tr.endpos, te->s.origin); - VectorCopy(tr.plane.normal, te->s.angles); - if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2]) - { - te->s.angles[1] = 1; - } - te->s.eventParm = 1; - - if (!returning) - { //return to owner if blocked - thrownSaberTouch(saberent, saberent, NULL); - } - return; - } - else - { - vec3_t dir; - - VectorSubtract(tr.endpos, saberent->r.currentOrigin, dir); - VectorNormalize(dir); - - if (!dir[0] && !dir[1] && !dir[2]) - { - dir[1] = 1; - } - - if (saberOwner->client->ps.isJediMaster) - { //2x damage for the Jedi Master - G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, saberent->damage*2, 0, MOD_SABER); - } - else - { - G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, saberent->damage, 0, MOD_SABER); - } - - te = G_TempEntity( tr.endpos, EV_SABER_HIT ); - VectorCopy(tr.endpos, te->s.origin); - VectorCopy(tr.plane.normal, te->s.angles); - if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2]) - { - te->s.angles[1] = 1; - } - - te->s.eventParm = 1; - } - - saberOwner->client->ps.saberAttackWound = level.time + 300; - } - } - } - else if (ent && ent->inuse && ent->takedamage && ent->health > 0 && ent->s.number != saberOwner->s.number && - ent->s.number != saberent->s.number && trap_InPVS(ent->r.currentOrigin, saberent->r.currentOrigin)) - { - vec3_t vecsub; - float veclen; - - VectorSubtract(saberent->r.currentOrigin, ent->r.currentOrigin, vecsub); - veclen = VectorLength(vecsub); - - if (veclen < dist) - { - trace_t tr; - - trap_Trace(&tr, saberent->r.currentOrigin, NULL, NULL, ent->r.currentOrigin, saberent->s.number, MASK_SHOT); - - if (tr.fraction == 1 || tr.entityNum == ent->s.number) - { - vec3_t dir; - - VectorSubtract(tr.endpos, saberent->r.currentOrigin, dir); - VectorNormalize(dir); - - G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, 5, 0, MOD_SABER); - - te = G_TempEntity( tr.endpos, EV_SABER_HIT ); - VectorCopy(tr.endpos, te->s.origin); - VectorCopy(tr.plane.normal, te->s.angles); - if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2]) - { - te->s.angles[1] = 1; - } - - te->s.eventParm = 1; - - saberOwner->client->ps.saberAttackWound = level.time + 100; - } - } - } + CheckThrownSaberDamaged(saberent, saberOwner, ent, dist, returning); i++; } } -#define THROWN_SABER_COMP +//#define THROWN_SABER_COMP void saberMoveBack( gentity_t *ent, qboolean goingBack ) { @@ -1556,6 +1637,9 @@ void saberMoveBack( gentity_t *ent, qboolean goingBack ) //Unfortunately doing this would defeat the purpose of the compensation. We will have to settle for a jerk on the client. //VectorCopy( origin, ent->r.currentOrigin ); + CheckThrownSaberDamaged(ent, &g_entities[ent->r.ownerNum], &g_entities[tr.entityNum], 256, 0); + + tr.startsolid = 0; thrownSaberTouch(ent, &g_entities[tr.entityNum], &tr); return; } @@ -1606,7 +1690,7 @@ void MakeDeadSaber(gentity_t *ent) saberent->r.svFlags = SVF_USE_CURRENT_ORIGIN; saberent->r.ownerNum = ent->s.number; - saberent->clipmask = MASK_SOLID; + saberent->clipmask = MASK_PLAYERSOLID; saberent->r.contents = CONTENTS_TRIGGER;//0; VectorSet( saberent->r.mins, -3.0f, -3.0f, -3.0f ); @@ -1740,7 +1824,7 @@ void saberBackToOwner(gentity_t *saberent) saberent->s.pos.trTime = level.time; } - if (ownerLen <= 256) + if (ownerLen <= 512) { saberent->s.saberInFlight = qfalse; saberent->s.loopSound = saberHumSound; @@ -1775,8 +1859,16 @@ void saberBackToOwner(gentity_t *saberent) saberent->nextthink = level.time; } +void saberFirstThrown(gentity_t *saberent); + void thrownSaberTouch (gentity_t *saberent, gentity_t *other, trace_t *trace) { + gentity_t *hitEnt = other; + + if (other && other->s.number == saberent->r.ownerNum) + { + return; + } VectorClear(saberent->s.pos.trDelta); saberent->s.pos.trTime = level.time; @@ -1792,6 +1884,17 @@ void thrownSaberTouch (gentity_t *saberent, gentity_t *other, trace_t *trace) saberent->think = saberBackToOwner; saberent->nextthink = level.time; + //saberCheckRadiusDamage(saberent, 2); + if (other && other->r.ownerNum < MAX_CLIENTS && + (other->r.contents & CONTENTS_LIGHTSABER) && + g_entities[other->r.ownerNum].client && + g_entities[other->r.ownerNum].inuse) + { + hitEnt = &g_entities[other->r.ownerNum]; + } + + CheckThrownSaberDamaged(saberent, &g_entities[saberent->r.ownerNum], hitEnt, 256, 0); + saberent->speed = 0; } @@ -1859,7 +1962,7 @@ void saberFirstThrown(gentity_t *saberent) } } - if (BG_HasYsalimari(g_gametype.integer, &saberOwn->client->ps)) + if (BG_HasYsalamiri(g_gametype.integer, &saberOwn->client->ps)) { thrownSaberTouch(saberent, saberent, NULL); goto runMin; @@ -1896,6 +1999,9 @@ void saberFirstThrown(gentity_t *saberent) traceTo[1] += fwd[1]*4096; traceTo[2] += fwd[2]*4096; + saberMoveBack(saberent, qfalse); + VectorCopy(saberent->r.currentOrigin, saberent->s.pos.trBase); + if (saberOwn->client->ps.fd.forcePowerLevel[FP_SABERTHROW] >= FORCE_LEVEL_3) { //if highest saber throw rank, we can direct the saber toward players directly by looking at them trap_Trace(&tr, traceFrom, NULL, NULL, traceTo, saberOwn->s.number, MASK_PLAYERSOLID); @@ -1905,23 +2011,25 @@ void saberFirstThrown(gentity_t *saberent) trap_Trace(&tr, traceFrom, NULL, NULL, traceTo, saberOwn->s.number, MASK_SOLID); } - VectorSubtract(tr.endpos, saberent->r.currentOrigin, dir); + //G_TestLine(traceFrom, tr.endpos, 0x000000ff, 100); - VectorNormalize(dir); - - saberMoveBack(saberent, qfalse); - VectorCopy(saberent->r.currentOrigin, saberent->s.pos.trBase); - - VectorScale(dir, 700, saberent->s.pos.trDelta ); - saberent->s.pos.trTime = level.time; - - if (saberOwn->client->ps.fd.forcePowerLevel[FP_SABERTHROW] >= FORCE_LEVEL_3) - { //we'll treat them to a quicker update rate if their throw rank is high enough - saberent->speed = level.time + 100; - } - else + //if (tr.fraction != 1) { - saberent->speed = level.time + 400; + VectorSubtract(tr.endpos, saberent->r.currentOrigin, dir); + + VectorNormalize(dir); + + VectorScale(dir, 500, saberent->s.pos.trDelta ); + saberent->s.pos.trTime = level.time; + + if (saberOwn->client->ps.fd.forcePowerLevel[FP_SABERTHROW] >= FORCE_LEVEL_3) + { //we'll treat them to a quicker update rate if their throw rank is high enough + saberent->speed = level.time + 100; + } + else + { + saberent->speed = level.time + 400; + } } } @@ -1946,6 +2054,7 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) int legsAnim; int returnAfterUpdate = 0; float animSpeedScale = 1; + qboolean setTorso = qfalse; if (self && self->inuse && self->client) { @@ -2125,7 +2234,9 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) saberent->s.eType = ET_GENERAL; saberent->s.eFlags = 0; saberent->s.modelindex = G_ModelIndex("models/weapons2/saber/saber_w.glm"); - saberent->s.modelGhoul2 = 999; + saberent->s.modelGhoul2 = 127; + + saberent->parent = self; self->client->ps.saberEntityState = 1; @@ -2255,30 +2366,35 @@ finalUpdate: if (self->client->ps.legsAnimExecute != legsAnim) { - trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "model_root", bgGlobalAnimations[legsAnim].firstFrame, bgGlobalAnimations[legsAnim].firstFrame+bgGlobalAnimations[legsAnim].numFrames, BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND, animSpeedScale, level.time, -1, 150); - self->client->ps.legsAnimExecute = legsAnim; + float animSpeed = 50.0f / bgGlobalAnimations[legsAnim].frameLerp; + int aFlags; + animSpeedScale = (animSpeed *= animSpeedScale); - if ((self->client->ps.torsoAnim&~ANIM_TOGGLEBIT) == legsAnim) + if (bgGlobalAnimations[legsAnim].loopFrames != -1) { - if (!BG_FlippingAnim( self->client->ps.legsAnim ) && - !BG_SpinningSaberAnim( self->client->ps.legsAnim ) && - !BG_InSpecialJump( self->client->ps.legsAnim ) && - !BG_InRoll(&self->client->ps, self->client->ps.legsAnim) && - !BG_SaberInSpecial(self->client->ps.saberMove) && - !BG_SaberInSpecialAttack(self->client->ps.legsAnim) ) - { - trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "Motion", bgGlobalAnimations[legsAnim].firstFrame, bgGlobalAnimations[legsAnim].firstFrame+bgGlobalAnimations[legsAnim].numFrames, BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND, animSpeedScale, level.time, -1, 150); - } + aFlags = BONE_ANIM_OVERRIDE_LOOP; } + else + { + aFlags = BONE_ANIM_OVERRIDE_FREEZE; + } + + aFlags |= BONE_ANIM_BLEND; //since client defaults to blend. Not sure if this will make much difference if any on client position, but it's here just for the sake of matching them. + + trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "model_root", bgGlobalAnimations[legsAnim].firstFrame, bgGlobalAnimations[legsAnim].firstFrame+bgGlobalAnimations[legsAnim].numFrames, aFlags, animSpeedScale, level.time, -1, 150); + self->client->ps.legsAnimExecute = legsAnim; } if (self->client->ps.torsoAnimExecute != torsoAnim) { int initialFrame; + int aFlags = 0; + float animSpeed = 0; f = torsoAnim; initialFrame = bgGlobalAnimations[f].firstFrame; + /* if (bgGlobalAnimations[f].numFrames > 20) { initialFrame += 6; @@ -2287,25 +2403,59 @@ finalUpdate: { //HACK: Force it a couple frames into the animation so it doesn't lag behind the client visual position as much.. initialFrame += 2; } + */ BG_SaberStartTransAnim(self->client->ps.fd.saberAnimLevel, f, &animSpeedScale); - trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "upper_lumbar", initialFrame, bgGlobalAnimations[f].firstFrame+bgGlobalAnimations[f].numFrames, BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND, animSpeedScale, level.time, initialFrame, 150); + animSpeed = 50.0f / bgGlobalAnimations[f].frameLerp; + animSpeedScale = (animSpeed *= animSpeedScale); + + if (bgGlobalAnimations[f].loopFrames != -1) + { + aFlags = BONE_ANIM_OVERRIDE_LOOP; + } + else + { + aFlags = BONE_ANIM_OVERRIDE_FREEZE; + } + + aFlags |= BONE_ANIM_BLEND; //since client defaults to blend. Not sure if this will make much difference if any on client position, but it's here just for the sake of matching them. + + trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "upper_lumbar", initialFrame, bgGlobalAnimations[f].firstFrame+bgGlobalAnimations[f].numFrames, aFlags, animSpeedScale, level.time, initialFrame, 150); self->client->ps.torsoAnimExecute = torsoAnim; + + setTorso = qtrue; + } - if ((self->client->ps.torsoAnim&~ANIM_TOGGLEBIT) == torsoAnim) + if (!BG_FlippingAnim( self->client->ps.legsAnim ) && + !BG_FlippingAnim( self->client->ps.torsoAnim ) && + !BG_SpinningSaberAnim( self->client->ps.legsAnim ) && + !BG_SpinningSaberAnim( self->client->ps.torsoAnim ) && + !BG_InSpecialJump( self->client->ps.legsAnim ) && + !BG_InSpecialJump( self->client->ps.torsoAnim ) && + !BG_InRoll(&self->client->ps, self->client->ps.legsAnim) && + !BG_SaberInSpecial(self->client->ps.saberMove) && + !BG_SaberInSpecialAttack(self->client->ps.legsAnim) && + !BG_SaberInSpecialAttack(self->client->ps.torsoAnim) && + setTorso ) + { + float animSpeed = 50.0f / bgGlobalAnimations[torsoAnim].frameLerp; + int aFlags; + animSpeedScale = (animSpeed *= animSpeedScale); + + if (bgGlobalAnimations[torsoAnim].loopFrames != -1) { - if (!BG_FlippingAnim( self->client->ps.torsoAnim ) && - !BG_SpinningSaberAnim( self->client->ps.torsoAnim ) && - !BG_InSpecialJump( self->client->ps.torsoAnim ) && - !BG_InRoll(&self->client->ps, self->client->ps.legsAnim) && - !BG_SaberInSpecial(self->client->ps.saberMove) && - !BG_SaberInSpecialAttack(self->client->ps.torsoAnim) ) - { - trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "Motion", bgGlobalAnimations[f].firstFrame, bgGlobalAnimations[f].firstFrame+bgGlobalAnimations[f].numFrames, BONE_ANIM_OVERRIDE_FREEZE|BONE_ANIM_BLEND, animSpeedScale, level.time, initialFrame, 150); - } + aFlags = BONE_ANIM_OVERRIDE_LOOP; } + else + { + aFlags = BONE_ANIM_OVERRIDE_FREEZE; + } + + aFlags |= BONE_ANIM_BLEND; //since client defaults to blend. Not sure if this will make much difference if any on client position, but it's here just for the sake of matching them. + + trap_G2API_SetBoneAnim(self->client->ghoul2, 0, "Motion", bgGlobalAnimations[torsoAnim].firstFrame, bgGlobalAnimations[torsoAnim].firstFrame+bgGlobalAnimations[torsoAnim].numFrames, aFlags, animSpeedScale, level.time, -1, 150); } } @@ -2539,11 +2689,34 @@ void WP_SaberBlock( gentity_t *playerent, vec3_t hitloc, qboolean missileBlock ) int WP_SaberCanBlock(gentity_t *self, vec3_t point, int dflags, int mod, qboolean projectile, int attackStr) { + qboolean thrownSaber = qfalse; + float blockFactor = 0; + if (!self || !self->client || !point) { return 0; } + if (attackStr == 8) + { + attackStr = 0; + thrownSaber = qtrue; + } + + if (BG_SaberInAttack(self->client->ps.saberMove)) + { + return 0; + } + + if (PM_InSaberAnim(self->client->ps.torsoAnim) && !self->client->ps.saberBlocked && + self->client->ps.saberMove != LS_READY && self->client->ps.saberMove != LS_NONE) + { + if ( self->client->ps.saberMove < LS_PARRY_UP || self->client->ps.saberMove > LS_REFLECT_LL ) + { + return 0; + } + } + if (self->client->ps.saberHolstered) { return 0; @@ -2569,8 +2742,8 @@ int WP_SaberCanBlock(gentity_t *self, vec3_t point, int dflags, int mod, qboolea return 0; } - if ((self->client->pers.cmd.buttons & BUTTON_ATTACK) && - (projectile || attackStr == FORCE_LEVEL_3)) + if ((self->client->pers.cmd.buttons & BUTTON_ATTACK)/* && + (projectile || attackStr == FORCE_LEVEL_3)*/) { //don't block when the player is trying to slash, if it's a projectile or he's doing a very strong attack return 0; } @@ -2640,30 +2813,30 @@ int WP_SaberCanBlock(gentity_t *self, vec3_t point, int dflags, int mod, qboolea if (self->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] == FORCE_LEVEL_3) { - if (!InFront( point, self->client->ps.origin, self->client->ps.viewangles, 0.05f )) //orig 0.2f - { - return 0; - } + blockFactor = 0.05f; } else if (self->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] == FORCE_LEVEL_2) { - if (!InFront( point, self->client->ps.origin, self->client->ps.viewangles, 0.6f )) - { - return 0; - } + blockFactor = 0.6f; } else if (self->client->ps.fd.forcePowerLevel[FP_SABERDEFEND] == FORCE_LEVEL_1) { - if (!InFront( point, self->client->ps.origin, self->client->ps.viewangles, 0.9f )) - { - return 0; - } + blockFactor = 0.9f; } else { //for now we just don't get to autoblock with no def return 0; } + if (thrownSaber) + { + blockFactor -= 0.25f; + } + + if (!InFront( point, self->client->ps.origin, self->client->ps.viewangles, blockFactor )) //orig 0.2f + { + return 0; + } WP_SaberBlockNonRandom(self, point, projectile); return 1; @@ -2672,15 +2845,25 @@ int WP_SaberCanBlock(gentity_t *self, vec3_t point, int dflags, int mod, qboolea qboolean HasSetSaberOnly(void) { int i = 0; + int wDisable = 0; if (g_gametype.integer == GT_JEDIMASTER) { //set to 0 return qfalse; } + if (g_gametype.integer == GT_TOURNAMENT) + { + wDisable = g_duelWeaponDisable.integer; + } + else + { + wDisable = g_weaponDisable.integer; + } + while (i < WP_NUM_WEAPONS) { - if (!(g_weaponDisable.integer & (1 << i)) && + if (!(wDisable & (1 << i)) && i != WP_SABER && i != WP_NONE) { return qfalse; diff --git a/CODE-mp/game/w_saber.h b/CODE-mp/game/w_saber.h index d0b581b..ec80449 100644 --- a/CODE-mp/game/w_saber.h +++ b/CODE-mp/game/w_saber.h @@ -3,7 +3,7 @@ #define MAX_TRICK_DISTANCE 512 #define FORCE_JUMP_CHARGE_TIME 6400//3000.0f #define GRIP_DRAIN_AMOUNT 30 -#define FORCE_LIGHTNING_RADIUS 512 +#define FORCE_LIGHTNING_RADIUS 300 #define MAX_DRAIN_DISTANCE 512 typedef enum diff --git a/CODE-mp/ghoul2/G2.h b/CODE-mp/ghoul2/G2.h index faffb66..5de0efa 100644 --- a/CODE-mp/ghoul2/G2.h +++ b/CODE-mp/ghoul2/G2.h @@ -1,4 +1,6 @@ +#if defined (_MSC_VER) && (_MSC_VER >= 1020) #pragma once +#endif #if !defined(G2_H_INC) #define G2_H_INC @@ -6,17 +8,13 @@ #define BONE_ANGLES_PREMULT 0x0001 #define BONE_ANGLES_POSTMULT 0x0002 #define BONE_ANGLES_REPLACE 0x0004 -#define BONE_ANGLES_REPLACE_TO_ANIM 0x0400 -#define BONE_ANGLES_TOTAL ( BONE_ANGLES_PREMULT | BONE_ANGLES_POSTMULT | BONE_ANGLES_REPLACE | BONE_ANGLES_REPLACE_TO_ANIM ) +#define BONE_ANGLES_TOTAL ( BONE_ANGLES_PREMULT | BONE_ANGLES_POSTMULT | BONE_ANGLES_REPLACE ) #define BONE_ANIM_OVERRIDE 0x0008 #define BONE_ANIM_OVERRIDE_LOOP 0x0010 -#define BONE_ANIM_OVERRIDE_DEFAULT ( 0x0020 + BONE_ANIM_OVERRIDE ) #define BONE_ANIM_OVERRIDE_FREEZE ( 0x0040 + BONE_ANIM_OVERRIDE ) #define BONE_ANIM_BLEND 0x0080 -#define BONE_ANIM_BLEND_FROM_PARENT 0x0100 -#define BONE_ANIM_BLEND_TO_PARENT 0x0200 -#define BONE_ANIM_TOTAL ( BONE_ANIM_OVERRIDE | BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE_DEFAULT | BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND | BONE_ANIM_BLEND_TO_PARENT | BONE_ANIM_BLEND_FROM_PARENT ) +#define BONE_ANIM_TOTAL ( BONE_ANIM_OVERRIDE | BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND) // defines to setup the diff --git a/CODE-mp/ghoul2/G2_API.cpp b/CODE-mp/ghoul2/G2_API.cpp index b29b46c..f8f8a7d 100644 --- a/CODE-mp/ghoul2/G2_API.cpp +++ b/CODE-mp/ghoul2/G2_API.cpp @@ -15,16 +15,73 @@ #endif #include "G2_local.h" +#include + extern mdxaBone_t worldMatrix; extern mdxaBone_t worldMatrixInv; +set OkLetsFixTheLeaksTheEasyWay[2]; + +bool RicksCrazyOnServer=true; + +void FixGhoul2InfoLeaks(bool clearClient,bool clearServer) +{ + if (clearClient&&OkLetsFixTheLeaksTheEasyWay[0].size()) + { +#if _DEBUG + OutputDebugString(va("Fixing Ghoul2 Client Leaks %d leaked.\n",OkLetsFixTheLeaksTheEasyWay[0].size())); +#endif + set::iterator i; + for (i=OkLetsFixTheLeaksTheEasyWay[0].begin();i!=OkLetsFixTheLeaksTheEasyWay[0].end();i++) + { + delete *i; + } + OkLetsFixTheLeaksTheEasyWay[0].clear(); + } + + if (clearServer&&OkLetsFixTheLeaksTheEasyWay[1].size()) + { +#if _DEBUG + OutputDebugString(va("Fixing Ghoul2 Server Leaks %d leaked.\n",OkLetsFixTheLeaksTheEasyWay[1].size())); +#endif + set::iterator i; + for (i=OkLetsFixTheLeaksTheEasyWay[1].begin();i!=OkLetsFixTheLeaksTheEasyWay[1].end();i++) + { + delete *i; + } + OkLetsFixTheLeaksTheEasyWay[1].clear(); + } +} + + +class EasyCleaner +{ +public: + ~EasyCleaner() + { + FixGhoul2InfoLeaks(true,true); + } +}; + +static EasyCleaner TheEasyCleaner; + + // this is the ONLY function to read entity states directly void G2API_CleanGhoul2Models(CGhoul2Info_v **ghoul2Ptr) { if (*ghoul2Ptr) { - delete *ghoul2Ptr; + if (OkLetsFixTheLeaksTheEasyWay[0].find(*ghoul2Ptr)!=OkLetsFixTheLeaksTheEasyWay[0].end()) + { + OkLetsFixTheLeaksTheEasyWay[0].erase(*ghoul2Ptr); + delete *ghoul2Ptr; + } + else if (OkLetsFixTheLeaksTheEasyWay[1].find(*ghoul2Ptr)!=OkLetsFixTheLeaksTheEasyWay[1].end()) + { + OkLetsFixTheLeaksTheEasyWay[1].erase(*ghoul2Ptr); + delete *ghoul2Ptr; + } *ghoul2Ptr = NULL; } } @@ -54,6 +111,14 @@ int G2API_InitGhoul2Model(CGhoul2Info_v **ghoul2Ptr, const char *fileName, int m if (!(*ghoul2Ptr)) { *ghoul2Ptr = new CGhoul2Info_v; + if (RicksCrazyOnServer) + { + OkLetsFixTheLeaksTheEasyWay[1].insert(*ghoul2Ptr); + } + else + { + OkLetsFixTheLeaksTheEasyWay[0].insert(*ghoul2Ptr); + } } CGhoul2Info_v &ghoul2 = *(*ghoul2Ptr); @@ -107,6 +172,7 @@ int G2API_InitGhoul2Model(CGhoul2Info_v **ghoul2Ptr, const char *fileName, int m { if (ghoul2.size() == 0)//very first model created {//you can't have an empty vector, so let's not give it one + G2API_CleanGhoul2Models(ghoul2Ptr); delete *ghoul2Ptr; *ghoul2Ptr = 0; } @@ -305,8 +371,41 @@ qboolean G2API_RemoveGhoul2Model(CGhoul2Info_v **ghlRemove, const int modelIndex return qtrue; } -qboolean G2API_SetBoneAnimIndex(CGhoul2Info *ghlInfo, const int index, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime) +qboolean G2API_SetBoneAnimIndex(CGhoul2Info *ghlInfo, const int index, const int AstartFrame, const int AendFrame, const int flags, const float animSpeed, const int currentTime, const float AsetFrame, const int blendTime) { + int endFrame=AendFrame; + int startFrame=AstartFrame; + float setFrame=AsetFrame; + assert(endFrame>0); + assert(startFrame>=0); + assert(endFrame<100000); + assert(startFrame<100000); + assert(setFrame>=0.0f||setFrame==-1.0f); + assert(setFrame<=100000.0f); + if (endFrame<=0) + { + endFrame=1; + } + if (endFrame>=100000) + { + endFrame=1; + } + if (startFrame<0) + { + startFrame=0; + } + if (startFrame>=100000) + { + startFrame=0; + } + if (setFrame<0.0f&&setFrame!=-1.0f) + { + setFrame=0.0f; + } + if (setFrame>100000.0f) + { + setFrame=0.0f; + } if (ghlInfo) { // ensure we flush the cache @@ -316,8 +415,41 @@ qboolean G2API_SetBoneAnimIndex(CGhoul2Info *ghlInfo, const int index, const int return qfalse; } -qboolean G2API_SetBoneAnim(CGhoul2Info_v &ghoul2, const int modelIndex, const char *boneName, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime) +qboolean G2API_SetBoneAnim(CGhoul2Info_v &ghoul2, const int modelIndex, const char *boneName, const int AstartFrame, const int AendFrame, const int flags, const float animSpeed, const int currentTime, const float AsetFrame, const int blendTime) { + int endFrame=AendFrame; + int startFrame=AstartFrame; + float setFrame=AsetFrame; + assert(endFrame>0); + assert(startFrame>=0); + assert(endFrame<100000); + assert(startFrame<100000); + assert(setFrame>=0.0f||setFrame==-1.0f); + assert(setFrame<=100000.0f); + if (endFrame<=0) + { + endFrame=1; + } + if (endFrame>=100000) + { + endFrame=1; + } + if (startFrame<0) + { + startFrame=0; + } + if (startFrame>=100000) + { + startFrame=0; + } + if (setFrame<0.0f&&setFrame!=-1.0f) + { + setFrame=0.0f; + } + if (setFrame>100000.0f) + { + setFrame=0.0f; + } if ((int)&ghoul2 && ghoul2.size()>modelIndex) { CGhoul2Info *ghlInfo = &ghoul2[modelIndex]; @@ -334,19 +466,76 @@ qboolean G2API_SetBoneAnim(CGhoul2Info_v &ghoul2, const int modelIndex, const ch qboolean G2API_GetBoneAnim(CGhoul2Info *ghlInfo, const char *boneName, const int currentTime, float *currentFrame, int *startFrame, int *endFrame, int *flags, float *animSpeed, int *modelList) { + assert(startFrame!=endFrame); //this is bad + assert(startFrame!=flags); //this is bad + assert(endFrame!=flags); //this is bad + assert(currentFrame!=animSpeed); //this is bad if (ghlInfo) { - return G2_Get_Bone_Anim(ghlInfo->mFileName, ghlInfo->mBlist, boneName, currentTime, currentFrame, + qboolean ret=G2_Get_Bone_Anim(ghlInfo->mFileName, ghlInfo->mBlist, boneName, currentTime, currentFrame, startFrame, endFrame, flags, animSpeed, modelList, ghlInfo->mModelindex); + assert(*endFrame>0); + assert(*endFrame<100000); + assert(*startFrame>=0); + assert(*startFrame<100000); + assert(*currentFrame>=0.0f); + assert(*currentFrame<100000.0f); + if (*endFrame<1) + { + *endFrame=1; + } + if (*endFrame>100000) + { + *endFrame=1; + } + if (*startFrame<0) + { + *startFrame=0; + } + if (*startFrame>100000) + { + *startFrame=1; + } + if (*currentFrame<0.0f) + { + *currentFrame=0.0f; + } + if (*currentFrame>100000) + { + *currentFrame=1; + } + return ret; } return qfalse; } qboolean G2API_GetAnimRange(CGhoul2Info *ghlInfo, const char *boneName, int *startFrame, int *endFrame) { + assert(startFrame!=endFrame); //this is bad if (ghlInfo) { - return G2_Get_Bone_Anim_Range(ghlInfo->mFileName, ghlInfo->mBlist, boneName, startFrame, endFrame); + qboolean ret=G2_Get_Bone_Anim_Range(ghlInfo->mFileName, ghlInfo->mBlist, boneName, startFrame, endFrame); + assert(*endFrame>0); + assert(*endFrame<100000); + assert(*startFrame>=0); + assert(*startFrame<100000); + if (*endFrame<1) + { + *endFrame=1; + } + if (*endFrame>100000) + { + *endFrame=1; + } + if (*startFrame<0) + { + *startFrame=0; + } + if (*startFrame>100000) + { + *startFrame=1; + } + return ret; } return qfalse; } @@ -697,7 +886,7 @@ qboolean G2API_HaveWeGhoul2Models(CGhoul2Info_v &ghoul2) void G2API_SetGhoul2ModelIndexes(CGhoul2Info_v &ghoul2, qhandle_t *modelList, qhandle_t *skinList) { return; - +#if 0 int i; if ((int)&ghoul2) { @@ -715,6 +904,7 @@ void G2API_SetGhoul2ModelIndexes(CGhoul2Info_v &ghoul2, qhandle_t *modelList, qh } } } +#endif } @@ -961,6 +1151,14 @@ void G2API_DuplicateGhoul2Instance(CGhoul2Info_v &g2From, CGhoul2Info_v **g2To) } *g2To = new CGhoul2Info_v; + if (RicksCrazyOnServer) + { + OkLetsFixTheLeaksTheEasyWay[1].insert(*g2To); + } + else + { + OkLetsFixTheLeaksTheEasyWay[0].insert(*g2To); + } CGhoul2Info_v &ghoul2 = *(*g2To); ignore = G2API_CopyGhoul2Instance(g2From, ghoul2, -1); diff --git a/CODE-mp/ghoul2/G2_bones.cpp b/CODE-mp/ghoul2/G2_bones.cpp index b5d4b71..4ac19ed 100644 --- a/CODE-mp/ghoul2/G2_bones.cpp +++ b/CODE-mp/ghoul2/G2_bones.cpp @@ -394,6 +394,9 @@ qboolean G2_Remove_Bone (const char *fileName, boneInfo_v &blist, const char *bo return G2_Remove_Bone_Index(blist, index); } +#define DEBUG_PCJ (0) + + // Given a model handle, and a bone name, we want to set angles specifically for overriding qboolean G2_Set_Bone_Angles_Index( boneInfo_v &blist, const int index, const float *angles, const int flags, const Eorientations yaw, @@ -419,6 +422,9 @@ qboolean G2_Set_Bone_Angles_Index( boneInfo_v &blist, const int index, blist[index].flags |= flags; blist[index].boneBlendStart = currentTime; blist[index].boneBlendTime = blendTime; +#if DEBUG_PCJ + OutputDebugString(va("PCJ %2d %6d (%6.2f,%6.2f,%6.2f) %d %d %d %d\n",index,currentTime,angles[0],angles[1],angles[2],yaw,pitch,roll,flags)); +#endif G2_Generate_Matrix(NULL, blist, index, angles, flags, yaw, pitch, roll); return qtrue; @@ -452,6 +458,9 @@ qboolean G2_Set_Bone_Angles(const char *fileName, boneInfo_v &blist, const char blist[index].flags |= flags; blist[index].boneBlendStart = currentTime; blist[index].boneBlendTime = blendTime; +#if DEBUG_PCJ + OutputDebugString(va("%2d %6d (%6.2f,%6.2f,%6.2f) %d %d %d %d\n",index,currentTime,angles[0],angles[1],angles[2],up,left,forward,flags)); +#endif G2_Generate_Matrix(mod_a, blist, index, angles, flags, up, left, forward); return qtrue; @@ -468,6 +477,9 @@ qboolean G2_Set_Bone_Angles(const char *fileName, boneInfo_v &blist, const char blist[index].flags |= flags; blist[index].boneBlendStart = currentTime; blist[index].boneBlendTime = blendTime; +#if DEBUG_PCJ + OutputDebugString(va("%2d %6d (%6.2f,%6.2f,%6.2f) %d %d %d %d\n",index,currentTime,angles[0],angles[1],angles[2],up,left,forward,flags)); +#endif G2_Generate_Matrix(mod_a, blist, index, angles, flags, up, left, forward); return qtrue; @@ -550,16 +562,22 @@ qboolean G2_Set_Bone_Angles_Matrix(const char *fileName, boneInfo_v &blist, cons return qfalse; } +#define DEBUG_G2_TIMING (0) + // given a model, bone name, a bonelist, a start/end frame number, a anim speed and some anim flags, set up or modify an existing bone entry for a new set of anims -qboolean G2_Set_Bone_Anim_Index(boneInfo_v &blist, const int index, const int startFrame, - const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime) +qboolean G2_Set_Bone_Anim_Index( + boneInfo_v &blist, + const int index, + const int startFrame, + const int endFrame, + const int flags, + const float animSpeed, + const int currentTime, + const float setFrame, + const int blendTime) { int modFlags = flags; - // sanity check some stuff - //assert(startFrame < 1000);//do we really need this??? - //assert((animSpeed > 0.01) && (animSpeed < 20.0)); - if ((index >= blist.size()) || (blist[index].boneNumber == -1)) { // we are attempting to set a bone override that doesn't exist @@ -567,262 +585,182 @@ qboolean G2_Set_Bone_Anim_Index(boneInfo_v &blist, const int index, const int st return qfalse; } - // sanity check to see if setfram is within animation bounds if (setFrame != -1) { assert((setFrame >= startFrame) && (setFrame <= endFrame)); } - - - // since we already existed, we can check to see if we want to start some blending - if (flags & (BONE_ANIM_BLEND|BONE_ANIM_BLEND_TO_PARENT)) + if (flags & BONE_ANIM_BLEND) + { + float currentFrame, animSpeed; + int startFrame, endFrame, flags; + // figure out where we are now + if (G2_Get_Bone_Anim_Index(blist, index, currentTime, ¤tFrame, &startFrame, &endFrame, &flags, &animSpeed, NULL, 0)) { - float currentFrame, animSpeed; - int startFrame, endFrame, flags; - // figure out where we are now - if (G2_Get_Bone_Anim_Index(blist, index, currentTime, ¤tFrame, &startFrame, &endFrame, &flags, &animSpeed, NULL, 0)) + if (blist[index].blendStart == currentTime) //we're replacing a blend in progress which hasn't started { - blist[index].blendFrame = currentFrame; - blist[index].blendLerpFrame = currentFrame+1; - // cope with if the lerp frame is actually off the end of the anim - if (blist[index].blendFrame >= blist[index].endFrame ) - { - // we only want to lerp with the first frame of the anim if we are looping - if (blist[index].flags & BONE_ANIM_OVERRIDE_LOOP) - { - blist[index].blendFrame = blist[index].startFrame; - } - // if we intend to end this anim or freeze after this, then just keep on the last frame - else - { - blist[index].blendFrame = blist[index].endFrame -1; - } - } - // cope with if the lerp frame is actually off the end of the anim - if (blist[index].blendLerpFrame >= blist[index].endFrame ) - { - // we only want to lerp with the first frame of the anim if we are looping - if (blist[index].flags & BONE_ANIM_OVERRIDE_LOOP) - { - blist[index].blendLerpFrame = blist[index].startFrame; - } - // if we intend to end this anim or freeze after this, then just keep on the last frame - else - { - blist[index].blendLerpFrame = blist[index].endFrame - 1; - } - } - + // set the amount of time it's going to take to blend this anim with the last frame of the last one + blist[index].blendTime = blendTime; + } + else + { + if (animSpeed<0.0f) + { + blist[index].blendFrame = floor(currentFrame); + blist[index].blendLerpFrame = floor(currentFrame); + } + else + { + blist[index].blendFrame = currentFrame; + blist[index].blendLerpFrame = currentFrame+1; + + // cope with if the lerp frame is actually off the end of the anim + if (blist[index].blendFrame >= endFrame ) + { + // we only want to lerp with the first frame of the anim if we are looping + if (blist[index].flags & BONE_ANIM_OVERRIDE_LOOP) + { + blist[index].blendFrame = startFrame; + } + // if we intend to end this anim or freeze after this, then just keep on the last frame + else + { + // assert(endFrame>0); + if (endFrame <= 0) + { + blist[index].blendLerpFrame = 0; + } + else + { + blist[index].blendFrame = endFrame -1; + } + } + } + + // cope with if the lerp frame is actually off the end of the anim + if (blist[index].blendLerpFrame >= endFrame ) + { + // we only want to lerp with the first frame of the anim if we are looping + if (blist[index].flags & BONE_ANIM_OVERRIDE_LOOP) + { + blist[index].blendLerpFrame = startFrame; + } + // if we intend to end this anim or freeze after this, then just keep on the last frame + else + { + // assert(endFrame>0); + if (endFrame <= 0) + { + blist[index].blendLerpFrame = 0; + } + else + { + blist[index].blendLerpFrame = endFrame - 1; + } + } + } + } // set the amount of time it's going to take to blend this anim with the last frame of the last one blist[index].blendTime = blendTime; blist[index].blendStart = currentTime; - } - // hmm, we weren't animating on this bone. In which case disable the blend - else - { - blist[index].blendFrame = blist[index].blendLerpFrame = 0; - blist[index].blendTime = 0; - // we aren't blending, so remove the option to do so - modFlags &= ~(BONE_ANIM_BLEND|BONE_ANIM_BLEND_TO_PARENT); + } } - else - // if we are doing it from parent, then we only care about blendtime and blend start, since the rest gets constructed in the renderer - if (flags & BONE_ANIM_BLEND_FROM_PARENT) - { - // if we hit this, someone put a BLEND_FROM_PARENT on a root bone - that's a no no - assert(blist[index].boneNumber); - // set the amount of time it's going to take to blend this anim with the last frame of the last one - blist[index].blendTime = blendTime; - blist[index].blendStart = currentTime; - } - else - { - blist[index].blendFrame = blist[index].blendLerpFrame = 0; - blist[index].blendTime = blist[index].blendStart = 0; - // we aren't blending, so remove the option to do so - modFlags &= ~(BONE_ANIM_BLEND|BONE_ANIM_BLEND_TO_PARENT); - } - - // yes, so set the anim data and flags correctly - blist[index].endFrame = endFrame; - blist[index].startFrame = startFrame; - blist[index].animSpeed = animSpeed; - blist[index].pauseTime = 0; - // start up the animation:) - if (setFrame != -1) - { - blist[index].lastTime = blist[index].startTime = (currentTime - (((setFrame - (float)startFrame) * 50.0)/ animSpeed)); - } - else - { - blist[index].lastTime = blist[index].startTime = currentTime; - } - blist[index].flags &= ~(BONE_ANIM_TOTAL); - blist[index].flags |= modFlags; - -// assert(blist[index].startTime <= currentTime); - return qtrue; - -} - -// given a model, bone name, a bonelist, a start/end frame number, a anim speed and some anim flags, set up or modify an existing bone entry for a new set of anims -qboolean G2_Set_Bone_Anim(const char *fileName, boneInfo_v &blist, const char *boneName, const int startFrame, - const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime) -{ - model_t *mod_m = R_GetModelByHandle(RE_RegisterModel(fileName)); - model_t *mod_a = R_GetModelByHandle(mod_m->mdxm->animIndex); - int index = G2_Find_Bone(mod_a, blist, boneName); - int modFlags = flags; - - // sanity check some stuff - //assert(startFrame < 1000);//do we really need this??? - //assert((animSpeed > 0.01) && (animSpeed < 20.0)); - - // sanity check to see if setfram is within animation bounds - if (setFrame != -1) - { - assert((setFrame >= startFrame) && (setFrame <= endFrame)); - } - - // did we find it? - if (index != -1) - { - // since we already existed, we can check to see if we want to start some blending - if (flags & (BONE_ANIM_BLEND|BONE_ANIM_BLEND_TO_PARENT)) - { - float currentFrame, animSpeed; - int startFrame, endFrame, flags; - // figure out where we are now - if (G2_Get_Bone_Anim(fileName, blist, boneName, currentTime, ¤tFrame, &startFrame, &endFrame, &flags, &animSpeed, NULL, 0)) - { - blist[index].blendFrame = currentFrame; - blist[index].blendLerpFrame = currentFrame+1; - // cope with if the lerp frame is actually off the end of the anim - if (blist[index].blendFrame >= blist[index].endFrame ) - { - // we only want to lerp with the first frame of the anim if we are looping - if (blist[index].flags & BONE_ANIM_OVERRIDE_LOOP) - { - blist[index].blendFrame = blist[index].startFrame; - } - // if we intend to end this anim or freeze after this, then just keep on the last frame - else - { - blist[index].blendFrame = blist[index].endFrame -1; - } - } - // cope with if the lerp frame is actually off the end of the anim - if (blist[index].blendLerpFrame >= blist[index].endFrame ) - { - // we only want to lerp with the first frame of the anim if we are looping - if (blist[index].flags & BONE_ANIM_OVERRIDE_LOOP) - { - blist[index].blendLerpFrame = blist[index].startFrame; - } - // if we intend to end this anim or freeze after this, then just keep on the last frame - else - { - blist[index].blendLerpFrame = blist[index].endFrame -1; - } - } - - // set the amount of time it's going to take to blend this anim with the last frame of the last one - blist[index].blendTime = blendTime; - blist[index].blendStart = currentTime; - } - // hmm, we weren't animating on this bone. In which case disable the blend - else - { - blist[index].blendFrame = blist[index].blendLerpFrame = 0; - blist[index].blendTime = 0; - // we aren't blending, so remove the option to do so - modFlags &= ~(BONE_ANIM_BLEND|BONE_ANIM_BLEND_TO_PARENT); - } - } - else - // if we are doing it from parent, then we only care about blendtime and blend start, since the rest gets constructed in the renderer - if (flags & BONE_ANIM_BLEND_FROM_PARENT) - { - // if we hit this, someone put a BLEND_FROM_PARENT on a root bone - that's a no no - assert(blist[index].boneNumber); - // set the amount of time it's going to take to blend this anim with the last frame of the last one - blist[index].blendTime = blendTime; - blist[index].blendStart = currentTime; - } - else - { - blist[index].blendFrame = blist[index].blendLerpFrame = 0; - blist[index].blendTime = blist[index].blendStart = 0; - // we aren't blending, so remove the option to do so - modFlags &= ~(BONE_ANIM_BLEND|BONE_ANIM_BLEND_TO_PARENT); - } - - // yes, so set the anim data and flags correctly - blist[index].endFrame = endFrame; - blist[index].startFrame = startFrame; - blist[index].animSpeed = animSpeed; - blist[index].pauseTime = 0; - // start up the animation:) - if (setFrame != -1) - { - blist[index].lastTime = blist[index].startTime = (currentTime - (((setFrame - (float)startFrame) * 50.0)/ animSpeed)); - } - else - { - blist[index].lastTime = blist[index].startTime = currentTime; - } - blist[index].flags &= ~(BONE_ANIM_TOTAL); - blist[index].flags |= modFlags; - -// assert(blist[index].startTime <= currentTime); - return qtrue; - } - - // no - lets try and add this bone in - index = G2_Add_Bone(mod_a, blist, boneName); - - // did we find a free one? - if (index != -1) - { - // if we are doing it from parent, then we only care about blendtime and blend start, since the rest gets constructed in the renderer - if (flags & BONE_ANIM_BLEND_FROM_PARENT) - { - // if we hit this, someone put a BLEND_FROM_PARENT on a root bone - that's a no no - assert(blist[index].boneNumber); - // set the amount of time it's going to take to blend this anim with the last frame of the last one - blist[index].blendTime = blendTime; - blist[index].blendStart = currentTime; - } + // hmm, we weren't animating on this bone. In which case disable the blend else { blist[index].blendFrame = blist[index].blendLerpFrame = 0; blist[index].blendTime = 0; - // we aren't blending, so remove the option to do so - modFlags &= ~(BONE_ANIM_BLEND|BONE_ANIM_BLEND_TO_PARENT); + modFlags &= ~(BONE_ANIM_BLEND); } - // yes, so set the anim data and flags correctly - blist[index].endFrame = endFrame; - blist[index].startFrame = startFrame; - blist[index].animSpeed = animSpeed; - blist[index].pauseTime = 0; - // start up the animation:) - if (setFrame != -1) + } + else + { + blist[index].blendFrame = blist[index].blendLerpFrame = 0; + blist[index].blendTime = blist[index].blendStart = 0; + // we aren't blending, so remove the option to do so + modFlags &= ~BONE_ANIM_BLEND; + } + // yes, so set the anim data and flags correctly + blist[index].endFrame = endFrame; + blist[index].startFrame = startFrame; + blist[index].animSpeed = animSpeed; + blist[index].pauseTime = 0; + // start up the animation:) + if (setFrame != -1) + { + blist[index].lastTime = blist[index].startTime = (currentTime - (((setFrame - (float)startFrame) * 50.0)/ animSpeed)); + } + else + { + blist[index].lastTime = blist[index].startTime = currentTime; + } + blist[index].flags &= ~(BONE_ANIM_TOTAL); + blist[index].flags |= modFlags; + +#if DEBUG_G2_TIMING + if (index==2) + { + const boneInfo_t &bone=blist[index]; + char mess[1000]; + if (bone.flags&BONE_ANIM_BLEND) { - blist[index].lastTime = blist[index].startTime = (currentTime - (((setFrame - (float)startFrame) * 50.0)/ animSpeed)); + sprintf(mess,"sab[%2d] %5d %5d (%5d-%5d) %4.2f %4x bt(%5d-%5d) %7.2f %5d\n", + index, + currentTime, + bone.startTime, + bone.startFrame, + bone.endFrame, + bone.animSpeed, + bone.flags, + bone.blendStart, + bone.blendStart+bone.blendTime, + bone.blendFrame, + bone.blendLerpFrame + ); } else { - blist[index].lastTime = blist[index].startTime = currentTime; + sprintf(mess,"saa[%2d] %5d %5d (%5d-%5d) %4.2f %4x\n", + index, + currentTime, + bone.startTime, + bone.startFrame, + bone.endFrame, + bone.animSpeed, + bone.flags + ); } - blist[index].flags &= ~(BONE_ANIM_TOTAL); - blist[index].flags |= modFlags; -// assert(blist[index].startTime <= currentTime); - return qtrue; + OutputDebugString(mess); } +#endif - assert(0); - // no + return qtrue; + +} + +// given a model, bone name, a bonelist, a start/end frame number, a anim speed and some anim flags, set up or modify an existing bone entry for a new set of anims +qboolean G2_Set_Bone_Anim(const char *fileName, + boneInfo_v &blist, + const char *boneName, + const int startFrame, + const int endFrame, + const int flags, + const float animSpeed, + const int currentTime, + const float setFrame, + const int blendTime) +{ + model_t *mod_m = R_GetModelByHandle(RE_RegisterModel(fileName)); + model_t *mod_a = R_GetModelByHandle(mod_m->mdxm->animIndex); + int index = G2_Find_Bone(mod_a, blist, boneName); + if (index == -1) + { + index = G2_Add_Bone(mod_a, blist, boneName); + } + if (index != -1) + { + return G2_Set_Bone_Anim_Index(blist,index,startFrame,endFrame,flags,animSpeed,currentTime,setFrame,blendTime); + } return qfalse; } @@ -868,6 +806,10 @@ qboolean G2_Get_Bone_Anim_Index( boneInfo_v &blist, const int index, const int c { time = (blist[index].pauseTime - blist[index].startTime) / 50.0f; } + if (time<0) + { + time=0; + } float newFrame_g = blist[index].startFrame + (time * animSpeed); *currentFrame = newFrame_g; @@ -877,26 +819,25 @@ qboolean G2_Get_Bone_Anim_Index( boneInfo_v &blist, const int index, const int c if (animSize) { // did we run off the end? - if (((animSpeed > 0.0f) && (newFrame_g > mendFrame)) || - ((animSpeed < 0.0f) && (newFrame_g < mendFrame))) + if (((animSpeed > 0.0f) && (newFrame_g > mendFrame-1)) || + ((animSpeed < 0.0f) && (newFrame_g < mendFrame+1))) { // yep - decide what to do if (blist[index].flags & BONE_ANIM_OVERRIDE_LOOP) { - // get our new animation frame back within the bounds of the animation set if (animSpeed < 0.0f) { - while (newFrame_g <= mendFrame) + if (newFrame_g <= mendFrame+1) { - newFrame_g -= animSize; + newFrame_g=mendFrame+fmod(newFrame_g-mendFrame,animSize)-animSize; } } else { - while (newFrame_g >= mendFrame) + if (newFrame_g >= mendFrame) { - newFrame_g -= animSize; + newFrame_g=mendFrame+fmod(newFrame_g-mendFrame,animSize)-animSize; } } @@ -918,7 +859,7 @@ qboolean G2_Get_Bone_Anim_Index( boneInfo_v &blist, const int index, const int c } else { - *currentFrame = -1; + *currentFrame = 0; } } } @@ -935,7 +876,11 @@ qboolean G2_Get_Bone_Anim_Index( boneInfo_v &blist, const int index, const int c return qtrue; } } - *startFrame = *endFrame = *currentFrame = *flags = -1; + *startFrame =0; + *endFrame =1; + *currentFrame =0; + *flags = 0; + *retAnimSpeed = 1.0f; return qfalse; } @@ -974,6 +919,10 @@ qboolean G2_Get_Bone_Anim(const char *fileName, boneInfo_v &blist, const char *b { time = (blist[index].pauseTime - blist[index].startTime) / 50.0f; } + if (time<0) + { + time=0; + } float newFrame_g = blist[index].startFrame + (time * animSpeed); *currentFrame = newFrame_g; @@ -983,8 +932,8 @@ qboolean G2_Get_Bone_Anim(const char *fileName, boneInfo_v &blist, const char *b if (animSize) { // did we run off the end? - if (((animSpeed > 0.0f) && (newFrame_g > mendFrame)) || - ((animSpeed < 0.0f) && (newFrame_g < mendFrame))) + if (((animSpeed > 0.0f) && (newFrame_g > mendFrame-1)) || + ((animSpeed < 0.0f) && (newFrame_g < mendFrame+1))) { // yep - decide what to do if (blist[index].flags & BONE_ANIM_OVERRIDE_LOOP) @@ -993,16 +942,16 @@ qboolean G2_Get_Bone_Anim(const char *fileName, boneInfo_v &blist, const char *b // get our new animation frame back within the bounds of the animation set if (animSpeed < 0.0f) { - while (newFrame_g <= mendFrame) + if (newFrame_g <= mendFrame+1) { - newFrame_g -= animSize; + newFrame_g=mendFrame+fmod(newFrame_g-mendFrame,animSize)-animSize; } } else { - while (newFrame_g >= mendFrame) + if (newFrame_g >= mendFrame) { - newFrame_g -= animSize; + newFrame_g=mendFrame+fmod(newFrame_g-mendFrame,animSize)-animSize; } } @@ -1024,7 +973,7 @@ qboolean G2_Get_Bone_Anim(const char *fileName, boneInfo_v &blist, const char *b } else { - *currentFrame = -1; + *currentFrame = 0; } } } @@ -1041,7 +990,11 @@ qboolean G2_Get_Bone_Anim(const char *fileName, boneInfo_v &blist, const char *b return qtrue; } } - *startFrame = *endFrame = *currentFrame = *flags = -1; + *startFrame =0; + *endFrame =1 ; + *currentFrame = 0; + *flags = 0; //hmmmm this used to be -1 + *retAnimSpeed = 1.0f; return qfalse; } @@ -1180,92 +1133,6 @@ void G2_Animate_Bone_List(CGhoul2Info_v &ghoul2, const int currentTime, const in int i; boneInfo_v &blist = ghoul2[index].mBlist; - -#if 0 - // look through entire list - for(i=0; imMap.lower_bound(adjustedLastTime); - CWInstBoneMap::TBoneMapIter itStop = blist[i].boneMap->mMap.upper_bound(adjustedCurrentTime); - vector callbacksToFire; - - boneInfo_t *bone = &blist[i]; - - // walk through the map list of call backs we should hit this frame - while (itCur != itStop) - { - - int calltime = (*itCur).first; - - // push it into the list ready to fire off later. - callbacksToFire.push_back((*itCur).second); - - // did we hit an exact match? - if ((*itCur).first == adjustedCurrentTime) - { - // adjust the next time by the anim speed, so if we are running fast we won't lose this jumping of one millisecond - int adjuster = 1; - if (blist[i].animSpeed > 1) - { - adjuster = blist[i].animSpeed + 1; - } - callbackCurrentTime += adjuster; - } - // select next call back to check against - itCur++; - - // have we run off the end of the map? - if (itCur == blist[i].boneMap->mMap.end()) - { - // does the map loop back to the beginning? - if (itCur != itStop) - { - itCur = blist[i].boneMap->mMap.begin(); - } - } - } - - // fire off all the call backs we have selected for this bone. - for (int cllbks = 0; cllbks < callbacksToFire.size(); cllbks++) - { - TheGhoul2Wraith()->FireCallback(ghoul2, index, callbacksToFire[cllbks], callbackCurrentTime); - } - callbacksToFire.clear(); - - // assuming the bone is still here, set the last time to current time - if (blist[i].boneNumber != -1) - { - blist[i].lastTime = callbackCurrentTime; - } - } - } - } - } -#endif - // look through entire list for(i=0; i 0.0f) && (newFrame_g > endFrame )) || - ((animSpeed < 0.0f) && (newFrame_g < endFrame ))) + if (((animSpeed > 0.0f) && (newFrame_g > endFrame-1 )) || + ((animSpeed < 0.0f) && (newFrame_g < endFrame+1 ))) { // yep - decide what to do if (blist[i].flags & BONE_ANIM_OVERRIDE_LOOP) @@ -1300,40 +1171,32 @@ void G2_Animate_Bone_List(CGhoul2Info_v &ghoul2, const int currentTime, const in // get our new animation frame back within the bounds of the animation set if (animSpeed < 0.0f) { - while (newFrame_g <= endFrame) + if (newFrame_g <= endFrame+1) { - newFrame_g -= animSize; + newFrame_g=endFrame+fmod(newFrame_g-endFrame,animSize)-animSize; } } else { - while (newFrame_g >= endFrame) + if (newFrame_g >= endFrame) { - newFrame_g -= animSize; + newFrame_g=endFrame+fmod(newFrame_g-endFrame,animSize)-animSize; } } // figure out new start time float frameTime = newFrame_g - blist[i].startFrame ; blist[i].startTime = currentTime - (int)((frameTime / animSpeed) * 50.0f); + if (blist[i].startTime>currentTime) + { + blist[i].startTime=currentTime; + } assert(blist[i].startTime <= currentTime); blist[i].lastTime = blist[i].startTime; } else { - if ((blist[i].flags & (BONE_ANIM_OVERRIDE_FREEZE)) != (BONE_ANIM_OVERRIDE_FREEZE)) + if ((blist[i].flags & BONE_ANIM_OVERRIDE_FREEZE) != BONE_ANIM_OVERRIDE_FREEZE) { - // if we are supposed to reset the default anim, then do so - if (blist[i].flags & (BONE_ANIM_OVERRIDE_DEFAULT)) - { - if (animSpeed > 0.0f) - { - ghoul2[index].mAnimFrameDefault = blist[i].endFrame -1; - } - else - { - ghoul2[index].mAnimFrameDefault = blist[i].endFrame + 1; - } - } // nope, just stop it. And remove the bone if possible G2_Stop_Bone_Index(blist, i, (BONE_ANIM_TOTAL)); } @@ -1341,26 +1204,6 @@ void G2_Animate_Bone_List(CGhoul2Info_v &ghoul2, const int currentTime, const in } } } - // else lets see if we are blending to a parent - if so we should stop the anim once the blend is done - else if (blist[i].flags & BONE_ANIM_BLEND_TO_PARENT) - { - // are we done yet? - if ((blist[i].blendTime + blist[i].blendStart) < currentTime) - { - G2_Stop_Bone_Index(blist, i, (BONE_ANIM_TOTAL)); - } - } - - // also, lets check to see if this bone might have been doing a bone override that we need to dispose of? - // we might have deleted this bone? - if ((blist.size() > i) && (blist[i].flags & BONE_ANGLES_REPLACE_TO_ANIM)) - { - // are we done yet? - if ((blist[i].boneBlendTime + blist[i].boneBlendStart) < currentTime) - { - G2_Stop_Bone_Index(blist, i, (BONE_ANGLES_TOTAL)); - } - } } } } diff --git a/CODE-mp/ghoul2/G2_gore.h b/CODE-mp/ghoul2/G2_gore.h index 0468267..b6e1dee 100644 --- a/CODE-mp/ghoul2/G2_gore.h +++ b/CODE-mp/ghoul2/G2_gore.h @@ -1,5 +1,7 @@ #ifdef _SOF2 +#if defined (_MSC_VER) && (_MSC_VER >= 1020) #pragma once +#endif #if !defined(G2_GORE_H_INC) #define G2_GORE_H_INC diff --git a/CODE-mp/ghoul2/G2_local.h b/CODE-mp/ghoul2/G2_local.h index 5342d71..dfd7014 100644 --- a/CODE-mp/ghoul2/G2_local.h +++ b/CODE-mp/ghoul2/G2_local.h @@ -165,4 +165,5 @@ void G2_ConstructGhoulSkeleton( CGhoul2Info_v &ghoul2, const int frameNum, qhan #ifdef _SOF2 void G2API_AddSkinGore(CGhoul2Info_v &ghoul2,SSkinGoreData &gore); -#endif // _SOF2 \ No newline at end of file +#endif // _SOF2 + diff --git a/CODE-mp/ghoul2/G2_misc.cpp b/CODE-mp/ghoul2/G2_misc.cpp index 01b8ca1..2cff8f8 100644 --- a/CODE-mp/ghoul2/G2_misc.cpp +++ b/CODE-mp/ghoul2/G2_misc.cpp @@ -343,21 +343,21 @@ void R_TransformEachSurface( mdxmSurface_t *surface, vec3_t scale, CMiniHeap *G2 // w = v->weights; const int iNumWeights = G2_GetVertWeights( v ); - + float fTotalWeight = 0.0f; for ( k = 0 ; k < iNumWeights ; k++ ) { int iBoneIndex = G2_GetVertBoneIndex( v, k ); - float fBoneWeight = G2_GetVertBoneWeight( v, k ); + float fBoneWeight = G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights ); //bone = bonePtr + piBoneRefs[w->boneIndex]; - tempVert[0] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[0], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[0][3] ); - tempVert[1] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[1], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[1][3] ); - tempVert[2] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[2], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[2][3] ); + tempVert[0] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0][3] ); + tempVert[1] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1][3] ); + tempVert[2] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2][3] ); - tempNormal[0] += fBoneWeight * DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[0], v->normal ); - tempNormal[1] += fBoneWeight * DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[1], v->normal ); - tempNormal[2] += fBoneWeight * DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[2], v->normal ); + tempNormal[0] += fBoneWeight * DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0], v->normal ); + tempNormal[1] += fBoneWeight * DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1], v->normal ); + tempNormal[2] += fBoneWeight * DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2], v->normal ); } int pos = j * 5; @@ -384,21 +384,22 @@ void R_TransformEachSurface( mdxmSurface_t *surface, vec3_t scale, CMiniHeap *G2 // w = v->weights; const int iNumWeights = G2_GetVertWeights( v ); + float fTotalWeight = 0.0f; for ( k = 0 ; k < iNumWeights ; k++ ) { int iBoneIndex = G2_GetVertBoneIndex( v, k ); - float fBoneWeight = G2_GetVertBoneWeight( v, k ); + float fBoneWeight = G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights ); //bone = bonePtr + piBoneRefs[w->boneIndex]; - tempVert[0] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[0], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[0][3] ); - tempVert[1] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[1], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[1][3] ); - tempVert[2] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[2], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[2][3] ); + tempVert[0] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0][3] ); + tempVert[1] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1][3] ); + tempVert[2] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2][3] ); - tempNormal[0] += fBoneWeight * DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[0], v->normal ); - tempNormal[1] += fBoneWeight * DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[1], v->normal ); - tempNormal[2] += fBoneWeight * DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[2], v->normal ); + tempNormal[0] += fBoneWeight * DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0], v->normal ); + tempNormal[1] += fBoneWeight * DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1], v->normal ); + tempNormal[2] += fBoneWeight * DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2], v->normal ); } int pos = j * 5; @@ -970,6 +971,7 @@ bool G2_TracePolys( const mdxmSurface_t *surface, const vec3_t rayStart, const v return false; } + // look at a surface and then do the trace on each poly void G2_TraceSurfaces(CTraceSurface &TS) { @@ -1216,7 +1218,8 @@ qboolean G2_SaveGhoul2Models(CGhoul2Info_v &ghoul2, char **buffer, int *size) // add in count for number of ghoul2 models *size += 4; // start out working out the total size of the buffer we need to allocate - for (int i=0; i= 1020) #pragma once +#endif #if !defined(GHOUL2_SHARED_H_INC) #define GHOUL2_SHARED_H_INC @@ -142,7 +144,7 @@ struct SSkinGoreData typedef vector surfaceInfo_v; typedef vector boneInfo_v; typedef vector boltInfo_v; -typedef vector mdxaBone_v; +typedef vector > mdxaBone_v; // defines for stuff to go into the mflags #define GHOUL2_NOCOLLIDE 0x001 @@ -200,14 +202,6 @@ public: { mFileName[0] = 0; } - - ~CGhoul2Info(void) - { - mSlist.~surfaceInfo_v(); - mBltlist.~boltInfo_v(); - mBlist.~boneInfo_v(); - mTempBoneList.~mdxaBone_v(); - } }; typedef vector CGhoul2Info_v; @@ -260,4 +254,4 @@ enum EWraithInstFlags //==================================================================== -#endif // GHOUL2_SHARED_H_INC \ No newline at end of file +#endif // GHOUL2_SHARED_H_INC diff --git a/CODE-mp/ghoul2/vssver.scc b/CODE-mp/ghoul2/vssver.scc new file mode 100644 index 0000000..f1447ea Binary files /dev/null and b/CODE-mp/ghoul2/vssver.scc differ diff --git a/CODE-mp/installvms.bat b/CODE-mp/installvms.bat new file mode 100644 index 0000000..43c7700 --- /dev/null +++ b/CODE-mp/installvms.bat @@ -0,0 +1,4 @@ +xcopy/d/y release\jk2mp.exe w:\game +xcopy/d/y base\vm\cgame.* w:\game\base\vm +xcopy/d/y base\vm\jk2mpgame.* w:\game\base\vm +xcopy/d/y base\vm\ui.* w:\game\base\vm diff --git a/CODE-mp/jk2mp.dsp b/CODE-mp/jk2mp.dsp index 0366e7b..708b52c 100644 --- a/CODE-mp/jk2mp.dsp +++ b/CODE-mp/jk2mp.dsp @@ -75,7 +75,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /G5 /MTd /W3 /GX /ZI /Od /D "WIN32" /D "_Debug" /D "_WINDOWS" /D "__USEA3D" /D "__A3D_GEOM" /Fr /YX /FD /c -# ADD CPP /nologo /G6 /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_JK2" /Fr /FD /GZ /c +# ADD CPP /nologo /G6 /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_JK2" /D "MEM_DEBUG" /Fr /FD /GZ /c # ADD BASE MTL /nologo /D "_Debug" /mktyplib203 /win32 # ADD MTL /nologo /D "_Debug" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /fo"win32\winquake.res" /d "_Debug" @@ -86,7 +86,7 @@ BSC32=bscmake.exe LINK32=link.exe # ADD BASE LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /profile /map /debug /machine:I386 # SUBTRACT BASE LINK32 /nodefaultlib -# ADD LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Debug/jk2mp.map" /debug /machine:I386 +# ADD LINK32 ./debug/jk2/smrtheap.obj advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Debug/jk2mp.map" /debug /machine:I386 # SUBTRACT LINK32 /profile !ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" @@ -183,6 +183,23 @@ SOURCE=.\win32\winquake.rc # PROP Default_Filter "" # Begin Source File +SOURCE=.\client\0_SH_Leak.cpp + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + SOURCE=.\client\cl_cgame.cpp !IF "$(CFG)" == "jk2mp - Win32 Release JK2" @@ -329,10 +346,6 @@ SOURCE=.\qcommon\cm_public.h # End Source File # Begin Source File -SOURCE=.\qcommon\cm_shader.cpp -# End Source File -# Begin Source File - SOURCE=.\qcommon\cm_test.cpp # End Source File # Begin Source File @@ -345,6 +358,10 @@ SOURCE=.\qcommon\cmd.cpp # End Source File # Begin Source File +SOURCE=.\qcommon\CNetProfile.cpp +# End Source File +# Begin Source File + SOURCE=.\qcommon\common.cpp # End Source File # Begin Source File @@ -361,6 +378,10 @@ SOURCE=.\game\g_public.h # End Source File # Begin Source File +SOURCE=.\qcommon\game_version.h +# End Source File +# Begin Source File + SOURCE=.\qcommon\GenericParser2.cpp # End Source File # Begin Source File @@ -369,10 +390,22 @@ SOURCE=.\qcommon\GenericParser2.h # End Source File # Begin Source File +SOURCE=.\qcommon\hstring.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\hstring.h +# End Source File +# Begin Source File + SOURCE=.\qcommon\huffman.cpp # End Source File # Begin Source File +SOURCE=.\qcommon\INetProfile.h +# End Source File +# Begin Source File + SOURCE=.\ui\keycodes.h # End Source File # Begin Source File @@ -1334,6 +1367,163 @@ SOURCE=.\encryption\sockets.cpp # Begin Source File SOURCE=.\encryption\sockets.h +# End Source File +# End Group +# Begin Group "SmartHeap" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\smartheap\HA312W32.DLL + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\smartheap\HEAPAGNT.H + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\smartheap\SHW32.DLL + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\smartheap\SMRTHEAP.C + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\smartheap\SMRTHEAP.H + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\smartheap\smrtheap.hpp + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\smartheap\HAW32M.LIB + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# End Group +# Begin Group "Debug" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\Debug\HA312W32.DLL + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\Debug\SHW32.DLL + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +!ENDIF + # End Source File # End Group # End Target diff --git a/CODE-mp/jk2mp.dsw b/CODE-mp/jk2mp.dsw index 2b9f289..91b1b55 100644 --- a/CODE-mp/jk2mp.dsw +++ b/CODE-mp/jk2mp.dsw @@ -3,13 +3,13 @@ Microsoft Developer Studio Workspace File, Format Version 6.00 ############################################################################### -Project: "JK2cgame"=.\cgame\JK2_cgame.dsp - Package Owner=<4> +Project: "JK2cgame"=".\cgame\JK2_cgame.dsp" - Package Owner=<4> Package=<5> {{{ begin source code control - "$/General/code/cgame", UPCAAAAA - .\cgame + "$/General/code/cgame", UPCAAAAA + .\cgame end source code control }}} @@ -19,13 +19,13 @@ Package=<4> ############################################################################### -Project: "JK2game"=.\game\JK2_game.dsp - Package Owner=<4> +Project: "JK2game"=".\game\JK2_game.dsp" - Package Owner=<4> Package=<5> {{{ begin source code control - "$/General/code/game", VPCAAAAA - .\game + "$/General/code/game", VPCAAAAA + .\game end source code control }}} @@ -35,7 +35,23 @@ Package=<4> ############################################################################### -Project: "botlib"=.\botlib\botlib.dsp - Package Owner=<4> +Project: "WinDed"=".\WinDed.dsp" - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + "$/General/code", EAAAAAAA + . + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "botlib"=".\botlib\botlib.dsp" - Package Owner=<4> Package=<5> {{{ @@ -51,7 +67,7 @@ Package=<4> ############################################################################### -Project: "jk2mp"=.\jk2mp.dsp - Package Owner=<4> +Project: "jk2mp"=".\jk2mp.dsp" - Package Owner=<4> Package=<5> {{{ @@ -79,7 +95,7 @@ Package=<4> ############################################################################### -Project: "ui"=.\ui\ui.dsp - Package Owner=<4> +Project: "ui"=".\ui\ui.dsp" - Package Owner=<4> Package=<5> {{{ diff --git a/CODE-mp/jk2mp.ncb b/CODE-mp/jk2mp.ncb new file mode 100644 index 0000000..d198736 Binary files /dev/null and b/CODE-mp/jk2mp.ncb differ diff --git a/CODE-mp/jk2mp.opt b/CODE-mp/jk2mp.opt new file mode 100644 index 0000000..bda61d3 Binary files /dev/null and b/CODE-mp/jk2mp.opt differ diff --git a/CODE-mp/jk2mp.plg b/CODE-mp/jk2mp.plg new file mode 100644 index 0000000..3d7297d --- /dev/null +++ b/CODE-mp/jk2mp.plg @@ -0,0 +1,207 @@ + + +
+

Build Log

+

+--------------------Configuration: jk2mp - Win32 Debug JK2-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP64B.tmp" with contents +[ +/nologo /G6 /MLd /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_JK2" /D "MEM_DEBUG" /Fr".\Debug\jk2/" /Fo".\Debug\jk2/" /Fd".\Debug\jk2/" /FD /GZ /c +"C:\projects\jk2\CODE-mp\win32\win_wndproc.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP64B.tmp" +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP64C.tmp" with contents +[ +./debug/jk2/smrtheap.obj advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /incremental:yes /pdb:".\Debug/jk2mp.pdb" /map:"Debug/jk2mp.map" /debug /machine:I386 /out:".\Debug/jk2mp.exe" +".\Debug\jk2\0_SH_Leak.obj" +".\Debug\jk2\cl_cgame.obj" +".\Debug\jk2\cl_cin.obj" +".\Debug\jk2\cl_console.obj" +".\Debug\jk2\cl_input.obj" +".\Debug\jk2\cl_keys.obj" +".\Debug\jk2\cl_main.obj" +".\Debug\jk2\cl_net_chan.obj" +".\Debug\jk2\cl_parse.obj" +".\Debug\jk2\cl_scrn.obj" +".\Debug\jk2\cl_ui.obj" +".\Debug\jk2\FXExport.obj" +".\Debug\jk2\FxPrimitives.obj" +".\Debug\jk2\FxScheduler.obj" +".\Debug\jk2\FxSystem.obj" +".\Debug\jk2\FxTemplate.obj" +".\Debug\jk2\FxUtil.obj" +".\Debug\jk2\cm_load.obj" +".\Debug\jk2\cm_patch.obj" +".\Debug\jk2\cm_polylib.obj" +".\Debug\jk2\cm_test.obj" +".\Debug\jk2\cm_trace.obj" +".\Debug\jk2\cmd.obj" +".\Debug\jk2\CNetProfile.obj" +".\Debug\jk2\common.obj" +".\Debug\jk2\cvar.obj" +".\Debug\jk2\files.obj" +".\Debug\jk2\GenericParser2.obj" +".\Debug\jk2\hstring.obj" +".\Debug\jk2\huffman.obj" +".\Debug\jk2\md4.obj" +".\Debug\jk2\msg.obj" +".\Debug\jk2\net_chan.obj" +".\Debug\jk2\q_math.obj" +".\Debug\jk2\q_shared.obj" +".\Debug\jk2\RoffSystem.obj" +".\Debug\jk2\strip.obj" +".\Debug\jk2\unzip.obj" +".\Debug\jk2\vm.obj" +".\Debug\jk2\vm_interpreted.obj" +".\Debug\jk2\vm_x86.obj" +".\Debug\jk2\win_input.obj" +".\Debug\jk2\win_main.obj" +".\Debug\jk2\win_net.obj" +".\Debug\jk2\win_shared.obj" +".\Debug\jk2\win_snd.obj" +".\Debug\jk2\win_syscon.obj" +".\Debug\jk2\win_wndproc.obj" +".\Debug\jk2\sv_bot.obj" +".\Debug\jk2\sv_ccmds.obj" +".\Debug\jk2\sv_client.obj" +".\Debug\jk2\sv_game.obj" +".\Debug\jk2\sv_init.obj" +".\Debug\jk2\sv_main.obj" +".\Debug\jk2\sv_net_chan.obj" +".\Debug\jk2\sv_snapshot.obj" +".\Debug\jk2\sv_world.obj" +".\Debug\jk2\cdct.obj" +".\Debug\jk2\csbt.obj" +".\Debug\jk2\csbtb.obj" +".\Debug\jk2\csbtl3.obj" +".\Debug\jk2\cup.obj" +".\Debug\jk2\cupini.obj" +".\Debug\jk2\cupl1.obj" +".\Debug\jk2\cupl3.obj" +".\Debug\jk2\cwin.obj" +".\Debug\jk2\cwinb.obj" +".\Debug\jk2\cwinm.obj" +".\Debug\jk2\hwin.obj" +".\Debug\jk2\l3dq.obj" +".\Debug\jk2\l3init.obj" +".\Debug\jk2\mdct.obj" +".\Debug\jk2\mhead.obj" +".\Debug\jk2\msis.obj" +".\Debug\jk2\towave.obj" +".\Debug\jk2\uph.obj" +".\Debug\jk2\upsf.obj" +".\Debug\jk2\wavep.obj" +".\Debug\jk2\snd_dma.obj" +".\Debug\jk2\snd_mem.obj" +".\Debug\jk2\snd_mix.obj" +".\Debug\jk2\snd_mp3.obj" +".\Debug\jk2\jcapimin.obj" +".\Debug\jk2\jccoefct.obj" +".\Debug\jk2\jccolor.obj" +".\Debug\jk2\jcdctmgr.obj" +".\Debug\jk2\jchuff.obj" +".\Debug\jk2\jcinit.obj" +".\Debug\jk2\jcmainct.obj" +".\Debug\jk2\jcmarker.obj" +".\Debug\jk2\jcmaster.obj" +".\Debug\jk2\jcomapi.obj" +".\Debug\jk2\jcparam.obj" +".\Debug\jk2\jcphuff.obj" +".\Debug\jk2\jcprepct.obj" +".\Debug\jk2\jcsample.obj" +".\Debug\jk2\jctrans.obj" +".\Debug\jk2\jdapimin.obj" +".\Debug\jk2\jdapistd.obj" +".\Debug\jk2\jdatadst.obj" +".\Debug\jk2\jdatasrc.obj" +".\Debug\jk2\jdcoefct.obj" +".\Debug\jk2\jdcolor.obj" +".\Debug\jk2\jddctmgr.obj" +".\Debug\jk2\jdhuff.obj" +".\Debug\jk2\jdinput.obj" +".\Debug\jk2\jdmainct.obj" +".\Debug\jk2\jdmarker.obj" +".\Debug\jk2\jdmaster.obj" +".\Debug\jk2\jdpostct.obj" +".\Debug\jk2\jdsample.obj" +".\Debug\jk2\jdtrans.obj" +".\Debug\jk2\jerror.obj" +".\Debug\jk2\jfdctflt.obj" +".\Debug\jk2\jidctflt.obj" +".\Debug\jk2\jmemmgr.obj" +".\Debug\jk2\jmemnobs.obj" +".\Debug\jk2\jutils.obj" +".\Debug\jk2\png.obj" +".\Debug\jk2\matcomp.obj" +".\Debug\jk2\tr_animation.obj" +".\Debug\jk2\tr_backend.obj" +".\Debug\jk2\tr_bsp.obj" +".\Debug\jk2\tr_cmds.obj" +".\Debug\jk2\tr_curve.obj" +".\Debug\jk2\tr_flares.obj" +".\Debug\jk2\tr_font.obj" +".\Debug\jk2\tr_ghoul2.obj" +".\Debug\jk2\tr_image.obj" +".\Debug\jk2\tr_init.obj" +".\Debug\jk2\tr_light.obj" +".\Debug\jk2\tr_main.obj" +".\Debug\jk2\tr_marks.obj" +".\Debug\jk2\tr_mesh.obj" +".\Debug\jk2\tr_model.obj" +".\Debug\jk2\tr_noise.obj" +".\Debug\jk2\tr_quicksprite.obj" +".\Debug\jk2\tr_scene.obj" +".\Debug\jk2\tr_shade.obj" +".\Debug\jk2\tr_shade_calc.obj" +".\Debug\jk2\tr_shader.obj" +".\Debug\jk2\tr_shadows.obj" +".\Debug\jk2\tr_sky.obj" +".\Debug\jk2\tr_surface.obj" +".\Debug\jk2\tr_surfacesprites.obj" +".\Debug\jk2\tr_world.obj" +".\Debug\jk2\tr_WorldEffects.obj" +".\Debug\jk2\win_gamma.obj" +".\Debug\jk2\win_glimp.obj" +".\Debug\jk2\win_qgl.obj" +".\Debug\jk2\G2_API.obj" +".\Debug\jk2\G2_bolts.obj" +".\Debug\jk2\G2_bones.obj" +".\Debug\jk2\G2_misc.obj" +".\Debug\jk2\G2_surfaces.obj" +".\Debug\jk2\adler32.obj" +".\Debug\jk2\crc32.obj" +".\Debug\jk2\deflate.obj" +".\Debug\jk2\infblock.obj" +".\Debug\jk2\infcodes.obj" +".\Debug\jk2\inffast.obj" +".\Debug\jk2\inflate.obj" +".\Debug\jk2\inftrees.obj" +".\Debug\jk2\infutil.obj" +".\Debug\jk2\trees.obj" +".\Debug\jk2\zutil.obj" +".\Debug\jk2\buffer.obj" +".\Debug\jk2\cpp_interface.obj" +".\Debug\jk2\sockets.obj" +".\Debug\jk2\SMRTHEAP.OBJ" +".\win32\winquake.res" +".\smartheap\HAW32M.LIB" +".\Debug\botlib.lib" +".\Debug\uix86.lib" +".\Debug\cgamex86.lib" +".\Debug\jk2mpgamex86.lib" +] +Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP64C.tmp" +

Output Window

+Compiling... +win_wndproc.cpp +Linking... + + + +

Results

+jk2mp.exe - 0 error(s), 0 warning(s) +
+ + diff --git a/CODE-mp/jpeg-6/vssver.scc b/CODE-mp/jpeg-6/vssver.scc new file mode 100644 index 0000000..863686c Binary files /dev/null and b/CODE-mp/jpeg-6/vssver.scc differ diff --git a/CODE-mp/mp3code/vssver.scc b/CODE-mp/mp3code/vssver.scc new file mode 100644 index 0000000..c64c7e5 Binary files /dev/null and b/CODE-mp/mp3code/vssver.scc differ diff --git a/CODE-mp/null/mac_net.c b/CODE-mp/null/mac_net.c new file mode 100644 index 0000000..6232aff --- /dev/null +++ b/CODE-mp/null/mac_net.c @@ -0,0 +1,44 @@ + +#include "../game/q_shared.h" +#include "../qcommon/qcommon.h" + +/* +============= +NET_StringToAdr + +localhost +idnewt +idnewt:28000 +192.246.40.70 +192.246.40.70:28000 +============= +*/ +qboolean NET_StringToAdr (char *s, netadr_t *a) +{ + if (!strcmp (s, "localhost")) { + memset (a, 0, sizeof(*a)); + a->type = NA_LOOPBACK; + return true; + } + + return false; +} + +/* +================== +Sys_SendPacket +================== +*/ +void Sys_SendPacket( int length, void *data, netadr_t to ) { +} + +/* +================== +Sys_GetPacket + +Never called by the game logic, just the system event queing +================== +*/ +qboolean Sys_GetPacket ( netadr_t *net_from, msg_t *net_message ) { + return false; +} diff --git a/CODE-mp/null/null_client.cpp b/CODE-mp/null/null_client.cpp new file mode 100644 index 0000000..bc45bd7 --- /dev/null +++ b/CODE-mp/null/null_client.cpp @@ -0,0 +1,68 @@ + +#include "../client/client.h" + + +char cl_cdkey[17] = "123456789"; + +cvar_t *cl_shownet; + +void CL_Shutdown( void ) { +} + +void CL_Init( void ) { + cl_shownet = Cvar_Get ("cl_shownet", "0", CVAR_TEMP ); +} + +void CL_MouseEvent( int dx, int dy, int time ) { +} + +void Key_WriteBindings( fileHandle_t f ) { +} + +void CL_Frame ( int msec ) { +} + +void CL_PacketEvent( netadr_t from, msg_t *msg ) { +} + +void CL_CharEvent( int key ) { +} + +void CL_Disconnect( qboolean showMainMenu ) { +} + +void CL_MapLoading( void ) { +} + +qboolean CL_GameCommand( void ) { + return qfalse; +} + +void CL_KeyEvent (int key, qboolean down, unsigned time) { +} + +qboolean UI_GameCommand( void ) { + return qfalse; +} + +void CL_ForwardCommandToServer( const char *string ) { +} + +void CL_ConsolePrint( char *txt ) { +} + +void CL_JoystickEvent( int axis, int value, int time ) { +} + +void CL_InitKeyCommands( void ) { +} + +void CL_CDDialog( const char *msg ) { +} + +void CL_FlushMemory( void ) { +} + +void CL_StartHunkUsers( void ) { +} + diff --git a/CODE-mp/null/null_glimp.cpp b/CODE-mp/null/null_glimp.cpp new file mode 100644 index 0000000..2ca9693 --- /dev/null +++ b/CODE-mp/null/null_glimp.cpp @@ -0,0 +1,69 @@ +#include "../renderer/tr_local.h" + +#ifdef _WIN32 +BOOL (WINAPI * qwglSwapIntervalEXT)( int interval ); +void (APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, float s, float t ); +void (APIENTRY * qglActiveTextureARB )( GLenum texture ); +void (APIENTRY * qglClientActiveTextureARB )( GLenum texture ); + + +void (APIENTRY * qglLockArraysEXT)( int, int); +void (APIENTRY * qglUnlockArraysEXT) ( void ); + + +void GLimp_EndFrame( void ) { +} + +void GLimp_Init( void ) +{ +} + +void GLimp_Shutdown( void ) { +} + +void GLimp_EnableLogging( qboolean enable ) { +} + +void GLimp_LogComment( char *comment ) { +} + +qboolean QGL_Init( const char *dllname ) { + return qtrue; +} + +void QGL_Shutdown( void ) { +} +#else +qboolean ( * qwglSwapIntervalEXT)( int interval ); +void ( * qglMultiTexCoord2fARB )( GLenum texture, float s, float t ); +void ( * qglActiveTextureARB )( GLenum texture ); +void ( * qglClientActiveTextureARB )( GLenum texture ); + + +void ( * qglLockArraysEXT)( int, int); +void ( * qglUnlockArraysEXT) ( void ); + + +void GLimp_EndFrame( void ) { +} + +void GLimp_Init( void ) +{ +} + +void GLimp_Shutdown( void ) { +} + +void GLimp_EnableLogging( qboolean enable ) { +} + +void GLimp_LogComment( char *comment ) { +} + +qboolean QGL_Init( const char *dllname ) { + return qtrue; +} + +void QGL_Shutdown( void ) { +} +#endif // !WIN32 diff --git a/CODE-mp/null/null_input.cpp b/CODE-mp/null/null_input.cpp new file mode 100644 index 0000000..7f79d2f --- /dev/null +++ b/CODE-mp/null/null_input.cpp @@ -0,0 +1,14 @@ +#include "../client/client.h" + +void IN_Init( void ) { +} + +void IN_Frame (void) { +} + +void IN_Shutdown( void ) { +} + +void Sys_SendKeyEvents (void) { +} + diff --git a/CODE-mp/null/null_main.c b/CODE-mp/null/null_main.c new file mode 100644 index 0000000..cab5b0d --- /dev/null +++ b/CODE-mp/null/null_main.c @@ -0,0 +1,95 @@ +// sys_null.h -- null system driver to aid porting efforts + +#include +#include +#include "../qcommon/qcommon.h" + +int sys_curtime; + + +//=================================================================== + +void Sys_BeginStreamedFile( FILE *f, int readAhead ) { +} + +void Sys_EndStreamedFile( FILE *f ) { +} + +int Sys_StreamedRead( void *buffer, int size, int count, FILE *f ) { + return fread( buffer, size, count, f ); +} + +void Sys_StreamSeek( FILE *f, int offset, int origin ) { + fseek( f, offset, origin ); +} + + +//=================================================================== + + +void Sys_mkdir ( const char *path ) { +} + +void Sys_Error (char *error, ...) { + va_list argptr; + + printf ("Sys_Error: "); + va_start (argptr,error); + vprintf (error,argptr); + va_end (argptr); + printf ("\n"); + + exit (1); +} + +void Sys_Quit (void) { + exit (0); +} + +void Sys_UnloadGame (void) { +} + +void *Sys_GetGameAPI (void *parms) { + return NULL; +} + +char *Sys_GetClipboardData( void ) { + return NULL; +} + +int Sys_Milliseconds (void) { + return 0; +} + +void Sys_Mkdir (char *path) { +} + +char *Sys_FindFirst (char *path, unsigned musthave, unsigned canthave) { + return NULL; +} + +char *Sys_FindNext (unsigned musthave, unsigned canthave) { + return NULL; +} + +void Sys_FindClose (void) { +} + +void Sys_Init (void) { +} + + +void Sys_EarlyOutput( char *string ) { + printf( "%s", string ); +} + + +void main (int argc, char **argv) { + Com_Init (argc, argv); + + while (1) { + Com_Frame( ); + } +} + + diff --git a/CODE-mp/null/null_net.c b/CODE-mp/null/null_net.c new file mode 100644 index 0000000..2973a8d --- /dev/null +++ b/CODE-mp/null/null_net.c @@ -0,0 +1,43 @@ + +#include "../qcommon/qcommon.h" + +/* +============= +NET_StringToAdr + +localhost +idnewt +idnewt:28000 +192.246.40.70 +192.246.40.70:28000 +============= +*/ +qboolean NET_StringToAdr (char *s, netadr_t *a) +{ + if (!strcmp (s, "localhost")) { + memset (a, 0, sizeof(*a)); + a->type = NA_LOOPBACK; + return true; + } + + return false; +} + +/* +================== +Sys_SendPacket +================== +*/ +void Sys_SendPacket( int length, void *data, netadr_t to ) { +} + +/* +================== +Sys_GetPacket + +Never called by the game logic, just the system event queing +================== +*/ +qboolean Sys_GetPacket ( netadr_t *net_from, msg_t *net_message ) { + return false; +} diff --git a/CODE-mp/null/null_renderer.cpp b/CODE-mp/null/null_renderer.cpp new file mode 100644 index 0000000..dadb28c --- /dev/null +++ b/CODE-mp/null/null_renderer.cpp @@ -0,0 +1,21 @@ +/* Null renderer functions */ + +void RB_StageIteratorGeneric(void) +{ +} + +void RB_StageIteratorSky(void) +{ +} + +void RB_StageIteratorVertexLitTexture(void) +{ +} + +void RB_StageIteratorLightmappedMultitexture(void) +{ +} + +void R_SyncRenderThread(void) +{ +} diff --git a/CODE-mp/null/null_snddma.cpp b/CODE-mp/null/null_snddma.cpp new file mode 100644 index 0000000..eb2afce --- /dev/null +++ b/CODE-mp/null/null_snddma.cpp @@ -0,0 +1,49 @@ + +// snddma_null.c +// all other sound mixing is portable + +#include "../client/client.h" + +qboolean gbInsideLoadSound = qfalse; // important to default to this!!! + +qboolean SNDDMA_Init(void) +{ + return qfalse; +} + +int SNDDMA_GetDMAPos(void) +{ + return 0; +} + +void SNDDMA_Shutdown(void) +{ +} + +void SNDDMA_BeginPainting (void) +{ +} + +void SNDDMA_Submit(void) +{ +} + +sfxHandle_t S_RegisterSound( const char *name ) { + return 0; +} + +void S_StartLocalSound( sfxHandle_t sfxHandle, int channelNum ) { +} + +void S_ClearSoundBuffer( void ) { +} + +qboolean SND_RegisterAudio_LevelLoadEnd(qboolean something) +{ + return qfalse; +} + +int SND_FreeOldestSound(void) +{ + return 0; +} \ No newline at end of file diff --git a/CODE-mp/null/vssver.scc b/CODE-mp/null/vssver.scc new file mode 100644 index 0000000..8be47c1 Binary files /dev/null and b/CODE-mp/null/vssver.scc differ diff --git a/CODE-mp/null/win_main.cpp b/CODE-mp/null/win_main.cpp new file mode 100644 index 0000000..78e357a --- /dev/null +++ b/CODE-mp/null/win_main.cpp @@ -0,0 +1,1693 @@ +// win_main.c + +#include "../client/client.h" +#include "../qcommon/qcommon.h" +#include "../win32/win_local.h" +#include "../win32/resource.h" +#include +#include +#include +#include +#include +#include +#include +#include "../qcommon/strip.h" + +#define CD_BASEDIR "gamedata\\gamedata" +#define CD_EXE "jk2sp.exe" +#define CD_BASEDIR_LINUX "bin\\x86\\glibc-2.1" +#define CD_EXE_LINUX "jk2sp" +#define MEM_THRESHOLD 96*1024*1024 + +static char sys_cmdline[MAX_STRING_CHARS]; +clientStatic_t cls; + +// enable this for executable checksumming +#ifdef FINAL_BUILD +#define SPANK_MONKEYS +#endif +static int sys_monkeySpank; +static int sys_checksum; + + +static unsigned busyCount = 0; +static bool otherTasksRunning = false; +unsigned otherTaskTime = 0; + +#pragma optimize("", off) + +void busyFunction(void) +{ + float a = MEM_THRESHOLD; + float b = 9343; + short c = 4; + + while((int)b > (float)(b-1)) + { + a = a + b / c; + busyCount++; + } +} + +void CheckProcessTime(void) +{ + HANDLE threadHandle; + int threadId; + FILETIME creationTime; // thread creation time + FILETIME exitTime; // thread exit time + FILETIME kernelTime; // thread kernel-mode time + FILETIME userTime; // thread user-mode time +// char temp[1024]; + + busyCount = 0; + threadHandle = CreateThread( + NULL, // LPSECURITY_ATTRIBUTES lpsa, + 0, // DWORD cbStack, + (LPTHREAD_START_ROUTINE)busyFunction, // LPTHREAD_START_ROUTINE lpStartAddr, + 0, // LPVOID lpvThreadParm, + CREATE_SUSPENDED, // DWORD fdwCreate, + (unsigned long *)&threadId ); + + SetThreadPriority(threadHandle, THREAD_PRIORITY_IDLE); + ResumeThread(threadHandle); + while(busyCount < 10) + { + Sleep(100); + } + Sleep(1000); + + TerminateThread(threadHandle, 0); + GetThreadTimes(threadHandle, &creationTime, &exitTime, &kernelTime, &userTime); + CloseHandle(threadHandle); + +// sprintf(temp, "Time = %u\n", userTime.dwLowDateTime); +// OutputDebugString(temp); + + otherTaskTime = userTime.dwLowDateTime; + if (userTime.dwLowDateTime < 7500000) + { + otherTasksRunning = true; +// OutputDebugString("WARNING: possibly running on a system with another task\n"); + } +} + +#pragma optimize("", on) + + +void *Sys_GetBotAIAPI (void *parms ) { + return NULL; +} + +void Conbuf_AppendText( const char *pMsg ) +{ + printf(pMsg); +} + +/* +================== +Sys_LowPhysicalMemory() +================== +*/ + +qboolean Sys_LowPhysicalMemory() { + MEMORYSTATUS stat; + GlobalMemoryStatus (&stat); + return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse; +} + +/* +================== +Sys_FunctionCmp +================== +*/ +int Sys_FunctionCmp(void *f1, void *f2) { + + int i, j, l; + byte func_end[32] = {0xC3, 0x90, 0x90, 0x00}; + byte *ptr, *ptr2; + byte *f1_ptr, *f2_ptr; + + ptr = (byte *) f1; + if (*(byte *)ptr == 0xE9) { + //Com_Printf("f1 %p1 jmp %d\n", (int *) f1, *(int*)(ptr+1)); + f1_ptr = (byte*)(((byte*)f1) + (*(int *)(ptr+1)) + 5); + } + else { + f1_ptr = ptr; + } + //Com_Printf("f1 ptr %p\n", f1_ptr); + + ptr = (byte *) f2; + if (*(byte *)ptr == 0xE9) { + //Com_Printf("f2 %p jmp %d\n", (int *) f2, *(int*)(ptr+1)); + f2_ptr = (byte*)(((byte*)f2) + (*(int *)(ptr+1)) + 5); + } + else { + f2_ptr = ptr; + } + //Com_Printf("f2 ptr %p\n", f2_ptr); + +#ifdef _DEBUG + sprintf((char *)func_end, "%c%c%c%c%c%c%c", 0x5F, 0x5E, 0x5B, 0x8B, 0xE5, 0x5D, 0xC3); +#endif + for (i = 0; i < 1024; i++) { + for (j = 0; func_end[j]; j++) { + if (f1_ptr[i+j] != func_end[j]) + break; + } + if (!func_end[j]) { + break; + } + } +#ifdef _DEBUG + l = i + 7; +#else + l = i + 2; +#endif + //Com_Printf("function length = %d\n", l); + + for (i = 0; i < l; i++) { + // check for a potential function call + if (*((byte *) &f1_ptr[i]) == 0xE8) { + // get the function pointers in case this really is a function call + ptr = (byte *) (((byte *) &f1_ptr[i]) + (*(int *) &f1_ptr[i+1])) + 5; + ptr2 = (byte *) (((byte *) &f2_ptr[i]) + (*(int *) &f2_ptr[i+1])) + 5; + // if it was a function call and both f1 and f2 call the same function + if (ptr == ptr2) { + i += 4; + continue; + } + } + if (f1_ptr[i] != f2_ptr[i]) + return qfalse; + } + return qtrue; +} + +/* +================== +Sys_FunctionCheckSum +================== +*/ +int Sys_FunctionCheckSum(void *f1) { + + int i, j, l; + byte func_end[32] = {0xC3, 0x90, 0x90, 0x00}; + byte *ptr; + byte *f1_ptr; + + ptr = (byte *) f1; + if (*(byte *)ptr == 0xE9) { + //Com_Printf("f1 %p1 jmp %d\n", (int *) f1, *(int*)(ptr+1)); + f1_ptr = (byte*)(((byte*)f1) + (*(int *)(ptr+1)) + 5); + } + else { + f1_ptr = ptr; + } + //Com_Printf("f1 ptr %p\n", f1_ptr); + +#ifdef _DEBUG + sprintf((char *)func_end, "%c%c%c%c%c%c%c", 0x5F, 0x5E, 0x5B, 0x8B, 0xE5, 0x5D, 0xC3); +#endif + for (i = 0; i < 1024; i++) { + for (j = 0; func_end[j]; j++) { + if (f1_ptr[i+j] != func_end[j]) + break; + } + if (!func_end[j]) { + break; + } + } +#ifdef _DEBUG + l = i + 7; +#else + l = i + 2; +#endif + //Com_Printf("function length = %d\n", l); + return Com_BlockChecksum( f1_ptr, l ); +} + +/* +================== +Sys_MonkeyShouldBeSpanked +================== +*/ +int Sys_MonkeyShouldBeSpanked( void ) { + return sys_monkeySpank; +} + +/* +================== +Sys_CodeInMemoryChecksum +================== +*/ +#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr) + (addValue) ) + +int Sys_CodeInMemoryChecksum( void *codeBase ) { + PIMAGE_DOS_HEADER dosHeader; + PIMAGE_NT_HEADERS pNTHeader; + PIMAGE_SECTION_HEADER section; + + dosHeader = (PIMAGE_DOS_HEADER)codeBase; + pNTHeader = MakePtr( PIMAGE_NT_HEADERS, dosHeader, dosHeader->e_lfanew ); + + // First, verify that the e_lfanew field gave us a reasonable + // pointer, then verify the PE signature. + if ( IsBadReadPtr(pNTHeader, sizeof(IMAGE_NT_HEADERS)) || + pNTHeader->Signature != IMAGE_NT_SIGNATURE ) + { + //printf("Unhandled EXE type, or invalid .EXE\n"); + return 0; + } + // first section oughta be the code section + section = (PIMAGE_SECTION_HEADER)(pNTHeader+1); + /* + // the name of the code section should be .text + if ( Q_stricmp( section->Name, ".text" ) ) { + return 0; + } + */ + + return Com_BlockChecksum( ((byte *) codeBase) + section->VirtualAddress, section->SizeOfRawData ); +} + +/* +================== +Sys_ChecksumExe +================== +*/ + +// make sure this string is unique in the executable +// 01234567890123 +byte *exeChecksumId = (unsigned char *)"q3monkeyid\0\0\0\0"; + +void Sys_ChecksumExe( void *codeBase ) { + TCHAR szPathOrig[_MAX_PATH], szPathClone[_MAX_PATH]; + STARTUPINFO si; + TCHAR szCmdLine[512]; + HANDLE hfile, hProcessOrig; + PROCESS_INFORMATION pi; + int l, i, n; + FILE *f; + byte *buf, *ptr; + + // Is this the original EXE or the clone EXE? + if ( Q_stricmp(__argv[1], "monkey") ) { + // Original EXE: Spawn clone EXE to delete this EXE + + GetModuleFileName(NULL, szPathOrig, _MAX_PATH); + GetTempPath(_MAX_PATH, szPathClone); + GetTempFileName(szPathClone, __TEXT("Del"), 0, szPathClone); + CopyFile(szPathOrig, szPathClone, FALSE); + + // Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE + hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL); + // Spawn the clone EXE passing it our EXE's process handle + // and the full path name to the original EXE file. + hProcessOrig = OpenProcess(SYNCHRONIZE, TRUE, + GetCurrentProcessId()); + wsprintf(szCmdLine, __TEXT("%s monkey %d %d \"%s\""), szPathClone, + sys_checksum, hProcessOrig, szPathOrig); + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); + CloseHandle(hProcessOrig); + CloseHandle(hfile); + } else { + // Clone EXE: When original EXE terminates, overwrite it with a new one + sys_checksum = atoi( __argv[2] ); + hProcessOrig = (HANDLE) atoi( __argv[3] ); + WaitForSingleObject(hProcessOrig, INFINITE); + CloseHandle(hProcessOrig); + // open the original executable + f = fopen( __argv[4], "rb" ); + if ( !f ) { + return; + } + fseek (f, 0, SEEK_END); + l = ftell (f); + fseek (f, 0, SEEK_SET); + buf = (unsigned char *)malloc(l); + if ( fread(buf, l, 1, f) != 1 ) { + return; + } + fclose(f); + // search for the exe name string, nice brute force + n = strlen((const char *)exeChecksumId); + for ( i = 0; i < l; i++ ) { + if ( !Q_strncmp((const char *)(buf + i), (const char *)exeChecksumId, n) ) { + break; + } + } + if ( i >= l ) { + return; + } + ptr = buf + i; + // write checksum into exe memory image + ptr[0] = (sys_checksum >> 24) & 0xFF; + ptr[1] = (sys_checksum >> 16) & 0xFF; + ptr[2] = (sys_checksum >> 8) & 0xFF; + ptr[3] = (sys_checksum >> 0) & 0xFF; + ptr[4] = ptr[5] = ptr[6] = ptr[7] = ptr[8] = ptr[9] = 0; + // write out new exe with checksum + f = fopen( __argv[4], "wb" ); + if ( !f ) { + return; + } + if ( fwrite(buf, l, 1, f) != 1 ) { + return; + } + fclose(f); + free(buf); + // The system will delete the clone EXE automatically + // because it was opened with FILE_FLAG_DELETE_ON_CLOSE + } + // + exit(0); +} + +/* +================== +Sys_VerifyCodeChecksum +================== +*/ +void Sys_VerifyCodeChecksum( void *codeBase ) { + // NOTE: should not checksum code in debug mode because the memory image changes + // as soon as you set a break point! +#if defined(SPANK_MONKEYS) && !defined(_DEBUG) + int exeChecksum; + + // if the checksum is not yet stored in the executable + if ( exeChecksumId[4] != 0 ) { + // spawn another process that will replace this executable with one that has a checksum + Sys_ChecksumExe( codeBase ); + return; + } + + exeChecksum = (exeChecksumId[0] << 24) | (exeChecksumId[1] << 16) | (exeChecksumId[2] << 8) | exeChecksumId[3]; + if ( exeChecksum != sys_checksum ) { + sys_monkeySpank = qtrue; + } +#endif +} + +//qboolean stdin_active = qtrue; +char *Sys_ConsoleInput(void) +{ + static char text[256]; + static int len=0; + fd_set fdset; + struct timeval timeout; + +// if (!com_dedicated || !com_dedicated->value) +// return NULL; + +// if (!stdin_active) +// return NULL; + +// FD_ZERO(&fdset); +// FD_SET(0, &fdset); // stdin +// timeout.tv_sec = 0; +// timeout.tv_usec = 0; +// if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset)) +// return NULL; + + if (!kbhit()) return NULL; + if (len == 0) memset(text,0,sizeof(text)); + + text[len] = getch(); + + switch (text[len]) + { + case 8: // backspace + printf("%c %c",text[len],text[len]); + text[len] = 0; + if (len > 0) len--; + text[len] = 0; + break; + case 27: // esc + // clear the line + len = 0; + printf("\n"); + break; + case '\r': + printf("\n"); + text[len] = 0; + len = 0; + return text; + default: + printf("%c",text[len]); + len++; + if (len == sizeof(text)) + { + len = 0; + return text; + } + break; + } +// len = read (0, text, sizeof(text)); +// if (len == 0) { // eof! +// stdin_active = qfalse; +// return NULL; +// } + +// if (len < 1) +// return NULL; +// len = strlen(text); +// text[len-1] = 0; // rip off the /n and terminate + + return NULL; +} + +/* +================== +Sys_BeginProfiling +================== +*/ +void Sys_BeginProfiling( void ) { + // this is just used on the mac build +} + +void Sys_ShowConsole( int visLevel, qboolean quitOnClose ) +{ +} + +/* +============= +Sys_Error + +Show the early console as an error dialog +============= +*/ +void QDECL Sys_Error( const char *error, ... ) { + va_list argptr; + char text[4096]; + MSG msg; + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + Conbuf_AppendText( text ); + Conbuf_AppendText( "\n" ); + +// Sys_SetErrorText( text ); + Sys_ShowConsole( 1, qtrue ); + + timeEndPeriod( 1 ); + + IN_Shutdown(); + + // wait for the user to quit + while ( 1 ) { + if (!GetMessage (&msg, NULL, 0, 0)) + Com_Quit_f (); + TranslateMessage (&msg); + DispatchMessage (&msg); + } + +// Sys_DestroyConsole(); + Com_ShutdownZoneMemory(); +// Com_ShutdownHunkMemory(); + + exit (1); +} + +/* +============== +Sys_Quit +============== +*/ +void Sys_Quit( void ) { + timeEndPeriod( 1 ); + IN_Shutdown(); +// Sys_DestroyConsole(); + Com_ShutdownZoneMemory(); +// Com_ShutdownHunkMemory(); + + exit (0); +} + +/* +============== +Sys_Print +============== +*/ +void Sys_Print( const char *msg ) { + Conbuf_AppendText( msg ); +} + + +/* +============== +Sys_Mkdir +============== +*/ +void Sys_Mkdir( const char *path ) { + _mkdir (path); +} + +/* +============== +Sys_Cwd +============== +*/ +char *Sys_Cwd( void ) { + static char cwd[MAX_OSPATH]; + + _getcwd( cwd, sizeof( cwd ) - 1 ); + cwd[MAX_OSPATH-1] = 0; + + return cwd; +} + +/* +============== +Sys_DefaultCDPath +============== +*/ +char *Sys_DefaultCDPath( void ) { + return ""; +} + +/* +============== +Sys_DefaultBasePath +============== +*/ +char *Sys_DefaultBasePath( void ) { + return Sys_Cwd(); +} + +/* +============================================================== + +DIRECTORY SCANNING + +============================================================== +*/ + +#define MAX_FOUND_FILES 0x1000 + +void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **psList, int *numfiles ) { + char search[MAX_OSPATH], newsubdirs[MAX_OSPATH]; + char filename[MAX_OSPATH]; + int findhandle; + struct _finddata_t findinfo; + + if ( *numfiles >= MAX_FOUND_FILES - 1 ) { + return; + } + + if (strlen(subdirs)) { + Com_sprintf( search, sizeof(search), "%s\\%s\\*", basedir, subdirs ); + } + else { + Com_sprintf( search, sizeof(search), "%s\\*", basedir ); + } + + findhandle = _findfirst (search, &findinfo); + if (findhandle == -1) { + return; + } + + do { + if (findinfo.attrib & _A_SUBDIR) { + if (Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..")) { + if (strlen(subdirs)) { + Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s\\%s", subdirs, findinfo.name); + } + else { + Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", findinfo.name); + } + Sys_ListFilteredFiles( basedir, newsubdirs, filter, psList, numfiles ); + } + } + if ( *numfiles >= MAX_FOUND_FILES - 1 ) { + break; + } + Com_sprintf( filename, sizeof(filename), "%s\\%s", subdirs, findinfo.name ); + if (!Com_FilterPath( filter, filename, qfalse )) + continue; + psList[ *numfiles ] = CopyString( filename ); + (*numfiles)++; + } while ( _findnext (findhandle, &findinfo) != -1 ); + + _findclose (findhandle); +} + +static qboolean strgtr(const char *s0, const char *s1) { + int l0, l1, i; + + l0 = strlen(s0); + l1 = strlen(s1); + + if (l1 s0[i]) { + return qtrue; + } + if (s1[i] < s0[i]) { + return qfalse; + } + } + return qfalse; +} + +char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) { + char search[MAX_OSPATH]; + int nfiles; + char **listCopy; + char *list[MAX_FOUND_FILES]; + struct _finddata_t findinfo; + int findhandle; + int flag; + int i; + + if (filter) { + + nfiles = 0; + Sys_ListFilteredFiles( directory, "", filter, list, &nfiles ); + + list[ nfiles ] = 0; + *numfiles = nfiles; + + if (!nfiles) + return NULL; + + listCopy = (char **)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ), TAG_FILESYS ); + for ( i = 0 ; i < nfiles ; i++ ) { + listCopy[i] = list[i]; + } + listCopy[i] = NULL; + + return listCopy; + } + + if ( !extension) { + extension = ""; + } + + // passing a slash as extension will find directories + if ( extension[0] == '/' && extension[1] == 0 ) { + extension = ""; + flag = 0; + } else { + flag = _A_SUBDIR; + } + + Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension ); + + // search + nfiles = 0; + + findhandle = _findfirst (search, &findinfo); + if (findhandle == -1) { + *numfiles = 0; + return NULL; + } + + do { + if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) { + if ( nfiles == MAX_FOUND_FILES - 1 ) { + break; + } + list[ nfiles ] = CopyString( findinfo.name ); + nfiles++; + } + } while ( _findnext (findhandle, &findinfo) != -1 ); + + list[ nfiles ] = 0; + + _findclose (findhandle); + + // return a copy of the list + *numfiles = nfiles; + + if ( !nfiles ) { + return NULL; + } + + listCopy = (char **)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ), TAG_FILESYS ); + for ( i = 0 ; i < nfiles ; i++ ) { + listCopy[i] = list[i]; + } + listCopy[i] = NULL; + + do { + flag = 0; + for(i=1; i (5 * 60000)) && !Cvar_VariableIntegerValue( "dedicated" ) + && !Cvar_VariableIntegerValue( "com_blindlyLoadDLLs" ) ) { + if (FS_FileExists(filename)) { + lastWarning = timestamp; + ret = MessageBoxEx( NULL, "You are about to load a .DLL executable that\n" + "has not been verified for use with Quake III Arena.\n" + "This type of file can compromise the security of\n" + "your computer.\n\n" + "Select 'OK' if you choose to load it anyway.", + "Security Warning", MB_OKCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_TOPMOST | MB_SETFOREGROUND, + MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ) ); + if( ret != IDOK ) { + return NULL; + } + } + } +#endif + + +// rjr disable for final release #ifndef NDEBUG + libHandle = LoadLibrary( filename ); + if ( !libHandle ) { +//#endif + basepath = Cvar_VariableString( "fs_basepath" ); + cdpath = Cvar_VariableString( "fs_cdpath" ); + gamedir = Cvar_VariableString( "fs_game" ); + + fn = FS_BuildOSPath( basepath, gamedir, filename ); + libHandle = LoadLibrary( fn ); + + if ( !libHandle ) { + if( cdpath[0] ) { + fn = FS_BuildOSPath( cdpath, gamedir, filename ); + libHandle = LoadLibrary( fn ); + } + + if ( !libHandle ) { + return NULL; + } + } +//#ifndef NDEBUG + } +//#endif + + dllEntry = ( void (QDECL *)( int (QDECL *)( int, ... ) ) )GetProcAddress( libHandle, "dllEntry" ); + *entryPoint = (int (QDECL *)(int,...))GetProcAddress( libHandle, "vmMain" ); + if ( !*entryPoint || !dllEntry ) { + FreeLibrary( libHandle ); + return NULL; + } + dllEntry( systemcalls ); + + return libHandle; +} + + +/* +======================================================================== + +BACKGROUND FILE STREAMING + +======================================================================== +*/ + +#if 1 + +void Sys_InitStreamThread( void ) { +} + +void Sys_ShutdownStreamThread( void ) { +} + +void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) { +} + +void Sys_EndStreamedFile( fileHandle_t f ) { +} + +int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) { + return FS_Read( buffer, size * count, f ); +} + +void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) { + FS_Seek( f, offset, origin ); +} + + +#else + +typedef struct { + fileHandle_t file; + byte *buffer; + qboolean eof; + qboolean active; + int bufferSize; + int streamPosition; // next byte to be returned by Sys_StreamRead + int threadPosition; // next byte to be read from file +} streamsIO_t; + +typedef struct { + HANDLE threadHandle; + int threadId; + CRITICAL_SECTION crit; + streamsIO_t sIO[MAX_FILE_HANDLES]; +} streamState_t; + +streamState_t stream; + +/* +=============== +Sys_StreamThread + +A thread will be sitting in this loop forever +================ +*/ +void Sys_StreamThread( void ) { + int buffer; + int count; + int readCount; + int bufferPoint; + int r, i; + + while (1) { + Sleep( 10 ); +// EnterCriticalSection (&stream.crit); + + for (i=1;i 0 ) { + available = stream.sIO[f].threadPosition - stream.sIO[f].streamPosition; + if ( !available ) { + if ( stream.sIO[f].eof ) { + break; + } + if ( sleepCount == 1 ) { + Com_DPrintf( "Sys_StreamedRead: waiting\n" ); + } + if ( ++sleepCount > 100 ) { + Com_Error( ERR_FATAL, "Sys_StreamedRead: thread has died"); + } + Sleep( 10 ); + continue; + } + + EnterCriticalSection( &stream.crit ); + + bufferPoint = stream.sIO[f].streamPosition % stream.sIO[f].bufferSize; + bufferCount = stream.sIO[f].bufferSize - bufferPoint; + + copy = available < bufferCount ? available : bufferCount; + if ( copy > remaining ) { + copy = remaining; + } + memcpy( dest, stream.sIO[f].buffer + bufferPoint, copy ); + stream.sIO[f].streamPosition += copy; + dest += copy; + remaining -= copy; + + LeaveCriticalSection( &stream.crit ); + } + + return (count * size - remaining) / size; +} + +/* +=============== +Sys_StreamSeek + +================ +*/ +void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) { + + // halt the thread + EnterCriticalSection( &stream.crit ); + + // clear to that point + FS_Seek( f, offset, origin ); + stream.sIO[f].streamPosition = 0; + stream.sIO[f].threadPosition = 0; + stream.sIO[f].eof = qfalse; + + // let the thread start running at the new position + LeaveCriticalSection( &stream.crit ); +} + +#endif + +/* +======================================================================== + +EVENT LOOP + +======================================================================== +*/ + +#define MAX_QUED_EVENTS 256 +#define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 ) + +sysEvent_t eventQue[MAX_QUED_EVENTS]; +int eventHead, eventTail; +byte sys_packetReceived[MAX_MSGLEN]; + +/* +================ +Sys_QueEvent + +A time of 0 will get the current time +Ptr should either be null, or point to a block of data that can +be freed by the game later. +================ +*/ +void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) { + sysEvent_t *ev; + + ev = &eventQue[ eventHead & MASK_QUED_EVENTS ]; + if ( eventHead - eventTail >= MAX_QUED_EVENTS ) { + Com_Printf("Sys_QueEvent: overflow\n"); + // we are discarding an event, but don't leak memory + if ( ev->evPtr ) { + Z_Free( ev->evPtr ); + } + eventTail++; + } + + eventHead++; + + if ( time == 0 ) { + time = Sys_Milliseconds(); + } + + ev->evTime = time; + ev->evType = type; + ev->evValue = value; + ev->evValue2 = value2; + ev->evPtrLength = ptrLength; + ev->evPtr = ptr; +} + +/* +================ +Sys_GetEvent + +================ +*/ +sysEvent_t Sys_GetEvent( void ) { + MSG msg; + sysEvent_t ev; + char *s; + msg_t netmsg; + netadr_t adr; + + // return if we have data + if ( eventHead > eventTail ) { + eventTail++; + return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ]; + } + + // pump the message loop + while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) { + if ( !GetMessage (&msg, NULL, 0, 0) ) { + Com_Quit_f(); + } + + // save the msg time, because wndprocs don't have access to the timestamp +// g_wv.sysMsgTime = msg.time; + + TranslateMessage (&msg); + DispatchMessage (&msg); + } + + // check for console commands + s = Sys_ConsoleInput(); + if ( s ) { + char *b; + int len; + + len = strlen( s ) + 1; + b = (char *)Z_Malloc( len, TAG_EVENT ); + Q_strncpyz( b, s, len ); + Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b ); + } + + // check for network packets + MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) ); + if ( Sys_GetPacket ( &adr, &netmsg ) ) { + netadr_t *buf; + int len; + + // copy out to a seperate buffer for qeueing + // the readcount stepahead is for SOCKS support + len = sizeof( netadr_t ) + netmsg.cursize - netmsg.readcount; + buf = (netadr_t *)Z_Malloc( len, TAG_EVENT, qtrue ); + *buf = adr; + memcpy( buf+1, &netmsg.data[netmsg.readcount], netmsg.cursize - netmsg.readcount ); + Sys_QueEvent( 0, SE_PACKET, 0, 0, len, buf ); + } + + // return if we have data + if ( eventHead > eventTail ) { + eventTail++; + return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ]; + } + + // create an empty event to return + + memset( &ev, 0, sizeof( ev ) ); + ev.evTime = timeGetTime(); + + return ev; +} + +//================================================================ + +/* +================= +Sys_In_Restart_f + +Restart the input subsystem +================= +*/ +void Sys_In_Restart_f( void ) { + IN_Shutdown(); + IN_Init(); +} + + +/* +================= +Sys_Net_Restart_f + +Restart the network subsystem +================= +*/ +void Sys_Net_Restart_f( void ) { + NET_Restart(); +} + + +/* +================ +Sys_Init + +Called after the common systems (cvars, files, etc) +are initialized +================ +*/ +#define OSR2_BUILD_NUMBER 1111 +#define WIN98_BUILD_NUMBER 1998 + +void Sys_Init( void ) { + int cpuid; + + // make sure the timer is high precision, otherwise + // NT gets 18ms resolution + timeBeginPeriod( 1 ); + + Cmd_AddCommand ("in_restart", Sys_In_Restart_f); + Cmd_AddCommand ("net_restart", Sys_Net_Restart_f); + +// g_wv.osversion.dwOSVersionInfoSize = sizeof( g_wv.osversion ); + +// if (!GetVersionEx (&g_wv.osversion)) +// Sys_Error ("Couldn't get OS info"); + +// if (g_wv.osversion.dwMajorVersion < 4) +// Sys_Error ("This game requires Windows version 4 or greater"); +// if (g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32s) +// Sys_Error ("This game doesn't run on Win32s"); + +// if ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ) +// { +// Cvar_Set( "arch", "winnt" ); +// } +// else if ( g_wv.osversion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) +// { +// if ( LOWORD( g_wv.osversion.dwBuildNumber ) >= WIN98_BUILD_NUMBER ) +// { +// Cvar_Set( "arch", "win98" ); +// } +// else if ( LOWORD( g_wv.osversion.dwBuildNumber ) >= OSR2_BUILD_NUMBER ) +// { +// Cvar_Set( "arch", "win95 osr2.x" ); +// } +// else +// { +// Cvar_Set( "arch", "win95" ); +// } +// } +// else +// { +// Cvar_Set( "arch", "unknown Windows variant" ); +// } + + // save out a couple things in rom cvars for the renderer to access +// Cvar_Get( "win_hinstance", va("%i", (int)g_wv.hInstance), CVAR_ROM ); +// Cvar_Get( "win_wndproc", va("%i", (int)MainWndProc), CVAR_ROM ); + + // + // figure out our CPU + // + Cvar_Get( "sys_cpustring", "detect", 0 ); + if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring"), "detect" ) ) + { + Com_Printf( "...detecting CPU, found " ); + + cpuid = Sys_GetProcessorId(); + + switch ( cpuid ) + { + case CPUID_GENERIC: + Cvar_Set( "sys_cpustring", "generic" ); + break; + case CPUID_INTEL_UNSUPPORTED: + Cvar_Set( "sys_cpustring", "x86 (pre-Pentium)" ); + break; + case CPUID_INTEL_PENTIUM: + Cvar_Set( "sys_cpustring", "x86 (P5/PPro, non-MMX)" ); + break; + case CPUID_INTEL_MMX: + Cvar_Set( "sys_cpustring", "x86 (P5/Pentium2, MMX)" ); + break; + case CPUID_INTEL_KATMAI: + Cvar_Set( "sys_cpustring", "Intel Pentium III" ); + break; + case CPUID_INTEL_WILLIAMETTE: + Cvar_Set( "sys_cpustring", "Intel Pentium IV" ); + break; + case CPUID_AMD_3DNOW: + Cvar_Set( "sys_cpustring", "AMD w/ 3DNow!" ); + break; + case CPUID_AXP: + Cvar_Set( "sys_cpustring", "Alpha AXP" ); + break; + default: + Com_Error( ERR_FATAL, "Unknown cpu type %d\n", cpuid ); + break; + } + } + else + { + Com_Printf( "...forcing CPU type to " ); + if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "generic" ) ) + { + cpuid = CPUID_GENERIC; + } + else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "x87" ) ) + { + cpuid = CPUID_INTEL_PENTIUM; + } + else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "mmx" ) ) + { + cpuid = CPUID_INTEL_MMX; + } + else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "3dnow" ) ) + { + cpuid = CPUID_AMD_3DNOW; + } + else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "PentiumIII" ) ) + { + cpuid = CPUID_INTEL_KATMAI; + } + else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "PentiumIV" ) ) + { + cpuid = CPUID_INTEL_WILLIAMETTE; + } + else if ( !Q_stricmp( Cvar_VariableString( "sys_cpustring" ), "axp" ) ) + { + cpuid = CPUID_AXP; + } + else + { + Com_Printf( "WARNING: unknown sys_cpustring '%s'\n", Cvar_VariableString( "sys_cpustring" ) ); + cpuid = CPUID_GENERIC; + } + } + Cvar_SetValue( "sys_cpuid", cpuid ); + Com_Printf( "%s\n", Cvar_VariableString( "sys_cpustring" ) ); + + Cvar_Set( "username", Sys_GetCurrentUser() ); + + IN_Init(); // FIXME: not in dedicated? +} + +// do a quick mem test to check for any potential future mem problems... +// +void QuickMemTest(void) +{ +// if (!Sys_LowPhysicalMemory()) + { + const int iMemTestMegs = 64; // useful search label + // special test, + void *pvData = malloc(iMemTestMegs * 1024 * 1024); + if (pvData) + { + free(pvData); + } + else + { + // err... + // + LPCSTR psContinue = "Your machine failed to allocate %dMB in a memory test, which may mean you'll have problems running this game all the way through.\n\nContinue anyway?"; + LPCSTR psNoMem = "Insufficient memory to run this game!\n"; + + switch (Language_GetIntegerValue()) + { + case SP_LANGUAGE_GERMAN: + + psContinue = "Ihr Computer konnte bei einem Speichertest keine %dMB reservieren, daher werden Sie mit dem Starten des Spiels Probleme haben.\n\nDennoch fortsetzen?"; + psNoMem = "Unzureichender Speicher zum Starten!\n"; + break; + + case SP_LANGUAGE_FRENCH: + + psContinue = "Votre système n'a pu allouer %d Mo lors d'une vérification de la mémoire, ce qui signifie que vous aurez peut-être du mal à faire fonctionner ce jeu. \n\nSouhaitez-vous continuer malgré tout ?"; + psNoMem = "Mémoire insuffisante pour lancer ce jeu !\n"; + break; + } + + #define GetYesNo(psQuery) (!!(MessageBox(NULL,psQuery,"Query",MB_YESNO|MB_ICONWARNING|MB_TASKMODAL)==IDYES)) + if (!GetYesNo(va(psContinue,iMemTestMegs))) + { + Com_Error( ERR_FATAL, psNoMem ); + } + } + } +} + + +//======================================================================= +//int totalMsec, countMsec; + +/* +================== +WinMain + +================== +*/ +//int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { +int main(int argc, char **argv) +{ + char cwd[MAX_OSPATH]; + char *cmdline; + int i,len; +// int startTime, endTime; + + // should never get a previous instance in Win32 +// if ( hPrevInstance ) { +// return 0; +// } + +// sys_checksum = Sys_CodeInMemoryChecksum( hInstance ); +// Sys_VerifyCodeChecksum( hInstance ); + + // merge the command line, this is kinda silly + for (len = 1, i = 1; i < argc; i++) + len += strlen(argv[i]) + 1; + cmdline = (char *)malloc(len); + *cmdline = 0; + for (i = 1; i < argc; i++) { + if (i > 1) + strcat(cmdline, " "); + strcat(cmdline, argv[i]); + } + +// g_wv.hInstance = hInstance; +// Q_strncpyz( sys_cmdline, lpCmdLine, sizeof( sys_cmdline ) ); + + + // done before Com/Sys_Init since we need this for error output +// Sys_CreateConsole(); + + // no abort/retry/fail errors + SetErrorMode( SEM_FAILCRITICALERRORS ); + + // get the initial time base + Sys_Milliseconds(); + +#if 0 + // if we find the CD, add a +set cddir xxx command line + Sys_ScanForCD(); +#endif + + + Sys_InitStreamThread(); + +#if 0 + CheckProcessTime(); +#endif + + Com_Init( cmdline ); +#if 0 + Cvar_Set( "com_othertasks", ( otherTasksRunning ? "1" : "0" ) ); + Cvar_Set( "com_othertaskstime", va("%u", otherTaskTime) ); +#else + Cvar_Set( "com_othertasks", "0" ); +#endif + + NET_Init(); + + _getcwd (cwd, sizeof(cwd)); + Com_Printf("Working directory: %s\n", cwd); + + // hide the early console since we've reached the point where we + // have a working graphics subsystems + if ( !com_dedicated->integer && !com_viewlog->integer ) { + Sys_ShowConsole( 0, qfalse ); + } + +#ifdef _DEBUG + if ( sys_monkeySpank ) { + Cvar_Set("cl_trn", "666"); + } +#endif + + // main game loop + while( 1 ) { + // if not running as a game client, sleep a bit +// if ( g_wv.isMinimized || ( com_dedicated && com_dedicated->integer ) ) { + Sleep( 5 ); +// } + + // set low precision every frame, because some system calls + // reset it arbitrarily +// _controlfp( _PC_24, _MCW_PC ); + +// startTime = Sys_Milliseconds(); + + // make sure mouse and joystick are only called once a frame + IN_Frame(); + + // run the game + Com_Frame(); + +// endTime = Sys_Milliseconds(); +// totalMsec += endTime - startTime; +// countMsec++; + } + + // never gets here + return 0; +} + + diff --git a/CODE-mp/png/vssver.scc b/CODE-mp/png/vssver.scc new file mode 100644 index 0000000..5286c8b Binary files /dev/null and b/CODE-mp/png/vssver.scc differ diff --git a/CODE-mp/put.bat b/CODE-mp/put.bat new file mode 100644 index 0000000..4e62303 --- /dev/null +++ b/CODE-mp/put.bat @@ -0,0 +1 @@ +@echo use installvms instead diff --git a/CODE-mp/qcommon/CNetProfile.cpp b/CODE-mp/qcommon/CNetProfile.cpp new file mode 100644 index 0000000..81aba13 --- /dev/null +++ b/CODE-mp/qcommon/CNetProfile.cpp @@ -0,0 +1,94 @@ +#ifdef _DONETPROFILE_ + +#pragma warning( disable : 4786) +#pragma warning( disable : 4100) +#pragma warning( disable : 4663) + +#include +#include +#include +#include "hstring.h" +#include "INetProfile.h" + +using namespace std; + +class CNetProfile : public INetProfile +{ + float mElapsedTime; + map mFieldCounts; + float mFrameCount; + +public: + void Reset(void) + { + mFieldCounts.clear(); + mFrameCount=0; + } + + void AddField(char *fieldName,int sizeBytes) + { + assert(sizeBytes>=0); + if(sizeBytes==0) + { + return; + } + map::iterator f=mFieldCounts.find(fieldName); + if(f==mFieldCounts.end()) + { + mFieldCounts[fieldName]=(unsigned int)sizeBytes; + } + else + { + mFieldCounts[fieldName]+=(unsigned int)sizeBytes; + } + } + + void IncTime(int msec) + { + mElapsedTime+=msec; + } + + void ShowTotals(void) + { + float totalBytes=0; + multimap sort; + map::iterator f; + for(f=mFieldCounts.begin();f!=mFieldCounts.end();f++) + { + sort.insert(pair ((*f).second,(*f).first)); + totalBytes+=(*f).second; + } + + multimap::iterator j; + char msg[1024]; + float percent; + sprintf(msg, + "******** Totals: bytes %d : bytes per sec %d ********\n", + (unsigned int)totalBytes, + (unsigned int)((totalBytes/mElapsedTime)*1000)); + Sleep(10); + OutputDebugString(msg); + for(j=sort.begin();j!=sort.end();j++) + { + percent=(((float)(*j).first)/totalBytes)*100.0f; + assert(strlen((*j).second.c_str())<1024); + sprintf(msg,"%36s : %3.4f percent : %d bytes \n",(*j).second.c_str(),percent,(*j).first); + Sleep(10); + OutputDebugString(msg); + } + } +}; + +INetProfile &ClReadProf(void) +{ + static CNetProfile theClReadProf; + return(theClReadProf); +} + +INetProfile &ClSendProf(void) +{ + static CNetProfile theClSendProf; + return(theClSendProf); +} + +#endif // _DONETPROFILE_ \ No newline at end of file diff --git a/CODE-mp/qcommon/GenericParser2.h b/CODE-mp/qcommon/GenericParser2.h index e2e654a..8b97da5 100644 --- a/CODE-mp/qcommon/GenericParser2.h +++ b/CODE-mp/qcommon/GenericParser2.h @@ -1,4 +1,6 @@ +#if defined (_MSC_VER) && (_MSC_VER >= 1020) #pragma once +#endif #if !defined(GENERICPARSER2_H_INC) #define GENERICPARSER2_H_INC diff --git a/CODE-mp/qcommon/INetProfile.h b/CODE-mp/qcommon/INetProfile.h new file mode 100644 index 0000000..9dd9600 --- /dev/null +++ b/CODE-mp/qcommon/INetProfile.h @@ -0,0 +1,20 @@ +#ifdef _DONETPROFILE_ + +#define _INETPROFILE_H_ +#ifdef _INETPROFILE_H_ + +class INetProfile +{ +public: + virtual void Reset(void)=0; + virtual void AddField(char *fieldName,int sizeBytes)=0; + virtual void IncTime(int msec)=0; + virtual void ShowTotals(void)=0; +}; + +INetProfile &ClReadProf(void); +INetProfile &ClSendProf(void); + +#endif // _INETPROFILE_H_ + +#endif // _DONETPROFILE_ \ No newline at end of file diff --git a/CODE-mp/qcommon/RoffSystem.cpp b/CODE-mp/qcommon/RoffSystem.cpp index fae64cd..67819d9 100644 --- a/CODE-mp/qcommon/RoffSystem.cpp +++ b/CODE-mp/qcommon/RoffSystem.cpp @@ -1,6 +1,6 @@ -#include "RoffSystem.h" +#include "ROFFSystem.h" #include "qcommon.h" -#include "..\client\client.h" +#include "../client/client.h" // The one and only instance... CROFFSystem theROFFSystem; @@ -406,7 +406,15 @@ qboolean CROFFSystem::Unload( int id ) { // requested item found in the list, free mem, then remove from list delete ((CROFF *)(*itr).second); +#ifndef __linux__ itr = mROFFList.erase( itr ); +#else + // darn stl differences + TROFFList::iterator titr; + titr = itr; + itr++; + mROFFList.erase(titr); +#endif #ifdef _DEBUG Com_Printf( S_COLOR_GREEN"roff unloaded\n" ); @@ -803,12 +811,14 @@ qboolean CROFFSystem::ApplyROFF( SROFFEntity *roff_ent, CROFFSystem::CROFF *roff if (roff_ent->mIsClient) { +#ifndef DEDICATED originTrajectory = (trajectory_t *)VM_Call( cgvm, CG_GET_ORIGIN_TRAJECTORY, roff_ent->mEntID ); angleTrajectory = (trajectory_t *)VM_Call( cgvm, CG_GET_ANGLE_TRAJECTORY, roff_ent->mEntID ); VM_Call( cgvm, CG_GET_ORIGIN, roff_ent->mEntID, originTemp ); origin = originTemp; VM_Call( cgvm, CG_GET_ANGLES, roff_ent->mEntID, angleTemp ); angle = angleTemp; +#endif } else { @@ -912,7 +922,9 @@ void CROFFSystem::ProcessNote(SROFFEntity *roff_ent, char *note) { if (roff_ent->mIsClient) { +#ifndef DEDICATED VM_Call( cgvm, CG_ROFF_NOTETRACK_CALLBACK, roff_ent->mEntID, temp ); +#endif } else { @@ -941,12 +953,14 @@ qboolean CROFFSystem::ClearLerp( SROFFEntity *roff_ent ) if (roff_ent->mIsClient) { +#ifndef DEDICATED originTrajectory = (trajectory_t *)VM_Call( cgvm, CG_GET_ORIGIN_TRAJECTORY, roff_ent->mEntID ); angleTrajectory = (trajectory_t *)VM_Call( cgvm, CG_GET_ANGLE_TRAJECTORY, roff_ent->mEntID ); VM_Call( cgvm, CG_GET_ORIGIN, roff_ent->mEntID, originTemp ); origin = originTemp; VM_Call( cgvm, CG_GET_ANGLES, roff_ent->mEntID, angleTemp ); angle = angleTemp; +#endif } else { diff --git a/CODE-mp/qcommon/RoffSystem.h b/CODE-mp/qcommon/RoffSystem.h index 13f5c54..a2e07c4 100644 --- a/CODE-mp/qcommon/RoffSystem.h +++ b/CODE-mp/qcommon/RoffSystem.h @@ -1,4 +1,6 @@ +#if defined (_MSC_VER) && (_MSC_VER >= 1020) #pragma once +#endif #if !defined(CROFFSYSTEM_H_INC) #define CROFFSYSTEM_H_INC diff --git a/CODE-mp/qcommon/cm_load.cpp b/CODE-mp/qcommon/cm_load.cpp index 7acef50..5dcd38b 100644 --- a/CODE-mp/qcommon/cm_load.cpp +++ b/CODE-mp/qcommon/cm_load.cpp @@ -91,7 +91,6 @@ void CMod_LoadShaders( lump_t *l ) out->contentFlags = LittleLong( in->contentFlags ); out->surfaceFlags = LittleLong( in->surfaceFlags ); } - CM_SetupShaderProperties(); } @@ -610,8 +609,7 @@ static void CM_LoadMap_Actual( const char *name, qboolean clientload, int *check } // free old stuff - Com_Memset( &cm, 0, sizeof( cm ) ); - CM_ClearLevelPatches(); + CM_ClearMap(); if ( !name[0] ) { cm.numLeafs = 1; @@ -675,9 +673,6 @@ static void CM_LoadMap_Actual( const char *name, qboolean clientload, int *check , name, header.version, BSP_VERSION ); } - // Load in the shader text - return instantly if already loaded - CM_LoadShaderText(false); - cmod_base = (byte *)buf; // load into heap @@ -701,7 +696,7 @@ static void CM_LoadMap_Actual( const char *name, qboolean clientload, int *check // map data will have been Little-Long'd, but some hasn't). // if (Sys_LowPhysicalMemory() - || com_dedicated->integer // no need to check for dedicated in single-player codebase + || com_dedicated->integer // || we're on a big-endian machine ) { @@ -746,8 +741,8 @@ void CM_LoadMap( const char *name, qboolean clientload, int *checksum ) CM_ClearMap ================== */ -void CM_ClearMap( void ) { - +void CM_ClearMap( void ) +{ Com_Memset( &cm, 0, sizeof( cm ) ); CM_ClearLevelPatches(); } diff --git a/CODE-mp/qcommon/cm_local.h b/CODE-mp/qcommon/cm_local.h index 08f9256..47e388c 100644 --- a/CODE-mp/qcommon/cm_local.h +++ b/CODE-mp/qcommon/cm_local.h @@ -194,10 +194,3 @@ struct patchCollide_s *CM_GeneratePatchCollide( int width, int height, vec3_t *p void CM_TraceThroughPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ); qboolean CM_PositionTestInPatchCollide( traceWork_t *tw, const struct patchCollide_s *pc ); void CM_ClearLevelPatches( void ); - -// cm_shader.cpp -void CM_SetupShaderProperties( void ); -void CM_ShutdownShaderProperties(void); -CCMShader *CM_GetShaderInfo( const char *name ); -CCMShader *CM_GetShaderInfo( int shaderNum ); -int CM_HandleDamageShader(int sideNum, int damage); diff --git a/CODE-mp/qcommon/cm_public.h b/CODE-mp/qcommon/cm_public.h index 912b63f..54bab44 100644 --- a/CODE-mp/qcommon/cm_public.h +++ b/CODE-mp/qcommon/cm_public.h @@ -1,4 +1,4 @@ - +#include "../game/q_shared.h" #include "qfiles.h" @@ -57,4 +57,4 @@ void CM_DrawDebugSurface( void (*drawPoly)(int color, int numPoints, float *poin // cm_shader.cpp const char *CM_GetShaderText(const char *key); void CM_FreeShaderText(void); -void CM_LoadShaderText(bool forceReload); +void CM_LoadShaderText(qboolean forceReload); diff --git a/CODE-mp/qcommon/cm_shader.cpp b/CODE-mp/qcommon/cm_shader.cpp index bc80872..80edfad 100644 --- a/CODE-mp/qcommon/cm_shader.cpp +++ b/CODE-mp/qcommon/cm_shader.cpp @@ -71,7 +71,7 @@ void CM_LoadShaderFiles( void ) { char **shaderFiles1; int numShaders1; -#ifndef _FINAL +#ifndef FINAL_BUILD char **shaderFiles2; int numShaders2; #endif @@ -82,7 +82,7 @@ void CM_LoadShaderFiles( void ) // scan for shader files shaderFiles1 = FS_ListFiles( "shaders", ".shader", &numShaders1 ); -#ifndef _FINAL +#ifndef FINAL_BUILD shaderFiles2 = FS_ListFiles( "shaders/test", ".shader", &numShaders2 ); #endif @@ -92,7 +92,7 @@ void CM_LoadShaderFiles( void ) return; } -#ifndef _FINAL +#ifndef FINAL_BUILD numShaders = numShaders1 + numShaders2; #else numShaders = numShaders1; @@ -115,7 +115,7 @@ void CM_LoadShaderFiles( void ) Com_Error( ERR_DROP, "Couldn't load %s", filename ); } } -#ifndef _FINAL +#ifndef FINAL_BUILD for ( ; i < numShaders; i++ ) { char filename[MAX_QPATH]; @@ -143,7 +143,7 @@ void CM_LoadShaderFiles( void ) // free up memory FS_FreeFileList( shaderFiles1 ); -#ifndef _FINAL +#ifndef FINAL_BUILD FS_FreeFileList( shaderFiles2 ); #endif } @@ -191,7 +191,7 @@ CM_LoadShaderText ================== */ -void CM_LoadShaderText(bool forceReload) +void CM_LoadShaderText(qboolean forceReload) { if(forceReload) { @@ -311,7 +311,7 @@ void SV_ParseMaterial( CCMShader *shader, const char **text ) ParseVector =============== */ -qboolean CM_ParseVector( CCMShader *shader, const char **text, int count, float *v ) +static qboolean CM_ParseVector( CCMShader *shader, const char **text, int count, float *v ) { char *token; int i; @@ -356,7 +356,7 @@ It is designed to *NOT* load any image files and not require any of the renderer be initialised. ================= */ -void CM_ParseShader( CCMShader *shader, const char **text ) +static void CM_ParseShader( CCMShader *shader, const char **text ) { char *token; diff --git a/CODE-mp/qcommon/common.cpp b/CODE-mp/qcommon/common.cpp index b9d2e9d..f412a42 100644 --- a/CODE-mp/qcommon/common.cpp +++ b/CODE-mp/qcommon/common.cpp @@ -3,7 +3,7 @@ #include "../game/q_shared.h" #include "qcommon.h" #include "strip.h" -#include +#include "../qcommon/game_version.h" #ifndef __linux__ #include #endif @@ -278,6 +278,7 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { va_end (argptr); if ( code != ERR_DISCONNECT ) { + Cvar_Get("com_errorMessage", "", CVAR_ROM); //give com_errorMessage a default so it won't come back to life after a resetDefaults Cvar_Set("com_errorMessage", com_errorMessage); } @@ -882,7 +883,7 @@ void *Z_Malloc(int iSize, memtag_t eTag, qboolean bZeroit /* = qfalse */) continue; // we've dropped at least one sound, so try again with the malloc } - +#ifndef DEDICATED // ditch any image_t's (and associated GL memory) not used on this level... // extern qboolean RE_RegisterImages_LevelLoadEnd(void); @@ -891,7 +892,7 @@ void *Z_Malloc(int iSize, memtag_t eTag, qboolean bZeroit /* = qfalse */) gbMemFreeupOccured = qtrue; continue; // we've dropped at least one image, so try again with the malloc } - +#endif // ditch the model-binaries cache... (must be getting desperate here!) // @@ -1942,11 +1943,11 @@ Hunk_Trash ================= */ void Hunk_Trash( void ) { + return; +#if 0 int length, i, rnd; char *buf, value; - return; - if ( s_hunkData == NULL ) return; @@ -1974,6 +1975,7 @@ void Hunk_Trash( void ) { buf[rnd+i] ^= value; } } +#endif } /* @@ -2445,6 +2447,10 @@ static void Com_WriteCDKey( const char *filename, const char *ikey ) { #endif // USE_CD_KEY +#ifdef MEM_DEBUG + void SH_Register(void); +#endif + /* ================= Com_Init @@ -2485,7 +2491,7 @@ void Com_Init( char *commandLine ) { Com_InitJournaling(); - Cbuf_AddText ("exec default.cfg\n"); + Cbuf_AddText ("exec mpdefault.cfg\n"); // skip the jk2mpconfig.cfg if "safe" is on the command line if ( !Com_SafeMode() ) { @@ -2501,7 +2507,7 @@ void Com_Init( char *commandLine ) { // get dedicated here for proper hunk megs initialization #ifdef DEDICATED - com_dedicated = Cvar_Get ("dedicated", "1", CVAR_ROM); + com_dedicated = Cvar_Get ("dedicated", "2", CVAR_ROM); #else com_dedicated = Cvar_Get ("dedicated", "0", CVAR_LATCH); #endif @@ -2564,10 +2570,10 @@ void Com_Init( char *commandLine ) { com_version = Cvar_Get ("version", s, CVAR_ROM | CVAR_SERVERINFO ); SP_Init(); - +#ifndef __linux__ extern void QuickMemTest(void); QuickMemTest(); - +#endif Sys_Init(); Netchan_Init( Com_Milliseconds() & 0xffff ); // pick a port value that should be nice and random VM_Init(); @@ -2588,7 +2594,6 @@ void Com_Init( char *commandLine ) { // add + commands from command line if ( !Com_AddStartupCommands() ) { - #ifdef FINAL_BUILD // if the user didn't give any commands, run default action if ( !com_dedicated->integer ) { @@ -2599,7 +2604,6 @@ void Com_Init( char *commandLine ) { // Cvar_Set( "nextmap", "cinematic intro.RoQ" ); // } } - #endif } // start in full screen ui mode @@ -2610,6 +2614,10 @@ void Com_Init( char *commandLine ) { // make sure single player is off by default Cvar_Set("ui_singlePlayerActive", "0"); +#ifdef MEM_DEBUG + SH_Register(); +#endif + com_fullyInitialized = qtrue; Com_Printf ("--- Common Initialization Complete ---\n"); @@ -2841,6 +2849,7 @@ try if ( !com_dedicated->integer ) { CL_Init(); Sys_ShowConsole( com_viewlog->integer, qfalse ); + CL_StartHunkUsers(); //fire up the UI! } else { CL_Shutdown(); Sys_ShowConsole( 1, qtrue ); @@ -2926,10 +2935,15 @@ try Com_Shutdown ================= */ -void Com_Shutdown (void) { +void MSG_shutdownHuffman(); +void Com_Shutdown (void) +{ + CM_ClearMap(); + if (logfile) { FS_FCloseFile (logfile); logfile = 0; + com_logfile->integer = 0;//don't open up the log file again!! } if ( com_journalFile ) { @@ -2937,6 +2951,16 @@ void Com_Shutdown (void) { com_journalFile = 0; } + MSG_shutdownHuffman(); +/* + // Only used for testing changes to huffman frequency table when tuning. + { + extern float Huff_GetCR(void); + char mess[256]; + sprintf(mess,"Eff. CR = %f\n",Huff_GetCR()); + OutputDebugString(mess); + } +*/ } #if !( defined __linux__ || defined __FreeBSD__ ) // r010123 - include FreeBSD diff --git a/CODE-mp/qcommon/cvar.cpp b/CODE-mp/qcommon/cvar.cpp index c7adddc..323f3f0 100644 --- a/CODE-mp/qcommon/cvar.cpp +++ b/CODE-mp/qcommon/cvar.cpp @@ -429,7 +429,14 @@ void Cvar_SetCheatState( void ) { // set all default vars to the safe value for ( var = cvar_vars ; var ; var = var->next ) { - if ( var->flags & CVAR_CHEAT && !com_developer->integer ) { + if ( var->flags & CVAR_CHEAT ) { + // the CVAR_LATCHED|CVAR_CHEAT vars might escape the reset here + // because of a different var->latchedString + if (var->latchedString) + { + Z_Free(var->latchedString); + var->latchedString = NULL; + } if (strcmp(var->resetString,var->string)) { Cvar_Set( var->name, var->resetString ); } @@ -669,6 +676,12 @@ void Cvar_List_f( void ) { i = 0; for (var = cvar_vars ; var ; var = var->next, i++) { + // Dont show internal cvars + if ( var->flags & CVAR_INTERNAL ) + { + continue; + } + if (match && !Com_Filter(match, var->name, qfalse)) continue; if (var->flags & CVAR_SERVERINFO) { @@ -889,7 +902,7 @@ Reads in all archived cvars ============ */ void Cvar_Init (void) { - cvar_cheats = Cvar_Get("sv_cheats", "1", CVAR_ROM | CVAR_SYSTEMINFO ); + cvar_cheats = Cvar_Get("sv_cheats", "0", CVAR_ROM | CVAR_SYSTEMINFO ); Cmd_AddCommand ("toggle", Cvar_Toggle_f); Cmd_AddCommand ("set", Cvar_Set_f); diff --git a/CODE-mp/qcommon/disablewarnings.h b/CODE-mp/qcommon/disablewarnings.h index c7eaf4a..7f8c6cc 100644 --- a/CODE-mp/qcommon/disablewarnings.h +++ b/CODE-mp/qcommon/disablewarnings.h @@ -19,7 +19,7 @@ #pragma warning(disable : 4305) // truncation from const double to float #pragma warning(disable : 4310) // cast truncates constant value #pragma warning(disable : 4503) // decorated name length truncated -#pragma warning(disable: 4505) // unreferenced local function has been removed +//#pragma warning(disable: 4505)!!!remove these to reduce vm size!! // unreferenced local function has been removed #pragma warning(disable : 4511) //copy ctor could not be genned #pragma warning(disable : 4512) //assignment op could not be genned #pragma warning(disable : 4514) // unreffed inline removed diff --git a/CODE-mp/qcommon/files.cpp b/CODE-mp/qcommon/files.cpp index a9e1e6b..c3442d1 100644 --- a/CODE-mp/qcommon/files.cpp +++ b/CODE-mp/qcommon/files.cpp @@ -320,6 +320,10 @@ qboolean FS_PakIsPure( pack_t *pack ) { int i; if ( fs_numServerPaks ) { + // NOTE TTimo we are matching checksums without checking the pak names + // this means you can have the same pk3 as the server under a different name, you will still get through sv_pure validation + // (what happens when two pk3's have the same checkums? is it a likely situation?) + // also, if there's a wrong checksumed pk3 and autodownload is enabled, the checksum will be appended to the downloaded pk3 name for ( i = 0 ; i < fs_numServerPaks ; i++ ) { // FIXME: also use hashed file names if ( pack->checksum == fs_serverPaks[i] ) { @@ -1052,6 +1056,7 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF if ( Q_stricmp(filename + l - 7, ".shader") != 0 && Q_stricmp(filename + l - 4, ".txt") != 0 && Q_stricmp(filename + l - 4, ".cfg") != 0 && + Q_stricmp(filename + l - 4, ".fcf") != 0 && Q_stricmp(filename + l - 7, ".config") != 0 && strstr(filename, "levelshots") == NULL && Q_stricmp(filename + l - 4, ".bot") != 0 && @@ -1105,13 +1110,15 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF Com_Printf( "FS_FOpenFileRead: %s (found in '%s')\n", filename, pak->pakFilename ); } -#ifdef _DEBUG +#ifndef DEDICATED +#ifndef FINAL_BUILD // Check for unprecached files when in game but not in the menus if((cls.state == CA_ACTIVE) && !(cls.keyCatchers & KEYCATCH_UI)) { Com_Printf(S_COLOR_YELLOW "WARNING: File %s not precached\n", filename); } #endif +#endif // DEDICATED return zfi->cur_file_info.uncompressed_size; } pakFile = pakFile->next; @@ -1130,6 +1137,7 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF if ( fs_restrict->integer || fs_numServerPaks ) { if ( Q_stricmp( filename + l - 4, ".cfg" ) // for config files + && Q_stricmp( filename + l - 4, ".fcf" ) // force configuration files && Q_stricmp( filename + l - 5, ".menu" ) // menu files && Q_stricmp( filename + l - 5, ".game" ) // menu files && Q_stricmp( filename + l - strlen(demoExt), demoExt ) // menu files @@ -1147,6 +1155,7 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF } if ( Q_stricmp( filename + l - 4, ".cfg" ) // for config files + && Q_stricmp( filename + l - 4, ".fcf" ) // force configuration files && Q_stricmp( filename + l - 5, ".menu" ) // menu files && Q_stricmp( filename + l - 5, ".game" ) // menu files && Q_stricmp( filename + l - strlen(demoExt), demoExt ) // menu files @@ -1169,13 +1178,15 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF copypath = FS_BuildOSPath( fs_basepath->string, dir->gamedir, filename ); FS_CopyFile( netpath, copypath ); } -#ifdef _DEBUG +#ifndef DEDICATED +#ifndef FINAL_BUILD // Check for unprecached files when in game but not in the menus if((cls.state == CA_ACTIVE) && !(cls.keyCatchers & KEYCATCH_UI)) { Com_Printf(S_COLOR_YELLOW "WARNING: File %s not precached\n", filename); } #endif +#endif // dedicated return FS_filelength (*file); } } @@ -1918,9 +1929,14 @@ char **FS_ListFilteredFiles( const char *path, const char *extension, char *filt char *name; // don't scan directories for files if we are pure or restricted - if ( fs_restrict->integer || fs_numServerPaks ) { - continue; - } else { + if ( (fs_restrict->integer || fs_numServerPaks) && + (!extension || Q_stricmp(extension, "fcf") || fs_restrict->integer) ) + { + //rww - allow scanning for fcf files outside of pak even if pure + continue; + } + else + { netpath = FS_BuildOSPath( search->dir->path, search->dir->gamedir, path ); sysFiles = Sys_ListFiles( netpath, extension, filter, &numSysFiles, qfalse ); for ( i = 0 ; i < numSysFiles ; i++ ) { @@ -2529,6 +2545,8 @@ qboolean FS_idPak( char *pak, char *base ) { ================ FS_ComparePaks +if dlstring == qtrue + Returns a list of pak files that we should download from the server. They all get stored in the current gamedir and an FS_Restart will be fired up after we download them all. @@ -2540,9 +2558,14 @@ static int fs_numServerReferencedPaks; static int fs_serverReferencedPaks[MAX_SEARCH_PATHS]; static char *fs_serverReferencedPakNames[MAX_SEARCH_PATHS]; +---------------- +dlstring == qfalse + +we are not interested in a download string format, we want something human-readable +(this is used for diagnostics while connecting to a pure server) ================ */ -qboolean FS_ComparePaks( char *neededpaks, int len ) { +qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) { searchpath_t *sp; qboolean havepak, badchecksum; int i; @@ -2572,30 +2595,42 @@ qboolean FS_ComparePaks( char *neededpaks, int len ) { if ( !havepak && fs_serverReferencedPakNames[i] && *fs_serverReferencedPakNames[i] ) { // Don't got it - - // Remote name - Q_strcat( neededpaks, len, "@"); - Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] ); - Q_strcat( neededpaks, len, ".pk3" ); - - // Local name - Q_strcat( neededpaks, len, "@"); - // Do we have one with the same name? - if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) ) { - char st[MAX_ZPATH]; - // We already have one called this, we need to download it to another name - // Make something up with the checksum in it - Com_sprintf( st, sizeof( st ), "%s.%08x.pk3", fs_serverReferencedPakNames[i], fs_serverReferencedPaks[i] ); - Q_strcat( neededpaks, len, st ); - } else { + + if (dlstring) + { + // Remote name + Q_strcat( neededpaks, len, "@"); Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] ); Q_strcat( neededpaks, len, ".pk3" ); + + // Local name + Q_strcat( neededpaks, len, "@"); + // Do we have one with the same name? + if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) ) { + char st[MAX_ZPATH]; + // We already have one called this, we need to download it to another name + // Make something up with the checksum in it + Com_sprintf( st, sizeof( st ), "%s.%08x.pk3", fs_serverReferencedPakNames[i], fs_serverReferencedPaks[i] ); + Q_strcat( neededpaks, len, st ); + } else { + Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] ); + Q_strcat( neededpaks, len, ".pk3" ); + } + } + else + { + Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] ); + Q_strcat( neededpaks, len, ".pk3" ); + // Do we have one with the same name? + if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) ) + { + Q_strcat( neededpaks, len, " (local file exists with wrong checksum)"); + } + Q_strcat( neededpaks, len, "\n"); } } } - if ( *neededpaks ) { - Com_Printf("Need paks: %s\n", neededpaks); return qtrue; } @@ -3173,8 +3208,8 @@ void FS_InitFilesystem( void ) { // if we can't find default.cfg, assume that the paths are // busted and error out now, rather than getting an unreadable // graphics screen when the font fails to load - if ( FS_ReadFile( "default.cfg", NULL ) <= 0 ) { - Com_Error( ERR_FATAL, "Couldn't load default.cfg" ); + if ( FS_ReadFile( "mpdefault.cfg", NULL ) <= 0 ) { + Com_Error( ERR_FATAL, "Couldn't load mpdefault.cfg" ); // bk001208 - SafeMode see below, FIXME? } @@ -3210,7 +3245,7 @@ void FS_Restart( int checksumFeed ) { // if we can't find default.cfg, assume that the paths are // busted and error out now, rather than getting an unreadable // graphics screen when the font fails to load - if ( FS_ReadFile( "default.cfg", NULL ) <= 0 ) { + if ( FS_ReadFile( "mpdefault.cfg", NULL ) <= 0 ) { // this might happen when connecting to a pure server not using BASEGAME/pak0.pk3 // (for instance a TA demo server) if (lastValidBase[0]) { @@ -3224,7 +3259,7 @@ void FS_Restart( int checksumFeed ) { Com_Error( ERR_DROP, "Invalid game folder\n" ); return; } - Com_Error( ERR_FATAL, "Couldn't load default.cfg" ); + Com_Error( ERR_FATAL, "Couldn't load mpdefault.cfg" ); } // bk010116 - new check before safeMode @@ -3293,6 +3328,10 @@ int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) { return -1; } + if (!f) { + return r; + } + if ( *f ) { if (fsh[*f].zipFile == qtrue) { fsh[*f].baseOffset = unztell(fsh[*f].handleFiles.file.z); diff --git a/CODE-mp/qcommon/files.org b/CODE-mp/qcommon/files.org new file mode 100644 index 0000000..df25f3d --- /dev/null +++ b/CODE-mp/qcommon/files.org @@ -0,0 +1,3328 @@ +/***************************************************************************** + * name: files.c + * + * desc: handle based filesystem for Quake III Arena + * + * $Archive: /MissionPack/code/qcommon/files.c $ + * $Author: Zaphod $ + * $Revision: 81 $ + * $Modtime: 5/30/01 2:31p $ + * $Date: 5/30/01 2:31p $ + * + *****************************************************************************/ + + +#include "../game/q_shared.h" +#include "../client/client.h" +#include "qcommon.h" +#include "unzip.h" + +/* +============================================================================= + +QUAKE3 FILESYSTEM + +All of Quake's data access is through a hierarchical file system, but the contents of +the file system can be transparently merged from several sources. + +A "qpath" is a reference to game file data. MAX_ZPATH is 256 characters, which must include +a terminating zero. "..", "\\", and ":" are explicitly illegal in qpaths to prevent any +references outside the quake directory system. + +The "base path" is the path to the directory holding all the game directories and usually +the executable. It defaults to ".", but can be overridden with a "+set fs_basepath c:\quake3" +command line to allow code debugging in a different directory. Basepath cannot +be modified at all after startup. Any files that are created (demos, screenshots, +etc) will be created reletive to the base path, so base path should usually be writable. + +The "cd path" is the path to an alternate hierarchy that will be searched if a file +is not located in the base path. A user can do a partial install that copies some +data to a base path created on their hard drive and leave the rest on the cd. Files +are never writen to the cd path. It defaults to a value set by the installer, like +"e:\quake3", but it can be overridden with "+set ds_cdpath g:\quake3". + +If a user runs the game directly from a CD, the base path would be on the CD. This +should still function correctly, but all file writes will fail (harmlessly). + +The "home path" is the path used for all write access. On win32 systems we have "base path" +== "home path", but on *nix systems the base installation is usually readonly, and +"home path" points to ~/.q3a or similar + +The user can also install custom mods and content in "home path", so it should be searched +along with "home path" and "cd path" for game content. + + +The "base game" is the directory under the paths where data comes from by default, and +can be either "base" or "demo". + +The "current game" may be the same as the base game, or it may be the name of another +directory under the paths that should be searched for files before looking in the base game. +This is the basis for addons. + +Clients automatically set the game directory after receiving a gamestate from a server, +so only servers need to worry about +set fs_game. + +No other directories outside of the base game and current game will ever be referenced by +filesystem functions. + +To save disk space and speed loading, directory trees can be collapsed into zip files. +The files use a ".pk3" extension to prevent users from unzipping them accidentally, but +otherwise the are simply normal uncompressed zip files. A game directory can have multiple +zip files of the form "pak0.pk3", "pak1.pk3", etc. Zip files are searched in decending order +from the highest number to the lowest, and will always take precedence over the filesystem. +This allows a pk3 distributed as a patch to override all existing data. + +Because we will have updated executables freely available online, there is no point to +trying to restrict demo / oem versions of the game with code changes. Demo / oem versions +should be exactly the same executables as release versions, but with different data that +automatically restricts where game media can come from to prevent add-ons from working. + +After the paths are initialized, quake will look for the product.txt file. If not +found and verified, the game will run in restricted mode. In restricted mode, only +files contained in demoq3/pak0.pk3 will be available for loading, and only if the zip header is +verified to not have been modified. A single exception is made for jk2mpconfig.cfg. Files +can still be written out in restricted mode, so screenshots and demos are allowed. +Restricted mode can be tested by setting "+set fs_restrict 1" on the command line, even +if there is a valid product.txt under the basepath or cdpath. + +If not running in restricted mode, and a file is not found in any local filesystem, +an attempt will be made to download it and save it under the base path. + +If the "fs_copyfiles" cvar is set to 1, then every time a file is sourced from the cd +path, it will be copied over to the base path. This is a development aid to help build +test releases and to copy working sets over slow network links. + +File search order: when FS_FOpenFileRead gets called it will go through the fs_searchpaths +structure and stop on the first successful hit. fs_searchpaths is built with successive +calls to FS_AddGameDirectory + +Additionaly, we search in several subdirectories: +current game is the current mode +base game is a variable to allow mods based on other mods +(such as base + missionpack content combination in a mod for instance) +BASEGAME is the hardcoded base game ("base") + +e.g. the qpath "sound/newstuff/test.wav" would be searched for in the following places: + +home path + current game's zip files +home path + current game's directory +base path + current game's zip files +base path + current game's directory +cd path + current game's zip files +cd path + current game's directory + +home path + base game's zip file +home path + base game's directory +base path + base game's zip file +base path + base game's directory +cd path + base game's zip file +cd path + base game's directory + +home path + BASEGAME's zip file +home path + BASEGAME's directory +base path + BASEGAME's zip file +base path + BASEGAME's directory +cd path + BASEGAME's zip file +cd path + BASEGAME's directory + +server download, to be written to home path + current game's directory + + +The filesystem can be safely shutdown and reinitialized with different +basedir / cddir / game combinations, but all other subsystems that rely on it +(sound, video) must also be forced to restart. + +Because the same files are loaded by both the clip model (CM_) and renderer (TR_) +subsystems, a simple single-file caching scheme is used. The CM_ subsystems will +load the file with a request to cache. Only one file will be kept cached at a time, +so any models that are going to be referenced by both subsystems should alternate +between the CM_ load function and the ref load function. + +TODO: A qpath that starts with a leading slash will always refer to the base game, even if another +game is currently active. This allows character models, skins, and sounds to be downloaded +to a common directory no matter which game is active. + +How to prevent downloading zip files? +Pass pk3 file names in systeminfo, and download before FS_Restart()? + +Aborting a download disconnects the client from the server. + +How to mark files as downloadable? Commercial add-ons won't be downloadable. + +Non-commercial downloads will want to download the entire zip file. +the game would have to be reset to actually read the zip in + +Auto-update information + +Path separators + +Casing + + separate server gamedir and client gamedir, so if the user starts + a local game after having connected to a network game, it won't stick + with the network game. + + allow menu options for game selection? + +Read / write config to floppy option. + +Different version coexistance? + +When building a pak file, make sure a jk2mpconfig.cfg isn't present in it, +or configs will never get loaded from disk! + + todo: + + downloading (outside fs?) + game directory passing and restarting + +============================================================================= + +*/ + +#define BASEGAME "base" +#define DEMOGAME "demo" + +// every time a new demo pk3 file is built, this checksum must be updated. +// the easiest way to get it is to just run the game and see what it spits out +#define DEMO_PAK_CHECKSUM 437558517u + +// if this is defined, the executable positively won't work with any paks other +// than the demo pak, even if productid is present. This is only used for our +// last demo release to prevent the mac and linux users from using the demo +// executable with the production windows pak before the mac/linux products +// hit the shelves a little later +// NOW defined in build files +//#define PRE_RELEASE_TADEMO + +#define MAX_ZPATH 256 +#define MAX_SEARCH_PATHS 4096 +#define MAX_FILEHASH_SIZE 1024 + +typedef struct fileInPack_s { + char *name; // name of the file + unsigned long pos; // file info position in zip + struct fileInPack_s* next; // next file in the hash +} fileInPack_t; + +typedef struct { + char pakFilename[MAX_OSPATH]; // c:\quake3\base\pak0.pk3 + char pakBasename[MAX_OSPATH]; // pak0 + char pakGamename[MAX_OSPATH]; // base + unzFile handle; // handle to zip file + int checksum; // regular checksum + int pure_checksum; // checksum for pure + int numfiles; // number of files in pk3 + int referenced; // referenced file flags + int hashSize; // hash table size (power of 2) + fileInPack_t* *hashTable; // hash table + fileInPack_t* buildBuffer; // buffer with the filenames etc. +} pack_t; + +typedef struct { + char path[MAX_OSPATH]; // c:\jk2 + char gamedir[MAX_OSPATH]; // base +} directory_t; + +typedef struct searchpath_s { + struct searchpath_s *next; + + pack_t *pack; // only one of pack / dir will be non NULL + directory_t *dir; +} searchpath_t; + +static char fs_gamedir[MAX_OSPATH]; // this will be a single file name with no separators +static cvar_t *fs_debug; +static cvar_t *fs_homepath; +static cvar_t *fs_basepath; +static cvar_t *fs_basegame; +static cvar_t *fs_cdpath; +static cvar_t *fs_copyfiles; +static cvar_t *fs_gamedirvar; +static cvar_t *fs_restrict; +static searchpath_t *fs_searchpaths; +static int fs_readCount; // total bytes read +static int fs_loadCount; // total files read +static int fs_loadStack; // total files in memory +static int fs_packFiles; // total number of files in packs + +static int fs_fakeChkSum; +static int fs_checksumFeed; + +typedef union qfile_gus { + FILE* o; + unzFile z; +} qfile_gut; + +typedef struct qfile_us { + qfile_gut file; + qboolean unique; +} qfile_ut; + +typedef struct { + qfile_ut handleFiles; + qboolean handleSync; + int baseOffset; + int fileSize; + int zipFilePos; + qboolean zipFile; + qboolean streamed; + char name[MAX_ZPATH]; +} fileHandleData_t; + +static fileHandleData_t fsh[MAX_FILE_HANDLES]; + +// never load anything from pk3 files that are not present at the server when pure +static int fs_numServerPaks; +static int fs_serverPaks[MAX_SEARCH_PATHS]; // checksums +static char *fs_serverPakNames[MAX_SEARCH_PATHS]; // pk3 names + +// only used for autodownload, to make sure the client has at least +// all the pk3 files that are referenced at the server side +static int fs_numServerReferencedPaks; +static int fs_serverReferencedPaks[MAX_SEARCH_PATHS]; // checksums +static char *fs_serverReferencedPakNames[MAX_SEARCH_PATHS]; // pk3 names + +// last valid game folder used +char lastValidBase[MAX_OSPATH]; +char lastValidGame[MAX_OSPATH]; + +// productId: This file is copyright 2000 Raven Software, and may not be duplicated except during a licensed installation of the full commercial version of Star Wars: Jedi Outcast +static byte fs_scrambledProductId[165] = { + 42, 143, 149, 190, 10, 197, 225, 133, 243, 63, 189, 182, 226, 56, 143, 17, 215, 37, 197, 218, 50, 103, 24, 235, 246, 191, 180, 149, 160, 170, 230, + 52, 176, 231, 15, 194, 236, 247, 159, 168, 132, 154, 24, 133, 67, 85, 36, 97, 99, 86, 117, 189, 212, 156, 236, 153, 68, 10, 196, 241, 39, +219, 156, 88, 93, 198, 200, 232, 142, 67, 45, 209, 53, 186, 228, 241, 162, 127, 213, 83, 7, 121, 11, 93, 123, 243, 148, 240, 229, 42, 42, + 6, 215, 239, 112, 120, 240, 244, 104, 12, 38, 47, 201, 253, 223, 208, 154, 69, 141, 157, 32, 117, 166, 146, 236, 59, 15, 223, 52, 89, 133, + 64, 201, 56, 119, 25, 211, 152, 159, 11, 92, 59, 207, 81, 123, 0, 121, 241, 116, 42, 36, 251, 51, 149, 79, 165, 12, 106, 187, 225, 203, + 99, 102, 69, 97, 81, 27, 107, 95, 164, 42, 36, 189, 94, 126 +}; + +#ifdef FS_MISSING +FILE* missingFiles = NULL; +#endif + +/* +============== +FS_Initialized +============== +*/ + +qboolean FS_Initialized() { + return (qboolean)(fs_searchpaths != NULL); +} + +/* +================= +FS_PakIsPure +================= +*/ +qboolean FS_PakIsPure( pack_t *pack ) { + int i; + + if ( fs_numServerPaks ) { + for ( i = 0 ; i < fs_numServerPaks ; i++ ) { + // FIXME: also use hashed file names + if ( pack->checksum == fs_serverPaks[i] ) { + return qtrue; // on the aproved list + } + } + return qfalse; // not on the pure server pak list + } + return qtrue; +} + + +/* +================= +FS_LoadStack +return load stack +================= +*/ +int FS_LoadStack() +{ + return fs_loadStack; +} + +/* +================ +return a hash value for the filename +================ +*/ +static long FS_HashFileName( const char *fname, int hashSize ) { + int i; + long hash; + char letter; + + hash = 0; + i = 0; + while (fname[i] != '\0') { + letter = tolower(fname[i]); + if (letter =='.') break; // don't include extension + if (letter =='\\') letter = '/'; // damn path names + if (letter == PATH_SEP) letter = '/'; // damn path names + hash+=(long)(letter)*(i+119); + i++; + } + hash = (hash ^ (hash >> 10) ^ (hash >> 20)); + hash &= (hashSize-1); + return hash; +} + +static fileHandle_t FS_HandleForFile(void) { + int i; + + for ( i = 1 ; i < MAX_FILE_HANDLES ; i++ ) { + if ( fsh[i].handleFiles.file.o == NULL ) { + return i; + } + } + Com_Error( ERR_DROP, "FS_HandleForFile: none free" ); + return 0; +} + +static FILE *FS_FileForHandle( fileHandle_t f ) { + if ( f < 0 || f > MAX_FILE_HANDLES ) { + Com_Error( ERR_DROP, "FS_FileForHandle: out of reange" ); + } + if (fsh[f].zipFile == qtrue) { + Com_Error( ERR_DROP, "FS_FileForHandle: can't get FILE on zip file" ); + } + if ( ! fsh[f].handleFiles.file.o ) { + Com_Error( ERR_DROP, "FS_FileForHandle: NULL" ); + } + + return fsh[f].handleFiles.file.o; +} + +void FS_ForceFlush( fileHandle_t f ) { + FILE *file; + + file = FS_FileForHandle(f); + setvbuf( file, NULL, _IONBF, 0 ); +} + +/* +================ +FS_filelength + +If this is called on a non-unique FILE (from a pak file), +it will return the size of the pak file, not the expected +size of the file. +================ +*/ +int FS_filelength( fileHandle_t f ) { + int pos; + int end; + FILE* h; + + h = FS_FileForHandle(f); + pos = ftell (h); + fseek (h, 0, SEEK_END); + end = ftell (h); + fseek (h, pos, SEEK_SET); + + return end; +} + +/* +==================== +FS_ReplaceSeparators + +Fix things up differently for win/unix/mac +==================== +*/ +static void FS_ReplaceSeparators( char *path ) { + char *s; + + for ( s = path ; *s ; s++ ) { + if ( *s == '/' || *s == '\\' ) { + *s = PATH_SEP; + } + } +} + +/* +=================== +FS_BuildOSPath + +Qpath may have either forward or backwards slashes +=================== +*/ +char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ) { + char temp[MAX_OSPATH]; + static char ospath[2][MAX_OSPATH]; + static int toggle; + + toggle ^= 1; // flip-flop to allow two returns without clash + + if( !game || !game[0] ) { + game = fs_gamedir; + } + + Com_sprintf( temp, sizeof(temp), "/%s/%s", game, qpath ); + FS_ReplaceSeparators( temp ); + Com_sprintf( ospath[toggle], sizeof( ospath[0] ), "%s%s", base, temp ); + + return ospath[toggle]; +} + + +/* +============ +FS_CreatePath + +Creates any directories needed to store the given filename +============ +*/ +static qboolean FS_CreatePath (char *OSPath) { + char *ofs; + + // make absolutely sure that it can't back up the path + // FIXME: is c: allowed??? + if ( strstr( OSPath, ".." ) || strstr( OSPath, "::" ) ) { + Com_Printf( "WARNING: refusing to create relative path \"%s\"\n", OSPath ); + return qtrue; + } + + for (ofs = OSPath+1 ; *ofs ; ofs++) { + if (*ofs == PATH_SEP) { + // create the directory + *ofs = 0; + Sys_Mkdir (OSPath); + *ofs = PATH_SEP; + } + } + return qfalse; +} + +/* +================= +FS_CopyFile + +Copy a fully specified file from one place to another +================= +*/ +static void FS_CopyFile( char *fromOSPath, char *toOSPath ) { + FILE *f; + int len; + byte *buf; + + Com_Printf( "copy %s to %s\n", fromOSPath, toOSPath ); + + if (strstr(fromOSPath, "journal.dat") || strstr(fromOSPath, "journaldata.dat")) { + Com_Printf( "Ignoring journal files\n"); + return; + } + + f = fopen( fromOSPath, "rb" ); + if ( !f ) { + return; + } + fseek (f, 0, SEEK_END); + len = ftell (f); + fseek (f, 0, SEEK_SET); + + // we are using direct malloc instead of Z_Malloc here, so it + // probably won't work on a mac... Its only for developers anyway... + buf = (unsigned char *)malloc( len ); + if (fread( buf, 1, len, f ) != len) + Com_Error( ERR_FATAL, "Short read in FS_Copyfiles()\n" ); + fclose( f ); + + if( FS_CreatePath( toOSPath ) ) { + return; + } + + f = fopen( toOSPath, "wb" ); + if ( !f ) { + return; + } + if (fwrite( buf, 1, len, f ) != len) + Com_Error( ERR_FATAL, "Short write in FS_Copyfiles()\n" ); + fclose( f ); + free( buf ); +} + +/* +=========== +FS_Remove + +=========== +*/ +static void FS_Remove( const char *osPath ) { + remove( osPath ); +} + +/* +================ +FS_FileExists + +Tests if the file exists in the current gamedir, this DOES NOT +search the paths. This is to determine if opening a file to write +(which always goes into the current gamedir) will cause any overwrites. +NOTE TTimo: this goes with FS_FOpenFileWrite for opening the file afterwards +================ +*/ +qboolean FS_FileExists( const char *file ) +{ + FILE *f; + char *testpath; + + testpath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, file ); + + f = fopen( testpath, "rb" ); + if (f) { + fclose( f ); + return qtrue; + } + return qfalse; +} + +/* +================ +FS_SV_FileExists + +Tests if the file exists +================ +*/ +qboolean FS_SV_FileExists( const char *file ) +{ + FILE *f; + char *testpath; + + testpath = FS_BuildOSPath( fs_homepath->string, file, ""); + testpath[strlen(testpath)-1] = '\0'; + + f = fopen( testpath, "rb" ); + if (f) { + fclose( f ); + return qtrue; + } + return qfalse; +} + + +/* +=========== +FS_SV_FOpenFileWrite + +=========== +*/ +fileHandle_t FS_SV_FOpenFileWrite( const char *filename ) { + char *ospath; + fileHandle_t f; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + ospath = FS_BuildOSPath( fs_homepath->string, filename, "" ); + ospath[strlen(ospath)-1] = '\0'; + + f = FS_HandleForFile(); + fsh[f].zipFile = qfalse; + + if ( fs_debug->integer ) { + Com_Printf( "FS_SV_FOpenFileWrite: %s\n", ospath ); + } + + if( FS_CreatePath( ospath ) ) { + return 0; + } + + Com_DPrintf( "writing to: %s\n", ospath ); + fsh[f].handleFiles.file.o = fopen( ospath, "wb" ); + + Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) ); + + fsh[f].handleSync = qfalse; + if (!fsh[f].handleFiles.file.o) { + f = 0; + } + return f; +} + +/* +=========== +FS_SV_FOpenFileRead +search for a file somewhere below the home path, base path or cd path +we search in that order, matching FS_SV_FOpenFileRead order +=========== +*/ +int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ) { + char *ospath; + fileHandle_t f = 0; // bk001129 - from cvs1.17 + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + f = FS_HandleForFile(); + fsh[f].zipFile = qfalse; + + Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) ); + + // don't let sound stutter + S_ClearSoundBuffer(); + + // search homepath + ospath = FS_BuildOSPath( fs_homepath->string, filename, "" ); + // remove trailing slash + ospath[strlen(ospath)-1] = '\0'; + + if ( fs_debug->integer ) { + Com_Printf( "FS_SV_FOpenFileRead (fs_homepath): %s\n", ospath ); + } + + fsh[f].handleFiles.file.o = fopen( ospath, "rb" ); + fsh[f].handleSync = qfalse; + if (!fsh[f].handleFiles.file.o) + { + // NOTE TTimo on non *nix systems, fs_homepath == fs_basepath, might want to avoid + if (Q_stricmp(fs_homepath->string,fs_basepath->string)) + { + // search basepath + ospath = FS_BuildOSPath( fs_basepath->string, filename, "" ); + ospath[strlen(ospath)-1] = '\0'; + + if ( fs_debug->integer ) + { + Com_Printf( "FS_SV_FOpenFileRead (fs_basepath): %s\n", ospath ); + } + + fsh[f].handleFiles.file.o = fopen( ospath, "rb" ); + fsh[f].handleSync = qfalse; + + if ( !fsh[f].handleFiles.file.o ) + { + f = 0; + } + } + } + + if (!fsh[f].handleFiles.file.o) { + // search cd path + ospath = FS_BuildOSPath( fs_cdpath->string, filename, "" ); + ospath[strlen(ospath)-1] = '\0'; + + if (fs_debug->integer) + { + Com_Printf( "FS_SV_FOpenFileRead (fs_cdpath) : %s\n", ospath ); + } + + fsh[f].handleFiles.file.o = fopen( ospath, "rb" ); + fsh[f].handleSync = qfalse; + + if( !fsh[f].handleFiles.file.o ) { + f = 0; + } + } + + *fp = f; + if (f) { + return FS_filelength(f); + } + return 0; +} + + +/* +=========== +FS_SV_Rename + +=========== +*/ +void FS_SV_Rename( const char *from, const char *to ) { + char *from_ospath, *to_ospath; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + // don't let sound stutter + S_ClearSoundBuffer(); + + from_ospath = FS_BuildOSPath( fs_homepath->string, from, "" ); + to_ospath = FS_BuildOSPath( fs_homepath->string, to, "" ); + from_ospath[strlen(from_ospath)-1] = '\0'; + to_ospath[strlen(to_ospath)-1] = '\0'; + + if ( fs_debug->integer ) { + Com_Printf( "FS_SV_Rename: %s --> %s\n", from_ospath, to_ospath ); + } + + if (rename( from_ospath, to_ospath )) { + // Failed, try copying it and deleting the original + FS_CopyFile ( from_ospath, to_ospath ); + FS_Remove ( from_ospath ); + } +} + + + +/* +=========== +FS_Rename + +=========== +*/ +void FS_Rename( const char *from, const char *to ) { + char *from_ospath, *to_ospath; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + // don't let sound stutter + S_ClearSoundBuffer(); + + from_ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, from ); + to_ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, to ); + + if ( fs_debug->integer ) { + Com_Printf( "FS_Rename: %s --> %s\n", from_ospath, to_ospath ); + } + + if (rename( from_ospath, to_ospath )) { + // Failed, try copying it and deleting the original + FS_CopyFile ( from_ospath, to_ospath ); + FS_Remove ( from_ospath ); + } +} + +/* +============== +FS_FCloseFile + +If the FILE pointer is an open pak file, leave it open. + +For some reason, other dll's can't just cal fclose() +on files returned by FS_FOpenFile... +============== +*/ +void FS_FCloseFile( fileHandle_t f ) { + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + if (fsh[f].streamed) { + Sys_EndStreamedFile(f); + } + if (fsh[f].zipFile == qtrue) { + unzCloseCurrentFile( fsh[f].handleFiles.file.z ); + if ( fsh[f].handleFiles.unique ) { + unzClose( fsh[f].handleFiles.file.z ); + } + Com_Memset( &fsh[f], 0, sizeof( fsh[f] ) ); + return; + } + + // we didn't find it as a pak, so close it as a unique file + if (fsh[f].handleFiles.file.o) { + fclose (fsh[f].handleFiles.file.o); + } + Com_Memset( &fsh[f], 0, sizeof( fsh[f] ) ); +} + +/* +=========== +FS_FOpenFileWrite + +=========== +*/ +fileHandle_t FS_FOpenFileWrite( const char *filename ) { + char *ospath; + fileHandle_t f; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + f = FS_HandleForFile(); + fsh[f].zipFile = qfalse; + + ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename ); + + if ( fs_debug->integer ) { + Com_Printf( "FS_FOpenFileWrite: %s\n", ospath ); + } + + if( FS_CreatePath( ospath ) ) { + return 0; + } + + // enabling the following line causes a recursive function call loop + // when running with +set logfile 1 +set developer 1 + //Com_DPrintf( "writing to: %s\n", ospath ); + fsh[f].handleFiles.file.o = fopen( ospath, "wb" ); + + Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) ); + + fsh[f].handleSync = qfalse; + if (!fsh[f].handleFiles.file.o) { + f = 0; + } + return f; +} + +/* +=========== +FS_FOpenFileAppend + +=========== +*/ +fileHandle_t FS_FOpenFileAppend( const char *filename ) { + char *ospath; + fileHandle_t f; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + f = FS_HandleForFile(); + fsh[f].zipFile = qfalse; + + Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) ); + + // don't let sound stutter + S_ClearSoundBuffer(); + + ospath = FS_BuildOSPath( fs_homepath->string, fs_gamedir, filename ); + + if ( fs_debug->integer ) { + Com_Printf( "FS_FOpenFileAppend: %s\n", ospath ); + } + + if( FS_CreatePath( ospath ) ) { + return 0; + } + + fsh[f].handleFiles.file.o = fopen( ospath, "ab" ); + fsh[f].handleSync = qfalse; + if (!fsh[f].handleFiles.file.o) { + f = 0; + } + return f; +} + +/* +=========== +FS_FilenameCompare + +Ignore case and seprator char distinctions +=========== +*/ +qboolean FS_FilenameCompare( const char *s1, const char *s2 ) { + int c1, c2; + + do { + c1 = *s1++; + c2 = *s2++; + + if (c1 >= 'a' && c1 <= 'z') { + c1 -= ('a' - 'A'); + } + if (c2 >= 'a' && c2 <= 'z') { + c2 -= ('a' - 'A'); + } + + if ( c1 == '\\' || c1 == ':' ) { + c1 = '/'; + } + if ( c2 == '\\' || c2 == ':' ) { + c2 = '/'; + } + + if (c1 != c2) { + return (qboolean)-1; // strings not equal + } + } while (c1); + + return (qboolean)0; // strings are equal +} + +/* +=========== +FS_ShiftedStrStr +=========== +*/ +char *FS_ShiftedStrStr(const char *string, const char *substring, int shift) { + char buf[MAX_STRING_TOKENS]; + int i; + + for (i = 0; substring[i]; i++) { + buf[i] = substring[i] + shift; + } + buf[i] = '\0'; + return strstr(string, buf); +} + +/* +=========== +FS_FOpenFileRead + +Finds the file in the search path. +Returns filesize and an open FILE pointer. +Used for streaming data out of either a +separate file or a ZIP file. +=========== +*/ +extern qboolean com_fullyInitialized; + +int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ) { + searchpath_t *search; + char *netpath; + pack_t *pak; + fileInPack_t *pakFile; + directory_t *dir; + long hash; + unz_s *zfi; + ZIP_FILE *temp; + int l; + char demoExt[16]; + + hash = 0; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + if ( file == NULL ) { + Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'file' parameter passed\n" ); + } + + if ( !filename ) { + Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed\n" ); + } + + Com_sprintf (demoExt, sizeof(demoExt), ".dm_%d",PROTOCOL_VERSION ); + // qpaths are not supposed to have a leading slash + if ( filename[0] == '/' || filename[0] == '\\' ) { + filename++; + } + + // make absolutely sure that it can't back up the path. + // The searchpaths do guarantee that something will always + // be prepended, so we don't need to worry about "c:" or "//limbo" + if ( strstr( filename, ".." ) || strstr( filename, "::" ) ) { + *file = 0; + return -1; + } + + // make sure the q3key file is only readable by the quake3.exe at initialization + // any other time the key should only be accessed in memory using the provided functions + if( com_fullyInitialized && strstr( filename, "q3key" ) ) { + *file = 0; + return -1; + } + + // + // search through the path, one element at a time + // + + *file = FS_HandleForFile(); + fsh[*file].handleFiles.unique = uniqueFILE; + + for ( search = fs_searchpaths ; search ; search = search->next ) { + // + if ( search->pack ) { + hash = FS_HashFileName(filename, search->pack->hashSize); + } + // is the element a pak file? + if ( search->pack && search->pack->hashTable[hash] ) { + // disregard if it doesn't match one of the allowed pure pak files + if ( !FS_PakIsPure(search->pack) ) { + continue; + } + + // look through all the pak file elements + pak = search->pack; + pakFile = pak->hashTable[hash]; + do { + // case and separator insensitive comparisons + if ( !FS_FilenameCompare( pakFile->name, filename ) ) { + // found it! + + // mark the pak as having been referenced and mark specifics on cgame and ui + // shaders, txt, arena files by themselves do not count as a reference as + // these are loaded from all pk3s + // from every pk3 file.. + l = strlen( filename ); + if ( !(pak->referenced & FS_GENERAL_REF)) { + if ( Q_stricmp(filename + l - 7, ".shader") != 0 && + Q_stricmp(filename + l - 4, ".txt") != 0 && + Q_stricmp(filename + l - 4, ".cfg") != 0 && + Q_stricmp(filename + l - 7, ".config") != 0 && + strstr(filename, "levelshots") == NULL && + Q_stricmp(filename + l - 4, ".bot") != 0 && + Q_stricmp(filename + l - 6, ".arena") != 0 && + Q_stricmp(filename + l - 5, ".menu") != 0) { + pak->referenced |= FS_GENERAL_REF; + } + } + + // jk2mpgame.qvm - 13 + // ]^%`cZT`X!di` + if (!(pak->referenced & FS_QAGAME_REF) && FS_ShiftedStrStr(filename, "]^%`cZT`X!di`", 13)) { + pak->referenced |= FS_QAGAME_REF; + } + // cgame.qvm - 7 + // \`Zf^'jof + if (!(pak->referenced & FS_CGAME_REF) && FS_ShiftedStrStr(filename , "\\`Zf^'jof", 7)) { + pak->referenced |= FS_CGAME_REF; + } + // ui.qvm - 5 + // pd)lqh + if (!(pak->referenced & FS_UI_REF) && FS_ShiftedStrStr(filename , "pd)lqh", 5)) { + pak->referenced |= FS_UI_REF; + } + + if ( uniqueFILE ) { + // open a new file on the pakfile + fsh[*file].handleFiles.file.z = unzReOpen (pak->pakFilename, pak->handle); + if (fsh[*file].handleFiles.file.z == NULL) { + Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->pakFilename); + } + } else { + fsh[*file].handleFiles.file.z = pak->handle; + } + Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) ); + fsh[*file].zipFile = qtrue; + zfi = (unz_s *)fsh[*file].handleFiles.file.z; + // in case the file was new + temp = zfi->file; + // set the file position in the zip file (also sets the current file info) + unzSetCurrentFileInfoPosition(pak->handle, pakFile->pos); + // copy the file info into the unzip structure + Com_Memcpy( zfi, pak->handle, sizeof(unz_s) ); + // we copy this back into the structure + zfi->file = temp; + // open the file in the zip + unzOpenCurrentFile( fsh[*file].handleFiles.file.z ); + fsh[*file].zipFilePos = pakFile->pos; + + if ( fs_debug->integer ) { + Com_Printf( "FS_FOpenFileRead: %s (found in '%s')\n", + filename, pak->pakFilename ); + } +#ifdef _DEBUG + // Check for unprecached files when in game but not in the menus + if((cls.state == CA_ACTIVE) && !(cls.keyCatchers & KEYCATCH_UI)) + { + Com_Printf(S_COLOR_YELLOW "WARNING: File %s not precached\n", filename); + } +#endif + return zfi->cur_file_info.uncompressed_size; + } + pakFile = pakFile->next; + } while(pakFile != NULL); + } else if ( search->dir ) { + // check a file in the directory tree + + // if we are running restricted, the only files we + // will allow to come from the directory are .cfg files + l = strlen( filename ); + // FIXME TTimo I'm not sure about the fs_numServerPaks test + // if you are using FS_ReadFile to find out if a file exists, + // this test can make the search fail although the file is in the directory + // I had the problem on https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8 + // turned out I used FS_FileExists instead + if ( fs_restrict->integer || fs_numServerPaks ) { + + if ( Q_stricmp( filename + l - 4, ".cfg" ) // for config files + && Q_stricmp( filename + l - 5, ".menu" ) // menu files + && Q_stricmp( filename + l - 5, ".game" ) // menu files + && Q_stricmp( filename + l - strlen(demoExt), demoExt ) // menu files + && Q_stricmp( filename + l - 4, ".dat" ) ) { // for journal files + continue; + } + } + + dir = search->dir; + + netpath = FS_BuildOSPath( dir->path, dir->gamedir, filename ); + fsh[*file].handleFiles.file.o = fopen (netpath, "rb"); + if ( !fsh[*file].handleFiles.file.o ) { + continue; + } + + if ( Q_stricmp( filename + l - 4, ".cfg" ) // for config files + && Q_stricmp( filename + l - 5, ".menu" ) // menu files + && Q_stricmp( filename + l - 5, ".game" ) // menu files + && Q_stricmp( filename + l - strlen(demoExt), demoExt ) // menu files + && Q_stricmp( filename + l - 4, ".dat" ) ) { // for journal files + fs_fakeChkSum = random(); + } + + Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) ); + fsh[*file].zipFile = qfalse; + if ( fs_debug->integer ) { + Com_Printf( "FS_FOpenFileRead: %s (found in '%s/%s')\n", filename, + dir->path, dir->gamedir ); + } + + // if we are getting it from the cdpath, optionally copy it + // to the basepath + if ( fs_copyfiles->integer && !Q_stricmp( dir->path, fs_cdpath->string ) ) { + char *copypath; + + copypath = FS_BuildOSPath( fs_basepath->string, dir->gamedir, filename ); + FS_CopyFile( netpath, copypath ); + } +#ifdef _DEBUG + // Check for unprecached files when in game but not in the menus + if((cls.state == CA_ACTIVE) && !(cls.keyCatchers & KEYCATCH_UI)) + { + Com_Printf(S_COLOR_YELLOW "WARNING: File %s not precached\n", filename); + } +#endif + return FS_filelength (*file); + } + } + + Com_DPrintf ("Can't find %s\n", filename); +#ifdef FS_MISSING + if (missingFiles) { + fprintf(missingFiles, "%s\n", filename); + } +#endif + *file = 0; + return -1; +} + + +/* +================= +FS_Read + +Properly handles partial reads +================= +*/ +int FS_Read2( void *buffer, int len, fileHandle_t f ) { + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + if ( !f ) { + return 0; + } + if (fsh[f].streamed) { + int r; + fsh[f].streamed = qfalse; + r = Sys_StreamedRead( buffer, len, 1, f); + fsh[f].streamed = qtrue; + return r; + } else { + return FS_Read( buffer, len, f); + } +} + +int FS_Read( void *buffer, int len, fileHandle_t f ) { + int block, remaining; + int read; + byte *buf; + int tries; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + if ( !f ) { + return 0; + } + + buf = (byte *)buffer; + fs_readCount += len; + + if (fsh[f].zipFile == qfalse) { + remaining = len; + tries = 0; + while (remaining) { + block = remaining; + read = fread (buf, 1, block, fsh[f].handleFiles.file.o); + if (read == 0) { + // we might have been trying to read from a CD, which + // sometimes returns a 0 read on windows + if (!tries) { + tries = 1; + } else { + return len-remaining; //Com_Error (ERR_FATAL, "FS_Read: 0 bytes read"); + } + } + + if (read == -1) { + Com_Error (ERR_FATAL, "FS_Read: -1 bytes read"); + } + + remaining -= read; + buf += read; + } + return len; + } else { + return unzReadCurrentFile(fsh[f].handleFiles.file.z, buffer, len); + } +} + +/* +================= +FS_Write + +Properly handles partial writes +================= +*/ +int FS_Write( const void *buffer, int len, fileHandle_t h ) { + int block, remaining; + int written; + byte *buf; + int tries; + FILE *f; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + if ( !h ) { + return 0; + } + + f = FS_FileForHandle(h); + buf = (byte *)buffer; + + remaining = len; + tries = 0; + while (remaining) { + block = remaining; + written = fwrite (buf, 1, block, f); + if (written == 0) { + if (!tries) { + tries = 1; + } else { + Com_Printf( "FS_Write: 0 bytes written\n" ); + return 0; + } + } + + if (written == -1) { + Com_Printf( "FS_Write: -1 bytes written\n" ); + return 0; + } + + remaining -= written; + buf += written; + } + if ( fsh[h].handleSync ) { + fflush( f ); + } + return len; +} + +#define MAXPRINTMSG 4096 +void QDECL FS_Printf( fileHandle_t h, const char *fmt, ... ) { + va_list argptr; + char msg[MAXPRINTMSG]; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + FS_Write(msg, strlen(msg), h); +} + +/* +================= +FS_Seek + +================= +*/ +int FS_Seek( fileHandle_t f, long offset, int origin ) { + int _origin; + char foo[65536]; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + return -1; + } + + if (fsh[f].streamed) { + fsh[f].streamed = qfalse; + Sys_StreamSeek( f, offset, origin ); + fsh[f].streamed = qtrue; + } + + if (fsh[f].zipFile == qtrue) { + if (offset == 0 && origin == FS_SEEK_SET) { + // set the file position in the zip file (also sets the current file info) + unzSetCurrentFileInfoPosition(fsh[f].handleFiles.file.z, fsh[f].zipFilePos); + return unzOpenCurrentFile(fsh[f].handleFiles.file.z); + } else if (offset<65536) { + // set the file position in the zip file (also sets the current file info) + unzSetCurrentFileInfoPosition(fsh[f].handleFiles.file.z, fsh[f].zipFilePos); + unzOpenCurrentFile(fsh[f].handleFiles.file.z); + return FS_Read(foo, offset, f); + } else { + Com_Error( ERR_FATAL, "ZIP FILE FSEEK NOT YET IMPLEMENTED\n" ); + return -1; + } + } else { + FILE *file; + file = FS_FileForHandle(f); + switch( origin ) { + case FS_SEEK_CUR: + _origin = SEEK_CUR; + break; + case FS_SEEK_END: + _origin = SEEK_END; + break; + case FS_SEEK_SET: + _origin = SEEK_SET; + break; + default: + _origin = SEEK_CUR; + Com_Error( ERR_FATAL, "Bad origin in FS_Seek\n" ); + break; + } + + return fseek( file, offset, _origin ); + } +} + + +/* +====================================================================================== + +CONVENIENCE FUNCTIONS FOR ENTIRE FILES + +====================================================================================== +*/ + +int FS_FileIsInPAK(const char *filename, int *pChecksum ) { + searchpath_t *search; + pack_t *pak; + fileInPack_t *pakFile; + long hash = 0; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + if ( !filename ) { + Com_Error( ERR_FATAL, "FS_FOpenFileRead: NULL 'filename' parameter passed\n" ); + } + + // qpaths are not supposed to have a leading slash + if ( filename[0] == '/' || filename[0] == '\\' ) { + filename++; + } + + // make absolutely sure that it can't back up the path. + // The searchpaths do guarantee that something will always + // be prepended, so we don't need to worry about "c:" or "//limbo" + if ( strstr( filename, ".." ) || strstr( filename, "::" ) ) { + return -1; + } + + // + // search through the path, one element at a time + // + + for ( search = fs_searchpaths ; search ; search = search->next ) { + // + if (search->pack) { + hash = FS_HashFileName(filename, search->pack->hashSize); + } + // is the element a pak file? + if ( search->pack && search->pack->hashTable[hash] ) { + // disregard if it doesn't match one of the allowed pure pak files + if ( !FS_PakIsPure(search->pack) ) { + continue; + } + + // look through all the pak file elements + pak = search->pack; + pakFile = pak->hashTable[hash]; + do { + // case and separator insensitive comparisons + if ( !FS_FilenameCompare( pakFile->name, filename ) ) { + if (pChecksum) { + *pChecksum = pak->pure_checksum; + } + return 1; + } + pakFile = pakFile->next; + } while(pakFile != NULL); + } + } + return -1; +} + +/* +============ +FS_ReadFile + +Filename are relative to the quake search path +a null buffer will just return the file length without loading +============ +*/ +int FS_ReadFile( const char *qpath, void **buffer ) { + fileHandle_t h; + byte* buf; + qboolean isConfig; + int len; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + if ( !qpath || !qpath[0] ) { + Com_Error( ERR_FATAL, "FS_ReadFile with empty name\n" ); + } + + buf = NULL; // quiet compiler warning + + // if this is a .cfg file and we are playing back a journal, read + // it from the journal file + if ( strstr( qpath, ".cfg" ) ) { + isConfig = qtrue; + if ( com_journal && com_journal->integer == 2 ) { + int r; + + Com_DPrintf( "Loading %s from journal file.\n", qpath ); + r = FS_Read( &len, sizeof( len ), com_journalDataFile ); + if ( r != sizeof( len ) ) { + if (buffer != NULL) *buffer = NULL; + return -1; + } + // if the file didn't exist when the journal was created + if (!len) { + if (buffer == NULL) { + return 1; // hack for old journal files + } + *buffer = NULL; + return -1; + } + if (buffer == NULL) { + return len; + } + + buf = (unsigned char *)Hunk_AllocateTempMemory(len+1); + *buffer = buf; + + r = FS_Read( buf, len, com_journalDataFile ); + if ( r != len ) { + Com_Error( ERR_FATAL, "Read from journalDataFile failed" ); + } + + fs_loadCount++; + fs_loadStack++; + + // guarantee that it will have a trailing 0 for string operations + buf[len] = 0; + + return len; + } + } else { + isConfig = qfalse; + } + + // look for it in the filesystem or pack files + len = FS_FOpenFileRead( qpath, &h, qfalse ); + if ( h == 0 ) { + if ( buffer ) { + *buffer = NULL; + } + // if we are journalling and it is a config file, write a zero to the journal file + if ( isConfig && com_journal && com_journal->integer == 1 ) { + Com_DPrintf( "Writing zero for %s to journal file.\n", qpath ); + len = 0; + FS_Write( &len, sizeof( len ), com_journalDataFile ); + FS_Flush( com_journalDataFile ); + } + return -1; + } + + if ( !buffer ) { + if ( isConfig && com_journal && com_journal->integer == 1 ) { + Com_DPrintf( "Writing len for %s to journal file.\n", qpath ); + FS_Write( &len, sizeof( len ), com_journalDataFile ); + FS_Flush( com_journalDataFile ); + } + FS_FCloseFile( h); + return len; + } + + fs_loadCount++; +/* fs_loadStack++; + + buf = (unsigned char *)Hunk_AllocateTempMemory(len+1); + *buffer = buf;*/ + + buf = (byte*)Z_Malloc( len+1, TAG_FILESYS, qfalse); + buf[len]='\0'; // because we're not calling Z_Malloc with optional trailing 'bZeroIt' bool + *buffer = buf; + +// Z_Label(buf, qpath); + + FS_Read (buf, len, h); + + // guarantee that it will have a trailing 0 for string operations + buf[len] = 0; + FS_FCloseFile( h ); + + // if we are journalling and it is a config file, write it to the journal file + if ( isConfig && com_journal && com_journal->integer == 1 ) { + Com_DPrintf( "Writing %s to journal file.\n", qpath ); + FS_Write( &len, sizeof( len ), com_journalDataFile ); + FS_Write( buf, len, com_journalDataFile ); + FS_Flush( com_journalDataFile ); + } + return len; +} + +/* +============= +FS_FreeFile +============= +*/ +void FS_FreeFile( void *buffer ) { + /* + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + if ( !buffer ) { + Com_Error( ERR_FATAL, "FS_FreeFile( NULL )" ); + } + fs_loadStack--; + + Hunk_FreeTempMemory( buffer ); + + // if all of our temp files are free, clear all of our space + if ( fs_loadStack == 0 ) { + Hunk_ClearTempMemory(); + } + */ + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + if ( !buffer ) { + Com_Error( ERR_FATAL, "FS_FreeFile( NULL )" ); + } + + Z_Free( buffer ); +} + +/* +============ +FS_WriteFile + +Filename are reletive to the quake search path +============ +*/ +void FS_WriteFile( const char *qpath, const void *buffer, int size ) { + fileHandle_t f; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + if ( !qpath || !buffer ) { + Com_Error( ERR_FATAL, "FS_WriteFile: NULL parameter" ); + } + + f = FS_FOpenFileWrite( qpath ); + if ( !f ) { + Com_Printf( "Failed to open %s\n", qpath ); + return; + } + + FS_Write( buffer, size, f ); + + FS_FCloseFile( f ); +} + + + +/* +========================================================================== + +ZIP FILE LOADING + +========================================================================== +*/ + +/* +================= +FS_LoadZipFile + +Creates a new pak_t in the search chain for the contents +of a zip file. +================= +*/ +static pack_t *FS_LoadZipFile( char *zipfile, const char *basename ) +{ + fileInPack_t *buildBuffer; + pack_t *pack; + unzFile uf; + int err; + unz_global_info gi; + char filename_inzip[MAX_ZPATH]; + unz_file_info file_info; + int i, len; + long hash; + int fs_numHeaderLongs; + int *fs_headerLongs; + char *namePtr; + + fs_numHeaderLongs = 0; + + uf = unzOpen(zipfile); + err = unzGetGlobalInfo (uf,&gi); + + if (err != UNZ_OK) + return NULL; + + fs_packFiles += gi.number_entry; + + len = 0; + unzGoToFirstFile(uf); + for (i = 0; i < gi.number_entry; i++) + { + err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + if (err != UNZ_OK) { + break; + } + len += strlen(filename_inzip) + 1; + unzGoToNextFile(uf); + } + + buildBuffer = (struct fileInPack_s *)Z_Malloc( (gi.number_entry * sizeof( fileInPack_t )) + len, TAG_FILESYS, qtrue ); + namePtr = ((char *) buildBuffer) + gi.number_entry * sizeof( fileInPack_t ); + fs_headerLongs = (int *)Z_Malloc( gi.number_entry * sizeof(int), TAG_FILESYS, qtrue ); + + // get the hash table size from the number of files in the zip + // because lots of custom pk3 files have less than 32 or 64 files + for (i = 1; i <= MAX_FILEHASH_SIZE; i <<= 1) { + if (i > gi.number_entry) { + break; + } + } + + pack = (pack_t *)Z_Malloc( sizeof( pack_t ) + i * sizeof(fileInPack_t *), TAG_FILESYS, qtrue ); + pack->hashSize = i; + pack->hashTable = (fileInPack_t **) (((char *) pack) + sizeof( pack_t )); + for(i = 0; i < pack->hashSize; i++) { + pack->hashTable[i] = NULL; + } + + Q_strncpyz( pack->pakFilename, zipfile, sizeof( pack->pakFilename ) ); + Q_strncpyz( pack->pakBasename, basename, sizeof( pack->pakBasename ) ); + + // strip .pk3 if needed + if ( strlen( pack->pakBasename ) > 4 && !Q_stricmp( pack->pakBasename + strlen( pack->pakBasename ) - 4, ".pk3" ) ) { + pack->pakBasename[strlen( pack->pakBasename ) - 4] = 0; + } + + pack->handle = uf; + pack->numfiles = gi.number_entry; + unzGoToFirstFile(uf); + + for (i = 0; i < gi.number_entry; i++) + { + err = unzGetCurrentFileInfo(uf, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + if (err != UNZ_OK) { + break; + } + if (file_info.uncompressed_size > 0) { + fs_headerLongs[fs_numHeaderLongs++] = LittleLong(file_info.crc); + } + Q_strlwr( filename_inzip ); + hash = FS_HashFileName(filename_inzip, pack->hashSize); + buildBuffer[i].name = namePtr; + strcpy( buildBuffer[i].name, filename_inzip ); + namePtr += strlen(filename_inzip) + 1; + // store the file position in the zip + unzGetCurrentFileInfoPosition(uf, &buildBuffer[i].pos); + // + buildBuffer[i].next = pack->hashTable[hash]; + pack->hashTable[hash] = &buildBuffer[i]; + unzGoToNextFile(uf); + } + + pack->checksum = Com_BlockChecksum( fs_headerLongs, 4 * fs_numHeaderLongs ); + pack->pure_checksum = Com_BlockChecksumKey( fs_headerLongs, 4 * fs_numHeaderLongs, LittleLong(fs_checksumFeed) ); + pack->checksum = LittleLong( pack->checksum ); + pack->pure_checksum = LittleLong( pack->pure_checksum ); + + Z_Free(fs_headerLongs); + + pack->buildBuffer = buildBuffer; + return pack; +} + +/* +================================================================================= + +DIRECTORY SCANNING FUNCTIONS + +================================================================================= +*/ + +#define MAX_FOUND_FILES 0x1000 + +static int FS_ReturnPath( const char *zname, char *zpath, int *depth ) { + int len, at, newdep; + + newdep = 0; + zpath[0] = 0; + len = 0; + at = 0; + + while(zname[at] != 0) + { + if (zname[at]=='/' || zname[at]=='\\') { + len = at; + newdep++; + } + at++; + } + strcpy(zpath, zname); + zpath[len] = 0; + *depth = newdep; + + return len; +} + +/* +================== +FS_AddFileToList +================== +*/ +static int FS_AddFileToList( char *name, char *list[MAX_FOUND_FILES], int nfiles ) { + int i; + + if ( nfiles == MAX_FOUND_FILES - 1 ) { + return nfiles; + } + for ( i = 0 ; i < nfiles ; i++ ) { + if ( !Q_stricmp( name, list[i] ) ) { + return nfiles; // allready in list + } + } + list[nfiles] = CopyString( name ); + nfiles++; + + return nfiles; +} + +/* +=============== +FS_ListFilteredFiles + +Returns a uniqued list of files that match the given criteria +from all search paths +=============== +*/ +char **FS_ListFilteredFiles( const char *path, const char *extension, char *filter, int *numfiles ) { + int nfiles; + char **listCopy; + char *list[MAX_FOUND_FILES]; + searchpath_t *search; + int i; + int pathLength; + int extensionLength; + int length, pathDepth, temp; + pack_t *pak; + fileInPack_t *buildBuffer; + char zpath[MAX_ZPATH]; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + if ( !path ) { + *numfiles = 0; + return NULL; + } + if ( !extension ) { + extension = ""; + } + + pathLength = strlen( path ); + if ( path[pathLength-1] == '\\' || path[pathLength-1] == '/' ) { + pathLength--; + } + extensionLength = strlen( extension ); + nfiles = 0; + FS_ReturnPath(path, zpath, &pathDepth); + + // + // search through the path, one element at a time, adding to list + // + for (search = fs_searchpaths ; search ; search = search->next) { + // is the element a pak file? + if (search->pack) { + + //ZOID: If we are pure, don't search for files on paks that + // aren't on the pure list + if ( !FS_PakIsPure(search->pack) ) { + continue; + } + + // look through all the pak file elements + pak = search->pack; + buildBuffer = pak->buildBuffer; + for (i = 0; i < pak->numfiles; i++) { + char *name; + int zpathLen, depth; + + // check for directory match + name = buildBuffer[i].name; + // + if (filter) { + // case insensitive + if (!Com_FilterPath( filter, name, qfalse )) + continue; + // unique the match + nfiles = FS_AddFileToList( name, list, nfiles ); + } + else { + + zpathLen = FS_ReturnPath(name, zpath, &depth); + + if ( (depth-pathDepth)>2 || pathLength > zpathLen || Q_stricmpn( name, path, pathLength ) ) { + continue; + } + + // check for extension match + length = strlen( name ); + if ( length < extensionLength ) { + continue; + } + + if ( Q_stricmp( name + length - extensionLength, extension ) ) { + continue; + } + // unique the match + + temp = pathLength; + if (pathLength) { + temp++; // include the '/' + } + nfiles = FS_AddFileToList( name + temp, list, nfiles ); + } + } + } else if (search->dir) { // scan for files in the filesystem + char *netpath; + int numSysFiles; + char **sysFiles; + char *name; + + // don't scan directories for files if we are pure or restricted + if ( fs_restrict->integer || fs_numServerPaks ) { + continue; + } else { + netpath = FS_BuildOSPath( search->dir->path, search->dir->gamedir, path ); + sysFiles = Sys_ListFiles( netpath, extension, filter, &numSysFiles, qfalse ); + for ( i = 0 ; i < numSysFiles ; i++ ) { + // unique the match + name = sysFiles[i]; + nfiles = FS_AddFileToList( name, list, nfiles ); + } + Sys_FreeFileList( sysFiles ); + } + } + } + + // return a copy of the list + *numfiles = nfiles; + + if ( !nfiles ) { + return NULL; + } + + listCopy = (char **)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ), TAG_FILESYS ); + for ( i = 0 ; i < nfiles ; i++ ) { + listCopy[i] = list[i]; + } + listCopy[i] = NULL; + + return listCopy; +} + +/* +================= +FS_ListFiles +================= +*/ +char **FS_ListFiles( const char *path, const char *extension, int *numfiles ) { + return FS_ListFilteredFiles( path, extension, NULL, numfiles ); +} + +/* +================= +FS_FreeFileList +================= +*/ +void FS_FreeFileList( char **list ) { + int i; + + if ( !fs_searchpaths ) { + Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" ); + } + + if ( !list ) { + return; + } + + for ( i = 0 ; list[i] ; i++ ) { + Z_Free( list[i] ); + } + + Z_Free( list ); +} + + +/* +================ +FS_GetFileList +================ +*/ +int FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ) { + int nFiles, i, nTotal, nLen; + char **pFiles = NULL; + + *listbuf = 0; + nFiles = 0; + nTotal = 0; + + if (Q_stricmp(path, "$modlist") == 0) { + return FS_GetModList(listbuf, bufsize); + } + + pFiles = FS_ListFiles(path, extension, &nFiles); + + for (i =0; i < nFiles; i++) { + nLen = strlen(pFiles[i]) + 1; + if (nTotal + nLen + 1 < bufsize) { + strcpy(listbuf, pFiles[i]); + listbuf += nLen; + nTotal += nLen; + } + else { + nFiles = i; + break; + } + } + + FS_FreeFileList(pFiles); + + return nFiles; +} + +// NOTE: could prolly turn out useful for the win32 version too, but it's used only by linux and Mac OS X +//#if defined(__linux__) || defined(MACOS_X) +/* +======================= +Sys_ConcatenateFileLists + +mkv: Naive implementation. Concatenates three lists into a + new list, and frees the old lists from the heap. +bk001129 - from cvs1.17 (mkv) + +FIXME TTimo those two should move to common.c next to Sys_ListFiles +======================= + */ +static unsigned int Sys_CountFileList(char **list) +{ + int i = 0; + + if (list) + { + while (*list) + { + list++; + i++; + } + } + return i; +} + +static char** Sys_ConcatenateFileLists( char **list0, char **list1, char **list2 ) +{ + int totalLength = 0; + char** cat = NULL, **dst, **src; + + totalLength += Sys_CountFileList(list0); + totalLength += Sys_CountFileList(list1); + totalLength += Sys_CountFileList(list2); + + /* Create new list. */ + dst = cat = (char **)Z_Malloc( ( totalLength + 1 ) * sizeof( char* ), TAG_FILESYS, qtrue ); + + /* Copy over lists. */ + if (list0) { + for (src = list0; *src; src++, dst++) + *dst = *src; + } + if (list1) { + for (src = list1; *src; src++, dst++) + *dst = *src; + } + if (list2) { + for (src = list2; *src; src++, dst++) + *dst = *src; + } + + // Terminate the list + *dst = NULL; + + // Free our old lists. + // NOTE: not freeing their content, it's been merged in dst and still being used + if (list0) Z_Free( list0 ); + if (list1) Z_Free( list1 ); + if (list2) Z_Free( list2 ); + + return cat; +} +//#endif + +/* +================ +FS_GetModList + +Returns a list of mod directory names +A mod directory is a peer to base with a pk3 in it +The directories are searched in base path, cd path and home path +================ +*/ +int FS_GetModList( char *listbuf, int bufsize ) { + int nMods, i, j, nTotal, nLen, nPaks, nPotential, nDescLen; + char **pFiles = NULL; + char **pPaks = NULL; + char *name, *path; + char descPath[MAX_OSPATH]; + fileHandle_t descHandle; + + int dummy; + char **pFiles0 = NULL; + char **pFiles1 = NULL; + char **pFiles2 = NULL; + qboolean bDrop = qfalse; + + *listbuf = 0; + nMods = nPotential = nTotal = 0; + + pFiles0 = Sys_ListFiles( fs_homepath->string, NULL, NULL, &dummy, qtrue ); + pFiles1 = Sys_ListFiles( fs_basepath->string, NULL, NULL, &dummy, qtrue ); + pFiles2 = Sys_ListFiles( fs_cdpath->string, NULL, NULL, &dummy, qtrue ); + // we searched for mods in the three paths + // it is likely that we have duplicate names now, which we will cleanup below + pFiles = Sys_ConcatenateFileLists( pFiles0, pFiles1, pFiles2 ); + nPotential = Sys_CountFileList(pFiles); + + for ( i = 0 ; i < nPotential ; i++ ) { + name = pFiles[i]; + // NOTE: cleaner would involve more changes + // ignore duplicate mod directories + if (i!=0) { + bDrop = qfalse; + for(j=0; jstring, name, "" ); + nPaks = 0; + pPaks = Sys_ListFiles(path, ".pk3", NULL, &nPaks, qfalse); + Sys_FreeFileList( pPaks ); // we only use Sys_ListFiles to check wether .pk3 files are present + + /* Try on cd path */ + if( nPaks <= 0 ) { + path = FS_BuildOSPath( fs_cdpath->string, name, "" ); + nPaks = 0; + pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse ); + Sys_FreeFileList( pPaks ); + } + + /* try on home path */ + if ( nPaks <= 0 ) + { + path = FS_BuildOSPath( fs_homepath->string, name, "" ); + nPaks = 0; + pPaks = Sys_ListFiles( path, ".pk3", NULL, &nPaks, qfalse ); + Sys_FreeFileList( pPaks ); + } + + if (nPaks > 0) { + nLen = strlen(name) + 1; + // nLen is the length of the mod path + // we need to see if there is a description available + descPath[0] = '\0'; + strcpy(descPath, name); + strcat(descPath, "/description.txt"); + nDescLen = FS_SV_FOpenFileRead( descPath, &descHandle ); + if ( nDescLen > 0 && descHandle) { + FILE *file; + file = FS_FileForHandle(descHandle); + Com_Memset( descPath, 0, sizeof( descPath ) ); + nDescLen = fread(descPath, 1, 48, file); + if (nDescLen >= 0) { + descPath[nDescLen] = '\0'; + } + FS_FCloseFile(descHandle); + } else { + strcpy(descPath, name); + } + nDescLen = strlen(descPath) + 1; + + if (nTotal + nLen + 1 + nDescLen + 1 < bufsize) { + strcpy(listbuf, name); + listbuf += nLen; + strcpy(listbuf, descPath); + listbuf += nDescLen; + nTotal += nLen + nDescLen; + nMods++; + } + else { + break; + } + } + } + } + Sys_FreeFileList( pFiles ); + + return nMods; +} + + + + +//============================================================================ + +/* +================ +FS_Dir_f +================ +*/ +void FS_Dir_f( void ) { + char *path; + char *extension; + char **dirnames; + int ndirs; + int i; + + if ( Cmd_Argc() < 2 || Cmd_Argc() > 3 ) { + Com_Printf( "usage: dir [extension]\n" ); + return; + } + + if ( Cmd_Argc() == 2 ) { + path = Cmd_Argv( 1 ); + extension = ""; + } else { + path = Cmd_Argv( 1 ); + extension = Cmd_Argv( 2 ); + } + + Com_Printf( "Directory of %s %s\n", path, extension ); + Com_Printf( "---------------\n" ); + + dirnames = FS_ListFiles( path, extension, &ndirs ); + + for ( i = 0; i < ndirs; i++ ) { + Com_Printf( "%s\n", dirnames[i] ); + } + FS_FreeFileList( dirnames ); +} + +/* +=========== +FS_ConvertPath +=========== +*/ +void FS_ConvertPath( char *s ) { + while (*s) { + if ( *s == '\\' || *s == ':' ) { + *s = '/'; + } + s++; + } +} + +/* +=========== +FS_PathCmp + +Ignore case and seprator char distinctions +=========== +*/ +int FS_PathCmp( const char *s1, const char *s2 ) { + int c1, c2; + + do { + c1 = *s1++; + c2 = *s2++; + + if (c1 >= 'a' && c1 <= 'z') { + c1 -= ('a' - 'A'); + } + if (c2 >= 'a' && c2 <= 'z') { + c2 -= ('a' - 'A'); + } + + if ( c1 == '\\' || c1 == ':' ) { + c1 = '/'; + } + if ( c2 == '\\' || c2 == ':' ) { + c2 = '/'; + } + + if (c1 < c2) { + return -1; // strings not equal + } + if (c1 > c2) { + return 1; + } + } while (c1); + + return 0; // strings are equal +} + +/* +================ +FS_SortFileList +================ +*/ +void FS_SortFileList(char **filelist, int numfiles) { + int i, j, k, numsortedfiles; + char **sortedlist; + + sortedlist = (char **)Z_Malloc( ( numfiles + 1 ) * sizeof( *sortedlist ), TAG_FILESYS, qtrue ); + sortedlist[0] = NULL; + numsortedfiles = 0; + for (i = 0; i < numfiles; i++) { + for (j = 0; j < numsortedfiles; j++) { + if (FS_PathCmp(filelist[i], sortedlist[j]) < 0) { + break; + } + } + for (k = numsortedfiles; k > j; k--) { + sortedlist[k] = sortedlist[k-1]; + } + sortedlist[j] = filelist[i]; + numsortedfiles++; + } + Com_Memcpy(filelist, sortedlist, numfiles * sizeof( *filelist ) ); + Z_Free(sortedlist); +} + +/* +================ +FS_NewDir_f +================ +*/ +void FS_NewDir_f( void ) { + char *filter; + char **dirnames; + int ndirs; + int i; + + if ( Cmd_Argc() < 2 ) { + Com_Printf( "usage: fdir \n" ); + Com_Printf( "example: fdir *q3dm*.bsp\n"); + return; + } + + filter = Cmd_Argv( 1 ); + + Com_Printf( "---------------\n" ); + + dirnames = FS_ListFilteredFiles( "", "", filter, &ndirs ); + + FS_SortFileList(dirnames, ndirs); + + for ( i = 0; i < ndirs; i++ ) { + FS_ConvertPath(dirnames[i]); + Com_Printf( "%s\n", dirnames[i] ); + } + Com_Printf( "%d files listed\n", ndirs ); + FS_FreeFileList( dirnames ); +} + +/* +============ +FS_Path_f + +============ +*/ +void FS_Path_f( void ) { + searchpath_t *s; + int i; + + Com_Printf ("Current search path:\n"); + for (s = fs_searchpaths; s; s = s->next) { + if (s->pack) { + Com_Printf ("%s (%i files)\n", s->pack->pakFilename, s->pack->numfiles); + if ( fs_numServerPaks ) { + if ( !FS_PakIsPure(s->pack) ) { + Com_Printf( " not on the pure list\n" ); + } else { + Com_Printf( " on the pure list\n" ); + } + } + } else { + Com_Printf ("%s/%s\n", s->dir->path, s->dir->gamedir ); + } + } + + + Com_Printf( "\n" ); + for ( i = 1 ; i < MAX_FILE_HANDLES ; i++ ) { + if ( fsh[i].handleFiles.file.o ) { + Com_Printf( "handle %i: %s\n", i, fsh[i].name ); + } + } +} + +/* +============ +FS_TouchFile_f + +The only purpose of this function is to allow game script files to copy +arbitrary files furing an "fs_copyfiles 1" run. +============ +*/ +void FS_TouchFile_f( void ) { + fileHandle_t f; + + if ( Cmd_Argc() != 2 ) { + Com_Printf( "Usage: touchFile \n" ); + return; + } + + FS_FOpenFileRead( Cmd_Argv( 1 ), &f, qfalse ); + if ( f ) { + FS_FCloseFile( f ); + } +} + +//=========================================================================== + + +static int QDECL paksort( const void *a, const void *b ) { + char *aa, *bb; + + aa = *(char **)a; + bb = *(char **)b; + + return FS_PathCmp( aa, bb ); +} + +/* +================ +FS_AddGameDirectory + +Sets fs_gamedir, adds the directory to the head of the path, +then loads the zip headers +================ +*/ +#define MAX_PAKFILES 1024 +static void FS_AddGameDirectory( const char *path, const char *dir ) { + searchpath_t *sp; + int i; + searchpath_t *search; + pack_t *pak; + char *pakfile; + int numfiles; + char **pakfiles; + char *sorted[MAX_PAKFILES]; + + // this fixes the case where fs_basepath is the same as fs_cdpath + // which happens on full installs + for ( sp = fs_searchpaths ; sp ; sp = sp->next ) { + if ( sp->dir && !Q_stricmp(sp->dir->path, path) && !Q_stricmp(sp->dir->gamedir, dir)) { + return; // we've already got this one + } + } + + Q_strncpyz( fs_gamedir, dir, sizeof( fs_gamedir ) ); + + // + // add the directory to the search path + // + search = (struct searchpath_s *)Z_Malloc (sizeof(searchpath_t), TAG_FILESYS, qtrue); + search->dir = (directory_t *)Z_Malloc( sizeof( *search->dir ), TAG_FILESYS, qtrue ); + + Q_strncpyz( search->dir->path, path, sizeof( search->dir->path ) ); + Q_strncpyz( search->dir->gamedir, dir, sizeof( search->dir->gamedir ) ); + search->next = fs_searchpaths; + fs_searchpaths = search; + + // find all pak files in this directory + pakfile = FS_BuildOSPath( path, dir, "" ); + pakfile[ strlen(pakfile) - 1 ] = 0; // strip the trailing slash + + pakfiles = Sys_ListFiles( pakfile, ".pk3", NULL, &numfiles, qfalse ); + + // sort them so that later alphabetic matches override + // earlier ones. This makes pak1.pk3 override pak0.pk3 + if ( numfiles > MAX_PAKFILES ) { + numfiles = MAX_PAKFILES; + } + for ( i = 0 ; i < numfiles ; i++ ) { + sorted[i] = pakfiles[i]; + } + + qsort( sorted, numfiles, 4, paksort ); + + for ( i = 0 ; i < numfiles ; i++ ) { + pakfile = FS_BuildOSPath( path, dir, sorted[i] ); + if ( ( pak = FS_LoadZipFile( pakfile, sorted[i] ) ) == 0 ) + continue; + // store the game name for downloading + strcpy(pak->pakGamename, dir); + + search = (searchpath_s *)Z_Malloc (sizeof(searchpath_t), TAG_FILESYS, qtrue); + search->pack = pak; + search->next = fs_searchpaths; + fs_searchpaths = search; + } + + // done + Sys_FreeFileList( pakfiles ); +} + +/* +================ +FS_idPak +================ +*/ +qboolean FS_idPak( char *pak, char *base ) { + int i; + + for (i = 0; i < NUM_ID_PAKS; i++) { + if ( !FS_FilenameCompare(pak, va("%s/pak%d", base, i)) ) { + break; + } + } + if (i < NUM_ID_PAKS) { + return qtrue; + } + return qfalse; +} + +/* +================ +FS_ComparePaks + +Returns a list of pak files that we should download from the server. They all get stored +in the current gamedir and an FS_Restart will be fired up after we download them all. + +The string is the format: + +@remotename@localname [repeat] + +static int fs_numServerReferencedPaks; +static int fs_serverReferencedPaks[MAX_SEARCH_PATHS]; +static char *fs_serverReferencedPakNames[MAX_SEARCH_PATHS]; + +================ +*/ +qboolean FS_ComparePaks( char *neededpaks, int len ) { + searchpath_t *sp; + qboolean havepak, badchecksum; + int i; + + if ( !fs_numServerReferencedPaks ) { + return qfalse; // Server didn't send any pack information along + } + + *neededpaks = 0; + + for ( i = 0 ; i < fs_numServerReferencedPaks ; i++ ) { + // Ok, see if we have this pak file + badchecksum = qfalse; + havepak = qfalse; + + // never autodownload any of the id paks + if ( FS_idPak(fs_serverReferencedPakNames[i], "base") || FS_idPak(fs_serverReferencedPakNames[i], "missionpack") ) { + continue; + } + + for ( sp = fs_searchpaths ; sp ; sp = sp->next ) { + if ( sp->pack && sp->pack->checksum == fs_serverReferencedPaks[i] ) { + havepak = qtrue; // This is it! + break; + } + } + + if ( !havepak && fs_serverReferencedPakNames[i] && *fs_serverReferencedPakNames[i] ) { + // Don't got it + + // Remote name + Q_strcat( neededpaks, len, "@"); + Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] ); + Q_strcat( neededpaks, len, ".pk3" ); + + // Local name + Q_strcat( neededpaks, len, "@"); + // Do we have one with the same name? + if ( FS_SV_FileExists( va( "%s.pk3", fs_serverReferencedPakNames[i] ) ) ) { + char st[MAX_ZPATH]; + // We already have one called this, we need to download it to another name + // Make something up with the checksum in it + Com_sprintf( st, sizeof( st ), "%s.%08x.pk3", fs_serverReferencedPakNames[i], fs_serverReferencedPaks[i] ); + Q_strcat( neededpaks, len, st ); + } else { + Q_strcat( neededpaks, len, fs_serverReferencedPakNames[i] ); + Q_strcat( neededpaks, len, ".pk3" ); + } + } + } + + if ( *neededpaks ) { + Com_Printf("Need paks: %s\n", neededpaks); + return qtrue; + } + + return qfalse; // We have them all +} + +/* +================ +FS_Shutdown + +Frees all resources and closes all files +================ +*/ +void FS_Shutdown( qboolean closemfp ) { + searchpath_t *p, *next; + int i; + + for(i = 0; i < MAX_FILE_HANDLES; i++) { + if (fsh[i].fileSize) { + FS_FCloseFile(i); + } + } + + // free everything + for ( p = fs_searchpaths ; p ; p = next ) { + next = p->next; + + if ( p->pack ) { + unzClose(p->pack->handle); + Z_Free( p->pack->buildBuffer ); + Z_Free( p->pack ); + } + if ( p->dir ) { + Z_Free( p->dir ); + } + Z_Free( p ); + } + + // any FS_ calls will now be an error until reinitialized + fs_searchpaths = NULL; + + Cmd_RemoveCommand( "path" ); + Cmd_RemoveCommand( "dir" ); + Cmd_RemoveCommand( "fdir" ); + Cmd_RemoveCommand( "touchFile" ); + +#ifdef FS_MISSING + if (closemfp) { + fclose(missingFiles); + } +#endif +} + +#ifdef USE_CD_KEY + +void Com_AppendCDKey( const char *filename ); +void Com_ReadCDKey( const char *filename ); + +#endif // USE_CD_KEY + +/* +================ +FS_Startup +================ +*/ +static void FS_Startup( const char *gameName ) { + const char *homePath; +#ifdef USE_CD_KEY + cvar_t *fs; +#endif // USE_CD_KEY + + Com_Printf( "----- FS_Startup -----\n" ); + + fs_debug = Cvar_Get( "fs_debug", "0", 0 ); + fs_copyfiles = Cvar_Get( "fs_copyfiles", "0", CVAR_INIT ); + fs_cdpath = Cvar_Get ("fs_cdpath", Sys_DefaultCDPath(), CVAR_INIT ); + fs_basepath = Cvar_Get ("fs_basepath", Sys_DefaultInstallPath(), CVAR_INIT ); + fs_basegame = Cvar_Get ("fs_basegame", "", CVAR_INIT ); + homePath = Sys_DefaultHomePath(); + if (!homePath || !homePath[0]) { + homePath = fs_basepath->string; + } + fs_homepath = Cvar_Get ("fs_homepath", homePath, CVAR_INIT ); + fs_gamedirvar = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO ); + fs_restrict = Cvar_Get ("fs_restrict", "", CVAR_INIT ); + + // add search path elements in reverse priority order + if (fs_cdpath->string[0]) { + FS_AddGameDirectory( fs_cdpath->string, gameName ); + } + if (fs_basepath->string[0]) { + FS_AddGameDirectory( fs_basepath->string, gameName ); + } + // fs_homepath is somewhat particular to *nix systems, only add if relevant + // NOTE: same filtering below for mods and basegame + if (fs_basepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) { + FS_AddGameDirectory ( fs_homepath->string, gameName ); + } + + // check for additional base game so mods can be based upon other mods + if ( fs_basegame->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_basegame->string, gameName ) ) { + if (fs_cdpath->string[0]) { + FS_AddGameDirectory(fs_cdpath->string, fs_basegame->string); + } + if (fs_basepath->string[0]) { + FS_AddGameDirectory(fs_basepath->string, fs_basegame->string); + } + if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) { + FS_AddGameDirectory(fs_homepath->string, fs_basegame->string); + } + } + + // check for additional game folder for mods + if ( fs_gamedirvar->string[0] && !Q_stricmp( gameName, BASEGAME ) && Q_stricmp( fs_gamedirvar->string, gameName ) ) { + if (fs_cdpath->string[0]) { + FS_AddGameDirectory(fs_cdpath->string, fs_gamedirvar->string); + } + if (fs_basepath->string[0]) { + FS_AddGameDirectory(fs_basepath->string, fs_gamedirvar->string); + } + if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) { + FS_AddGameDirectory(fs_homepath->string, fs_gamedirvar->string); + } + } + +#ifdef USE_CD_KEY + Com_ReadCDKey( "base" ); + fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO ); + if (fs && fs->string[0] != 0) { + Com_AppendCDKey( fs->string ); + } +#endif // USE_CD_KEY + + // add our commands + Cmd_AddCommand ("path", FS_Path_f); + Cmd_AddCommand ("dir", FS_Dir_f ); + Cmd_AddCommand ("fdir", FS_NewDir_f ); + Cmd_AddCommand ("touchFile", FS_TouchFile_f ); + + // print the current search paths + FS_Path_f(); + + fs_gamedirvar->modified = qfalse; // We just loaded, it's not modified + + Com_Printf( "----------------------\n" ); + +#ifdef FS_MISSING + if (missingFiles == NULL) { + missingFiles = fopen( "\\missing.txt", "ab" ); + } +#endif + Com_Printf( "%d files in pk3 files\n", fs_packFiles ); +} + + +/* +=================== +FS_SetRestrictions + +Looks for product keys and restricts media add on ability +if the full version is not found +=================== +*/ +static void FS_SetRestrictions( void ) { + searchpath_t *path; + +#ifndef PRE_RELEASE_DEMO + char *productId; + + // if fs_restrict is set, don't even look for the id file, + // which allows the demo release to be tested even if + // the full game is present + if ( !fs_restrict->integer ) { + // look for the full game id + FS_ReadFile( "productid.txt", (void **)&productId ); + if ( productId ) { + // check against the hardcoded string + int seed, i; + + seed = 102270; + for ( i = 0 ; i < sizeof( fs_scrambledProductId ) ; i++ ) { + if ( ( fs_scrambledProductId[i] ^ (seed&255) ) != productId[i] ) { + break; + } + seed = (69069 * seed + 1); + } + + FS_FreeFile( productId ); + + if ( i == sizeof( fs_scrambledProductId ) ) { + return; // no restrictions + } + Com_Error( ERR_FATAL, "Invalid product identification" ); + } + } +#endif + Cvar_Set( "fs_restrict", "1" ); + + Com_Printf( "\nRunning in restricted demo mode.\n\n" ); + + // restart the filesystem with just the demo directory + FS_Shutdown(qfalse); + FS_Startup( DEMOGAME ); + + // make sure that the pak file has the header checksum we expect + for ( path = fs_searchpaths ; path ; path = path->next ) { + if ( path->pack ) { + // a tiny attempt to keep the checksum from being scannable from the exe + if ( (path->pack->checksum ^ 0x02261994u) != (DEMO_PAK_CHECKSUM ^ 0x02261994u) ) { + Com_Error( ERR_FATAL, "Corrupted pak0.pk3: %u", path->pack->checksum ); + } + } + } +} + +/* +===================== +FS_GamePureChecksum + +Returns the checksum of the pk3 from which the server loaded the qagame.qvm +===================== +*/ +const char *FS_GamePureChecksum( void ) { + static char info[MAX_STRING_TOKENS]; + searchpath_t *search; + + info[0] = 0; + + for ( search = fs_searchpaths ; search ; search = search->next ) { + // is the element a pak file? + if ( search->pack ) { + if (search->pack->referenced & FS_QAGAME_REF) { + Com_sprintf(info, sizeof(info), "%d", search->pack->checksum); + } + } + } + + return info; +} + +/* +===================== +FS_LoadedPakChecksums + +Returns a space separated string containing the checksums of all loaded pk3 files. +Servers with sv_pure set will get this string and pass it to clients. +===================== +*/ +const char *FS_LoadedPakChecksums( void ) { + static char info[BIG_INFO_STRING]; + searchpath_t *search; + + info[0] = 0; + + for ( search = fs_searchpaths ; search ; search = search->next ) { + // is the element a pak file? + if ( !search->pack ) { + continue; + } + + Q_strcat( info, sizeof( info ), va("%i ", search->pack->checksum ) ); + } + + return info; +} + +/* +===================== +FS_LoadedPakNames + +Returns a space separated string containing the names of all loaded pk3 files. +Servers with sv_pure set will get this string and pass it to clients. +===================== +*/ +const char *FS_LoadedPakNames( void ) { + static char info[BIG_INFO_STRING]; + searchpath_t *search; + + info[0] = 0; + + for ( search = fs_searchpaths ; search ; search = search->next ) { + // is the element a pak file? + if ( !search->pack ) { + continue; + } + + if (*info) { + Q_strcat(info, sizeof( info ), " " ); + } + Q_strcat( info, sizeof( info ), search->pack->pakBasename ); + } + + return info; +} + +/* +===================== +FS_LoadedPakPureChecksums + +Returns a space separated string containing the pure checksums of all loaded pk3 files. +Servers with sv_pure use these checksums to compare with the checksums the clients send +back to the server. +===================== +*/ +const char *FS_LoadedPakPureChecksums( void ) { + static char info[BIG_INFO_STRING]; + searchpath_t *search; + + info[0] = 0; + + for ( search = fs_searchpaths ; search ; search = search->next ) { + // is the element a pak file? + if ( !search->pack ) { + continue; + } + + Q_strcat( info, sizeof( info ), va("%i ", search->pack->pure_checksum ) ); + } + + return info; +} + +/* +===================== +FS_ReferencedPakChecksums + +Returns a space separated string containing the checksums of all referenced pk3 files. +The server will send this to the clients so they can check which files should be auto-downloaded. +===================== +*/ +const char *FS_ReferencedPakChecksums( void ) { + static char info[BIG_INFO_STRING]; + searchpath_t *search; + + info[0] = 0; + + + for ( search = fs_searchpaths ; search ; search = search->next ) { + // is the element a pak file? + if ( search->pack ) { + if (search->pack->referenced || Q_stricmpn(search->pack->pakGamename, BASEGAME, strlen(BASEGAME))) { + Q_strcat( info, sizeof( info ), va("%i ", search->pack->checksum ) ); + } + } + } + + return info; +} + +/* +===================== +FS_ReferencedPakPureChecksums + +Returns a space separated string containing the pure checksums of all referenced pk3 files. +Servers with sv_pure set will get this string back from clients for pure validation + +The string has a specific order, "cgame ui @ ref1 ref2 ref3 ..." +===================== +*/ +const char *FS_ReferencedPakPureChecksums( void ) { + static char info[BIG_INFO_STRING]; + searchpath_t *search; + int nFlags, numPaks, checksum; + + info[0] = 0; + + checksum = fs_checksumFeed; + numPaks = 0; + for (nFlags = FS_CGAME_REF; nFlags; nFlags = nFlags >> 1) { + if (nFlags & FS_GENERAL_REF) { + // add a delimter between must haves and general refs + //Q_strcat(info, sizeof(info), "@ "); + info[strlen(info)+1] = '\0'; + info[strlen(info)+2] = '\0'; + info[strlen(info)] = '@'; + info[strlen(info)] = ' '; + } + for ( search = fs_searchpaths ; search ; search = search->next ) { + // is the element a pak file and has it been referenced based on flag? + if ( search->pack && (search->pack->referenced & nFlags)) { + Q_strcat( info, sizeof( info ), va("%i ", search->pack->pure_checksum ) ); + if (nFlags & (FS_CGAME_REF | FS_UI_REF)) { + break; + } + checksum ^= search->pack->pure_checksum; + numPaks++; + } + } + if (fs_fakeChkSum != 0) { + // only added if a non-pure file is referenced + Q_strcat( info, sizeof( info ), va("%i ", fs_fakeChkSum ) ); + } + } + // last checksum is the encoded number of referenced pk3s + checksum ^= numPaks; + Q_strcat( info, sizeof( info ), va("%i ", checksum ) ); + + return info; +} + +/* +===================== +FS_ReferencedPakNames + +Returns a space separated string containing the names of all referenced pk3 files. +The server will send this to the clients so they can check which files should be auto-downloaded. +===================== +*/ +const char *FS_ReferencedPakNames( void ) { + static char info[BIG_INFO_STRING]; + searchpath_t *search; + + info[0] = 0; + + // we want to return ALL pk3's from the fs_game path + // and referenced one's from base + for ( search = fs_searchpaths ; search ; search = search->next ) { + // is the element a pak file? + if ( search->pack ) { + if (*info) { + Q_strcat(info, sizeof( info ), " " ); + } + if (search->pack->referenced || Q_stricmpn(search->pack->pakGamename, BASEGAME, strlen(BASEGAME))) { + Q_strcat( info, sizeof( info ), search->pack->pakGamename ); + Q_strcat( info, sizeof( info ), "/" ); + Q_strcat( info, sizeof( info ), search->pack->pakBasename ); + } + } + } + + return info; +} + +/* +===================== +FS_ClearPakReferences +===================== +*/ +void FS_ClearPakReferences( int flags ) { + searchpath_t *search; + + if ( !flags ) { + flags = -1; + } + for ( search = fs_searchpaths; search; search = search->next ) { + // is the element a pak file and has it been referenced? + if ( search->pack ) { + search->pack->referenced &= ~flags; + } + } +} + + +/* +===================== +FS_PureServerSetLoadedPaks + +If the string is empty, all data sources will be allowed. +If not empty, only pk3 files that match one of the space +separated checksums will be checked for files, with the +exception of .cfg and .dat files. +===================== +*/ +void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames ) { + int i, c, d; + + Cmd_TokenizeString( pakSums ); + + c = Cmd_Argc(); + if ( c > MAX_SEARCH_PATHS ) { + c = MAX_SEARCH_PATHS; + } + + fs_numServerPaks = c; + + for ( i = 0 ; i < c ; i++ ) { + fs_serverPaks[i] = atoi( Cmd_Argv( i ) ); + } + + if (fs_numServerPaks) { + Com_DPrintf( "Connected to a pure server.\n" ); + } + + for ( i = 0 ; i < c ; i++ ) { + if (fs_serverPakNames[i]) { + Z_Free(fs_serverPakNames[i]); + } + fs_serverPakNames[i] = NULL; + } + if ( pakNames && *pakNames ) { + Cmd_TokenizeString( pakNames ); + + d = Cmd_Argc(); + if ( d > MAX_SEARCH_PATHS ) { + d = MAX_SEARCH_PATHS; + } + + for ( i = 0 ; i < d ; i++ ) { + fs_serverPakNames[i] = CopyString( Cmd_Argv( i ) ); + } + } +} + +/* +===================== +FS_PureServerSetReferencedPaks + +The checksums and names of the pk3 files referenced at the server +are sent to the client and stored here. The client will use these +checksums to see if any pk3 files need to be auto-downloaded. +===================== +*/ +void FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames ) { + int i, c, d; + + Cmd_TokenizeString( pakSums ); + + c = Cmd_Argc(); + if ( c > MAX_SEARCH_PATHS ) { + c = MAX_SEARCH_PATHS; + } + + fs_numServerReferencedPaks = c; + + for ( i = 0 ; i < c ; i++ ) { + fs_serverReferencedPaks[i] = atoi( Cmd_Argv( i ) ); + } + + for ( i = 0 ; i < c ; i++ ) { + if (fs_serverReferencedPakNames[i]) { + Z_Free(fs_serverReferencedPakNames[i]); + } + fs_serverReferencedPakNames[i] = NULL; + } + if ( pakNames && *pakNames ) { + Cmd_TokenizeString( pakNames ); + + d = Cmd_Argc(); + if ( d > MAX_SEARCH_PATHS ) { + d = MAX_SEARCH_PATHS; + } + + for ( i = 0 ; i < d ; i++ ) { + fs_serverReferencedPakNames[i] = CopyString( Cmd_Argv( i ) ); + } + } +} + +/* +================ +FS_InitFilesystem + +Called only at inital startup, not when the filesystem +is resetting due to a game change +================ +*/ +void FS_InitFilesystem( void ) { + // allow command line parms to override our defaults + // we have to specially handle this, because normal command + // line variable sets don't happen until after the filesystem + // has already been initialized + Com_StartupVariable( "fs_cdpath" ); + Com_StartupVariable( "fs_basepath" ); + Com_StartupVariable( "fs_homepath" ); + Com_StartupVariable( "fs_game" ); + Com_StartupVariable( "fs_copyfiles" ); + Com_StartupVariable( "fs_restrict" ); + + // try to start up normally + FS_Startup( BASEGAME ); + + // see if we are going to allow add-ons + FS_SetRestrictions(); + + // if we can't find default.cfg, assume that the paths are + // busted and error out now, rather than getting an unreadable + // graphics screen when the font fails to load + if ( FS_ReadFile( "default.cfg", NULL ) <= 0 ) { /* mpdefault */ + Com_Error( ERR_FATAL, "Couldn't load default.cfg" ); + // bk001208 - SafeMode see below, FIXME? + } + + Q_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase)); + Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame)); + + // bk001208 - SafeMode see below, FIXME? +} + + +/* +================ +FS_Restart +================ +*/ +void FS_Restart( int checksumFeed ) { + + // free anything we currently have loaded + FS_Shutdown(qfalse); + + // set the checksum feed + fs_checksumFeed = checksumFeed; + + // clear pak references + FS_ClearPakReferences(0); + + // try to start up normally + FS_Startup( BASEGAME ); + + // see if we are going to allow add-ons + FS_SetRestrictions(); + + // if we can't find default.cfg, assume that the paths are + // busted and error out now, rather than getting an unreadable + // graphics screen when the font fails to load + if ( FS_ReadFile( "default.cfg", NULL ) <= 0 ) { /* mpdefault */ + // this might happen when connecting to a pure server not using BASEGAME/pak0.pk3 + // (for instance a TA demo server) + if (lastValidBase[0]) { + FS_PureServerSetLoadedPaks("", ""); + Cvar_Set("fs_basepath", lastValidBase); + Cvar_Set("fs_gamedirvar", lastValidGame); + lastValidBase[0] = '\0'; + lastValidGame[0] = '\0'; + Cvar_Set( "fs_restrict", "0" ); + FS_Restart(checksumFeed); + Com_Error( ERR_DROP, "Invalid game folder\n" ); + return; + } + Com_Error( ERR_FATAL, "Couldn't load default.cfg" ); + } + + // bk010116 - new check before safeMode + if ( Q_stricmp(fs_gamedirvar->string, lastValidGame) ) { + // skip the jk2mpconfig.cfg if "safe" is on the command line + if ( !Com_SafeMode() ) { + Cbuf_AddText ("exec jk2mpconfig.cfg\n"); + } + } + + Q_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase)); + Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame)); + +} + +/* +================= +FS_ConditionalRestart +restart if necessary +================= +*/ +qboolean FS_ConditionalRestart( int checksumFeed ) { + if( fs_gamedirvar->modified || checksumFeed != fs_checksumFeed ) { + FS_Restart( checksumFeed ); + return qtrue; + } + return qfalse; +} + +/* +======================================================================================== + +Handle based file calls for virtual machines + +======================================================================================== +*/ + +int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) { + int r; + qboolean sync; + + sync = qfalse; + + switch( mode ) { + case FS_READ: + r = FS_FOpenFileRead( qpath, f, qtrue ); + break; + case FS_WRITE: + *f = FS_FOpenFileWrite( qpath ); + r = 0; + if (*f == 0) { + r = -1; + } + break; + case FS_APPEND_SYNC: + sync = qtrue; + case FS_APPEND: + *f = FS_FOpenFileAppend( qpath ); + r = 0; + if (*f == 0) { + r = -1; + } + break; + default: + Com_Error( ERR_FATAL, "FSH_FOpenFile: bad mode" ); + return -1; + } + + if ( *f ) { + if (fsh[*f].zipFile == qtrue) { + fsh[*f].baseOffset = unztell(fsh[*f].handleFiles.file.z); + } else { + fsh[*f].baseOffset = ftell(fsh[*f].handleFiles.file.o); + } + fsh[*f].fileSize = r; + fsh[*f].streamed = qfalse; + + if (mode == FS_READ) { + Sys_BeginStreamedFile( *f, 0x4000 ); + fsh[*f].streamed = qtrue; + } + } + fsh[*f].handleSync = sync; + + return r; +} + +int FS_FTell( fileHandle_t f ) { + int pos; + if (fsh[f].zipFile == qtrue) { + pos = unztell(fsh[f].handleFiles.file.z); + } else { + pos = ftell(fsh[f].handleFiles.file.o); + } + return pos; +} + +void FS_Flush( fileHandle_t f ) { + fflush(fsh[f].handleFiles.file.o); +} + diff --git a/CODE-mp/qcommon/game_version.h b/CODE-mp/qcommon/game_version.h new file mode 100644 index 0000000..a1d3b40 --- /dev/null +++ b/CODE-mp/qcommon/game_version.h @@ -0,0 +1,8 @@ +// Copyright (C) 2000-2002 Raven Software, Inc. +// + +// Current version of the multi player game + +#define Q3_VERSION "JK2MP: v1.02a" + +//end diff --git a/CODE-mp/qcommon/hstring.cpp b/CODE-mp/qcommon/hstring.cpp new file mode 100644 index 0000000..8cf9505 --- /dev/null +++ b/CODE-mp/qcommon/hstring.cpp @@ -0,0 +1,499 @@ +#ifdef _DONETPROFILE_ + +#include +#include "hstring.h" + +using namespace std; + +// mapPoolBlockCount is defined differently in the executable (sv_main.cpp) and the game dll (g_main.cpp) cuz +//we likely don't need as many blocks in the executable as we do in the game +extern int mapPoolBlockCount; + +// Used to fool optimizer during compilation of mem touch routines. +int HaHaOptimizer2=0; + +CMapPoolLow &GetMapPool() +{ + // this may need to be ifdefed to be different for different modules + static CMapPoolLow thePool; + return thePool; +} + +#define MAPBLOCK_SIZE_NODES (1024) +#define MAPNODE_FREE (0xa1) +#define MAPNODE_INUSE (0x94) + +struct SMapNode +{ + unsigned char mData[MAP_NODE_SIZE-2]; + unsigned char mMapBlockNum; + unsigned char mTag; +}; + +class CMapBlock +{ + int mId; + char mRaw[(MAPBLOCK_SIZE_NODES+1)*MAP_NODE_SIZE]; + SMapNode *mNodes; + int mLastNode; + +public: + CMapBlock(int id,vector &freeList) : + mLastNode(0) + { + // Alloc node storage for MAPBLOCK_SIZE_NODES worth of nodes. + mNodes=(SMapNode *)((((unsigned long)mRaw)+MAP_NODE_SIZE)&~(unsigned long)0x1f); + // Set all nodes to initially be free. + int i; + for(i=0;i=&mNodes[0])&&(((SMapNode *)node)<&mNodes[MAPBLOCK_SIZE_NODES])); + } +}; + +CMapPoolLow::CMapPoolLow() +{ + mLastBlockNum=-1; +} + +CMapPoolLow::~CMapPoolLow() +{ +#if _DEBUG +#if _GAME + if(mFreeList.size()mTag==MAPNODE_FREE); + assert((((SMapNode *)node)->mMapBlockNum)>=0); + assert((((SMapNode *)node)->mMapBlockNum)<256); + assert((((SMapNode *)node)->mMapBlockNum)<=mLastBlockNum); + assert(mMapBlocks[((SMapNode *)node)->mMapBlockNum]->bOwnsNode(node)); + + // Ok, mark the node as in use. + ((SMapNode *)node)->mTag=MAPNODE_INUSE; + + return(node); +} + +void CMapPoolLow::Free(void *p) +{ + // Validate that someone isn't trying to double free this node and also + // that the end marker is intact. + assert(((SMapNode *)p)->mTag==MAPNODE_INUSE); + assert((((SMapNode *)p)->mMapBlockNum)>=0); + assert((((SMapNode *)p)->mMapBlockNum)<256); + assert((((SMapNode *)p)->mMapBlockNum)<=mLastBlockNum); + assert(mMapBlocks[((SMapNode *)p)->mMapBlockNum]->bOwnsNode(p)); + + // Ok, mark the the node as free. + ((SMapNode *)p)->mTag=MAPNODE_FREE; + + // Add a new freelist entry to point at this node. + mFreeList.push_back(p); +} + +void CMapPoolLow::TouchMem() +{ + int i,j; + unsigned char *memory; + int totSize=0; + for(i=0;i=0&&hash=0&&mFindPtr(BLOCK_SIZE-mBytesUsed)) + { + return(0); + } + + // Return the pointer to the start of allocated space. + char *ret=&mRaw[mBytesUsed]; + mBytesUsed+=sizeBytes; + return ret; + } + + bool operator== (const CHSBlock &block) const + { + if(!memcmp(mRaw,block.mRaw,BLOCK_SIZE)) + { + return(true); + } + return(false); + } +}; + +class CPool +{ + vector mBlockVec; + +public: + int mNextStringId; + int mLastBlockNum; + + CPool(void) : + mNextStringId(1), + mLastBlockNum(-1) + { + memset(gCharPtrs,0,MAX_STRINGS*4); + } + + ~CPool(void) + { + int i; + for (i=0;i=0) + { + // Get the pointer to the start of allocated space in the current block. + raw=mBlockVec[mLastBlockNum]->Alloc(sizeBytes); + } + if(!raw) + { + // Ok, make a new empty block and append it. + CHSBlock *block=new(CHSBlock); + mBlockVec.push_back(block); + mLastBlockNum++; + raw=mBlockVec[mLastBlockNum]->Alloc(sizeBytes); + } + // Should never really happen!! + assert(raw); + + id=mNextStringId; + gCharPtrs[mNextStringId]=raw; + mNextStringId++; + + return(raw); + } + + bool operator== (const CPool &pool) const + { + int i; + for(i=0;i0&&id0&&mId0&&mId +#include +#include +#include +#include + +using namespace std; + +class hstring +{ + int mId; + void Init(const char *str); +public: + hstring() + { + mId=0; + } + hstring(const char *str) + { + Init(str); + } + hstring(const string &str) + { + Init(str.c_str()); + } + hstring(const hstring &str) + { + mId=str.mId; + } + + operator string () const + { + return str(); + } + + const char *c_str(void) const; + string str(void) const; + + hstring& operator= (const char *str) + { + Init(str); + return *this; + } + hstring& operator= (const string &str) + { + Init(str.c_str()); + return *this; + } + hstring& operator= (const hstring &str) + { + mId=str.mId; + return *this; + } + + bool operator== (const hstring &str) const + { + return((mId==str.mId)?true:false); + } + + int compare(const hstring &str) const + { + return strcmp(c_str(),str.c_str()); + } + + bool operator< (const hstring &str) const + { + return((mId mMapBlocks; + vector mFreeList; + int mLastBlockNum; + +public: + CMapPoolLow(); + ~CMapPoolLow(); + void *Alloc(); + void Free(void *p); + void TouchMem(); +}; + +CMapPoolLow &GetMapPool(); + +template +class CMapPool +{ + CMapPoolLow &mPool; +public: + CMapPool() : mPool(GetMapPool()) + { + + } + template + CMapPool(const U&) : mPool(GetMapPool()) + { + } + ~CMapPool() + { + } + + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + template + struct rebind + { + typedef CMapPool other; + }; + + // return address of values + pointer address (reference value) const + { + return &value; + } + const_pointer address (const_reference value) const + { + return &value; + } + + // return maximum number of elements that can be allocated + size_type max_size () const + { + return 0xfffffff; + } + + // allocate but don't initialize num elements of type T + pointer allocate (size_type num, const void* = 0) + { + assert(sizeof(T)<=(MAP_NODE_SIZE-2)); // to big for this pool + assert(num==1); //allocator not design for this + return (T*)mPool.Alloc(); + } + void *_Charalloc(size_type size) + { + assert(size<=(MAP_NODE_SIZE-2)); // to big for this pool + return mPool.Alloc(); + } + + // initialize elements of allocated storage p with value value + void construct (pointer p, const T& value) + { + // initialize memory with placement new + new((void*)p)T(value); + } + + // destroy elements of initialized storage p + void destroy (pointer p) + { + // destroy objects by calling their destructor + p->~T(); + } + + // deallocate storage p of deleted elements + template + void deallocate (U *p, size_type num) + { + assert(num==1); //allocator not design for this + mPool.Free(p); + } +}; + + +template +bool operator== (const CMapPool&, + const CMapPool&) +{ + return false; +} +template +bool operator!= (const CMapPool&, + const CMapPool&) +{ + return true; +} + +template > +class hmap : public map >{}; + +template > +class hmultimap : public multimap >{}; + +template > +class hset : public set >{}; + +template > +class hmultiset : public multiset >{}; + +template +class hlist : public list >{}; + +// General purpose allocator/deallocator. +template X *XAlloc(void) +{ + assert(sizeof(X)<=(MAP_NODE_SIZE-2)); + return((X *)GetMapPool().Alloc()); +} + +template void XFree(X *x) +{ + GetMapPool().Free((void *)x); +} +#endif // hString_H + +#endif // _DONETPROFILE_ \ No newline at end of file diff --git a/CODE-mp/qcommon/huffman.cpp b/CODE-mp/qcommon/huffman.cpp index 98d537a..0ee677e 100644 --- a/CODE-mp/qcommon/huffman.cpp +++ b/CODE-mp/qcommon/huffman.cpp @@ -6,8 +6,14 @@ #include "../game/q_shared.h" #include "qcommon.h" +//#define _TESTCR_ static int bloc = 0; +#ifdef _TESTCR_ +static int byteCount=0; +static int bitCount=0; +#endif + void Huff_putBit( int bit, byte *fout, int *offset) { bloc = *offset; if ((bloc&7) == 0) { @@ -234,6 +240,9 @@ void Huff_addRef(huff_t* huff, byte ch) { /* Get a symbol */ int Huff_Receive (node_t *node, int *ch, byte *fin) { while (node && node->symbol == INTERNAL_NODE) { +#ifdef _TESTCR_ + bitCount++; +#endif if (get_bit(fin)) { node = node->right; } else { @@ -243,6 +252,9 @@ int Huff_Receive (node_t *node, int *ch, byte *fin) { if (!node) { Com_Error(ERR_DROP, "Illegal tree!\n"); } +#ifdef _TESTCR_ + byteCount++; +#endif return (*ch = node->symbol); } @@ -250,6 +262,9 @@ int Huff_Receive (node_t *node, int *ch, byte *fin) { void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) { bloc = *offset; while (node && node->symbol == INTERNAL_NODE) { +#ifdef _TESTCR_ + bitCount++; +#endif if (get_bit(fin)) { node = node->right; } else { @@ -259,6 +274,9 @@ void Huff_offsetReceive (node_t *node, int *ch, byte *fin, int *offset) { if (!node) { Com_Error(ERR_DROP, "Illegal tree!\n"); } +#ifdef _TESTCR_ + byteCount++; +#endif *ch = node->symbol; *offset = bloc; } @@ -382,6 +400,11 @@ void Huff_Compress(msg_t *mbuf, int offset) { void Huff_Init(huffman_t *huff) { +#ifdef _TESTCR_ + byteCount=0; + bitCount=0; +#endif + Com_Memset(&huff->compressor, 0, sizeof(huff_t)); Com_Memset(&huff->decompressor, 0, sizeof(huff_t)); @@ -401,3 +424,16 @@ void Huff_Init(huffman_t *huff) { huff->compressor.loc[NYT] = huff->compressor.tree; } +float Huff_GetCR(void) +{ +#ifdef _TESTCR_ + if(!bitCount) + { + // No valid data. + return(-1.0f); + } + return(((float)byteCount*8.0f)/bitCount); +#else + return(-1.0f); +#endif +} diff --git a/CODE-mp/qcommon/msg.cpp b/CODE-mp/qcommon/msg.cpp index c22f004..fe2fee5 100644 --- a/CODE-mp/qcommon/msg.cpp +++ b/CODE-mp/qcommon/msg.cpp @@ -1,9 +1,16 @@ #include "../game/q_shared.h" #include "qcommon.h" +#ifdef _DONETPROFILE_ +#include "INetProfile.h" +#endif + +//#define _NEWHUFFTABLE_ // Build "c:\\netchan.bin" +//#define _USINGNEWHUFFTABLE_ // Build a new frequency table to cut and paste. static huffman_t msgHuff; static qboolean msgInit = qfalse; +static FILE *fp=0; int pcount[256]; @@ -80,7 +87,6 @@ int overflows; // negative bit values include signs void MSG_WriteBits( msg_t *msg, int value, int bits ) { int i; -// FILE* fp; oldsize += bits; @@ -138,7 +144,6 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) { Com_Error(ERR_DROP, "can't read %d bits\n", bits); } } else { -// fp = fopen("c:\\netchan.bin", "a"); value &= (0xffffffff>>(32-bits)); if (bits&7) { int nbits; @@ -151,13 +156,14 @@ void MSG_WriteBits( msg_t *msg, int value, int bits ) { } if (bits) { for(i=0;idata, &msg->bit); value = (value>>8); } } msg->cursize = (msg->bit>>3)+1; -// fclose(fp); } } @@ -166,8 +172,6 @@ int MSG_ReadBits( msg_t *msg, int bits ) { int get; qboolean sgn; int i, nbits; -// FILE* fp; - value = 0; if ( bits < 0 ) { @@ -205,13 +209,13 @@ int MSG_ReadBits( msg_t *msg, int bits ) { bits = bits - nbits; } if (bits) { -// fp = fopen("c:\\netchan.bin", "a"); for(i=0;idata, &msg->bit); -// fwrite(&get, 1, 1, fp); +#ifdef _NEWHUFFTABLE_ + fwrite(&get, 1, 1, fp); +#endif // _NEWHUFFTABLE_ value |= (get<<(i+nbits)); } -// fclose(fp); } msg->readcount = (msg->bit>>3)+1; } @@ -427,9 +431,17 @@ char *MSG_ReadString( msg_t *msg ) { string[l] = c; l++; - } while (l < sizeof(string)-1); + } while (l <= sizeof(string)-1); - string[l] = 0; + // some bonus protection, shouldn't occur cause server doesn't write such things + if (l <= sizeof(string)-1) + { + string[l] = 0; + } + else + { + string[sizeof(string)-1] = 0; + } return string; } @@ -811,7 +823,7 @@ netField_t entityStateFields[] = { NETF(angles2[1]), 0 }, { NETF(eType), 8 }, { NETF(torsoAnim), 16 }, // Maximum number of animation sequences is 2048. Top bit is reserved for the togglebit -{ NETF(forceFrame), 32 }, +{ NETF(forceFrame), 16 }, //if you have over 65536 frames, then this will explode. Of course if you have that many things then lots of things will probably explode. { NETF(eventParm), 8 }, { NETF(legsAnim), 16 }, // Maximum number of animation sequences is 2048. Top bit is reserved for the togglebit { NETF(groundEntityNum), GENTITYNUM_BITS }, @@ -819,14 +831,14 @@ netField_t entityStateFields[] = { NETF(eFlags), 32 }, { NETF(bolt1), 8 }, { NETF(bolt2), GENTITYNUM_BITS }, -{ NETF(trickedentindex), 32 }, //See note in PSF -{ NETF(trickedentindex2), 32 }, -{ NETF(trickedentindex3), 32 }, -{ NETF(trickedentindex4), 32 }, +{ NETF(trickedentindex), 16 }, //See note in PSF +{ NETF(trickedentindex2), 16 }, +{ NETF(trickedentindex3), 16 }, +{ NETF(trickedentindex4), 16 }, { NETF(speed), 0 }, { NETF(fireflag), 2 }, { NETF(genericenemyindex), 32 }, //Do not change to GENTITYNUM_BITS, used as a time offset for seeker -{ NETF(activeForcePass), 16 }, +{ NETF(activeForcePass), 6 }, { NETF(emplacedOwner), 32 }, //As above, also used as a time value (for electricity render time) { NETF(otherEntityNum), GENTITYNUM_BITS }, { NETF(weapon), 8 }, @@ -842,7 +854,7 @@ netField_t entityStateFields[] = { NETF(teamowner), 8 }, { NETF(shouldtarget), 1 }, { NETF(powerups), 16 }, -{ NETF(modelGhoul2), 8 }, +{ NETF(modelGhoul2), 4 }, { NETF(g2radius), 8 }, { NETF(modelindex), -8 }, { NETF(otherEntityNum2), GENTITYNUM_BITS }, @@ -1059,10 +1071,17 @@ void MSG_ReadDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to, to->number = number; +#ifdef _DONETPROFILE_ + int startBytes,endBytes; +#endif + for ( i = 0, field = entityStateFields ; i < lc ; i++, field++ ) { fromF = (int *)( (byte *)from + field->offset ); toF = (int *)( (byte *)to + field->offset ); +#ifdef _DONETPROFILE_ + startBytes=msg->readcount; +#endif if ( ! MSG_ReadBits( msg, 1 ) ) { // no change *toF = *fromF; @@ -1102,6 +1121,10 @@ void MSG_ReadDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to, } // pcount[i]++; } +#ifdef _DONETPROFILE_ + endBytes=msg->readcount; + ClReadProf().AddField(field->name,endBytes-startBytes); +#endif } for ( i = lc, field = &entityStateFields[lc] ; i < numFields ; i++, field++ ) { fromF = (int *)( (byte *)from + field->offset ); @@ -1120,7 +1143,6 @@ void MSG_ReadDeltaEntity( msg_t *msg, entityState_t *from, entityState_t *to, } } - /* ============================================================================ @@ -1171,6 +1193,7 @@ netField_t playerStateFields[] = { PSF(damageYaw), 8 }, { PSF(damagePitch), 8 }, { PSF(damageCount), 8 }, +{ PSF(damageType), 2 }, { PSF(generic1), 8 }, { PSF(pm_type), 8 }, { PSF(delta_angles[0]), 16 }, @@ -1190,10 +1213,10 @@ netField_t playerStateFields[] = { PSF(zoomFov), 8 }, { PSF(fd.forcePowersActive), 32 }, -{ PSF(fd.forceMindtrickTargetIndex), 32 }, //NOTE: Not just an index, used as a (1 << val) bitflag for up to 16 clients -{ PSF(fd.forceMindtrickTargetIndex2), 32 }, //NOTE: Not just an index, used as a (1 << val) bitflag for up to 16 clients -{ PSF(fd.forceMindtrickTargetIndex3), 32 }, //NOTE: Not just an index, used as a (1 << val) bitflag for up to 16 clients -{ PSF(fd.forceMindtrickTargetIndex4), 32 }, //NOTE: Not just an index, used as a (1 << val) bitflag for up to 16 clients +{ PSF(fd.forceMindtrickTargetIndex), 16 }, //NOTE: Not just an index, used as a (1 << val) bitflag for up to 16 clients +{ PSF(fd.forceMindtrickTargetIndex2), 16 }, //NOTE: Not just an index, used as a (1 << val) bitflag for up to 16 clients +{ PSF(fd.forceMindtrickTargetIndex3), 16 }, //NOTE: Not just an index, used as a (1 << val) bitflag for up to 16 clients +{ PSF(fd.forceMindtrickTargetIndex4), 16 }, //NOTE: Not just an index, used as a (1 << val) bitflag for up to 16 clients { PSF(fd.forceJumpZStart), 0 }, { PSF(fd.forcePowerSelected), 8 }, { PSF(fd.forcePowersKnown), 32 }, @@ -1203,7 +1226,7 @@ netField_t playerStateFields[] = { PSF(fd.forcePowerLevel[FP_LEVITATION]), 2 }, //unfortunately we need this for fall damage calculation (client needs to know the distance for the fall noise) { PSF(fd.forcePowerLevel[FP_SEE]), 2 }, //needed for knowing when to display players through walls { PSF(genericEnemyIndex), 32 }, //NOTE: This isn't just an index all the time, it's often used as a time value, and thus needs 32 bits -{ PSF(activeForcePass), 16 }, +{ PSF(activeForcePass), 6 }, { PSF(hasDetPackPlanted), 1 }, { PSF(emplacedIndex), GENTITYNUM_BITS }, { PSF(fd.forceRageRecoveryTime), 32 }, @@ -1225,9 +1248,9 @@ netField_t playerStateFields[] = { PSF(saberCanThrow), 1 }, { PSF(forceHandExtend), 8 }, { PSF(forceDodgeAnim), 16 }, -{ PSF(fd.saberAnimLevel), 4 }, -{ PSF(fd.saberDrawAnimLevel), 4 }, -{ PSF(saberAttackChainCount), 32 }, +{ PSF(fd.saberAnimLevel), 2 }, +{ PSF(fd.saberDrawAnimLevel), 2 }, +{ PSF(saberAttackChainCount), 4 }, { PSF(saberHolstered), 1 }, { PSF(usingATST), 1 }, { PSF(atstAltFire), 1 }, @@ -1238,7 +1261,7 @@ netField_t playerStateFields[] = { PSF(saberLockTime), 32 }, { PSF(saberLockEnemy), GENTITYNUM_BITS }, -{ PSF(saberLockFrame), 32 }, +{ PSF(saberLockFrame), 16 }, { PSF(saberLockAdvance), 1 }, { PSF(inAirAnim), 1 }, //just transmit it for the sake of knowing right when on the client to play a land anim, it's only 1 bit @@ -1450,10 +1473,17 @@ void MSG_ReadDeltaPlayerstate (msg_t *msg, playerState_t *from, playerState_t *t numFields = sizeof( playerStateFields ) / sizeof( playerStateFields[0] ); lc = MSG_ReadByte(msg); +#ifdef _DONETPROFILE_ + int startBytes,endBytes; +#endif + for ( i = 0, field = playerStateFields ; i < lc ; i++, field++ ) { fromF = (int *)( (byte *)from + field->offset ); toF = (int *)( (byte *)to + field->offset ); +#ifdef _DONETPROFILE_ + startBytes=msg->readcount; +#endif if ( ! MSG_ReadBits( msg, 1 ) ) { // no change *toF = *fromF; @@ -1484,6 +1514,10 @@ void MSG_ReadDeltaPlayerstate (msg_t *msg, playerState_t *from, playerState_t *t } } } +#ifdef _DONETPROFILE_ + endBytes=msg->readcount; + ClReadProf().AddField(field->name,endBytes-startBytes); +#endif } for ( i=lc,field = &playerStateFields[lc];ioffset ); @@ -1492,8 +1526,10 @@ void MSG_ReadDeltaPlayerstate (msg_t *msg, playerState_t *from, playerState_t *t *toF = *fromF; } - // read the arrays +#ifdef _DONETPROFILE_ + startBytes=msg->readcount; +#endif if (MSG_ReadBits( msg, 1 ) ) { // parse stats if ( MSG_ReadBits( msg, 1 ) ) { @@ -1505,8 +1541,15 @@ void MSG_ReadDeltaPlayerstate (msg_t *msg, playerState_t *from, playerState_t *t } } } +#ifdef _DONETPROFILE_ + endBytes=msg->readcount; + ClReadProf().AddField("PS_STATS",endBytes-startBytes); +#endif // parse persistant stats +#ifdef _DONETPROFILE_ + startBytes=msg->readcount; +#endif if ( MSG_ReadBits( msg, 1 ) ) { LOG("PS_PERSISTANT"); bits = MSG_ReadShort (msg); @@ -1516,8 +1559,15 @@ void MSG_ReadDeltaPlayerstate (msg_t *msg, playerState_t *from, playerState_t *t } } } +#ifdef _DONETPROFILE_ + endBytes=msg->readcount; + ClReadProf().AddField("PS_PERSISTANT",endBytes-startBytes); +#endif // parse ammo +#ifdef _DONETPROFILE_ + startBytes=msg->readcount; +#endif if ( MSG_ReadBits( msg, 1 ) ) { LOG("PS_AMMO"); bits = MSG_ReadShort (msg); @@ -1527,8 +1577,15 @@ void MSG_ReadDeltaPlayerstate (msg_t *msg, playerState_t *from, playerState_t *t } } } +#ifdef _DONETPROFILE_ + endBytes=msg->readcount; + ClReadProf().AddField("PS_AMMO",endBytes-startBytes); +#endif // parse powerups +#ifdef _DONETPROFILE_ + startBytes=msg->readcount; +#endif if ( MSG_ReadBits( msg, 1 ) ) { LOG("PS_POWERUPS"); bits = MSG_ReadShort (msg); @@ -1539,6 +1596,10 @@ void MSG_ReadDeltaPlayerstate (msg_t *msg, playerState_t *from, playerState_t *t } } } +#ifdef _DONETPROFILE_ + endBytes=msg->readcount; + ClReadProf().AddField("PS_POWERUPS",endBytes-startBytes); +#endif if ( print ) { if ( msg->bit == 0 ) { @@ -1550,6 +1611,270 @@ void MSG_ReadDeltaPlayerstate (msg_t *msg, playerState_t *from, playerState_t *t } } +/* +// New data gathered to tune Q3 to JK2MP. Takes longer to crunch and gain was minimal. +int msg_hData[256] = +{ + 3163878, // 0 + 473992, // 1 + 564019, // 2 + 136497, // 3 + 129559, // 4 + 283019, // 5 + 75812, // 6 + 179836, // 7 + 85958, // 8 + 168542, // 9 + 78898, // 10 + 82007, // 11 + 48613, // 12 + 138741, // 13 + 35482, // 14 + 47433, // 15 + 65214, // 16 + 51636, // 17 + 63741, // 18 + 52823, // 19 + 42464, // 20 + 44495, // 21 + 45347, // 22 + 40260, // 23 + 59168, // 24 + 44990, // 25 + 52957, // 26 + 42700, // 27 + 42414, // 28 + 36451, // 29 + 45653, // 30 + 44667, // 31 + 125336, // 32 + 38435, // 33 + 53658, // 34 + 42621, // 35 + 40932, // 36 + 33409, // 37 + 35470, // 38 + 40769, // 39 + 33813, // 40 + 32480, // 41 + 33664, // 42 + 32303, // 43 + 32394, // 44 + 34822, // 45 + 37724, // 46 + 48016, // 47 + 94212, // 48 + 53774, // 49 + 54522, // 50 + 44044, // 51 + 42800, // 52 + 47597, // 53 + 29742, // 54 + 30237, // 55 + 34291, // 56 + 106496, // 57 + 20963, // 58 + 19342, // 59 + 20603, // 60 + 19568, // 61 + 23013, // 62 + 23939, // 63 + 44995, // 64 + 37128, // 65 + 44264, // 66 + 46636, // 67 + 56400, // 68 + 32746, // 69 + 23458, // 70 + 29702, // 71 + 25305, // 72 + 20159, // 73 + 19645, // 74 + 20593, // 75 + 21729, // 76 + 19362, // 77 + 24760, // 78 + 22788, // 79 + 25085, // 80 + 21074, // 81 + 97271, // 82 + 22048, // 83 + 24131, // 84 + 19287, // 85 + 20296, // 86 + 20131, // 87 + 86477, // 88 + 25352, // 89 + 20872, // 90 + 21382, // 91 + 38744, // 92 + 137256, // 93 + 26025, // 94 + 22243, // 95 + 23974, // 96 + 43305, // 97 + 28191, // 98 + 34638, // 99 + 37613, // 100 + 46003, // 101 + 31415, // 102 + 25746, // 103 + 28338, // 104 + 34689, // 105 + 24948, // 106 + 27110, // 107 + 39950, // 108 + 32793, // 109 + 42639, // 110 + 47883, // 111 + 37439, // 112 + 23875, // 113 + 36092, // 114 + 46471, // 115 + 37392, // 116 + 33063, // 117 + 29604, // 118 + 42140, // 119 + 61745, // 120 + 45618, // 121 + 51779, // 122 + 49684, // 123 + 57644, // 124 + 65021, // 125 + 67318, // 126 + 88197, // 127 + 258378, // 128 + 76806, // 129 + 72430, // 130 + 64936, // 131 + 62196, // 132 + 56461, // 133 + 166474, // 134 + 70036, // 135 + 40735, // 136 + 29598, // 137 + 26966, // 138 + 26093, // 139 + 25853, // 140 + 26065, // 141 + 26176, // 142 + 26777, // 143 + 26684, // 144 + 23880, // 145 + 22932, // 146 + 24566, // 147 + 24305, // 148 + 26399, // 149 + 23487, // 150 + 24485, // 151 + 25956, // 152 + 26065, // 153 + 26151, // 154 + 23111, // 155 + 23900, // 156 + 22128, // 157 + 24096, // 158 + 20863, // 159 + 24298, // 160 + 22572, // 161 + 22364, // 162 + 20813, // 163 + 21414, // 164 + 21570, // 165 + 20799, // 166 + 20971, // 167 + 22485, // 168 + 20397, // 169 + 88096, // 170 + 17802, // 171 + 20091, // 172 + 84250, // 173 + 21953, // 174 + 21406, // 175 + 23401, // 176 + 19546, // 177 + 19180, // 178 + 18843, // 179 + 20673, // 180 + 19918, // 181 + 20640, // 182 + 20326, // 183 + 21174, // 184 + 21736, // 185 + 22511, // 186 + 20290, // 187 + 23303, // 188 + 19800, // 189 + 25465, // 190 + 22801, // 191 + 28831, // 192 + 26663, // 193 + 36485, // 194 + 45768, // 195 + 49795, // 196 + 36026, // 197 + 24119, // 198 + 18543, // 199 + 19261, // 200 + 17137, // 201 + 19435, // 202 + 23672, // 203 + 22988, // 204 + 18107, // 205 + 18734, // 206 + 19847, // 207 + 101897, // 208 + 18405, // 209 + 21260, // 210 + 17818, // 211 + 18971, // 212 + 19317, // 213 + 19112, // 214 + 19395, // 215 + 20688, // 216 + 18438, // 217 + 18945, // 218 + 29309, // 219 + 19666, // 220 + 18735, // 221 + 87691, // 222 + 18478, // 223 + 22634, // 224 + 20984, // 225 + 20079, // 226 + 18624, // 227 + 20045, // 228 + 18369, // 229 + 19014, // 230 + 83179, // 231 + 20899, // 232 + 17854, // 233 + 19332, // 234 + 17875, // 235 + 28647, // 236 + 17465, // 237 + 20277, // 238 + 18994, // 239 + 22192, // 240 + 17443, // 241 + 20243, // 242 + 28174, // 243 + 134871, // 244 + 17753, // 245 + 18924, // 246 + 18281, // 247 + 18937, // 248 + 17419, // 249 + 20679, // 250 + 17865, // 251 + 17984, // 252 + 58615, // 253 + 35506, // 254 + 123499, // 255 +}; +*/ + +// Q3 TA freq. table. int msg_hData[256] = { 250315, // 0 41193, // 1 @@ -1809,9 +2134,15 @@ int msg_hData[256] = { 13504, // 255 }; +#ifndef _USINGNEWHUFFTABLE_ + void MSG_initHuffman() { int i,j; +#ifdef _NEWHUFFTABLE_ + fp=fopen("c:\\netchan.bin", "a"); +#endif // _NEWHUFFTABLE_ + msgInit = qtrue; Huff_Init(&msgHuff); for(i=0;i<256;i++) { @@ -1822,8 +2153,10 @@ void MSG_initHuffman() { } } -/* -void MSG_NUinitHuffman() { +#else + +void MSG_initHuffman() { + byte *data; int size, i, ch; int array[256]; @@ -1832,7 +2165,7 @@ void MSG_NUinitHuffman() { Huff_Init(&msgHuff); // load it in - size = FS_ReadFile( "netchan/netchan.bin", (void **)&data ); + size = FS_ReadFile( "netchan\\netchan.bin", (void **)&data ); for(i=0;i<256;i++) { array[i] = 0; @@ -1855,6 +2188,17 @@ void MSG_NUinitHuffman() { FS_FreeFile( data ); Cbuf_AddText( "condump dump.txt\n" ); } -*/ + +#endif _USINGNEWHUFFTABLE_ + +void MSG_shutdownHuffman() +{ +#ifdef _NEWHUFFTABLE_ + if(fp) + { + fclose(fp); + } +#endif // _NEWHUFFTABLE_ +} //=========================================================================== diff --git a/CODE-mp/qcommon/net_chan.cpp b/CODE-mp/qcommon/net_chan.cpp index 0eef0fe..f2dd86a 100644 --- a/CODE-mp/qcommon/net_chan.cpp +++ b/CODE-mp/qcommon/net_chan.cpp @@ -36,6 +36,7 @@ to the new value before sending out any replies. cvar_t *showpackets; cvar_t *showdrop; cvar_t *qport; +cvar_t *net_killdroppedfragments; static char *netsrcString[2] = { "client", @@ -53,6 +54,7 @@ void Netchan_Init( int port ) { showpackets = Cvar_Get ("showpackets", "0", CVAR_TEMP ); showdrop = Cvar_Get ("showdrop", "0", CVAR_TEMP ); qport = Cvar_Get ("net_qport", va("%i", port), CVAR_INIT ); + net_killdroppedfragments = Cvar_Get ("net_killdroppedfragments", "0", CVAR_TEMP); } /* @@ -234,8 +236,13 @@ void Netchan_Transmit( netchan_t *chan, int length, const byte *data ) { } chan->unsentFragmentStart = 0; + if (chan->unsentFragments) + { + Com_Printf("[ISM] Stomping Unsent Fragments %s\n",netsrcString[ chan->sock ]); + } // fragment large reliable messages - if ( length >= FRAGMENT_SIZE ) { + if ( length >= FRAGMENT_SIZE ) + { chan->unsentFragments = qtrue; chan->unsentLength = length; Com_Memcpy( chan->unsentBuffer, data, length ); @@ -383,6 +390,18 @@ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) { } // we can still keep the part that we have so far, // so we don't need to clear chan->fragmentLength + + //rww - not clearing this will allow us to piece together fragments belonging to other packets + //that happen to have the same sequence (or so it seems). I am just going to clear it and force + //the packet to be dropped. + + // hell yeah we have to dump the whole thing -gil + // but I am scared - mw + /* + chan->fragmentLength = 0; + chan->incomingSequence = sequence; + chan->fragmentSequence = 0; + */ return qfalse; } @@ -418,12 +437,18 @@ qboolean Netchan_Process( netchan_t *chan, msg_t *msg ) { // make sure the sequence number is still there *(int *)msg->data = LittleLong( sequence ); + if ( chan->fragmentLength + 4 > MAX_MSGLEN ) + { + Com_Error( ERR_DROP, "Netchan_Process: length = %i",chan->fragmentLength + 4); + } Com_Memcpy( msg->data + 4, chan->fragmentBuffer, chan->fragmentLength ); msg->cursize = chan->fragmentLength + 4; chan->fragmentLength = 0; msg->readcount = 4; // past the sequence number msg->bit = 32; // past the sequence number + // but I am a wuss -mw + // chan->incomingSequence = sequence; // lets not accept any more with this sequence number -gil return qtrue; } diff --git a/CODE-mp/qcommon/qcommon.h b/CODE-mp/qcommon/qcommon.h index 8cd7f70..0d15863 100644 --- a/CODE-mp/qcommon/qcommon.h +++ b/CODE-mp/qcommon/qcommon.h @@ -3,7 +3,7 @@ #define _QCOMMON_H_ #include "../qcommon/cm_public.h" - +#include "../game/q_shared.h" //#define PRE_RELEASE_DEMO @@ -99,7 +99,7 @@ NET #define PORT_ANY -1 -#define MAX_RELIABLE_COMMANDS 64 // max string commands buffered for restransmit +#define MAX_RELIABLE_COMMANDS 128 // max string commands buffered for restransmit typedef enum { NA_BOT, @@ -228,6 +228,7 @@ enum svc_ops_e { svc_download, // [short] size [size bytes] svc_snapshot, svc_mapchange, + svc_EOF }; @@ -594,8 +595,7 @@ void FS_PureServerSetLoadedPaks( const char *pakSums, const char *pakNames ); // sole exception of .cfg files. qboolean FS_idPak( char *pak, char *base ); -qboolean FS_ComparePaks( char *neededpaks, int len ); - +qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ); void FS_Rename( const char *from, const char *to ); /* @@ -744,7 +744,7 @@ void Z_LogHeap( void ); void *Z_Malloc ( int iSize, memtag_t eTag, qboolean bZeroit = qfalse); // return memory NOT zero-filled by default void *S_Malloc ( int iSize ); // NOT 0 filled memory only for small allocations #else -void *Z_Malloc ( int iSize, memtag_t eTag, qboolean bZeroit = qfalse); // return memory NOT zero-filled by default +void *Z_Malloc ( int iSize, memtag_t eTag, qboolean bZeroit = qfalse ); // return memory NOT zero-filled by default void *S_Malloc ( int iSize ); // NOT 0 filled memory only for small allocations #endif void Z_Validate( void ); @@ -923,12 +923,19 @@ void Sys_Print( const char *msg ); // any game related timing information should come from event timestamps int Sys_Milliseconds (void); +#if __linux__ +extern "C" void Sys_SnapVector( float *v ); + +#else void Sys_SnapVector( float *v ); +#endif // the system console is shown when a dedicated server is running void Sys_DisplaySystemConsole( qboolean show ); int Sys_GetProcessorId( void ); +int Sys_GetCPUSpeed( void ); +int Sys_GetPhysicalMemory(void); void Sys_BeginStreamedFile( fileHandle_t f, int readahead ); void Sys_EndStreamedFile( fileHandle_t f ); diff --git a/CODE-mp/qcommon/sstring.h b/CODE-mp/qcommon/sstring.h index b370543..1b01eca 100644 --- a/CODE-mp/qcommon/sstring.h +++ b/CODE-mp/qcommon/sstring.h @@ -80,7 +80,7 @@ public: } bool operator==(const sstring &o) const { - if (!strcmpi(mStorage.data,o.mStorage.data)) + if (!Q_stricmp(mStorage.data,o.mStorage.data)) { return true; } @@ -88,7 +88,7 @@ public: } bool operator!=(const sstring &o) const { - if (strcmpi(mStorage.data,o.mStorage.data)!=0) + if (Q_stricmp(mStorage.data,o.mStorage.data)!=0) { return true; } @@ -96,7 +96,7 @@ public: } bool operator<(const sstring &o) const { - if (strcmpi(mStorage.data,o.mStorage.data)<0) + if (Q_stricmp(mStorage.data,o.mStorage.data)<0) { return true; } @@ -104,7 +104,7 @@ public: } bool operator>(const sstring &o) const { - if (strcmpi(mStorage.data,o.mStorage.data)>0) + if (Q_stricmp(mStorage.data,o.mStorage.data)>0) { return true; } diff --git a/CODE-mp/qcommon/stri.cpp b/CODE-mp/qcommon/stri.cpp new file mode 100644 index 0000000..3299d75 --- /dev/null +++ b/CODE-mp/qcommon/stri.cpp @@ -0,0 +1,1717 @@ +// this include must remain at the top of every CPP file +#include "../server/server.h" +#include "../game/q_shared.h" +#include "qcommon.h" +#include "sstring.h" + + +/* +#if !defined(G_LOCAL_H_INC) + #include "..\game\g_local.h" +#endif +*/ + +//#include "stdafx.h" + +#ifndef _STRIPED_ +// #include "parental.h" + #include "strip.h" +// #include "../qcommon/palette.h" +#endif + + + +#ifdef _STRIPED_ + + #include "resource.h" // main symbols + #include "SP_ConfigFile.h" + +cStringPackageED *StringPackage = NULL; + +char LanguageList[LANGUAGELIST_MAX][LANGUAGE_LENGTH]; +char FlagList[FLAGLIST_MAX][FLAG_LENGTH]; + +#else + +static cvar_t *sp_language; +static cvar_t *sp_show_strip; + +#endif + +/* +void LogFile(char *Text, ...) +{ + char Buffer[16384]; + va_list argptr; + FILE *FH; + + va_start (argptr,Text); + vsprintf (Buffer,Text,argptr); + va_end (argptr); + + FH = fopen("c:\\striped.log", "r+"); + if (!FH) + { + FH = fopen("c:\\striped.log", "w"); + } + else + { + fseek(FH, 0, SEEK_END); + } + fprintf(FH, "%s", Buffer); + fclose(FH); +} +*/ + +enum +{ + TK_INVALID = -1, + TK_VERSION = 0, + TK_ID, + TK_REFERENCE, + TK_DESCRIPTION, + TK_COUNT, + TK_FLAGS, + TK_SP_FLAG1, + TK_SP_FLAG2, + TK_SP_FLAG3, + TK_SP_FLAG4, + TK_SP_FLAG5, + TK_SP_FLAG6, + TK_SP_FLAG7, + TK_SP_FLAG8, + TK_SP_FLAG9, + TK_SP_FLAG_ORIGINAL, + TK_LEFT_BRACE, + TK_RIGHT_BRACE, + TK_INDEX, + TK_NOTES, + TK_CONFIG, + TK_TEXT_LANGUAGE1, + TK_TEXT_LANGUAGE2, + TK_TEXT_LANGUAGE3, + TK_TEXT_LANGUAGE4, + TK_TEXT_LANGUAGE5, + TK_TEXT_LANGUAGE6, + TK_TEXT_LANGUAGE7, + TK_TEXT_LANGUAGE8, + TK_TEXT_LANGUAGE9, + TK_TEXT_LANGUAGE10, + TK_END +}; + + +char *Tokens[TK_END] = +{ + "VERSION", + "ID", + "REFERENCE", + "DESCRIPTION", + "COUNT", + "FLAGS", + "SP_FLAG1", + "SP_FLAG2", + "SP_FLAG3", + "SP_FLAG4", + "SP_FLAG5", + "SP_FLAG6", + "SP_FLAG7", + "SP_FLAG8", + "SP_FLAG9", + "SP_FLAG_ORIGINAL", + "{", + "}", + "INDEX", + "NOTES", + "CONFIG", + "TEXT_LANGUAGE1", + "TEXT_LANGUAGE2", + "TEXT_LANGUAGE3", + "TEXT_LANGUAGE4", + "TEXT_LANGUAGE5", + "TEXT_LANGUAGE6", + "TEXT_LANGUAGE7", + "TEXT_LANGUAGE8", + "TEXT_LANGUAGE9", + "TEXT_LANGUAGE10" +}; + + +sFlagPair FlagPairs[] = +{ + { TK_SP_FLAG1, SP_FLAG1 }, + { TK_SP_FLAG2, SP_FLAG2 }, + { TK_SP_FLAG3, SP_FLAG3 }, + { TK_SP_FLAG4, SP_FLAG4 }, + { TK_SP_FLAG5, SP_FLAG5 }, + { TK_SP_FLAG6, SP_FLAG6 }, + { TK_SP_FLAG7, SP_FLAG7 }, + { TK_SP_FLAG8, SP_FLAG8 }, + { TK_SP_FLAG9, SP_FLAG9 }, + { TK_SP_FLAG_ORIGINAL, SP_FLAG_ORIGINAL }, + { TK_INVALID, 0 } +}; + +sFlagPair LanguagePairs[] = +{ + { TK_TEXT_LANGUAGE1, SP_LANGUAGE_ENGLISH }, + { TK_TEXT_LANGUAGE2, SP_LANGUAGE_FRENCH }, + { TK_TEXT_LANGUAGE3, SP_LANGUAGE_GERMAN }, + { TK_TEXT_LANGUAGE4, SP_LANGUAGE_BRITISH }, + { TK_TEXT_LANGUAGE5, SP_LANGUAGE_KOREAN }, + { TK_TEXT_LANGUAGE6, SP_LANGUAGE_TAIWANESE }, + { TK_TEXT_LANGUAGE7, SP_LANGUAGE_ITALIAN }, + { TK_TEXT_LANGUAGE8, SP_LANGUAGE_SPANISH }, + { TK_TEXT_LANGUAGE9, SP_LANGUAGE_JAPANESE }, + { TK_TEXT_LANGUAGE10, SP_LANGUAGE_10}, + { TK_INVALID, 0 } +}; + +/************************************************************************************************ + * FindToken + * + * inputs: + * token string + * flag indicating if token string is partial or not + * + * return: + * token enum + * + ************************************************************************************************/ +int FindToken(char *token, bool whole) +{ + int token_value; + int i; + + for(token_value = 0; token_value != TK_END; token_value++) + { + if (whole) + { + if (Q_stricmp(token, Tokens[token_value]) == 0) + { + return token_value; + } + } + else + { + if (Q_stricmpn(token, Tokens[token_value], strlen(Tokens[token_value])) == 0) + { + i = strlen(Tokens[token_value]); + while(token[i] == ' ') + { + i++; + } + memmove(token, &token[i], strlen(token)-i+1); + + return token_value; + } + } + } + + return TK_INVALID; +} + +/************************************************************************************************ + * ReadData + * + * inputs: + * + * return: + * + ************************************************************************************************/ +bool ReadData(char *&Data, int &Size, char *Result, int Result_Size) +{ + char *pos; + + Result[0] = 0; + + if (Size <= 0) + { + return false; + } + pos = Result; + do + { + *pos = *Data; + pos++; + Data++; + Size--; + Result_Size--; + } while(Size > 0 && Result_Size > 0 && *(Data-1) != '\n'); + + *pos = 0; + + return true; +} + +/************************************************************************************************ + * GetLine + * + * inputs: + * + * return: + * + ************************************************************************************************/ +void GetLine(char *&Data, int &Size, int &token, char *&data) +{ + static char save_data[8192]; + char temp_data[8192]; + char *test_token, *pos; + + save_data[0] = 0; + token = TK_INVALID; + data = save_data; + + if (!ReadData(Data, Size, temp_data, sizeof(temp_data))) + { + return; + } + +// strcpy(temp_data, " DATA \"test of the data\ntest test\ndfa dfd"); +// strcpy(temp_data, " DATA"); + + pos = temp_data; + while((*pos) && strchr(" \n\r", *pos)) + { // remove white space + pos++; + } + test_token = pos; + + while((*pos) && !strchr(" \n\r", *pos)) + { // scan until end of white space + pos++; + } + + if ((*pos)) + { + *pos = 0; + pos++; + } + token = FindToken(test_token, true); + + while((*pos) && strchr(" \n\r", *pos)) + { // remove white space + pos++; + } + + if ((*pos) == '\"') + { + pos++; + test_token = save_data; + memset(save_data, 0, sizeof(save_data)); + + while(((*pos) != '\"' || !strchr("\n\r", (*(pos+1)))) && (*pos)) + { + if ((*pos) == '\\' && (*(pos+1)) == 'n') + { +#ifdef _STRIPED_ + *test_token = '\r'; + test_token++; +#endif + *test_token = '\n'; + test_token++; + pos+=2; + continue; + } + + *test_token = *pos; + test_token++; + pos++; + } + + if ((*pos) == '\"') + { + *pos = 0; + } + } + else + { + test_token = pos; + while((*pos) && !strchr("\n\r", *pos)) + { // scan until end of white space + pos++; + } + *pos = 0; + + strcpy(save_data, test_token); + } +} + + +#ifdef _STRIPED_ + +/************************************************************************************************ + * SaveString + * + * inputs: + * + * return: + * + ************************************************************************************************/ +void SaveString(FILE *FH, char *data) +{ + fputc('\"', FH); + + if (data) + { + for(;*data;data++) + { + if ((*data) == '\r') + { + } + else if ((*data) == '\n') + { + fputc('\\', FH); + fputc('n', FH); + } + else + { + fputc(*data, FH); + } + } + } + + fputc('\"', FH); +} + +#endif + + +//====================================================================== + + +/************************************************************************************************ + * cCriteria + * + * inputs: + * + * return: + * + ************************************************************************************************/ +cCriteria::cCriteria(int initWhichLanguage) +{ + WhichLanguage = initWhichLanguage; +} + + +#ifdef _STRIPED_ + +/************************************************************************************************ + * cCriteriaED + * + * inputs: + * + * return: + * + ************************************************************************************************/ +cCriteriaED::cCriteriaED(int initWhichLanguage, cStringPackageED *initMerge) +:cCriteria(initWhichLanguage) +{ + Merge = initMerge; +} + +#endif + + +//====================================================================== + +/************************************************************************************************ + * cStrings + * + * inputs: + * + * return: + * + ************************************************************************************************/ +cStrings::cStrings(unsigned int initFlags, char *initReference) +{ + Flags = initFlags; + Reference = NULL; + + SetReference(initReference); +} + +/************************************************************************************************ + * ~cStrings + * + * inputs: + * + * return: + * + ************************************************************************************************/ +cStrings::~cStrings(void) +{ + Clear(); +} + +/************************************************************************************************ + * Clear + * + * inputs: + * + * return: + * + ************************************************************************************************/ +void cStrings::Clear(void) +{ + Flags = 0; + + if (Reference) + { + delete Reference; + Reference = NULL; + } +} + +/************************************************************************************************ + * SetFlags + * + * inputs: + * + * return: + * + ************************************************************************************************/ +void cStrings::SetFlags(unsigned int newFlags) +{ + Flags = newFlags; +} + + +void cStrings::SetReference(char *newReference) +{ + if (Reference) + { + delete Reference; + Reference = NULL; + } + + if (!newReference || !newReference[0]) + { + return; + } + + Reference = new char[strlen(newReference)+1]; + strcpy(Reference, newReference); +} + +bool cStrings::UnderstandToken(int token, char *data) +{ + sFlagPair *FlagPair; + + switch(token) + { + case TK_FLAGS: + while(token != TK_INVALID) + { + token = FindToken(data, false); + for(FlagPair = FlagPairs; FlagPair->Name != TK_INVALID; FlagPair++) + { + if (FlagPair->Name == token) + { + Flags |= FlagPair->Value; + break; + } + } + } + return true; + + case TK_REFERENCE: + SetReference(data); + return true; + + case TK_RIGHT_BRACE: + return false; + } + + if (token == TK_INVALID) + { + return false; + } + + return true; +} + +bool cStrings::SubSave(FILE *FH) +{ + sFlagPair *FlagPair; + + if (Flags) + { + fprintf(FH, " %s", Tokens[TK_FLAGS]); + for(FlagPair = FlagPairs; FlagPair->Name != TK_INVALID; FlagPair++) + { + if (Flags & FlagPair->Value) + { + fprintf(FH, " %s", Tokens[FlagPair->Name]); + } + } + fprintf(FH,"\n"); + } + + if (Reference) + { + fprintf(FH, " %s %s\n", Tokens[TK_REFERENCE], Reference); + } + + return true; +} + +bool cStrings::Save(FILE *FH) +{ + fprintf(FH,"%s\n", Tokens[TK_LEFT_BRACE]); + + SubSave(FH); + + fprintf(FH,"%s\n", Tokens[TK_RIGHT_BRACE]); + + return true; +} + +bool cStrings::Load(char *&Data, int &Size) +{ + int token; + char *data; + + Clear(); + + GetLine(Data, Size, token, data); + if (token != TK_LEFT_BRACE) + { + return false; + } + + GetLine(Data, Size, token, data); + while (UnderstandToken(token, data)) + { + GetLine(Data, Size, token, data); + } + + if (token != TK_RIGHT_BRACE) + { + return false; + } + + return true; +} + + + + + + + +#ifdef _STRIPED_ + +cStringsED::cStringsED(unsigned int initFlags, char *initReference, char *initNotes) +:cStrings(initFlags, initReference) +{ + int i; + + Used = false; + Notes = NULL; + + for(i=0;iName != TK_INVALID; LanguagePair++) + { + if (LanguagePair->Name == token) + { + SetText(LanguagePair->Value, data); + return true; + } + } + + return cStrings::UnderstandToken(token, data, Criteria); + } +} + +bool cStringsED::SubSave(FILE *FH, cCriteria &Criteria) +{ + int i; + sFlagPair *LanguagePair; + + cStrings::SubSave(FH, Criteria); + + if (Notes) + { + fprintf(FH, " %s ", Tokens[TK_NOTES]); + SaveString(FH, Notes); + fprintf(FH, "\n"); + } + + for(i=0;iName != TK_INVALID; LanguagePair++) + { + if (i == (int)LanguagePair->Value) + { + fprintf(FH, " %s ",Tokens[LanguagePair->Name]); + SaveString(FH, Text[i]); + fprintf(FH, "\n"); + } + } + } + } + + return true; +} + +bool cStringsED::Load(char *&Data, int &Size, cCriteria &Criteria) +{ + if (cStrings::Load(Data, Size, Criteria)) + { + Used = true; + return true; + } + + return false; +} + +#endif + + + +#ifndef _STRIPED_ + +cStringsSingle::cStringsSingle(unsigned int initFlags, char *initReference) +:cStrings(initFlags, initReference) +{ + Text = NULL; +} + +cStringsSingle::~cStringsSingle() +{ + Clear(); +} + +void cStringsSingle::Clear(void) +{ + cStrings::Clear(); + + if (Text) + { + delete Text; + Text = NULL; + } +} + +void cStringsSingle::SetText(const char *newText) +{ + int length; + char *Dest; + + if (Text) + { + delete Text; + Text = NULL; + } + + if (!newText || !newText[0]) + { + return; + } + + length = strlen(newText)+1; + +#ifndef _STRIPED_ + // Following is for TESTING for SOF. + if(sp_show_strip->value) + { + Dest = Text = new char[length + 6]; + strcpy(Dest,"STRIP-"); + Dest += strlen(Dest); + } + else +#endif + { + Dest = Text = new char[length]; + } + strcpy(Dest, newText); +} + +// fix problems caused by fucking morons entering clever "rich" chars in to new text files *after* the auto-stripper +// removed them all in the first place... +// +// ONLY DO THIS FOR ENGLISH, OR IT BREAKS ASIAN STRINGS!!!!!!!!!!!!!!!!!!!!! +// +static void FixIllegalChars(char *psText) +{ + char *p; + +// strXLS_Speech.Replace(va("%c",0x92),va("%c",0x27)); // "'" + while ((p=strchr(psText,0x92))!=NULL) // "rich" (and illegal) apostrophe + { + *p = 0x27; + } + +// strXLS_Speech.Replace(va("%c",0x93),"\""); // smart quotes -> '"' + while ((p=strchr(psText,0x93))!=NULL) // "rich" (and illegal) apostrophe + { + *p = '"'; + } + +// strXLS_Speech.Replace(va("%c",0x94),"\""); // smart quotes -> '"' + while ((p=strchr(psText,0x94))!=NULL) // "rich" (and illegal) apostrophe + { + *p = '"'; + } + +// strXLS_Speech.Replace(va("%c",0x0B),"."); // full stop + while ((p=strchr(psText,0x0B))!=NULL) // "rich" (and illegal) apostrophe + { + *p = '.'; + } + +// strXLS_Speech.Replace(va("%c",0x85),"..."); // "..."-char -> 3-char "..." + while ((p=strchr(psText,0x85))!=NULL) // "rich" (and illegal) apostrophe + { + *p = '.'; // can't do in-string replace of "." with "...", so just forget it + } + +// strXLS_Speech.Replace(va("%c",0x91),va("%c",0x27)); // "'" + while ((p=strchr(psText,0x91))!=NULL) // "rich" (and illegal) apostrophe + { + *p = 0x27; + } + +// strXLS_Speech.Replace(va("%c",0x96),va("%c",0x2D)); // "-" + while ((p=strchr(psText,0x96))!=NULL) + { + *p = 0x2D; + } + +// strXLS_Speech.Replace(va("%c",0x97),va("%c",0x2D)); // "-" + while ((p=strchr(psText,0x97))!=NULL) + { + *p = 0x2D; + } +} + +bool cStringsSingle::UnderstandToken(int token, char *data) +{ + sFlagPair *LanguagePair; + +// switch(token) +// { +// default: + + for(LanguagePair = LanguagePairs; LanguagePair->Name != TK_INVALID; LanguagePair++) + { + if (LanguagePair->Name == TK_TEXT_LANGUAGE1 && token == TK_TEXT_LANGUAGE1 && !Text) + { // default to english in case there is no foreign + if (LanguagePair->Name == TK_TEXT_LANGUAGE1) + { + FixIllegalChars(data); + } + SetText(data); + return true; + } + else if (LanguagePair->Name == token && LanguagePair->Value == (int)sp_language->value) + { + if (LanguagePair->Name == TK_TEXT_LANGUAGE1) + { + FixIllegalChars(data); + } + SetText(data); + return true; + } + } + + return cStrings::UnderstandToken(token, data); +// } +} + +#endif + + + + + + + + +cStringPackage::cStringPackage(const char *in, unsigned char initID, char *initDescription, char *initReference) +{ + ID = initID; + Registration = 0; + name = in; + Reference = NULL; + + SetReference(initReference); +} + +cStringPackage::~cStringPackage(void) +{ + if (Reference) + { + delete Reference; + Reference = NULL; + } +} + +void cStringPackage::SetReference(char *newReference) +{ + if (Reference) + { + delete Reference; + Reference = NULL; + } + + if (!newReference || !newReference[0]) + { + return; + } + + Reference = new char[strlen(newReference)+1]; + strcpy(Reference, newReference); +} + +#ifndef _STRIPED_ + +bool cStringPackage::UnderstandToken(char *&Data, int &Size, int token, char *data ) +{ + cCriteria FullCriteria; + + switch(token) + { + case TK_ID: + ID = (unsigned char)atol(data); + return true; + + case TK_CONFIG: +#ifdef _STRIPED_ + ConfigFile.Load(data,FullCriteria); +#endif + return true; + + case TK_REFERENCE: +#ifdef _STRIPED_ + if (Reference) + { + char temp[1024]; + + sprintf(temp, "Please get RJ about this error! Do NOT save or do anything! OldRefeence: %s, New: %s", Reference, data); + MessageBox(NULL, temp, "RJ Error!", MB_OK); + } +#endif + SetReference(data); + return true; + } + + if (token == TK_INVALID) + { + return false; + } + + return true; +} + +#endif + +bool cStringPackage::SubSave(FILE *FH ) +{ + fprintf(FH,"%s %d\n",Tokens[TK_ID], ID); + + if (Reference) + { + fprintf(FH,"%s %s\n", Tokens[TK_REFERENCE], Reference); + } + + return true; +} + +#ifdef _STRIPED_ + +bool cStringPackage::Save(char *FileName) +{ + FILE *FH; + + FH = fopen(FileName,"w"); + if (!FH) + { + return false; + } + + fprintf(FH,"%s %d\n",Tokens[TK_VERSION], STRIP_VERSION); + fprintf(FH,"%s %s\n",Tokens[TK_CONFIG], ConfigFile.fileName); + + SubSave(FH); + + fclose(FH); + + return true; +} +#endif + +bool cStringPackage::Load(char *FileName) +{ + FILE *FH; + int Size; + char *buffer; + + FH = fopen(FileName,"rb"); + if (!FH) + { + return false; + } + + fseek(FH, 0, SEEK_END); + Size = ftell(FH); + fseek(FH, 0, SEEK_SET); + + buffer = new char[Size]; + fread(buffer, 1, Size, FH); + fclose(FH); + + Load(buffer, Size); + + delete buffer; + + return true; +} + +bool cStringPackage::Load(char *Data, int &Size) +{ + char *token_data; + int token; + + GetLine(Data, Size, token, token_data); + if (token != TK_VERSION || atol(token_data) != STRIP_VERSION) + { + return false; + } + + GetLine(Data, Size, token, token_data); + while (UnderstandToken(Data, Size, token, token_data )) + { + GetLine(Data, Size, token, token_data); + } + + return true; +} + + + +#ifdef _STRIPED_ + + +cStringPackageED::cStringPackageED(unsigned char initID, char *initDescription, char *initReference) +:cStringPackage("", initID, initReference) +{ + Description = NULL; + + SetDescription(initDescription); +} + +cStringPackageED::~cStringPackageED(void) +{ + if (Description) + { + delete Description; + Description = NULL; + } +} + +void cStringPackageED::SetDescription(char *newDescription) +{ + if (Description) + { + delete Description; + Description = NULL; + } + + if (!newDescription || !newDescription[0]) + { + return; + } + + Description = new char[strlen(newDescription)+1]; + strcpy(Description, newDescription); +} + +cStringsED *cStringPackageED::FindString(int &index) +{ + if (index == -1) + { + for(index=0;index::iterator i; + int size; + + if (!Reference) + { + return -1; + } + + size = strlen(Reference); + if (strlen(ReferenceLookup) < size+2) + { + return -1; + } + + if (strncmp(ReferenceLookup, Reference, size)) + { + return -1; + } + + i = ReferenceTable.find(string(ReferenceLookup + size + 1)); + if (i != ReferenceTable.end()) + { + return (*i).second; + } + + return -1; +} + +bool cStringPackageSingle::UnderstandToken(char *&Data, int &Size, int token, char *data ) +{ + int count, i, pos; + char *ReferenceLookup; + + switch(token) + { + case TK_COUNT: + count = atol(data); + + for(i=0;i SP_ListByName; +map SP_ListByID; + + +// Registration +cStringPackageSingle *SP_Register(const char *inPackage, unsigned char Registration) +{ + char *buffer; + char Package[MAX_QPATH]; + int size; + cStringPackageSingle *new_sp; + map::iterator i; + + + assert(SP_ListByName.size() == SP_ListByID.size()); + + Q_strncpyz(Package, inPackage, MAX_QPATH); + Q_strupr(Package); + + i = SP_ListByName.find(Package); + if (i != SP_ListByName.end()) + { + new_sp = (*i).second; + } + else + { + size = FS_ReadFile(va("strip/%s.sp", Package), (void **)&buffer); + if (size == -1) + { + if ( Registration & SP_REGISTER_REQUIRED ) + { + Com_Error(ERR_FATAL, "Could not open string package '%s'", Package); + } + return NULL; + } + + // Create the new string package + new_sp = new cStringPackageSingle(Package); + new_sp->Load(buffer, size ); + FS_FreeFile(buffer); + + if (Registration & SP_REGISTER_CLIENT) + { + Com_DPrintf(S_COLOR_YELLOW "SP_Register: Registered client string package '%s' with ID %02x\n", Package, (int)new_sp->GetID()); + } + else + { + Com_DPrintf(S_COLOR_YELLOW "SP_Register: Registered string package '%s' with ID %02x\n", Package, (int)new_sp->GetID()); + } + + // Insert into the name vs package map + SP_ListByName[Package] = new_sp; + // Insert into the id vs package map + SP_ListByID[new_sp->GetID()] = new_sp; + } + // Or in the new registration data + new_sp->Register(Registration); + + return new_sp; +} + +// Update configstrings array on clients and server +void SP_RegisterServer(const char *Package) +{ + cStringPackageSingle *sp; + + sp = SP_Register(Package, SP_REGISTER_SERVER); + if (sp) + { + SV_AddConfigstring(Package,CS_STRING_PACKAGES,MAX_STRING_PACKAGES); + } +} + +// Unload all packages with the relevant registration bits +void SP_Unload(unsigned char Registration) +{ + map::iterator i, next; + map::iterator id; + + assert(SP_ListByName.size() == SP_ListByID.size()); + + for(i = SP_ListByName.begin(); i != SP_ListByName.end(); i = next) + { + next = i; + next++; + + if ((*i).second->UnRegister(Registration)) + { + Com_DPrintf(S_COLOR_YELLOW "SP_UnRegister: Package '%s' with ID %02x\n", (*i).first.c_str(), (int)(*i).second->GetID()); + + id = SP_ListByID.find((*i).second->GetID()); + SP_ListByID.erase(id); + delete (*i).second; + SP_ListByName.erase(i); + } + } + +} + +// Direct string functions + +int SP_GetStringID(const char *Reference) +{ + map::iterator i; + int ID; + + for(i = SP_ListByID.begin(); i != SP_ListByID.end(); i++) + { + ID = (*i).second->FindStringID(Reference); + if (ID >= 0) + { + ID |= ((int)(*i).first) << 8; + return ID; + } + } + return -1; +} + +/************************************************************************************************ + * SP_GetString + * + * inputs: + * ID of the string package + * + * return: + * pointer to desired String Package + * + ************************************************************************************************/ +cStringsSingle *SP_GetString(unsigned short ID) +{ + cStringPackageSingle *sp; + cStringsSingle *string; + map::iterator i; + + i = SP_ListByID.find(SP_GET_PACKAGE(ID)); + if (i == SP_ListByID.end()) + { + Com_Error(ERR_DROP, "String package not registered for ID %04x", ID); + + return NULL; + } + + sp = (*i).second; + string = sp->FindString(ID & SP_STRING); + + if (!string) + { + Com_Error(ERR_DROP, "String ID %04x not defined\n", ID); + } + + return string; +} + +cStringsSingle *SP_GetString(const char *Reference) +{ + int index; + + index = SP_GetStringID(Reference); + if (index == -1) + { + return NULL; + } + + return SP_GetString(index); +} + + +const char *SP_GetStringText(unsigned short ID) +{ + cStringsSingle *string; + char *value; + + string = SP_GetString(ID); + + value = string->GetText(); + if (!value) + { + value = ""; + } + + return value; +} + +const char *SP_GetStringTextString(const char *Reference) +{ + int index; + + index = SP_GetStringID(Reference); + if (index == -1) + { + return ""; + } + + return SP_GetStringText(index); +} + + +static void SP_UpdateLanguage(void) +{ + map::iterator it; + list sps; + list::iterator spit; + + // Grab all SP ids + for(it = SP_ListByID.begin(); it != SP_ListByID.end(); it++) + { + sps.push_back(cStringPackageID((*it).second->GetName(), (*it).second->GetRegistration())); + } + // Clear out all pointers + SP_Unload(SP_REGISTER_CLIENT | SP_REGISTER_SERVER | SP_REGISTER_MENU | SP_REGISTER_REQUIRED); + + // Reinitialise with new language + for(spit = sps.begin(); spit != sps.end(); spit++) + { + SP_Register((*spit).GetName(), (*spit).GetReg()); + } + sps.clear(); +} + +void SP_Init(void) +{ + sp_language = Cvar_Get("sp_language", va("%d", SP_LANGUAGE_ENGLISH), CVAR_ARCHIVE); + sp_show_strip = Cvar_Get ("sv_show_strip", "0", 0); + + SP_UpdateLanguage(); + sp_language->modified = qfalse; +} + +// called in Com_Frame, so don't take up any time! (can also be called during dedicated) +// +void SP_CheckForLanguageUpdates(void) +{ + if (sp_language && sp_language->modified) + { + SP_Init(); // force language package to reload + sp_language->modified = qfalse; + } +} + + +int Language_GetIntegerValue(void) +{ + if (sp_language) + { + return sp_language->integer; + } + + return 0; +} + +#endif + diff --git a/CODE-mp/qcommon/strip.cpp b/CODE-mp/qcommon/strip.cpp index 81eb708..e0aaca4 100644 --- a/CODE-mp/qcommon/strip.cpp +++ b/CODE-mp/qcommon/strip.cpp @@ -3,7 +3,9 @@ #include "../game/q_shared.h" #include "qcommon.h" - +//#ifdef _DEBUG +//#include +//#endif /* #if !defined(G_LOCAL_H_INC) @@ -33,7 +35,7 @@ char FlagList[FLAGLIST_MAX][FLAG_LENGTH]; #else -static cvar_t *sp_language; +/*static*/ cvar_t *sp_language; static cvar_t *sp_show_strip; #endif @@ -806,7 +808,7 @@ void cStringsSingle::SetText(const char *newText) if(sp_show_strip->value) { Dest = Text = new char[length + 6]; - strcpy(Dest,"STRIP-"); + strcpy(Dest,"SP:"); Dest += strlen(Dest); } else @@ -873,6 +875,13 @@ static void FixIllegalChars(char *psText) { *p = 0x2D; } + + // StripEd and our print code don't support tabs... + // + while ((p=strchr(psText,0x09))!=NULL) + { + *p = ' '; + } } bool cStringsSingle::UnderstandToken(int token, char *data) @@ -887,7 +896,10 @@ bool cStringsSingle::UnderstandToken(int token, char *data) { if (LanguagePair->Name == TK_TEXT_LANGUAGE1 && token == TK_TEXT_LANGUAGE1 && !Text) { // default to english in case there is no foreign - if (LanguagePair->Name == TK_TEXT_LANGUAGE1) + if (LanguagePair->Name == TK_TEXT_LANGUAGE1 || + LanguagePair->Name == TK_TEXT_LANGUAGE2 || + LanguagePair->Name == TK_TEXT_LANGUAGE3 + ) { FixIllegalChars(data); } @@ -896,7 +908,10 @@ bool cStringsSingle::UnderstandToken(int token, char *data) } else if (LanguagePair->Name == token && LanguagePair->Value == (int)sp_language->value) { - if (LanguagePair->Name == TK_TEXT_LANGUAGE1) + if (LanguagePair->Name == TK_TEXT_LANGUAGE1 || + LanguagePair->Name == TK_TEXT_LANGUAGE2 || + LanguagePair->Name == TK_TEXT_LANGUAGE3 + ) { FixIllegalChars(data); } @@ -1413,6 +1428,15 @@ int cStringPackageSingle::FindStringID(const char *ReferenceLookup) return (*i).second; } + +//#ifdef _DEBUG +// // findmeste +// for (map::iterator it = ReferenceTable.begin(); it != ReferenceTable.end(); ++it) +// { +// OutputDebugString(va("%s\n",(*it).first.c_str())); +// } +//#endif + return -1; } @@ -1525,7 +1549,7 @@ cStringPackageSingle *SP_Register(const char *inPackage, unsigned char Registrat } // Update configstrings array on clients and server -void SP_RegisterServer(const char *Package) +qboolean SP_RegisterServer(const char *Package) { cStringPackageSingle *sp; @@ -1533,7 +1557,10 @@ void SP_RegisterServer(const char *Package) if (sp) { SV_AddConfigstring(Package,CS_STRING_PACKAGES,MAX_STRING_PACKAGES); + return qtrue; } + + return qfalse; } // Unload all packages with the relevant registration bits @@ -1564,10 +1591,13 @@ void SP_Unload(unsigned char Registration) // Direct string functions -int SP_GetStringID(const char *Reference) +int SP_GetStringID(const char *inReference) { map::iterator i; int ID; + char Reference[MAX_QPATH]; + Q_strncpyz(Reference, inReference, MAX_QPATH); + Q_strupr(Reference); for(i = SP_ListByID.begin(); i != SP_ListByID.end(); i++) { @@ -1684,8 +1714,8 @@ static void SP_UpdateLanguage(void) void SP_Init(void) { - sp_language = Cvar_Get("sp_language", va("%d", SP_LANGUAGE_ENGLISH), CVAR_ARCHIVE); - sp_show_strip = Cvar_Get ("sv_show_strip", "0", 0); + sp_language = Cvar_Get("sp_language", va("%d", SP_LANGUAGE_ENGLISH), CVAR_ARCHIVE | CVAR_NORESTART); + sp_show_strip = Cvar_Get ("sp_show_strip", "0", 0); SP_UpdateLanguage(); sp_language->modified = qfalse; diff --git a/CODE-mp/qcommon/strip.h b/CODE-mp/qcommon/strip.h index b461fb7..bfb94b0 100644 --- a/CODE-mp/qcommon/strip.h +++ b/CODE-mp/qcommon/strip.h @@ -292,7 +292,7 @@ extern char FlagList[FLAGLIST_MAX][FLAG_LENGTH]; // Registration cStringPackageSingle *SP_Register(const char *Package, unsigned char Registration); -void SP_RegisterServer(const char *Package); +qboolean SP_RegisterServer(const char *Package); void SP_Unload(unsigned char Registration); // Direct string functions diff --git a/CODE-mp/qcommon/vm_ppc.cpp b/CODE-mp/qcommon/vm_ppc.cpp new file mode 100644 index 0000000..266c34d --- /dev/null +++ b/CODE-mp/qcommon/vm_ppc.cpp @@ -0,0 +1,1274 @@ +// vm_ppc.c +// ppc dynamic compiler + +#include "vm_local.h" + +#pragma opt_pointer_analysis off + + +typedef enum { + R_REAL_STACK = 1, + // registers 3-11 are the parameter passing registers + + // state + R_STACK = 3, // local + R_OPSTACK, // global + + // constants + R_MEMBASE, // global + R_MEMMASK, + R_ASMCALL, // global + R_INSTRUCTIONS, // global + R_NUM_INSTRUCTIONS, // global + R_CVM, // currentVM + + // temps + R_TOP = 12, + R_SECOND = 13, + R_EA = 14 // effective address calculation + +} regNums_t; + +#define RG_REAL_STACK r1 +#define RG_STACK r3 +#define RG_OPSTACK r4 +#define RG_MEMBASE r5 +#define RG_MEMMASK r6 +#define RG_ASMCALL r7 +#define RG_INSTRUCTIONS r8 +#define RG_NUM_INSTRUCTIONS r9 +#define RG_CVM r10 +#define RG_TOP r12 +#define RG_SECOND r13 +#define RG_EA r14 + +// this doesn't have the low order bits set for instructions i'm not using... +typedef enum { + PPC_TDI = 0x08000000, + PPC_TWI = 0x0c000000, + PPC_MULLI = 0x1c000000, + PPC_SUBFIC = 0x20000000, + PPC_CMPI = 0x28000000, + PPC_CMPLI = 0x2c000000, + PPC_ADDIC = 0x30000000, + PPC_ADDIC_ = 0x34000000, + PPC_ADDI = 0x38000000, + PPC_ADDIS = 0x3c000000, + PPC_BC = 0x40000000, + PPC_SC = 0x44000000, + PPC_B = 0x48000000, + + PPC_MCRF = 0x4c000000, + PPC_BCLR = 0x4c000020, + PPC_RFID = 0x4c000000, + PPC_CRNOR = 0x4c000000, + PPC_RFI = 0x4c000000, + PPC_CRANDC = 0x4c000000, + PPC_ISYNC = 0x4c000000, + PPC_CRXOR = 0x4c000000, + PPC_CRNAND = 0x4c000000, + PPC_CREQV = 0x4c000000, + PPC_CRORC = 0x4c000000, + PPC_CROR = 0x4c000000, +//------------ + PPC_BCCTR = 0x4c000420, + PPC_RLWIMI = 0x50000000, + PPC_RLWINM = 0x54000000, + PPC_RLWNM = 0x5c000000, + PPC_ORI = 0x60000000, + PPC_ORIS = 0x64000000, + PPC_XORI = 0x68000000, + PPC_XORIS = 0x6c000000, + PPC_ANDI_ = 0x70000000, + PPC_ANDIS_ = 0x74000000, + PPC_RLDICL = 0x78000000, + PPC_RLDICR = 0x78000000, + PPC_RLDIC = 0x78000000, + PPC_RLDIMI = 0x78000000, + PPC_RLDCL = 0x78000000, + PPC_RLDCR = 0x78000000, + PPC_CMP = 0x7c000000, + PPC_TW = 0x7c000000, + PPC_SUBFC = 0x7c000010, + PPC_MULHDU = 0x7c000000, + PPC_ADDC = 0x7c000014, + PPC_MULHWU = 0x7c000000, + PPC_MFCR = 0x7c000000, + PPC_LWAR = 0x7c000000, + PPC_LDX = 0x7c000000, + PPC_LWZX = 0x7c00002e, + PPC_SLW = 0x7c000030, + PPC_CNTLZW = 0x7c000000, + PPC_SLD = 0x7c000000, + PPC_AND = 0x7c000038, + PPC_CMPL = 0x7c000040, + PPC_SUBF = 0x7c000050, + PPC_LDUX = 0x7c000000, +//------------ + PPC_DCBST = 0x7c000000, + PPC_LWZUX = 0x7c00006c, + PPC_CNTLZD = 0x7c000000, + PPC_ANDC = 0x7c000000, + PPC_TD = 0x7c000000, + PPC_MULHD = 0x7c000000, + PPC_MULHW = 0x7c000000, + PPC_MTSRD = 0x7c000000, + PPC_MFMSR = 0x7c000000, + PPC_LDARX = 0x7c000000, + PPC_DCBF = 0x7c000000, + PPC_LBZX = 0x7c0000ae, + PPC_NEG = 0x7c000000, + PPC_MTSRDIN = 0x7c000000, + PPC_LBZUX = 0x7c000000, + PPC_NOR = 0x7c0000f8, + PPC_SUBFE = 0x7c000000, + PPC_ADDE = 0x7c000000, + PPC_MTCRF = 0x7c000000, + PPC_MTMSR = 0x7c000000, + PPC_STDX = 0x7c000000, + PPC_STWCX_ = 0x7c000000, + PPC_STWX = 0x7c00012e, + PPC_MTMSRD = 0x7c000000, + PPC_STDUX = 0x7c000000, + PPC_STWUX = 0x7c00016e, + PPC_SUBFZE = 0x7c000000, + PPC_ADDZE = 0x7c000000, + PPC_MTSR = 0x7c000000, + PPC_STDCX_ = 0x7c000000, + PPC_STBX = 0x7c0001ae, + PPC_SUBFME = 0x7c000000, + PPC_MULLD = 0x7c000000, +//------------ + PPC_ADDME = 0x7c000000, + PPC_MULLW = 0x7c0001d6, + PPC_MTSRIN = 0x7c000000, + PPC_DCBTST = 0x7c000000, + PPC_STBUX = 0x7c000000, + PPC_ADD = 0x7c000214, + PPC_DCBT = 0x7c000000, + PPC_LHZX = 0x7c00022e, + PPC_EQV = 0x7c000000, + PPC_TLBIE = 0x7c000000, + PPC_ECIWX = 0x7c000000, + PPC_LHZUX = 0x7c000000, + PPC_XOR = 0x7c000278, + PPC_MFSPR = 0x7c0002a6, + PPC_LWAX = 0x7c000000, + PPC_LHAX = 0x7c000000, + PPC_TLBIA = 0x7c000000, + PPC_MFTB = 0x7c000000, + PPC_LWAUX = 0x7c000000, + PPC_LHAUX = 0x7c000000, + PPC_STHX = 0x7c00032e, + PPC_ORC = 0x7c000338, + PPC_SRADI = 0x7c000000, + PPC_SLBIE = 0x7c000000, + PPC_ECOWX = 0x7c000000, + PPC_STHUX = 0x7c000000, + PPC_OR = 0x7c000378, + PPC_DIVDU = 0x7c000000, + PPC_DIVWU = 0x7c000396, + PPC_MTSPR = 0x7c0003a6, + PPC_DCBI = 0x7c000000, + PPC_NAND = 0x7c000000, + PPC_DIVD = 0x7c000000, +//------------ + PPC_DIVW = 0x7c0003d6, + PPC_SLBIA = 0x7c000000, + PPC_MCRXR = 0x7c000000, + PPC_LSWX = 0x7c000000, + PPC_LWBRX = 0x7c000000, + PPC_LFSX = 0x7c000000, + PPC_SRW = 0x7c000430, + PPC_SRD = 0x7c000000, + PPC_TLBSYNC = 0x7c000000, + PPC_LFSUX = 0x7c000000, + PPC_MFSR = 0x7c000000, + PPC_LSWI = 0x7c000000, + PPC_SYNC = 0x7c000000, + PPC_LFDX = 0x7c000000, + PPC_LFDUX = 0x7c000000, + PPC_MFSRIN = 0x7c000000, + PPC_STSWX = 0x7c000000, + PPC_STWBRX = 0x7c000000, + PPC_STFSX = 0x7c000000, + PPC_STFSUX = 0x7c000000, + PPC_STSWI = 0x7c000000, + PPC_STFDX = 0x7c000000, + PPC_DCBA = 0x7c000000, + PPC_STFDUX = 0x7c000000, + PPC_LHBRX = 0x7c000000, + PPC_SRAW = 0x7c000630, + PPC_SRAD = 0x7c000000, + PPC_SRAWI = 0x7c000000, + PPC_EIEIO = 0x7c000000, + PPC_STHBRX = 0x7c000000, + PPC_EXTSH = 0x7c000734, + PPC_EXTSB = 0x7c000774, + PPC_ICBI = 0x7c000000, +//------------ + PPC_STFIWX = 0x7c0007ae, + PPC_EXTSW = 0x7c000000, + PPC_DCBZ = 0x7c000000, + PPC_LWZ = 0x80000000, + PPC_LWZU = 0x84000000, + PPC_LBZ = 0x88000000, + PPC_LBZU = 0x8c000000, + PPC_STW = 0x90000000, + PPC_STWU = 0x94000000, + PPC_STB = 0x98000000, + PPC_STBU = 0x9c000000, + PPC_LHZ = 0xa0000000, + PPC_LHZU = 0xa4000000, + PPC_LHA = 0xa8000000, + PPC_LHAU = 0xac000000, + PPC_STH = 0xb0000000, + PPC_STHU = 0xb4000000, + PPC_LMW = 0xb8000000, + PPC_STMW = 0xbc000000, + PPC_LFS = 0xc0000000, + PPC_LFSU = 0xc4000000, + PPC_LFD = 0xc8000000, + PPC_LFDU = 0xcc000000, + PPC_STFS = 0xd0000000, + PPC_STFSU = 0xd4000000, + PPC_STFD = 0xd8000000, + PPC_STFDU = 0xdc000000, + PPC_LD = 0xe8000000, + PPC_LDU = 0xe8000001, + PPC_LWA = 0xe8000002, + PPC_FDIVS = 0xec000024, + PPC_FSUBS = 0xec000028, + PPC_FADDS = 0xec00002a, +//------------ + PPC_FSQRTS = 0xec000000, + PPC_FRES = 0xec000000, + PPC_FMULS = 0xec000032, + PPC_FMSUBS = 0xec000000, + PPC_FMADDS = 0xec000000, + PPC_FNMSUBS = 0xec000000, + PPC_FNMADDS = 0xec000000, + PPC_STD = 0xf8000000, + PPC_STDU = 0xf8000001, + PPC_FCMPU = 0xfc000000, + PPC_FRSP = 0xfc000018, + PPC_FCTIW = 0xfc000000, + PPC_FCTIWZ = 0xfc00001e, + PPC_FDIV = 0xfc000000, + PPC_FSUB = 0xfc000028, + PPC_FADD = 0xfc000000, + PPC_FSQRT = 0xfc000000, + PPC_FSEL = 0xfc000000, + PPC_FMUL = 0xfc000000, + PPC_FRSQRTE = 0xfc000000, + PPC_FMSUB = 0xfc000000, + PPC_FMADD = 0xfc000000, + PPC_FNMSUB = 0xfc000000, + PPC_FNMADD = 0xfc000000, + PPC_FCMPO = 0xfc000000, + PPC_MTFSB1 = 0xfc000000, + PPC_FNEG = 0xfc000050, + PPC_MCRFS = 0xfc000000, + PPC_MTFSB0 = 0xfc000000, + PPC_FMR = 0xfc000000, + PPC_MTFSFI = 0xfc000000, + PPC_FNABS = 0xfc000000, + PPC_FABS = 0xfc000000, +//------------ + PPC_MFFS = 0xfc000000, + PPC_MTFSF = 0xfc000000, + PPC_FCTID = 0xfc000000, + PPC_FCTIDZ = 0xfc000000, + PPC_FCFID = 0xfc000000 + +} ppcOpcodes_t; + + +// the newly generated code +static unsigned *buf; +static int compiledOfs; // in dwords + +// fromt the original bytecode +static byte *code; +static int pc; + +void AsmCall( void ); + +double itofConvert[2]; + +static int Constant4( void ) { + int v; + + v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24); + pc += 4; + return v; +} + +static int Constant1( void ) { + int v; + + v = code[pc]; + pc += 1; + return v; +} + +static void Emit4( int i ) { + buf[ compiledOfs ] = i; + compiledOfs++; +} + +static void Inst( int opcode, int destReg, int aReg, int bReg ) { + unsigned r; + + r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ; + buf[ compiledOfs ] = r; + compiledOfs++; +} + +static void Inst4( int opcode, int destReg, int aReg, int bReg, int cReg ) { + unsigned r; + + r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 ); + buf[ compiledOfs ] = r; + compiledOfs++; +} + +static void InstImm( int opcode, int destReg, int aReg, int immediate ) { + unsigned r; + + if ( immediate > 32767 || immediate < -32768 ) { + Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg ); + } + r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff ); + buf[ compiledOfs ] = r; + compiledOfs++; +} + +static void InstImmU( int opcode, int destReg, int aReg, int immediate ) { + unsigned r; + + if ( immediate > 0xffff || immediate < 0 ) { + Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate ); + } + r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff ); + buf[ compiledOfs ] = r; + compiledOfs++; +} + +static qboolean rtopped; +static int pop0, pop1, oc0, oc1; +static vm_t *tvm; +static int instruction; +static byte *jused; +static int pass; + +static void ltop() { + if (rtopped == qfalse) { + InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 ); // get value from opstack + } +} + +static void ltopandsecond() { + if (pass>=0 && buf[compiledOfs-1] == (PPC_STWU | R_TOP<<21 | R_OPSTACK<<16 | 4 ) && jused[instruction]==0 ) { + compiledOfs--; + if (!pass) { + tvm->instructionPointers[instruction] = compiledOfs * 4; + } + InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); + } else if (pass>=0 && buf[compiledOfs-1] == (PPC_STW | R_TOP<<21 | R_OPSTACK<<16 | 0 ) && jused[instruction]==0 ) { + compiledOfs--; + if (!pass) { + tvm->instructionPointers[instruction] = compiledOfs * 4; + } + InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 ); + } else { + ltop(); // get value from opstack + InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 ); + } + rtopped = qfalse; +} + +// TJW: Unused +#if 0 +static void fltop() { + if (rtopped == qfalse) { + InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack + } +} +#endif + +static void fltopandsecond() { + InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack + InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 ); + rtopped = qfalse; + return; +} + +/* +================= +VM_Compile +================= +*/ +void VM_Compile( vm_t *vm, vmHeader_t *header ) { + int op; + int maxLength; + int v; + int i; + + // set up the into-to-float variables + ((int *)itofConvert)[0] = 0x43300000; + ((int *)itofConvert)[1] = 0x80000000; + ((int *)itofConvert)[2] = 0x43300000; + + // allocate a very large temp buffer, we will shrink it later + maxLength = header->codeLength * 8; + buf = Z_Malloc( maxLength ); + jused = Z_Malloc(header->instructionCount + 2); + Com_Memset(jused, 0, header->instructionCount+2); + + // compile everything twice, so the second pass will have valid instruction + // pointers for branches + for ( pass = -1 ; pass < 2 ; pass++ ) { + + rtopped = qfalse; + // translate all instructions + pc = 0; + + pop0 = 343545; + pop1 = 2443545; + oc0 = -2343535; + oc1 = 24353454; + tvm = vm; + + code = (byte *)header + header->codeOffset; + compiledOfs = 0; +#ifndef __GNUC__ + // metrowerks seems to require this header in front of functions + Emit4( (int)(buf+2) ); + Emit4( 0 ); +#endif + + for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) { + if ( compiledOfs*4 > maxLength - 16 ) { + Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" ); + } + + op = code[ pc ]; + if ( !pass ) { + vm->instructionPointers[ instruction ] = compiledOfs * 4; + } + pc++; + switch ( op ) { + case 0: + break; + case OP_BREAK: + InstImmU( PPC_ADDI, R_TOP, 0, 0 ); + InstImm( PPC_LWZ, R_TOP, R_TOP, 0 ); // *(int *)0 to crash to debugger + rtopped = qfalse; + break; + case OP_ENTER: + InstImm( PPC_ADDI, R_STACK, R_STACK, -Constant4() ); // sub R_STACK, R_STACK, imm + rtopped = qfalse; + break; + case OP_CONST: + v = Constant4(); + if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) { + v &= vm->dataMask; + } + if ( v < 32768 && v >= -32768 ) { + InstImmU( PPC_ADDI, R_TOP, 0, v & 0xffff ); + } else { + InstImmU( PPC_ADDIS, R_TOP, 0, (v >> 16)&0xffff ); + if ( v & 0xffff ) { + InstImmU( PPC_ORI, R_TOP, R_TOP, v & 0xffff ); + } + } + if (code[pc] == OP_LOAD4) { + Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base + pc++; + instruction++; + } else if (code[pc] == OP_LOAD2) { + Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base + pc++; + instruction++; + } else if (code[pc] == OP_LOAD1) { + Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base + pc++; + instruction++; + } + if (code[pc] == OP_STORE4) { + InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); + //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it + Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base + pc++; + instruction++; + rtopped = qfalse; + break; + } else if (code[pc] == OP_STORE2) { + InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); + //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it + Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base + pc++; + instruction++; + rtopped = qfalse; + break; + } else if (code[pc] == OP_STORE1) { + InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); + //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it + Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base + pc++; + instruction++; + rtopped = qfalse; + break; + } + if (code[pc] == OP_JUMP) { + jused[v] = 1; + } + InstImm( PPC_STWU, R_TOP, R_OPSTACK, 4 ); + rtopped = qtrue; + break; + case OP_LOCAL: + oc0 = oc1; + oc1 = Constant4(); + if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) { + oc1 &= vm->dataMask; + } + InstImm( PPC_ADDI, R_TOP, R_STACK, oc1 ); + if (code[pc] == OP_LOAD4) { + Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base + pc++; + instruction++; + } else if (code[pc] == OP_LOAD2) { + Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base + pc++; + instruction++; + } else if (code[pc] == OP_LOAD1) { + Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base + pc++; + instruction++; + } + if (code[pc] == OP_STORE4) { + InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); + //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it + Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base + pc++; + instruction++; + rtopped = qfalse; + break; + } else if (code[pc] == OP_STORE2) { + InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); + //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it + Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base + pc++; + instruction++; + rtopped = qfalse; + break; + } else if (code[pc] == OP_STORE1) { + InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, 0 ); // get value from opstack + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); + //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it + Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base + pc++; + instruction++; + rtopped = qfalse; + break; + } + InstImm( PPC_STWU, R_TOP, R_OPSTACK, 4 ); + rtopped = qtrue; + break; + case OP_ARG: + ltop(); // get value from opstack + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); + InstImm( PPC_ADDI, R_EA, R_STACK, Constant1() ); // location to put it + Inst( PPC_STWX, R_TOP, R_EA, R_MEMBASE ); + rtopped = qfalse; + break; + case OP_CALL: + Inst( PPC_MFSPR, R_SECOND, 8, 0 ); // move from link register + InstImm( PPC_STWU, R_SECOND, R_REAL_STACK, -16 ); // save off the old return address + + Inst( PPC_MTSPR, R_ASMCALL, 9, 0 ); // move to count register + Inst( PPC_BCCTR | 1, 20, 0, 0 ); // jump and link to the count register + + InstImm( PPC_LWZ, R_SECOND, R_REAL_STACK, 0 ); // fetch the old return address + InstImm( PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 ); + Inst( PPC_MTSPR, R_SECOND, 8, 0 ); // move to link register + rtopped = qfalse; + break; + case OP_PUSH: + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, 4 ); + rtopped = qfalse; + break; + case OP_POP: + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); + rtopped = qfalse; + break; + case OP_LEAVE: + InstImm( PPC_ADDI, R_STACK, R_STACK, Constant4() ); // add R_STACK, R_STACK, imm + Inst( PPC_BCLR, 20, 0, 0 ); // branch unconditionally to link register + rtopped = qfalse; + break; + case OP_LOAD4: + ltop(); // get value from opstack + //Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP ); // mask it + Inst( PPC_LWZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); + rtopped = qtrue; + break; + case OP_LOAD2: + ltop(); // get value from opstack + //Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP ); // mask it + Inst( PPC_LHZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); + rtopped = qtrue; + break; + case OP_LOAD1: + ltop(); // get value from opstack + //Inst( PPC_AND, R_MEMMASK, R_TOP, R_TOP ); // mask it + Inst( PPC_LBZX, R_TOP, R_TOP, R_MEMBASE ); // load from memory base + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); + rtopped = qtrue; + break; + case OP_STORE4: + ltopandsecond(); // get value from opstack + //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it + Inst( PPC_STWX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base + rtopped = qfalse; + break; + case OP_STORE2: + ltopandsecond(); // get value from opstack + //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it + Inst( PPC_STHX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base + rtopped = qfalse; + break; + case OP_STORE1: + ltopandsecond(); // get value from opstack + //Inst( PPC_AND, R_MEMMASK, R_SECOND, R_SECOND ); // mask it + Inst( PPC_STBX, R_TOP, R_SECOND, R_MEMBASE ); // store from memory base + rtopped = qfalse; + break; + + case OP_EQ: + ltopandsecond(); // get value from opstack + Inst( PPC_CMP, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + InstImm( PPC_BC, 4, 2, 8 ); + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + Emit4(PPC_B | (v&0x3ffffff) ); + rtopped = qfalse; + break; + case OP_NE: + ltopandsecond(); // get value from opstack + Inst( PPC_CMP, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + InstImm( PPC_BC, 12, 2, 8 ); + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( PPC_BC, 4, 2, v ); + + rtopped = qfalse; + break; + case OP_LTI: + ltopandsecond(); // get value from opstack + Inst( PPC_CMP, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + InstImm( PPC_BC, 4, 0, 8 ); + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( PPC_BC, 12, 0, v ); + rtopped = qfalse; + break; + case OP_LEI: + ltopandsecond(); // get value from opstack + Inst( PPC_CMP, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + InstImm( PPC_BC, 12, 1, 8 ); + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( PPC_BC, 4, 1, v ); + rtopped = qfalse; + break; + case OP_GTI: + ltopandsecond(); // get value from opstack + Inst( PPC_CMP, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + InstImm( PPC_BC, 4, 1, 8 ); + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + Emit4(PPC_B | (unsigned int)(v&0x3ffffff) ); +// InstImm( PPC_BC, 12, 1, v ); + rtopped = qfalse; + break; + case OP_GEI: + ltopandsecond(); // get value from opstack + Inst( PPC_CMP, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + InstImm( PPC_BC, 4, 0, v ); + rtopped = qfalse; + break; + case OP_LTU: + ltopandsecond(); // get value from opstack + Inst( PPC_CMPL, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + InstImm( PPC_BC, 12, 0, v ); + rtopped = qfalse; + break; + case OP_LEU: + ltopandsecond(); // get value from opstack + Inst( PPC_CMPL, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + InstImm( PPC_BC, 4, 1, v ); + rtopped = qfalse; + break; + case OP_GTU: + ltopandsecond(); // get value from opstack + Inst( PPC_CMPL, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + InstImm( PPC_BC, 12, 1, v ); + rtopped = qfalse; + break; + case OP_GEU: + ltopandsecond(); // get value from opstack + Inst( PPC_CMPL, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + InstImm( PPC_BC, 4, 0, v ); + rtopped = qfalse; + break; + + case OP_EQF: + fltopandsecond(); // get value from opstack + Inst( PPC_FCMPU, 0, R_TOP, R_SECOND ); + i = Constant4(); + jused[i] = 1; + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + InstImm( PPC_BC, 12, 2, v ); + rtopped = qfalse; + break; + case OP_NEF: + fltopandsecond(); // get value from opstack + Inst( PPC_FCMPU, 0, R_TOP, R_SECOND ); + i = Constant4(); + jused[i] = 1; + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + InstImm( PPC_BC, 4, 2, v ); + rtopped = qfalse; + break; + case OP_LTF: + fltopandsecond(); // get value from opstack + Inst( PPC_FCMPU, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + InstImm( PPC_BC, 12, 0, v ); + rtopped = qfalse; + break; + case OP_LEF: + fltopandsecond(); // get value from opstack + Inst( PPC_FCMPU, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + InstImm( PPC_BC, 4, 1, v ); + rtopped = qfalse; + break; + case OP_GTF: + fltopandsecond(); // get value from opstack + Inst( PPC_FCMPU, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + InstImm( PPC_BC, 12, 1, v ); + rtopped = qfalse; + break; + case OP_GEF: + fltopandsecond(); // get value from opstack + Inst( PPC_FCMPU, 0, R_SECOND, R_TOP ); + i = Constant4(); + jused[i] = 1; + if ( pass==1 ) { + v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; + } else { + v = 0; + } + InstImm( PPC_BC, 4, 0, v ); + rtopped = qfalse; + break; + + case OP_NEGI: + ltop(); // get value from opstack + InstImm( PPC_SUBFIC, R_TOP, R_TOP, 0 ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_ADD: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_ADD, R_TOP, R_TOP, R_SECOND ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_SUB: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_SUBF, R_TOP, R_TOP, R_SECOND ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_DIVI: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_DIVW, R_TOP, R_SECOND, R_TOP ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_DIVU: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_DIVWU, R_TOP, R_SECOND, R_TOP ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_MODI: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_DIVW, R_EA, R_SECOND, R_TOP ); + Inst( PPC_MULLW, R_EA, R_TOP, R_EA ); + Inst( PPC_SUBF, R_TOP, R_EA, R_SECOND ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_MODU: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_DIVWU, R_EA, R_SECOND, R_TOP ); + Inst( PPC_MULLW, R_EA, R_TOP, R_EA ); + Inst( PPC_SUBF, R_TOP, R_EA, R_SECOND ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_MULI: + case OP_MULU: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_MULLW, R_TOP, R_SECOND, R_TOP ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_BAND: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_AND, R_SECOND, R_TOP, R_TOP ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_BOR: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_OR, R_SECOND, R_TOP, R_TOP ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_BXOR: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_XOR, R_SECOND, R_TOP, R_TOP ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_BCOM: + ltop(); // get value from opstack + Inst( PPC_NOR, R_TOP, R_TOP, R_TOP ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_LSH: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_SLW, R_SECOND, R_TOP, R_TOP ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_RSHI: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_SRAW, R_SECOND, R_TOP, R_TOP ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + case OP_RSHU: + ltop(); // get value from opstack + InstImm( PPC_LWZU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_SRW, R_SECOND, R_TOP, R_TOP ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qtrue; + break; + + case OP_NEGF: + InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack + Inst( PPC_FNEG, R_TOP, 0, R_TOP ); + InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qfalse; + break; + case OP_ADDF: + InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack + InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_FADDS, R_TOP, R_SECOND, R_TOP ); + InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qfalse; + break; + case OP_SUBF: + InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack + InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_FSUBS, R_TOP, R_SECOND, R_TOP ); + InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qfalse; + break; + case OP_DIVF: + InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack + InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst( PPC_FDIVS, R_TOP, R_SECOND, R_TOP ); + InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qfalse; + break; + case OP_MULF: + InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack + InstImm( PPC_LFSU, R_SECOND, R_OPSTACK, -4 ); // get value from opstack + Inst4( PPC_FMULS, R_TOP, R_SECOND, 0, R_TOP ); + InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qfalse; + break; + + case OP_CVIF: + v = (int)&itofConvert; + InstImmU( PPC_ADDIS, R_EA, 0, (v >> 16)&0xffff ); + InstImmU( PPC_ORI, R_EA, R_EA, v & 0xffff ); + InstImm( PPC_LWZ, R_TOP, R_OPSTACK, 0 ); // get value from opstack + InstImmU( PPC_XORIS, R_TOP, R_TOP, 0x8000 ); + InstImm( PPC_STW, R_TOP, R_EA, 12 ); + InstImm( PPC_LFD, R_TOP, R_EA, 0 ); + InstImm( PPC_LFD, R_SECOND, R_EA, 8 ); + Inst( PPC_FSUB, R_TOP, R_SECOND, R_TOP ); + // Inst( PPC_FRSP, R_TOP, 0, R_TOP ); + InstImm( PPC_STFS, R_TOP, R_OPSTACK, 0 ); // save value to opstack + rtopped = qfalse; + break; + case OP_CVFI: + InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack + Inst( PPC_FCTIWZ, R_TOP, 0, R_TOP ); + Inst( PPC_STFIWX, R_TOP, 0, R_OPSTACK ); // save value to opstack + rtopped = qfalse; + break; + case OP_SEX8: + ltop(); // get value from opstack + Inst( PPC_EXTSB, R_TOP, R_TOP, 0 ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); + rtopped = qtrue; + break; + case OP_SEX16: + ltop(); // get value from opstack + Inst( PPC_EXTSH, R_TOP, R_TOP, 0 ); + InstImm( PPC_STW, R_TOP, R_OPSTACK, 0 ); + rtopped = qtrue; + break; + + case OP_BLOCK_COPY: + v = Constant4() >> 2; + ltop(); // source + InstImm( PPC_LWZ, R_SECOND, R_OPSTACK, -4 ); // dest + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 ); + InstImmU( PPC_ADDI, R_EA, 0, v ); // count + // FIXME: range check + Inst( PPC_MTSPR, R_EA, 9, 0 ); // move to count register + + Inst( PPC_ADD, R_TOP, R_TOP, R_MEMBASE ); + InstImm( PPC_ADDI, R_TOP, R_TOP, -4 ); + Inst( PPC_ADD, R_SECOND, R_SECOND, R_MEMBASE ); + InstImm( PPC_ADDI, R_SECOND, R_SECOND, -4 ); + + InstImm( PPC_LWZU, R_EA, R_TOP, 4 ); // source + InstImm( PPC_STWU, R_EA, R_SECOND, 4 ); // dest + Inst( PPC_BC | 0xfff8 , 16, 0, 0 ); // loop + rtopped = qfalse; + break; + + case OP_JUMP: + ltop(); // get value from opstack + InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -4 ); + Inst( PPC_RLWINM | ( 29 << 1 ), R_TOP, R_TOP, 2 ); + // FIXME: range check + Inst( PPC_LWZX, R_TOP, R_TOP, R_INSTRUCTIONS ); + Inst( PPC_MTSPR, R_TOP, 9, 0 ); // move to count register + Inst( PPC_BCCTR, 20, 0, 0 ); // jump to the count register + rtopped = qfalse; + break; + default: + Com_Error( ERR_DROP, "VM_CompilePPC: bad opcode %i at instruction %i, offset %i", op, instruction, pc ); + } + pop0 = pop1; + pop1 = op; + } + + Com_Printf( "VM file %s pass %d compiled to %i bytes of code\n", vm->name, (pass+1), compiledOfs*4 ); + + if ( pass == 0 ) { + // copy to an exact size buffer on the hunk + vm->codeLength = compiledOfs * 4; + vm->codeBase = Hunk_Alloc( vm->codeLength, h_low ); + Com_Memcpy( vm->codeBase, buf, vm->codeLength ); + Z_Free( buf ); + + // offset all the instruction pointers for the new location + for ( i = 0 ; i < header->instructionCount ; i++ ) { + vm->instructionPointers[i] += (int)vm->codeBase; + } + + // go back over it in place now to fixup reletive jump targets + buf = (unsigned *)vm->codeBase; + } + } + Z_Free( jused ); +} + +/* +============== +VM_CallCompiled + +This function is called directly by the generated code +============== +*/ +int VM_CallCompiled( vm_t *vm, int *args ) { + int stack[1024]; + int programStack; + int stackOnEntry; + byte *image; + + currentVM = vm; + + // interpret the code + vm->currentlyInterpreting = qtrue; + + // we might be called recursively, so this might not be the very top + programStack = vm->programStack; + stackOnEntry = programStack; + image = vm->dataBase; + + // set up the stack frame + programStack -= 48; + + *(int *)&image[ programStack + 44] = args[9]; + *(int *)&image[ programStack + 40] = args[8]; + *(int *)&image[ programStack + 36] = args[7]; + *(int *)&image[ programStack + 32] = args[6]; + *(int *)&image[ programStack + 28] = args[5]; + *(int *)&image[ programStack + 24] = args[4]; + *(int *)&image[ programStack + 20] = args[3]; + *(int *)&image[ programStack + 16] = args[2]; + *(int *)&image[ programStack + 12] = args[1]; + *(int *)&image[ programStack + 8 ] = args[0]; + *(int *)&image[ programStack + 4 ] = 0; // return stack + *(int *)&image[ programStack ] = -1; // will terminate the loop on return + + // off we go into generated code... + // the PPC calling standard says the parms will all go into R3 - R11, so + // no special asm code is needed here +#ifdef __GNUC__ + ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))( + programStack, (int)&stack, + (int)image, vm->dataMask, (int)&AsmCall, + (int)vm->instructionPointers, vm->instructionPointersLength, + (int)vm ); +#else + ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))( + programStack, (int)&stack, + (int)image, vm->dataMask, *(int *)&AsmCall /* skip function pointer header */, + (int)vm->instructionPointers, vm->instructionPointersLength, + (int)vm ); +#endif + vm->programStack = stackOnEntry; + + vm->currentlyInterpreting = qfalse; + + return stack[1]; +} + + +/* +================== +AsmCall + +Put this at end of file because gcc messes up debug line numbers +================== +*/ +#ifdef __GNUC__ + +void AsmCall( void ) { +asm (" + // pop off the destination instruction + lwz r12,0(r4) // RG_TOP, 0(RG_OPSTACK) + addi r4,r4,-4 // RG_OPSTACK, RG_OPSTACK, -4 + + // see if it is a system trap + cmpwi r12,0 // RG_TOP, 0 + bc 12,0, systemTrap + + // calling another VM function, so lookup in instructionPointers + slwi r12,r12,2 // RG_TOP,RG_TOP,2 + // FIXME: range check + lwzx r12, r8, r12 // RG_TOP, RG_INSTRUCTIONS(RG_TOP) + mtctr r12 // RG_TOP +"); + + +#if defined(MACOS_X) && defined(__OPTIMIZE__) + // On Mac OS X, gcc doesn't push a frame when we are optimized, so trying to tear it down results in grave disorder. +#warning Mac OS X optimization on, not popping GCC AsmCall frame +#else + // Mac OS X Server and unoptimized compiles include a GCC AsmCall frame + asm (" + lwz r1,0(r1) // pop off the GCC AsmCall frame + lmw r30,-8(r1) +"); +#endif + +asm (" + bcctr 20,0 // when it hits a leave, it will branch to the current link register + + // calling a system trap +systemTrap: + // convert to positive system call number + subfic r12,r12,-1 + + // save all our registers, including the current link register + mflr r13 // RG_SECOND // copy off our link register + addi r1,r1,-92 // required 24 byets of linkage, 32 bytes of parameter, plus our saves + stw r3,56(r1) // RG_STACK, -36(REAL_STACK) + stw r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK) + stw r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK) + stw r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK) + stw r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK) + stw r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK) + stw r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK) + stw r10,84(r1) // RG_VM, 28(RG_REAL_STACK) + stw r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK) // link register + + // save the vm stack position to allow recursive VM entry + addi r13,r3,-4 // RG_TOP, RG_STACK, -4 + stw r13,0(r10) //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM) + + // save the system call number as the 0th parameter + add r3,r3,r5 // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls + stwu r12,4(r3) // RG_TOP, 4(r3) + + // make the system call with the address of all the VM parms as a parameter + // vm->systemCalls( &parms ) + lwz r12,4(r10) // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM) + mtctr r12 // RG_TOP + bcctrl 20,0 + mr r12,r3 // RG_TOP, r3 + + // pop our saved registers + lwz r3,56(r1) // RG_STACK, 0(RG_REAL_STACK) + lwz r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK) + lwz r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK) + lwz r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK) + lwz r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK) + lwz r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK) + lwz r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK) + lwz r10,84(r1) // RG_VM, 28(RG_REAL_STACK) + lwz r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK) + addi r1,r1,92 // RG_REAL_STACK, RG_REAL_STACK, 36 + + // restore the old link register + mtlr r13 // RG_SECOND + + // save off the return value + stwu r12,4(r4) // RG_TOP, 0(RG_OPSTACK) + + // GCC adds its own prolog / epliog code +" ); +} + +#endif diff --git a/CODE-mp/qcommon/vm_x86.cpp b/CODE-mp/qcommon/vm_x86.cpp index 78722ea..67b6ff3 100644 --- a/CODE-mp/qcommon/vm_x86.cpp +++ b/CODE-mp/qcommon/vm_x86.cpp @@ -49,17 +49,18 @@ static int asmCallPtr = (int)AsmCall; // bk001213 - BEWARE: does not work! UI menu etc. broken - stack! // bk001119 - added: int gftol( float x ) { return (int)x; } +extern "C" { int qftol( void ); // bk001213 - label, see unix/ftol.nasm int qftol027F( void ); // bk001215 - fixed FPU control variants int qftol037F( void ); int qftol0E7F( void ); // bk010102 - fixed bogus bits (duh) int qftol0F7F( void ); - +} static int ftolPtr = (int)qftol0F7F; #endif // FTOL_PTR -void doAsmCall( void ); +extern "C" void doAsmCall( void ); static int asmCallPtr = (int)doAsmCall; #endif // !_WIN32 @@ -127,7 +128,7 @@ static int callProgramStack; static int *callOpStack; static int callSyscallNum; -void callAsmCall(void) { +extern "C" void callAsmCall(void) { // save the stack to allow recursive VM entry currentVM->programStack = callProgramStack - 4; *(int *)((byte *)currentVM->dataBase + callProgramStack + 4) = callSyscallNum; diff --git a/CODE-mp/qcommon/vssver.scc b/CODE-mp/qcommon/vssver.scc new file mode 100644 index 0000000..d0573c2 Binary files /dev/null and b/CODE-mp/qcommon/vssver.scc differ diff --git a/CODE-mp/renderer/matcomp.h b/CODE-mp/renderer/matcomp.h index 8d2a0aa..285de2b 100644 --- a/CODE-mp/renderer/matcomp.h +++ b/CODE-mp/renderer/matcomp.h @@ -29,4 +29,5 @@ void MC_UnCompressQuat(float mat[3][4],const unsigned char * comp); } #endif -#endif \ No newline at end of file +#endif + diff --git a/CODE-mp/renderer/mdx_format.h b/CODE-mp/renderer/mdx_format.h index 113c9f9..46903f3 100644 --- a/CODE-mp/renderer/mdx_format.h +++ b/CODE-mp/renderer/mdx_format.h @@ -294,20 +294,23 @@ static inline int G2_GetVertBoneIndex( const mdxmVertex_t *pVert, const int iWei return iBoneIndex; } -static inline float G2_GetVertBoneWeight( const mdxmVertex_t *pVert, const int iWeightNum ) +static inline float G2_GetVertBoneWeight( const mdxmVertex_t *pVert, const int iWeightNum, float &fTotalWeight, int iNumWeights ) { - int iTemp = pVert->BoneWeightings[iWeightNum]; - iTemp|= (pVert->uiNmWeightsAndBoneIndexes >> (iG2_BONEWEIGHT_TOPBITS_SHIFT+(iWeightNum*2)) ) & iG2_BONEWEIGHT_TOPBITS_AND; + float fBoneWeight; - float fBoneWeight = fG2_BONEWEIGHT_RECIPROCAL_MULT * iTemp; - - if (fBoneWeight == 0.0f) + if (iWeightNum == iNumWeights-1) { - // special case to fix flatten-to-zero cases for extremely light weightings. Could probably be omitted if desperate... - // - fBoneWeight = 0.00045f; + fBoneWeight = 1.0f-fTotalWeight; } - + else + { + int iTemp = pVert->BoneWeightings[iWeightNum]; + iTemp|= (pVert->uiNmWeightsAndBoneIndexes >> (iG2_BONEWEIGHT_TOPBITS_SHIFT+(iWeightNum*2)) ) & iG2_BONEWEIGHT_TOPBITS_AND; + + fBoneWeight = fG2_BONEWEIGHT_RECIPROCAL_MULT * iTemp; + fTotalWeight += fBoneWeight; + } + return fBoneWeight; } #endif diff --git a/CODE-mp/renderer/mssccprj.scc b/CODE-mp/renderer/mssccprj.scc new file mode 100644 index 0000000..ff8df37 --- /dev/null +++ b/CODE-mp/renderer/mssccprj.scc @@ -0,0 +1,5 @@ +SCC = This is a Source Code Control file + +[renderer.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\jk2sof2MP" +SCC_Project_Name = "$/General/code/renderer", YAAAAAAA diff --git a/CODE-mp/renderer/ref_trin.def b/CODE-mp/renderer/ref_trin.def new file mode 100644 index 0000000..2fefbd3 --- /dev/null +++ b/CODE-mp/renderer/ref_trin.def @@ -0,0 +1,2 @@ +EXPORTS + GetRefAPI diff --git a/CODE-mp/renderer/renderer.dsp b/CODE-mp/renderer/renderer.dsp new file mode 100644 index 0000000..044ff63 --- /dev/null +++ b/CODE-mp/renderer/renderer.dsp @@ -0,0 +1,914 @@ +# Microsoft Developer Studio Project File - Name="renderer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=renderer - Win32 Debug TA +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "renderer.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "renderer.mak" CFG="renderer - Win32 Debug TA" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "renderer - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "renderer - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "renderer - Win32 Release TA" (based on "Win32 (x86) Static Library") +!MESSAGE "renderer - Win32 Debug TA" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/MissionPack/code/renderer", EJBAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "renderer - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /G6 /W4 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "renderer - Win32 Release TA" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "renderer___Win32_Release_TA" +# PROP BASE Intermediate_Dir "renderer___Win32_Release_TA" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release_TA" +# PROP Intermediate_Dir "Release_TA" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /W4 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /D "__USEA3D" /D "__A3D_GEOM" /YX /FD /c +# ADD CPP /nologo /G6 /W4 /GX /O2 /Ob2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug TA" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "renderer___Win32_Debug_TA" +# PROP BASE Intermediate_Dir "renderer___Win32_Debug_TA" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug_TA" +# PROP Intermediate_Dir "Debug_TA" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /D "__USEA3D" /D "__A3D_GEOM" /FR /YX /FD /GZ /c +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "renderer - Win32 Release" +# Name "renderer - Win32 Debug" +# Name "renderer - Win32 Release TA" +# Name "renderer - Win32 Debug TA" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\ref_trin.def +# End Source File +# Begin Source File + +SOURCE=.\tr_animation.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_backend.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_bsp.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_cmds.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_curve.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_flares.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_font.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_image.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_init.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_light.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_marks.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_mesh.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_model.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_noise.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_scene.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_shade.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_shade_calc.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_shader.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_shadows.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_sky.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_surface.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_world.cpp +# End Source File +# Begin Source File + +SOURCE=..\win32\win_gamma.cpp +# End Source File +# Begin Source File + +SOURCE=..\win32\win_glimp.cpp +# End Source File +# Begin Source File + +SOURCE=..\win32\win_qgl.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\qcommon\cm_public.h +# End Source File +# Begin Source File + +SOURCE=..\win32\glw_win.h +# End Source File +# Begin Source File + +SOURCE=..\game\q_shared.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qcommon.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qfiles.h +# End Source File +# Begin Source File + +SOURCE=.\qgl.h +# End Source File +# Begin Source File + +SOURCE=..\game\surfaceflags.h +# End Source File +# Begin Source File + +SOURCE=.\tr_local.h +# End Source File +# Begin Source File + +SOURCE=.\tr_public.h +# End Source File +# Begin Source File + +SOURCE=..\cgame\tr_types.h +# End Source File +# Begin Source File + +SOURCE=..\win32\win_local.h +# End Source File +# End Group +# Begin Group "jpeg" + +# PROP Default_Filter "" +# Begin Group "Source Files No. 1" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE="..\jpeg-6\jcapimin.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jccoefct.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jccolor.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jcdctmgr.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jchuff.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jcinit.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jcmainct.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jcmarker.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jcmaster.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jcomapi.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jcparam.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jcphuff.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jcprepct.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jcsample.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jctrans.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdapimin.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdapistd.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdatadst.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdatasrc.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdcoefct.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdcolor.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jddctmgr.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdhuff.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdinput.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdmainct.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdmarker.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdmaster.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdpostct.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdsample.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdtrans.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jerror.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jfdctflt.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jidctflt.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jmemmgr.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jmemnobs.cpp" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jutils.cpp" +# End Source File +# End Group +# Begin Group "Header Files No. 1" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE="..\jpeg-6\jchuff.h" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jconfig.h" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdct.h" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jdhuff.h" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jerror.h" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jinclude.h" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jmemsys.h" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jmorecfg.h" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jpegint.h" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jpeglib.h" +# End Source File +# Begin Source File + +SOURCE="..\jpeg-6\jversion.h" +# End Source File +# Begin Source File + +SOURCE=..\ft2\sfdriver.h +# End Source File +# Begin Source File + +SOURCE=..\ft2\sfobjs.h +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttcmap.h +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttload.h +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttpost.h +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttsbit.h +# End Source File +# End Group +# End Group +# Begin Group "FreeType2" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Group "Include files" + +# PROP Default_Filter "*.h" +# Begin Source File + +SOURCE=..\ft2\ahangles.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ahglobal.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ahglyph.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ahhint.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ahloader.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ahmodule.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ahoptim.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ahtypes.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\autohint.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\freetype.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftbbox.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftcalc.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftconfig.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftdebug.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftdriver.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\fterrors.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftextend.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftglyph.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftgrays.h +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftimage.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftlist.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftmemory.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftmm.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftmodule.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftnames.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftobjs.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftoption.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftoutln.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftraster.h +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftrend1.h +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftrender.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftsmooth.h +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftstream.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftsystem.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\fttypes.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\psnames.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\sfnt.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\t1errors.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\t1tables.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\t1types.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\t2errors.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\t2types.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttdriver.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\tterrors.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttgload.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttinterp.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttnameid.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttobjs.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttpload.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\tttables.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\tttags.h +# PROP Exclude_From_Build 1 +# End Source File +# Begin Source File + +SOURCE=..\ft2\tttypes.h +# PROP Exclude_From_Build 1 +# End Source File +# End Group +# Begin Source File + +SOURCE=..\ft2\ahangles.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ahglobal.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ahglyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ahhint.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ahmodule.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ahoptim.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftcalc.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftdebug.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftextend.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftglyph.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftgrays.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftinit.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftlist.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftmm.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftnames.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftobjs.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftoutln.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftraster.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftrend1.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftsmooth.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftstream.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ftsystem.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\sfdriver.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\sfobjs.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttcmap.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttdriver.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttgload.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttinterp.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttload.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttobjs.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttpload.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttpost.cpp +# End Source File +# Begin Source File + +SOURCE=..\ft2\ttsbit.cpp +# End Source File +# End Group +# End Target +# End Project diff --git a/CODE-mp/renderer/tr_WorldEffects.cpp b/CODE-mp/renderer/tr_WorldEffects.cpp index 37a19bd..1d0c107 100644 --- a/CODE-mp/renderer/tr_WorldEffects.cpp +++ b/CODE-mp/renderer/tr_WorldEffects.cpp @@ -437,8 +437,8 @@ void CMistyFog::Update(CWorldEffectsSystem *system, float elapseTime) // translate - forwardWind = DotProduct(mWindTransform, backEnd.viewParms.or.axis[0]); - rightWind = DotProduct(mWindTransform, backEnd.viewParms.or.axis[1]); + forwardWind = DotProduct(mWindTransform, backEnd.viewParms.ori.axis[0]); + rightWind = DotProduct(mWindTransform, backEnd.viewParms.ori.axis[1]); mTextureCoords[0][0] += rightWind / mSpeed; mTextureCoords[1][0] += rightWind / mSpeed; @@ -587,8 +587,8 @@ void CMistyFog::CreateTextureCoords(void) mSpeed = flrand(200.0f, 700.0f); - forwardWind = DotProduct(mWindTransform, backEnd.viewParms.or.axis[0]); - rightWind = DotProduct(mWindTransform, backEnd.viewParms.or.axis[1]); + forwardWind = DotProduct(mWindTransform, backEnd.viewParms.ori.axis[0]); + rightWind = DotProduct(mWindTransform, backEnd.viewParms.ori.axis[1]); if (forwardWind > 0.5) { // moving away, so make the size smaller @@ -698,13 +698,13 @@ bool CMistyFog2::Command(const char *command) } token = COM_ParseExt((const char **)&command, qfalse); - if (strcmpi(token, "fog") != 0) + if (Q_stricmp(token, "fog") != 0) { return false; } token = COM_ParseExt((const char **)&command, qfalse); - if (strcmpi(token, "density") == 0) + if (Q_stricmp(token, "density") == 0) { token = COM_ParseExt((const char **)&command, qfalse); mAlpha = atof(token); @@ -1012,7 +1012,7 @@ void CWind::Update(CWorldEffectsSystem *system, float elapseTime) return; } - VectorSubtract(backEnd.viewParms.or.origin, mPoint, difference); + VectorSubtract(backEnd.viewParms.ori.origin, mPoint, difference); if (VectorLength(difference) > 300.0) { return; @@ -1346,7 +1346,7 @@ bool CSnowSystem::Command(const char *command) token = COM_ParseExt((const char **)&command, qfalse); - if (strcmpi(token, "wind") == 0) + if (Q_stricmp(token, "wind") == 0) { // snow wind ( windOriginX windOriginY windOriginZ ) ( windVelocityX windVelocityY windVelocityZ ) ( sizeX sizeY sizeZ ) vec3_t origin, velocity, size; @@ -1358,46 +1358,46 @@ bool CSnowSystem::Command(const char *command) return true; } - else if (strcmpi(token, "fog") == 0) + else if (Q_stricmp(token, "fog") == 0) { // snow fog AddWorldEffect(new CMistyFog2); mWindChange = 0; return true; } - else if (strcmpi(token, "alpha") == 0) + else if (Q_stricmp(token, "alpha") == 0) { // snow alpha default: 0.09 token = COM_ParseExt((const char **)&command, qfalse); mAlpha = atof(token); return true; } - else if (strcmpi(token, "spread") == 0) + else if (Q_stricmp(token, "spread") == 0) { // snow spread ( minX minY minZ ) ( maxX maxY maxZ ) default: ( -600 -600 -200 ) ( 600 600 250 ) ParseVector((const char **)&command, 3, mMinSpread); ParseVector((const char **)&command, 3, mMaxSpread); return true; } - else if (strcmpi(token, "velocity") == 0) + else if (Q_stricmp(token, "velocity") == 0) { // snow velocity ( minX minY minZ ) ( maxX maxY maxZ ) default: ( -15 -15 -20 ) ( 15 15 -70 ) ParseVector((const char **)&command, 3, mMinSpread); ParseVector((const char **)&command, 3, mMaxSpread); return true; } - else if (strcmpi(token, "blowing") == 0) + else if (Q_stricmp(token, "blowing") == 0) { token = COM_ParseExt((const char **)&command, qfalse); - if (strcmpi(token, "duration") == 0) + if (Q_stricmp(token, "duration") == 0) { // snow blowing duration default: 2 token = COM_ParseExt((const char **)&command, qfalse); mWindDuration = atol(token); return true; } - else if (strcmpi(token, "low") == 0) + else if (Q_stricmp(token, "low") == 0) { // snow blowing low default: 3 token = COM_ParseExt((const char **)&command, qfalse); mWindLow = atol(token); return true; } - else if (strcmpi(token, "velocity") == 0) + else if (Q_stricmp(token, "velocity") == 0) { // snow blowing velocity ( min max ) default: ( 30 70 ) float data[2]; @@ -1406,7 +1406,7 @@ bool CSnowSystem::Command(const char *command) mWindMax = data[1]; return true; } - else if (strcmpi(token, "size") == 0) + else if (Q_stricmp(token, "size") == 0) { // snow blowing size ( minX minY minZ ) default: ( 1000 300 300 ) ParseVector((const char **)&command, 3, mWindSize); return true; @@ -1446,7 +1446,7 @@ void CSnowSystem::Update(float elapseTime) CWorldEffectsSystem::Update(elapseTime); } - VectorCopy(backEnd.viewParms.or.origin, origin); + VectorCopy(backEnd.viewParms.ori.origin, origin); mNextWindGust -= elapseTime; if (mNextWindGust < 0.0) @@ -1683,7 +1683,7 @@ void CSnowSystem::Render(void) CWorldEffectsSystem::Render(); - VectorAdd(backEnd.viewParms.or.origin, mMinSpread, origin); + VectorAdd(backEnd.viewParms.ori.origin, mMinSpread, origin); qglColor4f(0.8, 0.8, 0.8, mAlpha); @@ -1856,13 +1856,13 @@ bool CRainSystem::Command(const char *command) token = COM_ParseExt((const char **)&command, qfalse); - if (strcmpi(token, "fog") == 0) + if (Q_stricmp(token, "fog") == 0) { // rain fog AddWorldEffect(new CMistyFog2); mWindChange = 0; return true; } - else if (strcmpi(token, "fall") == 0) + else if (Q_stricmp(token, "fall") == 0) { // rain fall ( minVelocity maxVelocity ) default: ( -60 -50 ) float data[2]; @@ -1873,24 +1873,24 @@ bool CRainSystem::Command(const char *command) } return true; } - else if (strcmpi(token, "spread") == 0) + else if (Q_stricmp(token, "spread") == 0) { // rain spread ( radius height ) default: ( 20 20 ) ParseVector((const char **)&command, 2, &mSpread[1]); return true; } - else if (strcmpi(token, "alpha") == 0) + else if (Q_stricmp(token, "alpha") == 0) { // rain alpha default: 0.15 token = COM_ParseExt((const char **)&command, qfalse); mAlpha = atof(token); return true; } - else if (strcmpi(token, "height") == 0) + else if (Q_stricmp(token, "height") == 0) { // rain height default: 1.5 token = COM_ParseExt((const char **)&command, qfalse); mRainHeight = atof(token); return true; } - else if (strcmpi(token, "angle") == 0) + else if (Q_stricmp(token, "angle") == 0) { // rain angle default: 1.0 token = COM_ParseExt((const char **)&command, qfalse); mWindAngle = atof(token); @@ -1994,8 +1994,8 @@ void CRainSystem::Render(void) return; } - VectorScale(backEnd.viewParms.or.axis[0], 1, forward); // forward - VectorScale(backEnd.viewParms.or.axis[1], 0.2, left); // left + VectorScale(backEnd.viewParms.ori.axis[0], 1, forward); // forward + VectorScale(backEnd.viewParms.ori.axis[1], 0.2, left); // left down[0] = 0 - mWindDirection[0] * mRainHeight * mWindAngle; down[1] = 0 - mWindDirection[1] * mRainHeight * mWindAngle; down[2] = -mRainHeight; @@ -2008,7 +2008,7 @@ void CRainSystem::Render(void) qglMatrixMode(GL_MODELVIEW); qglPushMatrix(); - qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); + qglTranslatef (backEnd.viewParms.ori.origin[0], backEnd.viewParms.ori.origin[1], backEnd.viewParms.ori.origin[2]); item = mRainList; qglBegin(GL_TRIANGLES ); @@ -2120,7 +2120,7 @@ void RB_RenderWorldEffects(void) // qglPushMatrix(); qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); - originContents = ri.CM_PointContents(backEnd.viewParms.or.origin, 0); + originContents = ri.CM_PointContents(backEnd.viewParms.ori.origin, 0); if (rainSystem) { @@ -2176,12 +2176,12 @@ void R_WorldEffectCommand(const char *command) origCommand = command; token = COM_ParseExt((const char **)&command, qfalse); - if (strcmpi(token, "snow") == 0) + if (Q_stricmp(token, "snow") == 0) { origCommand = command; token = COM_ParseExt((const char **)&command, qfalse); - if (strcmpi(token, "init") == 0) + if (Q_stricmp(token, "init") == 0) { // snow init token = COM_ParseExt((const char **)&command, qfalse); if (snowSystem) @@ -2190,7 +2190,7 @@ void R_WorldEffectCommand(const char *command) } snowSystem = new CSnowSystem(atoi(token)); } - else if (strcmpi(token, "remove") == 0) + else if (Q_stricmp(token, "remove") == 0) { // snow remove if (snowSystem) { @@ -2203,12 +2203,12 @@ void R_WorldEffectCommand(const char *command) snowSystem->Command(origCommand); } } - else if (strcmpi(token, "rain") == 0) + else if (Q_stricmp(token, "rain") == 0) { origCommand = command; token = COM_ParseExt((const char **)&command, qfalse); - if (strcmpi(token, "init") == 0) + if (Q_stricmp(token, "init") == 0) { // rain init token = COM_ParseExt((const char **)&command, qfalse); if (rainSystem) @@ -2217,7 +2217,7 @@ void R_WorldEffectCommand(const char *command) } rainSystem = new CRainSystem(atoi(token)); } - else if (strcmpi(token, "remove") == 0) + else if (Q_stricmp(token, "remove") == 0) { // rain remove if (rainSystem) { @@ -2230,21 +2230,21 @@ void R_WorldEffectCommand(const char *command) rainSystem->Command(origCommand); } } - else if (strcmpi(token, "debug") == 0) + else if (Q_stricmp(token, "debug") == 0) { token = COM_ParseExt((const char **)&command, qfalse); - if (strcmpi(token, "wind") == 0) + if (Q_stricmp(token, "wind") == 0) { debugShowWind = !debugShowWind; } - else if (strcmpi(token, "blah") == 0) + else if (Q_stricmp(token, "blah") == 0) { R_WorldEffectCommand("snow init 1000"); R_WorldEffectCommand("snow alpha 1"); R_WorldEffectCommand("snow fog"); } } - else if (strcmpi(token, "exec") == 0) + else if (Q_stricmp(token, "exec") == 0) { ri.Cmd_ExecuteText(EXEC_NOW, command); } diff --git a/CODE-mp/renderer/tr_WorldEffects.h b/CODE-mp/renderer/tr_WorldEffects.h index 5320830..a26a143 100644 --- a/CODE-mp/renderer/tr_WorldEffects.h +++ b/CODE-mp/renderer/tr_WorldEffects.h @@ -1,4 +1,6 @@ +#if defined (_MSC_VER) && (_MSC_VER >= 1020) #pragma once +#endif #if !defined __TR_WORLDEFFECTS_H #define __TR_WORLDEFFECTS_H diff --git a/CODE-mp/renderer/tr_backend.cpp b/CODE-mp/renderer/tr_backend.cpp index 836d188..4ec8d98 100644 --- a/CODE-mp/renderer/tr_backend.cpp +++ b/CODE-mp/renderer/tr_backend.cpp @@ -1,8 +1,10 @@ #include "tr_local.h" +#ifndef DEDICATED #if !defined __TR_WORLDEFFECTS_H #include "tr_WorldEffects.h" #endif +#endif backEndData_t *backEndData[SMP_FRAMES]; backEndState_t backEnd; @@ -17,6 +19,8 @@ static float s_flipMatrix[16] = { 0, 0, 0, 1 }; +#ifndef DEDICATED + /* ** GL_Bind */ @@ -430,6 +434,11 @@ void RB_BeginDrawingView (void) { glState.finishCalled = qtrue; } + if (!com_developer->integer && r_shadows->integer == 2) + { + Cvar_Set("cg_shadows", "1"); + } + // we will need to change the projection matrix before drawing // 2D images again backEnd.projection2D = qfalse; @@ -484,10 +493,10 @@ void RB_BeginDrawingView (void) { plane[2] = backEnd.viewParms.portalPlane.normal[2]; plane[3] = backEnd.viewParms.portalPlane.dist; - plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane); - plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane); - plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane); - plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3]; + plane2[0] = DotProduct (backEnd.viewParms.ori.axis[0], plane); + plane2[1] = DotProduct (backEnd.viewParms.ori.axis[1], plane); + plane2[2] = DotProduct (backEnd.viewParms.ori.axis[2], plane); + plane2[3] = DotProduct (plane, backEnd.viewParms.ori.origin) - plane[3]; qglLoadMatrixf( s_flipMatrix ); qglClipPlane (GL_CLIP_PLANE0, plane2); @@ -591,11 +600,11 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; // set up the transformation matrix - R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or ); + R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.ori ); // set up the dynamic lighting if needed if ( backEnd.currentEntity->needDlights ) { - R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); + R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori ); } if ( backEnd.currentEntity->e.renderfx & RF_NODEPTH ) { @@ -609,14 +618,14 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { } else { backEnd.currentEntity = &tr.worldEntity; backEnd.refdef.floatTime = originalTime; - backEnd.or = backEnd.viewParms.world; + backEnd.ori = backEnd.viewParms.world; // we have to reset the shaderTime as well otherwise image animations on // the world (like water) continue with the wrong frame tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; - R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); + R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.ori ); } - qglLoadMatrixf( backEnd.or.modelMatrix ); + qglLoadMatrixf( backEnd.ori.modelMatrix ); // // change depthrange if needed @@ -1265,3 +1274,4 @@ void RB_RenderThread( void ) { } } +#endif //!DEDICATED diff --git a/CODE-mp/renderer/tr_bsp.cpp b/CODE-mp/renderer/tr_bsp.cpp index cddea4f..083ce3c 100644 --- a/CODE-mp/renderer/tr_bsp.cpp +++ b/CODE-mp/renderer/tr_bsp.cpp @@ -81,7 +81,7 @@ static void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) { // should NOT do it if overbrightBits is 0 if (tr.overbrightBits) - shift = r_mapOverBrightBits->integer - tr.overbrightBits; + shift = 1 - tr.overbrightBits; if (!shift) { @@ -126,7 +126,7 @@ static void R_ColorShiftLightingBytes( byte in[3]) // should NOT do it if overbrightBits is 0 if (tr.overbrightBits) - shift = r_mapOverBrightBits->integer - tr.overbrightBits; + shift = 1 - tr.overbrightBits; if (!shift) { diff --git a/CODE-mp/renderer/tr_flares.cpp b/CODE-mp/renderer/tr_flares.cpp index 472fb34..6c9d7da 100644 --- a/CODE-mp/renderer/tr_flares.cpp +++ b/CODE-mp/renderer/tr_flares.cpp @@ -99,7 +99,7 @@ void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t // if the point is off the screen, don't bother adding it // calculate screen coordinates and depth - R_TransformModelToClip( point, backEnd.or.modelMatrix, + R_TransformModelToClip( point, backEnd.ori.modelMatrix, backEnd.viewParms.projectionMatrix, eye, clip ); // check to see if the point is completely off screen @@ -155,7 +155,7 @@ void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t // fade the intensity of the flare down as the // light surface turns away from the viewer if ( normal ) { - VectorSubtract( backEnd.viewParms.or.origin, point, local ); + VectorSubtract( backEnd.viewParms.ori.origin, point, local ); VectorNormalizeFast( local ); d = DotProduct( local, normal ); VectorScale( f->color, d, f->color ); diff --git a/CODE-mp/renderer/tr_font.cpp b/CODE-mp/renderer/tr_font.cpp index 98e4348..03e7633 100644 --- a/CODE-mp/renderer/tr_font.cpp +++ b/CODE-mp/renderer/tr_font.cpp @@ -485,9 +485,11 @@ int RE_Font_StrLenPixels(const char *psText, const int iFontHandle, const float } while(*constParseText) { - x += curfont->GetLetterHorizAdvance( AnyLanguage_ReadCharFromString( &constParseText )); + int a = curfont->GetLetterHorizAdvance( AnyLanguage_ReadCharFromString( &constParseText )); + + x += Round ( a * fScale ); } - x = Round(x * fScale); + return(x); } diff --git a/CODE-mp/renderer/tr_ghoul2.cpp b/CODE-mp/renderer/tr_ghoul2.cpp index f7fe5fb..15387b0 100644 --- a/CODE-mp/renderer/tr_ghoul2.cpp +++ b/CODE-mp/renderer/tr_ghoul2.cpp @@ -18,13 +18,15 @@ #include "../ghoul2/G2.h" #endif #include "../ghoul2/G2_local.h" -#include "matcomp.h" +#include "MatComp.h" #pragma warning (disable: 4512) //default assignment operator could not be gened #include "../qcommon/disablewarnings.h" #define LL(x) x=LittleLong(x) +extern cvar_t *r_Ghoul2AnimSmooth; +extern cvar_t *r_Ghoul2UnSqashAfterSmooth; // I hate doing this, but this is the simplest way to get this into the routines it needs to be mdxaBone_t worldMatrix; @@ -265,7 +267,7 @@ static int G2_ComputeLOD( trRefEntity_t *ent, const model_t *currentModel, int l return(0); } - if (r_lodbias->integer > lodBias) + if ( r_lodbias->integer > lodBias ) { lodBias = r_lodbias->integer; } @@ -288,8 +290,15 @@ static int G2_ComputeLOD( trRefEntity_t *ent, const model_t *currentModel, int l if ( ( projectedRadius = ProjectRadius( 0.75*largestScale*ent->e.radius, ent->e.origin ) ) != 0 ) //we reduce the radius to make the LOD match other model types which use the actual bound box size { - lodscale = r_lodscale->value; - if (lodscale > 20) lodscale = 20; + lodscale = (r_lodscale->value+r_autolodscalevalue->value); + if ( lodscale > 20 ) + { + lodscale = 20; + } + else if ( lodscale < 0 ) + { + lodscale = 0; + } flod = 1.0f - projectedRadius * lodscale; } else @@ -297,7 +306,9 @@ static int G2_ComputeLOD( trRefEntity_t *ent, const model_t *currentModel, int l // object intersects near view plane, e.g. view weapon flod = 0; } - +#ifdef DEDICATED +#define myftol(x) ((int)(x)) +#endif flod *= currentModel->numLods; lod = myftol( flod ); @@ -442,7 +453,7 @@ static int G2_GetBonePoolIndex( const mdxaHeader_t *pMDXAHeader, int iFrame, int MC_UnCompressQuat(mat, pCompBonePool[ G2_GetBonePoolIndex( pMDXAHeader, iFrame, iBoneIndex ) ].Comp); } - +#define DEBUG_G2_TIMING (0) // transform each individual bone's information - making sure to use any override information provided, both for angles and for animations, as // well as multiplying each bone's matrix by it's parents matrix @@ -455,6 +466,10 @@ void G2_TransformBone (CTransformBone &TB) int i, j, boneListIndex; int angleOverride = 0; +#if DEBUG_G2_TIMING + bool printTiming=false; +#endif + // decide here if we should go down this path? - is this bone used? -If not, return from this function. Due the hierarchial nature of the bones // any bone below this one in the tree shouldn't be used either. if (!TB.usedBoneList[TB.child]) @@ -474,12 +489,11 @@ void G2_TransformBone (CTransformBone &TB) angleOverride = (boneList[boneListIndex].flags) & (BONE_ANGLES_TOTAL); } - // set blending stuff if we need to - if (boneList[boneListIndex].flags & (BONE_ANIM_BLEND | BONE_ANIM_BLEND_TO_PARENT)) + if (boneList[boneListIndex].flags & BONE_ANIM_BLEND) { float blendTime = TB.incomingTime - boneList[boneListIndex].blendStart; // only set up the blend anim if we actually have some blend time left on this bone anim - otherwise we might corrupt some blend higher up the hiearchy - if (blendTime < boneList[boneListIndex].blendTime) + if (blendTime>=0.0f&&blendTime < boneList[boneListIndex].blendTime) { TB.blendFrame = boneList[boneListIndex].blendFrame; TB.blendOldFrame = boneList[boneListIndex].blendLerpFrame; @@ -491,34 +505,13 @@ void G2_TransformBone (CTransformBone &TB) TB.blendMode = false; } } - else - // are blending *from* the parent? If so, grab what the parent is set to, and stick it in the blendFrame info - if (boneList[boneListIndex].flags & BONE_ANIM_BLEND_FROM_PARENT) - { - float blendTime = TB.incomingTime - boneList[boneListIndex].blendStart; - // only set up the blend anim if we actually have some blend time left on this bone anim - otherwise we might corrupt some blend higher up the hiearchy - if (blendTime < boneList[boneListIndex].blendTime) - { - TB.blendFrame = TB.newFrame; - TB.blendOldFrame = TB.currentFrame; - TB.blendLerp = (blendTime / boneList[boneListIndex].blendTime); - TB.blendMode = true; - } - else - { - TB.blendMode = false; - } - } - else - if ((boneList[boneListIndex].flags) & (BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE)) + else if ((boneList[boneListIndex].flags) & (BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE)) { TB.blendMode = false; } - // should this animation be overridden by an animation in the bone list? if ((boneList[boneListIndex].flags) & (BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE)) { - // yes - add in animation speed to current frame float animSpeed = boneList[boneListIndex].animSpeed; float time; if (boneList[boneListIndex].pauseTime) @@ -529,6 +522,10 @@ void G2_TransformBone (CTransformBone &TB) { time = (TB.incomingTime - boneList[boneListIndex].startTime) / 50.0f; } + if (time<0) + { + time=0; + } float newFrame_g = boneList[boneListIndex].startFrame + (time * animSpeed); float endFrame = (float)boneList[boneListIndex].endFrame ; @@ -547,27 +544,26 @@ void G2_TransformBone (CTransformBone &TB) // get our new animation frame back within the bounds of the animation set if (animSpeed < 0.0f) { - // should we be creating a virtual frame? - if ((newFrame_g < endFrame + 1) && (newFrame_g > endFrame)) + if ((newFrame_g < endFrame+1) && (newFrame_g >= endFrame)) { // now figure out what we are lerping between // delta is the fraction between this frame and the next, since the new anim is always at a .0f; - TB.backlerp = (newFrame_g - (int)newFrame_g); + TB.backlerp = (float(endFrame+1)-newFrame_g); // frames are easy to calculate - TB.currentFrame = (int)newFrame_g; + TB.currentFrame = endFrame; TB.newFrame = boneList[boneListIndex].startFrame; } else { - while (newFrame_g <= endFrame) + if (newFrame_g <= endFrame+1) { - newFrame_g -= animSize; + newFrame_g=endFrame+fmod(newFrame_g-endFrame,animSize)-animSize; } // now figure out what we are lerping between // delta is the fraction between this frame and the next, since the new anim is always at a .0f; - TB.backlerp = (newFrame_g - (int)newFrame_g); + TB.backlerp = (ceil(newFrame_g)-newFrame_g); // frames are easy to calculate - TB.currentFrame = (int)newFrame_g; + TB.currentFrame = ceil(newFrame_g); // should we be creating a virtual frame? if (newFrame_g <= endFrame + 1) { @@ -594,9 +590,9 @@ void G2_TransformBone (CTransformBone &TB) } else { - while (newFrame_g >= endFrame) + if (newFrame_g >= endFrame) { - newFrame_g -= animSize; + newFrame_g=endFrame+fmod(newFrame_g-endFrame,animSize)-animSize; } // now figure out what we are lerping between // delta is the fraction between this frame and the next, since the new anim is always at a .0f; @@ -619,8 +615,7 @@ void G2_TransformBone (CTransformBone &TB) } else { - if (((boneList[boneListIndex].flags & (BONE_ANIM_OVERRIDE_DEFAULT)) == (BONE_ANIM_OVERRIDE_DEFAULT))|| - ((boneList[boneListIndex].flags & (BONE_ANIM_OVERRIDE_FREEZE)) == (BONE_ANIM_OVERRIDE_FREEZE))) + if ((boneList[boneListIndex].flags & BONE_ANIM_OVERRIDE_FREEZE) == BONE_ANIM_OVERRIDE_FREEZE) { // if we are supposed to reset the default anim, then do so if (animSpeed > 0.0f) @@ -639,21 +634,19 @@ void G2_TransformBone (CTransformBone &TB) // nope, just stop processing this bone. And do nothing - let the bone take the parents anim info } } - else + else // { - // figure out the difference between the two frames - we have to decide what frame and what percentage of that - // frame we want to display - TB.backlerp = (newFrame_g - (int)newFrame_g); - - // frames are easy to calculate - TB.currentFrame = (int)newFrame_g; - if (animSpeed> 0.0) { + + TB.currentFrame = (int)newFrame_g; + + // figure out the difference between the two frames - we have to decide what frame and what percentage of that + // frame we want to display + TB.backlerp = (newFrame_g - TB.currentFrame); + TB.newFrame = TB.currentFrame + 1; - - // are we now on the end frame? - if (TB.newFrame > endFrame) + if (TB.newFrame >= (int)endFrame) { // we only want to lerp with the first frame of the anim if we are looping if (boneList[boneListIndex].flags & BONE_ANIM_OVERRIDE_LOOP) @@ -669,39 +662,55 @@ void G2_TransformBone (CTransformBone &TB) } else { - TB.currentFrame++; - TB.newFrame = TB.currentFrame - 1; - - TB.backlerp = 1-TB.backlerp; - // are we now on the end frame? - if (TB.newFrame < endFrame) + TB.backlerp = (ceil(newFrame_g)-newFrame_g); + TB.currentFrame = ceil(newFrame_g); + if (TB.currentFrame>boneList[boneListIndex].startFrame) { - // we only want to lerp with the first frame of the anim if we are looping - if (boneList[boneListIndex].flags & BONE_ANIM_OVERRIDE_LOOP) + TB.currentFrame=boneList[boneListIndex].startFrame; + TB.newFrame = TB.currentFrame; + TB.backlerp=0.0f; + } + else + { + TB.newFrame=TB.currentFrame-1; + // are we now on the end frame? + if (TB.newFrame < endFrame+1) { - TB.newFrame = boneList[boneListIndex].startFrame; - } - // if we intend to end this anim or freeze after this, then just keep on the last frame - else - { - TB.newFrame = boneList[boneListIndex].endFrame; + if (boneList[boneListIndex].flags & BONE_ANIM_OVERRIDE_LOOP) + { + TB.newFrame = boneList[boneListIndex].startFrame; + } + else + { + TB.newFrame = boneList[boneListIndex].endFrame+1; + } } } } - - // sanity check - //assert ((newFrame_g < endFrame) && (newFrame_g >= boneList[boneListIndex].startFrame)); } } else { - TB.currentFrame = boneList[boneListIndex].endFrame; + if (animSpeed<0.0) + { + TB.currentFrame = boneList[boneListIndex].endFrame+1; + } + else + { + TB.currentFrame = boneList[boneListIndex].endFrame-1; + } + if (TB.currentFrame<0) + { + TB.currentFrame=0; + } TB.newFrame = TB.currentFrame; TB.backlerp = 0; } - } - +#if DEBUG_G2_TIMING + printTiming=true; +#endif + } } //If either of these things happen the code below will choke to death miserably. Or so I gather. @@ -715,6 +724,51 @@ void G2_TransformBone (CTransformBone &TB) { return; } +#if DEBUG_G2_TIMING + if (printTiming&&boneListIndex==2) + { + char mess[1000]; + if (TB.blendMode) + { + sprintf(mess,"frb[%2d] %5d %5d %5d %5d %5d %f %f\n",boneListIndex,TB.incomingTime,(int)TB.newFrame,(int)TB.currentFrame,(int)TB.blendFrame,(int)TB.blendOldFrame,TB.backlerp,TB.blendLerp); + } + else + { + sprintf(mess,"fra[%2d] %5d %5d %5d %f\n",boneListIndex,TB.incomingTime,TB.newFrame,TB.currentFrame,TB.backlerp); + } + OutputDebugString(mess); + const boneInfo_t &bone=boneList[boneListIndex]; + if (bone.flags&BONE_ANIM_BLEND) + { + sprintf(mess," bfb[%2d] %5d %5d (%5d-%5d) %4.2f %4x bt(%5d-%5d) %7.2f %5d\n", + boneListIndex, + TB.incomingTime, + bone.startTime, + bone.startFrame, + bone.endFrame, + bone.animSpeed, + bone.flags, + bone.blendStart, + bone.blendStart+bone.blendTime, + bone.blendFrame, + bone.blendLerpFrame + ); + } + else + { + sprintf(mess," bfa[%2d] %5d %5d (%5d-%5d) %4.2f %4x\n", + boneListIndex, + TB.incomingTime, + bone.startTime, + bone.startFrame, + bone.endFrame, + bone.animSpeed, + bone.flags + ); + } + OutputDebugString(mess); + } +#endif // const mdxaCompBone_t *compBonePointer = (mdxaCompBone_t *)((byte *)TB.header + TB.header->ofsCompBonePool); @@ -758,7 +812,7 @@ void G2_TransformBone (CTransformBone &TB) // blend in the other frame if we need to if (TB.blendMode) { - float blendFrontlerp = 1.0 - TB.blendLerp; + float blendFrontlerp = 1.0 - TB.blendLerp; for ( j = 0 ; j < 12 ; j++ ) { ((float *)&tbone[2])[j] = (TB.blendLerp * ((float *)&tbone[2])[j]) @@ -769,7 +823,7 @@ void G2_TransformBone (CTransformBone &TB) if (TB.rootBone) { // now multiply by the root matrix, so we can offset this model should we need to - Multiply_3x4Matrix(&TB.bonePtr[TB.child], &TB.rootMatrix, &tbone[2]); + Multiply_3x4Matrix(&TB.bonePtr[TB.child].second, &TB.rootMatrix, &tbone[2]); } } else @@ -793,83 +847,38 @@ void G2_TransformBone (CTransformBone &TB) // blend in the other frame if we need to if (TB.blendMode) { -#if 0 - vec4_t quat; - mdxaBone_t inverseStart; - mdxaBone_t rotation, scaledRotation; - mdxaBone_t startMatrix, endMatrix; - - // tbone[5] contains the start from where we are blending from - put this in model space - Multiply_3x4Matrix(&startMatrix, &tbone[5], &skel->BasePoseMat); - - // tbone[2] contains the current animation, where are blending to - put this in model space - Multiply_3x4Matrix(&endMatrix, &tbone[2], &skel->BasePoseMat); - - // create inverse of start matrix - Inverse_Matrix(&startMatrix, &inverseStart); - - // generate rotation matrix from start to finish - Multiply_3x4Matrix(&rotation, &endMatrix, &inverseStart); - - // create a quaterion out of this matrix - G2_CreateQuaterion(&rotation, quat); - - // scale it appropriately by lerp - quat[3] *= TB.blendLerp; - - // go back and create a new rotation matrix from this scaled quaterion - G2_CreateMatrixFromQuaterion(&scaledRotation, quat); - - scaledRotation.matrix[0][3] = rotation.matrix[0][3]; - scaledRotation.matrix[1][3] = rotation.matrix[1][3]; - scaledRotation.matrix[2][3] = rotation.matrix[2][3]; - - // we should have a rotation matrix now in model space, put it back into bone space - Multiply_3x4Matrix(&endMatrix, &scaledRotation, &skel->BasePoseMatInv ); - - // multiply that by the original start to get result. - Multiply_3x4Matrix(&tbone[2], &endMatrix, &tbone[5]); - -#else const float blendFrontlerp = 1.0 - TB.blendLerp; for ( j = 0 ; j < 12 ; j++ ) { ((float *)&tbone[2])[j] = (TB.blendLerp * ((float *)&tbone[2])[j]) + (blendFrontlerp * ((float *)&tbone[5])[j]); } -#endif } if (TB.rootBone) { // now multiply by the root matrix, so we can offset this model should we need to - Multiply_3x4Matrix(&TB.bonePtr[TB.child], &TB.rootMatrix, &tbone[2]); + Multiply_3x4Matrix(&TB.bonePtr[TB.child].second, &TB.rootMatrix, &tbone[2]); } } - if (angleOverride & (BONE_ANGLES_REPLACE | BONE_ANGLES_REPLACE_TO_ANIM)) + if (angleOverride & BONE_ANGLES_REPLACE) { mdxaBone_t temp, firstPass; - mdxaBone_t &bone = TB.bonePtr[TB.child]; + mdxaBone_t &bone = TB.bonePtr[TB.child].second; boneInfo_t &boneOverride = boneList[boneListIndex]; // give us the matrix the animation thinks we should have, so we can get the correct X&Y coors - Multiply_3x4Matrix(&firstPass, &TB.bonePtr[TB.parent], &tbone[2]); + Multiply_3x4Matrix(&firstPass, &TB.bonePtr[TB.parent].second, &tbone[2]); // are we attempting to blend with the base animation? and still within blend time? - if (boneOverride.boneBlendTime && (((boneOverride.boneBlendTime + boneOverride.boneBlendStart) < TB.incomingTime) || (angleOverride & BONE_ANGLES_REPLACE_TO_ANIM))) + if (boneOverride.boneBlendTime && (((boneOverride.boneBlendTime + boneOverride.boneBlendStart) < TB.incomingTime))) { // ok, we are supposed to be blending. Work out lerp const float blendTime = TB.incomingTime - boneList[boneListIndex].boneBlendStart; float blendLerp = (blendTime / boneList[boneListIndex].boneBlendTime); if (blendLerp <= 1) { - // if we are going *to* the anim then reverse the lerp - if (angleOverride & BONE_ANGLES_REPLACE_TO_ANIM) - { - blendLerp = 1.0 - blendLerp; - } - if (blendLerp < 0) { assert(0); @@ -935,27 +944,27 @@ void G2_TransformBone (CTransformBone &TB) if (TB.rootBone) { // use the in coming root matrix as our basis - Multiply_3x4Matrix(&TB.bonePtr[TB.child], &TB.rootMatrix, &boneList[boneListIndex].newMatrix); + Multiply_3x4Matrix(&TB.bonePtr[TB.child].second, &TB.rootMatrix, &boneList[boneListIndex].newMatrix); } else { // convert from 3x4 matrix to a 4x4 matrix - Multiply_3x4Matrix(&TB.bonePtr[TB.child], &TB.bonePtr[TB.parent], &boneList[boneListIndex].newMatrix); + Multiply_3x4Matrix(&TB.bonePtr[TB.child].second, &TB.bonePtr[TB.parent].second, &boneList[boneListIndex].newMatrix); } } else // now transform the matrix by it's TB.parent, asumming we have a TB.parent, and we aren't overriding the angles absolutely if (!TB.rootBone) { - Multiply_3x4Matrix(&TB.bonePtr[TB.child], &TB.bonePtr[TB.parent], &tbone[2]); + Multiply_3x4Matrix(&TB.bonePtr[TB.child].second, &TB.bonePtr[TB.parent].second, &tbone[2]); } // now multiply our resulting bone by an override matrix should we need to if (angleOverride & BONE_ANGLES_POSTMULT) { mdxaBone_t tempMatrix; - memcpy (&tempMatrix, &TB.bonePtr[TB.child], sizeof(mdxaBone_t)); - Multiply_3x4Matrix(&TB.bonePtr[TB.child], &tempMatrix, &boneList[boneListIndex].newMatrix); + memcpy (&tempMatrix, &TB.bonePtr[TB.child].second, sizeof(mdxaBone_t)); + Multiply_3x4Matrix(&TB.bonePtr[TB.child].second, &tempMatrix, &boneList[boneListIndex].newMatrix); } // are the bone that we are resetting to the origin? @@ -963,7 +972,7 @@ void G2_TransformBone (CTransformBone &TB) { //create a world matrix for the new origin mdxaBone_t tempMatrix; - Multiply_3x4Matrix(&tempMatrix, &TB.bonePtr[TB.child], &skel->BasePoseMat); + Multiply_3x4Matrix(&tempMatrix, &TB.bonePtr[TB.child].second, &skel->BasePoseMat); TB.newModelOrigin[0] = tempMatrix.matrix[0][3]; TB.newModelOrigin[1] = tempMatrix.matrix[1][3]; TB.newModelOrigin[2] = tempMatrix.matrix[2][3]; @@ -1006,7 +1015,7 @@ void G2_SetUpBolts( mdxaHeader_t *header, CGhoul2Info &ghoul2, mdxaBone_v &boneP { // figure out where the bone hirearchy info is skel = (mdxaSkel_t *)((byte *)header + sizeof(mdxaHeader_t) + offsets->offsets[boltList[i].boneNumber]); - Multiply_3x4Matrix(&boltList[i].position, &bonePtr[boltList[i].boneNumber], &skel->BasePoseMat); + Multiply_3x4Matrix(&boltList[i].position, &bonePtr[boltList[i].boneNumber].second, &skel->BasePoseMat); } } } @@ -1094,37 +1103,40 @@ void G2_ProcessSurfaceBolt(mdxaBone_v &bonePtr, mdxmSurface_t *surface, int bolt // now go and transform just the points we need from the surface that was hit originally // w = vert0->weights; + float fTotalWeight = 0.0f; int iNumWeights = G2_GetVertWeights( vert0 ); for ( k = 0 ; k < iNumWeights ; k++ ) { int iBoneIndex = G2_GetVertBoneIndex( vert0, k ); - float fBoneWeight = G2_GetVertBoneWeight( vert0, k ); + float fBoneWeight = G2_GetVertBoneWeight( vert0, k, fTotalWeight, iNumWeights ); - pTri[0][0] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[0], vert0->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[0][3] ); - pTri[0][1] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[1], vert0->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[1][3] ); - pTri[0][2] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[2], vert0->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[2][3] ); + pTri[0][0] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0], vert0->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0][3] ); + pTri[0][1] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1], vert0->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1][3] ); + pTri[0][2] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2], vert0->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2][3] ); } // w = vert1->weights; + fTotalWeight = 0.0f; iNumWeights = G2_GetVertWeights( vert1 ); for ( k = 0 ; k < iNumWeights ; k++ ) { int iBoneIndex = G2_GetVertBoneIndex( vert1, k ); - float fBoneWeight = G2_GetVertBoneWeight( vert1, k ); + float fBoneWeight = G2_GetVertBoneWeight( vert1, k, fTotalWeight, iNumWeights ); - pTri[1][0] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[0], vert1->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[0][3] ); - pTri[1][1] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[1], vert1->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[1][3] ); - pTri[1][2] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[2], vert1->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[2][3] ); + pTri[1][0] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0], vert1->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0][3] ); + pTri[1][1] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1], vert1->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1][3] ); + pTri[1][2] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2], vert1->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2][3] ); } // w = vert2->weights; + fTotalWeight = 0.0f; iNumWeights = G2_GetVertWeights( vert2 ); for ( k = 0 ; k < iNumWeights ; k++ ) { int iBoneIndex = G2_GetVertBoneIndex( vert2, k ); - float fBoneWeight = G2_GetVertBoneWeight( vert2, k ); + float fBoneWeight = G2_GetVertBoneWeight( vert2, k, fTotalWeight, iNumWeights ); - pTri[2][0] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[0], vert2->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[0][3] ); - pTri[2][1] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[1], vert2->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[1][3] ); - pTri[2][2] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[2], vert2->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[2][3] ); + pTri[2][0] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0], vert2->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0][3] ); + pTri[2][1] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1], vert2->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1][3] ); + pTri[2][2] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2], vert2->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2][3] ); } vec3_t normal; @@ -1190,17 +1202,17 @@ void G2_ProcessSurfaceBolt(mdxaBone_v &bonePtr, mdxmSurface_t *surface, int bolt // w = v->weights; const int iNumWeights = G2_GetVertWeights( v ); - + float fTotalWeight = 0.0f; for ( k = 0 ; k < iNumWeights ; k++ ) { int iBoneIndex = G2_GetVertBoneIndex( v, k ); - float fBoneWeight = G2_GetVertBoneWeight( v, k ); + float fBoneWeight = G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights ); //bone = bonePtr + piBoneRefs[w->boneIndex]; - pTri[j][0] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[0], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[0][3] ); - pTri[j][1] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[1], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[1][3] ); - pTri[j][2] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].matrix[2], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].matrix[2][3] ); + pTri[j][0] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[0][3] ); + pTri[j][1] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[1][3] ); + pTri[j][2] += fBoneWeight * ( DotProduct( bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2], v->vertCoords ) + bonePtr[piBoneRefs[iBoneIndex]].second.matrix[2][3] ); } v++;// = (mdxmVertex_t *)&v->weights[/*v->numWeights*/surface->maxVertBoneWeights]; @@ -1272,6 +1284,7 @@ void G2_ProcessGeneratedSurfaceBolts(CGhoul2Info &ghoul2, mdxaBone_v &bonePtr, m } } +#ifndef DEDICATED // set up each surface ready for rendering in the back end void RenderSurfaces(CRenderSurface &RS) { @@ -1385,6 +1398,7 @@ void RenderSurfaces(CRenderSurface &RS) RenderSurfaces(RS); } } +#endif //!DEDICATED // Go through the model and deal with just the surfaces that are tagged as bolt on points - this is for the server side skeleton construction void ProcessModelBoltSurfaces(int surfaceNum, surfaceInfo_v &rootSList, @@ -1517,20 +1531,6 @@ void G2_ConstructUsedBoneList(CConstructBoneList &CBL) } } -// count to the last bone used in the used bone list so we can resize the bone repository array struct for this ent -static int G2_CountBonesUsed(const int * const boneUsedList, int boneCount) -{ - int found = -1; - for (int i=0; ie.ghoul2); - // if we don't want server ghoul2 models and this is one, or we just don't want ghoul2 models at all, then return - if ((r_noServerGhoul2->integer && !(ghoul2[0].mCreationID & WF_CLIENTONLY)) || (r_noGhoul2->integer)) + // if we don't want server ghoul2 models and this is one, then return + if ((r_noServerGhoul2->integer && !(ghoul2[0].mCreationID & WF_CLIENTONLY)) ) { return; } @@ -1679,7 +1680,7 @@ void R_AddGhoulSurfaces( trRefEntity_t *ent ) { personalModel = (qboolean)((ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal); modelList = (int*)Z_Malloc(ghoul2.size() * 4, TAG_GHOUL2, qtrue); - +#ifndef DEDICATED // set up lighting now that we know we aren't culled if ( !personalModel || r_shadows->integer > 1 ) { @@ -1689,6 +1690,7 @@ void R_AddGhoulSurfaces( trRefEntity_t *ent ) { // see if we are in a fog volume fogNum = R_GComputeFogNum( ent ); +#endif // !DEDICATED // order sort the ghoul 2 models so bolt ons get bolted to the right model G2_Sort_Models(ghoul2, modelList, &modelCount); @@ -1708,7 +1710,7 @@ void R_AddGhoulSurfaces( trRefEntity_t *ent ) { currentModel = R_GetModelByHandle(ghoul2[i].mModel); animModel = R_GetModelByHandle(currentModel->mdxm->animIndex); aHeader = animModel->mdxa; - + #ifndef DEDICATED // // figure out whether we should be using a custom shader for this model // @@ -1734,7 +1736,7 @@ void R_AddGhoulSurfaces( trRefEntity_t *ent ) { skin = R_GetSkinByHandle( ghoul2[i].mSkin ); } } - +#endif //!DEDICATED if (ghoul2[i].mSkelFrameNum != tr.refdef.time) { @@ -1761,8 +1763,16 @@ void R_AddGhoulSurfaces( trRefEntity_t *ent ) { // make sure the root bone is marked as being referenced boneUsedList[0] =1; } - - ghoul2[i].mTempBoneList.resize(G2_CountBonesUsed(boneUsedList, animModel->mdxa->numBones)+1); + + if (ghoul2[i].mTempBoneList.size()!=animModel->mdxa->numBones+1) + { + ghoul2[i].mTempBoneList.resize(animModel->mdxa->numBones+1); + int k; + for (k=0;kmdxa->numBones;k++) + { + ghoul2[i].mTempBoneList[k].first=-10000; //reset it to an invalid time + } + } // if this is the root model, and we have a new root matrix because the model has a new origin, use that if (!setNewOrigin || j) @@ -1782,8 +1792,61 @@ void R_AddGhoulSurfaces( trRefEntity_t *ent ) { } } + mdxaBone_v oldBones; + if (r_Ghoul2AnimSmooth&&r_Ghoul2AnimSmooth->value>0.005f&&r_Ghoul2AnimSmooth->value<0.995f) + { + oldBones=ghoul2[i].mTempBoneList; + } // pre-transform all the bones of this model G2_TransformGhoulBones( aHeader, boneUsedList, ghoul2[i].mBlist, ghoul2[i].mTempBoneList, ghoul2[i].mBltlist, rootMatrix, ghoul2[i], tr.refdef.time, animModel->mdxa->numBones); + if (oldBones.size()) + { + int b; + for (b=0;bmdxa->numBones;b++) + { + if (r_Ghoul2AnimSmooth&&r_Ghoul2AnimSmooth->value>0.005f&&r_Ghoul2AnimSmooth->value<0.995f) + { + if (tr.refdef.time-ghoul2[i].mTempBoneList[b].first<200&&tr.refdef.time-ghoul2[i].mTempBoneList[b].first>-200) + { + int k; + float *oldM=&oldBones[b].second.matrix[0][0]; + float *newM=&ghoul2[i].mTempBoneList[b].second.matrix[0][0]; + for (k=0;k<12;k++,oldM++,newM++) + { + *newM=r_Ghoul2AnimSmooth->value*(*oldM-*newM)+*newM; + } + } + ghoul2[i].mTempBoneList[b].first=tr.refdef.time; + } + } + } + + if (r_Ghoul2UnSqashAfterSmooth&&r_Ghoul2UnSqashAfterSmooth->value>0.5f) + { + mdxaSkelOffsets_t *offsets = (mdxaSkelOffsets_t *)((byte *)aHeader + sizeof(mdxaHeader_t)); + int b; + for (b=0;bmdxa->numBones;b++) + { + if (!boneUsedList) + { + continue; + } + mdxaSkel_t *skel= (mdxaSkel_t *)((byte *)aHeader + sizeof(mdxaHeader_t) + offsets->offsets[b]); + mdxaBone_t tempMatrix; + Multiply_3x4Matrix(&tempMatrix,&ghoul2[i].mTempBoneList[b].second, &skel->BasePoseMat); + float maxl; + maxl=VectorLength(&skel->BasePoseMat.matrix[0][0]); + VectorNormalize(&tempMatrix.matrix[0][0]); + VectorNormalize(&tempMatrix.matrix[1][0]); + VectorNormalize(&tempMatrix.matrix[2][0]); + + VectorScale(&tempMatrix.matrix[0][0],maxl,&tempMatrix.matrix[0][0]); + VectorScale(&tempMatrix.matrix[1][0],maxl,&tempMatrix.matrix[1][0]); + VectorScale(&tempMatrix.matrix[2][0],maxl,&tempMatrix.matrix[2][0]); + Multiply_3x4Matrix(&ghoul2[i].mTempBoneList[b].second,&tempMatrix,&skel->BasePoseMatInv); + } + + } Z_Free(boneUsedList); } @@ -1810,7 +1873,9 @@ void R_AddGhoulSurfaces( trRefEntity_t *ent ) { else { // start the walk of the surface hierarchy CRenderSurface RS(ghoul2[i].mSurfaceRoot, ghoul2[i].mSlist, cust_shader, fogNum, personalModel, ghoul2[i].mTempBoneList, ent->e.renderfx, skin, currentModel, whichLod, ghoul2[i].mBltlist); +#ifndef DEDICATED RenderSurfaces(RS); +#endif } // go through all the generated surfaces and create their bolt info if we need it. @@ -1837,8 +1902,8 @@ void G2_ConstructGhoulSkeleton( CGhoul2Info_v &ghoul2, const int frameNum, qhand bool setNewOrigin = false; mdxaBone_t rootMatrix; - // if we don't want server ghoul2 models and this is one, or we just don't want ghoul2 models at all, then return - if ((r_noServerGhoul2->integer && !(ghoul2[0].mCreationID & WF_CLIENTONLY)) || (r_noGhoul2->integer)) + // if we don't want server ghoul2 models and this is one, then return + if ((r_noServerGhoul2->integer && !(ghoul2[0].mCreationID & WF_CLIENTONLY)) ) { return; } @@ -1942,7 +2007,15 @@ void G2_ConstructGhoulSkeleton( CGhoul2Info_v &ghoul2, const int frameNum, qhand boneUsedList[0] =1; } - ghoul2[i].mTempBoneList.resize(G2_CountBonesUsed(boneUsedList, animModel->mdxa->numBones)+1); + if (ghoul2[i].mTempBoneList.size()!=animModel->mdxa->numBones+1) + { + ghoul2[i].mTempBoneList.resize(animModel->mdxa->numBones+1); + int k; + for (k=0;kmdxa->numBones;k++) + { + ghoul2[i].mTempBoneList[k].first=-10000; //reset it to an invalid time + } + } // decide what to do about the root matrix @@ -1963,9 +2036,63 @@ void G2_ConstructGhoulSkeleton( CGhoul2Info_v &ghoul2, const int frameNum, qhand } } + mdxaBone_v oldBones; + if (r_Ghoul2AnimSmooth&&r_Ghoul2AnimSmooth->value>0.005f&&r_Ghoul2AnimSmooth->value<0.995f) + { + oldBones=ghoul2[i].mTempBoneList; + } // pre-transform all the bones of this model G2_TransformGhoulBones( aHeader, boneUsedList, ghoul2[i].mBlist, ghoul2[i].mTempBoneList, ghoul2[i].mBltlist, rootMatrix, ghoul2[i], frameNum, animModel->mdxa->numBones); + if (oldBones.size()) + { + int b; + for (b=0;bmdxa->numBones;b++) + { + if (r_Ghoul2AnimSmooth&&r_Ghoul2AnimSmooth->value>0.005f&&r_Ghoul2AnimSmooth->value<0.995f) + { + if (tr.refdef.time-ghoul2[i].mTempBoneList[b].first<200&&tr.refdef.time-ghoul2[i].mTempBoneList[b].first>-200) + { + int k; + float *oldM=&oldBones[b].second.matrix[0][0]; + float *newM=&ghoul2[i].mTempBoneList[b].second.matrix[0][0]; + for (k=0;k<12;k++,oldM++,newM++) + { + *newM=r_Ghoul2AnimSmooth->value*(*oldM-*newM)+*newM; + } + } + ghoul2[i].mTempBoneList[b].first=tr.refdef.time; + } + } + } + + if (r_Ghoul2UnSqashAfterSmooth&&r_Ghoul2UnSqashAfterSmooth->value>0.5f) + { + mdxaSkelOffsets_t *offsets = (mdxaSkelOffsets_t *)((byte *)aHeader + sizeof(mdxaHeader_t)); + int b; + for (b=0;bmdxa->numBones;b++) + { + if (!boneUsedList) + { + continue; + } + mdxaSkel_t *skel= (mdxaSkel_t *)((byte *)aHeader + sizeof(mdxaHeader_t) + offsets->offsets[b]); + mdxaBone_t tempMatrix; + Multiply_3x4Matrix(&tempMatrix,&ghoul2[i].mTempBoneList[b].second, &skel->BasePoseMat); + float maxl; + maxl=VectorLength(&skel->BasePoseMat.matrix[0][0]); + VectorNormalize(&tempMatrix.matrix[0][0]); + VectorNormalize(&tempMatrix.matrix[1][0]); + VectorNormalize(&tempMatrix.matrix[2][0]); + + VectorScale(&tempMatrix.matrix[0][0],maxl,&tempMatrix.matrix[0][0]); + VectorScale(&tempMatrix.matrix[1][0],maxl,&tempMatrix.matrix[1][0]); + VectorScale(&tempMatrix.matrix[2][0],maxl,&tempMatrix.matrix[2][0]); + Multiply_3x4Matrix(&ghoul2[i].mTempBoneList[b].second,&tempMatrix,&skel->BasePoseMatInv); + } + + } + Z_Free(boneUsedList); // call function that will go through the main model and generate all the bolts required @@ -1980,7 +2107,7 @@ void G2_ConstructGhoulSkeleton( CGhoul2Info_v &ghoul2, const int frameNum, qhand return; } - +#ifndef DEDICATED /* ============== RB_SurfaceGhoul @@ -2040,12 +2167,13 @@ void RB_SurfaceGhoul( CRenderableSurface *surf ) { VectorClear( tess.xyz[baseVert]); VectorClear( tess.normal[baseVert]); + float fTotalWeight = 0.0f; for ( k = 0 ; k < iNumWeights ; k++ ) { int iBoneIndex = G2_GetVertBoneIndex( v, k ); - float fBoneWeight = G2_GetVertBoneWeight( v, k ); + float fBoneWeight = G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights ); - mdxaBone_t &bone = bonePtr[piBoneRefs[iBoneIndex]]; + mdxaBone_t &bone = bonePtr[piBoneRefs[iBoneIndex]].second; tess.xyz[baseVert][0] += fBoneWeight * ( DotProduct( bone.matrix[0], v->vertCoords ) + bone.matrix[0][3] ); tess.xyz[baseVert][1] += fBoneWeight * ( DotProduct( bone.matrix[1], v->vertCoords ) + bone.matrix[1][3] ); @@ -2064,7 +2192,7 @@ void RB_SurfaceGhoul( CRenderableSurface *surf ) { tess.numVertexes += surface->numVerts; } - +#endif // !DEDICATED /* ================= @@ -2158,11 +2286,11 @@ qboolean R_LoadMDXM( model_t *mod, void *buffer, const char *mod_name, qboolean { LL(surfInfo->childIndexes[j]); } - +#ifndef DEDICATED // get the shader name sh = R_FindShader( surfInfo->shader, lightmapsNone, stylesDefault, qtrue ); // insert it in the surface list - +#endif if ( sh->defaultShader ) { surfInfo->shaderIndex = 0; diff --git a/CODE-mp/renderer/tr_image.cpp b/CODE-mp/renderer/tr_image.cpp index 10f0cc7..f1331a1 100644 --- a/CODE-mp/renderer/tr_image.cpp +++ b/CODE-mp/renderer/tr_image.cpp @@ -1,8 +1,6 @@ // tr_image.c #include "tr_local.h" #include "glext.h" -#include "../win32/glw_win.h" - #pragma warning (push, 3) //go back down to 3 for the stl include #include @@ -22,7 +20,7 @@ using namespace std; #include "../jpeg-6/jpeglib.h" #include "../png/png.h" -static void LoadBMP( const char *name, byte **pic, int *width, int *height ); +#ifndef DEDICATED static void LoadTGA( const char *name, byte **pic, int *width, int *height ); static void LoadJPG( const char *name, byte **pic, int *width, int *height ); @@ -60,128 +58,6 @@ textureMode_t modes[] = { {"GL_LINEAR_MIPMAP_LINEAR", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR} }; -typedef struct textureFormat_s -{ - char *name; - GLenum type; - float bytesPerTexel; - char *primaryExtension; - char *secondaryExtension; -} textureFormat_t; - -static textureFormat_t textureFormats[] = -{ - // Fallback safe formats - { "GL_SOLID_FORMAT", GL_SOLID_FORMAT, 2.0f, NULL, NULL }, - { "GL_ALPHA_FORMAT", GL_ALPHA_FORMAT, 2.0f, NULL, NULL }, - - // OpenGL1.1 formats - all should be valid - { "GL_RGB", GL_RGB, 2.0f, NULL, NULL }, - { "GL_RGB5", GL_RGB5, 2.0f, NULL, NULL }, - { "GL_RGB8", GL_RGB8, 4.0f, NULL, NULL }, - { "GL_RGB16", GL_RGB16, 8.0f, NULL, NULL }, - - { "GL_RGBA", GL_RGBA, 2.0f, NULL, NULL }, - { "GL_RGBA4", GL_RGBA4, 2.0f, NULL, NULL }, - { "GL_RGBA8", GL_RGBA8, 4.0f, NULL, NULL }, - { "GL_RGBA16", GL_RGBA16, 8.0f, NULL, NULL }, - - { "GL_LUMINANCE8", GL_LUMINANCE8, 1.0f, NULL, NULL }, - { "GL_INTENSITY8", GL_INTENSITY8, 1.0f, NULL, NULL }, - { "GL_ALPHA8", GL_ALPHA8, 1.0f, NULL, NULL }, - - // Extended formats - { "GL_RGB4_S3TC", GL_RGB4_S3TC, 0.33333f, "GL_S3_s3tc", NULL }, - - { "GL_COMPRESSED_RGB_DXT1", GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 0.33333f, "ARB_texture_compression", "EXT_texture_compression_s3tc" }, - { "GL_COMPRESSED_RGBA_DXT5", GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 1.0f, "ARB_texture_compression", "EXT_texture_compression_s3tc" }, - - { "GL_COMPRESSED_RGB_FXT1", GL_COMPRESSED_RGB_FXT1_3DFX, 1.0f, "ARB_texture_compression", "3DFX_texture_compression_FXT1" }, -}; - -/* -=============== -GL_SetTextureFormat -=============== -*/ - -// fallback is either 0 or 1 for the simple 1.0 textures - -int GL_SetTextureFormat( const char *format, int fallback ) -{ - int i, count; - char *primary; - char *secondary; - - count = sizeof(textureFormats) / sizeof(textureFormat_t); - for ( i = 0 ; i < count ; i++ ) - { - if ( !Q_stricmp( textureFormats[i].name, format ) ) - { - break; - } - } - if(i == count) - { - ri.Printf(PRINT_ALL, S_COLOR_RED "TextureFormat: Unknown texture format %s\n", format); - return(fallback); - } - // If no extension required, just return the enum - if(!textureFormats[i].primaryExtension && !textureFormats[i].secondaryExtension) - { - return(i); - } - - // Check for extensions - primary = textureFormats[i].primaryExtension; - secondary = textureFormats[i].secondaryExtension; - if(GL_CheckForExtension(primary) && !secondary) - { - return(i); - } - if(GL_CheckForExtension(primary) && GL_CheckForExtension(secondary)) - { - return(i); - } - ri.Printf(PRINT_ALL, S_COLOR_RED "TextureFormat: Unsupported extended texture format %s\n", format); - return(fallback); -} - -void GL_InitTextureFormats( void ) -{ - int idx; - - idx = GL_SetTextureFormat( r_tf_solid_compressed->string, 0 ); - glConfig.tfSolidCompressed = textureFormats[idx].type; - glConfig.tfSolidCompressedBPT = textureFormats[idx].bytesPerTexel; - ri.Cvar_Set("r_tf_solid_compressed", textureFormats[idx].name); - - idx = GL_SetTextureFormat( r_tf_alpha_compressed->string, 1 ); - glConfig.tfAlphaCompressed = textureFormats[idx].type; - glConfig.tfAlphaCompressedBPT = textureFormats[idx].bytesPerTexel; - ri.Cvar_Set("r_tf_alpha_compressed", textureFormats[idx].name); - - idx = GL_SetTextureFormat( r_tf_solid_uncompressed->string, 0 ); - glConfig.tfSolidUncompressed = textureFormats[idx].type; - glConfig.tfSolidUncompressedBPT = textureFormats[idx].bytesPerTexel; - ri.Cvar_Set("r_tf_solid_uncompressed", textureFormats[idx].name); - - idx = GL_SetTextureFormat( r_tf_alpha_uncompressed->string, 1 ); - glConfig.tfAlphaUncompressed = textureFormats[idx].type; - glConfig.tfAlphaUncompressedBPT = textureFormats[idx].bytesPerTexel; - ri.Cvar_Set("r_tf_alpha_uncompressed", textureFormats[idx].name); - - idx = GL_SetTextureFormat( r_tf_lightmap->string, 0 ); - glConfig.tfLightmap = textureFormats[idx].type; - glConfig.tfLightmapBPT = textureFormats[idx].bytesPerTexel; - ri.Cvar_Set("r_tf_lightmap", textureFormats[idx].name); - - idx = GL_SetTextureFormat( r_tf_cinematic->string, 0 ); - glConfig.tfCinematic = textureFormats[idx].type; - glConfig.tfCinematicBPT = textureFormats[idx].bytesPerTexel; - ri.Cvar_Set("r_tf_cinematic", textureFormats[idx].name); -} - // makeup a nice clean, consistant name to query for and file under, for map<> usage... // @@ -424,56 +300,6 @@ void R_ImageList_f( void ) { //======================================================================= -/* -================ -ResampleTexture - -Used to resample images in a more general than quartering fashion. - -This will only be filtered properly if the resampled size -is greater than half the original size. - -If a larger shrinking is needed, use the mipmap function -before or after. -================ -*/ -static void ResampleTexture( unsigned *in, int inwidth, int inheight, unsigned *out, - int outwidth, int outheight ) { - int i, j; - unsigned *inrow, *inrow2; - unsigned frac, fracstep; - unsigned p1[1024], p2[1024]; - byte *pix1, *pix2, *pix3, *pix4; - - fracstep = inwidth*0x10000/outwidth; - - frac = fracstep>>2; - for ( i=0 ; i>16); - frac += fracstep; - } - frac = 3*(fracstep>>2); - for ( i=0 ; i>16); - frac += fracstep; - } - - for (i=0 ; i> 1; - for (j=0 ; j>2; - ((byte *)(out+j))[1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2; - ((byte *)(out+j))[2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2; - ((byte *)(out+j))[3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2; - } - } -} /* ================ @@ -724,7 +550,9 @@ static void R_Images_DeleteImageContents( image_t *pImage ) assert(pImage); // should never be called with NULL if (pImage) { - qglDeleteTextures( 1, &pImage->texnum ); + if (qglDeleteTextures) { //won't have one if we switched to dedicated. + qglDeleteTextures( 1, &pImage->texnum ); + } Z_Free(pImage); } } @@ -741,68 +569,36 @@ Upload32 */ extern qboolean charSet; static void Upload32( unsigned *data, - int width, int height, - qboolean mipmap, - qboolean picmip, - qboolean lightMap, - qboolean allowTC, - int *format, - int *pUploadWidth, int *pUploadHeight ) + int img_width, int img_height, + qboolean mipmap, + qboolean picmip, + qboolean isLightmap, + qboolean allowTC, + int *pformat, + int *pUploadWidth, int *pUploadHeight ) { int samples; - unsigned *scaledBuffer = NULL; - unsigned *resampledBuffer = NULL; - int scaled_width, scaled_height; int i, c; byte *scan; - GLenum internalFormat = GL_RGB; float rMax = 0, gMax = 0, bMax = 0; - - if (r_force_compressed_textures->integer) - { - allowTC = qtrue; - } - if (!r_ext_compressed_textures->integer) - { - allowTC = qfalse; - } - - // - // convert to exact power of 2 sizes - // - for (scaled_width = 1 ; scaled_width < width ; scaled_width<<=1) - ; - for (scaled_height = 1 ; scaled_height < height ; scaled_height<<=1) - ; - if ( r_roundImagesDown->integer && scaled_width > width ) - scaled_width >>= 1; - if ( r_roundImagesDown->integer && scaled_height > height ) - scaled_height >>= 1; - - if ( scaled_width != width || scaled_height != height ) { - resampledBuffer = (unsigned int *)ri.Hunk_AllocateTempMemory( scaled_width * scaled_height * 4 ); - ResampleTexture (data, width, height, resampledBuffer, scaled_width, scaled_height); - data = resampledBuffer; - width = scaled_width; - height = scaled_height; - } + int width = img_width; + int height = img_height; // // perform optional picmip operation // if ( picmip ) { - scaled_width >>= r_picmip->integer; - scaled_height >>= r_picmip->integer; - } - - // - // clamp to minimum size - // - if (scaled_width < 1) { - scaled_width = 1; - } - if (scaled_height < 1) { - scaled_height = 1; + for(i = 0; i < r_picmip->integer; i++) { + R_MipMap( (byte *)data, width, height ); + width >>= 1; + height >>= 1; + if (width < 1) { + width = 1; + } + if (height < 1) { + height = 1; + } + } } // @@ -810,14 +606,12 @@ static void Upload32( unsigned *data, // scale both axis down equally so we don't have to // deal with a half mip resampling // - while ( scaled_width > glConfig.maxTextureSize - || scaled_height > glConfig.maxTextureSize ) { - scaled_width >>= 1; - scaled_height >>= 1; + while ( width > glConfig.maxTextureSize || height > glConfig.maxTextureSize ) { + R_MipMap( (byte *)data, width, height ); + width >>= 1; + height >>= 1; } - scaledBuffer = (unsigned int *)ri.Hunk_AllocateTempMemory( sizeof( unsigned ) * scaled_width * scaled_height ); - // // scan the texture for each channel's max values // and verify if the alpha channel is being used or not @@ -825,116 +619,124 @@ static void Upload32( unsigned *data, c = width*height; scan = ((byte *)data); samples = 3; - if (!lightMap) + for ( i = 0; i < c; i++ ) { - for ( i = 0; i < c; i++ ) + if ( scan[i*4+0] > rMax ) { - if ( scan[i*4+0] > rMax ) - { - rMax = scan[i*4+0]; - } - if ( scan[i*4+1] > gMax ) - { - gMax = scan[i*4+1]; - } - if ( scan[i*4+2] > bMax ) - { - bMax = scan[i*4+2]; - } - if ( scan[i*4 + 3] != 255 ) - { - samples = 4; - break; - } + rMax = scan[i*4+0]; } - // select proper internal format - if ( samples == 3 ) + if ( scan[i*4+1] > gMax ) { - if ( allowTC) - { - internalFormat = glConfig.tfSolidCompressed; - } - else - { - internalFormat = glConfig.tfSolidUncompressed; - } + gMax = scan[i*4+1]; } - else if ( samples == 4 ) + if ( scan[i*4+2] > bMax ) { - if ( allowTC) - { // Compress both alpha and color - internalFormat = glConfig.tfAlphaCompressed; - } - else - { - internalFormat = glConfig.tfAlphaUncompressed; - } + bMax = scan[i*4+2]; + } + if ( scan[i*4 + 3] != 255 ) + { + samples = 4; + break; } } - else + + // select proper internal format + if ( samples == 3 ) { - internalFormat = glConfig.tfLightmap; + if ( glConfig.textureCompression == TC_S3TC && allowTC ) + { + *pformat = GL_RGB4_S3TC; + } + else if ( glConfig.textureCompression == TC_S3TC_DXT && allowTC ) + { // Compress purely color - no alpha + if ( r_texturebits->integer == 16 ) { + *pformat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; //this format cuts to 16 bit + } + else {//if we aren't using 16 bit then, use 32 bit compression + *pformat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + } + } + else if ( isLightmap && r_texturebitslm->integer > 0 ) + { + // Allow different bit depth when we are a lightmap + if ( r_texturebitslm->integer == 16 ) + { + *pformat = GL_RGB5; + } + else if ( r_texturebitslm->integer == 32 ) + { + *pformat = GL_RGB8; + } + } + else if ( r_texturebits->integer == 16 ) + { + *pformat = GL_RGB5; + } + else if ( r_texturebits->integer == 32 ) + { + *pformat = GL_RGB8; + } + else + { + *pformat = 3; + } } + else if ( samples == 4 ) + { + if ( glConfig.textureCompression == TC_S3TC_DXT && allowTC) + { // Compress both alpha and color + *pformat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + } + else if ( r_texturebits->integer == 16 ) + { + *pformat = GL_RGBA4; + } + else if ( r_texturebits->integer == 32 ) + { + *pformat = GL_RGBA8; + } + else + { + *pformat = 4; + } + } + + *pUploadWidth = width; + *pUploadHeight = height; + // copy or resample data as appropriate for first MIP level - if ( ( scaled_width == width ) && - ( scaled_height == height ) ) { - if (!mipmap) - { - qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - *format = internalFormat; - - goto done; - } - Com_Memcpy (scaledBuffer, data, width*height*4); - } - else + if (!mipmap) { - // use the normal mip-mapping function to go down from here - while ( width > scaled_width || height > scaled_height ) { - R_MipMap( (byte *)data, width, height ); - width >>= 1; - height >>= 1; - if ( width < 1 ) { - width = 1; - } - if ( height < 1 ) { - height = 1; - } - } - Com_Memcpy( scaledBuffer, data, width * height * 4 ); + qglTexImage2D (GL_TEXTURE_2D, 0, *pformat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + goto done; } - R_LightScaleTexture (scaledBuffer, scaled_width, scaled_height, (qboolean)!mipmap ); + R_LightScaleTexture (data, width, height, (qboolean)!mipmap ); - *pUploadWidth = scaled_width; - *pUploadHeight = scaled_height; - *format = internalFormat; - - qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); + qglTexImage2D (GL_TEXTURE_2D, 0, *pformat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); if (mipmap) { int miplevel; miplevel = 0; - while (scaled_width > 1 || scaled_height > 1) + while (width > 1 || height > 1) { - R_MipMap( (byte *)scaledBuffer, scaled_width, scaled_height ); - scaled_width >>= 1; - scaled_height >>= 1; - if (scaled_width < 1) - scaled_width = 1; - if (scaled_height < 1) - scaled_height = 1; + R_MipMap( (byte *)data, width, height ); + width >>= 1; + height >>= 1; + if (width < 1) + width = 1; + if (height < 1) + height = 1; miplevel++; - if ( r_colorMipLevels->integer ) { - R_BlendOverTexture( (byte *)scaledBuffer, scaled_width * scaled_height, mipBlendColors[miplevel] ); + if ( r_colorMipLevels->integer ) + { + R_BlendOverTexture( (byte *)data, width * height, mipBlendColors[miplevel] ); } - qglTexImage2D (GL_TEXTURE_2D, miplevel, internalFormat, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaledBuffer ); + qglTexImage2D (GL_TEXTURE_2D, miplevel, *pformat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); } } done: @@ -954,11 +756,6 @@ done: } GL_CheckErrors(); - - if ( scaledBuffer != 0 ) - ri.Hunk_FreeTempMemory( scaledBuffer ); - if ( resampledBuffer != 0 ) - ri.Hunk_FreeTempMemory( resampledBuffer ); } @@ -998,9 +795,15 @@ void R_Images_DeleteLightMaps(void) if (pImage->imgName[0] == '*' && strstr(pImage->imgName,"lightmap")) // loose check, but should be ok { R_Images_DeleteImageContents(pImage); - +#ifndef __linux__ itImage = AllocatedImages.erase(itImage); bEraseOccured = qtrue; +#else + // MS & Dinkimware got the map::erase return wrong (it's null) + AllocatedImages_t::iterator itTemp = itImage; + itImage++; + AllocatedImages.erase(itTemp); +#endif } } @@ -1096,9 +899,14 @@ qboolean RE_RegisterImages_LevelLoadEnd(void) ri.Printf( PRINT_DEVELOPER, "Dumping image \"%s\"\n",pImage->imgName); R_Images_DeleteImageContents(pImage); - +#ifndef __linux__ itImage = AllocatedImages.erase(itImage); bEraseOccured = qtrue; +#else + AllocatedImages_t::iterator itTemp = itImage; + itImage++; + AllocatedImages.erase(itTemp); +#endif } } } @@ -1260,321 +1068,7 @@ image_t *R_CreateImage( const char *name, const byte *pic, int width, int height return image; } - - -/* -========================================================= - -BMP LOADING - -========================================================= -*/ -typedef struct -{ - char id[2]; - unsigned long fileSize; - unsigned long reserved0; - unsigned long bitmapDataOffset; - unsigned long bitmapHeaderSize; - unsigned long width; - unsigned long height; - unsigned short planes; - unsigned short bitsPerPixel; - unsigned long compression; - unsigned long bitmapDataSize; - unsigned long hRes; - unsigned long vRes; - unsigned long colors; - unsigned long importantColors; - unsigned char palette[256][4]; -} BMPHeader_t; - -static void LoadBMP( const char *name, byte **pic, int *width, int *height ) -{ - int columns, rows, numPixels; - byte *pixbuf; - int row, column; - byte *buf_p; - byte *buffer; - int length; - BMPHeader_t bmpHeader; - byte *bmpRGBA; - - *pic = NULL; - - // - // load the file - // - length = ri.FS_ReadFile( ( char * ) name, (void **)&buffer); - if (!buffer) { - return; - } - - buf_p = buffer; - - bmpHeader.id[0] = *buf_p++; - bmpHeader.id[1] = *buf_p++; - bmpHeader.fileSize = LittleLong( * ( long * ) buf_p ); - buf_p += 4; - bmpHeader.reserved0 = LittleLong( * ( long * ) buf_p ); - buf_p += 4; - bmpHeader.bitmapDataOffset = LittleLong( * ( long * ) buf_p ); - buf_p += 4; - bmpHeader.bitmapHeaderSize = LittleLong( * ( long * ) buf_p ); - buf_p += 4; - bmpHeader.width = LittleLong( * ( long * ) buf_p ); - buf_p += 4; - bmpHeader.height = LittleLong( * ( long * ) buf_p ); - buf_p += 4; - bmpHeader.planes = LittleShort( * ( short * ) buf_p ); - buf_p += 2; - bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p ); - buf_p += 2; - bmpHeader.compression = LittleLong( * ( long * ) buf_p ); - buf_p += 4; - bmpHeader.bitmapDataSize = LittleLong( * ( long * ) buf_p ); - buf_p += 4; - bmpHeader.hRes = LittleLong( * ( long * ) buf_p ); - buf_p += 4; - bmpHeader.vRes = LittleLong( * ( long * ) buf_p ); - buf_p += 4; - bmpHeader.colors = LittleLong( * ( long * ) buf_p ); - buf_p += 4; - bmpHeader.importantColors = LittleLong( * ( long * ) buf_p ); - buf_p += 4; - - Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) ); - - if ( bmpHeader.bitsPerPixel == 8 ) - buf_p += 1024; - - if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) - { - ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)\n", name ); - } - if ( bmpHeader.fileSize != length ) - { - ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%d vs. %d) (%s)\n", bmpHeader.fileSize, length, name ); - } - if ( bmpHeader.compression != 0 ) - { - ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)\n", name ); - } - if ( bmpHeader.bitsPerPixel < 8 ) - { - ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name ); - } - - columns = bmpHeader.width; - rows = bmpHeader.height; - if ( rows < 0 ) - rows = -rows; - numPixels = columns * rows; - - if ( width ) - *width = columns; - if ( height ) - *height = rows; - - bmpRGBA = (unsigned char *)ri.Malloc( numPixels * 4, TAG_TEMP_WORKSPACE, qfalse ); - *pic = bmpRGBA; - - - for ( row = rows-1; row >= 0; row-- ) - { - pixbuf = bmpRGBA + row*columns*4; - - for ( column = 0; column < columns; column++ ) - { - unsigned char red, green, blue, alpha; - int palIndex; - unsigned short shortPixel; - - switch ( bmpHeader.bitsPerPixel ) - { - case 8: - palIndex = *buf_p++; - *pixbuf++ = bmpHeader.palette[palIndex][2]; - *pixbuf++ = bmpHeader.palette[palIndex][1]; - *pixbuf++ = bmpHeader.palette[palIndex][0]; - *pixbuf++ = 0xff; - break; - case 16: - shortPixel = * ( unsigned short * ) pixbuf; - pixbuf += 2; - *pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7; - *pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2; - *pixbuf++ = ( shortPixel & ( 31 ) ) << 3; - *pixbuf++ = 0xff; - break; - - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alpha = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alpha; - break; - default: - ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel, name ); - break; - } - } - } - - ri.FS_FreeFile( buffer ); - -} - - -/* -================================================================= - -PCX LOADING - -================================================================= -*/ - - -/* -============== -LoadPCX -============== -*/ -static void LoadPCX ( const char *filename, byte **pic, byte **palette, int *width, int *height) -{ - byte *raw; - pcx_t *pcx; - int x, y; - int len; - int dataByte, runLength; - byte *out, *pix; - int xmax, ymax; - - *pic = NULL; - *palette = NULL; - - // - // load the file - // - len = ri.FS_ReadFile( ( char * ) filename, (void **)&raw); - if (!raw) { - return; - } - - // - // parse the PCX file - // - pcx = (pcx_t *)raw; - raw = &pcx->data; - - xmax = LittleShort(pcx->xmax); - ymax = LittleShort(pcx->ymax); - - if (pcx->manufacturer != 0x0a - || pcx->version != 5 - || pcx->encoding != 1 - || pcx->bits_per_pixel != 8 - || xmax >= 1024 - || ymax >= 1024) - { - ri.Printf (PRINT_ALL, "Bad pcx file %s (%i x %i) (%i x %i)\n", filename, xmax+1, ymax+1, pcx->xmax, pcx->ymax); - return; - } - - out = (unsigned char *)ri.Malloc ( (ymax+1) * (xmax+1), TAG_TEMP_WORKSPACE, qfalse ); - - *pic = out; - - pix = out; - - if (palette) - { - *palette = (unsigned char *)ri.Malloc(768, TAG_TEMP_WORKSPACE, qfalse ); - Com_Memcpy (*palette, (byte *)pcx + len - 768, 768); - } - - if (width) - *width = xmax+1; - if (height) - *height = ymax+1; -// FIXME: use bytes_per_line here? - - for (y=0 ; y<=ymax ; y++, pix += xmax+1) - { - for (x=0 ; x<=xmax ; ) - { - dataByte = *raw++; - - if((dataByte & 0xC0) == 0xC0) - { - runLength = dataByte & 0x3F; - dataByte = *raw++; - } - else - runLength = 1; - - while(runLength-- > 0) - pix[x++] = dataByte; - } - - } - - if ( raw - (byte *)pcx > len) - { - ri.Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename); - ri.Free (*pic); - *pic = NULL; - } - - ri.FS_FreeFile (pcx); -} - - -/* -============== -LoadPCX32 -============== -*/ -static void LoadPCX32 ( const char *filename, byte **pic, int *width, int *height) { - byte *palette; - byte *pic8; - int i, c, p; - byte *pic32; - - LoadPCX (filename, &pic8, &palette, width, height); - if (!pic8) { - *pic = NULL; - return; - } - - c = (*width) * (*height); - pic32 = *pic = (unsigned char *)ri.Malloc(4 * c, TAG_TEMP_WORKSPACE, qfalse ); - for (i = 0 ; i < c ; i++) { - p = pic8[i]; - pic32[0] = palette[p*3]; - pic32[1] = palette[p*3 + 1]; - pic32[2] = palette[p*3 + 2]; - pic32[3] = 255; - pic32 += 4; - } - - ri.Free (pic8); - ri.Free (palette); -} - +#endif // !DEDICATED /* ========================================================= @@ -1657,6 +1151,7 @@ bool LoadTGAPalletteImage ( const char *name, byte **pic, int *width, int *heigh return true; } +#ifndef DEDICATED /* Ghoul2 Insert End */ @@ -2876,9 +2371,6 @@ R_InitImages */ void R_InitImages( void ) { //memset(hashTable, 0, sizeof(hashTable)); // DO NOT DO THIS NOW (because of image cacheing) -ste. - - GL_InitTextureFormats(); - // build brightness translation tables R_SetColorMappings(); @@ -3121,7 +2613,7 @@ qhandle_t RE_RegisterSkin( const char *name ) { return hSkin; } - +#endif // !DEDICATED /* =============== R_InitSkins @@ -3152,6 +2644,7 @@ skin_t *R_GetSkinByHandle( qhandle_t hSkin ) { return tr.skins[ hSkin ]; } +#ifndef DEDICATED /* =============== R_SkinList_f @@ -3175,3 +2668,4 @@ void R_SkinList_f( void ) { ri.Printf (PRINT_ALL, "------------------\n"); } +#endif // !DEDICATED diff --git a/CODE-mp/renderer/tr_init.cpp b/CODE-mp/renderer/tr_init.cpp index 5ebb56b..e0a4a31 100644 --- a/CODE-mp/renderer/tr_init.cpp +++ b/CODE-mp/renderer/tr_init.cpp @@ -2,9 +2,11 @@ #include "tr_local.h" +#ifndef DEDICATED #if !defined __TR_WORLDEFFECTS_H #include "tr_WorldEffects.h" #endif +#endif //!DEDICATED #include "tr_font.h" @@ -14,11 +16,14 @@ //void RE_A3D_RenderGeometry (void *pVoidA3D, void *pVoidGeom, void *pVoidMat, void *pVoidGeomStatus); //#endif +#ifndef DEDICATED glconfig_t glConfig; glstate_t glState; - static void GfxInfo_f( void ); +#endif + + cvar_t *r_flareSize; cvar_t *r_flareFade; @@ -48,6 +53,7 @@ cvar_t *r_dlightBacks; cvar_t *r_lodbias; cvar_t *r_lodscale; +cvar_t *r_autolodscalevalue; cvar_t *r_norefresh; cvar_t *r_drawentities; @@ -71,17 +77,11 @@ cvar_t *r_windPointForce; cvar_t *r_windPointX; cvar_t *r_windPointY; - cvar_t *r_allowExtensions; -cvar_t *r_tf_solid_compressed; -cvar_t *r_tf_alpha_compressed; -cvar_t *r_tf_solid_uncompressed; -cvar_t *r_tf_alpha_uncompressed; -cvar_t *r_tf_lightmap; -cvar_t *r_tf_cinematic; -cvar_t *r_force_compressed_textures; cvar_t *r_ext_compressed_textures; +cvar_t *r_ext_compressed_lightmaps; +cvar_t *r_ext_preferred_tc_method; cvar_t *r_ext_gamma_control; cvar_t *r_ext_multitexture; cvar_t *r_ext_compiled_vertex_array; @@ -108,7 +108,6 @@ cvar_t *r_flares; cvar_t *r_mode; cvar_t *r_nobind; cvar_t *r_singleShader; -cvar_t *r_roundImagesDown; cvar_t *r_colorMipLevels; cvar_t *r_picmip; cvar_t *r_showtris; @@ -136,7 +135,6 @@ cvar_t *r_customheight; cvar_t *r_customaspect; cvar_t *r_overBrightBits; -cvar_t *r_mapOverBrightBits; cvar_t *r_debugSurface; cvar_t *r_simpleMipMaps; @@ -162,11 +160,19 @@ Ghoul2 Insert Start */ cvar_t *r_noServerGhoul2; -cvar_t *r_noGhoul2; +cvar_t *r_Ghoul2AnimSmooth=0; +cvar_t *r_Ghoul2UnSqashAfterSmooth=0; +//cvar_t *r_Ghoul2UnSqash; +//cvar_t *r_Ghoul2TimeBase=0; from single player +//cvar_t *r_Ghoul2NoLerp; +//cvar_t *r_Ghoul2NoBlend; +//cvar_t *r_Ghoul2BlendMultiplier=0; + /* Ghoul2 Insert End */ +#ifndef DEDICATED void ( APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t ); void ( APIENTRY * qglActiveTextureARB )( GLenum texture ); void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture ); @@ -181,6 +187,8 @@ void RE_SetLightStyle(int style, int color); void RE_GetBModelVerts( int bmodelIndex, vec3_t *verts, vec3_t normal ); +#endif // !DEDICATED + static void AssertCvarRange( cvar_t *cv, float minVal, float maxVal, qboolean shouldBeIntegral ) { if ( shouldBeIntegral ) @@ -204,6 +212,7 @@ static void AssertCvarRange( cvar_t *cv, float minVal, float maxVal, qboolean sh } } +#ifndef DEDICATED /* ** InitOpenGL @@ -215,8 +224,6 @@ static void AssertCvarRange( cvar_t *cv, float minVal, float maxVal, qboolean sh */ static void InitOpenGL( void ) { - char renderer_buffer[1024]; - // // initialize OS specific portions of the renderer // @@ -230,30 +237,14 @@ static void InitOpenGL( void ) if ( glConfig.vidWidth == 0 ) { - GLint temp; - GLimp_Init(); - - strcpy( renderer_buffer, glConfig.renderer_string ); - Q_strlwr( renderer_buffer ); - - // OpenGL driver constants - qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &temp ); - glConfig.maxTextureSize = temp; - - // stubbed or broken drivers may have reported 0... - if ( glConfig.maxTextureSize <= 0 ) - { - glConfig.maxTextureSize = 0; - } + // print info the first time only + GfxInfo_f(); } // init command buffers and SMP R_InitCommandBuffers(); - // print info - GfxInfo_f(); - // set default state GL_SetDefaultState(); } @@ -301,6 +292,7 @@ void GL_CheckErrors( void ) { ri.Error( ERR_FATAL, "GL_CheckErrors: %s", s ); } +#endif //!DEDICATED /* ** R_GetModeInfo @@ -378,7 +370,7 @@ static void R_ModeList_f( void ) ============================================================================== */ - +#ifndef DEDICATED /* ================== R_TakeScreenshot @@ -721,6 +713,13 @@ void GfxInfo_f( void ) "fullscreen" }; + const char *tc_table[] = + { + "None", + "GL_S3_s3tc", + "GL_EXT_texture_compression_s3tc", + }; + ri.Printf( PRINT_ALL, "\nGL_VENDOR: %s\n", glConfig.vendor_string ); ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glConfig.renderer_string ); ri.Printf( PRINT_ALL, "GL_VERSION: %s\n", glConfig.version_string ); @@ -779,6 +778,9 @@ void GfxInfo_f( void ) ri.Printf( PRINT_ALL, "multitexture: %s\n", enablestrings[qglActiveTextureARB != 0] ); ri.Printf( PRINT_ALL, "compiled vertex arrays: %s\n", enablestrings[qglLockArraysEXT != 0 ] ); ri.Printf( PRINT_ALL, "texenv add: %s\n", enablestrings[glConfig.textureEnvAddAvailable != 0] ); + ri.Printf( PRINT_ALL, "compressed textures: %s\n", enablestrings[glConfig.textureCompression != TC_NONE] ); + ri.Printf( PRINT_ALL, "compressed lightmaps: %s\n", enablestrings[(r_ext_compressed_lightmaps->integer != 0 && glConfig.textureCompression != TC_NONE)] ); + ri.Printf( PRINT_ALL, "texture compression method: %s\n", tc_table[glConfig.textureCompression] ); ri.Printf( PRINT_ALL, "anisotropic filtering: %s\n", enablestrings[(r_ext_texture_filter_anisotropic->integer != 0) && glConfig.textureFilterAnisotropicAvailable] ); if ( glConfig.smpActive ) { @@ -787,8 +789,16 @@ void GfxInfo_f( void ) if ( r_finish->integer ) { ri.Printf( PRINT_ALL, "Forcing glFinish\n" ); } + if ( r_displayRefresh ->integer ) { + ri.Printf( PRINT_ALL, "Display refresh set to %d\n", r_displayRefresh->integer ); + } + if (tr.world) + { + ri.Printf( PRINT_ALL, "Light Grid size set to (%.2f %.2f %.2f)\n", tr.world->lightGridSize[0], tr.world->lightGridSize[1], tr.world->lightGridSize[2] ); + } } +#endif // !DEDICATED /* =============== R_Register @@ -800,15 +810,9 @@ void R_Register( void ) // latched and archived variables // r_allowExtensions = ri.Cvar_Get( "r_allowExtensions", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_tf_solid_compressed = ri.Cvar_Get( "r_tf_solid_compressed", "GL_COMPRESSED_RGBA_DXT5", CVAR_ARCHIVE | CVAR_LATCH ); - r_tf_alpha_compressed = ri.Cvar_Get( "r_tf_alpha_compressed", "GL_COMPRESSED_RGBA_DXT5", CVAR_ARCHIVE | CVAR_LATCH ); - r_tf_solid_uncompressed = ri.Cvar_Get( "r_tf_solid_uncompressed", "GL_RGB8", CVAR_ARCHIVE | CVAR_LATCH ); - r_tf_alpha_uncompressed = ri.Cvar_Get( "r_tf_alpha_uncompressed", "GL_RGBA8", CVAR_ARCHIVE | CVAR_LATCH ); - r_tf_lightmap = ri.Cvar_Get( "r_tf_lightmap", "GL_RGB8", CVAR_ARCHIVE | CVAR_LATCH ); - r_tf_cinematic = ri.Cvar_Get( "r_tf_cinematic", "GL_RGB8", CVAR_ARCHIVE | CVAR_LATCH ); - r_force_compressed_textures = ri.Cvar_Get( "r_force_compressed_textures", "1", CVAR_ARCHIVE | CVAR_LATCH ); - - r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compressed_textures", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_ext_compressed_textures = ri.Cvar_Get( "r_ext_compress_textures", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_ext_compressed_lightmaps = ri.Cvar_Get( "r_ext_compress_lightmaps", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_ext_preferred_tc_method = ri.Cvar_Get( "r_ext_preferred_tc_method", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_ext_gamma_control = ri.Cvar_Get( "r_ext_gamma_control", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_ext_multitexture = ri.Cvar_Get( "r_ext_multitexture", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_ext_compiled_vertex_array = ri.Cvar_Get( "r_ext_compiled_vertex_array", "1", CVAR_ARCHIVE | CVAR_LATCH); @@ -821,7 +825,6 @@ void R_Register( void ) r_picmip = ri.Cvar_Get ("r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH ); - r_roundImagesDown = ri.Cvar_Get ("r_roundImagesDown", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_colorMipLevels = ri.Cvar_Get ("r_colorMipLevels", "0", CVAR_LATCH ); AssertCvarRange( r_picmip, 0, 16, qtrue ); r_detailTextures = ri.Cvar_Get( "r_detailtextures", "1", CVAR_ARCHIVE | CVAR_LATCH ); @@ -861,7 +864,6 @@ void R_Register( void ) r_displayRefresh = ri.Cvar_Get( "r_displayRefresh", "0", CVAR_LATCH ); AssertCvarRange( r_displayRefresh, 0, 200, qtrue ); r_fullbright = ri.Cvar_Get ("r_fullbright", "0", CVAR_CHEAT ); - r_mapOverBrightBits = ri.Cvar_Get ("r_mapOverBrightBits", "1", CVAR_LATCH ); r_intensity = ri.Cvar_Get ("r_intensity", "1", CVAR_LATCH ); r_singleShader = ri.Cvar_Get ("r_singleShader", "0", CVAR_CHEAT | CVAR_LATCH ); @@ -870,6 +872,8 @@ void R_Register( void ) // r_lodCurveError = ri.Cvar_Get( "r_lodCurveError", "250", CVAR_ARCHIVE ); r_lodbias = ri.Cvar_Get( "r_lodbias", "0", CVAR_ARCHIVE ); + r_autolodscalevalue = ri.Cvar_Get( "r_autolodscalevalue", "0", CVAR_ROM ); + r_flares = ri.Cvar_Get ("r_flares", "0", CVAR_ARCHIVE ); r_znear = ri.Cvar_Get( "r_znear", "4", CVAR_CHEAT ); AssertCvarRange( r_znear, 0.001f, 200, qtrue ); @@ -903,8 +907,8 @@ void R_Register( void ) r_debugSort = ri.Cvar_Get( "r_debugSort", "0", CVAR_CHEAT ); r_printShaders = ri.Cvar_Get( "r_printShaders", "0", 0 ); - r_surfaceSprites = ri.Cvar_Get ("r_surfaceSprites", "1", CVAR_CHEAT); - r_surfaceWeather = ri.Cvar_Get ("r_surfaceWeather", "0", 0); + r_surfaceSprites = ri.Cvar_Get ("r_surfaceSprites", "1", CVAR_TEMP); + r_surfaceWeather = ri.Cvar_Get ("r_surfaceWeather", "0", CVAR_TEMP); r_windSpeed = ri.Cvar_Get ("r_windSpeed", "0", 0); r_windAngle = ri.Cvar_Get ("r_windAngle", "0", 0); @@ -916,7 +920,7 @@ void R_Register( void ) r_nocurves = ri.Cvar_Get ("r_nocurves", "0", CVAR_CHEAT ); r_drawworld = ri.Cvar_Get ("r_drawworld", "1", CVAR_CHEAT ); - r_lightmap = ri.Cvar_Get ("r_lightmap", "0", 0 ); + r_lightmap = ri.Cvar_Get ("r_lightmap", "0", CVAR_CHEAT ); r_portalOnly = ri.Cvar_Get ("r_portalOnly", "0", CVAR_CHEAT ); r_flareSize = ri.Cvar_Get ("r_flareSize", "40", CVAR_CHEAT); @@ -926,7 +930,7 @@ void R_Register( void ) r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT); r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT ); - r_lodscale = ri.Cvar_Get( "r_lodscale", "5", CVAR_CHEAT ); + r_lodscale = ri.Cvar_Get( "r_lodscale", "5", 0 ); r_norefresh = ri.Cvar_Get ("r_norefresh", "0", CVAR_CHEAT); r_drawentities = ri.Cvar_Get ("r_drawentities", "1", CVAR_CHEAT ); r_ignore = ri.Cvar_Get( "r_ignore", "1", CVAR_CHEAT ); @@ -955,25 +959,34 @@ void R_Register( void ) Ghoul2 Insert Start */ r_noServerGhoul2 = ri.Cvar_Get( "r_noserverghoul2", "0", CVAR_CHEAT); - r_noGhoul2 = ri.Cvar_Get( "r_noghoul2", "0", CVAR_CHEAT); + + r_Ghoul2AnimSmooth = ri.Cvar_Get( "r_ghoul2animsmooth", ".3", 0 ); + r_Ghoul2UnSqashAfterSmooth = ri.Cvar_Get( "r_ghoul2unsqashaftersmooth", "1", 0 ); /* Ghoul2 Insert End */ +extern qboolean Sys_LowPhysicalMemory(); r_modelpoolmegs = Cvar_Get("r_modelpoolmegs", "10", CVAR_ARCHIVE); + if (Sys_LowPhysicalMemory() ) + { + Cvar_Set("r_modelpoolmegs", "0"); + } // make sure all the commands added here are also // removed in R_Shutdown +#ifndef DEDICATED ri.Cmd_AddCommand( "imagelist", R_ImageList_f ); ri.Cmd_AddCommand( "shaderlist", R_ShaderList_f ); ri.Cmd_AddCommand( "skinlist", R_SkinList_f ); - ri.Cmd_AddCommand( "modellist", R_Modellist_f ); - ri.Cmd_AddCommand( "modelist", R_ModeList_f ); ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f ); ri.Cmd_AddCommand( "screenshot_tga", R_ScreenShotTGA_f ); ri.Cmd_AddCommand( "gfxinfo", GfxInfo_f ); ri.Cmd_AddCommand("r_we", R_WorldEffect_f); - ri.Cmd_AddCommand( "modelcacheinfo", RE_RegisterModels_Info_f); ri.Cmd_AddCommand( "imagecacheinfo", RE_RegisterImages_Info_f); +#endif + ri.Cmd_AddCommand( "modellist", R_Modellist_f ); + ri.Cmd_AddCommand( "modelist", R_ModeList_f ); + ri.Cmd_AddCommand( "modelcacheinfo", RE_RegisterModels_Info_f); } @@ -992,18 +1005,20 @@ void R_Init( void ) { // clear all our internal state Com_Memset( &tr, 0, sizeof( tr ) ); Com_Memset( &backEnd, 0, sizeof( backEnd ) ); +#ifndef DEDICATED Com_Memset( &tess, 0, sizeof( tess ) ); +#endif // Swap_Init(); +#ifndef DEDICATED #ifndef FINAL_BUILD if ( (int)tess.xyz & 15 ) { Com_Printf( "WARNING: tess.xyz not 16 byte aligned (%x)\n",(int)tess.xyz & 15 ); } #endif - Com_Memset( tess.constantColor255, 255, sizeof( tess.constantColor255 ) ); - +#endif // // init function tables // @@ -1030,11 +1045,11 @@ void R_Init( void ) { tr.triangleTable[i] = -tr.triangleTable[i-FUNCTABLE_SIZE/2]; } } - +#ifndef DEDICATED R_InitFogTable(); R_NoiseInit(); - +#endif R_Register(); max_polys = r_maxpolys->integer; @@ -1057,25 +1072,26 @@ void R_Init( void ) { } else { backEndData[1] = NULL; } +#ifndef DEDICATED R_ToggleSmpFrame(); for(i = 0; i < MAX_LIGHT_STYLES; i++) { RE_SetLightStyle(i, -1); } - InitOpenGL(); R_InitImages(); R_InitShaders(); R_InitSkins(); - R_ModelInit(); R_InitFonts(); - +#endif + R_ModelInit(); +#ifndef DEDICATED err = qglGetError(); if ( err != GL_NO_ERROR ) ri.Printf (PRINT_ALL, "glGetError() = 0x%x\n", err); - +#endif ri.Printf( PRINT_ALL, "----- finished R_Init -----\n" ); } @@ -1100,9 +1116,8 @@ void RE_Shutdown( qboolean destroyWindow ) { ri.Cmd_RemoveCommand ("r_we"); ri.Cmd_RemoveCommand ("modelcacheinfo"); ri.Cmd_RemoveCommand ("imagecacheinfo"); - +#ifndef DEDICATED R_ShutdownFonts(); - if ( tr.registered ) { R_SyncRenderThread(); R_ShutdownCommandBuffers(); @@ -1116,10 +1131,12 @@ void RE_Shutdown( qboolean destroyWindow ) { if ( destroyWindow ) { GLimp_Shutdown(); } +#endif //!DEDICATED tr.registered = qfalse; } +#ifndef DEDICATED /* ============= @@ -1160,6 +1177,7 @@ void RE_SetLightStyle(int style, int color) } } +#endif //!DEDICATED /* @@@@@@@@@@@@@@@@@@@@@ GetRefAPI @@ -1182,7 +1200,7 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { // the RE_ functions are Renderer Entry points re.Shutdown = RE_Shutdown; - +#ifndef DEDICATED re.BeginRegistration = RE_BeginRegistration; re.RegisterModel = RE_RegisterModel; re.RegisterSkin = RE_RegisterSkin; @@ -1231,7 +1249,7 @@ refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { re.SetLightStyle = RE_SetLightStyle; re.GetBModelVerts = RE_GetBModelVerts; - +#endif //!DEDICATED return &re; } diff --git a/CODE-mp/renderer/tr_light.cpp b/CODE-mp/renderer/tr_light.cpp index 51fcec8..ad5e729 100644 --- a/CODE-mp/renderer/tr_light.cpp +++ b/CODE-mp/renderer/tr_light.cpp @@ -18,15 +18,15 @@ Used by both the front end (for DlightBmodel) and the back end (before doing the lighting calculation) =============== */ -void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or) { +void R_TransformDlights( int count, dlight_t *dl, orientationr_t *ori) { int i; vec3_t temp; for ( i = 0 ; i < count ; i++, dl++ ) { - VectorSubtract( dl->origin, or->origin, temp ); - dl->transformed[0] = DotProduct( temp, or->axis[0] ); - dl->transformed[1] = DotProduct( temp, or->axis[1] ); - dl->transformed[2] = DotProduct( temp, or->axis[2] ); + VectorSubtract( dl->origin, ori->origin, temp ); + dl->transformed[0] = DotProduct( temp, ori->axis[0] ); + dl->transformed[1] = DotProduct( temp, ori->axis[1] ); + dl->transformed[2] = DotProduct( temp, ori->axis[2] ); } } diff --git a/CODE-mp/renderer/tr_local.h b/CODE-mp/renderer/tr_local.h index ce6671f..bb2665b 100644 --- a/CODE-mp/renderer/tr_local.h +++ b/CODE-mp/renderer/tr_local.h @@ -3,6 +3,10 @@ #ifndef TR_LOCAL_H #define TR_LOCAL_H +#ifdef __linux__ +typedef const char * LPCSTR; +#endif + #include "../game/q_shared.h" #include "../qcommon/qfiles.h" #include "../qcommon/qcommon.h" @@ -33,11 +37,6 @@ long myftol( float f ); // can't be increased without changing bit packing for drawsurfs -// Default texture format constants -#define GL_SOLID_FORMAT 3 -#define GL_ALPHA_FORMAT 4 - - typedef struct dlight_s { vec3_t origin; vec3_t color; // range from 0.0 to 1.0, should be color normalized @@ -557,7 +556,7 @@ typedef struct { } fog_t; typedef struct { - orientationr_t or; + orientationr_t ori; // Can't use "or" as it is a reserved word with gcc DREWS 2/2/2002 orientationr_t world; vec3_t pvsOrigin; // may be different than or.origin for portals qboolean isPortal; // true if this view is through a portal @@ -958,7 +957,7 @@ typedef struct { int smpFrame; trRefdef_t refdef; viewParms_t viewParms; - orientationr_t or; + orientationr_t ori; // Can't use or as it is a c++ reserved word DREWS 2/2/2002 backEndCounters_t pc; qboolean isHyperspace; trRefEntity_t *currentEntity; @@ -1106,6 +1105,7 @@ extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measuremen extern cvar_t *r_lodbias; // push/pull LOD transitions extern cvar_t *r_lodscale; +extern cvar_t *r_autolodscalevalue; extern cvar_t *r_primitives; // "0" = based on compiled vertex array existance // "1" = glDrawElemet tristrips @@ -1147,15 +1147,9 @@ extern cvar_t *r_displayRefresh; // optional display refresh option extern cvar_t *r_ignorehwgamma; // overrides hardware gamma capabilities extern cvar_t *r_allowExtensions; // global enable/disable of OpenGL extensions -extern cvar_t *r_tf_solid_compressed; -extern cvar_t *r_tf_alpha_compressed; -extern cvar_t *r_tf_solid_uncompressed; -extern cvar_t *r_tf_alpha_uncompressed; -extern cvar_t *r_tf_lightmap; -extern cvar_t *r_tf_cinematic; -extern cvar_t *r_force_compressed_textures; // these control use of specific extensions - extern cvar_t *r_ext_compressed_textures; // these control use of specific extensions +extern cvar_t *r_ext_compressed_lightmaps; // turns on compression of lightmaps, off by default +extern cvar_t *r_ext_preferred_tc_method; extern cvar_t *r_ext_gamma_control; extern cvar_t *r_ext_texenv_op; extern cvar_t *r_ext_multitexture; @@ -1165,7 +1159,6 @@ extern cvar_t *r_ext_texture_filter_anisotropic; extern cvar_t *r_nobind; // turns off binding to appropriate textures extern cvar_t *r_singleShader; // make most world faces use default shader -extern cvar_t *r_roundImagesDown; extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage extern cvar_t *r_picmip; // controls picmip values extern cvar_t *r_finish; @@ -1204,7 +1197,6 @@ extern cvar_t *r_skipBackEnd; extern cvar_t *r_ignoreGLErrors; extern cvar_t *r_overBrightBits; -extern cvar_t *r_mapOverBrightBits; extern cvar_t *r_debugSurface; extern cvar_t *r_simpleMipMaps; @@ -1217,7 +1209,6 @@ extern cvar_t *r_printShaders; Ghoul2 Insert Start */ extern cvar_t *r_noServerGhoul2; -extern cvar_t *r_noGhoul2; /* Ghoul2 Insert End */ @@ -1254,7 +1245,7 @@ int R_CullLocalBox (vec3_t bounds[2]); int R_CullPointAndRadius( vec3_t origin, float radius ); int R_CullLocalPointAndRadius( vec3_t origin, float radius ); -void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *or ); +void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, orientationr_t *ori ); /* ** GL wrapper/helper functions @@ -1454,10 +1445,10 @@ struct shaderCommands_s qboolean SSInitializedWind; }; - +#ifndef DEDICATED typedef __declspec(align(16)) shaderCommands_s shaderCommands_t; - extern shaderCommands_t tess; +#endif extern color4ub_t styleColors[MAX_LIGHT_STYLES]; void RB_BeginSurface(shader_t *shader, int fogNum ); @@ -1513,7 +1504,7 @@ LIGHTS void R_DlightBmodel( bmodel_t *bmodel ); void R_SetupEntityLighting( const trRefdef_t *refdef, trRefEntity_t *ent ); -void R_TransformDlights( int count, dlight_t *dl, orientationr_t *or ); +void R_TransformDlights( int count, dlight_t *dl, orientationr_t *ori ); int R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); @@ -1536,13 +1527,13 @@ SKIES ============================================================ */ - +#ifndef DEDICATED void R_BuildCloudData( shaderCommands_t *shader ); void R_InitSkyTexCoords( float cloudLayerHeight ); void R_DrawSkyBox( shaderCommands_t *shader ); void RB_DrawSun( void ); void RB_ClipSkyPolygons( shaderCommands_t *shader ); - +#endif /* ============================================================ @@ -1818,8 +1809,8 @@ void RE_InsertModelIntoHash(const char *name, model_t *mod); /* Ghoul2 Insert End */ - +#ifndef DEDICATED // tr_surfacesprites void RB_DrawSurfaceSprites( shaderStage_t *stage, shaderCommands_t *input); - +#endif #endif //TR_LOCAL_H diff --git a/CODE-mp/renderer/tr_main.cpp b/CODE-mp/renderer/tr_main.cpp index ad6bde9..1eaf12b 100644 --- a/CODE-mp/renderer/tr_main.cpp +++ b/CODE-mp/renderer/tr_main.cpp @@ -1,7 +1,7 @@ // tr_main.c -- main control flow for each frame #include "tr_local.h" -#include "../ghoul2/g2_local.h" +#include "../ghoul2/G2_local.h" trGlobals_t tr; @@ -17,6 +17,8 @@ static float s_flipMatrix[16] = { refimport_t ri; +#ifndef DEDICATED + // entities that will have procedurally generated surfaces will just // point at this for their sorting surface surfaceType_t entitySurface = SF_ENTITY; @@ -84,6 +86,8 @@ int R_CullLocalBox (vec3_t bounds[2]) { return CULL_CLIP; // partially clipped } +#endif // !DEDICATED + /* ** R_CullLocalPointAndRadius */ @@ -147,6 +151,7 @@ int R_CullPointAndRadius( vec3_t pt, float radius ) return CULL_IN; // completely inside frustum } +#ifndef DEDICATED /* ================= @@ -160,6 +165,7 @@ void R_LocalNormalToWorld (vec3_t local, vec3_t world) { world[2] = local[0] * tr.ori.axis[0][2] + local[1] * tr.ori.axis[1][2] + local[2] * tr.ori.axis[2][2]; } +#endif // !DEDICATED /* ================= R_LocalPointToWorld @@ -172,6 +178,8 @@ void R_LocalPointToWorld (vec3_t local, vec3_t world) { world[2] = local[0] * tr.ori.axis[0][2] + local[1] * tr.ori.axis[1][2] + local[2] * tr.ori.axis[2][2] + tr.ori.origin[2]; } +#ifndef DEDICATED + float preTransEntMatrix[16]; /* @@ -290,47 +298,47 @@ Called by both the front end and the back end ================= */ void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, - orientationr_t *or ) { + orientationr_t *ori ) { // float glMatrix[16]; vec3_t delta; float axisLength; if ( ent->e.reType != RT_MODEL ) { - *or = viewParms->world; + *ori = viewParms->world; return; } - VectorCopy( ent->e.origin, or->origin ); + VectorCopy( ent->e.origin, ori->origin ); - VectorCopy( ent->e.axis[0], or->axis[0] ); - VectorCopy( ent->e.axis[1], or->axis[1] ); - VectorCopy( ent->e.axis[2], or->axis[2] ); + VectorCopy( ent->e.axis[0], ori->axis[0] ); + VectorCopy( ent->e.axis[1], ori->axis[1] ); + VectorCopy( ent->e.axis[2], ori->axis[2] ); - preTransEntMatrix[0] = or->axis[0][0]; - preTransEntMatrix[4] = or->axis[1][0]; - preTransEntMatrix[8] = or->axis[2][0]; - preTransEntMatrix[12] = or->origin[0]; + preTransEntMatrix[0] = ori->axis[0][0]; + preTransEntMatrix[4] = ori->axis[1][0]; + preTransEntMatrix[8] = ori->axis[2][0]; + preTransEntMatrix[12] = ori->origin[0]; - preTransEntMatrix[1] = or->axis[0][1]; - preTransEntMatrix[5] = or->axis[1][1]; - preTransEntMatrix[9] = or->axis[2][1]; - preTransEntMatrix[13] = or->origin[1]; + preTransEntMatrix[1] = ori->axis[0][1]; + preTransEntMatrix[5] = ori->axis[1][1]; + preTransEntMatrix[9] = ori->axis[2][1]; + preTransEntMatrix[13] = ori->origin[1]; - preTransEntMatrix[2] = or->axis[0][2]; - preTransEntMatrix[6] = or->axis[1][2]; - preTransEntMatrix[10] = or->axis[2][2]; - preTransEntMatrix[14] = or->origin[2]; + preTransEntMatrix[2] = ori->axis[0][2]; + preTransEntMatrix[6] = ori->axis[1][2]; + preTransEntMatrix[10] = ori->axis[2][2]; + preTransEntMatrix[14] = ori->origin[2]; preTransEntMatrix[3] = 0; preTransEntMatrix[7] = 0; preTransEntMatrix[11] = 0; preTransEntMatrix[15] = 1; - myGlMultMatrix( preTransEntMatrix, viewParms->world.modelMatrix, or->modelMatrix ); + myGlMultMatrix( preTransEntMatrix, viewParms->world.modelMatrix, ori->modelMatrix ); // calculate the viewer origin in the model's space // needed for fog, specular, and environment mapping - VectorSubtract( viewParms->or.origin, or->origin, delta ); + VectorSubtract( viewParms->ori.origin, ori->origin, delta ); // compensate for scale in the axes if necessary if ( ent->e.nonNormalizedAxes ) { @@ -344,9 +352,9 @@ void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms, axisLength = 1.0f; } - or->viewOrigin[0] = DotProduct( delta, or->axis[0] ) * axisLength; - or->viewOrigin[1] = DotProduct( delta, or->axis[1] ) * axisLength; - or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength; + ori->viewOrigin[0] = DotProduct( delta, ori->axis[0] ) * axisLength; + ori->viewOrigin[1] = DotProduct( delta, ori->axis[1] ) * axisLength; + ori->viewOrigin[2] = DotProduct( delta, ori->axis[2] ) * axisLength; } /* @@ -365,24 +373,24 @@ void R_RotateForViewer (void) tr.ori.axis[0][0] = 1; tr.ori.axis[1][1] = 1; tr.ori.axis[2][2] = 1; - VectorCopy (tr.viewParms.or.origin, tr.ori.viewOrigin); + VectorCopy (tr.viewParms.ori.origin, tr.ori.viewOrigin); // transform by the camera placement - VectorCopy( tr.viewParms.or.origin, origin ); + VectorCopy( tr.viewParms.ori.origin, origin ); - viewerMatrix[0] = tr.viewParms.or.axis[0][0]; - viewerMatrix[4] = tr.viewParms.or.axis[0][1]; - viewerMatrix[8] = tr.viewParms.or.axis[0][2]; + viewerMatrix[0] = tr.viewParms.ori.axis[0][0]; + viewerMatrix[4] = tr.viewParms.ori.axis[0][1]; + viewerMatrix[8] = tr.viewParms.ori.axis[0][2]; viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8]; - viewerMatrix[1] = tr.viewParms.or.axis[1][0]; - viewerMatrix[5] = tr.viewParms.or.axis[1][1]; - viewerMatrix[9] = tr.viewParms.or.axis[1][2]; + viewerMatrix[1] = tr.viewParms.ori.axis[1][0]; + viewerMatrix[5] = tr.viewParms.ori.axis[1][1]; + viewerMatrix[9] = tr.viewParms.ori.axis[1][2]; viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9]; - viewerMatrix[2] = tr.viewParms.or.axis[2][0]; - viewerMatrix[6] = tr.viewParms.or.axis[2][1]; - viewerMatrix[10] = tr.viewParms.or.axis[2][2]; + viewerMatrix[2] = tr.viewParms.ori.axis[2][0]; + viewerMatrix[6] = tr.viewParms.ori.axis[2][1]; + viewerMatrix[10] = tr.viewParms.ori.axis[2][2]; viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10]; viewerMatrix[3] = 0; @@ -450,7 +458,7 @@ static void SetFarClip( void ) v[2] = tr.viewParms.visBounds[1][2]; } - VectorSubtract( v, tr.viewParms.or.origin, vecTo ); + VectorSubtract( v, tr.viewParms.ori.origin, vecTo ); distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2]; @@ -529,25 +537,25 @@ void R_SetupFrustum (void) { xs = sin( ang ); xc = cos( ang ); - VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[0].normal ); - VectorMA( tr.viewParms.frustum[0].normal, xc, tr.viewParms.or.axis[1], tr.viewParms.frustum[0].normal ); + VectorScale( tr.viewParms.ori.axis[0], xs, tr.viewParms.frustum[0].normal ); + VectorMA( tr.viewParms.frustum[0].normal, xc, tr.viewParms.ori.axis[1], tr.viewParms.frustum[0].normal ); - VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[1].normal ); - VectorMA( tr.viewParms.frustum[1].normal, -xc, tr.viewParms.or.axis[1], tr.viewParms.frustum[1].normal ); + VectorScale( tr.viewParms.ori.axis[0], xs, tr.viewParms.frustum[1].normal ); + VectorMA( tr.viewParms.frustum[1].normal, -xc, tr.viewParms.ori.axis[1], tr.viewParms.frustum[1].normal ); ang = tr.viewParms.fovY / 180 * M_PI * 0.5f; xs = sin( ang ); xc = cos( ang ); - VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[2].normal ); - VectorMA( tr.viewParms.frustum[2].normal, xc, tr.viewParms.or.axis[2], tr.viewParms.frustum[2].normal ); + VectorScale( tr.viewParms.ori.axis[0], xs, tr.viewParms.frustum[2].normal ); + VectorMA( tr.viewParms.frustum[2].normal, xc, tr.viewParms.ori.axis[2], tr.viewParms.frustum[2].normal ); - VectorScale( tr.viewParms.or.axis[0], xs, tr.viewParms.frustum[3].normal ); - VectorMA( tr.viewParms.frustum[3].normal, -xc, tr.viewParms.or.axis[2], tr.viewParms.frustum[3].normal ); + VectorScale( tr.viewParms.ori.axis[0], xs, tr.viewParms.frustum[3].normal ); + VectorMA( tr.viewParms.frustum[3].normal, -xc, tr.viewParms.ori.axis[2], tr.viewParms.frustum[3].normal ); for (i=0 ; i<4 ; i++) { tr.viewParms.frustum[i].type = PLANE_NON_AXIAL; - tr.viewParms.frustum[i].dist = DotProduct (tr.viewParms.or.origin, tr.viewParms.frustum[i].normal); + tr.viewParms.frustum[i].dist = DotProduct (tr.viewParms.ori.origin, tr.viewParms.frustum[i].normal); SetPlaneSignbits( &tr.viewParms.frustum[i] ); } } @@ -817,7 +825,7 @@ static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum ) } return qfalse; } - +#ifndef DEDICATED /* ** SurfIsOffscreen ** @@ -844,9 +852,7 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128 R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); RB_BeginSurface( shader, fogNum ); rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - assert( tess.numVertexes < 128 ); - for ( i = 0; i < tess.numVertexes; i++ ) { int j; @@ -888,7 +894,7 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128 float dot; float len; - VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal ); + VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.ori.origin, normal ); len = VectorLengthSquared( normal ); // lose the sqrt if ( len < shortest ) @@ -921,6 +927,7 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128 return qfalse; } +#endif // DEDICATED /* ======================== R_MirrorViewBySurface @@ -959,14 +966,14 @@ qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) { return qfalse; // bad portal, no portalentity } - R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin ); + R_MirrorPoint (oldParms.ori.origin, &surface, &camera, newParms.ori.origin ); VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal ); newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal ); - R_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]); - R_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]); - R_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]); + R_MirrorVector (oldParms.ori.axis[0], &surface, &camera, newParms.ori.axis[0]); + R_MirrorVector (oldParms.ori.axis[1], &surface, &camera, newParms.ori.axis[1]); + R_MirrorVector (oldParms.ori.axis[2], &surface, &camera, newParms.ori.axis[2]); // OPTIMIZE: restrict the viewport on the mirrored view @@ -1533,4 +1540,5 @@ void R_RenderView (viewParms_t *parms) { } +#endif // !DEDICATED diff --git a/CODE-mp/renderer/tr_mesh.cpp b/CODE-mp/renderer/tr_mesh.cpp index 48c5737..7c0139b 100644 --- a/CODE-mp/renderer/tr_mesh.cpp +++ b/CODE-mp/renderer/tr_mesh.cpp @@ -10,8 +10,8 @@ float ProjectRadius( float r, vec3_t location ) vec3_t p; float projected[4]; - c = DotProduct( tr.viewParms.or.axis[0], tr.viewParms.or.origin ); - dist = DotProduct( tr.viewParms.or.axis[0], location ) - c; + c = DotProduct( tr.viewParms.ori.axis[0], tr.viewParms.ori.origin ); + dist = DotProduct( tr.viewParms.ori.axis[0], location ) - c; if ( dist <= 0 ) return 0; @@ -49,6 +49,7 @@ float ProjectRadius( float r, vec3_t location ) return pr; } +#ifndef DEDICATED /* ============= R_CullModel @@ -167,8 +168,15 @@ int R_ComputeLOD( trRefEntity_t *ent ) { if ( ( projectedRadius = ProjectRadius( radius, ent->e.origin ) ) != 0 ) { - lodscale = r_lodscale->value; - if (lodscale > 20) lodscale = 20; + lodscale = (r_lodscale->value+r_autolodscalevalue->value); + if ( lodscale > 20 ) + { + lodscale = 20; + } + else if ( lodscale < 0 ) + { + lodscale = 0; + } flod = 1.0f - projectedRadius * lodscale; } else @@ -374,3 +382,5 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) { } +#endif // !DEDICATED + diff --git a/CODE-mp/renderer/tr_model.cpp b/CODE-mp/renderer/tr_model.cpp index 081547b..101e5fa 100644 --- a/CODE-mp/renderer/tr_model.cpp +++ b/CODE-mp/renderer/tr_model.cpp @@ -63,7 +63,7 @@ struct CachedEndianedModelBinary_s }; typedef struct CachedEndianedModelBinary_s CachedEndianedModelBinary_t; typedef map CachedModels_t; - CachedModels_t CachedModels; // the important cache item. +CachedModels_t CachedModels; // the important cache item. void RE_RegisterModels_StoreShaderRequest(const char *psModelFileName, const char *psShaderName, int *piShaderIndexPoke) { @@ -202,6 +202,7 @@ void *RE_RegisterModels_Malloc(int iSize, const char *psModelFileName, qboolean } else { +#ifndef DEDICATED // if we already had this model entry, then re-register all the shaders it wanted... // int iEntries = ModelBin.ShaderRegisterData.size(); @@ -222,6 +223,7 @@ void *RE_RegisterModels_Malloc(int iSize, const char *psModelFileName, qboolean *piShaderPokePtr = sh->index; } } +#endif //!DEDICATED *pqbAlreadyFound = qtrue; // tell caller not to re-Endian or re-Shader this binary } @@ -306,8 +308,6 @@ static int GetModelDataAllocSize(void) Z_MemSize( TAG_MODEL_GLA); } extern cvar_t *r_modelpoolmegs; -extern qboolean Sys_LowPhysicalMemory(); - // // return qtrue if at least one cached model was freed (which tells z_malloc()-fail recoveryt code to try again) // @@ -325,7 +325,7 @@ qboolean RE_RegisterModels_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLev else { int iLoadedModelBytes = GetModelDataAllocSize(); - const int iMaxModelBytes= (!Sys_LowPhysicalMemory() && r_modelpoolmegs) ? (r_modelpoolmegs->integer * 1024 * 1024) : 0; + const int iMaxModelBytes= r_modelpoolmegs->integer * 1024 * 1024; qboolean bEraseOccured = qfalse; for (CachedModels_t::iterator itModel = CachedModels.begin(); itModel != CachedModels.end() && ( bDeleteEverythingNotUsedThisLevel || iLoadedModelBytes > iMaxModelBytes ); bEraseOccured?itModel:++itModel) @@ -361,9 +361,18 @@ qboolean RE_RegisterModels_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLev //CachedModel.pModelDiskImage = NULL; // REM for reference, erase() call below negates the need for it. bAtLeastoneModelFreed = qtrue; } - +#ifndef __linux__ itModel = CachedModels.erase(itModel); bEraseOccured = qtrue; +#else + // Both MS and Dinkumware got the map::erase wrong + // The STL has the return type as a void + CachedModels_t::iterator itTemp; + itTemp = itModel; + itModel++; + CachedModels.erase(itTemp); + +#endif iLoadedModelBytes = GetModelDataAllocSize(); } @@ -409,9 +418,18 @@ static void RE_RegisterModels_DumpNonPure(void) Z_Free(CachedModel.pModelDiskImage); //CachedModel.pModelDiskImage = NULL; // REM for reference, erase() call below negates the need for it. } - +#ifndef __linux__ itModel = CachedModels.erase(itModel); bEraseOccured = qtrue; +#else + // Both MS and Dinkumware got the map::erase wrong + // The STL has the return type as a void + CachedModels_t::iterator itTemp; + itTemp = itModel; + itModel++; + CachedModels.erase(itTemp); + +#endif } } } @@ -444,6 +462,7 @@ void RE_RegisterModels_Info_f( void ) // static void RE_RegisterModels_DeleteAll(void) { +#ifndef __linux__ for (CachedModels_t::iterator itModel = CachedModels.begin(); itModel != CachedModels.end(); ) { CachedEndianedModelBinary_t &CachedModel = (*itModel).second; @@ -454,6 +473,9 @@ static void RE_RegisterModels_DeleteAll(void) itModel = CachedModels.erase(itModel); } +#else + CachedModels.erase(CachedModels.begin(),CachedModels.end()); +#endif } @@ -478,7 +500,7 @@ void RE_RegisterMedia_LevelLoadBegin(const char *psMapName, ForceReload_e eForce RE_RegisterModels_DumpNonPure(); } } - +#ifndef DEDICATED // not used in MP codebase... // // if (bDeleteBSP) @@ -486,7 +508,7 @@ void RE_RegisterMedia_LevelLoadBegin(const char *psMapName, ForceReload_e eForce // CM_DeleteCachedMap(); R_Images_DeleteLightMaps(); // always do this now, makes no real load time difference, and lets designers work ok // } - +#endif // at some stage I'll probably want to put some special logic here, like not incrementing the level number // when going into a map like "brig" or something, so returning to the previous level doesn't require an @@ -515,10 +537,12 @@ extern void S_RestartMusic(void); void RE_RegisterMedia_LevelLoadEnd(void) { RE_RegisterModels_LevelLoadEnd(qfalse); +#ifndef DEDICATED RE_RegisterImages_LevelLoadEnd(); SND_RegisterAudio_LevelLoadEnd(qfalse); // RE_InitDissolve(); S_RestartMusic(); +#endif } @@ -971,10 +995,9 @@ Ghoul2 Insert Start Ghoul2 Insert End */ - if (!r_noServerGhoul2 || !r_noGhoul2) + if (!r_noServerGhoul2) { //keep it from choking when it gets to these checks in the g2 code. Registering all r_ cvars for the server would be a Bad Thing though. r_noServerGhoul2 = Cvar_Get( "r_noserverghoul2", "0", 0); - r_noGhoul2 = Cvar_Get( "r_noghoul2", "0", 0); } if ( !name || !name[0] ) { @@ -1003,10 +1026,10 @@ Ghoul2 Insert End // only set the name after the model has been successfully loaded Q_strncpyz( mod->name, name, sizeof( mod->name ) ); - +#ifndef DEDICATED // make sure the render thread is stopped R_SyncRenderThread(); - +#endif int iLODStart = 0; if (strstr (name, ".md3")) { @@ -1192,10 +1215,10 @@ Ghoul2 Insert End // only set the name after the model has been successfully loaded Q_strncpyz( mod->name, name, sizeof( mod->name ) ); - +#ifndef DEDICATED // make sure the render thread is stopped R_SyncRenderThread(); - +#endif int iLODStart = 0; if (strstr (name, ".md3")) { @@ -1482,7 +1505,7 @@ static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_ if ( j > 2 && surf->name[j-2] == '_' ) { surf->name[j-2] = 0; } - +#ifndef DEDICATED // register the shaders shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders ); for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) { @@ -1496,7 +1519,7 @@ static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_ } RE_RegisterModels_StoreShaderRequest(mod_name, &shader->name[0], &shader->shaderIndex); } - +#endif #ifndef _M_IX86 // @@ -1665,7 +1688,7 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name, qbo // change to surface identifier surf->ident = SF_MD4; - +#ifndef DEDICATED // register the shaders sh = R_FindShader( surf->shader, lightmapsNone, stylesDefault, qtrue ); if ( sh->defaultShader ) { @@ -1674,6 +1697,7 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name, qbo surf->shaderIndex = sh->index; } RE_RegisterModels_StoreShaderRequest(mod_name, &surf->shader[0], &surf->shaderIndex); +#endif #ifndef _M_IX86 // @@ -1724,7 +1748,7 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name, qbo //============================================================================= - +#ifndef DEDICATED /* ** RE_BeginRegistration */ @@ -1753,6 +1777,7 @@ void RE_BeginRegistration( glconfig_t *glconfigOut ) { //============================================================================= +#endif // !DEDICATED void R_SVModelInit() { model_t *mod; diff --git a/CODE-mp/renderer/tr_scene.cpp b/CODE-mp/renderer/tr_scene.cpp index 87dea18..9b910df 100644 --- a/CODE-mp/renderer/tr_scene.cpp +++ b/CODE-mp/renderer/tr_scene.cpp @@ -5,7 +5,7 @@ #include "../ghoul2/G2.h" #endif #include "../ghoul2/G2_local.h" -#include "matcomp.h" +#include "MatComp.h" #pragma warning (disable: 4512) //default assignment operator could not be gened #include "../qcommon/disablewarnings.h" @@ -206,10 +206,12 @@ void RE_AddRefEntityToScene( const refEntity_t *ent ) { { CGhoul2Info_v &ghoul2 = *((CGhoul2Info_v *)ent->ghoul2); +#ifndef __linux__ if (!ghoul2[0].mModel) { DebugBreak(); } +#endif } if (ent->reType == RT_ENT_CHAIN) @@ -456,10 +458,10 @@ void RE_RenderScene( const refdef_t *fd ) { parms.fovX = tr.refdef.fov_x; parms.fovY = tr.refdef.fov_y; - VectorCopy( fd->vieworg, parms.or.origin ); - VectorCopy( fd->viewaxis[0], parms.or.axis[0] ); - VectorCopy( fd->viewaxis[1], parms.or.axis[1] ); - VectorCopy( fd->viewaxis[2], parms.or.axis[2] ); + VectorCopy( fd->vieworg, parms.ori.origin ); + VectorCopy( fd->viewaxis[0], parms.ori.axis[0] ); + VectorCopy( fd->viewaxis[1], parms.ori.axis[1] ); + VectorCopy( fd->viewaxis[2], parms.ori.axis[2] ); VectorCopy( fd->vieworg, parms.pvsOrigin ); diff --git a/CODE-mp/renderer/tr_shade.cpp b/CODE-mp/renderer/tr_shade.cpp index a632cdd..abb70db 100644 --- a/CODE-mp/renderer/tr_shade.cpp +++ b/CODE-mp/renderer/tr_shade.cpp @@ -2,7 +2,7 @@ #include "tr_local.h" -#include "tr_quicksprite.h" +#include "tr_QuickSprite.h" /* @@ -787,7 +787,7 @@ static void ComputeColors( shaderStage_t *pStage, int forceRGBGen ) float len; vec3_t v; - VectorSubtract( tess.xyz[i], backEnd.viewParms.or.origin, v ); + VectorSubtract( tess.xyz[i], backEnd.viewParms.ori.origin, v ); len = VectorLength( v ); len /= tess.shader->portalRange; @@ -1005,7 +1005,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) if ( backEnd.currentEntity->e.renderfx & RF_DISINTEGRATE1 ) { // we want to be able to rip a hole in the thing being disintegrated, and by doing the depth-testing it avoids some kinds of artefacts, but will probably introduce others? - stateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK_TRUE | GLS_DEPTHTEST_DISABLE; + stateBits = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHMASK_TRUE | GLS_ATEST_GE_C0; } if ( backEnd.currentEntity->e.renderfx & RF_RGB_TINT ) diff --git a/CODE-mp/renderer/tr_shade_calc.cpp b/CODE-mp/renderer/tr_shade_calc.cpp index 2b1b7d7..bcb40c3 100644 --- a/CODE-mp/renderer/tr_shade_calc.cpp +++ b/CODE-mp/renderer/tr_shade_calc.cpp @@ -363,9 +363,9 @@ GlobalVectorToLocal ================== */ static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) { - out[0] = DotProduct( in, backEnd.or.axis[0] ); - out[1] = DotProduct( in, backEnd.or.axis[1] ); - out[2] = DotProduct( in, backEnd.or.axis[2] ); + out[0] = DotProduct( in, backEnd.ori.axis[0] ); + out[1] = DotProduct( in, backEnd.ori.axis[1] ); + out[2] = DotProduct( in, backEnd.ori.axis[2] ); } /* @@ -397,11 +397,11 @@ static void AutospriteDeform( void ) { tess.numIndexes = 0; if ( backEnd.currentEntity != &tr.worldEntity ) { - GlobalVectorToLocal( backEnd.viewParms.or.axis[1], leftDir ); - GlobalVectorToLocal( backEnd.viewParms.or.axis[2], upDir ); + GlobalVectorToLocal( backEnd.viewParms.ori.axis[1], leftDir ); + GlobalVectorToLocal( backEnd.viewParms.ori.axis[2], upDir ); } else { - VectorCopy( backEnd.viewParms.or.axis[1], leftDir ); - VectorCopy( backEnd.viewParms.or.axis[2], upDir ); + VectorCopy( backEnd.viewParms.ori.axis[1], leftDir ); + VectorCopy( backEnd.viewParms.ori.axis[2], upDir ); } for ( i = 0 ; i < oldVerts ; i+=4 ) { @@ -470,9 +470,9 @@ static void Autosprite2Deform( void ) { } if ( backEnd.currentEntity != &tr.worldEntity ) { - GlobalVectorToLocal( backEnd.viewParms.or.axis[0], forward ); + GlobalVectorToLocal( backEnd.viewParms.ori.axis[0], forward ); } else { - VectorCopy( backEnd.viewParms.or.axis[0], forward ); + VectorCopy( backEnd.viewParms.ori.axis[0], forward ); } // this is a lot of work for two triangles... @@ -845,11 +845,11 @@ void RB_CalcFogTexCoords( float *st ) { fog = tr.world->fogs + tess.fogNum; // all fogging distance is based on world Z units - VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local ); - fogDistanceVector[0] = -backEnd.or.modelMatrix[2]; - fogDistanceVector[1] = -backEnd.or.modelMatrix[6]; - fogDistanceVector[2] = -backEnd.or.modelMatrix[10]; - fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] ); + VectorSubtract( backEnd.ori.origin, backEnd.viewParms.ori.origin, local ); + fogDistanceVector[0] = -backEnd.ori.modelMatrix[2]; + fogDistanceVector[1] = -backEnd.ori.modelMatrix[6]; + fogDistanceVector[2] = -backEnd.ori.modelMatrix[10]; + fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.ori.axis[0] ); // scale the fog vectors based on the fog's thickness fogDistanceVector[0] *= fog->tcScale; @@ -859,15 +859,15 @@ void RB_CalcFogTexCoords( float *st ) { // rotate the gradient vector for this orientation if ( fog->hasSurface ) { - fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] + - fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2]; - fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] + - fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2]; - fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] + - fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2]; - fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface ); + fogDepthVector[0] = fog->surface[0] * backEnd.ori.axis[0][0] + + fog->surface[1] * backEnd.ori.axis[0][1] + fog->surface[2] * backEnd.ori.axis[0][2]; + fogDepthVector[1] = fog->surface[0] * backEnd.ori.axis[1][0] + + fog->surface[1] * backEnd.ori.axis[1][1] + fog->surface[2] * backEnd.ori.axis[1][2]; + fogDepthVector[2] = fog->surface[0] * backEnd.ori.axis[2][0] + + fog->surface[1] * backEnd.ori.axis[2][1] + fog->surface[2] * backEnd.ori.axis[2][2]; + fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.ori.origin, fog->surface ); - eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3]; + eyeT = DotProduct( backEnd.ori.viewOrigin, fogDepthVector ) + fogDepthVector[3]; } else { eyeT = 1; // non-surface fog always has eye inside } @@ -927,7 +927,7 @@ void RB_CalcEnvironmentTexCoords( float *st ) for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) { - VectorSubtract (backEnd.or.viewOrigin, v, viewer); + VectorSubtract (backEnd.ori.viewOrigin, v, viewer); VectorNormalizeFast (viewer); d = DotProduct (normal, viewer); @@ -1103,7 +1103,7 @@ void RB_CalcSpecularAlpha( unsigned char *alphas ) { reflected[1] = normal[1]*d - lightDir[1]; reflected[2] = normal[2]*d - lightDir[2]; - VectorSubtract (backEnd.or.viewOrigin, v, viewer); + VectorSubtract (backEnd.ori.viewOrigin, v, viewer); ilength = Q_rsqrt( DotProduct( viewer, viewer ) ); l = DotProduct (reflected, viewer); l *= ilength; diff --git a/CODE-mp/renderer/tr_shader.cpp b/CODE-mp/renderer/tr_shader.cpp index a7ae72f..3f5c934 100644 --- a/CODE-mp/renderer/tr_shader.cpp +++ b/CODE-mp/renderer/tr_shader.cpp @@ -1154,12 +1154,17 @@ static qboolean ParseStage( shaderStage_t *stage, const char **text ) } else { +#ifdef DEDICATED + stage->bundle[0].image[0] = NULL; + return qfalse; +#else stage->bundle[0].image[0] = R_FindImageFile( token, (qboolean)!shader.noMipMaps, (qboolean)!shader.noPicMip, (qboolean)!shader.noTC, GL_REPEAT ); if ( !stage->bundle[0].image[0] ) { ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); return qfalse; } +#endif // !DEDICATED } } // @@ -1173,13 +1178,17 @@ static qboolean ParseStage( shaderStage_t *stage, const char **text ) ri.Printf( PRINT_WARNING, "WARNING: missing parameter for 'clampmap' keyword in shader '%s'\n", shader.name ); return qfalse; } - +#ifdef DEDICATED + stage->bundle[0].image[0] = NULL; + return qfalse; +#else stage->bundle[0].image[0] = R_FindImageFile( token, (qboolean)!shader.noMipMaps, (qboolean)!shader.noPicMip, (qboolean)!shader.noTC, GL_CLAMP ); if ( !stage->bundle[0].image[0] ) { ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); return qfalse; } +#endif } // // animMap .... @@ -1208,6 +1217,10 @@ static qboolean ParseStage( shaderStage_t *stage, const char **text ) } num = stage->bundle[0].numImageAnimations; if ( num < MAX_IMAGE_ANIMATIONS ) { +#ifdef DEDICATED + stage->bundle[0].image[num] = NULL; + return qfalse; +#else stage->bundle[0].image[num] = R_FindImageFile( token, (qboolean)!shader.noMipMaps, (qboolean)!shader.noPicMip, (qboolean)!shader.noTC, bClamp?GL_CLAMP:GL_REPEAT ); if ( !stage->bundle[0].image[num] ) { @@ -1215,6 +1228,7 @@ static qboolean ParseStage( shaderStage_t *stage, const char **text ) return qfalse; } stage->bundle[0].numImageAnimations++; +#endif } } } @@ -1806,6 +1820,9 @@ static void ParseSkyParms( const char **text ) { if ( strcmp( token, "-" ) ) { for (i=0 ; i<6 ; i++) { Com_sprintf( pathname, sizeof(pathname), "%s_%s", token, suf[i] ); +#ifdef DEDICATED + shader.sky.outerbox[i] = NULL; +#else shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, (qboolean)!shader.noTC, GL_CLAMP ); if ( !shader.sky.outerbox[i] ) { if (i) { @@ -1814,6 +1831,7 @@ static void ParseSkyParms( const char **text ) { shader.sky.outerbox[i] = tr.defaultImage; } } +#endif } } @@ -1827,8 +1845,9 @@ static void ParseSkyParms( const char **text ) { if ( !shader.sky.cloudHeight ) { shader.sky.cloudHeight = 512; } +#ifndef DEDICATED R_InitSkyTexCoords( shader.sky.cloudHeight ); - +#endif // innerbox token = COM_ParseExt( text, qfalse ); @@ -1839,6 +1858,9 @@ static void ParseSkyParms( const char **text ) { if ( strcmp( token, "-" ) ) { for (i=0 ; i<6 ; i++) { Com_sprintf( pathname, sizeof(pathname), "%s_%s", token, suf[i] ); +#ifdef DEDICATED + shader.sky.innerbox[i] = NULL; +#else shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, (qboolean)!shader.noTC, GL_CLAMP ); if ( !shader.sky.innerbox[i] ) { if (i) { @@ -1847,6 +1869,7 @@ static void ParseSkyParms( const char **text ) { shader.sky.innerbox[i] = tr.defaultImage; } } +#endif // !DEDICATED } } @@ -2536,11 +2559,14 @@ static qboolean CollapseMultitexture( void ) { if ( collapse[i].blendA == -1 ) { return qfalse; } - +#ifdef DEDICATED + return qfalse; +#else // GL_ADD is a separate extension if ( collapse[i].multitextureEnv == GL_ADD && !glConfig.textureEnvAddAvailable ) { return qfalse; } +#endif //!DEDICATED // make sure waveforms have identical parameters if ( ( stages[0].rgbGen != stages[1].rgbGen ) || @@ -2721,6 +2747,8 @@ what it is supposed to look like. OUTPUT: Number of stages after the collapse (in the case of surfacesprites this isn't one). ================= */ +//rww - no longer used, at least for now. destroys alpha shaders completely. +#if 0 static int VertexLightingCollapse( void ) { int stage, nextopenstage; shaderStage_t *bestStage; @@ -2822,6 +2850,7 @@ static int VertexLightingCollapse( void ) { return finalstagenum; } +#endif /* ========================= @@ -3342,13 +3371,17 @@ shader_t *R_FindShader( const char *name, const int *lightmapIndex, const byte * // look for a single TGA, BMP, or PCX // COM_StripExtension(name,fileName); +#ifdef DEDICATED + shader.defaultShader = qtrue; + return FinishShader(); +#else image = R_FindImageFile( fileName, mipRawImage, mipRawImage, qtrue, mipRawImage ? GL_REPEAT : GL_CLAMP ); if ( !image ) { ri.Printf( PRINT_DEVELOPER, "Couldn't find image for shader %s\n", name ); shader.defaultShader = qtrue; return FinishShader(); } - +#endif //!DEDICATED // // create the default shading commands // diff --git a/CODE-mp/renderer/tr_shadows.cpp b/CODE-mp/renderer/tr_shadows.cpp index 767f8ee..c630816 100644 --- a/CODE-mp/renderer/tr_shadows.cpp +++ b/CODE-mp/renderer/tr_shadows.cpp @@ -225,6 +225,8 @@ void RB_ShadowTessEnd( void ) { // reenable writing to the color buffer qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + + qglDisable( GL_CULL_FACE ); } @@ -291,11 +293,11 @@ void RB_ProjectionShadowDeform( void ) { xyz = ( float * ) tess.xyz; - ground[0] = backEnd.or.axis[0][2]; - ground[1] = backEnd.or.axis[1][2]; - ground[2] = backEnd.or.axis[2][2]; + ground[0] = backEnd.ori.axis[0][2]; + ground[1] = backEnd.ori.axis[1][2]; + ground[2] = backEnd.ori.axis[2][2]; - groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane; + groundDist = backEnd.ori.origin[2] - backEnd.currentEntity->e.shadowPlane; VectorCopy( backEnd.currentEntity->lightDir, lightDir ); d = DotProduct( lightDir, ground ); diff --git a/CODE-mp/renderer/tr_sky.cpp b/CODE-mp/renderer/tr_sky.cpp index ab129a2..2084bbd 100644 --- a/CODE-mp/renderer/tr_sky.cpp +++ b/CODE-mp/renderer/tr_sky.cpp @@ -248,7 +248,7 @@ void RB_ClipSkyPolygons( shaderCommands_t *input ) for (j = 0 ; j < 3 ; j++) { VectorSubtract( input->xyz[input->indexes[i+j]], - backEnd.viewParms.or.origin, + backEnd.viewParms.ori.origin, p[j] ); } ClipSkyPolygon( 3, p[0], 0 ); @@ -445,7 +445,7 @@ static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean ad { for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) { - VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] ); + VectorAdd( s_skyPoints[t][s], backEnd.viewParms.ori.origin, tess.xyz[tess.numVertexes] ); tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; @@ -687,7 +687,7 @@ void RB_DrawSun( void ) { return; } qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); - qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); + qglTranslatef (backEnd.viewParms.ori.origin[0], backEnd.viewParms.ori.origin[1], backEnd.viewParms.ori.origin[2]); dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) size = dist * 0.4; @@ -798,7 +798,7 @@ void RB_StageIteratorSky( void ) { qglPushMatrix (); GL_State( 0 ); - qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); + qglTranslatef (backEnd.viewParms.ori.origin[0], backEnd.viewParms.ori.origin[1], backEnd.viewParms.ori.origin[2]); DrawSkyBox( tess.shader ); diff --git a/CODE-mp/renderer/tr_surface.cpp b/CODE-mp/renderer/tr_surface.cpp index 7d49137..b87ecd5 100644 --- a/CODE-mp/renderer/tr_surface.cpp +++ b/CODE-mp/renderer/tr_surface.cpp @@ -25,10 +25,16 @@ RB_CheckOverflow ============== */ void RB_CheckOverflow( int verts, int indexes ) { - if (tess.numVertexes + verts < SHADER_MAX_VERTEXES - && tess.numIndexes + indexes < SHADER_MAX_INDEXES) { - return; - } + if ( tess.shader == tr.shadowShader ) { + if (tess.numVertexes + verts < SHADER_MAX_VERTEXES/2 + && tess.numIndexes + indexes < SHADER_MAX_INDEXES) { + return; + } + } else + if (tess.numVertexes + verts < SHADER_MAX_VERTEXES + && tess.numIndexes + indexes < SHADER_MAX_INDEXES) { + return; + } RB_EndSurface(); @@ -83,7 +89,7 @@ void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, flo // constant normal all the way around - VectorSubtract( vec3_origin, backEnd.viewParms.or.axis[0], normal ); + VectorSubtract( vec3_origin, backEnd.viewParms.ori.axis[0], normal ); tess.normal[ndx][0] = tess.normal[ndx+1][0] = tess.normal[ndx+2][0] = tess.normal[ndx+3][0] = normal[0]; tess.normal[ndx][1] = tess.normal[ndx+1][1] = tess.normal[ndx+2][1] = tess.normal[ndx+3][1] = normal[1]; @@ -136,8 +142,8 @@ static void RB_SurfaceSprite( void ) { // calculate the xyz locations for the four corners radius = backEnd.currentEntity->e.radius; if ( backEnd.currentEntity->e.rotation == 0 ) { - VectorScale( backEnd.viewParms.or.axis[1], radius, left ); - VectorScale( backEnd.viewParms.or.axis[2], radius, up ); + VectorScale( backEnd.viewParms.ori.axis[1], radius, left ); + VectorScale( backEnd.viewParms.ori.axis[2], radius, up ); } else { float s, c; float ang; @@ -146,11 +152,11 @@ static void RB_SurfaceSprite( void ) { s = sin( ang ); c = cos( ang ); - VectorScale( backEnd.viewParms.or.axis[1], c * radius, left ); - VectorMA( left, -s * radius, backEnd.viewParms.or.axis[2], left ); + VectorScale( backEnd.viewParms.ori.axis[1], c * radius, left ); + VectorMA( left, -s * radius, backEnd.viewParms.ori.axis[2], left ); - VectorScale( backEnd.viewParms.or.axis[2], c * radius, up ); - VectorMA( up, s * radius, backEnd.viewParms.or.axis[1], up ); + VectorScale( backEnd.viewParms.ori.axis[2], c * radius, up ); + VectorMA( up, s * radius, backEnd.viewParms.ori.axis[1], up ); } if ( backEnd.viewParms.isMirror ) { VectorSubtract( vec3_origin, left, left ); @@ -428,11 +434,11 @@ static void DoSprite( vec3_t origin, float radius, float rotation ) s = sin( ang ); c = cos( ang ); - VectorScale( backEnd.viewParms.or.axis[1], c * radius, left ); - VectorMA( left, -s * radius, backEnd.viewParms.or.axis[2], left ); + VectorScale( backEnd.viewParms.ori.axis[1], c * radius, left ); + VectorMA( left, -s * radius, backEnd.viewParms.ori.axis[2], left ); - VectorScale( backEnd.viewParms.or.axis[2], c * radius, up ); - VectorMA( up, s * radius, backEnd.viewParms.or.axis[1], up ); + VectorScale( backEnd.viewParms.ori.axis[2], c * radius, up ); + VectorMA( up, s * radius, backEnd.viewParms.ori.axis[1], up ); if ( backEnd.viewParms.isMirror ) { @@ -665,8 +671,8 @@ void RB_SurfaceLine( void ) VectorCopy( e->origin, start ); // compute side vector - VectorSubtract( start, backEnd.viewParms.or.origin, v1 ); - VectorSubtract( end, backEnd.viewParms.or.origin, v2 ); + VectorSubtract( start, backEnd.viewParms.ori.origin, v1 ); + VectorSubtract( end, backEnd.viewParms.ori.origin, v2 ); CrossProduct( v1, v2, right ); VectorNormalize( right ); @@ -749,7 +755,7 @@ void RB_SurfaceCylinder( void ) VectorAdd( e->origin, e->oldorigin, midpoint ); VectorScale(midpoint, 0.5f, midpoint); // Average start and end - VectorSubtract( midpoint, backEnd.viewParms.or.origin, midpoint ); + VectorSubtract( midpoint, backEnd.viewParms.ori.origin, midpoint ); length = VectorNormalize( midpoint ); // this doesn't need to be perfect....just a rough compensation for zoom level is enough @@ -838,6 +844,8 @@ void RB_SurfaceCylinder( void ) static vec3_t sh1, sh2; static float f_count; +#define LIGHTNING_RECURSION_LEVEL 1 // was 2 + // these functions are pretty crappy in terms of returning a nice range of rnd numbers, but it's probably good enough? /*static int Q_rand( int *seed ) { *seed = (69069 * *seed + 1); @@ -975,7 +983,7 @@ static void DoBoltSeg( vec3_t start, vec3_t end, vec3_t right, float radius ) } // Apply the random shape to our line seg to give it some micro-detail-jaggy-coolness. - ApplyShape( cur, old, right, newRadius, oldRadius, 2 ); + ApplyShape( cur, old, right, newRadius, oldRadius, LIGHTNING_RECURSION_LEVEL ); // randomly split off to create little tendrils, but don't do it too close to the end and especially if we are not even of the forked variety if ( ( e->renderfx & RF_FORKED ) && f_count > 0 && Q_random(&e->frame) > 0.94f && radius * (1.0f - perc) > 0.2f ) @@ -1041,8 +1049,8 @@ static void RB_SurfaceElectricity() VectorCopy( e->oldorigin, end ); // compute side vector - VectorSubtract( start, backEnd.viewParms.or.origin, v1 ); - VectorSubtract( end, backEnd.viewParms.or.origin, v2 ); + VectorSubtract( start, backEnd.viewParms.ori.origin, v1 ); + VectorSubtract( end, backEnd.viewParms.ori.origin, v2 ); CrossProduct( v1, v2, right ); VectorNormalize( right ); @@ -1336,15 +1344,15 @@ static float LodErrorForVolume( vec3_t local, float radius ) { return 0; } - world[0] = local[0] * backEnd.or.axis[0][0] + local[1] * backEnd.or.axis[1][0] + - local[2] * backEnd.or.axis[2][0] + backEnd.or.origin[0]; - world[1] = local[0] * backEnd.or.axis[0][1] + local[1] * backEnd.or.axis[1][1] + - local[2] * backEnd.or.axis[2][1] + backEnd.or.origin[1]; - world[2] = local[0] * backEnd.or.axis[0][2] + local[1] * backEnd.or.axis[1][2] + - local[2] * backEnd.or.axis[2][2] + backEnd.or.origin[2]; + world[0] = local[0] * backEnd.ori.axis[0][0] + local[1] * backEnd.ori.axis[1][0] + + local[2] * backEnd.ori.axis[2][0] + backEnd.ori.origin[0]; + world[1] = local[0] * backEnd.ori.axis[0][1] + local[1] * backEnd.ori.axis[1][1] + + local[2] * backEnd.ori.axis[2][1] + backEnd.ori.origin[1]; + world[2] = local[0] * backEnd.ori.axis[0][2] + local[1] * backEnd.ori.axis[1][2] + + local[2] * backEnd.ori.axis[2][2] + backEnd.ori.origin[2]; - VectorSubtract( world, backEnd.viewParms.or.origin, world ); - d = DotProduct( world, backEnd.viewParms.or.axis[0] ); + VectorSubtract( world, backEnd.viewParms.ori.origin, world ); + d = DotProduct( world, backEnd.viewParms.ori.axis[0] ); if ( d < 0 ) { d = -d; diff --git a/CODE-mp/renderer/tr_surfacesprites.cpp b/CODE-mp/renderer/tr_surfacesprites.cpp index e27d010..6bd6bfb 100644 --- a/CODE-mp/renderer/tr_surfacesprites.cpp +++ b/CODE-mp/renderer/tr_surfacesprites.cpp @@ -2,8 +2,8 @@ #include "tr_local.h" -#include "tr_quicksprite.h" -#include "tr_worldeffects.h" +#include "tr_QuickSprite.h" +#include "tr_WorldEffects.h" /////===== Part of the VERTIGON system =====///// @@ -1425,18 +1425,18 @@ void RB_DrawSurfaceSprites( shaderStage_t *stage, shaderCommands_t *input) { if (backEnd.currentEntity == &tr.worldEntity) { // Drawing the world, so our job is dead-easy, in the viewparms - VectorCopy(backEnd.viewParms.or.origin, ssViewOrigin); - VectorCopy(backEnd.viewParms.or.axis[1], ssViewRight); - VectorCopy(backEnd.viewParms.or.axis[2], ssViewUp); + VectorCopy(backEnd.viewParms.ori.origin, ssViewOrigin); + VectorCopy(backEnd.viewParms.ori.axis[1], ssViewRight); + VectorCopy(backEnd.viewParms.ori.axis[2], ssViewUp); } else { // Drawing an entity, so we need to transform the viewparms to the model's coordinate system -// R_WorldPointToEntity (backEnd.viewParms.or.origin, ssViewOrigin); - R_WorldNormalToEntity (backEnd.viewParms.or.axis[1], ssViewRight); - R_WorldNormalToEntity (backEnd.viewParms.or.axis[2], ssViewUp); - VectorCopy(backEnd.or.viewOrigin, ssViewOrigin); -// R_WorldToLocal(backEnd.viewParms.or.axis[1], ssViewRight); -// R_WorldToLocal(backEnd.viewParms.or.axis[2], ssViewUp); +// R_WorldPointToEntity (backEnd.viewParms.ori.origin, ssViewOrigin); + R_WorldNormalToEntity (backEnd.viewParms.ori.axis[1], ssViewRight); + R_WorldNormalToEntity (backEnd.viewParms.ori.axis[2], ssViewUp); + VectorCopy(backEnd.ori.viewOrigin, ssViewOrigin); +// R_WorldToLocal(backEnd.viewParms.ori.axis[1], ssViewRight); +// R_WorldToLocal(backEnd.viewParms.ori.axis[2], ssViewUp); } ssLastEntityDrawn = backEnd.currentEntity; } diff --git a/CODE-mp/renderer/vssver.scc b/CODE-mp/renderer/vssver.scc new file mode 100644 index 0000000..7210697 Binary files /dev/null and b/CODE-mp/renderer/vssver.scc differ diff --git a/CODE-mp/server/server.h b/CODE-mp/server/server.h index d677b9b..f5d1365 100644 --- a/CODE-mp/server/server.h +++ b/CODE-mp/server/server.h @@ -212,6 +212,8 @@ extern cvar_t *sv_pure; extern cvar_t *sv_floodProtect; extern cvar_t *sv_allowAnonymous; +extern cvar_t *sv_debugserver; + //=========================================================== diff --git a/CODE-mp/server/sv_bot.cpp b/CODE-mp/server/sv_bot.cpp index 57a7c25..f49584b 100644 --- a/CODE-mp/server/sv_bot.cpp +++ b/CODE-mp/server/sv_bot.cpp @@ -531,10 +531,6 @@ SV_BotInitBotLib void SV_BotInitBotLib(void) { botlib_import_t botlib_import; - if ( !Cvar_VariableValue("fs_restrict") && !Sys_CheckCD() ) { - Com_Error( ERR_NEED_CD, "Game CD not in drive" ); - } - if (debugpolygons) Z_Free(debugpolygons); bot_maxdebugpolys = Cvar_VariableIntegerValue("bot_maxdebugpolys"); debugpolygons = (struct bot_debugpoly_s *)Z_Malloc(sizeof(bot_debugpoly_t) * bot_maxdebugpolys, TAG_BOTLIB, qtrue); diff --git a/CODE-mp/server/sv_bot.org b/CODE-mp/server/sv_bot.org new file mode 100644 index 0000000..57a7c25 --- /dev/null +++ b/CODE-mp/server/sv_bot.org @@ -0,0 +1,648 @@ +// sv_bot.c + +#include "server.h" +#include "../game/botlib.h" + +typedef struct bot_debugpoly_s +{ + int inuse; + int color; + int numPoints; + vec3_t points[128]; +} bot_debugpoly_t; + +static bot_debugpoly_t *debugpolygons; +int bot_maxdebugpolys; + +extern botlib_export_t *botlib_export; +int bot_enable; + + +/* +================== +SV_BotAllocateClient +================== +*/ +int SV_BotAllocateClient(void) { + int i; + client_t *cl; + + // find a client slot + for ( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { + if ( cl->state == CS_FREE ) { + break; + } + } + + if ( i == sv_maxclients->integer ) { + return -1; + } + + cl->gentity = SV_GentityNum( i ); + cl->gentity->s.number = i; + cl->state = CS_ACTIVE; + cl->lastPacketTime = svs.time; + cl->netchan.remoteAddress.type = NA_BOT; + cl->rate = 16384; + + return i; +} + +/* +================== +SV_BotFreeClient +================== +*/ +void SV_BotFreeClient( int clientNum ) { + client_t *cl; + + if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) { + Com_Error( ERR_DROP, "SV_BotFreeClient: bad clientNum: %i", clientNum ); + } + cl = &svs.clients[clientNum]; + cl->state = CS_FREE; + cl->name[0] = 0; + if ( cl->gentity ) { + cl->gentity->r.svFlags &= ~SVF_BOT; + } +} + +/* +================== +BotDrawDebugPolygons +================== +*/ +void BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value) { + static cvar_t *bot_debug, *bot_groundonly, *bot_reachability, *bot_highlightarea; + bot_debugpoly_t *poly; + int i, parm0; + + if (!debugpolygons) + return; + //bot debugging + if (!bot_debug) bot_debug = Cvar_Get("bot_debug", "0", 0); + // + if (bot_enable && bot_debug->integer) { + //show reachabilities + if (!bot_reachability) bot_reachability = Cvar_Get("bot_reachability", "0", 0); + //show ground faces only + if (!bot_groundonly) bot_groundonly = Cvar_Get("bot_groundonly", "1", 0); + //get the hightlight area + if (!bot_highlightarea) bot_highlightarea = Cvar_Get("bot_highlightarea", "0", 0); + // + parm0 = 0; + if (svs.clients[0].lastUsercmd.buttons & BUTTON_ATTACK) parm0 |= 1; + if (bot_reachability->integer) parm0 |= 2; + if (bot_groundonly->integer) parm0 |= 4; + botlib_export->BotLibVarSet("bot_highlightarea", bot_highlightarea->string); + botlib_export->Test(parm0, NULL, svs.clients[0].gentity->r.currentOrigin, + svs.clients[0].gentity->r.currentAngles); + } //end if + //draw all debug polys + for (i = 0; i < bot_maxdebugpolys; i++) { + poly = &debugpolygons[i]; + if (!poly->inuse) continue; + drawPoly(poly->color, poly->numPoints, (float *) poly->points); + //Com_Printf("poly %i, numpoints = %d\n", i, poly->numPoints); + } +} + +/* +================== +BotImport_Print +================== +*/ +void QDECL BotImport_Print(int type, char *fmt, ...) +{ + char str[2048]; + va_list ap; + + va_start(ap, fmt); + vsprintf(str, fmt, ap); + va_end(ap); + + switch(type) { + case PRT_MESSAGE: { + Com_Printf("%s", str); + break; + } + case PRT_WARNING: { + Com_Printf(S_COLOR_YELLOW "Warning: %s", str); + break; + } + case PRT_ERROR: { + Com_Printf(S_COLOR_RED "Error: %s", str); + break; + } + case PRT_FATAL: { + Com_Printf(S_COLOR_RED "Fatal: %s", str); + break; + } + case PRT_EXIT: { + Com_Error(ERR_DROP, S_COLOR_RED "Exit: %s", str); + break; + } + default: { + Com_Printf("unknown print type\n"); + break; + } + } +} + +/* +================== +BotImport_Trace +================== +*/ +void BotImport_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) { + trace_t trace; + + SV_Trace(&trace, start, mins, maxs, end, passent, contentmask, qfalse, 0, 10); + //copy the trace information + bsptrace->allsolid = trace.allsolid; + bsptrace->startsolid = trace.startsolid; + bsptrace->fraction = trace.fraction; + VectorCopy(trace.endpos, bsptrace->endpos); + bsptrace->plane.dist = trace.plane.dist; + VectorCopy(trace.plane.normal, bsptrace->plane.normal); + bsptrace->plane.signbits = trace.plane.signbits; + bsptrace->plane.type = trace.plane.type; + bsptrace->surface.value = trace.surfaceFlags; + bsptrace->ent = trace.entityNum; + bsptrace->exp_dist = 0; + bsptrace->sidenum = 0; + bsptrace->contents = 0; +} + +/* +================== +BotImport_EntityTrace +================== +*/ +void BotImport_EntityTrace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask) { + trace_t trace; + + SV_ClipToEntity(&trace, start, mins, maxs, end, entnum, contentmask, qfalse); + //copy the trace information + bsptrace->allsolid = trace.allsolid; + bsptrace->startsolid = trace.startsolid; + bsptrace->fraction = trace.fraction; + VectorCopy(trace.endpos, bsptrace->endpos); + bsptrace->plane.dist = trace.plane.dist; + VectorCopy(trace.plane.normal, bsptrace->plane.normal); + bsptrace->plane.signbits = trace.plane.signbits; + bsptrace->plane.type = trace.plane.type; + bsptrace->surface.value = trace.surfaceFlags; + bsptrace->ent = trace.entityNum; + bsptrace->exp_dist = 0; + bsptrace->sidenum = 0; + bsptrace->contents = 0; +} + + +/* +================== +BotImport_PointContents +================== +*/ +int BotImport_PointContents(vec3_t point) { + return SV_PointContents(point, -1); +} + +/* +================== +BotImport_inPVS +================== +*/ +int BotImport_inPVS(vec3_t p1, vec3_t p2) { + return SV_inPVS (p1, p2); +} + +/* +================== +BotImport_BSPEntityData +================== +*/ +char *BotImport_BSPEntityData(void) { + return CM_EntityString(); +} + +/* +================== +BotImport_BSPModelMinsMaxsOrigin +================== +*/ +void BotImport_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin) { + clipHandle_t h; + vec3_t mins, maxs; + float max; + int i; + + h = CM_InlineModel(modelnum); + CM_ModelBounds(h, mins, maxs); + //if the model is rotated + if ((angles[0] || angles[1] || angles[2])) { + // expand for rotation + + max = RadiusFromBounds(mins, maxs); + for (i = 0; i < 3; i++) { + mins[i] = -max; + maxs[i] = max; + } + } + if (outmins) VectorCopy(mins, outmins); + if (outmaxs) VectorCopy(maxs, outmaxs); + if (origin) VectorClear(origin); +} + +/* +================== +BotImport_GetMemoryGame +================== +*/ +void *Bot_GetMemoryGame(int size) { + void *ptr; + + ptr = Z_Malloc( size, TAG_BOTGAME, qtrue ); + + return ptr; +} + +/* +================== +BotImport_FreeMemoryGame +================== +*/ +void Bot_FreeMemoryGame(void *ptr) { + Z_Free(ptr); +} + +/* +================== +BotImport_GetMemory +================== +*/ +void *BotImport_GetMemory(int size) { + void *ptr; + + ptr = Z_Malloc( size, TAG_BOTLIB, qtrue ); + return ptr; +} + +/* +================== +BotImport_FreeMemory +================== +*/ +void BotImport_FreeMemory(void *ptr) { + Z_Free(ptr); +} + +/* +================= +BotImport_HunkAlloc +================= +*/ +void *BotImport_HunkAlloc( int size ) { + if( Hunk_CheckMark() ) { + Com_Error( ERR_DROP, "SV_Bot_HunkAlloc: Alloc with marks already set\n" ); + } + return Hunk_Alloc( size, h_high ); +} + +/* +================== +BotImport_DebugPolygonCreate +================== +*/ +int BotImport_DebugPolygonCreate(int color, int numPoints, vec3_t *points) { + bot_debugpoly_t *poly; + int i; + + if (!debugpolygons) + return 0; + + for (i = 1; i < bot_maxdebugpolys; i++) { + if (!debugpolygons[i].inuse) + break; + } + if (i >= bot_maxdebugpolys) + return 0; + poly = &debugpolygons[i]; + poly->inuse = qtrue; + poly->color = color; + poly->numPoints = numPoints; + Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t)); + // + return i; +} + +/* +================== +BotImport_DebugPolygonShow +================== +*/ +void BotImport_DebugPolygonShow(int id, int color, int numPoints, vec3_t *points) { + bot_debugpoly_t *poly; + + if (!debugpolygons) return; + poly = &debugpolygons[id]; + poly->inuse = qtrue; + poly->color = color; + poly->numPoints = numPoints; + Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t)); +} + +/* +================== +BotImport_DebugPolygonDelete +================== +*/ +void BotImport_DebugPolygonDelete(int id) +{ + if (!debugpolygons) return; + debugpolygons[id].inuse = qfalse; +} + +/* +================== +BotImport_DebugLineCreate +================== +*/ +int BotImport_DebugLineCreate(void) { + vec3_t points[1]; + return BotImport_DebugPolygonCreate(0, 0, points); +} + +/* +================== +BotImport_DebugLineDelete +================== +*/ +void BotImport_DebugLineDelete(int line) { + BotImport_DebugPolygonDelete(line); +} + +/* +================== +BotImport_DebugLineShow +================== +*/ +void BotImport_DebugLineShow(int line, vec3_t start, vec3_t end, int color) { + vec3_t points[4], dir, cross, up = {0, 0, 1}; + float dot; + + VectorCopy(start, points[0]); + VectorCopy(start, points[1]); + //points[1][2] -= 2; + VectorCopy(end, points[2]); + //points[2][2] -= 2; + VectorCopy(end, points[3]); + + + VectorSubtract(end, start, dir); + VectorNormalize(dir); + dot = DotProduct(dir, up); + if (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0); + else CrossProduct(dir, up, cross); + + VectorNormalize(cross); + + VectorMA(points[0], 2, cross, points[0]); + VectorMA(points[1], -2, cross, points[1]); + VectorMA(points[2], -2, cross, points[2]); + VectorMA(points[3], 2, cross, points[3]); + + BotImport_DebugPolygonShow(line, color, 4, points); +} + +/* +================== +SV_BotClientCommand +================== +*/ +void BotClientCommand( int client, char *command ) { + SV_ExecuteClientCommand( &svs.clients[client], command, qtrue ); +} + +/* +================== +SV_BotFrame +================== +*/ +void SV_BotFrame( int time ) { + if (!bot_enable) return; + //NOTE: maybe the game is already shutdown + if (!gvm) return; + VM_Call( gvm, BOTAI_START_FRAME, time ); +} + +/* +=============== +SV_BotLibSetup +=============== +*/ +int SV_BotLibSetup( void ) { + if (!bot_enable) { + return 0; + } + + if ( !botlib_export ) { + Com_Printf( S_COLOR_RED "Error: SV_BotLibSetup without SV_BotInitBotLib\n" ); + return -1; + } + + return botlib_export->BotLibSetup(); +} + +/* +=============== +SV_ShutdownBotLib + +Called when either the entire server is being killed, or +it is changing to a different game directory. +=============== +*/ +int SV_BotLibShutdown( void ) { + + if ( !botlib_export ) { + return -1; + } + + return botlib_export->BotLibShutdown(); +} + +/* +================== +SV_BotInitCvars +================== +*/ +void SV_BotInitCvars(void) { + + Cvar_Get("bot_enable", "1", 0); //enable the bot + Cvar_Get("bot_developer", "0", CVAR_CHEAT); //bot developer mode + Cvar_Get("bot_debug", "0", CVAR_CHEAT); //enable bot debugging + Cvar_Get("bot_maxdebugpolys", "2", 0); //maximum number of debug polys + Cvar_Get("bot_groundonly", "1", 0); //only show ground faces of areas + Cvar_Get("bot_reachability", "0", 0); //show all reachabilities to other areas + Cvar_Get("bot_visualizejumppads", "0", CVAR_CHEAT); //show jumppads + Cvar_Get("bot_forceclustering", "0", 0); //force cluster calculations + Cvar_Get("bot_forcereachability", "0", 0); //force reachability calculations + Cvar_Get("bot_forcewrite", "0", 0); //force writing aas file + Cvar_Get("bot_aasoptimize", "0", 0); //no aas file optimisation + Cvar_Get("bot_saveroutingcache", "0", 0); //save routing cache + Cvar_Get("bot_thinktime", "100", CVAR_CHEAT); //msec the bots thinks + Cvar_Get("bot_reloadcharacters", "0", 0); //reload the bot characters each time + Cvar_Get("bot_testichat", "0", 0); //test ichats + Cvar_Get("bot_testrchat", "0", 0); //test rchats + Cvar_Get("bot_testsolid", "0", CVAR_CHEAT); //test for solid areas + Cvar_Get("bot_testclusters", "0", CVAR_CHEAT); //test the AAS clusters + Cvar_Get("bot_fastchat", "0", 0); //fast chatting bots + Cvar_Get("bot_nochat", "0", 0); //disable chats + Cvar_Get("bot_pause", "0", CVAR_CHEAT); //pause the bots thinking + Cvar_Get("bot_report", "0", CVAR_CHEAT); //get a full report in ctf + Cvar_Get("bot_grapple", "0", 0); //enable grapple + Cvar_Get("bot_rocketjump", "1", 0); //enable rocket jumping + Cvar_Get("bot_challenge", "0", 0); //challenging bot + Cvar_Get("bot_minplayers", "0", 0); //minimum players in a team or the game + Cvar_Get("bot_interbreedchar", "", CVAR_CHEAT); //bot character used for interbreeding + Cvar_Get("bot_interbreedbots", "10", CVAR_CHEAT); //number of bots used for interbreeding + Cvar_Get("bot_interbreedcycle", "20", CVAR_CHEAT); //bot interbreeding cycle + Cvar_Get("bot_interbreedwrite", "", CVAR_CHEAT); //write interbreeded bots to this file +} + +extern botlib_export_t *GetBotLibAPI( int apiVersion, botlib_import_t *import ); + +// there's no such thing as this now, since the zone is unlimited, but I have to provide something +// so it doesn't run out of control alloc-wise (since the bot code calls this in a while() loop to free +// up bot mem until zone has > 1MB available again. So, simulate a reasonable limit... +// +static int bot_Z_AvailableMemory(void) +{ + const int iMaxBOTLIBMem = 8 * 1024 * 1024; // adjust accordingly. + return iMaxBOTLIBMem - Z_MemSize( TAG_BOTLIB ); +} + +/* +================== +SV_BotInitBotLib +================== +*/ +void SV_BotInitBotLib(void) { + botlib_import_t botlib_import; + + if ( !Cvar_VariableValue("fs_restrict") && !Sys_CheckCD() ) { + Com_Error( ERR_NEED_CD, "Game CD not in drive" ); + } + + if (debugpolygons) Z_Free(debugpolygons); + bot_maxdebugpolys = Cvar_VariableIntegerValue("bot_maxdebugpolys"); + debugpolygons = (struct bot_debugpoly_s *)Z_Malloc(sizeof(bot_debugpoly_t) * bot_maxdebugpolys, TAG_BOTLIB, qtrue); + + botlib_import.Print = BotImport_Print; + botlib_import.Trace = BotImport_Trace; + botlib_import.EntityTrace = BotImport_EntityTrace; + botlib_import.PointContents = BotImport_PointContents; + botlib_import.inPVS = BotImport_inPVS; + botlib_import.BSPEntityData = BotImport_BSPEntityData; + botlib_import.BSPModelMinsMaxsOrigin = BotImport_BSPModelMinsMaxsOrigin; + botlib_import.BotClientCommand = BotClientCommand; + + //memory management + botlib_import.GetMemory = BotImport_GetMemory; + botlib_import.FreeMemory = BotImport_FreeMemory; + botlib_import.AvailableMemory = bot_Z_AvailableMemory; //Z_AvailableMemory; + botlib_import.HunkAlloc = BotImport_HunkAlloc; + + // file system access + botlib_import.FS_FOpenFile = FS_FOpenFileByMode; + botlib_import.FS_Read = FS_Read2; + botlib_import.FS_Write = FS_Write; + botlib_import.FS_FCloseFile = FS_FCloseFile; + botlib_import.FS_Seek = FS_Seek; + + //debug lines + botlib_import.DebugLineCreate = BotImport_DebugLineCreate; + botlib_import.DebugLineDelete = BotImport_DebugLineDelete; + botlib_import.DebugLineShow = BotImport_DebugLineShow; + + //debug polygons + botlib_import.DebugPolygonCreate = BotImport_DebugPolygonCreate; + botlib_import.DebugPolygonDelete = BotImport_DebugPolygonDelete; + + botlib_export = (botlib_export_t *)GetBotLibAPI( BOTLIB_API_VERSION, &botlib_import ); + assert(botlib_export); // bk001129 - somehow we end up with a zero import. +} + + +// +// * * * BOT AI CODE IS BELOW THIS POINT * * * +// + +/* +================== +SV_BotGetConsoleMessage +================== +*/ +int SV_BotGetConsoleMessage( int client, char *buf, int size ) +{ + client_t *cl; + int index; + + cl = &svs.clients[client]; + cl->lastPacketTime = svs.time; + + if ( cl->reliableAcknowledge == cl->reliableSequence ) { + return qfalse; + } + + cl->reliableAcknowledge++; + index = cl->reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 ); + + if ( !cl->reliableCommands[index][0] ) { + return qfalse; + } + + Q_strncpyz( buf, cl->reliableCommands[index], size ); + return qtrue; +} + +#if 0 +/* +================== +EntityInPVS +================== +*/ +int EntityInPVS( int client, int entityNum ) { + client_t *cl; + clientSnapshot_t *frame; + int i; + + cl = &svs.clients[client]; + frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK]; + for ( i = 0; i < frame->num_entities; i++ ) { + if ( svs.snapshotEntities[(frame->first_entity + i) % svs.numSnapshotEntities].number == entityNum ) { + return qtrue; + } + } + return qfalse; +} +#endif + +/* +================== +SV_BotGetSnapshotEntity +================== +*/ +int SV_BotGetSnapshotEntity( int client, int sequence ) { + client_t *cl; + clientSnapshot_t *frame; + + cl = &svs.clients[client]; + frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK]; + if (sequence < 0 || sequence >= frame->num_entities) { + return -1; + } + return svs.snapshotEntities[(frame->first_entity + sequence) % svs.numSnapshotEntities].number; +} + diff --git a/CODE-mp/server/sv_ccmds.cpp b/CODE-mp/server/sv_ccmds.cpp index 29faf07..7f999fb 100644 --- a/CODE-mp/server/sv_ccmds.cpp +++ b/CODE-mp/server/sv_ccmds.cpp @@ -12,6 +12,25 @@ These commands can only be entered from stdin or by a remote operator datagram =============================================================================== */ +const char *SV_GetStripEdString(char *refSection, char *refName) +{ + /* + static char text[1024]={0}; + trap_SP_GetStringTextString(va("%s_%s", refSection, refName), text, sizeof(text)); + return text; + */ + + //Well, it would've been lovely doing it the above way, but it would mean mixing + //languages for the client depending on what the server is. So we'll mark this as + //a striped reference with @@@ and send the refname to the client, and when it goes + //to print it will get scanned for the striped reference indication and dealt with + //properly. + static char text[1024]={0}; + Com_sprintf(text, sizeof(text), "@@@%s", refName); + return text; +} + + /* ================== @@ -102,8 +121,6 @@ static client_t *SV_GetPlayerByNum( void ) { return NULL; } return cl; - - return NULL; } //========================================================= @@ -237,7 +254,7 @@ static void SV_MapRestart_f( void ) { else { delay = 5; } - if( delay && !Cvar_VariableValue("g_doWarmup") ) { + if( delay && (!Cvar_VariableValue("g_doWarmup") || Cvar_VariableValue("g_gametype") == GT_TOURNAMENT) ) { sv.restartTime = svs.time + delay * 1000; SV_SetConfigstring( CS_WARMUP, va("%i", sv.restartTime) ); return; @@ -322,6 +339,107 @@ static void SV_MapRestart_f( void ) { //=============================================================== +/* +================== +SV_GetPlayerByName + +Returns the player with name from Cmd_Argv(1) +================== +*/ +static client_t *SV_GetPlayerByFedName( const char *name ) +{ + client_t *cl; + int i; + char cleanName[64]; + + // make sure server is running + if ( !com_sv_running->integer ) + { + return NULL; + } + + // check for a name match + for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) + { + if ( !cl->state ) + { + continue; + } + if ( !Q_stricmp( cl->name, name ) ) + { + return cl; + } + + Q_strncpyz( cleanName, cl->name, sizeof(cleanName) ); + Q_CleanStr( cleanName ); + if ( !Q_stricmp( cleanName, name ) ) + { + return cl; + } + } + + return NULL; +} + +static void SV_KickByName( const char *name ) +{ + client_t *cl; + int i; + + // make sure server is running + if ( !com_sv_running->integer ) + { + return; + } + + cl = SV_GetPlayerByFedName(name); + if ( !cl ) + { + if ( !Q_stricmp(name, "all") ) + { + for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) + { + if ( !cl->state ) + { + continue; + } + if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) + { + continue; + } + SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); + cl->lastPacketTime = svs.time; // in case there is a funny zombie + } + } + else if ( !Q_stricmp(name, "allbots") ) + { + for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) + { + if ( !cl->state ) + { + continue; + } + if( cl->netchan.remoteAddress.type != NA_BOT ) + { + continue; + } + SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); + cl->lastPacketTime = svs.time; // in case there is a funny zombie + } + } + return; + } + if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) + { +// SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n"); + SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST")); + return; + } + + SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); + cl->lastPacketTime = svs.time; // in case there is a funny zombie +} + /* ================== SV_Kick_f @@ -344,6 +462,11 @@ static void SV_Kick_f( void ) { return; } + if (!Q_stricmp(Cmd_Argv(1), "Padawan")) + { //if you try to kick the default name, also try to kick "" + SV_KickByName(""); + } + cl = SV_GetPlayerByName(); if ( !cl ) { if ( !Q_stricmp(Cmd_Argv(1), "all") ) { @@ -354,7 +477,7 @@ static void SV_Kick_f( void ) { if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) { continue; } - SV_DropClient( cl, "was kicked" ); + SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie } } @@ -366,18 +489,19 @@ static void SV_Kick_f( void ) { if( cl->netchan.remoteAddress.type != NA_BOT ) { continue; } - SV_DropClient( cl, "was kicked" ); + SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie } } return; } if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) { - SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n"); +// SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n"); + SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST")); return; } - SV_DropClient( cl, "was kicked" ); + SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie } @@ -412,7 +536,8 @@ static void SV_Ban_f( void ) { } if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) { - SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n"); +// SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n"); + SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST")); return; } @@ -466,7 +591,8 @@ static void SV_BanNum_f( void ) { return; } if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) { - SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n"); +// SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n"); + SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST")); return; } @@ -521,11 +647,12 @@ static void SV_KickNum_f( void ) { return; } if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) { - SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n"); +// SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n"); + SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST")); return; } - SV_DropClient( cl, "was kicked" ); + SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie } diff --git a/CODE-mp/server/sv_client.cpp b/CODE-mp/server/sv_client.cpp index 0dcbebe..769a928 100644 --- a/CODE-mp/server/sv_client.cpp +++ b/CODE-mp/server/sv_client.cpp @@ -1,6 +1,7 @@ // sv_client.c -- server code for dealing with clients #include "server.h" +#include "../qcommon/strip.h" static void SV_CloseDownload( client_t *cl ); @@ -363,7 +364,8 @@ void SV_DirectConnect( netadr_t from ) { } } else { - NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is full.\n" ); + const char *SV_GetStripEdString(char *refSection, char *refName); + NET_OutOfBandPrint( NS_SERVER, from, va("print\n%s\n", SV_GetStripEdString("SVINGAME","SERVER_IS_FULL"))); Com_DPrintf ("Rejected a connection.\n"); return; } @@ -521,6 +523,17 @@ void SV_SendClientGameState( client_t *client ) { msg_t msg; byte msgBuffer[MAX_MSGLEN]; + // MW - my attempt to fix illegible server message errors caused by + // packet fragmentation of initial snapshot. + while(client->state&&client->netchan.unsentFragments) + { + // send additional message fragments if the last message + // was too large to send at once + + Com_Printf ("[ISM]SV_SendClientGameState() [2] for %s, writing out old fragments\n", client->name); + SV_Netchan_TransmitNextFragment(&client->netchan); + } + Com_DPrintf ("SV_SendClientGameState() for %s\n", client->name); Com_DPrintf( "Going from CS_CONNECTED to CS_PRIMED for %s\n", client->name ); client->state = CS_PRIMED; @@ -919,8 +932,10 @@ SV_Disconnect_f The client is going to disconnect, so remove the connection immediately FIXME: move to game? ================= */ +const char *SV_GetStripEdString(char *refSection, char *refName); static void SV_Disconnect_f( client_t *cl ) { - SV_DropClient( cl, "disconnected" ); +// SV_DropClient( cl, "disconnected" ); + SV_DropClient( cl, SV_GetStripEdString("SVINGAME","DISCONNECTED") ); } /* diff --git a/CODE-mp/server/sv_client.org b/CODE-mp/server/sv_client.org new file mode 100644 index 0000000..ee972d5 --- /dev/null +++ b/CODE-mp/server/sv_client.org @@ -0,0 +1,1439 @@ +// sv_client.c -- server code for dealing with clients + +#include "server.h" + +static void SV_CloseDownload( client_t *cl ); + +/* +================= +SV_GetChallenge + +A "getchallenge" OOB command has been received +Returns a challenge number that can be used +in a subsequent connectResponse command. +We do this to prevent denial of service attacks that +flood the server with invalid connection IPs. With a +challenge, they must give a valid IP address. + +If we are authorizing, a challenge request will cause a packet +to be sent to the authorize server. + +When an authorizeip is returned, a challenge response will be +sent to that ip. +================= +*/ +void SV_GetChallenge( netadr_t from ) { + int i; + int oldest; + int oldestTime; + challenge_t *challenge; + + // ignore if we are in single player + if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) { + return; + } + + oldest = 0; + oldestTime = 0x7fffffff; + + // see if we already have a challenge for this ip + challenge = &svs.challenges[0]; + for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { + if ( !challenge->connected && NET_CompareAdr( from, challenge->adr ) ) { + break; + } + if ( challenge->time < oldestTime ) { + oldestTime = challenge->time; + oldest = i; + } + } + + if (i == MAX_CHALLENGES) { + // this is the first time this client has asked for a challenge + challenge = &svs.challenges[oldest]; + + challenge->challenge = ( (rand() << 16) ^ rand() ) ^ svs.time; + challenge->adr = from; + challenge->firstTime = svs.time; + challenge->time = svs.time; + challenge->connected = qfalse; + i = oldest; + } + + // if they are on a lan address, send the challengeResponse immediately + if ( Sys_IsLANAddress( from ) ) { + challenge->pingTime = svs.time; + NET_OutOfBandPrint( NS_SERVER, from, "challengeResponse %i", challenge->challenge ); + return; + } + +#ifdef USE_CD_KEY + // look up the authorize server's IP + if ( !svs.authorizeAddress.ip[0] && svs.authorizeAddress.type != NA_BAD ) { + Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME ); + if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &svs.authorizeAddress ) ) { + Com_Printf( "Couldn't resolve address\n" ); + return; + } + svs.authorizeAddress.port = BigShort( PORT_AUTHORIZE ); + Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME, + svs.authorizeAddress.ip[0], svs.authorizeAddress.ip[1], + svs.authorizeAddress.ip[2], svs.authorizeAddress.ip[3], + BigShort( svs.authorizeAddress.port ) ); + } + + // if they have been challenging for a long time and we + // haven't heard anything from the authoirze server, go ahead and + // let them in, assuming the id server is down + if ( svs.time - challenge->firstTime > AUTHORIZE_TIMEOUT ) { + Com_DPrintf( "authorize server timed out\n" ); + + challenge->pingTime = svs.time; + NET_OutOfBandPrint( NS_SERVER, challenge->adr, + "challengeResponse %i", challenge->challenge ); + return; + } + + // otherwise send their ip to the authorize server + if ( svs.authorizeAddress.type != NA_BAD ) { + cvar_t *fs; + char game[1024]; + + game[0] = 0; + fs = Cvar_Get ("fs_game", "", CVAR_INIT|CVAR_SYSTEMINFO ); + if (fs && fs->string[0] != 0) { + strcpy(game, fs->string); + } + Com_DPrintf( "sending getIpAuthorize for %s\n", NET_AdrToString( from )); + fs = Cvar_Get ("sv_allowAnonymous", "0", CVAR_SERVERINFO); + + NET_OutOfBandPrint( NS_SERVER, svs.authorizeAddress, + "getIpAuthorize %i %i.%i.%i.%i %s %s", svs.challenges[i].challenge, + from.ip[0], from.ip[1], from.ip[2], from.ip[3], game, fs->integer ); + } +#else + challenge->pingTime = svs.time; + NET_OutOfBandPrint( NS_SERVER, challenge->adr, "challengeResponse %i", challenge->challenge ); +#endif // USE_CD_KEY +} + +/* +==================== +SV_AuthorizeIpPacket + +A packet has been returned from the authorize server. +If we have a challenge adr for that ip, send the +challengeResponse to it +==================== +*/ +void SV_AuthorizeIpPacket( netadr_t from ) { + int challenge; + int i; + char *s; + char *r; + char ret[1024]; + + if ( !NET_CompareBaseAdr( from, svs.authorizeAddress ) ) { + Com_Printf( "SV_AuthorizeIpPacket: not from authorize server\n" ); + return; + } + + challenge = atoi( Cmd_Argv( 1 ) ); + + for (i = 0 ; i < MAX_CHALLENGES ; i++) { + if ( svs.challenges[i].challenge == challenge ) { + break; + } + } + if ( i == MAX_CHALLENGES ) { + Com_Printf( "SV_AuthorizeIpPacket: challenge not found\n" ); + return; + } + + // send a packet back to the original client + svs.challenges[i].pingTime = svs.time; + s = Cmd_Argv( 2 ); + r = Cmd_Argv( 3 ); // reason + + if ( !Q_stricmp( s, "demo" ) ) { + if ( Cvar_VariableValue( "fs_restrict" ) ) { + // a demo client connecting to a demo server + NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, + "challengeResponse %i", svs.challenges[i].challenge ); + return; + } + // they are a demo client trying to connect to a real server + NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nServer is not a demo server\n" ); + // clear the challenge record so it won't timeout and let them through + Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) ); + return; + } + if ( !Q_stricmp( s, "accept" ) ) { + NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, + "challengeResponse %i", svs.challenges[i].challenge ); + return; + } + if ( !Q_stricmp( s, "unknown" ) ) { + if (!r) { + NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nAwaiting CD key authorization\n" ); + } else { + sprintf(ret, "print\n%s\n", r); + NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, ret ); + } + // clear the challenge record so it won't timeout and let them through + Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) ); + return; + } + + // authorization failed + if (!r) { + NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "print\nSomeone is using this CD Key\n" ); + } else { + sprintf(ret, "print\n%s\n", r); + NET_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, ret ); + } + + // clear the challenge record so it won't timeout and let them through + Com_Memset( &svs.challenges[i], 0, sizeof( svs.challenges[i] ) ); +} + +/* +================== +SV_DirectConnect + +A "connect" OOB command has been received +================== +*/ +void SV_DirectConnect( netadr_t from ) { + char userinfo[MAX_INFO_STRING]; + int i; + client_t *cl, *newcl; + MAC_STATIC client_t temp; + sharedEntity_t *ent; + int clientNum; + int version; + int qport; + int challenge; + char *password; + int startIndex; + char *denied; + int count; + + Com_DPrintf ("SVC_DirectConnect ()\n"); + + Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) ); + + version = atoi( Info_ValueForKey( userinfo, "protocol" ) ); + if ( version != PROTOCOL_VERSION ) { + NET_OutOfBandPrint( NS_SERVER, from, "print\nServer uses protocol version %i.\n", PROTOCOL_VERSION ); + Com_DPrintf (" rejected connect from version %i\n", version); + return; + } + + challenge = atoi( Info_ValueForKey( userinfo, "challenge" ) ); + qport = atoi( Info_ValueForKey( userinfo, "qport" ) ); + + // quick reject + for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) { + if ( cl->state == CS_FREE ) { + continue; + } + if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) + && ( cl->netchan.qport == qport + || from.port == cl->netchan.remoteAddress.port ) ) { + if (( svs.time - cl->lastConnectTime) + < (sv_reconnectlimit->integer * 1000)) { + Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (from)); + return; + } + break; + } + } + + // see if the challenge is valid (LAN clients don't need to challenge) + if ( !NET_IsLocalAddress (from) ) { + int ping; + + for (i=0 ; ivalue && ping < sv_minPing->value ) { + // don't let them keep trying until they get a big delay + NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for high pings only\n" ); + Com_DPrintf ("Client %i rejected on a too low ping\n", i); + // reset the address otherwise their ping will keep increasing + // with each connect message and they'd eventually be able to connect + svs.challenges[i].adr.port = 0; + return; + } + if ( sv_maxPing->value && ping > sv_maxPing->value ) { + NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for low pings only\n" ); + Com_DPrintf ("Client %i rejected on a too high ping\n", i); + return; + } + } + } else { + // force the "ip" info key to "localhost" + Info_SetValueForKey( userinfo, "ip", "localhost" ); + } + + newcl = &temp; + Com_Memset (newcl, 0, sizeof(client_t)); + + // if there is already a slot for this ip, reuse it + for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) { + if ( cl->state == CS_FREE ) { + continue; + } + if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) + && ( cl->netchan.qport == qport + || from.port == cl->netchan.remoteAddress.port ) ) { + Com_Printf ("%s:reconnect\n", NET_AdrToString (from)); + newcl = cl; + // disconnect the client from the game first so any flags the + // player might have are dropped + VM_Call( gvm, GAME_CLIENT_DISCONNECT, newcl - svs.clients ); + // + goto gotnewcl; + } + } + + // find a client slot + // if "sv_privateClients" is set > 0, then that number + // of client slots will be reserved for connections that + // have "password" set to the value of "sv_privatePassword" + // Info requests will report the maxclients as if the private + // slots didn't exist, to prevent people from trying to connect + // to a full server. + // This is to allow us to reserve a couple slots here on our + // servers so we can play without having to kick people. + + // check for privateClient password + password = Info_ValueForKey( userinfo, "password" ); + if ( !strcmp( password, sv_privatePassword->string ) ) { + startIndex = 0; + } else { + // skip past the reserved slots + startIndex = sv_privateClients->integer; + } + + newcl = NULL; + for ( i = startIndex; i < sv_maxclients->integer ; i++ ) { + cl = &svs.clients[i]; + if (cl->state == CS_FREE) { + newcl = cl; + break; + } + } + + if ( !newcl ) { + if ( NET_IsLocalAddress( from ) ) { + count = 0; + for ( i = startIndex; i < sv_maxclients->integer ; i++ ) { + cl = &svs.clients[i]; + if (cl->netchan.remoteAddress.type == NA_BOT) { + count++; + } + } + // if they're all bots + if (count >= sv_maxclients->integer - startIndex) { + SV_DropClient(&svs.clients[sv_maxclients->integer - 1], "only bots on server"); + newcl = &svs.clients[sv_maxclients->integer - 1]; + } + else { + Com_Error( ERR_FATAL, "server is full on local connect\n" ); + return; + } + } + else { + NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is full.\n" ); + Com_DPrintf ("Rejected a connection.\n"); + return; + } + } + + // we got a newcl, so reset the reliableSequence and reliableAcknowledge + cl->reliableAcknowledge = 0; + cl->reliableSequence = 0; + +gotnewcl: + // build a new connection + // accept the new client + // this is the only place a client_t is ever initialized + *newcl = temp; + clientNum = newcl - svs.clients; + ent = SV_GentityNum( clientNum ); + newcl->gentity = ent; + + // save the challenge + newcl->challenge = challenge; + + // save the address + Netchan_Setup (NS_SERVER, &newcl->netchan , from, qport); + + // save the userinfo + Q_strncpyz( newcl->userinfo, userinfo, sizeof(newcl->userinfo) ); + + // get the game a chance to reject this connection or modify the userinfo + denied = (char *)VM_Call( gvm, GAME_CLIENT_CONNECT, clientNum, qtrue, qfalse ); // firstTime = qtrue + if ( denied ) { + // we can't just use VM_ArgPtr, because that is only valid inside a VM_Call + denied = (char *)VM_ExplicitArgPtr( gvm, (int)denied ); + + NET_OutOfBandPrint( NS_SERVER, from, "print\n%s\n", denied ); + Com_DPrintf ("Game rejected a connection: %s.\n", denied); + return; + } + + SV_UserinfoChanged( newcl ); + + // send the connect packet to the client + NET_OutOfBandPrint( NS_SERVER, from, "connectResponse" ); + + Com_DPrintf( "Going from CS_FREE to CS_CONNECTED for %s\n", newcl->name ); + + newcl->state = CS_CONNECTED; + newcl->nextSnapshotTime = svs.time; + newcl->lastPacketTime = svs.time; + newcl->lastConnectTime = svs.time; + + // when we receive the first packet from the client, we will + // notice that it is from a different serverid and that the + // gamestate message was not just sent, forcing a retransmit + newcl->gamestateMessageNum = -1; + + // if this was the first client on the server, or the last client + // the server can hold, send a heartbeat to the master. + count = 0; + for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) { + if ( svs.clients[i].state >= CS_CONNECTED ) { + count++; + } + } + if ( count == 1 || count == sv_maxclients->integer ) { + SV_Heartbeat_f(); + } +} + + +/* +===================== +SV_DropClient + +Called when the player is totally leaving the server, either willingly +or unwillingly. This is NOT called if the entire server is quiting +or crashing -- SV_FinalMessage() will handle that +===================== +*/ +void SV_DropClient( client_t *drop, const char *reason ) { + int i; + challenge_t *challenge; + + if ( drop->state == CS_ZOMBIE ) { + return; // already dropped + } + + if ( !drop->gentity || !(drop->gentity->r.svFlags & SVF_BOT) ) { + // see if we already have a challenge for this ip + challenge = &svs.challenges[0]; + + for (i = 0 ; i < MAX_CHALLENGES ; i++, challenge++) { + if ( NET_CompareAdr( drop->netchan.remoteAddress, challenge->adr ) ) { + challenge->connected = qfalse; + break; + } + } + } + + // Kill any download + SV_CloseDownload( drop ); + + // tell everyone why they got dropped + SV_SendServerCommand( NULL, "print \"%s" S_COLOR_WHITE " %s\n\"", drop->name, reason ); + + Com_DPrintf( "Going to CS_ZOMBIE for %s\n", drop->name ); + drop->state = CS_ZOMBIE; // become free in a few seconds + + if (drop->download) { + FS_FCloseFile( drop->download ); + drop->download = 0; + } + + // call the prog function for removing a client + // this will remove the body, among other things + VM_Call( gvm, GAME_CLIENT_DISCONNECT, drop - svs.clients ); + + // add the disconnect command + SV_SendServerCommand( drop, "disconnect" ); + + if ( drop->netchan.remoteAddress.type == NA_BOT ) { + SV_BotFreeClient( drop - svs.clients ); + } + + // nuke user info + SV_SetUserinfo( drop - svs.clients, "" ); + + // if this was the last client on the server, send a heartbeat + // to the master so it is known the server is empty + // send a heartbeat now so the master will get up to date info + // if there is already a slot for this ip, reuse it + for (i=0 ; i < sv_maxclients->integer ; i++ ) { + if ( svs.clients[i].state >= CS_CONNECTED ) { + break; + } + } + if ( i == sv_maxclients->integer ) { + SV_Heartbeat_f(); + } +} + +/* +================ +SV_SendClientGameState + +Sends the first message from the server to a connected client. +This will be sent on the initial connection and upon each new map load. + +It will be resent if the client acknowledges a later message but has +the wrong gamestate. +================ +*/ +void SV_SendClientGameState( client_t *client ) { + int start; + entityState_t *base, nullstate; + msg_t msg; + byte msgBuffer[MAX_MSGLEN]; + + Com_DPrintf ("SV_SendClientGameState() for %s\n", client->name); + Com_DPrintf( "Going from CS_CONNECTED to CS_PRIMED for %s\n", client->name ); + client->state = CS_PRIMED; + client->pureAuthentic = 0; + + // when we receive the first packet from the client, we will + // notice that it is from a different serverid and that the + // gamestate message was not just sent, forcing a retransmit + client->gamestateMessageNum = client->netchan.outgoingSequence; + + MSG_Init( &msg, msgBuffer, sizeof( msgBuffer ) ); + + // NOTE, MRE: all server->client messages now acknowledge + // let the client know which reliable clientCommands we have received + MSG_WriteLong( &msg, client->lastClientCommand ); + + // send any server commands waiting to be sent first. + // we have to do this cause we send the client->reliableSequence + // with a gamestate and it sets the clc.serverCommandSequence at + // the client side + SV_UpdateServerCommandsToClient( client, &msg ); + + // send the gamestate + MSG_WriteByte( &msg, svc_gamestate ); + MSG_WriteLong( &msg, client->reliableSequence ); + + // write the configstrings + for ( start = 0 ; start < MAX_CONFIGSTRINGS ; start++ ) { + if (sv.configstrings[start][0]) { + MSG_WriteByte( &msg, svc_configstring ); + MSG_WriteShort( &msg, start ); + MSG_WriteBigString( &msg, sv.configstrings[start] ); + } + } + + // write the baselines + Com_Memset( &nullstate, 0, sizeof( nullstate ) ); + for ( start = 0 ; start < MAX_GENTITIES; start++ ) { + base = &sv.svEntities[start].baseline; + if ( !base->number ) { + continue; + } + MSG_WriteByte( &msg, svc_baseline ); + MSG_WriteDeltaEntity( &msg, &nullstate, base, qtrue ); + } + + MSG_WriteByte( &msg, svc_EOF ); + + MSG_WriteLong( &msg, client - svs.clients); + + // write the checksum feed + MSG_WriteLong( &msg, sv.checksumFeed); + + // deliver this to the client + SV_SendMessageToClient( &msg, client ); +} + + +/* +================== +SV_ClientEnterWorld +================== +*/ +void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ) { + int clientNum; + sharedEntity_t *ent; + + Com_DPrintf( "Going from CS_PRIMED to CS_ACTIVE for %s\n", client->name ); + client->state = CS_ACTIVE; + + // set up the entity for the client + clientNum = client - svs.clients; + ent = SV_GentityNum( clientNum ); + ent->s.number = clientNum; + client->gentity = ent; + + client->deltaMessage = -1; + client->nextSnapshotTime = svs.time; // generate a snapshot immediately + client->lastUsercmd = *cmd; + + // call the game begin function + VM_Call( gvm, GAME_CLIENT_BEGIN, client - svs.clients ); +} + +/* +============================================================ + +CLIENT COMMAND EXECUTION + +============================================================ +*/ + +/* +================== +SV_CloseDownload + +clear/free any download vars +================== +*/ +static void SV_CloseDownload( client_t *cl ) { + int i; + + // EOF + if (cl->download) { + FS_FCloseFile( cl->download ); + } + cl->download = 0; + *cl->downloadName = 0; + + // Free the temporary buffer space + for (i = 0; i < MAX_DOWNLOAD_WINDOW; i++) { + if (cl->downloadBlocks[i]) { + Z_Free( cl->downloadBlocks[i] ); + cl->downloadBlocks[i] = NULL; + } + } + +} + +/* +================== +SV_StopDownload_f + +Abort a download if in progress +================== +*/ +void SV_StopDownload_f( client_t *cl ) { + if (*cl->downloadName) + Com_DPrintf( "clientDownload: %d : file \"%s\" aborted\n", cl - svs.clients, cl->downloadName ); + + SV_CloseDownload( cl ); +} + +/* +================== +SV_DoneDownload_f + +Downloads are finished +================== +*/ +void SV_DoneDownload_f( client_t *cl ) { + Com_DPrintf( "clientDownload: %s Done\n", cl->name); + // resend the game state to update any clients that entered during the download + SV_SendClientGameState(cl); +} + +/* +================== +SV_NextDownload_f + +The argument will be the last acknowledged block from the client, it should be +the same as cl->downloadClientBlock +================== +*/ +void SV_NextDownload_f( client_t *cl ) +{ + int block = atoi( Cmd_Argv(1) ); + + if (block == cl->downloadClientBlock) { + Com_DPrintf( "clientDownload: %d : client acknowledge of block %d\n", cl - svs.clients, block ); + + // Find out if we are done. A zero-length block indicates EOF + if (cl->downloadBlockSize[cl->downloadClientBlock % MAX_DOWNLOAD_WINDOW] == 0) { + Com_Printf( "clientDownload: %d : file \"%s\" completed\n", cl - svs.clients, cl->downloadName ); + SV_CloseDownload( cl ); + return; + } + + cl->downloadSendTime = svs.time; + cl->downloadClientBlock++; + return; + } + // We aren't getting an acknowledge for the correct block, drop the client + // FIXME: this is bad... the client will never parse the disconnect message + // because the cgame isn't loaded yet + SV_DropClient( cl, "broken download" ); +} + +/* +================== +SV_BeginDownload_f +================== +*/ +void SV_BeginDownload_f( client_t *cl ) { + + // Kill any existing download + SV_CloseDownload( cl ); + + // cl->downloadName is non-zero now, SV_WriteDownloadToClient will see this and open + // the file itself + Q_strncpyz( cl->downloadName, Cmd_Argv(1), sizeof(cl->downloadName) ); +} + +/* +================== +SV_WriteDownloadToClient + +Check to see if the client wants a file, open it if needed and start pumping the client +Fill up msg with data +================== +*/ +void SV_WriteDownloadToClient( client_t *cl , msg_t *msg ) +{ + int curindex; + int rate; + int blockspersnap; + int idPack, missionPack; + char errorMessage[1024]; + + if (!*cl->downloadName) + return; // Nothing being downloaded + + if (!cl->download) { + // We open the file here + + Com_Printf( "clientDownload: %d : begining \"%s\"\n", cl - svs.clients, cl->downloadName ); + + missionPack = FS_idPak(cl->downloadName, "missionpack"); + idPack = missionPack || FS_idPak(cl->downloadName, "base"); + + if ( !sv_allowDownload->integer || idPack || + ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) <= 0 ) { + // cannot auto-download file + if (idPack) { + Com_Printf("clientDownload: %d : \"%s\" cannot download id pk3 files\n", cl - svs.clients, cl->downloadName); + if (missionPack) { + Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload Team Arena file \"%s\"\n" + "The Team Arena mission pack can be found in your local game store.", cl->downloadName); + } + else { + Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload id pk3 file \"%s\"", cl->downloadName); + } + } else if ( !sv_allowDownload->integer ) { + Com_Printf("clientDownload: %d : \"%s\" download disabled", cl - svs.clients, cl->downloadName); + if (sv_pure->integer) { + Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" + "You will need to get this file elsewhere before you " + "can connect to this pure server.\n", cl->downloadName); + } else { + Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" + "Set autodownload to No in your settings and you might be " + "able to connect if you do have the file.\n", cl->downloadName); + } + } else { + Com_Printf("clientDownload: %d : \"%s\" file not found on server\n", cl - svs.clients, cl->downloadName); + Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" not found on server for autodownloading.\n", cl->downloadName); + } + MSG_WriteByte( msg, svc_download ); + MSG_WriteShort( msg, 0 ); // client is expecting block zero + MSG_WriteLong( msg, -1 ); // illegal file size + MSG_WriteString( msg, errorMessage ); + + *cl->downloadName = 0; + return; + } + + // Init + cl->downloadCurrentBlock = cl->downloadClientBlock = cl->downloadXmitBlock = 0; + cl->downloadCount = 0; + cl->downloadEOF = qfalse; + } + + // Perform any reads that we need to + while (cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW && + cl->downloadSize != cl->downloadCount) { + + curindex = (cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW); + + if (!cl->downloadBlocks[curindex]) + cl->downloadBlocks[curindex] = (unsigned char *)Z_Malloc( MAX_DOWNLOAD_BLKSIZE, TAG_DOWNLOAD, qtrue ); + + cl->downloadBlockSize[curindex] = FS_Read( cl->downloadBlocks[curindex], MAX_DOWNLOAD_BLKSIZE, cl->download ); + + if (cl->downloadBlockSize[curindex] < 0) { + // EOF right now + cl->downloadCount = cl->downloadSize; + break; + } + + cl->downloadCount += cl->downloadBlockSize[curindex]; + + // Load in next block + cl->downloadCurrentBlock++; + } + + // Check to see if we have eof condition and add the EOF block + if (cl->downloadCount == cl->downloadSize && + !cl->downloadEOF && + cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW) { + + cl->downloadBlockSize[cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW] = 0; + cl->downloadCurrentBlock++; + + cl->downloadEOF = qtrue; // We have added the EOF block + } + + // Loop up to window size times based on how many blocks we can fit in the + // client snapMsec and rate + + // based on the rate, how many bytes can we fit in the snapMsec time of the client + // normal rate / snapshotMsec calculation + rate = cl->rate; + if ( sv_maxRate->integer ) { + if ( sv_maxRate->integer < 1000 ) { + Cvar_Set( "sv_MaxRate", "1000" ); + } + if ( sv_maxRate->integer < rate ) { + rate = sv_maxRate->integer; + } + } + + if (!rate) { + blockspersnap = 1; + } else { + blockspersnap = ( (rate * cl->snapshotMsec) / 1000 + MAX_DOWNLOAD_BLKSIZE ) / + MAX_DOWNLOAD_BLKSIZE; + } + + if (blockspersnap < 0) + blockspersnap = 1; + + while (blockspersnap--) { + + // Write out the next section of the file, if we have already reached our window, + // automatically start retransmitting + + if (cl->downloadClientBlock == cl->downloadCurrentBlock) + return; // Nothing to transmit + + if (cl->downloadXmitBlock == cl->downloadCurrentBlock) { + // We have transmitted the complete window, should we start resending? + + //FIXME: This uses a hardcoded one second timeout for lost blocks + //the timeout should be based on client rate somehow + if (svs.time - cl->downloadSendTime > 1000) + cl->downloadXmitBlock = cl->downloadClientBlock; + else + return; + } + + // Send current block + curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW); + + MSG_WriteByte( msg, svc_download ); + MSG_WriteShort( msg, cl->downloadXmitBlock ); + + // block zero is special, contains file size + if ( cl->downloadXmitBlock == 0 ) + MSG_WriteLong( msg, cl->downloadSize ); + + MSG_WriteShort( msg, cl->downloadBlockSize[curindex] ); + + // Write the block + if ( cl->downloadBlockSize[curindex] ) { + MSG_WriteData( msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex] ); + } + + Com_DPrintf( "clientDownload: %d : writing block %d\n", cl - svs.clients, cl->downloadXmitBlock ); + + // Move on to the next block + // It will get sent with next snap shot. The rate will keep us in line. + cl->downloadXmitBlock++; + + cl->downloadSendTime = svs.time; + } +} + +/* +================= +SV_Disconnect_f + +The client is going to disconnect, so remove the connection immediately FIXME: move to game? +================= +*/ +static void SV_Disconnect_f( client_t *cl ) { + SV_DropClient( cl, "disconnected" ); +} + +/* +================= +SV_VerifyPaks_f + +If we are pure, disconnect the client if they do no meet the following conditions: + +1. the first two checksums match our view of cgame and ui +2. there are no any additional checksums that we do not have + +This routine would be a bit simpler with a goto but i abstained + +================= +*/ +static void SV_VerifyPaks_f( client_t *cl ) { + int nChkSum1, nChkSum2, nClientPaks, nServerPaks, i, j, nCurArg; + int nClientChkSum[1024]; + int nServerChkSum[1024]; + const char *pPaks, *pArg; + qboolean bGood = qtrue; + + // if we are pure, we "expect" the client to load certain things from + // certain pk3 files, namely we want the client to have loaded the + // ui and cgame that we think should be loaded based on the pure setting + // + if ( sv_pure->integer != 0 ) { + + bGood = qtrue; + nChkSum1 = nChkSum2 = 0; + // we run the game, so determine which cgame and ui the client "should" be running + bGood = (qboolean)(FS_FileIsInPAK("vm/cgame.qvm", &nChkSum1) == 1); + if (bGood) + bGood = (qboolean)(FS_FileIsInPAK("vm/ui.qvm", &nChkSum2) == 1); + + nClientPaks = Cmd_Argc(); + + // start at arg 1 ( skip cl_paks ) + nCurArg = 1; + + // we basically use this while loop to avoid using 'goto' :) + while (bGood) { + + // must be at least 6: "cl_paks cgame ui @ firstref ... numChecksums" + // numChecksums is encoded + if (nClientPaks < 6) { + bGood = qfalse; + break; + } + // verify first to be the cgame checksum + pArg = Cmd_Argv(nCurArg++); + if (!pArg || *pArg == '@' || atoi(pArg) != nChkSum1 ) { + bGood = qfalse; + break; + } + // verify the second to be the ui checksum + pArg = Cmd_Argv(nCurArg++); + if (!pArg || *pArg == '@' || atoi(pArg) != nChkSum2 ) { + bGood = qfalse; + break; + } + // should be sitting at the delimeter now + pArg = Cmd_Argv(nCurArg++); + if (*pArg != '@') { + bGood = qfalse; + break; + } + // store checksums since tokenization is not re-entrant + for (i = 0; nCurArg < nClientPaks; i++) { + nClientChkSum[i] = atoi(Cmd_Argv(nCurArg++)); + } + + // store number to compare against (minus one cause the last is the number of checksums) + nClientPaks = i - 1; + + // make sure none of the client check sums are the same + // so the client can't send 5 the same checksums + for (i = 0; i < nClientPaks; i++) { + for (j = 0; j < nClientPaks; j++) { + if (i == j) + continue; + if (nClientChkSum[i] == nClientChkSum[j]) { + bGood = qfalse; + break; + } + } + if (bGood == qfalse) + break; + } + if (bGood == qfalse) + break; + + // get the pure checksums of the pk3 files loaded by the server + pPaks = FS_LoadedPakPureChecksums(); + Cmd_TokenizeString( pPaks ); + nServerPaks = Cmd_Argc(); + if (nServerPaks > 1024) + nServerPaks = 1024; + + for (i = 0; i < nServerPaks; i++) { + nServerChkSum[i] = atoi(Cmd_Argv(i)); + } + + // check if the client has provided any pure checksums of pk3 files not loaded by the server + for (i = 0; i < nClientPaks; i++) { + for (j = 0; j < nServerPaks; j++) { + if (nClientChkSum[i] == nServerChkSum[j]) { + break; + } + } + if (j >= nServerPaks) { + bGood = qfalse; + break; + } + } + if ( bGood == qfalse ) { + break; + } + + // check if the number of checksums was correct + nChkSum1 = sv.checksumFeed; + for (i = 0; i < nClientPaks; i++) { + nChkSum1 ^= nClientChkSum[i]; + } + nChkSum1 ^= nClientPaks; + if (nChkSum1 != nClientChkSum[nClientPaks]) { + bGood = qfalse; + break; + } + + // break out + break; + } + + if (bGood) { + cl->pureAuthentic = 1; + } + else { + cl->pureAuthentic = 0; + cl->nextSnapshotTime = -1; + cl->state = CS_ACTIVE; + SV_SendClientSnapshot( cl ); + SV_DropClient( cl, "Unpure client detected. Invalid .PK3 files referenced!" ); + } + } +} + +/* +================= +SV_ResetPureClient_f +================= +*/ +static void SV_ResetPureClient_f( client_t *cl ) { + cl->pureAuthentic = 0; +} + +/* +================= +SV_UserinfoChanged + +Pull specific info from a newly changed userinfo string +into a more C friendly form. +================= +*/ +void SV_UserinfoChanged( client_t *cl ) { + char *val; + int i; + + // name for C code + Q_strncpyz( cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name) ); + + // rate command + + // if the client is on the same subnet as the server and we aren't running an + // internet public server, assume they don't need a rate choke + if ( Sys_IsLANAddress( cl->netchan.remoteAddress ) && com_dedicated->integer != 2 ) { + cl->rate = 99999; // lans should not rate limit + } else { + val = Info_ValueForKey (cl->userinfo, "rate"); + if (strlen(val)) { + i = atoi(val); + cl->rate = i; + if (cl->rate < 1000) { + cl->rate = 1000; + } else if (cl->rate > 90000) { + cl->rate = 90000; + } + } else { + cl->rate = 3000; + } + } + val = Info_ValueForKey (cl->userinfo, "handicap"); + if (strlen(val)) { + i = atoi(val); + if (i<=0 || i>100 || strlen(val) > 4) { + Info_SetValueForKey( cl->userinfo, "handicap", "100" ); + } + } + + // snaps command + val = Info_ValueForKey (cl->userinfo, "snaps"); + if (strlen(val)) { + i = atoi(val); + if ( i < 1 ) { + i = 1; + } else if ( i > 30 ) { + i = 30; + } + cl->snapshotMsec = 1000/i; + } else { + cl->snapshotMsec = 50; + } +} + + +/* +================== +SV_UpdateUserinfo_f +================== +*/ +static void SV_UpdateUserinfo_f( client_t *cl ) { + Q_strncpyz( cl->userinfo, Cmd_Argv(1), sizeof(cl->userinfo) ); + + SV_UserinfoChanged( cl ); + // call prog code to allow overrides + VM_Call( gvm, GAME_CLIENT_USERINFO_CHANGED, cl - svs.clients ); +} + +typedef struct { + char *name; + void (*func)( client_t *cl ); +} ucmd_t; + +static ucmd_t ucmds[] = { + {"userinfo", SV_UpdateUserinfo_f}, + {"disconnect", SV_Disconnect_f}, + {"cp", SV_VerifyPaks_f}, + {"vdr", SV_ResetPureClient_f}, + {"download", SV_BeginDownload_f}, + {"nextdl", SV_NextDownload_f}, + {"stopdl", SV_StopDownload_f}, + {"donedl", SV_DoneDownload_f}, + + {NULL, NULL} +}; + +/* +================== +SV_ExecuteClientCommand + +Also called by bot code +================== +*/ +void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK ) { + ucmd_t *u; + + Cmd_TokenizeString( s ); + + // see if it is a server level command + for (u=ucmds ; u->name ; u++) { + if (!strcmp (Cmd_Argv(0), u->name) ) { + u->func( cl ); + break; + } + } + + if (clientOK) { + // pass unknown strings to the game + if (!u->name && sv.state == SS_GAME) { + VM_Call( gvm, GAME_CLIENT_COMMAND, cl - svs.clients ); + } + } +} + +/* +=============== +SV_ClientCommand +=============== +*/ +static qboolean SV_ClientCommand( client_t *cl, msg_t *msg ) { + int seq; + const char *s; + qboolean clientOk = qtrue; + + seq = MSG_ReadLong( msg ); + s = MSG_ReadString( msg ); + + // see if we have already executed it + if ( cl->lastClientCommand >= seq ) { + return qtrue; + } + + Com_DPrintf( "clientCommand: %s : %i : %s\n", cl->name, seq, s ); + + // drop the connection if we have somehow lost commands + if ( seq > cl->lastClientCommand + 1 ) { + Com_Printf( "Client %s lost %i clientCommands\n", cl->name, + seq - cl->lastClientCommand + 1 ); + SV_DropClient( cl, "Lost reliable commands" ); + return qfalse; + } + + // malicious users may try using too many string commands + // to lag other players. If we decide that we want to stall + // the command, we will stop processing the rest of the packet, + // including the usercmd. This causes flooders to lag themselves + // but not other people + // We don't do this when the client hasn't been active yet since its + // normal to spam a lot of commands when downloading + if ( !com_cl_running->integer && + cl->state >= CS_ACTIVE && + sv_floodProtect->integer && + svs.time < cl->nextReliableTime ) { + // ignore any other text messages from this client but let them keep playing + clientOk = qfalse; + Com_DPrintf( "client text ignored for %s\n", cl->name ); + //return qfalse; // stop processing + } + + // don't allow another command for one second + cl->nextReliableTime = svs.time + 1000; + + SV_ExecuteClientCommand( cl, s, clientOk ); + + cl->lastClientCommand = seq; + Com_sprintf(cl->lastClientCommandString, sizeof(cl->lastClientCommandString), "%s", s); + + return qtrue; // continue procesing +} + + +//================================================================================== + + +/* +================== +SV_ClientThink + +Also called by bot code +================== +*/ +void SV_ClientThink (client_t *cl, usercmd_t *cmd) { + cl->lastUsercmd = *cmd; + + if ( cl->state != CS_ACTIVE ) { + return; // may have been kicked during the last usercmd + } + + VM_Call( gvm, GAME_CLIENT_THINK, cl - svs.clients ); +} + +/* +================== +SV_UserMove + +The message usually contains all the movement commands +that were in the last three packets, so that the information +in dropped packets can be recovered. + +On very fast clients, there may be multiple usercmd packed into +each of the backup packets. +================== +*/ +static void SV_UserMove( client_t *cl, msg_t *msg, qboolean delta ) { + int i, key; + int cmdCount; + usercmd_t nullcmd; + usercmd_t cmds[MAX_PACKET_USERCMDS]; + usercmd_t *cmd, *oldcmd; + + if ( delta ) { + cl->deltaMessage = cl->messageAcknowledge; + } else { + cl->deltaMessage = -1; + } + + cmdCount = MSG_ReadByte( msg ); + + if ( cmdCount < 1 ) { + Com_Printf( "cmdCount < 1\n" ); + return; + } + + if ( cmdCount > MAX_PACKET_USERCMDS ) { + Com_Printf( "cmdCount > MAX_PACKET_USERCMDS\n" ); + return; + } + + // use the checksum feed in the key + key = sv.checksumFeed; + // also use the message acknowledge + key ^= cl->messageAcknowledge; + // also use the last acknowledged server command in the key + key ^= Com_HashKey(cl->reliableCommands[ cl->reliableAcknowledge & (MAX_RELIABLE_COMMANDS-1) ], 32); + + Com_Memset( &nullcmd, 0, sizeof(nullcmd) ); + oldcmd = &nullcmd; + for ( i = 0 ; i < cmdCount ; i++ ) { + cmd = &cmds[i]; + MSG_ReadDeltaUsercmdKey( msg, key, oldcmd, cmd ); + oldcmd = cmd; + } + + // save time for ping calculation + cl->frames[ cl->messageAcknowledge & PACKET_MASK ].messageAcked = svs.time; + + // if this is the first usercmd we have received + // this gamestate, put the client into the world + if ( cl->state == CS_PRIMED ) { + SV_ClientEnterWorld( cl, &cmds[0] ); + // the moves can be processed normaly + } + // + if (sv_pure->integer != 0 && cl->pureAuthentic == 0) { + SV_DropClient( cl, "Cannot validate pure client!"); + return; + } + + if ( cl->state != CS_ACTIVE ) { + cl->deltaMessage = -1; + return; + } + + // usually, the first couple commands will be duplicates + // of ones we have previously received, but the servertimes + // in the commands will cause them to be immediately discarded + for ( i = 0 ; i < cmdCount ; i++ ) { + // if this is a cmd from before a map_restart ignore it + if ( cmds[i].serverTime > cmds[cmdCount-1].serverTime ) { + continue; + } + // extremely lagged or cmd from before a map_restart + //if ( cmds[i].serverTime > svs.time + 3000 ) { + // continue; + //} + // don't execute if this is an old cmd which is already executed + // these old cmds are included when cl_packetdup > 0 + if ( cmds[i].serverTime <= cl->lastUsercmd.serverTime ) { + continue; + } + SV_ClientThink (cl, &cmds[ i ]); + } +} + + +/* +=========================================================================== + +USER CMD EXECUTION + +=========================================================================== +*/ + +/* +=================== +SV_ExecuteClientMessage + +Parse a client packet +=================== +*/ +void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ) { + int c; + int serverId; + + MSG_Bitstream(msg); + + serverId = MSG_ReadLong( msg ); + cl->messageAcknowledge = MSG_ReadLong( msg ); + + if (cl->messageAcknowledge < 0) { + // usually only hackers create messages like this + // it is more annoying for them to let them hanging + //SV_DropClient( cl, "illegible client message" ); + return; + } + + cl->reliableAcknowledge = MSG_ReadLong( msg ); + + // NOTE: when the client message is fux0red the acknowledgement numbers + // can be out of range, this could cause the server to send thousands of server + // commands which the server thinks are not yet acknowledged in SV_UpdateServerCommandsToClient + if (cl->reliableAcknowledge < cl->reliableSequence - MAX_RELIABLE_COMMANDS) { + // usually only hackers create messages like this + // it is more annoying for them to let them hanging + //SV_DropClient( cl, "illegible client message" ); + cl->reliableAcknowledge = cl->reliableSequence; + return; + } + // if this is a usercmd from a previous gamestate, + // ignore it or retransmit the current gamestate + // + // if the client was downloading, let it stay at whatever serverId and + // gamestate it was at. This allows it to keep downloading even when + // the gamestate changes. After the download is finished, we'll + // notice and send it a new game state + if ( serverId != sv.serverId && + !*cl->downloadName ) { + if ( serverId == sv.restartedServerId ) { + // they just haven't caught the map_restart yet + return; + } + // if we can tell that the client has dropped the last + // gamestate we sent them, resend it + if ( cl->messageAcknowledge > cl->gamestateMessageNum ) { + Com_DPrintf( "%s : dropped gamestate, resending\n", cl->name ); + SV_SendClientGameState( cl ); + } + return; + } + + // read optional clientCommand strings + do { + c = MSG_ReadByte( msg ); + if ( c == clc_EOF ) { + break; + } + if ( c != clc_clientCommand ) { + break; + } + if ( !SV_ClientCommand( cl, msg ) ) { + return; // we couldn't execute it because of the flood protection + } + if (cl->state == CS_ZOMBIE) { + return; // disconnect command + } + } while ( 1 ); + + // read the usercmd_t + if ( c == clc_move ) { + SV_UserMove( cl, msg, qtrue ); + } else if ( c == clc_moveNoDelta ) { + SV_UserMove( cl, msg, qfalse ); + } else if ( c != clc_EOF ) { + Com_Printf( "WARNING: bad command byte for client %i\n", cl - svs.clients ); + } +// if ( msg->readcount != msg->cursize ) { +// Com_Printf( "WARNING: Junk at end of packet for client %i\n", cl - svs.clients ); +// } +} + diff --git a/CODE-mp/server/sv_game.cpp b/CODE-mp/server/sv_game.cpp index 8bbaf94..ff0288e 100644 --- a/CODE-mp/server/sv_game.cpp +++ b/CODE-mp/server/sv_game.cpp @@ -299,6 +299,8 @@ The module is making a system call #define VMF(x) ((float *)args)[x] +extern bool RicksCrazyOnServer; + int SV_GameSystemCalls( int *args ) { switch( args[0] ) { case G_PRINT: @@ -447,8 +449,7 @@ int SV_GameSystemCalls( int *args ) { return 0; case SP_REGISTER_SERVER_CMD: - SP_RegisterServer( (const char *)VMA(1) ); - return 0; + return SP_RegisterServer( (const char *)VMA(1) ); case SP_GETSTRINGTEXTSTRING: //return (int)SP_GetStringTextString((char *)VMA(1)); const char* text; @@ -931,6 +932,7 @@ int SV_GameSystemCalls( int *args ) { return G2API_GetBoltMatrix(*((CGhoul2Info_v *)args[1]), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); case G_G2_INITGHOUL2MODEL: + RicksCrazyOnServer=true; return G2API_InitGhoul2Model((CGhoul2Info_v **)VMA(1), (const char *)VMA(2), args[3], (qhandle_t) args[4], (qhandle_t) args[5], args[6], args[7]); @@ -1078,6 +1080,11 @@ void SV_InitGameProgs( void ) { bot_enable = 0; } + if ( !Cvar_VariableValue("fs_restrict") && !Sys_CheckCD() ) + { + Com_Error( ERR_NEED_CD, SP_GetStringTextString("CON_TEXT_NEED_CD") ); //"Game CD not in drive" ); + } + // load the dll or bytecode gvm = VM_Create( "jk2mpgame", SV_GameSystemCalls, (vmInterpret_t)(int)Cvar_VariableValue( "vm_game" ) ); if ( !gvm ) { diff --git a/CODE-mp/server/sv_game.org b/CODE-mp/server/sv_game.org new file mode 100644 index 0000000..8bbaf94 --- /dev/null +++ b/CODE-mp/server/sv_game.org @@ -0,0 +1,1105 @@ +// sv_game.c -- interface to the game dll + +#include "server.h" + +#include "../game/botlib.h" +#include "../qcommon/strip.h" + +#if !defined(CROFFSYSTEM_H_INC) + #include "../qcommon/ROFFSystem.h" +#endif + +#if !defined(G2_H_INC) + #include "../ghoul2/G2_local.h" +#endif + +botlib_export_t *botlib_export; + +void SV_GameError( const char *string ) { + Com_Error( ERR_DROP, "%s", string ); +} + +void SV_GamePrint( const char *string ) { + Com_Printf( "%s", string ); +} + +// these functions must be used instead of pointer arithmetic, because +// the game allocates gentities with private information after the server shared part +int SV_NumForGentity( sharedEntity_t *ent ) { + int num; + + num = ( (byte *)ent - (byte *)sv.gentities ) / sv.gentitySize; + + return num; +} + +sharedEntity_t *SV_GentityNum( int num ) { + sharedEntity_t *ent; + + ent = (sharedEntity_t *)((byte *)sv.gentities + sv.gentitySize*(num)); + + return ent; +} + +playerState_t *SV_GameClientNum( int num ) { + playerState_t *ps; + + ps = (playerState_t *)((byte *)sv.gameClients + sv.gameClientSize*(num)); + + return ps; +} + +svEntity_t *SV_SvEntityForGentity( sharedEntity_t *gEnt ) { + if ( !gEnt || gEnt->s.number < 0 || gEnt->s.number >= MAX_GENTITIES ) { + Com_Error( ERR_DROP, "SV_SvEntityForGentity: bad gEnt" ); + } + return &sv.svEntities[ gEnt->s.number ]; +} + +sharedEntity_t *SV_GEntityForSvEntity( svEntity_t *svEnt ) { + int num; + + num = svEnt - sv.svEntities; + return SV_GentityNum( num ); +} + +/* +=============== +SV_GameSendServerCommand + +Sends a command string to a client +=============== +*/ +void SV_GameSendServerCommand( int clientNum, const char *text ) { + if ( clientNum == -1 ) { + SV_SendServerCommand( NULL, "%s", text ); + } else { + if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) { + return; + } + SV_SendServerCommand( svs.clients + clientNum, "%s", text ); + } +} + + +/* +=============== +SV_GameDropClient + +Disconnects the client with a message +=============== +*/ +void SV_GameDropClient( int clientNum, const char *reason ) { + if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) { + return; + } + SV_DropClient( svs.clients + clientNum, reason ); +} + + +/* +================= +SV_SetBrushModel + +sets mins and maxs for inline bmodels +================= +*/ +void SV_SetBrushModel( sharedEntity_t *ent, const char *name ) { + clipHandle_t h; + vec3_t mins, maxs; + + if (!name) { + Com_Error( ERR_DROP, "SV_SetBrushModel: NULL" ); + } + + if (name[0] != '*') { + Com_Error( ERR_DROP, "SV_SetBrushModel: %s isn't a brush model", name ); + } + + + ent->s.modelindex = atoi( name + 1 ); + + h = CM_InlineModel( ent->s.modelindex ); + CM_ModelBounds( h, mins, maxs ); + VectorCopy (mins, ent->r.mins); + VectorCopy (maxs, ent->r.maxs); + ent->r.bmodel = qtrue; + + ent->r.contents = -1; // we don't know exactly what is in the brushes + + SV_LinkEntity( ent ); // FIXME: remove +} + + + +/* +================= +SV_inPVS + +Also checks portalareas so that doors block sight +================= +*/ +qboolean SV_inPVS (const vec3_t p1, const vec3_t p2) +{ + int leafnum; + int cluster; + int area1, area2; + byte *mask; + + leafnum = CM_PointLeafnum (p1); + cluster = CM_LeafCluster (leafnum); + area1 = CM_LeafArea (leafnum); + mask = CM_ClusterPVS (cluster); + + leafnum = CM_PointLeafnum (p2); + cluster = CM_LeafCluster (leafnum); + area2 = CM_LeafArea (leafnum); + if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) ) + return qfalse; + if (!CM_AreasConnected (area1, area2)) + return qfalse; // a door blocks sight + return qtrue; +} + + +/* +================= +SV_inPVSIgnorePortals + +Does NOT check portalareas +================= +*/ +qboolean SV_inPVSIgnorePortals( const vec3_t p1, const vec3_t p2) +{ + int leafnum; + int cluster; + int area1, area2; + byte *mask; + + leafnum = CM_PointLeafnum (p1); + cluster = CM_LeafCluster (leafnum); + area1 = CM_LeafArea (leafnum); + mask = CM_ClusterPVS (cluster); + + leafnum = CM_PointLeafnum (p2); + cluster = CM_LeafCluster (leafnum); + area2 = CM_LeafArea (leafnum); + + if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7)) ) ) ) + return qfalse; + + return qtrue; +} + + +/* +======================== +SV_AdjustAreaPortalState +======================== +*/ +void SV_AdjustAreaPortalState( sharedEntity_t *ent, qboolean open ) { + svEntity_t *svEnt; + + svEnt = SV_SvEntityForGentity( ent ); + if ( svEnt->areanum2 == -1 ) { + return; + } + CM_AdjustAreaPortalState( svEnt->areanum, svEnt->areanum2, open ); +} + + +/* +================== +SV_GameAreaEntities +================== +*/ +qboolean SV_EntityContact( const vec3_t mins, const vec3_t maxs, const sharedEntity_t *gEnt, int capsule ) { + const float *origin, *angles; + clipHandle_t ch; + trace_t trace; + + // check for exact collision + origin = gEnt->r.currentOrigin; + angles = gEnt->r.currentAngles; + + ch = SV_ClipHandleForEntity( gEnt ); + CM_TransformedBoxTrace ( &trace, vec3_origin, vec3_origin, mins, maxs, + ch, -1, origin, angles, capsule ); + + return trace.startsolid; +} + + +/* +=============== +SV_GetServerinfo + +=============== +*/ +void SV_GetServerinfo( char *buffer, int bufferSize ) { + if ( bufferSize < 1 ) { + Com_Error( ERR_DROP, "SV_GetServerinfo: bufferSize == %i", bufferSize ); + } + Q_strncpyz( buffer, Cvar_InfoString( CVAR_SERVERINFO ), bufferSize ); +} + +/* +=============== +SV_LocateGameData + +=============== +*/ +void SV_LocateGameData( sharedEntity_t *gEnts, int numGEntities, int sizeofGEntity_t, + playerState_t *clients, int sizeofGameClient ) { + sv.gentities = gEnts; + sv.gentitySize = sizeofGEntity_t; + sv.num_entities = numGEntities; + + sv.gameClients = clients; + sv.gameClientSize = sizeofGameClient; +} + + +/* +=============== +SV_GetUsercmd + +=============== +*/ +void SV_GetUsercmd( int clientNum, usercmd_t *cmd ) { + if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) { + Com_Error( ERR_DROP, "SV_GetUsercmd: bad clientNum:%i", clientNum ); + } + *cmd = svs.clients[clientNum].lastUsercmd; +} + +//============================================== + +static int FloatAsInt( float f ) { + int temp; + + *(float *)&temp = f; + + return temp; +} + +/* +==================== +SV_GameSystemCalls + +The module is making a system call +==================== +*/ +//rcg010207 - see my comments in VM_DllSyscall(), in qcommon/vm.c ... +#if ((defined __linux__) && (defined __powerpc__)) +#define VMA(x) ((void *) args[x]) +#else +#define VMA(x) VM_ArgPtr(args[x]) +#endif + +#define VMF(x) ((float *)args)[x] + +int SV_GameSystemCalls( int *args ) { + switch( args[0] ) { + case G_PRINT: + Com_Printf( "%s", VMA(1) ); + return 0; + case G_ERROR: + Com_Error( ERR_DROP, "%s", VMA(1) ); + return 0; + case G_MILLISECONDS: + return Sys_Milliseconds(); + case G_CVAR_REGISTER: + Cvar_Register( (vmCvar_t *)VMA(1), (const char *)VMA(2), (const char *)VMA(3), args[4] ); + return 0; + case G_CVAR_UPDATE: + Cvar_Update( (vmCvar_t *)VMA(1) ); + return 0; + case G_CVAR_SET: + Cvar_Set( (const char *)VMA(1), (const char *)VMA(2) ); + return 0; + case G_CVAR_VARIABLE_INTEGER_VALUE: + return Cvar_VariableIntegerValue( (const char *)VMA(1) ); + case G_CVAR_VARIABLE_STRING_BUFFER: + Cvar_VariableStringBuffer( (const char *)VMA(1), (char *)VMA(2), args[3] ); + return 0; + case G_ARGC: + return Cmd_Argc(); + case G_ARGV: + Cmd_ArgvBuffer( args[1], (char *)VMA(2), args[3] ); + return 0; + case G_SEND_CONSOLE_COMMAND: + Cbuf_ExecuteText( args[1], (const char *)VMA(2) ); + return 0; + + case G_FS_FOPEN_FILE: + return FS_FOpenFileByMode( (const char *)VMA(1), (int *)VMA(2), (fsMode_t)args[3] ); + case G_FS_READ: + FS_Read2( VMA(1), args[2], args[3] ); + return 0; + case G_FS_WRITE: + FS_Write( VMA(1), args[2], args[3] ); + return 0; + case G_FS_FCLOSE_FILE: + FS_FCloseFile( args[1] ); + return 0; + case G_FS_GETFILELIST: + return FS_GetFileList( (const char *)VMA(1), (const char *)VMA(2), (char *)VMA(3), args[4] ); + + case G_LOCATE_GAME_DATA: + SV_LocateGameData( (sharedEntity_t *)VMA(1), args[2], args[3], (struct playerState_s *)VMA(4), args[5] ); + return 0; + case G_DROP_CLIENT: + SV_GameDropClient( args[1], (const char *)VMA(2) ); + return 0; + case G_SEND_SERVER_COMMAND: + SV_GameSendServerCommand( args[1], (const char *)VMA(2) ); + return 0; + case G_LINKENTITY: + SV_LinkEntity( (sharedEntity_t *)VMA(1) ); + return 0; + case G_UNLINKENTITY: + SV_UnlinkEntity( (sharedEntity_t *)VMA(1) ); + return 0; + case G_ENTITIES_IN_BOX: + return SV_AreaEntities( (const float *)VMA(1), (const float *)VMA(2), (int *)VMA(3), args[4] ); + case G_ENTITY_CONTACT: + return SV_EntityContact( (const float *)VMA(1), (const float *)VMA(2), (const sharedEntity_t *)VMA(3), /*int capsule*/ qfalse ); + case G_ENTITY_CONTACTCAPSULE: + return SV_EntityContact( (const float *)VMA(1), (const float *)VMA(2), (const sharedEntity_t *)VMA(3), /*int capsule*/ qtrue ); + case G_TRACE: + SV_Trace( (trace_t *)VMA(1), (const float *)VMA(2), (const float *)VMA(3), (const float *)VMA(4), (const float *)VMA(5), args[6], args[7], /*int capsule*/ qfalse, args[8], args[9] ); + return 0; + case G_TRACECAPSULE: + SV_Trace( (trace_t *)VMA(1), (const float *)VMA(2), (const float *)VMA(3), (const float *)VMA(4), (const float *)VMA(5), args[6], args[7], /*int capsule*/ qtrue, args[8], args[9] ); + return 0; + case G_POINT_CONTENTS: + return SV_PointContents( (const float *)VMA(1), args[2] ); + case G_SET_BRUSH_MODEL: + SV_SetBrushModel( (sharedEntity_t *)VMA(1), (const char *)VMA(2) ); + return 0; + case G_IN_PVS: + return SV_inPVS( (const float *)VMA(1), (const float *)VMA(2) ); + case G_IN_PVS_IGNORE_PORTALS: + return SV_inPVSIgnorePortals( (const float *)VMA(1), (const float *)VMA(2) ); + + case G_SET_CONFIGSTRING: + SV_SetConfigstring( args[1], (const char *)VMA(2) ); + return 0; + case G_GET_CONFIGSTRING: + SV_GetConfigstring( args[1], (char *)VMA(2), args[3] ); + return 0; + case G_SET_USERINFO: + SV_SetUserinfo( args[1], (const char *)VMA(2) ); + return 0; + case G_GET_USERINFO: + SV_GetUserinfo( args[1], (char *)VMA(2), args[3] ); + return 0; + case G_GET_SERVERINFO: + SV_GetServerinfo( (char *)VMA(1), args[2] ); + return 0; + case G_ADJUST_AREA_PORTAL_STATE: + SV_AdjustAreaPortalState( (sharedEntity_t *)VMA(1), (qboolean)args[2] ); + return 0; + case G_AREAS_CONNECTED: + return CM_AreasConnected( args[1], args[2] ); + + case G_BOT_ALLOCATE_CLIENT: + return SV_BotAllocateClient(); + case G_BOT_FREE_CLIENT: + SV_BotFreeClient( args[1] ); + return 0; + + case G_GET_USERCMD: + SV_GetUsercmd( args[1], (struct usercmd_s *)VMA(2) ); + return 0; + case G_GET_ENTITY_TOKEN: + { + const char *s; + + s = COM_Parse( (const char **) &sv.entityParsePoint ); + Q_strncpyz( (char *)VMA(1), s, args[2] ); + if ( !sv.entityParsePoint && !s[0] ) { + return qfalse; + } else { + return qtrue; + } + } + + /* + case G_BOT_GET_MEMORY: + void *ptr; + ptr = Bot_GetMemoryGame(args[1]); + return (int)ptr; + case G_BOT_FREE_MEMORY: + Bot_FreeMemoryGame((void *)VMA(1)); + return 0; + */ + case G_DEBUG_POLYGON_CREATE: + return BotImport_DebugPolygonCreate( args[1], args[2], (float (*)[3])VMA(3) ); + case G_DEBUG_POLYGON_DELETE: + BotImport_DebugPolygonDelete( args[1] ); + return 0; + case G_REAL_TIME: + return Com_RealTime( (struct qtime_s *)VMA(1) ); + case G_SNAPVECTOR: + Sys_SnapVector( (float *)VMA(1) ); + return 0; + + case SP_REGISTER_SERVER_CMD: + SP_RegisterServer( (const char *)VMA(1) ); + return 0; + case SP_GETSTRINGTEXTSTRING: + //return (int)SP_GetStringTextString((char *)VMA(1)); + const char* text; + + assert(VMA(1)); + assert(VMA(2)); + +// if (args[0] == CG_SP_GETSTRINGTEXT) +// { +// text = SP_GetStringText( args[1] ); +// } +// else + { + text = SP_GetStringTextString( (const char *) VMA(1) ); + } + + if ( text[0] ) + { + Q_strncpyz( (char *) VMA(2), text, args[3] ); + return qtrue; + } + else + { + Q_strncpyz( (char *) VMA(2), "??", args[3] ); + return qfalse; + } + break; + + case G_ROFF_CLEAN: + return theROFFSystem.Clean(qfalse); + + case G_ROFF_UPDATE_ENTITIES: + theROFFSystem.UpdateEntities(qfalse); + return 0; + + case G_ROFF_CACHE: + return theROFFSystem.Cache( (char *)VMA(1), qfalse ); + + case G_ROFF_PLAY: + return theROFFSystem.Play(args[1], args[2], (qboolean)args[3], qfalse ); + + case G_ROFF_PURGE_ENT: + return theROFFSystem.PurgeEnt( args[1], qfalse ); + + + + + //==================================== + + case BOTLIB_SETUP: + return SV_BotLibSetup(); + case BOTLIB_SHUTDOWN: + return SV_BotLibShutdown(); + case BOTLIB_LIBVAR_SET: + return botlib_export->BotLibVarSet( (char *)VMA(1), (char *)VMA(2) ); + case BOTLIB_LIBVAR_GET: + return botlib_export->BotLibVarGet( (char *)VMA(1), (char *)VMA(2), args[3] ); + + case BOTLIB_PC_ADD_GLOBAL_DEFINE: + return botlib_export->PC_AddGlobalDefine( (char *)VMA(1) ); + case BOTLIB_PC_LOAD_SOURCE: + return botlib_export->PC_LoadSourceHandle( (const char *)VMA(1) ); + case BOTLIB_PC_FREE_SOURCE: + return botlib_export->PC_FreeSourceHandle( args[1] ); + case BOTLIB_PC_READ_TOKEN: + return botlib_export->PC_ReadTokenHandle( args[1], (struct pc_token_s *)VMA(2) ); + case BOTLIB_PC_SOURCE_FILE_AND_LINE: + return botlib_export->PC_SourceFileAndLine( args[1], (char *)VMA(2), (int *)VMA(3) ); + + case BOTLIB_START_FRAME: + return botlib_export->BotLibStartFrame( VMF(1) ); + case BOTLIB_LOAD_MAP: + return botlib_export->BotLibLoadMap( (const char *)VMA(1) ); + case BOTLIB_UPDATENTITY: + return botlib_export->BotLibUpdateEntity( args[1], (struct bot_entitystate_s *)VMA(2) ); + case BOTLIB_TEST: + return botlib_export->Test( args[1], (char *)VMA(2), (float *)VMA(3), (float *)VMA(4) ); + + case BOTLIB_GET_SNAPSHOT_ENTITY: + return SV_BotGetSnapshotEntity( args[1], args[2] ); + case BOTLIB_GET_CONSOLE_MESSAGE: + return SV_BotGetConsoleMessage( args[1], (char *)VMA(2), args[3] ); + case BOTLIB_USER_COMMAND: + SV_ClientThink( &svs.clients[args[1]], (struct usercmd_s *)VMA(2) ); + return 0; + + case BOTLIB_AAS_BBOX_AREAS: + return botlib_export->aas.AAS_BBoxAreas( (float *)VMA(1), (float *)VMA(2), (int *)VMA(3), args[4] ); + case BOTLIB_AAS_AREA_INFO: + return botlib_export->aas.AAS_AreaInfo( args[1], (struct aas_areainfo_s *)VMA(2) ); + case BOTLIB_AAS_ALTERNATIVE_ROUTE_GOAL: + return botlib_export->aas.AAS_AlternativeRouteGoals( (float *)VMA(1), args[2], (float *)VMA(3), args[4], args[5], (struct aas_altroutegoal_s *)VMA(6), args[7], args[8] ); + case BOTLIB_AAS_ENTITY_INFO: + botlib_export->aas.AAS_EntityInfo( args[1], (struct aas_entityinfo_s *)VMA(2) ); + return 0; + + case BOTLIB_AAS_INITIALIZED: + return botlib_export->aas.AAS_Initialized(); + case BOTLIB_AAS_PRESENCE_TYPE_BOUNDING_BOX: + botlib_export->aas.AAS_PresenceTypeBoundingBox( args[1], (float *)VMA(2), (float *)VMA(3) ); + return 0; + case BOTLIB_AAS_TIME: + return FloatAsInt( botlib_export->aas.AAS_Time() ); + + case BOTLIB_AAS_POINT_AREA_NUM: + return botlib_export->aas.AAS_PointAreaNum( (float *)VMA(1) ); + case BOTLIB_AAS_POINT_REACHABILITY_AREA_INDEX: + return botlib_export->aas.AAS_PointReachabilityAreaIndex( (float *)VMA(1) ); + case BOTLIB_AAS_TRACE_AREAS: + return botlib_export->aas.AAS_TraceAreas( (float *)VMA(1), (float *)VMA(2), (int *)VMA(3), (float (*)[3])VMA(4), args[5] ); + + case BOTLIB_AAS_POINT_CONTENTS: + return botlib_export->aas.AAS_PointContents( (float *)VMA(1) ); + case BOTLIB_AAS_NEXT_BSP_ENTITY: + return botlib_export->aas.AAS_NextBSPEntity( args[1] ); + case BOTLIB_AAS_VALUE_FOR_BSP_EPAIR_KEY: + return botlib_export->aas.AAS_ValueForBSPEpairKey( args[1], (char *)VMA(2), (char *)VMA(3), args[4] ); + case BOTLIB_AAS_VECTOR_FOR_BSP_EPAIR_KEY: + return botlib_export->aas.AAS_VectorForBSPEpairKey( args[1], (char *)VMA(2), (float *)VMA(3) ); + case BOTLIB_AAS_FLOAT_FOR_BSP_EPAIR_KEY: + return botlib_export->aas.AAS_FloatForBSPEpairKey( args[1], (char *)VMA(2), (float *)VMA(3) ); + case BOTLIB_AAS_INT_FOR_BSP_EPAIR_KEY: + return botlib_export->aas.AAS_IntForBSPEpairKey( args[1], (char *)VMA(2), (int *)VMA(3) ); + + case BOTLIB_AAS_AREA_REACHABILITY: + return botlib_export->aas.AAS_AreaReachability( args[1] ); + + case BOTLIB_AAS_AREA_TRAVEL_TIME_TO_GOAL_AREA: + return botlib_export->aas.AAS_AreaTravelTimeToGoalArea( args[1], (float *)VMA(2), args[3], args[4] ); + case BOTLIB_AAS_ENABLE_ROUTING_AREA: + return botlib_export->aas.AAS_EnableRoutingArea( args[1], args[2] ); + case BOTLIB_AAS_PREDICT_ROUTE: + return botlib_export->aas.AAS_PredictRoute( (struct aas_predictroute_s *)VMA(1), args[2], (float *)VMA(3), args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11] ); + + case BOTLIB_AAS_SWIMMING: + return botlib_export->aas.AAS_Swimming( (float *)VMA(1) ); + case BOTLIB_AAS_PREDICT_CLIENT_MOVEMENT: + return botlib_export->aas.AAS_PredictClientMovement( (struct aas_clientmove_s *)VMA(1), args[2], (float *)VMA(3), args[4], args[5], + (float *)VMA(6), (float *)VMA(7), args[8], args[9], VMF(10), args[11], args[12], args[13] ); + + case BOTLIB_EA_SAY: + botlib_export->ea.EA_Say( args[1], (char *)VMA(2) ); + return 0; + case BOTLIB_EA_SAY_TEAM: + botlib_export->ea.EA_SayTeam( args[1], (char *)VMA(2) ); + return 0; + case BOTLIB_EA_COMMAND: + botlib_export->ea.EA_Command( args[1], (char *)VMA(2) ); + return 0; + + case BOTLIB_EA_ACTION: + botlib_export->ea.EA_Action( args[1], args[2] ); + break; + case BOTLIB_EA_GESTURE: + botlib_export->ea.EA_Gesture( args[1] ); + return 0; + case BOTLIB_EA_TALK: + botlib_export->ea.EA_Talk( args[1] ); + return 0; + case BOTLIB_EA_ATTACK: + botlib_export->ea.EA_Attack( args[1] ); + return 0; + case BOTLIB_EA_ALT_ATTACK: + botlib_export->ea.EA_Alt_Attack( args[1] ); + return 0; + case BOTLIB_EA_FORCEPOWER: + botlib_export->ea.EA_ForcePower( args[1] ); + return 0; + case BOTLIB_EA_USE: + botlib_export->ea.EA_Use( args[1] ); + return 0; + case BOTLIB_EA_RESPAWN: + botlib_export->ea.EA_Respawn( args[1] ); + return 0; + case BOTLIB_EA_CROUCH: + botlib_export->ea.EA_Crouch( args[1] ); + return 0; + case BOTLIB_EA_MOVE_UP: + botlib_export->ea.EA_MoveUp( args[1] ); + return 0; + case BOTLIB_EA_MOVE_DOWN: + botlib_export->ea.EA_MoveDown( args[1] ); + return 0; + case BOTLIB_EA_MOVE_FORWARD: + botlib_export->ea.EA_MoveForward( args[1] ); + return 0; + case BOTLIB_EA_MOVE_BACK: + botlib_export->ea.EA_MoveBack( args[1] ); + return 0; + case BOTLIB_EA_MOVE_LEFT: + botlib_export->ea.EA_MoveLeft( args[1] ); + return 0; + case BOTLIB_EA_MOVE_RIGHT: + botlib_export->ea.EA_MoveRight( args[1] ); + return 0; + + case BOTLIB_EA_SELECT_WEAPON: + botlib_export->ea.EA_SelectWeapon( args[1], args[2] ); + return 0; + case BOTLIB_EA_JUMP: + botlib_export->ea.EA_Jump( args[1] ); + return 0; + case BOTLIB_EA_DELAYED_JUMP: + botlib_export->ea.EA_DelayedJump( args[1] ); + return 0; + case BOTLIB_EA_MOVE: + botlib_export->ea.EA_Move( args[1], (float *)VMA(2), VMF(3) ); + return 0; + case BOTLIB_EA_VIEW: + botlib_export->ea.EA_View( args[1], (float *)VMA(2) ); + return 0; + + case BOTLIB_EA_END_REGULAR: + botlib_export->ea.EA_EndRegular( args[1], VMF(2) ); + return 0; + case BOTLIB_EA_GET_INPUT: + botlib_export->ea.EA_GetInput( args[1], VMF(2), (struct bot_input_s *)VMA(3) ); + return 0; + case BOTLIB_EA_RESET_INPUT: + botlib_export->ea.EA_ResetInput( args[1] ); + return 0; + + case BOTLIB_AI_LOAD_CHARACTER: + return botlib_export->ai.BotLoadCharacter( (char *)VMA(1), VMF(2) ); + case BOTLIB_AI_FREE_CHARACTER: + botlib_export->ai.BotFreeCharacter( args[1] ); + return 0; + case BOTLIB_AI_CHARACTERISTIC_FLOAT: + return FloatAsInt( botlib_export->ai.Characteristic_Float( args[1], args[2] ) ); + case BOTLIB_AI_CHARACTERISTIC_BFLOAT: + return FloatAsInt( botlib_export->ai.Characteristic_BFloat( args[1], args[2], VMF(3), VMF(4) ) ); + case BOTLIB_AI_CHARACTERISTIC_INTEGER: + return botlib_export->ai.Characteristic_Integer( args[1], args[2] ); + case BOTLIB_AI_CHARACTERISTIC_BINTEGER: + return botlib_export->ai.Characteristic_BInteger( args[1], args[2], args[3], args[4] ); + case BOTLIB_AI_CHARACTERISTIC_STRING: + botlib_export->ai.Characteristic_String( args[1], args[2], (char *)VMA(3), args[4] ); + return 0; + + case BOTLIB_AI_ALLOC_CHAT_STATE: + return botlib_export->ai.BotAllocChatState(); + case BOTLIB_AI_FREE_CHAT_STATE: + botlib_export->ai.BotFreeChatState( args[1] ); + return 0; + case BOTLIB_AI_QUEUE_CONSOLE_MESSAGE: + botlib_export->ai.BotQueueConsoleMessage( args[1], args[2], (char *)VMA(3) ); + return 0; + case BOTLIB_AI_REMOVE_CONSOLE_MESSAGE: + botlib_export->ai.BotRemoveConsoleMessage( args[1], args[2] ); + return 0; + case BOTLIB_AI_NEXT_CONSOLE_MESSAGE: + return botlib_export->ai.BotNextConsoleMessage( args[1], (struct bot_consolemessage_s *)VMA(2) ); + case BOTLIB_AI_NUM_CONSOLE_MESSAGE: + return botlib_export->ai.BotNumConsoleMessages( args[1] ); + case BOTLIB_AI_INITIAL_CHAT: + botlib_export->ai.BotInitialChat( args[1], (char *)VMA(2), args[3], (char *)VMA(4), (char *)VMA(5), (char *)VMA(6), (char *)VMA(7), (char *)VMA(8), (char *)VMA(9), (char *)VMA(10), (char *)VMA(11) ); + return 0; + case BOTLIB_AI_NUM_INITIAL_CHATS: + return botlib_export->ai.BotNumInitialChats( args[1], (char *)VMA(2) ); + case BOTLIB_AI_REPLY_CHAT: + return botlib_export->ai.BotReplyChat( args[1], (char *)VMA(2), args[3], args[4], (char *)VMA(5), (char *)VMA(6), (char *)VMA(7), (char *)VMA(8), (char *)VMA(9), (char *)VMA(10), (char *)VMA(11), (char *)VMA(12) ); + case BOTLIB_AI_CHAT_LENGTH: + return botlib_export->ai.BotChatLength( args[1] ); + case BOTLIB_AI_ENTER_CHAT: + botlib_export->ai.BotEnterChat( args[1], args[2], args[3] ); + return 0; + case BOTLIB_AI_GET_CHAT_MESSAGE: + botlib_export->ai.BotGetChatMessage( args[1], (char *)VMA(2), args[3] ); + return 0; + case BOTLIB_AI_STRING_CONTAINS: + return botlib_export->ai.StringContains( (char *)VMA(1), (char *)VMA(2), args[3] ); + case BOTLIB_AI_FIND_MATCH: + return botlib_export->ai.BotFindMatch( (char *)VMA(1), (struct bot_match_s *)VMA(2), args[3] ); + case BOTLIB_AI_MATCH_VARIABLE: + botlib_export->ai.BotMatchVariable( (struct bot_match_s *)VMA(1), args[2], (char *)VMA(3), args[4] ); + return 0; + case BOTLIB_AI_UNIFY_WHITE_SPACES: + botlib_export->ai.UnifyWhiteSpaces( (char *)VMA(1) ); + return 0; + case BOTLIB_AI_REPLACE_SYNONYMS: + botlib_export->ai.BotReplaceSynonyms( (char *)VMA(1), args[2] ); + return 0; + case BOTLIB_AI_LOAD_CHAT_FILE: + return botlib_export->ai.BotLoadChatFile( args[1], (char *)VMA(2), (char *)VMA(3) ); + case BOTLIB_AI_SET_CHAT_GENDER: + botlib_export->ai.BotSetChatGender( args[1], args[2] ); + return 0; + case BOTLIB_AI_SET_CHAT_NAME: + botlib_export->ai.BotSetChatName( args[1], (char *)VMA(2), args[3] ); + return 0; + + case BOTLIB_AI_RESET_GOAL_STATE: + botlib_export->ai.BotResetGoalState( args[1] ); + return 0; + case BOTLIB_AI_RESET_AVOID_GOALS: + botlib_export->ai.BotResetAvoidGoals( args[1] ); + return 0; + case BOTLIB_AI_REMOVE_FROM_AVOID_GOALS: + botlib_export->ai.BotRemoveFromAvoidGoals( args[1], args[2] ); + return 0; + case BOTLIB_AI_PUSH_GOAL: + botlib_export->ai.BotPushGoal( args[1], (struct bot_goal_s *)VMA(2) ); + return 0; + case BOTLIB_AI_POP_GOAL: + botlib_export->ai.BotPopGoal( args[1] ); + return 0; + case BOTLIB_AI_EMPTY_GOAL_STACK: + botlib_export->ai.BotEmptyGoalStack( args[1] ); + return 0; + case BOTLIB_AI_DUMP_AVOID_GOALS: + botlib_export->ai.BotDumpAvoidGoals( args[1] ); + return 0; + case BOTLIB_AI_DUMP_GOAL_STACK: + botlib_export->ai.BotDumpGoalStack( args[1] ); + return 0; + case BOTLIB_AI_GOAL_NAME: + botlib_export->ai.BotGoalName( args[1], (char *)VMA(2), args[3] ); + return 0; + case BOTLIB_AI_GET_TOP_GOAL: + return botlib_export->ai.BotGetTopGoal( args[1], (struct bot_goal_s *)VMA(2) ); + case BOTLIB_AI_GET_SECOND_GOAL: + return botlib_export->ai.BotGetSecondGoal( args[1], (struct bot_goal_s *)VMA(2) ); + case BOTLIB_AI_CHOOSE_LTG_ITEM: + return botlib_export->ai.BotChooseLTGItem( args[1], (float *)VMA(2), (int *)VMA(3), args[4] ); + case BOTLIB_AI_CHOOSE_NBG_ITEM: + return botlib_export->ai.BotChooseNBGItem( args[1], (float *)VMA(2), (int *)VMA(3), args[4], (struct bot_goal_s *)VMA(5), VMF(6) ); + case BOTLIB_AI_TOUCHING_GOAL: + return botlib_export->ai.BotTouchingGoal( (float *)VMA(1), (struct bot_goal_s *)VMA(2) ); + case BOTLIB_AI_ITEM_GOAL_IN_VIS_BUT_NOT_VISIBLE: + return botlib_export->ai.BotItemGoalInVisButNotVisible( args[1], (float *)VMA(2), (float *)VMA(3), (struct bot_goal_s *)VMA(4) ); + case BOTLIB_AI_GET_LEVEL_ITEM_GOAL: + return botlib_export->ai.BotGetLevelItemGoal( args[1], (char *)VMA(2), (struct bot_goal_s *)VMA(3) ); + case BOTLIB_AI_GET_NEXT_CAMP_SPOT_GOAL: + return botlib_export->ai.BotGetNextCampSpotGoal( args[1], (struct bot_goal_s *)VMA(2) ); + case BOTLIB_AI_GET_MAP_LOCATION_GOAL: + return botlib_export->ai.BotGetMapLocationGoal( (char *)VMA(1), (struct bot_goal_s *)VMA(2) ); + case BOTLIB_AI_AVOID_GOAL_TIME: + return FloatAsInt( botlib_export->ai.BotAvoidGoalTime( args[1], args[2] ) ); + case BOTLIB_AI_SET_AVOID_GOAL_TIME: + botlib_export->ai.BotSetAvoidGoalTime( args[1], args[2], VMF(3)); + return 0; + case BOTLIB_AI_INIT_LEVEL_ITEMS: + botlib_export->ai.BotInitLevelItems(); + return 0; + case BOTLIB_AI_UPDATE_ENTITY_ITEMS: + botlib_export->ai.BotUpdateEntityItems(); + return 0; + case BOTLIB_AI_LOAD_ITEM_WEIGHTS: + return botlib_export->ai.BotLoadItemWeights( args[1], (char *)VMA(2) ); + case BOTLIB_AI_FREE_ITEM_WEIGHTS: + botlib_export->ai.BotFreeItemWeights( args[1] ); + return 0; + case BOTLIB_AI_INTERBREED_GOAL_FUZZY_LOGIC: + botlib_export->ai.BotInterbreedGoalFuzzyLogic( args[1], args[2], args[3] ); + return 0; + case BOTLIB_AI_SAVE_GOAL_FUZZY_LOGIC: + botlib_export->ai.BotSaveGoalFuzzyLogic( args[1], (char *)VMA(2) ); + return 0; + case BOTLIB_AI_MUTATE_GOAL_FUZZY_LOGIC: + botlib_export->ai.BotMutateGoalFuzzyLogic( args[1], VMF(2) ); + return 0; + case BOTLIB_AI_ALLOC_GOAL_STATE: + return botlib_export->ai.BotAllocGoalState( args[1] ); + case BOTLIB_AI_FREE_GOAL_STATE: + botlib_export->ai.BotFreeGoalState( args[1] ); + return 0; + + case BOTLIB_AI_RESET_MOVE_STATE: + botlib_export->ai.BotResetMoveState( args[1] ); + return 0; + case BOTLIB_AI_ADD_AVOID_SPOT: + botlib_export->ai.BotAddAvoidSpot( args[1], (float *)VMA(2), VMF(3), args[4] ); + return 0; + case BOTLIB_AI_MOVE_TO_GOAL: + botlib_export->ai.BotMoveToGoal( (struct bot_moveresult_s *)VMA(1), args[2], (struct bot_goal_s *)VMA(3), args[4] ); + return 0; + case BOTLIB_AI_MOVE_IN_DIRECTION: + return botlib_export->ai.BotMoveInDirection( args[1], (float *)VMA(2), VMF(3), args[4] ); + case BOTLIB_AI_RESET_AVOID_REACH: + botlib_export->ai.BotResetAvoidReach( args[1] ); + return 0; + case BOTLIB_AI_RESET_LAST_AVOID_REACH: + botlib_export->ai.BotResetLastAvoidReach( args[1] ); + return 0; + case BOTLIB_AI_REACHABILITY_AREA: + return botlib_export->ai.BotReachabilityArea( (float *)VMA(1), args[2] ); + case BOTLIB_AI_MOVEMENT_VIEW_TARGET: + return botlib_export->ai.BotMovementViewTarget( args[1], (struct bot_goal_s *)VMA(2), args[3], VMF(4), (float *)VMA(5) ); + case BOTLIB_AI_PREDICT_VISIBLE_POSITION: + return botlib_export->ai.BotPredictVisiblePosition( (float *)VMA(1), args[2], (struct bot_goal_s *)VMA(3), args[4], (float *)VMA(5) ); + case BOTLIB_AI_ALLOC_MOVE_STATE: + return botlib_export->ai.BotAllocMoveState(); + case BOTLIB_AI_FREE_MOVE_STATE: + botlib_export->ai.BotFreeMoveState( args[1] ); + return 0; + case BOTLIB_AI_INIT_MOVE_STATE: + botlib_export->ai.BotInitMoveState( args[1], (struct bot_initmove_s *)VMA(2) ); + return 0; + + case BOTLIB_AI_CHOOSE_BEST_FIGHT_WEAPON: + return botlib_export->ai.BotChooseBestFightWeapon( args[1], (int *)VMA(2) ); + case BOTLIB_AI_GET_WEAPON_INFO: + botlib_export->ai.BotGetWeaponInfo( args[1], args[2], (struct weaponinfo_s *)VMA(3) ); + return 0; + case BOTLIB_AI_LOAD_WEAPON_WEIGHTS: + return botlib_export->ai.BotLoadWeaponWeights( args[1], (char *)VMA(2) ); + case BOTLIB_AI_ALLOC_WEAPON_STATE: + return botlib_export->ai.BotAllocWeaponState(); + case BOTLIB_AI_FREE_WEAPON_STATE: + botlib_export->ai.BotFreeWeaponState( args[1] ); + return 0; + case BOTLIB_AI_RESET_WEAPON_STATE: + botlib_export->ai.BotResetWeaponState( args[1] ); + return 0; + + case BOTLIB_AI_GENETIC_PARENTS_AND_CHILD_SELECTION: + return botlib_export->ai.GeneticParentsAndChildSelection(args[1], (float *)VMA(2), (int *)VMA(3), (int *)VMA(4), (int *)VMA(5)); + + case TRAP_MEMSET: + Com_Memset( VMA(1), args[2], args[3] ); + return 0; + + case TRAP_MEMCPY: + Com_Memcpy( VMA(1), VMA(2), args[3] ); + return 0; + + case TRAP_STRNCPY: + return (int)strncpy( (char *)VMA(1), (const char *)VMA(2), args[3] ); + + case TRAP_SIN: + return FloatAsInt( sin( VMF(1) ) ); + + case TRAP_COS: + return FloatAsInt( cos( VMF(1) ) ); + + case TRAP_ATAN2: + return FloatAsInt( atan2( VMF(1), VMF(2) ) ); + + case TRAP_SQRT: + return FloatAsInt( sqrt( VMF(1) ) ); + + case TRAP_MATRIXMULTIPLY: + MatrixMultiply( (vec3_t *)VMA(1), (vec3_t *)VMA(2), (vec3_t *)VMA(3) ); + return 0; + + case TRAP_ANGLEVECTORS: + AngleVectors( (const float *)VMA(1), (float *)VMA(2), (float *)VMA(3), (float *)VMA(4) ); + return 0; + + case TRAP_PERPENDICULARVECTOR: + PerpendicularVector( (float *)VMA(1), (const float *)VMA(2) ); + return 0; + + case TRAP_FLOOR: + return FloatAsInt( floor( VMF(1) ) ); + + case TRAP_CEIL: + return FloatAsInt( ceil( VMF(1) ) ); + + case G_G2_LISTBONES: + G2API_ListBones( (CGhoul2Info *) VMA(1), args[2]); + return 0; + + case G_G2_LISTSURFACES: + G2API_ListSurfaces( (CGhoul2Info *) args[1] ); + return 0; + + case G_G2_HAVEWEGHOULMODELS: + return G2API_HaveWeGhoul2Models( *((CGhoul2Info_v *)args[1]) ); + + case G_G2_SETMODELS: + G2API_SetGhoul2ModelIndexes( *((CGhoul2Info_v *)args[1]),(qhandle_t *)VMA(2),(qhandle_t *)VMA(3)); + return 0; + + case G_G2_GETBOLT: + return G2API_GetBoltMatrix(*((CGhoul2Info_v *)args[1]), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + + case G_G2_GETBOLT_NOREC: + gG2_GBMNoReconstruct = qtrue; + return G2API_GetBoltMatrix(*((CGhoul2Info_v *)args[1]), args[2], args[3], (mdxaBone_t *)VMA(4), (const float *)VMA(5),(const float *)VMA(6), args[7], (qhandle_t *)VMA(8), (float *)VMA(9)); + + case G_G2_INITGHOUL2MODEL: + return G2API_InitGhoul2Model((CGhoul2Info_v **)VMA(1), (const char *)VMA(2), args[3], (qhandle_t) args[4], + (qhandle_t) args[5], args[6], args[7]); + + case G_G2_ADDBOLT: + return G2API_AddBolt(*((CGhoul2Info_v *)args[1]), args[2], (const char *)VMA(3)); + + case G_G2_SETBOLTINFO: + G2API_SetBoltInfo(*((CGhoul2Info_v *)args[1]), args[2], args[3]); + return 0; + + case G_G2_ANGLEOVERRIDE: + return G2API_SetBoneAngles(*((CGhoul2Info_v *)args[1]), args[2], (const char *)VMA(3), (float *)VMA(4), args[5], + (const Eorientations) args[6], (const Eorientations) args[7], (const Eorientations) args[8], + (qhandle_t *)VMA(9), args[10], args[11] ); + + case G_G2_PLAYANIM: + return G2API_SetBoneAnim(*((CGhoul2Info_v *)args[1]), args[2], (const char *)VMA(3), args[4], args[5], + args[6], VMF(7), args[8], VMF(9), args[10]); + case G_G2_GETGLANAME: + //return (int)G2API_GetGLAName(*((CGhoul2Info_v *)args[1]), args[2]); + { //Since returning a pointer in such a way to a VM seems to cause MASSIVE FAILURE, we will shove data into the pointer the vm passes instead + char *point = ((char *)VMA(3)); + char *local; + local = G2API_GetGLAName(*((CGhoul2Info_v *)args[1]), args[2]); + if (local) + { + strcpy(point, local); + } + } + + return 0; + + case G_G2_COPYGHOUL2INSTANCE: + return (int)G2API_CopyGhoul2Instance(*((CGhoul2Info_v *)args[1]), *((CGhoul2Info_v *)args[2]), args[3]); + + case G_G2_COPYSPECIFICGHOUL2MODEL: + G2API_CopySpecificG2Model(*((CGhoul2Info_v *)args[1]), args[2], *((CGhoul2Info_v *)args[3]), args[4]); + return 0; + + case G_G2_DUPLICATEGHOUL2INSTANCE: + G2API_DuplicateGhoul2Instance(*((CGhoul2Info_v *)args[1]), (CGhoul2Info_v **)VMA(2)); + return 0; + + case G_G2_HASGHOUL2MODELONINDEX: + //return (int)G2API_HasGhoul2ModelOnIndex((CGhoul2Info_v **)args[1], args[2]); + return (int)G2API_HasGhoul2ModelOnIndex((CGhoul2Info_v **)VMA(1), args[2]); + + case G_G2_REMOVEGHOUL2MODEL: + //return (int)G2API_RemoveGhoul2Model((CGhoul2Info_v **)args[1], args[2]); + return (int)G2API_RemoveGhoul2Model((CGhoul2Info_v **)VMA(1), args[2]); + + case G_G2_CLEANMODELS: + G2API_CleanGhoul2Models((CGhoul2Info_v **)VMA(1)); + // G2API_CleanGhoul2Models((CGhoul2Info_v **)args[1]); + return 0; + + default: + Com_Error( ERR_DROP, "Bad game system trap: %i", args[0] ); + } + return -1; +} + +/* +=============== +SV_ShutdownGameProgs + +Called every time a map changes +=============== +*/ +void SV_ShutdownGameProgs( void ) { + if ( !gvm ) { + return; + } + VM_Call( gvm, GAME_SHUTDOWN, qfalse ); + VM_Free( gvm ); + gvm = NULL; +} + +/* +================== +SV_InitGameVM + +Called for both a full init and a restart +================== +*/ +static void SV_InitGameVM( qboolean restart ) { + int i; + + // start the entity parsing at the beginning + sv.entityParsePoint = CM_EntityString(); + + // use the current msec count for a random seed + // init for this gamestate + VM_Call( gvm, GAME_INIT, svs.time, Com_Milliseconds(), restart ); + + // clear all gentity pointers that might still be set from + // a previous level + for ( i = 0 ; i < sv_maxclients->integer ; i++ ) { + svs.clients[i].gentity = NULL; + } +} + + + +/* +=================== +SV_RestartGameProgs + +Called on a map_restart, but not on a normal map change +=================== +*/ +void SV_RestartGameProgs( void ) { + if ( !gvm ) { + return; + } + VM_Call( gvm, GAME_SHUTDOWN, qtrue ); + + // do a restart instead of a free + gvm = VM_Restart( gvm ); + if ( !gvm ) { // bk001212 - as done below + Com_Error( ERR_FATAL, "VM_Restart on game failed" ); + } + + SV_InitGameVM( qtrue ); +} + + +/* +=============== +SV_InitGameProgs + +Called on a normal map change, not on a map_restart +=============== +*/ +void SV_InitGameProgs( void ) { + cvar_t *var; + //FIXME these are temp while I make bots run in vm + extern int bot_enable; + + var = Cvar_Get( "bot_enable", "1", CVAR_LATCH ); + if ( var ) { + bot_enable = var->integer; + } + else { + bot_enable = 0; + } + + // load the dll or bytecode + gvm = VM_Create( "jk2mpgame", SV_GameSystemCalls, (vmInterpret_t)(int)Cvar_VariableValue( "vm_game" ) ); + if ( !gvm ) { + Com_Error( ERR_FATAL, "VM_Create on game failed" ); + } + + SV_InitGameVM( qfalse ); +} + + +/* +==================== +SV_GameCommand + +See if the current console command is claimed by the game +==================== +*/ +qboolean SV_GameCommand( void ) { + if ( sv.state != SS_GAME ) { + return qfalse; + } + + return (qboolean)VM_Call( gvm, GAME_CONSOLE_COMMAND ); +} + diff --git a/CODE-mp/server/sv_init.cpp b/CODE-mp/server/sv_init.cpp index 1c81b61..ec1fcee 100644 --- a/CODE-mp/server/sv_init.cpp +++ b/CODE-mp/server/sv_init.cpp @@ -1,6 +1,7 @@ #include "server.h" +#include "../game/q_shared.h" /* Ghoul2 Insert Start */ @@ -258,6 +259,9 @@ void SV_Startup( void ) { svs.clients = (struct client_s *)Z_Malloc (sizeof(client_t) * sv_maxclients->integer, TAG_CLIENTS, qtrue ); if ( com_dedicated->integer ) { svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64; + Cvar_Set( "r_ghoul2animsmooth", "0"); + Cvar_Set( "r_ghoul2unsqashaftersmooth", "0"); + } else { // we don't need nearly as many when playing locally svs.numSnapshotEntities = sv_maxclients->integer * 4 * 64; @@ -265,6 +269,7 @@ void SV_Startup( void ) { svs.initialized = qtrue; Cvar_Set( "sv_running", "1" ); + } /* @@ -359,6 +364,9 @@ void SV_ClearServer(void) { Z_Free( sv.configstrings[i] ); } } + +// CM_ClearMap(); + /* Ghoul2 Insert Start */ @@ -420,6 +428,8 @@ clients along with it. This is NOT called for map_restart ================ */ +extern void FixGhoul2InfoLeaks(bool,bool); + extern void RE_RegisterMedia_LevelLoadBegin(const char *psMapName, ForceReload_e eForceReload); void SV_SpawnServer( char *server, qboolean killBots, ForceReload_e eForceReload ) { int i; @@ -435,6 +445,9 @@ void SV_SpawnServer( char *server, qboolean killBots, ForceReload_e eForceReload // shut down the existing game if it is running SV_ShutdownGameProgs(); + FixGhoul2InfoLeaks(false,true); + + Com_Printf ("------ Server Initialization ------\n"); Com_Printf ("Server: %s\n",server); @@ -457,8 +470,12 @@ Ghoul2 Insert End // also print some status stuff CL_MapLoading(); +#ifndef DEDICATED // make sure all the client stuff is unloaded CL_ShutdownAll(); +#endif + + CM_ClearMap(); // clear the whole hunk because we're (re)loading the server Hunk_Clear(); @@ -470,11 +487,13 @@ Ghoul2 Insert Start // isnt a dedicated server. if ( !com_dedicated->integer ) { +#ifndef DEDICATED R_InitImages(); R_InitShaders(); R_ModelInit(); +#endif } else { @@ -483,9 +502,6 @@ Ghoul2 Insert Start SV_SendMapChange(); - // clear collision map data - CM_ClearMap(); - // init client structures and svs.numSnapshotEntities if ( !Cvar_VariableValue("sv_running") ) { SV_Startup(); @@ -705,6 +721,17 @@ void SV_Init (void) { Cvar_Get ("dmflags", "0", CVAR_SERVERINFO); Cvar_Get ("fraglimit", "20", CVAR_SERVERINFO); Cvar_Get ("timelimit", "0", CVAR_SERVERINFO); + + // Get these to establish them and to make sure they have a default before the menus decide to stomp them. + Cvar_Get ("g_maxHolocronCarry", "3", CVAR_SERVERINFO); + Cvar_Get ("g_privateDuel", "1", CVAR_SERVERINFO ); + Cvar_Get ("g_saberLocking", "1", CVAR_SERVERINFO ); + Cvar_Get ("g_maxForceRank", "6", CVAR_SERVERINFO ); + Cvar_Get ("duel_fraglimit", "10", CVAR_SERVERINFO); + Cvar_Get ("g_forceBasedTeams", "0", CVAR_SERVERINFO); + Cvar_Get ("g_duelWeaponDisable", "1", CVAR_SERVERINFO); + Cvar_Get ("g_needpass", "0", CVAR_SERVERINFO); + sv_gametype = Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_LATCH ); Cvar_Get ("sv_keywords", "", CVAR_SERVERINFO); Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO | CVAR_ROM); @@ -719,11 +746,10 @@ void SV_Init (void) { sv_allowAnonymous = Cvar_Get ("sv_allowAnonymous", "0", CVAR_SERVERINFO); // systeminfo - Cvar_Get ("sv_cheats", "1", CVAR_SYSTEMINFO | CVAR_ROM ); + Cvar_Get ("sv_cheats", "0", CVAR_SYSTEMINFO | CVAR_ROM ); sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM ); #ifndef DLL_ONLY // bk010216 - for DLL-only servers -// sv_pure = Cvar_Get ("sv_pure", "1", CVAR_SYSTEMINFO ); - sv_pure = Cvar_Get ("sv_pure", "0", CVAR_SYSTEMINFO );//FIXME: put back for release + sv_pure = Cvar_Get ("sv_pure", "1", CVAR_SYSTEMINFO ); #else sv_pure = Cvar_Get ("sv_pure", "0", CVAR_SYSTEMINFO | CVAR_INIT | CVAR_ROM ); #endif @@ -752,6 +778,8 @@ void SV_Init (void) { sv_killserver = Cvar_Get ("sv_killserver", "0", 0); sv_mapChecksum = Cvar_Get ("sv_mapChecksum", "", CVAR_ROM); + sv_debugserver = Cvar_Get ("sv_debugserver", "0", 0); + SP_Register("str_server",SP_REGISTER_REQUIRED); // initialize bot cvars so they are listed and can be set before loading the botlib diff --git a/CODE-mp/server/sv_main.cpp b/CODE-mp/server/sv_main.cpp index 454c38b..9feaf0b 100644 --- a/CODE-mp/server/sv_main.cpp +++ b/CODE-mp/server/sv_main.cpp @@ -30,6 +30,8 @@ cvar_t *sv_pure; cvar_t *sv_floodProtect; cvar_t *sv_allowAnonymous; +cvar_t *sv_debugserver; + /* ============================================================================= diff --git a/CODE-mp/server/sv_rankings.cpp b/CODE-mp/server/sv_rankings.cpp new file mode 100644 index 0000000..0290069 --- /dev/null +++ b/CODE-mp/server/sv_rankings.cpp @@ -0,0 +1,1516 @@ +// sv_rankings.c -- global rankings interface + +#include "server.h" +#include "..\rankings\1.0\gr\grapi.h" +#include "..\rankings\1.0\gr\grlog.h" + +typedef struct +{ + GR_CONTEXT context; + uint64_t game_id; + uint64_t match; + uint64_t player_id; + GR_PLAYER_TOKEN token; + grank_status_t grank_status; + grank_status_t final_status; // status to set after cleanup + uint32_t grank; // global rank + char name[32]; +} ranked_player_t; + +static int s_rankings_contexts = 0; +static qboolean s_rankings_active = qfalse; +static GR_CONTEXT s_server_context = 0; +static uint64_t s_server_match = 0; +static char* s_rankings_game_key = NULL; +static uint64_t s_rankings_game_id = 0; +static ranked_player_t* s_ranked_players = NULL; +static qboolean s_server_quitting = qfalse; +static const char s_ascii_encoding[] = + "0123456789abcdef" + "ghijklmnopqrstuv" + "wxyzABCDEFGHIJKL" + "MNOPQRSTUVWXYZ[]"; + +// private functions +static void SV_RankNewGameCBF( GR_NEWGAME* gr_newgame, void* cbf_arg ); +static void SV_RankUserCBF( GR_LOGIN* gr_login, void* cbf_arg ); +static void SV_RankJoinGameCBF( GR_JOINGAME* gr_joingame, void* cbf_arg ); +static void SV_RankSendReportsCBF( GR_STATUS* gr_status, void* cbf_arg ); +static void SV_RankCleanupCBF( GR_STATUS* gr_status, void* cbf_arg ); +static void SV_RankCloseContext( ranked_player_t* ranked_player ); +static int SV_RankAsciiEncode( char* dest, const unsigned char* src, + int src_len ); +static int SV_RankAsciiDecode( unsigned char* dest, const char* src, + int src_len ); +static void SV_RankEncodeGameID( uint64_t game_id, char* result, + int len ); +static uint64_t SV_RankDecodePlayerID( const char* string ); +static void SV_RankDecodePlayerKey( const char* string, GR_PLAYER_TOKEN key ); +static char* SV_RankStatusString( GR_STATUS status ); +static void SV_RankError( const char* fmt, ... ); +static char SV_RankGameKey[64]; + +/* +================ +SV_RankBegin +================ +*/ +void SV_RankBegin( char *gamekey ) +{ + GR_INIT init; + GR_STATUS status; + + assert( s_rankings_contexts == 0 ); + assert( !s_rankings_active ); + assert( s_ranked_players == NULL ); + + if( sv_enableRankings->integer == 0 || Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER ) + { + s_rankings_active = qfalse; + if( sv_rankingsActive->integer == 1 ) + { + Cvar_Set( "sv_rankingsActive", "0" ); + } + return; + } + + // only allow official game key on pure servers + if( strcmp(gamekey, GR_GAMEKEY) == 0 ) + { +/* + if( Cvar_VariableValue("sv_pure") != 1 ) + { + Cvar_Set( "sv_enableRankings", "0" ); + return; + } +*/ + + // substitute game-specific game key + switch( (int)Cvar_VariableValue("g_gametype") ) + { + case GT_FFA: + gamekey = "Q3 Free For All"; + break; + case GT_TOURNAMENT: + gamekey = "Q3 Tournament"; + break; + case GT_TEAM: + gamekey = "Q3 Team Deathmatch"; + break; + case GT_CTF: + gamekey = "Q3 Capture the Flag"; + break; + case GT_1FCTF: + gamekey = "Q3 One Flag CTF"; + break; + case GT_OBELISK: + gamekey = "Q3 Overload"; + break; + case GT_HARVESTER: + gamekey = "Q3 Harvester"; + break; + default: + break; + } + } + s_rankings_game_key = gamekey; + + // initialize rankings + GRankLogLevel( GRLOG_OFF ); + memset(SV_RankGameKey,0,sizeof(SV_RankGameKey)); + strncpy(SV_RankGameKey,gamekey,sizeof(SV_RankGameKey)-1); + init = GRankInit( 1, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END ); + s_server_context = init.context; + s_rankings_contexts++; + Com_DPrintf( "SV_RankBegin(); GR_GAMEKEY is %s\n", gamekey ); + Com_DPrintf( "SV_RankBegin(); s_rankings_contexts=%d\n",s_rankings_contexts ); + Com_DPrintf( "SV_RankBegin(); s_server_context=%d\n",init.context ); + + // new game + if(!strlen(Cvar_VariableString( "sv_leagueName" ))) + { + status = GRankNewGameAsync + ( + s_server_context, + SV_RankNewGameCBF, + NULL, + GR_OPT_LEAGUENAME, + (void*)(Cvar_VariableString( "sv_leagueName" )), + GR_OPT_END + ); + } + else + { + status = GRankNewGameAsync + ( + s_server_context, + SV_RankNewGameCBF, + NULL, + GR_OPT_END + ); + } + + if( status != GR_STATUS_PENDING ) + { + SV_RankError( "SV_RankBegin: Expected GR_STATUS_PENDING, got %s", + SV_RankStatusString( status ) ); + return; + } + + // logging + if( com_developer->value ) + { + GRankLogLevel( GRLOG_TRACE ); + } + + // allocate rankings info for each player + s_ranked_players = Z_Malloc( sv_maxclients->value * + sizeof(ranked_player_t) ); + memset( (void*)s_ranked_players, 0 ,sv_maxclients->value + * sizeof(ranked_player_t)); +} + +/* +================ +SV_RankEnd +================ +*/ +void SV_RankEnd( void ) +{ + GR_STATUS status; + int i; + + Com_DPrintf( "SV_RankEnd();\n" ); + + if( !s_rankings_active ) + { + // cleanup after error during game + if( s_ranked_players != NULL ) + { + for( i = 0; i < sv_maxclients->value; i++ ) + { + if( s_ranked_players[i].context != 0 ) + { + SV_RankCloseContext( &(s_ranked_players[i]) ); + } + } + } + if( s_server_context != 0 ) + { + SV_RankCloseContext( NULL ); + } + + return; + } + + for( i = 0; i < sv_maxclients->value; i++ ) + { + if( s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE ) + { + SV_RankUserLogout( i ); + Com_DPrintf( "SV_RankEnd: SV_RankUserLogout %d\n",i ); + } + } + + assert( s_server_context != 0 ); + + // send match reports, proceed to SV_RankSendReportsCBF + status = GRankSendReportsAsync + ( + s_server_context, + 0, + SV_RankSendReportsCBF, + NULL, + GR_OPT_END + ); + + if( status != GR_STATUS_PENDING ) + { + SV_RankError( "SV_RankEnd: Expected GR_STATUS_PENDING, got %s", + SV_RankStatusString( status ) ); + } + + s_rankings_active = qfalse; + Cvar_Set( "sv_rankingsActive", "0" ); +} + +/* +================ +SV_RankPoll +================ +*/ +void SV_RankPoll( void ) +{ + GRankPoll(); +} + +/* +================ +SV_RankCheckInit +================ +*/ +qboolean SV_RankCheckInit( void ) +{ + return (s_rankings_contexts > 0); +} + +/* +================ +SV_RankActive +================ +*/ +qboolean SV_RankActive( void ) +{ + return s_rankings_active; +} + +/* +================= +SV_RankUserStatus +================= +*/ +grank_status_t SV_RankUserStatus( int index ) +{ + if( !s_rankings_active ) + { + return GR_STATUS_ERROR; + } + + assert( s_ranked_players != NULL ); + assert( index >= 0 ); + assert( index < sv_maxclients->value ); + + return s_ranked_players[index].grank_status; +} + +/* +================ +SV_RankUserGRank +================ +*/ +int SV_RankUserGrank( int index ) +{ + if( !s_rankings_active ) + { + return 0; + } + + assert( s_ranked_players != NULL ); + assert( index >= 0 ); + assert( index < sv_maxclients->value ); + + return s_ranked_players[index].grank; +} + +/* +================ +SV_RankUserReset +================ +*/ +void SV_RankUserReset( int index ) +{ + if( !s_rankings_active ) + { + return; + } + + assert( s_ranked_players != NULL ); + assert( index >= 0 ); + assert( index < sv_maxclients->value ); + + switch( s_ranked_players[index].grank_status ) + { + case QGR_STATUS_SPECTATOR: + case QGR_STATUS_NO_USER: + case QGR_STATUS_BAD_PASSWORD: + case QGR_STATUS_USER_EXISTS: + case QGR_STATUS_NO_MEMBERSHIP: + case QGR_STATUS_TIMEOUT: + case QGR_STATUS_ERROR: + s_ranked_players[index].grank_status = QGR_STATUS_NEW; + break; + default: + break; + } +} + +/* +================ +SV_RankUserSpectate +================ +*/ +void SV_RankUserSpectate( int index ) +{ + if( !s_rankings_active ) + { + return; + } + + assert( s_ranked_players != NULL ); + assert( index >= 0 ); + assert( index < sv_maxclients->value ); + + // GRANK_FIXME - check current status? + s_ranked_players[index].grank_status = QGR_STATUS_SPECTATOR; +} + +/* +================ +SV_RankUserCreate +================ +*/ +void SV_RankUserCreate( int index, char* username, char* password, + char* email ) +{ + GR_INIT init; + GR_STATUS status; + + assert( index >= 0 ); + assert( index < sv_maxclients->value ); + assert( username != NULL ); + assert( password != NULL ); + assert( email != NULL ); + assert( s_ranked_players ); + assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE ); + + Com_DPrintf( "SV_RankUserCreate( %d, %s, \"****\", %s );\n", index, + username, email ); + + if( !s_rankings_active ) + { + Com_DPrintf( "SV_RankUserCreate: Not ready to create\n" ); + s_ranked_players[index].grank_status = QGR_STATUS_ERROR; + return; + } + + if( s_ranked_players[index].grank_status == QGR_STATUS_ACTIVE ) + { + Com_DPrintf( "SV_RankUserCreate: Got Create from active player\n" ); + return; + } + + // get a separate context for the new user + init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END ); + s_ranked_players[index].context = init.context; + s_rankings_contexts++; + Com_DPrintf( "SV_RankUserCreate(); s_rankings_contexts=%d\n",s_rankings_contexts ); + Com_DPrintf( "SV_RankUserCreate(); s_ranked_players[%d].context=%d\n",index,init.context ); + + // attempt to create a new account, proceed to SV_RankUserCBF + status = GRankUserCreateAsync + ( + s_ranked_players[index].context, + username, + password, + email, + SV_RankUserCBF, + (void*)&s_ranked_players[index], + GR_OPT_END + ); + + if( status == GR_STATUS_PENDING ) + { + s_ranked_players[index].grank_status = QGR_STATUS_PENDING; + s_ranked_players[index].final_status = QGR_STATUS_NEW; + } + else + { + SV_RankError( "SV_RankUserCreate: Expected GR_STATUS_PENDING, got %s", + SV_RankStatusString( status ) ); + } +} + +/* +================ +SV_RankUserLogin +================ +*/ +void SV_RankUserLogin( int index, char* username, char* password ) +{ + GR_INIT init; + GR_STATUS status; + + assert( index >= 0 ); + assert( index < sv_maxclients->value ); + assert( username != NULL ); + assert( password != NULL ); + assert( s_ranked_players ); + assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE ); + + Com_DPrintf( "SV_RankUserLogin( %d, %s, \"****\" );\n", index, username ); + + if( !s_rankings_active ) + { + Com_DPrintf( "SV_RankUserLogin: Not ready for login\n" ); + s_ranked_players[index].grank_status = QGR_STATUS_ERROR; + return; + } + + if( s_ranked_players[index].grank_status == QGR_STATUS_ACTIVE ) + { + Com_DPrintf( "SV_RankUserLogin: Got Login from active player\n" ); + return; + } + + // get a separate context for the new user + init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END ); + s_ranked_players[index].context = init.context; + s_rankings_contexts++; + Com_DPrintf( "SV_RankUserLogin(); s_rankings_contexts=%d\n",s_rankings_contexts ); + Com_DPrintf( "SV_RankUserLogin(); s_ranked_players[%d].context=%d\n",index,init.context ); + + // login user, proceed to SV_RankUserCBF + status = GRankUserLoginAsync + ( + s_ranked_players[index].context, + username, + password, + SV_RankUserCBF, + (void*)&s_ranked_players[index], + GR_OPT_END + ); + + if( status == GR_STATUS_PENDING ) + { + s_ranked_players[index].grank_status = QGR_STATUS_PENDING; + s_ranked_players[index].final_status = QGR_STATUS_NEW; + } + else + { + SV_RankError( "SV_RankUserLogin: Expected GR_STATUS_PENDING, got %s", + SV_RankStatusString( status ) ); + } +} + +/* +=================== +SV_RankUserValidate +=================== +*/ +qboolean SV_RankUserValidate( int index, const char* player_id, const char* key, int token_len, int rank, char* name ) +{ + GR_INIT init; + GR_STATUS status; + qboolean rVal; + ranked_player_t* ranked_player; + int i; + + assert( s_ranked_players ); + assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE ); + + rVal = qfalse; + + if( !s_rankings_active ) + { + Com_DPrintf( "SV_RankUserValidate: Not ready to validate\n" ); + s_ranked_players[index].grank_status = QGR_STATUS_ERROR; + return rVal; + } + + ranked_player = &(s_ranked_players[index]); + + if ( (player_id != NULL) && (key != NULL)) + { + // the real player_id and key is set when SV_RankJoinGameCBF + // is called we do this so that SV_RankUserValidate + // can be shared by both server side login and client side login + + // for client side logined in players + // server is creating GR_OPT_PLAYERCONTEXT + init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END ); + ranked_player->context = init.context; + s_rankings_contexts++; + Com_DPrintf( "SV_RankUserValidate(); s_rankings_contexts=%d\n",s_rankings_contexts ); + Com_DPrintf( "SV_RankUserValidate(); s_ranked_players[%d].context=%d\n",index,init.context ); + + // uudecode player id and player token + ranked_player->player_id = SV_RankDecodePlayerID(player_id); + Com_DPrintf( "SV_RankUserValidate(); ranked_player->player_id =%u\n", (uint32_t)ranked_player->player_id ); + SV_RankDecodePlayerKey(key, ranked_player->token); + + // save name and check for duplicates + Q_strncpyz( ranked_player->name, name, sizeof(ranked_player->name) ); + for( i = 0; i < sv_maxclients->value; i++ ) + { + if( (i != index) && (s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE) && + (strcmp( s_ranked_players[i].name, name ) == 0) ) + { + Com_DPrintf( "SV_RankUserValidate: Duplicate login\n" ); + ranked_player->grank_status = QGR_STATUS_NO_USER; + ranked_player->final_status = QGR_STATUS_NEW; + ranked_player->grank = 0; + return qfalse; + } + } + + // then validate + status = GRankPlayerValidate( + s_server_context, + ranked_player->player_id, + ranked_player->token, + token_len, + GR_OPT_PLAYERCONTEXT, + ranked_player->context, + GR_OPT_END); + } + else + { + // make server side login (bots) happy + status = GR_STATUS_OK; + } + + if (status == GR_STATUS_OK) + { + ranked_player->grank_status = QGR_STATUS_ACTIVE; + ranked_player->final_status = QGR_STATUS_NEW; + ranked_player->grank = rank; + rVal = qtrue; + } + else if (status == GR_STATUS_INVALIDUSER) + { + ranked_player->grank_status = QGR_STATUS_INVALIDUSER; + ranked_player->final_status = QGR_STATUS_NEW; + ranked_player->grank = 0; + rVal = qfalse; + } + else + { + SV_RankError( "SV_RankUserValidate: Unexpected status %s", + SV_RankStatusString( status ) ); + s_ranked_players[index].grank_status = QGR_STATUS_ERROR; + ranked_player->grank = 0; + } + + return rVal; +} + +/* +================ +SV_RankUserLogout +================ +*/ +void SV_RankUserLogout( int index ) +{ + GR_STATUS status; + GR_STATUS cleanup_status; + + if( !s_rankings_active ) + { + return; + } + + assert( index >= 0 ); + assert( index < sv_maxclients->value ); + assert( s_ranked_players ); + + if( s_ranked_players[index].context == 0 ) { + return; + } + + Com_DPrintf( "SV_RankUserLogout( %d );\n", index ); + + // masqueraded player may not be active yet, if they fail validation, + // but still they have a context needs to be cleaned + // what matters is the s_ranked_players[index].context + + // send reports, proceed to SV_RankSendReportsCBF + status = GRankSendReportsAsync + ( + s_ranked_players[index].context, + 0, + SV_RankSendReportsCBF, + (void*)&s_ranked_players[index], + GR_OPT_END + ); + + if( status == GR_STATUS_PENDING ) + { + s_ranked_players[index].grank_status = QGR_STATUS_PENDING; + s_ranked_players[index].final_status = QGR_STATUS_NEW; + } + else + { + SV_RankError( "SV_RankUserLogout: Expected GR_STATUS_PENDING, got %s", + SV_RankStatusString( status ) ); + + cleanup_status = GRankCleanupAsync + ( + s_ranked_players[index].context, + 0, + SV_RankCleanupCBF, + (void*)&s_ranked_players[index], + GR_OPT_END + ); + + if( cleanup_status != GR_STATUS_PENDING ) + { + SV_RankError( "SV_RankUserLogout: Expected " + "GR_STATUS_PENDING from GRankCleanupAsync, got %s", + SV_RankStatusString( cleanup_status ) ); + SV_RankCloseContext( &(s_ranked_players[index]) ); + } + } +} + +/* +================ +SV_RankReportInt +================ +*/ +void SV_RankReportInt( int index1, int index2, int key, int value, + qboolean accum ) +{ + GR_STATUS status; + GR_CONTEXT context; + uint64_t match; + uint64_t user1; + uint64_t user2; + int opt_accum; + + if( !s_rankings_active ) + { + return; + } + + assert( index1 >= -1 ); + assert( index1 < sv_maxclients->value ); + assert( index2 >= -1 ); + assert( index2 < sv_maxclients->value ); + assert( s_ranked_players ); + +// Com_DPrintf( "SV_RankReportInt( %d, %d, %d, %d, %d );\n", index1, index2, +// key, value, accum ); + + // get context, match, and player_id for player index1 + if( index1 == -1 ) + { + context = s_server_context; + match = s_server_match; + user1 = 0; + } + else + { + if( s_ranked_players[index1].grank_status != QGR_STATUS_ACTIVE ) + { + Com_DPrintf( "SV_RankReportInt: Expecting QGR_STATUS_ACTIVE" + " Got Unexpected status %d for player %d\n", + s_ranked_players[index1].grank_status, index1 ); + return; + } + + context = s_ranked_players[index1].context; + match = s_ranked_players[index1].match; + user1 = s_ranked_players[index1].player_id; + } + + // get player_id for player index2 + if( index2 == -1 ) + { + user2 = 0; + } + else + { + if( s_ranked_players[index2].grank_status != QGR_STATUS_ACTIVE ) + { + Com_DPrintf( "SV_RankReportInt: Expecting QGR_STATUS_ACTIVE" + " Got Unexpected status %d for player %d\n", + s_ranked_players[index2].grank_status, index2 ); + return; + } + + user2 = s_ranked_players[index2].player_id; + } + + opt_accum = accum ? GR_OPT_ACCUM : GR_OPT_END; + + status = GRankReportInt + ( + context, + match, + user1, + user2, + key, + value, + opt_accum, + GR_OPT_END + ); + + if( status != GR_STATUS_OK ) + { + SV_RankError( "SV_RankReportInt: Unexpected status %s", + SV_RankStatusString( status ) ); + } + + if( user2 != 0 ) + { + context = s_ranked_players[index2].context; + match = s_ranked_players[index2].match; + + status = GRankReportInt + ( + context, + match, + user1, + user2, + key, + value, + opt_accum, + GR_OPT_END + ); + + if( status != GR_STATUS_OK ) + { + SV_RankError( "SV_RankReportInt: Unexpected status %s", + SV_RankStatusString( status ) ); + } + } +} + +/* +================ +SV_RankReportStr +================ +*/ +void SV_RankReportStr( int index1, int index2, int key, char* value ) +{ + GR_STATUS status; + GR_CONTEXT context; + uint64_t match; + uint64_t user1; + uint64_t user2; + + if( !s_rankings_active ) + { + return; + } + + assert( index1 >= -1 ); + assert( index1 < sv_maxclients->value ); + assert( index2 >= -1 ); + assert( index2 < sv_maxclients->value ); + assert( s_ranked_players ); + +// Com_DPrintf( "SV_RankReportStr( %d, %d, %d, \"%s\" );\n", index1, index2, +// key, value ); + + // get context, match, and player_id for player index1 + if( index1 == -1 ) + { + context = s_server_context; + match = s_server_match; + user1 = 0; + } + else + { + if( s_ranked_players[index1].grank_status != QGR_STATUS_ACTIVE ) + { + Com_DPrintf( "SV_RankReportStr: Unexpected status %d\n", + s_ranked_players[index1].grank_status ); + return; + } + + context = s_ranked_players[index1].context; + match = s_ranked_players[index1].match; + user1 = s_ranked_players[index1].player_id; + } + + // get player_id for player index2 + if( index2 == -1 ) + { + user2 = 0; + } + else + { + if( s_ranked_players[index2].grank_status != QGR_STATUS_ACTIVE ) + { + Com_DPrintf( "SV_RankReportStr: Unexpected status %d\n", + s_ranked_players[index2].grank_status ); + return; + } + + user2 = s_ranked_players[index2].player_id; + } + + status = GRankReportStr + ( + context, + match, + user1, + user2, + key, + value, + GR_OPT_END + ); + + if( status != GR_STATUS_OK ) + { + SV_RankError( "SV_RankReportStr: Unexpected status %s", + SV_RankStatusString( status ) ); + } + + if( user2 != 0 ) + { + context = s_ranked_players[index2].context; + match = s_ranked_players[index2].match; + + status = GRankReportStr + ( + context, + match, + user1, + user2, + key, + value, + GR_OPT_END + ); + + if( status != GR_STATUS_OK ) + { + SV_RankError( "SV_RankReportInt: Unexpected status %s", + SV_RankStatusString( status ) ); + } + } +} + +/* +================ +SV_RankQuit +================ +*/ +void SV_RankQuit( void ) +{ + int i; + int j = 0; + // yuck + + while( s_rankings_contexts > 1 ) + { + assert(s_ranked_players); + if( s_ranked_players != NULL ) + { + for( i = 0; i < sv_maxclients->value; i++ ) + { + // check for players that weren't yet active in SV_RankEnd + if( s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE ) + { + SV_RankUserLogout( i ); + Com_DPrintf( "SV_RankQuit: SV_RankUserLogout %d\n",i ); + } + else + { + if( s_ranked_players[i].context ) + { + GR_STATUS cleanup_status; + cleanup_status = GRankCleanupAsync + ( + s_ranked_players[i].context, + 0, + SV_RankCleanupCBF, + (void*)&(s_ranked_players[i]), + GR_OPT_END + ); + + if( cleanup_status != GR_STATUS_PENDING ) + { + SV_RankError( "SV_RankQuit: Expected " + "GR_STATUS_PENDING from GRankCleanupAsync, got %s", + SV_RankStatusString( cleanup_status ) ); + } + } + } + } + } + SV_RankPoll(); + + // should've finished by now + assert( (j++) < 68 ); + } +} + +/* +============================================================================== + +Private Functions + +============================================================================== +*/ + +/* +================= +SV_RankNewGameCBF +================= +*/ +static void SV_RankNewGameCBF( GR_NEWGAME* gr_newgame, void* cbf_arg ) +{ + GR_MATCH match; + int i; + + assert( gr_newgame != NULL ); + assert( cbf_arg == NULL ); + + Com_DPrintf( "SV_RankNewGameCBF( %08X, %08X );\n", gr_newgame, cbf_arg ); + + if( gr_newgame->status == GR_STATUS_OK ) + { + char info[MAX_INFO_STRING]; + char gameid[sizeof(s_ranked_players[i].game_id) * 4 / 3 + 2]; + + // save game id + s_rankings_game_id = gr_newgame->game_id; + + // encode gameid + memset(gameid,0,sizeof(gameid)); + SV_RankEncodeGameID(s_rankings_game_id,gameid,sizeof(gameid)); + + // set CS_GRANK rankingsGameID to pass to client + memset(info,0,sizeof(info)); + Info_SetValueForKey( info, "rankingsGameKey", s_rankings_game_key ); + Info_SetValueForKey( info, "rankingsGameID", gameid ); + SV_SetConfigstring( CS_GRANK, info ); + + // initialize client status + for( i = 0; i < sv_maxclients->value; i++ ) + s_ranked_players[i].grank_status = QGR_STATUS_NEW; + + // start new match + match = GRankStartMatch( s_server_context ); + s_server_match = match.match; + + // ready to go + s_rankings_active = qtrue; + Cvar_Set( "sv_rankingsActive", "1" ); + + } + else if( gr_newgame->status == GR_STATUS_BADLEAGUE ) + { + SV_RankError( "SV_RankNewGameCBF: Invalid League name\n" ); + } + else + { + //GRank handle new game failure + // force SV_RankEnd() to run + //SV_RankEnd(); + SV_RankError( "SV_RankNewGameCBF: Unexpected status %s", + SV_RankStatusString( gr_newgame->status ) ); + } +} + +/* +================ +SV_RankUserCBF +================ +*/ +static void SV_RankUserCBF( GR_LOGIN* gr_login, void* cbf_arg ) +{ + ranked_player_t* ranked_player; + GR_STATUS join_status; + GR_STATUS cleanup_status; + + assert( gr_login != NULL ); + assert( cbf_arg != NULL ); + + Com_DPrintf( "SV_RankUserCBF( %08X, %08X );\n", gr_login, cbf_arg ); + + ranked_player = (ranked_player_t*)cbf_arg; + assert(ranked_player); + assert( ranked_player->context ); + + switch( gr_login->status ) + { + case GR_STATUS_OK: + // attempt to join the game, proceed to SV_RankJoinGameCBF + join_status = GRankJoinGameAsync + ( + ranked_player->context, + s_rankings_game_id, + SV_RankJoinGameCBF, + cbf_arg, + GR_OPT_END + ); + + if( join_status != GR_STATUS_PENDING ) + { + SV_RankError( "SV_RankUserCBF: Expected GR_STATUS_PENDING " + "from GRankJoinGameAsync, got %s", + SV_RankStatusString( join_status ) ); + } + break; + case GR_STATUS_NOUSER: + Com_DPrintf( "SV_RankUserCBF: Got status %s\n", + SV_RankStatusString( gr_login->status ) ); + ranked_player->final_status = QGR_STATUS_NO_USER; + break; + case GR_STATUS_BADPASSWORD: + Com_DPrintf( "SV_RankUserCBF: Got status %s\n", + SV_RankStatusString( gr_login->status ) ); + ranked_player->final_status = QGR_STATUS_BAD_PASSWORD; + break; + case GR_STATUS_TIMEOUT: + Com_DPrintf( "SV_RankUserCBF: Got status %s\n", + SV_RankStatusString( gr_login->status ) ); + ranked_player->final_status = QGR_STATUS_TIMEOUT; + break; + default: + Com_DPrintf( "SV_RankUserCBF: Unexpected status %s\n", + SV_RankStatusString( gr_login->status ) ); + ranked_player->final_status = QGR_STATUS_ERROR; + break; + } + + if( ranked_player->final_status != QGR_STATUS_NEW ) + { + // login or create failed, so clean up before the next attempt + cleanup_status = GRankCleanupAsync + ( + ranked_player->context, + 0, + SV_RankCleanupCBF, + (void*)ranked_player, + GR_OPT_END + ); + + if( cleanup_status != GR_STATUS_PENDING ) + { + SV_RankError( "SV_RankUserCBF: Expected GR_STATUS_PENDING " + "from GRankCleanupAsync, got %s", + SV_RankStatusString( cleanup_status ) ); + SV_RankCloseContext( ranked_player ); + } + } +} + +/* +================ +SV_RankJoinGameCBF +================ +*/ +static void SV_RankJoinGameCBF( GR_JOINGAME* gr_joingame, void* cbf_arg ) +{ + ranked_player_t* ranked_player; + GR_MATCH match; + GR_STATUS cleanup_status; + + assert( gr_joingame != NULL ); + assert( cbf_arg != NULL ); + + Com_DPrintf( "SV_RankJoinGameCBF( %08X, %08X );\n", gr_joingame, cbf_arg ); + + ranked_player = (ranked_player_t*)cbf_arg; + + assert( ranked_player ); + assert( ranked_player->context != 0 ); + + if( gr_joingame->status == GR_STATUS_OK ) + { + int i; + // save user id + ranked_player->player_id = gr_joingame->player_id; + memcpy(ranked_player->token,gr_joingame->token, + sizeof(GR_PLAYER_TOKEN)) ; + match = GRankStartMatch( ranked_player->context ); + ranked_player->match = match.match; + ranked_player->grank = gr_joingame->rank; + + // find the index and call SV_RankUserValidate + for (i=0;ivalue;i++) + if ( ranked_player == &s_ranked_players[i] ) + SV_RankUserValidate(i,NULL,NULL,0, gr_joingame->rank,ranked_player->name); + } + else + { + //GRand handle join game failure + SV_RankError( "SV_RankJoinGameCBF: Unexpected status %s", + SV_RankStatusString( gr_joingame->status ) ); + + cleanup_status = GRankCleanupAsync + ( + ranked_player->context, + 0, + SV_RankCleanupCBF, + cbf_arg, + GR_OPT_END + ); + + if( cleanup_status != GR_STATUS_PENDING ) + { + SV_RankError( "SV_RankJoinGameCBF: Expected " + "GR_STATUS_PENDING from GRankCleanupAsync, got %s", + SV_RankStatusString( cleanup_status ) ); + SV_RankCloseContext( ranked_player ); + } + } +} + +/* +================ +SV_RankSendReportsCBF +================ +*/ +static void SV_RankSendReportsCBF( GR_STATUS* status, void* cbf_arg ) +{ + ranked_player_t* ranked_player; + GR_CONTEXT context; + GR_STATUS cleanup_status; + + assert( status != NULL ); + // NULL cbf_arg means server is sending match reports + + Com_DPrintf( "SV_RankSendReportsCBF( %08X, %08X );\n", status, cbf_arg ); + + ranked_player = (ranked_player_t*)cbf_arg; + if( ranked_player == NULL ) + { + Com_DPrintf( "SV_RankSendReportsCBF: server\n" ); + context = s_server_context; + } + else + { + Com_DPrintf( "SV_RankSendReportsCBF: player\n" ); + context = ranked_player->context; + } + + //assert( context != 0 ); + if( *status != GR_STATUS_OK ) + { + SV_RankError( "SV_RankSendReportsCBF: Unexpected status %s", + SV_RankStatusString( *status ) ); + } + + if( context == 0 ) + { + Com_DPrintf( "SV_RankSendReportsCBF: WARNING: context == 0" ); + SV_RankCloseContext( ranked_player ); + } + else + { + cleanup_status = GRankCleanupAsync + ( + context, + 0, + SV_RankCleanupCBF, + cbf_arg, + GR_OPT_END + ); + + if( cleanup_status != GR_STATUS_PENDING ) + { + SV_RankError( "SV_RankSendReportsCBF: Expected " + "GR_STATUS_PENDING from GRankCleanupAsync, got %s", + SV_RankStatusString( cleanup_status ) ); + SV_RankCloseContext( ranked_player ); + } + } +} + +/* +================ +SV_RankCleanupCBF +================ +*/ +static void SV_RankCleanupCBF( GR_STATUS* status, void* cbf_arg ) +{ + ranked_player_t* ranked_player; + ranked_player = (ranked_player_t*)cbf_arg; + + assert( status != NULL ); + // NULL cbf_arg means server is cleaning up + + Com_DPrintf( "SV_RankCleanupCBF( %08X, %08X );\n", status, cbf_arg ); + + if( *status != GR_STATUS_OK ) + { + SV_RankError( "SV_RankCleanupCBF: Unexpected status %s", + SV_RankStatusString( *status ) ); + } + + SV_RankCloseContext( ranked_player ); +} + +/* +================ +SV_RankCloseContext +================ +*/ +static void SV_RankCloseContext( ranked_player_t* ranked_player ) +{ + if( ranked_player == NULL ) + { + // server cleanup + if( s_server_context == 0 ) + { + return; + } + s_server_context = 0; + s_server_match = 0; + } + else + { + // player cleanup + if( s_ranked_players == NULL ) + { + return; + } + if( ranked_player->context == 0 ) + { + return; + } + ranked_player->context = 0; + ranked_player->match = 0; + ranked_player->player_id = 0; + memset( ranked_player->token, 0, sizeof(GR_PLAYER_TOKEN) ); + ranked_player->grank_status = ranked_player->final_status; + ranked_player->final_status = QGR_STATUS_NEW; + ranked_player->name[0] = '\0'; + } + + assert( s_rankings_contexts > 0 ); + s_rankings_contexts--; + Com_DPrintf( "SV_RankCloseContext: s_rankings_contexts = %d\n", + s_rankings_contexts ); + + if( s_rankings_contexts == 0 ) + { + GRankLogLevel( GRLOG_OFF ); + + if( s_ranked_players != NULL ) + { + Z_Free( s_ranked_players ); + s_ranked_players = NULL; + } + + s_rankings_active = qfalse; + Cvar_Set( "sv_rankingsActive", "0" ); + } +} + +/* +================ +SV_RankAsciiEncode + +Encodes src_len bytes of binary data from the src buffer as ASCII text, +using 6 bits per character. The result string is null-terminated and +stored in the dest buffer. + +The dest buffer must be at least (src_len * 4) / 3 + 2 bytes in length. + +Returns the length of the result string, not including the null. +================ +*/ +static int SV_RankAsciiEncode( char* dest, const unsigned char* src, + int src_len ) +{ + unsigned char bin[3]; + unsigned char txt[4]; + int dest_len = 0; + int i; + int j; + int num_chars; + + assert( dest != NULL ); + assert( src != NULL ); + + for( i = 0; i < src_len; i += 3 ) + { + // read three bytes of input + for( j = 0; j < 3; j++ ) + { + bin[j] = (i + j < src_len) ? src[i + j] : 0; + } + + // get four 6-bit values from three bytes + txt[0] = bin[0] >> 2; + txt[1] = ((bin[0] << 4) | (bin[1] >> 4)) & 63; + txt[2] = ((bin[1] << 2) | (bin[2] >> 6)) & 63; + txt[3] = bin[2] & 63; + + // store ASCII encoding of 6-bit values + num_chars = (i + 2 < src_len) ? 4 : ((src_len - i) * 4) / 3 + 1; + for( j = 0; j < num_chars; j++ ) + { + dest[dest_len++] = s_ascii_encoding[txt[j]]; + } + } + + dest[dest_len] = '\0'; + + return dest_len; +} + +/* +================ +SV_RankAsciiDecode + +Decodes src_len characters of ASCII text from the src buffer, stores +the binary result in the dest buffer. + +The dest buffer must be at least (src_len * 3) / 4 bytes in length. + +Returns the length of the binary result, or zero for invalid input. +================ +*/ +static int SV_RankAsciiDecode( unsigned char* dest, const char* src, + int src_len ) +{ + static unsigned char s_inverse_encoding[256]; + static char s_init = 0; + + unsigned char bin[3]; + unsigned char txt[4]; + int dest_len = 0; + int i; + int j; + int num_bytes; + + assert( dest != NULL ); + assert( src != NULL ); + + if( !s_init ) + { + // initialize lookup table for decoding + memset( s_inverse_encoding, 255, sizeof(s_inverse_encoding) ); + for( i = 0; i < 64; i++ ) + { + s_inverse_encoding[s_ascii_encoding[i]] = i; + } + s_init = 1; + } + + for( i = 0; i < src_len; i += 4 ) + { + // read four characters of input, decode them to 6-bit values + for( j = 0; j < 4; j++ ) + { + txt[j] = (i + j < src_len) ? s_inverse_encoding[src[i + j]] : 0; + if (txt[j] == 255) + { + return 0; // invalid input character + } + } + + // get three bytes from four 6-bit values + bin[0] = (txt[0] << 2) | (txt[1] >> 4); + bin[1] = (txt[1] << 4) | (txt[2] >> 2); + bin[2] = (txt[2] << 6) | txt[3]; + + // store binary data + num_bytes = (i + 3 < src_len) ? 3 : ((src_len - i) * 3) / 4; + for( j = 0; j < num_bytes; j++ ) + { + dest[dest_len++] = bin[j]; + } + } + + return dest_len; +} + +/* +================ +SV_RankEncodeGameID +================ +*/ +static void SV_RankEncodeGameID( uint64_t game_id, char* result, + int len ) +{ + assert( result != NULL ); + + if( len < ( ( sizeof(game_id) * 4) / 3 + 2) ) + { + Com_DPrintf( "SV_RankEncodeGameID: result buffer too small\n" ); + result[0] = '\0'; + } + else + { + qint64 gameid = LittleLong64(*(qint64*)&game_id); + SV_RankAsciiEncode( result, (unsigned char*)&gameid, + sizeof(qint64) ); + } +} + +/* +================ +SV_RankDecodePlayerID +================ +*/ +static uint64_t SV_RankDecodePlayerID( const char* string ) +{ + unsigned char buffer[9]; + int len; + qint64 player_id; + + assert( string != NULL ); + + len = strlen (string) ; + Com_DPrintf( "SV_RankDecodePlayerID: string length %d\n",len ); + SV_RankAsciiDecode( buffer, string, len ); + player_id = LittleLong64(*(qint64*)buffer); + return *(uint64_t*)&player_id; +} + +/* +================ +SV_RankDecodePlayerKey +================ +*/ +static void SV_RankDecodePlayerKey( const char* string, GR_PLAYER_TOKEN key ) +{ + unsigned char buffer[1400]; + int len; + assert( string != NULL ); + + len = strlen (string) ; + Com_DPrintf( "SV_RankDecodePlayerKey: string length %d\n",len ); + + memset(key,0,sizeof(GR_PLAYER_TOKEN)); + memset(buffer,0,sizeof(buffer)); + memcpy( key, buffer, SV_RankAsciiDecode( buffer, string, len ) ); +} + +/* +================ +SV_RankStatusString +================ +*/ +static char* SV_RankStatusString( GR_STATUS status ) +{ + switch( status ) + { + case GR_STATUS_OK: return "GR_STATUS_OK"; + case GR_STATUS_ERROR: return "GR_STATUS_ERROR"; + case GR_STATUS_BADPARAMS: return "GR_STATUS_BADPARAMS"; + case GR_STATUS_NETWORK: return "GR_STATUS_NETWORK"; + case GR_STATUS_NOUSER: return "GR_STATUS_NOUSER"; + case GR_STATUS_BADPASSWORD: return "GR_STATUS_BADPASSWORD"; + case GR_STATUS_BADGAME: return "GR_STATUS_BADGAME"; + case GR_STATUS_PENDING: return "GR_STATUS_PENDING"; + case GR_STATUS_BADDOMAIN: return "GR_STATUS_BADDOMAIN"; + case GR_STATUS_DOMAINLOCK: return "GR_STATUS_DOMAINLOCK"; + case GR_STATUS_TIMEOUT: return "GR_STATUS_TIMEOUT"; + case GR_STATUS_INVALIDUSER: return "GR_STATUS_INVALIDUSER"; + case GR_STATUS_INVALIDCONTEXT: return "GR_STATUS_INVALIDCONTEXT"; + default: return "(UNKNOWN)"; + } +} + +/* +================ +SV_RankError +================ +*/ +static void SV_RankError( const char* fmt, ... ) +{ + va_list arg_ptr; + char text[1024]; + + va_start( arg_ptr, fmt ); + vsprintf( text, fmt, arg_ptr ); + va_end( arg_ptr ); + + Com_DPrintf( "****************************************\n" ); + Com_DPrintf( "SV_RankError: %s\n", text ); + Com_DPrintf( "****************************************\n" ); + + s_rankings_active = qfalse; + Cvar_Set( "sv_rankingsActive", "0" ); + // FIXME - attempt clean shutdown? +} + diff --git a/CODE-mp/server/sv_snapshot.cpp b/CODE-mp/server/sv_snapshot.cpp index 7210554..a7a01e3 100644 --- a/CODE-mp/server/sv_snapshot.cpp +++ b/CODE-mp/server/sv_snapshot.cpp @@ -427,6 +427,8 @@ static void SV_BuildClientSnapshot( client_t *client ) { entityNumbers.numSnapshotEntities = 0; Com_Memset( frame->areabits, 0, sizeof( frame->areabits ) ); + frame->num_entities = 0; + clent = client->gentity; if ( !clent || client->state == CS_ZOMBIE ) { return; @@ -527,6 +529,16 @@ Called by SV_SendClientSnapshot and SV_SendClientGameState void SV_SendMessageToClient( msg_t *msg, client_t *client ) { int rateMsec; + // MW - my attempt to fix illegible server message errors caused by + // packet fragmentation of initial snapshot. + while(client->state&&client->netchan.unsentFragments) + { + // send additional message fragments if the last message + // was too large to send at once + Com_Printf ("[ISM]SV_SendClientGameState() [1] for %s, writing out old fragments\n", client->name); + SV_Netchan_TransmitNextFragment(&client->netchan); + } + // record information about the message client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSize = msg->cursize; client->frames[client->netchan.outgoingSequence & PACKET_MASK].messageSent = svs.time; diff --git a/CODE-mp/server/vssver.scc b/CODE-mp/server/vssver.scc new file mode 100644 index 0000000..6189189 Binary files /dev/null and b/CODE-mp/server/vssver.scc differ diff --git a/CODE-mp/servercache.dat b/CODE-mp/servercache.dat new file mode 100644 index 0000000..9479b6b Binary files /dev/null and b/CODE-mp/servercache.dat differ diff --git a/CODE-mp/smartheap/HA312W32.DLL b/CODE-mp/smartheap/HA312W32.DLL new file mode 100644 index 0000000..2b1ea82 Binary files /dev/null and b/CODE-mp/smartheap/HA312W32.DLL differ diff --git a/CODE-mp/smartheap/HAW32M.LIB b/CODE-mp/smartheap/HAW32M.LIB new file mode 100644 index 0000000..1fc259c Binary files /dev/null and b/CODE-mp/smartheap/HAW32M.LIB differ diff --git a/CODE-mp/smartheap/HEAPAGNT.H b/CODE-mp/smartheap/HEAPAGNT.H new file mode 100644 index 0000000..6dbdb8c --- /dev/null +++ b/CODE-mp/smartheap/HEAPAGNT.H @@ -0,0 +1,442 @@ +/* heapagnt.h -- HeapAgent (tm) public C/C++ header file + * + * Copyright (C) 1991-1997 Compuware Corporation. + * All Rights Reserved. + * + * No part of this source code may be copied, modified or reproduced + * in any form without retaining the above copyright notice. + * This source code, or source code derived from it, may not be redistributed + * without express written permission of the copyright owner. + * + */ + +#if !defined(_HEAPAGNT_H) +#define _HEAPAGNT_H + +#if !defined(_SMARTHEAP_H) +#include "smrtheap.h" +#endif /* _SMARTHEAP_H */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#define HA_MAJOR_VERSION 3 +#define HA_MINOR_VERSION 1 +#define HA_UPDATE_LEVEL 2 + + +/*** Types ***/ + +/* Saftey Levels: parameter to dbgMemSetSafetyLevel */ +typedef enum +{ + MEM_SAFETY_SOME=2, /* fast: minimal debug performance degredation */ + MEM_SAFETY_FULL, /* slower: recommended during development */ + MEM_SAFETY_DEBUG, /* entire memory pool is checked each entrypoint */ + MEM_SAFETY_LEVEL_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_SAFETY_LEVEL; + +/* Pointer types: parameter to dbgMemCheckPtr */ +typedef enum +{ + MEM_POINTER_HEAP, + MEM_POINTER_STACK, + MEM_POINTER_STATIC, + MEM_POINTER_CODE, + MEM_POINTER_READONLY, + MEM_POINTER_READWRITE +} MEM_POINTER_TYPE; + +/* Debug Pool Info: parameter to dbgMemPoolInfo */ +typedef struct +{ + MEM_POOL pool; + const char MEM_FAR *name; + MEM_API createAPI; + const char MEM_FAR *createFile; + int createLine; + unsigned long createPass; + unsigned long createAllocCount; + unsigned createCheckpoint; + int isDeferFreeing; + unsigned long deferQueueLength; + unsigned checkFrequency; + MEM_ERROR_INFO lastOkInfo; + unsigned long threadID; + unsigned long pid; + void *callStack[MEM_MAXCALLSTACK]; +} DBGMEM_POOL_INFO; + +/* Debug Ptr Info: parameter to dbgMemPtrInfo */ +typedef struct +{ + void MEM_FAR *ptr; + MEM_POOL pool; + unsigned long argSize; + MEM_BLOCK_TYPE blockType; + MEM_BOOL isInUse; + MEM_API createAPI; + const char MEM_FAR *createFile; + int createLine; + unsigned long createPass; + unsigned checkpoint; + unsigned long allocCount; + MEM_BOOL isDeferFreed; + MEM_BOOL isFreeFillSuppressed; + MEM_BOOL isReadOnly; + MEM_BOOL isNoFree; + MEM_BOOL isNoRealloc; + unsigned long threadID; + unsigned long pid; + void MEM_FAR *callStack[MEM_MAXCALLSTACK]; +} DBGMEM_PTR_INFO; + +/* Stack checking settting: parameter to dbgMemSetStackChecking */ +typedef enum +{ + DBGMEM_STACK_CHECK_NONE=1, + DBGMEM_STACK_CHECK_ENTRY, + DBGMEM_STACK_CHECK_RETURN, + DBGMEM_STACK_CHECK_INT_MAX = INT_MAX /* to ensure enum is full int size */ +} DBGMEM_STACK_CHECKING; + +/* Debug Settings Info: parameter to dbgMemSettingsInfo */ +typedef struct +{ + MEM_SAFETY_LEVEL safetyLevel; + unsigned checkFrequency; + unsigned long allocCount; + unsigned checkpoint; + MEM_BOOL isDeferFreeing; + unsigned long deferQueueLength; + unsigned long deferSizeThreshold; + MEM_BOOL isFreeFillSuppressed; + MEM_BOOL isReallocAlwaysMoves; + MEM_BOOL isWrongTaskRefReported; + unsigned outputFlags; + const char MEM_FAR *outputFile; + unsigned guardSize; + unsigned callstackChains; + DBGMEM_STACK_CHECKING stackChecking; + unsigned char guardFill; + unsigned char freeFill; + unsigned char inUseFill; +} DBGMEM_SETTINGS_INFO; + +/* Trace function pointer: parameter to dbgMemSet[Entry/Exit]Handler */ +typedef void (MEM_ENTRY2 * MEM_ENTRY3 MEM_TRACE_FN) + (MEM_ERROR_INFO MEM_FAR *, unsigned long); + +/* define and initialize these variables at file scope to change defaults */ +extern const unsigned dbgMemGuardSize; +extern const unsigned char dbgMemGuardFill; +extern const unsigned char dbgMemFreeFill; +extern const unsigned char dbgMemInUseFill; + +#define DBGMEM_PTR_NOPROTECTION 0x0000u +#define DBGMEM_PTR_READONLY 0x0001u +#define DBGMEM_PTR_NOFREE 0x0002u +#define DBGMEM_PTR_NOREALLOC 0x0004u + +#define DBGMEM_OUTPUT_PROMPT 0x0001u +#define DBGMEM_OUTPUT_CONSOLE 0x0002u +#define DBGMEM_OUTPUT_BEEP 0x0004u +#define DBGMEM_OUTPUT_FILE 0x0010u +#define DBGMEM_OUTPUT_FILE_APPEND 0x0020u + + + +/*** Function Prototypes ***/ + +#ifdef MEM_DEBUG + +#if defined(MEM_WIN16) || defined(MEM_WIN32) +#define SHI_MAJOR_VERSION HA_MAJOR_VERSION +#define SHI_MINOR_VERSION HA_MINOR_VERSION +#define SHI_UPDATE_LEVEL HA_UPDATE_LEVEL +#endif /* MEM_WIN16 || MEM_WIN32 */ + +/* malloc, new, et al call these entry-point in debug lib */ +MEM_ENTRY1 void MEM_FAR * MEM_ENTRY _dbgMemAllocPtr1(MEM_POOL, unsigned long, + unsigned, MEM_API, const char MEM_FAR *, int); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _dbgMemFreePtr1(void MEM_FAR *, MEM_API, + const char MEM_FAR *, int); +MEM_ENTRY1 void MEM_FAR * MEM_ENTRY _dbgMemReAllocPtr1(void MEM_FAR *, + unsigned long, unsigned, MEM_API, const char MEM_FAR *, int); +MEM_ENTRY1 unsigned long MEM_ENTRY _dbgMemSizePtr1(void MEM_FAR *, MEM_API, + const char MEM_FAR *, int); +void MEM_FAR * MEM_ENTRY _dbgMEM_alloc(size_t, unsigned, MEM_API, + const char MEM_FAR *, int); +void MEM_FAR * MEM_ENTRY _dbgMEM_realloc(void MEM_FAR *, size_t, + const char MEM_FAR *, int); +void MEM_ENTRY _dbgMEM_free(void MEM_FAR *, const char MEM_FAR *, int); +MEM_ENTRY1 void MEM_ENTRY _shi_deleteLoc(const char MEM_FAR *file, int line); + + +/* functions to control error detection */ +MEM_ENTRY1 MEM_SAFETY_LEVEL MEM_ENTRY dbgMemSetSafetyLevel(MEM_SAFETY_LEVEL); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY dbgMemSetGuardSize(unsigned); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY dbgMemSetGuardFill(MEM_UCHAR); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY dbgMemSetFreeFill(MEM_UCHAR); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY dbgMemSetInUseFill(MEM_UCHAR); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY dbgMemSetCallstackChains(unsigned); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY dbgMemSetStackChecking(DBGMEM_STACK_CHECKING); +MEM_ENTRY1 unsigned MEM_ENTRY dbgMemSetCheckpoint(unsigned); +MEM_ENTRY1 unsigned MEM_ENTRY _dbgMemPoolSetCheckFrequency(MEM_POOL, + unsigned, const char MEM_FAR *, int); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _dbgMemPoolDeferFreeing(MEM_POOL, int, + const char MEM_FAR *, int); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _dbgMemPoolFreeDeferred(MEM_POOL, + const char MEM_FAR *, int); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _dbgMemProtectPtr(void MEM_FAR *, unsigned, + const char MEM_FAR *, int); + +/* functions to control error reporting */ +MEM_ENTRY1 unsigned MEM_ENTRY dbgMemFormatErrorInfo(MEM_ERROR_INFO MEM_FAR *, + char MEM_FAR *, unsigned); +MEM_ENTRY1 unsigned MEM_ENTRY dbgMemFormatCall(MEM_ERROR_INFO MEM_FAR *, + char MEM_FAR *, unsigned); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY dbgMemSetDefaultErrorOutput(unsigned flags, + const char MEM_FAR *file); +MEM_ENTRY1 MEM_TRACE_FN MEM_ENTRY dbgMemSetEntryHandler(MEM_TRACE_FN); +MEM_ENTRY1 MEM_TRACE_FN MEM_ENTRY dbgMemSetExitHandler(MEM_TRACE_FN); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _dbgMemReportLeakage(MEM_POOL,unsigned,unsigned, + const char MEM_FAR *, unsigned); + +MEM_ENTRY1 unsigned long MEM_ENTRY _dbgMemTotalCount(const char MEM_FAR *, int); +MEM_ENTRY1 unsigned long MEM_ENTRY _dbgMemTotalSize(const char MEM_FAR *, int); +MEM_ENTRY1 void MEM_ENTRY _dbgMemBreakpoint(const char MEM_FAR *, int); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _dbg_MemPoolInfo(MEM_POOL, + DBGMEM_POOL_INFO MEM_FAR *, const char MEM_FAR *, int); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _dbgMemPtrInfo(void MEM_FAR *, + DBGMEM_PTR_INFO MEM_FAR *, const char MEM_FAR *, int); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _dbgMemSettingsInfo( + DBGMEM_SETTINGS_INFO MEM_FAR *, const char MEM_FAR *, int); +MEM_ENTRY1 unsigned MEM_ENTRY dbgMemSetCheckFrequency(unsigned); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY dbgMemDeferFreeing(MEM_BOOL); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _dbgMemFreeDeferred(const char MEM_FAR *, int); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY dbgMemReallocMoves(MEM_BOOL); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY dbgMemSuppressFreeFill(MEM_BOOL); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY dbgMemReportWrongTaskRef(MEM_BOOL); +MEM_ENTRY1 unsigned long MEM_ENTRY dbgMemSetDeferQueueLen(unsigned long); +MEM_ENTRY1 unsigned long MEM_ENTRY dbgMemSetDeferSizeThreshold(unsigned long); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _dbgMemPoolSetName(MEM_POOL, + const char MEM_FAR *, const char MEM_FAR *, int); +MEM_ENTRY1 unsigned long MEM_ENTRY _dbgMemPoolSetDeferQueueLen(MEM_POOL, + unsigned long, const char MEM_FAR *, int); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _dbgMemCheckAll(const char MEM_FAR *, int); +MEM_POOL_STATUS MEM_ENTRY _dbgMemWalkHeap( + MEM_POOL_ENTRY MEM_FAR *, const char MEM_FAR *, int); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _dbg_MemCheckPtr(void MEM_FAR *, + MEM_POINTER_TYPE, unsigned long, const char MEM_FAR *, int); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY dbgMemScheduleChecking(MEM_BOOL, int, unsigned); +#endif + + +/* Wrapper macros for passing file/line info */ + +#ifndef _SHI_dbgMacros +#ifdef MEM_DEBUG +#ifndef MALLOC_MACRO +#define MEM_malloc(s_) _dbgMEM_alloc(s_, 0, MEM_MEM_MALLOC, __FILE__, __LINE__) +#define MEM_calloc(s_, c_) _dbgMEM_alloc((s_)*(c_), 1 /*MEM_ZEROINIT*/, \ + MEM_MEM_CALLOC, __FILE__, __LINE__) +#define MEM_realloc(p_, s_) _dbgMEM_realloc(p_, s_, __FILE__, __LINE__) +#define MEM_free(p_) _dbgMEM_free(p_, __FILE__, __LINE__) +#endif +#if !defined(NO_MALLOC_MACRO) +#ifdef malloc +#undef malloc +#endif +#ifdef calloc +#undef calloc +#endif +#ifdef realloc +#undef realloc +#endif +#ifdef free +#undef free +#endif +#define malloc(s_) MEM_malloc(s_) +#define calloc(s_, c_) MEM_calloc(s_, c_) +#define realloc(p_, s_) MEM_realloc(p_, s_) +#define free(p_) MEM_free(p_) +#endif /* NO_MALLOC_MACRO */ + +#define dbgMemPoolSetCheckFrequency(p, b) \ + _dbgMemPoolSetCheckFrequency(p, b, __FILE__, __LINE__) +#define dbgMemPoolDeferFreeing(p, b) \ + _dbgMemPoolDeferFreeing(p, b, __FILE__, __LINE__) +#define dbgMemPoolFreeDeferred(p) _dbgMemPoolFreeDeferred(p,__FILE__,__LINE__) +#define dbgMemProtectPtr(p, b) _dbgMemProtectPtr(p, b, __FILE__, __LINE__) +#define dbgMemReportLeakage(p, c1, c2) \ + _dbgMemReportLeakage(p, c1, c2, __FILE__, __LINE__) + +#define dbgMemTotalCount() _dbgMemTotalCount(__FILE__, __LINE__) +#define dbgMemTotalSize() _dbgMemTotalSize(__FILE__, __LINE__) +#define dbgMemPoolInfo(p, b) _dbg_MemPoolInfo(p, b, __FILE__, __LINE__) +#define dbgMemPtrInfo(p, b) _dbgMemPtrInfo(p, b, __FILE__, __LINE__) +#define dbgMemSettingsInfo(b) _dbgMemSettingsInfo(b, __FILE__, __LINE__) +#define dbgMemPoolSetName(p, n) _dbgMemPoolSetName(p, n, __FILE__, __LINE__) +#define dbgMemPoolSetDeferQueueLen(p, l) \ + _dbgMemPoolSetDeferQueueLen(p, l, __FILE__, __LINE__) +#define dbgMemFreeDeferred() _dbgMemFreeDeferred(__FILE__, __LINE__) +#define dbgMemWalkHeap(b) _dbgMemWalkHeap(b, __FILE__, __LINE__) +#define dbgMemCheckAll() _dbgMemCheckAll(__FILE__, __LINE__) +#define dbgMemCheckPtr(p, t, s) _dbg_MemCheckPtr(p, t, s, __FILE__, __LINE__) +#define dbgMemBreakpoint() _dbgMemBreakpoint(__FILE__, __LINE__) + +#endif /* MEM_DEBUG */ +#endif /* _SHI_dbgMacros */ + + +#ifdef __cplusplus +} + +#ifndef __BORLANDC__ +/* Borland C++ does not treat extern "C++" correctly */ +extern "C++" +{ +#endif /* __BORLANDC__ */ + +#if defined(_MSC_VER) && _MSC_VER >= 900 +#pragma warning(disable : 4507) +#endif + +#if defined(new) +#if defined(MEM_DEBUG) +#undef new +#define DEFINE_NEW_MACRO 1 +#endif +#endif + +#ifdef DEBUG_NEW +#undef DEBUG_NEW +#endif +#ifdef DEBUG_DELETE +#undef DEBUG_DELETE +#endif + +#ifdef MEM_DEBUG +#define DBG_FORMAL , const char MEM_FAR *file, int line +#define DBG_ACTUAL , file, line + + +/* both debug and non-debug versions are both defined so that calls + * to shi_New from inline versions of operator new in modules + * that were not recompiled with MEM_DEBUG will resolve correctly + */ +void MEM_FAR * MEM_ENTRY_ANSI shi_New(unsigned long DBG_FORMAL, unsigned=0, + MEM_POOL=0); + +/* operator new variants: */ + +/* compiler-specific versions of new */ +#if UINT_MAX == 0xFFFFu +#if defined(__BORLANDC__) +#if (defined(__LARGE__) || defined(__COMPACT__) || defined(__HUGE__)) +inline void far *operator new(unsigned long sz DBG_FORMAL) + { return shi_New(sz DBG_ACTUAL); } +#if __BORLANDC__ >= 0x450 +inline void MEM_FAR *operator new[](unsigned long sz DBG_FORMAL) + { return shi_New(sz DBG_ACTUAL); } +#endif /* __BORLANDC__ >= 0x450 */ +#endif /* __LARGE__ */ + +#elif defined(_MSC_VER) +#if (defined(M_I86LM) || defined(M_I86CM) || defined(M_I86HM)) +inline void __huge * operator new(unsigned long count, size_t sz DBG_FORMAL) + { return (void __huge *)shi_New(count * sz DBG_ACTUAL, MEM_HUGE); } +#endif /* M_I86LM */ +#endif /* _MSC_VER */ + +#endif /* compiler-specific versions of new */ + +/* version of new that passes memory allocation flags */ +inline void MEM_FAR *operator new(size_t sz DBG_FORMAL, unsigned flags) + { return shi_New(sz DBG_ACTUAL, flags); } + +/* version of new that allocates from a specified memory pool with alloc flags*/ +inline void MEM_FAR *operator new(size_t sz DBG_FORMAL, MEM_POOL pool) + { return shi_New(sz DBG_ACTUAL, 0, pool); } +inline void MEM_FAR *operator new(size_t sz DBG_FORMAL, MEM_POOL pool, + unsigned flags) + { return shi_New(sz DBG_ACTUAL, flags, pool); } +#ifdef SHI_ARRAY_NEW +inline void MEM_FAR *operator new[](size_t sz DBG_FORMAL, MEM_POOL pool) + { return shi_New(sz DBG_ACTUAL, 0, pool); } +inline void MEM_FAR *operator new[](size_t sz DBG_FORMAL, MEM_POOL pool, + unsigned flags) + { return shi_New(sz DBG_ACTUAL, flags, pool); } +#endif /* SHI_ARRAY_NEW */ + +/* version of new that changes the size of a memory block */ +inline void MEM_FAR *operator new(size_t new_sz DBG_FORMAL, + void MEM_FAR *lpMem, unsigned flags) + { return _dbgMemReAllocPtr1(lpMem, new_sz, flags, MEM_NEW DBG_ACTUAL); } +#ifdef SHI_ARRAY_NEW +inline void MEM_FAR *operator new[](size_t new_sz DBG_FORMAL, + void MEM_FAR *lpMem, unsigned flags) + { return _dbgMemReAllocPtr1(lpMem, new_sz, flags, MEM_NEW DBG_ACTUAL); } +#endif /* SHI_ARRAY_NEW */ + +/* To have HeapAgent track file/line of C++ allocations, + * define new/delete as macros: + * #define new DEBUG_NEW + * #define delete DEBUG_DELETE + * + * In cases where you use explicit placement syntax, or in modules that define + * operator new/delete, you must undefine the new/delete macros, e.g.: + * #undef new + * void *x = new(placementArg) char[30]; // cannot track file/line info + * #define new DEBUG_NEW + * void *y = new char[20]; // resume tracking file/line info + */ + +#if (!(defined(_AFX) && defined(_DEBUG)) \ + && !(defined(_MSC_VER) && _MSC_VER >= 900)) +/* this must be defined out-of-line for _DEBUG MFC and MEM_DEBUG VC++/Win32 */ +inline void MEM_FAR *operator new(size_t sz DBG_FORMAL) + { return shi_New(sz DBG_ACTUAL); } +#else +void MEM_FAR * MEM_ENTRY_ANSI operator new(size_t sz DBG_FORMAL); +#endif /* _AFX && _DEBUG */ + +#ifdef SHI_ARRAY_NEW +inline void MEM_FAR *operator new[](size_t sz DBG_FORMAL) + { return shi_New(sz DBG_ACTUAL); } +#endif /* SHI_ARRAY_NEW */ + +#if !(defined(__IBMCPP__) && defined(__DEBUG_ALLOC__)) +/* debug new/delete built in for IBM Set C++ and Visual Age C++ */ + +#define DEBUG_NEW new(__FILE__, __LINE__) +#define DEBUG_NEW1(x_) new(__FILE__, __LINE__, x_) +#define DEBUG_NEW2(x_, y_) new(__FILE__, __LINE__, x_, y_) +#define DEBUG_NEW3(x_, y_, z_) new(__FILE__, __LINE__, x_, y_, z_) + +#define DEBUG_DELETE _shi_deleteLoc(__FILE__, __LINE__), delete + +#ifdef DEFINE_NEW_MACRO +#ifdef macintosh /* MPW C++ bug precludes new --> DEBUG_NEW --> new(...) */ +#define new new(__FILE__, __LINE__) +#define delete _shi_deleteLoc(__FILE__, __LINE__), delete +#else +#define new DEBUG_NEW +#define delete DEBUG_DELETE +#endif /* macintosh */ +#endif /* DEFINE_NEW_MACRO */ +#endif /* __IBMCPP__ */ +#endif /* MEM_DEBUG */ + +#include "smrtheap.hpp" + +#ifndef __BORLANDC__ +} +#endif /* __BORLANDC__ */ + +#endif /* __cplusplus */ + +#endif /* !defined(_HEAPAGNT_H) */ diff --git a/CODE-mp/smartheap/SHW32.DLL b/CODE-mp/smartheap/SHW32.DLL new file mode 100644 index 0000000..42b2f67 Binary files /dev/null and b/CODE-mp/smartheap/SHW32.DLL differ diff --git a/CODE-mp/smartheap/SMRTHEAP.C b/CODE-mp/smartheap/SMRTHEAP.C new file mode 100644 index 0000000..925f52d --- /dev/null +++ b/CODE-mp/smartheap/SMRTHEAP.C @@ -0,0 +1,54 @@ +extern int SmartHeap_malloc; +extern int SmartHeap_new; + +static void *refSmartHeap_malloc = &SmartHeap_malloc; + +#if defined(_DEBUG) && !defined(MEM_DEBUG) +#define MEM_DEBUG 1 +#endif + +#if defined(MFC) && !defined(_AFXDLL) + +static void *refSmartHeap_new = &SmartHeap_new; + +#ifdef MEM_DEBUG +#if _MSC_VER < 1000 +#pragma comment(lib, "hamfc32m.lib") +#else +#pragma comment(lib, "hamfc4m.lib") +#endif /* _MSC_VER */ +#else +#if _MSC_VER >= 1000 +#ifdef _MT +#pragma comment(lib, "shmfc4mt.lib") +#else +#pragma comment(lib, "shmfc4m.lib") +#endif /* _MT */ +#endif /* _MSC_VER */ +#endif /* MEM_DEBUG */ + +#endif /* MFC */ + +#if defined(MEM_DEBUG) +#pragma comment(lib, "haw32m.lib") +#elif defined(_DLL) +#ifdef _MT +#ifdef MEM_SMP +#pragma comment(lib, "shdsmpmt.lib") +#else +#pragma comment(lib, "shdw32mt.lib") +#endif /* MEM_SMP */ +#else +#pragma comment(lib, "shdw32m.lib") +#endif /* _MT */ +#else /* _DLL */ +#ifdef _MT +#ifdef MEM_SMP +#pragma comment(lib, "shlsmpmt.lib") +#else +#pragma comment(lib, "shlw32mt.lib") +#endif /* MEM_SMP */ +#else +#pragma comment(lib, "shlw32m.lib") +#endif /* _MT */ +#endif /* MEM_DEBUG */ diff --git a/CODE-mp/smartheap/SMRTHEAP.H b/CODE-mp/smartheap/SMRTHEAP.H new file mode 100644 index 0000000..90bce42 --- /dev/null +++ b/CODE-mp/smartheap/SMRTHEAP.H @@ -0,0 +1,847 @@ +/* smrtheap.h -- SmartHeap (tm) public C header file + * Professional Memory Management Library + * + * Copyright (C) 1991-1999 Compuware Corporation. + * All Rights Reserved. + * + * No part of this source code may be copied, modified or reproduced + * in any form without retaining the above copyright notice. + * This source code, or source code derived from it, may not be redistributed + * without express written permission of the author. + * + */ + +#if !defined(_SMARTHEAP_H) +#define _SMARTHEAP_H + +#include +#include + +#if !defined(macintosh) && !defined(THINK_C) && !defined(__MWERKS__) \ + && !defined(SHANSI) && UINT_MAX == 0xFFFFu \ + && (defined(_Windows) || defined(_WINDOWS) || defined(__WINDOWS__)) + #define MEM_WIN16 +#endif + +#if (UINT_MAX == 0xFFFFu) && (defined(MEM_WIN16) \ + || defined(MSDOS) || defined(__MSDOS__) || defined(__DOS__)) + /* 16-bit X86 */ + #if defined(SYS_DLL) + #if defined(_MSC_VER) && _MSC_VER <= 600 + #define MEM_ENTRY _export _loadds far pascal + #else + #define MEM_ENTRY _export far pascal + #endif + #else + #define MEM_ENTRY far pascal + #endif + #ifdef __WATCOMC__ + #define MEM_ENTRY_ANSI __far + #else + #define MEM_ENTRY_ANSI far cdecl + #endif + #define MEM_FAR far + #if defined(MEM_WIN16) + #define MEM_ENTRY2 _export far pascal + #elif defined(DOS16M) || defined(DOSX286) + #define MEM_ENTRY2 _export _loadds far pascal + #endif + +#else /* not 16-bit X86 */ + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) \ + || defined(__WIN32__) || defined(__NT__) + #define MEM_WIN32 + #if defined(_MSC_VER) + #if defined(_SHI_Pool) && defined(SYS_DLL) + #define MEM_ENTRY1 __declspec(dllexport) + #define MEM_ENTRY4 __declspec(dllexport) extern + #elif !defined(_SHI_Pool) && (defined(MEM_DEBUG) || defined(MEM_DLL)) + #define MEM_ENTRY1 __declspec(dllimport) + #if defined(_M_IX86) || defined(_X86_) + #define MemDefaultPool shi_MemDefaultPool + #define MEM_ENTRY4 __declspec(dllimport) + #endif + #endif + #endif + #if (defined(_MT) || defined(__MT__)) && !defined(MEM_DEBUG) +/* @@@ #define MEM_MT 1 */ + #endif + #if !defined(_MSC_VER) || defined(_M_IX86) || defined(_X86_) + #define MEM_ENTRY __stdcall + #else + #define MEM_ENTRY __cdecl /* for NT/RISC */ + #endif + #ifndef __WATCOMC__ + #define MEM_ENTRY_ANSI __cdecl + #endif + +#elif defined(__OS2__) + #if defined(__BORLANDC__) || defined(__WATCOMC__) + #if defined(SYS_DLL) + #define MEM_ENTRY __export __syscall + #else + #define MEM_ENTRY __syscall + #endif /* SYS_DLL */ + #ifdef __BORLANDC__ + #define MEM_ENTRY_ANSI __stdcall + #endif + #elif defined(__IBMC__) || defined(__IBMCPP__) + #if defined(SYS_DLL) && 0 + #define MEM_ENTRY _Export _System + #else + #define MEM_ENTRY _System + #endif + #define MEM_ENTRY_ANSI _Optlink + #define MEM_ENTRY3 MEM_ENTRY + #define MEM_CALLBACK MEM_ENTRY3 + #define MEM_ENTRY2 + #endif + +#elif defined(__sun) || defined(__hpux) || defined(__osf__) || defined(sgi) + #if defined(_REENTRANT) && !defined(MEM_DEBUG) +/* @@@ #define MEM_MT 1 */ + #endif + +#elif defined(_AIX) + #if defined(_THREAD_SAFE) && !defined(MEM_DEBUG) +/* #define MEM_MT 1 */ + #endif + +#endif /* WIN32, OS2, UNIX */ + +#if defined(__WATCOMC__) && defined(__SW_3S) + /* Watcom stack calling convention */ +#ifndef __OS2__ +#ifdef __WINDOWS_386__ + #pragma aux syscall "*_" parm routine [eax ebx ecx edx fs gs] modify [eax]; +#else + #pragma aux syscall "*_" parm routine [eax ebx ecx edx] modify [eax]; +#endif +#ifndef MEM_ENTRY + #define MEM_ENTRY __syscall +#endif /* MEM_ENTRY */ +#endif +#endif /* Watcom stack calling convention */ + +#endif /* end of system-specific declarations */ + +#ifndef MEM_ENTRY + #define MEM_ENTRY +#endif +#ifndef MEM_ENTRY1 + #define MEM_ENTRY1 +#endif +#ifndef MEM_ENTRY2 + #define MEM_ENTRY2 MEM_ENTRY +#endif +#ifndef MEM_ENTRY3 + #define MEM_ENTRY3 +#endif +#ifndef MEM_ENTRY4 + #define MEM_ENTRY4 extern +#endif +#ifndef MEM_CALLBACK +#define MEM_CALLBACK MEM_ENTRY2 +#endif +#ifndef MEM_ENTRY_ANSI + #define MEM_ENTRY_ANSI +#endif +#ifndef MEM_FAR + #define MEM_FAR +#endif + +#ifdef applec +/* Macintosh: Apple MPW C/C++ passes char/short parms as longs (4 bytes), + * whereas Symantec C/C++ for MPW passes these as words (2 bytes); + * therefore, canonicalize all integer parms as 'int' for this platform. + */ + #define MEM_USHORT unsigned + #define MEM_UCHAR unsigned +#else + #define MEM_USHORT unsigned short + #define MEM_UCHAR unsigned char +#endif /* applec */ + +#ifdef __cplusplus +extern "C" { +#endif + + +#if !defined(MEM_DEBUG) || !(defined(MEM_WIN16) || defined(MEM_WIN32)) +#define SHI_MAJOR_VERSION 5 +#define SHI_MINOR_VERSION 0 +#define SHI_UPDATE_LEVEL 0 +#endif /* !(MEM_WIN16 || MEM_WIN32) */ + + +/*** Types ***/ + +typedef int MEM_BOOL; + +/* Version Masks */ +typedef unsigned MEM_VERSION; +#define MEM_MAJOR_VERSION(v) (((v) & 0xF000u) >> 12) +#define MEM_MINOR_VERSION(v) (((v) & 0x0F00u) >> 8) +#define MEM_UPDATE_VERSION(v) ((v) & 0x00FFu) + +/* Note: these types are struct's rather than integral types to facilitate + * compile-time type-checking. MEM_POOL and MEM_HANDLE should be regarded + * as black boxes, and treated just like handles. + * You should not have any type casts to or from MEM_POOL or MEM_HANDLE; + * nor should you dereference variables of type MEM_POOL or MEM_HANDLE + * (unless you are using SmartHeap to replace NewHandle on the Mac, and + * you have existing code that dereferences handles). + */ +#ifdef _SHI_Pool + typedef struct _SHI_Pool MEM_FAR *MEM_POOL; + typedef struct _SHI_MovHandle MEM_FAR *MEM_HANDLE; +#else + #ifdef THINK_C + typedef void *MEM_POOL; + typedef void **MEM_HANDLE; + #else + typedef struct _SHI_Pool { int reserved; } MEM_FAR *MEM_POOL; + typedef struct _SHI_MovHandle { int reserved; } MEM_FAR *MEM_HANDLE; + #endif +#endif + + +/* Error codes: errorCode field of MEM_ERROR_INFO */ +typedef enum +{ + MEM_NO_ERROR=0, + MEM_INTERNAL_ERROR, + MEM_OUT_OF_MEMORY, + MEM_BLOCK_TOO_BIG, + MEM_ALLOC_ZERO, + MEM_RESIZE_FAILED, + MEM_LOCK_ERROR, + MEM_EXCEEDED_CEILING, + MEM_TOO_MANY_PAGES, + MEM_TOO_MANY_TASKS, + MEM_BAD_MEM_POOL, + MEM_BAD_BLOCK, + MEM_BAD_FREE_BLOCK, + MEM_BAD_HANDLE, + MEM_BAD_POINTER, + MEM_WRONG_TASK, + MEM_NOT_FIXED_SIZE, + MEM_BAD_FLAGS, +#ifdef MEM_DEBUG + MEM_BAD_BUFFER, + MEM_DOUBLE_FREE, + MEM_UNDERWRITE, + MEM_OVERWRITE, + MEM_FREE_BLOCK_WRITE, + MEM_READONLY_MODIFIED, + MEM_NOFREE, + MEM_NOREALLOC, + MEM_LEAKAGE, + MEM_FREE_BLOCK_READ, + MEM_UNINITIALIZED_READ, + MEM_UNINITIALIZED_WRITE, + MEM_OUT_OF_BOUNDS_READ, + MEM_UNDERWRITE_STACK, + MEM_OVERWRITE_STACK, + MEM_FREE_STACK_READ, + MEM_UNINITIALIZED_READ_STACK, + MEM_UNINITIALIZED_WRITE_STACK, + MEM_OUT_OF_BOUNDS_READ_STACK, + MEM_LASTOK, + MEM_BREAKPOINT, + MEM_ERROR_CODE_COUNT, +#endif /* MEM_DEBUG */ + MEM_ERROR_CODE_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_ERROR_CODE; + +/* HeapAgent Entry-Point API identifiers: errorAPI field of MEM_ERROR_INFO */ +typedef enum +{ + MEM_NO_API, + MEM_MEMVERSION, + MEM_MEMREGISTERTASK, + MEM_MEMUNREGISTERTASK, + MEM_MEMPOOLINIT, + MEM_MEMPOOLINITFS, + MEM_MEMPOOLFREE, + MEM_MEMPOOLSETPAGESIZE, + MEM_MEMPOOLSETBLOCKSIZEFS, + MEM_MEMPOOLSETFLOOR, + MEM_MEMPOOLSETCEILING, + MEM_MEMPOOLPREALLOCATE, + MEM_MEMPOOLPREALLOCATEHANDLES, + MEM_MEMPOOLSHRINK, + MEM_MEMPOOLSIZE, + MEM_MEMPOOLCOUNT, + MEM_MEMPOOLINFO, + MEM_MEMPOOLFIRST, + MEM_MEMPOOLNEXT, + MEM_MEMPOOLWALK, + MEM_MEMPOOLCHECK, + MEM_MEMALLOC, + MEM_MEMREALLOC, + MEM_MEMFREE, + MEM_MEMLOCK, + MEM_MEMUNLOCK, + MEM_MEMFIX, + MEM_MEMUNFIX, + MEM_MEMLOCKCOUNT, + MEM_MEMISMOVEABLE, + MEM_MEMREFERENCE, + MEM_MEMHANDLE, + MEM_MEMSIZE, + MEM_MEMALLOCPTR, + MEM_MEMREALLOCPTR, + MEM_MEMFREEPTR, + MEM_MEMSIZEPTR, + MEM_MEMCHECKPTR, + MEM_MEMALLOCFS, + MEM_MEMFREEFS, + MEM_MEM_MALLOC, + MEM_MEM_CALLOC, + MEM_MEM_REALLOC, + MEM_MEM_FREE, + MEM_NEW, + MEM_DELETE, + MEM_DBGMEMPOOLSETCHECKFREQUENCY, + MEM_DBGMEMPOOLDEFERFREEING, + MEM_DBGMEMPOOLFREEDEFERRED, + MEM_DBGMEMPROTECTPTR, + MEM_DBGMEMREPORTLEAKAGE, + MEM_MEMPOOLINITNAMEDSHARED, + MEM_MEMPOOLINITNAMEDSHAREDEX, + MEM_MEMPOOLATTACHSHARED, + MEM_DBGMEMPOOLINFO, + MEM_DBGMEMPTRINFO, + MEM_DBGMEMSETTINGSINFO, + MEM_DBGMEMCHECKPTR, + MEM_DBGMEMPOOLSETNAME, + MEM_DBGMEMPOOLSETDEFERQUEUELEN, + MEM_DBGMEMFREEDEFERRED, + MEM_DBGMEMCHECKALL, + MEM_DBGMEMBREAKPOINT, + MEM_MEMPOOLLOCK, + MEM_MEMPOOLUNLOCK, + MEM_MEMPOOLSETSMALLBLOCKSIZE, + MEM_MEMSIZEREQUESTED, + MEM_MSIZE, + MEM_EXPAND, + MEM_GETPROCESSHEAP, + MEM_GETPROCESSHEAPS, + MEM_GLOBALALLOC, + MEM_GLOBALFLAGS, + MEM_GLOBALFREE, + MEM_GLOBALHANDLE, + MEM_GLOBALLOCK, + MEM_GLOBALREALLOC, + MEM_GLOBALSIZE, + MEM_GLOBALUNLOCK, + MEM_HEAPALLOC, + MEM_HEAPCOMPACT, + MEM_HEAPCREATE, + MEM_HEAPDESTROY, + MEM_HEAPFREE, + MEM_HEAPLOCK, + MEM_HEAPREALLOC, + MEM_HEAPSIZE, + MEM_HEAPUNLOCK, + MEM_HEAPVALIDATE, + MEM_HEAPWALK, + MEM_LOCALALLOC, + MEM_LOCALFLAGS, + MEM_LOCALFREE, + MEM_LOCALHANDLE, + MEM_LOCALLOCK, + MEM_LOCALREALLOC, + MEM_LOCALSIZE, + MEM_LOCALUNLOCK, + MEM_MEMPOOLINITREGION, + MEM_TERMINATE, + MEM_HEAPAGENT, + MEM_USER_API, + MEM_API_COUNT, + MEM_API_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_API; + +#define MEM_MAXCALLSTACK 16 /* maximum number of call stack frames recorded */ + +/* Error info, passed to error-handling callback routine */ +typedef struct _MEM_ERROR_INFO +{ + MEM_ERROR_CODE errorCode; /* error code identifying type of error */ + MEM_POOL pool; /* pool in which error occurred, if known */ + +/* all fields below this are valid only for debugging lib */ + /* the following seven fields identify the call where error detected */ + MEM_API errorAPI; /* fn ID of entry-point where error detected */ + MEM_POOL argPool; /* memory pool parameter, if applicable */ + void MEM_FAR *argPtr; /* memory pointer parameter, if applicable */ + void MEM_FAR *argBuf; /* result buffer parameter, if applicable */ + MEM_HANDLE argHandle; /* memory handle parameter, if applicable */ + unsigned long argSize; /* size parameter, if applicable */ + unsigned long argCount; /* count parameter, if applicable */ + unsigned argFlags; /* flags parameter, if applicable */ + + /* the following two fields identify the app source file and line */ + const char MEM_FAR *file; /* app source file containing above call */ + int line; /* source line in above file */ + + /* the following two fields identify call instance of error detection */ + unsigned long allocCount; /* enumeration of allocation since 1st alloc */ + unsigned long passCount; /* enumeration of call at at above file/line */ + unsigned checkpoint; /* group with which call has been tagged */ + + /* the following fields, if non-NULL, points to the address where an + overwrite was detected and another MEM_ERROR_INFO structure + identifying where the corrupted object was first created, if known */ + void MEM_FAR *errorAlloc; /* ptr to beginning of alloc related to error */ + void MEM_FAR *corruptAddr; + struct _MEM_ERROR_INFO MEM_FAR *objectCreationInfo; + + unsigned long threadID; /* ID of thread where error detected */ + unsigned long pid; /* ID of process where error detected */ + + void MEM_FAR *callStack[MEM_MAXCALLSTACK]; +} MEM_ERROR_INFO; + +/* Error handling callback function */ +typedef MEM_BOOL (MEM_ENTRY2 * MEM_ENTRY3 MEM_ERROR_FN) + (MEM_ERROR_INFO MEM_FAR *); + + +/* Block Type: field of MEM_POOL_ENTRY, field of MEM_POOL_INFO, + * parameter to MemPoolPreAllocate + */ +typedef enum +{ + MEM_FS_BLOCK = 0x0001u, + MEM_VAR_MOVEABLE_BLOCK = 0x0002u, + MEM_VAR_FIXED_BLOCK = 0x0004u, + MEM_EXTERNAL_BLOCK = 0x0008u, + MEM_BLOCK_TYPE_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_BLOCK_TYPE; + +typedef enum +{ + MEM_SMALL_BLOCK_NONE, + MEM_SMALL_BLOCK_SH3, + MEM_SMALL_BLOCK_SH5, + MEM_SMALL_BLOCK_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_SMALL_BLOCK_ALLOCATOR; + +/* Pool Entry: parameter to MemPoolWalk */ +typedef struct +{ + void MEM_FAR *entry; + MEM_POOL pool; + MEM_BLOCK_TYPE type; + MEM_BOOL isInUse; + unsigned long size; + MEM_HANDLE handle; + unsigned lockCount; + void MEM_FAR *reserved_ptr; +} MEM_POOL_ENTRY; + +/* Pool Status: returned by MemPoolWalk, MemPoolFirst, MemPoolNext */ +typedef enum +{ + MEM_POOL_OK = 1, + MEM_POOL_CORRUPT = -1, + MEM_POOL_CORRUPT_FATAL = -2, + MEM_POOL_END = 0, + MEM_POOL_STATUS_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_POOL_STATUS; + +/* Pointer Status: returned by MemCheckPtr */ +typedef enum +{ + MEM_POINTER_OK = 1, + MEM_POINTER_WILD = 0, + MEM_POINTER_FREE = -1, + MEM_POINTER_STATUS_INT_MAX = INT_MAX /* to ensure enum is full int */ +} MEM_POINTER_STATUS; + +/* Pool Info: parameter to MemPoolInfo, MemPoolFirst, MemPoolNext */ +typedef struct +{ + MEM_POOL pool; + MEM_BLOCK_TYPE type; /* disjunctive combination of block type flags */ + unsigned short blockSizeFS; + unsigned short smallBlockSize; + unsigned pageSize; + unsigned long floor; + unsigned long ceiling; + unsigned flags; + MEM_ERROR_FN errorFn; +} MEM_POOL_INFO; + +/* Flags passed to MemAlloc, MemAllocPtr, MemReAlloc, MemReAllocPtr */ +#define MEM_FIXED 0x0000u /* fixed handle-based block */ +#define MEM_ZEROINIT 0x0001u /* == TRUE for SH 1.5 compatibility */ +#define MEM_MOVEABLE 0x0002u /* moveable handle-based block */ +#define MEM_RESIZEABLE 0x0004u /* reserve space above block */ +#define MEM_RESIZE_IN_PLACE 0x0008u /* do not move block (realloc) */ +#define MEM_NOGROW 0x0010u /* do not grow heap to satisfy request */ +#define MEM_NOEXTERNAL 0x0020u /* reserved for internal use */ +#define MEM_NOCOMPACT 0x0040u /* do not compact to satisfy request */ +#define MEM_NO_SERIALIZE 0x0080u /* do not serialize this request */ +#define MEM_HANDLEBASED 0x4000u /* for internal use */ +#define MEM_RESERVED 0x8000u /* for internal use */ + +#define MEM_UNLOCK_FAILED USHRT_MAX + +/* Flags passed to MemPoolInit, MemPoolInitFS */ +#define MEM_POOL_SHARED 0x0001u /* == TRUE for SH 1.5 compatibility */ +#define MEM_POOL_SERIALIZE 0x0002u /* pool used in more than one thread */ +#define MEM_POOL_VIRTUAL_LOCK 0x0004u /* pool is locked in physical memory */ +#define MEM_POOL_ZEROINIT 0x0008u /* malloc/new from pool zero-inits */ +#define MEM_POOL_REGION 0x0010u /* store pool in user-supplied region*/ +#define MEM_POOL_DEFAULT 0x8000u /* pool with default characteristics */ + +/* Default memory pool for C malloc, C++ new (for backwards compatibility) */ +#define MEM_DEFAULT_POOL MemDefaultPool + +/* define and initialize these variables at file scope to change defaults */ +extern unsigned short MemDefaultPoolBlockSizeFS; +extern unsigned MemDefaultPoolPageSize; +extern unsigned MemDefaultPoolFlags; + +/* define SmartHeap_malloc at file scope if you + * are intentionally _NOT_ linking in the SmartHeap malloc definition + * ditto for SmartHeap operator new, and fmalloc et al. + */ +extern int SmartHeap_malloc; +extern int SmartHeap_far_malloc; +extern int SmartHeap_new; + +#define MEM_ERROR_RET ULONG_MAX + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#ifdef MEM_DEBUG +#include "heapagnt.h" +#endif + +#endif /* !defined(_SMARTHEAP_H) */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef MEM_MT +#ifdef MemDefaultPool +#undef MemDefaultPool +#endif +#define MemDefaultPool shi_getThreadPool() +#ifndef MemInitDefaultPool +#define MemInitDefaultPool() shi_getThreadPool() +#define MemFreeDefaultPool() shi_freeThreadPools() +#endif +MEM_ENTRY1 MEM_POOL MEM_ENTRY shi_getThreadPool(void); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY shi_freeThreadPools(void); + +#else /* MEM_MT */ +MEM_ENTRY4 MEM_POOL MemDefaultPool; +MEM_POOL MEM_ENTRY MemInitDefaultPool(void); +MEM_BOOL MEM_ENTRY MemFreeDefaultPool(void); +#endif /* MEM_MT */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +/*** Function Prototypes ***/ + +#ifndef _SMARTHEAP_PROT +#define _SMARTHEAP_PROT + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _shAPI + #if defined(MEM_DEBUG) && !defined(SHI_NO_MEM_DEBUG) + #define _shAPI(ret, name) MEM_ENTRY1 ret MEM_ENTRY _dbg ## name + #else + #define _shAPI(ret, name) MEM_ENTRY1 ret MEM_ENTRY name + #endif +#endif + +#ifndef _dbgARGS + #if defined(MEM_DEBUG) && !defined(SHI_NO_MEM_DEBUG) + #define _dbgARGS1 const char MEM_FAR *, int + #define _dbgARGS , _dbgARGS1 + #else + #define _dbgARGS1 void + #define _dbgARGS + #endif +#endif + + +/**** HOW TO READ SmartHeap PROTOTYPES **** + * prototypes below have the follow syntax in order to support both debug + * and non-debug APIs with single-source: + * + * _shiAPI(, )([] _dbgARGS); + * + * the above translates to a C prototype as follows: + * + * ([]); + */ + +/* Library Version */ +MEM_ENTRY1 MEM_VERSION MEM_ENTRY MemVersion(void); + +/* Library Registration */ +_shAPI(MEM_BOOL, MemRegisterTask)(_dbgARGS1); +_shAPI(MEM_BOOL, MemUnregisterTask)(_dbgARGS1); + +/* Process heap usage */ +MEM_ENTRY1 void MEM_ENTRY MemProcessSetGrowIncrement(unsigned long); + +/* Memory Pool Functions */ +_shAPI(MEM_POOL, MemPoolInit)(unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitFS)(MEM_USHORT, unsigned long, + unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitRegion)(void MEM_FAR *, + unsigned long size, unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitRegionEx)(void MEM_FAR *addr, + unsigned long size, unsigned flags, void MEM_FAR *security _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitNamedShared)(const char MEM_FAR *, + unsigned long size,unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitNamedSharedEx)(void MEM_FAR *addr, + unsigned pidCount, unsigned long MEM_FAR *pids, void MEM_FAR *security, + const char MEM_FAR *name, unsigned long size, unsigned flags _dbgARGS); +_shAPI(MEM_POOL, MemPoolAttachShared)(MEM_POOL, const char MEM_FAR * _dbgARGS); +_shAPI(MEM_BOOL, MemPoolFree)(MEM_POOL _dbgARGS); +_shAPI(unsigned, MemPoolSetPageSize)(MEM_POOL, unsigned _dbgARGS); +_shAPI(MEM_BOOL, MemPoolSetBlockSizeFS)(MEM_POOL, MEM_USHORT _dbgARGS); +MEM_ENTRY1 unsigned long MEM_ENTRY MemPoolSetGrowIncrement(MEM_POOL, + unsigned long); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY MemPoolSetSmallBlockAllocator(MEM_POOL, MEM_SMALL_BLOCK_ALLOCATOR); +_shAPI(MEM_BOOL, MemPoolSetSmallBlockSize)(MEM_POOL, MEM_USHORT _dbgARGS); +_shAPI(unsigned long, MemPoolSetFloor)(MEM_POOL, unsigned long _dbgARGS); +_shAPI(unsigned long, MemPoolSetCeiling)(MEM_POOL, unsigned long _dbgARGS); +_shAPI(unsigned long, MemPoolPreAllocate)(MEM_POOL, unsigned long, + MEM_BLOCK_TYPE _dbgARGS); +_shAPI(unsigned long, MemPoolPreAllocateHandles)(MEM_POOL, + unsigned long _dbgARGS); +_shAPI(unsigned long, MemPoolShrink)(MEM_POOL _dbgARGS); +_shAPI(unsigned long, MemPoolSize)(MEM_POOL _dbgARGS); +_shAPI(unsigned long, MemPoolCount)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemPoolInfo)(MEM_POOL, void MEM_FAR *, + MEM_POOL_INFO MEM_FAR* _dbgARGS); +_shAPI(MEM_POOL_STATUS, MemPoolFirst)(MEM_POOL_INFO MEM_FAR *, + MEM_BOOL _dbgARGS); +_shAPI(MEM_POOL_STATUS,MemPoolNext)(MEM_POOL_INFO MEM_FAR*,MEM_BOOL _dbgARGS); +_shAPI(MEM_POOL_STATUS,MemPoolWalk)(MEM_POOL,MEM_POOL_ENTRY MEM_FAR*_dbgARGS); +_shAPI(MEM_BOOL, MemPoolCheck)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemPoolLock)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemPoolUnlock)(MEM_POOL _dbgARGS); + +/* Handle-based API for moveable memory within heap. */ +_shAPI(MEM_HANDLE, MemAlloc)(MEM_POOL, unsigned, unsigned long _dbgARGS); +_shAPI(MEM_HANDLE, MemReAlloc)(MEM_HANDLE,unsigned long,unsigned _dbgARGS); +_shAPI(MEM_BOOL, MemFree)(MEM_HANDLE _dbgARGS); +_shAPI(void MEM_FAR *, MemLock)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned, MemUnlock)(MEM_HANDLE _dbgARGS); +_shAPI(void MEM_FAR *, MemFix)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned, MemUnfix)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned, MemLockCount)(MEM_HANDLE _dbgARGS); +#ifndef MemFlags +#define MemFlags(mem) MemLockCount(mem) +#endif +_shAPI(MEM_BOOL, MemIsMoveable)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned long, MemSize)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned long, MemSizeRequested)(MEM_HANDLE _dbgARGS); +_shAPI(MEM_HANDLE, MemHandle)(void MEM_FAR * _dbgARGS); +#ifndef MEM_REFERENCE + #ifdef MEM_DEBUG + MEM_ENTRY1 void MEM_FAR * MEM_ENTRY _dbgMemReference(MEM_HANDLE, + const char MEM_FAR *, int); + #define MEM_REFERENCE(handle) \ + _dbgMemReference(handle, __FILE__, __LINE__) + #else + #define MEM_REFERENCE(handle) (*(void MEM_FAR * MEM_FAR *)handle) + #endif +#endif + +/* General Heap Allocator (returns direct pointer to memory) */ +_shAPI(void MEM_FAR*,MemAllocPtr)(MEM_POOL,unsigned long,unsigned _dbgARGS); +_shAPI(void MEM_FAR *, MemReAllocPtr)(void MEM_FAR *, unsigned long, + unsigned _dbgARGS); +_shAPI(MEM_BOOL, MemFreePtr)(void MEM_FAR * _dbgARGS); +_shAPI(unsigned long, MemSizePtr)(void MEM_FAR * _dbgARGS); +_shAPI(MEM_POINTER_STATUS, MemCheckPtr)(MEM_POOL, void MEM_FAR * _dbgARGS); + +/* Fixed-Size Allocator */ +_shAPI(void MEM_FAR *, MemAllocFS)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemFreeFS)(void MEM_FAR * _dbgARGS); + +/* Error Handling Functions */ +MEM_ENTRY1 MEM_ERROR_FN MEM_ENTRY MemSetErrorHandler(MEM_ERROR_FN); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY MemDefaultErrorHandler(MEM_ERROR_INFO MEM_FAR*); +MEM_ENTRY1 void MEM_ENTRY MemErrorUnwind(void); + +#ifdef MEM_WIN32 +/* patching control */ + +#ifndef MEM_PATCHING_DEFINED +#define MEM_PATCHING_DEFINED +typedef enum +{ + MEM_PATCH_ALL = 0, + MEM_SKIP_PATCHING_THIS_DLL = 1, + MEM_DISABLE_SYSTEM_HEAP_PATCHING = 2, + MEM_DISABLE_ALL_PATCHING = 4|2|1, + MEM_PATCHING_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_PATCHING; +#endif /* MEM_PATCHING_DEFINED */ + +#ifdef _MSC_VER +__declspec(dllexport) +#endif +MEM_PATCHING MEM_ENTRY MemSetPatching(const char ***skipDLLs); + +#endif /* MEM_WIN32 */ + +/* Internal routines */ +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _shi_enterCriticalSection(void); +MEM_ENTRY1 void MEM_ENTRY _shi_leaveCriticalSection(void); +MEM_BOOL shi_call_new_handler_msc(size_t, MEM_BOOL); + + +/* Wrapper macros for debugging API */ +#ifndef _SHI_dbgMacros +#ifdef MEM_DEBUG +#define MemRegisterTask() _dbgMemRegisterTask(__FILE__, __LINE__) +#define MemUnregisterTask() _dbgMemUnregisterTask(__FILE__, __LINE__) +#define MemPoolInit(flags) _dbgMemPoolInit(flags, __FILE__, __LINE__) +#define MemPoolInitFS(bs, bc, f) _dbgMemPoolInitFS(bs,bc,f,__FILE__,__LINE__) +#define MemPoolInitRegion(addr, sz, f) \ + _dbgMemPoolInitRegion(addr, sz, f, __FILE__, __LINE__) +#define MemPoolInitRegionEx(addr, sz, f) \ + _dbgMemPoolInitRegionEx(addr, sz, f, s, __FILE__, __LINE__) +#define MemPoolInitNamedShared(nm, sz, f) \ + _dbgMemPoolInitNamedShared(nm, sz, f, __FILE__, __LINE__) +#define MemPoolInitNamedSharedEx(a, c, p, sec, nm, sz, f) \ + _dbgMemPoolInitNamedSharedEx(a, c, p, sec, nm, sz, f, __FILE__, __LINE__) +#define MemPoolAttachShared(p, n) \ + _dbgMemPoolAttachShared(p, n, __FILE__, __LINE__) +#define MemPoolFree(pool) _dbgMemPoolFree(pool, __FILE__, __LINE__) +#define MemPoolSetPageSize(p, s) _dbgMemPoolSetPageSize(p,s,__FILE__,__LINE__) +#define MemPoolSetBlockSizeFS(p, s) \ + _dbgMemPoolSetBlockSizeFS(p, s, __FILE__, __LINE__) +#define MemPoolSetSmallBlockSize(p, s) \ + _dbgMemPoolSetSmallBlockSize(p, s, __FILE__, __LINE__) +#define MemPoolSetFloor(p, f) _dbgMemPoolSetFloor(p, f, __FILE__, __LINE__) +#define MemPoolSetCeiling(p, c) _dbgMemPoolSetCeiling(p,c,__FILE__, __LINE__) +#define MemPoolPreAllocate(p,s,t) \ + _dbgMemPoolPreAllocate(p,s,t,__FILE__, __LINE__) +#define MemPoolPreAllocateHandles(p,h) \ + _dbgMemPoolPreAllocateHandles(p,h,__FILE__, __LINE__) +#define MemPoolShrink(p) _dbgMemPoolShrink(p, __FILE__, __LINE__) +#define MemPoolCheck(p) _dbgMemPoolCheck(p, __FILE__, __LINE__) +#define MemPoolWalk(p, e) _dbgMemPoolWalk(p, e, __FILE__, __LINE__) +#define MemPoolSize(p) _dbgMemPoolSize(p, __FILE__, __LINE__) +#define MemPoolCount(p) _dbgMemPoolCount(p, __FILE__, __LINE__) +#define MemPoolInfo(p,x,i) _dbgMemPoolInfo(p,x,i, __FILE__, __LINE__) +#define MemPoolFirst(i, b) _dbgMemPoolFirst(i, b, __FILE__, __LINE__) +#define MemPoolNext(i, b) _dbgMemPoolNext(i, b, __FILE__, __LINE__) +#define MemPoolLock(p) _dbgMemPoolLock(p, __FILE__, __LINE__) +#define MemPoolUnlock(p) _dbgMemPoolUnlock(p, __FILE__, __LINE__) +#define MemAlloc(p, f, s) _dbgMemAlloc(p, f, s, __FILE__, __LINE__) +#define MemReAlloc(h, s, f) _dbgMemReAlloc(h, s, f, __FILE__, __LINE__) +#define MemFree(h) _dbgMemFree(h, __FILE__, __LINE__) +#define MemLock(h) _dbgMemLock(h, __FILE__, __LINE__) +#define MemUnlock(h) _dbgMemUnlock(h, __FILE__, __LINE__) +#define MemFix(h) _dbgMemFix(h, __FILE__, __LINE__) +#define MemUnfix(h) _dbgMemUnfix(h, __FILE__, __LINE__) +#define MemSize(h) _dbgMemSize(h, __FILE__, __LINE__) +#define MemSizeRequested(h) _dbgMemSizeRequested(h, __FILE__, __LINE__) +#define MemLockCount(h) _dbgMemLockCount(h, __FILE__, __LINE__) +#define MemIsMoveable(h) _dbgMemIsMoveable(h, __FILE__, __LINE__) +#define MemHandle(p) _dbgMemHandle(p, __FILE__, __LINE__) +#define MemAllocPtr(p, s, f) _dbgMemAllocPtr(p, s, f, __FILE__, __LINE__) +#define MemReAllocPtr(p, s, f) _dbgMemReAllocPtr(p, s, f, __FILE__,__LINE__) +#define MemFreePtr(p) _dbgMemFreePtr(p, __FILE__, __LINE__) +#define MemSizePtr(p) _dbgMemSizePtr(p, __FILE__, __LINE__) +#define MemCheckPtr(p, x) _dbgMemCheckPtr(p, x, __FILE__, __LINE__) +#define MemAllocFS(p) _dbgMemAllocFS(p, __FILE__, __LINE__) +#define MemFreeFS(p) _dbgMemFreeFS(p, __FILE__, __LINE__) + +#else /* MEM_DEBUG */ + +/* MEM_DEBUG not defined: define dbgMemXXX as no-op macros + * each macro returns "success" value when MEM_DEBUG not defined + */ +#ifndef dbgMemBreakpoint +#define dbgMemBreakpoint() ((void)0) +#define dbgMemCheckAll() 1 +#define dbgMemCheckPtr(p, f, s) 1 +#define dbgMemDeferFreeing(b) 1 +#define dbgMemFormatCall(i, b, s) 0 +#define dbgMemFormatErrorInfo(i, b, s) 0 +#define dbgMemPoolDeferFreeing(p, b) 1 +#define dbgMemFreeDeferred() 1 +#define dbgMemPoolFreeDeferred(p) 1 +#define dbgMemPoolInfo(p, b) 1 +#define dbgMemPoolSetCheckFrequency(p, f) 1 +#define dbgMemPoolSetDeferQueueLen(p, b) 1 +#define dbgMemPoolSetName(p, n) 1 +#define dbgMemProtectPtr(p, f) 1 +#define dbgMemPtrInfo(p, b) 1 +#define dbgMemReallocMoves(b) 1 +#define dbgMemReportLeakage(p, c1, c2) 1 +#define dbgMemReportWrongTaskRef(b) 1 +#define dbgMemScheduleChecking(b, p, i) 1 +#define dbgMemSetCheckFrequency(f) 1 +#define dbgMemSetCheckpoint(c) 1 +#define dbgMemSetDefaultErrorOutput(x, f) 1 +#define dbgMemSetDeferQueueLen(l) 1 +#define dbgMemSetDeferSizeThreshold(s) 1 +#define dbgMemSetEntryHandler(f) 0 +#define dbgMemSetExitHandler(f) 0 +#define dbgMemSetFreeFill(c) 1 +#define dbgMemSetGuardFill(c) 1 +#define dbgMemSetGuardSize(s) 1 +#define dbgMemSetInUseFill(c) 1 +#define dbgMemSetCallstackChains(s) 1 +#define dbgMemSetStackChecking(s) 1 +#define dbgMemSetSafetyLevel(s) 1 +#define dbgMemSettingsInfo(b) 1 +#define dbgMemSuppressFreeFill(b) 1 +#define dbgMemTotalCount() 1 +#define dbgMemTotalSize() 1 +#define dbgMemWalkHeap(b) MEM_POOL_OK +#endif /* dbgMemBreakpoint */ + +#endif /* MEM_DEBUG */ +#endif /* _SHI_dbgMacros */ + +#if defined(__WATCOMC__) && defined(__SW_3S) +/* Watcom stack calling convention */ + #pragma aux MemDefaultPool "_*"; + #pragma aux MemDefaultPoolBlockSizeFS "_*"; + #pragma aux MemDefaultPoolPageSize "_*"; + #pragma aux MemDefaultPoolFlags "_*"; + #pragma aux SmartHeap_malloc "_*"; + #pragma aux SmartHeap_far_malloc "_*"; + #pragma aux SmartHeap_new "_*"; +#ifdef MEM_DEBUG + #pragma aux dbgMemGuardSize "_*"; + #pragma aux dbgMemGuardFill "_*"; + #pragma aux dbgMemFreeFill "_*"; + #pragma aux dbgMemInUseFill "_*"; +#endif +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !defined(_SMARTHEAP_PROT) */ diff --git a/CODE-mp/smartheap/smrtheap.hpp b/CODE-mp/smartheap/smrtheap.hpp new file mode 100644 index 0000000..dfc8435 --- /dev/null +++ b/CODE-mp/smartheap/smrtheap.hpp @@ -0,0 +1,197 @@ +// smrtheap.hpp -- SmartHeap public C++ header file +// Professional Memory Management Library +// +// Copyright (C) 1991-1999 Compuware Corporation. +// All Rights Reserved. +// +// No part of this source code may be copied, modified or reproduced +// in any form without retaining the above copyright notice. +// This source code, or source code derived from it, may not be redistributed +// without express written permission of the copyright owner. +// +// COMMENTS: +// - Include this header file to call the SmartHeap-specific versions of +// operators new (i.e. with placement syntax), to: +// o allocate from a specific memory pool; +// o specify allocation flags, such as zero-initialization; +// o resize an allocation. +// +// - If you include this header file, you must compile and link shnew.cpp, or +// link with one of the SmartHeap static operator new libraries: +// sh[l|d]XXXX.lib +// +// - Can be used in both EXEs and DLLs. +// +// - For 16-bit x86 platforms, use only in large or compact memory model. +// +// - If you do not want to use SmartHeap's global operator new but you do +// want to use SmartHeap's other facilities in a C++ application, then +// include the smrtheap.h header file but do not include this header file, +// and do not link with shnew.cpp. The two ".Xpp" files are present +// ONLY for the purpose of defining operator new and operator delete. +// +// - Use the MemDefaultPool global variable to refer to a memory pool to pass +// to SmartHeap functions that accept a pool as a parameter, +// e.g. MemPoolCount, MemPoolSize, MemPoolWalk, etc. +// + +#if !defined(_SMARTHEAP_HPP) +#define _SMARTHEAP_HPP + +#if defined(_MSC_VER) \ + && (defined(M_I86LM) || defined(M_I86CM) || defined(M_I86HM)) \ + && !defined(MEM_HUGE) +#define MEM_HUGE 0x8000u +#endif + +#ifndef __BORLANDC__ +/* Borland C++ does not treat extern "C++" correctly */ +extern "C++" +{ +#endif /* __BORLANDC__ */ + +#if defined(_MSC_VER) && _MSC_VER >= 900 +#pragma warning(disable : 4507) +#endif + +#if defined(new) +#if defined(MEM_DEBUG) +#undef new +#endif +#endif + +#include + +#include "smrtheap.h" + +#if defined(new) +#if defined(MEM_DEBUG) +#undef new +#endif +#endif + +#if ((defined(__BORLANDC__) && (__BORLANDC__ >= 0x450)) \ + || (defined(__WATCOMC__) && __WATCOMC__ >= 1000) \ + || (defined(__IBMCPP__) && __IBMCPP__ >= 250) \ + || defined(__hpux) \ + || defined(__osf__) \ + || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x500) \ + || defined(_AIX43)) +#define SHI_ARRAY_NEW 1 +#define SHI_ARRAY_DELETE 1 +#endif + +#if !(defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x500) +#define SHI_NEWDEFARGS 1 +#endif + +void MEM_FAR * MEM_ENTRY_ANSI shi_New(unsigned long sz, unsigned flags=0, MEM_POOL pool=0); + +// operator new variants: + + +// version of new that passes memory allocation flags +// (e.g. MEM_ZEROINIT to zero-initialize memory) +// call with syntax 'ptr = new (flags) ' +inline void MEM_FAR *operator new(size_t sz, unsigned flags) + { return shi_New(sz, flags); } +#if defined(_MSC_VER) && _MSC_VER >= 1200 +inline void MEM_FAR operator delete(void *p, unsigned) + { ::operator delete(p); } +#endif // _MSC_VER + +// version of new that allocates from a specified memory pool with alloc flags +// call with the syntax 'ptr = new (pool, [flags=0]) ' +inline void MEM_FAR *operator new(size_t sz, MEM_POOL pool, unsigned flags +#ifdef SHI_NEWDEFARGS + =0 +#endif + ) + { return shi_New(sz, flags, pool); } +#if defined(_MSC_VER) && _MSC_VER >= 1200 +inline void MEM_FAR operator delete(void *p, MEM_POOL, unsigned) + { ::operator delete(p); } +#endif // _MSC_VER + +#ifdef SHI_ARRAY_NEW +inline void MEM_FAR *operator new[](size_t sz, MEM_POOL pool, unsigned flags +#ifdef SHI_NEWDEFARGS + =0 +#endif + ) + { return shi_New(sz, flags, pool); } +#endif + +// version of new that changes the size of a memory block previously allocated +// from an SmartHeap memory pool +// call with the syntax 'ptr = new (ptr, flags) ' +#if !defined(__BORLANDC__) && !defined(__HIGHC__) +/* bug in BC++, MetaWare High C++ parsers confuse this with new(file,line) */ +inline void MEM_FAR *operator new(size_t new_sz, void MEM_FAR *lpMem, + unsigned flags) + { return MemReAllocPtr(lpMem, new_sz, flags); } +#if defined(_MSC_VER) && _MSC_VER >= 1200 +inline void MEM_FAR operator delete(void *p, void MEM_FAR *, unsigned) + { ::operator delete(p); } +#endif // _MSC_VER + +#ifdef SHI_ARRAY_NEW +inline void MEM_FAR *operator new[](size_t new_sz, void MEM_FAR *lpMem, + unsigned flags) + { return MemReAllocPtr(lpMem, new_sz, flags); } +#endif // SHI_ARRAY_NEW +#endif + + +// new_handler prototypes: note that MSC/C++ prototype differs from the +// protosed ANSI standard prototype for set_new_handler +#if defined(__MWERKS__) \ + || defined(__hpux) \ + || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x500) + +#define MEM_CPP_THROW throw() +#define MEM_CPP_THROW1(x) throw(x) +//#elif defined(_MSC_VER) && _MSC_VER >= 1100 && defined(_CPPUNWIND) +//#define MEM_CPP_THROW throw() +#else +#define MEM_CPP_THROW +#define MEM_CPP_THROW1(x) +#endif // __MWERKS__ +#ifndef _CRTIMP +#define _CRTIMP +#endif // _CRTIMP +#ifdef _MSC_VER +_CRTIMP _PNH MEM_ENTRY_ANSI _set_new_handler(_PNH); +#if UINT_MAX == 0xFFFFu +_PNH MEM_ENTRY_ANSI _set_fnew_handler(_PNH); +_PNHH MEM_ENTRY_ANSI _set_hnew_handler(_PNHH); +#endif // UINT_MAX +#endif // _MSC_VER +typedef void (MEM_ENTRY_ANSI * pnh)(); +_CRTIMP pnh MEM_ENTRY_ANSI set_new_handler(pnh) MEM_CPP_THROW; + +#ifndef DBG_FORMAL +#define DBG_FORMAL +#define DBG_ACTUAL +#ifndef DEBUG_NEW +#define DEBUG_NEW new +#endif // DEBUG_NEW +#define DEBUG_NEW1(x_) new(x_) +#define DEBUG_NEW2(x_, y_) new(x_, y_) +#define DEBUG_NEW3(x_, y_, z_) new(x_, y_, z_) +#define DEBUG_DELETE delete +#endif + +#ifdef DEFINE_NEW_MACRO +#define new DEBUG_NEW +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 900 +#pragma warning(default : 4507) +#endif + +#ifndef __BORLANDC__ +} +#endif /* __BORLANDC__ */ + +#endif /* !defined(_SMARTHEAP_HPP) */ diff --git a/CODE-mp/smartheap/vssver.scc b/CODE-mp/smartheap/vssver.scc new file mode 100644 index 0000000..3acbcd8 Binary files /dev/null and b/CODE-mp/smartheap/vssver.scc differ diff --git a/CODE-mp/strings/vssver.scc b/CODE-mp/strings/vssver.scc new file mode 100644 index 0000000..adf3b76 Binary files /dev/null and b/CODE-mp/strings/vssver.scc differ diff --git a/CODE-mp/tosend.bat b/CODE-mp/tosend.bat new file mode 100644 index 0000000..17a9ea9 --- /dev/null +++ b/CODE-mp/tosend.bat @@ -0,0 +1,4 @@ +xcopy/y final\*.exe c:\send\game +xcopy/y base\vm\cgame.qvm c:\send\game\base\vm +xcopy/y base\vm\jk2mpgame.qvm c:\send\game\base\vm +xcopy/y base\vm\ui.qvm c:\send\game\base\vm diff --git a/CODE-mp/ui/mssccprj.scc b/CODE-mp/ui/mssccprj.scc new file mode 100644 index 0000000..3ad6dae --- /dev/null +++ b/CODE-mp/ui/mssccprj.scc @@ -0,0 +1,5 @@ +SCC = This is a Source Code Control file + +[ui.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\jk2sof2MP" +SCC_Project_Name = "$/General/code/ui", ZAAAAAAA diff --git a/CODE-mp/ui/ui.bat b/CODE-mp/ui/ui.bat new file mode 100644 index 0000000..551fbc8 --- /dev/null +++ b/CODE-mp/ui/ui.bat @@ -0,0 +1,41 @@ +del /q vm +mkdir vm +cd vm + +set cc=lcc -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui %1 + +%cc% ../ui_main.c +@if errorlevel 1 goto quit +%cc% ../../game/bg_misc.c +@if errorlevel 1 goto quit +%cc% ../../game/bg_weapons.c +@if errorlevel 1 goto quit +%cc% ../../game/bg_lib.c +@if errorlevel 1 goto quit +%cc% ../../game/q_math.c +@if errorlevel 1 goto quit +%cc% ../../game/q_shared.c +@if errorlevel 1 goto quit +%cc% ../ui_atoms.c +@if errorlevel 1 goto quit +%cc% ../ui_force.c +@if errorlevel 1 goto quit +%cc% ../ui_util.c +@if errorlevel 1 goto quit +%cc% ../ui_shared.c +@if errorlevel 1 goto quit +%cc% ../ui_gameinfo.c +@if errorlevel 1 goto quit + +sysmaker ../ui_public.h ../ui_syscalls.c ../ui_syscalls.asm +@if errorlevel 1 goto quit + +q3asm -f ../ui +@if errorlevel 1 goto quit + +mkdir "..\..\base\vm" +copy *.map "..\..\base\vm" +copy *.qvm "..\..\base\vm" + +:quit +cd .. diff --git a/CODE-mp/ui/ui.def b/CODE-mp/ui/ui.def new file mode 100644 index 0000000..01861ba --- /dev/null +++ b/CODE-mp/ui/ui.def @@ -0,0 +1,3 @@ +EXPORTS + vmMain + dllEntry diff --git a/CODE-mp/ui/ui.dsp b/CODE-mp/ui/ui.dsp index 8411ab2..3ad8b27 100644 --- a/CODE-mp/ui/ui.dsp +++ b/CODE-mp/ui/ui.dsp @@ -166,10 +166,6 @@ SOURCE=.\ui_main.c # End Source File # Begin Source File -SOURCE=.\ui_players.c -# End Source File -# Begin Source File - SOURCE=.\ui_shared.c # End Source File # Begin Source File @@ -206,6 +202,10 @@ SOURCE=..\qcommon\disablewarnings.h # End Source File # Begin Source File +SOURCE=..\qcommon\game_version.h +# End Source File +# Begin Source File + SOURCE=.\keycodes.h # End Source File # Begin Source File diff --git a/CODE-mp/ui/ui.q3asm b/CODE-mp/ui/ui.q3asm new file mode 100644 index 0000000..469cba7 --- /dev/null +++ b/CODE-mp/ui/ui.q3asm @@ -0,0 +1,13 @@ +-o "ui" +ui_main +..\ui_syscalls +ui_atoms +ui_force +ui_util +ui_shared +ui_gameinfo +bg_misc +bg_weapons +bg_lib +q_math +q_shared diff --git a/CODE-mp/ui/ui_atoms.c b/CODE-mp/ui/ui_atoms.c index 561c540..b5ef818 100644 --- a/CODE-mp/ui/ui_atoms.c +++ b/CODE-mp/ui/ui_atoms.c @@ -274,6 +274,7 @@ static void UI_CalcPostGameStats() { // put back all the ui overrides trap_Cvar_Set("capturelimit", UI_Cvar_VariableString("ui_saveCaptureLimit")); trap_Cvar_Set("fraglimit", UI_Cvar_VariableString("ui_saveFragLimit")); + trap_Cvar_Set("duel_fraglimit", UI_Cvar_VariableString("ui_saveDuelLimit")); trap_Cvar_Set("cg_drawTimer", UI_Cvar_VariableString("ui_drawTimer")); trap_Cvar_Set("g_doWarmup", UI_Cvar_VariableString("ui_doWarmup")); trap_Cvar_Set("g_Warmup", UI_Cvar_VariableString("ui_Warmup")); @@ -317,6 +318,15 @@ qboolean UI_ConsoleCommand( int realTime ) { return qtrue; } + if ( Q_stricmp (cmd, "ui_openmenu" ) == 0 ) + { + if ( trap_Cvar_VariableValue ( "developer" ) ) + { + Menus_OpenByName ( UI_Argv(1) ); + return qtrue; + } + } + if ( Q_stricmp (cmd, "remapShader") == 0 ) { if (trap_Argc() == 4) { char shader1[MAX_QPATH]; diff --git a/CODE-mp/ui/ui_force.c b/CODE-mp/ui/ui_force.c index 9fa9a2d..9363f6a 100644 --- a/CODE-mp/ui/ui_force.c +++ b/CODE-mp/ui/ui_force.c @@ -13,14 +13,14 @@ FORCE INTERFACE #include "ui_force.h" int uiForceSide = FORCE_LIGHTSIDE; -int uiForceRank = FORCE_MASTERY_JEDI_LORD; +int uiForceRank = FORCE_MASTERY_JEDI_KNIGHT; int uiMaxRank = MAX_FORCE_RANK; int uiMaxPoints = 20; int uiForceUsed = 0; int uiForceAvailable=0; qboolean gTouchedForce = qfalse; -vmCvar_t ui_freeSaber; +vmCvar_t ui_freeSaber, ui_forcePowerDisable; void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow); int uiForcePowersRank[NUM_FORCE_POWERS] = { @@ -39,8 +39,8 @@ int uiForcePowersRank[NUM_FORCE_POWERS] = { 0,//FP_TEAM_FORCE, 0,//FP_DRAIN, 0,//FP_SEE, - 0,//FP_SABERATTACK, - 0,//FP_SABERDEFEND, + 1,//FP_SABERATTACK, //default to 1 point in attack + 1,//FP_SABERDEFEND, //defualt to 1 point in defense 0//FP_SABERTHROW, }; @@ -67,30 +67,6 @@ int uiForcePowerDarkLight[NUM_FORCE_POWERS] = //0 == neutral //NUM_FORCE_POWERS }; -int uiForcePowerCost[NUM_FORCE_POWERS][NUM_FORCE_POWER_LEVELS] = //0 == neutral -{ - { 0, 2, 3, 4 }, // FP_HEAL - { 0, 0, 1, 1 }, //FP_LEVITATION,//hold/duration - { 0, 1, 1, 1 }, //FP_SPEED,//duration - { 0, 1, 2, 3 }, //FP_PUSH,//hold/duration - { 0, 1, 2, 3 }, //FP_PULL,//hold/duration - { 0, 2, 3, 4 }, //FP_TELEPATHY,//instant - { 0, 1, 2, 3 }, //FP_GRIP,//hold/duration - { 0, 2, 3, 4 }, //FP_LIGHTNING,//hold/duration - { 0, 2, 3, 4 }, //FP_RAGE,//duration - { 0, 1, 2, 3 }, //FP_PROTECT,//duration - { 0, 1, 2, 3 }, //FP_ABSORB,//duration - { 0, 1, 1, 1 }, //FP_TEAM_HEAL,//instant - { 0, 1, 1, 1 }, //FP_TEAM_FORCE,//instant - { 0, 1, 2, 3 }, //FP_DRAIN,//hold/duration - { 0, 1, 2, 3 }, //FP_SEE,//duration - { 0, 1, 2, 4 }, //FP_SABERATTACK, - { 0, 1, 2, 4 }, //FP_SABERDEFEND, - { 0, 1, 2, 4 } //FP_SABERTHROW, - //NUM_FORCE_POWERS -}; - - int uiForceStarShaders[NUM_FORCE_STAR_IMAGES][2]; int uiSaberColorShaders[NUM_SABER_COLORS]; void UI_InitForceShaders(void) @@ -122,7 +98,6 @@ void UI_InitForceShaders(void) uiSaberColorShaders[SABER_PURPLE] = trap_R_RegisterShaderNoMip("menu/art/saber_purple"); } - // Draw the stars spent on the current force power void UI_DrawForceStars(rectDef_t *rect, float scale, vec4_t color, int textStyle, int forceindex, int val, int min, int max) { @@ -141,7 +116,7 @@ void UI_DrawForceStars(rectDef_t *rect, float scale, vec4_t color, int textStyle for (i=FORCE_LEVEL_1;i<=max;i++) { - starcolor = uiForcePowerCost[forceindex][i]; + starcolor = bgForcePowerCost[forceindex][i]; if (val >= i) { // Draw a star. @@ -157,7 +132,7 @@ void UI_DrawForceStars(rectDef_t *rect, float scale, vec4_t color, int textStyle } // Set the client's force power layout. -void UI_UpdateClientForcePowers() +void UI_UpdateClientForcePowers(const char *teamArg) { trap_Cvar_Set( "forcepowers", va("%i-%i-%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i", uiForceRank, uiForceSide, uiForcePowersRank[0], uiForcePowersRank[1], @@ -170,12 +145,29 @@ void UI_UpdateClientForcePowers() if (gTouchedForce) { - trap_Cmd_ExecuteText( EXEC_APPEND, "forcechanged\n" ); + if (teamArg && teamArg[0]) + { + trap_Cmd_ExecuteText( EXEC_APPEND, va("forcechanged \"%s\"\n", teamArg) ); + } + else + { + trap_Cmd_ExecuteText( EXEC_APPEND, "forcechanged\n" ); + } } gTouchedForce = qfalse; } +int UI_TranslateFCFIndex(int index) +{ + if (uiForceSide == FORCE_LIGHTSIDE) + { + return index-uiInfo.forceConfigLightIndexBegin; + } + + return index-uiInfo.forceConfigDarkIndexBegin; +} + void UI_SaveForceTemplate() { char *selectedName = UI_Cvar_VariableString("ui_SaveFCF"); @@ -184,6 +176,8 @@ void UI_SaveForceTemplate() fileHandle_t f; int strPlace = 0; int forcePlace = 0; + int i = 0; + qboolean foundFeederItem = qfalse; if (!selectedName || !selectedName[0]) { @@ -191,7 +185,14 @@ void UI_SaveForceTemplate() return; } - trap_FS_FOpenFile(va("forcecfg/%s.fcf", selectedName), &f, FS_WRITE); + if (uiForceSide == FORCE_LIGHTSIDE) + { //write it into the light side folder + trap_FS_FOpenFile(va("forcecfg/light/%s.fcf", selectedName), &f, FS_WRITE); + } + else + { //if it isn't light it must be dark + trap_FS_FOpenFile(va("forcecfg/dark/%s.fcf", selectedName), &f, FS_WRITE); + } if (!f) { @@ -217,6 +218,31 @@ void UI_SaveForceTemplate() trap_FS_FCloseFile(f); Com_Printf("Template saved as \"%s\".\n", selectedName); + + //Now, update the FCF list + UI_LoadForceConfig_List(); + + //Then, scroll through and select the template for the file we just saved + while (i < uiInfo.forceConfigCount) + { + if (!Q_stricmp(uiInfo.forceConfigNames[i], selectedName)) + { + if ((uiForceSide == FORCE_LIGHTSIDE && uiInfo.forceConfigSide[i]) || + (uiForceSide == FORCE_DARKSIDE && !uiInfo.forceConfigSide[i])) + { + Menu_SetFeederSelection(NULL, FEEDER_FORCECFG, UI_TranslateFCFIndex(i), NULL); + foundFeederItem = qtrue; + } + } + + i++; + } + + //Else, go back to 0 + if (!foundFeederItem) + { + Menu_SetFeederSelection(NULL, FEEDER_FORCECFG, 0, NULL); + } } // @@ -242,12 +268,17 @@ void UpdateForceUsed() // Set the cost of the saberattack according to whether its free. if (ui_freeSaber.integer) { // Make saber free - uiForcePowerCost[FP_SABERATTACK][FORCE_LEVEL_1] = 0; + bgForcePowerCost[FP_SABERATTACK][FORCE_LEVEL_1] = 0; + bgForcePowerCost[FP_SABERDEFEND][FORCE_LEVEL_1] = 0; // Make sure that we have one freebie in saber if applicable. if (uiForcePowersRank[FP_SABERATTACK]<1) { uiForcePowersRank[FP_SABERATTACK]=1; } + if (uiForcePowersRank[FP_SABERDEFEND]<1) + { + uiForcePowersRank[FP_SABERDEFEND]=1; + } if (menu) { Menu_ShowItemByName(menu, "setfp_saberdefend", qtrue); @@ -259,7 +290,8 @@ void UpdateForceUsed() } else { // Make saber normal cost - uiForcePowerCost[FP_SABERATTACK][FORCE_LEVEL_1] = 1; + bgForcePowerCost[FP_SABERATTACK][FORCE_LEVEL_1] = 1; + bgForcePowerCost[FP_SABERDEFEND][FORCE_LEVEL_1] = 1; // Also, check if there is no saberattack. If there isn't, there had better not be any defense or throw! if (uiForcePowersRank[FP_SABERATTACK]<1) { @@ -300,13 +332,14 @@ void UpdateForceUsed() if (uiForcePowersRank[curpower]>0) { // Do not charge the player for the one freebie in jump, or if there is one in saber. if ( (curpower == FP_LEVITATION && currank == FORCE_LEVEL_1) || - (curpower == FP_SABERATTACK && currank == FORCE_LEVEL_1 && ui_freeSaber.integer)) + (curpower == FP_SABERATTACK && currank == FORCE_LEVEL_1 && ui_freeSaber.integer) || + (curpower == FP_SABERDEFEND && currank == FORCE_LEVEL_1 && ui_freeSaber.integer) ) { // Do nothing (written this way for clarity) } else { // Check if we can accrue the cost of this power. - if (uiForcePowerCost[curpower][currank] > uiForceAvailable) + if (bgForcePowerCost[curpower][currank] > uiForceAvailable) { // We can't afford this power. Break to the next one. // Remove this power from the player's roster. uiForcePowersRank[curpower] = currank-1; @@ -314,56 +347,183 @@ void UpdateForceUsed() } else { // Sure we can afford it. - uiForceUsed += uiForcePowerCost[curpower][currank]; - uiForceAvailable -= uiForcePowerCost[curpower][currank]; + uiForceUsed += bgForcePowerCost[curpower][currank]; + uiForceAvailable -= bgForcePowerCost[curpower][currank]; } } } } } - if (menu) - { - char info[MAX_INFO_STRING]; - trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ); +} - // Set or reset buttons based on choices - if (atoi(Info_ValueForKey(info, "g_gametype")) >= GT_TEAM) - { // This is a team-based game. - Menu_ShowItemByName(menu, "playerforcejoin", qtrue); - Menu_ShowItemByName(menu, "playerforcespectate", qtrue); - if (atoi(Info_ValueForKey(info, "g_forceBasedTeams"))) - { // Show red or blue based on what side is chosen. - if (uiForceSide==FORCE_LIGHTSIDE) - { - Menu_ShowItemByName(menu, "playerforcered", qfalse); - Menu_ShowItemByName(menu, "playerforceblue", qtrue); - } - else if (uiForceSide==FORCE_DARKSIDE) - { - Menu_ShowItemByName(menu, "playerforcered", qtrue); - Menu_ShowItemByName(menu, "playerforceblue", qfalse); - } - else - { - Menu_ShowItemByName(menu, "playerforcered", qtrue); - Menu_ShowItemByName(menu, "playerforceblue", qtrue); - } - } - else - { - Menu_ShowItemByName(menu, "playerforcered", qtrue); - Menu_ShowItemByName(menu, "playerforceblue", qtrue); - } - } - else + +//Mostly parts of other functions merged into one another. +//Puts the current UI stuff into a string, legalizes it, and then reads it back out. +void UI_ReadLegalForce(void) +{ + char fcfString[512]; + char forceStringValue[4]; + int strPlace = 0; + int forcePlace = 0; + int i = 0; + char singleBuf[64]; + char info[MAX_INFO_VALUE]; + int c = 0; + int iBuf = 0; + int forcePowerRank = 0; + int currank = 0; + int forceTeam = 0; + qboolean updateForceLater = qfalse; + + //First, stick them into a string. + Com_sprintf(fcfString, sizeof(fcfString), "%i-%i-", uiForceRank, uiForceSide); + strPlace = strlen(fcfString); + + while (forcePlace < NUM_FORCE_POWERS) + { + Com_sprintf(forceStringValue, sizeof(forceStringValue), "%i", uiForcePowersRank[forcePlace]); + //Just use the force digit even if multiple digits. Shouldn't be longer than 1. + fcfString[strPlace] = forceStringValue[0]; + strPlace++; + forcePlace++; + } + fcfString[strPlace] = '\n'; + fcfString[strPlace+1] = 0; + + info[0] = '\0'; + trap_GetConfigString(CS_SERVERINFO, info, sizeof(info)); + + if (atoi( Info_ValueForKey( info, "g_forceBasedTeams" ) )) + { + switch((int)(trap_Cvar_VariableValue("ui_myteam"))) { - Menu_ShowItemByName(menu, "playerforcejoin", qtrue); - Menu_ShowItemByName(menu, "playerforcered", qfalse); - Menu_ShowItemByName(menu, "playerforceblue", qfalse); - Menu_ShowItemByName(menu, "playerforcespectate", qtrue); + case TEAM_RED: + forceTeam = FORCE_DARKSIDE; + break; + case TEAM_BLUE: + forceTeam = FORCE_LIGHTSIDE; + break; + default: + break; } } + //Second, legalize them. + if (!BG_LegalizedForcePowers(fcfString, uiMaxRank, ui_freeSaber.integer, forceTeam, atoi( Info_ValueForKey( info, "g_gametype" )), 0)) + { //if they were illegal, we should refresh them. + updateForceLater = qtrue; + } + + //Lastly, put them back into the UI storage from the legalized string + i = 0; + + while (fcfString[i] && fcfString[i] != '-') + { + singleBuf[c] = fcfString[i]; + c++; + i++; + } + singleBuf[c] = 0; + c = 0; + i++; + + iBuf = atoi(singleBuf); + + if (iBuf > uiMaxRank || iBuf < 0) + { //this force config uses a rank level higher than our currently restricted level.. so we can't use it + //FIXME: Print a message indicating this to the user + // return; + } + + uiForceRank = iBuf; + + while (fcfString[i] && fcfString[i] != '-') + { + singleBuf[c] = fcfString[i]; + c++; + i++; + } + singleBuf[c] = 0; + c = 0; + i++; + + uiForceSide = atoi(singleBuf); + + if (uiForceSide != FORCE_LIGHTSIDE && + uiForceSide != FORCE_DARKSIDE) + { + uiForceSide = FORCE_LIGHTSIDE; + return; + } + + //clear out the existing powers + while (c < NUM_FORCE_POWERS) + { + uiForcePowersRank[c] = 0; + c++; + } + uiForceUsed = 0; + uiForceAvailable = forceMasteryPoints[uiForceRank]; + gTouchedForce = qtrue; + + for (c=0;fcfString[i]&&c FORCE_LEVEL_3 || forcePowerRank < 0) + { //err.. not correct + continue; // skip this power + } + + if (uiForcePowerDarkLight[c] && uiForcePowerDarkLight[c] != uiForceSide) + { //Apparently the user has crafted a force config that has powers that don't fit with the config's side. + continue; // skip this power + } + + // Accrue cost for each assigned rank for this power. + for (currank=FORCE_LEVEL_1;currank<=forcePowerRank;currank++) + { + if (bgForcePowerCost[c][currank] > uiForceAvailable) + { // Break out, we can't afford any more power. + break; + } + // Pay for this rank of this power. + uiForceUsed += bgForcePowerCost[c][currank]; + uiForceAvailable -= bgForcePowerCost[c][currank]; + + uiForcePowersRank[c]++; + } + } + + if (uiForcePowersRank[FP_LEVITATION] < 1) + { + uiForcePowersRank[FP_LEVITATION]=1; + } + if (uiForcePowersRank[FP_SABERATTACK] < 1 && ui_freeSaber.integer) + { + uiForcePowersRank[FP_SABERATTACK]=1; + } + if (uiForcePowersRank[FP_SABERDEFEND] < 1 && ui_freeSaber.integer) + { + uiForcePowersRank[FP_SABERDEFEND]=1; + } + + UpdateForceUsed(); + + if (updateForceLater) + { + gTouchedForce = qtrue; + UI_UpdateClientForcePowers(NULL); + } } void UI_UpdateForcePowers() @@ -440,6 +600,13 @@ void UI_UpdateForcePowers() uiForcePowersRank[i_f] = 1; } + if (i_f == FP_SABERDEFEND && + uiForcePowersRank[i_f] < 1 && + ui_freeSaber.integer) + { + uiForcePowersRank[i_f] = 1; + } + i_f++; i++; } @@ -470,6 +637,10 @@ validitycheck: { uiForcePowersRank[i] = 1; } + else if (i == FP_SABERDEFEND && ui_freeSaber.integer) + { + uiForcePowersRank[i] = 1; + } else { uiForcePowersRank[i] = 0; @@ -478,7 +649,7 @@ validitycheck: i++; } - UI_UpdateClientForcePowers(); + UI_UpdateClientForcePowers(NULL); } UpdateForceUsed(); @@ -513,6 +684,8 @@ qboolean UI_SkinColor_HandleKey(int flags, float *special, int key, int num, int uiSkinColor = num; + UI_FeederSelection(FEEDER_Q3HEADS, uiInfo.q3SelectedHead); + return qtrue; } return qfalse; @@ -523,11 +696,32 @@ qboolean UI_SkinColor_HandleKey(int flags, float *special, int key, int num, int qboolean UI_ForceSide_HandleKey(int flags, float *special, int key, int num, int min, int max, int type) { + char info[MAX_INFO_VALUE]; + + info[0] = '\0'; + trap_GetConfigString(CS_SERVERINFO, info, sizeof(info)); + + if (atoi( Info_ValueForKey( info, "g_forceBasedTeams" ) )) + { + switch((int)(trap_Cvar_VariableValue("ui_myteam"))) + { + case TEAM_RED: + return qfalse; + case TEAM_BLUE: + return qfalse; + default: + break; + } + } + if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { int i = num; int x = 0; + //update the feeder item selection, it might be different depending on side + Menu_SetFeederSelection(NULL, FEEDER_FORCECFG, 0, NULL); + if (key == K_MOUSE2) { i--; @@ -563,7 +757,6 @@ qboolean UI_ForceSide_HandleKey(int flags, float *special, int key, int num, int UpdateForceUsed(); gTouchedForce = qtrue; - return qtrue; } return qfalse; @@ -598,6 +791,8 @@ qboolean UI_ForceMaxRank_HandleKey(int flags, float *special, int key, int num, uiMaxRank = num; + trap_Cvar_Set( "g_maxForceRank", va("%i", num)); + // The update force used will remove overallocated powers automatically. UpdateForceUsed(); @@ -642,6 +837,10 @@ qboolean UI_ForcePowerRank_HandleKey(int flags, float *special, int key, int num { min += 1; } + if (type == UI_FORCE_RANK_SABERDEFEND && ui_freeSaber.integer) + { + min += 1; + } if (key == K_MOUSE2) { // Lower a point. @@ -663,22 +862,22 @@ qboolean UI_ForcePowerRank_HandleKey(int flags, float *special, int key, int num if (raising) { // Check if we can accrue the cost of this power. rank = uiForcePowersRank[forcepower]+1; - if (uiForcePowerCost[forcepower][rank] > uiForceAvailable) + if (bgForcePowerCost[forcepower][rank] > uiForceAvailable) { // We can't afford this power. Abandon ship. return qtrue; } else { // Sure we can afford it. - uiForceUsed += uiForcePowerCost[forcepower][rank]; - uiForceAvailable -= uiForcePowerCost[forcepower][rank]; + uiForceUsed += bgForcePowerCost[forcepower][rank]; + uiForceAvailable -= bgForcePowerCost[forcepower][rank]; uiForcePowersRank[forcepower]=rank; } } else { // Lower the point. rank = uiForcePowersRank[forcepower]; - uiForceUsed -= uiForcePowerCost[forcepower][rank]; - uiForceAvailable += uiForcePowerCost[forcepower][rank]; + uiForceUsed -= bgForcePowerCost[forcepower][rank]; + uiForceAvailable += bgForcePowerCost[forcepower][rank]; uiForcePowersRank[forcepower]--; } @@ -730,6 +929,8 @@ void UI_ForceConfigHandle( int oldindex, int newindex ) int iBuf = 0, forcePowerRank, currank; char fcfBuffer[8192]; char singleBuf[64]; + char info[MAX_INFO_VALUE]; + int forceTeam = 0; if (oldindex == 0) { //switching out from custom config, so first shove the current values into the custom storage @@ -758,15 +959,46 @@ void UI_ForceConfigHandle( int oldindex, int newindex ) } uiForceRank = gCustRank; uiForceSide = gCustSide; + + UpdateForceUsed(); return; } //If we made it here, we want to load in a new config - len = trap_FS_FOpenFile(va("forcecfg/%s.fcf", uiInfo.forceConfigNames[newindex]), &f, FS_READ); + if (uiForceSide == FORCE_LIGHTSIDE) + { //we should only be displaying lightside configs, so.. look in the light folder + newindex += uiInfo.forceConfigLightIndexBegin; + if (newindex >= uiInfo.forceConfigCount) + { + return; + } + len = trap_FS_FOpenFile(va("forcecfg/light/%s.fcf", uiInfo.forceConfigNames[newindex]), &f, FS_READ); + } + else + { //else dark + newindex += uiInfo.forceConfigDarkIndexBegin; + if (newindex >= uiInfo.forceConfigCount || newindex > uiInfo.forceConfigLightIndexBegin) + { //dark gets read in before light + return; + } + len = trap_FS_FOpenFile(va("forcecfg/dark/%s.fcf", uiInfo.forceConfigNames[newindex]), &f, FS_READ); + } if (len <= 0) - { - return; + { //This should not have happened. But, before we quit out, attempt searching the other light/dark folder for the file. + if (uiForceSide == FORCE_LIGHTSIDE) + { + len = trap_FS_FOpenFile(va("forcecfg/dark/%s.fcf", uiInfo.forceConfigNames[newindex]), &f, FS_READ); + } + else + { + len = trap_FS_FOpenFile(va("forcecfg/light/%s.fcf", uiInfo.forceConfigNames[newindex]), &f, FS_READ); + } + + if (len <= 0) + { //still failure? Oh well. + return; + } } if (len >= 8192) @@ -780,6 +1012,27 @@ void UI_ForceConfigHandle( int oldindex, int newindex ) i = 0; + info[0] = '\0'; + trap_GetConfigString(CS_SERVERINFO, info, sizeof(info)); + + if (atoi( Info_ValueForKey( info, "g_forceBasedTeams" ) )) + { + switch((int)(trap_Cvar_VariableValue("ui_myteam"))) + { + case TEAM_RED: + forceTeam = FORCE_DARKSIDE; + break; + case TEAM_BLUE: + forceTeam = FORCE_LIGHTSIDE; + break; + default: + break; + } + } + + BG_LegalizedForcePowers(fcfBuffer, uiMaxRank, ui_freeSaber.integer, forceTeam, atoi( Info_ValueForKey( info, "g_gametype" )), 0); + //legalize the config based on the max rank + //now that we're done with the handle, it's time to parse our force data out of the string //we store strings in rank-side-xxxxxxxxx format (where the x's are individual force power levels) while (fcfBuffer[i] && fcfBuffer[i] != '-') @@ -824,6 +1077,7 @@ void UI_ForceConfigHandle( int oldindex, int newindex ) //clear out the existing powers while (c < NUM_FORCE_POWERS) { + /* if (c==FP_LEVITATION) { uiForcePowersRank[c]=1; @@ -832,10 +1086,17 @@ void UI_ForceConfigHandle( int oldindex, int newindex ) { uiForcePowersRank[c]=1; } + else if (c==FP_SABERDEFEND && ui_freeSaber.integer) + { + uiForcePowersRank[c]=1; + } else { uiForcePowersRank[c] = 0; } + */ + //rww - don't need to do these checks. Just trust whatever the saber config says. + uiForcePowersRank[c] = 0; c++; } uiForceUsed = 0; @@ -868,17 +1129,30 @@ void UI_ForceConfigHandle( int oldindex, int newindex ) // Accrue cost for each assigned rank for this power. for (currank=FORCE_LEVEL_1;currank<=forcePowerRank;currank++) { - if (uiForcePowerCost[c][currank] > uiForceAvailable) + if (bgForcePowerCost[c][currank] > uiForceAvailable) { // Break out, we can't afford any more power. break; } // Pay for this rank of this power. - uiForceUsed += uiForcePowerCost[c][currank]; - uiForceAvailable -= uiForcePowerCost[c][currank]; + uiForceUsed += bgForcePowerCost[c][currank]; + uiForceAvailable -= bgForcePowerCost[c][currank]; uiForcePowersRank[c]++; } } + if (uiForcePowersRank[FP_LEVITATION] < 1) + { + uiForcePowersRank[FP_LEVITATION]=1; + } + if (uiForcePowersRank[FP_SABERATTACK] < 1 && ui_freeSaber.integer) + { + uiForcePowersRank[FP_SABERATTACK]=1; + } + if (uiForcePowersRank[FP_SABERDEFEND] < 1 && ui_freeSaber.integer) + { + uiForcePowersRank[FP_SABERDEFEND]=1; + } + UpdateForceUsed(); } diff --git a/CODE-mp/ui/ui_force.h b/CODE-mp/ui/ui_force.h index ed72e58..87576ac 100644 --- a/CODE-mp/ui/ui_force.h +++ b/CODE-mp/ui/ui_force.h @@ -10,15 +10,15 @@ extern int uiForceAvailable; extern qboolean gTouchedForce; extern int uiForcePowersRank[NUM_FORCE_POWERS]; extern int uiForcePowerDarkLight[NUM_FORCE_POWERS]; -extern int uiForcePowerCost[NUM_FORCE_POWERS][NUM_FORCE_POWER_LEVELS]; extern int uiSaberColorShaders[NUM_SABER_COLORS]; // Dots above or equal to a given rank carry a certain color. -extern vmCvar_t ui_freeSaber; +extern vmCvar_t ui_freeSaber, ui_forcePowerDisable; void UI_InitForceShaders(void); +void UI_ReadLegalForce(void); void UI_DrawTotalForceStars(rectDef_t *rect, float scale, vec4_t color, int textStyle); void UI_DrawForceStars(rectDef_t *rect, float scale, vec4_t color, int textStyle, int findex, int val, int min, int max) ; -void UI_UpdateClientForcePowers(); +void UI_UpdateClientForcePowers(const char *teamArg); void UI_SaveForceTemplate(); void UI_UpdateForcePowers(); qboolean UI_SkinColor_HandleKey(int flags, float *special, int key, int num, int min, int max, int type); diff --git a/CODE-mp/ui/ui_local.h b/CODE-mp/ui/ui_local.h index c1fc578..3d21ecd 100644 --- a/CODE-mp/ui/ui_local.h +++ b/CODE-mp/ui/ui_local.h @@ -18,6 +18,8 @@ extern vmCvar_t ui_ffa_timelimit; extern vmCvar_t ui_tourney_fraglimit; extern vmCvar_t ui_tourney_timelimit; +extern vmCvar_t ui_selectedModelIndex; + extern vmCvar_t ui_team_fraglimit; extern vmCvar_t ui_team_timelimit; extern vmCvar_t ui_team_friendly; @@ -123,7 +125,7 @@ extern vmCvar_t ui_serverStatusTimeOut; #define MAX_EDIT_LINE 256 #define MAX_MENUDEPTH 8 -#define MAX_MENUITEMS 128 +#define MAX_MENUITEMS 256 #define MAX_FORCE_CONFIGS 128 @@ -333,6 +335,7 @@ extern sfxHandle_t MenuField_Key( menufield_s* m, int* key ); // // ui_main.c // +qboolean UI_FeederSelection(float feederID, int index); void UI_Report(); void UI_Load(); void UI_LoadMenus(const char *menuFile, qboolean reset); @@ -341,6 +344,7 @@ int UI_AdjustTimeByGame(int time); void UI_ShowPostGame(qboolean newHigh); void UI_ClearScores(); void UI_LoadArenas(void); +void UI_LoadForceConfig_List( void ); // // ui_menu.c @@ -510,8 +514,8 @@ typedef struct { qhandle_t torsoSkin; lerpFrame_t torso; - qhandle_t headModel; - qhandle_t headSkin; +// qhandle_t headModel; +// qhandle_t headSkin; animation_t animations[MAX_TOTALANIMATIONS]; @@ -549,10 +553,10 @@ typedef struct { int realWeapon; } playerInfo_t; -void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ); -void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model, const char *headmodel, char *teamName ); -void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNum, qboolean chat ); -qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName , const char *headName, const char *teamName); +//void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ); +//void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model, const char *headmodel, char *teamName ); +//void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNum, qboolean chat ); +//qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName , const char *headName, const char *teamName); // // ui_atoms.c @@ -827,6 +831,9 @@ typedef struct { int forceConfigCount; int forceConfigSelected; char forceConfigNames[MAX_FORCE_CONFIGS][128]; + qboolean forceConfigSide[MAX_FORCE_CONFIGS]; //true if it's a light side config, false if dark side + int forceConfigDarkIndexBegin; //mark the index number dark configs start at + int forceConfigLightIndexBegin; //mark the index number light configs start at int effectsColor; diff --git a/CODE-mp/ui/ui_main.c b/CODE-mp/ui/ui_main.c index 60665fa..2737217 100644 --- a/CODE-mp/ui/ui_main.c +++ b/CODE-mp/ui/ui_main.c @@ -13,110 +13,19 @@ USER INTERFACE MAIN #include "ui_local.h" #include "../qcommon/qfiles.h" +#include "../qcommon/game_version.h" #include "ui_force.h" -menuDef_t *Menus_FindByName(const char *p); -void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow); -void UpdateForceUsed(); - -char holdSPString[1024]={0}; - -uiInfo_t uiInfo; - -static const char *MonthAbbrev[] = { - "Jan","Feb","Mar", - "Apr","May","Jun", - "Jul","Aug","Sep", - "Oct","Nov","Dec" -}; - - -static const char *skillLevels[] = { - "SKILL1",//"I Can Win", - "SKILL2",//"Bring It On", - "SKILL3",//"Hurt Me Plenty", - "SKILL4",//"Hardcore", - "SKILL5"//"Nightmare" -}; - -static const int numSkillLevels = sizeof(skillLevels) / sizeof(const char*); - - -static const char *netSources[] = { - "Local", - "Mplayer", - "Internet", - "Favorites" -}; -static const int numNetSources = sizeof(netSources) / sizeof(const char*); - -static const serverFilter_t serverFilters[] = { - {"All", "" }, - {"Jedi Knight 2", "" }, -}; - -static const char *teamArenaGameTypes[] = { - "FFA", - "HOLOCRON", - "JEDIMASTER", - "DUEL", - "SP", - "TEAM FFA", - "SAGA", - "CTF", - "CTY", - "TEAMTOURNAMENT" -}; - -static int const numTeamArenaGameTypes = sizeof(teamArenaGameTypes) / sizeof(const char*); - - -static const int numServerFilters = sizeof(serverFilters) / sizeof(serverFilter_t); - - -static char* netnames[] = { - "???", - "UDP", - "IPX", - NULL -}; - -static int gamecodetoui[] = {4,2,3,0,5,1,6}; -static int uitogamecode[] = {4,6,2,3,1,5,7}; - - -static void UI_StartServerRefresh(qboolean full); -static void UI_StopServerRefresh( void ); -static void UI_DoServerRefresh( void ); -static void UI_FeederSelection(float feederID, int index); -static void UI_BuildServerDisplayList(qboolean force); -static void UI_BuildServerStatus(qboolean force); -static void UI_BuildFindPlayerList(qboolean force); -static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 ); -static int UI_MapCountByGameType(qboolean singlePlayer); -static int UI_HeadCountByTeam( void ); -static int UI_HeadCountByColor( void ); -static void UI_ParseGameInfo(const char *teamFile); -static void UI_ParseTeamInfo(const char *teamFile); -static const char *UI_SelectedMap(int index, int *actual); -static const char *UI_SelectedHead(int index, int *actual); -static int UI_GetIndexFromSelection(int actual); - -int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 ); -int uiSkinColor=TEAM_FREE; - /* ================ vmMain This is the only way control passes into the module. -This must be the very first function compiled into the .qvm file +!!! This MUST BE THE VERY FIRST FUNCTION compiled into the .qvm file !!! ================ */ -vmCvar_t ui_new; vmCvar_t ui_debug; vmCvar_t ui_initialized; -vmCvar_t ui_teamArenaFirstRun; void _UI_Init( qboolean ); void _UI_Shutdown( void ); @@ -170,6 +79,135 @@ int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int a return -1; } +menuDef_t *Menus_FindByName(const char *p); +void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow); +void UpdateForceUsed(); + +char holdSPString[1024]={0}; + +uiInfo_t uiInfo; + +static void UI_StartServerRefresh(qboolean full); +static void UI_StopServerRefresh( void ); +static void UI_DoServerRefresh( void ); +static void UI_BuildServerDisplayList(qboolean force); +static void UI_BuildServerStatus(qboolean force); +static void UI_BuildFindPlayerList(qboolean force); +static int QDECL UI_ServersQsortCompare( const void *arg1, const void *arg2 ); +static int UI_MapCountByGameType(qboolean singlePlayer); +static int UI_HeadCountByTeam( void ); +static int UI_HeadCountByColor( void ); +static void UI_ParseGameInfo(const char *teamFile); +static const char *UI_SelectedMap(int index, int *actual); +static const char *UI_SelectedHead(int index, int *actual); +static int UI_GetIndexFromSelection(int actual); + +int ProcessNewUI( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6 ); +int uiSkinColor=TEAM_FREE; + +static const serverFilter_t serverFilters[] = { + {"All", "" }, + {"Jedi Knight 2", "" }, +}; +static const int numServerFilters = sizeof(serverFilters) / sizeof(serverFilter_t); + + + + +static const char *skillLevels[] = { + "SKILL1",//"I Can Win", + "SKILL2",//"Bring It On", + "SKILL3",//"Hurt Me Plenty", + "SKILL4",//"Hardcore", + "SKILL5"//"Nightmare" +}; +static const int numSkillLevels = sizeof(skillLevels) / sizeof(const char*); + + + +static const char *teamArenaGameTypes[] = { + "FFA", + "HOLOCRON", + "JEDIMASTER", + "DUEL", + "SP", + "TEAM FFA", + "N/A", + "CTF", + "CTY", + "TEAMTOURNAMENT" +}; +static int const numTeamArenaGameTypes = sizeof(teamArenaGameTypes) / sizeof(const char*); + + + +static char* netnames[] = { + "???", + "UDP", + "IPX", + NULL +}; + +static int gamecodetoui[] = {4,2,3,0,5,1,6}; +static int uitogamecode[] = {4,6,2,3,1,5,7}; + +const char *UI_GetStripEdString(const char *refSection, const char *refName); + +// returns either string or NULL for OOR... +// +static const char *GetCRDelineatedString( const char *psStripFileRef, const char *psStripStringRef, int iIndex) +{ + static char sTemp[256]; + const char *psList = UI_GetStripEdString(psStripFileRef, psStripStringRef); + char *p; + + while (iIndex--) + { + psList = strchr(psList,'\n'); + if (!psList){ + return NULL; // OOR + } + psList++; + } + + strcpy(sTemp,psList); + p = strchr(sTemp,'\n'); + if (p) { + *p = '\0'; + } + + return sTemp; +} + + +static const char *GetMonthAbbrevString( int iMonth ) +{ + const char *p = GetCRDelineatedString("INGAMETEXT","MONTHS", iMonth); + + return p ? p : "Jan"; // sanity +} + + + + +/* +static const char *netSources[] = { + "Local", + "Internet", + "Favorites" +// "Mplayer" +}; +static const int numNetSources = sizeof(netSources) / sizeof(const char*); +*/ +static const int numNetSources = 3; // now hard-entered in StripEd file +static const char *GetNetSourceString(int iSource) +{ + const char *p = GetCRDelineatedString("INGAMETEXT","NET_SOURCES", iSource); + + return p ? p : "??"; +} + + void AssetCache() { @@ -395,7 +433,7 @@ char parsedFPMessage[1024]; extern int FPMessageTime; void Text_PaintCenter(float x, float y, float scale, vec4_t color, const char *text, float adjust, int iMenuFont); -const char *UI_GetStripEdString(char *refSection, char *refName) +const char *UI_GetStripEdString(const char *refSection, const char *refName) { static char text[1024]={0}; @@ -449,7 +487,7 @@ void _UI_Refresh( int realtime ) // draw cursor UI_SetColor( NULL ); if (Menu_Count() > 0) { - UI_DrawHandlePic( uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory, 32, 32, uiInfo.uiDC.Assets.cursor); + UI_DrawHandlePic( uiInfo.uiDC.cursorx, uiInfo.uiDC.cursory, 48, 48, uiInfo.uiDC.Assets.cursor); } #ifndef NDEBUG @@ -463,11 +501,9 @@ void _UI_Refresh( int realtime ) if (ui_rankChange.integer) { - int x = 0; - FPMessageTime = realtime + 3000; - if (!parsedFPMessage[0] && uiMaxRank > ui_rankChange.integer) + if (!parsedFPMessage[0] /*&& uiMaxRank > ui_rankChange.integer*/) { const char *printMessage = UI_GetStripEdString("INGAMETEXT", "SET_NEW_RANK"); @@ -492,11 +528,12 @@ void _UI_Refresh( int realtime ) parsedFPMessage[p] = '\0'; } - if (uiMaxRank > ui_rankChange.integer) + //if (uiMaxRank > ui_rankChange.integer) { uiMaxRank = ui_rankChange.integer; - uiForceRank = uiMaxRank; + + /* while (x < NUM_FORCE_POWERS) { //For now just go ahead and clear force powers upon rank change @@ -504,17 +541,39 @@ void _UI_Refresh( int realtime ) x++; } uiForcePowersRank[FP_LEVITATION] = 1; - uiForceUsed = 0; + */ + + //Use BG_LegalizedForcePowers and transfer the result into the UI force settings + UI_ReadLegalForce(); } if (ui_freeSaber.integer && uiForcePowersRank[FP_SABERATTACK] < 1) { uiForcePowersRank[FP_SABERATTACK] = 1; } + if (ui_freeSaber.integer && uiForcePowersRank[FP_SABERDEFEND] < 1) + { + uiForcePowersRank[FP_SABERDEFEND] = 1; + } trap_Cvar_Set("ui_rankChange", "0"); + + //remember to update the force power count after changing the max rank + UpdateForceUsed(); } + if (ui_freeSaber.integer) + { + bgForcePowerCost[FP_SABERATTACK][FORCE_LEVEL_1] = 0; + bgForcePowerCost[FP_SABERDEFEND][FORCE_LEVEL_1] = 0; + } + else + { + bgForcePowerCost[FP_SABERATTACK][FORCE_LEVEL_1] = 1; + bgForcePowerCost[FP_SABERDEFEND][FORCE_LEVEL_1] = 1; + } + + /* if (parsedFPMessage[0] && FPMessageTime > realtime) { vec4_t txtCol; @@ -539,6 +598,8 @@ void _UI_Refresh( int realtime ) Text_Paint(10, 0, 1, txtCol, parsedFPMessage, 0, 1024, txtStyle, FONT_MEDIUM); } + */ + //For now, don't bother. } /* @@ -577,6 +638,7 @@ char *GetMenuBuffer(const char *filename) { } qboolean Asset_Parse(int handle) { + char stripedFile[MAX_STRING_CHARS]; pc_token_t token; const char *tempStr; @@ -636,13 +698,8 @@ qboolean Asset_Parse(int handle) { Com_Printf(S_COLOR_YELLOW,"Bad 1st parameter for keyword 'stripedFile'"); return qfalse; } - - Q_strncpyz( (char *) uiInfo.uiDC.Assets.stripedFile, tempStr, sizeof(uiInfo.uiDC.Assets.stripedFile) ); - - trap_SP_Register(uiInfo.uiDC.Assets.stripedFile); - - Menu_currentStipEdFile(uiInfo.uiDC.Assets.stripedFile); - + Q_strncpyz( stripedFile, tempStr, sizeof(stripedFile) ); + trap_SP_Register(stripedFile); continue; } @@ -835,8 +892,6 @@ void UI_LoadMenus(const char *menuFile, qboolean reset) { int handle; int start; - Menu_currentStipEdFile("MP_MENUS"); - start = trap_Milliseconds(); trap_PC_LoadGlobalDefines ( "ui/jk2mp/menudef.h" ); @@ -850,8 +905,6 @@ void UI_LoadMenus(const char *menuFile, qboolean reset) { } } - ui_new.integer = 1; - if (reset) { Menu_Reset(); } @@ -884,12 +937,26 @@ void UI_LoadMenus(const char *menuFile, qboolean reset) { } void UI_Load() { + char *menuSet; char lastName[1024]; - menuDef_t *menu = Menu_GetFocused(); - char *menuSet = UI_Cvar_VariableString("ui_menuFiles"); + menuDef_t *menu = Menu_GetFocused(); + if (menu && menu->window.name) { strcpy(lastName, menu->window.name); } + else + { + lastName[0] = 0; + } + + if (uiInfo.inGameLoad) + { + menuSet= "ui/jk2mpingame.txt"; + } + else + { + menuSet= UI_Cvar_VariableString("ui_menuFilesMP"); + } if (menuSet == NULL || menuSet[0] == '\0') { menuSet = "ui/jk2mpmenus.txt"; } @@ -900,8 +967,9 @@ void UI_Load() { UI_ParseGameInfo("demogameinfo.txt"); #else UI_ParseGameInfo("ui/jk2mp/gameinfo.txt"); - UI_LoadArenas(); #endif + UI_LoadArenas(); + UI_LoadBots(); UI_LoadMenus(menuSet, qtrue); Menus_CloseAll(); @@ -1089,7 +1157,7 @@ static void UI_DrawGenericNum(rectDef_t *rect, float scale, vec4_t color, int te static void UI_DrawForceMastery(rectDef_t *rect, float scale, vec4_t color, int textStyle, int val, int min, int max, int iMenuFont) { int i; - char s[256]; + char *s; i = val; if (i < min || i > max) @@ -1097,9 +1165,8 @@ static void UI_DrawForceMastery(rectDef_t *rect, float scale, vec4_t color, int i = min; } - Com_sprintf(s, sizeof(s), forceMasteryLevels[val]); - - Text_Paint(rect->x, rect->y, scale, color, s,0, 0, textStyle, iMenuFont); + s = (char *)UI_GetStripEdString("INGAMETEXT", forceMasteryLevels[val]); + Text_Paint(rect->x, rect->y, scale, color, s, 0, 0, textStyle, iMenuFont); } @@ -1135,6 +1202,8 @@ static void UI_DrawForceSide(rectDef_t *rect, float scale, vec4_t color, int tex int i; char s[256]; menuDef_t *menu; + + char info[MAX_INFO_VALUE]; i = val; if (i < min || i > max) @@ -1142,9 +1211,33 @@ static void UI_DrawForceSide(rectDef_t *rect, float scale, vec4_t color, int tex i = min; } + info[0] = '\0'; + trap_GetConfigString(CS_SERVERINFO, info, sizeof(info)); + + if (atoi( Info_ValueForKey( info, "g_forceBasedTeams" ) )) + { + switch((int)(trap_Cvar_VariableValue("ui_myteam"))) + { + case TEAM_RED: + uiForceSide = FORCE_DARKSIDE; + color[0] = 0.2; + color[1] = 0.2; + color[2] = 0.2; + break; + case TEAM_BLUE: + uiForceSide = FORCE_LIGHTSIDE; + color[0] = 0.2; + color[1] = 0.2; + color[2] = 0.2; + break; + default: + break; + } + } + if (val == FORCE_LIGHTSIDE) { - Com_sprintf(s, sizeof(s), "Light\0"); + trap_SP_GetStringTextString("MENUS3_FORCEDESC_LIGHT",s, sizeof(s)); menu = Menus_FindByName("forcealloc"); if (menu) { @@ -1167,8 +1260,7 @@ static void UI_DrawForceSide(rectDef_t *rect, float scale, vec4_t color, int tex } else { - Com_sprintf(s, sizeof(s), "Dark\0"); - + trap_SP_GetStringTextString("MENUS3_FORCEDESC_DARK",s, sizeof(s)); menu = Menus_FindByName("forcealloc"); if (menu) { @@ -1236,11 +1328,13 @@ static void UI_DrawTeamMember(rectDef_t *rect, float scale, vec4_t color, qboole if (value <= 1) { if (value == -1) { - text = "Closed"; + //text = "Closed"; + text = UI_GetStripEdString("MENUS3", "CLOSED"); } else { - text = "Human"; + //text = "Human"; + text = UI_GetStripEdString("MENUS3", "HUMAN"); } } else { value -= 2; @@ -1339,9 +1433,133 @@ static void UI_DrawMapCinematic(rectDef_t *rect, float scale, vec4_t color, qboo } +void UpdateForceStatus() +{ + menuDef_t *menu; + + // Currently we don't make a distinction between those that wish to play Jedi of lower than maximum skill. +/* if (ui_forcePowerDisable.integer) + { + uiForceRank = 0; + uiForceAvailable = 0; + uiForceUsed = 0; + } + else + { + uiForceRank = uiMaxRank; + uiForceUsed = 0; + uiForceAvailable = forceMasteryPoints[uiForceRank]; + } +*/ + menu = Menus_FindByName("ingame_player"); + if (menu) + { + char info[MAX_INFO_STRING]; + + if (uiForcePowersRank[FP_SABERATTACK] > 0 || ui_freeSaber.integer) + { // Show lightsaber stuff. + Menu_ShowItemByName(menu, "nosaber", qfalse); + Menu_ShowItemByName(menu, "yessaber", qtrue); + } + else + { + Menu_ShowItemByName(menu, "nosaber", qtrue); + Menu_ShowItemByName(menu, "yessaber", qfalse); + } + + trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ); + + //already have serverinfo at this point for stuff below. Don't bother trying to use ui_forcePowerDisable. + //if (ui_forcePowerDisable.integer) + if (atoi(Info_ValueForKey(info, "g_forcePowerDisable"))) + { // No force stuff + Menu_ShowItemByName(menu, "noforce", qtrue); + Menu_ShowItemByName(menu, "yesforce", qfalse); + // We don't want the saber explanation to say "configure saber attack 1" since we can't. + Menu_ShowItemByName(menu, "sabernoneconfigme", qfalse); + } + else + { + Menu_ShowItemByName(menu, "noforce", qfalse); + Menu_ShowItemByName(menu, "yesforce", qtrue); + } + + // The leftmost button should be "apply" unless you are in spectator, where you can join any team. + if ((int)(trap_Cvar_VariableValue("ui_myteam")) != TEAM_SPECTATOR) + { + Menu_ShowItemByName(menu, "playerapply", qtrue); + Menu_ShowItemByName(menu, "playerforcejoin", qfalse); + Menu_ShowItemByName(menu, "playerforcered", qfalse); + Menu_ShowItemByName(menu, "playerforceblue", qfalse); + Menu_ShowItemByName(menu, "playerforcespectate", qtrue); + } + else + { + // Set or reset buttons based on choices + if (atoi(Info_ValueForKey(info, "g_gametype")) >= GT_TEAM) + { // This is a team-based game. + Menu_ShowItemByName(menu, "playerforcespectate", qtrue); + + // This is disabled, always show both sides from spectator. + if ( 0 && atoi(Info_ValueForKey(info, "g_forceBasedTeams"))) + { // Show red or blue based on what side is chosen. + if (uiForceSide==FORCE_LIGHTSIDE) + { + Menu_ShowItemByName(menu, "playerforcered", qfalse); + Menu_ShowItemByName(menu, "playerforceblue", qtrue); + } + else if (uiForceSide==FORCE_DARKSIDE) + { + Menu_ShowItemByName(menu, "playerforcered", qtrue); + Menu_ShowItemByName(menu, "playerforceblue", qfalse); + } + else + { + Menu_ShowItemByName(menu, "playerforcered", qtrue); + Menu_ShowItemByName(menu, "playerforceblue", qtrue); + } + } + else + { + Menu_ShowItemByName(menu, "playerforcered", qtrue); + Menu_ShowItemByName(menu, "playerforceblue", qtrue); + } + } + else + { + Menu_ShowItemByName(menu, "playerforcered", qfalse); + Menu_ShowItemByName(menu, "playerforceblue", qfalse); + } + + Menu_ShowItemByName(menu, "playerapply", qfalse); + Menu_ShowItemByName(menu, "playerforcejoin", qtrue); + Menu_ShowItemByName(menu, "playerforcespectate", qtrue); + } + } + + + // Take the current team and force a skin color based on it. + switch((int)(trap_Cvar_VariableValue("ui_myteam"))) + { + case TEAM_RED: + uiSkinColor = TEAM_RED; + uiInfo.effectsColor = SABER_RED; + break; + case TEAM_BLUE: + uiSkinColor = TEAM_BLUE; + uiInfo.effectsColor = SABER_BLUE; + break; + default: + uiSkinColor = TEAM_FREE; + break; + } +} + + static qboolean updateModel = qtrue; static qboolean q3Model = qfalse; +/* static void UI_DrawPlayerModel(rectDef_t *rect) { static playerInfo_t info; @@ -1384,7 +1602,7 @@ static void UI_DrawPlayerModel(rectDef_t *rect) { UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info, uiInfo.uiDC.realTime / 2); } - +*/ static void UI_DrawNetSource(rectDef_t *rect, float scale, vec4_t color, int textStyle, int iMenuFont) { if (ui_netSource.integer < 0 || ui_netSource.integer > uiInfo.numGameTypes) @@ -1392,9 +1610,9 @@ static void UI_DrawNetSource(rectDef_t *rect, float scale, vec4_t color, int tex ui_netSource.integer = 0; } - trap_SP_GetStringTextString((char *)va("%s_SOURCE",uiInfo.uiDC.Assets.stripedFile), holdSPString, sizeof(holdSPString) ); + trap_SP_GetStringTextString("MENUS3_SOURCE", holdSPString, sizeof(holdSPString) ); Text_Paint(rect->x, rect->y, scale, color, va("%s %s",holdSPString, - netSources[ui_netSource.integer]), 0, 0, textStyle, iMenuFont); + GetNetSourceString(ui_netSource.integer)), 0, 0, textStyle, iMenuFont); } static void UI_DrawNetMapPreview(rectDef_t *rect, float scale, vec4_t color) { @@ -1430,7 +1648,7 @@ static void UI_DrawNetFilter(rectDef_t *rect, float scale, vec4_t color, int tex ui_serverFilterType.integer = 0; } - trap_SP_GetStringTextString((char *)va("%s_SERVER_FILTER",uiInfo.uiDC.Assets.stripedFile), holdSPString, sizeof(holdSPString)); + trap_SP_GetStringTextString("MENUS3_GAME", holdSPString, sizeof(holdSPString)); Text_Paint(rect->x, rect->y, scale, color, va("%s %s",holdSPString, serverFilters[ui_serverFilterType.integer].description), 0, 0, textStyle, iMenuFont); } @@ -1509,6 +1727,7 @@ static const char *UI_AIFromName(const char *name) { } +/* static qboolean updateOpponentModel = qtrue; static void UI_DrawOpponent(rectDef_t *rect) { static playerInfo_t info2; @@ -1538,7 +1757,7 @@ static void UI_DrawOpponent(rectDef_t *rect) { UI_DrawPlayer( rect->x, rect->y, rect->w, rect->h, &info2, uiInfo.uiDC.realTime / 2); } - +*/ static void UI_NextOpponent() { int i = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_opponentName")); int j = UI_TeamIndexFromName(UI_Cvar_VariableString("ui_teamName")); @@ -1666,6 +1885,7 @@ static int UI_OwnerDrawWidth(int ownerDraw, float scale) { const char *text; const char *s = NULL; + switch (ownerDraw) { case UI_HANDICAP: h = Com_Clamp( 5, 100, trap_Cvar_VariableValue("handicap") ); @@ -1694,11 +1914,13 @@ static int UI_OwnerDrawWidth(int ownerDraw, float scale) { if (i == FORCE_LIGHTSIDE) { - s = "Light"; +// s = "Light"; + s = (char *)UI_GetStripEdString("MENUS3", "FORCEDESC_LIGHT"); } else { - s = "Dark"; +// s = "Dark"; + s = (char *)UI_GetStripEdString("MENUS3", "FORCEDESC_DARK"); } break; case UI_FORCE_RANK: @@ -1707,7 +1929,7 @@ static int UI_OwnerDrawWidth(int ownerDraw, float scale) { i = 1; } - s = forceMasteryLevels[i]; + s = (char *)UI_GetStripEdString("INGAMETEXT", forceMasteryLevels[i]); break; case UI_FORCE_RANK_HEAL: case UI_FORCE_RANK_LEVITATION: @@ -1825,13 +2047,15 @@ static int UI_OwnerDrawWidth(int ownerDraw, float scale) { if (ui_netSource.integer < 0 || ui_netSource.integer > uiInfo.numJoinGameTypes) { ui_netSource.integer = 0; } - s = va("Source: %s", netSources[ui_netSource.integer]); + trap_SP_GetStringTextString("MENUS3_SOURCE", holdSPString, sizeof(holdSPString)); + s = va("%s %s", holdSPString, GetNetSourceString(ui_netSource.integer)); break; case UI_NETFILTER: if (ui_serverFilterType.integer < 0 || ui_serverFilterType.integer > numServerFilters) { ui_serverFilterType.integer = 0; } - s = va("Filter: %s", serverFilters[ui_serverFilterType.integer].description ); + trap_SP_GetStringTextString("MENUS3_GAME", holdSPString, sizeof(holdSPString)); + s = va("%s %s", holdSPString, serverFilters[ui_serverFilterType.integer].description ); break; case UI_TIER: break; @@ -1845,9 +2069,9 @@ static int UI_OwnerDrawWidth(int ownerDraw, float scale) { break; case UI_KEYBINDSTATUS: if (Display_KeyBindPending()) { - s = "Waiting for new key... Press ESCAPE to cancel"; + s = UI_GetStripEdString("INGAMETEXT", "WAITING_FOR_NEW_KEY"); } else { - s = "Press ENTER or CLICK to change, Press BACKSPACE to clear"; + // s = "Press ENTER or CLICK to change, Press BACKSPACE to clear"; } break; case UI_SERVERREFRESHDATE: @@ -1993,14 +2217,14 @@ static void UI_DrawServerRefreshDate(rectDef_t *rect, float scale, vec4_t color, lowLight[3] = 0.8 * color[3]; LerpColor(color,lowLight,newColor,0.5+0.5*sin(uiInfo.uiDC.realTime / PULSE_DIVISOR)); - trap_SP_GetStringTextString((char *)va("%s_GETTINGINFOFORSERVERS",uiInfo.uiDC.Assets.stripedFile), holdSPString, sizeof(holdSPString)); + trap_SP_GetStringTextString("INGAMETEXT_GETTINGINFOFORSERVERS", holdSPString, sizeof(holdSPString)); Text_Paint(rect->x, rect->y, scale, newColor, va((char *) holdSPString, trap_LAN_GetServerCount(ui_netSource.integer)), 0, 0, textStyle, iMenuFont); } else { char buff[64]; Q_strncpyz(buff, UI_Cvar_VariableString(va("ui_lastServerRefresh_%i", ui_netSource.integer)), 64); - trap_SP_GetStringTextString((char *)va("%s_SERVER_REFRESHTIME",uiInfo.uiDC.Assets.stripedFile), holdSPString, sizeof(holdSPString)); + trap_SP_GetStringTextString("INGAMETEXT_SERVER_REFRESHTIME", holdSPString, sizeof(holdSPString)); Text_Paint(rect->x, rect->y, scale, color, va("%s: %s", holdSPString, buff), 0, 0, textStyle, iMenuFont); } @@ -2069,9 +2293,9 @@ static void UI_DrawKeyBindStatus(rectDef_t *rect, float scale, vec4_t color, int // int ofs = 0; TTimo: unused if (Display_KeyBindPending()) { - Text_Paint(rect->x, rect->y, scale, color, "Waiting for new key... Press ESCAPE to cancel", 0, 0, textStyle,iMenuFont); + Text_Paint(rect->x, rect->y, scale, color, UI_GetStripEdString("INGAMETEXT", "WAITING_FOR_NEW_KEY"), 0, 0, textStyle,iMenuFont); } else { - Text_Paint(rect->x, rect->y, scale, color, "Press ENTER or CLICK to change, Press BACKSPACE to clear", 0, 0, textStyle,iMenuFont); +// Text_Paint(rect->x, rect->y, scale, color, "Press ENTER or CLICK to change, Press BACKSPACE to clear", 0, 0, textStyle,iMenuFont); } } @@ -2079,12 +2303,12 @@ static void UI_DrawGLInfo(rectDef_t *rect, float scale, vec4_t color, int textSt { char * eptr; char buff[4096]; - const char *lines[64]; + const char *lines[128]; int y, numLines, i; - Text_Paint(rect->x + 2, rect->y, scale, color, va("VENDOR: %s", uiInfo.uiDC.glconfig.vendor_string), 0, 30, textStyle,iMenuFont); - Text_Paint(rect->x + 2, rect->y + 15, scale, color, va("VERSION: %s: %s", uiInfo.uiDC.glconfig.version_string,uiInfo.uiDC.glconfig.renderer_string), 0, 30, textStyle,iMenuFont); - Text_Paint(rect->x + 2, rect->y + 30, scale, color, va ("PIXELFORMAT: color(%d-bits) Z(%d-bits) stencil(%d-bits)", uiInfo.uiDC.glconfig.colorBits, uiInfo.uiDC.glconfig.depthBits, uiInfo.uiDC.glconfig.stencilBits), 0, 30, textStyle,iMenuFont); + Text_Paint(rect->x + 2, rect->y, scale, color, va("GL_VENDOR: %s", uiInfo.uiDC.glconfig.vendor_string), 0, 30, textStyle,iMenuFont); + Text_Paint(rect->x + 2, rect->y + 15, scale, color, va("GL_VERSION: %s: %s", uiInfo.uiDC.glconfig.version_string,uiInfo.uiDC.glconfig.renderer_string), 0, 30, textStyle,iMenuFont); + Text_Paint(rect->x + 2, rect->y + 30, scale, color, va ("GL_PIXELFORMAT: color(%d-bits) Z(%d-bits) stencil(%d-bits)", uiInfo.uiDC.glconfig.colorBits, uiInfo.uiDC.glconfig.depthBits, uiInfo.uiDC.glconfig.stencilBits), 0, 30, textStyle,iMenuFont); // build null terminated extension strings Q_strncpyz(buff, uiInfo.uiDC.glconfig.extensions_string, 4096); @@ -2171,7 +2395,7 @@ static void UI_OwnerDraw(float x, float y, float w, float h, float text_x, float UI_DrawGenericNum(&rect, scale, color, textStyle, uiForceAvailable, 1, forceMasteryPoints[MAX_FORCE_RANK], ownerDraw,iMenuFont); break; case UI_FORCE_MASTERY_SET: - UI_DrawForceMastery(&rect, scale, color, textStyle, uiMaxRank, 0, MAX_FORCE_RANK, iMenuFont); + UI_DrawForceMastery(&rect, scale, color, textStyle, uiForceRank, 0, MAX_FORCE_RANK, iMenuFont); break; case UI_FORCE_RANK: UI_DrawForceMastery(&rect, scale, color, textStyle, uiForceRank, 0, MAX_FORCE_RANK, iMenuFont); @@ -2217,7 +2441,7 @@ static void UI_OwnerDraw(float x, float y, float w, float h, float text_x, float color[1] *= 0.5; color[2] *= 0.5; } -/* else if (uiForceRank < UI_ForceColorMinRank[uiForcePowerCost[findex][FORCE_LEVEL_1]]) +/* else if (uiForceRank < UI_ForceColorMinRank[bgForcePowerCost[findex][FORCE_LEVEL_1]]) { color[0] *= 0.5; color[1] *= 0.5; @@ -2231,7 +2455,7 @@ static void UI_OwnerDraw(float x, float y, float w, float h, float text_x, float UI_DrawEffects(&rect, scale, color); break; case UI_PLAYERMODEL: - UI_DrawPlayerModel(&rect); + //UI_DrawPlayerModel(&rect); break; case UI_CLANNAME: UI_DrawClanName(&rect, scale, color, textStyle, iMenuFont); @@ -2333,7 +2557,7 @@ static void UI_OwnerDraw(float x, float y, float w, float h, float text_x, float UI_DrawTier(&rect, scale, color, textStyle, iMenuFont); break; case UI_OPPONENTMODEL: - UI_DrawOpponent(&rect); + //UI_DrawOpponent(&rect); break; case UI_TIERMAP1: UI_DrawTierMap(&rect, 0); @@ -2548,6 +2772,14 @@ static qboolean UI_Handicap_HandleKey(int flags, float *special, int key) { static qboolean UI_Effects_HandleKey(int flags, float *special, int key) { if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_ENTER || key == K_KP_ENTER) { + int team = (int)(trap_Cvar_VariableValue("ui_myteam")); + + if (team == TEAM_RED || team==TEAM_BLUE) + { + return qfalse; + } + + if (key == K_MOUSE2) { uiInfo.effectsColor--; } else { @@ -2669,9 +2901,9 @@ static qboolean UI_AutoSwitch_HandleKey(int flags, float *special, int key) { if (switchVal < 0) { - switchVal = 3; + switchVal = 2; } - else if (switchVal >= 4) + else if (switchVal >= 3) { switchVal = 0; } @@ -3212,30 +3444,6 @@ static void UI_LoadMods() { } -/* -=============== -UI_LoadTeams -=============== -*/ -static void UI_LoadTeams() { - char teamList[4096]; - char *teamName; - int i, len, count; - - count = trap_FS_GetFileList( "", "team", teamList, 4096 ); - - if (count) { - teamName = teamList; - for ( i = 0; i < count; i++ ) { - len = strlen( teamName ); - UI_ParseTeamInfo(teamName); - teamName += len + 1; - } - } - -} - - /* =============== UI_LoadMovies @@ -3352,6 +3560,8 @@ static void UI_StartSkirmish(qboolean next) { trap_Cvar_Set("ui_saveCaptureLimit", va("%i", temp)); temp = trap_Cvar_VariableValue( "fraglimit" ); trap_Cvar_Set("ui_saveFragLimit", va("%i", temp)); + temp = trap_Cvar_VariableValue( "duel_fraglimit" ); + trap_Cvar_Set("ui_saveDuelLimit", va("%i", temp)); UI_SetCapFragLimits(qfalse); @@ -3427,6 +3637,12 @@ static void UI_StartSkirmish(qboolean next) { static void UI_Update(const char *name) { int val = trap_Cvar_VariableValue(name); + if (Q_stricmp(name, "s_khz") == 0) + { + trap_Cmd_ExecuteText( EXEC_APPEND, "snd_restart\n" ); + return; + } + if (Q_stricmp(name, "ui_SetName") == 0) { trap_Cvar_Set( "name", UI_Cvar_VariableString("ui_Name")); } else if (Q_stricmp(name, "ui_setRate") == 0) { @@ -3441,99 +3657,120 @@ static void UI_Update(const char *name) { trap_Cvar_Set("cl_maxpackets", "15"); trap_Cvar_Set("cl_packetdup", "1"); // favor lower bandwidth } - } else if (Q_stricmp(name, "ui_GetName") == 0) { + } + else if (Q_stricmp(name, "ui_GetName") == 0) + { trap_Cvar_Set( "ui_Name", UI_Cvar_VariableString("name")); - } else if (Q_stricmp(name, "r_colorbits") == 0) { - switch (val) { + } + else if (Q_stricmp(name, "ui_r_colorbits") == 0) + { + switch (val) + { case 0: - trap_Cvar_SetValue( "r_depthbits", 0 ); - break; + trap_Cvar_SetValue( "ui_r_depthbits", 0 ); + break; + case 16: - trap_Cvar_SetValue( "r_depthbits", 16 ); - break; + trap_Cvar_SetValue( "ui_r_depthbits", 16 ); + break; + case 32: - trap_Cvar_SetValue( "r_depthbits", 24 ); - break; + trap_Cvar_SetValue( "ui_r_depthbits", 24 ); + break; } - } else if (Q_stricmp(name, "r_lodbias") == 0) { - switch (val) { + } + else if (Q_stricmp(name, "ui_r_lodbias") == 0) + { + switch (val) + { case 0: - trap_Cvar_SetValue( "r_subdivisions", 4 ); - break; + trap_Cvar_SetValue( "ui_r_subdivisions", 4 ); + break; case 1: - trap_Cvar_SetValue( "r_subdivisions", 12 ); - break; + trap_Cvar_SetValue( "ui_r_subdivisions", 12 ); + break; + case 2: - trap_Cvar_SetValue( "r_subdivisions", 20 ); - break; + trap_Cvar_SetValue( "ui_r_subdivisions", 20 ); + break; } - } else if (Q_stricmp(name, "ui_glCustom") == 0) { - switch (val) { + } + else if (Q_stricmp(name, "ui_r_glCustom") == 0) + { + switch (val) + { case 0: // high quality - trap_Cvar_SetValue( "r_fullScreen", 1 ); - trap_Cvar_SetValue( "r_subdivisions", 4 ); - trap_Cvar_SetValue( "r_vertexlight", 0 ); - trap_Cvar_SetValue( "r_lodbias", 0 ); - trap_Cvar_SetValue( "r_colorbits", 32 ); - trap_Cvar_SetValue( "r_depthbits", 24 ); - trap_Cvar_SetValue( "r_picmip", 0 ); - trap_Cvar_SetValue( "r_mode", 4 ); - trap_Cvar_SetValue( "r_texturebits", 32 ); - trap_Cvar_SetValue( "r_fastSky", 0 ); - trap_Cvar_SetValue( "r_inGameVideo", 1 ); - trap_Cvar_SetValue( "cg_shadows", 1 ); - trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); - break; + + trap_Cvar_SetValue( "ui_r_fullScreen", 1 ); + trap_Cvar_SetValue( "ui_r_subdivisions", 4 ); + trap_Cvar_SetValue( "ui_r_lodbias", 0 ); + trap_Cvar_SetValue( "ui_r_colorbits", 32 ); + trap_Cvar_SetValue( "ui_r_depthbits", 24 ); + trap_Cvar_SetValue( "ui_r_picmip", 0 ); + trap_Cvar_SetValue( "ui_r_mode", 4 ); + trap_Cvar_SetValue( "ui_r_texturebits", 32 ); + trap_Cvar_SetValue( "ui_r_fastSky", 0 ); + trap_Cvar_SetValue( "ui_r_inGameVideo", 1 ); + //trap_Cvar_SetValue( "ui_cg_shadows", 2 );//stencil + trap_Cvar_Set( "ui_r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); + break; + case 1: // normal - trap_Cvar_SetValue( "r_fullScreen", 1 ); - trap_Cvar_SetValue( "r_subdivisions", 12 ); - trap_Cvar_SetValue( "r_vertexlight", 0 ); - trap_Cvar_SetValue( "r_lodbias", 0 ); - trap_Cvar_SetValue( "r_colorbits", 0 ); - trap_Cvar_SetValue( "r_depthbits", 24 ); - trap_Cvar_SetValue( "r_picmip", 1 ); - trap_Cvar_SetValue( "r_mode", 3 ); - trap_Cvar_SetValue( "r_texturebits", 0 ); - trap_Cvar_SetValue( "r_fastSky", 0 ); - trap_Cvar_SetValue( "r_inGameVideo", 1 ); - trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); - trap_Cvar_SetValue( "cg_shadows", 0 ); - break; + trap_Cvar_SetValue( "ui_r_fullScreen", 1 ); + trap_Cvar_SetValue( "ui_r_subdivisions", 4 ); + trap_Cvar_SetValue( "ui_r_lodbias", 0 ); + trap_Cvar_SetValue( "ui_r_colorbits", 0 ); + trap_Cvar_SetValue( "ui_r_depthbits", 24 ); + trap_Cvar_SetValue( "ui_r_picmip", 1 ); + trap_Cvar_SetValue( "ui_r_mode", 3 ); + trap_Cvar_SetValue( "ui_r_texturebits", 0 ); + trap_Cvar_SetValue( "ui_r_fastSky", 0 ); + trap_Cvar_SetValue( "ui_r_inGameVideo", 1 ); + //trap_Cvar_SetValue( "ui_cg_shadows", 2 ); + trap_Cvar_Set( "ui_r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); + break; + case 2: // fast - trap_Cvar_SetValue( "r_fullScreen", 1 ); - trap_Cvar_SetValue( "r_subdivisions", 8 ); - trap_Cvar_SetValue( "r_vertexlight", 0 ); - trap_Cvar_SetValue( "r_lodbias", 1 ); - trap_Cvar_SetValue( "r_colorbits", 0 ); - trap_Cvar_SetValue( "r_depthbits", 0 ); - trap_Cvar_SetValue( "r_picmip", 1 ); - trap_Cvar_SetValue( "r_mode", 3 ); - trap_Cvar_SetValue( "r_texturebits", 0 ); - trap_Cvar_SetValue( "cg_shadows", 0 ); - trap_Cvar_SetValue( "r_fastSky", 1 ); - trap_Cvar_SetValue( "r_inGameVideo", 0 ); - trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" ); - break; + + trap_Cvar_SetValue( "ui_r_fullScreen", 1 ); + trap_Cvar_SetValue( "ui_r_subdivisions", 12 ); + trap_Cvar_SetValue( "ui_r_lodbias", 1 ); + trap_Cvar_SetValue( "ui_r_colorbits", 0 ); + trap_Cvar_SetValue( "ui_r_depthbits", 0 ); + trap_Cvar_SetValue( "ui_r_picmip", 2 ); + trap_Cvar_SetValue( "ui_r_mode", 3 ); + trap_Cvar_SetValue( "ui_r_texturebits", 0 ); + trap_Cvar_SetValue( "ui_r_fastSky", 1 ); + trap_Cvar_SetValue( "ui_r_inGameVideo", 0 ); + //trap_Cvar_SetValue( "ui_cg_shadows", 1 ); + trap_Cvar_Set( "ui_r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" ); + break; + case 3: // fastest - trap_Cvar_SetValue( "r_fullScreen", 1 ); - trap_Cvar_SetValue( "r_subdivisions", 20 ); - trap_Cvar_SetValue( "r_vertexlight", 1 ); - trap_Cvar_SetValue( "r_lodbias", 2 ); - trap_Cvar_SetValue( "r_colorbits", 16 ); - trap_Cvar_SetValue( "r_depthbits", 16 ); - trap_Cvar_SetValue( "r_mode", 3 ); - trap_Cvar_SetValue( "r_picmip", 2 ); - trap_Cvar_SetValue( "r_texturebits", 16 ); - trap_Cvar_SetValue( "cg_shadows", 0 ); - trap_Cvar_SetValue( "r_fastSky", 1 ); - trap_Cvar_SetValue( "r_inGameVideo", 0 ); - trap_Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" ); + + trap_Cvar_SetValue( "ui_r_fullScreen", 1 ); + trap_Cvar_SetValue( "ui_r_subdivisions", 20 ); + trap_Cvar_SetValue( "ui_r_lodbias", 2 ); + trap_Cvar_SetValue( "ui_r_colorbits", 16 ); + trap_Cvar_SetValue( "ui_r_depthbits", 16 ); + trap_Cvar_SetValue( "ui_r_mode", 3 ); + trap_Cvar_SetValue( "ui_r_picmip", 3 ); + trap_Cvar_SetValue( "ui_r_texturebits", 16 ); + trap_Cvar_SetValue( "ui_r_fastSky", 1 ); + trap_Cvar_SetValue( "ui_r_inGameVideo", 0 ); + //trap_Cvar_SetValue( "ui_cg_shadows", 0 ); + trap_Cvar_Set( "ui_r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" ); break; } - } else if (Q_stricmp(name, "ui_mousePitch") == 0) { - if (val == 0) { + } + else if (Q_stricmp(name, "ui_mousePitch") == 0) + { + if (val == 0) + { trap_Cvar_SetValue( "m_pitch", 0.022f ); - } else { + } + else + { trap_Cvar_SetValue( "m_pitch", -0.022f ); } } @@ -3541,6 +3778,140 @@ static void UI_Update(const char *name) { int gUISelectedMap = 0; +/* +=============== +UI_DeferMenuScript + +Return true if the menu script should be deferred for later +=============== +*/ +static qboolean UI_DeferMenuScript ( char **args ) +{ + const char* name; + + // Whats the reason for being deferred? + if (!String_Parse( (char**)args, &name)) + { + return qfalse; + } + + // Handle the custom cases + if ( !Q_stricmp ( name, "VideoSetup" ) ) + { + const char* warningMenuName; + qboolean deferred; + + // No warning menu specified + if ( !String_Parse( (char**)args, &warningMenuName) ) + { + return qfalse; + } + + // Defer if the video options were modified + deferred = trap_Cvar_VariableValue ( "ui_r_modified" ) ? qtrue : qfalse; + + if ( deferred ) + { + // Open the warning menu + Menus_OpenByName(warningMenuName); + } + + return deferred; + } + else if ( !Q_stricmp ( name, "RulesBackout" ) ) + { + qboolean deferred; + + deferred = trap_Cvar_VariableValue ( "ui_rules_backout" ) ? qtrue : qfalse ; + + trap_Cvar_Set ( "ui_rules_backout", "0" ); + + return deferred; + } + + return qfalse; +} + +/* +================= +UI_UpdateVideoSetup + +Copies the temporary user interface version of the video cvars into +their real counterparts. This is to create a interface which allows +you to discard your changes if you did something you didnt want +================= +*/ +void UI_UpdateVideoSetup ( void ) +{ + trap_Cvar_Set ( "r_mode", UI_Cvar_VariableString ( "ui_r_mode" ) ); + trap_Cvar_Set ( "r_fullscreen", UI_Cvar_VariableString ( "ui_r_fullscreen" ) ); + trap_Cvar_Set ( "r_colorbits", UI_Cvar_VariableString ( "ui_r_colorbits" ) ); + trap_Cvar_Set ( "r_lodbias", UI_Cvar_VariableString ( "ui_r_lodbias" ) ); + trap_Cvar_Set ( "r_picmip", UI_Cvar_VariableString ( "ui_r_picmip" ) ); + trap_Cvar_Set ( "r_texturebits", UI_Cvar_VariableString ( "ui_r_texturebits" ) ); + trap_Cvar_Set ( "r_texturemode", UI_Cvar_VariableString ( "ui_r_texturemode" ) ); + trap_Cvar_Set ( "r_detailtextures", UI_Cvar_VariableString ( "ui_r_detailtextures" ) ); + trap_Cvar_Set ( "r_ext_compress_textures", UI_Cvar_VariableString ( "ui_r_ext_compress_textures" ) ); + trap_Cvar_Set ( "r_depthbits", UI_Cvar_VariableString ( "ui_r_depthbits" ) ); + trap_Cvar_Set ( "r_subdivisions", UI_Cvar_VariableString ( "ui_r_subdivisions" ) ); + trap_Cvar_Set ( "r_fastSky", UI_Cvar_VariableString ( "ui_r_fastSky" ) ); + trap_Cvar_Set ( "r_inGameVideo", UI_Cvar_VariableString ( "ui_r_inGameVideo" ) ); + trap_Cvar_Set ( "r_allowExtensions", UI_Cvar_VariableString ( "ui_r_allowExtensions" ) ); + trap_Cvar_Set ( "cg_shadows", UI_Cvar_VariableString ( "ui_cg_shadows" ) ); + trap_Cvar_Set ( "ui_r_modified", "0" ); + + trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart;" ); +} + +/* +================= +UI_GetVideoSetup + +Retrieves the current actual video settings into the temporary user +interface versions of the cvars. +================= +*/ +void UI_GetVideoSetup ( void ) +{ + // Make sure the cvars are registered as read only. + trap_Cvar_Register ( NULL, "ui_r_glCustom", "4", CVAR_ROM|CVAR_INTERNAL|CVAR_ARCHIVE ); + + trap_Cvar_Register ( NULL, "ui_r_mode", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_fullscreen", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_colorbits", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_lodbias", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_picmip", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_texturebits", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_texturemode", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_detailtextures", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_ext_compress_textures","0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_depthbits", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_subdivisions", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_fastSky", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_inGameVideo", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_allowExtensions", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_cg_shadows", "0", CVAR_ROM|CVAR_INTERNAL ); + trap_Cvar_Register ( NULL, "ui_r_modified", "0", CVAR_ROM|CVAR_INTERNAL ); + + // Copy over the real video cvars into their temporary counterparts + trap_Cvar_Set ( "ui_r_mode", UI_Cvar_VariableString ( "r_mode" ) ); + trap_Cvar_Set ( "ui_r_colorbits", UI_Cvar_VariableString ( "r_colorbits" ) ); + trap_Cvar_Set ( "ui_r_fullscreen", UI_Cvar_VariableString ( "r_fullscreen" ) ); + trap_Cvar_Set ( "ui_r_lodbias", UI_Cvar_VariableString ( "r_lodbias" ) ); + trap_Cvar_Set ( "ui_r_picmip", UI_Cvar_VariableString ( "r_picmip" ) ); + trap_Cvar_Set ( "ui_r_texturebits", UI_Cvar_VariableString ( "r_texturebits" ) ); + trap_Cvar_Set ( "ui_r_texturemode", UI_Cvar_VariableString ( "r_texturemode" ) ); + trap_Cvar_Set ( "ui_r_detailtextures", UI_Cvar_VariableString ( "r_detailtextures" ) ); + trap_Cvar_Set ( "ui_r_ext_compress_textures", UI_Cvar_VariableString ( "r_ext_compress_textures" ) ); + trap_Cvar_Set ( "ui_r_depthbits", UI_Cvar_VariableString ( "r_depthbits" ) ); + trap_Cvar_Set ( "ui_r_subdivisions", UI_Cvar_VariableString ( "r_subdivisions" ) ); + trap_Cvar_Set ( "ui_r_fastSky", UI_Cvar_VariableString ( "r_fastSky" ) ); + trap_Cvar_Set ( "ui_r_inGameVideo", UI_Cvar_VariableString ( "r_inGameVideo" ) ); + trap_Cvar_Set ( "ui_r_allowExtensions", UI_Cvar_VariableString ( "r_allowExtensions" ) ); + trap_Cvar_Set ( "ui_cg_shadows", UI_Cvar_VariableString ( "cg_shadows" ) ); + trap_Cvar_Set ( "ui_r_modified", "0" ); +} + static void UI_RunMenuScript(char **args) { const char *name, *name2; @@ -3552,6 +3923,9 @@ static void UI_RunMenuScript(char **args) { int i, added = 0; float skill; + int warmupTime = 0; + int doWarmup = 0; + trap_Cvar_Set("cg_thirdPerson", "0"); trap_Cvar_Set("cg_cameraOrbit", "0"); trap_Cvar_Set("ui_singlePlayerActive", "0"); @@ -3562,6 +3936,28 @@ static void UI_RunMenuScript(char **args) trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName ) ); skill = trap_Cvar_VariableValue( "g_spSkill" ); + //Cap the warmup values in case the user tries a dumb setting. + warmupTime = trap_Cvar_VariableValue( "g_warmup" ); + doWarmup = trap_Cvar_VariableValue( "g_doWarmup" ); + + if (doWarmup && warmupTime < 1) + { + trap_Cvar_Set("g_doWarmup", "0"); + } + if (warmupTime < 5) + { + trap_Cvar_Set("g_warmup", "5"); + } + if (warmupTime > 120) + { + trap_Cvar_Set("g_warmup", "120"); + } + + if (trap_Cvar_VariableValue( "g_gametype" ) == GT_TOURNAMENT) + { //always set fraglimit 1 when starting a duel game + trap_Cvar_Set("fraglimit", "1"); + } + for (i = 0; i < PLAYERS_PER_TEAM; i++) { int bot = trap_Cvar_VariableValue( va("ui_blueteam%i", i+1)); @@ -3618,11 +4014,10 @@ static void UI_RunMenuScript(char **args) UI_GameType_HandleKey(0, 0, K_MOUSE1, qfalse); UI_GameType_HandleKey(0, 0, K_MOUSE2, qfalse); } else if (Q_stricmp(name, "resetDefaults") == 0) { - trap_Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n"); trap_Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n"); - Controls_SetDefaults(); - trap_Cvar_Set("com_introPlayed", "1" ); + trap_Cmd_ExecuteText( EXEC_APPEND, "exec mpdefault.cfg\n"); trap_Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" ); + trap_Cvar_Set("com_introPlayed", "1" ); #ifdef USE_CD_KEY } else if (Q_stricmp(name, "getCDKey") == 0) { char out[17]; @@ -3660,6 +4055,7 @@ static void UI_RunMenuScript(char **args) UI_LoadArenas(); UI_MapCountByGameType(qfalse); Menu_SetFeederSelection(NULL, FEEDER_ALLMAPS, gUISelectedMap, "createserver"); + uiForceRank = trap_Cvar_VariableValue("g_maxForceRank"); } else if (Q_stricmp(name, "saveControls") == 0) { Controls_SetConfig(qtrue); } else if (Q_stricmp(name, "loadControls") == 0) { @@ -3759,12 +4155,24 @@ static void UI_RunMenuScript(char **args) trap_Key_SetCatcher( KEYCATCH_UI ); Menus_CloseAll(); Menus_ActivateByName("setup_menu2"); - } else if (Q_stricmp(name, "Leave") == 0) { + } + else if (Q_stricmp(name, "Leave") == 0) + { trap_Cmd_ExecuteText( EXEC_APPEND, "disconnect\n" ); trap_Key_SetCatcher( KEYCATCH_UI ); Menus_CloseAll(); Menus_ActivateByName("main"); - } else if (Q_stricmp(name, "ServerSort") == 0) { + } + else if (Q_stricmp(name, "getvideosetup") == 0) + { + UI_GetVideoSetup ( ); + } + else if (Q_stricmp(name, "updatevideosetup") == 0) + { + UI_UpdateVideoSetup ( ); + } + else if (Q_stricmp(name, "ServerSort") == 0) + { int sortColumn; if (Int_Parse(args, &sortColumn)) { // if same column we're already sorting on then flip the direction @@ -3789,7 +4197,7 @@ static void UI_RunMenuScript(char **args) } } else if (Q_stricmp(name, "voteKick") == 0) { if (uiInfo.playerIndex >= 0 && uiInfo.playerIndex < uiInfo.playerCount) { - trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote kick %s\n",uiInfo.playerNames[uiInfo.playerIndex]) ); + trap_Cmd_ExecuteText( EXEC_APPEND, va("callvote kick \"%s\"\n",uiInfo.playerNames[uiInfo.playerIndex]) ); } } else if (Q_stricmp(name, "voteGame") == 0) { if (ui_netGameType.integer >= 0 && ui_netGameType.integer < uiInfo.numGameTypes) { @@ -3797,7 +4205,7 @@ static void UI_RunMenuScript(char **args) } } else if (Q_stricmp(name, "voteLeader") == 0) { if (uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount) { - trap_Cmd_ExecuteText( EXEC_APPEND, va("callteamvote leader %s\n",uiInfo.teamNames[uiInfo.teamIndex]) ); + trap_Cmd_ExecuteText( EXEC_APPEND, va("callteamvote leader \"%s\"\n",uiInfo.teamNames[uiInfo.teamIndex]) ); } } else if (Q_stricmp(name, "addBot") == 0) { if (trap_Cvar_VariableValue("g_gametype") >= GT_TEAM) { @@ -3859,7 +4267,8 @@ static void UI_RunMenuScript(char **args) } else if (Q_stricmp(name, "createFavorite") == 0) { - if (ui_netSource.integer == AS_FAVORITES) + // if (ui_netSource.integer == AS_FAVORITES) + //rww - don't know why this check was here.. why would you want to only add new favorites when the filter was favorites? { char name[MAX_NAME_LENGTH]; char addr[MAX_NAME_LENGTH]; @@ -3944,14 +4353,26 @@ static void UI_RunMenuScript(char **args) trap_Cvar_Set( "cl_paused", "0" ); Menus_CloseAll(); } - } else if (Q_stricmp(name, "setForce") == 0) { - UI_UpdateClientForcePowers(); - } else if (Q_stricmp(name, "saveTemplate") == 0) { + } + else if (Q_stricmp(name, "setForce") == 0) + { + const char *teamArg; + + if (String_Parse(args, &teamArg)) + { + UI_UpdateClientForcePowers(teamArg); + } + else + { + UI_UpdateClientForcePowers(NULL); + } + } + else if (Q_stricmp(name, "saveTemplate") == 0) { UI_SaveForceTemplate(); } else if (Q_stricmp(name, "refreshForce") == 0) { UI_UpdateForcePowers(); } else if (Q_stricmp(name, "glCustom") == 0) { - trap_Cvar_Set("ui_glCustom", "4"); + trap_Cvar_Set("ui_r_glCustom", "4"); } else if (Q_stricmp(name, "forcePowersDisable") == 0) { @@ -3967,11 +4388,9 @@ static void UI_RunMenuScript(char **args) forcePowerDisable |= (1<= 0 && index < uiInfo.forceConfigCount) { - return uiInfo.forceConfigNames[index]; + if (index == 0) + { //always show "custom" + return uiInfo.forceConfigNames[index]; + } + else + { + if (uiForceSide == FORCE_LIGHTSIDE) + { + index += uiInfo.forceConfigLightIndexBegin; + if (index < 0) + { + return NULL; + } + if (index >= uiInfo.forceConfigCount) + { + return NULL; + } + return uiInfo.forceConfigNames[index]; + } + else if (uiForceSide == FORCE_DARKSIDE) + { + index += uiInfo.forceConfigDarkIndexBegin; + if (index < 0) + { + return NULL; + } + if (index > uiInfo.forceConfigLightIndexBegin) + { //dark gets read in before light + return NULL; + } + if (index >= uiInfo.forceConfigCount) + { + return NULL; + } + return uiInfo.forceConfigNames[index]; + } + else + { + return NULL; + } + } } } else if (feederID == FEEDER_MAPS || feederID == FEEDER_ALLMAPS) { int actual; @@ -4993,9 +5473,69 @@ static qhandle_t UI_FeederItemImage(float feederID, int index) { int actual; UI_SelectedTeamHead(index, &actual); index = actual; + if (index >= 0 && index < uiInfo.q3HeadCount) - { - return uiInfo.q3HeadIcons[index]; + { //we want it to load them as it draws them, like the TA feeder + //return uiInfo.q3HeadIcons[index]; + int selModel = trap_Cvar_VariableValue("ui_selectedModelIndex"); + + if (selModel != -1) + { + if (uiInfo.q3SelectedHead != selModel) + { + uiInfo.q3SelectedHead = selModel; + //UI_FeederSelection(FEEDER_Q3HEADS, uiInfo.q3SelectedHead); + Menu_SetFeederSelection(NULL, FEEDER_Q3HEADS, selModel, NULL); + } + } + + if (!uiInfo.q3HeadIcons[index]) + { //this isn't the best way of doing this I guess, but I didn't want a whole seperate string array + //for storing shader names. I can't just replace q3HeadNames with the shader name, because we + //print what's in q3HeadNames and the icon name would look funny. + char iconNameFromSkinName[256]; + int i = 0; + int skinPlace; + + i = strlen(uiInfo.q3HeadNames[index]); + + while (uiInfo.q3HeadNames[index][i] != '/') + { + i--; + } + + i++; + skinPlace = i; //remember that this is where the skin name begins + + //now, build a full path out of what's in q3HeadNames, into iconNameFromSkinName + Com_sprintf(iconNameFromSkinName, sizeof(iconNameFromSkinName), "models/players/%s", uiInfo.q3HeadNames[index]); + + i = strlen(iconNameFromSkinName); + + while (iconNameFromSkinName[i] != '/') + { + i--; + } + + i++; + iconNameFromSkinName[i] = 0; //terminate, and append.. + Q_strcat(iconNameFromSkinName, 256, "icon_"); + + //and now, for the final step, append the skin name from q3HeadNames onto the end of iconNameFromSkinName + i = strlen(iconNameFromSkinName); + + while (uiInfo.q3HeadNames[index][skinPlace]) + { + iconNameFromSkinName[i] = uiInfo.q3HeadNames[index][skinPlace]; + i++; + skinPlace++; + } + iconNameFromSkinName[i] = 0; + + //and now we are ready to register (thankfully this will only happen once) + uiInfo.q3HeadIcons[index] = trap_R_RegisterShaderNoMip(iconNameFromSkinName); + } + return uiInfo.q3HeadIcons[index]; } } else if (feederID == FEEDER_ALLMAPS || feederID == FEEDER_MAPS) @@ -5013,7 +5553,7 @@ static qhandle_t UI_FeederItemImage(float feederID, int index) { return 0; } -static void UI_FeederSelection(float feederID, int index) { +qboolean UI_FeederSelection(float feederID, int index) { static char info[MAX_STRING_CHARS]; if (feederID == FEEDER_HEADS) { @@ -5023,7 +5563,7 @@ static void UI_FeederSelection(float feederID, int index) { if (index >= 0 && index < uiInfo.characterCount) { trap_Cvar_Set( "team_model", va("%s", uiInfo.characterList[index].base)); - trap_Cvar_Set( "team_headmodel", va("*%s", uiInfo.characterList[index].name)); + //trap_Cvar_Set( "team_headmodel", va("*%s", uiInfo.characterList[index].name)); updateModel = qtrue; } } @@ -5031,21 +5571,42 @@ static void UI_FeederSelection(float feederID, int index) { { int actual; UI_SelectedTeamHead(index, &actual); + uiInfo.q3SelectedHead = index; + trap_Cvar_Set("ui_selectedModelIndex", va("%i", index)); index = actual; if (index >= 0 && index < uiInfo.q3HeadCount) { trap_Cvar_Set( "model", uiInfo.q3HeadNames[index]); - trap_Cvar_Set( "headmodel", uiInfo.q3HeadNames[index]); + //trap_Cvar_Set( "headmodel", uiInfo.q3HeadNames[index]); //Update team_model for now here also, because we're using a different team skin system trap_Cvar_Set( "team_model", uiInfo.q3HeadNames[index]); - trap_Cvar_Set( "team_headmodel", uiInfo.q3HeadNames[index]); + //trap_Cvar_Set( "team_headmodel", uiInfo.q3HeadNames[index]); updateModel = qtrue; } } else if (feederID == FEEDER_FORCECFG) { + int newindex = index; + + if (uiForceSide == FORCE_LIGHTSIDE) + { + newindex += uiInfo.forceConfigLightIndexBegin; + if (newindex >= uiInfo.forceConfigCount) + { + return qfalse; + } + } + else + { //else dark + newindex += uiInfo.forceConfigDarkIndexBegin; + if (newindex >= uiInfo.forceConfigCount || newindex > uiInfo.forceConfigLightIndexBegin) + { //dark gets read in before light + return qfalse; + } + } + if (index >= 0 && index < uiInfo.forceConfigCount) { UI_ForceConfigHandle(uiInfo.forceConfigSelected, index); @@ -5079,8 +5640,8 @@ static void UI_FeederSelection(float feederID, int index) { trap_Cvar_Set("ui_currentMap", va("%d", actual)); uiInfo.mapList[ui_currentMap.integer].cinematic = trap_CIN_PlayCinematic(va("%s.roq", uiInfo.mapList[ui_currentMap.integer].mapLoadName), 0, 0, 0, 0, (CIN_loop | CIN_silent) ); UI_LoadBestScores(uiInfo.mapList[ui_currentMap.integer].mapLoadName, uiInfo.gameTypes[ui_gameType.integer].gtEnum); - trap_Cvar_Set("ui_opponentModel", uiInfo.mapList[ui_currentMap.integer].opponentName); - updateOpponentModel = qtrue; + //trap_Cvar_Set("ui_opponentModel", uiInfo.mapList[ui_currentMap.integer].opponentName); + //updateOpponentModel = qtrue; } else { ui_currentNetMap.integer = actual; trap_Cvar_Set("ui_currentNetMap", va("%d", actual)); @@ -5126,216 +5687,8 @@ static void UI_FeederSelection(float feederID, int index) { } else if (feederID == FEEDER_DEMOS) { uiInfo.demoIndex = index; } -} - -static qboolean Team_Parse(char **p) { - char *token; - const char *tempStr; - int i; - - token = COM_ParseExt((const char **)p, qtrue); - - if (token[0] != '{') { - return qfalse; - } - - while ( 1 ) { - - token = COM_ParseExt((const char **)p, qtrue); - - if (Q_stricmp(token, "}") == 0) { - return qtrue; - } - - if ( !token || token[0] == 0 ) { - return qfalse; - } - - if (token[0] == '{') { - // seven tokens per line, team name and icon, and 5 team member names - if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamName) || !String_Parse(p, &tempStr)) { - return qfalse; - } - - - uiInfo.teamList[uiInfo.teamCount].imageName = tempStr; - uiInfo.teamList[uiInfo.teamCount].teamIcon = trap_R_RegisterShaderNoMip(uiInfo.teamList[uiInfo.teamCount].imageName); - uiInfo.teamList[uiInfo.teamCount].teamIcon_Metal = trap_R_RegisterShaderNoMip(va("%s_metal",uiInfo.teamList[uiInfo.teamCount].imageName)); - uiInfo.teamList[uiInfo.teamCount].teamIcon_Name = trap_R_RegisterShaderNoMip(va("%s_name", uiInfo.teamList[uiInfo.teamCount].imageName)); - - uiInfo.teamList[uiInfo.teamCount].cinematic = -1; - - for (i = 0; i < TEAM_MEMBERS; i++) { - uiInfo.teamList[uiInfo.teamCount].teamMembers[i] = NULL; - if (!String_Parse(p, &uiInfo.teamList[uiInfo.teamCount].teamMembers[i])) { - return qfalse; - } - } - - Com_Printf("Loaded team %s with team icon %s.\n", uiInfo.teamList[uiInfo.teamCount].teamName, tempStr); - if (uiInfo.teamCount < MAX_TEAMS) { - uiInfo.teamCount++; - } else { - Com_Printf("Too many teams, last team replaced!\n"); - } - token = COM_ParseExt((const char **)p, qtrue); - if (token[0] != '}') { - return qfalse; - } - } - } - - return qfalse; -} - -static qboolean Character_Parse(char **p) { - char *token; - const char *tempStr; - - token = COM_ParseExt((const char **)p, qtrue); - - if (token[0] != '{') { - return qfalse; - } - - - while ( 1 ) { - token = COM_ParseExt((const char **)p, qtrue); - - if (Q_stricmp(token, "}") == 0) { - return qtrue; - } - - if ( !token || token[0] == 0 ) { - return qfalse; - } - - if (token[0] == '{') { - // two tokens per line, character name and sex - if (!String_Parse(p, &uiInfo.characterList[uiInfo.characterCount].name) || !String_Parse(p, &tempStr)) { - return qfalse; - } - - uiInfo.characterList[uiInfo.characterCount].headImage = -1; - uiInfo.characterList[uiInfo.characterCount].imageName = String_Alloc(va("models/players/heads/%s/icon_default.tga", uiInfo.characterList[uiInfo.characterCount].name)); - - if (tempStr && (!Q_stricmp(tempStr, "female"))) { - uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("Jan")); - } else if (tempStr && (!Q_stricmp(tempStr, "male"))) { - uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("Kyle")); - } else { - uiInfo.characterList[uiInfo.characterCount].base = String_Alloc(va("%s",tempStr)); - } - - Com_Printf("Loaded %s character %s.\n", uiInfo.characterList[uiInfo.characterCount].base, uiInfo.characterList[uiInfo.characterCount].name); - if (uiInfo.characterCount < MAX_HEADS) { - uiInfo.characterCount++; - } else { - Com_Printf("Too many characters, last character replaced!\n"); - } - - token = COM_ParseExt((const char **)p, qtrue); - if (token[0] != '}') { - return qfalse; - } - } - } - - return qfalse; -} - - -static qboolean Alias_Parse(char **p) { - char *token; - - token = COM_ParseExt((const char **)p, qtrue); - - if (token[0] != '{') { - return qfalse; - } - - while ( 1 ) { - token = COM_ParseExt((const char **)p, qtrue); - - if (Q_stricmp(token, "}") == 0) { - return qtrue; - } - - if ( !token || token[0] == 0 ) { - return qfalse; - } - - if (token[0] == '{') { - // three tokens per line, character name, bot alias, and preferred action a - all purpose, d - defense, o - offense - if (!String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].name) || !String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].ai) || !String_Parse(p, &uiInfo.aliasList[uiInfo.aliasCount].action)) { - return qfalse; - } - - Com_Printf("Loaded character alias %s using character ai %s.\n", uiInfo.aliasList[uiInfo.aliasCount].name, uiInfo.aliasList[uiInfo.aliasCount].ai); - if (uiInfo.aliasCount < MAX_ALIASES) { - uiInfo.aliasCount++; - } else { - Com_Printf("Too many aliases, last alias replaced!\n"); - } - - token = COM_ParseExt((const char **)p, qtrue); - if (token[0] != '}') { - return qfalse; - } - } - } - - return qfalse; -} - - - -// mode -// 0 - high level parsing -// 1 - team parsing -// 2 - character parsing -static void UI_ParseTeamInfo(const char *teamFile) { - char *token; - char *p; - char *buff = NULL; - //static int mode = 0; TTimo: unused - - buff = GetMenuBuffer(teamFile); - if (!buff) { - return; - } - - p = buff; - - while ( 1 ) { - token = COM_ParseExt( (const char **)(&p), qtrue ); - if( !token || token[0] == 0 || token[0] == '}') { - break; - } - - if ( Q_stricmp( token, "}" ) == 0 ) { - break; - } - - if (Q_stricmp(token, "teams") == 0) { - - if (Team_Parse(&p)) { - continue; - } else { - break; - } - } - - if (Q_stricmp(token, "characters") == 0) { - Character_Parse(&p); - } - - if (Q_stricmp(token, "aliases") == 0) { - Alias_Parse(&p); - } - - } + return qtrue; } @@ -5573,21 +5926,32 @@ UI_LoadForceConfig_List ================= Looks in the directory for force config files (.fcf) and loads the name in */ -static void UI_LoadForceConfig_List( void ) +void UI_LoadForceConfig_List( void ) { - int numfiles = 0; - char filelist[2048]; - char configname[128]; - char *fileptr = NULL; - int j = 0; - int filelen = 0; + int numfiles = 0; + char filelist[2048]; + char configname[128]; + char *fileptr = NULL; + int j = 0; + int filelen = 0; + qboolean lightSearch = qfalse; uiInfo.forceConfigCount = 0; Com_sprintf( uiInfo.forceConfigNames[uiInfo.forceConfigCount], sizeof(uiInfo.forceConfigNames[uiInfo.forceConfigCount]), "Custom"); uiInfo.forceConfigCount++; //Always reserve index 0 as the "custom" config - numfiles = trap_FS_GetFileList("forcecfg", "fcf", filelist, 2048 ); +nextSearch: + if (lightSearch) + { //search light side folder + numfiles = trap_FS_GetFileList("forcecfg/light", "fcf", filelist, 2048 ); + uiInfo.forceConfigLightIndexBegin = uiInfo.forceConfigCount-1; + } + else + { //search dark side folder + numfiles = trap_FS_GetFileList("forcecfg/dark", "fcf", filelist, 2048 ); + uiInfo.forceConfigDarkIndexBegin = uiInfo.forceConfigCount-1; + } fileptr = filelist; @@ -5596,9 +5960,24 @@ static void UI_LoadForceConfig_List( void ) filelen = strlen(fileptr); COM_StripExtension(fileptr, configname); + if (lightSearch) + { + uiInfo.forceConfigSide[uiInfo.forceConfigCount] = qtrue; //light side config + } + else + { + uiInfo.forceConfigSide[uiInfo.forceConfigCount] = qfalse; //dark side config + } + Com_sprintf( uiInfo.forceConfigNames[uiInfo.forceConfigCount], sizeof(uiInfo.forceConfigNames[uiInfo.forceConfigCount]), configname); uiInfo.forceConfigCount++; } + + if (!lightSearch) + { + lightSearch = qtrue; + goto nextSearch; + } } @@ -5701,7 +6080,8 @@ static void UI_BuildQ3Model_List( void ) } Com_sprintf( uiInfo.q3HeadNames[uiInfo.q3HeadCount], sizeof(uiInfo.q3HeadNames[uiInfo.q3HeadCount]), va("%s%s", dirptr, skinname)); - uiInfo.q3HeadIcons[uiInfo.q3HeadCount++] = trap_R_RegisterShaderNoMip(fpath); + uiInfo.q3HeadIcons[uiInfo.q3HeadCount++] = 0;//trap_R_RegisterShaderNoMip(fpath); + //rww - we are now registering them as they are drawn like the TA feeder, so as to decrease UI load time. } if (uiInfo.q3HeadCount >= MAX_PLAYERMODELS) @@ -5721,10 +6101,11 @@ UI_Init ================= */ void _UI_Init( qboolean inGameLoad ) { + int i; const char *menuSet; int start; - //uiInfo.inGameLoad = inGameLoad; + uiInfo.inGameLoad = inGameLoad; UI_UpdateForcePowers(); @@ -5775,6 +6156,7 @@ void _UI_Init( qboolean inGameLoad ) { uiInfo.uiDC.getValue = &UI_GetValue; uiInfo.uiDC.ownerDrawVisible = &UI_OwnerDrawVisible; uiInfo.uiDC.runScript = &UI_RunMenuScript; + uiInfo.uiDC.deferScript = &UI_DeferMenuScript; uiInfo.uiDC.getTeamColor = &UI_GetTeamColor; uiInfo.uiDC.setCVar = trap_Cvar_Set; uiInfo.uiDC.getCVarString = trap_Cvar_VariableStringBuffer; @@ -5804,6 +6186,13 @@ void _UI_Init( qboolean inGameLoad ) { uiInfo.uiDC.drawCinematic = &UI_DrawCinematic; uiInfo.uiDC.runCinematicFrame = &UI_RunCinematicFrame; + for (i=0; i<10; i++) + { + if (!trap_SP_Register(va("menus%d",i))) //, /*SP_REGISTER_REQUIRED|*/SP_REGISTER_MENU)) + break; + } + + Init_Display(&uiInfo.uiDC); String_Init(); @@ -5829,7 +6218,7 @@ void _UI_Init( qboolean inGameLoad ) { #endif - menuSet = UI_Cvar_VariableString("ui_menuFiles"); + menuSet = UI_Cvar_VariableString("ui_menuFilesMP"); if (menuSet == NULL || menuSet[0] == '\0') { menuSet = "ui/jk2mpmenus.txt"; } @@ -5868,12 +6257,6 @@ void _UI_Init( qboolean inGameLoad ) { uiInfo.serverStatus.currentServerCinematic = -1; uiInfo.previewMovie = -1; - if (trap_Cvar_VariableValue("ui_TeamArenaFirstRun") == 0) { - trap_Cvar_Set("s_volume", "0.8"); - trap_Cvar_Set("s_musicvolume", "0.5"); - trap_Cvar_Set("ui_TeamArenaFirstRun", "1"); - } - trap_Cvar_Register(NULL, "debug_protocol", "", 0 ); trap_Cvar_Set("ui_actualNetGameType", va("%d", ui_netGameType.integer)); @@ -5936,7 +6319,7 @@ void _UI_MouseEvent( int dx, int dy ) } void UI_LoadNonIngame() { - const char *menuSet = UI_Cvar_VariableString("ui_menuFiles"); + const char *menuSet = UI_Cvar_VariableString("ui_menuFilesMP"); if (menuSet == NULL || menuSet[0] == '\0') { menuSet = "ui/jk2mpmenus.txt"; } @@ -5970,7 +6353,7 @@ void _UI_SetActiveMenu( uiMenuCommand_t menu ) { //trap_S_StartBackgroundTrack("sound/misc/menu_background.wav", NULL); if (uiInfo.inGameLoad) { - UI_LoadNonIngame(); +// UI_LoadNonIngame(); } Menus_CloseAll(); @@ -6011,7 +6394,7 @@ void _UI_SetActiveMenu( uiMenuCommand_t menu ) { //trap_Cvar_Set( "sv_killserver", "1" ); trap_Key_SetCatcher( KEYCATCH_UI ); if (uiInfo.inGameLoad) { - UI_LoadNonIngame(); +// UI_LoadNonIngame(); } Menus_CloseAll(); Menus_ActivateByName("endofgame"); @@ -6075,11 +6458,11 @@ static void UI_PrintTime ( char *buf, int bufsize, int time ) { time /= 1000; // change to seconds if (time > 3600) { // in the hours range - Com_sprintf( buf, bufsize, "%d hr %d min", time / 3600, (time % 3600) / 60 ); + Com_sprintf( buf, bufsize, "%d hr %2d min", time / 3600, (time % 3600) / 60 ); } else if (time > 60) { // mins - Com_sprintf( buf, bufsize, "%d min %d sec", time / 60, time % 60 ); + Com_sprintf( buf, bufsize, "%2d min %2d sec", time / 60, time % 60 ); } else { // secs - Com_sprintf( buf, bufsize, "%d sec", time ); + Com_sprintf( buf, bufsize, "%2d sec", time ); } } @@ -6090,16 +6473,36 @@ void Text_PaintCenter(float x, float y, float scale, vec4_t color, const char *t static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, float yStart, float scale, int iMenuFont) { - static char dlText[] = "Downloading:"; - static char etaText[] = "Estimated time left:"; - static char xferText[] = "Transfer rate:"; - + char sDownLoading[256]; + char sEstimatedTimeLeft[256]; + char sTransferRate[256]; + char sOf[20]; + char sCopied[256]; + char sSec[20]; + // int downloadSize, downloadCount, downloadTime; char dlSizeBuf[64], totalSizeBuf[64], xferRateBuf[64], dlTimeBuf[64]; int xferRate; int leftWidth; const char *s; + vec4_t colorLtGreyAlpha = {0, 0, 0, .5}; + + UI_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, colorLtGreyAlpha ); + + s = GetCRDelineatedString("MENUS3","DOWNLOAD_STUFF", 0); // "Downloading:" + strcpy(sDownLoading,s?s:""); + s = GetCRDelineatedString("MENUS3","DOWNLOAD_STUFF", 1); // "Estimated time left:" + strcpy(sEstimatedTimeLeft,s?s:""); + s = GetCRDelineatedString("MENUS3","DOWNLOAD_STUFF", 2); // "Transfer rate:" + strcpy(sTransferRate,s?s:""); + s = GetCRDelineatedString("MENUS3","DOWNLOAD_STUFF", 3); // "of" + strcpy(sOf,s?s:""); + s = GetCRDelineatedString("MENUS3","DOWNLOAD_STUFF", 4); // "copied" + strcpy(sCopied,s?s:""); + s = GetCRDelineatedString("MENUS3","DOWNLOAD_STUFF", 5); // "sec." + strcpy(sSec,s?s:""); + downloadSize = trap_Cvar_VariableValue( "cl_downloadSize" ); downloadCount = trap_Cvar_VariableValue( "cl_downloadCount" ); downloadTime = trap_Cvar_VariableValue( "cl_downloadTime" ); @@ -6107,9 +6510,10 @@ static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, leftWidth = 320; UI_SetColor(colorWhite); - Text_PaintCenter(centerPoint, yStart + 112, scale, colorWhite, dlText, 0, iMenuFont); - Text_PaintCenter(centerPoint, yStart + 192, scale, colorWhite, etaText, 0, iMenuFont); - Text_PaintCenter(centerPoint, yStart + 248, scale, colorWhite, xferText, 0, iMenuFont); + + Text_PaintCenter(centerPoint, yStart + 112, scale, colorWhite, sDownLoading, 0, iMenuFont); + Text_PaintCenter(centerPoint, yStart + 192, scale, colorWhite, sEstimatedTimeLeft, 0, iMenuFont); + Text_PaintCenter(centerPoint, yStart + 248, scale, colorWhite, sTransferRate, 0, iMenuFont); if (downloadSize > 0) { s = va( "%s (%d%%)", downloadName, downloadCount * 100 / downloadSize ); @@ -6124,7 +6528,7 @@ static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, if (downloadCount < 4096 || !downloadTime) { Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0, iMenuFont); - Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0, iMenuFont); + Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s %s %s %s)", dlSizeBuf, sOf, totalSizeBuf, sCopied), 0, iMenuFont); } else { if ((uiInfo.uiDC.realTime - downloadTime) / 1000) { xferRate = downloadCount / ((uiInfo.uiDC.realTime - downloadTime) / 1000); @@ -6142,18 +6546,18 @@ static void UI_DisplayDownloadInfo( const char *downloadName, float centerPoint, (n - (((downloadCount/1024) * n) / (downloadSize/1024))) * 1000); Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, dlTimeBuf, 0, iMenuFont); - Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0, iMenuFont); + Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s %s %s %s)", dlSizeBuf, sOf, totalSizeBuf, sCopied), 0, iMenuFont); } else { Text_PaintCenter(leftWidth, yStart+216, scale, colorWhite, "estimating", 0, iMenuFont); if (downloadSize) { - Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s of %s copied)", dlSizeBuf, totalSizeBuf), 0, iMenuFont); + Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s %s %s %s)", dlSizeBuf, sOf, totalSizeBuf, sCopied), 0, iMenuFont); } else { - Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s copied)", dlSizeBuf), 0, iMenuFont); + Text_PaintCenter(leftWidth, yStart+160, scale, colorWhite, va("(%s %s)", dlSizeBuf, sCopied), 0, iMenuFont); } } if (xferRate) { - Text_PaintCenter(leftWidth, yStart+272, scale, colorWhite, va("%s/Sec", xferRateBuf), 0, iMenuFont); + Text_PaintCenter(leftWidth, yStart+272, scale, colorWhite, va("%s/%s", xferRateBuf,sSec), 0, iMenuFont); } } } @@ -6167,12 +6571,14 @@ to prevent it from blinking away too rapidly on local or lan games. ======================== */ void UI_DrawConnectScreen( qboolean overlay ) { - char *s; + const char *s; uiClientState_t cstate; char info[MAX_INFO_VALUE]; char text[256]; float centerPoint, yStart, scale; - + + char sStripEdTemp[256]; + menuDef_t *menu = Menus_FindByName("Connect"); @@ -6194,15 +6600,19 @@ void UI_DrawConnectScreen( qboolean overlay ) { // see what information we should display trap_GetClientState( &cstate ); + info[0] = '\0'; if( trap_GetConfigString( CS_SERVERINFO, info, sizeof(info) ) ) { - Text_PaintCenter(centerPoint, yStart, scale, colorWhite, va( "Loading %s", Info_ValueForKey( info, "mapname" )), 0, FONT_MEDIUM); + trap_SP_GetStringTextString("MENUS3_LOADING_MAPNAME", sStripEdTemp, sizeof(sStripEdTemp)); + Text_PaintCenter(centerPoint, yStart, scale, colorWhite, va( /*"Loading %s"*/sStripEdTemp, Info_ValueForKey( info, "mapname" )), 0, FONT_MEDIUM); } if (!Q_stricmp(cstate.servername,"localhost")) { - Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite, va("Starting up..."), ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM); + trap_SP_GetStringTextString("MENUS3_STARTING_UP", sStripEdTemp, sizeof(sStripEdTemp)); + Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite, sStripEdTemp, ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM); } else { - strcpy(text, va("Connecting to %s", cstate.servername)); + trap_SP_GetStringTextString("MENUS3_CONNECTING_TO", sStripEdTemp, sizeof(sStripEdTemp)); + strcpy(text, va(/*"Connecting to %s"*/sStripEdTemp, cstate.servername)); Text_PaintCenter(centerPoint, yStart + 48, scale, colorWhite,text , ITEM_TEXTSTYLE_SHADOWEDMORE, FONT_MEDIUM); } @@ -6222,10 +6632,16 @@ void UI_DrawConnectScreen( qboolean overlay ) { switch ( cstate.connState ) { case CA_CONNECTING: - s = va("Awaiting connection...%i", cstate.connectPacketCount); + { + trap_SP_GetStringTextString("MENUS3_AWAITING_CONNECTION", sStripEdTemp, sizeof(sStripEdTemp)); + s = va(/*"Awaiting connection...%i"*/sStripEdTemp, cstate.connectPacketCount); + } break; case CA_CHALLENGING: - s = va("Awaiting challenge...%i", cstate.connectPacketCount); + { + trap_SP_GetStringTextString("MENUS3_AWAITING_CHALLENGE", sStripEdTemp, sizeof(sStripEdTemp)); + s = va(/*"Awaiting challenge...%i"*/sStripEdTemp, cstate.connectPacketCount); + } break; case CA_CONNECTED: { char downloadName[MAX_INFO_VALUE]; @@ -6236,7 +6652,8 @@ void UI_DrawConnectScreen( qboolean overlay ) { return; } } - s = "Awaiting gamestate..."; + trap_SP_GetStringTextString("MENUS3_AWAITING_GAMESTATE", sStripEdTemp, sizeof(sStripEdTemp)); + s = /*"Awaiting gamestate..."*/sStripEdTemp; break; case CA_LOADING: return; @@ -6246,7 +6663,6 @@ void UI_DrawConnectScreen( qboolean overlay ) { return; } - if (Q_stricmp(cstate.servername,"localhost")) { Text_PaintCenter(centerPoint, yStart + 80, scale, colorWhite, s, 0, FONT_MEDIUM); } @@ -6274,6 +6690,8 @@ vmCvar_t ui_ffa_timelimit; vmCvar_t ui_tourney_fraglimit; vmCvar_t ui_tourney_timelimit; +vmCvar_t ui_selectedModelIndex; + vmCvar_t ui_team_fraglimit; vmCvar_t ui_team_timelimit; vmCvar_t ui_team_friendly; @@ -6401,6 +6819,8 @@ static cvarTable_t cvarTable[] = { { &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE }, { &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE }, + { &ui_selectedModelIndex, "ui_selectedModelIndex", "16", CVAR_ARCHIVE }, + { &ui_team_fraglimit, "ui_team_fraglimit", "0", CVAR_ARCHIVE }, { &ui_team_timelimit, "ui_team_timelimit", "20", CVAR_ARCHIVE }, { &ui_team_friendly, "ui_team_friendly", "1", CVAR_ARCHIVE }, @@ -6449,15 +6869,15 @@ static cvarTable_t cvarTable[] = { { &ui_server15, "server15", "", CVAR_ARCHIVE }, { &ui_server16, "server16", "", CVAR_ARCHIVE }, { &ui_cdkeychecked, "ui_cdkeychecked", "0", CVAR_ROM }, - { &ui_new, "ui_new", "0", CVAR_TEMP }, { &ui_debug, "ui_debug", "0", CVAR_TEMP }, { &ui_initialized, "ui_initialized", "0", CVAR_TEMP }, - { &ui_teamName, "ui_teamName", "Pagans", CVAR_ARCHIVE }, - { &ui_opponentName, "ui_opponentName", "Stroggs", CVAR_ARCHIVE }, + { &ui_teamName, "ui_teamName", "Empire", CVAR_ARCHIVE }, + { &ui_opponentName, "ui_opponentName", "Rebellion", CVAR_ARCHIVE }, { &ui_rankChange, "ui_rankChange", "0", CVAR_ARCHIVE }, { &ui_freeSaber, "ui_freeSaber", "0", CVAR_ARCHIVE }, - { &ui_redteam, "ui_redteam", "Pagans", CVAR_ARCHIVE }, - { &ui_blueteam, "ui_blueteam", "Stroggs", CVAR_ARCHIVE }, + { &ui_forcePowerDisable, "ui_forcePowerDisable", "0", CVAR_ARCHIVE }, + { &ui_redteam, "ui_redteam", "Empire", CVAR_ARCHIVE }, + { &ui_blueteam, "ui_blueteam", "Rebellion", CVAR_ARCHIVE }, { &ui_dedicated, "ui_dedicated", "0", CVAR_ARCHIVE }, { &ui_gameType, "ui_gametype", "0", CVAR_ARCHIVE }, { &ui_joinGameType, "ui_joinGametype", "0", CVAR_ARCHIVE }, @@ -6479,8 +6899,8 @@ static cvarTable_t cvarTable[] = { { &ui_blueteam6, "ui_blueteam6", "1", CVAR_ARCHIVE }, { &ui_blueteam7, "ui_blueteam7", "1", CVAR_ARCHIVE }, { &ui_blueteam8, "ui_blueteam8", "1", CVAR_ARCHIVE }, - { &ui_netSource, "ui_netSource", "1", CVAR_ARCHIVE }, - { &ui_menuFiles, "ui_menuFiles", "ui/jk2mpmenus.txt", CVAR_ARCHIVE }, + { &ui_netSource, "ui_netSource", "0", CVAR_ARCHIVE }, + { &ui_menuFiles, "ui_menuFilesMP", "ui/jk2mpmenus.txt", CVAR_ARCHIVE }, { &ui_currentTier, "ui_currentTier", "0", CVAR_ARCHIVE }, { &ui_currentMap, "ui_currentMap", "0", CVAR_ARCHIVE }, { &ui_currentNetMap, "ui_currentNetMap", "0", CVAR_ARCHIVE }, @@ -6515,12 +6935,11 @@ static cvarTable_t cvarTable[] = { { &ui_findPlayer, "ui_findPlayer", "Kyle", CVAR_ARCHIVE}, { &ui_Q3Model, "ui_q3model", "0", CVAR_ARCHIVE}, { &ui_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE}, - { &ui_teamArenaFirstRun, "ui_teamArenaFirstRun", "0", CVAR_ARCHIVE}, { &ui_realWarmUp, "g_warmup", "20", CVAR_ARCHIVE}, { &ui_realCaptureLimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_NORESTART}, { &ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE}, { &s_language, "s_language", "english", CVAR_ARCHIVE | CVAR_NORESTART}, - { &k_language, "k_language", "", CVAR_ARCHIVE | CVAR_NORESTART}, // any default ("" or "american") is fine, only foreign strings ("deutsch" etc) make a different keyboard table get looked at + { &k_language, "k_language", "english", CVAR_ARCHIVE | CVAR_NORESTART}, // any default ("" or "american") is fine, only foreign strings ("deutsch" etc) make a different keyboard table get looked at }; // bk001129 - made static to avoid aliasing @@ -6638,7 +7057,7 @@ static void UI_StartServerRefresh(qboolean full) qtime_t q; trap_RealTime(&q); - trap_Cvar_Set( va("ui_lastServerRefresh_%i", ui_netSource.integer), va("%s-%i, %i at %i:%i", MonthAbbrev[q.tm_mon],q.tm_mday, 1900+q.tm_year,q.tm_hour,q.tm_min)); + trap_Cvar_Set( va("ui_lastServerRefresh_%i", ui_netSource.integer), va("%s-%i, %i @ %i:%2i", GetMonthAbbrevString(q.tm_mon),q.tm_mday, 1900+q.tm_year,q.tm_hour,q.tm_min)); if (!full) { UI_UpdatePendingPings(); diff --git a/CODE-mp/ui/ui_players.c b/CODE-mp/ui/ui_players.c deleted file mode 100644 index 5111460..0000000 --- a/CODE-mp/ui/ui_players.c +++ /dev/null @@ -1,1338 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// ui_players.c - -#include "ui_local.h" - - -#define UI_TIMER_GESTURE 2300 -#define UI_TIMER_JUMP 1000 -#define UI_TIMER_LAND 130 -#define UI_TIMER_WEAPON_SWITCH 300 -#define UI_TIMER_ATTACK 500 -#define UI_TIMER_MUZZLE_FLASH 20 -#define UI_TIMER_WEAPON_DELAY 250 - -#define JUMP_HEIGHT 56 - -#define SWINGSPEED 0.3f - -#define SPIN_SPEED 0.9f -#define COAST_TIME 1000 - - -static int dp_realtime; -static float jumpHeight; -sfxHandle_t weaponChangeSound; - - -/* -=============== -UI_PlayerInfo_SetWeapon -=============== -*/ -static void UI_PlayerInfo_SetWeapon( playerInfo_t *pi, weapon_t weaponNum ) { - gitem_t * item; - char path[MAX_QPATH]; - - pi->currentWeapon = weaponNum; -tryagain: - pi->realWeapon = weaponNum; - pi->weaponModel = 0; - pi->barrelModel = 0; - pi->flashModel = 0; - - if ( weaponNum == WP_NONE ) { - return; - } - - for ( item = bg_itemlist + 1; item->classname ; item++ ) { - if ( item->giType != IT_WEAPON ) { - continue; - } - if ( item->giTag == weaponNum ) { - break; - } - } - - if ( item->classname ) { - pi->weaponModel = trap_R_RegisterModel( item->world_model[0] ); - } - - if( pi->weaponModel == 0 ) { - if( weaponNum == WP_BRYAR_PISTOL ) { - weaponNum = WP_NONE; - goto tryagain; - } - weaponNum = WP_BRYAR_PISTOL; - goto tryagain; - } -/* - if ( weaponNum == WP_MACHINEGUN || weaponNum == WP_BFG ) { - strcpy( path, item->world_model[0] ); - COM_StripExtension( path, path ); - strcat( path, "_barrel.md3" ); - pi->barrelModel = trap_R_RegisterModel( path ); - } -*/ - strcpy( path, item->world_model[0] ); - COM_StripExtension( path, path ); - strcat( path, "_flash.md3" ); - pi->flashModel = trap_R_RegisterModel( path ); - - switch( weaponNum ) { - case WP_STUN_BATON: - case WP_SABER: - MAKERGB( pi->flashDlightColor, 0.6f, 0.6f, 1 ); - break; - - case WP_BRYAR_PISTOL: - case WP_BLASTER: - case WP_DISRUPTOR: - case WP_BOWCASTER: - case WP_REPEATER: - case WP_DEMP2: - case WP_FLECHETTE: - case WP_ROCKET_LAUNCHER: - case WP_THERMAL: - case WP_TRIP_MINE: - case WP_DET_PACK: - MAKERGB( pi->flashDlightColor, 1, 1, 0 ); - break; - - default: - MAKERGB( pi->flashDlightColor, 1, 1, 1 ); - break; - } -} - - -/* -=============== -UI_ForceLegsAnim -=============== -*/ -static void UI_ForceLegsAnim( playerInfo_t *pi, int anim ) { - pi->legsAnim = ( ( pi->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; - - if ( anim == BOTH_JUMP1 ) { - pi->legsAnimationTimer = UI_TIMER_JUMP; - } -} - - -/* -=============== -UI_SetLegsAnim -=============== -*/ -static void UI_SetLegsAnim( playerInfo_t *pi, int anim ) { - if ( pi->pendingLegsAnim ) { - anim = pi->pendingLegsAnim; - pi->pendingLegsAnim = 0; - } - UI_ForceLegsAnim( pi, anim ); -} - - -/* -=============== -UI_ForceTorsoAnim -=============== -*/ -static void UI_ForceTorsoAnim( playerInfo_t *pi, int anim ) { - pi->torsoAnim = ( ( pi->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; - - if ( anim == BOTH_GESTURE1 ) { - pi->torsoAnimationTimer = UI_TIMER_GESTURE; - } - - if ( anim == BOTH_ATTACK3 || anim == BOTH_A1_T__B_ ) { - pi->torsoAnimationTimer = UI_TIMER_ATTACK; - } -} - - -/* -=============== -UI_SetTorsoAnim -=============== -*/ -static void UI_SetTorsoAnim( playerInfo_t *pi, int anim ) { - if ( pi->pendingTorsoAnim ) { - anim = pi->pendingTorsoAnim; - pi->pendingTorsoAnim = 0; - } - - UI_ForceTorsoAnim( pi, anim ); -} - - -/* -=============== -UI_TorsoSequencing -=============== -*/ -static void UI_TorsoSequencing( playerInfo_t *pi ) { - int currentAnim; - - currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT; - - if ( pi->weapon != pi->currentWeapon ) { - if ( currentAnim != TORSO_DROPWEAP1 ) { - pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH; - UI_ForceTorsoAnim( pi, TORSO_DROPWEAP1 ); - } - } - - if ( pi->torsoAnimationTimer > 0 ) { - return; - } - - if( currentAnim == BOTH_GESTURE1 ) { - UI_SetTorsoAnim( pi, TORSO_WEAPONREADY3 ); - return; - } - - if( currentAnim == BOTH_ATTACK3 || currentAnim == BOTH_A1_T__B_ ) { - UI_SetTorsoAnim( pi, TORSO_WEAPONREADY3 ); - return; - } - - if ( currentAnim == TORSO_DROPWEAP1 ) { - UI_PlayerInfo_SetWeapon( pi, pi->weapon ); - pi->torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH; - UI_ForceTorsoAnim( pi, TORSO_RAISEWEAP1 ); - return; - } - - if ( currentAnim == TORSO_RAISEWEAP1 ) { - UI_SetTorsoAnim( pi, TORSO_WEAPONREADY3 ); - return; - } -} - - -/* -=============== -UI_LegsSequencing -=============== -*/ -static void UI_LegsSequencing( playerInfo_t *pi ) { - int currentAnim; - - currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT; - - if ( pi->legsAnimationTimer > 0 ) { - if ( currentAnim == BOTH_JUMP1 ) { - jumpHeight = JUMP_HEIGHT * sin( M_PI * ( UI_TIMER_JUMP - pi->legsAnimationTimer ) / UI_TIMER_JUMP ); - } - return; - } - - if ( currentAnim == BOTH_JUMP1 ) { - UI_ForceLegsAnim( pi, BOTH_LAND1 ); - pi->legsAnimationTimer = UI_TIMER_LAND; - jumpHeight = 0; - return; - } - - if ( currentAnim == BOTH_LAND1 ) { - UI_SetLegsAnim( pi, TORSO_WEAPONREADY3 ); - return; - } -} - - -/* -====================== -UI_PositionEntityOnTag -====================== -*/ -static void UI_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent, - clipHandle_t parentModel, char *tagName ) { - int i; - orientation_t lerped; - - // lerp the tag - trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame, - 1.0 - parent->backlerp, tagName ); - - // FIXME: allow origin offsets along tag? - VectorCopy( parent->origin, entity->origin ); - for ( i = 0 ; i < 3 ; i++ ) { - VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin ); - } - - // cast away const because of compiler problems - MatrixMultiply( lerped.axis, ((refEntity_t*)parent)->axis, entity->axis ); - entity->backlerp = parent->backlerp; -} - - -/* -====================== -UI_PositionRotatedEntityOnTag -====================== -*/ -static void UI_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent, - clipHandle_t parentModel, char *tagName ) { - int i; - orientation_t lerped; - vec3_t tempAxis[3]; - - // lerp the tag - trap_CM_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame, - 1.0 - parent->backlerp, tagName ); - - // FIXME: allow origin offsets along tag? - VectorCopy( parent->origin, entity->origin ); - for ( i = 0 ; i < 3 ; i++ ) { - VectorMA( entity->origin, lerped.origin[i], parent->axis[i], entity->origin ); - } - - // cast away const because of compiler problems - MatrixMultiply( entity->axis, ((refEntity_t *)parent)->axis, tempAxis ); - MatrixMultiply( lerped.axis, tempAxis, entity->axis ); -} - - -/* -=============== -UI_SetLerpFrameAnimation -=============== -*/ -static void UI_SetLerpFrameAnimation( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) { - animation_t *anim; - - lf->animationNumber = newAnimation; - newAnimation &= ~ANIM_TOGGLEBIT; - - if ( newAnimation < 0 || newAnimation >= MAX_ANIMATIONS ) { - trap_Error( va("Bad animation number: %i", newAnimation) ); - } - - anim = &ci->animations[ newAnimation ]; - - lf->animation = anim; - lf->animationTime = lf->frameTime + anim->initialLerp; -} - - -/* -=============== -UI_RunLerpFrame -=============== -*/ -static void UI_RunLerpFrame( playerInfo_t *ci, lerpFrame_t *lf, int newAnimation ) { - int f; - animation_t *anim; - - // see if the animation sequence is switching - if ( newAnimation != lf->animationNumber || !lf->animation ) { - UI_SetLerpFrameAnimation( ci, lf, newAnimation ); - } - - // if we have passed the current frame, move it to - // oldFrame and calculate a new frame - if ( dp_realtime >= lf->frameTime ) { - lf->oldFrame = lf->frame; - lf->oldFrameTime = lf->frameTime; - - // get the next frame based on the animation - anim = lf->animation; - if ( dp_realtime < lf->animationTime ) { - lf->frameTime = lf->animationTime; // initial lerp - } else { - lf->frameTime = lf->oldFrameTime + anim->frameLerp; - } - f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp; - if ( f >= anim->numFrames ) { - f -= anim->numFrames; - if ( anim->loopFrames ) { - f %= anim->loopFrames; - f += anim->numFrames - anim->loopFrames; - } else { - f = anim->numFrames - 1; - // the animation is stuck at the end, so it - // can immediately transition to another sequence - lf->frameTime = dp_realtime; - } - } - lf->frame = anim->firstFrame + f; - if ( dp_realtime > lf->frameTime ) { - lf->frameTime = dp_realtime; - } - } - - if ( lf->frameTime > dp_realtime + 200 ) { - lf->frameTime = dp_realtime; - } - - if ( lf->oldFrameTime > dp_realtime ) { - lf->oldFrameTime = dp_realtime; - } - // calculate current lerp value - if ( lf->frameTime == lf->oldFrameTime ) { - lf->backlerp = 0; - } else { - lf->backlerp = 1.0 - (float)( dp_realtime - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime ); - } -} - - -/* -=============== -UI_PlayerAnimation -=============== -*/ -static void UI_PlayerAnimation( playerInfo_t *pi, int *legsOld, int *legs, float *legsBackLerp, - int *torsoOld, int *torso, float *torsoBackLerp ) { - - // legs animation - pi->legsAnimationTimer -= uiInfo.uiDC.frameTime; - if ( pi->legsAnimationTimer < 0 ) { - pi->legsAnimationTimer = 0; - } - - UI_LegsSequencing( pi ); - - if ( pi->legs.yawing && ( pi->legsAnim & ~ANIM_TOGGLEBIT ) == TORSO_WEAPONREADY3 ) { - UI_RunLerpFrame( pi, &pi->legs, TORSO_WEAPONREADY3 ); - } else { - UI_RunLerpFrame( pi, &pi->legs, pi->legsAnim ); - } - *legsOld = pi->legs.oldFrame; - *legs = pi->legs.frame; - *legsBackLerp = pi->legs.backlerp; - - // torso animation - pi->torsoAnimationTimer -= uiInfo.uiDC.frameTime; - if ( pi->torsoAnimationTimer < 0 ) { - pi->torsoAnimationTimer = 0; - } - - UI_TorsoSequencing( pi ); - - UI_RunLerpFrame( pi, &pi->torso, pi->torsoAnim ); - *torsoOld = pi->torso.oldFrame; - *torso = pi->torso.frame; - *torsoBackLerp = pi->torso.backlerp; -} - - -/* -================== -UI_SwingAngles -================== -*/ -static void UI_SwingAngles( float destination, float swingTolerance, float clampTolerance, - float speed, float *angle, qboolean *swinging ) { - float swing; - float move; - float scale; - - if ( !*swinging ) { - // see if a swing should be started - swing = AngleSubtract( *angle, destination ); - if ( swing > swingTolerance || swing < -swingTolerance ) { - *swinging = qtrue; - } - } - - if ( !*swinging ) { - return; - } - - // modify the speed depending on the delta - // so it doesn't seem so linear - swing = AngleSubtract( destination, *angle ); - scale = fabs( swing ); - if ( scale < swingTolerance * 0.5 ) { - scale = 0.5; - } else if ( scale < swingTolerance ) { - scale = 1.0; - } else { - scale = 2.0; - } - - // swing towards the destination angle - if ( swing >= 0 ) { - move = uiInfo.uiDC.frameTime * scale * speed; - if ( move >= swing ) { - move = swing; - *swinging = qfalse; - } - *angle = AngleMod( *angle + move ); - } else if ( swing < 0 ) { - move = uiInfo.uiDC.frameTime * scale * -speed; - if ( move <= swing ) { - move = swing; - *swinging = qfalse; - } - *angle = AngleMod( *angle + move ); - } - - // clamp to no more than tolerance - swing = AngleSubtract( destination, *angle ); - if ( swing > clampTolerance ) { - *angle = AngleMod( destination - (clampTolerance - 1) ); - } else if ( swing < -clampTolerance ) { - *angle = AngleMod( destination + (clampTolerance - 1) ); - } -} - - -/* -====================== -UI_MovedirAdjustment -====================== -*/ -static float UI_MovedirAdjustment( playerInfo_t *pi ) { - vec3_t relativeAngles; - vec3_t moveVector; - - VectorSubtract( pi->viewAngles, pi->moveAngles, relativeAngles ); - AngleVectors( relativeAngles, moveVector, NULL, NULL ); - if ( Q_fabs( moveVector[0] ) < 0.01 ) { - moveVector[0] = 0.0; - } - if ( Q_fabs( moveVector[1] ) < 0.01 ) { - moveVector[1] = 0.0; - } - - if ( moveVector[1] == 0 && moveVector[0] > 0 ) { - return 0; - } - if ( moveVector[1] < 0 && moveVector[0] > 0 ) { - return 22; - } - if ( moveVector[1] < 0 && moveVector[0] == 0 ) { - return 45; - } - if ( moveVector[1] < 0 && moveVector[0] < 0 ) { - return -22; - } - if ( moveVector[1] == 0 && moveVector[0] < 0 ) { - return 0; - } - if ( moveVector[1] > 0 && moveVector[0] < 0 ) { - return 22; - } - if ( moveVector[1] > 0 && moveVector[0] == 0 ) { - return -45; - } - - return -22; -} - - -/* -=============== -UI_PlayerAngles -=============== -*/ -static void UI_PlayerAngles( playerInfo_t *pi, vec3_t legs[3], vec3_t torso[3], vec3_t head[3] ) { - vec3_t legsAngles, torsoAngles, headAngles; - float dest; - float adjust; - - VectorCopy( pi->viewAngles, headAngles ); - headAngles[YAW] = AngleMod( headAngles[YAW] ); - VectorClear( legsAngles ); - VectorClear( torsoAngles ); - - // --------- yaw ------------- - - // allow yaw to drift a bit - if ( ( pi->legsAnim & ~ANIM_TOGGLEBIT ) != TORSO_WEAPONREADY3 - || ( pi->torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_WEAPONREADY3 ) { - // if not standing still, always point all in the same direction - pi->torso.yawing = qtrue; // always center - pi->torso.pitching = qtrue; // always center - pi->legs.yawing = qtrue; // always center - } - - // adjust legs for movement dir - adjust = UI_MovedirAdjustment( pi ); - legsAngles[YAW] = headAngles[YAW] + adjust; - torsoAngles[YAW] = headAngles[YAW] + 0.25 * adjust; - - - // torso - UI_SwingAngles( torsoAngles[YAW], 25, 90, SWINGSPEED, &pi->torso.yawAngle, &pi->torso.yawing ); - UI_SwingAngles( legsAngles[YAW], 40, 90, SWINGSPEED, &pi->legs.yawAngle, &pi->legs.yawing ); - - torsoAngles[YAW] = pi->torso.yawAngle; - legsAngles[YAW] = pi->legs.yawAngle; - - // --------- pitch ------------- - - // only show a fraction of the pitch angle in the torso - if ( headAngles[PITCH] > 180 ) { - dest = (-360 + headAngles[PITCH]) * 0.75; - } else { - dest = headAngles[PITCH] * 0.75; - } - UI_SwingAngles( dest, 15, 30, 0.1f, &pi->torso.pitchAngle, &pi->torso.pitching ); - torsoAngles[PITCH] = pi->torso.pitchAngle; - - // pull the angles back out of the hierarchial chain - AnglesSubtract( headAngles, torsoAngles, headAngles ); - AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); - AnglesToAxis( legsAngles, legs ); - AnglesToAxis( torsoAngles, torso ); - AnglesToAxis( headAngles, head ); -} - - -/* -=============== -UI_PlayerFloatSprite -=============== -*/ -static void UI_PlayerFloatSprite( playerInfo_t *pi, vec3_t origin, qhandle_t shader ) { - refEntity_t ent; - - memset( &ent, 0, sizeof( ent ) ); - VectorCopy( origin, ent.origin ); - ent.origin[2] += 48; - ent.reType = RT_SPRITE; - ent.customShader = shader; - ent.radius = 10; - ent.renderfx = 0; - trap_R_AddRefEntityToScene( &ent ); -} - - -/* -====================== -UI_MachinegunSpinAngle -====================== -*/ -float UI_MachinegunSpinAngle( playerInfo_t *pi ) { - int delta; - float angle; - float speed; - int torsoAnim; - - delta = dp_realtime - pi->barrelTime; - if ( pi->barrelSpinning ) { - angle = pi->barrelAngle + delta * SPIN_SPEED; - } else { - if ( delta > COAST_TIME ) { - delta = COAST_TIME; - } - - speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME ); - angle = pi->barrelAngle + delta * speed; - } - - torsoAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT; - if( torsoAnim == BOTH_A1_T__B_ ) { - torsoAnim = BOTH_ATTACK3; - } - if ( pi->barrelSpinning == !(torsoAnim == BOTH_ATTACK3) ) { - pi->barrelTime = dp_realtime; - pi->barrelAngle = AngleMod( angle ); - pi->barrelSpinning = !!(torsoAnim == BOTH_ATTACK3); - } - - return angle; -} - - -/* -=============== -UI_DrawPlayer -=============== -*/ -void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ) { - refdef_t refdef; - refEntity_t legs; - refEntity_t torso; - refEntity_t head; - refEntity_t gun; -// refEntity_t barrel; - refEntity_t flash; - vec3_t origin; - int renderfx; - vec3_t mins = {-16, -16, -24}; - vec3_t maxs = {16, 16, 32}; - float len; - float xx; - - if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) { - return; - } - - // this allows the ui to cache the player model on the main menu - if (w == 0 || h == 0) { - return; - } - - dp_realtime = time; - - if ( pi->pendingWeapon != -1 && dp_realtime > pi->weaponTimer ) { - pi->weapon = pi->pendingWeapon; - pi->lastWeapon = pi->pendingWeapon; - pi->pendingWeapon = -1; - pi->weaponTimer = 0; - if( pi->currentWeapon != pi->weapon ) { - trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL ); - } - } - - y -= jumpHeight; - - memset( &refdef, 0, sizeof( refdef ) ); - memset( &legs, 0, sizeof(legs) ); - memset( &torso, 0, sizeof(torso) ); - memset( &head, 0, sizeof(head) ); - - refdef.rdflags = RDF_NOWORLDMODEL; - - AxisClear( refdef.viewaxis ); - - refdef.x = x; - refdef.y = y; - refdef.width = w; - refdef.height = h; - - refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f); - xx = refdef.width / tan( refdef.fov_x / 360 * M_PI ); - refdef.fov_y = atan2( refdef.height, xx ); - refdef.fov_y *= ( 360 / (float)M_PI ); - - // calculate distance so the player nearly fills the box - len = 0.7 * ( maxs[2] - mins[2] ); - origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 ); - origin[1] = 0.5 * ( mins[1] + maxs[1] ); - origin[2] = -0.5 * ( mins[2] + maxs[2] ); - - refdef.time = dp_realtime; - - trap_R_ClearScene(); - - // get the rotation information - UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis ); - - // get the animation state (after rotation, to allow feet shuffle) - UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp, - &torso.oldframe, &torso.frame, &torso.backlerp ); - - renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW; - - // - // add the legs - // - legs.hModel = pi->legsModel; - legs.customSkin = pi->legsSkin; - - VectorCopy( origin, legs.origin ); - - VectorCopy( origin, legs.lightingOrigin ); - legs.renderfx = renderfx; - VectorCopy (legs.origin, legs.oldorigin); - - trap_R_AddRefEntityToScene( &legs ); - - if (!legs.hModel) { - return; - } - - // - // add the torso - // - torso.hModel = pi->torsoModel; - if (!torso.hModel) { - return; - } - - torso.customSkin = pi->torsoSkin; - - VectorCopy( origin, torso.lightingOrigin ); - - UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso"); - - torso.renderfx = renderfx; - - trap_R_AddRefEntityToScene( &torso ); - - // - // add the head - // - head.hModel = pi->headModel; - if (!head.hModel) { - return; - } - head.customSkin = pi->headSkin; - - VectorCopy( origin, head.lightingOrigin ); - - UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head"); - - head.renderfx = renderfx; - - trap_R_AddRefEntityToScene( &head ); - - // - // add the gun - // - if ( pi->currentWeapon != WP_NONE ) { - memset( &gun, 0, sizeof(gun) ); - gun.hModel = pi->weaponModel; - VectorCopy( origin, gun.lightingOrigin ); - UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon"); - gun.renderfx = renderfx; - trap_R_AddRefEntityToScene( &gun ); - } - - // - // add the spinning barrel - // -/* - if ( pi->realWeapon == WP_MACHINEGUN || pi->realWeapon == WP_BFG ) { - vec3_t angles; - - memset( &barrel, 0, sizeof(barrel) ); - VectorCopy( origin, barrel.lightingOrigin ); - barrel.renderfx = renderfx; - - barrel.hModel = pi->barrelModel; - angles[YAW] = 0; - angles[PITCH] = 0; - angles[ROLL] = UI_MachinegunSpinAngle( pi ); - if(pi->realWeapon == WP_BFG ) { - angles[PITCH] = angles[ROLL]; - angles[ROLL] = 0; - } - AnglesToAxis( angles, barrel.axis ); - - UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel"); - - trap_R_AddRefEntityToScene( &barrel ); - } -*/ - // - // add muzzle flash - // - if ( dp_realtime <= pi->muzzleFlashTime ) { - if ( pi->flashModel ) { - memset( &flash, 0, sizeof(flash) ); - flash.hModel = pi->flashModel; - VectorCopy( origin, flash.lightingOrigin ); - UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash"); - flash.renderfx = renderfx; - trap_R_AddRefEntityToScene( &flash ); - } - - // make a dlight for the flash - if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) { - trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0], - pi->flashDlightColor[1], pi->flashDlightColor[2] ); - } - } - - // - // add the chat icon - // - if ( pi->chat ) { - UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) ); - } - - // - // add an accent light - // - origin[0] -= 100; // + = behind, - = in front - origin[1] += 100; // + = left, - = right - origin[2] += 100; // + = above, - = below - trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0 ); - - origin[0] -= 100; - origin[1] -= 100; - origin[2] -= 100; - trap_R_AddLightToScene( origin, 500, 1.0, 0.0, 0.0 ); - - trap_R_RenderScene( &refdef ); -} - -/* -========================== -UI_FileExists -========================== -*/ -static qboolean UI_FileExists(const char *filename) { - int len; - fileHandle_t f; - - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - if (len>0) { - trap_FS_FCloseFile(f); - return qtrue; - } - return qfalse; -} - -/* -========================== -UI_FindClientHeadFile -========================== -*/ -static qboolean UI_FindClientHeadFile( char *filename, int length, const char *teamName, const char *headModelName, const char *headSkinName, const char *base, const char *ext ) { - char *team, *headsFolder; - int i; - - team = "default"; - - if ( headModelName[0] == '*' ) { - headsFolder = "heads/"; - headModelName++; - } - else { - headsFolder = ""; - } - while(1) { - for ( i = 0; i < 2; i++ ) { - if ( i == 0 && teamName && *teamName ) { - Com_sprintf( filename, length, "models/players/%s%s/%s/%s%s_%s.%s", headsFolder, headModelName, headSkinName, teamName, base, team, ext ); - } - else { - Com_sprintf( filename, length, "models/players/%s%s/%s/%s_%s.%s", headsFolder, headModelName, headSkinName, base, team, ext ); - } - if ( UI_FileExists( filename ) ) { - return qtrue; - } - if ( i == 0 && teamName && *teamName ) { - Com_sprintf( filename, length, "models/players/%s%s/%s%s_%s.%s", headsFolder, headModelName, teamName, base, headSkinName, ext ); - } - else { - Com_sprintf( filename, length, "models/players/%s%s/%s_%s.%s", headsFolder, headModelName, base, headSkinName, ext ); - } - if ( UI_FileExists( filename ) ) { - return qtrue; - } - if ( !teamName || !*teamName ) { - break; - } - } - // if tried the heads folder first - if ( headsFolder[0] ) { - break; - } - headsFolder = "heads/"; - } - - return qfalse; -} - -/* -========================== -UI_RegisterClientSkin -========================== -*/ -static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName , const char *teamName) { - char filename[MAX_QPATH*2]; - - if (teamName && *teamName) { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/%s/lower_%s.skin", modelName, teamName, skinName ); - } else { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName ); - } - pi->legsSkin = trap_R_RegisterSkin( filename ); - if (!pi->legsSkin) { - if (teamName && *teamName) { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%s/lower_%s.skin", modelName, teamName, skinName ); - } else { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower_%s.skin", modelName, skinName ); - } - pi->legsSkin = trap_R_RegisterSkin( filename ); - } - - if (teamName && *teamName) { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/%s/upper_%s.skin", modelName, teamName, skinName ); - } else { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName ); - } - pi->torsoSkin = trap_R_RegisterSkin( filename ); - if (!pi->torsoSkin) { - if (teamName && *teamName) { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%s/upper_%s.skin", modelName, teamName, skinName ); - } else { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper_%s.skin", modelName, skinName ); - } - pi->torsoSkin = trap_R_RegisterSkin( filename ); - } - - if ( UI_FindClientHeadFile( filename, sizeof(filename), teamName, headModelName, headSkinName, "head", "skin" ) ) { - pi->headSkin = trap_R_RegisterSkin( filename ); - } - - if ( !pi->legsSkin || !pi->torsoSkin || !pi->headSkin ) { - return qfalse; - } - - return qtrue; -} - - -/* -====================== -UI_ParseAnimationFile -====================== -*/ -static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) { - char *text_p, *prev; - int len; - int i; - char *token; - float fps; - int skip; - char text[20000]; - fileHandle_t f; - - memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS ); - - // load the file - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - if ( len <= 0 ) { - return qfalse; - } - if ( len >= ( sizeof( text ) - 1 ) ) { - Com_Printf( "File %s too long\n", filename ); - return qfalse; - } - trap_FS_Read( text, len, f ); - text[len] = 0; - trap_FS_FCloseFile( f ); - - COM_Compress(text); - - // parse the text - text_p = text; - skip = 0; // quite the compiler warning - - // read optional parameters - while ( 1 ) { - prev = text_p; // so we can unget - token = COM_Parse( (const char **)&text_p ); - if ( !token ) { - break; - } - if ( !Q_stricmp( token, "footsteps" ) ) { - token = COM_Parse( (const char **)&text_p ); - if ( !token ) { - break; - } - continue; - } else if ( !Q_stricmp( token, "headoffset" ) ) { - for ( i = 0 ; i < 3 ; i++ ) { - token = COM_Parse( (const char **)&text_p ); - if ( !token ) { - break; - } - } - continue; - } else if ( !Q_stricmp( token, "sex" ) ) { - token = COM_Parse( (const char **)&text_p ); - if ( !token ) { - break; - } - continue; - } - - // if it is a number, start parsing animations - if ( token[0] >= '0' && token[0] <= '9' ) { - text_p = prev; // unget the token - break; - } - - Com_Printf( "unknown token '%s' is %s\n", token, filename ); - } - - // read information for each frame - for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) { - - token = COM_Parse( (const char **)&text_p ); - if ( !token ) { - break; - } - animations[i].firstFrame = atoi( token ); - // leg only frames are adjusted to not count the upper body only frames - if ( i == BOTH_CROUCH1WALK ) { - skip = animations[BOTH_CROUCH1WALK].firstFrame - animations[BOTH_GESTURE1].firstFrame; - } - if ( i >= BOTH_CROUCH1WALK ) { - animations[i].firstFrame -= skip; - } - - token = COM_Parse( (const char **)&text_p ); - if ( !token ) { - break; - } - animations[i].numFrames = atoi( token ); - - token = COM_Parse( (const char **)&text_p ); - if ( !token ) { - break; - } - animations[i].loopFrames = atoi( token ); - - token = COM_Parse( (const char **)&text_p ); - if ( !token ) { - break; - } - fps = atof( token ); - if ( fps == 0 ) { - fps = 1; - } - animations[i].frameLerp = 1000 / fps; - animations[i].initialLerp = 1000 / fps; - } - - if ( i != MAX_ANIMATIONS ) { - Com_Printf( "Error parsing animation file: %s", filename ); - return qfalse; - } - - return qtrue; -} - -/* -========================== -UI_RegisterClientModelname -========================== -*/ -qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName, const char *headModelSkinName, const char *teamName ) { - char modelName[MAX_QPATH]; - char skinName[MAX_QPATH]; - char headModelName[MAX_QPATH]; - char headSkinName[MAX_QPATH]; - char filename[MAX_QPATH]; - char *slash; - - pi->torsoModel = 0; - pi->headModel = 0; - - if ( !modelSkinName[0] ) { - return qfalse; - } - - Q_strncpyz( modelName, modelSkinName, sizeof( modelName ) ); - - slash = strchr( modelName, '/' ); - if ( !slash ) { - // modelName did not include a skin name - Q_strncpyz( skinName, "default", sizeof( skinName ) ); - } else { - Q_strncpyz( skinName, slash + 1, sizeof( skinName ) ); - *slash = '\0'; - } - - Q_strncpyz( headModelName, headModelSkinName, sizeof( headModelName ) ); - slash = strchr( headModelName, '/' ); - if ( !slash ) { - // modelName did not include a skin name - Q_strncpyz( headSkinName, "default", sizeof( skinName ) ); - } else { - Q_strncpyz( headSkinName, slash + 1, sizeof( skinName ) ); - *slash = '\0'; - } - - // load cmodels before models so filecache works - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName ); - pi->legsModel = trap_R_RegisterModel( filename ); - if ( !pi->legsModel ) { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower.md3", modelName ); - pi->legsModel = trap_R_RegisterModel( filename ); - if ( !pi->legsModel ) { - Com_Printf( "Failed to load model file %s\n", filename ); - return qfalse; - } - } - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName ); - pi->torsoModel = trap_R_RegisterModel( filename ); - if ( !pi->torsoModel ) { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper.md3", modelName ); - pi->torsoModel = trap_R_RegisterModel( filename ); - if ( !pi->torsoModel ) { - Com_Printf( "Failed to load model file %s\n", filename ); - return qfalse; - } - } - - if (headModelName && headModelName[0] == '*' ) { - Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] ); - } - else { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headModelName ); - } - pi->headModel = trap_R_RegisterModel( filename ); - if ( !pi->headModel && headModelName[0] != '*') { - Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName ); - pi->headModel = trap_R_RegisterModel( filename ); - } - - if (!pi->headModel) { - Com_Printf( "Failed to load model file %s\n", filename ); - return qfalse; - } - - // if any skins failed to load, fall back to default - if ( !UI_RegisterClientSkin( pi, modelName, skinName, headModelName, headSkinName, teamName) ) { - if ( !UI_RegisterClientSkin( pi, modelName, "default", headModelName, "default", teamName ) ) { - Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName ); - return qfalse; - } - } - - // load the animations - Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName ); - if ( !UI_ParseAnimationFile( filename, pi->animations ) ) { - Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName ); - if ( !UI_ParseAnimationFile( filename, pi->animations ) ) { - Com_Printf( "Failed to load animation file %s\n", filename ); - return qfalse; - } - } - - return qtrue; -} - - -/* -=============== -UI_PlayerInfo_SetModel -=============== -*/ -void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model, const char *headmodel, char *teamName ) { - memset( pi, 0, sizeof(*pi) ); - UI_RegisterClientModelname( pi, model, headmodel, teamName ); - pi->weapon = WP_BRYAR_PISTOL; - pi->currentWeapon = pi->weapon; - pi->lastWeapon = pi->weapon; - pi->pendingWeapon = -1; - pi->weaponTimer = 0; - pi->chat = qfalse; - pi->newModel = qtrue; - UI_PlayerInfo_SetWeapon( pi, pi->weapon ); -} - - -/* -=============== -UI_PlayerInfo_SetInfo -=============== -*/ -void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) { - int currentAnim; - weapon_t weaponNum; - - pi->chat = chat; - - // view angles - VectorCopy( viewAngles, pi->viewAngles ); - - // move angles - VectorCopy( moveAngles, pi->moveAngles ); - - if ( pi->newModel ) { - pi->newModel = qfalse; - - jumpHeight = 0; - pi->pendingLegsAnim = 0; - UI_ForceLegsAnim( pi, legsAnim ); - pi->legs.yawAngle = viewAngles[YAW]; - pi->legs.yawing = qfalse; - - pi->pendingTorsoAnim = 0; - UI_ForceTorsoAnim( pi, torsoAnim ); - pi->torso.yawAngle = viewAngles[YAW]; - pi->torso.yawing = qfalse; - - if ( weaponNumber != -1 ) { - pi->weapon = weaponNumber; - pi->currentWeapon = weaponNumber; - pi->lastWeapon = weaponNumber; - pi->pendingWeapon = -1; - pi->weaponTimer = 0; - UI_PlayerInfo_SetWeapon( pi, pi->weapon ); - } - - return; - } - - // weapon - if ( weaponNumber == -1 ) { - pi->pendingWeapon = -1; - pi->weaponTimer = 0; - } - else if ( weaponNumber != WP_NONE ) { - pi->pendingWeapon = weaponNumber; - pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY; - } - weaponNum = pi->lastWeapon; - pi->weapon = weaponNum; - - if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) { - torsoAnim = legsAnim = BOTH_DEATH1; - pi->weapon = pi->currentWeapon = WP_NONE; - UI_PlayerInfo_SetWeapon( pi, pi->weapon ); - - jumpHeight = 0; - pi->pendingLegsAnim = 0; - UI_ForceLegsAnim( pi, legsAnim ); - - pi->pendingTorsoAnim = 0; - UI_ForceTorsoAnim( pi, torsoAnim ); - - return; - } - - // leg animation - currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT; - if ( legsAnim != BOTH_JUMP1 && ( currentAnim == BOTH_JUMP1 || currentAnim == BOTH_LAND1 ) ) { - pi->pendingLegsAnim = legsAnim; - } - else if ( legsAnim != currentAnim ) { - jumpHeight = 0; - pi->pendingLegsAnim = 0; - UI_ForceLegsAnim( pi, legsAnim ); - } - - // torso animation - if ( torsoAnim == TORSO_WEAPONREADY3 || torsoAnim == BOTH_STAND2 ) { - if ( weaponNum == WP_NONE || weaponNum == WP_SABER ) { - torsoAnim = BOTH_STAND2; - } - else { - torsoAnim = TORSO_WEAPONREADY3; - } - } - - if ( torsoAnim == BOTH_ATTACK3 || torsoAnim == BOTH_A1_T__B_ ) { - if ( weaponNum == WP_NONE || weaponNum == WP_SABER ) { - torsoAnim = BOTH_A1_T__B_; - } - else { - torsoAnim = BOTH_ATTACK3; - } - pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH; - //FIXME play firing sound here - } - - currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT; - - if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISEWEAP1|| currentAnim == TORSO_DROPWEAP1 ) { - pi->pendingTorsoAnim = torsoAnim; - } - else if ( ( currentAnim == BOTH_GESTURE1 || currentAnim == BOTH_ATTACK3 ) && ( torsoAnim != currentAnim ) ) { - pi->pendingTorsoAnim = torsoAnim; - } - else if ( torsoAnim != currentAnim ) { - pi->pendingTorsoAnim = 0; - UI_ForceTorsoAnim( pi, torsoAnim ); - } -} diff --git a/CODE-mp/ui/ui_shared.c b/CODE-mp/ui/ui_shared.c index 9b085ee..eeb507f 100644 --- a/CODE-mp/ui/ui_shared.c +++ b/CODE-mp/ui/ui_shared.c @@ -52,7 +52,7 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down); itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu); itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu); static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y); -qboolean MenuParse_stripedFile( itemDef_t *item, int handle); +static void Item_TextScroll_BuildLines ( itemDef_t* item ); #ifdef CGAME #define MEM_POOL_SIZE 128 * 1024 @@ -64,7 +64,6 @@ qboolean MenuParse_stripedFile( itemDef_t *item, int handle); static char memoryPool[MEM_POOL_SIZE]; static int allocPoint, outOfMemory; -char stripedFile[MAX_STRING_CHARS]; typedef struct itemFlagsDef_s { char *string; @@ -525,7 +524,8 @@ PC_String_Parse */ qboolean PC_String_Parse(int handle, const char **out) { - pc_token_t token; + static char* squiggy = "}"; + pc_token_t token; if (!trap_PC_ReadToken(handle, &token)) { @@ -539,7 +539,8 @@ qboolean PC_String_Parse(int handle, const char **out) temp = &token.string[0]; // The +1 is to offset the @ at the beginning of the text - trap_SP_GetStringTextString(va("%s_%s",stripedFile,(temp+1)), text, sizeof(text)); +// trap_SP_GetStringTextString(va("%s_%s",stripedFile,(temp+1)), text, sizeof(text)); + trap_SP_GetStringTextString( temp+1 , text, sizeof(text)); // findmeste if (text[0] == 0) // Couldn't find it { @@ -553,7 +554,15 @@ qboolean PC_String_Parse(int handle, const char **out) } else { - *(out) = String_Alloc(token.string); + // Save some memory by not return the end squiggy as an allocated string + if ( !Q_stricmp ( token.string, "}" ) ) + { + *(out) = squiggy; + } + else + { + *(out) = String_Alloc(token.string); + } } return qtrue; @@ -565,10 +574,10 @@ PC_Script_Parse ================= */ qboolean PC_Script_Parse(int handle, const char **out) { - char script[1024]; + char script[2048]; pc_token_t token; - memset(script, 0, sizeof(script)); + script[0] = 0; // scripts start with { and have ; separated command lists.. commands are command, arg.. // basically we want everything between the { } as it will be interpreted at run time @@ -588,11 +597,11 @@ qboolean PC_Script_Parse(int handle, const char **out) { } if (token.string[1] != '\0') { - Q_strcat(script, 1024, va("\"%s\"", token.string)); + Q_strcat(script, 2048, va("\"%s\"", token.string)); } else { - Q_strcat(script, 1024, token.string); + Q_strcat(script, 2048, token.string); } - Q_strcat(script, 1024, " "); + Q_strcat(script, 2048, " "); } return qfalse; // bk001105 - LCC missing return value } @@ -793,25 +802,44 @@ void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle) } -void Item_SetScreenCoords(itemDef_t *item, float x, float y) { - - if (item == NULL) { - return; - } +void Item_SetScreenCoords(itemDef_t *item, float x, float y) +{ + if (item == NULL) + { + return; + } - if (item->window.border != 0) { - x += item->window.borderSize; - y += item->window.borderSize; - } + if (item->window.border != 0) + { + x += item->window.borderSize; + y += item->window.borderSize; + } - item->window.rect.x = x + item->window.rectClient.x; - item->window.rect.y = y + item->window.rectClient.y; - item->window.rect.w = item->window.rectClient.w; - item->window.rect.h = item->window.rectClient.h; + item->window.rect.x = x + item->window.rectClient.x; + item->window.rect.y = y + item->window.rectClient.y; + item->window.rect.w = item->window.rectClient.w; + item->window.rect.h = item->window.rectClient.h; - // force the text rects to recompute - item->textRect.w = 0; - item->textRect.h = 0; + // force the text rects to recompute + item->textRect.w = 0; + item->textRect.h = 0; + + switch ( item->type) + { + case ITEM_TYPE_TEXTSCROLL: + { + textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData; + if ( scrollPtr ) + { + scrollPtr->startPos = 0; + scrollPtr->endPos = 0; + } + + Item_TextScroll_BuildLines ( item ); + + break; + } + } } // FIXME: consolidate this with nearby stuff @@ -930,58 +958,74 @@ itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char * return NULL; } +qboolean Script_SetColor ( itemDef_t *item, char **args ) +{ + const char *name; + int i; + float f; + vec4_t *out; + + // expecting type of color to set and 4 args for the color + if (String_Parse(args, &name)) + { + out = NULL; + if (Q_stricmp(name, "backcolor") == 0) + { + out = &item->window.backColor; + item->window.flags |= WINDOW_BACKCOLORSET; + } + else if (Q_stricmp(name, "forecolor") == 0) + { + out = &item->window.foreColor; + item->window.flags |= WINDOW_FORECOLORSET; + } + else if (Q_stricmp(name, "bordercolor") == 0) + { + out = &item->window.borderColor; + } + if (out) + { + for (i = 0; i < 4; i++) + { + if (!Float_Parse(args, &f)) + { + return qtrue; + } + (*out)[i] = f; + } + } + } -void Script_SetColor(itemDef_t *item, char **args) { - const char *name; - int i; - float f; - vec4_t *out; - // expecting type of color to set and 4 args for the color - if (String_Parse(args, &name)) { - out = NULL; - if (Q_stricmp(name, "backcolor") == 0) { - out = &item->window.backColor; - item->window.flags |= WINDOW_BACKCOLORSET; - } else if (Q_stricmp(name, "forecolor") == 0) { - out = &item->window.foreColor; - item->window.flags |= WINDOW_FORECOLORSET; - } else if (Q_stricmp(name, "bordercolor") == 0) { - out = &item->window.borderColor; - } - - if (out) { - for (i = 0; i < 4; i++) { - if (!Float_Parse(args, &f)) { - return; - } - (*out)[i] = f; - } - } - } + return qtrue; } -void Script_SetAsset(itemDef_t *item, char **args) { - const char *name; - // expecting name to set asset to - if (String_Parse(args, &name)) { - // check for a model - if (item->type == ITEM_TYPE_MODEL) { - } - } +qboolean Script_SetAsset(itemDef_t *item, char **args) +{ + const char *name; + // expecting name to set asset to + if (String_Parse(args, &name)) + { + // check for a model + if (item->type == ITEM_TYPE_MODEL) + { + } + } + return qtrue; } -void Script_SetBackground(itemDef_t *item, char **args) { - const char *name; - // expecting name to set asset to - if (String_Parse(args, &name)) { - item->window.background = DC->registerShaderNoMip(name); - } +qboolean Script_SetBackground(itemDef_t *item, char **args) +{ + const char *name; + // expecting name to set asset to + if (String_Parse(args, &name)) + { + item->window.background = DC->registerShaderNoMip(name); + } + return qtrue; } - - itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p) { int i; if (menu == NULL || p == NULL) { @@ -997,57 +1041,76 @@ itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p) { return NULL; } -void Script_SetTeamColor(itemDef_t *item, char **args) { - if (DC->getTeamColor) { - int i; - vec4_t color; - DC->getTeamColor(&color); - for (i = 0; i < 4; i++) { - item->window.backColor[i] = color[i]; - } - } +qboolean Script_SetTeamColor(itemDef_t *item, char **args) +{ + if (DC->getTeamColor) + { + int i; + vec4_t color; + DC->getTeamColor(&color); + for (i = 0; i < 4; i++) + { + item->window.backColor[i] = color[i]; + } + } + return qtrue; } -void Script_SetItemColor(itemDef_t *item, char **args) { - const char *itemname; - const char *name; - vec4_t color; - int i; - vec4_t *out; - // expecting type of color to set and 4 args for the color - if (String_Parse(args, &itemname) && String_Parse(args, &name)) { - itemDef_t *item2; - int j; - int count = Menu_ItemsMatchingGroup(item->parent, itemname); +qboolean Script_SetItemColor(itemDef_t *item, char **args) +{ + const char *itemname; + const char *name; + vec4_t color; + int i; + vec4_t *out; - if (!Color_Parse(args, &color)) { - return; - } + // expecting type of color to set and 4 args for the color + if (String_Parse(args, &itemname) && String_Parse(args, &name)) + { + itemDef_t *item2; + int j; + int count = Menu_ItemsMatchingGroup(item->parent, itemname); - for (j = 0; j < count; j++) { - item2 = Menu_GetMatchingItemByNumber(item->parent, j, itemname); - if (item2 != NULL) { - out = NULL; - if (Q_stricmp(name, "backcolor") == 0) { - out = &item2->window.backColor; - } else if (Q_stricmp(name, "forecolor") == 0) { - out = &item2->window.foreColor; - item2->window.flags |= WINDOW_FORECOLORSET; - } else if (Q_stricmp(name, "bordercolor") == 0) { - out = &item2->window.borderColor; - } + if (!Color_Parse(args, &color)) + { + return qtrue; + } - if (out) { - for (i = 0; i < 4; i++) { - (*out)[i] = color[i]; - } - } - } - } - } + for (j = 0; j < count; j++) + { + item2 = Menu_GetMatchingItemByNumber(item->parent, j, itemname); + if (item2 != NULL) + { + out = NULL; + if (Q_stricmp(name, "backcolor") == 0) + { + out = &item2->window.backColor; + } + else if (Q_stricmp(name, "forecolor") == 0) + { + out = &item2->window.foreColor; + item2->window.flags |= WINDOW_FORECOLORSET; + } + else if (Q_stricmp(name, "bordercolor") == 0) + { + out = &item2->window.borderColor; + } + + if (out) + { + for (i = 0; i < 4; i++) + { + (*out)[i] = color[i]; + } + } + } + } + } + + return qtrue; } -void Script_SetItemRect(itemDef_t *item, char **args) +qboolean Script_SetItemRect(itemDef_t *item, char **args) { const char *itemname; rectDef_t *out; @@ -1062,7 +1125,7 @@ void Script_SetItemRect(itemDef_t *item, char **args) if (!Rect_Parse(args, &rect)) { - return; + return qtrue; } for (j = 0; j < count; j++) @@ -1082,6 +1145,7 @@ void Script_SetItemRect(itemDef_t *item, char **args) } } } + return qtrue; } @@ -1153,68 +1217,128 @@ static void Menu_RunCloseScript(menuDef_t *menu) { } } -void Menus_CloseByName(const char *p) { - menuDef_t *menu = Menus_FindByName(p); - if (menu != NULL) { - Menu_RunCloseScript(menu); - menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS); - } +void Menus_CloseByName ( const char *p ) +{ + menuDef_t *menu = Menus_FindByName(p); + + // If the menu wasnt found just exit + if (menu == NULL) + { + return; + } + + // Run the close script for the menu + Menu_RunCloseScript(menu); + + // If this window had the focus then take it away + if ( menu->window.flags & WINDOW_HASFOCUS ) + { + // If there is something still in the open menu list then + // set it to have focus now + if ( openMenuCount ) + { + // Subtract one from the open menu count to prepare to + // remove the top menu from the list + openMenuCount -= 1; + + // Set the top menu to have focus now + menuStack[openMenuCount]->window.flags |= WINDOW_HASFOCUS; + + // Remove the top menu from the list + menuStack[openMenuCount] = NULL; + } + } + + // Window is now invisible and doenst have focus + menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS); } int FPMessageTime = 0; -void Menus_CloseAll() { - int i; - for (i = 0; i < menuCount; i++) { - Menu_RunCloseScript(&Menus[i]); +void Menus_CloseAll() +{ + int i; + + g_waitingForKey = qfalse; + + for (i = 0; i < menuCount; i++) + { + Menu_RunCloseScript ( &Menus[i] ); Menus[i].window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE); - } - FPMessageTime = 0; + } + + // Clear the menu stack + openMenuCount = 0; + + FPMessageTime = 0; } - -void Script_Show(itemDef_t *item, char **args) { - const char *name; - if (String_Parse(args, &name)) { - Menu_ShowItemByName(item->parent, name, qtrue); - } +qboolean Script_Show(itemDef_t *item, char **args) +{ + const char *name; + if (String_Parse(args, &name)) + { + Menu_ShowItemByName(item->parent, name, qtrue); + } + return qtrue; } -void Script_Hide(itemDef_t *item, char **args) { - const char *name; - if (String_Parse(args, &name)) { - Menu_ShowItemByName(item->parent, name, qfalse); - } +qboolean Script_Hide(itemDef_t *item, char **args) +{ + const char *name; + if (String_Parse(args, &name)) + { + Menu_ShowItemByName(item->parent, name, qfalse); + } + return qtrue; } -void Script_FadeIn(itemDef_t *item, char **args) { - const char *name; - if (String_Parse(args, &name)) { - Menu_FadeItemByName(item->parent, name, qfalse); - } +qboolean Script_FadeIn(itemDef_t *item, char **args) +{ + const char *name; + if (String_Parse(args, &name)) + { + Menu_FadeItemByName(item->parent, name, qfalse); + } + + return qtrue; } -void Script_FadeOut(itemDef_t *item, char **args) { - const char *name; - if (String_Parse(args, &name)) { - Menu_FadeItemByName(item->parent, name, qtrue); - } +qboolean Script_FadeOut(itemDef_t *item, char **args) +{ + const char *name; + if (String_Parse(args, &name)) + { + Menu_FadeItemByName(item->parent, name, qtrue); + } + return qtrue; } - - -void Script_Open(itemDef_t *item, char **args) { - const char *name; - if (String_Parse(args, &name)) { - Menus_OpenByName(name); - } +qboolean Script_Open(itemDef_t *item, char **args) +{ + const char *name; + if (String_Parse(args, &name)) + { + Menus_OpenByName(name); + } + return qtrue; } -void Script_Close(itemDef_t *item, char **args) { - const char *name; - if (String_Parse(args, &name)) { - Menus_CloseByName(name); - } +qboolean Script_Close(itemDef_t *item, char **args) +{ + const char *name; + if (String_Parse(args, &name)) + { + if (Q_stricmp(name, "all") == 0) + { + Menus_CloseAll(); + } + else + { + Menus_CloseByName(name); + } + } + return qtrue; } void Menu_TransitionItemByName(menuDef_t *menu, const char *p, rectDef_t rectFrom, rectDef_t rectTo, int time, float amt) { @@ -1237,22 +1361,80 @@ void Menu_TransitionItemByName(menuDef_t *menu, const char *p, rectDef_t rectFro } } +#define MAX_DEFERRED_SCRIPT 2048 -void Script_Transition(itemDef_t *item, char **args) { - const char *name; - rectDef_t rectFrom, rectTo; - int time; - float amt; +char ui_deferredScript [ MAX_DEFERRED_SCRIPT ]; +itemDef_t* ui_deferredScriptItem = NULL; - if (String_Parse(args, &name)) { - if ( Rect_Parse(args, &rectFrom) && Rect_Parse(args, &rectTo) && Int_Parse(args, &time) && Float_Parse(args, &amt)) { - Menu_TransitionItemByName(item->parent, name, rectFrom, rectTo, time, amt); - } - } +/* +================= +Script_Defer + +Defers the rest of the script based on the defer condition. The deferred +portion of the script can later be run with the "rundeferred" +================= +*/ +qboolean Script_Defer ( itemDef_t* item, char **args ) +{ + // Should the script be deferred? + if ( DC->deferScript ( (char**)args ) ) + { + // Need the item the script was being run on + ui_deferredScriptItem = item; + + // Save the rest of the script + Q_strncpyz ( ui_deferredScript, *args, MAX_DEFERRED_SCRIPT ); + + // No more running + return qfalse; + } + + // Keep running the script, its ok + return qtrue; } +/* +================= +Script_RunDeferred -void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time) { +Runs the last deferred script, there can only be one script deferred at a +time so be careful of recursion +================= +*/ +qboolean Script_RunDeferred ( itemDef_t* item, char **args ) +{ + // Make sure there is something to run. + if ( !ui_deferredScript[0] || !ui_deferredScriptItem ) + { + return qtrue; + } + + // Run the deferred script now + Item_RunScript ( ui_deferredScriptItem, ui_deferredScript ); + + return qtrue; +} + +qboolean Script_Transition(itemDef_t *item, char **args) +{ + const char *name; + rectDef_t rectFrom, rectTo; + int time; + float amt; + + if (String_Parse(args, &name)) + { + if ( Rect_Parse(args, &rectFrom) && Rect_Parse(args, &rectTo) && Int_Parse(args, &time) && Float_Parse(args, &amt)) + { + Menu_TransitionItemByName(item->parent, name, rectFrom, rectTo, time, amt); + } + } + + return qtrue; +} + +void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time) +{ itemDef_t *item; int i; int count = Menu_ItemsMatchingGroup(menu, p); @@ -1270,22 +1452,25 @@ void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, floa } } +qboolean Script_Orbit(itemDef_t *item, char **args) +{ + const char *name; + float cx, cy, x, y; + int time; -void Script_Orbit(itemDef_t *item, char **args) { - const char *name; - float cx, cy, x, y; - int time; + if (String_Parse(args, &name)) + { + if ( Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) && Int_Parse(args, &time) ) + { + Menu_OrbitItemByName(item->parent, name, x, y, cx, cy, time); + } + } - if (String_Parse(args, &name)) { - if ( Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) && Int_Parse(args, &time) ) { - Menu_OrbitItemByName(item->parent, name, x, y, cx, cy, time); - } - } + return qtrue; } - - -void Script_SetFocus(itemDef_t *item, char **args) { +qboolean Script_SetFocus(itemDef_t *item, char **args) +{ const char *name; itemDef_t *focusItem; @@ -1302,60 +1487,74 @@ void Script_SetFocus(itemDef_t *item, char **args) { } } } + + return qtrue; } -void Script_SetPlayerModel(itemDef_t *item, char **args) { - const char *name; - if (String_Parse(args, &name)) { - DC->setCVar("team_model", name); - } +qboolean Script_SetPlayerModel(itemDef_t *item, char **args) +{ + const char *name; + if (String_Parse(args, &name)) + { + DC->setCVar("team_model", name); + } + + return qtrue; } -void Script_SetPlayerHead(itemDef_t *item, char **args) { - const char *name; - if (String_Parse(args, &name)) { - DC->setCVar("team_headmodel", name); - } +qboolean Script_SetPlayerHead(itemDef_t *item, char **args) +{ + const char *name; + if (String_Parse(args, &name)) + { + DC->setCVar("team_headmodel", name); + } + return qtrue; } -void Script_SetCvar(itemDef_t *item, char **args) { +qboolean Script_SetCvar(itemDef_t *item, char **args) +{ const char *cvar, *val; - if (String_Parse(args, &cvar) && String_Parse(args, &val)) { + if (String_Parse(args, &cvar) && String_Parse(args, &val)) + { DC->setCVar(cvar, val); } - + return qtrue; } -void Script_SetCvarToCvar(itemDef_t *item, char **args) { +qboolean Script_SetCvarToCvar(itemDef_t *item, char **args) { const char *cvar, *val; if (String_Parse(args, &cvar) && String_Parse(args, &val)) { char cvarBuf[1024]; DC->getCVarString(val, cvarBuf, sizeof(cvarBuf)); DC->setCVar(cvar, cvarBuf); } - + return qtrue; } -void Script_Exec(itemDef_t *item, char **args) { +qboolean Script_Exec(itemDef_t *item, char **args) { const char *val; if (String_Parse(args, &val)) { DC->executeText(EXEC_APPEND, va("%s ; ", val)); } + return qtrue; } -void Script_Play(itemDef_t *item, char **args) { +qboolean Script_Play(itemDef_t *item, char **args) { const char *val; if (String_Parse(args, &val)) { - DC->startLocalSound(DC->registerSound(val), CHAN_LOCAL_SOUND); + DC->startLocalSound(DC->registerSound(val), CHAN_AUTO); } + return qtrue; } -void Script_playLooped(itemDef_t *item, char **args) { +qboolean Script_playLooped(itemDef_t *item, char **args) { const char *val; if (String_Parse(args, &val)) { DC->stopBackgroundTrack(); DC->startBackgroundTrack(val, val, qfalse); } + return qtrue; } @@ -1371,67 +1570,86 @@ commandDef_t commandList[] = {"setasset", &Script_SetAsset}, // works on this {"setbackground", &Script_SetBackground}, // works on this {"setitemcolor", &Script_SetItemColor}, // group/name - {"setitemrect", &Script_SetItemRect}, // group/name + {"setitemrect", &Script_SetItemRect}, // group/name {"setteamcolor", &Script_SetTeamColor}, // sets this background color to team color - {"setfocus", &Script_SetFocus}, // sets this background color to team color - {"setplayermodel", &Script_SetPlayerModel}, // sets this background color to team color - {"setplayerhead", &Script_SetPlayerHead}, // sets this background color to team color + {"setfocus", &Script_SetFocus}, // sets focus + {"setplayermodel", &Script_SetPlayerModel}, // sets model + {"setplayerhead", &Script_SetPlayerHead}, // sets head {"transition", &Script_Transition}, // group/name - {"setcvar", &Script_SetCvar}, // group/name - {"setcvartocvar", &Script_SetCvarToCvar}, // group/name - {"exec", &Script_Exec}, // group/name - {"play", &Script_Play}, // group/name + {"setcvar", &Script_SetCvar}, // name + {"setcvartocvar", &Script_SetCvarToCvar}, // name + {"exec", &Script_Exec}, // group/name + {"play", &Script_Play}, // group/name {"playlooped", &Script_playLooped}, // group/name - {"orbit", &Script_Orbit} // group/name + {"orbit", &Script_Orbit}, // group/name + {"defer", &Script_Defer}, // + {"rundeferred", &Script_RunDeferred}, // }; int scriptCommandCount = sizeof(commandList) / sizeof(commandDef_t); -void Item_RunScript(itemDef_t *item, const char *s) { - char script[1024], *p; - int i; - qboolean bRan; - memset(script, 0, sizeof(script)); - if (item && s && s[0]) { - Q_strcat(script, 1024, s); - p = script; - while (1) { - const char *command; - // expect command then arguments, ; ends command, NULL ends script - if (!String_Parse(&p, &command)) { - return; - } +void Item_RunScript(itemDef_t *item, const char *s) +{ + char script[2048], *p; + int i; + qboolean bRan; + + script[0] = 0; + + if (item && s && s[0]) + { + Q_strcat(script, 2048, s); + p = script; + + while (1) + { + const char *command; - if (command[0] == ';' && command[1] == '\0') { - continue; - } + // expect command then arguments, ; ends command, NULL ends script + if (!String_Parse(&p, &command)) + { + return; + } - bRan = qfalse; - for (i = 0; i < scriptCommandCount; i++) { - if (Q_stricmp(command, commandList[i].name) == 0) { - (commandList[i].handler(item, &p)); - bRan = qtrue; - break; - } - } - // not in our auto list, pass to handler - if (!bRan) { - DC->runScript(&p); - } - } - } + if (command[0] == ';' && command[1] == '\0') + { + continue; + } + + bRan = qfalse; + for (i = 0; i < scriptCommandCount; i++) + { + if (Q_stricmp(command, commandList[i].name) == 0) + { + // Allow a script command to stop processing the script + if ( !commandList[i].handler(item, &p) ) + { + return; + } + + bRan = qtrue; + break; + } + } + + // not in our auto list, pass to handler + if (!bRan) + { + DC->runScript(&p); + } + } + } } qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag) { - char script[1024], *p; - memset(script, 0, sizeof(script)); + char script[2048], *p; if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) { - char buff[1024]; + char buff[2048]; DC->getCVarString(item->cvarTest, buff, sizeof(buff)); - Q_strcat(script, 1024, item->enableCvar); + Q_strncpyz(script, item->enableCvar, 2048); p = script; while (1) { const char *val; @@ -1537,7 +1755,7 @@ int Item_TextScroll_MaxScroll ( itemDef_t *item ) textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData; int count = scrollPtr->lineCount; - int max = count - (item->window.rect.h / scrollPtr->lineHeight) + 1; + int max = count - (int)(item->window.rect.h / scrollPtr->lineHeight) + 1; if (max < 0) { @@ -2213,8 +2431,14 @@ qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolea } lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY; if (item->cursorPos != listPtr->cursorPos) { + int prePos = item->cursorPos; + item->cursorPos = listPtr->cursorPos; - DC->feederSelection(item->special, item->cursorPos); + + if (!DC->feederSelection(item->special, item->cursorPos)) + { + item->cursorPos = listPtr->cursorPos = prePos; + } } } return qtrue; @@ -2303,7 +2527,7 @@ int Item_Multi_CountSettings(itemDef_t *item) { } int Item_Multi_FindCvarByValue(itemDef_t *item) { - char buff[1024]; + char buff[2048]; float value = 0; int i; multiDef_t *multiPtr = (multiDef_t*)item->typeData; @@ -2329,7 +2553,7 @@ int Item_Multi_FindCvarByValue(itemDef_t *item) { } const char *Item_Multi_Setting(itemDef_t *item) { - char buff[1024]; + char buff[2048]; float value = 0; int i; multiDef_t *multiPtr = (multiDef_t*)item->typeData; @@ -2383,14 +2607,14 @@ qboolean Item_Multi_HandleKey(itemDef_t *item, int key) { } qboolean Item_TextField_HandleKey(itemDef_t *item, int key) { - char buff[1024]; + char buff[2048]; int len; itemDef_t *newItem = NULL; editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData; if (item->cvar) { - memset(buff, 0, sizeof(buff)); + buff[0] = 0; DC->getCVarString(item->cvar, buff, sizeof(buff)); len = strlen(buff); if (editPtr->maxChars && len > editPtr->maxChars) { @@ -2439,6 +2663,16 @@ qboolean Item_TextField_HandleKey(itemDef_t *item, int key) { buff[item->cursorPos] = key; + //rww - nul-terminate! + if (item->cursorPos+1 < 2048) + { + buff[item->cursorPos+1] = 0; + } + else + { + buff[item->cursorPos] = 0; + } + DC->setCVar(item->cvar, buff); if (item->cursorPos < len + 1) { @@ -3155,6 +3389,7 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) { it.parent = menu; Item_RunScript(&it, menu->onESC); } + g_waitingForKey = qfalse; break; case K_TAB: case K_KP_DOWNARROW: @@ -3307,9 +3542,9 @@ void Item_TextColor(itemDef_t *item, vec4_t *newColor) { } void Item_Text_AutoWrapped_Paint(itemDef_t *item) { - char text[1024]; + char text[2048]; const char *p, *textPtr, *newLinePtr; - char buff[1024]; + char buff[2048]; int width, height, len, textWidth, newLine, newLineWidth; float y; vec4_t color; @@ -3543,10 +3778,11 @@ void Item_TextField_Paint(itemDef_t *item) { // DC->drawText(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, 0, editPtr->maxPaintChars, item->textStyle); DC->drawText(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textscale, newColor, buff + editPtr->paintOffset, 0, editPtr->maxPaintChars, item->textStyle,item->iMenuFont); } - } void Item_YesNo_Paint(itemDef_t *item) { + char sYES[20]; + char sNO[20]; vec4_t newColor, lowLight; float value; menuDef_t *parent = (menuDef_t*)item->parent; @@ -3563,13 +3799,17 @@ void Item_YesNo_Paint(itemDef_t *item) { memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t)); } + + trap_SP_GetStringTextString("MENUS0_YES",sYES, sizeof(sYES)); + trap_SP_GetStringTextString("MENUS0_NO", sNO, sizeof(sNO)); + if (item->text) { Item_Text_Paint(item); -// DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle); - DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle,item->iMenuFont); +// DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? sYES : sNO, 0, 0, item->textStyle); + DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? sYES : sNO, 0, 0, item->textStyle,item->iMenuFont); } else { -// DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle); - DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0, item->textStyle,item->iMenuFont); +// DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? sYES : sNO, 0, 0, item->textStyle); + DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? sYES : sNO, 0, 0, item->textStyle,item->iMenuFont); } } @@ -3647,7 +3887,7 @@ static bind_t g_bindings[] = {"weapon 8", '8', -1, -1, -1}, {"weapon 9", '9', -1, -1, -1}, {"weapon 10", '0', -1, -1, -1}, - {"saberAttackCycle", '\\', -1, -1, -1}, + {"saberAttackCycle", 'l', -1, -1, -1}, {"weapon 11", -1, -1, -1, -1}, {"weapon 12", -1, -1, -1, -1}, {"weapon 13", -1, -1, -1, -1}, @@ -3655,9 +3895,9 @@ static bind_t g_bindings[] = {"+altattack", -1, -1, -1, -1}, {"+use", -1, -1, -1, -1}, {"engage_duel", 'h', -1, -1, -1}, + {"+taunt", 'u', -1, -1, -1}, {"weapprev", '[', -1, -1, -1}, {"weapnext", ']', -1, -1, -1}, - {"+button3", K_MOUSE3, -1, -1, -1}, {"prevTeamMember", 'w', -1, -1, -1}, {"nextTeamMember", 'r', -1, -1, -1}, {"nextOrder", 't', -1, -1, -1}, @@ -3677,8 +3917,8 @@ static bind_t g_bindings[] = {"tauntTaunt", -1, -1, -1, -1}, {"tauntDeathInsult",-1, -1, -1, -1}, {"tauntGauntlet", -1, -1, -1, -1}, - {"scoresUp", K_KP_PGUP, -1, -1, -1}, - {"scoresDown", K_KP_PGDN, -1, -1, -1}, + {"scoresUp", K_INS, -1, -1, -1}, + {"scoresDown", K_DEL, -1, -1, -1}, {"messagemode", -1, -1, -1, -1}, {"messagemode2", -1, -1, -1, -1}, {"messagemode3", -1, -1, -1, -1}, @@ -3790,7 +4030,6 @@ void Controls_SetConfig(qboolean restart) // iterate each command, get its numeric binding for (i=0; i < g_bindCount; i++) { - if (g_bindings[i].bind1 != -1) { DC->setBinding( g_bindings[i].bind1, g_bindings[i].command ); @@ -3812,35 +4051,11 @@ void Controls_SetConfig(qboolean restart) //trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue ); //trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue ); //trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue ); - DC->executeText(EXEC_APPEND, "in_restart\n"); - //trap_Cmd_ExecuteText( EXEC_APPEND, "in_restart\n" ); +// +// DC->executeText(EXEC_APPEND, "in_restart\n"); +// ^--this is bad, it shows the cursor during map load, if you need to, add it as an exec cmd to use_joy or something. } -/* -================= -Controls_SetDefaults -================= -*/ -void Controls_SetDefaults( void ) -{ - int i; - - // iterate each command, set its default binding - for (i=0; i < g_bindCount; i++) - { - g_bindings[i].bind1 = g_bindings[i].defaultbind1; - g_bindings[i].bind2 = g_bindings[i].defaultbind2; - } - - //s_controls.invertmouse.curvalue = Controls_GetCvarDefault( "m_pitch" ) < 0; - //s_controls.smoothmouse.curvalue = Controls_GetCvarDefault( "m_filter" ); - //s_controls.alwaysrun.curvalue = Controls_GetCvarDefault( "cl_run" ); - //s_controls.autoswitch.curvalue = Controls_GetCvarDefault( "cg_autoswitch" ); - //s_controls.sensitivity.curvalue = Controls_GetCvarDefault( "sensitivity" ); - //s_controls.joyenable.curvalue = Controls_GetCvarDefault( "in_joystick" ); - //s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" ); - //s_controls.freelook.curvalue = Controls_GetCvarDefault( "cl_freelook" ); -} int BindingIDFromName(const char *name) { int i; @@ -3857,7 +4072,9 @@ char g_nameBind1[32]; char g_nameBind2[32]; void BindingFromName(const char *cvar) { - int i, b1, b2; + int i, b1, b2; + char sOR[32]; + // iterate each command, set its default binding for (i=0; i < g_bindCount; i++) @@ -3875,7 +4092,10 @@ void BindingFromName(const char *cvar) { { DC->keynumToStringBuf( b2, g_nameBind2, 32 ); Q_strupr(g_nameBind2); - strcat( g_nameBind1, " or " ); + + trap_SP_GetStringTextString("MENUS3_KEYBIND_OR",sOR, sizeof(sOR)); + + strcat( g_nameBind1, va(" %s ",sOR)); strcat( g_nameBind1, g_nameBind2 ); } return; @@ -3921,6 +4141,10 @@ void Item_Bind_Paint(itemDef_t *item) vec4_t newColor, lowLight; float value; int maxChars = 0; + float textScale,textWidth; + int textHeight,yAdj,startingXPos; + + menuDef_t *parent = (menuDef_t*)item->parent; editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData; if (editPtr) @@ -3957,7 +4181,27 @@ void Item_Bind_Paint(itemDef_t *item) { Item_Text_Paint(item); BindingFromName(item->cvar); - DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, g_nameBind1, 0, maxChars, item->textStyle,item->iMenuFont); + + // If the text runs past the limit bring the scale down until it fits. + textScale = item->textscale; + textWidth = DC->textWidth(g_nameBind1,(float) textScale, item->iMenuFont); + startingXPos = (item->textRect.x + item->textRect.w + 8); + + while ((startingXPos + textWidth) >= SCREEN_WIDTH) + { + textScale -= .05f; + textWidth = DC->textWidth(g_nameBind1,(float) textScale, item->iMenuFont); + } + + // Try to adjust it's y placement if the scale has changed. + yAdj = 0; + if (textScale != item->textscale) + { + textHeight = DC->textHeight(g_nameBind1, item->textscale, item->iMenuFont); + yAdj = textHeight - DC->textHeight(g_nameBind1, textScale, item->iMenuFont); + } + + DC->drawText(startingXPos, item->textRect.y + yAdj, textScale, newColor, g_nameBind1, 0, maxChars, item->textStyle,item->iMenuFont); } else { @@ -3973,9 +4217,18 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) { int id; int i; - if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey) + if (key == K_MOUSE1 && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey) { - if (down && (key == K_MOUSE1 || key == K_ENTER)) { + if (down) { + g_waitingForKey = qtrue; + g_bindItem = item; + } + return qtrue; + } + else if (key == K_ENTER && !g_waitingForKey) + { + if (down) + { g_waitingForKey = qtrue; g_bindItem = item; } @@ -3984,7 +4237,7 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) { else { if (!g_waitingForKey || g_bindItem == NULL) { - return qtrue; + return qfalse; } if (key & K_CHAR_FLAG) { @@ -3999,7 +4252,18 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) { case K_BACKSPACE: id = BindingIDFromName(item->cvar); - if (id != -1) { + if (id != -1) + { + if ( g_bindings[id].bind1 != -1 ) + { + DC->setBinding ( g_bindings[id].bind1, "" ); + } + + if ( g_bindings[id].bind2 != -1 ) + { + DC->setBinding ( g_bindings[id].bind2, "" ); + } + g_bindings[id].bind1 = -1; g_bindings[id].bind2 = -1; } @@ -4349,6 +4613,7 @@ void Item_ListBox_Paint(itemDef_t *item) { if (listPtr->numColumns > 0) { int j; + for (j = 0; j < listPtr->numColumns; j++) { text = DC->feederItemText(item->special, i, j, &optionalImage); if (optionalImage >= 0) { @@ -4466,36 +4731,6 @@ void Item_Paint(itemDef_t *item) return; } - if (item->window.flags & WINDOW_MOUSEOVER) - { - if (item->descText) - { - textWidth = DC->textWidth(item->descText,(float) 0.7f, FONT_MEDIUM); - - if (parent->descAlignment == ITEM_ALIGN_RIGHT) - { - xPos = parent->descX - textWidth; // Right justify - } - else if (parent->descAlignment == ITEM_ALIGN_CENTER) - { - xPos = parent->descX - (textWidth/2); // Center justify - } - else // Left justify - { - xPos = parent->descX; - } - - Item_TextColor(item, &color); - - if (!parent->descScale) - { - parent->descScale = 1; - } - - DC->drawText(xPos, parent->descY, (float) parent->descScale, parent->descColor, item->descText, 0, 0, item->textStyle, FONT_MEDIUM); - } - } - if (item->window.flags & WINDOW_ORBITING) { if (DC->realTime > item->window.nextTime) @@ -4619,9 +4854,72 @@ void Item_Paint(itemDef_t *item) } - if (!(item->window.flags & WINDOW_VISIBLE)) { - return; - } + if (!(item->window.flags & WINDOW_VISIBLE)) + { + return; + } + + if ((item->window.flags & WINDOW_MOUSEOVER)) + { + if (item->descText && !Display_KeyBindPending()) + { + // Make DOUBLY sure that this item should have desctext. + if (!Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) + { // It isn't something that should, because it isn't live anymore. + item->window.flags &= ~WINDOW_MOUSEOVER; + } + else + { // Draw the desctext + const char *textPtr = item->descText; + + Item_TextColor(item, &color); + + {// stupid C language + float fDescScale = parent->descScale ? parent->descScale : 1; + float fDescScaleCopy = fDescScale; + int iYadj = 0; + while (1) + { + textWidth = DC->textWidth(textPtr,fDescScale, FONT_MEDIUM); + + if (parent->descAlignment == ITEM_ALIGN_RIGHT) + { + xPos = parent->descX - textWidth; // Right justify + } + else if (parent->descAlignment == ITEM_ALIGN_CENTER) + { + xPos = parent->descX - (textWidth/2); // Center justify + } + else // Left justify + { + xPos = parent->descX; + } + + if (parent->descAlignment == ITEM_ALIGN_CENTER) + { + // only this one will auto-shrink the scale until we eventually fit... + // + if (xPos + textWidth > (SCREEN_WIDTH-4)) { + fDescScale -= 0.001f; + continue; + } + } + + // Try to adjust it's y placement if the scale has changed... + // + if (fDescScale != fDescScaleCopy) + { + int iOriginalTextHeight = DC->textHeight(textPtr, fDescScaleCopy, FONT_MEDIUM); + iYadj = iOriginalTextHeight - DC->textHeight(textPtr, fDescScale, FONT_MEDIUM); + } + + DC->drawText(xPos, parent->descY + iYadj, fDescScale, parent->descColor, textPtr, 0, 0, item->textStyle, FONT_MEDIUM); + break; + } + } + } + } + } // paint the rect first.. Window_Paint(&item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle); @@ -4781,7 +5079,11 @@ menuDef_t *Menus_ActivateByName(const char *p) { } } Display_CloseCinematics(); - return m; + + // Want to handle a mouse move on the new menu in case your already over an item + Menu_HandleMouseMove ( m, DC->cursorx, DC->cursory ); + + return m; } @@ -5630,23 +5932,6 @@ qboolean ItemParse_action( itemDef_t *item, int handle ) { return qtrue; } -qboolean ItemParse_stripedFile( itemDef_t *item, int handle ) { - - char *tempStr; - - if (!PC_String_Parse(handle, (const char **)&tempStr)) { - return qfalse; - } - - Q_strncpyz( (char *) DC->Assets.stripedFile, tempStr, sizeof(DC->Assets.stripedFile) ); - - trap_SP_Register(DC->Assets.stripedFile); - - Menu_currentStipEdFile(DC->Assets.stripedFile); - - return qtrue; -} - qboolean ItemParse_special( itemDef_t *item, int handle ) { if (!PC_Float_Parse(handle, &item->special)) { return qfalse; @@ -5661,18 +5946,32 @@ qboolean ItemParse_cvarTest( itemDef_t *item, int handle ) { return qtrue; } -qboolean ItemParse_cvar( itemDef_t *item, int handle ) { - editFieldDef_t *editPtr; - +qboolean ItemParse_cvar( itemDef_t *item, int handle ) +{ Item_ValidateTypeData(item); - if (!PC_String_Parse(handle, &item->cvar)) { + if (!PC_String_Parse(handle, &item->cvar)) + { return qfalse; } - if (item->typeData) { - editPtr = (editFieldDef_t*)item->typeData; - editPtr->minVal = -1; - editPtr->maxVal = -1; - editPtr->defVal = -1; + + if ( item->typeData) + { + editFieldDef_t *editPtr; + + switch ( item->type ) + { + case ITEM_TYPE_EDITFIELD: + case ITEM_TYPE_NUMERICFIELD: + case ITEM_TYPE_YESNO: + case ITEM_TYPE_BIND: + case ITEM_TYPE_SLIDER: + case ITEM_TYPE_TEXT: + editPtr = (editFieldDef_t*)item->typeData; + editPtr->minVal = -1; + editPtr->maxVal = -1; + editPtr->defVal = -1; + break; + } } return qtrue; } @@ -5796,24 +6095,34 @@ qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) { pass = 0; while ( 1 ) { - if (!trap_PC_ReadToken(handle, &token)) { + char* psString; + +// if (!trap_PC_ReadToken(handle, &token)) { +// PC_SourceError(handle, "end of file inside menu item\n"); +// return qfalse; +// } + if (!PC_String_Parse(handle, (const char **)&psString)) { PC_SourceError(handle, "end of file inside menu item\n"); return qfalse; } - if (*token.string == '}') { - return qtrue; - } + //a normal StringAlloc ptr + if ((int)psString > 0) + { + if (*psString == '}') { + return qtrue; + } - if (*token.string == ',' || *token.string == ';') { - continue; + if (*psString == ',' || *psString == ';') { + continue; + } } if (pass == 0) { - multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string); + multiPtr->cvarList[multiPtr->count] = psString; pass = 1; } else { - multiPtr->cvarStr[multiPtr->count] = String_Alloc(token.string); + multiPtr->cvarStr[multiPtr->count] = psString; pass = 0; multiPtr->count++; if (multiPtr->count >= MAX_MULTI_CVARS) { @@ -5825,44 +6134,64 @@ qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) { return qfalse; // bk001205 - LCC missing return value } -qboolean ItemParse_cvarFloatList( itemDef_t *item, int handle ) { +qboolean ItemParse_cvarFloatList( itemDef_t *item, int handle ) +{ pc_token_t token; multiDef_t *multiPtr; Item_ValidateTypeData(item); if (!item->typeData) + { return qfalse; + } + multiPtr = (multiDef_t*)item->typeData; multiPtr->count = 0; multiPtr->strDef = qfalse; if (!trap_PC_ReadToken(handle, &token)) + { return qfalse; - if (*token.string != '{') { + } + + if (*token.string != '{') + { return qfalse; } - while ( 1 ) { - if (!trap_PC_ReadToken(handle, &token)) { + while ( 1 ) + { + char* string; + + if ( !PC_String_Parse ( handle, (const char **)&string ) ) + { PC_SourceError(handle, "end of file inside menu item\n"); return qfalse; } + + //a normal StringAlloc ptr + if ((int)string > 0) + { + if (*string == '}') + { + return qtrue; + } - if (*token.string == '}') { - return qtrue; + if (*string == ',' || *string == ';') + { + continue; + } } - if (*token.string == ',' || *token.string == ';') { - continue; - } - - multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string); - if (!PC_Float_Parse(handle, &multiPtr->cvarValue[multiPtr->count])) { + multiPtr->cvarList[multiPtr->count] = string; + if (!PC_Float_Parse(handle, &multiPtr->cvarValue[multiPtr->count])) + { return qfalse; } multiPtr->count++; - if (multiPtr->count >= MAX_MULTI_CVARS) { + if (multiPtr->count >= MAX_MULTI_CVARS) + { return qfalse; } @@ -6000,7 +6329,6 @@ keywordHash_t itemParseKeywords[] = { {"rect", ItemParse_rect, NULL }, {"showCvar", ItemParse_showCvar, NULL }, {"special", ItemParse_special, NULL }, - {"stripedFile", ItemParse_stripedFile, NULL }, {"style", ItemParse_style, NULL }, {"text", ItemParse_text, NULL }, {"textalign", ItemParse_textalign, NULL }, @@ -6079,73 +6407,73 @@ qboolean Item_Parse(int handle, itemDef_t *item) { static void Item_TextScroll_BuildLines ( itemDef_t* item ) { textScrollDef_t* scrollPtr = (textScrollDef_t*) item->typeData; - int len; int width; char* lineStart; + char* lineEnd; + float w; + float cw; scrollPtr->lineCount = 0; - len = strlen ( item->text ); width = scrollPtr->maxLineChars; lineStart = (char*)item->text; + lineEnd = lineStart; + w = 0; // Keep going as long as there are more lines - while ( len > width && scrollPtr->lineCount < MAX_TEXTSCROLL_LINES ) + while ( scrollPtr->lineCount < MAX_TEXTSCROLL_LINES ) { - char* lineEnd; - - // Carriage returns break the line earlier than the width - lineEnd = lineStart; - while ( lineEnd - lineStart < width && *lineEnd ) + // End of the road + if ( *lineEnd == '\0') { - if ( *lineEnd == '\n' ) + if ( lineStart < lineEnd ) { - break; + scrollPtr->lines[ scrollPtr->lineCount++ ] = lineStart; } - lineEnd++; + break; } - // If a wasnt found then start with the width - if ( !lineEnd || *lineEnd != '\n' ) + // Force a line end if its a '\n' + else if ( *lineEnd == '\n' ) { - // Start with a position right at the width and then backtrack until we - // find a space. - lineEnd = lineStart + width; + *lineEnd = '\0'; + scrollPtr->lines[ scrollPtr->lineCount++ ] = lineStart; + lineStart = lineEnd + 1; + lineEnd = lineStart; + w = 0; + continue; + } + + // Get the current character width + cw = DC->textWidth ( va("%c", *lineEnd), item->textscale, item->iMenuFont ); + + // Past the end of the boundary? + if ( w + cw > (item->window.rect.w - SCROLLBAR_SIZE - 10) ) + { + // Past the end so backtrack to the word boundary while ( *lineEnd != ' ' && *lineEnd != '\t' && lineEnd > lineStart ) { lineEnd--; - } - } + } - // This probably isnt too graceful, but if a line has a word that is longer - // than the width in characters then the word will be skipped all together. - if ( lineEnd >= lineStart ) - { - // throw down a null terminator *lineEnd = '\0'; - - // Add the line to the list, leave any trailing spaces scrollPtr->lines[ scrollPtr->lineCount++ ] = lineStart; - - // Skip past the space that we landed on - lineEnd++; // Skip any whitespaces + lineEnd++; while ( (*lineEnd == ' ' || *lineEnd == '\t') && *lineEnd ) { lineEnd++; } - // Subtract out the number of characters used in the last line - len -= ( lineEnd - lineStart); - lineStart = lineEnd; + w = 0; + } + else + { + w += cw; + lineEnd++; } - } - - if ( len && scrollPtr->lineCount < MAX_TEXTSCROLL_LINES ) - { - scrollPtr->lines[ scrollPtr->lineCount++ ] = lineStart; } } @@ -6174,20 +6502,6 @@ void Item_InitControls(itemDef_t *item) break; } - - case ITEM_TYPE_TEXTSCROLL: - { - textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData; - if ( scrollPtr ) - { - scrollPtr->startPos = 0; - scrollPtr->endPos = 0; - } - - Item_TextScroll_BuildLines ( item ); - - break; - } } } @@ -6215,7 +6529,7 @@ qboolean MenuParse_name( itemDef_t *item, int handle ) { if (!PC_String_Parse(handle, &menu->window.name)) { return qfalse; } - if (Q_stricmp(menu->window.name, "mainMenu") == 0) { + if (Q_stricmp(menu->window.name, "main") == 0) { // default main as having focus //menu->window.flags |= WINDOW_HASFOCUS; } @@ -6634,7 +6948,6 @@ keywordHash_t menuParseKeywords[] = { {"popup", MenuParse_popup, NULL }, {"rect", MenuParse_rect, NULL }, {"soundLoop", MenuParse_soundLoop, NULL }, - {"stripedFile", MenuParse_stripedFile, NULL }, {"style", MenuParse_style, NULL }, {"visible", MenuParse_visible, NULL }, {0, 0, 0 } @@ -6672,8 +6985,6 @@ qboolean Menu_Parse(int handle, menuDef_t *menu) { } while ( 1 ) { - - memset(&token, 0, sizeof(pc_token_t)); if (!trap_PC_ReadToken(handle, &token)) { PC_SourceError(handle, "end of file inside menu\n"); return qfalse; @@ -6880,31 +7191,3 @@ static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y) { } return qfalse; } - -/* -================= -MenuParse_stripedFile -================= -*/ -qboolean MenuParse_stripedFile( itemDef_t *item, int handle) -{ - char *tempStr; - - if (!PC_String_Parse(handle, (const char **)&tempStr)) - { - return qfalse; - } - - Q_strncpyz( (char *) stripedFile, tempStr, sizeof(stripedFile) ); - - trap_SP_Register(stripedFile); - - return qtrue; - -} - - -void Menu_currentStipEdFile(char *stripEdFile) -{ - memcpy(stripedFile, stripEdFile, sizeof(stripedFile)); -} diff --git a/CODE-mp/ui/ui_shared.h b/CODE-mp/ui/ui_shared.h index df33718..63845a7 100644 --- a/CODE-mp/ui/ui_shared.h +++ b/CODE-mp/ui/ui_shared.h @@ -14,7 +14,7 @@ #define MAX_MENUDEFFILE 4096 #define MAX_MENUFILE 32768 #define MAX_MENUS 64 -#define MAX_MENUITEMS 128 +#define MAX_MENUITEMS 256 #define MAX_COLOR_RANGES 10 #define MAX_OPEN_MENUS 16 #define MAX_TEXTSCROLL_LINES 256 @@ -78,8 +78,8 @@ #define ASSET_SCROLLBAR_ARROWLEFT "gfx/menus/scrollbar_arrow_left.tga" #define ASSET_SCROLLBAR_ARROWRIGHT "gfx/menus/scrollbar_arrow_right.tga" #define ASSET_SCROLL_THUMB "gfx/menus/scrollbar_thumb.tga" -#define ASSET_SLIDER_BAR "ui/assets/slider2.tga" -#define ASSET_SLIDER_THUMB "ui/assets/sliderbutt_1.tga" +#define ASSET_SLIDER_BAR "menu/new/slider" +#define ASSET_SLIDER_THUMB "menu/new/sliderthumb" #define SCROLLBAR_SIZE 16.0 #define SLIDER_WIDTH 96.0 #define SLIDER_HEIGHT 16.0 @@ -316,7 +316,6 @@ typedef struct { vec4_t shadowColor; float shadowFadeClamp; qboolean fontRegistered; - char stripedFile[MAX_STRING_CHARS]; // player settings qhandle_t fxBasePic; @@ -325,9 +324,10 @@ typedef struct { } cachedAssets_t; -typedef struct { - const char *name; - void (*handler) (itemDef_t *item, char** args); +typedef struct +{ + const char *name; + qboolean (*handler) (itemDef_t *item, char** args); } commandDef_t; typedef struct { @@ -359,6 +359,7 @@ typedef struct { float (*getValue) (int ownerDraw); qboolean (*ownerDrawVisible) (int flags); void (*runScript)(char **p); + qboolean (*deferScript)(char **p); void (*getTeamColor)(vec4_t *color); void (*getCVarString)(const char *cvar, char *buffer, int bufsize); float (*getCVarValue)(const char *cvar); @@ -371,7 +372,7 @@ typedef struct { int (*feederCount)(float feederID); const char *(*feederItemText)(float feederID, int index, int column, qhandle_t *handle); qhandle_t (*feederItemImage)(float feederID, int index); - void (*feederSelection)(float feederID, int index); + qboolean (*feederSelection)(float feederID, int index); void (*keynumToStringBuf)( int keynum, char *buf, int buflen ); void (*getBindingBuf)( int keynum, char *buf, int buflen ); void (*setBinding)( int keynum, const char *binding ); @@ -461,7 +462,6 @@ qboolean UI_OutOfMemory(); void Controls_GetConfig( void ); void Controls_SetConfig(qboolean restart); -void Controls_SetDefaults( void ); int trap_PC_AddGlobalDefine ( char *define ); int trap_PC_LoadSource ( const char *filename ); @@ -471,8 +471,7 @@ int trap_PC_SourceFileAndLine ( int handle, char *filename, int *line ); int trap_PC_LoadGlobalDefines ( const char* filename ); void trap_PC_RemoveAllGlobalDefines ( void ); -void trap_SP_RegisterServer( const char *package ); -void trap_SP_Register(char *file ); -void Menu_currentStipEdFile(char *stripEdFile); +qboolean trap_SP_RegisterServer( const char *package ); +qboolean trap_SP_Register(char *file ); int trap_SP_GetStringTextString(const char *text, char *buffer, int bufferLength); #endif diff --git a/CODE-mp/ui/ui_syscalls.asm b/CODE-mp/ui/ui_syscalls.asm new file mode 100644 index 0000000..42131d4 --- /dev/null +++ b/CODE-mp/ui/ui_syscalls.asm @@ -0,0 +1,114 @@ +code + +equ trap_Print -2 ; UI_PRINT +equ trap_Error -1 ; UI_ERROR +equ trap_Milliseconds -3 ; UI_MILLISECONDS +equ trap_Cvar_Register -51 ; UI_CVAR_REGISTER +equ trap_Cvar_Update -52 ; UI_CVAR_UPDATE +equ trap_Cvar_Set -4 ; UI_CVAR_SET +equ trap_Cvar_VariableValue -5 ; UI_CVAR_VARIABLEVALUE +equ trap_Cvar_VariableStringBuffer -6 ; UI_CVAR_VARIABLESTRINGBUFFER +equ trap_Cvar_SetValue -7 ; UI_CVAR_SETVALUE +equ trap_Cvar_Reset -8 ; UI_CVAR_RESET +equ trap_Cvar_Create -9 ; UI_CVAR_CREATE +equ trap_Cvar_InfoStringBuffer -10 ; UI_CVAR_INFOSTRINGBUFFER +equ trap_Argc -11 ; UI_ARGC +equ trap_Argv -12 ; UI_ARGV +equ trap_Cmd_ExecuteText -13 ; UI_CMD_EXECUTETEXT +equ trap_FS_FOpenFile -14 ; UI_FS_FOPENFILE +equ trap_FS_Read -15 ; UI_FS_READ +equ trap_FS_Write -16 ; UI_FS_WRITE +equ trap_FS_FCloseFile -17 ; UI_FS_FCLOSEFILE +equ trap_FS_GetFileList -18 ; UI_FS_GETFILELIST +equ trap_R_RegisterModel -19 ; UI_R_REGISTERMODEL +equ trap_R_RegisterSkin -20 ; UI_R_REGISTERSKIN +equ trap_R_RegisterFont -57 ; UI_R_REGISTERFONT +equ trap_R_Font_StrLenPixels -58 ; UI_R_FONT_STRLENPIXELS +equ trap_R_Font_StrLenChars -59 ; UI_R_FONT_STRLENCHARS +equ trap_R_Font_HeightPixels -60 ; UI_R_FONT_STRHEIGHTPIXELS +equ trap_R_Font_DrawString -61 ; UI_R_FONT_DRAWSTRING +equ trap_AnyLanguage_ReadCharFromString -62 ; UI_ANYLANGUAGE_READCHARFROMSTRING +equ trap_R_RegisterShaderNoMip -21 ; UI_R_REGISTERSHADERNOMIP +equ trap_R_ClearScene -22 ; UI_R_CLEARSCENE +equ trap_R_AddRefEntityToScene -23 ; UI_R_ADDREFENTITYTOSCENE +equ trap_R_AddPolyToScene -24 ; UI_R_ADDPOLYTOSCENE +equ trap_R_AddLightToScene -25 ; UI_R_ADDLIGHTTOSCENE +equ trap_R_RenderScene -26 ; UI_R_RENDERSCENE +equ trap_R_SetColor -27 ; UI_R_SETCOLOR +equ trap_R_DrawStretchPic -28 ; UI_R_DRAWSTRETCHPIC +equ trap_R_ModelBounds -63 ; UI_R_MODELBOUNDS +equ trap_UpdateScreen -29 ; UI_UPDATESCREEN +equ trap_CM_LerpTag -30 ; UI_CM_LERPTAG +equ trap_S_StartLocalSound -33 ; UI_S_STARTLOCALSOUND +equ trap_S_RegisterSound -32 ; UI_S_REGISTERSOUND +equ trap_Key_KeynumToStringBuf -34 ; UI_KEY_KEYNUMTOSTRINGBUF +equ trap_Key_GetBindingBuf -35 ; UI_KEY_GETBINDINGBUF +equ trap_Key_SetBinding -36 ; UI_KEY_SETBINDING +equ trap_Key_IsDown -37 ; UI_KEY_ISDOWN +equ trap_Key_GetOverstrikeMode -38 ; UI_KEY_GETOVERSTRIKEMODE +equ trap_Key_SetOverstrikeMode -39 ; UI_KEY_SETOVERSTRIKEMODE +equ trap_Key_ClearStates -40 ; UI_KEY_CLEARSTATES +equ trap_Key_GetCatcher -41 ; UI_KEY_GETCATCHER +equ trap_Key_SetCatcher -42 ; UI_KEY_SETCATCHER +equ trap_GetClipboardData -43 ; UI_GETCLIPBOARDDATA +equ trap_GetClientState -45 ; UI_GETCLIENTSTATE +equ trap_GetGlconfig -44 ; UI_GETGLCONFIG +equ trap_GetConfigString -46 ; UI_GETCONFIGSTRING +equ trap_LAN_GetServerCount -74 ; UI_LAN_GETSERVERCOUNT +equ trap_LAN_GetServerAddressString -75 ; UI_LAN_GETSERVERADDRESSSTRING +equ trap_LAN_GetServerInfo -76 ; UI_LAN_GETSERVERINFO +equ trap_LAN_GetServerPing -91 ; UI_LAN_GETSERVERPING +equ trap_LAN_GetPingQueueCount -47 ; UI_LAN_GETPINGQUEUECOUNT +equ trap_LAN_ServerStatus -90 ; UI_LAN_SERVERSTATUS +equ trap_LAN_SaveCachedServers -81 ; UI_LAN_SAVECACHEDSERVERS +equ trap_LAN_LoadCachedServers -80 ; UI_LAN_LOADCACHEDSERVERS +equ trap_LAN_ResetPings -79 ; UI_LAN_RESETPINGS +equ trap_LAN_ClearPing -48 ; UI_LAN_CLEARPING +equ trap_LAN_GetPing -49 ; UI_LAN_GETPING +equ trap_LAN_GetPingInfo -50 ; UI_LAN_GETPINGINFO +equ trap_LAN_MarkServerVisible -77 ; UI_LAN_MARKSERVERVISIBLE +equ trap_LAN_ServerIsVisible -92 ; UI_LAN_SERVERISVISIBLE +equ trap_LAN_UpdateVisiblePings -78 ; UI_LAN_UPDATEVISIBLEPINGS +equ trap_LAN_AddServer -82 ; UI_LAN_ADDSERVER +equ trap_LAN_RemoveServer -83 ; UI_LAN_REMOVESERVER +equ trap_LAN_CompareServers -93 ; UI_LAN_COMPARESERVERS +equ trap_MemoryRemaining -53 ; UI_MEMORY_REMAINING +equ trap_GetCDKey -54 ; UI_GET_CDKEY +equ trap_SetCDKey -55 ; UI_SET_CDKEY +equ trap_VerifyCDKey -56 ; UI_VERIFY_CDKEY +equ trap_PC_AddGlobalDefine -64 ; UI_PC_ADD_GLOBAL_DEFINE +equ trap_PC_LoadSource -65 ; UI_PC_LOAD_SOURCE +equ trap_PC_FreeSource -66 ; UI_PC_FREE_SOURCE +equ trap_PC_ReadToken -67 ; UI_PC_READ_TOKEN +equ trap_PC_SourceFileAndLine -68 ; UI_PC_SOURCE_FILE_AND_LINE +equ trap_PC_LoadGlobalDefines -69 ; UI_PC_LOAD_GLOBAL_DEFINES +equ trap_PC_RemoveAllGlobalDefines -70 ; UI_PC_REMOVE_ALL_GLOBAL_DEFINES +equ trap_S_StopBackgroundTrack -71 ; UI_S_STOPBACKGROUNDTRACK +equ trap_S_StartBackgroundTrack -72 ; UI_S_STARTBACKGROUNDTRACK +equ trap_RealTime -73 ; UI_REAL_TIME +equ trap_CIN_PlayCinematic -84 ; UI_CIN_PLAYCINEMATIC +equ trap_CIN_StopCinematic -85 ; UI_CIN_STOPCINEMATIC +equ trap_CIN_RunCinematic -86 ; UI_CIN_RUNCINEMATIC +equ trap_CIN_DrawCinematic -87 ; UI_CIN_DRAWCINEMATIC +equ trap_CIN_SetExtents -88 ; UI_CIN_SETEXTENTS +equ trap_R_RemapShader -89 ; UI_R_REMAP_SHADER +equ trap_SP_Register -201 ; UI_SP_REGISTER +equ trap_SP_GetStringTextString -202 ; UI_SP_GETSTRINGTEXTSTRING +equ trap_G2API_SetBoneAngles -203 ; UI_G2_ANGLEOVERRIDE + + +; hardcoded functions +equ memset -101 ; UI_MEMSET +equ memcpy -102 ; UI_MEMCPY +equ strncpy -103 ; UI_STRNCPY +equ sin -104 ; UI_SIN +equ cos -105 ; UI_COS +equ atan2 -106 ; UI_ATAN2 +equ sqrt -107 ; UI_SQRT +equ matrixmultiply -116 ; UI_MATRIXMULTIPLY +equ anglevectors -109 ; UI_ANGLEVECTORS +equ perpendicularvector -110 ; UI_PERPENDICULARVECTOR +equ floor -108 ; UI_FLOOR +equ ceil -111 ; UI_CEIL +equ acos -114 ; UI_ACOS +equ asin -115 ; UI_ASIN diff --git a/CODE-mp/ui/ui_syscalls.c b/CODE-mp/ui/ui_syscalls.c index 1815354..0bd7e8e 100644 --- a/CODE-mp/ui/ui_syscalls.c +++ b/CODE-mp/ui/ui_syscalls.c @@ -409,9 +409,9 @@ void trap_R_RemapShader( const char *oldShader, const char *newShader, const cha syscall( UI_R_REMAP_SHADER, oldShader, newShader, timeOffset ); } -void trap_SP_Register(char *file ) +qboolean trap_SP_Register(char *file ) { - syscall( UI_SP_REGISTER,file ); + return syscall( UI_SP_REGISTER,file ); } int trap_SP_GetStringTextString(const char *text, char *buffer, int bufferLength) diff --git a/CODE-mp/ui/vssver.scc b/CODE-mp/ui/vssver.scc new file mode 100644 index 0000000..1a518eb Binary files /dev/null and b/CODE-mp/ui/vssver.scc differ diff --git a/CODE-mp/unix/ftol.nasm b/CODE-mp/unix/ftol.nasm new file mode 100644 index 0000000..48437f3 --- /dev/null +++ b/CODE-mp/unix/ftol.nasm @@ -0,0 +1,131 @@ +; +; qftol -- fast floating point to long conversion. +; + +segment .data + +temp dd 0.0 +fpucw dd 0 + +; Precision Control Field , 2 bits / 0x0300 +; PC24 0x0000 Single precision (24 bits). +; PC53 0x0200 Double precision (53 bits). +; PC64 0x0300 Extended precision (64 bits). + +; Rounding Control Field, 2 bits / 0x0C00 +; RCN 0x0000 Rounding to nearest (even). +; RCD 0x0400 Rounding down (directed, minus). +; RCU 0x0800 Rounding up (directed plus). +; RC0 0x0C00 Rounding towards zero (chop mode). + + +; rounding towards nearest (even) +cw027F dd 0x027F ; double precision +cw037F dd 0x037F ; extended precision + +; rounding towards zero (chop mode) +cw0E7F dd 0x0E7F ; double precision +cw0F7F dd 0x0F7F ; extended precision + + +segment .text + +; +; int qftol( void ) - default control word +; + +global qftol + +qftol: + fistp dword [temp] + mov eax, [temp] + ret + + +; +; int qftol027F( void ) - DirectX FPU +; + +global qftol027F + +qftol027F: + fnstcw [fpucw] + fldcw [cw027F] + fistp dword [temp] + fldcw [fpucw] + mov eax, [temp] + ret + +; +; int qftol037F( void ) - Linux FPU +; + +global qftol037F + +qftol037F: + fnstcw [fpucw] + fldcw [cw037F] + fistp dword [temp] + fldcw [fpucw] + mov eax, [temp] + ret + + +; +; int qftol0F7F( void ) - ANSI +; + +global qftol0F7F + +qftol0F7F: + fnstcw [fpucw] + fldcw [cw0F7F] + fistp dword [temp] + fldcw [fpucw] + mov eax, [temp] + ret + +; +; int qftol0E7F( void ) +; + +global qftol0E7F + +qftol0E7F: + fnstcw [fpucw] + fldcw [cw0E7F] + fistp dword [temp] + fldcw [fpucw] + mov eax, [temp] + ret + + + +; +; long Q_ftol( float q ) +; + +global Q_ftol + +Q_ftol: + fld dword [esp+4] + fistp dword [temp] + mov eax, [temp] + ret + + +; +; long qftol0F7F( float q ) - Linux FPU +; + +global Q_ftol0F7F + +Q_ftol0F7F: + fnstcw [fpucw] + fld dword [esp+4] + fldcw [cw0F7F] + fistp dword [temp] + fldcw [fpucw] + mov eax, [temp] + ret + diff --git a/CODE-mp/unix/linux_common.c b/CODE-mp/unix/linux_common.c new file mode 100644 index 0000000..042e3b1 --- /dev/null +++ b/CODE-mp/unix/linux_common.c @@ -0,0 +1,323 @@ +/** + * GAS syntax equivalents of the MSVC asm memory calls in common.c + * + * The following changes have been made to the asm: + * 1. Registers are loaded by the inline asm arguments when possible + * 2. Labels have been changed to local label format (0,1,etc.) to allow inlining + * + * HISTORY: + * AH - Created on 08 Dec 2000 + */ + +#include // AH - for size_t +#include + +// bk001207 - we need something under Linux, too. Mac? +#if 1 // defined(C_ONLY) // bk010102 - dedicated? +void Com_Memcpy (void* dest, const void* src, const size_t count) { + memcpy(dest, src, count); +} + +void Com_Memset (void* dest, const int val, const size_t count) { + memset(dest, val, count); +} + +#else + +typedef enum { + PRE_READ, // prefetch assuming that buffer is used for reading only + PRE_WRITE, // prefetch assuming that buffer is used for writing only + PRE_READ_WRITE // prefetch assuming that buffer is used for both reading and writing +} e_prefetch; + +void Com_Prefetch (const void *s, const unsigned int bytes, e_prefetch type); + +void _copyDWord (unsigned int* dest, const unsigned int constant, const unsigned int count) { + // MMX version not used on standard Pentium MMX + // because the dword version is faster (with + // proper destination prefetching) + __asm__ __volatile__ (" + //mov eax,constant // eax = val + //mov edx,dest // dest + //mov ecx,count + movd %%eax, %%mm0 + punpckldq %%mm0, %%mm0 + + // ensure that destination is qword aligned + + testl $7, %%edx // qword padding? + jz 0f + movl %%eax, (%%edx) + decl %%ecx + addl $4, %%edx + +0: movl %%ecx, %%ebx + andl $0xfffffff0, %%ecx + jz 2f + jmp 1f + .align 16 + + // funny ordering here to avoid commands + // that cross 32-byte boundaries (the + // [edx+0] version has a special 3-byte opcode... +1: movq %%mm0, 8(%%edx) + movq %%mm0, 16(%%edx) + movq %%mm0, 24(%%edx) + movq %%mm0, 32(%%edx) + movq %%mm0, 40(%%edx) + movq %%mm0, 48(%%edx) + movq %%mm0, 56(%%edx) + movq %%mm0, (%%edx) + addl $64, %%edx + subl $16, %%ecx + jnz 1b +2: + movl %%ebx, %%ecx // ebx = cnt + andl $0xfffffff0, %%ecx // ecx = cnt&~15 + subl %%ecx, %%ebx + jz 6f + cmpl $8, %%ebx + jl 3f + + movq %%mm0, (%%edx) + movq %%mm0, 8(%%edx) + movq %%mm0, 16(%%edx) + movq %%mm0, 24(%%edx) + addl $32, %%edx + subl $8, %%ebx + jz 6f + +3: cmpl $4, %%ebx + jl 4f + + movq %%mm0, (%%edx) + movq %%mm0, 8(%%edx) + addl $16, %%edx + subl $4, %%ebx + +4: cmpl $2, %%ebx + jl 5f + movq %%mm0, (%%edx) + addl $8, %%edx + subl $2, %%ebx + +5: cmpl $1, %%ebx + jl 6f + movl %%eax, (%%edx) +6: + emms + " + : : "a" (constant), "c" (count), "d" (dest) + : "%ebx", "%edi", "%esi", "cc", "memory"); +} + +// optimized memory copy routine that handles all alignment +// cases and block sizes efficiently +void Com_Memcpy (void* dest, const void* src, const size_t count) { + Com_Prefetch (src, count, PRE_READ); + __asm__ __volatile__ (" + pushl %%edi + pushl %%esi + //mov ecx,count + cmpl $0, %%ecx // count = 0 check (just to be on the safe side) + je 6f + //mov edx,dest + movl %0, %%ebx + cmpl $32, %%ecx // padding only? + jl 1f + + movl %%ecx, %%edi + andl $0xfffffe00, %%edi // edi = count&~31 + subl $32, %%edi + + .align 16 +0: + movl (%%ebx, %%edi, 1), %%eax + movl 4(%%ebx, %%edi, 1), %%esi + movl %%eax, (%%edx, %%edi, 1) + movl %%esi, 4(%%edx, %%edi, 1) + movl 8(%%ebx, %%edi, 1), %%eax + movl 12(%%ebx, %%edi, 1), %%esi + movl %%eax, 8(%%edx, %%edi, 1) + movl %%esi, 12(%%edx, %%edi, 1) + movl 16(%%ebx, %%edi, 1), %%eax + movl 20(%%ebx, %%edi, 1), %%esi + movl %%eax, 16(%%edx, %%edi, 1) + movl %%esi, 20(%%edx, %%edi, 1) + movl 24(%%ebx, %%edi, 1), %%eax + movl 28(%%ebx, %%edi, 1), %%esi + movl %%eax, 24(%%edx, %%edi, 1) + movl %%esi, 28(%%edx, %%edi, 1) + subl $32, %%edi + jge 0b + + movl %%ecx, %%edi + andl $0xfffffe00, %%edi + addl %%edi, %%ebx // increase src pointer + addl %%edi, %%edx // increase dst pointer + andl $31, %%ecx // new count + jz 6f // if count = 0, get outta here + +1: + cmpl $16, %%ecx + jl 2f + movl (%%ebx), %%eax + movl %%eax, (%%edx) + movl 4(%%ebx), %%eax + movl %%eax, 4(%%edx) + movl 8(%%ebx), %%eax + movl %%eax, 8(%%edx) + movl 12(%%ebx), %%eax + movl %%eax, 12(%%edx) + subl $16, %%ecx + addl $16, %%ebx + addl $16, %%edx +2: + cmpl $8, %%ecx + jl 3f + movl (%%ebx), %%eax + movl %%eax, (%%edx) + movl 4(%%ebx), %%eax + subl $8, %%ecx + movl %%eax, 4(%%edx) + addl $8, %%ebx + addl $8, %%edx +3: + cmpl $4, %%ecx + jl 4f + movl (%%ebx), %%eax // here 4-7 bytes + addl $4, %%ebx + subl $4, %%ecx + movl %%eax, (%%edx) + addl $4, %%edx +4: // 0-3 remaining bytes + cmpl $2, %%ecx + jl 5f + movw (%%ebx), %%ax // two bytes + cmpl $3, %%ecx // less than 3? + movw %%ax, (%%edx) + jl 6f + movb 2(%%ebx), %%al // last byte + movb %%al, 2(%%edx) + jmp 6f +5: + cmpl $1, %%ecx + jl 6f + movb (%%ebx), %%al + movb %%al, (%%edx) +6: + popl %%esi + popl %%edi + " + : : "m" (src), "d" (dest), "c" (count) + : "%eax", "%ebx", "%edi", "%esi", "cc", "memory"); +} + +void Com_Memset (void* dest, const int val, const size_t count) +{ + unsigned int fillval; + + if (count < 8) + { + __asm__ __volatile__ (" + //mov edx,dest + //mov eax, val + movb %%al, %%ah + movl %%eax, %%ebx + andl $0xffff, %%ebx + shll $16, %%eax + addl %%ebx, %%eax // eax now contains pattern + //mov ecx,count + cmpl $4, %%ecx + jl 0f + movl %%eax, (%%edx) // copy first dword + addl $4, %%edx + subl $4, %%ecx + 0: cmpl $2, %%ecx + jl 1f + movw %%ax, (%%edx) // copy 2 bytes + addl $2, %%edx + subl $2, %%ecx + 1: cmpl $0, %%ecx + je 2f + movb %%al, (%%edx) // copy single byte + 2: + " + : : "d" (dest), "a" (val), "c" (count) + : "%ebx", "%edi", "%esi", "cc", "memory"); + + return; + } + + fillval = val; + + fillval = fillval|(fillval<<8); + fillval = fillval|(fillval<<16); // fill dword with 8-bit pattern + + _copyDWord ((unsigned int*)(dest),fillval, count/4); + + __asm__ __volatile__ (" // padding of 0-3 bytes + //mov ecx,count + movl %%ecx, %%eax + andl $3, %%ecx + jz 1f + andl $0xffffff00, %%eax + //mov ebx,dest + addl %%eax, %%edx + movl %0, %%eax + cmpl $2, %%ecx + jl 0f + movw %%ax, (%%edx) + cmpl $2, %%ecx + je 1f + movb %%al, 2(%%edx) + jmp 1f +0: + cmpl $0, %%ecx + je 1f + movb %%al, (%%edx) +1: + " + : : "m" (fillval), "c" (count), "d" (dest) + : "%eax", "%ebx", "%edi", "%esi", "cc", "memory"); +} + +void Com_Prefetch (const void *s, const unsigned int bytes, e_prefetch type) +{ + // write buffer prefetching is performed only if + // the processor benefits from it. Read and read/write + // prefetching is always performed. + + switch (type) + { + case PRE_WRITE : break; + case PRE_READ: + case PRE_READ_WRITE: + + __asm__ __volatile__ (" + //mov ebx,s + //mov ecx,bytes + cmpl $4096, %%ecx // clamp to 4kB + jle 0f + movl $4096, %%ecx + 0: + addl $0x1f, %%ecx + shrl $5, %%ecx // number of cache lines + jz 2f + jmp 1f + + .align 16 + 1: testb %%al, (%%edx) + addl $32, %%edx + decl %%ecx + jnz 1b + 2: + " + : : "d" (s), "c" (bytes) + : "%eax", "%ebx", "%edi", "%esi", "memory", "cc"); + + break; + } +} + +#endif diff --git a/CODE-mp/unix/linux_glimp.c b/CODE-mp/unix/linux_glimp.c new file mode 100644 index 0000000..4de5929 --- /dev/null +++ b/CODE-mp/unix/linux_glimp.c @@ -0,0 +1,1543 @@ +/* +** GLW_IMP.C +** +** This file contains ALL Linux specific stuff having to do with the +** OpenGL refresh. When a port is being made the following functions +** must be implemented by the port: +** +** GLimp_EndFrame +** GLimp_Init +** GLimp_Shutdown +** GLimp_SwitchFullscreen +** +*/ + +#include +#include +#ifdef __linux__ +#include +#include +#endif +#include +#include +#include +#include +#include + +// bk001204 +#include + +// bk001206 - from my Heretic2 by way of Ryan's Fakk2 +// Needed for the new X11_PendingInput() function. +#include +#include +#include + +#include "../renderer/tr_local.h" +#include "../client/client.h" +#include "linux_local.h" // bk001130 + +#include "unix_glw.h" + +#include + +#include +#include + +#include +#include + +#define WINDOW_CLASS_NAME "Quake 3: Arena" + +typedef enum { + RSERR_OK, + + RSERR_INVALID_FULLSCREEN, + RSERR_INVALID_MODE, + + RSERR_UNKNOWN +} rserr_t; + +glwstate_t glw_state; + +static Display *dpy = NULL; +static int scrnum; +static Window win = 0; +static GLXContext ctx = NULL; + +// bk001206 - not needed anymore +// static qboolean autorepeaton = qtrue; + +#define KEY_MASK (KeyPressMask | KeyReleaseMask) +#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \ + PointerMotionMask | ButtonMotionMask ) +#define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask ) + +static qboolean mouse_avail; +static qboolean mouse_active; +static int mwx, mwy; +static int mx = 0, my = 0; + +// Time mouse was reset, we ignore the first 50ms of the mouse to allow settling of events +static int mouseResetTime = 0; +#define MOUSE_RESET_DELAY 50 + +static cvar_t *in_mouse; +static cvar_t *in_dgamouse; + +// bk001130 - from cvs1.17 (mkv), but not static +cvar_t *in_joystick = NULL; +cvar_t *in_joystickDebug = NULL; +cvar_t *joy_threshold = NULL; + +cvar_t *r_allowSoftwareGL; // don't abort out if the pixelformat claims software +cvar_t *r_previousglDriver; + +qboolean dgamouse = qfalse; +qboolean vidmode_ext = qfalse; + +static int win_x, win_y; + +static XF86VidModeModeInfo **vidmodes; +//static int default_dotclock_vidmode; // bk001204 - unused +static int num_vidmodes; +static qboolean vidmode_active = qfalse; + +static int mouse_accel_numerator; +static int mouse_accel_denominator; +static int mouse_threshold; + +/* +* Find the first occurrence of find in s. +*/ +// bk001130 - from cvs1.17 (mkv), const +// bk001130 - made first argument const +static const char *Q_stristr( const char *s, const char *find) +{ +register char c, sc; +register size_t len; + + if ((c = *find++) != 0) { + if (c >= 'a' && c <= 'z') { + c -= ('a' - 'A'); + } + len = strlen(find); + do { + do { + if ((sc = *s++) == 0) + return NULL; + if (sc >= 'a' && sc <= 'z') { + sc -= ('a' - 'A'); + } + } while (sc != c); + } while (Q_stricmpn(s, find, len) != 0); + s--; + } + return s; +} + +/*****************************************************************************/ +/* KEYBOARD */ +/*****************************************************************************/ + +// bk001204 - unused +// static unsigned int keyshift[256]; // key to map to if shift held down in console +// static qboolean shift_down=qfalse; + +static char *XLateKey(XKeyEvent *ev, int *key) +{ + static char buf[64]; + KeySym keysym; + // static qboolean setup = qfalse; // bk001204 - unused + // int i; // bk001204 - unused + + *key = 0; + + XLookupString(ev, buf, sizeof buf, &keysym, 0); + + switch(keysym) + { + case XK_KP_Page_Up: + case XK_KP_9: *key = K_KP_PGUP; break; + case XK_Page_Up: *key = K_PGUP; break; + + case XK_KP_Page_Down: + case XK_KP_3: *key = K_KP_PGDN; break; + case XK_Page_Down: *key = K_PGDN; break; + + case XK_KP_Home: *key = K_KP_HOME; break; + case XK_KP_7: *key = K_KP_HOME; break; + case XK_Home: *key = K_HOME; break; + + case XK_KP_End: + case XK_KP_1: *key = K_KP_END; break; + case XK_End: *key = K_END; break; + + case XK_KP_Left: *key = K_KP_LEFTARROW; break; + case XK_KP_4: *key = K_KP_LEFTARROW; break; + case XK_Left: *key = K_LEFTARROW; break; + + case XK_KP_Right: *key = K_KP_RIGHTARROW; break; + case XK_KP_6: *key = K_KP_RIGHTARROW; break; + case XK_Right: *key = K_RIGHTARROW; break; + + case XK_KP_Down: + case XK_KP_2: *key = K_KP_DOWNARROW; break; + case XK_Down: *key = K_DOWNARROW; break; + + case XK_KP_Up: + case XK_KP_8: *key = K_KP_UPARROW; break; + case XK_Up: *key = K_UPARROW; break; + + case XK_Escape: *key = K_ESCAPE; break; + + case XK_KP_Enter: *key = K_KP_ENTER; break; + case XK_Return: *key = K_ENTER; break; + + case XK_Tab: *key = K_TAB; break; + + case XK_F1: *key = K_F1; break; + + case XK_F2: *key = K_F2; break; + + case XK_F3: *key = K_F3; break; + + case XK_F4: *key = K_F4; break; + + case XK_F5: *key = K_F5; break; + + case XK_F6: *key = K_F6; break; + + case XK_F7: *key = K_F7; break; + + case XK_F8: *key = K_F8; break; + + case XK_F9: *key = K_F9; break; + + case XK_F10: *key = K_F10; break; + + case XK_F11: *key = K_F11; break; + + case XK_F12: *key = K_F12; break; + + // bk001206 - from Ryan's Fakk2 + //case XK_BackSpace: *key = 8; break; // ctrl-h + case XK_BackSpace: *key = K_BACKSPACE; break; // ctrl-h + + case XK_KP_Delete: + case XK_KP_Decimal: *key = K_KP_DEL; break; + case XK_Delete: *key = K_DEL; break; + + case XK_Pause: *key = K_PAUSE; break; + + case XK_Shift_L: + case XK_Shift_R: *key = K_SHIFT; break; + + case XK_Execute: + case XK_Control_L: + case XK_Control_R: *key = K_CTRL; break; + + case XK_Alt_L: + case XK_Meta_L: + case XK_Alt_R: + case XK_Meta_R: *key = K_ALT; break; + + case XK_KP_Begin: *key = K_KP_5; break; + + case XK_Insert: *key = K_INS; break; + case XK_KP_Insert: + case XK_KP_0: *key = K_KP_INS; break; + + case XK_KP_Multiply: *key = '*'; break; + case XK_KP_Add: *key = K_KP_PLUS; break; + case XK_KP_Subtract: *key = K_KP_MINUS; break; + case XK_KP_Divide: *key = K_KP_SLASH; break; + + // bk001130 - from cvs1.17 (mkv) + case XK_exclam: *key = '1'; break; + case XK_at: *key = '2'; break; + case XK_numbersign: *key = '3'; break; + case XK_dollar: *key = '4'; break; + case XK_percent: *key = '5'; break; + case XK_asciicircum: *key = '6'; break; + case XK_ampersand: *key = '7'; break; + case XK_asterisk: *key = '8'; break; + case XK_parenleft: *key = '9'; break; + case XK_parenright: *key = '0'; break; + + default: + *key = *(unsigned char *)buf; + if (*key >= 'A' && *key <= 'Z') + *key = *key - 'A' + 'a'; + break; + } + + return buf; +} + +// ======================================================================== +// makes a null cursor +// ======================================================================== + +static Cursor CreateNullCursor(Display *display, Window root) +{ + Pixmap cursormask; + XGCValues xgc; + GC gc; + XColor dummycolour; + Cursor cursor; + + cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/); + xgc.function = GXclear; + gc = XCreateGC(display, cursormask, GCFunction, &xgc); + XFillRectangle(display, cursormask, gc, 0, 0, 1, 1); + dummycolour.pixel = 0; + dummycolour.red = 0; + dummycolour.flags = 04; + cursor = XCreatePixmapCursor(display, cursormask, cursormask, + &dummycolour,&dummycolour, 0,0); + XFreePixmap(display,cursormask); + XFreeGC(display,gc); + return cursor; +} + +static void install_grabs(void) +{ + // inviso cursor + XWarpPointer(dpy, None, win, + 0, 0, 0, 0, + glConfig.vidWidth / 2, glConfig.vidHeight / 2); + XSync(dpy, False); + + XDefineCursor(dpy, win, CreateNullCursor(dpy, win)); + + XGrabPointer(dpy, win, // bk010108 - do this earlier? + False, + MOUSE_MASK, + GrabModeAsync, GrabModeAsync, + win, + None, + CurrentTime); + + XGetPointerControl(dpy, &mouse_accel_numerator, &mouse_accel_denominator, + &mouse_threshold); + + XChangePointerControl(dpy, True, True, 1, 1, 0); + + XSync(dpy, False); + + mouseResetTime = Sys_Milliseconds (); + + if (in_dgamouse->value) { + int MajorVersion, MinorVersion; + + if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) { + // unable to query, probalby not supported + ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" ); + ri.Cvar_Set( "in_dgamouse", "0" ); + } else { + dgamouse = qtrue; + XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse); + XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0); + } + } else { + mwx = glConfig.vidWidth / 2; + mwy = glConfig.vidHeight / 2; + mx = my = 0; + } + + XGrabKeyboard(dpy, win, + False, + GrabModeAsync, GrabModeAsync, + CurrentTime); + + XSync(dpy, False); +} + +static void uninstall_grabs(void) +{ + if (dgamouse) { + dgamouse = qfalse; + XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0); + } + + XChangePointerControl(dpy, qtrue, qtrue, mouse_accel_numerator, + mouse_accel_denominator, mouse_threshold); + + XUngrabPointer(dpy, CurrentTime); + XUngrabKeyboard(dpy, CurrentTime); + + XWarpPointer(dpy, None, win, + 0, 0, 0, 0, + glConfig.vidWidth / 2, glConfig.vidHeight / 2); + + // inviso cursor + XUndefineCursor(dpy, win); +} + + + +// bk001206 - from Ryan's Fakk2 +/** + * XPending() actually performs a blocking read + * if no events available. From Fakk2, by way of + * Heretic2, by way of SDL, original idea GGI project. + * The benefit of this approach over the quite + * badly behaved XAutoRepeatOn/Off is that you get + * focus handling for free, which is a major win + * with debug and windowed mode. It rests on the + * assumption that the X server will use the + * same timestamp on press/release event pairs + * for key repeats. + */ +static qboolean X11_PendingInput(void) { + + assert(dpy != NULL); + + // Flush the display connection + // and look to see if events are queued + XFlush( dpy ); + if ( XEventsQueued( dpy, QueuedAlready) ) { + return qtrue; + } + + // More drastic measures are required -- see if X is ready to talk + { + static struct timeval zero_time; + int x11_fd; + fd_set fdset; + + x11_fd = ConnectionNumber( dpy ); + FD_ZERO(&fdset); + FD_SET(x11_fd, &fdset); + if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) { + return(XPending(dpy)); + } + } + + // Oh well, nothing is ready .. + return qfalse; +} + + +// bk001206 - from Ryan's Fakk2. See above. +static qboolean repeated_press(XEvent *event) +{ + XEvent peekevent; + qboolean repeated = qfalse; + + assert(dpy != NULL); + + if (X11_PendingInput()) + { + XPeekEvent(dpy, &peekevent); + + if ((peekevent.type == KeyPress) && + (peekevent.xkey.keycode == event->xkey.keycode) && + (peekevent.xkey.time == event->xkey.time)) + { + repeated = qtrue; + XNextEvent(dpy, &peekevent); // skip event. + } // if + } // if + + return(repeated); +} // repeated_press + + + +static void HandleEvents(void) +{ + int b; + int key; + XEvent event; + qboolean dowarp = qfalse; + char *p; + int dx, dy; + int t; + + if (!dpy) + return; + + while (XPending(dpy)) { + XNextEvent(dpy, &event); + switch(event.type) { + case KeyPress: + p = XLateKey(&event.xkey, &key); + if (key) + Sys_QueEvent( 0, SE_KEY, key, qtrue, 0, NULL ); + while (*p) + Sys_QueEvent( 0, SE_CHAR, *p++, 0, 0, NULL ); + break; + + case KeyRelease: + + // bk001206 - handle key repeat w/o XAutRepatOn/Off + // also: not done if console/menu is active. + // From Ryan's Fakk2. + // see game/q_shared.h, KEYCATCH_* . 0 == in 3d game. + if (cls.keyCatchers == 0) { // FIXME: KEYCATCH_NONE + if (repeated_press(&event) == qtrue) + continue; + } // if + XLateKey(&event.xkey, &key); + + Sys_QueEvent( 0, SE_KEY, key, qfalse, 0, NULL ); + break; + + case MotionNotify: + if (mouse_active) { + if (dgamouse) { + if (abs(event.xmotion.x_root) > 1) + mx += event.xmotion.x_root * 2; + else + mx += event.xmotion.x_root; + if (abs(event.xmotion.y_root) > 1) + my += event.xmotion.y_root * 2; + else + my += event.xmotion.y_root; + t = Sys_Milliseconds(); + if (t - mouseResetTime > MOUSE_RESET_DELAY ) { + Sys_QueEvent( t, SE_MOUSE, mx, my, 0, NULL ); + } + mx = my = 0; + } + else + { +// ri.Printf( PRINT_ALL, "MotionNotify: %d,%d: ", event.xmotion.x, event.xmotion.y ); + // If it's a center motion, we've just returned from our warp + if (event.xmotion.x == glConfig.vidWidth/2 && + event.xmotion.y == glConfig.vidHeight/2) { + mwx = glConfig.vidWidth/2; + mwy = glConfig.vidHeight/2; +// ri.Printf( PRINT_ALL, "SE_MOUSE (%d,%d)\n", mx, my ); + t = Sys_Milliseconds(); + if (t - mouseResetTime > MOUSE_RESET_DELAY ) { + Sys_QueEvent( t, SE_MOUSE, mx, my, 0, NULL ); + } + mx = my = 0; + break; + } + + dx = ((int)event.xmotion.x - mwx); + dy = ((int)event.xmotion.y - mwy); + if (abs(dx) > 1) + mx += dx * 2; + else + mx += dx; + if (abs(dy) > 1) + my += dy * 2; + else + my += dy; + +// ri.Printf( PRINT_ALL, "mx=%d,my=%d [%d - %d,%d - %d]\n", mx, my, event.xmotion.x, mwx, event.xmotion.y, mwy ); + mwx = event.xmotion.x; + mwy = event.xmotion.y; + dowarp = qtrue; + } + } + break; + + case ButtonPress: + if (event.xbutton.button == 4) { + Sys_QueEvent( 0, SE_KEY, K_MWHEELUP, qtrue, 0, NULL ); + } else if (event.xbutton.button == 5) { + Sys_QueEvent( 0, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL ); + } else { + b=-1; + if (event.xbutton.button == 1) { + b = 0; + } else if (event.xbutton.button == 2) { + b = 2; + } else if (event.xbutton.button == 3) { + b = 1; + } + + Sys_QueEvent( 0, SE_KEY, K_MOUSE1 + b, qtrue, 0, NULL ); + } + break; + + case ButtonRelease: + if (event.xbutton.button == 4) { + Sys_QueEvent( 0, SE_KEY, K_MWHEELUP, qfalse, 0, NULL ); + } else if (event.xbutton.button == 5) { + Sys_QueEvent( 0, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL ); + } else { + b=-1; + if (event.xbutton.button == 1) { + b = 0; + } else if (event.xbutton.button == 2) { + b = 2; + } else if (event.xbutton.button == 3) { + b = 1; + } + Sys_QueEvent( 0, SE_KEY, K_MOUSE1 + b, qfalse, 0, NULL ); + } + break; + + case CreateNotify : + win_x = event.xcreatewindow.x; + win_y = event.xcreatewindow.y; + break; + + case ConfigureNotify : + win_x = event.xconfigure.x; + win_y = event.xconfigure.y; + break; + } + } + + if (dowarp) { + XWarpPointer(dpy,None,win,0,0,0,0, + (glConfig.vidWidth/2),(glConfig.vidHeight/2)); + } +} + +void KBD_Init(void) +{ +} + +void KBD_Close(void) +{ +} + +void IN_ActivateMouse( void ) +{ + if (!mouse_avail || !dpy || !win) + return; + + if (!mouse_active) { + install_grabs(); + mouse_active = qtrue; + } +} + +void IN_DeactivateMouse( void ) +{ + if (!mouse_avail || !dpy || !win) + return; + + if (mouse_active) { + uninstall_grabs(); + mouse_active = qfalse; + } +} +/*****************************************************************************/ + +static qboolean signalcaught = qfalse;; + +void Sys_Exit(int); // bk010104 - abstraction + +static void signal_handler(int sig) // bk010104 - replace this... +{ + if (signalcaught) { + printf("DOUBLE SIGNAL FAULT: Received signal %d, exiting...\n", sig); + Sys_Exit(1); // bk010104 - abstraction + } + + signalcaught = qtrue; + printf("Received signal %d, exiting...\n", sig); + GLimp_Shutdown(); // bk010104 - shouldn't this be CL_Shutdown + Sys_Exit(1); // bk010104 - abstraction +} + +static void InitSig(void) +{ + signal(SIGHUP, signal_handler); + signal(SIGQUIT, signal_handler); + signal(SIGILL, signal_handler); + signal(SIGTRAP, signal_handler); + signal(SIGIOT, signal_handler); + signal(SIGBUS, signal_handler); + signal(SIGFPE, signal_handler); + signal(SIGSEGV, signal_handler); + signal(SIGTERM, signal_handler); +} + +/* +** GLimp_SetGamma +** +** This routine should only be called if glConfig.deviceSupportsGamma is TRUE +*/ +void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] ) +{ +} + +/* +** GLimp_Shutdown +** +** This routine does all OS specific shutdown procedures for the OpenGL +** subsystem. Under OpenGL this means NULLing out the current DC and +** HGLRC, deleting the rendering context, and releasing the DC acquired +** for the window. The state structure is also nulled out. +** +*/ +void GLimp_Shutdown( void ) +{ + if (!ctx || !dpy) + return; + IN_DeactivateMouse(); + // bk001206 - replaced with H2/Fakk2 solution + // XAutoRepeatOn(dpy); + // autorepeaton = qfalse; // bk001130 - from cvs1.17 (mkv) + if (dpy) { + if (ctx) + qglXDestroyContext(dpy, ctx); + if (win) + XDestroyWindow(dpy, win); + if (vidmode_active) + XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]); + XCloseDisplay(dpy); + } + vidmode_active = qfalse; + dpy = NULL; + win = 0; + ctx = NULL; + + memset( &glConfig, 0, sizeof( glConfig ) ); + memset( &glState, 0, sizeof( glState ) ); + + QGL_Shutdown(); +} + +/* +** GLimp_LogComment +*/ +void GLimp_LogComment( char *comment ) +{ + if ( glw_state.log_fp ) { + fprintf( glw_state.log_fp, "%s", comment ); + } +} + +/* +** GLW_StartDriverAndSetMode +*/ +// bk001204 - prototype needed +int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen ); +static qboolean GLW_StartDriverAndSetMode( const char *drivername, + int mode, + qboolean fullscreen ) +{ + rserr_t err; + + // don't ever bother going into fullscreen with a voodoo card +#if 1 // JDC: I reenabled this + if ( Q_stristr( drivername, "Voodoo" ) ) { + ri.Cvar_Set( "r_fullscreen", "0" ); + r_fullscreen->modified = qfalse; + fullscreen = qfalse; + } +#endif + + err = GLW_SetMode( drivername, mode, fullscreen ); + + switch ( err ) + { + case RSERR_INVALID_FULLSCREEN: + ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" ); + return qfalse; + case RSERR_INVALID_MODE: + ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode ); + return qfalse; + default: + break; + } + return qtrue; +} + +/* +** GLW_SetMode +*/ +int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen ) +{ + int attrib[] = { + GLX_RGBA, // 0 + GLX_RED_SIZE, 4, // 1, 2 + GLX_GREEN_SIZE, 4, // 3, 4 + GLX_BLUE_SIZE, 4, // 5, 6 + GLX_DOUBLEBUFFER, // 7 + GLX_DEPTH_SIZE, 1, // 8, 9 + GLX_STENCIL_SIZE, 1, // 10, 11 + None + }; + // these match in the array +#define ATTR_RED_IDX 2 +#define ATTR_GREEN_IDX 4 +#define ATTR_BLUE_IDX 6 +#define ATTR_DEPTH_IDX 9 +#define ATTR_STENCIL_IDX 11 + Window root; + XVisualInfo *visinfo; + XSetWindowAttributes attr; + unsigned long mask; + int colorbits, depthbits, stencilbits; + int tcolorbits, tdepthbits, tstencilbits; + int MajorVersion, MinorVersion; + int actualWidth, actualHeight; + int i; + const char* glstring; // bk001130 - from cvs1.17 (mkv) + + ri.Printf( PRINT_ALL, "Initializing OpenGL display\n"); + + ri.Printf (PRINT_ALL, "...setting mode %d:", mode ); + + if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) ) + { + ri.Printf( PRINT_ALL, " invalid mode\n" ); + return RSERR_INVALID_MODE; + } + ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight); + + if (!(dpy = XOpenDisplay(NULL))) { + fprintf(stderr, "Error couldn't open the X display\n"); + return RSERR_INVALID_MODE; + } + + scrnum = DefaultScreen(dpy); + root = RootWindow(dpy, scrnum); + + actualWidth = glConfig.vidWidth; + actualHeight = glConfig.vidHeight; + + // Get video mode list + MajorVersion = MinorVersion = 0; + if (!XF86VidModeQueryVersion(dpy, &MajorVersion, &MinorVersion)) { + vidmode_ext = qfalse; + } else { + ri.Printf(PRINT_ALL, "Using XFree86-VidModeExtension Version %d.%d\n", + MajorVersion, MinorVersion); + vidmode_ext = qtrue; + } + + // Check for DGA + if (in_dgamouse->value) { + if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) { + // unable to query, probalby not supported + ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" ); + ri.Cvar_Set( "in_dgamouse", "0" ); + } else { + ri.Printf( PRINT_ALL, "XF86DGA Mouse (Version %d.%d) initialized\n", + MajorVersion, MinorVersion); + } + } + + if (vidmode_ext) { + int best_fit, best_dist, dist, x, y; + + XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes); + + // Are we going fullscreen? If so, let's change video mode + if (fullscreen) { + best_dist = 9999999; + best_fit = -1; + + for (i = 0; i < num_vidmodes; i++) { + if (glConfig.vidWidth > vidmodes[i]->hdisplay || + glConfig.vidHeight > vidmodes[i]->vdisplay) + continue; + + x = glConfig.vidWidth - vidmodes[i]->hdisplay; + y = glConfig.vidHeight - vidmodes[i]->vdisplay; + dist = (x * x) + (y * y); + if (dist < best_dist) { + best_dist = dist; + best_fit = i; + } + } + + if (best_fit != -1) { + actualWidth = vidmodes[best_fit]->hdisplay; + actualHeight = vidmodes[best_fit]->vdisplay; + + // change to the mode + XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]); + vidmode_active = qtrue; + + // Move the viewport to top left + XF86VidModeSetViewPort(dpy, scrnum, 0, 0); + + ri.Printf(PRINT_ALL, "XFree86-VidModeExtension Activated at %dx%d\n", + actualWidth, actualHeight); + + } else { + fullscreen = 0; + ri.Printf(PRINT_ALL, "XFree86-VidModeExtension: No acceptable modes found\n"); + } + } else { + ri.Printf(PRINT_ALL, "XFree86-VidModeExtension: Ignored on non-fullscreen/Voodoo\n"); + } + } + + + if (!r_colorbits->value) + colorbits = 24; + else + colorbits = r_colorbits->value; + + if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) ) + colorbits = 16; + + if (!r_depthbits->value) + depthbits = 24; + else + depthbits = r_depthbits->value; + stencilbits = r_stencilbits->value; + + for (i = 0; i < 16; i++) { + // 0 - default + // 1 - minus colorbits + // 2 - minus depthbits + // 3 - minus stencil + if ((i % 4) == 0 && i) { + // one pass, reduce + switch (i / 4) { + case 2 : + if (colorbits == 24) + colorbits = 16; + break; + case 1 : + if (depthbits == 24) + depthbits = 16; + else if (depthbits == 16) + depthbits = 8; + case 3 : + if (stencilbits == 24) + stencilbits = 16; + else if (stencilbits == 16) + stencilbits = 8; + } + } + + tcolorbits = colorbits; + tdepthbits = depthbits; + tstencilbits = stencilbits; + + if ((i % 4) == 3) { // reduce colorbits + if (tcolorbits == 24) + tcolorbits = 16; + } + + if ((i % 4) == 2) { // reduce depthbits + if (tdepthbits == 24) + tdepthbits = 16; + else if (tdepthbits == 16) + tdepthbits = 8; + } + + if ((i % 4) == 1) { // reduce stencilbits + if (tstencilbits == 24) + tstencilbits = 16; + else if (tstencilbits == 16) + tstencilbits = 8; + else + tstencilbits = 0; + } + + if (tcolorbits == 24) { + attrib[ATTR_RED_IDX] = 8; + attrib[ATTR_GREEN_IDX] = 8; + attrib[ATTR_BLUE_IDX] = 8; + } else { + // must be 16 bit + attrib[ATTR_RED_IDX] = 4; + attrib[ATTR_GREEN_IDX] = 4; + attrib[ATTR_BLUE_IDX] = 4; + } + + attrib[ATTR_DEPTH_IDX] = tdepthbits; // default to 24 depth + attrib[ATTR_STENCIL_IDX] = tstencilbits; + + visinfo = qglXChooseVisual(dpy, scrnum, attrib); + if (!visinfo) { + continue; + } + + ri.Printf( PRINT_ALL, "Using %d/%d/%d Color bits, %d depth, %d stencil display.\n", + attrib[ATTR_RED_IDX], attrib[ATTR_GREEN_IDX], attrib[ATTR_BLUE_IDX], + attrib[ATTR_DEPTH_IDX], attrib[ATTR_STENCIL_IDX]); + + glConfig.colorBits = tcolorbits; + glConfig.depthBits = tdepthbits; + glConfig.stencilBits = tstencilbits; + break; + } + + if (!visinfo) { + ri.Printf( PRINT_ALL, "Couldn't get a visual\n" ); + return RSERR_INVALID_MODE; + } + + /* window attributes */ + attr.background_pixel = BlackPixel(dpy, scrnum); + attr.border_pixel = 0; + attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone); + attr.event_mask = X_MASK; + if (vidmode_active) { + mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | + CWEventMask | CWOverrideRedirect; + attr.override_redirect = True; + attr.backing_store = NotUseful; + attr.save_under = False; + } else + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + win = XCreateWindow(dpy, root, 0, 0, + actualWidth, actualHeight, + 0, visinfo->depth, InputOutput, + visinfo->visual, mask, &attr); + + XStoreName( dpy, win, WINDOW_CLASS_NAME ); + + XMapWindow( dpy, win ); + + if (vidmode_active) + XMoveWindow(dpy, win, 0, 0); + + XFlush(dpy); + XSync(dpy,False); // bk001130 - from cvs1.17 (mkv) + ctx = qglXCreateContext(dpy, visinfo, NULL, True); + XSync(dpy,False); // bk001130 - from cvs1.17 (mkv) + + qglXMakeCurrent(dpy, win, ctx); + + // bk001130 - from cvs1.17 (mkv) + glstring = qglGetString (GL_RENDERER); + ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glstring ); + + // bk010122 - new software token (Indirect) + if ( !Q_stricmp( glstring, "Mesa X11") + || !Q_stricmp( glstring, "Mesa GLX Indirect") ) + { + if ( !r_allowSoftwareGL->integer ) { + ri.Printf( PRINT_ALL, "\n\n***********************************************************\n" ); + ri.Printf( PRINT_ALL, " You are using software Mesa (no hardware acceleration)! \n" ); + ri.Printf( PRINT_ALL, " Driver DLL used: %s\n", drivername ); + ri.Printf( PRINT_ALL, " If this is intentional, add\n" ); + ri.Printf( PRINT_ALL, " \"+set r_allowSoftwareGL 1\"\n" ); + ri.Printf( PRINT_ALL, " to the command line when starting the game.\n" ); + ri.Printf( PRINT_ALL, "***********************************************************\n"); + GLimp_Shutdown( ); + return RSERR_INVALID_MODE; + } else { + ri.Printf( PRINT_ALL, "...using software Mesa (r_allowSoftwareGL==1).\n" ); + } + } + + return RSERR_OK; +} + +/* +** GLW_InitExtensions +*/ +static void GLW_InitExtensions( void ) +{ + if ( !r_allowExtensions->integer ) + { + ri.Printf( PRINT_ALL, "*** IGNORING OPENGL EXTENSIONS ***\n" ); + return; + } + + ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" ); + + // GL_S3_s3tc + if ( Q_stristr( glConfig.extensions_string, "GL_S3_s3tc" ) ) + { + if ( r_ext_compressed_textures->value ) + { + glConfig.textureCompression = TC_S3TC; + ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" ); + } + else + { + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" ); + } + } + else + { + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...GL_S3_s3tc not found\n" ); + } + + // GL_EXT_texture_env_add + glConfig.textureEnvAddAvailable = qfalse; + if ( Q_stristr( glConfig.extensions_string, "EXT_texture_env_add" ) ) + { + if ( r_ext_texture_env_add->integer ) + { + glConfig.textureEnvAddAvailable = qtrue; + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" ); + } + else + { + glConfig.textureEnvAddAvailable = qfalse; + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" ); + } + + // GL_ARB_multitexture + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + if ( Q_stristr( glConfig.extensions_string, "GL_ARB_multitexture" ) ) + { + if ( r_ext_multitexture->value ) + { + qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) dlsym( glw_state.OpenGLLib, "glMultiTexCoord2fARB" ); + qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glActiveTextureARB" ); + qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glClientActiveTextureARB" ); + + if ( qglActiveTextureARB ) + { + qglGetIntegerv( GL_MAX_ACTIVE_TEXTURES_ARB, &glConfig.maxActiveTextures ); + + if ( glConfig.maxActiveTextures > 1 ) + { + ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); + } + else + { + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" ); + } + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); + } + + // GL_EXT_compiled_vertex_array + if ( Q_stristr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) ) + { + if ( r_ext_compiled_vertex_array->value ) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" ); + qglLockArraysEXT = ( void ( APIENTRY * )( int, int ) ) dlsym( glw_state.OpenGLLib, "glLockArraysEXT" ); + qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) dlsym( glw_state.OpenGLLib, "glUnlockArraysEXT" ); + if (!qglLockArraysEXT || !qglUnlockArraysEXT) { + ri.Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); + } + +} + +/* +** GLW_LoadOpenGL +** +** GLimp_win.c internal function that that attempts to load and use +** a specific OpenGL DLL. +*/ +static qboolean GLW_LoadOpenGL( const char *name ) +{ + qboolean fullscreen; + + ri.Printf( PRINT_ALL, "...loading %s: ", name ); + + // disable the 3Dfx splash screen and set gamma + // we do this all the time, but it shouldn't hurt anything + // on non-3Dfx stuff + putenv("FX_GLIDE_NO_SPLASH=0"); + + // Mesa VooDoo hacks + putenv("MESA_GLX_FX=fullscreen\n"); + + // load the QGL layer + if ( QGL_Init( name ) ) + { + fullscreen = r_fullscreen->integer; + + // create the window and set up the context + if ( !GLW_StartDriverAndSetMode( name, r_mode->integer, fullscreen ) ) + { + if (r_mode->integer != 3) { + if ( !GLW_StartDriverAndSetMode( name, 3, fullscreen ) ) { + goto fail; + } + } else + goto fail; + } + + return qtrue; + } + else + { + ri.Printf( PRINT_ALL, "failed\n" ); + } +fail: + + QGL_Shutdown(); + + return qfalse; +} + +/* +** GLimp_Init +** +** This routine is responsible for initializing the OS specific portions +** of OpenGL. +*/ +void GLimp_Init( void ) +{ + qboolean attemptedlibGL = qfalse; + qboolean attempted3Dfx = qfalse; + qboolean success = qfalse; + char buf[1024]; + cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE ); + // cvar_t *cv; // bk001204 - unused + + r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); + + r_previousglDriver = ri.Cvar_Get( "r_previousglDriver", "", CVAR_ROM ); + + glConfig.deviceSupportsGamma = qfalse; + + InitSig(); + + // Hack here so that if the UI + if ( *r_previousglDriver->string ) { + // The UI changed it on us, hack it back + // This means the renderer can't be changed on the fly + ri.Cvar_Set( "r_glDriver", r_previousglDriver->string ); + } + + // + // load and initialize the specific OpenGL driver + // + if ( !GLW_LoadOpenGL( r_glDriver->string ) ) + { + if ( !Q_stricmp( r_glDriver->string, OPENGL_DRIVER_NAME ) ) + { + attemptedlibGL = qtrue; + } + else if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) ) + { + attempted3Dfx = qtrue; + } + + if ( !attempted3Dfx && !success ) + { + attempted3Dfx = qtrue; + if ( GLW_LoadOpenGL( _3DFX_DRIVER_NAME ) ) + { + ri.Cvar_Set( "r_glDriver", _3DFX_DRIVER_NAME ); + r_glDriver->modified = qfalse; + success = qtrue; + } + } + + // try ICD before trying 3Dfx standalone driver + if ( !attemptedlibGL && !success ) + { + attemptedlibGL = qtrue; + if ( GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) ) + { + ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME ); + r_glDriver->modified = qfalse; + success = qtrue; + } + } + + if (!success) + ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" ); + + } + + // Save it in case the UI stomps it + ri.Cvar_Set( "r_previousglDriver", r_glDriver->string ); + + // This values force the UI to disable driver selection + glConfig.driverType = GLDRV_ICD; + glConfig.hardwareType = GLHW_GENERIC; + + // get our config strings + Q_strncpyz( glConfig.vendor_string, qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) ); + Q_strncpyz( glConfig.renderer_string, qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) ); + if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n') + glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0; + Q_strncpyz( glConfig.version_string, qglGetString (GL_VERSION), sizeof( glConfig.version_string ) ); + Q_strncpyz( glConfig.extensions_string, qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) ); + + // + // chipset specific configuration + // + strcpy( buf, glConfig.renderer_string ); + strlwr( buf ); + + // + // NOTE: if changing cvars, do it within this block. This allows them + // to be overridden when testing driver fixes, etc. but only sets + // them to their default state when the hardware is first installed/run. + // + if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) ) + { + glConfig.hardwareType = GLHW_GENERIC; + + ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); + + // VOODOO GRAPHICS w/ 2MB + if ( Q_stristr( buf, "voodoo graphics/1 tmu/2 mb" ) ) + { + ri.Cvar_Set( "r_picmip", "2" ); + ri.Cvar_Get( "r_picmip", "1", CVAR_ARCHIVE | CVAR_LATCH ); + } + else + { + ri.Cvar_Set( "r_picmip", "1" ); + + if ( Q_stristr( buf, "rage 128" ) || Q_stristr( buf, "rage128" ) ) + { + ri.Cvar_Set( "r_finish", "0" ); + } + // Savage3D and Savage4 should always have trilinear enabled + else if ( Q_stristr( buf, "savage3d" ) || Q_stristr( buf, "s3 savage4" ) ) + { + ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); + } + } + } + + // + // this is where hardware specific workarounds that should be + // detected/initialized every startup should go. + // + if ( Q_stristr( buf, "banshee" ) || Q_stristr( buf, "Voodoo_Graphics" ) ) + { + glConfig.hardwareType = GLHW_3DFX_2D3D; + } + else if ( Q_stristr( buf, "rage pro" ) || Q_stristr( buf, "RagePro" ) ) + { + glConfig.hardwareType = GLHW_RAGEPRO; + } + else if ( Q_stristr( buf, "permedia2" ) ) + { + glConfig.hardwareType = GLHW_PERMEDIA2; + } + else if ( Q_stristr( buf, "riva 128" ) ) + { + glConfig.hardwareType = GLHW_RIVA128; + } + else if ( Q_stristr( buf, "riva tnt " ) ) + { + } + + ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string ); + + // initialize extensions + GLW_InitExtensions(); + + InitSig(); + + return; +} + + +/* +** GLimp_EndFrame +** +** Responsible for doing a swapbuffers and possibly for other stuff +** as yet to be determined. Probably better not to make this a GLimp +** function and instead do a call to GLimp_SwapBuffers. +*/ +void GLimp_EndFrame (void) +{ + // don't flip if drawing to front buffer + if ( stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 ) + { + qglXSwapBuffers(dpy, win); + } + + // check logging + QGL_EnableLogging( (qboolean)r_logFile->integer ); // bk001205 - was ->value +} + +#ifdef SMP +/* +=========================================================== + +SMP acceleration + +=========================================================== +*/ + +sem_t renderCommandsEvent; +sem_t renderCompletedEvent; +sem_t renderActiveEvent; + +void (*glimpRenderThread)( void ); + +void *GLimp_RenderThreadWrapper( void *stub ) { + glimpRenderThread(); + return NULL; +} + + +/* +======================= +GLimp_SpawnRenderThread +======================= +*/ +pthread_t renderThreadHandle; +qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) { + + sem_init( &renderCommandsEvent, 0, 0 ); + sem_init( &renderCompletedEvent, 0, 0 ); + sem_init( &renderActiveEvent, 0, 0 ); + + glimpRenderThread = function; + + if (pthread_create( &renderThreadHandle, NULL, + GLimp_RenderThreadWrapper, NULL)) { + return qfalse; + } + + return qtrue; +} + +static void *smpData; +//static int glXErrors; // bk001204 - unused + +void *GLimp_RendererSleep( void ) { + void *data; + + // after this, the front end can exit GLimp_FrontEndSleep + sem_post ( &renderCompletedEvent ); + + sem_wait ( &renderCommandsEvent ); + + data = smpData; + + // after this, the main thread can exit GLimp_WakeRenderer + sem_post ( &renderActiveEvent ); + + return data; +} + + +void GLimp_FrontEndSleep( void ) { + sem_wait ( &renderCompletedEvent ); +} + + +void GLimp_WakeRenderer( void *data ) { + smpData = data; + + // after this, the renderer can continue through GLimp_RendererSleep + sem_post( &renderCommandsEvent ); + + sem_wait( &renderActiveEvent ); +} + +#else + +void GLimp_RenderThreadWrapper( void *stub ) { } +qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) { + return qfalse; +} +void *GLimp_RendererSleep( void ) { + return NULL; +} +void GLimp_FrontEndSleep( void ) { } +void GLimp_WakeRenderer( void *data ) { } + +#endif + +/*****************************************************************************/ +/* MOUSE */ +/*****************************************************************************/ + +void IN_Init(void) { + // mouse variables + in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE); + in_dgamouse = Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE); + + // bk001130 - from cvs.17 (mkv), joystick variables + in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE|CVAR_LATCH); + // bk001130 - changed this to match win32 + in_joystickDebug = Cvar_Get ("in_debugjoystick", "0", CVAR_TEMP); + joy_threshold = Cvar_Get ("joy_threshold", "0.15", CVAR_ARCHIVE); // FIXME: in_joythreshold + + if (in_mouse->value) + mouse_avail = qtrue; + else + mouse_avail = qfalse; + + IN_StartupJoystick( ); // bk001130 - from cvs1.17 (mkv) +} + +void IN_Shutdown(void) +{ + mouse_avail = qfalse; +} + +void IN_Frame (void) { + + // bk001130 - from cvs 1.17 (mkv) + IN_JoyMove(); // FIXME: disable if on desktop? + + if ( cls.keyCatchers & KEYCATCH_CONSOLE ) { + // temporarily deactivate if not in the game and + // running on the desktop + // voodoo always counts as full screen + if (Cvar_VariableValue ("r_fullscreen") == 0 + && strcmp( Cvar_VariableString("r_glDriver"), _3DFX_DRIVER_NAME ) ) { + IN_DeactivateMouse (); + return; + } + // bk001206 - not used, now done the H2/Fakk2 way + //if (dpy && !autorepeaton) { + // XAutoRepeatOn(dpy); + // autorepeaton = qtrue; + //} + } + //else if (dpy && autorepeaton) { + //XAutoRepeatOff(dpy); + //autorepeaton = qfalse; + //} + + IN_ActivateMouse(); +} + +void IN_Activate(void) +{ +} + +// bk001130 - cvs1.17 joystick code (mkv) was here, no linux_joystick.c + +void Sys_SendKeyEvents (void) { + // XEvent event; // bk001204 - unused + + if (!dpy) + return; + HandleEvents(); +} + + +// bk010216 - added stubs for non-Linux UNIXes here +// FIXME - use NO_JOYSTICK or something else generic + +#if defined( __FreeBSD__ ) // rb010123 +void IN_StartupJoystick( void ) {} +void IN_JoyMove( void ) {} +#endif diff --git a/CODE-mp/unix/linux_joystick.c b/CODE-mp/unix/linux_joystick.c new file mode 100644 index 0000000..662c8b2 --- /dev/null +++ b/CODE-mp/unix/linux_joystick.c @@ -0,0 +1,186 @@ +/* +** linux_joystick.c +** +** This file contains ALL Linux specific stuff having to do with the +** Joystick input. When a port is being made the following functions +** must be implemented by the port: +** +** Authors: mkv, bk +** +*/ + +#include +#include +#include +#include +#include // bk001204 + + +#include "../client/client.h" +#include "linux_local.h" + +/* We translate axes movement into keypresses. */ +int joy_keys[16] = { + K_LEFTARROW, K_RIGHTARROW, + K_UPARROW, K_DOWNARROW, + K_JOY16, K_JOY17, + K_JOY18, K_JOY19, + K_JOY20, K_JOY21, + K_JOY22, K_JOY23, + + K_JOY24, K_JOY25, + K_JOY26, K_JOY27 +}; + +/* Our file descriptor for the joystick device. */ +static int joy_fd = -1; + + +// bk001130 - from linux_glimp.c +extern cvar_t * in_joystick; +extern cvar_t * in_joystickDebug; +extern cvar_t * joy_threshold; + + +/**********************************************/ +/* Joystick routines. */ +/**********************************************/ +// bk001130 - from cvs1.17 (mkv), removed from linux_glimp.c +void IN_StartupJoystick( void ) +{ + int i = 0; + + joy_fd = -1; + + if( !in_joystick->integer ) { + Com_Printf( "Joystick is not active.\n" ); + return; + } + + for( i = 0; i < 4; i++ ) { + char filename[PATH_MAX]; + + snprintf( filename, PATH_MAX, "/dev/js%d", i ); + + joy_fd = open( filename, O_RDONLY | O_NONBLOCK ); + + if( joy_fd != -1 ) { + struct js_event event; + char axes = 0; + char buttons = 0; + char name[128]; + int n = -1; + + Com_Printf( "Joystick %s found\n", filename ); + + /* Get rid of initialization messages. */ + do { + n = read( joy_fd, &event, sizeof( event ) ); + + if( n == -1 ) { + break; + } + + } while( ( event.type & JS_EVENT_INIT ) ); + + /* Get joystick statistics. */ + ioctl( joy_fd, JSIOCGAXES, &axes ); + ioctl( joy_fd, JSIOCGBUTTONS, &buttons ); + + if( ioctl( joy_fd, JSIOCGNAME( sizeof( name ) ), name ) < 0 ) { + strncpy( name, "Unknown", sizeof( name ) ); + } + + Com_Printf( "Name: %s\n", name ); + Com_Printf( "Axes: %d\n", axes ); + Com_Printf( "Buttons: %d\n", buttons ); + + /* Our work here is done. */ + return; + } + + } + + /* No soup for you. */ + if( joy_fd == -1 ) { + Com_Printf( "No joystick found.\n" ); + return; + } + +} + +void IN_JoyMove( void ) +{ + /* Store instantaneous joystick state. Hack to get around + * event model used in Linux joystick driver. + */ + static int axes_state[16]; + /* Old bits for Quake-style input compares. */ + static unsigned int old_axes = 0; + /* Our current goodies. */ + unsigned int axes = 0; + int i = 0; + + if( joy_fd == -1 ) { + return; + } + + /* Empty the queue, dispatching button presses immediately + * and updating the instantaneous state for the axes. + */ + do { + int n = -1; + struct js_event event; + + n = read( joy_fd, &event, sizeof( event ) ); + + if( n == -1 ) { + /* No error, we're non-blocking. */ + break; + } + + if( event.type & JS_EVENT_BUTTON ) { + Sys_QueEvent( 0, SE_KEY, K_JOY1 + event.number, event.value, 0, NULL ); + } else if( event.type & JS_EVENT_AXIS ) { + + if( event.number >= 16 ) { + continue; + } + + axes_state[event.number] = event.value; + } else { + Com_Printf( "Unknown joystick event type\n" ); + } + + } while( 1 ); + + + /* Translate our instantaneous state to bits. */ + for( i = 0; i < 16; i++ ) { + float f = ( (float) axes_state[i] ) / 32767.0f; + + if( f < -joy_threshold->value ) { + axes |= ( 1 << ( i * 2 ) ); + } else if( f > joy_threshold->value ) { + axes |= ( 1 << ( ( i * 2 ) + 1 ) ); + } + + } + + /* Time to update axes state based on old vs. new. */ + for( i = 0; i < 16; i++ ) { + + if( ( axes & ( 1 << i ) ) && !( old_axes & ( 1 << i ) ) ) { + Sys_QueEvent( 0, SE_KEY, joy_keys[i], qtrue, 0, NULL ); + } + + if( !( axes & ( 1 << i ) ) && ( old_axes & ( 1 << i ) ) ) { + Sys_QueEvent( 0, SE_KEY, joy_keys[i], qfalse, 0, NULL ); + } + } + + /* Save for future generations. */ + old_axes = axes; +} + + diff --git a/CODE-mp/unix/linux_local.h b/CODE-mp/unix/linux_local.h new file mode 100644 index 0000000..008bea9 --- /dev/null +++ b/CODE-mp/unix/linux_local.h @@ -0,0 +1,29 @@ +// linux_local.h: Linux-specific Quake3 header file + +void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ); +qboolean Sys_GetPacket ( netadr_t *net_from, msg_t *net_message ); +void Sys_SendKeyEvents (void); + +// Input subsystem + +void IN_Init (void); +void IN_Frame (void); +void IN_Shutdown (void); + + +void IN_JoyMove( void ); +void IN_StartupJoystick( void ); + +// GL subsystem +qboolean QGL_Init( const char *dllname ); +void QGL_EnableLogging( qboolean enable ); +void QGL_Shutdown( void ); + + + + + +// bk001130 - win32 +// void IN_JoystickCommands (void); + +char *strlwr (char *s); diff --git a/CODE-mp/unix/linux_qgl.c b/CODE-mp/unix/linux_qgl.c new file mode 100644 index 0000000..339bfe9 --- /dev/null +++ b/CODE-mp/unix/linux_qgl.c @@ -0,0 +1,4132 @@ +/* +** LINUX_QGL.C +** +** This file implements the operating system binding of GL to QGL function +** pointers. When doing a port of Quake2 you must implement the following +** two functions: +** +** QGL_Init() - loads libraries, assigns function pointers, etc. +** QGL_Shutdown() - unloads libraries, NULLs function pointers +*/ + +// bk001204 +#include +#include + + +#include +#include "../renderer/tr_local.h" +#include "unix_glw.h" + +// bk001129 - from cvs1.17 (mkv) +//#if defined(__FX__) +//#include +//#endif +//#include // bk010216 - FIXME: all of the above redundant? renderer/qgl.h + +#include + + +// bk001129 - from cvs1.17 (mkv) +#if defined(__FX__) +//FX Mesa Functions +fxMesaContext (*qfxMesaCreateContext)(GLuint win, GrScreenResolution_t, GrScreenRefresh_t, const GLint attribList[]); +fxMesaContext (*qfxMesaCreateBestContext)(GLuint win, GLint width, GLint height, const GLint attribList[]); +void (*qfxMesaDestroyContext)(fxMesaContext ctx); +void (*qfxMesaMakeCurrent)(fxMesaContext ctx); +fxMesaContext (*qfxMesaGetCurrentContext)(void); +void (*qfxMesaSwapBuffers)(void); +#endif + +//GLX Functions +XVisualInfo * (*qglXChooseVisual)( Display *dpy, int screen, int *attribList ); +GLXContext (*qglXCreateContext)( Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct ); +void (*qglXDestroyContext)( Display *dpy, GLXContext ctx ); +Bool (*qglXMakeCurrent)( Display *dpy, GLXDrawable drawable, GLXContext ctx); +void (*qglXCopyContext)( Display *dpy, GLXContext src, GLXContext dst, GLuint mask ); +void (*qglXSwapBuffers)( Display *dpy, GLXDrawable drawable ); + +void ( APIENTRY * qglAccum )(GLenum op, GLfloat value); +void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref); +GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +void ( APIENTRY * qglArrayElement )(GLint i); +void ( APIENTRY * qglBegin )(GLenum mode); +void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture); +void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor); +void ( APIENTRY * qglCallList )(GLuint list); +void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +void ( APIENTRY * qglClear )(GLbitfield mask); +void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +void ( APIENTRY * qglClearDepth )(GLclampd depth); +void ( APIENTRY * qglClearIndex )(GLfloat c); +void ( APIENTRY * qglClearStencil )(GLint s); +void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation); +void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue); +void ( APIENTRY * qglColor3bv )(const GLbyte *v); +void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue); +void ( APIENTRY * qglColor3dv )(const GLdouble *v); +void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue); +void ( APIENTRY * qglColor3fv )(const GLfloat *v); +void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue); +void ( APIENTRY * qglColor3iv )(const GLint *v); +void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue); +void ( APIENTRY * qglColor3sv )(const GLshort *v); +void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +void ( APIENTRY * qglColor3ubv )(const GLubyte *v); +void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue); +void ( APIENTRY * qglColor3uiv )(const GLuint *v); +void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue); +void ( APIENTRY * qglColor3usv )(const GLushort *v); +void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +void ( APIENTRY * qglColor4bv )(const GLbyte *v); +void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +void ( APIENTRY * qglColor4dv )(const GLdouble *v); +void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglColor4fv )(const GLfloat *v); +void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +void ( APIENTRY * qglColor4iv )(const GLint *v); +void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +void ( APIENTRY * qglColor4sv )(const GLshort *v); +void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +void ( APIENTRY * qglColor4ubv )(const GLubyte *v); +void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +void ( APIENTRY * qglColor4uiv )(const GLuint *v); +void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +void ( APIENTRY * qglColor4usv )(const GLushort *v); +void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode); +void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglCullFace )(GLenum mode); +void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range); +void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures); +void ( APIENTRY * qglDepthFunc )(GLenum func); +void ( APIENTRY * qglDepthMask )(GLboolean flag); +void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar); +void ( APIENTRY * qglDisable )(GLenum cap); +void ( APIENTRY * qglDisableClientState )(GLenum array); +void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count); +void ( APIENTRY * qglDrawBuffer )(GLenum mode); +void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglEdgeFlag )(GLboolean flag); +void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag); +void ( APIENTRY * qglEnable )(GLenum cap); +void ( APIENTRY * qglEnableClientState )(GLenum array); +void ( APIENTRY * qglEnd )(void); +void ( APIENTRY * qglEndList )(void); +void ( APIENTRY * qglEvalCoord1d )(GLdouble u); +void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord1f )(GLfloat u); +void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u); +void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v); +void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v); +void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u); +void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +void ( APIENTRY * qglEvalPoint1 )(GLint i); +void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j); +void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +void ( APIENTRY * qglFinish )(void); +void ( APIENTRY * qglFlush )(void); +void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglFogi )(GLenum pname, GLint param); +void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglFrontFace )(GLenum mode); +void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLuint ( APIENTRY * qglGenLists )(GLsizei range); +void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures); +void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params); +void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation); +void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params); +GLenum ( APIENTRY * qglGetError )(void); +void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params); +void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params); +void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v); +void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v); +void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v); +void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values); +void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values); +void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values); +void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params); +void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask); +const GLubyte * ( APIENTRY * qglGetString )(GLenum name); +void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglHint )(GLenum target, GLenum mode); +void ( APIENTRY * qglIndexMask )(GLuint mask); +void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglIndexd )(GLdouble c); +void ( APIENTRY * qglIndexdv )(const GLdouble *c); +void ( APIENTRY * qglIndexf )(GLfloat c); +void ( APIENTRY * qglIndexfv )(const GLfloat *c); +void ( APIENTRY * qglIndexi )(GLint c); +void ( APIENTRY * qglIndexiv )(const GLint *c); +void ( APIENTRY * qglIndexs )(GLshort c); +void ( APIENTRY * qglIndexsv )(const GLshort *c); +void ( APIENTRY * qglIndexub )(GLubyte c); +void ( APIENTRY * qglIndexubv )(const GLubyte *c); +void ( APIENTRY * qglInitNames )(void); +void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap); +GLboolean ( APIENTRY * qglIsList )(GLuint list); +GLboolean ( APIENTRY * qglIsTexture )(GLuint texture); +void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param); +void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param); +void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param); +void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params); +void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern); +void ( APIENTRY * qglLineWidth )(GLfloat width); +void ( APIENTRY * qglListBase )(GLuint base); +void ( APIENTRY * qglLoadIdentity )(void); +void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m); +void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m); +void ( APIENTRY * qglLoadName )(GLuint name); +void ( APIENTRY * qglLogicOp )(GLenum opcode); +void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param); +void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param); +void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params); +void ( APIENTRY * qglMatrixMode )(GLenum mode); +void ( APIENTRY * qglMultMatrixd )(const GLdouble *m); +void ( APIENTRY * qglMultMatrixf )(const GLfloat *m); +void ( APIENTRY * qglNewList )(GLuint list, GLenum mode); +void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +void ( APIENTRY * qglNormal3bv )(const GLbyte *v); +void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +void ( APIENTRY * qglNormal3dv )(const GLdouble *v); +void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +void ( APIENTRY * qglNormal3fv )(const GLfloat *v); +void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz); +void ( APIENTRY * qglNormal3iv )(const GLint *v); +void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz); +void ( APIENTRY * qglNormal3sv )(const GLshort *v); +void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +void ( APIENTRY * qglPassThrough )(GLfloat token); +void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor); +void ( APIENTRY * qglPointSize )(GLfloat size); +void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode); +void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units); +void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask); +void ( APIENTRY * qglPopAttrib )(void); +void ( APIENTRY * qglPopClientAttrib )(void); +void ( APIENTRY * qglPopMatrix )(void); +void ( APIENTRY * qglPopName )(void); +void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +void ( APIENTRY * qglPushAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushMatrix )(void); +void ( APIENTRY * qglPushName )(GLuint name); +void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y); +void ( APIENTRY * qglRasterPos2iv )(const GLint *v); +void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y); +void ( APIENTRY * qglRasterPos2sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglRasterPos3iv )(const GLint *v); +void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglRasterPos3sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglRasterPos4iv )(const GLint *v); +void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglRasterPos4sv )(const GLshort *v); +void ( APIENTRY * qglReadBuffer )(GLenum mode); +void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2); +void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2); +void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2); +void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2); +GLint ( APIENTRY * qglRenderMode )(GLenum mode); +void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer); +void ( APIENTRY * qglShadeModel )(GLenum mode); +void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask); +void ( APIENTRY * qglStencilMask )(GLuint mask); +void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +void ( APIENTRY * qglTexCoord1d )(GLdouble s); +void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord1f )(GLfloat s); +void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord1i )(GLint s); +void ( APIENTRY * qglTexCoord1iv )(const GLint *v); +void ( APIENTRY * qglTexCoord1s )(GLshort s); +void ( APIENTRY * qglTexCoord1sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t); +void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t); +void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t); +void ( APIENTRY * qglTexCoord2iv )(const GLint *v); +void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t); +void ( APIENTRY * qglTexCoord2sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r); +void ( APIENTRY * qglTexCoord3iv )(const GLint *v); +void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r); +void ( APIENTRY * qglTexCoord3sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +void ( APIENTRY * qglTexCoord4iv )(const GLint *v); +void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +void ( APIENTRY * qglTexCoord4sv )(const GLshort *v); +void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param); +void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param); +void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglVertex2dv )(const GLdouble *v); +void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglVertex2fv )(const GLfloat *v); +void ( APIENTRY * qglVertex2i )(GLint x, GLint y); +void ( APIENTRY * qglVertex2iv )(const GLint *v); +void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y); +void ( APIENTRY * qglVertex2sv )(const GLshort *v); +void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglVertex3dv )(const GLdouble *v); +void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex3fv )(const GLfloat *v); +void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglVertex3iv )(const GLint *v); +void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglVertex3sv )(const GLshort *v); +void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglVertex4dv )(const GLdouble *v); +void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglVertex4fv )(const GLfloat *v); +void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglVertex4iv )(const GLint *v); +void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglVertex4sv )(const GLshort *v); +void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +void ( APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t ); +void ( APIENTRY * qglActiveTextureARB )( GLenum texture ); +void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture ); + +void ( APIENTRY * qglLockArraysEXT)( int, int); +void ( APIENTRY * qglUnlockArraysEXT) ( void ); + +void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value ); +void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value ); +void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * ); +void ( APIENTRY * qgl3DfxSetPaletteEXT)( GLuint * ); +void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); +void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); + +static void ( APIENTRY * dllAccum )(GLenum op, GLfloat value); +static void ( APIENTRY * dllAlphaFunc )(GLenum func, GLclampf ref); +GLboolean ( APIENTRY * dllAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +static void ( APIENTRY * dllArrayElement )(GLint i); +static void ( APIENTRY * dllBegin )(GLenum mode); +static void ( APIENTRY * dllBindTexture )(GLenum target, GLuint texture); +static void ( APIENTRY * dllBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +static void ( APIENTRY * dllBlendFunc )(GLenum sfactor, GLenum dfactor); +static void ( APIENTRY * dllCallList )(GLuint list); +static void ( APIENTRY * dllCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +static void ( APIENTRY * dllClear )(GLbitfield mask); +static void ( APIENTRY * dllClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +static void ( APIENTRY * dllClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +static void ( APIENTRY * dllClearDepth )(GLclampd depth); +static void ( APIENTRY * dllClearIndex )(GLfloat c); +static void ( APIENTRY * dllClearStencil )(GLint s); +static void ( APIENTRY * dllClipPlane )(GLenum plane, const GLdouble *equation); +static void ( APIENTRY * dllColor3b )(GLbyte red, GLbyte green, GLbyte blue); +static void ( APIENTRY * dllColor3bv )(const GLbyte *v); +static void ( APIENTRY * dllColor3d )(GLdouble red, GLdouble green, GLdouble blue); +static void ( APIENTRY * dllColor3dv )(const GLdouble *v); +static void ( APIENTRY * dllColor3f )(GLfloat red, GLfloat green, GLfloat blue); +static void ( APIENTRY * dllColor3fv )(const GLfloat *v); +static void ( APIENTRY * dllColor3i )(GLint red, GLint green, GLint blue); +static void ( APIENTRY * dllColor3iv )(const GLint *v); +static void ( APIENTRY * dllColor3s )(GLshort red, GLshort green, GLshort blue); +static void ( APIENTRY * dllColor3sv )(const GLshort *v); +static void ( APIENTRY * dllColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +static void ( APIENTRY * dllColor3ubv )(const GLubyte *v); +static void ( APIENTRY * dllColor3ui )(GLuint red, GLuint green, GLuint blue); +static void ( APIENTRY * dllColor3uiv )(const GLuint *v); +static void ( APIENTRY * dllColor3us )(GLushort red, GLushort green, GLushort blue); +static void ( APIENTRY * dllColor3usv )(const GLushort *v); +static void ( APIENTRY * dllColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +static void ( APIENTRY * dllColor4bv )(const GLbyte *v); +static void ( APIENTRY * dllColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +static void ( APIENTRY * dllColor4dv )(const GLdouble *v); +static void ( APIENTRY * dllColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +static void ( APIENTRY * dllColor4fv )(const GLfloat *v); +static void ( APIENTRY * dllColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +static void ( APIENTRY * dllColor4iv )(const GLint *v); +static void ( APIENTRY * dllColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +static void ( APIENTRY * dllColor4sv )(const GLshort *v); +static void ( APIENTRY * dllColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +static void ( APIENTRY * dllColor4ubv )(const GLubyte *v); +static void ( APIENTRY * dllColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +static void ( APIENTRY * dllColor4uiv )(const GLuint *v); +static void ( APIENTRY * dllColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +static void ( APIENTRY * dllColor4usv )(const GLushort *v); +static void ( APIENTRY * dllColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +static void ( APIENTRY * dllColorMaterial )(GLenum face, GLenum mode); +static void ( APIENTRY * dllColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +static void ( APIENTRY * dllCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +static void ( APIENTRY * dllCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +static void ( APIENTRY * dllCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +static void ( APIENTRY * dllCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +static void ( APIENTRY * dllCullFace )(GLenum mode); +static void ( APIENTRY * dllDeleteLists )(GLuint list, GLsizei range); +static void ( APIENTRY * dllDeleteTextures )(GLsizei n, const GLuint *textures); +static void ( APIENTRY * dllDepthFunc )(GLenum func); +static void ( APIENTRY * dllDepthMask )(GLboolean flag); +static void ( APIENTRY * dllDepthRange )(GLclampd zNear, GLclampd zFar); +static void ( APIENTRY * dllDisable )(GLenum cap); +static void ( APIENTRY * dllDisableClientState )(GLenum array); +static void ( APIENTRY * dllDrawArrays )(GLenum mode, GLint first, GLsizei count); +static void ( APIENTRY * dllDrawBuffer )(GLenum mode); +static void ( APIENTRY * dllDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +static void ( APIENTRY * dllDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllEdgeFlag )(GLboolean flag); +static void ( APIENTRY * dllEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllEdgeFlagv )(const GLboolean *flag); +static void ( APIENTRY * dllEnable )(GLenum cap); +static void ( APIENTRY * dllEnableClientState )(GLenum array); +static void ( APIENTRY * dllEnd )(void); +static void ( APIENTRY * dllEndList )(void); +static void ( APIENTRY * dllEvalCoord1d )(GLdouble u); +static void ( APIENTRY * dllEvalCoord1dv )(const GLdouble *u); +static void ( APIENTRY * dllEvalCoord1f )(GLfloat u); +static void ( APIENTRY * dllEvalCoord1fv )(const GLfloat *u); +static void ( APIENTRY * dllEvalCoord2d )(GLdouble u, GLdouble v); +static void ( APIENTRY * dllEvalCoord2dv )(const GLdouble *u); +static void ( APIENTRY * dllEvalCoord2f )(GLfloat u, GLfloat v); +static void ( APIENTRY * dllEvalCoord2fv )(const GLfloat *u); +static void ( APIENTRY * dllEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +static void ( APIENTRY * dllEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +static void ( APIENTRY * dllEvalPoint1 )(GLint i); +static void ( APIENTRY * dllEvalPoint2 )(GLint i, GLint j); +static void ( APIENTRY * dllFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +static void ( APIENTRY * dllFinish )(void); +static void ( APIENTRY * dllFlush )(void); +static void ( APIENTRY * dllFogf )(GLenum pname, GLfloat param); +static void ( APIENTRY * dllFogfv )(GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllFogi )(GLenum pname, GLint param); +static void ( APIENTRY * dllFogiv )(GLenum pname, const GLint *params); +static void ( APIENTRY * dllFrontFace )(GLenum mode); +static void ( APIENTRY * dllFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLuint ( APIENTRY * dllGenLists )(GLsizei range); +static void ( APIENTRY * dllGenTextures )(GLsizei n, GLuint *textures); +static void ( APIENTRY * dllGetBooleanv )(GLenum pname, GLboolean *params); +static void ( APIENTRY * dllGetClipPlane )(GLenum plane, GLdouble *equation); +static void ( APIENTRY * dllGetDoublev )(GLenum pname, GLdouble *params); +GLenum ( APIENTRY * dllGetError )(void); +static void ( APIENTRY * dllGetFloatv )(GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetIntegerv )(GLenum pname, GLint *params); +static void ( APIENTRY * dllGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetLightiv )(GLenum light, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetMapdv )(GLenum target, GLenum query, GLdouble *v); +static void ( APIENTRY * dllGetMapfv )(GLenum target, GLenum query, GLfloat *v); +static void ( APIENTRY * dllGetMapiv )(GLenum target, GLenum query, GLint *v); +static void ( APIENTRY * dllGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetPixelMapfv )(GLenum map, GLfloat *values); +static void ( APIENTRY * dllGetPixelMapuiv )(GLenum map, GLuint *values); +static void ( APIENTRY * dllGetPixelMapusv )(GLenum map, GLushort *values); +static void ( APIENTRY * dllGetPointerv )(GLenum pname, GLvoid* *params); +static void ( APIENTRY * dllGetPolygonStipple )(GLubyte *mask); +const GLubyte * ( APIENTRY * dllGetString )(GLenum name); +static void ( APIENTRY * dllGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +static void ( APIENTRY * dllGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +static void ( APIENTRY * dllGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +static void ( APIENTRY * dllHint )(GLenum target, GLenum mode); +static void ( APIENTRY * dllIndexMask )(GLuint mask); +static void ( APIENTRY * dllIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllIndexd )(GLdouble c); +static void ( APIENTRY * dllIndexdv )(const GLdouble *c); +static void ( APIENTRY * dllIndexf )(GLfloat c); +static void ( APIENTRY * dllIndexfv )(const GLfloat *c); +static void ( APIENTRY * dllIndexi )(GLint c); +static void ( APIENTRY * dllIndexiv )(const GLint *c); +static void ( APIENTRY * dllIndexs )(GLshort c); +static void ( APIENTRY * dllIndexsv )(const GLshort *c); +static void ( APIENTRY * dllIndexub )(GLubyte c); +static void ( APIENTRY * dllIndexubv )(const GLubyte *c); +static void ( APIENTRY * dllInitNames )(void); +static void ( APIENTRY * dllInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +GLboolean ( APIENTRY * dllIsEnabled )(GLenum cap); +GLboolean ( APIENTRY * dllIsList )(GLuint list); +GLboolean ( APIENTRY * dllIsTexture )(GLuint texture); +static void ( APIENTRY * dllLightModelf )(GLenum pname, GLfloat param); +static void ( APIENTRY * dllLightModelfv )(GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllLightModeli )(GLenum pname, GLint param); +static void ( APIENTRY * dllLightModeliv )(GLenum pname, const GLint *params); +static void ( APIENTRY * dllLightf )(GLenum light, GLenum pname, GLfloat param); +static void ( APIENTRY * dllLightfv )(GLenum light, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllLighti )(GLenum light, GLenum pname, GLint param); +static void ( APIENTRY * dllLightiv )(GLenum light, GLenum pname, const GLint *params); +static void ( APIENTRY * dllLineStipple )(GLint factor, GLushort pattern); +static void ( APIENTRY * dllLineWidth )(GLfloat width); +static void ( APIENTRY * dllListBase )(GLuint base); +static void ( APIENTRY * dllLoadIdentity )(void); +static void ( APIENTRY * dllLoadMatrixd )(const GLdouble *m); +static void ( APIENTRY * dllLoadMatrixf )(const GLfloat *m); +static void ( APIENTRY * dllLoadName )(GLuint name); +static void ( APIENTRY * dllLogicOp )(GLenum opcode); +static void ( APIENTRY * dllMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +static void ( APIENTRY * dllMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +static void ( APIENTRY * dllMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +static void ( APIENTRY * dllMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +static void ( APIENTRY * dllMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +static void ( APIENTRY * dllMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +static void ( APIENTRY * dllMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +static void ( APIENTRY * dllMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +static void ( APIENTRY * dllMaterialf )(GLenum face, GLenum pname, GLfloat param); +static void ( APIENTRY * dllMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllMateriali )(GLenum face, GLenum pname, GLint param); +static void ( APIENTRY * dllMaterialiv )(GLenum face, GLenum pname, const GLint *params); +static void ( APIENTRY * dllMatrixMode )(GLenum mode); +static void ( APIENTRY * dllMultMatrixd )(const GLdouble *m); +static void ( APIENTRY * dllMultMatrixf )(const GLfloat *m); +static void ( APIENTRY * dllNewList )(GLuint list, GLenum mode); +static void ( APIENTRY * dllNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +static void ( APIENTRY * dllNormal3bv )(const GLbyte *v); +static void ( APIENTRY * dllNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +static void ( APIENTRY * dllNormal3dv )(const GLdouble *v); +static void ( APIENTRY * dllNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +static void ( APIENTRY * dllNormal3fv )(const GLfloat *v); +static void ( APIENTRY * dllNormal3i )(GLint nx, GLint ny, GLint nz); +static void ( APIENTRY * dllNormal3iv )(const GLint *v); +static void ( APIENTRY * dllNormal3s )(GLshort nx, GLshort ny, GLshort nz); +static void ( APIENTRY * dllNormal3sv )(const GLshort *v); +static void ( APIENTRY * dllNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +static void ( APIENTRY * dllPassThrough )(GLfloat token); +static void ( APIENTRY * dllPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +static void ( APIENTRY * dllPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +static void ( APIENTRY * dllPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +static void ( APIENTRY * dllPixelStoref )(GLenum pname, GLfloat param); +static void ( APIENTRY * dllPixelStorei )(GLenum pname, GLint param); +static void ( APIENTRY * dllPixelTransferf )(GLenum pname, GLfloat param); +static void ( APIENTRY * dllPixelTransferi )(GLenum pname, GLint param); +static void ( APIENTRY * dllPixelZoom )(GLfloat xfactor, GLfloat yfactor); +static void ( APIENTRY * dllPointSize )(GLfloat size); +static void ( APIENTRY * dllPolygonMode )(GLenum face, GLenum mode); +static void ( APIENTRY * dllPolygonOffset )(GLfloat factor, GLfloat units); +static void ( APIENTRY * dllPolygonStipple )(const GLubyte *mask); +static void ( APIENTRY * dllPopAttrib )(void); +static void ( APIENTRY * dllPopClientAttrib )(void); +static void ( APIENTRY * dllPopMatrix )(void); +static void ( APIENTRY * dllPopName )(void); +static void ( APIENTRY * dllPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +static void ( APIENTRY * dllPushAttrib )(GLbitfield mask); +static void ( APIENTRY * dllPushClientAttrib )(GLbitfield mask); +static void ( APIENTRY * dllPushMatrix )(void); +static void ( APIENTRY * dllPushName )(GLuint name); +static void ( APIENTRY * dllRasterPos2d )(GLdouble x, GLdouble y); +static void ( APIENTRY * dllRasterPos2dv )(const GLdouble *v); +static void ( APIENTRY * dllRasterPos2f )(GLfloat x, GLfloat y); +static void ( APIENTRY * dllRasterPos2fv )(const GLfloat *v); +static void ( APIENTRY * dllRasterPos2i )(GLint x, GLint y); +static void ( APIENTRY * dllRasterPos2iv )(const GLint *v); +static void ( APIENTRY * dllRasterPos2s )(GLshort x, GLshort y); +static void ( APIENTRY * dllRasterPos2sv )(const GLshort *v); +static void ( APIENTRY * dllRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllRasterPos3dv )(const GLdouble *v); +static void ( APIENTRY * dllRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllRasterPos3fv )(const GLfloat *v); +static void ( APIENTRY * dllRasterPos3i )(GLint x, GLint y, GLint z); +static void ( APIENTRY * dllRasterPos3iv )(const GLint *v); +static void ( APIENTRY * dllRasterPos3s )(GLshort x, GLshort y, GLshort z); +static void ( APIENTRY * dllRasterPos3sv )(const GLshort *v); +static void ( APIENTRY * dllRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +static void ( APIENTRY * dllRasterPos4dv )(const GLdouble *v); +static void ( APIENTRY * dllRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +static void ( APIENTRY * dllRasterPos4fv )(const GLfloat *v); +static void ( APIENTRY * dllRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +static void ( APIENTRY * dllRasterPos4iv )(const GLint *v); +static void ( APIENTRY * dllRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +static void ( APIENTRY * dllRasterPos4sv )(const GLshort *v); +static void ( APIENTRY * dllReadBuffer )(GLenum mode); +static void ( APIENTRY * dllReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +static void ( APIENTRY * dllRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +static void ( APIENTRY * dllRectdv )(const GLdouble *v1, const GLdouble *v2); +static void ( APIENTRY * dllRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +static void ( APIENTRY * dllRectfv )(const GLfloat *v1, const GLfloat *v2); +static void ( APIENTRY * dllRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +static void ( APIENTRY * dllRectiv )(const GLint *v1, const GLint *v2); +static void ( APIENTRY * dllRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +static void ( APIENTRY * dllRectsv )(const GLshort *v1, const GLshort *v2); +GLint ( APIENTRY * dllRenderMode )(GLenum mode); +static void ( APIENTRY * dllRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllScaled )(GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllScalef )(GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +static void ( APIENTRY * dllSelectBuffer )(GLsizei size, GLuint *buffer); +static void ( APIENTRY * dllShadeModel )(GLenum mode); +static void ( APIENTRY * dllStencilFunc )(GLenum func, GLint ref, GLuint mask); +static void ( APIENTRY * dllStencilMask )(GLuint mask); +static void ( APIENTRY * dllStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +static void ( APIENTRY * dllTexCoord1d )(GLdouble s); +static void ( APIENTRY * dllTexCoord1dv )(const GLdouble *v); +static void ( APIENTRY * dllTexCoord1f )(GLfloat s); +static void ( APIENTRY * dllTexCoord1fv )(const GLfloat *v); +static void ( APIENTRY * dllTexCoord1i )(GLint s); +static void ( APIENTRY * dllTexCoord1iv )(const GLint *v); +static void ( APIENTRY * dllTexCoord1s )(GLshort s); +static void ( APIENTRY * dllTexCoord1sv )(const GLshort *v); +static void ( APIENTRY * dllTexCoord2d )(GLdouble s, GLdouble t); +static void ( APIENTRY * dllTexCoord2dv )(const GLdouble *v); +static void ( APIENTRY * dllTexCoord2f )(GLfloat s, GLfloat t); +static void ( APIENTRY * dllTexCoord2fv )(const GLfloat *v); +static void ( APIENTRY * dllTexCoord2i )(GLint s, GLint t); +static void ( APIENTRY * dllTexCoord2iv )(const GLint *v); +static void ( APIENTRY * dllTexCoord2s )(GLshort s, GLshort t); +static void ( APIENTRY * dllTexCoord2sv )(const GLshort *v); +static void ( APIENTRY * dllTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +static void ( APIENTRY * dllTexCoord3dv )(const GLdouble *v); +static void ( APIENTRY * dllTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +static void ( APIENTRY * dllTexCoord3fv )(const GLfloat *v); +static void ( APIENTRY * dllTexCoord3i )(GLint s, GLint t, GLint r); +static void ( APIENTRY * dllTexCoord3iv )(const GLint *v); +static void ( APIENTRY * dllTexCoord3s )(GLshort s, GLshort t, GLshort r); +static void ( APIENTRY * dllTexCoord3sv )(const GLshort *v); +static void ( APIENTRY * dllTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +static void ( APIENTRY * dllTexCoord4dv )(const GLdouble *v); +static void ( APIENTRY * dllTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +static void ( APIENTRY * dllTexCoord4fv )(const GLfloat *v); +static void ( APIENTRY * dllTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +static void ( APIENTRY * dllTexCoord4iv )(const GLint *v); +static void ( APIENTRY * dllTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +static void ( APIENTRY * dllTexCoord4sv )(const GLshort *v); +static void ( APIENTRY * dllTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllTexEnvf )(GLenum target, GLenum pname, GLfloat param); +static void ( APIENTRY * dllTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllTexEnvi )(GLenum target, GLenum pname, GLint param); +static void ( APIENTRY * dllTexEnviv )(GLenum target, GLenum pname, const GLint *params); +static void ( APIENTRY * dllTexGend )(GLenum coord, GLenum pname, GLdouble param); +static void ( APIENTRY * dllTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +static void ( APIENTRY * dllTexGenf )(GLenum coord, GLenum pname, GLfloat param); +static void ( APIENTRY * dllTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllTexGeni )(GLenum coord, GLenum pname, GLint param); +static void ( APIENTRY * dllTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +static void ( APIENTRY * dllTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllTexParameterf )(GLenum target, GLenum pname, GLfloat param); +static void ( APIENTRY * dllTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllTexParameteri )(GLenum target, GLenum pname, GLint param); +static void ( APIENTRY * dllTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +static void ( APIENTRY * dllTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllTranslated )(GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllTranslatef )(GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllVertex2d )(GLdouble x, GLdouble y); +static void ( APIENTRY * dllVertex2dv )(const GLdouble *v); +static void ( APIENTRY * dllVertex2f )(GLfloat x, GLfloat y); +static void ( APIENTRY * dllVertex2fv )(const GLfloat *v); +static void ( APIENTRY * dllVertex2i )(GLint x, GLint y); +static void ( APIENTRY * dllVertex2iv )(const GLint *v); +static void ( APIENTRY * dllVertex2s )(GLshort x, GLshort y); +static void ( APIENTRY * dllVertex2sv )(const GLshort *v); +static void ( APIENTRY * dllVertex3d )(GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllVertex3dv )(const GLdouble *v); +static void ( APIENTRY * dllVertex3f )(GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllVertex3fv )(const GLfloat *v); +static void ( APIENTRY * dllVertex3i )(GLint x, GLint y, GLint z); +static void ( APIENTRY * dllVertex3iv )(const GLint *v); +static void ( APIENTRY * dllVertex3s )(GLshort x, GLshort y, GLshort z); +static void ( APIENTRY * dllVertex3sv )(const GLshort *v); +static void ( APIENTRY * dllVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +static void ( APIENTRY * dllVertex4dv )(const GLdouble *v); +static void ( APIENTRY * dllVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +static void ( APIENTRY * dllVertex4fv )(const GLfloat *v); +static void ( APIENTRY * dllVertex4i )(GLint x, GLint y, GLint z, GLint w); +static void ( APIENTRY * dllVertex4iv )(const GLint *v); +static void ( APIENTRY * dllVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +static void ( APIENTRY * dllVertex4sv )(const GLshort *v); +static void ( APIENTRY * dllVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +static void APIENTRY logAccum(GLenum op, GLfloat value) +{ + fprintf( glw_state.log_fp, "glAccum\n" ); + dllAccum( op, value ); +} + +static void APIENTRY logAlphaFunc(GLenum func, GLclampf ref) +{ + fprintf( glw_state.log_fp, "glAlphaFunc( 0x%x, %f )\n", func, ref ); + dllAlphaFunc( func, ref ); +} + +static GLboolean APIENTRY logAreTexturesResident(GLsizei n, const GLuint *textures, GLboolean *residences) +{ + fprintf( glw_state.log_fp, "glAreTexturesResident\n" ); + return dllAreTexturesResident( n, textures, residences ); +} + +static void APIENTRY logArrayElement(GLint i) +{ + fprintf( glw_state.log_fp, "glArrayElement\n" ); + dllArrayElement( i ); +} + +static void APIENTRY logBegin(GLenum mode) +{ + fprintf( glw_state.log_fp, "glBegin( 0x%x )\n", mode ); + dllBegin( mode ); +} + +static void APIENTRY logBindTexture(GLenum target, GLuint texture) +{ + fprintf( glw_state.log_fp, "glBindTexture( 0x%x, %u )\n", target, texture ); + dllBindTexture( target, texture ); +} + +static void APIENTRY logBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap) +{ + fprintf( glw_state.log_fp, "glBitmap\n" ); + dllBitmap( width, height, xorig, yorig, xmove, ymove, bitmap ); +} + +static void APIENTRY logBlendFunc(GLenum sfactor, GLenum dfactor) +{ + fprintf( glw_state.log_fp, "glBlendFunc( 0x%x, 0x%x )\n", sfactor, dfactor ); + dllBlendFunc( sfactor, dfactor ); +} + +static void APIENTRY logCallList(GLuint list) +{ + fprintf( glw_state.log_fp, "glCallList( %u )\n", list ); + dllCallList( list ); +} + +static void APIENTRY logCallLists(GLsizei n, GLenum type, const void *lists) +{ + fprintf( glw_state.log_fp, "glCallLists\n" ); + dllCallLists( n, type, lists ); +} + +static void APIENTRY logClear(GLbitfield mask) +{ + fprintf( glw_state.log_fp, "glClear\n" ); + dllClear( mask ); +} + +static void APIENTRY logClearAccum(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + fprintf( glw_state.log_fp, "glClearAccum\n" ); + dllClearAccum( red, green, blue, alpha ); +} + +static void APIENTRY logClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + fprintf( glw_state.log_fp, "glClearColor\n" ); + dllClearColor( red, green, blue, alpha ); +} + +static void APIENTRY logClearDepth(GLclampd depth) +{ + fprintf( glw_state.log_fp, "glClearDepth\n" ); + dllClearDepth( depth ); +} + +static void APIENTRY logClearIndex(GLfloat c) +{ + fprintf( glw_state.log_fp, "glClearIndex\n" ); + dllClearIndex( c ); +} + +static void APIENTRY logClearStencil(GLint s) +{ + fprintf( glw_state.log_fp, "glClearStencil\n" ); + dllClearStencil( s ); +} + +static void APIENTRY logClipPlane(GLenum plane, const GLdouble *equation) +{ + fprintf( glw_state.log_fp, "glClipPlane\n" ); + dllClipPlane( plane, equation ); +} + +static void APIENTRY logColor3b(GLbyte red, GLbyte green, GLbyte blue) +{ + fprintf( glw_state.log_fp, "glColor3b\n" ); + dllColor3b( red, green, blue ); +} + +static void APIENTRY logColor3bv(const GLbyte *v) +{ + fprintf( glw_state.log_fp, "glColor3bv\n" ); + dllColor3bv( v ); +} + +static void APIENTRY logColor3d(GLdouble red, GLdouble green, GLdouble blue) +{ + fprintf( glw_state.log_fp, "glColor3d\n" ); + dllColor3d( red, green, blue ); +} + +static void APIENTRY logColor3dv(const GLdouble *v) +{ + fprintf( glw_state.log_fp, "glColor3dv\n" ); + dllColor3dv( v ); +} + +static void APIENTRY logColor3f(GLfloat red, GLfloat green, GLfloat blue) +{ + fprintf( glw_state.log_fp, "glColor3f\n" ); + dllColor3f( red, green, blue ); +} + +static void APIENTRY logColor3fv(const GLfloat *v) +{ + fprintf( glw_state.log_fp, "glColor3fv\n" ); + dllColor3fv( v ); +} + +static void APIENTRY logColor3i(GLint red, GLint green, GLint blue) +{ + fprintf( glw_state.log_fp, "glColor3i\n" ); + dllColor3i( red, green, blue ); +} + +static void APIENTRY logColor3iv(const GLint *v) +{ + fprintf( glw_state.log_fp, "glColor3iv\n" ); + dllColor3iv( v ); +} + +static void APIENTRY logColor3s(GLshort red, GLshort green, GLshort blue) +{ + fprintf( glw_state.log_fp, "glColor3s\n" ); + dllColor3s( red, green, blue ); +} + +static void APIENTRY logColor3sv(const GLshort *v) +{ + fprintf( glw_state.log_fp, "glColor3sv\n" ); + dllColor3sv( v ); +} + +static void APIENTRY logColor3ub(GLubyte red, GLubyte green, GLubyte blue) +{ + fprintf( glw_state.log_fp, "glColor3ub\n" ); + dllColor3ub( red, green, blue ); +} + +static void APIENTRY logColor3ubv(const GLubyte *v) +{ + fprintf( glw_state.log_fp, "glColor3ubv\n" ); + dllColor3ubv( v ); +} + +#define SIG( x ) fprintf( glw_state.log_fp, x "\n" ) + +static void APIENTRY logColor3ui(GLuint red, GLuint green, GLuint blue) +{ + SIG( "glColor3ui" ); + dllColor3ui( red, green, blue ); +} + +static void APIENTRY logColor3uiv(const GLuint *v) +{ + SIG( "glColor3uiv" ); + dllColor3uiv( v ); +} + +static void APIENTRY logColor3us(GLushort red, GLushort green, GLushort blue) +{ + SIG( "glColor3us" ); + dllColor3us( red, green, blue ); +} + +static void APIENTRY logColor3usv(const GLushort *v) +{ + SIG( "glColor3usv" ); + dllColor3usv( v ); +} + +static void APIENTRY logColor4b(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha) +{ + SIG( "glColor4b" ); + dllColor4b( red, green, blue, alpha ); +} + +static void APIENTRY logColor4bv(const GLbyte *v) +{ + SIG( "glColor4bv" ); + dllColor4bv( v ); +} + +static void APIENTRY logColor4d(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha) +{ + SIG( "glColor4d" ); + dllColor4d( red, green, blue, alpha ); +} +static void APIENTRY logColor4dv(const GLdouble *v) +{ + SIG( "glColor4dv" ); + dllColor4dv( v ); +} +static void APIENTRY logColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + fprintf( glw_state.log_fp, "glColor4f( %f,%f,%f,%f )\n", red, green, blue, alpha ); + dllColor4f( red, green, blue, alpha ); +} +static void APIENTRY logColor4fv(const GLfloat *v) +{ + fprintf( glw_state.log_fp, "glColor4fv( %f,%f,%f,%f )\n", v[0], v[1], v[2], v[3] ); + dllColor4fv( v ); +} +static void APIENTRY logColor4i(GLint red, GLint green, GLint blue, GLint alpha) +{ + SIG( "glColor4i" ); + dllColor4i( red, green, blue, alpha ); +} +static void APIENTRY logColor4iv(const GLint *v) +{ + SIG( "glColor4iv" ); + dllColor4iv( v ); +} +static void APIENTRY logColor4s(GLshort red, GLshort green, GLshort blue, GLshort alpha) +{ + SIG( "glColor4s" ); + dllColor4s( red, green, blue, alpha ); +} +static void APIENTRY logColor4sv(const GLshort *v) +{ + SIG( "glColor4sv" ); + dllColor4sv( v ); +} +static void APIENTRY logColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) +{ + SIG( "glColor4b" ); + dllColor4b( red, green, blue, alpha ); +} +static void APIENTRY logColor4ubv(const GLubyte *v) +{ + SIG( "glColor4ubv" ); + dllColor4ubv( v ); +} +static void APIENTRY logColor4ui(GLuint red, GLuint green, GLuint blue, GLuint alpha) +{ + SIG( "glColor4ui" ); + dllColor4ui( red, green, blue, alpha ); +} +static void APIENTRY logColor4uiv(const GLuint *v) +{ + SIG( "glColor4uiv" ); + dllColor4uiv( v ); +} +static void APIENTRY logColor4us(GLushort red, GLushort green, GLushort blue, GLushort alpha) +{ + SIG( "glColor4us" ); + dllColor4us( red, green, blue, alpha ); +} +static void APIENTRY logColor4usv(const GLushort *v) +{ + SIG( "glColor4usv" ); + dllColor4usv( v ); +} +static void APIENTRY logColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + SIG( "glColorMask" ); + dllColorMask( red, green, blue, alpha ); +} +static void APIENTRY logColorMaterial(GLenum face, GLenum mode) +{ + SIG( "glColorMaterial" ); + dllColorMaterial( face, mode ); +} + +static void APIENTRY logColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glColorPointer" ); + dllColorPointer( size, type, stride, pointer ); +} + +static void APIENTRY logCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) +{ + SIG( "glCopyPixels" ); + dllCopyPixels( x, y, width, height, type ); +} + +static void APIENTRY logCopyTexImage1D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border) +{ + SIG( "glCopyTexImage1D" ); + dllCopyTexImage1D( target, level, internalFormat, x, y, width, border ); +} + +static void APIENTRY logCopyTexImage2D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + SIG( "glCopyTexImage2D" ); + dllCopyTexImage2D( target, level, internalFormat, x, y, width, height, border ); +} + +static void APIENTRY logCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) +{ + SIG( "glCopyTexSubImage1D" ); + dllCopyTexSubImage1D( target, level, xoffset, x, y, width ); +} + +static void APIENTRY logCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + SIG( "glCopyTexSubImage2D" ); + dllCopyTexSubImage2D( target, level, xoffset, yoffset, x, y, width, height ); +} + +static void APIENTRY logCullFace(GLenum mode) +{ + SIG( "glCullFace" ); + dllCullFace( mode ); +} + +static void APIENTRY logDeleteLists(GLuint list, GLsizei range) +{ + SIG( "glDeleteLists" ); + dllDeleteLists( list, range ); +} + +static void APIENTRY logDeleteTextures(GLsizei n, const GLuint *textures) +{ + SIG( "glDeleteTextures" ); + dllDeleteTextures( n, textures ); +} + +static void APIENTRY logDepthFunc(GLenum func) +{ + SIG( "glDepthFunc" ); + dllDepthFunc( func ); +} + +static void APIENTRY logDepthMask(GLboolean flag) +{ + SIG( "glDepthMask" ); + dllDepthMask( flag ); +} + +static void APIENTRY logDepthRange(GLclampd zNear, GLclampd zFar) +{ + SIG( "glDepthRange" ); + dllDepthRange( zNear, zFar ); +} + +static void APIENTRY logDisable(GLenum cap) +{ + fprintf( glw_state.log_fp, "glDisable( 0x%x )\n", cap ); + dllDisable( cap ); +} + +static void APIENTRY logDisableClientState(GLenum array) +{ + SIG( "glDisableClientState" ); + dllDisableClientState( array ); +} + +static void APIENTRY logDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + SIG( "glDrawArrays" ); + dllDrawArrays( mode, first, count ); +} + +static void APIENTRY logDrawBuffer(GLenum mode) +{ + SIG( "glDrawBuffer" ); + dllDrawBuffer( mode ); +} + +static void APIENTRY logDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) +{ + SIG( "glDrawElements" ); + dllDrawElements( mode, count, type, indices ); +} + +static void APIENTRY logDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glDrawPixels" ); + dllDrawPixels( width, height, format, type, pixels ); +} + +static void APIENTRY logEdgeFlag(GLboolean flag) +{ + SIG( "glEdgeFlag" ); + dllEdgeFlag( flag ); +} + +static void APIENTRY logEdgeFlagPointer(GLsizei stride, const void *pointer) +{ + SIG( "glEdgeFlagPointer" ); + dllEdgeFlagPointer( stride, pointer ); +} + +static void APIENTRY logEdgeFlagv(const GLboolean *flag) +{ + SIG( "glEdgeFlagv" ); + dllEdgeFlagv( flag ); +} + +static void APIENTRY logEnable(GLenum cap) +{ + fprintf( glw_state.log_fp, "glEnable( 0x%x )\n", cap ); + dllEnable( cap ); +} + +static void APIENTRY logEnableClientState(GLenum array) +{ + SIG( "glEnableClientState" ); + dllEnableClientState( array ); +} + +static void APIENTRY logEnd(void) +{ + SIG( "glEnd" ); + dllEnd(); +} + +static void APIENTRY logEndList(void) +{ + SIG( "glEndList" ); + dllEndList(); +} + +static void APIENTRY logEvalCoord1d(GLdouble u) +{ + SIG( "glEvalCoord1d" ); + dllEvalCoord1d( u ); +} + +static void APIENTRY logEvalCoord1dv(const GLdouble *u) +{ + SIG( "glEvalCoord1dv" ); + dllEvalCoord1dv( u ); +} + +static void APIENTRY logEvalCoord1f(GLfloat u) +{ + SIG( "glEvalCoord1f" ); + dllEvalCoord1f( u ); +} + +static void APIENTRY logEvalCoord1fv(const GLfloat *u) +{ + SIG( "glEvalCoord1fv" ); + dllEvalCoord1fv( u ); +} +static void APIENTRY logEvalCoord2d(GLdouble u, GLdouble v) +{ + SIG( "glEvalCoord2d" ); + dllEvalCoord2d( u, v ); +} +static void APIENTRY logEvalCoord2dv(const GLdouble *u) +{ + SIG( "glEvalCoord2dv" ); + dllEvalCoord2dv( u ); +} +static void APIENTRY logEvalCoord2f(GLfloat u, GLfloat v) +{ + SIG( "glEvalCoord2f" ); + dllEvalCoord2f( u, v ); +} +static void APIENTRY logEvalCoord2fv(const GLfloat *u) +{ + SIG( "glEvalCoord2fv" ); + dllEvalCoord2fv( u ); +} + +static void APIENTRY logEvalMesh1(GLenum mode, GLint i1, GLint i2) +{ + SIG( "glEvalMesh1" ); + dllEvalMesh1( mode, i1, i2 ); +} +static void APIENTRY logEvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2) +{ + SIG( "glEvalMesh2" ); + dllEvalMesh2( mode, i1, i2, j1, j2 ); +} +static void APIENTRY logEvalPoint1(GLint i) +{ + SIG( "glEvalPoint1" ); + dllEvalPoint1( i ); +} +static void APIENTRY logEvalPoint2(GLint i, GLint j) +{ + SIG( "glEvalPoint2" ); + dllEvalPoint2( i, j ); +} + +static void APIENTRY logFeedbackBuffer(GLsizei size, GLenum type, GLfloat *buffer) +{ + SIG( "glFeedbackBuffer" ); + dllFeedbackBuffer( size, type, buffer ); +} + +static void APIENTRY logFinish(void) +{ + SIG( "glFinish" ); + dllFinish(); +} + +static void APIENTRY logFlush(void) +{ + SIG( "glFlush" ); + dllFlush(); +} + +static void APIENTRY logFogf(GLenum pname, GLfloat param) +{ + SIG( "glFogf" ); + dllFogf( pname, param ); +} + +static void APIENTRY logFogfv(GLenum pname, const GLfloat *params) +{ + SIG( "glFogfv" ); + dllFogfv( pname, params ); +} + +static void APIENTRY logFogi(GLenum pname, GLint param) +{ + SIG( "glFogi" ); + dllFogi( pname, param ); +} + +static void APIENTRY logFogiv(GLenum pname, const GLint *params) +{ + SIG( "glFogiv" ); + dllFogiv( pname, params ); +} + +static void APIENTRY logFrontFace(GLenum mode) +{ + SIG( "glFrontFace" ); + dllFrontFace( mode ); +} + +static void APIENTRY logFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) +{ + SIG( "glFrustum" ); + dllFrustum( left, right, bottom, top, zNear, zFar ); +} + +static GLuint APIENTRY logGenLists(GLsizei range) +{ + SIG( "glGenLists" ); + return dllGenLists( range ); +} + +static void APIENTRY logGenTextures(GLsizei n, GLuint *textures) +{ + SIG( "glGenTextures" ); + dllGenTextures( n, textures ); +} + +static void APIENTRY logGetBooleanv(GLenum pname, GLboolean *params) +{ + SIG( "glGetBooleanv" ); + dllGetBooleanv( pname, params ); +} + +static void APIENTRY logGetClipPlane(GLenum plane, GLdouble *equation) +{ + SIG( "glGetClipPlane" ); + dllGetClipPlane( plane, equation ); +} + +static void APIENTRY logGetDoublev(GLenum pname, GLdouble *params) +{ + SIG( "glGetDoublev" ); + dllGetDoublev( pname, params ); +} + +static GLenum APIENTRY logGetError(void) +{ + SIG( "glGetError" ); + return dllGetError(); +} + +static void APIENTRY logGetFloatv(GLenum pname, GLfloat *params) +{ + SIG( "glGetFloatv" ); + dllGetFloatv( pname, params ); +} + +static void APIENTRY logGetIntegerv(GLenum pname, GLint *params) +{ + SIG( "glGetIntegerv" ); + dllGetIntegerv( pname, params ); +} + +static void APIENTRY logGetLightfv(GLenum light, GLenum pname, GLfloat *params) +{ + SIG( "glGetLightfv" ); + dllGetLightfv( light, pname, params ); +} + +static void APIENTRY logGetLightiv(GLenum light, GLenum pname, GLint *params) +{ + SIG( "glGetLightiv" ); + dllGetLightiv( light, pname, params ); +} + +static void APIENTRY logGetMapdv(GLenum target, GLenum query, GLdouble *v) +{ + SIG( "glGetMapdv" ); + dllGetMapdv( target, query, v ); +} + +static void APIENTRY logGetMapfv(GLenum target, GLenum query, GLfloat *v) +{ + SIG( "glGetMapfv" ); + dllGetMapfv( target, query, v ); +} + +static void APIENTRY logGetMapiv(GLenum target, GLenum query, GLint *v) +{ + SIG( "glGetMapiv" ); + dllGetMapiv( target, query, v ); +} + +static void APIENTRY logGetMaterialfv(GLenum face, GLenum pname, GLfloat *params) +{ + SIG( "glGetMaterialfv" ); + dllGetMaterialfv( face, pname, params ); +} + +static void APIENTRY logGetMaterialiv(GLenum face, GLenum pname, GLint *params) +{ + SIG( "glGetMaterialiv" ); + dllGetMaterialiv( face, pname, params ); +} + +static void APIENTRY logGetPixelMapfv(GLenum map, GLfloat *values) +{ + SIG( "glGetPixelMapfv" ); + dllGetPixelMapfv( map, values ); +} + +static void APIENTRY logGetPixelMapuiv(GLenum map, GLuint *values) +{ + SIG( "glGetPixelMapuiv" ); + dllGetPixelMapuiv( map, values ); +} + +static void APIENTRY logGetPixelMapusv(GLenum map, GLushort *values) +{ + SIG( "glGetPixelMapusv" ); + dllGetPixelMapusv( map, values ); +} + +static void APIENTRY logGetPointerv(GLenum pname, GLvoid* *params) +{ + SIG( "glGetPointerv" ); + dllGetPointerv( pname, params ); +} + +static void APIENTRY logGetPolygonStipple(GLubyte *mask) +{ + SIG( "glGetPolygonStipple" ); + dllGetPolygonStipple( mask ); +} + +static const GLubyte * APIENTRY logGetString(GLenum name) +{ + SIG( "glGetString" ); + return dllGetString( name ); +} + +static void APIENTRY logGetTexEnvfv(GLenum target, GLenum pname, GLfloat *params) +{ + SIG( "glGetTexEnvfv" ); + dllGetTexEnvfv( target, pname, params ); +} + +static void APIENTRY logGetTexEnviv(GLenum target, GLenum pname, GLint *params) +{ + SIG( "glGetTexEnviv" ); + dllGetTexEnviv( target, pname, params ); +} + +static void APIENTRY logGetTexGendv(GLenum coord, GLenum pname, GLdouble *params) +{ + SIG( "glGetTexGendv" ); + dllGetTexGendv( coord, pname, params ); +} + +static void APIENTRY logGetTexGenfv(GLenum coord, GLenum pname, GLfloat *params) +{ + SIG( "glGetTexGenfv" ); + dllGetTexGenfv( coord, pname, params ); +} + +static void APIENTRY logGetTexGeniv(GLenum coord, GLenum pname, GLint *params) +{ + SIG( "glGetTexGeniv" ); + dllGetTexGeniv( coord, pname, params ); +} + +static void APIENTRY logGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void *pixels) +{ + SIG( "glGetTexImage" ); + dllGetTexImage( target, level, format, type, pixels ); +} +static void APIENTRY logGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params ) +{ + SIG( "glGetTexLevelParameterfv" ); + dllGetTexLevelParameterfv( target, level, pname, params ); +} + +static void APIENTRY logGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) +{ + SIG( "glGetTexLevelParameteriv" ); + dllGetTexLevelParameteriv( target, level, pname, params ); +} + +static void APIENTRY logGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) +{ + SIG( "glGetTexParameterfv" ); + dllGetTexParameterfv( target, pname, params ); +} + +static void APIENTRY logGetTexParameteriv(GLenum target, GLenum pname, GLint *params) +{ + SIG( "glGetTexParameteriv" ); + dllGetTexParameteriv( target, pname, params ); +} + +static void APIENTRY logHint(GLenum target, GLenum mode) +{ + fprintf( glw_state.log_fp, "glHint( 0x%x, 0x%x )\n", target, mode ); + dllHint( target, mode ); +} + +static void APIENTRY logIndexMask(GLuint mask) +{ + SIG( "glIndexMask" ); + dllIndexMask( mask ); +} + +static void APIENTRY logIndexPointer(GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glIndexPointer" ); + dllIndexPointer( type, stride, pointer ); +} + +static void APIENTRY logIndexd(GLdouble c) +{ + SIG( "glIndexd" ); + dllIndexd( c ); +} + +static void APIENTRY logIndexdv(const GLdouble *c) +{ + SIG( "glIndexdv" ); + dllIndexdv( c ); +} + +static void APIENTRY logIndexf(GLfloat c) +{ + SIG( "glIndexf" ); + dllIndexf( c ); +} + +static void APIENTRY logIndexfv(const GLfloat *c) +{ + SIG( "glIndexfv" ); + dllIndexfv( c ); +} + +static void APIENTRY logIndexi(GLint c) +{ + SIG( "glIndexi" ); + dllIndexi( c ); +} + +static void APIENTRY logIndexiv(const GLint *c) +{ + SIG( "glIndexiv" ); + dllIndexiv( c ); +} + +static void APIENTRY logIndexs(GLshort c) +{ + SIG( "glIndexs" ); + dllIndexs( c ); +} + +static void APIENTRY logIndexsv(const GLshort *c) +{ + SIG( "glIndexsv" ); + dllIndexsv( c ); +} + +static void APIENTRY logIndexub(GLubyte c) +{ + SIG( "glIndexub" ); + dllIndexub( c ); +} + +static void APIENTRY logIndexubv(const GLubyte *c) +{ + SIG( "glIndexubv" ); + dllIndexubv( c ); +} + +static void APIENTRY logInitNames(void) +{ + SIG( "glInitNames" ); + dllInitNames(); +} + +static void APIENTRY logInterleavedArrays(GLenum format, GLsizei stride, const void *pointer) +{ + SIG( "glInterleavedArrays" ); + dllInterleavedArrays( format, stride, pointer ); +} + +static GLboolean APIENTRY logIsEnabled(GLenum cap) +{ + SIG( "glIsEnabled" ); + return dllIsEnabled( cap ); +} +static GLboolean APIENTRY logIsList(GLuint list) +{ + SIG( "glIsList" ); + return dllIsList( list ); +} +static GLboolean APIENTRY logIsTexture(GLuint texture) +{ + SIG( "glIsTexture" ); + return dllIsTexture( texture ); +} + +static void APIENTRY logLightModelf(GLenum pname, GLfloat param) +{ + SIG( "glLightModelf" ); + dllLightModelf( pname, param ); +} + +static void APIENTRY logLightModelfv(GLenum pname, const GLfloat *params) +{ + SIG( "glLightModelfv" ); + dllLightModelfv( pname, params ); +} + +static void APIENTRY logLightModeli(GLenum pname, GLint param) +{ + SIG( "glLightModeli" ); + dllLightModeli( pname, param ); + +} + +static void APIENTRY logLightModeliv(GLenum pname, const GLint *params) +{ + SIG( "glLightModeliv" ); + dllLightModeliv( pname, params ); +} + +static void APIENTRY logLightf(GLenum light, GLenum pname, GLfloat param) +{ + SIG( "glLightf" ); + dllLightf( light, pname, param ); +} + +static void APIENTRY logLightfv(GLenum light, GLenum pname, const GLfloat *params) +{ + SIG( "glLightfv" ); + dllLightfv( light, pname, params ); +} + +static void APIENTRY logLighti(GLenum light, GLenum pname, GLint param) +{ + SIG( "glLighti" ); + dllLighti( light, pname, param ); +} + +static void APIENTRY logLightiv(GLenum light, GLenum pname, const GLint *params) +{ + SIG( "glLightiv" ); + dllLightiv( light, pname, params ); +} + +static void APIENTRY logLineStipple(GLint factor, GLushort pattern) +{ + SIG( "glLineStipple" ); + dllLineStipple( factor, pattern ); +} + +static void APIENTRY logLineWidth(GLfloat width) +{ + SIG( "glLineWidth" ); + dllLineWidth( width ); +} + +static void APIENTRY logListBase(GLuint base) +{ + SIG( "glListBase" ); + dllListBase( base ); +} + +static void APIENTRY logLoadIdentity(void) +{ + SIG( "glLoadIdentity" ); + dllLoadIdentity(); +} + +static void APIENTRY logLoadMatrixd(const GLdouble *m) +{ + SIG( "glLoadMatrixd" ); + dllLoadMatrixd( m ); +} + +static void APIENTRY logLoadMatrixf(const GLfloat *m) +{ + SIG( "glLoadMatrixf" ); + dllLoadMatrixf( m ); +} + +static void APIENTRY logLoadName(GLuint name) +{ + SIG( "glLoadName" ); + dllLoadName( name ); +} + +static void APIENTRY logLogicOp(GLenum opcode) +{ + SIG( "glLogicOp" ); + dllLogicOp( opcode ); +} + +static void APIENTRY logMap1d(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points) +{ + SIG( "glMap1d" ); + dllMap1d( target, u1, u2, stride, order, points ); +} + +static void APIENTRY logMap1f(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points) +{ + SIG( "glMap1f" ); + dllMap1f( target, u1, u2, stride, order, points ); +} + +static void APIENTRY logMap2d(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points) +{ + SIG( "glMap2d" ); + dllMap2d( target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points ); +} + +static void APIENTRY logMap2f(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points) +{ + SIG( "glMap2f" ); + dllMap2f( target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points ); +} + +static void APIENTRY logMapGrid1d(GLint un, GLdouble u1, GLdouble u2) +{ + SIG( "glMapGrid1d" ); + dllMapGrid1d( un, u1, u2 ); +} + +static void APIENTRY logMapGrid1f(GLint un, GLfloat u1, GLfloat u2) +{ + SIG( "glMapGrid1f" ); + dllMapGrid1f( un, u1, u2 ); +} + +static void APIENTRY logMapGrid2d(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2) +{ + SIG( "glMapGrid2d" ); + dllMapGrid2d( un, u1, u2, vn, v1, v2 ); +} +static void APIENTRY logMapGrid2f(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2) +{ + SIG( "glMapGrid2f" ); + dllMapGrid2f( un, u1, u2, vn, v1, v2 ); +} +static void APIENTRY logMaterialf(GLenum face, GLenum pname, GLfloat param) +{ + SIG( "glMaterialf" ); + dllMaterialf( face, pname, param ); +} +static void APIENTRY logMaterialfv(GLenum face, GLenum pname, const GLfloat *params) +{ + SIG( "glMaterialfv" ); + dllMaterialfv( face, pname, params ); +} + +static void APIENTRY logMateriali(GLenum face, GLenum pname, GLint param) +{ + SIG( "glMateriali" ); + dllMateriali( face, pname, param ); +} + +static void APIENTRY logMaterialiv(GLenum face, GLenum pname, const GLint *params) +{ + SIG( "glMaterialiv" ); + dllMaterialiv( face, pname, params ); +} + +static void APIENTRY logMatrixMode(GLenum mode) +{ + SIG( "glMatrixMode" ); + dllMatrixMode( mode ); +} + +static void APIENTRY logMultMatrixd(const GLdouble *m) +{ + SIG( "glMultMatrixd" ); + dllMultMatrixd( m ); +} + +static void APIENTRY logMultMatrixf(const GLfloat *m) +{ + SIG( "glMultMatrixf" ); + dllMultMatrixf( m ); +} + +static void APIENTRY logNewList(GLuint list, GLenum mode) +{ + SIG( "glNewList" ); + dllNewList( list, mode ); +} + +static void APIENTRY logNormal3b(GLbyte nx, GLbyte ny, GLbyte nz) +{ + SIG ("glNormal3b" ); + dllNormal3b( nx, ny, nz ); +} + +static void APIENTRY logNormal3bv(const GLbyte *v) +{ + SIG( "glNormal3bv" ); + dllNormal3bv( v ); +} + +static void APIENTRY logNormal3d(GLdouble nx, GLdouble ny, GLdouble nz) +{ + SIG( "glNormal3d" ); + dllNormal3d( nx, ny, nz ); +} + +static void APIENTRY logNormal3dv(const GLdouble *v) +{ + SIG( "glNormal3dv" ); + dllNormal3dv( v ); +} + +static void APIENTRY logNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) +{ + SIG( "glNormal3f" ); + dllNormal3f( nx, ny, nz ); +} + +static void APIENTRY logNormal3fv(const GLfloat *v) +{ + SIG( "glNormal3fv" ); + dllNormal3fv( v ); +} +static void APIENTRY logNormal3i(GLint nx, GLint ny, GLint nz) +{ + SIG( "glNormal3i" ); + dllNormal3i( nx, ny, nz ); +} +static void APIENTRY logNormal3iv(const GLint *v) +{ + SIG( "glNormal3iv" ); + dllNormal3iv( v ); +} +static void APIENTRY logNormal3s(GLshort nx, GLshort ny, GLshort nz) +{ + SIG( "glNormal3s" ); + dllNormal3s( nx, ny, nz ); +} +static void APIENTRY logNormal3sv(const GLshort *v) +{ + SIG( "glNormal3sv" ); + dllNormal3sv( v ); +} +static void APIENTRY logNormalPointer(GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glNormalPointer" ); + dllNormalPointer( type, stride, pointer ); +} +static void APIENTRY logOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) +{ + SIG( "glOrtho" ); + dllOrtho( left, right, bottom, top, zNear, zFar ); +} + +static void APIENTRY logPassThrough(GLfloat token) +{ + SIG( "glPassThrough" ); + dllPassThrough( token ); +} + +static void APIENTRY logPixelMapfv(GLenum map, GLsizei mapsize, const GLfloat *values) +{ + SIG( "glPixelMapfv" ); + dllPixelMapfv( map, mapsize, values ); +} + +static void APIENTRY logPixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values) +{ + SIG( "glPixelMapuiv" ); + dllPixelMapuiv( map, mapsize, values ); +} + +static void APIENTRY logPixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values) +{ + SIG( "glPixelMapusv" ); + dllPixelMapusv( map, mapsize, values ); +} +static void APIENTRY logPixelStoref(GLenum pname, GLfloat param) +{ + SIG( "glPixelStoref" ); + dllPixelStoref( pname, param ); +} +static void APIENTRY logPixelStorei(GLenum pname, GLint param) +{ + SIG( "glPixelStorei" ); + dllPixelStorei( pname, param ); +} +static void APIENTRY logPixelTransferf(GLenum pname, GLfloat param) +{ + SIG( "glPixelTransferf" ); + dllPixelTransferf( pname, param ); +} + +static void APIENTRY logPixelTransferi(GLenum pname, GLint param) +{ + SIG( "glPixelTransferi" ); + dllPixelTransferi( pname, param ); +} + +static void APIENTRY logPixelZoom(GLfloat xfactor, GLfloat yfactor) +{ + SIG( "glPixelZoom" ); + dllPixelZoom( xfactor, yfactor ); +} + +static void APIENTRY logPointSize(GLfloat size) +{ + SIG( "glPointSize" ); + dllPointSize( size ); +} + +static void APIENTRY logPolygonMode(GLenum face, GLenum mode) +{ + fprintf( glw_state.log_fp, "glPolygonMode( 0x%x, 0x%x )\n", face, mode ); + dllPolygonMode( face, mode ); +} + +static void APIENTRY logPolygonOffset(GLfloat factor, GLfloat units) +{ + SIG( "glPolygonOffset" ); + dllPolygonOffset( factor, units ); +} +static void APIENTRY logPolygonStipple(const GLubyte *mask ) +{ + SIG( "glPolygonStipple" ); + dllPolygonStipple( mask ); +} +static void APIENTRY logPopAttrib(void) +{ + SIG( "glPopAttrib" ); + dllPopAttrib(); +} + +static void APIENTRY logPopClientAttrib(void) +{ + SIG( "glPopClientAttrib" ); + dllPopClientAttrib(); +} + +static void APIENTRY logPopMatrix(void) +{ + SIG( "glPopMatrix" ); + dllPopMatrix(); +} + +static void APIENTRY logPopName(void) +{ + SIG( "glPopName" ); + dllPopName(); +} + +static void APIENTRY logPrioritizeTextures(GLsizei n, const GLuint *textures, const GLclampf *priorities) +{ + SIG( "glPrioritizeTextures" ); + dllPrioritizeTextures( n, textures, priorities ); +} + +static void APIENTRY logPushAttrib(GLbitfield mask) +{ + SIG( "glPushAttrib" ); + dllPushAttrib( mask ); +} + +static void APIENTRY logPushClientAttrib(GLbitfield mask) +{ + SIG( "glPushClientAttrib" ); + dllPushClientAttrib( mask ); +} + +static void APIENTRY logPushMatrix(void) +{ + SIG( "glPushMatrix" ); + dllPushMatrix(); +} + +static void APIENTRY logPushName(GLuint name) +{ + SIG( "glPushName" ); + dllPushName( name ); +} + +static void APIENTRY logRasterPos2d(GLdouble x, GLdouble y) +{ + SIG ("glRasterPot2d" ); + dllRasterPos2d( x, y ); +} + +static void APIENTRY logRasterPos2dv(const GLdouble *v) +{ + SIG( "glRasterPos2dv" ); + dllRasterPos2dv( v ); +} + +static void APIENTRY logRasterPos2f(GLfloat x, GLfloat y) +{ + SIG( "glRasterPos2f" ); + dllRasterPos2f( x, y ); +} +static void APIENTRY logRasterPos2fv(const GLfloat *v) +{ + SIG( "glRasterPos2dv" ); + dllRasterPos2fv( v ); +} +static void APIENTRY logRasterPos2i(GLint x, GLint y) +{ + SIG( "glRasterPos2if" ); + dllRasterPos2i( x, y ); +} +static void APIENTRY logRasterPos2iv(const GLint *v) +{ + SIG( "glRasterPos2iv" ); + dllRasterPos2iv( v ); +} +static void APIENTRY logRasterPos2s(GLshort x, GLshort y) +{ + SIG( "glRasterPos2s" ); + dllRasterPos2s( x, y ); +} +static void APIENTRY logRasterPos2sv(const GLshort *v) +{ + SIG( "glRasterPos2sv" ); + dllRasterPos2sv( v ); +} +static void APIENTRY logRasterPos3d(GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glRasterPos3d" ); + dllRasterPos3d( x, y, z ); +} +static void APIENTRY logRasterPos3dv(const GLdouble *v) +{ + SIG( "glRasterPos3dv" ); + dllRasterPos3dv( v ); +} +static void APIENTRY logRasterPos3f(GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glRasterPos3f" ); + dllRasterPos3f( x, y, z ); +} +static void APIENTRY logRasterPos3fv(const GLfloat *v) +{ + SIG( "glRasterPos3fv" ); + dllRasterPos3fv( v ); +} +static void APIENTRY logRasterPos3i(GLint x, GLint y, GLint z) +{ + SIG( "glRasterPos3i" ); + dllRasterPos3i( x, y, z ); +} +static void APIENTRY logRasterPos3iv(const GLint *v) +{ + SIG( "glRasterPos3iv" ); + dllRasterPos3iv( v ); +} +static void APIENTRY logRasterPos3s(GLshort x, GLshort y, GLshort z) +{ + SIG( "glRasterPos3s" ); + dllRasterPos3s( x, y, z ); +} +static void APIENTRY logRasterPos3sv(const GLshort *v) +{ + SIG( "glRasterPos3sv" ); + dllRasterPos3sv( v ); +} +static void APIENTRY logRasterPos4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + SIG( "glRasterPos4d" ); + dllRasterPos4d( x, y, z, w ); +} +static void APIENTRY logRasterPos4dv(const GLdouble *v) +{ + SIG( "glRasterPos4dv" ); + dllRasterPos4dv( v ); +} +static void APIENTRY logRasterPos4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + SIG( "glRasterPos4f" ); + dllRasterPos4f( x, y, z, w ); +} +static void APIENTRY logRasterPos4fv(const GLfloat *v) +{ + SIG( "glRasterPos4fv" ); + dllRasterPos4fv( v ); +} +static void APIENTRY logRasterPos4i(GLint x, GLint y, GLint z, GLint w) +{ + SIG( "glRasterPos4i" ); + dllRasterPos4i( x, y, z, w ); +} +static void APIENTRY logRasterPos4iv(const GLint *v) +{ + SIG( "glRasterPos4iv" ); + dllRasterPos4iv( v ); +} +static void APIENTRY logRasterPos4s(GLshort x, GLshort y, GLshort z, GLshort w) +{ + SIG( "glRasterPos4s" ); + dllRasterPos4s( x, y, z, w ); +} +static void APIENTRY logRasterPos4sv(const GLshort *v) +{ + SIG( "glRasterPos4sv" ); + dllRasterPos4sv( v ); +} +static void APIENTRY logReadBuffer(GLenum mode) +{ + SIG( "glReadBuffer" ); + dllReadBuffer( mode ); +} +static void APIENTRY logReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) +{ + SIG( "glReadPixels" ); + dllReadPixels( x, y, width, height, format, type, pixels ); +} + +static void APIENTRY logRectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) +{ + SIG( "glRectd" ); + dllRectd( x1, y1, x2, y2 ); +} + +static void APIENTRY logRectdv(const GLdouble *v1, const GLdouble *v2) +{ + SIG( "glRectdv" ); + dllRectdv( v1, v2 ); +} + +static void APIENTRY logRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) +{ + SIG( "glRectf" ); + dllRectf( x1, y1, x2, y2 ); +} + +static void APIENTRY logRectfv(const GLfloat *v1, const GLfloat *v2) +{ + SIG( "glRectfv" ); + dllRectfv( v1, v2 ); +} +static void APIENTRY logRecti(GLint x1, GLint y1, GLint x2, GLint y2) +{ + SIG( "glRecti" ); + dllRecti( x1, y1, x2, y2 ); +} +static void APIENTRY logRectiv(const GLint *v1, const GLint *v2) +{ + SIG( "glRectiv" ); + dllRectiv( v1, v2 ); +} +static void APIENTRY logRects(GLshort x1, GLshort y1, GLshort x2, GLshort y2) +{ + SIG( "glRects" ); + dllRects( x1, y1, x2, y2 ); +} +static void APIENTRY logRectsv(const GLshort *v1, const GLshort *v2) +{ + SIG( "glRectsv" ); + dllRectsv( v1, v2 ); +} +static GLint APIENTRY logRenderMode(GLenum mode) +{ + SIG( "glRenderMode" ); + return dllRenderMode( mode ); +} +static void APIENTRY logRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glRotated" ); + dllRotated( angle, x, y, z ); +} + +static void APIENTRY logRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glRotatef" ); + dllRotatef( angle, x, y, z ); +} + +static void APIENTRY logScaled(GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glScaled" ); + dllScaled( x, y, z ); +} + +static void APIENTRY logScalef(GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glScalef" ); + dllScalef( x, y, z ); +} + +static void APIENTRY logScissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + SIG( "glScissor" ); + dllScissor( x, y, width, height ); +} + +static void APIENTRY logSelectBuffer(GLsizei size, GLuint *buffer) +{ + SIG( "glSelectBuffer" ); + dllSelectBuffer( size, buffer ); +} + +static void APIENTRY logShadeModel(GLenum mode) +{ + SIG( "glShadeModel" ); + dllShadeModel( mode ); +} + +static void APIENTRY logStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + SIG( "glStencilFunc" ); + dllStencilFunc( func, ref, mask ); +} + +static void APIENTRY logStencilMask(GLuint mask) +{ + SIG( "glStencilMask" ); + dllStencilMask( mask ); +} + +static void APIENTRY logStencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + SIG( "glStencilOp" ); + dllStencilOp( fail, zfail, zpass ); +} + +static void APIENTRY logTexCoord1d(GLdouble s) +{ + SIG( "glTexCoord1d" ); + dllTexCoord1d( s ); +} + +static void APIENTRY logTexCoord1dv(const GLdouble *v) +{ + SIG( "glTexCoord1dv" ); + dllTexCoord1dv( v ); +} + +static void APIENTRY logTexCoord1f(GLfloat s) +{ + SIG( "glTexCoord1f" ); + dllTexCoord1f( s ); +} +static void APIENTRY logTexCoord1fv(const GLfloat *v) +{ + SIG( "glTexCoord1fv" ); + dllTexCoord1fv( v ); +} +static void APIENTRY logTexCoord1i(GLint s) +{ + SIG( "glTexCoord1i" ); + dllTexCoord1i( s ); +} +static void APIENTRY logTexCoord1iv(const GLint *v) +{ + SIG( "glTexCoord1iv" ); + dllTexCoord1iv( v ); +} +static void APIENTRY logTexCoord1s(GLshort s) +{ + SIG( "glTexCoord1s" ); + dllTexCoord1s( s ); +} +static void APIENTRY logTexCoord1sv(const GLshort *v) +{ + SIG( "glTexCoord1sv" ); + dllTexCoord1sv( v ); +} +static void APIENTRY logTexCoord2d(GLdouble s, GLdouble t) +{ + SIG( "glTexCoord2d" ); + dllTexCoord2d( s, t ); +} + +static void APIENTRY logTexCoord2dv(const GLdouble *v) +{ + SIG( "glTexCoord2dv" ); + dllTexCoord2dv( v ); +} +static void APIENTRY logTexCoord2f(GLfloat s, GLfloat t) +{ + SIG( "glTexCoord2f" ); + dllTexCoord2f( s, t ); +} +static void APIENTRY logTexCoord2fv(const GLfloat *v) +{ + SIG( "glTexCoord2fv" ); + dllTexCoord2fv( v ); +} +static void APIENTRY logTexCoord2i(GLint s, GLint t) +{ + SIG( "glTexCoord2i" ); + dllTexCoord2i( s, t ); +} +static void APIENTRY logTexCoord2iv(const GLint *v) +{ + SIG( "glTexCoord2iv" ); + dllTexCoord2iv( v ); +} +static void APIENTRY logTexCoord2s(GLshort s, GLshort t) +{ + SIG( "glTexCoord2s" ); + dllTexCoord2s( s, t ); +} +static void APIENTRY logTexCoord2sv(const GLshort *v) +{ + SIG( "glTexCoord2sv" ); + dllTexCoord2sv( v ); +} +static void APIENTRY logTexCoord3d(GLdouble s, GLdouble t, GLdouble r) +{ + SIG( "glTexCoord3d" ); + dllTexCoord3d( s, t, r ); +} +static void APIENTRY logTexCoord3dv(const GLdouble *v) +{ + SIG( "glTexCoord3dv" ); + dllTexCoord3dv( v ); +} +static void APIENTRY logTexCoord3f(GLfloat s, GLfloat t, GLfloat r) +{ + SIG( "glTexCoord3f" ); + dllTexCoord3f( s, t, r ); +} +static void APIENTRY logTexCoord3fv(const GLfloat *v) +{ + SIG( "glTexCoord3fv" ); + dllTexCoord3fv( v ); +} +static void APIENTRY logTexCoord3i(GLint s, GLint t, GLint r) +{ + SIG( "glTexCoord3i" ); + dllTexCoord3i( s, t, r ); +} +static void APIENTRY logTexCoord3iv(const GLint *v) +{ + SIG( "glTexCoord3iv" ); + dllTexCoord3iv( v ); +} +static void APIENTRY logTexCoord3s(GLshort s, GLshort t, GLshort r) +{ + SIG( "glTexCoord3s" ); + dllTexCoord3s( s, t, r ); +} +static void APIENTRY logTexCoord3sv(const GLshort *v) +{ + SIG( "glTexCoord3sv" ); + dllTexCoord3sv( v ); +} +static void APIENTRY logTexCoord4d(GLdouble s, GLdouble t, GLdouble r, GLdouble q) +{ + SIG( "glTexCoord4d" ); + dllTexCoord4d( s, t, r, q ); +} +static void APIENTRY logTexCoord4dv(const GLdouble *v) +{ + SIG( "glTexCoord4dv" ); + dllTexCoord4dv( v ); +} +static void APIENTRY logTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ + SIG( "glTexCoord4f" ); + dllTexCoord4f( s, t, r, q ); +} +static void APIENTRY logTexCoord4fv(const GLfloat *v) +{ + SIG( "glTexCoord4fv" ); + dllTexCoord4fv( v ); +} +static void APIENTRY logTexCoord4i(GLint s, GLint t, GLint r, GLint q) +{ + SIG( "glTexCoord4i" ); + dllTexCoord4i( s, t, r, q ); +} +static void APIENTRY logTexCoord4iv(const GLint *v) +{ + SIG( "glTexCoord4iv" ); + dllTexCoord4iv( v ); +} +static void APIENTRY logTexCoord4s(GLshort s, GLshort t, GLshort r, GLshort q) +{ + SIG( "glTexCoord4s" ); + dllTexCoord4s( s, t, r, q ); +} +static void APIENTRY logTexCoord4sv(const GLshort *v) +{ + SIG( "glTexCoord4sv" ); + dllTexCoord4sv( v ); +} +static void APIENTRY logTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glTexCoordPointer" ); + dllTexCoordPointer( size, type, stride, pointer ); +} + +static void APIENTRY logTexEnvf(GLenum target, GLenum pname, GLfloat param) +{ + fprintf( glw_state.log_fp, "glTexEnvf( 0x%x, 0x%x, %f )\n", target, pname, param ); + dllTexEnvf( target, pname, param ); +} + +static void APIENTRY logTexEnvfv(GLenum target, GLenum pname, const GLfloat *params) +{ + SIG( "glTexEnvfv" ); + dllTexEnvfv( target, pname, params ); +} + +static void APIENTRY logTexEnvi(GLenum target, GLenum pname, GLint param) +{ + fprintf( glw_state.log_fp, "glTexEnvi( 0x%x, 0x%x, 0x%x )\n", target, pname, param ); + dllTexEnvi( target, pname, param ); +} +static void APIENTRY logTexEnviv(GLenum target, GLenum pname, const GLint *params) +{ + SIG( "glTexEnviv" ); + dllTexEnviv( target, pname, params ); +} + +static void APIENTRY logTexGend(GLenum coord, GLenum pname, GLdouble param) +{ + SIG( "glTexGend" ); + dllTexGend( coord, pname, param ); +} + +static void APIENTRY logTexGendv(GLenum coord, GLenum pname, const GLdouble *params) +{ + SIG( "glTexGendv" ); + dllTexGendv( coord, pname, params ); +} + +static void APIENTRY logTexGenf(GLenum coord, GLenum pname, GLfloat param) +{ + SIG( "glTexGenf" ); + dllTexGenf( coord, pname, param ); +} +static void APIENTRY logTexGenfv(GLenum coord, GLenum pname, const GLfloat *params) +{ + SIG( "glTexGenfv" ); + dllTexGenfv( coord, pname, params ); +} +static void APIENTRY logTexGeni(GLenum coord, GLenum pname, GLint param) +{ + SIG( "glTexGeni" ); + dllTexGeni( coord, pname, param ); +} +static void APIENTRY logTexGeniv(GLenum coord, GLenum pname, const GLint *params) +{ + SIG( "glTexGeniv" ); + dllTexGeniv( coord, pname, params ); +} +static void APIENTRY logTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glTexImage1D" ); + dllTexImage1D( target, level, internalformat, width, border, format, type, pixels ); +} +static void APIENTRY logTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glTexImage2D" ); + dllTexImage2D( target, level, internalformat, width, height, border, format, type, pixels ); +} + +static void APIENTRY logTexParameterf(GLenum target, GLenum pname, GLfloat param) +{ + fprintf( glw_state.log_fp, "glTexParameterf( 0x%x, 0x%x, %f )\n", target, pname, param ); + dllTexParameterf( target, pname, param ); +} + +static void APIENTRY logTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) +{ + SIG( "glTexParameterfv" ); + dllTexParameterfv( target, pname, params ); +} +static void APIENTRY logTexParameteri(GLenum target, GLenum pname, GLint param) +{ + fprintf( glw_state.log_fp, "glTexParameteri( 0x%x, 0x%x, 0x%x )\n", target, pname, param ); + dllTexParameteri( target, pname, param ); +} +static void APIENTRY logTexParameteriv(GLenum target, GLenum pname, const GLint *params) +{ + SIG( "glTexParameteriv" ); + dllTexParameteriv( target, pname, params ); +} +static void APIENTRY logTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glTexSubImage1D" ); + dllTexSubImage1D( target, level, xoffset, width, format, type, pixels ); +} +static void APIENTRY logTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glTexSubImage2D" ); + dllTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, pixels ); +} +static void APIENTRY logTranslated(GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glTranslated" ); + dllTranslated( x, y, z ); +} + +static void APIENTRY logTranslatef(GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glTranslatef" ); + dllTranslatef( x, y, z ); +} + +static void APIENTRY logVertex2d(GLdouble x, GLdouble y) +{ + SIG( "glVertex2d" ); + dllVertex2d( x, y ); +} + +static void APIENTRY logVertex2dv(const GLdouble *v) +{ + SIG( "glVertex2dv" ); + dllVertex2dv( v ); +} +static void APIENTRY logVertex2f(GLfloat x, GLfloat y) +{ + SIG( "glVertex2f" ); + dllVertex2f( x, y ); +} +static void APIENTRY logVertex2fv(const GLfloat *v) +{ + SIG( "glVertex2fv" ); + dllVertex2fv( v ); +} +static void APIENTRY logVertex2i(GLint x, GLint y) +{ + SIG( "glVertex2i" ); + dllVertex2i( x, y ); +} +static void APIENTRY logVertex2iv(const GLint *v) +{ + SIG( "glVertex2iv" ); + dllVertex2iv( v ); +} +static void APIENTRY logVertex2s(GLshort x, GLshort y) +{ + SIG( "glVertex2s" ); + dllVertex2s( x, y ); +} +static void APIENTRY logVertex2sv(const GLshort *v) +{ + SIG( "glVertex2sv" ); + dllVertex2sv( v ); +} +static void APIENTRY logVertex3d(GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glVertex3d" ); + dllVertex3d( x, y, z ); +} +static void APIENTRY logVertex3dv(const GLdouble *v) +{ + SIG( "glVertex3dv" ); + dllVertex3dv( v ); +} +static void APIENTRY logVertex3f(GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glVertex3f" ); + dllVertex3f( x, y, z ); +} +static void APIENTRY logVertex3fv(const GLfloat *v) +{ + SIG( "glVertex3fv" ); + dllVertex3fv( v ); +} +static void APIENTRY logVertex3i(GLint x, GLint y, GLint z) +{ + SIG( "glVertex3i" ); + dllVertex3i( x, y, z ); +} +static void APIENTRY logVertex3iv(const GLint *v) +{ + SIG( "glVertex3iv" ); + dllVertex3iv( v ); +} +static void APIENTRY logVertex3s(GLshort x, GLshort y, GLshort z) +{ + SIG( "glVertex3s" ); + dllVertex3s( x, y, z ); +} +static void APIENTRY logVertex3sv(const GLshort *v) +{ + SIG( "glVertex3sv" ); + dllVertex3sv( v ); +} +static void APIENTRY logVertex4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + SIG( "glVertex4d" ); + dllVertex4d( x, y, z, w ); +} +static void APIENTRY logVertex4dv(const GLdouble *v) +{ + SIG( "glVertex4dv" ); + dllVertex4dv( v ); +} +static void APIENTRY logVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + SIG( "glVertex4f" ); + dllVertex4f( x, y, z, w ); +} +static void APIENTRY logVertex4fv(const GLfloat *v) +{ + SIG( "glVertex4fv" ); + dllVertex4fv( v ); +} +static void APIENTRY logVertex4i(GLint x, GLint y, GLint z, GLint w) +{ + SIG( "glVertex4i" ); + dllVertex4i( x, y, z, w ); +} +static void APIENTRY logVertex4iv(const GLint *v) +{ + SIG( "glVertex4iv" ); + dllVertex4iv( v ); +} +static void APIENTRY logVertex4s(GLshort x, GLshort y, GLshort z, GLshort w) +{ + SIG( "glVertex4s" ); + dllVertex4s( x, y, z, w ); +} +static void APIENTRY logVertex4sv(const GLshort *v) +{ + SIG( "glVertex4sv" ); + dllVertex4sv( v ); +} +static void APIENTRY logVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glVertexPointer" ); + dllVertexPointer( size, type, stride, pointer ); +} +static void APIENTRY logViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + SIG( "glViewport" ); + dllViewport( x, y, width, height ); +} + +/* +** QGL_Shutdown +** +** Unloads the specified DLL then nulls out all the proc pointers. +*/ +void QGL_Shutdown( void ) +{ + if ( glw_state.OpenGLLib ) + { + dlclose ( glw_state.OpenGLLib ); + glw_state.OpenGLLib = NULL; + } + + glw_state.OpenGLLib = NULL; + + qglAccum = NULL; + qglAlphaFunc = NULL; + qglAreTexturesResident = NULL; + qglArrayElement = NULL; + qglBegin = NULL; + qglBindTexture = NULL; + qglBitmap = NULL; + qglBlendFunc = NULL; + qglCallList = NULL; + qglCallLists = NULL; + qglClear = NULL; + qglClearAccum = NULL; + qglClearColor = NULL; + qglClearDepth = NULL; + qglClearIndex = NULL; + qglClearStencil = NULL; + qglClipPlane = NULL; + qglColor3b = NULL; + qglColor3bv = NULL; + qglColor3d = NULL; + qglColor3dv = NULL; + qglColor3f = NULL; + qglColor3fv = NULL; + qglColor3i = NULL; + qglColor3iv = NULL; + qglColor3s = NULL; + qglColor3sv = NULL; + qglColor3ub = NULL; + qglColor3ubv = NULL; + qglColor3ui = NULL; + qglColor3uiv = NULL; + qglColor3us = NULL; + qglColor3usv = NULL; + qglColor4b = NULL; + qglColor4bv = NULL; + qglColor4d = NULL; + qglColor4dv = NULL; + qglColor4f = NULL; + qglColor4fv = NULL; + qglColor4i = NULL; + qglColor4iv = NULL; + qglColor4s = NULL; + qglColor4sv = NULL; + qglColor4ub = NULL; + qglColor4ubv = NULL; + qglColor4ui = NULL; + qglColor4uiv = NULL; + qglColor4us = NULL; + qglColor4usv = NULL; + qglColorMask = NULL; + qglColorMaterial = NULL; + qglColorPointer = NULL; + qglCopyPixels = NULL; + qglCopyTexImage1D = NULL; + qglCopyTexImage2D = NULL; + qglCopyTexSubImage1D = NULL; + qglCopyTexSubImage2D = NULL; + qglCullFace = NULL; + qglDeleteLists = NULL; + qglDeleteTextures = NULL; + qglDepthFunc = NULL; + qglDepthMask = NULL; + qglDepthRange = NULL; + qglDisable = NULL; + qglDisableClientState = NULL; + qglDrawArrays = NULL; + qglDrawBuffer = NULL; + qglDrawElements = NULL; + qglDrawPixels = NULL; + qglEdgeFlag = NULL; + qglEdgeFlagPointer = NULL; + qglEdgeFlagv = NULL; + qglEnable = NULL; + qglEnableClientState = NULL; + qglEnd = NULL; + qglEndList = NULL; + qglEvalCoord1d = NULL; + qglEvalCoord1dv = NULL; + qglEvalCoord1f = NULL; + qglEvalCoord1fv = NULL; + qglEvalCoord2d = NULL; + qglEvalCoord2dv = NULL; + qglEvalCoord2f = NULL; + qglEvalCoord2fv = NULL; + qglEvalMesh1 = NULL; + qglEvalMesh2 = NULL; + qglEvalPoint1 = NULL; + qglEvalPoint2 = NULL; + qglFeedbackBuffer = NULL; + qglFinish = NULL; + qglFlush = NULL; + qglFogf = NULL; + qglFogfv = NULL; + qglFogi = NULL; + qglFogiv = NULL; + qglFrontFace = NULL; + qglFrustum = NULL; + qglGenLists = NULL; + qglGenTextures = NULL; + qglGetBooleanv = NULL; + qglGetClipPlane = NULL; + qglGetDoublev = NULL; + qglGetError = NULL; + qglGetFloatv = NULL; + qglGetIntegerv = NULL; + qglGetLightfv = NULL; + qglGetLightiv = NULL; + qglGetMapdv = NULL; + qglGetMapfv = NULL; + qglGetMapiv = NULL; + qglGetMaterialfv = NULL; + qglGetMaterialiv = NULL; + qglGetPixelMapfv = NULL; + qglGetPixelMapuiv = NULL; + qglGetPixelMapusv = NULL; + qglGetPointerv = NULL; + qglGetPolygonStipple = NULL; + qglGetString = NULL; + qglGetTexEnvfv = NULL; + qglGetTexEnviv = NULL; + qglGetTexGendv = NULL; + qglGetTexGenfv = NULL; + qglGetTexGeniv = NULL; + qglGetTexImage = NULL; + qglGetTexLevelParameterfv = NULL; + qglGetTexLevelParameteriv = NULL; + qglGetTexParameterfv = NULL; + qglGetTexParameteriv = NULL; + qglHint = NULL; + qglIndexMask = NULL; + qglIndexPointer = NULL; + qglIndexd = NULL; + qglIndexdv = NULL; + qglIndexf = NULL; + qglIndexfv = NULL; + qglIndexi = NULL; + qglIndexiv = NULL; + qglIndexs = NULL; + qglIndexsv = NULL; + qglIndexub = NULL; + qglIndexubv = NULL; + qglInitNames = NULL; + qglInterleavedArrays = NULL; + qglIsEnabled = NULL; + qglIsList = NULL; + qglIsTexture = NULL; + qglLightModelf = NULL; + qglLightModelfv = NULL; + qglLightModeli = NULL; + qglLightModeliv = NULL; + qglLightf = NULL; + qglLightfv = NULL; + qglLighti = NULL; + qglLightiv = NULL; + qglLineStipple = NULL; + qglLineWidth = NULL; + qglListBase = NULL; + qglLoadIdentity = NULL; + qglLoadMatrixd = NULL; + qglLoadMatrixf = NULL; + qglLoadName = NULL; + qglLogicOp = NULL; + qglMap1d = NULL; + qglMap1f = NULL; + qglMap2d = NULL; + qglMap2f = NULL; + qglMapGrid1d = NULL; + qglMapGrid1f = NULL; + qglMapGrid2d = NULL; + qglMapGrid2f = NULL; + qglMaterialf = NULL; + qglMaterialfv = NULL; + qglMateriali = NULL; + qglMaterialiv = NULL; + qglMatrixMode = NULL; + qglMultMatrixd = NULL; + qglMultMatrixf = NULL; + qglNewList = NULL; + qglNormal3b = NULL; + qglNormal3bv = NULL; + qglNormal3d = NULL; + qglNormal3dv = NULL; + qglNormal3f = NULL; + qglNormal3fv = NULL; + qglNormal3i = NULL; + qglNormal3iv = NULL; + qglNormal3s = NULL; + qglNormal3sv = NULL; + qglNormalPointer = NULL; + qglOrtho = NULL; + qglPassThrough = NULL; + qglPixelMapfv = NULL; + qglPixelMapuiv = NULL; + qglPixelMapusv = NULL; + qglPixelStoref = NULL; + qglPixelStorei = NULL; + qglPixelTransferf = NULL; + qglPixelTransferi = NULL; + qglPixelZoom = NULL; + qglPointSize = NULL; + qglPolygonMode = NULL; + qglPolygonOffset = NULL; + qglPolygonStipple = NULL; + qglPopAttrib = NULL; + qglPopClientAttrib = NULL; + qglPopMatrix = NULL; + qglPopName = NULL; + qglPrioritizeTextures = NULL; + qglPushAttrib = NULL; + qglPushClientAttrib = NULL; + qglPushMatrix = NULL; + qglPushName = NULL; + qglRasterPos2d = NULL; + qglRasterPos2dv = NULL; + qglRasterPos2f = NULL; + qglRasterPos2fv = NULL; + qglRasterPos2i = NULL; + qglRasterPos2iv = NULL; + qglRasterPos2s = NULL; + qglRasterPos2sv = NULL; + qglRasterPos3d = NULL; + qglRasterPos3dv = NULL; + qglRasterPos3f = NULL; + qglRasterPos3fv = NULL; + qglRasterPos3i = NULL; + qglRasterPos3iv = NULL; + qglRasterPos3s = NULL; + qglRasterPos3sv = NULL; + qglRasterPos4d = NULL; + qglRasterPos4dv = NULL; + qglRasterPos4f = NULL; + qglRasterPos4fv = NULL; + qglRasterPos4i = NULL; + qglRasterPos4iv = NULL; + qglRasterPos4s = NULL; + qglRasterPos4sv = NULL; + qglReadBuffer = NULL; + qglReadPixels = NULL; + qglRectd = NULL; + qglRectdv = NULL; + qglRectf = NULL; + qglRectfv = NULL; + qglRecti = NULL; + qglRectiv = NULL; + qglRects = NULL; + qglRectsv = NULL; + qglRenderMode = NULL; + qglRotated = NULL; + qglRotatef = NULL; + qglScaled = NULL; + qglScalef = NULL; + qglScissor = NULL; + qglSelectBuffer = NULL; + qglShadeModel = NULL; + qglStencilFunc = NULL; + qglStencilMask = NULL; + qglStencilOp = NULL; + qglTexCoord1d = NULL; + qglTexCoord1dv = NULL; + qglTexCoord1f = NULL; + qglTexCoord1fv = NULL; + qglTexCoord1i = NULL; + qglTexCoord1iv = NULL; + qglTexCoord1s = NULL; + qglTexCoord1sv = NULL; + qglTexCoord2d = NULL; + qglTexCoord2dv = NULL; + qglTexCoord2f = NULL; + qglTexCoord2fv = NULL; + qglTexCoord2i = NULL; + qglTexCoord2iv = NULL; + qglTexCoord2s = NULL; + qglTexCoord2sv = NULL; + qglTexCoord3d = NULL; + qglTexCoord3dv = NULL; + qglTexCoord3f = NULL; + qglTexCoord3fv = NULL; + qglTexCoord3i = NULL; + qglTexCoord3iv = NULL; + qglTexCoord3s = NULL; + qglTexCoord3sv = NULL; + qglTexCoord4d = NULL; + qglTexCoord4dv = NULL; + qglTexCoord4f = NULL; + qglTexCoord4fv = NULL; + qglTexCoord4i = NULL; + qglTexCoord4iv = NULL; + qglTexCoord4s = NULL; + qglTexCoord4sv = NULL; + qglTexCoordPointer = NULL; + qglTexEnvf = NULL; + qglTexEnvfv = NULL; + qglTexEnvi = NULL; + qglTexEnviv = NULL; + qglTexGend = NULL; + qglTexGendv = NULL; + qglTexGenf = NULL; + qglTexGenfv = NULL; + qglTexGeni = NULL; + qglTexGeniv = NULL; + qglTexImage1D = NULL; + qglTexImage2D = NULL; + qglTexParameterf = NULL; + qglTexParameterfv = NULL; + qglTexParameteri = NULL; + qglTexParameteriv = NULL; + qglTexSubImage1D = NULL; + qglTexSubImage2D = NULL; + qglTranslated = NULL; + qglTranslatef = NULL; + qglVertex2d = NULL; + qglVertex2dv = NULL; + qglVertex2f = NULL; + qglVertex2fv = NULL; + qglVertex2i = NULL; + qglVertex2iv = NULL; + qglVertex2s = NULL; + qglVertex2sv = NULL; + qglVertex3d = NULL; + qglVertex3dv = NULL; + qglVertex3f = NULL; + qglVertex3fv = NULL; + qglVertex3i = NULL; + qglVertex3iv = NULL; + qglVertex3s = NULL; + qglVertex3sv = NULL; + qglVertex4d = NULL; + qglVertex4dv = NULL; + qglVertex4f = NULL; + qglVertex4fv = NULL; + qglVertex4i = NULL; + qglVertex4iv = NULL; + qglVertex4s = NULL; + qglVertex4sv = NULL; + qglVertexPointer = NULL; + qglViewport = NULL; + +// bk001129 - from cvs1.17 (mkv) +#if defined(__FX__) + qfxMesaCreateContext = NULL; + qfxMesaCreateBestContext = NULL; + qfxMesaDestroyContext = NULL; + qfxMesaMakeCurrent = NULL; + qfxMesaGetCurrentContext = NULL; + qfxMesaSwapBuffers = NULL; +#endif + + qglXChooseVisual = NULL; + qglXCreateContext = NULL; + qglXDestroyContext = NULL; + qglXMakeCurrent = NULL; + qglXCopyContext = NULL; + qglXSwapBuffers = NULL; +} + +#define GPA( a ) dlsym( glw_state.OpenGLLib, a ) + +void *qwglGetProcAddress(char *symbol) +{ + if (glw_state.OpenGLLib) + return GPA ( symbol ); + return NULL; +} + +/* +** QGL_Init +** +** This is responsible for binding our qgl function pointers to +** the appropriate GL stuff. In Windows this means doing a +** LoadLibrary and a bunch of calls to GetProcAddress. On other +** operating systems we need to do the right thing, whatever that +** might be. +** +*/ + +qboolean QGL_Init( const char *dllname ) +{ + if ( ( glw_state.OpenGLLib = dlopen( dllname, RTLD_LAZY|RTLD_GLOBAL ) ) == 0 ) + { + char fn[1024]; + // FILE *fp; // bk001204 - unused + extern uid_t saved_euid; // unix_main.c + + // if we are not setuid, try current directory + if (getuid() == saved_euid) { + getcwd(fn, sizeof(fn)); + Q_strcat(fn, sizeof(fn), "/"); + Q_strcat(fn, sizeof(fn), dllname); + + if ( ( glw_state.OpenGLLib = dlopen( fn, RTLD_LAZY ) ) == 0 ) { + ri.Printf(PRINT_ALL, "QGL_Init: Can't load %s from /etc/ld.so.conf or current dir: %s\n", dllname, dlerror()); + return qfalse; + } + } else { + ri.Printf(PRINT_ALL, "QGL_Init: Can't load %s from /etc/ld.so.conf: %s\n", dllname, dlerror()); + return qfalse; + } + } + + qglAccum = dllAccum = GPA( "glAccum" ); + qglAlphaFunc = dllAlphaFunc = GPA( "glAlphaFunc" ); + qglAreTexturesResident = dllAreTexturesResident = GPA( "glAreTexturesResident" ); + qglArrayElement = dllArrayElement = GPA( "glArrayElement" ); + qglBegin = dllBegin = GPA( "glBegin" ); + qglBindTexture = dllBindTexture = GPA( "glBindTexture" ); + qglBitmap = dllBitmap = GPA( "glBitmap" ); + qglBlendFunc = dllBlendFunc = GPA( "glBlendFunc" ); + qglCallList = dllCallList = GPA( "glCallList" ); + qglCallLists = dllCallLists = GPA( "glCallLists" ); + qglClear = dllClear = GPA( "glClear" ); + qglClearAccum = dllClearAccum = GPA( "glClearAccum" ); + qglClearColor = dllClearColor = GPA( "glClearColor" ); + qglClearDepth = dllClearDepth = GPA( "glClearDepth" ); + qglClearIndex = dllClearIndex = GPA( "glClearIndex" ); + qglClearStencil = dllClearStencil = GPA( "glClearStencil" ); + qglClipPlane = dllClipPlane = GPA( "glClipPlane" ); + qglColor3b = dllColor3b = GPA( "glColor3b" ); + qglColor3bv = dllColor3bv = GPA( "glColor3bv" ); + qglColor3d = dllColor3d = GPA( "glColor3d" ); + qglColor3dv = dllColor3dv = GPA( "glColor3dv" ); + qglColor3f = dllColor3f = GPA( "glColor3f" ); + qglColor3fv = dllColor3fv = GPA( "glColor3fv" ); + qglColor3i = dllColor3i = GPA( "glColor3i" ); + qglColor3iv = dllColor3iv = GPA( "glColor3iv" ); + qglColor3s = dllColor3s = GPA( "glColor3s" ); + qglColor3sv = dllColor3sv = GPA( "glColor3sv" ); + qglColor3ub = dllColor3ub = GPA( "glColor3ub" ); + qglColor3ubv = dllColor3ubv = GPA( "glColor3ubv" ); + qglColor3ui = dllColor3ui = GPA( "glColor3ui" ); + qglColor3uiv = dllColor3uiv = GPA( "glColor3uiv" ); + qglColor3us = dllColor3us = GPA( "glColor3us" ); + qglColor3usv = dllColor3usv = GPA( "glColor3usv" ); + qglColor4b = dllColor4b = GPA( "glColor4b" ); + qglColor4bv = dllColor4bv = GPA( "glColor4bv" ); + qglColor4d = dllColor4d = GPA( "glColor4d" ); + qglColor4dv = dllColor4dv = GPA( "glColor4dv" ); + qglColor4f = dllColor4f = GPA( "glColor4f" ); + qglColor4fv = dllColor4fv = GPA( "glColor4fv" ); + qglColor4i = dllColor4i = GPA( "glColor4i" ); + qglColor4iv = dllColor4iv = GPA( "glColor4iv" ); + qglColor4s = dllColor4s = GPA( "glColor4s" ); + qglColor4sv = dllColor4sv = GPA( "glColor4sv" ); + qglColor4ub = dllColor4ub = GPA( "glColor4ub" ); + qglColor4ubv = dllColor4ubv = GPA( "glColor4ubv" ); + qglColor4ui = dllColor4ui = GPA( "glColor4ui" ); + qglColor4uiv = dllColor4uiv = GPA( "glColor4uiv" ); + qglColor4us = dllColor4us = GPA( "glColor4us" ); + qglColor4usv = dllColor4usv = GPA( "glColor4usv" ); + qglColorMask = dllColorMask = GPA( "glColorMask" ); + qglColorMaterial = dllColorMaterial = GPA( "glColorMaterial" ); + qglColorPointer = dllColorPointer = GPA( "glColorPointer" ); + qglCopyPixels = dllCopyPixels = GPA( "glCopyPixels" ); + qglCopyTexImage1D = dllCopyTexImage1D = GPA( "glCopyTexImage1D" ); + qglCopyTexImage2D = dllCopyTexImage2D = GPA( "glCopyTexImage2D" ); + qglCopyTexSubImage1D = dllCopyTexSubImage1D = GPA( "glCopyTexSubImage1D" ); + qglCopyTexSubImage2D = dllCopyTexSubImage2D = GPA( "glCopyTexSubImage2D" ); + qglCullFace = dllCullFace = GPA( "glCullFace" ); + qglDeleteLists = dllDeleteLists = GPA( "glDeleteLists" ); + qglDeleteTextures = dllDeleteTextures = GPA( "glDeleteTextures" ); + qglDepthFunc = dllDepthFunc = GPA( "glDepthFunc" ); + qglDepthMask = dllDepthMask = GPA( "glDepthMask" ); + qglDepthRange = dllDepthRange = GPA( "glDepthRange" ); + qglDisable = dllDisable = GPA( "glDisable" ); + qglDisableClientState = dllDisableClientState = GPA( "glDisableClientState" ); + qglDrawArrays = dllDrawArrays = GPA( "glDrawArrays" ); + qglDrawBuffer = dllDrawBuffer = GPA( "glDrawBuffer" ); + qglDrawElements = dllDrawElements = GPA( "glDrawElements" ); + qglDrawPixels = dllDrawPixels = GPA( "glDrawPixels" ); + qglEdgeFlag = dllEdgeFlag = GPA( "glEdgeFlag" ); + qglEdgeFlagPointer = dllEdgeFlagPointer = GPA( "glEdgeFlagPointer" ); + qglEdgeFlagv = dllEdgeFlagv = GPA( "glEdgeFlagv" ); + qglEnable = dllEnable = GPA( "glEnable" ); + qglEnableClientState = dllEnableClientState = GPA( "glEnableClientState" ); + qglEnd = dllEnd = GPA( "glEnd" ); + qglEndList = dllEndList = GPA( "glEndList" ); + qglEvalCoord1d = dllEvalCoord1d = GPA( "glEvalCoord1d" ); + qglEvalCoord1dv = dllEvalCoord1dv = GPA( "glEvalCoord1dv" ); + qglEvalCoord1f = dllEvalCoord1f = GPA( "glEvalCoord1f" ); + qglEvalCoord1fv = dllEvalCoord1fv = GPA( "glEvalCoord1fv" ); + qglEvalCoord2d = dllEvalCoord2d = GPA( "glEvalCoord2d" ); + qglEvalCoord2dv = dllEvalCoord2dv = GPA( "glEvalCoord2dv" ); + qglEvalCoord2f = dllEvalCoord2f = GPA( "glEvalCoord2f" ); + qglEvalCoord2fv = dllEvalCoord2fv = GPA( "glEvalCoord2fv" ); + qglEvalMesh1 = dllEvalMesh1 = GPA( "glEvalMesh1" ); + qglEvalMesh2 = dllEvalMesh2 = GPA( "glEvalMesh2" ); + qglEvalPoint1 = dllEvalPoint1 = GPA( "glEvalPoint1" ); + qglEvalPoint2 = dllEvalPoint2 = GPA( "glEvalPoint2" ); + qglFeedbackBuffer = dllFeedbackBuffer = GPA( "glFeedbackBuffer" ); + qglFinish = dllFinish = GPA( "glFinish" ); + qglFlush = dllFlush = GPA( "glFlush" ); + qglFogf = dllFogf = GPA( "glFogf" ); + qglFogfv = dllFogfv = GPA( "glFogfv" ); + qglFogi = dllFogi = GPA( "glFogi" ); + qglFogiv = dllFogiv = GPA( "glFogiv" ); + qglFrontFace = dllFrontFace = GPA( "glFrontFace" ); + qglFrustum = dllFrustum = GPA( "glFrustum" ); + qglGenLists = dllGenLists = GPA( "glGenLists" ); + qglGenTextures = dllGenTextures = GPA( "glGenTextures" ); + qglGetBooleanv = dllGetBooleanv = GPA( "glGetBooleanv" ); + qglGetClipPlane = dllGetClipPlane = GPA( "glGetClipPlane" ); + qglGetDoublev = dllGetDoublev = GPA( "glGetDoublev" ); + qglGetError = dllGetError = GPA( "glGetError" ); + qglGetFloatv = dllGetFloatv = GPA( "glGetFloatv" ); + qglGetIntegerv = dllGetIntegerv = GPA( "glGetIntegerv" ); + qglGetLightfv = dllGetLightfv = GPA( "glGetLightfv" ); + qglGetLightiv = dllGetLightiv = GPA( "glGetLightiv" ); + qglGetMapdv = dllGetMapdv = GPA( "glGetMapdv" ); + qglGetMapfv = dllGetMapfv = GPA( "glGetMapfv" ); + qglGetMapiv = dllGetMapiv = GPA( "glGetMapiv" ); + qglGetMaterialfv = dllGetMaterialfv = GPA( "glGetMaterialfv" ); + qglGetMaterialiv = dllGetMaterialiv = GPA( "glGetMaterialiv" ); + qglGetPixelMapfv = dllGetPixelMapfv = GPA( "glGetPixelMapfv" ); + qglGetPixelMapuiv = dllGetPixelMapuiv = GPA( "glGetPixelMapuiv" ); + qglGetPixelMapusv = dllGetPixelMapusv = GPA( "glGetPixelMapusv" ); + qglGetPointerv = dllGetPointerv = GPA( "glGetPointerv" ); + qglGetPolygonStipple = dllGetPolygonStipple = GPA( "glGetPolygonStipple" ); + qglGetString = dllGetString = GPA( "glGetString" ); + qglGetTexEnvfv = dllGetTexEnvfv = GPA( "glGetTexEnvfv" ); + qglGetTexEnviv = dllGetTexEnviv = GPA( "glGetTexEnviv" ); + qglGetTexGendv = dllGetTexGendv = GPA( "glGetTexGendv" ); + qglGetTexGenfv = dllGetTexGenfv = GPA( "glGetTexGenfv" ); + qglGetTexGeniv = dllGetTexGeniv = GPA( "glGetTexGeniv" ); + qglGetTexImage = dllGetTexImage = GPA( "glGetTexImage" ); + qglGetTexParameterfv = dllGetTexParameterfv = GPA( "glGetTexParameterfv" ); + qglGetTexParameteriv = dllGetTexParameteriv = GPA( "glGetTexParameteriv" ); + qglHint = dllHint = GPA( "glHint" ); + qglIndexMask = dllIndexMask = GPA( "glIndexMask" ); + qglIndexPointer = dllIndexPointer = GPA( "glIndexPointer" ); + qglIndexd = dllIndexd = GPA( "glIndexd" ); + qglIndexdv = dllIndexdv = GPA( "glIndexdv" ); + qglIndexf = dllIndexf = GPA( "glIndexf" ); + qglIndexfv = dllIndexfv = GPA( "glIndexfv" ); + qglIndexi = dllIndexi = GPA( "glIndexi" ); + qglIndexiv = dllIndexiv = GPA( "glIndexiv" ); + qglIndexs = dllIndexs = GPA( "glIndexs" ); + qglIndexsv = dllIndexsv = GPA( "glIndexsv" ); + qglIndexub = dllIndexub = GPA( "glIndexub" ); + qglIndexubv = dllIndexubv = GPA( "glIndexubv" ); + qglInitNames = dllInitNames = GPA( "glInitNames" ); + qglInterleavedArrays = dllInterleavedArrays = GPA( "glInterleavedArrays" ); + qglIsEnabled = dllIsEnabled = GPA( "glIsEnabled" ); + qglIsList = dllIsList = GPA( "glIsList" ); + qglIsTexture = dllIsTexture = GPA( "glIsTexture" ); + qglLightModelf = dllLightModelf = GPA( "glLightModelf" ); + qglLightModelfv = dllLightModelfv = GPA( "glLightModelfv" ); + qglLightModeli = dllLightModeli = GPA( "glLightModeli" ); + qglLightModeliv = dllLightModeliv = GPA( "glLightModeliv" ); + qglLightf = dllLightf = GPA( "glLightf" ); + qglLightfv = dllLightfv = GPA( "glLightfv" ); + qglLighti = dllLighti = GPA( "glLighti" ); + qglLightiv = dllLightiv = GPA( "glLightiv" ); + qglLineStipple = dllLineStipple = GPA( "glLineStipple" ); + qglLineWidth = dllLineWidth = GPA( "glLineWidth" ); + qglListBase = dllListBase = GPA( "glListBase" ); + qglLoadIdentity = dllLoadIdentity = GPA( "glLoadIdentity" ); + qglLoadMatrixd = dllLoadMatrixd = GPA( "glLoadMatrixd" ); + qglLoadMatrixf = dllLoadMatrixf = GPA( "glLoadMatrixf" ); + qglLoadName = dllLoadName = GPA( "glLoadName" ); + qglLogicOp = dllLogicOp = GPA( "glLogicOp" ); + qglMap1d = dllMap1d = GPA( "glMap1d" ); + qglMap1f = dllMap1f = GPA( "glMap1f" ); + qglMap2d = dllMap2d = GPA( "glMap2d" ); + qglMap2f = dllMap2f = GPA( "glMap2f" ); + qglMapGrid1d = dllMapGrid1d = GPA( "glMapGrid1d" ); + qglMapGrid1f = dllMapGrid1f = GPA( "glMapGrid1f" ); + qglMapGrid2d = dllMapGrid2d = GPA( "glMapGrid2d" ); + qglMapGrid2f = dllMapGrid2f = GPA( "glMapGrid2f" ); + qglMaterialf = dllMaterialf = GPA( "glMaterialf" ); + qglMaterialfv = dllMaterialfv = GPA( "glMaterialfv" ); + qglMateriali = dllMateriali = GPA( "glMateriali" ); + qglMaterialiv = dllMaterialiv = GPA( "glMaterialiv" ); + qglMatrixMode = dllMatrixMode = GPA( "glMatrixMode" ); + qglMultMatrixd = dllMultMatrixd = GPA( "glMultMatrixd" ); + qglMultMatrixf = dllMultMatrixf = GPA( "glMultMatrixf" ); + qglNewList = dllNewList = GPA( "glNewList" ); + qglNormal3b = dllNormal3b = GPA( "glNormal3b" ); + qglNormal3bv = dllNormal3bv = GPA( "glNormal3bv" ); + qglNormal3d = dllNormal3d = GPA( "glNormal3d" ); + qglNormal3dv = dllNormal3dv = GPA( "glNormal3dv" ); + qglNormal3f = dllNormal3f = GPA( "glNormal3f" ); + qglNormal3fv = dllNormal3fv = GPA( "glNormal3fv" ); + qglNormal3i = dllNormal3i = GPA( "glNormal3i" ); + qglNormal3iv = dllNormal3iv = GPA( "glNormal3iv" ); + qglNormal3s = dllNormal3s = GPA( "glNormal3s" ); + qglNormal3sv = dllNormal3sv = GPA( "glNormal3sv" ); + qglNormalPointer = dllNormalPointer = GPA( "glNormalPointer" ); + qglOrtho = dllOrtho = GPA( "glOrtho" ); + qglPassThrough = dllPassThrough = GPA( "glPassThrough" ); + qglPixelMapfv = dllPixelMapfv = GPA( "glPixelMapfv" ); + qglPixelMapuiv = dllPixelMapuiv = GPA( "glPixelMapuiv" ); + qglPixelMapusv = dllPixelMapusv = GPA( "glPixelMapusv" ); + qglPixelStoref = dllPixelStoref = GPA( "glPixelStoref" ); + qglPixelStorei = dllPixelStorei = GPA( "glPixelStorei" ); + qglPixelTransferf = dllPixelTransferf = GPA( "glPixelTransferf" ); + qglPixelTransferi = dllPixelTransferi = GPA( "glPixelTransferi" ); + qglPixelZoom = dllPixelZoom = GPA( "glPixelZoom" ); + qglPointSize = dllPointSize = GPA( "glPointSize" ); + qglPolygonMode = dllPolygonMode = GPA( "glPolygonMode" ); + qglPolygonOffset = dllPolygonOffset = GPA( "glPolygonOffset" ); + qglPolygonStipple = dllPolygonStipple = GPA( "glPolygonStipple" ); + qglPopAttrib = dllPopAttrib = GPA( "glPopAttrib" ); + qglPopClientAttrib = dllPopClientAttrib = GPA( "glPopClientAttrib" ); + qglPopMatrix = dllPopMatrix = GPA( "glPopMatrix" ); + qglPopName = dllPopName = GPA( "glPopName" ); + qglPrioritizeTextures = dllPrioritizeTextures = GPA( "glPrioritizeTextures" ); + qglPushAttrib = dllPushAttrib = GPA( "glPushAttrib" ); + qglPushClientAttrib = dllPushClientAttrib = GPA( "glPushClientAttrib" ); + qglPushMatrix = dllPushMatrix = GPA( "glPushMatrix" ); + qglPushName = dllPushName = GPA( "glPushName" ); + qglRasterPos2d = dllRasterPos2d = GPA( "glRasterPos2d" ); + qglRasterPos2dv = dllRasterPos2dv = GPA( "glRasterPos2dv" ); + qglRasterPos2f = dllRasterPos2f = GPA( "glRasterPos2f" ); + qglRasterPos2fv = dllRasterPos2fv = GPA( "glRasterPos2fv" ); + qglRasterPos2i = dllRasterPos2i = GPA( "glRasterPos2i" ); + qglRasterPos2iv = dllRasterPos2iv = GPA( "glRasterPos2iv" ); + qglRasterPos2s = dllRasterPos2s = GPA( "glRasterPos2s" ); + qglRasterPos2sv = dllRasterPos2sv = GPA( "glRasterPos2sv" ); + qglRasterPos3d = dllRasterPos3d = GPA( "glRasterPos3d" ); + qglRasterPos3dv = dllRasterPos3dv = GPA( "glRasterPos3dv" ); + qglRasterPos3f = dllRasterPos3f = GPA( "glRasterPos3f" ); + qglRasterPos3fv = dllRasterPos3fv = GPA( "glRasterPos3fv" ); + qglRasterPos3i = dllRasterPos3i = GPA( "glRasterPos3i" ); + qglRasterPos3iv = dllRasterPos3iv = GPA( "glRasterPos3iv" ); + qglRasterPos3s = dllRasterPos3s = GPA( "glRasterPos3s" ); + qglRasterPos3sv = dllRasterPos3sv = GPA( "glRasterPos3sv" ); + qglRasterPos4d = dllRasterPos4d = GPA( "glRasterPos4d" ); + qglRasterPos4dv = dllRasterPos4dv = GPA( "glRasterPos4dv" ); + qglRasterPos4f = dllRasterPos4f = GPA( "glRasterPos4f" ); + qglRasterPos4fv = dllRasterPos4fv = GPA( "glRasterPos4fv" ); + qglRasterPos4i = dllRasterPos4i = GPA( "glRasterPos4i" ); + qglRasterPos4iv = dllRasterPos4iv = GPA( "glRasterPos4iv" ); + qglRasterPos4s = dllRasterPos4s = GPA( "glRasterPos4s" ); + qglRasterPos4sv = dllRasterPos4sv = GPA( "glRasterPos4sv" ); + qglReadBuffer = dllReadBuffer = GPA( "glReadBuffer" ); + qglReadPixels = dllReadPixels = GPA( "glReadPixels" ); + qglRectd = dllRectd = GPA( "glRectd" ); + qglRectdv = dllRectdv = GPA( "glRectdv" ); + qglRectf = dllRectf = GPA( "glRectf" ); + qglRectfv = dllRectfv = GPA( "glRectfv" ); + qglRecti = dllRecti = GPA( "glRecti" ); + qglRectiv = dllRectiv = GPA( "glRectiv" ); + qglRects = dllRects = GPA( "glRects" ); + qglRectsv = dllRectsv = GPA( "glRectsv" ); + qglRenderMode = dllRenderMode = GPA( "glRenderMode" ); + qglRotated = dllRotated = GPA( "glRotated" ); + qglRotatef = dllRotatef = GPA( "glRotatef" ); + qglScaled = dllScaled = GPA( "glScaled" ); + qglScalef = dllScalef = GPA( "glScalef" ); + qglScissor = dllScissor = GPA( "glScissor" ); + qglSelectBuffer = dllSelectBuffer = GPA( "glSelectBuffer" ); + qglShadeModel = dllShadeModel = GPA( "glShadeModel" ); + qglStencilFunc = dllStencilFunc = GPA( "glStencilFunc" ); + qglStencilMask = dllStencilMask = GPA( "glStencilMask" ); + qglStencilOp = dllStencilOp = GPA( "glStencilOp" ); + qglTexCoord1d = dllTexCoord1d = GPA( "glTexCoord1d" ); + qglTexCoord1dv = dllTexCoord1dv = GPA( "glTexCoord1dv" ); + qglTexCoord1f = dllTexCoord1f = GPA( "glTexCoord1f" ); + qglTexCoord1fv = dllTexCoord1fv = GPA( "glTexCoord1fv" ); + qglTexCoord1i = dllTexCoord1i = GPA( "glTexCoord1i" ); + qglTexCoord1iv = dllTexCoord1iv = GPA( "glTexCoord1iv" ); + qglTexCoord1s = dllTexCoord1s = GPA( "glTexCoord1s" ); + qglTexCoord1sv = dllTexCoord1sv = GPA( "glTexCoord1sv" ); + qglTexCoord2d = dllTexCoord2d = GPA( "glTexCoord2d" ); + qglTexCoord2dv = dllTexCoord2dv = GPA( "glTexCoord2dv" ); + qglTexCoord2f = dllTexCoord2f = GPA( "glTexCoord2f" ); + qglTexCoord2fv = dllTexCoord2fv = GPA( "glTexCoord2fv" ); + qglTexCoord2i = dllTexCoord2i = GPA( "glTexCoord2i" ); + qglTexCoord2iv = dllTexCoord2iv = GPA( "glTexCoord2iv" ); + qglTexCoord2s = dllTexCoord2s = GPA( "glTexCoord2s" ); + qglTexCoord2sv = dllTexCoord2sv = GPA( "glTexCoord2sv" ); + qglTexCoord3d = dllTexCoord3d = GPA( "glTexCoord3d" ); + qglTexCoord3dv = dllTexCoord3dv = GPA( "glTexCoord3dv" ); + qglTexCoord3f = dllTexCoord3f = GPA( "glTexCoord3f" ); + qglTexCoord3fv = dllTexCoord3fv = GPA( "glTexCoord3fv" ); + qglTexCoord3i = dllTexCoord3i = GPA( "glTexCoord3i" ); + qglTexCoord3iv = dllTexCoord3iv = GPA( "glTexCoord3iv" ); + qglTexCoord3s = dllTexCoord3s = GPA( "glTexCoord3s" ); + qglTexCoord3sv = dllTexCoord3sv = GPA( "glTexCoord3sv" ); + qglTexCoord4d = dllTexCoord4d = GPA( "glTexCoord4d" ); + qglTexCoord4dv = dllTexCoord4dv = GPA( "glTexCoord4dv" ); + qglTexCoord4f = dllTexCoord4f = GPA( "glTexCoord4f" ); + qglTexCoord4fv = dllTexCoord4fv = GPA( "glTexCoord4fv" ); + qglTexCoord4i = dllTexCoord4i = GPA( "glTexCoord4i" ); + qglTexCoord4iv = dllTexCoord4iv = GPA( "glTexCoord4iv" ); + qglTexCoord4s = dllTexCoord4s = GPA( "glTexCoord4s" ); + qglTexCoord4sv = dllTexCoord4sv = GPA( "glTexCoord4sv" ); + qglTexCoordPointer = dllTexCoordPointer = GPA( "glTexCoordPointer" ); + qglTexEnvf = dllTexEnvf = GPA( "glTexEnvf" ); + qglTexEnvfv = dllTexEnvfv = GPA( "glTexEnvfv" ); + qglTexEnvi = dllTexEnvi = GPA( "glTexEnvi" ); + qglTexEnviv = dllTexEnviv = GPA( "glTexEnviv" ); + qglTexGend = dllTexGend = GPA( "glTexGend" ); + qglTexGendv = dllTexGendv = GPA( "glTexGendv" ); + qglTexGenf = dllTexGenf = GPA( "glTexGenf" ); + qglTexGenfv = dllTexGenfv = GPA( "glTexGenfv" ); + qglTexGeni = dllTexGeni = GPA( "glTexGeni" ); + qglTexGeniv = dllTexGeniv = GPA( "glTexGeniv" ); + qglTexImage1D = dllTexImage1D = GPA( "glTexImage1D" ); + qglTexImage2D = dllTexImage2D = GPA( "glTexImage2D" ); + qglTexParameterf = dllTexParameterf = GPA( "glTexParameterf" ); + qglTexParameterfv = dllTexParameterfv = GPA( "glTexParameterfv" ); + qglTexParameteri = dllTexParameteri = GPA( "glTexParameteri" ); + qglTexParameteriv = dllTexParameteriv = GPA( "glTexParameteriv" ); + qglTexSubImage1D = dllTexSubImage1D = GPA( "glTexSubImage1D" ); + qglTexSubImage2D = dllTexSubImage2D = GPA( "glTexSubImage2D" ); + qglTranslated = dllTranslated = GPA( "glTranslated" ); + qglTranslatef = dllTranslatef = GPA( "glTranslatef" ); + qglVertex2d = dllVertex2d = GPA( "glVertex2d" ); + qglVertex2dv = dllVertex2dv = GPA( "glVertex2dv" ); + qglVertex2f = dllVertex2f = GPA( "glVertex2f" ); + qglVertex2fv = dllVertex2fv = GPA( "glVertex2fv" ); + qglVertex2i = dllVertex2i = GPA( "glVertex2i" ); + qglVertex2iv = dllVertex2iv = GPA( "glVertex2iv" ); + qglVertex2s = dllVertex2s = GPA( "glVertex2s" ); + qglVertex2sv = dllVertex2sv = GPA( "glVertex2sv" ); + qglVertex3d = dllVertex3d = GPA( "glVertex3d" ); + qglVertex3dv = dllVertex3dv = GPA( "glVertex3dv" ); + qglVertex3f = dllVertex3f = GPA( "glVertex3f" ); + qglVertex3fv = dllVertex3fv = GPA( "glVertex3fv" ); + qglVertex3i = dllVertex3i = GPA( "glVertex3i" ); + qglVertex3iv = dllVertex3iv = GPA( "glVertex3iv" ); + qglVertex3s = dllVertex3s = GPA( "glVertex3s" ); + qglVertex3sv = dllVertex3sv = GPA( "glVertex3sv" ); + qglVertex4d = dllVertex4d = GPA( "glVertex4d" ); + qglVertex4dv = dllVertex4dv = GPA( "glVertex4dv" ); + qglVertex4f = dllVertex4f = GPA( "glVertex4f" ); + qglVertex4fv = dllVertex4fv = GPA( "glVertex4fv" ); + qglVertex4i = dllVertex4i = GPA( "glVertex4i" ); + qglVertex4iv = dllVertex4iv = GPA( "glVertex4iv" ); + qglVertex4s = dllVertex4s = GPA( "glVertex4s" ); + qglVertex4sv = dllVertex4sv = GPA( "glVertex4sv" ); + qglVertexPointer = dllVertexPointer = GPA( "glVertexPointer" ); + qglViewport = dllViewport = GPA( "glViewport" ); + +// bk001129 - from cvs1.17 (mkv) +#if defined(__FX__) + qfxMesaCreateContext = GPA("fxMesaCreateContext"); + qfxMesaCreateBestContext = GPA("fxMesaCreateBestContext"); + qfxMesaDestroyContext = GPA("fxMesaDestroyContext"); + qfxMesaMakeCurrent = GPA("fxMesaMakeCurrent"); + qfxMesaGetCurrentContext = GPA("fxMesaGetCurrentContext"); + qfxMesaSwapBuffers = GPA("fxMesaSwapBuffers"); +#endif + + qglXChooseVisual = GPA("glXChooseVisual"); + qglXCreateContext = GPA("glXCreateContext"); + qglXDestroyContext = GPA("glXDestroyContext"); + qglXMakeCurrent = GPA("glXMakeCurrent"); + qglXCopyContext = GPA("glXCopyContext"); + qglXSwapBuffers = GPA("glXSwapBuffers"); + + qglLockArraysEXT = 0; + qglUnlockArraysEXT = 0; + qglPointParameterfEXT = 0; + qglPointParameterfvEXT = 0; + qglColorTableEXT = 0; + qgl3DfxSetPaletteEXT = 0; + qglSelectTextureSGIS = 0; + qglMTexCoord2fSGIS = 0; + qglActiveTextureARB = 0; + qglClientActiveTextureARB = 0; + qglMultiTexCoord2fARB = 0; + + return qtrue; +} + +void QGL_EnableLogging( qboolean enable ) { + // bk001205 - fixed for new countdown + static qboolean isEnabled = qfalse; // init + + // return if we're already active + if ( isEnabled && enable ) { + // decrement log counter and stop if it has reached 0 + ri.Cvar_Set( "r_logFile", va("%d", r_logFile->integer - 1 ) ); + if ( r_logFile->integer ) { + return; + } + enable = qfalse; + } + + // return if we're already disabled + if ( !enable && !isEnabled ) + return; + + isEnabled = enable; + + // bk001205 - old code starts here + if ( enable ) { + if ( !glw_state.log_fp ) { + struct tm *newtime; + time_t aclock; + char buffer[1024]; + cvar_t *basedir; + + time( &aclock ); + newtime = localtime( &aclock ); + + asctime( newtime ); + + basedir = ri.Cvar_Get( "fs_basepath", "", 0 ); // FIXME: userdir? + assert(basedir); + Com_sprintf( buffer, sizeof(buffer), "%s/gl.log", basedir->string ); + glw_state.log_fp = fopen( buffer, "wt" ); + assert(glw_state.log_fp); + ri.Printf(PRINT_ALL, "QGL_EnableLogging(%d): writing %s\n", r_logFile->integer, buffer ); + + fprintf( glw_state.log_fp, "%s\n", asctime( newtime ) ); + } + + qglAccum = logAccum; + qglAlphaFunc = logAlphaFunc; + qglAreTexturesResident = logAreTexturesResident; + qglArrayElement = logArrayElement; + qglBegin = logBegin; + qglBindTexture = logBindTexture; + qglBitmap = logBitmap; + qglBlendFunc = logBlendFunc; + qglCallList = logCallList; + qglCallLists = logCallLists; + qglClear = logClear; + qglClearAccum = logClearAccum; + qglClearColor = logClearColor; + qglClearDepth = logClearDepth; + qglClearIndex = logClearIndex; + qglClearStencil = logClearStencil; + qglClipPlane = logClipPlane; + qglColor3b = logColor3b; + qglColor3bv = logColor3bv; + qglColor3d = logColor3d; + qglColor3dv = logColor3dv; + qglColor3f = logColor3f; + qglColor3fv = logColor3fv; + qglColor3i = logColor3i; + qglColor3iv = logColor3iv; + qglColor3s = logColor3s; + qglColor3sv = logColor3sv; + qglColor3ub = logColor3ub; + qglColor3ubv = logColor3ubv; + qglColor3ui = logColor3ui; + qglColor3uiv = logColor3uiv; + qglColor3us = logColor3us; + qglColor3usv = logColor3usv; + qglColor4b = logColor4b; + qglColor4bv = logColor4bv; + qglColor4d = logColor4d; + qglColor4dv = logColor4dv; + qglColor4f = logColor4f; + qglColor4fv = logColor4fv; + qglColor4i = logColor4i; + qglColor4iv = logColor4iv; + qglColor4s = logColor4s; + qglColor4sv = logColor4sv; + qglColor4ub = logColor4ub; + qglColor4ubv = logColor4ubv; + qglColor4ui = logColor4ui; + qglColor4uiv = logColor4uiv; + qglColor4us = logColor4us; + qglColor4usv = logColor4usv; + qglColorMask = logColorMask; + qglColorMaterial = logColorMaterial; + qglColorPointer = logColorPointer; + qglCopyPixels = logCopyPixels; + qglCopyTexImage1D = logCopyTexImage1D; + qglCopyTexImage2D = logCopyTexImage2D; + qglCopyTexSubImage1D = logCopyTexSubImage1D; + qglCopyTexSubImage2D = logCopyTexSubImage2D; + qglCullFace = logCullFace; + qglDeleteLists = logDeleteLists ; + qglDeleteTextures = logDeleteTextures ; + qglDepthFunc = logDepthFunc ; + qglDepthMask = logDepthMask ; + qglDepthRange = logDepthRange ; + qglDisable = logDisable ; + qglDisableClientState = logDisableClientState ; + qglDrawArrays = logDrawArrays ; + qglDrawBuffer = logDrawBuffer ; + qglDrawElements = logDrawElements ; + qglDrawPixels = logDrawPixels ; + qglEdgeFlag = logEdgeFlag ; + qglEdgeFlagPointer = logEdgeFlagPointer ; + qglEdgeFlagv = logEdgeFlagv ; + qglEnable = logEnable ; + qglEnableClientState = logEnableClientState ; + qglEnd = logEnd ; + qglEndList = logEndList ; + qglEvalCoord1d = logEvalCoord1d ; + qglEvalCoord1dv = logEvalCoord1dv ; + qglEvalCoord1f = logEvalCoord1f ; + qglEvalCoord1fv = logEvalCoord1fv ; + qglEvalCoord2d = logEvalCoord2d ; + qglEvalCoord2dv = logEvalCoord2dv ; + qglEvalCoord2f = logEvalCoord2f ; + qglEvalCoord2fv = logEvalCoord2fv ; + qglEvalMesh1 = logEvalMesh1 ; + qglEvalMesh2 = logEvalMesh2 ; + qglEvalPoint1 = logEvalPoint1 ; + qglEvalPoint2 = logEvalPoint2 ; + qglFeedbackBuffer = logFeedbackBuffer ; + qglFinish = logFinish ; + qglFlush = logFlush ; + qglFogf = logFogf ; + qglFogfv = logFogfv ; + qglFogi = logFogi ; + qglFogiv = logFogiv ; + qglFrontFace = logFrontFace ; + qglFrustum = logFrustum ; + qglGenLists = logGenLists ; + qglGenTextures = logGenTextures ; + qglGetBooleanv = logGetBooleanv ; + qglGetClipPlane = logGetClipPlane ; + qglGetDoublev = logGetDoublev ; + qglGetError = logGetError ; + qglGetFloatv = logGetFloatv ; + qglGetIntegerv = logGetIntegerv ; + qglGetLightfv = logGetLightfv ; + qglGetLightiv = logGetLightiv ; + qglGetMapdv = logGetMapdv ; + qglGetMapfv = logGetMapfv ; + qglGetMapiv = logGetMapiv ; + qglGetMaterialfv = logGetMaterialfv ; + qglGetMaterialiv = logGetMaterialiv ; + qglGetPixelMapfv = logGetPixelMapfv ; + qglGetPixelMapuiv = logGetPixelMapuiv ; + qglGetPixelMapusv = logGetPixelMapusv ; + qglGetPointerv = logGetPointerv ; + qglGetPolygonStipple = logGetPolygonStipple ; + qglGetString = logGetString ; + qglGetTexEnvfv = logGetTexEnvfv ; + qglGetTexEnviv = logGetTexEnviv ; + qglGetTexGendv = logGetTexGendv ; + qglGetTexGenfv = logGetTexGenfv ; + qglGetTexGeniv = logGetTexGeniv ; + qglGetTexImage = logGetTexImage ; + qglGetTexLevelParameterfv = logGetTexLevelParameterfv ; + qglGetTexLevelParameteriv = logGetTexLevelParameteriv ; + qglGetTexParameterfv = logGetTexParameterfv ; + qglGetTexParameteriv = logGetTexParameteriv ; + qglHint = logHint ; + qglIndexMask = logIndexMask ; + qglIndexPointer = logIndexPointer ; + qglIndexd = logIndexd ; + qglIndexdv = logIndexdv ; + qglIndexf = logIndexf ; + qglIndexfv = logIndexfv ; + qglIndexi = logIndexi ; + qglIndexiv = logIndexiv ; + qglIndexs = logIndexs ; + qglIndexsv = logIndexsv ; + qglIndexub = logIndexub ; + qglIndexubv = logIndexubv ; + qglInitNames = logInitNames ; + qglInterleavedArrays = logInterleavedArrays ; + qglIsEnabled = logIsEnabled ; + qglIsList = logIsList ; + qglIsTexture = logIsTexture ; + qglLightModelf = logLightModelf ; + qglLightModelfv = logLightModelfv ; + qglLightModeli = logLightModeli ; + qglLightModeliv = logLightModeliv ; + qglLightf = logLightf ; + qglLightfv = logLightfv ; + qglLighti = logLighti ; + qglLightiv = logLightiv ; + qglLineStipple = logLineStipple ; + qglLineWidth = logLineWidth ; + qglListBase = logListBase ; + qglLoadIdentity = logLoadIdentity ; + qglLoadMatrixd = logLoadMatrixd ; + qglLoadMatrixf = logLoadMatrixf ; + qglLoadName = logLoadName ; + qglLogicOp = logLogicOp ; + qglMap1d = logMap1d ; + qglMap1f = logMap1f ; + qglMap2d = logMap2d ; + qglMap2f = logMap2f ; + qglMapGrid1d = logMapGrid1d ; + qglMapGrid1f = logMapGrid1f ; + qglMapGrid2d = logMapGrid2d ; + qglMapGrid2f = logMapGrid2f ; + qglMaterialf = logMaterialf ; + qglMaterialfv = logMaterialfv ; + qglMateriali = logMateriali ; + qglMaterialiv = logMaterialiv ; + qglMatrixMode = logMatrixMode ; + qglMultMatrixd = logMultMatrixd ; + qglMultMatrixf = logMultMatrixf ; + qglNewList = logNewList ; + qglNormal3b = logNormal3b ; + qglNormal3bv = logNormal3bv ; + qglNormal3d = logNormal3d ; + qglNormal3dv = logNormal3dv ; + qglNormal3f = logNormal3f ; + qglNormal3fv = logNormal3fv ; + qglNormal3i = logNormal3i ; + qglNormal3iv = logNormal3iv ; + qglNormal3s = logNormal3s ; + qglNormal3sv = logNormal3sv ; + qglNormalPointer = logNormalPointer ; + qglOrtho = logOrtho ; + qglPassThrough = logPassThrough ; + qglPixelMapfv = logPixelMapfv ; + qglPixelMapuiv = logPixelMapuiv ; + qglPixelMapusv = logPixelMapusv ; + qglPixelStoref = logPixelStoref ; + qglPixelStorei = logPixelStorei ; + qglPixelTransferf = logPixelTransferf ; + qglPixelTransferi = logPixelTransferi ; + qglPixelZoom = logPixelZoom ; + qglPointSize = logPointSize ; + qglPolygonMode = logPolygonMode ; + qglPolygonOffset = logPolygonOffset ; + qglPolygonStipple = logPolygonStipple ; + qglPopAttrib = logPopAttrib ; + qglPopClientAttrib = logPopClientAttrib ; + qglPopMatrix = logPopMatrix ; + qglPopName = logPopName ; + qglPrioritizeTextures = logPrioritizeTextures ; + qglPushAttrib = logPushAttrib ; + qglPushClientAttrib = logPushClientAttrib ; + qglPushMatrix = logPushMatrix ; + qglPushName = logPushName ; + qglRasterPos2d = logRasterPos2d ; + qglRasterPos2dv = logRasterPos2dv ; + qglRasterPos2f = logRasterPos2f ; + qglRasterPos2fv = logRasterPos2fv ; + qglRasterPos2i = logRasterPos2i ; + qglRasterPos2iv = logRasterPos2iv ; + qglRasterPos2s = logRasterPos2s ; + qglRasterPos2sv = logRasterPos2sv ; + qglRasterPos3d = logRasterPos3d ; + qglRasterPos3dv = logRasterPos3dv ; + qglRasterPos3f = logRasterPos3f ; + qglRasterPos3fv = logRasterPos3fv ; + qglRasterPos3i = logRasterPos3i ; + qglRasterPos3iv = logRasterPos3iv ; + qglRasterPos3s = logRasterPos3s ; + qglRasterPos3sv = logRasterPos3sv ; + qglRasterPos4d = logRasterPos4d ; + qglRasterPos4dv = logRasterPos4dv ; + qglRasterPos4f = logRasterPos4f ; + qglRasterPos4fv = logRasterPos4fv ; + qglRasterPos4i = logRasterPos4i ; + qglRasterPos4iv = logRasterPos4iv ; + qglRasterPos4s = logRasterPos4s ; + qglRasterPos4sv = logRasterPos4sv ; + qglReadBuffer = logReadBuffer ; + qglReadPixels = logReadPixels ; + qglRectd = logRectd ; + qglRectdv = logRectdv ; + qglRectf = logRectf ; + qglRectfv = logRectfv ; + qglRecti = logRecti ; + qglRectiv = logRectiv ; + qglRects = logRects ; + qglRectsv = logRectsv ; + qglRenderMode = logRenderMode ; + qglRotated = logRotated ; + qglRotatef = logRotatef ; + qglScaled = logScaled ; + qglScalef = logScalef ; + qglScissor = logScissor ; + qglSelectBuffer = logSelectBuffer ; + qglShadeModel = logShadeModel ; + qglStencilFunc = logStencilFunc ; + qglStencilMask = logStencilMask ; + qglStencilOp = logStencilOp ; + qglTexCoord1d = logTexCoord1d ; + qglTexCoord1dv = logTexCoord1dv ; + qglTexCoord1f = logTexCoord1f ; + qglTexCoord1fv = logTexCoord1fv ; + qglTexCoord1i = logTexCoord1i ; + qglTexCoord1iv = logTexCoord1iv ; + qglTexCoord1s = logTexCoord1s ; + qglTexCoord1sv = logTexCoord1sv ; + qglTexCoord2d = logTexCoord2d ; + qglTexCoord2dv = logTexCoord2dv ; + qglTexCoord2f = logTexCoord2f ; + qglTexCoord2fv = logTexCoord2fv ; + qglTexCoord2i = logTexCoord2i ; + qglTexCoord2iv = logTexCoord2iv ; + qglTexCoord2s = logTexCoord2s ; + qglTexCoord2sv = logTexCoord2sv ; + qglTexCoord3d = logTexCoord3d ; + qglTexCoord3dv = logTexCoord3dv ; + qglTexCoord3f = logTexCoord3f ; + qglTexCoord3fv = logTexCoord3fv ; + qglTexCoord3i = logTexCoord3i ; + qglTexCoord3iv = logTexCoord3iv ; + qglTexCoord3s = logTexCoord3s ; + qglTexCoord3sv = logTexCoord3sv ; + qglTexCoord4d = logTexCoord4d ; + qglTexCoord4dv = logTexCoord4dv ; + qglTexCoord4f = logTexCoord4f ; + qglTexCoord4fv = logTexCoord4fv ; + qglTexCoord4i = logTexCoord4i ; + qglTexCoord4iv = logTexCoord4iv ; + qglTexCoord4s = logTexCoord4s ; + qglTexCoord4sv = logTexCoord4sv ; + qglTexCoordPointer = logTexCoordPointer ; + qglTexEnvf = logTexEnvf ; + qglTexEnvfv = logTexEnvfv ; + qglTexEnvi = logTexEnvi ; + qglTexEnviv = logTexEnviv ; + qglTexGend = logTexGend ; + qglTexGendv = logTexGendv ; + qglTexGenf = logTexGenf ; + qglTexGenfv = logTexGenfv ; + qglTexGeni = logTexGeni ; + qglTexGeniv = logTexGeniv ; + qglTexImage1D = logTexImage1D ; + qglTexImage2D = logTexImage2D ; + qglTexParameterf = logTexParameterf ; + qglTexParameterfv = logTexParameterfv ; + qglTexParameteri = logTexParameteri ; + qglTexParameteriv = logTexParameteriv ; + qglTexSubImage1D = logTexSubImage1D ; + qglTexSubImage2D = logTexSubImage2D ; + qglTranslated = logTranslated ; + qglTranslatef = logTranslatef ; + qglVertex2d = logVertex2d ; + qglVertex2dv = logVertex2dv ; + qglVertex2f = logVertex2f ; + qglVertex2fv = logVertex2fv ; + qglVertex2i = logVertex2i ; + qglVertex2iv = logVertex2iv ; + qglVertex2s = logVertex2s ; + qglVertex2sv = logVertex2sv ; + qglVertex3d = logVertex3d ; + qglVertex3dv = logVertex3dv ; + qglVertex3f = logVertex3f ; + qglVertex3fv = logVertex3fv ; + qglVertex3i = logVertex3i ; + qglVertex3iv = logVertex3iv ; + qglVertex3s = logVertex3s ; + qglVertex3sv = logVertex3sv ; + qglVertex4d = logVertex4d ; + qglVertex4dv = logVertex4dv ; + qglVertex4f = logVertex4f ; + qglVertex4fv = logVertex4fv ; + qglVertex4i = logVertex4i ; + qglVertex4iv = logVertex4iv ; + qglVertex4s = logVertex4s ; + qglVertex4sv = logVertex4sv ; + qglVertexPointer = logVertexPointer ; + qglViewport = logViewport ; + } + else + { + qglAccum = dllAccum; + qglAlphaFunc = dllAlphaFunc; + qglAreTexturesResident = dllAreTexturesResident; + qglArrayElement = dllArrayElement; + qglBegin = dllBegin; + qglBindTexture = dllBindTexture; + qglBitmap = dllBitmap; + qglBlendFunc = dllBlendFunc; + qglCallList = dllCallList; + qglCallLists = dllCallLists; + qglClear = dllClear; + qglClearAccum = dllClearAccum; + qglClearColor = dllClearColor; + qglClearDepth = dllClearDepth; + qglClearIndex = dllClearIndex; + qglClearStencil = dllClearStencil; + qglClipPlane = dllClipPlane; + qglColor3b = dllColor3b; + qglColor3bv = dllColor3bv; + qglColor3d = dllColor3d; + qglColor3dv = dllColor3dv; + qglColor3f = dllColor3f; + qglColor3fv = dllColor3fv; + qglColor3i = dllColor3i; + qglColor3iv = dllColor3iv; + qglColor3s = dllColor3s; + qglColor3sv = dllColor3sv; + qglColor3ub = dllColor3ub; + qglColor3ubv = dllColor3ubv; + qglColor3ui = dllColor3ui; + qglColor3uiv = dllColor3uiv; + qglColor3us = dllColor3us; + qglColor3usv = dllColor3usv; + qglColor4b = dllColor4b; + qglColor4bv = dllColor4bv; + qglColor4d = dllColor4d; + qglColor4dv = dllColor4dv; + qglColor4f = dllColor4f; + qglColor4fv = dllColor4fv; + qglColor4i = dllColor4i; + qglColor4iv = dllColor4iv; + qglColor4s = dllColor4s; + qglColor4sv = dllColor4sv; + qglColor4ub = dllColor4ub; + qglColor4ubv = dllColor4ubv; + qglColor4ui = dllColor4ui; + qglColor4uiv = dllColor4uiv; + qglColor4us = dllColor4us; + qglColor4usv = dllColor4usv; + qglColorMask = dllColorMask; + qglColorMaterial = dllColorMaterial; + qglColorPointer = dllColorPointer; + qglCopyPixels = dllCopyPixels; + qglCopyTexImage1D = dllCopyTexImage1D; + qglCopyTexImage2D = dllCopyTexImage2D; + qglCopyTexSubImage1D = dllCopyTexSubImage1D; + qglCopyTexSubImage2D = dllCopyTexSubImage2D; + qglCullFace = dllCullFace; + qglDeleteLists = dllDeleteLists ; + qglDeleteTextures = dllDeleteTextures ; + qglDepthFunc = dllDepthFunc ; + qglDepthMask = dllDepthMask ; + qglDepthRange = dllDepthRange ; + qglDisable = dllDisable ; + qglDisableClientState = dllDisableClientState ; + qglDrawArrays = dllDrawArrays ; + qglDrawBuffer = dllDrawBuffer ; + qglDrawElements = dllDrawElements ; + qglDrawPixels = dllDrawPixels ; + qglEdgeFlag = dllEdgeFlag ; + qglEdgeFlagPointer = dllEdgeFlagPointer ; + qglEdgeFlagv = dllEdgeFlagv ; + qglEnable = dllEnable ; + qglEnableClientState = dllEnableClientState ; + qglEnd = dllEnd ; + qglEndList = dllEndList ; + qglEvalCoord1d = dllEvalCoord1d ; + qglEvalCoord1dv = dllEvalCoord1dv ; + qglEvalCoord1f = dllEvalCoord1f ; + qglEvalCoord1fv = dllEvalCoord1fv ; + qglEvalCoord2d = dllEvalCoord2d ; + qglEvalCoord2dv = dllEvalCoord2dv ; + qglEvalCoord2f = dllEvalCoord2f ; + qglEvalCoord2fv = dllEvalCoord2fv ; + qglEvalMesh1 = dllEvalMesh1 ; + qglEvalMesh2 = dllEvalMesh2 ; + qglEvalPoint1 = dllEvalPoint1 ; + qglEvalPoint2 = dllEvalPoint2 ; + qglFeedbackBuffer = dllFeedbackBuffer ; + qglFinish = dllFinish ; + qglFlush = dllFlush ; + qglFogf = dllFogf ; + qglFogfv = dllFogfv ; + qglFogi = dllFogi ; + qglFogiv = dllFogiv ; + qglFrontFace = dllFrontFace ; + qglFrustum = dllFrustum ; + qglGenLists = dllGenLists ; + qglGenTextures = dllGenTextures ; + qglGetBooleanv = dllGetBooleanv ; + qglGetClipPlane = dllGetClipPlane ; + qglGetDoublev = dllGetDoublev ; + qglGetError = dllGetError ; + qglGetFloatv = dllGetFloatv ; + qglGetIntegerv = dllGetIntegerv ; + qglGetLightfv = dllGetLightfv ; + qglGetLightiv = dllGetLightiv ; + qglGetMapdv = dllGetMapdv ; + qglGetMapfv = dllGetMapfv ; + qglGetMapiv = dllGetMapiv ; + qglGetMaterialfv = dllGetMaterialfv ; + qglGetMaterialiv = dllGetMaterialiv ; + qglGetPixelMapfv = dllGetPixelMapfv ; + qglGetPixelMapuiv = dllGetPixelMapuiv ; + qglGetPixelMapusv = dllGetPixelMapusv ; + qglGetPointerv = dllGetPointerv ; + qglGetPolygonStipple = dllGetPolygonStipple ; + qglGetString = dllGetString ; + qglGetTexEnvfv = dllGetTexEnvfv ; + qglGetTexEnviv = dllGetTexEnviv ; + qglGetTexGendv = dllGetTexGendv ; + qglGetTexGenfv = dllGetTexGenfv ; + qglGetTexGeniv = dllGetTexGeniv ; + qglGetTexImage = dllGetTexImage ; + qglGetTexLevelParameterfv = dllGetTexLevelParameterfv ; + qglGetTexLevelParameteriv = dllGetTexLevelParameteriv ; + qglGetTexParameterfv = dllGetTexParameterfv ; + qglGetTexParameteriv = dllGetTexParameteriv ; + qglHint = dllHint ; + qglIndexMask = dllIndexMask ; + qglIndexPointer = dllIndexPointer ; + qglIndexd = dllIndexd ; + qglIndexdv = dllIndexdv ; + qglIndexf = dllIndexf ; + qglIndexfv = dllIndexfv ; + qglIndexi = dllIndexi ; + qglIndexiv = dllIndexiv ; + qglIndexs = dllIndexs ; + qglIndexsv = dllIndexsv ; + qglIndexub = dllIndexub ; + qglIndexubv = dllIndexubv ; + qglInitNames = dllInitNames ; + qglInterleavedArrays = dllInterleavedArrays ; + qglIsEnabled = dllIsEnabled ; + qglIsList = dllIsList ; + qglIsTexture = dllIsTexture ; + qglLightModelf = dllLightModelf ; + qglLightModelfv = dllLightModelfv ; + qglLightModeli = dllLightModeli ; + qglLightModeliv = dllLightModeliv ; + qglLightf = dllLightf ; + qglLightfv = dllLightfv ; + qglLighti = dllLighti ; + qglLightiv = dllLightiv ; + qglLineStipple = dllLineStipple ; + qglLineWidth = dllLineWidth ; + qglListBase = dllListBase ; + qglLoadIdentity = dllLoadIdentity ; + qglLoadMatrixd = dllLoadMatrixd ; + qglLoadMatrixf = dllLoadMatrixf ; + qglLoadName = dllLoadName ; + qglLogicOp = dllLogicOp ; + qglMap1d = dllMap1d ; + qglMap1f = dllMap1f ; + qglMap2d = dllMap2d ; + qglMap2f = dllMap2f ; + qglMapGrid1d = dllMapGrid1d ; + qglMapGrid1f = dllMapGrid1f ; + qglMapGrid2d = dllMapGrid2d ; + qglMapGrid2f = dllMapGrid2f ; + qglMaterialf = dllMaterialf ; + qglMaterialfv = dllMaterialfv ; + qglMateriali = dllMateriali ; + qglMaterialiv = dllMaterialiv ; + qglMatrixMode = dllMatrixMode ; + qglMultMatrixd = dllMultMatrixd ; + qglMultMatrixf = dllMultMatrixf ; + qglNewList = dllNewList ; + qglNormal3b = dllNormal3b ; + qglNormal3bv = dllNormal3bv ; + qglNormal3d = dllNormal3d ; + qglNormal3dv = dllNormal3dv ; + qglNormal3f = dllNormal3f ; + qglNormal3fv = dllNormal3fv ; + qglNormal3i = dllNormal3i ; + qglNormal3iv = dllNormal3iv ; + qglNormal3s = dllNormal3s ; + qglNormal3sv = dllNormal3sv ; + qglNormalPointer = dllNormalPointer ; + qglOrtho = dllOrtho ; + qglPassThrough = dllPassThrough ; + qglPixelMapfv = dllPixelMapfv ; + qglPixelMapuiv = dllPixelMapuiv ; + qglPixelMapusv = dllPixelMapusv ; + qglPixelStoref = dllPixelStoref ; + qglPixelStorei = dllPixelStorei ; + qglPixelTransferf = dllPixelTransferf ; + qglPixelTransferi = dllPixelTransferi ; + qglPixelZoom = dllPixelZoom ; + qglPointSize = dllPointSize ; + qglPolygonMode = dllPolygonMode ; + qglPolygonOffset = dllPolygonOffset ; + qglPolygonStipple = dllPolygonStipple ; + qglPopAttrib = dllPopAttrib ; + qglPopClientAttrib = dllPopClientAttrib ; + qglPopMatrix = dllPopMatrix ; + qglPopName = dllPopName ; + qglPrioritizeTextures = dllPrioritizeTextures ; + qglPushAttrib = dllPushAttrib ; + qglPushClientAttrib = dllPushClientAttrib ; + qglPushMatrix = dllPushMatrix ; + qglPushName = dllPushName ; + qglRasterPos2d = dllRasterPos2d ; + qglRasterPos2dv = dllRasterPos2dv ; + qglRasterPos2f = dllRasterPos2f ; + qglRasterPos2fv = dllRasterPos2fv ; + qglRasterPos2i = dllRasterPos2i ; + qglRasterPos2iv = dllRasterPos2iv ; + qglRasterPos2s = dllRasterPos2s ; + qglRasterPos2sv = dllRasterPos2sv ; + qglRasterPos3d = dllRasterPos3d ; + qglRasterPos3dv = dllRasterPos3dv ; + qglRasterPos3f = dllRasterPos3f ; + qglRasterPos3fv = dllRasterPos3fv ; + qglRasterPos3i = dllRasterPos3i ; + qglRasterPos3iv = dllRasterPos3iv ; + qglRasterPos3s = dllRasterPos3s ; + qglRasterPos3sv = dllRasterPos3sv ; + qglRasterPos4d = dllRasterPos4d ; + qglRasterPos4dv = dllRasterPos4dv ; + qglRasterPos4f = dllRasterPos4f ; + qglRasterPos4fv = dllRasterPos4fv ; + qglRasterPos4i = dllRasterPos4i ; + qglRasterPos4iv = dllRasterPos4iv ; + qglRasterPos4s = dllRasterPos4s ; + qglRasterPos4sv = dllRasterPos4sv ; + qglReadBuffer = dllReadBuffer ; + qglReadPixels = dllReadPixels ; + qglRectd = dllRectd ; + qglRectdv = dllRectdv ; + qglRectf = dllRectf ; + qglRectfv = dllRectfv ; + qglRecti = dllRecti ; + qglRectiv = dllRectiv ; + qglRects = dllRects ; + qglRectsv = dllRectsv ; + qglRenderMode = dllRenderMode ; + qglRotated = dllRotated ; + qglRotatef = dllRotatef ; + qglScaled = dllScaled ; + qglScalef = dllScalef ; + qglScissor = dllScissor ; + qglSelectBuffer = dllSelectBuffer ; + qglShadeModel = dllShadeModel ; + qglStencilFunc = dllStencilFunc ; + qglStencilMask = dllStencilMask ; + qglStencilOp = dllStencilOp ; + qglTexCoord1d = dllTexCoord1d ; + qglTexCoord1dv = dllTexCoord1dv ; + qglTexCoord1f = dllTexCoord1f ; + qglTexCoord1fv = dllTexCoord1fv ; + qglTexCoord1i = dllTexCoord1i ; + qglTexCoord1iv = dllTexCoord1iv ; + qglTexCoord1s = dllTexCoord1s ; + qglTexCoord1sv = dllTexCoord1sv ; + qglTexCoord2d = dllTexCoord2d ; + qglTexCoord2dv = dllTexCoord2dv ; + qglTexCoord2f = dllTexCoord2f ; + qglTexCoord2fv = dllTexCoord2fv ; + qglTexCoord2i = dllTexCoord2i ; + qglTexCoord2iv = dllTexCoord2iv ; + qglTexCoord2s = dllTexCoord2s ; + qglTexCoord2sv = dllTexCoord2sv ; + qglTexCoord3d = dllTexCoord3d ; + qglTexCoord3dv = dllTexCoord3dv ; + qglTexCoord3f = dllTexCoord3f ; + qglTexCoord3fv = dllTexCoord3fv ; + qglTexCoord3i = dllTexCoord3i ; + qglTexCoord3iv = dllTexCoord3iv ; + qglTexCoord3s = dllTexCoord3s ; + qglTexCoord3sv = dllTexCoord3sv ; + qglTexCoord4d = dllTexCoord4d ; + qglTexCoord4dv = dllTexCoord4dv ; + qglTexCoord4f = dllTexCoord4f ; + qglTexCoord4fv = dllTexCoord4fv ; + qglTexCoord4i = dllTexCoord4i ; + qglTexCoord4iv = dllTexCoord4iv ; + qglTexCoord4s = dllTexCoord4s ; + qglTexCoord4sv = dllTexCoord4sv ; + qglTexCoordPointer = dllTexCoordPointer ; + qglTexEnvf = dllTexEnvf ; + qglTexEnvfv = dllTexEnvfv ; + qglTexEnvi = dllTexEnvi ; + qglTexEnviv = dllTexEnviv ; + qglTexGend = dllTexGend ; + qglTexGendv = dllTexGendv ; + qglTexGenf = dllTexGenf ; + qglTexGenfv = dllTexGenfv ; + qglTexGeni = dllTexGeni ; + qglTexGeniv = dllTexGeniv ; + qglTexImage1D = dllTexImage1D ; + qglTexImage2D = dllTexImage2D ; + qglTexParameterf = dllTexParameterf ; + qglTexParameterfv = dllTexParameterfv ; + qglTexParameteri = dllTexParameteri ; + qglTexParameteriv = dllTexParameteriv ; + qglTexSubImage1D = dllTexSubImage1D ; + qglTexSubImage2D = dllTexSubImage2D ; + qglTranslated = dllTranslated ; + qglTranslatef = dllTranslatef ; + qglVertex2d = dllVertex2d ; + qglVertex2dv = dllVertex2dv ; + qglVertex2f = dllVertex2f ; + qglVertex2fv = dllVertex2fv ; + qglVertex2i = dllVertex2i ; + qglVertex2iv = dllVertex2iv ; + qglVertex2s = dllVertex2s ; + qglVertex2sv = dllVertex2sv ; + qglVertex3d = dllVertex3d ; + qglVertex3dv = dllVertex3dv ; + qglVertex3f = dllVertex3f ; + qglVertex3fv = dllVertex3fv ; + qglVertex3i = dllVertex3i ; + qglVertex3iv = dllVertex3iv ; + qglVertex3s = dllVertex3s ; + qglVertex3sv = dllVertex3sv ; + qglVertex4d = dllVertex4d ; + qglVertex4dv = dllVertex4dv ; + qglVertex4f = dllVertex4f ; + qglVertex4fv = dllVertex4fv ; + qglVertex4i = dllVertex4i ; + qglVertex4iv = dllVertex4iv ; + qglVertex4s = dllVertex4s ; + qglVertex4sv = dllVertex4sv ; + qglVertexPointer = dllVertexPointer ; + qglViewport = dllViewport ; + } +} + + +void GLimp_LogNewFrame( void ) +{ + fprintf( glw_state.log_fp, "*** R_BeginFrame ***\n" ); +} + + diff --git a/CODE-mp/unix/linux_snd.c b/CODE-mp/unix/linux_snd.c new file mode 100644 index 0000000..793c5f1 --- /dev/null +++ b/CODE-mp/unix/linux_snd.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __linux__ // rb0101023 - guard this +#include +#endif +#ifdef __FreeBSD__ // rb0101023 - added +#include +#endif +#include + +#include "../client/snd_local.h" + +int audio_fd; +int snd_inited=0; + +cvar_t *sndbits; +cvar_t *sndspeed; +cvar_t *sndchannels; + +cvar_t *snddevice; + +/* Some devices may work only with 48000 */ +static int tryrates[] = { 22050, 11025, 44100, 48000, 8000 }; + +qboolean SNDDMA_Init(void) +{ + int rc; + int fmt; + int tmp; + int i; + // char *s; // bk001204 - unused + struct audio_buf_info info; + int caps; + extern uid_t saved_euid; + + if (snd_inited) + return 1; + + if (!snddevice) { + sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE); + sndspeed = Cvar_Get("sndspeed", "0", CVAR_ARCHIVE); + sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE); + snddevice = Cvar_Get("snddevice", "/dev/dsp", CVAR_ARCHIVE); + } + + // open /dev/dsp, confirm capability to mmap, and get size of dma buffer + if (!audio_fd) { + seteuid(saved_euid); + + audio_fd = open(snddevice->string, O_RDWR); + + seteuid(getuid()); + + if (audio_fd < 0) { + perror(snddevice->string); + Com_Printf("Could not open %s\n", snddevice->string); + return 0; + } + } + + if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps) == -1) { + perror(snddevice->string); + Com_Printf("Sound driver too old\n"); + close(audio_fd); + return 0; + } + + if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP)) { + Com_Printf("Sorry but your soundcard can't do this\n"); + close(audio_fd); + return 0; + } + + + /* SNDCTL_DSP_GETOSPACE moved to be called later */ + + // set sample bits & speed + dma.samplebits = (int)sndbits->value; + if (dma.samplebits != 16 && dma.samplebits != 8) { + ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt); + if (fmt & AFMT_S16_LE) + dma.samplebits = 16; + else if (fmt & AFMT_U8) + dma.samplebits = 8; + } + + dma.speed = (int)sndspeed->value; + if (!dma.speed) { + for (i=0 ; ivalue; + if (dma.channels < 1 || dma.channels > 2) + dma.channels = 2; + +/* mmap() call moved forward */ + + tmp = 0; + if (dma.channels == 2) + tmp = 1; + rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not set %s to stereo=%d", snddevice->string, dma.channels); + close(audio_fd); + return 0; + } + + if (tmp) + dma.channels = 2; + else + dma.channels = 1; + + rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &dma.speed); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not set %s speed to %d", snddevice->string, dma.speed); + close(audio_fd); + return 0; + } + + if (dma.samplebits == 16) { + rc = AFMT_S16_LE; + rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not support 16-bit data. Try 8-bit.\n"); + close(audio_fd); + return 0; + } + } else if (dma.samplebits == 8) { + rc = AFMT_U8; + rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not support 8-bit data.\n"); + close(audio_fd); + return 0; + } + } else { + perror(snddevice->string); + Com_Printf("%d-bit sound not supported.", dma.samplebits); + close(audio_fd); + return 0; + } + + if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1) { + perror("GETOSPACE"); + Com_Printf("Um, can't do GETOSPACE?\n"); + close(audio_fd); + return 0; + } + + dma.samples = info.fragstotal * info.fragsize / (dma.samplebits/8); + dma.submission_chunk = 1; + + // memory map the dma buffer + + if (!dma.buffer) + dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal + * info.fragsize, PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0); + + if (!dma.buffer) { + perror(snddevice->string); + Com_Printf("Could not mmap %s\n", snddevice->string); + close(audio_fd); + return 0; + } + + // toggle the trigger & start her up + + tmp = 0; + rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not toggle.\n"); + close(audio_fd); + return 0; + } + + tmp = PCM_ENABLE_OUTPUT; + rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not toggle.\n"); + close(audio_fd); + + return 0; + } + + snd_inited = 1; + return 1; +} + +int SNDDMA_GetDMAPos(void) +{ + struct count_info count; + + if (!snd_inited) return 0; + + if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count) == -1) { + perror(snddevice->string); + Com_Printf("Uh, sound dead.\n"); + close(audio_fd); + snd_inited = 0; + return 0; + } + return count.ptr / (dma.samplebits / 8); +} + +void SNDDMA_Shutdown(void) +{ +} + +/* +============== +SNDDMA_Submit + +Send sound to device if buffer isn't really the dma buffer +=============== +*/ +void SNDDMA_Submit(void) +{ +} + +void SNDDMA_BeginPainting (void) +{ +} diff --git a/CODE-mp/unix/makefile b/CODE-mp/unix/makefile new file mode 100644 index 0000000..a9f86b0 --- /dev/null +++ b/CODE-mp/unix/makefile @@ -0,0 +1,1430 @@ +# +# GNU Make required +# + +PLATFORM=$(shell uname|tr A-Z a-z) +PLATFORM_RELEASE=$(shell uname -r) + +### +### These paths are where you probably want to change things +### + +# Where we are building from (where the source code should be!) +MOUNT_DIR=../ + + +# Where we are building to, libMesaVoodooGL.so.3.3 should be here, etc. +# the demo pk3 file should be here in demoq3/pak0.pk3 or baseq3/pak0.pk3 +BDIR=$(MOUNT_DIR)/../run + + +# Build name +# BUILD_NAME=$(BUILD_NAME) +BUILD_NAME=jkii + + + +############################################################################# +## +## You shouldn't have to touch anything below here +## +############################################################################# + +BASEQ3_DIR=$(BDIR)/base + +BD=debug$(ARCH)$(GLIBC) +BR=release$(ARCH)$(GLIBC) +CDIR=$(MOUNT_DIR)/client +SDIR=$(MOUNT_DIR)/server +RDIR=$(MOUNT_DIR)/renderer +CMDIR=$(MOUNT_DIR)/qcommon +UDIR=$(MOUNT_DIR)/unix +GDIR=$(MOUNT_DIR)/game +CGDIR=$(MOUNT_DIR)/cgame +BAIDIR=$(GDIR) +BLIBDIR=$(MOUNT_DIR)/botlib +NDIR=$(MOUNT_DIR)/null +UIDIR=$(MOUNT_DIR)/ui +Q3UIDIR=$(MOUNT_DIR)/q3_ui +FTDIR=$(MOUNT_DIR)/ft2 +JPDIR=$(MOUNT_DIR)/jpeg-6 +SPLNDIR=$(MOUNT_DIR)/splines +GHOUL2DIR=$(MOUNT_DIR)/ghoul2 + +# TTimo: game/q_shared.h is the main version string +# we have to keep this one up to date? +VERSION=0.55 + +############################################################################# +# SETUP AND BUILD -- LINUX +############################################################################# + +## Defaults +DLL_ONLY=false + + ifneq (,$(findstring libc6,$(shell if [ -e /lib/libc.so.6* ];then echo libc6;fi))) + GLIBC=-glibc + else + GLIBC= + endif #libc6 test + + MESADIR=../Mesa/ + ARCH=i386 + RPMARCH=i386 + VENDOR=unknown + DLL_ONLY=false + + # bk001205: no mo' -I/usr/include/glide, no FX + # bk001205: no mo' -Dstricmp=strcasecmp, see q_shared.h + #BASE_CFLAGS = -pipe -fsigned-char -x c++ -D_JK2 -D_M_IX86 -I/home/drews/STLport-4.5.3/stlport -I/opt/intel/compiler50/ia32/include + BASE_CFLAGS = -pipe -fsigned-char -Kc++ -D_JK2 -D_M_IX86 -I/opt/intel/compiler50/ia32/include + # rcg010216: DLL_ONLY for PPC + ifeq ($(strip $(DLL_ONLY)),true) + BASE_CFLAGS += -DDLL_ONLY + endif + + + #GL_CFLAGS = -I$(MESADIR)/include -I/usr/X11R6/include + GL_CFAGS = -I/usr/X11R6/include + + # bk001204 - need -O for -Wall for uninitialized + # bk001205 - took out -O to get assertions (NDEBUG) + # bk001206 - MALLOC_CHECK in addition to ZONE_DEBUG + # TTimo 03/30/2001 temporary took out -Werror for initial merge + DEBUG_CFLAGS=$(BASE_CFLAGS) -g +# DEBUG_CFLAGS=$(BASE_CFLAGS) -g -Wall -Werror -O + ifeq ($(ARCH),axp) + CC=pgcc + RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O6 -ffast-math -funroll-loops -fomit-frame-pointer -fexpensive-optimizations + else + ifeq ($(ARCH),ppc) + NEWPGCC=/loki/global/ppc/bin/gcc + CC=$(NEWPGCC) + RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O6 -fomit-frame-pointer -pipe -ffast-math -malign-loops=2 -malign-jumps=2 -malign-functions=2 -fno-strict-aliasing -fstrength-reduce + else + #NEWPGCC=/usr/local/gcc-2.95.2/bin/gcc # bk001205 + #NEWPGCC=/loki/global/x86/bin/gcc + #NEWPGCC=/usr/bin/gcc + #NEWPGCC=/usr/local/bin/gcc + NEWPGCC=/opt/intel/compiler50/ia32/bin/icc + CC=$(shell if [ -f $(NEWPGCC) ]; then echo $(NEWPGCC); else echo pgcc; fi ) + CXX=/usr/bin/g++ +# TTimo: legacy RELEASE_CFLAGS +# NOTE: the -fomit-frame-pointer option leads to an unstable binary on my test box if it was built on the main box +# but building on the Mdk 7.2 baseline seems to work + RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O6 -mcpu=pentiumpro -march=pentium -fomit-frame-pointer -pipe -ffast-math -malign-loops=2 -malign-jumps=2 -malign-functions=2 -fno-strict-aliasing -fstrength-reduce +# TTimo: use this for building on P3 gcc 2.95.3 libc2.2 for all targets (experimental! -fomit-fram-pointer removed) +# RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O6 -mcpu=pentiumpro -march=pentium -pipe -ffast-math -malign-loops=2 -malign-jumps=2 -malign-functions=2 -fno-strict-aliasing -fstrength-reduce + endif + endif + + LIBEXT=a + + SHLIBEXT=so + SHLIBCFLAGS=-fPIC + SHLIBLDFLAGS=-shared $(LDFLAGS) + + ARFLAGS=ar rv + RANLIB=ranlib + + THREAD_LDFLAGS=-lpthread + #LDFLAGS=/opt/sxl/lib/sxlgcc3.a -lpthread -ldl -lm -lstdc++ -static -Wl --gc-sections + LDFLAGS=-ldl -lm -lstdc++ -static + GLLDFLAGS=-L/usr/X11R6/lib -L$(MESADIR)/lib -lX11 -lXext -lXxf86dga -lXxf86vm + + TARGETS=\ + $(B)/$(PLATFORM)q3ded + + +DO_CC=$(CC) $(CFLAGS) -o $@ -c $< +DO_CXX=$(CXX) $(CFLAGS) -o $@ -c $< +DO_SMP_CC=$(CC) $(CFLAGS) -DSMP -o $@ -c $< +DO_BOT_CC=$(CC) $(CFLAGS) -DBOTLIB -o $@ -c $< # $(SHLIBCFLAGS) # bk001212 +DO_DEBUG_CC=$(CC) $(DEBUG_CFLAGS) -o $@ -c $< +DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $< +DO_SHLIB_DEBUG_CC=$(CC) $(DEBUG_CFLAGS) $(SHLIBCFLAGS) -o $@ -c $< +DO_AS=$(CC) $(CFLAGS) -DELF -x assembler-with-cpp -o $@ -c $< +DO_NASM=nasm -f elf -o $@ $< +DO_DED_CC=$(CC) -DDEDICATED -DC_ONLY $(CFLAGS) -o $@ -c $< +DO_DED_CPP=$(CXX) -DDEDICATED -DC_ONLY $(CFLAGS) -o $@ -c $< + +#DO_LCC=$(LCC) -o $@ -S -Wf-target=bytecode -Wf-g -DQ3_VM -I$(CGDIR) -I$(GDIR) -I$(UIDIR) $< + +#### DEFAULT TARGET +default:build_debug + +debug: build_debug +release: build_release + +build_debug: + $(MAKE) targets B=$(BD) CFLAGS="$(DEBUG_CFLAGS)" + +build_release: + $(MAKE) targets B=$(BR) CFLAGS="$(RELEASE_CFLAGS)" + +#Build both debug and release builds +all:build_debug build_release + +targets:makedirs $(TARGETS) + +fixnames: + @if [ ! -d $(GHOUL2DIR)/G2_local.h ]; then mv $(GHOUL2DIR)/g2_local.h $(GHOUL2DIR)/G2_local.h;fi + @if [ ! -d $(GHOUL2DIR)/G2.h ]; then mv $(GHOUL2DIR)/g2.h $(GHOUL2DIR)/G2.h;fi + @if [ ! -d $(CMDIR)/ROFFSystem.h ]; then mv $(CMDIR)/roffsystem.h $(CMDIR)/ROFFSystem.h;fi + @if [ ! -d $(RDIR)/MatComp.h ] ; then mv $(RDIR)/matcomp.h $(RDIR)/MatComp.h;fi + + +makedirs: + @if [ ! -d $(B) ];then mkdir $(B);fi +# @if [ ! -d $(B)/client ];then mkdir $(B)/client;fi + @if [ ! -d $(B)/ded ];then mkdir $(B)/ded;fi +# @if [ ! -d $(B)/ref ];then mkdir $(B)/ref;fi +# @if [ ! -d $(B)/ft2 ];then mkdir $(B)/ft2;fi +# @if [ ! -d $(B)/baseq3 ];then mkdir $(B)/baseq3;fi +# @if [ ! -d $(B)/baseq3/cgame ];then mkdir $(B)/baseq3/cgame;fi +# @if [ ! -d $(B)/baseq3/game ];then mkdir $(B)/baseq3/game;fi +# @if [ ! -d $(B)/baseq3/ui ];then mkdir $(B)/baseq3/ui;fi +# @if [ ! -d $(B)/baseq3/vm ];then mkdir $(B)/baseq3/vm;fi +# @if [ ! -d $(B)/missionpack ];then mkdir $(B)/missionpack;fi +# @if [ ! -d $(B)/missionpack/cgame ];then mkdir $(B)/missionpack/cgame;fi +# @if [ ! -d $(B)/missionpack/game ];then mkdir $(B)/missionpack/game;fi +# @if [ ! -d $(B)/missionpack/ui ];then mkdir $(B)/missionpack/ui;fi +# @if [ ! -d $(B)/missionpack/vm ];then mkdir $(B)/missionpack/vm;fi +# @if [ ! -d $(B)/q3static ];then mkdir $(B)/q3static;fi + + +############################################################################# +# DEDICATED SERVER +############################################################################# + +Q3DOBJ = \ + $(B)/ded/sv_bot.o \ + $(B)/ded/sv_client.o \ + $(B)/ded/sv_ccmds.o \ + $(B)/ded/sv_game.o \ + $(B)/ded/sv_init.o \ + $(B)/ded/sv_main.o \ + $(B)/ded/sv_net_chan.o \ + $(B)/ded/sv_snapshot.o \ + $(B)/ded/sv_world.o \ + \ + $(B)/ded/cm_load.o \ + $(B)/ded/cm_patch.o \ + $(B)/ded/cm_polylib.o \ + $(B)/ded/cm_test.o \ + $(B)/ded/cm_trace.o \ + $(B)/ded/cm_shader.o \ + $(B)/ded/cmd.o \ + $(B)/ded/common.o \ + $(B)/ded/cvar.o \ + $(B)/ded/files.o \ + $(B)/ded/md4.o \ + $(B)/ded/msg.o \ + $(B)/ded/net_chan.o \ + $(B)/ded/huffman.o \ + \ + $(B)/ded/q_math.o \ + $(B)/ded/q_shared.o \ + \ + $(B)/ded/unzip.o \ + $(B)/ded/vm.o \ + $(B)/ded/vm_interpreted.o \ + \ + $(B)/ded/be_aas_bspq3.o \ + $(B)/ded/be_aas_cluster.o \ + $(B)/ded/be_aas_debug.o \ + $(B)/ded/be_aas_entity.o \ + $(B)/ded/be_aas_file.o \ + $(B)/ded/be_aas_main.o \ + $(B)/ded/be_aas_move.o \ + $(B)/ded/be_aas_optimize.o \ + $(B)/ded/be_aas_reach.o \ + $(B)/ded/be_aas_route.o \ + $(B)/ded/be_aas_routealt.o \ + $(B)/ded/be_aas_sample.o \ + $(B)/ded/be_ai_char.o \ + $(B)/ded/be_ai_chat.o \ + $(B)/ded/be_ai_gen.o \ + $(B)/ded/be_ai_goal.o \ + $(B)/ded/be_ai_move.o \ + $(B)/ded/be_ai_weap.o \ + $(B)/ded/be_ai_weight.o \ + $(B)/ded/be_ea.o \ + $(B)/ded/be_interface.o \ + $(B)/ded/l_crc.o \ + $(B)/ded/l_libvar.o \ + $(B)/ded/l_log.o \ + $(B)/ded/l_memory.o \ + $(B)/ded/l_precomp.o \ + $(B)/ded/l_script.o \ + $(B)/ded/l_struct.o \ + \ + $(B)/ded/linux_common.o \ + $(B)/ded/unix_main.o \ + $(B)/ded/unix_net.o \ + $(B)/ded/unix_shared.o \ + \ + $(B)/ded/g2_api.o \ + $(B)/ded/g2_bolts.o \ + $(B)/ded/g2_bones.o \ + $(B)/ded/g2_surfaces.o \ + $(B)/ded/g2_misc.o \ + \ + $(B)/ded/null_client.o \ + $(B)/ded/null_input.o \ + $(B)/ded/null_snddma.o \ + $(B)/ded/null_glimp.o \ + $(B)/ded/null_renderer.o \ + \ + $(B)/ded/tr_model.o \ + $(B)/ded/tr_image.o \ + $(B)/ded/roffsystem.o \ + $(B)/ded/tr_ghoul2.o \ + $(B)/ded/matcomp.o \ + $(B)/ded/tr_init.o \ + $(B)/ded/tr_main.o \ + $(B)/ded/tr_backend.o \ + $(B)/ded/tr_mesh.o \ + $(B)/ded/tr_shader.o \ + $(B)/ded/strip.o \ +# \ +# $(B)/ded/null_main.o \ +# $(B)/ded/null_net.o \ +# $(B)/ded/tr_cmds.o \ +# $(B)/ded/tr_animation.o \ +# $(B)/ded/tr_bsp.o \ +# $(B)/ded/tr_curve.o \ +# $(B)/ded/tr_flares.o \ +# $(B)/ded/tr_font.o \ +# $(B)/ded/tr_light.o \ +# $(B)/ded/tr_marks.o \ +# $(B)/ded/tr_noise.o \ +# $(B)/ded/tr_quicksprite.o \ +# $(B)/ded/tr_scene.o \ +# $(B)/ded/tr_shade_calc.o \ +# $(B)/ded/tr_shade.o \ +# $(B)/ded/tr_shadows.o \ +# $(B)/ded/tr_surfacesprites.o \ +# $(B)/ded/tr_world.o \ +# $(B)/ded/tr_worldeffects.o \ +# \ +# $(B)/ded/linux_glimp.o \ +# $(B)/ded/tr_image.o +# $(B)/ded/linux_qgl.o +# $(B)/ded/snapvector.o \ +# $(B)/ded/tr_main.o +# $(B)/ded/tr_sky.o + +#ifeq ($(ARCH),i386) + Q3DOBJ += $(B)/ded/vm_x86.o $(B)/ded/ftol.o $(B)/ded/snapvector.o +#endif + +ifeq ($(ARCH),ppc) + ifeq ($(DLL_ONLY),false) + Q3DOBJ += $(B)/ded/vm_ppc.o + endif +endif + +$(B)/$(PLATFORM)q3ded : $(Q3DOBJ) + $(CC) -o $@ $(Q3DOBJ) $(LDFLAGS) + +$(B)/ded/sv_bot.o : $(SDIR)/sv_bot.cpp; $(DO_DED_CC) +$(B)/ded/sv_client.o : $(SDIR)/sv_client.cpp; $(DO_DED_CC) +$(B)/ded/sv_ccmds.o : $(SDIR)/sv_ccmds.cpp; $(DO_DED_CC) +$(B)/ded/sv_game.o : $(SDIR)/sv_game.cpp; $(DO_DED_CC) +$(B)/ded/sv_init.o : $(SDIR)/sv_init.cpp; $(DO_DED_CC) +$(B)/ded/sv_main.o : $(SDIR)/sv_main.cpp; $(DO_DED_CC) +$(B)/ded/sv_net_chan.o : $(SDIR)/sv_net_chan.cpp; $(DO_DED_CC) +$(B)/ded/sv_snapshot.o : $(SDIR)/sv_snapshot.cpp; $(DO_DED_CC) +$(B)/ded/sv_world.o : $(SDIR)/sv_world.cpp; $(DO_DED_CC) +$(B)/ded/cm_load.o : $(CMDIR)/cm_load.cpp; $(DO_DED_CC) +$(B)/ded/cm_shader.o : $(CMDIR)/cm_shader.cpp; $(DO_DED_CC) +$(B)/ded/cm_polylib.o : $(CMDIR)/cm_polylib.cpp; $(DO_DED_CC) +$(B)/ded/cm_test.o : $(CMDIR)/cm_test.cpp; $(DO_DED_CC) +$(B)/ded/cm_trace.o : $(CMDIR)/cm_trace.cpp; $(DO_DED_CC) +$(B)/ded/cm_patch.o : $(CMDIR)/cm_patch.cpp; $(DO_DED_CC) +$(B)/ded/cmd.o : $(CMDIR)/cmd.cpp; $(DO_DED_CC) +$(B)/ded/common.o : $(CMDIR)/common.cpp; $(DO_DED_CC) +$(B)/ded/cvar.o : $(CMDIR)/cvar.cpp; $(DO_DED_CC) +$(B)/ded/files.o : $(CMDIR)/files.cpp; $(DO_DED_CC) +$(B)/ded/md4.o : $(CMDIR)/md4.cpp; $(DO_DED_CC) +$(B)/ded/msg.o : $(CMDIR)/msg.cpp; $(DO_DED_CC) +$(B)/ded/net_chan.o : $(CMDIR)/net_chan.cpp; $(DO_DED_CC) +$(B)/ded/huffman.o : $(CMDIR)/huffman.cpp; $(DO_DED_CC) +$(B)/ded/q_shared.o : $(CMDIR)/q_shared.cpp; $(DO_DED_CC) +$(B)/ded/q_math.o : $(GDIR)/q_math.c; $(DO_DED_CC) +$(B)/ded/strip.o : $(CMDIR)/strip.cpp; $(DO_DED_CC) + +$(B)/ded/g2_api.o : $(GHOUL2DIR)/g2_api.cpp; $(DO_DED_CC) +$(B)/ded/g2_bolts.o : $(GHOUL2DIR)/g2_bolts.cpp; $(DO_DED_CC) +$(B)/ded/g2_bones.o : $(GHOUL2DIR)/g2_bones.cpp; $(DO_DED_CC) +$(B)/ded/g2_misc.o : $(GHOUL2DIR)/g2_misc.cpp; $(DO_DED_CC) +$(B)/ded/g2_surfaces.o : $(GHOUL2DIR)/g2_surfaces.cpp; $(DO_DED_CC) + +$(B)/ded/roffsystem.o : $(CMDIR)/roffsystem.cpp; $(DO_DED_CC) + +$(B)/ded/tr_model.o : $(RDIR)/tr_model.cpp; $(DO_DED_CC) +$(B)/ded/tr_image.o : $(RDIR)/tr_image.cpp; $(DO_DED_CC) +$(B)/ded/tr_ghoul2.o : $(RDIR)/tr_ghoul2.cpp; $(DO_DED_CC) +$(B)/ded/tr_shader.o : $(RDIR)/tr_shader.cpp; $(DO_DED_CC) +$(B)/ded/tr_sky.o : $(RDIR)/tr_shader.cpp; $(DO_DED_CC) +$(B)/ded/tr_cmds.o : $(RDIR)/tr_cmds.cpp; $(DO_DED_CC) +$(B)/ded/tr_backend.o : $(RDIR)/tr_backend.cpp; $(DO_DED_CC) +$(B)/ded/tr_animation.o : $(RDIR)/tr_animation.cpp; $(DO_DED_CC) +$(B)/ded/tr_bsp.o : $(RDIR)/tr_bsp.cpp; $(DO_DED_CC) +$(B)/ded/tr_curve.o : $(RDIR)/tr_curve.cpp; $(DO_DED_CC) +$(B)/ded/tr_flares.o : $(RDIR)/tr_flares.cpp; $(DO_DED_CC) +$(B)/ded/tr_font.o : $(RDIR)/tr_font.cpp; $(DO_DED_CC) +$(B)/ded/tr_init.o : $(RDIR)/tr_init.cpp; $(DO_DED_CC) +$(B)/ded/tr_light.o : $(RDIR)/tr_light.cpp; $(DO_DED_CC) +$(B)/ded/tr_main.o : $(RDIR)/tr_main.cpp; $(DO_DED_CC) +$(B)/ded/tr_marks.o : $(RDIR)/tr_marks.cpp; $(DO_DED_CC) +$(B)/ded/tr_mesh.o : $(RDIR)/tr_mesh.cpp; $(DO_DED_CC) +$(B)/ded/tr_noise.o : $(RDIR)/tr_noise.cpp; $(DO_DED_CC) +$(B)/ded/tr_quicksprite.o : $(RDIR)/tr_quicksprite.cpp; $(DO_DED_CC) +$(B)/ded/tr_scene.o : $(RDIR)/tr_scene.cpp; $(DO_DED_CC) +$(B)/ded/tr_shade.o : $(RDIR)/tr_shade.cpp; $(DO_DED_CC) +$(B)/ded/tr_shade_calc.o : $(RDIR)/tr_shade_calc.cpp; $(DO_DED_CC) +$(B)/ded/tr_shadows.o : $(RDIR)/tr_shadows.cpp; $(DO_DED_CC) +$(B)/ded/tr_surface.o : $(RDIR)/tr_surface.cpp; $(DO_DED_CC) +$(B)/ded/tr_surfacesprites.o : $(RDIR)/tr_surfacesprites.cpp; $(DO_DED_CC) +$(B)/ded/tr_world.o : $(RDIR)/tr_world.cpp; $(DO_DED_CC) +$(B)/ded/tr_worldeffects.o : $(RDIR)/tr_worldeffects.cpp; $(DO_DED_CC) +$(B)/ded/matcomp.o : $(RDIR)/matcomp.c; $(DO_DED_CC) + + +$(B)/ded/be_aas_bspq3.o : $(BLIBDIR)/be_aas_bspq3.cpp; $(DO_BOT_CC) +$(B)/ded/be_aas_cluster.o : $(BLIBDIR)/be_aas_cluster.cpp; $(DO_BOT_CC) +$(B)/ded/be_aas_debug.o : $(BLIBDIR)/be_aas_debug.cpp; $(DO_BOT_CC) +$(B)/ded/be_aas_entity.o : $(BLIBDIR)/be_aas_entity.cpp; $(DO_BOT_CC) +$(B)/ded/be_aas_file.o : $(BLIBDIR)/be_aas_file.cpp; $(DO_BOT_CC) +$(B)/ded/be_aas_main.o : $(BLIBDIR)/be_aas_main.cpp; $(DO_BOT_CC) +$(B)/ded/be_aas_move.o : $(BLIBDIR)/be_aas_move.cpp; $(DO_BOT_CC) +$(B)/ded/be_aas_optimize.o : $(BLIBDIR)/be_aas_optimize.cpp; $(DO_BOT_CC) +$(B)/ded/be_aas_reach.o : $(BLIBDIR)/be_aas_reach.cpp; $(DO_BOT_CC) +$(B)/ded/be_aas_route.o : $(BLIBDIR)/be_aas_route.cpp; $(DO_BOT_CC) +$(B)/ded/be_aas_routealt.o : $(BLIBDIR)/be_aas_routealt.cpp; $(DO_BOT_CC) +$(B)/ded/be_aas_sample.o : $(BLIBDIR)/be_aas_sample.cpp; $(DO_BOT_CC) +$(B)/ded/be_ai_char.o : $(BLIBDIR)/be_ai_char.cpp; $(DO_BOT_CC) +$(B)/ded/be_ai_chat.o : $(BLIBDIR)/be_ai_chat.cpp; $(DO_BOT_CC) +$(B)/ded/be_ai_gen.o : $(BLIBDIR)/be_ai_gen.cpp; $(DO_BOT_CC) +$(B)/ded/be_ai_goal.o : $(BLIBDIR)/be_ai_goal.cpp; $(DO_BOT_CC) +$(B)/ded/be_ai_move.o : $(BLIBDIR)/be_ai_move.cpp; $(DO_BOT_CC) +$(B)/ded/be_ai_weap.o : $(BLIBDIR)/be_ai_weap.cpp; $(DO_BOT_CC) +$(B)/ded/be_ai_weight.o : $(BLIBDIR)/be_ai_weight.cpp; $(DO_BOT_CC) +$(B)/ded/be_ea.o : $(BLIBDIR)/be_ea.cpp; $(DO_BOT_CC) +$(B)/ded/be_interface.o : $(BLIBDIR)/be_interface.cpp; $(DO_BOT_CC) +$(B)/ded/l_crc.o : $(BLIBDIR)/l_crc.cpp; $(DO_BOT_CC) +$(B)/ded/l_libvar.o : $(BLIBDIR)/l_libvar.cpp; $(DO_BOT_CC) +$(B)/ded/l_log.o : $(BLIBDIR)/l_log.cpp; $(DO_BOT_CC) +$(B)/ded/l_memory.o : $(BLIBDIR)/l_memory.cpp; $(DO_BOT_CC) +$(B)/ded/l_precomp.o : $(BLIBDIR)/l_precomp.cpp; $(DO_BOT_CC) +$(B)/ded/l_script.o : $(BLIBDIR)/l_script.cpp; $(DO_BOT_CC) +$(B)/ded/l_struct.o : $(BLIBDIR)/l_struct.cpp; $(DO_BOT_CC) + +$(B)/ded/linux_common.o : $(UDIR)/linux_common.c; $(DO_CC) +$(B)/ded/linux_glimp.o : $(UDIR)/linux_glimp.c; $(DO_DED_CC) +$(B)/ded/unix_main.o : $(UDIR)/unix_main.c; $(DO_DED_CC) +$(B)/ded/unix_net.o : $(UDIR)/unix_net.c; $(DO_DED_CC) +$(B)/ded/unix_shared.o : $(UDIR)/unix_shared.c; $(DO_DED_CC) +$(B)/ded/linux_qgl.o : $(UDIR)/linux_qgl.c; $(DO_DED_CC) +$(B)/ded/null_client.o : $(NDIR)/null_client.c; $(DO_DED_CC) +$(B)/ded/null_input.o : $(NDIR)/null_input.c; $(DO_DED_CC) +$(B)/ded/null_snddma.o : $(NDIR)/null_snddma.c; $(DO_DED_CC) +$(B)/ded/null_glimp.o : $(NDIR)/null_glimp.c; $(DO_DED_CC) +$(B)/ded/null_main.o : $(NDIR)/null_main.c; $(DO_DED_CC) +$(B)/ded/null_net.o : $(NDIR)/null_net.c; $(DO_DED_CC) +$(B)/ded/null_renderer.o : $(NDIR)/null_renderer.c; $(DO_DED_CC) +$(B)/ded/unzip.o : $(CMDIR)/unzip.cpp; $(DO_DED_CC) +$(B)/ded/vm.o : $(CMDIR)/vm.cpp; $(DO_DED_CC) +$(B)/ded/vm_interpreted.o : $(CMDIR)/vm_interpreted.cpp; $(DO_DED_CC) + +#ifeq ($(ARCH),i386) +$(B)/ded/vm_x86.o : $(CMDIR)/vm_x86.cpp; $(DO_DED_CC) +$(B)/ded/ftol.o : $(UDIR)/ftol.nasm; $(DO_NASM) +$(B)/ded/snapvector.o : $(UDIR)/snapvector.nasm; $(DO_NASM) +#endif + +ifeq ($(ARCH),ppc) +ifeq ($(DLL_ONLY),false) +$(B)/ded/vm_ppc.o : $(CMDIR)/vm_ppc.c; $(DO_DED_CC) +endif +endif + + +############################################################################# +## QVM +############################################################################# + +$(B)/baseq3/vm/cgame.qvm: + cd $(CGDIR) && ./cgame.sh + mv /tmp/quake3/baseq3/vm/cgame.qvm $@ + +$(B)/baseq3/vm/ui.qvm: + cd $(Q3UIDIR) && ./q3_ui.sh + mv /tmp/quake3/baseq3/vm/ui.qvm $@ + +$(B)/baseq3/vm/qagame.qvm: + cd $(GDIR) && ./game.sh + mv /tmp/quake3/baseq3/vm/qagame.qvm $@ + +$(B)/missionpack/vm/cgame.qvm: + cd $(CGDIR) && ./cgame_ta.sh + mv /tmp/quake3/missionpack/vm/cgame.qvm $@ + +$(B)/missionpack/vm/qagame.qvm: + cd $(GDIR) && ./game_ta.sh + mv /tmp/quake3/missionpack/vm/qagame.qvm $@ + +$(B)/missionpack/vm/ui.qvm: + cd $(UIDIR) && ./ui.sh + mv /tmp/quake3/missionpack/vm/ui.qvm $@ + + + +############################################################################# +## BASEQ3 CGAME +############################################################################# + +Q3CGOBJ = \ + $(B)/baseq3/cgame/bg_misc.o \ + $(B)/baseq3/cgame/bg_pmove.o \ + $(B)/baseq3/cgame/bg_slidemove.o \ + $(B)/baseq3/cgame/cg_consolecmds.o \ + $(B)/baseq3/cgame/cg_draw.o \ + $(B)/baseq3/cgame/cg_drawtools.o \ + $(B)/baseq3/cgame/cg_effects.o \ + $(B)/baseq3/cgame/cg_ents.o \ + $(B)/baseq3/cgame/cg_event.o \ + $(B)/baseq3/cgame/cg_info.o \ + $(B)/baseq3/cgame/cg_localents.o \ + $(B)/baseq3/cgame/cg_main.o \ + $(B)/baseq3/cgame/cg_marks.o \ + $(B)/baseq3/cgame/cg_players.o \ + $(B)/baseq3/cgame/cg_playerstate.o \ + $(B)/baseq3/cgame/cg_predict.o \ + $(B)/baseq3/cgame/cg_scoreboard.o \ + $(B)/baseq3/cgame/cg_servercmds.o \ + $(B)/baseq3/cgame/cg_snapshot.o \ + $(B)/baseq3/cgame/cg_syscalls.o \ + $(B)/baseq3/cgame/cg_view.o \ + $(B)/baseq3/cgame/cg_weapons.o \ + $(B)/baseq3/cgame/q_math.o \ + $(B)/baseq3/cgame/q_shared.o + +$(B)/baseq3/cgame$(ARCH).$(SHLIBEXT) : $(Q3CGOBJ) + $(CC) $(SHLIBLDFLAGS) -o $@ $(Q3CGOBJ) + +$(B)/baseq3/cgame/bg_misc.o : $(GDIR)/bg_misc.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/bg_pmove.o : $(GDIR)/bg_pmove.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/bg_slidemove.o : $(GDIR)/bg_slidemove.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_consolecmds.o : $(CGDIR)/cg_consolecmds.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_draw.o : $(CGDIR)/cg_draw.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_drawtools.o : $(CGDIR)/cg_drawtools.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_effects.o : $(CGDIR)/cg_effects.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_ents.o : $(CGDIR)/cg_ents.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_event.o : $(CGDIR)/cg_event.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_info.o : $(CGDIR)/cg_info.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_localents.o : $(CGDIR)/cg_localents.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_main.o : $(CGDIR)/cg_main.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_marks.o : $(CGDIR)/cg_marks.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_players.o : $(CGDIR)/cg_players.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_playerstate.o : $(CGDIR)/cg_playerstate.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_predict.o : $(CGDIR)/cg_predict.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_scoreboard.o : $(CGDIR)/cg_scoreboard.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_servercmds.o : $(CGDIR)/cg_servercmds.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_snapshot.o : $(CGDIR)/cg_snapshot.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_syscalls.o : $(CGDIR)/cg_syscalls.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_view.o : $(CGDIR)/cg_view.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/cg_weapons.o : $(CGDIR)/cg_weapons.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/q_math.o : $(GDIR)/q_math.c; $(DO_SHLIB_CC) +$(B)/baseq3/cgame/q_shared.o : $(GDIR)/q_shared.c; $(DO_SHLIB_CC) + +############################################################################# +## BASEQ3 GAME +############################################################################# + +Q3GOBJ = \ + $(B)/baseq3/game/ai_chat.o \ + $(B)/baseq3/game/ai_cmd.o \ + $(B)/baseq3/game/ai_dmnet.o \ + $(B)/baseq3/game/ai_dmq3.o \ + $(B)/baseq3/game/ai_main.o \ + $(B)/baseq3/game/ai_team.o \ + $(B)/baseq3/game/ai_vcmd.o \ + $(B)/baseq3/game/bg_misc.o \ + $(B)/baseq3/game/bg_pmove.o \ + $(B)/baseq3/game/bg_slidemove.o \ + $(B)/baseq3/game/g_active.o \ + $(B)/baseq3/game/g_arenas.o \ + $(B)/baseq3/game/g_bot.o \ + $(B)/baseq3/game/g_client.o \ + $(B)/baseq3/game/g_cmds.o \ + $(B)/baseq3/game/g_combat.o \ + $(B)/baseq3/game/g_items.o \ + $(B)/baseq3/game/g_main.o \ + $(B)/baseq3/game/g_mem.o \ + $(B)/baseq3/game/g_misc.o \ + $(B)/baseq3/game/g_missile.o \ + $(B)/baseq3/game/g_mover.o \ + $(B)/baseq3/game/g_session.o \ + $(B)/baseq3/game/g_spawn.o \ + $(B)/baseq3/game/g_svcmds.o \ + $(B)/baseq3/game/g_syscalls.o \ + $(B)/baseq3/game/g_target.o \ + $(B)/baseq3/game/g_team.o \ + $(B)/baseq3/game/g_trigger.o \ + $(B)/baseq3/game/g_utils.o \ + $(B)/baseq3/game/g_weapon.o \ + \ + $(B)/baseq3/game/q_math.o \ + $(B)/baseq3/game/q_shared.o + +$(B)/baseq3/qagame$(ARCH).$(SHLIBEXT) : $(Q3GOBJ) + $(CC) $(SHLIBLDFLAGS) -o $@ $(Q3GOBJ) + +$(B)/baseq3/game/ai_chat.o : $(GDIR)/ai_chat.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/ai_cmd.o : $(GDIR)/ai_cmd.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/ai_dmnet.o : $(GDIR)/ai_dmnet.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/ai_dmq3.o : $(GDIR)/ai_dmq3.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/ai_main.o : $(GDIR)/ai_main.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/ai_team.o : $(GDIR)/ai_team.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/ai_vcmd.o : $(GDIR)/ai_vcmd.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_misc.o : $(GDIR)/bg_misc.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_pmove.o : $(GDIR)/bg_pmove.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_slidemove.o : $(GDIR)/bg_slidemove.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_active.o : $(GDIR)/g_active.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_arenas.o : $(GDIR)/g_arenas.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_bot.o : $(GDIR)/g_bot.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_client.o : $(GDIR)/g_client.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_cmds.o : $(GDIR)/g_cmds.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_combat.o : $(GDIR)/g_combat.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_items.o : $(GDIR)/g_items.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_main.o : $(GDIR)/g_main.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_mem.o : $(GDIR)/g_mem.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_misc.o : $(GDIR)/g_misc.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_missile.o : $(GDIR)/g_missile.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_mover.o : $(GDIR)/g_mover.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_session.o : $(GDIR)/g_session.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_spawn.o : $(GDIR)/g_spawn.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_svcmds.o : $(GDIR)/g_svcmds.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_syscalls.o : $(GDIR)/g_syscalls.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_target.o : $(GDIR)/g_target.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_team.o : $(GDIR)/g_team.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_trigger.o : $(GDIR)/g_trigger.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_utils.o : $(GDIR)/g_utils.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_weapon.o : $(GDIR)/g_weapon.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/q_math.o : $(GDIR)/q_math.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/q_shared.o : $(GDIR)/q_shared.c; $(DO_SHLIB_CC) + + +############################################################################# +## BASEQ3 UI +############################################################################# + +Q3UIOBJ = \ + $(B)/baseq3/ui/bg_misc.o \ + $(B)/baseq3/ui/ui_addbots.o \ + $(B)/baseq3/ui/ui_atoms.o \ + $(B)/baseq3/ui/ui_cdkey.o \ + $(B)/baseq3/ui/ui_cinematics.o \ + $(B)/baseq3/ui/ui_confirm.o \ + $(B)/baseq3/ui/ui_connect.o \ + $(B)/baseq3/ui/ui_controls2.o \ + $(B)/baseq3/ui/ui_credits.o \ + $(B)/baseq3/ui/ui_demo2.o \ + $(B)/baseq3/ui/ui_display.o \ + $(B)/baseq3/ui/ui_gameinfo.o \ + $(B)/baseq3/ui/ui_ingame.o \ + $(B)/baseq3/ui/ui_loadconfig.o \ + $(B)/baseq3/ui/ui_main.o \ + $(B)/baseq3/ui/ui_menu.o \ + $(B)/baseq3/ui/ui_mfield.o \ + $(B)/baseq3/ui/ui_mods.o \ + $(B)/baseq3/ui/ui_network.o \ + $(B)/baseq3/ui/ui_options.o \ + $(B)/baseq3/ui/ui_playermodel.o \ + $(B)/baseq3/ui/ui_players.o \ + $(B)/baseq3/ui/ui_playersettings.o \ + $(B)/baseq3/ui/ui_preferences.o \ + $(B)/baseq3/ui/ui_qmenu.o \ + $(B)/baseq3/ui/ui_removebots.o \ + $(B)/baseq3/ui/ui_saveconfig.o \ + $(B)/baseq3/ui/ui_serverinfo.o \ + $(B)/baseq3/ui/ui_servers2.o \ + $(B)/baseq3/ui/ui_setup.o \ + $(B)/baseq3/ui/ui_sound.o \ + $(B)/baseq3/ui/ui_sparena.o \ + $(B)/baseq3/ui/ui_specifyserver.o \ + $(B)/baseq3/ui/ui_splevel.o \ + $(B)/baseq3/ui/ui_sppostgame.o \ + $(B)/baseq3/ui/ui_spskill.o \ + $(B)/baseq3/ui/ui_startserver.o \ + $(B)/baseq3/ui/ui_syscalls.o \ + $(B)/baseq3/ui/ui_team.o \ + $(B)/baseq3/ui/ui_teamorders.o \ + $(B)/baseq3/ui/ui_video.o \ + \ + $(B)/baseq3/ui/q_math.o \ + $(B)/baseq3/ui/q_shared.o + +$(B)/baseq3/ui$(ARCH).$(SHLIBEXT) : $(Q3UIOBJ) + $(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3UIOBJ) + +$(B)/baseq3/ui/bg_misc.o : $(GDIR)/bg_misc.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_addbots.o : $(Q3UIDIR)/ui_addbots.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_atoms.o : $(Q3UIDIR)/ui_atoms.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_cinematics.o : $(Q3UIDIR)/ui_cinematics.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_cdkey.o : $(Q3UIDIR)/ui_cdkey.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_confirm.o : $(Q3UIDIR)/ui_confirm.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_connect.o : $(Q3UIDIR)/ui_connect.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_controls2.o : $(Q3UIDIR)/ui_controls2.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_credits.o : $(Q3UIDIR)/ui_credits.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_demo2.o : $(Q3UIDIR)/ui_demo2.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_display.o : $(Q3UIDIR)/ui_display.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_gameinfo.o : $(Q3UIDIR)/ui_gameinfo.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_ingame.o : $(Q3UIDIR)/ui_ingame.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_loadconfig.o : $(Q3UIDIR)/ui_loadconfig.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_main.o : $(Q3UIDIR)/ui_main.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_menu.o : $(Q3UIDIR)/ui_menu.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_mfield.o : $(Q3UIDIR)/ui_mfield.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_mods.o : $(Q3UIDIR)/ui_mods.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_network.o : $(Q3UIDIR)/ui_network.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_options.o : $(Q3UIDIR)/ui_options.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_playermodel.o : $(Q3UIDIR)/ui_playermodel.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_players.o : $(Q3UIDIR)/ui_players.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_playersettings.o : $(Q3UIDIR)/ui_playersettings.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_preferences.o : $(Q3UIDIR)/ui_preferences.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_qmenu.o : $(Q3UIDIR)/ui_qmenu.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_quit.o : $(Q3UIDIR)/ui_quit.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_removebots.o : $(Q3UIDIR)/ui_removebots.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_saveconfig.o : $(Q3UIDIR)/ui_saveconfig.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_serverinfo.o : $(Q3UIDIR)/ui_serverinfo.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_servers2.o : $(Q3UIDIR)/ui_servers2.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_setup.o : $(Q3UIDIR)/ui_setup.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_sound.o : $(Q3UIDIR)/ui_sound.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_sparena.o : $(Q3UIDIR)/ui_sparena.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_specifyserver.o : $(Q3UIDIR)/ui_specifyserver.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_splevel.o : $(Q3UIDIR)/ui_splevel.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_sppostgame.o : $(Q3UIDIR)/ui_sppostgame.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_spskill.o : $(Q3UIDIR)/ui_spskill.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_startserver.o : $(Q3UIDIR)/ui_startserver.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_team.o : $(Q3UIDIR)/ui_team.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_teamorders.o : $(Q3UIDIR)/ui_teamorders.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_syscalls.o : $(Q3UIDIR)/ui_syscalls.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/ui_video.o : $(Q3UIDIR)/ui_video.c; $(DO_SHLIB_CC) + +# bk001205 - these wre the only SHLIB compiles in 1.17 +$(B)/baseq3/ui/q_math.o : $(GDIR)/q_math.c; $(DO_SHLIB_CC) +$(B)/baseq3/ui/q_shared.o : $(GDIR)/q_shared.c; $(DO_SHLIB_CC) + + +############################################################################# +## Q3 STATIC (DEBUG) BUILD +############################################################################# + +Q3SOBJ = \ + $(B)/q3static/cl_cgame.o \ + $(B)/q3static/cl_cin.o \ + $(B)/q3static/cl_console.o \ + $(B)/q3static/cl_input.o \ + $(B)/q3static/cl_keys.o \ + $(B)/q3static/cl_main.o \ + $(B)/q3static/cl_net_chan.o \ + $(B)/q3static/cl_parse.o \ + $(B)/q3static/cl_scrn.o \ + $(B)/q3static/cl_ui.o \ + \ + $(B)/q3static/cm_load.o \ + $(B)/q3static/cm_patch.o \ + $(B)/q3static/cm_polylib.o \ + $(B)/q3static/cm_test.o \ + $(B)/q3static/cm_trace.o \ + \ + $(B)/q3static/cmd.o \ + $(B)/q3static/common.o \ + $(B)/q3static/cvar.o \ + $(B)/q3static/files.o \ + $(B)/q3static/md4.o \ + $(B)/q3static/msg.o \ + $(B)/q3static/net_chan.o \ + \ + $(B)/q3static/snd_adpcm.o \ + $(B)/q3static/snd_dma.o \ + $(B)/q3static/snd_mem.o \ + $(B)/q3static/snd_mix.o \ + $(B)/q3static/snd_wavelet.o \ + \ + $(B)/q3static/sv_bot.o \ + $(B)/q3static/sv_ccmds.o \ + $(B)/q3static/sv_client.o \ + $(B)/q3static/sv_game.o \ + $(B)/q3static/sv_init.o \ + $(B)/q3static/sv_main.o \ + $(B)/q3static/sv_net_chan.o \ + $(B)/q3static/sv_snapshot.o \ + $(B)/q3static/sv_world.o \ + \ + $(B)/q3static/unzip.o \ + $(B)/q3static/vm.o \ + $(B)/q3static/vm_interpreted.o \ + \ + $(B)/q3static/be_aas_bspq3.o \ + $(B)/q3static/be_aas_cluster.o \ + $(B)/q3static/be_aas_debug.o \ + $(B)/q3static/be_aas_entity.o \ + $(B)/q3static/be_aas_file.o \ + $(B)/q3static/be_aas_main.o \ + $(B)/q3static/be_aas_move.o \ + $(B)/q3static/be_aas_optimize.o \ + $(B)/q3static/be_aas_reach.o \ + $(B)/q3static/be_aas_route.o \ + $(B)/q3static/be_aas_routealt.o \ + $(B)/q3static/be_aas_sample.o \ + $(B)/q3static/be_ai_char.o \ + $(B)/q3static/be_ai_chat.o \ + $(B)/q3static/be_ai_gen.o \ + $(B)/q3static/be_ai_goal.o \ + $(B)/q3static/be_ai_move.o \ + $(B)/q3static/be_ai_weap.o \ + $(B)/q3static/be_ai_weight.o \ + $(B)/q3static/be_ea.o \ + $(B)/q3static/be_interface.o \ + $(B)/q3static/l_crc.o \ + $(B)/q3static/l_libvar.o \ + $(B)/q3static/l_log.o \ + $(B)/q3static/l_memory.o \ + $(B)/q3static/l_precomp.o \ + $(B)/q3static/l_script.o \ + $(B)/q3static/l_struct.o \ + \ + $(B)/q3static/jcapimin.o \ + $(B)/q3static/jchuff.o \ + $(B)/q3static/jcinit.o \ + $(B)/q3static/jccoefct.o \ + $(B)/q3static/jccolor.o \ + $(B)/q3static/jfdctflt.o \ + $(B)/q3static/jcdctmgr.o \ + $(B)/q3static/jcphuff.o \ + $(B)/q3static/jcmainct.o \ + $(B)/q3static/jcmarker.o \ + $(B)/q3static/jcmaster.o \ + $(B)/q3static/jcomapi.o \ + $(B)/q3static/jcparam.o \ + $(B)/q3static/jcprepct.o \ + $(B)/q3static/jcsample.o \ + $(B)/q3static/jdapimin.o \ + $(B)/q3static/jdapistd.o \ + $(B)/q3static/jdatasrc.o \ + $(B)/q3static/jdcoefct.o \ + $(B)/q3static/jdcolor.o \ + $(B)/q3static/jddctmgr.o \ + $(B)/q3static/jdhuff.o \ + $(B)/q3static/jdinput.o \ + $(B)/q3static/jdmainct.o \ + $(B)/q3static/jdmarker.o \ + $(B)/q3static/jdmaster.o \ + $(B)/q3static/jdpostct.o \ + $(B)/q3static/jdsample.o \ + $(B)/q3static/jdtrans.o \ + $(B)/q3static/jerror.o \ + $(B)/q3static/jidctflt.o \ + $(B)/q3static/jmemmgr.o \ + $(B)/q3static/jmemnobs.o \ + $(B)/q3static/jutils.o \ + \ + $(B)/q3static/tr_animation.o \ + $(B)/q3static/tr_backend.o \ + $(B)/q3static/tr_bsp.o \ + $(B)/q3static/tr_cmds.o \ + $(B)/q3static/tr_curve.o \ + $(B)/q3static/tr_flares.o \ + $(B)/q3static/tr_font.o \ + $(B)/q3static/tr_image.o \ + $(B)/q3static/tr_init.o \ + $(B)/q3static/tr_light.o \ + $(B)/q3static/tr_main.o \ + $(B)/q3static/tr_marks.o \ + $(B)/q3static/tr_mesh.o \ + $(B)/q3static/tr_model.o \ + $(B)/q3static/tr_noise.o \ + $(B)/q3static/tr_scene.o \ + $(B)/q3static/tr_shade.o \ + $(B)/q3static/tr_shade_calc.o \ + $(B)/q3static/tr_shader.o \ + $(B)/q3static/tr_shadows.o \ + $(B)/q3static/tr_sky.o \ + $(B)/q3static/tr_surface.o \ + $(B)/q3static/tr_world.o \ + \ + $(B)/q3static/unix_main.o \ + $(B)/q3static/unix_net.o \ + $(B)/q3static/unix_shared.o \ + \ + $(B)/q3static/ahoptim.o \ + $(B)/q3static/autohint.o \ + $(B)/q3static/ftbase.o \ + $(B)/q3static/ftdebug.o \ + $(B)/q3static/ftglyph.o \ + $(B)/q3static/ftinit.o \ + $(B)/q3static/ftmm.o \ + $(B)/q3static/ftsystem.o \ + $(B)/q3static/raster1.o \ + $(B)/q3static/sfnt.o \ + $(B)/q3static/sfobjs.o \ + $(B)/q3static/smooth.o \ + $(B)/q3static/truetype.o \ + \ + $(B)/q3static/linux_qgl.o \ + $(B)/q3static/linux_glimp.o \ + $(B)/q3static/linux_joystick.o \ + $(B)/q3static/linux_snd.o \ + $(B)/q3static/snd_mixa.o \ + $(B)/q3static/matha.o + +ifeq ($(ARCH),i386) + Q3SOBJ += $(B)/q3static/vm_x86.o +endif + +ifeq ($(ARCH),ppc) + ifeq ($(DLL_ONLY),false) + Q3SOBJ += $(B)/q3static/vm_ppc.o + endif +endif + + +$(B)/q3static/cl_cgame.o : $(CDIR)/cl_cgame.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cl_cin.o : $(CDIR)/cl_cin.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cl_console.o : $(CDIR)/cl_console.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cl_input.o : $(CDIR)/cl_input.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cl_keys.o : $(CDIR)/cl_keys.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cl_main.o : $(CDIR)/cl_main.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cl_net_chan.o : $(CDIR)/cl_net_chan.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cl_parse.o : $(CDIR)/cl_parse.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cl_scrn.o : $(CDIR)/cl_scrn.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cl_ui.o : $(CDIR)/cl_ui.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/snd_adpcm.o : $(CDIR)/snd_adpcm.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/snd_dma.o : $(CDIR)/snd_dma.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/snd_mem.o : $(CDIR)/snd_mem.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/snd_mix.o : $(CDIR)/snd_mix.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/snd_wavelet.o : $(CDIR)/snd_wavelet.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/sv_bot.o : $(SDIR)/sv_bot.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/sv_client.o : $(SDIR)/sv_client.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/sv_ccmds.o : $(SDIR)/sv_ccmds.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/sv_game.o : $(SDIR)/sv_game.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/sv_init.o : $(SDIR)/sv_init.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/sv_main.o : $(SDIR)/sv_main.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/sv_net_chan.o : $(SDIR)/sv_net_chan.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/sv_snapshot.o : $(SDIR)/sv_snapshot.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/sv_world.o : $(SDIR)/sv_world.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cm_trace.o : $(CMDIR)/cm_trace.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cm_load.o : $(CMDIR)/cm_load.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cm_test.o : $(CMDIR)/cm_test.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cm_patch.o : $(CMDIR)/cm_patch.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cm_polylib.o : $(CMDIR)/cm_polylib.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cmd.o : $(CMDIR)/cmd.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/common.o : $(CMDIR)/common.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cvar.o : $(CMDIR)/cvar.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/files.o : $(CMDIR)/files.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/md4.o : $(CMDIR)/md4.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/msg.o : $(CMDIR)/msg.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/net_chan.o : $(CMDIR)/net_chan.c; $(DO_CC) -DQ3_STATIC + +$(B)/q3static/be_aas_bspq3.o : $(BLIBDIR)/be_aas_bspq3.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_aas_cluster.o : $(BLIBDIR)/be_aas_cluster.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_aas_debug.o : $(BLIBDIR)/be_aas_debug.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_aas_entity.o : $(BLIBDIR)/be_aas_entity.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_aas_file.o : $(BLIBDIR)/be_aas_file.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_aas_main.o : $(BLIBDIR)/be_aas_main.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_aas_move.o : $(BLIBDIR)/be_aas_move.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_aas_optimize.o : $(BLIBDIR)/be_aas_optimize.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_aas_reach.o : $(BLIBDIR)/be_aas_reach.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_aas_route.o : $(BLIBDIR)/be_aas_route.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_aas_routealt.o : $(BLIBDIR)/be_aas_routealt.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_aas_sample.o : $(BLIBDIR)/be_aas_sample.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_ai_char.o : $(BLIBDIR)/be_ai_char.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_ai_chat.o : $(BLIBDIR)/be_ai_chat.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_ai_gen.o : $(BLIBDIR)/be_ai_gen.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_ai_goal.o : $(BLIBDIR)/be_ai_goal.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_ai_move.o : $(BLIBDIR)/be_ai_move.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_ai_weap.o : $(BLIBDIR)/be_ai_weap.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_ai_weight.o : $(BLIBDIR)/be_ai_weight.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_ea.o : $(BLIBDIR)/be_ea.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/be_interface.o : $(BLIBDIR)/be_interface.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/l_crc.o : $(BLIBDIR)/l_crc.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/l_libvar.o : $(BLIBDIR)/l_libvar.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/l_log.o : $(BLIBDIR)/l_log.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/l_memory.o : $(BLIBDIR)/l_memory.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/l_precomp.o : $(BLIBDIR)/l_precomp.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/l_script.o : $(BLIBDIR)/l_script.c; $(DO_BOT_CC) -DQ3_STATIC +$(B)/q3static/l_struct.o : $(BLIBDIR)/l_struct.c; $(DO_BOT_CC) -DQ3_STATIC + +$(B)/q3static/jcapimin.o : $(JPDIR)/jcapimin.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jchuff.o : $(JPDIR)/jchuff.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jcinit.o : $(JPDIR)/jcinit.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jccoefct.o : $(JPDIR)/jccoefct.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jccolor.o : $(JPDIR)/jccolor.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jfdctflt.o : $(JPDIR)/jfdctflt.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jcdctmgr.o : $(JPDIR)/jcdctmgr.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jcmainct.o : $(JPDIR)/jcmainct.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jcmarker.o : $(JPDIR)/jcmarker.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jcmaster.o : $(JPDIR)/jcmaster.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jcomapi.o : $(JPDIR)/jcomapi.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jcparam.o : $(JPDIR)/jcparam.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jcprepct.o : $(JPDIR)/jcprepct.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jcsample.o : $(JPDIR)/jcsample.c; $(DO_CC) -DQ3_STATIC + +$(B)/q3static/jdapimin.o : $(JPDIR)/jdapimin.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jdapistd.o : $(JPDIR)/jdapistd.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jdatasrc.o : $(JPDIR)/jdatasrc.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jdcoefct.o : $(JPDIR)/jdcoefct.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jdcolor.o : $(JPDIR)/jdcolor.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jcphuff.o : $(JPDIR)/jcphuff.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jddctmgr.o : $(JPDIR)/jddctmgr.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jdhuff.o : $(JPDIR)/jdhuff.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jdinput.o : $(JPDIR)/jdinput.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jdmainct.o : $(JPDIR)/jdmainct.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jdmarker.o : $(JPDIR)/jdmarker.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jdmaster.o : $(JPDIR)/jdmaster.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jdpostct.o : $(JPDIR)/jdpostct.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jdsample.o : $(JPDIR)/jdsample.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jdtrans.o : $(JPDIR)/jdtrans.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jerror.o : $(JPDIR)/jerror.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jidctflt.o : $(JPDIR)/jidctflt.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jmemmgr.o : $(JPDIR)/jmemmgr.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jmemnobs.o : $(JPDIR)/jmemnobs.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/jutils.o : $(JPDIR)/jutils.c; $(DO_CC) -DQ3_STATIC + +$(B)/q3static/tr_bsp.o : $(RDIR)/tr_bsp.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_animation.o : $(RDIR)/tr_animation.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_backend.o : $(RDIR)/tr_backend.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_cmds.o : $(RDIR)/tr_cmds.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_curve.o : $(RDIR)/tr_curve.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_flares.o : $(RDIR)/tr_flares.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_font.o : $(RDIR)/tr_font.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_image.o : $(RDIR)/tr_image.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_init.o : $(RDIR)/tr_init.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_light.o : $(RDIR)/tr_light.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_main.o : $(RDIR)/tr_main.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_marks.o : $(RDIR)/tr_marks.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_mesh.o : $(RDIR)/tr_mesh.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_model.o : $(RDIR)/tr_model.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_noise.o : $(RDIR)/tr_noise.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_scene.o : $(RDIR)/tr_scene.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_shade.o : $(RDIR)/tr_shade.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_shader.o : $(RDIR)/tr_shader.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_shade_calc.o : $(RDIR)/tr_shade_calc.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_shadows.o : $(RDIR)/tr_shadows.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_sky.o : $(RDIR)/tr_sky.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_smp.o : $(RDIR)/tr_smp.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_stripify.o : $(RDIR)/tr_stripify.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_subdivide.o : $(RDIR)/tr_subdivide.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_surface.o : $(RDIR)/tr_surface.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/tr_world.o : $(RDIR)/tr_world.c; $(DO_CC) -DQ3_STATIC + +$(B)/q3static/unix_qgl.o : $(UDIR)/unix_qgl.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/unix_main.o : $(UDIR)/unix_main.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/unix_net.o : $(UDIR)/unix_net.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/unix_shared.o : $(UDIR)/unix_shared.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/linux_glimp.o : $(UDIR)/linux_glimp.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/linux_joystick.o : $(UDIR)/linux_joystick.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/linux_qgl.o : $(UDIR)/linux_qgl.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/linux_input.o : $(UDIR)/linux_input.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/linux_snd.o : $(UDIR)/linux_snd.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/snd_mixa.o : $(UDIR)/snd_mixa.s; $(DO_AS) +$(B)/q3static/matha.o : $(UDIR)/matha.s; $(DO_AS) +$(B)/q3static/unzip.o : $(CMDIR)/unzip.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/vm.o : $(CMDIR)/vm.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/vm_interpreted.o : $(CMDIR)/vm_interpreted.c; $(DO_CC) -DQ3_STATIC + +ifeq ($(ARCH),i386) + $(B)/q3static/vm_x86.o : $(CMDIR)/vm_x86.c; $(DO_CC) -DQ3_STATIC +endif + +ifeq ($(ARCH),ppc) +ifeq ($(DLL_ONLY),false) +$(B)/q3static/vm_ppc.o : $(CMDIR)/vm_ppc.c; $(DO_CC) -DQ3_STATIC +endif +endif + +$(B)/q3static/ahoptim.o : $(FTDIR)/ahoptim.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/autohint.o : $(FTDIR)/autohint.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ftbase.o : $(FTDIR)/ftbase.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ftdebug.o : $(FTDIR)/ftdebug.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ftglyph.o : $(FTDIR)/ftglyph.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ftinit.o : $(FTDIR)/ftinit.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ftmm.o : $(FTDIR)/ftmm.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ftsystem.o : $(FTDIR)/ftsystem.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/raster1.o : $(FTDIR)/raster1.c; $(DO_CC) -DQ3_STATIC -DFT_FLAT_COMPILE +$(B)/q3static/sfnt.o : $(FTDIR)/sfnt.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/sfobjs.o : $(FTDIR)/sfobjs.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/smooth.o : $(FTDIR)/smooth.c; $(DO_CC) -DQ3_STATIC -DFT_FLAT_COMPILE +$(B)/q3static/truetype.o : $(FTDIR)/truetype.c; $(DO_CC) -DQ3_STATIC + +## add BASEQ3 CGAME +Q3SOBJ += \ + $(B)/q3static/cg_consolecmds.o \ + $(B)/q3static/cg_draw.o \ + $(B)/q3static/cg_drawtools.o \ + $(B)/q3static/cg_effects.o \ + $(B)/q3static/cg_ents.o \ + $(B)/q3static/cg_event.o \ + $(B)/q3static/cg_info.o \ + $(B)/q3static/cg_localents.o \ + $(B)/q3static/cg_main.o \ + $(B)/q3static/cg_marks.o \ + $(B)/q3static/cg_players.o \ + $(B)/q3static/cg_playerstate.o \ + $(B)/q3static/cg_predict.o \ + $(B)/q3static/cg_scoreboard.o \ + $(B)/q3static/cg_servercmds.o \ + $(B)/q3static/cg_snapshot.o \ + $(B)/q3static/cg_syscalls.o \ + $(B)/q3static/cg_view.o \ + $(B)/q3static/cg_weapons.o + +$(B)/q3static/cg_consolecmds.o : $(CGDIR)/cg_consolecmds.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_draw.o : $(CGDIR)/cg_draw.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_drawtools.o : $(CGDIR)/cg_drawtools.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_effects.o : $(CGDIR)/cg_effects.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_ents.o : $(CGDIR)/cg_ents.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_event.o : $(CGDIR)/cg_event.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_info.o : $(CGDIR)/cg_info.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_localents.o : $(CGDIR)/cg_localents.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_main.o : $(CGDIR)/cg_main.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_marks.o : $(CGDIR)/cg_marks.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_players.o : $(CGDIR)/cg_players.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_playerstate.o : $(CGDIR)/cg_playerstate.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_predict.o : $(CGDIR)/cg_predict.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_scoreboard.o : $(CGDIR)/cg_scoreboard.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_servercmds.o : $(CGDIR)/cg_servercmds.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_snapshot.o : $(CGDIR)/cg_snapshot.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_syscalls.o : $(CGDIR)/cg_syscalls.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_view.o : $(CGDIR)/cg_view.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/cg_weapons.o : $(CGDIR)/cg_weapons.c; $(DO_CC) -DQ3_STATIC + +## add BASEQ3 GAME +Q3SOBJ += \ + $(B)/q3static/ai_chat.o \ + $(B)/q3static/ai_cmd.o \ + $(B)/q3static/ai_dmnet.o \ + $(B)/q3static/ai_dmq3.o \ + $(B)/q3static/ai_main.o \ + $(B)/q3static/ai_team.o \ + $(B)/q3static/ai_vcmd.o \ + $(B)/q3static/g_active.o \ + $(B)/q3static/g_arenas.o \ + $(B)/q3static/g_bot.o \ + $(B)/q3static/g_client.o \ + $(B)/q3static/g_cmds.o \ + $(B)/q3static/g_combat.o \ + $(B)/q3static/g_items.o \ + $(B)/q3static/g_main.o \ + $(B)/q3static/g_mem.o \ + $(B)/q3static/g_misc.o \ + $(B)/q3static/g_missile.o \ + $(B)/q3static/g_mover.o \ + $(B)/q3static/g_session.o \ + $(B)/q3static/g_spawn.o \ + $(B)/q3static/g_svcmds.o \ + $(B)/q3static/g_target.o \ + $(B)/q3static/g_team.o \ + $(B)/q3static/g_trigger.o \ + $(B)/q3static/g_utils.o \ + $(B)/q3static/g_weapon.o \ + \ + $(B)/q3static/g_syscalls.o + +$(B)/q3static/ai_chat.o : $(GDIR)/ai_chat.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ai_cmd.o : $(GDIR)/ai_cmd.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ai_dmnet.o : $(GDIR)/ai_dmnet.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ai_dmq3.o : $(GDIR)/ai_dmq3.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ai_main.o : $(GDIR)/ai_main.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ai_team.o : $(GDIR)/ai_team.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ai_vcmd.o : $(GDIR)/ai_vcmd.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_active.o : $(GDIR)/g_active.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_arenas.o : $(GDIR)/g_arenas.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_bot.o : $(GDIR)/g_bot.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_client.o : $(GDIR)/g_client.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_cmds.o : $(GDIR)/g_cmds.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_combat.o : $(GDIR)/g_combat.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_items.o : $(GDIR)/g_items.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_main.o : $(GDIR)/g_main.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_mem.o : $(GDIR)/g_mem.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_misc.o : $(GDIR)/g_misc.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_missile.o : $(GDIR)/g_missile.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_mover.o : $(GDIR)/g_mover.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_session.o : $(GDIR)/g_session.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_spawn.o : $(GDIR)/g_spawn.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_svcmds.o : $(GDIR)/g_svcmds.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_syscalls.o : $(GDIR)/g_syscalls.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_target.o : $(GDIR)/g_target.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_team.o : $(GDIR)/g_team.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_trigger.o : $(GDIR)/g_trigger.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_utils.o : $(GDIR)/g_utils.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/g_weapon.o : $(GDIR)/g_weapon.c; $(DO_CC) -DQ3_STATIC + +## add BASEQ3 UI +Q3SOBJ += \ + $(B)/q3static/ui_addbots.o \ + $(B)/q3static/ui_atoms.o \ + $(B)/q3static/ui_cdkey.o \ + $(B)/q3static/ui_cinematics.o \ + $(B)/q3static/ui_confirm.o \ + $(B)/q3static/ui_connect.o \ + $(B)/q3static/ui_controls2.o \ + $(B)/q3static/ui_credits.o \ + $(B)/q3static/ui_demo2.o \ + $(B)/q3static/ui_display.o \ + $(B)/q3static/ui_gameinfo.o \ + $(B)/q3static/ui_ingame.o \ + $(B)/q3static/ui_loadconfig.o \ + $(B)/q3static/ui_main.o \ + $(B)/q3static/ui_menu.o \ + $(B)/q3static/ui_mfield.o \ + $(B)/q3static/ui_mods.o \ + $(B)/q3static/ui_network.o \ + $(B)/q3static/ui_options.o \ + $(B)/q3static/ui_playermodel.o \ + $(B)/q3static/ui_players.o \ + $(B)/q3static/ui_playersettings.o \ + $(B)/q3static/ui_preferences.o \ + $(B)/q3static/ui_qmenu.o \ + $(B)/q3static/ui_removebots.o \ + $(B)/q3static/ui_saveconfig.o \ + $(B)/q3static/ui_serverinfo.o \ + $(B)/q3static/ui_servers2.o \ + $(B)/q3static/ui_setup.o \ + $(B)/q3static/ui_sound.o \ + $(B)/q3static/ui_sparena.o \ + $(B)/q3static/ui_specifyserver.o \ + $(B)/q3static/ui_splevel.o \ + $(B)/q3static/ui_sppostgame.o \ + $(B)/q3static/ui_spskill.o \ + $(B)/q3static/ui_startserver.o \ + $(B)/q3static/ui_team.o \ + $(B)/q3static/ui_teamorders.o \ + $(B)/q3static/ui_video.o \ + \ + $(B)/q3static/ui_syscalls.o + +$(B)/q3static/ui_addbots.o : $(Q3UIDIR)/ui_addbots.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_atoms.o : $(Q3UIDIR)/ui_atoms.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_cinematics.o : $(Q3UIDIR)/ui_cinematics.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_cdkey.o : $(Q3UIDIR)/ui_cdkey.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_confirm.o : $(Q3UIDIR)/ui_confirm.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_connect.o : $(Q3UIDIR)/ui_connect.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_controls2.o : $(Q3UIDIR)/ui_controls2.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_credits.o : $(Q3UIDIR)/ui_credits.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_demo2.o : $(Q3UIDIR)/ui_demo2.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_display.o : $(Q3UIDIR)/ui_display.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_gameinfo.o : $(Q3UIDIR)/ui_gameinfo.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_ingame.o : $(Q3UIDIR)/ui_ingame.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_loadconfig.o : $(Q3UIDIR)/ui_loadconfig.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_main.o : $(Q3UIDIR)/ui_main.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_menu.o : $(Q3UIDIR)/ui_menu.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_mfield.o : $(Q3UIDIR)/ui_mfield.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_mods.o : $(Q3UIDIR)/ui_mods.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_network.o : $(Q3UIDIR)/ui_network.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_options.o : $(Q3UIDIR)/ui_options.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_playermodel.o : $(Q3UIDIR)/ui_playermodel.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_players.o : $(Q3UIDIR)/ui_players.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_playersettings.o : $(Q3UIDIR)/ui_playersettings.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_preferences.o : $(Q3UIDIR)/ui_preferences.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_qmenu.o : $(Q3UIDIR)/ui_qmenu.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_quit.o : $(Q3UIDIR)/ui_quit.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_removebots.o : $(Q3UIDIR)/ui_removebots.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_saveconfig.o : $(Q3UIDIR)/ui_saveconfig.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_serverinfo.o : $(Q3UIDIR)/ui_serverinfo.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_servers2.o : $(Q3UIDIR)/ui_servers2.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_setup.o : $(Q3UIDIR)/ui_setup.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_sound.o : $(Q3UIDIR)/ui_sound.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_sparena.o : $(Q3UIDIR)/ui_sparena.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_specifyserver.o : $(Q3UIDIR)/ui_specifyserver.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_splevel.o : $(Q3UIDIR)/ui_splevel.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_sppostgame.o : $(Q3UIDIR)/ui_sppostgame.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_spskill.o : $(Q3UIDIR)/ui_spskill.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_startserver.o : $(Q3UIDIR)/ui_startserver.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_team.o : $(Q3UIDIR)/ui_team.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_teamorders.o : $(Q3UIDIR)/ui_teamorders.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_syscalls.o : $(Q3UIDIR)/ui_syscalls.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/ui_video.o : $(Q3UIDIR)/ui_video.c; $(DO_CC) -DQ3_STATIC + + +## add shared files +Q3SOBJ += \ + $(B)/q3static/bg_misc.o \ + $(B)/q3static/bg_pmove.o \ + $(B)/q3static/bg_slidemove.o \ + $(B)/q3static/q_math.o \ + $(B)/q3static/q_shared.o + +## shared files +$(B)/q3static/q_math.o : $(GDIR)/q_math.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/q_shared.o : $(GDIR)/q_shared.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/bg_misc.o : $(GDIR)/bg_misc.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/bg_pmove.o : $(GDIR)/bg_pmove.c; $(DO_CC) -DQ3_STATIC +$(B)/q3static/bg_slidemove.o : $(GDIR)/bg_slidemove.c; $(DO_CC) -DQ3_STATIC + + + +$(B)/$(PLATFORM)q3static : $(Q3SOBJ) + $(CC) $(CFLAGS) -o $@ $(Q3SOBJ) $(GLLDFLAGS) $(LDFLAGS) + + +############################################################################# +# RPM +############################################################################# + +TMPDIR=/var/tmp +TARDIR=$(TMPDIR)/$(BUILD_NAME) +TARFILE = $(BUILD_NAME)-$(VERSION)-$(RPM_RELEASE).$(ARCH).tar + +tar: + if [ ! -d archives ];then mkdir archives;chmod 755 archives;fi + $(MAKE) copyfiles COPYDIR=$(TARDIR) + cd $(TARDIR); tar cvf $(TARFILE) * && gzip -9 $(TARFILE) + mv $(TARDIR)/$(TARFILE).gz archives/. + rm -rf $(TARDIR) + +# Make RPMs. You need to be root to make this work +RPMROOT=/usr/src/redhat +RPM = rpm +RPMFLAGS = -bb +INSTALLDIR = /usr/local/games/$(BUILD_NAME) +RPMDIR = $(TMPDIR)/$(BUILD_NAME)-$(VERSION) +DESTDIR= $(RPMDIR)/$(INSTALLDIR) + +rpm: $(BUILD_NAME).spec + touch $(RPMROOT)/SOURCES/$(BUILD_NAME)-$(VERSION).tar.gz + if [ ! -d archives ];then mkdir archives;fi + $(MAKE) copyfiles COPYDIR=$(DESTDIR) + cp $(UDIR)/quake3.gif $(RPMROOT)/SOURCES/. + cp $(BUILD_NAME).spec $(RPMROOT)/SPECS/. + cd $(RPMROOT)/SPECS; $(RPM) $(RPMFLAGS) $(BUILD_NAME).spec + rm -rf $(RPMDIR) + mv $(RPMROOT)/RPMS/$(RPMARCH)/$(BUILD_NAME)-$(VERSION)-$(RPM_RELEASE).$(RPMARCH).rpm archives/$(BUILD_NAME)-$(VERSION)-$(RPM_RELEASE).$(RPMARCH).rpm + +copyfiles: + -mkdirhier $(COPYDIR) + cp $(BR)/linuxquake3 $(COPYDIR)/quake3.x86 + strip $(COPYDIR)/quake3.x86 + chmod 755 $(COPYDIR)/quake3.x86 + cp $(BR)/linuxq3ded $(COPYDIR)/q3ded + strip $(COPYDIR)/q3ded + chmod 755 $(COPYDIR)/q3ded + cp $(BDIR)/libMesaVoodooGL.so.3.2 $(COPYDIR)/. + chmod 755 $(COPYDIR)/libMesaVoodooGL.so.3.2 + ( cd $(COPYDIR); ln -s libMesaVoodooGL.so.3.2 libMesaVoodooGL.so ) + cp $(BDIR)/Quake_III_Arena_FAQ.html $(COPYDIR)/. + chmod 644 $(COPYDIR)/Quake_III_Arena_FAQ.html + mkdir $(COPYDIR)/baseq3 + cp $(BASEQ3_DIR)/pak2.pk3 $(COPYDIR)/baseq3/. + chmod 644 $(COPYDIR)/baseq3/pak2.pk3 + +$(BUILD_NAME).spec : $(UDIR)/$(BUILD_NAME).spec.sh Makefile + sh $< $(VERSION) $(RPM_RELEASE) $(ARCH) $(INSTALLDIR) > $@ + +############################################################################# +# MISC +############################################################################# + +# TTimo: FIXME: doesn't clean the binary and .so + +clean:clean-debug clean-release + +clean2: clean-bins + rm -f $(Q3OBJ) $(Q3POBJ) $(Q3POBJ_SMP) $(Q3DOBJ) $(MPGOBJ) $(Q3GOBJ) $(Q3CGOBJ) $(MPCGOBJ) $(Q3UIOBJ) $(MPUIOBJ) + rm -f $(CGDIR)/vm/*.asm + rm -f $(GDIR)/vm/*.asm + rm -f $(UIDIR)/vm/*.asm + rm -f $(Q3UIDIR)/vm/*.asm + +# TTimo: linuxq3ded linuxquake3 linuxquake3-smp .. hardcoded the names .. maybe not such a good thing +# FIXME: also, removing the *.so is crappy .. I just want to avoid rm -rf debugi386-glibc to save the symlinks to pk3's for testing +clean-bins: + if [ -d $(B) ];then (find $(B) -name '*.so' -exec rm {} \;)fi + rm -f $(B)/linuxq3ded + rm -f $(B)/linuxquake3 + rm -f $(B)/linuxquake3-smp + rm -f $(B)/baseq3/vm/cgame.qvm + rm -f $(B)/baseq3/vm/ui.qvm + rm -f $(B)/baseq3/vm/qagame.qvm + rm -f $(B)/missionpack/vm/cgame.qvm + rm -f $(B)/missionpack/vm/qagame.qvm + rm -f $(B)/missionpack/vm/ui.qvm + +clean-debug: + $(MAKE) clean2 B=$(BD) CFLAGS="$(DEBUG_CFLAGS)" + +clean-release: + $(MAKE) clean2 B=$(BR) CFLAGS="$(DEBUG_CFLAGS)" + +# +# TTimo: the make tar and make rpm don't really fit my needs +# writing custom hack + +DATADIR = /home/timo/Id/Q3SetupMedia/quake3 + +setup: release $(B)/linuxq3a-$(VERSION).tar.gz + +$(B)/linuxq3a-$(VERSION).tar.gz: + rm -rf setup + mkdir setup + cp -R $(DATADIR) setup + cp release$(ARCH)-glibc/linuxquake3 setup/quake3/quake3.x86 + strip setup/quake3/quake3.x86 + cp release$(ARCH)-glibc/linuxq3ded setup/quake3/q3ded + strip setup/quake3/q3ded + cd setup; tar cvzf linuxq3a-$(VERSION).tar.gz quake3 +# TTimo: the .so where distributed with 1.27g because of a VM problem that made them break on linux +# cp release$(ARCH)-glibc/baseq3/cgame$(ARCH).so setup/quake3/baseq3 +# cp release$(ARCH)-glibc/baseq3/qagame$(ARCH).so setup/quake3/baseq3 +# cp release$(ARCH)-glibc/baseq3/ui$(ARCH).so setup/quake3/baseq3 +# cp release$(ARCH)-glibc/missionpack/cgame$(ARCH).so setup/quake3/missionpack +# cp release$(ARCH)-glibc/missionpack/qagame$(ARCH).so setup/quake3/missionpack +# cp release$(ARCH)-glibc/missionpack/ui$(ARCH).so setup/quake3/missionpack + +# don't redistribute this one! +setup-debug: debug $(B)/linuxq3a-$(VERSION)-DEBUG.tar.gz + +$(B)/linuxq3a-$(VERSION)-DEBUG.tar.gz: + rm -rf setup-debug + mkdir setup-debug + cp -R $(DATADIR) setup-debug + cp debug$(ARCH)-glibc/linuxquake3 setup-debug/quake3/quake3.x86 + cp debug$(ARCH)-glibc/linuxq3ded setup-debug/quake3/q3ded + cp debug$(ARCH)-glibc/baseq3/cgame$(ARCH).so setup-debug/quake3/baseq3 + cp debug$(ARCH)-glibc/baseq3/qagame$(ARCH).so setup-debug/quake3/baseq3 + cp debug$(ARCH)-glibc/baseq3/ui$(ARCH).so setup-debug/quake3/baseq3 + cp debug$(ARCH)-glibc/missionpack/cgame$(ARCH).so setup-debug/quake3/missionpack + cp debug$(ARCH)-glibc/missionpack/qagame$(ARCH).so setup-debug/quake3/missionpack + cp debug$(ARCH)-glibc/missionpack/ui$(ARCH).so setup-debug/quake3/missionpack + cd setup-debug; tar cvzf linuxq3a-$(VERSION)-DEBUG.tar.gz quake3 + +## temps +# NOTE: not referenced + +dcp: + cp debug$(ARCH)-glibc/linuxquake3 $(TESTDIR)/quake3-$(VERSION)-debug.$(ARCH) + cp debug$(ARCH)-glibc/linuxq3ded $(TESTDIR)/q3ded-$(VERSION)-debug.$(ARCH) + cp debug$(ARCH)-glibc/baseq3/cgame$(ARCH).so $(TESTDIR)/baseq3/cgame$(ARCH)-debug.so + cp debug$(ARCH)-glibc/baseq3/qagame$(ARCH).so $(TESTDIR)/baseq3/qagame$(ARCH)-debug.so + cp debug$(ARCH)-glibc/baseq3/ui$(ARCH).so $(TESTDIR)/baseq3/ui$(ARCH)-debug.so + cp debug$(ARCH)-glibc/missionpack/cgame$(ARCH).so $(TESTDIR)/missionpack/cgame$(ARCH)-debug.so + cp debug$(ARCH)-glibc/missionpack/qagame$(ARCH).so $(TESTDIR)/missionpack/qagame$(ARCH)-debug.so + cp debug$(ARCH)-glibc/missionpack/ui$(ARCH).so $(TESTDIR)/missionpack/ui$(ARCH)-debug.so + cp debug$(ARCH)-glibc/baseq3/vm/*.qvm $(TESTDIR)/baseq3/vm/ + cp debug$(ARCH)-glibc/missionpack/vm/*.qvm $(TESTDIR)/missionpack/vm/ + +rcp: + cp release$(ARCH)-glibc/linuxquake3 $(TESTDIR)/quake3-$(VERSION).$(ARCH) + cp release$(ARCH)-glibc/linuxq3ded $(TESTDIR)/q3ded-$(VERSION).$(ARCH) + cp release$(ARCH)-glibc/baseq3/cgame$(ARCH).so $(TESTDIR)/baseq3/cgame$(ARCH).so + cp release$(ARCH)-glibc/baseq3/qagame$(ARCH).so $(TESTDIR)/baseq3/qagame$(ARCH).so + cp release$(ARCH)-glibc/baseq3/ui$(ARCH).so $(TESTDIR)/baseq3/ui$(ARCH).so + cp release$(ARCH)-glibc/missionpack/cgame$(ARCH).so $(TESTDIR)/missionpack/cgame$(ARCH).so + cp release$(ARCH)-glibc/missionpack/qagame$(ARCH).so $(TESTDIR)/missionpack/qagame$(ARCH).so + cp release$(ARCH)-glibc/missionpack/ui$(ARCH).so $(TESTDIR)/missionpack/ui$(ARCH).so + cp release$(ARCH)-glibc/baseq3/vm/*.qvm $(TESTDIR)/baseq3/vm/ + cp release$(ARCH)-glibc/missionpack/vm/*.qvm $(TESTDIR)/missionpack/vm/ diff --git a/CODE-mp/unix/snapvector.nasm b/CODE-mp/unix/snapvector.nasm new file mode 100644 index 0000000..705f3d3 --- /dev/null +++ b/CODE-mp/unix/snapvector.nasm @@ -0,0 +1,75 @@ +; +; Sys_SnapVector NASM code (Andrew Henderson) +; See win32/win_shared.c for the Win32 equivalent +; This code is provided to ensure that the +; rounding behavior (and, if necessary, the +; precision) of DLL and QVM code are identical +; e.g. for network-visible operations. +; See ftol.nasm for operations on a single float, +; as used in compiled VM and DLL code that does +; not use this system trap. +; + + +segment .data + +fpucw dd 0 +cw037F dd 0x037F ; Rounding to nearest (even). + +segment .text + +; void Sys_SnapVector( float *v ) +global Sys_SnapVector +Sys_SnapVector: + push eax + push ebp + mov ebp, esp + + fnstcw [fpucw] + mov eax, dword [ebp + 12] + fldcw [cw037F] + fld dword [eax] + fistp dword [eax] + fild dword [eax] + fstp dword [eax] + fld dword [eax + 4] + fistp dword [eax + 4] + fild dword [eax + 4] + fstp dword [eax + 4] + fld dword [eax + 8] + fistp dword [eax + 8] + fild dword [eax + 8] + fstp dword [eax + 8] + fldcw [fpucw] + + pop ebp + pop eax + ret + +; void Sys_SnapVectorCW( float *v, unsigned short int cw ) +global Sys_SnapVectorCW +Sys_SnapVector_cw: + push eax + push ebp + mov ebp, esp + + fnstcw [fpucw] + mov eax, dword [ebp + 12] + fldcw [ebp + 16] + fld dword [eax] + fistp dword [eax] + fild dword [eax] + fstp dword [eax] + fld dword [eax + 4] + fistp dword [eax + 4] + fild dword [eax + 4] + fstp dword [eax + 4] + fld dword [eax + 8] + fistp dword [eax + 8] + fild dword [eax + 8] + fstp dword [eax + 8] + fldcw [fpucw] + + pop ebp + pop eax + ret \ No newline at end of file diff --git a/CODE-mp/unix/unix_main.c b/CODE-mp/unix/unix_main.c new file mode 100644 index 0000000..8d58b9b --- /dev/null +++ b/CODE-mp/unix/unix_main.c @@ -0,0 +1,1164 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __linux__ // rb010123 +#include +#endif +#include + +#ifdef __linux__ +#include // bk001213 - force dumps on divide by zero +#endif + + +#include "../game/q_shared.h" +#include "../qcommon/qcommon.h" +#include "../renderer/tr_public.h" + +#include "linux_local.h" // bk001204 + +cvar_t *nostdout; + +// Structure containing functions exported from refresh DLL +refexport_t re; + +unsigned sys_frame_time; + +uid_t saved_euid; +qboolean stdin_active = qtrue; + +// ======================================================================= +// General routines +// ======================================================================= + +// bk001207 +#define MEM_THRESHOLD 96*1024*1024 +/* +================== +Sys_LowPhysicalMemory() +================== +*/ +qboolean Sys_LowPhysicalMemory() { + //MEMORYSTATUS stat; + //GlobalMemoryStatus (&stat); + //return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse; + return qfalse; // bk001207 - FIXME +} + +/* +================== +Sys_FunctionCmp +================== +*/ +int Sys_FunctionCmp(void *f1, void *f2) { + return qtrue; +} + +/* +================== +Sys_FunctionCheckSum +================== +*/ +int Sys_FunctionCheckSum(void *f1) { + return 0; +} + +/* +================== +Sys_MonkeyShouldBeSpanked +================== +*/ +int Sys_MonkeyShouldBeSpanked( void ) { + return 0; +} + +void Sys_BeginProfiling( void ) { +} + +/* +================= +Sys_In_Restart_f + +Restart the input subsystem +================= +*/ +void Sys_In_Restart_f( void ) +{ + IN_Shutdown(); + IN_Init(); +} + +void Sys_ConsoleOutput (char *string) +{ + if (nostdout && nostdout->value) + return; + + fputs(string, stdout); +} + +void Sys_Printf (char *fmt, ...) +{ + va_list argptr; + char text[1024]; + unsigned char *p; + + va_start (argptr,fmt); + vsprintf (text,fmt,argptr); + va_end (argptr); + + if (strlen(text) > sizeof(text)) + Sys_Error("memory overwrite in Sys_Printf"); + + if (nostdout && nostdout->value) + return; + + for (p = (unsigned char *)text; *p; p++) { + *p &= 0x7f; + if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9) + printf("[%02x]", *p); + else + putc(*p, stdout); + } +} + +// bk010104 - added for abstraction +void Sys_Exit( int ex ) { +#ifdef NDEBUG // regular behavior + // We can't do this + // as long as GL DLL's keep installing with atexit... + //exit(ex); + _exit(ex); +#else + // Give me a backtrace on error exits. + assert( ex == 0 ); + exit(ex); +#endif +} + + +void Sys_Quit (void) { + CL_Shutdown (); + fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); + Sys_Exit(0); +} + +void Sys_Init(void) +{ + Cmd_AddCommand ("in_restart", Sys_In_Restart_f); + +#if defined __linux__ +#if defined __i386__ + Cvar_Set( "arch", "linux i386" ); +#elif defined __alpha__ + Cvar_Set( "arch", "linux alpha" ); +#elif defined __sparc__ + Cvar_Set( "arch", "linux sparc" ); +#elif defined __FreeBSD__ + +#if defined __i386__ // FreeBSD + Cvar_Set( "arch", "freebsd i386" ); +#elif defined __alpha__ + Cvar_Set( "arch", "freebsd alpha" ); +#else + Cvar_Set( "arch", "freebsd unknown" ); +#endif // FreeBSD + +#else + Cvar_Set( "arch", "linux unknown" ); +#endif +#elif defined __sun__ +#if defined __i386__ + Cvar_Set( "arch", "solaris x86" ); +#elif defined __sparc__ + Cvar_Set( "arch", "solaris sparc" ); +#else + Cvar_Set( "arch", "solaris unknown" ); +#endif +#elif defined __sgi__ +#if defined __mips__ + Cvar_Set( "arch", "sgi mips" ); +#else + Cvar_Set( "arch", "sgi unknown" ); +#endif +#else + Cvar_Set( "arch", "unknown" ); +#endif + + Cvar_Set( "username", Sys_GetCurrentUser() ); + + IN_Init(); + +} + +void Sys_Error( const char *error, ...) +{ + va_list argptr; + char string[1024]; + + // change stdin to non blocking + fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); + + CL_Shutdown (); + + va_start (argptr,error); + vsprintf (string,error,argptr); + va_end (argptr); + fprintf(stderr, "Sys_Error: %s\n", string); + + Sys_Exit( 1 ); // bk010104 - use single exit point. +} + +void Sys_Warn (char *warning, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,warning); + vsprintf (string,warning,argptr); + va_end (argptr); + fprintf(stderr, "Warning: %s", string); +} + +/* +============ +Sys_FileTime + +returns -1 if not present +============ +*/ +int Sys_FileTime (char *path) +{ + struct stat buf; + + if (stat (path,&buf) == -1) + return -1; + + return buf.st_mtime; +} + +void floating_point_exception_handler(int whatever) +{ + signal(SIGFPE, floating_point_exception_handler); +} + +char *Sys_ConsoleInput(void) +{ + static char text[256]; + int len; + fd_set fdset; + struct timeval timeout; + + if (!com_dedicated || !com_dedicated->value) + return NULL; + + if (!stdin_active) + return NULL; + + FD_ZERO(&fdset); + FD_SET(0, &fdset); // stdin + timeout.tv_sec = 0; + timeout.tv_usec = 0; + if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset)) + return NULL; + + len = read (0, text, sizeof(text)); + if (len == 0) { // eof! + stdin_active = qfalse; + return NULL; + } + + if (len < 1) + return NULL; + text[len-1] = 0; // rip off the /n and terminate + + return text; +} + +/*****************************************************************************/ + +/* +================= +Sys_UnloadDll + +================= +*/ +void Sys_UnloadDll( void *dllHandle ) { + // bk001206 - verbose error reporting + const char* err; // rb010123 - now const + if ( !dllHandle ) { + Com_Printf("Sys_UnloadDll(NULL)\n"); + return; + } + dlclose( dllHandle ); + err = dlerror(); + if ( err != NULL ) + Com_Printf ( "Sys_UnloadGame failed on dlclose: \"%s\"!\n", err ); +} + + +/* +================= +Sys_LoadDll + +Used to load a development dll instead of a virtual machine +================= +*/ +extern char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ); + +void *Sys_LoadDll( const char *name, + int (**entryPoint)(int, ...), + int (*systemcalls)(int, ...) ) +{ + void *libHandle; + void (*dllEntry)( int (*syscallptr)(int, ...) ); + char curpath[MAX_OSPATH]; + char fname[MAX_OSPATH]; + //char loadname[MAX_OSPATH]; + char *basepath; + char *cdpath; + char *gamedir; + char *fn; + const char* err = NULL; // bk001206 // rb0101023 - now const + + // bk001206 - let's have some paranoia + assert( name ); + + getcwd(curpath, sizeof(curpath)); +#if defined __i386__ +#ifndef NDEBUG + snprintf (fname, sizeof(fname), "%si386-debug.so", name); // bk010205 - different DLL name +#else + snprintf (fname, sizeof(fname), "%si386.so", name); +#endif +#elif defined __powerpc__ //rcg010207 - PPC support. + snprintf (fname, sizeof(fname), "%sppc.so", name); +#elif defined __axp__ + snprintf (fname, sizeof(fname), "%saxp.so", name); +#elif defined __mips__ + snprintf (fname, sizeof(fname), "%smips.so", name); +#else +#error Unknown arch +#endif + +// bk001129 - was RTLD_LAZY +#define Q_RTLD RTLD_NOW + +#if 0 // bk010205 - was NDEBUG // bk001129 - FIXME: what is this good for? + // bk001206 - do not have different behavior in builds + Q_strncpyz(loadname, curpath, sizeof(loadname)); + // bk001129 - from cvs1.17 (mkv) + Q_strcat(loadname, sizeof(loadname), "/"); + + Q_strcat(loadname, sizeof(loadname), fname); + Com_Printf( "Sys_LoadDll(%s)... \n", loadname ); + libHandle = dlopen( loadname, Q_RTLD ); + //if ( !libHandle ) { + // bk001206 - report any problem + //Com_Printf( "Sys_LoadDll(%s) failed: \"%s\"\n", loadname, dlerror() ); +#endif // bk010205 - do not load from installdir + + basepath = Cvar_VariableString( "fs_basepath" ); + cdpath = Cvar_VariableString( "fs_cdpath" ); + gamedir = Cvar_VariableString( "fs_game" ); + + fn = FS_BuildOSPath( basepath, gamedir, fname ); + // bk001206 - verbose + Com_Printf( "Sys_LoadDll(%s)... \n", fn ); + + // bk001129 - from cvs1.17 (mkv), was fname not fn + libHandle = dlopen( fn, Q_RTLD ); + + if ( !libHandle ) { + if( cdpath[0] ) { + // bk001206 - report any problem + Com_Printf( "Sys_LoadDll(%s) failed: \"%s\"\n", fn, dlerror() ); + + fn = FS_BuildOSPath( cdpath, gamedir, fname ); + libHandle = dlopen( fn, Q_RTLD ); + if ( !libHandle ) { + // bk001206 - report any problem + Com_Printf( "Sys_LoadDll(%s) failed: \"%s\"\n", fn, dlerror() ); + } + else + Com_Printf ( "Sys_LoadDll(%s): succeeded ...\n", fn ); + } + else + Com_Printf ( "Sys_LoadDll(%s): succeeded ...\n", fn ); + + if ( !libHandle ) { +#ifdef NDEBUG // bk001206 - in debug abort on failure + Com_Error ( ERR_FATAL, "Sys_LoadDll(%s) failed dlopen() completely!\n", name ); +#else + Com_Printf ( "Sys_LoadDll(%s) failed dlopen() completely!\n", name ); +#endif + return NULL; + } + } + // bk001206 - no different behavior + //#ifndef NDEBUG } + //else Com_Printf ( "Sys_LoadDll(%s): succeeded ...\n", loadname ); + //#endif + + dllEntry = (void (*)(int (*)(int,...))) dlsym( libHandle, "dllEntry" ); + *entryPoint = (int(*)(int,...))dlsym( libHandle, "vmMain" ); + if ( !*entryPoint || !dllEntry ) { + err = dlerror(); +#ifdef NDEBUG // bk001206 - in debug abort on failure + Com_Error ( ERR_FATAL, "Sys_LoadDll(%s) failed dlsym(vmMain): \"%s\" !\n", name, err ); +#else + Com_Printf ( "Sys_LoadDll(%s) failed dlsym(vmMain): \"%s\" !\n", name, err ); +#endif + dlclose( libHandle ); + err = dlerror(); + if ( err != NULL ) + Com_Printf ( "Sys_LoadDll(%s) failed dlcose: \"%s\"\n", name, err ); + return NULL; + } + Com_Printf ( "Sys_LoadDll(%s) found **vmMain** at %p \n", name, *entryPoint ); // bk001212 + dllEntry( systemcalls ); + Com_Printf ( "Sys_LoadDll(%s) succeeded!\n", name ); + return libHandle; +} + + +#if 0 // bk010215 - scheduled for full deletion +/*****************************************************************************/ + +static void *game_library; + +#ifdef __i386__ + const char *gamename = "qagamei386.so"; +#elif defined __alpha__ + const char *gamename = "qagameaxp.so"; +#elif defined __mips__ + const char *gamename = "qagamemips.so"; +#else +#error Unknown arch +#endif + +/* +================= +Sys_UnloadGame +================= +*/ +void Sys_UnloadGame (void) { + // bk001206 - this code is never used + assert(0); + + Com_Printf("------ Unloading %s ------\n", gamename); + if (game_library) { + dlclose (game_library); + game_library = NULL; + } +} + +/* +================= +Sys_GetGameAPI + +Loads the game dll +================= +*/ +void *Sys_GetGameAPI (void *parms) +{ + void *(*GetGameAPI) (void *); + + char name[MAX_OSPATH]; + char curpath[MAX_OSPATH]; + //char *path; // bk001204 - unused + + // bk001206 - this code is never used + assert(0); + + if (game_library) + Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame"); + + // check the current debug directory first for development purposes + getcwd(curpath, sizeof(curpath)); + + Com_Printf("------- Loading %s -------\n", gamename); + Com_sprintf (name, sizeof(name), "%s/%s", curpath, gamename); + + game_library = dlopen (name, RTLD_LAZY ); + if (game_library) + Com_DPrintf ("LoadLibrary (%s)\n",name); + else { + Com_Printf( "LoadLibrary(\"%s\") failed\n", name); + Com_Printf( "...reason: '%s'\n", dlerror() ); + Com_Error( ERR_FATAL, "Couldn't load game" ); + } + + GetGameAPI = (void *)dlsym (game_library, "GetGameAPI"); + if (!GetGameAPI) + { + Sys_UnloadGame (); + return NULL; + } + + return GetGameAPI (parms); +} + +/*****************************************************************************/ + +static void *cgame_library; + +/* +================= +Sys_UnloadGame +================= +*/ +void Sys_UnloadCGame (void) +{ + // bk001206 - this code is never used + assert(0); + if (cgame_library) + dlclose (cgame_library); + cgame_library = NULL; +} + +/* +================= +Sys_GetGameAPI + +Loads the game dll +================= +*/ +void *Sys_GetCGameAPI (void) +{ + void *(*api) (void); + + char name[MAX_OSPATH]; + char curpath[MAX_OSPATH]; +#ifdef __i386__ + const char *cgamename = "cgamei386.so"; +#elif defined __alpha__ + const char *cgamename = "cgameaxp.so"; +#elif defined __mips__ + const char *cgamename = "cgamemips.so"; +#else +#error Unknown arch +#endif + + // bk001206 - this code is never used + assert(0); + + Sys_UnloadCGame(); + + getcwd(curpath, sizeof(curpath)); + + Com_Printf("------- Loading %s -------\n", cgamename); + + sprintf (name, "%s/%s", curpath, cgamename); + cgame_library = dlopen (name, RTLD_LAZY ); + if (!cgame_library) + { + Com_Printf ("LoadLibrary (%s)\n",name); + Com_Error( ERR_FATAL, "Couldn't load cgame: %s", dlerror() ); + } + + api = (void *)dlsym (cgame_library, "GetCGameAPI"); + if (!api) + { + Com_Error( ERR_FATAL, "dlsym() failed on GetCGameAPI" ); + } + + return api(); +} + +/*****************************************************************************/ + +static void *ui_library; + +/* +================= +Sys_UnloadUI +================= +*/ +void Sys_UnloadUI(void) +{ + // bk001206 - this code is never used + assert(0); + if (ui_library) + dlclose (ui_library); + ui_library = NULL; +} + +/* +================= +Sys_GetUIAPI + +Loads the ui dll +================= +*/ +void *Sys_GetUIAPI (void) +{ + void *(*api)(void); + + char name[MAX_OSPATH]; + char curpath[MAX_OSPATH]; +#ifdef __i386__ + const char *uiname = "uii386.so"; +#elif defined __alpha__ + const char *uiname = "uiaxp.so"; +#elif defined __mips__ + const char *uiname = "uimips.so"; +#else +#error Unknown arch +#endif + + // bk001206 - this code is never used + assert(0); + Sys_UnloadUI(); + + getcwd(curpath, sizeof(curpath)); + + Com_Printf("------- Loading %s -------\n", uiname); + + sprintf (name, "%s/%s", curpath, uiname); + ui_library = dlopen (name, RTLD_LAZY ); + if (!ui_library) + { + Com_Printf ("LoadLibrary (%s)\n",name); + Com_Error( ERR_FATAL, "Couldn't load ui: %s", dlerror() ); + } + + api = (void *(*)(void))dlsym (ui_library, "GetUIAPI"); + if (!api) + { + Com_Error( ERR_FATAL, "dlsym() failed on GetUIAPI" ); + } + + return api(); +} + +/*****************************************************************************/ + +static void *botlib_library; + +/* +================= +Sys_UnloadGame +================= +*/ +void Sys_UnloadBotLib (void) +{ + // bk001206 - this code is never used + assert(0); + if (botlib_library) + dlclose (botlib_library); + botlib_library = NULL; +} + +/* +================= +Sys_GetGameAPI + +Loads the game dll +================= +*/ +void *Sys_GetBotLibAPI (void *parms ) +{ + void *(*GetBotLibAPI) (void *); + char name[MAX_OSPATH]; + char curpath[MAX_OSPATH]; +#ifdef __i386__ + const char *botlibname = "qaboti386.so"; +#elif defined __alpha__ + const char *botlibname = "qabotaxp.so"; +#elif defined __mips__ + const char *botlibname = "qabotmips.so"; +#else +#error Unknown arch +#endif + // bk001129 - this code is never used + assert(0); + + Sys_UnloadBotLib(); + + getcwd(curpath, sizeof(curpath)); + + Com_Printf("------- Loading %s -------\n", botlibname); + + sprintf (name, "%s/%s", curpath, botlibname);\ + // bk001129 - was RTLD_LAZY + botlib_library = dlopen (name, RTLD_NOW ); + if (!botlib_library) + { + Com_Printf ("LoadLibrary (%s)\n",name); + Com_Error( ERR_FATAL, "Couldn't load botlib: %s", dlerror() ); + } + + GetBotLibAPI = (void *)dlsym (botlib_library, "GetBotLibAPI"); + if (!GetBotLibAPI) + { + Sys_UnloadBotLib (); + Com_Error( ERR_FATAL, "dlsym() failed on GetBotLibAPI" ); + } + + // bk001129 - this is a signature mismatch + return GetBotLibAPI (parms); +} + +void *Sys_GetBotAIAPI (void *parms ) { + return NULL; +} + +/*****************************************************************************/ +#endif // bk010215 + + +/* +======================================================================== + +BACKGROUND FILE STREAMING + +======================================================================== +*/ + +#if 1 + +void Sys_InitStreamThread( void ) { +} + +void Sys_ShutdownStreamThread( void ) { +} + +void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) { +} + +void Sys_EndStreamedFile( fileHandle_t f ) { +} + +int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) { + return FS_Read( buffer, size * count, f ); +} + +void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) { + FS_Seek( f, offset, origin ); +} + +#else + +typedef struct { + fileHandle_t file; + byte *buffer; + qboolean eof; + int bufferSize; + int streamPosition; // next byte to be returned by Sys_StreamRead + int threadPosition; // next byte to be read from file +} streamState_t; + +streamState_t stream; + +/* +=============== +Sys_StreamThread + +A thread will be sitting in this loop forever +================ +*/ +void Sys_StreamThread( void ) +{ + int buffer; + int count; + int readCount; + int bufferPoint; + int r; + + // if there is any space left in the buffer, fill it up + if ( !stream.eof ) { + count = stream.bufferSize - (stream.threadPosition - stream.streamPosition); + if ( count ) { + bufferPoint = stream.threadPosition % stream.bufferSize; + buffer = stream.bufferSize - bufferPoint; + readCount = buffer < count ? buffer : count; + r = FS_Read ( stream.buffer + bufferPoint, readCount, stream.file ); + stream.threadPosition += r; + + if ( r != readCount ) + stream.eof = qtrue; + } + } +} + +/* +=============== +Sys_InitStreamThread + +================ +*/ +void Sys_InitStreamThread( void ) +{ +} + +/* +=============== +Sys_ShutdownStreamThread + +================ +*/ +void Sys_ShutdownStreamThread( void ) +{ +} + + +/* +=============== +Sys_BeginStreamedFile + +================ +*/ +void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) +{ + if ( stream.file ) { + Com_Error( ERR_FATAL, "Sys_BeginStreamedFile: unclosed stream"); + } + + stream.file = f; + stream.buffer = Z_Malloc( readAhead,TAG_FILESYS,qfalse ); + stream.bufferSize = readAhead; + stream.streamPosition = 0; + stream.threadPosition = 0; + stream.eof = qfalse; +} + +/* +=============== +Sys_EndStreamedFile + +================ +*/ +void Sys_EndStreamedFile( fileHandle_t f ) +{ + if ( f != stream.file ) { + Com_Error( ERR_FATAL, "Sys_EndStreamedFile: wrong file"); + } + + stream.file = 0; + Z_Free( stream.buffer ); +} + + +/* +=============== +Sys_StreamedRead + +================ +*/ +int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) +{ + int available; + int remaining; + int sleepCount; + int copy; + int bufferCount; + int bufferPoint; + byte *dest; + + dest = (byte *)buffer; + remaining = size * count; + + if ( remaining <= 0 ) { + Com_Error( ERR_FATAL, "Streamed read with non-positive size" ); + } + + sleepCount = 0; + while ( remaining > 0 ) { + available = stream.threadPosition - stream.streamPosition; + if ( !available ) { + if (stream.eof) + break; + Sys_StreamThread(); + continue; + } + + bufferPoint = stream.streamPosition % stream.bufferSize; + bufferCount = stream.bufferSize - bufferPoint; + + copy = available < bufferCount ? available : bufferCount; + if ( copy > remaining ) { + copy = remaining; + } + memcpy( dest, stream.buffer + bufferPoint, copy ); + stream.streamPosition += copy; + dest += copy; + remaining -= copy; + } + + return (count * size - remaining) / size; +} + +/* +=============== +Sys_StreamSeek + +================ +*/ +void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) { + // clear to that point + FS_Seek( f, offset, origin ); + stream.streamPosition = 0; + stream.threadPosition = 0; + stream.eof = qfalse; +} + +#endif + +/* +======================================================================== + +EVENT LOOP + +======================================================================== +*/ + +// bk000306: upped this from 64 +#define MAX_QUED_EVENTS 256 +#define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 ) + +sysEvent_t eventQue[MAX_QUED_EVENTS]; +// bk000306: initialize +int eventHead = 0; +int eventTail = 0; +byte sys_packetReceived[MAX_MSGLEN]; + +/* +================ +Sys_QueEvent + +A time of 0 will get the current time +Ptr should either be null, or point to a block of data that can +be freed by the game later. +================ +*/ +void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) { + sysEvent_t *ev; + + ev = &eventQue[ eventHead & MASK_QUED_EVENTS ]; + + // bk000305 - was missing + if ( eventHead - eventTail >= MAX_QUED_EVENTS ) { + Com_Printf("Sys_QueEvent: overflow\n"); + // we are discarding an event, but don't leak memory + if ( ev->evPtr ) { + Z_Free( ev->evPtr ); + } + eventTail++; + } + + eventHead++; + + if ( time == 0 ) { + time = Sys_Milliseconds(); + } + + ev->evTime = time; + ev->evType = type; + ev->evValue = value; + ev->evValue2 = value2; + ev->evPtrLength = ptrLength; + ev->evPtr = ptr; +} + +/* +================ +Sys_GetEvent + +================ +*/ +sysEvent_t Sys_GetEvent( void ) { + sysEvent_t ev; + char *s; + msg_t netmsg; + netadr_t adr; + + // return if we have data + if ( eventHead > eventTail ) { + eventTail++; + return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ]; + } + + // pump the message loop + // in vga this calls KBD_Update, under X, it calls GetEvent + Sys_SendKeyEvents (); + + // check for console commands + s = Sys_ConsoleInput(); + if ( s ) { + char *b; + int len; + + len = strlen( s ) + 1; + b = (char *)Z_Malloc( len,TAG_EVENT,qfalse ); + strcpy( b, s ); + Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b ); + } + + // check for other input devices + IN_Frame(); + + // check for network packets + MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) ); + if ( Sys_GetPacket ( &adr, &netmsg ) ) { + netadr_t *buf; + int len; + + // copy out to a seperate buffer for qeueing + len = sizeof( netadr_t ) + netmsg.cursize; + buf = (netadr_t *)Z_Malloc( len,TAG_EVENT,qfalse ); + *buf = adr; + memcpy( buf+1, netmsg.data, netmsg.cursize ); + Sys_QueEvent( 0, SE_PACKET, 0, 0, len, buf ); + } + + // return if we have data + if ( eventHead > eventTail ) { + eventTail++; + return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ]; + } + + // create an empty event to return + + memset( &ev, 0, sizeof( ev ) ); + ev.evTime = Sys_Milliseconds(); + + return ev; +} + +/*****************************************************************************/ + +qboolean Sys_CheckCD( void ) { + return qtrue; +} + +void Sys_AppActivate (void) +{ +} + +char *Sys_GetClipboardData(void) +{ + return NULL; +} + +void Sys_Print( const char *msg ) +{ + fputs(msg, stderr); +} + + +void Sys_ConfigureFPU() { // bk001213 - divide by zero +#ifdef __linux__ +#ifdef __i386 +#ifndef NDEBUG + // bk0101022 - enable FPE's in debug mode + static int fpu_word = _FPU_DEFAULT & ~(_FPU_MASK_ZM | _FPU_MASK_IM); + int current = 0; + _FPU_GETCW(current); + if ( current!=fpu_word) { +#if 0 + Com_Printf("FPU Control 0x%x (was 0x%x)\n", fpu_word, current ); + _FPU_SETCW( fpu_word ); + _FPU_GETCW( current ); + assert(fpu_word==current); +#endif + } +#else // NDEBUG + static int fpu_word = _FPU_DEFAULT; + _FPU_SETCW( fpu_word ); +#endif // NDEBUG +#endif // __i386 +#endif // __linux +} + + +void Sys_PrintBinVersion( const char* name ) { + char* date = __DATE__; + char* time = __TIME__; + char* sep = "=============================================================="; + fprintf( stdout, "\n\n%s\n", sep ); +#ifdef DEDICATED + fprintf( stdout, "Linux Quake3 Dedicated Server [%s %s]\n", date, time ); +#else + fprintf( stdout, "Linux Quake3 Full Executable [%s %s]\n", date, time ); +#endif + fprintf( stdout, " local install: %s\n", name ); + fprintf( stdout, "%s\n\n", sep ); +} + +void Sys_ParseArgs( int argc, char* argv[] ) { + + if ( argc==2 ) { + if ( (!strcmp( argv[1], "--version" )) + || ( !strcmp( argv[1], "-v" )) ) + { + Sys_PrintBinVersion( argv[0] ); + Sys_Exit(0); + } + } +} + +#include "../client/client.h" +extern clientStatic_t cls; + +int main ( int argc, char* argv[] ) +{ + // int oldtime, newtime; // bk001204 - unused + int len, i; + char *cmdline; + void Sys_SetDefaultCDPath(const char *path); + + // go back to real user for config loads + saved_euid = geteuid(); + seteuid(getuid()); + + Sys_ParseArgs( argc, argv ); // bk010104 - added this for support + + Sys_SetDefaultCDPath(argv[0]); + + // merge the command line, this is kinda silly + for (len = 1, i = 1; i < argc; i++) + len += strlen(argv[i]) + 1; + cmdline = (char *)malloc(len); + *cmdline = 0; + for (i = 1; i < argc; i++) { + if (i > 1) + strcat(cmdline, " "); + strcat(cmdline, argv[i]); + } + + // bk000306 - clear queues + memset( &eventQue[0], 0, MAX_QUED_EVENTS*sizeof(sysEvent_t) ); + memset( &sys_packetReceived[0], 0, MAX_MSGLEN*sizeof(byte) ); + + Com_Init(cmdline); + NET_Init(); + + fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); + + nostdout = Cvar_Get("nostdout", "0", 0); + if (!nostdout->value) { + fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); + } + + while (1) { +#ifdef __linux__ + Sys_ConfigureFPU(); +#endif + Com_Frame (); + } +} diff --git a/CODE-mp/unix/unix_net.c b/CODE-mp/unix/unix_net.c new file mode 100644 index 0000000..bce5aa6 --- /dev/null +++ b/CODE-mp/unix/unix_net.c @@ -0,0 +1,595 @@ +// unix_net.c + +#include "../game/q_shared.h" +#include "../qcommon/qcommon.h" + +#include +#include +#include +#include +#include +#include // bk001204 + +#include +#include +#include +#include + +#ifdef MACOS_X +#import +#import +#import + +#import // for inet_ntoa() +#import // for 'struct sockaddr_dl' +#endif + +static cvar_t *noudp; + +netadr_t net_local_adr; + +int ip_socket; +int ipx_socket; + +#define MAX_IPS 16 +static int numIP; +static byte localIP[MAX_IPS][4]; + +int NET_Socket (char *net_interface, int port); +char *NET_ErrorString (void); + +//============================================================================= + +void NetadrToSockadr (netadr_t *a, struct sockaddr_in *s) +{ + memset (s, 0, sizeof(*s)); + + if (a->type == NA_BROADCAST) + { + s->sin_family = AF_INET; + + s->sin_port = a->port; + *(int *)&s->sin_addr = -1; + } + else if (a->type == NA_IP) + { + s->sin_family = AF_INET; + + *(int *)&s->sin_addr = *(int *)&a->ip; + s->sin_port = a->port; + } +} + +void SockadrToNetadr (struct sockaddr_in *s, netadr_t *a) +{ + *(int *)&a->ip = *(int *)&s->sin_addr; + a->port = s->sin_port; + a->type = NA_IP; +} + +char *NET_BaseAdrToString (netadr_t a) +{ + static char s[64]; + + Com_sprintf (s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]); + + return s; +} + +/* +============= +Sys_StringToAdr + +idnewt +192.246.40.70 +============= +*/ +qboolean Sys_StringToSockaddr (const char *s, struct sockaddr *sadr) +{ + struct hostent *h; + //char *colon; // bk001204 - unused + + memset (sadr, 0, sizeof(*sadr)); + ((struct sockaddr_in *)sadr)->sin_family = AF_INET; + + ((struct sockaddr_in *)sadr)->sin_port = 0; + + if ( s[0] >= '0' && s[0] <= '9') + { + *(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(s); + } + else + { + if (! (h = gethostbyname(s)) ) + return qfalse; + *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0]; + } + + return qtrue; +} + +/* +============= +Sys_StringToAdr + +localhost +idnewt +idnewt:28000 +192.246.40.70 +192.246.40.70:28000 +============= +*/ +qboolean Sys_StringToAdr (const char *s, netadr_t *a) +{ + struct sockaddr_in sadr; + + if (!Sys_StringToSockaddr (s, (struct sockaddr *)&sadr)) + return qfalse; + + SockadrToNetadr (&sadr, a); + + return qtrue; +} + + +//============================================================================= + +qboolean Sys_GetPacket (netadr_t *net_from, msg_t *net_message) +{ + int ret; + struct sockaddr_in from; + int fromlen; + int net_socket; + int protocol; + int err; + + for (protocol = 0 ; protocol < 2 ; protocol++) + { + if (protocol == 0) + net_socket = ip_socket; + else + net_socket = ipx_socket; + + if (!net_socket) + continue; + + fromlen = sizeof(from); + ret = recvfrom (net_socket, net_message->data, net_message->maxsize + , 0, (struct sockaddr *)&from,(socklen_t*) &fromlen); + + SockadrToNetadr (&from, net_from); + // bk000305: was missing + net_message->readcount = 0; + + if (ret == -1) + { + err = errno; + + if (err == EWOULDBLOCK || err == ECONNREFUSED) + continue; + Com_Printf ("NET_GetPacket: %s from %s\n", NET_ErrorString(), + NET_AdrToString(*net_from)); + continue; + } + + if (ret == net_message->maxsize) + { + Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from)); + continue; + } + + net_message->cursize = ret; + return qtrue; + } + + return qfalse; +} + +//============================================================================= + +void Sys_SendPacket( int length, const void *data, netadr_t to ) +{ + int ret; + struct sockaddr_in addr; + int net_socket; + + if (to.type == NA_BROADCAST) + { + net_socket = ip_socket; + } + else if (to.type == NA_IP) + { + net_socket = ip_socket; + } + else if (to.type == NA_IPX) + { + net_socket = ipx_socket; + } + else if (to.type == NA_BROADCAST_IPX) + { + net_socket = ipx_socket; + } + else { + Com_Error (ERR_FATAL, "NET_SendPacket: bad address type"); + return; + } + + if (!net_socket) + return; + + NetadrToSockadr (&to, &addr); + + ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) ); + if (ret == -1) + { + Com_Printf ("NET_SendPacket ERROR: %s to %s\n", NET_ErrorString(), + NET_AdrToString (to)); + } +} + + +//============================================================================= + +/* +================== +Sys_IsLANAddress + +LAN clients will have their rate var ignored +================== +*/ +qboolean Sys_IsLANAddress (netadr_t adr) { + int i; + + if( adr.type == NA_LOOPBACK ) { + return qtrue; + } + + if( adr.type == NA_IPX ) { + return qtrue; + } + + if( adr.type != NA_IP ) { + return qfalse; + } + + // choose which comparison to use based on the class of the address being tested + // any local adresses of a different class than the address being tested will fail based on the first byte + + // Class A + if( (adr.ip[0] & 0x80) == 0x00 ) { + for ( i = 0 ; i < numIP ; i++ ) { + if( adr.ip[0] == localIP[i][0] ) { + return qtrue; + } + } + // the RFC1918 class a block will pass the above test + return qfalse; + } + + // Class B + if( (adr.ip[0] & 0xc0) == 0x80 ) { + for ( i = 0 ; i < numIP ; i++ ) { + if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] ) { + return qtrue; + } + // also check against the RFC1918 class b blocks + if( adr.ip[0] == 172 && localIP[i][0] == 172 && (adr.ip[1] & 0xf0) == 16 && (localIP[i][1] & 0xf0) == 16 ) { + return qtrue; + } + } + return qfalse; + } + + // Class C + for ( i = 0 ; i < numIP ; i++ ) { + if( adr.ip[0] == localIP[i][0] && adr.ip[1] == localIP[i][1] && adr.ip[2] == localIP[i][2] ) { + return qtrue; + } + // also check against the RFC1918 class c blocks + if( adr.ip[0] == 192 && localIP[i][0] == 192 && adr.ip[1] == 168 && localIP[i][1] == 168 ) { + return qtrue; + } + } + return qfalse; +} + +/* +================== +Sys_ShowIP +================== +*/ +void Sys_ShowIP(void) { + int i; + + for (i = 0; i < numIP; i++) { + Com_Printf( "IP: %i.%i.%i.%i\n", localIP[i][0], localIP[i][1], localIP[i][2], localIP[i][3] ); + } +} + +/* +===================== +NET_GetLocalAddress +===================== +*/ +#ifdef MACOS_X +// Don't do a forward mapping from the hostname of the machine to the IP. The reason is that we might have obtained an IP address from DHCP and there might not be any name registered for the machine. On Mac OS X, the machine name defaults to 'localhost' and NetInfo has 127.0.0.1 listed for this name. Instead, we want to get a list of all the IP network interfaces on the machine. +// This code adapted from OmniNetworking. + +#define IFR_NEXT(ifr) \ + ((struct ifreq *) ((char *) (ifr) + sizeof(*(ifr)) + \ + MAX(0, (int) (ifr)->ifr_addr.sa_len - (int) sizeof((ifr)->ifr_addr)))) + +void NET_GetLocalAddress( void ) { + struct ifreq requestBuffer[MAX_IPS], *linkInterface, *inetInterface; + struct ifconf ifc; + struct ifreq ifr; + struct sockaddr_dl *sdl; + int interfaceSocket; + int family; + + //Com_Printf("NET_GetLocalAddress: Querying for network interfaces\n"); + + // Set this early so we can just return if there is an error + numIP = 0; + + ifc.ifc_len = sizeof(requestBuffer); + ifc.ifc_buf = (caddr_t)requestBuffer; + + // Since we get at this info via an ioctl, we need a temporary little socket. This will only get AF_INET interfaces, but we probably don't care about anything else. If we do end up caring later, we should add a ONAddressFamily and at a -interfaces method to it. + family = AF_INET; + if ((interfaceSocket = socket(family, SOCK_DGRAM, 0)) < 0) { + Com_Printf("NET_GetLocalAddress: Unable to create temporary socket, errno = %d\n", errno); + return; + } + + if (ioctl(interfaceSocket, SIOCGIFCONF, &ifc) != 0) { + Com_Printf("NET_GetLocalAddress: Unable to get list of network interfaces, errno = %d\n", errno); + return; + } + + + linkInterface = (struct ifreq *) ifc.ifc_buf; + while ((char *) linkInterface < &ifc.ifc_buf[ifc.ifc_len]) { + unsigned int nameLength; + + // The ioctl returns both the entries having the address (AF_INET) and the link layer entries (AF_LINK). The AF_LINK entry has the link layer address which contains the interface type. This is the only way I can see to get this information. We cannot assume that we will get bot an AF_LINK and AF_INET entry since the interface may not be configured. For example, if you have a 10Mb port on the motherboard and a 100Mb card, you may not configure the motherboard port. + + // For each AF_LINK entry... + if (linkInterface->ifr_addr.sa_family == AF_LINK) { + // if there is a matching AF_INET entry + inetInterface = (struct ifreq *) ifc.ifc_buf; + while ((char *) inetInterface < &ifc.ifc_buf[ifc.ifc_len]) { + if (inetInterface->ifr_addr.sa_family == AF_INET && + !strncmp(inetInterface->ifr_name, linkInterface->ifr_name, sizeof(linkInterface->ifr_name))) { + + for (nameLength = 0; nameLength < IFNAMSIZ; nameLength++) + if (!linkInterface->ifr_name[nameLength]) + break; + + sdl = (struct sockaddr_dl *)&linkInterface->ifr_addr; + // Skip loopback interfaces + if (sdl->sdl_type != IFT_LOOP) { + // Get the local interface address + strncpy(ifr.ifr_name, inetInterface->ifr_name, sizeof(ifr.ifr_name)); + if (ioctl(interfaceSocket, OSIOCGIFADDR, (caddr_t)&ifr) < 0) { + Com_Printf("NET_GetLocalAddress: Unable to get local address for interface '%s', errno = %d\n", inetInterface->ifr_name, errno); + } else { + struct sockaddr_in *sin; + int ip; + + sin = (struct sockaddr_in *)&ifr.ifr_addr; + + ip = ntohl(sin->sin_addr.s_addr); + localIP[ numIP ][0] = (ip >> 24) & 0xff; + localIP[ numIP ][1] = (ip >> 16) & 0xff; + localIP[ numIP ][2] = (ip >> 8) & 0xff; + localIP[ numIP ][3] = (ip >> 0) & 0xff; + Com_Printf( "IP: %i.%i.%i.%i (%s)\n", localIP[ numIP ][0], localIP[ numIP ][1], localIP[ numIP ][2], localIP[ numIP ][3], inetInterface->ifr_name); + numIP++; + } + } + + // We will assume that there is only one AF_INET entry per AF_LINK entry. + // What happens when we have an interface that has multiple IP addresses, or + // can that even happen? + // break; + } + inetInterface = IFR_NEXT(inetInterface); + } + } + linkInterface = IFR_NEXT(linkInterface); + } + + close(interfaceSocket); +} + +#else +void NET_GetLocalAddress( void ) { + char hostname[256]; + struct hostent *hostInfo; + // int error; // bk001204 - unused + char *p; + int ip; + int n; + + if ( gethostname( hostname, 256 ) == -1 ) { + return; + } + + hostInfo = gethostbyname( hostname ); + if ( !hostInfo ) { + return; + } + + Com_Printf( "Hostname: %s\n", hostInfo->h_name ); + n = 0; + while( ( p = hostInfo->h_aliases[n++] ) != NULL ) { + Com_Printf( "Alias: %s\n", p ); + } + + if ( hostInfo->h_addrtype != AF_INET ) { + return; + } + + numIP = 0; + while( ( p = hostInfo->h_addr_list[numIP++] ) != NULL && numIP < MAX_IPS ) { + ip = ntohl( *(int *)p ); + localIP[ numIP ][0] = p[0]; + localIP[ numIP ][1] = p[1]; + localIP[ numIP ][2] = p[2]; + localIP[ numIP ][3] = p[3]; + Com_Printf( "IP: %i.%i.%i.%i\n", ( ip >> 24 ) & 0xff, ( ip >> 16 ) & 0xff, ( ip >> 8 ) & 0xff, ip & 0xff ); + } +} +#endif + +/* +==================== +NET_OpenIP +==================== +*/ +// bk001204 - prototype needed +int NET_IPSocket (char *net_interface, int port); +void NET_OpenIP (void) +{ + cvar_t *ip; + int port; + int i; + + ip = Cvar_Get ("net_ip", "localhost", 0); + + port = Cvar_Get("net_port", va("%i", PORT_SERVER), 0)->value; + + for ( i = 0 ; i < 10 ; i++ ) { + ip_socket = NET_IPSocket (ip->string, port + i); + if ( ip_socket ) { + Cvar_SetValue( "net_port", port + i ); + NET_GetLocalAddress(); + return; + } + } + Com_Error (ERR_FATAL, "Couldn't allocate IP port"); +} + + +/* +==================== +NET_Init +==================== +*/ +void NET_Init (void) +{ + noudp = Cvar_Get ("net_noudp", "0", 0); + // open sockets + if (! noudp->value) { + NET_OpenIP (); + } +} + + +/* +==================== +NET_IPSocket +==================== +*/ +int NET_IPSocket (char *net_interface, int port) +{ + int newsocket; + struct sockaddr_in address; + qboolean _qtrue = qtrue; + int i = 1; + + if ( net_interface ) { + Com_Printf("Opening IP socket: %s:%i\n", net_interface, port ); + } else { + Com_Printf("Opening IP socket: localhost:%i\n", port ); + } + + if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + { + Com_Printf ("ERROR: UDP_OpenSocket: socket: %s", NET_ErrorString()); + return 0; + } + + // make it non-blocking + if (ioctl (newsocket, FIONBIO, &_qtrue) == -1) + { + Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString()); + return 0; + } + + // make it broadcast capable + if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1) + { + Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString()); + return 0; + } + + if (!net_interface || !net_interface[0] || !Q_stricmp(net_interface, "localhost")) + address.sin_addr.s_addr = INADDR_ANY; + else + Sys_StringToSockaddr (net_interface, (struct sockaddr *)&address); + + if (port == PORT_ANY) + address.sin_port = 0; + else + address.sin_port = htons((short)port); + + address.sin_family = AF_INET; + + if( bind (newsocket, (sockaddr *)&address, sizeof(address)) == -1) + { + Com_Printf ("ERROR: UDP_OpenSocket: bind: %s\n", NET_ErrorString()); + close (newsocket); + return 0; + } + + return newsocket; +} + +/* +==================== +NET_Shutdown +==================== +*/ +void NET_Shutdown (void) +{ + if (ip_socket) { + close(ip_socket); + ip_socket = 0; + } +} + + +/* +==================== +NET_ErrorString +==================== +*/ +char *NET_ErrorString (void) +{ + int code; + + code = errno; + return strerror (code); +} + +// sleeps msec or until net socket is ready +void NET_Sleep(int msec) +{ + struct timeval timeout; + fd_set fdset; + extern qboolean stdin_active; + + if (!ip_socket || !com_dedicated->integer) + return; // we're not a server, just run full speed + + FD_ZERO(&fdset); + if (stdin_active) + FD_SET(0, &fdset); // stdin is processed too + FD_SET(ip_socket, &fdset); // network socket + timeout.tv_sec = msec/1000; + timeout.tv_usec = (msec%1000)*1000; + select(ip_socket+1, &fdset, NULL, NULL, &timeout); +} + diff --git a/CODE-mp/unix/unix_shared.c b/CODE-mp/unix/unix_shared.c new file mode 100644 index 0000000..7886ceb --- /dev/null +++ b/CODE-mp/unix/unix_shared.c @@ -0,0 +1,336 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../game/q_shared.h" +#include "../qcommon/qcommon.h" + +//============================================================================= + +// Used to determine CD Path +static char cdPath[MAX_OSPATH]; + +// Used to determine local installation path +static char installPath[MAX_OSPATH]; + +// Used to determine where to store user-specific files +static char homePath[MAX_OSPATH]; + +/* +================ +Sys_Milliseconds +================ +*/ +int curtime; +int sys_timeBase; +int Sys_Milliseconds (void) +{ + struct timeval tp; + struct timezone tzp; + + gettimeofday(&tp, &tzp); + + if (!sys_timeBase) + { + sys_timeBase = tp.tv_sec; + return tp.tv_usec/1000; + } + + curtime = (tp.tv_sec - sys_timeBase)*1000 + tp.tv_usec/1000; + + return curtime; +} + + +//#if 0 // bk001215 - see snapvector.nasm for replacement +#if (defined __APPLE__) // rcg010206 - using this for PPC builds... +long fastftol( float f ) { // bk001213 - from win32/win_shared.c + //static int tmp; + // __asm fld f + //__asm fistp tmp + //__asm mov eax, tmp + return (long)f; +} + +void Sys_SnapVector3( float *v ) { // bk001213 - see win32/win_shared.c + // bk001213 - old linux + v[0] = rint(v[0]); + v[1] = rint(v[1]); + v[2] = rint(v[2]); +} +#endif + + +void Sys_Mkdir( const char *path ) +{ + mkdir (path, 0777); +} + +char *strlwr (char *s) { + if ( s==NULL ) { // bk001204 - paranoia + assert(0); + return s; + } + while (*s) { + *s = tolower(*s); + s++; + } + return s; // bk001204 - duh +} + +//============================================ + +#define MAX_FOUND_FILES 0x1000 + +// bk001129 - new in 1.26 +void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles ) { + char search[MAX_OSPATH], newsubdirs[MAX_OSPATH]; + char filename[MAX_OSPATH]; + DIR *fdir; + struct dirent *d; + struct stat st; + + if ( *numfiles >= MAX_FOUND_FILES - 1 ) { + return; + } + + if (strlen(subdirs)) { + Com_sprintf( search, sizeof(search), "%s/%s", basedir, subdirs ); + } + else { + Com_sprintf( search, sizeof(search), "%s", basedir ); + } + + if ((fdir = opendir(search)) == NULL) { + return; + } + + while ((d = readdir(fdir)) != NULL) { + Com_sprintf(filename, sizeof(filename), "%s/%s", search, d->d_name); + if (stat(filename, &st) == -1) + continue; + + if (st.st_mode & S_IFDIR) { + if (Q_stricmp(d->d_name, ".") && Q_stricmp(d->d_name, "..")) { + if (strlen(subdirs)) { + Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s/%s", subdirs, d->d_name); + } + else { + Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", d->d_name); + } + Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles ); + } + } + if ( *numfiles >= MAX_FOUND_FILES - 1 ) { + break; + } + Com_sprintf( filename, sizeof(filename), "%s/%s", subdirs, d->d_name ); + if (!Com_FilterPath( filter, filename, qfalse )) + continue; + list[ *numfiles ] = CopyString( filename ); + (*numfiles)++; + } + + closedir(fdir); +} + +// bk001129 - in 1.17 this used to be +// char **Sys_ListFiles( const char *directory, const char *extension, int *numfiles, qboolean wantsubs ) +char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) +{ + struct dirent *d; + // char *p; // bk001204 - unused + DIR *fdir; + qboolean dironly = wantsubs; + char search[MAX_OSPATH]; + int nfiles; + char **listCopy; + char *list[MAX_FOUND_FILES]; + //int flag; // bk001204 - unused + int i; + struct stat st; + + int extLen; + + if (filter) { + + nfiles = 0; + Sys_ListFilteredFiles( directory, "", filter, list, &nfiles ); + + list[ nfiles ] = 0; + *numfiles = nfiles; + + if (!nfiles) + return NULL; + + listCopy = (char **)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ),TAG_FILESYS,qfalse ); + for ( i = 0 ; i < nfiles ; i++ ) { + listCopy[i] = list[i]; + } + listCopy[i] = NULL; + + return listCopy; + } + + if ( !extension) + extension = ""; + + if ( extension[0] == '/' && extension[1] == 0 ) { + extension = ""; + dironly = qtrue; + } + + extLen = strlen( extension ); + + // search + nfiles = 0; + + if ((fdir = opendir(directory)) == NULL) { + *numfiles = 0; + return NULL; + } + + while ((d = readdir(fdir)) != NULL) { + Com_sprintf(search, sizeof(search), "%s/%s", directory, d->d_name); + if (stat(search, &st) == -1) + continue; + if ((dironly && !(st.st_mode & S_IFDIR)) || + (!dironly && (st.st_mode & S_IFDIR))) + continue; + + if (*extension) { + if ( strlen( d->d_name ) < strlen( extension ) || + Q_stricmp( + d->d_name + strlen( d->d_name ) - strlen( extension ), + extension ) ) { + continue; // didn't match + } + } + + if ( nfiles == MAX_FOUND_FILES - 1 ) + break; + list[ nfiles ] = CopyString( d->d_name ); + nfiles++; + } + + list[ nfiles ] = 0; + + closedir(fdir); + + // return a copy of the list + *numfiles = nfiles; + + if ( !nfiles ) { + return NULL; + } + + listCopy = (char **)Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ),TAG_FILESYS,qfalse ); + for ( i = 0 ; i < nfiles ; i++ ) { + listCopy[i] = list[i]; + } + listCopy[i] = NULL; + + return listCopy; +} + +void Sys_FreeFileList( char **list ) { + int i; + + if ( !list ) { + return; + } + + for ( i = 0 ; list[i] ; i++ ) { + Z_Free( list[i] ); + } + + Z_Free( list ); +} + +char *Sys_Cwd( void ) +{ + static char cwd[MAX_OSPATH]; + + getcwd( cwd, sizeof( cwd ) - 1 ); + cwd[MAX_OSPATH-1] = 0; + + return cwd; +} + +void Sys_SetDefaultCDPath(const char *path) +{ + Q_strncpyz(cdPath, path, sizeof(cdPath)); +} + +char *Sys_DefaultCDPath(void) +{ + return cdPath; +} + +void Sys_SetDefaultInstallPath(const char *path) +{ + Q_strncpyz(installPath, path, sizeof(installPath)); +} + +char *Sys_DefaultInstallPath(void) +{ + if (*installPath) + return installPath; + else + return Sys_Cwd(); +} + +void Sys_SetDefaultHomePath(const char *path) +{ + Q_strncpyz(homePath, path, sizeof(homePath)); +} + +char *Sys_DefaultHomePath(void) +{ + char *p; + + if (*homePath) + return homePath; + + if ((p = getenv("HOME")) != NULL) { + Q_strncpyz(homePath, p, sizeof(homePath)); +#ifdef MACOS_X + Q_strcat(homePath, sizeof(homePath), "/Library/Application Support/Quake3"); +#else + Q_strcat(homePath, sizeof(homePath), "/.jkii"); +#endif + if (mkdir(homePath, 0777)) { + if (errno != EEXIST) + Sys_Error("Unable to create directory \"%s\", error is %s(%d)\n", homePath, strerror(errno), errno); + } + return homePath; + } + return ""; // assume current dir +} + +//============================================ + +int Sys_GetProcessorId( void ) +{ + return CPUID_GENERIC; +} + +void Sys_ShowConsole( int visLevel, qboolean quitOnClose ) +{ +} + +char *Sys_GetCurrentUser( void ) +{ + struct passwd *p; + + if ( (p = getpwuid( getuid() )) == NULL ) { + return "player"; + } + return p->pw_name; +} diff --git a/CODE-mp/unix/vm_x86.c b/CODE-mp/unix/vm_x86.c new file mode 100644 index 0000000..7881443 --- /dev/null +++ b/CODE-mp/unix/vm_x86.c @@ -0,0 +1,8 @@ + +#include "../qcommon/vm_local.h" + +void VM_Compile( vm_t *vm, vmHeader_t *header ) {} +int VM_CallCompiled( vm_t *vm, int *args ) {} + + + diff --git a/CODE-mp/unix/vssver.scc b/CODE-mp/unix/vssver.scc new file mode 100644 index 0000000..c48f019 Binary files /dev/null and b/CODE-mp/unix/vssver.scc differ diff --git a/CODE-mp/vssver.scc b/CODE-mp/vssver.scc new file mode 100644 index 0000000..711fd2d Binary files /dev/null and b/CODE-mp/vssver.scc differ diff --git a/CODE-mp/win32/qe3.ico b/CODE-mp/win32/qe3.ico index d6df0e7..dfa7bfc 100644 Binary files a/CODE-mp/win32/qe3.ico and b/CODE-mp/win32/qe3.ico differ diff --git a/CODE-mp/win32/vssver.scc b/CODE-mp/win32/vssver.scc new file mode 100644 index 0000000..89a3780 Binary files /dev/null and b/CODE-mp/win32/vssver.scc differ diff --git a/CODE-mp/win32/win_glimp.cpp b/CODE-mp/win32/win_glimp.cpp index d498f1e..646e2e7 100644 --- a/CODE-mp/win32/win_glimp.cpp +++ b/CODE-mp/win32/win_glimp.cpp @@ -69,7 +69,7 @@ static qboolean GLW_StartDriverAndSetMode( int mode, { rserr_t err; - err = GLW_SetMode( r_mode->integer, colorbits, cdsFullscreen ); + err = GLW_SetMode( mode, colorbits, cdsFullscreen ); switch ( err ) { @@ -890,12 +890,14 @@ static rserr_t GLW_SetMode( int mode, ri.Printf( PRINT_ALL, "...restoring display settings\n" ); ChangeDisplaySettings( 0, 0 ); +/* jfm: i took out the following code to allow fallback to mode 3, with this code it goes half windowed and just doesn't work. glw_state.cdsFullscreen = qfalse; glConfig.isFullscreen = qfalse; if ( !GLW_CreateWindow( glConfig.vidWidth, glConfig.vidHeight, colorbits, qfalse) ) { return RSERR_INVALID_MODE; } +*/ return RSERR_INVALID_FULLSCREEN; } } @@ -956,6 +958,115 @@ bool GL_CheckForExtension(const char *ext) return(false); } +//-------------------------------------------- +static void GLW_InitTextureCompression( void ) +{ + qboolean newer_tc, old_tc; + + // Check for available tc methods. + newer_tc = ( strstr( glConfig.extensions_string, "ARB_texture_compression" ) + && strstr( glConfig.extensions_string, "EXT_texture_compression_s3tc" )) ? qtrue : qfalse; + old_tc = ( strstr( glConfig.extensions_string, "GL_S3_s3tc" )) ? qtrue : qfalse; + + if ( old_tc ) + { + ri.Printf( PRINT_ALL, "...GL_S3_s3tc available\n" ); + } + + if ( newer_tc ) + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_compression_s3tc available\n" ); + } + + if ( !r_ext_compressed_textures->value ) + { + // Compressed textures are off + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...ignoring texture compression\n" ); + } + else if ( !old_tc && !newer_tc ) + { + // Requesting texture compression, but no method found + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...no supported texture compression method found\n" ); + ri.Printf( PRINT_ALL, ".....ignoring texture compression\n" ); + } + else + { + // some form of supported texture compression is avaiable, so see if the user has a preference + if ( r_ext_preferred_tc_method->integer == TC_NONE ) + { + // No preference, so pick the best + if ( newer_tc ) + { + ri.Printf( PRINT_ALL, "...no tc preference specified\n" ); + ri.Printf( PRINT_ALL, ".....using GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + else + { + ri.Printf( PRINT_ALL, "...no tc preference specified\n" ); + ri.Printf( PRINT_ALL, ".....using GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + } + else + { + // User has specified a preference, now see if this request can be honored + if ( old_tc && newer_tc ) + { + // both are avaiable, so we can use the desired tc method + if ( r_ext_preferred_tc_method->integer == TC_S3TC ) + { + ri.Printf( PRINT_ALL, "...using preferred tc method, GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + else + { + ri.Printf( PRINT_ALL, "...using preferred tc method, GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + } + else + { + // Both methods are not available, so this gets trickier + if ( r_ext_preferred_tc_method->integer == TC_S3TC ) + { + // Preferring to user older compression + if ( old_tc ) + { + ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + else + { + // Drat, preference can't be honored + ri.Printf( PRINT_ALL, "...preferred tc method, GL_S3_s3tc not available\n" ); + ri.Printf( PRINT_ALL, ".....falling back to GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + } + else + { + // Preferring to user newer compression + if ( newer_tc ) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_compression_s3tc\n" ); + glConfig.textureCompression = TC_S3TC_DXT; + } + else + { + // Drat, preference can't be honored + ri.Printf( PRINT_ALL, "...preferred tc method, GL_EXT_texture_compression_s3tc not available\n" ); + ri.Printf( PRINT_ALL, ".....falling back to GL_S3_s3tc\n" ); + glConfig.textureCompression = TC_S3TC; + } + } + } + } + } +} + /* ** GLW_InitExtensions */ @@ -969,6 +1080,9 @@ static void GLW_InitExtensions( void ) ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" ); + // Select our tc scheme + GLW_InitTextureCompression(); + // GL_EXT_texture_env_add glConfig.textureEnvAddAvailable = qfalse; if ( strstr( glConfig.extensions_string, "EXT_texture_env_add" ) ) @@ -1287,56 +1401,83 @@ void GLimp_Init( void ) GLW_StartOpenGL(); // get our config strings - Q_strncpyz( glConfig.vendor_string, (const char *)qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) ); - Q_strncpyz( glConfig.renderer_string, (const char *)qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) ); - Q_strncpyz( glConfig.version_string, (const char *)qglGetString (GL_VERSION), sizeof( glConfig.version_string ) ); - Q_strncpyz( glConfig.extensions_string, (const char *)qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) ); + const char* glstring; + glstring = (const char *)qglGetString (GL_VENDOR); + if (!glstring) { + glstring = "invalid driver"; + } + Q_strncpyz( glConfig.vendor_string, glstring, sizeof( glConfig.vendor_string ) ); + glstring = (const char *)qglGetString (GL_RENDERER); + if (!glstring) { + glstring = "invalid driver"; + } + Q_strncpyz( glConfig.renderer_string, glstring, sizeof( glConfig.renderer_string ) ); + glstring = (const char *)qglGetString (GL_VERSION); + if (!glstring) { + glstring = "invalid driver"; + } + Q_strncpyz( glConfig.version_string, glstring, sizeof( glConfig.version_string ) ); + glstring = (const char *)qglGetString (GL_EXTENSIONS); + if (!glstring) { + glstring = "invalid driver"; + } + Q_strncpyz( glConfig.extensions_string, glstring, sizeof( glConfig.extensions_string ) ); + + // OpenGL driver constants + qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &glConfig.maxTextureSize ); + // stubbed or broken drivers may have reported 0... + if ( glConfig.maxTextureSize <= 0 ) + { + glConfig.maxTextureSize = 0; + } + GLW_InitExtensions(); // // chipset specific configuration // Q_strncpyz( buf, glConfig.renderer_string, sizeof(buf) ); strlwr( buf ); - + // // NOTE: if changing cvars, do it within this block. This allows them // to be overridden when testing driver fixes, etc. but only sets // them to their default state when the hardware is first installed/run. // +extern qboolean Sys_LowPhysicalMemory(); if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) ) { - ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); - - // VOODOO GRAPHICS w/ 2MB -/* if ( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) ) + if (Sys_LowPhysicalMemory()) { - ri.Cvar_Set( "r_picmip", "2" ); + ri.Cvar_Set("s_khz", "11");// this will get called before S_Init + } + //reset to defaults + ri.Cvar_Set( "r_picmip", "1" ); + + // Savage3D and Savage4 should always have trilinear enabled + if ( strstr( buf, "savage3d" ) || strstr( buf, "s3 savage4" ) || strstr( buf, "geforce" )) + { + ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); } else -*/ { - ri.Cvar_Set( "r_picmip", "1" ); - -/* if ( strstr( buf, "rage 128" ) || strstr( buf, "rage128" ) ) - { - ri.Cvar_Set( "r_finish", "0" ); - } - // Savage3D and Savage4 should always have trilinear enabled - else -*/ if ( strstr( buf, "savage3d" ) || strstr( buf, "s3 savage4" ) ) - { - ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); - } - else if ( strstr( buf, "geforce" ) || strstr( buf, "quadro" ) ) - { - ri.Cvar_Set( "r_picmip", "0" ); - ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); - } + { + ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); + } + + //this must be a really sucky card! + if ( (glConfig.textureCompression == TC_NONE) || (glConfig.maxActiveTextures < 2) || (glConfig.maxTextureSize <= 512) ) + { + ri.Cvar_Set( "r_picmip", "2"); + ri.Cvar_Set( "r_lodbias", "2"); + ri.Cvar_Set( "r_detailtextures", "0"); + ri.Cvar_Set( "r_colorbits", "16"); + ri.Cvar_Set( "r_texturebits", "16"); + ri.Cvar_Set( "cg_shadows", "0"); + ri.Cvar_Set( "r_mode", "3"); //force 640 } } ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string ); - GLW_InitExtensions(); WG_CheckHardwareGamma(); } diff --git a/CODE-mp/win32/win_input.cpp b/CODE-mp/win32/win_input.cpp index f66bfe5..1c35a00 100644 --- a/CODE-mp/win32/win_input.cpp +++ b/CODE-mp/win32/win_input.cpp @@ -557,7 +557,7 @@ void IN_MouseEvent (int mstate) return; // perform button actions - for (i = 0 ; i < 3 ; i++ ) + for (i = 0 ; i < 5 ; i++ ) { if ( (mstate & (1<integer) + { + return qfalse; + } + if( adr.type == NA_LOOPBACK ) { return qtrue; } @@ -845,7 +857,13 @@ static qboolean NET_GetCvars( void ) { if( net_noipx && net_noipx->modified ) { modified = qtrue; } - net_noipx = Cvar_Get( "net_noipx", "0", CVAR_LATCH | CVAR_ARCHIVE ); + net_noipx = Cvar_Get( "net_noipx", "1", CVAR_LATCH | CVAR_ARCHIVE ); + + + if( net_forcenonlocal && net_forcenonlocal->modified ) { + modified = qtrue; + } + net_forcenonlocal = Cvar_Get( "net_forcenonlocal", "0", CVAR_LATCH | CVAR_ARCHIVE ); if( net_socksEnabled && net_socksEnabled->modified ) { diff --git a/CODE-mp/win32/win_shared.cpp b/CODE-mp/win32/win_shared.cpp index a04d1af..c53344f 100644 --- a/CODE-mp/win32/win_shared.cpp +++ b/CODE-mp/win32/win_shared.cpp @@ -315,3 +315,222 @@ char *Sys_DefaultInstallPath(void) return Sys_Cwd(); } +int Sys_GetPhysicalMemory( void ) +{ + MEMORYSTATUS MemoryStatus; + + memset( &MemoryStatus, sizeof(MEMORYSTATUS), 0 ); + MemoryStatus.dwLength = sizeof(MEMORYSTATUS); + + GlobalMemoryStatus( &MemoryStatus ); + + return( (int)(MemoryStatus.dwTotalPhys / (1024 * 1024)) + 1 ); + +} + +int Sys_GetCPUSpeedOld() +{ + timeBeginPeriod(1); + + DWORD clockStart = timeGetTime(); + DWORD clockEnd = clockStart + 100; + + while(clockEnd < clockStart) + { + clockStart = timeGetTime(); + clockEnd = clockStart + 100; + } + +#ifdef WIN32 + int iPriority; + HANDLE hThread = GetCurrentThread(); + + iPriority = GetThreadPriority(hThread); + if ( iPriority != THREAD_PRIORITY_ERROR_RETURN ) + { + SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); + } +#endif // WIN32 + + unsigned long start; + unsigned long end; + + __asm + { + rdtsc + mov start, eax + } + + while(timeGetTime() < clockEnd) + { // loop for 1 tenth of a second + } + __asm + { + rdtsc + mov end, eax + } + + +#ifdef WIN32 + // Reset priority + if ( iPriority != THREAD_PRIORITY_ERROR_RETURN ) + { + SetThreadPriority(hThread, iPriority); + } +#endif // WIN32 + + timeEndPeriod(1); + + unsigned long time; + time = end - start; + int coarse = time / 100000; + int firsttry = floor((coarse + 25) / 50) * 50; + if (abs(firsttry - coarse) < 10) + { + return firsttry; + } + else + { + return floor(floor((coarse + 17) / 33.3) * 33.3); + } +} + +int Sys_GetCPUSpeed() +{ + unsigned long raw_freq; // Raw frequency of CPU in MHz + unsigned long norm_freq; // Normalized frequency of CPU in MHz. + LARGE_INTEGER t0,t1; // Variables for High-Resolution Performance Counter reads + + unsigned long freq =0; // Most current frequ. calculation + unsigned long freq2 =0; // 2nd most current frequ. calc. + unsigned long freq3 =0; // 3rd most current frequ. calc. + + unsigned long total; // Sum of previous three frequency calculations + int tries=0; // Number of times a calculation has been made on this call to cpuspeed + unsigned long total_cycles=0, cycles; // Clock cycles elapsed during test + unsigned long stamp0=0, stamp1=0; // Time Stamp Variable for beginning and end of test + unsigned long total_ticks=0, ticks; // Microseconds elapsed during test + LARGE_INTEGER count_freq; // High Resolution Performance Counter frequency + +#define TOLERANCE 1 // Number of MHz to allow samplings to deviate from average of samplings. +#define ROUND_THRESHOLD 6 + +#ifdef WIN32 + int iPriority; + HANDLE hThread = GetCurrentThread(); +#endif // WIN32; + + if ( !QueryPerformanceFrequency ( &count_freq ) ) + return Sys_GetCPUSpeedOld(); //should never happen + + // On processors supporting the Read + // Time Stamp opcode, compare elapsed + // time on the High-Resolution Counter + // with elapsed cycles on the Time + // Stamp Register. + + do { // This do loop runs up to 20 times or until the average of the previous + // three calculated frequencies is within 1 MHz of each of the + // individual calculated frequencies. This resampling increases the + // accuracy of the results since outside factors could affect this calculation + + tries++; // Increment number of times sampled on this call to cpuspeed + + freq3 = freq2; // Shift frequencies back to make + freq2 = freq; // room for new frequency measurement + + QueryPerformanceCounter(&t0);// Get high-resolution performance counter time + + t1 = t0; // Set Initial time + +#ifdef WIN32 + iPriority = GetThreadPriority(hThread); + if ( iPriority != THREAD_PRIORITY_ERROR_RETURN ) + { + SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); + } +#endif // WIN32 + + while ( (unsigned long)t1.LowPart - (unsigned long)t0.LowPart<50) { + // Loop until 50 ticks have passed since last read of hi-res counter. This accounts for overhead later. + QueryPerformanceCounter(&t1); + _asm { + rdtsc; // Read Time Stamp + MOV stamp0, EAX + } + } + + t0 = t1; // Reset Initial Time + + while ((unsigned long)t1.LowPart-(unsigned long)t0.LowPart<1000 ) { + // Loop until 1000 ticks have passed since last read of hi-res counter. This allows for elapsed time for sampling. + QueryPerformanceCounter(&t1); + __asm { + rdtsc; // Read Time Stamp + MOV stamp1, EAX + } + } + +#ifdef WIN32 + if ( iPriority != THREAD_PRIORITY_ERROR_RETURN ) + { // Reset priority + SetThreadPriority(hThread, iPriority); + } +#endif // WIN32 + + cycles = stamp1 - stamp0; // Number of internal clock cycles is difference between two time stamp readings. + + ticks = (unsigned long) t1.LowPart - (unsigned long) t0.LowPart; + // Number of external ticks is difference between two hi-res counter reads. + + + // Note that some seemingly arbitrary mulitplies and + // divides are done below. This is to maintain a + // high level of precision without truncating the + // most significant data. According to what value + // ITERATIIONS is set to, these multiplies and + // divides might need to be shifted for optimal + // precision. + + ticks = ticks * 100000; // Convert ticks to hundred thousandths of a tick + + ticks = ticks / ( count_freq.LowPart/10 ); + // Hundred Thousandths of a Ticks / ( 10 ticks/second ) = microseconds (us) + + total_ticks += ticks; + total_cycles += cycles; + + if ( ticks%count_freq.LowPart > count_freq.LowPart/2 ) + ticks++; // Round up if necessary + + freq = cycles/ticks; // Cycles / us = MHz + + if ( cycles%ticks > ticks/2 ) + freq++; // Round up if necessary + + total = ( freq + freq2 + freq3 ); // Total last three frequency calculations + + } while ( (tries < 3 ) || + (tries < 20)&& + ((abs(3 * freq -total) > 3*TOLERANCE )|| + (abs(3 * freq2-total) > 3*TOLERANCE )|| + (abs(3 * freq3-total) > 3*TOLERANCE ))); + // Compare last three calculations to average of last three calculations. + + // Try one more significant digit. + freq3 = ( total_cycles * 10 ) / total_ticks; + freq2 = ( total_cycles * 100 ) / total_ticks; + + + if ( freq2 - (freq3 * 10) >= ROUND_THRESHOLD ) + freq3++; + + raw_freq = total_cycles / total_ticks; + norm_freq = raw_freq; + + freq = raw_freq * 10; + if( (freq3 - freq) >= ROUND_THRESHOLD ) + norm_freq++; + + return norm_freq; +} diff --git a/CODE-mp/win32/win_syscon.cpp b/CODE-mp/win32/win_syscon.cpp index e5d0360..859fc37 100644 --- a/CODE-mp/win32/win_syscon.cpp +++ b/CODE-mp/win32/win_syscon.cpp @@ -113,24 +113,25 @@ static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara case WM_CTLCOLORSTATIC: if ( ( HWND ) lParam == s_wcd.hwndBuffer ) { - SetBkColor( ( HDC ) wParam, RGB( 0x00, 0x00, 0xB0 ) ); - SetTextColor( ( HDC ) wParam, RGB( 0xff, 0xff, 0x00 ) ); + SetBkColor( ( HDC ) wParam, RGB( 0, 0, 0 ) ); + SetTextColor( ( HDC ) wParam, RGB( 249, 249, 000 ) ); return ( long ) s_wcd.hbrEditBackground; } else if ( ( HWND ) lParam == s_wcd.hwndErrorBox ) { if ( s_timePolarity & 1 ) { - SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) ); - SetTextColor( ( HDC ) wParam, RGB( 0xff, 0x0, 0x00 ) ); + SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) ); + SetTextColor( ( HDC ) wParam, RGB( 0xff, 0x00, 0x00 ) ); } else { - SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) ); - SetTextColor( ( HDC ) wParam, RGB( 0x00, 0x0, 0x00 ) ); + SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) ); + SetTextColor( ( HDC ) wParam, RGB( 0x00, 0x00, 0x00 ) ); } return ( long ) s_wcd.hbrErrorBackground; } + return FALSE; break; case WM_COMMAND: @@ -159,7 +160,7 @@ static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara } break; case WM_CREATE: - s_wcd.hbrEditBackground = CreateSolidBrush( RGB( 0x00, 0x00, 0xB0 ) ); + s_wcd.hbrEditBackground = CreateSolidBrush( RGB( 0x00, 0x00, 0x00 ) ); s_wcd.hbrErrorBackground = CreateSolidBrush( RGB( 0x80, 0x80, 0x80 ) ); SetTimer( hWnd, 1, 1000, NULL ); break; @@ -277,17 +278,16 @@ void Sys_CreateConsole( void ) wc.hInstance = g_wv.hInstance; wc.hIcon = LoadIcon( g_wv.hInstance, MAKEINTRESOURCE(IDI_ICON1)); wc.hCursor = LoadCursor (NULL,IDC_ARROW); - wc.hbrBackground = (struct HBRUSH__ *)COLOR_WINDOW; + wc.hbrBackground = (HBRUSH__ *)COLOR_INACTIVEBORDER; wc.lpszMenuName = 0; wc.lpszClassName = DEDCLASS; - if ( !RegisterClass (&wc) ) - { + if ( !RegisterClass (&wc) ) { return; } rect.left = 0; - rect.right = 538; + rect.right = 600; rect.top = 0; rect.bottom = 450; AdjustWindowRect( &rect, DEDSTYLE, FALSE ); @@ -343,7 +343,7 @@ void Sys_CreateConsole( void ) // s_wcd.hwndInputLine = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP, - 6, 400, 528, 20, + 6, 400, s_wcd.windowWidth-20, 20, s_wcd.hWnd, ( HMENU ) INPUT_ID, // child window ID g_wv.hInstance, NULL ); @@ -366,7 +366,7 @@ void Sys_CreateConsole( void ) SendMessage( s_wcd.hwndButtonClear, WM_SETTEXT, 0, ( LPARAM ) "Clear" ); s_wcd.hwndButtonQuit = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON | WS_TABSTOP, - 462, 425, 72, 24, + s_wcd.windowWidth-92, 425, 72, 24, s_wcd.hWnd, ( HMENU ) QUIT_ID, // child window ID g_wv.hInstance, NULL ); @@ -378,7 +378,7 @@ void Sys_CreateConsole( void ) // s_wcd.hwndBuffer = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_TABSTOP, - 6, 40, 526, 354, + 6, 40, s_wcd.windowWidth-20, 354, s_wcd.hWnd, ( HMENU ) EDIT_ID, // child window ID g_wv.hInstance, NULL ); @@ -562,7 +562,7 @@ void Sys_SetErrorText( const char *buf ) if ( !s_wcd.hwndErrorBox ) { s_wcd.hwndErrorBox = CreateWindow( "static", NULL, WS_CHILD | WS_VISIBLE | SS_SUNKEN, - 6, 5, 526, 30, + 6, 5, s_wcd.windowWidth-20, 30, s_wcd.hWnd, ( HMENU ) ERRORBOX_ID, // child window ID g_wv.hInstance, NULL ); diff --git a/CODE-mp/win32/win_wndproc.cpp b/CODE-mp/win32/win_wndproc.cpp index 8ad1f42..7a67d02 100644 --- a/CODE-mp/win32/win_wndproc.cpp +++ b/CODE-mp/win32/win_wndproc.cpp @@ -145,7 +145,7 @@ static byte s_scantokey_french[128] = 0 , 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', ')', '=', K_BACKSPACE, 9, // 0 'a', 'z', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '^', '$', 13 , K_CTRL, 'q', 's', // 1 + 'o', 'p', '^', '$', 13 , K_CTRL, 'q', 's', // 1 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', '%' , '`', K_SHIFT,'*', 'w', 'x', 'c', 'v', // 2 'b', 'n', ',', ';', ':', '!', K_SHIFT,'*', @@ -300,6 +300,12 @@ MainWndProc main window procedure ==================== */ + +#define WM_BUTTON4DOWN (WM_MOUSELAST+2) +#define WM_BUTTON4UP (WM_MOUSELAST+3) +#define MK_BUTTON4L 0x0020 +#define MK_BUTTON4R 0x0040 + LONG WINAPI MainWndProc ( HWND hWnd, UINT uMsg, @@ -440,6 +446,8 @@ LONG WINAPI MainWndProc ( case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MOUSEMOVE: + case WM_BUTTON4DOWN: + case WM_BUTTON4UP: { int temp; @@ -454,13 +462,21 @@ LONG WINAPI MainWndProc ( if (wParam & MK_MBUTTON) temp |= 4; + if (wParam & MK_BUTTON4L) + temp |= 8; + + if (wParam & MK_BUTTON4R) + temp |= 16; + IN_MouseEvent (temp); } break; case WM_SYSCOMMAND: - if ( wParam == SC_SCREENSAVE ) + if ( (wParam&0xFFF0) == SC_SCREENSAVE || (wParam&0xFFF0) == SC_MONITORPOWER) + { return 0; + } break; case WM_SYSKEYDOWN: @@ -486,6 +502,13 @@ LONG WINAPI MainWndProc ( case WM_CHAR: Sys_QueEvent( g_wv.sysMsgTime, SE_CHAR, wParam, 0, 0, NULL ); break; + case WM_POWERBROADCAST: + if (wParam == PBT_APMQUERYSUSPEND) + { + Com_Printf("Cannot go into hibernate / standby mode while game is running!\n"); + return BROADCAST_QUERY_DENY; + } + break; } return DefWindowProc( hWnd, uMsg, wParam, lParam ); diff --git a/CODE-mp/win32/winquake.aps b/CODE-mp/win32/winquake.aps new file mode 100644 index 0000000..2218a42 Binary files /dev/null and b/CODE-mp/win32/winquake.aps differ diff --git a/CODE-mp/win32/winquake.res b/CODE-mp/win32/winquake.res index 9bc4bc4..2f0a921 100644 Binary files a/CODE-mp/win32/winquake.res and b/CODE-mp/win32/winquake.res differ diff --git a/CODE-mp/winded/WinDed.dsp b/CODE-mp/winded/WinDed.dsp new file mode 100644 index 0000000..de40a26 --- /dev/null +++ b/CODE-mp/winded/WinDed.dsp @@ -0,0 +1,651 @@ +# Microsoft Developer Studio Project File - Name="WinDed" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=WinDed - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "WinDed.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "WinDed.mak" CFG="WinDed - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "WinDed - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "WinDed - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "WinDed - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEDICATED" /D "BOTLIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib Winmm.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "WinDed - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "DEDICATED" /D "_JK2" /D "BOTLIB" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib Winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "WinDed - Win32 Release" +# Name "WinDed - Win32 Debug" +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\qcommon\chash.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_load.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_local.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_patch.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_patch.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_polylib.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_polylib.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_public.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_shader.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_test.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_trace.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cmd.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\CNetProfile.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\common.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cvar.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\disablewarnings.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\files.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\game_version.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\GenericParser2.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\GenericParser2.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\hstring.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\hstring.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\huffman.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\INetProfile.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\md4.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\MiniHeap.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\msg.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\net_chan.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\q_math.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\q_shared.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\qcommon.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\qfiles.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\RoffSystem.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\RoffSystem.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\sstring.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\strip.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\strip.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\tags.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\unzip.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\unzip.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\vm.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\vm_interpreted.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\vm_local.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\vm_x86.cpp +# End Source File +# End Group +# Begin Group "Ghoul2" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\ghoul2\G2.h +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_API.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_bolts.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_bones.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_gore.h +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_local.h +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_misc.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_surfaces.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\ghoul2_shared.h +# End Source File +# End Group +# Begin Group "Server" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\server\server.h +# End Source File +# Begin Source File + +SOURCE=.\server\sv_bot.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_ccmds.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_client.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_game.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_init.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_net_chan.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_snapshot.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_world.cpp +# End Source File +# End Group +# Begin Group "Null" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\null\null_client.cpp +# End Source File +# Begin Source File + +SOURCE=.\null\null_glimp.cpp +# End Source File +# Begin Source File + +SOURCE=.\null\null_input.cpp +# End Source File +# Begin Source File + +SOURCE=.\null\null_renderer.cpp +# End Source File +# Begin Source File + +SOURCE=.\null\null_snddma.cpp +# End Source File +# Begin Source File + +SOURCE=.\null\win_main.cpp +# End Source File +# End Group +# Begin Group "Renderer" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\renderer\matcomp.c +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_backend.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_ghoul2.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_image.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_init.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_mesh.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_model.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_shader.cpp +# End Source File +# End Group +# Begin Group "Win32" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\win32\win_net.cpp +# End Source File +# Begin Source File + +SOURCE=.\win32\win_shared.cpp +# End Source File +# End Group +# Begin Group "botlib" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\botlib\aasfile.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_bsp.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_bspq3.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_cluster.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_cluster.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_debug.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_debug.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_def.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_entity.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_entity.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_file.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_file.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_funcs.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_main.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_move.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_move.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_optimize.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_optimize.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_reach.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_reach.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_route.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_route.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_routealt.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_routealt.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_sample.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_aas_sample.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_char.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_chat.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_gen.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_goal.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_move.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_weap.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_weight.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ai_weight.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_ea.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_interface.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\be_interface.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_crc.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_crc.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_libvar.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_libvar.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_log.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_log.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_memory.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_memory.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_precomp.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_precomp.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_script.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_script.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_struct.cpp +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_struct.h +# End Source File +# Begin Source File + +SOURCE=.\botlib\l_utils.h +# End Source File +# End Group +# End Target +# End Project diff --git a/CODE-mp/winded/WinDed.plg b/CODE-mp/winded/WinDed.plg new file mode 100644 index 0000000..e47f04c --- /dev/null +++ b/CODE-mp/winded/WinDed.plg @@ -0,0 +1,107 @@ + + +
+

Build Log

+

+--------------------Configuration: WinDed - Win32 Release-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\drews\LOCALS~1\Temp\RSP54.tmp" with contents +[ +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib Winmm.lib /nologo /subsystem:console /incremental:no /pdb:"Release/WinDed.pdb" /machine:I386 /out:"Release/WinDed.exe" +.\Release\cm_load.obj +.\Release\cm_patch.obj +.\Release\cm_polylib.obj +.\Release\cm_shader.obj +.\Release\cm_test.obj +.\Release\cm_trace.obj +.\Release\cmd.obj +.\Release\CNetProfile.obj +.\Release\common.obj +.\Release\cvar.obj +.\Release\files.obj +.\Release\GenericParser2.obj +.\Release\hstring.obj +.\Release\huffman.obj +.\Release\md4.obj +.\Release\msg.obj +.\Release\net_chan.obj +.\Release\q_math.obj +.\Release\q_shared.obj +.\Release\RoffSystem.obj +.\Release\strip.obj +.\Release\unzip.obj +.\Release\vm.obj +.\Release\vm_interpreted.obj +.\Release\vm_x86.obj +.\Release\G2_API.obj +.\Release\G2_bolts.obj +.\Release\G2_bones.obj +.\Release\G2_misc.obj +.\Release\G2_surfaces.obj +.\Release\sv_bot.obj +.\Release\sv_ccmds.obj +.\Release\sv_client.obj +.\Release\sv_game.obj +.\Release\sv_init.obj +.\Release\sv_main.obj +.\Release\sv_net_chan.obj +.\Release\sv_snapshot.obj +.\Release\sv_world.obj +.\Release\null_client.obj +.\Release\null_glimp.obj +.\Release\null_input.obj +.\Release\null_renderer.obj +.\Release\null_snddma.obj +.\Release\win_main.obj +.\Release\matcomp.obj +.\Release\tr_backend.obj +.\Release\tr_ghoul2.obj +.\Release\tr_image.obj +.\Release\tr_init.obj +.\Release\tr_main.obj +.\Release\tr_mesh.obj +.\Release\tr_model.obj +.\Release\tr_shader.obj +.\Release\win_net.obj +.\Release\win_shared.obj +.\Release\be_aas_bspq3.obj +.\Release\be_aas_cluster.obj +.\Release\be_aas_debug.obj +.\Release\be_aas_entity.obj +.\Release\be_aas_file.obj +.\Release\be_aas_main.obj +.\Release\be_aas_move.obj +.\Release\be_aas_optimize.obj +.\Release\be_aas_reach.obj +.\Release\be_aas_route.obj +.\Release\be_aas_routealt.obj +.\Release\be_aas_sample.obj +.\Release\be_ai_char.obj +.\Release\be_ai_chat.obj +.\Release\be_ai_gen.obj +.\Release\be_ai_goal.obj +.\Release\be_ai_move.obj +.\Release\be_ai_weap.obj +.\Release\be_ai_weight.obj +.\Release\be_ea.obj +.\Release\be_interface.obj +.\Release\l_crc.obj +.\Release\l_libvar.obj +.\Release\l_log.obj +.\Release\l_memory.obj +.\Release\l_precomp.obj +.\Release\l_script.obj +.\Release\l_struct.obj +] +Creating command line "link.exe @C:\DOCUME~1\drews\LOCALS~1\Temp\RSP54.tmp" +

Output Window

+Linking... + + + +

Results

+WinDed.exe - 0 error(s), 0 warning(s) +
+ + diff --git a/CODE-mp/winded/buildvms.bat b/CODE-mp/winded/buildvms.bat new file mode 100644 index 0000000..00d402b --- /dev/null +++ b/CODE-mp/winded/buildvms.bat @@ -0,0 +1,8 @@ +set include= +cd game +call game +cd ..\cgame +call cgame +cd ..\ui +call ui +cd .. diff --git a/CODE-mp/winded/installvms.bat b/CODE-mp/winded/installvms.bat new file mode 100644 index 0000000..43c7700 --- /dev/null +++ b/CODE-mp/winded/installvms.bat @@ -0,0 +1,4 @@ +xcopy/d/y release\jk2mp.exe w:\game +xcopy/d/y base\vm\cgame.* w:\game\base\vm +xcopy/d/y base\vm\jk2mpgame.* w:\game\base\vm +xcopy/d/y base\vm\ui.* w:\game\base\vm diff --git a/CODE-mp/winded/jk2mp.dsp b/CODE-mp/winded/jk2mp.dsp new file mode 100644 index 0000000..8602794 --- /dev/null +++ b/CODE-mp/winded/jk2mp.dsp @@ -0,0 +1,1360 @@ +# Microsoft Developer Studio Project File - Name="jk2mp" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 60000 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=jk2mp - Win32 Debug JK2 +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "jk2mp.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "jk2mp.mak" CFG="jk2mp - Win32 Debug JK2" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "jk2mp - Win32 Release JK2" (based on "Win32 (x86) Application") +!MESSAGE "jk2mp - Win32 Debug JK2" (based on "Win32 (x86) Application") +!MESSAGE "jk2mp - Win32 Final JK2" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 1 +# PROP Scc_ProjName ""$/General/code", EAAAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release\jk2" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\Release" +# PROP Intermediate_Dir ".\Release\jk2" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /W4 /GX /O2 /Ob2 /D "WIN32" /D "NDebug" /D "_WINDOWS" /D "__USEA3D" /D "__A3D_GEOM" /YX /FD /c +# ADD CPP /nologo /G6 /W4 /GX /Zi /O2 /Ob0 /D "_WIN32" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_JK2" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDebug" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDebug" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDebug" +# ADD RSC /l 0x409 /d "NDebug" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map /debug /machine:I386 +# SUBTRACT BASE LINK32 /incremental:yes /nodefaultlib +# ADD LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Release/jk2mp.map" /debug /machine:I386 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug\jk2" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\Debug" +# PROP Intermediate_Dir ".\Debug\jk2" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G5 /MTd /W3 /GX /ZI /Od /D "WIN32" /D "_Debug" /D "_WINDOWS" /D "__USEA3D" /D "__A3D_GEOM" /Fr /YX /FD /c +# ADD CPP /nologo /G6 /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_JK2" /Fr /FD /GZ /c +# ADD BASE MTL /nologo /D "_Debug" /mktyplib203 /win32 +# ADD MTL /nologo /D "_Debug" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /fo"win32\winquake.res" /d "_Debug" +# ADD RSC /l 0x409 /fo"win32\winquake.res" /d "_Debug" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo /o"Debug/jk2mp.bsc" +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /profile /map /debug /machine:I386 +# SUBTRACT BASE LINK32 /nodefaultlib +# ADD LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Debug/jk2mp.map" /debug /machine:I386 +# SUBTRACT LINK32 /profile + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Final" +# PROP BASE Intermediate_Dir ".\Final\jk2" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\Final" +# PROP Intermediate_Dir ".\Final\jk2" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /W4 /GX /Zi /O2 /Ob0 /I "./jk2/game" /I "." /D "_WIN32" /D "NDebug" /D "WIN32" /D "_WINDOWS" /D "_JK2" /YX /FD /c +# SUBTRACT BASE CPP /Fr +# ADD CPP /nologo /G6 /W4 /GX /O2 /Ob0 /D "_WIN32" /D "NDEBUG" /D "_WINDOWS" /D "WIN32" /D "_JK2" /D "FINAL_BUILD" /YX /FD /c +# ADD BASE MTL /nologo /D "NDebug" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDebug" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDebug" +# ADD RSC /l 0x409 /d "NDebug" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Release/jk2mp.map" /debug /machine:I386 /out:".\Release/jk2mp.exe" +# SUBTRACT BASE LINK32 /pdb:none +# ADD LINK32 advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /map:"Final/jk2mp.map" /machine:I386 +# SUBTRACT LINK32 /pdb:none /debug + +!ENDIF + +# Begin Target + +# Name "jk2mp - Win32 Release JK2" +# Name "jk2mp - Win32 Debug JK2" +# Name "jk2mp - Win32 Final JK2" +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\game\anims.h +# End Source File +# Begin Source File + +SOURCE=.\game\bg_weapons.h +# End Source File +# Begin Source File + +SOURCE=.\game\botlib.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\disablewarnings.h +# End Source File +# Begin Source File + +SOURCE=.\win32\resource.h +# End Source File +# Begin Source File + +SOURCE=.\ui\ui_public.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\win32\qe3.ico +# End Source File +# Begin Source File + +SOURCE=.\win32\winquake.rc + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +# ADD BASE RSC /l 0x409 /i "win32" +# ADD RSC /l 0x409 /i "win32" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +!ENDIF + +# End Source File +# End Group +# Begin Group "Client" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\client\cl_cgame.cpp + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# ADD CPP /Ob0 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +# ADD BASE CPP /Ob0 +# ADD CPP /Ob0 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\client\cl_cin.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\cl_console.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\cl_input.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\cl_keys.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\cl_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\cl_net_chan.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\cl_parse.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\cl_scrn.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\cl_ui.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\client.h +# End Source File +# Begin Source File + +SOURCE=.\client\FXExport.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\FXExport.h +# End Source File +# Begin Source File + +SOURCE=.\client\FxPrimitives.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\FxPrimitives.h +# End Source File +# Begin Source File + +SOURCE=.\client\FxScheduler.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\FxScheduler.h +# End Source File +# Begin Source File + +SOURCE=.\client\FxSystem.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\FxSystem.h +# End Source File +# Begin Source File + +SOURCE=.\client\FxTemplate.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\FxUtil.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\FxUtil.h +# End Source File +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\game\bg_public.h +# End Source File +# Begin Source File + +SOURCE=.\cgame\cg_public.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\chash.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_load.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_local.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_patch.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_patch.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_polylib.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_polylib.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_public.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_shader.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_test.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cm_trace.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cmd.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\CNetProfile.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\common.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\cvar.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\files.cpp +# End Source File +# Begin Source File + +SOURCE=.\game\g_public.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\game_version.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\GenericParser2.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\GenericParser2.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\hstring.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\hstring.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\huffman.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\INetProfile.h +# End Source File +# Begin Source File + +SOURCE=.\ui\keycodes.h +# End Source File +# Begin Source File + +SOURCE=.\client\keys.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\md4.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\MiniHeap.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\msg.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\net_chan.cpp +# End Source File +# Begin Source File + +SOURCE=.\game\q_math.c + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +# PROP BASE Exclude_From_Build 1 +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\qcommon\q_math.cpp +# End Source File +# Begin Source File + +SOURCE=.\game\q_shared.c + +!IF "$(CFG)" == "jk2mp - Win32 Release JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Debug JK2" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "jk2mp - Win32 Final JK2" + +# PROP BASE Exclude_From_Build 1 +# PROP Exclude_From_Build 1 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\qcommon\q_shared.cpp +# End Source File +# Begin Source File + +SOURCE=.\game\q_shared.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\qcommon.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\qfiles.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\qgl.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\RoffSystem.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\RoffSystem.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\sstring.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\strip.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\strip.h +# End Source File +# Begin Source File + +SOURCE=.\game\surfaceflags.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\tags.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\unzip.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\unzip.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\vm.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\vm_interpreted.cpp +# End Source File +# Begin Source File + +SOURCE=.\qcommon\vm_local.h +# End Source File +# Begin Source File + +SOURCE=.\qcommon\vm_x86.cpp +# End Source File +# End Group +# Begin Group "Win32" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\win32\win_input.cpp +# End Source File +# Begin Source File + +SOURCE=.\win32\win_local.h +# End Source File +# Begin Source File + +SOURCE=.\win32\win_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\win32\win_net.cpp +# End Source File +# Begin Source File + +SOURCE=.\win32\win_shared.cpp +# End Source File +# Begin Source File + +SOURCE=.\win32\win_snd.cpp +# End Source File +# Begin Source File + +SOURCE=.\win32\win_syscon.cpp +# End Source File +# Begin Source File + +SOURCE=.\win32\win_wndproc.cpp +# End Source File +# End Group +# Begin Group "Server" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\server\server.h +# End Source File +# Begin Source File + +SOURCE=.\server\sv_bot.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_ccmds.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_client.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_game.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_init.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_net_chan.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_snapshot.cpp +# End Source File +# Begin Source File + +SOURCE=.\server\sv_world.cpp +# End Source File +# End Group +# Begin Group "Sound" + +# PROP Default_Filter "" +# Begin Group "MP3" + +# PROP Default_Filter "" +# Begin Group "MP3 Headers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\mp3code\config.h +# End Source File +# Begin Source File + +SOURCE=.\mp3code\copyright.h +# End Source File +# Begin Source File + +SOURCE=.\mp3code\htable.h +# End Source File +# Begin Source File + +SOURCE=.\mp3code\jdw.h +# End Source File +# Begin Source File + +SOURCE=.\mp3code\l3.h +# End Source File +# Begin Source File + +SOURCE=.\mp3code\mhead.h +# End Source File +# Begin Source File + +SOURCE=.\mp3code\mp3struct.h +# End Source File +# Begin Source File + +SOURCE=.\mp3code\port.h +# End Source File +# Begin Source File + +SOURCE=.\mp3code\small_header.h +# End Source File +# Begin Source File + +SOURCE=.\mp3code\tableawd.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\mp3code\cdct.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\csbt.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\csbtb.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\csbtl3.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\cup.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\cupini.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\cupl1.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\cupl3.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\cwin.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\cwinb.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\cwinm.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\hwin.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\l3dq.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\l3init.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\mdct.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\mhead.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\msis.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\towave.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\uph.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\upsf.c +# End Source File +# Begin Source File + +SOURCE=.\mp3code\wavep.c +# End Source File +# End Group +# Begin Source File + +SOURCE=.\client\snd_dma.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\snd_local.h +# End Source File +# Begin Source File + +SOURCE=.\client\snd_mem.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\snd_mix.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\snd_mp3.cpp +# End Source File +# Begin Source File + +SOURCE=.\client\snd_mp3.h +# End Source File +# Begin Source File + +SOURCE=.\client\snd_public.h +# End Source File +# End Group +# Begin Group "Renderer" + +# PROP Default_Filter "" +# Begin Group "jpeg files" + +# PROP Default_Filter "" +# Begin Group "JPG Source" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=".\jpeg-6\jcapimin.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jccoefct.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jccolor.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jcdctmgr.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jchuff.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jcinit.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jcmainct.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jcmarker.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jcmaster.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jcomapi.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jcparam.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jcphuff.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jcprepct.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jcsample.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jctrans.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdapimin.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdapistd.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdatadst.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdatasrc.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdcoefct.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdcolor.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jddctmgr.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdhuff.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdinput.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdmainct.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdmarker.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdmaster.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdpostct.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdsample.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdtrans.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jerror.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jfdctflt.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jidctflt.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jmemmgr.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jmemnobs.cpp" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jutils.cpp" +# End Source File +# End Group +# Begin Group "JPG Headers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=".\jpeg-6\jchuff.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jconfig.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdct.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jdhuff.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jerror.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jinclude.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jmemsys.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jmorecfg.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jpegint.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jpeglib.h" +# End Source File +# Begin Source File + +SOURCE=".\jpeg-6\jversion.h" +# End Source File +# Begin Source File + +SOURCE=.\ft2\sfdriver.h +# End Source File +# Begin Source File + +SOURCE=.\ft2\sfobjs.h +# End Source File +# Begin Source File + +SOURCE=.\ft2\ttcmap.h +# End Source File +# Begin Source File + +SOURCE=.\ft2\ttload.h +# End Source File +# Begin Source File + +SOURCE=.\ft2\ttpost.h +# End Source File +# Begin Source File + +SOURCE=.\ft2\ttsbit.h +# End Source File +# End Group +# End Group +# Begin Group "png" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\png\png.cpp +# End Source File +# Begin Source File + +SOURCE=.\png\png.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\renderer\glext.h +# End Source File +# Begin Source File + +SOURCE=.\win32\glw_win.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\matcomp.c +# End Source File +# Begin Source File + +SOURCE=.\renderer\matcomp.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_animation.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_backend.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_bsp.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_cmds.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_curve.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_flares.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_font.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_font.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_ghoul2.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_image.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_init.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_light.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_local.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_marks.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_mesh.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_model.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_noise.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_public.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_quicksprite.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_quicksprite.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_scene.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_shade.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_shade_calc.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_shader.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_shadows.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_sky.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_surface.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_surfacesprites.cpp +# End Source File +# Begin Source File + +SOURCE=.\cgame\tr_types.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_world.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_WorldEffects.cpp +# End Source File +# Begin Source File + +SOURCE=.\renderer\tr_WorldEffects.h +# End Source File +# Begin Source File + +SOURCE=.\win32\win_gamma.cpp +# End Source File +# Begin Source File + +SOURCE=.\win32\win_glimp.cpp +# End Source File +# Begin Source File + +SOURCE=.\win32\win_qgl.cpp +# End Source File +# End Group +# Begin Group "Ghoul2" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\ghoul2\G2.h +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_API.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_bolts.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_bones.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_gore.h +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_local.h +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_misc.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\G2_surfaces.cpp +# End Source File +# Begin Source File + +SOURCE=.\ghoul2\ghoul2_shared.h +# End Source File +# Begin Source File + +SOURCE=.\renderer\mdx_format.h +# End Source File +# End Group +# Begin Group "zlib" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\zlib\adler32.c +# End Source File +# Begin Source File + +SOURCE=.\zlib\crc32.cpp +# End Source File +# Begin Source File + +SOURCE=.\zlib\deflate.c +# End Source File +# Begin Source File + +SOURCE=.\zlib\deflate.h +# End Source File +# Begin Source File + +SOURCE=.\zlib\infblock.c +# End Source File +# Begin Source File + +SOURCE=.\zlib\infblock.h +# End Source File +# Begin Source File + +SOURCE=.\zlib\infcodes.c +# End Source File +# Begin Source File + +SOURCE=.\zlib\infcodes.h +# End Source File +# Begin Source File + +SOURCE=.\zlib\inffast.c +# End Source File +# Begin Source File + +SOURCE=.\zlib\inffast.h +# End Source File +# Begin Source File + +SOURCE=.\zlib\inffixed.h +# End Source File +# Begin Source File + +SOURCE=.\zlib\inflate.c +# End Source File +# Begin Source File + +SOURCE=.\zlib\inftrees.c +# End Source File +# Begin Source File + +SOURCE=.\zlib\inftrees.h +# End Source File +# Begin Source File + +SOURCE=.\zlib\infutil.c +# End Source File +# Begin Source File + +SOURCE=.\zlib\infutil.h +# End Source File +# Begin Source File + +SOURCE=.\zlib\trees.c +# End Source File +# Begin Source File + +SOURCE=.\zlib\trees.h +# End Source File +# Begin Source File + +SOURCE=.\zlib\zconf.h +# End Source File +# Begin Source File + +SOURCE=.\zlib\zlib.h +# End Source File +# Begin Source File + +SOURCE=.\zlib\zutil.c +# End Source File +# Begin Source File + +SOURCE=.\zlib\zutil.h +# End Source File +# End Group +# Begin Group "strings" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\strings\con_text.h +# End Source File +# Begin Source File + +SOURCE=.\strings\str_server.h +# End Source File +# End Group +# Begin Group "encryption" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\encryption\buffer.cpp +# End Source File +# Begin Source File + +SOURCE=.\encryption\buffer.h +# End Source File +# Begin Source File + +SOURCE=.\encryption\cpp_interface.cpp +# End Source File +# Begin Source File + +SOURCE=.\encryption\cpp_interface.h +# End Source File +# Begin Source File + +SOURCE=.\encryption\encryption.h +# End Source File +# Begin Source File + +SOURCE=.\encryption\sockets.cpp +# End Source File +# Begin Source File + +SOURCE=.\encryption\sockets.h +# End Source File +# End Group +# End Target +# End Project diff --git a/CODE-mp/winded/jk2mp.dsw b/CODE-mp/winded/jk2mp.dsw new file mode 100644 index 0000000..6799c5a --- /dev/null +++ b/CODE-mp/winded/jk2mp.dsw @@ -0,0 +1,101 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "JK2cgame"=.\cgame\JK2_cgame.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "JK2game"=.\game\JK2_game.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "WinDed"=.\WinDed.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "botlib"=.\botlib\botlib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "jk2mp"=.\jk2mp.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name botlib + End Project Dependency + Begin Project Dependency + Project_Dep_Name ui + End Project Dependency + Begin Project Dependency + Project_Dep_Name JK2cgame + End Project Dependency + Begin Project Dependency + Project_Dep_Name JK2game + End Project Dependency +}}} + +############################################################################### + +Project: "ui"=.\ui\ui.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/CODE-mp/winded/jk2mp.ncb b/CODE-mp/winded/jk2mp.ncb new file mode 100644 index 0000000..766834b Binary files /dev/null and b/CODE-mp/winded/jk2mp.ncb differ diff --git a/CODE-mp/winded/jk2mp.opt b/CODE-mp/winded/jk2mp.opt new file mode 100644 index 0000000..7f869b3 Binary files /dev/null and b/CODE-mp/winded/jk2mp.opt differ diff --git a/CODE-mp/winded/jk2mp.plg b/CODE-mp/winded/jk2mp.plg new file mode 100644 index 0000000..4bae736 --- /dev/null +++ b/CODE-mp/winded/jk2mp.plg @@ -0,0 +1,205 @@ + + +
+

Build Log

+

+--------------------Configuration: jk2mp - Win32 Debug JK2-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\drews\LOCALS~1\Temp\RSP1C5.tmp" with contents +[ +/nologo /G6 /MLd /W3 /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_JK2" /Fr".\Debug\jk2/" /Fo".\Debug\jk2/" /Fd".\Debug\jk2/" /FD /GZ /c +"C:\Raven\JKII\WinDed\qcommon\cm_shader.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\drews\LOCALS~1\Temp\RSP1C5.tmp" +Creating temporary file "C:\DOCUME~1\drews\LOCALS~1\Temp\RSP1C6.tmp" with contents +[ +advapi32.lib winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib ole32.lib /nologo /stack:0x800000 /subsystem:windows /incremental:yes /pdb:".\Debug/jk2mp.pdb" /map:"Debug/jk2mp.map" /debug /machine:I386 /out:".\Debug/jk2mp.exe" +.\Debug\jk2\cl_cgame.obj +.\Debug\jk2\cl_cin.obj +.\Debug\jk2\cl_console.obj +.\Debug\jk2\cl_input.obj +.\Debug\jk2\cl_keys.obj +.\Debug\jk2\cl_main.obj +.\Debug\jk2\cl_net_chan.obj +.\Debug\jk2\cl_parse.obj +.\Debug\jk2\cl_scrn.obj +.\Debug\jk2\cl_ui.obj +.\Debug\jk2\FXExport.obj +.\Debug\jk2\FxPrimitives.obj +.\Debug\jk2\FxScheduler.obj +.\Debug\jk2\FxSystem.obj +.\Debug\jk2\FxTemplate.obj +.\Debug\jk2\FxUtil.obj +.\Debug\jk2\cm_load.obj +.\Debug\jk2\cm_patch.obj +.\Debug\jk2\cm_polylib.obj +.\Debug\jk2\cm_shader.obj +.\Debug\jk2\cm_test.obj +.\Debug\jk2\cm_trace.obj +.\Debug\jk2\cmd.obj +.\Debug\jk2\CNetProfile.obj +.\Debug\jk2\common.obj +.\Debug\jk2\cvar.obj +.\Debug\jk2\files.obj +.\Debug\jk2\GenericParser2.obj +.\Debug\jk2\hstring.obj +.\Debug\jk2\huffman.obj +.\Debug\jk2\md4.obj +.\Debug\jk2\msg.obj +.\Debug\jk2\net_chan.obj +.\Debug\jk2\q_math.obj +.\Debug\jk2\q_shared.obj +.\Debug\jk2\RoffSystem.obj +.\Debug\jk2\strip.obj +.\Debug\jk2\unzip.obj +.\Debug\jk2\vm.obj +.\Debug\jk2\vm_interpreted.obj +.\Debug\jk2\vm_x86.obj +.\Debug\jk2\win_input.obj +.\Debug\jk2\win_main.obj +.\Debug\jk2\win_net.obj +.\Debug\jk2\win_shared.obj +.\Debug\jk2\win_snd.obj +.\Debug\jk2\win_syscon.obj +.\Debug\jk2\win_wndproc.obj +.\Debug\jk2\sv_bot.obj +.\Debug\jk2\sv_ccmds.obj +.\Debug\jk2\sv_client.obj +.\Debug\jk2\sv_game.obj +.\Debug\jk2\sv_init.obj +.\Debug\jk2\sv_main.obj +.\Debug\jk2\sv_net_chan.obj +.\Debug\jk2\sv_snapshot.obj +.\Debug\jk2\sv_world.obj +.\Debug\jk2\cdct.obj +.\Debug\jk2\csbt.obj +.\Debug\jk2\csbtb.obj +.\Debug\jk2\csbtl3.obj +.\Debug\jk2\cup.obj +.\Debug\jk2\cupini.obj +.\Debug\jk2\cupl1.obj +.\Debug\jk2\cupl3.obj +.\Debug\jk2\cwin.obj +.\Debug\jk2\cwinb.obj +.\Debug\jk2\cwinm.obj +.\Debug\jk2\hwin.obj +.\Debug\jk2\l3dq.obj +.\Debug\jk2\l3init.obj +.\Debug\jk2\mdct.obj +.\Debug\jk2\mhead.obj +.\Debug\jk2\msis.obj +.\Debug\jk2\towave.obj +.\Debug\jk2\uph.obj +.\Debug\jk2\upsf.obj +.\Debug\jk2\wavep.obj +.\Debug\jk2\snd_dma.obj +.\Debug\jk2\snd_mem.obj +.\Debug\jk2\snd_mix.obj +.\Debug\jk2\snd_mp3.obj +.\Debug\jk2\jcapimin.obj +.\Debug\jk2\jccoefct.obj +.\Debug\jk2\jccolor.obj +.\Debug\jk2\jcdctmgr.obj +.\Debug\jk2\jchuff.obj +.\Debug\jk2\jcinit.obj +.\Debug\jk2\jcmainct.obj +.\Debug\jk2\jcmarker.obj +.\Debug\jk2\jcmaster.obj +.\Debug\jk2\jcomapi.obj +.\Debug\jk2\jcparam.obj +.\Debug\jk2\jcphuff.obj +.\Debug\jk2\jcprepct.obj +.\Debug\jk2\jcsample.obj +.\Debug\jk2\jctrans.obj +.\Debug\jk2\jdapimin.obj +.\Debug\jk2\jdapistd.obj +.\Debug\jk2\jdatadst.obj +.\Debug\jk2\jdatasrc.obj +.\Debug\jk2\jdcoefct.obj +.\Debug\jk2\jdcolor.obj +.\Debug\jk2\jddctmgr.obj +.\Debug\jk2\jdhuff.obj +.\Debug\jk2\jdinput.obj +.\Debug\jk2\jdmainct.obj +.\Debug\jk2\jdmarker.obj +.\Debug\jk2\jdmaster.obj +.\Debug\jk2\jdpostct.obj +.\Debug\jk2\jdsample.obj +.\Debug\jk2\jdtrans.obj +.\Debug\jk2\jerror.obj +.\Debug\jk2\jfdctflt.obj +.\Debug\jk2\jidctflt.obj +.\Debug\jk2\jmemmgr.obj +.\Debug\jk2\jmemnobs.obj +.\Debug\jk2\jutils.obj +.\Debug\jk2\png.obj +.\Debug\jk2\matcomp.obj +.\Debug\jk2\tr_animation.obj +.\Debug\jk2\tr_backend.obj +.\Debug\jk2\tr_bsp.obj +.\Debug\jk2\tr_cmds.obj +.\Debug\jk2\tr_curve.obj +.\Debug\jk2\tr_flares.obj +.\Debug\jk2\tr_font.obj +.\Debug\jk2\tr_ghoul2.obj +.\Debug\jk2\tr_image.obj +.\Debug\jk2\tr_init.obj +.\Debug\jk2\tr_light.obj +.\Debug\jk2\tr_main.obj +.\Debug\jk2\tr_marks.obj +.\Debug\jk2\tr_mesh.obj +.\Debug\jk2\tr_model.obj +.\Debug\jk2\tr_noise.obj +.\Debug\jk2\tr_quicksprite.obj +.\Debug\jk2\tr_scene.obj +.\Debug\jk2\tr_shade.obj +.\Debug\jk2\tr_shade_calc.obj +.\Debug\jk2\tr_shader.obj +.\Debug\jk2\tr_shadows.obj +.\Debug\jk2\tr_sky.obj +.\Debug\jk2\tr_surface.obj +.\Debug\jk2\tr_surfacesprites.obj +.\Debug\jk2\tr_world.obj +.\Debug\jk2\tr_WorldEffects.obj +.\Debug\jk2\win_gamma.obj +.\Debug\jk2\win_glimp.obj +.\Debug\jk2\win_qgl.obj +.\Debug\jk2\G2_API.obj +.\Debug\jk2\G2_bolts.obj +.\Debug\jk2\G2_bones.obj +.\Debug\jk2\G2_misc.obj +.\Debug\jk2\G2_surfaces.obj +.\Debug\jk2\adler32.obj +.\Debug\jk2\crc32.obj +.\Debug\jk2\deflate.obj +.\Debug\jk2\infblock.obj +.\Debug\jk2\infcodes.obj +.\Debug\jk2\inffast.obj +.\Debug\jk2\inflate.obj +.\Debug\jk2\inftrees.obj +.\Debug\jk2\infutil.obj +.\Debug\jk2\trees.obj +.\Debug\jk2\zutil.obj +.\Debug\jk2\buffer.obj +.\Debug\jk2\cpp_interface.obj +.\Debug\jk2\sockets.obj +.\win32\winquake.res +.\Debug\botlib.lib +.\Debug\uix86.lib +.\Debug\cgamex86.lib +.\Debug\jk2mpgamex86.lib +] +Creating command line "link.exe @C:\DOCUME~1\drews\LOCALS~1\Temp\RSP1C6.tmp" +

Output Window

+Compiling... +cm_shader.cpp +Linking... + + + +

Results

+jk2mp.exe - 0 error(s), 0 warning(s) +
+ + diff --git a/CODE-mp/winded/mssccprj.scc b/CODE-mp/winded/mssccprj.scc new file mode 100644 index 0000000..3ec70d1 --- /dev/null +++ b/CODE-mp/winded/mssccprj.scc @@ -0,0 +1,5 @@ +SCC = This is a Source Code Control file + +[jk2mp.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\jk2sof2MP" +SCC_Project_Name = "$/General/code", EAAAAAAA diff --git a/CODE-mp/winded/put.bat b/CODE-mp/winded/put.bat new file mode 100644 index 0000000..4e62303 --- /dev/null +++ b/CODE-mp/winded/put.bat @@ -0,0 +1 @@ +@echo use installvms instead diff --git a/CODE-mp/winded/tosend.bat b/CODE-mp/winded/tosend.bat new file mode 100644 index 0000000..17a9ea9 --- /dev/null +++ b/CODE-mp/winded/tosend.bat @@ -0,0 +1,4 @@ +xcopy/y final\*.exe c:\send\game +xcopy/y base\vm\cgame.qvm c:\send\game\base\vm +xcopy/y base\vm\jk2mpgame.qvm c:\send\game\base\vm +xcopy/y base\vm\ui.qvm c:\send\game\base\vm diff --git a/CODE-mp/winded/vssver.scc b/CODE-mp/winded/vssver.scc new file mode 100644 index 0000000..72bea3d Binary files /dev/null and b/CODE-mp/winded/vssver.scc differ diff --git a/CODE-mp/zlib/vssver.scc b/CODE-mp/zlib/vssver.scc new file mode 100644 index 0000000..07555ff Binary files /dev/null and b/CODE-mp/zlib/vssver.scc differ diff --git a/code/0_compiled_first/vssver.scc b/code/0_compiled_first/vssver.scc new file mode 100644 index 0000000..d8b8cba Binary files /dev/null and b/code/0_compiled_first/vssver.scc differ diff --git a/code/Default.SUP b/code/Default.SUP new file mode 100644 index 0000000..e0d55e7 --- /dev/null +++ b/code/Default.SUP @@ -0,0 +1,3 @@ +//SUPPRESSIONPROJ:Default +//VERSION:5.00 +//ENABLE:Yes diff --git a/code/FinalBuild/exe/winquake.res b/code/FinalBuild/exe/winquake.res deleted file mode 100644 index 9ef8365..0000000 Binary files a/code/FinalBuild/exe/winquake.res and /dev/null differ diff --git a/code/Release/exe/winquake.res b/code/Release/exe/winquake.res deleted file mode 100644 index 9ef8365..0000000 Binary files a/code/Release/exe/winquake.res and /dev/null differ diff --git a/code/StarWars.ncb b/code/StarWars.ncb new file mode 100644 index 0000000..ae42150 Binary files /dev/null and b/code/StarWars.ncb differ diff --git a/code/StarWars.opt b/code/StarWars.opt new file mode 100644 index 0000000..a257699 Binary files /dev/null and b/code/StarWars.opt differ diff --git a/code/alut.lib b/code/alut.lib new file mode 100644 index 0000000..67cde9f Binary files /dev/null and b/code/alut.lib differ diff --git a/code/base/ext_data/NPCs.cfg b/code/base/ext_data/NPCs.cfg new file mode 100644 index 0000000..034e381 --- /dev/null +++ b/code/base/ext_data/NPCs.cfg @@ -0,0 +1,2315 @@ +//Star Wars +/* +defaults and explanations of fields: + aggression 3 How likely they are to attack (from 1 (least) to 5 (most)) + aim 3 How good their aim is (from 1 (worst) to 5 (best)) + earshot 1024 How far in map units they can hear, in map units + evasion 3 How likely they are to take cover or defensive maneuvers (from 1 (least) to 5 (most)) + hfov 45 Horizontal field of view, in angles + intelligence 3 How smart they are, in general (from 1 (least) to 5 (most)) + move 3 How complex their moves are when evading or in combat (from 1 (least) to 5 (most)) + reactions 3 How quickly they react (from 1 (worst) to 5 (best)) + shootDistance 0 Overrides current weapon's max range + vfov 34 Vertical field of view, in angles + vigilance 0.1 How likely they are to notice something (from 0 (never) to 1 (always)) + visrange 2048 How far away they can see something, in map units + race none human, borg, parasite, klingon, malon, hirogen, stasis, species8472, dreadnought, harvester, reaver, avatar, vulcan + playerTeam none player, enemy, neutral + enemyTeam none player, enemy, neutral + + health 100 Health of entity (if not supplied by designer) + + moveType "runjump" Which movetype they can be (other choices are "static", "walk" and "flyswim" + yawSpeed 50 How quickly they can turn + walkSpeed 150 How fast they walk + runSpeed 300 How fast they run + acceleration 15 Acceleration (accel x 20fps = speed up per second, so accel of 15 means they can go from 0 to 300 in one second) + Accel of 0 means don't accel/decel - just start/stop (good if you're a slow mover anyway and/or robotic - like a Borg) + + scaleX 100 X (horiz) scale, 100 is normal 100% scale + scaleY 100 Y (horiz) scale, 100 is normal 100% scale + scaleZ 100 Z (vert) scale, 100 is normal 100% scale + scale 100 Sets all above 3 to what you specify + headModel "hazard" model directory/skin name + torsoModel "hazard" model directory/skin name + legsModel "hazard" model directory/skin name + headYawRangeLeft 70 How far left you can turn your head (angles) + headYawRangeRight 70 How far right you can turn your head (angles) + headPitchRangeUp 60 How far up you can tilt your head (angles) + headPitchRangeDown 60 How far down you can tilt your head (angles) + torsoYawRangeLeft 60 How far left you can turn your torso (angles) + torsoYawRangeRight 60 How far right you can turn your torso (angles) + torsoPitchRangeUp 30 How far up you can tilt your torso (angles) + torsoPitchRangeDown 70 How far down you can tilt your torso (angles) + + snd "munro" subdirectory of sound/player from which to get custom sounds (pain, death, jump, etc.) + dismemberProbHead 0 probability of head being dismembered ( from 0 (never) to 100 (always) ) + dismemberProbArms 0 probability of arms being dismembered ( from 0 (never) to 100 (always) ) + dismemberProbHands 0 probability of hands being dismembered ( from 0 (never) to 100 (always) ) + dismemberProbLegs 0 probability of legs being dismembered ( from 0 (never) to 100 (always) ) + dismemberProbWaist 0 probability of waist being dismembered ( from 0 (never) to 100 (always) ) +*/ + +//Characters +munro +{ + fullName "Katarn, Kyle" + playerModel kyle + saberColor blue + reactions 4 + aim 5 + move 3 + aggression 5 + evasion 5 + intelligence 5 + playerTeam player +// race human + class kyle + snd munro +} + +Kyle +{ + fullName "Katarn, Kyle" + playerModel kyle + saberColor blue + reactions 4 + aim 5 + move 3 + aggression 5 + evasion 5 + intelligence 5 + playerTeam player +// race human + class kyle + snd kyle + sndcombat kyle + sndjedi kyle + dismemberProbHead 1 + dismemberProbArms 1 + dismemberProbHands 20 + dismemberProbLegs 1 + dismemberProbWaist 1 +} + +Tavion +{ + playerModel tavion + rank commander + saberColor red + reactions 3 + aim 3 + move 5 + aggression 3 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam enemy + enemyTeam player +// race human + class tavion + snd tavion + sndcombat tavion + sndjedi tavion + yawSpeed 120 + walkSpeed 55 + runSpeed 200 + health 300 + dismemberProbHead 10 + dismemberProbArms 35 + dismemberProbLegs 10 + dismemberProbHands 50 + dismemberProbWaist 10 +} + +Lando +{ + fullName "Calrissian, Lando" + playerModel lando + snd lando + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam player + enemyTeam enemy +// race human + class lando + snd lando + sndcombat lando + sndextra lando + sndjedi lando + walkSpeed 55 + runSpeed 200 + yawspeed 120 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 0 + dismemberProbLegs 0 + dismemberProbWaist 0 +} + +Reelo +{ + fullName "Baruk, Reelo" + playerModel reelo + snd reelo + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam enemy + enemyTeam player +// race klingon + class reelo + snd reelo + sndcombat reelo + sndextra reelo + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 5 + dismemberProbArms 1 + dismemberProbHands 20 + dismemberProbLegs 1 + dismemberProbWaist 0 +} + +Jan +{ + fullName "Ors, Jan" + playerModel jan + rank lt + reactions 3 + aim 5 + move 3 + aggression 3 + evasion 3 + intelligence 3 + playerTeam player + enemyTeam enemy + class jan + snd jan + sndcombat jan + sndextra jan + yawSpeed 140 + walkSpeed 55 + runSpeed 200 +// race human + snd jan + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 1 + dismemberProbLegs 0 + dismemberProbWaist 0 +} + +Galak +{ + fullName "Fyyar, Galak" + playerModel galak + snd galak + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank captain + playerTeam enemy + enemyTeam player +// race klingon + class imperial + yawspeed 90 + walkSpeed 55 + runSpeed 200 +} + +Galak_Mech +{ + fullName "Fyyar, Galak" + playerModel galak_mech + health 1000 + width 20 + height 88 + crouchheight 88 + snd galak_mech + reactions 3 + aim 5 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam enemy + enemyTeam player +// race klingon + class galak_mech + snd galak + sndcombat galak + sndextra galak + yawSpeed 50 + walkSpeed 45 + runSpeed 150 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 0 + dismemberProbLegs 0 + dismemberProbWaist 0 + headPitchRangeUp 60 + headPitchRangeDown 60 + torsoPitchRangeUp 60 + torsoPitchRangeDown 60 +} + + +Desann +{ + fullName "Desann" + playerModel desann + saberColor red + rank captain + reactions 3 + aim 3 + move 5 + aggression 3 + evasion 5 + intelligence 5 + hfov 160 + vfov 160 + scale 135 + height 78 + crouchheight 42 + width 18 + playerTeam enemy + enemyTeam player +// race human + class desann + yawSpeed 120 + walkSpeed 55 + runSpeed 200 + snd desann + sndcombat desann + sndjedi desann + health 500 + dismemberProbHead 10 + dismemberProbArms 35 + dismemberProbLegs 10 + dismemberProbHands 50 + dismemberProbWaist 10 +} + +Luke +{ + fullName "Skywalker, Luke" + playerModel luke + saberColor green + rank captain + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 5 + intelligence 3 + playerTeam player + enemyTeam enemy + class luke + yawSpeed 140 + walkSpeed 55 + runSpeed 200 +// race human + snd luke + sndcombat luke + sndjedi luke + health 200 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} + +MonMothma +{ + fullName "Mon Mothma" + playerModel monmothma + snd monmothma + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam player + enemyTeam enemy +// race human + class monmotha + walkSpeed 55 + runSpeed 200 + yawspeed 90 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} + +Bartender +{ + fullName "Bartender" + playerModel chiss + snd bartender + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam neutral + enemyTeam neutral +// race human + class bartender + walkSpeed 55 + runSpeed 200 + yawspeed 90 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} + +MorganKatarn +{ + fullName "MorganKatarn" + playerModel morgan + snd morgan + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam neutral + enemyTeam neutral +// race human + class morgan + walkSpeed 55 + runSpeed 200 + yawspeed 90 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} + +Prisoner +{ + playerModel prisoner + snd prisoner + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam player + enemyTeam enemy + class prisoner + snd prisoner1 + sndcombat prisoner1 + sndextra prisoner1 + walkSpeed 55 + runSpeed 200 + yawspeed 110 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +Prisoner2 +{ + playerModel prisoner + snd prisoner + surfOff "head head_face" + surfOn "head_off head_face_off" + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam player + enemyTeam enemy + class prisoner + snd prisoner2 + sndcombat prisoner2 + sndextra prisoner2 + walkSpeed 55 + runSpeed 200 + yawspeed 110 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +//NPC Humanoids +Jedi +{ + playerModel jedi + saberColor yellow + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam player + enemyTeam enemy + class jedi + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi1 + sndcombat jedi1 + sndjedi jedi1 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +Jedi2 +{ + playerModel jedi + saberColor orange + rank lt + customSkin j2 + surfOff "head head_face" + surfOn "head_off head_face_off" + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam player + enemyTeam enemy + class jedi + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi2 + sndcombat jedi2 + sndjedi jedi2 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +JediF +{ + playerModel jan + surfOff "torso_vest hips_chaps torso_computer head_goggles torso_comp hips_belt" + surfOn "torso_augment_off hips_augment_off hips_torso_off" + saberColor random + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam player + enemyTeam enemy + class jedi + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jan + sndcombat jan + sndjedi jan + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +JediTrainer +{ + playerModel jeditrainer + saberColor purple + rank commander + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + playerTeam player + enemyTeam enemy + class jedi + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi1 + sndcombat jedi1 + sndjedi jedi1 + health 400 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +Rebel +{ + playerModel rebel + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam player + enemyTeam enemy +// race human + class rebel + snd rebel1 + sndcombat rebel1 + sndextra rebel1 + yawspeed 120 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Rebel2 +{ + playerModel rebel + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam player + enemyTeam enemy +// race human + class rebel + snd rebel2 + sndcombat rebel2 + sndextra rebel2 + yawspeed 120 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +BespinCop +{ + playerModel bespin_cop + health 40 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam player + enemyTeam enemy + walkSpeed 55 + runSpeed 200 + yawspeed 120 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +// race bespincop + class bespin_cop + snd bespincop1 + sndcombat bespincop1 + sndextra bespincop1 +} + +BespinCop2 +{ + playerModel bespin_cop + health 40 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam player + enemyTeam enemy + walkSpeed 55 + runSpeed 200 + yawspeed 120 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +// race bespincop + class bespin_cop + snd bespincop2 + sndcombat bespincop2 + sndextra bespincop2 +} + +Ugnaught +{ + playerModel ugnaught + scale 75 + health 10 + snd ugnaught + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam neutral + enemyTeam player +// race klingon + class ugnaught + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Ugnaught2 +{ + playerModel ugnaught + surfOff "l_hand_purse" + surfOn "r_hand_tool_off" + scale 75 + health 10 + snd ugnaught + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam neutral + enemyTeam player +// race klingon + class ugnaught + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Gran +{ + playerModel gran + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + health 30 + playerTeam enemy + enemyTeam player +// race klingon + class gran + snd gran1 + sndcombat gran1 + sndextra gran1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Gran2 +{ + playerModel gran + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + health 30 + playerTeam enemy + enemyTeam player +// race klingon + class gran + snd gran2 + sndcombat gran2 + sndextra gran2 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +GranShooter +{ + playerModel gran + surfOff "l_leg_kneeguard" + reactions 3 + aim 5 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 40 + rank crewman + playerTeam enemy + enemyTeam player +// race klingon + class gran + snd gran1 + sndcombat gran1 + sndextra gran1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +GranBoxer +{ + playerModel gran + surfOff "l_leg_kneeguard r_leg_kneeguard" + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 50 + rank crewman + playerTeam enemy + enemyTeam player +// race klingon + class gran + snd gran2 + sndcombat gran2 + sndextra gran2 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Rodian +{ + playerModel rodian + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 25 + rank crewman + playerTeam enemy + enemyTeam player +// race klingon + class rodian + snd rodian1 + sndcombat rodian1 + sndextra rodian1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + visrange 8192 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Rodian2 +{ + playerModel rodian + surfOff "hips_belt torso_vest" + surfOn "torso_augment_off" + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 20 + rank crewman + playerTeam enemy + enemyTeam player +// race klingon + class rodian + snd rodian2 + sndcombat rodian2 + sndextra rodian2 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Weequay +{ + playerModel weequay +//FIXME: randomize these somehow, also belt... + surfOff "hips_lowerarmor" + surfOn "hips_torso_augment_off" + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 30 + rank crewman + playerTeam enemy + enemyTeam player +// race klingon + class weequay + snd weequay + sndcombat weequay + sndextra weequay + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Weequay2 +{ + playerModel weequay + surfOff "head_l_hairback hips_r_strap hips_r_packsmall" + surfOn "head_r_hairshoulder_off hips_l_packsmall_off hips_l_strap_off" + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 30 + rank crewman + playerTeam enemy + enemyTeam player + class weequay + snd weequay + sndcombat weequay + sndextra weequay + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Weequay3 +{ + playerModel weequay + surfOff "head_l_hairback hips_l_packlarge hips_l_packwide hips_r_strap hips_r_packsmall" + surfOn "head_r_hairback_off hips_l_packsmall_off hips_l_strap_off hips_r_packlarge_off hips_r_packwide_off" + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 30 + rank crewman + playerTeam enemy + enemyTeam player + class weequay + snd weequay + sndcombat weequay + sndextra weequay + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Weequay4 +{ + playerModel weequay + surfOff "head_l_hairback hips_l_packlarge hips_l_packwide" + surfOn "head_l_hairshoulder_off hips_r_packlarge_off hips_r_packwide_off" + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 30 + rank crewman + playerTeam enemy + enemyTeam player +// race klingon + class weequay + snd weequay + sndcombat weequay + sndextra weequay + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Trandoshan +{ + playerModel trandoshan + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 40 + rank crewman + playerTeam enemy + enemyTeam player +// race klingon + class trandoshan + snd trandoshan1 + sndcombat trandoshan1 + sndextra trandoshan1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +StormTrooper +{ + playerModel stormtrooper + surfOff torso_pauldron_off + surfOn "torso_armor_neck_augment torso_body_neck_augment" + health 30 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam enemy + enemyTeam player +// race klingon + class stormtrooper + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd st1 + sndcombat st1 + sndextra st1 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +StormTrooper2 +{ + playerModel stormtrooper + surfOff torso_pauldron_off + surfOn "torso_armor_neck_augment torso_body_neck_augment" + health 30 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam enemy + enemyTeam player +// race klingon + class stormtrooper + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd st2 + sndcombat st2 + sndextra st2 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +STOfficer +{ + playerModel stormtrooper + surfOn torso_pauldron_off + surfOff "torso_armor_neck_augment torso_body_neck_augment" + health 60 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + rank ensign + scale 110 + playerTeam enemy + enemyTeam player +// race klingon + class stormtrooper + height 68 + crouchheight 52 + walkSpeed 51 + runSpeed 200 + snd stofficer1 + sndcombat stofficer1 + sndextra stofficer1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +StormPilot +{ + playerModel stormpilot + health 30 + headPitchRangeDown 30 + reactions 3 + aim 5 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam enemy + enemyTeam player + class stormtrooper + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd st3 + sndcombat st3 + sndextra st3 + yawspeed 80 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +STOfficerAlt +{ + playerModel stormtrooper + surfOn torso_pauldron_off + surfOff "torso_armor_neck_augment torso_body_neck_augment" + health 60 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + rank ensign + scale 110 + playerTeam enemy + enemyTeam player +// race klingon + class stormtrooper + height 68 + crouchheight 52 + walkSpeed 51 + runSpeed 200 + snd stofficer2 + sndcombat stofficer2 + sndextra stofficer2 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +STCommander +{ + playerModel stormtrooper + surfOn torso_pauldron_off + surfOff "torso_armor_neck_augment torso_body_neck_augment" + health 60 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + rank ensign + scale 110 + playerTeam enemy + enemyTeam player +// race klingon + class stormtrooper + height 68 + crouchheight 52 + walkSpeed 51 + runSpeed 200 + snd stofficer2 + sndcombat stofficer2 + sndextra stofficer2 + yawspeed 110 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +SwampTrooper +{ + playerModel swamptrooper + headPitchRangeDown 30 + health 70 + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 3 + intelligence 3 + scale 110 + playerTeam enemy + enemyTeam player +// race klingon + class swamptrooper + height 68 + crouchheight 52 + snd swamp1 + sndcombat swamp1 + sndextra swamp1 + yawspeed 100 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +SwampTrooper2 +{ + playerModel swamptrooper + headPitchRangeDown 30 + health 70 + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 3 + intelligence 3 + scale 110 + playerTeam enemy + enemyTeam player +// race klingon + class swamptrooper + height 68 + crouchheight 52 + snd swamp2 + sndcombat swamp2 + sndextra swamp2 + yawspeed 100 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +RocketTrooper +{ + playerModel stormtrooper + surfOn torso_pauldron_off + surfOff "torso_armor_neck_augment torso_body_neck_augment" + health 60 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + rank ensign + scale 110 + playerTeam enemy + enemyTeam player +// race klingon + class stormtrooper + height 68 + crouchheight 52 + walkSpeed 51 + runSpeed 200 + snd st3 + sndcombat st3 + sndextra st3 + yawspeed 100 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Imperial +{ + playerModel imperial + surfOff l_arm_key + health 20 + reactions 2 + aim 2 + move 2 + aggression 2 + evasion 2 + intelligence 2 + rank lt + playerTeam enemy + enemyTeam player +// race klingon + class imperial + snd io2 + sndcombat io2 + sndextra io2 + yawspeed 110 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +ImpOfficer +{ + playerModel imperial + surfOff l_arm_key + customSkin officer + health 40 + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 3 + intelligence 3 + rank ltcomm + playerTeam enemy + enemyTeam player +// race klingon + class imperial + snd io1 + sndcombat io1 + sndextra io1 + yawspeed 110 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +ImpCommander +{ + playerModel imperial + surfOff l_arm_key + customSkin commander + health 80 + reactions 4 + aim 4 + move 4 + aggression 4 + evasion 4 + intelligence 4 + rank commander + playerTeam enemy + enemyTeam player +// race klingon + class imperial +// snd io3 +// sndcombat io3 +// sndextra io3 + snd io1 + sndcombat io1 + sndextra io1 + yawspeed 110 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +ImpWorker +{ + playerModel imperial_worker + headPitchRangeDown 30 + health 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam enemy + enemyTeam player +// race imperial + class impworker + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd worker1 + sndcombat worker1 + sndextra worker1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +ImpWorker2 +{ + playerModel imperial_worker + headPitchRangeDown 30 + health 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam enemy + enemyTeam player +// race imperial + class impworker + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd worker2 + sndcombat worker2 + sndextra worker2 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +ImpWorker3 +{ + playerModel imperial_worker + headPitchRangeDown 30 + health 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam enemy + enemyTeam player +// race imperial + class impworker + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd worker3 + sndcombat worker3 + sndextra worker3 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +RebornAcrobat +{ + playerModel reborn + customSkin acrobat + saberColor red + rank crewman + reactions 3 + aim 3 + move 5 + aggression 3 + evasion 3 + intelligence 5 + hfov 160 + vfov 160 + scale 96 + playerTeam enemy + enemyTeam player +// race human + class reborn + snd reborn1 + sndcombat reborn1 + sndjedi reborn1 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +Reborn +{ + playerModel reborn + saberColor red + reactions 1 + aim 1 + move 1 + aggression 1 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + scale 94 + playerTeam enemy + enemyTeam player +// race human + class reborn + snd reborn1 + sndcombat reborn1 + sndjedi reborn1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 40 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +RebornForceUser +{ + playerModel reborn + customSkin forceuser + saberColor red + rank ensign + reactions 3 + aim 3 + move 5 + aggression 2 + evasion 2 + intelligence 5 + hfov 160 + vfov 160 + scale 96 + playerTeam enemy + enemyTeam player +// race human + class reborn + snd reborn2 + sndcombat reborn2 + sndjedi reborn2 + yawSpeed 80 + walkSpeed 55 + runSpeed 200 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +RebornFencer +{ + playerModel reborn + customSkin fencer + saberColor red + rank ltjg + reactions 3 + aim 3 + move 5 + aggression 4 + evasion 2 + intelligence 5 + hfov 160 + vfov 160 + scale 96 + playerTeam enemy + enemyTeam player +// race human + class reborn + snd reborn2 + sndcombat reborn2 + sndjedi reborn2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +RebornBoss +{ + playerModel reborn + customSkin boss + saberColor red + rank lt + reactions 3 + aim 3 + move 5 + aggression 4 + evasion 3 + intelligence 5 + hfov 160 + vfov 160 + playerTeam enemy + enemyTeam player +// race human + class reborn + snd reborn3 + sndcombat reborn3 + sndjedi reborn3 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 150 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +ShadowTrooper +{ + playerModel shadowtrooper + saberColor red + rank ltcomm + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam enemy + enemyTeam player +// race human + class shadowtrooper + snd shadow1 + sndcombat shadow1 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 1 +} + +ShadowTrooper2 +{ + playerModel shadowtrooper + saberColor red + rank lt + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam enemy + enemyTeam player +// race human + class shadowtrooper + snd shadow2 + sndcombat shadow2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 1 +} +//NPC Monsters +Howler +{ + playerModel howler + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam enemy + enemyTeam player + class howler + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + hFOV 120 + vfov 45 + snd howler + health 60 +} + +Minemonster +{ + playerModel minemonster + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam enemy + enemyTeam player + class minemonster + snd mine + yawSpeed 160 + runSpeed 210 + walkSpeed 50 + hFOV 120 + vfov 45 + height 30 + width 9 + snd mine + health 40 +} + + +Glider +{ + playerModel glider + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam neutral + enemyTeam neutral +// race harvester + class glider + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + hFOV 120 + vfov 45 + snd glider +} + + +//NPC Droids +protocol +{ + playerModel protocol + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam neutral + enemyTeam neutral +// race bot + class protocol + snd protocol + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + height 48 + width 12 + hFOV 120 + vfov 45 + snd protocol +} + +protocol_imp +{ + playerModel protocol + surfOn head_off + surfOff head + customSkin imp + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam neutral + enemyTeam neutral +// race bot + class protocol + snd protocol + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + height 48 + width 12 + hFOV 120 + vfov 45 + snd protocol +} + +r2d2 +{ + playermodel r2d2 + headYawRangeLeft 180 + headYawRangeRight 180 + headPitchRangeUp 0 + headPitchRangeDown 0 + torsoYawRangeLeft 0 + torsoYawRangeRight 0 + torsoPitchRangeUp 10 + torsoPitchRangeDown 10 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam neutral + enemyTeam neutral +// race bot + class r2d2 + yawSpeed 120 + runSpeed 150 + walkSpeed 50 + height 40 + width 12 + hFOV 120 + vfov 45 + snd r2d2 +} + +r2d2_imp +{ + playermodel r2d2 + customSkin imp + headYawRangeLeft 180 + headYawRangeRight 180 + headPitchRangeUp 0 + headPitchRangeDown 0 + torsoYawRangeLeft 0 + torsoYawRangeRight 0 + torsoPitchRangeUp 10 + torsoPitchRangeDown 10 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam neutral + enemyTeam neutral +// race bot + class r2d2 + yawSpeed 120 + runSpeed 150 + walkSpeed 50 + height 40 + width 12 + hFOV 120 + vfov 45 + snd r2d2 +} + +r5d2 +{ + playerModel r5d2 + headYawRangeLeft 180 + headYawRangeRight 180 + headPitchRangeUp 0 + headPitchRangeDown 0 + torsoYawRangeLeft 0 + torsoYawRangeRight 0 + torsoPitchRangeUp 10 + torsoPitchRangeDown 10 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam neutral + enemyTeam neutral +// race bot + class r5d2 + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + height 40 + width 12 + hFOV 120 + vfov 45 + snd r5d2 +} + +r5d2_imp +{ + playerModel r5d2 + customSkin imp + headYawRangeLeft 180 + headYawRangeRight 180 + headPitchRangeUp 0 + headPitchRangeDown 0 + torsoYawRangeLeft 0 + torsoYawRangeRight 0 + torsoPitchRangeUp 10 + torsoPitchRangeDown 10 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam neutral + enemyTeam neutral +// race bot + class r5d2 + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + height 40 + width 12 + hFOV 120 + vfov 45 + snd r5d2 +} + +gonk +{ + playerModel gonk + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam neutral + enemyTeam neutral +// race bot + class gonk + yawSpeed 60 + runSpeed 40 + walkSpeed 30 + height 32 + width 12 + hFOV 120 + vfov 45 + snd gonk +} + + +mouse +{ + headmodel none + torsomodel none + legsmodel mouse + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam neutral + enemyTeam neutral +// race bot + class mouse + yawSpeed 120 + runSpeed 500 + walkSpeed 150 + height 16 + width 8 + hFOV 120 + vfov 45 + snd mouse +} + + +seeker +{ + headmodel none + torsomodel none + legsmodel remote + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 3 + intelligence 5 + playerTeam player + enemyTeam enemy +// race bot + class seeker + yawSpeed 120 + runSpeed 500 + walkSpeed 150 + height 32 + width 8 + hFOV 160 + vfov 45 + snd remote + moveType "flyswim" +} + +remote +{ + headmodel none + torsomodel none + legsmodel remote + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 3 + intelligence 5 + playerTeam enemy + enemyTeam player +// race bot + class remote + yawSpeed 120 + runSpeed 500 + walkSpeed 150 + height 32 + width 8 + hFOV 160 + vfov 45 + snd remote + moveType "flyswim" +} + +sentry +{ + playermodel sentry + health 100 + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam enemy + enemyTeam player +// race bot + class sentry + health 150 + yawSpeed 120 + runSpeed 400 + walkSpeed 250 + height 48 + width 24 + hFOV 120 + vfov 160 + snd sentry +} + +interrogator +{ + playermodel interrogator + health 100 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam enemy + enemyTeam player +// race bot + class interrogator + yawSpeed 120 + runSpeed 150 + walkSpeed 50 + height 24 + width 12 + hFOV 120 + vfov 45 + snd interrogator +} + + +probe +{ + playerModel probe + health 200 + headYawRangeLeft 180 + headYawRangeRight 180 + headPitchRangeUp 0 + headPitchRangeDown 0 + torsoYawRangeLeft 0 + torsoYawRangeRight 0 + torsoPitchRangeUp 10 + torsoPitchRangeDown 10 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam enemy + enemyTeam player +// race bot + class probe + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + height 110 + width 24 + hFOV 120 + vfov 45 + snd probe + moveType "flyswim" +} + +mark1 +{ + playerModel mark1 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + height 120 + width 36 + playerTeam enemy + enemyTeam player + health 300 +// race bot + class mark1 + yawSpeed 60 + runSpeed 150 + walkSpeed 70 + hFOV 120 + vfov 45 + snd mark1 +} + +mark2 +{ + playerModel mark2 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam enemy + enemyTeam player +// race bot + class mark2 + yawSpeed 60 + runSpeed 150 + walkSpeed 75 + hFOV 120 + vfov 45 + snd mark2 +} + +atst +{ + playerModel atst +// headModel atst + //torsoModel atst + //legsModel atst + headYawRangeLeft 80 + headYawRangeRight 80 + headPitchRangeUp 30 + headPitchRangeDown 30 + torsoYawRangeLeft 0 + torsoYawRangeRight 0 + torsoPitchRangeUp 0 + torsoPitchRangeDown 0 + health 200 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam enemy + enemyTeam player + height 272 + width 80 +// race bot + class atst + yawSpeed 60 + runSpeed 150 + walkSpeed 150 + hFOV 120 + vfov 45 + snd atst +} + +test +{ + playerModel test + playerTeam player + enemyTeam neutral + class kyle +} diff --git a/code/base/ext_data/dms.dat b/code/base/ext_data/dms.dat new file mode 100644 index 0000000..2aeb179 --- /dev/null +++ b/code/base/ext_data/dms.dat @@ -0,0 +1,1238 @@ +musicfiles +{ + kejimbase_explore + { + entry + { + marker0 0.000 + marker1 22.070 + marker2 53.723 + marker3 90.926 + } + exit + { + nextfile kejimbase_etr00 + time00 3.337 + time01 5.668 + time02 22.040 + time03 29.889 + time04 50.124 + time05 37.168 + time06 53.473 + time07 65.923 + time08 90.478 + time09 143.233 + time10 156.166 + time11 176.608 + time12 193.505 + } + exit + { + nextfile kejimbase_etr01 + time00 45.555 + time01 81.525 + time02 106.406 + time03 128.648 + time04 185.168 + time05 209.309 + } + } + kejimbase_action + { + entry + { + marker0 0.00 + marker1 42.585 + marker2 87.664 + } + exit + { + nextfile kejimbase_atr00 + nextmark marker0 + time00 69.347 + time01 72.142 + time02 80.444 + time03 87.608 + time04 90.185 + } + exit + { + nextfile kejimbase_atr01 + nextmark marker1 + time00 2.434 + time01 5.667 + time02 20.281 + } + exit + { + nextfile kejimbase_atr02 + nextmark marker2 + time00 62.894 + } + exit + { + nextfile kejimbase_atr03 + nextmark marker3 + time00 12.397 + time01 28.679 + time02 35.492 + time03 45.328 + } + } + ImpBaseB_Explore + { + entry + { + marker0 0 + marker1 37 + marker2 69.81 + marker3 119.97 + } + exit + { + nextfile ImpBaseB_Etr00 + time0 37 + time1 54.0 + time2 62.35 + time3 69.81 + time4 79.85 + time5 119.97 + time6 132.75 + time7 146.88 + } + exit + { + nextfile ImpBaseB_Etr01 + time0 13.67 + time1 26.96 + time2 89.42 + time3 96.92 + time4 107.77 + } + + } + ImpBaseB_Action + { + entry + { + marker0 0 + marker1 30.23 + marker2 45.45 + marker3 104.48 + } + exit + { + nextfile ImpBaseB_Atr00 + nextmark marker3 + time0 38.22 + time1 50.31 + time2 59.23 + time3 64.47 + time4 80.41 + time5 87.69 + time6 92.01 + time7 98.07 + time8 104.48 + } + exit + { + nextfile ImpBaseB_Atr01 + nextmark marker2 + time0 8.91 + time1 20.89 + } + exit + { + nextfile ImpBaseB_Atr02 + nextmark marker1 + time0 25.45 + time1 30.23 + } + exit + { + nextfile ImpBaseB_Atr03 + nextmark marker0 + time0 4.97 + time1 11.33 + time2 16.11 + time3 45.45 + time4 70.61 + time5 74.66 + } + } + ImpBaseC_explore + { + entry + { + marker0 0.000 + marker1 55.831 + marker2 11.160 + marker3 11.160 + + } + exit + { + nextfile ImpBaseC_etr00 + time00 42.904 + time01 71.172 + time02 127.721 + time03 150.290 + time04 171.618 + + } + exit + { + nextfile ImpBaseC_etr01 + time00 19.096 + time01 26.412 + time02 88.211 + time03 101.169 + + } + } + ImpBaseC_action + { + entry + { + marker0 0.00 + marker1 19.468 + marker2 33.480 + } + exit + { + nextfile ImpBaseC_atr00 + nextmark marker0 + time00 2.542 + time01 5.440 + time02 9.470 + time03 19.366 + } + exit + { + nextfile ImpBaseC_atr01 + nextmark marker1 + time00 25.544 + time01 29.140 + } + exit + { + nextfile ImpBaseC_atr02 + nextmark marker2 + time00 44.888 + } + exit + { + nextfile ImpBaseC_atr03 + nextmark marker3 + time00 34.272 + time01 65.224 + } + } + BespinA_Explore + { + entry + { + marker0 6.74 + marker1 17.51 + marker2 95.95 + marker3 149.87 + } + exit + { + nextfile BespinA_Etr00 + time00 42.01 + } + exit + { + nextfile BespinA_Etr01 + time00 165.65 + } + exit + { + nextfile BespinA_Etr02 + time00 17.51 + time01 29.50 + time02 54.80 + time03 70.21 + time04 90.25 + time05 106.40 + time06 120.53 + time07 149.87 + time08 178.36 + } + } + BespinA_Action + { + entry + { + marker0 0.00 + marker1 42.585 + marker2 87.664 + } + exit + { + nextfile BespinA_Atr00 + nextmark marker0 + time00 3.08 + time01 6.19 + time02 35.26 + } + exit + { + nextfile BespinA_Atr01 + nextmark marker1 + time00 8.98 + time01 14.76 + time02 20.65 + time03 44.34 + time04 47.28 + } + exit + { + nextfile BespinA_Atr02 + nextmark marker2 + time00 51.82 + time01 58.00 + } + exit + { + nextfile BespinA_Atr03 + nextmark marker3 + time00 28.90 + time01 64.78 + } + } + + besplat_explore + { + entry + { + marker0 46.78 + marker1 69.05 + marker2 85.85 + } + exit + { + nextfile besplat_etr00 + time0 6.89 + time1 21.26 + time3 55.52 + time4 69.75 + time5 85.87 + time6 98.12 + time7 119.44 + time8 131.95 + time9 157.58 + } + exit + { + nextfile besplat_etr01 + time0 34.15 + time1 141.84 + time2 174.72 + time3 183.05 + } + } + + besplat_action + { + entry + { + marker0 0 + marker1 16.56 + marker2 24.86 + marker3 62.37 + } + exit + { + nextfile besplat_atr00 + nextmark marker1 + time0 2.82 + time1 68.46 + } + exit + { + nextfile besplat_atr01 + nextmark marker2 + time0 41.23 + time1 54.20 + time2 59.31 + time3 76.51 + } + exit + { + nextfile besplat_atr02 + nextmark marker0 + time0 13.47 + time1 21.19 + time2 24.65 + time3 28.82 + time4 83.53 + } + } + + besplat_boss + { + } + + yavtrial_explore + { + entry + { + marker0 124.126 + marker1 102.326 + marker2 24.853 + marker3 0.00 + } + exit + { + nextfile yavtrial_etr00 + time00 3.095 + time01 23.931 + time02 24.937 + time03 46.905 + time04 61.268 + time05 79.042 + time06 101.750 + time07 118.136 + time08 147.951 + } + exit + { + nextfile yavtrial_etr01 + time00 161.783 + } + } + yavtrial_action + { + entry + { + marker0 0.00 + marker1 60.145 + marker2 85.922 + } + exit + { + nextfile yavtrial_atr00 + nextmark marker0 + time00 3.553 + time01 6.118 + time02 8.718 + time03 41.152 + time04 103.559 + } + exit + { + nextfile yavtrial_atr01 + nextmark marker1 + time00 9.307 + time01 12.310 + time02 16.719 + time03 20.045 + time04 26.229 + time05 35.160 + } + exit + { + nextfile yavtrial_atr02 + nextmark marker2 + time00 59.302 + time01 65.837 + time02 74.429 + } + exit + { + nextfile yavtrial_atr03 + nextmark marker3 + time00 38.325 + time01 49.857 + } + } + alienha_explore + { + entry + { + marker0 0 + marker1 65.84 + marker2 93.63 + } + exit + { + nextfile alienha_etr00 + time0 5.80 + time1 33.04 + time3 67.61 + } + exit + { + nextfile alienha_etr01 + time0 94.47 + time1 103.06 + time2 115.75 + time3 127.32 + time4 138.36 + time5 152.10 + time6 166.11 + time7 180.29 + } + } + alienha_action + { + entry + { + marker0 0 + marker1 40.96 + marker2 63.33 + } + exit + { + nextfile alienha_atr00 + nextmark marker2 + time0 3.35 + time1 6.85 + time3 15.70 + time4 22.61 + } + exit + { + nextfile alienha_atr01 + nextmark marker0 + time0 31.85 + time1 41.42 + time2 47.06 + } + exit + { + nextfile alienha_atr03 + nextmark marker1 + time0 53.01 + time1 58.57 + time2 62.87 + time3 72.03 + time4 89.64 + time5 96.94 + } + } + tunnels_explore + { + entry + { + marker0 0 + marker1 64.20 + marker2 96.47 + } + exit + { + nextfile tunnels_etr00 + time0 6.06 + time1 18.26 + time3 35.01 + time4 42.98 + time5 69.73 + time6 84.16 + } + exit + { + nextfile tunnels_etr01 + time0 94.81 + time1 111.25 + time2 121.77 + time3 134.68 + } + } + tunnels_action + { + entry + { + marker0 0 + marker1 22.39 + } + exit + { + nextfile tunnels_atr00 + nextmark marker0 + time0 0.29 + } + exit + { + nextfile tunnels_atr01 + nextmark marker2 + time0 15.62 + time1 22.94 + } + exit + { + nextfile tunnels_atr02 + nextmark marker2 + time0 29.14 + time1 35.63 + time2 45.33 + time3 51.78 + time4 58.67 + } + exit + { + nextfile tunnels_atr03 + nextmark marker1 + time0 64.81 + time1 68.53 + time2 72.28 + time3 75.89 + } + } + IMPBaseD_explore + { + entry + { + marker0 0.000 + marker1 66.790 + marker2 102.874 + marker3 150.554 + } + exit + { + nextfile IMPBaseD_etr00 + time00 7.997 + time01 16.678 + time02 44.664 + time03 70.836 + + } + exit + { + nextfile IMPBaseD_etr01 + time00 89.986 + time01 111.971 + time02 130.629 + time03 166.389 + time04 172.530 + } + } + IMPBaseD_action + { + entry + { + marker0 6.607 + marker1 60.118 + marker2 140.053 + } + exit + { + nextfile IMPBaseD_atr00 + nextmark marker0 + time00 6.457 + time01 13.265 + time02 18.757 + time03 25.194 + time04 152.772 + } + exit + { + nextfile IMPBaseD_atr01 + nextmark marker1 + time00 30.336 + time01 37.883 + time02 46.802 + time03 61.122 + } + exit + { + nextfile IMPBaseD_atr02 + nextmark marker2 + time00 78.257 + time01 85.312 + time02 92.170 + time03 140.866 + time04 149.597 + } + exit + { + nextfile IMPBaseD_atr03 + nextmark marker3 + time00 105.982 + time01 115.569 + time02 128.476 + } + } + swamp_explore + { + entry + { + marker0 0.000 + marker1 16.916 + marker2 80.714 + marker3 31.761 + + } + exit + { + nextfile swamp_etr00 + time00 11.185 + time01 20.989 + time02 51.408 + time03 63.196 + time04 71.293 + + } + exit + { + nextfile swamp_etr01 + time00 42.044 + time01 78.362 + time02 95.485 + time03 113.023 + + } + } + swamp_action + { + entry + { + marker0 0.00 + marker1 36.318 + marker2 45.982 + } + exit + { + nextfile swamp_atr00 + nextmark marker0 + time00 1.035 + } + exit + { + nextfile swamp_atr01 + nextmark marker1 + time00 6.835 + time01 11.323 + time02 18.592 + time03 36.230 + time04 59.793 + } + exit + { + nextfile swamp_atr02 + nextmark marker2 + time00 34.108 + time01 79.955 + time02 89.847 + time03 126.994 + + } + exit + { + nextfile swamp_atr03 + nextmark marker3 + time00 102.414 + time01 115.382 + time02 120.039 + } + } + yavtemp2_explore + { + entry + { + marker0 88.28 + marker1 48.10 + marker2 117.47 + marker3 0 + } + exit + { + nextfile yavtemp2_etr00 + time0 46.23 + time1 53.44 + time2 62.08 + time3 69.09 + time4 77.08 + time5 87.03 + time6 96.49 + } + exit + { + nextfile yavtemp2_etr01 + time0 15.24 + time1 31.79 + time2 42.78 + time3 114.18 + time4 134.25 + time5 144.89 + time6 160.03 + time7 168.03 + } + } + yavtemp2_action + { + entry + { + marker0 0 + marker1 17.35 + marker2 43.31 + marker3 60.39 + } + exit + { + nextfile yavtemp2_atr00 + nextmark marker0 + time0 0 + time1 8.78 + time2 13.47 + } + exit + { + nextfile yavtemp2_atr01 + nextmark marker1 + time0 23.89 + time1 28.62 + time2 41.11 + time3 46.73 + } + exit + { + nextfile yavtemp2_atr02 + nextmark marker2 + time0 48.95 + time1 60.59 + time2 69.13 + time3 97.63 + } + exit + { + nextfile yavtemp2_atr03 + nextmark marker3 + time0 91.11 + } + } + ImpBaseE_explore + { + entry + { + marker0 0.000 + marker1 13.805 + marker2 29.265 + marker3 137.915 + + } + exit + { + nextfile ImpBaseE_etr00 + time00 13.712 + time01 37.872 + time02 52.541 + time03 131.875 + time04 232.256 + + } + exit + { + nextfile ImpBaseE_etr01 + time00 120.057 + time01 157.080 + time02 176.388 + + } + } + ImpBaseE_action + { + entry + { + marker0 0.00 + marker1 18.336 + marker2 52.491 + } + exit + { + nextfile ImpBaseE_atr00 + nextmark marker0 + time00 22.012 + time01 32.861 + time02 73.853 + time03 77.808 + } + exit + { + nextfile ImpBaseE_atr01 + nextmark marker1 + time00 5.824 + time01 18.457 + time02 81.088 + time03 114.805 + } + exit + { + nextfile ImpBaseE_atr02 + nextmark marker2 + time00 1.923 + time01 26.892 + time02 30.703 + time03 59.294 + time04 65.331 + time05 88.803 + time06 91.876 + + } + exit + { + nextfile ImpBaseE_atr03 + nextmark marker3 + time00 11.958 + time01 43.027 + time02 48.014 + time04 96.757 + time05 107.858 + time06 130.437 + } + } + alienhb_explore + { + entry + { + marker0 127.71 + marker1 36.56 + marker2 89.94 + } + exit + { + nextfile alienhb_etr00 + time0 13.60 + time1 22.58 + time3 31.69 + time4 41.08 + time5 53.08 + time6 67.91 + time7 89.29 + time8 181.41 + } + exit + { + nextfile alienhb_etr01 + time0 109.08 + time1 123.18 + time2 134.76 + time3 149.54 + time4 160.53 + time5 174.10 + } + } + alienhb_action + { + entry + { + marker0 0 + marker1 6.85 + marker2 31.84 + marker3 66.77 + } + exit + { + nextfile alienhb_atr00 + nextmark marker0 + time0 5.29 + time1 21.54 + time3 26.21 + time4 120.30 + } + exit + { + nextfile alienhb_atr01 + nextmark marker1 + time0 10.35 + time1 17.03 + } + exit + { + nextfile alienhb_atr02 + nextmark marker2 + time0 60.27 + time1 70.21 + time2 80.36 + time3 93.55 + time4 100.47 + time5 111.75 + } + } + yavfinal_explore + { + entry + { + marker0 0.000 + marker1 18.664 + marker2 53.390 + marker3 97.161 + + } + exit + { + nextfile yavfinal_etr00 + time00 53.434 + time01 83.935 + + } + exit + { + nextfile yavfinal_etr01 + time00 9.852 + time01 94.171 + time02 104.106 + + } + } + yavfinal_action + { + entry + { + marker0 0.00 + marker1 43.094 + marker2 73.785 + } + exit + { + nextfile yavfinal_atr00 + nextmark marker0 + time00 53.502 + time01 61.386 + } + exit + { + nextfile yavfinal_atr01 + nextmark marker1 + time00 3.623 + time01 96.341 + } + exit + { + nextfile yavfinal_atr02 + nextmark marker2 + time00 9.019 + time01 11.707 + time02 15.535 + time03 29.107 + time04 35.847 + time05 75.327 + time06 101.992 + + } + exit + { + nextfile yavfinal_atr03 + nextmark marker3 + time00 21.257 + time01 25.167 + time02 43.800 + time03 106.249 + time04 113.638 + + } + } + yavfinal_boss + { + } + narshaada_explore + { + entry + { + marker0 123.18 + marker1 0 + marker2 43.30 + marker3 12.27 + } + exit + { + nextfile narshaada_etr00 + time0 55.86 + time1 70.17 + time2 78.63 + time3 88.61 + time4 106.57 + + } + exit + { + nextfile narshaada_etr01 + time0 13.75 + time1 31.29 + time2 43.84 + time4 123.91 + time5 134.92 + time6 149.29 + time7 168.16 + time8 184.19 + } + } + narshaada_action + { + entry + { + marker0 0 + marker1 15.65 + marker2 47.07 + } + exit + { + nextfile narshaada_atr00 + nextmark marker0 + time0 2.72 + time1 59.84 + time2 63.90 + time3 74.16 + time4 82.37 + } + exit + { + nextfile narshaada_atr01 + nextmark marker1 + time0 10.89 + time1 20.59 + time2 28.15 + time3 39.65 + time4 46.35 + } + exit + { + nextfile narshaada_atr02 + nextmark marker2 + time0 48.98 + time1 69.05 + } + exit + { + nextfile narshaada_atr03 + nextmark marker3 + time0 86.14 + time1 90.73 + time2 96.40 + time3 101.09 + } + } + +} +levelmusic +{ + kejim_post + { + explore ImpBaseB_Explore + action ImpBaseB_Action + } + kejim_base + { + explore kejimbase_explore + action kejimbase_action + } + artus_mine + { + explore tunnels_explore + action tunnels_action + } + artus_detention + { + explore ImpBaseC_explore + action ImpBaseC_action + useboss bespin_platform + } + artus_topside + { + explore ImpBaseD_explore + action ImpBaseD_action + } + ns_streets + { + explore narshaada_explore + action narshaada_action + } + ns_hideout + { + explore alienha_explore + action alienha_action + } + ns_starpad + { + explore alienhb_explore + action alienhb_action + } + bespin_undercity + { + uses artus_mine + } + bespin_streets + { + explore BespinA_Explore + action BespinA_Action + } + bespin_platform + { + explore besplat_explore + action besplat_action + boss besplat_boss + } + cairn_bay + { + explore ImpBaseE_explore + action ImpBaseE_action + } + cairn_dock1 + { + uses kejim_base + } + cairn_assembly + { + uses kejim_post + } + cairn_stockpile + { + uses artus_detention + } + cairn_reactor + { + uses artus_topside + } + cairn_dock2 + { + uses cairn_bay + } + demo + { + uses kejim_post + useboss bespin_platform + } + doom_comm + { + uses kejim_base + } + doom_detention + { + uses kejim_post + } + doom_shields + { + uses artus_detention + } + yavin_swamp + { + explore swamp_explore + action swamp_action + } + yavin_canyon + { + uses ns_hideout + } + yavin_courtyard + { + explore yavtemp2_explore + action yavtemp2_action + } + yavin_final + { + explore yavfinal_explore + action yavfinal_action + boss yavfinal_boss + } + yavin_temple + { + explore placeholder + action placeholder + } + yavin_trial + { + explore yavtrial_explore + action yavtrial_action + } +} diff --git a/code/base/ext_data/items.dat b/code/base/ext_data/items.dat new file mode 100644 index 0000000..537abb4 --- /dev/null +++ b/code/base/ext_data/items.dat @@ -0,0 +1,712 @@ +// EXTERNAL ITEM DATA +// + +//Fields +//pickupsound STRING; DEFAULT = sound/weapons/w_pkup.wav +//itemname STRING; +//classname STRING; +//count INT; ammount of ammo or health given with item +//icon STRING; +//min VECTOR; item bounds min, DEFAULT = -16 -16 -2 +//max VECTOR; item bounds max, DEFAULT = 16 16 16 +//pickupname STRING; name to show in inventory +//tag ENUM; WP_, or AMMO_ +//type ENUM; IT_WEAPON, IT_AMMO, IT_ARMOR, IT_HEALTH +//worldmodel STRING; model to show on ground or in hand + +{ +itemname ITM_SABER_PICKUP + +classname weapon_saber +worldmodel models/weapons2/saber/saber_w.md3 +icon gfx/hud/w_icon_lightsaber +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_SABER +min -16 -16 -8 +max 16 16 16 +} + + +{ +itemname ITM_BRYAR_PISTOL_PICKUP + +classname weapon_bryar_pistol +worldmodel models/weapons2/briar_pistol/briar_pistol_w.glm +icon gfx/hud/w_icon_briar +// Amount of ammo given with weapon +count 10 +type IT_WEAPON +tag WP_BRYAR_PISTOL +min -10 -10 -2 +max 10 10 12 +} + + +{ +itemname ITM_BLASTER_PICKUP + +classname weapon_blaster +worldmodel models/weapons2/blaster_r/blaster_w.glm +icon gfx/hud/w_icon_blaster +// Amount of ammo given with weapon +count 10 +type IT_WEAPON +tag WP_BLASTER +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_DISRUPTOR_PICKUP + +classname weapon_disruptor +worldmodel models/weapons2/disruptor/disruptor_w.glm +icon gfx/hud/w_icon_disruptor +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_DISRUPTOR +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_BOWCASTER_PICKUP + +classname weapon_bowcaster +worldmodel models/weapons2/bowcaster/bowcaster_w.glm +icon gfx/hud/w_icon_bowcaster +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_BOWCASTER +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_REPEATER_PICKUP + +classname weapon_repeater +worldmodel models/weapons2/heavy_repeater/heavy_repeater_w.glm +icon gfx/hud/w_icon_repeater +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_REPEATER +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_DEMP2_PICKUP + +classname weapon_demp2 +worldmodel models/weapons2/demp2/demp2_w.glm +icon gfx/hud/w_icon_demp2 +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_DEMP2 +min -10 -10 -2 +max 10 10 12 +} + + +{ +itemname ITM_FLECHETTE_PICKUP + +classname weapon_flechette +worldmodel models/weapons2/golan_arms/golan_arms_w.glm +icon gfx/hud/w_icon_flechette +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_FLECHETTE +min -10 -10 -2 +max 10 10 12 +} + + +{ +itemname ITM_ROCKET_LAUNCHER_PICKUP + +classname weapon_rocket_launcher +worldmodel models/weapons2/merr_sonn/merr_sonn_w.glm +icon gfx/hud/w_icon_merrsonn +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_ROCKET_LAUNCHER +min -10 -10 -2 +max 10 10 12 +} + + +{ +itemname ITM_THERMAL_DET_PICKUP + +classname weapon_thermal +worldmodel models/weapons2/thermal/thermal_w.glm +icon gfx/hud/w_icon_thermal +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_THERMAL +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_TRIP_MINE_PICKUP + +classname weapon_trip_mine +worldmodel models/weapons2/laser_trap/laser_trap_w.glm +icon gfx/hud/w_icon_tripmine +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_TRIP_MINE +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_DET_PACK_PICKUP + +classname weapon_det_pack +worldmodel models/weapons2/detpack/det_pack_w.glm +icon gfx/hud/w_icon_detpack +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_DET_PACK +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_STUN_BATON_PICKUP + +classname weapon_stun_baton +worldmodel models/weapons2/stun_baton/stunbaton_w.glm +icon gfx/hud/w_icon_stunbaton +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_STUN_BATON +} + + +{ +itemname ITM_BOT_LASER_PICKUP + +classname weapon_botwelder +worldmodel models/weapons2/noweap/noweap.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_BOT_LASER +} + +{ +itemname ITM_MELEE + +classname weapon_melee +worldmodel models/weapons2/noweap/noweap.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_MELEE +min -16 -16 -2 +max 16 16 16 +} + +{ +itemname ITM_EMPLACED_GUN_PICKUP + +classname weapon_emplaced_gun +worldmodel models/weapons2/noweap/noweap.md3 +// Amount of ammo given with weapon +count 800 +type IT_WEAPON +tag WP_EMPLACED_GUN +} + +{ +itemname ITM_TURRET_PICKUP + +classname weapon_turret +worldmodel models/weapons2/noweap/noweap.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_TURRET +} + +{ +itemname ITM_ATST_MAIN_PICKUP + +classname weapon_atst_main +worldmodel models/weapons2/noweap/noweap.md3 +icon gfx/hud/w_icon_atst +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_ATST_MAIN +} + +{ +itemname ITM_ATST_SIDE_PICKUP + +classname weapon_atst_side +worldmodel models/weapons2/noweap/noweap.md3 +icon gfx/hud/w_icon_atstside +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_ATST_SIDE +} + +{ +itemname ITM_TIE_FIGHTER_PICKUP + +classname weapon_tie_fighter +worldmodel models/weapons2/noweap/noweap.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_TIE_FIGHTER +} + +{ +itemname ITM_RAPID_FIRE_CONC_PICKUP + +classname weapon_rapid_concussion +worldmodel models/weapons2/noweap/noweap.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_RAPID_FIRE_CONC +} + +{ +itemname ITM_BLASTER_PISTOL_PICKUP + +classname weapon_blaster_pistol +worldmodel models/weapons2/imp_pistol/pistol_w.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_BLASTER_PISTOL +} + +// +//Items +// + +// AMMO Items +//------------- +{ +itemname ITM_AMMO_FORCE_PICKUP + +classname ammo_force +worldmodel models/items/forcegem.md3 +pickupsound sound/player/enlightenment.wav +icon gfx/hud/forcegem_icon2 +count 100 +type IT_AMMO +tag AMMO_FORCE +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_AMMO_BLASTER_PICKUP + +classname ammo_blaster +worldmodel models/items/energy_cell.md3 +icon gfx/hud/energy_cell +count 25 +type IT_AMMO +tag AMMO_BLASTER +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_AMMO_POWERCELL_PICKUP + +classname ammo_powercell +worldmodel models/items/power_cell.md3 +icon gfx/hud/power_cell +count 100 +type IT_AMMO +tag AMMO_POWERCELL +max 8 8 16 +min -8 -8 -0 +} + + +{ +itemname ITM_AMMO_METAL_BOLTS_PICKUP + +classname ammo_metallic_bolts +worldmodel models/items/metallic_bolts.md3 +icon gfx/hud/metallic_bolts +count 100 +type IT_AMMO +tag AMMO_METAL_BOLTS +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_AMMO_ROCKETS_PICKUP + +classname ammo_rockets +worldmodel models/items/rockets.md3 +icon gfx/hud/rockets +count 3 +type IT_AMMO +tag AMMO_ROCKETS +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_AMMO_EMPLACED_PICKUP + +classname ammo_emplaced +worldmodel models/weapons2/noweap/noweap.md3 +count 100 +type IT_AMMO +tag AMMO_EMPLACED +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_AMMO_THERMAL_PICKUP + +classname ammo_thermal +worldmodel models/weapons2/thermal/thermal_pu.md3 +icon gfx/hud/w_icon_thermal +count 4 +type IT_AMMO +tag AMMO_THERMAL +max 16 16 16 +min -16 -16 -0 +} + +{ +itemname ITM_AMMO_TRIPMINE_PICKUP + +classname ammo_tripmine +worldmodel models/weapons2/laser_trap/laser_trap_pu.md3 +icon gfx/hud/w_icon_tripmine +count 3 +type IT_AMMO +tag AMMO_TRIPMINE +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_AMMO_DETPACK_PICKUP + +classname ammo_detpack +worldmodel models/weapons2/detpack/det_pack_pu.md3 +icon gfx/hud/w_icon_detpack +count 3 +type IT_AMMO +tag AMMO_DETPACK +max 8 8 16 +min -8 -8 -0 +} + + + +{ +itemname ITM_BATTERY_PICKUP + +classname item_battery +worldmodel models/items/battery.md3 +icon gfx/hud/battery +count 1000 +type IT_BATTERY +tag ITM_BATTERY_PICKUP +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_SEEKER_PICKUP +classname item_seeker +worldmodel models/items/remote.md3 +icon gfx/hud/i_icon_seeker +count 120 +type IT_HOLDABLE +tag INV_SEEKER +max 8 8 16 +min -8 -8 -4 +} + +{ +itemname ITM_SHIELD_PICKUP +classname item_enviro +worldmodel models/items/shield.md3 +icon gfx/hud/i_icon_shieldwall +count 100 +type IT_HOLDABLE +tag ITM_SHIELD_PICKUP +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_BACTA_PICKUP +classname item_bacta +worldmodel models/items/bacta.md3 +icon gfx/hud/i_icon_bacta +count 25 +type IT_HOLDABLE +tag INV_BACTA_CANISTER +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_DATAPAD_PICKUP +classname item_datapad +worldmodel models/items/datapad.md3 +count 1 +type IT_HOLDABLE +tag ITM_DATAPAD_PICKUP +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_BINOCULARS_PICKUP +classname item_binoculars +worldmodel models/items/binoculars.md3 +icon gfx/hud/i_icon_zoom +count 1 +type IT_HOLDABLE +tag INV_ELECTROBINOCULARS +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_SENTRY_GUN_PICKUP +classname item_sentry_gun +worldmodel models/items/psgun.glm +icon gfx/hud/i_icon_sentrygun +count 120 +type IT_HOLDABLE +tag INV_SENTRY +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_LA_GOGGLES_PICKUP +classname item_la_goggles +worldmodel models/items/binoculars.md3 +icon gfx/hud/i_icon_goggles +count 30 +type IT_HOLDABLE +tag INV_LIGHTAMP_GOGGLES +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_MEDPAK_PICKUP +classname item_medpak_instant +worldmodel models/items/medpac.md3 +icon gfx/hud/i_icon_medkit +count 20 +type IT_HEALTH +tag ITM_MEDPAK_PICKUP +max 8 8 16 +min -8 -8 -4 +} + +{ +itemname ITM_SHIELD_SM_PICKUP +classname item_shield_sm_instant +worldmodel models/items/psd_sm.md3 +icon gfx/hud/psd_small +count 25 +type IT_ARMOR +tag ITM_SHIELD_SM_PICKUP +max 8 8 16 +min -8 -8 -4 +} + +{ +itemname ITM_SHIELD_LRG_PICKUP +classname item_shield_lrg_instant +worldmodel models/items/psd.md3 +icon gfx/hud/psd_medium +count 50 +type IT_ARMOR +tag ITM_SHIELD_LRG_PICKUP +max 8 8 16 +min -8 -8 -4 +} + + +{ +itemname ITM_GOODIE_KEY_PICKUP +classname item_goodie_key +worldmodel models/items/key.md3 +icon gfx/hud/i_icon_goodie_key +type IT_HOLDABLE +tag INV_GOODIE_KEY +max 8 8 16 +min -8 -8 -0 +} + + +{ +itemname ITM_SECURITY_KEY_PICKUP +classname item_security_key +worldmodel models/items/key.md3 +icon gfx/hud/i_icon_security_key +type IT_HOLDABLE +tag INV_SECURITY_KEY +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_HEAL_PICKUP + +classname holocron_force_heal +worldmodel models/map_objects/force_holocrons/heal.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_heal +count 1 +type IT_HOLOCRON +tag FP_HEAL +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_LEVITATION_PICKUP + +classname holocron_force_levitation +worldmodel models/map_objects/force_holocrons/jump.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_levitation +count 1 +type IT_HOLOCRON +tag FP_LEVITATION +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_SPEED_PICKUP + +classname holocron_force_speed +worldmodel models/map_objects/force_holocrons/speed.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_speed +count 1 +type IT_HOLOCRON +tag FP_SPEED +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_PUSH_PICKUP + +classname holocron_force_push +worldmodel models/map_objects/force_holocrons/push.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_push +count 1 +type IT_HOLOCRON +tag FP_PUSH +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_PULL_PICKUP + +classname holocron_force_pull +worldmodel models/map_objects/force_holocrons/pull.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_pull +count 1 +type IT_HOLOCRON +tag FP_PULL +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_TELEPATHY_PICKUP + +classname holocron_force_telepathy +worldmodel models/map_objects/force_holocrons/telepathy.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_telepathy +count 1 +type IT_HOLOCRON +tag FP_TELEPATHY +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_GRIP_PICKUP + +classname holocron_force_grip +worldmodel models/map_objects/force_holocrons/grip.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_grip +count 1 +type IT_HOLOCRON +tag FP_GRIP +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_LIGHTNING_PICKUP + +classname holocron_force_lightning +worldmodel models/map_objects/force_holocrons/lightning.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_lightning +count 1 +type IT_HOLOCRON +tag FP_LIGHTNING +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_SABERTHROW_PICKUP + +classname holocron_force_saberthrow +worldmodel models/map_objects/force_holocrons/saberthrow.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_saberthrow +count 1 +type IT_HOLOCRON +tag FP_SABERTHROW +max 8 8 16 +min -8 -8 -0 +} diff --git a/code/base/ext_data/vssver.scc b/code/base/ext_data/vssver.scc new file mode 100644 index 0000000..4fc4fca Binary files /dev/null and b/code/base/ext_data/vssver.scc differ diff --git a/code/base/ext_data/weapons.dat b/code/base/ext_data/weapons.dat new file mode 100644 index 0000000..e6d7975 --- /dev/null +++ b/code/base/ext_data/weapons.dat @@ -0,0 +1,610 @@ +// EXTERNAL WEAPON & AMMO DATA +// +// NOTE!!!!!!!!! Weapontype must start the block of weapon data. +// NOTE!!!!!!!!! Ammo must start the block of ammo data. +// +// Weapontype - weapon data is associated with which weapon (must be first) +// WP_NONE +// WP_PHASER +// WP_COMPRESSION_RIFLE +// WP_IMOD +// WP_SCAVENGER_RIFLE +// WP_STASIS +// WP_GRENADE_LAUNCHER, +// WP_TETRION_DISRUPTOR, +// WP_DREADNOUGHT, +// WP_QUANTUM_BURST, +// WP_BORG_WEAPON +// WP_BORG_TASER +// WP_BORG_ASSIMILATOR +// WP_BORG_DRILL +// WP_TRICORDER +// +// Weaponclass - weapon name +// Weaponmodel - weapon model used in game +// weaponicon - interface image +// Ammotype - type of power weapon needs to fire +// 0 - No power +// 1 - Star Fleet power +// 2 - Alien Crystal power +// 3 - Phaser power +// Ammolowcount - amount when "Low ammo" warning appears on screen +// Flashcolor - color generate by weapon flash (R,G,B) +// Firingsound - sound file used when firing +// altfiringsound - sound file used when alt-firing +// flashsound - sound file used by flash +// altflashsound - sound file used by an alt-fire flash +// stopsound - sound file used when a firing sound stops +// Firetime - amount of time between firings +// altfireTime - for alt fire +// Range - range of weapon +// energyPerShot - amount of energy used per shot +// altenergypershot- for alt fire +// barrelcount - number of barrels the model has (weaponname_b?.md3) +// missileModel - missile .md3 +// altmissileModel - alternate missile .md3 +// missileSound - played while flying +// altmissileSound - alternate missile launch sound +// missileLight - intensity of lightsource for missile - if 0.0 then none (float) +// altmissileLight - alternate missile light +// missileLightColor - color in three float style R, G, B (0.0 to 1.0) - NOTE - if you have a light, you MUST HAVE THESE +// altmissileLightColor - alternate color in three float style R, G, B (0.0 to 1.0) +// missileHitSound - played on impact +// altmissileHitSound - for alt fire +// missileFuncName - missile fly function +// altmissileFuncName - for alt fire +// +// FUNCTION NAMES +// borgfunc +// scavengerfunc +// altscavengerfunc +// stasisfunc +// grenadefunc +// altgrenadefunc +// tetrionfunc +// dreadnoughtfunc +// quantumfunc +// quantumaltfunc +// botrocketfunc +// forgeprojfunc +// forgeprojfunc2 +// forgepsychfunc +// parasiteacidfunc +// stasisattackfunc +// loaderlaserfunc +// botprojfunc + +// +// For AMMO Types +// ammoicon - STRING +// ammomax - INT + + +// WP_NULL +{ +WEAPONTYPE WP_NONE +} + +// WP_STUN_BATON +{ +weapontype WP_STUN_BATON +weaponclass weapon_stun_baton +weaponmodel models/weapons2/stun_baton/baton.md3 +weaponIcon gfx/hud/w_icon_stunbaton +firingsound sound/weapons/baton/idle.wav +barrelcount 3 +ammotype 1 +ammolowcount 5 +energypershot 0 +firetime 400 +range 8192 +altenergypershot 0 +altfiretime 400 +altrange 8192 +} + +// WP_SABER +{ +weapontype WP_SABER +weaponclass weapon_saber +weaponmodel models/weapons2/saber/saber_w.md3 +weaponIcon gfx/hud/w_icon_lightsaber +firingsound sound/weapons/saber/saberhum1.wav +ammotype 1 +ammolowcount 5 +energypershot 1 +firetime 100 +range 8192 +altenergypershot 3 +altfiretime 100 +altrange 8192 +missilemodel models/weapons2/saber/saber_w.md3 +} + + +// WP_BRYAR_PISTOL +{ +weapontype WP_BRYAR_PISTOL +weaponclass weapon_bryar_pistol +weaponmodel models/weapons2/briar_pistol/briar_pistol.md3 +weaponIcon gfx/hud/w_icon_briar +missileFuncName bryar_func +altmissileFuncName bryar_alt_func +ammotype 2 +ammolowcount 15 +energypershot 1 +firetime 400 +range 8192 +altenergypershot 1 +altfiretime 400 +altrange 8192 +muzzleEffect bryar/muzzle_flash +altmuzzleEffect bryar/altmuzzle_flash +altchargesound sound/weapons/bryar/altcharge.wav +selectSound sound/weapons/bryar/select.wav +} + +// WP_BLASTER +{ +weapontype WP_BLASTER +weaponclass weapon_blaster +weaponmodel models/weapons2/blaster_r/blaster.md3 +weaponIcon gfx/hud/w_icon_blaster +ammotype 2 +ammolowcount 15 +energypershot 1 +firetime 350 +range 8192 +altenergypershot 2 +altfiretime 150 +altrange 8192 +missileFuncName blaster_func +altmissileFuncName blaster_alt_func +muzzleEffect blaster/muzzle_flash +altmuzzleEffect blaster/altmuzzle_flash +selectSound sound/weapons/blaster/select.wav +} + +// WP_DISRUPTOR +{ +weapontype WP_DISRUPTOR +weaponclass weapon_disruptor +weaponmodel models/weapons2/disruptor/disruptor.md3 +weaponIcon gfx/hud/w_icon_disruptor +ammotype 3 +ammolowcount 15 +energypershot 3 +barrelcount 1 +firetime 600 +range 8192 +altenergypershot 3 +altfiretime 1300 +altrange 8192 +muzzleEffect disruptor/muzzle_flash +altmuzzleEffect disruptor/altmuzzle_flash +selectSound sound/weapons/disruptor/select.wav +altchargesound sound/weapons/disruptor/altCharge.wav +} + +// WP_BOWCASTER +{ +weapontype WP_BOWCASTER +weaponclass weapon_bowcaster +weaponmodel models/weapons2/bowcaster/bowcaster.md3 +weaponIcon gfx/hud/w_icon_bowcaster +altchargesound sound/weapons/bowcaster/altcharge.wav +ammotype 3 +ammolowcount 15 +energypershot 5 +firetime 750 +range 8192 +altenergypershot 5 +altfiretime 400 +altrange 8192 +missileFuncName bowcaster_func +altmissileFuncName bowcaster_func +muzzleEffect bowcaster/muzzle_flash +altmuzzleEffect bowcaster/altmuzzle_flash +selectSound sound/weapons/bowcaster/select.wav +chargesound sound/weapons/bowcaster/altcharge.wav +} + +// WP_REPEATER +{ +weapontype WP_REPEATER +weaponclass weapon_repeater +weaponmodel models/weapons2/heavy_repeater/heavy_repeater.md3 +weaponIcon gfx/hud/w_icon_repeater +ammotype 4 +ammolowcount 25 +energypershot 1 +firetime 50 +range 8192 +altenergypershot 8 +altfiretime 800 +altrange 8192 +barrelcount 1 +missileFuncName repeater_func +altmissileFuncName repeater_alt_func +muzzleEffect repeater/muzzle_flash +altmuzzleEffect repeater/altmuzzle_flash +selectSound sound/weapons/repeater/select.wav +} + +// WP_DEMP2 +{ +weapontype WP_DEMP2 +weaponclass weapon_demp2 +weaponmodel models/weapons2/demp2/demp2.md3 +weaponIcon gfx/hud/w_icon_demp2 +ammotype 3 +ammolowcount 15 +energypershot 8 +firetime 450 +range 8192 +altenergypershot 10 +altfiretime 1200 +altrange 8192 +missileFuncName demp2_func +muzzleEffect demp2/muzzle_flash +altmissileFuncName demp2_alt_func +altmuzzleEffect demp2/altmuzzle_flash +selectSound sound/weapons/demp2/select.wav +altchargesound sound/weapons/demp2/altCharge.wav +} + + +// WP_FLECHETTE +{ +weapontype WP_FLECHETTE +weaponclass weapon_flechette +weaponmodel models/weapons2/golan_arms/golan_arms.md3 +barrelcount 1 +ammotype 4 +ammolowcount 15 +firetime 550 +energypershot 8 +range 8192 +weaponIcon gfx/hud/w_icon_flechette +altenergypershot 8 +altfiretime 400 +altrange 8192 +missileFuncName flechette_func +missileModel models/weapons2/golan_arms/projectileMain.md3 +altmissileFuncName flechette_alt_func +muzzleEffect flechette/muzzle_flash +altmuzzleEffect flechette/altmuzzle_flash +altmissileModel models/weapons2/golan_arms/projectile.md3 +selectSound sound/weapons/flechette/select.wav +} + +// WP_ROCKET_LAUNCHER +{ +weapontype WP_ROCKET_LAUNCHER +weaponclass weapon_rocket_launcher +weaponmodel models/weapons2/merr_sonn/merr_sonn.md3 +ammotype 5 +ammolowcount 1 +firetime 600 +energypershot 1 +range 8192 +weaponIcon gfx/hud/w_icon_merrsonn +barrelcount 1 +altenergypershot 1 +altfiretime 1000 +altrange 8192 +missileLight 125 +missileLightColor 1.0 1.0 0.5 +altmissileLight 125 +altmissileLightColor 1.0 1.0 0.5 +missileFuncName rocket_func +altmissileFuncName rocket_alt_func +muzzleEffect rocket/muzzle_flash2 +altmuzzleEffect rocket/altmuzzle_flash +missileModel models/weapons2/merr_sonn/projectile.md3 +altmissileModel models/weapons2/merr_sonn/projectile.md3 +missilesound sound/weapons/rocket/missleloop.wav +altmissilesound sound/weapons/rocket/missleloop.wav +selectSound sound/weapons/rocket/select.wav +} + + +// WP_THERMAL +{ +weapontype WP_THERMAL +weaponclass weapon_thermal +weaponmodel models/weapons2/thermal/thermal.md3 +weaponIcon gfx/hud/w_icon_thermal +ammotype 7 +ammolowcount 1 +energypershot 1 +firetime 800 +range 8192 +altenergypershot 1 +altfiretime 400 +altrange 8192 +missileModel models/weapons2/thermal/thermal_proj.md3 +altmissileModel models/weapons2/thermal/thermal_proj.md3 +barrelcount 0 +chargesound sound/weapons/thermal/charge.wav +altchargesound sound/weapons/thermal/charge.wav +selectSound sound/weapons/thermal/select.wav +muzzleEffect thermal/muzzle_flash +} + +// WP_TRIP_MINE +{ +weapontype WP_TRIP_MINE +weaponclass weapon_trip_mine +weaponmodel models/weapons2/laser_trap/laser_trap.md3 +weaponIcon gfx/hud/w_icon_tripmine +ammotype 8 +ammolowcount 1 +energypershot 1 +firetime 800 +range 8192 +altenergypershot 1 +altfiretime 400 +altrange 8192 +missileModel models/weapons2/laser_trap/laser_trap_w.glm +altmissileModel models/weapons2/laser_trap/laser_trap_w.glm +selectSound sound/weapons/detpack/select.wav +muzzleEffect tripmine/muzzle_flash + +} + +// WP_DET_PACK +{ +weapontype WP_DET_PACK +weaponclass weapon_det_pack +weaponmodel models/weapons2/detpack/det_pack.md3 +weaponIcon gfx/hud/w_icon_detpack +ammotype 9 +ammolowcount 1 +energypershot 1 +firetime 800 +range 8192 +altenergypershot 0 +altfiretime 400 +altrange 8192 +missileModel models/weapons2/detpack/det_pack_proj.glm +selectSound sound/weapons/detpack/select.wav +muzzleEffect detpack/muzzle_flash +} + +// WP_EMPLACED_GUN +{ +weapontype WP_EMPLACED_GUN +weaponclass weapon_emplaced_gun +weaponmodel models/weapons2/noweap/noweap.md3 + +altenergypershot 1 +altrange 8192 +missileFuncName emplaced_func +altmissileFuncName emplaced_func +ammotype 6 +ammolowcount 15 +energypershot 1 +firetime 150 +altfiretime 150 +range 8192 +muzzleEffect emplaced/muzzle_flash +} + +// WP_BOT_LASER +{ +weapontype WP_BOT_LASER +weaponclass weapon_bryar_pistol +weaponmodel models/weapons2/noweap/noweap.md3 + +//flashsound sound/weapons/probe/fire.wav +//altflashsound sound/weapons/probe/alt_fire.wav +altenergypershot 0 +altrange 8192 +missileFuncName bryar_func +ammotype 1 +ammolowcount 15 +energypershot 2 +firetime 1600 +range 8192 +} + +// WP_MELEE +{ +weapontype WP_MELEE +weaponclass weapon_melee +weaponmodel models/weapons2/noweap/noweap.md3 + +ammotype 3 +ammolowcount 5 +energypershot 0 +firetime 1000 +range 1024 +} + +// WP_ATST_MAIN +{ +weapontype WP_ATST_MAIN +weaponclass weapon_atst_main +weaponmodel models/weapons2/noweap/noweap.md3 +weaponIcon gfx/hud/w_icon_atst +//flashsound sound/weapons/atst/ATSTfire1.wav +//altflashsound sound/weapons/atst/ATSTfire2.wav +altenergypershot 1 +altrange 8192 +missileFuncName atstmain_func +altmissileFuncName atstmain_func +ammotype 6 +ammolowcount 15 +energypershot 1 +firetime 200 +altfiretime 150 +range 8192 +muzzleEffect emplaced/muzzle_flash +} + +// WP_ATST_SIDE +{ +weapontype WP_ATST_SIDE +weaponclass weapon_atst_side +weaponmodel models/weapons2/noweap/noweap.md3 +weaponIcon gfx/hud/w_icon_atstside +//flashsound sound/weapons/atst/ATSTfire3.wav +//altflashsound sound/weapons/atst/ATSTfire4.wav +altenergypershot 1 +altrange 8192 + +altmissileModel models/weapons2/merr_sonn/projectile.md3 + +missileFuncName atst_side_main_func +altmissileFuncName atst_side_alt_func +muzzleEffect emplaced/muzzle_flash +altmuzzleEffect emplaced/muzzle_flash + +ammotype 6 +ammolowcount 15 +energypershot 1 +firetime 400 +altfiretime 1000 +range 8192 +} + +// WP_TIE_FIGHTER +{ +weapontype WP_TIE_FIGHTER +weaponclass weapon_tie_fighter +weaponmodel models/weapons2/noweap/noweap.md3 +weaponIcon icons/w_icon_tie +//flashsound sound/weapons/tie_fighter/tie_fire.wav +//altflashsound sound/weapons/tie_fighter/tie_fire2.wav +altenergypershot 1 +altrange 8192 +missileFuncName emplaced_func +altmissileFuncName emplaced_func +ammotype 6 +ammolowcount 15 +energypershot 1 +firetime 400 +altfiretime 400 +range 8192 +muzzleEffect emplaced/muzzle_flash +} + +// WP_RAPID_FIRE_CONC +{ +weapontype WP_RAPID_FIRE_CONC +weaponclass weapon_radid_concussion +weaponmodel models/weapons2/noweap/noweap.md3 +weaponIcon icons/w_icon_tie +//flashsound sound/weapons/rapid_conc/fire.wav +//altflashsound sound/weapons/rapid_conc/alt_fire.wav +altenergypershot 1 +altrange 8192 +missileFuncName emplaced_func +altmissileFuncName repeater_alt_func +ammotype 6 +ammolowcount 15 +energypershot 1 +firetime 400 +altfiretime 1000 +range 8192 +muzzleEffect emplaced/muzzle_flash +} + +// WP_BLASTER_PISTOL +{ +weapontype WP_BLASTER_PISTOL +weaponclass weapon_blaster_pistol +weaponmodel models/weapons2/imp_pistol/pistol.md3 + +//flashsound sound/weapons/npc_blaster/fire.wav +//altflashsound sound/weapons/npc_blaster/alt_fire.wav +missileFuncName bryar_func +altmissileFuncName bryar_alt_func +ammotype 2 +ammolowcount 15 +energypershot 2 +firetime 400 +range 8192 +altenergypershot 2 +altfiretime 400 +altrange 8192 +muzzleEffect bryar/muzzle_flash +} + +// WP_TURRET +{ +weapontype WP_TURRET +weaponclass weapon_turret +weaponmodel models/weapons2/noweap/noweap.md3 +weaponIcon icons/w_icon_turret +altenergypershot 1 +altrange 8192 +missileFuncName turret_func +ammotype 6 +ammolowcount 15 +energypershot 1 +firetime 400 +altfiretime 400 +range 8192 +muzzleEffect turret/muzzle_flash +} + +// AMMO_NONE +{ +AMMOTYPE AMMO_NONE +} + +// AMMO_FORCE +{ +AMMO AMMO_FORCE +AMMOMAX 100 +} + +// AMMO_BLASTER +{ +AMMO AMMO_BLASTER +AMMOMAX 300 +} + +// AMMO_POWERCELL +{ +AMMO AMMO_POWERCELL +AMMOMAX 300 +} + +// AMMO_METAL_BOLTS +{ +AMMO AMMO_METAL_BOLTS +AMMOMAX 400 +} + +// AMMO_ROCKETS +{ +AMMO AMMO_ROCKETS +AMMOMAX 10 +} + +// AMMO_EMPLACED +{ +AMMO AMMO_EMPLACED +AMMOMAX 999 +} + +// AMMO_THERMAL +{ +AMMO AMMO_THERMAL +AMMOMAX 10 +} + +// AMMO_TRIPMINE +{ +AMMO AMMO_TRIPMINE +AMMOMAX 5 +} + +// AMMO_DETPACK +{ +AMMO AMMO_DETPACK +AMMOMAX 5 +} \ No newline at end of file diff --git a/code/base/jk2config.cfg b/code/base/jk2config.cfg new file mode 100644 index 0000000..77fff94 --- /dev/null +++ b/code/base/jk2config.cfg @@ -0,0 +1,213 @@ +// generated by Star Wars Jedi Outcast, do not modify +unbindall +bind TAB "datapad" +bind ENTER "invuse" +bind SPACE "+moveup" +bind , "+moveleft" +bind - "weapon 0" +bind . "+moveright" +bind / "+mlook" +bind 0 "weapon 10" +bind 1 "weapon 1" +bind 2 "weapon 2" +bind 3 "weapon 3" +bind 4 "weapon 4" +bind 5 "weapon 5" +bind 6 "weapon 6" +bind 7 "weapon 7" +bind 8 "weapon 8" +bind 9 "weapon 9" +bind = "screenshot silent" +bind [ "invprev" +bind \ "weapongrabbed" +bind ] "invnext" +bind ` "toggleconsole" +bind a "+moveleft" +bind b "use_bacta" +bind c "+movedown" +bind d "+moveright" +bind e "+use" +bind f "+useforce" +bind g "zoom" +bind l "saberAttackCycle" +bind m "datapad" +bind p "cg_thirdperson !" +bind q "weapprev" +bind r "weapnext" +bind s "+back" +bind v "+strafe" +bind w "+forward" +bind x "forcenext" +bind z "forceprev" +bind ~ "toggleconsole" +bind UPARROW "+forward" +bind DOWNARROW "+back" +bind LEFTARROW "+left" +bind RIGHTARROW "+right" +bind ALT "+altattack" +bind CTRL "+use" +bind SHIFT "+speed" +bind PGDN "+lookdown" +bind PGUP "+lookup" +bind END "centerview" +bind F1 "force_throw" +bind F2 "force_pull" +bind F3 "force_speed" +bind F4 "force_distract" +bind F5 "force_heal" +bind F6 "+force_grip" +bind F7 "+force_lightning" +bind F9 "load quik" +bind F10 "uimenu ingameloadmenu" +bind F11 "uimenu ingamesavemenu" +bind F12 "save quik*" +bind KP_LEFTARROW "use_lightamp_goggles" +bind KP_5 "use_sentry" +bind KP_PGDN "use_seeker" +bind MOUSE1 "+attack" +bind MOUSE2 "+altattack" +bind MOUSE3 "zoom" +bind MWHEELDOWN "weapnext" +bind MWHEELUP "weapprev" +seta d_slowmodeath "3" +seta ui_iscensored "0" +seta g_saberAutoAim "1" +seta g_saberAnimSpeed "1" +seta g_saberMoveSpeed "1" +seta g_saberRealisticCombat "0" +seta g_saberAutoBlocking "1" +seta g_subtitles "2" +seta g_dismemberProbabilities "0" +seta g_dismemberment "4" +seta g_spskill "1" +seta cg_reliableAnimSounds "1" +seta cg_gunAutoFirst "1" +seta cg_saberAutoThird "1" +seta cg_bobroll "0.002" +seta cg_bobpitch "0.002" +seta cg_bobup "0.005" +seta cg_runroll "0.005" +seta cg_runpitch "0.002" +seta cg_simpleItems "0" +seta cg_crosshairY "0" +seta cg_crosshairX "0" +seta cg_crosshairSize "24" +seta cg_crosshairForceHint "1" +seta cg_crosshairIdentifyTarget "1" +seta cg_dynamicCrosshair "1" +seta cg_drawAmmoWarning "1" +seta cg_drawSnapshot "0" +seta cg_drawFPS "0" +seta cg_drawTimer "0" +seta cg_drawStatus "1" +seta cg_draw2D "1" +seta cg_stereoSeparation "0.4" +seta cg_drawGun "1" +seta cm_playerCurveClip "1" +seta cg_hudFiles "ui/jk2hud.txt" +seta ui_bigFont "0.4" +seta ui_smallFont "0.25" +seta ui_menuFiles "ui/menus.txt" +seta cg_marks "1" +seta cg_drawCrosshair "1" +seta s_soundpoolmegs "25" +seta s_UseOpenAL "0" +seta s_mp3overhead "31760" +seta s_language "english" +seta s_mixPreStep "0.05" +seta s_mixahead "0.2" +seta s_allowDynamicMusic "1" +seta s_khz "22" +seta s_separation "0.5" +seta s_musicvolume "0.25" +seta s_volumeVoice "1.0" +seta s_volume "0.5" +seta vid_ypos "0" +seta vid_xpos "0" +seta r_lastValidRenderer "GeForce2 MX/AGP/SSE2" +seta r_modelpoolmegs "20" +seta cg_shadows "1" +seta r_showtriscolor "0" +seta r_primitives "0" +seta r_facePlaneCull "1" +seta r_gamma "1" +seta r_swapInterval "0" +seta r_textureMode "GL_LINEAR_MIPMAP_LINEAR" +seta r_finish "0" +seta r_dlightBacks "1" +seta r_dynamiclight "1" +seta r_drawSun "0" +seta r_fastsky "0" +seta r_ignoreGLErrors "1" +seta r_lodscale "10" +seta r_flares "1" +seta r_lodbias "0" +seta r_lodCurveError "250" +seta r_intensity "1" +seta r_ignoreFastPath "1" +seta r_subdivisions "4" +seta r_vertexLight "0" +seta r_simpleMipMaps "1" +seta r_customaspect "1" +seta r_customheight "1024" +seta r_customwidth "1600" +seta r_mode "3" +seta r_ignorehwgamma "0" +seta r_depthbits "0" +seta r_stencilbits "8" +seta r_stereo "0" +seta r_colorbits "0" +seta r_texturebitslm "0" +seta r_texturebits "0" +seta r_detailtextures "1" +seta r_picmip "1" +seta r_ext_texture_filter_anisotropic "1" +seta r_ext_texture_env_add "1" +seta r_ext_compiled_vertex_array "1" +seta r_ext_multitexture "1" +seta r_ext_gamma_control "1" +seta r_ext_preferred_tc_method "0" +seta r_ext_compress_lightmaps "0" +seta r_ext_compress_textures "1" +seta r_allowExtensions "1" +seta handicap "100" +seta sex "male" +seta snaps "20" +seta name "Kyle" +seta m_filter "0" +seta m_side "0.25" +seta m_forward "0.25" +seta m_yaw "0.022" +seta m_pitch "0.022" +seta cg_autoswitch "1" +seta cl_VideoQuality "0" +seta cl_ingameVideo "1" +seta cl_freelook "1" +seta cl_mouseAccel "0" +seta sensitivity "5" +seta cl_run "1" +seta cl_packetdup "1" +seta cl_maxpackets "30" +seta cl_anglespeedkey "1.5" +seta cl_pitchspeed "140" +seta cl_yawspeed "140" +seta panoNumShots "10" +seta conAlpha "1.6" +seta ff_defaultTension "1" +seta use_ff "0" +seta k_language "american" +seta joy_ybutton "0" +seta joy_xbutton "1" +seta js_ffmult "3.0" +seta joy_threshold "0.15" +seta in_joyBallScale "0.02" +seta in_joystick "0" +seta in_mouse "-1" +seta in_mididevice "0" +seta in_midichannel "1" +seta in_midiport "1" +seta in_midi "0" +seta sp_language "0" +seta com_maxfps "85" +seta r_overBrightBits "1" +seta r_fullscreen "0" diff --git a/code/cgame/FX_Emplaced.cpp b/code/cgame/FX_Emplaced.cpp index a3f81eb..bdaacc6 100644 --- a/code/cgame/FX_Emplaced.cpp +++ b/code/cgame/FX_Emplaced.cpp @@ -63,24 +63,6 @@ void FX_EmplacedHitWall( vec3_t origin, vec3_t normal ) theFxScheduler.PlayEffect( "emplaced/wall_impact", origin, normal ); } -/* ---------------------------- -FX_EmplacedHitPlayer ---------------------------- -*/ - -void FX_EmplacedHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid ) -{ - if ( humanoid ) - { - theFxScheduler.PlayEffect( "emplaced/flesh_impact", origin, normal ); - } - else - { - theFxScheduler.PlayEffect( "emplaced/droid_impact", origin, normal ); - } -} - /* --------------------------- FX_TurretProjectileThink diff --git a/code/cgame/FX_HeavyRepeater.cpp b/code/cgame/FX_HeavyRepeater.cpp index 5834772..61492b6 100644 --- a/code/cgame/FX_HeavyRepeater.cpp +++ b/code/cgame/FX_HeavyRepeater.cpp @@ -87,6 +87,6 @@ FX_RepeaterAltHitPlayer void FX_RepeaterAltHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid ) { - theFxScheduler.PlayEffect( "repeater/concussion", origin, normal ); + theFxScheduler.PlayEffect( "repeater/concussion", origin ); // theFxScheduler.PlayEffect( "repeater/alt_wall_impact2", origin, normal ); } \ No newline at end of file diff --git a/code/cgame/FxScheduler.cpp b/code/cgame/FxScheduler.cpp index 583808e..4869a5e 100644 --- a/code/cgame/FxScheduler.cpp +++ b/code/cgame/FxScheduler.cpp @@ -767,7 +767,7 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, int clientID, int delay // If depth hack ISN'T already on, then turn it on. Otherwise, we treat a pre-existing depth_hack flag as NOT being depth_hack. // This is done because muzzle flash fx files are shared amongst all shooters, but for the player we need to do depth hack in first person.... - if ( !( fx->mFlags & FX_DEPTH_HACK )) + if ( !( fx->mFlags & FX_DEPTH_HACK ) && !cg.renderingThirdPerson ) // hack! { flags = fx->mFlags | FX_RELATIVE | FX_DEPTH_HACK; } @@ -822,7 +822,7 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, int clientID, int delay case Sound: //--------- - // bolted sounds actually play on the client....completely assumes weapon channel!!! + // bolted sounds actually play on the client.... theFxHelper.PlaySound( NULL, clientID, CHAN_WEAPON, fx->mMediaHandles.GetHandle() ); break; diff --git a/code/cgame/FxSystem.cpp b/code/cgame/FxSystem.cpp index ac740c3..b6ee4d4 100644 --- a/code/cgame/FxSystem.cpp +++ b/code/cgame/FxSystem.cpp @@ -49,6 +49,11 @@ void SFxHelper::AdjustTime( int frameTime ) { if ( !cg_paused.integer ) { + if ( frameTime > 1500 ) // hack + { + frameTime = 200; + } + mFrameTime = frameTime; mFloatFrameTime = mFrameTime * 0.001f; mTime += mFrameTime; diff --git a/code/cgame/animtable.h b/code/cgame/animtable.h index cde00d7..d091b1b 100644 --- a/code/cgame/animtable.h +++ b/code/cgame/animtable.h @@ -8,6 +8,7 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = //================================================= //ANIMS IN WHICH UPPER AND LOWER OBJECTS ARE IN MD3 //================================================= + ENUM2STRING(BOTH_1CRUFTFORGIL), //# G2 cannot have a reverse anim at beginning of file //# #sep ENUM2STRING(BOTH_ DEATHS ENUM2STRING(BOTH_DEATH1), //# First Death anim ENUM2STRING(BOTH_DEATH2), //# Second Death anim @@ -28,6 +29,12 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_DEATH17), //# ENUM2STRING(BOTH_DEATH18), //# ENUM2STRING(BOTH_DEATH19), //# + ENUM2STRING(BOTH_DEATH20), //# + ENUM2STRING(BOTH_DEATH21), //# + ENUM2STRING(BOTH_DEATH22), //# + ENUM2STRING(BOTH_DEATH23), //# + ENUM2STRING(BOTH_DEATH24), //# + ENUM2STRING(BOTH_DEATH25), //# ENUM2STRING(BOTH_DEATHFORWARD1), //# First Death in which they get thrown forward ENUM2STRING(BOTH_DEATHFORWARD2), //# Second Death in which they get thrown forward @@ -71,6 +78,12 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_DEAD17), //# ENUM2STRING(BOTH_DEAD18), //# ENUM2STRING(BOTH_DEAD19), //# + ENUM2STRING(BOTH_DEAD20), //# + ENUM2STRING(BOTH_DEAD21), //# + ENUM2STRING(BOTH_DEAD22), //# + ENUM2STRING(BOTH_DEAD23), //# + ENUM2STRING(BOTH_DEAD24), //# + ENUM2STRING(BOTH_DEAD25), //# ENUM2STRING(BOTH_DEADFORWARD1), //# First thrown forward death finished pose ENUM2STRING(BOTH_DEADFORWARD2), //# Second thrown forward death finished pose ENUM2STRING(BOTH_DEADBACKWARD1), //# First thrown backward death finished pose @@ -606,6 +619,16 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_CCWCIRCLEBREAK), //# ENUM2STRING(BOTH_CWCIRCLELOCK), //# ENUM2STRING(BOTH_CCWCIRCLELOCK), //# + //other saber anims/attacks + ENUM2STRING(BOTH_SABERFAST_STANCE), + ENUM2STRING(BOTH_SABERSLOW_STANCE), + ENUM2STRING(BOTH_A2_STABBACK1), //# Stab saber backward + ENUM2STRING(BOTH_ATTACK_BACK), //# Swing around backwards and attack + ENUM2STRING(BOTH_JUMPFLIPSLASHDOWN1),//# + ENUM2STRING(BOTH_JUMPFLIPSTABDOWN),//# + ENUM2STRING(BOTH_FORCELEAP2_T__B_),//# + ENUM2STRING(BOTH_LUNGE2_B__T_),//# + ENUM2STRING(BOTH_CROUCHATTACKBACK1),//# //# #sep ENUM2STRING(BOTH_ STANDING ENUM2STRING(BOTH_STAND1), //# Standing idle, no weapon, hands down @@ -643,6 +666,15 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_STAND5TOSTAND8), //# Transition from stand5 to stand8 ENUM2STRING(BOTH_STAND7TOSTAND8), //# Tavion putting hands on back of chair (cin #11) ENUM2STRING(BOTH_STAND8TOSTAND5), //# Transition from stand8 to stand5 + ENUM2STRING(BOTH_STAND5SHIFTWEIGHT), //# Weightshift from stand5 to side and back to stand5 + ENUM2STRING(BOTH_STAND5SHIFTWEIGHTSTART), //# From stand5 to side + ENUM2STRING(BOTH_STAND5SHIFTWEIGHTSTOP), //# From side to stand5 + ENUM2STRING(BOTH_STAND5TURNLEFTSTART), //# Start turning left from stand5 + ENUM2STRING(BOTH_STAND5TURNLEFTSTOP), //# Stop turning left from stand5 + ENUM2STRING(BOTH_STAND5TURNRIGHTSTART), //# Start turning right from stand5 + ENUM2STRING(BOTH_STAND5TURNRIGHTSTOP), //# Stop turning right from stand5 + ENUM2STRING(BOTH_STAND5LOOK180LEFTSTART), //# Start looking over left shoulder (cin #17) + ENUM2STRING(BOTH_STAND5LOOK180LEFTSTOP), //# Stop looking over left shoulder (cin #17) ENUM2STRING(BOTH_CONSOLE1START), //# typing at a console ENUM2STRING(BOTH_CONSOLE1), //# typing at a console @@ -661,6 +693,7 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_GESTURE3), //# Generic gesture), non-specific ENUM2STRING(BOTH_WALK1TALKCOMM1), //# Talking into coom link while walking ENUM2STRING(BOTH_TALK1), //# Generic talk anim + ENUM2STRING(BOTH_TALK2), //# Generic talk anim ENUM2STRING(BOTH_TALKCOMM1START), //# Start talking into a comm link ENUM2STRING(BOTH_TALKCOMM1), //# Talking into a comm link ENUM2STRING(BOTH_TALKCOMM1STOP), //# Stop talking into a comm link @@ -721,6 +754,8 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_SITHEADTILTRSTOP), //# Head tilt to right from seated position ENUM2STRING(BOTH_SITHEADNOD), //# Head shake YES from seated position ENUM2STRING(BOTH_SITHEADSHAKE), //# Head shake NO from seated position + ENUM2STRING(BOTH_SIT2HEADTILTLSTART), //# Head tilt to left from seated position 2 + ENUM2STRING(BOTH_SIT2HEADTILTLSTOP), //# Head tilt to left from seated position 2 ENUM2STRING(BOTH_REACH1START), //# Monmothma reaching for crystal ENUM2STRING(BOTH_REACH1STOP), //# Monmothma reaching for crystal @@ -878,6 +913,9 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_WALK5), //# Tavion taunting Kyle (cin 22) ENUM2STRING(BOTH_WALK6), //# Slow walk for Luke (cin 12) ENUM2STRING(BOTH_WALK7), //# Fast walk + ENUM2STRING(BOTH_WALK8), //# Normal walk with hands behind back (Luke in cin#12) + ENUM2STRING(BOTH_WALK9), //# Lando walk (cin #17) + ENUM2STRING(BOTH_WALK10), //# Lando walk (cin #17) ENUM2STRING(BOTH_WALKTORUN1), //# transition from walk to run ENUM2STRING(BOTH_RUN1), //# Full run ENUM2STRING(BOTH_RUN1START), //# Start into full run1 @@ -966,16 +1004,7 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_DIVE1), //# Dive! - ENUM2STRING(BOTH_SABERFAST_STANCE), - ENUM2STRING(BOTH_SABERSLOW_STANCE), ENUM2STRING(BOTH_ENGAGETAUNT), - ENUM2STRING(BOTH_A2_STABBACK1), //# Stab saber backward - ENUM2STRING(BOTH_ATTACK_BACK), //# Swing around backwards and attack - ENUM2STRING(BOTH_JUMPFLIPSLASHDOWN1),//# - ENUM2STRING(BOTH_JUMPFLIPSTABDOWN),//# - ENUM2STRING(BOTH_FORCELEAP2_T__B_),//# - ENUM2STRING(BOTH_LUNGE2_B__T_),//# - ENUM2STRING(BOTH_CROUCHATTACKBACK1),//# ENUM2STRING(BOTH_ARIAL_LEFT), //# ENUM2STRING(BOTH_ARIAL_RIGHT), //# ENUM2STRING(BOTH_CARTWHEEL_LEFT), //# @@ -1031,11 +1060,6 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_ARIAL_F1),//# ENUM2STRING(BOTH_BUTTERFLY_FR1),//# ENUM2STRING(BOTH_BUTTERFLY_FL1),//# - ENUM2STRING(BOTH_POSE1),//# - ENUM2STRING(BOTH_POSE2),//# - ENUM2STRING(BOTH_POSE3),//# - ENUM2STRING(BOTH_POSE4),//# - ENUM2STRING(BOTH_POSE5),//# //# #sep BOTH_ MISC MOVEMENT ENUM2STRING(BOTH_HIT1), //# Kyle hit by crate in cin #9 @@ -1068,12 +1092,7 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = //# #sep BOTH_ SWIMMING ENUM2STRING(BOTH_SWIM_IDLE1), //# Swimming Idle 1 - ENUM2STRING(BOTH_SWIMFORWARDSTART), //# Swim forward start ENUM2STRING(BOTH_SWIMFORWARD), //# Swim forward loop - ENUM2STRING(BOTH_SWIMFORWARDSTOP), //# Swim forward end - ENUM2STRING(BOTH_SWIMBACKWARDSTART),//# Swim backward start - ENUM2STRING(BOTH_SWIMBACKWARD), //# Swim backward loop - ENUM2STRING(BOTH_SWIMBACKWARDSTOP), //# Swim backward end //# #sep ENUM2STRING(BOTH_ LYING ENUM2STRING(BOTH_LIE_DOWN1), //# From a stand position), get down on ground), face down @@ -1158,6 +1177,7 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_SABERPULL), //# Use off-hand to do force power. ENUM2STRING(BOTH_FORCEGRIP1), //# force-gripping (no anim?) ENUM2STRING(BOTH_FORCEGRIP3), //# force-gripping (right-hand) + ENUM2STRING(BOTH_FORCEGRIP3THROW), //# throwing while force-gripping (right hand) ENUM2STRING(BOTH_FORCEGRIP_HOLD), //# Use off-hand to do grip - hold ENUM2STRING(BOTH_FORCEGRIP_RELEASE),//# Use off-hand to do grip - release ENUM2STRING(BOTH_TOSS1), //# throwing to left after force gripping @@ -1191,10 +1211,11 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(BOTH_COCKPIT_HEADTILTRSTART), //# start tilt head right while sitting ENUM2STRING(BOTH_COCKPIT_HEADTILTRSTOP), //# stop tilt head right while sitting - ENUM2STRING(BOTH_COCKPIT_TALKGESTURE7START), //# - ENUM2STRING(BOTH_COCKPIT_TALKGESTURE7STOP), //# - ENUM2STRING(BOTH_COCKPIT_TALKGESTURE8), //# - ENUM2STRING(BOTH_COCKPIT_TALKGESTURE11START), //# + ENUM2STRING(BOTH_COCKPIT_TALKGESTURE7START), //# Lando's supporting hand to Kyle (cin #21) + ENUM2STRING(BOTH_COCKPIT_TALKGESTURE7STOP), //# Lando's supporting hand away from Kyle (cin #21) + ENUM2STRING(BOTH_COCKPIT_TALKGESTURE8START), //# Hand to Lando's chin (cin #21) + ENUM2STRING(BOTH_COCKPIT_TALKGESTURE8STOP), //# hand away from Lando's chin *cin #21) + ENUM2STRING(BOTH_COCKPIT_TALKGESTURE11START), //# ENUM2STRING(BOTH_COCKPIT_TALKGESTURE11STOP), //# ENUM2STRING(BOTH_COCKPIT_SLEEP6START), //# @@ -1240,20 +1261,6 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = //# #sep ENUM2STRING(TORSO_ USING NON-WEAPON OBJECTS //# #sep ENUM2STRING(TORSO_ MISC - ENUM2STRING(TORSO_TALKR1START), //# begin turning head for ENUM2STRING(BOTH_ENUM2STRING(TORSO_TALKR - ENUM2STRING(TORSO_TALKR1STOP), //# return head to straight forward from ENUM2STRING(BOTH_ENUM2STRING(TORSO_TALKL - ENUM2STRING(TORSO_TALKR1), //# talk to right side - ENUM2STRING(TORSO_TALKL1START), //# begin turning head for ENUM2STRING(BOTH_ENUM2STRING(TORSO_TALKL - ENUM2STRING(TORSO_TALKL1STOP), //# return head to straight forward from ENUM2STRING(BOTH_ENUM2STRING(TORSO_TALKL - ENUM2STRING(TORSO_TALKL1), //# talk to left side - ENUM2STRING(TORSO_LOOKL1), //# looking left - ENUM2STRING(TORSO_LOOKR1), //# looking right - ENUM2STRING(TORSO_LOOKR2START), //# turn not so far as TALKR1 - ENUM2STRING(TORSO_LOOKR2STOP), //# turn not so far as TALKR1 - ENUM2STRING(TORSO_LOOKR2), //# looking right - not so far as LOOKR1 - ENUM2STRING(TORSO_LOOKL2START), //# turn not so far as TALKL1 - ENUM2STRING(TORSO_LOOKL2STOP), //# turn not so far as TALKL1 - ENUM2STRING(TORSO_LOOKL2), //# looking right - not so far as LOOKL1 ENUM2STRING(TORSO_HANDGESTURE1), //# gestures to left one hand ENUM2STRING(TORSO_HANDGESTURE2), //# gestures to right one hand ENUM2STRING(TORSO_HANDGESTURE3), //# gestures to the left both hands @@ -1355,7 +1362,6 @@ stringID_table_t animTable [MAX_ANIMATIONS+1] = ENUM2STRING(FACE_SMILE), //# ENUM2STRING(FACE_FROWN), //# ENUM2STRING(FACE_DEAD), //# - ENUM2STRING(FACE_GALAK), //# This has to be last for Galak Mech to talk //must be terminated NULL,-1 diff --git a/code/cgame/cg_camera.cpp b/code/cgame/cg_camera.cpp index ccc764c..ef8471e 100644 --- a/code/cgame/cg_camera.cpp +++ b/code/cgame/cg_camera.cpp @@ -18,6 +18,7 @@ void CGCam_TrackDisable( void ); void CGCam_Distance( float distance, qboolean initLerp ); void CGCam_DistanceDisable( void ); extern int CG_CalcFOVFromX( float fov_x ); +extern void WP_SaberCatch( gentity_t *self, gentity_t *saber, qboolean switchToSaber ); /* TODO: @@ -85,6 +86,15 @@ void CGCam_Enable( void ) cg.zoomMode = 0; } + if ( g_entities[0].client->ps.saberInFlight && g_entities[0].client->ps.saberActive ) + {//saber is out + gentity_t *saberent = &g_entities[g_entities[0].client->ps.saberEntityNum]; + if ( saberent ) + { + WP_SaberCatch( &g_entities[0], saberent, qfalse ); + } + } + for ( int i = 0; i < NUM_FORCE_POWERS; i++ ) {//deactivate any active force powers g_entities[0].client->ps.forcePowerDuration[i] = 0; @@ -124,6 +134,11 @@ void CGCam_Disable( void ) gi.SendServerCommand( NULL, "cts"); + if ( cg_skippingcin.integer ) + {//We're skipping the cinematic and it's over now + gi.cvar_set("timescale", "1"); + gi.cvar_set("skippingCinematic", "0"); + } } /* @@ -414,6 +429,11 @@ void CGCam_Follow( const char *cameraGroup, float speed, float initLerp ) return; } + if ( Q_stricmp("NULL", (char *)cameraGroup) == 0 ) + {//Turn off all aiming + return; + } + //NOTE: if this interrupts a pan before it's done, need to copy the cg.refdef.viewAngles to the camera.angles! client_camera.info_state |= CAMERA_FOLLOWING; client_camera.info_state &= ~CAMERA_PANNING; @@ -669,7 +689,14 @@ void CGCam_FollowUpdate ( void ) if ( from->s.pos.trType != TR_STATIONARY ) // if ( from->s.pos.trType == TR_INTERPOLATE ) {//use interpolated origin? - VectorCopy(fromCent->lerpOrigin, focus[num_subjects]); + if ( !VectorCompare( vec3_origin, fromCent->lerpOrigin ) ) + {//hunh? Somehow we've never seen this gentity on the client, so there is no lerpOrigin, so cheat over to the game and use the currentOrigin + VectorCopy( from->currentOrigin, focus[num_subjects] ); + } + else + { + VectorCopy( fromCent->lerpOrigin, focus[num_subjects] ); + } } else { @@ -716,6 +743,12 @@ void CGCam_FollowUpdate ( void ) VectorSubtract( client_camera.subjectPos, center, vec ); client_camera.subjectSpeed = VectorLengthSquared( vec ) * 100.0f / cg.frametime; + /* + if ( !cg_skippingcin.integer ) + { + Com_Printf( S_COLOR_RED"org: %s\n", vtos(center) ); + } + */ VectorCopy( center, client_camera.subjectPos ); VectorSubtract( center, cg.refdef.vieworg, dir );//can't use client_camera.origin because it's not updated until the end of the move. @@ -732,7 +765,7 @@ void CGCam_FollowUpdate ( void ) cameraAngles[i] = AngleNormalize180( client_camera.angles[i] + frac * AngleNormalize180(cameraAngles[i] - client_camera.angles[i]) ); cameraAngles[i] = AngleNormalize180( cameraAngles[i] ); } -#ifdef _DEBUG +#if 0 Com_Printf( "%s\n", vtos(cameraAngles) ); #endif } @@ -740,12 +773,22 @@ void CGCam_FollowUpdate ( void ) {//Snapping, should do this first time if follow_lerp_to_start_duration is zero //will lerp from this point on client_camera.followInitLerp = qtrue; + for( i = 0; i < 3; i++ ) + {//normalize so that when we start lerping, it doesn't freak out + cameraAngles[i] = AngleNormalize180( cameraAngles[i] ); + } //So tracker doesn't move right away thinking the first angle change //is the subject moving... FIXME: shouldn't set this until lerp done OR snapped? client_camera.subjectSpeed = 0; } //Point camera to lerp angles + /* + if ( !cg_skippingcin.integer ) + { + Com_Printf( "ang: %s\n", vtos(cameraAngles) ); + } + */ VectorCopy( cameraAngles, client_camera.angles ); } diff --git a/code/cgame/cg_consolecmds.cpp b/code/cgame/cg_consolecmds.cpp index 0deb8a6..e299f61 100644 --- a/code/cgame/cg_consolecmds.cpp +++ b/code/cgame/cg_consolecmds.cpp @@ -59,7 +59,7 @@ extern float cg_zoomFov; //from cg_view.cpp void CG_ToggleBinoculars( void ) { - if ( in_camera) + if ( in_camera || !cg.snap) { return; } diff --git a/code/cgame/cg_credits.cpp b/code/cgame/cg_credits.cpp new file mode 100644 index 0000000..f2aef34 --- /dev/null +++ b/code/cgame/cg_credits.cpp @@ -0,0 +1,635 @@ +// Filename:- cg_credits.cpp +// +// module for end credits code + +// this line must stay at top so the whole PCH thing works... +// +#include "cg_headers.h" + +//#include "cg_local.h" +#include "cg_media.h" + + +#define fCARD_FADESECONDS 1.0f // fade up time, also fade down time +#define fCARD_SUSTAINSECONDS 2.0f // hold time before fade down +#define fLINE_SECONDTOSCROLLUP 15.0f // how long one line takes to scroll up the screen + + +#define MAX_LINE_BYTES 2048 + +qhandle_t ghFontHandle = 0; +float gfFontScale = 1.0f; +vec4_t gv4Color = {0}; + +struct StringAndSize_t +{ + int iStrLenPixels; + string str; + + StringAndSize_t() + { + iStrLenPixels = -1; + str = ""; + } + StringAndSize_t(const char *psString) + { + iStrLenPixels = -1; + str = psString; + } + StringAndSize_t & operator = (const char *psString) + { + iStrLenPixels = -1; + str = psString; + return *this; + } + + const char *c_str(void) + { + return str.c_str(); + } + + int GetPixelLength(void) + { + if (iStrLenPixels == -1) + { + iStrLenPixels = cgi_R_Font_StrLenPixels(str.c_str(), ghFontHandle, gfFontScale); + } + + return iStrLenPixels; + } + + bool IsEmpty(void) + { + return str.empty(); + } +}; + +struct CreditCard_t +{ + int iTime; + StringAndSize_t strTitle; + vector vstrText; + + CreditCard_t() + { + iTime = -1; // flag "not set yet" + } +}; + +struct CreditLine_t +{ + int iLine; + StringAndSize_t strText; + vector vstrText; + bool bDotted; +}; + +typedef list CreditLines_t; +typedef list CreditCards_t; + +struct CreditData_t +{ + int iStartTime; + + CreditCards_t CreditCards; + CreditLines_t CreditLines; + + bool Running(void) + { + return !!( CreditCards.size() || CreditLines.size() ); + } +}; + +CreditData_t CreditData; + + +static LPCSTR Capitalize(LPCSTR psTest) +{ + static char sTemp[MAX_LINE_BYTES]; + + Q_strncpyz(sTemp, psTest, sizeof(sTemp)); + + if (!cgi_Language_IsAsian()) + { + strupr(sTemp); // capitalise titles (if not asian!!!!) + } + + return sTemp; +} + +static bool CountsAsWhiteSpaceForCaps( char c ) +{ + return !!(isspace(c) || c == '-' || c == '.' || c == '(' || c == ')'); +} +static LPCSTR UpperCaseFirstLettersOnly(LPCSTR psTest) +{ + static char sTemp[MAX_LINE_BYTES]; + + Q_strncpyz(sTemp, psTest, sizeof(sTemp)); + + if (!cgi_Language_IsAsian()) + { + strlwr(sTemp); + + char *p = sTemp; + while (*p) + { + while (*p && CountsAsWhiteSpaceForCaps(*p)) p++;//(isspace(*p) || *p == '-' || *p == '.')) p++; // also copes with hyphenated names (awkward gits) + if (*p) + { + *p = toupper(*p); + while (*p && !CountsAsWhiteSpaceForCaps(*p)) p++; // cope with hyphenated names and initials (awkward gits) + } + } + } + + // now restore any weird stuff... + // + char *p = strstr(sTemp," Mc"); // eg "Mcfarrell" should be "McFarrell" + if (p && isalpha(p[3])) + { + p[3] = toupper(p[3]); + } + p = strstr(sTemp," O'"); // eg "O'flaherty" should be "O'Flaherty" + if (p && isalpha(p[3])) + { + p[3] = toupper(p[3]); + } + p = strstr(sTemp,"Lucasarts"); + if (p) + { + p[5] = 'A'; // capitalise the 'A' in LucasArts (jeez...) + } + + return sTemp; +} + +static const char *GetSubString(string &strResult) +{ + static char sTemp[MAX_LINE_BYTES]; + + if (!strlen(strResult.c_str())) + return NULL; + + strncpy(sTemp,strResult.c_str(),sizeof(sTemp)-1); + sTemp[sizeof(sTemp)-1]='\0'; + + char *psSemiColon = strchr(sTemp,';'); + if ( psSemiColon) + { + *psSemiColon = '\0'; + + strResult.erase(0,(psSemiColon-sTemp)+1); + } + else + { + // no semicolon found, probably last entry? (though i think even those have them on, oh well) + // + strResult.erase(); + } + + return sTemp; +} + +// sort entries by their last name (starts at back of string and moves forward until start or just before whitespace) +// ... +static int SortBySurname(const void *elem1, const void *elem2) +{ + StringAndSize_t *p1 = (StringAndSize_t *) elem1; + StringAndSize_t *p2 = (StringAndSize_t *) elem2; + + LPCSTR psSurName1 = p1->c_str() + (strlen(p1->c_str())-1); + LPCSTR psSurName2 = p2->c_str() + (strlen(p2->c_str())-1); + + while (psSurName1 > p1->c_str() && !isspace(*psSurName1)) psSurName1--; + while (psSurName2 > p2->c_str() && !isspace(*psSurName2)) psSurName2--; + if (isspace(*psSurName1)) psSurName1++; + if (isspace(*psSurName2)) psSurName2++; + + return stricmp(psSurName1, psSurName2); +} + + + +void CG_Credits_Init( LPCSTR psStripReference, vec4_t *pv4Color) +{ + // could make these into parameters later, but for now... + // + ghFontHandle = cgs.media.qhFontMedium; + gfFontScale = 1.0f; + + memcpy(gv4Color,pv4Color,sizeof(gv4Color)); // memcpy so we can poke into alpha channel + + // first, ask the strlen of the final string... + // + int iStrLen = cgi_SP_GetStringTextString( psStripReference, NULL, 0 ); + if (!iStrLen) + { +#ifndef FINAL_BUILD + Com_Printf("WARNING: CG_Credits_Init(): invalid text key :'%s'\n", psStripReference); +#endif + return; + } + // + // malloc space to hold it... + // + char *psMallocText = (char *) cgi_Z_Malloc( iStrLen+1, TAG_STRING ); + // + // now get the string... + // + iStrLen = cgi_SP_GetStringTextString( psStripReference, psMallocText, iStrLen+1 ); + //ensure we found a match + if (!iStrLen) + { + assert(0); // should never get here now, but wtf? + cgi_Z_Free(psMallocText); +#ifndef FINAL_BUILD + Com_Printf("WARNING: CG_Credits_Init(): invalid text key :'%s'\n", psStripReference); +#endif + return; + } + + // read whole string in and process as cards, lines etc... + // + typedef enum + { + eNothing = 0, + eLine, + eDotEntry, + eTitle, + eCard, + eFinished, + } Mode_e; + Mode_e eMode = eNothing; + + qboolean bCardsFinished = qfalse; + int iLineNumber = 0; + const char *psTextParse = psMallocText; + while (*psTextParse != NULL) + { + // read a line... + // + char sLine[MAX_LINE_BYTES]; + sLine[0]='\0'; + qboolean bWasCommand = qtrue; + while (1) + { + qboolean bIsTrailingPunctuation; + unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(&psTextParse, &bIsTrailingPunctuation); + + // concat onto string so far... + // + if (uiLetter == 32 && sLine[0] == '\0') + { + continue; // unless it's a space at the start of a line, in which case ignore it. + } + + if (uiLetter == '\n' || uiLetter == '\0' ) + { + // have we got a command word?... + // + if (!strnicmp(sLine,"(#",2)) + { + // yep... + // + if (!stricmp(sLine, "(#CARD)")) + { + if (!bCardsFinished) + { + eMode = eCard; + } + else + { + #ifndef FINAL_BUILD + Com_Printf( S_COLOR_YELLOW "CG_Credits_Init(): No current support for cards after scroll!\n" ); + #endif + eMode = eNothing; + } + break; + } + else + if (!stricmp(sLine, "(#TITLE)")) + { + eMode = eTitle; + bCardsFinished = qtrue; + break; + } + else + if (!stricmp(sLine, "(#LINE)")) + { + eMode = eLine; + bCardsFinished = qtrue; + break; + } + else + if (!stricmp(sLine, "(#DOTENTRY)")) + { + eMode = eDotEntry; + bCardsFinished = qtrue; + break; + } + else + { + #ifndef FINAL_BUILD + Com_Printf( S_COLOR_YELLOW "CG_Credits_Init(): bad keyword \"%s\"!\n", sLine ); + #endif + eMode = eNothing; + } + } + else + { + // I guess not... + // + bWasCommand = qfalse; + break; + } + } + else + { + // must be a letter... + // + if (uiLetter > 255) + { + Q_strcat(sLine, sizeof(sLine), va("%c%c",uiLetter >> 8, uiLetter & 0xFF)); + } + else + { + Q_strcat(sLine, sizeof(sLine), va("%c",uiLetter & 0xFF)); + } + } + } + + // command?... + // + if (bWasCommand) + { + // this'll just be a mode change, so ignore... + // + } + else + { + // else we've got some text to display... + // + switch (eMode) + { + case eNothing: break; + case eLine: + { + CreditLine_t CreditLine; + CreditLine.iLine = iLineNumber++; + CreditLine.strText = sLine; + + CreditData.CreditLines.push_back( CreditLine ); + } + break; + + case eDotEntry: + { + CreditLine_t CreditLine; + CreditLine.iLine = iLineNumber; + CreditLine.bDotted = true; + + string strResult(sLine); + const char *p; + while ((p=GetSubString(strResult)) != NULL) + { + if (CreditLine.strText.IsEmpty()) + { + CreditLine.strText = p; + } + else + { + CreditLine.vstrText.push_back( UpperCaseFirstLettersOnly(p) ); + } + } + + if (!CreditLine.strText.IsEmpty() && CreditLine.vstrText.size()) + { + // sort entries RHS dotted entries by alpha... + // + qsort(&CreditLine.vstrText[0], CreditLine.vstrText.size(), sizeof(CreditLine.vstrText[0]), SortBySurname); + + CreditData.CreditLines.push_back( CreditLine ); + iLineNumber += CreditLine.vstrText.size(); + } + } + break; + + case eTitle: + { + iLineNumber++; // leading blank line + + CreditLine_t CreditLine; + CreditLine.iLine = iLineNumber++; + CreditLine.strText = Capitalize(sLine); + + CreditData.CreditLines.push_back( CreditLine ); + + iLineNumber++; // trailing blank line + break; + } + case eCard: + { + CreditCard_t CreditCard; + + string strResult(sLine); + const char *p; + while ((p=GetSubString(strResult)) != NULL) + { + if (CreditCard.strTitle.IsEmpty()) + { + CreditCard.strTitle = Capitalize( p ); + } + else + { + CreditCard.vstrText.push_back( UpperCaseFirstLettersOnly( p ) ); + } + } + + if (!CreditCard.strTitle.IsEmpty()) + { + // sort entries by alpha... + // + qsort(&CreditCard.vstrText[0], CreditCard.vstrText.size(), sizeof(CreditCard.vstrText[0]), SortBySurname); + + CreditData.CreditCards.push_back(CreditCard); + } + } + break; + } + } + } + + cgi_Z_Free(psMallocText); + CreditData.iStartTime = cg.time; +} + +qboolean CG_Credits_Running( void ) +{ + return CreditData.Running(); +} + +// returns qtrue if still drawing... +// +qboolean CG_Credits_Draw( void ) +{ + if ( CG_Credits_Running() ) + { + const int iFontHeight = (int) (1.5f * (float) cgi_R_Font_HeightPixels(ghFontHandle, gfFontScale)); // taiwanese & japanese need 1.5 fontheight spacing + +// cgi_R_SetColor( *gpv4Color ); + + // display cards first... + // + if (CreditData.CreditCards.size()) + { + // grab first card off the list (we know there's at least one here, so...) + // + CreditCard_t &CreditCard = (*CreditData.CreditCards.begin()); + + if (CreditCard.iTime == -1) + { + // onceonly time init... + // + CreditCard.iTime = cg.time; + } + + // play with the alpha channel for fade up/down... + // + const float fMilliSecondsElapsed = cg.time - CreditCard.iTime; + const float fSecondsElapsed = fMilliSecondsElapsed / 1000.0f; + if (fSecondsElapsed < fCARD_FADESECONDS) + { + // fading up... + // + gv4Color[3] = fSecondsElapsed / fCARD_FADESECONDS; +// OutputDebugString(va("fade up: %f\n",gv4Color[3])); + } + else + if (fSecondsElapsed > fCARD_FADESECONDS + fCARD_SUSTAINSECONDS) + { + // fading down... + // + const float fFadeDownSeconds = fSecondsElapsed - (fCARD_FADESECONDS + fCARD_SUSTAINSECONDS); + gv4Color[3] = 1.0f - (fFadeDownSeconds / fCARD_FADESECONDS); +// OutputDebugString(va("fade dw: %f\n",gv4Color[3])); + } + else + { + gv4Color[3] = 1.0f; +// OutputDebugString(va("normal: %f\n",gv4Color[3])); + } + if (gv4Color[3] < 0.0f) + gv4Color[3] = 0.0f; // ... otherwise numbers that have dipped slightly -ve flash up fullbright after fade down + + // + // how many lines is it? + // + int iLines = CreditCard.vstrText.size() + 2; // +2 for title itself & one seperator line + // + int iYpos = (SCREEN_HEIGHT - (iLines * iFontHeight))/2; + // + // draw it, title first... + // + int iWidth = CreditCard.strTitle.GetPixelLength(); + int iXpos = (SCREEN_WIDTH - iWidth)/2; + cgi_R_Font_DrawString(iXpos, iYpos, CreditCard.strTitle.c_str(), gv4Color, ghFontHandle, -1, gfFontScale); + // + iYpos += iFontHeight*2; // skip blank line then move to main pos + // + for (int i=0; i fCARD_FADESECONDS + fCARD_SUSTAINSECONDS + fCARD_FADESECONDS) + { + // yep, so erase the first entry (which will trigger the next one to be initialised on re-entry)... + // + CreditData.CreditCards.erase( CreditData.CreditCards.begin() ); + + if (!CreditData.CreditCards.size()) + { + // all cards gone, so re-init timer for lines... + // + CreditData.iStartTime = cg.time; + } + } + // + return qtrue; + } + else + { + // doing scroll text... + // + if (CreditData.CreditLines.size()) + { + // process all lines... + // + const float fMilliSecondsElapsed = cg.time - CreditData.iStartTime; + const float fSecondsElapsed = fMilliSecondsElapsed / 1000.0f; + + bool bEraseOccured = false; + for (CreditLines_t::iterator it = CreditData.CreditLines.begin(); it != CreditData.CreditLines.end(); bEraseOccured ? it : ++it) + { + CreditLine_t &CreditLine = (*it); + bEraseOccured = false; + + static const float fPixelsPerSecond = ((float)SCREEN_HEIGHT / fLINE_SECONDTOSCROLLUP); + + int iYpos = SCREEN_HEIGHT + (CreditLine.iLine * iFontHeight); + iYpos-= (int) (fPixelsPerSecond * fSecondsElapsed); + + int iTextLinesThisItem = max(CreditLine.vstrText.size(),1); + if (iYpos + (iTextLinesThisItem * iFontHeight) < 0) + { + // scrolled off top of screen, so erase it... + // + it = CreditData.CreditLines.erase( it ); + bEraseOccured = true; + } + else + if (iYpos < SCREEN_HEIGHT) + { + // onscreen, so print it... + // + bool bIsDotted = !!CreditLine.vstrText.size(); // eg "STUNTS ...................... MR ED" + + int iWidth = CreditLine.strText.GetPixelLength(); + int iXpos = bIsDotted ? 4 : (SCREEN_WIDTH - iWidth)/2; + + gv4Color[3] = 1.0f; + + cgi_R_Font_DrawString(iXpos, iYpos, CreditLine.strText.c_str(), gv4Color, ghFontHandle, -1, gfFontScale); + + // now print any dotted members... + // + for (int i=0; igent->client->ps.forcePowersKnown ) + { + return; + } inc = (float) cent->gent->client->ps.forcePowerMax / MAX_TICS; value = cent->gent->client->ps.forcePower; + if ( value > cent->gent->client->ps.forcePowerMax ) + {//supercharged with force + extra = value - cent->gent->client->ps.forcePowerMax; + value = cent->gent->client->ps.forcePowerMax; + } for (i=MAX_TICS-1;i>=0;i--) { - - if (value <= 0) // partial tic + if ( extra ) + {//supercharged + memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t)); + percent = 0.75f + (sin( cg.time * 0.005f )*((extra/cent->gent->client->ps.forcePowerMax)*0.25f)); + calcColor[0] *= percent; + calcColor[1] *= percent; + calcColor[2] *= percent; + } + else if ( value <= 0 ) // partial tic { memcpy(calcColor, colorTable[CT_BLACK], sizeof(vec4_t)); } else if (value < inc) // partial tic { - memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t)); + memcpy(calcColor, colorTable[CT_LTGREY], sizeof(vec4_t)); percent = value / inc; calcColor[0] *= percent; calcColor[1] *= percent; @@ -284,7 +301,7 @@ static void CG_DrawForcePower(centity_t *cent,int x,int y) } else { - memcpy(calcColor, colorTable[CT_WHITE], sizeof(vec4_t)); + memcpy(calcColor, colorTable[CT_LTGREY], sizeof(vec4_t)); } cgi_R_SetColor( calcColor); @@ -327,17 +344,23 @@ static void CG_DrawAmmo(centity_t *cent,int x,int y) { cgi_R_SetColor( colorTable[CT_WHITE] ); + if ( !cg.saberAnimLevelPending && cent->gent->client ) + {//uninitialized after a loadgame, cheat across and get it + cg.saberAnimLevelPending = cent->gent->client->ps.saberAnimLevel; + } // don't need to draw ammo, but we will draw the current saber style in this window switch ( cg.saberAnimLevelPending ) { case 1://FORCE_LEVEL_1: - CG_DrawPic( x, y, 80, 40, cgs.media.HUDSaberStyle1 ); + case 5://FORCE_LEVEL_5://Tavion + CG_DrawPic( x, y, 80, 40, cgs.media.HUDSaberStyleFast ); break; case 2://FORCE_LEVEL_2: - CG_DrawPic( x, y, 80, 40, cgs.media.HUDSaberStyle2 ); + CG_DrawPic( x, y, 80, 40, cgs.media.HUDSaberStyleMed ); break; case 3://FORCE_LEVEL_3: - CG_DrawPic( x, y, 80, 40, cgs.media.HUDSaberStyle3 ); + case 4://FORCE_LEVEL_4://Desann + CG_DrawPic( x, y, 80, 40, cgs.media.HUDSaberStyleStrong ); break; } return; @@ -585,7 +608,16 @@ static qboolean CG_DrawCustomHealthHud( centity_t *cent ) // NOTE: this looks ugly if ( cent->gent && cent->gent->owner ) { - health = cent->gent->owner->health / (float)cent->gent->owner->max_health; + if (( cent->gent->owner->flags & FL_GODMODE )) + { + // chair is in godmode, so render the health of the player instead + health = cent->gent->health / (float)cent->gent->max_health; + } + else + { + // render the chair health + health = cent->gent->owner->health / (float)cent->gent->owner->max_health; + } } color[0] = 1.0f; @@ -736,6 +768,25 @@ static void CG_DrawHUD( centity_t *cent ) CG_DrawHUDRightFrame2(x,y); } } + +/* +================ +CG_ClearDataPadCvars +================ +*/ +void CG_ClearDataPadCvars( void ) +{ + cg_updatedDataPadForcePower1.integer = 0; //don't wait for the cvar-refresh. + cg_updatedDataPadForcePower2.integer = 0; //don't wait for the cvar-refresh. + cg_updatedDataPadForcePower3.integer = 0; //don't wait for the cvar-refresh. + cgi_Cvar_Set( "cg_updatedDataPadForcePower1", "0" ); + cgi_Cvar_Set( "cg_updatedDataPadForcePower2", "0" ); + cgi_Cvar_Set( "cg_updatedDataPadForcePower3", "0" ); + + cg_updatedDataPadObjective.integer = 0; //don't wait for the cvar-refresh. + cgi_Cvar_Set( "cg_updatedDataPadObjective", "0" ); +} + /* ================ CG_DrawDataPadHUD @@ -754,7 +805,7 @@ void CG_DrawDataPadHUD( centity_t *cent ) x = 526; - if ((cg_updatedDataPadForcePower.integer) || (cg_updatedDataPadObjective.integer)) + if ((missionInfo_Updated) && ((cg_updatedDataPadForcePower1.integer) || (cg_updatedDataPadObjective.integer))) { // Stop flashing light cg.missionInfoFlashTime = 0; @@ -763,21 +814,19 @@ void CG_DrawDataPadHUD( centity_t *cent ) // Set which force power to show. // cg_updatedDataPadForcePower is set from Q3_Interface, because force powers would only be given // from a script. - cg.DataPadforcepowerSelect = cg_updatedDataPadForcePower.integer - 1; // Not pretty, I know - if (cg.DataPadforcepowerSelect > MAX_SHOWPOWERS) - { //duh - cg.DataPadforcepowerSelect = MAX_SHOWPOWERS; - } - else if (cg.DataPadforcepowerSelect<0) + if (cg_updatedDataPadForcePower1.integer) { - cg.DataPadforcepowerSelect=0; + cg.DataPadforcepowerSelect = cg_updatedDataPadForcePower1.integer - 1; // Not pretty, I know + if (cg.DataPadforcepowerSelect >= MAX_DPSHOWPOWERS) + { //duh + cg.DataPadforcepowerSelect = MAX_DPSHOWPOWERS-1; + } + else if (cg.DataPadforcepowerSelect<0) + { + cg.DataPadforcepowerSelect=0; + } } - - cgi_Cvar_Set( "cg_updatedDataPadForcePower", "0" ); - cg_updatedDataPadForcePower.integer = 0; //don't wait for the cvar-refresh. - - cgi_Cvar_Set( "cg_updatedDataPadObjective", "0" ); - cg_updatedDataPadObjective.integer = 0; //don't wait for the cvar-refresh. +// CG_ClearDataPadCvars(); } CG_DrawHUDRightFrame1(x,y); @@ -1046,7 +1095,7 @@ static void CG_DrawZoomMask( void ) cgi_R_SetColor( colorTable[CT_WHITE] ); // draw the charge level - max = ( cg.time - cg_entities[0].gent->client->ps.weaponChargeTime ) / ( 50.0f * 30.0f ); // bad hardcodedness 50 is disruptor charge unit and 30 is max charge units allowed. + max = ( cg.time - cg_entities[0].gent->client->ps.weaponChargeTime ) / ( 150.0f * 10.0f ); // bad hardcodedness 150 is disruptor charge unit and 10 is max charge units allowed. if ( max > 1.0f ) { @@ -1071,6 +1120,12 @@ static void CG_DrawZoomMask( void ) CG_DrawPic( 570, 140, 12, 160, cgs.media.laGogglesSideBit ); float light = (128-cent->gent->lightLevel) * 0.5f; + + if ( light < -81 ) // saber can really jack up local light levels....?magic number?? + { + light = -81; + } + float pos1 = 220 + light; float pos2 = 220 + cos( cg.time * 0.0004f + light * 0.05f ) * 40 + sin( cg.time * 0.0013f + 1 ) * 20 + sin( cg.time * 0.0021f ) * 5; @@ -1087,7 +1142,7 @@ static void CG_DrawZoomMask( void ) // Black out the area behind the battery display cgi_R_SetColor( colorTable[CT_DKGREY]); - CG_DrawPic( 236, 357, 163, 16, cgs.media.whiteShader ); + CG_DrawPic( 236, 357, 164, 16, cgs.media.whiteShader ); if ( power ) { @@ -1154,7 +1209,7 @@ static void CG_DrawStats( void ) drawHud = CG_DrawCustomHealthHud( cent ); } - if ( drawHud ) + if (( drawHud ) && ( cg_drawHUD.integer )) { CG_DrawHUD( cent ); } @@ -1173,22 +1228,23 @@ static void CG_DrawPickupItem( void ) { float *fadeColor; value = cg.itemPickup; - if ( value ) { + if ( value && cg_items[ value ].icon != -1 ) + { fadeColor = CG_FadeColor( cg.itemPickupTime, 3000 ); - if ( fadeColor ) { + if ( fadeColor ) + { CG_RegisterItemVisuals( value ); -// cgi_R_SetColor( fadeColor ); -// CG_DrawPic( 8, 380, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon ); -// CG_DrawBigString( ICON_SIZE + 16, 398, bg_itemlist[ value ].pickup_name, fadeColor[0] ); -// CG_DrawProportionalString( ICON_SIZE + 16, 398, -// bg_itemlist[ value ].pickup_name, CG_SMALLFONT,fadeColor ); -// cgi_R_SetColor( NULL ); + cgi_R_SetColor( fadeColor ); + CG_DrawPic( 573, 340, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon ); + //CG_DrawBigString( ICON_SIZE + 16, 398, bg_itemlist[ value ].classname, fadeColor[0] ); + //CG_DrawProportionalString( ICON_SIZE + 16, 398, + // bg_itemlist[ value ].classname, CG_SMALLFONT,fadeColor ); + cgi_R_SetColor( NULL ); } } } -int cgi_EndGame(void); -void CMD_CGCam_Disable( void ); +extern int cgi_EndGame(void); /* =================== @@ -1199,25 +1255,23 @@ void CG_DrawCredits(void) { if (!cg.creditsStart) { + // cg.creditsStart = qtrue; - cgi_SP_Register("CREDITS", qfalse); //do not keep around after level - CG_ScrollText( "CREDITS_RAVEN", SCREEN_WIDTH - 16 ) ; - extern vec4_t textcolor_scroll; - memcpy(textcolor_scroll,colorTable[CT_LTGOLD1], sizeof(textcolor_scroll)); + cgi_SP_Register("CREDITS", qfalse); // do not keep around after level + CG_Credits_Init("CREDITS_RAVEN", &colorTable[CT_ICON_BLUE]); + if ( cg_skippingcin.integer ) + {//Were skipping a cinematic and it's over now + gi.cvar_set("timescale", "1"); + gi.cvar_set("skippingCinematic", "0"); + } } - -/* const char *psTempString = "JEDI KNIGHT II CREDITS"; - int w = cgi_R_Font_StrLenPixels(psTempString, cgs.media.qhFontMedium, 1.0f); - cgi_R_Font_DrawString(320 - w/2, 240, psTempString, colorTable[CT_LTGOLD1], cgs.media.qhFontMedium, -1, 1.0f); -*/ if (cg.creditsStart) { - if ( !cg.scrollTextTime ) + if ( !CG_Credits_Running() ) { cgi_Cvar_Set( "cg_endcredits", "0" ); - CMD_CGCam_Disable(); cgi_EndGame(); } } @@ -1264,20 +1318,10 @@ static void CG_DrawCrosshair( vec3_t worldPoint ) } else if ( cg_forceCrosshair && cg_crosshairForceHint.integer ) { - if ( cg_crosshairForceHint.integer == 1 ) - { - // force-affectable targets are blue..do subtle for level 1 hint - ecolor[0] = 0.4f; - ecolor[1] = 0.7f; - ecolor[2] = 1.0f; - } - else - { - // level 2 hint or higher, make it more obvious blue - ecolor[0] = 0.2f; - ecolor[1] = 0.5f; - ecolor[2] = 1.0f; - } + ecolor[0] = 0.2f; + ecolor[1] = 0.5f; + ecolor[2] = 1.0f; + corona = qtrue; } else if ( cg_crosshairIdentifyTarget.integer ) @@ -1365,11 +1409,11 @@ static void CG_DrawCrosshair( vec3_t worldPoint ) // both of these calcs will fade the corona in one direction if ( cg.forceCrosshairEndTime ) { - ecolor[3] = (cg.time - cg.forceCrosshairEndTime) / 1000.0f; + ecolor[3] = (cg.time - cg.forceCrosshairEndTime) / 500.0f; } else { - ecolor[3] = (cg.time - cg.forceCrosshairStartTime) / 1000.0f; + ecolor[3] = (cg.time - cg.forceCrosshairStartTime) / 300.0f; } // clamp @@ -1400,7 +1444,7 @@ static void CG_DrawCrosshair( vec3_t worldPoint ) if ( cg.forceCrosshairEndTime ) { // must have just gone over a force thing again...and we were in the process of fading out. Set fade in level to the level where the fade left off - cg.forceCrosshairStartTime = cg.time - ( 1.0f - ecolor[3] ) * 1000.0f; + cg.forceCrosshairStartTime = cg.time - ( 1.0f - ecolor[3] ) * 300.0f; cg.forceCrosshairEndTime = 0; } } @@ -1409,9 +1453,9 @@ static void CG_DrawCrosshair( vec3_t worldPoint ) if ( cg.forceCrosshairStartTime && !cg.forceCrosshairEndTime ) // were currently fading in { // must fade back out, but we will have to set the fadeout time to be equal to the current level of faded-in-edness - cg.forceCrosshairEndTime = cg.time - ecolor[3] * 1000.0f; + cg.forceCrosshairEndTime = cg.time - ecolor[3] * 500.0f; } - if ( cg.forceCrosshairEndTime && cg.time - cg.forceCrosshairEndTime > 1000.0f ) // not pointing at anything and fade out is totally done + if ( cg.forceCrosshairEndTime && cg.time - cg.forceCrosshairEndTime > 500.0f ) // not pointing at anything and fade out is totally done { // reset everything cg.forceCrosshairStartTime = 0; @@ -1464,15 +1508,15 @@ static void CG_DrawCrosshair( vec3_t worldPoint ) w, h, 0, 0, 1, 1, hShader ); } - if ( cg.forceCrosshairStartTime && cg_crosshairForceHint.integer > 1 ) // drawing extra bits + if ( cg.forceCrosshairStartTime && cg_crosshairForceHint.integer ) // drawing extra bits { - ecolor[0] = ecolor[1] = ecolor[2] = 1.0f; - ecolor[3] = (1 - ecolor[3]) * ( sin( cg.time * 0.001f ) * 0.05f + 0.2f ); + ecolor[0] = ecolor[1] = ecolor[2] = (1 - ecolor[3]) * ( sin( cg.time * 0.001f ) * 0.08f + 0.35f ); // don't draw full color + ecolor[3] = 1.0f; cgi_R_SetColor( ecolor ); - w *= 2.5f; - h *= 1.6f; + w *= 2.0f; + h *= 2.0f; cgi_R_DrawStretchPic( x + cg.refdef.x + 0.5f * ( 640 - w ), y + cg.refdef.y + 0.5f * ( 480 - h ), w, h, @@ -1539,7 +1583,8 @@ static void CG_ScanForRocketLock( void ) traceEnt = &g_entities[g_crosshairEntNum]; - if ( !traceEnt || g_crosshairEntNum <= 0 || g_crosshairEntNum >= ENTITYNUM_WORLD || (!traceEnt->client && traceEnt->s.weapon != WP_TURRET ) || !traceEnt->health ) + if ( !traceEnt || g_crosshairEntNum <= 0 || g_crosshairEntNum >= ENTITYNUM_WORLD || (!traceEnt->client && traceEnt->s.weapon != WP_TURRET ) || !traceEnt->health + || ( traceEnt && traceEnt->client && traceEnt->client->ps.powerups[PW_CLOAKED] )) { // see how much locking we have int dif = ( cg.time - g_rocketLockTime ) / ( 1200.0f / 8.0f ); @@ -1765,6 +1810,14 @@ static void CG_ScanForCrosshairEntity( qboolean scanAll ) cg.snap->ps.clientNum, MASK_PLAYERSOLID|CONTENTS_CORPSE|CONTENTS_ITEM ); */ //FIXME: pick up corpses + if ( trace.startsolid || trace.allsolid ) + { + // trace should not be allowed to pick up anything if it started solid. I tried actually moving the trace start back, which also worked, + // but the dynamic cursor drawing caused it to render around the clip of the gun when I pushed the blaster all the way into a wall. + // It looked quite horrible...but, if this is bad for some reason that I don't know + trace.entityNum = ENTITYNUM_NONE; + } + traceEnt = &g_entities[trace.entityNum]; } @@ -2184,7 +2237,7 @@ extern void CG_SaberClashFlare( void ); static void CG_Draw2D( void ) { char text[1024]={0}; - int w; + int w,y_pos; centity_t *cent; cent = &cg_entities[cg.snap->ps.clientNum]; @@ -2206,6 +2259,14 @@ static void CG_Draw2D( void ) return; } + if (cg_endcredits.integer) + { + if (!CG_Credits_Draw()) + { + CG_DrawCredits(); // will probably get rid of this soon + } + } + CGCam_DrawWideScreen(); CG_DrawBatteryCharge(); @@ -2217,20 +2278,15 @@ static void CG_Draw2D( void ) } CG_DrawScrollText(); - - CG_DrawCaptionText(); - + CG_DrawCaptionText(); CG_DrawGameText(); - if (cg_endcredits.integer) - { - CG_DrawCredits(); + if ( in_camera ) + {//still draw the saber clash flare, but nothing else + CG_SaberClashFlare(); return; } - if ( in_camera ) - return; - if ( CG_RenderingFromMiscCamera()) { // purposely doing an early out when in a misc_camera, change it if needed. @@ -2272,8 +2328,8 @@ static void CG_Draw2D( void ) CG_DrawForceSelect(); CG_DrawPickupItem(); - CG_SaberClashFlare(); } + CG_SaberClashFlare(); float y = 0; if (cg_drawSnapshot.integer) { @@ -2302,17 +2358,20 @@ static void CG_Draw2D( void ) if (cg.predicted_player_state.pm_type != PM_DEAD) { // Was a objective given? - if ((cg_updatedDataPadForcePower.integer) || (cg_updatedDataPadObjective.integer)) +/* if ((cg_updatedDataPadForcePower.integer) || (cg_updatedDataPadObjective.integer)) { // How long has the game been running? If within 15 seconds of starting, throw up the datapad. if (cg.dataPadLevelStartTime>cg.time) { // Make it pop up - cgi_SendConsoleCommand( "datapad" ); - cg.dataPadLevelStartTime=cg.time; //and don't do it again this level! + if (!in_camera) + { + cgi_SendConsoleCommand( "datapad" ); + cg.dataPadLevelStartTime=cg.time; //and don't do it again this level! + } } } - +*/ if (!cg.missionInfoFlashTime) { cg.missionInfoFlashTime = cg.time + cg_missionInfoFlashTime.integer; @@ -2322,12 +2381,31 @@ static void CG_Draw2D( void ) { cg.missionInfoFlashTime = 0; missionInfo_Updated = qfalse; + + CG_ClearDataPadCvars(); } cgi_SP_GetStringTextString( "INGAME_DATAPAD_UPDATED", text, sizeof(text) ); - w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontMedium, 1.0f); - cgi_R_Font_DrawString((SCREEN_WIDTH/2)-(w/2), (SCREEN_HEIGHT/2)+40, text, colorTable[CT_LTRED1], cgs.media.qhFontMedium, -1, 1.0f); + y_pos = (SCREEN_HEIGHT/2)+80; + w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontSmall, 1.0f); + cgi_R_Font_DrawString((SCREEN_WIDTH/2)-(w/2), y_pos, text, colorTable[CT_LTRED1], cgs.media.qhFontMedium, -1, 1.0f); + + if (cg_updatedDataPadForcePower1.integer) + { + y_pos += 25; + cgi_SP_GetStringTextString("INGAME_NEW_FORCE_POWER_INFO", text, sizeof(text) ); + w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontSmall, 1.0f); + cgi_R_Font_DrawString((SCREEN_WIDTH/2)-(w/2), y_pos, text, colorTable[CT_LTRED1], cgs.media.qhFontMedium, -1, 1.0f); + } + + if (cg_updatedDataPadObjective.integer) + { + y_pos += 25; + cgi_SP_GetStringTextString( "INGAME_NEW_OBJECTIVE_INFO", text, sizeof(text) ); + w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontSmall, 1.0f); + cgi_R_Font_DrawString((SCREEN_WIDTH/2)-(w/2), y_pos, text, colorTable[CT_LTRED1], cgs.media.qhFontMedium, -1, 1.0f); + } // if (cent->gent->client->sess.missionObjectivesShown<3) // { diff --git a/code/cgame/cg_effects.cpp b/code/cgame/cg_effects.cpp index 3e54af0..f10aebd 100644 --- a/code/cgame/cg_effects.cpp +++ b/code/cgame/cg_effects.cpp @@ -310,9 +310,10 @@ void CG_MiscModelExplosion( vec3_t mins, vec3_t maxs, int size, material_t chunk ct = 8; break; case MAT_ROPE: - ct = 1; + ct = 20; effect = "chunks/ropebreak"; break; + case MAT_WHITE_METAL: //not sure what this crap is really supposed to be.. case MAT_DRK_STONE: case MAT_LT_STONE: case MAT_GREY_STONE: @@ -335,7 +336,7 @@ void CG_MiscModelExplosion( vec3_t mins, vec3_t maxs, int size, material_t chunk ct += 7 * size; - // FIXME: real precache + // FIXME: real precache .. VERify that these need to be here...don't think they would because the effects should be registered in g_breakable theFxScheduler.RegisterEffect( effect ); if ( effect2 ) @@ -412,6 +413,7 @@ void CG_Chunks( int owner, vec3_t origin, const vec3_t normal, const vec3_t mins case MAT_DRK_STONE: case MAT_LT_STONE: case MAT_GREY_STONE: + case MAT_WHITE_METAL: // not quite sure what this stuff is supposed to be...it's for Stu cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.rockBreakSound ); bounce = LEBS_ROCK; speedMod = 0.5f; // rock blows up less @@ -420,11 +422,13 @@ void CG_Chunks( int owner, vec3_t origin, const vec3_t normal, const vec3_t mins cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.glassChunkSound ); // FIXME: should probably have a custom sound bounce = LEBS_METAL; break; + case MAT_CRATE1: + case MAT_CRATE2: + cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.crateBreakSound[Q_irand(0,1)] ); + break; case MAT_METAL: case MAT_METAL2: case MAT_METAL3: - case MAT_CRATE1: - case MAT_CRATE2: case MAT_ELEC_METAL:// FIXME: maybe have its own sound? cgi_S_StartSound( NULL, owner, CHAN_BODY, cgs.media.chunkSound ); bounce = LEBS_METAL; @@ -471,6 +475,9 @@ void CG_Chunks( int owner, vec3_t origin, const vec3_t normal, const vec3_t mins case MAT_DRK_STONE://brown chunkModel = cgs.media.chunkModels[CHUNK_ROCK3][Q_irand(0, 3)]; break; + case MAT_WHITE_METAL: + chunkModel = cgs.media.chunkModels[CHUNK_WHITE_METAL][Q_irand(0, 3)]; + break; case MAT_CRATE1://yellow multi-colored crate chunks chunkModel = cgs.media.chunkModels[CHUNK_CRATE1][Q_irand(0, 3)]; break; diff --git a/code/cgame/cg_ents.cpp b/code/cgame/cg_ents.cpp index 0e035f1..937ffe9 100644 --- a/code/cgame/cg_ents.cpp +++ b/code/cgame/cg_ents.cpp @@ -859,6 +859,11 @@ Ghoul2 Insert Start /* Ghoul2 Insert End */ + if ( cent->gent && !cent->gent->inuse ) + { + // Yeah, I know....items were being freed on touch, but it could still get here and draw incorrectly... + return; + } item = &bg_itemlist[ es->modelindex ]; @@ -987,7 +992,7 @@ Ghoul2 Insert End { VectorMA( ent.origin, -i, ent.axis[2], org ); - FX_AddSprite( org, NULL, NULL, 10.0f, 10.0f, wv * 0.5f, wv * 0.5f, 0.0f, 0.0f, 1.0f, cgs.media.yellowSaberGlowShader, 0x08000000 ); + FX_AddSprite( org, NULL, NULL, 10.0f, 10.0f, wv * 0.5f, wv * 0.5f, 0.0f, 0.0f, 1.0f, cgs.media.yellowDroppedSaberShader, 0x08000000 ); } // THIS light looks crappy...maybe it should just be removed... @@ -1190,12 +1195,12 @@ Ghoul2 Insert End */ ent.hModel = cgs.model_draw[s1->modelindex2]; } - else + + // I changed it to always do it because nodraw seemed like it should actually do what it says. Be aware that if you change this, + // the movers for the shooting gallery on doom_detention will break. + if ( (s1->eFlags & EF_NODRAW) ) { - if ( (s1->eFlags & EF_NODRAW) ) - { - return; - } + return; } //fall through and render the hModel or... @@ -1461,7 +1466,7 @@ Also called by client movement prediction code void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int atTime, vec3_t out ) { centity_t *cent; vec3_t oldOrigin, origin, deltaOrigin; - vec3_t oldAngles, angles, deltaAngles; +// vec3_t oldAngles, angles, deltaAngles; if ( moverNum <= 0 ) { VectorCopy( in, out ); @@ -1475,19 +1480,19 @@ void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int atTime, vec3_ } EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, oldOrigin ); - EvaluateTrajectory( ¢->currentState.apos, cg.snap->serverTime, oldAngles ); +// EvaluateTrajectory( ¢->currentState.apos, cg.snap->serverTime, oldAngles ); EvaluateTrajectory( ¢->currentState.pos, atTime, origin ); - EvaluateTrajectory( ¢->currentState.apos, atTime, angles ); +// EvaluateTrajectory( ¢->currentState.apos, atTime, angles ); VectorSubtract( origin, oldOrigin, deltaOrigin ); - VectorSubtract( angles, oldAngles, deltaAngles ); +// VectorSubtract( angles, oldAngles, deltaAngles ); + VectorAdd( in, deltaOrigin, out ); // FIXME: origin change when on a rotating object } - /* =============== CG_CalcEntityLerpPositions @@ -1893,11 +1898,13 @@ void CG_Limb ( centity_t *cent ) } //done! owner->client->dismembered = qfalse; + //done! + cent->gent->e_clThinkFunc = clThinkF_NULL; } else { extern cvar_t *g_dismemberment; -extern cvar_t *g_realisticSaberDamage; +extern cvar_t *g_saberRealisticCombat; //3) turn off w/descendants that surf in original model if ( cent->gent->target )//stubTagName ) {//add smoke to cap surf, spawn effect @@ -1915,7 +1922,7 @@ extern cvar_t *g_realisticSaberDamage; {//turn on caps gi.G2API_SetSurfaceOnOff( &owner->ghoul2[owner->playerModel], cent->gent->target3, 0 ); } - if ( owner->weaponModel != -1 ) + if ( owner->weaponModel >= 0 ) {//the corpse hasn't dropped their weapon if ( cent->gent->count == BOTH_DISMEMBER_RARM || cent->gent->count == BOTH_DISMEMBER_TORSO1 )//&& ent->s.weapon == WP_SABER && ent->weaponModel != -1 ) {//FIXME: is this first check needed with this lower one? @@ -1924,17 +1931,20 @@ extern cvar_t *g_realisticSaberDamage; } } if ( owner->client->NPC_class == CLASS_PROTOCOL - || g_dismemberment->integer > 3 - || g_realisticSaberDamage->integer ) + || g_dismemberment->integer >= 11381138 + || g_saberRealisticCombat->integer ) { //wait 100ms before allowing owner to be dismembered again cent->gent->aimDebounceTime = cg.time + 100; return; } + else + { + //done! + cent->gent->e_clThinkFunc = clThinkF_NULL; + } } } - //done! - cent->gent->e_clThinkFunc = clThinkF_NULL; } qboolean MatrixMode = qfalse; diff --git a/code/cgame/cg_event.cpp b/code/cgame/cg_event.cpp index 77b4601..c30eb5e 100644 --- a/code/cgame/cg_event.cpp +++ b/code/cgame/cg_event.cpp @@ -10,7 +10,6 @@ #include "..\game\anims.h" extern void CG_TryPlayCustomSound( vec3_t origin, int entityNum, soundChannel_t channel, const char *soundName, int customSoundSet ); -extern void CG_FireSeeker( centity_t *cent ); //========================================================================== @@ -68,17 +67,30 @@ CG_ItemPickup A new item was picked up this frame ================ */ -void CG_ItemPickup( int itemNum ) { +void CG_ItemPickup( int itemNum, qboolean bHadItem ) { cg.itemPickup = itemNum; cg.itemPickupTime = cg.time; cg.itemPickupBlendTime = cg.time; + + if (bg_itemlist[itemNum].classname && bg_itemlist[itemNum].classname[0]) + { + char text[1024], data[1024]; + if (cgi_SP_GetStringTextString("INGAME_PICKUPLINE",text, sizeof(text)) ) + { + if ( cgi_SP_GetStringTextString( va("INGAME_%s",bg_itemlist[itemNum].classname ), data, sizeof( data ))) + { + Com_Printf("%s %s\n", text, data ); + } + } + } + // see if it should be the grabbed weapon if ( bg_itemlist[itemNum].giType == IT_WEAPON ) { const int nCurWpn = cg.predicted_player_state.weapon; const int nNewWpn = bg_itemlist[itemNum].giTag; - if ( nCurWpn == WP_SABER ) + if ( nCurWpn == WP_SABER || bHadItem) {//never switch away from the saber! return; } @@ -92,7 +104,12 @@ void CG_ItemPickup( int itemNum ) { // NOTE: automatically switching to any weapon you pick up is stupid and annoying and we won't do it. // - if (0 == cg_autoswitch.integer) + if ( nNewWpn == WP_SABER ) + {//always switch to saber + SetWeaponSelectTime(); + cg.weaponSelect = nNewWpn; + } + else if (0 == cg_autoswitch.integer) { // don't switch } @@ -123,17 +140,6 @@ void CG_ItemPickup( int itemNum ) { } } } - if (bg_itemlist[itemNum].classname && bg_itemlist[itemNum].classname[0]) - { - char text[1024], data[1024]; - if (cgi_SP_GetStringTextString("INGAME_PICKUPLINE",text, sizeof(text)) ) - { - if ( cgi_SP_GetStringTextString( va("INGAME_%s",bg_itemlist[itemNum].classname ), data, sizeof( data ))) - { - Com_Printf("%s %s\n", text, data ); - } - } - } } @@ -159,24 +165,16 @@ void UseItem(int itemNum) case INV_LIGHTAMP_GOGGLES: CG_ToggleLAGoggles(); break; - case INV_GOODIE_KEY1: - case INV_GOODIE_KEY2: - case INV_GOODIE_KEY3: - case INV_GOODIE_KEY4: - case INV_GOODIE_KEY5: - if (cent->gent->client->ps.inventory[INV_GOODIE_KEY1]) + case INV_GOODIE_KEY: + if (cent->gent->client->ps.inventory[INV_GOODIE_KEY]) { - cent->gent->client->ps.inventory[INV_GOODIE_KEY1]--; + cent->gent->client->ps.inventory[INV_GOODIE_KEY]--; } break; - case INV_SECURITY_KEY1: - case INV_SECURITY_KEY2: - case INV_SECURITY_KEY3: - case INV_SECURITY_KEY4: - case INV_SECURITY_KEY5: - if (cent->gent->client->ps.inventory[INV_SECURITY_KEY1]) + case INV_SECURITY_KEY: + if (cent->gent->client->ps.inventory[INV_SECURITY_KEY]) { - cent->gent->client->ps.inventory[INV_SECURITY_KEY1]--; + cent->gent->client->ps.inventory[INV_SECURITY_KEY]--; } break; } @@ -240,7 +238,7 @@ An entity has an event value void CG_EntityEvent( centity_t *cent, vec3_t position ) { entityState_t *es; int event; - vec3_t dir, axis[3]; + vec3_t axis[3]; const char *s, *s2; int clientNum; //clientInfo_t *ci; @@ -300,14 +298,14 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { DEBUGNAME("EV_FOOTWADE"); if (cg_footsteps.integer) { cgi_S_StartSound (NULL, es->number, CHAN_BODY, - cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] ); + cgs.media.footsteps[ FOOTSTEP_WADE ][rand()&3] ); } break; case EV_SWIM: DEBUGNAME("EV_SWIM"); if (cg_footsteps.integer) { cgi_S_StartSound (NULL, es->number, CHAN_BODY, - cgs.media.footsteps[ FOOTSTEP_SPLASH ][rand()&3] ); + cgs.media.footsteps[ FOOTSTEP_SWIM ][rand()&3] ); } break; @@ -329,6 +327,10 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { {//dead cgi_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound ); } + else if ( g_entities[es->number].s.weapon == WP_SABER ) + {//jedi + CG_TryPlayCustomSound( NULL, es->number, CHAN_BODY, "*land1.wav", CS_BASIC ); + } else {//still alive CG_TryPlayCustomSound( NULL, es->number, CHAN_BODY, "*pain100.wav", CS_BASIC ); @@ -437,10 +439,17 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { { gitem_t *item; int index; - + qboolean bHadItem = qfalse; + index = es->eventParm; // player predicted - if ( index < 1 || index >= bg_numItems ) { + if ( (char)index < 0 ) + { + index = -(char)index; + bHadItem = qtrue; + } + + if ( index >= bg_numItems ) { break; } item = &bg_itemlist[ index ]; @@ -448,7 +457,7 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { // show icon and name on status bar if ( es->number == cg.snap->ps.clientNum ) { - CG_ItemPickup( index ); + CG_ItemPickup( index, bHadItem ); } } break; @@ -660,14 +669,12 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_MISSILE_HIT: DEBUGNAME("EV_MISSILE_HIT"); - ByteToDir( es->eventParm, dir ); - CG_MissileHitPlayer( cent, es->weapon, position, dir, cent->gent->alt_fire ); + CG_MissileHitPlayer( cent, es->weapon, position, cent->gent->pos1, cent->gent->alt_fire ); break; case EV_MISSILE_MISS: DEBUGNAME("EV_MISSILE_MISS"); - ByteToDir( es->eventParm, dir ); - CG_MissileHitWall( cent, es->weapon, position, dir, cent->gent->alt_fire ); + CG_MissileHitWall( cent, es->weapon, position, cent->gent->pos1, cent->gent->alt_fire ); break; case EV_BMODEL_SOUND: @@ -850,6 +857,17 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { DEBUGNAME("EV_CHOKEx"); CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, va("*choke%i.wav", event - EV_CHOKE1 + 1), CS_COMBAT ); break; + + case EV_FFWARN: //Warn ally to stop shooting you + DEBUGNAME("EV_FFWARN"); + CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, "*ffwarn.wav", CS_COMBAT ); + break; + + case EV_FFTURN: //Turn on ally after being shot by them + DEBUGNAME("EV_FFTURN"); + CG_TryPlayCustomSound( NULL, es->number, CHAN_VOICE, "*ffturn.wav", CS_COMBAT ); + break; + //extra sounds for ST case EV_CHASE1: case EV_CHASE2: diff --git a/code/cgame/cg_info.cpp b/code/cgame/cg_info.cpp index 8a93296..434653d 100644 --- a/code/cgame/cg_info.cpp +++ b/code/cgame/cg_info.cpp @@ -328,21 +328,25 @@ static void CG_LoadScreen_PersonalInfo(void) static void CG_LoadBar(void) { - int x,y,i,xLength,height,pad; - - y = 442; - pad = 5; - x = 202 + pad; - height = 12; - xLength = 21; + const int numticks = 9, tickwidth = 40, tickheight = 8; + const int tickpadx = 20, tickpady = 12; + const int capwidth = 8; + const int barwidth = numticks*tickwidth+tickpadx*2+capwidth*2, barleft = ((640-barwidth)/2); + const int barheight = tickheight + tickpady*2, bartop = 480-barheight; + const int capleft = barleft+tickpadx, tickleft = capleft+capwidth, ticktop = bartop+tickpady; cgi_R_SetColor( colorTable[CT_WHITE]); - CG_DrawPic(166,428,640-(164*2), 32, cgs.media.levelLoad); + // Draw background + CG_DrawPic(barleft, bartop, barwidth, barheight, cgs.media.levelLoad); - for (i=0;i < cg.loadLCARSStage;i++) - { - CG_DrawPic(x + (i*pad) + (i*xLength),y, 32, 8, cgs.media.loadTick); - } + // Draw left cap (backwards) + CG_DrawPic(tickleft, ticktop, -capwidth, tickheight, cgs.media.loadTickCap); + + // Draw bar + CG_DrawPic(tickleft, ticktop, tickwidth*cg.loadLCARSStage, tickheight, cgs.media.loadTick); + + // Draw right cap + CG_DrawPic(tickleft+tickwidth*cg.loadLCARSStage, ticktop, capwidth, tickheight, cgs.media.loadTickCap); } /* @@ -376,12 +380,13 @@ void CG_DrawInformation( void ) { CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, levelshot ); } - if ( !strcmp(s,"kejim_post") )//special case for first map! + if ( g_eSavedGameJustLoaded != eFULL && !strcmp(s,"kejim_post") )//special case for first map! { char text[1024]={0}; cgi_SP_GetStringTextString( "INGAME_ALONGTIME", text, sizeof(text) ); - int w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontMedium, 1.5f); - cgi_R_Font_DrawString((320)-(w/2), 140, text, colorTable[CT_ICON_BLUE], cgs.media.qhFontMedium, -1, 1.5f); + + int w = cgi_R_Font_StrLenPixels(text,cgs.media.qhFontMedium, 1.0f); + cgi_R_Font_DrawString((320)-(w/2), 140, text, colorTable[CT_ICON_BLUE], cgs.media.qhFontMedium, -1, 1.0f); } else if (cg_missionstatusscreen.integer ) diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h index 4b32fba..83e5a1f 100644 --- a/code/cgame/cg_local.h +++ b/code/cgame/cg_local.h @@ -256,7 +256,8 @@ typedef struct { #define CG_OVERRIDE_3RD_PERSON_VOF 0x00000008 #define CG_OVERRIDE_3RD_PERSON_POF 0x00000010 #define CG_OVERRIDE_3RD_PERSON_CDP 0x00000020 -#define CG_OVERRIDE_FOV 0x00000040 +#define CG_OVERRIDE_3RD_PERSON_APH 0x00000040 +#define CG_OVERRIDE_FOV 0x00000080 typedef struct { //NOTE: these probably get cleared in save/load!!! @@ -267,6 +268,7 @@ typedef struct { float thirdPersonVertOffset; //how high to be above them float thirdPersonPitchOffset; //what offset pitch to apply the the camera view float thirdPersonCameraDamp; //how tightly to move the camera pos behind the player + float thirdPersonAlpha; //how tightly to move the camera pos behind the player float fov; //what fov to use //NOTE: could put Alpha and HorzOffset and the target & camera damps, but no-one is trying to override those, so... } overrides_t; @@ -349,7 +351,6 @@ typedef struct { // information screen text during loading char infoScreenText[MAX_STRING_CHARS]; - qboolean showInformation; // centerprinting int centerPrintTime; @@ -413,8 +414,6 @@ typedef struct { int DataPadWeaponSelect; // Current weapon item chosen on Data Pad int DataPadforcepowerSelect; // Current force power chosen on Data Pad - int dataPadLevelStartTime; // Time until datapad won't pop up when level starts - qboolean messageLitActive; // Flag to show of message lite is active int weaponSelectTime; @@ -444,7 +443,6 @@ typedef struct { int missionInfoFlashTime; qboolean missionStatusShow; - int missionStatusShowTime; int missionStatusDeadTime; int HUDTickFlashTime; @@ -484,8 +482,11 @@ Ghoul2 Insert End } cg_t; -#define MAX_SHOWPOWERS 6 -extern int showPowers[8]; +#define MAX_SHOWPOWERS 7 +extern int showPowers[MAX_SHOWPOWERS]; +extern char *showPowersName[MAX_SHOWPOWERS]; +extern int force_icons[NUM_FORCE_POWERS]; +#define MAX_DPSHOWPOWERS 11 //============================================================================== @@ -545,6 +546,7 @@ extern vmCvar_t cg_crosshairX; extern vmCvar_t cg_crosshairY; extern vmCvar_t cg_crosshairSize; extern vmCvar_t cg_drawStatus; +extern vmCvar_t cg_drawHUD; extern vmCvar_t cg_draw2D; extern vmCvar_t cg_animSpeed; extern vmCvar_t cg_debugAnim; @@ -565,11 +567,14 @@ extern vmCvar_t cg_simpleItems; extern vmCvar_t cg_fov; extern vmCvar_t cg_missionstatusscreen; extern vmCvar_t cg_endcredits; -extern vmCvar_t cg_updatedDataPadForcePower; +extern vmCvar_t cg_updatedDataPadForcePower1; +extern vmCvar_t cg_updatedDataPadForcePower2; +extern vmCvar_t cg_updatedDataPadForcePower3; extern vmCvar_t cg_updatedDataPadObjective; extern vmCvar_t cg_thirdPerson; extern vmCvar_t cg_thirdPersonRange; +extern vmCvar_t cg_thirdPersonMaxRange; extern vmCvar_t cg_thirdPersonAngle; extern vmCvar_t cg_thirdPersonPitchOffset; extern vmCvar_t cg_thirdPersonVertOffset; @@ -602,7 +607,12 @@ extern vmCvar_t cg_debugBB; Ghoul2 Insert End */ extern vmCvar_t cg_turnAnims; +extern vmCvar_t cg_motionBoneComp; +extern vmCvar_t cg_reliableAnimSounds; + extern vmCvar_t cg_smoothPlayerPos; +extern vmCvar_t cg_smoothPlayerPlat; +extern vmCvar_t cg_smoothPlayerPlatAccel; void CG_NewClientinfo( int clientNum ); // @@ -858,6 +868,12 @@ void CG_ParseServerinfo( void ); void CG_Respawn( void ); void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ); +// cg_credits.cpp +// +void CG_Credits_Init( const char *psStripReference, vec4_t *pv4Color); +qboolean CG_Credits_Running( void ); +qboolean CG_Credits_Draw( void ); + //=============================================== @@ -1036,7 +1052,7 @@ int cgi_GetCurrentCmdNumber( void ); qboolean cgi_GetUserCmd( int cmdNumber, usercmd_t *ucmd ); // used for the weapon select and zoom -void cgi_SetUserCmdValue( int stateValue, float sensitivityScale ); +void cgi_SetUserCmdValue( int stateValue, float sensitivityScale, float mPitchOverride, float mYawOverride ); void cgi_SetUserCmdAngles( float pitchOverride, float yawOverride, float rollOverride ); void cgi_S_UpdateAmbientSet( const char *name, vec3_t origin ); @@ -1147,8 +1163,4 @@ void cgi_UI_String_Init(void); void SetWeaponSelectTime(void); -extern int force_icons[NUM_FORCE_POWERS]; -extern char *showPowersName[]; - - #endif //__CG_LOCAL_H__ diff --git a/code/cgame/cg_main.cpp b/code/cgame/cg_main.cpp index 7e0404d..5a2c999 100644 --- a/code/cgame/cg_main.cpp +++ b/code/cgame/cg_main.cpp @@ -67,6 +67,7 @@ char *inv_names[] = int force_icons[NUM_FORCE_POWERS]; + int cgi_UI_GetMenuInfo(char *menuFile,int *x,int *y); void CG_DrawDataPadHUD( centity_t *cent ); void MissionInformation_Draw( centity_t *cent ); @@ -141,16 +142,25 @@ Ghoul2 Insert End return 0; case CG_DRAW_DATAPAD_WEAPONS: - CG_DrawDataPadIconBackground(ICON_WEAPONS); - CG_DrawDataPadWeaponSelect(); + if (cg.snap) + { + CG_DrawDataPadIconBackground(ICON_WEAPONS); + CG_DrawDataPadWeaponSelect(); + } return 0; case CG_DRAW_DATAPAD_INVENTORY: - CG_DrawDataPadIconBackground(ICON_INVENTORY); - CG_DrawDataPadInventorySelect(); + if (cg.snap) + { + CG_DrawDataPadIconBackground(ICON_INVENTORY); + CG_DrawDataPadInventorySelect(); + } return 0; case CG_DRAW_DATAPAD_FORCEPOWERS: - CG_DrawDataPadIconBackground(ICON_FORCE); - CG_DrawDataPadForceSelect(); + if (cg.snap) + { + CG_DrawDataPadIconBackground(ICON_FORCE); + CG_DrawDataPadForceSelect(); + } return 0; } return -1; @@ -226,6 +236,7 @@ vmCvar_t cg_crosshairY; vmCvar_t cg_crosshairSize; vmCvar_t cg_draw2D; vmCvar_t cg_drawStatus; +vmCvar_t cg_drawHUD; vmCvar_t cg_animSpeed; vmCvar_t cg_debugAnim; vmCvar_t cg_debugSaber; @@ -245,11 +256,14 @@ vmCvar_t cg_simpleItems; vmCvar_t cg_fov; vmCvar_t cg_missionstatusscreen; vmCvar_t cg_endcredits; -vmCvar_t cg_updatedDataPadForcePower; +vmCvar_t cg_updatedDataPadForcePower1; +vmCvar_t cg_updatedDataPadForcePower2; +vmCvar_t cg_updatedDataPadForcePower3; vmCvar_t cg_updatedDataPadObjective; vmCvar_t cg_thirdPerson; vmCvar_t cg_thirdPersonRange; +vmCvar_t cg_thirdPersonMaxRange; vmCvar_t cg_thirdPersonAngle; vmCvar_t cg_thirdPersonPitchOffset; vmCvar_t cg_thirdPersonVertOffset; @@ -259,6 +273,7 @@ vmCvar_t cg_saberAutoThird; vmCvar_t cg_gunAutoFirst; vmCvar_t cg_thirdPersonAlpha; +vmCvar_t cg_thirdPersonAutoAlpha; vmCvar_t cg_thirdPersonHorzOffset; vmCvar_t cg_stereoSeparation; @@ -285,8 +300,12 @@ Ghoul2 Insert End vmCvar_t cg_VariantSoundCap; // 0 = no capping, else cap to (n) max (typically just 1, but allows more) vmCvar_t cg_turnAnims; +vmCvar_t cg_motionBoneComp; +vmCvar_t cg_reliableAnimSounds; vmCvar_t cg_smoothPlayerPos; +vmCvar_t cg_smoothPlayerPlat; +vmCvar_t cg_smoothPlayerPlatAccel; typedef struct { vmCvar_t *vmCvar; @@ -304,6 +323,7 @@ cvarTable_t cvarTable[] = { { &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE }, { &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE }, + { &cg_drawHUD, "cg_drawHUD", "1", 0 }, { &cg_drawTimer, "cg_drawTimer", "0", CVAR_ARCHIVE }, { &cg_drawFPS, "cg_drawFPS", "0", CVAR_ARCHIVE }, { &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE }, @@ -314,7 +334,9 @@ cvarTable_t cvarTable[] = { { &cg_crosshairForceHint, "cg_crosshairForceHint", "1", CVAR_ARCHIVE }, { &cg_missionstatusscreen, "cg_missionstatusscreen", "0", CVAR_ROM}, { &cg_endcredits, "cg_endcredits", "0", 0}, - { &cg_updatedDataPadForcePower, "cg_updatedDataPadForcePower", "0", 0}, + { &cg_updatedDataPadForcePower1, "cg_updatedDataPadForcePower1", "0", 0}, + { &cg_updatedDataPadForcePower2, "cg_updatedDataPadForcePower2", "0", 0}, + { &cg_updatedDataPadForcePower3, "cg_updatedDataPadForcePower3", "0", 0}, { &cg_updatedDataPadObjective, "cg_updatedDataPadObjective", "0", 0}, { &cg_crosshairSize, "cg_crosshairSize", "24", CVAR_ARCHIVE }, @@ -347,6 +369,7 @@ cvarTable_t cvarTable[] = { { &cg_thirdPerson, "cg_thirdPerson", "0", CVAR_USERINFO }, { &cg_thirdPersonRange, "cg_thirdPersonRange", "80", 0 }, + { &cg_thirdPersonMaxRange, "cg_thirdPersonMaxRange", "150", 0 }, { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", 0 }, { &cg_thirdPersonPitchOffset, "cg_thirdPersonPitchOffset", "0", 0 }, { &cg_thirdPersonVertOffset, "cg_thirdPersonVertOffset", "16", 0}, @@ -355,6 +378,7 @@ cvarTable_t cvarTable[] = { { &cg_thirdPersonHorzOffset, "cg_thirdPersonHorzOffset", "0", 0}, { &cg_thirdPersonAlpha, "cg_thirdPersonAlpha", "1.0", CVAR_CHEAT }, + { &cg_thirdPersonAutoAlpha, "cg_thirdPersonAutoAlpha", "0", 0 }, { &cg_saberAutoThird, "cg_saberAutoThird", "1", CVAR_ARCHIVE }, { &cg_gunAutoFirst, "cg_gunAutoFirst", "1", CVAR_ARCHIVE }, @@ -371,7 +395,7 @@ cvarTable_t cvarTable[] = { { &cg_developer, "developer", "", 0 }, { &cg_timescale, "timescale", "1", 0 }, { &cg_skippingcin, "skippingCinematic", "0", CVAR_ROM}, - { &cg_missionInfoFlashTime, "cg_missionInfoFlashTime", "15000", CVAR_ARCHIVE }, + { &cg_missionInfoFlashTime, "cg_missionInfoFlashTime", "10000", 0 }, { &cg_hudFiles, "cg_hudFiles", "ui/jk2hud.txt", CVAR_ARCHIVE}, /* Ghoul2 Insert Start @@ -381,8 +405,12 @@ Ghoul2 Insert Start Ghoul2 Insert End */ { &cg_VariantSoundCap, "cg_VariantSoundCap", "0", 0 }, - { &cg_turnAnims, "cg_turnAnims", "0", CVAR_ARCHIVE }, + { &cg_turnAnims, "cg_turnAnims", "0", 0 }, + { &cg_motionBoneComp, "cg_motionBoneComp", "2", 0 }, + { &cg_reliableAnimSounds, "cg_reliableAnimSounds", "1", CVAR_ARCHIVE }, { &cg_smoothPlayerPos, "cg_smoothPlayerPos", "0.5", 0}, + { &cg_smoothPlayerPlat, "cg_smoothPlayerPlat", "0.75", 0}, + { &cg_smoothPlayerPlatAccel, "cg_smoothPlayerPlatAccel", "3.25", 0}, }; int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] ); @@ -435,8 +463,25 @@ int CG_GetCameraPos( vec3_t camerapos ) { else if ( cg_entities[0].gent && cg_entities[0].gent->client && cg_entities[0].gent->client->ps.viewEntity > 0 && cg_entities[0].gent->client->ps.viewEntity < ENTITYNUM_WORLD ) //else if ( cg.snap && cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD ) {//in an entity camera view - //VectorCopy( cg_entities[cg.snap->ps.viewEntity].lerpOrigin, camerapos ); - VectorCopy( cg_entities[cg_entities[0].gent->client->ps.viewEntity].lerpOrigin, camerapos ); + if ( g_entities[cg_entities[0].gent->client->ps.viewEntity].client && cg.renderingThirdPerson ) + { + VectorCopy( g_entities[cg_entities[0].gent->client->ps.viewEntity].client->renderInfo.eyePoint, camerapos ); + } + else + { + VectorCopy( g_entities[cg_entities[0].gent->client->ps.viewEntity].currentOrigin, camerapos ); + } + //VectorCopy( cg_entities[cg_entities[0].gent->client->ps.viewEntity].lerpOrigin, camerapos ); + /* + if ( g_entities[cg.snap->ps.viewEntity].client && cg.renderingThirdPerson ) + { + VectorCopy( g_entities[cg.snap->ps.viewEntity].client->renderInfo.eyePoint, camerapos ); + } + else + {//use the g_ent because it may not have gotten over to the client yet... + VectorCopy( g_entities[cg.snap->ps.viewEntity].currentOrigin, camerapos ); + } + */ return 1; } else if ( cg.renderingThirdPerson ) @@ -445,6 +490,11 @@ int CG_GetCameraPos( vec3_t camerapos ) { VectorCopy( cg.refdef.vieworg, camerapos ); return 1; } + else if (cg.snap && (cg.snap->ps.weapon == WP_SABER||cg.snap->ps.weapon == WP_MELEE) )//implied: !cg.renderingThirdPerson + {//first person saber hack + VectorCopy( cg.refdef.vieworg, camerapos ); + return 1; + } return 0; } @@ -563,6 +613,25 @@ void CG_LoadingString( const char *s ) { cgi_UpdateScreen(); } + +static void CG_AS_Register(void) +{ + CG_LoadingString( "ambient sound sets" ); + + //Load the ambient sets + + cgi_AS_AddPrecacheEntry( "#clear" ); // ;-) + //FIXME: Don't ask... I had to get around a really nasty MS error in the templates with this... + namePrecache_m::iterator pi; + STL_ITERATE( pi, as_preCacheMap ) + { + cgi_AS_AddPrecacheEntry( ((*pi).first).c_str() ); + } + + cgi_AS_ParseSets(); +} + + /* ================= CG_RegisterSounds @@ -575,18 +644,7 @@ static void CG_RegisterSounds( void ) { char name[MAX_QPATH]; const char *soundName; - CG_LoadingString( "ambient sound sets" ); - - //Load the ambient sets - - //FIXME: Don't ask... I had to get around a really nasty MS error in the templates with this... - namePrecache_m::iterator pi; - STL_ITERATE( pi, as_preCacheMap ) - { - cgi_AS_AddPrecacheEntry( ((*pi).first).c_str() ); - } - - cgi_AS_ParseSets(); + CG_AS_Register(); CG_LoadingString( "general sounds" ); @@ -594,6 +652,7 @@ static void CG_RegisterSounds( void ) { cgi_S_RegisterSound( "sound/player/fallsplat.wav" ); cgs.media.selectSound = cgi_S_RegisterSound( "sound/weapons/change.wav" ); + cgs.media.selectSound2 = cgi_S_RegisterSound( "sound/interface/button1.wav" ); // cgs.media.useNothingSound = cgi_S_RegisterSound( "sound/items/use_nothing.wav" ); cgs.media.noAmmoSound = cgi_S_RegisterSound( "sound/weapons/noammo.wav" ); @@ -625,25 +684,30 @@ static void CG_RegisterSounds( void ) { cgs.media.zoomLoop = cgi_S_RegisterSound( "sound/interface/zoomloop.wav" ); cgs.media.zoomEnd = cgi_S_RegisterSound( "sound/interface/zoomend.wav" ); - // TEMP: FIXME: TODO: would like to be able to do this conditionally, personal assault sentry guns. - //---------------- cgi_S_RegisterSound( "sound/chars/turret/startup.wav" ); cgi_S_RegisterSound( "sound/chars/turret/shutdown.wav" ); cgi_S_RegisterSound( "sound/chars/turret/ping.wav" ); cgi_S_RegisterSound( "sound/chars/turret/move.wav" ); + cgi_S_RegisterSound( "sound/player/use_sentry" ); cgi_R_RegisterModel( "models/items/psgun.glm" ); - theFxScheduler.RegisterEffect( "tripMine/explosion" ); - //---------------- + theFxScheduler.RegisterEffect( "turret/explode" ); + theFxScheduler.RegisterEffect( "spark_exp_nosnd" ); for (i=0 ; i<4 ; i++) { - Com_sprintf (name, sizeof(name), "sound/player/footsteps/step%i.wav", i+1); + Com_sprintf (name, sizeof(name), "sound/player/footsteps/stone_step%i.wav", i+1); cgs.media.footsteps[FOOTSTEP_NORMAL][i] = cgi_S_RegisterSound (name); - Com_sprintf (name, sizeof(name), "sound/player/footsteps/water_wade0%i.wav", i+1); + Com_sprintf (name, sizeof(name), "sound/player/footsteps/metal_step%i.wav", i+1); + cgs.media.footsteps[FOOTSTEP_METAL][i] = cgi_S_RegisterSound (name); + + Com_sprintf (name, sizeof(name), "sound/player/footsteps/water_run%i.wav", i+1); cgs.media.footsteps[FOOTSTEP_SPLASH][i] = cgi_S_RegisterSound (name); - Com_sprintf (name, sizeof(name), "sound/player/footsteps/clank%i.wav", i+1); - cgs.media.footsteps[FOOTSTEP_METAL][i] = cgi_S_RegisterSound (name); + Com_sprintf (name, sizeof(name), "sound/player/footsteps/water_walk%i.wav", i+1); + cgs.media.footsteps[FOOTSTEP_WADE][i] = cgi_S_RegisterSound (name); + + Com_sprintf (name, sizeof(name), "sound/player/footsteps/water_wade_0%i.wav", i+1); + cgs.media.footsteps[FOOTSTEP_SWIM][i] = cgi_S_RegisterSound (name); // should these always be registered?? Com_sprintf (name, sizeof(name), "sound/player/footsteps/boot%i.wav", i+1); @@ -655,11 +719,11 @@ static void CG_RegisterSounds( void ) { CG_LoadingString( "item sounds" ); // only register the items that the server says we need -// char items[MAX_ITEMS+1]; -// strcpy( items, CG_ConfigString( CS_ITEMS ) ); + char items[MAX_ITEMS+1]; + strcpy( items, CG_ConfigString( CS_ITEMS ) ); for ( i = 1 ; i < bg_numItems ; i++ ) { -// if ( items[ i ] == '1' ) //sound pooling means we can just load them always + if ( items[ i ] == '1' ) //even with sound pooling, don't clutter it for low end machines { CG_RegisterItemSounds( i ); } @@ -1202,16 +1266,19 @@ static void CG_RegisterGraphics( void ) { cgs.media.chunkModels[CHUNK_ROCK3][i] = cgi_R_RegisterModel( va( "models/chunks/rock/rock3_%i.md3", i+1 ) ); cgs.media.chunkModels[CHUNK_CRATE1][i] = cgi_R_RegisterModel( va( "models/chunks/crate/crate1_%i.md3", i+1 ) ); cgs.media.chunkModels[CHUNK_CRATE2][i] = cgi_R_RegisterModel( va( "models/chunks/crate/crate2_%i.md3", i+1 ) ); + cgs.media.chunkModels[CHUNK_WHITE_METAL][i] = cgi_R_RegisterModel( va( "models/chunks/metal/wmetal1_%i.md3", i+1 ) ); } - cgs.media.chunkSound = cgi_S_RegisterSound("sound/weapons/explosions/glasslcar.wav"); - cgs.media.grateSound = cgi_S_RegisterSound( "sound/effects/grate_destroy.mp3" ); - cgs.media.rockBreakSound = cgi_S_RegisterSound("sound/effects/wall_smash.mp3"); - cgs.media.rockBounceSound[0]= cgi_S_RegisterSound("sound/effects/stone_bounce.wav"); - cgs.media.rockBounceSound[1]= cgi_S_RegisterSound("sound/effects/stone_bounce2.wav"); - cgs.media.metalBounceSound[0] = cgi_S_RegisterSound("sound/effects/metal_bounce.wav"); - cgs.media.metalBounceSound[1] = cgi_S_RegisterSound("sound/effects/metal_bounce2.wav"); - cgs.media.glassChunkSound = cgi_S_RegisterSound("sound/weapons/explosions/glassbreak1.wav"); + cgs.media.chunkSound = cgi_S_RegisterSound("sound/weapons/explosions/glasslcar"); + cgs.media.grateSound = cgi_S_RegisterSound( "sound/effects/grate_destroy" ); + cgs.media.rockBreakSound = cgi_S_RegisterSound("sound/effects/wall_smash"); + cgs.media.rockBounceSound[0] = cgi_S_RegisterSound("sound/effects/stone_bounce"); + cgs.media.rockBounceSound[1] = cgi_S_RegisterSound("sound/effects/stone_bounce2"); + cgs.media.metalBounceSound[0] = cgi_S_RegisterSound("sound/effects/metal_bounce"); + cgs.media.metalBounceSound[1] = cgi_S_RegisterSound("sound/effects/metal_bounce2"); + cgs.media.glassChunkSound = cgi_S_RegisterSound("sound/weapons/explosions/glassbreak1"); + cgs.media.crateBreakSound[0] = cgi_S_RegisterSound("sound/weapons/explosions/crateBust1" ); + cgs.media.crateBreakSound[1] = cgi_S_RegisterSound("sound/weapons/explosions/crateBust2" ); cgs.media.weaponbox = cgi_R_RegisterShaderNoMip( "gfx/interface/weapon_box"); @@ -1236,8 +1303,11 @@ static void CG_RegisterGraphics( void ) { cgs.media.messageLitOff = cgi_R_RegisterShaderNoMip( "gfx/hud/message_off" ); cgs.media.messageObjCircle = cgi_R_RegisterShaderNoMip( "gfx/hud/objective_circle" ); + cgs.media.DPForcePowerOverlay = cgi_R_RegisterShader( "gfx/hud/force_swirl" ); + // battery charge shader when using a gonk cgs.media.batteryChargeShader = cgi_R_RegisterShader( "gfx/2d/battery" ); + cgi_R_RegisterShader( "gfx/2d/droid_view" ); // Load force tics for (i=0;iinteger) { - cgi_R_RegisterShader( "gfx/2d/droid_view" ); cgi_R_RegisterShader( "gfx/misc/nav_cpoint" ); cgi_R_RegisterShader( "gfx/misc/nav_line" ); cgi_R_RegisterShader( "gfx/misc/nav_arrow" ); @@ -1554,8 +1623,6 @@ Ghoul2 Insert End CG_ClearLightStyles(); - cg.dataPadLevelStartTime = cg.time+15000; - } void CG_WriteTheEvilCGHackStuff(void) @@ -1632,6 +1699,8 @@ Called after every level change or subsystem restart void CG_Init( int serverCommandSequence ) { cgs.serverCommandSequence = serverCommandSequence; + cgi_Cvar_Set( "cg_drawHUD", "1" ); + // fonts... // cgs.media.charsetShader = cgi_R_RegisterShaderNoMip("gfx/2d/charsgrid_med"); @@ -1640,7 +1709,8 @@ void CG_Init( int serverCommandSequence ) { cgs.media.qhFontMedium= cgi_R_RegisterFont("ergoec"); cgs.media.whiteShader = cgi_R_RegisterShader( "white" ); - cgs.media.loadTick = cgi_R_RegisterShaderNoMip( "gfx/hud/load_tick" ); + cgs.media.loadTick = cgi_R_RegisterShaderNoMip( "gfx/hud/load_tick" ); + cgs.media.loadTickCap = cgi_R_RegisterShaderNoMip( "gfx/hud/load_tick_cap" ); static char *force_icon_files[NUM_FORCE_POWERS] = { @@ -1705,6 +1775,7 @@ Called before every level change or subsystem restart */ void CG_Shutdown( void ) { + in_camera = false; FX_Free(); } @@ -2521,6 +2592,7 @@ void CG_NextInventory_f( void ) if ( CG_InventorySelectable( cg.inventorySelect ) && (inv_icons[cg.inventorySelect])) { + cgi_S_StartSound (NULL, 0, CHAN_AUTO, cgs.media.selectSound2 ); SetInventoryTime(); return; } @@ -2574,6 +2646,7 @@ void CG_PrevInventory_f( void ) if ( CG_InventorySelectable( cg.inventorySelect ) && (inv_icons[cg.inventorySelect])) { + cgi_S_StartSound (NULL, 0, CHAN_AUTO, cgs.media.selectSound2 ); SetInventoryTime(); return; } @@ -2653,6 +2726,7 @@ void CG_DrawInventorySelect( void ) // int tag; float addX; vec4_t textColor = { .312f, .75f, .621f, 1.0f }; + char text[1024]={0}; // don't display if dead if ( cg.predicted_player_state.stats[STAT_HEALTH] <= 0 || ( cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD )) @@ -2690,7 +2764,10 @@ void CG_DrawInventorySelect( void ) if (!count) { - CG_DrawProportionalString(320, y2 + 22, "EMPTY INVENTORY", CG_CENTER | CG_SMALLFONT, colorTable[CT_ICON_BLUE]); + cgi_SP_GetStringTextString("INGAME_EMPTY_INV",text, sizeof(text) ); + int w = cgi_R_Font_StrLenPixels( text, cgs.media.qhFontSmall, 1.0f ); + x = ( SCREEN_WIDTH - w ) / 2; + CG_DrawProportionalString(x, y2 + 22, text, CG_CENTER | CG_SMALLFONT, colorTable[CT_ICON_BLUE]); return; } @@ -2846,16 +2923,8 @@ char *inventoryDesc[15] = "INQUISITOR_DESC", "LA_GOGGLES_DESC", "PORTABLE_SENTRY_DESC", -"SECURITY_KEY_DESC", -"SECURITY_KEY_DESC", -"SECURITY_KEY_DESC", -"SECURITY_KEY_DESC", -"SECURITY_KEY_DESC", -"SECURITY_KEY_DESC", -"SECURITY_KEY_DESC", -"SECURITY_KEY_DESC", -"SECURITY_KEY_DESC", -"SECURITY_KEY_DESC", +"GOODIE_KEY_DESC", +"SECURITY_KEY_DP_DESC", }; @@ -2875,6 +2944,7 @@ void CG_DrawDataPadInventorySelect( void ) int height; float addX; char text[1024]={0}; + vec4_t textColor = { .312f, .75f, .621f, 1.0f }; // count the number of items owned @@ -2891,7 +2961,9 @@ void CG_DrawDataPadInventorySelect( void ) if (!count) { cgi_SP_GetStringTextString("INGAME_EMPTY_INV",text, sizeof(text) ); - CG_DrawProportionalString(320, 300 + 22, text, CG_CENTER | CG_SMALLFONT, colorTable[CT_ICON_BLUE]); + int w = cgi_R_Font_StrLenPixels( text, cgs.media.qhFontSmall, 1.0f ); + x = ( SCREEN_WIDTH - w ) / 2; + CG_DrawProportionalString(x, 300 + 22, text, CG_CENTER | CG_SMALLFONT, colorTable[CT_ICON_BLUE]); return; } @@ -2915,9 +2987,8 @@ void CG_DrawDataPadInventorySelect( void ) sideRightIconCnt = holdCount - sideLeftIconCnt; } - char buffer[256]; - - cgi_UI_GetItemText("datapadInventoryMenu",va("invdesc%d",cg.DataPadInventorySelect+1),buffer); +// char buffer[256]; +// cgi_UI_GetItemText("datapadInventoryMenu",va("invdesc%d",cg.DataPadInventorySelect+1),buffer); i = cg.DataPadInventorySelect - 1; if (i<0) @@ -3040,7 +3111,7 @@ void CG_DrawDataPadInventorySelect( void ) CG_DisplayBoxedText(70,50,500,300,text, cgs.media.qhFontSmall, 0.7f, - colorTable[CT_WHITE] + textColor ); } } @@ -3066,7 +3137,7 @@ void SetForcePowerTime(void) } } -int showPowers[] = +int showPowers[MAX_SHOWPOWERS] = { FP_HEAL, FP_SPEED, @@ -3074,23 +3145,9 @@ int showPowers[] = FP_PULL, FP_TELEPATHY, FP_GRIP, - FP_LIGHTNING, - NUM_FORCE_POWERS, + FP_LIGHTNING }; -/* -char *showPowersName[] = -{ - "Heal", - "Speed", - "Push", - "Pull", - "Mind Trick", - "Grip", - "Lightning", - NULL, -}; -*/ -char *showPowersName[] = +char *showPowersName[MAX_SHOWPOWERS] = { "HEAL2", "SPEED2", @@ -3099,10 +3156,9 @@ char *showPowersName[] = "MINDTRICK2", "GRIP2", "LIGHTNING2", - NULL, }; -int showDataPadPowers[] = +int showDataPadPowers[MAX_DPSHOWPOWERS] = { FP_HEAL, FP_LEVITATION, @@ -3115,10 +3171,9 @@ int showDataPadPowers[] = FP_SABERTHROW, FP_SABER_DEFENSE, FP_SABER_OFFENSE, - NUM_FORCE_POWERS, }; -char *showDataPadPowersName[] = +/*char *showDataPadPowersName[MAX_DPSHOWPOWERS] = { "HEAL2", "JUMP2", @@ -3131,8 +3186,9 @@ char *showDataPadPowersName[] = "SABER_THROW2", "SABER_DEFENSE2", "SABER_OFFENSE2", - NULL, }; +/* + /* =============== ForcePower_Valid @@ -3142,6 +3198,8 @@ qboolean ForcePower_Valid(int index) { gentity_t *player = &g_entities[0]; + assert (MAX_SHOWPOWERS == ( sizeof(showPowers)/sizeof(showPowers[0]) )); + assert (index < MAX_SHOWPOWERS ); //is this a valid index? if (player->client->ps.forcePowersKnown & (1 << showPowers[index]) && player->client->ps.forcePowerLevel[showPowers[index]]) // Does he have the force power? { @@ -3178,13 +3236,14 @@ void CG_NextForcePower_f( void ) { cg.forcepowerSelect++; - if (showPowers[cg.forcepowerSelect] >= NUM_FORCE_POWERS) + if (cg.forcepowerSelect >= MAX_SHOWPOWERS) { cg.forcepowerSelect = 0; } if (ForcePower_Valid(cg.forcepowerSelect)) // Does he have the force power? { + cgi_S_StartSound (NULL, 0, CHAN_AUTO, cgs.media.selectSound2 ); return; } } @@ -3221,11 +3280,12 @@ void CG_PrevForcePower_f( void ) if (cg.forcepowerSelect < 0) { - cg.forcepowerSelect = MAX_SHOWPOWERS; + cg.forcepowerSelect = MAX_SHOWPOWERS - 1; } if (ForcePower_Valid(cg.forcepowerSelect)) // Does he have the force power? { + cgi_S_StartSound (NULL, 0, CHAN_AUTO, cgs.media.selectSound2 ); return; } } @@ -3264,7 +3324,7 @@ void CG_DrawForceSelect( void ) // count the number of powers owned count = 0; - for (i=0;showPowers[i]!=NUM_FORCE_POWERS;++i) + for (i=0; iMAX_SHOWPOWERS) + if (i>=MAX_SHOWPOWERS) { i = 0; } @@ -3367,7 +3427,7 @@ void CG_DrawForceSelect( void ) holdX = x + (bigIconSize/2) + pad; for (iconCnt=1;iconCnt<(sideRightIconCnt+1);i++) { - if (i>MAX_SHOWPOWERS) + if (i>=MAX_SHOWPOWERS) { i = 0; } @@ -3395,6 +3455,25 @@ void CG_DrawForceSelect( void ) } } +/* +=============== +ForcePowerDataPad_Valid +=============== +*/ +qboolean ForcePowerDataPad_Valid(int index) +{ + gentity_t *player = &g_entities[0]; + + assert (index < MAX_DPSHOWPOWERS); + if (player->client->ps.forcePowersKnown & (1 << showDataPadPowers[index]) && + player->client->ps.forcePowerLevel[showDataPadPowers[index]]) // Does he have the force power? + { + return qtrue; + } + + return qfalse; +} + /* =============== CG_DPNextForcePower_f @@ -3412,16 +3491,16 @@ void CG_DPNextForcePower_f( void ) original = cg.DataPadforcepowerSelect; - for ( i = 0 ;showDataPadPowers[i]!=NUM_FORCE_POWERS ; i++ ) + for ( i = 0; i= NUM_FORCE_POWERS) + if (cg.DataPadforcepowerSelect >= MAX_DPSHOWPOWERS) { cg.DataPadforcepowerSelect = 0; } - if (ForcePower_Valid(i)) // Does he have the force power? + if (ForcePowerDataPad_Valid(cg.DataPadforcepowerSelect)) // Does he have the force power? { return; } @@ -3447,16 +3526,16 @@ void CG_DPPrevForcePower_f( void ) original = cg.DataPadforcepowerSelect; - for ( i = 0 ;showDataPadPowers[i]!=NUM_FORCE_POWERS ; i++ ) + for ( i = 0; iclient->ps.forcePowersKnown & (1 << showDataPadPowers[index]) && - player->client->ps.forcePowerLevel[showDataPadPowers[index]]) // Does he have the force power? - { - return qtrue; - } - - return qfalse; -} /* =================== CG_DrawDataPadForceSelect @@ -3562,7 +3624,7 @@ void CG_DrawDataPadForceSelect( void ) // count the number of powers owned count = 0; - for (i=0;showDataPadPowers[i]!=NUM_FORCE_POWERS;++i) + for (i=0;i=NUM_FORCE_POWERS) + if (i>=MAX_DPSHOWPOWERS) { i = 0; } @@ -3655,7 +3743,7 @@ void CG_DrawDataPadForceSelect( void ) holdX = x + (bigIconSize/2) + pad; for (iconCnt=1;iconCnt<(sideRightIconCnt+1);i++) { - if (i>=NUM_FORCE_POWERS) + if (i>=MAX_DPSHOWPOWERS) { i = 0; } @@ -3670,6 +3758,18 @@ void CG_DrawDataPadForceSelect( void ) if (force_icons[showDataPadPowers[i]]) { CG_DrawPic( holdX, y, smallIconSize, smallIconSize, force_icons[showDataPadPowers[i]] ); //only cache the icon for display + } + + // A new force power + if (((cg_updatedDataPadForcePower1.integer - 1) == showDataPadPowers[i]) || + ((cg_updatedDataPadForcePower2.integer - 1) == showDataPadPowers[i]) || + ((cg_updatedDataPadForcePower3.integer - 1) == showDataPadPowers[i])) + { + CG_DrawPic( holdX, y, smallIconSize, smallIconSize, cgs.media.DPForcePowerOverlay ); //only cache the icon for display + } + + if (force_icons[showDataPadPowers[i]]) + { holdX += (smallIconSize+pad); } } @@ -3695,7 +3795,7 @@ void CG_DrawDataPadForceSelect( void ) CG_DisplayBoxedText(70,50,500,300,va("%s%s",text,text2), cgs.media.qhFontSmall, 0.7f, - colorTable[CT_WHITE] + colorTable[CT_ICON_BLUE] ); } } diff --git a/code/cgame/cg_media.h b/code/cgame/cg_media.h index 10166a8..0636b73 100644 --- a/code/cgame/cg_media.h +++ b/code/cgame/cg_media.h @@ -1,13 +1,14 @@ #ifndef __CG_MEDIA_H_ #define __CG_MEDIA_H_ -#define NUM_CROSSHAIRS 12 +#define NUM_CROSSHAIRS 10 typedef enum { FOOTSTEP_NORMAL, FOOTSTEP_METAL, FOOTSTEP_SPLASH, - FOOTSTEP_BORG, + FOOTSTEP_WADE, + FOOTSTEP_SWIM, FOOTSTEP_TOTAL } footstep_t; @@ -41,6 +42,7 @@ typedef enum CHUNK_ROCK3, CHUNK_CRATE1, CHUNK_CRATE2, + CHUNK_WHITE_METAL, NUM_CHUNK_TYPES }; @@ -62,6 +64,7 @@ typedef struct { qhandle_t chunkyNumberShaders[11]; qhandle_t loadTick; + qhandle_t loadTickCap; // HUD artwork int currentBackground; @@ -87,6 +90,7 @@ typedef struct { sfxHandle_t rockBounceSound[2]; sfxHandle_t metalBounceSound[2]; sfxHandle_t glassChunkSound; + sfxHandle_t crateBreakSound[2]; // Saber shaders //----------------------------- @@ -177,14 +181,15 @@ typedef struct { qhandle_t HUDArmorTic; qhandle_t HUDInnerLeft; - qhandle_t HUDSaberStyle1; - qhandle_t HUDSaberStyle2; - qhandle_t HUDSaberStyle3; + qhandle_t HUDSaberStyleFast; + qhandle_t HUDSaberStyleMed; + qhandle_t HUDSaberStyleStrong; qhandle_t HUDRightFrame; qhandle_t HUDInnerRight; qhandle_t dataPadFrame; + qhandle_t DPForcePowerOverlay; qhandle_t talkingtop; qhandle_t talkingbot; @@ -215,6 +220,7 @@ typedef struct { sfxHandle_t tripMineStickSound; sfxHandle_t selectSound; + sfxHandle_t selectSound2; sfxHandle_t overchargeSlowSound; sfxHandle_t overchargeFastSound; sfxHandle_t overchargeLoopSound; @@ -286,6 +292,9 @@ typedef struct fxHandle_t forceConfusion; fxHandle_t forceLightning; fxHandle_t forceLightningWide; + fxHandle_t forceInvincibility; + fxHandle_t forceHeal; + } cgEffects_t; diff --git a/code/cgame/cg_players.cpp b/code/cgame/cg_players.cpp index d5771bb..106ca58 100644 --- a/code/cgame/cg_players.cpp +++ b/code/cgame/cg_players.cpp @@ -26,7 +26,7 @@ qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *headModelName const char *torsoModelName, const char *torsoSkinName, const char *legsModelName, const char *legsSkinName ); -void CG_PlayerAnimSounds( animsounds_t *animSounds, int frame, int entNum ); +void CG_PlayerAnimSounds( int animFileIndex, qboolean torso, int oldFrame, int frame, int entNum ); extern void BG_G2SetBoneAngles( centity_t *cent, gentity_t *gent, int boneIndex, const vec3_t angles, const int flags, const Eorientations up, const Eorientations left, const Eorientations forward, qhandle_t *modelList ); extern void FX_BorgDeathSparkParticles( vec3_t origin, vec3_t angles, vec3_t vel, vec3_t user ); @@ -73,6 +73,8 @@ const char *cg_customCombatSoundNames[MAX_CUSTOM_COMBAT_SOUNDS] = "*choke1.wav", "*choke2.wav", "*choke3.wav", + "*ffwarn.wav", + "*ffturn.wav", }; //Used as a supplement to the basic set for stormtroopers @@ -92,18 +94,18 @@ const char *cg_customExtraSoundNames[MAX_CUSTOM_EXTRA_SOUNDS] = "*detected3.wav", "*detected4.wav", "*detected5.wav", - "*giveup1.wav", - "*giveup2.wav", - "*giveup3.wav", - "*giveup4.wav", - "*look1.wav", - "*look2.wav", "*lost1.wav", "*outflank1.wav", "*outflank2.wav", "*escaping1.wav", "*escaping2.wav", "*escaping3.wav", + "*giveup1.wav", + "*giveup2.wav", + "*giveup3.wav", + "*giveup4.wav", + "*look1.wav", + "*look2.wav", "*sight1.wav", "*sight2.wav", "*sight3.wav", @@ -543,7 +545,7 @@ PLAYER ANIMATION qboolean ValidAnimFileIndex ( int index ) { - if ( index < 0 || index >= MAX_ANIM_FILES ) + if ( index < 0 || index >= level.numKnownAnimFileSets ) { Com_Printf( S_COLOR_RED "Bad animFileIndex: %d\n", index ); return qfalse; @@ -576,6 +578,10 @@ void ParseAnimationSndBlock(const char *asb_filename, animsounds_t *animSounds, // read information for each frame while ( 1 ) { + if (*i >= MAX_ANIM_SOUNDS) + { + CG_Error( "ParseAnimationSndBlock: animation number >= MAX_ANIM_SOUNDS(%i)", MAX_ANIM_SOUNDS ); + } // Get base frame of sequence token = COM_Parse( text_p ); if ( !token || !token[0]) @@ -725,6 +731,8 @@ void CG_ParseAnimationSndFile( const char *as_filename, int animFileIndex ) char sfilename[MAX_QPATH]; fileHandle_t f; int i, j, upper_i, lower_i; + + assert(animFileIndex < MAX_ANIM_FILES); animsounds_t *legsAnimSnds = level.knownAnimFileSets[animFileIndex].legsAnimSnds; animsounds_t *torsoAnimSnds = level.knownAnimFileSets[animFileIndex].torsoAnimSnds; animation_t *animations = level.knownAnimFileSets[animFileIndex].animations; @@ -803,16 +811,24 @@ void CG_SetLerpFrameAnimation( clientInfo_t *ci, lerpFrame_t *lf, int newAnimati { animation_t *anim; - lf->animationNumber = newAnimation; - if ( newAnimation < 0 || newAnimation >= MAX_ANIMATIONS ) { +#ifdef FINAL_BUILD + newAnimation = 0; +#else CG_Error( "Bad animation number: %i", newAnimation ); +#endif } + lf->animationNumber = newAnimation; + if ( !ValidAnimFileIndex( ci->animFileIndex ) ) { +#ifdef FINAL_BUILD + ci->animFileIndex = 0; +#else CG_Error( "Bad animFileIndex: %i", ci->animFileIndex ); +#endif } anim = &level.knownAnimFileSets[ci->animFileIndex].animations[ newAnimation ]; @@ -1028,7 +1044,7 @@ void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBa { if ( ValidAnimFileIndex( ci->animFileIndex ) ) { - CG_PlayerAnimSounds( level.knownAnimFileSets[ci->animFileIndex].legsAnimSnds, cent->pe.legs.frame, cent->currentState.number ); + CG_PlayerAnimSounds( ci->animFileIndex, qfalse, cent->pe.legs.frame, cent->pe.legs.frame, cent->currentState.number ); } } @@ -1045,7 +1061,7 @@ void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBa *torsoBackLerp = 0; if ( ValidAnimFileIndex( ci->animFileIndex ) ) { - CG_PlayerAnimSounds(knownAnimFileSets[ci->animFileIndex].torsoAnimSnds, cent->pe.torso.frame, cent->currentState.number ); + CG_PlayerAnimSounds(ci->animFileIndex, qtrue, cent->pe.torso.frame, cent->pe.torso.frame, cent->currentState.number ); } return; } @@ -1063,23 +1079,83 @@ void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBa { if ( ValidAnimFileIndex( ci->animFileIndex ) ) { - CG_PlayerAnimSounds(level.knownAnimFileSets[ci->animFileIndex].torsoAnimSnds, cent->pe.torso.frame, cent->currentState.number ); + CG_PlayerAnimSounds(ci->animFileIndex, qtrue, cent->pe.torso.frame, cent->pe.torso.frame, cent->currentState.number ); } } } /* -void CG_PlayerAnimSounds( animsounds_t *animSounds, int frame, const vec3_t org, int entNum ) +void CG_PlayerAnimSounds( int animFileIndex, qboolean torso, int oldFrame, int frame, const vec3_t org, int entNum ) play any keyframed sounds - only when start a new frame This func is called once for legs and once for torso */ -void CG_PlayerAnimSounds( animsounds_t *animSounds, int frame, int entNum ) +extern int PM_LegsAnimForFrame( gentity_t *ent, int legsFrame ); +extern int PM_TorsoAnimForFrame( gentity_t *ent, int torsoFrame ); +void CG_PlayerAnimSounds( int animFileIndex, qboolean torso, int oldFrame, int frame, int entNum ) { int i; int holdSnd = -1; - qboolean playSound = qfalse; + int firstFrame = 0, lastFrame = 0; + qboolean playSound = qfalse, inSameAnim = qfalse, loopAnim = qfalse, match = qfalse, animBackward = qfalse; + animsounds_t *animSounds = NULL; + + if ( torso ) + { + animSounds = level.knownAnimFileSets[animFileIndex].torsoAnimSnds; + } + else + { + animSounds = level.knownAnimFileSets[animFileIndex].legsAnimSnds; + } + if ( fabs(oldFrame-frame) > 1 && cg_reliableAnimSounds.integer ) + {//given a range, see if keyFrame falls in that range + int oldAnim, anim; + if ( torso ) + { + if ( cg_reliableAnimSounds.integer > 1 ) + {//more precise, slower + oldAnim = PM_TorsoAnimForFrame( &g_entities[entNum], oldFrame ); + anim = PM_TorsoAnimForFrame( &g_entities[entNum], frame ); + } + else + {//less precise, but faster + oldAnim = cg_entities[entNum].currentState.torsoAnim; + anim = cg_entities[entNum].nextState.torsoAnim; + } + } + else + { + if ( cg_reliableAnimSounds.integer > 1 ) + {//more precise, slower + oldAnim = PM_LegsAnimForFrame( &g_entities[entNum], oldFrame ); + anim = PM_TorsoAnimForFrame( &g_entities[entNum], frame ); + } + else + {//less precise, but faster + oldAnim = cg_entities[entNum].currentState.legsAnim; + anim = cg_entities[entNum].nextState.legsAnim; + } + } + if ( anim != oldAnim ) + {//not in same anim + inSameAnim = qfalse; + //FIXME: we *could* see if the oldFrame was *just about* to play the keyframed sound... + } + else + {//still in same anim, check for looping anim + inSameAnim = qtrue; + animation_t *animation = &level.knownAnimFileSets[animFileIndex].animations[anim]; + animBackward = (animation->frameLerp<0); + if ( animation->loopFrames != -1 ) + {//a looping anim! + loopAnim = qtrue; + firstFrame = animation->firstFrame; + lastFrame = animation->firstFrame+animation->numFrames; + } + } + } if ( entNum == 0 && !cg.renderingThirdPerson )//!cg_thirdPerson.integer ) {//player in first person view does not play any keyframed sounds @@ -1094,7 +1170,58 @@ void CG_PlayerAnimSounds( animsounds_t *animSounds, int frame, int entNum ) break; } - if (animSounds[i].keyFrame == frame) + match = qfalse; + if ( animSounds[i].keyFrame == frame ) + {//exact match + match = qtrue; + } + else if ( fabs(oldFrame-frame) > 1 && cg_reliableAnimSounds.integer ) + {//given a range, see if keyFrame falls in that range + if ( inSameAnim ) + {//if changed anims altogether, sorry, the sound is lost + if ( fabs(oldFrame-animSounds[i].keyFrame) <= 3 + || fabs(frame-animSounds[i].keyFrame) <= 3 ) + {//must be at least close to the keyframe + if ( animBackward ) + {//animation plays backwards + if ( oldFrame > animSounds[i].keyFrame && frame < animSounds[i].keyFrame ) + {//old to new passed through keyframe + match = qtrue; + } + else if ( loopAnim ) + {//hmm, didn't pass through it linearally, see if we looped + if ( animSounds[i].keyFrame >= firstFrame && animSounds[i].keyFrame < lastFrame ) + {//keyframe is in this anim + if ( oldFrame > animSounds[i].keyFrame + && frame > oldFrame ) + {//old to new passed through keyframe + match = qtrue; + } + } + } + } + else + {//anim plays forwards + if ( oldFrame < animSounds[i].keyFrame && frame > animSounds[i].keyFrame ) + {//old to new passed through keyframe + match = qtrue; + } + else if ( loopAnim ) + {//hmm, didn't pass through it linearally, see if we looped + if ( animSounds[i].keyFrame >= firstFrame && animSounds[i].keyFrame < lastFrame ) + {//keyframe is in this anim + if ( oldFrame < animSounds[i].keyFrame + && frame < oldFrame ) + {//old to new passed through keyframe + match = qtrue; + } + } + } + } + } + } + } + if ( match ) { // are there variations on the sound? holdSnd = animSounds[i].soundIndex[ Q_irand( 0, animSounds[i].numRandomAnimSounds ) ]; @@ -1150,7 +1277,7 @@ void CGG2_AnimSounds( centity_t *cent ) } if ( curFrame != cent->gent->client->renderInfo.legsFrame ) { - CG_PlayerAnimSounds( level.knownAnimFileSets[cent->gent->client->clientInfo.animFileIndex].legsAnimSnds, curFrame, cent->currentState.clientNum ); + CG_PlayerAnimSounds( cent->gent->client->clientInfo.animFileIndex, qfalse, cent->gent->client->renderInfo.legsFrame, curFrame, cent->currentState.clientNum ); } cent->gent->client->renderInfo.legsFrame = curFrame; cent->pe.legs.frame = curFrame; @@ -1161,7 +1288,7 @@ void CGG2_AnimSounds( centity_t *cent ) } if ( curFrame != cent->gent->client->renderInfo.torsoFrame ) { - CG_PlayerAnimSounds( level.knownAnimFileSets[cent->gent->client->clientInfo.animFileIndex].torsoAnimSnds, curFrame, cent->currentState.clientNum ); + CG_PlayerAnimSounds( cent->gent->client->clientInfo.animFileIndex, qtrue, cent->gent->client->renderInfo.torsoFrame, curFrame, cent->currentState.clientNum ); } cent->gent->client->renderInfo.torsoFrame = curFrame; cent->pe.torso.frame = curFrame; @@ -1624,6 +1751,11 @@ qboolean CG_PlayerLegsYawFromMovement( centity_t *cent, const vec3_t velocity, f { return qfalse; } + if ( cent->gent && cent->gent->client && cent->gent->client->ps.forcePowersActive & (1 << FP_SPEED) ) + {//using force speed + //scale up the turning speed + turnRate /= cg_timescale.value; + } //lerp the legs angle to the new angle angleDiff = AngleDelta( cent->pe.legs.yawAngle, (*yaw+addAngle) ); newAddAngle = angleDiff*cg.frameInterpolation*-1; @@ -1742,21 +1874,26 @@ void CG_G2ClientSpineAngles( centity_t *cent, vec3_t viewAngles, const vec3_t an viewAngles[YAW] = AngleDelta( cent->lerpAngles[YAW], angles[YAW] ); cent->pe.torso.yawAngle = viewAngles[YAW]; - if ( !PM_FlippingAnim( cent->currentState.legsAnim ) && - !PM_SpinningSaberAnim( cent->currentState.legsAnim ) && - !PM_SpinningSaberAnim( cent->currentState.torsoAnim ) && - cent->currentState.legsAnim != cent->currentState.torsoAnim )//NOTE: presumes your legs & torso are on the same frame, though they *should* be because PM_SetAnimFinal tries to keep them in synch + if ( cg_motionBoneComp.integer + && !PM_FlippingAnim( cent->currentState.legsAnim ) + && !PM_SpinningSaberAnim( cent->currentState.legsAnim ) + && !PM_SpinningSaberAnim( cent->currentState.torsoAnim ) + && cent->currentState.legsAnim != cent->currentState.torsoAnim )//NOTE: presumes your legs & torso are on the same frame, though they *should* be because PM_SetAnimFinal tries to keep them in synch {//FIXME: no need to do this if legs and torso on are same frame //adjust for motion offset mdxaBone_t boltMatrix; - vec3_t motionFwd, motionRt, motionAngles, tempAng; + vec3_t motionFwd, motionAngles; gi.G2API_GetBoltMatrix( cent->gent->ghoul2, cent->gent->playerModel, cent->gent->motionBolt, &boltMatrix, vec3_origin, cent->lerpOrigin, cg.time, cgs.model_draw, cent->currentState.modelScale ); gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, motionFwd ); - gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_X, motionRt ); vectoangles( motionFwd, motionAngles ); - vectoangles( motionRt, tempAng ); - motionAngles[ROLL] = -tempAng[PITCH]; + if ( cg_motionBoneComp.integer > 1 ) + {//do roll, too + vec3_t motionRt, tempAng; + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_X, motionRt ); + vectoangles( motionRt, tempAng ); + motionAngles[ROLL] = -tempAng[PITCH]; + } for ( int ang = 0; ang < 3; ang++ ) { @@ -2838,13 +2975,13 @@ static qboolean CG_PlayerShadow( centity_t *const cent, float *const shadowPlane } -void _PlayerSplash( const vec3_t origin, const float radius ) +void _PlayerSplash( const vec3_t origin, const vec3_t velocity, const float radius, const int maxUp ) { + static vec3_t WHITE={1,1,1}; vec3_t start, end; trace_t trace; int contents; - polyVert_t verts[4]; - + VectorCopy( origin, end ); end[2] -= 24; @@ -2857,7 +2994,14 @@ void _PlayerSplash( const vec3_t origin, const float radius ) } VectorCopy( origin, start ); - start[2] += 32; + if ( maxUp < 32 ) + {//our head may actually be lower than 32 above our origin + start[2] += maxUp; + } + else + { + start[2] += 32; + } // if the head isn't out of liquid, don't make a mark contents = cgi_CM_PointContents( start, 0 ); @@ -2874,48 +3018,27 @@ void _PlayerSplash( const vec3_t origin, const float radius ) return; } - // create a mark polygon - VectorCopy( trace.endpos, verts[0].xyz ); - verts[0].xyz[0] -= radius; - verts[0].xyz[1] -= radius; - verts[0].st[0] = 0; - verts[0].st[1] = 0; - verts[0].modulate[0] = 255; - verts[0].modulate[1] = 255; - verts[0].modulate[2] = 255; - verts[0].modulate[3] = 255; + VectorCopy( trace.endpos, end ); - VectorCopy( trace.endpos, verts[1].xyz ); - verts[1].xyz[0] -= radius; - verts[1].xyz[1] += radius; - verts[1].st[0] = 0; - verts[1].st[1] = 1; - verts[1].modulate[0] = 255; - verts[1].modulate[1] = 255; - verts[1].modulate[2] = 255; - verts[1].modulate[3] = 255; + end[0] += crandom() * 3.0f; + end[1] += crandom() * 3.0f; + end[2] += 1.0f; //fudge up + + int t = VectorLengthSquared( velocity ); + + if ( t > 8192 ) // oh, magic number + { + t = 8192; + } - VectorCopy( trace.endpos, verts[2].xyz ); - verts[2].xyz[0] += radius; - verts[2].xyz[1] += radius; - verts[2].st[0] = 1; - verts[2].st[1] = 1; - verts[2].modulate[0] = 255; - verts[2].modulate[1] = 255; - verts[2].modulate[2] = 255; - verts[2].modulate[3] = 255; + float alpha = ( t / 8192.0f ) * 0.6f + 0.2f; - VectorCopy( trace.endpos, verts[3].xyz ); - verts[3].xyz[0] += radius; - verts[3].xyz[1] -= radius; - verts[3].st[0] = 1; - verts[3].st[1] = 0; - verts[3].modulate[0] = 255; - verts[3].modulate[1] = 255; - verts[3].modulate[2] = 255; - verts[3].modulate[3] = 255; - - cgi_R_AddPolyToScene( cgs.media.wakeMarkShader, 4, verts ); + FX_AddOrientedParticle( end, trace.plane.normal, NULL, NULL, + 6.0f, radius + random() * 48.0f, 0, + alpha, 0.0f, 0.0f, + WHITE, WHITE, 0.0f, + random() * 360, crandom() * 6.0f, NULL, NULL, 0.0f, 0 ,0, 1200, + cgs.media.wakeMarkShader, FX_ALPHA_LINEAR | FX_SIZE_LINEAR ); } /* @@ -2932,34 +3055,44 @@ void CG_PlayerSplash( centity_t *cent ) return; } - if ( cent->gent->client->NPC_class == CLASS_ATST ) + if ( cent->gent && cent->gent->client ) { - mdxaBone_t boltMatrix; - vec3_t tempAngles, sideOrigin; + gclient_t *cl = cent->gent->client; - tempAngles[PITCH] = 0; - tempAngles[YAW] = cent->pe.legs.yawAngle; - tempAngles[ROLL] = 0; - - gi.G2API_GetBoltMatrix( cent->gent->ghoul2, cent->gent->playerModel, cent->gent->footLBolt, - &boltMatrix, tempAngles, cent->lerpOrigin, - cg.time, cgs.model_draw, cent->currentState.modelScale ); - gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, sideOrigin ); - sideOrigin[2] += 22; //fudge up a bit for coplaner - _PlayerSplash( sideOrigin, 42 ); - - gi.G2API_GetBoltMatrix( cent->gent->ghoul2, cent->gent->playerModel, cent->gent->footRBolt, - &boltMatrix, tempAngles, cent->lerpOrigin, cg.time, - cgs.model_draw, cent->currentState.modelScale); - gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, sideOrigin ); - sideOrigin[2] += 22; //fudge up a bit for coplaner + if ( cent->gent->disconnectDebounceTime < cg.time ) // can't do these expanding ripples all the time + { + if ( cl->NPC_class == CLASS_ATST ) + { + mdxaBone_t boltMatrix; + vec3_t tempAngles, sideOrigin; - _PlayerSplash( sideOrigin, 42 ); - } - else - { - // player splash mark - _PlayerSplash( cent->lerpOrigin, 28 ); + tempAngles[PITCH] = 0; + tempAngles[YAW] = cent->pe.legs.yawAngle; + tempAngles[ROLL] = 0; + + gi.G2API_GetBoltMatrix( cent->gent->ghoul2, cent->gent->playerModel, cent->gent->footLBolt, + &boltMatrix, tempAngles, cent->lerpOrigin, + cg.time, cgs.model_draw, cent->currentState.modelScale ); + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, sideOrigin ); + sideOrigin[2] += 22; //fudge up a bit for coplaner + _PlayerSplash( sideOrigin, cl->ps.velocity, 42, cent->gent->maxs[2] ); + + gi.G2API_GetBoltMatrix( cent->gent->ghoul2, cent->gent->playerModel, cent->gent->footRBolt, + &boltMatrix, tempAngles, cent->lerpOrigin, cg.time, + cgs.model_draw, cent->currentState.modelScale); + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, sideOrigin ); + sideOrigin[2] += 22; //fudge up a bit for coplaner + + _PlayerSplash( sideOrigin, cl->ps.velocity, 42, cent->gent->maxs[2] ); + } + else + { + // player splash mark + _PlayerSplash( cent->lerpOrigin, cl->ps.velocity, 36, cl->renderInfo.eyePoint[2] - cent->lerpOrigin[2] + 5 ); + } + + cent->gent->disconnectDebounceTime = cg.time + 125 + random() * 50.0f; + } } } @@ -3314,7 +3447,6 @@ void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, centity_t *cen // If certain states are active, we don't want to add in the regular body if ( !gent->client->ps.powerups[PW_CLOAKED] && !gent->client->ps.powerups[PW_UNCLOAKING] && - !gent->client->ps.powerups[PW_QUAD] && !gent->client->ps.powerups[PW_DISRUPTION] ) { cgi_R_AddRefEntityToScene( ent ); @@ -3439,7 +3571,8 @@ void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, centity_t *cen // FORCE speed does blur trails //------------------------------------------------------ - if ( gent->client->ps.forcePowersActive & (1 << FP_SPEED) && cg.renderingThirdPerson ) // looks dumb doing this with first peron mode on + if ( gent->client->ps.forcePowersActive & (1 << FP_SPEED) + && (gent->s.number || cg.renderingThirdPerson) ) // looks dumb doing this with first peron mode on { localEntity_t *ex; @@ -3458,19 +3591,12 @@ void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, centity_t *cen } // Personal Shields + //------------------------ if ( powerups & ( 1 << PW_BATTLESUIT )) { float diff = gent->client->ps.powerups[PW_BATTLESUIT] - cg.time; float t; - /* - if ( !cg.damageValue ) - { - return; - } - - t = 1.0f - ((float)(cg.time - cg.damageTime ) / (DAMAGE_TIME * 2.0f)); - */ if ( diff > 0 ) { t = 1.0f - ( diff / (ARMOR_EFFECT_TIME * 2.0f)); @@ -3525,33 +3651,25 @@ void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, centity_t *cen cgi_R_AddRefEntityToScene( &tent ); } - // Invincibility -- Fixme: this isn't even the real thing. + // Invincibility -- effect needs work //------------------------------------------------------ if ( powerups & ( 1 << PW_INVINCIBLE )) { - float diff = gent->client->ps.powerups[PW_INVINCIBLE] - cg.time; - float t; - - if ( diff > 0 ) - { - t = 1.0f - ( diff / (ARMOR_EFFECT_TIME * 2.0f)); - // Only display when we have damage - if ( t < 0.0f || t > 1.0f ) - { - } - else - { - ent->shaderRGBA[0] = ent->shaderRGBA[1] = ent->shaderRGBA[2] = 255.0f * t; - ent->shaderRGBA[3] = 255; - ent->renderfx &= ~RF_ALPHA_FADE; - ent->renderfx |= RF_RGB_TINT; - ent->customShader = cgs.media.personalShieldShader; - - cgi_R_AddRefEntityToScene( ent ); - } - } + theFxScheduler.PlayEffect( cgs.effects.forceInvincibility, cent->lerpOrigin ); } + // Healing -- could use some work....maybe also make it NOT be framerate dependant + //------------------------------------------------------ +/* if ( powerups & ( 1 << PW_HEALING )) + { + vec3_t axis[3]; + + AngleVectors( cent->gent->client->renderInfo.eyeAngles, axis[0], axis[1], axis[2] ); + + theFxScheduler.PlayEffect( cgs.effects.forceHeal, cent->gent->client->renderInfo.eyePoint, axis ); + } +*/ + // Push Blur if ( gent->forcePushTime > cg.time && gi.G2API_HaveWeGhoul2Models( cent->gent->ghoul2 ) ) { CG_ForcePushBlur( ent->origin ); @@ -3573,7 +3691,7 @@ static void CG_G2SetHeadBlink( centity_t *cent, qboolean bStart ) gentity_t *gent = cent->gent; //FIXME: get these boneIndices game-side and pass it down? //FIXME: need a version of this that *doesn't* need the mFileName in the ghoul2 - const int hLeye = gi.G2API_GetBoneIndex( &gent->ghoul2[0], "leye", qfalse ); + const int hLeye = gi.G2API_GetBoneIndex( &gent->ghoul2[0], "leye", qtrue ); if (hLeye == -1) { return; @@ -3586,7 +3704,7 @@ static void CG_G2SetHeadBlink( centity_t *cent, qboolean bStart ) if (bStart) { desiredAngles[YAW] = -50; - if ( random() > 0.95f ) + if ( !in_camera && random() > 0.95f ) { bWink = qtrue; blendTime /=3; @@ -3594,7 +3712,7 @@ static void CG_G2SetHeadBlink( centity_t *cent, qboolean bStart ) } gi.G2API_SetBoneAnglesIndex( &gent->ghoul2[gent->playerModel], hLeye, desiredAngles, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL, blendTime, cg.time ); - const int hReye = gi.G2API_GetBoneIndex( &gent->ghoul2[0], "reye", qfalse ); + const int hReye = gi.G2API_GetBoneIndex( &gent->ghoul2[0], "reye", qtrue ); if (hReye == -1) { return; @@ -3645,11 +3763,10 @@ static void CG_G2SetHeadAnim( centity_t *cent, int anim ) } // first decide if we are doing an animation on the head already - int startFrame, endFrame; - //FIXME: need a version of this that *doesn't* need the mFileName in the ghoul2 - const qboolean animatingHead = gi.G2API_GetAnimRangeIndex(&gent->ghoul2[gent->playerModel], cent->gent->faceBone, &startFrame, &endFrame); +// int startFrame, endFrame; +// const qboolean animatingHead = gi.G2API_GetAnimRangeIndex(&gent->ghoul2[gent->playerModel], cent->gent->faceBone, &startFrame, &endFrame); - if (!animatingHead || ( animations[anim].firstFrame != startFrame ) )// only set the anim if we aren't going to do the same animation again +// if (!animatingHead || ( animations[anim].firstFrame != startFrame ) )// only set the anim if we aren't going to do the same animation again { gi.G2API_SetBoneAnimIndex(&gent->ghoul2[gent->playerModel], cent->gent->faceBone, firstFrame, lastFrame, animFlags, animSpeed, cg.time, -1, blendTime); @@ -3709,12 +3826,12 @@ qboolean CG_G2PlayerHeadAnims( centity_t *cent ) } - if (gi.VoiceVolume[cent->gent->s.clientNum] > 0) // if we aren't talking, then it will be 0 + if (gi.VoiceVolume[cent->gent->s.clientNum] > 0) // if we aren't talking, then it will be 0, -1 for talking but paused { anim = FACE_TALK1 + gi.VoiceVolume[cent->gent->s.clientNum] -1; } - else //not talking - { + else if (gi.VoiceVolume[cent->gent->s.clientNum] == 0) //don't do aux if in a slient part of speech + {//not talking if (cent->gent->client->facial_aux < 0) // are we auxing ? { //yes if (-(cent->gent->client->facial_aux) < cg.time)// are we done auxing ? @@ -3736,7 +3853,7 @@ qboolean CG_G2PlayerHeadAnims( centity_t *cent ) } } -/* if (anim != -1) //we we are auxing, see if we should override with a frown + if (anim != -1) //we we are auxing, see if we should override with a frown { if (cent->gent->client->facial_frown < 0)// are we frowning ? { // yes, @@ -3746,20 +3863,20 @@ qboolean CG_G2PlayerHeadAnims( centity_t *cent ) } else { // not yet, so choose frown - anim = FACE_FEAR; + anim = FACE_FROWN; } } else// no we aren't frowning { // but should we start ? if (cent->gent->client->facial_frown < cg.time) { - anim = FACE_FEAR; + anim = FACE_FROWN; // set frown timer cent->gent->client->facial_frown = -(cg.time + 2000.0); } } } -*/ + }//talking }//dead if (anim != -1) @@ -3983,84 +4100,6 @@ void CG_GetPlayerLightLevel( centity_t *cent ) } } -void CG_AddFaceDisruption( refEntity_t *ent, int powerups ) -{ -/* if ( powerups > cg.time ) - { - vec3_t org, end; - float alpha = (powerups - cg.time)/2000.0f;//1.0 to 0.0 - float lengthScale = 1.0 - alpha;//0.0 to 1.0 - if ( alpha > 0.5 ) - { - alpha = 1.0 - alpha; - } - - //Right eye - VectorMA( ent->origin, 4, ent->axis[0], org );//forward - VectorMA( org, 1.5, ent->axis[1], org );//right - VectorMA( org, 4, ent->axis[2], org );//up - - VectorMA( org, 4, ent->axis[2], end );//up -// FX_AddLine( org, end, 1.0, 5, 0.0, 1.0, 0.0, 1.0, cgs.media.dkorangeParticleShader ); - - VectorMA( org, -4, ent->axis[0], org );//pull it back - VectorMA( org, 56*lengthScale, ent->axis[0], end );//forward - VectorMA( end, 6*lengthScale, ent->axis[1], end );//right - VectorMA( end, 6*lengthScale, ent->axis[2], end );//up - - if( rand() & 1 ) - { -// FX_AddLine( org, end, 1.0, 2.0, 12.0, alpha, 0.0, 1.0, cgs.media.orangeParticleShader ); - } - else - { -// FX_AddLine( org, end, 1.0, 2.0, 12.0, alpha, 0.0, 1.0, cgs.media.yellowParticleShader ); - } - - //Left eye - VectorMA( ent->origin, 4, ent->axis[0], org );//forward - VectorMA( org, -1.5, ent->axis[1], org );//right - VectorMA( org, 4, ent->axis[2], org );//up - - VectorMA( org, 4, ent->axis[2], end );//up -// FX_AddLine( org, end, 1.0, 5, 0.0, 1.0, 0.0, 1.0, cgs.media.dkorangeParticleShader ); - - VectorMA( org, -4, ent->axis[0], org );//pull it back - VectorMA( org, 56*lengthScale, ent->axis[0], end );//forward - VectorMA( end, -6*lengthScale, ent->axis[1], end );//right - VectorMA( end, 6*lengthScale, ent->axis[2], end );//up - - if( rand() & 1 ) - { -// FX_AddLine( org, end, 1.0, 2.0, 12.0, alpha, 0.0, 1.0, cgs.media.orangeParticleShader ); - } - else - { -// FX_AddLine( org, end, 1.0, 2.0, 12.0, alpha, 0.0, 1.0, cgs.media.yellowParticleShader ); - } - - //Mouth - VectorMA( ent->origin, 4, ent->axis[0], org );//forward - VectorMA( org, 1, ent->axis[2], org );//up - - VectorMA( org, 4, ent->axis[2], end );//up -// FX_AddLine( org, end, 1.0, 5, 0.0, 1.0, 0.0, 1.0, cgs.media.dkorangeParticleShader ); - - VectorMA( org, -4, ent->axis[0], org );//pull it back - VectorMA( org, 56*lengthScale, ent->axis[0], end );//forward - VectorMA( end, -2*lengthScale, ent->axis[2], end );//up - - if( rand() & 1 ) - { -// FX_AddLine( org, end, 1.0, 2.0, 12.0, alpha, 0.0, 1.0, cgs.media.orangeParticleShader ); - } - else - { -// FX_AddLine( org, end, 1.0, 2.0, 12.0, alpha, 0.0, 1.0, cgs.media.yellowParticleShader ); - } - }*/ -} - int CG_SaberHumSoundForEnt( gentity_t *gent ) { //now: based on saber type and npc, pick correct hum sound @@ -4117,6 +4156,15 @@ void CG_StopWeaponSounds( centity_t *cent ) return; } + if ( cent->currentState.weapon == WP_STUN_BATON ) + { + cgi_S_AddLoopingSound( cent->currentState.number, + cent->lerpOrigin, + vec3_origin, + weapon->firingSound ); + return; + } + if ( !( cent->currentState.eFlags & EF_FIRING ) ) { if ( cent->pe.lightningFiring ) @@ -4263,7 +4311,7 @@ extern markPoly_t *CG_AllocMark(); void CG_CreateSaberMarks( vec3_t start, vec3_t end, vec3_t normal ) { // byte colors[4]; - int i, j; + int i, j, numFragments; vec3_t axis[3], originalPoints[4], mid; vec3_t markPoints[MAX_MARK_POINTS], projection; polyVert_t *v, verts[MAX_VERTS_ON_POLY]; @@ -4274,81 +4322,73 @@ void CG_CreateSaberMarks( vec3_t start, vec3_t end, vec3_t normal ) return; } - const float radius = 0.3f + random() * 0.3f; + float radius = 0.65f; VectorSubtract( end, start, axis[1] ); + VectorNormalize( axis[1] ); - // We probably don't want to create a ton of small marks, so bias towards doing larger ones - if ( 1)// VectorNormalize( axis[1] ) > 1.0f )// || rand() & 3 ) + // create the texture axis + VectorCopy( normal, axis[0] ); + CrossProduct( axis[1], axis[0], axis[2] ); + + // create the full polygon that we'll project + for ( i = 0 ; i < 3 ; i++ ) { - VectorNormalize( axis[1] ); - // create the texture axis - VectorCopy( normal, axis[0] ); - CrossProduct( axis[1], axis[0], axis[2] ); + originalPoints[0][i] = start[i] - radius * axis[1][i] - radius * axis[2][i]; + originalPoints[1][i] = end[i] + radius * axis[1][i] - radius * axis[2][i]; + originalPoints[2][i] = end[i] + radius * axis[1][i] + radius * axis[2][i]; + originalPoints[3][i] = start[i] - radius * axis[1][i] + radius * axis[2][i]; + } - // create the full polygon that we'll project - for ( i = 0 ; i < 3 ; i++ ) + VectorScale( normal, -1, projection ); + + // get the fragments + numFragments = cgi_CM_MarkFragments( 4, (const float (*)[3])originalPoints, + projection, MAX_MARK_POINTS, markPoints[0], MAX_MARK_FRAGMENTS, markFragments ); + + + for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) + { + // we have an upper limit on the complexity of polygons that we store persistantly + if ( mf->numPoints > MAX_VERTS_ON_POLY ) { - // stretch a bit more in the direction that we are traveling in... - // debateable as to whether this makes things better or worse - originalPoints[0][i] = start[i] - radius * axis[1][i] - radius * axis[2][i] * 1.3f; - originalPoints[1][i] = end[i] + radius * axis[1][i] - radius * axis[2][i] * 1.3f; - originalPoints[2][i] = end[i] + radius * axis[1][i] + radius * axis[2][i] * 1.3f; - originalPoints[3][i] = start[i] - radius * axis[1][i] + radius * axis[2][i] * 1.3f; + mf->numPoints = MAX_VERTS_ON_POLY; } - VectorScale( normal, -1, projection ); - - // get the fragments - const int numFragments = cgi_CM_MarkFragments( 4, (const float (*)[3])originalPoints, - projection, MAX_MARK_POINTS, markPoints[0], MAX_MARK_FRAGMENTS, markFragments ); - -// colors[0] = colors[1] = colors[2] = colors[3] = 255; - - for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) + for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) { - // we have an upper limit on the complexity of polygons that we store persistantly - if ( mf->numPoints > MAX_VERTS_ON_POLY ) - { - mf->numPoints = MAX_VERTS_ON_POLY; - } + vec3_t delta; - for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) - { - vec3_t delta; + // Set up our texture coords, this may need some work + VectorCopy( markPoints[mf->firstPoint + j], v->xyz ); + VectorAdd( end, start, mid ); + VectorScale( mid, 0.5f, mid ); + VectorSubtract( v->xyz, mid, delta ); - // Set up our texture coords, this may need some work - VectorCopy( markPoints[mf->firstPoint + j], v->xyz ); - VectorAdd( end, start, mid ); - VectorScale( mid, 0.5f, mid ); - VectorSubtract( v->xyz, mid, delta ); - - v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * (0.15f + crandom() * 0.14f); - v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * (0.1f + crandom() * 0.05f); -// *(int *)v->modulate = *(int *)colors; - } - - // save it persistantly, do burn first - mark = CG_AllocMark(); - mark->time = cg.time; - mark->alphaFade = qtrue; - mark->markShader = cgs.media.rivetMarkShader; - mark->poly.numVerts = mf->numPoints; - mark->color[0] = mark->color[1] = mark->color[2] = mark->color[3] = 255; - memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); - - // And now do a glow pass - // by moving the start time back, we can hack it to fade out way before the burn does - mark = CG_AllocMark(); - mark->time = cg.time - 8500; - mark->alphaFade = qfalse; - mark->markShader = cgi_R_RegisterShader("gfx/effects/saberDamageGlow" ); - mark->poly.numVerts = mf->numPoints; - mark->color[0] = 255; - mark->color[1] = 130 + sin( cg.time * 0.03f ) * 36.0f;//80 + random() * 96.0f; - mark->color[2] = mark->color[3] = 10;//= random()*15.0f; - memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); + v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * (0.05f + random() * 0.03f); + v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * (0.15f + random() * 0.05f); } + + // save it persistantly, do burn first + mark = CG_AllocMark(); + mark->time = cg.time; + mark->alphaFade = qtrue; + mark->markShader = cgs.media.rivetMarkShader; + mark->poly.numVerts = mf->numPoints; + mark->color[0] = mark->color[1] = mark->color[2] = mark->color[3] = 255; + memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); + + // And now do a glow pass + // by moving the start time back, we can hack it to fade out way before the burn does + mark = CG_AllocMark(); + mark->time = cg.time - 8500; + mark->alphaFade = qfalse; + mark->markShader = cgi_R_RegisterShader("gfx/effects/saberDamageGlow" ); + mark->poly.numVerts = mf->numPoints; + mark->color[0] = 215 + random() * 40.0f; + mark->color[1] = 96 + random() * 32.0f; + mark->color[2] = mark->color[3] = random()*15.0f; + memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); } } @@ -4504,7 +4544,7 @@ Ghoul2 Insert End if ( trace.fraction < 1.0f ) { // Saber is on the other side of a wall - cent->gent->client->ps.saberLength = 1; + cent->gent->client->ps.saberLength = 0.1f; cent->gent->client->ps.saberEventFlags &= ~SEF_INWATER; } else @@ -4533,8 +4573,11 @@ Ghoul2 Insert End */ if ( !Q_irand( 0, 10 ) ) {//FIXME: don't do this this way.... :) - G_PlayEffect( "saber/boil", trace.endpos ); - cgi_S_StartSound ( trace.endpos, -1, CHAN_AUTO, cgi_S_RegisterSound( "sound/weapons/saber/hitwater.wav" ) ); + vec3_t spot; + VectorCopy( trace.endpos, spot ); + spot[2] += 4; + G_PlayEffect( "saber/boil", spot ); + cgi_S_StartSound ( spot, -1, CHAN_AUTO, cgi_S_RegisterSound( "sound/weapons/saber/hitwater.wav" ) ); } //cent->gent->client->ps.saberEventFlags |= SEF_INWATER; //don't do other trace @@ -4556,7 +4599,7 @@ Ghoul2 Insert End if ( cg.time - cent->gent->client->ps.saberHitWallSoundDebounceTime >= 100 ) {//ugh, need to have a real sound debouncer... or do this game-side cent->gent->client->ps.saberHitWallSoundDebounceTime = cg.time; - cgi_S_StartSound ( cent->lerpOrigin, -1, CHAN_WEAPON, cgi_S_RegisterSound( va ( "sound/weapons/saber/saberhitwall%d.wav", Q_irand( 1, 3 ) ) ) ); + cgi_S_StartSound ( cent->lerpOrigin, cent->currentState.clientNum, CHAN_ITEM, cgi_S_RegisterSound( va ( "sound/weapons/saber/saberhitwall%d.wav", Q_irand( 1, 3 ) ) ) ); } } } @@ -4577,9 +4620,9 @@ Ghoul2 Insert End { //Now that we don't let the blade go through walls, we need to shorten the blade when it hits one cent->gent->client->ps.saberLength = cent->gent->client->ps.saberLength * trace.fraction;//this will stop damage from going through walls - if ( cent->gent->client->ps.saberLength <= 1 ) + if ( cent->gent->client->ps.saberLength <= 0.1f ) {//SIGH... hack so it doesn't play the saber turn-on sound that plays when you first turn the saber on (assumed when saber is active but length is zero) - cent->gent->client->ps.saberLength = 1;//FIXME: may go through walls still?? + cent->gent->client->ps.saberLength = 0.1f;//FIXME: may go through walls still?? } //FIXME: should probably re-extend instantly, not use the "turning-on" growth rate } @@ -4608,6 +4651,13 @@ Ghoul2 Insert End // if we happen to be timescaled or running in a high framerate situation, we don't want to flood // the system with very small trail slices...but perhaps doing it by distance would yield better results? + if ( saberTrail->lastTime > cg.time ) + {//after a pause, cg.time jumps ahead in time for one frame + //and lastTime gets set to that and will freak out, so, since + //it's never valid for saberTrail->lastTime to be > cg.time, + //cap it to cg.time here + saberTrail->lastTime = cg.time; + } if ( cg.time > saberTrail->lastTime + 2 && saberTrail->inAction ) // 2ms { if ( saberTrail->inAction && cg.time < saberTrail->lastTime + 300 ) // if we have a stale segment, don't draw until we have a fresh one @@ -4754,6 +4804,7 @@ CG_Player =============== */ +extern qboolean G_ControlledByPlayer( gentity_t *self ); void CG_Player( centity_t *cent ) { clientInfo_t *ci; qboolean shadow, staticScale = qfalse; @@ -4826,7 +4877,7 @@ void CG_Player( centity_t *cent ) { // add the shadow shadow = CG_PlayerShadow( cent, &shadowPlane ); - if ( cg_shadows.integer == 3 && shadow ) + if ( (cg_shadows.integer == 2) || (cg_shadows.integer == 3 && shadow) ) { ent.renderfx |= RF_SHADOW_PLANE; } @@ -4975,10 +5026,11 @@ Ghoul2 Insert Start ent.renderfx = RF_THIRD_PERSON; // only draw in mirrors } - if ( cg_shadows.integer == 3 && shadow ) + if ( (cg_shadows.integer == 2) || (cg_shadows.integer == 3 && shadow) ) { ent.renderfx |= RF_SHADOW_PLANE; } + ent.shadowPlane = shadowPlane; ent.renderfx |= RF_LIGHTING_ORIGIN; // use the same origin for all if ( cent->gent->NPC && cent->gent->NPC->scriptFlags & SCF_MORELIGHT ) { @@ -5009,6 +5061,8 @@ Ghoul2 Insert Start //gi.G2API_SetBoneAngles( &chair->gent->ghoul2[0], "swivel_bone", temp, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, cgs.model_draw ); VectorCopy( temp, chair->gent->lastAngles ); + gi.G2API_StopBoneAnimIndex( ¢->gent->ghoul2[cent->gent->playerModel], cent->gent->hipsBone ); + // Getting the seat bolt here gi.G2API_GetBoltMatrix( chair->gent->ghoul2, chair->gent->playerModel, chair->gent->headBolt, &boltMatrix, chair->gent->s.apos.trBase, chair->gent->currentOrigin, cg.time, @@ -5055,10 +5109,23 @@ Ghoul2 Insert Start extern vmCvar_t cg_thirdPersonAlpha; - if ( cent->gent->s.number == 0 && cg_thirdPersonAlpha.value < 1.0f ) + if ( (cent->gent->s.number == 0 || G_ControlledByPlayer( cent->gent )) ) { - ent.renderfx |= RF_ALPHA_FADE; - ent.shaderRGBA[3] = (unsigned char)(cg_thirdPersonAlpha.value * 255.0f); + float alpha = 1.0f; + if ( (cg.overrides.active&CG_OVERRIDE_3RD_PERSON_APH) ) + { + alpha = cg.overrides.thirdPersonAlpha; + } + else + { + alpha = cg_thirdPersonAlpha.value; + } + + if ( alpha < 1.0f ) + { + ent.renderfx |= RF_ALPHA_FADE; + ent.shaderRGBA[3] = (unsigned char)(alpha * 255.0f); + } } if ( !cg.renderingThirdPerson @@ -5104,8 +5171,11 @@ extern vmCvar_t cg_thirdPersonAlpha; //we don't override thes in pure 1st person because they will be set before this func VectorCopy( ent.origin, cent->gent->client->renderInfo.eyePoint ); VectorCopy( cent->lerpAngles, cent->gent->client->renderInfo.eyeAngles ); - VectorCopy( ent.origin, cent->gent->client->renderInfo.muzzlePoint ); - VectorCopy( ent.axis[0], cent->gent->client->renderInfo.muzzleDir ); + if ( !cent->gent->client->ps.saberInFlight ) + { + VectorCopy( ent.origin, cent->gent->client->renderInfo.muzzlePoint ); + VectorCopy( ent.axis[0], cent->gent->client->renderInfo.muzzleDir ); + } } //now try to get the right data @@ -5165,10 +5235,6 @@ extern vmCvar_t cg_thirdPersonAlpha; cent->gent->client->ps.saberLength -= cent->gent->client->ps.saberLengthMax/10 * cg.frametime/100; } } - if ( cent->gent->client->ps.saberLength < 0 ) - { - cent->gent->client->ps.saberLength = 0; - } } else if ( cent->gent->client->ps.saberLength < cent->gent->client->ps.saberLengthMax ) {//saber is on @@ -5184,6 +5250,11 @@ extern vmCvar_t cg_thirdPersonAlpha; { saberOnSound = cgi_S_RegisterSound( "sound/weapons/saber/enemy_saber_on.wav" ); } + if ( !cent->gent->client->ps.weaponTime ) + {//make us play the turn on anim + cent->gent->client->ps.weaponstate = WEAPON_RAISING; + cent->gent->client->ps.weaponTime = 250; + } if ( cent->currentState.saberInFlight ) {//play it on the saber cgi_S_UpdateEntityPosition( cent->gent->client->ps.saberEntityNum, g_entities[cent->gent->client->ps.saberEntityNum].currentOrigin ); @@ -5194,7 +5265,10 @@ extern vmCvar_t cg_thirdPersonAlpha; cgi_S_StartSound (NULL, cent->currentState.number, CHAN_AUTO, saberOnSound ); } } - cent->gent->client->ps.saberLength += cent->gent->client->ps.saberLengthMax/10 * cg.frametime/100;//= saberLengthMax; + if ( cg.frametime > 0 ) + { + cent->gent->client->ps.saberLength += cent->gent->client->ps.saberLengthMax/10 * cg.frametime/100;//= saberLengthMax; + } if ( cent->gent->client->ps.saberLength > cent->gent->client->ps.saberLengthMax ) { cent->gent->client->ps.saberLength = cent->gent->client->ps.saberLengthMax; @@ -5217,7 +5291,11 @@ extern vmCvar_t cg_thirdPersonAlpha; } else { - if ( cent->gent->client->ps.saberEventFlags&SEF_INWATER ) + if ( cent->gent->client->ps.saberLength < 0 ) + { + cent->gent->client->ps.saberLength = 0; + } + //if ( cent->gent->client->ps.saberEventFlags&SEF_INWATER ) { CG_CheckSaberInWater( cent, cent, cent->gent->weaponModel, ent.origin, tempAngles ); } @@ -5235,13 +5313,17 @@ extern vmCvar_t cg_thirdPersonAlpha; ) {//if NPC, third person, or dead, unless using saber //Get eyePoint & eyeAngles - if ( cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD && cg.snap->ps.viewEntity == cent->currentState.clientNum ) + /* + if ( cg.snap->ps.viewEntity > 0 + && cg.snap->ps.viewEntity < ENTITYNUM_WORLD + && cg.snap->ps.viewEntity == cent->currentState.clientNum ) {//player is in an entity camera view, ME VectorCopy( ent.origin, cent->gent->client->renderInfo.eyePoint ); VectorCopy( tempAngles, cent->gent->client->renderInfo.eyeAngles ); VectorCopy( ent.origin, cent->gent->client->renderInfo.headPoint ); } - else if ( cent->gent->headBolt == -1 ) + else + */if ( cent->gent->headBolt == -1 ) {//no headBolt VectorCopy( ent.origin, cent->gent->client->renderInfo.eyePoint ); VectorCopy( tempAngles, cent->gent->client->renderInfo.eyeAngles ); @@ -5400,7 +5482,7 @@ extern vmCvar_t cg_thirdPersonAlpha; effect = &wData->mMuzzleEffect[0]; } - if ( cent->currentState.eFlags & EF_ALT_FIRING ) + if ( cent->altFire ) { // We're alt-firing, so see if we need to override with a custom alt-fire effect if ( wData->mAltMuzzleEffect[0] ) @@ -5409,9 +5491,9 @@ extern vmCvar_t cg_thirdPersonAlpha; } } - if (( cent->currentState.eFlags & EF_FIRING || cent->currentState.eFlags & EF_ALT_FIRING ) && effect ) + if (/*( cent->currentState.eFlags & EF_FIRING || cent->currentState.eFlags & EF_ALT_FIRING ) &&*/ effect ) { - if (( cent->gent && cent->gent->NPC ) || cg.renderingThirdPerson ) + if ( cent->gent && cent->gent->NPC ) { theFxScheduler.PlayEffect( effect, cent->gent->client->renderInfo.muzzlePoint, cent->gent->client->renderInfo.muzzleDir ); @@ -5425,7 +5507,7 @@ extern vmCvar_t cg_thirdPersonAlpha; } //play special force effects - if ( cent->gent->NPC && ( cent->gent->NPC->confusionTime > cg.time || cent->gent->NPC->charmedTime > cg.time ) ) + if ( cent->gent->NPC && ( cent->gent->NPC->confusionTime > cg.time || cent->gent->NPC->charmedTime > cg.time || cent->gent->NPC->controlledTime > cg.time) ) {// we are currently confused, so play an effect at the headBolt position theFxScheduler.PlayEffect( cgs.effects.forceConfusion, cent->gent->client->renderInfo.eyePoint ); } @@ -5480,7 +5562,27 @@ extern vmCvar_t cg_thirdPersonAlpha; //As good a place as any, I suppose, to do this keyframed sound thing CGG2_AnimSounds( cent ); //setup old system for gun to look at - CG_RunLerpFrame( ci, ¢->pe.torso, cent->gent->client->ps.torsoAnim, cent->gent->client->renderInfo.torsoFpsMod, cent->gent->s.number ); + //CG_RunLerpFrame( ci, ¢->pe.torso, cent->gent->client->ps.torsoAnim, cent->gent->client->renderInfo.torsoFpsMod, cent->gent->s.number ); + if ( cent->gent && cent->gent->client && cent->gent->client->ps.weapon == WP_SABER ) + { + if ( cg_timescale.value < 1.0f && (cent->gent->client->ps.forcePowersActive&(1<gent->client->ps.saberDamageDebounceTime - cg.time > wait ) + {//when you unpause the game with force speed on, the time gets *really* wiggy... + cent->gent->client->ps.saberDamageDebounceTime = cg.time + wait; + } + if ( cent->gent->client->ps.saberDamageDebounceTime <= cg.time ) + { +extern void WP_SaberDamageTrace( gentity_t *ent ); +extern void WP_SaberUpdateOldBladeData( gentity_t *ent ); + WP_SaberDamageTrace( cent->gent ); + WP_SaberUpdateOldBladeData( cent->gent ); + cent->gent->client->ps.saberDamageDebounceTime = cg.time + floor((float)wait*cg_timescale.value); + } + } + } } else { @@ -5556,7 +5658,7 @@ Ghoul2 Insert End } } - if ( cg_shadows.integer == 3 && shadow ) + if ( (cg_shadows.integer == 2) || (cg_shadows.integer == 3 && shadow) ) { renderfx |= RF_SHADOW_PLANE; } @@ -5566,6 +5668,17 @@ Ghoul2 Insert End renderfx |= RF_MORELIGHT; //bigger than normal min light } + if ( cent->gent && cent->gent->client ) + { + VectorCopy( cent->lerpOrigin, cent->gent->client->renderInfo.headPoint ); + VectorCopy( cent->lerpOrigin, cent->gent->client->renderInfo.handRPoint ); + VectorCopy( cent->lerpOrigin, cent->gent->client->renderInfo.handLPoint ); + VectorCopy( cent->lerpOrigin, cent->gent->client->renderInfo.footRPoint ); + VectorCopy( cent->lerpOrigin, cent->gent->client->renderInfo.footLPoint ); + VectorCopy( cent->lerpOrigin, cent->gent->client->renderInfo.torsoPoint ); + VectorCopy( cent->lerpAngles, cent->gent->client->renderInfo.torsoAngles ); + VectorCopy( cent->lerpOrigin, cent->gent->client->renderInfo.crotchPoint ); + } if ( cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD && cg.snap->ps.viewEntity == cent->currentState.clientNum ) {//player is in an entity camera view, ME VectorCopy( cent->lerpOrigin, cent->gent->client->renderInfo.eyePoint ); @@ -5662,9 +5775,8 @@ Ghoul2 Insert End head.renderfx = renderfx; CG_AddRefEntityWithPowerups( &head, cent->currentState.powerups, cent ); - //CG_AddFaceDisruption( &head, cent->gent->client->ps.powerups[PW_DISRUPTION] ); - if ( cent->gent && cent->gent->NPC && ( cent->gent->NPC->confusionTime > cg.time || cent->gent->NPC->charmedTime > cg.time ) ) + if ( cent->gent && cent->gent->NPC && ( cent->gent->NPC->confusionTime > cg.time || cent->gent->NPC->charmedTime > cg.time || cent->gent->NPC->controlledTime > cg.time) ) { // we are currently confused, so play an effect theFxScheduler.PlayEffect( cgs.effects.forceConfusion, head.origin ); @@ -5763,7 +5875,7 @@ Ghoul2 Insert End } else { - if ( cent->gent->client->ps.saberEventFlags&SEF_INWATER ) + //if ( cent->gent->client->ps.saberEventFlags&SEF_INWATER ) { CG_CheckSaberInWater( cent, cent, 0, NULL, NULL ); } @@ -5778,7 +5890,7 @@ Ghoul2 Insert End if ( drawGun ) { CG_AddRefEntityWithPowerups( &gun, - (cent->currentState.powerups & ((1<currentState.powerups & ((1<errorTime = -99999; // guarantee no error decay added cent->extrapolated = qfalse; - if(cent->currentState.clientNum < MAX_CLIENTS) + if ( cent->gent && cent->gent->ghoul2.size() ) { - CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.legs, cent->currentState.legsAnim ); - CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.torso, cent->currentState.torsoAnim ); - } - else if(cent->gent && cent->gent->client) - { - CG_ClearLerpFrame( ¢->gent->client->clientInfo, ¢->pe.legs, cent->currentState.legsAnim ); - CG_ClearLerpFrame( ¢->gent->client->clientInfo, ¢->pe.torso, cent->currentState.torsoAnim ); + if ( cent->currentState.clientNum < MAX_CLIENTS ) + { + CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.legs, cent->currentState.legsAnim ); + CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], ¢->pe.torso, cent->currentState.torsoAnim ); + } + else if ( cent->gent && cent->gent->client ) + { + CG_ClearLerpFrame( ¢->gent->client->clientInfo, ¢->pe.legs, cent->currentState.legsAnim ); + CG_ClearLerpFrame( ¢->gent->client->clientInfo, ¢->pe.torso, cent->currentState.torsoAnim ); + } } //else???? diff --git a/code/cgame/cg_predict.cpp b/code/cgame/cg_predict.cpp index 26d228f..6a9a88e 100644 --- a/code/cgame/cg_predict.cpp +++ b/code/cgame/cg_predict.cpp @@ -200,17 +200,20 @@ int CG_PointContents( const vec3_t point, int passEntityNum ) { } -void CG_SetClientViewAngles( vec3_t angles ) +void CG_SetClientViewAngles( vec3_t angles, qboolean overrideViewEnt ) { - for( int i = 0; i < 3; i++ ) - { - cg.predicted_player_state.viewangles[PITCH] = angles[i]; - cg.predicted_player_state.delta_angles[i] = 0; - cg.snap->ps.viewangles[PITCH] = angles[i]; - cg.snap->ps.delta_angles[i] = 0; - g_entities[0].client->pers.cmd_angles[i] = ANGLE2SHORT(angles[i]); + if ( cg.snap->ps.viewEntity <= 0 || cg.snap->ps.viewEntity >= ENTITYNUM_WORLD || overrideViewEnt ) + {//don't clamp angles when looking through a viewEntity + for( int i = 0; i < 3; i++ ) + { + cg.predicted_player_state.viewangles[PITCH] = angles[i]; + cg.predicted_player_state.delta_angles[i] = 0; + cg.snap->ps.viewangles[PITCH] = angles[i]; + cg.snap->ps.delta_angles[i] = 0; + g_entities[0].client->pers.cmd_angles[i] = ANGLE2SHORT(angles[i]); + } + cgi_SetUserCmdAngles( angles[PITCH], angles[YAW], angles[ROLL] ); } - cgi_SetUserCmdAngles( angles[PITCH], angles[YAW], angles[ROLL] ); } extern qboolean PM_AdjustAnglesToGripper( gentity_t *gent, usercmd_t *cmd ); @@ -226,10 +229,15 @@ qboolean CG_CheckModifyUCmd( usercmd_t *cmd, vec3_t viewangles ) if ( cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD ) {//controlling something else memset( cmd, 0, sizeof( usercmd_t ) ); + /* //to keep pointing in same dir, need to set cmd.angles - cmd->angles[PITCH] = cmd->angles[ROLL] = 0; + cmd->angles[PITCH] = ANGLE2SHORT( cg.snap->ps.viewangles[PITCH] ) - cg.snap->ps.delta_angles[PITCH]; cmd->angles[YAW] = ANGLE2SHORT( cg.snap->ps.viewangles[YAW] ) - cg.snap->ps.delta_angles[YAW]; - //CG_SetClientViewAngles( cg.snap->ps.viewangles ); + cmd->angles[ROLL] = 0; + */ + VectorCopy( g_entities[0].pos4, viewangles ); + overridAngles = qtrue; + //CG_SetClientViewAngles( g_entities[cg.snap->ps.viewEntity].client->ps.viewangles, qtrue ); } else if ( cg.snap->ps.vehicleModel != 0 ) {//in vehicle flight mode @@ -239,7 +247,7 @@ qboolean CG_CheckModifyUCmd( usercmd_t *cmd, vec3_t viewangles ) cmd->rightmove = 0; cmd->angles[PITCH] = 0; cmd->angles[YAW] = ANGLE2SHORT( cg.snap->ps.viewangles[YAW] ) - cg.snap->ps.delta_angles[YAW]; - CG_SetClientViewAngles( cg.snap->ps.viewangles ); + CG_SetClientViewAngles( cg.snap->ps.viewangles, qfalse ); } } @@ -249,7 +257,7 @@ qboolean CG_CheckModifyUCmd( usercmd_t *cmd, vec3_t viewangles ) { if ( PM_AdjustAnglesForSpinningFlip( &g_entities[0], cmd, qtrue ) ) { - CG_SetClientViewAngles( g_entities[0].client->ps.viewangles ); + CG_SetClientViewAngles( g_entities[0].client->ps.viewangles, qfalse ); if ( viewangles ) { VectorCopy( g_entities[0].client->ps.viewangles, viewangles ); @@ -259,7 +267,7 @@ qboolean CG_CheckModifyUCmd( usercmd_t *cmd, vec3_t viewangles ) } else { - CG_SetClientViewAngles( g_entities[0].client->ps.viewangles ); + CG_SetClientViewAngles( g_entities[0].client->ps.viewangles, qfalse ); if ( viewangles ) { VectorCopy( g_entities[0].client->ps.viewangles, viewangles ); @@ -268,7 +276,7 @@ qboolean CG_CheckModifyUCmd( usercmd_t *cmd, vec3_t viewangles ) } if ( G_CheckClampUcmd( &g_entities[0], cmd ) ) { - CG_SetClientViewAngles( g_entities[0].client->ps.viewangles ); + CG_SetClientViewAngles( g_entities[0].client->ps.viewangles, qfalse ); if ( viewangles ) { VectorCopy( g_entities[0].client->ps.viewangles, viewangles ); @@ -278,6 +286,35 @@ qboolean CG_CheckModifyUCmd( usercmd_t *cmd, vec3_t viewangles ) } return overridAngles; } + +qboolean CG_OnMovingPlat( playerState_t *ps ) +{ + if ( ps->groundEntityNum != ENTITYNUM_NONE ) + { + entityState_t *es = &cg_entities[ps->groundEntityNum].currentState; + if ( es->eType == ET_MOVER ) + {//on a mover + if ( es->pos.trType != TR_STATIONARY ) + { + if ( es->pos.trType != TR_LINEAR_STOP && es->pos.trType != TR_NONLINEAR_STOP ) + {//a constant mover + if ( !VectorCompare( vec3_origin, es->pos.trDelta ) ) + {//is moving + return qtrue; + } + } + else + {//a linear-stop mover + if ( es->pos.trTime+es->pos.trDuration > cg.time ) + {//still moving + return qtrue; + } + } + } + } + } + return qfalse; +} /* ======================== CG_InterpolatePlayerState @@ -348,7 +385,25 @@ void CG_InterpolatePlayerState( qboolean grabAngles ) { f * (next->ps.velocity[i] - prev->ps.velocity[i] ); } } - if (cg.validPPS && cg_smoothPlayerPos.value>0.0f && cg_smoothPlayerPos.value<1.0f) + + bool onPlat=false; + centity_t *pent=0; + if (out->groundEntityNum>0) + { + pent=&cg_entities[out->groundEntityNum]; + if (pent->currentState.eType == ET_MOVER ) + + { + onPlat=true; + } + } + + if ( + cg.validPPS && + cg_smoothPlayerPos.value>0.0f && + cg_smoothPlayerPos.value<1.0f && + !onPlat + ) { // 0 = no smoothing, 1 = no movement for (i=0;i<3;i++) @@ -356,6 +411,54 @@ void CG_InterpolatePlayerState( qboolean grabAngles ) { out->origin[i]=cg_smoothPlayerPos.value*(oldOrg[i]-out->origin[i])+out->origin[i]; } } + else if (onPlat&&cg_smoothPlayerPlat.value>0.0f&&cg_smoothPlayerPlat.value<1.0f) + { +// if (cg.frametime<150) +// { + assert(pent); + vec3_t p1,p2,vel; + float lerpTime; + + + EvaluateTrajectory( &pent->currentState.pos,cg.snap->serverTime, p1 ); + if ( cg.nextSnap &&cg.nextSnap->serverTime > cg.snap->serverTime) + { + EvaluateTrajectory( &pent->nextState.pos,cg.nextSnap->serverTime, p2 ); + lerpTime=float(cg.nextSnap->serverTime - cg.snap->serverTime); + } + else + { + EvaluateTrajectory( &pent->currentState.pos,cg.snap->serverTime+50, p2 ); + lerpTime=50.0f; + } + + float accel=cg_smoothPlayerPlatAccel.value*cg.frametime/lerpTime; + + if (accel>20.0f) + { + accel=20.0f; + } + + for (i=0;i<3;i++) + { + vel[i]=accel*(p2[i]-p1[i]); + } + + VectorAdd(out->origin,vel,out->origin); + + if (cg.validPPS && + cg_smoothPlayerPlat.value>0.0f && + cg_smoothPlayerPlat.value<1.0f + ) + { + // 0 = no smoothing, 1 = no movement + for (i=0;i<3;i++) + { + out->origin[i]=cg_smoothPlayerPlat.value*(oldOrg[i]-out->origin[i])+out->origin[i]; + } + } +// } + } } /* diff --git a/code/cgame/cg_public.h b/code/cgame/cg_public.h index fcf933b..b832363 100644 --- a/code/cgame/cg_public.h +++ b/code/cgame/cg_public.h @@ -81,6 +81,7 @@ typedef enum { CG_CM_BOXTRACE, CG_CM_TRANSFORMEDBOXTRACE, CG_CM_MARKFRAGMENTS, + CG_CM_SNAPPVS, CG_S_STARTSOUND, CG_S_STARTLOCALSOUND, CG_S_CLEARLOOPINGSOUNDS, diff --git a/code/cgame/cg_scoreboard.cpp b/code/cgame/cg_scoreboard.cpp index 86f4c36..39fc081 100644 --- a/code/cgame/cg_scoreboard.cpp +++ b/code/cgame/cg_scoreboard.cpp @@ -8,10 +8,6 @@ #define SCOREBOARD_WIDTH (26*BIGCHAR_WIDTH) -static int success,failed; -static char objectiveString[256]; -static char objectiveString2[256]; - /* static void Scoreboard_Draw( void ) @@ -65,31 +61,6 @@ static void Scoreboard_Draw( void ) } */ -/* -================= -CG_MissionFailed -================= -*/ -void CG_MissionFailedHeroDied(void) -{ - char text[1024]={0}; - int w; - - cgi_R_SetColor( NULL ); - CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, cgs.media.levelLoad ); - - cgi_SP_GetStringTextString( "INGAME_MISSIONFAILED", text, sizeof(text) ); - w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 1.0f); - cgi_R_Font_DrawString(320 - w/2, 120, text, colorTable[CT_HUD_RED], cgs.media.qhFontMedium, -1, 1.2f); - - cgi_SP_GetStringTextString( "INGAME_MISSIONFAILED_KYLE", text, sizeof(text) ); - w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontMedium, 1.2f); - cgi_R_Font_DrawString(320 - w/2, 220, text, colorTable[CT_HUD_RED], cgs.media.qhFontMedium, -1, 1.2f); - - cgi_SP_GetStringTextString( "INGAME_RELOADMISSION", text, sizeof(text) ); - w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 1.0f); - cgi_R_Font_DrawString(320 - w/2, 390, text, colorTable[CT_CYAN], cgs.media.qhFontSmall, -1, 1.0f); -} /* @@ -102,17 +73,18 @@ void CG_MissionFailed(void) { char text[1024]={0}; int w; - - cgi_R_SetColor( NULL ); - CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, cgs.media.levelLoad ); + int y = 230; cgi_SP_GetStringTextString( "INGAME_MISSIONFAILED", text, sizeof(text) ); - w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 1.0f); - cgi_R_Font_DrawString(320 - w/2, 120, text, colorTable[CT_HUD_RED], cgs.media.qhFontMedium, -1, 1.2f); + w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontMedium, 1.2f); + cgi_R_Font_DrawString(320 - w/2, y, text, colorTable[CT_HUD_RED], cgs.media.qhFontMedium, -1, 1.2f); switch (statusTextIndex) { + case -1: //Our HERO DIED!!! + cgi_SP_GetStringTextString( "INGAME_MISSIONFAILED_KYLE", text, sizeof(text) ); + break; case MISSIONFAILED_JAN: cgi_SP_GetStringTextString( "INGAME_MISSIONFAILED_JAN", text, sizeof(text) ); break; @@ -141,7 +113,7 @@ void CG_MissionFailed(void) cgi_SP_GetStringTextString( "INGAME_MISSIONFAILED_KYLECAPTURE", text, sizeof(text) ); break; case MISSIONFAILED_TOOMANYALLIESDIED: - cgi_SP_GetStringTextString( "INGAME_MISSIONFAILED_TOOMANYALLIESDIED:", text, sizeof(text) ); + cgi_SP_GetStringTextString( "INGAME_MISSIONFAILED_TOOMANYALLIESDIED", text, sizeof(text) ); break; default: cgi_SP_GetStringTextString( "INGAME_MISSIONFAILED_UNKNOWN", text, sizeof(text) ); @@ -149,11 +121,11 @@ void CG_MissionFailed(void) } w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontMedium, 1.2f); - cgi_R_Font_DrawString(320 - w/2, 220, text, colorTable[CT_HUD_RED], cgs.media.qhFontMedium, -1, 1.2f); + cgi_R_Font_DrawString(320 - w/2, y+30, text, colorTable[CT_HUD_RED], cgs.media.qhFontMedium, -1, 1.2f); cgi_SP_GetStringTextString( "INGAME_RELOADMISSION", text, sizeof(text) ); w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 1.0f); - cgi_R_Font_DrawString(320 - w/2, 390, text, colorTable[CT_CYAN], cgs.media.qhFontSmall, -1, 1.0f); + cgi_R_Font_DrawString(320 - w/2, 450, text, colorTable[CT_CYAN], cgs.media.qhFontSmall, -1, 1.0f); } @@ -169,11 +141,8 @@ void CG_MissionCompletion(void) int w,x,y; const int pad = 18; - cgi_R_SetColor( NULL ); -// CG_DrawPic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, cgs.media.levelLoad ); - cgi_SP_GetStringTextString( "INGAME_MISSIONCOMPLETION", text, sizeof(text) ); -w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 1.0f); +w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontMedium, 1.2f); cgi_R_Font_DrawString(320 - w/2, 53, text, colorTable[CT_LTGOLD1], cgs.media.qhFontMedium, -1, 1.2f); x = 75; @@ -181,7 +150,12 @@ w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 1.0f); cgi_SP_GetStringTextString( "INGAME_SECRETAREAS", text, sizeof(text) ); w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 0.8f); cgi_R_Font_DrawString(x, y, text, colorTable[CT_LTGOLD1], cgs.media.qhFontSmall, -1, 0.8f); - cgi_R_Font_DrawString(x+w, y, va("%d of %d", cg_entities[0].gent->client->sess.missionStats.secretsFound, cg_entities[0].gent->client->sess.missionStats.totalSecrets), + cgi_SP_GetStringTextString( "INGAME_SECRETAREAS_OF", text, sizeof(text) ); + cgi_R_Font_DrawString(x+w, y, va("%d %s %d", + cg_entities[0].gent->client->sess.missionStats.secretsFound, + text, + cg_entities[0].gent->client->sess.missionStats.totalSecrets + ), colorTable[CT_WHITE], cgs.media.qhFontSmall, -1, 0.8f); y +=pad; @@ -189,6 +163,15 @@ w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 0.8f); w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 0.8f); cgi_R_Font_DrawString(x, y, text, colorTable[CT_LTGOLD1], cgs.media.qhFontSmall, -1, 0.8f); cgi_R_Font_DrawString(x+w,y, va("%d",cg_entities[0].gent->client->sess.missionStats.enemiesKilled), colorTable[CT_WHITE], cgs.media.qhFontSmall, -1, 0.8f); + /* + cgi_SP_GetStringTextString( "INGAME_SECRETAREAS_OF", text, sizeof(text) ); + cgi_R_Font_DrawString(x+w,y, va("%d %s %d", + cg_entities[0].gent->client->sess.missionStats.enemiesKilled, + text, + cg_entities[0].gent->client->sess.missionStats.enemiesSpawned + ), + colorTable[CT_WHITE], cgs.media.qhFontSmall, -1, 0.8f); + */ y +=pad; y +=pad; @@ -237,7 +220,11 @@ w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 0.8f); const float percent = cg_entities[0].gent->client->sess.missionStats.shotsFired? 100.0f * (float)cg_entities[0].gent->client->sess.missionStats.hits / cg_entities[0].gent->client->sess.missionStats.shotsFired : 0; cgi_R_Font_DrawString(x+w, y, va("%.2f%%",percent), colorTable[CT_WHITE], cgs.media.qhFontSmall, -1, 0.8f); - + if ( cg_entities[0].gent->client->sess.missionStats.weaponUsed[WP_SABER] <= 0 ) + { + return; //don't have saber yet, so don't print any stats + } +//first column, FORCE POWERS y =180; cgi_SP_GetStringTextString( "INGAME_FORCEUSE", text, sizeof(text) ); cgi_R_Font_DrawString(x, y, text, colorTable[CT_WHITE], cgs.media.qhFontSmall, -1, 0.8f); @@ -284,7 +271,7 @@ w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 0.8f); cgi_R_Font_DrawString(x, y, text, colorTable[CT_LTGOLD1], cgs.media.qhFontSmall, -1, 0.8f); cgi_R_Font_DrawString(x+w, y, va("%d",cg_entities[0].gent->client->sess.missionStats.forceUsed[FP_LIGHTNING]), colorTable[CT_WHITE], cgs.media.qhFontSmall, -1, 0.8f); -//second column +//second column, LIGHT SABER y = 180; x = 140; cgi_SP_GetStringTextString( "INGAME_LIGHTSABERUSE", text, sizeof(text) ); @@ -333,6 +320,7 @@ w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 0.8f); CG_DrawScoreboard Draw the normal in-game scoreboard +return value is bool to NOT draw centerstring ================= */ qboolean CG_DrawScoreboard( void ) @@ -344,40 +332,11 @@ qboolean CG_DrawScoreboard( void ) } // Character is either dead, or a script has brought up the screen - if (((cg.predicted_player_state.pm_type == PM_DEAD) && (cg.missionStatusDeadTime < level.time)) || - (cg.missionStatusShow)) + if (((cg.predicted_player_state.pm_type == PM_DEAD) && (cg.missionStatusDeadTime < level.time)) + || (cg.missionStatusShow)) { - if (statusTextIndex>=0) // Mission failure? - { - CG_MissionFailed(); - } - else if (!cg.missionStatusShow) - { - char text[1024]={0}; - cgi_SP_GetStringTextString( "INGAME_RELOADMISSION", text, sizeof(text) ); - int w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 1.0f); - cgi_R_Font_DrawString(320 - w/2, 460, text, colorTable[CT_CYAN], cgs.media.qhFontSmall, -1, 1.0f); - return qtrue; - } - else if (cg.missionStatusShow) // A value means you want to view the Mission Completion screen - { - CG_MissionFailedHeroDied(); - } - -/* else if (!cg.missionStatusShow) - { - #define pText "Press fire button to view mission stats." - int w = cgi_R_Font_StrLenPixels(pText, cgs.media.qhFontSmall, 1.0f); - cgi_R_Font_DrawString(320 - w/2, 460, pText, colorTable[CT_CYAN], cgs.media.qhFontSmall, -1, 1.0f); - return qtrue; - } - else if (cg.missionStatusShow) // A value means you want to view the Mission Completion screen - { - if (!statusTextIndex) - { - CG_MissionCompletion(); - } - } */ + CG_MissionFailed(); + return qtrue; } return qfalse; diff --git a/code/cgame/cg_servercmds.cpp b/code/cgame/cg_servercmds.cpp index 6237a2c..c27c7f0 100644 --- a/code/cgame/cg_servercmds.cpp +++ b/code/cgame/cg_servercmds.cpp @@ -28,7 +28,8 @@ void CG_ParseServerinfo( void ) { cgs.maxclients = 1; mapname = Info_ValueForKey( info, "mapname" ); Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname ); - strcpy( cgs.stripLevelName[0], mapname ); + char *p = strrchr(mapname,'/'); + strcpy( cgs.stripLevelName[0], p?p+1:mapname ); strupr( cgs.stripLevelName[0] ); for (int i=1; iserverTime > cg.time ) + { + cg.time=cg.snap->serverTime; +#if _DEBUG + Com_Printf("CG_ProcessSnapshots: cg.snap->serverTime > cg.time"); +#endif + + } + if ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) + { + cg.time=cg.nextSnap->serverTime-1; +#if _DEBUG + Com_Printf("CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time"); +#endif + } // assert our valid conditions upon exiting if ( cg.snap == NULL ) { CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" ); diff --git a/code/cgame/cg_syscalls.cpp b/code/cgame/cg_syscalls.cpp index 62e9a72..1d1beb3 100644 --- a/code/cgame/cg_syscalls.cpp +++ b/code/cgame/cg_syscalls.cpp @@ -148,6 +148,11 @@ int cgi_CM_MarkFragments( int numPoints, const vec3_t *points, return syscall( CG_CM_MARKFRAGMENTS, numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer ); } +void cgi_CM_SnapPVS(vec3_t origin,byte *buffer) +{ + syscall(CG_CM_SNAPPVS,origin,buffer); +} + void cgi_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ) { syscall( CG_S_STARTSOUND, origin, entityNum, entchannel, sfx ); } @@ -233,7 +238,9 @@ qhandle_t cgi_R_RegisterSkin( const char *name ) { } qhandle_t cgi_R_RegisterShader( const char *name ) { - return syscall( CG_R_REGISTERSHADER, name ); + qhandle_t hShader = syscall( CG_R_REGISTERSHADER, name ); + assert (hShader); + return hShader; } qhandle_t cgi_R_RegisterShaderNoMip( const char *name ) { @@ -366,8 +373,8 @@ qboolean cgi_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) { return syscall( CG_GETUSERCMD, cmdNumber, ucmd ); } -void cgi_SetUserCmdValue( int stateValue, float sensitivityScale ) { - syscall( CG_SETUSERCMDVALUE, stateValue, PASSFLOAT(sensitivityScale) ); +void cgi_SetUserCmdValue( int stateValue, float sensitivityScale, float mPitchOverride, float mYawOverride ) { + syscall( CG_SETUSERCMDVALUE, stateValue, PASSFLOAT(sensitivityScale), PASSFLOAT(mPitchOverride), PASSFLOAT(mYawOverride) ); } void cgi_SetUserCmdAngles( float pitchOverride, float yawOverride, float rollOverride ) { @@ -526,5 +533,7 @@ int cgi_SP_GetStringText(int ID, char *buffer, int bufferLength) int cgi_EndGame(void) { - return syscall( CG_SENDCONSOLECOMMAND, "disconnect" ); +//extern void CMD_CGCam_Disable( void ); + //CMD_CGCam_Disable(); //can't do it here because it will draw the hud when we're out of camera + return syscall( CG_SENDCONSOLECOMMAND, "cam_disable; set nextmap disconnect; cinematic outcast\n" ); } diff --git a/code/cgame/cg_text.cpp b/code/cgame/cg_text.cpp index 058df65..ca6bf08 100644 --- a/code/cgame/cg_text.cpp +++ b/code/cgame/cg_text.cpp @@ -294,6 +294,12 @@ const char *CG_DisplayBoxedText(int iBoxX, int iBoxY, int iBoxWidth, int iBoxHei // concat onto string so far... // + if (uiLetter == 32 && sLineForDisplay[0] == '\0') + { + psReadPosAtLineStart++; + continue; // unless it's a space at the start of a line, in which case ignore it. + } + if (uiLetter > 255) { Q_strcat(sLineForDisplay, sizeof(sLineForDisplay),va("%c%c",uiLetter >> 8, uiLetter & 0xFF)); @@ -355,7 +361,7 @@ const char *CG_DisplayBoxedText(int iBoxX, int iBoxY, int iBoxWidth, int iBoxHei // if ( cg_developer.integer ) { - Com_Printf( "%psCurrentTextReadPos\n", sLineForDisplay ); +// Com_Printf( "%psCurrentTextReadPos\n", sLineForDisplay ); } } return psReadPosAtLineStart; @@ -431,7 +437,15 @@ void CG_CaptionText( const char *str, int sound, int y ) if (!i) { #ifndef FINAL_BUILD - Com_Printf("WARNING: CG_CaptionText given invalid text key :'%s'\n",str); + // we only care about some sound dirs... + if (!strnicmp(str,"sound/chars/",12)) // whichever language it is, it'll be pathed as english at this point + { + Com_Printf("WARNING: CG_CaptionText given invalid text key :'%s'\n",str); + } + else + { + // anything else is probably stuff we don't care about. It certainly shouldn't be speech, anyway + } #endif return; } @@ -442,7 +456,7 @@ void CG_CaptionText( const char *str, int sound, int y ) if (in_camera) { cg.captionTextY = SCREEN_HEIGHT - (client_camera.bar_height_dest/2); // ths is now a centre'd Y, not a start Y } else { //get above the hud - cg.captionTextY = (int) (0.75f * ((float)SCREEN_HEIGHT - (float)fontHeight * 1.5f)); + cg.captionTextY = (int) (0.88f * ((float)SCREEN_HEIGHT - (float)fontHeight * 1.5f)); // do NOT move this, it has to fit in between the weapon HUD and the datapad update. } cg.captionTextCurrentLine = 0; @@ -483,6 +497,12 @@ void CG_CaptionText( const char *str, int sound, int y ) // concat onto string so far... // + if (uiLetter == 32 && cg.captionText[i][0] == '\0') + { + holds++; + continue; // unless it's a space at the start of a line, in which case ignore it. + } + if (uiLetter > 255) { Q_strcat(cg.captionText[i],sizeof(cg.captionText[i]),va("%c%c",uiLetter >> 8, uiLetter & 0xFF)); @@ -565,7 +585,7 @@ void CG_DrawCaptionText(void) const float fFontScale = cgi_Language_IsAsian() ? 0.8f : 1.0f; - if (cg_skippingcin.value != 0.0f) + if (cg_skippingcin.integer != 0) { cg.captionTextTime = 0; return; @@ -696,6 +716,12 @@ void CG_ScrollText( const char *str, int iPixelWidth ) // concat onto string so far... // + if (uiLetter == 32 && cg.printText[i][0] == '\0') + { + holds++; + continue; // unless it's a space at the start of a line, in which case ignore it. + } + if (uiLetter > 255) { Q_strcat(cg.printText[i],sizeof(cg.printText[i]),va("%c%c",uiLetter >> 8, uiLetter & 0xFF)); @@ -718,6 +744,11 @@ void CG_ScrollText( const char *str, int iPixelWidth ) // cg.printText[i][ strlen(cg.printText[i])-1 ] = '\0'; // kill the CR i++; + assert (i < (sizeof(cg.printText)/sizeof(cg.printText[0])) ); + if (i >= (sizeof(cg.printText)/sizeof(cg.printText[0])) ) + { + break; + } holds = s; cg.scrollTextLines++; } @@ -741,6 +772,7 @@ void CG_ScrollText( const char *str, int iPixelWidth ) cg.printText[i][ psBestLineBreakSrcPos - holds ] = '\0'; holds = s = psBestLineBreakSrcPos; i++; + assert (i < (sizeof(cg.printText)/sizeof(cg.printText[0])) ); cg.scrollTextLines++; } } @@ -900,7 +932,7 @@ void CG_DrawCenterString( void ) // const char *psString = start; int iOutIndex = 0; - for ( l = 0; l < 40; l++ ) { + for ( l = 0; l < sizeof(linebuffer)-1; l++ ) { unsigned int uiLetter = cgi_AnyLanguage_ReadCharFromString(&psString); if (!uiLetter || uiLetter == '\n'){ break; diff --git a/code/cgame/cg_view.cpp b/code/cgame/cg_view.cpp index e858a33..c801178 100644 --- a/code/cgame/cg_view.cpp +++ b/code/cgame/cg_view.cpp @@ -10,9 +10,13 @@ #include "cg_lights.h" #include "..\game\wp_saber.h" +#define MASK_CAMERACLIP (MASK_SOLID) +#define CAMERA_SIZE 4 + float cg_zoomFov; //#define CG_CAM_ABOVE 2 +extern qboolean CG_OnMovingPlat( playerState_t *ps ); /* ============================================================================= @@ -313,9 +317,11 @@ void CG_CalcVrect (void) { //============================================================================== #define CAMERA_DAMP_INTERVAL 50 -static vec3_t cameramins = { -4, -4, -4 }; -static vec3_t cameramaxs = { 4, 4, 4 }; -vec3_t camerafwd, cameraup; +#define CAMERA_CROUCH_NUDGE 6 + +static vec3_t cameramins = { -CAMERA_SIZE, -CAMERA_SIZE, -CAMERA_SIZE }; +static vec3_t cameramaxs = { CAMERA_SIZE, CAMERA_SIZE, CAMERA_SIZE }; +vec3_t camerafwd, cameraup, camerahorizdir; vec3_t cameraFocusAngles, cameraFocusLoc; vec3_t cameraIdealTarget, cameraIdealLoc; @@ -323,6 +329,9 @@ vec3_t cameraCurTarget={0,0,0}, cameraCurLoc={0,0,0}; vec3_t cameraOldLoc={0,0,0}, cameraNewLoc={0,0,0}; int cameraLastFrame=0; +float cameraLastYaw=0; +float cameraStiffFactor=0.0f; + /* =============== Notes on the camera viewpoint in and out... @@ -339,7 +348,7 @@ cg.refdefViewAngles /* =============== -CG_CalcTargetThirdPersonViewLocation +CG_CalcIdealThirdPersonViewTarget =============== */ @@ -348,26 +357,62 @@ static void CG_CalcIdealThirdPersonViewTarget(void) // Initialize IdealTarget VectorCopy(cg.refdef.vieworg, cameraFocusLoc); - // Add in the new viewheight - cameraFocusLoc[2] += cg.predicted_player_state.viewheight; - if ( cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD ) { - VectorCopy( cameraFocusLoc, cameraIdealTarget ); + gentity_t *gent = &g_entities[cg.snap->ps.viewEntity]; + if ( gent->client && (gent->client->NPC_class != CLASS_GONK ) + && (gent->client->NPC_class != CLASS_INTERROGATOR) + && (gent->client->NPC_class != CLASS_SENTRY) + && (gent->client->NPC_class != CLASS_PROBE ) + && (gent->client->NPC_class != CLASS_MOUSE ) + && (gent->client->NPC_class != CLASS_R2D2 ) + && (gent->client->NPC_class != CLASS_R5D2) ) + {//use the NPC's viewheight + cameraFocusLoc[2] += gent->client->ps.viewheight; + } + else + {//droids use a generic offset + cameraFocusLoc[2] += 4; + } + VectorCopy( cameraFocusLoc, cameraIdealTarget ); } - else if ( cg.overrides.active & CG_OVERRIDE_3RD_PERSON_VOF ) + else { - // Add in a vertical offset from the viewpoint, which puts the actual target above the head, regardless of angle. - VectorCopy( cameraFocusLoc, cameraIdealTarget ); - cameraIdealTarget[2] += cg.overrides.thirdPersonVertOffset; - //VectorMA(cameraFocusLoc, cg.overrides.thirdPersonVertOffset, cameraup, cameraIdealTarget); - } - else - { - // Add in a vertical offset from the viewpoint, which puts the actual target above the head, regardless of angle. - VectorCopy( cameraFocusLoc, cameraIdealTarget ); - cameraIdealTarget[2] += cg_thirdPersonVertOffset.value; - //VectorMA(cameraFocusLoc, cg_thirdPersonVertOffset.value, cameraup, cameraIdealTarget); + // Add in the new viewheight + cameraFocusLoc[2] += cg.predicted_player_state.viewheight; + if ( cg.overrides.active & CG_OVERRIDE_3RD_PERSON_VOF ) + { + // Add in a vertical offset from the viewpoint, which puts the actual target above the head, regardless of angle. + VectorCopy( cameraFocusLoc, cameraIdealTarget ); + cameraIdealTarget[2] += cg.overrides.thirdPersonVertOffset; + //VectorMA(cameraFocusLoc, cg.overrides.thirdPersonVertOffset, cameraup, cameraIdealTarget); + } + else + { + // Add in a vertical offset from the viewpoint, which puts the actual target above the head, regardless of angle. + VectorCopy( cameraFocusLoc, cameraIdealTarget ); + cameraIdealTarget[2] += cg_thirdPersonVertOffset.value; + //VectorMA(cameraFocusLoc, cg_thirdPersonVertOffset.value, cameraup, cameraIdealTarget); + } + + // Now, if the player is crouching, do a little special tweak. The problem is that the player's head is way out of his bbox. + if (cg.predicted_player_state.pm_flags & PMF_DUCKED) + { // Nudge to focus location up a tad. + vec3_t nudgepos; + trace_t trace; + + VectorCopy(cameraFocusLoc, nudgepos); + nudgepos[2]+=CAMERA_CROUCH_NUDGE; + CG_Trace(&trace, cameraFocusLoc, cameramins, cameramaxs, nudgepos, cg.predicted_player_state.clientNum, MASK_CAMERACLIP); + if (trace.fraction < 1.0) + { + VectorCopy(trace.endpos, cameraFocusLoc); + } + else + { + VectorCopy(nudgepos, cameraFocusLoc); + } + } } } @@ -375,7 +420,7 @@ static void CG_CalcIdealThirdPersonViewTarget(void) /* =============== -CG_CalcTargetThirdPersonViewLocation +CG_CalcIdealThirdPersonViewLocation =============== */ @@ -438,20 +483,22 @@ static void CG_ResetThirdPersonViewDamp(void) VectorCopy(cameraIdealTarget, cameraCurTarget); // First thing we do is trace from the first person viewpoint out to the new target location. - CG_Trace(&trace, cameraFocusLoc, cameramins, cameramaxs, cameraCurTarget, cg.predicted_player_state.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP); + CG_Trace(&trace, cameraFocusLoc, cameramins, cameramaxs, cameraCurTarget, cg.predicted_player_state.clientNum, MASK_CAMERACLIP); if (trace.fraction <= 1.0) { VectorCopy(trace.endpos, cameraCurTarget); } // Now we trace from the new target location to the new view location, to make sure there is nothing in the way. - CG_Trace(&trace, cameraCurTarget, cameramins, cameramaxs, cameraCurLoc, cg.predicted_player_state.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP); + CG_Trace(&trace, cameraCurTarget, cameramins, cameramaxs, cameraCurLoc, cg.predicted_player_state.clientNum, MASK_CAMERACLIP); if (trace.fraction <= 1.0) { VectorCopy(trace.endpos, cameraCurLoc); } cameraLastFrame = cg.time; + cameraLastYaw = cameraFocusAngles[YAW]; + cameraStiffFactor = 0.0f; } // This is called every frame. @@ -465,7 +512,11 @@ static void CG_UpdateThirdPersonTargetDamp(void) // Automatically get the ideal target, to avoid jittering. CG_CalcIdealThirdPersonViewTarget(); - if (cg_thirdPersonTargetDamp.value>=1.0)//||cg.thisFrameTeleport) + if ( CG_OnMovingPlat( &cg.snap->ps ) ) + {//if moving on a plat, camera is *tight* + VectorCopy(cameraIdealTarget, cameraCurTarget); + } + else if (cg_thirdPersonTargetDamp.value>=1.0)//||cg.thisFrameTeleport) { // No damping. VectorCopy(cameraIdealTarget, cameraCurTarget); } @@ -491,7 +542,7 @@ static void CG_UpdateThirdPersonTargetDamp(void) // Now we trace to see if the new location is cool or not. // First thing we do is trace from the first person viewpoint out to the new target location. - CG_Trace(&trace, cameraFocusLoc, cameramins, cameramaxs, cameraCurTarget, cg.predicted_player_state.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP); + CG_Trace(&trace, cameraFocusLoc, cameramins, cameramaxs, cameraCurTarget, cg.predicted_player_state.clientNum, MASK_CAMERACLIP); if (trace.fraction < 1.0) { VectorCopy(trace.endpos, cameraCurTarget); @@ -516,8 +567,12 @@ static void CG_UpdateThirdPersonCameraDamp(void) // First thing we do is calculate the appropriate damping factor for the camera. - dampfactor=0.0; - if ( cg.overrides.active & CG_OVERRIDE_3RD_PERSON_CDP ) + dampfactor=0.0f; + if ( CG_OnMovingPlat( &cg.snap->ps ) ) + {//if moving on a plat, camera is *tight* + dampfactor=1.0f; + } + else if ( cg.overrides.active & CG_OVERRIDE_3RD_PERSON_CDP ) { if ( cg.overrides.thirdPersonCameraDamp != 0.0f ) { @@ -545,6 +600,12 @@ static void CG_UpdateThirdPersonCameraDamp(void) dampfactor = (1.0-cg_thirdPersonCameraDamp.value)*(pitch*pitch); dampfactor += cg_thirdPersonCameraDamp.value; + + // Now we also multiply in the stiff factor, so that faster yaw changes are stiffer. + if (cameraStiffFactor > 0.0f) + { // The cameraStiffFactor is how much of the remaining damp below 1 should be shaved off, i.e. approach 1 as stiffening increases. + dampfactor += (1.0-dampfactor)*cameraStiffFactor; + } } if (dampfactor>=1.0)//||cg.thisFrameTeleport) @@ -570,11 +631,18 @@ static void CG_UpdateThirdPersonCameraDamp(void) ///////////////////////////////////////////////////////////////////////////////////////////////////////// } - // Now we trace from the new target location to the new view location, to make sure there is nothing in the way. - CG_Trace( &trace, cameraCurTarget, cameramins, cameramaxs, cameraCurLoc, cg.predicted_player_state.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP ); + // Now we trace from the first person viewpoint to the new view location, to make sure there is nothing in the way between the user and the camera... +// CG_Trace(&trace, cameraFocusLoc, cameramins, cameramaxs, cameraCurLoc, cg.predicted_player_state.clientNum, MASK_CAMERACLIP); + // (OLD) Now we trace from the new target location to the new view location, to make sure there is nothing in the way. + CG_Trace( &trace, cameraCurTarget, cameramins, cameramaxs, cameraCurLoc, cg.predicted_player_state.clientNum, MASK_CAMERACLIP); if ( trace.fraction < 1.0f ) { VectorCopy( trace.endpos, cameraCurLoc ); + + // We didn't trace all the way back, so push down the target accordingly. +// VectorSubtract(cameraCurTarget, cameraFocusLoc, locdiff); +// VectorMA(cameraFocusLoc, trace.fraction, locdiff, cameraCurTarget); + //FIXME: when the trace hits movers, it gets very very jaggy... ? /* //this doesn't actually help any @@ -614,8 +682,11 @@ extern qboolean MatrixMode; static void CG_OffsetThirdPersonView( void ) { vec3_t diff; + float deltayaw; camWaterAdjust = 0; + cameraStiffFactor = 0.0; + // Set camera viewing direction. VectorCopy( cg.refdefViewAngles, cameraFocusAngles ); @@ -692,6 +763,26 @@ static void CG_OffsetThirdPersonView( void ) AngleVectors(cameraFocusAngles, camerafwd, NULL, cameraup); + deltayaw = fabs(cameraFocusAngles[YAW] - cameraLastYaw); + if (deltayaw > 180.0f) + { // Normalize this angle so that it is between 0 and 180. + deltayaw = fabs(deltayaw - 360.0f); + } + cameraStiffFactor = deltayaw / (float)(cg.time-cameraLastFrame); + if (cameraStiffFactor < 1.0) + { + cameraStiffFactor = 0.0; + } + else if (cameraStiffFactor > 2.5) + { + cameraStiffFactor = 0.75; + } + else + { // 1 to 2 scales from 0.0 to 0.5 + cameraStiffFactor = (cameraStiffFactor-1.0f)*0.5f; + } + cameraLastYaw = cameraFocusAngles[YAW]; + // Move the target to the new location. CG_UpdateThirdPersonTargetDamp(); CG_UpdateThirdPersonCameraDamp(); @@ -783,7 +874,7 @@ static void CG_OffsetThirdPersonView( void ) { // trace a ray from the origin to the viewpoint to make sure the view isn't // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything - CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predicted_player_state.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP ); + CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predicted_player_state.clientNum, MASK_CAMERACLIP ); if ( trace.fraction != 1.0 ) { VectorCopy( trace.endpos, view ); @@ -791,7 +882,7 @@ static void CG_OffsetThirdPersonView( void ) { // try another trace to this position, because a tunnel may have the ceiling // close enogh that this is poking out - CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predicted_player_state.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP ); + CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predicted_player_state.clientNum, MASK_CAMERACLIP ); VectorCopy( trace.endpos, view ); } @@ -856,7 +947,7 @@ static void CG_OffsetThirdPersonOverheadView( void ) { // Trace a ray from the origin to the viewpoint to make sure the view isn't // in a solid block. - CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predicted_player_state.clientNum, MASK_SOLID|CONTENTS_PLAYERCLIP ); + CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predicted_player_state.clientNum, MASK_CAMERACLIP); if ( trace.fraction != 1.0 ) { @@ -1217,7 +1308,10 @@ static qboolean CG_CalcFov( void ) { // if in intermission, use a fixed value fov_x = 80; } - else if ( cg.snap && cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD && !cg.renderingThirdPerson ) + else if ( cg.snap + && cg.snap->ps.viewEntity > 0 + && cg.snap->ps.viewEntity < ENTITYNUM_WORLD + && (!cg.renderingThirdPerson || g_entities[cg.snap->ps.viewEntity].e_DieFunc == dieF_camera_die) ) { // if in entity camera view, use a special FOV if ( &g_entities[cg.snap->ps.viewEntity] && @@ -1246,7 +1340,7 @@ static qboolean CG_CalcFov( void ) { } } } - else if ( (cg.snap->ps.forcePowersActive&(1<client->ps.forcePowerDuration[FP_SPEED] )//cg.renderingThirdPerson && + else if ( (!cg.zoomMode || cg.zoomMode > 2) && (cg.snap->ps.forcePowersActive&(1<client->ps.forcePowerDuration[FP_SPEED] )//cg.renderingThirdPerson && { fov_x = CG_ForceSpeedFOV(); } else { @@ -1307,9 +1401,10 @@ static qboolean CG_CalcFov( void ) { { snd = cgs.media.disruptorZoomLoop; } - + + // huh? This could probably just be added as a looping sound?? cgi_S_StartSound( cg.refdef.vieworg, ENTITYNUM_WORLD, CHAN_LOCAL, snd ); - zoomSoundTime = cg.time + 300; + zoomSoundTime = cg.time + 150; } } } @@ -1468,16 +1563,18 @@ static qboolean CG_CalcViewValues( void ) { if ( cg.snap->ps.viewEntity > 0 && cg.snap->ps.viewEntity < ENTITYNUM_WORLD ) {//in an entity camera view + /* if ( g_entities[cg.snap->ps.viewEntity].client && cg.renderingThirdPerson ) { VectorCopy( g_entities[cg.snap->ps.viewEntity].client->renderInfo.eyePoint, cg.refdef.vieworg ); } else + */ { VectorCopy( cg_entities[cg.snap->ps.viewEntity].lerpOrigin, cg.refdef.vieworg ); } VectorCopy( cg_entities[cg.snap->ps.viewEntity].lerpAngles, cg.refdefViewAngles ); - if ( !Q_stricmp( "misc_camera", g_entities[cg.snap->ps.viewEntity].classname )) + if ( !Q_stricmp( "misc_camera", g_entities[cg.snap->ps.viewEntity].classname ) || g_entities[cg.snap->ps.viewEntity].s.weapon == WP_TURRET ) { viewEntIsCam = qtrue; } @@ -1661,6 +1758,8 @@ Generates and draws a game scene and status information at the given time. ================= */ extern void CG_BuildSolidList( void ); +void cgi_CM_SnapPVS(vec3_t origin,byte *buffer); +extern vec3_t serverViewOrg; void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView ) { qboolean inwater = qfalse; @@ -1676,6 +1775,7 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView ) { return; } + CG_RunLightStyles(); // any looped sounds will be respecified as entities @@ -1685,11 +1785,10 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView ) { // clear all the render lists cgi_R_ClearScene(); - // set up cg.snap and possibly cg.nextSnap - CG_ProcessSnapshots(); - CG_BuildSolidList(); + // set up cg.snap and possibly cg.nextSnap + CG_ProcessSnapshots(); // if we haven't received any snapshots yet, all // we can draw is the information screen if ( !cg.snap ) { @@ -1720,13 +1819,21 @@ if (isForceSpeed&&!wasForceSpeed) wasForceSpeed=isForceSpeed; // - - if ( cg_entities[0].gent->s.eFlags & EF_LOCKED_TO_WEAPON && - cg.snap->ps.clientNum == 0 ) - { - speed *= 0.25f; + float mPitchOverride = 0.0f; + float mYawOverride = 0.0f; + if ( cg.snap->ps.clientNum == 0 ) + {//pointless check, but.. + if ( cg_entities[0].gent->s.eFlags & EF_LOCKED_TO_WEAPON ) + { + speed *= 0.25f; + } + if ( cg_entities[0].gent->s.eFlags & EF_IN_ATST ) + { + mPitchOverride = 0.01f; + mYawOverride = 0.0075f; + } } - cgi_SetUserCmdValue( cg.weaponSelect, speed ); + cgi_SetUserCmdValue( cg.weaponSelect, speed, mPitchOverride, mYawOverride ); // this counter will be bumped for every valid scene we generate cg.clientFrame++; @@ -1756,33 +1863,8 @@ wasForceSpeed=isForceSpeed; inwater = CG_CalcViewValues(); } - //check for opaque water - if ( 1 ) - { - vec3_t camTest; - VectorCopy( cg.refdef.vieworg, camTest ); - camTest[2] += 6; - if ( !(CG_PointContents( camTest, ENTITYNUM_NONE )&CONTENTS_SOLID) && !gi.inPVS( cg.refdef.vieworg, camTest ) ) - {//crossed visible line into another room - cg.refdef.vieworg[2] -= 6; - } - else - { - VectorCopy( cg.refdef.vieworg, camTest ); - camTest[2] -= 6; - if ( !(CG_PointContents( camTest, ENTITYNUM_NONE )&CONTENTS_SOLID) && !gi.inPVS( cg.refdef.vieworg, camTest ) ) - { - cg.refdef.vieworg[2] += 6; - } - } - /* - if ( (trace.contents&(CONTENTS_WATER|CONTENTS_OPAQUE)) ) - {//opaque water - } - */ - } - //This is done from the vieworg to get origin for non-attenuated sounds - cgi_S_UpdateAmbientSet( CG_ConfigString( CS_AMBIENT_SET ), cg.refdef.vieworg ); + // NOTE: this may completely override the camera + CG_RunEmplacedWeapon(); // first person blend blobs, done after AnglesToAxis if ( !cg.renderingThirdPerson ) { @@ -1796,8 +1878,43 @@ wasForceSpeed=isForceSpeed; CG_AddLocalEntities(); } - // NOTE: this may completely override the camera - CG_RunEmplacedWeapon(); + //check for opaque water + if ( 1 ) + { + vec3_t camTest; + VectorCopy( cg.refdef.vieworg, camTest ); + camTest[2] += 6; + if ( !(CG_PointContents( camTest, 0 )&CONTENTS_SOLID) && !gi.inPVS( cg.refdef.vieworg, camTest ) ) + {//crossed visible line into another room + cg.refdef.vieworg[2] -= 6; + //cgi_CM_SnapPVS(cg.refdef.vieworg,cg.snap->areamask); + } + else + { + VectorCopy( cg.refdef.vieworg, camTest ); + camTest[2] -= 6; + if ( !(CG_PointContents( camTest, 0 )&CONTENTS_SOLID) && !gi.inPVS( cg.refdef.vieworg, camTest ) ) + { + cg.refdef.vieworg[2] += 6; + //cgi_CM_SnapPVS(cg.refdef.vieworg,cg.snap->areamask); + } + else //if ( inwater ) + {//extra-special hack... sometimes when crouched in water with first person lightsaber, your PVS is wrong??? + /* + if ( !cg.renderingThirdPerson && (cg.snap->ps.weapon == WP_SABER||cg.snap->ps.weapon == WP_MELEE) ) + {//pseudo first-person for saber and fists + cgi_CM_SnapPVS(cg.refdef.vieworg,cg.snap->areamask); + } + */ + } + } + } + //FIXME: first person crouch-uncrouch STILL FUCKS UP THE AREAMASK!!! + //if ( !VectorCompare2( cg.refdef.vieworg, cg.snap->ps.serverViewOrg ) && !gi.inPVS( cg.refdef.vieworg, cg.snap->ps.serverViewOrg ) ) + {//actual view org and server's view org don't match and aren't same PVS, rebuild the areamask + //Com_Printf( S_COLOR_RED"%s != %s\n", vtos(cg.refdef.vieworg), vtos(cg.snap->ps.serverViewOrg) ); + cgi_CM_SnapPVS( cg.refdef.vieworg, cg.snap->areamask ); + } // Don't draw the in-view weapon when in camera mode if ( !in_camera @@ -1823,6 +1940,8 @@ wasForceSpeed=isForceSpeed; memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) ); // update audio positions + //This is done from the vieworg to get origin for non-attenuated sounds + cgi_S_UpdateAmbientSet( CG_ConfigString( CS_AMBIENT_SET ), cg.refdef.vieworg ); //NOTE: if we want to make you be able to hear far away sounds with electrobinoculars, add the hacked-in positional offset here (base on fov) cgi_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater ); @@ -1840,5 +1959,11 @@ wasForceSpeed=isForceSpeed; // actually issue the rendering calls CG_DrawActive( stereoView ); } + /* + if ( in_camera && !cg_skippingcin.integer ) + { + Com_Printf( S_COLOR_GREEN"ang: %s\n", vtos(cg.refdefViewAngles) ); + } + */ } diff --git a/code/cgame/cg_weapons.cpp b/code/cgame/cg_weapons.cpp index 77ce5d7..d303188 100644 --- a/code/cgame/cg_weapons.cpp +++ b/code/cgame/cg_weapons.cpp @@ -202,13 +202,15 @@ void CG_RegisterWeapon( int weaponNum ) { 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.HUDSaberStyle1 = cgi_R_RegisterShader( "gfx/hud/saber_styles1" ); - cgs.media.HUDSaberStyle2 = cgi_R_RegisterShader( "gfx/hud/saber_styles2" ); - cgs.media.HUDSaberStyle3 = cgi_R_RegisterShader( "gfx/hud/saber_styles3" ); + 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" ); @@ -298,7 +300,7 @@ void CG_RegisterWeapon( int weaponNum ) { 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/2d/corona" ); + cgs.media.forceCoronaShader = cgi_R_RegisterShaderNoMip( "gfx/hud/force_swirl" ); break; case WP_BRYAR_PISTOL: @@ -404,9 +406,6 @@ void CG_RegisterWeapon( int weaponNum ) { // theFxScheduler.RegisterEffect( "flechette/explosion" ); theFxScheduler.RegisterEffect( "flechette/alt_blow" ); - - cgi_S_RegisterSound( "sound/weapons/flechette/warning.wav" ); - cgs.media.flechetteStickSound = cgi_S_RegisterSound( "sound/weapons/flechette/stick.wav" ); break; case WP_ROCKET_LAUNCHER: @@ -454,8 +453,6 @@ void CG_RegisterWeapon( int weaponNum ) { theFxScheduler.RegisterEffect( "emplaced/shot" ); theFxScheduler.RegisterEffect( "emplaced/shotNPC" ); theFxScheduler.RegisterEffect( "emplaced/wall_impact" ); - theFxScheduler.RegisterEffect( "emplaced/flesh_impact" ); - theFxScheduler.RegisterEffect( "emplaced/droid_impact" ); cgi_R_RegisterShader( "models/map_objects/imp_mine/turret_chair_dmg" ); cgi_R_RegisterShader( "models/map_objects/imp_mine/turret_chair_on" ); @@ -481,6 +478,7 @@ void CG_RegisterWeapon( int weaponNum ) { 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: @@ -524,7 +522,14 @@ void CG_RegisterItemVisuals( int itemNum ) { itemInfo->models = cgi_R_RegisterModel( item->world_model ); -// itemInfo->icon = cgi_R_RegisterShaderNoMip( item->icon ); + if ( item->icon && item->icon[0] ) + { + itemInfo->icon = cgi_R_RegisterShaderNoMip( item->icon ); + } + else + { + itemInfo->icon = -1; + } if ( item->giType == IT_WEAPON ) { @@ -564,6 +569,7 @@ void CG_RegisterItemVisuals( int itemNum ) { case INV_SENTRY: CG_RegisterWeapon( WP_TURRET ); + cgi_S_RegisterSound( "sound/player/use_sentry" ); break; case INV_ELECTROBINOCULARS: @@ -630,7 +636,18 @@ int CG_MapTorsoToWeaponFrame( const clientInfo_t *ci, int frame, int animNum, in 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; @@ -851,7 +868,7 @@ void CG_AddViewWeapon( playerState_t *ps ) const weaponInfo_t *weapon; weaponData_t *wData; centity_t *cent; - float fovOffset; + float fovOffset, leanOffset; // no gun if in third person view if ( cg.renderingThirdPerson ) @@ -939,17 +956,36 @@ void CG_AddViewWeapon( playerState_t *ps ) fovOffset = 0; } + if ( cg.snap->ps.leanofs != 0 ) + { + //add leaning offset + leanOffset = cg.snap->ps.leanofs * 0.25f; + fovOffset += fabs(cg.snap->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 ); + } + // set up gun position CG_CalculateWeaponPosition( hand.origin, angles ); VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin ); - VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], 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 ); @@ -965,7 +1001,7 @@ void CG_AddViewWeapon( playerState_t *ps ) { // get clientinfo for animation map const clientInfo_t *ci = ¢->gent->client->clientInfo; - int torsoAnim = cent->pe.torso.animationNumber; + int torsoAnim = cent->gent->client->ps.torsoAnim;//pe.torso.animationNumber; float currentFrame; int startFrame,endFrame,flags; float animSpeed; @@ -974,10 +1010,10 @@ void CG_AddViewWeapon( playerState_t *ps ) 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 ); -// } + 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 { @@ -1209,7 +1245,7 @@ void CG_DrawIconBackground(void) int prongLeftX,prongRightX; qhandle_t background; - if ( cg.zoomMode != 0 ) + if (( cg.zoomMode != 0 ) || !( cg_drawHUD.integer )) { return; } @@ -1366,6 +1402,7 @@ void CG_DrawDataPadWeaponSelect( void ) int height; 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; @@ -1407,11 +1444,21 @@ void CG_DrawDataPadWeaponSelect( void ) sideRightIconCnt = holdCount - sideLeftIconCnt; } + // This seems to be a problem is datapad comes up too early + if (cg.DataPadWeaponSelectMAX_PLAYER_WEAPONS) + { + cg.DataPadWeaponSelect = MAX_PLAYER_WEAPONS; + } + i = cg.DataPadWeaponSelect - 1; if (i<1) { i = 13; - } + } smallIconSize = 40; bigIconSize = 80; @@ -1468,9 +1515,8 @@ void CG_DrawDataPadWeaponSelect( void ) height = bigIconSize * cg.iconHUDPercent; cgi_R_SetColor(NULL); - char buffer[256]; - - cgi_UI_GetItemText("datapadWeaponsMenu",va("weapondesc%d",cg.DataPadWeaponSelect+1),buffer); +// char buffer[256]; +// cgi_UI_GetItemText("datapadWeaponsMenu",va("weapondesc%d",cg.DataPadWeaponSelect+1),buffer); if (weaponData[cg.DataPadWeaponSelect].weaponIcon[0]) { @@ -1544,7 +1590,7 @@ void CG_DrawDataPadWeaponSelect( void ) CG_DisplayBoxedText(70,50,500,300,text, cgs.media.qhFontSmall, 0.7f, - colorTable[CT_WHITE] + textColor ); } @@ -1735,7 +1781,7 @@ void CG_DrawWeaponSelect( void ) cg.iconSelectTime = cg.weaponSelectTime; // showing weapon select clears pickup item display, but not the blend blob - cg.itemPickupTime = 0; + //cg.itemPickupTime = 0; bits = cg.snap->ps.stats[ STAT_WEAPONS ]; @@ -1900,18 +1946,13 @@ void CG_DrawWeaponSelect( void ) // draw the selected name if ( item && item->classname && item->classname[0] ) { - char itemName[256], data[1024]; - - sprintf( itemName, "INGAME_%s", item->classname ); + char text[1024]; - if ( cgi_SP_GetStringTextString( itemName, data, sizeof( data ))) + if ( cgi_SP_GetStringTextString( va("INGAME_%s",item->classname), text, sizeof( text ))) { -// Just doing this for now...... -//#ifdef _DEBUG - int w = cgi_R_Font_StrLenPixels(data, cgs.media.qhFontSmall, 1.0f); + int w = cgi_R_Font_StrLenPixels(text, cgs.media.qhFontSmall, 1.0f); int x = ( SCREEN_WIDTH - w ) / 2; - cgi_R_Font_DrawString(x, (SCREEN_HEIGHT - 24), data, textColor, cgs.media.qhFontSmall, -1, 1.0f); -//#endif + cgi_R_Font_DrawString(x, (SCREEN_HEIGHT - 24), text, textColor, cgs.media.qhFontSmall, -1, 1.0f); } } @@ -1953,7 +1994,7 @@ qboolean CG_WeaponSelectable( int i, int original, qboolean dpMode ) ? weaponData[i].energyPerShot : weaponData[i].altEnergyPerShot; - if ( cg.snap->ps.ammo[weaponData[i].ammoIndex] - usage_for_weap <= 0 ) + 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? { @@ -2039,8 +2080,7 @@ void CG_NextWeapon_f( void ) { CG_PlayerLockedWeaponSpeech( qfalse ); return; } - //FIXME: cheaper check? -// if ( !Q_stricmp( "atst", g_entities[0].NPC_type ) ) + if( g_entities[0].client && g_entities[0].client->NPC_class == CLASS_ATST ) { CG_ToggleATSTWeapon(); @@ -2186,8 +2226,7 @@ void CG_PrevWeapon_f( void ) { CG_PlayerLockedWeaponSpeech( qfalse ); return; } - //FIXME: cheaper check? -// if ( !Q_stricmp( "atst", g_entities[0].NPC_type ) ) + if( g_entities[0].client && g_entities[0].client->NPC_class == CLASS_ATST ) { CG_ToggleATSTWeapon(); @@ -2255,6 +2294,24 @@ void CG_ChangeWeapon( int 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; @@ -2265,9 +2322,15 @@ void CG_ChangeWeapon( int num ) CG_Weapon_f =============== */ -void CG_Weapon_f( void ) { +void CG_Weapon_f( void ) +{ int num; + if ( cg.weaponSelectTime + 200 > cg.time ) + { + return; + } + if ( !cg.snap ) { return; } @@ -2282,8 +2345,7 @@ void CG_Weapon_f( void ) { CG_PlayerLockedWeaponSpeech( qfalse ); return; } - //FIXME: cheaper check? -// if ( !Q_stricmp( "atst", g_entities[0].NPC_type ) ) + if( g_entities[0].client && g_entities[0].client->NPC_class == CLASS_ATST ) { CG_ToggleATSTWeapon(); @@ -2321,67 +2383,66 @@ void CG_Weapon_f( void ) { } else if ( num == cg.snap->ps.weapon ) {//already have it up, let's try to toggle it - //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" ) ); + 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 { - cgi_S_StartSound (NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgi_S_RegisterSound( "sound/weapons/saber/saberoff.wav" ) ); + cg_entities[0].gent->client->ps.saberActive = qtrue; } } - else - { - cg_entities[0].gent->client->ps.saberActive = qtrue; - } } } } - else if ( num >= WP_THERMAL && num <= WP_DET_PACK ) + else if ( num >= WP_THERMAL && num <= WP_DET_PACK ) // these weapons cycle { - if (cg.snap->ps.weapon >= WP_THERMAL && cg.snap->ps.weapon <= WP_DET_PACK ) + int weap, i = 0; + + if ( cg.snap->ps.weapon >= WP_THERMAL && cg.snap->ps.weapon <= WP_DET_PACK ) { - //cycle through these - int weap = cg.snap->ps.weapon + 1, ct = 0; + // 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 ( ct <= 3 ) + // prevent an endless loop + while ( i <= 4 ) + { + if ( weap > WP_DET_PACK ) { - if ( weap > WP_DET_PACK ) - { - weap = WP_THERMAL; - } + 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++; - ct++; - } - } - else //not in cycle range, but tyring to choose one - { - for (int ct=0; ct<3; ct++) - { - if ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) { - break; //have the weapon - } - num++; - if ( num > WP_DET_PACK ) - { - num = WP_THERMAL; - } - } + weap++; + i++; } } @@ -2410,8 +2471,6 @@ void CG_OutOfAmmoChange( void ) { if ( cg.weaponSelectTime + 200 > cg.time ) return; - //FIXME: cheaper check? -// if ( !Q_stricmp( "atst", g_entities[0].NPC_type ) ) if( g_entities[0].client && g_entities[0].client->NPC_class == CLASS_ATST ) { CG_ToggleATSTWeapon(); @@ -2420,23 +2479,45 @@ void CG_OutOfAmmoChange( void ) { original = cg.weaponSelect; - for ( i = WP_DET_PACK; i > 0 ; i-- ) { //We don't want the emplaced, or melee here + 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 ) ) { - if ( 1 == cg_autoswitch.integer && - ( i == WP_TRIP_MINE || i == WP_DET_PACK || i == WP_THERMAL || i == WP_ROCKET_LAUNCHER) ) // safe weapon switch + 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 ) ) { - // don't switch to this weapon - } - else - { - SetWeaponSelectTime(); -// cg.weaponSelectTime = cg.time; - cg.weaponSelect = i; - break; + 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; + } } @@ -2495,48 +2576,53 @@ void CG_FireWeapon( centity_t *cent, qboolean alt_fire ) if ( cent->gent->s.number == 0 ) switch (ent->weapon) { - // FIXME: These will need to be remapped to the most appropriate weapon since these are just leftovers - // from EF + // FIXME: I can NOT get this !@#$% iFeel USB mouse to work, it completely fails to register even with their + // latest drivers, and I haven't got time to get it working now so close to release, so here's a complete + // guess as to which FX forces go with which weapon. Sorry if they're crap... + // case WP_SABER: - //cgi_FF_StartFX( fffx_SwitchClick ); // repeat-fire handled above, but this just give an initial jolt + cgi_FF_StartFX( fffx_SwitchClick ); // repeat-fire handled above, but this just give an initial jolt break; case WP_DISRUPTOR: case WP_BRYAR_PISTOL: case WP_THERMAL: + case WP_DET_PACK: cgi_FF_StartFX( alt_fire ? fffx_Shotgun : fffx_Pistol); break; case WP_FLECHETTE: + cgi_FF_StartFX( alt_fire ? fffx_Shotgun : fffx_ShortPlasma); + break; + case WP_REPEATER: cgi_FF_StartFX( alt_fire ? fffx_MachineGun : fffx_GatlingGun); break; case WP_BLASTER: - cgi_FF_StartFX( alt_fire ? fffx_Missile : fffx_Pistol); + cgi_FF_StartFX( alt_fire ? fffx_Shotgun : fffx_Pistol); break; -/* - case WP_CHAOTICA_GUARD_GUN: - - cgi_FF_StartFX( alt_fire ? fffx_Missile : fffx_Pistol); + + case WP_ROCKET_LAUNCHER: + cgi_FF_StartFX( fffx_RocketLaunch ); break; - case WP_QUANTUM_BURST: - - cgi_FF_StartFX( alt_fire ? fffx_RocketLaunch : fffx_Punched); + case WP_BOWCASTER: + cgi_FF_StartFX( alt_fire ? fffx_Land : fffx_Jump); break; - case WP_DREADNOUGHT: - - cgi_FF_StartFX( fffx_Shotgun ); // repeat-fire handled above + case WP_DEMP2: + cgi_FF_StartFX( alt_fire ? fffx_Shotgun : fffx_Pistol); break; - case WP_TRICORDER: - - cgi_FF_StartFX( fffx_SwitchClick); + case WP_STUN_BATON: + cgi_FF_StartFX( fffx_Laser1 ); break; -*/ - } + + case WP_TRIP_MINE: + cgi_FF_StartFX( fffx_OutOfAmmo ); + break; + } // Do overcharge sound that get's added to the top /* if (( ent->powerups & ( 1<currentState; - weap = &cg_weapons[ WP_BLASTER ]; - - // must match cg_effects ( CG_Seeker ) & g_weapon ( SeekerAcquiresTarget ) & cg_weapons ( CG_FireSeeker ) - float angle = cg.time * 0.004f; - - org[0] = cg_entities[ent->eventParm].lerpOrigin[0] + 18 * cos( angle ); - org[1] = cg_entities[ent->eventParm].lerpOrigin[1] + 18 * sin( angle ); - org[2] = cg_entities[ent->eventParm].lerpOrigin[2] + cg.predicted_player_state.viewheight + 8 + (3 * cos(cg.time * 0.001)); - - cgi_S_StartSound( NULL, ent->eventParm, CHAN_WEAPON, cgi_S_RegisterSound( "sound/weapons/blaster/fire.wav" )); - theFxScheduler.PlayEffect( "blaster/muzzle_flash", org, cent->gent->pos1 ); -} - /* ================= CG_BounceEffect @@ -2884,7 +2943,7 @@ void CG_MissileHitPlayer( centity_t *cent, int weapon, vec3_t origin, vec3_t dir break; case WP_EMPLACED_GUN: - FX_EmplacedHitPlayer( origin, dir, humanoid ); + FX_EmplacedHitWall( origin, dir ); break; case WP_TRIP_MINE: @@ -2900,7 +2959,7 @@ void CG_MissileHitPlayer( centity_t *cent, int weapon, vec3_t origin, vec3_t dir break; case WP_ATST_MAIN: - FX_EmplacedHitPlayer( origin, dir, humanoid ); + FX_EmplacedHitWall( origin, dir ); break; case WP_ATST_SIDE: diff --git a/code/cgame/vssver.scc b/code/cgame/vssver.scc new file mode 100644 index 0000000..177f925 Binary files /dev/null and b/code/cgame/vssver.scc differ diff --git a/code/client/OpenAL/vssver.scc b/code/client/OpenAL/vssver.scc new file mode 100644 index 0000000..931cf94 Binary files /dev/null and b/code/client/OpenAL/vssver.scc differ diff --git a/code/client/cl_cgame.cpp b/code/client/cl_cgame.cpp index d9d71fb..0358383 100644 --- a/code/client/cl_cgame.cpp +++ b/code/client/cl_cgame.cpp @@ -175,9 +175,13 @@ Ghoul2 Insert End -void CL_SetUserCmdValue( int userCmdValue, float sensitivityScale ) { +extern float cl_mPitchOverride; +extern float cl_mYawOverride; +void CL_SetUserCmdValue( int userCmdValue, float sensitivityScale, float mPitchOverride, float mYawOverride ) { cl.cgameUserCmdValue = userCmdValue; cl.cgameSensitivity = sensitivityScale; + cl_mPitchOverride = mPitchOverride; + cl_mYawOverride = mYawOverride; } extern vec3_t cl_overriddenAngles; @@ -364,7 +368,7 @@ The cgame module is making a system call ==================== */ void *VM_ArgPtr( int intValue ); - +void CM_SnapPVS(vec3_t origin,byte *buffer); //#define VMA(x) VM_ArgPtr(args[x]) #define VMA(x) ((void*)args[x]) #define VMF(x) ((float *)args)[x] @@ -441,6 +445,9 @@ int CL_CgameSystemCalls( int *args ) { return 0; case CG_CM_MARKFRAGMENTS: return re.MarkFragments( args[1], (float(*)[3]) VMA(2), (const float *) VMA(3), args[4], (float *) VMA(5), args[6], (markFragment_t *) VMA(7) ); + case CG_CM_SNAPPVS: + CM_SnapPVS((float(*))VMA(1),(byte *) VMA(2)); + return 0; case CG_S_STARTSOUND: // stops an ERR_DROP internally if called illegally from game side, but note that it also gets here // legally during level start where normally the internal s_soundStarted check would return. So ok to hit this. @@ -599,7 +606,7 @@ int CL_CgameSystemCalls( int *args ) { case CG_GETUSERCMD: return CL_GetUserCmd( args[1], (usercmd_s *) VMA(2) ); case CG_SETUSERCMDVALUE: - CL_SetUserCmdValue( args[1], VMF(2) ); + CL_SetUserCmdValue( args[1], VMF(2), VMF(3), VMF(4) ); return 0; case CG_SETUSERCMDANGLES: CL_SetUserCmdAngles( VMF(1), VMF(2), VMF(3) ); @@ -876,8 +883,13 @@ void CL_CGameRendering( stereoFrame_t stereo ) { } } #endif + int timei=cl.serverTime; + if (timei>60) + { + timei-=0; + } G2API_SetTime(cl.serverTime,G2T_CG_TIME); - VM_Call( CG_DRAW_ACTIVE_FRAME, cl.serverTime, stereo, qfalse ); + VM_Call( CG_DRAW_ACTIVE_FRAME,timei, stereo, qfalse ); // VM_Debug( 0 ); } diff --git a/code/client/cl_cin.cpp b/code/client/cl_cin.cpp index f325f1a..cff3ce3 100644 --- a/code/client/cl_cin.cpp +++ b/code/client/cl_cin.cpp @@ -114,6 +114,7 @@ typedef struct { byte* buf; long drawX, drawY; sfxHandle_t hSFX; // 0 = none + qhandle_t hCRAWLTEXT; // 0 = none } cin_cache; static cinematics_t cin; @@ -188,7 +189,8 @@ static void RllSetupTable() // // Returns: Number of samples placed in output buffer //----------------------------------------------------------------------------- -long RllDecodeMonoToMono(unsigned char *from,short *to,unsigned int size,char signedOutput ,unsigned short flag) +/* +static long RllDecodeMonoToMono(unsigned char *from,short *to,unsigned int size,char signedOutput ,unsigned short flag) { unsigned int z; int prev; @@ -205,7 +207,7 @@ long RllDecodeMonoToMono(unsigned char *from,short *to,unsigned int size,char si } return size; //*sizeof(short)); } - +*/ //----------------------------------------------------------------------------- // RllDecodeMonoToStereo @@ -221,7 +223,7 @@ long RllDecodeMonoToMono(unsigned char *from,short *to,unsigned int size,char si // // Returns: Number of samples placed in output buffer //----------------------------------------------------------------------------- -long RllDecodeMonoToStereo(unsigned char *from,unsigned int size,char signedOutput,unsigned short flag, qboolean bMixedWithCurrentAudio) +static long RllDecodeMonoToStereo(unsigned char *from,unsigned int size,char signedOutput,unsigned short flag, qboolean bMixedWithCurrentAudio) { unsigned int z; int prev, dst; @@ -263,7 +265,7 @@ long RllDecodeMonoToStereo(unsigned char *from,unsigned int size,char signedOutp // // Returns: Number of samples placed in output buffer //----------------------------------------------------------------------------- -long RllDecodeStereoToStereo(unsigned char *from,unsigned int size,char signedOutput, unsigned short flag, qboolean bMixedWithCurrentAudio) +static long RllDecodeStereoToStereo(unsigned char *from,unsigned int size,char signedOutput, unsigned short flag, qboolean bMixedWithCurrentAudio) { unsigned int z; unsigned char *zz = from; @@ -356,7 +358,8 @@ long RllDecodeStereoToStereo(unsigned char *from,unsigned int size,char signedOu // // Returns: Number of samples placed in output buffer //----------------------------------------------------------------------------- -long RllDecodeStereoToMono(unsigned char *from,short *to,unsigned int size,char signedOutput, unsigned short flag) +/* +static long RllDecodeStereoToMono(unsigned char *from,short *to,unsigned int size,char signedOutput, unsigned short flag) { unsigned int z; int prevL,prevR; @@ -379,7 +382,7 @@ long RllDecodeStereoToMono(unsigned char *from,short *to,unsigned int size,char return size; } - +*/ /****************************************************************************** * * Function: @@ -900,7 +903,7 @@ static void readQuadInfo( byte *qData ) cinTable[currentHandle].drawY = 256; } if (cinTable[currentHandle].CIN_WIDTH != 256 || cinTable[currentHandle].CIN_HEIGHT != 256) { - Com_Printf("HACK: approxmimating cinematic for Rage Pro or Voodoo\n"); + Com_DPrintf("HACK: approxmimating cinematic for Rage Pro or Voodoo\n"); } } } @@ -1013,15 +1016,14 @@ static void RoQInterrupt(void) RoQReset(); } else { cinTable[currentHandle].status = FMV_EOF; + if (cinTable[currentHandle].hSFX && !cinTable[currentHandle].looping) + { + S_CIN_StopSound( cinTable[currentHandle].hSFX ); + } } } else { cinTable[currentHandle].status = FMV_IDLE; } - - if (cinTable[currentHandle].hSFX && !cinTable[currentHandle].looping) - { - S_CIN_StopSound( cinTable[currentHandle].hSFX ); - } return; } @@ -1416,6 +1418,7 @@ int CIN_PlayCinematic( const char *arg, int x, int y, int w, int h, int systemBi { cinTable[currentHandle].hSFX = 0; } + cinTable[currentHandle].hCRAWLTEXT = 0; if (cinTable[currentHandle].alterGameState) { @@ -1483,6 +1486,94 @@ void CIN_SetLooping(int handle, qboolean loop) { cinTable[handle].looping = loop; } +// Text crawl defines +#define TC_PLANE_WIDTH 250 +#define TC_PLANE_NEAR 90 +#define TC_PLANE_FAR 715 +#define TC_PLANE_TOP 0 +#define TC_PLANE_BOTTOM 1100 + +#define TC_DELAY 9000 +#define TC_STOPTIME 81000 +static void CIN_AddTextCrawl() +{ + refdef_t refdef; + polyVert_t verts[4]; + + // Set up refdef + memset( &refdef, 0, sizeof( refdef )); + + refdef.rdflags = RDF_NOWORLDMODEL; + AxisClear( refdef.viewaxis ); + + refdef.fov_x = 130; + refdef.fov_y = 130; + + refdef.x = 0; + refdef.y = -50; + refdef.width = cls.glconfig.vidWidth; + refdef.height = cls.glconfig.vidHeight * 2; // deliberately extend off the bottom of the screen + + // use to set shaderTime for scrolling shaders + refdef.time = 0; + + // Set up the poly verts + float fadeDown = 1.0; + if (cls.realtime-CL_iPlaybackStartTime >= (TC_STOPTIME-2500)) + { + fadeDown = (TC_STOPTIME - (cls.realtime-CL_iPlaybackStartTime))/ 2480.0f; + if (fadeDown < 0) + { + fadeDown = 0; + } + if (fadeDown > 1) + { + fadeDown = 1; + } + } + for ( int i = 0; i < 4; i++ ) + { + verts[i].modulate[0] = 255*fadeDown; // gold color? + verts[i].modulate[1] = 235*fadeDown; + verts[i].modulate[2] = 127*fadeDown; + verts[i].modulate[3] = 255*fadeDown; + } + + _VectorScale( verts[2].modulate, 0.1f, verts[2].modulate ); // darken at the top?? + _VectorScale( verts[3].modulate, 0.1f, verts[3].modulate ); + +#define TIMEOFFSET +(cls.realtime-CL_iPlaybackStartTime-TC_DELAY)*0.000015f -1 + VectorSet( verts[0].xyz, TC_PLANE_NEAR, -TC_PLANE_WIDTH, TC_PLANE_TOP ); + verts[0].st[0] = 1; + verts[0].st[1] = 1 TIMEOFFSET; + + VectorSet( verts[1].xyz, TC_PLANE_NEAR, TC_PLANE_WIDTH, TC_PLANE_TOP ); + verts[1].st[0] = 0; + verts[1].st[1] = 1 TIMEOFFSET; + + VectorSet( verts[2].xyz, TC_PLANE_FAR, TC_PLANE_WIDTH, TC_PLANE_BOTTOM ); + verts[2].st[0] = 0; + verts[2].st[1] = 0 TIMEOFFSET; + + VectorSet( verts[3].xyz, TC_PLANE_FAR, -TC_PLANE_WIDTH, TC_PLANE_BOTTOM ); + verts[3].st[0] = 1; + verts[3].st[1] = 0 TIMEOFFSET; + + // render it out + re.ClearScene(); + re.AddPolyToScene( cinTable[CL_handle].hCRAWLTEXT, 4, verts ); + re.RenderScene( &refdef ); + + //time's up + if (cls.realtime-CL_iPlaybackStartTime >= TC_STOPTIME) + { +// cinTable[currentHandle].holdAtEnd = qfalse; + cinTable[CL_handle].status = FMV_EOF; + RoQShutdown(); + SCR_StopCinematic(); // change ROQ from FMV_IDLE to FMV_EOF, and clear some other vars + } +} + /* ================== SCR_DrawCinematic @@ -1521,6 +1612,7 @@ void CIN_DrawCinematic (int handle) { re.DrawStretchRaw( x, y, w, h, 256, 256, (byte *)buf2, handle, qtrue); cinTable[handle].dirty = qfalse; Z_Free(buf2); + return; } @@ -1535,15 +1627,30 @@ extern qboolean s_soundStarted, s_soundMuted; // // ... and if the app isn't ready yet (which should only apply for the intro video), then I use these... // -char sPendingCinematic_Arg [256]={0}; -char sPendingCinematic_s [256]={0}; -qboolean gbPendingCinematic = qfalse; +static char sPendingCinematic_Arg [256]={0}; +static char sPendingCinematic_s [256]={0}; +static qboolean gbPendingCinematic = qfalse; // // This stuff is for EF1-type ingame cinematics... // -qboolean qbPlayingInGameCinematic = qfalse; -qboolean qbInGameCinematicOnStandBy = qfalse; -char sInGameCinematicStandingBy[MAX_QPATH]; +static qboolean qbPlayingInGameCinematic = qfalse; +static qboolean qbInGameCinematicOnStandBy = qfalse; +static char sInGameCinematicStandingBy[MAX_QPATH]; + + + +static qboolean CIN_HardwareReadyToPlayVideos(void) +{ + if (com_fullyInitialized && cls.rendererStarted && + cls.soundStarted && + cls.soundRegistered + ) + { + return qtrue; + } + + return qfalse; +} static void PlayCinematic(const char *arg, const char *s, qboolean qbInGame) @@ -1555,7 +1662,6 @@ static void PlayCinematic(const char *arg, const char *s, qboolean qbInGame) qbInGameCinematicOnStandBy = qfalse; - qboolean holdatend; int bits = qbInGame?0:CIN_system; Com_DPrintf("CL_PlayCinematic_f\n"); @@ -1575,7 +1681,7 @@ static void PlayCinematic(const char *arg, const char *s, qboolean qbInGame) SCR_StopCinematic(); // command-line hack to avoid problems when playing intro video before app is fully setup... // - if (!(com_fullyInitialized && s_soundStarted && !s_soundMuted)) + if (!CIN_HardwareReadyToPlayVideos()) { strcpy(sPendingCinematic_Arg,arg); strcpy(sPendingCinematic_s , (s&&s[0])?s:""); @@ -1585,8 +1691,7 @@ static void PlayCinematic(const char *arg, const char *s, qboolean qbInGame) qbPlayingInGameCinematic = qbInGame; - holdatend = qfalse; - if ((s && s[0] == '1') || Q_stricmp(arg,"demoend.roq")==0 || Q_stricmp(arg,"end.roq")==0) { + if ((s && s[0] == '1') || Q_stricmp(arg,"end.roq")==0) { bits |= CIN_hold; } if (s && s[0] == '2') { @@ -1601,18 +1706,29 @@ static void PlayCinematic(const char *arg, const char *s, qboolean qbInGame) // work out associated audio-overlay file, if any... // extern cvar_t *s_language; - qboolean bIsForeign = s_language && !(!stricmp(s_language->string,"english") || !stricmp(s_language->string,"")); + qboolean bIsForeign = s_language && stricmp(s_language->string,"english") && stricmp(s_language->string,""); LPCSTR psAudioFile = NULL; - if (bIsForeign && !stricmp(arg,"video/jk05.roq")) + qhandle_t hCrawl = 0; + if (!stricmp(arg,"video/jk0101_sw.roq")) { - psAudioFile = "sound/chars/video/cinematic_5"; - bits |= CIN_silent; // knock out existing english track + psAudioFile = "music/cinematic_1"; + hCrawl = re.RegisterShader( va("menu/video/tc_%d",sp_language->integer) ); + bits |= CIN_hold; } else - if (bIsForeign && !stricmp(arg,"video/jk06.roq")) + if (bIsForeign) { - psAudioFile = "sound/chars/video/cinematic_6"; - bits |= CIN_silent; // knock out existing english track + if (!stricmp(arg,"video/jk05.roq")) + { + psAudioFile = "sound/chars/video/cinematic_5"; + bits |= CIN_silent; // knock out existing english track + } + else + if (!stricmp(arg,"video/jk06.roq")) + { + psAudioFile = "sound/chars/video/cinematic_6"; + bits |= CIN_silent; // knock out existing english track + } } // //////////////////////////////////////////////////////////////////// @@ -1620,6 +1736,7 @@ static void PlayCinematic(const char *arg, const char *s, qboolean qbInGame) CL_handle = CIN_PlayCinematic( arg, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, bits, psAudioFile ); if (CL_handle >= 0) { + cinTable[CL_handle].hCRAWLTEXT = hCrawl; do { SCR_RunCinematic(); @@ -1666,9 +1783,7 @@ static void PlayCinematic(const char *arg, const char *s, qboolean qbInGame) qboolean CL_CheckPendingCinematic(void) { - if ( gbPendingCinematic && - (com_fullyInitialized && s_soundStarted && !s_soundMuted) - ) + if ( gbPendingCinematic && CIN_HardwareReadyToPlayVideos() ) { gbPendingCinematic = qfalse; // BEFORE next line, or we get recursion PlayCinematic(sPendingCinematic_Arg,sPendingCinematic_s[0]?sPendingCinematic_s:NULL,false); @@ -1713,6 +1828,10 @@ void SCR_DrawCinematic (void) if (CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES) { CIN_DrawCinematic(CL_handle); + if (cinTable[CL_handle].hCRAWLTEXT && (cls.realtime - CL_iPlaybackStartTime >= TC_DELAY)) + { + CIN_AddTextCrawl(); + } } } @@ -1723,7 +1842,7 @@ void SCR_RunCinematic (void) if (CL_handle >= 0 && CL_handle < MAX_VIDEO_HANDLES) { e_status Status = CIN_RunCinematic(CL_handle); - if (CL_IsRunningInGameCinematic() && Status == FMV_IDLE) + if (CL_IsRunningInGameCinematic() && Status == FMV_IDLE && !cinTable[CL_handle].holdAtEnd) { SCR_StopCinematic(); // change ROQ from FMV_IDLE to FMV_EOF, and clear some other vars } diff --git a/code/client/cl_console.cpp b/code/client/cl_console.cpp index 7228740..4c6778d 100644 --- a/code/client/cl_console.cpp +++ b/code/client/cl_console.cpp @@ -83,7 +83,7 @@ void Con_Dump_f (void) if (Cmd_Argc() != 2) { - Com_Printf ("usage: condump \n"); + Com_Printf (SP_GetStringTextString("CON_TEXT_DUMP_USAGE")); return; } @@ -164,15 +164,22 @@ void Con_CheckResize (void) if (width < 1) // video hasn't been initialized yet { + con.xadjust = 1; + con.yadjust = 1; width = DEFAULT_CONSOLE_WIDTH; con.linewidth = width; con.totallines = CON_TEXTSIZE / con.linewidth; for(i=0; i cls.glconfig.vidHeight ) lines = cls.glconfig.vidHeight; - // on wide screens, we will center the text - con.xadjust = 640.0f / cls.glconfig.vidWidth; - con.yadjust = 480.0f / cls.glconfig.vidHeight; - // draw the background y = frac * SCREEN_HEIGHT - 2; if ( y < 1 ) { diff --git a/code/client/cl_input.cpp b/code/client/cl_input.cpp index c2399e1..8494e56 100644 --- a/code/client/cl_input.cpp +++ b/code/client/cl_input.cpp @@ -388,6 +388,8 @@ void CL_JoystickMove( usercmd_t *cmd ) { CL_MouseMove ================= */ +float cl_mPitchOverride = 0.0f; +float cl_mYawOverride = 0.0f; void CL_MouseMove( usercmd_t *cmd ) { float mx, my; float accelSensitivity; @@ -426,9 +428,9 @@ void CL_MouseMove( usercmd_t *cmd ) { if ( in_strafe.active ) { cmd->rightmove = ClampChar( cmd->rightmove + m_side->value * mx ); } else { - if ( m_yawOverride->value ) + if ( cl_mYawOverride ) { - cl.viewangles[YAW] -= m_yawOverride->value * mx; + cl.viewangles[YAW] -= cl_mYawOverride * mx; } else { @@ -437,15 +439,15 @@ void CL_MouseMove( usercmd_t *cmd ) { } if ( (in_mlooking || cl_freelook->integer) && !in_strafe.active ) { - if ( m_pitchOverride->value ) + if ( cl_mPitchOverride ) { if ( m_pitch->value > 0 ) { - cl.viewangles[PITCH] += m_pitchOverride->value * my; + cl.viewangles[PITCH] += cl_mPitchOverride * my; } else { - cl.viewangles[PITCH] -= m_pitchOverride->value * my; + cl.viewangles[PITCH] -= cl_mPitchOverride * my; } } else diff --git a/code/client/cl_keys.cpp b/code/client/cl_keys.cpp index 0349c88..422d255 100644 --- a/code/client/cl_keys.cpp +++ b/code/client/cl_keys.cpp @@ -161,6 +161,134 @@ keyname_t keynames[] = {NULL,0} }; +//english printed keynames, for when we want what's printed to be different +//from the "technical" bind label +keyname_t keynames_e[] = +{ + {"TAB", K_TAB}, + {"ENTER", K_ENTER}, + {"ESCAPE", K_ESCAPE}, + {"SPACE", K_SPACE}, + {"BACKSPACE", K_BACKSPACE}, + {"UP", K_UPARROW}, + {"DOWN", K_DOWNARROW}, + {"LEFT", K_LEFTARROW}, + {"RIGHT", K_RIGHTARROW}, + + {"ALT", K_ALT}, + {"CTRL", K_CTRL}, + {"SHIFT", K_SHIFT}, + + {"COMMAND", K_COMMAND}, + + {"CAPSLOCK", K_CAPSLOCK}, + + + {"F1", K_F1}, + {"F2", K_F2}, + {"F3", K_F3}, + {"F4", K_F4}, + {"F5", K_F5}, + {"F6", K_F6}, + {"F7", K_F7}, + {"F8", K_F8}, + {"F9", K_F9}, + {"F10", K_F10}, + {"F11", K_F11}, + {"F12", K_F12}, + + {"INS", K_INS}, + {"DEL", K_DEL}, + {"PGDN", K_PGDN}, + {"PGUP", K_PGUP}, + {"HOME", K_HOME}, + {"END", K_END}, + + {"MOUSE1", K_MOUSE1}, + {"MOUSE2", K_MOUSE2}, + {"MOUSE3", K_MOUSE3}, + {"MOUSE4", K_MOUSE4}, + {"MOUSE5", K_MOUSE5}, + + {"MWHEELUP", K_MWHEELUP }, + {"MWHEELDOWN", K_MWHEELDOWN }, + + {"JOY1", K_JOY1}, + {"JOY2", K_JOY2}, + {"JOY3", K_JOY3}, + {"JOY4", K_JOY4}, + {"JOY5", K_JOY5}, + {"JOY6", K_JOY6}, + {"JOY7", K_JOY7}, + {"JOY8", K_JOY8}, + {"JOY9", K_JOY9}, + {"JOY10", K_JOY10}, + {"JOY11", K_JOY11}, + {"JOY12", K_JOY12}, + {"JOY13", K_JOY13}, + {"JOY14", K_JOY14}, + {"JOY15", K_JOY15}, + {"JOY16", K_JOY16}, + {"JOY17", K_JOY17}, + {"JOY18", K_JOY18}, + {"JOY19", K_JOY19}, + {"JOY20", K_JOY20}, + {"JOY21", K_JOY21}, + {"JOY22", K_JOY22}, + {"JOY23", K_JOY23}, + {"JOY24", K_JOY24}, + {"JOY25", K_JOY25}, + {"JOY26", K_JOY26}, + {"JOY27", K_JOY27}, + {"JOY28", K_JOY28}, + {"JOY29", K_JOY29}, + {"JOY30", K_JOY30}, + {"JOY31", K_JOY31}, + {"JOY32", K_JOY32}, + + {"AUX1", K_AUX1}, + {"AUX2", K_AUX2}, + {"AUX3", K_AUX3}, + {"AUX4", K_AUX4}, + {"AUX5", K_AUX5}, + {"AUX6", K_AUX6}, + {"AUX7", K_AUX7}, + {"AUX8", K_AUX8}, + {"AUX9", K_AUX9}, + {"AUX10", K_AUX10}, + {"AUX11", K_AUX11}, + {"AUX12", K_AUX12}, + {"AUX13", K_AUX13}, + {"AUX14", K_AUX14}, + {"AUX15", K_AUX15}, + {"AUX16", K_AUX16}, + + {"KP_HOME", K_KP_HOME }, + {"KP_UP", K_KP_UPARROW }, + {"KP_PGUP", K_KP_PGUP }, + {"KP_LEFT", K_KP_LEFTARROW }, + {"KP_5", K_KP_5 }, + {"KP_RIGHT", K_KP_RIGHTARROW }, + {"KP_END", K_KP_END }, + {"KP_DOWN", K_KP_DOWNARROW }, + {"KP_PGDN", K_KP_PGDN }, + {"KP_ENTER", K_KP_ENTER }, + {"KP_INS", K_KP_INS }, + {"KP_DEL", K_KP_DEL }, + {"KP_SLASH", K_KP_SLASH }, + {"KP_MINUS", K_KP_MINUS }, + {"KP_PLUS", K_KP_PLUS }, + {"KP_NUMLOCK", K_KP_NUMLOCK }, + {"KP_STAR", K_KP_STAR }, + {"KP_EQUALS", K_KP_EQUALS }, + + {"PAUSE", K_PAUSE}, + + {"SEMICOLON", ';'}, // because a raw semicolon seperates commands + + {NULL,0} +}; + keyname_t keynames_d[] = //deutsch { {"TAB", K_TAB}, @@ -175,7 +303,7 @@ keyname_t keynames_d[] = //deutsch {"ALT", K_ALT}, {"STRG", K_CTRL}, - {"UMSCHALLT", K_SHIFT}, + {"UMSCHALT", K_SHIFT}, {"FESTSTELLT", K_CAPSLOCK}, @@ -403,6 +531,8 @@ keyname_t keynames_f[] = //french {"COMMAND", K_COMMAND}, //mac + {"POINT-VIRGULE", ';' }, // because a raw semicolon seperates commands + {NULL,0} }; //end french @@ -1034,6 +1164,10 @@ char *Key_KeynumToString( int keynum, qboolean bTranslate ) { //note: translate } else if ( sp_language->integer == SP_LANGUAGE_FRENCH ) { kn=keynames_f; //use french } + else //rww - this is actually English and doesn't need to be "translated". + { //however, certain key names are too long to display right, this does the trick. + kn=keynames_e; + } } // check for a key string @@ -1091,6 +1225,7 @@ char *Key_GetBinding( int keynum ) { return ""; } + assert (keynum < (sizeof(keys)/sizeof(keys[0]))); return keys[ keynum ].binding; } diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index cd82605..8fe90f9 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -31,6 +31,7 @@ cvar_t *cl_avidemo; cvar_t *cl_pano; cvar_t *cl_panoNumShots; cvar_t *cl_skippingcin; +cvar_t *cl_endcredits; cvar_t *cl_freelook; cvar_t *cl_sensitivity; @@ -43,9 +44,7 @@ cvar_t *cl_VidFadeDown; cvar_t *cl_framerate; cvar_t *m_pitch; -cvar_t *m_pitchOverride; cvar_t *m_yaw; -cvar_t *m_yawOverride; cvar_t *m_forward; cvar_t *m_side; cvar_t *m_filter; @@ -263,7 +262,6 @@ void CL_Disconnect( void ) { cls.state = CA_DISCONNECTED; // allow cheats locally - Cvar_Set( "sv_cheats", "1" ); Cvar_Set( "timescale", "1" );//jic we were skipping Cvar_Set( "skippingCinematic", "0" );//jic we were skipping } @@ -438,6 +436,9 @@ void CL_Snd_Restart_f( void ) { extern void S_ReloadAllUsedSounds(void); S_ReloadAllUsedSounds(); + + extern void AS_ParseSets(void); + AS_ParseSets(); } /* ================== @@ -520,7 +521,7 @@ void CL_CheckForResend( void ) { case CA_CHALLENGING: // sending back the challenge - port = Cvar_VariableValue ("qport"); + port = Cvar_VariableIntegerValue("qport"); UI_UpdateConnectionString( va("(%i)", clc.connectPacketCount ) ); @@ -628,7 +629,7 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) { NET_AdrToString( clc.serverAddress ) ); return; } - Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableValue( "qport" ) ); + Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableIntegerValue( "qport" ) ); cls.state = CA_CONNECTED; clc.lastPacketSentTime = -9999; // send first packet immediately return; @@ -862,7 +863,7 @@ void CL_Frame ( int msec,float fractionMsec ) { cl_noprint->integer = oldnoprint; } - if (cl_skippingcin->integer) { + if (cl_skippingcin->integer && !cl_endcredits->integer) { if (cl_skippingcin->modified){ S_StopSounds(); //kill em all but music cl_skippingcin->modified=qfalse; @@ -1065,7 +1066,9 @@ CL_Init void CL_Init( void ) { Com_Printf( "----- Client Initialization -----\n" ); - Con_Init (); + SP_Register("con_text", SP_REGISTER_REQUIRED); //reference is CON_TEXT + + Con_Init (); CL_ClearState (); @@ -1093,6 +1096,7 @@ void CL_Init( void ) { cl_pano = Cvar_Get ("pano", "0", 0); cl_panoNumShots= Cvar_Get ("panoNumShots", "10", CVAR_ARCHIVE); cl_skippingcin = Cvar_Get ("skippingCinematic", "0", CVAR_ROM); + cl_endcredits = Cvar_Get ("cg_endcredits", "0", 0); cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", CVAR_ARCHIVE); cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "140", CVAR_ARCHIVE); @@ -1101,7 +1105,7 @@ void CL_Init( void ) { cl_maxpackets = Cvar_Get ("cl_maxpackets", "30", CVAR_ARCHIVE ); cl_packetdup = Cvar_Get ("cl_packetdup", "1", CVAR_ARCHIVE ); - cl_run = Cvar_Get ("cl_run", "0", CVAR_ARCHIVE); + cl_run = Cvar_Get ("cl_run", "1", CVAR_ARCHIVE); cl_sensitivity = Cvar_Get ("sensitivity", "5", CVAR_ARCHIVE); cl_mouseAccel = Cvar_Get ("cl_mouseAccel", "0", CVAR_ARCHIVE); cl_freelook = Cvar_Get( "cl_freelook", "1", CVAR_ARCHIVE ); @@ -1119,9 +1123,7 @@ void CL_Init( void ) { Cvar_Get ("cg_autoswitch", "1", CVAR_ARCHIVE); m_pitch = Cvar_Get ("m_pitch", "0.022", CVAR_ARCHIVE); - m_pitchOverride = Cvar_Get ("m_pitchOverride", "0", 0 ); m_yaw = Cvar_Get ("m_yaw", "0.022", CVAR_ARCHIVE); - m_yawOverride = Cvar_Get ("m_yawOverride", "0", 0 ); m_forward = Cvar_Get ("m_forward", "0.25", CVAR_ARCHIVE); m_side = Cvar_Get ("m_side", "0.25", CVAR_ARCHIVE); m_filter = Cvar_Get ("m_filter", "0", CVAR_ARCHIVE); diff --git a/code/client/cl_mp3.org b/code/client/cl_mp3.org new file mode 100644 index 0000000..1db5f52 --- /dev/null +++ b/code/client/cl_mp3.org @@ -0,0 +1,419 @@ +// Filename:- cl_mp3.cpp +// +// (The interface module between all the MP3 stuff and Trek) +// +#include "client.h" +#include "cl_mp3.h" //(only included directly from snd_mem.cpp, so not in client.h) +#include "../mp3code/mp3struct.h" // keep this rather awful file secret from the rest of the program + +// call the real worker code in the messy C stuff... +// +#ifdef __cplusplus +extern "C" +{ +#endif + +char* C_MP3_IsValid (void *pvData, int iDataLen); +char* C_MP3_GetUnpackedSize (void *pvData, int iDataLen, int *piUnpackedSize); +char* C_MP3_UnpackRawPCM (void *pvData, int iDataLen, int *piUnpackedSize, void *pbUnpackBuffer); +char* C_MP3_GetHeaderData (void *pvData, int iDataLen, int *piRate, int *piWidth, int *piChannels); +char* C_MP3Stream_DecodeInit (LP_MP3STREAM pSFX_MP3Stream, void *pvSourceData, int iSourceBytesRemaining, + int iGameAudioSampleRate, int iGameAudioSampleBits ); +unsigned int C_MP3Stream_Decode (LP_MP3STREAM pSFX_MP3Stream); +char* C_MP3Stream_Rewind (LP_MP3STREAM pSFX_MP3Stream); + + +// these two are temp and will eventually be deleted... honest... +// +char* C_TEST_MP3_GetUnpackedSize( const char *_FILENAME1, const char *_FILENAME2, const char *_FILENAME3, + void *data1,void *data2,void *data3, + int size1,int size2,int size3, + int *iUnpackedSize1,int *iUnpackedSize2,int *iUnpackedSize3 + ); +char * C_TEST_MP3_UnpackRawPCM(const char *_FILENAME1, const char *_FILENAME2, const char *_FILENAME3, + void *data1,void *data2,void *data3, + int iSourceBytesRemaining1,int iSourceBytesRemaining2,int iSourceBytesRemaining3, + int *piUnpackedSize1,int *piUnpackedSize2,int *piUnpackedSize3, + void *pbUnpackBuffer1,void *pbUnpackBuffer2,void *pbUnpackBuffer3 + ); + + +#ifdef __cplusplus +} +#endif + + + +// expects data already loaded, filename arg is for error printing only +// +// returns success/fail +// +qboolean MP3_IsValid( const char *psLocalFilename, void *pvData, int iDataLen ) +{ + char *psError = C_MP3_IsValid(pvData, iDataLen); + + if (psError) + { + Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename)); + } + + return !psError; +} + + + +// expects data already loaded, filename arg is for error printing only +// +// returns unpacked length, or 0 for errors (which will be printed internally) +// +int MP3_GetUnpackedSize( const char *psLocalFilename, void *pvData, int iDataLen, qboolean qbIgnoreID3Tag /* = qfalse */) +{ + int iUnpackedSize = 0; + + if (qbIgnoreID3Tag || !MP3_ReadSpecialTagInfo((byte *)pvData, iDataLen, NULL, &iUnpackedSize)) + { + char *psError = C_MP3_GetUnpackedSize( pvData, iDataLen, &iUnpackedSize); + + if (psError) + { + Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename)); + return 0; + } + } + + return iUnpackedSize; +} + + + +// expects data already loaded, filename arg is for error printing only +// +// returns byte count of unpacked data (effectively a success/fail bool) +// +int MP3_UnpackRawPCM( const char *psLocalFilename, void *pvData, int iDataLen, byte *pbUnpackBuffer ) +{ + int iUnpackedSize; + char *psError = C_MP3_UnpackRawPCM( pvData, iDataLen, &iUnpackedSize, pbUnpackBuffer); + + if (psError) + { + Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename)); + return 0; + } + + return iUnpackedSize; +} + + + +// expects data already loaded, filename arg is for error printing only +// +qboolean MP3_FakeUpWAVInfo( const char *psLocalFilename, void *pvData, int iDataLen, int iUnpackedDataLength, int &format, int &rate, int &width, int &channels, int &samples, int &dataofs) +{ + // some things can be done instantly... + // + format = 1; // 1 for MS format + dataofs= 0; // will be 0 for me (since there's no header in the unpacked data) + + // some things need to be read... + // + char *psError = C_MP3_GetHeaderData(pvData, iDataLen, &rate, &width, &channels); + if (psError) + { + Com_Printf(va(S_COLOR_RED"%s\n(File: %s)\n",psError, psLocalFilename)); + } + + // and some stuff needs calculating... + // + samples = iUnpackedDataLength / width; + + + return !psError; + +} + + + +const char sKEY_MAXVOL[]="#MAXVOL"; // formerly #defines +const char sKEY_UNCOMP[]="#UNCOMP"; // " " + +// returns qtrue for success... +// +qboolean MP3_ReadSpecialTagInfo(byte *pbLoadedFile, int iLoadedFileLen, // (in) + id3v1_1** ppTAG, // (out), can be NULL + int *piUncompressedSize, float *pfMaxVol // (out), can be NULL + ) +{ + qboolean qbError = qfalse; + + id3v1_1* pTAG = (id3v1_1*) ((pbLoadedFile+iLoadedFileLen)-sizeof(id3v1_1)); // sizeof = 128 + + if (!strncmp(pTAG->id, "TAG", 3)) + { + // TAG found... + // + + // read MAXVOL key... + // + if (strncmp(pTAG->comment, sKEY_MAXVOL, strlen(sKEY_MAXVOL))) + { + qbError = qtrue; + } + else + { + if ( pfMaxVol) + { + *pfMaxVol = atof(pTAG->comment + strlen(sKEY_MAXVOL)); + } + } + + // + // read UNCOMP key... + // + if (strncmp(pTAG->album, sKEY_UNCOMP, strlen(sKEY_UNCOMP))) + { + qbError = qtrue; + } + else + { + if ( piUncompressedSize) + { + *piUncompressedSize = atoi(pTAG->album + strlen(sKEY_UNCOMP)); + } + } + } + else + { + pTAG = NULL; + } + + if (ppTAG) + { + *ppTAG = pTAG; + } + + return (pTAG && !qbError); +} + + + +qboolean TEST_MP3_GetUnpackedSize(const char *_FILENAME1, const char *_FILENAME2, const char *_FILENAME3, + void *data1,void *data2,void *data3, + int size1,int size2,int size3, + int *iUnpackedSize1,int *iUnpackedSize2,int *iUnpackedSize3 + ) +{ + char *psError = C_TEST_MP3_GetUnpackedSize(_FILENAME1, _FILENAME2, _FILENAME3, + data1,data2,data3, + size1,size2,size3, + iUnpackedSize1,iUnpackedSize2,iUnpackedSize3 + ); + + if (psError) + { + Com_Printf(va(S_COLOR_RED"%s\n",psError)); + return qfalse; + } + + return qtrue; +} + + +// expects data already loaded, filename arg is for error printing only +// +// returns byte count of unpacked data (effectively a success/fail bool) +// +qboolean TEST_MP3_UnpackRawPCM( const char *_FILENAME1, const char *_FILENAME2, const char *_FILENAME3, + void *data1,void *data2,void *data3, + int iSourceBytesRemaining1,int iSourceBytesRemaining2,int iSourceBytesRemaining3, + int *piUnpackedSize1,int *piUnpackedSize2,int *piUnpackedSize3, + void *pbUnpackBuffer1,void *pbUnpackBuffer2,void *pbUnpackBuffer3 + ) +{ + char *psError = C_TEST_MP3_UnpackRawPCM(_FILENAME1, _FILENAME2, _FILENAME3, + data1,data2,data3, + iSourceBytesRemaining1,iSourceBytesRemaining2,iSourceBytesRemaining3, + piUnpackedSize1,piUnpackedSize2,piUnpackedSize3, + pbUnpackBuffer1,pbUnpackBuffer2,pbUnpackBuffer3 + ); + if (psError) + { + Com_Printf(va(S_COLOR_RED"%s\n",psError)); + return qfalse; + } + + return qtrue; +} + + + + + +// a file has been loaded in memory, see if we want to keep it as MP3, else as normal WAV... +// +// return = qtrue if keeping as MP3 +// +// (note: the reason I pass in the unpacked size rather than working it out here is simply because I already have it) +// +qboolean MP3Stream_InitFromFile( sfx_t* sfx, byte *pbSrcData, int iSrcDatalen, const char *psSrcDataFilename, int iMP3UnPackedSize ) +{ + // first, make a decision based on size here as to whether or not it's worth it because of MP3 buffer space + // making small files much bigger (and therefore best left as WAV)... + // +#define FUZZY_AMOUNT (5*1024) // so it has to be significantly over, not just break even, because of + // the xtra CPU time versus memory saving + + if (iSrcDatalen + sizeof(MP3STREAM) + FUZZY_AMOUNT < iMP3UnPackedSize) + { + // ok, let's keep it as MP3 then... + // + + float fMaxVol = 128; // seems to be a reasonable typical default for maxvol (for lip synch). Naturally there's no #define I can use instead... + + MP3_ReadSpecialTagInfo(pbSrcData, iSrcDatalen, NULL, NULL, &fMaxVol ); // try and read a read maxvol from MP3 header + + // fill in some sfx_t fields... + // + sfx->eCompressionType = ct_MP3; + sfx->data = (byte*) Hunk_Alloc( iSrcDatalen ); // will err_drop if fails + memcpy ( sfx->data, pbSrcData, iSrcDatalen ); // ... so the -> data field is MP3, not PCM + sfx->width = 2;//(s_compression->value == 1)?1:2; + sfx->length = (iMP3UnPackedSize / sfx->width) / (44100 / dma.speed); + sfx->vol_range = fMaxVol; + + // now init the low-level MP3 stuff... + // + MP3STREAM SFX_MP3Stream = {0}; + char *psError = C_MP3Stream_DecodeInit( &SFX_MP3Stream, sfx->data, iSrcDatalen, + dma.speed,//(s_khz->value == 44)?44100:(s_khz->value == 22)?22050:11025, + sfx->width * 8 + ); + if (psError) + { + // This should never happen, since any errors or problems with the MP3 file would have stopped us getting + // to this whole function, but just in case... + // + Com_Printf(va(S_COLOR_YELLOW"File \"%s\": %s\n",psSrcDataFilename,psError)); + + // This will leave iSrcDatalen bytes on the hunk stack (since you can't dealloc that), but MP3 files are + // usually small, and like I say, it should never happen. + // + // Strictly speaking, I should do a Z_Malloc above, then I could do a Z_Free if failed, else do a Hunk_Alloc + // to copy the Z_Malloc data into, then Z_Free, but for something that shouldn't happen it seemed bad to + // penalise the rest of the game with extra malloc demands. + // + return qfalse; + } + + // success ( ...on a plate). + // + // make a copy of the filled-in stream struct and attach to the sfx_t struct... + // + sfx->pMP3StreamHeader = (MP3STREAM *) Hunk_Alloc( sizeof(MP3STREAM) ); + memcpy( sfx->pMP3StreamHeader, &SFX_MP3Stream, sizeof(MP3STREAM) ); + // + return qtrue; + } + + return qfalse; +} + + +// return is decoded byte count, else 0 for finished +// +int MP3Stream_Decode( LP_MP3STREAM lpMP3Stream ) +{ + lpMP3Stream->iCopyOffset = 0; + return C_MP3Stream_Decode( lpMP3Stream ); +} + +// returns qtrue for all ok +// +// (this can be optimised by copying the whole header from the sfx struct sometime) +// +qboolean MP3Stream_Rewind( channel_t *ch ) +{ +/* char *psError = C_MP3Stream_Rewind( lpMP3Stream ); + + if (psError) + { + Com_Printf(S_COLOR_YELLOW"%s\n",psError); + return qfalse; + } + + return qtrue; +*/ + memcpy(&ch->MP3StreamHeader, ch->sfx->pMP3StreamHeader, sizeof(ch->MP3StreamHeader)); + return qtrue; +} + +void MP3Stream_GetSamples( channel_t *ch, int startingSampleNum, int count, short *buf ) +{ + static const int iQuarterOfSlidingBuffer = sizeof(ch->MP3SlidingDecodeBuffer)/4; + static const int iThreeQuartersOfSlidingBuffer = (sizeof(ch->MP3SlidingDecodeBuffer)*3)/4; + +// Com_Printf("startingSampleNum %d\n",startingSampleNum); + + count *= ch->sfx->width; // count arg was for words, so double it for bytes; + + startingSampleNum *= ch->sfx->width; + + if ( startingSampleNum < ch->iMP3SlidingDecodeWindowPos) + { + // what?!?!?! Fucking time travel needed or something?, forget it + memset(buf,0,count); + return; + } + +// OutputDebugString(va("\nRequest: startingSampleNum %d, count %d\n",startingSampleNum,count)); +// OutputDebugString(va("WindowPos %d, WindowWritePos %d\n",ch->iMP3SlidingDecodeWindowPos,ch->iMP3SlidingDecodeWritePos)); + + while (! + ( + (startingSampleNum >= ch->iMP3SlidingDecodeWindowPos) + && + (startingSampleNum + count < ch->iMP3SlidingDecodeWindowPos + ch->iMP3SlidingDecodeWritePos) + ) + ) + { +// OutputDebugString("Scrolling..."); + + int _iBytesDecoded = MP3Stream_Decode( (LP_MP3STREAM) &ch->MP3StreamHeader ); +// OutputDebugString(va("%d bytes decoded\n",_iBytesDecoded)); + if (_iBytesDecoded == 0) + { + // no more source data left so clear the remainder of the buffer... + // + memset(ch->MP3SlidingDecodeBuffer + ch->iMP3SlidingDecodeWritePos, 0, sizeof(ch->MP3SlidingDecodeBuffer)-ch->iMP3SlidingDecodeWritePos); + //MP3Stream_Rewind(ch); // should I do this??? +// OutputDebugString("Finished\n"); + break; + } + else + { + memcpy(ch->MP3SlidingDecodeBuffer + ch->iMP3SlidingDecodeWritePos,ch->MP3StreamHeader.bDecodeBuffer,_iBytesDecoded); + + ch->iMP3SlidingDecodeWritePos += _iBytesDecoded; + + // if reached 3/4 of buffer pos, backscroll the decode window by one quarter... + // + if (ch->iMP3SlidingDecodeWritePos > (sizeof(ch->MP3SlidingDecodeBuffer)*3)/4) + { + memmove(ch->MP3SlidingDecodeBuffer, ((byte *)ch->MP3SlidingDecodeBuffer + (sizeof(ch->MP3SlidingDecodeBuffer)/4)), (sizeof(ch->MP3SlidingDecodeBuffer)*3)/4); + ch->iMP3SlidingDecodeWritePos -= sizeof(ch->MP3SlidingDecodeBuffer)/4; + ch->iMP3SlidingDecodeWindowPos+= sizeof(ch->MP3SlidingDecodeBuffer)/4; + } + } +// OutputDebugString(va("WindowPos %d, WindowWritePos %d\n",ch->iMP3SlidingDecodeWindowPos,ch->iMP3SlidingDecodeWritePos)); + } + + assert(startingSampleNum >= ch->iMP3SlidingDecodeWindowPos); + memcpy( buf, ch->MP3SlidingDecodeBuffer + (startingSampleNum-ch->iMP3SlidingDecodeWindowPos), count); + + +// OutputDebugString("OK\n"); +} + + +///////////// eof ///////////// + diff --git a/code/client/cl_parse.cpp b/code/client/cl_parse.cpp index e0b5e05..3e23663 100644 --- a/code/client/cl_parse.cpp +++ b/code/client/cl_parse.cpp @@ -309,7 +309,7 @@ void CL_SystemInfoChanged( void ) { systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ]; cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) ); - s = Info_ValueForKey( systemInfo, "sv_cheats" ); + s = Info_ValueForKey( systemInfo, "helpUsObi" ); if ( atoi(s) == 0 ) { Cvar_SetCheatState(); } @@ -324,6 +324,13 @@ void CL_SystemInfoChanged( void ) { Cvar_Set( key, value ); } + extern cvar_t *s_language; + if ( ( Q_stricmp( "DEUTSCH", s_language->string ) == 0 )//voice language is German + || (sp_language->integer == SP_LANGUAGE_GERMAN )//text language is German + || Cvar_VariableIntegerValue("ui_iscensored") == 1 ) + { + Cvar_Set( "g_dismemberment", "0"); + } } void UI_UpdateConnectionString( char *string ); diff --git a/code/client/cl_ui.cpp b/code/client/cl_ui.cpp index 6e49456..7afdcfa 100644 --- a/code/client/cl_ui.cpp +++ b/code/client/cl_ui.cpp @@ -291,6 +291,10 @@ void CL_InitUI( void ) { qboolean UI_GameCommand( void ) { + if (!cls.uiStarted) + { + return qfalse; + } return UI_ConsoleCommand(); } @@ -299,7 +303,9 @@ void CL_GenericMenu_f(void) { char *arg = Cmd_Argv( 1 ); - UI_SetActiveMenu("ingame",arg); + if (cls.uiStarted) { + UI_SetActiveMenu("ingame",arg); + } } @@ -310,10 +316,9 @@ void CL_EndScreenDissolve_f(void) void CL_DataPad_f(void) { - Cvar_Set( "cl_paused", "1" ); - UI_SetActiveMenu("datapad",NULL); - Key_SetCatcher( KEYCATCH_UI ); - + if (cls.uiStarted && cls.cgameStarted && (cls.state == CA_ACTIVE) ) { + UI_SetActiveMenu("datapad",NULL); + } } /* diff --git a/code/client/client.h b/code/client/client.h index c3dc515..53e235d 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -275,9 +275,7 @@ extern cvar_t *cl_VidFadeUp; extern cvar_t *cl_VidFadeDown; extern cvar_t *m_pitch; -extern cvar_t *m_pitchOverride; extern cvar_t *m_yaw; -extern cvar_t *m_yawOverride; extern cvar_t *m_forward; extern cvar_t *m_side; extern cvar_t *m_filter; diff --git a/code/client/eax/vssver.scc b/code/client/eax/vssver.scc new file mode 100644 index 0000000..0af2ca0 Binary files /dev/null and b/code/client/eax/vssver.scc differ diff --git a/code/client/snd_ambient.cpp b/code/client/snd_ambient.cpp index c36bf1a..2ebb112 100644 --- a/code/client/snd_ambient.cpp +++ b/code/client/snd_ambient.cpp @@ -252,7 +252,9 @@ static void AS_GetTimeBetweenWaves( ambientSet_t &set ) //Check for swapped start / end if ( startTime > endTime ) { + #ifndef FINAL_BUILD Com_Printf(S_COLOR_YELLOW"WARNING: Corrected swapped start / end times in a \"timeBetweenWaves\" keyword\n"); + #endif int swap = startTime; startTime = endTime; @@ -287,27 +289,33 @@ static void AS_GetSubWaves( ambientSet_t &set ) //Get all the subwaves while ( parsePos <= parseSize ) { - if ( set.numSubWaves > MAX_WAVES_PER_GROUP ) - { - Com_Printf(S_COLOR_YELLOW"WARNING: Too many subwaves on set \"%s\"\n", set.name ); - } - //Get the data sscanf( parseBuffer+parsePos, "%s", &waveBuffer ); - //Construct the wave name (pretty, huh?) - strcpy( (char *) waveName, "sound/" ); - strncat( (char *) waveName, (const char *) dirBuffer, 1024 ); - strncat( (char *) waveName, "/", 512 ); - strncat( (char *) waveName, (const char *) waveBuffer, 512 ); - strncat( (char *) waveName, ".wav", 512 ); - - //Place this onto the sound directory name - - //Precache the file at this point and store off the ID instead of the name - if ( ( set.subWaves[set.numSubWaves++] = S_RegisterSound( waveName ) ) <= 0 ) + if ( set.numSubWaves > MAX_WAVES_PER_GROUP ) { - Com_Printf(S_COLOR_YELLOW"WARNING: Unable to load ambient sound \"%s\"\n", waveName); + #ifndef FINAL_BUILD + Com_Printf(S_COLOR_YELLOW"WARNING: Too many subwaves on set \"%s\"\n", set.name ); + #endif + } + else + { + //Construct the wave name (pretty, huh?) + strcpy( (char *) waveName, "sound/" ); + strncat( (char *) waveName, (const char *) dirBuffer, 1024 ); + strncat( (char *) waveName, "/", 512 ); + strncat( (char *) waveName, (const char *) waveBuffer, 512 ); + strncat( (char *) waveName, ".wav", 512 ); + + //Place this onto the sound directory name + + //Precache the file at this point and store off the ID instead of the name + if ( ( set.subWaves[set.numSubWaves++] = S_RegisterSound( waveName ) ) <= 0 ) + { + #ifndef FINAL_BUILD + Com_Printf(S_COLOR_YELLOW"WARNING: Unable to load ambient sound \"%s\"\n", waveName); + #endif + } } //Move the pointer past this string @@ -343,7 +351,9 @@ static void AS_GetLoopedWave( ambientSet_t &set ) //Precache the file at this point and store off the ID instead of the name if ( ( set.loopedWave = S_RegisterSound( waveName ) ) <= 0 ) { + #ifndef FINAL_BUILD Com_Printf(S_COLOR_YELLOW"WARNING: Unable to load ambient sound \"%s\"\n", waveName); + #endif } AS_SkipLine(); @@ -365,7 +375,9 @@ static void AS_GetVolumeRange( ambientSet_t &set ) //Check for swapped min / max if ( min > max ) { + #ifndef FINAL_BUILD Com_Printf(S_COLOR_YELLOW"WARNING: Corrected swapped min / max range in a \"volRange\" keyword\n"); + #endif int swap = min; min = max; @@ -441,7 +453,9 @@ static void AS_GetGeneralSet( ambientSet_t &set ) return; //This wasn't a set name, so it's an error + #ifndef FINAL_BUILD Com_Printf( S_COLOR_YELLOW"WARNING: Unknown ambient set keyword \"%s\"\n", tempBuffer ); + #endif } return; @@ -502,7 +516,9 @@ static void AS_GetLocalSet( ambientSet_t &set ) return; //This wasn't a set name, so it's an error + #ifndef FINAL_BUILD Com_Printf( S_COLOR_YELLOW"WARNING: Unknown ambient set keyword \"%s\"\n", tempBuffer ); + #endif } return; @@ -547,7 +563,9 @@ static void AS_GetBModelSet( ambientSet_t &set ) return; //This wasn't a set name, so it's an error + #ifndef FINAL_BUILD Com_Printf( S_COLOR_YELLOW"WARNING: Unknown ambient set keyword \"%s\"\n", tempBuffer ); + #endif } return; @@ -727,7 +745,14 @@ AS_AddPrecacheEntry void AS_AddPrecacheEntry( const char *name ) { - pMap[ name ] = 1; + if (!stricmp(name,"#clear")) + { + pMap.clear(); + } + else + { + pMap[ name ] = 1; + } } /* @@ -768,8 +793,8 @@ void AS_ParseSets( void ) Com_Error( ERR_DROP, "....%d missing sound sets! (see above)\n", iErrorsOccured); } - //Done with the precache info, it will be rebuilt on a restart - pMap.clear(); +// //Done with the precache info, it will be rebuilt on a restart +// pMap.clear(); // do NOT do this here now } /* diff --git a/code/client/snd_dma.cpp b/code/client/snd_dma.cpp index b42cbd3..58f8ee1 100644 --- a/code/client/snd_dma.cpp +++ b/code/client/snd_dma.cpp @@ -104,6 +104,7 @@ static qboolean bMusic_IsDynamic = qfalse; static MusicState_e eMusic_StateActual = eBGRNDTRACK_EXPLORE; // actual state, can be any enum static MusicState_e eMusic_StateRequest = eBGRNDTRACK_EXPLORE; // requested state, can only be explore, action, boss, or silence static char sMusic_BackgroundLoop[MAX_QPATH] = {0}; // only valid for non-dynamic music +static char sInfoOnly_CurrentDynamicMusicSet[64]; // any old reasonable size, only has to fit stuff like "kejim_post" // ////////////////////////// @@ -149,6 +150,7 @@ cvar_t *s_volume; cvar_t *s_volumeVoice; cvar_t *s_testsound; cvar_t *s_khz; +cvar_t *s_allowDynamicMusic; cvar_t *s_show; cvar_t *s_mixahead; cvar_t *s_mixPreStep; @@ -315,9 +317,14 @@ void S_SoundInfo_f(void) { if (bMusic_IsDynamic) { DynamicMusicInfoPrint(); + Com_Printf("( Dynamic music set name: \"%s\" )\n",sInfoOnly_CurrentDynamicMusicSet); } else { + if (!s_allowDynamicMusic->integer) + { + Com_Printf("( Dynamic music inhibited (s_allowDynamicMusic == 0) )\n", sMusic_BackgroundLoop ); + } if ( tMusic_Info[eBGRNDTRACK_NONDYNAMIC].s_backgroundFile ) { Com_Printf("Background file: %s\n", sMusic_BackgroundLoop ); @@ -354,9 +361,10 @@ void S_Init( void ) { s_volume = Cvar_Get ("s_volume", "0.5", CVAR_ARCHIVE); s_volumeVoice= Cvar_Get ("s_volumeVoice", "1.0", CVAR_ARCHIVE); - s_musicVolume = Cvar_Get ("s_musicvolume", "0.5", CVAR_ARCHIVE); + s_musicVolume = Cvar_Get ("s_musicvolume", "0.25", CVAR_ARCHIVE); s_separation = Cvar_Get ("s_separation", "0.5", CVAR_ARCHIVE); s_khz = Cvar_Get ("s_khz", "22", CVAR_ARCHIVE|CVAR_LATCH); + s_allowDynamicMusic = Cvar_Get ("s_allowDynamicMusic", "1", CVAR_ARCHIVE); s_mixahead = Cvar_Get ("s_mixahead", "0.2", CVAR_ARCHIVE); s_mixPreStep = Cvar_Get ("s_mixPreStep", "0.05", CVAR_ARCHIVE); @@ -382,8 +390,9 @@ void S_Init( void ) { #endif #endif - cv = Cvar_Get ("s_initsound", "1", 0); + cv = Cvar_Get ("s_initsound", "1", CVAR_ROM); if ( !cv->integer ) { + s_soundStarted = 0; // needed in case you set s_initsound to 0 midgame then snd_restart (div0 err otherwise later) Com_Printf ("not initializing.\n"); Com_Printf("------------------------------------\n"); return; @@ -539,14 +548,17 @@ void S_Init( void ) { // void S_ReloadAllUsedSounds(void) { - // new bit, reload all soundsthat are used on the current level... - // - for (int i=1 ; i < s_numSfx ; i++) // start @ 1 to skip freeing default sound + if (s_soundStarted && !s_soundMuted ) { - sfx_t *sfx = &s_knownSfx[i]; + // new bit, reload all soundsthat are used on the current level... + // + for (int i=1 ; i < s_numSfx ; i++) // start @ 1 to skip freeing default sound + { + sfx_t *sfx = &s_knownSfx[i]; - if (!sfx->bInMemory && !sfx->bDefaultSound && sfx->iLastLevelUsedOn == RE_RegisterMedia_GetLevel()){ - S_memoryLoad(sfx); + if (!sfx->bInMemory && !sfx->bDefaultSound && sfx->iLastLevelUsedOn == RE_RegisterMedia_GetLevel()){ + S_memoryLoad(sfx); + } } } } @@ -851,7 +863,7 @@ void EALFileInit(char *level) // Try and load an EAL file for the new level COM_StripExtension(level, name); - Com_sprintf(szEALFilename, MAX_QPATH, "%s.eal", name); + Com_sprintf(szEALFilename, MAX_QPATH, "eagle/%s.eal", name); s_bEALFileLoaded = LoadEALFile(szEALFilename); @@ -1050,6 +1062,7 @@ channel_t *S_OpenALPickChannel(int entnum, int entchannel) int ch_idx; channel_t *ch, *ch_firstToDie; bool foundChan = false; + float source_pos[3]; if ( entchannel < 0 ) { @@ -1096,36 +1109,80 @@ channel_t *S_OpenALPickChannel(int entnum, int entchannel) if (ch->fixed_origin) { - longestDist = ((listener_pos[0] - ch->origin[0]) * (listener_pos[0] - ch->origin[0])) + - ((listener_pos[1] - ch->origin[1]) * (listener_pos[1] - ch->origin[1])) + - ((listener_pos[2] - ch->origin[2]) * (listener_pos[2] - ch->origin[2])); + // Convert to Open AL co-ordinates + source_pos[0] = ch->origin[0]; + source_pos[1] = ch->origin[2]; + source_pos[2] = -ch->origin[1]; + + longestDist = ((listener_pos[0] - source_pos[0]) * (listener_pos[0] - source_pos[0])) + + ((listener_pos[1] - source_pos[1]) * (listener_pos[1] - source_pos[1])) + + ((listener_pos[2] - source_pos[2]) * (listener_pos[2] - source_pos[2])); } else { if (ch->entnum == listener_number) longestDist = 0; else - longestDist = ((listener_pos[0] - loopSounds[ch->entnum].origin[0]) * (listener_pos[0] - loopSounds[ch->entnum].origin[0])) + - ((listener_pos[1] - loopSounds[ch->entnum].origin[1]) * (listener_pos[1] - loopSounds[ch->entnum].origin[1])) + - ((listener_pos[2] - loopSounds[ch->entnum].origin[2]) * (listener_pos[2] - loopSounds[ch->entnum].origin[2])); + { + if (ch->bLooping) + { + // Convert to Open AL co-ordinates + source_pos[0] = loopSounds[ch->entnum].origin[0]; + source_pos[1] = loopSounds[ch->entnum].origin[2]; + source_pos[2] = -loopSounds[ch->entnum].origin[1]; + } + else + { + // Convert to Open AL co-ordinates + source_pos[0] = s_entityPosition[ch->entnum][0]; + source_pos[1] = s_entityPosition[ch->entnum][2]; + source_pos[2] = -s_entityPosition[ch->entnum][1]; + } + + longestDist = ((listener_pos[0] - source_pos[0]) * (listener_pos[0] - source_pos[0])) + + ((listener_pos[1] - source_pos[1]) * (listener_pos[1] - source_pos[1])) + + ((listener_pos[2] - source_pos[2]) * (listener_pos[2] - source_pos[2])); + } } for (ch_idx = 2, ch = s_channels + ch_idx; ch_idx < s_numChannels; ch_idx++, ch++) { if (ch->fixed_origin) { - dist = ((listener_pos[0] - ch->origin[0]) * (listener_pos[0] - ch->origin[0])) + - ((listener_pos[1] - ch->origin[1]) * (listener_pos[1] - ch->origin[1])) + - ((listener_pos[2] - ch->origin[2]) * (listener_pos[2] - ch->origin[2])); + // Convert to Open AL co-ordinates + source_pos[0] = ch->origin[0]; + source_pos[1] = ch->origin[2]; + source_pos[2] = -ch->origin[1]; + + dist = ((listener_pos[0] - source_pos[0]) * (listener_pos[0] - source_pos[0])) + + ((listener_pos[1] - source_pos[1]) * (listener_pos[1] - source_pos[1])) + + ((listener_pos[2] - source_pos[2]) * (listener_pos[2] - source_pos[2])); } else { if (ch->entnum == listener_number) dist = 0; else - dist = ((listener_pos[0] - loopSounds[ch->entnum].origin[0]) * (listener_pos[0] - loopSounds[ch->entnum].origin[0])) + - ((listener_pos[1] - loopSounds[ch->entnum].origin[1]) * (listener_pos[1] - loopSounds[ch->entnum].origin[1])) + - ((listener_pos[2] - loopSounds[ch->entnum].origin[2]) * (listener_pos[2] - loopSounds[ch->entnum].origin[2])); + { + if (ch->bLooping) + { + // Convert to Open AL co-ordinates + source_pos[0] = loopSounds[ch->entnum].origin[0]; + source_pos[1] = loopSounds[ch->entnum].origin[2]; + source_pos[2] = -loopSounds[ch->entnum].origin[1]; + } + else + { + // Convert to Open AL co-ordinates + source_pos[0] = s_entityPosition[ch->entnum][0]; + source_pos[1] = s_entityPosition[ch->entnum][2]; + source_pos[2] = -s_entityPosition[ch->entnum][1]; + } + + dist = ((listener_pos[0] - source_pos[0]) * (listener_pos[0] - source_pos[0])) + + ((listener_pos[1] - source_pos[1]) * (listener_pos[1] - source_pos[1])) + + ((listener_pos[2] - source_pos[2]) * (listener_pos[2] - source_pos[2])); + } } if (dist > longestDist) @@ -1179,6 +1236,7 @@ void S_SpatializeOrigin (const vec3_t origin, float master_vol, int *left_vol, i if ( channel == CHAN_VOICE ) { dist -= SOUND_FULLVOLUME * 3.0f; +// dist_mult = VOICE_ATTENUATE; // tweak added (this fixes an NPC dialogue "in your ears" bug, but we're not sure if it'll make a bunch of others fade too early. Too close to shipping...) } else if ( channel == CHAN_LESS_ATTEN ) { @@ -1509,12 +1567,19 @@ void S_CIN_StopSound(sfxHandle_t sfxHandle) sfx_t *sfx = &s_knownSfx[ sfxHandle ]; channel_t *ch = s_channels; - - for (int i = 0; i < s_numChannels; i++, ch++) + int i; + + for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) { + if ( !ch->thesfx || (ch->leftvol<0.25 && ch->rightvol<0.25 )) { + continue; + } if (ch->thesfx == sfx) { - alSourceStop(s_channels[i].alSource); + if (s_UseOpenAL) + { + alSourceStop(s_channels[i].alSource); + } SND_FreeSFXMem(ch->thesfx); // heh, may as well... ch->thesfx = NULL; memset(&ch->MP3StreamHeader, 0, sizeof(MP3STREAM)); @@ -2524,9 +2589,18 @@ void S_Update_(void) { else { // Get position of Entity - pos[0] = loopSounds[ ch->entnum ].origin[0]; - pos[1] = loopSounds[ ch->entnum ].origin[2]; - pos[2] = -loopSounds[ ch->entnum ].origin[1]; + if (ch->bLooping) + { + pos[0] = loopSounds[ ch->entnum ].origin[0]; + pos[1] = loopSounds[ ch->entnum ].origin[2]; + pos[2] = -loopSounds[ ch->entnum ].origin[1]; + } + else + { + pos[0] = s_entityPosition[ch->entnum][0]; + pos[1] = s_entityPosition[ch->entnum][2]; + pos[2] = -s_entityPosition[ch->entnum][1]; + } alSourcei(s_channels[source].alSource, AL_SOURCE_RELATIVE, AL_FALSE); } } @@ -3525,6 +3599,9 @@ void S_SoundList_f( void ) { } } } + Com_Printf(" Slot Smpls Type In? Lev Name\n"); + + Com_Printf ("Total resident samples: %i %s ( not mem usage, see 'meminfo' ).\n", total, bWavOnly?"(WAV only)":""); Com_Printf ("%d out of %d sfx_t slots used\n", s_numSfx, MAX_SFX); Com_Printf ("%.2fMB bytes used when counting sfx_t->pSoundData + MP3 headers (if any)\n", (float)iTotalBytes / 1024.0f / 1024.0f); @@ -4144,9 +4221,9 @@ void S_StartBackgroundTrack( const char *intro, const char *loop, qboolean bCall COM_DefaultExtension( sName, sizeof( sName ), ".mp3" ); - // if low physical memory, then just stream the explore music instead of playing dynamic... + // if dynamic music not allowed, then just stream the explore music instead of playing dynamic... // - if (Sys_LowPhysicalMemory() && Music_DynamicDataAvailable(intro)) // "intro", NOT "sName" (i.e. don't use version with ".mp3" extension) + if (!s_allowDynamicMusic->integer && Music_DynamicDataAvailable(intro)) // "intro", NOT "sName" (i.e. don't use version with ".mp3" extension) { LPCSTR psMusicName = Music_GetFileNameForState( eBGRNDTRACK_DATABEGIN ); if (psMusicName && S_FileExists( psMusicName )) @@ -4160,12 +4237,14 @@ void S_StartBackgroundTrack( const char *intro, const char *loop, qboolean bCall if ( (strstr(sName,"/") && S_FileExists( sName )) ) // strstr() check avoids extra file-exists check at runtime if reverting from streamed music to dynamic since literal files all need at least one slash in their name (eg "music/blah") { Com_DPrintf("S_StartBackgroundTrack: Found/using non-dynamic music track '%s'\n", sName); - S_StartBackgroundTrack_Actual( &tMusic_Info[eBGRNDTRACK_NONDYNAMIC], bMusic_IsDynamic, sName, loop ); + S_StartBackgroundTrack_Actual( &tMusic_Info[eBGRNDTRACK_NONDYNAMIC], bMusic_IsDynamic, sName, sName ); } else { if (Music_DynamicDataAvailable(intro)) // "intro", NOT "sName" (i.e. don't use version with ".mp3" extension) { + extern const char *Music_GetLevelSetName(void); + Q_strncpyz(sInfoOnly_CurrentDynamicMusicSet, Music_GetLevelSetName(), sizeof(sInfoOnly_CurrentDynamicMusicSet)); for (int i = eBGRNDTRACK_DATABEGIN; i != eBGRNDTRACK_DATAEND; i++) { qboolean bOk = qfalse; @@ -4252,7 +4331,7 @@ void S_StopBackgroundTrack( void ) // qboolean return is true only if we're changing from a streamed intro to a dynamic loop... // -static qboolean S_UpdateBackgroundTrack_Actual( MusicInfo_t *pMusicInfo, qboolean bFirstOrOnlyMusicTrack) +static qboolean S_UpdateBackgroundTrack_Actual( MusicInfo_t *pMusicInfo, qboolean bFirstOrOnlyMusicTrack, float fDefaultVolume) { int bufferSamples; int fileSamples; @@ -4260,7 +4339,7 @@ static qboolean S_UpdateBackgroundTrack_Actual( MusicInfo_t *pMusicInfo, qboolea int fileBytes; int r; - float fMasterVol = s_musicVolume->value; + float fMasterVol = fDefaultVolume; // s_musicVolume->value; if (bMusic_IsDynamic) { @@ -4297,6 +4376,7 @@ static qboolean S_UpdateBackgroundTrack_Actual( MusicInfo_t *pMusicInfo, qboolea } pMusicInfo->fSmoothedOutVolume = (pMusicInfo->fSmoothedOutVolume + fMasterVol)/2.0f; +// OutputDebugString(va("%f\n",pMusicInfo->fSmoothedOutVolume)); // don't bother playing anything if musicvolume is 0 if ( pMusicInfo->fSmoothedOutVolume <= 0 ) { @@ -4423,6 +4503,21 @@ static qboolean S_UpdateBackgroundTrack_Actual( MusicInfo_t *pMusicInfo, qboolea } +// used to be just for dynamic, but now even non-dynamic music has to know whether it should be silent or not... +// +static LPCSTR S_Music_GetRequestedState(void) +{ + int iStringOffset = cl.gameState.stringOffsets[CS_DYNAMIC_MUSIC_STATE]; + if (iStringOffset) + { + LPCSTR psCommand = cl.gameState.stringData+iStringOffset; + + return psCommand; + } + + return NULL; +} + // scan the configstring to see if there's been a state-change requested... // (note that even if the state doesn't change it still gets here, so do a same-state check for applying) @@ -4431,11 +4526,10 @@ static qboolean S_UpdateBackgroundTrack_Actual( MusicInfo_t *pMusicInfo, qboolea // static void S_CheckDynamicMusicState(void) { - int iStringOffset = cl.gameState.stringOffsets[CS_DYNAMIC_MUSIC_STATE]; - if (iStringOffset) - { - LPCSTR psCommand = cl.gameState.stringData+iStringOffset; + LPCSTR psCommand = S_Music_GetRequestedState(); + if (psCommand) + { MusicState_e eNewState; if ( !Q_stricmpn( psCommand, "silence", 7) ) @@ -4508,7 +4602,7 @@ static void S_UpdateBackgroundTrack( void ) if ( pMusicInfoCurrent->s_backgroundFile == -1) { int iRawEnd = s_rawend; - S_UpdateBackgroundTrack_Actual( pMusicInfoCurrent, qtrue ); + S_UpdateBackgroundTrack_Actual( pMusicInfoCurrent, qtrue, s_musicVolume->value ); /* static int iPrevFrontVol = 0; if (iPrevFrontVol != pMusicInfoCurrent->iXFadeVolume) @@ -4520,7 +4614,7 @@ static void S_UpdateBackgroundTrack( void ) if (pMusicInfoFadeOut->bActive) { s_rawend = iRawEnd; - S_UpdateBackgroundTrack_Actual( pMusicInfoFadeOut, qfalse ); // inactive-checked internally + S_UpdateBackgroundTrack_Actual( pMusicInfoFadeOut, qfalse, s_musicVolume->value ); // inactive-checked internally /* static int iPrevFadeVol = 0; if (iPrevFadeVol != pMusicInfoFadeOut->iXFadeVolume) @@ -4580,7 +4674,7 @@ static void S_UpdateBackgroundTrack( void ) MusicInfo_t *pMusicInfoFadeOut = &tMusic_Info[ eBGRNDTRACK_FADE ]; if (pMusicInfoFadeOut->bActive) { - S_UpdateBackgroundTrack_Actual( pMusicInfoFadeOut, qtrue ); + S_UpdateBackgroundTrack_Actual( pMusicInfoFadeOut, qtrue, s_musicVolume->value ); if (pMusicInfoFadeOut->iXFadeVolume == 0) { pMusicInfoFadeOut->bActive = qfalse; @@ -4592,7 +4686,13 @@ static void S_UpdateBackgroundTrack( void ) { // standard / non-dynamic one-track music... // - qboolean bNewTrackDesired = S_UpdateBackgroundTrack_Actual(&tMusic_Info[eBGRNDTRACK_NONDYNAMIC], qtrue ); + LPCSTR psCommand = S_Music_GetRequestedState(); // special check just for "silence" case... + qboolean bShouldBeSilent = (psCommand && !stricmp(psCommand,"silence")); + float fDesiredVolume = bShouldBeSilent ? 0.0f : s_musicVolume->value; + // + // internal to this code is a volume-smoother... + // + qboolean bNewTrackDesired = S_UpdateBackgroundTrack_Actual(&tMusic_Info[eBGRNDTRACK_NONDYNAMIC], qtrue, fDesiredVolume); if (bNewTrackDesired) { @@ -5093,6 +5193,7 @@ void UpdateEAXBuffer(channel_t *ch) // Convert Source co-ordinate to left-handed system if (ch->fixed_origin) { + // Converting from Quake -> DS3D (for EAGLE) ... swap Y and Z EMSourcePoint.fX = ch->origin[0]; EMSourcePoint.fY = ch->origin[2]; EMSourcePoint.fZ = ch->origin[1]; @@ -5103,17 +5204,27 @@ void UpdateEAXBuffer(channel_t *ch) { // Source at same position as listener // Probably won't be any Occlusion / Obstruction effect -- unless the listener is underwater + // Converting from Open AL -> DS3D (for EAGLE) ... invert Z EMSourcePoint.fX = listener_pos[0]; - EMSourcePoint.fY = listener_pos[2]; - EMSourcePoint.fZ = listener_pos[1]; + EMSourcePoint.fY = listener_pos[1]; + EMSourcePoint.fZ = -listener_pos[2]; } else { // Get position of Entity - EMSourcePoint.fX = loopSounds[ ch->entnum ].origin[0]; - EMSourcePoint.fY = loopSounds[ ch->entnum ].origin[2]; - EMSourcePoint.fZ = loopSounds[ ch->entnum ].origin[1]; - + // Converting from Quake -> DS3D (for EAGLE) ... swap Y and Z + if (ch->bLooping) + { + EMSourcePoint.fX = loopSounds[ ch->entnum ].origin[0]; + EMSourcePoint.fY = loopSounds[ ch->entnum ].origin[2]; + EMSourcePoint.fZ = loopSounds[ ch->entnum ].origin[1]; + } + else + { + EMSourcePoint.fX = s_entityPosition[ch->entnum][0]; + EMSourcePoint.fY = s_entityPosition[ch->entnum][2]; + EMSourcePoint.fZ = s_entityPosition[ch->entnum][1]; + } } } diff --git a/code/client/snd_local.h b/code/client/snd_local.h index bab7ee3..ce3180e 100644 --- a/code/client/snd_local.h +++ b/code/client/snd_local.h @@ -186,6 +186,7 @@ extern cvar_t *s_volume; extern cvar_t *s_volumeVoice; extern cvar_t *s_nosound; extern cvar_t *s_khz; +extern cvar_t *s_allowDynamicMusic; extern cvar_t *s_show; extern cvar_t *s_mixahead; diff --git a/code/client/snd_mem.cpp b/code/client/snd_mem.cpp index b6eba57..ab61fae 100644 --- a/code/client/snd_mem.cpp +++ b/code/client/snd_mem.cpp @@ -580,7 +580,7 @@ static qboolean S_LoadSound_FileLoadAndNameAdjuster(char *psFilename, byte **pDa { FS_FCloseFile(hFile); } - strcpy(&psFilename[iNameStrlen-3],"wav"); + strcpy(&psFilename[iNameStrlen-3],"wav"); //put it back to wav strncpy(psVoice,"chr_f",5); // same number of letters as "chars" FS_FOpenFileRead(psFilename, &hFile, qfalse); //cahce this file @@ -594,6 +594,7 @@ static qboolean S_LoadSound_FileLoadAndNameAdjuster(char *psFilename, byte **pDa FS_FCloseFile(hFile); } strncpy(psVoice,"chars",5); //put it back to chars + strcpy(&psFilename[iNameStrlen-3],"wav"); //put it back to wav } // account for foreign voices... @@ -630,6 +631,45 @@ static qboolean S_LoadSound_FileLoadAndNameAdjuster(char *psFilename, byte **pDa { // yep, so fallback to re-try the english... // + + + // this doesn't work that well, there are just FAR too many exception (probetalk, gonktalk, headjump etc) + // that this fails to do english fallback on. If I put the check the other way round, then the list of + // what's not acceptable is also pretty long. Just forget it I guess... + // +#if 0 +/* + if (0) // set to 0 to be disabled + { + // NEW BIT!!! We can sort of make this work by only allowing vocal fallback to certain noises, + // this stops foreigners whining that their languages aren't fully localised... + // + const char *psBasePart = strrchr(psFilename,'/'); + psBasePart = psBasePart ? psBasePart+1 : psFilename; // probably irrelevant here, but good practice + + // quicker to say what's allowed than what's forbidden (based on quick dir check)... + // + if (! + ( + !strnicmp(psBasePart,"choke",5) || + !strnicmp(psBasePart,"death",5) || + !strnicmp(psBasePart,"drown",5) || + !strnicmp(psBasePart,"falling",7) || + !strnicmp(psBasePart,"gasp",4) || + !strnicmp(psBasePart,"gurp",4) || + !strnicmp(psBasePart,"jump",4) || + !strnicmp(psBasePart,"land",4) || + !strnicmp(psBasePart,"pain",4) || + !strnicmp(psBasePart,"pushed",5) + ) + ) + { + return qfalse; + } + } +*/ +#endif + #ifndef FINAL_BUILD Com_Printf(S_COLOR_YELLOW "Foreign file missing: \"%s\"! (using English...)\n",psFilename); #endif diff --git a/code/client/snd_music.cpp b/code/client/snd_music.cpp index dddd1e3..d7e061e 100644 --- a/code/client/snd_music.cpp +++ b/code/client/snd_music.cpp @@ -763,22 +763,6 @@ qboolean Music_DynamicDataAvailable(const char *psDynamicMusicLabel) Music_GetBaseMusicFile( eBGRNDTRACK_ACTION ) ); } - else - { - /* - // ALPHACODE only!!!!!!!!!!!!!, fall back to "kejim_base" music... - // fixme - // findmeste - // - // Com_DPrintf("Falling back to \"kejim_base\" music\n"); - if (Music_ParseLeveldata("kejim_base")) - { - return !!( Music_GetBaseMusicFile( eBGRNDTRACK_EXPLORE ) && - Music_GetBaseMusicFile( eBGRNDTRACK_ACTION ) - ); - } - */ - } } return qfalse; @@ -1108,6 +1092,19 @@ float Music_GetRandomEntryTime( MusicState_e eMusicState ) return 0.0f; } +// info only, used in "soundinfo" command... +// +const char *Music_GetLevelSetName(void) +{ + if (Q_stricmp(gsLevelNameForCompare.c_str(), gsLevelNameForLoad.c_str())) + { + // music remap via USES command... + // + return va("%s -> %s",gsLevelNameForCompare.c_str(), gsLevelNameForLoad.c_str()); + } + + return gsLevelNameForLoad.c_str(); +} ///////////////// eof ///////////////////// diff --git a/code/client/vssver.scc b/code/client/vssver.scc new file mode 100644 index 0000000..dfe76ed Binary files /dev/null and b/code/client/vssver.scc differ diff --git a/code/eaxman.dll b/code/eaxman.dll new file mode 100644 index 0000000..0a41c53 Binary files /dev/null and b/code/eaxman.dll differ diff --git a/code/encryption/vssver.scc b/code/encryption/vssver.scc new file mode 100644 index 0000000..6d3de2c Binary files /dev/null and b/code/encryption/vssver.scc differ diff --git a/code/ffc10.dll b/code/ffc10.dll new file mode 100644 index 0000000..0536f23 Binary files /dev/null and b/code/ffc10.dll differ diff --git a/code/ffc10d.dll b/code/ffc10d.dll new file mode 100644 index 0000000..1f546c2 Binary files /dev/null and b/code/ffc10d.dll differ diff --git a/code/game/AI_Atst.cpp b/code/game/AI_Atst.cpp index 8bcb4bf..467f721 100644 --- a/code/game/AI_Atst.cpp +++ b/code/game/AI_Atst.cpp @@ -16,6 +16,7 @@ #define LEFT_ARM_HEALTH 40 #define RIGHT_ARM_HEALTH 40 +extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); /* ------------------------- NPC_ATST_Precache @@ -23,15 +24,39 @@ NPC_ATST_Precache */ void NPC_ATST_Precache(void) { + G_SoundIndex( "sound/chars/atst/atst_damaged1" ); + G_SoundIndex( "sound/chars/atst/atst_damaged2" ); + RegisterItem( FindItemForWeapon( WP_ATST_MAIN )); //precache the weapon RegisterItem( FindItemForWeapon( WP_BOWCASTER )); //precache the weapon RegisterItem( FindItemForWeapon( WP_ROCKET_LAUNCHER )); //precache the weapon - G_EffectIndex( "mouseexplosion1" ); - G_EffectIndex( "smaller_chunks" ); + G_EffectIndex( "env/med_explode2" ); +// G_EffectIndex( "smaller_chunks" ); G_EffectIndex( "blaster/smoke_bolton" ); G_EffectIndex( "droidexplosion1" ); } + +//----------------------------------------------------------------- +static void ATST_PlayEffect( gentity_t *self, const int boltID, const char *fx ) +{ + if ( boltID >=0 && fx && fx[0] ) + { + mdxaBone_t boltMatrix; + vec3_t org, dir; + + gi.G2API_GetBoltMatrix( self->ghoul2, self->playerModel, + boltID, + &boltMatrix, self->currentAngles, self->currentOrigin, (cg.time?cg.time:level.time), + NULL, self->s.modelScale ); + + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org ); + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, dir ); + + G_PlayEffect( fx, org, dir ); + } +} + /* ------------------------- G_ATSTCheckPain @@ -44,6 +69,15 @@ void G_ATSTCheckPain( gentity_t *self, gentity_t *other, vec3_t point, int damag { int newBolt; + if ( rand() & 1 ) + { + G_SoundOnEnt( self, CHAN_LESS_ATTEN, "sound/chars/atst/atst_damaged1" ); + } + else + { + G_SoundOnEnt( self, CHAN_LESS_ATTEN, "sound/chars/atst/atst_damaged2" ); + } + if ((hitLoc==HL_ARM_LT) && (self->locationDamage[HL_ARM_LT] > LEFT_ARM_HEALTH)) { if (self->locationDamage[hitLoc] >= LEFT_ARM_HEALTH) // Blow it up? @@ -51,8 +85,8 @@ void G_ATSTCheckPain( gentity_t *self, gentity_t *other, vec3_t point, int damag newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*flash3" ); if ( newBolt != -1 ) { - G_PlayEffect( "small_chunks", self->playerModel, self->genericBolt1, self->s.number); - G_PlayEffect( "mouseexplosion1", self->playerModel, self->genericBolt1, self->s.number); +// G_PlayEffect( "small_chunks", self->playerModel, self->genericBolt1, self->s.number); + ATST_PlayEffect( self, self->genericBolt1, "env/med_explode2" ); G_PlayEffect( "blaster/smoke_bolton", self->playerModel, newBolt, self->s.number); } @@ -66,8 +100,8 @@ void G_ATSTCheckPain( gentity_t *self, gentity_t *other, vec3_t point, int damag newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*flash4" ); if ( newBolt != -1 ) { - G_PlayEffect( "small_chunks", self->playerModel, self->genericBolt2, self->s.number); - G_PlayEffect( "mouseexplosion1", self->playerModel, self->genericBolt2, self->s.number); +// G_PlayEffect( "small_chunks", self->playerModel, self->genericBolt2, self->s.number); + ATST_PlayEffect( self, self->genericBolt2, "env/med_explode2" ); G_PlayEffect( "blaster/smoke_bolton", self->playerModel, newBolt, self->s.number); } @@ -113,7 +147,7 @@ ATST_Ranged void ATST_Ranged( qboolean visible, qboolean advance, qboolean altAttack ) { - if ( TIMER_Done( NPC, "atkDelay" ) ) // Attack? + if ( TIMER_Done( NPC, "atkDelay" ) && visible ) // Attack? { TIMER_Set( NPC, "atkDelay", Q_irand( 500, 3000 ) ); @@ -149,6 +183,8 @@ void ATST_Attack( void ) return; } + NPC_FaceEnemy( qtrue ); + // Rate our distance to the target, and our visibilty float distance = (int) DistanceHorizontalSquared( NPC->currentOrigin, NPC->enemy->currentOrigin ); distance_e distRate = ( distance > MIN_MELEE_RANGE_SQR ) ? DIST_LONG : DIST_MELEE; diff --git a/code/game/AI_Default.cpp b/code/game/AI_Default.cpp index b5a0fca..c5d3151 100644 --- a/code/game/AI_Default.cpp +++ b/code/game/AI_Default.cpp @@ -742,7 +742,7 @@ void NPC_BSDefault( void ) if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) ) {//check for alert events //FIXME: Check Alert events, see if we should investigate or just look at it - int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, AEL_DISCOVERED ); + int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qtrue, AEL_DISCOVERED ); //There is an event to look at if ( alertEvent >= 0 && level.alertEvents[alertEvent].ID != NPCInfo->lastAlertID ) @@ -766,7 +766,13 @@ void NPC_BSDefault( void ) { // just use the stormtrooper attack AI... NPC_CheckGetNewWeapon(); - NPC_BSST_Attack(); + if ( NPC->client->leader + && NPCInfo->goalEntity == NPC->client->leader + && !Q3_TaskIDPending( NPC, TID_MOVE_NAV ) ) + { + NPC_ClearGoal(); + } + NPC_BSST_Attack(); return; /* //have an enemy @@ -874,58 +880,68 @@ void NPC_BSDefault( void ) if ( UpdateGoal() ) {//have a goal - //set angles - if ( (NPCInfo->scriptFlags & SCF_FACE_MOVE_DIR) || NPCInfo->goalEntity != NPC->enemy ) - {//face direction of movement, NOTE: default behavior when not chasing enemy - NPCInfo->combatMove = qfalse; + if ( !NPC->enemy + && NPC->client->leader + && NPCInfo->goalEntity == NPC->client->leader + && !Q3_TaskIDPending( NPC, TID_MOVE_NAV ) ) + { + NPC_BSFollowLeader(); } else - {//face goal.. FIXME: what if have a navgoal but want to face enemy while moving? Will this do that? - vec3_t dir, angles; + { + //set angles + if ( (NPCInfo->scriptFlags & SCF_FACE_MOVE_DIR) || NPCInfo->goalEntity != NPC->enemy ) + {//face direction of movement, NOTE: default behavior when not chasing enemy + NPCInfo->combatMove = qfalse; + } + else + {//face goal.. FIXME: what if have a navgoal but want to face enemy while moving? Will this do that? + vec3_t dir, angles; - NPCInfo->combatMove = qfalse; + NPCInfo->combatMove = qfalse; - VectorSubtract( NPCInfo->goalEntity->currentOrigin, NPC->currentOrigin, dir ); - vectoangles( dir, angles ); - NPCInfo->desiredYaw = angles[YAW]; - if ( NPCInfo->goalEntity == NPC->enemy ) + VectorSubtract( NPCInfo->goalEntity->currentOrigin, NPC->currentOrigin, dir ); + vectoangles( dir, angles ); + NPCInfo->desiredYaw = angles[YAW]; + if ( NPCInfo->goalEntity == NPC->enemy ) + { + NPCInfo->desiredPitch = angles[PITCH]; + } + } + + //set movement + //override default walk/run behavior + //NOTE: redundant, done in NPC_ApplyScriptFlags + if ( NPCInfo->scriptFlags & SCF_RUNNING ) { - NPCInfo->desiredPitch = angles[PITCH]; + ucmd.buttons &= ~BUTTON_WALKING; } - } - - //set movement - //override default walk/run behavior - //NOTE: redundant, done in NPC_ApplyScriptFlags - if ( NPCInfo->scriptFlags & SCF_RUNNING ) - { - ucmd.buttons &= ~BUTTON_WALKING; - } - else if ( NPCInfo->scriptFlags & SCF_WALKING ) - { - ucmd.buttons |= BUTTON_WALKING; - } - else if ( NPCInfo->goalEntity == NPC->enemy ) - { - ucmd.buttons &= ~BUTTON_WALKING; - } - else - { - ucmd.buttons |= BUTTON_WALKING; - } - - if ( NPCInfo->scriptFlags & SCF_FORCED_MARCH ) - {//being forced to walk - if ( g_crosshairEntNum != NPC->s.number ) - {//don't walk if player isn't aiming at me - move = qfalse; + else if ( NPCInfo->scriptFlags & SCF_WALKING ) + { + ucmd.buttons |= BUTTON_WALKING; + } + else if ( NPCInfo->goalEntity == NPC->enemy ) + { + ucmd.buttons &= ~BUTTON_WALKING; + } + else + { + ucmd.buttons |= BUTTON_WALKING; } - } - if ( move ) - { - //move toward goal - NPC_MoveToGoal( qtrue ); + if ( NPCInfo->scriptFlags & SCF_FORCED_MARCH ) + {//being forced to walk + if ( g_crosshairEntNum != NPC->s.number ) + {//don't walk if player isn't aiming at me + move = qfalse; + } + } + + if ( move ) + { + //move toward goal + NPC_MoveToGoal( qtrue ); + } } } else if ( !NPC->enemy && NPC->client->leader ) diff --git a/code/game/AI_Droid.cpp b/code/game/AI_Droid.cpp index 3dea7d9..7c9bb7d 100644 --- a/code/game/AI_Droid.cpp +++ b/code/game/AI_Droid.cpp @@ -6,6 +6,7 @@ //static void R5D2_LookAround( void ); float NPC_GetPainChance( gentity_t *self, int damage ); +extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); #define TURN_OFF 0x00000100 @@ -102,9 +103,11 @@ void Droid_Patrol( void ) NPC->pos1[1] = AngleNormalize360( NPC->pos1[1]); - R2D2_PartsMove(); // Get his eye moving. - - R2D2_TurnAnims(); + if ( NPC->client && NPC->client->NPC_class != CLASS_GONK ) + { + R2D2_PartsMove(); // Get his eye moving. + R2D2_TurnAnims(); + } //If we have somewhere to go, then do that if ( UpdateGoal() ) @@ -118,7 +121,7 @@ void Droid_Patrol( void ) if (TIMER_Done(NPC,"patrolNoise")) { - G_Sound(NPC, G_SoundIndex(va("sound/chars/mouse/misc/mousego%d.wav", Q_irand(1, 3)))); + G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/mouse/misc/mousego%d.wav", Q_irand(1, 3)) ); TIMER_Set( NPC, "patrolNoise", Q_irand( 2000, 4000 ) ); } @@ -127,7 +130,7 @@ void Droid_Patrol( void ) { if (TIMER_Done(NPC,"patrolNoise")) { - G_Sound(NPC, G_SoundIndex(va("sound/chars/r2d2/misc/r2d2talk0%d.wav", Q_irand(1, 3)))); + G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/r2d2/misc/r2d2talk0%d.wav", Q_irand(1, 3)) ); TIMER_Set( NPC, "patrolNoise", Q_irand( 2000, 4000 ) ); } @@ -136,7 +139,7 @@ void Droid_Patrol( void ) { if (TIMER_Done(NPC,"patrolNoise")) { - G_Sound(NPC, G_SoundIndex(va("sound/chars/r5d2/misc/r5talk%d.wav", Q_irand(1, 4)))); + G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/r5d2/misc/r5talk%d.wav", Q_irand(1, 4)) ); TIMER_Set( NPC, "patrolNoise", Q_irand( 2000, 4000 ) ); } @@ -145,7 +148,7 @@ void Droid_Patrol( void ) { if (TIMER_Done(NPC,"patrolNoise")) { - G_Sound(NPC, G_SoundIndex(va("sound/chars/gonk/misc/gonktalk%d.wav", Q_irand(1, 2)))); + G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/gonk/misc/gonktalk%d.wav", Q_irand(1, 2)) ); TIMER_Set( NPC, "patrolNoise", Q_irand( 2000, 4000 ) ); } @@ -403,6 +406,8 @@ void NPC_Mouse_Precache( void ) } G_EffectIndex( "env/small_explode" ); + G_SoundIndex( "sound/chars/mouse/misc/death1" ); + G_SoundIndex( "sound/chars/mouse/misc/mouse_lp" ); } /* @@ -416,12 +421,11 @@ void NPC_R5D2_Precache(void) { G_SoundIndex( va( "sound/chars/r5d2/misc/r5talk%d.wav", i ) ); } + G_SoundIndex( "sound/chars/mark2/misc/mark2_explo" ); // ?? G_SoundIndex( "sound/chars/r2d2/misc/r2_move_lp2.wav" ); - G_EffectIndex( "r5_droidexplosion"); + G_EffectIndex( "env/med_explode"); G_EffectIndex( "droid_smoke" ); -// G_EffectIndex( "small_chunks"); G_EffectIndex( "r5d2head"); -// G_EffectIndex( "r5d2headland"); } /* @@ -435,9 +439,9 @@ void NPC_R2D2_Precache(void) { G_SoundIndex( va( "sound/chars/r2d2/misc/r2d2talk0%d.wav", i ) ); } + G_SoundIndex( "sound/chars/mark2/misc/mark2_explo" ); // ?? G_SoundIndex( "sound/chars/r2d2/misc/r2_move_lp.wav" ); - G_EffectIndex( "r2_droidexplosion"); -// G_EffectIndex( "small_chunks"); + G_EffectIndex( "env/med_explode"); } /* @@ -454,6 +458,18 @@ void NPC_Gonk_Precache( void ) G_SoundIndex("sound/chars/gonk/misc/death2.wav"); G_SoundIndex("sound/chars/gonk/misc/death3.wav"); + G_EffectIndex( "env/med_explode"); +} + +/* +------------------------- +NPC_Protocol_Precache +------------------------- +*/ +void NPC_Protocol_Precache( void ) +{ + G_SoundIndex( "sound/chars/mark2/misc/mark2_explo" ); + G_EffectIndex( "env/med_explode"); } /* diff --git a/code/game/AI_GalakMech.cpp b/code/game/AI_GalakMech.cpp index 227eff8..2ffe827 100644 --- a/code/game/AI_GalakMech.cpp +++ b/code/game/AI_GalakMech.cpp @@ -7,6 +7,7 @@ #include "anims.h" #include "wp_saber.h" +extern qboolean G_StandardHumanoid( const char *modelName ); extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType ); extern void NPC_AimAdjust( int change ); @@ -17,6 +18,7 @@ extern qboolean InFront( vec3_t spot, vec3_t from, vec3_t fromAngles, float thre extern void G_SoundAtSpot( vec3_t org, int soundIndex ); extern void G_SoundOnEnt (gentity_t *ent, soundChannel_t channel, const char *soundPath); extern qboolean PM_CrouchAnim( int anim ); +//extern void NPC_Mark1_Part_Explode(gentity_t *self,int bolt); #define MELEE_DIST_SQUARED 6400//80*80 #define MIN_LOB_DIST_SQUARED 65536//256*256 @@ -46,16 +48,16 @@ void NPC_GalakMech_Precache( void ) G_SoundIndex( "sound/weapons/galak/skewerhit.wav" ); G_SoundIndex( "sound/weapons/galak/lasercharge.wav" ); G_SoundIndex( "sound/weapons/galak/lasercutting.wav" ); - G_SoundIndex( "sound/weapons/galak/lasercutting.wav" ); - G_SoundIndex( "sound/weapons/galak/laserdamage.wav" ); G_SoundIndex( "sound/weapons/galak/laserdamage.wav" ); + G_EffectIndex( "galak/trace_beam" ); G_EffectIndex( "galak/beam_warmup" ); - G_EffectIndex( "small_chunks"); - G_EffectIndex( "mouseexplosion1"); - G_EffectIndex( "probeexplosion1"); +// G_EffectIndex( "small_chunks"); + G_EffectIndex( "env/med_explode2"); + G_EffectIndex( "env/small_explode2"); + G_EffectIndex( "galak/explode"); G_EffectIndex( "blaster/smoke_bolton"); - G_EffectIndex( "env/exp_trail_comp"); +// G_EffectIndex( "env/exp_trail_comp"); } void NPC_GalakMech_Init( gentity_t *ent ) @@ -76,6 +78,13 @@ void NPC_GalakMech_Init( gentity_t *ent ) TIMER_Set( ent, "beamDelay", 0 ); TIMER_Set( ent, "noLob", 0 ); TIMER_Set( ent, "noRapid", 0 ); + TIMER_Set( ent, "talkDebounce", 0 ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_shield_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_galakface_off", TURN_OFF ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_galakhead_off", TURN_OFF ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_eyes_mouth_off", TURN_OFF ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_collar_off", TURN_OFF ); + gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "torso_galaktorso_off", TURN_OFF ); } else { @@ -90,17 +99,45 @@ void NPC_GalakMech_Init( gentity_t *ent ) } +//----------------------------------------------------------------- +static void GM_CreateExplosion( gentity_t *self, const int boltID, qboolean doSmall = qfalse ) +{ + if ( boltID >=0 ) + { + mdxaBone_t boltMatrix; + vec3_t org, dir; + + gi.G2API_GetBoltMatrix( self->ghoul2, self->playerModel, + boltID, + &boltMatrix, self->currentAngles, self->currentOrigin, (cg.time?cg.time:level.time), + NULL, self->s.modelScale ); + + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org ); + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, dir ); + + if ( doSmall ) + { + G_PlayEffect( "env/small_explode2", org, dir ); + } + else + { + G_PlayEffect( "env/med_explode2", org, dir ); + } + } +} /* ------------------------- GM_Dying ------------------------- */ -extern void NPC_Mark1_Part_Explode(gentity_t *self,int bolt); + void GM_Dying( gentity_t *self ) { - if ( level.time - self->s.time < 10000 ) + if ( level.time - self->s.time < 4000 ) {//FIXME: need a real effect + self->s.powerups |= ( 1 << PW_SHOCKED ); + self->client->ps.powerups[PW_SHOCKED] = level.time + 1000; if ( TIMER_Done( self, "dyingExplosion" ) ) { int newBolt; @@ -110,7 +147,7 @@ void GM_Dying( gentity_t *self ) case 1: if (!gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "r_hand" )) {//r_hand still there - NPC_Mark1_Part_Explode( self, self->handRBolt ); + GM_CreateExplosion( self, self->handRBolt, qtrue ); gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "r_hand", TURN_OFF ); } else if (!gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "r_arm_middle" )) @@ -123,7 +160,7 @@ void GM_Dying( gentity_t *self ) //FIXME: do only once? if (!gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "l_hand" )) {//l_hand still there - NPC_Mark1_Part_Explode( self, self->handLBolt ); + GM_CreateExplosion( self, self->handLBolt ); gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "l_hand", TURN_OFF ); } else if (!gi.G2API_GetSurfaceRenderStatus( &self->ghoul2[self->playerModel], "l_arm_wrist" )) @@ -145,48 +182,48 @@ void GM_Dying( gentity_t *self ) case 3: case 4: newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*hip_fr" ); - NPC_Mark1_Part_Explode( self, newBolt ); + GM_CreateExplosion( self, newBolt ); break; case 5: case 6: newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*shldr_l" ); - NPC_Mark1_Part_Explode( self, newBolt ); + GM_CreateExplosion( self, newBolt ); break; case 7: case 8: newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*uchest_r" ); - NPC_Mark1_Part_Explode( self, newBolt ); + GM_CreateExplosion( self, newBolt ); break; case 9: case 10: - NPC_Mark1_Part_Explode( self, self->headBolt ); + GM_CreateExplosion( self, self->headBolt ); break; case 11: newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*l_leg_knee" ); - NPC_Mark1_Part_Explode( self, newBolt ); + GM_CreateExplosion( self, newBolt, qtrue ); break; case 12: newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*r_leg_knee" ); - NPC_Mark1_Part_Explode( self, newBolt ); + GM_CreateExplosion( self, newBolt, qtrue ); break; case 13: newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*l_leg_foot" ); - NPC_Mark1_Part_Explode( self, newBolt ); + GM_CreateExplosion( self, newBolt, qtrue ); break; case 14: newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*r_leg_foot" ); - NPC_Mark1_Part_Explode( self, newBolt ); + GM_CreateExplosion( self, newBolt, qtrue ); break; } - TIMER_Set( self, "dyingExplosion", Q_irand( 100, 600 ) ); + TIMER_Set( self, "dyingExplosion", Q_irand( 300, 1100 ) ); } } else {//one final, huge explosion - G_PlayEffect( "probeexplosion1", self->currentOrigin ); - G_PlayEffect( "small_chunks", self->currentOrigin ); - G_PlayEffect( "env/exp_trail_comp", self->currentOrigin, self->currentAngles ); + G_PlayEffect( "galak/explode", self->currentOrigin ); +// G_PlayEffect( "small_chunks", self->currentOrigin ); +// G_PlayEffect( "env/exp_trail_comp", self->currentOrigin, self->currentAngles ); self->nextthink = level.time + FRAMETIME; self->e_ThinkFunc = thinkF_G_FreeEntity; } @@ -198,6 +235,7 @@ NPC_GM_Pain ------------------------- */ +extern void NPC_SetPainEvent( gentity_t *self ); void NPC_GM_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, vec3_t point, int damage, int mod,int hitLoc ) { if ( self->client->ps.powerups[PW_GALAK_SHIELD] == 0 ) @@ -208,7 +246,7 @@ void NPC_GM_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, ve int newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*antenna_base" ); if ( newBolt != -1 ) { - NPC_Mark1_Part_Explode(self,newBolt); + GM_CreateExplosion( self, newBolt ); } gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "torso_shield_off", TURN_OFF ); @@ -220,6 +258,7 @@ void NPC_GM_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, ve NPC_SetAnim( self, SETANIM_BOTH, BOTH_ALERT1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); TIMER_Set( self, "attackDelay", self->client->ps.torsoAnimTimer ); + G_AddEvent( self, Q_irand( EV_DEATH1, EV_DEATH3 ), self->health ); } } else @@ -233,7 +272,43 @@ void NPC_GM_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, ve if ( !self->lockCount && !self->client->ps.torsoAnimTimer ) {//don't interrupt laser sweep attack or other special attacks/moves - NPC_Pain( self, inflictor, attacker, point, damage, mod, hitLoc ); + if ( self->count < 4 && self->health > 100 && hitLoc != HL_GENERIC1 ) + { + if ( self->delay < level.time ) + { + int speech; + switch( self->count ) + { + default: + case 0: + speech = EV_PUSHED1; + break; + case 1: + speech = EV_PUSHED2; + break; + case 2: + speech = EV_PUSHED3; + break; + case 3: + speech = EV_DETECTED1; + break; + } + self->count++; + self->NPC->blockedSpeechDebounceTime = 0; + G_AddVoiceEvent( self, speech, Q_irand( 3000, 5000 ) ); + self->delay = level.time + Q_irand( 5000, 7000 ); + } + } + else + { + NPC_Pain( self, inflictor, attacker, point, damage, mod, hitLoc ); + } + } + else if ( hitLoc == HL_GENERIC1 ) + { + NPC_SetPainEvent( self ); + self->s.powerups |= ( 1 << PW_SHOCKED ); + self->client->ps.powerups[PW_SHOCKED] = level.time + Q_irand( 500, 2500 ); } if ( inflictor && inflictor->lastEnemy == self ) @@ -470,7 +545,7 @@ void NPC_GM_StartLaser( void ) if ( !NPC->lockCount ) {//haven't already started a laser attack //warm up for the beam attack - NPC_SetAnim( NPC, SETANIM_BOTH, TORSO_RAISEWEAP2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC_SetAnim( NPC, SETANIM_TORSO, TORSO_RAISEWEAP2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); TIMER_Set( NPC, "beamDelay", NPC->client->ps.torsoAnimTimer ); TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer+3000 ); NPC->lockCount = 1; @@ -480,6 +555,18 @@ void NPC_GM_StartLaser( void ) } } +void GM_StartGloat( void ) +{ + NPC->wait = 0; + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_galakface_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_galakhead_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_eyes_mouth_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_collar_off", TURN_ON ); + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_galaktorso_off", TURN_ON ); + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_STAND2TO1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC->client->ps.legsAnimTimer += 500; + NPC->client->ps.torsoAnimTimer += 500; +} /* ------------------------- NPC_BSGM_Attack @@ -496,6 +583,66 @@ void NPC_BSGM_Attack( void ) } //FIXME: if killed enemy, use victory anim + if ( NPC->enemy && NPC->enemy->health <= 0 + && !NPC->enemy->s.number ) + {//my enemy is dead + if ( NPC->client->ps.torsoAnim == BOTH_STAND2TO1 ) + { + if ( NPC->client->ps.torsoAnimTimer <= 500 ) + { + G_AddVoiceEvent( NPC, Q_irand( EV_VICTORY1, EV_VICTORY3 ), 3000 ); + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TRIUMPHANT1START, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC->client->ps.legsAnimTimer += 500; + NPC->client->ps.torsoAnimTimer += 500; + } + } + else if ( NPC->client->ps.torsoAnim == BOTH_TRIUMPHANT1START ) + { + if ( NPC->client->ps.torsoAnimTimer <= 500 ) + { + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TRIUMPHANT1STARTGESTURE, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC->client->ps.legsAnimTimer += 500; + NPC->client->ps.torsoAnimTimer += 500; + } + } + else if ( NPC->client->ps.torsoAnim == BOTH_TRIUMPHANT1STARTGESTURE ) + { + if ( NPC->client->ps.torsoAnimTimer <= 500 ) + { + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_TRIUMPHANT1STOP, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC->client->ps.legsAnimTimer += 500; + NPC->client->ps.torsoAnimTimer += 500; + } + } + else if ( NPC->client->ps.torsoAnim == BOTH_TRIUMPHANT1STOP ) + { + if ( NPC->client->ps.torsoAnimTimer <= 500 ) + { + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_STAND1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC->client->ps.legsAnimTimer = -1; + NPC->client->ps.torsoAnimTimer = -1; + } + } + else if ( NPC->wait ) + { + if ( TIMER_Done( NPC, "gloatTime" ) ) + { + GM_StartGloat(); + } + else if ( DistanceHorizontalSquared( NPC->client->renderInfo.eyePoint, NPC->enemy->currentOrigin ) > 4096 && (NPCInfo->scriptFlags&SCF_CHASE_ENEMIES) )//64 squared + { + NPCInfo->goalEntity = NPC->enemy; + GM_Move(); + } + else + {//got there + GM_StartGloat(); + } + } + NPC_FaceEnemy( qtrue ); + NPC_UpdateAngles( qtrue, qtrue ); + return; + } //If we don't have an enemy, just idle if ( NPC_CheckEnemyExt() == qfalse || !NPC->enemy ) { @@ -516,7 +663,7 @@ void NPC_BSGM_Attack( void ) NPC->client->ps.torsoAnim == BOTH_ATTACK5 ) { shoot = qfalse; - if ( TIMER_Done( NPC, "smackTime" ) && !NPCInfo->greetingDebounceTime ) + if ( TIMER_Done( NPC, "smackTime" ) && !NPCInfo->blockedDebounceTime ) {//time to smack //recheck enemyDist and InFront if ( enemyDist < MELEE_DIST_SQUARED && InFront( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 0.3f ) ) @@ -549,7 +696,7 @@ void NPC_BSGM_Attack( void ) NPC_SetAnim( NPC->enemy, SETANIM_BOTH, BOTH_KNOCKDOWN5, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); } //done with the damage - NPCInfo->greetingDebounceTime = 1; + NPCInfo->blockedDebounceTime = 1; } } } @@ -594,7 +741,7 @@ void NPC_BSGM_Attack( void ) NPC->lockCount = 0; G_FreeEntity( NPCInfo->coverTarg ); NPC->s.loopSound = 0; - NPC_SetAnim( NPC, SETANIM_BOTH, TORSO_DROPWEAP2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC_SetAnim( NPC, SETANIM_TORSO, TORSO_DROPWEAP2, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer ); } else @@ -652,7 +799,10 @@ void NPC_BSGM_Attack( void ) } } else*/ - if ( !NPC->client->ps.powerups[PW_GALAK_SHIELD] && enemyDist < MELEE_DIST_SQUARED && InFront( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 0.3f ) )//within 80 and in front + if ( !NPC->client->ps.powerups[PW_GALAK_SHIELD] + && enemyDist < MELEE_DIST_SQUARED + && InFront( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 0.3f ) + && G_StandardHumanoid( NPC->enemy->NPC_type ) )//within 80 and in front {//our shield is down, and enemy within 80, if very close, use melee attack to slap away if ( TIMER_Done( NPC, "attackDelay" ) ) { @@ -671,7 +821,7 @@ void NPC_BSGM_Attack( void ) TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer + Q_irand( 1000, 3000 ) ); //delay the hurt until the proper point in the anim TIMER_Set( NPC, "smackTime", 600 ); - NPCInfo->greetingDebounceTime = 0; + NPCInfo->blockedDebounceTime = 0; //FIXME: say something? } } @@ -679,12 +829,15 @@ void NPC_BSGM_Attack( void ) && TIMER_Done( NPC, "attackDelay" ) && InFront( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 0.3f ) && ((!Q_irand( 0, 10*(2-g_spskill->integer))&& enemyDist > MIN_LOB_DIST_SQUARED&& enemyDist < MAX_LOB_DIST_SQUARED) - ||(!TIMER_Done( NPC, "noLob" )&&!TIMER_Done( NPC, "noRapid" ))) ) + ||(!TIMER_Done( NPC, "noLob" )&&!TIMER_Done( NPC, "noRapid" ))) + && NPC->enemy->s.weapon != WP_TURRET ) {//sometimes use the laser beam attack, but only after he's taken down our generator shoot = qfalse; NPC_GM_StartLaser(); } - else if ( enemyDist < MIN_LOB_DIST_SQUARED && TIMER_Done( NPC, "noRapid" ) )//256 + else if ( enemyDist < MIN_LOB_DIST_SQUARED + && (NPC->enemy->s.weapon != WP_TURRET || Q_stricmp( "PAS", NPC->enemy->classname )) + && TIMER_Done( NPC, "noRapid" ) )//256 {//enemy within 256 if ( (NPC->client->ps.weapon == WP_REPEATER) && (NPCInfo->scriptFlags & SCF_ALT_FIRE) ) {//shooting an explosive, but enemy too close, switch to primary fire @@ -694,7 +847,8 @@ void NPC_BSGM_Attack( void ) NPC_ChangeWeapon( WP_REPEATER ); } } - else if ( enemyDist > MAX_LOB_DIST_SQUARED && TIMER_Done( NPC, "noLob" ) )//448 + else if ( (enemyDist > MAX_LOB_DIST_SQUARED || (NPC->enemy->s.weapon == WP_TURRET && !Q_stricmp( "PAS", NPC->enemy->classname ))) + && TIMER_Done( NPC, "noLob" ) )//448 {//enemy more than 448 away and we are ready to try lob fire again if ( (NPC->client->ps.weapon == WP_REPEATER) && !(NPCInfo->scriptFlags & SCF_ALT_FIRE) ) {//enemy far enough away to use lobby explosives @@ -709,7 +863,7 @@ void NPC_BSGM_Attack( void ) //can we see our target? if ( NPC_ClearLOS( NPC->enemy ) ) { - NPCInfo->enemyLastSeenTime = level.time; + NPCInfo->enemyLastSeenTime = level.time;//used here for aim debouncing, not always a clear LOS enemyLOS = qtrue; if ( NPC->client->ps.weapon == WP_NONE ) @@ -753,6 +907,39 @@ void NPC_BSGM_Attack( void ) } else if ( gi.inPVS( NPC->enemy->currentOrigin, NPC->currentOrigin ) ) { + if ( TIMER_Done( NPC, "talkDebounce" ) && !Q_irand( 0, 10 ) ) + { + if ( NPCInfo->enemyCheckDebounceTime < 8 ) + { + int speech = -1; + switch( NPCInfo->enemyCheckDebounceTime ) + { + case 0: + case 1: + case 2: + speech = EV_CHASE1 + NPCInfo->enemyCheckDebounceTime; + break; + case 3: + case 4: + case 5: + speech = EV_COVER1 + NPCInfo->enemyCheckDebounceTime-3; + break; + case 6: + case 7: + speech = EV_ESCAPING1 + NPCInfo->enemyCheckDebounceTime-6; + break; + } + NPCInfo->enemyCheckDebounceTime++; + if ( speech != -1 ) + { + G_AddVoiceEvent( NPC, speech, Q_irand( 3000, 5000 ) ); + TIMER_Set( NPC, "talkDebounce", Q_irand( 5000, 7000 ) ); + } + } + } + + NPCInfo->enemyLastSeenTime = level.time; + int hit = NPC_ShotEntity( NPC->enemy, impactPos ); gentity_t *hitEnt = &g_entities[hit]; if ( hit == NPC->enemy->s.number @@ -763,7 +950,6 @@ void NPC_BSGM_Attack( void ) } else { - NPCInfo->enemyLastSeenTime = level.time; faceEnemy = qtrue; NPC_AimAdjust( -1 );//adjust aim worse longer we cannot see enemy } @@ -787,6 +973,7 @@ void NPC_BSGM_Attack( void ) if ( enemyCS ) { shoot = qtrue; + //NPCInfo->enemyCheckDebounceTime = level.time;//actually used here as a last actual LOS } else { @@ -871,7 +1058,12 @@ void NPC_BSGM_Attack( void ) if ( move && !NPC->lockCount ) {//move toward goal - if ( NPCInfo->goalEntity ) + if ( NPCInfo->goalEntity + && NPC->client->ps.legsAnim != BOTH_ALERT1 + && NPC->client->ps.legsAnim != BOTH_ATTACK2 + && NPC->client->ps.legsAnim != BOTH_ATTACK4 + && NPC->client->ps.legsAnim != BOTH_ATTACK5 + && NPC->client->ps.legsAnim != BOTH_ATTACK7 ) { move = GM_Move(); } @@ -928,27 +1120,70 @@ void NPC_BSGM_Attack( void ) } //also: - if ( NPCInfo->touchedByPlayer != NULL && NPCInfo->touchedByPlayer == NPC->enemy && NPC->client->ps.powerups[PW_GALAK_SHIELD] > 0 ) - {//zap him! - //animate me - NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK6, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer ); - TIMER_Set( NPC, "standTime", NPC->client->ps.legsAnimTimer ); - //FIXME: debounce this? - NPCInfo->touchedByPlayer = NULL; - //FIXME: some shield effect? - NPC->client->ps.powerups[PW_BATTLESUIT] = level.time + ARMOR_EFFECT_TIME; - vec3_t smackDir; - VectorSubtract( NPC->enemy->currentOrigin, NPC->currentOrigin, smackDir ); - smackDir[2] += 30; - VectorNormalize( smackDir ); - G_Damage( NPC->enemy, NPC, NPC, smackDir, NPC->currentOrigin, (g_spskill->integer+1)*Q_irand( 5, 10), DAMAGE_NO_KNOCKBACK, MOD_ELECTROCUTE ); - //throw them - G_Throw( NPC->enemy, smackDir, 100 ); - NPC->enemy->s.powerups |= ( 1 << PW_SHOCKED ); - NPC->enemy->client->ps.powerups[PW_SHOCKED] = level.time + 1000; - //stop any attacks - ucmd.buttons = 0; + if ( NPC->enemy->s.weapon == WP_TURRET && !Q_stricmp( "PAS", NPC->enemy->classname ) ) + {//crush turrets + if ( G_BoundsOverlap( NPC->absmin, NPC->absmax, NPC->enemy->absmin, NPC->enemy->absmax ) ) + {//have to do this test because placed turrets are not solid to NPCs (so they don't obstruct navigation) + if ( NPC->client->ps.powerups[PW_GALAK_SHIELD] > 0 ) + { + NPC->client->ps.powerups[PW_BATTLESUIT] = level.time + ARMOR_EFFECT_TIME; + G_Damage( NPC->enemy, NPC, NPC, NULL, NPC->currentOrigin, 100, DAMAGE_NO_KNOCKBACK, MOD_ELECTROCUTE ); + } + else + { + G_Damage( NPC->enemy, NPC, NPC, NULL, NPC->currentOrigin, 100, DAMAGE_NO_KNOCKBACK, MOD_CRUSH ); + } + } + } + else if ( NPCInfo->touchedByPlayer != NULL && NPCInfo->touchedByPlayer == NPC->enemy ) + {//touched enemy + if ( NPC->client->ps.powerups[PW_GALAK_SHIELD] > 0 ) + {//zap him! + //animate me + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK6, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + TIMER_Set( NPC, "attackDelay", NPC->client->ps.torsoAnimTimer ); + TIMER_Set( NPC, "standTime", NPC->client->ps.legsAnimTimer ); + //FIXME: debounce this? + NPCInfo->touchedByPlayer = NULL; + //FIXME: some shield effect? + NPC->client->ps.powerups[PW_BATTLESUIT] = level.time + ARMOR_EFFECT_TIME; + vec3_t smackDir; + VectorSubtract( NPC->enemy->currentOrigin, NPC->currentOrigin, smackDir ); + smackDir[2] += 30; + VectorNormalize( smackDir ); + G_Damage( NPC->enemy, NPC, NPC, smackDir, NPC->currentOrigin, (g_spskill->integer+1)*Q_irand( 5, 10), DAMAGE_NO_KNOCKBACK, MOD_ELECTROCUTE ); + //throw them + G_Throw( NPC->enemy, smackDir, 100 ); + NPC->enemy->s.powerups |= ( 1 << PW_SHOCKED ); + if ( NPC->enemy->client ) + { + NPC->enemy->client->ps.powerups[PW_SHOCKED] = level.time + 1000; + } + //stop any attacks + ucmd.buttons = 0; + } + } + + if ( NPCInfo->movementSpeech < 3 && NPCInfo->blockedSpeechDebounceTime <= level.time ) + { + if ( NPC->enemy && NPC->enemy->health > 0 && NPC->enemy->painDebounceTime > level.time ) + { + if ( NPC->enemy->health < 50 && NPCInfo->movementSpeech == 2 ) + { + G_AddVoiceEvent( NPC, EV_ANGER2, Q_irand( 2000, 4000 ) ); + NPCInfo->movementSpeech = 3; + } + else if ( NPC->enemy->health < 75 && NPCInfo->movementSpeech == 1 ) + { + G_AddVoiceEvent( NPC, EV_ANGER1, Q_irand( 2000, 4000 ) ); + NPCInfo->movementSpeech = 2; + } + else if ( NPC->enemy->health < 100 && NPCInfo->movementSpeech == 0 ) + { + G_AddVoiceEvent( NPC, EV_ANGER3, Q_irand( 2000, 4000 ) ); + NPCInfo->movementSpeech = 1; + } + } } } @@ -959,52 +1194,58 @@ void NPC_BSGM_Default( void ) WeaponThink( qtrue ); } + if ( NPC->client->ps.stats[STAT_ARMOR] <= 0 ) + {//armor gone + if ( !NPCInfo->investigateDebounceTime ) + {//start regenerating the armor + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_shield_off", TURN_OFF ); + NPC->flags &= ~FL_SHIELDED;//no more reflections + VectorSet( NPC->mins, -20, -20, -24 ); + VectorSet( NPC->maxs, 20, 20, 64 ); + NPC->client->crouchheight = NPC->client->standheight = 64; + if ( NPC->locationDamage[HL_GENERIC1] < GENERATOR_HEALTH ) + {//still have the generator bolt-on + if ( NPCInfo->investigateCount < 12 ) + { + NPCInfo->investigateCount++; + } + NPCInfo->investigateDebounceTime = level.time + (NPCInfo->investigateCount * 5000); + } + } + else if ( NPCInfo->investigateDebounceTime < level.time ) + {//armor regenerated, turn shield back on + //do a trace and make sure we can turn this back on? + trace_t tr; + gi.trace( &tr, NPC->currentOrigin, shieldMins, shieldMaxs, NPC->currentOrigin, NPC->s.number, NPC->clipmask ); + if ( !tr.startsolid ) + { + VectorCopy( shieldMins, NPC->mins ); + VectorCopy( shieldMaxs, NPC->maxs ); + NPC->client->crouchheight = NPC->client->standheight = shieldMaxs[2]; + NPC->client->ps.stats[STAT_ARMOR] = GALAK_SHIELD_HEALTH; + NPCInfo->investigateDebounceTime = 0; + NPC->flags |= FL_SHIELDED;//reflect normal shots + NPC->fx_time = level.time; + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_shield_off", TURN_ON ); + } + } + } + if ( NPC->client->ps.stats[STAT_ARMOR] > 0 ) + {//armor present + NPC->client->ps.powerups[PW_GALAK_SHIELD] = Q3_INFINITE;//temp, for effect + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_shield_off", TURN_ON ); + } + else + { + gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_shield_off", TURN_OFF ); + } + if( !NPC->enemy ) {//don't have an enemy, look for one NPC_BSGM_Patrol(); } else //if ( NPC->enemy ) {//have an enemy - if ( NPC->client->ps.stats[STAT_ARMOR] <= 0 ) - {//armor gone - if ( !NPCInfo->investigateDebounceTime ) - {//start regenerating the armor - gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_shield_off", TURN_OFF ); - NPC->flags &= ~FL_SHIELDED;//no more reflections - VectorSet( NPC->mins, -20, -20, -24 ); - VectorSet( NPC->maxs, 20, 20, 64 ); - NPC->client->crouchheight = NPC->client->standheight = 64; - if ( NPC->locationDamage[HL_GENERIC1] < GENERATOR_HEALTH ) - {//still have the generator bolt-on - if ( NPCInfo->investigateCount < 12 ) - { - NPCInfo->investigateCount++; - } - NPCInfo->investigateDebounceTime = level.time + (NPCInfo->investigateCount * 5000); - } - } - else if ( NPCInfo->investigateDebounceTime < level.time ) - {//armor regenerated, turn shield back on - //do a trace and make sure we can turn this back on? - trace_t tr; - gi.trace( &tr, NPC->currentOrigin, shieldMins, shieldMaxs, NPC->currentOrigin, NPC->s.number, NPC->clipmask ); - if ( !tr.startsolid ) - { - VectorCopy( shieldMins, NPC->mins ); - VectorCopy( shieldMaxs, NPC->maxs ); - NPC->client->crouchheight = NPC->client->standheight = shieldMaxs[2]; - NPC->client->ps.stats[STAT_ARMOR] = GALAK_SHIELD_HEALTH; - NPCInfo->investigateDebounceTime = 0; - NPC->flags |= FL_SHIELDED;//reflect normal shots - NPC->fx_time = level.time; - gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "torso_shield_off", TURN_ON ); - } - } - } - if ( NPC->client->ps.stats[STAT_ARMOR] > 0 ) - {//armor present - NPC->client->ps.powerups[PW_GALAK_SHIELD] = Q3_INFINITE;//temp, for effect - } NPC_BSGM_Attack(); } } diff --git a/code/game/AI_Grenadier.cpp b/code/game/AI_Grenadier.cpp index 282718b..1160501 100644 --- a/code/game/AI_Grenadier.cpp +++ b/code/game/AI_Grenadier.cpp @@ -204,7 +204,7 @@ void NPC_BSGrenadier_Patrol( void ) if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) ) { //Is there danger nearby - int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, qfalse, AEL_SUSPICIOUS ); + int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_SUSPICIOUS ); if ( NPC_CheckForDanger( alertEvent ) ) { NPC_UpdateAngles( qtrue, qtrue ); @@ -285,7 +285,7 @@ void NPC_BSGrenadier_Idle( void ) //FIXME: check for other alert events? //Is there danger nearby? - if ( NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, qfalse, AEL_DANGER ) ) ) + if ( NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) ) { NPC_UpdateAngles( qtrue, qtrue ); return; @@ -474,7 +474,7 @@ void NPC_BSGrenadier_Attack( void ) return; } - if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, qfalse, AEL_DANGER ) ) ) + if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) ) {//going to run NPC_UpdateAngles( qtrue, qtrue ); return; @@ -493,8 +493,8 @@ void NPC_BSGrenadier_Attack( void ) enemyDist = DistanceSquared( NPC->enemy->currentOrigin, NPC->currentOrigin ); //See if we should switch to melee attack - if ( enemyDist < 16384 )//128 - { + if ( enemyDist < 16384 && (!NPC->enemy->client||NPC->enemy->client->ps.weapon != WP_SABER||!NPC->enemy->client->ps.saberActive) )//128 + {//enemy is close and not using saber if ( NPC->client->ps.weapon == WP_THERMAL ) {//grenadier trace_t trace; @@ -510,8 +510,8 @@ void NPC_BSGrenadier_Attack( void ) } } } - else if ( enemyDist > 65536 )//256 - { + else if ( enemyDist > 65536 || (NPC->enemy->client && NPC->enemy->client->ps.weapon == WP_SABER && NPC->enemy->client->ps.saberActive) )//256 + {//enemy is far or using saber if ( NPC->client->ps.weapon == WP_MELEE && (NPC->client->ps.stats[STAT_WEAPONS]&(1<health) { @@ -292,8 +300,6 @@ void ImperialProbe_FireBlaster(void) AngleVectors (NPC->currentAngles, forward, vright, up); } - G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/shoot1.wav")); - missile = CreateMissile( muzzle1, forward, 1600, 10000, NPC ); missile->classname = "bryar_proj"; @@ -376,7 +382,7 @@ void ImperialProbe_AttackDecision( void ) { if (TIMER_Done(NPC,"angerNoise")) { - G_Sound( NPC, G_SoundIndex(va("sound/chars/probe/misc/probetalk%d.wav", Q_irand(1, 3)))); + G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/probe/misc/probetalk%d", Q_irand(1, 3)) ); TIMER_Set( NPC, "patrolNoise", Q_irand( 4000, 10000 ) ); } @@ -441,9 +447,9 @@ void NPC_Probe_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, ve VectorCopy(self->currentOrigin,origin); origin[2] +=50; - G_PlayEffect( "small_chunks", origin ); +// G_PlayEffect( "small_chunks", origin ); G_PlayEffect( "probehead", origin ); - G_PlayEffect( "mouseexplosion1", origin ); + G_PlayEffect( "env/med_explode2", origin ); self->client->clientInfo.headModel = 0; self->NPC->stats.moveType = MT_RUNJUMP; self->client->ps.gravity = g_gravity->value*.1; @@ -517,21 +523,21 @@ void ImperialProbe_Patrol( void ) if ( UpdateGoal() ) { //start loop sound once we move - NPC->s.loopSound = G_SoundIndex( "sound/chars/probe/misc/probedroidloop.wav" ); + NPC->s.loopSound = G_SoundIndex( "sound/chars/probe/misc/probedroidloop" ); ucmd.buttons |= BUTTON_WALKING; NPC_MoveToGoal( qtrue ); } //randomly talk if (TIMER_Done(NPC,"patrolNoise")) { - G_Sound( NPC, G_SoundIndex(va("sound/chars/probe/misc/probetalk%d.wav", Q_irand(1, 3)))); + G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/probe/misc/probetalk%d", Q_irand(1, 3)) ); TIMER_Set( NPC, "patrolNoise", Q_irand( 2000, 4000 ) ); } } else // He's got an enemy. Make him angry. { - G_Sound( NPC, G_SoundIndex("sound/chars/probe/misc/anger1.wav")); + G_SoundOnEnt( NPC, CHAN_AUTO, "sound/chars/probe/misc/anger1" ); TIMER_Set( NPC, "angerNoise", Q_irand( 2000, 4000 ) ); //NPCInfo->behaviorState = BS_HUNT_AND_KILL; } diff --git a/code/game/AI_Interrogator.cpp b/code/game/AI_Interrogator.cpp index 8394131..203d057 100644 --- a/code/game/AI_Interrogator.cpp +++ b/code/game/AI_Interrogator.cpp @@ -7,6 +7,7 @@ void Interrogator_Idle( void ); void DeathFX( gentity_t *ent ); +extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); enum { @@ -22,11 +23,11 @@ NPC_Interrogator_Precache */ void NPC_Interrogator_Precache(gentity_t *self) { - G_SoundIndex( "sound/chars/probe/misc/talk.wav"); - G_SoundIndex( "sound/chars/interrogator/misc/torture_droid_inject.mp3" ); -// G_SoundIndex( "sound/chars/probe/misc/probedroidloop.wav" ); -// G_SoundIndex("sound/chars/probe/misc/anger1.wav"); - G_EffectIndex( "probeexplosion1"); + G_SoundIndex( "sound/chars/interrogator/misc/torture_droid_lp" ); + G_SoundIndex("sound/chars/mark1/misc/anger.wav"); + G_SoundIndex( "sound/chars/probe/misc/talk"); + G_SoundIndex( "sound/chars/interrogator/misc/torture_droid_inject" ); + G_SoundIndex( "sound/chars/interrogator/misc/int_droid_explo" ); G_EffectIndex( "droidexplosion1" ); } /* @@ -37,6 +38,7 @@ Interrogator_die void Interrogator_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc ) { self->client->ps.velocity[2] = -100; + /* self->locationDamage[HL_NONE] += damage; if (self->locationDamage[HL_NONE] > 40) { @@ -45,12 +47,16 @@ void Interrogator_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacke self->contents = CONTENTS_CORPSE; } else + */ { self->NPC->stats.moveType = MT_WALK; self->client->ps.velocity[0] = Q_irand( -10, -20 ); self->client->ps.velocity[1] = Q_irand( -10, -20 ); self->client->ps.velocity[2] = -100; } + //self->takedamage = qfalse; + //self->client->ps.eFlags |= EF_NODRAW; + //self->contents = 0; return; } @@ -132,6 +138,7 @@ void Interrogator_MaintainHeight( void ) // vec3_t endPos; // trace_t trace; + NPC->s.loopSound = G_SoundIndex( "sound/chars/interrogator/misc/torture_droid_lp" ); // Update our angles regardless NPC_UpdateAngles( qtrue, qtrue ); @@ -375,7 +382,7 @@ void Interrogator_Attack( void ) { if (TIMER_Done(NPC,"angerNoise")) { - G_Sound( NPC, G_SoundIndex(va("sound/chars/probe/misc/talk.wav", Q_irand(1, 3)))); + G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/probe/misc/talk.wav", Q_irand(1, 3)) ); TIMER_Set( NPC, "patrolNoise", Q_irand( 4000, 10000 ) ); } @@ -419,7 +426,7 @@ void Interrogator_Idle( void ) { if ( NPC_CheckPlayerTeamStealth() ) { - G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/anger.wav")); + G_SoundOnEnt( NPC, CHAN_AUTO, "sound/chars/mark1/misc/anger.wav" ); NPC_UpdateAngles( qtrue, qtrue ); return; } @@ -436,7 +443,7 @@ NPC_BSInterrogator_Default */ void NPC_BSInterrogator_Default( void ) { - NPC->e_DieFunc = dieF_Interrogator_die; + //NPC->e_DieFunc = dieF_Interrogator_die; if ( NPC->enemy ) { diff --git a/code/game/AI_Jedi.cpp b/code/game/AI_Jedi.cpp index b420247..3911d9d 100644 --- a/code/game/AI_Jedi.cpp +++ b/code/game/AI_Jedi.cpp @@ -11,6 +11,7 @@ extern void CG_DrawAlert( vec3_t origin, float rating ); extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); extern qboolean InFront( vec3_t spot, vec3_t from, vec3_t fromAngles, float threshHold = 0.0f ); extern void G_StartMatrixEffect( gentity_t *ent, qboolean falling = qfalse, int length = 1000 ); +extern cvar_t *g_saberRealisticCombat; extern cvar_t *d_slowmodeath; #define MAX_VIEW_DIST 2048 @@ -36,10 +37,11 @@ extern void NPC_TempLookTarget( gentity_t *self, int lookEntNum, int minLookTime extern qboolean G_ExpandPointToBBox( vec3_t point, const vec3_t mins, const vec3_t maxs, int ignore, int clipmask ); extern qboolean NPC_CheckEnemyStealth( void ); extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); +extern gitem_t *FindItemForAmmo( ammo_t ammo ); extern void ForceThrow( gentity_t *self, qboolean pull ); extern void ForceLightning( gentity_t *self ); extern int WP_MissileBlockForBlock( int saberBlock ); -extern qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir ); +extern qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir, int mod ); extern qboolean WP_ForcePowerUsable( gentity_t *self, forcePowers_t forcePower, int overrideAmt ); extern qboolean WP_ForcePowerAvailable( gentity_t *self, forcePowers_t forcePower, int overrideAmt ); extern void WP_ForcePowerStop( gentity_t *self, forcePowers_t forcePower ); @@ -76,6 +78,7 @@ enum void NPC_ShadowTrooper_Precache( void ) { + RegisterItem( FindItemForAmmo( AMMO_FORCE ) ); G_SoundIndex( "sound/chars/shadowtrooper/cloak.wav" ); G_SoundIndex( "sound/chars/shadowtrooper/decloak.wav" ); } @@ -101,6 +104,8 @@ void Jedi_ClearTimers( gentity_t *ent ) TIMER_Set( ent, "movecenter", 0 ); TIMER_Set( ent, "saberLevelDebounce", 0 ); TIMER_Set( ent, "noRetreat", 0 ); + TIMER_Set( ent, "holdLightning", 0 ); + TIMER_Set( ent, "noturn", 0 ); } void Jedi_PlayBlockedPushSound( gentity_t *self ) @@ -133,7 +138,18 @@ void NPC_Jedi_PlayConfusionSound( gentity_t *self ) { if ( self->health > 0 ) { - G_AddVoiceEvent( self, Q_irand( EV_CONFUSE1, EV_CONFUSE2 ), 2000 ); + if ( self->client && ( self->client->NPC_class == CLASS_TAVION || self->client->NPC_class == CLASS_DESANN ) ) + { + G_AddVoiceEvent( self, Q_irand( EV_CONFUSE1, EV_CONFUSE3 ), 2000 ); + } + else if ( Q_irand( 0, 1 ) ) + { + G_AddVoiceEvent( self, Q_irand( EV_TAUNT1, EV_TAUNT3 ), 2000 ); + } + else + { + G_AddVoiceEvent( self, Q_irand( EV_GLOAT1, EV_GLOAT3 ), 2000 ); + } } } @@ -301,14 +317,30 @@ static qboolean Jedi_BattleTaunt( void ) && NPCInfo->blockedSpeechDebounceTime < level.time && jediSpeechDebounceTime[NPC->client->playerTeam] < level.time ) { - G_AddVoiceEvent( NPC, Q_irand( EV_TAUNT1, EV_TAUNT3 ), 3000 ); - jediSpeechDebounceTime[NPC->client->playerTeam] = NPCInfo->blockedSpeechDebounceTime = level.time + 6000; - TIMER_Set( NPC, "chatter", Q_irand( 5000, 10000 ) ); - - if ( NPC->enemy && NPC->enemy->NPC && NPC->enemy->s.weapon == WP_SABER && NPC->enemy->client && NPC->enemy->client->NPC_class == CLASS_JEDI ) - {//Have the enemy jedi say something in response when I'm done? + int event = -1; + if ( NPC->client->playerTeam == TEAM_PLAYER + && NPC->enemy && NPC->enemy->client && NPC->enemy->client->NPC_class == CLASS_JEDI ) + {//a jedi fighting a jedi - training + if ( NPC->client->NPC_class == CLASS_JEDI && NPCInfo->rank == RANK_COMMANDER ) + {//only trainer taunts + event = EV_TAUNT1; + } + } + else + {//reborn or a jedi fighting an enemy + event = Q_irand( EV_TAUNT1, EV_TAUNT3 ); + } + if ( event != -1 ) + { + G_AddVoiceEvent( NPC, event, 3000 ); + jediSpeechDebounceTime[NPC->client->playerTeam] = NPCInfo->blockedSpeechDebounceTime = level.time + 6000; + TIMER_Set( NPC, "chatter", Q_irand( 5000, 10000 ) ); + + if ( NPC->enemy && NPC->enemy->NPC && NPC->enemy->s.weapon == WP_SABER && NPC->enemy->client && NPC->enemy->client->NPC_class == CLASS_JEDI ) + {//Have the enemy jedi say something in response when I'm done? + } + return qtrue; } - return qtrue; } return qfalse; } @@ -732,9 +764,11 @@ static void Jedi_CombatDistance( int enemy_dist ) { Jedi_Advance(); } - if ( NPC->client->ps.weapon == WP_SABER && //using saber - NPC->client->ps.saberEntityState == SES_LEAVING && //not returning yet - NPC->client->ps.forcePowerLevel[FP_SABERTHROW] > FORCE_LEVEL_1 )//2nd or 3rd level lightsaber + if ( NPC->client->ps.weapon == WP_SABER //using saber + && NPC->client->ps.saberEntityState == SES_LEAVING //not returning yet + && NPC->client->ps.forcePowerLevel[FP_SABERTHROW] > FORCE_LEVEL_1 //2nd or 3rd level lightsaber + && !(NPC->client->ps.forcePowersActive&(1 << FP_SPEED)) + && !(NPC->client->ps.saberEventFlags&SEF_INWATER) )//saber not in water {//hold it out there ucmd.buttons |= BUTTON_ALT_ATTACK; //FIXME: time limit? @@ -815,6 +849,14 @@ static void Jedi_CombatDistance( int enemy_dist ) } } } + else if ( enemy_dist <= 64 && (NPCInfo->scriptFlags&SCF_DONT_FIRE) ) + {//can't use saber and they're in striking range + if ( !Q_irand( 0, 5 ) && InFront( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, 0.2f ) ) + { + ForceThrow( NPC, qfalse ); + } + Jedi_Retreat(); + } else if ( enemy_dist <= -16 ) {//we're too damn close! Jedi_Retreat(); @@ -853,7 +895,7 @@ static void Jedi_CombatDistance( int enemy_dist ) } */ else if ( enemy_dist > 50 )//FIXME: not hardcoded- base on our reach (modelScale?) and saberLengthMax - {//we're out of striking range + {//we're out of striking range and we are allowed to attack //first, check some tactical force power decisions if ( NPC->enemy && NPC->enemy->client && (NPC->enemy->client->ps.eFlags&EF_FORCE_GRIPPED) ) {//They're being gripped, rush them! @@ -861,10 +903,16 @@ static void Jedi_CombatDistance( int enemy_dist ) {//they're on the ground, so advance if ( TIMER_Done( NPC, "parryTime" ) || NPCInfo->rank > RANK_LT ) {//not parrying - Jedi_Advance(); + if ( enemy_dist > 200 || !(NPCInfo->scriptFlags&SCF_DONT_FIRE) ) + {//far away or allowed to use saber + Jedi_Advance(); + } } } - if ( NPCInfo->rank >= RANK_LT_JG && !Q_irand( 0, 5 ) ) + if ( NPCInfo->rank >= RANK_LT_JG + && !Q_irand( 0, 5 ) + && !(NPC->client->ps.forcePowersActive&(1 << FP_SPEED)) + && !(NPC->client->ps.saberEventFlags&SEF_INWATER) )//saber not in water {//throw saber ucmd.buttons |= BUTTON_ALT_ATTACK; } @@ -897,7 +945,10 @@ static void Jedi_CombatDistance( int enemy_dist ) {//they're on the ground, so advance if ( TIMER_Done( NPC, "parryTime" ) || NPCInfo->rank > RANK_LT ) {//not parrying - Jedi_Advance(); + if ( enemy_dist > 200 || !(NPCInfo->scriptFlags&SCF_DONT_FIRE) ) + {//far away or allowed to use saber + Jedi_Advance(); + } } } } @@ -914,7 +965,10 @@ static void Jedi_CombatDistance( int enemy_dist ) { chanceScale = 5; } - if ( chanceScale && enemy_dist > Q_irand( 100, 200 ) && enemy_dist < 500 && (Q_irand( 0, chanceScale*10 )<5 || (NPC->enemy->client && NPC->enemy->client->ps.weapon != WP_SABER && !Q_irand( 0, chanceScale ) ) ) ) + if ( chanceScale + && (enemy_dist > Q_irand( 100, 200 ) || (NPCInfo->scriptFlags&SCF_DONT_FIRE)) + && enemy_dist < 500 + && (Q_irand( 0, chanceScale*10 )<5 || (NPC->enemy->client && NPC->enemy->client->ps.weapon != WP_SABER && !Q_irand( 0, chanceScale ) ) ) ) {//else, randomly try some kind of attack every now and then if ( (NPCInfo->rank == RANK_ENSIGN || NPCInfo->rank > RANK_LT_JG) && !Q_irand( 0, 1 ) ) { @@ -933,6 +987,11 @@ static void Jedi_CombatDistance( int enemy_dist ) else if ( WP_ForcePowerAvailable( NPC, FP_LIGHTNING, 0 ) && Q_irand( 0, 1 ) ) { ForceLightning( NPC ); + if ( NPC->client->ps.forcePowerLevel[FP_LIGHTNING] > FORCE_LEVEL_1 ) + { + NPC->client->ps.weaponTime = Q_irand( 1000, 3000+(g_spskill->integer*500) ); + TIMER_Set( NPC, "holdLightning", NPC->client->ps.weaponTime ); + } TIMER_Set( NPC, "attackDelay", NPC->client->ps.weaponTime ); } else if ( WP_ForcePowerAvailable( NPC, FP_GRIP, 0 ) ) @@ -949,12 +1008,16 @@ static void Jedi_CombatDistance( int enemy_dist ) TIMER_Set( NPC, "gripping", 3000 ); TIMER_Set( NPC, "attackDelay", 3000 ); } - else if ( WP_ForcePowerAvailable( NPC, FP_SABERTHROW, 0 ) ) + else if ( WP_ForcePowerAvailable( NPC, FP_SABERTHROW, 0 ) + && !(NPC->client->ps.forcePowersActive&(1 << FP_SPEED)) + && !(NPC->client->ps.saberEventFlags&SEF_INWATER) )//saber not in water {//throw saber ucmd.buttons |= BUTTON_ALT_ATTACK; } } - else if ( NPCInfo->rank >= RANK_LT_JG ) + else if ( NPCInfo->rank >= RANK_LT_JG + && !(NPC->client->ps.forcePowersActive&(1 << FP_SPEED)) + && !(NPC->client->ps.saberEventFlags&SEF_INWATER) )//saber not in water {//throw saber ucmd.buttons |= BUTTON_ALT_ATTACK; } @@ -966,7 +1029,10 @@ static void Jedi_CombatDistance( int enemy_dist ) {//not parrying if ( !NPC->enemy->client || NPC->enemy->client->ps.groundEntityNum != ENTITYNUM_NONE ) {//they're on the ground, so advance - Jedi_Advance(); + if ( enemy_dist > 200 || !(NPCInfo->scriptFlags&SCF_DONT_FIRE) ) + {//far away or allowed to use saber + Jedi_Advance(); + } } } } @@ -984,8 +1050,8 @@ static void Jedi_CombatDistance( int enemy_dist ) } else if ( NPCInfo->stats.aggression > 5 ) {//try to get closer - if ( enemy_dist > 0 ) - { + if ( enemy_dist > 0 && !(NPCInfo->scriptFlags&SCF_DONT_FIRE)) + {//we're allowed to use our lightsaber, get closer if ( TIMER_Done( NPC, "parryTime" ) || NPCInfo->rank > RANK_LT ) {//not parrying if ( !NPC->enemy->client || NPC->enemy->client->ps.groundEntityNum != ENTITYNUM_NONE ) @@ -1160,7 +1226,7 @@ qboolean Jedi_DodgeEvasion( gentity_t *self, gentity_t *shooter, trace_t *tr, in } CCollisionRecord &coll = tr->G2CollisionMap[z]; - G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &hitLoc, coll.mCollisionPosition, NULL, NULL ); + G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &hitLoc, coll.mCollisionPosition, NULL, NULL, MOD_UNKNOWN ); //only want the first break; } @@ -1188,7 +1254,8 @@ qboolean Jedi_DodgeEvasion( gentity_t *self, gentity_t *shooter, trace_t *tr, in { G_SetEnemy( self, shooter ); } - if ( self->NPC && (self->NPC->scriptFlags&SCF_NO_ACROBATICS) ) + if ( self->NPC + && ((self->NPC->scriptFlags&SCF_NO_ACROBATICS) || PM_InKnockDown( &self->client->ps ) ) ) { return qfalse; } @@ -1527,72 +1594,128 @@ int Jedi_ReCalcParryTime( gentity_t *self, evasionType_t evasionType ) } else if ( self->NPC ) { - int baseTime; - if ( evasionType == EVASION_DODGE ) + if ( !g_saberRealisticCombat->integer + && ( g_spskill->integer == 2 || (g_spskill->integer == 1 && self->client->NPC_class == CLASS_TAVION) ) ) { - baseTime = self->client->ps.torsoAnimTimer; - } - else if ( evasionType == EVASION_CARTWHEEL ) - { - baseTime = self->client->ps.torsoAnimTimer; + if ( self->client->NPC_class == CLASS_TAVION ) + { + return 0; + } + else + { + return Q_irand( 0, 150 ); + } } else { - baseTime = 300;//500; - - switch ( g_spskill->integer ) + int baseTime; + if ( evasionType == EVASION_DODGE ) { - case 0: - baseTime = 300;//500; - break; - case 1: - baseTime = 150;//300; - break; - case 2: - default: - baseTime = 50;//100; - break; + baseTime = self->client->ps.torsoAnimTimer; } - - if ( self->client->NPC_class == CLASS_TAVION ) - {//Tavion is faster - baseTime = baseTime/2; + else if ( evasionType == EVASION_CARTWHEEL ) + { + baseTime = self->client->ps.torsoAnimTimer; } - else if ( self->NPC->rank >= RANK_LT_JG ) - {//fencers, bosses, shadowtroopers, luke, desann, et al use the norm - //baseTime = baseTime; - } - else if ( self->NPC->rank == RANK_CIVILIAN ) - {//grunts are slowest - baseTime = baseTime*5; - } - else if ( self->NPC->rank == RANK_CREWMAN ) - {//acrobats aren't so bad - baseTime = baseTime*3; + else if ( self->client->ps.saberInFlight ) + { + baseTime = Q_irand( 1, 3 ) * 50; } else - {//force users, are kinda slow - baseTime = baseTime*4; - } - if ( evasionType == EVASION_DUCK || evasionType == EVASION_DUCK_PARRY ) { - baseTime += 300; - } - else if ( evasionType == EVASION_JUMP || evasionType == EVASION_JUMP_PARRY ) - { - baseTime += 100; - } - else if ( evasionType == EVASION_OTHER ) - { - baseTime += 300; - } - else if ( evasionType == EVASION_FJUMP ) - { - baseTime += 200; + if ( g_saberRealisticCombat->integer ) + { + baseTime = 500; + + switch ( g_spskill->integer ) + { + case 0: + baseTime = 500; + break; + case 1: + baseTime = 300; + break; + case 2: + default: + baseTime = 100; + break; + } + } + else + { + baseTime = 150;//500; + + switch ( g_spskill->integer ) + { + case 0: + baseTime = 200;//500; + break; + case 1: + baseTime = 100;//300; + break; + case 2: + default: + baseTime = 50;//100; + break; + } + } + + if ( self->client->NPC_class == CLASS_TAVION ) + {//Tavion is faster + baseTime = ceil(baseTime/2.0f); + } + else if ( self->NPC->rank >= RANK_LT_JG ) + {//fencers, bosses, shadowtroopers, luke, desann, et al use the norm + if ( Q_irand( 0, 2 ) ) + {//medium speed parry + baseTime = baseTime; + } + else + {//with the occasional fast parry + baseTime = ceil(baseTime/2.0f); + } + } + else if ( self->NPC->rank == RANK_CIVILIAN ) + {//grunts are slowest + baseTime = baseTime*Q_irand(1,3); + } + else if ( self->NPC->rank == RANK_CREWMAN ) + {//acrobats aren't so bad + if ( evasionType == EVASION_PARRY + || evasionType == EVASION_DUCK_PARRY + || evasionType == EVASION_JUMP_PARRY ) + {//slower with parries + baseTime = baseTime*Q_irand(1,2); + } + else + {//faster with acrobatics + //baseTime = baseTime; + } + } + else + {//force users are kinda slow + baseTime = baseTime*Q_irand(1,2); + } + if ( evasionType == EVASION_DUCK || evasionType == EVASION_DUCK_PARRY ) + { + baseTime += 100; + } + else if ( evasionType == EVASION_JUMP || evasionType == EVASION_JUMP_PARRY ) + { + baseTime += 50; + } + else if ( evasionType == EVASION_OTHER ) + { + baseTime += 100; + } + else if ( evasionType == EVASION_FJUMP ) + { + baseTime += 100; + } } + + return baseTime; } - - return baseTime; } return 0; } @@ -1639,7 +1762,7 @@ NOTE: always blocking projectiles in this func! ------------------------- */ extern qboolean G_FindClosestPointOnLineSegment( const vec3_t start, const vec3_t end, const vec3_t from, vec3_t result ); -evasionType_t Jedi_SaberBlockGo( gentity_t *self, vec3_t pHitloc, vec3_t phitDir, gentity_t *incoming, float dist = 0.0f ) +evasionType_t Jedi_SaberBlockGo( gentity_t *self, usercmd_t *cmd, vec3_t pHitloc, vec3_t phitDir, gentity_t *incoming, float dist = 0.0f ) { vec3_t hitloc, hitdir, diff, fwdangles={0,0,0}, right; float rightdot; @@ -1656,7 +1779,11 @@ evasionType_t Jedi_SaberBlockGo( gentity_t *self, vec3_t pHitloc, vec3_t phitDir VectorCopy( pHitloc, hitloc ); VectorCopy( phitDir, hitdir ); //FIXME: maybe base this on rank some? And/or g_spskill? - if ( Jedi_QuickReactions( self ) ) + if ( self->client->ps.saberInFlight ) + {//DOH! do non-saber evasion! + saberBusy = qtrue; + } + else if ( Jedi_QuickReactions( self ) ) {//jedi trainer and tavion are must faster at parrying and can do it whenever they like //Also, on medium, all level 3 people can parry any time and on hard, all level 2 or 3 people can parry any time } @@ -1692,13 +1819,16 @@ evasionType_t Jedi_SaberBlockGo( gentity_t *self, vec3_t pHitloc, vec3_t phitDir if ( self->NPC && (self->NPC->rank == RANK_CREWMAN || self->NPC->rank >= RANK_LT_JG) ) {//acrobat or fencer or above if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE &&//on the ground - !(self->client->ps.pm_flags&PMF_DUCKED)&&ucmd.upmove>=0&&TIMER_Done( self, "duck" )//not ducking + !(self->client->ps.pm_flags&PMF_DUCKED)&&cmd->upmove>=0&&TIMER_Done( self, "duck" )//not ducking && !PM_InRoll( &self->client->ps )//not rolling && !PM_InKnockDown( &self->client->ps )//not knocked down - && !PM_SaberInAttack( self->client->ps.saberMove )//not attacking - && !PM_SaberInStart( self->client->ps.saberMove )//not starting an attack - && !PM_SpinningSaberAnim( self->client->ps.torsoAnim )//not in a saber spin - && !PM_SaberInSpecialAttack( self->client->ps.torsoAnim ) )//not in a special attack + && ( self->client->ps.saberInFlight || + (!PM_SaberInAttack( self->client->ps.saberMove )//not attacking + && !PM_SaberInStart( self->client->ps.saberMove )//not starting an attack + && !PM_SpinningSaberAnim( self->client->ps.torsoAnim )//not in a saber spin + && !PM_SaberInSpecialAttack( self->client->ps.torsoAnim ))//not in a special attack + ) + ) {//need to check all these because it overrides both torso and legs with the dodge doDodge = qtrue; } @@ -1958,10 +2088,12 @@ evasionType_t Jedi_SaberBlockGo( gentity_t *self, vec3_t pHitloc, vec3_t phitDir else {//gotta jump! if ( self->NPC && (self->NPC->rank == RANK_CREWMAN || self->NPC->rank > RANK_LT_JG ) && - (!Q_irand( 0, 10 ) || (!Q_irand( 0, 2 ) && (ucmd.forwardmove || ucmd.rightmove))) ) + (!Q_irand( 0, 10 ) || (!Q_irand( 0, 2 ) && (cmd->forwardmove || cmd->rightmove))) ) {//superjump //FIXME: check the jump, if can't, then block - if ( self->NPC && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS) ) + if ( self->NPC + && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS) + && !PM_InKnockDown( &self->client->ps ) ) { self->client->ps.forceJumpCharge = 320;//FIXME: calc this intelligently evasionType = EVASION_FJUMP; @@ -1977,7 +2109,14 @@ evasionType_t Jedi_SaberBlockGo( gentity_t *self, vec3_t pHitloc, vec3_t phitDir //FIXME: check the jump, if can't, then block if ( self->NPC && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS) ) { - ucmd.upmove = 127; + if ( self == NPC ) + { + cmd->upmove = 127; + } + else + { + self->client->ps.velocity[2] = JUMP_VELOCITY; + } evasionType = EVASION_JUMP; evaded = qtrue; if ( d_JediAI->integer ) @@ -2010,7 +2149,7 @@ evasionType_t Jedi_SaberBlockGo( gentity_t *self, vec3_t pHitloc, vec3_t phitDir self->client->saberTrail.inAction = qtrue;//FIXME: reset this when done! self->client->saberTrail.duration = 300;//FIXME: reset this when done! G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" ); - ucmd.upmove = 0; + cmd->upmove = 0; saberBusy = qtrue; evaded = qtrue; } @@ -2086,6 +2225,45 @@ evasionType_t Jedi_SaberBlockGo( gentity_t *self, vec3_t pHitloc, vec3_t phitDir gi.Printf( "LL block\n" ); } } + if ( incoming && incoming->s.weapon == WP_SABER ) + {//thrown saber! + if ( self->NPC && (self->NPC->rank == RANK_CREWMAN || self->NPC->rank > RANK_LT_JG ) && + (!Q_irand( 0, 10 ) || (!Q_irand( 0, 2 ) && (cmd->forwardmove || cmd->rightmove))) ) + {//superjump + //FIXME: check the jump, if can't, then block + if ( self->NPC + && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS) + && !PM_InKnockDown( &self->client->ps ) ) + { + self->client->ps.forceJumpCharge = 320;//FIXME: calc this intelligently + evasionType = EVASION_FJUMP; + if ( d_JediAI->integer ) + { + gi.Printf( "force jump + " ); + } + } + } + else + {//normal jump + //FIXME: check the jump, if can't, then block + if ( self->NPC && !(self->NPC->scriptFlags&SCF_NO_ACROBATICS) ) + { + if ( self == NPC ) + { + cmd->upmove = 127; + } + else + { + self->client->ps.velocity[2] = JUMP_VELOCITY; + } + evasionType = EVASION_JUMP_PARRY; + if ( d_JediAI->integer ) + { + gi.Printf( "jump + " ); + } + } + } + } evaded = qtrue; } } @@ -2251,6 +2429,7 @@ static qboolean Jedi_SaberBlock( void ) { gi.Printf( S_COLOR_RED"enemy saber dist: %4.2f\n", dist ); } + /* if ( dist < 300 //close && !Jedi_QuickReactions( NPC )//quick reaction people can interrupt themselves && (PM_SaberInStart( NPC->enemy->client->ps.saberMove ) || PM_SaberInAttack( NPC->enemy->client->ps.saberMove )) )//enemy is swinging at me @@ -2258,6 +2437,7 @@ static qboolean Jedi_SaberBlock( void ) TIMER_Set( NPC, "parryTime", 100 ); } else + */ { TIMER_Set( NPC, "parryTime", -1 ); } @@ -2295,6 +2475,7 @@ static qboolean Jedi_SaberBlock( void ) dist = VectorNormalize( dir2Me ); if ( DotProduct( dir, dir2Me ) < 0.2f ) {//saber is not swinging in my direction + /* if ( dist < 300 //close && !Jedi_QuickReactions( NPC )//quick reaction people can interrupt themselves && (PM_SaberInStart( NPC->enemy->client->ps.saberMove ) || PM_SaberInAttack( NPC->enemy->client->ps.saberMove )) )//enemy is swinging at me @@ -2302,6 +2483,7 @@ static qboolean Jedi_SaberBlock( void ) TIMER_Set( NPC, "parryTime", 100 ); } else + */ { TIMER_Set( NPC, "parryTime", -1 ); } @@ -2327,7 +2509,7 @@ static qboolean Jedi_SaberBlock( void ) //FIXME: if saber is off and/or we have force speed and want to be really cocky, // and the swing misses by some amount, we can use the dodges here... :) evasionType_t evasionType; - if ( (evasionType=Jedi_SaberBlockGo( NPC, hitloc, dir, NULL, dist )) != EVASION_DODGE ) + if ( (evasionType=Jedi_SaberBlockGo( NPC, &ucmd, hitloc, dir, NULL, dist )) != EVASION_DODGE ) {//we did block (not dodge) if ( !NPC->client->ps.saberInFlight ) {//make sure saber is on @@ -2351,11 +2533,11 @@ static qboolean Jedi_SaberBlock( void ) } else if ( NPCInfo->rank >= RANK_LT_JG ) {//fencers and higher hold a parry less - TIMER_Set( NPC, "parryTime", Q_irand( 1, 3 )*parryReCalcTime ); + TIMER_Set( NPC, "parryTime", parryReCalcTime ); } else {//others hold it longer - TIMER_Set( NPC, "parryTime", Q_irand( 2, 4 )*parryReCalcTime ); + TIMER_Set( NPC, "parryTime", Q_irand( 1, 2 )*parryReCalcTime ); } } } @@ -2593,7 +2775,9 @@ static void Jedi_EvasionSaber( vec3_t enemy_movedir, float enemy_dist, vec3_t en {//FIXME: check forcePushRadius[NPC->client->ps.forcePowerLevel[FP_PUSH]] ForceThrow( NPC, qfalse ); } - else if ( (NPCInfo->rank==RANK_CREWMAN||NPCInfo->rank>RANK_LT_JG) && !(NPCInfo->scriptFlags&SCF_NO_ACROBATICS) ) + else if ( (NPCInfo->rank==RANK_CREWMAN||NPCInfo->rank>RANK_LT_JG) + && !(NPCInfo->scriptFlags&SCF_NO_ACROBATICS) + && !PM_InKnockDown( &NPC->client->ps ) ) {//FIXME: make this a function call? //FIXME: check for clearance, safety of landing spot? NPC->client->ps.forceJumpCharge = 480; @@ -2632,7 +2816,10 @@ static void Jedi_EvasionSaber( vec3_t enemy_movedir, float enemy_dist, vec3_t en { gi.Printf( "def strafe\n" ); } - if ( !(NPCInfo->scriptFlags&SCF_NO_ACROBATICS) && (NPCInfo->rank == RANK_CREWMAN || NPCInfo->rank > RANK_LT_JG ) && !Q_irand( 0, 5 ) ) + if ( !(NPCInfo->scriptFlags&SCF_NO_ACROBATICS) + && (NPCInfo->rank == RANK_CREWMAN || NPCInfo->rank > RANK_LT_JG ) + && !PM_InKnockDown( &NPC->client->ps ) + && !Q_irand( 0, 5 ) ) {//FIXME: make this a function call? //FIXME: check for clearance, safety of landing spot? NPC->client->ps.forceJumpCharge = 320; @@ -2800,13 +2987,24 @@ static void Jedi_FaceEnemy( qboolean doPitch ) CalcEntitySpot( NPC->enemy, SPOT_HEAD, enemy_eyes ); //Find the desired angles - GetAnglesForDirection( eyes, enemy_eyes, angles ); + if ( NPC->client->ps.legsAnim == BOTH_A2_STABBACK1 + || NPC->client->ps.legsAnim == BOTH_CROUCHATTACKBACK1 + || NPC->client->ps.legsAnim == BOTH_ATTACK_BACK ) + {//point *away* + GetAnglesForDirection( enemy_eyes, eyes, angles ); + } + else + {//point towards him + GetAnglesForDirection( eyes, enemy_eyes, angles ); + } NPCInfo->desiredYaw = AngleNormalize360( angles[YAW] ); + /* if ( NPC->client->ps.saberBlocked == BLOCKED_UPPER_LEFT ) {//temp hack- to make up for poor coverage on left side NPCInfo->desiredYaw += 30; } + */ if ( doPitch ) { @@ -2997,6 +3195,11 @@ static void Jedi_TimersApply( void ) //FIXME: don't keep turning to face enemy or we'll end up spinning around ucmd.buttons |= BUTTON_FORCEGRIP; } + + if ( !TIMER_Done( NPC, "holdLightning" ) ) + {//hold down the lightning key + ucmd.buttons |= BUTTON_FORCE_LIGHTNING; + } } static void Jedi_CombatTimersUpdate( int enemy_dist ) @@ -3297,22 +3500,22 @@ static qboolean Jedi_AttackDecide( int enemy_dist ) TIMER_Set( NPC, "noRetreat", Q_irand( 500, 2000 ) ); //FIXME: check enemy_dist? NPC->client->ps.weaponTime = NPCInfo->shotTime = NPC->attackDebounceTime = 0; - NPC->client->ps.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + 500; + //NPC->client->ps.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + 500; NPC->client->ps.saberBlocked = BLOCKED_NONE; WeaponThink( qtrue ); return qtrue; } } - if ( NPC->client->NPC_class == CLASS_DESANN || + if ( NPC->client->NPC_class == CLASS_TAVION || ( NPC->client->NPC_class == CLASS_REBORN && NPCInfo->rank == RANK_LT_JG ) || ( NPC->client->NPC_class == CLASS_JEDI && NPCInfo->rank == RANK_COMMANDER ) ) - {//desann, fencers, jedi trainer are all good at following up a parry with an attack + {//tavion, fencers, jedi trainer are all good at following up a parry with an attack if ( ( PM_SaberInParry( NPC->client->ps.saberMove ) || PM_SaberInKnockaway( NPC->client->ps.saberMove ) ) && NPC->client->ps.saberBlocked != BLOCKED_PARRY_BROKEN ) {//try to attack straight from a parry NPC->client->ps.weaponTime = NPCInfo->shotTime = NPC->attackDebounceTime = 0; - NPC->client->ps.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + 500; + //NPC->client->ps.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + 500; NPC->client->ps.saberBlocked = BLOCKED_NONE; Jedi_AdjustSaberAnimLevel( NPC, FORCE_LEVEL_1 );//try to follow-up with a quick attack WeaponThink( qtrue ); @@ -3331,6 +3534,11 @@ static qboolean Jedi_AttackDecide( int enemy_dist ) return qfalse; } + if ( (NPCInfo->scriptFlags&SCF_DONT_FIRE) ) + {//not allowed to attack + return qfalse; + } + if ( !(ucmd.buttons&BUTTON_ATTACK) && !(ucmd.buttons&BUTTON_ALT_ATTACK) ) {//not already attacking //Try to attack @@ -3546,7 +3754,7 @@ static qboolean Jedi_Jump( vec3_t dest, int goalEntNum ) if ( hitCount >= maxHits ) {//NOTE: worst case scenario, use the one that impacted closest to the target (or just use the first try...?) - //FIXME: or refuse to jump? + //NOTE: or try failcase? VectorCopy( failCase, NPC->client->ps.velocity ); } VectorCopy( shotVel, NPC->client->ps.velocity ); @@ -3644,120 +3852,131 @@ static qboolean Jedi_TryJump( gentity_t *goal ) { return qfalse; } - if ( TIMER_Done( NPC, "jumpChaseDebounce" ) && - (!goal->client || goal->client->ps.groundEntityNum != ENTITYNUM_NONE) && - !PM_InKnockDown( &NPC->client->ps ) && !PM_InRoll( &NPC->client->ps ) ) - {//enemy is on terra firma - vec3_t goal_diff; - float goal_z_diff; - VectorSubtract( goal->currentOrigin, NPC->currentOrigin, goal_diff ); - goal_z_diff = goal_diff[2]; - goal_diff[2] = 0; - float goal_xy_dist = VectorNormalize( goal_diff ); - if ( goal_xy_dist < 550 && goal_z_diff > -400/*was -256*/ )//for now, jedi don't take falling damage && (NPC->health > 20 || goal_z_diff > 0 ) && (NPC->health >= 100 || goal_z_diff > -128 ))//closer than @512 + if ( TIMER_Done( NPC, "jumpChaseDebounce" ) ) + { + if ( (!goal->client || goal->client->ps.groundEntityNum != ENTITYNUM_NONE) ) { - if ( NPC->health < 150 && ((NPC->health < 30 && goal_z_diff < 0) || goal_z_diff < -128 ) ) - {//don't jump, just walk off... doesn't help with ledges, though - } - else if ( goal_z_diff < 32 && goal_xy_dist < 200 ) - {//what is their ideal jump height? - ucmd.upmove = 127; - } - else - { - /* - //NO! All Jedi can jump-navigate now... - if ( NPCInfo->rank != RANK_CREWMAN && NPCInfo->rank <= RANK_LT_JG ) - {//can't do acrobatics - return qfalse; - } - */ - if ( goal_z_diff > 0 || goal_xy_dist > 128 ) - {//Fake a force-jump - //Screw it, just do my own calc & throw - vec3_t dest; - VectorCopy( goal->currentOrigin, dest ); - if ( goal == NPC->enemy ) - { - int sideTry = 0; - while( sideTry < 10 ) - {//FIXME: make it so it doesn't try the same spot again? - if ( Q_irand( 0, 1 ) ) - { - dest[0] += NPC->enemy->maxs[0]*1.25; - } - else - { - dest[0] += NPC->enemy->mins[0]*1.25; - } - if ( Q_irand( 0, 1 ) ) - { - dest[1] += NPC->enemy->maxs[1]*1.25; - } - else - { - dest[1] += NPC->enemy->mins[1]*1.25; - } - trace_t trace; - vec3_t bottom; - VectorCopy( dest, bottom ); - bottom[2] -= 128; - gi.trace( &trace, dest, NPC->mins, NPC->maxs, bottom, goal->s.number, NPC->clipmask ); - if ( trace.fraction < 1.0f ) - {//hit floor, okay to land here - break; - } - sideTry++; - } - if ( sideTry >= 10 ) - {//screw it, just jump right at him? - VectorCopy( goal->currentOrigin, dest ); - } + if ( !PM_InKnockDown( &NPC->client->ps ) && !PM_InRoll( &NPC->client->ps ) ) + {//enemy is on terra firma + vec3_t goal_diff; + float goal_z_diff; + VectorSubtract( goal->currentOrigin, NPC->currentOrigin, goal_diff ); + goal_z_diff = goal_diff[2]; + goal_diff[2] = 0; + float goal_xy_dist = VectorNormalize( goal_diff ); + if ( goal_xy_dist < 550 && goal_z_diff > -400/*was -256*/ )//for now, jedi don't take falling damage && (NPC->health > 20 || goal_z_diff > 0 ) && (NPC->health >= 100 || goal_z_diff > -128 ))//closer than @512 + { + qboolean debounce = qfalse; + if ( NPC->health < 150 && ((NPC->health < 30 && goal_z_diff < 0) || goal_z_diff < -128 ) ) + {//don't jump, just walk off... doesn't help with ledges, though + debounce = qtrue; } - if ( Jedi_Jump( dest, goal->s.number ) ) + else if ( goal_z_diff < 32 && goal_xy_dist < 200 ) + {//what is their ideal jump height? + ucmd.upmove = 127; + debounce = qtrue; + } + else { - //gi.Printf( "(%d) pre-checked force jump\n", level.time ); - - //FIXME: store the dir we;re going in in case something gets in the way of the jump? - //? = vectoyaw( NPC->client->ps.velocity ); /* - if ( NPC->client->ps.velocity[2] < 320 ) - { - NPC->client->ps.velocity[2] = 320; + //NO! All Jedi can jump-navigate now... + if ( NPCInfo->rank != RANK_CREWMAN && NPCInfo->rank <= RANK_LT_JG ) + {//can't do acrobatics + return qfalse; } - else */ - {//FIXME: make this a function call - int jumpAnim; - //FIXME: this should be more intelligent, like the normal force jump anim logic - if ( NPCInfo->rank != RANK_CREWMAN && NPCInfo->rank <= RANK_LT_JG ) - {//can't do acrobatics - jumpAnim = BOTH_FORCEJUMP1; - } - else + if ( goal_z_diff > 0 || goal_xy_dist > 128 ) + {//Fake a force-jump + //Screw it, just do my own calc & throw + vec3_t dest; + VectorCopy( goal->currentOrigin, dest ); + if ( goal == NPC->enemy ) { - jumpAnim = BOTH_FLIP_F; + int sideTry = 0; + while( sideTry < 10 ) + {//FIXME: make it so it doesn't try the same spot again? + if ( Q_irand( 0, 1 ) ) + { + dest[0] += NPC->enemy->maxs[0]*1.25; + } + else + { + dest[0] += NPC->enemy->mins[0]*1.25; + } + if ( Q_irand( 0, 1 ) ) + { + dest[1] += NPC->enemy->maxs[1]*1.25; + } + else + { + dest[1] += NPC->enemy->mins[1]*1.25; + } + trace_t trace; + vec3_t bottom; + VectorCopy( dest, bottom ); + bottom[2] -= 128; + gi.trace( &trace, dest, NPC->mins, NPC->maxs, bottom, goal->s.number, NPC->clipmask ); + if ( trace.fraction < 1.0f ) + {//hit floor, okay to land here + break; + } + sideTry++; + } + if ( sideTry >= 10 ) + {//screw it, just jump right at him? + VectorCopy( goal->currentOrigin, dest ); + } + } + if ( Jedi_Jump( dest, goal->s.number ) ) + { + //gi.Printf( "(%d) pre-checked force jump\n", level.time ); + + //FIXME: store the dir we;re going in in case something gets in the way of the jump? + //? = vectoyaw( NPC->client->ps.velocity ); + /* + if ( NPC->client->ps.velocity[2] < 320 ) + { + NPC->client->ps.velocity[2] = 320; + } + else + */ + {//FIXME: make this a function call + int jumpAnim; + //FIXME: this should be more intelligent, like the normal force jump anim logic + if ( NPCInfo->rank != RANK_CREWMAN && NPCInfo->rank <= RANK_LT_JG ) + {//can't do acrobatics + jumpAnim = BOTH_FORCEJUMP1; + } + else + { + jumpAnim = BOTH_FLIP_F; + } + NPC_SetAnim( NPC, SETANIM_BOTH, jumpAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + } + + NPC->client->ps.forceJumpZStart = NPC->currentOrigin[2]; + NPC->client->ps.pm_flags |= PMF_JUMPING; + + NPC->client->ps.weaponTime = NPC->client->ps.torsoAnimTimer; + NPC->client->ps.forcePowersActive |= ( 1 << FP_LEVITATION ); + G_SoundOnEnt( NPC, CHAN_BODY, "sound/weapons/force/jump.wav" ); + + TIMER_Set( NPC, "forceJumpChasing", Q_irand( 2000, 3000 ) ); + debounce = qtrue; } - NPC_SetAnim( NPC, SETANIM_BOTH, jumpAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); } - - NPC->client->ps.forceJumpZStart = NPC->currentOrigin[2]; - NPC->client->ps.pm_flags |= PMF_JUMPING; - - NPC->client->ps.weaponTime = NPC->client->ps.torsoAnimTimer; - NPC->client->ps.forcePowersActive |= ( 1 << FP_LEVITATION ); - G_SoundOnEnt( NPC, CHAN_BODY, "sound/weapons/force/jump.wav" ); - - TIMER_Set( NPC, "forceJumpChasing", Q_irand( 2000, 3000 ) ); + } + if ( debounce ) + { + //Don't jump again for another 2 to 5 seconds + TIMER_Set( NPC, "jumpChaseDebounce", Q_irand( 2000, 5000 ) ); + ucmd.forwardmove = 127; + VectorClear( NPC->client->ps.moveDir ); + TIMER_Set( NPC, "duck", -level.time ); + return qtrue; } } } - //Don't jump again for another 2 to 5 seconds - TIMER_Set( NPC, "jumpChaseDebounce", Q_irand( 2000, 5000 ) ); - ucmd.forwardmove = 127; - VectorClear( NPC->client->ps.moveDir ); - TIMER_Set( NPC, "duck", -level.time ); - return qtrue; } } return qfalse; @@ -3811,27 +4030,119 @@ static qboolean Jedi_Jumping( gentity_t *goal ) return qfalse; } -static void Jedi_CheckEnemyMovement( void ) +extern void G_UcmdMoveForDir( gentity_t *self, usercmd_t *cmd, vec3_t dir ); +static void Jedi_CheckEnemyMovement( float enemy_dist ) { if ( !NPC->enemy || !NPC->enemy->client ) { return; } - if ( NPC->enemy->enemy && NPC->enemy->enemy == NPC ) - {//enemy is mad at *me* - if ( NPC->enemy->client->ps.legsAnim == BOTH_JUMPFLIPSLASHDOWN1 || - NPC->enemy->client->ps.legsAnim == BOTH_JUMPFLIPSTABDOWN ) - {//enemy is flipping over me - if ( Q_irand( 0, NPCInfo->rank ) < RANK_LT ) - {//be nice and stand still for him... - ucmd.forwardmove = ucmd.rightmove = ucmd.upmove = 0; - NPC->client->ps.forceJumpCharge = 0; - TIMER_Set( NPC, "strafeLeft", -1 ); - TIMER_Set( NPC, "strafeRight", -1 ); - TIMER_Set( NPC, "noStrafe", Q_irand( 500, 1000 ) ); - TIMER_Set( NPC, "movenone", Q_irand( 500, 1000 ) ); - TIMER_Set( NPC, "movecenter", Q_irand( 500, 1000 ) ); + if ( NPC->client->NPC_class != CLASS_TAVION + && NPC->client->NPC_class != CLASS_DESANN + && NPC->client->NPC_class != CLASS_LUKE ) + { + if ( NPC->enemy->enemy && NPC->enemy->enemy == NPC ) + {//enemy is mad at *me* + if ( NPC->enemy->client->ps.legsAnim == BOTH_JUMPFLIPSLASHDOWN1 || + NPC->enemy->client->ps.legsAnim == BOTH_JUMPFLIPSTABDOWN ) + {//enemy is flipping over me + if ( Q_irand( 0, NPCInfo->rank ) < RANK_LT ) + {//be nice and stand still for him... + ucmd.forwardmove = ucmd.rightmove = ucmd.upmove = 0; + VectorClear( NPC->client->ps.moveDir ); + NPC->client->ps.forceJumpCharge = 0; + TIMER_Set( NPC, "strafeLeft", -1 ); + TIMER_Set( NPC, "strafeRight", -1 ); + TIMER_Set( NPC, "noStrafe", Q_irand( 500, 1000 ) ); + TIMER_Set( NPC, "movenone", Q_irand( 500, 1000 ) ); + TIMER_Set( NPC, "movecenter", Q_irand( 500, 1000 ) ); + } + } + else if ( NPC->enemy->client->ps.legsAnim == BOTH_WALL_FLIP_BACK1 + || NPC->enemy->client->ps.legsAnim == BOTH_WALL_FLIP_RIGHT + || NPC->enemy->client->ps.legsAnim == BOTH_WALL_FLIP_LEFT + || NPC->enemy->client->ps.legsAnim == BOTH_WALL_RUN_LEFT_FLIP + || NPC->enemy->client->ps.legsAnim == BOTH_WALL_RUN_RIGHT_FLIP ) + {//he's flipping off a wall + if ( NPC->enemy->client->ps.groundEntityNum == ENTITYNUM_NONE ) + {//still in air + if ( enemy_dist < 256 ) + {//close + if ( Q_irand( 0, NPCInfo->rank ) < RANK_LT ) + {//be nice and stand still for him... + /* + ucmd.forwardmove = ucmd.rightmove = ucmd.upmove = 0; + VectorClear( NPC->client->ps.moveDir ); + NPC->client->ps.forceJumpCharge = 0; + TIMER_Set( NPC, "strafeLeft", -1 ); + TIMER_Set( NPC, "strafeRight", -1 ); + TIMER_Set( NPC, "noStrafe", Q_irand( 500, 1000 ) ); + TIMER_Set( NPC, "movenone", Q_irand( 500, 1000 ) ); + TIMER_Set( NPC, "movecenter", Q_irand( 500, 1000 ) ); + TIMER_Set( NPC, "noturn", Q_irand( 200, 500 ) ); + */ + //stop current movement + ucmd.forwardmove = ucmd.rightmove = ucmd.upmove = 0; + VectorClear( NPC->client->ps.moveDir ); + NPC->client->ps.forceJumpCharge = 0; + TIMER_Set( NPC, "strafeLeft", -1 ); + TIMER_Set( NPC, "strafeRight", -1 ); + TIMER_Set( NPC, "noStrafe", Q_irand( 500, 1000 ) ); + TIMER_Set( NPC, "noturn", Q_irand( 250, 500 )*(3-g_spskill->integer) ); + + vec3_t enemyFwd, dest, dir; + + VectorCopy( NPC->enemy->client->ps.velocity, enemyFwd ); + VectorNormalize( enemyFwd ); + VectorMA( NPC->enemy->currentOrigin, -64, enemyFwd, dest ); + VectorSubtract( dest, NPC->currentOrigin, dir ); + if ( VectorNormalize( dir ) > 32 ) + { + G_UcmdMoveForDir( NPC, &ucmd, dir ); + } + else + { + TIMER_Set( NPC, "movenone", Q_irand( 500, 1000 ) ); + TIMER_Set( NPC, "movecenter", Q_irand( 500, 1000 ) ); + } + } + } + } + } + else if ( NPC->enemy->client->ps.legsAnim == BOTH_A2_STABBACK1 ) + {//he's stabbing backwards + if ( enemy_dist < 256 && enemy_dist > 64 ) + {//close + if ( !InFront( NPC->currentOrigin, NPC->enemy->currentOrigin, NPC->enemy->currentAngles, 0.0f ) ) + {//behind him + if ( !Q_irand( 0, NPCInfo->rank ) ) + {//be nice and stand still for him... + //stop current movement + ucmd.forwardmove = ucmd.rightmove = ucmd.upmove = 0; + VectorClear( NPC->client->ps.moveDir ); + NPC->client->ps.forceJumpCharge = 0; + TIMER_Set( NPC, "strafeLeft", -1 ); + TIMER_Set( NPC, "strafeRight", -1 ); + TIMER_Set( NPC, "noStrafe", Q_irand( 500, 1000 ) ); + + vec3_t enemyFwd, dest, dir; + + AngleVectors( NPC->enemy->currentAngles, enemyFwd, NULL, NULL ); + VectorMA( NPC->enemy->currentOrigin, -32, enemyFwd, dest ); + VectorSubtract( dest, NPC->currentOrigin, dir ); + if ( VectorNormalize( dir ) > 64 ) + { + G_UcmdMoveForDir( NPC, &ucmd, dir ); + } + else + { + TIMER_Set( NPC, "movenone", Q_irand( 500, 1000 ) ); + TIMER_Set( NPC, "movecenter", Q_irand( 500, 1000 ) ); + } + } + } + } } } } @@ -4077,7 +4388,10 @@ static void Jedi_Combat( void ) } //Turn to face the enemy - Jedi_FaceEnemy( qtrue ); + if ( TIMER_Done( NPC, "noturn" ) ) + { + Jedi_FaceEnemy( qtrue ); + } NPC_UpdateAngles( qtrue, qtrue ); //Check for evasion @@ -4119,7 +4433,7 @@ static void Jedi_Combat( void ) } //Check for certain enemy special moves - Jedi_CheckEnemyMovement(); + Jedi_CheckEnemyMovement( enemy_dist ); //Make sure that we don't jump off ledges over long drops Jedi_CheckJumps(); //Just make sure we don't strafe into walls or off cliffs @@ -4160,15 +4474,15 @@ void NPC_Jedi_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, vec TIMER_Set( self, "parryTime", -1 ); if ( self->client->NPC_class == CLASS_DESANN ) {//less for Desann - self->client->ps.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + (3-g_spskill->integer)*100; + self->client->ps.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + (3-g_spskill->integer)*50; } else if ( self->NPC->rank >= RANK_LT_JG ) { - self->client->ps.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + (3-g_spskill->integer)*300; + self->client->ps.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + (3-g_spskill->integer)*100;//300 } else { - self->client->ps.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + (3-g_spskill->integer)*500; + self->client->ps.forcePowerDebounce[FP_SABER_DEFENSE] = level.time + (3-g_spskill->integer)*200;//500 } if ( !Q_irand( 0, 3 ) ) {//ouch... maybe switch up which saber power level we're using @@ -4583,6 +4897,22 @@ void NPC_BSJedi_FollowLeader( void ) } } } + if ( NPCInfo->aiFlags & NPCAI_BLOCKED ) + {//try to jump to the blockedDest + if ( fabs(NPCInfo->blockedDest[2]-NPC->currentOrigin[2]) > 64 ) + { + gentity_t *tempGoal = G_Spawn();//ugh, this is NOT good...? + G_SetOrigin( tempGoal, NPCInfo->blockedDest ); + gi.linkentity( tempGoal ); + TIMER_Set( NPC, "jumpChaseDebounce", -1 ); + if ( Jedi_TryJump( tempGoal ) ) + {//going to jump to the dest + G_FreeEntity( tempGoal ); + return; + } + G_FreeEntity( tempGoal ); + } + } } //try normal movement NPC_BSFollowLeader(); @@ -4618,10 +4948,45 @@ static void Jedi_Attack( void ) ForceThrow( NPC, qfalse ); } //based on my skill, hit attack button every other to every several frames in order to push enemy back - else if ( Q_flrand( -2.0f, (float)(NPCInfo->rank)/2.0f+g_spskill->value ) >= 0.0f - && !(NPC->client->ps.pm_flags&PMF_ATTACK_HELD) ) + else { - ucmd.buttons |= BUTTON_ATTACK; + float chance; + + if ( NPC->client->NPC_class == CLASS_DESANN ) + { + if ( g_spskill->integer ) + { + chance = 4.0f;//he pushes *hard* + } + else + { + chance = 3.0f;//he pushes *hard* + } + } + else if ( NPC->client->NPC_class == CLASS_TAVION ) + { + chance = 2.0f+g_spskill->value;//from 2 to 4 + } + else + {//the escalation in difficulty is nice, here, but cap it so it doesn't get *impossible* on hard + float maxChance = (float)(RANK_LT)/2.0f+3.0f;//5? + if ( !g_spskill->value ) + { + chance = (float)(NPCInfo->rank)/2.0f; + } + else + { + chance = (float)(NPCInfo->rank)/2.0f+1.0f; + } + if ( chance > maxChance ) + { + chance = maxChance; + } + } + if ( Q_flrand( -4.0f, chance ) >= 0.0f && !(NPC->client->ps.pm_flags&PMF_ATTACK_HELD) ) + { + ucmd.buttons |= BUTTON_ATTACK; + } } NPC_UpdateAngles( qtrue, qtrue ); return; @@ -4770,7 +5135,8 @@ static void Jedi_Attack( void ) ucmd.buttons &= ~BUTTON_ATTACK; } - if( NPCInfo->scriptFlags & SCF_DONT_FIRE ) + if( (NPCInfo->scriptFlags&SCF_DONT_FIRE) //not allowed to attack + || ((NPC->client->ps.saberEventFlags&SEF_INWATER)&&!NPC->client->ps.saberInFlight) )//saber in water { ucmd.buttons &= ~(BUTTON_ATTACK|BUTTON_ALT_ATTACK); } @@ -4793,16 +5159,30 @@ static void Jedi_Attack( void ) } } - if ( NPC->client->NPC_class == CLASS_TAVION ) + if ( NPC->client->NPC_class == CLASS_TAVION + || (NPC->client->NPC_class == CLASS_DESANN&&g_spskill->integer) ) {//Tavion will kick in force speed if the player does... if ( NPC->enemy && !NPC->enemy->s.number && NPC->enemy->client && (NPC->enemy->client->ps.forcePowersActive & (1<client->ps.forcePowersActive & (1<client->ps.forcePowersActive & (1<integer ) + { + case 0: + chance = 9; + case 1: + chance = 3; + case 2: + chance = 1; + break; + } + if ( !Q_irand( 0, chance ) ) + { + ForceSpeed( NPC ); + } } } } diff --git a/code/game/AI_Mark1.cpp b/code/game/AI_Mark1.cpp index 629276c..21616c7 100644 --- a/code/game/AI_Mark1.cpp +++ b/code/game/AI_Mark1.cpp @@ -49,32 +49,28 @@ NPC_Mark1_Precache */ void NPC_Mark1_Precache(void) { - G_SoundIndex( "sound/chars/mark1/misc/wakeup.wav"); - G_SoundIndex( "sound/chars/mark1/misc/shutdown.wav"); - G_SoundIndex( "sound/chars/mark1/misc/walk.wav"); - G_SoundIndex( "sound/chars/mark1/misc/run.wav"); - G_SoundIndex( "sound/chars/mark1/misc/talk1.wav"); - G_SoundIndex( "sound/chars/mark1/misc/talk2.wav"); - G_SoundIndex( "sound/chars/mark1/misc/talk3.wav"); - G_SoundIndex( "sound/chars/mark1/misc/talk4.wav"); - G_SoundIndex( "sound/chars/mark1/misc/pain01.wav"); - G_SoundIndex( "sound/chars/mark1/misc/pain02.wav"); - G_SoundIndex( "sound/chars/mark1/misc/death1.wav"); - G_SoundIndex( "sound/chars/mark1/misc/death2.wav"); - G_SoundIndex( "sound/chars/mark1/misc/anger.wav"); - G_SoundIndex( "sound/chars/mark1/misc/shoot1.wav"); - G_SoundIndex( "sound/chars/mark1/misc/shoot2.wav"); - G_SoundIndex( "sound/chars/mark1/misc/shoot3.wav"); + G_SoundIndex( "sound/chars/mark1/misc/mark1_wakeup"); + G_SoundIndex( "sound/chars/mark1/misc/shutdown"); + G_SoundIndex( "sound/chars/mark1/misc/walk"); + G_SoundIndex( "sound/chars/mark1/misc/run"); + G_SoundIndex( "sound/chars/mark1/misc/death1"); + G_SoundIndex( "sound/chars/mark1/misc/death2"); + G_SoundIndex( "sound/chars/mark1/misc/anger"); + G_SoundIndex( "sound/chars/mark1/misc/mark1_fire"); + G_SoundIndex( "sound/chars/mark1/misc/mark1_pain"); + G_SoundIndex( "sound/chars/mark1/misc/mark1_explo"); - G_EffectIndex( "small_chunks"); - G_EffectIndex( "mouseexplosion1"); +// G_EffectIndex( "small_chunks"); + G_EffectIndex( "env/med_explode2"); G_EffectIndex( "probeexplosion1"); G_EffectIndex( "blaster/smoke_bolton"); G_EffectIndex( "bryar/muzzle_flash"); G_EffectIndex( "droidexplosion1" ); RegisterItem( FindItemForAmmo( AMMO_METAL_BOLTS)); - RegisterItem( FindItemForAmmo( AMMO_POWERCELL )); + RegisterItem( FindItemForAmmo( AMMO_BLASTER )); + RegisterItem( FindItemForWeapon( WP_BOWCASTER )); + RegisterItem( FindItemForWeapon( WP_BRYAR_PISTOL )); } /* @@ -82,11 +78,25 @@ void NPC_Mark1_Precache(void) NPC_Mark1_Part_Explode ------------------------- */ -void NPC_Mark1_Part_Explode(gentity_t *self,int bolt) +void NPC_Mark1_Part_Explode( gentity_t *self, int bolt ) { - G_PlayEffect( "small_chunks", self->playerModel, bolt, self->s.number); - G_PlayEffect( "mouseexplosion1", self->playerModel, bolt, self->s.number); - G_PlayEffect( "blaster/smoke_bolton", self->playerModel, bolt, self->s.number); + if ( bolt >=0 ) + { + mdxaBone_t boltMatrix; + vec3_t org, dir; + + gi.G2API_GetBoltMatrix( self->ghoul2, self->playerModel, + bolt, + &boltMatrix, self->currentAngles, self->currentOrigin, (cg.time?cg.time:level.time), + NULL, self->s.modelScale ); + + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org ); + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, dir ); + + G_PlayEffect( "env/med_explode2", org, dir ); + } + + G_PlayEffect( "blaster/smoke_bolton", self->playerModel, bolt, self->s.number ); } /* @@ -123,9 +133,9 @@ void Mark1Dead_FireRocket (void) gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, muzzle1 ); gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, muzzle_dir ); -// G_PlayEffect( "blaster/muzzle_flash", muzzle1 ); + G_PlayEffect( "bryar/muzzle_flash", muzzle1, muzzle_dir ); - G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/shoot2.wav")); + G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/mark1_fire")); gentity_t *missile = CreateMissile( muzzle1, muzzle_dir, BOWCASTER_VELOCITY, 10000, NPC ); @@ -174,7 +184,7 @@ void Mark1Dead_FireBlaster (void) missile = CreateMissile( muzzle1, muzzle_dir, 1600, 10000, NPC ); - G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/shoot1.wav")); + G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/mark1_fire")); missile->classname = "bryar_proj"; missile->s.weapon = WP_BRYAR_PISTOL; @@ -193,6 +203,7 @@ Mark1_die */ void Mark1_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod,int dFlags,int hitLoc ) { + /* int anim; // Is he dead already? @@ -205,10 +216,13 @@ void Mark1_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int DeathFX(self); self->client->ps.eFlags |= EF_NODRAW; self->contents = CONTENTS_CORPSE; - G_FreeEntity( self ); // Is this safe? I can't see why we'd mark it nodraw and then just leave it around?? + // G_FreeEntity( self ); // Is this safe? I can't see why we'd mark it nodraw and then just leave it around?? + self->e_ThinkFunc = thinkF_G_FreeEntity; + self->nextthink = level.time + FRAMETIME; } return; } + */ G_Sound( self, G_SoundIndex(va("sound/chars/mark1/misc/death%d.wav",Q_irand( 1, 2)))); @@ -304,6 +318,8 @@ void NPC_Mark1_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, ve NPC_Pain( self, inflictor, other, point, damage, mod ); + G_Sound( self, G_SoundIndex("sound/chars/mark1/misc/mark1_pain")); + // Hit in the CHEST??? if (hitLoc==HL_CHEST) { @@ -336,9 +352,8 @@ void NPC_Mark1_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, ve newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*flash4" ); if ( newBolt != -1 ) { - G_PlayEffect( "small_chunks", self->playerModel, self->genericBolt2, self->s.number); - G_PlayEffect( "mouseexplosion1", self->playerModel, self->genericBolt2, self->s.number); - G_PlayEffect( "blaster/smoke_bolton", self->playerModel, newBolt, self->s.number); +// G_PlayEffect( "small_chunks", self->playerModel, self->genericBolt2, self->s.number); + NPC_Mark1_Part_Explode( self, newBolt ); } gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "r_arm", TURN_OFF ); @@ -453,7 +468,7 @@ void Mark1_FireBlaster(void) G_PlayEffect( "bryar/muzzle_flash", muzzle1, forward ); - G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/shoot1.wav")); + G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/mark1_fire")); missile = CreateMissile( muzzle1, forward, 1600, 10000, NPC ); @@ -554,7 +569,7 @@ void Mark1_FireRocket(void) vectoangles ( delta1, angleToEnemy1 ); AngleVectors (angleToEnemy1, forward, vright, up); - G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/shoot2.wav")); + G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/mark1_fire" )); gentity_t *missile = CreateMissile( muzzle1, forward, BOWCASTER_VELOCITY, 10000, NPC ); @@ -609,7 +624,7 @@ void Mark1_AttackDecision( void ) { if (TIMER_Done(NPC,"angerNoise")) { - G_Sound( NPC, G_SoundIndex(va("sound/chars/mark1/misc/talk%d.wav", Q_irand(1, 4)))); +// G_Sound( NPC, G_SoundIndex(va("sound/chars/mark1/misc/talk%d.wav", Q_irand(1, 4)))); TIMER_Set( NPC, "patrolNoise", Q_irand( 4000, 10000 ) ); } } @@ -680,7 +695,7 @@ void Mark1_Patrol( void ) { if ( NPC_CheckPlayerTeamStealth() ) { - G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/anger.wav")); + G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/mark1_wakeup")); NPC_UpdateAngles( qtrue, qtrue ); return; } @@ -696,12 +711,12 @@ void Mark1_Patrol( void ) } //randomly talk - if (TIMER_Done(NPC,"patrolNoise")) - { - G_Sound( NPC, G_SoundIndex(va("sound/chars/mark1/misc/talk%d.wav", Q_irand(1, 4)))); - - TIMER_Set( NPC, "patrolNoise", Q_irand( 2000, 4000 ) ); - } +// if (TIMER_Done(NPC,"patrolNoise")) +// { +// G_Sound( NPC, G_SoundIndex(va("sound/chars/mark1/misc/talk%d.wav", Q_irand(1, 4)))); +// +// TIMER_Set( NPC, "patrolNoise", Q_irand( 2000, 4000 ) ); +// } } } @@ -714,7 +729,7 @@ NPC_BSMark1_Default */ void NPC_BSMark1_Default( void ) { - NPC->e_DieFunc = dieF_Mark1_die; + //NPC->e_DieFunc = dieF_Mark1_die; if ( NPC->enemy ) { diff --git a/code/game/AI_Mark2.cpp b/code/game/AI_Mark2.cpp index 958c751..2fe4171 100644 --- a/code/game/AI_Mark2.cpp +++ b/code/game/AI_Mark2.cpp @@ -15,6 +15,7 @@ #define MIN_DISTANCE 24 #define MIN_DISTANCE_SQR ( MIN_DISTANCE * MIN_DISTANCE ) +extern gitem_t *FindItemForAmmo( ammo_t ammo ); //Local state enums enum @@ -29,13 +30,20 @@ gentity_t *CreateMissile( vec3_t org, vec3_t dir, float vel, int life, gentity_t void NPC_Mark2_Precache( void ) { - G_EffectIndex( "small_chunks" ); + G_SoundIndex( "sound/chars/mark2/misc/mark2_explo" );// blows up on death + G_SoundIndex( "sound/chars/mark2/misc/mark2_pain" ); + G_SoundIndex( "sound/chars/mark2/misc/mark2_fire" ); + G_SoundIndex( "sound/chars/mark2/misc/mark2_move_lp" ); + G_EffectIndex( "droidexplosion1" ); - G_EffectIndex( "mouseexplosion1" ); + G_EffectIndex( "env/med_explode2" ); G_EffectIndex( "blaster/smoke_bolton" ); G_EffectIndex( "bryar/muzzle_flash" ); - G_SoundIndex( "sound/chars/mark1/misc/shoot1.wav" ); + RegisterItem( FindItemForWeapon( WP_BRYAR_PISTOL )); + RegisterItem( FindItemForAmmo( AMMO_METAL_BOLTS)); + RegisterItem( FindItemForAmmo( AMMO_POWERCELL )); + RegisterItem( FindItemForAmmo( AMMO_BLASTER )); } /* @@ -43,10 +51,24 @@ void NPC_Mark2_Precache( void ) NPC_Mark2_Part_Explode ------------------------- */ -void NPC_Mark2_Part_Explode(gentity_t *self,int bolt) +void NPC_Mark2_Part_Explode( gentity_t *self, int bolt ) { - G_PlayEffect( "small_chunks", self->playerModel, bolt, self->s.number); - G_PlayEffect( "mouseexplosion1", self->playerModel, bolt, self->s.number); + if ( bolt >=0 ) + { + mdxaBone_t boltMatrix; + vec3_t org, dir; + + gi.G2API_GetBoltMatrix( self->ghoul2, self->playerModel, + bolt, + &boltMatrix, self->currentAngles, self->currentOrigin, (cg.time?cg.time:level.time), + NULL, self->s.modelScale ); + + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org ); + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, dir ); + + G_PlayEffect( "env/med_explode2", org, dir ); + } + G_PlayEffect( "blaster/smoke_bolton", self->playerModel, bolt, self->s.number); self->count++; // Count of pods blown off @@ -81,6 +103,8 @@ void NPC_Mark2_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, ve } } + G_Sound( self, G_SoundIndex( "sound/chars/mark2/misc/mark2_pain" )); + // If any pods were blown off, kill him if (self->count > 0) { @@ -141,7 +165,7 @@ void Mark2_FireBlaster(qboolean advance) G_PlayEffect( "bryar/muzzle_flash", muzzle1, forward ); - G_Sound( NPC, G_SoundIndex("sound/chars/mark1/misc/shoot1.wav")); + G_Sound( NPC, G_SoundIndex("sound/chars/mark2/misc/mark2_fire")); missile = CreateMissile( muzzle1, forward, 1600, 10000, NPC ); diff --git a/code/game/AI_MineMonster.cpp b/code/game/AI_MineMonster.cpp index 5f0b860..0371d34 100644 --- a/code/game/AI_MineMonster.cpp +++ b/code/game/AI_MineMonster.cpp @@ -138,49 +138,50 @@ void MineMonster_Attack( void ) || random() > 0.8f )) { // Going to do ATTACK4 - TIMER_Set( NPC, "attacking", 2350 + random() * 250 ); + TIMER_Set( NPC, "attacking", 1750 + random() * 200 ); NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK4, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); - TIMER_Set( NPC, "attack2_dmg", 1250 ); // level two damage + TIMER_Set( NPC, "attack2_dmg", 950 ); // level two damage } else if ( random() > 0.5f ) { if ( random() > 0.8f ) { // Going to do ATTACK3, (rare) - TIMER_Set( NPC, "attacking", 1150 ); + TIMER_Set( NPC, "attacking", 850 ); NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK3, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); - TIMER_Set( NPC, "attack2_dmg", 450 ); // level two damage + TIMER_Set( NPC, "attack2_dmg", 400 ); // level two damage } else { // Going to do ATTACK1 - TIMER_Set( NPC, "attacking", 1150 ); + TIMER_Set( NPC, "attacking", 850 ); NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); - TIMER_Set( NPC, "attack1_dmg", 650 ); // level one damage + TIMER_Set( NPC, "attack1_dmg", 450 ); // level one damage } } else { // Going to do ATTACK2 - TIMER_Set( NPC, "attacking", 1700 ); + TIMER_Set( NPC, "attacking", 1250 ); NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_ATTACK2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); - TIMER_Set( NPC, "attack1_dmg", 1050 ); // level one damage + TIMER_Set( NPC, "attack1_dmg", 700 ); // level one damage } } - - // Need to do delayed damage since the attack animations encapsulate multiple mini-attacks - if ( TIMER_Done2( NPC, "attack1_dmg", qtrue )) + else { - MineMonster_TryDamage( NPC->enemy, 5 ); - } - - if ( TIMER_Done2( NPC, "attack2_dmg", qtrue )) - { - MineMonster_TryDamage( NPC->enemy, 10 ); + // Need to do delayed damage since the attack animations encapsulate multiple mini-attacks + if ( TIMER_Done2( NPC, "attack1_dmg", qtrue )) + { + MineMonster_TryDamage( NPC->enemy, 5 ); + } + else if ( TIMER_Done2( NPC, "attack2_dmg", qtrue )) + { + MineMonster_TryDamage( NPC->enemy, 10 ); + } } // Just using this to remove the attacking flag at the right time @@ -237,7 +238,9 @@ void NPC_MineMonster_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *oth if ( damage >= 10 ) { TIMER_Remove( self, "attacking" ); - TIMER_Set( self, "takingPain", 2400 ); + TIMER_Remove( self, "attacking1_dmg" ); + TIMER_Remove( self, "attacking2_dmg" ); + TIMER_Set( self, "takingPain", 1350 ); VectorCopy( self->NPC->lastPathAngles, self->s.angles ); diff --git a/code/game/AI_Remote.cpp b/code/game/AI_Remote.cpp index 66e0d5b..6466a04 100644 --- a/code/game/AI_Remote.cpp +++ b/code/game/AI_Remote.cpp @@ -33,11 +33,12 @@ NPC_Remote_Pain */ void NPC_Remote_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, vec3_t point, int damage, int mod,int hitLoc ) { - NPC = self; - NPCInfo = self->NPC; + SaveNPCGlobals(); + SetNPCGlobals( self ); Remote_Strafe(); - NPC_Pain( self, inflictor, other, point, damage, mod ); + RestoreNPCGlobals(); + NPC_Pain( self, inflictor, other, point, damage, mod ); } /* diff --git a/code/game/AI_Seeker.cpp b/code/game/AI_Seeker.cpp index 9d86818..992cdee 100644 --- a/code/game/AI_Seeker.cpp +++ b/code/game/AI_Seeker.cpp @@ -42,9 +42,10 @@ void NPC_Seeker_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, v G_Damage( self, NULL, NULL, (float*)vec3_origin, (float*)vec3_origin, 999, 0, MOD_FALLING ); } - NPC = self; - NPCInfo = self->NPC; + SaveNPCGlobals(); + SetNPCGlobals( self ); Seeker_Strafe(); + RestoreNPCGlobals(); NPC_Pain( self, inflictor, other, point, damage, mod ); } @@ -159,7 +160,7 @@ void Seeker_Strafe( void ) { VectorMA( NPC->client->ps.velocity, SEEKER_STRAFE_VEL * side, right, NPC->client->ps.velocity ); - G_Sound( NPC, G_SoundIndex( "sound/chars/SEEKER/misc/hiss.wav" )); + G_Sound( NPC, G_SoundIndex( "sound/chars/seeker/misc/hiss" )); // Add a slight upward push NPC->client->ps.velocity[2] += SEEKER_UPWARD_PUSH; @@ -191,7 +192,7 @@ void Seeker_Strafe( void ) // Try to move the desired enemy side VectorMA( NPC->client->ps.velocity, dis, dir, NPC->client->ps.velocity ); - G_Sound( NPC, G_SoundIndex( "sound/chars/SEEKER/misc/hiss.wav" )); + G_Sound( NPC, G_SoundIndex( "sound/chars/seeker/misc/hiss" )); // Add a slight upward push NPC->client->ps.velocity[2] += SEEKER_UPWARD_PUSH; @@ -290,9 +291,10 @@ void Seeker_Ranged( qboolean visible, qboolean advance ) else { // out of ammo, so let it die...give it a push up so it can fall more and blow up on impact - NPC->client->ps.gravity = 900; - NPC->svFlags &= ~SVF_CUSTOM_GRAVITY; - NPC->client->ps.velocity[2] += 16; +// NPC->client->ps.gravity = 900; +// NPC->svFlags &= ~SVF_CUSTOM_GRAVITY; +// NPC->client->ps.velocity[2] += 16; + G_Damage( NPC, NPC, NPC, NULL, NULL, 999, 0, MOD_UNKNOWN ); } if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES ) @@ -370,7 +372,7 @@ void Seeker_FindEnemy( void ) if ( best ) { // used to offset seekers around a circle so they don't occupy the same spot. This is not a fool-proof method. - NPC->random = random() * 6.2f; // roughly 2pi + NPC->random = random() * 6.3f; // roughly 2pi NPC->enemy = best; } @@ -396,6 +398,12 @@ void Seeker_FollowPlayer( void ) } else { + if ( TIMER_Done( NPC, "seekerhiss" )) + { + TIMER_Set( NPC, "seekerhiss", 1000 + random() * 1000 ); + G_Sound( NPC, G_SoundIndex( "sound/chars/seeker/misc/hiss" )); + } + // Hey come back! NPCInfo->goalEntity = &g_entities[0]; NPCInfo->goalRadius = 32; @@ -416,10 +424,16 @@ void Seeker_FollowPlayer( void ) //------------------------------------ void NPC_BSSeeker_Default( void ) { + if ( in_camera ) + { + // cameras make me commit suicide.... + G_Damage( NPC, NPC, NPC, NULL, NULL, 999, 0, MOD_UNKNOWN ); + } + if ( NPC->random == 0.0f ) { // used to offset seekers around a circle so they don't occupy the same spot. This is not a fool-proof method. - NPC->random = random() * 6.4f; // roughly 2pi + NPC->random = random() * 6.3f; // roughly 2pi } if ( NPC->enemy && NPC->enemy->health && NPC->enemy->inuse ) diff --git a/code/game/AI_Sentry.cpp b/code/game/AI_Sentry.cpp index eef0060..d7d5995 100644 --- a/code/game/AI_Sentry.cpp +++ b/code/game/AI_Sentry.cpp @@ -7,6 +7,7 @@ gentity_t *CreateMissile( vec3_t org, vec3_t dir, float vel, int life, gentity_t *owner, qboolean altFire = qfalse ); extern gitem_t *FindItemForAmmo( ammo_t ammo ); +extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); #define MIN_DISTANCE 256 #define MIN_DISTANCE_SQR ( MIN_DISTANCE * MIN_DISTANCE ) @@ -38,18 +39,16 @@ NPC_Sentry_Precache */ void NPC_Sentry_Precache(void) { - G_SoundIndex( "sound/chars/sentry/misc/death.wav" ); - G_SoundIndex( "sound/chars/sentry/misc/sentry_pain.mp3" ); - G_SoundIndex( "sound/chars/sentry/misc/sentry_shield_open.mp3" ); - G_SoundIndex( "sound/chars/sentry/misc/sentry_shield_close.mp3" ); - G_SoundIndex( "sound/chars/sentry/misc/sentry_hover_1_lp.wav" ); - G_SoundIndex( "sound/chars/sentry/misc/sentry_hover_2_lp.wav" ); - -// G_SoundIndex( "sound/chars/sentry/misc/shoot.wav"); + G_SoundIndex( "sound/chars/sentry/misc/sentry_explo" ); + G_SoundIndex( "sound/chars/sentry/misc/sentry_pain" ); + G_SoundIndex( "sound/chars/sentry/misc/sentry_shield_open" ); + G_SoundIndex( "sound/chars/sentry/misc/sentry_shield_close" ); + G_SoundIndex( "sound/chars/sentry/misc/sentry_hover_1_lp" ); + G_SoundIndex( "sound/chars/sentry/misc/sentry_hover_2_lp" ); for ( int i = 1; i < 4; i++) { - G_SoundIndex( va( "sound/chars/sentry/misc/talk%d.wav", i ) ); + G_SoundIndex( va( "sound/chars/sentry/misc/talk%d", i ) ); } G_EffectIndex( "bryar/muzzle_flash"); @@ -88,7 +87,7 @@ void NPC_Sentry_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, v TIMER_Set( self, "attackDelay", Q_irand( 9000, 12000) ); self->flags |= FL_SHIELDED; NPC_SetAnim( self, SETANIM_BOTH, BOTH_FLY_SHIELDED, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - G_Sound( NPC, G_SoundIndex( "sound/chars/misc/sentry/sentry_pain.mp3" )); + G_SoundOnEnt( self, CHAN_AUTO, "sound/chars/sentry/misc/sentry_pain" ); self->NPC->localState = LSTATE_ACTIVE; } @@ -136,7 +135,7 @@ void Sentry_Fire (void) { NPCInfo->localState = LSTATE_POWERING_UP; - G_Sound( NPC, G_SoundIndex( "sound/chars/sentry/misc/sentry_shield_open.mp3" )); + G_SoundOnEnt( NPC, CHAN_AUTO, "sound/chars/sentry/misc/sentry_shield_open" ); NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_POWERUP1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); TIMER_Set( NPC, "powerup", 250 ); return; @@ -210,7 +209,7 @@ void Sentry_MaintainHeight( void ) { float dif; - NPC->s.loopSound = G_SoundIndex( "sound/chars/sentry/misc/sentry_hover_1_lp.wav" ); + NPC->s.loopSound = G_SoundIndex( "sound/chars/sentry/misc/sentry_hover_1_lp" ); // Update our angles regardless NPC_UpdateAngles( qtrue, qtrue ); @@ -420,12 +419,19 @@ void Sentry_RangedAttack( qboolean visible, qboolean advance ) { if ( NPCInfo->burstCount > 6 ) { - NPCInfo->localState = LSTATE_ACTIVE; - NPCInfo->burstCount = 0; - TIMER_Set( NPC, "attackDelay", Q_irand( 2000, 3500) ); - NPC->flags |= FL_SHIELDED; - NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_FLY_SHIELDED, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - G_Sound( NPC, G_SoundIndex( "sound/chars/sentry/misc/sentry_shield_close.mp3" )); + if ( !NPC->fly_sound_debounce_time ) + {//delay closing down to give the player an opening + NPC->fly_sound_debounce_time = level.time + Q_irand( 500, 2000 ); + } + else if ( NPC->fly_sound_debounce_time < level.time ) + { + NPCInfo->localState = LSTATE_ACTIVE; + NPC->fly_sound_debounce_time = NPCInfo->burstCount = 0; + TIMER_Set( NPC, "attackDelay", Q_irand( 2000, 3500) ); + NPC->flags |= FL_SHIELDED; + NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_FLY_SHIELDED, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + G_SoundOnEnt( NPC, CHAN_AUTO, "sound/chars/sentry/misc/sentry_shield_close" ); + } } else { @@ -449,14 +455,14 @@ void Sentry_AttackDecision( void ) // Always keep a good height off the ground Sentry_MaintainHeight(); - NPC->s.loopSound = G_SoundIndex( "sound/chars/sentry/misc/sentry_hover_2_lp.wav" ); + NPC->s.loopSound = G_SoundIndex( "sound/chars/sentry/misc/sentry_hover_2_lp" ); //randomly talk if ( TIMER_Done(NPC,"patrolNoise") ) { if (TIMER_Done(NPC,"angerNoise")) { - G_Sound( NPC, G_SoundIndex(va("sound/chars/sentry/misc/talk%d.wav", Q_irand(1, 3)))); + G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/sentry/misc/talk%d", Q_irand(1, 3)) ); TIMER_Set( NPC, "patrolNoise", Q_irand( 4000, 10000 ) ); } @@ -528,7 +534,7 @@ void NPC_Sentry_Patrol( void ) //randomly talk if (TIMER_Done(NPC,"patrolNoise")) { - G_Sound( NPC, G_SoundIndex(va("sound/chars/sentry/misc/talk%d.wav", Q_irand(1, 3)))); + G_SoundOnEnt( NPC, CHAN_AUTO, va("sound/chars/sentry/misc/talk%d", Q_irand(1, 3)) ); TIMER_Set( NPC, "patrolNoise", Q_irand( 2000, 4000 ) ); } diff --git a/code/game/AI_Sniper.cpp b/code/game/AI_Sniper.cpp index eaa67bb..144c055 100644 --- a/code/game/AI_Sniper.cpp +++ b/code/game/AI_Sniper.cpp @@ -207,7 +207,7 @@ void NPC_BSSniper_Patrol( void ) if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) ) { //Is there danger nearby - int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, qfalse, AEL_SUSPICIOUS ); + int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_SUSPICIOUS ); if ( NPC_CheckForDanger( alertEvent ) ) { NPC_UpdateAngles( qtrue, qtrue ); @@ -461,22 +461,24 @@ static void Sniper_CheckFireState( void ) //continue to fire on their last position if ( !Q_irand( 0, 1 ) && NPCInfo->enemyLastSeenTime && level.time - NPCInfo->enemyLastSeenTime < ((5-NPCInfo->stats.aim)*1000) )//FIXME: incorporate skill too? { - //Fire on the last known position - vec3_t muzzle, dir, angles; + if ( !VectorCompare( vec3_origin, NPCInfo->enemyLastSeenLocation ) ) + { + //Fire on the last known position + vec3_t muzzle, dir, angles; - CalcEntitySpot( NPC, SPOT_WEAPON, muzzle ); - VectorSubtract( NPCInfo->enemyLastSeenLocation, muzzle, dir ); + CalcEntitySpot( NPC, SPOT_WEAPON, muzzle ); + VectorSubtract( NPCInfo->enemyLastSeenLocation, muzzle, dir ); - VectorNormalize( dir ); + VectorNormalize( dir ); - vectoangles( dir, angles ); + vectoangles( dir, angles ); - NPCInfo->desiredYaw = angles[YAW]; - NPCInfo->desiredPitch = angles[PITCH]; - - shoot = qtrue; - //faceEnemy = qfalse; + NPCInfo->desiredYaw = angles[YAW]; + NPCInfo->desiredPitch = angles[PITCH]; + shoot = qtrue; + //faceEnemy = qfalse; + } return; } else if ( level.time - NPCInfo->enemyLastSeenTime > 10000 ) @@ -651,7 +653,7 @@ void NPC_BSSniper_Attack( void ) return; } - if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, qfalse, AEL_DANGER ) ) ) + if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) ) {//going to run NPC_UpdateAngles( qtrue, qtrue ); return; @@ -668,7 +670,7 @@ void NPC_BSSniper_Attack( void ) faceEnemy = qfalse; shoot = qfalse; enemyDist = DistanceSquared( NPC->currentOrigin, NPC->enemy->currentOrigin ); - if ( enemyDist < 16384 ) + if ( enemyDist < 16384 )//128 squared {//too close, so switch to primary fire if ( NPC->client->ps.weapon == WP_DISRUPTOR ) {//sniping... should be assumed @@ -688,12 +690,27 @@ void NPC_BSSniper_Attack( void ) //FIXME: switch back if he gets far away again? } } + else if ( enemyDist > 65536 )//256 squared + { + if ( NPC->client->ps.weapon == WP_DISRUPTOR ) + {//sniping... should be assumed + if ( !(NPCInfo->scriptFlags&SCF_ALT_FIRE) ) + {//use primary fire + NPCInfo->scriptFlags |= SCF_ALT_FIRE; + //reset fire-timing variables + NPC_ChangeWeapon( WP_DISRUPTOR ); + NPC_UpdateAngles( qtrue, qtrue ); + return; + } + } + } Sniper_UpdateEnemyPos(); //can we see our target? if ( NPC_ClearLOS( NPC->enemy ) )//|| (NPCInfo->stats.aim >= 5 && gi.inPVS( NPC->client->renderInfo.eyePoint, NPC->enemy->currentOrigin )) ) { NPCInfo->enemyLastSeenTime = level.time; + VectorCopy( NPC->enemy->currentOrigin, NPCInfo->enemyLastSeenLocation ); enemyLOS = qtrue; float maxShootDist = NPC_MaxDistSquaredForWeapon(); if ( enemyDist < maxShootDist ) @@ -709,7 +726,6 @@ void NPC_BSSniper_Attack( void ) //can we shoot our target? if ( Sniper_EvaluateShot( hit ) ) { - VectorCopy( NPC->enemy->currentOrigin, NPCInfo->enemyLastSeenLocation ); enemyCS = qtrue; } } @@ -770,6 +786,20 @@ void NPC_BSSniper_Attack( void ) TIMER_Set( NPC, "duck", -1 ); } + if ( TIMER_Done( NPC, "duck" ) + && TIMER_Done( NPC, "watch" ) + && (TIMER_Get( NPC, "attackDelay" )-level.time) > 1000 + && NPC->attackDebounceTime < level.time ) + { + if ( enemyLOS && (NPCInfo->scriptFlags&SCF_ALT_FIRE) ) + { + if ( NPC->fly_sound_debounce_time < level.time ) + { + NPC->fly_sound_debounce_time = level.time + 2000; + } + } + } + if ( !faceEnemy ) {//we want to face in the dir we're running if ( move ) @@ -796,6 +826,10 @@ void NPC_BSSniper_Attack( void ) if ( TIMER_Done( NPC, "attackDelay" ) ) { WeaponThink( qtrue ); + if ( ucmd.buttons&(BUTTON_ATTACK|BUTTON_ALT_ATTACK) ) + { + G_SoundOnEnt( NPC, CHAN_WEAPON, "sound/null.wav" ); + } //took a shot, now hide if ( !(NPC->spawnflags&SPF_NO_HIDE) && !Q_irand( 0, 1 ) ) diff --git a/code/game/AI_Stormtrooper.cpp b/code/game/AI_Stormtrooper.cpp index 6f637c2..4d02fe5 100644 --- a/code/game/AI_Stormtrooper.cpp +++ b/code/game/AI_Stormtrooper.cpp @@ -145,6 +145,15 @@ static void ST_Speech( gentity_t *self, int speechType, float failChance ) { return; } + /* + else if ( !self->NPC->group->enemy ) + { + if ( groupSpeechDebounceTime[self->client->playerTeam] > level.time ) + { + return; + } + } + */ } else if ( !TIMER_Done( self, "chatter" ) ) {//personal timer @@ -165,8 +174,8 @@ static void ST_Speech( gentity_t *self, int speechType, float failChance ) else { TIMER_Set( self, "chatter", Q_irand( 2000, 4000 ) ); - groupSpeechDebounceTime[self->client->playerTeam] = level.time + Q_irand( 1000, 2000 ); } + groupSpeechDebounceTime[self->client->playerTeam] = level.time + Q_irand( 2000, 4000 ); if ( self->NPC->blockedSpeechDebounceTime > level.time ) { @@ -179,7 +188,7 @@ static void ST_Speech( gentity_t *self, int speechType, float failChance ) G_AddVoiceEvent( self, Q_irand(EV_CHASE1, EV_CHASE3), 2000 ); break; case SPEECH_CONFUSED: - G_AddVoiceEvent( self, Q_irand(EV_CONFUSE1, EV_CONFUSE2), 2000 ); + G_AddVoiceEvent( self, Q_irand(EV_CONFUSE1, EV_CONFUSE3), 2000 ); break; case SPEECH_COVER: G_AddVoiceEvent( self, Q_irand(EV_COVER1, EV_COVER5), 2000 ); @@ -224,35 +233,6 @@ static void ST_Speech( gentity_t *self, int speechType, float failChance ) self->NPC->blockedSpeechDebounceTime = level.time + 2000; } -void NPC_ST_PlayConfusionSound( gentity_t *self ) -{ - if ( self->health > 0 ) - { - if ( self->enemy ||//was mad - !TIMER_Done( self, "enemyLastVisible" ) ||//saw something suspicious - self->client->renderInfo.lookTarget == 0//was looking at player - ) - { - self->NPC->blockedSpeechDebounceTime = 0;//make sure we say this - G_AddVoiceEvent( self, EV_CONFUSE2, 2000 ); - } - else if ( self->NPC && self->NPC->investigateDebounceTime+self->NPC->pauseTime > level.time )//was checking something out - { - self->NPC->blockedSpeechDebounceTime = 0;//make sure we say this - G_AddVoiceEvent( self, EV_CONFUSE1, 2000 ); - } - //G_AddVoiceEvent( self, Q_irand(EV_CONFUSE1, EV_CONFUSE3), 2000 ); - } - //reset him to be totally unaware again - TIMER_Set( self, "enemyLastVisible", 0 ); - self->NPC->tempBehavior = BS_DEFAULT; - - //self->NPC->behaviorState = BS_PATROL; - G_ClearEnemy( self );//FIXME: or just self->enemy = NULL;? - - self->NPC->investigateCount = 0; -} - void ST_MarkToCover( gentity_t *self ) { if ( !self || !self->NPC ) @@ -544,7 +524,7 @@ qboolean NPC_CheckEnemyStealth( gentity_t *target ) if ( InFOV( target, NPC, NPCInfo->stats.hfov, NPCInfo->stats.vfov ) == qfalse ) return qfalse; - qboolean clearLOS = ( target->client->ps.leanofs ) ? NPC_ClearLOS( target->currentOrigin ) : NPC_ClearLOS( target ); + qboolean clearLOS = ( target->client->ps.leanofs ) ? NPC_ClearLOS( target->client->renderInfo.eyePoint ) : NPC_ClearLOS( target ); //Now check for clear line of vision if ( clearLOS ) @@ -968,6 +948,9 @@ NPC_BSST_Investigate void NPC_BSST_Investigate( void ) { + //get group- mainly for group speech debouncing, but may use for group scouting/investigating AI, too + AI_GetGroup( NPC ); + if( NPCInfo->scriptFlags & SCF_FIRE_WEAPON ) { WeaponThink( qtrue ); @@ -983,7 +966,7 @@ void NPC_BSST_Investigate( void ) return; } - int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue ); + int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, NPCInfo->lastAlertID ); //There is an event to look at if ( alertEvent >= 0 ) @@ -1144,7 +1127,7 @@ void NPC_BSST_Patrol( void ) ChangeWeapon( NPC, WP_NONE ); NPC->client->ps.weapon = WP_NONE; NPC->client->ps.weaponstate = WEAPON_READY; - if ( NPC->weaponModel != -1 ) + if ( NPC->weaponModel >= 0 ) { gi.G2API_RemoveGhoul2Model( NPC->ghoul2, NPC->weaponModel ); NPC->weaponModel = -1; @@ -1860,10 +1843,19 @@ void ST_Commander( void ) continue; } + if ( NPC->s.weapon == WP_NONE + && NPCInfo->goalEntity + && NPCInfo->goalEntity == NPCInfo->tempGoal + && NPCInfo->goalEntity->enemy + && NPCInfo->goalEntity->enemy->s.eType == ET_ITEM ) + {//running to pick up a gun, don't do other logic + continue; + } + //see if this member should start running (only if have no officer... FIXME: should always run from AEL_DANGER_GREAT?) if ( !group->commander || group->commander->NPC->rank < RANK_ENSIGN ) { - if ( NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, qfalse, AEL_DANGER ) ) ) + if ( NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) ) {//going to run ST_Speech( NPC, SPEECH_COVER, 0 ); continue; @@ -2429,7 +2421,7 @@ void NPC_BSST_Attack( void ) #endif// AI_TIMERS } } - else if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, qfalse, AEL_DANGER ) ) ) + else if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) ) {//not already fleeing, and going to run ST_Speech( NPC, SPEECH_COVER, 0 ); NPC_UpdateAngles( qtrue, qtrue ); @@ -2469,6 +2461,20 @@ void NPC_BSST_Attack( void ) //FIXME: we can never go back to alt-fire this way since, after this, we don't know if we were initially supposed to use alt-fire or not... } } + else if ( enemyDist > 65536 )//256 squared + { + if ( NPC->client->ps.weapon == WP_DISRUPTOR ) + {//sniping... should be assumed + if ( !(NPCInfo->scriptFlags&SCF_ALT_FIRE) ) + {//use primary fire + NPCInfo->scriptFlags |= SCF_ALT_FIRE; + //reset fire-timing variables + NPC_ChangeWeapon( WP_DISRUPTOR ); + NPC_UpdateAngles( qtrue, qtrue ); + return; + } + } + } //can we see our target? if ( NPC_ClearLOS( NPC->enemy ) ) @@ -2566,6 +2572,11 @@ void NPC_BSST_Attack( void ) } } + if ( NPC->client->fireDelay && NPC->s.weapon == WP_ROCKET_LAUNCHER ) + { + move = qfalse; + } + if ( move ) {//move toward goal if ( NPCInfo->goalEntity )//&& ( NPCInfo->goalEntity != NPC->enemy || enemyDist > 10000 ) )//100 squared @@ -2626,7 +2637,21 @@ void NPC_BSST_Attack( void ) } } //FIXME: don't shoot right away! - if ( shoot ) + if ( NPC->client->fireDelay ) + { + if ( NPC->s.weapon == WP_ROCKET_LAUNCHER ) + { + if ( !enemyLOS || !enemyCS ) + {//cancel it + NPC->client->fireDelay = 0; + } + else + {//delay our next attempt + TIMER_Set( NPC, "attackDelay", Q_irand( 3000, 5000 ) ); + } + } + } + else if ( shoot ) {//try to shoot if it's time if ( TIMER_Done( NPC, "attackDelay" ) ) { @@ -2634,14 +2659,17 @@ void NPC_BSST_Attack( void ) { WeaponThink( qtrue ); } - /* //NASTY - if ( NPC->s.weapon == WP_ROCKET_LAUNCHER && (ucmd.buttons&BUTTON_ATTACK) && Q_irand( -6, g_spskill->integer*3) >= 0 ) + if ( NPC->s.weapon == WP_ROCKET_LAUNCHER + && (ucmd.buttons&BUTTON_ATTACK) + && !move + && g_spskill->integer > 1 + && !Q_irand( 0, 3 ) ) {//every now and then, shoot a homing rocket ucmd.buttons &= ~BUTTON_ATTACK; ucmd.buttons |= BUTTON_ALT_ATTACK; + NPC->client->fireDelay = Q_irand( 1000, 2500 ); } - */ } } } diff --git a/code/game/AI_Utils.cpp b/code/game/AI_Utils.cpp index 587c59f..441733a 100644 --- a/code/game/AI_Utils.cpp +++ b/code/game/AI_Utils.cpp @@ -213,8 +213,8 @@ qboolean AI_FindSelfInPreviousGroup( gentity_t *self ) int i, j; for ( i = 0; i < MAX_FRAME_GROUPS; i++ ) { - if ( level.groups[i].numGroup && level.groups[i].enemy != NULL ) - {//make a new one + if ( level.groups[i].numGroup )//&& level.groups[i].enemy != NULL ) + {//check this one for ( j = 0; j < level.groups[i].numGroup; j++ ) { if ( level.groups[i].member[j].number == self->s.number ) @@ -260,7 +260,7 @@ qboolean AI_TryJoinPreviousGroup( gentity_t *self ) { if ( level.groups[i].numGroup && level.groups[i].numGroup < (MAX_GROUP_MEMBERS - 1) - && level.groups[i].enemy != NULL + //&& level.groups[i].enemy != NULL && level.groups[i].enemy == self->enemy ) {//has members, not full and has my enemy if ( AI_ValidateGroupMember( &level.groups[i], self ) ) @@ -302,6 +302,37 @@ qboolean AI_GetNextEmptyGroup( gentity_t *self ) } } +qboolean AI_ValidateNoEnemyGroupMember( AIGroupInfo_t *group, gentity_t *member ) +{ + if ( !group ) + { + return qfalse; + } + vec3_t center; + if ( group->commander ) + { + VectorCopy( group->commander->currentOrigin, center ); + } + else + {//hmm, just pick the first member + if ( group->member[0].number < 0 || group->member[0].number >= ENTITYNUM_WORLD ) + { + return qfalse; + } + VectorCopy( g_entities[group->member[0].number].currentOrigin, center ); + } + //FIXME: maybe it should be based on the center of the mass of the group, not the commander? + if ( DistanceSquared( center, member->currentOrigin ) > 147456/*384*384*/ ) + { + return qfalse; + } + if ( !gi.inPVS( member->currentOrigin, center ) ) + {//not within PVS of the group enemy + return qfalse; + } + return qtrue; +} + qboolean AI_ValidateGroupMember( AIGroupInfo_t *group, gentity_t *member ) { //Validate ents @@ -382,6 +413,13 @@ qboolean AI_ValidateGroupMember( AIGroupInfo_t *group, gentity_t *member ) return qfalse; } } + else if ( group->enemy == NULL ) + {//if the group is a patrol group, only take those within the room and radius + if ( !AI_ValidateNoEnemyGroupMember( group, member ) ) + { + return qfalse; + } + } //must be actually in combat mode if ( !TIMER_Done( member, "interrogating" ) ) return qfalse; @@ -502,6 +540,20 @@ void AI_GetGroup( gentity_t *self ) AI_SetClosestBuddy( self->NPC->group ); } +void AI_SetNewGroupCommander( AIGroupInfo_t *group ) +{ + gentity_t *member = NULL; + group->commander = NULL; + for ( int i = 0; i < group->numGroup; i++ ) + { + member = &g_entities[group->member[i].number]; + + if ( !group->commander || (member && member->NPC && group->commander->NPC && member->NPC->rank > group->commander->NPC->rank) ) + {//keep track of highest rank + group->commander = member; + } + } +} void AI_DeleteGroupMember( AIGroupInfo_t *group, int memberNum ) { @@ -509,6 +561,10 @@ void AI_DeleteGroupMember( AIGroupInfo_t *group, int memberNum ) { group->commander = NULL; } + if ( g_entities[group->member[memberNum].number].NPC ) + { + g_entities[group->member[memberNum].number].NPC->group = NULL; + } for ( int i = memberNum; i < (group->numGroup-1); i++ ) { memcpy( &group->member[i], &group->member[i+1], sizeof( group->member[i] ) ); @@ -526,6 +582,7 @@ void AI_DeleteGroupMember( AIGroupInfo_t *group, int memberNum ) { group->numGroup = 0; } + AI_SetNewGroupCommander( group ); } void AI_DeleteSelfFromGroup( gentity_t *self ) @@ -679,10 +736,19 @@ qboolean AI_RefreshGroup( AIGroupInfo_t *group ) {//2 groups with same enemy if ( level.groups[i].numGroup+group->numGroup < (MAX_GROUP_MEMBERS - 1) ) {//combining the members would fit in one group + qboolean deleteWhenDone = qtrue; //combine the members of mine into theirs for ( int j = 0; j < group->numGroup; j++ ) { member = &g_entities[group->member[j].number]; + if ( level.groups[i].enemy == NULL ) + {//special case for groups without enemies, must be in range + if ( !AI_ValidateNoEnemyGroupMember( &level.groups[i], member ) ) + { + deleteWhenDone = qfalse; + continue; + } + } //remove this member from this group AI_DeleteGroupMember( group, j ); //keep marker at same place since we deleted this guy and shifted everyone up one @@ -691,7 +757,10 @@ qboolean AI_RefreshGroup( AIGroupInfo_t *group ) AI_InsertGroupMember( &level.groups[i], member ); } //return and delete this group - return qfalse; + if ( deleteWhenDone ) + { + return qfalse; + } } } } @@ -787,6 +856,10 @@ qboolean AI_RefreshGroup( AIGroupInfo_t *group ) { group->morale += member->NPC->rank; } + if ( group->commander && debugNPCAI->integer ) + { + G_DebugLine( group->commander->currentOrigin, member->currentOrigin, FRAMETIME, 0x00ff00ff, qtrue ); + } } if ( group->enemy ) {//modify morale based on enemy health and weapon @@ -875,7 +948,7 @@ void AI_UpdateGroups( void ) //Clear all Groups for ( int i = 0; i < MAX_FRAME_GROUPS; i++ ) { - if ( !level.groups[i].numGroup || level.groups[i].enemy == NULL || AI_RefreshGroup( &level.groups[i] ) == qfalse ) + if ( !level.groups[i].numGroup || AI_RefreshGroup( &level.groups[i] ) == qfalse )//level.groups[i].enemy == NULL || { memset( &level.groups[i], 0, sizeof( level.groups[i] ) ); } diff --git a/code/game/NPC.cpp b/code/game/NPC.cpp index b48e1f9..3a1048b 100644 --- a/code/game/NPC.cpp +++ b/code/game/NPC.cpp @@ -16,6 +16,7 @@ extern vec3_t playerMins; extern vec3_t playerMaxs; //extern void PM_SetAnimFinal(int *torsoAnim,int *legsAnim,int type,int anim,int priority,int *torsoAnimTimer,int *legsAnimTimer,gentity_t *gent); +extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); extern void PM_SetTorsoAnimTimer( gentity_t *ent, int *torsoAnimTimer, int time ); extern void PM_SetLegsAnimTimer( gentity_t *ent, int *legsAnimTimer, int time ); extern void NPC_BSNoClip ( void ); @@ -31,9 +32,10 @@ extern void Mark1_dying( gentity_t *self ); extern void NPC_BSCinematic( void ); extern int GetTime ( int lastTime ); extern void NPC_BSGM_Default( void ); +extern void NPC_CheckCharmed( void ); extern cvar_t *g_dismemberment; -extern cvar_t *g_realisticSaberDamage; +extern cvar_t *g_saberRealisticCombat; //Local Variables // ai debug cvars @@ -48,6 +50,7 @@ cvar_t *d_JediAI; cvar_t *d_noGroupAI; cvar_t *d_asynchronousGroupAI; cvar_t *d_altRoutes; +cvar_t *d_patched; cvar_t *d_slowmodeath; extern int eventClearTime; @@ -69,13 +72,13 @@ void CorpsePhysics( gentity_t *self ) memset( &ucmd, 0, sizeof( ucmd ) ); ClientThink( self->s.number, &ucmd ); VectorCopy( self->s.origin, self->s.origin2 ); - + if ( self->client->NPC_class == CLASS_GALAKMECH ) { GM_Dying( self ); } //FIXME: match my pitch and roll for the slope of my groundPlane - if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE && !(self->flags|FL_DISINTEGRATED) ) + if ( self->client->ps.groundEntityNum != ENTITYNUM_NONE && !(self->flags&FL_DISINTEGRATED) ) {//on the ground //FIXME: check 4 corners pitch_roll_for_slope( self, NULL ); @@ -91,9 +94,12 @@ void CorpsePhysics( gentity_t *self ) if ( level.time - self->s.time > 3000 ) {//been dead for 3 seconds - if ( g_dismemberment->integer < 4 && !g_realisticSaberDamage->integer ) + if ( g_dismemberment->integer < 11381138 && !g_saberRealisticCombat->integer ) {//can't be dismembered once dead - self->client->dismembered = qtrue; + if ( self->client->NPC_class != CLASS_PROTOCOL ) + { + self->client->dismembered = qtrue; + } } } @@ -125,8 +131,18 @@ Determines when it's ok to ditch the corpse void NPC_RemoveBody( gentity_t *self ) { CorpsePhysics( self ); + self->nextthink = level.time + FRAMETIME; + if ( self->NPC->nextBStateThink <= level.time ) + { + if( self->taskManager && !stop_icarus ) + { + self->taskManager->Update( ); + } + } + self->NPC->nextBStateThink = level.time + FRAMETIME; + if ( self->message ) {//I still have a key return; @@ -140,9 +156,17 @@ void NPC_RemoveBody( gentity_t *self ) } // Since these blow up, remove the bounding box. - if (( self->client->NPC_class == CLASS_REMOTE ) || ( self->client->NPC_class == CLASS_SENTRY ) || ( self->client->NPC_class == CLASS_PROBE )) + if ( self->client->NPC_class == CLASS_REMOTE + || self->client->NPC_class == CLASS_SENTRY + || self->client->NPC_class == CLASS_PROBE + || self->client->NPC_class == CLASS_INTERROGATOR + || self->client->NPC_class == CLASS_PROBE + || self->client->NPC_class == CLASS_MARK2 ) { - G_FreeEntity( self ); + if ( !self->taskManager || !self->taskManager->IsRunning() ) + { + G_FreeEntity( self ); + } return; } @@ -190,15 +214,18 @@ void NPC_RemoveBody( gentity_t *self ) // placed in the map as a corpse if ( self->enemy ) { - if ( self->client && self->client->ps.saberEntityNum > 0 && self->client->ps.saberEntityNum < ENTITYNUM_WORLD ) + if ( !self->taskManager || !self->taskManager->IsRunning() ) { - gentity_t *saberent = &g_entities[self->client->ps.saberEntityNum]; - if ( saberent ) + if ( self->client && self->client->ps.saberEntityNum > 0 && self->client->ps.saberEntityNum < ENTITYNUM_WORLD ) { - G_FreeEntity( saberent ); + gentity_t *saberent = &g_entities[self->client->ps.saberEntityNum]; + if ( saberent ) + { + G_FreeEntity( saberent ); + } } + G_FreeEntity( self ); } - G_FreeEntity( self ); } } } @@ -769,8 +796,11 @@ static void DeadThink ( void ) { if ( NPC->client->ps.eFlags & EF_NODRAW ) { - NPC->e_ThinkFunc = thinkF_G_FreeEntity; - NPC->nextthink = level.time + FRAMETIME; + if ( !NPC->taskManager || !NPC->taskManager->IsRunning() ) + { + NPC->e_ThinkFunc = thinkF_G_FreeEntity; + NPC->nextthink = level.time + FRAMETIME; + } } else { @@ -890,9 +920,15 @@ void NPC_ShowDebugInfo (void) void NPC_ApplyScriptFlags (void) { - if(NPCInfo->scriptFlags & SCF_CROUCHED) + if ( NPCInfo->scriptFlags & SCF_CROUCHED ) { - ucmd.upmove = -127; + if ( NPCInfo->charmedTime > level.time && (ucmd.forwardmove || ucmd.rightmove) ) + {//ugh, if charmed and moving, ignore the crouched command + } + else + { + ucmd.upmove = -127; + } } if(NPCInfo->scriptFlags & SCF_RUNNING) @@ -901,7 +937,13 @@ void NPC_ApplyScriptFlags (void) } else if(NPCInfo->scriptFlags & SCF_WALKING) { - ucmd.buttons |= BUTTON_WALKING; + if ( NPCInfo->charmedTime > level.time && (ucmd.forwardmove || ucmd.rightmove) ) + {//ugh, if charmed and moving, ignore the walking command + } + else + { + ucmd.buttons |= BUTTON_WALKING; + } } /* if(NPCInfo->scriptFlags & SCF_CAREFUL) @@ -954,6 +996,7 @@ void NPC_HandleAIFlags (void) } //MRJ Request: + /* if ( NPCInfo->aiFlags & NPCAI_GREET_ALLIES && !NPC->enemy )//what if "enemy" is the greetEnt? {//If no enemy, look for teammates to greet //FIXME: don't say hi to the same guy over and over again. @@ -1001,6 +1044,13 @@ void NPC_HandleAIFlags (void) } } } + */ + //been told to play a victory sound after a delay + if ( NPCInfo->greetingDebounceTime && NPCInfo->greetingDebounceTime < level.time ) + { + G_AddVoiceEvent( NPC, Q_irand(EV_VICTORY1, EV_VICTORY3), Q_irand( 2000, 4000 ) ); + NPCInfo->greetingDebounceTime = 0; + } if ( NPCInfo->ffireCount > 0 ) { @@ -1011,7 +1061,13 @@ void NPC_HandleAIFlags (void) NPCInfo->ffireFadeDebounce = level.time + 3000; } } - + if ( d_patched->integer ) + {//use patch-style navigation + if ( NPCInfo->consecutiveBlockedMoves > 20 ) + {//been stuck for a while, try again? + NPCInfo->consecutiveBlockedMoves = 0; + } + } } void NPC_AvoidWallsAndCliffs (void) @@ -1173,6 +1229,37 @@ void NPC_KeepCurrentFacing(void) } } +/* +------------------------- +NPC_BehaviorSet_Charmed +------------------------- +*/ + +void NPC_BehaviorSet_Charmed( int bState ) +{ + switch( bState ) + { + case BS_FOLLOW_LEADER://# 40: Follow your leader and shoot any enemies you come across + NPC_BSFollowLeader(); + break; + case BS_REMOVE: + NPC_BSRemove(); + break; + case BS_SEARCH: //# 43: Using current waypoint as a base, search the immediate branches of waypoints for enemies + NPC_BSSearch(); + break; + case BS_WANDER: //# 46: Wander down random waypoint paths + NPC_BSWander(); + break; + case BS_FLEE: + NPC_BSFlee(); + break; + default: + case BS_DEFAULT://whatever + NPC_BSDefault(); + break; + } +} /* ------------------------- NPC_BehaviorSet_Default @@ -1592,19 +1679,7 @@ void NPC_RunBehavior( int team, int bState ) else if ( NPC->client->ps.weapon == WP_EMPLACED_GUN ) { NPC_BSEmplaced(); - if ( NPC->client->playerTeam == TEAM_PLAYER && NPCInfo->charmedTime && NPCInfo->charmedTime < level.time && NPC->client ) - {//we were charmed, set us back! - //NOTE: presumptions here... - team_t savTeam = NPC->client->enemyTeam; - NPC->client->enemyTeam = NPC->client->playerTeam; - NPC->client->playerTeam = savTeam; - NPC->client->leader = NULL; - if ( NPCInfo->tempBehavior == BS_FOLLOW_LEADER ) - { - NPCInfo->tempBehavior = BS_DEFAULT; - } - G_ClearEnemy( NPC ); - } + NPC_CheckCharmed(); return; } else if ( NPC->client->ps.weapon == WP_SABER ) @@ -1719,21 +1794,16 @@ void NPC_RunBehavior( int team, int bState ) } else { - NPC_BehaviorSet_Default( bState ); - dontSetAim = qtrue; - if ( NPCInfo->charmedTime && NPCInfo->charmedTime < level.time && NPC->client ) - {//we were charmed, set us back! - //NOTE: presumptions here... - team_t saveTeam = NPC->client->enemyTeam; - NPC->client->enemyTeam = NPC->client->playerTeam; - NPC->client->playerTeam = saveTeam; - NPC->client->leader = NULL; - if ( NPCInfo->tempBehavior == BS_FOLLOW_LEADER ) - { - NPCInfo->tempBehavior = BS_DEFAULT; - } - G_ClearEnemy( NPC ); + if ( NPCInfo->charmedTime > level.time ) + { + NPC_BehaviorSet_Charmed( bState ); } + else + { + NPC_BehaviorSet_Default( bState ); + } + NPC_CheckCharmed(); + dontSetAim = qtrue; } break; } @@ -1885,7 +1955,7 @@ void NPC_ExecuteBState ( gentity_t *self)//, int msec ) // run the bot through the server like it was a real client //=== Save the ucmd for the second no-think Pmove ============================ ucmd.serverTime = level.time - 50; - NPCInfo->last_ucmd = ucmd; + memcpy( &NPCInfo->last_ucmd, &ucmd, sizeof( usercmd_t ) ); if ( !NPCInfo->attackHoldTime ) { NPCInfo->last_ucmd.buttons &= ~(BUTTON_ATTACK|BUTTON_ALT_ATTACK);//so we don't fire twice in one think @@ -2023,29 +2093,29 @@ void NPC_Think ( gentity_t *self)//, int msec ) switch( self->client->NPC_class ) { case CLASS_R2D2: // droid - G_Sound(self, G_SoundIndex(va("sound/chars/r2d2/misc/r2d2talk0%d.wav",Q_irand(1, 3)))); + G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/r2d2/misc/r2d2talk0%d.wav",Q_irand(1, 3)) ); break; case CLASS_R5D2: // droid - G_Sound(self, G_SoundIndex(va("sound/chars/r5d2/misc/r5talk%d.wav",Q_irand(1, 4)))); + G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/r5d2/misc/r5talk%d.wav",Q_irand(1, 4)) ); break; case CLASS_PROBE: // droid - G_Sound(self, G_SoundIndex(va("sound/chars/probe/misc/probetalk%d.wav",Q_irand(1, 3)))); + G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/probe/misc/probetalk%d.wav",Q_irand(1, 3)) ); break; case CLASS_MOUSE: // droid - G_Sound(self, G_SoundIndex(va("sound/chars/mouse/misc/mousego%d.wav",Q_irand(1, 3)))); + G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/mouse/misc/mousego%d.wav",Q_irand(1, 3)) ); break; case CLASS_GONK: // droid - G_Sound(self, G_SoundIndex(va("sound/chars/gonk/misc/gonktalk%d.wav",Q_irand(1, 2)))); + G_SoundOnEnt(self, CHAN_AUTO, va("sound/chars/gonk/misc/gonktalk%d.wav",Q_irand(1, 2)) ); break; } TIMER_Set( self, "patrolNoise", Q_irand( 2000, 4000 ) ); } } //FIXME: might want to at least make sounds or something? - NPC_UpdateAngles(qtrue, qtrue); + //NPC_UpdateAngles(qtrue, qtrue); //Which ucmd should we send? Does it matter, since it gets overridden anyway? NPCInfo->last_ucmd.serverTime = level.time - 50; - ClientThink(NPC->s.number, &NPCInfo->last_ucmd); + ClientThink( NPC->s.number, &ucmd ); VectorCopy(self->s.origin, self->s.origin2 ); return; } @@ -2090,7 +2160,8 @@ void NPC_Think ( gentity_t *self)//, int msec ) {//If we were following a roff, we don't do normal pmoves. //FIXME: firing angles (no aim offset) or regular angles? NPC_UpdateAngles(qtrue, qtrue); - ClientThink(NPC->s.number, &NPCInfo->last_ucmd); + memcpy( &ucmd, &NPCInfo->last_ucmd, sizeof( usercmd_t ) ); + ClientThink(NPC->s.number, &ucmd); } else { @@ -2117,6 +2188,7 @@ void NPC_InitAI ( void ) d_noGroupAI = gi.cvar ( "d_noGroupAI", "0", CVAR_CHEAT ); d_asynchronousGroupAI = gi.cvar ( "d_asynchronousGroupAI", "1", CVAR_CHEAT ); d_altRoutes = gi.cvar ( "d_altRoutes", "1", CVAR_CHEAT ); + d_patched = gi.cvar ( "d_patched", "0", CVAR_CHEAT ); //0 = never (BORING) //1 = kyle only diff --git a/code/game/NPC_behavior.cpp b/code/game/NPC_behavior.cpp index f4ac19b..0d42178 100644 --- a/code/game/NPC_behavior.cpp +++ b/code/game/NPC_behavior.cpp @@ -18,6 +18,7 @@ static vec3_t NPCDEBUG_BLUE = {0.0, 0.0, 1.0}; extern void CG_Cube( vec3_t mins, vec3_t maxs, vec3_t color, float alpha ); extern void NPC_CheckGetNewWeapon( void ); extern qboolean PM_InKnockDown( playerState_t *ps ); +extern void NPC_AimAdjust( int change ); /* void NPC_BSAdvanceFight (void) @@ -192,7 +193,6 @@ void BeamOut (gentity_t *self) { // gentity_t *tent = G_Spawn(); - self->client->ps.powerups[PW_QUAD] = level.time + 2000; /* tent->owner = self; tent->think = MakeOwnerInvis; @@ -547,6 +547,46 @@ void NPC_BSFollowLeader (void) {//just found one NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 3000, 10000 ); } + else + { + if ( !(NPCInfo->scriptFlags&SCF_IGNORE_ALERTS) ) + { + int eventID = NPC_CheckAlertEvents( qtrue, qtrue ); + if ( level.alertEvents[eventID].level >= AEL_SUSPICIOUS && (NPCInfo->scriptFlags&SCF_LOOK_FOR_ENEMIES) ) + { + NPCInfo->lastAlertID = level.alertEvents[eventID].ID; + if ( !level.alertEvents[eventID].owner || + !level.alertEvents[eventID].owner->client || + level.alertEvents[eventID].owner->health <= 0 || + level.alertEvents[eventID].owner->client->playerTeam != NPC->client->enemyTeam ) + {//not an enemy + } + else + { + //FIXME: what if can't actually see enemy, don't know where he is... should we make them just become very alert and start looking for him? Or just let combat AI handle this... (act as if you lost him) + G_SetEnemy( NPC, level.alertEvents[eventID].owner ); + NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 3000, 10000 ); + NPCInfo->enemyLastSeenTime = level.time; + TIMER_Set( NPC, "attackDelay", Q_irand( 500, 1000 ) ); + } + } + + } + } + if ( !NPC->enemy ) + { + if ( NPC->client->leader + && NPC->client->leader->enemy + && NPC->client->leader->enemy != NPC + && ( (NPC->client->leader->enemy->client&&NPC->client->leader->enemy->client->playerTeam==NPC->client->enemyTeam) + ||(NPC->client->leader->enemy->svFlags&SVF_NONNPC_ENEMY&&NPC->client->leader->enemy->noDamageTeam==NPC->client->enemyTeam) ) + && NPC->client->leader->enemy->health > 0 ) + { + G_SetEnemy( NPC, NPC->client->leader->enemy ); + NPCInfo->enemyCheckDebounceTime = level.time + Q_irand( 3000, 10000 ); + NPCInfo->enemyLastSeenTime = level.time; + } + } } else { @@ -598,11 +638,24 @@ void NPC_BSFollowLeader (void) if ( enemyVisibility >= VIS_SHOOT ) {//shoot - WeaponThink( qtrue ); + NPC_AimAdjust( 2 ); + if ( NPC_GetHFOVPercentage( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, NPCInfo->stats.hfov ) > 0.6f + && NPC_GetHFOVPercentage( NPC->enemy->currentOrigin, NPC->currentOrigin, NPC->client->ps.viewangles, NPCInfo->stats.vfov ) > 0.5f ) + {//actually withing our front cone + WeaponThink( qtrue ); + } + } + else + { + NPC_AimAdjust( 1 ); } //NPC_CheckCanAttack(1.0, qfalse); } + else + { + NPC_AimAdjust( -1 ); + } } else {//FIXME: combine with vector calc below @@ -1255,6 +1308,10 @@ extern void ChangeWeapon( gentity_t *ent, int newWeapon ); extern int g_crosshairEntNum; void NPC_Surrender( void ) {//FIXME: say "don't shoot!" if we weren't already surrendering + if ( NPC->client->ps.weaponTime || PM_InKnockDown( &NPC->client->ps ) ) + { + return; + } if ( NPC->s.weapon != WP_NONE && NPC->s.weapon != WP_MELEE && NPC->s.weapon != WP_SABER ) @@ -1572,7 +1629,6 @@ void G_StartFlee( gentity_t *self, gentity_t *enemy, vec3_t dangerPoint, int dan RestoreNPCGlobals(); } -extern void NPC_AimAdjust( int change ); void NPC_BSEmplaced( void ) { //Don't do anything if we're hurt diff --git a/code/game/NPC_combat.cpp b/code/game/NPC_combat.cpp index 0f71754..161cb51 100644 --- a/code/game/NPC_combat.cpp +++ b/code/game/NPC_combat.cpp @@ -131,6 +131,7 @@ void G_AttackDelay( gentity_t *self, gentity_t *enemy ) int attDelay; VectorSubtract( self->client->renderInfo.eyePoint, enemy->currentOrigin, dir );//purposely backwards + VectorNormalize( dir ); AngleVectors( self->client->renderInfo.eyeAngles, fwd, NULL, NULL ); //dir[2] = fwd[2] = 0;//ignore z diff? @@ -296,6 +297,10 @@ void G_AttackDelay( gentity_t *self, gentity_t *enemy ) } //don't shoot right away + if ( attDelay > 4000+((2-g_spskill->integer)*3000) ) + { + attDelay = 4000+((2-g_spskill->integer)*3000); + } TIMER_Set( self, "attackDelay", attDelay );//Q_irand( 1500, 4500 ) ); //don't move right away either if ( attDelay > 4000 ) @@ -344,6 +349,13 @@ void G_SetEnemy( gentity_t *self, gentity_t *enemy ) {//can't pick up enemies if confused return; } + +#ifdef _DEBUG + if ( self->s.number ) + { + assert( enemy != self ); + } +#endif// _DEBUG // if ( enemy->client && enemy->client->playerTeam == TEAM_DISGUISE ) // {//unmask the player @@ -413,7 +425,27 @@ void G_SetEnemy( gentity_t *self, gentity_t *enemy ) {//Hmm, how about sniper and bowcaster? //When first get mad, aim is bad //Hmm, base on game difficulty, too? Rank? - G_AimSet( self, Q_irand( self->NPC->stats.aim - (15*(3-g_spskill->integer)), self->NPC->stats.aim - (5*(3-g_spskill->integer)) ) ); + if ( self->client->playerTeam == TEAM_PLAYER ) + { + G_AimSet( self, Q_irand( self->NPC->stats.aim - (5*(g_spskill->integer)), self->NPC->stats.aim - g_spskill->integer ) ); + } + else + { + int minErr = 3; + int maxErr = 12; + if ( self->client->NPC_class == CLASS_IMPWORKER ) + { + minErr = 15; + maxErr = 30; + } + else if ( self->client->NPC_class == CLASS_STORMTROOPER && self->NPC && self->NPC->rank <= RANK_CREWMAN ) + { + minErr = 5; + maxErr = 15; + } + + G_AimSet( self, Q_irand( self->NPC->stats.aim - (maxErr*(3-g_spskill->integer)), self->NPC->stats.aim - (minErr*(3-g_spskill->integer)) ) ); + } } //Alert anyone else in the area @@ -525,12 +557,24 @@ void ChangeWeapon( gentity_t *ent, int newWeapon ) case WP_BLASTER_PISTOL: ent->NPC->aiFlags &= ~NPCAI_BURST_WEAPON; - ent->NPC->burstSpacing = 1000;//attackdebounce + // ent->NPC->burstSpacing = 1000;//attackdebounce + if ( g_spskill->integer == 0 ) + ent->NPC->burstSpacing = 1000;//attack debounce + else if ( g_spskill->integer == 1 ) + ent->NPC->burstSpacing = 750;//attack debounce + else + ent->NPC->burstSpacing = 500;//attack debounce break; case WP_BOT_LASER://probe attack ent->NPC->aiFlags &= ~NPCAI_BURST_WEAPON; - ent->NPC->burstSpacing = 600;//attackdebounce + // ent->NPC->burstSpacing = 600;//attackdebounce + if ( g_spskill->integer == 0 ) + ent->NPC->burstSpacing = 600;//attack debounce + else if ( g_spskill->integer == 1 ) + ent->NPC->burstSpacing = 400;//attack debounce + else + ent->NPC->burstSpacing = 200;//attack debounce break; case WP_SABER: @@ -542,7 +586,18 @@ void ChangeWeapon( gentity_t *ent, int newWeapon ) ent->NPC->aiFlags &= ~NPCAI_BURST_WEAPON; if ( ent->NPC->scriptFlags & SCF_ALT_FIRE ) { - ent->NPC->burstSpacing = 2000;//attackdebounce + switch( g_spskill->integer ) + { + case 0: + ent->NPC->burstSpacing = 2500;//attackdebounce + break; + case 1: + ent->NPC->burstSpacing = 2000;//attackdebounce + break; + case 2: + ent->NPC->burstSpacing = 1500;//attackdebounce + break; + } } else { @@ -552,7 +607,13 @@ void ChangeWeapon( gentity_t *ent, int newWeapon ) case WP_BOWCASTER: ent->NPC->aiFlags &= ~NPCAI_BURST_WEAPON; - ent->NPC->burstSpacing = 1000;//attackdebounce + // ent->NPC->burstSpacing = 1000;//attackdebounce + if ( g_spskill->integer == 0 ) + ent->NPC->burstSpacing = 1000;//attack debounce + else if ( g_spskill->integer == 1 ) + ent->NPC->burstSpacing = 750;//attack debounce + else + ent->NPC->burstSpacing = 500;//attack debounce break; case WP_REPEATER: @@ -595,12 +656,24 @@ void ChangeWeapon( gentity_t *ent, int newWeapon ) case WP_ROCKET_LAUNCHER: ent->NPC->aiFlags &= ~NPCAI_BURST_WEAPON; - ent->NPC->burstSpacing = 2500;//attackdebounce + // ent->NPC->burstSpacing = 2500;//attackdebounce + if ( g_spskill->integer == 0 ) + ent->NPC->burstSpacing = 2500;//attack debounce + else if ( g_spskill->integer == 1 ) + ent->NPC->burstSpacing = 2000;//attack debounce + else + ent->NPC->burstSpacing = 1500;//attack debounce break; case WP_THERMAL: ent->NPC->aiFlags &= ~NPCAI_BURST_WEAPON; - ent->NPC->burstSpacing = 3000;//attackdebounce + // ent->NPC->burstSpacing = 3000;//attackdebounce + if ( g_spskill->integer == 0 ) + ent->NPC->burstSpacing = 3000;//attack debounce + else if ( g_spskill->integer == 1 ) + ent->NPC->burstSpacing = 2500;//attack debounce + else + ent->NPC->burstSpacing = 2000;//attack debounce break; /* @@ -639,7 +712,13 @@ void ChangeWeapon( gentity_t *ent, int newWeapon ) else { ent->NPC->aiFlags &= ~NPCAI_BURST_WEAPON; - ent->NPC->burstSpacing = 1000;//attackdebounce + if ( g_spskill->integer == 0 ) + ent->NPC->burstSpacing = 1000;//attack debounce + else if ( g_spskill->integer == 1 ) + ent->NPC->burstSpacing = 750;//attack debounce + else + ent->NPC->burstSpacing = 500;//attack debounce + // ent->NPC->burstSpacing = 1000;//attackdebounce } break; @@ -651,7 +730,13 @@ void ChangeWeapon( gentity_t *ent, int newWeapon ) case WP_ATST_MAIN: case WP_ATST_SIDE: ent->NPC->aiFlags &= ~NPCAI_BURST_WEAPON; - ent->NPC->burstSpacing = 1000;//attackdebounce + // ent->NPC->burstSpacing = 1000;//attackdebounce + if ( g_spskill->integer == 0 ) + ent->NPC->burstSpacing = 1000;//attack debounce + else if ( g_spskill->integer == 1 ) + ent->NPC->burstSpacing = 750;//attack debounce + else + ent->NPC->burstSpacing = 500;//attack debounce break; case WP_EMPLACED_GUN: @@ -659,12 +744,13 @@ void ChangeWeapon( gentity_t *ent, int newWeapon ) if ( ent->client && ent->client->NPC_class == CLASS_REELO ) { ent->NPC->aiFlags &= ~NPCAI_BURST_WEAPON; - if ( g_spskill->integer == 0 ) - ent->NPC->burstSpacing = 300;//attack debounce - else if ( g_spskill->integer == 1 ) - ent->NPC->burstSpacing = 200;//attack debounce - else - ent->NPC->burstSpacing = 100;//attack debounce + ent->NPC->burstSpacing = 1000;//attack debounce + // if ( g_spskill->integer == 0 ) + // ent->NPC->burstSpacing = 300;//attack debounce + // else if ( g_spskill->integer == 1 ) + // ent->NPC->burstSpacing = 200;//attack debounce + // else + // ent->NPC->burstSpacing = 100;//attack debounce } else { @@ -721,7 +807,7 @@ void NPC_ChangeWeapon( int newWeapon ) { changing = qtrue; } - if ( changing && NPC->weaponModel != -1 ) + if ( changing && NPC->weaponModel >= 9 ) { gi.G2API_RemoveGhoul2Model( NPC->ghoul2, NPC->weaponModel ); } @@ -764,7 +850,7 @@ void NPC_ApplyWeaponFireDelay(void) // would look right in 3rd person. Really should have a wind-up anim // for player as he holds down the fire button to throw, then play // the actual throw when he lets go... - client->fireDelay = 1300; + client->fireDelay = 700; } break; @@ -1262,6 +1348,9 @@ qboolean ValidEnemy(gentity_t *ent) if ( ent == NULL ) return qfalse; + if ( ent == NPC ) + return qfalse; + //if team_free, maybe everyone is an enemy? if ( !NPC->client->enemyTeam ) return qfalse; @@ -1491,12 +1580,20 @@ gentity_t *NPC_PickEnemy( gentity_t *closestTo, int enemyTeam, qboolean checkVis { newenemy = &g_entities[entNum]; - if ( (newenemy->client || newenemy->svFlags & SVF_NONNPC_ENEMY) && !(newenemy->flags & FL_NOTARGET) && !(newenemy->s.eFlags & EF_NODRAW)) + if ( newenemy != NPC && (newenemy->client || newenemy->svFlags & SVF_NONNPC_ENEMY) && !(newenemy->flags & FL_NOTARGET) && !(newenemy->s.eFlags & EF_NODRAW)) { if ( newenemy->health > 0 ) { if ( (newenemy->client && newenemy->client->playerTeam == enemyTeam) || (!newenemy->client && newenemy->noDamageTeam == enemyTeam) ) {//FIXME: check for range and FOV or vis? + if ( NPC->client->playerTeam == TEAM_PLAYER && enemyTeam == TEAM_PLAYER ) + {//player allies turning on ourselves? How? + if ( newenemy->s.number ) + {//only turn on the player, not other player allies + continue; + } + } + if ( newenemy != NPC->lastEnemy ) {//Make sure we're not just going back and forth here if(!gi.inPVS(newenemy->currentOrigin, NPC->currentOrigin)) @@ -1727,7 +1824,7 @@ gentity_t *NPC_CheckEnemy( qboolean findNew, qboolean tooFarOk, qboolean setEnem if ( NPC->enemy ) { - if ( !NPC->enemy->inuse ) + if ( !NPC->enemy->inuse )//|| NPC->enemy == NPC )//wtf? NPCs should never get mad at themselves! { if ( setEnemy ) { @@ -2805,8 +2902,20 @@ gentity_t *NPC_SearchForWeapons( void ) dist = DistanceSquared( found->currentOrigin, NPC->currentOrigin ); if ( dist < bestDist ) { - bestDist = dist; - bestFound = found; + if ( !navigator.GetBestPathBetweenEnts( NPC, found, NF_CLEAR_PATH ) + || navigator.GetBestNodeAltRoute( NPC->waypoint, found->waypoint ) == WAYPOINT_NONE ) + {//can't possibly have a route to any OR can't possibly have a route to this one OR don't have a route to this one + if ( NAV_ClearPathToPoint( NPC, NPC->mins, NPC->maxs, found->currentOrigin, NPC->clipmask, ENTITYNUM_NONE ) ) + {//have a clear straight path to this one + bestDist = dist; + bestFound = found; + } + } + else + {//can nav to it + bestDist = dist; + bestFound = found; + } } } } @@ -2819,9 +2928,11 @@ void NPC_SetPickUpGoal( gentity_t *foundWeap ) { vec3_t org; + //NPCInfo->goalEntity = foundWeap; VectorCopy( foundWeap->currentOrigin, org ); org[2] += 24 - (foundWeap->mins[2]*-1);//adjust the origin so that I am on the ground NPC_SetMoveGoal( NPC, org, foundWeap->maxs[0]*0.75, qfalse, -1, foundWeap ); + NPCInfo->tempGoal->waypoint = foundWeap->waypoint; NPCInfo->tempBehavior = BS_DEFAULT; NPCInfo->squadState = SQUAD_TRANSITION; } @@ -2830,12 +2941,21 @@ void NPC_CheckGetNewWeapon( void ) { if ( NPC->s.weapon == WP_NONE && NPC->enemy ) {//if running away because dropped weapon... + if ( NPCInfo->goalEntity + && NPCInfo->goalEntity == NPCInfo->tempGoal + && NPCInfo->goalEntity->enemy + && !NPCInfo->goalEntity->enemy->inuse ) + {//maybe was running at a weapon that was picked up + NPCInfo->goalEntity = NULL; + } if ( TIMER_Done( NPC, "panic" ) && NPCInfo->goalEntity == NULL ) {//need a weapon, any lying around? gentity_t *foundWeap = NPC_SearchForWeapons(); if ( foundWeap ) {//try to nav to it - if ( !navigator.GetBestPathBetweenEnts( NPC, foundWeap, NF_CLEAR_PATH ) || navigator.GetBestNodeAltRoute( NPC->waypoint, foundWeap->waypoint ) == WAYPOINT_NONE ) + /* + if ( !navigator.GetBestPathBetweenEnts( NPC, foundWeap, NF_CLEAR_PATH ) + || navigator.GetBestNodeAltRoute( NPC->waypoint, foundWeap->waypoint ) == WAYPOINT_NONE ) {//can't possibly have a route to any OR can't possibly have a route to this one OR don't have a route to this one if ( !NAV_ClearPathToPoint( NPC, NPC->mins, NPC->maxs, foundWeap->currentOrigin, NPC->clipmask, ENTITYNUM_NONE ) ) {//don't even have a clear straight path to this one @@ -2846,6 +2966,7 @@ void NPC_CheckGetNewWeapon( void ) } } else + */ { NPC_SetPickUpGoal( foundWeap ); } diff --git a/code/game/NPC_move.cpp b/code/game/NPC_move.cpp index 5d42341..124ad91 100644 --- a/code/game/NPC_move.cpp +++ b/code/game/NPC_move.cpp @@ -292,7 +292,7 @@ qboolean NPC_GetMoveDirectionAltRoute( vec3_t out, float *distance, qboolean try memcpy( &tempInfo, &frameNavInfo, sizeof( tempInfo ) ); if ( NAVNEW_AvoidCollision( NPC, NPCInfo->goalEntity, tempInfo, qtrue, 5 ) == qfalse ) {//revert to macro nav - //Can't get straight to goal, deump tempInfo and use macro nav + //Can't get straight to goal, dump tempInfo and use macro nav if ( NAVNEW_MoveToGoal( NPC, frameNavInfo ) == WAYPOINT_NONE ) { //Can't reach goal, just face @@ -326,6 +326,53 @@ qboolean NPC_GetMoveDirectionAltRoute( vec3_t out, float *distance, qboolean try return qtrue; } +void G_UcmdMoveForDir( gentity_t *self, usercmd_t *cmd, vec3_t dir ) +{ + vec3_t forward, right; + + AngleVectors( self->currentAngles, forward, right, NULL ); + + dir[2] = 0; + VectorNormalize( dir ); + //NPCs cheat and store this directly because converting movement into a ucmd loses precision + VectorCopy( dir, self->client->ps.moveDir ); + + float fDot = DotProduct( forward, dir ) * 127.0f; + float rDot = DotProduct( right, dir ) * 127.0f; + //Must clamp this because DotProduct is not guaranteed to return a number within -1 to 1, and that would be bad when we're shoving this into a signed byte + if ( fDot > 127.0f ) + { + fDot = 127.0f; + } + if ( fDot < -127.0f ) + { + fDot = -127.0f; + } + if ( rDot > 127.0f ) + { + rDot = 127.0f; + } + if ( rDot < -127.0f ) + { + rDot = -127.0f; + } + cmd->forwardmove = floor(fDot); + cmd->rightmove = floor(rDot); + + /* + vec3_t wishvel; + for ( int i = 0 ; i < 3 ; i++ ) + { + wishvel[i] = forward[i]*cmd->forwardmove + right[i]*cmd->rightmove; + } + VectorNormalize( wishvel ); + if ( !VectorCompare( wishvel, dir ) ) + { + Com_Printf( "PRECISION LOSS: %s != %s\n", vtos(wishvel), vtos(dir) ); + } + */ +} + /* ------------------------- NPC_MoveToGoal @@ -373,49 +420,7 @@ qboolean NPC_MoveToGoal( qboolean tryStraight ) //If in combat move, then move directly towards our goal if ( NPC_CheckCombatMove() ) {//keep current facing - vec3_t forward, right; - - AngleVectors( NPC->currentAngles, forward, right, NULL ); - - dir[2] = 0; - VectorNormalize( dir ); - //NPCs cheat and store this directly because converting movement into a ucmd loses precision - VectorCopy( dir, NPC->client->ps.moveDir ); - - float fDot = DotProduct( forward, dir ) * 127.0f; - float rDot = DotProduct( right, dir ) * 127.0f; - //Must clamp this because DotProduct is not guaranteed to return a number within -1 to 1, and that would be bad when we're shoving this into a signed byte - if ( fDot > 127.0f ) - { - fDot = 127.0f; - } - if ( fDot < -127.0f ) - { - fDot = -127.0f; - } - if ( rDot > 127.0f ) - { - rDot = 127.0f; - } - if ( rDot < -127.0f ) - { - rDot = -127.0f; - } - ucmd.forwardmove = floor(fDot); - ucmd.rightmove = floor(rDot); - - /* - vec3_t wishvel; - for ( int i = 0 ; i < 3 ; i++ ) - { - wishvel[i] = forward[i]*ucmd.forwardmove + right[i]*ucmd.rightmove; - } - VectorNormalize( wishvel ); - if ( !VectorCompare( wishvel, dir ) ) - { - Com_Printf( "PRECISION LOSS: %s != %s\n", vtos(wishvel), vtos(dir) ); - } - */ + G_UcmdMoveForDir( NPC, &ucmd, dir ); } else {//face our goal @@ -430,8 +435,17 @@ qboolean NPC_MoveToGoal( qboolean tryStraight ) if ( dir[2] ) { -// ucmd.upmove = (dir[2] > 0) ? 64 : -64; - NPC->client->ps.velocity[2] = (dir[2] > 0) ? 64 : -64; + float scale = (dir[2] * distance); + if ( scale > 64 ) + { + scale = 64; + } + else if ( scale < -64 ) + { + scale = -64; + } + NPC->client->ps.velocity[2] = scale; + //NPC->client->ps.velocity[2] = (dir[2] > 0) ? 64 : -64; } } diff --git a/code/game/NPC_reactions.cpp b/code/game/NPC_reactions.cpp index e6d53a9..c1da586 100644 --- a/code/game/NPC_reactions.cpp +++ b/code/game/NPC_reactions.cpp @@ -15,12 +15,6 @@ extern qboolean G_CheckForStrongAttackMomentum( gentity_t *self ); extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); -float g_crosshairEntDist = Q3_INFINITE; -int g_crosshairSameEntTime = 0; -int g_crosshairEntNum = ENTITYNUM_NONE; -int g_crosshairEntTime = 0; -extern int teamLastEnemyTime[]; -extern cvar_t *g_spskill; extern int PM_AnimLength( int index, animNumber_t anim ); extern void cgi_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ); extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType ); @@ -39,7 +33,15 @@ extern qboolean PM_FlippingAnim( int anim ); extern qboolean PM_RollingAnim( int anim ); extern qboolean PM_InCartwheel( int anim ); +extern cvar_t *g_spskill; +extern int teamLastEnemyTime[]; extern qboolean stop_icarus; +extern int killPlayerTimer; + +float g_crosshairEntDist = Q3_INFINITE; +int g_crosshairSameEntTime = 0; +int g_crosshairEntNum = ENTITYNUM_NONE; +int g_crosshairEntTime = 0; /* ------------------------- NPC_CheckAttacker @@ -56,6 +58,9 @@ static void NPC_CheckAttacker( gentity_t *other, int mod ) if ( !other ) return; + if ( other == NPC ) + return; + if ( !other->inuse ) return; @@ -154,28 +159,38 @@ NPC_GetPainChance ------------------------- */ -#define MIN_FLINCH_DAMAGE 50 - float NPC_GetPainChance( gentity_t *self, int damage ) { - if ( damage > self->max_health/2.0f )//MIN_FLINCH_DAMAGE ) + if ( !self->enemy ) + {//surprised, always take pain return 1.0f; + } + if ( damage > self->max_health/2.0f ) + { + return 1.0f; + } + + float pain_chance = (float)(self->max_health-self->health)/(self->max_health*2.0f) + (float)damage/(self->max_health/2.0f); switch ( g_spskill->integer ) { case 0: //easy - return 0.75f; + //return 0.75f; break; case 1://med - return 0.35f; + pain_chance *= 0.5f; + //return 0.35f; break; case 2://hard default: - return 0.05f; + pain_chance *= 0.1f; + //return 0.05f; break; } + //Com_Printf( "%s: %4.2f\n", self->NPC_type, pain_chance ); + return pain_chance; } /* @@ -187,7 +202,7 @@ NPC_ChoosePainAnimation #define MIN_PAIN_TIME 200 extern int G_PickPainAnim( gentity_t *self, vec3_t point, int damage, int hitLoc ); -void NPC_ChoosePainAnimation( gentity_t *self, gentity_t *other, vec3_t point, int damage, int mod, int hitLoc ) +void NPC_ChoosePainAnimation( gentity_t *self, gentity_t *other, vec3_t point, int damage, int mod, int hitLoc, int voiceEvent = -1 ) { //If we've already taken pain, then don't take it again if ( level.time < self->painDebounceTime && mod != MOD_ELECTROCUTE && mod != MOD_MELEE ) @@ -198,9 +213,19 @@ void NPC_ChoosePainAnimation( gentity_t *self, gentity_t *other, vec3_t point, i int pain_anim = -1; float pain_chance; - if ( self->client->NPC_class == CLASS_GALAKMECH ) + if ( self->s.weapon == WP_THERMAL && self->client->fireDelay > 0 ) + {//don't interrupt thermal throwing anim + return; + } + else if ( self->client->NPC_class == CLASS_GALAKMECH ) { - if ( self->client->ps.powerups[PW_GALAK_SHIELD] ) + if ( hitLoc == HL_GENERIC1 ) + {//hit the antenna! + pain_chance = 1.0f; + self->s.powerups |= ( 1 << PW_SHOCKED ); + self->client->ps.powerups[PW_SHOCKED] = level.time + Q_irand( 500, 2500 ); + } + else if ( self->client->ps.powerups[PW_GALAK_SHIELD] ) {//shield up return; } @@ -227,6 +252,10 @@ void NPC_ChoosePainAnimation( gentity_t *self, gentity_t *other, vec3_t point, i {//higher in rank (skill) we are, less likely we are to be fazed by a punch pain_chance = 1.0f - ((RANK_CAPTAIN-self->NPC->rank)/(float)RANK_CAPTAIN); } + else if ( self->client->NPC_class == CLASS_PROTOCOL ) + { + pain_chance = 1.0f; + } else { pain_chance = NPC_GetPainChance( self, damage ); @@ -284,7 +313,14 @@ void NPC_ChoosePainAnimation( gentity_t *self, gentity_t *other, vec3_t point, i } NPC_SetAnim( self, parts, pain_anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); } - NPC_SetPainEvent( self ); + if ( voiceEvent != -1 ) + { + G_AddVoiceEvent( self, voiceEvent, Q_irand( 2000, 4000 ) ); + } + else + { + NPC_SetPainEvent( self ); + } } else { @@ -309,6 +345,7 @@ NPC_Pain void NPC_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, vec3_t point, int damage, int mod, int hitLoc ) { team_t otherTeam = TEAM_FREE; + int voiceEvent = -1; if ( self->NPC == NULL ) return; @@ -333,7 +370,10 @@ void NPC_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, vec3_t p // } } - if ( self->client->playerTeam && other->client && otherTeam == self->client->playerTeam && (!player->client->ps.viewEntity || other->s.number != player->client->ps.viewEntity)) + if ( self->client->playerTeam + && other->client + && otherTeam == self->client->playerTeam + && (!player->client->ps.viewEntity || other->s.number != player->client->ps.viewEntity)) {//hit by a teammate if ( other != self->enemy && self != other->enemy ) {//we weren't already enemies @@ -357,24 +397,48 @@ void NPC_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, vec3_t p if ( damage != -1 ) {//-1 == don't play pain anim //Set our proper pain animation - NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc ); + if ( Q_irand( 0, 1 ) ) + { + NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, EV_FFWARN ); + } + else + { + NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc ); + } } return; } else if ( self->NPC && !other->s.number )//should be assumed, but... {//dammit, stop that! - if ( self->NPC->ffireCount < 3+((2-g_spskill->integer)*2) ) + if ( self->NPC->charmedTime ) + {//mindtricked + return; + } + else if ( self->NPC->ffireCount < 3+((2-g_spskill->integer)*2) ) {//not mad enough yet //Com_Printf( "chck: %d < %d\n", self->NPC->ffireCount, 3+((2-g_spskill->integer)*2) ); if ( damage != -1 ) {//-1 == don't play pain anim //Set our proper pain animation - NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc ); + if ( Q_irand( 0, 1 ) ) + { + NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, EV_FFWARN ); + } + else + { + NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc ); + } } return; } + else if ( G_ActivateBehavior( self, BSET_FFIRE ) ) + {//we have a specific script to run, so do that instead + return; + } else - {//okay, we're going to turn on our ally, we need to + {//okay, we're going to turn on our ally, we need to set and lock our enemy and put ourselves in a bstate that lets us attack him (and clear any flags that would stop us) + self->NPC->blockedSpeechDebounceTime = 0; + voiceEvent = EV_FFTURN; self->NPC->behaviorState = self->NPC->tempBehavior = self->NPC->defaultBehavior = BS_DEFAULT; other->flags &= ~FL_NOTARGET; self->svFlags &= ~(SVF_IGNORE_ENEMIES|SVF_ICARUS_FREEZE|SVF_NO_COMBAT_SOUNDS); @@ -382,7 +446,12 @@ void NPC_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, vec3_t p self->svFlags |= SVF_LOCKEDENEMY; self->NPC->scriptFlags &= ~(SCF_DONT_FIRE|SCF_CROUCHED|SCF_WALKING|SCF_NO_COMBAT_TALK|SCF_FORCED_MARCH); self->NPC->scriptFlags |= (SCF_CHASE_ENEMIES|SCF_NO_MIND_TRICK); + //NOTE: we also stop ICARUS altogether stop_icarus = qtrue; + if ( !killPlayerTimer ) + { + killPlayerTimer = level.time + 10000; + } } } } @@ -394,34 +463,21 @@ void NPC_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, vec3_t p //Do extra bits if ( NPCInfo->ignorePain == qfalse ) { - if ( NPCInfo->charmedTime && NPCInfo->charmedTime < level.time && NPC->client ) - {//charmed enemy - team_t saveTeam = NPC->client->enemyTeam; - NPC->client->enemyTeam = NPC->client->playerTeam; - NPC->client->playerTeam = saveTeam; - NPC->client->leader = NULL; - if ( NPCInfo->tempBehavior == BS_FOLLOW_LEADER ) - { - NPCInfo->tempBehavior = BS_DEFAULT; - } - G_ClearEnemy( NPC ); - } - NPCInfo->charmedTime = NPCInfo->confusionTime = 0;//clear any charm or confusion, regardless - //Check to take a new enemy - if ( NPC->enemy != other ) - {//not already mad at them - NPC_CheckAttacker( other, mod ); - } - + NPCInfo->confusionTime = 0;//clear any charm or confusion, regardless if ( damage != -1 ) {//-1 == don't play pain anim //Set our proper pain animation - NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc ); + NPC_ChoosePainAnimation( self, other, point, damage, mod, hitLoc, voiceEvent ); + } + //Check to take a new enemy + if ( NPC->enemy != other && NPC != other ) + {//not already mad at them + NPC_CheckAttacker( other, mod ); } } //Attempt to run any pain instructions - if(self->client && self->NPC) + if ( self->client && self->NPC ) { //FIXME: This needs better heuristics perhaps if(self->health <= (self->max_health/3) && G_ActivateBehavior(self, BSET_FLEE) ) @@ -468,6 +524,7 @@ void NPC_Touch(gentity_t *self, gentity_t *other, trace_t *trace) if ( (keyTaken = INV_GoodieKeyGive( other )) == qtrue ) { text = "cp @INGAME_TOOK_IMPERIAL_GOODIE_KEY"; + G_AddEvent( other, EV_ITEM_PICKUP, (FindItemForInventory( INV_GOODIE_KEY )-bg_itemlist) ); } else { @@ -479,6 +536,7 @@ void NPC_Touch(gentity_t *self, gentity_t *other, trace_t *trace) if ( (keyTaken = INV_SecurityKeyGive( player, self->message )) == qtrue ) { text = "cp @INGAME_TOOK_IMPERIAL_SECURITY_KEY"; + G_AddEvent( other, EV_ITEM_PICKUP, (FindItemForInventory( INV_SECURITY_KEY )-bg_itemlist) ); } else { @@ -534,12 +592,20 @@ void NPC_Touch(gentity_t *self, gentity_t *other, trace_t *trace) /* if ( other->s.number == 0 && self->client->playerTeam == other->client->playerTeam ) { - VectorAdd( self->s.pushVec, other->client->ps.velocity, self->s.pushVec ); + VectorAdd( self->client->pushVec, other->client->ps.velocity, self->client->pushVec ); } */ } else {//FIXME: check for SVF_NONNPC_ENEMY flag here? + if ( other->health > 0 ) + { + if ( NPC->enemy == other && (other->svFlags&SVF_NONNPC_ENEMY) ) + { + NPCInfo->touchedByPlayer = other; + } + } + if ( other == NPCInfo->goalEntity ) { NPCInfo->aiFlags |= NPCAI_TOUCHED_GOAL; @@ -581,8 +647,8 @@ void NPC_TempLookTarget( gentity_t *self, int lookEntNum, int minLookTime, int m void NPC_Respond( gentity_t *self, int userNum ) { + int event = -1; /* - int event; if ( Q_irand( 0, 1 ) ) { @@ -599,42 +665,234 @@ void NPC_Respond( gentity_t *self, int userNum ) NPC_TempLookTarget( self, userNum, 1000, 3000 ); } - //G_AddVoiceEvent( self, event, 3000 ); -} - -void WaitNPCRespond ( gentity_t *self ) -{ - //make sure the responding ent is still valid - if ( !self->enemy || !self->enemy->client || !self->enemy->NPC ) + //some last-minute hacked in responses + switch ( self->client->NPC_class ) { - G_FreeEntity( self ); - return; + case CLASS_JAN: + if ( self->enemy ) + { + if ( !Q_irand( 0, 2 ) ) + { + event = Q_irand( EV_CHASE1, EV_CHASE3 ); + } + else if ( Q_irand( 0, 1 ) ) + { + event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 ); + } + else + { + event = Q_irand( EV_COVER1, EV_COVER5 ); + } + } + else if ( !Q_irand( 0, 2 ) ) + { + event = EV_SUSPICIOUS4; + } + else if ( !Q_irand( 0, 1 ) ) + { + event = EV_SOUND1; + } + else + { + event = EV_CONFUSE1; + } + break; + case CLASS_LANDO: + if ( self->enemy ) + { + if ( !Q_irand( 0, 2 ) ) + { + event = Q_irand( EV_CHASE1, EV_CHASE3 ); + } + else if ( Q_irand( 0, 1 ) ) + { + event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 ); + } + else + { + event = Q_irand( EV_COVER1, EV_COVER5 ); + } + } + else if ( !Q_irand( 0, 6 ) ) + { + event = EV_SIGHT2; + } + else if ( !Q_irand( 0, 5 ) ) + { + event = EV_GIVEUP4; + } + else if ( Q_irand( 0, 4 ) > 1 ) + { + event = Q_irand( EV_SOUND1, EV_SOUND3 ); + } + else + { + event = Q_irand( EV_JDETECTED1, EV_JDETECTED2 ); + } + break; + case CLASS_LUKE: + if ( self->enemy ) + { + event = EV_COVER1; + } + else + { + event = Q_irand( EV_SOUND1, EV_SOUND3 ); + } + break; + case CLASS_JEDI: + if ( !self->enemy ) + { + if ( !(self->svFlags&SVF_IGNORE_ENEMIES) + && (self->NPC->scriptFlags&SCF_LOOK_FOR_ENEMIES) + && self->client->enemyTeam == TEAM_ENEMY ) + { + event = Q_irand( EV_ANGER1, EV_ANGER3 ); + } + else + { + event = Q_irand( EV_TAUNT1, EV_TAUNT2 ); + } + } + break; + case CLASS_PRISONER: + if ( self->enemy ) + { + if ( Q_irand( 0, 1 ) ) + { + event = Q_irand( EV_CHASE1, EV_CHASE3 ); + } + else + { + event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 ); + } + } + else + { + event = Q_irand( EV_SOUND1, EV_SOUND3 ); + } + break; + case CLASS_REBEL: + if ( self->enemy ) + { + if ( !Q_irand( 0, 2 ) ) + { + event = Q_irand( EV_CHASE1, EV_CHASE3 ); + } + else + { + event = Q_irand( EV_DETECTED1, EV_DETECTED5 ); + } + } + else + { + event = Q_irand( EV_SOUND1, EV_SOUND3 ); + } + break; + case CLASS_BESPIN_COP: + if ( !Q_stricmp( "bespincop", self->NPC_type ) ) + {//variant 1 + if ( self->enemy ) + { + if ( Q_irand( 0, 9 ) > 6 ) + { + event = Q_irand( EV_CHASE1, EV_CHASE3 ); + } + else if ( Q_irand( 0, 6 ) > 4 ) + { + event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 ); + } + else + { + event = Q_irand( EV_COVER1, EV_COVER5 ); + } + } + else if ( !Q_irand( 0, 3 ) ) + { + event = Q_irand( EV_SIGHT2, EV_SIGHT3 ); + } + else if ( !Q_irand( 0, 1 ) ) + { + event = Q_irand( EV_SOUND1, EV_SOUND3 ); + } + else if ( !Q_irand( 0, 2 ) ) + { + event = EV_LOST1; + } + else if ( !Q_irand( 0, 1 ) ) + { + event = EV_ESCAPING2; + } + else + { + event = EV_GIVEUP4; + } + } + else + {//variant2 + if ( self->enemy ) + { + if ( Q_irand( 0, 9 ) > 6 ) + { + event = Q_irand( EV_CHASE1, EV_CHASE3 ); + } + else if ( Q_irand( 0, 6 ) > 4 ) + { + event = Q_irand( EV_OUTFLANK1, EV_OUTFLANK2 ); + } + else + { + event = Q_irand( EV_COVER1, EV_COVER5 ); + } + } + else if ( !Q_irand( 0, 3 ) ) + { + event = Q_irand( EV_SIGHT1, EV_SIGHT2 ); + } + else if ( !Q_irand( 0, 1 ) ) + { + event = Q_irand( EV_SOUND1, EV_SOUND3 ); + } + else if ( !Q_irand( 0, 2 ) ) + { + event = EV_LOST1; + } + else if ( !Q_irand( 0, 1 ) ) + { + event = EV_GIVEUP3; + } + else + { + event = EV_CONFUSE1; + } + } + break; + case CLASS_R2D2: // droid + G_Sound(self, G_SoundIndex(va("sound/chars/r2d2/misc/r2d2talk0%d.wav",Q_irand(1, 3)))); + break; + case CLASS_R5D2: // droid + G_Sound(self, G_SoundIndex(va("sound/chars/r5d2/misc/r5talk%d.wav",Q_irand(1, 4)))); + break; + case CLASS_MOUSE: // droid + G_Sound(self, G_SoundIndex(va("sound/chars/mouse/misc/mousego%d.wav",Q_irand(1, 3)))); + break; + case CLASS_GONK: // droid + G_Sound(self, G_SoundIndex(va("sound/chars/gonk/misc/gonktalk%d.wav",Q_irand(1, 2)))); + break; } - - if ( gi.VoiceVolume[0] ) - {//player is still talking - self->nextthink = level.time + 500; - //set enemy to not respond for a bit longer - self->enemy->NPC->blockedSpeechDebounceTime = level.time + 1000; - return; - } - - if ( self->enemy->health <= 0 || (!self->alt_fire && (self->enemy->NPC->scriptFlags&SCF_NO_RESPONSE)) ) + + if ( event != -1 ) { - G_FreeEntity( self ); - return; - } + //hack here because we reuse some "combat" and "extra" sounds + qboolean addFlag = (self->NPC->scriptFlags&SCF_NO_COMBAT_TALK); + self->NPC->scriptFlags &= ~SCF_NO_COMBAT_TALK; - //set enemy to be ready to respond - self->enemy->NPC->blockedSpeechDebounceTime = 0; + G_AddVoiceEvent( self, event, 3000 ); - if ( self->alt_fire ) - {//Run the NPC's usescript - G_ActivateBehavior( self->enemy, BSET_USE ); - } - else - {//make them respond generically - NPC_Respond( self->enemy, 0 ); + if ( addFlag ) + { + self->NPC->scriptFlags |= SCF_NO_COMBAT_TALK; + } } } @@ -660,7 +918,7 @@ void NPC_UseResponse( gentity_t *self, gentity_t *user, qboolean useWhenDone ) return; } - if ( user->client && self->client->playerTeam != user->client->playerTeam ) + if ( user->client && self->client->playerTeam != user->client->playerTeam && self->client->playerTeam != TEAM_NEUTRAL ) {//only those on the same team react if ( useWhenDone ) { diff --git a/code/game/NPC_senses.cpp b/code/game/NPC_senses.cpp index 40c3ef0..90be281 100644 --- a/code/game/NPC_senses.cpp +++ b/code/game/NPC_senses.cpp @@ -336,16 +336,20 @@ visibility_t NPC_CheckVisibility ( gentity_t *ent, int flags ) NPC_CheckSoundEvents ------------------------- */ -static int G_CheckSoundEvents( gentity_t *self, float maxHearDist, qboolean mustHaveOwner, int minAlertLevel ) +static int G_CheckSoundEvents( gentity_t *self, float maxHearDist, int ignoreAlert, qboolean mustHaveOwner, int minAlertLevel ) { int bestEvent = -1; int bestAlert = -1; + int bestTime = -1; float dist, radius; maxHearDist *= maxHearDist; for ( int i = 0; i < level.numAlertEvents; i++ ) { + //are we purposely ignoring this alert? + if ( i == ignoreAlert ) + continue; //We're only concerned about sounds if ( level.alertEvents[i].type != AET_SOUND ) continue; @@ -366,24 +370,27 @@ static int G_CheckSoundEvents( gentity_t *self, float maxHearDist, qboolean must if ( dist > radius ) continue; + if ( level.alertEvents[i].addLight ) + {//a quiet sound, must have LOS to hear it + if ( G_ClearLOS( self, level.alertEvents[i].position ) == qfalse ) + {//no LOS, didn't hear it + continue; + } + } + //See if this one takes precedence over the previous one - if ( level.alertEvents[i].level > bestAlert ) - { + if ( level.alertEvents[i].level >= bestAlert //higher alert level + || (level.alertEvents[i].level==bestAlert&&level.alertEvents[i].timestamp >= bestTime) )//same alert level, but this one is newer + {//NOTE: equal is better because it's later in the array bestEvent = i; bestAlert = level.alertEvents[i].level; + bestTime = level.alertEvents[i].timestamp; } } return bestEvent; } -/* -static int NPC_CheckSoundEvents( void ) -{ - return G_CheckSoundEvents( NPC ); -} -*/ - float G_GetLightLevel( vec3_t pos, vec3_t fromDir ) { vec3_t ambient={0}, directed, lightDir; @@ -400,15 +407,19 @@ float G_GetLightLevel( vec3_t pos, vec3_t fromDir ) NPC_CheckSightEvents ------------------------- */ -static int G_CheckSightEvents( gentity_t *self, int hFOV, int vFOV, float maxSeeDist, qboolean mustHaveOwner, int minAlertLevel ) +static int G_CheckSightEvents( gentity_t *self, int hFOV, int vFOV, float maxSeeDist, int ignoreAlert, qboolean mustHaveOwner, int minAlertLevel ) { int bestEvent = -1; int bestAlert = -1; + int bestTime = -1; float dist, radius; maxSeeDist *= maxSeeDist; for ( int i = 0; i < level.numAlertEvents; i++ ) { + //are we purposely ignoring this alert? + if ( i == ignoreAlert ) + continue; //We're only concerned about sounds if ( level.alertEvents[i].type != AET_SIGHT ) continue; @@ -445,22 +456,18 @@ static int G_CheckSightEvents( gentity_t *self, int hFOV, int vFOV, float maxSee // is added to the actual light level at this position? //See if this one takes precedence over the previous one - if ( level.alertEvents[i].level > bestAlert ) - { + if ( level.alertEvents[i].level >= bestAlert //higher alert level + || (level.alertEvents[i].level==bestAlert&&level.alertEvents[i].timestamp >= bestTime) )//same alert level, but this one is newer + {//NOTE: equal is better because it's later in the array bestEvent = i; bestAlert = level.alertEvents[i].level; + bestTime = level.alertEvents[i].timestamp; } } return bestEvent; } -/* -static int NPC_CheckSightEvents( void ) -{ - return G_CheckSightEvents( NPC, NPCInfo->stats.hfov, NPCInfo->stats.vfov ); -} -*/ /* ------------------------- NPC_CheckAlertEvents @@ -469,7 +476,7 @@ NPC_CheckAlertEvents ------------------------- */ -int G_CheckAlertEvents( gentity_t *self, qboolean checkSight, qboolean checkSound, float maxSeeDist, float maxHearDist, qboolean mustHaveOwner, int minAlertLevel ) +int G_CheckAlertEvents( gentity_t *self, qboolean checkSight, qboolean checkSound, float maxSeeDist, float maxHearDist, int ignoreAlert, qboolean mustHaveOwner, int minAlertLevel ) { if ( &g_entities[0] == NULL || g_entities[0].health <= 0 ) { @@ -483,7 +490,7 @@ int G_CheckAlertEvents( gentity_t *self, qboolean checkSight, qboolean checkSoun int bestSightAlert = -1; //get sound event - bestSoundEvent = G_CheckSoundEvents( self, maxHearDist, mustHaveOwner, minAlertLevel ); + bestSoundEvent = G_CheckSoundEvents( self, maxHearDist, ignoreAlert, mustHaveOwner, minAlertLevel ); //get sound event alert level if ( bestSoundEvent >= 0 ) { @@ -493,11 +500,11 @@ int G_CheckAlertEvents( gentity_t *self, qboolean checkSight, qboolean checkSoun //get sight event if ( self->NPC ) { - bestSightEvent = G_CheckSightEvents( self, self->NPC->stats.hfov, self->NPC->stats.vfov, maxSeeDist, mustHaveOwner, minAlertLevel ); + bestSightEvent = G_CheckSightEvents( self, self->NPC->stats.hfov, self->NPC->stats.vfov, maxSeeDist, ignoreAlert, mustHaveOwner, minAlertLevel ); } else { - bestSightEvent = G_CheckSightEvents( self, 80, 80, maxSeeDist, mustHaveOwner, minAlertLevel );//FIXME: look at cg_view to get more accurate numbers? + bestSightEvent = G_CheckSightEvents( self, 80, 80, maxSeeDist, ignoreAlert, mustHaveOwner, minAlertLevel );//FIXME: look at cg_view to get more accurate numbers? } //get sight event alert level if ( bestSightEvent >= 0 ) @@ -522,9 +529,10 @@ int G_CheckAlertEvents( gentity_t *self, qboolean checkSight, qboolean checkSoun //return the sound event return bestSoundEvent; } -int NPC_CheckAlertEvents( qboolean checkSight, qboolean checkSound, qboolean mustHaveOwner, int minAlertLevel ) + +int NPC_CheckAlertEvents( qboolean checkSight, qboolean checkSound, int ignoreAlert, qboolean mustHaveOwner, int minAlertLevel ) { - return G_CheckAlertEvents( NPC, checkSight, checkSound, NPCInfo->stats.visrange, NPCInfo->stats.earshot, mustHaveOwner, minAlertLevel ); + return G_CheckAlertEvents( NPC, checkSight, checkSound, NPCInfo->stats.visrange, NPCInfo->stats.earshot, ignoreAlert, mustHaveOwner, minAlertLevel ); } qboolean G_CheckForDanger( gentity_t *self, int alertEvent ) @@ -568,12 +576,17 @@ qboolean NPC_CheckForDanger( int alertEvent ) AddSoundEvent ------------------------- */ - -void AddSoundEvent( gentity_t *owner, vec3_t position, float radius, alertEventLevel_e alertLevel ) +qboolean RemoveOldestAlert( void ); +void AddSoundEvent( gentity_t *owner, vec3_t position, float radius, alertEventLevel_e alertLevel, qboolean needLOS ) { //FIXME: Handle this in another manner? if ( level.numAlertEvents >= MAX_ALERT_EVENTS ) - return; + { + if ( !RemoveOldestAlert() ) + {//how could that fail? + return; + } + } if ( owner == NULL && alertLevel < AEL_DANGER ) //allows un-owned danger alerts return; @@ -591,7 +604,16 @@ void AddSoundEvent( gentity_t *owner, vec3_t position, float radius, alertEventL level.alertEvents[ level.numAlertEvents ].level = alertLevel; level.alertEvents[ level.numAlertEvents ].type = AET_SOUND; level.alertEvents[ level.numAlertEvents ].owner = owner; + if ( needLOS ) + {//a very low-level sound, when check this sound event, check for LOS + level.alertEvents[ level.numAlertEvents ].addLight = 1; //will force an LOS trace on this sound + } + else + { + level.alertEvents[ level.numAlertEvents ].addLight = 0; //will force an LOS trace on this sound + } level.alertEvents[ level.numAlertEvents ].ID = level.curAlertID++; + level.alertEvents[ level.numAlertEvents ].timestamp = level.time; level.numAlertEvents++; } @@ -606,7 +628,12 @@ void AddSightEvent( gentity_t *owner, vec3_t position, float radius, alertEventL { //FIXME: Handle this in another manner? if ( level.numAlertEvents >= MAX_ALERT_EVENTS ) - return; + { + if ( !RemoveOldestAlert() ) + {//how could that fail? + return; + } + } if ( owner == NULL && alertLevel < AEL_DANGER ) //allows un-owned danger alerts return; @@ -626,6 +653,7 @@ void AddSightEvent( gentity_t *owner, vec3_t position, float radius, alertEventL level.alertEvents[ level.numAlertEvents ].owner = owner; level.alertEvents[ level.numAlertEvents ].addLight = addLight; //will get added to actual light at that point when it's checked level.alertEvents[ level.numAlertEvents ].ID = level.curAlertID++; + level.alertEvents[ level.numAlertEvents ].timestamp = level.time; level.numAlertEvents++; } @@ -638,7 +666,67 @@ ClearPlayerAlertEvents void ClearPlayerAlertEvents( void ) { - level.numAlertEvents = 0; + int curNumAlerts = level.numAlertEvents; + //loop through them all (max 32) + for ( int i = 0; i < curNumAlerts; i++ ) + { + //see if the event is old enough to delete + if ( level.alertEvents[i].timestamp && level.alertEvents[i].timestamp + ALERT_CLEAR_TIME < level.time ) + {//this event has timed out + //drop the count + level.numAlertEvents--; + //shift the rest down + if ( level.numAlertEvents > 0 ) + {//still have more in the array + if ( (i+1) < MAX_ALERT_EVENTS ) + { + memmove( &level.alertEvents[i], &level.alertEvents[i+1], sizeof(alertEvent_t)*(MAX_ALERT_EVENTS-(i+1) ) ); + } + } + else + {//just clear this one... or should we clear the whole array? + memset( &level.alertEvents[i], 0, sizeof( alertEvent_t ) ); + } + } + } + //make sure this never drops below zero... if it does, something very very bad happened + assert( level.numAlertEvents >= 0 ); +} + +qboolean RemoveOldestAlert( void ) +{ + int oldestEvent = -1, oldestTime = Q3_INFINITE; + //loop through them all (max 32) + for ( int i = 0; i < level.numAlertEvents; i++ ) + { + //see if the event is old enough to delete + if ( level.alertEvents[i].timestamp < oldestTime ) + { + oldestEvent = i; + oldestTime = level.alertEvents[i].timestamp; + } + } + if ( oldestEvent != -1 ) + { + //drop the count + level.numAlertEvents--; + //shift the rest down + if ( level.numAlertEvents > 0 ) + {//still have more in the array + if ( (oldestEvent+1) < MAX_ALERT_EVENTS ) + { + memmove( &level.alertEvents[oldestEvent], &level.alertEvents[oldestEvent+1], sizeof(alertEvent_t)*(MAX_ALERT_EVENTS-(oldestEvent+1) ) ); + } + } + else + {//just clear this one... or should we clear the whole array? + memset( &level.alertEvents[oldestEvent], 0, sizeof( alertEvent_t ) ); + } + } + //make sure this never drops below zero... if it does, something very very bad happened + assert( level.numAlertEvents >= 0 ); + //return true is have room for one now + return (level.numAlertEventsNPC->scriptFlags&SCF_NO_ALERT_TALK) && (event >= EV_GIVEUP1 && event <= EV_SUSPICIOUS5) ) + { + return; + } //FIXME: Also needs to check for teammates. Don't want // everyone babbling at once @@ -65,3 +69,32 @@ void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ) //won't speak again for 5 seconds (unless otherwise specified) self->NPC->blockedSpeechDebounceTime = level.time + ((speakDebounceTime==0) ? 5000 : speakDebounceTime); } + +void NPC_PlayConfusionSound( gentity_t *self ) +{ + if ( self->health > 0 ) + { + if ( self->enemy ||//was mad + !TIMER_Done( self, "enemyLastVisible" ) ||//saw something suspicious + self->client->renderInfo.lookTarget == 0//was looking at player + ) + { + self->NPC->blockedSpeechDebounceTime = 0;//make sure we say this + G_AddVoiceEvent( self, Q_irand( EV_CONFUSE2, EV_CONFUSE3 ), 2000 ); + } + else if ( self->NPC && self->NPC->investigateDebounceTime+self->NPC->pauseTime > level.time )//was checking something out + { + self->NPC->blockedSpeechDebounceTime = 0;//make sure we say this + G_AddVoiceEvent( self, EV_CONFUSE1, 2000 ); + } + //G_AddVoiceEvent( self, Q_irand(EV_CONFUSE1, EV_CONFUSE3), 2000 ); + } + //reset him to be totally unaware again + TIMER_Set( self, "enemyLastVisible", 0 ); + self->NPC->tempBehavior = BS_DEFAULT; + + //self->NPC->behaviorState = BS_PATROL; + G_ClearEnemy( self );//FIXME: or just self->enemy = NULL;? + + self->NPC->investigateCount = 0; +} diff --git a/code/game/NPC_spawn.cpp b/code/game/NPC_spawn.cpp index 001f05a..e16ee36 100644 --- a/code/game/NPC_spawn.cpp +++ b/code/game/NPC_spawn.cpp @@ -56,6 +56,8 @@ extern void NPC_Mark1_Precache(void); extern void NPC_Mark2_Precache(void); extern void NPC_GalakMech_Precache( void ); extern void NPC_GalakMech_Init( gentity_t *ent ); +extern void NPC_Protocol_Precache( void ); +extern int WP_SetSaberModel( gclient_t *client, class_t npcClass ); #define NSF_DROP_TO_FLOOR 16 @@ -439,7 +441,7 @@ int NPC_WeaponsForTeam( team_t team, int spawnflags, const char *NPC_type ) { return ( 1 << WP_BLASTER_PISTOL); } - if ( Q_stricmp( "impworker", NPC_type ) == 0 ) + if ( Q_strncmp( "impworker", NPC_type, 9 ) == 0 ) { return ( 1 << WP_BLASTER_PISTOL); } @@ -455,14 +457,10 @@ int NPC_WeaponsForTeam( team_t team, int spawnflags, const char *NPC_type ) { return ( 1 << WP_REPEATER); } - if ( Q_stricmp( "ugnaught", NPC_type ) == 0 ) + if ( Q_strncmp( "ugnaught", NPC_type, 8 ) == 0 ) { return WP_NONE; } - if ( Q_strncmp( "gran", NPC_type, 4 ) == 0 ) - { - return (( 1 << WP_THERMAL)|( 1 << WP_MELEE)); - } if ( Q_stricmp( "granshooter", NPC_type ) == 0 ) { return ( 1 << WP_BLASTER); @@ -471,6 +469,10 @@ int NPC_WeaponsForTeam( team_t team, int spawnflags, const char *NPC_type ) { return ( 1 << WP_MELEE); } + if ( Q_strncmp( "gran", NPC_type, 4 ) == 0 ) + { + return (( 1 << WP_THERMAL)|( 1 << WP_MELEE)); + } if ( Q_stricmp( "rodian", NPC_type ) == 0 ) { return ( 1 << WP_DISRUPTOR); @@ -485,7 +487,7 @@ int NPC_WeaponsForTeam( team_t team, int spawnflags, const char *NPC_type ) return WP_NONE; } - if ( Q_stricmp( "weequay", NPC_type ) == 0 ) + if ( Q_strncmp( "weequay", NPC_type, 7 ) == 0 ) { return ( 1 << WP_BOWCASTER);//|( 1 << WP_STAFF )(FIXME: new weap?) } @@ -547,11 +549,11 @@ int NPC_WeaponsForTeam( team_t team, int spawnflags, const char *NPC_type ) if ( Q_strncmp( "jedi", NPC_type, 4 ) == 0 || Q_stricmp( "luke", NPC_type ) == 0 ) return ( 1 << WP_SABER); - if ( Q_stricmp( "prisoner", NPC_type ) == 0 ) + if ( Q_strncmp( "prisoner", NPC_type, 8 ) == 0 ) { return WP_NONE; } - if ( Q_stricmp( "bespincop", NPC_type ) == 0 ) + if ( Q_strncmp( "bespincop", NPC_type, 9 ) == 0 ) { return ( 1 << WP_BLASTER_PISTOL); } @@ -575,7 +577,7 @@ int NPC_WeaponsForTeam( team_t team, int spawnflags, const char *NPC_type ) { return WP_NONE; } - if ( Q_stricmp( "ugnaught", NPC_type ) == 0 ) + if ( Q_strncmp( "ugnaught", NPC_type, 8 ) == 0 ) { return WP_NONE; } @@ -822,15 +824,16 @@ void NPC_Begin (gentity_t *ent) } else if ( ent->NPC->stats.health ) // Was health supplied in NPC.cfg? { - /* - if ( ent->client->NPC_class == CLASS_REBORN - || ent->client->NPC_class == CLASS_SHADOWTROOPER - || ent->client->NPC_class == CLASS_TAVION - || ent->client->NPC_class == CLASS_DESANN ) - {//hmm, up Jedi - ent->NPC->stats.health += ent->NPC->stats.health/2 * g_spskill->integer; + + if ( ent->client->NPC_class != CLASS_REBORN + && ent->client->NPC_class != CLASS_SHADOWTROOPER + //&& ent->client->NPC_class != CLASS_TAVION + //&& ent->client->NPC_class != CLASS_DESANN + && ent->client->NPC_class != CLASS_JEDI ) + {// up everyone except jedi + ent->NPC->stats.health += ent->NPC->stats.health/4 * g_spskill->integer; // 100% on easy, 125% on medium, 150% on hard } - */ + ent->max_health = client->pers.maxHealth = client->ps.stats[STAT_MAX_HEALTH] = ent->NPC->stats.health; } else @@ -838,7 +841,23 @@ void NPC_Begin (gentity_t *ent) ent->max_health = client->pers.maxHealth = client->ps.stats[STAT_MAX_HEALTH] = 100; } - if ( ent->client->NPC_class == CLASS_STORMTROOPER + if ( !Q_stricmp( "rodian", ent->NPC_type ) ) + {//sniper + //NOTE: this will get overridden by any aim settings in their spawnscripts + switch ( g_spskill->integer ) + { + case 0: + ent->NPC->stats.aim = 1; + break; + case 1: + ent->NPC->stats.aim = Q_irand( 2, 3 ); + break; + case 2: + ent->NPC->stats.aim = Q_irand( 3, 4 ); + break; + } + } + else if ( ent->client->NPC_class == CLASS_STORMTROOPER || ent->client->NPC_class == CLASS_SWAMPTROOPER || ent->client->NPC_class == CLASS_IMPWORKER || !Q_stricmp( "rodian2", ent->NPC_type ) ) @@ -847,6 +866,33 @@ void NPC_Begin (gentity_t *ent) { case 0: ent->NPC->stats.yawSpeed *= 0.75f; + if ( ent->client->NPC_class == CLASS_IMPWORKER ) + { + ent->NPC->stats.aim -= Q_irand( 3, 6 ); + } + break; + case 1: + if ( ent->client->NPC_class == CLASS_IMPWORKER ) + { + ent->NPC->stats.aim -= Q_irand( 2, 4 ); + } + break; + case 2: + ent->NPC->stats.yawSpeed *= 1.5f; + if ( ent->client->NPC_class == CLASS_IMPWORKER ) + { + ent->NPC->stats.aim -= Q_irand( 0, 2 ); + } + break; + } + } + else if ( ent->client->NPC_class == CLASS_REBORN + || ent->client->NPC_class == CLASS_SHADOWTROOPER ) + { + switch ( g_spskill->integer ) + { + case 1: + ent->NPC->stats.yawSpeed *= 1.25f; break; case 2: ent->NPC->stats.yawSpeed *= 1.5f; @@ -854,6 +900,7 @@ void NPC_Begin (gentity_t *ent) } } + ent->s.groundEntityNum = ENTITYNUM_NONE; ent->mass = 10; ent->takedamage = qtrue; @@ -1011,6 +1058,17 @@ void NPC_Begin (gentity_t *ent) ClientThink( ent->s.number, &ucmd ); gi.linkentity( ent ); + + if ( ent->client->playerTeam == TEAM_ENEMY ) + {//valid enemy spawned + if ( !(ent->spawnflags&SFB_CINEMATIC) && ent->NPC->behaviorState != BS_CINEMATIC ) + {//not a cinematic enemy + if ( g_entities[0].client ) + { + g_entities[0].client->sess.missionStats.enemiesSpawned++; + } + } + } } gNPC_t *New_NPC_t() @@ -1242,9 +1300,10 @@ void NPC_Spawn_Go( gentity_t *ent ) newent->health = ent->health; newent->script_targetname = ent->NPC_targetname; newent->targetname = ent->NPC_targetname; - newent->target = ent->NPC_target; - newent->target2 = ent->target2; - newent->target3 = ent->target3; + newent->target = ent->NPC_target;//death + newent->target2 = ent->target2;//knocked out death + newent->target3 = ent->target3;//??? + newent->target4 = ent->target4;//ffire death newent->wait = ent->wait; for( index = BSET_FIRST; index < NUM_BSETS; index++) @@ -1297,8 +1356,18 @@ void NPC_Spawn_Go( gentity_t *ent ) } //FIXME: copy cameraGroup, store mine in message or other string field - // allow to ride movers - newent->s.pos.trType = TR_GRAVITY; + //set origin + newent->s.pos.trType = TR_INTERPOLATE; + newent->s.pos.trTime = level.time; + VectorCopy( newent->currentOrigin, newent->s.pos.trBase ); + VectorClear( newent->s.pos.trDelta ); + newent->s.pos.trDuration = 0; + //set angles + newent->s.apos.trType = TR_INTERPOLATE; + newent->s.apos.trTime = level.time; + VectorCopy( newent->currentOrigin, newent->s.apos.trBase ); + VectorClear( newent->s.apos.trDelta ); + newent->s.apos.trDuration = 0; newent->NPC->combatPoint = -1; @@ -1450,6 +1519,7 @@ wait - if trying to spawn and blocked, how many seconds to wait before trying ag NPC_targetname - NPC's targetname AND script_targetname NPC_target - NPC's target to fire when killed NPC_target2 - NPC's target to fire when knocked out +NPC_target4 - NPC's target to fire when killed by friendly fire NPC_type - type of NPC ("Borg" (default), "Xian", etc) health - starting health (default = 100) @@ -1489,6 +1559,7 @@ first and so no scripts should be names with these names: delay - after spawned or triggered, how many seconds to wait to spawn the NPC */ //void NPC_PrecacheModels ( char *NPCName ); +extern qboolean spawning; // the G_Spawn*() functions are valid (only turned on during one function) void SP_NPC_spawner( gentity_t *self) { extern void NPC_PrecacheAnimationCFG( const char *NPC_type ); @@ -1543,7 +1614,7 @@ void SP_NPC_spawner( gentity_t *self) //We have to load the animation.cfg now because spawnscripts are going to want to set anims and we need to know their length and if they're valid NPC_PrecacheAnimationCFG( self->NPC_type ); - if(self->targetname) + if ( self->targetname ) {//Wait for triggering self->e_UseFunc = useF_NPC_Spawn; self->svFlags |= SVF_NPC_PRECACHE;//FIXME: precache my weapons somehow? @@ -1552,7 +1623,16 @@ void SP_NPC_spawner( gentity_t *self) } else { - NPC_Spawn (self, self, self); + //NOTE: auto-spawners never check for shy spawning + if ( spawning ) + {//in entity spawn stage - map starting up + self->e_ThinkFunc = thinkF_NPC_Spawn_Go; + self->nextthink = level.time + START_TIME_REMOVE_ENTS + 50; + } + else + {//else spawn right now + NPC_Spawn( self, self, self ); + } } //FIXME: store cameraGroup somewhere else and apply to spawned NPCs' cameraGroup @@ -1644,7 +1724,9 @@ void SP_NPC_Kyle( gentity_t *self) { self->NPC_type = "Kyle"; - SP_NPC_spawner(self); + WP_SetSaberModel( NULL, CLASS_KYLE ); + + SP_NPC_spawner( self ); } /*QUAKED NPC_Lando(1 0 0) (-16 -16 -24) (16 16 40) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY @@ -1686,6 +1768,8 @@ void SP_NPC_Luke( gentity_t *self) { self->NPC_type = "Luke"; + WP_SetSaberModel( NULL, CLASS_LUKE ); + SP_NPC_spawner( self ); } @@ -1714,6 +1798,8 @@ void SP_NPC_Tavion( gentity_t *self) { self->NPC_type = "Tavion"; + WP_SetSaberModel( NULL, CLASS_TAVION ); + SP_NPC_spawner( self ); } @@ -1766,6 +1852,8 @@ void SP_NPC_Desann( gentity_t *self) { self->NPC_type = "Desann"; + WP_SetSaberModel( NULL, CLASS_DESANN ); + SP_NPC_spawner( self ); } @@ -1838,6 +1926,7 @@ void SP_NPC_Jedi( gentity_t *self) } } + WP_SetSaberModel( NULL, CLASS_JEDI ); SP_NPC_spawner( self ); } @@ -1972,7 +2061,14 @@ void SP_NPC_Ugnaught( gentity_t *self) { if ( !self->NPC_type ) { - self->NPC_type = "Ugnaught"; + if ( Q_irand( 0, 1 ) ) + { + self->NPC_type = "Ugnaught"; + } + else + { + self->NPC_type = "Ugnaught2"; + } } SP_NPC_spawner( self ); @@ -2054,7 +2150,21 @@ void SP_NPC_Weequay( gentity_t *self) { if ( !self->NPC_type ) { - self->NPC_type = "Weequay"; + switch ( Q_irand( 0, 3 ) ) + { + case 0: + self->NPC_type = "Weequay"; + break; + case 1: + self->NPC_type = "Weequay2"; + break; + case 2: + self->NPC_type = "Weequay3"; + break; + case 3: + self->NPC_type = "Weequay4"; + break; + } } SP_NPC_spawner( self ); @@ -2138,7 +2248,14 @@ void SP_NPC_Imperial( gentity_t *self) if ( self->message ) {//may drop a key, precache the key model and pickup sound G_SoundIndex( "sound/weapons/key_pkup.wav" ); - RegisterItem( FindItemForInventory( INV_SECURITY_KEY1 ) ); + if ( !Q_stricmp( "goodie", self->message ) ) + { + RegisterItem( FindItemForInventory( INV_GOODIE_KEY ) ); + } + else + { + RegisterItem( FindItemForInventory( INV_SECURITY_KEY ) ); + } } SP_NPC_spawner( self ); } @@ -2238,6 +2355,7 @@ void SP_NPC_Reborn( gentity_t *self) } } + WP_SetSaberModel( NULL, CLASS_REBORN ); SP_NPC_spawner( self ); } @@ -2263,7 +2381,7 @@ void SP_NPC_ShadowTrooper( gentity_t *self) } NPC_ShadowTrooper_Precache(); - RegisterItem( FindItemForAmmo( AMMO_FORCE ) ); + WP_SetSaberModel( NULL, CLASS_SHADOWTROOPER ); SP_NPC_spawner( self ); } @@ -2433,8 +2551,6 @@ void SP_NPC_Droid_Probe( gentity_t *self) SP_NPC_spawner( self ); - RegisterItem( FindItemForWeapon( WP_BRYAR_PISTOL ) ); - NPC_Probe_Precache(); } @@ -2474,8 +2590,6 @@ void SP_NPC_Droid_Mark2( gentity_t *self) SP_NPC_spawner( self ); NPC_Mark2_Precache(); - RegisterItem( FindItemForAmmo( AMMO_BLASTER )); - RegisterItem( FindItemForAmmo( AMMO_METAL_BOLTS)); } /*QUAKED NPC_Droid_ATST (1 0 0) (-40 -40 -24) (40 40 248) x x x x DROPTOFLOOR CINEMATIC NOTSOLID STARTINSOLID SHY @@ -2667,6 +2781,7 @@ void SP_NPC_Droid_Protocol( gentity_t *self) } SP_NPC_spawner( self ); + NPC_Protocol_Precache(); } @@ -2787,9 +2902,16 @@ static void NPC_Spawn_f(void) { NPC_Sentry_Precache(); } + else if ( !Q_stricmp( "protocol", NPCspawner->NPC_type )) + { + NPC_Protocol_Precache(); + } + else if ( !Q_stricmp( "galak_mech", NPCspawner->NPC_type )) + { + NPC_GalakMech_Precache(); + } - - NPC_Spawn (NPCspawner, NPCspawner, NPCspawner); + NPC_Spawn( NPCspawner, NPCspawner, NPCspawner ); } /* diff --git a/code/game/NPC_utils.cpp b/code/game/NPC_utils.cpp index bae02ac..171ab5b 100644 --- a/code/game/NPC_utils.cpp +++ b/code/game/NPC_utils.cpp @@ -27,6 +27,7 @@ Added: Uses shootAngles if a NPC has them */ extern void ViewHeightFix(const gentity_t *const ent); extern void AddLeanOfs(const gentity_t *const ent, vec3_t point); +extern void SubtractLeanOfs(const gentity_t *const ent, vec3_t point); void CalcEntitySpot ( const gentity_t *ent, const spot_t spot, vec3_t point ) { vec3_t forward, up, right; @@ -67,6 +68,10 @@ void CalcEntitySpot ( const gentity_t *ent, const spot_t spot, vec3_t point ) point[0] = ent->currentOrigin[0]; point[1] = ent->currentOrigin[1]; } + else if ( !ent->s.number ) + { + SubtractLeanOfs( ent, point ); + } } else { @@ -99,6 +104,10 @@ void CalcEntitySpot ( const gentity_t *ent, const spot_t spot, vec3_t point ) point[0] = ent->currentOrigin[0]; point[1] = ent->currentOrigin[1]; } + else if ( !ent->s.number ) + { + SubtractLeanOfs( ent, point ); + } //NOTE: automatically takes leaning into account! } else @@ -108,7 +117,7 @@ void CalcEntitySpot ( const gentity_t *ent, const spot_t spot, vec3_t point ) { point[2] += ent->client->ps.viewheight; } - AddLeanOfs ( ent, point ); + //AddLeanOfs ( ent, point ); } break; @@ -178,6 +187,7 @@ Does not include "aim" in it's calculations FIXME: stop compressing angles into shorts!!!! */ +extern cvar_t *g_timescale; qboolean NPC_UpdateAngles ( qboolean doPitch, qboolean doYaw ) { #if 1 @@ -226,6 +236,12 @@ qboolean NPC_UpdateAngles ( qboolean doPitch, qboolean doYaw ) { yawSpeed = NPCInfo->stats.yawSpeed; } + + if ( (NPC->client->NPC_class == CLASS_TAVION||NPC->client->NPC_class == CLASS_DESANN) + && NPC->client->ps.forcePowersActive&(1<value; + } if( doYaw ) { @@ -901,6 +917,10 @@ qboolean NPC_ValidEnemy( gentity_t *ent ) if ( ent == NULL ) return qfalse; + //Must not be me + if ( ent == NPC ) + return qfalse; + //Must not be deleted if ( ent->inuse == qfalse ) return qfalse; @@ -1075,7 +1095,7 @@ gentity_t *NPC_PickEnemyExt( qboolean checkAlerts = qfalse ) if ( checkAlerts ) { - int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, qtrue, AEL_DISCOVERED ); + int alertEvent = NPC_CheckAlertEvents( qtrue, qtrue, -1, qtrue, AEL_DISCOVERED ); //There is an event to look at if ( alertEvent >= 0 ) @@ -1232,7 +1252,14 @@ qboolean NPC_FacePosition( vec3_t position, qboolean doPitch ) qboolean facing = qtrue; //Get the positions - CalcEntitySpot( NPC, SPOT_HEAD_LEAN, muzzle );//SPOT_HEAD + if ( NPC->client && NPC->client->NPC_class == CLASS_GALAKMECH ) + { + CalcEntitySpot( NPC, SPOT_WEAPON, muzzle ); + } + else + { + CalcEntitySpot( NPC, SPOT_HEAD_LEAN, muzzle );//SPOT_HEAD + } //Find the desired angles vec3_t angles; @@ -1394,3 +1421,30 @@ qboolean NPC_CheckLookTarget( gentity_t *self ) return qfalse; } +/* +------------------------- +NPC_CheckCharmed +------------------------- +*/ +extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); +void NPC_CheckCharmed( void ) +{ + if ( NPC->client->playerTeam == TEAM_PLAYER && NPCInfo->charmedTime && NPCInfo->charmedTime < level.time && NPC->client ) + {//we were charmed, set us back! + //NOTE: presumptions here... + team_t savTeam = NPC->client->enemyTeam; + NPC->client->enemyTeam = NPC->client->playerTeam; + NPC->client->playerTeam = savTeam; + NPC->client->leader = NULL; + if ( NPCInfo->tempBehavior == BS_FOLLOW_LEADER ) + { + NPCInfo->tempBehavior = BS_DEFAULT; + } + G_ClearEnemy( NPC ); + NPCInfo->charmedTime = 0; + //say something to let player know you've snapped out of it + G_AddVoiceEvent( NPC, Q_irand(EV_CONFUSE1, EV_CONFUSE3), 2000 ); + } + +} + diff --git a/code/game/Q3_Interface.cpp b/code/game/Q3_Interface.cpp index f1eadaf..2433353 100644 --- a/code/game/Q3_Interface.cpp +++ b/code/game/Q3_Interface.cpp @@ -56,7 +56,6 @@ extern int BMS_MID; extern int BMS_END; extern cvar_t *g_skippingcin; - extern qboolean stop_icarus; #define stringIDExpand(str, strEnum) str, strEnum, ENUM2STRING(strEnum) @@ -155,6 +154,18 @@ stringID_table_t eventTable[] = "", EV_BAD, }; +stringID_table_t DMSTable[] = +{ + "NULL",-1, + ENUM2STRING(DM_AUTO), //# let the game determine the dynamic music as normal + ENUM2STRING(DM_SILENCE), //# stop the music + ENUM2STRING(DM_EXPLORE), //# force the exploration music to play + ENUM2STRING(DM_ACTION), //# force the action music to play + ENUM2STRING(DM_BOSS), //# force the boss battle music to play (if there is any) + ENUM2STRING(DM_DEATH), //# force the "player dead" music to play + "", -1 +}; + stringID_table_t setTable[] = { ENUM2STRING(SET_SPAWNSCRIPT),//0 @@ -230,6 +241,7 @@ stringID_table_t setTable[] = ENUM2STRING(SET_FORCED_MARCH), ENUM2STRING(SET_NO_RESPONSE), ENUM2STRING(SET_NO_COMBAT_TALK), + ENUM2STRING(SET_NO_ALERT_TALK), ENUM2STRING(SET_UNDYING), ENUM2STRING(SET_TREASONED), ENUM2STRING(SET_DISABLE_SHADER_ANIM), @@ -287,6 +299,7 @@ stringID_table_t setTable[] = ENUM2STRING(SET_GREET_ALLIES), ENUM2STRING(SET_PLAYER_LOCKED), ENUM2STRING(SET_LOCK_PLAYER_WEAPONS), + ENUM2STRING(SET_NO_IMPACT_DAMAGE), ENUM2STRING(SET_PARM1), ENUM2STRING(SET_PARM2), ENUM2STRING(SET_PARM3), @@ -362,6 +375,11 @@ stringID_table_t setTable[] = ENUM2STRING(SET_NO_FALLTODEATH), ENUM2STRING(SET_DISMEMBERABLE), ENUM2STRING(SET_NO_ACROBATICS), + ENUM2STRING(SET_MUSIC_STATE), + ENUM2STRING(SET_USE_SUBTITLES), + ENUM2STRING(SET_CLEAN_DAMAGING_ENTS), + ENUM2STRING(SET_HUD), + //FIXME: add BOTH_ attributes here too "", SET_, }; @@ -735,15 +753,25 @@ static void Q3_SetObjective(const char *ObjEnum, int status) Q3_SetMissionFailed ------------------------- */ +extern void G_PlayerGuiltDeath( void ); static void Q3_SetMissionFailed(const char *TextEnum) { gentity_t *ent = &g_entities[0]; + if ( ent->health >= 0 ) + { + G_PlayerGuiltDeath(); + } ent->health = 0; + //FIXME: what about other NPCs? Scripts? // statusTextIndex is looked at on the client side. statusTextIndex = GetIDForString( missionFailedTable, TextEnum ); - + cg.missionStatusShow = qtrue; + if ( ent->client ) + {//hold this screen up for at least 2 seconds + ent->client->respawnTime = level.time + 2000; + } } /* @@ -785,7 +813,6 @@ static void Q3_ObjectiveClearAll(void) { client = &level.clients[0]; memset(client->sess.mission_objectives,0,sizeof(client->sess.mission_objectives)); - memset(client->tourSess.tour_objectives,0,sizeof(client->tourSess.tour_objectives)); } /* @@ -1001,7 +1028,8 @@ static int Q3_PlaySound( int taskID, int entID, const char *name, const char *ch ) // paranoia towards project end { // Text on - if (g_subtitles->integer == 1) // Show all text + // certain NPC's we always want to use subtitles regardless of subtitle setting + if (g_subtitles->integer == 1 || (ent->NPC && (ent->NPC->scriptFlags & SCF_USE_SUBTITLES) ) ) // Show all text { if ( in_camera) // Cinematic { @@ -1444,16 +1472,19 @@ void Blocked_Mover( gentity_t *ent, gentity_t *other ) { // remove anything other than a client -- no longer the case // don't remove security keys or goodie keys - if ( (other->s.eType == ET_ITEM) && (other->item->giTag >= INV_GOODIE_KEY1 && other->item->giTag <= INV_SECURITY_KEY5) ) + if ( (other->s.eType == ET_ITEM) && (other->item->giTag >= INV_GOODIE_KEY && other->item->giTag <= INV_SECURITY_KEY) ) { // should we be doing anything special if a key blocks it... move it somehow..? } // if your not a client, or your a dead client remove yourself... else if ( other->s.number && (!other->client || (other->client && other->health <= 0 && other->contents == CONTENTS_CORPSE && !other->message)) ) { - // if an item or weapon can we do a little explosion..? - G_FreeEntity( other ); - return; + if ( !other->taskManager || !other->taskManager->IsRunning() ) + { + // if an item or weapon can we do a little explosion..? + G_FreeEntity( other ); + return; + } } if ( ent->damage ) { @@ -1837,7 +1868,7 @@ static void Q3_Lerp2Angles( int taskID, int entID, vec3_t angles, float duration Q3_TaskIDSet( ent, TID_ANGLE_FACE, taskID ); - ent->e_ReachedFunc = reachedF_NULL; + //ent->e_ReachedFunc = reachedF_NULL; ent->e_ThinkFunc = thinkF_anglerCallback; ent->nextthink = level.time + duration; @@ -1900,33 +1931,46 @@ static void Q3_SetNavGoal( int entID, const char *name ) Q3_DebugPrint( WL_ERROR, "Q3_SetNavGoal: tried to set a navgoal (\"%s\") on a dead NPC: \"%s\"\n", name, ent->script_targetname ); return; } - //Get the position of the goal - if ( TAG_GetOrigin2( NULL, name, goalPos ) == false ) + if ( !ent->NPC->tempGoal->inuse ) { - gentity_t *targ = G_Find(NULL, FOFS(targetname), (char*)name); - if ( !targ ) - { - Q3_DebugPrint( WL_ERROR, "Q3_SetNavGoal: can't find NAVGOAL \"%s\"\n", name ); - return; - } - else - { - ent->NPC->goalEntity = targ; - ent->NPC->goalRadius = sqrt(ent->maxs[0]+ent->maxs[0]) + sqrt(targ->maxs[0]+targ->maxs[0]); - ent->NPC->aiFlags &= ~NPCAI_TOUCHED_GOAL; - } + Q3_DebugPrint( WL_ERROR, "Q3_SetNavGoal: NPC's (\"%s\") navgoal is freed: \"%s\"\n", name, ent->script_targetname ); + return; + } + if( Q_stricmp( "null", name) == 0 ) + { + ent->NPC->goalEntity = NULL; + Q3_TaskIDComplete( ent, TID_MOVE_NAV ); } else { - int goalRadius = TAG_GetRadius( NULL, name ); - NPC_SetMoveGoal( ent, goalPos, goalRadius, qtrue ); - //We know we want to clear the lastWaypoint here - ent->NPC->goalEntity->lastWaypoint = WAYPOINT_NONE; - ent->NPC->aiFlags &= ~NPCAI_TOUCHED_GOAL; -#ifdef _DEBUG - //this is *only* for debugging navigation - ent->NPC->tempGoal->target = G_NewString( name ); -#endif// _DEBUG + //Get the position of the goal + if ( TAG_GetOrigin2( NULL, name, goalPos ) == false ) + { + gentity_t *targ = G_Find(NULL, FOFS(targetname), (char*)name); + if ( !targ ) + { + Q3_DebugPrint( WL_ERROR, "Q3_SetNavGoal: can't find NAVGOAL \"%s\"\n", name ); + return; + } + else + { + ent->NPC->goalEntity = targ; + ent->NPC->goalRadius = sqrt(ent->maxs[0]+ent->maxs[0]) + sqrt(targ->maxs[0]+targ->maxs[0]); + ent->NPC->aiFlags &= ~NPCAI_TOUCHED_GOAL; + } + } + else + { + int goalRadius = TAG_GetRadius( NULL, name ); + NPC_SetMoveGoal( ent, goalPos, goalRadius, qtrue ); + //We know we want to clear the lastWaypoint here + ent->NPC->goalEntity->lastWaypoint = WAYPOINT_NONE; + ent->NPC->aiFlags &= ~NPCAI_TOUCHED_GOAL; + #ifdef _DEBUG + //this is *only* for debugging navigation + ent->NPC->tempGoal->target = G_NewString( name ); + #endif// _DEBUG + } } } @@ -2339,6 +2383,12 @@ static void Q3_SetHealth( int entID, int data ) ent->health = data; + // should adjust max if new health is higher than max + if ( ent->health > ent->max_health ) + { + ent->max_health = ent->health; + } + if(!ent->client) { return; @@ -3270,7 +3320,7 @@ static void Q3_SetWeapon (int entID, const char *wp_name) {//no weapon, drop it TossClientItems( self ); self->client->ps.weapon = WP_NONE; - if ( self->weaponModel != -1 ) + if ( self->weaponModel >= 0 ) { gi.G2API_RemoveGhoul2Model( self->ghoul2, self->weaponModel ); self->weaponModel = -1; @@ -3282,7 +3332,7 @@ static void Q3_SetWeapon (int entID, const char *wp_name) if(wp == WP_NONE) {//no weapon self->client->ps.weapon = WP_NONE; - if ( self->weaponModel != -1 ) + if ( self->weaponModel >= 0 ) { gi.G2API_RemoveGhoul2Model( self->ghoul2, self->weaponModel ); self->weaponModel = -1; @@ -3317,7 +3367,7 @@ static void Q3_SetWeapon (int entID, const char *wp_name) CG_ChangeWeapon( wp ); G_AddEvent( self, EV_GENERAL_SOUND, G_SoundIndex( "sound/weapons/change.wav" )); } - if ( self->weaponModel != -1 ) + if ( self->weaponModel >= 0 ) { gi.G2API_RemoveGhoul2Model( self->ghoul2, self->weaponModel ); } @@ -3961,6 +4011,15 @@ static void Q3_SetFullName (int entID, const char *fullName) } } +static void Q3_SetMusicState( const char *dms ) +{ + int newDMS = GetIDForString( DMSTable, dms ); + if ( newDMS != -1 ) + { + level.dmState = newDMS; + } +} + static void Q3_SetForcePowerLevel ( int entID, int forcePower, int forceLevel ) { if ( forcePower < FP_FIRST || forceLevel >= NUM_FORCE_POWERS ) @@ -3989,10 +4048,26 @@ static void Q3_SetForcePowerLevel ( int entID, int forcePower, int forceLevel ) return; } - if (forceLevel > self->client->ps.forcePowerLevel[forcePower]) + if ((forceLevel > self->client->ps.forcePowerLevel[forcePower]) && (entID==0) && (forceLevel > 0)) { - missionInfo_Updated = qtrue; // Activate flashing text - gi.cvar_set("cg_updatedDataPadForcePower", va("%d",forcePower+1)); // The +1 is offset in the print routine. It ain't pretty, I know. + if (!cg_updatedDataPadForcePower1.integer) + { + missionInfo_Updated = qtrue; // Activate flashing text + gi.cvar_set("cg_updatedDataPadForcePower1", va("%d",forcePower+1)); // The +1 is offset in the print routine. It ain't pretty, I know. + cg_updatedDataPadForcePower1.integer = forcePower+1; + } + else if (!cg_updatedDataPadForcePower2.integer) + { + missionInfo_Updated = qtrue; // Activate flashing text + gi.cvar_set("cg_updatedDataPadForcePower2", va("%d",forcePower+1)); // The +1 is offset in the print routine. It ain't pretty, I know. + cg_updatedDataPadForcePower2.integer = forcePower+1; + } + else if (!cg_updatedDataPadForcePower3.integer) + { + missionInfo_Updated = qtrue; // Activate flashing text + gi.cvar_set("cg_updatedDataPadForcePower3", va("%d",forcePower+1)); // The +1 is offset in the print routine. It ain't pretty, I know. + cg_updatedDataPadForcePower3.integer = forcePower+1; + } } self->client->ps.forcePowerLevel[forcePower] = forceLevel; @@ -5019,6 +5094,39 @@ static void Q3_SetCombatTalk( int entID, qboolean add) } } +/* +============ +Q3_SetAlertTalk + +? +============ +*/ +static void Q3_SetAlertTalk( int entID, qboolean add) +{ + gentity_t *ent = &g_entities[entID]; + + if ( !ent ) + { + Q3_DebugPrint( WL_WARNING, "Q3_SetAlertTalk: invalid entID %d\n", entID); + return; + } + + if ( !ent->NPC ) + { + Q3_DebugPrint( WL_ERROR, "Q3_SetAlertTalk: '%s' is not an NPC!\n", ent->targetname ); + return; + } + + if ( add ) + { + ent->NPC->scriptFlags |= SCF_NO_ALERT_TALK; + } + else + { + ent->NPC->scriptFlags &= ~SCF_NO_ALERT_TALK; + } +} + /* ============ Q3_SetUseCpNearest @@ -5118,6 +5226,39 @@ static void Q3_SetNoAcrobatics( int entID, qboolean add) } } +/* +============ +Q3_SetUseSubtitles + +? +============ +*/ +static void Q3_SetUseSubtitles( int entID, qboolean add) +{ + gentity_t *ent = &g_entities[entID]; + + if ( !ent ) + { + Q3_DebugPrint( WL_WARNING, "Q3_SetUseSubtitles: invalid entID %d\n", entID); + return; + } + + if ( !ent->NPC ) + { + Q3_DebugPrint( WL_ERROR, "Q3_SetUseSubtitles: '%s' is not an NPC!\n", ent->targetname ); + return; + } + + if ( add ) + { + ent->NPC->scriptFlags |= SCF_USE_SUBTITLES; + } + else + { + ent->NPC->scriptFlags &= ~SCF_USE_SUBTITLES; + } +} + /* ============ Q3_SetNoFallToDeath @@ -5637,8 +5778,10 @@ static void Q3_RemoveRHandModel( int entID, char *addModel) { gentity_t *ent = &g_entities[entID]; - gi.G2API_RemoveGhoul2Model(ent->ghoul2,ent->cinematicModel); - + if ( ent->cinematicModel >= 0 ) + { + gi.G2API_RemoveGhoul2Model(ent->ghoul2,ent->cinematicModel); + } } /* @@ -5686,8 +5829,10 @@ static void Q3_RemoveLHandModel( int entID, char *addModel) { gentity_t *ent = &g_entities[entID]; - gi.G2API_RemoveGhoul2Model(ent->ghoul2, ent->cinematicModel); - + if ( ent->cinematicModel >= 0 ) + { + gi.G2API_RemoveGhoul2Model(ent->ghoul2, ent->cinematicModel); + } } /* @@ -6101,19 +6246,19 @@ static void Q3_SetSaberActive( int entID, qboolean active ) if ( !ent ) { - Q3_DebugPrint( WL_WARNING, "Q3_SetShields: invalid entID %d\n", entID); + Q3_DebugPrint( WL_WARNING, "Q3_SetSaberActive: invalid entID %d\n", entID); return; } if ( !ent->client ) { - Q3_DebugPrint( WL_ERROR, "Q3_SetShields: '%s' is not an player/NPC!\n", ent->targetname ); + Q3_DebugPrint( WL_ERROR, "Q3_SetSaberActive: '%s' is not an player/NPC!\n", ent->targetname ); return; } if ( ent->client->ps.weapon != WP_SABER ) { - Q3_DebugPrint( WL_ERROR, "Q3_SetShields: '%s' is not using a saber!\n", ent->targetname ); + Q3_DebugPrint( WL_ERROR, "Q3_SetSaberActive: '%s' is not using a saber!\n", ent->targetname ); return; } //FIXME: need an externalized call for the sound and any other internal changes? @@ -6149,6 +6294,47 @@ static void Q3_SetNoKnockback( int entID, qboolean noKnockback ) } } +/* +============ +Q3_SetCleanDamagingEnts + Description : + Return type : void +============ +*/ +static void Q3_SetCleanDamagingEnts( void ) +{ + gentity_t *ent = NULL; + + for ( int i = 0; i < ENTITYNUM_WORLD; i++ ) + { + if ( !PInUse( i )) + { + continue; + } + + ent = &g_entities[i]; + + if ( ent ) + { + if ( !ent->client && ( ent->s.weapon == WP_DET_PACK || ent->s.weapon == WP_TRIP_MINE || ent->s.weapon == WP_THERMAL )) + { + // check for a client, otherwise we could remove someone holding this weapon + G_FreeEntity( ent ); + } + else if ( ent->s.weapon == WP_TURRET && ent->activator && ent->activator->s.number == 0 && !Q_stricmp( "PAS", ent->classname )) + { + // is a player owner personal assault sentry gun. + G_FreeEntity( ent ); + } + else if ( ent->client && ent->client->NPC_class == CLASS_SEEKER ) + { + // they blow up when they run out of ammo, so this may as well just do the same. + G_Damage( ent, ent, ent, NULL, NULL, 999, 0, MOD_UNKNOWN ); + } + } + } +} + /* ============ @@ -6236,6 +6422,29 @@ static void Q3_SetLockPlayerWeapons( int entID, qboolean locked ) } + +/* +============ +Q3_SetNoImpactDamage + Description : + Return type : void + Argument : int entID + Argument : qboolean locked +============ +*/ +static void Q3_SetNoImpactDamage( int entID, qboolean noImp ) +{ + gentity_t *ent = &g_entities[0]; + + ent->flags &= ~FL_NO_IMPACT_DMG; + + if( noImp ) + { + ent->flags |= FL_NO_IMPACT_DMG; + } + +} + extern void CG_CameraAutoAim( const char *name ); extern void CG_CameraAutoTrack( const char *name ); @@ -6863,6 +7072,13 @@ static void Q3_Set( int taskID, int entID, const char *type_name, const char *da Q3_SetCombatTalk( entID, qfalse); break; + case SET_NO_ALERT_TALK: + if(!stricmp("true", ((char *)data))) + Q3_SetAlertTalk( entID, qtrue); + else + Q3_SetAlertTalk( entID, qfalse); + break; + case SET_USE_CP_NEAREST: if(!stricmp("true", ((char *)data))) Q3_SetUseCpNearest( entID, qtrue); @@ -6884,6 +7100,13 @@ static void Q3_Set( int taskID, int entID, const char *type_name, const char *da Q3_SetNoAcrobatics( entID, qfalse); break; + case SET_USE_SUBTITLES: + if(!stricmp("true", ((char *)data))) + Q3_SetUseSubtitles( entID, qtrue); + else + Q3_SetUseSubtitles( entID, qfalse); + break; + case SET_NO_FALLTODEATH: if(!stricmp("true", ((char *)data))) Q3_SetNoFallToDeath( entID, qtrue); @@ -6992,6 +7215,13 @@ static void Q3_Set( int taskID, int entID, const char *type_name, const char *da Q3_SetLockPlayerWeapons( entID, qfalse ); break; + case SET_NO_IMPACT_DAMAGE: + if( !stricmp("true", ((char *)data)) ) + Q3_SetNoImpactDamage( entID, qtrue ); + else + Q3_SetNoImpactDamage( entID, qfalse ); + break; + case SET_FORWARDMOVE: int_data = atoi((char *) data); Q3_SetForwardMove( entID, int_data); @@ -7362,6 +7592,25 @@ extern void LockDoors(gentity_t *const ent); } break; + case SET_MUSIC_STATE: + Q3_SetMusicState( (char *) data ); + break; + + case SET_CLEAN_DAMAGING_ENTS: + Q3_SetCleanDamagingEnts(); + break; + + case SET_HUD: + if(!stricmp("true", ((char *)data))) + { + gi.cvar_set("cg_drawHUD", "1"); + } + else + { + gi.cvar_set("cg_drawHUD", "0"); + } + break; + case SET_FORCE_HEAL_LEVEL: case SET_FORCE_JUMP_LEVEL: case SET_FORCE_SPEED_LEVEL: @@ -7376,7 +7625,7 @@ extern void LockDoors(gentity_t *const ent); int_data = atoi((char *) data); Q3_SetForcePowerLevel( entID, (toSet-SET_FORCE_HEAL_LEVEL), int_data ); break; - + default: //Q3_DebugPrint( WL_ERROR, "Q3_Set: '%s' is not a valid set field\n", type_name ); Q3_SetVar( taskID, entID, type_name, data ); @@ -7579,7 +7828,7 @@ void MakeOwnerEnergy(gentity_t *self) { if(self->owner && self->owner->client) { - self->owner->client->ps.powerups[PW_QUAD] = level.time + 1000; +// self->owner->client->ps.powerups[PW_QUAD] = level.time + 1000; } G_FreeEntity(self); @@ -8110,6 +8359,9 @@ static int Q3_GetFloat( int entID, int type, const char *name, float *value ) case SET_LOCK_PLAYER_WEAPONS://## %t="BOOL_TYPES" # Makes it so player cannot switch weapons *value = (ent->flags&FL_LOCK_PLAYER_WEAPONS); break; + case SET_NO_IMPACT_DAMAGE://## %t="BOOL_TYPES" # Makes it so player cannot switch weapons + *value = (ent->flags&FL_NO_IMPACT_DMG); + break; case SET_NO_KNOCKBACK://## %t="BOOL_TYPES" # Stops this ent from taking knockback from weapons *value = (ent->flags&FL_NO_KNOCKBACK); break; @@ -8142,6 +8394,15 @@ static int Q3_GetFloat( int entID, int type, const char *name, float *value ) return false; } *value = (ent->NPC->scriptFlags&SCF_NO_COMBAT_TALK); + break; + case SET_NO_ALERT_TALK://## %t="BOOL_TYPES" # NPCs will not do their combat talking noises when this is on + if ( ent->NPC == NULL ) + { + Q3_DebugPrint( WL_WARNING, "Q3_GetFloat: SET_NO_ALERT_TALK, %s not an NPC\n", ent->targetname ); + return false; + } + *value = (ent->NPC->scriptFlags&SCF_NO_ALERT_TALK); + break; case SET_USE_CP_NEAREST://## %t="BOOL_TYPES" # NPCs will use their closest combat points, not try and find ones next to the player, or flank player if ( ent->NPC == NULL ) { @@ -8174,6 +8435,14 @@ static int Q3_GetFloat( int entID, int type, const char *name, float *value ) } *value = (ent->NPC->scriptFlags&SCF_NO_ACROBATICS); break; + case SET_USE_SUBTITLES: + if ( ent->NPC == NULL ) + { + Q3_DebugPrint( WL_WARNING, "Q3_GetFloat: SET_USE_SUBTITLES, %s not an NPC\n", ent->targetname ); + return false; + } + *value = (ent->NPC->scriptFlags&SCF_USE_SUBTITLES); + break; case SET_NO_FALLTODEATH://## %t="BOOL_TYPES" # NPC will not be affected by force powers if ( ent->NPC == NULL ) { @@ -8485,7 +8754,9 @@ static int Q3_GetString( int entID, int type, const char *name, char **value ) // *value = (char *)GetStringForID( WPTable, ent->client->ps.weapon ); } break; - + case SET_MUSIC_STATE: + *value = (char *)GetStringForID( DMSTable, level.dmState ); + break; //The below cannot be gotten case SET_NAVGOAL://## %s="NULL" # *Move to this navgoal then continue script Q3_DebugPrint( WL_WARNING, "Q3_GetString: SET_NAVGOAL not implemented\n" ); @@ -8960,7 +9231,6 @@ void Interface_Init( interface_export_t *pe ) gclient_t *client; client = &level.clients[0]; memset(&client->sess,0,sizeof(client->sess)); - memset(&client->tourSess,0,sizeof(client->tourSess)); } // leave these two as standard mallocs for the moment, there's something weird happening in ICARUS... diff --git a/code/game/Q3_Interface.h b/code/game/Q3_Interface.h index 223e942..7e65d2e 100644 --- a/code/game/Q3_Interface.h +++ b/code/game/Q3_Interface.h @@ -167,12 +167,14 @@ typedef enum //# setType_e SET_VIDEO_FADE_OUT,//## %t="BOOL_TYPES" # Makes video playback fade out SET_PLAYER_LOCKED,//## %t="BOOL_TYPES" # Makes it so player cannot move SET_LOCK_PLAYER_WEAPONS,//## %t="BOOL_TYPES" # Makes it so player cannot switch weapons + SET_NO_IMPACT_DAMAGE,//## %t="BOOL_TYPES" # Stops this ent from taking impact damage SET_NO_KNOCKBACK,//## %t="BOOL_TYPES" # Stops this ent from taking knockback from weapons SET_ALT_FIRE,//## %t="BOOL_TYPES" # Force NPC to use altfire when shooting SET_NO_RESPONSE,//## %t="BOOL_TYPES" # NPCs will do generic responses when this is on (usescripts override generic responses as well) SET_INVINCIBLE,//## %t="BOOL_TYPES" # Completely unkillable SET_MISSIONSTATUSACTIVE, //# Turns on Mission Status Screen SET_NO_COMBAT_TALK,//## %t="BOOL_TYPES" # NPCs will not do their combat talking noises when this is on + SET_NO_ALERT_TALK,//## %t="BOOL_TYPES" # NPCs will not do their combat talking noises when this is on SET_TREASONED,//## %t="BOOL_TYPES" # Player has turned on his own- scripts will stop, NPCs will turn on him and level changes load the brig SET_DISABLE_SHADER_ANIM,//## %t="BOOL_TYPES" # Allows turning off an animating shader in a script SET_SHADER_ANIM,//## %t="BOOL_TYPES" # Sets a shader with an image map to be under frame control @@ -194,6 +196,9 @@ typedef enum //# setType_e SET_NO_FALLTODEATH,//## %t="BOOL_TYPES" # NPC will not scream and tumble and fall to hit death over large drops SET_DISMEMBERABLE,//## %t="BOOL_TYPES" # NPC will not be dismemberable if you set this to false (default is true) SET_NO_ACROBATICS,//## %t="BOOL_TYPES" # Jedi won't jump, roll or cartwheel + SET_USE_SUBTITLES,//## %t="BOOL_TYPES" # When true NPC will always display subtitle regardless of subtitle setting + SET_CLEAN_DAMAGING_ENTS,//## %t="BOOL_TYPES" # Removes entities that could muck up cinematics, explosives, turrets, seekers. + SET_HUD,//## %t="BOOL_TYPES" # Turns on/off HUD //# #sep calls SET_SKILL,//## %r%d="0" # Cannot set this, only get it - valid values are 0 through 3 @@ -210,6 +215,7 @@ typedef enum //# setType_e SET_EVENT,//## %t="EVENT_NAMES" # Events you can initiate SET_WEAPON,//## %t="WEAPON_NAMES" # Change/Stow/Drop weapon SET_ITEM,//## %t="ITEM_NAMES" # Give items + SET_MUSIC_STATE,//## %t="MUSIC_STATES" # Set the state of the dynamic music SET_FORCE_HEAL_LEVEL,//## %t="FORCE_LEVELS" # Change force power level SET_FORCE_JUMP_LEVEL,//## %t="FORCE_LEVELS" # Change force power level diff --git a/code/game/anims.h b/code/game/anims.h index 9564d40..debb567 100644 --- a/code/game/anims.h +++ b/code/game/anims.h @@ -8,8 +8,9 @@ typedef enum //# animNumber_e //================================================= //ANIMS IN WHICH UPPER AND LOWER OBJECTS ARE IN MD3 //================================================= + BOTH_1CRUFTFORGIL = 0, //# G2 cannot have a reverse anim at beginning of file //# #sep BOTH_ DEATHS - BOTH_DEATH1 = 0, //# First Death anim + BOTH_DEATH1, //# First Death anim BOTH_DEATH2, //# Second Death anim BOTH_DEATH3, //# Third Death anim BOTH_DEATH4, //# Fourth Death anim @@ -28,6 +29,12 @@ typedef enum //# animNumber_e BOTH_DEATH17, //# BOTH_DEATH18, //# BOTH_DEATH19, //# + BOTH_DEATH20, //# + BOTH_DEATH21, //# + BOTH_DEATH22, //# + BOTH_DEATH23, //# + BOTH_DEATH24, //# + BOTH_DEATH25, //# BOTH_DEATHFORWARD1, //# First Death in which they get thrown forward BOTH_DEATHFORWARD2, //# Second Death in which they get thrown forward @@ -71,6 +78,12 @@ typedef enum //# animNumber_e BOTH_DEAD17, //# BOTH_DEAD18, //# BOTH_DEAD19, //# + BOTH_DEAD20, //# + BOTH_DEAD21, //# + BOTH_DEAD22, //# + BOTH_DEAD23, //# + BOTH_DEAD24, //# + BOTH_DEAD25, //# BOTH_DEADFORWARD1, //# First thrown forward death finished pose BOTH_DEADFORWARD2, //# Second thrown forward death finished pose BOTH_DEADBACKWARD1, //# First thrown backward death finished pose @@ -607,6 +620,15 @@ typedef enum //# animNumber_e BOTH_CWCIRCLELOCK, //# BOTH_CCWCIRCLELOCK, //# + BOTH_SABERFAST_STANCE, + BOTH_SABERSLOW_STANCE, + BOTH_A2_STABBACK1, //# Stab saber backward + BOTH_ATTACK_BACK, //# Swing around backwards and attack + BOTH_JUMPFLIPSLASHDOWN1,//# + BOTH_JUMPFLIPSTABDOWN,//# + BOTH_FORCELEAP2_T__B_,//# + BOTH_LUNGE2_B__T_,//# + BOTH_CROUCHATTACKBACK1,//# //# #sep BOTH_ STANDING BOTH_STAND1, //# Standing idle, no weapon, hands down @@ -644,6 +666,15 @@ typedef enum //# animNumber_e BOTH_STAND5TOSTAND8, //# Transition from stand5 to stand8 BOTH_STAND7TOSTAND8, //# Tavion putting hands on back of chair (cin #11) BOTH_STAND8TOSTAND5, //# Transition from stand8 to stand5 + BOTH_STAND5SHIFTWEIGHT, //# Weightshift from stand5 to side and back to stand5 + BOTH_STAND5SHIFTWEIGHTSTART, //# From stand5 to side + BOTH_STAND5SHIFTWEIGHTSTOP, //# From side to stand5 + BOTH_STAND5TURNLEFTSTART, //# Start turning left from stand5 + BOTH_STAND5TURNLEFTSTOP, //# Stop turning left from stand5 + BOTH_STAND5TURNRIGHTSTART, //# Start turning right from stand5 + BOTH_STAND5TURNRIGHTSTOP, //# Stop turning right from stand5 + BOTH_STAND5LOOK180LEFTSTART, //# Start looking over left shoulder (cin #17) + BOTH_STAND5LOOK180LEFTSTOP, //# Stop looking over left shoulder (cin #17) BOTH_CONSOLE1START, //# typing at a console BOTH_CONSOLE1, //# typing at a console @@ -662,6 +693,7 @@ typedef enum //# animNumber_e BOTH_GESTURE3, //# Generic gesture, non-specific BOTH_WALK1TALKCOMM1, //# Talking into coom link while walking BOTH_TALK1, //# Generic talk anim + BOTH_TALK2, //# Generic talk anim BOTH_TALKCOMM1START, //# Start talking into a comm link BOTH_TALKCOMM1, //# Talking into a comm link BOTH_TALKCOMM1STOP, //# Stop talking into a comm link @@ -720,6 +752,8 @@ typedef enum //# animNumber_e BOTH_SITHEADTILTRSTOP, //# Head tilt to right from seated position BOTH_SITHEADNOD, //# Head shake YES from seated position BOTH_SITHEADSHAKE, //# Head shake NO from seated position + BOTH_SIT2HEADTILTLSTART, //# Head tilt to left from seated position 2 + BOTH_SIT2HEADTILTLSTOP, //# Head tilt to left from seated position 2 BOTH_REACH1START, //# Monmothma reaching for crystal BOTH_REACH1STOP, //# Monmothma reaching for crystal @@ -875,6 +909,9 @@ typedef enum //# animNumber_e BOTH_WALK5, //# Tavion taunting Kyle (cin 22) BOTH_WALK6, //# Slow walk for Luke (cin 12) BOTH_WALK7, //# Fast walk + BOTH_WALK8, //# Normal walk with hands behind back (Luke in cin#12) + BOTH_WALK9, //# Lando walk (cin #17) + BOTH_WALK10, //# Lando walk (cin #17) BOTH_WALKTORUN1, //# transition from walk to run BOTH_RUN1, //# Full run BOTH_RUN1START, //# Start into full run1 @@ -963,16 +1000,7 @@ typedef enum //# animNumber_e BOTH_DIVE1, //# Dive! - BOTH_SABERFAST_STANCE, - BOTH_SABERSLOW_STANCE, BOTH_ENGAGETAUNT, - BOTH_A2_STABBACK1, //# Stab saber backward - BOTH_ATTACK_BACK, //# Swing around backwards and attack - BOTH_JUMPFLIPSLASHDOWN1,//# - BOTH_JUMPFLIPSTABDOWN,//# - BOTH_FORCELEAP2_T__B_,//# - BOTH_LUNGE2_B__T_,//# - BOTH_CROUCHATTACKBACK1,//# BOTH_ARIAL_LEFT, //# BOTH_ARIAL_RIGHT, //# BOTH_CARTWHEEL_LEFT, //# @@ -1028,11 +1056,6 @@ typedef enum //# animNumber_e BOTH_ARIAL_F1,//# BOTH_BUTTERFLY_FR1,//# BOTH_BUTTERFLY_FL1,//# - BOTH_POSE1,//# - BOTH_POSE2,//# - BOTH_POSE3,//# - BOTH_POSE4,//# - BOTH_POSE5,//# //# #sep BOTH_ MISC MOVEMENT BOTH_HIT1, //# Kyle hit by crate in cin #9 @@ -1065,12 +1088,7 @@ typedef enum //# animNumber_e //# #sep BOTH_ SWIMMING BOTH_SWIM_IDLE1, //# Swimming Idle 1 - BOTH_SWIMFORWARDSTART, //# Swim forward start BOTH_SWIMFORWARD, //# Swim forward loop - BOTH_SWIMFORWARDSTOP, //# Swim forward end - BOTH_SWIMBACKWARDSTART, //# Swim backward start - BOTH_SWIMBACKWARD, //# Swim backward loop - BOTH_SWIMBACKWARDSTOP, //# Swim backward end //# #sep BOTH_ LYING BOTH_LIE_DOWN1, //# From a stand position, get down on ground, face down @@ -1156,6 +1174,7 @@ typedef enum //# animNumber_e BOTH_SABERPULL, //# Use off-hand to do force power. BOTH_FORCEGRIP1, //# force-gripping (no anim?) BOTH_FORCEGRIP3, //# force-gripping (right hand) + BOTH_FORCEGRIP3THROW, //# throwing while force-gripping (right hand) BOTH_FORCEGRIP_HOLD, //# Use off-hand to do grip - hold BOTH_FORCEGRIP_RELEASE,//# Use off-hand to do grip - release BOTH_TOSS1, //# throwing to left after force gripping @@ -1189,9 +1208,10 @@ typedef enum //# animNumber_e BOTH_COCKPIT_HEADTILTRSTART, //# start tilt head right while sitting BOTH_COCKPIT_HEADTILTRSTOP, //# stop tilt head right while sitting - BOTH_COCKPIT_TALKGESTURE7START, //# - BOTH_COCKPIT_TALKGESTURE7STOP, //# - BOTH_COCKPIT_TALKGESTURE8, //# + BOTH_COCKPIT_TALKGESTURE7START, //# Lando's supporting hand to Kyle (cin #21) + BOTH_COCKPIT_TALKGESTURE7STOP, //# Lando's supporting hand away from Kyle (cin #21) + BOTH_COCKPIT_TALKGESTURE8START, //# Hand to Lando's chin (cin #21) + BOTH_COCKPIT_TALKGESTURE8STOP, //# hand away from Lando's chin *cin #21) BOTH_COCKPIT_TALKGESTURE11START, //# BOTH_COCKPIT_TALKGESTURE11STOP, //# @@ -1235,23 +1255,7 @@ typedef enum //# animNumber_e TORSO_WEAPONIDLE11, //# Holding laser trap TORSO_WEAPONIDLE12, //# Holding detpack - //# #sep TORSO_ USING NON-WEAPON OBJECTS - //# #sep TORSO_ MISC - TORSO_TALKR1START, //# begin turning head for BOTH_TORSO_TALKR - TORSO_TALKR1STOP, //# return head to straight forward from BOTH_TORSO_TALKL - TORSO_TALKR1, //# talk to right side - TORSO_TALKL1START, //# begin turning head for BOTH_TORSO_TALKL - TORSO_TALKL1STOP, //# return head to straight forward from BOTH_TORSO_TALKL - TORSO_TALKL1, //# talk to left side - TORSO_LOOKL1, //# looking left - TORSO_LOOKR1, //# looking right - TORSO_LOOKR2START, //# turn not so far as TALKR1 - TORSO_LOOKR2STOP, //# turn not so far as TALKR1 - TORSO_LOOKR2, //# looking right - not so far as LOOKR1 - TORSO_LOOKL2START, //# turn not so far as TALKL1 - TORSO_LOOKL2STOP, //# turn not so far as TALKL1 - TORSO_LOOKL2, //# looking right - not so far as LOOKL1 TORSO_HANDGESTURE1, //# gestures to left one hand TORSO_HANDGESTURE2, //# gestures to right one hand TORSO_HANDGESTURE3, //# gestures to the left both hands @@ -1353,7 +1357,6 @@ typedef enum //# animNumber_e FACE_SMILE, //# FACE_FROWN, //# FACE_DEAD, //# - FACE_GALAK, //# This has to be last for Galak Mech to talk //# #eol MAX_ANIMATIONS, @@ -1361,7 +1364,7 @@ typedef enum //# animNumber_e #define SABER_ANIM_GROUP_SIZE (BOTH_A2_T__B_ - BOTH_A1_T__B_) -#define MAX_ANIM_SOUNDS 64 +#define MAX_ANIM_SOUNDS 69 #ifndef CG_PLAYERS_CPP diff --git a/code/game/b_local.h b/code/game/b_local.h index df29e9a..c9403c8 100644 --- a/code/game/b_local.h +++ b/code/game/b_local.h @@ -293,7 +293,7 @@ extern int NPC_CheckEnemyExt( qboolean checkAlerts = qfalse ); extern qboolean NPC_FindPlayer( void ); extern qboolean NPC_CheckCanAttackExt( void ); -extern int NPC_CheckAlertEvents( qboolean checkSight, qboolean checkSound, qboolean mustHaveOwner = qfalse, int minAlertLevel = AEL_MINOR ); +extern int NPC_CheckAlertEvents( qboolean checkSight, qboolean checkSound, int ignoreAlert = -1, qboolean mustHaveOwner = qfalse, int minAlertLevel = AEL_MINOR ); extern qboolean NPC_CheckForDanger( int alertEvent ); extern void G_AlertTeam( gentity_t *victim, gentity_t *attacker, float radius, float soundDist ); diff --git a/code/game/b_public.h b/code/game/b_public.h index 57e2eb2..7ccede7 100644 --- a/code/game/b_public.h +++ b/code/game/b_public.h @@ -48,6 +48,8 @@ #define SCF_NO_FORCE 0x00200000 //Not succeptible to force powers #define SCF_NO_FALLTODEATH 0x00400000 //NPC will not scream and tumble and fall to hit death over large drops #define SCF_NO_ACROBATICS 0x00800000 //Jedi won't jump, roll or cartwheel +#define SCF_USE_SUBTITLES 0x01000000 //Regardless of subtitle setting, this NPC will display subtitles when it speaks lines +#define SCF_NO_ALERT_TALK 0x02000000 //Will not say alert sounds, but still can be woken up by alerts //#ifdef __DEBUG @@ -258,6 +260,7 @@ typedef struct int confusionTime; //Doesn't respond to alerts or pick up enemies (unless shot) until this time is up int charmedTime; //charmed to enemy team + int controlledTime; //controlled by player int surrenderTime; //Hands up //Lagging enemy position - FIXME: seems awful wasteful... diff --git a/code/game/bg_misc.cpp b/code/game/bg_misc.cpp index 569aae0..0012b29 100644 --- a/code/game/bg_misc.cpp +++ b/code/game/bg_misc.cpp @@ -88,7 +88,7 @@ Ammo for Imperial Heavy Repeater and the Golan Arms Flechette /*QUAKED ammo_rockets (.3 .5 1) (-8 -8 -0) (8 8 16) SUSPEND STARFLEET MONSTER NOTSOLID Ammo for Merr-Sonn portable missile launcher */ -/*QUAKED ammo_thermal (.3 .5 1) (-8 -8 -0) (8 8 16) SUSPEND STARFLEET MONSTER NOTSOLID +/*QUAKED ammo_thermal (.3 .5 1) (-16 -16 -0) (16 16 16) SUSPEND STARFLEET MONSTER NOTSOLID Belt of thermal detonators */ /*QUAKED ammo_tripmine (.3 .5 1) (-8 -8 -0) (8 8 16) SUSPEND STARFLEET MONSTER NOTSOLID @@ -201,16 +201,6 @@ gitem_t *FindItemForInventory( int inv ) int i; gitem_t *it; - // this is particularly ugly because we do not have a 1 to 1 correlation between an inventory item and a real item. - if ( inv >= INV_GOODIE_KEY1 && inv <= INV_GOODIE_KEY5 ) - { - return &bg_itemlist[ITM_GOODIE_KEY_PICKUP]; - } - else if ( inv >= INV_SECURITY_KEY1 && inv <= INV_SECURITY_KEY5 ) - { - return &bg_itemlist[ITM_SECURITY_KEY_PICKUP]; - } - // Now just check for any other kind of item. for ( i = 1 ; i < bg_numItems ; i++ ) { @@ -309,6 +299,29 @@ qboolean BG_CanItemBeGrabbed( const entityState_t *ent, const playerState_t *ps if (item->giTag != AMMO_FORCE) { + // since the ammo is the weapon in this case, picking up ammo should actually give you the weapon + switch( item->giTag ) + { + case AMMO_THERMAL: + if( !(ps->stats[STAT_WEAPONS] & ( 1 << WP_THERMAL ) ) ) + { + return qtrue; + } + break; + case AMMO_DETPACK: + if( !(ps->stats[STAT_WEAPONS] & ( 1 << WP_DET_PACK ) ) ) + { + return qtrue; + } + break; + case AMMO_TRIPMINE: + if( !(ps->stats[STAT_WEAPONS] & ( 1 << WP_TRIP_MINE ) ) ) + { + return qtrue; + } + break; + } + if ( ps->ammo[ item->giTag ] >= ammoData[item->giTag].max ) // checkme { return qfalse; // can't hold any more @@ -316,7 +329,7 @@ qboolean BG_CanItemBeGrabbed( const entityState_t *ent, const playerState_t *ps } else { - if (ps->forcePower >= ammoData[item->giTag].max) + if (ps->forcePower >= ammoData[item->giTag].max*2) { return qfalse; // can't hold any more } @@ -538,11 +551,11 @@ void PlayerStateToEntityState( playerState_t *ps, entityState_t *s ) { s->pos.trType = TR_INTERPOLATE; VectorCopy( ps->origin, s->pos.trBase ); - SnapVector( s->pos.trBase ); + //SnapVector( s->pos.trBase ); s->apos.trType = TR_INTERPOLATE; VectorCopy( ps->viewangles, s->apos.trBase ); - SnapVector( s->apos.trBase ); + //SnapVector( s->apos.trBase ); s->angles2[YAW] = ps->movementDir; s->legsAnim = ps->legsAnim; diff --git a/code/game/bg_pangles.cpp b/code/game/bg_pangles.cpp index 59ece6a..c99e36f 100644 --- a/code/game/bg_pangles.cpp +++ b/code/game/bg_pangles.cpp @@ -72,9 +72,12 @@ qboolean PM_AdjustAnglesToGripper( gentity_t *ent, usercmd_t *ucmd ) VectorSubtract( ent->enemy->currentOrigin, ent->currentOrigin, dir ); vectoangles( dir, angles ); - angles[PITCH] = -AngleNormalize180( angles[PITCH] ); + angles[PITCH] = AngleNormalize180( angles[PITCH] ); angles[YAW] = AngleNormalize180( angles[YAW] ); - SetClientViewAngle( ent, angles ); + if ( ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD ) + {//don't clamp angles when looking through a viewEntity + SetClientViewAngle( ent, angles ); + } ucmd->angles[PITCH] = ANGLE2SHORT(angles[PITCH]) - ent->client->ps.delta_angles[PITCH]; ucmd->angles[YAW] = ANGLE2SHORT(angles[YAW]) - ent->client->ps.delta_angles[YAW]; return qtrue; @@ -108,47 +111,64 @@ qboolean PM_AdjustAngleForWallRun( gentity_t *ent, usercmd_t *ucmd, qboolean doM {//still a vertical wall there //FIXME: don't pull around 90 turns //FIXME: simulate stepping up steps here, somehow? - if ( ent->client->ps.legsAnim == BOTH_WALL_RUN_RIGHT ) + if ( ent->s.number || !player_locked ) { - ucmd->rightmove = 127; - } - else - { - ucmd->rightmove = -127; + if ( ent->client->ps.legsAnim == BOTH_WALL_RUN_RIGHT ) + { + ucmd->rightmove = 127; + } + else + { + ucmd->rightmove = -127; + } } if ( ucmd->upmove < 0 ) { ucmd->upmove = 0; } + if ( ent->NPC ) + {//invalid now + VectorClear( ent->client->ps.moveDir ); + } //make me face perpendicular to the wall ent->client->ps.viewangles[YAW] = vectoyaw( trace.plane.normal )+yawAdjust; - SetClientViewAngle( ent, ent->client->ps.viewangles ); + if ( ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD ) + {//don't clamp angles when looking through a viewEntity + SetClientViewAngle( ent, ent->client->ps.viewangles ); + } ucmd->angles[YAW] = ANGLE2SHORT( ent->client->ps.viewangles[YAW] ) - ent->client->ps.delta_angles[YAW]; - if ( doMove ) + if ( ent->s.number || !player_locked ) { - //push me forward - vec3_t fwd; - float zVel = ent->client->ps.velocity[2]; - if ( ent->client->ps.legsAnimTimer > 500 ) - {//not at end of anim yet - fwdAngles[YAW] = ent->client->ps.viewangles[YAW]; - AngleVectors( fwdAngles, fwd, NULL, NULL ); - //FIXME: or MA? - float speed = 175; - if ( ucmd->forwardmove < 0 ) - {//slower - speed = 100; - } - else if ( ucmd->forwardmove > 0 ) + if ( doMove ) + { + //push me forward + vec3_t fwd; + float zVel = ent->client->ps.velocity[2]; + if ( zVel > forceJumpStrength[FORCE_LEVEL_2]/2.0f ) { - speed = 250;//running speed + zVel = forceJumpStrength[FORCE_LEVEL_2]/2.0f; } - VectorScale( fwd, speed, ent->client->ps.velocity ); + if ( ent->client->ps.legsAnimTimer > 500 ) + {//not at end of anim yet + fwdAngles[YAW] = ent->client->ps.viewangles[YAW]; + AngleVectors( fwdAngles, fwd, NULL, NULL ); + //FIXME: or MA? + float speed = 175; + if ( ucmd->forwardmove < 0 ) + {//slower + speed = 100; + } + else if ( ucmd->forwardmove > 0 ) + { + speed = 250;//running speed + } + VectorScale( fwd, speed, ent->client->ps.velocity ); + } + ent->client->ps.velocity[2] = zVel;//preserve z velocity + VectorMA( ent->client->ps.velocity, -128, trace.plane.normal, ent->client->ps.velocity ); + //pull me toward the wall, too + //VectorMA( ent->client->ps.velocity, dist, rt, ent->client->ps.velocity ); } - ent->client->ps.velocity[2] = zVel;//preserve z velocity - VectorMA( ent->client->ps.velocity, -128, trace.plane.normal, ent->client->ps.velocity ); - //pull me toward the wall, too - //VectorMA( ent->client->ps.velocity, dist, rt, ent->client->ps.velocity ); } ucmd->forwardmove = 0; return qtrue; @@ -209,7 +229,10 @@ qboolean PM_AdjustAnglesForSpinningFlip( gentity_t *ent, usercmd_t *ucmd, qboole spinLength = spinEnd - spinStart; VectorCopy( ent->client->ps.viewangles, newAngles ); newAngles[YAW] = ent->angle + (spinAmt * (elapsedTime-spinStart) / spinLength); - SetClientViewAngle( ent, newAngles ); + if ( ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD ) + {//don't clamp angles when looking through a viewEntity + SetClientViewAngle( ent, newAngles ); + } ucmd->angles[PITCH] = ANGLE2SHORT( ent->client->ps.viewangles[PITCH] ) - ent->client->ps.delta_angles[PITCH]; ucmd->angles[YAW] = ANGLE2SHORT( ent->client->ps.viewangles[YAW] ) - ent->client->ps.delta_angles[YAW]; if ( anglesOnly ) @@ -224,11 +247,14 @@ qboolean PM_AdjustAnglesForSpinningFlip( gentity_t *ent, usercmd_t *ucmd, qboole //push me if ( ent->client->ps.legsAnimTimer > 300 )//&& ent->client->ps.groundEntityNum == ENTITYNUM_NONE ) {//haven't landed or reached end of anim yet - vec3_t pushDir, pushAngles = {0,ent->angle,0}; - AngleVectors( pushAngles, pushDir, NULL, NULL ); - if ( DotProduct( ent->client->ps.velocity, pushDir ) < 100 ) + if ( ent->s.number || !player_locked ) { - VectorMA( ent->client->ps.velocity, 10, pushDir, ent->client->ps.velocity ); + vec3_t pushDir, pushAngles = {0,ent->angle,0}; + AngleVectors( pushAngles, pushDir, NULL, NULL ); + if ( DotProduct( ent->client->ps.velocity, pushDir ) < 100 ) + { + VectorMA( ent->client->ps.velocity, 10, pushDir, ent->client->ps.velocity ); + } } } //do a dip in the view @@ -252,25 +278,39 @@ qboolean PM_AdjustAnglesForSpinningFlip( gentity_t *ent, usercmd_t *ucmd, qboole qboolean PM_AdjustAnglesForBackAttack( gentity_t *ent, usercmd_t *ucmd ) { + if ( ent->s.number ) + { + return qfalse; + } if ( ( ent->client->ps.saberMove == LS_A_BACK || ent->client->ps.saberMove == LS_A_BACK_CR || ent->client->ps.saberMove == LS_A_BACKSTAB ) && PM_InAnimForSaberMove( ent->client->ps.torsoAnim, ent->client->ps.saberMove ) ) { - //if ( ent->client->ps.saberMove != LS_A_BACKSTAB ) + if ( ent->client->ps.saberMove != LS_A_BACKSTAB || !ent->enemy || ent->s.number ) { - SetClientViewAngle( ent, ent->client->ps.viewangles ); + if ( ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD ) + {//don't clamp angles when looking through a viewEntity + SetClientViewAngle( ent, ent->client->ps.viewangles ); + } ucmd->angles[PITCH] = ANGLE2SHORT( ent->client->ps.viewangles[PITCH] ) - ent->client->ps.delta_angles[PITCH]; ucmd->angles[YAW] = ANGLE2SHORT( ent->client->ps.viewangles[YAW] ) - ent->client->ps.delta_angles[YAW]; } - /* else - {//FIXME: keep NPC facing away from their enemy - if ( ent->s.number ) + {//keep player facing away from their enemy + vec3_t enemyBehindDir; + VectorSubtract( ent->currentOrigin, ent->enemy->currentOrigin, enemyBehindDir ); + float enemyBehindYaw = AngleNormalize180( vectoyaw( enemyBehindDir ) ); + float yawError = AngleNormalize180( enemyBehindYaw - AngleNormalize180( ent->client->ps.viewangles[YAW] ) ); + if ( yawError > 1 ) { - ucmd->angles[YAW] *= -1; + yawError = 1; } - return qfalse; + else if ( yawError < -1 ) + { + yawError = -1; + } + ucmd->angles[YAW] = ANGLE2SHORT( AngleNormalize180( ent->client->ps.viewangles[YAW] + yawError ) ) - ent->client->ps.delta_angles[YAW]; + ucmd->angles[PITCH] = ANGLE2SHORT( ent->client->ps.viewangles[PITCH] ) - ent->client->ps.delta_angles[PITCH]; } - */ return qtrue; } return qfalse; @@ -280,7 +320,10 @@ qboolean PM_AdjustAnglesForSaberLock( gentity_t *ent, usercmd_t *ucmd ) { if ( ent->client->ps.saberLockTime > level.time ) { - SetClientViewAngle( ent, ent->client->ps.viewangles ); + if ( ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD ) + {//don't clamp angles when looking through a viewEntity + SetClientViewAngle( ent, ent->client->ps.viewangles ); + } ucmd->angles[PITCH] = ANGLE2SHORT( ent->client->ps.viewangles[PITCH] ) - ent->client->ps.delta_angles[PITCH]; ucmd->angles[YAW] = ANGLE2SHORT( ent->client->ps.viewangles[YAW] ) - ent->client->ps.delta_angles[YAW]; return qtrue; @@ -303,13 +346,17 @@ qboolean PM_AdjustAnglesForKnockdown( gentity_t *ent, usercmd_t *ucmd, qboolean //you can jump up out of a knockdown and you get get up into a crouch from a knockdown //ucmd->upmove = 0; //if ( !PM_InForceGetUp( &ent->client->ps ) || ent->client->ps.torsoAnimTimer > 800 || ent->s.weapon != WP_SABER ) + if ( ent->health > 0 ) {//can only attack if you've started a force-getup and are using the saber ucmd->buttons = 0; } } if ( !PM_InForceGetUp( &ent->client->ps ) ) {//can't turn unless in a force getup - SetClientViewAngle( ent, ent->client->ps.viewangles ); + if ( ent->client->ps.viewEntity <= 0 || ent->client->ps.viewEntity >= ENTITYNUM_WORLD ) + {//don't clamp angles when looking through a viewEntity + SetClientViewAngle( ent, ent->client->ps.viewangles ); + } ucmd->angles[PITCH] = ANGLE2SHORT( ent->client->ps.viewangles[PITCH] ) - ent->client->ps.delta_angles[PITCH]; ucmd->angles[YAW] = ANGLE2SHORT( ent->client->ps.viewangles[YAW] ) - ent->client->ps.delta_angles[YAW]; return qtrue; diff --git a/code/game/bg_panimate.cpp b/code/game/bg_panimate.cpp index 412f389..b085963 100644 --- a/code/game/bg_panimate.cpp +++ b/code/game/bg_panimate.cpp @@ -15,15 +15,19 @@ #include "g_local.h" #include "wp_saber.h" -extern pmove_t *pm; -extern pml_t pml; -extern cvar_t *g_ICARUSDebug; -extern cvar_t *g_timescale; +extern pmove_t *pm; +extern pml_t pml; +extern cvar_t *g_ICARUSDebug; +extern cvar_t *g_timescale; +extern cvar_t *g_synchSplitAnims; +extern cvar_t *g_saberAnimSpeed; +extern cvar_t *g_saberAutoAim; extern qboolean InFront( vec3_t spot, vec3_t from, vec3_t fromAngles, float threshHold = 0.0f ); extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); extern qboolean ValidAnimFileIndex ( int index ); +extern qboolean PM_ControlledByPlayer( void ); extern qboolean PM_DroidMelee( int npc_class ); extern qboolean PM_PainAnim( int anim ); extern qboolean PM_JumpingAnim( int anim ); @@ -40,6 +44,7 @@ extern qboolean PM_InSpecialJump( int anim ); extern qboolean PM_RunningAnim( int anim ); extern qboolean PM_WalkingAnim( int anim ); extern qboolean PM_SwimmingAnim( int anim ); +extern qboolean PM_JumpingAnim( int anim ); int PM_AnimLength( int index, animNumber_t anim ); // Okay, here lies the much-dreaded Pat-created FSM movement chart... Heretic II strikes again! @@ -1001,6 +1006,10 @@ qboolean PM_CheckEnemyInBack( float backCheckDist ) { return qfalse; } + if ( !pm->ps->clientNum && !g_saberAutoAim->integer && pm->cmd.forwardmove >= 0 ) + {//don't auto-backstab + return qfalse; + } trace_t trace; vec3_t end, fwd, fwdAngles = {0,pm->ps->viewangles[YAW],0}; @@ -1017,6 +1026,13 @@ qboolean PM_CheckEnemyInBack( float backCheckDist ) && traceEnt->client->playerTeam == pm->gent->client->enemyTeam && traceEnt->client->ps.groundEntityNum != ENTITYNUM_NONE ) { + if ( !pm->ps->clientNum ) + {//player + if ( pm->gent ) + {//set player enemy to traceEnt so he auto-aims at him + pm->gent->enemy = traceEnt; + } + } return qtrue; } } @@ -1075,7 +1091,7 @@ int PM_AttackForEnemyPos( qboolean allowFB ) //FIXME: predict enemy position? if ( pm->gent->enemy->client ) { - VectorCopy( pm->gent->enemy->currentOrigin, enemy_org ); + VectorCopy( pm->gent->enemy->currentOrigin, enemy_org ); VectorSubtract( pm->gent->enemy->client->renderInfo.eyePoint, pm->ps->origin, enemyDir ); } else @@ -1096,18 +1112,18 @@ int PM_AttackForEnemyPos( qboolean allowFB ) float dot = DotProduct( enemyDir, faceFwd ); if ( dot > 0 ) {//enemy is in front + if ( (!pm->ps->clientNum || PM_ControlledByPlayer()) + && dot > 0.65f + && pm->gent->enemy->client && PM_InKnockDownOnGround( &pm->gent->enemy->client->ps ) + && enemyDir[2] <= 20 ) + {//guy is on the ground below me, do a top-down attack + return LS_A_T2B; + } if ( allowFB ) {//directly in front anim allowed - if ( !pm->ps->clientNum - && dot > 0.75f - && pm->gent->enemy->client && PM_InKnockDownOnGround( &pm->gent->enemy->client->ps ) - && enemyDir[2] <= 0 ) - {//guy is on the ground below me, do a top-down attack - return LS_A_T2B; - } if ( enemyDist > 200 || pm->gent->enemy->health <= 0 ) {//hmm, look in back for an enemy - if ( pm->ps->clientNum ) + if ( pm->ps->clientNum && !PM_ControlledByPlayer() ) {//player should never do this automatically if ( pm->gent && pm->gent->client && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG && Q_irand( 0, pm->gent->NPC->rank ) > RANK_ENSIGN ) {//only fencers and higher can do this, higher rank does it more @@ -1119,17 +1135,18 @@ int PM_AttackForEnemyPos( qboolean allowFB ) } } //this is the default only if they're *right* in front... - if ( pm->ps->clientNum || (cg.renderingThirdPerson && !cg.zoomMode) ) + if ( (pm->ps->clientNum&&!PM_ControlledByPlayer()) || ((!pm->ps->clientNum||PM_ControlledByPlayer()) && cg.renderingThirdPerson && !cg.zoomMode) ) { - if ( pm->ps->saberAnimLevel == FORCE_LEVEL_2 //using medium attacks + if ( (pm->ps->saberAnimLevel == FORCE_LEVEL_2 || pm->ps->saberAnimLevel == FORCE_LEVEL_5)//using medium attacks or Tavion //&& !PM_InKnockDown( pm->ps ) && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 //can force jump && !(pm->gent->flags&FL_LOCK_PLAYER_WEAPONS) // yes this locked weapons check also includes force powers, if we need a separate check later I'll make one && (pm->ps->groundEntityNum != ENTITYNUM_NONE||level.time-pm->ps->lastOnGround<=500) //on ground or just jumped - && ((pm->ps->clientNum&&!Q_irand(0,2))||pm->cmd.upmove||pm->ps->pm_flags&PMF_JUMPING))//jumping + && ( pm->ps->clientNum || pm->ps->legsAnim == BOTH_JUMP1 || pm->ps->legsAnim == BOTH_FORCEJUMP1 || pm->ps->legsAnim == BOTH_INAIR1 || pm->ps->legsAnim == BOTH_FORCEINAIR1 )//either an NPC or in a non-flip forward jump + && ( (pm->ps->clientNum&&!PM_ControlledByPlayer()&&!Q_irand(0,2)) || pm->cmd.upmove || (pm->ps->pm_flags&PMF_JUMPING) ) )//jumping {//flip over-forward down-attack - if ( !pm->ps->clientNum || - (pm->gent->NPC && (pm->gent->NPC->rank==RANK_CREWMAN||pm->gent->NPC->rank>=RANK_LT) ) ) + if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) || + (pm->gent->NPC && (pm->gent->NPC->rank==RANK_CREWMAN||pm->gent->NPC->rank>=RANK_LT) && !Q_irand(0, 2) ) ) {//only player or acrobat or boss and higher can do this if ( pm->gent->enemy->health > 0 && pm->gent->enemy->maxs[2] > 12 @@ -1142,9 +1159,11 @@ int PM_AttackForEnemyPos( qboolean allowFB ) } } } - if ( pm->ps->clientNum ) + if ( pm->ps->clientNum && !PM_ControlledByPlayer()) {//NPC - if ( pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG + if ( pm->gent->NPC + && pm->gent->NPC->rank >= RANK_LT_JG + && ( pm->gent->NPC->rank == RANK_LT_JG || Q_irand( 0, pm->gent->NPC->rank ) >= RANK_ENSIGN ) //&& !PM_InKnockDown( pm->ps ) && ((pm->ps->saberAnimLevel == FORCE_LEVEL_1 && !Q_irand( 0, 2 )) ||(pm->gent && pm->gent->client && pm->gent->client->NPC_class == CLASS_DESANN && !Q_irand( 0, 4 ))) ) @@ -1217,11 +1236,11 @@ int PM_AttackForEnemyPos( qboolean allowFB ) { if ( dot < -0.75f && enemyDist < 128 - && (pm->ps->saberAnimLevel == FORCE_LEVEL_1 || (pm->gent->client &&pm->gent->client->NPC_class == CLASS_TAVION&&Q_irand(0,1))) ) + && (pm->ps->saberAnimLevel == FORCE_LEVEL_1 || (pm->gent->client &&pm->gent->client->NPC_class == CLASS_TAVION&&Q_irand(0,2))) ) {//fast back-stab if ( !(pm->ps->pm_flags&PMF_DUCKED) && pm->cmd.upmove >= 0 ) {//can't do it while ducked? - if ( !pm->ps->clientNum || (pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG) ) + if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) || (pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG) ) {//only fencers and above can do this autoMove = LS_A_BACKSTAB; } @@ -1229,7 +1248,7 @@ int PM_AttackForEnemyPos( qboolean allowFB ) } else if ( pm->ps->saberAnimLevel > FORCE_LEVEL_1 ) {//higher level back spin-attacks - if ( pm->ps->clientNum || (cg.renderingThirdPerson && !cg.zoomMode) ) + if ( (pm->ps->clientNum&&!PM_ControlledByPlayer()) || ((!pm->ps->clientNum||PM_ControlledByPlayer()) && cg.renderingThirdPerson && !cg.zoomMode) ) { if ( (pm->ps->pm_flags&PMF_DUCKED) || pm->cmd.upmove < 0 ) { @@ -1284,6 +1303,7 @@ int PM_SaberJumpAttackMove( void ) int PM_SaberFlipOverAttackMove( void ) { //FIXME: check above for room enough to jump! + //FIXME: while in this jump, keep velocity[2] at a minimum until the end of the anim vec3_t fwdAngles, jumpFwd; VectorCopy( pm->ps->viewangles, fwdAngles ); @@ -1371,10 +1391,10 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) {//forward= T2B slash if ( pm->gent && pm->gent->enemy && pm->gent->enemy->client ) {//I have an active enemy - if ( !pm->ps->clientNum ) + if ( !pm->ps->clientNum || PM_ControlledByPlayer() ) {//a player who is running at an enemy //if the enemy is not a jedi, don't use top-down, pick a diagonal or side attack - if ( pm->gent->enemy->s.weapon != WP_SABER ) + if ( pm->gent->enemy->s.weapon != WP_SABER && g_saberAutoAim->integer ) { int autoMove = PM_AttackForEnemyPos( qfalse ); if ( autoMove != -1 ) @@ -1383,17 +1403,18 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) } } } - if ( pm->ps->clientNum || (cg.renderingThirdPerson && !cg.zoomMode) ) + if ( (pm->ps->clientNum&&!PM_ControlledByPlayer()) || ((!pm->ps->clientNum||PM_ControlledByPlayer()) && cg.renderingThirdPerson && !cg.zoomMode) ) { - if ( pm->ps->saberAnimLevel == FORCE_LEVEL_2 //using medium attacks + if ( (pm->ps->saberAnimLevel == FORCE_LEVEL_2 || pm->ps->saberAnimLevel == FORCE_LEVEL_5)//using medium attacks or Tavion //&& !PM_InKnockDown( pm->ps ) && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 //can force jump && !(pm->gent->flags&FL_LOCK_PLAYER_WEAPONS) // yes this locked weapons check also includes force powers, if we need a separate check later I'll make one && (pm->ps->groundEntityNum != ENTITYNUM_NONE||level.time-pm->ps->lastOnGround<=500) //on ground or just jumped - && ((pm->ps->clientNum&&!Q_irand(0,2))||pm->cmd.upmove>0||pm->ps->pm_flags&PMF_JUMPING))//jumping + && ( pm->ps->clientNum || pm->ps->legsAnim == BOTH_JUMP1 || pm->ps->legsAnim == BOTH_FORCEJUMP1 || pm->ps->legsAnim == BOTH_INAIR1 || pm->ps->legsAnim == BOTH_FORCEINAIR1 )//either an NPC or in a non-flip forward jump + && ((pm->ps->clientNum&&!PM_ControlledByPlayer()&&!Q_irand(0,2))||pm->cmd.upmove>0||pm->ps->pm_flags&PMF_JUMPING))//jumping {//flip over-forward down-attack - if ( !pm->ps->clientNum || - (pm->gent->NPC && (pm->gent->NPC->rank==RANK_CREWMAN||pm->gent->NPC->rank>=RANK_LT) ) ) + if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) || + (pm->gent->NPC && (pm->gent->NPC->rank==RANK_CREWMAN||pm->gent->NPC->rank>=RANK_LT) && !Q_irand(0, 2) ) ) {//only player or acrobat or boss and higher can do this vec3_t fwdAngles = {0,pm->ps->viewangles[YAW],0}; if ( pm->gent->enemy->health > 0 @@ -1408,21 +1429,25 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) } } } - if ( pm->ps->clientNum || (cg.renderingThirdPerson && !cg.zoomMode) ) + if ( (pm->ps->clientNum&&!PM_ControlledByPlayer()) || ((!pm->ps->clientNum||PM_ControlledByPlayer()) && cg.renderingThirdPerson && !cg.zoomMode) ) { if ( (pm->ps->saberAnimLevel == FORCE_LEVEL_1 || (pm->gent&&pm->gent->client&&pm->gent->client->NPC_class == CLASS_DESANN && !Q_irand( 0, 2 ))) //&& !PM_InKnockDown( pm->ps ) && (pm->cmd.upmove < 0 || pm->ps->pm_flags&PMF_DUCKED) && (pm->ps->legsAnim == BOTH_STAND2||pm->ps->legsAnim == BOTH_SABERFAST_STANCE||pm->ps->legsAnim == BOTH_SABERSLOW_STANCE||level.time-pm->ps->lastStationary<=500) ) {//not moving (or just started), ducked and using fast attacks - if ( !pm->ps->clientNum || - ( pm->gent && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG ) ) + if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) || + ( pm->gent + && pm->gent->NPC + && pm->gent->NPC->rank >= RANK_LT_JG + && ( pm->gent->NPC->rank == RANK_LT_JG || Q_irand( 0, pm->gent->NPC->rank ) >= RANK_ENSIGN ) + && !Q_irand( 0, 3-g_spskill->integer ) ) ) {//only player or fencer and higher can do this return PM_SaberLungeAttackMove(); } } } - if ( pm->ps->clientNum ) + if ( pm->ps->clientNum && !PM_ControlledByPlayer() ) { if ( (pm->ps->saberAnimLevel == FORCE_LEVEL_3 || (pm->gent&&pm->gent->client&&pm->gent->client->NPC_class == CLASS_DESANN && !Q_irand( 0, 1 )))//using strong attacks //&& !PM_InKnockDown( pm->ps ) @@ -1433,7 +1458,7 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) && (pm->cmd.upmove||pm->ps->pm_flags&PMF_JUMPING))//jumping {//strong attack: jump-hack if ( //!pm->ps->clientNum || - (pm->gent && pm->gent->NPC && (pm->gent->NPC->rank==RANK_CREWMAN||pm->gent->NPC->rank>=RANK_LT) ) ) + (pm->gent && pm->gent->NPC && !PM_ControlledByPlayer() && (pm->gent->NPC->rank==RANK_CREWMAN||pm->gent->NPC->rank>=RANK_LT) ) ) {//only player or acrobat or boss and higher can do this return PM_SaberJumpAttackMove(); } @@ -1444,7 +1469,7 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) } else if ( forwardmove < 0 ) {//backward= T2B slash//B2T uppercut? - if ( pm->ps->clientNum || (cg.renderingThirdPerson && !cg.zoomMode) ) + if ( (pm->ps->clientNum&&!PM_ControlledByPlayer()) || ((!pm->ps->clientNum||PM_ControlledByPlayer()) && cg.renderingThirdPerson && !cg.zoomMode) ) { //if ( !PM_InKnockDown( pm->ps ) ) { @@ -1462,7 +1487,7 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) {//fast attacks and Tavion if ( !(pm->ps->pm_flags&PMF_DUCKED) && pm->cmd.upmove >= 0 ) {//can't do it while ducked? - if ( !pm->ps->clientNum || (pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG) ) + if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) || (pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG) ) {//only fencers and above can do this return LS_A_BACKSTAB; } @@ -1485,7 +1510,7 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) float enemyDistSq = DistanceSquared( pm->gent->currentOrigin, pm->gent->enemy->currentOrigin ); if ( (pm->ps->saberAnimLevel == FORCE_LEVEL_1||pm->gent->client->NPC_class==CLASS_TAVION||(pm->gent->client->NPC_class==CLASS_DESANN&&!Q_irand(0,3))) && enemyDistSq > 16384 || pm->gent->enemy->health <= 0 )//128 squared {//my enemy is pretty far in front of me and I'm using fast attacks - if ( !pm->ps->clientNum || + if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) || ( pm->gent && pm->gent->client && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG && Q_irand( 0, pm->gent->NPC->rank ) > RANK_ENSIGN ) ) {//only fencers and higher can do this, higher rank does it more if ( PM_CheckEnemyInBack( 128 ) ) @@ -1496,7 +1521,7 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) } else if ( (pm->ps->saberAnimLevel >= FORCE_LEVEL_2 || pm->gent->client->NPC_class == CLASS_DESANN) && enemyDistSq > 40000 || pm->gent->enemy->health <= 0 )//200 squared {//enemy is very faw away and I'm using medium/strong attacks - if ( !pm->ps->clientNum || + if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) || ( pm->gent && pm->gent->client && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG && Q_irand( 0, pm->gent->NPC->rank ) > RANK_ENSIGN ) ) {//only fencers and higher can do this, higher rank does it more if ( PM_CheckEnemyInBack( 164 ) ) @@ -1509,7 +1534,7 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) } else {//no current enemy - if ( !pm->ps->clientNum && pm->gent && pm->gent->client ) + if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) && pm->gent && pm->gent->client ) {//only player if ( PM_CheckEnemyInBack( 128 ) ) { @@ -1525,7 +1550,7 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) else if ( PM_SaberInBounce( move ) ) {//bounces should go to their default attack if you don't specify a direction but are attacking int newmove; - if ( pm->ps->clientNum && Q_irand( 0, 3 ) ) + if ( pm->ps->clientNum && !PM_ControlledByPlayer() && Q_irand( 0, 3 ) ) {//use NPC random newmove = PM_NPCSaberAttackFromQuad( saberMoveData[move].endQuad ); } @@ -1545,7 +1570,7 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) else if ( PM_SaberInKnockaway( move ) ) {//bounces should go to their default attack if you don't specify a direction but are attacking int newmove; - if ( pm->ps->clientNum && Q_irand( 0, 3 ) ) + if ( pm->ps->clientNum && !PM_ControlledByPlayer() && Q_irand( 0, 3 ) ) {//use NPC random newmove = PM_NPCSaberAttackFromQuad( saberMoveData[move].endQuad ); } @@ -1572,20 +1597,25 @@ int PM_SaberAttackForMovement( int forwardmove, int rightmove, int move ) } else if ( move == LS_READY || move == LS_A_FLIP_STAB || move == LS_A_FLIP_SLASH ) {//Not moving at all, shouldn't have gotten here...? - if ( pm->gent && pm->gent->enemy ) - {//based on enemy position, pick a proper attack - int autoMove = PM_AttackForEnemyPos( qtrue ); - if ( autoMove != -1 ) - { - return autoMove; + if ( pm->ps->clientNum || g_saberAutoAim->integer ) + {//auto-aim + if ( pm->gent && pm->gent->enemy ) + {//based on enemy position, pick a proper attack + int autoMove = PM_AttackForEnemyPos( qtrue ); + if ( autoMove != -1 ) + { + return autoMove; + } + } + else if ( fabs(pm->ps->viewangles[0]) > 30 ) + {//looking far up or far down uses the top to bottom attack, presuming you want a vertical attack + return LS_A_T2B; } } - else if ( fabs(pm->ps->viewangles[0]) > 30 ) - {//looking far up or far down uses the top to bottom attack, presuming you want a vertical attack - return LS_A_T2B; + else + {//for now, just pick a random attack + return Q_irand( LS_A_TL2BR, LS_A_T2B ); } - //for now, just pick a random attack - //return Q_irand( LS_A_TL2BR, LS_A_T2B ); } } //FIXME: pick a return? @@ -1754,6 +1784,84 @@ int PM_SaberAnimTransitionAnim( int curmove, int newmove ) return retmove; } +/* +------------------------- +PM_LegsAnimForFrame +Returns animNumber for current frame +------------------------- +*/ +int PM_LegsAnimForFrame( gentity_t *ent, int legsFrame ) +{ + //Must be a valid client + if ( ent->client == NULL ) + return -1; + + //Must have a file index entry + if( ValidAnimFileIndex( ent->client->clientInfo.animFileIndex ) == qfalse ) + return -1; + + animation_t *animations = level.knownAnimFileSets[ent->client->clientInfo.animFileIndex].animations; + + for ( int animation = 0; animation < FACE_TALK1; animation++ ) + { + if ( animation >= TORSO_DROPWEAP1 && animation < LEGS_WALKBACK1 ) + {//not a possible legs anim + continue; + } + + if ( animations[animation].firstFrame > legsFrame ) + {//This anim starts after this frame + continue; + } + + if ( animations[animation].firstFrame + animations[animation].numFrames < legsFrame ) + {//This anim ends before this frame + continue; + } + //else, must be in this anim! + return animation; + } + + //Not in ANY torsoAnim? SHOULD NEVER HAPPEN +// assert(0); + return -1; +} + +int PM_ValidateAnimRange( int startFrame, int endFrame, float animSpeed ) +{//given a startframe and endframe, see if that lines up with any known animation + animation_t *animations = level.knownAnimFileSets[0].animations; + + for ( int anim = 0; anim < MAX_ANIMATIONS; anim++ ) + { + if ( animSpeed < 0 ) + {//playing backwards + if ( animations[anim].firstFrame == endFrame ) + { + if ( animations[anim].numFrames + animations[anim].firstFrame == startFrame ) + { + //Com_Printf( "valid reverse anim: %s\n", animTable[anim].name ); + return anim; + } + } + } + else + {//playing forwards + if ( animations[anim].firstFrame == startFrame ) + {//This anim starts on this frame + if ( animations[anim].firstFrame + animations[anim].numFrames == endFrame ) + {//This anim ends on this frame + //Com_Printf( "valid forward anim: %s\n", animTable[anim].name ); + return anim; + } + } + } + //else, must not be this anim! + } + + //Not in ANY anim? SHOULD NEVER HAPPEN + Com_Printf( "invalid anim range %d to %d, speed %4.2f\n", startFrame, endFrame, animSpeed ); + return -1; +} /* ------------------------- PM_TorsoAnimForFrame @@ -1828,6 +1936,11 @@ qboolean PM_HasAnimation( gentity_t *ent, int animation ) if ( !ent || ent->client == NULL ) return qfalse; + //must be a valid anim number + if ( animation < 0 || animation >= MAX_ANIMATIONS ) + { + return qfalse; + } //Must have a file index entry if( ValidAnimFileIndex( ent->client->clientInfo.animFileIndex ) == qfalse ) return qfalse; @@ -1944,6 +2057,13 @@ extern qboolean PM_SpinningSaberAnim( int anim ); extern float saberAnimSpeedMod[NUM_FORCE_POWER_LEVELS]; void PM_SaberStartTransAnim( int saberAnimLevel, int anim, float *animSpeed, gentity_t *gent ) { + if ( g_saberAnimSpeed->value != 1.0f ) + { + if ( anim >= BOTH_A1_T__B_ && anim <= BOTH_CROUCHATTACKBACK1 ) + { + *animSpeed *= g_saberAnimSpeed->value; + } + } if ( gent && gent->NPC && gent->NPC->rank == RANK_CIVILIAN ) {//grunt reborn if ( anim >= BOTH_A1_T__B_ && anim <= BOTH_R1_TR_S1 ) @@ -2029,7 +2149,7 @@ float PM_GetTimeScaleMod( gentity_t *gent ) { return (1.0 / g_timescale->value); } - else if ( gent && gent->client && gent->client->NPC_class == CLASS_TAVION && gent->client->ps.forcePowersActive&(1<client && (gent->client->NPC_class == CLASS_TAVION||gent->client->NPC_class == CLASS_DESANN) && gent->client->ps.forcePowersActive&(1<value); } @@ -2053,6 +2173,14 @@ void PM_SetAnimFinal(int *torsoAnim,int *legsAnim, { return; } + if ( anim < 0 || anim >= MAX_ANIMATIONS ) + { + assert( 0&&"anim out of range!!!" ); +#ifndef FINAL_BUILD + G_Error( "%s tried to play invalid anim %d\n", gent->NPC_type, anim ); +#endif + return; + } animation_t *animations = level.knownAnimFileSets[gent->client->clientInfo.animFileIndex].animations; float timeScaleMod = PM_GetTimeScaleMod( gent ); float animSpeed, oldAnimSpeed; @@ -2153,44 +2281,72 @@ void PM_SetAnimFinal(int *torsoAnim,int *legsAnim, animFlags |= BONE_ANIM_BLEND; } //HACKHACKHACK - qboolean animatingLegs = gi.G2API_GetAnimRange(&gent->ghoul2[gent->playerModel], "model_root", &startFrame, &endFrame); - if ( !(setAnimFlags & SETANIM_FLAG_RESTART) && animatingLegs && (animations[anim].firstFrame == startFrame) && (((animations[anim].numFrames ) + animations[anim].firstFrame) == endFrame)) - {//if we're playing this anim on the legs already andwe're not restarting the anim, then match the legs' frame - float currentFrame, legAnimSpeed; - int flags; - gi.G2API_GetBoneAnimIndex(&gent->ghoul2[gent->playerModel], gent->rootBone,actualTime, ¤tFrame, &startFrame, &endFrame, &flags, &legAnimSpeed, NULL); - // assert((currentFrame <=endFrame) && (currentFrame>=startFrame)); - // yes, its the same animation, so work out where we are in the leg anim, and blend us + //qboolean animatingLegs = gi.G2API_GetAnimRange(&gent->ghoul2[gent->playerModel], "model_root", &startFrame, &endFrame); + float currentFrame, legAnimSpeed, firstFrame, lastFrame; + int flags; + qboolean animatingLegs = gi.G2API_GetBoneAnimIndex(&gent->ghoul2[gent->playerModel], + gent->rootBone, actualTime, ¤tFrame, + &startFrame, &endFrame, &flags, &legAnimSpeed, NULL ); + if ( g_synchSplitAnims->integer + && !(setAnimFlags & SETANIM_FLAG_RESTART) + && animatingLegs + && (animations[anim].firstFrame == startFrame) + && (legAnimSpeed == animSpeed )//|| oldAnimSpeed != animSpeed) + && (((animations[anim].numFrames ) + animations[anim].firstFrame) == endFrame)) + {//if we're playing this *exact* anim (speed check should fix problems with anims that play other anims backwards) on the legs already andwe're not restarting the anim, then match the legs' frame + if ( 0 ) + {//just stop it + gi.G2API_StopBoneAnimIndex( &gent->ghoul2[gent->playerModel], gent->lowerLumbarBone );//gent->upperLumbarBone + gi.G2API_StopBoneAnimIndex( &gent->ghoul2[gent->playerModel], gent->motionBone );//gent->upperLumbarBone + } + else + {//try to synch it +// assert((currentFrame <=endFrame) && (currentFrame>=startFrame)); + // yes, its the same animation, so work out where we are in the leg anim, and blend us #if G2_DEBUG_TIMING - Com_Printf("tlegb %d %d %d %4.2f %4.2f %d\n", - actualTime, - animations[anim].firstFrame, - (animations[anim].numFrames )+ animations[anim].firstFrame, - legAnimSpeed, - currentFrame, - blendTime); -#endif - gi.G2API_SetBoneAnimIndex(&gent->ghoul2[gent->playerModel], gent->lowerLumbarBone, animations[anim].firstFrame, //gent->upperLumbarBone - (animations[anim].numFrames )+ animations[anim].firstFrame, - animFlags, legAnimSpeed, actualTime, currentFrame, blendTime); - if ( gent->motionBone != -1 ) - { - gi.G2API_SetBoneAnimIndex(&gent->ghoul2[gent->playerModel], gent->motionBone, animations[anim].firstFrame, //gent->upperLumbarBone - (animations[anim].numFrames )+ animations[anim].firstFrame, - animFlags, legAnimSpeed, actualTime, currentFrame, blendTime); + Com_Printf("tlegb %d %d %d %4.2f %4.2f %d\n", + actualTime, + animations[anim].firstFrame, + (animations[anim].numFrames )+ animations[anim].firstFrame, + legAnimSpeed, + currentFrame, + blendTime); +#endif^ + if ( oldAnimSpeed != animSpeed + && ((oldAnimSpeed>0&&animSpeed>0) || (oldAnimSpeed<0&&animSpeed<0)) ) + {//match the new speed, actually + legAnimSpeed = animSpeed; + } + if ( legAnimSpeed < 0 ) + {//play anim backwards + lastFrame = animations[anim].firstFrame;// -1; + firstFrame = (animations[anim].numFrames) + animations[anim].firstFrame;// -1) + animations[anim].firstFrame; + } + else + { + firstFrame = animations[anim].firstFrame; + lastFrame = (animations[anim].numFrames ) + animations[anim].firstFrame; + } + gi.G2API_SetBoneAnimIndex(&gent->ghoul2[gent->playerModel], gent->lowerLumbarBone, //gent->upperLumbarBone + firstFrame, lastFrame, animFlags, legAnimSpeed, + actualTime, currentFrame, blendTime); + if ( gent->motionBone != -1 ) + { + gi.G2API_SetBoneAnimIndex(&gent->ghoul2[gent->playerModel], gent->motionBone, + firstFrame, lastFrame, animFlags, legAnimSpeed, + actualTime, currentFrame, blendTime); + } } } - // no, we aren't the same anim as the legs are running, so just run it. else - { + {// no, we aren't the same anim as the legs are running, so just run it. // animSpeed is 1.0 if the frameLerp (ms/frame) is 50 (20 fps). int firstFrame; int lastFrame; if ( animSpeed < 0 ) {//play anim backwards - - lastFrame = animations[anim].firstFrame -1; - firstFrame = (animations[anim].numFrames -1) + animations[anim].firstFrame ; + lastFrame = animations[anim].firstFrame;// -1; + firstFrame = (animations[anim].numFrames) + animations[anim].firstFrame;;// -1) + animations[anim].firstFrame; } else { @@ -2201,7 +2357,7 @@ void PM_SetAnimFinal(int *torsoAnim,int *legsAnim, qboolean animatingTorso = gi.G2API_GetAnimRange(&gent->ghoul2[gent->playerModel], "lower_lumbar", &startFrame, &endFrame);//"upper_lumbar" // lets see if a) we are already animating and b) we aren't going to do the same animation again - if (animatingTorso && ((animations[anim].firstFrame != startFrame) || (((animations[anim].numFrames ) + animations[anim].firstFrame) != endFrame))) + if (animatingTorso && ( (firstFrame != startFrame) || (lastFrame != endFrame) ) ) { #if G2_DEBUG_TIMING Com_Printf("trsob %d %d %d %4.2f %4.2f %d\n", @@ -2367,47 +2523,100 @@ setAnimLegs: int lastFrame; if ( animSpeed < 0 ) {//play anim backwards - lastFrame = animations[anim].firstFrame -1; - firstFrame = (animations[anim].numFrames -1) + animations[anim].firstFrame; + lastFrame = animations[anim].firstFrame;// -1; + firstFrame = (animations[anim].numFrames) + animations[anim].firstFrame;// -1) + animations[anim].firstFrame; } else { firstFrame = animations[anim].firstFrame; lastFrame = (animations[anim].numFrames ) + animations[anim].firstFrame; } - // before we do this, lets see if this animation is one the legs are already playing? - qboolean animatingLegs = gi.G2API_GetAnimRange(&gent->ghoul2[gent->playerModel], "model_root", &startFrame, &endFrame); - // lets see if a) we are already animating and b) we aren't going to do the same animation again - if (animatingLegs && ((animations[anim].firstFrame != startFrame) || (((animations[anim].numFrames ) + animations[anim].firstFrame) != endFrame))) - { + //HACKHACKHACK + //qboolean animatingTorso = gi.G2API_GetAnimRangeIndex(&gent->ghoul2[gent->playerModel], gent->lowerLumbarBone, &startFrame, &endFrame); + float currentFrame, torsoAnimSpeed; + int flags; + qboolean animatingTorso = gi.G2API_GetBoneAnimIndex(&gent->ghoul2[gent->playerModel], gent->lowerLumbarBone,actualTime, ¤tFrame, &startFrame, &endFrame, &flags, &torsoAnimSpeed, NULL); + if ( g_synchSplitAnims->integer + && !(setAnimFlags & SETANIM_FLAG_RESTART) + && animatingTorso + && (torsoAnimSpeed == animSpeed)//|| oldAnimSpeed != animSpeed) + && (animations[anim].firstFrame == startFrame) + && (((animations[anim].numFrames ) + animations[anim].firstFrame) == endFrame)) + {//if we're playing this *exact* anim on the torso already and we're not restarting the anim, then match the torso's frame + //try to synch it +// assert((currentFrame <=endFrame) && (currentFrame>=startFrame)); + // yes, its the same animation, so work out where we are in the torso anim, and blend us #if G2_DEBUG_TIMING - Com_Printf("legsb %d %d %d %4.2f %4.2f %d\n", + Com_Printf("ltrsb %d %d %d %4.2f %4.2f %d\n", actualTime, - firstFrame, - lastFrame, - animSpeed, - -1, + animations[anim].firstFrame, + (animations[anim].numFrames )+ animations[anim].firstFrame, + legAnimSpeed, + currentFrame, blendTime); #endif + if ( oldAnimSpeed != animSpeed + && ((oldAnimSpeed>0&&animSpeed>0) || (oldAnimSpeed<0&&animSpeed<0)) ) + {//match the new speed, actually + torsoAnimSpeed = animSpeed; + } + if ( torsoAnimSpeed < 0 ) + {//play anim backwards + lastFrame = animations[anim].firstFrame;// -1; + firstFrame = (animations[anim].numFrames) + animations[anim].firstFrame;// -1) + animations[anim].firstFrame; + } + else + { + firstFrame = animations[anim].firstFrame; + lastFrame = (animations[anim].numFrames ) + animations[anim].firstFrame; + } + gi.G2API_SetBoneAnimIndex(&gent->ghoul2[gent->playerModel], gent->rootBone, - firstFrame, lastFrame, animFlags, - animSpeed, actualTime, -1, blendTime); + firstFrame, lastFrame, animFlags, torsoAnimSpeed, + actualTime, currentFrame, blendTime ); } else - { - // no, ok, no blend then because we are either looping on the same anim, or starting from no anim + {// no, we aren't the same anim as the torso is running, so just run it. + // before we do this, lets see if this animation is one the legs are already playing? + //qboolean animatingLegs = gi.G2API_GetAnimRange(&gent->ghoul2[gent->playerModel], "model_root", &startFrame, &endFrame); + float currentFrame, legAnimSpeed; + int flags; + qboolean animatingLegs = gi.G2API_GetBoneAnimIndex(&gent->ghoul2[gent->playerModel], + gent->rootBone, actualTime, ¤tFrame, + &startFrame, &endFrame, &flags, &legAnimSpeed, NULL ); + // lets see if a) we are already animating and b) we aren't going to do the same animation again + if (animatingLegs + && ( (legAnimSpeed!=animSpeed) || (firstFrame != startFrame) || (lastFrame != endFrame) ) ) + { #if G2_DEBUG_TIMING - Com_Printf("legsn %d %d %d %4.2f %4.2f %d\n", - actualTime, - firstFrame, - lastFrame, - animSpeed, - -1, - -1); + Com_Printf("legsb %d %d %d %4.2f %4.2f %d\n", + actualTime, + firstFrame, + lastFrame, + animSpeed, + -1, + blendTime); #endif - gi.G2API_SetBoneAnimIndex(&gent->ghoul2[gent->playerModel], gent->rootBone, - firstFrame, lastFrame, animFlags&~BONE_ANIM_BLEND, - animSpeed, cg.time); + gi.G2API_SetBoneAnimIndex(&gent->ghoul2[gent->playerModel], gent->rootBone, + firstFrame, lastFrame, animFlags, + animSpeed, actualTime, -1, blendTime); + } + else + { + // no, ok, no blend then because we are either looping on the same anim, or starting from no anim +#if G2_DEBUG_TIMING + Com_Printf("legsn %d %d %d %4.2f %4.2f %d\n", + actualTime, + firstFrame, + lastFrame, + animSpeed, + -1, + -1); +#endif + gi.G2API_SetBoneAnimIndex(&gent->ghoul2[gent->playerModel], gent->rootBone, + firstFrame, lastFrame, animFlags&~BONE_ANIM_BLEND, + animSpeed, cg.time); + } } } } @@ -2517,12 +2726,10 @@ void PM_TorsoAnimLightsaber() return; } - if (pm->ps->weaponTime > 0) - { // weapon is already busy. - return; - } - - if ( pm->ps->saberActive && pm->ps->saberLength < 1 ) + if ( pm->ps->saberActive + && pm->ps->saberLength < 3 + && !(pm->ps->saberEventFlags&SEF_HITWALL) + && pm->ps->weaponstate == WEAPON_RAISING ) { PM_SetSaberMove(LS_DRAW); return; @@ -2533,6 +2740,11 @@ void PM_TorsoAnimLightsaber() return; } + if (pm->ps->weaponTime > 0) + { // weapon is already busy. + return; + } + if ( pm->ps->weaponstate == WEAPON_READY || pm->ps->weaponstate == WEAPON_CHARGING || pm->ps->weaponstate == WEAPON_CHARGING_ALT ) @@ -2723,7 +2935,14 @@ void PM_TorsoAnimLightsaber() } else { - PM_SetSaberMove(LS_READY); + if ( PM_RunningAnim( pm->ps->legsAnim ) ) + {//running w/1-handed weapon uses full-body anim + PM_SetAnim(pm,SETANIM_TORSO,pm->ps->legsAnim,SETANIM_FLAG_NORMAL); + } + else + { + PM_SetSaberMove(LS_READY); + } } } } @@ -2875,6 +3094,15 @@ void PM_TorsoAnimation( void ) { weaponBusy = qtrue; } + else if ( !pm->ps->clientNum && cg.zoomTime > cg.time - 5000 ) + {//if we used binoculars recently, aim weapon + weaponBusy = qtrue; + pm->ps->weaponstate = WEAPON_IDLE; + } + else if ( pm->ps->pm_flags & PMF_DUCKED ) + {//ducking is considered on alert... plus looks stupid to have arms hanging down when crouched + weaponBusy = qtrue; + } if ( pm->ps->weapon == WP_NONE || pm->ps->weaponstate == WEAPON_READY || @@ -2914,18 +3142,10 @@ void PM_TorsoAnimation( void ) { PM_SetAnim(pm,SETANIM_TORSO,BOTH_SWIM_IDLE1,SETANIM_FLAG_NORMAL); } - else if( pm->ps->legsAnim == BOTH_SWIMFORWARDSTART && !weaponBusy ) - { - PM_SetAnim(pm,SETANIM_TORSO,BOTH_SWIMFORWARDSTART,SETANIM_FLAG_NORMAL); - } else if( pm->ps->legsAnim == BOTH_SWIMFORWARD && !weaponBusy ) { PM_SetAnim(pm,SETANIM_TORSO,BOTH_SWIMFORWARD,SETANIM_FLAG_NORMAL); } - else if( pm->ps->legsAnim == BOTH_SWIMFORWARDSTOP && !weaponBusy ) - { - PM_SetAnim(pm,SETANIM_TORSO,BOTH_SWIMFORWARDSTOP,SETANIM_FLAG_NORMAL); - } else if ( pm->ps->weapon == WP_NONE ) { int legsAnim = pm->ps->legsAnim; @@ -2990,7 +3210,10 @@ void PM_TorsoAnimation( void ) { PM_SetAnim(pm,SETANIM_TORSO,TORSO_WEAPONREADY2,SETANIM_FLAG_NORMAL); } - else if ( PM_RunningAnim( pm->ps->legsAnim ) || PM_WalkingAnim( pm->ps->legsAnim ) || PM_SwimmingAnim( pm->ps->legsAnim ) ) + else if ( PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim ) ) {//running w/1-handed weapon uses full-body anim PM_SetAnim(pm,SETANIM_TORSO,pm->ps->legsAnim,SETANIM_FLAG_NORMAL); } @@ -3004,7 +3227,10 @@ void PM_TorsoAnimation( void ) { PM_SetAnim(pm,SETANIM_TORSO,TORSO_WEAPONREADY2,SETANIM_FLAG_NORMAL); } - else if ( PM_RunningAnim( pm->ps->legsAnim ) || PM_WalkingAnim( pm->ps->legsAnim ) || PM_SwimmingAnim( pm->ps->legsAnim ) ) + else if ( PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim ) ) {//running w/1-handed weapon uses full-body anim PM_SetAnim(pm,SETANIM_TORSO,pm->ps->legsAnim,SETANIM_FLAG_NORMAL); } @@ -3017,7 +3243,10 @@ void PM_TorsoAnimation( void ) //NOTE: should never get here break; case WP_MELEE: - if ( PM_RunningAnim( pm->ps->legsAnim ) || PM_WalkingAnim( pm->ps->legsAnim ) || PM_SwimmingAnim( pm->ps->legsAnim ) ) + if ( PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim ) ) {//running w/1-handed weapon uses full-body anim PM_SetAnim(pm,SETANIM_TORSO,pm->ps->legsAnim,SETANIM_FLAG_NORMAL); } @@ -3038,13 +3267,46 @@ void PM_TorsoAnimation( void ) //PM_SetAnim(pm,SETANIM_LEGS,BOTH_ATTACK2,SETANIM_FLAG_NORMAL); break; case WP_DISRUPTOR: - PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY3, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );//TORSO_WEAPONREADY4//SETANIM_FLAG_RESTART| + if ( (pm->ps->weaponstate != WEAPON_FIRING + && pm->ps->weaponstate != WEAPON_CHARGING + && pm->ps->weaponstate != WEAPON_CHARGING_ALT) + || PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim ) ) + {//running sniper weapon uses normal ready + if ( pm->ps->clientNum ) + { + PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY3, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );//TORSO_WEAPONREADY4//SETANIM_FLAG_RESTART| + } + else + { + PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY3, SETANIM_FLAG_NORMAL ); + } + } + else + { + if ( pm->ps->clientNum ) + { + PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY4, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );//TORSO_WEAPONREADY4//SETANIM_FLAG_RESTART| + } + else + { + PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY4, SETANIM_FLAG_NORMAL ); + } + } break; case WP_BOT_LASER: PM_SetAnim(pm,SETANIM_TORSO,TORSO_WEAPONIDLE2,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_RESTART|SETANIM_FLAG_HOLD); break; case WP_THERMAL: - if ( PM_RunningAnim( pm->ps->legsAnim ) || PM_WalkingAnim( pm->ps->legsAnim ) || PM_SwimmingAnim( pm->ps->legsAnim ) ) + if ( pm->ps->weaponstate != WEAPON_FIRING + && pm->ps->weaponstate != WEAPON_CHARGING + && pm->ps->weaponstate != WEAPON_CHARGING_ALT + && (PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim )) ) {//running w/1-handed weapon uses full-body anim PM_SetAnim(pm,SETANIM_TORSO,pm->ps->legsAnim,SETANIM_FLAG_NORMAL); } @@ -3056,7 +3318,14 @@ void PM_TorsoAnimation( void ) } else { - PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY10, SETANIM_FLAG_NORMAL ); + if ( weaponBusy ) + { + PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY10, SETANIM_FLAG_NORMAL ); + } + else + { + PM_SetAnim( pm, SETANIM_TORSO, BOTH_STAND1, SETANIM_FLAG_NORMAL ); + } } } break; @@ -3079,13 +3348,23 @@ void PM_TorsoAnimation( void ) break; case WP_TRIP_MINE: case WP_DET_PACK: - if ( PM_RunningAnim( pm->ps->legsAnim ) || PM_WalkingAnim( pm->ps->legsAnim ) || PM_SwimmingAnim( pm->ps->legsAnim ) ) + if ( PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim ) ) {//running w/1-handed weapon uses full-body anim PM_SetAnim(pm,SETANIM_TORSO,pm->ps->legsAnim,SETANIM_FLAG_NORMAL); } else { - PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY10, SETANIM_FLAG_NORMAL ); + if ( weaponBusy ) + { + PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY3, SETANIM_FLAG_NORMAL ); + } + else + { + PM_SetAnim( pm, SETANIM_TORSO, BOTH_STAND1, SETANIM_FLAG_NORMAL ); + } } break; default: @@ -3131,18 +3410,10 @@ void PM_TorsoAnimation( void ) { PM_SetAnim(pm,SETANIM_TORSO,BOTH_SWIM_IDLE1,SETANIM_FLAG_NORMAL); } - else if( pm->ps->legsAnim == BOTH_SWIMFORWARDSTART ) - { - PM_SetAnim(pm,SETANIM_TORSO,BOTH_SWIMFORWARDSTART,SETANIM_FLAG_NORMAL); - } else if( pm->ps->legsAnim == BOTH_SWIMFORWARD ) { PM_SetAnim(pm,SETANIM_TORSO,BOTH_SWIMFORWARD,SETANIM_FLAG_NORMAL); } - else if( pm->ps->legsAnim == BOTH_SWIMFORWARDSTOP ) - { - PM_SetAnim(pm,SETANIM_TORSO,BOTH_SWIMFORWARDSTOP,SETANIM_FLAG_NORMAL); - } else if ( PM_InSpecialJump( pm->ps->legsAnim ) ) {//use legs anim //FIXME: or just use whatever's currently playing? @@ -3162,7 +3433,10 @@ void PM_TorsoAnimation( void ) && pm->ps->weapon != WP_REPEATER && pm->ps->weapon != WP_FLECHETTE && pm->ps->weapon != WP_ROCKET_LAUNCHER - && ( PM_RunningAnim( pm->ps->legsAnim ) || PM_WalkingAnim( pm->ps->legsAnim ) || PM_SwimmingAnim( pm->ps->legsAnim ) ) ) + && ( PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim ) ) ) {//running w/1-handed or light 2-handed weapon uses full-body anim if you're not using the weapon right now PM_SetAnim(pm,SETANIM_TORSO,pm->ps->legsAnim,SETANIM_FLAG_NORMAL); } @@ -3181,7 +3455,10 @@ void PM_TorsoAnimation( void ) { PM_SetAnim(pm,SETANIM_TORSO,TORSO_WEAPONREADY2,SETANIM_FLAG_NORMAL); } - else if ( PM_RunningAnim( pm->ps->legsAnim ) || PM_WalkingAnim( pm->ps->legsAnim ) || PM_SwimmingAnim( pm->ps->legsAnim ) ) + else if ( PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim ) ) {//running w/1-handed weapon uses full-body anim PM_SetAnim(pm,SETANIM_TORSO,pm->ps->legsAnim,SETANIM_FLAG_NORMAL); } @@ -3195,7 +3472,10 @@ void PM_TorsoAnimation( void ) { PM_SetAnim(pm,SETANIM_TORSO,TORSO_WEAPONREADY2,SETANIM_FLAG_NORMAL); } - else if ( PM_RunningAnim( pm->ps->legsAnim ) || PM_WalkingAnim( pm->ps->legsAnim ) || PM_SwimmingAnim( pm->ps->legsAnim ) ) + else if ( PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim ) ) {//running w/1-handed weapon uses full-body anim PM_SetAnim(pm,SETANIM_TORSO,pm->ps->legsAnim,SETANIM_FLAG_NORMAL); } @@ -3210,7 +3490,10 @@ void PM_TorsoAnimation( void ) break; case WP_MELEE: - if ( PM_RunningAnim( pm->ps->legsAnim ) || PM_WalkingAnim( pm->ps->legsAnim ) || PM_SwimmingAnim( pm->ps->legsAnim ) ) + if ( PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim ) ) {//running w/1-handed weapon uses full-body anim PM_SetAnim(pm,SETANIM_TORSO,pm->ps->legsAnim,SETANIM_FLAG_NORMAL); } @@ -3239,7 +3522,34 @@ void PM_TorsoAnimation( void ) break; case WP_DISRUPTOR: - PM_SetAnim(pm,SETANIM_TORSO,TORSO_WEAPONREADY3,SETANIM_FLAG_NORMAL);//TORSO_WEAPONIDLE4//SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_RESTART|SETANIM_FLAG_HOLD + if ( (pm->ps->weaponstate != WEAPON_FIRING + && pm->ps->weaponstate != WEAPON_CHARGING + && pm->ps->weaponstate != WEAPON_CHARGING_ALT) + || PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim ) ) + {//running sniper weapon uses normal ready + if ( pm->ps->clientNum ) + { + PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY3, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );//TORSO_WEAPONREADY4//SETANIM_FLAG_RESTART| + } + else + { + PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY3, SETANIM_FLAG_NORMAL ); + } + } + else + { + if ( pm->ps->clientNum ) + { + PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY4, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );//TORSO_WEAPONREADY4//SETANIM_FLAG_RESTART| + } + else + { + PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONREADY4, SETANIM_FLAG_NORMAL ); + } + } break; case WP_BOT_LASER: @@ -3247,13 +3557,23 @@ void PM_TorsoAnimation( void ) break; case WP_THERMAL: - if ( PM_RunningAnim( pm->ps->legsAnim ) || PM_WalkingAnim( pm->ps->legsAnim ) || PM_SwimmingAnim( pm->ps->legsAnim ) ) + if ( PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim ) ) {//running w/1-handed weapon uses full-body anim PM_SetAnim(pm,SETANIM_TORSO,pm->ps->legsAnim,SETANIM_FLAG_NORMAL); } else { - PM_SetAnim(pm,SETANIM_TORSO,TORSO_WEAPONIDLE10,SETANIM_FLAG_NORMAL);//SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_RESTART|SETANIM_FLAG_HOLD + if ( weaponBusy ) + { + PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONIDLE10, SETANIM_FLAG_NORMAL ); + } + else + { + PM_SetAnim( pm, SETANIM_TORSO, BOTH_STAND1, SETANIM_FLAG_NORMAL ); + } } break; @@ -3283,13 +3603,23 @@ void PM_TorsoAnimation( void ) break; case WP_TRIP_MINE: case WP_DET_PACK: - if ( PM_RunningAnim( pm->ps->legsAnim ) || PM_WalkingAnim( pm->ps->legsAnim ) || PM_SwimmingAnim( pm->ps->legsAnim ) ) + if ( PM_RunningAnim( pm->ps->legsAnim ) + || PM_WalkingAnim( pm->ps->legsAnim ) + || PM_JumpingAnim( pm->ps->legsAnim ) + || PM_SwimmingAnim( pm->ps->legsAnim ) ) {//running w/1-handed weapon uses full-body anim PM_SetAnim(pm,SETANIM_TORSO,pm->ps->legsAnim,SETANIM_FLAG_NORMAL); } else { - PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONIDLE10, SETANIM_FLAG_NORMAL ); + if ( weaponBusy ) + { + PM_SetAnim( pm, SETANIM_TORSO, TORSO_WEAPONIDLE3, SETANIM_FLAG_NORMAL ); + } + else + { + PM_SetAnim( pm, SETANIM_TORSO, BOTH_STAND1, SETANIM_FLAG_NORMAL ); + } } break; @@ -3345,6 +3675,7 @@ int PM_GetTurnAnim( gentity_t *gent, int anim ) case BOTH_GESTURE2: //# Generic gesture: non-specific case BOTH_GESTURE3: //# Generic gesture: non-specific case BOTH_TALK1: //# Generic talk anim + case BOTH_TALK2: //# Generic talk anim if ( PM_HasAnimation( gent, LEGS_TURN1 ) ) { return LEGS_TURN1; @@ -3597,6 +3928,12 @@ qboolean PM_InDeathAnim ( void ) case BOTH_DEATH17: //# case BOTH_DEATH18: //# case BOTH_DEATH19: //# + case BOTH_DEATH20: //# + case BOTH_DEATH21: //# + case BOTH_DEATH22: //# + case BOTH_DEATH23: //# + case BOTH_DEATH24: //# + case BOTH_DEATH25: //# case BOTH_DEATHFORWARD1: //# First Death in which they get thrown forward case BOTH_DEATHFORWARD2: //# Second Death in which they get thrown forward @@ -3630,6 +3967,12 @@ qboolean PM_InDeathAnim ( void ) case BOTH_DEAD17: //# case BOTH_DEAD18: //# case BOTH_DEAD19: //# + case BOTH_DEAD20: //# + case BOTH_DEAD21: //# + case BOTH_DEAD22: //# + case BOTH_DEAD23: //# + case BOTH_DEAD24: //# + case BOTH_DEAD25: //# case BOTH_DEADFORWARD1: //# First thrown forward death finished pose case BOTH_DEADFORWARD2: //# Second thrown forward death finished pose case BOTH_DEADBACKWARD1: //# First thrown backward death finished pose diff --git a/code/game/bg_pmove.cpp b/code/game/bg_pmove.cpp index 61e821e..8547956 100644 --- a/code/game/bg_pmove.cpp +++ b/code/game/bg_pmove.cpp @@ -25,7 +25,7 @@ extern qboolean InFront( vec3_t spot, vec3_t from, vec3_t fromAngles, float thre extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType ); extern void WP_SaberInitBladeData( gentity_t *ent ); -extern void WP_SaberLose( gentity_t *self, vec3_t throwDir ); +extern qboolean WP_SaberLose( gentity_t *self, vec3_t throwDir ); extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); extern int Jedi_ReCalcParryTime( gentity_t *self, evasionType_t evasionType ); extern qboolean PM_HasAnimation( gentity_t *ent, int animation ); @@ -50,6 +50,7 @@ extern qboolean PM_SaberInStart( int move ); extern qboolean PM_SaberKataDone( int curmove, int newmove ); extern qboolean PM_SaberInSpecial( int move ); extern qboolean PM_InDeathAnim ( void ); +extern qboolean PM_StandingAnim( int anim ); extern int PM_SaberFlipOverAttackMove( void ); extern int PM_SaberJumpAttackMove( void ); @@ -63,10 +64,12 @@ qboolean PM_SpinningAnim( int anim ); qboolean PM_FlippingAnim( int anim ); qboolean PM_PainAnim( int anim ); qboolean PM_RollingAnim( int anim ); +qboolean PM_SwimmingAnim( int anim ); extern int parryDebounce[]; extern qboolean player_locked; extern qboolean MatrixMode; +qboolean waterForceJump; extern cvar_t *g_timescale; static void PM_SetWaterLevelAtPoint( vec3_t org, int *waterlevel, int *watertype ); @@ -116,6 +119,11 @@ extern void DoImpact( gentity_t *self, gentity_t *other, qboolean damageSelf ); #define PHASER_RECHARGE_TIME 100 extern int transitionMove[Q_NUM_QUADS][Q_NUM_QUADS]; +extern qboolean G_ControlledByPlayer( gentity_t *self ); +qboolean PM_ControlledByPlayer( void ) +{ + return G_ControlledByPlayer( pm->gent ); +} /* =============== PM_AddEvent @@ -284,9 +292,12 @@ static void PM_Friction( void ) { } // apply water friction even if just wading - if ( pm->waterlevel && !(pm->watertype & CONTENTS_LADDER)) + if ( !waterForceJump ) { - drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime; + if ( pm->waterlevel && !(pm->watertype & CONTENTS_LADDER)) + { + drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime; + } } // apply flying friction @@ -463,7 +474,15 @@ qboolean PM_ForceJumpingUp( gentity_t *gent ) if ( gent->NPC ) {//this is ONLY for the player - return qfalse; + if ( player + && player->client + && player->client->ps.viewEntity == gent->s.number ) + {//okay to jump if an NPC controlled by the player + } + else + { + return qfalse; + } } if ( !(gent->client->ps.forcePowersActive&(1<client->ps.forceJumpCharge ) @@ -485,11 +504,10 @@ qboolean PM_ForceJumpingUp( gentity_t *gent ) {//player can't use force powers in cinematic return qfalse; } - if ( gent->client->ps.groundEntityNum == ENTITYNUM_NONE && //in air - gent->client->ps.pm_flags & PMF_JUMPING &&//forceJumpZStart && //jumped - gent->client->ps.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_0 && //force-jump capable - gent->client->ps.velocity[2] > 0 &&//going up - !(gent->client->ps.pm_flags&PMF_TRIGGER_PUSHED) )//not pushed by a trigger + if ( gent->client->ps.groundEntityNum == ENTITYNUM_NONE //in air + && ( /*(gent->client->ps.waterHeightLevel==WHL_SHOULDERS&&gent->client->usercmd.upmove>0) ||*/ ((gent->client->ps.pm_flags&PMF_JUMPING)&&gent->client->ps.velocity[2] > 0) )//jumped & going up or at water surface + && gent->client->ps.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_0 //force-jump capable + && !(gent->client->ps.pm_flags&PMF_TRIGGER_PUSHED) )//not pushed by a trigger { if( gent->flags & FL_LOCK_PLAYER_WEAPONS ) // yes this locked weapons check also includes force powers, if we need a separate check later I'll make one { @@ -537,6 +555,27 @@ static void PM_JumpForDir( void ) extern qboolean WP_ForcePowerAvailable( gentity_t *self, forcePowers_t forcePower, int overrideAmt ); extern void WP_ForcePowerDrain( gentity_t *self, forcePowers_t forcePower, int overrideAmt ); +qboolean PM_GentCantJump( gentity_t *gent ) +{//FIXME: ugh, hacky, set a flag on NPC or something, please... + if ( gent && gent->client && + ( gent->client->NPC_class == CLASS_ATST || + gent->client->NPC_class == CLASS_GONK || + gent->client->NPC_class == CLASS_MARK1 || + gent->client->NPC_class == CLASS_MARK2 || + gent->client->NPC_class == CLASS_MOUSE || + gent->client->NPC_class == CLASS_PROBE || + gent->client->NPC_class == CLASS_PROTOCOL || + gent->client->NPC_class == CLASS_R2D2 || + gent->client->NPC_class == CLASS_R5D2 || + gent->client->NPC_class == CLASS_SEEKER || + gent->client->NPC_class == CLASS_REMOTE || + gent->client->NPC_class == CLASS_SENTRY ) ) + { + return qtrue; + } + return qfalse; +} + static qboolean PM_CheckJump( void ) { //Don't allow jump until all buttons are up @@ -549,20 +588,8 @@ static qboolean PM_CheckJump( void ) return qfalse; } - if ( pm->gent && pm->gent->client && - ( pm->gent->client->NPC_class == CLASS_ATST || - pm->gent->client->NPC_class == CLASS_GONK || - pm->gent->client->NPC_class == CLASS_MARK1 || - pm->gent->client->NPC_class == CLASS_MARK2 || - pm->gent->client->NPC_class == CLASS_MOUSE || - pm->gent->client->NPC_class == CLASS_PROBE || - pm->gent->client->NPC_class == CLASS_PROTOCOL || - pm->gent->client->NPC_class == CLASS_R2D2 || - pm->gent->client->NPC_class == CLASS_R5D2 || - pm->gent->client->NPC_class == CLASS_SEEKER || - pm->gent->client->NPC_class == CLASS_REMOTE || - pm->gent->client->NPC_class == CLASS_SENTRY ) ) - {//FIXME: ugh, hacky, set a flag on NPC or something, please... + if ( PM_GentCantJump( pm->gent ) ) + { return qfalse; } /* @@ -573,13 +600,19 @@ static qboolean PM_CheckJump( void ) */ #if METROID_JUMP - if ( pm->waterlevel < 3 ) + if ( pm->waterlevel < 3 )//|| (pm->ps->waterHeightLevel==WHL_SHOULDERS&&pm->cmd.upmove>0) ) { if ( pm->ps->gravity > 0 ) {//can't do this in zero-G //FIXME: still able to pogo-jump... - if ( PM_ForceJumpingUp( pm->gent ) && (pm->ps->pm_flags&PMF_JUMP_HELD) ) - {//holding jump in air + if ( PM_ForceJumpingUp( pm->gent ) && (pm->ps->pm_flags&PMF_JUMP_HELD) )//||pm->ps->waterHeightLevel==WHL_SHOULDERS) ) + {//force jumping && holding jump + /* + if ( !pm->ps->forceJumpZStart && (pm->ps->waterHeightLevel==WHL_SHOULDERS&&pm->cmd.upmove>0) ) + { + pm->ps->forceJumpZStart = pm->ps->origin[2]; + } + */ float curHeight = pm->ps->origin[2] - pm->ps->forceJumpZStart; //check for max force jump level and cap off & cut z vel if ( ( curHeight<=forceJumpHeight[0] ||//still below minimum jump height @@ -774,7 +807,7 @@ static qboolean PM_CheckJump( void ) { VectorMA( pm->ps->velocity, JUMP_VELOCITY/2, forward, pm->ps->velocity ); //FIXME: kicking off wall anim? At least check what anim we're in? - PM_SetAnim(pm,SETANIM_LEGS,BOTH_SWIMFORWARDSTART,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_RESTART); + PM_SetAnim(pm,SETANIM_LEGS,BOTH_FORCEJUMP1,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_RESTART); } else {//else no surf close enough to push off of @@ -811,7 +844,7 @@ static qboolean PM_CheckJump( void ) && !(pm->ps->pm_flags&PMF_JUMP_HELD) //&& !PM_InKnockDown( pm->ps ) && pm->gent && WP_ForcePowerAvailable( pm->gent, FP_LEVITATION, 0 ) - && (pm->ps->clientNum||(cg.renderingThirdPerson && !cg.zoomMode && !(pm->gent->flags&FL_LOCK_PLAYER_WEAPONS) )) )// yes this locked weapons check also includes force powers, if we need a separate check later I'll make one + && ((pm->ps->clientNum&&!PM_ControlledByPlayer())||((!pm->ps->clientNum||PM_ControlledByPlayer()) && cg.renderingThirdPerson && !cg.zoomMode && !(pm->gent->flags&FL_LOCK_PLAYER_WEAPONS) )) )// yes this locked weapons check also includes force powers, if we need a separate check later I'll make one { if ( pm->gent->NPC && pm->gent->NPC->rank != RANK_CREWMAN && pm->gent->NPC->rank <= RANK_LT_JG ) {//reborn who are not acrobats can't do any of these acrobatics @@ -847,7 +880,7 @@ static qboolean PM_CheckJump( void ) anim = BOTH_WALL_FLIP_LEFT; } } - else if ( pm->ps->clientNum && pm->cmd.forwardmove > 0 && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) + else if ( pm->ps->clientNum && !PM_ControlledByPlayer() && pm->cmd.forwardmove > 0 && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) {//run up wall, flip backwards if ( VectorLengthSquared( pm->ps->velocity ) > 40000 /*200*200*/) {//have to be moving... FIXME: make sure it's opposite the wall... or at least forward? @@ -857,8 +890,11 @@ static qboolean PM_CheckJump( void ) } else if ( pm->cmd.forwardmove < 0 && !(pm->cmd.buttons&BUTTON_ATTACK) )//pm->ps->clientNum && {//double-tap back-jump does backflip - vertPush = JUMP_VELOCITY; - anim = PM_PickAnim( pm->gent, BOTH_FLIP_BACK1, BOTH_FLIP_BACK3 ); + if ( pm->ps->velocity[2] >= 0 ) + {//must be going up already + vertPush = JUMP_VELOCITY; + anim = PM_PickAnim( pm->gent, BOTH_FLIP_BACK1, BOTH_FLIP_BACK3 ); + } } else if ( VectorLengthSquared( pm->ps->velocity ) < 256 /*16 squared*/) {//not moving @@ -879,7 +915,7 @@ static qboolean PM_CheckJump( void ) } } else - */if ( pm->ps->clientNum )//NOTE: pretty much useless, so player never does these + */if ( pm->ps->clientNum && !PM_ControlledByPlayer() )//NOTE: pretty much useless, so player never does these {//jump-spin FIXME: does direction matter? vertPush = forceJumpStrength[FORCE_LEVEL_2]/1.5f; anim = Q_irand( BOTH_FJSS_TR_BL, BOTH_FJSS_TL_BR ); @@ -1217,7 +1253,7 @@ static qboolean PM_CheckJump( void ) && pm->cmd.upmove > 0 && pm->ps->weapon == WP_SABER && (pm->ps->weaponTime > 0||pm->cmd.buttons&BUTTON_ATTACK) - && (pm->ps->clientNum||(cg.renderingThirdPerson && !cg.zoomMode)) ) + && ((pm->ps->clientNum&&!PM_ControlledByPlayer())||((!pm->ps->clientNum||PM_ControlledByPlayer()) && cg.renderingThirdPerson && !cg.zoomMode)) ) {//okay, we just jumped and we're in an attack if ( !PM_RollingAnim( pm->ps->legsAnim ) && !PM_InKnockDown( pm->ps ) @@ -1234,13 +1270,13 @@ static qboolean PM_CheckJump( void ) if ( animLength - pm->ps->torsoAnimTimer < 500 ) {//just started the saberMove //check for special-case jump attacks - if ( pm->ps->saberAnimLevel == FORCE_LEVEL_2 ) + if ( pm->ps->saberAnimLevel == FORCE_LEVEL_2 || pm->ps->saberAnimLevel == FORCE_LEVEL_5 )//using medium attacks or Tavion) {//using medium attacks if ( pm->gent->enemy && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 //can force jump && !(pm->gent->flags&FL_LOCK_PLAYER_WEAPONS) // yes this locked weapons check also includes force powers, if we need a separate check later I'll make one && (pm->ps->groundEntityNum != ENTITYNUM_NONE||level.time-pm->ps->lastOnGround<=500) )//on ground or just jumped {//flip over-forward down-attack - if ( !pm->ps->clientNum || + if ( ((!pm->ps->clientNum||PM_ControlledByPlayer())&&pm->cmd.forwardmove >= 0&&!pm->cmd.rightmove) || (pm->gent->NPC && (pm->gent->NPC->rank==RANK_CREWMAN||pm->gent->NPC->rank>=RANK_LT) ) ) {//only player or acrobat or boss and higher can do this vec3_t fwdAngles = {0,pm->ps->viewangles[YAW],0}; @@ -1260,10 +1296,13 @@ static qboolean PM_CheckJump( void ) if ( pm->cmd.forwardmove > 0 //going forward && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 //can force jump && !(pm->gent->flags&FL_LOCK_PLAYER_WEAPONS) // yes this locked weapons check also includes force powers, if we need a separate check later I'll make one - && (pm->ps->legsAnim == BOTH_STAND2||pm->ps->legsAnim == BOTH_SABERFAST_STANCE||pm->ps->legsAnim == BOTH_SABERSLOW_STANCE||level.time-pm->ps->lastStationary<=500)//standing or just started moving - && (pm->ps->groundEntityNum != ENTITYNUM_NONE||(pm->ps->clientNum&&level.time-pm->ps->lastOnGround<=500)))//on ground or just jumped if non-player + && ( pm->ps->legsAnim == BOTH_STAND2 + || pm->ps->legsAnim == BOTH_SABERFAST_STANCE + || pm->ps->legsAnim == BOTH_SABERSLOW_STANCE + || level.time-pm->ps->lastStationary <= 500 )//standing or just started moving + && (pm->ps->groundEntityNum != ENTITYNUM_NONE||(pm->ps->clientNum&&!PM_ControlledByPlayer()&&level.time-pm->ps->lastOnGround<=500)))//on ground or just jumped if non-player {//strong attack: jump-hack - if ( !pm->ps->clientNum || + if ( (!pm->ps->clientNum||PM_ControlledByPlayer()) || (pm->gent && pm->gent->NPC && (pm->gent->NPC->rank==RANK_CREWMAN||pm->gent->NPC->rank>=RANK_LT) ) ) {//only player or acrobat or boss and higher can do this PM_SetSaberMove( PM_SaberJumpAttackMove() ); @@ -1341,6 +1380,10 @@ static qboolean PM_CheckWaterJump( void ) { return qfalse; } + if ( pm->cmd.forwardmove <= 0 && pm->cmd.upmove <= 0 ) + {//they must not want to get out? + return qfalse; + } // check for water jump if ( pm->waterlevel != 2 ) { return qfalse; @@ -1357,7 +1400,7 @@ static qboolean PM_CheckWaterJump( void ) { VectorNormalize( flatforward ); VectorMA( pm->ps->origin, 30, flatforward, spot ); - spot[2] += 4; + spot[2] += 24; cont = pm->pointcontents (spot, pm->ps->clientNum ); if ( !(cont & CONTENTS_SOLID) ) { return qfalse; @@ -1371,7 +1414,7 @@ static qboolean PM_CheckWaterJump( void ) { // jump out of water VectorScale( pml.forward, 200, pm->ps->velocity ); - pm->ps->velocity[2] = 350; + pm->ps->velocity[2] = 350+((pm->ps->waterheight-pm->ps->origin[2])*2); pm->ps->pm_flags |= PMF_TIME_WATERJUMP; pm->ps->pm_time = 2000; @@ -1462,6 +1505,29 @@ static void PM_WaterMove( void ) { wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove; } wishvel[2] += scale * pm->cmd.upmove; + if ( !(pm->watertype&CONTENTS_LADDER) ) //ladder + { + float depth = (pm->ps->origin[2]+pm->gent->client->standheight)-pm->ps->waterheight; + if ( depth >= 12 ) + {//too high! + wishvel[2] -= 120; // sink towards bottom + if ( wishvel[2] > 0 ) + { + wishvel[2] = 0; + } + } + else if ( pm->ps->waterHeightLevel >= WHL_UNDER )//!depth && pm->waterlevel == 3 ) + { + } + else if ( depth < 12 ) + {//still deep + wishvel[2] -= 60; // sink towards bottom + if ( wishvel[2] > 30 ) + { + wishvel[2] = 30; + } + } + } } VectorCopy (wishvel, wishdir); @@ -1622,7 +1688,23 @@ static void PM_FlyMove( void ) PM_StepSlideMove( 1 ); } - +qboolean PM_GroundSlideOkay( float zNormal ) +{ + if ( zNormal > 0 ) + { + if ( pm->ps->velocity[2] > 0 ) + { + if ( pm->ps->legsAnim == BOTH_WALL_RUN_RIGHT + || pm->ps->legsAnim == BOTH_WALL_RUN_LEFT + || pm->ps->legsAnim == BOTH_WALL_RUN_RIGHT_STOP + || pm->ps->legsAnim == BOTH_WALL_RUN_LEFT_STOP ) + { + return qfalse; + } + } + } + return qtrue; +} /* =================== PM_AirMove @@ -1690,17 +1772,41 @@ static void PM_AirMove( void ) { } // not on ground, so little effect on velocity - PM_Accelerate (wishdir, wishspeed, pm_airaccelerate); + PM_Accelerate( wishdir, wishspeed, pm_airaccelerate ); //} // we may have a ground plane that is very steep, even // though we don't have a groundentity // slide along the steep plane - if ( pml.groundPlane ) { - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); + if ( pml.groundPlane ) + { + if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) ) + { + PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, + pm->ps->velocity, OVERCLIP ); + } } + if ( !pm->ps->clientNum + && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_0 + && pm->ps->forceJumpZStart + && pm->ps->velocity[2] > 0 ) + {//I am force jumping and I'm not holding the button anymore + float curHeight = pm->ps->origin[2] - pm->ps->forceJumpZStart + (pm->ps->velocity[2]*pml.frametime); + float maxJumpHeight = forceJumpHeight[pm->ps->forcePowerLevel[FP_LEVITATION]]; + if ( curHeight >= maxJumpHeight ) + {//reached top, cut velocity + pm->ps->velocity[2] = 0; + /* + //put on a cvar? + float stepCrouchAdd = STEPSIZE+(DEFAULT_MAXS_2-CROUCH_MAXS_2); + Com_Printf( S_COLOR_RED"capping force jump height %4.2f > %4.2f (%4.2f/%4.2f)\n", + curHeight, maxJumpHeight, + forceJumpHeight[pm->ps->forcePowerLevel[FP_LEVITATION]], + forceJumpHeight[pm->ps->forcePowerLevel[FP_LEVITATION]]+stepCrouchAdd ); + */ + } + } /* if ( g_timescale != NULL ) { @@ -1714,7 +1820,7 @@ static void PM_AirMove( void ) { } */ - PM_StepSlideMove ( gravMod ); + PM_StepSlideMove( gravMod ); } @@ -2085,7 +2191,7 @@ static void PM_CrashLandDamage( int damage ) damage = PM_DamageForDelta( damage ); } - if ( damage ) + if ( damage && !(pm->gent->flags&FL_NO_IMPACT_DMG) ) { pm->gent->painDebounceTime = level.time + 200; // no normal pain sound G_Damage( pm->gent, NULL, NULL, NULL, NULL, damage, DAMAGE_NO_ARMOR, MOD_FALLING ); @@ -2453,7 +2559,8 @@ static void PM_CrashLand( void ) return; } - if(!PM_InDeathAnim()) + qboolean deadFallSound = qfalse; + if( !PM_InDeathAnim() ) { if ( pm->cmd.upmove >= 0 && !PM_InKnockDown( pm->ps ) && !PM_InRoll( pm->ps )) {//not crouching @@ -2487,6 +2594,7 @@ static void PM_CrashLand( void ) { if ( pm->waterlevel < 2 ) {//don't play fallsplat when impact in the water + deadFallSound = qtrue; G_SoundOnEnt( pm->gent, CHAN_BODY, "sound/player/fallsplat.wav" ); } if ( gi.VoiceVolume[pm->ps->clientNum] @@ -2517,7 +2625,10 @@ static void PM_CrashLand( void ) if ( delta >= 75 ) { - PM_AddEvent( EV_FALL_FAR ); + if ( !deadFallSound ) + { + PM_AddEvent( EV_FALL_FAR ); + } if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) { PM_CrashLandDamage( delta ); @@ -2546,7 +2657,10 @@ static void PM_CrashLand( void ) // this is a pain grunt, so don't play it if dead if ( pm->ps->stats[STAT_HEALTH] > 0 ) { - PM_AddEvent( EV_FALL_MEDIUM );//damage is dealt in g_active, ClientEvents + if ( !deadFallSound ) + { + PM_AddEvent( EV_FALL_MEDIUM );//damage is dealt in g_active, ClientEvents + } if ( pm->gent ) { if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) @@ -2569,7 +2683,10 @@ static void PM_CrashLand( void ) } else if ( delta >= 30 ) { - PM_AddEvent( EV_FALL_SHORT ); + if ( !deadFallSound ) + { + PM_AddEvent( EV_FALL_SHORT ); + } if ( pm->gent ) { if ( pm->gent->s.number == 0 ) @@ -2594,13 +2711,16 @@ static void PM_CrashLand( void ) } else { - if ( forceLanding ) - {//we were force-jumping - PM_AddEvent( EV_FALL_SHORT ); - } - else + if ( !deadFallSound ) { - PM_AddEvent( PM_FootstepForSurface() ); + if ( forceLanding ) + {//we were force-jumping + PM_AddEvent( EV_FALL_SHORT ); + } + else + { + PM_AddEvent( PM_FootstepForSurface() ); + } } } @@ -2994,8 +3114,31 @@ static void PM_GroundTrace( void ) { pml.walking = qtrue; pm->ps->groundEntityNum = ENTITYNUM_WORLD; pm->ps->lastOnGround = level.time; + /* + pml.groundTrace.allsolid = qfalse; + pml.groundTrace.contents = CONTENTS_SOLID; + VectorCopy( pm->ps->origin, pml.groundTrace.endpos ); + pml.groundTrace.entityNum = ENTITYNUM_WORLD; + pml.groundTrace.fraction = 0.0f;; + pml.groundTrace.G2CollisionMap = NULL; + pml.groundTrace.plane.dist = 0.0f; + VectorSet( pml.groundTrace.plane.normal, 0, 0, 1 ); + pml.groundTrace.plane.pad = 0; + pml.groundTrace.plane.signbits = 0; + pml.groundTrace.plane.type = 0;; + pml.groundTrace.startsolid = qfalse; + pml.groundTrace.surfaceFlags = 0; + */ return; } + else if ( pm->ps->legsAnimTimer > 300 && (pm->ps->legsAnim == BOTH_WALL_RUN_RIGHT || pm->ps->legsAnim == BOTH_WALL_RUN_LEFT) ) + {//wall-running forces you to be in the air + pml.groundPlane = qfalse; + pml.walking = qfalse; + pm->ps->groundEntityNum = ENTITYNUM_NONE; + return; + } + point[0] = pm->ps->origin[0]; point[1] = pm->ps->origin[1]; @@ -3152,9 +3295,81 @@ static void PM_SetWaterLevelAtPoint( vec3_t org, int *waterlevel, int *watertype } } } - } +void PM_SetWaterHeight( void ) +{ + pm->ps->waterHeightLevel = WHL_NONE; + if ( pm->waterlevel < 1 ) + { + pm->ps->waterheight = pm->ps->origin[2] + DEFAULT_MINS_2 - 4; + return; + } + trace_t trace; + vec3_t top, bottom; + + VectorCopy( pm->ps->origin, top ); + VectorCopy( pm->ps->origin, bottom ); + top[2] += pm->gent->client->standheight; + bottom[2] += DEFAULT_MINS_2; + + gi.trace( &trace, top, pm->mins, pm->maxs, bottom, pm->ps->clientNum, (CONTENTS_WATER|CONTENTS_SLIME) ); + + if ( trace.startsolid ) + {//under water + pm->ps->waterheight = top[2] + 4; + } + else if ( trace.fraction < 1.0f ) + {//partially in and partially out of water + pm->ps->waterheight = trace.endpos[2]+pm->mins[2]; + } + else if ( trace.contents&(CONTENTS_WATER|CONTENTS_SLIME) ) + {//water is above me + pm->ps->waterheight = top[2] + 4; + } + else + {//water is below me + pm->ps->waterheight = bottom[2] - 4; + } + float distFromEyes = (pm->ps->origin[2]+pm->gent->client->standheight)-pm->ps->waterheight; + + if ( distFromEyes < 0 ) + { + pm->ps->waterHeightLevel = WHL_UNDER; + } + else if ( distFromEyes < 6 ) + { + pm->ps->waterHeightLevel = WHL_HEAD; + } + else if ( distFromEyes < 18 ) + { + pm->ps->waterHeightLevel = WHL_SHOULDERS; + } + else if ( distFromEyes < pm->gent->client->standheight-8 ) + {//at least 8 above origin + pm->ps->waterHeightLevel = WHL_TORSO; + } + else + { + float distFromOrg = pm->ps->origin[2]-pm->ps->waterheight; + if ( distFromOrg < 6 ) + { + pm->ps->waterHeightLevel = WHL_WAIST; + } + else if ( distFromOrg < 16 ) + { + pm->ps->waterHeightLevel = WHL_KNEES; + } + else if ( distFromOrg > fabs(pm->mins[2]) ) + { + pm->ps->waterHeightLevel = WHL_NONE; + } + else + { + pm->ps->waterHeightLevel = WHL_ANKLES; + } + } +} /* @@ -3276,6 +3491,10 @@ static void PM_CheckDuck (void) } if ( PM_InKnockDown( pm->ps ) ) {//forced crouch + if ( pm->gent && pm->gent->client ) + {//interrupted any potential delayed weapon fires + pm->gent->client->fireDelay = 0; + } pm->maxs[2] = crouchheight; pm->ps->viewheight = crouchheight + STANDARD_VIEWHEIGHT_OFFSET; pm->ps->pm_flags |= PMF_DUCKED; @@ -3285,7 +3504,7 @@ static void PM_CheckDuck (void) { // trying to duck pm->maxs[2] = crouchheight; pm->ps->viewheight = crouchheight + STANDARD_VIEWHEIGHT_OFFSET;//CROUCH_VIEWHEIGHT; - if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) + if ( pm->ps->groundEntityNum == ENTITYNUM_NONE && !PM_SwimmingAnim( pm->ps->legsAnim ) ) {//Not ducked already and trying to duck in mid-air //will raise your feet, unducking whilst in air will drop feet if ( !(pm->ps->pm_flags&PMF_DUCKED) ) @@ -3479,7 +3698,7 @@ qboolean PM_InKnockDownOnGround( playerState_t *ps ) case BOTH_KNOCKDOWN3: case BOTH_KNOCKDOWN4: case BOTH_KNOCKDOWN5: - if ( ps->legsAnimTimer < 500 ) + //if ( PM_AnimLength( g_entities[ps->clientNum].client->clientInfo.animFileIndex, (animNumber_t)ps->legsAnim ) - ps->legsAnimTimer > 300 ) {//at end of fall down anim return qtrue; } @@ -3499,7 +3718,7 @@ qboolean PM_InKnockDownOnGround( playerState_t *ps ) case BOTH_FORCE_GETUP_B4: case BOTH_FORCE_GETUP_B5: case BOTH_FORCE_GETUP_B6: - if ( PM_AnimLength( g_entities[pm->ps->clientNum].client->clientInfo.animFileIndex, (animNumber_t)pm->ps->legsAnim ) - ps->legsAnimTimer < 500 ) + if ( PM_AnimLength( g_entities[ps->clientNum].client->clientInfo.animFileIndex, (animNumber_t)ps->legsAnim ) - ps->legsAnimTimer < 500 ) {//at beginning of getup anim return qtrue; } @@ -3626,6 +3845,7 @@ qboolean PM_GettingUpFromKnockDown( float standheight, float crouchheight ) } break; } + //Com_Printf( "getupanim = %s\n", animTable[anim].name ); if ( forceGetUp ) { if ( pm->gent && pm->gent->client && pm->gent->client->playerTeam == TEAM_ENEMY @@ -3928,14 +4148,9 @@ qboolean PM_SwimmingAnim( int anim ) { switch ( anim ) { - case BOTH_SWIM1: //# Swimming - case BOTH_SWIM_IDLE1: //# Swimming Idle 1 - case BOTH_SWIMFORWARDSTART: //# Swim forward start - case BOTH_SWIMFORWARD: //# Swim forward loop - case BOTH_SWIMFORWARDSTOP: //# Swim forward end - case BOTH_SWIMBACKWARDSTART: //# Swim backward start - case BOTH_SWIMBACKWARD: //# Swim backward loop - case BOTH_SWIMBACKWARDSTOP: //# Swim backward end + case BOTH_SWIM1: //# Swimming + case BOTH_SWIM_IDLE1: //# Swimming Idle 1 + case BOTH_SWIMFORWARD: //# Swim forward loop return qtrue; break; } @@ -4112,21 +4327,40 @@ void PM_FootSlopeTrace( float *pDiff, float *pInterval ) #else //FIXME: these really should have been gotten on the cgame, but I guess sometimes they're not and we end up with qnan numbers! + mdxaBone_t boltMatrix; + vec3_t G2Angles = {0, pm->gent->client->ps.legsYaw, 0}; + //get the feet + gi.G2API_GetBoltMatrix( pm->gent->ghoul2, pm->gent->playerModel, pm->gent->footLBolt, + &boltMatrix, G2Angles, pm->ps->origin, (cg.time?cg.time:level.time), + NULL, pm->gent->s.modelScale ); + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, pm->gent->client->renderInfo.footLPoint ); + + gi.G2API_GetBoltMatrix( pm->gent->ghoul2, pm->gent->playerModel, pm->gent->footRBolt, + &boltMatrix, G2Angles, pm->ps->origin, (cg.time?cg.time:level.time), + NULL, pm->gent->s.modelScale ); + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, pm->gent->client->renderInfo.footRPoint ); +#endif + //NOTE: on AT-STs, rotating the foot moves this point, so it will wiggle... + // we have to do this extra work (more G2 transforms) to stop the wiggle... is it worth it? + /* + if ( pm->gent->client->NPC_class == CLASS_ATST ) { mdxaBone_t boltMatrix; vec3_t G2Angles = {0, pm->gent->client->ps.legsYaw, 0}; //get the feet + gi.G2API_SetBoneAnglesIndex( &pm->gent->ghoul2[0], pm->gent->footLBone, vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, NEGATIVE_X, NULL ); gi.G2API_GetBoltMatrix( pm->gent->ghoul2, pm->gent->playerModel, pm->gent->footLBolt, &boltMatrix, G2Angles, pm->ps->origin, (cg.time?cg.time:level.time), NULL, pm->gent->s.modelScale ); gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, pm->gent->client->renderInfo.footLPoint ); + gi.G2API_SetBoneAnglesIndex( &pm->gent->ghoul2[0], pm->gent->footRBone, vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, NEGATIVE_X, NULL ); gi.G2API_GetBoltMatrix( pm->gent->ghoul2, pm->gent->playerModel, pm->gent->footRBolt, &boltMatrix, G2Angles, pm->ps->origin, (cg.time?cg.time:level.time), NULL, pm->gent->s.modelScale ); gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, pm->gent->client->renderInfo.footRPoint ); } -#endif + */ //get these on the cgame and store it, save ourselves a ghoul2 construct skel call VectorCopy( pm->gent->client->renderInfo.footLPoint, footLOrg ); VectorCopy( pm->gent->client->renderInfo.footRPoint, footROrg ); @@ -4142,13 +4376,13 @@ void PM_FootSlopeTrace( float *pDiff, float *pInterval ) vec3_t footLSlope, footRSlope; if ( pm->gent->client->NPC_class == CLASS_ATST ) { - VectorSet( footMins, -8, -8, 0 ); - VectorSet( footMaxs, -8, -8, 1 ); + VectorSet( footMins, -16, -16, 0 ); + VectorSet( footMaxs, 16, 16, 1 ); } else { - VectorSet( footMins, 0, 0, 0 ); - VectorSet( footMaxs, 0, 0, 0 ); + VectorSet( footMins, -3, -3, 0 ); + VectorSet( footMaxs, 3, 3, 1 ); } pm->trace( &trace, footLOrg, footMins, footMaxs, footLBot, pm->ps->clientNum, pm->tracemask ); @@ -4345,6 +4579,7 @@ qboolean PM_AdjustStandAnimForSlope( void ) case BOTH_SABERFAST_STANCE: case BOTH_SABERSLOW_STANCE: case BOTH_CROUCH1IDLE: + case BOTH_CROUCH1: case LEGS_LEFTUP1: //# On a slope with left foot 4 higher than right case LEGS_LEFTUP2: //# On a slope with left foot 8 higher than right case LEGS_LEFTUP3: //# On a slope with left foot 12 higher than right @@ -4450,7 +4685,7 @@ qboolean PM_AdjustStandAnimForSlope( void ) {//in a stand of some sort? if ( pm->gent->client->NPC_class == CLASS_ATST ) { - if ( legsAnim == BOTH_STAND2 || legsAnim == BOTH_CROUCH1IDLE ) + if ( legsAnim == BOTH_STAND1 || legsAnim == BOTH_STAND2 || legsAnim == BOTH_CROUCH1IDLE ) { if ( destAnim >= LEGS_LEFTUP1 && destAnim <= LEGS_LEFTUP5 ) {//going into left side up @@ -4571,41 +4806,20 @@ qboolean PM_AdjustStandAnimForSlope( void ) void PM_SwimFloatAnim( void ) { int legsAnim = pm->ps->legsAnim; - if ( pm->cmd.forwardmove > 0 ) + //FIXME: no start or stop anims + if ( pm->cmd.forwardmove || pm->cmd.rightmove || pm->cmd.upmove ) { - if ( legsAnim == BOTH_SWIMFORWARDSTART && !pm->ps->legsAnimTimer ) - { - PM_SetAnim(pm,SETANIM_LEGS,BOTH_SWIMFORWARD,SETANIM_FLAG_NORMAL|SETANIM_FLAG_HOLD); - } - else if ( legsAnim == BOTH_SWIMFORWARD ) - { - PM_SetAnim(pm,SETANIM_LEGS,BOTH_SWIMFORWARD,SETANIM_FLAG_NORMAL); - } - else - { - PM_SetAnim(pm,SETANIM_LEGS,BOTH_SWIMFORWARDSTART,SETANIM_FLAG_NORMAL|SETANIM_FLAG_HOLD); - } + PM_SetAnim(pm,SETANIM_LEGS,BOTH_SWIMFORWARD,SETANIM_FLAG_NORMAL); } else - {//moving backward or stopping + {//stopping if ( legsAnim == BOTH_SWIMFORWARD ) - {//I was swimming forward, not stop - PM_SetAnim(pm,SETANIM_LEGS,BOTH_SWIMFORWARDSTOP,SETANIM_FLAG_NORMAL|SETANIM_FLAG_HOLD); - } - else if ( legsAnim == BOTH_SWIMFORWARDSTOP ) - {//was stopping, go to idle + {//I was swimming if ( !pm->ps->legsAnimTimer ) { PM_SetAnim(pm,SETANIM_LEGS,BOTH_SWIM_IDLE1,SETANIM_FLAG_NORMAL); } } - else if ( legsAnim == BOTH_SWIMFORWARDSTART ) - {//was starting, stop - if ( !pm->ps->legsAnimTimer ) - { - PM_SetAnim(pm,SETANIM_LEGS,BOTH_SWIMFORWARDSTOP,SETANIM_FLAG_NORMAL|SETANIM_FLAG_HOLD); - } - } else {//idle if ( !(pm->ps->pm_flags&PMF_DUCKED) && pm->cmd.upmove >= 0 ) @@ -4665,8 +4879,10 @@ static void PM_Footsteps( void ) flipping = qtrue; } - if ( pm->ps->groundEntityNum == ENTITYNUM_NONE || pm->waterlevel > 1 ) - {//in air or totally submerged in water + if ( pm->ps->groundEntityNum == ENTITYNUM_NONE + || ( pm->watertype & CONTENTS_LADDER ) + || pm->ps->waterHeightLevel >= WHL_TORSO ) + {//in air or submerged in water or in ladder // airborne leaves position in cycle intact, but doesn't advance if ( pm->waterlevel > 0 ) { @@ -4708,32 +4924,68 @@ static void PM_Footsteps( void ) } return; } - else if ( pm->waterlevel > 1 ) //in deep water + else if ( pm->ps->waterHeightLevel >= WHL_TORSO + && (!pm->ps->clientNum||pm->ps->weapon==WP_SABER||pm->ps->weapon==WP_NONE||pm->ps->weapon==WP_MELEE) )//pm->waterlevel > 1 ) //in deep water { - if ( (pm->cmd.forwardmove<=0||pm->ps->groundEntityNum == ENTITYNUM_NONE) - && (!PM_SwimmingAnim( pm->ps->legsAnim ) || pm->ps->legsAnim == BOTH_SWIM_IDLE1) - && pm->ps->pm_flags & PMF_DUCKED ) - {//not moving or on ground, in swim idle and ducking - if ( !flipping ) - {//not flipping - if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN - || pm->cmd.forwardmove < 0 ) - { - PM_SetAnim(pm,SETANIM_LEGS,BOTH_CROUCH1WALKBACK,setAnimFlags); + if ( !PM_ForceJumpingUp( pm->gent ) ) + { + if ( pm->ps->groundEntityNum != ENTITYNUM_NONE && (pm->ps->pm_flags&PMF_DUCKED) ) + { + if ( !flipping ) + {//you can crouch under water if feet are on ground + if ( pm->cmd.forwardmove || pm->cmd.rightmove ) + { + if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) + { + PM_SetAnim(pm,SETANIM_LEGS,BOTH_CROUCH1WALKBACK,setAnimFlags); + } + else + { + PM_SetAnim(pm,SETANIM_LEGS,BOTH_CROUCH1WALK,setAnimFlags); + } + } + else + { + PM_SetAnim(pm,SETANIM_LEGS,BOTH_CROUCH1,SETANIM_FLAG_NORMAL); + } + return; } - else if ( pm->cmd.rightmove ) + } + PM_SwimFloatAnim(); + if ( pm->ps->legsAnim != BOTH_SWIM_IDLE1 ) + {//moving + old = pm->ps->bobCycle; + bobmove = 0.15f; // swim is a slow cycle + pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255; + + // if we just crossed a cycle boundary, play an apropriate footstep event + if ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) { - PM_SetAnim(pm,SETANIM_LEGS,BOTH_CROUCH1WALK,setAnimFlags); + PM_AddEvent( EV_SWIM ); } - else + } + } + return; + } + else + {//hmm, in water, but not high enough to swim + //fall through to walk/run/stand + if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) + {//unless in the air + //NOTE: this is a dupe of the code just below... for when you are not in the water at all + if ( pm->ps->pm_flags & PMF_DUCKED ) + { + if ( !flipping ) { PM_SetAnim(pm,SETANIM_LEGS,BOTH_CROUCH1,SETANIM_FLAG_NORMAL); } } + else if ( pm->ps->gravity <= 0 )//FIXME: or just less than normal? + { + PM_SwimFloatAnim(); + } return; } - PM_SwimFloatAnim(); - return; } } else @@ -4761,7 +5013,14 @@ static void PM_Footsteps( void ) // if not trying to move if ( !pm->cmd.forwardmove && !pm->cmd.rightmove ) { - if ( pm->ps->pm_flags & PMF_DUCKED ) + if ( pm->gent && pm->gent->client && pm->gent->client->NPC_class == CLASS_ATST ) + { + if ( !PM_AdjustStandAnimForSlope() ) + { + PM_SetAnim(pm,SETANIM_LEGS,BOTH_STAND1,SETANIM_FLAG_NORMAL); + } + } + else if ( pm->ps->pm_flags & PMF_DUCKED ) { if( !PM_InOnGroundAnim( pm->ps ) ) { @@ -4886,7 +5145,7 @@ static void PM_Footsteps( void ) setAnimFlags |= SETANIM_FLAG_OVERRIDE; } - if ( (pm->ps->eFlags&EF_IN_ATST) ) + if ( (pm->ps->eFlags&EF_IN_ATST) )//does this catch NPCs, too? {//atst if ( pm->ps->legsAnim == BOTH_TURN_LEFT1 || pm->ps->legsAnim == BOTH_TURN_RIGHT1 ) @@ -5035,7 +5294,7 @@ DoFootSteps: { // if ( pm->gent->client && pm->gent->client->playerTeam != TEAM_DISGUISE ) { - AddSoundEvent( pm->gent, pm->ps->origin, 128, AEL_MINOR ); + AddSoundEvent( pm->gent, pm->ps->origin, 128, AEL_MINOR, qtrue ); } } } @@ -5054,7 +5313,7 @@ DoFootSteps: bottom[2] += pm->mins[2]; // if ( pm->gent->client && pm->gent->client->playerTeam != TEAM_DISGUISE ) { - AddSoundEvent( pm->gent, bottom, 256, AEL_MINOR ); + AddSoundEvent( pm->gent, bottom, 256, AEL_MINOR, qtrue ); } } } @@ -5062,7 +5321,14 @@ DoFootSteps: else if ( pm->waterlevel == 1 ) { // splashing - PM_AddEvent( EV_FOOTSPLASH ); + if ( pm->ps->waterHeightLevel >= WHL_KNEES ) + { + PM_AddEvent( EV_FOOTWADE ); + } + else + { + PM_AddEvent( EV_FOOTSPLASH ); + } if ( pm->gent && pm->gent->s.number == 0 ) { vec3_t bottom; @@ -5079,7 +5345,16 @@ DoFootSteps: else if ( pm->waterlevel == 2 ) { // wading / swimming at surface - PM_AddEvent( EV_SWIM ); + /* + if ( pm->ps->waterHeightLevel >= WHL_TORSO ) + { + PM_AddEvent( EV_SWIM ); + } + else + */ + { + PM_AddEvent( EV_FOOTWADE ); + } if ( pm->gent && pm->gent->s.number == 0 ) { // if ( pm->gent->client && pm->gent->client->playerTeam != TEAM_DISGUISE ) @@ -5088,7 +5363,11 @@ DoFootSteps: AddSightEvent( pm->gent, pm->ps->origin, 512, AEL_SUSPICIOUS ); } } - } // no sound when completely underwater + } + else + {// or no sound when completely underwater...? + PM_AddEvent( EV_SWIM ); + } } } @@ -5249,10 +5528,13 @@ static void PM_BeginWeaponChange( int weapon ) { // turn of any kind of zooming when weapon switching....except the LA Goggles - if ( cg.zoomMode > 0 && cg.zoomMode < 3 ) + if ( pm->ps->clientNum == 0 ) { - cg.zoomMode = 0; - cg.zoomTime = cg.time; + if ( cg.zoomMode > 0 && cg.zoomMode < 3 ) + { + cg.zoomMode = 0; + cg.zoomTime = cg.time; + } } if ( pm->gent && pm->gent->client && pm->gent->client->NPC_class == CLASS_ATST ) @@ -5329,7 +5611,7 @@ static void PM_FinishWeaponChange( void ) { // back to my hand, I have 2 weaponModels active...? if ( pm->gent ) {// remove gun if we had it. - if ( pm->gent->weaponModel != -1 ) + if ( pm->gent->weaponModel >= 0 ) { gi.G2API_RemoveGhoul2Model(pm->gent->ghoul2, pm->gent->weaponModel); } @@ -5372,7 +5654,7 @@ static void PM_FinishWeaponChange( void ) { if ( pm->gent ) { // remove the sabre if we had it. - if ( pm->gent->weaponModel != -1 ) + if ( pm->gent->weaponModel >= 0 ) { gi.G2API_RemoveGhoul2Model(pm->gent->ghoul2, pm->gent->weaponModel); pm->gent->weaponModel = -1; @@ -5397,7 +5679,7 @@ static void PM_FinishWeaponChange( void ) { { PM_SetAnim(pm,SETANIM_TORSO,TORSO_RAISEWEAP1,SETANIM_FLAG_HOLD); } - if ( !pm->ps->clientNum && cg_gunAutoFirst.value && oldWeap == WP_SABER ) + if ( !pm->ps->clientNum && cg_gunAutoFirst.value && oldWeap == WP_SABER && weapon != WP_NONE ) { gi.cvar_set( "cg_thirdperson", "0" ); } @@ -5553,7 +5835,7 @@ void PM_SetSaberMove(short newMove) pm->ps->saberMove = newMove; pm->ps->saberBlocking = saberMoveData[newMove].blocking; - if ( pm->ps->clientNum == 0 ) + if ( pm->ps->clientNum == 0 || PM_ControlledByPlayer() ) { if ( pm->ps->saberBlocked >= BLOCKED_UPPER_RIGHT_PROJ && pm->ps->saberBlocked <= BLOCKED_TOP_PROJ && newMove >= LS_REFLECT_UP && newMove <= LS_REFLECT_LL ) @@ -5592,13 +5874,13 @@ PM_Use Generates a use event ============== */ -#define USE_DELAY 2000 +#define USE_DELAY 250 void PM_Use( void ) { if ( pm->ps->useTime > 0 ) { - pm->ps->useTime -= 100;//pm->cmd.msec; + pm->ps->useTime -= pml.msec; if ( pm->ps->useTime < 0 ) { pm->ps->useTime = 0; @@ -5620,122 +5902,134 @@ void PM_Use( void ) pm->ps->useTime = USE_DELAY; } +extern int PM_AttackForEnemyPos( qboolean allowFB ); int PM_NPCSaberAttackFromQuad( int quad ) { //FIXME: this should be an AI decision // It should be based on the enemy's current LS_ move, saberAnimLevel, // the jedi's difficulty level, rank and FP_OFFENSE skill... - - int newmove = LS_NONE; - switch( quad ) + int autoMove = LS_NONE; + if ( pm->gent && ((pm->gent->NPC && pm->gent->NPC->rank != RANK_ENSIGN && pm->gent->NPC->rank != RANK_CIVILIAN ) || (pm->gent->client && pm->gent->client->NPC_class == CLASS_TAVION)) ) { - case Q_T://blocked top - if ( Q_irand( 0, 1 ) ) - { - newmove = LS_A_T2B; - } - else - { - newmove = LS_A_TR2BL; - } - break; - case Q_TR: - if ( !Q_irand( 0, 2 ) ) - { - newmove = LS_A_R2L; - } - else if ( !Q_irand( 0, 1 ) ) - { - newmove = LS_A_TR2BL; - } - else - { - newmove = LS_T1_TR_BR; - } - break; - case Q_TL: - if ( !Q_irand( 0, 2 ) ) - { - newmove = LS_A_L2R; - } - else if ( !Q_irand( 0, 1 ) ) - { - newmove = LS_A_TL2BR; - } - else - { - newmove = LS_T1_TL_BL; - } - break; - case Q_BR: - if ( !Q_irand( 0, 2 ) ) - { - newmove = LS_A_BR2TL; - } - else if ( !Q_irand( 0, 1 ) ) - { - newmove = LS_T1_BR_TR; - } - else - { - newmove = LS_A_R2L; - } - break; - case Q_BL: - if ( !Q_irand( 0, 2 ) ) - { - newmove = LS_A_BL2TR; - } - else if ( !Q_irand( 0, 1 ) ) - { - newmove = LS_T1_BL_TL; - } - else - { - newmove = LS_A_L2R; - } - break; - case Q_L: - if ( !Q_irand( 0, 2 ) ) - { - newmove = LS_A_L2R; - } - else if ( !Q_irand( 0, 1 ) ) - { - newmove = LS_T1__L_T_; - } - else - { - newmove = LS_A_R2L; - } - break; - case Q_R: - if ( !Q_irand( 0, 2 ) ) - { - newmove = LS_A_R2L; - } - else if ( !Q_irand( 0, 1 ) ) - { - newmove = LS_T1__R_T_; - } - else - { - newmove = LS_A_L2R; - } - break; - case Q_B: - if ( ( pm->gent && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG ) ) - {//fencers and above can do bottom-up attack - if ( Q_irand( 0, pm->gent->NPC->rank ) >= RANK_LT_JG ) - {//but not overly likely - newmove = LS_A_LUNGE; - } - } - break; - default: - break; + autoMove = PM_AttackForEnemyPos( qtrue ); + } + if ( autoMove != LS_NONE && PM_SaberInSpecial( autoMove ) ) + {//if have opportunity to do a special attack, do one + return autoMove; + } + else + {//pick another one + int newmove = LS_NONE; + switch( quad ) + { + case Q_T://blocked top + if ( Q_irand( 0, 1 ) ) + { + newmove = LS_A_T2B; + } + else + { + newmove = LS_A_TR2BL; + } + break; + case Q_TR: + if ( !Q_irand( 0, 2 ) ) + { + newmove = LS_A_R2L; + } + else if ( !Q_irand( 0, 1 ) ) + { + newmove = LS_A_TR2BL; + } + else + { + newmove = LS_T1_TR_BR; + } + break; + case Q_TL: + if ( !Q_irand( 0, 2 ) ) + { + newmove = LS_A_L2R; + } + else if ( !Q_irand( 0, 1 ) ) + { + newmove = LS_A_TL2BR; + } + else + { + newmove = LS_T1_TL_BL; + } + break; + case Q_BR: + if ( !Q_irand( 0, 2 ) ) + { + newmove = LS_A_BR2TL; + } + else if ( !Q_irand( 0, 1 ) ) + { + newmove = LS_T1_BR_TR; + } + else + { + newmove = LS_A_R2L; + } + break; + case Q_BL: + if ( !Q_irand( 0, 2 ) ) + { + newmove = LS_A_BL2TR; + } + else if ( !Q_irand( 0, 1 ) ) + { + newmove = LS_T1_BL_TL; + } + else + { + newmove = LS_A_L2R; + } + break; + case Q_L: + if ( !Q_irand( 0, 2 ) ) + { + newmove = LS_A_L2R; + } + else if ( !Q_irand( 0, 1 ) ) + { + newmove = LS_T1__L_T_; + } + else + { + newmove = LS_A_R2L; + } + break; + case Q_R: + if ( !Q_irand( 0, 2 ) ) + { + newmove = LS_A_R2L; + } + else if ( !Q_irand( 0, 1 ) ) + { + newmove = LS_T1__R_T_; + } + else + { + newmove = LS_A_L2R; + } + break; + case Q_B: + if ( ( pm->gent && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG ) ) + {//fencers and above can do bottom-up attack + if ( Q_irand( 0, pm->gent->NPC->rank ) >= RANK_LT_JG ) + {//but not overly likely + newmove = LS_A_LUNGE; + } + } + break; + default: + break; + } + return newmove; } - return newmove; } int PM_SaberMoveQuadrantForMovement( usercmd_t *ucmd ) @@ -5812,52 +6106,37 @@ void PM_SetAnimFrame( gentity_t *gent, int frame, qboolean torso, qboolean legs } } -void PM_SaberLockBreak( gentity_t *gent, gentity_t *genemy, saberLockResult_t result, int victoryStrength ) +int PM_SaberLockWinAnim( saberLockResult_t result ) { - int winAnim = -1, loseAnim = -1; - + int winAnim = -1; switch ( pm->ps->torsoAnim ) { +/* + default: +#ifndef FINAL_BUILD + Com_Printf( S_COLOR_RED"ERROR-PM_SaberLockBreak: %s not in saberlock anim, anim = (%d)%s\n", pm->gent->NPC_type, pm->ps->torsoAnim, animTable[pm->ps->torsoAnim].name ); +#endif +*/ case BOTH_BF2LOCK: if ( result == LOCK_DRAW ) { winAnim = BOTH_BF1BREAK; - loseAnim = BOTH_KNOCKDOWN4; } else { pm->ps->saberMove = LS_A_T2B; winAnim = BOTH_A3_T__B_; - if ( result == LOCK_STALEMATE ) - {//no-one won - genemy->client->ps.saberMove = LS_A_T2B; - loseAnim = winAnim; - } - else - { - loseAnim = BOTH_KNOCKDOWN4; - } } break; case BOTH_BF1LOCK: if ( result == LOCK_DRAW ) { winAnim = BOTH_KNOCKDOWN4; - loseAnim = BOTH_BF1BREAK; } else { pm->ps->saberMove = LS_K1_T_; winAnim = BOTH_K1_S1_T_; - if ( result == LOCK_STALEMATE ) - {//no-one won - genemy->client->ps.saberMove = LS_K1_T_; - loseAnim = winAnim; - } - else - {//FIXME: this anim needs to transition back to ready when done - loseAnim = BOTH_BF1BREAK; - } } break; case BOTH_CWCIRCLELOCK: @@ -5866,29 +6145,10 @@ void PM_SaberLockBreak( gentity_t *gent, gentity_t *genemy, saberLockResult_t re pm->ps->saberMove = pm->ps->saberBounceMove = LS_V1_BL; pm->ps->saberBlocked = BLOCKED_PARRY_BROKEN; winAnim = BOTH_V1_BL_S1; - // - genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_V1_BR; - genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; - loseAnim = BOTH_V1_BR_S1; } else { winAnim = BOTH_CWCIRCLEBREAK; - if ( result == LOCK_STALEMATE ) - {//no-one won - loseAnim = winAnim; - } - else - { - genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_V1_BR; - genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; - loseAnim = BOTH_V1_BR_S1; - /* - genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_H1_BL; - genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; - loseAnim = BOTH_H1_S1_BR; - */ - } } break; case BOTH_CCWCIRCLELOCK: @@ -5897,17 +6157,80 @@ void PM_SaberLockBreak( gentity_t *gent, gentity_t *genemy, saberLockResult_t re pm->ps->saberMove = pm->ps->saberBounceMove = LS_V1_BR; pm->ps->saberBlocked = BLOCKED_PARRY_BROKEN; winAnim = BOTH_V1_BR_S1; - // + } + else + { + winAnim = BOTH_CCWCIRCLEBREAK; + } + break; + } + if ( winAnim != -1 ) + { + PM_SetAnim( pm, SETANIM_BOTH, winAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + pm->ps->weaponTime = pm->ps->torsoAnimTimer; + } + return winAnim; +} + +int PM_SaberLockLoseAnim( gentity_t *genemy, saberLockResult_t result ) +{ + int loseAnim = -1; + switch ( genemy->client->ps.torsoAnim ) + { +/* + default: +#ifndef FINAL_BUILD + Com_Printf( S_COLOR_RED"ERROR-PM_SaberLockBreak: %s not in saberlock anim, anim = (%d)%s\n", genemy->NPC_type, genemy->client->ps.torsoAnim, animTable[genemy->client->ps.torsoAnim].name ); +#endif +*/ + case BOTH_BF2LOCK: + if ( result == LOCK_DRAW ) + { + loseAnim = BOTH_BF1BREAK; + } + else + { + if ( result == LOCK_STALEMATE ) + {//no-one won + genemy->client->ps.saberMove = LS_K1_T_; + loseAnim = BOTH_K1_S1_T_; + } + else + {//FIXME: this anim needs to transition back to ready when done + loseAnim = BOTH_BF1BREAK; + } + } + break; + case BOTH_BF1LOCK: + if ( result == LOCK_DRAW ) + { + loseAnim = BOTH_KNOCKDOWN4; + } + else + { + if ( result == LOCK_STALEMATE ) + {//no-one won + genemy->client->ps.saberMove = LS_A_T2B; + loseAnim = BOTH_A3_T__B_; + } + else + { + loseAnim = BOTH_KNOCKDOWN4; + } + } + break; + case BOTH_CWCIRCLELOCK: + if ( result == LOCK_DRAW ) + { genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_V1_BL; genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; loseAnim = BOTH_V1_BL_S1; } else { - winAnim = BOTH_CCWCIRCLEBREAK; if ( result == LOCK_STALEMATE ) {//no-one won - loseAnim = winAnim; + loseAnim = BOTH_CCWCIRCLEBREAK; } else { @@ -5922,16 +6245,56 @@ void PM_SaberLockBreak( gentity_t *gent, gentity_t *genemy, saberLockResult_t re } } break; + case BOTH_CCWCIRCLELOCK: + if ( result == LOCK_DRAW ) + { + genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_V1_BR; + genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; + loseAnim = BOTH_V1_BR_S1; + } + else + { + if ( result == LOCK_STALEMATE ) + {//no-one won + loseAnim = BOTH_CWCIRCLEBREAK; + } + else + { + genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_V1_BR; + genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; + loseAnim = BOTH_V1_BR_S1; + /* + genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_H1_BL; + genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; + loseAnim = BOTH_H1_S1_BR; + */ + } + } + break; } + if ( loseAnim != -1 ) + { + NPC_SetAnim( genemy, SETANIM_BOTH, loseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + genemy->client->ps.weaponTime = genemy->client->ps.torsoAnimTimer;// + 250; + } + return loseAnim; +} + +void PM_SaberLockBreak( gentity_t *gent, gentity_t *genemy, saberLockResult_t result, int victoryStrength ) +{ + int winAnim = -1, loseAnim = -1; + + winAnim = PM_SaberLockWinAnim( result ); + if ( genemy && genemy->client ) + { + loseAnim = PM_SaberLockLoseAnim( genemy, result ); + } + if ( d_saberCombat->integer ) { Com_Printf( "%s won saber lock, anim = %s!\n", gent->NPC_type, animTable[winAnim].name ); Com_Printf( "%s lost saber lock, anim = %s!\n", genemy->NPC_type, animTable[loseAnim].name ); } - PM_SetAnim( pm, SETANIM_BOTH, winAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - NPC_SetAnim( genemy, SETANIM_BOTH, loseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - pm->ps->weaponTime = pm->ps->torsoAnimTimer; - genemy->client->ps.weaponTime = genemy->client->ps.torsoAnimTimer;// + 250; pm->ps->saberLockTime = genemy->client->ps.saberLockTime = 0; pm->ps->saberLockEnemy = genemy->client->ps.saberLockEnemy = ENTITYNUM_NONE; @@ -6040,6 +6403,13 @@ qboolean PM_SaberLocked( void ) { if ( pm->ps->saberLockEnemy == ENTITYNUM_NONE ) { + if ( pm->ps->torsoAnim == BOTH_BF2LOCK || + pm->ps->torsoAnim == BOTH_BF1LOCK || + pm->ps->torsoAnim == BOTH_CWCIRCLELOCK || + pm->ps->torsoAnim == BOTH_CCWCIRCLELOCK ) + {//wtf? Maybe enemy died? + PM_SaberLockWinAnim( LOCK_STALEMATE ); + } return qfalse; } gentity_t *gent = pm->gent; @@ -6283,7 +6653,7 @@ qboolean PM_SaberLocked( void ) { PM_SaberLockBreak( genemy, gent, LOCK_VICTORY, 0 ); } - if ( genemy->painDebounceTime > level.time ) + else if ( genemy->painDebounceTime > level.time ) { PM_SaberLockBreak( gent, genemy, LOCK_VICTORY, 0 ); } @@ -6367,6 +6737,11 @@ void PM_WeaponLightsaber(void) return; } + if ( pm->ps->saberEventFlags&SEF_INWATER )//saber in water + { + pm->cmd.buttons &= ~(BUTTON_ATTACK|BUTTON_ALT_ATTACK); + } + qboolean saberInAir = qtrue; if ( !PM_SaberInBrokenParry( pm->ps->saberMove ) && pm->ps->saberBlocked != BLOCKED_PARRY_BROKEN && !PM_DodgeAnim( pm->ps->torsoAnim ) ) {//we're not stuck in a broken parry @@ -6400,10 +6775,10 @@ void PM_WeaponLightsaber(void) } } - if(pm->gent && pm->gent->client && pm->gent->client->fireDelay > 0) + if ( pm->gent && pm->gent->client && pm->gent->client->fireDelay > 0 ) {//FIXME: this is going to fire off one frame before you expect, actually pm->gent->client->fireDelay -= pml.msec; - if(pm->gent->client->fireDelay <= 0) + if ( pm->gent->client->fireDelay <= 0 ) {//just finished delay timer pm->gent->client->fireDelay = 0; delayed_fire = qtrue; @@ -6434,7 +6809,7 @@ void PM_WeaponLightsaber(void) } } - if ( !pm->ps->clientNum ) + if ( !pm->ps->clientNum || PM_ControlledByPlayer() ) {//player if ( pm->ps->saberBlocked >= BLOCKED_UPPER_RIGHT_PROJ && pm->ps->saberBlocked <= BLOCKED_TOP_PROJ ) {//blocking a projectile @@ -6475,7 +6850,7 @@ void PM_WeaponLightsaber(void) if ( pm->ps->saberBlocked != BLOCKED_ATK_BOUNCE ) {//can't attack for twice whatever your skill level's parry debounce time is - if ( pm->ps->clientNum == 0 ) + if ( pm->ps->clientNum == 0 || PM_ControlledByPlayer() ) {//player if ( pm->ps->forcePowerLevel[FP_SABER_DEFENSE] <= FORCE_LEVEL_1 ) { @@ -6533,7 +6908,7 @@ void PM_WeaponLightsaber(void) if ( pm->cmd.buttons & BUTTON_ATTACK ) {//transition to a new attack - if ( pm->ps->clientNum ) + if ( pm->ps->clientNum && !PM_ControlledByPlayer() ) {//NPC nextMove = saberMoveData[pm->ps->saberMove].chain_attack; } @@ -6551,7 +6926,7 @@ void PM_WeaponLightsaber(void) } else {//return to ready - if ( pm->ps->clientNum ) + if ( pm->ps->clientNum && !PM_ControlledByPlayer() ) {//NPC nextMove = saberMoveData[pm->ps->saberMove].chain_idle; } @@ -6775,6 +7150,10 @@ void PM_WeaponLightsaber(void) { PM_SetAnim(pm,SETANIM_TORSO,BOTH_WALK1,SETANIM_FLAG_NORMAL); } + else if( pm->ps->legsAnim == BOTH_RUN1 ) + { + PM_SetAnim(pm,SETANIM_TORSO,BOTH_RUN1,SETANIM_FLAG_NORMAL); + } else if( pm->ps->legsAnim == BOTH_RUN2 ) { PM_SetAnim(pm,SETANIM_TORSO,BOTH_RUN2,SETANIM_FLAG_NORMAL); @@ -6871,7 +7250,7 @@ void PM_WeaponLightsaber(void) } else if ( PM_SaberInBounce( curmove ) ) {//in a bounce - if ( pm->ps->clientNum ) + if ( pm->ps->clientNum && !PM_ControlledByPlayer() ) {//NPCs must play sequential attack //going into another attack... //allow endless chaining in level 1 attacks, several in level 2 and only one or a few in level 3 @@ -6933,7 +7312,7 @@ void PM_WeaponLightsaber(void) if ( curmove >= LS_PARRY_UP && curmove <= LS_REFLECT_LL ) {//from a parry or reflection, can go directly into an attack - if ( pm->ps->clientNum ) + if ( pm->ps->clientNum && !PM_ControlledByPlayer() ) {//NPCs newmove = PM_NPCSaberAttackFromQuad( saberMoveData[curmove].endQuad ); } @@ -6993,7 +7372,9 @@ void PM_WeaponLightsaber(void) newmove = saberMoveData[curmove].chain_idle; } else */ - if ( pm->ps->clientNum && Q_irand( 0, pm->ps->saberAnimLevel-1 ) ) + if ( pm->ps->clientNum + && !PM_ControlledByPlayer() + && (Q_irand( 0, pm->ps->saberAnimLevel-1 ) || ( pm->ps->saberAnimLevel == FORCE_LEVEL_1 && pm->gent && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG && Q_irand( 0, 1 ) ) ) )//minor change to make fast-attack users use the special attacks more {//NPCs use more randomized attacks the more skilled they are newmove = PM_NPCSaberAttackFromQuad( saberMoveData[curmove].endQuad ); } @@ -7130,7 +7511,7 @@ void PM_WeaponLightsaber(void) {//player always fires at normal speed addTime *= g_timescale->value; } - else if ( g_entities[pm->ps->clientNum].client && g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION && pm->ps->forcePowersActive&(1<ps->clientNum].client && (g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION||g_entities[pm->ps->clientNum].client->NPC_class == CLASS_DESANN) && pm->ps->forcePowersActive&(1<value; } @@ -7154,7 +7535,9 @@ void PM_WeaponLightsaber(void) {//player always fires at normal speed addTime *= g_timescale->value; } - else if ( g_entities[pm->ps->clientNum].client && g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION && pm->ps->forcePowersActive&(1<ps->clientNum].client + && (g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION || g_entities[pm->ps->clientNum].client->NPC_class == CLASS_DESANN) + && pm->ps->forcePowersActive&(1<value; } @@ -7200,12 +7583,26 @@ static bool PM_DoChargedWeapons( void ) // alt-fire charges the weapon...but due to zooming being controlled by the alt-button, the main button actually charges...but only when zoomed. // lovely, eh? - if ( cg.zoomMode == 2 ) + if ( !pm->ps->clientNum ) { - if ( pm->cmd.buttons & BUTTON_ATTACK ) + if ( cg.zoomMode == 2 ) { - charging = qtrue; - altFire = qtrue; // believe it or not, it really is an alt-fire in this case! + if ( pm->cmd.buttons & BUTTON_ATTACK ) + { + charging = qtrue; + altFire = qtrue; // believe it or not, it really is an alt-fire in this case! + } + } + } + else if ( pm->gent && pm->gent->NPC ) + { + if ( (pm->gent->NPC->scriptFlags&SCF_ALT_FIRE) ) + { + if ( pm->gent->fly_sound_debounce_time > level.time ) + { + charging = qtrue; + altFire = qtrue; + } } } break; @@ -7267,8 +7664,15 @@ static bool PM_DoChargedWeapons( void ) { if ( altFire ) { - if ( pm->ps->weaponstate != WEAPON_CHARGING_ALT ) + if ( pm->ps->weaponstate != WEAPON_CHARGING_ALT && pm->ps->weaponstate != WEAPON_DROPPING ) { + if ( pm->ps->ammo[weaponData[pm->ps->weapon].ammoIndex] <= 0) + { + PM_AddEvent( EV_NOAMMO ); + pm->ps->weaponTime += 500; + return true; + } + // charge isn't started, so do it now pm->ps->weaponstate = WEAPON_CHARGING_ALT; pm->ps->weaponChargeTime = level.time; @@ -7281,8 +7685,15 @@ static bool PM_DoChargedWeapons( void ) } else { - if ( pm->ps->weaponstate != WEAPON_CHARGING ) + if ( pm->ps->weaponstate != WEAPON_CHARGING && pm->ps->weaponstate != WEAPON_DROPPING ) { + if ( pm->ps->ammo[weaponData[pm->ps->weapon].ammoIndex] <= 0) + { + PM_AddEvent( EV_NOAMMO ); + pm->ps->weaponTime += 500; + return true; + } + // charge isn't started, so do it now pm->ps->weaponstate = WEAPON_CHARGING; pm->ps->weaponChargeTime = level.time; @@ -7321,7 +7732,7 @@ static bool PM_DoChargedWeapons( void ) #define BOWCASTER_CHARGE_UNIT 200.0f // bowcaster charging gives us one more unit every 200ms--if you change this, you'll have to do the same in g_weapon #define BRYAR_CHARGE_UNIT 200.0f // bryar charging gives us one more unit every 200ms--if you change this, you'll have to do the same in g_weapon #define DEMP2_CHARGE_UNIT 500.0f // ditto -#define DISRUPTOR_CHARGE_UNIT 50.0f // ditto +#define DISRUPTOR_CHARGE_UNIT 150.0f // ditto // Specific weapons can opt to modify the ammo usage based on charges, otherwise if no special case code // is handled below, regular ammo usage will happen @@ -7450,6 +7861,12 @@ static int PM_DoChargingAmmoUsage( int *amount ) // now that count is cool, get the real ammo usage *amount *= count; + + // this is an after-thought. should probably re-write the function to do this naturally. + if ( *amount > pm->ps->ammo[weaponData[pm->ps->weapon].ammoIndex] ) + { + *amount = pm->ps->ammo[weaponData[pm->ps->weapon].ammoIndex]; + } } else if ( pm->ps->weapon == WP_DISRUPTOR && pm->cmd.buttons & BUTTON_ALT_ATTACK ) // BUTTON_ATTACK will have been mapped to BUTTON_ALT_ATTACK if we are zoomed { @@ -7460,9 +7877,9 @@ static int PM_DoChargingAmmoUsage( int *amount ) { count = 1; } - else if ( count > 30 ) + else if ( count > 10 ) { - count = 30; + count = 10; } // Only bother with these checks if we don't have infinite ammo @@ -7488,6 +7905,12 @@ static int PM_DoChargingAmmoUsage( int *amount ) // now that count is cool, get the real ammo usage *amount *= count; + + // this is an after-thought. should probably re-write the function to do this naturally. + if ( *amount > pm->ps->ammo[weaponData[pm->ps->weapon].ammoIndex] ) + { + *amount = pm->ps->ammo[weaponData[pm->ps->weapon].ammoIndex]; + } } return count; @@ -7518,7 +7941,7 @@ static void PM_Weapon( void ) int addTime, amount, trueCount = 1; qboolean delayed_fire = qfalse; - if (pm->ps->weapon == WP_SABER && (!cg.zoomMode||pm->ps->clientNum) ) // WP_LIGHTSABER + if (pm->ps->weapon == WP_SABER && (cg.zoomMode==3||!cg.zoomMode||pm->ps->clientNum) ) // WP_LIGHTSABER { // Separate logic for lightsaber, but not for player when zoomed PM_WeaponLightsaber(); if ( pm->gent && pm->gent->client && pm->ps->saberActive && pm->ps->saberInFlight ) @@ -7554,9 +7977,21 @@ static void PM_Weapon( void ) pm->gent->client->fireDelay -= pml.msec; if(pm->gent->client->fireDelay <= 0) {//just finished delay timer + if ( pm->ps->clientNum && pm->ps->weapon == WP_ROCKET_LAUNCHER ) + { + G_SoundOnEnt( pm->gent, CHAN_WEAPON, "sound/weapons/rocket/lock.wav" ); + pm->cmd.buttons |= BUTTON_ALT_ATTACK; + } pm->gent->client->fireDelay = 0; delayed_fire = qtrue; } + else + { + if ( pm->ps->clientNum && pm->ps->weapon == WP_ROCKET_LAUNCHER && Q_irand( 0, 1 ) ) + { + G_SoundOnEnt( pm->gent, CHAN_WEAPON, "sound/weapons/rocket/tick.wav" ); + } + } } // don't allow attack until all buttons are up @@ -7818,9 +8253,12 @@ static void PM_Weapon( void ) } else // Not enough energy { - // Switch weapons - PM_AddEvent( EV_NOAMMO ); - pm->ps->weaponTime += 500; + if ( !( pm->ps->eFlags & EF_LOCKED_TO_WEAPON )) + { + // Switch weapons + PM_AddEvent( EV_NOAMMO ); + pm->ps->weaponTime += 500; + } return; } } @@ -7845,6 +8283,13 @@ static void PM_Weapon( void ) } else { + if ( pm->ps->clientNum //NPC + && !PM_ControlledByPlayer() //not under player control + && pm->ps->weapon == WP_THERMAL //using thermals + && pm->ps->torsoAnim != BOTH_ATTACK10 )//not in the throw anim + {//oops, got knocked out of the anim, don't throw the thermal + return; + } PM_AddEvent( EV_FIRE_WEAPON ); addTime = weaponData[pm->ps->weapon].fireTime; @@ -7876,7 +8321,9 @@ static void PM_Weapon( void ) {//player always fires at normal speed addTime *= g_timescale->value; } - else if ( g_entities[pm->ps->clientNum].client && g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION && pm->ps->forcePowersActive&(1<ps->clientNum].client + && (g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION || g_entities[pm->ps->clientNum].client->NPC_class == CLASS_DESANN) + && pm->ps->forcePowersActive&(1<value; } @@ -7886,6 +8333,19 @@ static void PM_Weapon( void ) pm->ps->weaponTime += addTime; pm->ps->lastShotTime = level.time;//so we know when the last time we fired our gun is + + // HACK!!!!! + if ( pm->ps->ammo[weaponData[pm->ps->weapon].ammoIndex] <= 0 ) + { + if ( pm->ps->weapon == WP_THERMAL || pm->ps->weapon == WP_TRIP_MINE ) + { + // because these weapons have the ammo attached to the hand, we should switch weapons when the last one is thrown, otherwise it will look silly + // NOTE: could also switch to an empty had version, but was told we aren't getting any new models at this point + CG_OutOfAmmoChange(); + PM_SetAnim(pm,SETANIM_TORSO,TORSO_DROPWEAP1 + 2,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD); // hack weapon down! + pm->ps->weaponTime = 50; + } + } } @@ -8054,7 +8514,9 @@ void PM_SetSpecialMoveValues (void ) { pml.frametime *= (1.0f/g_timescale->value); } - else if ( g_entities[pm->ps->clientNum].client && g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION && pm->ps->forcePowersActive&(1<ps->clientNum].client + && (g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION || g_entities[pm->ps->clientNum].client->NPC_class == CLASS_TAVION) + && pm->ps->forcePowersActive&(1<value); } @@ -8081,8 +8543,8 @@ void PM_AdjustAttackStates( pmove_t *pm ) amount = pm->ps->ammo[weaponData[ pm->ps->weapon ].ammoIndex] - weaponData[pm->ps->weapon].energyPerShot; } - if ( pm->ps->weapon == WP_SABER && !cg.zoomMode ) - { + if ( pm->ps->weapon == WP_SABER && (!cg.zoomMode||pm->ps->clientNum) ) + {//don't let the alt-attack be interpreted as an actual attack command //saber alt-attack does a normal swing, too pm->cmd.buttons &= ~BUTTON_ALT_ATTACK; if ( pm->ps->saberInFlight ) @@ -8344,10 +8806,20 @@ void Pmove( pmove_t *pmove ) // set watertype, and waterlevel PM_SetWaterLevelAtPoint( pm->ps->origin, &pm->waterlevel, &pm->watertype ); + PM_SetWaterHeight(); if ( !(pm->watertype & CONTENTS_LADDER) ) {//Don't want to remember this for ladders, is only for waterlevel change events (sounds) pml.previous_waterlevel = pmove->waterlevel; } + waterForceJump = qfalse; + if ( pmove->waterlevel && pm->ps->clientNum ) + { + if ( pm->ps->forceJumpZStart//force jumping + ||(pm->gent&&!TIMER_Done(pm->gent, "forceJumpChasing" )) )//force-jumping + { + waterForceJump = qtrue; + } + } // set mins, maxs, and viewheight PM_SetBounds(); @@ -8383,8 +8855,9 @@ void Pmove( pmove_t *pmove ) { PM_WaterJumpMove(); } - else if ( pm->waterlevel > 1 ) - { + else if ( pm->waterlevel > 1 //in water + &&(!pm->ps->clientNum || !waterForceJump) )//player or NPC not force jumping + {//force-jumping NPCs should // swimming or in ladder PM_WaterMove(); } @@ -8396,7 +8869,14 @@ void Pmove( pmove_t *pmove ) PM_WalkMove(); - if ( VectorCompare( oldOrg, pm->ps->origin ) ) + + float threshHold = 0.001f, movedDist = DistanceSquared( oldOrg, pm->ps->origin ); + if ( PM_StandingAnim( pm->ps->legsAnim ) || pm->ps->legsAnim == BOTH_CROUCH1 ) + { + threshHold = 0.005f; + } + + if ( movedDist < threshHold ) {//didn't move, play no legs anim pm->cmd.forwardmove = pm->cmd.rightmove = 0; } @@ -8436,6 +8916,7 @@ void Pmove( pmove_t *pmove ) if(!(VectorCompare(pm->ps->origin,pml.previous_origin))) { PM_SetWaterLevelAtPoint( pm->ps->origin, &pm->waterlevel, &pm->watertype ); + PM_SetWaterHeight(); } PM_Inventory(); @@ -8484,7 +8965,7 @@ void Pmove( pmove_t *pmove ) PM_WaterEvents(); // snap some parts of playerstate to save network bandwidth - SnapVector( pm->ps->velocity ); + // SnapVector( pm->ps->velocity ); if ( !pm->cmd.rightmove && !pm->cmd.forwardmove && pm->cmd.upmove <= 0 ) { diff --git a/code/game/bg_public.h b/code/game/bg_public.h index 40a9ea8..b0dbe01 100644 --- a/code/game/bg_public.h +++ b/code/game/bg_public.h @@ -234,7 +234,7 @@ typedef enum { PW_NUM_POWERUPS } powerup_t; - +#define PW_REMOVE_AT_DEATH ((1<event values // entity events are for effects that take place relative // to an existing entities origin. Very network efficient. @@ -337,6 +337,9 @@ typedef enum { EV_CHOKE1, //Say when choking EV_CHOKE2, EV_CHOKE3, + + EV_FFWARN, //ffire founds + EV_FFTURN, //extra sounds for ST EV_CHASE1, EV_CHASE2, @@ -351,18 +354,18 @@ typedef enum { EV_DETECTED3, EV_DETECTED4, EV_DETECTED5, - EV_GIVEUP1, - EV_GIVEUP2, - EV_GIVEUP3, - EV_GIVEUP4, - EV_LOOK1, - EV_LOOK2, EV_LOST1, EV_OUTFLANK1, EV_OUTFLANK2, EV_ESCAPING1, EV_ESCAPING2, EV_ESCAPING3, + EV_GIVEUP1, + EV_GIVEUP2, + EV_GIVEUP3, + EV_GIVEUP4, + EV_LOOK1, + EV_LOOK2, EV_SIGHT1, EV_SIGHT2, EV_SIGHT3, diff --git a/code/game/bg_slidemove.cpp b/code/game/bg_slidemove.cpp index c302dff..cf4106e 100644 --- a/code/game/bg_slidemove.cpp +++ b/code/game/bg_slidemove.cpp @@ -22,12 +22,13 @@ Returns qtrue if the velocity was clipped in some way ================== */ #define MAX_CLIP_PLANES 5 +extern qboolean PM_GroundSlideOkay( float zNormal ); qboolean PM_SlideMove( float gravMod ) { int bumpcount, numbumps; vec3_t dir; float d; int numplanes; - vec3_t planes[MAX_CLIP_PLANES]; + vec3_t normal, planes[MAX_CLIP_PLANES]; vec3_t primal_velocity; vec3_t clipVelocity; int i, j, k; @@ -43,7 +44,8 @@ qboolean PM_SlideMove( float gravMod ) { VectorCopy (pm->ps->velocity, primal_velocity); - if ( gravMod ) { + if ( gravMod ) + { VectorCopy( pm->ps->velocity, endVelocity ); if ( !(pm->ps->eFlags&EF_FORCE_GRIPPED) ) { @@ -51,20 +53,31 @@ qboolean PM_SlideMove( float gravMod ) { } pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; primal_velocity[2] = endVelocity[2]; - if ( pml.groundPlane ) { - // slide along the ground plane - PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); + if ( pml.groundPlane ) + { + if ( PM_GroundSlideOkay( pml.groundTrace.plane.normal[2] ) ) + {// slide along the ground plane + PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, + pm->ps->velocity, OVERCLIP ); + } } } time_left = pml.frametime; // never turn against the ground plane - if ( pml.groundPlane ) { + if ( pml.groundPlane ) + { numplanes = 1; VectorCopy( pml.groundTrace.plane.normal, planes[0] ); - } else { + if ( !PM_GroundSlideOkay( planes[0][2] ) ) + { + planes[0][2] = 0; + VectorNormalize( planes[0] ); + } + } + else + { numplanes = 0; } @@ -80,18 +93,19 @@ qboolean PM_SlideMove( float gravMod ) { // see if we can make it there pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask); - if (trace.allsolid) { - // entity is completely trapped in another solid + if ( trace.allsolid ) + {// entity is completely trapped in another solid pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration return qtrue; } - if (trace.fraction > 0) { - // actually covered some distance - VectorCopy (trace.endpos, pm->ps->origin); + if ( trace.fraction > 0 ) + {// actually covered some distance + VectorCopy( trace.endpos, pm->ps->origin ); } - if (trace.fraction == 1) { + if ( trace.fraction == 1 ) + { break; // moved the entire distance } @@ -105,7 +119,7 @@ qboolean PM_SlideMove( float gravMod ) { { damageSelf = qfalse; } - else if ( trace.entityNum == ENTITYNUM_WORLD && trace.plane.normal[2] > 0.5 ) + else if ( trace.entityNum == ENTITYNUM_WORLD && trace.plane.normal[2] > 0.5f ) {//if we land on the ground, let falling damage do it's thing itself, otherwise do impact damage damageSelf = qfalse; } @@ -121,27 +135,34 @@ qboolean PM_SlideMove( float gravMod ) { time_left -= time_left * trace.fraction; - if (numplanes >= MAX_CLIP_PLANES) { - // this shouldn't really happen + if ( numplanes >= MAX_CLIP_PLANES ) + {// this shouldn't really happen VectorClear( pm->ps->velocity ); return qtrue; } + VectorCopy( trace.plane.normal, normal ); + if ( !PM_GroundSlideOkay( normal[2] ) ) + {//wall-running + //never push up off a sloped wall + normal[2] = 0; + VectorNormalize( normal ); + } // // if this is the same plane we hit before, nudge velocity // out along it, which fixes some epsilon issues with // non-axial planes // for ( i = 0 ; i < numplanes ; i++ ) { - if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) { - VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity ); + if ( DotProduct( normal, planes[i] ) > 0.99 ) { + VectorAdd( normal, pm->ps->velocity, pm->ps->velocity ); break; } } if ( i < numplanes ) { continue; } - VectorCopy (trace.plane.normal, planes[numplanes]); + VectorCopy( normal, planes[numplanes] ); numplanes++; // @@ -242,7 +263,7 @@ void PM_StepSlideMove( float gravMod ) vec3_t slideMove, stepUpMove; trace_t trace; vec3_t up, down; - qboolean cantStepUpFwd; + qboolean cantStepUpFwd, isATST = qfalse;; int stepSize = STEPSIZE; VectorCopy (pm->ps->origin, start_o); @@ -254,6 +275,7 @@ void PM_StepSlideMove( float gravMod ) if ( pm->gent && pm->gent->client && pm->gent->client->NPC_class == CLASS_ATST) { + isATST = qtrue; stepSize = 66;//hack for AT-ST stepping, slightly taller than a standing stormtrooper } else if ( pm->maxs[2] <= 0 ) @@ -315,10 +337,21 @@ void PM_StepSlideMove( float gravMod ) VectorCopy (pm->ps->origin, down); down[2] -= stepSize; pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); - if ( !trace.allsolid ) { - VectorCopy (trace.endpos, pm->ps->origin); + if ( !trace.allsolid ) + { + if ( pm->ps->clientNum + && isATST + && g_entities[trace.entityNum].client + && g_entities[trace.entityNum].client->playerTeam == pm->gent->client->playerTeam ) + {//AT-ST's don't step up on allies + } + else + { + VectorCopy( trace.endpos, pm->ps->origin ); + } } - if ( trace.fraction < 1.0 ) { + if ( trace.fraction < 1.0 ) + { PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP ); } } diff --git a/code/game/boltons.h b/code/game/boltons.h new file mode 100644 index 0000000..522b346 --- /dev/null +++ b/code/game/boltons.h @@ -0,0 +1,30 @@ +#ifndef __BOLTONS_H__ +#define __BOLTONS_H__ + +#define MAX_GAME_BOLTONS 64 + +typedef struct boltOn_s +{//a tagged object + char name[32]; //If there is a name, it is considered active (look up in boltOns.cfg) + modelInfo_t model; + targetModel_t targetModel;// name of object to attach to + char targetTag[20];// name of tag on target object to attach to + vec3_t angleOffsets;// angle offsets to apply when attaching to target object's tag + vec3_t originOffsets;// angle offsets to apply when attaching to target object's tag +} boltOn_t; + +extern boltOn_t knownBoltOns[MAX_GAME_BOLTONS]; +extern int numBoltOns; + +extern void G_RegisterBoltOns(void); +//extern byte G_AddBoltOn( gentity_t *ent, const char *boltOnName ); +//extern void G_RemoveBoltOn( gentity_t *ent, const char *boltOnName ); +//extern void Q3_SetActiveBoltOn( int entID, const char *boltOnName ); +//extern void Q3_SetActiveBoltOnStartFrame( int entID, int startFrame ); +//extern void Q3_SetActiveBoltOnEndFrame( int entID, int endFrame ); +//extern void Q3_SetActiveBoltOnAnimLoop( int entID, qboolean loopAnim ); +extern void G_DropBoltOn( gentity_t *ent, const char *boltOnName ); +extern byte G_BoltOnNumberForName( gentity_t *ent, const char *boltOnName ); +extern void G_InitBoltOnData ( gentity_t *ent ); + +#endif// #ifndef __BOLTONS_H__ diff --git a/code/game/dmstates.h b/code/game/dmstates.h new file mode 100644 index 0000000..c66a87a --- /dev/null +++ b/code/game/dmstates.h @@ -0,0 +1,15 @@ +#ifndef __DMSTATES_H__ +#define __DMSTATES_H__ + +//dynamic music +typedef enum //# dynamicMusic_e +{ + DM_AUTO, //# let the game determine the dynamic music as normal + DM_SILENCE, //# stop the music + DM_EXPLORE, //# force the exploration music to play + DM_ACTION, //# force the action music to play + DM_BOSS, //# force the boss battle music to play (if there is any) + DM_DEATH //# force the "player dead" music to play +} dynamicMusic_t; + +#endif//#ifndef __DMSTATES_H__ diff --git a/code/game/fields.h b/code/game/fields.h index af277dc..751a863 100644 --- a/code/game/fields.h +++ b/code/game/fields.h @@ -59,6 +59,7 @@ typedef enum F_DIE_F, F_RESPAWN_F, */ + F_GROUP, F_IGNORE } fieldtypeSAVE_t; diff --git a/code/game/g_ICARUS.cpp b/code/game/g_ICARUS.cpp index c23ff01..c2e42c0 100644 --- a/code/game/g_ICARUS.cpp +++ b/code/game/g_ICARUS.cpp @@ -470,6 +470,8 @@ void ICARUS_InterrogateScript( const char *filename ) case SET_BLOCKEDSCRIPT: case SET_FFIRESCRIPT: case SET_FFDEATHSCRIPT: + case SET_MINDTRICKSCRIPT: + case SET_CINEMATIC_SKIPSCRIPT: //Recursively obtain all embedded scripts ICARUS_InterrogateScript( sVal2 ); break; @@ -498,6 +500,12 @@ extern cvar_t *com_buildScript; } } break; + case SET_ADDRHANDBOLT_MODEL: + case SET_ADDLHANDBOLT_MODEL: + { + gi.G2API_PrecacheGhoul2Model( sVal2 ); + } + break; default: break; } diff --git a/code/game/g_active.cpp b/code/game/g_active.cpp index 68650eb..3d87fa8 100644 --- a/code/game/g_active.cpp +++ b/code/game/g_active.cpp @@ -52,10 +52,15 @@ extern qboolean PM_InForceGetUp( playerState_t *ps ); extern void G_CreateG2AttachedWeaponModel( gentity_t *ent, const char *weaponModel ); extern qboolean FlyingCreature( gentity_t *ent ); -extern bool in_camera; -extern qboolean player_locked; +extern bool in_camera; +extern qboolean player_locked; extern qboolean stop_icarus; -extern cvar_t *g_spskill; +extern cvar_t *g_spskill; +extern cvar_t *g_timescale; +extern cvar_t *g_saberMoveSpeed; +extern cvar_t *g_saberAutoBlocking; +extern vmCvar_t cg_thirdPersonAlpha; +extern vmCvar_t cg_thirdPersonAutoAlpha; void ClientEndPowerUps( gentity_t *ent ); @@ -123,7 +128,7 @@ int G_FindLookItem( gentity_t *self ) VectorSubtract( ent->currentOrigin, center, dir ); rating = (1.0f-(VectorNormalize( dir )/radius)); rating *= DotProduct( forward, dir ); - if ( ent->item->giType == IT_HOLDABLE && ent->item->giTag == INV_SECURITY_KEY1 ) + if ( ent->item->giType == IT_HOLDABLE && ent->item->giTag == INV_SECURITY_KEY ) {//security keys are of the highest importance rating *= 2.0f; } @@ -136,14 +141,28 @@ int G_FindLookItem( gentity_t *self ) return bestEntNum; } +extern void CG_SetClientViewAngles( vec3_t angles, qboolean overrideViewEnt ); qboolean G_ClearViewEntity( gentity_t *ent ) { if ( !ent->client->ps.viewEntity ) return qfalse; - if ( &g_entities[ent->client->ps.viewEntity] ) + if ( ent->client->ps.viewEntity > 0 && ent->client->ps.viewEntity < ENTITYNUM_NONE ) { - g_entities[ent->client->ps.viewEntity].svFlags &= ~SVF_BROADCAST; + if ( &g_entities[ent->client->ps.viewEntity] ) + { + g_entities[ent->client->ps.viewEntity].svFlags &= ~SVF_BROADCAST; + if ( g_entities[ent->client->ps.viewEntity].NPC ) + { + g_entities[ent->client->ps.viewEntity].NPC->controlledTime = 0; + SetClientViewAngle( &g_entities[ent->client->ps.viewEntity], g_entities[ent->client->ps.viewEntity].currentAngles ); + G_SetAngles( &g_entities[ent->client->ps.viewEntity], g_entities[ent->client->ps.viewEntity].currentAngles ); + VectorCopy( g_entities[ent->client->ps.viewEntity].currentAngles, g_entities[ent->client->ps.viewEntity].NPC->lastPathAngles ); + g_entities[ent->client->ps.viewEntity].NPC->desiredYaw = g_entities[ent->client->ps.viewEntity].currentAngles[YAW]; + } + } + CG_SetClientViewAngles( ent->pos4, qtrue ); + SetClientViewAngle( ent, ent->pos4 ); } ent->client->ps.viewEntity = 0; return qtrue; @@ -161,12 +180,48 @@ void G_SetViewEntity( gentity_t *self, gentity_t *viewEntity ) // yeah, it should really toggle them so it plays the end sound.... cg.zoomMode = 0; } - + if ( viewEntity->s.number == self->client->ps.viewEntity ) + { + return; + } //clear old one first G_ClearViewEntity( self ); //set new one self->client->ps.viewEntity = viewEntity->s.number; viewEntity->svFlags |= SVF_BROADCAST; + //remember current angles + VectorCopy( self->client->ps.viewangles, self->pos4 ); + if ( viewEntity->client ) + { + //vec3_t clear = {0,0,0}; + CG_SetClientViewAngles( viewEntity->client->ps.viewangles, qtrue ); + //SetClientViewAngle( self, viewEntity->client->ps.viewangles ); + //SetClientViewAngle( viewEntity, clear ); + /* + VectorCopy( viewEntity->client->ps.viewangles, self->client->ps.viewangles ); + for ( int i = 0; i < 3; i++ ) + { + self->client->ps.delta_angles[i] = viewEntity->client->ps.delta_angles[i]; + } + */ + } + if ( !self->s.number ) + { + CG_CenterPrint( "@INGAME_EXIT_VIEW", SCREEN_HEIGHT * 0.95 ); + } +} + +qboolean G_ControlledByPlayer( gentity_t *self ) +{ + if ( self && self->NPC && self->NPC->controlledTime > level.time ) + {//being controlled + gentity_t *controller = &g_entities[0]; + if ( controller->client && controller->client->ps.viewEntity == self->s.number ) + {//we're the player's viewEntity + return qtrue; + } + } + return qfalse; } qboolean G_ValidateLookEnemy( gentity_t *self, gentity_t *enemy ) @@ -192,22 +247,27 @@ qboolean G_ValidateLookEnemy( gentity_t *self, gentity_t *enemy ) && enemy->noDamageTeam != self->client->playerTeam && enemy->health > 0 ) {//a turret - return qtrue; + //return qtrue; } - return qfalse; - } - - if ( enemy->health <= 0 && ((level.time-enemy->s.time) > 3000||!InFront(enemy->currentOrigin,self->currentOrigin,self->client->ps.viewangles,0.2f)||DistanceHorizontal(enemy->currentOrigin,self->currentOrigin)>16384))//>128 - {//corpse, been dead too long or too out of sight to be interesting - if ( !enemy->message ) + else { return qfalse; } } + else + { + if ( enemy->client->playerTeam == self->client->playerTeam ) + {//on same team + return qfalse; + } - if ( enemy->client->playerTeam == self->client->playerTeam ) - {//on same team - return qfalse; + if ( enemy->health <= 0 && ((level.time-enemy->s.time) > 3000||!InFront(enemy->currentOrigin,self->currentOrigin,self->client->ps.viewangles,0.2f)||DistanceHorizontal(enemy->currentOrigin,self->currentOrigin)>16384))//>128 + {//corpse, been dead too long or too out of sight to be interesting + if ( !enemy->message ) + { + return qfalse; + } + } } if ( (!InFront( enemy->currentOrigin, self->currentOrigin, self->client->ps.viewangles, 0.0f) || !G_ClearLOS( self, self->client->renderInfo.eyePoint, enemy ) ) @@ -395,7 +455,7 @@ Check for lava / slime contents and drowning ============= */ void P_WorldEffects( gentity_t *ent ) { - int waterlevel; + int mouthContents = 0; if ( ent->client->noclip ) { @@ -403,11 +463,14 @@ void P_WorldEffects( gentity_t *ent ) { return; } - waterlevel = ent->waterlevel; + if ( !in_camera ) + { + mouthContents = gi.pointcontents( ent->client->renderInfo.eyePoint, ent->s.number ); + } // // check for drowning // - if ( waterlevel == 3 && !(ent->watertype&CONTENTS_LADDER) ) + if ( (mouthContents&(CONTENTS_WATER|CONTENTS_SLIME)) ) { if ( ent->client->NPC_class == CLASS_SWAMPTROOPER ) {//they have air tanks @@ -451,14 +514,14 @@ void P_WorldEffects( gentity_t *ent ) { // // check for sizzle damage (move to pmove?) // - if (waterlevel && + if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) ) { if (ent->health > 0 && ent->painDebounceTime < level.time ) { if (ent->watertype & CONTENTS_LAVA) { G_Damage (ent, NULL, NULL, NULL, NULL, - 15*waterlevel, 0, MOD_LAVA); + 15*ent->waterlevel, 0, MOD_LAVA); } if (ent->watertype & CONTENTS_SLIME) { @@ -627,7 +690,7 @@ void DoImpact( gentity_t *self, gentity_t *other, qboolean damageSelf ) } } - if ( damageSelf && self->takedamage ) + if ( damageSelf && self->takedamage && !(self->flags&FL_NO_IMPACT_DMG)) { //Now damage me //FIXME: more lenient falling damage, especially for when driving a vehicle @@ -767,6 +830,9 @@ void G_TouchTriggersLerped( gentity_t *ent ) { #endif// _DEBUG VectorSubtract( ent->currentOrigin, ent->lastOrigin, diff ); dist = VectorNormalize( diff ); +#ifdef _DEBUG + assert( (dist<1024) && "insane distance in G_TouchTriggersLerped!" ); +#endif// _DEBUG memset (touched, qfalse, sizeof(touched) ); @@ -1006,7 +1072,7 @@ void G_MatchPlayerWeapon( gentity_t *ent ) } if ( newWeap != WP_NONE && ent->client->ps.weapon != newWeap ) { - if ( ent->weaponModel != -1 ) + if ( ent->weaponModel >= 0 ) { gi.G2API_RemoveGhoul2Model(ent->ghoul2, ent->weaponModel); } @@ -1103,6 +1169,10 @@ void ClientTimerActions( gentity_t *ent, int msec ) { { client->timeResidual -= 1000; + if ( ent->s.weapon != WP_NONE ) + { + ent->client->sess.missionStats.weaponUsed[ent->s.weapon]++; + } // if we've got the seeker powerup, see if we can shoot it at someone /* if ( ent->client->ps.powerups[PW_SEEKER] > level.time ) { @@ -1212,18 +1282,26 @@ void ClientEvents( gentity_t *ent, int oldEventSequence ) { //by the way, if you have your saber in hand and it's on, do the damage trace if ( client->ps.weapon == WP_SABER ) { - if ( client->ps.saberDamageDebounceTime <= level.time ) + if ( g_timescale->value >= 1.0f || !(client->ps.forcePowersActive&(1<value&&client->ps.clientNum==0&&!player_locked&&!MatrixMode&&client->ps.forcePowersActive&(1<value ); + //sanity check + if ( client->ps.saberDamageDebounceTime - level.time > wait ) + {//when you unpause the game with force speed on, the time gets *really* wiggy... + client->ps.saberDamageDebounceTime = level.time + wait; + } + if ( client->ps.saberDamageDebounceTime <= level.time ) + { + WP_SaberDamageTrace( ent ); + WP_SaberUpdateOldBladeData( ent ); + /* + if ( g_timescale->value&&client->ps.clientNum==0&&!player_locked&&!MatrixMode&&client->ps.forcePowersActive&(1<value ); + } + */ + client->ps.saberDamageDebounceTime = level.time + wait; } - */ - client->ps.saberDamageDebounceTime = level.time + wait; } } } @@ -1270,7 +1348,7 @@ qboolean G_CheckClampUcmd( gentity_t *ent, usercmd_t *ucmd ) if ( ent->client->ps.saberMove == LS_A_LUNGE ) {//can't move during lunge ucmd->rightmove = ucmd->upmove = 0; - if ( ent->client->ps.legsAnimTimer > 500 ) + if ( ent->client->ps.legsAnimTimer > 500 && (ent->s.number || !player_locked) ) { ucmd->forwardmove = 127; } @@ -1278,21 +1356,33 @@ qboolean G_CheckClampUcmd( gentity_t *ent, usercmd_t *ucmd ) { ucmd->forwardmove = 0; } + if ( ent->NPC ) + {//invalid now + VectorClear( ent->client->ps.moveDir ); + } } if ( ent->client->ps.saberMove == LS_A_JUMP_T__B_ ) {//can't move during leap - if ( ent->client->ps.groundEntityNum != ENTITYNUM_NONE ) + if ( ent->client->ps.groundEntityNum != ENTITYNUM_NONE || (!ent->s.number && player_locked) ) {//hit the ground ucmd->forwardmove = 0; } ucmd->rightmove = ucmd->upmove = 0; + if ( ent->NPC ) + {//invalid now + VectorClear( ent->client->ps.moveDir ); + } } if ( ent->client->ps.saberMove == LS_A_BACK || ent->client->ps.saberMove == LS_A_BACK_CR || ent->client->ps.saberMove == LS_A_BACKSTAB ) {//can't move or turn during back attacks ucmd->forwardmove = ucmd->rightmove = 0; + if ( ent->NPC ) + { + VectorClear( ent->client->ps.moveDir ); + } if ( (overridAngles = (PM_AdjustAnglesForBackAttack( ent, ucmd )?qtrue:overridAngles)) == qtrue ) { //pull back the view @@ -1347,28 +1437,42 @@ qboolean G_CheckClampUcmd( gentity_t *ent, usercmd_t *ucmd ) if ( PM_InRoll( &ent->client->ps ) ) { - PM_CmdForRoll( ent->client->ps.legsAnim, ucmd ); + if ( ent->s.number || !player_locked ) + { + PM_CmdForRoll( ent->client->ps.legsAnim, ucmd ); + } + if ( ent->NPC ) + {//invalid now + VectorClear( ent->client->ps.moveDir ); + } ent->client->ps.speed = 400; } if ( PM_InCartwheel( ent->client->ps.legsAnim ) ) {//can't keep moving in cartwheel ucmd->forwardmove = ucmd->rightmove = ucmd->upmove = 0; - switch ( ent->client->ps.legsAnim ) + if ( ent->NPC ) + {//invalid now + VectorClear( ent->client->ps.moveDir ); + } + if ( ent->s.number || !player_locked ) { - case BOTH_ARIAL_LEFT: - case BOTH_CARTWHEEL_LEFT: - ucmd->rightmove = -127; - break; - case BOTH_ARIAL_RIGHT: - case BOTH_CARTWHEEL_RIGHT: - ucmd->rightmove = 127; - break; - case BOTH_ARIAL_F1: - ucmd->forwardmove = 127; - break; - default: - break; + switch ( ent->client->ps.legsAnim ) + { + case BOTH_ARIAL_LEFT: + case BOTH_CARTWHEEL_LEFT: + ucmd->rightmove = -127; + break; + case BOTH_ARIAL_RIGHT: + case BOTH_CARTWHEEL_RIGHT: + ucmd->rightmove = 127; + break; + case BOTH_ARIAL_F1: + ucmd->forwardmove = 127; + break; + default: + break; + } } } @@ -1377,12 +1481,16 @@ qboolean G_CheckClampUcmd( gentity_t *ent, usercmd_t *ucmd ) return overridAngles; } -void BG_AddPushVecToUcmd(gentity_t *self, usercmd_t *ucmd) +void BG_AddPushVecToUcmd( gentity_t *self, usercmd_t *ucmd ) { vec3_t forward, right, moveDir; float pushSpeed, fMove, rMove; - pushSpeed = VectorLengthSquared(self->s.pushVec); + if ( !self->client ) + { + return; + } + pushSpeed = VectorLengthSquared(self->client->pushVec); if(!pushSpeed) {//not being pushed return; @@ -1393,7 +1501,7 @@ void BG_AddPushVecToUcmd(gentity_t *self, usercmd_t *ucmd) VectorMA(moveDir, ucmd->rightmove/127.0f * self->client->ps.speed, right, moveDir); //moveDir is now our intended move velocity - VectorAdd(moveDir, self->s.pushVec, moveDir); + VectorAdd(moveDir, self->client->pushVec, moveDir); self->client->ps.speed = VectorNormalize(moveDir); //moveDir is now our intended move velocity plus our push Vector @@ -1402,7 +1510,10 @@ void BG_AddPushVecToUcmd(gentity_t *self, usercmd_t *ucmd) ucmd->forwardmove = floor(fMove);//If in the same dir , will be positive ucmd->rightmove = floor(rMove);//If in the same dir , will be positive - VectorClear(self->s.pushVec); + if ( self->client->pushVecTime < level.time ) + { + VectorClear( self->client->pushVec ); + } } void NPC_Accelerate( gentity_t *ent, qboolean fullWalkAcc, qboolean fullRunAcc ) @@ -1613,6 +1724,11 @@ extern void CG_ChangeWeapon( int num ); } } + if ( ent->client->ps.weapon == WP_SABER ) + { + ent->client->ps.saberActive = ent->owner->alt_fire; + } + // We'll leave the gun pointed in the direction it was last facing, though we'll cut out the pitch if ( ent->client ) { @@ -1670,7 +1786,7 @@ extern void CG_ChangeWeapon( int num ); void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ) { - if (( (*ucmd)->buttons & BUTTON_USE || (*ucmd)->forwardmove < 0 ) && ent->owner && ent->owner->delay + 500 < level.time ) + if (( (*ucmd)->buttons & BUTTON_USE || (*ucmd)->forwardmove < 0 || (*ucmd)->upmove > 0 ) && ent->owner && ent->owner->delay + 500 < level.time ) { ent->owner->s.loopSound = 0; @@ -1682,7 +1798,7 @@ void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ) else { // this is a crappy way to put sounds on a moving emplaced gun.... - if ( ent->owner ) +/* if ( ent->owner ) { if ( !VectorCompare( ent->owner->pos3, ent->owner->movedir )) { @@ -1699,7 +1815,7 @@ void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ) VectorCopy( ent->owner->pos3, ent->owner->movedir ); } - +*/ // don't allow movement, weapon switching, and most kinds of button presses (*ucmd)->forwardmove = 0; (*ucmd)->rightmove = 0; @@ -1829,18 +1945,27 @@ void G_CheckMovingLoopingSounds( gentity_t *ent, usercmd_t *ucmd ) || (ucmd->upmove&&FlyingCreature( ent ))//flier using ucmds to move || (FlyingCreature( ent )&&!VectorCompare( vec3_origin, ent->client->ps.velocity )&&ent->health>0))//flier using velocity to move { - if ( ent->client->NPC_class == CLASS_R2D2 ) + switch( ent->client->NPC_class ) { + case CLASS_R2D2: + case CLASS_R5D2: ent->s.loopSound = G_SoundIndex( "sound/chars/r2d2/misc/r2_move_lp.wav" ); - } - if ( ent->client->NPC_class == CLASS_R5D2 ) - { - ent->s.loopSound = G_SoundIndex( "sound/chars/r2d2/misc/r2_move_lp2.wav" ); + break; + case CLASS_MARK2: + ent->s.loopSound = G_SoundIndex( "sound/chars/mark2/misc/mark2_move_lp" ); + break; + case CLASS_MOUSE: + ent->s.loopSound = G_SoundIndex( "sound/chars/mouse/misc/mouse_lp" ); + break; + case CLASS_PROBE: + ent->s.loopSound = G_SoundIndex( "sound/chars/probe/misc/probedroidloop" ); } } else {//not moving under your own control, stop loopSound - if ( ent->client->NPC_class == CLASS_R2D2 || ent->client->NPC_class == CLASS_R5D2 ) + if ( ent->client->NPC_class == CLASS_R2D2 || ent->client->NPC_class == CLASS_R5D2 + || ent->client->NPC_class == CLASS_MARK2 || ent->client->NPC_class == CLASS_MOUSE + || ent->client->NPC_class == CLASS_PROBE ) { ent->s.loopSound = 0; } @@ -1867,6 +1992,7 @@ void ClientThink_real( gentity_t *ent, usercmd_t *ucmd ) int oldEventSequence; int msec; qboolean inSpinFlipAttack = PM_AdjustAnglesForSpinningFlip( ent, ucmd, qfalse ); + qboolean controlledByPlayer = qfalse; //Don't let the player do anything if in a camera if ( ent->s.number == 0 ) @@ -1882,7 +2008,9 @@ extern cvar_t *g_skippingcin; { NPC_SetLookTarget( ent, ent->client->ps.saberLockEnemy, level.time+1000 ); } - if ( ent->client->renderInfo.lookTargetClearTime < level.time && ent->health > 0 )//NOTE: here this is used as a debounce, not an actual timer + if ( ent->client->renderInfo.lookTargetClearTime < level.time //NOTE: here this is used as a debounce, not an actual timer + && ent->health > 0 //must be alive + && (!ent->enemy || ent->client->ps.saberMove != LS_A_BACKSTAB) )//don't update if in backstab unless don't currently have an enemy {//NOTE: doesn't keep updating to nearest enemy once you're dead int newLookTarget; if ( !G_ValidateLookEnemy( ent, ent->enemy ) ) @@ -2039,9 +2167,11 @@ extern cvar_t *g_skippingcin; } if ( player && player->client && player->client->ps.viewEntity == ent->s.number ) { + controlledByPlayer = qtrue; int sav_weapon = ucmd->weapon; memcpy( ucmd, &player->client->usercmd, sizeof( usercmd_t ) ); ucmd->weapon = sav_weapon; + ent->client->usercmd = *ucmd; } G_NPCMunroMatchPlayerWeapon( ent ); } @@ -2149,6 +2279,7 @@ extern cvar_t *g_skippingcin; } else {//a corpse? Shit + //Hmm, corpses should probably *always* knockdown... ent->clipmask &= ~CONTENTS_BODY; } //FIXME: need impact sound event @@ -2157,7 +2288,11 @@ extern cvar_t *g_skippingcin; {//can't knock down desann unless you're luke //FIXME: should he smack you away like Galak Mech? } - else if ( ((groundEnt->s.number||(!Q_irand( 0, 3 )&&cg.renderingThirdPerson&&!cg.zoomMode))&&groundEnt->client->playerTeam != ent->client->playerTeam) || ent->client->NPC_class == CLASS_DESANN ) + else if ( + ( ( (groundEnt->s.number&&(groundEnt->s.weapon!=WP_SABER||!groundEnt->NPC||groundEnt->NPC->ranks.number||G_ControlledByPlayer(groundEnt)) && !Q_irand( 0, 3 )&&cg.renderingThirdPerson&&!cg.zoomMode) )//or a player in third person, 25% of the time + && groundEnt->client->playerTeam != ent->client->playerTeam ) //and not on the same team + || ent->client->NPC_class == CLASS_DESANN )//desann always knocks people down { int knockAnim = BOTH_KNOCKDOWN1; if ( PM_CrouchAnim( groundEnt->client->ps.legsAnim ) ) @@ -2254,7 +2389,7 @@ extern cvar_t *g_skippingcin; ent->NPC->desiredSpeed = NPC_GetRunSpeed( ent );//ent->NPC->stats.runSpeed; } - if ( ent->NPC->currentSpeed >= 80 ) + if ( ent->NPC->currentSpeed >= 80 && !controlledByPlayer ) {//At higher speeds, need to slow down close to stuff //Slow down as you approach your goal // if ( ent->NPC->distToGoal < SLOWDOWN_DIST && client->race != RACE_BORG && !(ent->NPC->aiFlags&NPCAI_NO_SLOWDOWN) )//128 @@ -2441,10 +2576,18 @@ extern cvar_t *g_skippingcin; client->ps.speed *= 0.45f; break; } + if ( g_saberMoveSpeed->value != 1.0f ) + { + client->ps.speed *= g_saberMoveSpeed->value; + } } else if ( PM_SpinningSaberAnim( client->ps.legsAnim ) ) { client->ps.speed *= 0.5f; + if ( g_saberMoveSpeed->value != 1.0f ) + { + client->ps.speed *= g_saberMoveSpeed->value; + } } else if ( client->ps.weapon == WP_SABER && ( ucmd->buttons & BUTTON_ATTACK ) ) {//if attacking with saber while running, drop your speed @@ -2458,6 +2601,10 @@ extern cvar_t *g_skippingcin; client->ps.speed *= 0.70f; break; } + if ( g_saberMoveSpeed->value != 1.0f ) + { + client->ps.speed *= g_saberMoveSpeed->value; + } } } } @@ -2514,7 +2661,7 @@ extern cvar_t *g_skippingcin; G_CheckClampUcmd( ent, ucmd ); - if ( ucmd->buttons&BUTTON_BLOCKING ) + if ( (ucmd->buttons&BUTTON_BLOCKING) && !g_saberAutoBlocking->integer ) {//blocking with saber ent->client->ps.saberBlockingTime = level.time + FRAMETIME; } @@ -2547,6 +2694,37 @@ extern cvar_t *g_skippingcin; { cg.overrides.active |= (CG_OVERRIDE_3RD_PERSON_RNG|CG_OVERRIDE_3RD_PERSON_POF|CG_OVERRIDE_3RD_PERSON_VOF); cg.overrides.thirdPersonRange = 240; + if ( cg_thirdPersonAutoAlpha.integer ) + { + if ( ent->health > 0 && ent->client->ps.viewangles[PITCH] < 15 && ent->client->ps.viewangles[PITCH] > 0 ) + { + cg.overrides.active |= CG_OVERRIDE_3RD_PERSON_APH; + if ( cg.overrides.thirdPersonAlpha > 0.525f ) + { + cg.overrides.thirdPersonAlpha -= 0.025f; + } + else if ( cg.overrides.thirdPersonAlpha > 0.5f ) + { + cg.overrides.thirdPersonAlpha = 0.5f; + } + } + else if ( cg.overrides.active&CG_OVERRIDE_3RD_PERSON_APH ) + { + if ( cg.overrides.thirdPersonAlpha > cg_thirdPersonAlpha.value ) + { + cg.overrides.active &= ~CG_OVERRIDE_3RD_PERSON_APH; + } + else if ( cg.overrides.thirdPersonAlpha < cg_thirdPersonAlpha.value-0.1f ) + { + cg.overrides.thirdPersonAlpha += 0.1f; + } + else if ( cg.overrides.thirdPersonAlpha < cg_thirdPersonAlpha.value ) + { + cg.overrides.thirdPersonAlpha = cg_thirdPersonAlpha.value; + cg.overrides.active &= ~CG_OVERRIDE_3RD_PERSON_APH; + } + } + } if ( ent->client->ps.viewangles[PITCH] > 0 ) { cg.overrides.thirdPersonPitchOffset = ent->client->ps.viewangles[PITCH]*-0.75; @@ -2680,36 +2858,38 @@ extern cvar_t *g_skippingcin; // pressing attack or use is the normal respawn method if ( ucmd->buttons & ( BUTTON_ATTACK ) ) { - if (!cg.missionStatusShow) // Has Mission Status screen shown yet? - { - cg.missionStatusShowTime = level.time + 1000; - cg.missionStatusShow = 1; - } - else if (cg.missionStatusShowTime < level.time) - { - respawn( ent ); - } + respawn( ent ); // gi.SendConsoleCommand( va("disconnect;wait;wait;wait;wait;wait;wait;devmap %s\n",level.mapname) ); } } - if ( ent && !ent->s.number && ent->enemy ) + if ( ent + && !ent->s.number + && ent->enemy + && ent->enemy != ent + && ent->enemy->s.number < ENTITYNUM_WORLD + && ent->enemy->inuse + && !(cg.overrides.active&CG_OVERRIDE_3RD_PERSON_ANG) ) {//keep facing enemy vec3_t deadDir; + float deadYaw; VectorSubtract( ent->enemy->currentOrigin, ent->currentOrigin, deadDir ); - ent->client->ps.stats[STAT_DEAD_YAW] = vectoyaw ( deadDir ); + deadYaw = AngleNormalize180( vectoyaw ( deadDir ) ); + if ( deadYaw > ent->client->ps.stats[STAT_DEAD_YAW] + 1 ) + { + ent->client->ps.stats[STAT_DEAD_YAW]++; + } + else if ( deadYaw < ent->client->ps.stats[STAT_DEAD_YAW] - 1 ) + { + ent->client->ps.stats[STAT_DEAD_YAW]--; + } + else + { + ent->client->ps.stats[STAT_DEAD_YAW] = deadYaw; + } } return; } - if ((cg.missionStatusShow) && ((cg.missionStatusDeadTime + 1) < level.time)) - { - if ( ucmd->buttons & ( BUTTON_ATTACK ) ) - { -// cg.missionStatusShow = 0; -// ScoreBoardReset(); -// Q3_TaskIDComplete( ent, TID_MISSIONSTATUS ); - } - } // perform once-a-second actions ClientTimerActions( ent, msec ); @@ -2736,6 +2916,7 @@ A new command has arrived from the client ================== */ extern void PM_CheckForceUseButton( gentity_t *ent, usercmd_t *ucmd ); +extern qboolean PM_GentCantJump( gentity_t *gent ); void ClientThink( int clientNum, usercmd_t *ucmd ) { gentity_t *ent; qboolean restore_ucmd = qfalse; @@ -2743,50 +2924,93 @@ void ClientThink( int clientNum, usercmd_t *ucmd ) { ent = g_entities + clientNum; - if ( ent->client->ps.viewEntity > 0 && ent->client->ps.viewEntity < ENTITYNUM_WORLD ) - {//you're controlling another NPC - if ( ucmd->upmove > 0 )//if ( (ucmd->buttons&BUTTON_BLOCKING) ) - {//jumping gets you out of it FIXME: check some other button instead... like ESCAPE... so you could even have total control over an NPC? - G_ClearViewEntity( ent ); - ucmd->upmove = 0;//ucmd->buttons = 0; + if ( !ent->s.number ) + { + if ( ent->client->ps.viewEntity > 0 && ent->client->ps.viewEntity < ENTITYNUM_WORLD ) + {//you're controlling another NPC + gentity_t *controlled = &g_entities[ent->client->ps.viewEntity]; + qboolean freed = qfalse; + if ( controlled->NPC + && controlled->NPC->controlledTime + && ent->client->ps.forcePowerLevel[FP_TELEPATHY] > FORCE_LEVEL_3 ) + {//An NPC I'm controlling with mind trick + if ( controlled->NPC->controlledTime < level.time ) + {//time's up! + G_ClearViewEntity( ent ); + freed = qtrue; + } + } + else if ( controlled->NPC //an NPC + && PM_GentCantJump( controlled ) //that cannot jump + && controlled->NPC->stats.moveType != MT_FLYSWIM ) //and does not use upmove to fly + {//these types use jump to get out + if ( ucmd->upmove > 0 ) + {//jumping gets you out of it FIXME: check some other button instead... like ESCAPE... so you could even have total control over an NPC? + G_ClearViewEntity( ent ); + ucmd->upmove = 0;//ucmd->buttons = 0; + //stop player from doing anything for a half second after + ent->aimDebounceTime = level.time + 500; + freed = qtrue; + } + } + else + {//others use the blocking key, button3 + if ( (ucmd->buttons&BUTTON_BLOCKING) ) + {//jumping gets you out of it FIXME: check some other button instead... like ESCAPE... so you could even have total control over an NPC? + G_ClearViewEntity( ent ); + ucmd->buttons = 0; + freed = qtrue; + } + } + if ( !freed ) + {//still controlling, save off my ucmd and clear it for my actual run through pmove + restore_ucmd = qtrue; + memcpy( &sav_ucmd, ucmd, sizeof( usercmd_t ) ); + memset( ucmd, 0, sizeof( usercmd_t ) ); + //to keep pointing in same dir, need to set ucmd->angles + ucmd->angles[PITCH] = ANGLE2SHORT( ent->client->ps.viewangles[PITCH] ) - ent->client->ps.delta_angles[PITCH]; + ucmd->angles[YAW] = ANGLE2SHORT( ent->client->ps.viewangles[YAW] ) - ent->client->ps.delta_angles[YAW]; + ucmd->angles[ROLL] = 0; + } + else + { + ucmd->angles[PITCH] = ANGLE2SHORT( ent->client->ps.viewangles[PITCH] ) - ent->client->ps.delta_angles[PITCH]; + ucmd->angles[YAW] = ANGLE2SHORT( ent->client->ps.viewangles[YAW] ) - ent->client->ps.delta_angles[YAW]; + ucmd->angles[ROLL] = 0; + } } - else + else if ( ent->client->NPC_class == CLASS_ATST ) { - restore_ucmd = qtrue; - memcpy( &sav_ucmd, ucmd, sizeof( usercmd_t ) ); - memset( ucmd, 0, sizeof( usercmd_t ) ); - //to keep pointing in same dir, need to set ucmd->angles - ucmd->angles[PITCH] = ucmd->angles[ROLL] = 0; - ucmd->angles[YAW] = ANGLE2SHORT( ent->client->ps.viewangles[YAW] ) - ent->client->ps.delta_angles[YAW]; + if ( ucmd->upmove > 0 ) + {//get out of ATST + GEntity_UseFunc( ent->activator, ent, ent ); + ucmd->upmove = 0;//ucmd->buttons = 0; + } } - } - else if ( ent->client->NPC_class == CLASS_ATST ) - { - if ( ucmd->upmove > 0 )//if ( (ucmd->buttons&BUTTON_BLOCKING) ) - {//get out of ATST - GEntity_UseFunc( ent->activator, ent, ent ); - ucmd->upmove = 0;//ucmd->buttons = 0; + + if ( (ucmd->buttons&BUTTON_BLOCKING) && !g_saberAutoBlocking->integer ) + { + ucmd->buttons &= ~(BUTTON_ATTACK|BUTTON_ALT_ATTACK); } + PM_CheckForceUseButton( ent, ucmd ); } - - if ( (ucmd->buttons&BUTTON_BLOCKING) ) - { - ucmd->buttons &= ~(BUTTON_ATTACK|BUTTON_ALT_ATTACK); - } - PM_CheckForceUseButton( ent, ucmd ); - ent->client->usercmd = *ucmd; // if ( !g_syncronousClients->integer ) { ClientThink_real( ent, ucmd ); } - - if ( restore_ucmd ) + // ClientThink_real can end up freeing this ent, need to check + if ( restore_ucmd && ent->client ) {//restore ucmd for later so NPC you're controlling can refer to them memcpy( &ent->client->usercmd, &sav_ucmd, sizeof( usercmd_t ) ); } + + if ( ent->s.number ) + {//NPCs drown, burn from lava, etc, also + P_WorldEffects( ent ); + } } void ClientEndPowerUps( gentity_t *ent ) diff --git a/code/game/g_breakable.cpp b/code/game/g_breakable.cpp index 2e40ba5..7c00aac 100644 --- a/code/game/g_breakable.cpp +++ b/code/game/g_breakable.cpp @@ -47,6 +47,7 @@ static void CacheChunkEffects( material_t material ) case MAT_DRK_STONE: case MAT_LT_STONE: case MAT_GREY_STONE: + case MAT_WHITE_METAL: // what is this crap really supposed to be?? G_EffectIndex( "chunks/rockbreaklg" ); G_EffectIndex( "chunks/rockbreakmed" ); break; @@ -193,19 +194,44 @@ void funcBBrushUse (gentity_t *self, gentity_t *other, gentity_t *activator) void funcBBrushPain(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, vec3_t point, int damage, int mod,int hitLoc) { - if(self->painDebounceTime > level.time) + if ( self->painDebounceTime > level.time ) { return; } - if(self->paintarget) + if ( self->paintarget ) { G_UseTargets2 (self, self->activator, self->paintarget); } G_ActivateBehavior( self, BSET_PAIN ); - if(self->wait == -1) + if ( self->material == MAT_DRK_STONE + || self->material == MAT_LT_STONE + || self->material == MAT_GREY_STONE ) + { + vec3_t org, dir; + float scale; + VectorSubtract( self->absmax, self->absmin, org );// size + // This formula really has no logical basis other than the fact that it seemed to be the closest to yielding the results that I wanted. + // Volume is length * width * height...then break that volume down based on how many chunks we have + scale = VectorLength( org ) / 100.0f; + VectorMA( self->absmin, 0.5, org, org ); + VectorAdd( self->absmin,self->absmax, org ); + VectorScale( org, 0.5f, org ); + if ( attacker != NULL && attacker->client ) + { + VectorSubtract( attacker->currentOrigin, org, dir ); + VectorNormalize( dir ); + } + else + { + VectorSet( dir, 0, 0, 1 ); + } + CG_Chunks( self->s.number, org, dir, self->mins, self->maxs, 300, Q_irand( 1, 3 ), self->material, 0, scale ); + } + + if ( self->wait == -1 ) { self->e_PainFunc = painF_NULL; return; @@ -328,6 +354,7 @@ Don't know if these work: 12 = MAT_GRATE1 (grate chunks--looks horrible right now) 13 = MAT_ROPE (for yavin_trial, no chunks, just wispy bits ) 14 = MAT_CRATE2 (red multi-colored crate chunks) +15 = MAT_WHITE_METAL (white angular chunks for Stu, NS_hideout ) */ void SP_func_breakable( gentity_t *self ) @@ -361,7 +388,7 @@ void SP_func_breakable( gentity_t *self ) self->e_UseFunc = useF_funcBBrushUse; - if(self->paintarget) + //if ( self->paintarget ) { self->e_PainFunc = painF_funcBBrushPain; } @@ -831,7 +858,7 @@ Damage: default is none 12 = MAT_GRATE1 (grate chunks--looks horrible right now) 13 = MAT_ROPE (for yavin_trial, no chunks, just wispy bits ) 14 = MAT_CRATE2 (red multi-colored crate chunks) - +15 = MAT_WHITE_METAL (white angular chunks for Stu, NS_hideout ) FIXME/TODO: set size better? multiple damage models? diff --git a/code/game/g_client.cpp b/code/game/g_client.cpp index 71bbd05..9545e3b 100644 --- a/code/game/g_client.cpp +++ b/code/game/g_client.cpp @@ -12,6 +12,7 @@ extern void Q3_DebugPrint( int level, const char *format, ... ); extern void WP_SaberInitBladeData( gentity_t *ent ); extern void G_CreateG2AttachedWeaponModel( gentity_t *ent, const char *weaponModel ); extern qboolean CheatsOk( gentity_t *ent ); +extern vmCvar_t cg_thirdPersonAlpha; // g_client.c -- client functions that don't happen every frame @@ -493,7 +494,6 @@ char *ClientConnect( int clientNum, qboolean firstTime, SavedGameJustLoaded_e eS char userinfo[MAX_INFO_STRING]; gentity_t *ent; clientSession_t savedSess; - clientTourSession_t savedTourSess; ent = &g_entities[ clientNum ]; gi.GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); @@ -507,11 +507,8 @@ char *ClientConnect( int clientNum, qboolean firstTime, SavedGameJustLoaded_e eS if (eSavedGameJustLoaded != eFULL) { savedSess = client->sess; // - savedTourSess = client->tourSess; memset( client, 0, sizeof(*client) ); client->sess = savedSess; - client->tourSess = savedTourSess; - } client->pers.connected = CON_CONNECTING; @@ -582,12 +579,15 @@ void ClientBegin( int clientNum, usercmd_t *cmd, SavedGameJustLoaded_e eSavedGam memset( &client->ps, 0, sizeof( client->ps ) ); memset( &client->sess.missionStats, 0, sizeof( client->sess.missionStats ) ); - + client->sess.missionStats.totalSecrets = gi.Cvar_VariableIntegerValue("newTotalSecrets"); + // locate ent at a spawn point if ( ClientSpawn( ent, eSavedGameJustLoaded) ) // SavedGameJustLoaded_e { // send teleport event } + client->ps.inventory[INV_GOODIE_KEY] = 0; + client->ps.inventory[INV_SECURITY_KEY] = 0; } } @@ -630,7 +630,7 @@ extern gitem_t *FindItemForInventory( int inv ); for ( i = 1 ; i < 16 ; i++ ) { - if ( bits & ( 1 << i ) ) + if ( ibits & ( 1 << i ) ) { RegisterItem( FindItemForInventory( i-1 )); } @@ -655,21 +655,29 @@ void Player_RestoreFromPrevLevel(gentity_t *ent) if (client) // though I can't see it not being true... { char s[MAX_STRING_CHARS]; + const char *var; gi.Cvar_VariableStringBuffer( sCVARNAME_PLAYERSAVE, s, sizeof(s) ); if (strlen(s)) // actually this would be safe anyway because of the way sscanf() works, but this is clearer { - sscanf( s, "%i %i %i %i %i %i %f %f %f", + sscanf( s, "%i %i %i %i %i %i %i %f %f %f %i %i %i %i %i %i", &client->ps.stats[STAT_HEALTH], &client->ps.stats[STAT_ARMOR], &client->ps.stats[STAT_WEAPONS], &client->ps.stats[STAT_ITEMS], &client->ps.weapon, &client->ps.weaponstate, + &client->ps.batteryCharge, &client->ps.viewangles[0], &client->ps.viewangles[1], - &client->ps.viewangles[2] + &client->ps.viewangles[2], + &client->ps.forcePowersKnown, + &client->ps.forcePower, + &client->ps.saberActive, + &client->ps.saberAnimLevel, + &client->ps.saberLockEnemy, + &client->ps.saberLockTime ); ent->health = client->ps.stats[STAT_HEALTH]; @@ -680,43 +688,46 @@ void Player_RestoreFromPrevLevel(gentity_t *ent) // // SetClientViewAngle( ent, ent->client->ps.viewangles); - for ( i = 0; i < AMMO_MAX; i++ ) + //ammo + gi.Cvar_VariableStringBuffer( "playerammo", s, sizeof(s) ); + i=0; + var = strtok( s, " " ); + while( var != NULL ) { - gi.Cvar_VariableStringBuffer( va("playerammo%d",i), s, sizeof(s) ); - sscanf( s,"%i",&client->ps.ammo[i]); + /* While there are tokens in "s" */ + client->ps.ammo[i++] = atoi(var); + /* Get next token: */ + var = strtok( NULL, " " ); } + assert (i==AMMO_MAX); - for ( i = 0; i < INV_MAX; i++ ) + //inventory + gi.Cvar_VariableStringBuffer( "playerinv", s, sizeof(s) ); + i=0; + var = strtok( s, " " ); + while( var != NULL ) { - gi.Cvar_VariableStringBuffer( va("playerinv%d",i), s, sizeof(s) ); - sscanf( s,"%i",&client->ps.inventory[i]); + /* While there are tokens in "s" */ + client->ps.inventory[i++] = atoi(var); + /* Get next token: */ + var = strtok( NULL, " " ); } + assert (i==INV_MAX); + // the new JK2 stuff - force powers, etc... // - for ( i=0; ips.forcePowerLevel[i]); + /* While there are tokens in "s" */ + client->ps.forcePowerLevel[i++] = atoi(var); + /* Get next token: */ + var = strtok( NULL, " " ); } - - gi.Cvar_VariableStringBuffer( "playerfpknown", s, sizeof(s) ); - sscanf( s, "%i", &client->ps.forcePowersKnown); - - gi.Cvar_VariableStringBuffer( "playerfp", s, sizeof(s) ); - sscanf( s, "%i", &client->ps.forcePower); - - gi.Cvar_VariableStringBuffer( "plsa", s, sizeof(s) ); - sscanf( s, "%i", &client->ps.saberActive); - - gi.Cvar_VariableStringBuffer( "plcs", s, sizeof(s) ); - sscanf( s, "%i", &client->ps.saberAnimLevel); - - gi.Cvar_VariableStringBuffer( "plle", s, sizeof(s) ); - sscanf( s, "%i", &client->ps.saberLockEnemy); - - gi.Cvar_VariableStringBuffer( "pllt", s, sizeof(s) ); - sscanf( s, "%i", &client->ps.saberLockTime); + assert (i==NUM_FORCE_POWERS); client->ps.forcePowerMax = FORCE_POWER_MAX; client->ps.forceGripEntityNum = ENTITYNUM_NONE; @@ -752,35 +763,39 @@ void G_SetSkin( gentity_t *ent, const char *modelName, const char *customSkin ) qboolean G_StandardHumanoid( const char *modelName ) { - if ( !Q_strncmp( "gran", modelName, 4 ) || - !Q_strncmp( "reborn", modelName, 6 ) || - !Q_strncmp( "imp", modelName, 3 ) || - !Q_strncmp( "rodian", modelName, 6 ) || + if ( !modelName ) + { + return qfalse; + } + if ( !Q_stricmp( "kyle", modelName ) || !Q_strncmp( "st", modelName, 2 ) || - !Q_stricmp( "swamptrooper", modelName ) || + !Q_strncmp( "imp", modelName, 3 ) || + !Q_strncmp( "gran", modelName, 4 ) || + !Q_strncmp( "rodian", modelName, 6 ) || + !Q_strncmp( "weequay", modelName, 7 ) || + !Q_strncmp( "reborn", modelName, 6 ) || + !Q_strncmp( "shadowtrooper", modelName, 13 ) || + !Q_strncmp( "swamptrooper", modelName, 12 ) || !Q_stricmp( "rockettrooper", modelName ) || - !Q_stricmp( "shadowtrooper", modelName ) || !Q_stricmp( "bespin_cop", modelName ) || - !Q_stricmp( "shadowtrooper", modelName ) || + !Q_strncmp( "bespincop", modelName, 9 ) || + !Q_strncmp( "rebel", modelName, 5 ) || + !Q_strncmp( "ugnaught", modelName, 8 ) || + !Q_strncmp( "morgan", modelName,6 ) || + !Q_strncmp( "protocol", modelName, 8 ) || + !Q_strncmp( "jedi", modelName, 4 ) || + !Q_strncmp( "prisoner", modelName, 8 ) || !Q_stricmp( "tavion", modelName ) || !Q_stricmp( "desann", modelName ) || - !Q_stricmp( "weequay", modelName ) || !Q_stricmp( "trandoshan", modelName ) || - !Q_stricmp( "kyle", modelName ) || !Q_stricmp( "jan", modelName ) || !Q_stricmp( "luke", modelName ) || !Q_stricmp( "lando", modelName ) || - !Q_stricmp( "rebel", modelName ) || !Q_stricmp( "reelo", modelName ) || !Q_stricmp( "bartender", modelName ) || - !Q_stricmp( "ugnaught", modelName ) || !Q_stricmp( "monmothma", modelName ) || !Q_stricmp( "chiss", modelName ) || - !Q_strncmp( "morgan", modelName,6 ) || - !Q_strncmp( "protocol", modelName,8 ) || - !Q_stricmp( "galak", modelName ) || - !Q_strncmp( "jedi", modelName, 4 ) || - !Q_strncmp( "prisoner", modelName, 8 ) ) + !Q_stricmp( "galak", modelName ) ) { return qtrue; } @@ -876,13 +891,15 @@ qboolean G_SetG2PlayerModelInfo( gentity_t *ent, const char *modelName, const ch } else if (!Q_strncmp( "probe",modelName, 5)) { - ent->headBolt = -1; + ent->headBolt = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "cranium"); // head pivot point ent->genericBolt1 = gi.G2API_AddBolt(&ent->ghoul2[ent->playerModel], "*flash"); // Gun 1 } + /* else if (!Q_strncmp( "protocol",modelName, 8)) { ent->headBolt = -1; } + */ else if (!Q_stricmp( "sentry",modelName)) { ent->headBolt = -1; @@ -988,9 +1005,11 @@ qboolean G_SetG2PlayerModelInfo( gentity_t *ent, const char *modelName, const ch gi.G2API_SetBoneAnglesIndex( &ent->ghoul2[ent->playerModel], ent->thoracicBone, angles, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL ); } } + /* else if (!Q_strncmp( "protocol",modelName,8)) { } + */ else if (!Q_stricmp( "interrogator", modelName )) { ent->genericBone1 = gi.G2API_GetBoneIndex( &ent->ghoul2[ent->playerModel], "left_arm", qtrue ); @@ -1284,8 +1303,8 @@ void G_PilotXWing( gentity_t *ent ) ent->svFlags &= ~SVF_CUSTOM_GRAVITY; ent->client->ps.stats[STAT_ARMOR] = 0;//HACK //ent->mass = 10; - gi.cvar_set( "m_pitchOverride", "0" ); - gi.cvar_set( "m_yawOverride", "0" ); + //gi.cvar_set( "m_pitchOverride", "0" ); + //gi.cvar_set( "m_yawOverride", "0" ); if ( ent->client->ps.weapon != WP_SABER ) { gi.cvar_set( "cg_thirdperson", "0" ); @@ -1311,8 +1330,8 @@ void G_PilotXWing( gentity_t *ent ) ent->client->ps.stats[STAT_ARMOR] = 200;//FIXME: define? //ent->mass = 300; ent->client->ps.speed = 0; - gi.cvar_set( "m_pitchOverride", "0.01" );//ignore inverse mouse look - gi.cvar_set( "m_yawOverride", "0.0075" ); + //gi.cvar_set( "m_pitchOverride", "0.01" );//ignore inverse mouse look + //gi.cvar_set( "m_yawOverride", "0.0075" ); gi.cvar_set( "cg_thirdperson", "1" ); cg.overrides.active |= (CG_OVERRIDE_3RD_PERSON_RNG|CG_OVERRIDE_FOV); cg.overrides.thirdPersonRange = 240; @@ -1324,9 +1343,6 @@ void G_PilotXWing( gentity_t *ent ) //HACK FOR ATST void G_DrivableATSTDie( gentity_t *self ) { - //restore mouse control - gi.cvar_set( "m_pitchOverride", "0" ); - gi.cvar_set( "m_yawOverride", "0" ); } void G_DriveATST( gentity_t *ent, gentity_t *atst ) @@ -1334,7 +1350,7 @@ void G_DriveATST( gentity_t *ent, gentity_t *atst ) if ( ent->NPC_type && ent->client && (ent->client->NPC_class == CLASS_ATST) ) {//already an atst, switch back //open hatch - if ( ent->playerModel != -1 ) + if ( ent->playerModel >= 0 ) { gi.G2API_RemoveGhoul2Model( ent->ghoul2, ent->playerModel ); } @@ -1353,16 +1369,14 @@ void G_DriveATST( gentity_t *ent, gentity_t *atst ) ent->client->ps.ammo[weaponData[WP_ATST_MAIN].ammoIndex] = 0; ent->client->ps.ammo[weaponData[WP_ATST_SIDE].ammoIndex] = 0; CG_ChangeWeapon( WP_BRYAR_PISTOL ); - //mouse control - gi.cvar_set( "m_pitchOverride", "0" ); - gi.cvar_set( "m_yawOverride", "0" ); //camera //if ( ent->client->ps.weapon != WP_SABER ) { gi.cvar_set( "cg_thirdperson", "0" ); } - cg.overrides.active &= ~(CG_OVERRIDE_3RD_PERSON_RNG|CG_OVERRIDE_3RD_PERSON_VOF|CG_OVERRIDE_3RD_PERSON_POF); + cg.overrides.active &= ~(CG_OVERRIDE_3RD_PERSON_RNG|CG_OVERRIDE_3RD_PERSON_VOF|CG_OVERRIDE_3RD_PERSON_POF|CG_OVERRIDE_3RD_PERSON_APH); cg.overrides.thirdPersonRange = cg.overrides.thirdPersonVertOffset = cg.overrides.thirdPersonPitchOffset = 0; + cg.overrides.thirdPersonAlpha = cg_thirdPersonAlpha.value; ent->client->ps.viewheight = ent->maxs[2] + STANDARD_VIEWHEIGHT_OFFSET; //ent->mass = 10; } @@ -1377,12 +1391,12 @@ void G_DriveATST( gentity_t *ent, gentity_t *atst ) VectorSet( ent->maxs, ATST_MAXS0, ATST_MAXS1, ATST_MAXS2 ); ent->client->crouchheight = ATST_MAXS2; ent->client->standheight = ATST_MAXS2; - if ( ent->playerModel != -1 ) + if ( ent->playerModel >= 0 ) { gi.G2API_RemoveGhoul2Model( ent->ghoul2, ent->playerModel ); ent->playerModel = -1; } - if ( ent->weaponModel != -1 ) + if ( ent->weaponModel >= 0 ) { gi.G2API_RemoveGhoul2Model( ent->ghoul2, ent->weaponModel ); ent->weaponModel = -1; @@ -1399,6 +1413,7 @@ void G_DriveATST( gentity_t *ent, gentity_t *atst ) G_SetG2PlayerModelInfo( ent, "atst", NULL, NULL, NULL ); //turn off hatch underside gi.G2API_SetSurfaceOnOff( &ent->ghoul2[ent->playerModel], "head_hatchcover_off", 0x00000002/*G2SURFACEFLAG_OFF*/ ); + G_Sound( ent, G_SoundIndex( "sound/chars/atst/atst_hatch_close" )); } ent->s.radius = 320; //weapon @@ -1423,10 +1438,7 @@ void G_DriveATST( gentity_t *ent, gentity_t *atst ) CG_RegisterItemSounds( (item-bg_itemlist) ); CG_RegisterItemVisuals( (item-bg_itemlist) ); //HACKHACKHACKTEMP - //mouse control //FIXME: these get lost in load/save! Must use variables that are set every frame or saved/loaded - gi.cvar_set( "m_pitchOverride", "0.01" );//ignore inverse mouse look - gi.cvar_set( "m_yawOverride", "0.0075" ); //camera gi.cvar_set( "cg_thirdperson", "1" ); cg.overrides.active |= CG_OVERRIDE_3RD_PERSON_RNG; @@ -1464,7 +1476,6 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded int i; clientPersistant_t saved; clientSession_t savedSess; - clientTourSession_t savedTourSess; clientInfo_t savedCi; int persistant[MAX_PERSISTANT]; usercmd_t ucmd; @@ -1525,7 +1536,6 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded // clear everything but the persistant data saved = client->pers; savedSess = client->sess; - savedTourSess = client->tourSess; for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { persistant[i] = client->ps.persistant[i]; @@ -1539,7 +1549,6 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded client->pers = saved; client->sess = savedSess; - client->tourSess = savedTourSess; for ( i = 0 ; i < MAX_PERSISTANT ; i++ ) { client->ps.persistant[i] = persistant[i]; @@ -1614,13 +1623,13 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded // ent->health = client->ps.stats[STAT_HEALTH] = client->ps.stats[STAT_MAX_HEALTH]; - ent->client->dismemberProbHead = 1; + ent->client->dismemberProbHead = 0; ent->client->dismemberProbArms = 5; ent->client->dismemberProbHands = 20; - ent->client->dismemberProbWaist = 1; - ent->client->dismemberProbLegs = 1; + ent->client->dismemberProbWaist = 0; + ent->client->dismemberProbLegs = 0; - ent->client->ps.batteryCharge = 200; // starts out with a small battery charge + ent->client->ps.batteryCharge = 2500; VectorCopy( spawn_origin, client->ps.origin ); VectorCopy( spawn_origin, ent->currentOrigin ); @@ -1749,6 +1758,11 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded client->pers.enterTime = level.time;//needed mainly to stop the weapon switch to WP_NONE that happens on loads ent->max_health = client->ps.stats[STAT_MAX_HEALTH]; + if ( eSavedGameJustLoaded == eNO ) + {//on map transitions, Ghoul2 frame gets reset to zero, restart our anim + NPC_SetAnim( ent, SETANIM_LEGS, ent->client->ps.legsAnim, SETANIM_FLAG_NORMAL|SETANIM_FLAG_RESTART ); + NPC_SetAnim( ent, SETANIM_TORSO, ent->client->ps.torsoAnim, SETANIM_FLAG_NORMAL|SETANIM_FLAG_RESTART ); + } return beamInEffect; } diff --git a/code/game/g_cmds.cpp b/code/game/g_cmds.cpp index 7244bd8..fe8d97a 100644 --- a/code/game/g_cmds.cpp +++ b/code/game/g_cmds.cpp @@ -20,6 +20,7 @@ extern void G_PilotXWing( gentity_t *ent ); extern void G_DriveATST( gentity_t *ent, gentity_t *atst ); extern void G_StartMatrixEffect( gentity_t *ent, qboolean falling = qfalse, int length = 1000 ); extern void ItemUse_Bacta(gentity_t *ent); +extern gentity_t *G_GetSelfForPlayerCmd( void ); /* ================== @@ -203,16 +204,8 @@ void Cmd_Give_f (gentity_t *ent) ent->client->ps.inventory[INV_SEEKER] = 5; ent->client->ps.inventory[INV_LIGHTAMP_GOGGLES] = 1; ent->client->ps.inventory[INV_SENTRY] = 5; - ent->client->ps.inventory[INV_GOODIE_KEY1] = 1; - ent->client->ps.inventory[INV_GOODIE_KEY2] = 1; - ent->client->ps.inventory[INV_GOODIE_KEY3] = 1; - ent->client->ps.inventory[INV_GOODIE_KEY4] = 1; - ent->client->ps.inventory[INV_GOODIE_KEY5] = 1; - ent->client->ps.inventory[INV_SECURITY_KEY1] = 1; - ent->client->ps.inventory[INV_SECURITY_KEY2] = 1; - ent->client->ps.inventory[INV_SECURITY_KEY3] = 1; - ent->client->ps.inventory[INV_SECURITY_KEY4] = 1; - ent->client->ps.inventory[INV_SECURITY_KEY5] = 1; + ent->client->ps.inventory[INV_GOODIE_KEY] = 5; + ent->client->ps.inventory[INV_SECURITY_KEY] = 5; if (!give_all) { @@ -592,7 +585,7 @@ Cmd_Kill_f */ void Cmd_Kill_f( gentity_t *ent ) { if( ( level.time - ent->client->respawnTime ) < 5000 ) { - gi.SendServerCommand( ent-g_entities, "cp \"Only one kill every five seconds\n\""); + gi.SendServerCommand( ent-g_entities, "cp @INGAME_ONE_KILL_PER_5_SECONDS"); return; } ent->flags &= ~FL_GODMODE; @@ -804,6 +797,67 @@ void Cmd_UseBacta_f(gentity_t *ent) ItemUse_Bacta(ent); } +//---------------------------------------------------------------------------------- +qboolean PickSeekerSpawnPoint( vec3_t org, vec3_t fwd, vec3_t right, int skip, vec3_t spot ) +{ + vec3_t mins, maxs, forward, end; + trace_t tr; + + VectorSet( maxs, -8, -8, -24); // ?? size + VectorSet( maxs, 8, 8, 8 ); + + VectorCopy( fwd, forward ); + + // to the front and side a bit + forward[2] = 0.3f; // start up a bit + + VectorMA( org, 48, forward, end ); + VectorMA( end, -8, right, end ); + + gi.trace( &tr, org, mins, maxs, end, skip, MASK_PLAYERSOLID ); + + if ( !tr.startsolid && !tr.allsolid && tr.fraction >= 1.0f ) + { + VectorCopy( tr.endpos, spot ); + return qtrue; + } + + // side + VectorMA( org, 48, right, end ); + + gi.trace( &tr, org, mins, maxs, end, skip, MASK_PLAYERSOLID ); + + if ( !tr.startsolid && !tr.allsolid && tr.fraction >= 1.0f ) + { + VectorCopy( tr.endpos, spot ); + return qtrue; + } + + // other side + VectorMA( org, -48, right, end ); + + gi.trace( &tr, org, mins, maxs, end, skip, MASK_PLAYERSOLID ); + + if ( !tr.startsolid && !tr.allsolid && tr.fraction >= 1.0f ) + { + VectorCopy( tr.endpos, spot ); + return qtrue; + } + + // behind + VectorMA( org, -48, fwd, end ); + + gi.trace( &tr, org, mins, maxs, end, skip, MASK_PLAYERSOLID ); + + if ( !tr.startsolid && !tr.allsolid && tr.fraction >= 1.0f ) + { + VectorCopy( tr.endpos, spot ); + return qtrue; + } + + return qfalse; +} + /* ================ Cmd_UseSeeker_f @@ -819,30 +873,32 @@ void Cmd_UseSeeker_f( gentity_t *ent ) // don't use them if we don't have any...also don't use them if one is already going if ( ent->client && ent->client->ps.inventory[INV_SEEKER] > 0 && level.time > ent->client->ps.powerups[PW_SEEKER] ) { - vec3_t fwd, right; gentity_t *tent = G_Spawn(); if ( tent ) { + vec3_t fwd, right, spot; + AngleVectors( ent->client->ps.viewangles, fwd, right, NULL ); - fwd[2] = 0.3f; // start up a bit - VectorMA( ent->currentOrigin, 48, fwd, tent->s.origin ); - VectorMA( tent->s.origin, -8, right, tent->s.origin ); + VectorCopy( ent->currentOrigin, spot ); // does nothing really, just initialize the goods... - G_SetOrigin( tent, tent->s.origin ); - G_SetAngles( tent, ent->currentAngles ); + if ( PickSeekerSpawnPoint( ent->currentOrigin, fwd, right, ent->s.number, spot )) + { + VectorCopy( spot, tent->s.origin ); + G_SetOrigin( tent, spot ); + G_SetAngles( tent, ent->currentAngles ); extern void SP_NPC_Droid_Seeker( gentity_t *ent ); -// tent->playerTeam = TEAM_PLAYER; -// tent->enemyTeam = TEAM_ENEMY; + SP_NPC_Droid_Seeker( tent ); + G_Sound( tent, G_SoundIndex( "sound/chars/seeker/misc/hiss" )); - SP_NPC_Droid_Seeker( tent ); + // make sure that we even have some + ent->client->ps.inventory[INV_SEEKER]--; + ent->client->ps.powerups[PW_SEEKER] = level.time + 1000;// can only drop one every second..maybe this is annoying? - // make sure that we even have some - ent->client->ps.inventory[INV_SEEKER]--; - ent->client->ps.powerups[PW_SEEKER] = level.time + 1000;// can only drop one every second..maybe this is annoying? + } } } } @@ -998,19 +1054,40 @@ void ClientCommand( int clientNum ) { else if (Q_stricmp (cmd, "viewobjective") == 0) Cmd_ViewObjective_f( ent ); else if (Q_stricmp (cmd, "force_throw") == 0) + { + ent = G_GetSelfForPlayerCmd(); ForceThrow( ent, qfalse ); + } else if (Q_stricmp (cmd, "force_pull") == 0) + { + ent = G_GetSelfForPlayerCmd(); ForceThrow( ent, qtrue ); + } else if (Q_stricmp (cmd, "force_speed") == 0) + { + ent = G_GetSelfForPlayerCmd(); ForceSpeed( ent ); + } else if (Q_stricmp (cmd, "force_heal") == 0) + { + ent = G_GetSelfForPlayerCmd(); ForceHeal( ent ); + } else if (Q_stricmp (cmd, "force_grip") == 0) + { + ent = G_GetSelfForPlayerCmd(); ForceGrip( ent ); + } else if (Q_stricmp (cmd, "force_distract") == 0) + { + ent = G_GetSelfForPlayerCmd(); ForceTelepathy( ent ); + } else if (Q_stricmp (cmd, "taunt") == 0) + { + ent = G_GetSelfForPlayerCmd(); G_Taunt( ent ); + } else if (Q_stricmp (cmd, "victory") == 0) G_Victory( ent ); // else if (Q_stricmp (cmd, "use_shield") == 0) // sounds like the design doc states that the shields will be a pickup and so the player never decides whether to use them or not. diff --git a/code/game/g_combat.cpp b/code/game/g_combat.cpp index 26ab7fa..f47c307 100644 --- a/code/game/g_combat.cpp +++ b/code/game/g_combat.cpp @@ -11,23 +11,24 @@ #include "g_functions.h" #include "anims.h" #include "objectives.h" -#include "..\cgame\cg_local.h" +#include "../cgame/cg_local.h" #include "g_icarus.h" #include "wp_saber.h" #include "Q3_Interface.h" +#include "../qcommon/stripPublic.h" extern cvar_t *g_debugDamage; extern qboolean stop_icarus; extern cvar_t *g_dismemberment; extern cvar_t *g_dismemberProbabilities; -extern cvar_t *g_realisticSaberDamage; +extern cvar_t *g_saberRealisticCombat; extern cvar_t *g_timescale; extern cvar_t *d_slowmodeath; extern gentity_t *player; gentity_t *g_lastClientDamaged; -int killPlayerTimer = 0; +extern int killPlayerTimer; extern void NPC_TempLookTarget ( gentity_t *self, int lookEntNum, int minLookTime, int maxLookTime ); extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); @@ -61,9 +62,11 @@ extern qboolean PM_SaberInStart( int move ); extern qboolean PM_SaberInReturn( int move ); extern int PM_AnimLength( int index, animNumber_t anim ); -qboolean G_CheckForLedge( gentity_t *self, vec3_t fallCheckDir ); +qboolean G_CheckForLedge( gentity_t *self, vec3_t fallCheckDir, float checkDist ); static int G_CheckSpecialDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hitLoc ); static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, int hitLoc ); +static void G_TrackWeaponUsage( gentity_t *self, gentity_t *inflictor, int add, int mod ); +static qboolean G_Dismemberable( gentity_t *self, int hitLoc ); extern gitem_t *FindItemForAmmo( ammo_t ammo ); /* ============ @@ -88,11 +91,11 @@ Toss the weapon and powerups for the killed player ================= */ extern gentity_t *WP_DropThermal( gentity_t *ent ); -extern void WP_SaberLose( gentity_t *self, vec3_t throwDir ); +extern qboolean WP_SaberLose( gentity_t *self, vec3_t throwDir ); gentity_t *TossClientItems( gentity_t *self ) { gentity_t *dropped = NULL; - gitem_t *item; + gitem_t *item = NULL; int weapon; if ( self->client->NPC_class == CLASS_SEEKER || self->client->NPC_class == CLASS_REMOTE ) @@ -105,24 +108,35 @@ gentity_t *TossClientItems( gentity_t *self ) weapon = self->s.weapon; if ( weapon == WP_SABER ) { - WP_SaberLose( self, NULL ); - if ( self->client->NPC_class == CLASS_SHADOWTROOPER ) - {//drop a force crystal - item = FindItemForAmmo( AMMO_FORCE ); - Drop_Item( self, item, 0, qtrue ); + if ( self->weaponModel < 0 || WP_SaberLose( self, NULL ) ) + { + self->s.weapon = WP_NONE; } } + else if ( weapon == WP_BLASTER_PISTOL ) + {//FIXME: either drop the pistol and make the pickup only give ammo or drop ammo + } else if ( weapon > WP_SABER && weapon <= MAX_PLAYER_WEAPONS )//&& self->client->ps.ammo[ weaponData[weapon].ammoIndex ] { - // find the item type for this weapon - item = FindItemForWeapon( (weapon_t) weapon ); + self->s.weapon = WP_NONE; - if ( weapon == WP_THERMAL && (self->client->ps.torsoAnim == BOTH_ATTACK10)) - {//drop it! - self->client->ps.weaponChargeTime = level.time - FRAMETIME;//so it just kind of drops it - dropped = WP_DropThermal( self ); + if ( weapon == WP_THERMAL ) + {//using thermal + if ( self->client->ps.torsoAnim == BOTH_ATTACK10 ) + {//we were getting ready to throw one, drop it! + self->client->ps.weaponChargeTime = level.time - FRAMETIME;//so it just kind of drops it + dropped = WP_DropThermal( self ); + } + else + {//drop the belt + item = FindItemForAmmo( AMMO_THERMAL ); + } } else + {// find the item type for this weapon + item = FindItemForWeapon( (weapon_t) weapon ); + } + if ( item && !dropped ) { // spawn the item dropped = Drop_Item( self, item, 0, qtrue ); @@ -144,7 +158,7 @@ gentity_t *TossClientItems( gentity_t *self ) dropped->count = 20; break; case WP_BLASTER: - dropped->count = 25; + dropped->count = 15; break; case WP_DISRUPTOR: dropped->count = 20; @@ -165,7 +179,7 @@ gentity_t *TossClientItems( gentity_t *self ) dropped->count = 3; break; case WP_THERMAL: - dropped->count = 3; + dropped->count = 4; break; case WP_TRIP_MINE: dropped->count = 3; @@ -181,17 +195,17 @@ gentity_t *TossClientItems( gentity_t *self ) break; } } + // well, dropped weapons are G2 models, so they have to be initialised if they want to draw..give us a radius so we don't get prematurely culled + if ( weapon != WP_THERMAL ) + { + gi.G2API_InitGhoul2Model( dropped->ghoul2, item->world_model, G_ModelIndex( item->world_model )); + dropped->s.radius = 10; + } } - - - // well, dropped weapons are G2 models, so they have to be initialised if they want to draw..give us a radius so we don't get prematurely culled - gi.G2API_InitGhoul2Model( dropped->ghoul2, item->world_model, G_ModelIndex( item->world_model )); - dropped->s.radius = 10; - } // else if (( self->client->NPC_class == CLASS_SENTRY ) || ( self->client->NPC_class == CLASS_PROBE )) // Looks dumb, Steve told us to take it out. // { -// item = FindItemForAmmo( AMMO_BLASTER ); +// item = FindItemForAmmo( AMMO_BLASTER ); // Drop_Item( self, item, 0, qtrue ); // } else if ( self->client->NPC_class == CLASS_MARK1 ) @@ -226,7 +240,15 @@ gentity_t *TossClientItems( gentity_t *self ) void G_DropKey( gentity_t *self ) {//drop whatever security key I was holding - gitem_t *item = FindItemForInventory( INV_SECURITY_KEY1 ); + gitem_t *item = NULL; + if ( !Q_stricmp( "goodie", self->message ) ) + { + item = FindItemForInventory( INV_GOODIE_KEY ); + } + else + { + item = FindItemForInventory( INV_SECURITY_KEY ); + } gentity_t *dropped = Drop_Item( self, item, 0, qtrue ); //Don't throw the key VectorClear( dropped->s.pos.trDelta ); @@ -234,38 +256,6 @@ void G_DropKey( gentity_t *self ) self->message = NULL; } -/* -================== -LookAtKiller -================== -*/ -void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) { - vec3_t dir; - //vec3_t angles; - - if ( attacker && attacker != self ) - { - VectorSubtract( attacker->s.pos.trBase, self->s.pos.trBase, dir ); - } - else if ( inflictor && inflictor != self ) - { - VectorSubtract( inflictor->s.pos.trBase, self->s.pos.trBase, dir ); - } - else - { - self->client->ps.stats[STAT_DEAD_YAW] = self->currentAngles[YAW]; - return; - } - - self->client->ps.stats[STAT_DEAD_YAW] = vectoyaw ( dir ); - - /* - angles[YAW] = vectoyaw ( dir ); - angles[PITCH] = 0; - angles[ROLL] = 0; - */ -} - void ObjectDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) { if(self->target) @@ -353,14 +343,23 @@ void G_CheckVictoryScript(gentity_t *self) self->NPC->blockedSpeechDebounceTime = 0;//get them ready to taunt return; } - //FIXME: any way to not say this *right away*? Wait for victim's death anim/scream to finish? - if ( self->NPC && self->NPC->group && self->NPC->group->commander && self->NPC->group->commander->NPC->rank > self->NPC->rank && !Q_irand( 0, 2 ) ) - {//sometimes have the group commander speak instead - G_AddVoiceEvent( self->NPC->group->commander, Q_irand(EV_VICTORY1, EV_VICTORY3), 2000 ); - } - else + if ( self->client && self->client->NPC_class == CLASS_GALAKMECH ) { - G_AddVoiceEvent( self, Q_irand(EV_VICTORY1, EV_VICTORY3), 2000 ); + self->wait = 1; + TIMER_Set( self, "gloatTime", Q_irand( 5000, 8000 ) ); + self->NPC->blockedSpeechDebounceTime = 0;//get him ready to taunt + return; + } + //FIXME: any way to not say this *right away*? Wait for victim's death anim/scream to finish? + if ( self->NPC && self->NPC->group && self->NPC->group->commander && self->NPC->group->commander->NPC && self->NPC->group->commander->NPC->rank > self->NPC->rank && !Q_irand( 0, 2 ) ) + {//sometimes have the group commander speak instead + self->NPC->group->commander->NPC->greetingDebounceTime = level.time + Q_irand( 2000, 5000 ); + //G_AddVoiceEvent( self->NPC->group->commander, Q_irand(EV_VICTORY1, EV_VICTORY3), 2000 ); + } + else if ( self->NPC ) + { + self->NPC->greetingDebounceTime = level.time + Q_irand( 2000, 5000 ); + //G_AddVoiceEvent( self, Q_irand(EV_VICTORY1, EV_VICTORY3), 2000 ); } } } @@ -458,6 +457,10 @@ void G_AlertTeam( gentity_t *victim, gentity_t *attacker, float radius, float so if ( radiusEnts[i] == victim ) continue; + //Skip the attacker + if ( radiusEnts[i] == attacker ) + continue; + //Must be on the same team if ( radiusEnts[i]->client->playerTeam != victim->client->playerTeam ) continue; @@ -562,13 +565,13 @@ void DeathFX( gentity_t *ent ) VectorCopy( ent->currentOrigin, effectPos ); effectPos[2] -= 20; G_PlayEffect( "env/small_explode", effectPos ); + G_SoundOnEnt( ent, CHAN_AUTO, "sound/chars/mouse/misc/death1" ); break; case CLASS_PROBE: VectorCopy( ent->currentOrigin, effectPos ); effectPos[2] += 50; G_PlayEffect( "probeexplosion1", effectPos ); -// G_PlayEffect( "small_chunks", effectPos ); break; case CLASS_ATST: @@ -576,7 +579,6 @@ void DeathFX( gentity_t *ent ) VectorMA( ent->currentOrigin, 20, right, effectPos ); effectPos[2] += 180; G_PlayEffect( "droidexplosion1", effectPos ); -// G_PlayEffect( "small_chunks", effectPos ); VectorMA( effectPos, -40, right, effectPos ); G_PlayEffect( "droidexplosion1", effectPos ); break; @@ -587,31 +589,41 @@ void DeathFX( gentity_t *ent ) break; case CLASS_GONK: + VectorCopy( ent->currentOrigin, effectPos ); + effectPos[2] -= 5; // statusTextIndex = Q_irand( IGT_RESISTANCEISFUTILE, IGT_NAMEIS8OF12 ); G_SoundOnEnt( ent, CHAN_AUTO, va("sound/chars/gonk/misc/death%d.wav",Q_irand( 1, 3 )) ); - // fall through, Gonk should still explode like the rest + G_PlayEffect( "env/med_explode", effectPos ); + break; // should list all remaining droids here, hope I didn't miss any case CLASS_R2D2: - VectorCopy( ent->currentOrigin, effectPos ); - effectPos[2] -= 15; - G_PlayEffect( "r2_droidexplosion", effectPos ); -// G_PlayEffect( "small_chunks", effectPos ); + effectPos[2] -= 10; + G_PlayEffect( "env/med_explode", effectPos ); + G_SoundOnEnt( ent, CHAN_AUTO, "sound/chars/mark2/misc/mark2_explo" ); break; + case CLASS_PROTOCOL://?? case CLASS_R5D2: VectorCopy( ent->currentOrigin, effectPos ); - effectPos[2] -= 15; - G_PlayEffect( "r5_droidexplosion", effectPos ); + effectPos[2] -= 10; + G_PlayEffect( "env/med_explode", effectPos ); + G_SoundOnEnt( ent, CHAN_AUTO, "sound/chars/mark2/misc/mark2_explo" ); + break; - case CLASS_PROTOCOL: case CLASS_MARK2: + VectorCopy( ent->currentOrigin, effectPos ); + effectPos[2] -= 15; + G_PlayEffect( "droidexplosion1", effectPos ); + G_SoundOnEnt( ent, CHAN_AUTO, "sound/chars/mark2/misc/mark2_explo" ); + break; + case CLASS_INTERROGATOR: VectorCopy( ent->currentOrigin, effectPos ); effectPos[2] -= 15; G_PlayEffect( "droidexplosion1", effectPos ); -// G_PlayEffect( "small_chunks", effectPos ); + G_SoundOnEnt( ent, CHAN_AUTO, "sound/chars/interrogator/misc/int_droid_explo" ); break; case CLASS_MARK1: @@ -623,11 +635,11 @@ void DeathFX( gentity_t *ent ) G_PlayEffect( "droidexplosion1", effectPos ); VectorMA( effectPos, -20, right, effectPos ); G_PlayEffect( "droidexplosion1", effectPos ); -// G_PlayEffect( "small_chunks", effectPos ); + G_SoundOnEnt( ent, CHAN_AUTO, "sound/chars/mark1/misc/mark1_explo" ); break; case CLASS_SENTRY: - G_SoundOnEnt( ent, CHAN_AUTO, "sound/chars/sentry/misc/death.wav"); + G_SoundOnEnt( ent, CHAN_AUTO, "sound/chars/sentry/misc/sentry_explo" ); VectorCopy( ent->currentOrigin, effectPos ); G_PlayEffect( "env/med_explode", effectPos ); break; @@ -749,18 +761,6 @@ void G_MakeTeamVulnerable( void ) { continue; } - if ( !ent->client->squadname ) - { - continue; - } - if ( !ent->client->squadname[0] ) - { - continue; - } - if ( Q_stricmp(self->client->squadname, ent->client->squadname) ) - { - continue; - } ent->flags &= ~FL_UNDYING; newhealth = Q_irand( 5, 40 ); if ( ent->health > newhealth ) @@ -840,7 +840,7 @@ qboolean G_JediInRoom( vec3_t from ) return qfalse; } -qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir ) +qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir, int mod ) { qboolean dismember = qfalse; @@ -946,7 +946,7 @@ qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hit { *hitLoc = HL_GENERIC1; } - else if (!Q_stricmp("torso_shield",surfName)) + else if (!Q_stricmp("torso_shield_off",surfName)) { *hitLoc = HL_GENERIC2; } @@ -1017,21 +1017,17 @@ qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hit {//hit at waist *hitLoc = HL_WAIST; } - else if ( upSide > -3 ) - {//hit at waist - *hitLoc = HL_HEAD; - } else {//hit on upper torso - if ( rightSide > 10 ) + if ( rightSide > 4 ) { *hitLoc = HL_ARM_RT; } - else if ( rightSide < -10 ) + else if ( rightSide < -4 ) { *hitLoc = HL_ARM_LT; } - else if ( rightSide > 4 ) + else if ( rightSide > 2 ) { if ( frontSide > 0 ) { @@ -1042,7 +1038,7 @@ qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hit *hitLoc = HL_BACK_RT; } } - else if ( rightSide < -4 ) + else if ( rightSide < -2 ) { if ( frontSide > 0 ) { @@ -1053,7 +1049,7 @@ qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hit *hitLoc = HL_BACK_LT; } } - else if ( upSide > -3 ) + else if ( upSide > -3 && mod == MOD_SABER ) { *hitLoc = HL_HEAD; } @@ -1160,88 +1156,102 @@ qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hit } } } - else if ( !Q_strncmp( "r_hand", surfName, 6 ) ) - { + else if ( !Q_strncmp( "r_hand", surfName, 6 ) || !Q_strncmp( "w_", surfName, 2 ) ) + {//right hand or weapon *hitLoc = HL_HAND_RT; } else if ( !Q_strncmp( "l_hand", surfName, 6 ) ) { *hitLoc = HL_HAND_LT; } - if ( g_realisticSaberDamage->integer ) +#ifdef _DEBUG + else + { + Com_Printf( "ERROR: surface %s does not belong to any hitLocation!!!\n", surfName ); + } +#endif //_DEBUG + + if ( g_saberRealisticCombat->integer ) { dismember = qtrue; } - else if ( g_dismemberment->integer > 3 || !ent->client->dismembered ) + else if ( g_dismemberment->integer >= 11381138 || !ent->client->dismembered ) { - if ( dir && (dir[0] || dir[1] || dir[2]) && + if ( ent->client && ent->client->NPC_class == CLASS_PROTOCOL ) + { + dismember = qtrue; + } + else if ( dir && (dir[0] || dir[1] || dir[2]) && bladeDir && (bladeDir[0] || bladeDir[1] || bladeDir[2]) ) {//we care about direction (presumably for dismemberment) - char *tagName = NULL; - float aoa = 0.5f; - //dir must be roughly perpendicular to the hitLoc's cap bolt - switch ( *hitLoc ) - { - case HL_LEG_RT: - tagName = "*hips_cap_r_leg"; - break; - case HL_LEG_LT: - tagName = "*hips_cap_l_leg"; - break; - case HL_WAIST: - tagName = "*hips_cap_torso"; - aoa = 0.25f; - break; - case HL_CHEST_RT: - case HL_ARM_RT: - case HL_BACK_RT: - tagName = "*torso_cap_r_arm"; - break; - case HL_CHEST_LT: - case HL_ARM_LT: - case HL_BACK_LT: - tagName = "*torso_cap_l_arm"; - break; - case HL_HAND_RT: - tagName = "*r_arm_cap_r_hand"; - break; - case HL_HAND_LT: - tagName = "*l_arm_cap_l_hand"; - break; - case HL_HEAD: - tagName = "*torso_cap_head"; - aoa = 0.25f; - break; - case HL_CHEST: - case HL_BACK: - case HL_FOOT_RT: - case HL_FOOT_LT: - default: - //no dismemberment possible with these, so no checks needed - break; - } - if ( tagName ) - { - int tagBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], tagName ); - if ( tagBolt != -1 ) + if ( g_dismemberProbabilities->value<=0.0f||G_Dismemberable( ent, *hitLoc ) ) + {//either we don't care about probabilties or the probability let us continue + char *tagName = NULL; + float aoa = 0.5f; + //dir must be roughly perpendicular to the hitLoc's cap bolt + switch ( *hitLoc ) { - mdxaBone_t boltMatrix; - vec3_t tagOrg, tagDir, angles; - VectorSet( angles, 0, ent->currentAngles[YAW], 0 ); - gi.G2API_GetBoltMatrix( ent->ghoul2, ent->playerModel, tagBolt, - &boltMatrix, angles, ent->currentOrigin, - actualTime, NULL, ent->s.modelScale ); - gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, tagOrg ); - gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, tagDir ); - if ( DistanceSquared( point, tagOrg ) < 256 ) - {//hit close - float dot = DotProduct( dir, tagDir ); - if ( dot < aoa && dot > -aoa ) - {//hit roughly perpendicular - dot = DotProduct( bladeDir, tagDir ); + case HL_LEG_RT: + tagName = "*hips_cap_r_leg"; + break; + case HL_LEG_LT: + tagName = "*hips_cap_l_leg"; + break; + case HL_WAIST: + tagName = "*hips_cap_torso"; + aoa = 0.25f; + break; + case HL_CHEST_RT: + case HL_ARM_RT: + case HL_BACK_LT: + tagName = "*torso_cap_r_arm"; + break; + case HL_CHEST_LT: + case HL_ARM_LT: + case HL_BACK_RT: + tagName = "*torso_cap_l_arm"; + break; + case HL_HAND_RT: + tagName = "*r_arm_cap_r_hand"; + break; + case HL_HAND_LT: + tagName = "*l_arm_cap_l_hand"; + break; + case HL_HEAD: + tagName = "*torso_cap_head"; + aoa = 0.25f; + break; + case HL_CHEST: + case HL_BACK: + case HL_FOOT_RT: + case HL_FOOT_LT: + default: + //no dismemberment possible with these, so no checks needed + break; + } + if ( tagName ) + { + int tagBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], tagName ); + if ( tagBolt != -1 ) + { + mdxaBone_t boltMatrix; + vec3_t tagOrg, tagDir, angles; + VectorSet( angles, 0, ent->currentAngles[YAW], 0 ); + gi.G2API_GetBoltMatrix( ent->ghoul2, ent->playerModel, tagBolt, + &boltMatrix, angles, ent->currentOrigin, + actualTime, NULL, ent->s.modelScale ); + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, tagOrg ); + gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, tagDir ); + if ( DistanceSquared( point, tagOrg ) < 256 ) + {//hit close + float dot = DotProduct( dir, tagDir ); if ( dot < aoa && dot > -aoa ) - {//blade was roughly perpendicular - dismember = qtrue; + {//hit roughly perpendicular + dot = DotProduct( bladeDir, tagDir ); + if ( dot < aoa && dot > -aoa ) + {//blade was roughly perpendicular + dismember = qtrue; + } } } } @@ -1249,7 +1259,6 @@ qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hit } } } - return dismember; } @@ -1606,13 +1615,30 @@ void LimbThink( gentity_t *ent ) } else {//lay flat - if ( ent->currentAngles[0] > 90 || ent->currentAngles[0] < -90 ) + if ( ent->owner + && ent->owner->client + && ent->owner->client->NPC_class == CLASS_PROTOCOL + && ent->count == BOTH_DISMEMBER_TORSO1 ) { - flatAngles[0] = 180; + if ( ent->currentAngles[0] > 0 || ent->currentAngles[0] < -180 ) + { + flatAngles[0] = -90; + } + else + { + flatAngles[0] = 90; + } } else { - flatAngles[0] = 0; + if ( ent->currentAngles[0] > 90 || ent->currentAngles[0] < -90 ) + { + flatAngles[0] = 180; + } + else + { + flatAngles[0] = 0; + } } } //yaw @@ -1664,7 +1690,40 @@ float hitLocHealthPercentage[HL_MAX] = 0.05f, //HL_ARM_LT, 0.01f, //HL_HAND_RT, 0.01f, //HL_HAND_LT, - 0.10f //HL_HEAD + 0.10f, //HL_HEAD + 0.0f, //HL_GENERIC1, + 0.0f, //HL_GENERIC2, + 0.0f, //HL_GENERIC3, + 0.0f, //HL_GENERIC4, + 0.0f, //HL_GENERIC5, + 0.0f //HL_GENERIC6 +}; + +char *hitLocName[HL_MAX] = +{ + "none", //HL_NONE = 0, + "right foot", //HL_FOOT_RT, + "left foot", //HL_FOOT_LT, + "right leg", //HL_LEG_RT, + "left leg", //HL_LEG_LT, + "waist", //HL_WAIST, + "back right shoulder", //HL_BACK_RT, + "back left shoulder", //HL_BACK_LT, + "back", //HL_BACK, + "front right shouler", //HL_CHEST_RT, + "front left shoulder", //HL_CHEST_LT, + "chest", //HL_CHEST, + "right arm", //HL_ARM_RT, + "left arm", //HL_ARM_LT, + "right hand", //HL_HAND_RT, + "left hand", //HL_HAND_LT, + "head", //HL_HEAD + "generic1", //HL_GENERIC1, + "generic2", //HL_GENERIC2, + "generic3", //HL_GENERIC3, + "generic4", //HL_GENERIC4, + "generic5", //HL_GENERIC5, + "generic6" //HL_GENERIC6 }; qboolean G_LimbLost( gentity_t *ent, int hitLoc ) @@ -1761,7 +1820,7 @@ qboolean G_LimbLost( gentity_t *ent, int hitLoc ) } } -qboolean G_Dismember( gentity_t *ent, vec3_t point, +static qboolean G_Dismember( gentity_t *ent, vec3_t point, const char *limbBone, const char *rotateBone, char *limbName, char *limbCapName, char *stubCapName, char *limbTagName, char *stubTagName, int limbAnim, float limbRollBase, float limbPitchBase, @@ -1834,6 +1893,19 @@ qboolean G_Dismember( gentity_t *ent, vec3_t point, BONE_ANIM_OVERRIDE_FREEZE, 1, cg.time); } */ + if ( limbBone && hitLoc == HL_WAIST && ent->client->NPC_class == CLASS_PROTOCOL ) + {//play the dismember anim on the limb? + gi.G2API_StopBoneAnim( &limb->ghoul2[limb->playerModel], "model_root" ); + gi.G2API_StopBoneAnim( &limb->ghoul2[limb->playerModel], "motion" ); + gi.G2API_StopBoneAnim( &limb->ghoul2[limb->playerModel], "pelvis" ); + gi.G2API_StopBoneAnim( &limb->ghoul2[limb->playerModel], "upper_lumbar" ); + //FIXME: screws up origin + animation_t *animations = level.knownAnimFileSets[ent->client->clientInfo.animFileIndex].animations; + //play the proper dismember anim on the limb + gi.G2API_SetBoneAnim(&limb->ghoul2[limb->playerModel], 0, animations[limbAnim].firstFrame, + animations[limbAnim].numFrames + animations[limbAnim].firstFrame, + BONE_ANIM_OVERRIDE_FREEZE, 1, cg.time ); + } if ( rotateBone ) { gi.G2API_SetNewOrigin( &limb->ghoul2[0], gi.G2API_AddBolt( &limb->ghoul2[0], rotateBone ) ); @@ -1907,36 +1979,49 @@ qboolean G_Dismember( gentity_t *ent, vec3_t point, limb->classname = "limb"; limb->owner = ent; limb->enemy = ent->enemy; - if ( ent->weaponModel != -1 && !ent->client->ps.saberInFlight ) + if ( ent->weaponModel >= 0 && !ent->client->ps.saberInFlight ) {//the corpse hasn't dropped their weapon if ( limbAnim == BOTH_DISMEMBER_RARM || limbAnim == BOTH_DISMEMBER_TORSO1 )//&& ent->s.weapon == WP_SABER && ent->weaponModel != -1 ) {//FIXME: is this first check needed with this lower one? if ( !gi.G2API_GetSurfaceRenderStatus( &limb->ghoul2[0], "r_hand" ) ) {//only copy the weapon over if the right hand is actually on this limb... - limb->s.weapon = ent->s.weapon; - limb->weaponModel = ent->weaponModel; + //copy it to limb + if ( ent->s.weapon != WP_NONE ) + {//only if they actually still have a weapon + limb->s.weapon = ent->s.weapon; + limb->weaponModel = ent->weaponModel; + }//else - weaponModel is not -1 but don't have a weapon? Oops, somehow G2 model wasn't removed? + //remove it on owner + if ( ent->weaponModel >= 0 ) + { + gi.G2API_RemoveGhoul2Model( ent->ghoul2, ent->weaponModel ); + ent->weaponModel = -1; + } + if ( ent->client->ps.saberEntityNum != ENTITYNUM_NONE && ent->client->ps.saberEntityNum > 0 ) + {//remove the owner ent's saber model and entity + if ( g_entities[ent->client->ps.saberEntityNum].inuse ) + { + G_FreeEntity( &g_entities[ent->client->ps.saberEntityNum] ); + } + ent->client->ps.saberEntityNum = ENTITYNUM_NONE; + } } else { - gi.G2API_RemoveGhoul2Model( limb->ghoul2, ent->weaponModel ); - limb->weaponModel = -1; - } - //remove the owner ent's saber model and entity - if ( ent->client->ps.saberEntityNum != ENTITYNUM_NONE && ent->client->ps.saberEntityNum > 0 ) - { - gi.G2API_RemoveGhoul2Model( ent->ghoul2, ent->weaponModel ); - ent->weaponModel = -1; - if ( g_entities[ent->client->ps.saberEntityNum].inuse ) + if ( ent->weaponModel >= 0 ) { - G_FreeEntity( &g_entities[ent->client->ps.saberEntityNum] ); + gi.G2API_RemoveGhoul2Model( limb->ghoul2, ent->weaponModel ); + limb->weaponModel = -1; } - ent->client->ps.saberEntityNum = ENTITYNUM_NONE; } } else { - gi.G2API_RemoveGhoul2Model( limb->ghoul2, ent->weaponModel ); - limb->weaponModel = -1; + if ( ent->weaponModel >= 0 ) + { + gi.G2API_RemoveGhoul2Model( limb->ghoul2, ent->weaponModel ); + limb->weaponModel = -1; + } } } @@ -2032,13 +2117,13 @@ qboolean G_Dismember( gentity_t *ent, vec3_t point, return qtrue; } -static qboolean G_Dismemberable( gentity_t *self, int hitLoc, int damage ) +static qboolean G_Dismemberable( gentity_t *self, int hitLoc ) { if ( self->client->dismembered ) {//cannot dismember me right now return qfalse; } - if ( g_dismemberment->integer < 4 && !g_realisticSaberDamage->integer ) + if ( g_dismemberment->integer < 11381138 && !g_saberRealisticCombat->integer ) { if ( g_dismemberProbabilities->value > 0.0f ) {//use the ent-specific dismemberProbabilities @@ -2074,14 +2159,26 @@ static qboolean G_Dismemberable( gentity_t *self, int hitLoc, int damage ) break; } - //check probability of this hapening on this npc - if ( floor((Q_flrand( 0, 100 )*g_dismemberProbabilities->value)) > dismemberProb ) + //check probability of this happening on this npc + if ( floor((Q_flrand( 1, 100 )*g_dismemberProbabilities->value)) > dismemberProb*2.0f )//probabilities seemed really really low, had to crank them up { return qfalse; } } - else - {//else add the passed-in damage to the locationDamage array, check to see if it's taken enough damage to actually dismember + } + return qtrue; +} + +static qboolean G_Dismemberable2( gentity_t *self, int hitLoc ) +{ + if ( self->client->dismembered ) + {//cannot dismember me right now + return qfalse; + } + if ( g_dismemberment->integer < 11381138 && !g_saberRealisticCombat->integer ) + { + if ( g_dismemberProbabilities->value <= 0.0f ) + {//add the passed-in damage to the locationDamage array, check to see if it's taken enough damage to actually dismember if ( self->locationDamage[hitLoc] < (self->client->ps.stats[STAT_MAX_HEALTH]*hitLocHealthPercentage[hitLoc]) ) {//this location has not taken enough damage to dismember return qfalse; @@ -2094,13 +2191,19 @@ static qboolean G_Dismemberable( gentity_t *self, int hitLoc, int damage ) extern qboolean G_StandardHumanoid( const char *modelName ); qboolean G_DoDismemberment( gentity_t *self, vec3_t point, int mod, int damage, int hitLoc, qboolean force = qfalse ) { +extern cvar_t *g_iscensored; // dismemberment -- FIXME: should have a check for how long npc has been dead so people can't // continue to dismember a dead body long after it's been dead - //NOTE that you can only cut one thing off unless the super dismemberment is > 3 - if ( g_dismemberment->integer && mod == MOD_SABER )//only lightsaber + //NOTE that you can only cut one thing off unless the dismemberment is >= 11381138 +#ifdef GERMAN_CENSORED + if ( 0 ) //germany == censorship +#else + if ( !g_iscensored->integer && ( g_dismemberment->integer || g_saberRealisticCombat->integer > 1 ) && mod == MOD_SABER )//only lightsaber +#endif {//FIXME: don't do strcmps here - if ( G_StandardHumanoid( self->NPC_type ) && (force||G_Dismemberable( self, hitLoc, damage)) ) - {//temp hack because only these models are set up the right way so far + if ( G_StandardHumanoid( self->NPC_type ) + && (force||g_dismemberProbabilities->value>0.0f||G_Dismemberable2( self, hitLoc )) ) + {//either it's a forced dismemberment or we're using probabilities (which are checked before this) or we've done enough damage to this location //FIXME: check the hitLoc and hitDir against the cap tag for the place //where the split will be- if the hit dir is roughly perpendicular to //the direction of the cap, then the split is allowed, otherwise we @@ -2292,6 +2395,454 @@ static int G_CheckSpecialDeathAnim( gentity_t *self, vec3_t point, int damage, i deathAnim = BOTH_DEATH_SPIN_90_L; //# Death anim when facing 90 degrees left } } + else if ( PM_InKnockDown( &self->client->ps ) ) + {//since these happen a lot, let's handle them case by case + int animLength = PM_AnimLength( self->client->clientInfo.animFileIndex, (animNumber_t)self->client->ps.legsAnim ); + switch ( self->client->ps.legsAnim ) + { + case BOTH_KNOCKDOWN1: + if ( animLength - self->client->ps.legsAnimTimer > 100 ) + {//on our way down + if ( self->client->ps.legsAnimTimer > 600 ) + {//still partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_KNOCKDOWN2: + if ( animLength - self->client->ps.legsAnimTimer > 700 ) + {//on our way down + if ( self->client->ps.legsAnimTimer > 600 ) + {//still partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_KNOCKDOWN3: + if ( animLength - self->client->ps.legsAnimTimer > 100 ) + {//on our way down + if ( self->client->ps.legsAnimTimer > 1300 ) + {//still partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_DN; + } + } + break; + case BOTH_KNOCKDOWN4: + if ( animLength - self->client->ps.legsAnimTimer > 300 ) + {//on our way down + if ( self->client->ps.legsAnimTimer > 350 ) + {//still partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + else + {//crouch death + vec3_t fwd; + AngleVectors( self->currentAngles, fwd, NULL, NULL ); + float thrown = DotProduct( fwd, self->client->ps.velocity ); + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + break; + case BOTH_KNOCKDOWN5: + if ( self->client->ps.legsAnimTimer < 750 ) + {//flat + deathAnim = BOTH_DEATH_LYING_DN; + } + break; + case BOTH_GETUP1: + if ( self->client->ps.legsAnimTimer < 350 ) + {//standing up + } + else if ( self->client->ps.legsAnimTimer < 800 ) + {//crouching + vec3_t fwd; + AngleVectors( self->currentAngles, fwd, NULL, NULL ); + float thrown = DotProduct( fwd, self->client->ps.velocity ); + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 450 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_GETUP2: + if ( self->client->ps.legsAnimTimer < 150 ) + {//standing up + } + else if ( self->client->ps.legsAnimTimer < 850 ) + {//crouching + vec3_t fwd; + AngleVectors( self->currentAngles, fwd, NULL, NULL ); + float thrown = DotProduct( fwd, self->client->ps.velocity ); + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 500 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_GETUP3: + if ( self->client->ps.legsAnimTimer < 250 ) + {//standing up + } + else if ( self->client->ps.legsAnimTimer < 600 ) + {//crouching + vec3_t fwd; + AngleVectors( self->currentAngles, fwd, NULL, NULL ); + float thrown = DotProduct( fwd, self->client->ps.velocity ); + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 150 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_DN; + } + } + break; + case BOTH_GETUP4: + if ( self->client->ps.legsAnimTimer < 250 ) + {//standing up + } + else if ( self->client->ps.legsAnimTimer < 600 ) + {//crouching + vec3_t fwd; + AngleVectors( self->currentAngles, fwd, NULL, NULL ); + float thrown = DotProduct( fwd, self->client->ps.velocity ); + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 850 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_GETUP5: + if ( self->client->ps.legsAnimTimer > 850 ) + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 1500 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_DN; + } + } + break; + case BOTH_GETUP_CROUCH_B1: + if ( self->client->ps.legsAnimTimer < 800 ) + {//crouching + vec3_t fwd; + AngleVectors( self->currentAngles, fwd, NULL, NULL ); + float thrown = DotProduct( fwd, self->client->ps.velocity ); + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 400 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_GETUP_CROUCH_F1: + if ( self->client->ps.legsAnimTimer < 800 ) + {//crouching + vec3_t fwd; + AngleVectors( self->currentAngles, fwd, NULL, NULL ); + float thrown = DotProduct( fwd, self->client->ps.velocity ); + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 150 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_DN; + } + } + break; + case BOTH_FORCE_GETUP_B1: + if ( self->client->ps.legsAnimTimer < 325 ) + {//standing up + } + else if ( self->client->ps.legsAnimTimer < 725 ) + {//spinning up + deathAnim = BOTH_DEATH_SPIN_180; //# Death anim when facing backwards + } + else if ( self->client->ps.legsAnimTimer < 900 ) + {//crouching + vec3_t fwd; + AngleVectors( self->currentAngles, fwd, NULL, NULL ); + float thrown = DotProduct( fwd, self->client->ps.velocity ); + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 50 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_FORCE_GETUP_B2: + if ( self->client->ps.legsAnimTimer < 575 ) + {//standing up + } + else if ( self->client->ps.legsAnimTimer < 875 ) + {//spinning up + deathAnim = BOTH_DEATH_SPIN_180; //# Death anim when facing backwards + } + else if ( self->client->ps.legsAnimTimer < 900 ) + {//crouching + vec3_t fwd; + AngleVectors( self->currentAngles, fwd, NULL, NULL ); + float thrown = DotProduct( fwd, self->client->ps.velocity ); + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else + {//lying down + //partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + break; + case BOTH_FORCE_GETUP_B3: + if ( self->client->ps.legsAnimTimer < 150 ) + {//standing up + } + else if ( self->client->ps.legsAnimTimer < 775 ) + {//flipping + deathAnim = BOTH_DEATHBACKWARD2; //backflip + } + else + {//lying down + //partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + break; + case BOTH_FORCE_GETUP_B4: + if ( self->client->ps.legsAnimTimer < 325 ) + {//standing up + } + else + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 150 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_FORCE_GETUP_B5: + if ( self->client->ps.legsAnimTimer < 550 ) + {//standing up + } + else if ( self->client->ps.legsAnimTimer < 1025 ) + {//kicking up + deathAnim = BOTH_DEATHBACKWARD2; //backflip + } + else + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 50 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_FORCE_GETUP_B6: + if ( self->client->ps.legsAnimTimer < 225 ) + {//standing up + } + else if ( self->client->ps.legsAnimTimer < 425 ) + {//crouching up + vec3_t fwd; + AngleVectors( self->currentAngles, fwd, NULL, NULL ); + float thrown = DotProduct( fwd, self->client->ps.velocity ); + if ( thrown < -150 ) + { + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + } + else + { + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched + } + } + else if ( self->client->ps.legsAnimTimer < 825 ) + {//flipping up + deathAnim = BOTH_DEATHFORWARD3; //backflip + } + else + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 225 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_UP; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_UP; + } + } + break; + case BOTH_FORCE_GETUP_F1: + if ( self->client->ps.legsAnimTimer < 275 ) + {//standing up + } + else if ( self->client->ps.legsAnimTimer < 750 ) + {//flipping + deathAnim = BOTH_DEATH14; + } + else + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 100 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_DN; + } + } + break; + case BOTH_FORCE_GETUP_F2: + if ( self->client->ps.legsAnimTimer < 1200 ) + {//standing + } + else + {//lying down + if ( animLength - self->client->ps.legsAnimTimer > 225 ) + {//partially up + deathAnim = BOTH_DEATH_FALLING_DN; + } + else + {//down + deathAnim = BOTH_DEATH_LYING_DN; + } + } + break; + } + } else if ( PM_InOnGroundAnim( &self->client->ps ) ) { if ( AngleNormalize180(self->client->renderInfo.torsoAngles[PITCH]) < 0 ) @@ -2303,21 +2854,24 @@ static int G_CheckSpecialDeathAnim( gentity_t *self, vec3_t point, int damage, i deathAnim = BOTH_DEATH_LYING_DN; //# Death anim when lying on front } } - else if ( PM_InKnockDown( &self->client->ps ) ) + else if ( PM_CrouchAnim( self->client->ps.legsAnim ) ) { - if ( AngleNormalize180(self->client->renderInfo.torsoAngles[PITCH]) < 0 ) + vec3_t fwd; + AngleVectors( self->currentAngles, fwd, NULL, NULL ); + float thrown = DotProduct( fwd, self->client->ps.velocity ); + if ( thrown < -200 ) { - deathAnim = BOTH_DEATH_FALLING_UP; //# Death anim when falling on back + deathAnim = BOTH_DEATHBACKWARD1; //# Death anim when crouched and thrown back + if ( self->client->ps.velocity[2] > 0 && self->client->ps.velocity[2] < 100 ) + { + self->client->ps.velocity[2] = 100; + } } else { - deathAnim = BOTH_DEATH_FALLING_DN; //# Death anim when falling on face + deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched } } - else if ( PM_CrouchAnim( self->client->ps.legsAnim ) ) - { - deathAnim = BOTH_DEATH_CROUCHED; //# Death anim when crouched - } return deathAnim; } @@ -2396,6 +2950,12 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, case BOTH_DEAD17: //# case BOTH_DEAD18: //# case BOTH_DEAD19: //# + case BOTH_DEAD20: //# + case BOTH_DEAD21: //# + case BOTH_DEAD22: //# + case BOTH_DEAD23: //# + case BOTH_DEAD24: //# + case BOTH_DEAD25: //# case BOTH_LYINGDEAD1: //# Killed lying down death finished pose case BOTH_STUMBLEDEAD1: //# Stumble forward death finished pose case BOTH_FALLDEAD1LAND: //# Fall forward and splat death finished pose @@ -2410,8 +2970,15 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, case BOTH_DEATH17: //# case BOTH_DEATH18: //# case BOTH_DEATH19: //# + case BOTH_DEATH20: //# + case BOTH_DEATH21: //# + case BOTH_DEATH22: //# + case BOTH_DEATH23: //# + case BOTH_DEATH24: //# + case BOTH_DEATH25: //# case BOTH_DEATHFORWARD1: //# First Death in which they get thrown forward case BOTH_DEATHFORWARD2: //# Second Death in which they get thrown forward + case BOTH_DEATHFORWARD3: //# Second Death in which they get thrown forward case BOTH_DEATHBACKWARD1: //# First Death in which they get thrown backward case BOTH_DEATHBACKWARD2: //# Second Death in which they get thrown backward case BOTH_DEATH1IDLE: //# Idle while close to death @@ -2443,28 +3010,44 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, if ( deathAnim == -1 ) {//base on hitLoc + vec3_t fwd; + AngleVectors( self->currentAngles, fwd, NULL, NULL ); + float thrown = DotProduct( fwd, self->client->ps.velocity ); //death anims switch( hitLoc ) { case HL_FOOT_RT: - case HL_FOOT_LT: - if ( !Q_irand( 0, 2 ) ) + if ( !Q_irand( 0, 2 ) && thrown < 250 ) { - deathAnim = BOTH_DEATH4;//back: forward + deathAnim = BOTH_DEATH24;//right foot trips up, spin } else if ( !Q_irand( 0, 1 ) ) { - deathAnim = BOTH_DEATH5;//same as 4 + deathAnim = BOTH_DEATH4;//back: forward } else { - deathAnim = BOTH_DEATH15;//back: forward + deathAnim = BOTH_DEATH5;//same as 4 + } + break; + case HL_FOOT_LT: + if ( !Q_irand( 0, 2 ) && thrown < 250 ) + { + deathAnim = BOTH_DEATH25;//left foot trips up, spin + } + else if ( !Q_irand( 0, 1 ) ) + { + deathAnim = BOTH_DEATH4;//back: forward + } + else + { + deathAnim = BOTH_DEATH5;//same as 4 } break; case HL_LEG_RT: - if ( !Q_irand( 0, 2 ) ) + if ( !Q_irand( 0, 2 ) && thrown < 250 ) { - deathAnim = BOTH_DEATH4;//back: forward + deathAnim = BOTH_DEATH3;//right leg collapse } else if ( !Q_irand( 0, 1 ) ) { @@ -2472,13 +3055,13 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, } else { - deathAnim = BOTH_DEATH15;//back: forward + deathAnim = BOTH_DEATH4;//back: forward } break; case HL_LEG_LT: - if ( !Q_irand( 0, 2 ) ) + if ( !Q_irand( 0, 2 ) && thrown < 250 ) { - deathAnim = BOTH_DEATH4;//back: forward + deathAnim = BOTH_DEATH7;//left leg collapse } else if ( !Q_irand( 0, 1 ) ) { @@ -2486,11 +3069,11 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, } else { - deathAnim = BOTH_DEATH15;//back: forward + deathAnim = BOTH_DEATH4;//back: forward } break; case HL_BACK: - if ( VectorLengthSquared( self->client->ps.velocity ) < 256 ) + if ( fabs(thrown) < 50 || (fabs(thrown) < 200&&!Q_irand(0,3)) ) { if ( Q_irand( 0, 1 ) ) { @@ -2503,60 +3086,63 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, } else { - if ( !Q_irand( 0, 2 ) ) + if ( !Q_irand( 0, 1 ) ) { deathAnim = BOTH_DEATH4;//back: forward } - else if ( !Q_irand( 0, 1 ) ) - { - deathAnim = BOTH_DEATH5;//same as 4 - } else { - deathAnim = BOTH_DEATH15;//back: forward + deathAnim = BOTH_DEATH5;//same as 4 } } break; case HL_HAND_RT: case HL_CHEST_RT: case HL_ARM_RT: - case HL_BACK_RT: - if ( deathAnim == -1 ) + case HL_BACK_LT: + if ( (damage <= self->max_health*0.25&&Q_irand(0,1)) || (fabs(thrown)<200&&!Q_irand(0,2)) || !Q_irand( 0, 10 ) ) { - if ( damage <= self->max_health*0.25 ) + if ( Q_irand( 0, 1 ) ) { deathAnim = BOTH_DEATH9;//chest right: snap, fall forward } - else if ( damage <= self->max_health*0.5 ) + else { - deathAnim = BOTH_DEATH3;//chest right: back + deathAnim = BOTH_DEATH20;//chest right: snap, fall forward } - else if ( damage <= self->max_health*0.75 ) + } + else if ( (damage <= self->max_health*0.5&&Q_irand(0,1)) || !Q_irand( 0, 10 ) ) + { + deathAnim = BOTH_DEATH3;//chest right: back + } + else if ( (damage <= self->max_health*0.75&&Q_irand(0,1)) || !Q_irand( 0, 10 ) ) + { + deathAnim = BOTH_DEATH6;//chest right: spin + } + else + { + //TEMP HACK: play spinny deaths less often + if ( Q_irand( 0, 1 ) ) { - deathAnim = BOTH_DEATH6;//chest right: spin + deathAnim = BOTH_DEATH8;//chest right: spin high } - else + else { - //TEMP HACK: play spinny deaths less often - if ( Q_irand( 0, 1 ) ) + switch ( Q_irand( 0, 3 ) ) { - deathAnim = BOTH_DEATH8;//chest right: spin high - } - else - { - switch ( Q_irand( 0, 2 ) ) - { - default: - case 0: - deathAnim = BOTH_DEATH9;//chest right: snap, fall forward - break; - case 1: - deathAnim = BOTH_DEATH3;//chest right: back - break; - case 2: - deathAnim = BOTH_DEATH6;//chest right: spin - break; - } + default: + case 0: + deathAnim = BOTH_DEATH9;//chest right: snap, fall forward + break; + case 1: + deathAnim = BOTH_DEATH3;//chest right: back + break; + case 2: + deathAnim = BOTH_DEATH6;//chest right: spin + break; + case 3: + deathAnim = BOTH_DEATH20;//chest right: spin + break; } } } @@ -2564,16 +3150,23 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, case HL_CHEST_LT: case HL_ARM_LT: case HL_HAND_LT: - case HL_BACK_LT: - if ( damage <= self->max_health*0.25 ) + case HL_BACK_RT: + if ( (damage <= self->max_health*0.25&&Q_irand(0,1)) || (fabs(thrown)<200&&!Q_irand(0,2)) || !Q_irand(0, 10) ) { - deathAnim = BOTH_DEATH11;//chest left: snap, fall forward + if ( Q_irand( 0, 1 ) ) + { + deathAnim = BOTH_DEATH11;//chest left: snap, fall forward + } + else + { + deathAnim = BOTH_DEATH21;//chest left: snap, fall forward + } } - else if ( damage <= self->max_health*0.5 ) + else if ( (damage <= self->max_health*0.5&&Q_irand(0,1)) || !Q_irand(0, 10) ) { deathAnim = BOTH_DEATH7;//chest left: back } - else if ( damage <= self->max_health*0.75 ) + else if ( (damage <= self->max_health*0.75&&Q_irand(0,1)) || !Q_irand(0, 10) ) { deathAnim = BOTH_DEATH12;//chest left: spin } @@ -2586,7 +3179,7 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, } else { - switch ( Q_irand( 0, 2 ) ) + switch ( Q_irand( 0, 3 ) ) { default: case 0: @@ -2598,13 +3191,16 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, case 2: deathAnim = BOTH_DEATH12;//chest left: spin break; + case 3: + deathAnim = BOTH_DEATH21;//chest left: spin + break; } } } break; case HL_CHEST: case HL_WAIST: - if ( damage <= self->max_health*0.25 || !VectorLengthSquared( self->client->ps.velocity ) ) + if ( (damage <= self->max_health*0.25&&Q_irand(0,1)) || thrown > -50 ) { if ( !Q_irand( 0, 1 ) ) { @@ -2615,11 +3211,37 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, deathAnim = BOTH_DEATH19;//gut: fall left } } - else if ( damage <= self->max_health*0.5 ) + else if ( (damage <= self->max_health*0.5&&!Q_irand(0,1)) || (fabs(thrown)<200&&!Q_irand(0,3)) ) { - deathAnim = BOTH_DEATH2;//chest: backward short + if ( Q_irand( 0, 2 ) ) + { + deathAnim = BOTH_DEATH2;//chest: backward short + } + else if ( Q_irand( 0, 1 ) ) + { + deathAnim = BOTH_DEATH22;//chest: backward short + } + else + { + deathAnim = BOTH_DEATH23;//chest: backward short + } } - else //if ( damage <= self->max_health*0.75 ) + else if ( thrown < -300 && Q_irand( 0, 1 ) ) + { + if ( Q_irand( 0, 1 ) ) + { + deathAnim = BOTH_DEATHBACKWARD1;//chest: fly back + } + else + { + deathAnim = BOTH_DEATHBACKWARD2;//chest: flip back + } + } + else if ( thrown < -200 && Q_irand( 0, 1 ) ) + { + deathAnim = BOTH_DEATH15;//chest: roll backward + } + else { if ( !Q_irand( 0, 1 ) ) { @@ -2632,13 +3254,20 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, } break; case HL_HEAD: - if ( damage <= self->max_health*0.5 ) + if ( damage <= self->max_health*0.5 && Q_irand(0,2) ) { deathAnim = BOTH_DEATH17;//head/back: croak } else { - deathAnim = BOTH_DEATH13;//head: stumble, fall back + if ( Q_irand( 0, 2 ) ) + { + deathAnim = BOTH_DEATH13;//head: stumble, fall back + } + else + { + deathAnim = BOTH_DEATH10;//head: stumble, fall back + } } break; default: @@ -2651,11 +3280,91 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, if ( deathAnim == -1 || !PM_HasAnimation( self, deathAnim )) { // I guess we'll take what we can get..... - deathAnim = PM_PickAnim( self, BOTH_DEATH1, BOTH_DEATH19 ); + deathAnim = PM_PickAnim( self, BOTH_DEATH1, BOTH_DEATH25 ); } return deathAnim; } + +int G_CheckLedgeDive( gentity_t *self, float checkDist, vec3_t checkVel, qboolean tryOpposite, qboolean tryPerp ) +{ + // Intelligent Ledge-Diving Deaths: + // If I'm an NPC, check for nearby ledges and fall off it if possible + // How should/would/could this interact with knockback if we already have some? + // Ideally - apply knockback if there are no ledges or a ledge in that dir + // But if there is a ledge and it's not in the dir of my knockback, fall off the ledge instead + if ( !self || !self->client ) + { + return 0; + } + + vec3_t fallForwardDir, fallRightDir; + vec3_t angles = {0}; + int cliff_fall = 0; + + if ( checkVel && !VectorCompare( checkVel, vec3_origin ) ) + {//already moving in a dir + angles[1] = vectoyaw( self->client->ps.velocity ); + AngleVectors( angles, fallForwardDir, fallRightDir, NULL ); + } + else + {//try forward first + angles[1] = self->client->ps.viewangles[1]; + AngleVectors( angles, fallForwardDir, fallRightDir, NULL ); + } + VectorNormalize( fallForwardDir ); + float fallDist = G_CheckForLedge( self, fallForwardDir, checkDist ); + if ( fallDist >= 128 ) + { + VectorClear( self->client->ps.velocity ); + G_Throw( self, fallForwardDir, 85 ); + self->client->ps.velocity[2] = 100; + self->client->ps.groundEntityNum = ENTITYNUM_NONE; + } + else if ( tryOpposite ) + { + VectorScale( fallForwardDir, -1, fallForwardDir ); + fallDist = G_CheckForLedge( self, fallForwardDir, checkDist ); + if ( fallDist >= 128 ) + { + VectorClear( self->client->ps.velocity ); + G_Throw( self, fallForwardDir, 85 ); + self->client->ps.velocity[2] = 100; + self->client->ps.groundEntityNum = ENTITYNUM_NONE; + } + } + if ( !cliff_fall && tryPerp ) + {//try sides + VectorNormalize( fallRightDir ); + fallDist = G_CheckForLedge( self, fallRightDir, checkDist ); + if ( fallDist >= 128 ) + { + VectorClear( self->client->ps.velocity ); + G_Throw( self, fallRightDir, 85 ); + self->client->ps.velocity[2] = 100; + } + else + { + VectorScale( fallRightDir, -1, fallRightDir ); + fallDist = G_CheckForLedge( self, fallRightDir, checkDist ); + if ( fallDist >= 128 ) + { + VectorClear( self->client->ps.velocity ); + G_Throw( self, fallRightDir, 85 ); + self->client->ps.velocity[2] = 100; + } + } + } + if ( fallDist >= 256 ) + { + cliff_fall = 2; + } + else if ( fallDist >= 128 ) + { + cliff_fall = 1; + } + return cliff_fall; +} /* ================== player_die @@ -2672,30 +3381,44 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int int contents; qboolean deathScript = qfalse; qboolean lastInGroup = qfalse; - qboolean cliff_fall = qfalse; qboolean specialAnim = qfalse; + qboolean holdingSaber = qfalse; + int cliff_fall = 0; //FIXME: somehow people are sometimes not completely dying??? if ( self->client->ps.pm_type == PM_DEAD && (meansOfDeath != MOD_SNIPER || (self->flags & FL_DISINTEGRATED)) ) {//do dismemberment/twitching - anim = G_PickDeathAnim( self, self->pos1, damage, meansOfDeath, hitLoc ); - if ( dflags & DAMAGE_DISMEMBER ) + if ( self->client->NPC_class == CLASS_MARK1 ) { - G_DoDismemberment( self, self->pos1, meansOfDeath, damage, hitLoc ); + DeathFX(self); + self->takedamage = qfalse; + self->client->ps.eFlags |= EF_NODRAW; + self->contents = 0; + // G_FreeEntity( self ); // Is this safe? I can't see why we'd mark it nodraw and then just leave it around?? + self->e_ThinkFunc = thinkF_G_FreeEntity; + self->nextthink = level.time + FRAMETIME; } - if ( anim >= 0 ) + else { - NPC_SetAnim(self, SETANIM_BOTH, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_RESTART|SETANIM_FLAG_HOLD); + anim = G_PickDeathAnim( self, self->pos1, damage, meansOfDeath, hitLoc ); + if ( dflags & DAMAGE_DISMEMBER ) + { + G_DoDismemberment( self, self->pos1, meansOfDeath, damage, hitLoc ); + } + if ( anim >= 0 ) + { + NPC_SetAnim(self, SETANIM_BOTH, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_RESTART|SETANIM_FLAG_HOLD); + } } return; } -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer && attacker && attacker->client ) { gi.Printf( S_COLOR_YELLOW"combatant %s died, killer anim = %s\n", self->targetname, animTable[attacker->client->ps.torsoAnim].name ); } -#endif//_FINAL_BUILD +#endif//FINAL_BUILD if ( self->NPC ) { @@ -2743,6 +3466,10 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); { attacker->NPC->group->enemy = NULL; } + if ( self->s.weapon == WP_SABER ) + { + holdingSaber = qtrue; + } if ( self->client->ps.saberEntityNum != ENTITYNUM_NONE && self->client->ps.saberEntityNum > 0 ) { if ( self->client->ps.saberInFlight ) @@ -2754,8 +3481,24 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); if ( (hitLoc != HL_HAND_RT || self->client->dismembered || meansOfDeath != MOD_SABER )//if might get hand cut off, leave saber in hand + && holdingSaber && ( Q_irand( 0, 1 ) || meansOfDeath == MOD_EXPLOSIVE + || meansOfDeath == MOD_REPEATER_ALT + || meansOfDeath == MOD_FLECHETTE_ALT + || meansOfDeath == MOD_ROCKET + || meansOfDeath == MOD_ROCKET_ALT + || meansOfDeath == MOD_THERMAL + || meansOfDeath == MOD_THERMAL_ALT + || meansOfDeath == MOD_DETPACK + || meansOfDeath == MOD_LASERTRIP + || meansOfDeath == MOD_LASERTRIP_ALT + || meansOfDeath == MOD_MELEE + || meansOfDeath == MOD_FORCE_GRIP + || meansOfDeath == MOD_KNOCKOUT + || meansOfDeath == MOD_CRUSH + || meansOfDeath == MOD_IMPACT + || meansOfDeath == MOD_FALLING || meansOfDeath == MOD_EXPLOSIVE_SPLASH ) ) {//drop it TossClientItems( self ); @@ -2770,6 +3513,12 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); } } } + if ( self->client->NPC_class == CLASS_SHADOWTROOPER ) + {//drop a force crystal + gitem_t *item; + item = FindItemForAmmo( AMMO_FORCE ); + Drop_Item( self, item, 0, qtrue ); + } //Use any target we had if ( meansOfDeath != MOD_KNOCKOUT ) { @@ -2780,7 +3529,17 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); { if ( attacker->client && !attacker->s.number ) { - attacker->client->sess.missionStats.enemiesKilled++; + if ( self->client ) + {//killed a client + if ( self->client->playerTeam == TEAM_ENEMY || (self->NPC && self->NPC->charmedTime > level.time) ) + {//killed an enemy + attacker->client->sess.missionStats.enemiesKilled++; + } + } + if ( attacker != self ) + { + G_TrackWeaponUsage( attacker, inflictor, 30, meansOfDeath ); + } } G_CheckVictoryScript(attacker); //player killing a jedi with a lightsaber spawns a matrix-effect entity @@ -2812,7 +3571,7 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); } } if ( !attacker->s.number - && self->s.weapon == WP_SABER + && holdingSaber && meansOfDeath == MOD_SABER && attacker->client && attacker->client->ps.weapon == WP_SABER @@ -2829,7 +3588,7 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); && attacker->client && attacker->client->ps.weapon == WP_SABER && !attacker->client->ps.saberInFlight - && (d_slowmodeath->integer > 4||lastInGroup))//either slow mo death level 5 (any enemy) or 4 and I was the last in my group + && (d_slowmodeath->integer > 4||lastInGroup||holdingSaber))//either slow mo death level 5 (any enemy) or 4 and I was the last in my group or I'm a saber user {//Matrix! G_StartMatrixEffect( self ); } @@ -2882,8 +3641,8 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); // if client is in a nodrop area, don't drop anything contents = gi.pointcontents( self->currentOrigin, -1 ); - if ( self->s.weapon != WP_SABER - && self->s.number != 0 + if ( !holdingSaber + //&& self->s.number != 0 && !( contents & CONTENTS_NODROP ) && meansOfDeath != MOD_SNIPER && (!self->client||self->client->NPC_class!=CLASS_GALAKMECH)) @@ -2900,7 +3659,7 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); } } - if ( self->s.weapon == WP_SABER ) + if ( holdingSaber ) {//never drop a lightsaber! if ( self->client->ps.saberActive ) { @@ -2915,17 +3674,18 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); } } } - else + else if ( self->s.weapon != WP_BLASTER_PISTOL ) {// Sigh...borg shouldn't drop their weapon attachments when they die.. self->s.weapon = WP_NONE; - if ( self->weaponModel != -1 && self->ghoul2.size()) + if ( self->weaponModel >= 0 && self->ghoul2.size()) { gi.G2API_RemoveGhoul2Model( self->ghoul2, self->weaponModel ); self->weaponModel = -1; } } - self->s.powerups = 0; + self->s.powerups &= ~PW_REMOVE_AT_DEATH;//removes everything but electricity and force push + //FIXME: do this on a callback? So people can't walk through long death anims? //Maybe set on last frame? Would be cool for big blocking corpses if the never got set? //self->contents = CONTENTS_CORPSE;//now done a second after death @@ -2951,7 +3711,7 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); //FACING========================================================== if ( attacker && self->s.number == 0 ) { - LookAtKiller( self, inflictor, attacker ); + self->client->ps.stats[STAT_DEAD_YAW] = AngleNormalize180( self->client->ps.viewangles[YAW] ); } self->currentAngles[PITCH] = 0; self->currentAngles[ROLL] = 0; @@ -2968,13 +3728,29 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); {//I was the player's viewentity and I died, kick him back to his normal view G_ClearViewEntity( player ); } + else if ( !self->s.number && self->client->ps.viewEntity > 0 && self->client->ps.viewEntity < ENTITYNUM_NONE ) + { + G_ClearViewEntity( self ); + } + else if ( !self->s.number && self->client->ps.viewEntity > 0 && self->client->ps.viewEntity < ENTITYNUM_NONE ) + { + G_ClearViewEntity( self ); + } self->s.loopSound = 0; // remove powerups memset( self->client->ps.powerups, 0, sizeof(self->client->ps.powerups) ); - if ( self->client->NPC_class == CLASS_GALAKMECH ) + if ( self->client->NPC_class == CLASS_MARK1 ) + { + Mark1_die( self, inflictor, attacker, damage, meansOfDeath, dflags, hitLoc ); + } + else if ( self->client->NPC_class == CLASS_INTERROGATOR ) + { + Interrogator_die( self, inflictor, attacker, damage, meansOfDeath, dflags, hitLoc ); + } + else if ( self->client->NPC_class == CLASS_GALAKMECH ) {//FIXME: need keyframed explosions? NPC_SetAnim( self, SETANIM_BOTH, BOTH_DEATH1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); G_AddEvent( self, Q_irand(EV_DEATH1, EV_DEATH3), self->health ); @@ -2985,7 +3761,7 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); { G_DrivableATSTDie( self ); } - anim = PM_PickAnim( self, BOTH_DEATH1, BOTH_DEATH19 ); //initialize to good data + anim = PM_PickAnim( self, BOTH_DEATH1, BOTH_DEATH25 ); //initialize to good data if ( anim != -1 ) { NPC_SetAnim( self, SETANIM_BOTH, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); @@ -3000,7 +3776,7 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); anim = BOTH_DEATH4; break; case 1: - anim = BOTH_DEATH15; + anim = BOTH_DEATH21; break; case 2: anim = BOTH_DEATH17; @@ -3095,80 +3871,14 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); {//electrocuted anim = BOTH_DEATH17; } + else if ( meansOfDeath == MOD_WATER ) + {//drowned + anim = BOTH_DEATH17; + } else if ( meansOfDeath != MOD_SNIPER ) { - // Intelligent Ledge-Diving Deaths: - // If I'm an NPC, check for nearby ledges and fall off it if possible - // How should/would/could this interact with knockback if we already have some? - // Ideally - apply knockback if there are no ledges or a ledge in that dir - // But if there is a ledge and it's not in the dir of my knockback, fall off the ledge instead - vec3_t fallForwardDir, fallRightDir; - vec3_t angles = {0}; - - if ( !VectorCompare( self->client->ps.velocity, vec3_origin ) ) - {//already moving in a dir - angles[1] = vectoyaw( self->client->ps.velocity ); - AngleVectors( angles, fallForwardDir, fallRightDir, NULL ); - } - else - {//try forward first - angles[1] = self->client->ps.viewangles[1]; - AngleVectors( angles, fallForwardDir, fallRightDir, NULL ); - } - VectorNormalize( fallForwardDir ); - float fallDist = G_CheckForLedge( self, fallForwardDir ); - if ( fallDist >= 128 ) - { - VectorClear( self->client->ps.velocity ); - G_Throw( self, fallForwardDir, 85 ); - self->client->ps.velocity[2] = 100; - self->client->ps.groundEntityNum = ENTITYNUM_NONE; - if ( fallDist >= 256 ) - { - cliff_fall = qtrue; - } - } - else - { - VectorScale( fallForwardDir, -1, fallForwardDir ); - fallDist = G_CheckForLedge( self, fallForwardDir ); - if ( fallDist >= 128 ) - { - VectorClear( self->client->ps.velocity ); - G_Throw( self, fallForwardDir, 85 ); - self->client->ps.velocity[2] = 100; - self->client->ps.groundEntityNum = ENTITYNUM_NONE; - if ( fallDist >= 256 ) - { - cliff_fall = qtrue; - } - } - else - {//try sides - /* - VectorNormalize( fallRightDir ); - if ( G_CheckForLedge( self, fallRightDir ) ) - { - VectorClear( self->client->ps.velocity ); - G_Throw( self, fallRightDir, 85 ); - self->client->ps.velocity[2] = 100; - cliff_fall = qtrue; - } - else - { - VectorScale( fallRightDir, -1, fallRightDir ); - if ( G_CheckForLedge( self, fallRightDir ) ) - { - VectorClear( self->client->ps.velocity ); - G_Throw( self, fallRightDir, 85 ); - self->client->ps.velocity[2] = 100; - cliff_fall = qtrue; - } - } - */ - } - } - if ( cliff_fall ) + cliff_fall = G_CheckLedgeDive( self, 128, self->client->ps.velocity, qtrue, qfalse ); + if ( cliff_fall == 2 ) { if ( !FlyingCreature( self ) && g_gravity->value > 0 ) { @@ -3192,73 +3902,108 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); AngleVectors(self->currentAngles, forward, NULL, NULL); thrown = VectorNormalize2(self->client->ps.velocity, throwdir); dot = DotProduct(forward, throwdir); - if(thrown > 100) + if ( thrown > 100 ) { if ( dot > 0.3 ) {//falling forward - if ( cliff_fall && PM_HasAnimation( self, BOTH_FALLDEATH1 ) ) + if ( cliff_fall == 2 && PM_HasAnimation( self, BOTH_FALLDEATH1 ) ) { anim = BOTH_FALLDEATH1; } - else if ( PM_HasAnimation( self, BOTH_DEATHFORWARD1 )) + else { - self->client->ps.gravity *= 0.8; - self->client->ps.friction = 0; - if ( PM_HasAnimation( self, BOTH_DEATHFORWARD2) ) + switch ( Q_irand( 0, 7 ) ) { - anim = Q_irand(BOTH_DEATHFORWARD1, BOTH_DEATHFORWARD2);//okay, i assume he has 2 since he has 1 - } - else - { - anim = BOTH_DEATHFORWARD1; + case 0: + case 1: + case 2: + anim = BOTH_DEATH4; + break; + case 3: + case 4: + case 5: + anim = BOTH_DEATH5; + break; + case 6: + anim = BOTH_DEATH8; + break; + case 7: + anim = BOTH_DEATH14; + break; } - } - } - else if ( dot < -0.3 && PM_HasAnimation( self, BOTH_DEATHBACKWARD1 )) - { - self->client->ps.gravity *= 0.8; - self->client->ps.friction = 0; - switch ( Q_irand( 0, 12 ) ) - { - case 0: - case 1: - case 2: - case 3: - anim = BOTH_DEATH1; - break; - case 4: - case 5: - case 6: - case 7: - anim = BOTH_DEATH2; - break; - case 8: - case 9: - case 10: - case 11: - anim = BOTH_DEATHBACKWARD1; - break; - case 12: - if ( thrown >= 250 ) + if ( PM_HasAnimation( self, anim )) { - anim = BOTH_DEATHBACKWARD2; + self->client->ps.gravity *= 0.8; + self->client->ps.friction = 0; + if ( self->client->ps.velocity[2] > 0 && self->client->ps.velocity[2] < 100 ) + { + self->client->ps.velocity[2] = 100; + } } else + { + anim = -1; + } + } + } + else if ( dot < -0.3 ) + { + if ( thrown >= 250 && !Q_irand( 0, 3 ) ) + { + if ( Q_irand( 0, 1 ) ) { anim = BOTH_DEATHBACKWARD1; } - break; + else + { + anim = BOTH_DEATHBACKWARD2; + } } - if ( !PM_HasAnimation( self, anim ) ) + else + { + switch ( Q_irand( 0, 7 ) ) + { + case 0: + case 1: + anim = BOTH_DEATH1; + break; + case 2: + case 3: + anim = BOTH_DEATH2; + break; + case 4: + case 5: + anim = BOTH_DEATH22; + break; + case 6: + case 7: + anim = BOTH_DEATH23; + break; + } + } + if ( PM_HasAnimation( self, anim ) ) + { + self->client->ps.gravity *= 0.8; + self->client->ps.friction = 0; + if ( self->client->ps.velocity[2] > 0 && self->client->ps.velocity[2] < 100 ) + { + self->client->ps.velocity[2] = 100; + } + } + else { anim = -1; } } else {//falling to one of the sides - if ( cliff_fall && PM_HasAnimation( self, BOTH_FALLDEATH1 ) ) + if ( cliff_fall == 2 && PM_HasAnimation( self, BOTH_FALLDEATH1 ) ) { anim = BOTH_FALLDEATH1; + if ( self->client->ps.velocity[2] > 0 && self->client->ps.velocity[2] < 100 ) + { + self->client->ps.velocity[2] = 100; + } } } } @@ -3272,8 +4017,9 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); if ( anim == -1 ) { - if ( meansOfDeath == MOD_ELECTROCUTE ) - { + if ( meansOfDeath == MOD_ELECTROCUTE + || (meansOfDeath == MOD_CRUSH && self->s.eFlags&EF_FORCE_GRIPPED) ) + {//electrocuted or choked to death anim = BOTH_DEATH17; } else @@ -3283,11 +4029,11 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); } if ( anim == -1 ) { - anim = PM_PickAnim( self, BOTH_DEATH1, BOTH_DEATH19 ); //initialize to good data + anim = PM_PickAnim( self, BOTH_DEATH1, BOTH_DEATH25 ); //initialize to good data //TEMP HACK: these spinny deaths should happen less often if ( ( anim == BOTH_DEATH8 || anim == BOTH_DEATH14 ) && Q_irand( 0, 1 ) ) { - anim = PM_PickAnim( self, BOTH_DEATH1, BOTH_DEATH19 ); //initialize to good data + anim = PM_PickAnim( self, BOTH_DEATH1, BOTH_DEATH25 ); //initialize to good data } } @@ -3312,10 +4058,12 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); VectorCopy( self->currentOrigin, spot ); self->flags |= FL_DISINTEGRATED; + self->svFlags |= SVF_BROADCAST; tent = G_TempEntity( spot, EV_DISINTEGRATION ); tent->s.eventParm = PW_DISRUPTION; + tent->svFlags |= SVF_BROADCAST; tent->owner = self; - + G_AlertTeam( self, attacker, 512, 88 ); if ( self->playerModel >= 0 ) @@ -3339,8 +4087,20 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); } else { - if ( hitLoc == HL_HEAD ) - {//no sound when killed by headshot + if ( hitLoc == HL_HEAD + && !(dflags&DAMAGE_RADIUS) + && meansOfDeath!=MOD_REPEATER_ALT + && meansOfDeath!=MOD_FLECHETTE_ALT + && meansOfDeath!=MOD_ROCKET + && meansOfDeath!=MOD_ROCKET_ALT + && meansOfDeath!=MOD_THERMAL + && meansOfDeath!=MOD_THERMAL_ALT + && meansOfDeath!=MOD_DETPACK + && meansOfDeath!=MOD_LASERTRIP + && meansOfDeath!=MOD_LASERTRIP_ALT + && meansOfDeath!=MOD_EXPLOSIVE + && meansOfDeath!=MOD_EXPLOSIVE_SPLASH ) + {//no sound when killed by headshot (explosions don't count) G_AlertTeam( self, attacker, 512, 0 ); if ( gi.VoiceVolume[self->s.number] ) {//I was talking, so cut it off... with a jump sound? @@ -3349,7 +4109,7 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); } else { - if ( !cliff_fall ) + if ( cliff_fall != 2 ) { if ( meansOfDeath == MOD_KNOCKOUT || meansOfDeath == MOD_MELEE ) { @@ -3375,7 +4135,7 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); //FIXME: danger event so that others will run away from this area since it's obviously dangerous } - if ( anim != -1 ) + if ( anim >= 0 )//can be -1 if it fails, -2 if it's already in a death anim { NPC_SetAnim(self, SETANIM_BOTH, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD); } @@ -3384,7 +4144,7 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); //do any dismemberment if there's any to do... if ( (dflags&DAMAGE_DISMEMBER) && G_DoDismemberment( self, self->pos1, meansOfDeath, damage, hitLoc ) && !specialAnim ) {//we did dismemberment and our death anim is okay to override - if ( hitLoc == HL_HAND_RT && self->locationDamage[hitLoc] >= Q3_INFINITE && !cliff_fall && self->client->ps.groundEntityNum != ENTITYNUM_NONE ) + if ( hitLoc == HL_HAND_RT && self->locationDamage[hitLoc] >= Q3_INFINITE && cliff_fall != 2 && self->client->ps.groundEntityNum != ENTITYNUM_NONE ) {//just lost our right hand and we're on the ground, use the special anim NPC_SetAnim( self, SETANIM_BOTH, BOTH_RIGHTHANDCHOPPEDOFF, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); } @@ -3418,9 +4178,13 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); deathScript = qtrue; } - if ( self->NPC && (self->NPC->scriptFlags&SCF_FFDEATH) && G_ActivateBehavior( self, BSET_FFDEATH ) ) - {//FIXME: should running this preclude running the normal deathscript? - deathScript = qtrue; + if ( self->NPC && (self->NPC->scriptFlags&SCF_FFDEATH) ) + { + if ( G_ActivateBehavior( self, BSET_FFDEATH ) ) + {//FIXME: should running this preclude running the normal deathscript? + deathScript = qtrue; + } + G_UseTargets2( self, self, self->target4 ); } if ( !deathScript && !(self->svFlags&SVF_KILLED_SELF) ) @@ -3647,6 +4411,142 @@ int CheckArmor (gentity_t *ent, int damage, int dflags) } } +extern void NPC_SetPainEvent( gentity_t *self ); +void G_Knockdown( gentity_t *self, gentity_t *attacker, vec3_t pushDir, float strength, qboolean breakSaberLock ) +{ + if ( !self || !self->client || !attacker || !attacker->client ) + { + return; + } + + //break out of a saberLock? + if ( breakSaberLock ) + { + self->client->ps.saberLockTime = 0; + self->client->ps.saberLockEnemy = ENTITYNUM_NONE; + } + + if ( self->health > 0 ) + { + if ( !self->s.number ) + { + NPC_SetPainEvent( self ); + } + else + { + GEntity_PainFunc( self, attacker, attacker, self->currentOrigin, 0, MOD_MELEE ); + } + G_CheckLedgeDive( self, 72, pushDir, qfalse, qfalse ); + + if ( !PM_SpinningSaberAnim( self->client->ps.legsAnim ) + && !PM_FlippingAnim( self->client->ps.legsAnim ) + && !PM_RollingAnim( self->client->ps.legsAnim ) + && !PM_InKnockDown( &self->client->ps ) ) + { + int knockAnim = BOTH_KNOCKDOWN1;//default knockdown + if ( !self->s.number && ( !g_spskill->integer || strength < 300 ) ) + {//player only knocked down if pushed *hard* + return; + } + else if ( PM_CrouchAnim( self->client->ps.legsAnim ) ) + {//crouched knockdown + knockAnim = BOTH_KNOCKDOWN4; + } + else + {//plain old knockdown + vec3_t pLFwd, pLAngles = {0,self->client->ps.viewangles[YAW],0}; + AngleVectors( pLAngles, pLFwd, NULL, NULL ); + if ( DotProduct( pLFwd, pushDir ) > 0.2f ) + {//pushing him from behind + knockAnim = BOTH_KNOCKDOWN3; + } + else + {//pushing him from front + knockAnim = BOTH_KNOCKDOWN1; + } + } + if ( knockAnim == BOTH_KNOCKDOWN1 && strength > 150 ) + {//push *hard* + knockAnim = BOTH_KNOCKDOWN2; + } + NPC_SetAnim( self, SETANIM_BOTH, knockAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + if ( self->s.number ) + {//randomize getup times + int addTime = Q_irand( -300, 1000 ); + self->client->ps.legsAnimTimer += addTime; + self->client->ps.torsoAnimTimer += addTime; + } + } + } +} + +void G_CheckKnockdown( gentity_t *targ, gentity_t *attacker, vec3_t newDir, int dflags, int mod ) +{ + if ( !targ || !attacker ) + { + return; + } + if ( !(dflags&DAMAGE_RADIUS) ) + {//not inherently explosive damage, check mod + if ( mod!=MOD_REPEATER_ALT + &&mod!=MOD_FLECHETTE_ALT + &&mod!=MOD_ROCKET + &&mod!=MOD_ROCKET_ALT + &&mod!=MOD_THERMAL + &&mod!=MOD_THERMAL_ALT + &&mod!=MOD_DETPACK + &&mod!=MOD_LASERTRIP + &&mod!=MOD_LASERTRIP_ALT + &&mod!=MOD_EXPLOSIVE + &&mod!=MOD_EXPLOSIVE_SPLASH ) + { + return; + } + } + + if ( !targ->client || targ->client->NPC_class == CLASS_PROTOCOL || !G_StandardHumanoid( targ->NPC_type ) ) + { + return; + } + + if ( targ->client->ps.groundEntityNum == ENTITYNUM_NONE ) + {//already in air + return; + } + + if ( !targ->s.number ) + {//player less likely to be knocked down + if ( !g_spskill->integer ) + {//never in easy + return; + } + if ( !cg.renderingThirdPerson || cg.zoomMode ) + {//never if not in chase camera view (so more likely with saber out) + return; + } + if ( g_spskill->integer == 1 ) + {//33% chance on medium + if ( Q_irand( 0, 2 ) ) + { + return; + } + } + else + {//50% chance on hard + if ( Q_irand( 0, 1 ) ) + { + return; + } + } + } + + float strength = VectorLength( targ->client->ps.velocity ); + if ( targ->client->ps.velocity[2] > 100 && strength > Q_irand( 150, 350 ) )//600 ) ) + {//explosive concussion possibly do a knockdown? + G_Knockdown( targ, attacker, newDir, strength, qtrue ); + } +} + void G_ApplyKnockback( gentity_t *targ, vec3_t newDir, float knockback ) { vec3_t kvel; @@ -3711,12 +4611,12 @@ void G_ApplyKnockback( gentity_t *targ, vec3_t newDir, float knockback ) } } -int G_CheckForLedge( gentity_t *self, vec3_t fallCheckDir ) +int G_CheckForLedge( gentity_t *self, vec3_t fallCheckDir, float checkDist ) { vec3_t start, end; trace_t tr; - VectorMA( self->currentOrigin, 128, fallCheckDir, end ); + VectorMA( self->currentOrigin, checkDist, fallCheckDir, end ); //Should have clip burshes masked out by now and have bbox resized to death size gi.trace( &tr, self->currentOrigin, self->mins, self->maxs, end, self->s.number, self->clipmask ); if ( tr.allsolid || tr.startsolid ) @@ -3793,8 +4693,113 @@ float damageModifier[HL_MAX] = 1.0f, //HL_GENERIC5, 1.0f, //HL_GENERIC6, }; -/* +void G_TrackWeaponUsage( gentity_t *self, gentity_t *inflictor, int add, int mod ) +{ + if ( !self || !self->client || self->s.number ) + {//player only + return; + } + int weapon = WP_NONE; + //FIXME: need to check the MOD to find out what weapon (if *any*) actually did the killing + if ( inflictor && !inflictor->client && mod != MOD_SABER && inflictor->lastEnemy && inflictor->lastEnemy != self ) + {//a missile that was reflected, ie: not owned by me originally + if ( inflictor->owner == self && self->s.weapon == WP_SABER ) + {//we reflected it + weapon = WP_SABER; + } + } + if ( weapon == WP_NONE ) + { + switch ( mod ) + { + case MOD_SABER: + weapon = WP_SABER; + break; + case MOD_BRYAR: + case MOD_BRYAR_ALT: + weapon = WP_BRYAR_PISTOL; + break; + case MOD_BLASTER: + case MOD_BLASTER_ALT: + weapon = WP_BLASTER; + break; + case MOD_DISRUPTOR: + case MOD_SNIPER: + weapon = WP_DISRUPTOR; + break; + case MOD_BOWCASTER: + case MOD_BOWCASTER_ALT: + weapon = WP_BOWCASTER; + break; + case MOD_REPEATER: + case MOD_REPEATER_ALT: + weapon = WP_REPEATER; + break; + case MOD_DEMP2: + case MOD_DEMP2_ALT: + weapon = WP_DEMP2; + break; + case MOD_FLECHETTE: + case MOD_FLECHETTE_ALT: + weapon = WP_FLECHETTE; + break; + case MOD_ROCKET: + case MOD_ROCKET_ALT: + weapon = WP_ROCKET_LAUNCHER; + break; + case MOD_THERMAL: + case MOD_THERMAL_ALT: + weapon = WP_THERMAL; + break; + case MOD_DETPACK: + weapon = WP_DET_PACK; + break; + case MOD_LASERTRIP: + case MOD_LASERTRIP_ALT: + weapon = WP_TRIP_MINE; + break; + case MOD_MELEE: + if ( self->s.weapon == WP_STUN_BATON ) + { + weapon = WP_STUN_BATON; + } + else if ( self->s.weapon == WP_MELEE ) + { + weapon = WP_MELEE; + } + break; + } + } + if ( weapon != WP_NONE ) + { + self->client->sess.missionStats.weaponUsed[weapon] += add; + } +} + +qboolean G_NonLocationSpecificDamage( int meansOfDeath ) +{ + if ( meansOfDeath == MOD_EXPLOSIVE + || meansOfDeath == MOD_REPEATER_ALT + || meansOfDeath == MOD_FLECHETTE_ALT + || meansOfDeath == MOD_ROCKET + || meansOfDeath == MOD_ROCKET_ALT + || meansOfDeath == MOD_THERMAL + || meansOfDeath == MOD_THERMAL_ALT + || meansOfDeath == MOD_DETPACK + || meansOfDeath == MOD_LASERTRIP + || meansOfDeath == MOD_LASERTRIP_ALT + || meansOfDeath == MOD_MELEE + || meansOfDeath == MOD_FORCE_GRIP + || meansOfDeath == MOD_KNOCKOUT + || meansOfDeath == MOD_CRUSH + || meansOfDeath == MOD_EXPLOSIVE_SPLASH ) + { + return qtrue; + } + return qfalse; +} +/* ============ T_Damage @@ -3840,7 +4845,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ } // if we are the player and we are locked to an emplaced gun, we have to reroute damage to the gun....sigh. - if ( targ->s.eFlags & EF_LOCKED_TO_WEAPON && targ->s.number == 0 && targ->owner ) + if ( targ->s.eFlags & EF_LOCKED_TO_WEAPON && targ->s.number == 0 && targ->owner && !( targ->owner->flags & FL_GODMODE )) { // swapping the gun into our place to absorb our damage targ = targ->owner; @@ -3940,18 +4945,33 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ if ( client->ps.stats[STAT_ARMOR] > 0 ) {//shields are up dflags &= ~DAMAGE_NO_ARMOR;//always affect armor - if ( mod == MOD_ELECTROCUTE ) + if ( mod == MOD_ELECTROCUTE + || mod == MOD_DEMP2 + || mod == MOD_DEMP2_ALT ) {//shield protects us from this damage = 0; } } else {//shields down - if ( mod == MOD_MELEE || (mod == MOD_CRUSH && attacker && attacker->client) ) + if ( mod == MOD_MELEE + || (mod == MOD_CRUSH && attacker && attacker->client) ) {//Galak takes no impact damage return; } - if ( (dflags & DAMAGE_RADIUS) || mod == MOD_SABER ) + if ( (dflags & DAMAGE_RADIUS) + || mod == MOD_REPEATER_ALT + || mod == MOD_FLECHETTE_ALT + || mod == MOD_ROCKET + || mod == MOD_ROCKET_ALT + || mod == MOD_THERMAL + || mod == MOD_THERMAL_ALT + || mod == MOD_DETPACK + || mod == MOD_LASERTRIP + || mod == MOD_LASERTRIP_ALT + || mod == MOD_EXPLOSIVE_SPLASH + || mod == MOD_ENERGY_SPLASH + || mod == MOD_SABER ) {//galak without shields takes quarter damage from explosives and lightsaber damage = ceil((float)damage/4.0f); } @@ -3970,7 +4990,8 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ damage *= 2; } else if ( client->NPC_class == CLASS_PROBE || client->NPC_class == CLASS_INTERROGATOR || - client->NPC_class == CLASS_MARK1 || client->NPC_class == CLASS_MARK2 || client->NPC_class == CLASS_SENTRY ) + client->NPC_class == CLASS_MARK1 || client->NPC_class == CLASS_MARK2 || client->NPC_class == CLASS_SENTRY || + client->NPC_class == CLASS_ATST ) { // DEMP2 does way more damage to these guys. damage *= 5; @@ -4013,12 +5034,16 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ if ( knockback && !(dflags&DAMAGE_DEATH_KNOCKBACK) ) //&& targ->client { G_ApplyKnockback( targ, newDir, knockback ); + G_CheckKnockdown( targ, attacker, newDir, dflags, mod ); } // check for godmode, completely getting out of the damage if ( targ->flags & FL_GODMODE && !(dflags&DAMAGE_NO_PROTECTION) ) { - if ( targ->client && attacker->client && targ->client->playerTeam == attacker->client->playerTeam ) + if ( targ->client + && attacker->client + && targ->client->playerTeam == attacker->client->playerTeam + && (!targ->NPC || !targ->NPC->charmedTime) ) {//complain, but don't turn on them G_FriendlyFireReaction( targ, attacker, dflags ); } @@ -4058,11 +5083,6 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ } */ - if ( !(dflags&DAMAGE_NO_HIT_LOC) ) - { - damage *= damageModifier[hitLoc]; - } - // add to the attacker's hit counter if ( attacker->client && targ != attacker && targ->health > 0 ) { if ( OnSameTeam( targ, attacker ) ) { @@ -4102,10 +5122,16 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ } take -= asave; } + if ( !(dflags&DAMAGE_NO_HIT_LOC) || !(dflags&DAMAGE_RADIUS)) + { + if ( !G_NonLocationSpecificDamage( mod ) ) + {//certain kinds of damage don't care about hitlocation + take = ceil( (float)take*damageModifier[hitLoc] ); + } + } if ( g_debugDamage->integer ) { - gi.Printf( "[%d]client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number, - targ->health, take, asave ); + gi.Printf( "[%d]client:%i health:%i damage:%i armor:%i hitloc:%s\n", level.time, targ->s.number, targ->health, take, asave, hitLocName[hitLoc] ); } // add to the damage inflicted on a player this frame @@ -4145,8 +5171,11 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ add = take; } add += asave; - //FIXME: need to check the MOD to find out what weapon (if *any*) actually did the killing - attacker->client->sess.missionStats.weaponUsed[attacker->client->ps.weapon]++; + add = ceil(add/10.0f); + if ( attacker != targ ) + { + G_TrackWeaponUsage( attacker, inflictor, add, mod ); + } } } if ( take || (dflags&DAMAGE_NO_DAMAGE) ) @@ -4268,10 +5297,19 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ targ->health = 1; } } - else if (targ->health < 0) + else if ( !alreadyDead && (((targ->flags&FL_UNDYING) && !(dflags&DAMAGE_NO_PROTECTION) && !attacker->s.number && !targ->s.number) || (dflags&DAMAGE_NO_KILL)) ) + {// player is undying and he's attacking himself, don't let him die + if ( targ->health < 1 ) + { + G_ActivateBehavior( targ, BSET_DEATH ); + + targ->health = 1; + } + } + else if ( targ->health < 0 ) { targ->health = 0; - if( attacker->s.number == 0 && targ->NPC ) + if ( attacker->s.number == 0 && targ->NPC ) { targ->NPC->scriptFlags |= SCF_FFDEATH; } @@ -4280,7 +5318,10 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ if ( yellAtAttacker ) { - G_FriendlyFireReaction( targ, attacker, dflags ); + if ( !targ->NPC || !targ->NPC->charmedTime ) + { + G_FriendlyFireReaction( targ, attacker, dflags ); + } } } } @@ -4330,7 +5371,6 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ } if ( targ->health <= 0 ) { - if ( knockback && (dflags&DAMAGE_DEATH_KNOCKBACK) )//&& targ->client {//only do knockback on death if ( mod == MOD_FLECHETTE ) @@ -4363,8 +5403,8 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, vec3_ VectorCopy( targ->currentOrigin, targ->pos1 ); } } - if ( !alreadyDead || !targ->enemy ) - {//just killed or didn't have an enemy before + if ( !alreadyDead && !targ->enemy ) + {//just killed and didn't have an enemy before targ->enemy = attacker; } GEntity_DieFunc( targ, inflictor, attacker, take, mod, dflags, hitLoc ); diff --git a/code/game/g_functions.cpp b/code/game/g_functions.cpp index 1069177..d367cdf 100644 --- a/code/game/g_functions.cpp +++ b/code/game/g_functions.cpp @@ -76,7 +76,6 @@ void GEntity_ThinkFunc(gentity_t *self) THINKCASE( MoveOwner ) THINKCASE( SolidifyOwner ) THINKCASE( cycleCamera ) - THINKCASE( WaitNPCRespond ) THINKCASE( spawn_ammo_crystal_trigger ) THINKCASE( NPC_ShySpawn ) THINKCASE( func_wait_return_solid ) @@ -221,7 +220,7 @@ void GEntity_TouchFunc(gentity_t *self, gentity_t *other, trace_t *trace) void GEntity_UseFunc(gentity_t *self, gentity_t *other, gentity_t *activator) { - if ( (self->svFlags&SVF_INACTIVE) ) + if ( !self || (self->svFlags&SVF_INACTIVE) ) { return; } @@ -303,6 +302,7 @@ void GEntity_UseFunc(gentity_t *self, gentity_t *other, gentity_t *activator) USECASE( jabba_cam_use ) USECASE( misc_use ) USECASE( pas_use ) + USECASE( item_spawn_use ) default: Com_Error(ERR_DROP, "GEntity_UseFunc: case %d not handled!\n",self->e_UseFunc); diff --git a/code/game/g_functions.h b/code/game/g_functions.h index f81a753..fddc0db 100644 --- a/code/game/g_functions.h +++ b/code/game/g_functions.h @@ -73,7 +73,6 @@ typedef enum thinkF_MoveOwner, thinkF_SolidifyOwner, thinkF_cycleCamera, - thinkF_WaitNPCRespond, thinkF_spawn_ammo_crystal_trigger, thinkF_NPC_ShySpawn, thinkF_func_wait_return_solid, @@ -172,7 +171,6 @@ extern void trigger_cleared_fire ( gentity_t *self ); extern void MoveOwner ( gentity_t *self ); extern void SolidifyOwner ( gentity_t *self ); extern void cycleCamera ( gentity_t *self ); -extern void WaitNPCRespond ( gentity_t *self ); extern void spawn_ammo_crystal_trigger ( gentity_t *ent ); extern void NPC_ShySpawn ( gentity_t *ent ); extern void func_wait_return_solid ( gentity_t *self ); @@ -386,6 +384,7 @@ typedef enum useF_jabba_cam_use, useF_misc_use, useF_pas_use, + useF_item_spawn_use, } useFunc_t; @@ -463,6 +462,7 @@ extern void welder_use ( gentity_t *self, gentity_t *other, gentity_t *activa extern void jabba_cam_use ( gentity_t *self, gentity_t *other, gentity_t *activator ); extern void misc_use ( gentity_t *self, gentity_t *other, gentity_t *activator ); extern void pas_use ( gentity_t *self, gentity_t *other, gentity_t *activator ); +extern void item_spawn_use ( gentity_t *self, gentity_t *other, gentity_t *activator ); // void (*pain)(gentity_t *self, gentity_t *attacker, int damage,int mod,int hitLoc); typedef enum diff --git a/code/game/g_fx.cpp b/code/game/g_fx.cpp index b566ad2..613f9cd 100644 --- a/code/game/g_fx.cpp +++ b/code/game/g_fx.cpp @@ -5,9 +5,14 @@ #include "g_local.h" #include "g_functions.h" -int G_FindConfigstringIndex( const char *name, int start, int max, qboolean create ); +extern int G_FindConfigstringIndex( const char *name, int start, int max, qboolean create ); + #define FX_ENT_RADIUS 32 +extern int BMS_START; +extern int BMS_MID; +extern int BMS_END; + //---------------------------------------------------------- /*QUAKED fx_runner (0 0 1) (-8 -8 -8) (8 8 8) STARTOFF ONESHOT DAMAGE @@ -24,7 +29,7 @@ Runs the specified effect, can also be targeted at an info_notnull to orient the "random" - random amount of time to add to delay, ( default 0, 200 = 0ms to 200ms ) "splashRadius" - only works when damage is checked ( default 16 ) "splashDamage" - only works when damage is checked ( default 5 ) - + "soundset" - bmodel set to use, plays start sound when toggled on, loop sound while on ( doesn't play on a oneshot), and a stop sound when turned off */ #define FX_RUNNER_RESERVED 0x800000 @@ -55,6 +60,20 @@ void fx_runner_think( gentity_t *ent ) // let our target know that we have spawned an effect G_UseTargets2( ent, ent, ent->target2 ); } + + if ( !(ent->spawnflags & 2 ) && !ent->s.loopSound ) // NOT ONESHOT...this is an assy thing to do + { + if ( VALIDSTRING( ent->soundSet ) == true ) + { + ent->s.loopSound = CAS_GetBModelSound( ent->soundSet, BMS_MID ); + + if ( ent->s.loopSound < 0 ) + { + ent->s.loopSound = 0; + } + } + } + } //---------------------------------------------------------- @@ -72,6 +91,11 @@ void fx_runner_use( gentity_t *self, gentity_t *other, gentity_t *activator ) // let our target know that we have spawned an effect G_UseTargets2( self, self, self->target2 ); } + + if ( VALIDSTRING( self->soundSet ) == true ) + { + G_AddEvent( self, EV_BMODEL_SOUND, CAS_GetBModelSound( self->soundSet, BMS_START )); + } } else { @@ -84,11 +108,28 @@ void fx_runner_use( gentity_t *self, gentity_t *other, gentity_t *activator ) // NOTE: we fire the effect immediately on use, the fx_runner_think func will set // up the nextthink time. fx_runner_think( self ); + + if ( VALIDSTRING( self->soundSet ) == true ) + { + G_AddEvent( self, EV_BMODEL_SOUND, CAS_GetBModelSound( self->soundSet, BMS_START )); + self->s.loopSound = CAS_GetBModelSound( self->soundSet, BMS_MID ); + + if ( self->s.loopSound < 0 ) + { + self->s.loopSound = 0; + } + } } else { // turn off for now self->nextthink = -1; + + if ( VALIDSTRING( self->soundSet ) == true ) + { + G_AddEvent( self, EV_BMODEL_SOUND, CAS_GetBModelSound( self->soundSet, BMS_END )); + self->s.loopSound = 0; + } } } } @@ -143,9 +184,25 @@ void fx_runner_link( gentity_t *ent ) } else { + if ( VALIDSTRING( ent->soundSet ) == true ) + { + ent->s.loopSound = CAS_GetBModelSound( ent->soundSet, BMS_MID ); + + if ( ent->s.loopSound < 0 ) + { + ent->s.loopSound = 0; + } + } + // Let's get to work right now! ent->e_ThinkFunc = thinkF_fx_runner_think; - ent->nextthink = level.time + 100; // wait a small bit, then start working + ent->nextthink = level.time + 200; // wait a small bit, then start working + } + + // make us useable if we can be targeted + if ( ent->targetname ) + { + ent->e_UseFunc = useF_fx_runner_use; } } @@ -164,12 +221,6 @@ void SP_fx_runner( gentity_t *ent ) VectorSet( ent->s.angles, -90, 0, 0 ); } - // make us useable if we can be targeted - if ( ent->targetname ) - { - ent->e_UseFunc = useF_fx_runner_use; - } - if ( !ent->fxFile ) { gi.Printf( S_COLOR_RED"ERROR: fx_runner %s at %s has no fxFile specified\n", ent->targetname, vtos(ent->s.origin) ); @@ -181,9 +232,11 @@ void SP_fx_runner( gentity_t *ent ) // until the CGAME trys to register it... ent->fxID = G_EffectIndex( ent->fxFile ); + ent->s.eType = ET_MOVER; + // Give us a bit of time to spawn in the other entities, since we may have to target one of 'em ent->e_ThinkFunc = thinkF_fx_runner_link; - ent->nextthink = level.time + 300; + ent->nextthink = level.time + 400; // Save our position and link us up! G_SetOrigin( ent, ent->s.origin ); @@ -207,11 +260,16 @@ void SP_CreateSnow( gentity_t *ent ) G_SpawnInt( "count", "1000", &ent->count ); - sprintf( temp, "snow init %i", ent->count ); + cvar_t *r_weatherScale = gi.cvar( "r_weatherScale", "1", CVAR_ARCHIVE ); - G_FindConfigstringIndex( temp, CS_WORLD_FX, MAX_WORLD_FX, qtrue ); + if ( r_weatherScale->value > 0.0f ) + { + sprintf( temp, "snow init %i", (int)( ent->count * r_weatherScale->value )); - level.worldFlags |= WF_SNOWING; + G_FindConfigstringIndex( temp, CS_WORLD_FX, MAX_WORLD_FX, qtrue ); + + level.worldFlags |= WF_SNOWING; + } } /*QUAKED fx_rain (1 0 0) (-16 -16 -16) (16 16 16) @@ -226,11 +284,16 @@ void SP_CreateRain( gentity_t *ent ) G_SpawnInt( "count", "500", &ent->count ); - sprintf( temp, "rain init %i", ent->count ); + cvar_t *r_weatherScale = gi.cvar( "r_weatherScale", "1", CVAR_ARCHIVE ); - G_FindConfigstringIndex( temp, CS_WORLD_FX, MAX_WORLD_FX, qtrue ); + if ( r_weatherScale->value > 0.0f ) + { + sprintf( temp, "rain init %i", (int)( ent->count * r_weatherScale->value )); - level.worldFlags |= WF_RAINING; + G_FindConfigstringIndex( temp, CS_WORLD_FX, MAX_WORLD_FX, qtrue ); + + level.worldFlags |= WF_RAINING; + } } @@ -275,6 +338,11 @@ void fx_explosion_trail_think( gentity_t *ent ) G_PlayEffect( ent->fullName, tr.endpos, tr.plane.normal ); } + if ( VALIDSTRING( ent->soundSet ) == true ) + { + G_AddEvent( ent, EV_BMODEL_SOUND, CAS_GetBModelSound( ent->soundSet, BMS_END )); + } + G_FreeEntity( ent ); return; } @@ -301,7 +369,7 @@ void fx_explosion_trail_use( gentity_t *self, gentity_t *other, gentity_t *activ missile->nextthink = level.time + 50; missile->e_ThinkFunc = thinkF_fx_explosion_trail_think; - missile->s.eType = ET_GENERAL; + missile->s.eType = ET_MOVER; missile->owner = self; @@ -333,6 +401,18 @@ void fx_explosion_trail_use( gentity_t *self, gentity_t *other, gentity_t *activ missile->clipmask = MASK_SHOT; gi.linkentity( missile ); + + if ( VALIDSTRING( self->soundSet ) == true ) + { + G_AddEvent( self, EV_BMODEL_SOUND, CAS_GetBModelSound( self->soundSet, BMS_START )); + missile->s.loopSound = CAS_GetBModelSound( self->soundSet, BMS_MID ); + missile->soundSet = self->soundSet; + + if ( missile->s.loopSound < 0 ) + { + missile->s.loopSound = 0; + } + } } } @@ -342,6 +422,9 @@ void fx_explosion_trail_link( gentity_t *ent ) vec3_t dir; gentity_t *target = NULL; + // we ony activate when used + ent->e_UseFunc = useF_fx_explosion_trail_use; + if ( ent->target ) { // try to use the target to override the orientation @@ -387,6 +470,7 @@ Can also be used for something like a meteor, just add an impact effect ( fxFile "damage" - radius damage ( default 128 ) "splashDamage" - damage when thing impacts ( default 0 ) "splashRadius" - damage radius on impact ( default 0 ) + "soundset" - soundset to use, start sound plays when explosion trail starts, loop sound plays on explosion trail, end sound plays when it impacts */ //---------------------------------------------------------- @@ -421,10 +505,7 @@ void SP_fx_explosion_trail( gentity_t *ent ) // Give us a bit of time to spawn in the other entities, since we may have to target one of 'em ent->e_ThinkFunc = thinkF_fx_explosion_trail_link; - ent->nextthink = level.time + 200; - - // we ony activate when used - ent->e_UseFunc = useF_fx_explosion_trail_use; + ent->nextthink = level.time + 500; // Save our position and link us up! G_SetOrigin( ent, ent->s.origin ); diff --git a/code/game/g_inventory.cpp b/code/game/g_inventory.cpp index 4d153ad..d5e4c5b 100644 --- a/code/game/g_inventory.cpp +++ b/code/game/g_inventory.cpp @@ -17,16 +17,9 @@ qboolean INV_GoodieKeyGive( gentity_t *target ) return (qfalse); } - for ( int i = INV_GOODIE_KEY1; i <= INV_GOODIE_KEY5; i++ ) - { - if ( target->client->ps.inventory[i] == 0 ) - {//fill first empty slot - target->client->ps.inventory[i] = 1; - return (qtrue); - } - } - //no empty slots - return (qfalse); + target->client->ps.inventory[INV_GOODIE_KEY]++; + return (qtrue); + } qboolean INV_GoodieKeyTake( gentity_t *target ) @@ -36,14 +29,12 @@ qboolean INV_GoodieKeyTake( gentity_t *target ) return (qfalse); } - for ( int i = INV_GOODIE_KEY5; i >= INV_GOODIE_KEY1; i-- ) + if (target->client->ps.inventory[INV_GOODIE_KEY]) { - if ( target->client->ps.inventory[i] ) - {//remove last one - target->client->ps.inventory[i] = 0; - return (qtrue); - } + target->client->ps.inventory[INV_GOODIE_KEY]--; + return (qtrue); } + //had no keys return (qfalse); } @@ -55,13 +46,11 @@ int INV_GoodieKeyCheck( gentity_t *target ) return (qfalse); } - for ( int i = INV_GOODIE_KEY5; i >= INV_GOODIE_KEY1; i-- ) - { - if ( target->client->ps.inventory[i] ) - {//found a key - return (i); - } + if ( target->client->ps.inventory[INV_GOODIE_KEY] ) + {//found a key + return (INV_GOODIE_KEY); } + //no keys return (qfalse); } @@ -78,12 +67,12 @@ qboolean INV_SecurityKeyGive( gentity_t *target, const char *keyname ) return qfalse; } - for ( int i = INV_SECURITY_KEY1; i <= INV_SECURITY_KEY5; i++ ) + for ( int i = 0; i <= 4; i++ ) { - if ( target->client->ps.security_key_message[i-INV_SECURITY_KEY1][0] == NULL ) + if ( target->client->ps.security_key_message[i][0] == NULL ) {//fill in the first empty slot we find with this key - target->client->ps.inventory[i] = 1; // He got the key - Q_strncpyz( target->client->ps.security_key_message[i-INV_SECURITY_KEY1], keyname, MAX_SECURITY_KEY_MESSSAGE, qtrue ); + target->client->ps.inventory[INV_SECURITY_KEY]++; // He got the key + Q_strncpyz( target->client->ps.security_key_message[i], keyname, MAX_SECURITY_KEY_MESSSAGE, qtrue ); return qtrue; } } @@ -98,14 +87,14 @@ void INV_SecurityKeyTake( gentity_t *target, char *keyname ) return; } - for ( int i = INV_SECURITY_KEY1; i <= INV_SECURITY_KEY5; i++ ) + for ( int i = 0; i <= 4; i++ ) { - if ( target->client->ps.security_key_message[i-INV_SECURITY_KEY1] ) + if ( target->client->ps.security_key_message[i] ) { - if ( !Q_stricmp( keyname, target->client->ps.security_key_message[i-INV_SECURITY_KEY1] ) ) + if ( !Q_stricmp( keyname, target->client->ps.security_key_message[i] ) ) { - target->client->ps.inventory[i] = 0; // Take the key - target->client->ps.security_key_message[i-INV_SECURITY_KEY1][0] = NULL; + target->client->ps.inventory[INV_SECURITY_KEY]--; // Take the key + target->client->ps.security_key_message[i][0] = NULL; return; } } @@ -126,11 +115,11 @@ qboolean INV_SecurityKeyCheck( gentity_t *target, char *keyname ) return (qfalse); } - for ( int i = INV_SECURITY_KEY1; i <= INV_SECURITY_KEY5; i++ ) + for ( int i = 0; i <= 4; i++ ) { - if ( target->client->ps.inventory[i] && target->client->ps.security_key_message[i-INV_SECURITY_KEY1] ) + if ( target->client->ps.inventory[INV_SECURITY_KEY] && target->client->ps.security_key_message[i] ) { - if ( !Q_stricmp( keyname, target->client->ps.security_key_message[i-INV_SECURITY_KEY1] ) ) + if ( !Q_stricmp( keyname, target->client->ps.security_key_message[i] ) ) { return (qtrue); } diff --git a/code/game/g_itemLoad.cpp b/code/game/g_itemLoad.cpp index c704a70..0034bc9 100644 --- a/code/game/g_itemLoad.cpp +++ b/code/game/g_itemLoad.cpp @@ -421,11 +421,11 @@ static void IT_Tag(const char **holdBuf) } else if (!Q_stricmp(tokenStr,"INV_GOODIE_KEY")) { - tag = INV_GOODIE_KEY1; + tag = INV_GOODIE_KEY; } else if (!Q_stricmp(tokenStr,"INV_SECURITY_KEY")) { - tag = INV_SECURITY_KEY1; + tag = INV_SECURITY_KEY; } else if (!Q_stricmp(tokenStr,"ITM_MEDPAK_PICKUP")) { diff --git a/code/game/g_items.cpp b/code/game/g_items.cpp index e115c7b..ae57f03 100644 --- a/code/game/g_items.cpp +++ b/code/game/g_items.cpp @@ -8,11 +8,14 @@ #include "g_items.h" #include "wp_saber.h" +extern qboolean missionInfo_Updated; extern void CrystalAmmoSettings(gentity_t *ent); extern void G_CreateG2AttachedWeaponModel( gentity_t *ent, const char *weaponModel ); extern void ChangeWeapon( gentity_t *ent, int newWeapon ); extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); +extern qboolean PM_InKnockDown( playerState_t *ps ); +extern qboolean PM_InGetUp( playerState_t *ps ); extern cvar_t *g_spskill; @@ -64,16 +67,16 @@ int Pickup_Holdable( gentity_t *ent, gentity_t *other ) other->client->ps.stats[STAT_ITEMS] |= (1<item->giTag); - if ( ent->item->giTag == INV_SECURITY_KEY1 ) + if ( ent->item->giTag == INV_SECURITY_KEY ) {//give the key //FIXME: temp message - gi.SendServerCommand( NULL, "cp \"You took the security key\"" ); + gi.SendServerCommand( NULL, "cp @INGAME_YOU_TOOK_SECURITY_KEY" ); INV_SecurityKeyGive( other, ent->message ); } - else if ( ent->item->giTag == INV_GOODIE_KEY1 ) + else if ( ent->item->giTag == INV_GOODIE_KEY ) {//give the key //FIXME: temp message - gi.SendServerCommand( NULL, "cp \"You took the key\"" ); + gi.SendServerCommand( NULL, "cp @INGAME_YOU_TOOK_SUPPLY_KEY" ); INV_GoodieKeyGive( other ); } else @@ -134,11 +137,22 @@ int Add_Ammo2 (gentity_t *ent, int ammoType, int count) } else { - ent->client->ps.forcePower += count; + if ( ent->client->ps.forcePower >= ammoData[ammoType].max ) + {//if have full force, just get 25 extra per crystal + ent->client->ps.forcePower += 25; + } + else + {//else if don't have full charge, give full amount, up to max + 25 + ent->client->ps.forcePower += count; + if ( ent->client->ps.forcePower >= ammoData[ammoType].max + 25 ) + {//cap at max + 25 + ent->client->ps.forcePower = ammoData[ammoType].max + 25; + } + } - if (ent->client->ps.forcePower >= ammoData[ammoType].max) - { - ent->client->ps.forcePower = ammoData[ammoType].max; + if ( ent->client->ps.forcePower >= ammoData[ammoType].max*2 ) + {//always cap at twice a full charge + ent->client->ps.forcePower = ammoData[ammoType].max*2; return qfalse; // can't hold any more } } @@ -213,6 +227,7 @@ int Pickup_Battery( gentity_t *ent, gentity_t *other ) extern void WP_SaberInitBladeData( gentity_t *ent ); +extern void CG_ChangeWeapon( int num ); int Pickup_Weapon (gentity_t *ent, gentity_t *other) { int quantity; @@ -251,19 +266,23 @@ int Pickup_Weapon (gentity_t *ent, gentity_t *other) WP_SaberInitBladeData( other ); } - if ( other->s.weapon == WP_NONE && other->s.number ) - {//NPC with no weapon picked up a weapon, change to this weapon - //FIXME: clear/set the alt-fire flag based on the picked up weapon and my class? - other->client->ps.weapon = ent->item->giTag; - other->client->ps.weaponstate = WEAPON_RAISING; - ChangeWeapon( other, ent->item->giTag ); - if ( ent->item->giTag == WP_SABER ) - { - G_CreateG2AttachedWeaponModel( other, other->client->ps.saberModel ); - } - else - { - G_CreateG2AttachedWeaponModel( other, weaponData[ent->item->giTag].weaponMdl ); + if ( other->s.number ) + {//NPC + if ( other->s.weapon == WP_NONE ) + {//NPC with no weapon picked up a weapon, change to this weapon + //FIXME: clear/set the alt-fire flag based on the picked up weapon and my class? + other->client->ps.weapon = ent->item->giTag; + other->client->ps.weaponstate = WEAPON_RAISING; + ChangeWeapon( other, ent->item->giTag ); + if ( ent->item->giTag == WP_SABER ) + { + other->client->ps.saberActive = qtrue; + G_CreateG2AttachedWeaponModel( other, other->client->ps.saberModel ); + } + else + { + G_CreateG2AttachedWeaponModel( other, weaponData[ent->item->giTag].weaponMdl ); + } } } @@ -272,7 +291,6 @@ int Pickup_Weapon (gentity_t *ent, gentity_t *other) // Give ammo Add_Ammo( other, ent->item->giTag, quantity ); } - return 5; } @@ -378,6 +396,13 @@ int Pickup_Holocron( gentity_t *ent, gentity_t *other ) other->client->ps.forcePowerLevel[forcePower] = forceLevel; other->client->ps.forcePowersKnown |= ( 1 << forcePower ); + missionInfo_Updated = qtrue; // Activate flashing text + gi.cvar_set("cg_updatedDataPadForcePower1", va("%d",forcePower+1)); // The +1 is offset in the print routine. + cg_updatedDataPadForcePower1.integer = forcePower+1; + gi.cvar_set("cg_updatedDataPadForcePower2", "0"); // The +1 is offset in the print routine. + cg_updatedDataPadForcePower2.integer = 0; + gi.cvar_set("cg_updatedDataPadForcePower3", "0"); // The +1 is offset in the print routine. + cg_updatedDataPadForcePower3.integer = 0; return 1; } @@ -404,7 +429,7 @@ qboolean CheckItemCanBePickedUpByNPC( gentity_t *item, gentity_t *pickerupper ) && pickerupper->painDebounceTime < level.time && pickerupper->NPC && pickerupper->NPC->surrenderTime < level.time //not surrendering && !(pickerupper->NPC->scriptFlags&SCF_FORCED_MARCH) //not being forced to march - && item->item->giTag != INV_SECURITY_KEY1 ) + && item->item->giTag != INV_SECURITY_KEY ) {//non-player, in combat, picking up a dropped item that does NOT belong to the player and it *not* a security key if ( level.time - item->s.time < 3000 )//was 5000 { @@ -419,6 +444,7 @@ qboolean CheckItemCanBePickedUpByNPC( gentity_t *item, gentity_t *pickerupper ) Touch_Item =============== */ +extern cvar_t *g_timescale; void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) { int respawn = 0; @@ -485,10 +511,22 @@ void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) { return; } + if ( other->client ) + { + if ( other->client->ps.eFlags&EF_FORCE_GRIPPED ) + {//can't pick up anything while being gripped + return; + } + if ( PM_InKnockDown( &other->client->ps ) && !PM_InGetUp( &other->client->ps ) ) + {//can't pick up while in a knockdown + return; + } + } if (!ent->item) { //not an item! gi.Printf( "Touch_Item: %s is not an item!\n", ent->classname); return; } + qboolean bHadWeapon = qfalse; // call the item-specific pickup function switch( ent->item->giType ) { @@ -503,6 +541,10 @@ void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) { TIMER_Set( other, "attackDelay", 600 ); respawn = 0; } + if ( other->client->ps.stats[STAT_WEAPONS] & ( 1 << ent->item->giTag ) ) + { + bHadWeapon = qtrue; + } respawn = Pickup_Weapon(ent, other); break; case IT_AMMO: @@ -533,7 +575,25 @@ void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) { } // play the normal pickup sound - G_AddEvent( other, EV_ITEM_PICKUP, ent->s.modelindex ); + if ( !other->s.number && g_timescale->value < 1.0f ) + {//SIGH... with timescale on, you lose events left and right +extern void CG_ItemPickup( int itemNum, qboolean bHadItem ); + // but we're SP so we'll cheat + cgi_S_StartSound( NULL, other->s.number, CHAN_AUTO, cgi_S_RegisterSound( ent->item->pickup_sound ) ); + // show icon and name on status bar + CG_ItemPickup( ent->s.modelindex, bHadWeapon ); + } + else + { + if ( bHadWeapon ) + { + G_AddEvent( other, EV_ITEM_PICKUP, -ent->s.modelindex ); + } + else + { + G_AddEvent( other, EV_ITEM_PICKUP, ent->s.modelindex ); + } + } // fire item targets G_UseTargets (ent, other); @@ -597,11 +657,17 @@ gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity, char *targ { // if not targeting something, auto-remove after 30 seconds // only if it's NOT a security or goodie key - if( (dropped->item->giTag < INV_SECURITY_KEY1 && dropped->item->giTag > INV_SECURITY_KEY5) ) + if (dropped->item->giTag != INV_SECURITY_KEY ) { dropped->e_ThinkFunc = thinkF_G_FreeEntity; dropped->nextthink = level.time + 30000; } + + if ( dropped->item->giType == IT_AMMO && dropped->item->giTag == AMMO_FORCE ) + { + dropped->nextthink = -1; + dropped->e_ThinkFunc = thinkF_NULL; + } } dropped->e_TouchFunc = touchF_Touch_Item; @@ -833,7 +899,7 @@ void FinishSpawningItem( gentity_t *ent ) { } -qboolean itemRegistered[MAX_ITEMS]; +char itemRegistered[MAX_ITEMS+1]; /* @@ -842,7 +908,8 @@ ClearRegisteredItems ============== */ void ClearRegisteredItems( void ) { - memset( itemRegistered, 0, sizeof( itemRegistered ) ); + memset( itemRegistered, '0', bg_numItems ); + itemRegistered[ bg_numItems ] = 0; RegisterItem( FindItemForWeapon( WP_BRYAR_PISTOL ) ); //these are given in g_client, ClientSpawn(), but MUST be registered HERE, BEFORE cgame starts. RegisterItem( FindItemForWeapon( WP_STUN_BATON ) ); //these are given in g_client, ClientSpawn(), but MUST be registered HERE, BEFORE cgame starts. @@ -864,7 +931,8 @@ void RegisterItem( gitem_t *item ) { if ( !item ) { G_Error( "RegisterItem: NULL" ); } - itemRegistered[ item - bg_itemlist ] = qtrue; + itemRegistered[ item - bg_itemlist ] = '1'; + gi.SetConfigstring(CS_ITEMS, itemRegistered); //Write the needed items to a config string } @@ -877,7 +945,7 @@ so the client will know which ones to precache =============== */ void SaveRegisteredItems( void ) { - char string[MAX_ITEMS+1]; +/* char string[MAX_ITEMS+1]; int i; int count; @@ -894,8 +962,25 @@ void SaveRegisteredItems( void ) { gi.Printf( "%i items registered\n", count ); gi.SetConfigstring(CS_ITEMS, string); +*/ + gi.SetConfigstring(CS_ITEMS, itemRegistered); } +/* +============ +item_spawn_use + + if an item is given a targetname, it will be spawned in when used +============ +*/ +void item_spawn_use( gentity_t *self, gentity_t *other, gentity_t *activator ) +//----------------------------------------------------------------------------- +{ + self->nextthink = level.time + 50; + self->e_ThinkFunc = thinkF_FinishSpawningItem; + // I could be fancy and add a count or something like that to be able to spawn the item numerous times... + self->e_UseFunc = NULL; +} /* ============ @@ -914,10 +999,17 @@ void G_SpawnItem (gentity_t *ent, gitem_t *item) { RegisterItem( item ); ent->item = item; - // some movers spawn on the second frame, so delay item - // spawns until the third frame so they can ride trains - ent->nextthink = level.time + START_TIME_MOVERS_SPAWNED; - ent->e_ThinkFunc = thinkF_FinishSpawningItem; + // targetname indicates they want to spawn it later + if( ent->targetname ) + { + ent->e_UseFunc = useF_item_spawn_use; + } + else + { // some movers spawn on the second frame, so delay item + // spawns until the third frame so they can ride trains + ent->nextthink = level.time + START_TIME_MOVERS_SPAWNED + 50; + ent->e_ThinkFunc = thinkF_FinishSpawningItem; + } ent->physicsBounce = 0.50; // items are bouncy @@ -990,7 +1082,9 @@ void G_RunItem( gentity_t *ent ) { { ent->s.pos.trType = TR_GRAVITY; ent->s.pos.trTime = level.time; - ent->s.pos.trDelta[2] += 100; + ent->s.pos.trDelta[0] += crandom() * 40.0f; // I dunno, just do this?? + ent->s.pos.trDelta[1] += crandom() * 40.0f; + ent->s.pos.trDelta[2] += random() * 20.0f; } return; } diff --git a/code/game/g_items.h b/code/game/g_items.h index 870a330..57c8d3f 100644 --- a/code/game/g_items.h +++ b/code/game/g_items.h @@ -79,16 +79,8 @@ typedef enum //# item_e INV_LIGHTAMP_GOGGLES, INV_SENTRY, //# #eol - INV_GOODIE_KEY1, // don't want to include keys in the icarus list - INV_GOODIE_KEY2, - INV_GOODIE_KEY3, - INV_GOODIE_KEY4, - INV_GOODIE_KEY5, - INV_SECURITY_KEY1, - INV_SECURITY_KEY2, - INV_SECURITY_KEY3, - INV_SECURITY_KEY4, - INV_SECURITY_KEY5, + INV_GOODIE_KEY, // don't want to include keys in the icarus list + INV_SECURITY_KEY, INV_MAX // Be sure to update MAX_INVENTORY }; diff --git a/code/game/g_local.h b/code/game/g_local.h index b68f12e..612f290 100644 --- a/code/game/g_local.h +++ b/code/game/g_local.h @@ -9,6 +9,7 @@ #include "../ui/gameinfo.h" #include "g_shared.h" #include "anims.h" +#include "dmstates.h" //================================================================== @@ -47,6 +48,7 @@ #define FL_LOCK_PLAYER_WEAPONS 0x00010000 // player can't switch weapons... ask james if there's a better spot for this #define FL_DISINTEGRATED 0x00020000 // marks that the corpse has already been disintegrated #define FL_FORCE_PULLABLE_ONLY 0x00040000 // cannot be force pushed +#define FL_NO_IMPACT_DMG 0x00080000 // Will not take impact damage //Pointer safety utilities #define VALID( a ) ( a != NULL ) @@ -113,6 +115,7 @@ typedef struct alertEvent_s float light; //ambient light level at point float addLight; //additional light- makes it more noticable, even in darkness int ID; //unique... if get a ridiculous number, this will repeat, but should not be a problem as it's just comparing it to your lastAlertID + int timestamp; //when it was created } alertEvent_t; // @@ -164,6 +167,8 @@ typedef struct int numKnownAnimFileSets; int worldFlags; + + int dmState; //actually, we do want save/load the dynamic music state // ===================================== // // NOTE!!!!!! The only things beyond this point in the structure should be the ones you do NOT wish to be @@ -184,7 +189,6 @@ typedef struct int numCombatPoints; char spawntarget[MAX_QPATH]; // the targetname of the spawnpoint you want the player to start at - int dmState; int dmDebounceTime; int dmBeatTime; } level_locals_t; @@ -486,9 +490,9 @@ void G_WriteSessionData( void ); // NPC_senses.cpp // extern void AddSightEvent( gentity_t *owner, vec3_t position, float radius, alertEventLevel_e alertLevel, float addLight=0.0f ); -extern void AddSoundEvent( gentity_t *owner, vec3_t position, float radius, alertEventLevel_e alertLevel ); +extern void AddSoundEvent( gentity_t *owner, vec3_t position, float radius, alertEventLevel_e alertLevel, qboolean needLOS = qfalse ); extern qboolean G_CheckForDanger( gentity_t *self, int alertEvent ); -extern int G_CheckAlertEvents( gentity_t *self, qboolean checkSight, qboolean checkSound, float maxSeeDist, float maxHearDist, qboolean mustHaveOwner = qfalse, int minAlertLevel = AEL_MINOR ); +extern int G_CheckAlertEvents( gentity_t *self, qboolean checkSight, qboolean checkSound, float maxSeeDist, float maxHearDist, int ignoreAlert = -1, qboolean mustHaveOwner = qfalse, int minAlertLevel = AEL_MINOR ); extern qboolean G_CheckForDanger( gentity_t *self, int alertEvent ); extern qboolean G_ClearLOS( gentity_t *self, const vec3_t start, const vec3_t end ); extern qboolean G_ClearLOS( gentity_t *self, gentity_t *ent, const vec3_t end ); @@ -565,14 +569,4 @@ void TIMER_Remove( gentity_t *ent, const char *identifier ); float NPC_GetHFOVPercentage( vec3_t spot, vec3_t from, vec3_t facing, float hFOV ); float NPC_GetVFOVPercentage( vec3_t spot, vec3_t from, vec3_t facing, float vFOV ); -//dynamic music -typedef enum -{ - DM_SILENCE, - DM_EXPLORE, - DM_ACTION, - DM_BOSS, - DM_DEATH -} dynamicMusic_t; - #endif//#ifndef __G_LOCAL_H__ diff --git a/code/game/g_main.cpp b/code/game/g_main.cpp index 8d57098..885d4bb 100644 --- a/code/game/g_main.cpp +++ b/code/game/g_main.cpp @@ -12,6 +12,7 @@ #include "b_local.h" #include "anims.h" #include "g_icarus.h" +#include "objectives.h" #include "../cgame/cg_local.h" // yeah I know this is naughty, but we're shipping soon... extern CNavigator navigator; @@ -111,6 +112,7 @@ cvar_t *g_timescale; cvar_t *g_knockback; cvar_t *g_dismemberment; cvar_t *g_dismemberProbabilities; +cvar_t *g_synchSplitAnims; cvar_t *g_inactivity; cvar_t *g_debugMove; @@ -120,9 +122,15 @@ cvar_t *g_subtitles; cvar_t *g_ICARUSDebug; cvar_t *com_buildScript; cvar_t *g_skippingcin; -cvar_t *g_autoBlocking; -cvar_t *g_realisticSaberDamage; cvar_t *g_AIsurrender; +cvar_t *g_numEntities; +cvar_t *g_iscensored; + +cvar_t *g_saberAutoBlocking; +cvar_t *g_saberRealisticCombat; +cvar_t *g_saberMoveSpeed; +cvar_t *g_saberAnimSpeed; +cvar_t *g_saberAutoAim; qboolean stop_icarus = qfalse; @@ -156,15 +164,14 @@ static void G_DynamicMusicUpdate( void ) int numListedEntities; vec3_t mins, maxs; int i, e; - int radius = 2048; + int distSq, radius = 2048; vec3_t center; int danger = 0; int battle = 0; int entTeam; qboolean dangerNear = qfalse; qboolean suspicious = qfalse; - //qboolean distraction = qfalse; - //qboolean mysterious = qfalse; + qboolean LOScalced = qfalse, clearLOS = qfalse; //FIXME: intro and/or other cues? (one-shot music sounds) @@ -177,18 +184,36 @@ static void G_DynamicMusicUpdate( void ) return; } - if ( !player->client || player->client->pers.teamState.state != TEAM_ACTIVE ) + if ( !player->client + || player->client->pers.teamState.state != TEAM_ACTIVE + || level.time - player->client->pers.enterTime < 100 ) {//player hasn't spawned yet return; } - if ( player->health <= 0 ) - {//FIXME: defeat music? + if ( player->health <= 0 && player->max_health > 0 ) + {//defeat music if ( level.dmState != DM_DEATH ) { - gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "death" ); level.dmState = DM_DEATH; } + } + + if ( level.dmState == DM_DEATH ) + { + gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "death" ); + return; + } + + if ( level.dmState == DM_BOSS ) + { + gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "boss" ); + return; + } + + if ( level.dmState == DM_SILENCE ) + { + gi.SetConfigstring( CS_DYNAMIC_MUSIC_STATE, "silence" ); return; } @@ -257,6 +282,7 @@ static void G_DynamicMusicUpdate( void ) continue; } + LOScalced = clearLOS = qfalse; if ( (ent->enemy==player&&(!ent->NPC||ent->NPC->confusionTimeclient&&ent->client->ps.weaponTime) || (!ent->client&&ent->attackDebounceTime>level.time)) {//mad if ( ent->health > 0 ) @@ -266,6 +292,34 @@ static void G_DynamicMusicUpdate( void ) {//a Jedi who has not yet gotten made at me continue; } + if ( ent->NPC && ent->NPC->behaviorState == BS_CINEMATIC ) + {//they're not actually going to do anything about being mad at me... + continue; + } + //okay, they're in my PVS, but how close are they? Are they actively attacking me? + if ( !ent->client && ent->s.weapon == WP_TURRET && ent->fly_sound_debounce_time && ent->fly_sound_debounce_time - level.time < 10000 ) + {//a turret that shot at me less than ten seconds ago + } + else if ( ent->client && ent->client->ps.lastShotTime && ent->client->ps.lastShotTime - level.time < 10000 ) + {//an NPC that shot at me less than ten seconds ago + } + else + {//not actively attacking me lately, see how far away they are + distSq = DistanceSquared( ent->currentOrigin, player->currentOrigin ); + if ( distSq > 4194304/*2048*2048*/ ) + {//> 2048 away + continue; + } + else if ( distSq > 1048576/*1024*1024*/ ) + {//> 1024 away + clearLOS = G_ClearLOS( player, player->client->renderInfo.eyePoint, ent ); + LOScalced = qtrue; + if ( clearLOS == qfalse ) + {//No LOS + continue; + } + } + } battle++; } } @@ -277,7 +331,11 @@ static void G_DynamicMusicUpdate( void ) continue; } - if ( !G_ClearLOS( player, player->client->renderInfo.eyePoint, ent ) ) + if ( !LOScalced ) + { + clearLOS = G_ClearLOS( player, player->client->renderInfo.eyePoint, ent ); + } + if ( !clearLOS ) {//can't see them directly continue; } @@ -297,7 +355,7 @@ static void G_DynamicMusicUpdate( void ) if ( !battle ) {//no active enemies, but look for missiles, shot impacts, etc... - int alert = G_CheckAlertEvents( player, qtrue, qtrue, 1024, 1024, qfalse, AEL_SUSPICIOUS ); + int alert = G_CheckAlertEvents( player, qtrue, qtrue, 1024, 1024, -1, qfalse, AEL_SUSPICIOUS ); if ( alert != -1 ) {//FIXME: maybe tripwires and other FIXED things need their own sound, some kind of danger/caution theme if ( G_CheckForDanger( player, alert ) ) @@ -460,7 +518,7 @@ G_InitCvars */ void G_InitCvars( void ) { // don't override the cheat state set by the system - g_cheats = gi.cvar ("sv_cheats", "", 0); + g_cheats = gi.cvar ("helpUsObi", "", 0); g_developer = gi.cvar ("developer", "", 0); // noset vars @@ -472,12 +530,13 @@ void G_InitCvars( void ) { // change anytime vars g_speed = gi.cvar( "g_speed", "250", CVAR_CHEAT ); - g_gravity = gi.cvar( "g_gravity", "800", CVAR_USERINFO|CVAR_CHEAT ); //using userinfo as savegame flag + g_gravity = gi.cvar( "g_gravity", "800", CVAR_USERINFO|CVAR_ROM ); //using userinfo as savegame flag g_sex = gi.cvar ("sex", "male", CVAR_USERINFO | CVAR_ARCHIVE ); g_spskill = gi.cvar ("g_spskill", "0", CVAR_ARCHIVE | CVAR_USERINFO); //using userinfo as savegame flag g_knockback = gi.cvar( "g_knockback", "1000", CVAR_CHEAT ); g_dismemberment = gi.cvar ( "g_dismemberment", "3", CVAR_ARCHIVE );//0 = none, 1 = arms and hands, 2 = legs, 3 = waist and head, 4 = mega dismemberment g_dismemberProbabilities = gi.cvar ( "g_dismemberProbabilities", "1", CVAR_ARCHIVE );//0 = ignore probabilities, 1 = use probabilities + g_synchSplitAnims = gi.cvar ( "g_synchSplitAnims", "1", 0 ); g_inactivity = gi.cvar ("g_inactivity", "0", 0); g_debugMove = gi.cvar ("g_debugMove", "0", CVAR_CHEAT ); @@ -488,9 +547,18 @@ void G_InitCvars( void ) { g_subtitles = gi.cvar( "g_subtitles", "2", CVAR_ARCHIVE ); com_buildScript = gi.cvar ("com_buildscript", "0", 0); - g_autoBlocking = gi.cvar( "autoBlocking", "1", 0 ); - g_realisticSaberDamage = gi.cvar( "g_realisticSaberDamage", "0", CVAR_CHEAT ); + g_saberAutoBlocking = gi.cvar( "g_saberAutoBlocking", "1", CVAR_ARCHIVE|CVAR_CHEAT );//must press +block button to do any blocking + g_saberRealisticCombat = gi.cvar( "g_saberRealisticCombat", "0", CVAR_ARCHIVE|CVAR_CHEAT );//makes collision more precise, increases damage + g_saberMoveSpeed = gi.cvar( "g_saberMoveSpeed", "1", CVAR_ARCHIVE|CVAR_CHEAT );//how fast you run while attacking with a saber + g_saberAnimSpeed = gi.cvar( "g_saberAnimSpeed", "1", CVAR_ARCHIVE|CVAR_CHEAT );//how fast saber animations run + g_saberAutoAim = gi.cvar( "g_saberAutoAim", "1", CVAR_ARCHIVE|CVAR_CHEAT );//auto-aims at enemies when not moving or when just running forward + g_AIsurrender = gi.cvar( "g_AIsurrender", "0", CVAR_CHEAT ); + g_numEntities = gi.cvar( "g_numEntities", "0", CVAR_CHEAT ); + + gi.cvar( "newTotalSecrets", "0", CVAR_ROM ); + gi.cvar_set("newTotalSecrets", "0");//used to carry over the count from SP_target_secret to ClientBegin + g_iscensored = gi.cvar( "ui_iscensored", "0", CVAR_ARCHIVE|CVAR_ROM|CVAR_INIT|CVAR_CHEAT|CVAR_NORESTART ); } /* @@ -592,7 +660,7 @@ void InitGame( const char *mapname, const char *spawntarget, int checkSum, cons // general initialization G_FindTeams(); - SaveRegisteredItems(); +// SaveRegisteredItems(); gi.Printf ("-----------------------------------\n"); @@ -683,6 +751,7 @@ Returns a pointer to the structure with all entry points and global variables ================= */ +extern int PM_ValidateAnimRange( int startFrame, int endFrame, float animSpeed ); game_export_t *GetGameAPI( game_import_t *import ) { gameinfo_import_t gameinfo_import; @@ -708,6 +777,8 @@ game_export_t *GetGameAPI( game_import_t *import ) { globals.ConsoleCommand = ConsoleCommand; globals.PrintEntClassname = PrintEntClassname; + globals.ValidateAnimRange = PM_ValidateAnimRange; + globals.gentitySize = sizeof(gentity_t); gameinfo_import.FS_FOpenFile = gi.FS_FOpenFile; @@ -716,6 +787,7 @@ game_export_t *GetGameAPI( game_import_t *import ) { gameinfo_import.Cvar_Set = gi.cvar_set; gameinfo_import.Cvar_VariableStringBuffer = gi.Cvar_VariableStringBuffer; gameinfo_import.Cvar_Create = G_Cvar_Create; + GI_Init( &gameinfo_import ); return &globals; @@ -830,7 +902,7 @@ void G_CheckSpecialPersistentEvents( gentity_t *ent ) if ( eventClearTime == level.time + ALERT_CLEAR_TIME ) {//events were just cleared out so add me again //NOTE: presumes the player did the pushing, this is not always true, but shouldn't really matter? - if ( ent->item && ent->item->giTag == INV_SECURITY_KEY1 ) + if ( ent->item && ent->item->giTag == INV_SECURITY_KEY ) { AddSightEvent( player, ent->currentOrigin, 128, AEL_DISCOVERED );//security keys are more important } @@ -1072,8 +1144,28 @@ void UpdateTeamCounters( gentity_t *ent ) teamEnemyCount[ent->client->playerTeam]++; } */ +extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); +void G_PlayerGuiltDeath( void ) +{ + if ( player && player->client ) + {//simulate death + player->client->ps.stats[STAT_HEALTH] = 0; + //turn off saber + if ( player->client->ps.weapon == WP_SABER && player->client->ps.saberActive ) + { + G_SoundOnEnt( player, CHAN_WEAPON, "sound/weapons/saber/saberoff.wav" ); + player->client->ps.saberActive = qfalse; + } + //play the "what have I done?!" anim + NPC_SetAnim( player, SETANIM_BOTH, BOTH_FORCEHEAL_START, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + player->client->ps.legsAnimTimer = player->client->ps.torsoAnimTimer = -1; + //look at yourself + player->client->ps.stats[STAT_DEAD_YAW] = player->client->ps.viewangles[YAW]+180; + } +} extern void NPC_SetAnim(gentity_t *ent,int type,int anim,int priority); extern void G_MakeTeamVulnerable( void ); +int killPlayerTimer = 0; void G_CheckEndLevelTimers( gentity_t *ent ) { if ( killPlayerTimer && level.time > killPlayerTimer ) @@ -1082,24 +1174,13 @@ void G_CheckEndLevelTimers( gentity_t *ent ) ent->health = 0; if ( ent->client && ent->client->ps.stats[STAT_HEALTH] > 0 ) { - //simulate death - ent->client->ps.stats[STAT_HEALTH] = 0; + G_PlayerGuiltDeath(); + //cg.missionStatusShow = qtrue; + statusTextIndex = MAX_MISSIONFAILED; //debounce respawn time ent->client->respawnTime = level.time + 2000; - //play the "what have I done?!" anim -// NPC_SetAnim( ent, SETANIM_BOTH, BOTH_GUILT1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - /* - NPC_SetAnim( ent, SETANIM_TORSO, BOTH_SIT2TO1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - NPC_SetAnim( ent, SETANIM_LEGS, LEGS_KNEELDOWN1, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - */ - ent->client->ps.torsoAnimTimer = -1; - ent->client->ps.legsAnimTimer = -1; - //look at yourself - ent->client->ps.stats[STAT_DEAD_YAW] = ent->client->ps.viewangles[YAW]+180; //stop all scripts - if (Q_stricmpn(level.mapname,"_holo",5)) { - stop_icarus = qtrue; - } + stop_icarus = qtrue; //make the team killable G_MakeTeamVulnerable(); } @@ -1132,6 +1213,7 @@ void NAV_CheckCalcPaths( void ) navCalcPathTime = 0; } } + /* ================ G_RunFrame @@ -1150,12 +1232,12 @@ void G_RunFrame( int levelTime ) { int i; gentity_t *ent; int msec; - + int ents_inuse=0; // someone's gonna be pissed I put this here... #if AI_TIMERS AITime = 0; navTime = 0; #endif// AI_TIMERS - + level.framenum++; level.previousTime = level.time; level.time = levelTime; @@ -1181,7 +1263,7 @@ void G_RunFrame( int levelTime ) { if(!PInUse(i)) continue; - + ent = &g_entities[i]; if ( ent->waypoint != WAYPOINT_NONE @@ -1197,10 +1279,10 @@ void G_RunFrame( int levelTime ) { } //Look to clear out old events - if ( eventClearTime < level.time ) + //if ( eventClearTime < level.time ) { ClearPlayerAlertEvents(); - eventClearTime = level.time + ALERT_CLEAR_TIME; + //eventClearTime = level.time + ALERT_CLEAR_TIME; } //Run the frame for all entities @@ -1212,7 +1294,7 @@ void G_RunFrame( int levelTime ) { if(!PInUse(i)) continue; - + ents_inuse++; ent = &g_entities[i]; // clear events that are too old @@ -1257,18 +1339,6 @@ void G_RunFrame( int levelTime ) { } } } -/* -Ghoul2 Insert Start -*/ - - if (ent->ghoul2.IsValid()) - { - gi.G2API_AnimateG2Models(ent->ghoul2, cg.time); - } -/* -Ghoul2 Insert End -*/ - G_CheckSpecialPersistentEvents( ent ); if ( ent->s.eType == ET_MISSILE ) @@ -1342,7 +1412,10 @@ Ghoul2 Insert End { ClientEndFrame( ent ); } - + if( g_numEntities->integer ) + { + gi.Printf( S_COLOR_WHITE"Number of Entities in use : %d\n", ents_inuse ); + } //DEBUG STUFF NAV_ShowDebugInfo(); NPC_ShowDebugInfo(); diff --git a/code/game/g_misc.cpp b/code/game/g_misc.cpp index 82fc644..3814e9c 100644 --- a/code/game/g_misc.cpp +++ b/code/game/g_misc.cpp @@ -581,6 +581,10 @@ void camera_aim( gentity_t *self ) G_ClearViewEntity( player ); G_Sound( player, self->soundPos2 ); self->painDebounceTime = level.time + (self->wait*1000);//FRAMETIME*5;//don't check for player buttons for 500 ms + if ( player->client->usercmd.upmove > 0 ) + {//stop player from doing anything for a half second after + player->aimDebounceTime = level.time + 500; + } } else if ( self->painDebounceTime < level.time ) {//check for use button @@ -611,6 +615,7 @@ void camera_aim( gentity_t *self ) vectoangles( dir, angles ); //FIXME: if a G2 model, do a bone override..??? VectorCopy( self->currentAngles, self->s.apos.trBase ); + for( int i = 0; i < 3; i++ ) { angles[i] = AngleNormalize180( angles[i] ); @@ -621,6 +626,17 @@ void camera_aim( gentity_t *self ) self->s.apos.trTime = level.time; self->s.apos.trDuration = FRAMETIME; VectorCopy( angles, self->currentAngles ); + + if ( DistanceSquared( self->currentAngles, self->lastAngles ) > 0.01f ) // if it moved at all, start a loop sound? not exactly the "bestest" solution + { + self->s.loopSound = G_SoundIndex( "sound/movers/objects/cameramove_lp2" ); + } + else + { + self->s.loopSound = 0; // not moving so don't bother + } + + VectorCopy( self->currentAngles, self->lastAngles ); //G_SetAngles( self, angles ); } } @@ -657,6 +673,8 @@ void SP_misc_camera( gentity_t *self ) self->s.modelindex3 = self->s.modelindex = G_ModelIndex( "models/map_objects/kejim/impcam.md3" ); self->soundPos1 = G_SoundIndex( "sound/movers/camera_on.mp3" ); self->soundPos2 = G_SoundIndex( "sound/movers/camera_off.mp3" ); + G_SoundIndex( "sound/movers/objects/cameramove_lp2" ); + G_SetOrigin( self, self->s.origin ); G_SetAngles( self, self->s.angles ); self->s.apos.trType = TR_LINEAR_STOP;//TR_INTERPOLATE;// @@ -2054,28 +2072,31 @@ void ammo_power_converter_use( gentity_t *self, gentity_t *other, gentity_t *act self->count -= add; } - } - if ( self->count <= 0 ) - { - G_Sound( self, G_SoundIndex( "sound/interface/ammocon_empty.mp3" )); - self->setTime = level.time + 1000; // extra debounce so that the sounds don't overlap too much - self->s.loopSound = 0; - - if ( self->s.eFlags & EF_SHADER_ANIM ) + if ( self->count <= 0 ) { - self->s.frame = 1; + // play empty sound + self->setTime = level.time + 1000; // extra debounce so that the sounds don't overlap too much + G_Sound( self, G_SoundIndex( "sound/interface/ammocon_empty.mp3" )); + self->s.loopSound = 0; + + if ( self->s.eFlags & EF_SHADER_ANIM ) + { + self->s.frame = 1; + } + } + else if ( ps->ammo[AMMO_BLASTER] >= ammoData[AMMO_BLASTER].max + && ps->ammo[AMMO_POWERCELL] >= ammoData[AMMO_POWERCELL].max + && ps->ammo[AMMO_METAL_BOLTS] >= ammoData[AMMO_METAL_BOLTS].max ) + { + // play full sound + G_Sound( self, G_SoundIndex( "sound/interface/ammocon_done.wav" )); + self->setTime = level.time + 1000; // extra debounce so that the sounds don't overlap too much + self->s.loopSound = 0; } } - else if ( ps->ammo[AMMO_BLASTER] >= ammoData[AMMO_BLASTER].max - && ps->ammo[AMMO_POWERCELL] >= ammoData[AMMO_POWERCELL].max - && ps->ammo[AMMO_METAL_BOLTS] >= ammoData[AMMO_METAL_BOLTS].max ) - { - G_Sound( self, G_SoundIndex( "sound/interface/ammocon_done.wav" )); - self->setTime = level.time + 1000; // extra debounce so that the sounds don't overlap too much - self->s.loopSound = 0; - } + if ( self->s.loopSound ) { // we will have to shut of the loop sound, so I guess try and do it intelligently...NOTE: this could get completely stomped every time through the loop @@ -2160,7 +2181,8 @@ welder_think void welder_think( gentity_t *self ) { self->nextthink = level.time + 200; - vec3_t org; + vec3_t org, + dir; mdxaBone_t boltMatrix; if( self->svFlags & SVF_INACTIVE ) @@ -2176,13 +2198,18 @@ void welder_think( gentity_t *self ) if ( newBolt != -1 ) { - G_PlayEffect( "blueWeldSparks", self->playerModel, newBolt, self->s.number); + G_Sound( self, self->noise_index ); + // G_PlayEffect( "blueWeldSparks", self->playerModel, newBolt, self->s.number); // The welder gets rotated around a lot, and since the origin is offset by 352 I have to make this super expensive call to position the hurt... gi.G2API_GetBoltMatrix( self->ghoul2, self->playerModel, newBolt, &boltMatrix, self->currentAngles, self->currentOrigin, (cg.time?cg.time:level.time), NULL, self->s.modelScale ); gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org ); + VectorSubtract( self->currentOrigin, org, dir ); + VectorNormalize( dir ); + // we want the welder effect to face inwards.... + G_PlayEffect( "blueWeldSparks", org, dir ); G_RadiusDamage( org, self, 10, 45, self, MOD_UNKNOWN ); } @@ -2226,6 +2253,7 @@ void SP_misc_model_welder( gentity_t *ent ) ent->takedamage = qfalse; ent->contents = 0; G_EffectIndex( "blueWeldSparks" ); + ent->noise_index = G_SoundIndex( "sound/movers/objects/welding.wav" ); ent->s.modelindex = G_ModelIndex( "models/map_objects/cairn/welder.glm" ); // ent->s.modelindex2 = G_ModelIndex( "models/map_objects/cairn/welder.md3" ); @@ -2564,7 +2592,7 @@ void misc_atst_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, VectorCopy( self->currentOrigin, effectPos ); effectPos[2] -= 15; G_PlayEffect( "droidexplosion1", effectPos ); - G_PlayEffect( "small_chunks", effectPos ); +// G_PlayEffect( "small_chunks", effectPos ); //set these to defaults that work in a worst-case scenario (according to current animation.cfg) gi.G2API_StopBoneAnimIndex( &self->ghoul2[self->playerModel], self->craniumBone ); misc_atst_setanim( self, self->rootBone, BOTH_DEATH1 ); @@ -2594,6 +2622,7 @@ void misc_atst_use( gentity_t *self, gentity_t *other, gentity_t *activator ) G_SetOrigin( activator, self->currentOrigin ); //copy angles + VectorCopy( self->s.angles2, self->currentAngles ); G_SetAngles( activator, self->currentAngles ); SetClientViewAngle( activator, self->currentAngles ); @@ -2616,6 +2645,10 @@ void misc_atst_use( gentity_t *self, gentity_t *other, gentity_t *activator ) activator->locationDamage[hl] = self->locationDamage[hl]; self->locationDamage[hl] = tempLocDmg[hl]; } + if ( !self->s.number ) + { + CG_CenterPrint( "@INGAME_EXIT_VIEW", SCREEN_HEIGHT * 0.95 ); + } } else {//get out of ATST @@ -2628,11 +2661,12 @@ void misc_atst_use( gentity_t *self, gentity_t *other, gentity_t *activator ) } //FIXME: after a load/save, this crashes, BAD... somewhere in G2 G_SetOrigin( self, activator->currentOrigin ); - VectorCopy( activator->currentAngles, self->currentAngles ); - self->currentAngles[PITCH] = activator->currentAngles[ROLL] = 0; + VectorSet( self->currentAngles, 0, activator->client->ps.legsYaw, 0 ); + //self->currentAngles[PITCH] = activator->currentAngles[ROLL] = 0; G_SetAngles( self, self->currentAngles ); + VectorCopy( activator->currentAngles, self->s.angles2 ); //remove my G2 - if ( self->playerModel != -1 ) + if ( self->playerModel >= 0 ) { gi.G2API_RemoveGhoul2Model( self->ghoul2, self->playerModel ); self->playerModel = -1; @@ -2666,6 +2700,7 @@ void misc_atst_use( gentity_t *self, gentity_t *other, gentity_t *activator ) //open the hatch misc_atst_setanim( self, self->craniumBone, BOTH_STAND2 ); gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "head_hatchcover_off", 0 ); + G_Sound( self, G_SoundIndex( "sound/chars/atst/atst_hatch_open" )); } } @@ -2686,10 +2721,13 @@ void SP_misc_atst_drivable( gentity_t *ent ) RegisterItem( FindItemForWeapon( WP_ATST_SIDE )); //precache the weapon //HACKHACKHACKTEMP - until ATST gets real weapons of it's own? RegisterItem( FindItemForWeapon( WP_EMPLACED_GUN )); //precache the weapon - RegisterItem( FindItemForWeapon( WP_ROCKET_LAUNCHER )); //precache the weapon - RegisterItem( FindItemForWeapon( WP_BOWCASTER )); //precache the weapon +// RegisterItem( FindItemForWeapon( WP_ROCKET_LAUNCHER )); //precache the weapon +// RegisterItem( FindItemForWeapon( WP_BOWCASTER )); //precache the weapon //HACKHACKHACKTEMP - until ATST gets real weapons of it's own? + G_SoundIndex( "sound/chars/atst/atst_hatch_open" ); + G_SoundIndex( "sound/chars/atst/atst_hatch_close" ); + NPC_ATST_Precache(); ent->NPC_type = "atst"; NPC_PrecacheAnimationCFG( ent->NPC_type ); @@ -2712,6 +2750,7 @@ void SP_misc_atst_drivable( gentity_t *ent ) G_SetOrigin( ent, ent->s.origin ); G_SetAngles( ent, ent->s.angles ); + VectorCopy( ent->currentAngles, ent->s.angles2 ); gi.linkentity ( ent ); diff --git a/code/game/g_misc_model.cpp b/code/game/g_misc_model.cpp index 70b2685..2c550d7 100644 --- a/code/game/g_misc_model.cpp +++ b/code/game/g_misc_model.cpp @@ -264,26 +264,13 @@ void GunRackAddItem( gitem_t *gun, vec3_t org, vec3_t angs, float ffwd, float fr switch( gun->giTag ) { case WP_BLASTER: - it_ent->count = 20; + it_ent->count = 15; break; case WP_REPEATER: - it_ent->count = 40; + it_ent->count = 100; break; case WP_ROCKET_LAUNCHER: - it_ent->count = 2; - break; - } - - // then scale based on skill - switch ( g_spskill->integer ) - { - case 0: - it_ent->count *= 5; - break; - case 1: - it_ent->count *= 3; - break; - case 2: // No soup for you!, or something.. + it_ent->count = 4; break; } } @@ -305,17 +292,27 @@ void GunRackAddItem( gitem_t *gun, vec3_t org, vec3_t angs, float ffwd, float fr if ( gun->giType == IT_AMMO ) { - // scale ammo based on skill - switch ( g_spskill->integer ) + if ( gun->giTag == AMMO_BLASTER ) // I guess this just has to use different logic?? { - case 0: // do default - break; - case 1: - it_ent->count *= 0.75f; - break; - case 2: - it_ent->count *= 0.5f; - break; + if ( g_spskill->integer >= 2 ) + { + it_ent->count += 10; // give more on higher difficulty because there will be more/harder enemies? + } + } + else + { + // scale ammo based on skill + switch ( g_spskill->integer ) + { + case 0: // do default + break; + case 1: + it_ent->count *= 0.75f; + break; + case 2: + it_ent->count *= 0.5f; + break; + } } } @@ -330,6 +327,7 @@ void GunRackAddItem( gitem_t *gun, vec3_t org, vec3_t angs, float ffwd, float fr // by doing this, we can force the amount of ammo we desire onto the weapon for when it gets picked-up it_ent->flags |= ( FL_DROPPED_ITEM | FL_FORCE_PULLABLE_ONLY ); + it_ent->physicsBounce = 0.1f; for ( int t = 0; t < 3; t++ ) { diff --git a/code/game/g_missile.cpp b/code/game/g_missile.cpp index 4756c26..69fe295 100644 --- a/code/game/g_missile.cpp +++ b/code/game/g_missile.cpp @@ -9,7 +9,7 @@ extern qboolean InFront( vec3_t spot, vec3_t from, vec3_t fromAngles, float threshHold = 0.0f ); qboolean LogAccuracyHit( gentity_t *target, gentity_t *attacker ); -extern qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir ); +extern qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir, int mod ); extern qboolean PM_SaberInParry( int move ); extern qboolean PM_SaberInReflect( int move ); extern qboolean PM_SaberInIdle( int move ); @@ -40,25 +40,39 @@ void G_MissileBounceEffect( gentity_t *ent, vec3_t org, vec3_t dir ) } } +void G_MissileReflectEffect( gentity_t *ent, vec3_t org, vec3_t dir ) +{ + //FIXME: have an EV_BOUNCE_MISSILE event that checks the s.weapon and does the appropriate effect + switch( ent->s.weapon ) + { + case WP_BOWCASTER: + G_PlayEffect( "bowcaster/deflect", ent->currentOrigin, dir ); + break; + case WP_BLASTER: + case WP_BRYAR_PISTOL: + default: + G_PlayEffect( "blaster/deflect", ent->currentOrigin, dir ); + break; + } +} + //------------------------------------------------------------------------- static void G_MissileStick( gentity_t *missile, gentity_t *other, trace_t *tr ) { if ( other->NPC || !Q_stricmp( other->classname, "misc_model_breakable" )) { // we bounce off of NPC's and misc model breakables because sticking to them requires too much effort - vec3_t dir; + vec3_t velocity; + int hitTime = level.previousTime + ( level.time - level.previousTime ) * tr->fraction; + + EvaluateTrajectoryDelta( &missile->s.pos, hitTime, velocity ); + + float dot = DotProduct( velocity, tr->plane.normal ); G_SetOrigin( missile, tr->endpos ); - - // get our bounce direction, not accurate, but it simplifies things. - dir[0] = missile->s.pos.trDelta[0] + crandom() * 40.0f; // randomize bounce a bit - dir[1] = missile->s.pos.trDelta[1] + crandom() * 40.0f; - dir[2] = 0;//missile->s.pos.trDelta[2] * 0.1f;// kill upward thrust - - VectorNormalize( dir ); - - VectorScale( dir, -72, missile->s.pos.trDelta ); - missile->s.pos.trTime = level.time - 100; // move a bit on the first frame + VectorMA( velocity, -1.6f * dot, tr->plane.normal, missile->s.pos.trDelta ); + VectorMA( missile->s.pos.trDelta, 10, tr->plane.normal, missile->s.pos.trDelta ); + missile->s.pos.trTime = level.time - 10; // move a bit on the first frame // check for stop if ( tr->entityNum >= 0 && tr->entityNum < ENTITYNUM_WORLD && @@ -383,8 +397,11 @@ void G_BounceMissile( gentity_t *ent, trace_t *trace ) { VectorCopy( ent->currentOrigin, ent->s.pos.trBase ); VectorCopy( trace->plane.normal, ent->pos1 ); - if ( ent->s.weapon != WP_SABER && ent->s.weapon != WP_THERMAL ) - {//not a saber + if ( ent->s.weapon != WP_SABER + && ent->s.weapon != WP_THERMAL + && ent->e_clThinkFunc != clThinkF_CG_Limb + && ent->e_ThinkFunc != thinkF_LimbThink ) + {//not a saber, bouncing thermal or limb //now you can damage the guy you came from ent->owner = NULL; } @@ -399,6 +416,7 @@ G_MissileImpact extern void WP_SaberBlock( gentity_t *saber, vec3_t hitloc, qboolean missleBlock ); extern void laserTrapStick( gentity_t *ent, vec3_t endpos, vec3_t normal ); +extern qboolean W_AccuracyLoggableWeapon( int weapon, qboolean alt_fire, int mod ); void G_MissileImpacted( gentity_t *ent, gentity_t *other, vec3_t impactPos, vec3_t normal, int hitLoc=HL_NONE ) { // impact damage @@ -415,14 +433,6 @@ void G_MissileImpacted( gentity_t *ent, gentity_t *other, vec3_t impactPos, vec3 velocity[2] = 1; // stepped on a grenade } - if ( ent->owner ) - { - if( LogAccuracyHit( other, ent->owner ) ) - { - ent->owner->client->ps.persistant[PERS_ACCURACY_HITS]++; - } - } - int damage = ent->damage; if( other->client ) @@ -432,7 +442,7 @@ void G_MissileImpacted( gentity_t *ent, gentity_t *other, vec3_t impactPos, vec3 // If we are a robot and we aren't currently doing the full body electricity... 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_REMOTE || - npc_class == CLASS_PROTOCOL || npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || + npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || //npc_class == CLASS_PROTOCOL ||//no protocol, looks odd npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY ) { // special droid only behaviors @@ -442,17 +452,13 @@ void G_MissileImpacted( gentity_t *ent, gentity_t *other, vec3_t impactPos, vec3 other->s.powerups |= ( 1 << PW_SHOCKED ); other->client->ps.powerups[PW_SHOCKED] = level.time + 450; } + //FIXME: throw some sparks off droids,too } } G_Damage( other, ent, ent->owner, velocity, impactPos, damage, ent->dflags, ent->methodOfDeath, hitLoc); - - if ( ent->owner && !ent->owner->s.number && ent->owner->client ) - { - ent->owner->client->sess.missionStats.hits++; - } } } @@ -460,7 +466,7 @@ void G_MissileImpacted( gentity_t *ent, gentity_t *other, vec3_t impactPos, vec3 // one, rather than changing the missile into the explosion? //G_FreeEntity(ent); - if ( other->takedamage && other->client ) + if ( (other->takedamage && other->client ) || (ent->s.weapon == WP_FLECHETTE && other->contents&CONTENTS_LIGHTSABER) ) { G_AddEvent( ent, EV_MISSILE_HIT, DirToByte( normal ) ); ent->s.otherEntityNum = other->s.number; @@ -471,6 +477,8 @@ void G_MissileImpacted( gentity_t *ent, gentity_t *other, vec3_t impactPos, vec3 ent->s.otherEntityNum = other->s.number; } + VectorCopy( normal, ent->pos1 ); + if ( ent->owner )//&& ent->owner->s.number == 0 ) { //Add the event @@ -526,6 +534,23 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace, int hitLoc=HL_NONE ) assert(0&&"missile hit itself!!!"); return; } + if ( ent->owner && (other->takedamage||other->client) ) + { + if ( !ent->lastEnemy || ent->lastEnemy == ent->owner ) + {//a missile that was not reflected or, if so, still is owned by original owner + if( LogAccuracyHit( other, ent->owner ) ) + { + ent->owner->client->ps.persistant[PERS_ACCURACY_HITS]++; + } + if ( ent->owner->client && !ent->owner->s.number ) + { + if ( W_AccuracyLoggableWeapon( ent->s.weapon, qfalse, ent->methodOfDeath ) ) + { + ent->owner->client->sess.missionStats.hits++; + } + } + } + } // check for bounce //OR: if the surfaceParm is has a reflect property (magnetic shielding) and the missile isn't an exploding missile qboolean bounce = !!( (!other->takedamage && (ent->s.eFlags&(EF_BOUNCE|EF_BOUNCE_HALF))) || (((trace->surfaceFlags&SURF_FORCEFIELD)||(other->flags&FL_SHIELDED))&&!ent->splashDamage&&!ent->splashRadius) ); @@ -578,7 +603,7 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace, int hitLoc=HL_NONE ) } } - if ( other->NPC) + if ( other->NPC ) { G_Damage( other, ent, ent->owner, ent->currentOrigin, ent->s.pos.trDelta, 0, DAMAGE_NO_DAMAGE, MOD_UNKNOWN ); } @@ -595,19 +620,29 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace, int hitLoc=HL_NONE ) } // I would glom onto the EF_BOUNCE code section above, but don't feel like risking breaking something else - if ( (!other->takedamage && ( ent->s.eFlags&(EF_BOUNCE_SHRAPNEL) ) ) || ((trace->surfaceFlags&SURF_FORCEFIELD)&&!ent->splashDamage&&!ent->splashRadius) ) + if ( (!other->takedamage && ( ent->s.eFlags&(EF_BOUNCE_SHRAPNEL) ) ) + || ((trace->surfaceFlags&SURF_FORCEFIELD)&&!ent->splashDamage&&!ent->splashRadius) ) { - G_BounceMissile( ent, trace ); - - if ( --ent->bounceCount < 0 ) + if ( !(other->contents&CONTENTS_LIGHTSABER) + || g_spskill->integer <= 0//on easy, it reflects all shots + || (g_spskill->integer == 1 && ent->s.weapon != WP_FLECHETTE && ent->s.weapon != WP_DEMP2 )//on medium it won't reflect flechette or demp shots + || (g_spskill->integer >= 2 && ent->s.weapon != WP_FLECHETTE && ent->s.weapon != WP_DEMP2 && ent->s.weapon != WP_BOWCASTER && ent->s.weapon != WP_REPEATER )//on hard it won't reflect flechette, demp, repeater or bowcaster shots + ) { - ent->s.eFlags &= ~EF_BOUNCE_SHRAPNEL; + G_BounceMissile( ent, trace ); + + if ( --ent->bounceCount < 0 ) + { + ent->s.eFlags &= ~EF_BOUNCE_SHRAPNEL; + } + G_MissileBounceEffect( ent, trace->endpos, trace->plane.normal ); + return; } - G_MissileBounceEffect( ent, trace->endpos, trace->plane.normal ); - return; } - if ( !other->takedamage && ent->s.weapon == WP_THERMAL && !ent->alt_fire ) + if ( (!other->takedamage || (other->client && other->health <= 0)) + && ent->s.weapon == WP_THERMAL + && !ent->alt_fire ) {//rolling thermal det - FIXME: make this an eFlag like bounce & stick!!! //G_BounceRollMissile( ent, trace ); if ( ent->owner )//&& ent->owner->s.number == 0 ) @@ -645,35 +680,45 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace, int hitLoc=HL_NONE ) } // check for hitting a lightsaber - if ( other->contents & CONTENTS_LIGHTSABER - && ( g_spskill->integer <= 0//on easy, it reflects all shots - || (g_spskill->integer == 1 && ent->s.weapon != WP_FLECHETTE && ent->s.weapon != WP_DEMP2 )//on medium it won't reflect flechette or demp shots - || (g_spskill->integer >= 2 && ent->s.weapon != WP_FLECHETTE && ent->s.weapon != WP_DEMP2 && ent->s.weapon != WP_BOWCASTER && ent->s.weapon != WP_REPEATER )//on hard it won't reflect flechette, demp, repeater or bowcaster shots - ) - && (!ent->splashDamage || !ent->splashRadius) )//this would be cool, though, to "bat" the thermal det away... - { - //FIXME: take other's owner's FP_SABER_DEFENSE into account here somehow? - if ( !other->owner || !other->owner->client || other->owner->client->ps.saberInFlight || InFront( ent->currentOrigin, other->owner->currentOrigin, other->owner->client->ps.viewangles, SABER_REFLECT_MISSILE_CONE ) )//other->owner->s.number != 0 || - {//Jedi cannot block shots from behind! - if ( (other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_1 && Q_irand( 0, 3 )) - ||(other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_0 && Q_irand( 0, 1 ))) - {//level 1 reflects 50% of the time, level 2 reflects 75% of the time - VectorSubtract(ent->currentOrigin, other->currentOrigin, diff); - VectorNormalize(diff); - //FIXME: take other's owner's FP_SABER_DEFENSE into account here somehow? - G_ReflectMissile( other, ent, diff); - //WP_SaberBlock( other, ent->currentOrigin, qtrue ); - if ( other->owner && other->owner->client ) - { - other->owner->client->ps.saberEventFlags |= SEF_DEFLECTED; + if ( other->contents & CONTENTS_LIGHTSABER ) + { + if ( other->owner && !other->owner->s.number && other->owner->client ) + { + other->owner->client->sess.missionStats.saberBlocksCnt++; + } + if ( ( g_spskill->integer <= 0//on easy, it reflects all shots + || (g_spskill->integer == 1 && ent->s.weapon != WP_FLECHETTE && ent->s.weapon != WP_DEMP2 )//on medium it won't reflect flechette or demp shots + || (g_spskill->integer >= 2 && ent->s.weapon != WP_FLECHETTE && ent->s.weapon != WP_DEMP2 && ent->s.weapon != WP_BOWCASTER && ent->s.weapon != WP_REPEATER )//on hard it won't reflect flechette, demp, repeater or bowcaster shots + ) + && (!ent->splashDamage || !ent->splashRadius) )//this would be cool, though, to "bat" the thermal det away... + { + //FIXME: take other's owner's FP_SABER_DEFENSE into account here somehow? + if ( !other->owner || !other->owner->client || other->owner->client->ps.saberInFlight || InFront( ent->currentOrigin, other->owner->currentOrigin, other->owner->client->ps.viewangles, SABER_REFLECT_MISSILE_CONE ) )//other->owner->s.number != 0 || + {//Jedi cannot block shots from behind! + if ( (other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_1 && Q_irand( 0, 3 )) + ||(other->owner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_0 && Q_irand( 0, 1 ))) + {//level 1 reflects 50% of the time, level 2 reflects 75% of the time + VectorSubtract(ent->currentOrigin, other->currentOrigin, diff); + VectorNormalize(diff); + //FIXME: take other's owner's FP_SABER_DEFENSE into account here somehow? + G_ReflectMissile( other, ent, diff); + //WP_SaberBlock( other, ent->currentOrigin, qtrue ); + if ( other->owner && other->owner->client ) + { + other->owner->client->ps.saberEventFlags |= SEF_DEFLECTED; + } + //do the effect + VectorCopy( ent->s.pos.trDelta, diff ); + VectorNormalize( diff ); + G_MissileReflectEffect( ent, trace->endpos, trace->plane.normal ); + return; } - //do the effect - VectorCopy( ent->s.pos.trDelta, diff ); - VectorNormalize( diff ); - G_MissileBounceEffect( ent, trace->endpos, trace->plane.normal ); - return; } } + else + {//still do the bounce effect + G_MissileReflectEffect( ent, trace->endpos, trace->plane.normal ); + } } G_MissileImpacted( ent, other, trace->endpos, trace->plane.normal, hitLoc ); @@ -1256,7 +1301,7 @@ void G_RunMissile( gentity_t *ent ) if (trHitLoc==HL_NONE) { - G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &trHitLoc, coll.mCollisionPosition, NULL, NULL ); + G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &trHitLoc, coll.mCollisionPosition, NULL, NULL, ent->methodOfDeath ); } break; // NOTE: the way this whole section was working, it would only get inside of this IF once anyway, might as well break out now diff --git a/code/game/g_mover.cpp b/code/game/g_mover.cpp index 44b063b..d77f8db 100644 --- a/code/game/g_mover.cpp +++ b/code/game/g_mover.cpp @@ -899,8 +899,11 @@ void UnLockDoors(gentity_t *const ent) //go through and unlock the door and all the slaves gentity_t *slave = ent; do - { - slave->targetname = NULL;//not usable ever again + { // want to allow locked toggle doors, so keep the targetname + if( !(slave->spawnflags & MOVER_TOGGLE) ) + { + slave->targetname = NULL;//not usable ever again + } slave->spawnflags &= ~MOVER_LOCKED; slave->s.frame = 1;//second stage of anim slave = slave->teamchain; @@ -962,7 +965,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) key = INV_GoodieKeyCheck( activator ); if (key) {//activator has a goodie key, remove it - activator->client->ps.inventory[key] = 0; + activator->client->ps.inventory[key]--; G_Sound( activator, G_SoundIndex( "sound/movers/goodie_pass.wav" ) ); // once the goodie mover has been used, it no longer requires a goodie key ent->spawnflags &= ~MOVER_GOODIE; @@ -971,7 +974,7 @@ void Use_BinaryMover( gentity_t *ent, gentity_t *other, gentity_t *activator ) { //don't have a goodie key G_Sound( activator, G_SoundIndex( "sound/movers/goodie_fail.wav" ) ); ent->fly_sound_debounce_time = level.time + 5000; - text = "cp \"You need a key to open\""; + text = "cp @INGAME_NEED_KEY_TO_OPEN"; //FIXME: temp message, only on certain difficulties?, graphic instead of text? gi.SendServerCommand( NULL, text ); return; @@ -1121,16 +1124,19 @@ void Blocked_Door( gentity_t *ent, gentity_t *other ) { // remove anything other than a client -- no longer the case // don't remove security keys or goodie keys - if ( (other->s.eType == ET_ITEM) && (other->item->giTag >= INV_GOODIE_KEY1 && other->item->giTag <= INV_SECURITY_KEY5) ) + if ( (other->s.eType == ET_ITEM) && (other->item->giTag >= INV_GOODIE_KEY && other->item->giTag <= INV_SECURITY_KEY) ) { // should we be doing anything special if a key blocks it... move it somehow..? } // if your not a client, or your a dead client remove yourself... else if ( other->s.number && (!other->client || (other->client && other->health <= 0 && other->contents == CONTENTS_CORPSE && !other->message)) ) { - // if an item or weapon can we do a little explosion..? - G_FreeEntity( other ); - return; + if ( !other->taskManager || !other->taskManager->IsRunning() ) + { + // if an item or weapon can we do a little explosion..? + G_FreeEntity( other ); + return; + } } if ( ent->damage ) { @@ -1740,6 +1746,13 @@ The wait time at a corner has completed, so start moving again =============== */ void Think_BeginMoving( gentity_t *ent ) { + + if ( ent->spawnflags & 2048 ) + { + // this tie fighter hack is done for doom_detention, where the shooting gallery takes place. let them draw again when they start moving + ent->s.eFlags &= ~EF_NODRAW; + } + ent->s.pos.trTime = level.time; if ( ent->alt_fire ) { @@ -1831,6 +1844,12 @@ void Reached_Train( gentity_t *ent ) { } } + // This is for the tie fighter shooting gallery on doom detention, you could see them waiting under the bay, but the architecture couldn't easily be changed.. + if (( next->spawnflags & 2 )) + { + ent->s.eFlags |= EF_NODRAW; // make us invisible until we start moving again + } + // if there is a "wait" value on the target, don't start moving yet if ( next->wait ) { @@ -1838,6 +1857,11 @@ void Reached_Train( gentity_t *ent ) { ent->e_ThinkFunc = thinkF_Think_BeginMoving; ent->s.pos.trType = TR_STATIONARY; } + else if (!( next->spawnflags & 2 )) + { + // we aren't waiting to start, so let us draw right away + ent->s.eFlags &= ~EF_NODRAW; + } } void TrainUse( gentity_t *ent, gentity_t *other, gentity_t *activator ) @@ -1859,7 +1883,7 @@ void Think_SetupTrainTargets( gentity_t *ent ) { if ( !ent->nextTrain ) { gi.Printf( "func_train at %s with an unfound target\n", vtos(ent->absmin) ); - //Free me? + //Free me?` return; } @@ -1918,9 +1942,11 @@ void Think_SetupTrainTargets( gentity_t *ent ) { -/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TURN_TRAIN +/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) TURN_TRAIN INVISIBLE TURN_TRAIN func_train moving on this path will turn to face the next path_corner within 2 seconds +INVISIBLE - train will become invisible ( but still solid ) when it reaches this path_corner. + It will become visible again at the next path_corner that does not have this option checked Train path corners. Target: next path corner and other targets to fire @@ -2147,9 +2173,25 @@ void func_rotating_use( gentity_t *self, gentity_t *other, gentity_t *activator if( self->s.apos.trType == TR_LINEAR ) { self->s.apos.trType = TR_STATIONARY; + // stop the sound if it stops moving + self->s.loopSound = 0; + // play stop sound too? + if ( VALIDSTRING( self->soundSet ) == true ) + { + G_AddEvent( self, EV_BMODEL_SOUND, CAS_GetBModelSound( self->soundSet, BMS_END )); + } } else { + if ( VALIDSTRING( self->soundSet ) == true ) + { + G_AddEvent( self, EV_BMODEL_SOUND, CAS_GetBModelSound( self->soundSet, BMS_START )); + self->s.loopSound = CAS_GetBModelSound( self->soundSet, BMS_MID ); + if ( self->s.loopSound < 0 ) + { + self->s.loopSound = 0; + } + } self->s.apos.trType = TR_LINEAR; } } @@ -2452,7 +2494,10 @@ void SP_func_wall( gentity_t *ent ) void security_panel_use( gentity_t *self, gentity_t *other, gentity_t *activator ) { - + if ( !activator ) + { + return; + } if ( INV_SecurityKeyCheck( activator, self->message ) ) {//congrats! gi.SendServerCommand( NULL, "cp @INGAME_SECURITY_KEY_UNLOCKEDDOOR" ); @@ -2473,7 +2518,7 @@ void security_panel_use( gentity_t *self, gentity_t *other, gentity_t *activator } else {//failure sound/display - if ( self->message ) + if ( activator->message ) {//have a key, just the wrong one gi.SendServerCommand( NULL, "cp @INGAME_INCORRECT_KEY" ); } diff --git a/code/game/g_nav.cpp b/code/game/g_nav.cpp index 21f353f..a91f2bb 100644 --- a/code/game/g_nav.cpp +++ b/code/game/g_nav.cpp @@ -99,7 +99,14 @@ void NPC_SetMoveGoal( gentity_t *ent, vec3_t point, int radius, qboolean isNavGo ent->NPC->tempGoal->target = NULL; ent->NPC->tempGoal->clipmask = ent->clipmask; ent->NPC->tempGoal->svFlags &= ~SVF_NAVGOAL; - ent->NPC->tempGoal->waypoint = WAYPOINT_NONE; + if ( targetEnt && targetEnt->waypoint >= 0 ) + { + ent->NPC->tempGoal->waypoint = targetEnt->waypoint; + } + else + { + ent->NPC->tempGoal->waypoint = WAYPOINT_NONE; + } ent->NPC->tempGoal->noWaypointTime = 0; if ( isNavGoal ) @@ -971,7 +978,7 @@ int NAV_TestBestNode( gentity_t *self, int startID, int endID, qboolean failEdge //path is blocked by a locked door, mark it as such if instructed to do so if ( failEdge ) { - // navigator.AddFailedEdge( self->s.number, startID, endID ); + navigator.AddFailedEdge( self->s.number, startID, endID ); } } } diff --git a/code/game/g_navigator.cpp b/code/game/g_navigator.cpp index a6e9cb1..4325d7f 100644 --- a/code/game/g_navigator.cpp +++ b/code/game/g_navigator.cpp @@ -17,6 +17,7 @@ extern qboolean G_EntIsBreakable( int entityNum ); extern qboolean G_EntIsRemovableUsable( int entNum ); extern cvar_t *d_altRoutes; +extern cvar_t *d_patched; static vec3_t wpMaxs = { 16, 16, 32 }; @@ -1674,7 +1675,7 @@ void CNavigator::SetCheckedNode(int wayPoint,int ent,byte value) } #define CHECK_FAILED_EDGE_INTERVAL 1000 -#define CHECK_FAILED_EDGE_INTITIAL 10000 +#define CHECK_FAILED_EDGE_INTITIAL 5000//10000 void CNavigator::CheckFailedNodes( gentity_t *ent ) { @@ -1765,6 +1766,28 @@ qboolean CNavigator::NodeFailed( gentity_t *ent, int nodeID ) return qfalse; } +qboolean CNavigator::NodesAreNeighbors( int startID, int endID ) +{//See if these 2 are neighbors + if ( startID == endID ) + { + return qfalse; + } + + CNode *start = m_nodes[startID]; + int nextID = -1; + //NOTE: we only check start because we assume all connections are 2-way + for ( int i = 0; i < start->GetNumEdges(); i++ ) + { + nextID = start->GetEdge(i); + if ( nextID == endID ) + { + return qtrue; + } + } + //not neighbors + return qfalse; +} + void CNavigator::ClearFailedEdge( failedEdge_t *failedEdge ) { if ( !failedEdge ) @@ -1863,6 +1886,14 @@ void CNavigator::AddFailedEdge( int entID, int startID, int endID ) if ( m_nodes.size() == 0 ) return; + if ( d_patched->integer ) + {//use patch-style navigation + if ( startID == endID ) + {//not an edge! + return; + } + } + //Validate the ent number if ( ( entID < 0 ) || ( entID > ENTITYNUM_NONE ) ) { diff --git a/code/game/g_navigator.h b/code/game/g_navigator.h index 51595ab..3b474be 100644 --- a/code/game/g_navigator.h +++ b/code/game/g_navigator.h @@ -185,6 +185,7 @@ public: void CheckFailedNodes( gentity_t *ent ); void AddFailedNode( gentity_t *ent, int nodeID ); qboolean NodeFailed( gentity_t *ent, int nodeID ); + qboolean NodesAreNeighbors( int startID, int endID ); void ClearFailedEdge( failedEdge_t *failedEdge ); void ClearAllFailedEdges( void ); qboolean EdgeFailed( int startID, int endID ); diff --git a/code/game/g_navnew.cpp b/code/game/g_navnew.cpp index cf7d2fb..07de0a8 100644 --- a/code/game/g_navnew.cpp +++ b/code/game/g_navnew.cpp @@ -9,6 +9,9 @@ //Global navigator extern CNavigator navigator; extern cvar_t *d_altRoutes; +extern cvar_t *d_patched; +extern vec3_t playerMins; +extern vec3_t playerMaxs; qboolean NAV_CheckAhead( gentity_t *self, vec3_t end, trace_t &trace, int clipmask ); qboolean NAV_TestForBlocked( gentity_t *self, gentity_t *goal, gentity_t *blocker, float distance, int &flags ); @@ -87,7 +90,12 @@ void NAVNEW_PushBlocker( gentity_t *self, gentity_t *blocker, vec3_t right, qboo return; } - if ( !VectorCompare( blocker->s.pushVec, vec3_origin ) ) + if ( !blocker->s.number ) + {//never push the player + return; + } + + if ( !blocker->client || !VectorCompare( blocker->client->pushVec, vec3_origin ) ) {//someone else is pushing him, wait until they give up? return; } @@ -114,7 +122,8 @@ void NAVNEW_PushBlocker( gentity_t *self, gentity_t *blocker, vec3_t right, qboo if ( leftSucc >= 1.0f ) {//it's clear, shove him that way - VectorScale( right, -moveamt, blocker->s.pushVec ); + VectorScale( right, -moveamt, blocker->client->pushVec ); + blocker->client->pushVecTime = level.time + 2000; } else { @@ -131,21 +140,28 @@ void NAVNEW_PushBlocker( gentity_t *self, gentity_t *blocker, vec3_t right, qboo if ( leftSucc == 0.0f && rightSucc == 0.0f ) {//both sides failed + if ( d_patched->integer ) + {//use patch-style navigation + blocker->client->pushVecTime = 0; + } return; } if ( rightSucc >= 1.0f ) {//it's clear, shove him that way - VectorScale( right, moveamt, blocker->s.pushVec ); + VectorScale( right, moveamt, blocker->client->pushVec ); + blocker->client->pushVecTime = level.time + 2000; } //if neither are enough, we probably can't get around him, but keep trying else if ( leftSucc >= rightSucc ) {//favor the left, all things being equal - VectorScale( right, -moveamt, blocker->s.pushVec ); + VectorScale( right, -moveamt, blocker->client->pushVec ); + blocker->client->pushVecTime = level.time + 2000; } else { - VectorScale( right, moveamt, blocker->s.pushVec ); + VectorScale( right, moveamt, blocker->client->pushVec ); + blocker->client->pushVecTime = level.time + 2000; } } @@ -453,6 +469,10 @@ qboolean NAVNEW_AvoidCollision( gentity_t *self, gentity_t *goal, navInfo_t &inf { if ( self->NPC->consecutiveBlockedMoves > blockedMovesLimit ) { + if ( d_patched->integer ) + {//use patch-style navigation + self->NPC->consecutiveBlockedMoves++; + } NPC_SetBlocked( self, info.blocker ); return qfalse; } @@ -497,6 +517,55 @@ qboolean NAVNEW_AvoidCollision( gentity_t *self, gentity_t *goal, navInfo_t &inf return qtrue; } +qboolean NAVNEW_TestNodeConnectionBlocked( int wp1, int wp2, gentity_t *ignoreEnt, int goalEntNum, qboolean checkWorld, qboolean checkEnts ) +{//see if the direct path between 2 nodes is blocked by architecture or an ent + vec3_t pos1, pos2, mins, maxs; + trace_t trace; + int clipmask = MASK_NPCSOLID|CONTENTS_BOTCLIP; + int ignoreEntNum; + + if ( !checkWorld && !checkEnts ) + {//duh, nothing to trace against + return qfalse; + } + navigator.GetNodePosition( wp1, pos1 ); + navigator.GetNodePosition( wp2, pos2 ); + + if ( !checkWorld ) + { + clipmask &= ~(CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP); + } + if ( !checkEnts ) + { + clipmask &= ~CONTENTS_BODY; + } + if ( ignoreEnt ) + { + VectorCopy( ignoreEnt->mins, mins ); + VectorCopy( ignoreEnt->maxs, maxs ); + ignoreEntNum = ignoreEnt->s.number; + } + else + { + VectorCopy( playerMins, mins ); + VectorCopy( playerMaxs, mins ); + ignoreEntNum = ENTITYNUM_NONE; + } + mins[2] += STEPSIZE; + //don't let box get inverted + if ( mins[2] > maxs[2] ) + { + mins[2] = maxs[2]; + } + + gi.trace( &trace, pos1, mins, maxs, pos2, ignoreEntNum, clipmask ); + if ( trace.fraction >= 1.0f || trace.entityNum == goalEntNum ) + {//clear or hit goal + return qfalse; + } + //hit something we weren't supposed to + return qtrue; +} /* ------------------------- NAVNEW_MoveToGoal @@ -580,6 +649,7 @@ int NAVNEW_MoveToGoal( gentity_t *self, navInfo_t &info ) } */ navigator.GetNodePosition( bestNode, origin ); + /* if ( !goalWPFailed ) {//we haven't already tried to go straight to goal or goal's wp if ( bestNode == self->NPC->goalEntity->waypoint ) @@ -595,6 +665,7 @@ int NAVNEW_MoveToGoal( gentity_t *self, navInfo_t &info ) } } } + */ if ( !inGoalWP ) {//not heading straight for goal if ( bestNode == self->waypoint ) @@ -646,6 +717,15 @@ int NAVNEW_MoveToGoal( gentity_t *self, navInfo_t &info ) NPC_ClearBlocked( self ); //Take the dir memcpy( &info, &tempInfo, sizeof( info ) ); + if ( self->s.weapon == WP_SABER ) + {//jedi + if ( info.direction[2] * info.distance > 64 ) + { + self->NPC->aiFlags |= NPCAI_BLOCKED; + VectorCopy( origin, NPCInfo->blockedDest ); + goto failed; + } + } } else {//blocked by ent! @@ -675,7 +755,15 @@ int NAVNEW_MoveToGoal( gentity_t *self, navInfo_t &info ) {//we headed toward our next waypoint (instead of our waypoint) and failed if ( d_altRoutes->integer ) {//mark this edge failed and try our waypoint - navigator.AddFailedEdge( self->s.number, self->waypoint, bestNode ); + //NOTE: don't assume there is something blocking the direct path + // between my waypoint and the bestNode... I could be off + // that path because of collision avoidance... + if ( d_patched->integer &&//use patch-style navigation + ( !navigator.NodesAreNeighbors( self->waypoint, bestNode ) + || NAVNEW_TestNodeConnectionBlocked( self->waypoint, bestNode, self, self->NPC->goalEntity->s.number, qfalse, qtrue ) ) ) + {//the direct path between these 2 nodes is blocked by an ent + navigator.AddFailedEdge( self->s.number, self->waypoint, bestNode ); + } bestNode = self->waypoint; } else diff --git a/code/game/g_public.h b/code/game/g_public.h index 3bcfd68..9973e1f 100644 --- a/code/game/g_public.h +++ b/code/game/g_public.h @@ -255,7 +255,6 @@ qboolean (*G2API_SetBoneAnglesMatrix)(CGhoul2Info *ghlInfo, const char *boneName qhandle_t *modelList, int blendTime = 0, int currentTime = 0); qboolean (*G2API_StopBoneAngles)(CGhoul2Info *ghlInfo, const char *boneName); qboolean (*G2API_RemoveBone)(CGhoul2Info *ghlInfo, const char *boneName); -void (*G2API_AnimateG2Models)(CGhoul2Info_v &ghoul2, float speedVar); qboolean (*G2API_RemoveBolt)(CGhoul2Info *ghlInfo, const int index); int (*G2API_AddBolt)(CGhoul2Info *ghlInfo, const char *boneName); int (*G2API_AddBoltSurfNum)(CGhoul2Info *ghlInfo, const int surfIndex); @@ -348,6 +347,7 @@ typedef struct { qboolean (*ConsoleCommand)( void ); void (*PrintEntClassname)( int clientNum ); + int (*ValidateAnimRange)( int startFrame, int endFrame, float animSpeed ); // // global variables shared between game and server // diff --git a/code/game/g_roff.cpp b/code/game/g_roff.cpp index e3e48d7..a261b40 100644 --- a/code/game/g_roff.cpp +++ b/code/game/g_roff.cpp @@ -439,9 +439,13 @@ int G_LoadRoff( const char *fileName ) void G_Roff( gentity_t *ent ) { - if ( !ent->next_roff_time || ent->next_roff_time > level.time ) + if ( !ent->next_roff_time ) { - // either I don't think or it's just not time to have me think yet + return; + } + + if ( ent->next_roff_time > level.time ) + {// either I don't think or it's just not time to have me think yet return; } @@ -556,6 +560,7 @@ void G_Roff( gentity_t *ent ) // Lock me to a 20hz update rate ent->next_roff_time = level.time + roff->mFrameTime; + assert( roff->mFrameTime >= 50 );//HAS to be at least 50 } diff --git a/code/game/g_roff.h b/code/game/g_roff.h index 1a73e3b..5d471c6 100644 --- a/code/game/g_roff.h +++ b/code/game/g_roff.h @@ -9,7 +9,7 @@ //------------------- #define ROFF_VERSION 1 // ver # for the (R)otation (O)bject (F)ile (F)ormat #define ROFF_VERSION2 2 // ver # for the (R)otation (O)bject (F)ile (F)ormat -#define MAX_ROFFS 16 // hard coded number of max roffs per level, sigh.. +#define MAX_ROFFS 32 // hard coded number of max roffs per level, sigh.. #define ROFF_SAMPLE_RATE 20 // 10hz diff --git a/code/game/g_savegame.cpp b/code/game/g_savegame.cpp index 78c2d89..8b6e0e2 100644 --- a/code/game/g_savegame.cpp +++ b/code/game/g_savegame.cpp @@ -82,6 +82,7 @@ field_t savefields_gNPC[] = {strNPCOFS(captureGoal), F_GENTITY}, {strNPCOFS(defendEnt), F_GENTITY}, {strNPCOFS(greetEnt), F_GENTITY}, + {strNPCOFS(group), F_GROUP}, {NULL, 0, F_IGNORE} }; @@ -218,6 +219,35 @@ gentity_t *GetGEntityPtr(int iEntNum) +static int GetGroupNumber(AIGroupInfo_t *pGroup) +{ + assert( pGroup != (AIGroupInfo_t *) 0xcdcdcdcd); + + if (pGroup == NULL) + { + return -1; + } + + int iReturnIndex = pGroup - level.groups; + if (iReturnIndex < 0 || iReturnIndex >= (sizeof(level.groups) / sizeof(level.groups[0])) ) + { + iReturnIndex = -1; // will get a NULL ptr on reload + } + return iReturnIndex; +} + +static AIGroupInfo_t *GetGroupPtr(int iGroupNum) +{ + if (iGroupNum == -1) + { + return NULL; + } + assert(iGroupNum >= 0); + assert(iGroupNum < (sizeof(level.groups) / sizeof(level.groups[0]))); + return (level.groups + iGroupNum); +} + + /////////// gclient_t * //////// // @@ -299,6 +329,10 @@ void EnumerateField(field_t *pField, byte *pbBase) *(int *)pv = GetGEntityNum(*(gentity_t **)pv); break; + case F_GROUP: + *(int *)pv = GetGroupNumber(*(AIGroupInfo_t **)pv); + break; + case F_GCLIENT: { // unfortunately, I now need to see if this is a 'real' client (and therefore resolve to an enum), or @@ -437,6 +471,10 @@ void EvaluateField(field_t *pField, byte *pbBase, byte *pbOriginalRefData/* may *(gentity_t **)pv = GetGEntityPtr(*(int *)pv); break; + case F_GROUP: + *(AIGroupInfo_t **)pv = GetGroupPtr(*(int *)pv); + break; + case F_GCLIENT: *(gclient_t **)pv = GetGClientPtr(*(int *)pv); break; @@ -671,6 +709,10 @@ void WriteGEntities(qboolean qbAutosave) static int iBlah = 1234; gi.AppendToSaveGame('ICOK', &iBlah, sizeof(iBlah)); } + if (!qbAutosave )//really shouldn't need to write these bits at all, just restore them from the ents... + { + WriteInUseBits(); + } } void ReadGEntities(qboolean qbAutosave) @@ -835,11 +877,14 @@ void ReadGEntities(qboolean qbAutosave) // if (pEnt->s.eType == ET_MOVER && pEnt->s.loopSound>0) { - extern int BMS_MID; // from g_mover - pEnt->s.loopSound = CAS_GetBModelSound( pEnt->soundSet, BMS_MID ); - if (pEnt->s.loopSound == -1) + if ( VALIDSTRING( pEnt->soundSet )) { - pEnt->s.loopSound = 0; + extern int BMS_MID; // from g_mover + pEnt->s.loopSound = CAS_GetBModelSound( pEnt->soundSet, BMS_MID ); + if (pEnt->s.loopSound == -1) + { + pEnt->s.loopSound = 0; + } } } @@ -876,6 +921,10 @@ void ReadGEntities(qboolean qbAutosave) static int iBlah = 1234; gi.ReadFromSaveGame('ICOK', &iBlah, sizeof(iBlah)); } + if (!qbAutosave) + { + ReadInUseBits();//really shouldn't need to read these bits in at all, just restore them from the ents... + } } @@ -888,20 +937,18 @@ void WriteLevel(qboolean qbAutosave) assert(level.maxclients == 1); // I'll need to know if this changes, otherwise I'll need to change the way ReadGame works gclient_t client = level.clients[0]; EnumerateFields(savefields_gClient, (byte *)&client, 'GCLI', sizeof(client)); + WriteLevelLocals(); // level_locals_t level } OBJ_SaveObjectiveData(); ///////////// - - WriteLevelLocals(); // level_locals_t level WriteGEntities(qbAutosave); Q3_VariableSave(); G_LoadSave_WriteMiscData(); extern void CG_WriteTheEvilCGHackStuff(void); CG_WriteTheEvilCGHackStuff(); - WriteInUseBits(); // (Do NOT put any write-code below this line) // @@ -933,6 +980,8 @@ void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition) //Read & throw away objective info objectives_t junkObj[MAX_MISSION_OBJ]; gi.ReadFromSaveGame('OBJT', (void *) &junkObj, 0); + + ReadLevelLocals(); // level_locals_t level } else { @@ -943,6 +992,7 @@ void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition) gclient_t GClient; EvaluateFields(savefields_gClient, (byte *)&GClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qfalse); level.clients[0] = GClient; // struct copy + ReadLevelLocals(); // level_locals_t level } OBJ_LoadObjectiveData();//loads mission objectives AND tactical info @@ -950,14 +1000,12 @@ void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition) ///////////// - ReadLevelLocals(); // level_locals_t level ReadGEntities(qbAutosave); Q3_VariableLoad(); G_LoadSave_ReadMiscData(); extern void CG_ReadTheEvilCGHackStuff(void); CG_ReadTheEvilCGHackStuff(); - ReadInUseBits(); // (Do NOT put any read-code below this line) // @@ -967,10 +1015,10 @@ void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition) gi.ReadFromSaveGame('DONE', &iDONE, sizeof(iDONE)); } - +extern int killPlayerTimer; qboolean GameAllowedToSaveHere(void) { - return !in_camera; + return (!in_camera&&!killPlayerTimer); } //////////////////// eof ///////////////////// diff --git a/code/game/g_session.cpp b/code/game/g_session.cpp index 1febebc..ec122d0 100644 --- a/code/game/g_session.cpp +++ b/code/game/g_session.cpp @@ -29,34 +29,34 @@ void G_WriteClientSessionData( gclient_t *client ) { const char *var; int i; - s2 = ""; - // Throw all status info into a string - for (i=0;i< MAX_OBJECTIVES; i++) - { - s2 = va("%s %i %i", - s2, client->sess.mission_objectives[i].display, - client->sess.mission_objectives[i].status); - } - var = va( "sessionobj%i", client - level.clients ); - gi.cvar_set( var, s2 ); - s = va("%i", client->sess.sessionTeam ); var = va( "session%i", client - level.clients ); gi.cvar_set( var, s ); + s2 = ""; + // Throw all status info into a string + for (i=0;i< MAX_OBJECTIVES; i++) + { + s2 = va("%s %i %i", s2, client->sess.mission_objectives[i].display, client->sess.mission_objectives[i].status); + } + var = va( "sessionobj%i", client - level.clients ); + gi.cvar_set( var, s2 ); + // Throw all mission stats in to a string - s2 = va("%i %i %i %i %i %i %i %i %i %i %i", - client->sess.missionStats.secretsFound, - client->sess.missionStats.totalSecrets, - client->sess.missionStats.shotsFired, - client->sess.missionStats.hits, - client->sess.missionStats.enemiesKilled, - client->sess.missionStats.saberThrownCnt, - client->sess.missionStats.saberBlocksCnt, - client->sess.missionStats.legAttacksCnt, - client->sess.missionStats.armAttacksCnt, - client->sess.missionStats.torsoAttacksCnt, - client->sess.missionStats.otherAttacksCnt); + s2 = va("%i %i %i %i %i %i %i %i %i %i %i %i", + client->sess.missionStats.secretsFound, + client->sess.missionStats.totalSecrets, + client->sess.missionStats.shotsFired, + client->sess.missionStats.hits, + client->sess.missionStats.enemiesSpawned, + client->sess.missionStats.enemiesKilled, + client->sess.missionStats.saberThrownCnt, + client->sess.missionStats.saberBlocksCnt, + client->sess.missionStats.legAttacksCnt, + client->sess.missionStats.armAttacksCnt, + client->sess.missionStats.torsoAttacksCnt, + client->sess.missionStats.otherAttacksCnt + ); var = va( "missionstats%i", client - level.clients ); gi.cvar_set( var, s2 ); @@ -114,11 +114,12 @@ void G_ReadSessionData( gclient_t *client ) { var = va( "missionstats%i", client - level.clients ); gi.Cvar_VariableStringBuffer( var, s, sizeof(s) ); - sscanf( s, "%i %i %i %i %i %i %i %i %i %i %i", + sscanf( s, "%i %i %i %i %i %i %i %i %i %i %i %i", &client->sess.missionStats.secretsFound, &client->sess.missionStats.totalSecrets, &client->sess.missionStats.shotsFired, &client->sess.missionStats.hits, + &client->sess.missionStats.enemiesSpawned, &client->sess.missionStats.enemiesKilled, &client->sess.missionStats.saberThrownCnt, &client->sess.missionStats.saberBlocksCnt, @@ -131,26 +132,30 @@ void G_ReadSessionData( gclient_t *client ) { var = va( "sessionpowers%i", client - level.clients ); gi.Cvar_VariableStringBuffer( var, s, sizeof(s) ); - var = s; - var++; - for (i=0;i< NUM_FORCE_POWERS; i++) + i=0; + var = strtok( s, " " ); + while( var != NULL ) { - sscanf( var, "%i", &client->sess.missionStats.forceUsed[i]); - var+=2; + /* While there are tokens in "s" */ + client->sess.missionStats.forceUsed[i++] = atoi(var); + /* Get next token: */ + var = strtok( NULL, " " ); } - + assert (i==NUM_FORCE_POWERS); var = va( "sessionweapons%i", client - level.clients ); gi.Cvar_VariableStringBuffer( var, s, sizeof(s) ); - var = s; - var++; - for (i=0;i< WP_NUM_WEAPONS; i++) + i=0; + var = strtok( s, " " ); + while( var != NULL ) { - sscanf( var, "%i", &client->sess.missionStats.weaponUsed[i]); - var+=2; + /* While there are tokens in "s" */ + client->sess.missionStats.weaponUsed[i++] = atoi(var); + /* Get next token: */ + var = strtok( NULL, " " ); } - + assert (i==WP_NUM_WEAPONS); } diff --git a/code/game/g_shared.h b/code/game/g_shared.h index 5a09ad1..c7e5aaf 100644 --- a/code/game/g_shared.h +++ b/code/game/g_shared.h @@ -73,6 +73,7 @@ typedef enum //# material_e MAT_GRATE1, // grate chunks MAT_ROPE, // for yavin trial...no chunks, just wispy bits MAT_CRATE2, // read multi-colored crate chunks + MAT_WHITE_METAL,// white angular chunks NUM_MATERIALS @@ -89,7 +90,7 @@ typedef enum //# material_e // this is regenerated each time a userinfo configstring changes #define MAX_CUSTOM_BASIC_SOUNDS 14 -#define MAX_CUSTOM_COMBAT_SOUNDS 15 +#define MAX_CUSTOM_COMBAT_SOUNDS 17 #define MAX_CUSTOM_EXTRA_SOUNDS 36 #define MAX_CUSTOM_JEDI_SOUNDS 22 #define MAX_CUSTOM_SOUNDS (MAX_CUSTOM_JEDI_SOUNDS + MAX_CUSTOM_EXTRA_SOUNDS + MAX_CUSTOM_COMBAT_SOUNDS + MAX_CUSTOM_BASIC_SOUNDS) @@ -321,6 +322,7 @@ typedef struct missionStats_s int totalSecrets; // # of secret areas that could have been found int shotsFired; // total number of shots fired int hits; // Shots that did damage + int enemiesSpawned; // # of enemies spawned int enemiesKilled; // # of enemies killed int saberThrownCnt; // # of times saber was thrown int saberBlocksCnt; // # of times saber was used to block @@ -406,10 +408,6 @@ typedef enum { } saberBlockedType_t; // !!!!!!!!!! LOADSAVE-affecting structure !!!!!!!!!! -typedef struct { - int tourObjectivesShown; // Number of times tour objectives have been updated - objectives_t tour_objectives[MAX_MISSION_OBJ]; -} clientTourSession_t; // this structure is cleared on each ClientSpawn(), // except for 'client->pers' and 'client->sess' @@ -499,7 +497,8 @@ struct gclient_s { int poisonTime; // When to apply poison damage int slopeRecalcTime; // debouncer for slope-foot-height-diff calcing - clientTourSession_t tourSess; + vec3_t pushVec; + int pushVecTime; }; #define MAX_PARMS 16 diff --git a/code/game/g_spawn.cpp b/code/game/g_spawn.cpp index b886439..70143d7 100644 --- a/code/game/g_spawn.cpp +++ b/code/game/g_spawn.cpp @@ -273,6 +273,7 @@ field_t fields[] = { {"NPC_targetname", FOFS(NPC_targetname), F_LSTRING}, {"NPC_target", FOFS(NPC_target), F_LSTRING}, {"NPC_target2", FOFS(target2), F_LSTRING},//NPC_spawner only + {"NPC_target4", FOFS(target4), F_LSTRING},//NPC_spawner only {"NPC_type", FOFS(NPC_type), F_LSTRING}, {"ownername", FOFS(ownername), F_LSTRING}, //freaky camera shit @@ -782,7 +783,7 @@ void G_ParseField( const char *key, const char *value, gentity_t *ent ) { assert(_iFieldsRead==3); if (_iFieldsRead!=3) { -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD gi.Printf (S_COLOR_YELLOW"G_ParseField: VEC3 sscanf() failed to read 3 floats ('angle' key bug?)\n"); #endif } @@ -797,7 +798,7 @@ void G_ParseField( const char *key, const char *value, gentity_t *ent ) { assert(_iFieldsRead==4); if (_iFieldsRead!=4) { -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD gi.Printf (S_COLOR_YELLOW"G_ParseField: VEC4 sscanf() failed to read 4 floats\n"); #endif } @@ -847,7 +848,7 @@ void G_ParseField( const char *key, const char *value, gentity_t *ent ) { } else { -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD gi.Printf (S_COLOR_YELLOW"WARNING: G_ParseField: can't find flag for key %s\n", key); #endif } @@ -860,7 +861,7 @@ void G_ParseField( const char *key, const char *value, gentity_t *ent ) { return; } } -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD //didn't find it? gi.Printf ( S_COLOR_YELLOW"WARNING: G_ParseField: no such field: %s\n", key ); #endif diff --git a/code/game/g_svcmds.cpp b/code/game/g_svcmds.cpp index 8d33a5a..db7c37d 100644 --- a/code/game/g_svcmds.cpp +++ b/code/game/g_svcmds.cpp @@ -134,6 +134,21 @@ extern cvar_t *g_skippingcin; } } +gentity_t *G_GetSelfForPlayerCmd( void ) +{ + if ( g_entities[0].client->ps.viewEntity > 0 + && g_entities[0].client->ps.viewEntity < ENTITYNUM_WORLD + && g_entities[g_entities[0].client->ps.viewEntity].client + && g_entities[g_entities[0].client->ps.viewEntity].s.weapon == WP_SABER ) + {//you're controlling another NPC + return (&g_entities[g_entities[0].client->ps.viewEntity]); + } + else + { + return (&g_entities[0]); + } +} + static void Svcmd_SaberColor_f() { char *color = gi.argv(1); @@ -144,31 +159,32 @@ static void Svcmd_SaberColor_f() return; } - + gentity_t *self = G_GetSelfForPlayerCmd(); + if ( !Q_stricmp( color, "red" )) { - g_entities[0].client->ps.saberColor = SABER_RED; + self->client->ps.saberColor = SABER_RED; } else if ( !Q_stricmp( color, "green" )) { - g_entities[0].client->ps.saberColor = SABER_GREEN; + self->client->ps.saberColor = SABER_GREEN; } else if ( !Q_stricmp( color, "yellow" )) { - g_entities[0].client->ps.saberColor = SABER_YELLOW; + self->client->ps.saberColor = SABER_YELLOW; } else if ( !Q_stricmp( color, "orange" )) { - g_entities[0].client->ps.saberColor = SABER_ORANGE; + self->client->ps.saberColor = SABER_ORANGE; } else if ( !Q_stricmp( color, "purple" )) { - g_entities[0].client->ps.saberColor = SABER_PURPLE; + self->client->ps.saberColor = SABER_PURPLE; } else if ( !Q_stricmp( color, "blue" )) { - g_entities[0].client->ps.saberColor = SABER_BLUE; + self->client->ps.saberColor = SABER_BLUE; } else { @@ -510,11 +526,12 @@ void Svcmd_MindTrick_f( void ) { g_entities[0].client->ps.forcePowerLevel[FP_TELEPATHY] = FORCE_LEVEL_0; } - else if ( g_entities[0].client->ps.forcePowerLevel[FP_TELEPATHY] > FORCE_LEVEL_3 ) + else if ( g_entities[0].client->ps.forcePowerLevel[FP_TELEPATHY] > FORCE_LEVEL_4 ) { - g_entities[0].client->ps.forcePowerLevel[FP_TELEPATHY] = FORCE_LEVEL_3; + g_entities[0].client->ps.forcePowerLevel[FP_TELEPATHY] = FORCE_LEVEL_4; } } + void Svcmd_SaberDefense_f( void ) { if ( !&g_entities[0] || !g_entities[0].client ) @@ -552,6 +569,7 @@ void Svcmd_SaberDefense_f( void ) g_entities[0].client->ps.forcePowerLevel[FP_SABER_DEFENSE] = FORCE_LEVEL_3; } } + void Svcmd_SaberOffense_f( void ) { if ( !&g_entities[0] || !g_entities[0].client ) @@ -599,47 +617,77 @@ void Svcmd_SaberAttackCycle_f( void ) { return; } - if ( g_entities[0].s.weapon != WP_SABER ) + + gentity_t *self = G_GetSelfForPlayerCmd(); + if ( self->s.weapon != WP_SABER ) { return; } - cg.saberAnimLevelPending++; - if ( g_entities[0].client->ps.forcePowerLevel[FP_SABER_OFFENSE] == FORCE_LEVEL_1 ) + + int saberAnimLevel; + if ( !self->s.number ) { - cg.saberAnimLevelPending = FORCE_LEVEL_2; + saberAnimLevel = cg.saberAnimLevelPending; } - else if ( g_entities[0].client->ps.forcePowerLevel[FP_SABER_OFFENSE] == FORCE_LEVEL_2 ) + else { - if ( cg.saberAnimLevelPending > FORCE_LEVEL_2 ) + saberAnimLevel = self->client->ps.saberAnimLevel; + } + saberAnimLevel++; + if ( self->client->ps.forcePowerLevel[FP_SABER_OFFENSE] == FORCE_LEVEL_1 ) + { + saberAnimLevel = FORCE_LEVEL_2; + } + else if ( self->client->ps.forcePowerLevel[FP_SABER_OFFENSE] == FORCE_LEVEL_2 ) + { + if ( saberAnimLevel > FORCE_LEVEL_2 ) { - cg.saberAnimLevelPending = FORCE_LEVEL_1; + saberAnimLevel = FORCE_LEVEL_1; } } else {//level 3 - if ( cg.saberAnimLevelPending > g_entities[0].client->ps.forcePowerLevel[FP_SABER_OFFENSE] ) + if ( saberAnimLevel > self->client->ps.forcePowerLevel[FP_SABER_OFFENSE] ) {//wrap around - cg.saberAnimLevelPending = FORCE_LEVEL_1; + saberAnimLevel = FORCE_LEVEL_1; } } - switch ( cg.saberAnimLevelPending ) + + if ( !self->s.number ) + { + cg.saberAnimLevelPending = saberAnimLevel; + } + else + { + self->client->ps.saberAnimLevel = saberAnimLevel; + } + +#ifndef FINAL_BUILD + switch ( saberAnimLevel ) { case FORCE_LEVEL_1: - gi.Printf( S_COLOR_GREEN"Saber Attack Set: fast\n" ); + gi.Printf( S_COLOR_BLUE"Lightsaber Combat Style: Fast\n" ); + //LIGHTSABERCOMBATSTYLE_FAST break; case FORCE_LEVEL_2: - gi.Printf( S_COLOR_YELLOW"Saber Attack Set: medium\n" ); + gi.Printf( S_COLOR_YELLOW"Lightsaber Combat Style: Medium\n" ); + //LIGHTSABERCOMBATSTYLE_MEDIUM break; case FORCE_LEVEL_3: - gi.Printf( S_COLOR_RED"Saber Attack Set: strong\n" ); + gi.Printf( S_COLOR_RED"Lightsaber Combat Style: Strong\n" ); + //LIGHTSABERCOMBATSTYLE_STRONG break; case FORCE_LEVEL_4: - gi.Printf( S_COLOR_BLUE"Saber Attack Set: desann\n" ); + gi.Printf( S_COLOR_CYAN"Lightsaber Combat Style: Desann\n" ); + //LIGHTSABERCOMBATSTYLE_DESANN break; case FORCE_LEVEL_5: - gi.Printf( S_COLOR_MAGENTA"Saber Attack Set: tavion\n" ); + gi.Printf( S_COLOR_MAGENTA"Lightsaber Combat Style: Tavion\n" ); + //LIGHTSABERCOMBATSTYLE_TAVION break; } + //gi.Printf("\n"); +#endif } /* ================= diff --git a/code/game/g_target.cpp b/code/game/g_target.cpp index 3871b64..2e21377 100644 --- a/code/game/g_target.cpp +++ b/code/game/g_target.cpp @@ -826,8 +826,12 @@ void SP_target_scriptrunner( gentity_t *self ) self->wait = 1;//default wait of 1 sec } */ + // FIXME: this is a hack... because delay is read in as an int, so I'm bypassing that because it's too late in the project to change it and I want to be able to set less than a second delays + // no one should be setting a radius on a scriptrunner, if they are this would be bad, take this out for the next project + self->radius = 0.0f; + G_SpawnFloat( "delay", "0", &self->radius ); + self->delay = self->radius * 1000;//sec to ms self->wait *= 1000;//sec to ms - self->delay *= 1000;//sec to ms G_SetOrigin( self, self->s.origin ); self->e_UseFunc = useF_target_scriptrunner_use; @@ -1022,8 +1026,11 @@ extern cvar_t *com_buildScript; void target_autosave_use(gentity_t *self, gentity_t *other, gentity_t *activator) { G_ActivateBehavior(self,BSET_USE); + //gi.SendServerCommand( NULL, "cp @INGAME_CHECKPOINT" ); + CG_CenterPrint( "@INGAME_CHECKPOINT", SCREEN_HEIGHT * 0.25 ); //jump the network + // if (self->spawnflags & 1) - gi.SendConsoleCommand( "save auto*\n" ); + gi.SendConsoleCommand( "wait 2;save auto*\n" ); } /*QUAKED target_autosave (1 0 0) (-4 -4 -4) (4 4 4) @@ -1041,22 +1048,30 @@ void target_secret_use(gentity_t *self, gentity_t *other, gentity_t *activator) //we'll assume that the activator is the player gclient_t* const client = &level.clients[0]; client->sess.missionStats.secretsFound++; - G_Sound( self, self->noise_index ); - gi.SendServerCommand( NULL, "cp \"Secret Area!\"" ); + if ( activator ) + { + G_Sound( activator, self->noise_index ); + } + else + { + G_Sound( self, self->noise_index ); + } + gi.SendServerCommand( NULL, "cp @INGAME_SECRET_AREA" ); + assert(client->sess.missionStats.totalSecrets); } /*QUAKED target_secret (1 0 1) (-4 -4 -4) (4 4 4) You found a Secret! -"count" - how many secrets on this level +"count" - how many secrets on this level, + if more than one on a level, be sure they all have the same count! */ void SP_target_secret( gentity_t *self ) { G_SetOrigin( self, self->s.origin ); self->e_UseFunc = useF_target_secret_use; - self->noise_index = G_SoundIndex("sound/movers/switches/switch4"); + self->noise_index = G_SoundIndex("sound/interface/secret_area"); if (self->count) { - gclient_t* const client = &level.clients[0]; - client->sess.missionStats.totalSecrets = self->count; + gi.cvar_set("newTotalSecrets", va("%i",self->count)); } } diff --git a/code/game/g_trigger.cpp b/code/game/g_trigger.cpp index a1ca1d8..d7a0c4c 100644 --- a/code/game/g_trigger.cpp +++ b/code/game/g_trigger.cpp @@ -1049,12 +1049,15 @@ NO_PROTECTION *nothing* stops the damage LOCKCAM Falling death results in camera locking in place FALLING Forces a falling scream and anim ELECTRICAL does electrical damage +INACTIVE Cannot be triggered until used by a target_activate MULTIPLE multiple entities can touch this trigger in a single frame *and* if needed, the trigger can have a wait of > 0 "dmg" default 5 (whole numbers only) "delay" How many seconds it takes to get from 0 to "dmg" (default is 0) "wait" Use in instead of "SLOW" - determines how often the player gets hurt, 0.1 is every frame, 1.0 is once per second. -1 will stop after one use "count" If set, FALLING death causes a fade to black in this many milliseconds (default is 10000 = 10 seconds) +"NPC_targetname" - If set, only an NPC with a matching NPC_targetname will trip this trigger +"noise" sound to play when it hurts something ( default: "sound/world/electro" ) */ void hurt_use( gentity_t *self, gentity_t *other, gentity_t *activator ) { @@ -1088,7 +1091,7 @@ void hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) { return; } - + if( level.time < self->painDebounceTime + self->wait ) // normal 'wait' check { if( self->spawnflags & 2048 ) // MULTIPLE - allow multiple entities to touch this trigger in one frame @@ -1119,6 +1122,21 @@ void hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) } } + if ( self->NPC_targetname && self->NPC_targetname[0] ) + {//I am for you, Kirk + if ( other->script_targetname && other->script_targetname[0] ) + {//must have a name + if ( Q_stricmp( self->NPC_targetname, other->script_targetname ) != 0 ) + {//not the right guy to fire me off + return; + } + } + else + {//no name? No trigger. + return; + } + } + // play sound if ( !(self->spawnflags & 4) ) { @@ -1158,6 +1176,7 @@ void hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) if ( self->spawnflags & 32 ) {//falling death G_Damage (other, self, self, NULL, NULL, actualDmg, dflags|DAMAGE_NO_ARMOR, MOD_FALLING); + // G_Damage will free this ent, which makes it s.number 0, so we must check inuse... if ( !other->s.number && other->health <= 0 ) { if ( self->count ) @@ -1186,6 +1205,10 @@ void hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) { self->aimDebounceTime = level.time; } + if (( self->spawnflags & 64 ) && other->client && other->health <= 0 )//electrical damage + {//just killed them, make the effect last longer since dead clients don't touch triggers + other->client->ps.powerups[PW_SHOCKED] = level.time + 10000; + } self->painDebounceTime = level.time; } @@ -1197,9 +1220,19 @@ void hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) void SP_trigger_hurt( gentity_t *self ) { + char buffer[MAX_QPATH]; + char *s; + InitTrigger (self); - self->noise_index = G_SoundIndex( "sound/world/electro.wav" ); + if ( !( self->spawnflags & 4 )) + { + G_SpawnString( "noise", "sound/world/electro", &s ); + + Q_strncpyz( buffer, s, sizeof(buffer) ); + self->noise_index = G_SoundIndex(buffer); + } + self->e_TouchFunc = touchF_hurt_touch; if ( !self->damage ) { diff --git a/code/game/g_turret.cpp b/code/game/g_turret.cpp index e5f7407..c6a70f6 100644 --- a/code/game/g_turret.cpp +++ b/code/game/g_turret.cpp @@ -11,6 +11,7 @@ extern cvar_t *g_spskill; void G_SetEnemy( gentity_t *self, gentity_t *enemy ); void finish_spawning_turret( gentity_t *base ); void ObjectDie (gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ); +extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); #define ARM_ANGLE_RANGE 60 #define HEAD_ANGLE_RANGE 90 @@ -56,7 +57,7 @@ void turret_die ( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, in VectorSet( forward, 0, 0, 1 ); } - VectorCopy( self->currentOrigin, self->s.pos.trBase ); +// VectorCopy( self->currentOrigin, self->s.pos.trBase ); if ( self->fxID > 0 ) { @@ -95,12 +96,23 @@ void turret_die ( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, in } } +#define START_DIS 15 + //---------------------------------------------------------------- static void turret_fire ( gentity_t *ent, vec3_t start, vec3_t dir ) //---------------------------------------------------------------- { + vec3_t org; gentity_t *bolt; + if ( gi.pointcontents( start, MASK_SHOT )) + { + return; + } + + VectorMA( start, -START_DIS, dir, org ); // dumb.... + G_PlayEffect( "blaster/muzzle_flash", org, dir ); + bolt = G_Spawn(); bolt->classname = "turret_proj"; @@ -120,7 +132,7 @@ static void turret_fire ( gentity_t *ent, vec3_t start, vec3_t dir ) VectorSet( bolt->maxs, 1.5, 1.5, 1.5 ); VectorScale( bolt->maxs, -1, bolt->mins ); bolt->s.pos.trType = TR_LINEAR; - bolt->s.pos.trTime = level.time - 10; // move a bit on the very first frame + bolt->s.pos.trTime = level.time; VectorCopy( start, bolt->s.pos.trBase ); VectorScale( dir, 1100, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth @@ -149,10 +161,10 @@ void turret_head_think( gentity_t *self ) gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org ); gi.G2API_GiveMeVectorFromMatrix( boltMatrix, POSITIVE_Y, fwd ); - G_PlayEffect( "blaster/muzzle_flash", org, fwd ); - VectorMA( org, 35, fwd, org ); // this might be bad?? + VectorMA( org, START_DIS, fwd, org ); turret_fire( self, org, fwd ); + self->fly_sound_debounce_time = level.time;//used as lastShotTime } } @@ -650,7 +662,7 @@ void finish_spawning_turret( gentity_t *base ) G_SoundIndex( "sound/chars/turret/ping.wav" ); G_SoundIndex( "sound/chars/turret/move.wav" ); - base->contents = MASK_SHOT;//CONTENTS_BODY; + base->contents = CONTENTS_BODY|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_SHOTCLIP; base->max_health = base->health; base->takedamage = qtrue; @@ -731,7 +743,8 @@ void laser_arm_fire (gentity_t *ent) VectorMA( start, 4096, fwd, end ); gi.trace( &trace, start, NULL, NULL, end, ENTITYNUM_NONE, MASK_SHOT );//ignore - + ent->fly_sound_debounce_time = level.time;//used as lastShotTime + // Only deal damage when in alt-fire mode if ( trace.fraction < 1.0 && ent->alt_fire ) { @@ -1327,6 +1340,7 @@ void pas_think( gentity_t *ent ) if ( ent->count ) { pas_fire( ent ); + ent->fly_sound_debounce_time = level.time;//used as lastShotTime } else { @@ -1409,7 +1423,7 @@ void SP_PAS( gentity_t *base ) } // Set up our explosion effect for the ExplodeDeath code.... - base->fxID = G_EffectIndex( "tripMine/explosion" ); + base->fxID = G_EffectIndex( "turret/explode" ); G_EffectIndex( "spark_exp_nosnd" ); if ( !base->health ) @@ -1490,6 +1504,8 @@ qboolean place_portable_assault_sentry( gentity_t *self, vec3_t origin, vec3_t a { pas->noDamageTeam = self->client->playerTeam; } + + G_Sound( self, G_SoundIndex( "sound/player/use_sentry" )); pas->activator = self; return qtrue; } @@ -1559,7 +1575,10 @@ void ion_cannon_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, vec3_t org; // dead, so nuke the ghoul model and put in the damage md3 version - gi.G2API_RemoveGhoul2Model( self->ghoul2, self->playerModel ); + if ( self->playerModel >= 0 ) + { + gi.G2API_RemoveGhoul2Model( self->ghoul2, self->playerModel ); + } self->s.modelindex = self->s.modelindex2; self->s.modelindex2 = 0; @@ -1766,7 +1785,7 @@ void spotlight_think( gentity_t *ent ) // hit player--use target2 G_UseTargets2( ent, &g_entities[0], ent->target2 ); -#ifndef FINAL +#ifndef FINAL_BUILD if ( g_developer->integer == PRINT_DEVELOPER ) { Com_Printf( S_COLOR_MAGENTA "Spotlight hit player at time: %d!!!\n", level.time ); @@ -1891,6 +1910,8 @@ void panel_turret_shoot( gentity_t *self, vec3_t org, vec3_t dir) missile->methodOfDeath = MOD_ENERGY; missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; + G_SoundOnEnt( self, CHAN_AUTO, "sound/movers/objects/ladygun_fire" ); + VectorMA( org, 32, dir, org ); org[2] -= 5; G_PlayEffect( "emplaced/muzzle_flash", org, dir ); @@ -1923,7 +1944,7 @@ void panel_turret_think( gentity_t *self ) for ( int i = 0; i < 3; i++ ) { // convert our base angle to a short, add with the usercmd.angle ( a short ), then switch use back to a real angle - self->s.apos.trBase[i] = AngleNormalize180( SHORT2ANGLE( ucmd->angles[i] + ANGLE2SHORT( self->s.angles[i] ) + self->pos1[i] )); + self->s.apos.trBase[i] = AngleNormalize180( SHORT2ANGLE( ucmd->angles[i] + ANGLE2SHORT( self->s.angles[i] ) + self->pos3[i] )); } // Only clamp if we have a PITCH clamp @@ -1932,12 +1953,12 @@ void panel_turret_think( gentity_t *self ) { if ( self->s.apos.trBase[PITCH] > self->random ) // random is PITCH { - self->pos1[PITCH] += ANGLE2SHORT( AngleNormalize180( self->random - self->s.apos.trBase[PITCH])); + self->pos3[PITCH] += ANGLE2SHORT( AngleNormalize180( self->random - self->s.apos.trBase[PITCH])); self->s.apos.trBase[PITCH] = self->random; } else if ( self->s.apos.trBase[PITCH] < -self->random ) { - self->pos1[PITCH] -= ANGLE2SHORT( AngleNormalize180( self->random + self->s.apos.trBase[PITCH])); + self->pos3[PITCH] -= ANGLE2SHORT( AngleNormalize180( self->random + self->s.apos.trBase[PITCH])); self->s.apos.trBase[PITCH] = -self->random; } } @@ -1950,12 +1971,12 @@ void panel_turret_think( gentity_t *self ) // Angle clamping -- YAW if ( yawDif > self->radius ) // radius is YAW { - self->pos1[YAW] += ANGLE2SHORT( self->radius - yawDif ); + self->pos3[YAW] += ANGLE2SHORT( self->radius - yawDif ); self->s.apos.trBase[YAW] = AngleNormalize180( self->s.angles[YAW] + self->radius ); } else if ( yawDif < -self->radius ) // radius is YAW { - self->pos1[YAW] -= ANGLE2SHORT( self->radius + yawDif ); + self->pos3[YAW] -= ANGLE2SHORT( self->radius + yawDif ); self->s.apos.trBase[YAW] = AngleNormalize180( self->s.angles[YAW] - self->radius ); } } @@ -1975,6 +1996,10 @@ void panel_turret_think( gentity_t *self ) cg.overrides.active &= ~CG_OVERRIDE_FOV; cg.overrides.fov = 0; + if ( ucmd->upmove > 0 ) + {//stop player from doing anything for a half second after + player->aimDebounceTime = level.time + 500; + } // can be drawn // self->s.eFlags &= ~EF_NODRAW; @@ -2025,11 +2050,17 @@ void panel_turret_use( gentity_t *self, gentity_t *other, gentity_t *activator ) return; } + if ( self->spawnflags & 1 ) // health...presumably the lady luck gun + { + G_Sound( self, G_SoundIndex( "sound/movers/objects/ladygun_on" )); + } + self->useDebounceTime = level.time + 200; // Compensating for the difference between the players view at the time of use and the start angles that the gun object has - self->pos1[PITCH] = -activator->client->usercmd.angles[PITCH]; - self->pos1[YAW] = -activator->client->usercmd.angles[YAW]; + self->pos3[PITCH] = -activator->client->usercmd.angles[PITCH]; + self->pos3[YAW] = -activator->client->usercmd.angles[YAW]; + self->pos3[ROLL] = 0; // set me as view entity G_UseTargets2( self, activator, self->target ); @@ -2051,7 +2082,7 @@ void SP_misc_panel_turret( gentity_t *self ) G_SpawnInt( "delay", "200", &self->delay ); G_SpawnInt( "damage", "50", &self->damage ); - VectorSet( self->pos1, 0.0f, 0.0f, 0.0f ); + VectorSet( self->pos3, 0.0f, 0.0f, 0.0f ); if ( self->spawnflags & 1 ) // heatlh { @@ -2061,6 +2092,7 @@ void SP_misc_panel_turret( gentity_t *self ) self->max_health = self->health; self->dflags |= DAMAGE_CUSTOM_HUD; // dumb, but we draw a custom hud + G_SoundIndex( "sound/movers/objects/ladygun_on" ); } self->s.modelindex = G_ModelIndex( "models/map_objects/imp_mine/ladyluck_gun.md3" ); @@ -2068,6 +2100,8 @@ void SP_misc_panel_turret( gentity_t *self ) self->soundPos1 = G_SoundIndex( "sound/movers/camera_on.mp3" ); self->soundPos2 = G_SoundIndex( "sound/movers/camera_off.mp3" ); + G_SoundIndex( "sound/movers/objects/ladygun_fire" ); + G_SetOrigin( self, self->s.origin ); G_SetAngles( self, self->s.angles ); @@ -2075,6 +2109,8 @@ void SP_misc_panel_turret( gentity_t *self ) VectorSet( self->maxs, 8, 8, 0 ); self->contents = CONTENTS_SOLID; + self->s.weapon = WP_TURRET; + RegisterItem( FindItemForWeapon( WP_EMPLACED_GUN )); gi.linkentity( self ); diff --git a/code/game/g_utils.cpp b/code/game/g_utils.cpp index a55e6d9..eb5b77e 100644 --- a/code/game/g_utils.cpp +++ b/code/game/g_utils.cpp @@ -263,6 +263,12 @@ void G_SpeechEvent( gentity_t *self, int event ) case EV_CHOKE3: CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, va("*choke%i.wav", event - EV_CHOKE1 + 1), CS_COMBAT ); break; + case EV_FFWARN: //Warn ally to stop shooting you + CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, "*ffwarn.wav", CS_COMBAT ); + break; + case EV_FFTURN: //Turn on ally after being shot by them + CG_TryPlayCustomSound( NULL, self->s.number, CHAN_VOICE, "*ffturn.wav", CS_COMBAT ); + break; //extra sounds for ST case EV_CHASE1: case EV_CHASE2: @@ -807,6 +813,7 @@ void G_FreeEntity( gentity_t *ed ) { // This is really fucking stupid and has caused us no end of // trouble!!! Change it to set the s.number to the proper index // (ed - g_entities) *OR* ENTITYNUM_NONE!!! + ed->s.number = ENTITYNUM_NONE; ed->classname = "freed"; ed->freetime = level.time; ed->inuse = qfalse; @@ -1291,7 +1298,12 @@ void TryUse( gentity_t *ent ) GEntity_UseFunc( target, ent, ent ); return; } - else if ( target->client && target->client->ps.pm_type < PM_DEAD && target->NPC!=NULL && target->client->playerTeam && target->client->playerTeam == ent->client->playerTeam && !(target->NPC->scriptFlags&SCF_NO_RESPONSE) ) + else if ( target->client + && target->client->ps.pm_type < PM_DEAD + && target->NPC!=NULL + && target->client->playerTeam + && (target->client->playerTeam == ent->client->playerTeam || target->client->playerTeam == TEAM_NEUTRAL) + && !(target->NPC->scriptFlags&SCF_NO_RESPONSE) ) { NPC_UseResponse ( target, ent, qfalse ); return; @@ -1304,12 +1316,17 @@ void TryUse( gentity_t *ent ) */ } +extern int killPlayerTimer; void G_ChangeMap (const char *mapname, const char *spawntarget, qboolean hub) { // gi.Printf("Loading..."); //ignore if player is dead if (g_entities[0].client->ps.pm_type == PM_DEAD) return; + if ( killPlayerTimer ) + {//can't go to next map if your allies have turned on you + return; + } if ( spawntarget == NULL ) { spawntarget = ""; //prevent it from becoming "(null)" diff --git a/code/game/g_weapon.cpp b/code/game/g_weapon.cpp index fafc350..737197e 100644 --- a/code/game/g_weapon.cpp +++ b/code/game/g_weapon.cpp @@ -36,20 +36,25 @@ static gentity_t *ent_list[MAX_GENTITIES]; #define BLASTER_NPC_SPREAD 0.5f #define BLASTER_VELOCITY 2300 #define BLASTER_NPC_VEL_CUT 0.5f +#define BLASTER_NPC_HARD_VEL_CUT 0.7f #define BLASTER_DAMAGE 20 #define BLASTER_NPC_DAMAGE_EASY 6 -#define BLASTER_NPC_DAMAGE_NORMAL 14 -#define BLASTER_NPC_DAMAGE_HARD 18 +#define BLASTER_NPC_DAMAGE_NORMAL 12 // 14 +#define BLASTER_NPC_DAMAGE_HARD 16 // 18 // Tenloss Disruptor //---------- #define DISRUPTOR_MAIN_DAMAGE 14 -#define DISRUPTOR_NPC_MAIN_DAMAGE_CUT 0.25f +#define DISRUPTOR_NPC_MAIN_DAMAGE_EASY 5 +#define DISRUPTOR_NPC_MAIN_DAMAGE_MEDIUM 10 +#define DISRUPTOR_NPC_MAIN_DAMAGE_HARD 15 -#define DISRUPTOR_ALT_DAMAGE 4 -#define DISRUPTOR_NPC_ALT_DAMAGE_SCALE 4 +#define DISRUPTOR_ALT_DAMAGE 12 +#define DISRUPTOR_NPC_ALT_DAMAGE_EASY 15 +#define DISRUPTOR_NPC_ALT_DAMAGE_MEDIUM 25 +#define DISRUPTOR_NPC_ALT_DAMAGE_HARD 30 #define DISRUPTOR_ALT_TRACES 3 // can go through a max of 3 entities -#define DISRUPTOR_CHARGE_UNIT 50.0f // distruptor charging gives us one more unit every 50ms--if you change this, you'll have to do the same in bg_pmove +#define DISRUPTOR_CHARGE_UNIT 150.0f // distruptor charging gives us one more unit every 150ms--if you change this, you'll have to do the same in bg_pmove // Wookie Bowcaster //---------- @@ -233,9 +238,8 @@ static void WP_TraceSetStart( const gentity_t *ent, vec3_t start, const vec3_t m return; } - // man, I'm not so sure about this, but....was having some nasty problems with weapon muzzles in walls so this is sort of a last - // desperate attempt to remedy the situation - VectorMA( start, -20, forward, newstart ); + VectorCopy( ent->currentOrigin, newstart ); + newstart[2] = start[2]; // force newstart to be on the same plane as the muzzle ( start ) gi.trace( &tr, newstart, entMins, entMaxs, start, ent->s.number, MASK_SOLID|CONTENTS_SHOTCLIP ); @@ -559,8 +563,15 @@ static void WP_FireBlasterMissile( gentity_t *ent, vec3_t start, vec3_t dir, qbo // If an enemy is shooting at us, lower the velocity so you have a chance to evade if ( ent->client && ent->client->ps.clientNum != 0 ) - { - velocity *= BLASTER_NPC_VEL_CUT; + { + if ( g_spskill->integer < 2 ) + { + velocity *= BLASTER_NPC_VEL_CUT; + } + else + { + velocity *= BLASTER_NPC_HARD_VEL_CUT; + } } WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall @@ -656,8 +667,8 @@ static void WP_FireBlaster( gentity_t *ent, qboolean alt_fire ) //--------------------- // Tenloss Disruptor //--------------------- -extern qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir ); -int G_GetHitLocFromTrace( trace_t *trace ) +extern qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir, int mod ); +int G_GetHitLocFromTrace( trace_t *trace, int mod ) { int hitLoc = HL_NONE; for (int i=0; i < MAX_G2_COLLISIONS; i++) @@ -670,7 +681,7 @@ int G_GetHitLocFromTrace( trace_t *trace ) CCollisionRecord &coll = trace->G2CollisionMap[i]; if ( (coll.mFlags & G2_FRONTFACE) ) { - G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &hitLoc, coll.mCollisionPosition, NULL, NULL ); + G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &hitLoc, coll.mCollisionPosition, NULL, NULL, mod ); //we only want the first "entrance wound", so break break; } @@ -691,7 +702,19 @@ static void WP_DisruptorMainFire( gentity_t *ent ) if ( ent->NPC ) { - damage *= DISRUPTOR_NPC_MAIN_DAMAGE_CUT; + switch ( g_spskill->integer ) + { + case 0: + damage = DISRUPTOR_NPC_MAIN_DAMAGE_EASY; + break; + case 1: + damage = DISRUPTOR_NPC_MAIN_DAMAGE_MEDIUM; + break; + case 2: + default: + damage = DISRUPTOR_NPC_MAIN_DAMAGE_HARD; + break; + } } VectorCopy( muzzle, start ); @@ -733,6 +756,7 @@ static void WP_DisruptorMainFire( gentity_t *ent ) // always render a shot beam, doing this the old way because I don't much feel like overriding the effect. tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_MAIN_SHOT ); + tent->svFlags |= SVF_BROADCAST; VectorCopy( muzzle, tent->s.origin2 ); if ( render_impact ) @@ -747,14 +771,14 @@ static void WP_DisruptorMainFire( gentity_t *ent ) ent->client->ps.persistant[PERS_ACCURACY_HITS]++; } + int hitLoc = G_GetHitLocFromTrace( &tr, MOD_DISRUPTOR ); if ( traceEnt && traceEnt->client && traceEnt->client->NPC_class == CLASS_GALAKMECH ) {//hehe - int hitLoc = G_GetHitLocFromTrace( &tr ); - G_Damage( traceEnt, ent, ent, forward, tr.endpos, 3, DAMAGE_DEATH_KNOCKBACK, MOD_DISRUPTOR, hitLoc ); + G_Damage( traceEnt, ent, ent, forward, tr.endpos, 3, DAMAGE_DEATH_KNOCKBACK, MOD_DISRUPTOR, hitLoc ); } else { - G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_DEATH_KNOCKBACK, MOD_DISRUPTOR ); + G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_DEATH_KNOCKBACK, MOD_DISRUPTOR, hitLoc ); } } else @@ -793,7 +817,19 @@ void WP_DisruptorAltFire( gentity_t *ent ) // The trace start will originate at the eye so we can ensure that it hits the crosshair. if ( ent->NPC ) { - damage *= DISRUPTOR_NPC_ALT_DAMAGE_SCALE; + switch ( g_spskill->integer ) + { + case 0: + damage = DISRUPTOR_NPC_ALT_DAMAGE_EASY; + break; + case 1: + damage = DISRUPTOR_NPC_ALT_DAMAGE_MEDIUM; + break; + case 2: + default: + damage = DISRUPTOR_NPC_ALT_DAMAGE_HARD; + break; + } VectorCopy( muzzle, start ); fullCharge = qtrue; @@ -804,30 +840,30 @@ void WP_DisruptorAltFire( gentity_t *ent ) AngleVectors( ent->client->renderInfo.eyeAngles, forward, NULL, NULL ); // don't let NPC's do charging - int count = ( level.time - ent->client->ps.weaponChargeTime ) / DISRUPTOR_CHARGE_UNIT; + int count = ( level.time - ent->client->ps.weaponChargeTime - 50 ) / DISRUPTOR_CHARGE_UNIT; if ( count < 1 ) { count = 1; } - else if ( count >= 30 ) + else if ( count >= 10 ) { - count = 30; + count = 10; fullCharge = qtrue; } // more powerful charges go through more things - if ( count < 10 ) + if ( count < 3 ) { traces = 1; } - else if ( count < 20 ) + else if ( count < 6 ) { traces = 2; } //else do full traces - damage *= count + DISRUPTOR_MAIN_DAMAGE * 0.75f; // give a boost to low charge shots + damage = damage * count + DISRUPTOR_MAIN_DAMAGE * 0.5f; // give a boost to low charge shots } skip = ent->s.number; @@ -866,6 +902,7 @@ void WP_DisruptorAltFire( gentity_t *ent ) // always render a shot beam, doing this the old way because I don't much feel like overriding the effect. tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_SNIPER_SHOT ); + tent->svFlags |= SVF_BROADCAST; tent->alt_fire = fullCharge; // mark us so we can alter the effect VectorCopy( muzzle2, tent->s.origin2 ); @@ -887,28 +924,30 @@ void WP_DisruptorAltFire( gentity_t *ent ) { if ( render_impact ) { - if ( tr.entityNum < ENTITYNUM_WORLD && traceEnt->takedamage ) + if (( tr.entityNum < ENTITYNUM_WORLD && traceEnt->takedamage ) || !Q_stricmp( traceEnt->classname, "misc_model_breakable" ) + || traceEnt->s.eType == ET_MOVER ) { // Create a simple impact type mark that doesn't last long in the world G_PlayEffect( G_EffectIndex( "disruptor/alt_hit" ), tr.endpos, tr.plane.normal ); if ( traceEnt->client && LogAccuracyHit( traceEnt, ent )) - { + {//NOTE: hitting multiple ents can still get you over 100% accuracy ent->client->ps.persistant[PERS_ACCURACY_HITS]++; } + int hitLoc = G_GetHitLocFromTrace( &tr, MOD_DISRUPTOR ); if ( traceEnt && traceEnt->client && traceEnt->client->NPC_class == CLASS_GALAKMECH ) {//hehe - int hitLoc = G_GetHitLocFromTrace( &tr ); - G_Damage( traceEnt, ent, ent, forward, tr.endpos, 10, DAMAGE_NO_KNOCKBACK, fullCharge ? MOD_SNIPER : MOD_DISRUPTOR, hitLoc ); + G_Damage( traceEnt, ent, ent, forward, tr.endpos, 10, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, fullCharge ? MOD_SNIPER : MOD_DISRUPTOR, hitLoc ); break; } - G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, fullCharge ? MOD_SNIPER : MOD_DISRUPTOR ); + G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK|DAMAGE_NO_HIT_LOC, fullCharge ? MOD_SNIPER : MOD_DISRUPTOR, hitLoc ); } else { // we only make this mark on things that can't break or move tent = G_TempEntity( tr.endpos, EV_DISRUPTOR_SNIPER_MISS ); + tent->svFlags |= SVF_BROADCAST; VectorCopy( tr.plane.normal, tent->pos1 ); break; // hit solid, but doesn't take damage, so stop the shot...we _could_ allow it to shoot through walls, might be cool? } @@ -1022,9 +1061,14 @@ static void WP_BowcasterMainFire( gentity_t *ent ) vectoangles( forward, angs ); - // add some slop to the alt-fire direction + // add some slop to the fire direction angs[PITCH] += crandom() * BOWCASTER_ALT_SPREAD * 0.2f; angs[YAW] += ((i+0.5f) * BOWCASTER_ALT_SPREAD - count * 0.5f * BOWCASTER_ALT_SPREAD ); + if ( ent->NPC ) + { + angs[PITCH] += ( crandom() * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f) ); + angs[YAW] += ( crandom() * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f) ); + } AngleVectors( angs, dir, NULL, NULL ); @@ -1050,6 +1094,7 @@ static void WP_BowcasterMainFire( gentity_t *ent ) // we don't want it to bounce missile->bounceCount = 0; + ent->client->sess.missionStats.shotsFired++; } } @@ -1404,7 +1449,7 @@ void DEMP2_AltRadiusDamage( gentity_t *ent ) // push the center of mass higher than the origin so players get knocked into the air more dir[2] += 12; - G_Damage( gent, NULL, ent, dir, ent->currentOrigin, DEMP2_ALT_DAMAGE, DAMAGE_DEATH_KNOCKBACK, ent->splashMethodOfDeath ); + G_Damage( gent, ent, ent->owner, dir, ent->currentOrigin, DEMP2_ALT_DAMAGE, DAMAGE_DEATH_KNOCKBACK, ent->splashMethodOfDeath ); if ( gent->takedamage && gent->client ) { gent->s.powerups |= ( 1 << PW_SHOCKED ); @@ -1574,6 +1619,7 @@ static void WP_FlechetteMainFire( gentity_t *ent ) missile->bounceCount = Q_irand(1,2); missile->s.eFlags |= EF_BOUNCE_SHRAPNEL; + ent->client->sess.missionStats.shotsFired++; } } @@ -1606,7 +1652,7 @@ void prox_mine_think( gentity_t *ent ) if ( blow ) { - G_Sound( ent, G_SoundIndex( "sound/weapons/flechette/warning.wav" )); +// G_Sound( ent, G_SoundIndex( "sound/weapons/flechette/warning.wav" )); ent->e_ThinkFunc = thinkF_WP_Explode; ent->nextthink = level.time + 200; } @@ -1706,6 +1752,7 @@ static void WP_CreateFlechetteBouncyThing( vec3_t start, vec3_t fwd, gentity_t * VectorSet( missile->mins, -3.0f, -3.0f, -3.0f ); VectorSet( missile->maxs, 3.0f, 3.0f, 3.0f ); missile->clipmask = MASK_SHOT; + missile->clipmask &= ~CONTENTS_CORPSE; // normal ones bounce, alt ones explode on impact missile->s.pos.trType = TR_GRAVITY; @@ -1745,6 +1792,7 @@ static void WP_FlechetteAltFire( gentity_t *self ) AngleVectors( dir, fwd, NULL, NULL ); WP_CreateFlechetteBouncyThing( start, fwd, self ); + self->client->sess.missionStats.shotsFired++; } } @@ -1783,6 +1831,22 @@ void rocketThink( gentity_t *ent ) VectorCopy( ent->enemy->currentOrigin, org ); org[2] += (ent->enemy->mins[2] + ent->enemy->maxs[2]) * 0.5f; + if ( ent->enemy->client ) + { + switch( ent->enemy->client->NPC_class ) + { + case CLASS_ATST: + org[2] += 80; + break; + case CLASS_MARK1: + org[2] += 40; + break; + case CLASS_PROBE: + org[2] += 60; + break; + } + } + VectorSubtract( org, ent->currentOrigin, targetdir ); VectorNormalize( targetdir ); @@ -1799,19 +1863,19 @@ void rocketThink( gentity_t *ent ) if ( dot2 > 0 ) { // Turn 45 degrees right. - VectorMA( ent->movedir, 0.4f, right, newdir ); + VectorMA( ent->movedir, 0.3f, right, newdir ); } else { // Turn 45 degrees left. - VectorMA(ent->movedir, -0.4f, right, newdir); + VectorMA(ent->movedir, -0.3f, right, newdir); } // Yeah we've adjusted horizontally, but let's split the difference vertically, so we kinda try to move towards it. newdir[2] = ( targetdir[2] + ent->movedir[2] ) * 0.5; - // let's also slow down a lot - vel *= 0.5f; + // slowing down coupled with fairly tight turns can lead us to orbit an enemy..looks bad so don't do it! +// vel *= 0.5f; } else if ( dot < 0.70f ) { @@ -1897,10 +1961,10 @@ static void WP_FireRocket( gentity_t *ent, qboolean alt_fire ) if ( alt_fire ) { int lockEntNum, lockTime; - if ( ent->NPC ) + if ( ent->NPC && ent->enemy ) { lockEntNum = ent->enemy->s.number; - lockTime = 1200; + lockTime = Q_irand( 600, 1200 ); } else { @@ -2050,7 +2114,7 @@ static void WP_DropDetPack( gentity_t *self, vec3_t start, vec3_t dir ) VectorSet( missile->s.modelScale, 1.0f, 1.0f, 1.0f ); gi.G2API_InitGhoul2Model( missile->ghoul2, weaponData[WP_DET_PACK].missileMdl, G_ModelIndex( weaponData[WP_DET_PACK].missileMdl )); - AddSoundEvent( NULL, missile->currentOrigin, 128, AEL_MINOR ); + AddSoundEvent( NULL, missile->currentOrigin, 128, AEL_MINOR, qtrue ); AddSightEvent( NULL, missile->currentOrigin, 128, AEL_SUSPICIOUS, 10 ); } @@ -2188,7 +2252,7 @@ void WP_prox_mine_think( gentity_t *ent ) if ( blow ) { - G_Sound( ent, G_SoundIndex( "sound/weapons/flechette/warning.wav" )); +// G_Sound( ent, G_SoundIndex( "sound/weapons/flechette/warning.wav" )); ent->e_ThinkFunc = thinkF_WP_Explode; ent->nextthink = level.time + 200; } @@ -2664,9 +2728,10 @@ gentity_t *WP_FireThermalDetonator( gentity_t *ent, qboolean alt_fire ) bolt->mass = 10; // How 'bout we give this thing a size... - VectorSet( bolt->mins, -6.0f, -6.0f, -6.0f ); - VectorSet( bolt->maxs, 6.0f, 6.0f, 6.0f ); + VectorSet( bolt->mins, -4.0f, -4.0f, -4.0f ); + VectorSet( bolt->maxs, 4.0f, 4.0f, 4.0f ); bolt->clipmask = MASK_SHOT; + bolt->clipmask &= ~CONTENTS_CORPSE; bolt->contents = CONTENTS_SHOTCLIP; bolt->takedamage = qtrue; bolt->health = 15; @@ -2827,15 +2892,15 @@ void WP_ATSTMainFire( gentity_t *ent ) { float vel = ATST_MAIN_VEL; - if ( ent->client && (ent->client->ps.eFlags & EF_IN_ATST )) - { - vel = 4500.0f; - } +// if ( ent->client && (ent->client->ps.eFlags & EF_IN_ATST )) +// { +// vel = 4500.0f; +// } if ( !ent->s.number ) { // player shoots faster - vel *= 1.5f; + vel *= 1.6f; } gentity_t *missile = CreateMissile( muzzle, forward, vel, 10000, ent ); @@ -2970,12 +3035,12 @@ void WP_FireStunBaton( gentity_t *ent, qboolean alt_fire ) VectorMA( start, STUN_BATON_RANGE, forward, end ); - VectorSet( maxs, 6, 6, 6 ); + VectorSet( maxs, 5, 5, 5 ); VectorScale( maxs, -1, mins ); - gi.trace ( &tr, start, mins, maxs, end, ent->s.number, MASK_SHOT ); + gi.trace ( &tr, start, mins, maxs, end, ent->s.number, CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_SHOTCLIP ); - if ( tr.entityNum >= ENTITYNUM_WORLD ) + if ( tr.entityNum >= ENTITYNUM_WORLD || tr.entityNum < 0 ) { return; } @@ -2990,14 +3055,11 @@ void WP_FireStunBaton( gentity_t *ent, qboolean alt_fire ) // G_Sound( tr_ent, G_SoundIndex( va("sound/weapons/melee/punch%d", Q_irand(1, 4)) ) ); tr_ent->client->ps.powerups[PW_SHOCKED] = level.time + 1500; - if ( alt_fire ) - { - G_Damage( tr_ent, ent, ent, forward, tr.endpos, STUN_BATON_ALT_DAMAGE, 0, MOD_MELEE ); - } - else - { - G_Damage( tr_ent, ent, ent, forward, tr.endpos, STUN_BATON_DAMAGE, DAMAGE_NO_KNOCKBACK, MOD_MELEE ); - } + G_Damage( tr_ent, ent, ent, forward, tr.endpos, STUN_BATON_DAMAGE, DAMAGE_NO_KNOCKBACK, MOD_MELEE ); + } + else if ( tr_ent->svFlags & SVF_GLASS_BRUSH || ( tr_ent->svFlags & SVF_BBRUSH && tr_ent->material == 12 )) // material grate...we are breaking a grate! + { + G_Damage( tr_ent, ent, ent, forward, tr.endpos, 999, DAMAGE_NO_KNOCKBACK, MOD_MELEE ); // smash that puppy } } @@ -3061,6 +3123,22 @@ void AddLeanOfs(const gentity_t *const ent, vec3_t point) } } +//--------------------------------------------------------- +void SubtractLeanOfs(const gentity_t *const ent, vec3_t point) +//--------------------------------------------------------- +{ + if(ent->client) + { + if(ent->client->ps.leanofs) + { + vec3_t right; + //add leaning offset + AngleVectors( ent->client->ps.viewangles, NULL, right, NULL ); + VectorMA( point, ent->client->ps.leanofs*-1, right, point ); + } + } +} + //--------------------------------------------------------- void ViewHeightFix(const gentity_t *const ent) //--------------------------------------------------------- @@ -3090,6 +3168,79 @@ void ViewHeightFix(const gentity_t *const ent) } } +qboolean W_AccuracyLoggableWeapon( int weapon, qboolean alt_fire, int mod ) +{ + if ( mod != MOD_UNKNOWN ) + { + switch( mod ) + { + //standard weapons + case MOD_BRYAR: + case MOD_BRYAR_ALT: + case MOD_BLASTER: + case MOD_BLASTER_ALT: + case MOD_DISRUPTOR: + case MOD_SNIPER: + case MOD_BOWCASTER: + case MOD_BOWCASTER_ALT: + case MOD_ROCKET: + case MOD_ROCKET_ALT: + return qtrue; + break; + //non-alt standard + case MOD_REPEATER: + case MOD_DEMP2: + case MOD_FLECHETTE: + return qtrue; + break; + //emplaced gun + case MOD_EMPLACED: + return qtrue; + break; + //atst + case MOD_ENERGY: + case MOD_EXPLOSIVE: + if ( weapon == WP_ATST_MAIN || weapon == WP_ATST_SIDE ) + { + return qtrue; + } + break; + } + } + else if ( weapon != WP_NONE ) + { + switch( weapon ) + { + case WP_BRYAR_PISTOL: + case WP_BLASTER: + case WP_DISRUPTOR: + case WP_BOWCASTER: + case WP_ROCKET_LAUNCHER: + return qtrue; + break; + //non-alt standard + case WP_REPEATER: + case WP_DEMP2: + case WP_FLECHETTE: + if ( !alt_fire ) + { + return qtrue; + } + break; + //emplaced gun + case WP_EMPLACED_GUN: + return qtrue; + break; + //atst + case WP_ATST_MAIN: + case WP_ATST_SIDE: + return qtrue; + break; + } + } + return qfalse; +} + /* =============== LogAccuracyHit @@ -3225,7 +3376,7 @@ void CalcMuzzlePoint( gentity_t *const ent, vec3_t forward, vec3_t right, vec3_t void FireWeapon( gentity_t *ent, qboolean alt_fire ) //--------------------------------------------------------- { - qboolean alert = qtrue; + float alert = 256; // track shots taken for accuracy tracking. ent->client->ps.persistant[PERS_ACCURACY_SHOTS]++; @@ -3351,6 +3502,7 @@ void FireWeapon( gentity_t *ent, qboolean alt_fire ) break; case WP_DISRUPTOR: + alert = 50; // if you want it to alert enemies, remove this WP_FireDisruptor( ent, alt_fire ); break; @@ -3379,12 +3531,12 @@ void FireWeapon( gentity_t *ent, qboolean alt_fire ) break; case WP_TRIP_MINE: - alert = qfalse; // if you want it to alert enemies, remove this + alert = 0; // if you want it to alert enemies, remove this WP_PlaceLaserTrap( ent, alt_fire ); break; case WP_DET_PACK: - alert = qfalse; // if you want it to alert enemies, remove this + alert = 0; // if you want it to alert enemies, remove this WP_FireDetPack( ent, alt_fire ); break; @@ -3398,6 +3550,7 @@ void FireWeapon( gentity_t *ent, qboolean alt_fire ) break; case WP_MELEE: + alert = 0; // if you want it to alert enemies, remove this WP_Melee( ent ); break; @@ -3462,13 +3615,19 @@ void FireWeapon( gentity_t *ent, qboolean alt_fire ) if ( !ent->s.number ) { - ent->client->sess.missionStats.shotsFired++; + if ( ent->s.weapon == WP_FLECHETTE || (ent->s.weapon == WP_BOWCASTER && !alt_fire) ) + {//these can fire multiple shots, count them individually within the firing functions + } + else if ( W_AccuracyLoggableWeapon( ent->s.weapon, alt_fire, MOD_UNKNOWN ) ) + { + ent->client->sess.missionStats.shotsFired++; + } } // We should probably just use this as a default behavior, in special cases, just set alert to false. - if ( ent->s.number == 0 && alert ) + if ( ent->s.number == 0 && alert > 0 ) { - AddSoundEvent( ent, muzzle, 256, AEL_DISCOVERED ); - AddSightEvent( ent, muzzle, 512, AEL_DISCOVERED, 20 ); + AddSoundEvent( ent, muzzle, alert, AEL_DISCOVERED ); + AddSightEvent( ent, muzzle, alert*2, AEL_DISCOVERED, 20 ); } } @@ -3485,7 +3644,7 @@ void FireWeapon( gentity_t *ent, qboolean alt_fire ) FACING - player must be facing relatively in the same direction as the gun in order to use it VULNERABLE - allow the gun to take damage - count - how much ammo to give this gun ( default 400 ) + count - how much ammo to give this gun ( default 999 ) health - how much damage the gun can take before it blows ( default 250 ) delay - ONLY AFFECTS NPCs - time between shots ( default 200 on hardest setting ) wait - ONLY AFFECTS NPCs - time between bursts ( default 800 on hardest setting ) @@ -3514,6 +3673,12 @@ void emplaced_gun_use( gentity_t *self, gentity_t *other, gentity_t *activator ) return; // only a client can use it. } + if ( self->activator ) + { + // someone is already in the gun. + return; + } + // We'll just let the designers duke this one out....I mean, as to whether they even want to limit such a thing. if ( self->spawnflags & EMPLACED_FACING ) { @@ -3537,6 +3702,11 @@ void emplaced_gun_use( gentity_t *self, gentity_t *other, gentity_t *activator ) { int oldWeapon = activator->s.weapon; + if ( oldWeapon == WP_SABER ) + { + self->alt_fire = activator->client->ps.saberActive; + } + // swap the users weapon with the emplaced gun and add the ammo the gun has to the player activator->client->ps.weapon = self->s.weapon; Add_Ammo( activator, WP_EMPLACED_GUN, self->count ); @@ -3546,7 +3716,7 @@ void emplaced_gun_use( gentity_t *self, gentity_t *other, gentity_t *activator ) activator->owner = self; // kind of dumb, but when we are locked to the weapon, we are owned by it. self->activator = activator; - if ( activator->weaponModel != -1 ) + if ( activator->weaponModel >= 0 ) { // rip that gun out of their hands.... gi.G2API_RemoveGhoul2Model( activator->ghoul2, activator->weaponModel ); @@ -3556,7 +3726,7 @@ void emplaced_gun_use( gentity_t *self, gentity_t *other, gentity_t *activator ) extern void ChangeWeapon( gentity_t *ent, int newWeapon ); if ( activator->NPC ) { - if ( activator->weaponModel != -1 ) + if ( activator->weaponModel >= 0 ) { // rip that gun out of their hands.... gi.G2API_RemoveGhoul2Model( activator->ghoul2, activator->weaponModel ); @@ -3574,6 +3744,7 @@ extern void ChangeWeapon( gentity_t *ent, int newWeapon ); { // we don't want for it to draw the weapon select stuff cg.weaponSelect = WP_EMPLACED_GUN; + CG_CenterPrint( "@INGAME_EXIT_VIEW", SCREEN_HEIGHT * 0.95 ); } // Since we move the activator inside of the gun, we reserve a solid spot where they were standing in order to be able to get back out without being in solid if ( self->nextTrain ) @@ -3717,9 +3888,10 @@ void emplaced_gun_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacke ugly[ROLL] = crandom() * 7; gi.G2API_SetBoneAnglesIndex( &self->ghoul2[self->playerModel], self->lowerLumbarBone, ugly, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL ); - VectorSet( org, 0, 0, 1 ); + VectorCopy( self->currentOrigin, org ); + org[2] += 20; - G_PlayEffect( "emplaced/explode", self->currentOrigin, org ); + G_PlayEffect( "emplaced/explode", org ); // create some persistent smoke by using a dynamically created fx runner gentity_t *ent = G_Spawn(); @@ -3765,9 +3937,11 @@ void SP_emplaced_gun( gentity_t *ent ) VectorSet( ent->mins, -30, -30, -5 ); VectorSet( ent->maxs, 30, 30, 60 ); - if ( ent->spawnflags & EMPLACED_VULNERABLE ) + ent->takedamage = qtrue; + + if ( !( ent->spawnflags & EMPLACED_VULNERABLE )) { - ent->takedamage = qtrue; + ent->flags |= FL_GODMODE; } ent->s.radius = 110; @@ -3785,7 +3959,7 @@ void SP_emplaced_gun( gentity_t *ent ) G_SoundIndex( "sound/weapons/emplaced/emplaced_move_lp.wav" ); // Set up our defaults and override with custom amounts as necessary - G_SpawnInt( "count", "600", &ent->count ); + G_SpawnInt( "count", "999", &ent->count ); G_SpawnInt( "health", "250", &ent->health ); G_SpawnInt( "splashDamage", "80", &ent->splashDamage ); G_SpawnInt( "splashRadius", "128", &ent->splashRadius ); diff --git a/code/game/game.def b/code/game/game.def new file mode 100644 index 0000000..d405f05 --- /dev/null +++ b/code/game/game.def @@ -0,0 +1,4 @@ +EXPORTS + GetGameAPI + vmMain + dllEntry diff --git a/code/game/game.dsp b/code/game/game.dsp index e0b1f59..7478572 100644 --- a/code/game/game.dsp +++ b/code/game/game.dsp @@ -272,6 +272,11 @@ SOURCE=..\cgame\cg_consolecmds.cpp # End Source File # Begin Source File +SOURCE=..\cgame\cg_credits.cpp +# ADD CPP /Yu"cg_headers.h" +# End Source File +# Begin Source File + SOURCE=..\cgame\cg_draw.cpp # ADD CPP /Yu"cg_headers.h" # End Source File @@ -984,6 +989,10 @@ SOURCE=.\common_headers.h # End Source File # Begin Source File +SOURCE=.\dmstates.h +# End Source File +# Begin Source File + SOURCE=.\events.h # End Source File # Begin Source File diff --git a/code/game/game.plg b/code/game/game.plg new file mode 100644 index 0000000..529ec50 --- /dev/null +++ b/code/game/game.plg @@ -0,0 +1,317 @@ + + +
+

Build Log

+

+--------------------Configuration: game - Win32 Debug-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP89.tmp" with contents +[ +/nologo /G6 /MLd /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\Debug\game/" /Fp"..\Debug\game/game.pch" /Yu"g_headers.h" /Fo"..\Debug\game/" /Fd"..\Debug\game/" /FD /c +"C:\projects\jk2\CODE\Icarus\Sequencer.cpp" +"C:\projects\jk2\CODE\game\g_items.cpp" +"C:\projects\jk2\CODE\game\g_mover.cpp" +"C:\projects\jk2\CODE\game\g_svcmds.cpp" +"C:\projects\jk2\CODE\game\NPC_spawn.cpp" +"C:\projects\jk2\CODE\game\wp_saber.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP89.tmp" +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP8A.tmp" with contents +[ +/nologo /G6 /MLd /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\Debug\game/" /Fp"..\Debug\game/game.pch" /Yu"common_headers.h" /Fo"..\Debug\game/" /Fd"..\Debug\game/" /FD /c +"C:\projects\jk2\CODE\game\bg_panimate.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP8A.tmp" +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP8B.tmp" with contents +[ +/nologo /G6 /MLd /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\Debug\game/" /Fp"..\Debug\game/game.pch" /Yu"cg_headers.h" /Fo"..\Debug\game/" /Fd"..\Debug\game/" /FD /c +"C:\projects\jk2\CODE\cgame\cg_main.cpp" +"C:\projects\jk2\CODE\cgame\cg_players.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP8B.tmp" +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP8C.tmp" with contents +[ +kernel32.lib user32.lib winmm.lib /nologo /base:"0x20000000" /subsystem:windows /dll /incremental:yes /pdb:"..\Debug/jk2gamex86.pdb" /debug /machine:I386 /def:".\game.def" /out:"..\Debug/jk2gamex86.dll" /implib:"..\Debug/jk2gamex86.lib" +\projects\jk2\CODE\Debug\game\BlockStream.obj +\projects\jk2\CODE\Debug\game\Instance.obj +\projects\jk2\CODE\Debug\game\Sequence.obj +\projects\jk2\CODE\Debug\game\Sequencer.obj +\projects\jk2\CODE\Debug\game\TaskManager.obj +\projects\jk2\CODE\Debug\game\bg_misc.obj +\projects\jk2\CODE\Debug\game\bg_pangles.obj +\projects\jk2\CODE\Debug\game\bg_panimate.obj +\projects\jk2\CODE\Debug\game\bg_pmove.obj +\projects\jk2\CODE\Debug\game\bg_slidemove.obj +\projects\jk2\CODE\Debug\game\cg_camera.obj +\projects\jk2\CODE\Debug\game\cg_consolecmds.obj +\projects\jk2\CODE\Debug\game\cg_draw.obj +\projects\jk2\CODE\Debug\game\cg_drawtools.obj +\projects\jk2\CODE\Debug\game\cg_effects.obj +\projects\jk2\CODE\Debug\game\cg_ents.obj +\projects\jk2\CODE\Debug\game\cg_event.obj +\projects\jk2\CODE\Debug\game\cg_headers.obj +\projects\jk2\CODE\Debug\game\cg_info.obj +\projects\jk2\CODE\Debug\game\cg_lights.obj +\projects\jk2\CODE\Debug\game\cg_localents.obj +\projects\jk2\CODE\Debug\game\cg_main.obj +\projects\jk2\CODE\Debug\game\cg_marks.obj +\projects\jk2\CODE\Debug\game\cg_players.obj +\projects\jk2\CODE\Debug\game\cg_playerstate.obj +\projects\jk2\CODE\Debug\game\cg_predict.obj +\projects\jk2\CODE\Debug\game\cg_scoreboard.obj +\projects\jk2\CODE\Debug\game\cg_servercmds.obj +\projects\jk2\CODE\Debug\game\cg_snapshot.obj +\projects\jk2\CODE\Debug\game\cg_syscalls.obj +\projects\jk2\CODE\Debug\game\cg_text.obj +\projects\jk2\CODE\Debug\game\cg_view.obj +\projects\jk2\CODE\Debug\game\cg_weapons.obj +\projects\jk2\CODE\Debug\game\FX_ATSTMain.obj +\projects\jk2\CODE\Debug\game\FX_Blaster.obj +\projects\jk2\CODE\Debug\game\FX_Bowcaster.obj +\projects\jk2\CODE\Debug\game\FX_BryarPistol.obj +\projects\jk2\CODE\Debug\game\FX_DEMP2.obj +\projects\jk2\CODE\Debug\game\FX_Disruptor.obj +\projects\jk2\CODE\Debug\game\FX_Emplaced.obj +\projects\jk2\CODE\Debug\game\FX_Flechette.obj +\projects\jk2\CODE\Debug\game\FX_HeavyRepeater.obj +\projects\jk2\CODE\Debug\game\FX_RocketLauncher.obj +\projects\jk2\CODE\Debug\game\FxParsing.obj +\projects\jk2\CODE\Debug\game\FxPrimitives.obj +\projects\jk2\CODE\Debug\game\FxScheduler.obj +\projects\jk2\CODE\Debug\game\FxSystem.obj +\projects\jk2\CODE\Debug\game\FxTemplate.obj +\projects\jk2\CODE\Debug\game\FxUtil.obj +\projects\jk2\CODE\Debug\game\AI_Atst.obj +\projects\jk2\CODE\Debug\game\AI_Default.obj +\projects\jk2\CODE\Debug\game\AI_Droid.obj +\projects\jk2\CODE\Debug\game\AI_GalakMech.obj +\projects\jk2\CODE\Debug\game\AI_Grenadier.obj +\projects\jk2\CODE\Debug\game\AI_Howler.obj +\projects\jk2\CODE\Debug\game\AI_ImperialProbe.obj +\projects\jk2\CODE\Debug\game\AI_Interrogator.obj +\projects\jk2\CODE\Debug\game\AI_Jedi.obj +\projects\jk2\CODE\Debug\game\AI_Mark1.obj +\projects\jk2\CODE\Debug\game\AI_Mark2.obj +\projects\jk2\CODE\Debug\game\AI_MineMonster.obj +\projects\jk2\CODE\Debug\game\AI_Remote.obj +\projects\jk2\CODE\Debug\game\AI_Seeker.obj +\projects\jk2\CODE\Debug\game\AI_Sentry.obj +\projects\jk2\CODE\Debug\game\AI_Sniper.obj +\projects\jk2\CODE\Debug\game\AI_Stormtrooper.obj +\projects\jk2\CODE\Debug\game\AI_Utils.obj +\projects\jk2\CODE\Debug\game\g_active.obj +\projects\jk2\CODE\Debug\game\g_breakable.obj +\projects\jk2\CODE\Debug\game\g_camera.obj +\projects\jk2\CODE\Debug\game\g_client.obj +\projects\jk2\CODE\Debug\game\g_cmds.obj +\projects\jk2\CODE\Debug\game\g_combat.obj +\projects\jk2\CODE\Debug\game\g_functions.obj +\projects\jk2\CODE\Debug\game\g_fx.obj +\projects\jk2\CODE\Debug\game\g_headers.obj +\projects\jk2\CODE\Debug\game\g_ICARUS.obj +\projects\jk2\CODE\Debug\game\g_inventory.obj +\projects\jk2\CODE\Debug\game\g_itemLoad.obj +\projects\jk2\CODE\Debug\game\g_items.obj +\projects\jk2\CODE\Debug\game\g_main.obj +\projects\jk2\CODE\Debug\game\g_mem.obj +\projects\jk2\CODE\Debug\game\g_misc.obj +\projects\jk2\CODE\Debug\game\g_misc_model.obj +\projects\jk2\CODE\Debug\game\g_missile.obj +\projects\jk2\CODE\Debug\game\g_mover.obj +\projects\jk2\CODE\Debug\game\g_nav.obj +\projects\jk2\CODE\Debug\game\g_navigator.obj +\projects\jk2\CODE\Debug\game\g_navnew.obj +\projects\jk2\CODE\Debug\game\g_object.obj +\projects\jk2\CODE\Debug\game\g_objectives.obj +\projects\jk2\CODE\Debug\game\g_ref.obj +\projects\jk2\CODE\Debug\game\g_roff.obj +\projects\jk2\CODE\Debug\game\g_savegame.obj +\projects\jk2\CODE\Debug\game\g_session.obj +\projects\jk2\CODE\Debug\game\g_spawn.obj +\projects\jk2\CODE\Debug\game\g_svcmds.obj +\projects\jk2\CODE\Debug\game\g_target.obj +\projects\jk2\CODE\Debug\game\G_Timer.obj +\projects\jk2\CODE\Debug\game\g_trigger.obj +\projects\jk2\CODE\Debug\game\g_turret.obj +\projects\jk2\CODE\Debug\game\g_usable.obj +\projects\jk2\CODE\Debug\game\g_utils.obj +\projects\jk2\CODE\Debug\game\g_weapon.obj +\projects\jk2\CODE\Debug\game\g_weaponLoad.obj +\projects\jk2\CODE\Debug\game\gameinfo.obj +\projects\jk2\CODE\Debug\game\genericparser2.obj +\projects\jk2\CODE\Debug\game\NPC.obj +\projects\jk2\CODE\Debug\game\NPC_behavior.obj +\projects\jk2\CODE\Debug\game\NPC_combat.obj +\projects\jk2\CODE\Debug\game\NPC_goal.obj +\projects\jk2\CODE\Debug\game\NPC_misc.obj +\projects\jk2\CODE\Debug\game\NPC_move.obj +\projects\jk2\CODE\Debug\game\NPC_reactions.obj +\projects\jk2\CODE\Debug\game\NPC_senses.obj +\projects\jk2\CODE\Debug\game\NPC_sounds.obj +\projects\jk2\CODE\Debug\game\NPC_spawn.obj +\projects\jk2\CODE\Debug\game\NPC_stats.obj +\projects\jk2\CODE\Debug\game\NPC_utils.obj +\projects\jk2\CODE\Debug\game\Q3_Interface.obj +\projects\jk2\CODE\Debug\game\Q3_Registers.obj +\projects\jk2\CODE\Debug\game\q_math.obj +\projects\jk2\CODE\Debug\game\q_shared.obj +\projects\jk2\CODE\Debug\game\tri_coll_test.obj +\projects\jk2\CODE\Debug\game\wp_saber.obj +] +Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP8C.tmp" +

Output Window

+Compiling... +Sequencer.cpp +g_items.cpp +g_mover.cpp +g_svcmds.cpp +NPC_spawn.cpp +wp_saber.cpp +Generating Code... +Compiling... +bg_panimate.cpp +Compiling... +cg_main.cpp +cg_players.cpp +Generating Code... +Linking... +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP90.tmp" with contents +[ +/nologo /o"..\Debug/game.bsc" +\projects\jk2\CODE\Debug\game\g_headers.sbr +\projects\jk2\CODE\Debug\game\BlockStream.sbr +\projects\jk2\CODE\Debug\game\Instance.sbr +\projects\jk2\CODE\Debug\game\Sequence.sbr +\projects\jk2\CODE\Debug\game\Sequencer.sbr +\projects\jk2\CODE\Debug\game\TaskManager.sbr +\projects\jk2\CODE\Debug\game\bg_misc.sbr +\projects\jk2\CODE\Debug\game\bg_pangles.sbr +\projects\jk2\CODE\Debug\game\bg_panimate.sbr +\projects\jk2\CODE\Debug\game\bg_pmove.sbr +\projects\jk2\CODE\Debug\game\bg_slidemove.sbr +\projects\jk2\CODE\Debug\game\cg_camera.sbr +\projects\jk2\CODE\Debug\game\cg_consolecmds.sbr +\projects\jk2\CODE\Debug\game\cg_draw.sbr +\projects\jk2\CODE\Debug\game\cg_drawtools.sbr +\projects\jk2\CODE\Debug\game\cg_effects.sbr +\projects\jk2\CODE\Debug\game\cg_ents.sbr +\projects\jk2\CODE\Debug\game\cg_event.sbr +\projects\jk2\CODE\Debug\game\cg_headers.sbr +\projects\jk2\CODE\Debug\game\cg_info.sbr +\projects\jk2\CODE\Debug\game\cg_lights.sbr +\projects\jk2\CODE\Debug\game\cg_localents.sbr +\projects\jk2\CODE\Debug\game\cg_main.sbr +\projects\jk2\CODE\Debug\game\cg_marks.sbr +\projects\jk2\CODE\Debug\game\cg_players.sbr +\projects\jk2\CODE\Debug\game\cg_playerstate.sbr +\projects\jk2\CODE\Debug\game\cg_predict.sbr +\projects\jk2\CODE\Debug\game\cg_scoreboard.sbr +\projects\jk2\CODE\Debug\game\cg_servercmds.sbr +\projects\jk2\CODE\Debug\game\cg_snapshot.sbr +\projects\jk2\CODE\Debug\game\cg_syscalls.sbr +\projects\jk2\CODE\Debug\game\cg_text.sbr +\projects\jk2\CODE\Debug\game\cg_view.sbr +\projects\jk2\CODE\Debug\game\cg_weapons.sbr +\projects\jk2\CODE\Debug\game\FX_ATSTMain.sbr +\projects\jk2\CODE\Debug\game\FX_Blaster.sbr +\projects\jk2\CODE\Debug\game\FX_Bowcaster.sbr +\projects\jk2\CODE\Debug\game\FX_BryarPistol.sbr +\projects\jk2\CODE\Debug\game\FX_DEMP2.sbr +\projects\jk2\CODE\Debug\game\FX_Disruptor.sbr +\projects\jk2\CODE\Debug\game\FX_Emplaced.sbr +\projects\jk2\CODE\Debug\game\FX_Flechette.sbr +\projects\jk2\CODE\Debug\game\FX_HeavyRepeater.sbr +\projects\jk2\CODE\Debug\game\FX_RocketLauncher.sbr +\projects\jk2\CODE\Debug\game\FxParsing.sbr +\projects\jk2\CODE\Debug\game\FxPrimitives.sbr +\projects\jk2\CODE\Debug\game\FxScheduler.sbr +\projects\jk2\CODE\Debug\game\FxSystem.sbr +\projects\jk2\CODE\Debug\game\FxTemplate.sbr +\projects\jk2\CODE\Debug\game\FxUtil.sbr +\projects\jk2\CODE\Debug\game\AI_Atst.sbr +\projects\jk2\CODE\Debug\game\AI_Default.sbr +\projects\jk2\CODE\Debug\game\AI_Droid.sbr +\projects\jk2\CODE\Debug\game\AI_GalakMech.sbr +\projects\jk2\CODE\Debug\game\AI_Grenadier.sbr +\projects\jk2\CODE\Debug\game\AI_Howler.sbr +\projects\jk2\CODE\Debug\game\AI_ImperialProbe.sbr +\projects\jk2\CODE\Debug\game\AI_Interrogator.sbr +\projects\jk2\CODE\Debug\game\AI_Jedi.sbr +\projects\jk2\CODE\Debug\game\AI_Mark1.sbr +\projects\jk2\CODE\Debug\game\AI_Mark2.sbr +\projects\jk2\CODE\Debug\game\AI_MineMonster.sbr +\projects\jk2\CODE\Debug\game\AI_Remote.sbr +\projects\jk2\CODE\Debug\game\AI_Seeker.sbr +\projects\jk2\CODE\Debug\game\AI_Sentry.sbr +\projects\jk2\CODE\Debug\game\AI_Sniper.sbr +\projects\jk2\CODE\Debug\game\AI_Stormtrooper.sbr +\projects\jk2\CODE\Debug\game\AI_Utils.sbr +\projects\jk2\CODE\Debug\game\g_active.sbr +\projects\jk2\CODE\Debug\game\g_breakable.sbr +\projects\jk2\CODE\Debug\game\g_camera.sbr +\projects\jk2\CODE\Debug\game\g_client.sbr +\projects\jk2\CODE\Debug\game\g_cmds.sbr +\projects\jk2\CODE\Debug\game\g_combat.sbr +\projects\jk2\CODE\Debug\game\g_functions.sbr +\projects\jk2\CODE\Debug\game\g_fx.sbr +\projects\jk2\CODE\Debug\game\g_ICARUS.sbr +\projects\jk2\CODE\Debug\game\g_inventory.sbr +\projects\jk2\CODE\Debug\game\g_itemLoad.sbr +\projects\jk2\CODE\Debug\game\g_items.sbr +\projects\jk2\CODE\Debug\game\g_main.sbr +\projects\jk2\CODE\Debug\game\g_mem.sbr +\projects\jk2\CODE\Debug\game\g_misc.sbr +\projects\jk2\CODE\Debug\game\g_misc_model.sbr +\projects\jk2\CODE\Debug\game\g_missile.sbr +\projects\jk2\CODE\Debug\game\g_mover.sbr +\projects\jk2\CODE\Debug\game\g_nav.sbr +\projects\jk2\CODE\Debug\game\g_navigator.sbr +\projects\jk2\CODE\Debug\game\g_navnew.sbr +\projects\jk2\CODE\Debug\game\g_object.sbr +\projects\jk2\CODE\Debug\game\g_objectives.sbr +\projects\jk2\CODE\Debug\game\g_ref.sbr +\projects\jk2\CODE\Debug\game\g_roff.sbr +\projects\jk2\CODE\Debug\game\g_savegame.sbr +\projects\jk2\CODE\Debug\game\g_session.sbr +\projects\jk2\CODE\Debug\game\g_spawn.sbr +\projects\jk2\CODE\Debug\game\g_svcmds.sbr +\projects\jk2\CODE\Debug\game\g_target.sbr +\projects\jk2\CODE\Debug\game\G_Timer.sbr +\projects\jk2\CODE\Debug\game\g_trigger.sbr +\projects\jk2\CODE\Debug\game\g_turret.sbr +\projects\jk2\CODE\Debug\game\g_usable.sbr +\projects\jk2\CODE\Debug\game\g_utils.sbr +\projects\jk2\CODE\Debug\game\g_weapon.sbr +\projects\jk2\CODE\Debug\game\g_weaponLoad.sbr +\projects\jk2\CODE\Debug\game\gameinfo.sbr +\projects\jk2\CODE\Debug\game\genericparser2.sbr +\projects\jk2\CODE\Debug\game\NPC.sbr +\projects\jk2\CODE\Debug\game\NPC_behavior.sbr +\projects\jk2\CODE\Debug\game\NPC_combat.sbr +\projects\jk2\CODE\Debug\game\NPC_goal.sbr +\projects\jk2\CODE\Debug\game\NPC_misc.sbr +\projects\jk2\CODE\Debug\game\NPC_move.sbr +\projects\jk2\CODE\Debug\game\NPC_reactions.sbr +\projects\jk2\CODE\Debug\game\NPC_senses.sbr +\projects\jk2\CODE\Debug\game\NPC_sounds.sbr +\projects\jk2\CODE\Debug\game\NPC_spawn.sbr +\projects\jk2\CODE\Debug\game\NPC_stats.sbr +\projects\jk2\CODE\Debug\game\NPC_utils.sbr +\projects\jk2\CODE\Debug\game\Q3_Interface.sbr +\projects\jk2\CODE\Debug\game\Q3_Registers.sbr +\projects\jk2\CODE\Debug\game\q_math.sbr +\projects\jk2\CODE\Debug\game\q_shared.sbr +\projects\jk2\CODE\Debug\game\tri_coll_test.sbr +\projects\jk2\CODE\Debug\game\wp_saber.sbr] +Creating command line "bscmake.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP90.tmp" +Creating browse info file... +

Output Window

+ + + +

Results

+jk2gamex86.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/code/game/ghoul2_shared.h b/code/game/ghoul2_shared.h index 0f2bd9d..501a599 100644 --- a/code/game/ghoul2_shared.h +++ b/code/game/ghoul2_shared.h @@ -52,16 +52,14 @@ surfaceInfo_t(): #define BONE_ANGLES_PREMULT 0x0001 #define BONE_ANGLES_POSTMULT 0x0002 #define BONE_ANGLES_REPLACE 0x0004 -#define BONE_ANGLES_REPLACE_TO_ANIM 0x0400 -#define BONE_ANGLES_TOTAL ( BONE_ANGLES_PREMULT | BONE_ANGLES_POSTMULT | BONE_ANGLES_REPLACE | BONE_ANGLES_REPLACE_TO_ANIM ) +#define BONE_ANGLES_TOTAL ( BONE_ANGLES_PREMULT | BONE_ANGLES_POSTMULT | BONE_ANGLES_REPLACE ) #define BONE_ANIM_OVERRIDE 0x0008 #define BONE_ANIM_OVERRIDE_LOOP 0x0010 // Causes Last Frame To Lerp to First Frame And Start Over -#define BONE_ANIM_OVERRIDE_DEFAULT (0x0020 + BONE_ANIM_OVERRIDE) #define BONE_ANIM_OVERRIDE_FREEZE (0x0040 + BONE_ANIM_OVERRIDE) // Causes Last Frame To Freeze And Not Loop To Beginning #define BONE_ANIM_BLEND 0x0080 // Blends to and from previously played frame on same bone for given time #define BONE_ANIM_NO_LERP 0x1000 -#define BONE_ANIM_TOTAL (BONE_ANIM_NO_LERP| BONE_ANIM_OVERRIDE | BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE_DEFAULT | BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ) +#define BONE_ANIM_TOTAL (BONE_ANIM_NO_LERP| BONE_ANIM_OVERRIDE | BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE_FREEZE | BONE_ANIM_BLEND ) #define BONE_INDEX_INVALID -1 @@ -90,7 +88,6 @@ struct boneInfo_t int blendStart; // Time when blending starts - not necessarily the same as startTime since we might start half way through an anim int boneBlendTime; // time for duration of bone angle blend with normal animation int boneBlendStart; // time bone angle blend with normal animation began - int lastTime; // this does not go across the network mdxaBone_t newMatrix; // This is the lerped matrix that Ghoul2 uses on the client side - does not go across the network boneInfo_t(): @@ -106,8 +103,7 @@ boneInfo_t(): blendTime(0), blendStart(0), boneBlendTime(0), - boneBlendStart(0), - lastTime(0) + boneBlendStart(0) { matrix.matrix[0][0] = matrix.matrix[0][1] = matrix.matrix[0][2] = matrix.matrix[0][3] = matrix.matrix[1][0] = matrix.matrix[1][1] = matrix.matrix[1][2] = matrix.matrix[1][3] = diff --git a/code/game/mssccprj.scc b/code/game/mssccprj.scc new file mode 100644 index 0000000..44583b2 --- /dev/null +++ b/code/game/mssccprj.scc @@ -0,0 +1,5 @@ +SCC = This is a Source Code Control file + +[game.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\StarWars" +SCC_Project_Name = "$/Code/game", OVOAAAAA diff --git a/code/game/q_shared.h b/code/game/q_shared.h index 7e646a1..a688553 100644 --- a/code/game/q_shared.h +++ b/code/game/q_shared.h @@ -1268,6 +1268,17 @@ typedef enum #define MIN_WORLD_COORD ( -64*1024 ) #define WORLD_SIZE ( MAX_WORLD_COORD - MIN_WORLD_COORD ) +typedef enum +{ + WHL_NONE, + WHL_ANKLES, + WHL_KNEES, + WHL_WAIST, + WHL_TORSO, + WHL_SHOULDERS, + WHL_HEAD, + WHL_UNDER +} waterHeightLevel_t; // playerState_t is the information needed by both the client and server // to predict player motion and actions @@ -1342,7 +1353,7 @@ typedef struct playerState_s { int inventory[MAX_INVENTORY]; // Count of each inventory item. char security_key_message[MAX_SECURITY_KEYS][MAX_SECURITY_KEY_MESSSAGE]; // Security key types - vec3_t pushVec; + vec3_t serverViewOrg; qboolean saberInFlight; qboolean saberActive; @@ -1402,6 +1413,9 @@ typedef struct playerState_s { float jumpZStart; //So when you land, you don't get hurt as much vec3_t moveDir; + + float waterheight; //exactly what the z org of the water is (will be +4 above if under water, -4 below if not in water) + waterHeightLevel_t waterHeightLevel; //how high it really is } playerState_t; @@ -1516,8 +1530,6 @@ typedef struct entityState_s {// !!!!!!!!!!! LOADSAVE-affecting struct !!!!!!!!! int scale; //Scale players - vec3_t pushVec; - qboolean saberInFlight; qboolean saberActive; diff --git a/code/game/vssver.scc b/code/game/vssver.scc new file mode 100644 index 0000000..56a7e12 Binary files /dev/null and b/code/game/vssver.scc differ diff --git a/code/game/wp_saber.cpp b/code/game/wp_saber.cpp index d967ab5..0a63f99 100644 --- a/code/game/wp_saber.cpp +++ b/code/game/wp_saber.cpp @@ -18,6 +18,7 @@ static vec3_t dmgSpot[MAX_SABER_VICTIMS]; static float dmgFraction[MAX_SABER_VICTIMS]; static int hitLoc[MAX_SABER_VICTIMS]; static qboolean hitDismember[MAX_SABER_VICTIMS]; +static int hitDismemberLoc[MAX_SABER_VICTIMS]; static vec3_t saberHitLocation, saberHitNormal={0,0,1.0}; static float saberHitFraction; static float sabersCrossed; @@ -30,18 +31,24 @@ static int numVictims = 0; extern cvar_t *g_timescale; extern cvar_t *g_dismemberment; +extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType ); +extern qboolean G_ClearViewEntity( gentity_t *ent ); +extern void G_SetViewEntity( gentity_t *self, gentity_t *viewEntity ); +extern qboolean G_ControlledByPlayer( gentity_t *self ); extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); extern void CG_ChangeWeapon( int num ); extern void G_ReflectMissile( gentity_t *ent, gentity_t *missile, vec3_t forward ); +extern int G_CheckLedgeDive( gentity_t *self, float checkDist, vec3_t checkVel, qboolean tryOpposite, qboolean tryPerp ); extern void G_BounceMissile( gentity_t *ent, trace_t *trace ); extern qboolean G_PointInBounds( const vec3_t point, const vec3_t mins, const vec3_t maxs ); extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath ); extern void NPC_UseResponse( gentity_t *self, gentity_t *user, qboolean useWhenDone ); extern void WP_FireDreadnoughtBeam( gentity_t *ent ); extern void G_MissileImpacted( gentity_t *ent, gentity_t *other, vec3_t impactPos, vec3_t normal, int hitLoc=HL_NONE ); -extern evasionType_t Jedi_SaberBlockGo( gentity_t *self, vec3_t pHitloc, vec3_t phitDir, gentity_t *incoming, float dist = 0.0f ); +extern evasionType_t Jedi_SaberBlockGo( gentity_t *self, usercmd_t *cmd, vec3_t pHitloc, vec3_t phitDir, gentity_t *incoming, float dist = 0.0f ); extern int PM_PickAnim( gentity_t *self, int minAnim, int maxAnim ); extern void NPC_SetPainEvent( gentity_t *self ); +extern qboolean PM_SwimmingAnim( int anim ); extern qboolean PM_InAnimForSaberMove( int anim, int saberMove ); extern qboolean PM_SpinningSaberAnim( int anim ); extern qboolean PM_SaberInSpecialAttack( int anim ); @@ -80,7 +87,7 @@ qboolean WP_ForcePowerUsable( gentity_t *self, forcePowers_t forcePower, int ove void WP_SaberInFlightReflectCheck( gentity_t *self, usercmd_t *ucmd ); void WP_SaberDrop( gentity_t *self, gentity_t *saber ); -void WP_SaberLose( gentity_t *self, vec3_t throwDir ); +qboolean WP_SaberLose( gentity_t *self, vec3_t throwDir ); void WP_SaberReturn( gentity_t *self, gentity_t *saber ); void WP_SaberBlock( gentity_t *saber, vec3_t hitloc, qboolean missleBlock ); void WP_SaberBlockNonRandom( gentity_t *self, vec3_t hitloc, qboolean missileBlock ); @@ -88,17 +95,18 @@ void ForceThrow( gentity_t *self, qboolean pull ); qboolean WP_ForcePowerAvailable( gentity_t *self, forcePowers_t forcePower, int overrideAmt ); void WP_ForcePowerDrain( gentity_t *self, forcePowers_t forcePower, int overrideAmt ); -extern cvar_t *g_autoBlocking; -extern cvar_t *g_realisticSaberDamage; +extern cvar_t *g_saberAutoBlocking; +extern cvar_t *g_saberRealisticCombat; +extern int g_crosshairEntNum; int g_saberFlashTime = 0; vec3_t g_saberFlashPos = {0,0,0}; int forcePowerNeeded[NUM_FORCE_POWERS] = { - 4,//FP_HEAL,//instant + 0,//FP_HEAL,//instant 10,//FP_LEVITATION,//hold/duration - 20,//FP_SPEED,//duration + 50,//FP_SPEED,//duration 15,//FP_PUSH,//hold/duration 15,//FP_PULL,//hold/duration 20,//FP_TELEPATHY,//instant @@ -126,6 +134,14 @@ float forceJumpHeight[NUM_FORCE_POWER_LEVELS] = 384//(+stepheight+crouchdiff = 418) }; +float forceJumpHeightMax[NUM_FORCE_POWER_LEVELS] = +{ + 66,//normal jump (32+stepheight(18)+crouchdiff(24) = 74) + 130,//(96+stepheight(18)+crouchdiff(24) = 138) + 226,//(192+stepheight(18)+crouchdiff(24) = 234) + 418//(384+stepheight(18)+crouchdiff(24) = 426) +}; + float forcePushPullRadius[NUM_FORCE_POWER_LEVELS] = { 0,//none @@ -138,8 +154,8 @@ float forcePushCone[NUM_FORCE_POWER_LEVELS] = { 1.0f,//none 1.0f, - 0.6f, - 0.3f + 0.8f, + 0.6f }; float forcePullCone[NUM_FORCE_POWER_LEVELS] = @@ -147,7 +163,7 @@ float forcePullCone[NUM_FORCE_POWER_LEVELS] = 1.0f,//none 1.0f, 1.0f, - 0.5f + 0.8f }; float forceSpeedValue[NUM_FORCE_POWER_LEVELS] = @@ -325,6 +341,47 @@ void G_Throw( gentity_t *targ, vec3_t newDir, float push ) } } +int WP_SetSaberModel( gclient_t *client, class_t npcClass ) +{ + if ( client ) + { + switch ( npcClass ) + { + case CLASS_DESANN://Desann + client->ps.saberModel = "models/weapons2/saber_desann/saber_w.glm"; + break; + case CLASS_LUKE://Luke + client->ps.saberModel = "models/weapons2/saber_luke/saber_w.glm"; + break; + case CLASS_KYLE://Kyle NPC and player + client->ps.saberModel = "models/weapons2/saber/saber_w.glm"; + break; + default://reborn and tavion and everyone else + client->ps.saberModel = "models/weapons2/saber_reborn/saber_w.glm"; + break; + } + return ( G_ModelIndex( client->ps.saberModel ) ); + } + else + { + switch ( npcClass ) + { + case CLASS_DESANN://Desann + return ( G_ModelIndex( "models/weapons2/saber_desann/saber_w.glm" ) ); + break; + case CLASS_LUKE://Luke + return ( G_ModelIndex( "models/weapons2/saber_luke/saber_w.glm" ) ); + break; + case CLASS_KYLE://Kyle NPC and player + return ( G_ModelIndex( "models/weapons2/saber/saber_w.glm" ) ); + break; + default://reborn and tavion and everyone else + return ( G_ModelIndex( "models/weapons2/saber_reborn/saber_w.glm" ) ); + break; + } + } +} + void WP_SaberInitBladeData( gentity_t *ent ) { gentity_t *saberent; @@ -382,6 +439,10 @@ void WP_SaberInitBladeData( gentity_t *ent ) ent->client->ps.saberAnimLevel = FORCE_LEVEL_2; } cg.saberAnimLevelPending = ent->client->ps.saberAnimLevel; + if ( ent->client->sess.missionStats.weaponUsed[WP_SABER] <= 0 ) + {//let missionStats know that we actually do have the saber, even if we never use it + ent->client->sess.missionStats.weaponUsed[WP_SABER] = 1; + } } ent->client->ps.saberAttackChainCount = 0; if ( ent->client->NPC_class == CLASS_DESANN ) @@ -422,23 +483,7 @@ void WP_SaberInitBladeData( gentity_t *ent ) Ghoul2 Insert Start */ //FIXME: get saberModel from NPCs.cfg for NPCs? - if ( ent->client->NPC_class == CLASS_DESANN ) - { - ent->client->ps.saberModel = "models/weapons2/saber_desann/saber_w.glm"; - } - else if ( ent->client->NPC_class == CLASS_LUKE ) - { - ent->client->ps.saberModel = "models/weapons2/saber_luke/saber_w.glm"; - } - else if ( ent->client->NPC_class == CLASS_KYLE ) - {//Kyle NPC and player - ent->client->ps.saberModel = "models/weapons2/saber/saber_w.glm"; - } - else - {//reborn and tavion and everyone else - ent->client->ps.saberModel = "models/weapons2/saber_reborn/saber_w.glm"; - } - saberent->s.modelindex = G_ModelIndex( ent->client->ps.saberModel ); + saberent->s.modelindex = WP_SetSaberModel( ent->client, ent->client->NPC_class ); gi.G2API_InitGhoul2Model( saberent->ghoul2, ent->client->ps.saberModel, saberent->s.modelindex ); // set up a bolt on the end so we can get where the sabre muzzle is - we can assume this is always bolt 0 gi.G2API_AddBolt( &saberent->ghoul2[0], "*flash" ); @@ -636,7 +681,7 @@ qboolean WP_GetSaberDeflectionAngle( gentity_t *attacker, gentity_t *defender ) } } } -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { gi.Printf( S_COLOR_BLUE"%s deflected from %s to %s\n", attacker->targetname, saberMoveData[attacker->client->ps.saberMove].name, saberMoveData[attacker->client->ps.saberBounceMove].name ); @@ -649,7 +694,7 @@ qboolean WP_GetSaberDeflectionAngle( gentity_t *attacker, gentity_t *defender ) void WP_SaberClearDamageForEntNum( int entityNum ) { -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { if ( entityNum ) @@ -657,13 +702,18 @@ void WP_SaberClearDamageForEntNum( int entityNum ) Com_Printf( "clearing damage for entnum %d\n", entityNum ); } } -#endif// _FINAL_BUILD +#endif// FINAL_BUILD + if ( g_saberRealisticCombat->integer > 1 ) + { + return; + } for ( int i = 0; i < numVictims; i++ ) { if ( victimEntityNum[i] == entityNum ) { totalDmg[i] = 0;//no damage hitLoc[i] = HL_NONE; + hitDismemberLoc[i] = HL_NONE; hitDismember[i] = qfalse; victimEntityNum[i] = ENTITYNUM_NONE;//like we never hit him } @@ -686,7 +736,7 @@ qboolean WP_SaberApplyDamage( gentity_t *ent, float baseDamage, int baseDFlags, } for ( int i = 0; i < numVictims; i++ ) { - dFlags = baseDFlags|DAMAGE_DEATH_KNOCKBACK; + dFlags = baseDFlags|DAMAGE_DEATH_KNOCKBACK|DAMAGE_NO_HIT_LOC; if ( victimEntityNum[i] != ENTITYNUM_NONE && &g_entities[victimEntityNum[i]] != NULL ) { // Don't bother with this damage if the fraction is higher than the saber's fraction if ( dmgFraction[i] < saberHitFraction || brokenParry ) @@ -697,144 +747,183 @@ qboolean WP_SaberApplyDamage( gentity_t *ent, float baseDamage, int baseDFlags, continue; } - if ( victim->s.weapon == WP_SABER && victim->client && !g_realisticSaberDamage->integer ) - {//dmg vs other saber fighters is modded by hitloc and capped - totalDmg[i] *= damageModifier[hitLoc[i]]; - if ( hitLoc[i] == HL_NONE ) + if ( victim->e_DieFunc == dieF_maglock_die ) + {//*sigh*, special check for maglocks + vec3_t testFrom; + if ( ent->client->ps.saberInFlight ) { - maxDmg = 33*baseDamage; + VectorCopy( g_entities[ent->client->ps.saberEntityNum].currentOrigin, testFrom ); } else { - maxDmg = 50*hitLocHealthPercentage[hitLoc[i]]*baseDamage;//*victim->client->ps.stats[STAT_MAX_HEALTH]*2.0f; + VectorCopy( ent->currentOrigin, testFrom ); } - if ( maxDmg < totalDmg[i] ) - { - totalDmg[i] = maxDmg; - } - dFlags |= DAMAGE_NO_HIT_LOC; - } - //clamp the dmg between 5 and 100 - if ( totalDmg[i] > 100 ) - { - totalDmg[i] = 100; - } - else if ( victim->s.weapon != WP_SABER ) - { - if ( totalDmg[i] < 25 ) - { - totalDmg[i] = 25; + testFrom[2] = victim->currentOrigin[2]; + trace_t testTrace; + gi.trace( &testTrace, testFrom, vec3_origin, vec3_origin, victim->currentOrigin, ent->s.number, MASK_SHOT ); + if ( testTrace.entityNum != victim->s.number ) + {//can only damage maglocks if have a clear trace to the thing's origin + continue; } } - else - { - if ( totalDmg[i] < 5 ) - { - totalDmg[i] = 5; - } - } - if ( totalDmg[i] > 0 ) - { - didDamage = qtrue; - if( victim->client ) - { - if ( victim->client->ps.pm_time > 0 && victim->client->ps.pm_flags & PMF_TIME_KNOCKBACK && victim->client->ps.velocity[2] > 0 ) - {//already being knocked around - dFlags |= DAMAGE_NO_KNOCKBACK; - } - if ( g_dismemberment->integer > 3 || g_realisticSaberDamage->integer ) + {//actually want to do *some* damage here + if ( victim->s.weapon == WP_SABER && victim->client && !g_saberRealisticCombat->integer ) + {//dmg vs other saber fighters is modded by hitloc and capped + totalDmg[i] *= damageModifier[hitLoc[i]]; + if ( hitLoc[i] == HL_NONE ) { - dFlags |= DAMAGE_DISMEMBER; - if ( hitDismember[i] ) - { - victim->client->dismembered = qfalse; - } - } - else if ( hitDismember[i] ) - { - dFlags |= DAMAGE_DISMEMBER; - } - if ( baseDamage <= 1.0f ) - {//very mild damage - if ( victim->s.number == 0 || victim->client->ps.weapon == WP_SABER || victim->client->NPC_class == CLASS_GALAKMECH ) - {//if it's the player or a saber-user, don't kill them with this blow - dFlags |= DAMAGE_NO_KILL; - } - } - } - else - { - if ( victim->takedamage ) - {//some other breakable thing - //create a flash here - g_saberFlashTime = level.time-50; - VectorCopy( dmgSpot[i], g_saberFlashPos ); - } - } - //victim->hitLoc = hitLoc[i]; - - dFlags |= DAMAGE_NO_KNOCKBACK;//okay, let's try no knockback whatsoever... - dFlags &= ~DAMAGE_DEATH_KNOCKBACK; - if ( g_realisticSaberDamage->integer ) - { - dFlags |= DAMAGE_NO_KNOCKBACK; - dFlags &= ~DAMAGE_DEATH_KNOCKBACK; - dFlags &= ~DAMAGE_NO_KILL; - } - if ( ent->client && !ent->s.number ) - { - switch( hitLoc[i] ) - { - case HL_FOOT_RT: - case HL_FOOT_LT: - case HL_LEG_RT: - case HL_LEG_LT: - ent->client->sess.missionStats.legAttacksCnt++; - break; - case HL_WAIST: - case HL_BACK_RT: - case HL_BACK_LT: - case HL_BACK: - case HL_CHEST_RT: - case HL_CHEST_LT: - case HL_CHEST: - ent->client->sess.missionStats.torsoAttacksCnt++; - break; - case HL_ARM_RT: - case HL_ARM_LT: - case HL_HAND_RT: - case HL_HAND_LT: - ent->client->sess.missionStats.armAttacksCnt++; - break; - default: - ent->client->sess.missionStats.otherAttacksCnt++; - break; - } - } - G_Damage( victim, ent, ent, dmgDir[i], dmgSpot[i], ceil(totalDmg[i]), dFlags, MOD_SABER, hitLoc[i] ); -#ifndef _FINAL_BUILD - if ( d_saberCombat->integer ) - { - gi.Printf( S_COLOR_RED"damage: %4.2f, hitLoc %d\n", totalDmg[i], hitLoc[i] ); - } -#endif - //do the effect - //G_PlayEffect( G_EffectIndex( "blood_sparks" ), dmgSpot[i], dmgDir[i] ); - if ( ent->s.number == 0 ) - { - AddSoundEvent( victim->owner, dmgSpot[i], 256, AEL_DISCOVERED ); - AddSightEvent( victim->owner, dmgSpot[i], 512, AEL_DISCOVERED, 50 ); - } - if ( ent->client ) - { - if ( ent->enemy && ent->enemy == victim ) - {//just so Jedi knows that he hit his enemy - ent->client->ps.saberEventFlags |= SEF_HITENEMY; + maxDmg = 33*baseDamage; } else { - ent->client->ps.saberEventFlags |= SEF_HITOBJECT; + maxDmg = 50*hitLocHealthPercentage[hitLoc[i]]*baseDamage;//*victim->client->ps.stats[STAT_MAX_HEALTH]*2.0f; + } + if ( maxDmg < totalDmg[i] ) + { + totalDmg[i] = maxDmg; + } + //dFlags |= DAMAGE_NO_HIT_LOC; + } + //clamp the dmg + if ( victim->s.weapon != WP_SABER ) + {//clamp the dmg between 25 and maxhealth + /* + if ( totalDmg[i] > victim->max_health ) + { + totalDmg[i] = victim->max_health; + } + else */if ( totalDmg[i] < 25 ) + { + totalDmg[i] = 25; + } + if ( totalDmg[i] > 100 )//+(50*g_spskill->integer) ) + {//clamp using same adjustment as in NPC_Begin + totalDmg[i] = 100;//+(50*g_spskill->integer); + } + } + else + {//clamp the dmg between 5 and 100 + if ( !victim->s.number && totalDmg[i] > 50 ) + {//never do more than half full health damage to player + //prevents one-hit kills + totalDmg[i] = 50; + } + else if ( totalDmg[i] > 100 ) + { + totalDmg[i] = 100; + } + else + { + if ( totalDmg[i] < 5 ) + { + totalDmg[i] = 5; + } + } + } + + if ( totalDmg[i] > 0 ) + { + didDamage = qtrue; + if( victim->client ) + { + if ( victim->client->ps.pm_time > 0 && victim->client->ps.pm_flags & PMF_TIME_KNOCKBACK && victim->client->ps.velocity[2] > 0 ) + {//already being knocked around + dFlags |= DAMAGE_NO_KNOCKBACK; + } + if ( g_dismemberment->integer >= 11381138 || g_saberRealisticCombat->integer ) + { + dFlags |= DAMAGE_DISMEMBER; + if ( hitDismember[i] ) + { + victim->client->dismembered = qfalse; + } + } + else if ( hitDismember[i] ) + { + dFlags |= DAMAGE_DISMEMBER; + } + if ( baseDamage <= 1.0f ) + {//very mild damage + if ( victim->s.number == 0 || victim->client->ps.weapon == WP_SABER || victim->client->NPC_class == CLASS_GALAKMECH ) + {//if it's the player or a saber-user, don't kill them with this blow + dFlags |= DAMAGE_NO_KILL; + } + } + } + else + { + if ( victim->takedamage ) + {//some other breakable thing + //create a flash here + g_saberFlashTime = level.time-50; + VectorCopy( dmgSpot[i], g_saberFlashPos ); + } + } + //victim->hitLoc = hitLoc[i]; + + dFlags |= DAMAGE_NO_KNOCKBACK;//okay, let's try no knockback whatsoever... + dFlags &= ~DAMAGE_DEATH_KNOCKBACK; + if ( g_saberRealisticCombat->integer ) + { + dFlags |= DAMAGE_NO_KNOCKBACK; + dFlags &= ~DAMAGE_DEATH_KNOCKBACK; + dFlags &= ~DAMAGE_NO_KILL; + } + if ( ent->client && !ent->s.number ) + { + switch( hitLoc[i] ) + { + case HL_FOOT_RT: + case HL_FOOT_LT: + case HL_LEG_RT: + case HL_LEG_LT: + ent->client->sess.missionStats.legAttacksCnt++; + break; + case HL_WAIST: + case HL_BACK_RT: + case HL_BACK_LT: + case HL_BACK: + case HL_CHEST_RT: + case HL_CHEST_LT: + case HL_CHEST: + ent->client->sess.missionStats.torsoAttacksCnt++; + break; + case HL_ARM_RT: + case HL_ARM_LT: + case HL_HAND_RT: + case HL_HAND_LT: + ent->client->sess.missionStats.armAttacksCnt++; + break; + default: + ent->client->sess.missionStats.otherAttacksCnt++; + break; + } + } + G_Damage( victim, ent, ent, dmgDir[i], dmgSpot[i], ceil(totalDmg[i]), dFlags, MOD_SABER, hitDismemberLoc[i] ); +#ifndef FINAL_BUILD + if ( d_saberCombat->integer ) + { + gi.Printf( S_COLOR_RED"damage: %4.2f, hitLoc %d\n", totalDmg[i], hitLoc[i] ); + } +#endif + //do the effect + //G_PlayEffect( G_EffectIndex( "blood_sparks" ), dmgSpot[i], dmgDir[i] ); + if ( ent->s.number == 0 ) + { + AddSoundEvent( victim->owner, dmgSpot[i], 256, AEL_DISCOVERED ); + AddSightEvent( victim->owner, dmgSpot[i], 512, AEL_DISCOVERED, 50 ); + } + if ( ent->client ) + { + if ( ent->enemy && ent->enemy == victim ) + {//just so Jedi knows that he hit his enemy + ent->client->ps.saberEventFlags |= SEF_HITENEMY; + } + else + { + ent->client->ps.saberEventFlags |= SEF_HITOBJECT; + } } } } @@ -844,7 +933,7 @@ qboolean WP_SaberApplyDamage( gentity_t *ent, float baseDamage, int baseDFlags, return didDamage; } -void WP_SaberDamageAdd( float trDmg, int trVictimEntityNum, vec3_t trDmgDir, vec3_t trDmgSpot, float dmg, float fraction, int trHitLoc, qboolean trDismember ) +void WP_SaberDamageAdd( float trDmg, int trVictimEntityNum, vec3_t trDmgDir, vec3_t trDmgSpot, float dmg, float fraction, int trHitLoc, qboolean trDismember, int trDismemberLoc ) { int curVictim = 0; @@ -897,8 +986,13 @@ void WP_SaberDamageAdd( float trDmg, int trVictimEntityNum, vec3_t trDmgDir, vec // Make sure we keep track of the fraction. Why? // Well, if the saber hits something that stops it, the damage isn't done past that point. dmgFraction[curVictim] = fraction; - if ( trDismember && !hitDismember[curVictim] ) - { + if ( (trDismemberLoc != HL_NONE && hitDismemberLoc[curVictim] == HL_NONE) + || (!hitDismember[curVictim] && trDismember) ) + {//either this is the first dismember loc we got or we got a loc before, but it wasn't a dismember loc, so take the new one + hitDismemberLoc[curVictim] = trDismemberLoc; + } + if ( trDismember ) + {//we scored a dismemberment hit... hitDismember[curVictim] = trDismember; } } @@ -917,9 +1011,10 @@ qboolean WP_SabersIntersect( gentity_t *ent1, gentity_t *ent2, qboolean checkDir { vec3_t saberBase1, saberTip1, saberBaseNext1, saberTipNext1; vec3_t saberBase2, saberTip2, saberBaseNext2, saberTipNext2; + vec3_t dir; /* -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { gi.Printf( S_COLOR_GREEN"Doing precise saber intersection check\n" ); @@ -944,8 +1039,17 @@ qboolean WP_SabersIntersect( gentity_t *ent1, gentity_t *ent2, qboolean checkDir { VectorCopy( ent1->client->renderInfo.muzzlePointOld, saberBase1 ); VectorCopy( ent1->client->renderInfo.muzzlePoint, saberBaseNext1 ); + + VectorSubtract( ent1->client->renderInfo.muzzlePoint, ent1->client->renderInfo.muzzlePointOld, dir ); + VectorNormalize( dir ); + VectorMA( saberBaseNext1, SABER_EXTRAPOLATE_DIST, dir, saberBaseNext1 ); + VectorMA( saberBase1, ent1->client->ps.saberLength, ent1->client->renderInfo.muzzleDirOld, saberTip1 ); VectorMA( saberBaseNext1, ent1->client->ps.saberLength, ent1->client->renderInfo.muzzleDir, saberTipNext1 ); + + VectorSubtract( saberTipNext1, saberTip1, dir ); + VectorNormalize( dir ); + VectorMA( saberTipNext1, SABER_EXTRAPOLATE_DIST, dir, saberTipNext1 ); } /* else @@ -961,8 +1065,17 @@ qboolean WP_SabersIntersect( gentity_t *ent1, gentity_t *ent2, qboolean checkDir { VectorCopy( ent2->client->renderInfo.muzzlePointOld, saberBase2 ); VectorCopy( ent2->client->renderInfo.muzzlePoint, saberBaseNext2 ); + + VectorSubtract( ent2->client->renderInfo.muzzlePoint, ent2->client->renderInfo.muzzlePointOld, dir ); + VectorNormalize( dir ); + VectorMA( saberBaseNext2, SABER_EXTRAPOLATE_DIST, dir, saberBaseNext2 ); + VectorMA( saberBase2, ent2->client->ps.saberLength, ent2->client->renderInfo.muzzleDirOld, saberTip2 ); VectorMA( saberBaseNext2, ent2->client->ps.saberLength, ent2->client->renderInfo.muzzleDir, saberTipNext2 ); + + VectorSubtract( saberTipNext2, saberTip2, dir ); + VectorNormalize( dir ); + VectorMA( saberTipNext2, SABER_EXTRAPOLATE_DIST, dir, saberTipNext2 ); } /* else @@ -1019,7 +1132,7 @@ float WP_SabersDistance( gentity_t *ent1, gentity_t *ent2 ) vec3_t saberBaseNext2, saberTipNext2, saberPoint2; /* -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { gi.Printf( S_COLOR_GREEN"Doing precise saber intersection check\n" ); @@ -1088,7 +1201,7 @@ float WP_SabersDistance( gentity_t *ent1, gentity_t *ent2 ) } */ -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer > 2 ) { G_DebugLine( saberPoint1, saberPoint2, FRAMETIME, 0x00ffffff, qtrue ); @@ -1130,7 +1243,7 @@ qboolean WP_SabersIntersection( gentity_t *ent1, gentity_t *ent2, vec3_t interse char *hit_blood_sparks = "blood_sparks"; char *hit_sparks = "saber_cut"; -extern qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir ); +extern qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hitLoc, vec3_t point, vec3_t dir, vec3_t bladeDir, int mod ); qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, float dmg, vec3_t dmgDir, vec3_t bladeDir, int enemyTeam ) { @@ -1141,6 +1254,7 @@ qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, f vec3_t hitEntDir[MAX_G2_COLLISIONS]; float hitEntStartFrac[MAX_G2_COLLISIONS] = {0}; int trHitLoc = HL_NONE; + int trDismemberLoc = HL_NONE; qboolean trDismember = qfalse; int i,z; int numHitEnts = 0; @@ -1163,7 +1277,7 @@ qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, f //FIXME: (distFromStart/length) is not guaranteed to be from 0 to 1... *sigh*... if ( length && saberHitFraction < 1.0f && (distFromStart/length) < 1.0f && (distFromStart/length) > saberHitFraction ) {//a saber was hit before this point, don't count it -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { gi.Printf( S_COLOR_MAGENTA"rejecting G2 collision- %4.2f farther than saberHitFraction %4.2f\n", (distFromStart/length), saberHitFraction ); @@ -1235,10 +1349,13 @@ qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, f G_PlayEffect( hitEffect, coll.mCollisionPosition, coll.mCollisionNormal ); //Get the hit location based on surface name - if ( hitLoc[hitEntNum[numHitEnts]] == HL_NONE || !hitDismember[hitEntNum[numHitEnts]] ) + if ( (hitLoc[hitEntNum[numHitEnts]] == HL_NONE && trHitLoc == HL_NONE) + || (hitDismemberLoc[hitEntNum[numHitEnts]] == HL_NONE && trDismemberLoc == HL_NONE) + || (!hitDismember[hitEntNum[numHitEnts]] && !trDismember) ) {//no hit loc set for this ent this damage cycle yet //FIXME: find closest impact surf *first* (per ent), then call G_GetHitLocFromSurfName? - trDismember = G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &trHitLoc, coll.mCollisionPosition, dmgDir, bladeDir ); + trDismember = G_GetHitLocFromSurfName( &g_entities[coll.mEntityNum], gi.G2API_GetSurfaceName( &g_entities[coll.mEntityNum].ghoul2[coll.mModelIndex], coll.mSurfaceIndex ), &trHitLoc, coll.mCollisionPosition, dmgDir, bladeDir, MOD_SABER ); + trDismemberLoc = trHitLoc; } numHitEnts++; } @@ -1281,7 +1398,7 @@ qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, f } if ( doDmg > 0 ) { - WP_SaberDamageAdd( 1.0, hitEntNum[i], hitEntDir[i], hitEntPoint[i], ceil(doDmg), hitEntStartFrac[i], trHitLoc, trDismember ); + WP_SaberDamageAdd( 1.0, hitEntNum[i], hitEntDir[i], hitEntPoint[i], ceil(doDmg), hitEntStartFrac[i], trHitLoc, trDismember, trDismemberLoc ); } } } @@ -1294,7 +1411,7 @@ void WP_SaberKnockaway( gentity_t *attacker, trace_t *tr ) G_Sound( &g_entities[attacker->client->ps.saberEntityNum], G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); G_PlayEffect( "saber_block", tr->endpos ); saberHitFraction = tr->fraction; -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { gi.Printf( S_COLOR_MAGENTA"WP_SaberKnockaway: saberHitFraction %4.2f\n", saberHitFraction ); @@ -1330,7 +1447,7 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg vec3_t diff; VectorSubtract( end, start, diff ); VectorNormalize( diff ); - VectorMA( end2, 16, diff, end2 ); + VectorMA( end2, SABER_EXTRAPOLATE_DIST, diff, end2 ); } if ( !noGhoul ) @@ -1358,7 +1475,7 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg } -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer > 1 ) { if ( attacker != NULL && attacker->client != NULL ) @@ -1386,7 +1503,15 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg { if ( attacker && attacker->client && attacker->client->ps.saberInFlight ) {//thrown saber hit something - if ( owner && owner->client && owner->health > 0 && owner->client->NPC_class == CLASS_TAVION ) + if ( owner + && owner->s.number + && owner->client + && owner->NPC + && owner->health > 0 + && ( owner->client->NPC_class == CLASS_TAVION + /*|| (owner->client->NPC_class == CLASS_SHADOWTROOPER && !Q_irand( 0, g_spskill->integer*3 )) + || (Q_irand( -5, owner->NPC->rank ) > RANK_CIVILIAN && !Q_irand( 0, g_spskill->integer*3 ))*/ ) + ) {//Tavion can toss a blocked thrown saber aside WP_SaberKnockaway( attacker, &tr ); Jedi_PlayDeflectSound( owner ); @@ -1394,10 +1519,11 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg } } //FIXME: take target FP_SABER_DEFENSE and attacker FP_SABER_OFFENSE into account here somehow? + qboolean sabersIntersect = WP_SabersIntersect( attacker, owner, qfalse );//qtrue ); float sabersDist; if ( attacker && attacker->client && attacker->client->ps.saberInFlight - && owner && owner->s.number == 0 && (g_autoBlocking->integer||attacker->client->ps.saberBlockingTime>level.time) )//NPC flying saber hit player's saber bounding box - {//players have g_autoBlocking, do the more generous check against flying sabers + && owner && owner->s.number == 0 && (g_saberAutoBlocking->integer||attacker->client->ps.saberBlockingTime>level.time) )//NPC flying saber hit player's saber bounding box + {//players have g_saberAutoBlocking, do the more generous check against flying sabers //FIXME: instead of hitting the player's saber bounding box //and picking an anim afterwards, have him use AI similar //to the AI the jedi use for picking a saber melee block...? @@ -1406,20 +1532,36 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg else {//sabers must actually collide with the attacking saber sabersDist = WP_SabersDistance( attacker, owner ); -#ifndef _FINAL_BUILD + if ( attacker && attacker->client && attacker->client->ps.saberInFlight ) + { + sabersDist /= 2.0f; + if ( sabersDist <= 16.0f ) + { + sabersIntersect = qtrue; + } + } +#ifndef FINAL_BUILD if ( d_saberCombat->integer > 1 ) { gi.Printf( "sabersDist: %4.2f\n", sabersDist ); } -#endif//_FINAL_BUILD +#endif//FINAL_BUILD } if ( sabersCrossed == -1 || sabersCrossed > sabersDist ) { sabersCrossed = sabersDist; } - qboolean sabersIntersect = WP_SabersIntersect( attacker, owner, qtrue ); - if ( owner && owner->client && (attacker != NULL) && - (sabersDist > SABER_COLLISION_DIST+4 )//|| !InFront( attacker->currentOrigin, owner->currentOrigin, owner->client->ps.viewangles, 0.35f )) + float collisionDist; + if ( g_saberRealisticCombat->integer ) + { + collisionDist = SABER_COLLISION_DIST; + } + else + { + collisionDist = SABER_COLLISION_DIST+6+g_spskill->integer*4; + } + if ( owner && owner->client && (attacker != NULL) + && (sabersDist > collisionDist )//|| !InFront( attacker->currentOrigin, owner->currentOrigin, owner->client->ps.viewangles, 0.35f )) && !sabersIntersect )//was qtrue, but missed too much? {//swing came from behind and/or was not stopped by a lightsaber //re-try the trace without checking for lightsabers @@ -1449,7 +1591,7 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg vec3_t attDir; VectorSubtract( end2, start, attDir ); VectorNormalize( attDir ); - Jedi_SaberBlockGo( owner, start, attDir, NULL ); + Jedi_SaberBlockGo( owner, owner->NPC->last_ucmd, start, attDir, NULL ); } } } @@ -1457,7 +1599,7 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg */ return qfalse; // Exit, but we didn't hit the wall. } -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer > 1 ) { if ( !attacker->s.number ) @@ -1465,15 +1607,15 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg gi.Printf( S_COLOR_MAGENTA"%d saber hit owner through saber %4.2f, dist = %4.2f\n", level.time, saberHitFraction, sabersDist ); } } -#endif//_FINAL_BUILD +#endif//FINAL_BUILD hitEnt = &g_entities[tr.entityNum]; owner = g_entities[tr.entityNum].owner; } else {//hit a lightsaber - if ( tr.fraction < saberHitFraction - && sabersDist < 16.0f - && sabersIntersect ) + if ( (tr.fraction < saberHitFraction || tr.startsolid) + && sabersDist < (8.0f+g_spskill->value)*4.0f// 50.0f//16.0f + && (sabersIntersect || sabersDist < (4.0f+g_spskill->value)*2.0f) )//32.0f) ) { // This saber hit closer than the last one. if ( (tr.allsolid || tr.startsolid) && owner && owner->client ) {//tr.fraction will be 0, unreliable... so calculate actual @@ -1494,7 +1636,7 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg { saberHitFraction = 0.0f; } -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer > 1 ) { if ( !attacker->s.number ) @@ -1502,11 +1644,11 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg gi.Printf( S_COLOR_GREEN"%d saber hit saber dist %4.2f allsolid %4.2f\n", level.time, sabersDist, saberHitFraction ); } } -#endif//_FINAL_BUILD +#endif//FINAL_BUILD } else { -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer > 1 ) { if ( !attacker->s.number ) @@ -1515,14 +1657,14 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg } saberHitFraction = tr.fraction; } -#endif//_FINAL_BUILD +#endif//FINAL_BUILD } -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { gi.Printf( S_COLOR_MAGENTA"hit saber: saberHitFraction %4.2f, allsolid %d, startsolid %d\n", saberHitFraction, tr.allsolid, tr.startsolid ); } -#endif//_FINAL_BUILD +#endif//FINAL_BUILD VectorCopy(tr.endpos, saberHitLocation); saberHitEntity = tr.entityNum; } @@ -1547,7 +1689,7 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg vec3_t attDir; VectorSubtract( end2, start, attDir ); VectorNormalize( attDir ); - Jedi_SaberBlockGo( owner, start, attDir, NULL ); + Jedi_SaberBlockGo( owner, owner->NPC->last_ucmd, start, attDir, NULL ); } } } @@ -1558,7 +1700,7 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg } else { -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer > 1 ) { if ( !attacker->s.number ) @@ -1566,7 +1708,7 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg gi.Printf( S_COLOR_RED"%d saber hit owner directly %4.2f\n", level.time, saberHitFraction ); } } -#endif//_FINAL_BUILD +#endif//FINAL_BUILD } if ( attacker && attacker->client && attacker->client->ps.saberInFlight ) @@ -1598,11 +1740,15 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg if ( noGhoul || !hitEnt->ghoul2.size() ) {//we weren't doing a ghoul trace char *hitEffect; + if ( dmg >= 1.0 && hitEnt->bmodel ) + { + dmg = 1.0; + } if ( len > 1 ) { dmg *= len; } -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer > 1 ) { if ( !(hitEnt->contents & CONTENTS_LIGHTSABER) ) @@ -1629,7 +1775,7 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg trFrac = (1.0f - tr.fraction); dmgFrac = tr.fraction; } - WP_SaberDamageAdd( trFrac, tr.entityNum, dir, tr.endpos, dmg, dmgFrac, HL_NONE, qfalse ); + WP_SaberDamageAdd( trFrac, tr.entityNum, dir, tr.endpos, dmg, dmgFrac, HL_NONE, qfalse, HL_NONE ); if ( !tr.allsolid && !tr.startsolid ) { VectorScale( dir, -1, dir ); @@ -1759,7 +1905,7 @@ qboolean WP_SabersCheckLock2( gentity_t *attacker, gentity_t *defender, sabersLo anim = &level.knownAnimFileSets[attacker->client->clientInfo.animFileIndex].animations[attAnim]; advance = floor( anim->numFrames*attStart ); PM_SetAnimFrame( attacker, anim->firstFrame + advance, qtrue, qtrue ); -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { Com_Printf( "%s starting saber lock, anim = %s, %d frames to go!\n", attacker->NPC_type, animTable[attAnim].name, anim->numFrames-advance ); @@ -1770,7 +1916,7 @@ qboolean WP_SabersCheckLock2( gentity_t *attacker, gentity_t *defender, sabersLo { anim = &level.knownAnimFileSets[defender->client->clientInfo.animFileIndex].animations[defAnim]; PM_SetAnimFrame( defender, anim->firstFrame + advance, qtrue, qtrue );//was anim->firstFrame + anim->numFrames - advance, but that's wrong since they are matched anims -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { Com_Printf( "%s starting saber lock, anim = %s, %d frames to go!\n", defender->NPC_type, animTable[defAnim].name, advance ); @@ -2288,7 +2434,7 @@ qboolean WP_SaberParry( gentity_t *victim, gentity_t *attacker ) { return qfalse; } - if ( victim->s.number || g_autoBlocking->integer || victim->client->ps.saberBlockingTime > level.time ) + if ( victim->s.number || g_saberAutoBlocking->integer || victim->client->ps.saberBlockingTime > level.time ) {//either an NPC or a player who is blocking if ( !PM_SaberInTransitionAny( victim->client->ps.saberMove ) && !PM_SaberInBounce( victim->client->ps.saberMove ) @@ -2362,10 +2508,14 @@ void WP_SaberDamageTrace( gentity_t *ent ) memset( dmgSpot, 0, sizeof( dmgSpot ) ); memset( dmgFraction, 0, sizeof( dmgFraction ) ); memset( hitLoc, HL_NONE, sizeof( hitLoc ) ); + memset( hitDismemberLoc, HL_NONE, sizeof( hitDismemberLoc ) ); memset( hitDismember, qfalse, sizeof( hitDismember ) ); numVictims = 0; VectorClear(saberHitLocation); + VectorClear(saberHitNormal); saberHitFraction = 1.0; // Closest saber hit. The saber can do no damage past this point. + saberHitEntity = ENTITYNUM_NONE; + sabersCrossed = -1; if ( !ent->client ) { @@ -2427,7 +2577,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) if ( ent->client->ps.saberInFlight ) {//flying sabers are much more deadly //unless you're dead - if ( ent->health <= 0 && !g_realisticSaberDamage->integer ) + if ( ent->health <= 0 && !g_saberRealisticCombat->integer ) {//so enemies don't keep trying to block it //FIXME: still do damage, just not to humanoid clients who should try to avoid it //baseDamage = 0.0f; @@ -2460,7 +2610,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) { if ( ent->client->ps.saberMove == LS_READY ) {//just do effects - if ( !g_realisticSaberDamage->integer ) + if ( g_saberRealisticCombat->integer < 2 ) {//don't kill with this hit baseDFlags = DAMAGE_NO_KILL; } @@ -2470,14 +2620,20 @@ void WP_SaberDamageTrace( gentity_t *ent ) {//just do effects baseDamage = 0; } - else if ( ent->client->ps.saberBlocked > BLOCKED_NONE || (!PM_SaberInAttack( ent->client->ps.saberMove ) && !PM_SaberInSpecialAttack( ent->client->ps.torsoAnim ) && !PM_SaberInTransitionAny( ent->client->ps.saberMove ) ) ) + else if ( ent->client->ps.saberBlocked > BLOCKED_NONE + || ( !PM_SaberInAttack( ent->client->ps.saberMove ) + && !PM_SaberInSpecialAttack( ent->client->ps.torsoAnim ) + && !PM_SaberInTransitionAny( ent->client->ps.saberMove ) + ) + ) {//don't do damage if parrying/reflecting/bouncing/deflecting or not actually attacking or in a transition to/from/between attacks baseDamage = 0; } else {//okay, in a saberMove that does damage //make sure we're in the right anim - if ( !PM_SaberInSpecialAttack( ent->client->ps.torsoAnim ) && !PM_InAnimForSaberMove( ent->client->ps.torsoAnim, ent->client->ps.saberMove ) ) + if ( !PM_SaberInSpecialAttack( ent->client->ps.torsoAnim ) + && !PM_InAnimForSaberMove( ent->client->ps.torsoAnim, ent->client->ps.saberMove ) ) {//forced into some other animation somehow, like a pain or death? baseDamage = 0; } @@ -2487,44 +2643,52 @@ void WP_SaberDamageTrace( gentity_t *ent ) //FIXME: more damage for higher attack power levels? // More damage based on length/color of saber? //FIXME: Desann does double damage? - /* - switch ( entPowerLevel ) + if ( g_saberRealisticCombat->integer ) { - case FORCE_LEVEL_3: - baseDamage = 5.0f; - break; - case FORCE_LEVEL_2: - baseDamage = 2.0f; - break; - default: - case FORCE_LEVEL_1: - baseDamage = 1.0f; - break; + switch ( entPowerLevel ) + { + case FORCE_LEVEL_3: + baseDamage = 10.0f; + break; + case FORCE_LEVEL_2: + baseDamage = 5.0f; + break; + default: + case FORCE_LEVEL_1: + baseDamage = 2.5f; + break; + } + } + else + { + baseDamage = 2.5f * (float)entPowerLevel; } - */ - baseDamage = 2.5f * (float)entPowerLevel; } else {//saber is transitioning, defending or idle, don't do as much damage //FIXME: strong attacks and returns should do damage and be unblockable if ( g_timescale->value < 1.0 ) {//in slow mo or force speed, we need to do damage during the transitions - /* - switch ( entPowerLevel ) + if ( g_saberRealisticCombat->integer ) { - case FORCE_LEVEL_3: - baseDamage = 5.0f; - break; - case FORCE_LEVEL_2: - baseDamage = 2.0f; - break; - default: - case FORCE_LEVEL_1: - baseDamage = 1.0f; - break; + switch ( entPowerLevel ) + { + case FORCE_LEVEL_3: + baseDamage = 10.0f; + break; + case FORCE_LEVEL_2: + baseDamage = 5.0f; + break; + default: + case FORCE_LEVEL_1: + baseDamage = 2.5f; + break; + } + } + else + { + baseDamage = 2.5f * (float)entPowerLevel; } - */ - baseDamage = 2.5f * (float)entPowerLevel; } else// if ( !ent->s.number ) {//I have to do *some* damage in transitions or else you feel like a total gimp @@ -2563,7 +2727,11 @@ void WP_SaberDamageTrace( gentity_t *ent ) if ( trace.entityNum < ENTITYNUM_WORLD && (trace.entityNum > 0||ent->client->NPC_class == CLASS_DESANN) )//NPCs don't push player away, unless it's Desann {//a valid ent gentity_t *traceEnt = &g_entities[trace.entityNum]; - if ( traceEnt && traceEnt->client && traceEnt->health > 0 && traceEnt->client->playerTeam != ent->client->playerTeam ) + if ( traceEnt + && traceEnt->client + && traceEnt->health > 0 + && traceEnt->client->playerTeam != ent->client->playerTeam + && !PM_InKnockDown( &traceEnt->client->ps ) ) {//enemy client, push them away if ( !traceEnt->client->ps.saberLockTime && !traceEnt->message ) {//don't push people in saberlock or with security keys @@ -2577,7 +2745,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) VectorMA( traceEnt->client->ps.velocity, knockback, hitDir, traceEnt->client->ps.velocity ); traceEnt->client->ps.pm_time = 200; traceEnt->client->ps.pm_flags |= PMF_TIME_NOFRICTION; -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { gi.Printf( "%s pushing away %s at %s\n", ent->NPC_type, traceEnt->NPC_type, vtos( traceEnt->client->ps.velocity ) ); @@ -2589,9 +2757,16 @@ void WP_SaberDamageTrace( gentity_t *ent ) } } - if ( g_realisticSaberDamage->integer ) + if ( g_saberRealisticCombat->integer > 1 ) {//always do damage, and lots of it - baseDamage = 25.0f; + if ( g_saberRealisticCombat->integer > 2 ) + {//always do damage, and lots of it + baseDamage = 25.0f; + } + else if ( baseDamage > 0.1f ) + {//only do super damage if we would have done damage according to normal rules + baseDamage = 25.0f; + } } else if ( (!ent->s.number&&ent->client->ps.forcePowersActive&(1<s.number, baseOld, baseNew, baseDamage, md2, qfalse, entPowerLevel ); //if hit a saber, shorten rest of traces to match if ( saberHitFraction < 1.0 ) - {//FIXME: doesn't adjust muzzleDir... + { + //adjust muzzleDir... + vec3_t ma1, ma2; + vectoangles( md1, ma1 ); + vectoangles( md2, ma2 ); + for ( xx = 0; xx < 3; xx++ ) + { + md2ang[xx] = LerpAngle( ma1[xx], ma2[xx], saberHitFraction ); + } + AngleVectors( md2ang, md2, NULL, NULL ); + //shorten the base pos VectorSubtract( mp2, mp1, baseDiff ); VectorMA( mp1, saberHitFraction, baseDiff, baseNew ); VectorMA( baseNew, ent->client->ps.saberLength, md2, endNew ); @@ -2625,7 +2812,11 @@ void WP_SaberDamageTrace( gentity_t *ent ) //If the angle diff in the blade is high, need to do it in chunks of 33 to avoid flattening of the arc float dirInc, curDirFrac; - if ( PM_SaberInAttack( ent->client->ps.saberMove ) || PM_SaberInSpecialAttack( ent->client->ps.torsoAnim ) || PM_SpinningSaberAnim( ent->client->ps.torsoAnim ) || PM_InSpecialJump( ent->client->ps.torsoAnim ) ) + if ( PM_SaberInAttack( ent->client->ps.saberMove ) + || PM_SaberInSpecialAttack( ent->client->ps.torsoAnim ) + || PM_SpinningSaberAnim( ent->client->ps.torsoAnim ) + || PM_InSpecialJump( ent->client->ps.torsoAnim ) + || (g_timescale->value<1.0f&&PM_SaberInTransitionAny( ent->client->ps.saberMove )) ) { curDirFrac = DotProduct( md1, md2 ); } @@ -2644,18 +2835,40 @@ void WP_SaberDamageTrace( gentity_t *ent ) dirInc = 0.0f; } qboolean hit_saber = qfalse; - vec3_t curMD1, curMD2, mdDiff, dirDiff; - VectorSubtract( md2, md1, mdDiff ); + + vectoangles( md1, ma1 ); + vectoangles( md2, ma2 ); + + vec3_t curMD1, curMD2;//, mdDiff, dirDiff; + //VectorSubtract( md2, md1, mdDiff ); VectorCopy( md1, curMD2 ); + VectorCopy( baseOld, curBase2 ); + while ( 1 ) { VectorCopy( curMD2, curMD1 ); - VectorMA( md1, curDirFrac, mdDiff, curMD2 ); + VectorCopy( curBase2, curBase1 ); + if ( curDirFrac >= 1.0f ) + { + VectorCopy( md2, curMD2 ); + VectorCopy( baseNew, curBase2 ); + } + else + { + for ( xx = 0; xx < 3; xx++ ) + { + md2ang[xx] = LerpAngle( ma1[xx], ma2[xx], curDirFrac ); + } + AngleVectors( md2ang, curMD2, NULL, NULL ); + //VectorMA( md1, curDirFrac, mdDiff, curMD2 ); + VectorSubtract( baseNew, baseOld, baseDiff ); + VectorMA( baseOld, curDirFrac, baseDiff, curBase2 ); + } // Move up the blade in intervals of stepsize for ( step = stepsize; step < ent->client->ps.saberLength && step < ent->client->ps.saberLengthOld; step+=12 ) { - VectorMA( baseOld, step, curMD1, bladePointOld ); - VectorMA( baseNew, step, curMD2, bladePointNew ); + VectorMA( curBase1, step, curMD1, bladePointOld ); + VectorMA( curBase2, step, curMD2, bladePointNew ); if ( WP_SaberDamageForTrace( ent->s.number, bladePointOld, bladePointNew, baseDamage, curMD2, qfalse, entPowerLevel ) ) { hit_wall = qtrue; @@ -2669,8 +2882,18 @@ void WP_SaberDamageTrace( gentity_t *ent ) VectorMA( mp1, saberHitFraction, baseDiff, baseNew ); VectorMA( baseNew, ent->client->ps.saberLength, curMD2, endNew ); //adjust muzzleDir... + vec3_t curMA1, curMA2; + vectoangles( curMD1, curMA1 ); + vectoangles( curMD2, curMA2 ); + for ( xx = 0; xx < 3; xx++ ) + { + md2ang[xx] = LerpAngle( curMA1[xx], curMA2[xx], saberHitFraction ); + } + AngleVectors( md2ang, curMD2, NULL, NULL ); + /* VectorSubtract( curMD2, curMD1, dirDiff ); VectorMA( curMD1, saberHitFraction, dirDiff, curMD2 ); + */ hit_saber = qtrue; } if (hit_wall) @@ -2727,6 +2950,15 @@ void WP_SaberDamageTrace( gentity_t *ent ) if ( hitOwner && hitOwner->client ) { hitOwnerPowerLevel = PM_PowerLevelForSaberAnim( &hitOwner->client->ps ); + if ( entPowerLevel == FORCE_LEVEL_3 && PM_SaberInSpecialAttack( ent->client->ps.torsoAnim ) ) + {//a special "unblockable" attack + if ( hitOwner->client->NPC_class == CLASS_DESANN + || hitOwner->client->NPC_class == CLASS_TAVION + || hitOwner->client->NPC_class == CLASS_LUKE ) + {//these masters can even block unblockables (stops cheap kills) + entPowerLevel = FORCE_LEVEL_2; + } + } } //FIXME: check for certain anims, facing, etc, to make them lock into a sabers-locked pose @@ -2810,6 +3042,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) } else if ( hitOwnerAttacking && entDefending + && !Q_irand( 0, 1 ) && (ent->client->ps.saberMove != LS_READY || (hitOwnerPowerLevel-ent->client->ps.forcePowerLevel[FP_SABER_DEFENSE]) < Q_irand( -6, 0 ) ) && ((hitOwnerPowerLevel < FORCE_LEVEL_3 && ent->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_2 )|| (hitOwnerPowerLevel < FORCE_LEVEL_2 && ent->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_1 )|| @@ -2820,7 +3053,10 @@ void WP_SaberDamageTrace( gentity_t *ent ) } else if ( entAttacking && hitOwnerDefending ) {//I'm attacking hit, they're parrying - if ( (hitOwner->client->ps.saberMove != LS_READY || (entPowerLevel-hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]) < Q_irand( -6, 0 ) ) + qboolean activeDefense = (hitOwner->s.number||g_saberAutoBlocking->integer||hitOwner->client->ps.saberBlockingTime > level.time); + if ( !Q_irand( 0, 1 ) + && activeDefense + && (hitOwner->client->ps.saberMove != LS_READY || (entPowerLevel-hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]) < Q_irand( -6, 0 ) ) && ( ( entPowerLevel < FORCE_LEVEL_3 && hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_2 ) || ( entPowerLevel < FORCE_LEVEL_2 && hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_1 ) || ( entPowerLevel < FORCE_LEVEL_3 && hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_0 && !Q_irand( 0, (entPowerLevel-hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]+1)*2 )) ) @@ -2830,7 +3066,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) } else if ( saberHitFraction < 1.0f ) {//an actual collision - if ( entPowerLevel < FORCE_LEVEL_3 ) + if ( entPowerLevel < FORCE_LEVEL_3 && activeDefense ) {//strong attacks cannot be deflected //based on angle of attack & angle of defensive saber, see if I should deflect off in another dir rather than bounce back deflected = WP_GetSaberDeflectionAngle( ent, hitOwner ); @@ -2841,6 +3077,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) if ( entPowerLevel < FORCE_LEVEL_3 //&& ent->client->ps.forcePowerLevel[FP_SABER_OFFENSE] < FORCE_LEVEL_3//if you have high saber offense, you cannot have your attack knocked away, regardless of what style you're using? && hitOwner->client->ps.saberAnimLevel != FORCE_LEVEL_5 + && activeDefense && (hitOwnerPowerLevel > FORCE_LEVEL_2||(hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]>FORCE_LEVEL_2&&Q_irand(0,hitOwner->client->ps.saberAnimLevel))) ) {//knockaways can make fast-attacker go into a broken parry anim if the ent is using fast or med (but not Tavion) //make me parry @@ -2851,7 +3088,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) ent->client->ps.saberBounceMove = PM_BrokenParryForAttack( ent->client->ps.saberMove ); ent->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; if ( ent->client->ps.forcePowerLevel[FP_SABER_DEFENSE] < FORCE_LEVEL_2 - && (ent->s.number||g_realisticSaberDamage->integer) )//&& !Q_irand( 0, 3 ) ) + && (ent->s.number||g_saberRealisticCombat->integer) )//&& !Q_irand( 0, 3 ) ) {//knocked the saber right out of his hand! (never happens to player) //Get a good velocity to send the saber in based on my parry move vec3_t throwDir; @@ -2863,14 +3100,16 @@ void WP_SaberDamageTrace( gentity_t *ent ) } //just so Jedi knows that he was blocked ent->client->ps.saberEventFlags |= SEF_BLOCKED; -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { gi.Printf( S_COLOR_RED"%s knockaway %s's attack, new move = %s, anim = %s\n", hitOwner->NPC_type, ent->NPC_type, saberMoveData[ent->client->ps.saberBounceMove].name, animTable[saberMoveData[ent->client->ps.saberBounceMove].animToUse].name ); } #endif } - else if ( entPowerLevel > FORCE_LEVEL_2 || (!deflected && Q_irand( 0, PM_PowerLevelForSaberAnim( &ent->client->ps ) - hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]/*PM_PowerLevelForSaberAnim( &hitOwner->client->ps )*/ ) > 0 ) ) + else if ( entPowerLevel > FORCE_LEVEL_2 + || !activeDefense + || (!deflected && Q_irand( 0, PM_PowerLevelForSaberAnim( &ent->client->ps ) - hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]/*PM_PowerLevelForSaberAnim( &hitOwner->client->ps )*/ ) > 0 ) ) {//broke their parry altogether if ( entPowerLevel > FORCE_LEVEL_2 || Q_irand( 0, ent->client->ps.forcePowerLevel[FP_SABER_OFFENSE] - hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] ) ) {//chance of continuing with the attack (not bouncing back) @@ -2882,7 +3121,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) hitOwner->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; hitOwner->client->ps.saberBounceMove = LS_NONE; if ( hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] < FORCE_LEVEL_2 - && (ent->s.number||g_realisticSaberDamage->integer) + && (ent->s.number||g_saberRealisticCombat->integer) && !Q_irand( 0, 2 ) ) {//knocked the saber right out of his hand! //get the right velocity for my attack direction @@ -2911,7 +3150,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) } } } -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { if ( ent->client->ps.saberEventFlags&SEF_BLOCKED ) @@ -2929,6 +3168,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) { WP_SaberParry( hitOwner, ent ); if ( PM_SaberInBounce( ent->client->ps.saberMove ) //FIXME: saberMove not set until pmove! + && activeDefense && hitOwner->client->ps.saberAnimLevel != FORCE_LEVEL_1 && hitOwner->client->ps.saberAnimLevel != FORCE_LEVEL_5 && hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] > FORCE_LEVEL_2 ) {//attacker bounced off, and defender has ability to do knockaways, so do one unless we're using fast attacks @@ -2969,7 +3209,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) } //do some time-consuming saber-knocked-aside broken parry anim ent->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { if ( hitOwner->client->ps.saberEventFlags&SEF_BLOCKED ) @@ -3027,7 +3267,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) //FIXME: what if the damage was done before the parry? WP_SaberClearDamageForEntNum( hitOwner->s.number ); /* - if ( ent->s.number || g_autoBlocking->integer || ent->client->ps.saberBlockingTime > level.time ) + if ( ent->s.number || g_saberAutoBlocking->integer || ent->client->ps.saberBlockingTime > level.time ) {//either an NPC or a player who has blocking if ( !PM_SaberInTransitionAny( ent->client->ps.saberMove ) && !PM_SaberInBounce( ent->client->ps.saberMove ) ) {//I'm not attacking, in transition or in a bounce, so play a parry @@ -3200,7 +3440,7 @@ void WP_SaberDamageTrace( gentity_t *ent ) if ( WP_SaberApplyDamage( ent, baseDamage, baseDFlags, brokenParry ) ) {//actually did damage to something -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { gi.Printf( "base damage was %4.2f\n", baseDamage ); @@ -3246,7 +3486,12 @@ void WP_SaberImpact( gentity_t *owner, gentity_t *saber, trace_t *trace ) VectorCopy( saber->s.pos.trDelta, dir ); VectorNormalize( dir ); - G_Damage( other, owner, saber, dir, trace->endpos, other->health*2, 0, MOD_SABER ); + int dmg = other->health*2; + if ( other->health > 50 && dmg > 20 && !(other->svFlags&SVF_GLASS_BRUSH) ) + { + dmg = 20; + } + G_Damage( other, owner, saber, dir, trace->endpos, dmg, 0, MOD_SABER ); G_PlayEffect( "saber_cut", trace->endpos, dir ); if ( owner->s.number == 0 ) { @@ -3733,7 +3978,7 @@ void WP_RunSaber( gentity_t *self, gentity_t *saber ) {//home in on enemy float enemyDist = Distance( self->client->renderInfo.handRPoint, enemy->currentOrigin ); VectorCopy( enemy->currentOrigin, saberDest ); - saberDest[2] += enemy->maxs[2]/2.0f; + saberDest[2] += enemy->maxs[2]/2.0f;//FIXME: when in a knockdown anim, the saber float above them... do we care? self->client->ps.saberEntityDist = enemyDist; } } @@ -3752,6 +3997,13 @@ void WP_RunSaber( gentity_t *self, gentity_t *saber ) else if ( self->client->ps.saberEntityState == SES_LEAVING && dist < 50 ) { saberSpeed = dist * 2 + 30; + if ( (enemy && dist > enemy->maxs[0]) || (!enemy && dist > 24) ) + {//auto-tracking an enemy and we can't hit him + if ( saberSpeed < 120 ) + {//clamp to a minimum speed + saberSpeed = 120; + } + } } /* if ( self->client->ps.saberEntityState == SES_RETURNING ) @@ -3764,7 +4016,13 @@ void WP_RunSaber( gentity_t *self, gentity_t *saber ) } */ VectorScale( saber->s.pos.trDelta, saberSpeed, saber->s.pos.trDelta ); - SnapVector( saber->s.pos.trDelta ); // save net bandwidth + //SnapVector( saber->s.pos.trDelta ); // save net bandwidth + VectorCopy( saber->currentOrigin, saber->s.pos.trBase ); + saber->s.pos.trTime = level.time; + saber->s.pos.trType = TR_LINEAR; + } + else + { VectorCopy( saber->currentOrigin, saber->s.pos.trBase ); saber->s.pos.trTime = level.time; saber->s.pos.trType = TR_LINEAR; @@ -3894,17 +4152,20 @@ qboolean WP_SaberLaunch( gentity_t *self, gentity_t *saber, qboolean thrown ) saber->clipmask = MASK_SOLID | CONTENTS_LIGHTSABER; // remove the ghoul2 sabre model on the player - gi.G2API_RemoveGhoul2Model(self->ghoul2, self->weaponModel); - self->weaponModel = -1; + if ( self->weaponModel >= 0 ) + { + gi.G2API_RemoveGhoul2Model(self->ghoul2, self->weaponModel); + self->weaponModel = -1; + } return qtrue; } -void WP_SaberLose( gentity_t *self, vec3_t throwDir ) +qboolean WP_SaberLose( gentity_t *self, vec3_t throwDir ) { if ( !self || !self->client || self->client->ps.saberEntityNum <= 0 ) {//WTF?!! We lost it already? - return; + return qfalse; } gentity_t *dropped = &g_entities[self->client->ps.saberEntityNum]; if ( !self->client->ps.saberInFlight ) @@ -3915,7 +4176,7 @@ void WP_SaberLose( gentity_t *self, vec3_t throwDir ) //throw it if ( !WP_SaberLaunch( self, dropped, qfalse ) ) {//couldn't throw it - return; + return qfalse; } } if ( self->client->ps.saberActive ) @@ -3933,6 +4194,7 @@ void WP_SaberLose( gentity_t *self, vec3_t throwDir ) { self->NPC->last_ucmd.buttons &= ~BUTTON_ATTACK; } + return qtrue; } void WP_SaberCatch( gentity_t *self, gentity_t *saber, qboolean switchToSaber ) @@ -4093,7 +4355,7 @@ void WP_SaberThrow( gentity_t *self, usercmd_t *ucmd ) } else if ( ucmd->buttons & BUTTON_ALT_ATTACK && !(self->client->ps.pm_flags&PMF_ALT_ATTACK_HELD) ) {//still holding it, not still holding attack from a previous throw, so throw it. - if ( WP_SaberLaunch( self, saberent, qtrue ) ) + if ( !(self->client->ps.saberEventFlags&SEF_INWATER) && WP_SaberLaunch( self, saberent, qtrue ) ) { if ( self->client && !self->s.number ) { @@ -4145,7 +4407,8 @@ void WP_SaberThrow( gentity_t *self, usercmd_t *ucmd ) self->client->ps.saberEntityNum = ENTITYNUM_NONE; return; } - if ( !self->s.number && level.time - saberent->aimDebounceTime > 15000 ) + if ( (!self->s.number && level.time - saberent->aimDebounceTime > 15000) + || (self->s.number && level.time - saberent->aimDebounceTime > 5000) ) {//(only for player) been missing for 15 seconds, automagicially return WP_SaberCatch( self, saberent, qfalse ); return; @@ -4380,7 +4643,7 @@ void WP_SaberBlockNonRandom( gentity_t *self, vec3_t hitloc, qboolean missileBlo } } -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer ) { if ( !self->s.number ) @@ -4585,7 +4848,10 @@ void WP_SaberStartMissileBlockCheck( gentity_t *self, usercmd_t *ucmd ) if ( !self->s.number ) {//don't do this if already attacking! - if ( ucmd->buttons & BUTTON_ATTACK ) + if ( ucmd->buttons & BUTTON_ATTACK + || PM_SaberInAttack( self->client->ps.saberMove ) + || PM_SaberInSpecialAttack( self->client->ps.torsoAnim ) + || PM_SaberInTransitionAny( self->client->ps.saberMove )) { return; } @@ -4596,7 +4862,7 @@ void WP_SaberStartMissileBlockCheck( gentity_t *self, usercmd_t *ucmd ) return; } - if ( !self->s.number && !g_autoBlocking->integer && self->client->ps.saberBlockingTimes.number && !g_saberAutoBlocking->integer && self->client->ps.saberBlockingTimeowner->health <= 0 && !g_realisticSaberDamage->integer ) + if ( ent->owner->health <= 0 && !g_saberRealisticCombat->integer ) {//it's not doing damage, so ignore it continue; } @@ -4802,13 +5068,13 @@ void WP_SaberStartMissileBlockCheck( gentity_t *self, usercmd_t *ucmd ) if ( incoming ) { - if ( self->NPC ) + if ( self->NPC && !G_ControlledByPlayer( self ) ) { if ( Jedi_WaitingAmbush( self ) ) { Jedi_Ambush( self ); } - if ( Jedi_SaberBlockGo( self, NULL, NULL, incoming ) != EVASION_NONE ) + if ( Jedi_SaberBlockGo( self, &self->NPC->last_ucmd, NULL, NULL, incoming ) != EVASION_NONE ) {//make sure to turn on your saber if it's not on self->client->ps.saberActive = qtrue; } @@ -4893,9 +5159,9 @@ void WP_SaberUpdate( gentity_t *self, usercmd_t *ucmd ) else if ( self->client->ps.saberBlocking == BLK_TIGHT || self->client->ps.saberBlocking == BLK_WIDE ) {//FIXME: keep bbox in front of player, even when wide? vec3_t saberOrg; - if ( ( (self->s.number&&!Jedi_SaberBusy(self)) || (self->s.number == 0 && self->client->ps.saberBlocking == BLK_WIDE && (g_autoBlocking->integer||self->client->ps.saberBlockingTime>level.time)) ) + if ( ( (self->s.number&&!Jedi_SaberBusy(self)&&!g_saberRealisticCombat->integer) || (self->s.number == 0 && self->client->ps.saberBlocking == BLK_WIDE && (g_saberAutoBlocking->integer||self->client->ps.saberBlockingTime>level.time)) ) && self->client->ps.weaponTime <= 0 ) - {//full-size blocking for non-attacking player with g_autoBlocking on + {//full-size blocking for non-attacking player with g_saberAutoBlocking on vec3_t saberang={0,0,0}, fwd, sabermins={-8,-8,-8}, sabermaxs={8,8,8}; saberang[YAW] = self->client->ps.viewangles[YAW]; @@ -4919,15 +5185,15 @@ void WP_SaberUpdate( gentity_t *self, usercmd_t *ucmd ) { if ( saberTip[i] > self->client->renderInfo.muzzlePoint[i] ) { - saberent->maxs[i] = saberTip[i] - saberOrg[i];//self->client->renderInfo.muzzlePoint[i]; - saberent->mins[i] = self->client->renderInfo.muzzlePoint[i] - saberOrg[i]; + saberent->maxs[i] = saberTip[i] - saberOrg[i] + 8;//self->client->renderInfo.muzzlePoint[i]; + saberent->mins[i] = self->client->renderInfo.muzzlePoint[i] - saberOrg[i] - 8; } else //if ( saberTip[i] < self->client->renderInfo.muzzlePoint[i] ) { - saberent->maxs[i] = self->client->renderInfo.muzzlePoint[i] - saberOrg[i]; - saberent->mins[i] = saberTip[i] - saberOrg[i];//self->client->renderInfo.muzzlePoint[i]; + saberent->maxs[i] = self->client->renderInfo.muzzlePoint[i] - saberOrg[i] + 8; + saberent->mins[i] = saberTip[i] - saberOrg[i] - 8;//self->client->renderInfo.muzzlePoint[i]; } - if ( self->client->ps.weaponTime > 0 || self->s.number || g_autoBlocking->integer || self->client->ps.saberBlockingTime > level.time ) + if ( self->client->ps.weaponTime > 0 || self->s.number || g_saberAutoBlocking->integer || self->client->ps.saberBlockingTime > level.time ) {//if attacking or blocking (or an NPC), inflate to a minimum size if ( saberent->maxs[i] < minsize ) { @@ -5012,7 +5278,7 @@ void WP_SaberUpdate( gentity_t *self, usercmd_t *ucmd ) { WP_SaberInFlightReflectCheck( self, ucmd ); } -#ifndef _FINAL_BUILD +#ifndef FINAL_BUILD if ( d_saberCombat->integer > 2 ) { CG_CubeOutline( saberent->absmin, saberent->absmax, 50, WPDEBUG_SaberColor( self->client->ps.saberColor ), 1 ); @@ -5035,32 +5301,34 @@ void WP_DropWeapon( gentity_t *dropper, vec3_t velocity ) return; } int replaceWeap = WP_NONE; + int oldWeap = dropper->s.weapon; gentity_t *weapon = TossClientItems( dropper ); - if ( dropper->s.weapon == WP_THERMAL && dropper->NPC ) + if ( oldWeap == WP_THERMAL && dropper->NPC ) {//Hmm, maybe all NPCs should go into melee? Not too many, though, or they mob you and look silly replaceWeap = WP_MELEE; } - if (dropper->ghoul2.IsValid()&& dropper->weaponModel != -1 ) + if (dropper->ghoul2.IsValid()&& dropper->weaponModel >= 0 ) { gi.G2API_RemoveGhoul2Model( dropper->ghoul2, dropper->weaponModel ); dropper->weaponModel = -1; } //FIXME: does this work on the player? + dropper->client->ps.stats[STAT_WEAPONS] |= ( 1 << replaceWeap ); if ( !dropper->s.number ) { - if ( dropper->s.weapon == WP_THERMAL ) + if ( oldWeap == WP_THERMAL ) { - dropper->client->ps.ammo[weaponData[dropper->s.weapon].ammoIndex] -= weaponData[dropper->s.weapon].energyPerShot; + dropper->client->ps.ammo[weaponData[oldWeap].ammoIndex] -= weaponData[oldWeap].energyPerShot; } else { - dropper->client->ps.stats[STAT_WEAPONS] &= ~( 1 << dropper->s.weapon ); + dropper->client->ps.stats[STAT_WEAPONS] &= ~( 1 << oldWeap ); } CG_ChangeWeapon( replaceWeap ); } else { - dropper->client->ps.stats[STAT_WEAPONS] &= ~( 1 << dropper->s.weapon ); + dropper->client->ps.stats[STAT_WEAPONS] &= ~( 1 << oldWeap ); } ChangeWeapon( dropper, replaceWeap ); dropper->s.weapon = replaceWeap; @@ -5104,12 +5372,12 @@ void WP_KnockdownTurret( gentity_t *self, gentity_t *pas ) pas->forcePushTime = level.time + 600; // let the push effect last for 600 ms } -void WP_ResistForcePush( gentity_t *self, gentity_t *pusher ) +void WP_ResistForcePush( gentity_t *self, gentity_t *pusher, qboolean noPenalty ) { int parts; qboolean runningResist = qfalse; - if ( !self || !self->client || !pusher || !pusher->client ) + if ( !self || self->health <= 0 || !self->client || !pusher || !pusher->client ) { return; } @@ -5133,20 +5401,31 @@ void WP_ResistForcePush( gentity_t *self, gentity_t *pusher ) parts = SETANIM_TORSO; } NPC_SetAnim( self, parts, BOTH_RESISTPUSH, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - if ( !runningResist ) + if ( !noPenalty ) { - VectorClear( self->client->ps.velocity ); - //still stop them from attacking or moving for a bit, though - //FIXME: maybe push just a little (like, slide)? - self->client->ps.weaponTime = 1000; - self->client->ps.pm_time = 1000; - self->client->ps.pm_flags |= PMF_TIME_KNOCKBACK; - //play the full body push effect on me - self->forcePushTime = level.time + 600; // let the push effect last for 600 ms - } - else - { - self->client->ps.weaponTime = 600; + if ( !runningResist ) + { + VectorClear( self->client->ps.velocity ); + //still stop them from attacking or moving for a bit, though + //FIXME: maybe push just a little (like, slide)? + self->client->ps.weaponTime = 1000; + if ( self->client->ps.forcePowersActive&(1<client->ps.weaponTime = floor( self->client->ps.weaponTime * g_timescale->value ); + } + self->client->ps.pm_time = self->client->ps.weaponTime; + self->client->ps.pm_flags |= PMF_TIME_KNOCKBACK; + //play the full body push effect on me + self->forcePushTime = level.time + 600; // let the push effect last for 600 ms + } + else + { + self->client->ps.weaponTime = 600; + if ( self->client->ps.forcePowersActive&(1<client->ps.weaponTime = floor( self->client->ps.weaponTime * g_timescale->value ); + } + } } //play my force push effect on my hand self->client->ps.powerups[PW_FORCE_PUSH] = level.time + self->client->ps.torsoAnimTimer + 500; @@ -5177,6 +5456,17 @@ void WP_ForceKnockdown( gentity_t *self, gentity_t *pusher, qboolean pull, qbool { GEntity_PainFunc( self, pusher, pusher, self->currentOrigin, 0, MOD_MELEE ); } + vec3_t pushDir; + if ( pull ) + { + VectorSubtract( pusher->currentOrigin, self->currentOrigin, pushDir ); + } + else + { + VectorSubtract( self->currentOrigin, pusher->currentOrigin, pushDir ); + } + G_CheckLedgeDive( self, 72, pushDir, qfalse, qfalse ); + if ( !PM_SpinningSaberAnim( self->client->ps.legsAnim ) && !PM_FlippingAnim( self->client->ps.legsAnim ) && !PM_RollingAnim( self->client->ps.legsAnim ) @@ -5272,7 +5562,7 @@ void ForceThrow( gentity_t *self, qboolean pull ) vec3_t center, ent_org, size, forward, right, end, dir, fwdangles = {0}; float dot1, cone; trace_t tr; - int anim, hold, soundIndex; + int anim, hold, soundIndex, cost, actualCost; if ( self->health <= 0 ) { @@ -5290,12 +5580,23 @@ void ForceThrow( gentity_t *self, qboolean pull ) {//can't force throw/pull when zoomed in or in cinematic return; } - if ( self->client->ps.saberLockTime > level.time && ( pull || self->client->ps.forcePowerLevel[FP_PUSH] < FORCE_LEVEL_3 ) ) - {//this can be a way to break out - return; + if ( self->client->ps.saberLockTime > level.time ) + { + if ( pull || self->client->ps.forcePowerLevel[FP_PUSH] < FORCE_LEVEL_3 ) + {//this can be a way to break out + return; + } + //else, I'm breaking my half of the saberlock + self->client->ps.saberLockTime = 0; + self->client->ps.saberLockEnemy = ENTITYNUM_NONE; } - if ( self->client->ps.legsAnim == BOTH_KNOCKDOWN3 || (self->client->ps.torsoAnim == BOTH_GETUP3 && self->client->ps.torsoAnimTimer > 500) ) + if ( self->client->ps.legsAnim == BOTH_KNOCKDOWN3 + || (self->client->ps.torsoAnim == BOTH_FORCE_GETUP_F1 && self->client->ps.torsoAnimTimer > 400) + || (self->client->ps.torsoAnim == BOTH_FORCE_GETUP_F2 && self->client->ps.torsoAnimTimer > 900) + || (self->client->ps.torsoAnim == BOTH_GETUP3 && self->client->ps.torsoAnimTimer > 500) + || (self->client->ps.torsoAnim == BOTH_GETUP4 && self->client->ps.torsoAnimTimer > 300) + || (self->client->ps.torsoAnim == BOTH_GETUP5 && self->client->ps.torsoAnimTimer > 500) ) {//we're face-down, so we'd only be force-push/pulling the floor return; } @@ -5315,13 +5616,11 @@ void ForceThrow( gentity_t *self, qboolean pull ) if ( pull ) { - //FIXME: base cost on the number of things you end up pulling? - int cost = forcePowerNeeded[FP_PULL]*self->client->ps.forcePowerLevel[FP_PULL]; + cost = forcePowerNeeded[FP_PULL]; if ( !WP_ForcePowerUsable( self, FP_PULL, cost ) ) { return; } - WP_ForcePowerStart( self, FP_PULL, cost ); //make sure this plays and that you cannot press fire for about 200ms after this anim = BOTH_FORCEPULL; soundIndex = G_SoundIndex( "sound/weapons/force/pull.wav" ); @@ -5329,17 +5628,15 @@ void ForceThrow( gentity_t *self, qboolean pull ) } else { - //FIXME: base cost on the number of things you end up pushing? - int cost = forcePowerNeeded[FP_PUSH]*self->client->ps.forcePowerLevel[FP_PUSH]; + cost = forcePowerNeeded[FP_PUSH]; if ( !WP_ForcePowerUsable( self, FP_PUSH, cost ) ) { return; } - WP_ForcePowerStart( self, FP_PUSH, cost ); //make sure this plays and that you cannot press fire for about 1 second after this anim = BOTH_FORCEPUSH; soundIndex = G_SoundIndex( "sound/weapons/force/push.wav" ); - hold = 1000; + hold = 650; } int parts = SETANIM_TORSO; @@ -5352,26 +5649,21 @@ void ForceThrow( gentity_t *self, qboolean pull ) hold += 1000; parts = SETANIM_BOTH; } - else if ( !VectorLengthSquared( self->client->ps.velocity ) ) + else if ( !VectorLengthSquared( self->client->ps.velocity ) && !(self->client->ps.pm_flags&PMF_DUCKED)) { parts = SETANIM_BOTH; } } - NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD|SETANIM_FLAG_RESTART ); self->client->ps.saberMove = self->client->ps.saberBounceMove = LS_READY;//don't finish whatever saber anim you may have been in self->client->ps.saberBlocked = BLOCKED_NONE; + if ( self->client->ps.forcePowersActive&(1<value ); + } self->client->ps.weaponTime = hold;//was 1000, but want to swing sooner //do effect... FIXME: build-up or delay this until in proper part of anim self->client->ps.powerups[PW_FORCE_PUSH] = level.time + self->client->ps.torsoAnimTimer + 500; - if ( self->NPC ) - {//NPCs can push more often - //FIXME: vary by rank and game skill? - self->client->ps.forcePowerDebounce[FP_PUSH] = level.time + 200; - } - else - { - self->client->ps.forcePowerDebounce[FP_PUSH] = level.time + self->client->ps.torsoAnimTimer + 500; - } G_Sound( self, soundIndex ); @@ -5422,7 +5714,13 @@ void ForceThrow( gentity_t *self, qboolean pull ) if ( !(ent->inuse) ) continue; if ( ent->NPC && ent->NPC->scriptFlags & SCF_NO_FORCE ) + { + if ( ent->s.weapon == WP_SABER ) + {//Hmm, should jedi do the resist behavior? If this is on, perhaps it's because of a cinematic? + WP_ResistForcePush( ent, self, qtrue ); + } continue; + } if ( (ent->flags&FL_FORCE_PULLABLE_ONLY) && !pull ) {//simple HACK: cannot force-push ammo rack items (because they may start in solid) continue; @@ -5434,7 +5732,15 @@ void ForceThrow( gentity_t *self, qboolean pull ) {//must be pointing right at them if ( ent != forwardEnt ) {//must be the person I'm looking right at - continue; + if ( ent->client && !pull + && ent->client->ps.forceGripEntityNum == self->s.number + && (self->s.eFlags&EF_FORCE_GRIPPED) ) + {//this is the guy that's force-gripping me, use a wider cone regardless of force power level + } + else + { + continue; + } } } if ( ent->s.eType != ET_ITEM && ent->e_ThinkFunc != thinkF_G_RunObject )//|| !(ent->flags&FL_DROPPED_ITEM) )//was only dropped items @@ -5498,9 +5804,38 @@ void ForceThrow( gentity_t *self, qboolean pull ) continue; } } - else if ( (!pull||self->s.number) && ent->s.eType == ET_ITEM && ent->item && ent->item->giType == IT_HOLDABLE && ent->item->giTag == INV_SECURITY_KEY1 && (ent->flags&FL_DROPPED_ITEM) ) + else if ( ent->s.eType == ET_ITEM + && ent->item + && ent->item->giType == IT_HOLDABLE + && ent->item->giTag == INV_SECURITY_KEY ) + //&& (ent->flags&FL_DROPPED_ITEM) ??? {//dropped security keys can't be pushed? But placed ones can...? does this make any sense? - continue; + if ( !pull || self->s.number ) + {//can't push, NPC's can't do anything to it + continue; + } + else + { + if ( g_crosshairEntNum != ent->s.number ) + {//player can pull it if looking *right* at it + if ( cone >= 1.0f ) + {//we did a forwardEnt trace + if ( forwardEnt != ent ) + {//must be pointing right at them + continue; + } + } + else + {//do a forwardEnt trace + VectorMA( self->client->renderInfo.eyePoint, radius, forward, end ); + gi.trace( &tr, self->client->renderInfo.eyePoint, vec3_origin, vec3_origin, end, self->s.number, MASK_OPAQUE|CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_ITEM|CONTENTS_CORPSE );//was MASK_SHOT, changed to match crosshair trace + if ( tr.entityNum != ent->s.number ) + {//last chance + continue; + } + } + } + } } } else @@ -5537,17 +5872,26 @@ void ForceThrow( gentity_t *self, qboolean pull ) //see if they're in front of me VectorSubtract( ent_org, center, dir ); VectorNormalize( dir ); - if ( ent->s.eType != ET_MISSILE )//&& ent->s.eType != ET_ITEM && ent->e_ThinkFunc != thinkF_G_RunObject ) - {//missiles are easier to force-push, never require direct trace (FIXME: maybe also items and general physics objects) - if ( (dot1 = DotProduct( dir, forward )) < cone-0.3f ) - continue; - } - else if ( cone < 1.0f ) + if ( cone < 1.0f ) {//must be within the forward cone - if ( (dot1 = DotProduct( dir, forward )) < cone ) + if ( ent->client && !pull + && ent->client->ps.forceGripEntityNum == self->s.number + && self->s.eFlags&EF_FORCE_GRIPPED ) + {//this is the guy that's force-gripping me, use a wider cone regardless of force power level + if ( (dot1 = DotProduct( dir, forward )) < cone-0.3f ) + continue; + } + else if ( ent->s.eType == ET_MISSILE )//&& ent->s.eType != ET_ITEM && ent->e_ThinkFunc != thinkF_G_RunObject ) + {//missiles are easier to force-push, never require direct trace (FIXME: maybe also items and general physics objects) + if ( (dot1 = DotProduct( dir, forward )) < cone-0.3f ) + continue; + } + else if ( (dot1 = DotProduct( dir, forward )) < cone ) + { continue; + } } - else + else if ( ent->s.eType == ET_MISSILE ) {//a missile and we're at force level 1... just use a small cone, but not ridiculously small if ( (dot1 = DotProduct( dir, forward )) < 0.75f ) { @@ -5623,7 +5967,9 @@ void ForceThrow( gentity_t *self, qboolean pull ) {//player's force push/pull is high enough to try to stop me if ( InFront( self->currentOrigin, push_list[x]->client->renderInfo.eyePoint, push_list[x]->client->ps.viewangles, 0.3f ) ) {//I'm in front of player - WP_ResistForcePush( push_list[x], self ); + WP_ResistForcePush( push_list[x], self, qfalse ); + push_list[x]->client->ps.saberMove = push_list[x]->client->ps.saberBounceMove = LS_READY;//don't finish whatever saber anim you may have been in + push_list[x]->client->ps.saberBlocked = BLOCKED_NONE; continue; } } @@ -5663,9 +6009,13 @@ void ForceThrow( gentity_t *self, qboolean pull ) {//we will knock them down self->painDebounceTime = 0; self->client->ps.weaponTime = 500; + if ( self->client->ps.forcePowersActive&(1<client->ps.weaponTime = floor( self->client->ps.weaponTime * g_timescale->value ); + } } } - if ( !pull && self->client->ps.forcePowerLevel[FP_PUSH] > FORCE_LEVEL_2 && + if ( !pull && self->client->ps.forcePowerLevel[FP_PUSH] > FORCE_LEVEL_2 && !Q_irand(0,2) && push_list[x]->client->ps.forcePowerLevel[FP_PUSH] < FORCE_LEVEL_3 ) {//a level 3 push can even knock down a jedi if ( PM_InKnockDown( &push_list[x]->client->ps ) ) @@ -5676,7 +6026,7 @@ void ForceThrow( gentity_t *self, qboolean pull ) } else { - WP_ResistForcePush( push_list[x], self ); + WP_ResistForcePush( push_list[x], self, qfalse ); } } else @@ -5951,7 +6301,9 @@ void ForceThrow( gentity_t *self, qboolean pull ) } GEntity_UseFunc( push_list[x], self, self ); } - else if ( push_list[x]->s.eType == ET_MISSILE/*thermal resting on ground*/ || push_list[x]->s.eType == ET_ITEM || push_list[x]->e_ThinkFunc == thinkF_G_RunObject || Q_stricmp( "limb", push_list[x]->classname ) == 0 ) + else if ( push_list[x]->s.eType == ET_MISSILE/*thermal resting on ground*/ + || push_list[x]->s.eType == ET_ITEM + || push_list[x]->e_ThinkFunc == thinkF_G_RunObject || Q_stricmp( "limb", push_list[x]->classname ) == 0 ) {//general object, toss it vec3_t pushDir, kvel; float knockback = pull?0:200; @@ -5962,7 +6314,7 @@ void ForceThrow( gentity_t *self, qboolean pull ) {//pull it to a little higher point vec3_t adjustedOrg; VectorCopy( self->currentOrigin, adjustedOrg ); - adjustedOrg[2] += self->maxs[2]/2; + adjustedOrg[2] += self->maxs[2]/3; VectorSubtract( adjustedOrg, push_list[x]->currentOrigin, pushDir ); } else @@ -5974,6 +6326,20 @@ void ForceThrow( gentity_t *self, qboolean pull ) { knockback = 200; } + if ( push_list[x]->s.eType == ET_ITEM + && push_list[x]->item + && push_list[x]->item->giType == IT_HOLDABLE + && push_list[x]->item->giTag == INV_SECURITY_KEY ) + {//security keys are pulled with less enthusiasm + if ( knockback > 100 ) + { + knockback = 100; + } + } + else if ( knockback > 200 ) + { + knockback = 200; + } } else { @@ -6035,7 +6401,7 @@ void ForceThrow( gentity_t *self, qboolean pull ) push_list[x]->nextthink = level.time + FRAMETIME; } push_list[x]->forcePushTime = level.time + 600; // let the push effect last for 600 ms - if ( push_list[x]->item && push_list[x]->item->giTag == INV_SECURITY_KEY1 ) + if ( push_list[x]->item && push_list[x]->item->giTag == INV_SECURITY_KEY ) { AddSightEvent( player, push_list[x]->currentOrigin, 128, AEL_DISCOVERED );//security keys are more important } @@ -6051,6 +6417,78 @@ void ForceThrow( gentity_t *self, qboolean pull ) WP_KnockdownTurret( self, push_list[x] ); } } + if ( pull ) + { + if ( self->client->ps.forcePowerLevel[FP_PUSH] > FORCE_LEVEL_2 ) + {//at level 3, can pull multiple, so it costs more + actualCost = forcePowerNeeded[FP_PUSH]*ent_count; + if ( actualCost > 50 ) + { + actualCost = 50; + } + else if ( actualCost < cost ) + { + actualCost = cost; + } + } + else + { + actualCost = cost; + } + WP_ForcePowerStart( self, FP_PULL, actualCost ); + } + else + { + if ( self->client->ps.forcePowerLevel[FP_PUSH] > FORCE_LEVEL_2 ) + {//at level 3, can push multiple, so costs more + actualCost = forcePowerNeeded[FP_PUSH]*ent_count; + if ( actualCost > 50 ) + { + actualCost = 50; + } + else if ( actualCost < cost ) + { + actualCost = cost; + } + } + else if ( self->client->ps.forcePowerLevel[FP_PUSH] > FORCE_LEVEL_1 ) + {//at level 3, can push multiple, so costs more + actualCost = floor(forcePowerNeeded[FP_PUSH]*ent_count/1.5f); + if ( actualCost > 50 ) + { + actualCost = 50; + } + else if ( actualCost < cost ) + { + actualCost = cost; + } + } + else + { + actualCost = cost; + } + WP_ForcePowerStart( self, FP_PUSH, actualCost ); + } + } + else + {//didn't push or pull anything? don't penalize them too much + if ( pull ) + { + WP_ForcePowerStart( self, FP_PULL, 5 ); + } + else + { + WP_ForcePowerStart( self, FP_PUSH, 5 ); + } + } + if ( self->NPC ) + {//NPCs can push more often + //FIXME: vary by rank and game skill? + self->client->ps.forcePowerDebounce[FP_PUSH] = level.time + 200; + } + else + { + self->client->ps.forcePowerDebounce[FP_PUSH] = level.time + self->client->ps.torsoAnimTimer + 500; } } @@ -6087,7 +6525,7 @@ void ForceHeal( gentity_t *self ) return; } - if ( !WP_ForcePowerUsable( self, FP_HEAL, forcePowerNeeded[FP_HEAL]*5 ) ) + if ( !WP_ForcePowerUsable( self, FP_HEAL, 20 ) ) {//must have enough force power for at least 5 points of health return; } @@ -6151,9 +6589,12 @@ void ForceHeal( gentity_t *self ) } else {//just a quick gesture + /* + //Can't get an anim that looks good... NPC_SetAnim( self, SETANIM_TORSO, BOTH_FORCEHEAL_QUICK, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); self->client->ps.saberMove = self->client->ps.saberBounceMove = LS_READY;//don't finish whatever saber anim you may have been in self->client->ps.saberBlocked = BLOCKED_NONE; + */ } } @@ -6161,8 +6602,49 @@ void ForceHeal( gentity_t *self ) G_SoundOnEnt( self, CHAN_ITEM, "sound/weapons/force/heal.mp3" ); } -extern void NPC_ST_PlayConfusionSound( gentity_t *self ); +extern void NPC_PlayConfusionSound( gentity_t *self ); extern void NPC_Jedi_PlayConfusionSound( gentity_t *self ); +qboolean WP_CheckBreakControl( gentity_t *self ) +{ + if ( !self ) + { + return qfalse; + } + if ( !self->s.number ) + {//player + if ( self->client && self->client->ps.forcePowerLevel[FP_TELEPATHY] > FORCE_LEVEL_3 ) + {//control-level + if ( self->client->ps.viewEntity > 0 && self->client->ps.viewEntity < ENTITYNUM_WORLD ) + {//we are in a viewentity + gentity_t *controlled = &g_entities[self->client->ps.viewEntity]; + if ( controlled->NPC && controlled->NPC->controlledTime > level.time ) + {//it is an NPC we controlled + //clear it and return + G_ClearViewEntity( self ); + return qtrue; + } + } + } + } + else + {//NPC + if ( self->NPC && self->NPC->controlledTime > level.time ) + {//being controlled + gentity_t *controller = &g_entities[0]; + if ( controller->client && controller->client->ps.viewEntity == self->s.number ) + {//we are being controlled by player + if ( controller->client->ps.forcePowerLevel[FP_TELEPATHY] > FORCE_LEVEL_3 ) + {//control-level mind trick + //clear the control and return + G_ClearViewEntity( controller ); + return qtrue; + } + } + } + } + return qfalse; +} + void ForceTelepathy( gentity_t *self ) { trace_t tr; @@ -6170,11 +6652,14 @@ void ForceTelepathy( gentity_t *self ) gentity_t *traceEnt; qboolean targetLive = qfalse; + if ( WP_CheckBreakControl( self ) ) + { + return; + } if ( self->health <= 0 ) { return; } - //FIXME: if mind trick 3 and aiming at an enemy need more force power if ( !WP_ForcePowerUsable( self, FP_TELEPATHY, 0 ) ) { @@ -6228,6 +6713,7 @@ void ForceTelepathy( gentity_t *self ) case CLASS_MOUSE: case CLASS_SEEKER: case CLASS_REMOTE: + case CLASS_PROTOCOL: break; default: targetLive = qtrue; @@ -6244,7 +6730,19 @@ void ForceTelepathy( gentity_t *self ) else if ( traceEnt->client->playerTeam != self->client->playerTeam ) {//an enemy int override = 0; - if ( traceEnt->s.weapon != WP_SABER ) + if ( (traceEnt->NPC->scriptFlags&SCF_NO_MIND_TRICK) ) + { + if ( traceEnt->client->NPC_class == CLASS_GALAKMECH ) + { + G_AddVoiceEvent( NPC, Q_irand( EV_CONFUSE1, EV_CONFUSE3 ), Q_irand( 3000, 5000 ) ); + } + } + else if ( self->client->ps.forcePowerLevel[FP_TELEPATHY] > FORCE_LEVEL_3 ) + {//control them, even jedi + G_SetViewEntity( self, traceEnt ); + traceEnt->NPC->controlledTime = level.time + 30000; + } + else if ( traceEnt->s.weapon != WP_SABER ) {//haha! Jedi aren't easily confused! if ( self->client->ps.forcePowerLevel[FP_TELEPATHY] > FORCE_LEVEL_2 ) {//turn them to our side @@ -6262,7 +6760,7 @@ void ForceTelepathy( gentity_t *self ) } if ( traceEnt->NPC ) { - traceEnt->NPC->tempBehavior = BS_FOLLOW_LEADER; + //traceEnt->NPC->tempBehavior = BS_FOLLOW_LEADER; traceEnt->client->leader = self; } //FIXME: maybe pick an enemy right here? @@ -6273,18 +6771,11 @@ void ForceTelepathy( gentity_t *self ) traceEnt->NPC->charmedTime = level.time + mindTrickTime[self->client->ps.forcePowerLevel[FP_TELEPATHY]]; } } - else if ( !(traceEnt->NPC->scriptFlags&SCF_NO_MIND_TRICK) ) + else {//just confuse them //somehow confuse them? Set don't fire to true for a while? Drop their aggression? Maybe just take their enemy away and don't let them pick one up for a while unless shot? traceEnt->NPC->confusionTime = level.time + mindTrickTime[self->client->ps.forcePowerLevel[FP_TELEPATHY]];//confused for about 10 seconds - //HACK!!! - // if ( !Q_stricmp( "stormtrooper", traceEnt->NPC_type ) || - // !Q_stricmp( "stormtrooper2", traceEnt->NPC_type ) || - // !Q_stricmp( "STOfficer", traceEnt->NPC_type ) ) - if ( traceEnt->client->NPC_class == CLASS_STORMTROOPER ) - { - NPC_ST_PlayConfusionSound( traceEnt ); - } + NPC_PlayConfusionSound( traceEnt ); if ( traceEnt->enemy ) { G_ClearEnemy( traceEnt ); @@ -6323,7 +6814,7 @@ void ForceTelepathy( gentity_t *self ) //use distraction anim instead G_PlayEffect( G_EffectIndex( "force_touch" ), tr.endpos, tr.plane.normal ); //FIXME: these events don't seem to always be picked up...? - AddSoundEvent( self, tr.endpos, 512, AEL_SUSPICIOUS ); + AddSoundEvent( self, tr.endpos, 512, AEL_SUSPICIOUS, qtrue ); AddSightEvent( self, tr.endpos, 512, AEL_SUSPICIOUS, 50 ); WP_ForcePowerStart( self, FP_TELEPATHY, 0 ); } @@ -6332,6 +6823,10 @@ void ForceTelepathy( gentity_t *self ) self->client->ps.saberMove = self->client->ps.saberBounceMove = LS_READY;//don't finish whatever saber anim you may have been in self->client->ps.saberBlocked = BLOCKED_NONE; self->client->ps.weaponTime = 1000; + if ( self->client->ps.forcePowersActive&(1<client->ps.weaponTime = floor( self->client->ps.weaponTime * g_timescale->value ); + } } void ForceGrip( gentity_t *self ) @@ -6359,6 +6854,10 @@ void ForceGrip( gentity_t *self ) { self->client->ps.forcePowerDuration[FP_GRIP] = level.time + 100; self->client->ps.weaponTime = 1000; + if ( self->client->ps.forcePowersActive&(1<client->ps.weaponTime = floor( self->client->ps.weaponTime * g_timescale->value ); + } } return; } @@ -6388,6 +6887,10 @@ void ForceGrip( gentity_t *self ) self->client->ps.saberBlocked = BLOCKED_NONE; self->client->ps.weaponTime = 1000; + if ( self->client->ps.forcePowersActive&(1<client->ps.weaponTime = floor( self->client->ps.weaponTime * g_timescale->value ); + } AngleVectors( self->client->ps.viewangles, forward, NULL, NULL ); VectorNormalize( forward ); @@ -6429,18 +6932,28 @@ void ForceGrip( gentity_t *self ) switch ( traceEnt->client->NPC_class ) { case CLASS_GALAKMECH://cant grip him, he's in armor + G_AddVoiceEvent( traceEnt, Q_irand(EV_PUSHED1, EV_PUSHED3), Q_irand( 3000, 5000 ) ); + return; + break; case CLASS_ATST://much too big to grip! + return; //no droids either...? - case CLASS_PROBE: case CLASS_GONK: case CLASS_R2D2: case CLASS_R5D2: case CLASS_MARK1: case CLASS_MARK2: case CLASS_MOUSE://? + case CLASS_PROTOCOL: + //*sigh*... in JK3, you'll be able to grab and move *anything*... + return; + break; + case CLASS_PROBE: case CLASS_SEEKER: case CLASS_REMOTE: - case CLASS_PROTOCOL: + case CLASS_SENTRY: + case CLASS_INTERROGATOR: + //*sigh*... in JK3, you'll be able to grab and move *anything*... return; break; case CLASS_DESANN://Desann cannot be gripped, he just pushes you back instantly @@ -6571,9 +7084,10 @@ void ForceLightning( gentity_t *self ) self->client->ps.saberMove = self->client->ps.saberBounceMove = LS_READY;//don't finish whatever saber anim you may have been in self->client->ps.saberBlocked = BLOCKED_NONE; + G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/lightning.wav" ); if ( self->client->ps.forcePowerLevel[FP_LIGHTNING] < FORCE_LEVEL_2 ) {//short burst - G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/lightning.wav" ); + //G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/lightning.wav" ); } else {//holding it @@ -6634,11 +7148,19 @@ void ForceLightningDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, flo parts = SETANIM_TORSO; } NPC_SetAnim( traceEnt, parts, BOTH_RESISTPUSH, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + Jedi_PlayDeflectSound( traceEnt ); dmg = 0; } - else if ( traceEnt->s.weapon == WP_SABER && Q_irand( 0, 1 ) ) - {//jedi less likely to be damaged - dmg = 0; + else if ( traceEnt->s.weapon == WP_SABER ) + { + if ( Q_irand( 0, 1 ) ) + {//jedi less likely to be damaged + dmg = 0; + } + else + { + dmg = 1; + } } if ( traceEnt && traceEnt->client && traceEnt->client->NPC_class == CLASS_GALAK ) { @@ -7033,17 +7555,20 @@ void WP_ForcePowerRegenerate( gentity_t *self, int overrideAmt ) return; } - if ( overrideAmt ) + if ( self->client->ps.forcePower < self->client->ps.forcePowerMax ) { - self->client->ps.forcePower += overrideAmt; - } - else - { - self->client->ps.forcePower++; - } - if ( self->client->ps.forcePower > self->client->ps.forcePowerMax ) - { - self->client->ps.forcePower = self->client->ps.forcePowerMax; + if ( overrideAmt ) + { + self->client->ps.forcePower += overrideAmt; + } + else + { + self->client->ps.forcePower++; + } + if ( self->client->ps.forcePower > self->client->ps.forcePowerMax ) + { + self->client->ps.forcePower = self->client->ps.forcePowerMax; + } } } @@ -7236,6 +7761,8 @@ void WP_ForcePowerStop( gentity_t *self, forcePowers_t forcePower ) gi.cvar_set("timescale", "1"); } } + //FIXME: reset my current anim, keeping current frame, but with proper anim speed + // otherwise, the anim will continue playing at high speed self->s.loopSound = 0; break; case FP_PUSH: @@ -7382,7 +7909,10 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd case FP_HEAL: if ( self->client->ps.forceHealCount >= MAX_FORCE_HEAL || self->health >= self->client->ps.stats[STAT_MAX_HEALTH] ) {//fully healed or used up all 25 - G_SoundOnEnt( self, CHAN_VOICE, va( "sound/weapons/force/heal%d.mp3", Q_irand( 1, 4 ) ) ); + if ( !Q3_TaskIDPending( self, TID_CHAN_VOICE ) ) + { + G_SoundOnEnt( self, CHAN_VOICE, va( "sound/weapons/force/heal%d.mp3", Q_irand( 1, 4 ) ) ); + } WP_ForcePowerStop( self, forcePower ); } else if ( self->client->ps.forcePowerLevel[FP_HEAL] < FORCE_LEVEL_3 && ( (cmd->buttons&BUTTON_ATTACK) || (cmd->buttons&BUTTON_ALT_ATTACK) || self->painDebounceTime > level.time || self->client->ps.weaponTime ) ) @@ -7397,7 +7927,7 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd } else if ( self->client->ps.forcePowerDebounce[FP_HEAL] < level.time ) {//time to heal again - if ( WP_ForcePowerAvailable( self, forcePower, 0 ) ) + if ( WP_ForcePowerAvailable( self, forcePower, 4 ) ) {//have available power self->health++; self->client->ps.forceHealCount++; @@ -7409,7 +7939,7 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd { self->client->ps.forcePowerDebounce[FP_HEAL] = level.time + FORCE_HEAL_INTERVAL; } - WP_ForcePowerDrain( self, forcePower, 0 ); + WP_ForcePowerDrain( self, forcePower, 4 ); } else {//stop @@ -7492,6 +8022,13 @@ static void WP_ForcePowerRun( gentity_t *self, forcePowers_t forcePower, usercmd WP_ForcePowerStop( self, FP_GRIP ); return; } + else if ( self->client->ps.forcePowerLevel[FP_GRIP] == FORCE_LEVEL_1 + && gripEnt->client + && gripEnt->client->ps.groundEntityNum == ENTITYNUM_NONE ) + { + WP_ForcePowerStop( self, FP_GRIP ); + return; + } else if ( gripEnt->s.weapon == WP_SABER && gripEnt->NPC && gripEnt->client && gripEnt->client->ps.forcePowersKnown&(1<NPC->stats.evasion*10)-(g_spskill->integer*10) ) ) {//a jedi who broke free FIXME: maybe have some minimum grip length- a reaction time? ForceThrow( gripEnt, qfalse ); @@ -7756,7 +8293,8 @@ void WP_ForcePowersUpdate( gentity_t *self, usercmd_t *ucmd ) if ( self->client->ps.forceJumpCharge ) {//let go of charge button, have charge //if leave the ground by some other means, cancel the force jump so we don't suddenly jump when we land. - if ( self->client->ps.groundEntityNum == ENTITYNUM_NONE ) + if ( self->client->ps.groundEntityNum == ENTITYNUM_NONE + && !PM_SwimmingAnim( self->client->ps.legsAnim ) ) {//FIXME: stop sound? //self->client->ps.forceJumpCharge = 0; //FIXME: actually, we want this to still be cleared... don't clear it if the button isn't being pressed, but clear it if not holding button and not on ground. diff --git a/code/game/wp_saber.h b/code/game/wp_saber.h index 59c915b..be46f1a 100644 --- a/code/game/wp_saber.h +++ b/code/game/wp_saber.h @@ -21,6 +21,8 @@ #define SES_HOVERING 2 #define SES_RETURNING 3 +#define SABER_EXTRAPOLATE_DIST 16.0f + #define SABER_MAX_DIST 400.0f #define SABER_MAX_DIST_SQUARED (SABER_MAX_DIST*SABER_MAX_DIST) diff --git a/code/ghoul2/g2.h b/code/ghoul2/g2.h index 1eb66cb..e56c12d 100644 --- a/code/ghoul2/g2.h +++ b/code/ghoul2/g2.h @@ -118,7 +118,6 @@ qboolean G2API_SetBoneAngles(CGhoul2Info *ghlInfo, const char *boneName, const v int blendTime = 0, int currentTime = 0); qboolean G2API_StopBoneAngles(CGhoul2Info *ghlInfo, const char *boneName); qboolean G2API_RemoveBone(CGhoul2Info *ghlInfo, const char *boneName); -void G2API_AnimateG2Models(CGhoul2Info_v &ghoul2, float speedVar); qboolean G2API_RemoveBolt(CGhoul2Info *ghlInfo, const int index); int G2API_AddBolt(CGhoul2Info *ghlInfo, const char *boneName); int G2API_AddBoltSurfNum(CGhoul2Info *ghlInfo, const int surfIndex); diff --git a/code/ghoul2/g2_api.cpp b/code/ghoul2/g2_api.cpp index 00f22d3..9a9ae81 100644 --- a/code/ghoul2/g2_api.cpp +++ b/code/ghoul2/g2_api.cpp @@ -27,9 +27,16 @@ #include "..\qcommon\MiniHeap.h" #endif + +#ifdef FINAL_BUILD +#define G2API_DEBUG (0) // please don't change this +#else #ifdef _DEBUG - #include -#endif //_DEBUG +#define G2API_DEBUG (1) +#else +#define G2API_DEBUG (0) // change this to test g2api in release +#endif +#endif using namespace std; @@ -47,7 +54,10 @@ static int G2TimeBases[NUM_G2T_TIME]; bool G2_TestModelPointers(CGhoul2Info *ghlInfo); -#if _DEBUG +#if G2API_DEBUG +#include //for isnan + + #define MAX_ERROR_PRINTS (3) class ErrorReporter { @@ -76,6 +86,124 @@ public: sprintf(mess,"****** %s Error Report End %d errors of %d kinds******\n",mName.c_str(),total,mErrors.size()); OutputDebugString(mess); } + int AnimTest(CGhoul2Info_v &ghoul2,const char *m,const char *, int line) + { + if (G2_SetupModelPointers(ghoul2)) + { + int i; + for (i=0; ianimModel->name); + strcpy(GLAName2,ghlInfo->aHeader->name); + strcpy(GLMName1,ghlInfo->mFileName); + strcpy(GLMName2,ghlInfo->currentModel->name); + + int numFramesInFile=ghlInfo->aHeader->numFrames; + + int numActiveBones=0; + for (i=0;imBlist.size();i++) + { + if (ghlInfo->mBlist[i].boneNumber!=-1) // slot used? + { + if (ghlInfo->mBlist[i].flags&BONE_ANIM_TOTAL) // anim on this? + { + numActiveBones++; + bool loop=!!(ghlInfo->mBlist[i].flags&BONE_ANIM_OVERRIDE_LOOP); + bool not_loop=!!(ghlInfo->mBlist[i].flags&BONE_ANIM_OVERRIDE); + + if (loop==not_loop) + { + Error("Unusual animation flags, should have some sort of override, but not both",1,0,line); + } + + bool freeze=(ghlInfo->mBlist[i].flags&BONE_ANIM_OVERRIDE_FREEZE) == BONE_ANIM_OVERRIDE_FREEZE; + + if (loop&&freeze) + { + Error("Unusual animation flags, loop and freeze",1,0,line); + } + bool no_lerp=!!(ghlInfo->mBlist[i].flags&BONE_ANIM_NO_LERP); + bool blend=!!(ghlInfo->mBlist[i].flags&BONE_ANIM_BLEND); + + + //comments according to jake + int startFrame=ghlInfo->mBlist[i].startFrame; // start frame for animation + int endFrame=ghlInfo->mBlist[i].endFrame; // end frame for animation NOTE anim actually ends on endFrame+1 + int startTime=ghlInfo->mBlist[i].startTime; // time we started this animation + int pauseTime=ghlInfo->mBlist[i].pauseTime; // time we paused this animation - 0 if not paused + float animSpeed=ghlInfo->mBlist[i].animSpeed; // speed at which this anim runs. 1.0f means full speed of animation incoming - ie if anim is 20hrtz, we run at 20hrts. If 5hrts, we run at 5 hrts + + float blendFrame=0.0f; // frame PLUS LERP value to blend + int blendLerpFrame=0; // frame to lerp the blend frame with. + + if (blend) + { + blendFrame=ghlInfo->mBlist[i].blendFrame; + blendLerpFrame=ghlInfo->mBlist[i].blendLerpFrame; + if (floor(blendFrame)<0.0f) + { + Error("negative blendFrame",1,0,line); + } + if (ceil(blendFrame)>=float(numFramesInFile)) + { + Error("blendFrame >= numFramesInFile",1,0,line); + } + if (blendLerpFrame<0) + { + Error("negative blendLerpFrame",1,0,line); + } + if (blendLerpFrame>=numFramesInFile) + { + Error("blendLerpFrame >= numFramesInFile",1,0,line); + } + } + if (startFrame<0) + { + Error("negative startFrame",1,0,line); + } + if (startFrame>=numFramesInFile) + { + Error("startFrame >= numFramesInFile",1,0,line); + } + if (endFrame<0) + { + Error("negative endFrame",1,0,line); + } + if (endFrame==0&&animSpeed>0.0f) + { + Error("Zero endFrame",1,0,line); + } + if (endFrame>numFramesInFile) + { + Error("endFrame > numFramesInFile",1,0,line); + } + // mikeg call out here for further checks. + ret=(int)startTime+(int)pauseTime+(int)no_lerp; // quiet VC. + } + } + } + return ret; + } int Error(const char *m,int kind,const char *, int line) { char mess[1000]; @@ -137,15 +265,17 @@ ErrorReporter &G2APIError() #define G2ERROR(exp,m) (void)( (exp) || (G2APIError().Error(m,0,__FILE__,__LINE__), 0) ) #define G2WARNING(exp,m) (void)( (exp) || (G2APIError().Error(m,1,__FILE__,__LINE__), 0) ) #define G2NOTE(exp,m) (void)( (exp) || (G2APIError().Error(m,2,__FILE__,__LINE__), 0) ) +#define G2ANIM(ghlInfo,m) (void)((G2APIError().AnimTest(ghlInfo,m,__FILE__,__LINE__), 0) ) #else #define G2ERROR(exp,m) ((void)0) #define G2WARNING(exp,m) ((void)0) #define G2NOTE(exp,m) ((void)0) +#define G2ANIM(ghlInfo,m) ((void)0) #endif -#ifdef _DEBUG +#if G2API_DEBUG void G2_Bone_Not_Found(const char *boneName,const char *modName) { G2ERROR(boneName,"NULL Bone Name"); @@ -174,6 +304,11 @@ void G2API_SetTime(int currentTime,int clock) Com_Printf("Set Time: before c%6d s%6d",G2TimeBases[1],G2TimeBases[0]); #endif G2TimeBases[clock]=currentTime; + if (G2TimeBases[1]>G2TimeBases[0]+200) + { + G2TimeBases[1]=0; // use server time instead + return; + } #if G2_DEBUG_TIME Com_Printf(" after c%6d s%6d\n",G2TimeBases[1],G2TimeBases[0]); #endif @@ -181,39 +316,11 @@ void G2API_SetTime(int currentTime,int clock) int G2API_GetTime(int argTime) // this may or may not return arg depending on ghoul2_time cvar { - static int LastTimeBase=0; - int ret=argTime; - int timeBase=0; - if (r_Ghoul2TimeBase&&r_Ghoul2TimeBase->integer>0&&r_Ghoul2TimeBase->integer<=NUM_G2T_TIME) + int ret=G2TimeBases[1]; + if ( !ret ) { - timeBase=r_Ghoul2TimeBase->integer; - ret=G2TimeBases[r_Ghoul2TimeBase->integer-1]; - if ( !ret ) - { - ret = G2TimeBases[0]; - } + ret = G2TimeBases[0]; } -#if _DEBUG - if (LastTimeBase!=timeBase) - { - LastTimeBase=timeBase; - if (timeBase==0) - { - Com_Printf("Ghoul2: Using argument time\n"); - } - if (timeBase==1) - { - Com_Printf("Ghoul2: Using server time\n"); - } - if (timeBase==2) - { - Com_Printf("Ghoul2: Using client time\n"); - } - } -#endif -#if G2_DEBUG_TIME - Com_Printf("Ghoul2: Get Time: in%6d c%6d s%6d returning %6d\n",argTime,G2TimeBases[1],G2TimeBases[0],ret); -#endif return ret; } @@ -263,7 +370,7 @@ public: mFreeIndecies.push_back(i); } } -#if _DEBUG +#if G2API_DEBUG ~Ghoul2InfoArray() { char mess[1000]; @@ -359,6 +466,34 @@ public: return mInfos[handle&G2_INDEX_MASK]; } +#if G2API_DEBUG + vector &GetDebug(int handle) + { + static vector null; + if (handle<=0||(handle&G2_INDEX_MASK)<0||(handle&G2_INDEX_MASK)>=MAX_G2_MODELS||mIds[handle&G2_INDEX_MASK]!=handle) + { + return *(vector *)0; // null reference, intentional + } + return mInfos[handle&G2_INDEX_MASK]; + } + void TestAllAnims() + { + int j; + for (j=0;j &ghoul2=mInfos[j]; + int i; + for (i=0; i &DebugG2Info(int handle) +#if G2API_DEBUG +vector &DebugG2Info(int handle) { - return TheGhoul2InfoArray().Get(handle); + return ((Ghoul2InfoArray *)(&TheGhoul2InfoArray()))->GetDebug(handle); } -const CGhoul2Info &DebugG2InfoI(int handle,int item) +CGhoul2Info &DebugG2InfoI(int handle,int item) { - return TheGhoul2InfoArray().Get(handle)[item]; + return ((Ghoul2InfoArray *)(&TheGhoul2InfoArray()))->GetDebug(handle)[item]; } +void TestAllGhoul2Anims() +{ + ((Ghoul2InfoArray *)(&TheGhoul2InfoArray()))->TestAllAnims(); +} + +#endif + + + + // this is the ONLY function to read entity states directly void G2API_CleanGhoul2Models(CGhoul2Info_v &ghoul2) { @@ -543,7 +689,7 @@ int G2API_GetSurfaceRenderStatus(CGhoul2Info *ghlInfo, const char *surfaceName) qboolean G2API_RemoveGhoul2Model(CGhoul2Info_v &ghlInfo, const int modelIndex) { // sanity check - if (!ghlInfo.size() || (ghlInfo.size() <= modelIndex) || (ghlInfo[modelIndex].mModelindex <0)) + if (!ghlInfo.size() || (ghlInfo.size() <= modelIndex) || modelIndex < 0 || (ghlInfo[modelIndex].mModelindex <0)) { // if we hit this assert then we are trying to delete a ghoul2 model on a ghoul2 instance that // one way or another is already gone. @@ -563,7 +709,7 @@ qboolean G2API_RemoveGhoul2Model(CGhoul2Info_v &ghlInfo, const int modelIndex) } -qboolean G2API_SetBoneAnimIndex(CGhoul2Info *ghlInfo, const int index, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime) +qboolean G2API_SetBoneAnimIndex(CGhoul2Info *ghlInfo, const int index, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int AcurrentTime, const float setFrame, const int blendTime) { qboolean ret=qfalse; if (G2_SetupModelPointers(ghlInfo)) @@ -591,14 +737,24 @@ qboolean G2API_SetBoneAnimIndex(CGhoul2Info *ghlInfo, const int index, const int if (index>=0&&indexmBlist.size()) { G2ERROR(ghlInfo->mBlist[index].boneNumber>=0,va("Bone Index is not Active (%s)",ghlInfo->mFileName)); + int currentTime=G2API_GetTime(AcurrentTime); +#if 0 + /* + if ( ge->ValidateAnimRange( startFrame, endFrame, animSpeed ) == -1 ) + { + int wtf = 1; + } + */ +#endif ret=G2_Set_Bone_Anim_Index(ghlInfo->mBlist, index, startFrame, endFrame, flags, animSpeed, currentTime, setFrame, blendTime,ghlInfo->aHeader->numFrames); + G2ANIM(ghlInfo,"G2API_SetBoneAnimIndex"); } } G2WARNING(ret,va("G2API_SetBoneAnimIndex Failed (%s)",ghlInfo->mFileName)); return ret; } -qboolean G2API_SetBoneAnim(CGhoul2Info *ghlInfo, const char *boneName, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime) +qboolean G2API_SetBoneAnim(CGhoul2Info *ghlInfo, const char *boneName, const int startFrame, const int endFrame, const int flags, const float animSpeed, const int AcurrentTime, const float setFrame, const int blendTime) { qboolean ret=qfalse; G2ERROR(boneName,"NULL boneName"); @@ -623,7 +779,9 @@ qboolean G2API_SetBoneAnim(CGhoul2Info *ghlInfo, const char *boneName, const int *(float *)&setFrame=0.0f; } ghlInfo->mSkelFrameNum = 0; + int currentTime=G2API_GetTime(AcurrentTime); ret=G2_Set_Bone_Anim(ghlInfo, ghlInfo->mBlist, boneName, startFrame, endFrame, flags, animSpeed, currentTime, setFrame, blendTime); + G2ANIM(ghlInfo,"G2API_SetBoneAnim"); } G2WARNING(ret,"G2API_SetBoneAnim Failed"); return ret; @@ -651,7 +809,7 @@ qboolean G2API_GetBoneAnimIndex(CGhoul2Info *ghlInfo, const int iBoneIndex, cons if (G2_SetupModelPointers(ghlInfo)) { int currentTime=G2API_GetTime(AcurrentTime); - G2ERROR(iBoneIndex>=0&&iBoneIndexmBlist.size(),va("Bad Bone Index (%d:%s)",iBoneIndex,ghlInfo->mFileName)); + G2NOTE(iBoneIndex>=0&&iBoneIndexmBlist.size(),va("Bad Bone Index (%d:%s)",iBoneIndex,ghlInfo->mFileName)); if (iBoneIndex>=0&&iBoneIndexmBlist.size()) { G2NOTE(ghlInfo->mBlist[iBoneIndex].flags & (BONE_ANIM_OVERRIDE_LOOP | BONE_ANIM_OVERRIDE),"GetBoneAnim on non-animating bone."); @@ -676,6 +834,7 @@ qboolean G2API_GetBoneAnimIndex(CGhoul2Info *ghlInfo, const int iBoneIndex, cons G2ERROR(((int)(*currentFrame))aHeader->numFrames,"returning currentframe>=numframes"); *endFrame=ef; *startFrame=sf; + G2ANIM(ghlInfo,"G2API_GetBoneAnimIndex"); } } } @@ -698,6 +857,7 @@ qboolean G2API_GetAnimRange(CGhoul2Info *ghlInfo, const char *boneName, int *sta if (boneName&&G2_SetupModelPointers(ghlInfo)) { ret=G2_Get_Bone_Anim_Range(ghlInfo, ghlInfo->mBlist, boneName, startFrame, endFrame); + G2ANIM(ghlInfo,"G2API_GetAnimRange"); } // looks like the game checks the return value // G2WARNING(ret,"G2API_GetAnimRange Failed"); @@ -713,6 +873,7 @@ qboolean G2API_GetAnimRangeIndex(CGhoul2Info *ghlInfo, const int boneIndex, int if (boneIndex>=0&&boneIndexmBlist.size()) { ret=G2_Get_Bone_Anim_Range_Index(ghlInfo->mBlist, boneIndex, startFrame, endFrame); + G2ANIM(ghlInfo,"G2API_GetAnimRange"); } } // looks like the game checks the return value @@ -728,6 +889,7 @@ qboolean G2API_PauseBoneAnim(CGhoul2Info *ghlInfo, const char *boneName, const i { int currentTime=G2API_GetTime(AcurrentTime); ret=G2_Pause_Bone_Anim(ghlInfo, ghlInfo->mBlist, boneName, currentTime); + G2ANIM(ghlInfo,"G2API_PauseBoneAnim"); } G2NOTE(ret,"G2API_PauseBoneAnim Failed"); return ret; @@ -743,6 +905,7 @@ qboolean G2API_PauseBoneAnimIndex(CGhoul2Info *ghlInfo, const int boneIndex, con if (boneIndex>=0&&boneIndexmBlist.size()) { ret=G2_Pause_Bone_Anim_Index(ghlInfo->mBlist, boneIndex, currentTime,ghlInfo->aHeader->numFrames); + G2ANIM(ghlInfo,"G2API_PauseBoneAnimIndex"); } } G2WARNING(ret,"G2API_PauseBoneAnimIndex Failed"); @@ -771,6 +934,7 @@ qboolean G2API_StopBoneAnimIndex(CGhoul2Info *ghlInfo, const int index) if (index>=0&&indexmBlist.size()) { ret=G2_Stop_Bone_Anim_Index(ghlInfo->mBlist, index); + G2ANIM(ghlInfo,"G2API_StopBoneAnimIndex"); } } //G2WARNING(ret,"G2API_StopBoneAnimIndex Failed"); @@ -784,6 +948,7 @@ qboolean G2API_StopBoneAnim(CGhoul2Info *ghlInfo, const char *boneName) if (boneName&&G2_SetupModelPointers(ghlInfo)) { ret=G2_Stop_Bone_Anim(ghlInfo, ghlInfo->mBlist, boneName); + G2ANIM(ghlInfo,"G2API_StopBoneAnim"); } G2WARNING(ret,"G2API_StopBoneAnim Failed"); return ret; @@ -901,24 +1066,14 @@ qboolean G2API_RemoveBone(CGhoul2Info *ghlInfo, const char *boneName) // ensure we flush the cache ghlInfo->mSkelFrameNum = 0; ret=G2_Remove_Bone(ghlInfo, ghlInfo->mBlist, boneName); + G2ANIM(ghlInfo,"G2API_RemoveBone"); } G2WARNING(ret,"G2API_RemoveBone Failed"); return ret; } -void G2API_AnimateG2Models(CGhoul2Info_v &ghoul2, float speedVar) +void G2API_AnimateG2Models(CGhoul2Info_v &, float) { - int model; - if (ghoul2.IsValid()) - { - for (model=0; model< ghoul2.size(); model++) - { - if (ghoul2[model].mModel) - { - G2_Animate_Bone_List(ghoul2, speedVar, model); - } - } - } } qboolean G2API_RemoveBolt(CGhoul2Info *ghlInfo, const int index) @@ -1076,7 +1231,7 @@ qboolean G2API_GetBoltMatrix(CGhoul2Info_v &ghoul2, const int modelIndex, const VectorNormalize((float*)&bolt.matrix[2]); Multiply_3x4Matrix(matrix, &worldMatrix, &bolt); -#ifdef _DEBUG +#if G2API_DEBUG for ( int i = 0; i < 3; i++ ) { for ( int j = 0; j < 4; j++ ) @@ -1085,6 +1240,7 @@ qboolean G2API_GetBoltMatrix(CGhoul2Info_v &ghoul2, const int modelIndex, const } } #endif// _DEBUG + G2ANIM(ghlInfo,"G2API_GetBoltMatrix"); return qtrue; } } @@ -1218,6 +1374,7 @@ void G2API_CollisionDetect(CCollisionRecord *collRecMap, CGhoul2Info_v &ghoul2, // now sort the resulting array of collision records so they are distance ordered qsort( collRecMap, MAX_G2_COLLISIONS, sizeof( CCollisionRecord ), QsortDistance ); + G2ANIM(ghoul2,"G2API_CollisionDetect"); } } @@ -1295,6 +1452,8 @@ void G2API_CopyGhoul2Instance(CGhoul2Info_v &ghoul2From, CGhoul2Info_v &ghoul2To if (ghoul2From.IsValid()) { ghoul2To.DeepCopy(ghoul2From); + G2ANIM(ghoul2From,"G2API_CopyGhoul2Instance (source)"); + G2ANIM(ghoul2To,"G2API_CopyGhoul2Instance (dest)"); } } @@ -1366,6 +1525,7 @@ int G2API_GetBoneIndex(CGhoul2Info *ghlInfo, const char *boneName, qboolean bAdd if (boneName&&G2_SetupModelPointers(ghlInfo)) { ret=G2_Get_Bone_Index(ghlInfo, boneName, bAddIfNotFound); + G2ANIM(ghlInfo,"G2API_GetBoneIndex"); } G2NOTE(ret>=0,"G2API_GetBoneIndex Failed"); return ret; @@ -1373,12 +1533,14 @@ int G2API_GetBoneIndex(CGhoul2Info *ghlInfo, const char *boneName, qboolean bAdd qboolean G2API_SaveGhoul2Models(CGhoul2Info_v &ghoul2, char **buffer, int *size) { + G2ANIM(ghoul2,"G2API_SaveGhoul2Models"); return G2_SaveGhoul2Models(ghoul2, buffer, size); } void G2API_LoadGhoul2Models(CGhoul2Info_v &ghoul2, char *buffer) { G2_LoadGhoul2Model(ghoul2, buffer); + G2ANIM(ghoul2,"G2API_LoadGhoul2Models"); // G2ERROR(ghoul2.IsValid(),"Invalid ghlInfo after load"); } diff --git a/code/ghoul2/g2_bones.cpp b/code/ghoul2/g2_bones.cpp index e9595ed..92a5c79 100644 --- a/code/ghoul2/g2_bones.cpp +++ b/code/ghoul2/g2_bones.cpp @@ -21,6 +21,7 @@ #include "G2.h" #endif +extern cvar_t *r_Ghoul2BlendMultiplier; void G2_Bone_Not_Found(const char *boneName,const char *modName); @@ -62,6 +63,8 @@ int G2_Find_Bone(CGhoul2Info *ghlInfo, boneInfo_v &blist, const char *boneName) return -1; } +#define DEBUG_G2_BONES (0) + // we need to add a bone to the list - find a free one and see if we can find a corresponding bone in the gla file int G2_Add_Bone (const model_t *mod, boneInfo_v &blist, const char *boneName) { @@ -102,6 +105,16 @@ int G2_Add_Bone (const model_t *mod, boneInfo_v &blist, const char *boneName) // if name is the same, we found it if (!stricmp(skel->name, boneName)) { +#if DEBUG_G2_BONES + { + char mess[1000]; + sprintf(mess,"ADD BONE1 blistIndex=%3d physicalIndex=%3d %s\n", + i, + x, + boneName); + OutputDebugString(mess); + } +#endif return i; } } @@ -110,6 +123,16 @@ int G2_Add_Bone (const model_t *mod, boneInfo_v &blist, const char *boneName) // if we found an entry that had a -1 for the bonenumber, then we hit a bone slot that was empty blist[i].boneNumber = x; blist[i].flags = 0; +#if DEBUG_G2_BONES + { + char mess[1000]; + sprintf(mess,"ADD BONE1 blistIndex=%3d physicalIndex=%3d %s\n", + i, + x, + boneName); + OutputDebugString(mess); + } +#endif return i; } } @@ -118,6 +141,16 @@ int G2_Add_Bone (const model_t *mod, boneInfo_v &blist, const char *boneName) tempBone.boneNumber = x; tempBone.flags = 0; blist.push_back(tempBone); +#if DEBUG_G2_BONES + { + char mess[1000]; + sprintf(mess,"ADD BONE1 blistIndex=%3d physicalIndex=%3d %s\n", + blist.size()-1, + x, + boneName); + OutputDebugString(mess); + } +#endif return blist.size()-1; } @@ -375,6 +408,8 @@ qboolean G2_Remove_Bone (CGhoul2Info *ghlInfo, boneInfo_v &blist, const char *bo return G2_Remove_Bone_Index(blist, index); } +#define DEBUG_PCJ (0) + // Given a model handle, and a bone name, we want to set angles specifically for overriding qboolean G2_Set_Bone_Angles_Index(CGhoul2Info *ghlInfo, boneInfo_v &blist, const int index, const float *angles, const int flags, const Eorientations yaw, @@ -384,8 +419,6 @@ qboolean G2_Set_Bone_Angles_Index(CGhoul2Info *ghlInfo, boneInfo_v &blist, const if (index<0||(index >= blist.size()) || (blist[index].boneNumber == -1)) { - // we are attempting to set a bone override that doesn't exist -// assert(0); return qfalse; } @@ -394,7 +427,9 @@ qboolean G2_Set_Bone_Angles_Index(CGhoul2Info *ghlInfo, boneInfo_v &blist, const blist[index].flags |= flags; blist[index].boneBlendStart = currentTime; blist[index].boneBlendTime = blendTime; - +#if DEBUG_PCJ + OutputDebugString(va("%8x %2d %6d (%6.2f,%6.2f,%6.2f) %d %d %d %d\n",(int)ghlInfo,index,currentTime,angles[0],angles[1],angles[2],yaw,pitch,roll,flags)); +#endif G2_Generate_Matrix(ghlInfo->animModel, blist, index, angles, flags, yaw, pitch, roll); return qtrue; @@ -467,18 +502,30 @@ qboolean G2_Set_Bone_Angles_Matrix(CGhoul2Info *ghlInfo, boneInfo_v &blist, cons return qfalse; } +#define DEBUG_G2_TIMING (0) + // given a model, bone name, a bonelist, a start/end frame number, a anim speed and some anim flags, set up or modify an existing bone entry for a new set of anims qboolean G2_Set_Bone_Anim_Index(boneInfo_v &blist, const int index, const int startFrame, - const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int blendTime,int numFrames) + const int endFrame, const int flags, const float animSpeed, const int currentTime, const float setFrame, const int AblendTime,int numFrames) { int modFlags = flags; - -#if G2_DEBUG_TIMING - if (doTiming) + int blendTime=AblendTime; + + if (r_Ghoul2BlendMultiplier) { - Com_Printf("anim %d %5d %5d %5d %5d %3.2f %3.2f %3.2f\n",tr.refdef.time,TB.currentFrame,TB.newFrame,(int)TB.blendFrame,TB.blendOldFrame,TB.backlerp,float(TB.blendFrame - (int)TB.blendFrame),TB.blendLerp); + if (r_Ghoul2BlendMultiplier->value!=1.0f) + { + if (r_Ghoul2BlendMultiplier->value<=0.0f) + { + modFlags&=~BONE_ANIM_BLEND; + } + else + { + blendTime=ceil(float(AblendTime)*r_Ghoul2BlendMultiplier->value); + } + } } -#endif + if (index<0||index >= blist.size()||blist[index].boneNumber<0) { @@ -493,7 +540,7 @@ qboolean G2_Set_Bone_Anim_Index(boneInfo_v &blist, const int index, const int st // since we already existed, we can check to see if we want to start some blending - if (flags & BONE_ANIM_BLEND) + if (modFlags & BONE_ANIM_BLEND) { float currentFrame, animSpeed; int startFrame, endFrame, flags; @@ -507,38 +554,46 @@ qboolean G2_Set_Bone_Anim_Index(boneInfo_v &blist, const int index, const int st } else { - blist[index].blendFrame = currentFrame; - blist[index].blendLerpFrame = currentFrame+1; - - // cope with if the lerp frame is actually off the end of the anim - if (blist[index].blendFrame >= blist[index].endFrame ) + if (animSpeed<0.0f) { - // we only want to lerp with the first frame of the anim if we are looping - if (blist[index].flags & BONE_ANIM_OVERRIDE_LOOP) - { - blist[index].blendFrame = blist[index].startFrame; - } - // if we intend to end this anim or freeze after this, then just keep on the last frame - else - { - assert(blist[index].endFrame>0); - blist[index].blendFrame = blist[index].endFrame -1; - } + blist[index].blendFrame = floor(currentFrame); + blist[index].blendLerpFrame = floor(currentFrame); } - - // cope with if the lerp frame is actually off the end of the anim - if (blist[index].blendLerpFrame >= blist[index].endFrame ) + else { - // we only want to lerp with the first frame of the anim if we are looping - if (blist[index].flags & BONE_ANIM_OVERRIDE_LOOP) + blist[index].blendFrame = currentFrame; + blist[index].blendLerpFrame = currentFrame+1; + + // cope with if the lerp frame is actually off the end of the anim + if (blist[index].blendFrame >= blist[index].endFrame ) { - blist[index].blendLerpFrame = blist[index].startFrame; + // we only want to lerp with the first frame of the anim if we are looping + if (blist[index].flags & BONE_ANIM_OVERRIDE_LOOP) + { + blist[index].blendFrame = blist[index].startFrame; + } + // if we intend to end this anim or freeze after this, then just keep on the last frame + else + { + assert(blist[index].endFrame>0); + blist[index].blendFrame = blist[index].endFrame -1; + } } - // if we intend to end this anim or freeze after this, then just keep on the last frame - else + + // cope with if the lerp frame is actually off the end of the anim + if (blist[index].blendLerpFrame >= blist[index].endFrame ) { - assert(blist[index].endFrame>0); - blist[index].blendLerpFrame = blist[index].endFrame - 1; + // we only want to lerp with the first frame of the anim if we are looping + if (blist[index].flags & BONE_ANIM_OVERRIDE_LOOP) + { + blist[index].blendLerpFrame = blist[index].startFrame; + } + // if we intend to end this anim or freeze after this, then just keep on the last frame + else + { + assert(blist[index].endFrame>0); + blist[index].blendLerpFrame = blist[index].endFrame - 1; + } } } // set the amount of time it's going to take to blend this anim with the last frame of the last one @@ -553,7 +608,7 @@ qboolean G2_Set_Bone_Anim_Index(boneInfo_v &blist, const int index, const int st blist[index].blendTime = 0; // we aren't blending, so remove the option to do so modFlags &= ~BONE_ANIM_BLEND; - return qfalse; + //return qfalse; } } else @@ -574,15 +629,60 @@ qboolean G2_Set_Bone_Anim_Index(boneInfo_v &blist, const int index, const int st // start up the animation:) if (setFrame != -1) { - blist[index].lastTime = blist[index].startTime = (currentTime - (((setFrame - (float)startFrame) * 50.0)/ animSpeed)); + blist[index].startTime = (currentTime - (((setFrame - (float)startFrame) * 50.0)/ animSpeed)); +/* + setFrame = bone.startFrame + ((currentTime - bone.startTime) / 50.0f * animSpeed); + + (setFrame - bone.startFrame) = ((currentTime - bone.startTime) / 50.0f * animSpeed); + + (setFrame - bone.startFrame)*50/animSpeed - currentTime = - bone.startTime; + + currentTime - (setFrame - bone.startFrame)*50/animSpeed = bone.startTime; +*/ } else { - blist[index].lastTime = blist[index].startTime = currentTime; + blist[index].startTime = currentTime; } blist[index].flags &= ~(BONE_ANIM_TOTAL); blist[index].flags |= modFlags; +#if DEBUG_G2_TIMING + if (index>-10) + { + const boneInfo_t &bone=blist[index]; + char mess[1000]; + if (bone.flags&BONE_ANIM_BLEND) + { + sprintf(mess,"sab[%2d] %5d %5d (%5d-%5d) %4.2f %4x bt(%5d-%5d) %7.2f %5d\n", + index, + currentTime, + bone.startTime, + bone.startFrame, + bone.endFrame, + bone.animSpeed, + bone.flags, + bone.blendStart, + bone.blendStart+bone.blendTime, + bone.blendFrame, + bone.blendLerpFrame + ); + } + else + { + sprintf(mess,"saa[%2d] %5d %5d (%5d-%5d) %4.2f %4x\n", + index, + currentTime, + bone.startTime, + bone.startFrame, + bone.endFrame, + bone.animSpeed, + bone.flags + ); + } + OutputDebugString(mess); + } +#endif // assert(blist[index].startTime <= currentTime); return qtrue; @@ -624,16 +724,52 @@ qboolean G2_Set_Bone_Anim(CGhoul2Info *ghlInfo, boneInfo_v &blist, const char *b // start up the animation:) if (setFrame != -1) { - blist[index].lastTime = blist[index].startTime = (currentTime - (((setFrame - (float)startFrame) * 50.0)/ animSpeed)); + blist[index].startTime = (currentTime - (((setFrame - (float)startFrame) * 50.0)/ animSpeed)); } else { - blist[index].lastTime = blist[index].startTime = currentTime; + blist[index].startTime = currentTime; } blist[index].flags &= ~BONE_ANIM_TOTAL; blist[index].flags |= modFlags; assert(blist[index].blendFrame>=0&&blist[index].blendFrameaHeader->numFrames); assert(blist[index].blendLerpFrame>=0&&blist[index].blendLerpFrameaHeader->numFrames); +#if DEBUG_G2_TIMING + if (index>-10) + { + const boneInfo_t &bone=blist[index]; + char mess[1000]; + if (bone.flags&BONE_ANIM_BLEND) + { + sprintf(mess,"s2b[%2d] %5d %5d (%5d-%5d) %4.2f %4x bt(%5d-%5d) %7.2f %5d\n", + index, + currentTime, + bone.startTime, + bone.startFrame, + bone.endFrame, + bone.animSpeed, + bone.flags, + bone.blendStart, + bone.blendStart+bone.blendTime, + bone.blendFrame, + bone.blendLerpFrame + ); + } + else + { + sprintf(mess,"s2a[%2d] %5d %5d (%5d-%5d) %4.2f %4x\n", + index, + currentTime, + bone.startTime, + bone.startFrame, + bone.endFrame, + bone.animSpeed, + bone.flags + ); + } + OutputDebugString(mess); + } +#endif return qtrue; } @@ -847,118 +983,6 @@ qboolean G2_Stop_Bone_Angles(CGhoul2Info *ghlInfo, boneInfo_v &blist, const char return qfalse; } - -// actually walk the bone list and update each and every bone if we have ended an animation for them. -void G2_Animate_Bone_List(CGhoul2Info_v &ghoul2, const int currentTime, const int index ) -{ - int i; - assert(index>=0&&index 0.0f) && (newFrame_g > endFrame - 1)) || - ((animSpeed < 0.0f) && (newFrame_g < endFrame + 1))) - { - // yep - decide what to do - if (blist[i].flags & BONE_ANIM_OVERRIDE_LOOP) - { - // get our new animation frame back within the bounds of the animation set - if (animSpeed < 0.0f) - { - if (newFrame_g <= endFrame) - { - newFrame_g=endFrame+fmod(newFrame_g-endFrame,animSize)-animSize; - } - // figure out new start time - float frameTime = newFrame_g - blist[i].startFrame ; - blist[i].startTime = currentTime - (int)((frameTime / animSpeed) * 50.0f); - assert(blist[i].startTime <= currentTime); - blist[i].lastTime = blist[i].startTime; - } - else - { - if (newFrame_g >= endFrame) - { - newFrame_g=endFrame+fmod(newFrame_g-endFrame,animSize)-animSize; - } - // figure out new start time - float frameTime = newFrame_g - blist[i].startFrame ; - blist[i].startTime = currentTime - (int)((frameTime / animSpeed) * 50.0f); - assert(blist[i].startTime <= currentTime); - blist[i].lastTime = blist[i].startTime; - } - } - else - { - if ((blist[i].flags & (BONE_ANIM_OVERRIDE_FREEZE)) != (BONE_ANIM_OVERRIDE_FREEZE)) -// if (((blist[i].flags & (BONE_ANIM_OVERRIDE_DEFAULT)) == (BONE_ANIM_OVERRIDE_DEFAULT))|| -// ((blist[i].flags & (BONE_ANIM_OVERRIDE_FREEZE)) == (BONE_ANIM_OVERRIDE_FREEZE))) - { - // if we are supposed to reset the default anim, then do so - if (blist[i].flags & (BONE_ANIM_OVERRIDE_DEFAULT)) - { - if (animSpeed > 0.0f) - { - ghoul2[index].mAnimFrameDefault = blist[i].endFrame -1; - } - else - { - ghoul2[index].mAnimFrameDefault = blist[i].endFrame + 1; - } - } - // nope, just stop it. And remove the bone if possible - G2_Stop_Bone_Index(blist, i, (BONE_ANIM_TOTAL)); - } - } - } - } - } - // also, lets check to see if this bone might have been doing a bone override that we need to dispose of? - // we might have deleted this bone? - if ((blist.size() > i) && (blist[i].flags & BONE_ANGLES_REPLACE_TO_ANIM)) - { - // are we done yet? - if ((blist[i].boneBlendTime + blist[i].boneBlendStart) < currentTime) - { - G2_Stop_Bone_Index(blist, i, (BONE_ANGLES_TOTAL)); - } - } - } - } -} - // set the bone list to all unused so the bone transformation routine ignores it. void G2_Init_Bone_List(boneInfo_v &blist) { diff --git a/code/ghoul2/g2_misc.cpp b/code/ghoul2/g2_misc.cpp index 6db93a1..4b463b5 100644 --- a/code/ghoul2/g2_misc.cpp +++ b/code/ghoul2/g2_misc.cpp @@ -248,10 +248,11 @@ void R_TransformEachSurface( const mdxmSurface_t *surface, vec3_t scale, CMiniHe const int iNumWeights = G2_GetVertWeights( v ); + float fTotalWeight = 0.0f; for ( k = 0 ; k < iNumWeights ; k++ ) { int iBoneIndex = G2_GetVertBoneIndex( v, k ); - float fBoneWeight = G2_GetVertBoneWeight( v, k ); + float fBoneWeight = G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights ); const mdxaBone_t &bone=EvalBoneCache(piBoneReferences[iBoneIndex],boneCache); @@ -290,10 +291,11 @@ void R_TransformEachSurface( const mdxmSurface_t *surface, vec3_t scale, CMiniHe const int iNumWeights = G2_GetVertWeights( v ); + float fTotalWeight = 0.0f; for ( k = 0 ; k < iNumWeights ; k++ ) { int iBoneIndex = G2_GetVertBoneIndex( v, k ); - float fBoneWeight = G2_GetVertBoneWeight( v, k ); + float fBoneWeight = G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights ); const mdxaBone_t &bone=EvalBoneCache(piBoneReferences[iBoneIndex],boneCache); diff --git a/code/ghoul2/vssver.scc b/code/ghoul2/vssver.scc new file mode 100644 index 0000000..8933594 Binary files /dev/null and b/code/ghoul2/vssver.scc differ diff --git a/code/icarus/Instance.cpp b/code/icarus/Instance.cpp index 33a5372..e2415ee 100644 --- a/code/icarus/Instance.cpp +++ b/code/icarus/Instance.cpp @@ -171,6 +171,9 @@ DeleteSequencer void ICARUS_Instance::DeleteSequencer( CSequencer *sequencer ) { + // added 2/12/2 to properly delete blocks that were passed to the task manager + sequencer->Recall(); + CTaskManager *taskManager = sequencer->GetTaskManager(); if ( taskManager ) diff --git a/code/icarus/Interface.cpp b/code/icarus/Interface.cpp new file mode 100644 index 0000000..6e5c1fa --- /dev/null +++ b/code/icarus/Interface.cpp @@ -0,0 +1,18 @@ +// ICARUS Engine Interface File +// +// This file is the only section of the ICARUS systems that +// is not directly portable from engine to engine. +// +// -- jweier + +#include "Interface.h" + +void Interface_Init( interface_export_t *pe ) +{ + + //TODO: This is where you link up all your functions to the engine + + //Example: + // + // pe->I_GetEntityByName = ENGINE_GetEntityByName; +} diff --git a/code/icarus/Interpreter.cpp b/code/icarus/Interpreter.cpp new file mode 100644 index 0000000..e046015 --- /dev/null +++ b/code/icarus/Interpreter.cpp @@ -0,0 +1,2506 @@ +// Token Interpreter +// +// -- jweier + +#include //For getcwd() +#include //For getch() +#include + +#include "Tokenizer.h" +#include "BlockStream.h" +#include "Interpreter.h" + +/* +=================================================================================================== + + Table Definitions + +=================================================================================================== +*/ + +//FIXME: The following tables should be passed in to the interpreter for flexibility + +//Symbol Table + +keywordArray_t CInterpreter::m_symbolKeywords[] = +{ + //Blocks + "{", TK_BLOCK_START, + "}", TK_BLOCK_END, + + //Vectors + "<", TK_VECTOR_START, + ">", TK_VECTOR_END, + + //Groups + "(", TK_OPEN_PARENTHESIS, + ")", TK_CLOSED_PARENTHESIS, + + "=", TK_EQUALS, + "!", TK_NOT, + + //End + "", TK_EOF, +}; + +keywordArray_t CInterpreter::m_conditionalKeywords[] = +{ + "", TK_EOF, +}; + +//ID Table + +keywordArray_t CInterpreter::m_IDKeywords[] = +{ + "AFFECT", ID_AFFECT, + "SOUND", ID_SOUND, + "MOVE", ID_MOVE, + "ROTATE", ID_ROTATE, + "WAIT", ID_WAIT, + "SET", ID_SET, + "LOOP", ID_LOOP, + "PRINT", ID_PRINT, + "TAG", ID_TAG, + "USE", ID_USE, + "FLUSH", ID_FLUSH, + "RUN", ID_RUN, + "KILL", ID_KILL, + "REMOVE", ID_REMOVE, + "CAMERA", ID_CAMERA, + "GET", ID_GET, + "RANDOM", ID_RANDOM, + "IF", ID_IF, + "ELSE", ID_ELSE, + "REM", ID_REM, + "FLOAT", TK_FLOAT, + "VECTOR", TK_VECTOR, + "STRING", TK_STRING, + "TASK", ID_TASK, + "DO", ID_DO, + "DECLARE", ID_DECLARE, + "FREE", ID_FREE, + "DOWAIT", ID_DOWAIT, + "SIGNAL", ID_SIGNAL, + "WAITSIGNAL", ID_WAITSIGNAL, + "PLAY", ID_PLAY, + + "", ID_EOF, +}; + +//Type Table + +keywordArray_t CInterpreter::m_typeKeywords[] = +{ + //Set types + "ANGLES", TYPE_ANGLES, + "ORIGIN", TYPE_ORIGIN, + + //Affect types + "INSERT", TYPE_INSERT, + "FLUSH", TYPE_FLUSH, + + //Get types + "FLOAT", TK_FLOAT, + "INT", TK_INT, + "VECTOR", TK_VECTOR, + "STRING", TK_STRING, + + "PAN", TYPE_PAN, + "ZOOM", TYPE_ZOOM, + "MOVE", TYPE_MOVE, + "FADE", TYPE_FADE, + "PATH", TYPE_PATH, + "ENABLE", TYPE_ENABLE, + "DISABLE", TYPE_DISABLE, + "SHAKE", TYPE_SHAKE, + "ROLL", TYPE_ROLL, + "TRACK", TYPE_TRACK, + "FOLLOW", TYPE_FOLLOW, + "DISTANCE", TYPE_DISTANCE, + + //End + "", TYPE_EOF, +}; + + +/* +=================================================================================================== + + Constructor / Destructor + +=================================================================================================== +*/ + +CInterpreter::CInterpreter() +{ +} + +CInterpreter::~CInterpreter() +{ +} + +/* +=================================================================================================== + + Error Handling + +=================================================================================================== +*/ + +int CInterpreter::Error( char *format, ... ) +{ + va_list argptr; + char *error_file, error_msg[1024]="", work_dir[1024]="", out_msg[1024]=""; + int error_line = m_iCurrentLine; // m_tokenizer->GetCurLine(); + + m_tokenizer->GetCurFilename( &error_file ); + if (!error_file) + { + // 99% of the time we'll get here now, because of pushed parse streams + // + error_file = (char *)m_sCurrentFile.c_str(); + } + + va_start (argptr, format); + vsprintf (error_msg, format, argptr); + va_end (argptr); + + strcpy((char *) work_dir, getcwd( (char *) &work_dir, 1024 ) ); + + if (error_file[1] == ':') + { + sprintf((char *) out_msg, "%s (%d) : error: %s\n", error_file, error_line, error_msg); + } + else + { + sprintf((char *) out_msg, "%s\\%s (%d) : error: %s\n", work_dir, error_file, error_line, error_msg); + } + + if (m_sCurrentLine.length()) + { + strcat(out_msg, "\nLine:\n\n"); + strcat(out_msg, m_sCurrentLine.c_str()); + strcat(out_msg, "\n"); + } + +#ifdef __POP_UPS__ + + MessageBox( NULL, out_msg, "Error", MB_OK ); + +#else + + printf(out_msg); + +#endif + + // A bit of kludge code that takes care of the case where there's some garbage at the beginning of the file + // before any blocks are read as valid. This is needed because ints are incapable of containing 0 + // + // This'll mean that technically it's saying block 1 is wrong, rather than the one in between them, but I can + // live with that. + // + if (m_iBadCBlockNumber == 0) + { + m_iBadCBlockNumber = 1; + } + return false; +} + +/* +=================================================================================================== + + Local Variable Functions + +=================================================================================================== +*/ + +/* +------------------------- +InitVars +------------------------- +*/ + +void CInterpreter::InitVars( void ) +{ + m_vars.clear(); + m_varMap.clear(); +} + +/* +------------------------- +FreeVars +------------------------- +*/ + +void CInterpreter::FreeVars( void ) +{ + variable_v::iterator vi; + + for ( vi = m_vars.begin(); vi != m_vars.end(); vi++ ) + { + delete (*vi); + } + + InitVars(); +} + +/* +------------------------- +AddVar +------------------------- +*/ + +variable_t *CInterpreter::AddVar( const char *name, int type ) +{ + variable_t *var; + + var = new variable_t; + + if ( var == NULL ) + return NULL; + + //Specify the type + var->type = type; + + //Retain the name internally + strncpy( (char *) var->name, name, MAX_VAR_NAME ); + + //Associate it + m_varMap[ name ] = var; + + return var; +} + +/* +------------------------- +FindVar +------------------------- +*/ + +variable_t *CInterpreter::FindVar( const char *name ) +{ + variable_m::iterator vmi; + + vmi = m_varMap.find( name ); + + if ( vmi == m_varMap.end() ) + return NULL; + + return (*vmi).second; +} + +/* +------------------------- +GetVariable +------------------------- +*/ + +int CInterpreter::GetVariable( int type ) +{ + const char *varName; + variable_t *var; + CToken *token; + + //Get the variable's name + token = m_tokenizer->GetToken( 0, 0 ); + varName = token->GetStringValue(); + + //See if we already have a variable by this name + var = FindVar( varName ); + + //Variable names must be unique on creation + if ( var ) + return Error( "\"%s\" : already exists\n", varName ); + + //Add the variable + AddVar( varName, type ); + + //Insert the variable into the stream + + CBlock block; + + block.Create( TYPE_VARIABLE ); + block.Write( TK_FLOAT, (float) type ); + block.Write( TK_STRING, varName ); + + m_blockStream->WriteBlock( &block ); + + token->Delete(); + + return true; +} + +/* +=================================================================================================== + + ID Table Functions + +=================================================================================================== +*/ + +int CInterpreter::GetVector( CBlock *block ) +{ + //Look for a tag + if ( MatchTag() ) + { + return GetTag( block ); + } + + //Look for a get + if ( MatchGet() ) + { + return GetGet( block ); + } + + if ( Match( TK_VECTOR_START ) ) + { + //Get the vector + block->Write( TK_VECTOR, (float) TK_VECTOR ); + + for (int i=0; i<3; i++) + GetFloat( block ); + + if (!Match( TK_VECTOR_END )) + { + return Error("syntax error : expected end of vector"); + } + + return true; + } + + return false; +} + +/* +=================================================================================================== + + MatchTag() + + Attempts to match to a tag identifier. + +=================================================================================================== +*/ + +int CInterpreter::MatchTag( void ) +{ + CToken *token; + const char *idName; + int id; + + token = m_tokenizer->GetToken( 0, 0 ); + idName = token->GetStringValue(); + id = FindSymbol( idName, m_IDKeywords ); + + if ( id != ID_TAG ) + { + //Return the token + m_tokenizer->PutBackToken( token ); + return false; + } + + token->Delete(); + return true; +} + +/* +=================================================================================================== + + MatchGet() + + Attempts to match to a get identifier. + +=================================================================================================== +*/ + +int CInterpreter::MatchGet( void ) +{ + CToken *token; + const char *idName; + int id; + + token = m_tokenizer->GetToken( 0, 0 ); + idName = token->GetStringValue(); + id = FindSymbol( idName, m_IDKeywords ); + + if ( id != ID_GET ) + { + //Return the token + m_tokenizer->PutBackToken( token ); + return false; + } + + token->Delete(); + return true; +} + +/* +=================================================================================================== + + MatchRandom() + + Attempts to match to a random identifier. + +=================================================================================================== +*/ + +int CInterpreter::MatchRandom( void ) +{ + CToken *token; + const char *idName; + int id; + + token = m_tokenizer->GetToken( 0, 0 ); + idName = token->GetStringValue(); + id = FindSymbol( idName, m_IDKeywords ); + + if ( id != ID_RANDOM ) + { + //Return the token + m_tokenizer->PutBackToken( token ); + return false; + } + + token->Delete(); + return true; +} + +/* +=================================================================================================== + + FindSymbol() + + Searches the symbol table for the given name. Returns the ID if found. + +=================================================================================================== +*/ + +int CInterpreter::FindSymbol( const char *name, keywordArray_t *table) +{ + keywordArray_t *ids; + + for (ids = table; (strcmp(ids->m_keyword, "")); ids++) + { + if (!stricmp(name, ids->m_keyword)) + return ids->m_tokenvalue; + } + + return -1; +} + + +/* +=================================================================================================== + + Match() + + Looks ahead to the next token to try and match it to the passed token, consumes token on success. + +=================================================================================================== +*/ + +//NOTENOTE: LookAhead() was separated from Match() for clarity + +int CInterpreter::Match( int token_id ) +{ + CToken *token; + + token = m_tokenizer->GetToken( 0, 0 ); + + if ( token->GetType() != token_id ) + { + //This may have been a check, so don't loose the token + m_tokenizer->PutBackToken( token ); + + return false; + } + + return true; +} + +/* +------------------------- +GetNextType +------------------------- +*/ + +int CInterpreter::GetNextType( void ) +{ + CToken *token = m_tokenizer->GetToken( 0, 0 ); + int id = token->GetType(); + + m_tokenizer->PutBackToken( token ); + + return id; +} + +/* +=================================================================================================== + + LookAhead() + + Looks ahead without consuming on success. + +=================================================================================================== +*/ + +int CInterpreter::LookAhead( int token_id ) +{ + CToken *token; + + token = m_tokenizer->GetToken( 0, 0 ); + + if ( token->GetType() != token_id ) + { + m_tokenizer->PutBackToken( token ); + + return false; + } + + m_tokenizer->PutBackToken( token ); + + return true; +} + +/* +=================================================================================================== + + GetTokenName() + + Returns the name of a token. + +=================================================================================================== +*/ + +const char *CInterpreter::GetTokenName( int token_id ) +{ + switch ( token_id ) + { + case TK_STRING: + return "STRING"; + break; + + case TK_CHAR: + return "CHARACTER"; + break; + + case TK_IDENTIFIER: + return "IDENTIFIER"; + break; + + case TK_FLOAT: + return "FLOAT"; + break; + + case TK_INTEGER: + return "INTEGER"; + break; + + default: + return "UNKNOWN"; + break; + } +} + +/* +=================================================================================================== + + Token Value Functions + +=================================================================================================== +*/ + +/* +=================================================================================================== + + GetFloat() + + Attempts to match and retrieve the value of a float token. + +=================================================================================================== +*/ + +int CInterpreter::GetFloat( CBlock *block ) +{ + CToken *token; + int type; + + //Look for a get + if ( MatchGet() ) + { + return GetGet( block ); + } + + //Look for a random + if ( MatchRandom() ) + { + return GetRandom( block ); + } + + token = m_tokenizer->GetToken(0,0); + type = token->GetType(); + + //Floats can accept either int or float values + if ( ( type != TK_FLOAT ) && ( type != TK_INT ) ) + { + return Error("syntax error : expected float; found %s", GetTokenName(type) ); + } + + if (type == TK_FLOAT) + { + block->Write( TK_FLOAT, (float) token->GetFloatValue() ); + } + else + { + block->Write( TK_FLOAT, (float) token->GetIntValue() ); + } + + token->Delete(); + + return true; +} + +/* +=================================================================================================== + + GetInteger() + + Attempts to match and retrieve the value of an integer token. + +=================================================================================================== +*/ + +int CInterpreter::GetInteger( CBlock *block ) +{ + return GetFloat( block ); +} + +/* +=================================================================================================== + + GetString() + + Attempts to match and retrieve the value of a string token. + +=================================================================================================== +*/ + +int CInterpreter::GetString( CBlock *block ) +{ + CToken *token; + int type; + + //Look for a get + if ( MatchGet() ) + { + return GetGet( block ); + } + + //Look for a random + if ( MatchRandom() ) + { + return GetRandom( block ); + } + + token = m_tokenizer->GetToken(0, 0); + type = token->GetType(); + + if ( (type != TK_STRING) && (type != TK_CHAR) ) + { + return Error("syntax error : expected string; found %s", GetTokenName(type)); + } + +//UGLY HACK!!! + + const char *temptr; + char temp[1024]; + + temptr = token->GetStringValue(); + + if ( strlen(temptr)+1 > sizeof( temp ) ) + { + return false; + } + + for ( int i = 0; i < strlen( temptr ); i++ ) + { + if ( temptr[i] == '#' ) + temp[i] = '\n'; + else + temp[i] = temptr[i]; + } + + temp[ strlen( temptr ) ] = 0; + +//UGLY HACK END!!! + + block->Write( TK_STRING, (const char *) &temp ); + + token->Delete(); + + return true; +} + +/* +=================================================================================================== + + GetIdentifier() + + Attempts to match and retrieve the value of an indentifier token. + +=================================================================================================== +*/ + +int CInterpreter::GetIdentifier( CBlock *block ) +{ + CToken *token; + int type; + + //FIXME: Should identifiers do this? + if ( MatchGet() ) + { + if ( GetGet( block ) == false ) + return false; + + return true; + } + + token = m_tokenizer->GetToken(0, 0); + type = token->GetType(); + + if ( type != TK_IDENTIFIER ) + { + return Error("syntax error : expected indentifier; found %s", GetTokenName(type)); + } + + block->Write( TK_IDENTIFIER, (const char *) token->GetStringValue() ); + + token->Delete(); + + return true; +} + +/* +=================================================================================================== + + GetEvaluator() + + Attempts to match and retrieve the value of an evaluator token. + +=================================================================================================== +*/ + +int CInterpreter::GetEvaluator( CBlock *block ) +{ + CToken *token; + int type; + + if ( MatchGet() ) + return false; + + if ( MatchRandom() ) + return false; + + token = m_tokenizer->GetToken(0, 0); + type = token->GetType(); + token->Delete(); + + switch ( type ) + { + case TK_GREATER_THAN: + case TK_LESS_THAN: + case TK_EQUALS: + case TK_NOT: + break; + + case TK_VECTOR_START: + type = TK_LESS_THAN; + break; + + case TK_VECTOR_END: + type = TK_GREATER_THAN; + break; + + default: + return Error("syntax error : expected operator type, found %s", GetTokenName( type ) ); + } + + block->Write( type, 0 ); + + return true; +} + +/* +=================================================================================================== + + GetAny() + + Attempts to match and retrieve any valid data type. + +=================================================================================================== +*/ + +int CInterpreter::GetAny( CBlock *block ) +{ + CToken *token; + int type; + + if ( MatchGet() ) + { + if ( GetGet( block ) == false ) + return false; + + return true; + } + + if ( MatchRandom() ) + { + if ( GetRandom( block ) == false ) + return false; + + return true; + } + + if ( MatchTag() ) + { + if ( GetTag( block ) == false ) + return false; + + return true; + } + + token = m_tokenizer->GetToken(0, 0); + type = token->GetType(); + + switch ( type ) + { + case TK_FLOAT: + m_tokenizer->PutBackToken( token ); + if ( GetFloat( block ) == false ) + return false; + + break; + + case TK_INT: + m_tokenizer->PutBackToken( token ); + if ( GetInteger( block ) == false ) + return false; + + break; + + case TK_VECTOR_START: + m_tokenizer->PutBackToken( token ); + if ( GetVector( block ) == false ) + return false; + + break; + + case TK_STRING: + case TK_CHAR: + m_tokenizer->PutBackToken( token ); + if ( GetString( block ) == false ) + return false; + + break; + + case TK_IDENTIFIER: + m_tokenizer->PutBackToken( token ); + if ( GetIdentifier( block ) == false ) + return false; + + break; + + default: + return false; + } + + return true; +} + +/* +=================================================================================================== + + GetType() + + Attempts to match and retrieve the value of a type token. + +=================================================================================================== +*/ + +int CInterpreter::GetType( char *get ) +{ + CToken *token; + char *string; + int type; + + token = m_tokenizer->GetToken(0, 0); + type = token->GetType(); + + if ( type != TK_IDENTIFIER ) + { + return Error("syntax error : expected identifier; found %s", GetTokenName(type)); + } + + string = (char *) token->GetStringValue(); + + if ( (strlen(string) + 1) > MAX_STRING_LENGTH) + { + Error("string exceeds 256 character limit"); + return false; + } + + strcpy(get, string); + + return true; +} + +/* +=================================================================================================== + + GetID() + + Attempts to match and interpret an identifier. + +=================================================================================================== +*/ + +//FIXME: This should use an externally defined table to match ID and functions + +int CInterpreter::GetID( char *id_name ) +{ + int id; + + id = FindSymbol( id_name, m_IDKeywords ); + + if ( id == -1 ) + return Error("'%s' : unknown identifier", id_name); + + //FIXME: Function pointers would be awfully nice.. but not inside a class! Weee!! + + switch (id) + { + + //Affect takes control of an entity + + case ID_AFFECT: + return GetAffect(); + break; + + //Wait for a specified amount of time + + case ID_WAIT: + return GetWait(); + break; + + //Generic set call + + case ID_SET: + return GetSet(); + break; + + case ID_LOOP: + return GetLoop(); + break; + + case ID_PRINT: + return GetPrint(); + break; + + case ID_USE: + return GetUse(); + break; + + case ID_FLUSH: + return GetFlush(); + break; + + case ID_RUN: + return GetRun(); + break; + + case ID_KILL: + return GetKill(); + break; + + case ID_REMOVE: + return GetRemove(); + break; + + case ID_CAMERA: + return GetCamera(); + break; + + case ID_SOUND: + return GetSound(); + break; + + case ID_MOVE: + return GetMove(); + break; + + case ID_ROTATE: + return GetRotate(); + break; + + case ID_IF: + return GetIf(); + break; + + case ID_ELSE: + //return Error("syntax error : else without matching if"); + return GetElse(); //FIXME: Protect this call so that floating else's aren't allowed + break; + + case ID_GET: + return Error("syntax error : illegal use of \"get\""); + break; + + case ID_TAG: + return Error("syntax error : illegal use of \"tag\""); + break; + + case ID_TASK: + return GetTask(); + break; + + case ID_DO: + return GetDo(); + break; + + case ID_DECLARE: + return GetDeclare(); + break; + + case ID_FREE: + return GetFree(); + break; + + case ID_REM: + GetRem(); + break; + + case ID_DOWAIT: + GetDoWait(); + break; + + case ID_SIGNAL: + GetSignal(); + break; + + case ID_WAITSIGNAL: + GetWaitSignal(); + break; + + case ID_PLAY: + GetPlay(); //Bad eighties slang joke... yeah, it's not really funny, I know... + break; + + //Local variable types + case TK_FLOAT: + case TK_INT: + case TK_STRING: + case TK_VECTOR: + GetVariable( id ); + break; + + //Unknown ID + + default: + case -1: + return Error("'%s' : unknown identifier", id_name); + break; + } + + return true; +} + +/* +=================================================================================================== + + ID Interpreting Functions + +=================================================================================================== +*/ + +/* +------------------------- +GetDeclare +------------------------- +*/ + +int CInterpreter::GetDeclare( void ) +{ + CBlock block; + char typeName[MAX_STRING_LENGTH]; + int type; + + block.Create( ID_DECLARE ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetType( (char *) typeName ) == false ) + return false; + + type = FindSymbol( typeName, m_typeKeywords); + + switch ( type ) + { + case TK_FLOAT: + case TK_VECTOR: + case TK_STRING: + block.Write( TK_FLOAT, (float) type ); + break; + + default: + return Error("unknown identifier %s", typeName ); + break; + } + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("declare : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + + +/* +------------------------- +GetFree +------------------------- +*/ + +int CInterpreter::GetFree( void ) +{ + CBlock block; + + block.Create( ID_FREE ); + + if ( Match( TK_OPEN_PARENTHESIS ) == false ) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if ( Match( TK_CLOSED_PARENTHESIS ) == false ) + return Error("free : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetIf() + + Handles the if() conditional statement. + +=================================================================================================== +*/ + +// if ( STRING ? STRING ) + +int CInterpreter::GetIf( void ) +{ + CBlock block; + + block.Create( ID_IF ); + + if ( Match( TK_OPEN_PARENTHESIS ) == false ) + return Error("syntax error : '(' not found"); + + if ( GetAny( &block ) == false ) + return false; + + if ( GetEvaluator( &block ) == false ) + return false; + + if ( GetAny( &block ) == false ) + return false; + + if ( Match( TK_CLOSED_PARENTHESIS ) == false ) + return Error("if : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetElse() + + Handles the else() conditional statement. + +=================================================================================================== +*/ + +// else + +int CInterpreter::GetElse( void ) +{ + CBlock block; + + block.Create( ID_ELSE ); + + /* + if ( Match( TK_OPEN_PARENTHESIS ) == false ) + return Error("syntax error : '(' not found"); + */ + + /* + if ( GetAny( &block ) == false ) + return false; + + if ( GetEvaluator( &block ) == false ) + return false; + + if ( GetAny( &block ) == false ) + return false; + */ + + /* + if ( Match( TK_CLOSED_PARENTHESIS ) == false ) + return Error("sound : too many parameters"); + */ + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetTask() + + Handles the task() sequence specifier. + +=================================================================================================== +*/ + +//task ( name ) { } + +int CInterpreter::GetTask( void ) +{ + CBlock block; + + block.Create( ID_TASK ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("GetTask: too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; + +} + +/* +=================================================================================================== + + GetDo() + + Handles the do() function. + +=================================================================================================== +*/ + +//do ( taskName ) + +int CInterpreter::GetDo( void ) +{ + CBlock block; + + block.Create( ID_DO ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("do : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetGet() + + Handles the get() function. + +=================================================================================================== +*/ + +// get( TYPE, NAME ); + +int CInterpreter::GetGet( CBlock *block ) +{ + char typeName[MAX_STRING_LENGTH]; + int type; + + block->Write( ID_GET, (float) ID_GET ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetType( (char *) typeName ) == false ) + return false; + + type = FindSymbol( typeName, m_typeKeywords); + + switch ( type ) + { + case TK_FLOAT: + case TK_INT: + case TK_VECTOR: + case TK_STRING: + block->Write( TK_FLOAT, (float) type ); + break; + + default: + return Error("unknown identifier %s", typeName ); + break; + } + + if ( GetString( block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("affect : too many parameters"); + + return true; +} + +/* +=================================================================================================== + + GetRandom() + + Handles the random() function. + +=================================================================================================== +*/ + +// random( low, high ); + +int CInterpreter::GetRandom( CBlock *block ) +{ + block->Write( ID_RANDOM, (float) ID_RANDOM ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetFloat( block ) == false ) + return false; + + if ( GetFloat( block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("affect : too many parameters"); + + return true; +} + +/* +=================================================================================================== + + GetSound() + + Handles the sound() function. + +=================================================================================================== +*/ + +// sound( NAME ); + +int CInterpreter::GetSound( void ) +{ + CBlock block; + + block.Create( ID_SOUND ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetIdentifier( &block ) == false ) + return false; + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("sound : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetMove() + + Handles the move() function. + +=================================================================================================== +*/ + +// move( ORIGIN, ANGLES, DURATION ); + +int CInterpreter::GetMove( void ) +{ + CBlock block; + + block.Create( ID_MOVE ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetVector( &block ) == false ) + return false; + + //Angles are optional + if ( LookAhead( TK_VECTOR_START ) || LookAhead( TK_IDENTIFIER ) ) + { + if ( GetVector( &block ) == false ) + return false; + } + + if ( GetFloat( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("move : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetRotate() + + Handles the rotate() function. + +=================================================================================================== +*/ + +// move( ANGLES, DURATION ); + +int CInterpreter::GetRotate( void ) +{ + CBlock block; + + block.Create( ID_ROTATE ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetVector( &block ) == false ) + return false; + + if ( GetFloat( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("move : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetAffect() + + Handles the affect() function. + +=================================================================================================== +*/ + +//FIXME: This should be externally defined + +int CInterpreter::GetAffect( void ) +{ + CBlock block; + char typeName[MAX_STRING_SIZE]; + int type; + + block.Create( ID_AFFECT ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!LookAhead( TK_IDENTIFIER )) + return Error("syntax error : identifier not found"); + + if ( MatchGet() ) + return Error("syntax error : illegal use of \"get\""); + + if ( GetType( (char *) typeName ) == false ) + return false; + + type = FindSymbol( typeName, m_typeKeywords); + + switch ( type ) + { + case TYPE_INSERT: + case TYPE_FLUSH: + + block.Write( TK_FLOAT, (float) type ); + break; + + default: + return Error("'%s': unknown affect type", typeName ); + break; + + } + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("affect : too many parameters"); + + if (!LookAhead( TK_BLOCK_START )) + return Error("syntax error : '{' not found"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetWait() + + Handles the wait() function. + +=================================================================================================== +*/ + +//FIXME: This should be externally defined + +int CInterpreter::GetWait( void ) +{ + CBlock block; + + block.Create( ID_WAIT ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( LookAhead( TK_STRING ) ) + { + if ( GetString( &block ) == false ) + return false; + } + else + { + if ( GetFloat( &block ) == false ) + return false; + } + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("wait : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetSet() + + Handles the set() function. + +=================================================================================================== +*/ + +//FIXME: This should be externally defined + +int CInterpreter::GetSet( void ) +{ + CBlock block; + + block.Create( ID_SET ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + //Check for get placement + if ( MatchGet() ) + { + if ( GetGet( &block ) == false ) + return false; + } + else + { + switch( GetNextType() ) + { + case TK_INT: + + if ( GetInteger( &block ) == false ) + return false; + + break; + + case TK_FLOAT: + + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TK_STRING: + + if ( GetString( &block ) == false ) + return false; + + break; + + case TK_VECTOR_START: + + if ( GetVector( &block ) == false ) + return false; + + break; + + default: + + if ( MatchTag() ) + { + GetTag( &block ); + break; + } + + if ( MatchRandom() ) + { + GetRandom( &block ); + break; + } + + return Error("unknown parameter type"); + break; + } + } + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("set : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetLoop() + + Handles the loop() function. + +=================================================================================================== +*/ + +int CInterpreter::GetLoop( void ) +{ + CBlock block; + + block.Create( ID_LOOP ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( LookAhead( TK_CLOSED_PARENTHESIS ) ) + { + //-1 denotes an infinite loop + block.Write( TK_FLOAT, (float) -1); + } + else + { + if ( GetInteger( &block ) == false ) + return false; + } + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("GetLoop : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetPrint() + + Handles the print() function. + +=================================================================================================== +*/ + +int CInterpreter::GetPrint( void ) +{ + CBlock block; + + block.Create( ID_PRINT ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("print : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetUse() + + Handles the use() function. + +=================================================================================================== +*/ + +int CInterpreter::GetUse( void ) +{ + CBlock block; + + block.Create( ID_USE ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("use : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetFlush() + + Handles the flush() function. + +=================================================================================================== +*/ + +int CInterpreter::GetFlush( void ) +{ + CBlock block; + + block.Create( ID_FLUSH ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("flush : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetRun() + + Handles the run() function. + +=================================================================================================== +*/ + +int CInterpreter::GetRun( void ) +{ + CBlock block; + + block.Create( ID_RUN ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("run : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetKill() + + Handles the kill() function. + +=================================================================================================== +*/ + +int CInterpreter::GetKill( void ) +{ + CBlock block; + + block.Create( ID_KILL ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("kill : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetRemove() + + Handles the remove() function. + +=================================================================================================== +*/ + +int CInterpreter::GetRemove( void ) +{ + CBlock block; + + block.Create( ID_REMOVE ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("remove : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetRem() + + Handles the rem() function. + +=================================================================================================== +*/ + +// this is just so people can put comments in scripts in BehavEd and not have them lost as normal comments would be. +// +int CInterpreter::GetRem( void ) +{ + CBlock block; + + block.Create( ID_REM ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + // optional string? + + if (Match( TK_CLOSED_PARENTHESIS )) + return true; + + GetString( &block ); + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("rem : function only takes 1 optional parameter"); + + return true; +} + + +/* +=================================================================================================== + + GetCamera() + + Handles the camera() function. + +=================================================================================================== +*/ + +int CInterpreter::GetCamera( void ) +{ + CBlock block; + char typeName[MAX_STRING_SIZE]; + int type; + + block.Create( ID_CAMERA ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetType( (char *) typeName ) == false ) + return false; + + type = FindSymbol( typeName, m_typeKeywords); + + switch ( type ) + { + case TYPE_PAN: //PAN ( ANGLES, DURATION ) + + block.Write( TK_FLOAT, (float) type ); + + if ( GetVector( &block ) == false ) + return false; + + if ( GetVector( &block ) == false ) + return false; + + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_ZOOM: //ZOOM ( FOV, DURATION ) + + block.Write( TK_FLOAT, (float) type ); + + if ( GetFloat( &block ) == false ) + return false; + + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_MOVE: //MOVE ( ORIGIN, DURATION ) + + block.Write( TK_FLOAT, (float) type ); + + if ( GetVector( &block ) == false ) + return false; + + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_FADE: //FADE ( SOURCE(R,G,B,A), DEST(R,G,B,A), DURATION ) + + block.Write( TK_FLOAT, (float) type ); + + //Source color + if ( GetVector( &block ) == false ) + return false; + if ( GetFloat( &block ) == false ) + return false; + + //Dest color + if ( GetVector( &block ) == false ) + return false; + if ( GetFloat( &block ) == false ) + return false; + + //Duration + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_PATH: //PATH ( FILENAME ) + + block.Write( TK_FLOAT, (float) type ); + + //Filename + if ( GetString( &block ) == false ) + return false; + + break; + + case TYPE_ENABLE: + case TYPE_DISABLE: + + block.Write( TK_FLOAT, (float) type ); + break; + + case TYPE_SHAKE: //SHAKE ( INTENSITY, DURATION ) + + block.Write( TK_FLOAT, (float) type ); + + //Intensity + if ( GetFloat( &block ) == false ) + return false; + + //Duration + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_ROLL: //ROLL ( ANGLE, TIME ) + + block.Write( TK_FLOAT, (float) type ); + + //Angle + if ( GetFloat( &block ) == false ) + return false; + + //Time + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_TRACK: //TRACK ( TARGETNAME, SPEED, INITLERP ) + + block.Write( TK_FLOAT, (float) type ); + + //Target name + if ( GetString( &block ) == false ) + return false; + + //Speed + if ( GetFloat( &block ) == false ) + return false; + + //Init lerp + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_FOLLOW: //FOLLOW ( CAMERAGROUP, SPEED, INITLERP ) + + block.Write( TK_FLOAT, (float) type ); + + //Camera group + if ( GetString( &block ) == false ) + return false; + + //Speed + if ( GetFloat( &block ) == false ) + return false; + + //Init lerp + if ( GetFloat( &block ) == false ) + return false; + + break; + + case TYPE_DISTANCE: //DISTANCE ( DISTANCE, INITLERP ) + + block.Write( TK_FLOAT, (float) type ); + + //Distance + if ( GetFloat( &block ) == false ) + return false; + + //Init lerp + if ( GetFloat( &block ) == false ) + return false; + + break; + } + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("camera : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +------------------------- +GetDoWait +------------------------- +*/ + +int CInterpreter::GetDoWait( void ) +{ + CBlock block; + + //Write out the "do" portion + block.Create( ID_DO ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("do : too many parameters"); + + //Write out the accompanying "wait" + char *str = (char *) block.GetMemberData( 0 ); + + CBlock block2; + + block2.Create( ID_WAIT ); + + block2.Write( TK_STRING, (char *) str ); + + m_blockStream->WriteBlock( &block ); + m_blockStream->WriteBlock( &block2 ); + + return true; +} + +/* +------------------------- +GetSignal +------------------------- +*/ + +int CInterpreter::GetSignal( void ) +{ + CBlock block; + + block.Create( ID_SIGNAL ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("signal : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +------------------------- +GetSignal +------------------------- +*/ + +int CInterpreter::GetWaitSignal( void ) +{ + CBlock block; + + block.Create( ID_WAITSIGNAL ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("waitsignal : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +------------------------- +GetPlay +------------------------- +*/ + +int CInterpreter::GetPlay( void ) +{ + CBlock block; + + block.Create( ID_PLAY ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + if ( GetString( &block ) == false ) + return false; + + if ( GetString( &block ) == false ) + return false; + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("waitsignal : too many parameters"); + + m_blockStream->WriteBlock( &block ); + + return true; +} + +/* +=================================================================================================== + + GetTag() + + Handles the tag() identifier. + +=================================================================================================== +*/ + +//NOTENOTE: The tag's information is included as block members, not as a separate block. + +int CInterpreter::GetTag( CBlock *block ) +{ + char typeName[MAX_STRING_SIZE]; + int typeID; + + //Mark as a tag + block->Write( ID_TAG, (float) ID_TAG ); + + if (!Match( TK_OPEN_PARENTHESIS )) + return Error("syntax error : '(' not found"); + + //Get the tag name + if ( GetString( block ) == false ) + return false; + + //Get the lookup ID + GetType( (char *) typeName ); + + typeID = FindSymbol( (char *) typeName, m_typeKeywords); + + //Tags only contain origin and angles lookups + if ( (typeID != TYPE_ORIGIN) && (typeID != TYPE_ANGLES) ) + { + return Error("syntax error : 'tag' : %s is not a valid look up identifier", typeName ); + } + + block->Write( TK_FLOAT, (float) typeID ); + + if (!Match( TK_CLOSED_PARENTHESIS )) + return Error("tag : too many parameters"); + + return true; +} + +/* +=================================================================================================== + + Interpret function + +=================================================================================================== +*/ + +// note new return type, this now returns the bad block number, else 0 for success. +// +// I also return -ve block numbers for errors between blocks. Eg if you read 3 good blocks, then find an unexpected +// float in the script between blocks 3 & 4 then I return -3 to indicate the error is after that, but not block 4 +// +int CInterpreter::Interpret( CTokenizer *Tokenizer, CBlockStream *BlockStream, char *filename ) +{ + CBlock block; + CToken *token; + int type, blockLevel = 0, parenthesisLevel = 0; + + m_sCurrentFile = filename; // used during error reporting because you can't ask tokenizer for pushed streams + + m_tokenizer = Tokenizer; + m_blockStream = BlockStream; + + m_iCurrentLine = m_tokenizer->GetCurLine(); + token = m_tokenizer->GetToEndOfLine(TK_STRING); + m_sCurrentLine = token->GetStringValue(); + m_tokenizer->PutBackToken(token, false, NULL, true); + + m_iBadCBlockNumber = 0; + + while (m_tokenizer->GetRemainingSize() > 0) + { + token = m_tokenizer->GetToken( TKF_USES_EOL, 0 ); + type = token->GetType(); + + switch ( type ) + { + case TK_UNDEFINED: + token->Delete(); + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("%d : undefined token", type); + return m_iBadCBlockNumber; + break; + + case TK_EOF: + break; + + case TK_EOL: + // read the next line, then put it back + token->Delete(); + m_iCurrentLine = m_tokenizer->GetCurLine(); + token = m_tokenizer->GetToEndOfLine(TK_STRING); + m_sCurrentLine = token->GetStringValue(); + m_tokenizer->PutBackToken(token, false, NULL, true); + break; + + case TK_CHAR: + case TK_STRING: + token->Delete(); + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : unexpected string"); + return m_iBadCBlockNumber; + break; + + case TK_INT: + token->Delete(); + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : unexpected integer"); + return m_iBadCBlockNumber; + break; + + case TK_FLOAT: + token->Delete(); + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : unexpected float"); + return m_iBadCBlockNumber; + break; + + case TK_IDENTIFIER: + m_iBadCBlockNumber++; + if (!GetID( (char *) token->GetStringValue() )) + { + token->Delete(); + return m_iBadCBlockNumber; + } + token->Delete(); + break; + + case TK_BLOCK_START: + token->Delete(); + if (parenthesisLevel) + { + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : brace inside parenthesis"); + return m_iBadCBlockNumber; + } + + blockLevel++; + break; + + case TK_BLOCK_END: + token->Delete(); + if (parenthesisLevel) + { + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : brace inside parenthesis"); + return m_iBadCBlockNumber; + } + + block.Create( ID_BLOCK_END ); + m_blockStream->WriteBlock( &block ); + block.Free(); + + blockLevel--; + break; + + case TK_OPEN_PARENTHESIS: + token->Delete(); + blockLevel++; + parenthesisLevel++; + break; + + case TK_CLOSED_PARENTHESIS: + token->Delete(); + blockLevel--; + parenthesisLevel--; + + if (parenthesisLevel<0) + { + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : closed parenthesis with no opening match"); + return m_iBadCBlockNumber; + } + break; + + case TK_VECTOR_START: + token->Delete(); + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : unexpected vector"); + return m_iBadCBlockNumber; + break; + + case TK_VECTOR_END: + token->Delete(); + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("syntax error : unexpected vector"); + return m_iBadCBlockNumber; + break; + } + } + + if ( blockLevel ) + { + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("error : open brace was not closed"); + return m_iBadCBlockNumber; + } + + if ( parenthesisLevel ) + { + m_iBadCBlockNumber = -m_iBadCBlockNumber; + Error("error: open parenthesis"); + return m_iBadCBlockNumber; + } + + //Release all the variable information, because it's already been written out + FreeVars(); + + m_iBadCBlockNumber = 0; + return m_iBadCBlockNumber; //true; +} + diff --git a/code/icarus/Sequencer.cpp b/code/icarus/Sequencer.cpp index ea3c78a..3c47aca 100644 --- a/code/icarus/Sequencer.cpp +++ b/code/icarus/Sequencer.cpp @@ -85,6 +85,13 @@ int CSequencer::Free( void ) m_numCommands = 0; m_curSequence = NULL; + bstream_t *streamToDel; + while(!m_streamsCreated.empty()) + { + streamToDel = m_streamsCreated.back(); + DeleteStream(streamToDel); + } + return SEQ_OK; } @@ -116,7 +123,7 @@ int CSequencer::Flush( CSequence *owner ) m_sequenceMap.erase( (*sli)->GetID() ); //Delete it, and remove all references - RemoveSequence( (*sli), false, false ); + RemoveSequence( (*sli) ); m_owner->DeleteSequence( (*sli) ); //Delete from the sequence list and move on @@ -146,6 +153,8 @@ bstream_t *CSequencer::AddStream( void ) stream->stream = new CBlockStream; //deleted in Route() stream->last = m_curStream; + m_streamsCreated.push_back(stream); + return stream; } @@ -158,6 +167,12 @@ Deletes parsing stream */ void CSequencer::DeleteStream( bstream_t *bstream ) { + vector::iterator finder = find(m_streamsCreated.begin(), m_streamsCreated.end(), bstream); + if(finder != m_streamsCreated.end()) + { + m_streamsCreated.erase(finder); + } + bstream->stream->Free(); delete bstream->stream; @@ -341,6 +356,8 @@ int CSequencer::ParseRun( CBlock *block ) if ( buffer_size <= 0 ) { m_ie->I_DPrintf( WL_ERROR, "'%s' : could not open file\n", (char*) block->GetMemberData( 0 )); + delete block; + block = NULL; return SEQ_FAILED; } @@ -351,6 +368,8 @@ int CSequencer::ParseRun( CBlock *block ) if (!new_stream->stream->Open( buffer, buffer_size )) { m_ie->I_DPrintf( WL_ERROR, "invalid stream" ); + delete block; + block = NULL; return SEQ_FAILED; } @@ -363,6 +382,8 @@ int CSequencer::ParseRun( CBlock *block ) if ( S_FAILED( Route( new_sequence, new_stream )) ) { //Error code is set inside of Route() + delete block; + block = NULL; return SEQ_FAILED; } @@ -395,6 +416,8 @@ int CSequencer::ParseIf( CBlock *block, bstream_t *bstream ) if ( sequence == NULL ) { m_ie->I_DPrintf( WL_ERROR, "ParseIf: failed to allocate container sequence" ); + delete block; + block = NULL; return SEQ_FAILED; } @@ -425,6 +448,10 @@ Parses an else statement int CSequencer::ParseElse( CBlock *block, bstream_t *bstream ) { + //The else is not retained + delete block; + block = NULL; + CSequence *sequence; //Create the container sequence @@ -451,10 +478,6 @@ int CSequencer::ParseElse( CBlock *block, bstream_t *bstream ) m_elseOwner->SetFlag( BF_ELSE ); - //The else is not retained - delete block; - block = NULL; - //Recursively obtain the conditional body Route( sequence, bstream ); @@ -487,6 +510,8 @@ int CSequencer::ParseLoop( CBlock *block, bstream_t *bstream ) if ( sequence == NULL ) { m_ie->I_DPrintf( WL_ERROR, "ParseLoop : failed to allocate container sequence" ); + delete block; + block = NULL; return SEQ_FAILED; } @@ -615,12 +640,16 @@ int CSequencer::ParseAffect( CBlock *block, bstream_t *bstream ) //only string is acceptable for affect, store result in p1 if ( m_ie->I_GetString( m_ownerID, type, name, &p1 ) == false) { + delete block; + block = NULL; return false; } break; default: //FIXME: Make an enum id for the error... m_ie->I_DPrintf( WL_ERROR, "Invalid parameter type on affect _1" ); + delete block; + block = NULL; return false; break; } @@ -631,6 +660,8 @@ int CSequencer::ParseAffect( CBlock *block, bstream_t *bstream ) default: //FIXME: Make an enum id for the error... m_ie->I_DPrintf( WL_ERROR, "Invalid parameter type on affect _2" ); + delete block; + block = NULL; return false; break; }//end id switch @@ -656,20 +687,24 @@ int CSequencer::ParseAffect( CBlock *block, bstream_t *bstream ) m_ie->I_DPrintf( WL_WARNING, "'%s' : invalid affect() target\n", entname ); //Fast-forward out of this affect block onto the next valid code - CSequence *backSeq, *trashSeq = m_owner->GetSequence(); + CSequence *backSeq = m_curSequence; - backSeq = m_curSequence; + CSequence *trashSeq = m_owner->GetSequence(); Route( trashSeq, bstream ); - RemoveSequence( trashSeq, true, true ); + Recall(); + DestroySequence( trashSeq ); m_curSequence = backSeq; - - m_owner->DeleteSequence( trashSeq ); - + delete block; + block = NULL; return SEQ_OK; } if S_FAILED ( stream_sequencer->AddAffect( bstream, (int) m_curSequence->HasFlag( SQ_RETAIN ), &ret ) ) + { + delete block; + block = NULL; return SEQ_FAILED; + } //Hold onto the id for later use //FIXME: If the target sequence is freed, what then? (!suspect!) @@ -713,6 +748,8 @@ int CSequencer::ParseTask( CBlock *block, bstream_t *bstream ) if ( group == NULL ) { m_ie->I_DPrintf( WL_ERROR, "error : unable to allocate a new task group" ); + delete block; + block = NULL; return SEQ_FAILED; } @@ -1990,7 +2027,11 @@ int CSequencer::Callback( CTaskManager *taskManager, CBlock *block, int returnCo { //There are no more pending commands if ( m_curSequence == NULL ) + { + delete block; + block = NULL; return SEQ_OK; + } //Check to retain the command if ( m_curSequence->HasFlag( SQ_RETAIN ) ) //This isn't true for affect sequences...? @@ -2040,7 +2081,15 @@ int CSequencer::Recall( void ) while ( ( block = m_taskManager->RecallTask() ) != NULL ) { - PushCommand( block, PUSH_BACK ); + if (m_curSequence) + { + PushCommand( block, PUSH_BACK ); + } + else + { + delete block; + block = NULL; + } } return true; @@ -2066,8 +2115,6 @@ int CSequencer::Affect( int id, int type ) case TYPE_FLUSH: - Recall(); - //Get rid of all old code Flush( sequence ); @@ -2080,9 +2127,9 @@ int CSequencer::Affect( int id, int type ) break; case TYPE_INSERT: - - Recall(); + Recall(); + sequence->SetReturn( m_curSequence ); sequence->RemoveFlag( SQ_PENDING, true ); @@ -2180,17 +2227,10 @@ RemoveSequence //NOTENOTE: This only removes references to the sequence, IT DOES NOT FREE THE ALLOCATED MEMORY! You've be warned! =) -int CSequencer::RemoveSequence( CSequence *sequence, bool eraseSequence, bool removeChildren ) +int CSequencer::RemoveSequence( CSequence *sequence ) { CSequence *temp; - if ( eraseSequence ) - { - //Remove it from the list - m_sequenceMap.erase( sequence->GetID() ); - m_sequences.remove( sequence ); - } - int numChildren = sequence->GetNumChildren(); //Add all the children @@ -2210,13 +2250,48 @@ int CSequencer::RemoveSequence( CSequence *sequence, bool eraseSequence, bool re temp->SetParent( NULL ); temp->SetReturn( NULL ); - if ( removeChildren ) - RemoveSequence( temp, eraseSequence, removeChildren ); } return SEQ_OK; } +int CSequencer::DestroySequence( CSequence *sequence ) +{ + m_sequenceMap.erase( sequence->GetID() ); + m_sequences.remove( sequence ); + + taskSequence_m::iterator tsi; + for ( tsi = m_taskSequences.begin(); tsi != m_taskSequences.end(); ) + { + if((*tsi).second == sequence) + { + tsi = m_taskSequences.erase(tsi); + } + else + { + ++tsi; + } + } + + CSequence* parent = sequence->GetParent(); + if ( parent ) + { + parent->RemoveChild( sequence ); + parent = NULL; + } + + int curChild = sequence->GetNumChildren(); + while(curChild) + { + curChild--; + DestroySequence(sequence->GetChild( curChild )); + } + + m_owner->DeleteSequence( sequence ); + + return SEQ_OK; +} + /* ------------------------- ReturnSequence diff --git a/code/icarus/TaskManager.cpp b/code/icarus/TaskManager.cpp index f1bb8d6..bd4d4a9 100644 --- a/code/icarus/TaskManager.cpp +++ b/code/icarus/TaskManager.cpp @@ -331,6 +331,16 @@ int CTaskManager::Update( void ) return returnVal; } +/* +------------------------- +IsRunning +------------------------- +*/ + +qboolean CTaskManager::IsRunning( void ) +{ + return ( m_tasks.empty() == false ); +} /* ------------------------- Check @@ -939,7 +949,12 @@ CBlock *CTaskManager::RecallTask( void ) if ( task ) { - return task->GetBlock(); + // fixed 2/12/2 to free the task that has been popped (called from sequencer Recall) + CBlock* retBlock = task->GetBlock(); + task->Free(); + + return retBlock; + // return task->GetBlock(); } return NULL; @@ -1022,8 +1037,12 @@ CBlock *CTaskManager::GetCurrentTask( void ) if ( task == NULL ) return NULL; +// fixed 2/12/2 to free the task that has been popped (called from sequencer Interrupt) + CBlock* retBlock = task->GetBlock(); + task->Free(); - return task->GetBlock(); + return retBlock; +// return task->GetBlock(); } /* diff --git a/code/icarus/Tokenizer.cpp b/code/icarus/Tokenizer.cpp new file mode 100644 index 0000000..914a8f2 --- /dev/null +++ b/code/icarus/Tokenizer.cpp @@ -0,0 +1,2833 @@ +// Tokenizer.cpp +#ifndef NOT_USING_MODULES +// !!! if you are not using modules, read BELOW !!! +#include "Module.h" // if you are not using modules, + // create an empty Module.h in your + // project -- use of modules allows + // the error handler to be overridden + // with a custom CErrHandler +#endif +#include "Tokenizer.h" + + +enum +{ + DIR_INCLUDE = TK_USERDEF, + DIR_IFDEF, + DIR_IFNDEF, + DIR_ENDIF, + DIR_ELSE, + DIR_DEFINE, + DIR_UNDEFINE, +}; + +keywordArray_t CTokenizer::directiveKeywords[] = +{ + "include", DIR_INCLUDE, + "ifdef", DIR_IFDEF, + "ifndef", DIR_IFNDEF, + "endif", DIR_ENDIF, + "else", DIR_ELSE, + "define", DIR_DEFINE, + "undefine", DIR_UNDEFINE, + "", TK_EOF, +}; + +keywordArray_t CTokenizer::errorMessages[] = +{ + "No Error", TKERR_NONE, + "Unknown Error", TKERR_UNKNOWN, + "Buffer creation failed", TKERR_BUFFERCREATE, + "Unrecognized symbol", TKERR_UNRECOGNIZEDSYMBOL, + "Duplicate symbol", TKERR_DUPLICATESYMBOL, + "String length exceeded", TKERR_STRINGLENGTHEXCEEDED, + "Identifier length exceeded", TKERR_IDENTIFIERLENGTHEXCEEDED, + "Expected integer", TKERR_EXPECTED_INTEGER, + "Expected identifier", TKERR_EXPECTED_IDENTIFIER, + "Expected string", TKERR_EXPECTED_STRING, + "Expected char", TKERR_EXPECTED_CHAR, + "Expected float", TKERR_EXPECTED_FLOAT, + "Unexpected token", TKERR_UNEXPECTED_TOKEN, + "Invalid directive", TKERR_INVALID_DIRECTIVE, + "Include file not found", TKERR_INCLUDE_FILE_NOTFOUND, + "Unmatched directive", TKERR_UNMATCHED_DIRECTIVE, + "", TKERR_USERERROR, +}; + +// +// CSymbol +// + +CSymbol::CSymbol() +{ +} + +CSymbol::~CSymbol() +{ +} + +CSymbol* CSymbol::Create(LPCTSTR symbolName) +{ + CSymbol* retval = new CSymbol(); + retval->Init(symbolName); + return retval; +} + +LPCTSTR CSymbol::GetName() +{ + if (m_symbolName == NULL) + { + return ""; + } + return m_symbolName; +} + +void CSymbol::Init(LPCTSTR symbolName) +{ + m_symbolName = (char*)malloc(strlen(symbolName) + 1); +// ASSERT(m_symbolName); + strcpy(m_symbolName, symbolName); +} + +void CSymbol::Delete() +{ + if (m_symbolName != NULL) + { + free(m_symbolName); + m_symbolName = NULL; + } + delete this; +} + +// +// CDirectiveSymbol +// + +CDirectiveSymbol::CDirectiveSymbol() +{ +} + +CDirectiveSymbol::~CDirectiveSymbol() +{ +} + +CDirectiveSymbol* CDirectiveSymbol::Create(LPCTSTR symbolName) +{ + CDirectiveSymbol* retval = new CDirectiveSymbol(); + retval->Init(symbolName); + return retval; +} + +void CDirectiveSymbol::Init(LPCTSTR symbolName) +{ + CSymbol::Init(symbolName); + m_value = NULL; +} + +void CDirectiveSymbol::Delete() +{ + if (m_value != NULL) + { + free(m_value); + m_value = NULL; + } + CSymbol::Delete(); +} + +void CDirectiveSymbol::SetValue(LPCTSTR value) +{ + if (m_value != NULL) + { + free(m_value); + } + m_value = (char*)malloc(strlen(value) + 1); + strcpy(m_value, value); +} + +LPCTSTR CDirectiveSymbol::GetValue() +{ + return m_value; +} + +// +// CIntSymbol +// + +CIntSymbol::CIntSymbol() +{ +} + +CIntSymbol* CIntSymbol::Create(LPCTSTR symbolName, int value) +{ + CIntSymbol* retval = new CIntSymbol(); + retval->Init(symbolName, value); + return retval; +} + +void CIntSymbol::Delete() +{ + CSymbol::Delete(); +} + +void CIntSymbol::Init(LPCTSTR symbolName, int value) +{ + CSymbol::Init(symbolName); + m_value = value; +} + +int CIntSymbol::GetValue() +{ + return m_value; +} + +// +// CSymbolTable +// + +CSymbolTable::CSymbolTable() +{ + Init(); +} + +CSymbolTable::~CSymbolTable() +{ +} + +CSymbolTable* CSymbolTable::Create() +{ + CSymbolTable* retval = new CSymbolTable(); + retval->Init(); + return retval; +} + +void CSymbolTable::Init() +{ +} + +void CSymbolTable::DiscardSymbols() +{ + for (symbolmap_t::iterator isymbol = m_symbols.begin(); isymbol != m_symbols.end(); isymbol++) + { + (*isymbol).second->Delete(); + } + m_symbols.erase(m_symbols.begin(), m_symbols.end()); +} + +void CSymbolTable::Delete() +{ + DiscardSymbols(); + delete this; +} + +bool CSymbolTable::AddSymbol(CSymbol* theSymbol) +{ + LPCTSTR name = theSymbol->GetName(); + + symbolmap_t::iterator iter = m_symbols.find(name); + if (iter != m_symbols.end()) + { + return false; + } + m_symbols.insert(symbolmap_t::value_type(name, theSymbol)); + return true; +} + +CSymbol* CSymbolTable::FindSymbol(LPCTSTR symbolName) +{ + symbolmap_t::iterator iter = m_symbols.find(symbolName); + if (iter != m_symbols.end()) + { + return (*iter).second; + } + return NULL; +} + +CSymbol* CSymbolTable::ExtractSymbol(LPCTSTR symbolName) +{ + symbolmap_t::iterator iter = m_symbols.find(symbolName); + if (iter != m_symbols.end()) + { + CSymbol* retval = (*iter).second; + m_symbols.erase(iter); + } + return NULL; +} + +void CSymbolTable::RemoveSymbol(LPCTSTR symbolName) +{ + m_symbols.erase(symbolName); +} + +// +// CParseStream +// + +CParseStream::CParseStream() +{ +} + +CParseStream::~CParseStream() +{ +} + +CParseStream* CParseStream::Create() +{ + return NULL; +} + +void CParseStream::Delete() +{ + delete this; +} + +bool CParseStream::Init() +{ + m_next = NULL; + + return true; +} + +bool CParseStream::NextChar(byte& theByte) +{ + return false; +} + +long CParseStream::GetRemainingSize() +{ + return 0; +} + +CParseStream* CParseStream::GetNext() +{ + return m_next; +} + +void CParseStream::SetNext(CParseStream* next) +{ + m_next = next; +} + +int CParseStream::GetCurLine() +{ + return 0; +} + +void CParseStream::GetCurFilename(char** theBuff) +{ + *theBuff = NULL; +} + +bool CParseStream::IsThisDefinition(void* theDefinition) +{ + return false; +} + +// +// CParsePutBack +// + +CParsePutBack::CParsePutBack() +{ +} + +CParsePutBack::~CParsePutBack() +{ +} + +CParsePutBack* CParsePutBack::Create(byte theByte, int curLine, LPCTSTR filename) +{ + CParsePutBack* curParsePutBack = new CParsePutBack(); + curParsePutBack->Init(theByte, curLine, filename); + return curParsePutBack; +} + +void CParsePutBack::Delete() +{ + if (m_curFile != NULL) + { + free(m_curFile); + m_curFile = NULL; + } + delete this; +} + +bool CParsePutBack::NextChar(byte& theByte) +{ + if (m_consumed) + { + return false; + } + theByte = m_byte; + m_consumed = true; + return true; +} + +void CParsePutBack::Init(byte theByte, int curLine, LPCTSTR filename) +{ + CParseStream::Init(); + m_consumed = false; + m_byte = theByte; + m_curLine = curLine; + if (filename != NULL) + { + m_curFile = (char*)malloc(strlen(filename) + 1); + strcpy(m_curFile, filename); + } + else + { + m_curFile = NULL; + } +} + +long CParsePutBack::GetRemainingSize() +{ + if (m_consumed) + { + return 0; + } + else + { + return 1; + } +} + +int CParsePutBack::GetCurLine() +{ + return m_curLine; +} + +void CParsePutBack::GetCurFilename(char** theBuff) +{ + if (m_curFile == NULL) + { + *theBuff = NULL; + return; + } + *theBuff = (char*)malloc(strlen(m_curFile) + 1); + strcpy(*theBuff, m_curFile); +} + +// +// CParseFile +// + +CParseFile::CParseFile() +{ +} + +CParseFile::~CParseFile() +{ +} + +CParseFile* CParseFile::Create() +{ + CParseFile* theParseFile = new CParseFile(); + + if ( !theParseFile->Init() ) + { + delete theParseFile; + return NULL; + } + + return theParseFile; +} + +CParseFile* CParseFile::Create(LPCTSTR filename, CTokenizer* tokenizer) +{ + CParseFile* theParseFile = new CParseFile(); + + if ( theParseFile->Init(filename, tokenizer) ) + return theParseFile; + + return NULL; +} + +void CParseFile::Delete() +{ + if (m_buff != NULL) + { + free(m_buff); + m_buff = NULL; + } + if (m_ownsFile && (m_fileHandle != NULL)) + { + CloseHandle(m_fileHandle); + m_fileHandle = NULL; + } + if (m_fileName != NULL) + { + free(m_fileName); + m_fileName = NULL; + } + delete this; +} + +bool CParseFile::Init() +{ + m_fileHandle = NULL; + m_buff = NULL; + m_ownsFile = false; + m_curByte = NULL; + m_curLine = 1; + m_fileName = NULL; + return CParseStream::Init(); +} + +DWORD CParseFile::GetFileSize() +{ + DWORD dwCur = SetFilePointer(m_fileHandle, 0L, NULL, FILE_CURRENT); + DWORD dwLen = SetFilePointer(m_fileHandle, 0, NULL, FILE_END); + SetFilePointer(m_fileHandle, dwCur, NULL, FILE_BEGIN); + return dwLen; +} + +void CParseFile::Read(void* buff, UINT buffsize) +{ + DWORD bytesRead; + ReadFile(m_fileHandle, buff, buffsize, &bytesRead, NULL); +} + +bool CParseFile::Init(LPCTSTR filename, CTokenizer* tokenizer) +{ + CParseStream::Init(); + m_fileName = (char*)malloc(strlen(filename) + 1); + strcpy(m_fileName, filename); + DWORD dwAccess = GENERIC_READ; + DWORD dwShareMode = FILE_SHARE_WRITE | FILE_SHARE_READ; + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = 0; + DWORD dwCreateFlag = OPEN_EXISTING; + + m_fileHandle = CreateFile(filename, dwAccess, dwShareMode, &sa, dwCreateFlag, FILE_ATTRIBUTE_NORMAL, NULL); + + if (m_fileHandle == (HANDLE)-1) + { + tokenizer->Error(TKERR_INCLUDE_FILE_NOTFOUND); + Init(); + + return false; + } + + m_filesize = GetFileSize(); + m_buff = (byte*)malloc(m_filesize); + if (m_buff == NULL) + { + tokenizer->Error(TKERR_BUFFERCREATE); + Init(); + return false; + } + Read(m_buff, m_filesize); + m_curByte = 0; + m_curPos = 1; + m_ownsFile = true; + m_curLine = 1; + + return true; +} + +long CParseFile::GetRemainingSize() +{ + return m_filesize - m_curByte; +} + +bool CParseFile::NextChar(byte& theByte) +{ + if (m_curByte < m_filesize) + { + if (m_buff[m_curByte] == '\n') + { + m_curLine += 1; + m_curPos = 1; + } + else + { + m_curPos++; + } + theByte = m_buff[m_curByte++]; + return true; + } + else + { + return false; + } +} + +int CParseFile::GetCurLine() +{ + return m_curLine; +} + +void CParseFile::GetCurFilename(char** theBuff) +{ + *theBuff = NULL; + if (m_fileName != NULL) + { + *theBuff = (char*)malloc(strlen(m_fileName) + 1); + strcpy(*theBuff, m_fileName); + } +} + +// +// CParseMemory +// + +CParseMemory::CParseMemory() +{ +} + +CParseMemory::~CParseMemory() +{ +} + +CParseMemory* CParseMemory::Create(byte* data, long datasize) +{ + CParseMemory* curParse = new CParseMemory(); + curParse->Init(data, datasize); + return curParse; +} + +void CParseMemory::Delete() +{ + delete this; +} + +bool CParseMemory::NextChar(byte& theByte) +{ + if (m_offset < m_datasize) + { + if (m_data[m_offset] == '\n') + { + m_curLine += 1; + m_curPos = 1; + } + else + { + m_curPos++; + } + theByte = m_data[m_offset++]; + return true; + } + else + { + return false; + } +} + +void CParseMemory::Init(byte* data, long datasize) +{ + m_data = data; + m_curLine = 1; + m_curPos = 1; + m_offset = 0; + m_datasize = datasize; +} + +long CParseMemory::GetRemainingSize() +{ + return m_datasize - m_offset; +} + +int CParseMemory::GetCurLine() +{ + return m_curLine; +} + +void CParseMemory::GetCurFilename(char** theBuff) +{ + *theBuff = NULL; +} + +// +// CParseBlock +// + +CParseBlock::CParseBlock() +{ +} + +CParseBlock::~CParseBlock() +{ +} + +CParseBlock* CParseBlock::Create(byte* data, long datasize) +{ + CParseBlock* curParse = new CParseBlock(); + curParse->Init(data, datasize); + return curParse; +} + +void CParseBlock::Delete() +{ + if (m_data != NULL) + { + free(m_data); + m_data = NULL; + } + delete this; +} + +void CParseBlock::Init(byte* data, long datasize) +{ + m_data = (byte*)malloc(datasize); + memcpy(m_data, data, datasize); + m_curLine = 1; + m_curPos = 1; + m_offset = 0; + m_datasize = datasize; +} + +// +// CParseToken +// + +CParseToken::CParseToken() +{ +} + +CParseToken::~CParseToken() +{ +} + +CParseToken* CParseToken::Create(CToken* token) +{ + CParseToken* curParse = new CParseToken(); + curParse->Init(token); + return curParse; +} + +void CParseToken::Delete() +{ + if (m_data != NULL) + { + free(m_data); + m_data = NULL; + } + delete this; +} + +bool CParseToken::NextChar(byte& theByte) +{ + if (m_offset < m_datasize) + { + if (m_data[m_offset] == '\n') + { + m_curLine += 1; + m_curPos = 1; + } + else + { + m_curPos++; + } + theByte = m_data[m_offset++]; + return true; + } + else + { + return false; + } +} + +void CParseToken::Init(CToken* token) +{ + LPCTSTR tokenString = token->GetStringValue(); + m_datasize = strlen(tokenString); + if (m_datasize > 0) + { + m_data = (byte*) malloc(m_datasize); + memcpy(m_data, tokenString, m_datasize); + } + else + { + m_data = NULL; + } + m_curLine = 1; + m_curPos = 1; + m_offset = 0; + token->Delete(); +} + +long CParseToken::GetRemainingSize() +{ + return m_datasize - m_offset; +} + +int CParseToken::GetCurLine() +{ + return m_curLine; +} + +void CParseToken::GetCurFilename(char** theBuff) +{ + *theBuff = NULL; +} + +// +// CParseDefine +// + +CParseDefine::CParseDefine() +{ +} + +CParseDefine::~CParseDefine() +{ +} + +CParseDefine* CParseDefine::Create(CDirectiveSymbol* definesymbol) +{ + CParseDefine* retval = new CParseDefine(); + retval->Init(definesymbol); + return retval; +} + +void CParseDefine::Delete() +{ + CParseMemory::Delete(); +} + +void CParseDefine::Init(CDirectiveSymbol* definesymbol) +{ + CParseMemory::Init((byte*)definesymbol->GetValue(), strlen(definesymbol->GetValue())); + m_defineSymbol = definesymbol; +} + +bool CParseDefine::IsThisDefinition(void* theDefinition) +{ + return (CDirectiveSymbol*)theDefinition == m_defineSymbol; +} + +// +// CToken +// + +CToken::CToken() +{ +} + +CToken::~CToken() +{ +} + +CToken* CToken::Create() +{ + CToken* theToken = new CToken(); + theToken->Init(); + return theToken; +} + +void CToken::Delete() +{ + if (m_string != NULL) + { + free(m_string); + m_string = NULL; + } + delete this; +} + +void CToken::Init() +{ + m_next = NULL; + m_string = NULL; +} + +void CToken::SetNext(CToken* theToken) +{ + m_next = theToken; +} + +CToken* CToken::GetNext() +{ + return m_next; +} + +int CToken::GetType() +{ + return TK_EOF; +} + +int CToken::GetIntValue() +{ + return 0; +} + +LPCTSTR CToken::GetStringValue() +{ + if (m_string == NULL) + { + return ""; + } + return m_string; +} + +float CToken::GetFloatValue() +{ + return 0.0; +} + +// +// CCharToken +// + +CCharToken::CCharToken() +{ +} + +CCharToken::~CCharToken() +{ +} + +CCharToken* CCharToken::Create(byte theByte) +{ + CCharToken* theToken = new CCharToken(); + theToken->Init(theByte); + return theToken; +} + +void CCharToken::Delete() +{ + CToken::Delete(); +} + +void CCharToken::Init(byte theByte) +{ + CToken::Init(); + char charString[10]; + switch(theByte) + { + case '\0': + strcpy(charString, "\\0"); + break; + case '\n': + strcpy(charString, "\\n"); + break; + case '\\': + strcpy(charString, "\\\\"); + break; + case '\'': + strcpy(charString, "\\'"); + break; + case '\?': + strcpy(charString, "\\?"); + break; + case '\a': + strcpy(charString, "\\a"); + break; + case '\b': + strcpy(charString, "\\b"); + break; + case '\f': + strcpy(charString, "\\f"); + break; + case '\r': + strcpy(charString, "\\r"); + break; + case '\t': + strcpy(charString, "\\t"); + break; + case '\v': + strcpy(charString, "\\v"); + break; + default: + charString[0] = (char)theByte; + charString[1] = '\0'; + break; + } + m_string = (char*)malloc(strlen(charString) + 1); + strcpy(m_string, charString); +} + +int CCharToken::GetType() +{ + return TK_CHAR; +} + +// +// CStringToken +// + +CStringToken::CStringToken() +{ +} + +CStringToken::~CStringToken() +{ +} + +CStringToken* CStringToken::Create(LPCTSTR theString) +{ + CStringToken* theToken = new CStringToken(); + theToken->Init(theString); + return theToken; +} + +void CStringToken::Delete() +{ + CToken::Delete(); +} + +void CStringToken::Init(LPCTSTR theString) +{ + CToken::Init(); + m_string = (char*)malloc(strlen(theString) + 1); +// ASSERT(m_string); + strcpy(m_string, theString); +} + +int CStringToken::GetType() +{ + return TK_STRING; +} + +// +// CIntToken +// + +CIntToken::CIntToken() +{ +} + +CIntToken::~CIntToken() +{ +} + +CIntToken* CIntToken::Create(long value) +{ + CIntToken* theToken = new CIntToken(); + theToken->Init(value); + return theToken; +} + +void CIntToken::Delete() +{ + CToken::Delete(); +} + +void CIntToken::Init(long value) +{ + CToken::Init(); + m_value = value; +} + +int CIntToken::GetType() +{ + return TK_INT; +} + +int CIntToken::GetIntValue() +{ + return m_value; +} + +float CIntToken::GetFloatValue() +{ + return (float)m_value; +} + +LPCTSTR CIntToken::GetStringValue() +{ + if (m_string != NULL) + { + free(m_string); + m_string = NULL; + } + char temp[128]; + sprintf(temp, "%d", m_value); + m_string = (char*)malloc(strlen(temp) + 1); + strcpy(m_string, temp); + return m_string; +} + +// +// CFloatToken +// + +CFloatToken::CFloatToken() +{ +} + +CFloatToken::~CFloatToken() +{ +} + +CFloatToken* CFloatToken::Create(float value) +{ + CFloatToken* theToken = new CFloatToken(); + theToken->Init(value); + return theToken; +} + +void CFloatToken::Delete() +{ + CToken::Delete(); +} + +void CFloatToken::Init(float value) +{ + CToken::Init(); + m_value = value; +} + +int CFloatToken::GetType() +{ + return TK_FLOAT; +} + +float CFloatToken::GetFloatValue() +{ + return m_value; +} + +LPCTSTR CFloatToken::GetStringValue() +{ + if (m_string != NULL) + { + free(m_string); + m_string = NULL; + } + char temp[128]; + sprintf(temp, "%g", m_value); + m_string = (char*)malloc(strlen(temp) + 1); + strcpy(m_string, temp); + return m_string; +} + +// +// CIdentifierToken +// + +CIdentifierToken::CIdentifierToken() +{ +} + +CIdentifierToken::~CIdentifierToken() +{ +} + +CIdentifierToken* CIdentifierToken::Create(LPCTSTR name) +{ + CIdentifierToken* theToken = new CIdentifierToken(); + theToken->Init(name); + return theToken; +} + +void CIdentifierToken::Delete() +{ + CToken::Delete(); +} + +void CIdentifierToken::Init(LPCTSTR name) +{ + CToken::Init(); + m_string = (char*)malloc(strlen(name) + 1); +// ASSERT(m_string); + strcpy(m_string, name); +} + +int CIdentifierToken::GetType() +{ + return TK_IDENTIFIER; +} + +// +// CCommentToken +// + +CCommentToken::CCommentToken() +{ +} + +CCommentToken::~CCommentToken() +{ +} + +CCommentToken* CCommentToken::Create(LPCTSTR name) +{ + CCommentToken* theToken = new CCommentToken(); + theToken->Init(name); + return theToken; +} + +void CCommentToken::Delete() +{ + CToken::Delete(); +} + +void CCommentToken::Init(LPCTSTR name) +{ + CToken::Init(); + m_string = (char*)malloc(strlen(name) + 1); +// ASSERT(m_string); + strcpy(m_string, name); +} + +int CCommentToken::GetType() +{ + return TK_COMMENT; +} + +// +// CUserToken +// + +CUserToken::CUserToken() +{ +} + +CUserToken::~CUserToken() +{ +} + +CUserToken* CUserToken::Create(int value, LPCTSTR string) +{ + CUserToken* theToken = new CUserToken(); + theToken->Init(value, string); + return theToken; +} + +void CUserToken::Delete() +{ + CToken::Delete(); +} + +void CUserToken::Init(int value, LPCTSTR string) +{ + CToken::Init(); + m_value = value; + m_string = (char*)malloc(strlen(string) + 1); + strcpy(m_string, string); +} + +int CUserToken::GetType() +{ + return m_value; +} + +// +// CUndefinedToken +// + +CUndefinedToken::CUndefinedToken() +{ +} + +CUndefinedToken::~CUndefinedToken() +{ +} + +CUndefinedToken* CUndefinedToken::Create(LPCTSTR string) +{ + CUndefinedToken* theToken = new CUndefinedToken(); + theToken->Init(string); + return theToken; +} + +void CUndefinedToken::Delete() +{ + CToken::Delete(); +} + +void CUndefinedToken::Init(LPCTSTR string) +{ + CToken::Init(); + m_string = (char*)malloc(strlen(string) + 1); + strcpy(m_string, string); +} + +int CUndefinedToken::GetType() +{ + return TK_UNDEFINED; +} + +// +// CTokenizerState +// + +CTokenizerState::CTokenizerState() +{ +} + +CTokenizerState::~CTokenizerState() +{ +} + +CTokenizerState* CTokenizerState::Create(bool skip) +{ + CTokenizerState* retval = new CTokenizerState(); + retval->Init(skip); + return retval; +} + +void CTokenizerState::Init(bool skip) +{ + m_next = NULL; + m_skip = skip; + m_elseHit = false; +} + +void CTokenizerState::Delete() +{ + delete this; +} + +CTokenizerState* CTokenizerState::GetNext() +{ + return m_next; +} + +bool CTokenizerState::ProcessElse() +{ + if (!m_elseHit) + { + m_elseHit = true; + m_skip = !m_skip; + } + return m_elseHit; +} + +void CTokenizerState::SetNext(CTokenizerState* next) +{ + m_next = next; +} + +bool CTokenizerState::Skipping() +{ + return m_skip; +} + +// +// CTokenizerHolderState +// + +CTokenizerHolderState::CTokenizerHolderState() +{ +} + +CTokenizerHolderState::~CTokenizerHolderState() +{ +} + +CTokenizerHolderState* CTokenizerHolderState::Create() +{ + CTokenizerHolderState* retval = new CTokenizerHolderState(); + retval->Init(); + return retval; +} + +void CTokenizerHolderState::Init() +{ + CTokenizerState::Init(true); +} + +void CTokenizerHolderState::Delete() +{ + delete this; +} + +bool CTokenizerHolderState::ProcessElse() +{ + if (!m_elseHit) + { + m_elseHit = true; + } + return m_elseHit; +} + +// +// CKeywordTable +// + +CKeywordTable::CKeywordTable(CTokenizer* tokenizer, keywordArray_t* keywords) +{ + m_tokenizer = tokenizer; + m_holdKeywords = tokenizer->SetKeywords(keywords); +} + +CKeywordTable::~CKeywordTable() +{ + m_tokenizer->SetKeywords(m_holdKeywords); +} + +// +// CTokenizer +// + +CTokenizer::CTokenizer() +{ +} + +CTokenizer::~CTokenizer() +{ +} + +CTokenizer* CTokenizer::Create(UINT dwFlags) +{ + CTokenizer* theTokenizer = new CTokenizer(); + theTokenizer->Init(dwFlags); + return theTokenizer; +} + +void CTokenizer::Delete() +{ + while (m_curParseStream != NULL) + { + CParseStream* curStream = m_curParseStream; + m_curParseStream = curStream->GetNext(); + curStream->Delete(); + } + if (m_symbolLookup != NULL) + { + m_symbolLookup->Delete(); + m_symbolLookup = NULL; + } + while (m_nextToken != NULL) + { + CToken* curToken = m_nextToken; + m_nextToken = curToken->GetNext(); + curToken->Delete(); + } + while (m_state != NULL) + { + Error(TKERR_UNMATCHED_DIRECTIVE); + CTokenizerState* curState = m_state; + m_state = curState->GetNext(); + curState->Delete(); + } + +/* if (m_lastErrMsg != NULL) + { + free(m_lastErrMsg); + m_lastErrMsg = NULL; + }*/ + delete this; +} + +void CTokenizer::Error(int theError) +{ + char errString[128]; + char lookupstring[128]; + int i = 0; + while ((errorMessages[i].m_tokenvalue != TKERR_USERERROR) && (errorMessages[i].m_tokenvalue != theError)) + { + i++; + } + if ((errorMessages[i].m_tokenvalue == TKERR_USERERROR) && (m_errors != NULL)) + { + i = 0; + while ((m_errors[i].m_tokenvalue != TK_EOF) && (m_errors[i].m_tokenvalue != theError)) + { + i++; + } + strcpy(lookupstring, m_errors[i].m_keyword); + } + else + { + strcpy(lookupstring, errorMessages[i].m_keyword); + } + sprintf(errString, "Error -- %d, %s", theError, lookupstring); + Error(errString, theError); +} + +void CTokenizer::Error(int theError, LPCTSTR errString) +{ + char errstring[128]; + char lookupstring[128]; + int i = 0; + while ((errorMessages[i].m_tokenvalue != TKERR_USERERROR) && (errorMessages[i].m_tokenvalue != theError)) + { + i++; + } + if ((errorMessages[i].m_tokenvalue == TKERR_USERERROR) && (m_errors != NULL)) + { + i = 0; + while ((m_errors[i].m_tokenvalue != TK_EOF) && (m_errors[i].m_tokenvalue != theError)) + { + i++; + } + strcpy(lookupstring, m_errors[i].m_keyword); + } + else + { + strcpy(lookupstring, errorMessages[i].m_keyword); + } + sprintf(errstring, "Error -- %d, %s - %s", theError, lookupstring, errString); + Error(errstring, theError); +} + +void CTokenizer::Error(LPCTSTR errString, int theError) +{ + if (m_errorProc != NULL) + { + m_errorProc(errString); + } +#ifdef USES_MODULES + else + { + ReportError(theError, errString); + } +#endif +} + +bool CTokenizer::AddParseFile(LPCTSTR filename) +{ + CParseStream* newStream = CParseFile::Create(filename, this); + + if ( newStream != NULL ) + { + newStream->SetNext(m_curParseStream); + m_curParseStream = newStream; + return true; + } + + return false; +} + +void CTokenizer::AddParseStream(byte* data, long datasize) +{ + CParseStream* newStream = CParseMemory::Create(data, datasize); + newStream->SetNext(m_curParseStream); + m_curParseStream = newStream; +} + +long CTokenizer::GetRemainingSize() +{ + long retval = 0; + CParseStream* curStream = m_curParseStream; + while (curStream != NULL) + { + retval += curStream->GetRemainingSize(); + curStream = curStream->GetNext(); + } + return retval; +} + +LPCTSTR CTokenizer::LookupToken(int tokenID, keywordArray_t* theTable) +{ + if (theTable == NULL) + { + theTable = m_keywords; + } + if (theTable == NULL) + { + return NULL; + } + + int i = 0; + while (theTable[i].m_tokenvalue != TK_EOF) + { + if (theTable[i].m_tokenvalue == tokenID) + { + return theTable[i].m_keyword; + } + i++; + } + return NULL; +} + +void CTokenizer::PutBackToken(CToken* theToken, bool commented, LPCTSTR addedChars, bool bIgnoreThisTokenType) +{ + if (commented) + { + CParseToken* newStream = CParseToken::Create(theToken); + newStream->SetNext(m_curParseStream); + m_curParseStream = newStream; + + if (addedChars != NULL) + { + CParsePutBack* spacer = CParsePutBack::Create(' ', 0, NULL); + spacer->SetNext(m_curParseStream); + m_curParseStream = spacer; + + CParseBlock* newBlock = CParseBlock::Create((byte*)addedChars, strlen(addedChars)); + newBlock->SetNext(m_curParseStream); + m_curParseStream = newBlock; + } + + char temp[] = "// * "; + CParseBlock* newBlock = CParseBlock::Create((byte*)temp, strlen(temp)); + newBlock->SetNext(m_curParseStream); + m_curParseStream = newBlock; + return; + } + + switch(theToken->GetType()) + { + case TK_INT: + case TK_EOF: + case TK_UNDEFINED: + case TK_FLOAT: + case TK_CHAR: + case TK_STRING: + case TK_EOL: + case TK_COMMENT: + if (!bIgnoreThisTokenType) + { + theToken->SetNext(m_nextToken); + m_nextToken = theToken; + break; + } + default: + CParseToken* newStream = CParseToken::Create(theToken); + newStream->SetNext(m_curParseStream); + m_curParseStream = newStream; + break; + } + + if (addedChars != NULL) + { + CParseBlock* newBlock = CParseBlock::Create((byte*)addedChars, strlen(addedChars)); + newBlock->SetNext(m_curParseStream); + m_curParseStream = newBlock; + } +} + +CToken* CTokenizer::GetToken(keywordArray_t* keywords, UINT onFlags, UINT offFlags) +{ + keywordArray_t* holdKeywords = SetKeywords(keywords); + CToken* retval = GetToken(onFlags, offFlags); + SetKeywords(holdKeywords); + return retval; +} + +CToken* CTokenizer::GetToken(UINT onFlags, UINT offFlags) +{ + UINT holdFlags = m_flags; + + m_flags |= onFlags; + m_flags &= (~offFlags); + CToken* theToken = NULL; + while (theToken == NULL) + { + theToken = FetchToken(); + if (theToken == NULL) + { + continue; + } + if (theToken->GetType() == TK_EOF) + { + break; + } + if (m_state != NULL) + { + if (m_state->Skipping()) + { + theToken->Delete(); + theToken = NULL; + } + } + } + + m_flags = holdFlags; + return theToken; +} + +CToken* CTokenizer::GetToEndOfLine(int tokenType) +{ + // update, if you just want the whole line returned as a string, then allow a much bigger size than + // the default string size of only 128 chars... + // + if (tokenType == TK_STRING) + { + #define iRETURN_STRING_SIZE 2048 + char theString[iRETURN_STRING_SIZE]; + theString[0] = ' '; + + for (int i = 1; i < iRETURN_STRING_SIZE; i++) + { + if (NextChar((byte&)theString[i])) + { + if (theString[i] != '\n') + { + continue; + } + PutBackChar(theString[i]); + } + theString[i] = '\0'; + + return CStringToken::Create(theString); + } + + // line would maks a string too big to fit in buffer... + // + Error(TKERR_STRINGLENGTHEXCEEDED); + } + else + { + char theString[MAX_IDENTIFIER_LENGTH]; + theString[0] = ' '; + while (theString[0] == ' ') + { + if (!NextChar((byte&)theString[0])) + { + return NULL; + } + } + for (int i = 1; i < MAX_IDENTIFIER_LENGTH; i++) + { + if (NextChar((byte&)theString[i])) + { + if (theString[i] != '\n') + { + continue; + } + PutBackChar(theString[i]); + } + theString[i] = '\0'; + switch(tokenType) + { + case TK_COMMENT: + return CCommentToken::Create(theString); + case TK_IDENTIFIER: + default: + return CIdentifierToken::Create(theString); + } + } + Error(TKERR_IDENTIFIERLENGTHEXCEEDED); + } + return NULL; +} + +void CTokenizer::SkipToLineEnd() +{ + byte theByte; + while(NextChar(theByte)) + { + if (theByte == '\n') + { + break; + } + } +} + +CToken* CTokenizer::FetchToken() +{ + if (m_nextToken != NULL) + { + CToken* curToken = m_nextToken; + m_nextToken = curToken->GetNext(); + curToken->SetNext(NULL); + return curToken; + } + byte theByte; + CToken* theToken = NULL; + + while (true) + { + if (!NextChar(theByte)) + { + return CToken::Create(); + } + if (theByte <= ' ') + { + if ((theByte == '\n') && ((TKF_USES_EOL & m_flags) != 0)) + { + return CUserToken::Create(TK_EOL, "-EOLN-"); + } + continue; + } + switch(theByte) + { + case '#': + if ((m_flags & TKF_IGNOREDIRECTIVES) == 0) + { + theToken = HandleDirective(); + } + else + { + if ((m_flags & TKF_NODIRECTIVES) != 0) + { + return HandleSymbol('#'); + } + SkipToLineEnd(); + } + break; + case '/': + theToken = HandleSlash(); + break; + case '"': + theToken = HandleString(); + break; + case '\'': + theToken = HandleQuote(); + break; + default: + if (((theByte >= 'a') && (theByte <= 'z')) + || ((theByte >= 'A') && (theByte <= 'Z')) + || ((theByte == '_') && ((m_flags & TKF_NOUNDERSCOREINIDENTIFIER) == 0))) + { + theToken = HandleIdentifier(theByte); + } + else if (((m_flags & TKF_NUMERICIDENTIFIERSTART) != 0) && (theByte >= '0') && (theByte <= '9')) + { + theToken = HandleIdentifier(theByte); + } + else if (((theByte >= '0') && (theByte <= '9')) || (theByte == '-')) + { + theToken = HandleNumeric(theByte); + } + else if (theByte == '.') + { + theToken = HandleDecimal(); + } + else if (theByte <= ' ') + { + break; + } + else + { + theToken = HandleSymbol(theByte); + } + } + if (theToken != NULL) + { + return theToken; + } + } +} + +bool CTokenizer::NextChar(byte& theByte) +{ + while (m_curParseStream != NULL) + { + if (m_curParseStream->NextChar(theByte)) + { + return true; + } + CParseStream* curParseStream = m_curParseStream; + m_curParseStream = curParseStream->GetNext(); + curParseStream->Delete(); + } + return false; +} + +bool CTokenizer::RequireToken(int tokenType) +{ + CToken* theToken = GetToken(); + bool retValue = theToken->GetType() == tokenType; + theToken->Delete(); + return retValue; +} + +void CTokenizer::ScanUntilToken(int tokenType) +{ + CToken* curToken; + int tokenValue = TK_UNDEFINED; + while (tokenValue != tokenType) + { + curToken = GetToken(); + tokenValue = curToken->GetType(); + if (tokenValue == TK_EOF) + { + PutBackToken(curToken); + break; + } + if (tokenValue == tokenType) + { + PutBackToken(curToken); + } + else + { + curToken->Delete(); + } + } +} + +void CTokenizer::Init(UINT dwFlags) +{ + m_symbolLookup = NULL; + m_nextToken = NULL; + m_curParseStream = NULL; + m_keywords = NULL; + m_symbols = NULL; + m_errors = NULL; + m_state = NULL; + m_flags = dwFlags; + m_errorProc = NULL; +} + +void CTokenizer::SetErrorProc(LPTokenizerErrorProc errorProc) +{ + m_errorProc = errorProc; +} + +void CTokenizer::SetAdditionalErrors(keywordArray_t* theErrors) +{ + m_errors = theErrors; +} + +keywordArray_t* CTokenizer::SetKeywords(keywordArray_t* theKeywords) +{ + keywordArray_t* retval = m_keywords; + m_keywords = theKeywords; + return retval; +} + +void CTokenizer::SetSymbols(keywordArray_t* theSymbols) +{ + m_symbols = theSymbols; + if (m_symbolLookup != NULL) + { + m_symbolLookup->Delete(); + m_symbolLookup = NULL; + } + int i = 0; + if (theSymbols == NULL) + { + return; + } + while(theSymbols[i].m_tokenvalue != TK_EOF) + { + InsertSymbol(theSymbols[i].m_keyword, theSymbols[i].m_tokenvalue); + i++; + } +} + +void CTokenizer::InsertSymbol(LPCTSTR theSymbol, int theValue) +{ + CSymbolLookup** curHead = &m_symbolLookup; + CSymbolLookup* curParent = NULL; + CSymbolLookup* curLookup = NULL; + + for (UINT i = 0; i < strlen(theSymbol); i++) + { + bool found = false; + curLookup = *curHead; + while (curLookup != NULL) + { + if (curLookup->GetByte() == theSymbol[i]) + { + found = true; + break; + } + curLookup = curLookup->GetNext(); + } + if (!found) + { + curLookup = CSymbolLookup::Create(theSymbol[i]); + curLookup->SetParent(curParent); + curLookup->SetNext(*curHead); + *curHead = curLookup; + } + curHead = curLookup->GetChildAddress(); + curParent = curLookup; + } + if (curLookup->GetValue() != -1) + { + Error(TKERR_DUPLICATESYMBOL); + } + curLookup->SetValue(theValue); +} + +CToken* CTokenizer::HandleString() +{ + char theString[MAX_STRING_LENGTH]; + for (int i = 0; i < MAX_STRING_LENGTH; i++) + { + if (!NextChar((byte&)theString[i])) + { + return NULL; + } + if (theString[i] == '"') + { + theString[i] = '\0'; + return CStringToken::Create(theString); + } + if (theString[i] == '\\') + { + theString[i] = Escapement(); + } + } + Error(TKERR_STRINGLENGTHEXCEEDED); + return NULL; +} + +void CTokenizer::GetCurFilename(char** filename) +{ + if (m_curParseStream == NULL) + { + *filename = (char*)malloc(1); + *filename[0] = '\0'; + return; + } + m_curParseStream->GetCurFilename(filename); +} + +int CTokenizer::GetCurLine() +{ + if (m_curParseStream == NULL) + { + return 0; + } + return m_curParseStream->GetCurLine(); +} + +void CTokenizer::PutBackChar(byte theByte, int curLine, LPCTSTR filename) +{ + CParseStream* newStream; + if (filename == NULL) + { + curLine = m_curParseStream->GetCurLine(); + char* theFile = NULL; + m_curParseStream->GetCurFilename(&theFile); + newStream = CParsePutBack::Create(theByte, curLine, theFile); + if (theFile != NULL) + { + free(theFile); + } + } + else + { + newStream = CParsePutBack::Create(theByte, curLine, filename); + } + newStream->SetNext(m_curParseStream); + m_curParseStream = newStream; +} + +byte CTokenizer::Escapement() +{ + byte theByte; + if (NextChar(theByte)) + { + switch(theByte) + { + case 'n': + return '\n'; + case '\\': + return '\\'; + case '\'': + return '\''; + case '?': + return '\?'; + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '0': + return '\0'; + // support for octal or hex sequences?? \000 or \xhhh + default: + PutBackChar(theByte); + } + } + return '\\'; +} + +bool CTokenizer::AddDefineSymbol(CDirectiveSymbol* definesymbol) +{ + CParseStream* curStream = m_curParseStream; + while(curStream != NULL) + { + if (curStream->IsThisDefinition(definesymbol)) + { + return false; + } + curStream = curStream->GetNext(); + } + CParseStream* newStream = CParseDefine::Create(definesymbol); + newStream->SetNext(m_curParseStream); + m_curParseStream = newStream; + return true; +} + +CToken* CTokenizer::TokenFromName(LPCTSTR name) +{ + CDirectiveSymbol* defineSymbol = (CDirectiveSymbol*)m_defines.FindSymbol(name); + if (defineSymbol != NULL) + { + if (AddDefineSymbol(defineSymbol)) + { + return FetchToken(); + } + } + if ((m_keywords != NULL) && ((m_flags & TKF_IGNOREKEYWORDS) == 0)) + { + int i = 0; + if ((m_flags & TKF_NOCASEKEYWORDS) == 0) + { + while (m_keywords[i].m_tokenvalue != TK_EOF) + { + if (strcmp(m_keywords[i].m_keyword, name) == 0) + { + return CUserToken::Create(m_keywords[i].m_tokenvalue, name); + } + i++; + } + } + else + { + while (m_keywords[i].m_tokenvalue != TK_EOF) + { + if (stricmp(m_keywords[i].m_keyword, name) == 0) + { + return CUserToken::Create(m_keywords[i].m_tokenvalue, name); + } + i++; + } + } + } + return CIdentifierToken::Create(name); +} + +int CTokenizer::DirectiveFromName(LPCTSTR name) +{ + if (directiveKeywords != NULL) + { + int i = 0; + while (directiveKeywords[i].m_tokenvalue != TK_EOF) + { + if (strcmp(directiveKeywords[i].m_keyword, name) == 0) + { + return directiveKeywords[i].m_tokenvalue; + } + i++; + } + } + return -1; +} + +CToken* CTokenizer::HandleIdentifier(byte theByte) +{ + char theString[MAX_IDENTIFIER_LENGTH]; + theString[0] = theByte; + for (int i = 1; i < MAX_IDENTIFIER_LENGTH; i++) + { + if (NextChar((byte&)theString[i])) + { + if (((theString[i] != '_') || ((m_flags & TKF_NOUNDERSCOREINIDENTIFIER) == 0)) && + ((theString[i] != '-') || ((m_flags & TKF_NODASHINIDENTIFIER) == 0))) + { + if (((theString[i] >= 'A') && (theString[i] <= 'Z')) + || ((theString[i] >= 'a') && (theString[i] <= 'z')) + || ((theString[i] >= '0') && (theString[i] <= '9')) + || (theString[i] == '_') || (theString[i] == '-')) + { + continue; + } + } + PutBackChar(theString[i]); + } + theString[i] = '\0'; + return TokenFromName(theString); + } + Error(TKERR_IDENTIFIERLENGTHEXCEEDED); + return NULL; +} + +CToken* CTokenizer::HandleSlash() +{ + byte theByte; + if (!NextChar(theByte)) + { + return NULL; + } + if (theByte == '/') + { + if (m_flags & TKF_COMMENTTOKENS) + { + return GetToEndOfLine(TK_COMMENT); + } + SkipToLineEnd(); + return NULL; + } + if (theByte == '*') + { + if (m_flags & TKF_COMMENTTOKENS) + { + char theString[MAX_IDENTIFIER_LENGTH + 1]; + theString[0] = ' '; + while (theString[0] == ' ') + { + if (!NextChar((byte&)theString[0])) + { + return NULL; + } + } + for (int i = 1; i < MAX_IDENTIFIER_LENGTH; i++) + { + if (NextChar((byte&)theString[i])) + { + if (theString[i] != '*') + { + continue; + } + i++; + if (NextChar((byte&)theString[i])) + { + if (theString[i] == '/') + { + i--; + theString[i] = '\0'; + return CCommentToken::Create(theString); + } + } + } + } + Error(TKERR_IDENTIFIERLENGTHEXCEEDED); + return NULL; + } + while(NextChar(theByte)) + { + while(theByte == '*') + { + if (!NextChar(theByte)) + { + break; + } + if (theByte == '/') + { + return NULL; + } + } + } + return NULL; + } + PutBackChar(theByte); + return HandleSymbol('/'); +} + +CToken* CTokenizer::HandleNumeric(byte theByte) +{ + bool thesign = theByte == '-'; + if (thesign) + { + if (!NextChar(theByte)) + { + return HandleSymbol('-'); + } + if (theByte == '.') + { + return HandleDecimal(thesign); + } + if ((theByte < '0') || (theByte > '9')) + { + PutBackChar(theByte); + return HandleSymbol('-'); + } + } + if (theByte == '0') + { + return HandleOctal(thesign); + } + long value = 0; + bool digithit = false; + while((theByte >= '0') && (theByte <= '9')) + { + value = (value * 10) + (theByte - '0'); + if (!NextChar(theByte)) + { + if (thesign) + { + value = -value; + } + return CIntToken::Create(value); + } + digithit = true; + } + if (theByte == '.') + { + if (digithit) + { + return HandleFloat(thesign, value); + } + if (thesign) + { + PutBackChar(theByte); + theByte = '-'; + } + return HandleSymbol(theByte); + } + PutBackChar(theByte); + if (thesign) + { + value = -value; + } + return CIntToken::Create(value); +} + +CToken* CTokenizer::HandleOctal(bool thesign) +{ + byte theByte; + int value = 0; + + if (!NextChar(theByte)) + { + return CIntToken::Create(value); + } + if (theByte == '.') + { + return HandleDecimal(thesign); + } + if ((theByte == 'x') || (theByte == 'X')) + { + return HandleHex(thesign); + } + while(true) + { + if((theByte >= '0') && (theByte <='7')) + { + value = (value * 8) + (theByte - '0'); + } + else + { + PutBackChar(theByte); + if (thesign) + { + value = -value; + } + return CIntToken::Create(value); + } + if (!NextChar(theByte)) + { + if (thesign) + { + value = -value; + } + return CIntToken::Create(value); + } + } +} + +CToken* CTokenizer::HandleHex(bool thesign) +{ + int value = 0; + + while (true) + { + byte theByte; + if (!NextChar(theByte)) + { + if (thesign) + { + value = -value; + } + return CIntToken::Create(value); + } + switch (theByte) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + theByte = theByte - '0'; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + theByte = theByte - 'A' + 10; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + theByte = theByte - 'a' + 10; + break; + default: + PutBackChar(theByte); + if (thesign) + { + value = -value; + } + return CIntToken::Create(value); + } + value = (value * 16) + theByte; + } +} + +CToken* CTokenizer::HandleDecimal(bool thesign) +{ + byte theByte; + if (!NextChar(theByte)) + { + if (thesign) + { + PutBackChar('.'); + return HandleSymbol('-'); + } + HandleSymbol('.'); + } + PutBackChar(theByte); + if ((theByte <= '9') && (theByte >= '0')) + { + return HandleFloat(thesign); + } + if (thesign) + { + PutBackChar('.'); + theByte = '-'; + } + else + { + theByte = '.'; + } + return HandleSymbol(theByte); +} + +CToken* CTokenizer::HandleFloat(bool thesign, long value) +{ + float lower = 1.0; + float newValue = (float)value; + byte theByte; + while(NextChar(theByte)) + { + if ((theByte >= '0') && (theByte <= '9')) + { + lower = lower / 10; + newValue = newValue + ((theByte - '0') * lower); + continue; + } + PutBackChar(theByte); + break; + } + if (thesign) + { + newValue = -newValue; + } + return CFloatToken::Create(newValue); +} + +CToken* CTokenizer::HandleQuote() +{ + byte theByte; + if (!NextChar(theByte)) + { + Error(TKERR_EXPECTED_CHAR); + return NULL; + } + if (theByte == '\\') + { + theByte = Escapement(); + } + byte dummy; + if (!NextChar(dummy)) + { + Error(TKERR_EXPECTED_CHAR); + return NULL; + } + if (dummy != '\'') + { + PutBackChar(dummy); + PutBackChar(theByte); + Error(TKERR_EXPECTED_CHAR); + return NULL; + } + return CCharToken::Create(theByte); +} + +void CTokenizer::SetFlags(UINT flags) +{ + m_flags = flags; +} + +UINT CTokenizer::GetFlags() +{ + return m_flags; +} + +CToken* CTokenizer::HandleSymbol(byte theByte) +{ + char symbolString[128]; + int curStrLen = 0; + symbolString[0] = '\0'; + bool consumed = false; + + CSymbolLookup* curLookup; + if ((m_flags & TKF_RAWSYMBOLSONLY) == 0) + { + curLookup = m_symbolLookup; + } + else + { + curLookup = NULL; + } + CSymbolLookup* lastLookup = NULL; + while(curLookup != NULL) + { + if (curLookup->GetByte() == theByte) + { + symbolString[curStrLen++] = theByte; + symbolString[curStrLen] = '\0'; + lastLookup = curLookup; + consumed = true; + if (curLookup->GetChild() == NULL) + { + break; + } + if (!NextChar(theByte)) + { + PutBackToken(CToken::Create()); + break; + } + consumed = false; + curLookup = curLookup->GetChild(); + continue; + } + curLookup = curLookup->GetNext(); + } + if ((!consumed) && (lastLookup != NULL)) + { + PutBackChar(theByte); + } + while ((lastLookup != NULL) && (lastLookup->GetValue() == -1)) + { + curStrLen--; + symbolString[curStrLen] = '\0'; + // symbolString = symbolString.Left(symbolString.GetLength() - 1); + if (lastLookup->GetParent() == NULL) + { + if ((m_flags & TKF_WANTUNDEFINED) == 0) + { + Error(TKERR_UNRECOGNIZEDSYMBOL); + } + } + else + { + PutBackChar(lastLookup->GetByte()); + } + lastLookup = lastLookup->GetParent(); + } + if (lastLookup == NULL) + { + if ((m_flags & TKF_WANTUNDEFINED) == 0) + { + return NULL; + } + curStrLen = 0; + symbolString[curStrLen++] = char(theByte); + symbolString[curStrLen] = '\0'; + if ((m_flags & TKF_WIDEUNDEFINEDSYMBOLS) != 0) + { + while (true) + { + if (!NextChar(theByte)) + { + PutBackToken(CToken::Create()); + break; + } + if (theByte == ' ') + { + break; + } + if (((theByte >= 'a') && (theByte <= 'z')) || ((theByte >= 'A') && (theByte <= 'Z')) || + ((theByte >= '0') && (theByte <= '9'))) + { + PutBackChar(theByte); + break; + } + if (theByte < ' ') + { + if ((theByte == '\n') && ((TKF_USES_EOL & m_flags) != 0)) + { + PutBackToken(CUserToken::Create(TK_EOL, "-EOLN-")); + break; + } + continue; + } + symbolString[curStrLen++] = theByte; + symbolString[curStrLen] = '\0'; + } + } + return CUndefinedToken::Create(symbolString); + } + return CUserToken::Create(lastLookup->GetValue(), symbolString); +} + +CToken* CTokenizer::HandleDirective() +{ + int tokenValue = 0; + CToken* theToken = FetchToken(); + if (theToken->GetType() == TK_EOF) + { + return theToken; + } + if (theToken->GetType() != TK_IDENTIFIER) + { + Error(TKERR_INVALID_DIRECTIVE); + theToken->Delete(); + SkipToLineEnd(); + return NULL; + } + + CDirectiveSymbol* curSymbol; + CTokenizerState* state; + int theDirective = DirectiveFromName(theToken->GetStringValue()); + theToken->Delete(); + byte theByte; + switch(theDirective) + { + case DIR_INCLUDE: + if ((m_state != NULL) && (m_state->Skipping())) + { + break; + } + theToken = GetToken(); + if (theToken->GetType() != TK_STRING) + { + Error(TKERR_INCLUDE_FILE_NOTFOUND); + theToken->Delete(); + SkipToLineEnd(); + break; + } + AddParseFile(theToken->GetStringValue()); + theToken->Delete(); + break; + case DIR_IFDEF: + if ((m_state != NULL) && (m_state->Skipping())) + { + state = CTokenizerHolderState::Create(); + state->SetNext(m_state); + m_state = state; + break; + } + theToken = GetToken(); + if (theToken->GetType() != TK_IDENTIFIER) + { + Error(TKERR_EXPECTED_IDENTIFIER); + theToken->Delete(); + SkipToLineEnd(); + break; + } + state = CTokenizerState::Create(m_defines.FindSymbol(theToken->GetStringValue()) == NULL); + theToken->Delete(); + state->SetNext(m_state); + m_state = state; + break; + case DIR_IFNDEF: + if ((m_state != NULL) && (m_state->Skipping())) + { + state = CTokenizerHolderState::Create(); + state->SetNext(m_state); + m_state = state; + break; + } + theToken = GetToken(); + if (theToken->GetType() != TK_IDENTIFIER) + { + Error(TKERR_EXPECTED_IDENTIFIER); + theToken->Delete(); + SkipToLineEnd(); + break; + } + state = CTokenizerState::Create(m_defines.FindSymbol(theToken->GetStringValue()) != NULL); + theToken->Delete(); + state->SetNext(m_state); + m_state = state; + break; + case DIR_ENDIF: + if (m_state == NULL) + { + Error(TKERR_UNMATCHED_DIRECTIVE); + break; + } + state = m_state; + m_state = state->GetNext(); + state->Delete(); + break; + case DIR_ELSE: + if (m_state == NULL) + { + Error(TKERR_UNMATCHED_DIRECTIVE); + break; + } + if (!m_state->ProcessElse()) + { + Error(TKERR_UNMATCHED_DIRECTIVE); + break; + } + break; + case DIR_DEFINE: + if ((m_state != NULL) && (m_state->Skipping())) + { + break; + } + theToken = GetToken(); + if (theToken->GetType() != TK_IDENTIFIER) + { + Error(TKERR_EXPECTED_IDENTIFIER); + theToken->Delete(); + SkipToLineEnd(); + break; + } + // blind add - should check first for value changes + { + curSymbol = CDirectiveSymbol::Create(theToken->GetStringValue()); + char temp[128]; + int tempsize = 0; + while(NextChar(theByte)) + { + if (theByte == '\n') + { + break; + } + temp[tempsize++] = char(theByte); + } + temp[tempsize] = '\0'; + curSymbol->SetValue(temp); + if (!m_defines.AddSymbol(curSymbol)) + { + curSymbol->Delete(); + } + } + break; + case DIR_UNDEFINE: + if ((m_state != NULL) && (m_state->Skipping())) + { + break; + } + theToken = GetToken(); + if (theToken->GetType() != TK_IDENTIFIER) + { + Error(TKERR_EXPECTED_IDENTIFIER); + theToken->Delete(); + SkipToLineEnd(); + break; + } + m_defines.RemoveSymbol(theToken->GetStringValue()); + break; + default: + Error(TKERR_INVALID_DIRECTIVE); + SkipToLineEnd(); + break; + } + return NULL; +} + +COLORREF CTokenizer::ParseRGB() +{ + CToken* theToken = GetToken(); + if (theToken->GetType() != TK_INT) + { + Error(TKERR_EXPECTED_INTEGER); + theToken->Delete(); + return RGB(0, 0, 0); + } + int red = theToken->GetIntValue(); + theToken->Delete(); + theToken = GetToken(); + if (theToken->GetType() != TK_INT) + { + Error(TKERR_EXPECTED_INTEGER); + theToken->Delete(); + return RGB(0, 0, 0); + } + int green = theToken->GetIntValue(); + theToken->Delete(); + theToken = GetToken(); + if (theToken->GetType() != TK_INT) + { + Error(TKERR_EXPECTED_INTEGER); + theToken->Delete(); + return RGB(0, 0, 0); + } + int blue = theToken->GetIntValue(); + theToken->Delete(); + return RGB(red, green, blue); +} + +// +// CSymbolLookup +// + +CSymbolLookup::CSymbolLookup() +{ +} + +CSymbolLookup::~CSymbolLookup() +{ +} + +CSymbolLookup* CSymbolLookup::Create(byte theByte) +{ + CSymbolLookup* curLookup = new CSymbolLookup(); + curLookup->Init(theByte); + return curLookup; +} + +void CSymbolLookup::Delete() +{ + if (m_sibling != NULL) + { + m_sibling->Delete(); + m_sibling = NULL; + } + if (m_child != NULL) + { + m_child->Delete(); + m_child = NULL; + } + delete this; +} + +void CSymbolLookup::Init(byte theByte) +{ + m_parent = NULL; + m_child = NULL; + m_sibling = NULL; + m_value = -1; + m_byte = theByte; +} + +CSymbolLookup* CSymbolLookup::GetNext() +{ + return m_sibling; +} + +void CSymbolLookup::SetNext(CSymbolLookup* next) +{ + m_sibling = next; +} + +void CSymbolLookup::SetParent(CSymbolLookup* parent) +{ + m_parent = parent; +} + +void CSymbolLookup::SetValue(int value) +{ + m_value = value; +} + +int CSymbolLookup::GetValue() +{ + return m_value; +} + +byte CSymbolLookup::GetByte() +{ + return m_byte; +} + +CSymbolLookup** CSymbolLookup::GetChildAddress() +{ + return &m_child; +} + +CSymbolLookup* CSymbolLookup::GetChild() +{ + return m_child; +} + +CSymbolLookup* CSymbolLookup::GetParent() +{ + return m_parent; +} \ No newline at end of file diff --git a/code/icarus/module.h b/code/icarus/module.h new file mode 100644 index 0000000..6ae5319 --- /dev/null +++ b/code/icarus/module.h @@ -0,0 +1 @@ +//This needs to be present to make the tokenizer happy... \ No newline at end of file diff --git a/code/icarus/sequencer.h b/code/icarus/sequencer.h index 6461e35..fd45fd6 100644 --- a/code/icarus/sequencer.h +++ b/code/icarus/sequencer.h @@ -15,6 +15,7 @@ #include #include #include +#include #pragma warning (pop) #pragma warning (disable:4503) // decorated name length xceeded, name was truncated using namespace std; @@ -95,11 +96,12 @@ public: int Save( void ); int Load( void ); +// moved to public on 2/12/2 to allow calling during shutdown + int Recall( void ); protected: int EvaluateConditional( CBlock *block ); - int Recall( void ); int Route( CSequence *sequence, bstream_t *bstream ); int Flush( CSequence *owner ); void Interrupt( void ); @@ -115,7 +117,8 @@ protected: CSequence *GetSequence( int id ); //NOTENOTE: This only removes references to the sequence, IT DOES NOT FREE THE ALLOCATED MEMORY! - int RemoveSequence( CSequence *sequence, bool eraseSequence, bool removeChildren = true ); + int RemoveSequence( CSequence *sequence); + int DestroySequence( CSequence *sequence); int PushCommand( CBlock *command, int flag ); CBlock *PopCommand( int flag ); @@ -169,6 +172,7 @@ protected: int m_elseValid; CBlock *m_elseOwner; + vector m_streamsCreated; }; #endif //__SEQUENCER__ \ No newline at end of file diff --git a/code/icarus/taskmanager.h b/code/icarus/taskmanager.h index fe15c62..521175a 100644 --- a/code/icarus/taskmanager.h +++ b/code/icarus/taskmanager.h @@ -118,6 +118,7 @@ public: int Completed( int id ); int Update( void ); + qboolean IsRunning( void ); CTaskGroup *AddTaskGroup( const char *name ); CTaskGroup *GetTaskGroup( const char *name ); diff --git a/code/icarus/vssver.scc b/code/icarus/vssver.scc new file mode 100644 index 0000000..6e33c74 Binary files /dev/null and b/code/icarus/vssver.scc differ diff --git a/code/jpeg-6/vssver.scc b/code/jpeg-6/vssver.scc new file mode 100644 index 0000000..5c773cd Binary files /dev/null and b/code/jpeg-6/vssver.scc differ diff --git a/code/mac/MacGamma.c b/code/mac/MacGamma.c new file mode 100644 index 0000000..e468450 --- /dev/null +++ b/code/mac/MacGamma.c @@ -0,0 +1,487 @@ +/* + File: MacGamma.cpp + + Contains: Functions to enable Mac OS device gamma adjustments using Windows common 3 channel 256 element 8 bit gamma ramps + + Written by: Geoff Stahl + + Copyright: Copyright © 1999 Apple Computer, Inc., All Rights Reserved + + Change History (most recent first): + + <4> 5/20/99 GGS Added handling for gamma tables with different data widths, + number of entries, and channels. Forced updates to 3 channels + (poss. could break on rare card, but very unlikely). Added + quick update with BlockMove for 3x256x8 tables. Updated function + names. + <3> 5/20/99 GGS Cleaned up and commented + <2> 5/20/99 GGS Added system wide get and restore gamma functions to enable + restoration of original for all devices. Modified functionality + to return pointers vice squirreling away the memory. + <1> 5/20/99 GGS Initial Add +*/ + + + +// system includes ---------------------------------------------------------- + +#include +#include +#include +#include +#include +#include + + + +// project includes --------------------------------------------------------- + +#include "MacGamma.h" + + + +// functions (external/public) ---------------------------------------------- + +// GetRawDeviceGamma + +// Returns the device gamma table pointer in ppDeviceTable + +OSErr GetGammaTable (GDHandle hGD, GammaTblPtr * ppTableGammaOut) +{ + VDGammaRecord DeviceGammaRec; + CntrlParam cParam; + OSErr err; + + cParam.ioCompletion = NULL; // set up control params + cParam.ioNamePtr = NULL; + cParam.ioVRefNum = 0; + cParam.ioCRefNum = (**hGD).gdRefNum; + cParam.csCode = cscGetGamma; // Get Gamma commnd to device + *(Ptr *)cParam.csParam = (Ptr) &DeviceGammaRec; // record for gamma + + err = PBStatus( (ParmBlkPtr)&cParam, 0 ); // get gamma + + *ppTableGammaOut = (GammaTblPtr)(DeviceGammaRec.csGTable); // pull table out of record + + return err; +} + +// -------------------------------------------------------------------------- + +// CreateEmptyGammaTable + +// creates an empty gamma table of a given size, assume no formula data will be used + +Ptr CreateEmptyGammaTable (short channels, short entries, short bits) +{ + GammaTblPtr pTableGammaOut = NULL; + short tableSize, dataWidth; + + dataWidth = (bits + 7) / 8; // number of bytes per entry + tableSize = sizeof (GammaTbl) + (channels * entries * dataWidth); + pTableGammaOut = (GammaTblPtr) NewPtrClear (tableSize); // allocate new tabel + + if (pTableGammaOut) // if we successfully allocated + { + pTableGammaOut->gVersion = 0; // set parameters based on input + pTableGammaOut->gType = 0; + pTableGammaOut->gFormulaSize = 0; + pTableGammaOut->gChanCnt = channels; + pTableGammaOut->gDataCnt = entries; + pTableGammaOut->gDataWidth = bits; + } + return (Ptr)pTableGammaOut; // return whatever we allocated +} + +// -------------------------------------------------------------------------- + +// CopyGammaTable + +// given a pointer toa device gamma table properly iterates and copies + +Ptr CopyGammaTable (GammaTblPtr pTableGammaIn) +{ + GammaTblPtr pTableGammaOut = NULL; + short tableSize, dataWidth; + + if (pTableGammaIn) // if there is a table to copy + { + dataWidth = (pTableGammaIn->gDataWidth + 7) / 8; // number of bytes per entry + tableSize = sizeof (GammaTbl) + pTableGammaIn->gFormulaSize + + (pTableGammaIn->gChanCnt * pTableGammaIn->gDataCnt * dataWidth); + pTableGammaOut = (GammaTblPtr) NewPtr (tableSize); // allocate new table + if (pTableGammaOut) + BlockMove( (Ptr)pTableGammaIn, (Ptr)pTableGammaOut, tableSize); // move everything + } + return (Ptr)pTableGammaOut; // return whatever we allocated, could be NULL +} + +// -------------------------------------------------------------------------- + +// DisposeGammaTable + +// disposes gamma table returned from GetGammaTable, GetDeviceGamma, or CopyGammaTable +// 5/20/99: (GGS) added + +void DisposeGammaTable (Ptr pGamma) +{ + if (pGamma) + DisposePtr((Ptr) pGamma); // get rid of it +} + +// -------------------------------------------------------------------------- + +// GetDeviceGamma + +// returns pointer to copy of orginal device gamma table in native format (allocates memory for gamma table, call DisposeDeviceGamma to delete) +// 5/20/99: (GGS) change spec to return the allocated pointer vice storing internally + +Ptr GetDeviceGamma (GDHandle hGD) +{ + GammaTblPtr pTableGammaDevice = NULL; + GammaTblPtr pTableGammaReturn = NULL; + OSErr err; + + err = GetGammaTable (hGD, &pTableGammaDevice); // get a pointer to the devices table + if ((err == noErr) && pTableGammaDevice) // if succesful + pTableGammaReturn = (GammaTblPtr) CopyGammaTable (pTableGammaDevice); // copy to global + + return (Ptr) pTableGammaReturn; +} + +// -------------------------------------------------------------------------- + +// RestoreDeviceGamma + +// sets device to saved table +// 5/20/99: (GGS) now does not delete table, avoids confusion + +void RestoreDeviceGamma (GDHandle hGD, Ptr pGammaTable) +{ + VDSetEntryRecord setEntriesRec; + VDGammaRecord gameRecRestore; + CTabHandle hCTabDeviceColors; + Ptr csPtr; + OSErr err = noErr; + + if (pGammaTable) // if we have a table to restore + { + gameRecRestore.csGTable = pGammaTable; // setup restore record + csPtr = (Ptr) &gameRecRestore; + err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr); // restore gamma + + if ((err == noErr) && ((**(**hGD).gdPMap).pixelSize == 8)) // if successful and on an 8 bit device + { + hCTabDeviceColors = (**(**hGD).gdPMap).pmTable; // do SetEntries to force CLUT update + setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable; + setEntriesRec.csStart = 0; + setEntriesRec.csCount = (**hCTabDeviceColors).ctSize; + csPtr = (Ptr) &setEntriesRec; + + err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr); // SetEntries in CLUT + } + } +} + +// -------------------------------------------------------------------------- + +// GetSystemGammas + +// returns a pointer to a set of all current device gammas in native format (returns NULL on failure, which means reseting gamma will not be possible) +// 5/20/99: (GGS) added + +Ptr GetSystemGammas (void) +{ + precSystemGamma pSysGammaOut; // return pointer to system device gamma info + short devCount = 0; // number of devices attached + Boolean fail = false; + GDHandle hGDevice; + + pSysGammaOut = (precSystemGamma) NewPtr (sizeof (recSystemGamma)); // allocate for structure + + hGDevice = GetDeviceList (); // top of device list + do // iterate + { + devCount++; // count devices + hGDevice = GetNextDevice (hGDevice); // next device + } while (hGDevice); + + pSysGammaOut->devGamma = (precDeviceGamma *) NewPtr (sizeof (precDeviceGamma) * devCount); // allocate for array of pointers to device records + if (pSysGammaOut) + { + pSysGammaOut->numDevices = devCount; // stuff count + + devCount = 0; // reset iteration + hGDevice = GetDeviceList (); + do + { + pSysGammaOut->devGamma [devCount] = (precDeviceGamma) NewPtr (sizeof (recDeviceGamma)); // new device record + if (pSysGammaOut->devGamma [devCount]) // if we actually allocated memory + { + pSysGammaOut->devGamma [devCount]->hGD = hGDevice; // stuff handle + pSysGammaOut->devGamma [devCount]->pDeviceGamma = (GammaTblPtr)GetDeviceGamma (hGDevice); // copy gamma table + } + else // otherwise dump record on exit + fail = true; + devCount++; // next device + hGDevice = GetNextDevice (hGDevice); + } while (hGDevice); + } + if (!fail) // if we did not fail + return (Ptr) pSysGammaOut; // return pointer to structure + else + { + DisposeSystemGammas (&(Ptr)pSysGammaOut); // otherwise dump the current structures (dispose does error checking) + return NULL; // could not complete + } +} + +// -------------------------------------------------------------------------- + +// RestoreSystemGammas + +// restores all system devices to saved gamma setting +// 5/20/99: (GGS) added + +void RestoreSystemGammas (Ptr pSystemGammas) +{ + short i; + precSystemGamma pSysGammaIn = (precSystemGamma) pSystemGammas; + if (pSysGammaIn) + for ( i = 0; i < pSysGammaIn->numDevices; i++) // for all devices + RestoreDeviceGamma (pSysGammaIn->devGamma [i]->hGD, (Ptr) pSysGammaIn->devGamma [i]->pDeviceGamma); // restore gamma +} + +// -------------------------------------------------------------------------- + +// DisposeSystemGammas + +// iterates through and deletes stored gamma settings +// 5/20/99: (GGS) added + +void DisposeSystemGammas (Ptr* ppSystemGammas) +{ + precSystemGamma pSysGammaIn; + if (ppSystemGammas) + { + pSysGammaIn = (precSystemGamma) *ppSystemGammas; + if (pSysGammaIn) + { + short i; + for (i = 0; i < pSysGammaIn->numDevices; i++) // for all devices + if (pSysGammaIn->devGamma [i]) // if pointer is valid + { + DisposeGammaTable ((Ptr) pSysGammaIn->devGamma [i]->pDeviceGamma); // dump gamma table + DisposePtr ((Ptr) pSysGammaIn->devGamma [i]); // dump device info + } + DisposePtr ((Ptr) pSysGammaIn->devGamma); // dump device pointer array + DisposePtr ((Ptr) pSysGammaIn); // dump system structure + *ppSystemGammas = NULL; + } + } +} + +// -------------------------------------------------------------------------- + +// GetDeviceGammaRampGD + +// retrieves the gamma ramp from a graphics device (pRamp: 3 arrays of 256 elements each) + +Boolean GetDeviceGammaRampGD (GDHandle hGD, Ptr pRamp) +{ + GammaTblPtr pTableGammaTemp = NULL; + long indexChan, indexEntry; + OSErr err; + + if (pRamp) // ensure pRamp is allocated + { + err = GetGammaTable (hGD, &pTableGammaTemp); // get a pointer to the current gamma + if ((err == noErr) && pTableGammaTemp) // if successful + { + // fill ramp + unsigned char * pEntry = (unsigned char *)&pTableGammaTemp->gFormulaData + pTableGammaTemp->gFormulaSize; // base of table + short bytesPerEntry = (pTableGammaTemp->gDataWidth + 7) / 8; // size, in bytes, of the device table entries + short shiftRightValue = pTableGammaTemp->gDataWidth - 8; // number of right shifts device -> ramp + short channels = pTableGammaTemp->gChanCnt; + short entries = pTableGammaTemp->gDataCnt; + if (channels == 3) // RGB format + { // note, this will create runs of entries if dest. is bigger (not linear interpolate) + for (indexChan = 0; indexChan < channels; indexChan++) + for (indexEntry = 0; indexEntry < 256; indexEntry++) + *((unsigned char *)pRamp + (indexChan << 8) + indexEntry) = + *(pEntry + (indexChan * entries * bytesPerEntry) + indexEntry * ((entries * bytesPerEntry) >> 8)) >> shiftRightValue; + } + else // single channel format + { + for (indexEntry = 0; indexEntry < 256; indexEntry++) // for all entries set vramp value + for (indexChan = 0; indexChan < channels; indexChan++) // repeat for all channels + *((unsigned char *)pRamp + (indexChan << 8) + indexEntry) = + *(pEntry + ((indexEntry * entries * bytesPerEntry) >> 8)) >> shiftRightValue; + } + return true; + } + } + return false; +} + +// -------------------------------------------------------------------------- + +// GetDeviceGammaRampGW + +// retrieves the gamma ramp from a graphics device associated with a GWorld pointer (pRamp: 3 arrays of 256 elements each) + +Boolean GetDeviceGammaRampGW (GWorldPtr pGW, Ptr pRamp) +{ + GDHandle hGD = GetGWorldDevice (pGW); + return GetDeviceGammaRampGD (hGD, pRamp); +} + +// -------------------------------------------------------------------------- + +// GetDeviceGammaRampCGP + +// retrieves the gamma ramp from a graphics device associated with a CGraf pointer (pRamp: 3 arrays of 256 elements each) + +Boolean GetDeviceGammaRampCGP (CGrafPtr pGraf, Ptr pRamp) +{ + CGrafPtr pGrafSave; + GDHandle hGDSave; + GDHandle hGD; + Boolean fResult; + + GetGWorld (&pGrafSave, &hGDSave); + SetGWorld (pGraf, NULL); + hGD = GetGDevice (); + fResult = GetDeviceGammaRampGD (hGD, pRamp); + SetGWorld (pGrafSave, hGDSave); + return fResult; +} + +// -------------------------------------------------------------------------- + +// SetDeviceGammaRampGD + +// sets the gamma ramp for a graphics device (pRamp: 3 arrays of 256 elements each (R,G,B)) + +Boolean SetDeviceGammaRampGD (GDHandle hGD, Ptr pRamp) +{ + VDSetEntryRecord setEntriesRec; + VDGammaRecord gameRecRestore; + GammaTblPtr pTableGammaNew; + GammaTblPtr pTableGammaCurrent = NULL; + CTabHandle hCTabDeviceColors; + Ptr csPtr; + OSErr err; + short dataBits, entries, channels = 3; // force three channels in the gamma table + + if (pRamp) // ensure pRamp is allocated + { + err= GetGammaTable (hGD, &pTableGammaCurrent); // get pointer to current table + if ((err == noErr) && pTableGammaCurrent) + { + dataBits = pTableGammaCurrent->gDataWidth; // table must have same data width + entries = pTableGammaCurrent->gDataCnt; // table must be same size + pTableGammaNew = (GammaTblPtr) CreateEmptyGammaTable (channels, entries, dataBits); // our new table + if (pTableGammaNew) // if successful fill table + { + unsigned char * pGammaBase = (unsigned char *)&pTableGammaNew->gFormulaData + pTableGammaNew->gFormulaSize; // base of table + if (entries == 256 && dataBits == 8) // simple case: direct mapping + BlockMove ((Ptr)pRamp, (Ptr)pGammaBase, channels * entries); // move everything + else // tough case handle entry, channel and data size disparities + { + short bytesPerEntry = (dataBits + 7) / 8; // size, in bytes, of the device table entries + short shiftRightValue = 8 - dataBits; // number of right shifts ramp -> device + short indexChan; + short indexEntry; + short indexByte; + + shiftRightValue += ((bytesPerEntry - 1) * 8); // multibyte entries and the need to map a byte at a time most sig. to least sig. + for ( indexChan = 0; indexChan < channels; indexChan++) // for all the channels + for ( indexEntry = 0; indexEntry < entries; indexEntry++) // for all the entries + { + short currentShift = shiftRightValue; // reset current bit shift + long temp = *((unsigned char *)pRamp + (indexChan << 8) + (indexEntry << 8) / entries); // get data from ramp + for ( indexByte = 0; indexByte < bytesPerEntry; indexByte++) // for all bytes + { + if (currentShift < 0) // shift data correctly for current byte + *(pGammaBase++) = temp << -currentShift; + else + *(pGammaBase++) = temp >> currentShift; + currentShift -= 8; // increment shift to align to next less sig. byte + } + } + } + + // set gamma + gameRecRestore.csGTable = (Ptr) pTableGammaNew; // setup restore record + csPtr = (Ptr) &gameRecRestore; + err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr); // restore gamma + + if (((**(**hGD).gdPMap).pixelSize == 8) && (err == noErr)) // if successful and on an 8 bit device + { + hCTabDeviceColors = (**(**hGD).gdPMap).pmTable; // do SetEntries to force CLUT update + setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable; + setEntriesRec.csStart = 0; + setEntriesRec.csCount = (**hCTabDeviceColors).ctSize; + csPtr = (Ptr) &setEntriesRec; + err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr); // SetEntries in CLUT + } + DisposeGammaTable ((Ptr) pTableGammaNew); // dump table + if (err == noErr) + return true; + } + } + } + else // set NULL gamma -> results in linear map + { + gameRecRestore.csGTable = (Ptr) NULL; // setup restore record + csPtr = (Ptr) &gameRecRestore; + err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr); // restore gamma + + if (((**(**hGD).gdPMap).pixelSize == 8) && (err == noErr)) // if successful and on an 8 bit device + { + hCTabDeviceColors = (**(**hGD).gdPMap).pmTable; // do SetEntries to force CLUT update + setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable; + setEntriesRec.csStart = 0; + setEntriesRec.csCount = (**hCTabDeviceColors).ctSize; + csPtr = (Ptr) &setEntriesRec; + err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr); // SetEntries in CLUT + } + if (err == noErr) + return true; + } + return false; // memory allocation or device control failed if we get here +} + +// -------------------------------------------------------------------------- + +// SetDeviceGammaRampGW + +// sets the gamma ramp for a graphics device associated with a GWorld pointer (pRamp: 3 arrays of 256 elements each (R,G,B)) + +Boolean SetDeviceGammaRampGW (GWorldPtr pGW, Ptr pRamp) +{ + GDHandle hGD = GetGWorldDevice (pGW); + return SetDeviceGammaRampGD (hGD, pRamp); +} + +// -------------------------------------------------------------------------- + +// SetDeviceGammaRampCGP + +// sets the gamma ramp for a graphics device associated with a CGraf pointer (pRamp: 3 arrays of 256 elements each (R,G,B)) + +Boolean SetDeviceGammaRampCGP (CGrafPtr pGraf, Ptr pRamp) +{ + CGrafPtr pGrafSave; + GDHandle hGDSave; + GDHandle hGD; + Boolean fResult; + + GetGWorld (&pGrafSave, &hGDSave); + SetGWorld (pGraf, NULL); + hGD = GetGDevice (); + fResult = SetDeviceGammaRampGD (hGD, pRamp); + SetGWorld (pGrafSave, hGDSave); + return fResult; +} \ No newline at end of file diff --git a/code/mac/MacGamma.cpp b/code/mac/MacGamma.cpp new file mode 100644 index 0000000..a429950 --- /dev/null +++ b/code/mac/MacGamma.cpp @@ -0,0 +1,474 @@ +/* + File: MacGamma.cpp + + Contains: Functions to enable Mac OS device gamma adjustments using Windows common 3 channel 256 element 8 bit gamma ramps + + Written by: Geoff Stahl + + Copyright: Copyright © 1999 Apple Computer, Inc., All Rights Reserved + + Change History (most recent first): + + <4> 5/20/99 GGS Added handling for gamma tables with different data widths, + number of entries, and channels. Forced updates to 3 channels + (poss. could break on rare card, but very unlikely). Added + quick update with BlockMove for 3x256x8 tables. Updated function + names. + <3> 5/20/99 GGS Cleaned up and commented + <2> 5/20/99 GGS Added system wide get and restore gamma functions to enable + restoration of original for all devices. Modified functionality + to return pointers vice squirreling away the memory. + <1> 5/20/99 GGS Initial Add +*/ + + + +// system includes ---------------------------------------------------------- + +#include +#include +#include +#include +#include +#include + + + +// project includes --------------------------------------------------------- + +#include "MacGamma.h" + + + +// functions (external/public) ---------------------------------------------- + +// GetRawDeviceGamma + +// Returns the device gamma table pointer in ppDeviceTable + +OSErr GetGammaTable (GDHandle hGD, GammaTblPtr * ppTableGammaOut) +{ + VDGammaRecord DeviceGammaRec; + CntrlParam cParam; + OSErr err; + + cParam.ioCompletion = NULL; // set up control params + cParam.ioNamePtr = NULL; + cParam.ioVRefNum = 0; + cParam.ioCRefNum = (**hGD).gdRefNum; + cParam.csCode = cscGetGamma; // Get Gamma commnd to device + *(Ptr *)cParam.csParam = (Ptr) &DeviceGammaRec; // record for gamma + + err = PBStatus( (ParmBlkPtr)&cParam, 0 ); // get gamma + + *ppTableGammaOut = (GammaTblPtr)(DeviceGammaRec.csGTable); // pull table out of record + + return err; +} + +// -------------------------------------------------------------------------- + +// CreateEmptyGammaTable + +// creates an empty gamma table of a given size, assume no formula data will be used + +Ptr CreateEmptyGammaTable (short channels, short entries, short bits) +{ + GammaTblPtr pTableGammaOut = NULL; + short tableSize, dataWidth; + + dataWidth = (bits + 7) / 8; // number of bytes per entry + tableSize = sizeof (GammaTbl) + (channels * entries * dataWidth); + pTableGammaOut = (GammaTblPtr) NewPtrClear (tableSize); // allocate new tabel + + if (pTableGammaOut) // if we successfully allocated + { + pTableGammaOut->gVersion = 0; // set parameters based on input + pTableGammaOut->gType = 0; + pTableGammaOut->gFormulaSize = 0; + pTableGammaOut->gChanCnt = channels; + pTableGammaOut->gDataCnt = entries; + pTableGammaOut->gDataWidth = bits; + } + return (Ptr)pTableGammaOut; // return whatever we allocated +} + +// -------------------------------------------------------------------------- + +// CopyGammaTable + +// given a pointer toa device gamma table properly iterates and copies + +Ptr CopyGammaTable (GammaTblPtr pTableGammaIn) +{ + GammaTblPtr pTableGammaOut = NULL; + short tableSize, dataWidth; + + if (pTableGammaIn) // if there is a table to copy + { + dataWidth = (pTableGammaIn->gDataWidth + 7) / 8; // number of bytes per entry + tableSize = sizeof (GammaTbl) + pTableGammaIn->gFormulaSize + + (pTableGammaIn->gChanCnt * pTableGammaIn->gDataCnt * dataWidth); + pTableGammaOut = (GammaTblPtr) NewPtr (tableSize); // allocate new table + if (pTableGammaOut) + BlockMove( (Ptr)pTableGammaIn, (Ptr)pTableGammaOut, tableSize); // move everything + } + return (Ptr)pTableGammaOut; // return whatever we allocated, could be NULL +} + +// -------------------------------------------------------------------------- + +// DisposeGammaTable + +// disposes gamma table returned from GetGammaTable, GetDeviceGamma, or CopyGammaTable +// 5/20/99: (GGS) added + +void DisposeGammaTable (Ptr pGamma) +{ + if (pGamma) + DisposePtr((Ptr) pGamma); // get rid of it +} + +// -------------------------------------------------------------------------- + +// GetDeviceGamma + +// returns pointer to copy of orginal device gamma table in native format (allocates memory for gamma table, call DisposeDeviceGamma to delete) +// 5/20/99: (GGS) change spec to return the allocated pointer vice storing internally + +Ptr GetDeviceGamma (GDHandle hGD) +{ + GammaTblPtr pTableGammaDevice = NULL; + GammaTblPtr pTableGammaReturn = NULL; + OSErr err; + + err = GetGammaTable (hGD, &pTableGammaDevice); // get a pointer to the devices table + if ((err == noErr) && pTableGammaDevice) // if succesful + pTableGammaReturn = (GammaTblPtr) CopyGammaTable (pTableGammaDevice); // copy to global + + return (Ptr) pTableGammaReturn; +} + +// -------------------------------------------------------------------------- + +// RestoreDeviceGamma + +// sets device to saved table +// 5/20/99: (GGS) now does not delete table, avoids confusion + +void RestoreDeviceGamma (GDHandle hGD, Ptr pGammaTable) +{ + VDSetEntryRecord setEntriesRec; + VDGammaRecord gameRecRestore; + CTabHandle hCTabDeviceColors; + Ptr csPtr; + OSErr err = noErr; + + if (pGammaTable) // if we have a table to restore + { + gameRecRestore.csGTable = pGammaTable; // setup restore record + csPtr = (Ptr) &gameRecRestore; + err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr); // restore gamma + + if ((err == noErr) && ((**(**hGD).gdPMap).pixelSize == 8)) // if successful and on an 8 bit device + { + hCTabDeviceColors = (**(**hGD).gdPMap).pmTable; // do SetEntries to force CLUT update + setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable; + setEntriesRec.csStart = 0; + setEntriesRec.csCount = (**hCTabDeviceColors).ctSize; + csPtr = (Ptr) &setEntriesRec; + + err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr); // SetEntries in CLUT + } + } +} + +// -------------------------------------------------------------------------- + +// GetSystemGammas + +// returns a pointer to a set of all current device gammas in native format (returns NULL on failure, which means reseting gamma will not be possible) +// 5/20/99: (GGS) added + +Ptr GetSystemGammas (void) +{ + precSystemGamma pSysGammaOut; // return pointer to system device gamma info + short devCount = 0; // number of devices attached + Boolean fail = false; + + pSysGammaOut = (precSystemGamma) NewPtr (sizeof (recSystemGamma)); // allocate for structure + + GDHandle hGDevice = GetDeviceList (); // top of device list + do // iterate + { + devCount++; // count devices + hGDevice = GetNextDevice (hGDevice); // next device + } while (hGDevice); + + pSysGammaOut->devGamma = (precDeviceGamma *) NewPtr (sizeof (precDeviceGamma) * devCount); // allocate for array of pointers to device records + if (pSysGammaOut) + { + pSysGammaOut->numDevices = devCount; // stuff count + + devCount = 0; // reset iteration + hGDevice = GetDeviceList (); + do + { + pSysGammaOut->devGamma [devCount] = (precDeviceGamma) NewPtr (sizeof (recDeviceGamma)); // new device record + if (pSysGammaOut->devGamma [devCount]) // if we actually allocated memory + { + pSysGammaOut->devGamma [devCount]->hGD = hGDevice; // stuff handle + pSysGammaOut->devGamma [devCount]->pDeviceGamma = (GammaTblPtr)GetDeviceGamma (hGDevice); // copy gamma table + } + else // otherwise dump record on exit + fail = true; + devCount++; // next device + hGDevice = GetNextDevice (hGDevice); + } while (hGDevice); + } + if (!fail) // if we did not fail + return (Ptr) pSysGammaOut; // return pointer to structure + else + { + DisposeSystemGammas (&(Ptr)pSysGammaOut); // otherwise dump the current structures (dispose does error checking) + return NULL; // could not complete + } +} + +// -------------------------------------------------------------------------- + +// RestoreSystemGammas + +// restores all system devices to saved gamma setting +// 5/20/99: (GGS) added + +void RestoreSystemGammas (Ptr pSystemGammas) +{ + precSystemGamma pSysGammaIn = (precSystemGamma) pSystemGammas; + if (pSysGammaIn) + for (short i = 0; i < pSysGammaIn->numDevices; i++) // for all devices + RestoreDeviceGamma (pSysGammaIn->devGamma [i]->hGD, (Ptr) pSysGammaIn->devGamma [i]->pDeviceGamma); // restore gamma +} + +// -------------------------------------------------------------------------- + +// DisposeSystemGammas + +// iterates through and deletes stored gamma settings +// 5/20/99: (GGS) added + +void DisposeSystemGammas (Ptr* ppSystemGammas) +{ + precSystemGamma pSysGammaIn; + if (ppSystemGammas) + { + pSysGammaIn = (precSystemGamma) *ppSystemGammas; + if (pSysGammaIn) + { + for (short i = 0; i < pSysGammaIn->numDevices; i++) // for all devices + if (pSysGammaIn->devGamma [i]) // if pointer is valid + { + DisposeGammaTable ((Ptr) pSysGammaIn->devGamma [i]->pDeviceGamma); // dump gamma table + DisposePtr ((Ptr) pSysGammaIn->devGamma [i]); // dump device info + } + DisposePtr ((Ptr) pSysGammaIn->devGamma); // dump device pointer array + DisposePtr ((Ptr) pSysGammaIn); // dump system structure + *ppSystemGammas = NULL; + } + } +} + +// -------------------------------------------------------------------------- + +// GetDeviceGammaRampGD + +// retrieves the gamma ramp from a graphics device (pRamp: 3 arrays of 256 elements each) + +Boolean GetDeviceGammaRampGD (GDHandle hGD, Ptr pRamp) +{ + GammaTblPtr pTableGammaTemp = NULL; + long indexChan, indexEntry; + OSErr err; + + if (pRamp) // ensure pRamp is allocated + { + err = GetGammaTable (hGD, &pTableGammaTemp); // get a pointer to the current gamma + if ((err == noErr) && pTableGammaTemp) // if successful + { + // fill ramp + unsigned char * pEntry = (unsigned char *)&pTableGammaTemp->gFormulaData + pTableGammaTemp->gFormulaSize; // base of table + short bytesPerEntry = (pTableGammaTemp->gDataWidth + 7) / 8; // size, in bytes, of the device table entries + short shiftRightValue = pTableGammaTemp->gDataWidth - 8; // number of right shifts device -> ramp + short channels = pTableGammaTemp->gChanCnt; + short entries = pTableGammaTemp->gDataCnt; + if (channels == 3) // RGB format + { // note, this will create runs of entries if dest. is bigger (not linear interpolate) + for (indexChan = 0; indexChan < channels; indexChan++) + for (indexEntry = 0; indexEntry < 256; indexEntry++) + *((unsigned char *)pRamp + (indexChan << 8) + indexEntry) = + *(pEntry + (indexChan * entries * bytesPerEntry) + indexEntry * ((entries * bytesPerEntry) >> 8)) >> shiftRightValue; + } + else // single channel format + { + for (indexEntry = 0; indexEntry < 256; indexEntry++) // for all entries set vramp value + for (indexChan = 0; indexChan < channels; indexChan++) // repeat for all channels + *((unsigned char *)pRamp + (indexChan << 8) + indexEntry) = + *(pEntry + ((indexEntry * entries * bytesPerEntry) >> 8)) >> shiftRightValue; + } + return true; + } + } + return false; +} + +// -------------------------------------------------------------------------- + +// GetDeviceGammaRampGW + +// retrieves the gamma ramp from a graphics device associated with a GWorld pointer (pRamp: 3 arrays of 256 elements each) + +Boolean GetDeviceGammaRampGW (GWorldPtr pGW, Ptr pRamp) +{ + GDHandle hGD = GetGWorldDevice (pGW); + return GetDeviceGammaRampGD (hGD, pRamp); +} + +// -------------------------------------------------------------------------- + +// GetDeviceGammaRampCGP + +// retrieves the gamma ramp from a graphics device associated with a CGraf pointer (pRamp: 3 arrays of 256 elements each) + +Boolean GetDeviceGammaRampCGP (CGrafPtr pGraf, Ptr pRamp) +{ + CGrafPtr pGrafSave; + GDHandle hGDSave; + GetGWorld (&pGrafSave, &hGDSave); + SetGWorld (pGraf, NULL); + GDHandle hGD = GetGDevice (); + Boolean fResult = GetDeviceGammaRampGD (hGD, pRamp); + SetGWorld (pGrafSave, hGDSave); + return fResult; +} + +// -------------------------------------------------------------------------- + +// SetDeviceGammaRampGD + +// sets the gamma ramp for a graphics device (pRamp: 3 arrays of 256 elements each (R,G,B)) + +Boolean SetDeviceGammaRampGD (GDHandle hGD, Ptr pRamp) +{ + VDSetEntryRecord setEntriesRec; + VDGammaRecord gameRecRestore; + GammaTblPtr pTableGammaNew; + GammaTblPtr pTableGammaCurrent = NULL; + CTabHandle hCTabDeviceColors; + Ptr csPtr; + OSErr err; + short dataBits, entries, channels = 3; // force three channels in the gamma table + + if (pRamp) // ensure pRamp is allocated + { + err= GetGammaTable (hGD, &pTableGammaCurrent); // get pointer to current table + if ((err == noErr) && pTableGammaCurrent) + { + dataBits = pTableGammaCurrent->gDataWidth; // table must have same data width + entries = pTableGammaCurrent->gDataCnt; // table must be same size + pTableGammaNew = (GammaTblPtr) CreateEmptyGammaTable (channels, entries, dataBits); // our new table + if (pTableGammaNew) // if successful fill table + { + unsigned char * pGammaBase = (unsigned char *)&pTableGammaNew->gFormulaData + pTableGammaNew->gFormulaSize; // base of table + if (entries == 256 && dataBits == 8) // simple case: direct mapping + BlockMove ((Ptr)pRamp, (Ptr)pGammaBase, channels * entries); // move everything + else // tough case handle entry, channel and data size disparities + { + short bytesPerEntry = (dataBits + 7) / 8; // size, in bytes, of the device table entries + short shiftRightValue = 8 - dataBits; // number of right shifts ramp -> device + shiftRightValue += ((bytesPerEntry - 1) * 8); // multibyte entries and the need to map a byte at a time most sig. to least sig. + for (short indexChan = 0; indexChan < channels; indexChan++) // for all the channels + for (short indexEntry = 0; indexEntry < entries; indexEntry++) // for all the entries + { + short currentShift = shiftRightValue; // reset current bit shift + long temp = *((unsigned char *)pRamp + (indexChan << 8) + (indexEntry << 8) / entries); // get data from ramp + for (short indexByte = 0; indexByte < bytesPerEntry; indexByte++) // for all bytes + { + if (currentShift < 0) // shift data correctly for current byte + *(pGammaBase++) = temp << -currentShift; + else + *(pGammaBase++) = temp >> currentShift; + currentShift -= 8; // increment shift to align to next less sig. byte + } + } + } + + // set gamma + gameRecRestore.csGTable = (Ptr) pTableGammaNew; // setup restore record + csPtr = (Ptr) &gameRecRestore; + err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr); // restore gamma + + if (((**(**hGD).gdPMap).pixelSize == 8) && (err == noErr)) // if successful and on an 8 bit device + { + hCTabDeviceColors = (**(**hGD).gdPMap).pmTable; // do SetEntries to force CLUT update + setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable; + setEntriesRec.csStart = 0; + setEntriesRec.csCount = (**hCTabDeviceColors).ctSize; + csPtr = (Ptr) &setEntriesRec; + err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr); // SetEntries in CLUT + } + DisposeGammaTable ((Ptr) pTableGammaNew); // dump table + if (err == noErr) + return true; + } + } + } + else // set NULL gamma -> results in linear map + { + gameRecRestore.csGTable = (Ptr) NULL; // setup restore record + csPtr = (Ptr) &gameRecRestore; + err = Control((**hGD).gdRefNum, cscSetGamma, (Ptr) &csPtr); // restore gamma + + if (((**(**hGD).gdPMap).pixelSize == 8) && (err == noErr)) // if successful and on an 8 bit device + { + hCTabDeviceColors = (**(**hGD).gdPMap).pmTable; // do SetEntries to force CLUT update + setEntriesRec.csTable = (ColorSpec *) &(**hCTabDeviceColors).ctTable; + setEntriesRec.csStart = 0; + setEntriesRec.csCount = (**hCTabDeviceColors).ctSize; + csPtr = (Ptr) &setEntriesRec; + err = Control((**hGD).gdRefNum, cscSetEntries, (Ptr) &csPtr); // SetEntries in CLUT + } + if (err == noErr) + return true; + } + return false; // memory allocation or device control failed if we get here +} + +// -------------------------------------------------------------------------- + +// SetDeviceGammaRampGW + +// sets the gamma ramp for a graphics device associated with a GWorld pointer (pRamp: 3 arrays of 256 elements each (R,G,B)) + +Boolean SetDeviceGammaRampGW (GWorldPtr pGW, Ptr pRamp) +{ + GDHandle hGD = GetGWorldDevice (pGW); + return SetDeviceGammaRampGD (hGD, pRamp); +} + +// -------------------------------------------------------------------------- + +// SetDeviceGammaRampCGP + +// sets the gamma ramp for a graphics device associated with a CGraf pointer (pRamp: 3 arrays of 256 elements each (R,G,B)) + +Boolean SetDeviceGammaRampCGP (CGrafPtr pGraf, Ptr pRamp) +{ + CGrafPtr pGrafSave; + GDHandle hGDSave; + GetGWorld (&pGrafSave, &hGDSave); + SetGWorld (pGraf, NULL); + GDHandle hGD = GetGDevice (); + Boolean fResult = SetDeviceGammaRampGD (hGD, pRamp); + SetGWorld (pGrafSave, hGDSave); + return fResult; +} \ No newline at end of file diff --git a/code/mac/MacGamma.h b/code/mac/MacGamma.h new file mode 100644 index 0000000..efb145e --- /dev/null +++ b/code/mac/MacGamma.h @@ -0,0 +1,82 @@ +/* + File: MacGamma.h + + Contains: Functions to enable Mac OS device gamma adjustments using Windows common 3 channel 256 element 8 bit gamma ramps + + Written by: Geoff Stahl + + Copyright: Copyright © 1999 Apple Computer, Inc., All Rights Reserved + + Change History (most recent first): + + <4> 5/20/99 GGS Updated function names. + <3> 5/20/99 GGS Cleaned up and commented + <2> 5/20/99 GGS Added system wide get and restore gamma functions to enable + restoration of original for all devices. Modified functionality + to return pointers vice squirreling away the memory. + <1> 5/20/99 GGS Initial Add +*/ + + + +// include control -------------------------------------------------- + +#ifndef MacGamma_h +#define MacGamma_h + + + +// includes --------------------------------------------------------- + +#include +#include + + + +// structures/classes ----------------------------------------------- + +typedef struct // storage for device handle and gamma table +{ + GDHandle hGD; // handle to device + GammaTblPtr pDeviceGamma; // pointer to device gamma table +} recDeviceGamma; +typedef recDeviceGamma * precDeviceGamma; + +typedef struct // storage for system devices and gamma tables +{ + short numDevices; // number of devices + precDeviceGamma * devGamma; // array of pointers to device gamma records +} recSystemGamma; +typedef recSystemGamma * precSystemGamma; + + + +// function declarations -------------------------------------------- + +// 5/20/99: (GGS) changed functional specification +OSErr GetGammaTable(GDHandle gd, GammaTblPtr * ppTableGammaOut); // Returns the device gamma table pointer in ppDeviceTable +Ptr CreateEmptyGammaTable (short channels, short entries, short bits); // creates an empty gamma table of a given size, assume no formula data will be used +Ptr CopyGammaTable (GammaTblPtr pTableGammaIn); // given a pointer toa device gamma table properly iterates and copies +void DisposeGammaTable (Ptr pGamma); // disposes gamma table returned from GetGammaTable, GetDeviceGamma, or CopyGammaTable + +Ptr GetDeviceGamma (GDHandle hGD); // returns pointer to copy of orginal device gamma table in native format +void RestoreDeviceGamma (GDHandle hGD, Ptr pGammaTable); // sets device to saved table + +// 5/20/99: (GGS) added system wide gamma get and restore +Ptr GetSystemGammas (void); // returns a pointer to a set of all current device gammas in native format + // (returns NULL on failure, which means reseting gamma will not be possible) +void RestoreSystemGammas (Ptr pSystemGammas); // restores all system devices to saved gamma setting +void DisposeSystemGammas (Ptr* ppSystemGammas); // iterates through and deletes stored gamma settings + +Boolean GetDeviceGammaRampGD (GDHandle hGD, Ptr pRamp); // retrieves the gamma ramp from a graphics device (pRamp: 3 arrays of 256 elements each) +Boolean GetDeviceGammaRampGW (GWorldPtr pGW, Ptr pRamp); // retrieves the gamma ramp from a graphics device associated with a GWorld pointer (pRamp: 3 arrays of 256 elements each) +Boolean GetDeviceGammaRampCGP (CGrafPtr pGraf, Ptr pRamp); // retrieves the gamma ramp from a graphics device associated with a CGraf pointer (pRamp: 3 arrays of 256 elements each) + + +Boolean SetDeviceGammaRampGD (GDHandle hGD, Ptr pRamp); // sets the gamma ramp for a graphics device (pRamp: 3 arrays of 256 elements each (R,G,B)) +Boolean SetDeviceGammaRampGW (GWorldPtr pGW, Ptr pRamp); // sets the gamma ramp for a graphics device associated with a GWorld pointer (pRamp: 3 arrays of 256 elements each (R,G,B)) +Boolean SetDeviceGammaRampCGP (CGrafPtr pGraf, Ptr pRamp); // sets the gamma ramp for a graphics device associated with a CGraf pointer (pRamp: 3 arrays of 256 elements each (R,G,B)) + + + +#endif // MacGamma_h \ No newline at end of file diff --git a/code/mac/MacQuake3 b/code/mac/MacQuake3 new file mode 100644 index 0000000..f6d71f8 Binary files /dev/null and b/code/mac/MacQuake3 differ diff --git a/code/mac/mac_console.c b/code/mac/mac_console.c new file mode 100644 index 0000000..839a4ef --- /dev/null +++ b/code/mac/mac_console.c @@ -0,0 +1,119 @@ +#include "../client/client.h" +#include "mac_local.h" +#include +#include + +#define CONSOLE_MASK 1023 +static char consoleChars[CONSOLE_MASK+1]; +static int consoleHead, consoleTail; +static qboolean consoleDisplayed; + +/* +================== +Sys_InitConsole +================== +*/ +void Sys_InitConsole( void ) { + SIOUXSettings.initializeTB = 0; + SIOUXSettings.standalone = 0; + SIOUXSettings.setupmenus = 0; + SIOUXSettings.autocloseonquit = 1; + SIOUXSettings.asktosaveonclose = 0; + SIOUXSettings.toppixel = 40; + SIOUXSettings.leftpixel = 10; + +// Sys_ShowConsole( 1, qfalse ); +} + +/* +================== +Sys_ShowConsole +================== +*/ +void Sys_ShowConsole( int level, qboolean quitOnClose ) { + + if ( level ) { + consoleDisplayed = qtrue; + printf( "\n" ); + } else { + // FIXME: I don't know how to hide this window... + consoleDisplayed = qfalse; + } +} + + +/* +================ +Sys_Print + +This is called for all console output, even if the game is running +full screen and the dedicated console window is hidden. +================ +*/ +void Sys_Print( const char *text ) { + if ( !consoleDisplayed ) { + return; + } + printf( "%s", text ); +} + + +/* +================== +Sys_ConsoleEvent +================== +*/ +qboolean Sys_ConsoleEvent( EventRecord *event ) { + qboolean flag; + + flag = SIOUXHandleOneEvent(event); + + // track keyboard events so we can do console input, + // because SIOUX doesn't offer a polled read as far + // as I can tell... + if ( flag && event->what == keyDown ) { + int myCharCode; + + myCharCode = BitAnd( event->message, charCodeMask ); + if ( myCharCode == 8 || myCharCode == 28 ) { + if ( consoleHead > consoleTail ) { + consoleHead--; + } + } else if ( myCharCode >= 32 || myCharCode == 13 ) { + consoleChars[ consoleHead & CONSOLE_MASK ] = myCharCode; + consoleHead++; + } + } + + return flag; +} + + +/* +================ +Sys_ConsoleInput + +Checks for a complete line of text typed in at the console. +Return NULL if a complete line is not ready. +================ +*/ +char *Sys_ConsoleInput( void ) { + static char string[1024]; + int i; + + if ( consoleTail == consoleHead ) { + return NULL; + } + + for ( i = 0 ; i + consoleTail < consoleHead ; i++ ) { + string[i] = consoleChars[ ( consoleTail + i ) & CONSOLE_MASK ]; + if ( string[i] == 13 ) { + consoleTail += i + 1; + string[i] = 0; + return string; + } + } + + return NULL; +} + diff --git a/code/mac/mac_event.c b/code/mac/mac_event.c new file mode 100644 index 0000000..b9ecdf8 --- /dev/null +++ b/code/mac/mac_event.c @@ -0,0 +1,357 @@ +#include "../client/client.h" +#include "mac_local.h" + +void DoMenuCommand(long menuAndItem); +void DoDrag(WindowPtr myWindow,Point mouseloc); +void DoGoAwayBox(WindowPtr myWindow, Point mouseloc); +void DoCloseWindow(WindowPtr myWindow); +void DoKeyDown(EventRecord *event); +void DoDiskEvent(EventRecord *event); +void DoOSEvent(EventRecord *event); +void DoUpdate(WindowPtr myWindow); +void DoActivate(WindowPtr myWindow, int myModifiers); +void DoAboutBox(void); +void DoMenuCommand(long menuAndItem); +void DoMouseDown(EventRecord *event); +void DoMouseUp(EventRecord *event); +void DoMenuAdjust(void); +void DoKeyUp(EventRecord *event); + +/* +================ +Sys_MsecForMacEvent + +Q3 event records take time in msec, +so convert the mac event record when +(60ths) to msec. The base values +are updated ever frame, so this +is guaranteed to not drift. +================= +*/ +int Sys_MsecForMacEvent( void ) { + int tics; + + tics = sys_lastEventTic - sys_ticBase; + + return sys_msecBase + tics * 16; +} + + + + +void DoMouseDown(EventRecord *event) +{ + int myPart; + WindowPtr myWindow; + Point point; + + myPart = FindWindow(event->where, &myWindow); + + switch(myPart) + { + case inMenuBar: + DrawMenuBar(); + DoMenuCommand(MenuSelect(event->where)); + break; + case inSysWindow: + SystemClick(event, myWindow); + break; + case inDrag: + DoDrag(myWindow, event->where); + + // update the vid_xpos / vid_ypos cvars + point.h = 0; + point.v = 0; + LocalToGlobal( &point ); + Cvar_SetValue( "vid_xpos", point.h ); + Cvar_SetValue( "vid_ypos", point.v ); + return; + break; + case inGoAway: + DoGoAwayBox(myWindow, event->where); + break; + + case inContent: + if (myWindow != FrontWindow()) + { + SelectWindow(myWindow); + } + break; + } +} + +void DoMouseUp(EventRecord *event) +{ +} + +void DoDrag(WindowPtr myWindow, Point mouseloc) +{ + Rect dragBounds; + + dragBounds = (**GetGrayRgn()).rgnBBox; + DragWindow(myWindow,mouseloc,&dragBounds); + + aglUpdateContext(aglGetCurrentContext()); +} + + +void DoGoAwayBox(WindowPtr myWindow, Point mouseloc) +{ + if(TrackGoAway(myWindow,mouseloc)) + { + DoCloseWindow(myWindow); + } +} + +void DoCloseWindow(WindowPtr myWindow) +{ +} + +void DoMenuAdjust(void) +{ +} + +int vkeyToQuakeKey[256] = { +/*0x00*/ 'a', 's', 'd', 'f', 'h', 'g', 'z', 'x', +/*0x08*/ 'c', 'v', '?', 'b', 'q', 'w', 'e', 'r', +/*0x10*/ 'y', 't', '1', '2', '3', '4', '6', '5', +/*0x18*/ '=', '9', '7', '-', '8', '0', ']', 'o', +/*0x20*/ 'u', '[', 'i', 'p', K_ENTER, 'l', 'j', '\'', +/*0x28*/ 'k', ';', '\\', ',', '/', 'n', 'm', '.', +/*0x30*/ K_TAB, K_SPACE, '`', K_BACKSPACE, '?', K_ESCAPE, '?', K_COMMAND, +/*0x38*/ K_SHIFT, K_CAPSLOCK, K_ALT, K_CTRL, '?', '?', '?', '?', +/*0x40*/ '?', K_KP_DEL, '?', K_KP_STAR, '?', K_KP_PLUS, '?', K_KP_NUMLOCK, +/*0x48*/ '?', '?', '?', K_KP_SLASH, K_KP_ENTER, '?', K_KP_MINUS, '?', +/*0x50*/ '?', K_KP_EQUALS, K_KP_INS, K_KP_END, K_KP_DOWNARROW, K_KP_PGDN, K_KP_LEFTARROW, K_KP_5, +/*0x58*/ K_KP_RIGHTARROW, K_KP_HOME, '?', K_KP_UPARROW, K_KP_PGUP, '?', '?', '?', +/*0x60*/ K_F5, K_F6, K_F7, K_F3, K_F8, K_F9, '?', K_F11, +/*0x68*/ '?', K_F13, '?', K_F14, '?', K_F10, '?', K_F12, +/*0x70*/ '?', K_F15, K_INS, K_HOME, K_PGUP, K_DEL, K_F4, K_END, +/*0x78*/ K_F2, K_PGDN, K_F1, K_LEFTARROW, K_RIGHTARROW, K_DOWNARROW, K_UPARROW, K_POWER +}; + +void DoKeyDown(EventRecord *event) +{ + int myCharCode; + int myKeyCode; + + myCharCode = BitAnd(event->message,charCodeMask); + myKeyCode = ( event->message & keyCodeMask ) >> 8; + + Sys_QueEvent( Sys_MsecForMacEvent(), SE_KEY, vkeyToQuakeKey[ myKeyCode ], 1, 0, NULL ); + Sys_QueEvent( Sys_MsecForMacEvent(), SE_CHAR, myCharCode, 0, 0, NULL ); +} + +void DoKeyUp(EventRecord *event) +{ + int myCharCode; + int myKeyCode; + + myCharCode = BitAnd(event->message,charCodeMask); + myKeyCode = ( event->message & keyCodeMask ) >> 8; + + Sys_QueEvent( Sys_MsecForMacEvent(), SE_KEY, vkeyToQuakeKey[ myKeyCode ], 0, 0, NULL ); +} + +/* +================== +Sys_ModifierEvents +================== +*/ +static void Sys_ModifierEvents( int modifiers ) { + static int oldModifiers; + int changed; + int i; + + typedef struct { + int bit; + int keyCode; + } modifierKey_t; + + static modifierKey_t keys[] = { + { 128, K_MOUSE1 }, + { 256, K_COMMAND }, + { 512, K_SHIFT }, + {1024, K_CAPSLOCK }, + {2048, K_ALT }, + {4096, K_CTRL }, + {-1, -1 } + }; + + changed = modifiers ^ oldModifiers; + + for ( i = 0 ; keys[i].bit != -1 ; i++ ) { + // if we have input sprockets running, ignore mouse events we + // get from the debug passthrough driver + if ( inputActive && keys[i].keyCode == K_MOUSE1 ) { + continue; + } + + if ( changed & keys[i].bit ) { + Sys_QueEvent( Sys_MsecForMacEvent(), + SE_KEY, keys[i].keyCode, !!( modifiers & keys[i].bit ), 0, NULL ); + } + } + + oldModifiers = modifiers; +} + + +static void DoDiskEvent(EventRecord *event) +{ + +} + +static void DoOSEvent(EventRecord *event) +{ + +} + +static void DoUpdate(WindowPtr myWindow) +{ + GrafPtr origPort; + + GetPort(&origPort); + SetPort(myWindow); + + BeginUpdate(myWindow); + EndUpdate(myWindow); + + aglUpdateContext(aglGetCurrentContext()); + + SetPort(origPort); +} + +static void DoActivate( WindowPtr myWindow, int myModifiers) { + +} + +static void DoAboutBox( void ) { + DialogPtr myDialog; + short itemHit; + + myDialog = GetNewDialog(kAboutDialog, nil, (WindowPtr) -1); + ModalDialog(nil, &itemHit); + DisposeDialog(myDialog); +} + +static void DoMenuCommand( long menuAndItem ) { + int myMenuNum; + int myItemNum; + int myResult; + Str255 myDAName; + WindowPtr myWindow; + + myMenuNum = HiWord(menuAndItem); + myItemNum = LoWord(menuAndItem); + + GetPort(&myWindow); + + switch (myMenuNum) { + case mApple: + switch( myItemNum ) { + case iAbout: + DoAboutBox(); + break; + default: + GetMenuItemText(GetMenuHandle(mApple), myItemNum, myDAName); + myResult = OpenDeskAcc(myDAName); + break; + } + break; + case mFile: + switch (myItemNum) { + case iQuit: + Com_Quit_f(); + break; + } + break; + } + + HiliteMenu(0); +} + +void TestTime( EventRecord *ev ) { + int msec; + int tics; + static int startTics, startMsec; + + msec = Sys_Milliseconds(); + tics = ev->when; + + if ( !startTics || ev->what == mouseDown ) { + startTics = tics; + startMsec = msec; + } + + msec -= startMsec; + tics -= startTics; + + if ( !tics ) { + return; + } + Com_Printf( "%i msec to tic\n", msec / tics ); +} + +/* +================== +Sys_SendKeyEvents +================== +*/ +void Sys_SendKeyEvents (void) { + Boolean gotEvent; + EventRecord event; + + if ( !glConfig.isFullscreen || sys_waitNextEvent->value ) { + // this call involves 68k code and task switching. + // do it on the desktop, or if they explicitly ask for + // it when fullscreen + gotEvent = WaitNextEvent(everyEvent, &event, 0, nil); + } else { + gotEvent = GetOSEvent( everyEvent, &event ); + } + + // generate faked events from modifer changes + Sys_ModifierEvents( event.modifiers ); + + sys_lastEventTic = event.when; + + if ( !gotEvent ) { + return; + } + if ( Sys_ConsoleEvent(&event) ) { + return; + } + switch(event.what) + { + case mouseDown: + DoMouseDown(&event); + break; + case mouseUp: + DoMouseUp(&event); + break; + case keyDown: + DoKeyDown(&event); + break; + case keyUp: + DoKeyUp(&event); + break; + case autoKey: + DoKeyDown(&event); + break; + case updateEvt: + DoUpdate((WindowPtr) event.message); + break; + case diskEvt: + DoDiskEvent(&event); + break; + case activateEvt: + DoActivate((WindowPtr) event.message, event.modifiers); + break; + case osEvt: + DoOSEvent(&event); + break; + default: + break; + } +} diff --git a/code/mac/mac_glimp.c b/code/mac/mac_glimp.c new file mode 100644 index 0000000..2f46cc1 --- /dev/null +++ b/code/mac/mac_glimp.c @@ -0,0 +1,829 @@ + +typedef int sysEventType_t; // FIXME... +#include "../renderer/tr_local.h" +#include "mac_local.h" +#include +#include +#include "MacGamma.h" + +#define MAX_DEVICES 32 + +typedef struct { + GDHandle devices[MAX_DEVICES]; + int numDevices; + + Ptr systemGammas; + + GDHandle device; + + AGLContext context; + AGLDrawable drawable; + AGLPixelFormat fmt; + + GLint textureMemory; + GLint videoMemory; + + DSpContextReference DSpContext; +} macGlInfo; + + +cvar_t *r_device; +cvar_t *r_ext_transform_hint; +glHardwareType_t sys_hardwareType; +macGlInfo sys_gl; + +void GLimp_EndFrame( void ); +static void GLimp_Extensions( void ); + + +void CToPStr(char *cs, Str255 ps) +{ + GLint i, l; + + l = strlen(cs); + if(l > 255) l = 255; + ps[0] = l; + for(i = 0; i < l; i++) ps[i + 1] = cs[i]; +} + +/* +============ +CheckErrors +============ +*/ +void CheckErrors( void ) { + GLenum err; + + err = aglGetError(); + if( err != AGL_NO_ERROR ) { + ri.Error( ERR_FATAL, "aglGetError: %s", + aglErrorString( err ) ); + } +} + +//======================================================================= + +/* +===================== +GLimp_ResetDisplay +===================== +*/ +void GLimp_ResetDisplay( void ) { + if ( !glConfig.isFullscreen ) { + return; + } + glConfig.isFullscreen = qfalse; + + // put the context into the inactive state + DSpContext_SetState( sys_gl.DSpContext, kDSpContextState_Inactive ); + + // release the context + DSpContext_Release( sys_gl.DSpContext ); + + // shutdown draw sprockets + DSpShutdown(); +} + +/* +===================== +GLimp_ChangeDisplay +===================== +*/ +void GLimp_ChangeDisplay( int *actualWidth, int *actualHeight ) { + OSStatus theError; + DSpContextAttributes inAttributes; + int colorBits; + + // startup DrawSprocket + theError = DSpStartup(); + if( theError ) { + ri.Printf( PRINT_ALL, "DSpStartup() failed: %i\n", theError ); + *actualWidth = 640; + *actualHeight = 480; + return; + } + + if ( r_colorbits->integer == 24 || r_colorbits->integer == 32 ) { + colorBits = kDSpDepthMask_32; + } else { + colorBits = kDSpDepthMask_16; + } + + memset( &inAttributes, 0, sizeof( inAttributes ) ); + inAttributes.frequency = 0; + inAttributes.displayWidth = glConfig.vidWidth; + inAttributes.displayHeight = glConfig.vidHeight; + inAttributes.reserved1 = 0; + inAttributes.reserved2 = 0; + inAttributes.colorNeeds = kDSpColorNeeds_Require; + inAttributes.colorTable = NULL; + inAttributes.contextOptions = 0; + inAttributes.backBufferDepthMask = colorBits; + inAttributes.displayDepthMask = colorBits; + inAttributes.backBufferBestDepth = colorBits; + inAttributes.displayBestDepth = colorBits; + inAttributes.pageCount = 1; + inAttributes.gameMustConfirmSwitch = false; + inAttributes.reserved3[0] = 0; + inAttributes.reserved3[1] = 0; + inAttributes.reserved3[2] = 0; + inAttributes.reserved3[3] = 0; + + theError = DSpFindBestContext( &inAttributes, &sys_gl.DSpContext ); + + inAttributes.displayWidth = glConfig.vidWidth; + inAttributes.displayHeight = glConfig.vidHeight; + inAttributes.backBufferDepthMask = colorBits; + inAttributes.displayDepthMask = colorBits; + inAttributes.backBufferBestDepth = colorBits; + inAttributes.displayBestDepth = colorBits; + inAttributes.pageCount = 1; + + theError = DSpContext_Reserve( sys_gl.DSpContext, &inAttributes ); + + // find out what res we actually got + theError = DSpContext_GetAttributes( sys_gl.DSpContext, &inAttributes ); + + *actualWidth = inAttributes.displayWidth; + *actualHeight = inAttributes.displayHeight; + + // put the context into the active state + theError = DSpContext_SetState( sys_gl.DSpContext, kDSpContextState_Active ); + + // fade back in + theError = DSpContext_FadeGammaIn( NULL, NULL ); + + glConfig.isFullscreen = qtrue; +} + +//======================================================================= + + +/* +=================== +GLimp_AglDescribe_f + +=================== +*/ +void GLimp_AglDescribe_f( void ) { + long value; + long r,g,b,a; + long stencil, depth; + + ri.Printf( PRINT_ALL, "Selected pixel format 0x%x\n", (int)sys_gl.fmt ); + + ri.Printf( PRINT_ALL, "TEXTURE_MEMORY: %i\n", sys_gl.textureMemory ); + ri.Printf( PRINT_ALL, "VIDEO_MEMORY: %i\n", sys_gl.videoMemory ); + + aglDescribePixelFormat(sys_gl.fmt, AGL_RED_SIZE, &r); + aglDescribePixelFormat(sys_gl.fmt, AGL_GREEN_SIZE, &g); + aglDescribePixelFormat(sys_gl.fmt, AGL_BLUE_SIZE, &b); + aglDescribePixelFormat(sys_gl.fmt, AGL_ALPHA_SIZE, &a); + aglDescribePixelFormat(sys_gl.fmt, AGL_STENCIL_SIZE, &stencil); + aglDescribePixelFormat(sys_gl.fmt, AGL_DEPTH_SIZE, &depth); + ri.Printf( PRINT_ALL, "red:%i green:%i blue:%i alpha:%i depth:%i stencil:%i\n", + r, g, b, a, depth, stencil ); + + aglDescribePixelFormat(sys_gl.fmt, AGL_BUFFER_SIZE, &value); + ri.Printf( PRINT_ALL, "BUFFER_SIZE: %i\n", value ); + + aglDescribePixelFormat(sys_gl.fmt, AGL_PIXEL_SIZE, &value); + ri.Printf( PRINT_ALL, "PIXEL_SIZE: %i\n", value ); + + aglDescribePixelFormat(sys_gl.fmt, AGL_RENDERER_ID, &value); + ri.Printf( PRINT_ALL, "RENDERER_ID: %i\n", value ); + + // memory functions + value = glmGetInteger( GLM_PAGE_SIZE ); + ri.Printf( PRINT_ALL, "GLM_PAGE_SIZE: %i\n", value ); + + value = glmGetInteger( GLM_NUMBER_PAGES ); + ri.Printf( PRINT_ALL, "GLM_NUMBER_PAGES: %i\n", value ); + + value = glmGetInteger( GLM_CURRENT_MEMORY ); + ri.Printf( PRINT_ALL, "GLM_CURRENT_MEMORY: %i\n", value ); + + value = glmGetInteger( GLM_MAXIMUM_MEMORY ); + ri.Printf( PRINT_ALL, "GLM_MAXIMUM_MEMORY: %i\n", value ); + +} + +/* +=================== +GLimp_AglState_f + +=================== +*/ +void GLimp_AglState_f( void ) { + char *cmd; + int state, value; + + if ( ri.Cmd_Argc() != 3 ) { + ri.Printf( PRINT_ALL, "Usage: aglstate <0/1>\n" ); + return; + } + + cmd = ri.Cmd_Argv( 1 ); + if ( !Q_stricmp( cmd, "rasterization" ) ) { + state = AGL_RASTERIZATION; + } else { + ri.Printf( PRINT_ALL, "Unknown agl state: %s\n", cmd ); + return; + } + + cmd = ri.Cmd_Argv( 2 ); + value = atoi( cmd ); + + if ( value ) { + aglEnable( sys_gl.context, state ); + } else { + aglDisable( sys_gl.context, state ); + } +} + +/* +=================== +GLimp_Extensions + +=================== +*/ +static void GLimp_Extensions( void ) { + const char *extensions; + + // get our config strings + Q_strncpyz( glConfig.vendor_string, (const char *)qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) ); + Q_strncpyz( glConfig.renderer_string, (const char *)qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) ); + Q_strncpyz( glConfig.version_string, (const char *)qglGetString (GL_VERSION), sizeof( glConfig.version_string ) ); + Q_strncpyz( glConfig.extensions_string, (const char *)qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) ); + + extensions = glConfig.extensions_string; + + // GL_ARB_multitexture + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + + if ( strstr( extensions, "GL_ARB_multitexture" ) ) { + if ( r_ext_multitexture->integer && r_allowExtensions->integer ) { + qglMultiTexCoord2fARB = glMultiTexCoord2fARB; + qglActiveTextureARB = glActiveTextureARB; + qglClientActiveTextureARB = glClientActiveTextureARB; + + ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); + } else { + ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); + } + } else { + ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); + } + + // GL_EXT_compiled_vertex_array + qglLockArraysEXT = NULL; + qglUnlockArraysEXT = NULL; + + if ( strstr( extensions, "GL_EXT_compiled_vertex_array" ) ) { + if ( r_ext_compiled_vertex_array->integer && r_allowExtensions->integer ) { + qglLockArraysEXT = glLockArraysEXT; + qglUnlockArraysEXT = glUnlockArraysEXT; + + ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" ); + } else { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" ); + } + } else { + ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); + } + + // GL_EXT_texture_env_add + glConfig.textureEnvAddAvailable = qfalse; + if ( strstr( glConfig.extensions_string, "EXT_texture_env_add" ) ) { + if ( r_ext_texture_env_add->integer ) { + glConfig.textureEnvAddAvailable = qtrue; + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" ); + } else { + glConfig.textureEnvAddAvailable = qfalse; + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" ); + } + } else { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" ); + } + + // GL_EXT_texture_filter_anisotropic + glConfig.textureFilterAnisotropicAvailable = qfalse; + if ( strstr( glConfig.extensions_string, "EXT_texture_filter_anisotropic" ) ) + { + glConfig.textureFilterAnisotropicAvailable = qtrue; + ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic available\n" ); + + if ( r_ext_texture_filter_anisotropic->integer ) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic\n" ); + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" ); + } + ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "1" ); + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" ); + ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "0" ); + } + + // apple transform hint + if ( strstr( extensions, "GL_APPLE_transform_hint" ) ) { + if ( r_ext_compiled_vertex_array->integer && r_allowExtensions->integer ) { + glHint( GL_TRANSFORM_HINT_APPLE, GL_FASTEST ); + ri.Printf( PRINT_ALL, "...using GL_APPLE_transform_hint\n" ); + } else { + ri.Printf( PRINT_ALL, "...ignoring GL_APPLE_transform_hint\n" ); + } + } else { + ri.Printf( PRINT_ALL, "...GL_APPLE_transform_hint not found\n" ); + } +} + +/* +============================ +GLimp_SufficientVideoMemory +============================ +*/ +#if 0 + +qboolean GLimp_SufficientVideoMemory( void ) { + AGLRendererInfo head_info, info; + GLint accelerated; + AGLDevice *device; + GLint i, ndevs; + + device = aglDevicesOfPixelFormat( sys_gl.fmt, &ndevs); + if (!device || ndevs < 1) { + ri.Printf( PRINT_ALL, "aglDevicesOfPixelFormat failed.\n" ); + return 0; + } + + ri.Printf( PRINT_ALL, "%i rendering devices\n", ndevs ); + + head_info = aglQueryRendererInfo( device, 1 ); + info = head_info; + if (!info) { + ri.Printf( PRINT_ALL, "aglQueryRendererInfo failed.\n" ); + return 0; + } + + for ( i = 0 ; i < ndevs ; i++ ) { + // ignore the software renderer listing + aglDescribeRenderer( info, AGL_ACCELERATED, &accelerated ); + if ( accelerated ) { + aglDescribeRenderer( info, AGL_TEXTURE_MEMORY, &sys_gl.textureMemory ); + aglDescribeRenderer( info, AGL_VIDEO_MEMORY, &sys_gl.videoMemory ); + } + info = aglNextRendererInfo(info); + } + + aglDestroyRendererInfo(head_info); +#if 0 + if ( sys_gl.videoMemory < 16000000 ) { + glConfig.hardwareType = GLHW_RAGEPRO; // FIXME when voodoo is available + } else { + glConfig.isRagePro = GLHW_GENERIC; // FIXME when voodoo is available + } +#endif + ri.Printf( PRINT_ALL, "%i texture memory, %i video memory\n", sys_gl.textureMemory, sys_gl.videoMemory ); + + return qtrue; +} + +#endif + +/* +======================= +CheckDeviceRenderers + +======================== +*/ +static void CheckDeviceRenderers( GDHandle device ) { + AGLRendererInfo info, head_info; + GLint inum; + GLint accelerated; + GLint textureMemory, videoMemory; + + head_info = aglQueryRendererInfo(&device, 1); + if( !head_info ) { + ri.Printf( PRINT_ALL, "aglQueryRendererInfo : Info Error\n"); + return; + } + + info = head_info; + inum = 0; + while( info ) { + ri.Printf( PRINT_ALL, " Renderer : %d\n", inum); + + aglDescribeRenderer( info, AGL_ACCELERATED, &accelerated ); + + if ( accelerated ) { + aglDescribeRenderer( info, AGL_TEXTURE_MEMORY, &textureMemory ); + aglDescribeRenderer( info, AGL_VIDEO_MEMORY, &videoMemory ); + ri.Printf( PRINT_ALL, " AGL_VIDEO_MEMORY: %i\n", textureMemory ); + ri.Printf( PRINT_ALL, " AGL_TEXTURE_MEMORY: %i\n", videoMemory ); + + // save the device with the most texture memory + if ( sys_gl.textureMemory < textureMemory ) { + sys_gl.textureMemory = textureMemory; + sys_gl.device = device; + } + } else { + ri.Printf( PRINT_ALL, " Not accelerated.\n" ); + } + + info = aglNextRendererInfo(info); + inum++; + } + + aglDestroyRendererInfo(head_info); +} + + +/* +======================= +CheckDevices + +Make sure there is a device with enough video memory to play +======================= +*/ +static void CheckDevices( void ) { + GDHandle device; + static qboolean checkedFullscreen; + + if ( checkedFullscreen ) { + return; + } + if ( glConfig.isFullscreen ) { + checkedFullscreen = qtrue; + } + + device = GetDeviceList(); + sys_gl.numDevices = 0; + while( device && sys_gl.numDevices < MAX_DEVICES ) { + sys_gl.devices[ sys_gl.numDevices ] = device; + + ri.Printf( PRINT_ALL, "Device : %d\n", sys_gl.numDevices); + CheckDeviceRenderers(device); + + device = GetNextDevice(device); + + sys_gl.numDevices++; + } + + CheckErrors(); + + if ( sys_gl.textureMemory < 4000000 ) { + ri.Error( ERR_FATAL, "You must have at least four megs of video memory to play" ); + } + + if ( sys_gl.textureMemory < 16000000 ) { + sys_hardwareType = GLHW_RAGEPRO; // this will have to change with voodoo + } else { + sys_hardwareType = GLHW_GENERIC; + } +} + +/* +================= +CreateGameWindow +================= +*/ +static qboolean CreateGameWindow( void ) { + cvar_t *vid_xpos; + cvar_t *vid_ypos; + int mode; + int x, y; + Str255 pstr; + + + vid_xpos = ri.Cvar_Get( "vid_xpos", "30", 0 ); + vid_ypos = ri.Cvar_Get( "vid_ypos", "30", 0 ); + + // get mode info + mode = r_mode->integer; + ri.Printf( PRINT_ALL, "...setting mode %d:", mode ); + + if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) ) { + ri.Printf( PRINT_ALL, " invalid mode\n" ); + return false; + } + ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight ); + + /* Create window */ + if ( r_fullscreen->integer ) { + int actualWidth, actualHeight; + + // change display resolution + GLimp_ChangeDisplay( &actualWidth, &actualHeight ); + + x = ( actualWidth - glConfig.vidWidth ) / 2; + y = ( actualHeight - glConfig.vidHeight ) / 2; + sys_gl.drawable = (AGLDrawable) GetNewCWindow(kFullScreenWindow,nil,(WindowPtr)-1L); + } else { + x = vid_xpos->integer; + y = vid_ypos->integer; + sys_gl.drawable = (AGLDrawable) GetNewCWindow(kMainWindow,nil,(WindowPtr)-1L); + } + if( !sys_gl.drawable ) { + return qfalse; + } + + SizeWindow((GrafPort *) sys_gl.drawable, glConfig.vidWidth, glConfig.vidHeight,GL_FALSE); + MoveWindow((GrafPort *) sys_gl.drawable,x, y, GL_FALSE); + ShowWindow((GrafPort *) sys_gl.drawable); + SetPort((GrafPort *) sys_gl.drawable); + CToPStr("Quake3: Arena", pstr); + SetWTitle((GrafPort *) sys_gl.drawable, pstr); + HiliteWindow((GrafPort *) sys_gl.drawable, 1); + + return qtrue; +} + + +/* +=================== +GLimp_SetMode + +Returns false if the mode / fullscrenn / options combination failed, +so another fallback can be tried +=================== +*/ +qboolean GLimp_SetMode( void ) { + GLint value; + GLint attrib[64]; + int i; + + if ( !CreateGameWindow() ) { + ri.Printf( PRINT_ALL, "GLimp_Init: window could not be created" ); + return qfalse; + } + + // check devices now that the game has set the display mode, + // because RAVE devices don't get reported if in an 8 bit desktop + CheckDevices(); + + // set up the attribute list + i = 0; + attrib[i++] = AGL_RGBA; + attrib[i++] = AGL_DOUBLEBUFFER; + attrib[i++] = AGL_NO_RECOVERY; + attrib[i++] = AGL_ACCELERATED; + + if ( r_colorbits->integer >= 16 ) { + attrib[i++] = AGL_RED_SIZE; + attrib[i++] = 8; + attrib[i++] = AGL_GREEN_SIZE; + attrib[i++] = 8; + attrib[i++] = AGL_BLUE_SIZE; + attrib[i++] = 8; + attrib[i++] = AGL_ALPHA_SIZE; + attrib[i++] = 0; + } else { + attrib[i++] = AGL_RED_SIZE; + attrib[i++] = 5; + attrib[i++] = AGL_GREEN_SIZE; + attrib[i++] = 5; + attrib[i++] = AGL_BLUE_SIZE; + attrib[i++] = 5; + attrib[i++] = AGL_ALPHA_SIZE; + attrib[i++] = 0; + } + + attrib[i++] = AGL_STENCIL_SIZE; + if ( r_stencilbits->integer ) { + attrib[i++] = r_stencilbits->integer; + } else { + attrib[i++] = 0; + } + + attrib[i++] = AGL_DEPTH_SIZE; + if ( r_depthbits->integer ) { + attrib[i++] = r_depthbits->integer; + } else { + attrib[i++] = 16; + } + + attrib[i++] = 0; + + /* Choose pixel format */ + ri.Printf( PRINT_ALL, "aglChoosePixelFormat\n" ); + if ( r_device->integer < 0 || r_device->integer >= sys_gl.numDevices ) { + ri.Cvar_Set( "r_device", "0" ); + } + sys_gl.fmt = aglChoosePixelFormat( &sys_gl.devices[ r_device->integer ], 1, attrib); + if(!sys_gl.fmt) { + ri.Printf( PRINT_ALL, "GLimp_Init: Pixel format could not be achieved\n"); + return qfalse; + } + ri.Printf( PRINT_ALL, "Selected pixel format 0x%x\n", (int)sys_gl.fmt ); + + aglDescribePixelFormat(sys_gl.fmt, AGL_RED_SIZE, &value); + glConfig.colorBits = value * 3; + aglDescribePixelFormat(sys_gl.fmt, AGL_STENCIL_SIZE, &value); + glConfig.stencilBits = value; + aglDescribePixelFormat(sys_gl.fmt, AGL_DEPTH_SIZE, &value); + glConfig.depthBits = value; + + CheckErrors(); + + /* Create context */ + sys_gl.context = aglCreateContext(sys_gl.fmt, NULL); + if(!sys_gl.context) { + ri.Printf( PRINT_ALL, "GLimp_init: Context could not be created\n"); + return qfalse; + } + + CheckErrors(); + + /* Make context current */ + + if(!aglSetDrawable(sys_gl.context, sys_gl.drawable)) { + ri.Printf( PRINT_ALL, "GLimp_Init: Could not attach to context\n" ); + return qfalse; + } + + CheckErrors(); + + if( !aglSetCurrentContext(sys_gl.context) ) { + ri.Printf( PRINT_ALL, "GLimp_Init: Could not attach to context"); + return qfalse; + } + + CheckErrors(); + + // check video memory and determine ragePro status +#if 0 + if ( !GLimp_SufficientVideoMemory() ) { + return qfalse; + } +#endif + glConfig.hardwareType = sys_hardwareType; // FIXME: this isn't really right + + // draw something to show that GL is alive + qglClearColor( 1, 0.5, 0.2, 0 ); + qglClear( GL_COLOR_BUFFER_BIT ); + GLimp_EndFrame(); + + CheckErrors(); + + // get the extensions + GLimp_Extensions(); + + CheckErrors(); + + return qtrue; +} + + + +/* +=================== +GLimp_Init + +Don't return unless OpenGL has been properly initialized +=================== +*/ +void GLimp_Init( void ) { + GLint major, minor; + static qboolean registered; + + ri.Printf( PRINT_ALL, "--- GLimp_Init ---\n" ); + + aglGetVersion( &major, &minor ); + ri.Printf( PRINT_ALL, "aglVersion: %i.%i\n", (int)major, (int)minor ); + + r_device = ri.Cvar_Get( "r_device", "0", CVAR_LATCH | CVAR_ARCHIVE ); + r_ext_transform_hint = ri.Cvar_Get( "r_ext_transform_hint", "1", CVAR_LATCH | CVAR_ARCHIVE ); + + if ( !registered ) { + ri.Cmd_AddCommand( "aglDescribe", GLimp_AglDescribe_f ); + ri.Cmd_AddCommand( "aglState", GLimp_AglState_f ); + } + + memset( &glConfig, 0, sizeof( glConfig ) ); + + + r_swapInterval->modified = qtrue; // force a set next frame + + + glConfig.deviceSupportsGamma = qtrue; + + // FIXME: try for a voodoo first + sys_gl.systemGammas = GetSystemGammas(); + + if ( GLimp_SetMode() ) { + ri.Printf( PRINT_ALL, "------------------\n" ); + return; + } + + // fall back to the known-good mode + ri.Cvar_Set( "r_fullscreen", "1" ); + ri.Cvar_Set( "r_mode", "3" ); + ri.Cvar_Set( "r_stereo", "0" ); + ri.Cvar_Set( "r_depthBits", "16" ); + ri.Cvar_Set( "r_colorBits", "16" ); + ri.Cvar_Set( "r_stencilBits", "0" ); + if ( GLimp_SetMode() ) { + ri.Printf( PRINT_ALL, "------------------\n" ); + return; + } + + ri.Error( ERR_FATAL, "Could not initialize OpenGL" ); +} + + +/* +=============== +GLimp_EndFrame + +=============== +*/ +void GLimp_EndFrame( void ) { + // check for variable changes + if ( r_swapInterval->modified ) { + r_swapInterval->modified = qfalse; + ri.Printf( PRINT_ALL, "Changing AGL_SWAP_INTERVAL\n" ); + aglSetInteger( sys_gl.context, AGL_SWAP_INTERVAL, (long *)&r_swapInterval->integer ); + } + + // make sure the event loop is pumped + Sys_SendKeyEvents(); + + aglSwapBuffers( sys_gl.context ); +} + +/* +=============== +GLimp_Shutdown + +=============== +*/ +void GLimp_Shutdown( void ) { + if ( sys_gl.systemGammas ) { + RestoreSystemGammas( sys_gl.systemGammas ); + DisposeSystemGammas( &sys_gl.systemGammas ); + sys_gl.systemGammas = 0; + } + + if ( sys_gl.context ) { + aglDestroyContext(sys_gl.context); + sys_gl.context = 0; + } + if ( sys_gl.fmt ) { + aglDestroyPixelFormat(sys_gl.fmt); + sys_gl.fmt = 0; + } + if ( sys_gl.drawable ) { + DisposeWindow((GrafPort *) sys_gl.drawable); + sys_gl.drawable = 0; + } + GLimp_ResetDisplay(); + + memset( &glConfig, 0, sizeof( glConfig ) ); +} + + +void GLimp_LogComment( char *comment ) { +} +qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) { +} +void *GLimp_RendererSleep( void ) { + +} + +void GLimp_FrontEndSleep( void ) { + +} + +void GLimp_WakeRenderer( void * data ) { + +} + + + +/* +=============== +GLimp_SetGamma + +=============== +*/ +void GLimp_SetGamma( unsigned char red[256], + unsigned char green[256], + unsigned char blue[256] ) { + char color[3][256]; + int i; + + for ( i = 0 ; i < 256 ; i++ ) { + color[0][i] = red[i]; + color[1][i] = green[i]; + color[2][i] = blue[i]; + } + SetDeviceGammaRampGD( sys_gl.device, color[0] ); +} + diff --git a/code/mac/mac_input.c b/code/mac/mac_input.c new file mode 100644 index 0000000..b9e3375 --- /dev/null +++ b/code/mac/mac_input.c @@ -0,0 +1,212 @@ + +#include "../client/client.h" +#include "mac_local.h" +#include "InputSprocket.h" + +qboolean inputActive; +qboolean inputSuspended; + +#define MAX_DEVICES 100 +ISpDeviceReference devices[MAX_DEVICES]; +ISpElementListReference elementList; + +#define MAX_ELEMENTS 512 +#define MAX_MOUSE_DEVICES 2 +UInt32 numDevices; +UInt32 numElements[MAX_MOUSE_DEVICES]; +ISpElementReference elements[MAX_MOUSE_DEVICES][MAX_ELEMENTS]; + +cvar_t *in_nomouse; + +void Input_Init(void); +void Input_GetState( void ); + +/* +================= +Sys_InitInput +================= +*/ +void Sys_InitInput( void ) { + NumVersion ver; + ISpElementInfo info; + int i, j; + OSStatus err; + + // no input with dedicated servers + if ( com_dedicated->integer ) { + return; + } + + Com_Printf( "------- Input Initialization -------\n" ); + in_nomouse = Cvar_Get( "in_nomouse", "0", 0 ); + if ( in_nomouse->integer != 0 ) { + Com_Printf( "in_nomouse is set, skipping.\n" ); + Com_Printf( "------------------------------------\n" ); + return; + } + + ver = ISpGetVersion(); + Com_Printf( "InputSprocket version: 0x%x\n", ver ); + + err = ISpStartup(); + if ( err ) { + Com_Printf( "ISpStartup failed: %i\n", err ); + Com_Printf( "------------------------------------\n" ); + return; + } + + // disable everything + ISpDevices_Extract( MAX_DEVICES, &numDevices, devices ); + Com_Printf("%i total devices\n", numDevices); + if (numDevices > MAX_DEVICES) { + numDevices = MAX_DEVICES; + } + err = ISpDevices_Deactivate( + numDevices, + devices); + + // enable mouse + err = ISpDevices_ExtractByClass( + kISpDeviceClass_Mouse, + MAX_DEVICES, + &numDevices, + devices); + Com_Printf("%i mouse devices\n", numDevices); + if (numDevices > MAX_MOUSE_DEVICES) { + numDevices = MAX_MOUSE_DEVICES; + } + + err = ISpDevices_Activate( numDevices, devices); + for ( i = 0 ; i < numDevices ; i++ ) { + ISpDevice_GetElementList( devices[i], &elementList ); + +// ISpGetGlobalElementList( &elementList ); + + // go through all the elements and asign them Quake key codes + ISpElementList_Extract( elementList, MAX_ELEMENTS, &numElements[i], elements[i] ); + Com_Printf("%i elements in list\n", numElements[i] ); + + for ( j = 0 ; j < numElements[i] ; j++ ) { + ISpElement_GetInfo( elements[i][j], &info ); + PStringToCString( (char *)info.theString ); + Com_Printf( "%i : %s\n", i, info.theString ); + } + } + + inputActive = true; + + HideCursor(); + + Com_Printf( "------------------------------------\n" ); +} + +/* +================= +Sys_ShutdownInput +================= +*/ +void Sys_ShutdownInput( void ) { + if ( !inputActive ) { + return; + } + ShowCursor(); + ISpShutdown(); + inputActive = qfalse; +} + +void Sys_SuspendInput( void ) { + if ( inputSuspended ) { + return; + } + inputSuspended = true; + ShowCursor(); + ISpSuspend(); +} + +void Sys_ResumeInput( void ) { + if ( !inputSuspended ) { + return; + } + inputSuspended = false; + HideCursor(); + ISpResume(); +} + +/* +================= +Sys_Input +================= +*/ +void Sys_Input( void ) { + ISpElementEvent event; + Boolean wasEvent; + UInt32 state, state2; + int xmove, ymove; + int button; + static int xtotal, ytotal; + int device; + + if ( !inputActive ) { + return; + } + + // during debugging it is sometimes usefull to be able to kill mouse support + if ( in_nomouse->integer ) { + Com_Printf( "Shutting down input.\n"); + Sys_ShutdownInput(); + return; + } + + // always suspend for dedicated + if ( com_dedicated->integer ) { + Sys_SuspendInput(); + return; + } + + // temporarily deactivate if not in the game and + if ( cls.keyCatchers || cls.state != CA_ACTIVE ) { + if ( !glConfig.isFullscreen ) { + Sys_SuspendInput(); + return; + } + } + + Sys_ResumeInput(); + + // send all button events + for ( device = 0 ; device < numDevices ; device++ ) { + // mouse buttons + + for ( button = 2 ; button < numElements[device] ; button++ ) { + while ( 1 ) { + ISpElement_GetNextEvent( elements[device][button], sizeof( event ), &event, &wasEvent ); + if ( !wasEvent ) { + break; + } + if ( event.data ) { + Sys_QueEvent( 0, SE_KEY, K_MOUSE1 + button - 2, 1, 0, NULL ); + } else { + Sys_QueEvent( 0, SE_KEY, K_MOUSE1 + button - 2, 0, 0, NULL ); + } + } + } + + // mouse movement + +#define MAC_MOUSE_SCALE 163 // why this constant? + // send mouse event + ISpElement_GetSimpleState( elements[device][0], &state ); + xmove = (int)state / MAC_MOUSE_SCALE; + + ISpElement_GetSimpleState( elements[device][1], &state2 ); + ymove = (int)state2 / -MAC_MOUSE_SCALE; + + if ( xmove || ymove ) { + xtotal += xmove; + ytotal += ymove; + //Com_Printf("%i %i = %i %i\n", state, state2, xtotal, ytotal ); + Sys_QueEvent( 0, SE_MOUSE, xmove, ymove, 0, NULL ); + } + } + +} diff --git a/code/mac/mac_local.h b/code/mac/mac_local.h new file mode 100644 index 0000000..da86397 --- /dev/null +++ b/code/mac/mac_local.h @@ -0,0 +1,321 @@ + +/* + * Apple Universal Headers 3.1 + * + * Uncomment any additional #includes you want to add to your MacHeaders. + */ +//#include + + +// #include +// #include + #include + #include + #include + #include + #include +// #include + #include + #include + #include + #include + #include + #include + #include + #include +// #include +// #include + #include +// #include +// #include + #include +// #include +// #include +// #include + #include +// #include +// #include +// #include + #include +// #include + #include +// #include +// #include + #include + #include +// #include +// #include + #include +// #include +// #include +// #include +// #include +// #include + #include +// #include +// #include + #include + #include +// #include +// #include + #include +// #include + #include + #include +// #include +// #include + #include +// #include +// #include +// #include +// #include +// #include +// #include + #include + #include + #include +// #include + #include +// #include +// #include + #include + #include + #include + #include + #include + #include +// #include +// #include +// #include + #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + #include +// #include + #include +// #include + #include +// #include +// #include + #include +// #include +// #include +// #include + #include +// #include +// #include + #include +// #include + #include +// #include + #include + #include +// #include +// #include + #include // Start using MacMemory.h + #include +// #include + #include + #include +// #include +// #include +// #include + #include +// #include + #include + #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + #include + #include + #include + #include +// #include + #include + #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + #include +// #include + #include + #include + #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + #include +// #include +// #include + #include + #include +// #include +// #include +// #include +// #include +// #include + #include +// #include +// #include +// #include +// #include + #include + #include +// #include + #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + #include +// #include +// #include +// #include +// #include +// #include +// #include + #include + #include +// #include + #include // Start using TextUtils.h +// #include +// #include +// #include + #include + #include +// #include +// #include + #include + #include + #include + #include +// #include +// #include + #include +// #include + #include // Start using MacTypes.h +// #include +// #include + #include +// #include + #include // Start using MacWindows.h +// #include +// #include + + + + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Menus: */ + #define rMenuBar 128 + /* Apple menu: */ + #define mApple 128 + #define iAbout 1 + /* File menu: */ + #define mFile 129 + #define iQuit 1 + /* Edit menu: */ + #define mEdit 130 + #define iUndo 1 + #define iCut 3 + #define iCopy 4 + #define iPaste 5 + #define iClear 6 +/* Windows: */ + #define kMainWindow 128 + #define kFullScreenWindow 129 +/* Dilogs: */ + #define kAboutDialog 128 + + +// mac_main.c +extern int sys_ticBase; +extern int sys_msecBase; +extern int sys_lastEventTic; + +extern cvar_t *sys_waitNextEvent; + +void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ); +int PStringToCString( char *s ); +int CStringToPString( char *s ); + +// mac_event.c +extern int vkeyToQuakeKey[256]; +void Sys_SendKeyEvents (void); + +// mac_net.c +void Sys_InitNetworking( void ); +void Sys_ShutdownNetworking( void ); + +// mac_input.c +void Sys_InitInput( void ); +void Sys_ShutdownInput( void ); +void Sys_Input( void ); + +extern qboolean inputActive; + +// mac_glimp.c +extern glconfig_t glConfig; + +// mac_console.c + +void Sys_InitConsole( void ); +void Sys_ShowConsole( int level, qboolean quitOnClose ); +void Sys_Print( const char *text ); +char *Sys_ConsoleInput( void ); +qboolean Sys_ConsoleEvent( EventRecord *event ); + + diff --git a/code/mac/mac_main.c b/code/mac/mac_main.c new file mode 100644 index 0000000..a195b48 --- /dev/null +++ b/code/mac/mac_main.c @@ -0,0 +1,693 @@ +#include "../client/client.h" +#include "mac_local.h" +#include +#include + +/* + +TODO: + +about box +dir with no extension gives strange results +console input? +dedicated servers +icons +dynamic loading of server game +clipboard pasting + +quit from menu + +*/ + +int sys_ticBase; +int sys_msecBase; +int sys_lastEventTic; + +cvar_t *sys_profile; +cvar_t *sys_waitNextEvent; + +void putenv( char *buffer ) { + // the mac doesn't seem to have the concept of environment vars, so nop this +} + +//=========================================================================== + +void Sys_UnloadGame (void) { +} +void *Sys_GetGameAPI (void *parms) { + void *GetGameAPI (void *import); + // we are hard-linked in, so no need to load anything + return GetGameAPI (parms); +} + +void Sys_UnloadUI (void) { +} +void *Sys_GetUIAPI (void) { + void *GetUIAPI (void); + // we are hard-linked in, so no need to load anything + return GetUIAPI (); +} + +void Sys_UnloadBotLib( void ) { +} + +void *Sys_GetBotLibAPI (void *parms) { + return NULL; +} + +void *Sys_GetBotAIAPI (void *parms) { + return NULL; +} + +void dllEntry( int (*syscallptr)( int arg,... ) ); +int vmMain( int command, ... ); + +void *Sys_LoadDll( const char *name, int (**entryPoint)(int, ...), + int (*systemCalls)(int, ...) ) { + + dllEntry( systemCalls ); + + *entryPoint = vmMain; + + return (void *)1; +} + +void Sys_UnloadDll( void *dllHandle ) { +} + +//=========================================================================== + +char *Sys_GetClipboardData( void ) { // FIXME + return NULL; +} + +int Sys_GetProcessorId( void ) { + return CPUID_GENERIC; +} + +void Sys_Mkdir( const char *path ) { + char ospath[MAX_OSPATH]; + int err; + + Com_sprintf( ospath, sizeof(ospath), "%s:", path ); + + err = mkdir( ospath, 0777 ); +} + +char *Sys_Cwd( void ) { + static char dir[MAX_OSPATH]; + int l; + + getcwd( dir, sizeof( dir ) ); + dir[MAX_OSPATH-1] = 0; + + // strip off the last colon + l = strlen( dir ); + if ( l > 0 ) { + dir[ l - 1 ] = 0; + } + return dir; +} + +char *Sys_DefaultCDPath( void ) { + return ""; +} + +char *Sys_DefaultBasePath( void ) { + return Sys_Cwd(); +} + +/* + ================================================================================= + + FILE FINDING + + ================================================================================= +*/ + +int PStringToCString( char *s ) { + int l; + int i; + + l = ((unsigned char *)s)[0]; + for ( i = 0 ; i < l ; i++ ) { + s[i] = s[i+1]; + } + s[l] = 0; + return l; +} + + +int CStringToPString( char *s ) { + int l; + int i; + + l = strlen( s ); + for ( i = 0 ; i < l ; i++ ) { + s[l-i] = s[l-i-1]; + } + s[0] = l; + return l; +} + +#define MAX_FOUND_FILES 0x1000 + +char **Sys_ListFiles( const char *directory, const char *extension, int *numfiles, qboolean wantsubs ) { + int nfiles; + char **listCopy; + char pdirectory[MAX_OSPATH]; + char *list[MAX_FOUND_FILES]; + int findhandle; + int directoryFlag; + int i; + int extensionLength; + int VRefNum; + int DrDirId; + int index; + FSSpec fsspec; + + // get the volume and directory numbers + // there has to be a better way than this... + { + CInfoPBRec paramBlock; + + Q_strncpyz( pdirectory, directory, sizeof(pdirectory) ); + CStringToPString( pdirectory ); + FSMakeFSSpec( 0, 0, (unsigned char *)pdirectory, &fsspec ); + + VRefNum = fsspec.vRefNum; + + memset( ¶mBlock, 0, sizeof( paramBlock ) ); + paramBlock.hFileInfo.ioNamePtr = (unsigned char *)pdirectory; + PBGetCatInfoSync( ¶mBlock ); + + DrDirId = paramBlock.hFileInfo.ioDirID; + } + + if ( !extension) { + extension = ""; + } + extensionLength = strlen( extension ); + + if ( wantsubs || (extension[0] == '/' && extension[1] == 0) ) { + directoryFlag = 16; + } else { + directoryFlag = 0; + } + + nfiles = 0; + + for ( index = 1 ; ; index++ ) { + CInfoPBRec paramBlock; + char fileName[MAX_OSPATH]; + int length; + OSErr err; + + memset( ¶mBlock, 0, sizeof( paramBlock ) ); + paramBlock.hFileInfo.ioNamePtr = (unsigned char *)fileName; + paramBlock.hFileInfo.ioVRefNum = VRefNum; + paramBlock.hFileInfo.ioFDirIndex = index; + paramBlock.hFileInfo.ioDirID = DrDirId; + + err = PBGetCatInfoSync( ¶mBlock ); + + if ( err != noErr ) { + break; + } + + if ( directoryFlag ^ ( paramBlock.hFileInfo.ioFlAttrib & 16 ) ) { + continue; + } + + // convert filename to C string + length = PStringToCString( fileName ); + + // check the extension + if ( !directoryFlag ) { + if ( length < extensionLength ) { + continue; + } + if ( Q_stricmp( fileName + length - extensionLength, extension ) ) { + continue; + } + } + + // add this file + if ( nfiles == MAX_FOUND_FILES - 1 ) { + break; + } + list[ nfiles ] = CopyString( fileName ); + nfiles++; + } + + list[ nfiles ] = 0; + + + // return a copy of the list + *numfiles = nfiles; + + if ( !nfiles ) { + return NULL; + } + + listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) ); + for ( i = 0 ; i < nfiles ; i++ ) { + listCopy[i] = list[i]; + } + listCopy[i] = NULL; + + return listCopy; +} + +void Sys_FreeFileList( char **list ) { + int i; + + if ( !list ) { + return; + } + + for ( i = 0 ; list[i] ; i++ ) { + Z_Free( list[i] ); + } + + Z_Free( list ); +} + + +//=================================================================== + + +/* +================ +Sys_Init + +The cvar and file system has been setup, so configurations are loaded +================ +*/ +void Sys_Init(void) { + Sys_InitNetworking(); + Sys_InitInput(); +} + +/* +================= +Sys_Shutdown +================= +*/ +void Sys_Shutdown( void ) { + Sys_EndProfiling(); + Sys_ShutdownInput(); + Sys_ShutdownNetworking(); +} + + +/* +================= +Sys_BeginProfiling +================= +*/ +static qboolean sys_profiling; +void Sys_BeginProfiling( void ) { + if ( !sys_profile->integer ) { + return; + } + ProfilerInit(collectDetailed, bestTimeBase, 16384, 64); + sys_profiling = qtrue; +} + +/* +================= +Sys_EndProfiling +================= +*/ +void Sys_EndProfiling( void ) { + unsigned char pstring[1024]; + + if ( !sys_profiling ) { + return; + } + sys_profiling = qfalse; + + sprintf( (char *)pstring + 1, "%s:profile.txt", Cvar_VariableString( "fs_basepath" ) ); + pstring[0] = strlen( (char *)pstring + 1 ); + ProfilerDump( pstring ); + ProfilerTerm(); +} + +//================================================================================ + + +/* +================ +Sys_Milliseconds +================ +*/ +int Sys_Milliseconds (void) { +#if 0 + int c; + + c = clock(); // FIXME, make more accurate + + return c*1000/60; +#else + AbsoluteTime t; + Nanoseconds nano; + double doub; + +#define kTwoPower32 (4294967296.0) /* 2^32 */ + + t = UpTime(); + nano = AbsoluteToNanoseconds( t ); + doub = (((double) nano.hi) * kTwoPower32) + nano.lo; + + return doub * 0.000001; +#endif +} + +/* +================ +Sys_Error +================ +*/ +void Sys_Error( const char *error, ... ) { + va_list argptr; + char string[1024]; + char string2[1024]; + + Sys_Shutdown(); + + va_start (argptr,error); + vsprintf (string2+1,error,argptr); + va_end (argptr); + string2[0] = strlen( string2 + 1 ); + + strcpy( string+1, "Quake 3 Error:" ); + string[0] = strlen( string + 1 ); + + // set the dialog box strings + ParamText( (unsigned char *)string, (unsigned char *)string2, + (unsigned char *)string2, (unsigned char *)string2 ); + + // run a dialog + StopAlert( 128, NULL ); + + exit(0); +} + + +/* +================ +Sys_Quit +================ +*/ +void Sys_Quit( void ) { + Sys_Shutdown(); + exit (0); +} + + +//=================================================================== + +void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) { +} + +void Sys_EndStreamedFile( fileHandle_t f ) { +} + +int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) { + return FS_Read( buffer, size, count, f ); +} + +void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) { + FS_Seek( f, offset, origin ); +} + +//================================================================================= + + +/* +======================================================================== + +EVENT LOOP + +======================================================================== +*/ + +qboolean Sys_GetPacket ( netadr_t *net_from, msg_t *net_message ); + +#define MAX_QUED_EVENTS 256 +#define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 ) + +sysEvent_t eventQue[MAX_QUED_EVENTS]; +int eventHead, eventTail; +byte sys_packetReceived[MAX_MSGLEN]; + +/* +================ +Sys_QueEvent + +A time of 0 will get the current time +Ptr should either be null, or point to a block of data that can +be freed by the game later. +================ +*/ +void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) { + sysEvent_t *ev; + + ev = &eventQue[ eventHead & MASK_QUED_EVENTS ]; + if ( eventHead - eventTail >= MAX_QUED_EVENTS ) { + Com_Printf("Sys_QueEvent: overflow\n"); + // we are discarding an event, but don't leak memory + if ( ev->evPtr ) { + free( ev->evPtr ); + } + eventTail++; + } + eventHead++; + + if ( time == 0 ) { + time = Sys_Milliseconds(); + } + + ev->evTime = time; + ev->evType = type; + ev->evValue = value; + ev->evValue2 = value2; + ev->evPtrLength = ptrLength; + ev->evPtr = ptr; +} + +/* +================= +Sys_PumpEvents +================= +*/ +void Sys_PumpEvents( void ) { + char *s; + msg_t netmsg; + netadr_t adr; + + // pump the message loop + Sys_SendKeyEvents(); + + // check for console commands + s = Sys_ConsoleInput(); + if ( s ) { + char *b; + int len; + + len = strlen( s ) + 1; + b = malloc( len ); + if ( !b ) { + Com_Error( ERR_FATAL, "malloc failed in Sys_PumpEvents" ); + } + strcpy( b, s ); + Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b ); + } + + // check for other input devices + Sys_Input(); + + // check for network packets + MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) ); + if ( Sys_GetPacket ( &adr, &netmsg ) ) { + netadr_t *buf; + int len; + + // copy out to a seperate buffer for qeueing + len = sizeof( netadr_t ) + netmsg.cursize; + buf = malloc( len ); + if ( !buf ) { + Com_Error( ERR_FATAL, "malloc failed in Sys_PumpEvents" ); + } + *buf = adr; + memcpy( buf+1, netmsg.data, netmsg.cursize ); + Sys_QueEvent( 0, SE_PACKET, 0, 0, len, buf ); + } +} + +/* +================ +Sys_GetEvent + +================ +*/ +sysEvent_t Sys_GetEvent( void ) { + sysEvent_t ev; + + if ( eventHead == eventTail ) { + Sys_PumpEvents(); + } + // return if we have data + if ( eventHead > eventTail ) { + eventTail++; + return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ]; + } + + // create an empty event to return + memset( &ev, 0, sizeof( ev ) ); + ev.evTime = Sys_Milliseconds(); + + // track the mac event "when" to milliseconds rate + sys_ticBase = sys_lastEventTic; + sys_msecBase = ev.evTime; + + return ev; +} + + +/* +============= +InitMacStuff +============= +*/ +void InitMacStuff( void ) { + Handle menuBar; + char dir[MAX_OSPATH]; + + // init toolbox + MaxApplZone(); + MoreMasters(); + + InitGraf(&qd.thePort); + InitFonts(); + FlushEvents(everyEvent, 0); + SetEventMask( -1 ); + InitWindows(); + InitMenus(); + TEInit(); + InitDialogs(nil); + InitCursor(); + + // init menu + menuBar = GetNewMBar(rMenuBar); + if(!menuBar) { + Com_Error( ERR_FATAL, "MenuBar not found."); + } + + SetMenuBar(menuBar); + DisposeHandle(menuBar); + AppendResMenu(GetMenuHandle(mApple),'DRVR'); + DrawMenuBar(); + + Sys_InitConsole(); + + SetEventMask( -1 ); +} + +//================================================================================== + +/* +============= +ReadCommandLineParms + +Read startup options from a text file or dialog box +============= +*/ +char *ReadCommandLineParms( void ) { + FILE *f; + int len; + char *buf; + EventRecord event; + + // flush out all the events and see if shift is held down + // to bring up the args window + while ( WaitNextEvent(everyEvent, &event, 0, nil) ) { + } + if ( event.modifiers & 512 ) { + static char text[1024]; + int argc; + char **argv; + int i; + + argc = ccommand( &argv ); + text[0] = 0; + // concat all the args into a string + // quote each arg seperately, because metrowerks does + // its own quote combining from the dialog + for ( i = 1 ; i < argc ; i++ ) { + if ( argv[i][0] != '+' ) { + Q_strcat( text, sizeof(text), "\"" ); + } + Q_strcat( text, sizeof(text), argv[i] ); + if ( argv[i][0] != '+' ) { + Q_strcat( text, sizeof(text), "\"" ); + } + Q_strcat( text, sizeof(text), " " ); + } + return text; + } + + // otherwise check for a parms file + f = fopen( "MacQuake3Parms.txt", "r" ); + if ( !f ) { + return ""; + } + len = FS_filelength( f ); + buf = malloc( len + 1 ); + if ( !buf ) { + exit( 1 ); + } + buf[len] = 0; + fread( buf, len, 1, f ); + fclose( f ); + + return buf; +} + +/* +============= +main +============= +*/ +void main( void ) { + char *commandLine; + + InitMacStuff(); + + commandLine = ReadCommandLineParms( ); + + Com_Init ( commandLine ); + + sys_profile = Cvar_Get( "sys_profile", "0", 0 ); + sys_profile->modified = qfalse; + + sys_waitNextEvent = Cvar_Get( "sys_waitNextEvent", "0", 0 ); + + while( 1 ) { + // run the frame + Com_Frame(); + + if ( sys_profile->modified ) { + sys_profile->modified = qfalse; + if ( sys_profile->integer ) { + Com_Printf( "Beginning profile.\n" ); + Sys_BeginProfiling() ; + } else { + Com_Printf( "Ending profile.\n" ); + Sys_EndProfiling(); + } + } + } +} + diff --git a/code/mac/mac_net.c b/code/mac/mac_net.c new file mode 100644 index 0000000..798c878 --- /dev/null +++ b/code/mac/mac_net.c @@ -0,0 +1,527 @@ +#include "../client/client.h" +#include "mac_local.h" +#include +#include + +static qboolean gOTInited; +static EndpointRef endpoint = kOTInvalidEndpointRef; +static EndpointRef resolverEndpoint = kOTInvalidEndpointRef; + +#define MAX_IPS 16 +static int numIP; +static InetInterfaceInfo sys_inetInfo[MAX_IPS]; + +static TUDErr uderr; + +void RcvUDErr( void ) { + memset( &uderr, 0, sizeof( uderr ) ); + uderr.addr.maxlen = 0; + uderr.opt.maxlen = 0; + OTRcvUDErr( endpoint, &uderr ); +} + +void HandleOTError( int err, const char *func ) { + int r; + static int lastErr; + + if ( err != lastErr ) { + Com_Printf( "%s: error %i\n", func, err ); + } + + // if we don't call OTLook, things wedge + r = OTLook( endpoint ); + if ( err != lastErr ) { + Com_DPrintf( "%s: OTLook %i\n", func, r ); + } + + switch( r ) { + case T_UDERR: + RcvUDErr(); + if ( err != lastErr ) { + Com_DPrintf( "%s: OTRcvUDErr %i\n", func, uderr.error ); + } + break; + default: +// Com_Printf( "%s: Unknown OTLook error %i\n", func, r ); + break; + } + lastErr = err; // don't spew tons of messages +} + +/* +================= +NotifyProc +================= +*/ +pascal void NotifyProc(void* contextPtr, OTEventCode code, + OTResult result, void* cookie) { + switch( code ) { + case T_OPENCOMPLETE: + endpoint = cookie; + break; + case T_UDERR: + RcvUDErr(); + break; + } +} + + +/* +================= +GetFourByteOption +================= +*/ +static OTResult GetFourByteOption(EndpointRef ep, + OTXTILevel level, + OTXTIName name, + UInt32 *value) +{ + OTResult err; + TOption option; + TOptMgmt request; + TOptMgmt result; + + /* Set up the option buffer */ + option.len = kOTFourByteOptionSize; + option.level= level; + option.name = name; + option.status = 0; + option.value[0] = 0;// Ignored because we're getting the value. + + /* Set up the request parameter for OTOptionManagement to point + to the option buffer we just filled out */ + + request.opt.buf= (UInt8 *) &option; + request.opt.len= sizeof(option); + request.flags= T_CURRENT; + + /* Set up the reply parameter for OTOptionManagement. */ + result.opt.buf = (UInt8 *) &option; + result.opt.maxlen = sizeof(option); + + err = OTOptionManagement(ep, &request, &result); + + if (err == noErr) { + switch (option.status) + { + case T_SUCCESS: + case T_READONLY: + *value = option.value[0]; + break; + default: + err = option.status; + break; + } + } + + return (err); +} + + +/* +================= +SetFourByteOption +================= +*/ +static OTResult SetFourByteOption(EndpointRef ep, + OTXTILevel level, + OTXTIName name, + UInt32 value) +{ + OTResult err; + TOption option; + TOptMgmt request; + TOptMgmt result; + + /* Set up the option buffer to specify the option and value to + set. */ + option.len = kOTFourByteOptionSize; + option.level= level; + option.name = name; + option.status = 0; + option.value[0] = value; + + /* Set up request parameter for OTOptionManagement */ + request.opt.buf= (UInt8 *) &option; + request.opt.len= sizeof(option); + request.flags = T_NEGOTIATE; + + /* Set up reply parameter for OTOptionManagement. */ + result.opt.buf = (UInt8 *) &option; + result.opt.maxlen = sizeof(option); + + + err = OTOptionManagement(ep, &request, &result); + + if (err == noErr) { + if (option.status != T_SUCCESS) + err = option.status; + } + + return (err); +} + + +/* +===================== +NET_GetLocalAddress +===================== +*/ +void NET_GetLocalAddress( void ) { + OSStatus err; + + for ( numIP = 0 ; numIP < MAX_IPS ; numIP++ ) { + err = OTInetGetInterfaceInfo( &sys_inetInfo[ numIP ], numIP ); + if ( err ) { + break; + } + Com_Printf( "LocalAddress: %i.%i.%i.%i\n", + ((byte *)&sys_inetInfo[numIP].fAddress)[0], + ((byte *)&sys_inetInfo[numIP].fAddress)[1], + ((byte *)&sys_inetInfo[numIP].fAddress)[2], + ((byte *)&sys_inetInfo[numIP].fAddress)[3] ); + + Com_Printf( "Netmask: %i.%i.%i.%i\n", + ((byte *)&sys_inetInfo[numIP].fNetmask)[0], + ((byte *)&sys_inetInfo[numIP].fNetmask)[1], + ((byte *)&sys_inetInfo[numIP].fNetmask)[2], + ((byte *)&sys_inetInfo[numIP].fNetmask)[3] ); + } +} + + +/* +================== +Sys_InitNetworking + + +struct InetAddress +{ + OTAddressType fAddressType; // always AF_INET + InetPort fPort; // Port number + InetHost fHost; // Host address in net byte order + UInt8 fUnused[8]; // Traditional unused bytes +}; +typedef struct InetAddress InetAddress; + +================== +*/ +void Sys_InitNetworking( void ) { + OSStatus err; + OTConfiguration *config; + TBind bind, bindOut; + InetAddress in, out; + int i; + + Com_Printf( "----- Sys_InitNetworking -----\n" ); + // init OpenTransport + Com_Printf( "... InitOpenTransport()\n" ); + err = InitOpenTransport(); + if ( err != noErr ) { + Com_Printf( "InitOpenTransport() failed\n" ); + Com_Printf( "------------------------------\n" ); + return; + } + + gOTInited = true; + + // get an endpoint + Com_Printf( "... OTOpenEndpoint()\n" ); + config = OTCreateConfiguration( kUDPName ); + +#if 1 + endpoint = OTOpenEndpoint( config, 0, nil, &err); +#else + err = OTAsyncOpenEndpoint( config, 0, 0, NotifyProc, 0 ); + if ( !endpoint ) { + err = 1; + } +#endif + + if ( err != noErr ) { + endpoint = 0; + Com_Printf( "OTOpenEndpoint() failed\n" ); + Com_Printf( "------------------------------\n" ); + return; + } + + // set non-blocking + err = OTSetNonBlocking( endpoint ); + + // scan for a valid port in our range + Com_Printf( "... OTBind()\n" ); + for ( i = 0 ; i < 10 ; i++ ) { + in.fAddressType = AF_INET; + in.fPort = PORT_SERVER + i; + in.fHost = 0; + + bind.addr.maxlen = sizeof( in ); + bind.addr.len = sizeof( in ); + bind.addr.buf = (unsigned char *)∈ + bind.qlen = 0; + + bindOut.addr.maxlen = sizeof( out ); + bindOut.addr.len = sizeof( out ); + bindOut.addr.buf = (unsigned char *)&out; + bindOut.qlen = 0; + + err = OTBind( endpoint, &bind, &bindOut ); + if ( err == noErr ) { + Com_Printf( "Opened UDP endpoint at port %i\n", + out.fPort ); + break; + } + } + + if ( err != noErr ) { + Com_Printf( "Couldn't bind a local port\n" ); + } + + // get the local address for LAN client detection + NET_GetLocalAddress(); + + + // set to allow broadcasts + err = SetFourByteOption( endpoint, INET_IP, IP_BROADCAST, T_YES ); + + if ( err != noErr ) { + Com_Printf( "IP_BROADCAST failed\n" ); + } + + // get an endpoint just for resolving addresses, because + // I was having crashing problems doing it on the same endpoint + config = OTCreateConfiguration( kUDPName ); + resolverEndpoint = OTOpenEndpoint( config, 0, nil, &err); + if ( err != noErr ) { + resolverEndpoint = 0; + Com_Printf( "OTOpenEndpoint() for resolver failed\n" ); + Com_Printf( "------------------------------\n" ); + return; + } + + in.fAddressType = AF_INET; + in.fPort = 0; + in.fHost = 0; + + bind.addr.maxlen = sizeof( in ); + bind.addr.len = sizeof( in ); + bind.addr.buf = (unsigned char *)∈ + bind.qlen = 0; + + bindOut.addr.maxlen = sizeof( out ); + bindOut.addr.len = sizeof( out ); + bindOut.addr.buf = (unsigned char *)&out; + bindOut.qlen = 0; + + err = OTBind( resolverEndpoint, &bind, &bindOut ); + + Com_Printf( "------------------------------\n" ); +} + + +/* +================== +Sys_ShutdownNetworking +================== +*/ +void Sys_ShutdownNetworking( void ) { + Com_Printf( "Sys_ShutdownNetworking();\n" ); + + if ( endpoint != kOTInvalidEndpointRef ) { + OTUnbind( endpoint ); + OTCloseProvider( endpoint ); + endpoint = kOTInvalidEndpointRef; + } + if ( resolverEndpoint != kOTInvalidEndpointRef ) { + OTUnbind( resolverEndpoint ); + OTCloseProvider( resolverEndpoint ); + resolverEndpoint = kOTInvalidEndpointRef; + } + if (gOTInited) { + CloseOpenTransport(); + gOTInited = false; + } +} + +/* +============= +Sys_StringToAdr + + +Does NOT parse port numbers + + +idnewt +192.246.40.70 +============= +*/ +qboolean Sys_StringToAdr( const char *s, netadr_t *a ) { + OSStatus err; + TBind in, out; + InetAddress inAddr; + DNSAddress dnsAddr; + + if ( !resolverEndpoint ) { + return qfalse; + } + + memset( &in, 0, sizeof( in ) ); + in.addr.buf = (UInt8 *) &dnsAddr; + in.addr.len = OTInitDNSAddress(&dnsAddr, (char *)s ); + in.qlen = 0; + + memset( &out, 0, sizeof( out ) ); + out.addr.buf = (byte *)&inAddr; + out.addr.maxlen = sizeof( inAddr ); + out.qlen = 0; + + err = OTResolveAddress( resolverEndpoint, &in, &out, 10000 ); + if ( err ) { + HandleOTError( err, "Sys_StringToAdr" ); + return qfalse; + } + + a->type = NA_IP; + *(int *)a->ip = inAddr.fHost; + + return qtrue; +} + +/* +================== +Sys_SendPacket +================== +*/ +#define MAX_PACKETLEN 1400 +void Sys_SendPacket( int length, const void *data, netadr_t to ) { + TUnitData d; + InetAddress inAddr; + OSStatus err; + + if ( !endpoint ) { + return; + } + + if ( length > MAX_PACKETLEN ) { + Com_Error( ERR_DROP, "Sys_SendPacket: length > MAX_PACKETLEN" ); + } + + inAddr.fAddressType = AF_INET; + inAddr.fPort = to.port; + if ( to.type == NA_BROADCAST ) { + inAddr.fHost = -1; + } else { + inAddr.fHost = *(int *)&to.ip; + } + + memset( &d, 0, sizeof( d ) ); + + d.addr.len = sizeof( inAddr ); + d.addr.maxlen = sizeof( inAddr ); + d.addr.buf = (unsigned char *)&inAddr; + + d.opt.len = 0; + d.opt.maxlen = 0; + d.opt.buf = NULL; + + d.udata.len = length; + d.udata.maxlen = length; + d.udata.buf = (unsigned char *)data; + + err = OTSndUData( endpoint, &d ); + if ( err ) { + HandleOTError( err, "Sys_SendPacket" ); + } +} + +/* +================== +Sys_GetPacket + +Never called by the game logic, just the system event queing +================== +*/ +qboolean Sys_GetPacket ( netadr_t *net_from, msg_t *net_message ) { + TUnitData d; + InetAddress inAddr; + OSStatus err; + OTFlags flags; + + if ( !endpoint ) { + return qfalse; + } + + inAddr.fAddressType = AF_INET; + inAddr.fPort = 0; + inAddr.fHost = 0; + + memset( &d, 0, sizeof( d ) ); + + d.addr.len = sizeof( inAddr ); + d.addr.maxlen = sizeof( inAddr ); + d.addr.buf = (unsigned char *)&inAddr; + + d.opt.len = 0; + d.opt.maxlen = 0; + d.opt.buf = 0; + + d.udata.len = net_message->maxsize; + d.udata.maxlen = net_message->maxsize; + d.udata.buf = net_message->data; + + err = OTRcvUData( endpoint, &d, &flags ); + if ( err ) { + if ( err == kOTNoDataErr ) { + return false; + } + HandleOTError( err, "Sys_GetPacket" ); + return qfalse; + } + + net_from->type = NA_IP; + net_from->port = inAddr.fPort; + *(int *)net_from->ip = inAddr.fHost; + + net_message->cursize = d.udata.len; + + return qtrue; +} + + +/* +================== +Sys_IsLANAddress + +LAN clients will have their rate var ignored +================== +*/ +qboolean Sys_IsLANAddress (netadr_t adr) { + int i; + int ip; + + if ( adr.type == NA_LOOPBACK ) { + return qtrue; + } + + if ( adr.type != NA_IP ) { + return qfalse; + } + + for ( ip = 0 ; ip < numIP ; ip++ ) { + for ( i = 0 ; i < 4 ; i++ ) { + if ( ( adr.ip[i] & ((byte *)&sys_inetInfo[ip].fNetmask)[i] ) + != ( ((byte *)&sys_inetInfo[ip].fAddress)[i] & ((byte *)&sys_inetInfo[ip].fNetmask)[i] ) ) { + break; + } + } + if ( i == 4 ) { + return qtrue; // matches this subnet + } + } + + return qfalse; +} + + +void NET_Sleep( int i ) { +} diff --git a/code/mac/mac_snddma.c b/code/mac/mac_snddma.c new file mode 100644 index 0000000..9643aa3 --- /dev/null +++ b/code/mac/mac_snddma.c @@ -0,0 +1,140 @@ + +// mac_snddma.c +// all other sound mixing is portable + +#include "../client/snd_local.h" +#include + +#define MAX_MIXED_SAMPLES 0x8000 +#define SUBMISSION_CHUNK 0x100 + +static short s_mixedSamples[MAX_MIXED_SAMPLES]; +static int s_chunkCount; // number of chunks submitted +static SndChannel *s_sndChan; +static ExtSoundHeader s_sndHeader; + +/* +=============== +S_Callback +=============== +*/ +void S_Callback( SndChannel *sc, SndCommand *cmd ) { + SndCommand mySndCmd; + SndCommand mySndCmd2; + int offset; + + offset = ( s_chunkCount * SUBMISSION_CHUNK ) & (MAX_MIXED_SAMPLES-1); + + // queue up another sound buffer + memset( &s_sndHeader, 0, sizeof( s_sndHeader ) ); + s_sndHeader.samplePtr = (void *)(s_mixedSamples + offset); + s_sndHeader.numChannels = 2; + s_sndHeader.sampleRate = rate22khz; + s_sndHeader.loopStart = 0; + s_sndHeader.loopEnd = 0; + s_sndHeader.encode = extSH; + s_sndHeader.baseFrequency = 1; + s_sndHeader.numFrames = SUBMISSION_CHUNK / 2; + s_sndHeader.markerChunk = NULL; + s_sndHeader.instrumentChunks = NULL; + s_sndHeader.AESRecording = NULL; + s_sndHeader.sampleSize = 16; + + mySndCmd.cmd = bufferCmd; + mySndCmd.param1 = 0; + mySndCmd.param2 = (int)&s_sndHeader; + SndDoCommand( sc, &mySndCmd, true ); + + // and another callback + mySndCmd2.cmd = callBackCmd; + mySndCmd2.param1 = 0; + mySndCmd2.param2 = 0; + SndDoCommand( sc, &mySndCmd2, true ); + + s_chunkCount++; // this is the next buffer we will submit +} + +/* +=============== +S_MakeTestPattern +=============== +*/ +void S_MakeTestPattern( void ) { + int i; + float v; + int sample; + + for ( i = 0 ; i < dma.samples / 2 ; i ++ ) { + v = sin( M_PI * 2 * i / 64 ); + sample = v * 0x4000; + ((short *)dma.buffer)[i*2] = sample; + ((short *)dma.buffer)[i*2+1] = sample; + } +} + +/* +=============== +SNDDMA_Init +=============== +*/ +qboolean SNDDMA_Init(void) { + int err; + + // create a sound channel + s_sndChan = NULL; + err = SndNewChannel( &s_sndChan, sampledSynth, initStereo, NewSndCallBackProc(S_Callback) ); + if ( err ) { + return false; + } + + dma.channels = 2; + dma.samples = MAX_MIXED_SAMPLES; + dma.submission_chunk = SUBMISSION_CHUNK; + dma.samplebits = 16; + dma.speed = 22050; + dma.buffer = (byte *)s_mixedSamples; + + // que up the first submission-chunk sized buffer + s_chunkCount = 0; + + S_Callback( s_sndChan, NULL ); + + return qtrue; +} + +/* +=============== +SNDDMA_GetDMAPos +=============== +*/ +int SNDDMA_GetDMAPos(void) { + return s_chunkCount * SUBMISSION_CHUNK; +} + +/* +=============== +SNDDMA_Shutdown +=============== +*/ +void SNDDMA_Shutdown(void) { + if ( s_sndChan ) { + SndDisposeChannel( s_sndChan, true ); + s_sndChan = NULL; + } +} + +/* +=============== +SNDDMA_BeginPainting +=============== +*/ +void SNDDMA_BeginPainting(void) { +} + +/* +=============== +SNDDMA_Submit +=============== +*/ +void SNDDMA_Submit(void) { +} diff --git a/code/mac/macprefix.h b/code/mac/macprefix.h new file mode 100644 index 0000000..2836860 --- /dev/null +++ b/code/mac/macprefix.h @@ -0,0 +1,3 @@ +//#define __MACOS__ // needed for MrC +#define BOTLIB + diff --git a/code/mac/q3.rsrc b/code/mac/q3.rsrc new file mode 100644 index 0000000..e69de29 diff --git a/code/mac/vssver.scc b/code/mac/vssver.scc new file mode 100644 index 0000000..6c074e9 Binary files /dev/null and b/code/mac/vssver.scc differ diff --git a/code/mp3code/vssver.scc b/code/mp3code/vssver.scc new file mode 100644 index 0000000..78a1e99 Binary files /dev/null and b/code/mp3code/vssver.scc differ diff --git a/code/mssccprj.scc b/code/mssccprj.scc new file mode 100644 index 0000000..f83a7bc --- /dev/null +++ b/code/mssccprj.scc @@ -0,0 +1,9 @@ +SCC = This is a Source Code Control file + +[game.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\StarWars" +SCC_Project_Name = "$/code", JVOAAAAA + +[starwars.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\StarWars" +SCC_Project_Name = "$/Code", JVOAAAAA diff --git a/code/null/mac_net.c b/code/null/mac_net.c new file mode 100644 index 0000000..6232aff --- /dev/null +++ b/code/null/mac_net.c @@ -0,0 +1,44 @@ + +#include "../game/q_shared.h" +#include "../qcommon/qcommon.h" + +/* +============= +NET_StringToAdr + +localhost +idnewt +idnewt:28000 +192.246.40.70 +192.246.40.70:28000 +============= +*/ +qboolean NET_StringToAdr (char *s, netadr_t *a) +{ + if (!strcmp (s, "localhost")) { + memset (a, 0, sizeof(*a)); + a->type = NA_LOOPBACK; + return true; + } + + return false; +} + +/* +================== +Sys_SendPacket +================== +*/ +void Sys_SendPacket( int length, void *data, netadr_t to ) { +} + +/* +================== +Sys_GetPacket + +Never called by the game logic, just the system event queing +================== +*/ +qboolean Sys_GetPacket ( netadr_t *net_from, msg_t *net_message ) { + return false; +} diff --git a/code/null/null_glimp.c b/code/null/null_glimp.c new file mode 100644 index 0000000..30b84f7 --- /dev/null +++ b/code/null/null_glimp.c @@ -0,0 +1,39 @@ +#include "../renderer/tr_local.h" + + +qboolean ( * qwglSwapIntervalEXT)( int interval ); +void ( * qglMultiTexCoord2fARB )( enum texture, float s, float t ); +void ( * qglActiveTextureARB )( enum texture ); +void ( * qglClientActiveTextureARB )( enum texture ); + + +void ( * qglLockArraysEXT)( int, int); +void ( * qglUnlockArraysEXT) ( void ); + + +void GLimp_EndFrame( void ) { +} + +int GLimp_Init( void ) +{ +} + +void GLimp_Shutdown( void ) { +} + +rserr_t GLimp_SetMode( const char *drivername, int *pWidth, int *pHeight, int mode, qboolean fullscreen ) { +} + + +void GLimp_EnableLogging( qboolean enable ) { +} + +void GLimp_LogComment( char *comment ) { +} + +qboolean QGL_Init( const char *dllname ) { + return true; +} + +void QGL_Shutdown( void ) { +} diff --git a/code/null/null_main.c b/code/null/null_main.c new file mode 100644 index 0000000..59a5797 --- /dev/null +++ b/code/null/null_main.c @@ -0,0 +1,94 @@ +// sys_null.h -- null system driver to aid porting efforts + +#include "../qcommon/qcommon.h" +#include "errno.h" + +int sys_curtime; + + +//=================================================================== + +void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) { +} + +void Sys_EndStreamedFile( fileHandle_t f ) { +} + +int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) { + return FS_Read( buffer, size, count, f ); +} + +void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) { + FS_Seek( f, offset, origin ); +} + + +//=================================================================== + + +void Sys_mkdir (char *path) { +} + +void Sys_Error (char *error, ...) { + va_list argptr; + + printf ("Sys_Error: "); + va_start (argptr,error); + vprintf (error,argptr); + va_end (argptr); + printf ("\n"); + + exit (1); +} + +void Sys_Quit (void) { + exit (0); +} + +void Sys_UnloadGame (void) { +} + +void *Sys_GetGameAPI (void *parms) { + return NULL; +} + +char *Sys_GetClipboardData( void ) { + return NULL; +} + +int Sys_Milliseconds (void) { + return 0; +} + +void Sys_Mkdir (char *path) { +} + +char *Sys_FindFirst (char *path, unsigned musthave, unsigned canthave) { + return NULL; +} + +char *Sys_FindNext (unsigned musthave, unsigned canthave) { + return NULL; +} + +void Sys_FindClose (void) { +} + +void Sys_Init (void) { +} + + +void Sys_EarlyOutput( char *string ) { + printf( "%s", string ); +} + + +void main (int argc, char **argv) { + Com_Init (argc, argv); + + while (1) { + Com_Frame( ); + } +} + + diff --git a/code/null/null_net.c b/code/null/null_net.c new file mode 100644 index 0000000..2973a8d --- /dev/null +++ b/code/null/null_net.c @@ -0,0 +1,43 @@ + +#include "../qcommon/qcommon.h" + +/* +============= +NET_StringToAdr + +localhost +idnewt +idnewt:28000 +192.246.40.70 +192.246.40.70:28000 +============= +*/ +qboolean NET_StringToAdr (char *s, netadr_t *a) +{ + if (!strcmp (s, "localhost")) { + memset (a, 0, sizeof(*a)); + a->type = NA_LOOPBACK; + return true; + } + + return false; +} + +/* +================== +Sys_SendPacket +================== +*/ +void Sys_SendPacket( int length, void *data, netadr_t to ) { +} + +/* +================== +Sys_GetPacket + +Never called by the game logic, just the system event queing +================== +*/ +qboolean Sys_GetPacket ( netadr_t *net_from, msg_t *net_message ) { + return false; +} diff --git a/code/null/null_snddma.c b/code/null/null_snddma.c new file mode 100644 index 0000000..2e5d3d4 --- /dev/null +++ b/code/null/null_snddma.c @@ -0,0 +1,27 @@ + +// snddma_null.c +// all other sound mixing is portable + +#include "../client/client.h" + +qboolean SNDDMA_Init(void) +{ + return qfalse; +} + +int SNDDMA_GetDMAPos(void) +{ + return 0; +} + +void SNDDMA_Shutdown(void) +{ +} + +void SNDDMA_BeginPainting (void) +{ +} + +void SNDDMA_Submit(void) +{ +} diff --git a/code/null/vssver.scc b/code/null/vssver.scc new file mode 100644 index 0000000..7d80815 Binary files /dev/null and b/code/null/vssver.scc differ diff --git a/code/openal32.dll b/code/openal32.dll new file mode 100644 index 0000000..e65826b Binary files /dev/null and b/code/openal32.dll differ diff --git a/code/openal32.lib b/code/openal32.lib new file mode 100644 index 0000000..86de420 Binary files /dev/null and b/code/openal32.lib differ diff --git a/code/qcommon/cm_load.cpp b/code/qcommon/cm_load.cpp index c9efc74..62e67d5 100644 --- a/code/qcommon/cm_load.cpp +++ b/code/qcommon/cm_load.cpp @@ -639,7 +639,11 @@ static void CM_LoadMap_Actual( const char *name, qboolean clientload, int *check // clear some stuff that needs zeroing... // cm.floodvalid = 0; - cm.checkcount = 0; + //NO... don't reset this because the brush checkcounts are cached, + //so when you load up, brush checkcounts equal the cm.checkcount + //and the trace will be skipped (because everything loads and + //traces in the same exact order ever time you load the map) + cm.checkcount++;// = 0; memset(cm.areas, 0, cm.numAreas * sizeof( *cm.areas )); memset(cm.areaPortals, 0, cm.numAreas * cm.numAreas * sizeof( *cm.areaPortals )); } diff --git a/code/qcommon/cm_test.cpp b/code/qcommon/cm_test.cpp index f43ad06..86bb2cb 100644 --- a/code/qcommon/cm_test.cpp +++ b/code/qcommon/cm_test.cpp @@ -611,3 +611,22 @@ int CM_WriteAreaBits (byte *buffer, int area) return bytes; } +void CM_SnapPVS(vec3_t origin,byte *buffer) +{ + int clientarea; + int leafnum; + int i; + + leafnum = CM_PointLeafnum (origin); + clientarea = CM_LeafArea (leafnum); + + // calculate the visible areas + memset(buffer,0,MAX_MAP_AREA_BYTES); + CM_WriteAreaBits(buffer,clientarea); + for ( i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++ ) { + ((int *)buffer)[i] = ((int *)buffer)[i] ^ -1; + } + +} + + diff --git a/code/qcommon/cm_trace.cpp b/code/qcommon/cm_trace.cpp index 3598ff5..4113edd 100644 --- a/code/qcommon/cm_trace.cpp +++ b/code/qcommon/cm_trace.cpp @@ -285,10 +285,11 @@ void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) { // if (!startout) { // original point was inside brush tw->trace.startsolid = qtrue; - if (!getout) { + tw->trace.contents |= brush->contents; //note, we always want to know the contents of something we're inside of + if (!getout) + { //endpoint was inside brush tw->trace.allsolid = qtrue; tw->trace.fraction = 0; - tw->trace.contents = brush->contents; } return; } diff --git a/code/qcommon/common.cpp b/code/qcommon/common.cpp index 771e601..71b63bc 100644 --- a/code/qcommon/common.cpp +++ b/code/qcommon/common.cpp @@ -5,6 +5,11 @@ #include "../qcommon/sstring.h" // to get Gil's string class, because MS's doesn't compile properly in here #include "stv_version.h" +#ifdef _WIN32 +#include // for Sleep for Z_Malloc recovery attempy +#endif + + #define MAXPRINTMSG 4096 #define MAX_NUM_ARGVS 50 @@ -51,7 +56,7 @@ cvar_t *com_logfile; // 1 = buffer log, 2 = flush after each print cvar_t *com_showtrace; cvar_t *com_version; cvar_t *com_buildScript; // for automated data building scripts -cvar_t *com_FirstTime; +//cvar_t *com_FirstTime; cvar_t *cl_paused; cvar_t *sv_paused; cvar_t *com_skippingcin; @@ -233,9 +238,11 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { va_end (argptr); if ( code != ERR_DISCONNECT ) { + Cvar_Get("com_errorMessage", "", CVAR_ROM); //give com_errorMessage a default so it won't come back to life after a resetDefaults Cvar_Set("com_errorMessage", com_errorMessage); } + SG_Shutdown(); // close any file pointers if ( code == ERR_DISCONNECT ) { CL_Disconnect(); CL_FlushMemory(); @@ -244,7 +251,6 @@ void QDECL Com_Error( int code, const char *fmt, ... ) { throw ("DISCONNECTED\n"); } else if ( code == ERR_DROP ) { // If loading/saving caused the crash/error - delete the temp file - SG_Shutdown(); // close any file pointers SG_WipeSavegame("current"); // delete file SV_Shutdown (va("Server crashed: %s\n", com_errorMessage)); @@ -738,6 +744,13 @@ void *Z_Malloc(int iSize, memtag_t eTag, qboolean bZeroit) zoneHeader_t *pMemory = NULL; while (pMemory == NULL) { + #ifdef _WIN32 + if (gbMemFreeupOccured) + { + Sleep(100); // sleep for 1/10 of a second, so Windows has a chance to shuffle mem to de-swiss-cheese it + } + #endif + pMemory = (zoneHeader_t *) malloc ( iRealSize ); if (!pMemory) { @@ -1863,7 +1876,7 @@ void Com_Init( char *commandLine ) { com_skippingcin = Cvar_Get ("skippingCinematic", "0", CVAR_ROM); com_buildScript = Cvar_Get( "com_buildScript", "0", 0 ); - com_FirstTime = Cvar_Get( "com_FirstTime", "0", CVAR_ARCHIVE); +// com_FirstTime = Cvar_Get( "com_FirstTime", "0", CVAR_ARCHIVE); if ( com_developer && com_developer->integer ) { Cmd_AddCommand ("error", Com_Error_f); Cmd_AddCommand ("crash", Com_Crash_f ); @@ -1877,7 +1890,7 @@ void Com_Init( char *commandLine ) { Sys_Init(); // this also detects CPU type, so I can now do this CPU check below... - if( !com_FirstTime->integer ) // special request to detect and use top-settings for Intel Williamette chip... +/* if( !com_FirstTime->integer ) // special request to detect and use top-settings for Intel Williamette chip... { Cvar_Set( "com_FirstTime", "1" ); // only do this once // @@ -1890,7 +1903,7 @@ void Com_Init( char *commandLine ) { // Cbuf_Execute (); } } - +*/ Netchan_Init( Com_Milliseconds() & 0xffff ); // pick a port value that should be nice and random // VM_Init(); SV_Init(); @@ -1919,6 +1932,16 @@ void Com_Init( char *commandLine ) { } com_fullyInitialized = qtrue; Com_Printf ("--- Common Initialization Complete ---\n"); + +//HACKERY FOR THE DEUTSCH + if ( (Cvar_VariableIntegerValue("ui_iscensored") == 1) //if this was on before, set it again so it gets its flags + || sp_language->integer == SP_LANGUAGE_GERMAN ) + { + Cvar_Get( "ui_iscensored", "1", CVAR_ARCHIVE|CVAR_ROM|CVAR_INIT|CVAR_CHEAT|CVAR_NORESTART); + Cvar_Set( "ui_iscensored", "1"); //just in case it was archived + Cvar_Get( "g_dismemberment", "0", CVAR_ARCHIVE|CVAR_ROM|CVAR_INIT|CVAR_CHEAT); + Cvar_Set( "g_dismemberment", "0"); //just in case it was archived + } } catch (const char* reason) { diff --git a/code/qcommon/cvar.cpp b/code/qcommon/cvar.cpp index e77e6e1..63cddca 100644 --- a/code/qcommon/cvar.cpp +++ b/code/qcommon/cvar.cpp @@ -130,17 +130,15 @@ char *Cvar_CompleteVariable( const char *partial ) { return NULL; } - // check exact match - for ( cvar = cvar_vars ; cvar ; cvar = cvar->next ) { - if ( !Q_stricmp (partial,cvar->name) ) { - return cvar->name; - } - } - // check partial match for ( cvar=cvar_vars ; cvar ; cvar=cvar->next ) { if ( !Q_stricmpn (partial,cvar->name, len) ) { - return cvar->name; + if ( (cvar->flags & CVAR_CHEAT) && !cvar_cheats->integer ) { + continue; + } + else { + return cvar->name; + } } } @@ -184,15 +182,19 @@ char *Cvar_CompleteVariableNext (char *partial, char *last) { base = cvar_vars; } - // check exact match - for (cvar=base ; cvar ; cvar=cvar->next) - if (!Q_stricmp (partial,cvar->name)) - return cvar->name; // check partial match for (cvar=base ; cvar ; cvar=cvar->next) - if (!Q_stricmpn (partial,cvar->name, len)) - return cvar->name; + { + if (!Q_stricmpn (partial,cvar->name, len)) { + if ( (cvar->flags & CVAR_CHEAT) && !cvar_cheats->integer ) { + continue; + } + else { + return cvar->name; + } + } + } return NULL; } @@ -513,7 +515,7 @@ void Cvar_Toggle_f( void ) { return; } - v = Cvar_VariableValue( Cmd_Argv( 1 ) ); + v = Cvar_VariableIntegerValue( Cmd_Argv( 1 ) ); v = !v; Cvar_Set2 (Cmd_Argv(1), va("%i", v), qfalse); @@ -710,6 +712,11 @@ void Cvar_List_f( void ) { Com_Printf(" "); } if (var->flags & CVAR_CHEAT) { + if (!cvar_cheats->integer) + { + i--; + continue; + } Com_Printf("C"); } else { Com_Printf(" "); @@ -858,7 +865,7 @@ Reads in all archived cvars ============ */ void Cvar_Init (void) { - cvar_cheats = Cvar_Get("sv_cheats", "1", CVAR_SYSTEMINFO ); + cvar_cheats = Cvar_Get("helpUsObi", "0", CVAR_SYSTEMINFO ); Cmd_AddCommand ("toggle", Cvar_Toggle_f); Cmd_AddCommand ("set", Cvar_Set_f); diff --git a/code/qcommon/hstring.cpp b/code/qcommon/hstring.cpp index c4dddbf..a32dc86 100644 --- a/code/qcommon/hstring.cpp +++ b/code/qcommon/hstring.cpp @@ -1,3 +1,4 @@ +#include #include "cm_local.h" #include "hstring.h" @@ -63,24 +64,31 @@ CMapPoolLow::CMapPoolLow() CMapPoolLow::~CMapPoolLow() { #if _DEBUG + char mess[1000]; #if _GAME if(mFreeList.size()value) { - Dest = Text = new char[length + 6]; - strcpy(Dest,"STRIP-"); + const char sDebugString[]="SP:"; + Dest = Text = new char[length + strlen(sDebugString)]; + strcpy(Dest,sDebugString); Dest += strlen(Dest); } else @@ -551,6 +553,34 @@ static void FixIllegalChars(char *psText) { *p = 0x2D; } + + // bug fix for picky grammatical errors, replace "?." with "? " + // + while ((p=strstr(psText,"?."))!=NULL) + { + p[1] = ' '; + } + + // StripEd and our print code don't support tabs... + // + while ((p=strchr(psText,0x09))!=NULL) + { + *p = ' '; + } + + + if (sp_leet->integer == 42) // very specific test, so you won't hit it accidentally + { + char cReplace[]={ 'o','0','l','1','e','3','a','4','s','5','t','7','i','!','h','#', + 'O','0','L','1','E','3','A','4','S','5','T','7','I','!','H','#' // laziness because of strchr() + }; + + for (int i=0; iName == TK_TEXT_LANGUAGE1 && token == TK_TEXT_LANGUAGE1 && !Text) { // default to english in case there is no foreign - if (LanguagePair->Name == TK_TEXT_LANGUAGE1) + if (LanguagePair->Name == TK_TEXT_LANGUAGE1 || + LanguagePair->Name == TK_TEXT_LANGUAGE2 || + LanguagePair->Name == TK_TEXT_LANGUAGE3 + ) { FixIllegalChars(data); } @@ -573,7 +606,10 @@ bool cStringsSingle::UnderstandToken(int token, char *data ) } else if (LanguagePair->Name == token && LanguagePair->Value == sp_language->integer) { - if (LanguagePair->Name == TK_TEXT_LANGUAGE1) + if (LanguagePair->Name == TK_TEXT_LANGUAGE1 || + LanguagePair->Name == TK_TEXT_LANGUAGE2 || + LanguagePair->Name == TK_TEXT_LANGUAGE3 + ) { FixIllegalChars(data); } @@ -959,6 +995,41 @@ cStringsSingle *SP_GetString(const char *Reference) return SP_GetString(index); } +#ifdef _DEBUG +// needed to add this to query which SP references the menus used -Ste. +// +const char *SP_GetReferenceText(unsigned short ID, const char *&psPackageName, const char *&psPackageReference, const char *&psText) +{ + cStringPackageSingle *sp; + map::iterator i; + + i = SP_ListByID.find(SP_GET_PACKAGE(ID)); + if (i == SP_ListByID.end()) + { + assert(0); + return NULL; + } + + cStringsSingle *string; + + sp = (*i).second; + string = sp->FindString(ID & SP_STRING); + + if (!string) + { + assert(0); + return NULL; + } + + psPackageName = sp->GetName(); + psPackageReference = sp->GetReference(); + psText = string->GetText(); + if (!psText) + psText = ""; + return string->GetReference(); +} +#endif + const char *SP_GetStringText(unsigned short ID) { cStringsSingle *string; @@ -1014,7 +1085,8 @@ static void SP_UpdateLanguage(void) void SP_Init(void) { sp_language = Cvar_Get("sp_language", va("%d", SP_LANGUAGE_ENGLISH), CVAR_ARCHIVE | CVAR_NORESTART); - sp_show_strip = Cvar_Get ("sv_show_strip", "0", 0); // don't switch this on!!!!!!, test only (apparently) + sp_show_strip = Cvar_Get ("sp_show_strip", "0", 0); // don't switch this on!!!!!!, test only (apparently) + sp_leet = Cvar_Get ("sp_leet", "0", CVAR_ROM); // do NOT leave this on in final product!!!! (only works when == 42 anyway ;-) // Cvar_Set("sp_language", va("%d", SP_LANGUAGE_JAPANESE)); // stetest, do NOT leave in diff --git a/code/qcommon/strippublic.h b/code/qcommon/strippublic.h index 74a5f6c..8706ede 100644 --- a/code/qcommon/strippublic.h +++ b/code/qcommon/strippublic.h @@ -55,6 +55,9 @@ void SP_Unload(unsigned char Registration); // Direct string functions int SP_GetStringID(const char *Reference); +#ifdef _DEBUG +const char *SP_GetReferenceText(unsigned short ID, const char *&psPackageName, const char *&psPackageReference, const char *&psText); +#endif const char *SP_GetStringText(unsigned short ID); const char *SP_GetStringTextString(const char *Reference); diff --git a/code/qcommon/stv_version.h b/code/qcommon/stv_version.h index cbc1f7d..3f6af50 100644 --- a/code/qcommon/stv_version.h +++ b/code/qcommon/stv_version.h @@ -1,6 +1,6 @@ // Current version of the single player game -#define Q3_VERSION "JK2: v0.56" +#define Q3_VERSION "JK2: v1.02a" // end diff --git a/code/qcommon/vssver.scc b/code/qcommon/vssver.scc new file mode 100644 index 0000000..17e5a0b Binary files /dev/null and b/code/qcommon/vssver.scc differ diff --git a/code/renderer/amd3d.h b/code/renderer/amd3d.h new file mode 100644 index 0000000..45fece2 --- /dev/null +++ b/code/renderer/amd3d.h @@ -0,0 +1,471 @@ +/****************************************************************** +; * +; * Copyright (c) 1996-1998 ADVANCED MICRO DEVICES, INC. +; * All Rights reserved. +; * +; * This software is unpublished and contains the trade secrets +; * and confidential proprietary information of AMD. Unless +; * otherwise provided in the Software Agreement associated +; * herewith, it is licensed in confidence "AS IS" and +; * is not to be reproduced in whole or part by any means except +; * for backup. Use, duplication, or disclosure by the Government +; * is subject to the restrictions in paragraph(b)(3)(B)of the +; * Rights in Technical Data and Computer Software clause in +; * DFAR 52.227-7013(a)(Oct 1988). Software owned by Advanced +; * Micro Devices Inc., One AMD Place, P.O. Box 3453, Sunnyvale, +; * CA 94088-3453. +; * +; ****************************************************************** + * + * AMD3D.H + * + * MACRO FORMAT + * ============ + * This file contains inline assembly macros that + * generate AMD-3D instructions in binary format. + * Therefore, C or C++ programmer can use AMD-3D instructions + * without any penalty in their C or C++ source code. + * + * The macro's name and format conventions are as follow: + * + * + * 1. First argument of macro is a destination and + * second argument is a source operand. + * ex) _asm PFCMPEQ (m3, m4) + * | | + * dst src + * + * 2. The destination operand can be m0 to m7 only. + * The source operand can be any one of the register + * m0 to m7 or _eax, _ecx, _edx, _ebx, _esi, or _edi + * that contains effective address. + * ex) _asm PFRCP (M7, M6) + * ex) _asm PFRCPIT2 (m0, m4) + * ex) _asm PFMUL (m3, _edi) + * + * 3. The prefetch(w) takes one src operand _eax, ecx, _edx, + * _ebx, _esi, or _edi that contains effective address. + * ex) _asm PREFETCH (_edi) + * + * EXAMPLE + * ======= + * Following program doesn't do anything but it shows you + * how to use inline assembly AMD-3D instructions in C. + * Note that this will only work in flat memory model which + * segment registers cs, ds, ss and es point to the same + * linear address space total less than 4GB. + * + * Used Microsoft VC++ 5.0 + * + * #include + * #include "amd3d.h" + * + * void main () + * { + * float x = (float)1.25; + * float y = (float)1.25; + * float z, zz; + * + * _asm { + * movd mm1, x + * movd mm2, y + * pfmul (m1, m2) + * movd z, mm1 + * femms + * } + * + * printf ("value of z = %f\n", z); + * + * // + * // Demonstration of using the memory instead of + * // multimedia register + * // + * _asm { + * movd mm3, x + * lea esi, y // load effective address of y + * pfmul (m3, _esi) + * movd zz, mm3 + * femms + * } + * + * printf ("value of zz = %f\n", zz); + * } + ******************************************************************/ + +#define M0 0xc0 +#define M1 0xc1 +#define M2 0xc2 +#define M3 0xc3 +#define M4 0xc4 +#define M5 0xc5 +#define M6 0xc6 +#define M7 0xc7 + +#define m0 0xc0 +#define m1 0xc1 +#define m2 0xc2 +#define m3 0xc3 +#define m4 0xc4 +#define m5 0xc5 +#define m6 0xc6 +#define m7 0xc7 +#define _EAX 0x00 +#define _ECX 0x01 +#define _EDX 0x02 +#define _EBX 0x03 +#define _ESI 0x06 +#define _EDI 0x07 +#define _eax 0x00 +#define _ecx 0x01 +#define _edx 0x02 +#define _ebx 0x03 +#define _esi 0x06 +#define _edi 0x07 + +#define PF2ID(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x1d \ +} + +#define PFACC(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xae \ +} + +#define PFADD(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x9e \ +} + +#define PFCMPEQ(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xb0 \ +} + +#define PFCMPGE(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x90 \ +} + +#define PFCMPGT(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xa0 \ +} + +#define PFMAX(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xa4 \ +} + +#define PFMIN(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x94 \ +} + +#define PFMUL(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xb4 \ +} + +#define PFRCP(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x96 \ +} + +#define PFRCPIT1(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xa6 \ +} + +#define PFRCPIT2(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xb6 \ +} + +#define PFRSQRT(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x97 \ +} + +#define PFRSQIT1(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xa7 \ +} + +#define PFSUB(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x9a \ +} + +#define PFSUBR(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xaa \ +} + +#define PI2FD(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x0d \ +} + +#define FEMMS \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0e \ +} + +#define PAVGUSB(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xbf \ +} + +#define PMULHRW(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xb7 \ +} + +#define PREFETCH(src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0d \ + _asm _emit 0x00 | src \ +} + +#define PREFETCHW(src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0d \ + _asm _emit 0x08 | src \ +} + +// +// Exactly same as above except macro names are all +// lower case latter. +// +#define pf2id(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x1d \ +} + +#define pfacc(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xae \ +} + +#define pfadd(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x9e \ +} + +#define pfcmpeq(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xb0 \ +} + +#define pfcmpge(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x90 \ +} + +#define pfcmpgt(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xa0 \ +} + +#define pfmax(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xa4 \ +} + +#define pfmin(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x94 \ +} + +#define pfmul(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xb4 \ +} + +#define pfrcp(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x96 \ +} + +#define pfrcpit1(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xa6 \ +} + +#define pfrcpit2(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xb6 \ +} + +#define pfrsqrt(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x97 \ +} + +#define pfrsqit1(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xa7 \ +} + +#define pfsub(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x9a \ +} + +#define pfsubr(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xaa \ +} + +#define pi2fd(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0x0d \ +} + +#define femms \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0e \ +} + +#define pavgusb(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xbf \ +} + +#define pmulhrw(dst, src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0f \ + _asm _emit ((dst & 0x3f) << 3) | src \ + _asm _emit 0xb7 \ +} + +#define prefetch(src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0d \ + _asm _emit 0x00 | src \ +} + +#define prefetchw(src) \ +{\ + _asm _emit 0x0f \ + _asm _emit 0x0d \ + _asm _emit 0x08 | src \ +} diff --git a/code/renderer/mdx_format.h b/code/renderer/mdx_format.h index 113c9f9..46903f3 100644 --- a/code/renderer/mdx_format.h +++ b/code/renderer/mdx_format.h @@ -294,20 +294,23 @@ static inline int G2_GetVertBoneIndex( const mdxmVertex_t *pVert, const int iWei return iBoneIndex; } -static inline float G2_GetVertBoneWeight( const mdxmVertex_t *pVert, const int iWeightNum ) +static inline float G2_GetVertBoneWeight( const mdxmVertex_t *pVert, const int iWeightNum, float &fTotalWeight, int iNumWeights ) { - int iTemp = pVert->BoneWeightings[iWeightNum]; - iTemp|= (pVert->uiNmWeightsAndBoneIndexes >> (iG2_BONEWEIGHT_TOPBITS_SHIFT+(iWeightNum*2)) ) & iG2_BONEWEIGHT_TOPBITS_AND; + float fBoneWeight; - float fBoneWeight = fG2_BONEWEIGHT_RECIPROCAL_MULT * iTemp; - - if (fBoneWeight == 0.0f) + if (iWeightNum == iNumWeights-1) { - // special case to fix flatten-to-zero cases for extremely light weightings. Could probably be omitted if desperate... - // - fBoneWeight = 0.00045f; + fBoneWeight = 1.0f-fTotalWeight; } - + else + { + int iTemp = pVert->BoneWeightings[iWeightNum]; + iTemp|= (pVert->uiNmWeightsAndBoneIndexes >> (iG2_BONEWEIGHT_TOPBITS_SHIFT+(iWeightNum*2)) ) & iG2_BONEWEIGHT_TOPBITS_AND; + + fBoneWeight = fG2_BONEWEIGHT_RECIPROCAL_MULT * iTemp; + fTotalWeight += fBoneWeight; + } + return fBoneWeight; } #endif diff --git a/code/renderer/mssccprj.scc b/code/renderer/mssccprj.scc new file mode 100644 index 0000000..df82911 --- /dev/null +++ b/code/renderer/mssccprj.scc @@ -0,0 +1,5 @@ +SCC = This is a Source Code Control file + +[renderer.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\StarWars" +SCC_Project_Name = "$/code/renderer", VVOAAAAA diff --git a/code/renderer/qgl_linked.h b/code/renderer/qgl_linked.h new file mode 100644 index 0000000..cf48a7c --- /dev/null +++ b/code/renderer/qgl_linked.h @@ -0,0 +1,336 @@ + +#define qglAccum glAccum +#define qglAlphaFunc glAlphaFunc +#define qglAreTexturesResident glAreTexturesResident +#define qglArrayElement glArrayElement +#define qglBegin glBegin +#define qglBindTexture glBindTexture +#define qglBitmap glBitmap +#define qglBlendFunc glBlendFunc +#define qglCallList glCallList +#define qglCallLists glCallLists +#define qglClear glClear +#define qglClearAccum glClearAccum +#define qglClearColor glClearColor +#define qglClearDepth glClearDepth +#define qglClearIndex glClearIndex +#define qglClearStencil glClearStencil +#define qglClipPlane glClipPlane +#define qglColor3b glColor3b +#define qglColor3bv glColor3bv +#define qglColor3d glColor3d +#define qglColor3dv glColor3dv +#define qglColor3f glColor3f +#define qglColor3fv glColor3fv +#define qglColor3i glColor3i +#define qglColor3iv glColor3iv +#define qglColor3s glColor3s +#define qglColor3sv glColor3sv +#define qglColor3ub glColor3ub +#define qglColor3ubv glColor3ubv +#define qglColor3ui glColor3ui +#define qglColor3uiv glColor3uiv +#define qglColor3us glColor3us +#define qglColor3usv glColor3usv +#define qglColor4b glColor4b +#define qglColor4bv glColor4bv +#define qglColor4d glColor4d +#define qglColor4dv glColor4dv +#define qglColor4f glColor4f +#define qglColor4fv glColor4fv +#define qglColor4i glColor4i +#define qglColor4iv glColor4iv +#define qglColor4s glColor4s +#define qglColor4sv glColor4sv +#define qglColor4ub glColor4ub +#define qglColor4ubv glColor4ubv +#define qglColor4ui glColor4ui +#define qglColor4uiv glColor4uiv +#define qglColor4us glColor4us +#define qglColor4usv glColor4usv +#define qglColorMask glColorMask +#define qglColorMaterial glColorMaterial +#define qglColorPointer glColorPointer +#define qglCopyPixels glCopyPixels +#define qglCopyTexImage1D glCopyTexImage1D +#define qglCopyTexImage2D glCopyTexImage2D +#define qglCopyTexSubImage1D glCopyTexSubImage1D +#define qglCopyTexSubImage2D glCopyTexSubImage2D +#define qglCullFace glCullFace +#define qglDeleteLists glDeleteLists +#define qglDeleteTextures glDeleteTextures +#define qglDepthFunc glDepthFunc +#define qglDepthMask glDepthMask +#define qglDepthRange glDepthRange +#define qglDisable glDisable +#define qglDisableClientState glDisableClientState +#define qglDrawArrays glDrawArrays +#define qglDrawBuffer glDrawBuffer +#define qglDrawElements glDrawElements +#define qglDrawPixels glDrawPixels +#define qglEdgeFlag glEdgeFlag +#define qglEdgeFlagPointer glEdgeFlagPointer +#define qglEdgeFlagv glEdgeFlagv +#define qglEnable glEnable +#define qglEnableClientState glEnableClientState +#define qglEnd glEnd +#define qglEndList glEndList +#define qglEvalCoord1d glEvalCoord1d +#define qglEvalCoord1dv glEvalCoord1dv +#define qglEvalCoord1f glEvalCoord1f +#define qglEvalCoord1fv glEvalCoord1fv +#define qglEvalCoord2d glEvalCoord2d +#define qglEvalCoord2dv glEvalCoord2dv +#define qglEvalCoord2f glEvalCoord2f +#define qglEvalCoord2fv glEvalCoord2fv +#define qglEvalMesh1 glEvalMesh1 +#define qglEvalMesh2 glEvalMesh2 +#define qglEvalPoint1 glEvalPoint1 +#define qglEvalPoint2 glEvalPoint2 +#define qglFeedbackBuffer glFeedbackBuffer +#define qglFinish glFinish +#define qglFlush glFlush +#define qglFogf glFogf +#define qglFogfv glFogfv +#define qglFogi glFogi +#define qglFogiv glFogiv +#define qglFrontFace glFrontFace +#define qglFrustum glFrustum +#define qglGenLists glGenLists +#define qglGenTextures glGenTextures +#define qglGetBooleanv glGetBooleanv +#define qglGetClipPlane glGetClipPlane +#define qglGetDoublev glGetDoublev +#define qglGetError glGetError +#define qglGetFloatv glGetFloatv +#define qglGetIntegerv glGetIntegerv +#define qglGetLightfv glGetLightfv +#define qglGetLightiv glGetLightiv +#define qglGetMapdv glGetMapdv +#define qglGetMapfv glGetMapfv +#define qglGetMapiv glGetMapiv +#define qglGetMaterialfv glGetMaterialfv +#define qglGetMaterialiv glGetMaterialiv +#define qglGetPixelMapfv glGetPixelMapfv +#define qglGetPixelMapuiv glGetPixelMapuiv +#define qglGetPixelMapusv glGetPixelMapusv +#define qglGetPointerv glGetPointerv +#define qglGetPolygonStipple glGetPolygonStipple +#define qglGetString glGetString +#define qglGetTexGendv glGetTexGendv +#define qglGetTexGenfv glGetTexGenfv +#define qglGetTexGeniv glGetTexGeniv +#define qglGetTexImage glGetTexImage +#define qglGetTexLevelParameterfv glGetTexLevelParameterfv +#define qglGetTexLevelParameteriv glGetTexLevelParameteriv +#define qglGetTexParameterfv glGetTexParameterfv +#define qglGetTexParameteriv glGetTexParameteriv +#define qglHint glHint +#define qglIndexMask glIndexMask +#define qglIndexPointer glIndexPointer +#define qglIndexd glIndexd +#define qglIndexdv glIndexdv +#define qglIndexf glIndexf +#define qglIndexfv glIndexfv +#define qglIndexi glIndexi +#define qglIndexiv glIndexiv +#define qglIndexs glIndexs +#define qglIndexsv glIndexsv +#define qglIndexub glIndexub +#define qglIndexubv glIndexubv +#define qglInitNames glInitNames +#define qglInterleavedArrays glInterleavedArrays +#define qglIsEnabled glIsEnabled +#define qglIsList glIsList +#define qglIsTexture glIsTexture +#define qglLightModelf glLightModelf +#define qglLightModelfv glLightModelfv +#define qglLightModeli glLightModeli +#define qglLightModeliv glLightModeliv +#define qglLightf glLightf +#define qglLightfv glLightfv +#define qglLighti glLighti +#define qglLightiv glLightiv +#define qglLineStipple glLineStipple +#define qglLineWidth glLineWidth +#define qglListBase glListBase +#define qglLoadIdentity glLoadIdentity +#define qglLoadMatrixd glLoadMatrixd +#define qglLoadMatrixf glLoadMatrixf +#define qglLoadName glLoadName +#define qglLogicOp glLogicOp +#define qglMap1d glMap1d +#define qglMap1f glMap1f +#define qglMap2d glMap2d +#define qglMap2f glMap2f +#define qglMapGrid1d glMapGrid1d +#define qglMapGrid1f glMapGrid1f +#define qglMapGrid2d glMapGrid2d +#define qglMapGrid2f glMapGrid2f +#define qglMaterialf glMaterialf +#define qglMaterialfv glMaterialfv +#define qglMateriali glMateriali +#define qglMaterialiv glMaterialiv +#define qglMatrixMode glMatrixMode +#define qglMultMatrixd glMultMatrixd +#define qglMultMatrixf glMultMatrixf +#define qglNewList glNewList +#define qglNormal3b glNormal3b +#define qglNormal3bv glNormal3bv +#define qglNormal3d glNormal3d +#define qglNormal3dv glNormal3dv +#define qglNormal3f glNormal3f +#define qglNormal3fv glNormal3fv +#define qglNormal3i glNormal3i +#define qglNormal3iv glNormal3iv +#define qglNormal3s glNormal3s +#define qglNormal3sv glNormal3sv +#define qglNormalPointer glNormalPointer +#define qglOrtho glOrtho +#define qglPassThrough glPassThrough +#define qglPixelMapfv glPixelMapfv +#define qglPixelMapuiv glPixelMapuiv +#define qglPixelMapusv glPixelMapusv +#define qglPixelStoref glPixelStoref +#define qglPixelStorei glPixelStorei +#define qglPixelTransferf glPixelTransferf +#define qglPixelTransferi glPixelTransferi +#define qglPixelZoom glPixelZoom +#define qglPointSize glPointSize +#define qglPolygonMode glPolygonMode +#define qglPolygonOffset glPolygonOffset +#define qglPolygonStipple glPolygonStipple +#define qglPopAttrib glPopAttrib +#define qglPopClientAttrib glPopClientAttrib +#define qglPopMatrix glPopMatrix +#define qglPopName glPopName +#define qglPrioritizeTextures glPrioritizeTextures +#define qglPushAttrib glPushAttrib +#define qglPushClientAttrib glPushClientAttrib +#define qglPushMatrix glPushMatrix +#define qglPushName glPushName +#define qglRasterPos2d glRasterPos2d +#define qglRasterPos2dv glRasterPos2dv +#define qglRasterPos2f glRasterPos2f +#define qglRasterPos2fv glRasterPos2fv +#define qglRasterPos2i glRasterPos2i +#define qglRasterPos2iv glRasterPos2iv +#define qglRasterPos2s glRasterPos2s +#define qglRasterPos2sv glRasterPos2sv +#define qglRasterPos3d glRasterPos3d +#define qglRasterPos3dv glRasterPos3dv +#define qglRasterPos3f glRasterPos3f +#define qglRasterPos3fv glRasterPos3fv +#define qglRasterPos3i glRasterPos3i +#define qglRasterPos3iv glRasterPos3iv +#define qglRasterPos3s glRasterPos3s +#define qglRasterPos3sv glRasterPos3sv +#define qglRasterPos4d glRasterPos4d +#define qglRasterPos4dv glRasterPos4dv +#define qglRasterPos4f glRasterPos4f +#define qglRasterPos4fv glRasterPos4fv +#define qglRasterPos4i glRasterPos4i +#define qglRasterPos4iv glRasterPos4iv +#define qglRasterPos4s glRasterPos4s +#define qglRasterPos4sv glRasterPos4sv +#define qglReadBuffer glReadBuffer +#define qglReadPixels glReadPixels +#define qglRectd glRectd +#define qglRectdv glRectdv +#define qglRectf glRectf +#define qglRectfv glRectfv +#define qglRecti glRecti +#define qglRectiv glRectiv +#define qglRects glRects +#define qglRectsv glRectsv +#define qglRenderMode glRenderMode +#define qglRotated glRotated +#define qglRotatef glRotatef +#define qglScaled glScaled +#define qglScalef glScalef +#define qglScissor glScissor +#define qglSelectBuffer glSelectBuffer +#define qglShadeModel glShadeModel +#define qglStencilFunc glStencilFunc +#define qglStencilMask glStencilMask +#define qglStencilOp glStencilOp +#define qglTexCoord1d glTexCoord1d +#define qglTexCoord1dv glTexCoord1dv +#define qglTexCoord1f glTexCoord1f +#define qglTexCoord1fv glTexCoord1fv +#define qglTexCoord1i glTexCoord1i +#define qglTexCoord1iv glTexCoord1iv +#define qglTexCoord1s glTexCoord1s +#define qglTexCoord1sv glTexCoord1sv +#define qglTexCoord2d glTexCoord2d +#define qglTexCoord2dv glTexCoord2dv +#define qglTexCoord2f glTexCoord2f +#define qglTexCoord2fv glTexCoord2fv +#define qglTexCoord2i glTexCoord2i +#define qglTexCoord2iv glTexCoord2iv +#define qglTexCoord2s glTexCoord2s +#define qglTexCoord2sv glTexCoord2sv +#define qglTexCoord3d glTexCoord3d +#define qglTexCoord3dv glTexCoord3dv +#define qglTexCoord3f glTexCoord3f +#define qglTexCoord3fv glTexCoord3fv +#define qglTexCoord3i glTexCoord3i +#define qglTexCoord3iv glTexCoord3iv +#define qglTexCoord3s glTexCoord3s +#define qglTexCoord3sv glTexCoord3sv +#define qglTexCoord4d glTexCoord4d +#define qglTexCoord4dv glTexCoord4dv +#define qglTexCoord4f glTexCoord4f +#define qglTexCoord4fv glTexCoord4fv +#define qglTexCoord4i glTexCoord4i +#define qglTexCoord4iv glTexCoord4iv +#define qglTexCoord4s glTexCoord4s +#define qglTexCoord4sv glTexCoord4sv +#define qglTexCoordPointer glTexCoordPointer +#define qglTexEnvf glTexEnvf +#define qglTexEnvfv glTexEnvfv +#define qglTexEnvi glTexEnvi +#define qglTexEnviv glTexEnviv +#define qglTexGend glTexGend +#define qglTexGendv glTexGendv +#define qglTexGenf glTexGenf +#define qglTexGenfv glTexGenfv +#define qglTexGeni glTexGeni +#define qglTexGeniv glTexGeniv +#define qglTexImage1D glTexImage1D +#define qglTexImage2D glTexImage2D +#define qglTexParameterf glTexParameterf +#define qglTexParameterfv glTexParameterfv +#define qglTexParameteri glTexParameteri +#define qglTexParameteriv glTexParameteriv +#define qglTexSubImage1D glTexSubImage1D +#define qglTexSubImage2D glTexSubImage2D +#define qglTranslated glTranslated +#define qglTranslatef glTranslatef +#define qglVertex2d glVertex2d +#define qglVertex2dv glVertex2dv +#define qglVertex2f glVertex2f +#define qglVertex2fv glVertex2fv +#define qglVertex2i glVertex2i +#define qglVertex2iv glVertex2iv +#define qglVertex2s glVertex2s +#define qglVertex2sv glVertex2sv +#define qglVertex3d glVertex3d +#define qglVertex3dv glVertex3dv +#define qglVertex3f glVertex3f +#define qglVertex3fv glVertex3fv +#define qglVertex3i glVertex3i +#define qglVertex3iv glVertex3iv +#define qglVertex3s glVertex3s +#define qglVertex3sv glVertex3sv +#define qglVertex4d glVertex4d +#define qglVertex4dv glVertex4dv +#define qglVertex4f glVertex4f +#define qglVertex4fv glVertex4fv +#define qglVertex4i glVertex4i +#define qglVertex4iv glVertex4iv +#define qglVertex4s glVertex4s +#define qglVertex4sv glVertex4sv +#define qglVertexPointer glVertexPointer +#define qglViewport glViewport + diff --git a/code/renderer/ref_trin.def b/code/renderer/ref_trin.def new file mode 100644 index 0000000..2fefbd3 --- /dev/null +++ b/code/renderer/ref_trin.def @@ -0,0 +1,2 @@ +EXPORTS + GetRefAPI diff --git a/code/renderer/renderer.dsp b/code/renderer/renderer.dsp new file mode 100644 index 0000000..5ce419f --- /dev/null +++ b/code/renderer/renderer.dsp @@ -0,0 +1,777 @@ +# Microsoft Developer Studio Project File - Name="renderer" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=renderer - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "renderer.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "renderer.mak" CFG="renderer - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "renderer - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "renderer - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE "renderer - Win32 FinalBuild" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Code/renderer", NCMAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "renderer - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\Release" +# PROP Intermediate_Dir "..\Release\renderer" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /Ob2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "__USEA3D" /D "__A3D_GEOM" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\Debug" +# PROP Intermediate_Dir "..\Debug\renderer" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /G6 /MTd /W3 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "__USEA3D" /D "__A3D_GEOM" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "renderer___Win32_FinalBuild" +# PROP BASE Intermediate_Dir "renderer___Win32_FinalBuild" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\FinalBuild" +# PROP Intermediate_Dir "..\FinalBuild\renderer" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /Ob2 /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "__USEA3D" /D "__A3D_GEOM" /YX /FD /c +# ADD CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /Ob2 /D "_MBCS" /D "_LIB" /D "__USEA3D" /D "__A3D_GEOM" /D "WIN32" /D "NDEBUG" /D "FINAL_BUILD" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "renderer - Win32 Release" +# Name "renderer - Win32 Debug" +# Name "renderer - Win32 FinalBuild" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\MatComp.c +# End Source File +# Begin Source File + +SOURCE=.\tr_animation.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_backend.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_bsp.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_cmds.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_curve.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_draw.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_ghoul2.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_image.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_init.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_jpeg_interface.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_light.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_marks.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_mesh.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_model.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_noise.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_scene.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_shade.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_shade_calc.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_shader.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_shadows.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_sky.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_stl.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_surface.cpp +# End Source File +# Begin Source File + +SOURCE=.\tr_world.cpp +# End Source File +# Begin Source File + +SOURCE=..\win32\win_gamma.cpp +# End Source File +# Begin Source File + +SOURCE=..\win32\win_glimp.cpp +# End Source File +# Begin Source File + +SOURCE=..\win32\win_qgl.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\amd3d.h +# End Source File +# Begin Source File + +SOURCE=..\game\channels.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\cm_public.h +# End Source File +# Begin Source File + +SOURCE=..\game\ghoul2_shared.h +# End Source File +# Begin Source File + +SOURCE=.\glext.h +# End Source File +# Begin Source File + +SOURCE=..\win32\glw_win.h +# End Source File +# Begin Source File + +SOURCE=.\MatComp.h +# End Source File +# Begin Source File + +SOURCE=.\mdx_format.h +# End Source File +# Begin Source File + +SOURCE=..\game\q_shared.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qcommon.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qfiles.h +# End Source File +# Begin Source File + +SOURCE=.\qgl.h +# End Source File +# Begin Source File + +SOURCE=..\game\surfaceflags.h +# End Source File +# Begin Source File + +SOURCE=.\tr_jpeg_interface.h +# End Source File +# Begin Source File + +SOURCE=.\tr_local.h +# End Source File +# Begin Source File + +SOURCE=.\tr_public.h +# End Source File +# Begin Source File + +SOURCE=.\tr_stl.h +# End Source File +# Begin Source File + +SOURCE=.\tr_types.h +# End Source File +# Begin Source File + +SOURCE=..\win32\win_local.h +# End Source File +# End Group +# Begin Group "JPEG Source" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\jpeg6\jcomapi.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdapimin.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdapistd.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdatasrc.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdcoefct.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdcolor.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jddctmgr.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdhuff.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdinput.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdmainct.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdmarker.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdmaster.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdpostct.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdsample.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdtrans.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jerror.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jidctflt.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jmemmgr.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jmemnobs.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jutils.c + +!IF "$(CFG)" == "renderer - Win32 Release" + +# ADD CPP /W3 + +!ELSEIF "$(CFG)" == "renderer - Win32 Debug" + +# ADD CPP /W3 +# SUBTRACT CPP /YX + +!ELSEIF "$(CFG)" == "renderer - Win32 FinalBuild" + +# ADD BASE CPP /W3 +# ADD CPP /W3 + +!ENDIF + +# End Source File +# End Group +# Begin Group "JPEG Headers" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\jpeg6\jconfig.h +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdct.h +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jdhuff.h +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jerror.h +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jinclude.h +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jmemsys.h +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jmorecfg.h +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jpegint.h +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jpeglib.h +# End Source File +# Begin Source File + +SOURCE=..\jpeg6\jversion.h +# End Source File +# End Group +# End Target +# End Project diff --git a/code/renderer/tr_animation.cpp b/code/renderer/tr_animation.cpp index e3d7b85..9a88500 100644 --- a/code/renderer/tr_animation.cpp +++ b/code/renderer/tr_animation.cpp @@ -304,6 +304,7 @@ void R_AddAnimSurfaces( trRefEntity_t *ent ) { if ( !personalModel && r_shadows->integer == 2 && fogNum == 0 + && (ent->e.renderfx & RF_SHADOW_PLANE ) && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) && shader->sort == SS_OPAQUE ) { #ifdef _NPATCH diff --git a/code/renderer/tr_bsp.cpp b/code/renderer/tr_bsp.cpp index 01c400c..8ffc0c6 100644 --- a/code/renderer/tr_bsp.cpp +++ b/code/renderer/tr_bsp.cpp @@ -86,7 +86,7 @@ static void R_ColorShiftLightingBytes( const byte in[4], byte out[4] ) { // should NOT do it if overbrightBits is 0 if (tr.overbrightBits) - shift = r_mapOverBrightBits->integer - tr.overbrightBits; + shift = 1 - tr.overbrightBits; if (!shift) { @@ -131,7 +131,7 @@ static void R_ColorShiftLightingBytes( byte in[3]) // should NOT do it if overbrightBits is 0 if (tr.overbrightBits) - shift = r_mapOverBrightBits->integer - tr.overbrightBits; + shift = 1 - tr.overbrightBits; if (!shift) { return; //no need if not overbright diff --git a/code/renderer/tr_draw.cpp b/code/renderer/tr_draw.cpp index 135707c..0f83927 100644 --- a/code/renderer/tr_draw.cpp +++ b/code/renderer/tr_draw.cpp @@ -52,21 +52,12 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * } #endif - qglTexImage2D( GL_TEXTURE_2D, 0, 3, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); + qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); -#if 0 - { - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); - } -#else - { - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } -#endif - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //GL_CLAMP + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); #ifdef TIMEBIND if ( r_ignore->integer ) @@ -130,11 +121,11 @@ void RE_UploadCinematic (int cols, int rows, const byte *data, int client, qbool if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; - qglTexImage2D( GL_TEXTURE_2D, 0, 3, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); + qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); //GL_CLAMP + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); + qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); } else { if (dirty) { // otherwise, just subimage upload it so that drivers can tell we are going to be changing @@ -194,6 +185,8 @@ void RE_GetScreenShot(byte *buffer, int w, int h) float xScale, yScale; int xx, yy; + qglFinish(); // try and fix broken Radeon cards (7500 & 8500) that don't read screen pixels properly + source = (byte *)ri.Malloc(glConfig.vidWidth * glConfig.vidHeight * 3, TAG_TEMP_WORKSPACE, qfalse); if(!source) { diff --git a/code/renderer/tr_flares.cpp b/code/renderer/tr_flares.cpp new file mode 100644 index 0000000..a8e9140 --- /dev/null +++ b/code/renderer/tr_flares.cpp @@ -0,0 +1,427 @@ +// tr_flares.c + +#include "tr_local.h" + +/* +============================================================================= + +LIGHT FLARES + +A light flare is an effect that takes place inside the eye when bright light +sources are visible. The size of the flare reletive to the screen is nearly +constant, irrespective of distance, but the intensity should be proportional to the +projected area of the light source. + +A surface that has been flagged as having a light flare will calculate the depth +buffer value that it's midpoint should have when the surface is added. + +After all opaque surfaces have been rendered, the depth buffer is read back for +each flare in view. If the point has not been obscured by a closer surface, the +flare should be drawn. + +Surfaces that have a repeated texture should never be flagged as flaring, because +there will only be a single flare added at the midpoint of the polygon. + +To prevent abrupt popping, the intensity of the flare is interpolated up and +down as it changes visibility. This involves scene to scene state, unlike almost +all other aspects of the renderer, and is complicated by the fact that a single +frame may have multiple scenes. + +RB_RenderFlares() will be called once per view (twice in a mirrored scene, potentially +up to five or more times in a frame with 3D status bar icons). + +============================================================================= +*/ + + +// flare states maintain visibility over multiple frames for fading +// layers: view, mirror, menu +typedef struct flare_s { + struct flare_s *next; // for active chain + + int addedFrame; + + qboolean inPortal; // true if in a portal view of the scene + int frameSceneNum; + void *surface; + int fogNum; + + int fadeTime; + + qboolean visible; // state of last test + float drawIntensity; // may be non 0 even if !visible due to fading + float lightScale; + int windowX, windowY; + float eyeZ; + + vec3_t color; +} flare_t; + +#define MAX_FLARES 128 + +flare_t r_flareStructs[MAX_FLARES]; +flare_t *r_activeFlares, *r_inactiveFlares; + +/* +================== +R_ClearFlares +================== +*/ +void R_ClearFlares( void ) { + int i; + + memset( r_flareStructs, 0, sizeof( r_flareStructs ) ); + r_activeFlares = NULL; + r_inactiveFlares = NULL; + + for ( i = 0 ; i < MAX_FLARES ; i++ ) { + r_flareStructs[i].next = r_inactiveFlares; + r_inactiveFlares = &r_flareStructs[i]; + } +} + + +/* +================== +RB_AddFlare + +This is called at surface tesselation time +================== +*/ +void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal, float lightScale) { + int i; + flare_t *f, *oldest; + vec3_t local; + float d; + vec4_t eye, clip, normalized, window; + + backEnd.pc.c_flareAdds++; + + // if the point is off the screen, don't bother adding it + // calculate screen coordinates and depth + R_TransformModelToClip( point, backEnd.or.modelMatrix, + backEnd.viewParms.projectionMatrix, eye, clip ); + + // check to see if the point is completely off screen + for ( i = 0 ; i < 3 ; i++ ) { + if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) { + return; + } + } + + R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window ); + + if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth + || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) { + return; // shouldn't happen, since we check the clip[] above, except for FP rounding + } + + // see if a flare with a matching surface, scene, and view exists + oldest = r_flareStructs; + for ( f = r_activeFlares ; f ; f = f->next ) { + if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum + && f->inPortal == backEnd.viewParms.isPortal ) { + break; + } + } + + // allocate a new one + if (!f ) { + if ( !r_inactiveFlares ) { + // the list is completely full + return; + } + f = r_inactiveFlares; + r_inactiveFlares = r_inactiveFlares->next; + f->next = r_activeFlares; + r_activeFlares = f; + + f->surface = surface; + f->frameSceneNum = backEnd.viewParms.frameSceneNum; + f->inPortal = backEnd.viewParms.isPortal; + f->addedFrame = -1; + } + + if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) { + f->visible = qfalse; + f->fadeTime = backEnd.refdef.time - 2000; + } + + f->addedFrame = backEnd.viewParms.frameCount; + f->fogNum = fogNum; + f->lightScale = lightScale; + + VectorCopy( color, f->color ); + + // fade the intensity of the flare down as the + // light surface turns away from the viewer + if ( normal ) { + VectorSubtract( backEnd.viewParms.or.origin, point, local ); + VectorNormalizeFast( local ); + d = DotProduct( local, normal ); + VectorScale( f->color, d, f->color ); + } + + // save info needed to test + f->windowX = backEnd.viewParms.viewportX + window[0]; + f->windowY = backEnd.viewParms.viewportY + window[1]; + + f->eyeZ = eye[2]; +} + +/* +================== +RB_AddDlightFlares +================== +*/ +void RB_AddDlightFlares( void ) { + dlight_t *l; + int i, j, k; + fog_t *fog; + + if ( !r_flares->integer ) { + return; + } + + l = backEnd.refdef.dlights; + fog = tr.world->fogs; + for (i=0 ; inumfogs ; j++ ) { + fog = &tr.world->fogs[j]; + for ( k = 0 ; k < 3 ; k++ ) { + if ( l->origin[k] < fog->bounds[0][k] || l->origin[k] > fog->bounds[1][k] ) { + break; + } + } + if ( k == 3 ) { + break; + } + } + if ( j == tr.world->numfogs ) { + j = 0; + } + + RB_AddFlare( (void *)l, j, l->origin, l->color, NULL, 1.0f ); + } +} + +/* +=============================================================================== + +FLARE BACK END + +=============================================================================== +*/ + +/* +================== +RB_TestFlare +================== +*/ +void RB_TestFlare( flare_t *f ) { + float depth; + qboolean visible; + float fade; + float screenZ; + + backEnd.pc.c_flareTests++; + + // doing a readpixels is as good as doing a glFinish(), so + // don't bother with another sync + glState.finishCalled = qfalse; + + // read back the z buffer contents + qglReadPixels( f->windowX, f->windowY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth ); + + screenZ = backEnd.viewParms.projectionMatrix[14] / + ( ( 2*depth - 1 ) * backEnd.viewParms.projectionMatrix[11] - backEnd.viewParms.projectionMatrix[10] ); + + visible = ( -f->eyeZ - -screenZ ) < 24; + + if ( visible ) { + if ( !f->visible ) { + f->visible = qtrue; + f->fadeTime = backEnd.refdef.time - 1; + } + fade = ( ( backEnd.refdef.time - f->fadeTime ) /1000.0f ) * r_flareFade->value; + } else { + if ( f->visible ) { + f->visible = qfalse; + f->fadeTime = backEnd.refdef.time - 1; + } + fade = 1.0 - ( ( backEnd.refdef.time - f->fadeTime ) / 1000.0f ) * r_flareFade->value; + } + + if ( fade < 0 ) { + fade = 0; + } + if ( fade > 1 ) { + fade = 1; + } + + f->drawIntensity = fade; +} + + +/* +================== +RB_RenderFlare +================== +*/ +void RB_RenderFlare( flare_t *f ) { + float size; + vec3_t color; + int iColor[3]; + + backEnd.pc.c_flareRenders++; + + VectorScale( f->color, f->drawIntensity*tr.identityLight, color ); + iColor[0] = color[0] * 255; + iColor[1] = color[1] * 255; + iColor[2] = color[2] * 255; + + size = f->lightScale * backEnd.viewParms.viewportWidth * ( r_flareSize->value/640.0 + 8 / -f->eyeZ ); + + RB_BeginSurface( tr.flareShader, f->fogNum ); + + // FIXME: use quadstamp? + tess.xyz[tess.numVertexes][0] = f->windowX - size; + tess.xyz[tess.numVertexes][1] = f->windowY - size; + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = iColor[0]; + tess.vertexColors[tess.numVertexes][1] = iColor[1]; + tess.vertexColors[tess.numVertexes][2] = iColor[2]; + tess.vertexColors[tess.numVertexes][3] = 255; + tess.numVertexes++; + + tess.xyz[tess.numVertexes][0] = f->windowX - size; + tess.xyz[tess.numVertexes][1] = f->windowY + size; + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = iColor[0]; + tess.vertexColors[tess.numVertexes][1] = iColor[1]; + tess.vertexColors[tess.numVertexes][2] = iColor[2]; + tess.vertexColors[tess.numVertexes][3] = 255; + tess.numVertexes++; + + tess.xyz[tess.numVertexes][0] = f->windowX + size; + tess.xyz[tess.numVertexes][1] = f->windowY + size; + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = iColor[0]; + tess.vertexColors[tess.numVertexes][1] = iColor[1]; + tess.vertexColors[tess.numVertexes][2] = iColor[2]; + tess.vertexColors[tess.numVertexes][3] = 255; + tess.numVertexes++; + + tess.xyz[tess.numVertexes][0] = f->windowX + size; + tess.xyz[tess.numVertexes][1] = f->windowY - size; + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = iColor[0]; + tess.vertexColors[tess.numVertexes][1] = iColor[1]; + tess.vertexColors[tess.numVertexes][2] = iColor[2]; + tess.vertexColors[tess.numVertexes][3] = 255; + tess.numVertexes++; + + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 1; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 3; + + RB_EndSurface(); +} + +/* +================== +RB_RenderFlares + +Because flares are simulating an occular effect, they should be drawn after +everything (all views) in the entire frame has been drawn. + +Because of the way portals use the depth buffer to mark off areas, the +needed information would be lost after each view, so we are forced to draw +flares after each view. + +The resulting artifact is that flares in mirrors or portals don't dim properly +when occluded by something in the main view, and portal flares that should +extend past the portal edge will be overwritten. +================== +*/ +void RB_RenderFlares (void) { + flare_t *f; + flare_t **prev; + qboolean draw; + + if ( !r_flares->integer ) { + return; + } + +// RB_AddDlightFlares(); + + // perform z buffer readback on each flare in this view + draw = qfalse; + prev = &r_activeFlares; + while ( ( f = *prev ) != NULL ) { + // throw out any flares that weren't added last frame + if ( f->addedFrame < backEnd.viewParms.frameCount - 1 ) { + *prev = f->next; + f->next = r_inactiveFlares; + r_inactiveFlares = f; + continue; + } + + // don't draw any here that aren't from this scene / portal + f->drawIntensity = 0; + if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum + && f->inPortal == backEnd.viewParms.isPortal ) { + RB_TestFlare( f ); + if ( f->drawIntensity ) { + draw = qtrue; + } else { + // this flare has completely faded out, so remove it from the chain + *prev = f->next; + f->next = r_inactiveFlares; + r_inactiveFlares = f; + continue; + } + } + + prev = &f->next; + } + + if ( !draw ) { + return; // none visible + } + + if ( backEnd.viewParms.isPortal ) { + qglDisable (GL_CLIP_PLANE0); + } + + qglPushMatrix(); + qglLoadIdentity(); + qglMatrixMode( GL_PROJECTION ); + qglPushMatrix(); + qglLoadIdentity(); + qglOrtho( backEnd.viewParms.viewportX, backEnd.viewParms.viewportX + backEnd.viewParms.viewportWidth, + backEnd.viewParms.viewportY, backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight, + -99999, 99999 ); + + for ( f = r_activeFlares ; f ; f = f->next ) { + if ( f->frameSceneNum == backEnd.viewParms.frameSceneNum + && f->inPortal == backEnd.viewParms.isPortal + && f->drawIntensity ) { + RB_RenderFlare( f ); + } + } + + qglPopMatrix(); + qglMatrixMode( GL_MODELVIEW ); + qglPopMatrix(); +} + diff --git a/code/renderer/tr_font.cpp b/code/renderer/tr_font.cpp index ce58efe..d31583c 100644 --- a/code/renderer/tr_font.cpp +++ b/code/renderer/tr_font.cpp @@ -385,7 +385,7 @@ CFontInfo::CFontInfo(const char *fontName) extern cvar_t *com_buildScript; - if (com_buildScript->integer) + if (com_buildScript->integer == 2) { static qboolean bDone = qfalse; // Do this once only (for speed)... if (!bDone) @@ -407,7 +407,7 @@ CFontInfo::CFontInfo(const char *fontName) for (int i=0; iGetLetterHorizAdvance( AnyLanguage_ReadCharFromString( &psText )); + unsigned int uiLetter = AnyLanguage_ReadCharFromString( &psText ); + if (uiLetter == 0x0A) + { + iThisWidth = 0; + } + else + { + int iPixelAdvance = curfont->GetLetterHorizAdvance( uiLetter ); + + iThisWidth += Round(iPixelAdvance * fScale); + if (iThisWidth > iMaxWidth) + { + iMaxWidth = iThisWidth; + } + } } - x = Round(x * fScale); - return(x); + + return iMaxWidth; } // not really a font function, but keeps naming consistant... @@ -750,7 +765,7 @@ int RE_Font_HeightPixels(const int iFontHandle, const float fScale) return(0); } -// iMaxPixelWidth is -1 for "all of string", else MBCS char count... +// iMaxPixelWidth is -1 for "all of string", else pixel display count... // void RE_Font_DrawString(int ox, int oy, const char *psText, const float *rgba, const int iFontHandle, int iMaxPixelWidth, const float fScale) { diff --git a/code/renderer/tr_ghoul2.cpp b/code/renderer/tr_ghoul2.cpp index e2c3b29..274d5c5 100644 --- a/code/renderer/tr_ghoul2.cpp +++ b/code/renderer/tr_ghoul2.cpp @@ -114,12 +114,9 @@ public: int mCurrentTouch; // for render smoothing - int mLastTouch; - int mLastLastTouch; bool mSmoothingActive; bool mUnsquash; float mSmoothFactor; - int mLastTime; int mWraithID; // this is just used for debug prints, can use it for any int of interest in JK2 CBoneCache(const model_t *amod,const mdxaHeader_t *aheader) : @@ -149,9 +146,6 @@ public: mFinalBones[i].parent=skel->parent; } mCurrentTouch=3; - mLastTouch=2; - mLastLastTouch=1; - mLastTime=0; } SBoneCalc &Root() { @@ -503,6 +497,7 @@ static int G2_GetBonePoolIndex( const mdxaHeader_t *pMDXAHeader, int iFrame, int #define DEBUG_G2_TIMING (0) +#define DEBUG_G2_TIMING_RENDER_ONLY (1) void G2_TimingModel(boneInfo_t &bone,int currentTime,int numFramesInFile,int ¤tFrame,int &newFrame,float &lerp) { @@ -535,7 +530,7 @@ void G2_TimingModel(boneInfo_t &bone,int currentTime,int numFramesInFile,int &cu { // did we run off the end? if (((animSpeed > 0.0f) && (newFrame_g > endFrame - 1)) || - ((animSpeed < 0.0f) && (newFrame_g < endFrame + 1))) + ((animSpeed < 0.0f) && (newFrame_g < endFrame+1))) { // yep - decide what to do if (bone.flags & BONE_ANIM_OVERRIDE_LOOP) @@ -547,31 +542,31 @@ void G2_TimingModel(boneInfo_t &bone,int currentTime,int numFramesInFile,int &cu // if we do, let me know, I need to insure the mod works // should we be creating a virtual frame? - if ((newFrame_g < endFrame + 1) && (newFrame_g > endFrame)) + if ((newFrame_g < endFrame+1) && (newFrame_g >= endFrame)) { // now figure out what we are lerping between // delta is the fraction between this frame and the next, since the new anim is always at a .0f; - lerp = (newFrame_g - (int)newFrame_g); + lerp = float(endFrame+1)-newFrame_g; // frames are easy to calculate - currentFrame = (int)newFrame_g; + currentFrame = endFrame; assert(currentFrame>=0&¤tFrame=0&&newFrame=0&¤tFrame=0&&newFrame 0.0f) @@ -638,7 +632,7 @@ void G2_TimingModel(boneInfo_t &bone,int currentTime,int numFramesInFile,int &cu } else { - currentFrame = bone.endFrame + 1; + currentFrame = bone.endFrame+1; assert(currentFrame>=0&¤tFrame=0&&newFrame=0&¤tFrame 0.0) { - newFrame = currentFrame + 1; + // frames are easy to calculate + currentFrame = (int)newFrame_g; + // figure out the difference between the two frames - we have to decide what frame and what percentage of that + // frame we want to display + lerp = (newFrame_g - currentFrame); + + assert(currentFrame>=0&¤tFrame= (int)endFrame) @@ -686,34 +682,50 @@ void G2_TimingModel(boneInfo_t &bone,int currentTime,int numFramesInFile,int &cu } else { - currentFrame++; - assert(currentFrame>=0&¤tFramebone.startFrame) { - // we only want to lerp with the first frame of the anim if we are looping - if (bone.flags & BONE_ANIM_OVERRIDE_LOOP) + currentFrame=bone.startFrame; + newFrame = currentFrame; + lerp=0.0f; + } + else + { + newFrame=currentFrame-1; + // are we now on the end frame? + if (newFrame < endFrame+1) { - newFrame = bone.startFrame; - assert(newFrame>=0&&newFrame=0&&newFrame=0&&newFrame=0&&newFrame=0&¤tFrame=0&&newFrame0.0f&&blendTime < boneList[boneListIndex].blendTime) + if (blendTime>=0.0f&&blendTime < boneList[boneListIndex].blendTime) { TB.blendFrame = boneList[boneListIndex].blendFrame; TB.blendOldFrame = boneList[boneListIndex].blendLerpFrame; @@ -823,18 +835,55 @@ void G2_TransformBone (int child,CBoneCache &BC) TB.blendOldFrame=0; } #if DEBUG_G2_TIMING + +#if DEBUG_G2_TIMING_RENDER_ONLY + if (!HackadelicOnClient) + { + printTiming=false; + } +#endif if (printTiming) { char mess[1000]; if (TB.blendMode) { - sprintf(mess,"b %2d %5d %4d %4d %4d %4d %f %f\n",BC.mWraithID,BC.incomingTime,(int)TB.newFrame,(int)TB.currentFrame,(int)TB.blendFrame,(int)TB.blendOldFrame,TB.backlerp,TB.blendLerp); + sprintf(mess,"b %2d %5d %4d %4d %4d %4d %f %f\n",boneListIndex,BC.incomingTime,(int)TB.newFrame,(int)TB.currentFrame,(int)TB.blendFrame,(int)TB.blendOldFrame,TB.backlerp,TB.blendLerp); } else { - sprintf(mess,"a %2d %5d %4d %4d %f\n",BC.mWraithID,BC.incomingTime,TB.newFrame,TB.currentFrame,TB.backlerp); + sprintf(mess,"a %2d %5d %4d %4d %f\n",boneListIndex,BC.incomingTime,TB.newFrame,TB.currentFrame,TB.backlerp); } OutputDebugString(mess); + const boneInfo_t &bone=boneList[boneListIndex]; + if (bone.flags&BONE_ANIM_BLEND) + { + sprintf(mess," bfb[%2d] %5d %5d (%5d-%5d) %4.2f %4x bt(%5d-%5d) %7.2f %5d\n", + boneListIndex, + BC.incomingTime, + bone.startTime, + bone.startFrame, + bone.endFrame, + bone.animSpeed, + bone.flags, + bone.blendStart, + bone.blendStart+bone.blendTime, + bone.blendFrame, + bone.blendLerpFrame + ); + } + else + { + sprintf(mess," bfa[%2d] %5d %5d (%5d-%5d) %4.2f %4x\n", + boneListIndex, + BC.incomingTime, + bone.startTime, + bone.startFrame, + bone.endFrame, + bone.animSpeed, + bone.flags + ); + } +// OutputDebugString(mess); } #endif // boldFrame = (mdxaFrame_t *)((byte *)BC.header + BC.header->ofsFrames + TB.blendOldFrame * BC.frameSize ); @@ -929,7 +978,7 @@ void G2_TransformBone (int child,CBoneCache &BC) int parent=BC.mFinalBones[child].parent; assert((parent==-1&&child==0)||(parent>=0&&parentmSmoothingActive=false; ghoul2.mBoneCache->mUnsquash=false; - ghoul2.mBoneCache->mLastTouch=ghoul2.mBoneCache->mLastLastTouch; // master smoothing control float val=r_Ghoul2AnimSmooth->value; @@ -1150,15 +1192,12 @@ void G2_TransformGhoulBones(boneInfo_v &rootBoneList,mdxaBone_t &rootMatrix, CGh { ghoul2.mBoneCache->mUnsquash=true; } - ghoul2.mBoneCache->mLastTime=time; } else { ghoul2.mBoneCache->mSmoothFactor=1.0f; - ghoul2.mBoneCache->mLastTime=0; } ghoul2.mBoneCache->mCurrentTouch++; - ghoul2.mBoneCache->mLastLastTouch=ghoul2.mBoneCache->mCurrentTouch; ghoul2.mBoneCache->mWraithID=0; ghoul2.mBoneCache->frameSize = 0;// can be deleted in new G2 format //(int)( &((mdxaFrame_t *)0)->boneIndexes[ ghoul2.aHeader->numBones ] ); @@ -1167,8 +1206,8 @@ void G2_TransformGhoulBones(boneInfo_v &rootBoneList,mdxaBone_t &rootMatrix, CGh ghoul2.mBoneCache->incomingTime=time; SBoneCalc &TB=ghoul2.mBoneCache->Root(); - TB.newFrame=ghoul2.mAnimFrameDefault; - TB.currentFrame=ghoul2.mAnimFrameDefault; + TB.newFrame=0; + TB.currentFrame=0; TB.backlerp=0.0f; TB.blendFrame=0; TB.blendOldFrame=0; @@ -1228,11 +1267,12 @@ void G2_ProcessSurfaceBolt2(CBoneCache &boneCache, const mdxmSurface_t *surface, // now go and transform just the points we need from the surface that was hit originally // w = vert0->weights; + float fTotalWeight = 0.0f; int iNumWeights = G2_GetVertWeights( vert0 ); for ( k = 0 ; k < iNumWeights ; k++ ) { int iBoneIndex = G2_GetVertBoneIndex( vert0, k ); - float fBoneWeight = G2_GetVertBoneWeight( vert0, k ); + float fBoneWeight = G2_GetVertBoneWeight( vert0, k, fTotalWeight, iNumWeights ); const mdxaBone_t &bone=boneCache.Eval(piBoneReferences[iBoneIndex]); @@ -1242,11 +1282,12 @@ void G2_ProcessSurfaceBolt2(CBoneCache &boneCache, const mdxmSurface_t *surface, } // w = vert1->weights; + fTotalWeight = 0.0f; iNumWeights = G2_GetVertWeights( vert1 ); for ( k = 0 ; k < iNumWeights ; k++) { int iBoneIndex = G2_GetVertBoneIndex( vert1, k ); - float fBoneWeight = G2_GetVertBoneWeight( vert1, k ); + float fBoneWeight = G2_GetVertBoneWeight( vert1, k, fTotalWeight, iNumWeights ); const mdxaBone_t &bone=boneCache.Eval(piBoneReferences[iBoneIndex]); @@ -1256,11 +1297,12 @@ void G2_ProcessSurfaceBolt2(CBoneCache &boneCache, const mdxmSurface_t *surface, } // w = vert2->weights; + fTotalWeight = 0.0f; iNumWeights = G2_GetVertWeights( vert2 ); for ( k = 0 ; k < iNumWeights ; k++) { int iBoneIndex = G2_GetVertBoneIndex( vert2, k ); - float fBoneWeight = G2_GetVertBoneWeight( vert2, k ); + float fBoneWeight = G2_GetVertBoneWeight( vert2, k, fTotalWeight, iNumWeights ); const mdxaBone_t &bone=boneCache.Eval(piBoneReferences[iBoneIndex]); @@ -1332,10 +1374,11 @@ void G2_ProcessSurfaceBolt2(CBoneCache &boneCache, const mdxmSurface_t *surface, const int iNumWeights = G2_GetVertWeights( v ); + float fTotalWeight = 0.0f; for ( k = 0 ; k < iNumWeights ; k++) { int iBoneIndex = G2_GetVertBoneIndex( v, k ); - float fBoneWeight = G2_GetVertBoneWeight( v, k ); + float fBoneWeight = G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights ); const mdxaBone_t &bone=boneCache.Eval(piBoneReferences[iBoneIndex]); @@ -1506,6 +1549,7 @@ void RenderSurfaces(CRenderSurface &RS) if ( !RS.personalModel && r_shadows->integer == 2 && RS.fogNum == 0 + && (RS.renderfx & RF_SHADOW_PLANE ) && !(RS.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) && shader->sort == SS_OPAQUE ) { // set the surface info to point at the where the transformed bone list is going to be for when the surface gets rendered out @@ -1906,10 +1950,11 @@ void RB_SurfaceGhoul( CRenderableSurface *surf ) { VectorClear( tess.xyz[baseVert]); VectorClear( tess.normal[baseVert]); + float fTotalWeight = 0.0f; for (k = 0 ; k < iNumWeights ; k++) { int iBoneIndex = G2_GetVertBoneIndex( v, k ); - float fBoneWeight = G2_GetVertBoneWeight( v, k ); + float fBoneWeight = G2_GetVertBoneWeight( v, k, fTotalWeight, iNumWeights ); bone = &bones->Eval(piBoneReferences[iBoneIndex]); diff --git a/code/renderer/tr_image.cpp b/code/renderer/tr_image.cpp index ba20c71..0e2c1d5 100644 --- a/code/renderer/tr_image.cpp +++ b/code/renderer/tr_image.cpp @@ -258,7 +258,7 @@ void R_ImageList_f( void ) { ri.Printf( PRINT_ALL, "RGBA8" ); break; case GL_RGB8: - ri.Printf( PRINT_ALL, "RGB8" ); + ri.Printf( PRINT_ALL, "RGB8 " ); break; case GL_RGB4_S3TC: ri.Printf( PRINT_ALL, "S3TC " ); @@ -588,6 +588,7 @@ static void Upload32( unsigned *data, if ( scan[i*4 + 3] != 255 ) { samples = 4; + break; } } @@ -1817,7 +1818,7 @@ void R_CreateBuiltinImages( void ) { // scratchimage is usually used for cinematic drawing for(x=0;xnumfogs ; tr.refdef.fogIndex++ ) - { - fog = &tr.world->fogs[tr.refdef.fogIndex]; - if ( tr.refdef.vieworg[0] >= fog->bounds[0][0] - && tr.refdef.vieworg[1] >= fog->bounds[0][1] - && tr.refdef.vieworg[2] >= fog->bounds[0][2] - && tr.refdef.vieworg[0] <= fog->bounds[1][0] - && tr.refdef.vieworg[1] <= fog->bounds[1][1] - && tr.refdef.vieworg[2] <= fog->bounds[1][2] ) + if ( tr.world->numfogs > 1 ) + {//more than just the LA goggles + fog_t *fog; + int contents = SV_PointContents( tr.refdef.vieworg, 0 ); + if ( (contents&CONTENTS_FOG) ) + {//only take a tr.refdef.fogIndex if the tr.refdef.vieworg is actually *in* that fog brush (assumption: checks pointcontents for any CONTENTS_FOG, not that particular brush...) + for ( tr.refdef.fogIndex = 1 ; tr.refdef.fogIndex < tr.world->numfogs ; tr.refdef.fogIndex++ ) + { + fog = &tr.world->fogs[tr.refdef.fogIndex]; + if ( tr.refdef.vieworg[0] >= fog->bounds[0][0] + && tr.refdef.vieworg[1] >= fog->bounds[0][1] + && tr.refdef.vieworg[2] >= fog->bounds[0][2] + && tr.refdef.vieworg[0] <= fog->bounds[1][0] + && tr.refdef.vieworg[1] <= fog->bounds[1][1] + && tr.refdef.vieworg[2] <= fog->bounds[1][2] ) + { + break; + } + } + if ( tr.refdef.fogIndex == tr.world->numfogs ) + { + tr.refdef.fogIndex = 0; + } + } + else { - break; + tr.refdef.fogIndex = 0; } } - if ( tr.refdef.fogIndex == tr.world->numfogs ) + else { tr.refdef.fogIndex = 0; } diff --git a/code/renderer/tr_mesh.cpp b/code/renderer/tr_mesh.cpp index 28f3f17..20a22ea 100644 --- a/code/renderer/tr_mesh.cpp +++ b/code/renderer/tr_mesh.cpp @@ -391,6 +391,7 @@ void R_AddMD3Surfaces( trRefEntity_t *ent ) { if ( !personalModel && r_shadows->integer == 2 && fogNum == 0 + && (ent->e.renderfx & RF_SHADOW_PLANE ) && !(ent->e.renderfx & ( RF_NOSHADOW | RF_DEPTHHACK ) ) && shader->sort == SS_OPAQUE ) { #ifdef _NPATCH diff --git a/code/renderer/tr_model.cpp b/code/renderer/tr_model.cpp index 6a1e5b6..2cffa17 100644 --- a/code/renderer/tr_model.cpp +++ b/code/renderer/tr_model.cpp @@ -225,7 +225,6 @@ static int GetModelDataAllocSize(void) Z_MemSize( TAG_MODEL_GLA); } extern cvar_t *r_modelpoolmegs; -extern qboolean Sys_LowPhysicalMemory(); // // return qtrue if at least one cached model was freed (which tells z_malloc()-fail recoveryt code to try again) // @@ -404,6 +403,9 @@ void RE_RegisterMedia_LevelLoadEnd(void) } S_RestartMusic(); + + extern qboolean gbAlreadyDoingLoad; + gbAlreadyDoingLoad = qfalse; } diff --git a/code/renderer/tr_quicksprite.cpp b/code/renderer/tr_quicksprite.cpp index 45a5850..356bc44 100644 --- a/code/renderer/tr_quicksprite.cpp +++ b/code/renderer/tr_quicksprite.cpp @@ -17,7 +17,7 @@ CQuickSpriteSystem SQuickSprite; // Construction/Destruction ////////////////////////////////////////////////////////////////////// -CQuickSpriteSystem::CQuickSpriteSystem() +CQuickSpriteSystem::CQuickSpriteSystem(void) { int i; @@ -38,9 +38,8 @@ CQuickSpriteSystem::CQuickSpriteSystem() } } -CQuickSpriteSystem::~CQuickSpriteSystem() +CQuickSpriteSystem::~CQuickSpriteSystem(void) { - } @@ -134,6 +133,17 @@ void CQuickSpriteSystem::StartGroup(textureBundle_t *bundle, unsigned long glbit mUseFog = qfalse; } + int cullingOn; + qglGetIntegerv(GL_CULL_FACE,&cullingOn); + + if(cullingOn) + { + mTurnCullBackOn=true; + } + else + { + mTurnCullBackOn=false; + } qglDisable(GL_CULL_FACE); } @@ -143,7 +153,10 @@ void CQuickSpriteSystem::EndGroup(void) Flush(); qglColor4ub(255,255,255,255); - qglEnable(GL_CULL_FACE); + if(mTurnCullBackOn) + { + qglEnable(GL_CULL_FACE); + } } diff --git a/code/renderer/tr_quicksprite.h b/code/renderer/tr_quicksprite.h index b0dcb21..d7e7036 100644 --- a/code/renderer/tr_quicksprite.h +++ b/code/renderer/tr_quicksprite.h @@ -26,12 +26,13 @@ private: vec2_t mFogTextureCoords[SHADER_MAX_VERTEXES]; unsigned long mColors[SHADER_MAX_VERTEXES]; int mNextVert; + qboolean mTurnCullBackOn; void Flush(void); public: - CQuickSpriteSystem(); - virtual ~CQuickSpriteSystem(); + CQuickSpriteSystem(void); + ~CQuickSpriteSystem(void); void StartGroup(textureBundle_t *bundle, unsigned long glbits, unsigned long fogcolor=0x00000000); void EndGroup(void); diff --git a/code/renderer/tr_scene.cpp b/code/renderer/tr_scene.cpp index a938bd6..ba15d50 100644 --- a/code/renderer/tr_scene.cpp +++ b/code/renderer/tr_scene.cpp @@ -136,7 +136,7 @@ void RE_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *vert r_numpolyverts += numVerts; // see if it is in a fog volume - if ( tr.world->numfogs == 1 ) { + if ( !tr.world || tr.world->numfogs == 1) { fogIndex = 0; } else { // find which fog volume the poly is in diff --git a/code/renderer/tr_sky.cpp b/code/renderer/tr_sky.cpp index 1269ea7..b5b9dcb 100644 --- a/code/renderer/tr_sky.cpp +++ b/code/renderer/tr_sky.cpp @@ -274,6 +274,7 @@ CLOUD VERTEX GENERATION ** ** Parms: s, t range from -1 to 1 */ + static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ ) { // 1 = s, 2 = t, 3 = 2048 @@ -372,6 +373,9 @@ static void DrawSkyBox( shader_t *shader ) { int i; + sky_min = 0.0f; + sky_max = 1.0f; + memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) ); for (i=0 ; i<6 ; i++) @@ -616,6 +620,7 @@ void R_BuildCloudData( shaderCommands_t *input ) ** Called when a sky shader is parsed */ #define SQR( a ) ((a)*(a)) + void R_InitSkyTexCoords( float heightCloud ) { int i, s, t; diff --git a/code/renderer/tr_surfacesprites.cpp b/code/renderer/tr_surfacesprites.cpp index 4c44845..e38480f 100644 --- a/code/renderer/tr_surfacesprites.cpp +++ b/code/renderer/tr_surfacesprites.cpp @@ -101,6 +101,7 @@ static void R_SurfaceSpriteFrameUpdate(void) curWindSpeed = r_windSpeed->value; nextGustTime = 0; gustLeft = 0; + curWindGrassDir[0]=curWindGrassDir[1]=curWindGrassDir[2]=0.0f; } // Reset the last entity drawn, since this is a new frame. diff --git a/code/renderer/vssver.scc b/code/renderer/vssver.scc new file mode 100644 index 0000000..b3e0139 Binary files /dev/null and b/code/renderer/vssver.scc differ diff --git a/code/server/server.h b/code/server/server.h index f9a3b48..6f84380 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -274,7 +274,7 @@ void SV_LoadTransition_f(void); void SV_SaveGame_f(void); void SV_WipeGame_f(void); qboolean SV_TryLoadTransition( const char *mapname ); -void SG_WriteSavegame(const char *psPathlessBaseName, qboolean qbAutosave); +qboolean SG_WriteSavegame(const char *psPathlessBaseName, qboolean qbAutosave); qboolean SG_ReadSavegame(const char *psPathlessBaseName); void SG_WipeSavegame(const char *psPathlessBaseName); qboolean SG_Append(unsigned long chid, void *data, int length); diff --git a/code/server/sv_ccmds.cpp b/code/server/sv_ccmds.cpp index 6e3370b..6a852d2 100644 --- a/code/server/sv_ccmds.cpp +++ b/code/server/sv_ccmds.cpp @@ -100,43 +100,52 @@ void SV_Player_EndOfLevelSave(void) // clientSnapshot_t* pFrame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK]; playerState_t* pState = cl->gentity->client; + const char *s2; - const char *s = va("%i %i %i %i %i %i %f %f %f", + const char *s = va("%i %i %i %i %i %i %i %f %f %f %i %i %i %i %i %i", pState->stats[STAT_HEALTH], pState->stats[STAT_ARMOR], pState->stats[STAT_WEAPONS], pState->stats[STAT_ITEMS], pState->weapon, pState->weaponstate, + pState->batteryCharge, pState->viewangles[0], pState->viewangles[1], - pState->viewangles[2] + pState->viewangles[2], + pState->forcePowersKnown, + pState->forcePower, + pState->saberActive, + pState->saberAnimLevel, + pState->saberLockEnemy, + pState->saberLockTime ); Cvar_Set( sCVARNAME_PLAYERSAVE, s ); - for ( i=0; iammo[i])); + s2 = va("%s %i",s2, pState->ammo[i]); } + Cvar_Set( "playerammo", s2 ); - for ( i=0; iinventory[i])); + s2 = va("%s %i",s2, pState->inventory[i]); } + Cvar_Set( "playerinv", s2 ); // the new JK2 stuff - force powers, etc... // - for ( i=0; iforcePowerLevel[i])); + s2 = va("%s %i",s2, pState->forcePowerLevel[i]); } - - Cvar_Set( "playerfpknown", va( "%i", pState->forcePowersKnown)); - Cvar_Set( "playerfp", va( "%i", pState->forcePower)); - Cvar_Set( "plsa", va( "%i", pState->saberActive)); - Cvar_Set( "plcs", va( "%i", pState->saberAnimLevel)); - Cvar_Set( "plle", va( "%i", pState->saberLockEnemy)); - Cvar_Set( "pllt", va( "%i", pState->saberLockTime)); + Cvar_Set( "playerfplvl", s2 ); } } @@ -199,9 +208,9 @@ static void SV_Map_f( void ) // cheats will not be allowed. If started with "devmap " // then cheats will be allowed if ( !Q_stricmpn( Cmd_Argv(0), "devmap", 6 ) ) { - Cvar_Set( "sv_cheats", "1" ); + Cvar_Set( "helpUsObi", "1" ); } else { - Cvar_Set( "sv_cheats", "0" ); + Cvar_Set( "helpUsObi", "0" ); } Cvar_Set( "cg_missionstatusscreen", "0" );//reset } @@ -397,6 +406,11 @@ void SV_AddOperatorCommands( void ) { Cmd_AddCommand ("loadtransition", SV_LoadTransition_f); Cmd_AddCommand ("save", SV_SaveGame_f); Cmd_AddCommand ("wipe", SV_WipeGame_f); + +//#ifdef _DEBUG +// extern void UI_Dump_f(void); +// Cmd_AddCommand ("ui_dump", UI_Dump_f); +//#endif } /* diff --git a/code/server/sv_client.cpp b/code/server/sv_client.cpp index ef15388..a48333b 100644 --- a/code/server/sv_client.cpp +++ b/code/server/sv_client.cpp @@ -490,14 +490,17 @@ static void SV_UserMove( client_t *cl, msg_t *msg ) { SV_ClientEnterWorld( cl, &cmds[0], eSavedGameJustLoaded ); if ( sv_mapname->string[0]!='_' ) { + char savename[MAX_QPATH]; if ( eSavedGameJustLoaded == eNO ) { SG_WriteSavegame("auto",qtrue); - SG_WriteSavegame(va("auto_%s",sv_mapname->string),qtrue); + Com_sprintf (savename, sizeof(savename), "auto_%s",sv_mapname->string); + SG_WriteSavegame(savename,qtrue);//can't use va becuase it's nested } else if ( qbLoadTransition == qtrue ) { - SG_WriteSavegame( va( "hub/%s", sv_mapname->string ), qfalse );//save a full one + Com_sprintf (savename, sizeof(savename), "hub/%s", sv_mapname->string ); + SG_WriteSavegame( savename, qfalse );//save a full one SG_WriteSavegame( "auto", qfalse );//need a copy for auto, too } } diff --git a/code/server/sv_game.cpp b/code/server/sv_game.cpp index 6b9ca59..f1b998b 100644 --- a/code/server/sv_game.cpp +++ b/code/server/sv_game.cpp @@ -332,8 +332,9 @@ void SV_InitGameProgs (void) { SV_ShutdownGameProgs (); } - if ( !Cvar_VariableValue("fs_restrict") && !Sys_CheckCD() ) { - Com_Error( ERR_NEED_CD, "Game CD not in drive" ); + if ( !Cvar_VariableIntegerValue("fs_restrict") && !Sys_CheckCD() ) + { + Com_Error( ERR_NEED_CD, SP_GetStringTextString("CON_TEXT_NEED_CD") ); //"Game CD not in drive" ); } // load a new game dll @@ -400,7 +401,6 @@ Ghoul2 Insert Start */ import.G2API_AddBolt = G2API_AddBolt; - import.G2API_AnimateG2Models = G2API_AnimateG2Models; import.G2API_AttachEnt = G2API_AttachEnt; import.G2API_AttachG2Model = G2API_AttachG2Model; import.G2API_CollisionDetect = G2API_CollisionDetect; diff --git a/code/server/sv_init.cpp b/code/server/sv_init.cpp index 5194f5b..ec0c05e 100644 --- a/code/server/sv_init.cpp +++ b/code/server/sv_init.cpp @@ -198,7 +198,7 @@ void SV_SpawnServer( char *server, ForceReload_e eForceReload, qboolean bAllowSc Com_Printf ("Server: %s\n",server); // init client structures and svs.numSnapshotEntities - if ( !Cvar_VariableValue("sv_running") ) { + if ( !Cvar_VariableIntegerValue("sv_running") ) { SV_Startup(); } @@ -349,7 +349,7 @@ void SV_Init (void) { sv_mapname = Cvar_Get ("mapname", "nomap", CVAR_SERVERINFO | CVAR_ROM); // systeminfo - Cvar_Get ("sv_cheats", "1", CVAR_SYSTEMINFO ); + Cvar_Get ("helpUsObi", "0", CVAR_SYSTEMINFO ); sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM ); // server vars diff --git a/code/server/sv_savegame.cpp b/code/server/sv_savegame.cpp index 9d4435a..b5b6d29 100644 --- a/code/server/sv_savegame.cpp +++ b/code/server/sv_savegame.cpp @@ -102,6 +102,18 @@ LPCSTR SG_GetChidText(unsigned long chid) } +static const char *GetString_FailedToOpenSaveGame(const char *psFilename, qboolean bOpen) +{ + static char sTemp[256]; + + strcpy(sTemp,S_COLOR_RED); + + const char *psReference = bOpen ? "MENUS3_FAILED_TO_OPEN_SAVEGAME" : "MENUS3_FAILED_TO_CREATE_SAVEGAME"; + Q_strncpyz(sTemp + strlen(sTemp), va( SP_GetStringTextString(psReference), psFilename),sizeof(sTemp)); + strcat(sTemp,"\n"); + return sTemp; +} + // (copes with up to 8 ptr returns at once) // static LPCSTR SG_AddSavePath( LPCSTR psPathlessBaseName ) @@ -150,7 +162,7 @@ static qboolean SG_Create( LPCSTR psPathlessBaseName ) if(!fhSaveGame) { - Com_Printf(S_COLOR_RED "Failed to create new savegame file \"%s\"\n", psLocalFilename ); + Com_Printf(GetString_FailedToOpenSaveGame(psLocalFilename,qfalse));//S_COLOR_RED "Failed to create new savegame file \"%s\"\n", psLocalFilename ); return qfalse; } @@ -177,6 +189,11 @@ void SG_Shutdown() eSavedGameJustLoaded = eNO; // important to do this if we ERR_DROP during loading, else next map you load after // a bad save-file you'll arrive at dead :-) + + // and this bit stops people messing up the laoder by repeatedly stabbing at the load key during loads... + // + extern qboolean gbAlreadyDoingLoad; + gbAlreadyDoingLoad = qfalse; } qboolean SG_Close() @@ -225,7 +242,7 @@ qboolean SG_Open( LPCSTR psPathlessBaseName ) if (!fhSaveGame) { // Com_Printf(S_COLOR_RED "Failed to open savegame file %s\n", psLocalFilename); - Com_DPrintf("Failed to open savegame file %s\n", psLocalFilename); + Com_DPrintf(GetString_FailedToOpenSaveGame(psLocalFilename, qtrue)); return qfalse; } @@ -290,8 +307,15 @@ qboolean SV_TryLoadTransition( const char *mapname ) return qtrue; } +qboolean gbAlreadyDoingLoad = qfalse; void SV_LoadGame_f(void) { + if (gbAlreadyDoingLoad) + { + Com_DPrintf ("( Already loading, ignoring extra 'load' commands... )\n"); + return; + } + // // check server is running // // // if ( !com_sv_running->integer ) @@ -366,12 +390,20 @@ void SV_LoadGame_f(void) } //default will continue to load auto } - + Com_Printf (S_COLOR_CYAN "Loading game \"%s\"...\n", psFilename); - SG_ReadSavegame(psFilename); - Com_Printf (S_COLOR_CYAN "Done.\n"); + + gbAlreadyDoingLoad = qtrue; + if (!SG_ReadSavegame(psFilename)) { + gbAlreadyDoingLoad = qfalse; // do NOT do this here now, need to wait until client spawn, unless the load failed. + } else + { + Com_Printf (S_COLOR_CYAN "Done.\n"); + } } +qboolean SG_GameAllowedToSaveHere(qboolean inCamera); + void SV_SaveGame_f(void) { // check server is running @@ -420,6 +452,15 @@ void SV_SaveGame_f(void) return; } + if (strstr (psFilename, "..") || strstr (psFilename, "/") || strstr (psFilename, "\\") ) + { + Com_Printf (S_COLOR_RED "Bad savegame name.\n"); + return; + } + + if (!SG_GameAllowedToSaveHere(qfalse)) //full check + return; // this prevents people saving via quick-save now during cinematics, and skips the screenshot below! + if (!stricmp (psFilename, "quik*") || !stricmp (psFilename, "auto*") ) { extern void SCR_PrecacheScreenshot(); //scr_scrn.cpp @@ -430,15 +471,15 @@ extern void SCR_PrecacheScreenshot(); //scr_scrn.cpp SG_StoreSaveGameComment(""); // clear previous comment/description, which will force time/date comment. } - if (strstr (psFilename, "..") || strstr (psFilename, "/") || strstr (psFilename, "\\") ) - { - Com_Printf (S_COLOR_RED "Bad savegame name.\n"); - return; - } - Com_Printf (S_COLOR_CYAN "Saving game \"%s\"...\n", psFilename); - SG_WriteSavegame(psFilename, qfalse); - Com_Printf (S_COLOR_CYAN "Done.\n"); + if (SG_WriteSavegame(psFilename, qfalse)) + { + Com_Printf (S_COLOR_CYAN "Done.\n"); + } + else + { + Com_Printf (S_COLOR_RED "Failed.\n"); + } } @@ -465,48 +506,21 @@ static void WriteGame(qboolean autosave) // write ammo... // - for ( int i=0; iGameAllowedToSaveHere(); } -void SG_WriteSavegame(const char *psPathlessBaseName, qboolean qbAutosave) +qboolean SG_WriteSavegame(const char *psPathlessBaseName, qboolean qbAutosave) { if (!qbAutosave && !SG_GameAllowedToSaveHere(qfalse)) //full check - return; // this prevents people saving via quick-save now during cinematics + return qfalse; // this prevents people saving via quick-save now during cinematics float fPrevTestSave = sv_testsave->value; sv_testsave->value = 0; if(!SG_Create( "current" )) { - Com_Printf (S_COLOR_RED "Failed to create savegame\n"); + Com_Printf (GetString_FailedToOpenSaveGame("current",qfalse));//S_COLOR_RED "Failed to create savegame\n"); SG_WipeSavegame( "current" ); sv_testsave->value = fPrevTestSave; - return; + return qfalse; } // Write out server data... @@ -974,15 +968,16 @@ void SG_WriteSavegame(const char *psPathlessBaseName, qboolean qbAutosave) SG_Close(); if (gbSGWriteFailed) { - Com_Printf (S_COLOR_RED "Failed to write savegame!\n"); + Com_Printf (GetString_FailedToOpenSaveGame("current",qfalse));//S_COLOR_RED "Failed to write savegame!\n"); SG_WipeSavegame( "current" ); sv_testsave->value = fPrevTestSave; - return; + return qfalse; } SG_Copy( "current", psPathlessBaseName ); sv_testsave->value = fPrevTestSave; + return qtrue; } qboolean SG_ReadSavegame(const char *psPathlessBaseName) @@ -998,7 +993,7 @@ qboolean SG_ReadSavegame(const char *psPathlessBaseName) if (!SG_Open( psPathlessBaseName )) { - Com_Printf (S_COLOR_RED "Failed to open savegame \"%s\"\n", psPathlessBaseName); + Com_Printf (GetString_FailedToOpenSaveGame(psPathlessBaseName, qtrue));//S_COLOR_RED "Failed to open savegame \"%s\"\n", psPathlessBaseName); sv_testsave->value = fPrevTestSave; return qfalse; } @@ -1039,7 +1034,7 @@ qboolean SG_ReadSavegame(const char *psPathlessBaseName) if(!SG_Close()) { - Com_Printf (S_COLOR_RED "Failed to close savegame\n"); + Com_Printf (GetString_FailedToOpenSaveGame(psPathlessBaseName,qfalse));//S_COLOR_RED "Failed to close savegame\n"); sv_testsave->value = fPrevTestSave; return qfalse; } @@ -1165,7 +1160,7 @@ static void CompressMem_FreeScratchBuffer(void) static byte *CompressMem_AllocScratchBuffer(int iSize) { - // only alloc new buffer is we need more than the existing one... + // only alloc new buffer if we need more than the existing one... // if (giCompBlockSize < iSize) { diff --git a/code/server/sv_snapshot.cpp b/code/server/sv_snapshot.cpp index 3af9a7d..e6e9a92 100644 --- a/code/server/sv_snapshot.cpp +++ b/code/server/sv_snapshot.cpp @@ -458,6 +458,8 @@ static clientSnapshot_t *SV_BuildClientSnapshot( client_t *client ) { } //============ } + VectorCopy( org, frame->ps.serverViewOrg ); + VectorCopy( org, clent->client->serverViewOrg ); // add all the entities directly visible to the eye, which // may include portal entities that merge other viewpoints diff --git a/code/server/sv_world.cpp b/code/server/sv_world.cpp index 0796c17..d9628a5 100644 --- a/code/server/sv_world.cpp +++ b/code/server/sv_world.cpp @@ -671,9 +671,19 @@ void SV_ClipMoveToEntities( moveclip_t *clip ) { else #endif { +#ifdef __MACOS__ + // compiler bug with const + CM_TransformedBoxTrace ( &trace, (float *)clip->start, (float *)clip->end, + (float *)clip->mins, (float *)clip->maxs, clipHandle, clip->contentmask, + origin, angles); +#else CM_TransformedBoxTrace ( &trace, clip->start, clip->end, clip->mins, clip->maxs, clipHandle, clip->contentmask, origin, angles); +#endif + //FIXME: when startsolid in another ent, doesn't return correct entityNum + //ALSO: 2 players can be standing next to each other and this function will + //think they're in each other!!! } oldTrace = clip->trace; diff --git a/code/server/vssver.scc b/code/server/vssver.scc new file mode 100644 index 0000000..a5ab97d Binary files /dev/null and b/code/server/vssver.scc differ diff --git a/code/smartheap/haw32m.lib b/code/smartheap/haw32m.lib new file mode 100644 index 0000000..1fc259c Binary files /dev/null and b/code/smartheap/haw32m.lib differ diff --git a/code/smartheap/vssver.scc b/code/smartheap/vssver.scc new file mode 100644 index 0000000..ca5fe45 Binary files /dev/null and b/code/smartheap/vssver.scc differ diff --git a/code/starwars.dsp b/code/starwars.dsp index 02471d4..02c3637 100644 --- a/code/starwars.dsp +++ b/code/starwars.dsp @@ -45,7 +45,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /D "_NPATCH" /D "NDEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -72,7 +72,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /G6 /MTd /W4 /Gm /Gi /GX /ZI /Od /D "_NPATCH" /D "_DEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fr /YX /FD /c +# ADD CPP /nologo /G6 /MTd /W4 /Gm /Gi /GX /ZI /Od /D "_DEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fr /YX /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -100,7 +100,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "__USEA3D" /D "__A3D_GEOM" /YX /FD /c -# ADD CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "FINAL_BUILD" /D "_NPATCH" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "FINAL_BUILD" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -129,7 +129,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /G6 /MTd /W4 /Gm /Gi /GX /ZI /Od /D "_NPATCH" /D "_DEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fr /YX /FD /c -# ADD CPP /nologo /G6 /MTd /W4 /Gm /Gi /GX /ZI /Od /D "_NPATCH" /D "_DEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /D "MEM_DEBUG" /Fr /YX /FD /c +# ADD CPP /nologo /G6 /MTd /W4 /Gm /Gi /GX /ZI /Od /D "_DEBUG" /D "MEM_DEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fr /YX /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /fo"win32\winquake.res" /d "_DEBUG" @@ -1480,6 +1480,11 @@ SOURCE=.\ui\ui_connect.cpp # End Source File # Begin Source File +SOURCE=.\ui\ui_debug.cpp +# ADD CPP /Yu"..\server\exe_headers.h" +# End Source File +# Begin Source File + SOURCE=.\ui\ui_main.cpp # ADD CPP /Yu"..\server\exe_headers.h" # End Source File diff --git a/code/starwars.plg b/code/starwars.plg new file mode 100644 index 0000000..38809a0 --- /dev/null +++ b/code/starwars.plg @@ -0,0 +1,726 @@ + + +
+

Build Log

+

+--------------------Configuration: starwars - Win32 Release-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A8B.tmp" with contents +[ +/nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fo".\Release\exe/" /Fd".\Release\exe/" /FD /c +"C:\projects\jk2\CODE\qcommon\files.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A8B.tmp" +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A8C.tmp" with contents +[ +ALut.lib OpenAL32.lib win32/FeelIt/ffc10.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib /nologo /stack:0x800000 /subsystem:windows /incremental:no /pdb:".\Release/jk2sp.pdb" /map:".\Release\exe/jk2sp.map" /debug /machine:I386 /out:".\Release/jk2sp.exe" +.\Release\exe\cl_cgame.obj +.\Release\exe\cl_cin.obj +.\Release\exe\cl_console.obj +.\Release\exe\cl_input.obj +.\Release\exe\cl_keys.obj +.\Release\exe\cl_main.obj +.\Release\exe\cl_mp3.obj +.\Release\exe\cl_parse.obj +.\Release\exe\cl_scrn.obj +.\Release\exe\cl_ui.obj +.\Release\exe\cm_load.obj +.\Release\exe\cm_patch.obj +.\Release\exe\cm_polylib.obj +.\Release\exe\cm_test.obj +.\Release\exe\cm_trace.obj +.\Release\exe\cmd.obj +.\Release\exe\common.obj +.\Release\exe\cvar.obj +.\Release\exe\exe_headers.obj +.\Release\exe\files.obj +.\Release\exe\genericparser2.obj +.\Release\exe\hstring.obj +.\Release\exe\md4.obj +.\Release\exe\msg.obj +.\Release\exe\net_chan.obj +.\Release\exe\q_math.obj +.\Release\exe\q_shared.obj +.\Release\exe\snd_ambient.obj +.\Release\exe\snd_dma.obj +.\Release\exe\snd_mem.obj +.\Release\exe\snd_mix.obj +.\Release\exe\snd_music.obj +.\Release\exe\strip.obj +.\Release\exe\sv_ccmds.obj +.\Release\exe\sv_client.obj +.\Release\exe\sv_game.obj +.\Release\exe\sv_init.obj +.\Release\exe\sv_main.obj +.\Release\exe\sv_savegame.obj +.\Release\exe\sv_snapshot.obj +.\Release\exe\sv_world.obj +.\Release\exe\unzip.obj +.\Release\exe\vmachine.obj +.\Release\exe\win_input.obj +.\Release\exe\win_main.obj +.\Release\exe\win_shared.obj +.\Release\exe\win_snd.obj +.\Release\exe\win_syscon.obj +.\Release\exe\win_video.obj +.\Release\exe\win_wndproc.obj +.\Release\exe\cdct.obj +.\Release\exe\csbt.obj +.\Release\exe\csbtb.obj +.\Release\exe\csbtL3.obj +.\Release\exe\cup.obj +.\Release\exe\cupini.obj +.\Release\exe\cupL1.obj +.\Release\exe\cupl3.obj +.\Release\exe\cwin.obj +.\Release\exe\cwinb.obj +.\Release\exe\cwinm.obj +.\Release\exe\hwin.obj +.\Release\exe\l3dq.obj +.\Release\exe\l3init.obj +.\Release\exe\mdct.obj +.\Release\exe\mhead.obj +.\Release\exe\msis.obj +.\Release\exe\towave.obj +.\Release\exe\uph.obj +.\Release\exe\upsf.obj +.\Release\exe\wavep.obj +.\Release\exe\fffx.obj +.\Release\exe\fffx_feel.obj +.\Release\exe\G2_API.obj +.\Release\exe\G2_bolts.obj +.\Release\exe\G2_bones.obj +.\Release\exe\G2_misc.obj +.\Release\exe\G2_surfaces.obj +.\Release\exe\MatComp.obj +.\Release\exe\tr_animation.obj +.\Release\exe\tr_backend.obj +.\Release\exe\tr_bsp.obj +.\Release\exe\tr_cmds.obj +.\Release\exe\tr_curve.obj +.\Release\exe\tr_draw.obj +.\Release\exe\tr_font.obj +.\Release\exe\tr_ghoul2.obj +.\Release\exe\tr_image.obj +.\Release\exe\tr_init.obj +.\Release\exe\tr_jpeg_interface.obj +.\Release\exe\tr_light.obj +.\Release\exe\tr_main.obj +.\Release\exe\tr_marks.obj +.\Release\exe\tr_mesh.obj +.\Release\exe\tr_model.obj +.\Release\exe\tr_noise.obj +.\Release\exe\tr_quicksprite.obj +.\Release\exe\tr_scene.obj +.\Release\exe\tr_shade.obj +.\Release\exe\tr_shade_calc.obj +.\Release\exe\tr_shader.obj +.\Release\exe\tr_shadows.obj +.\Release\exe\tr_sky.obj +.\Release\exe\tr_stl.obj +.\Release\exe\tr_surface.obj +.\Release\exe\tr_surfacesprites.obj +.\Release\exe\tr_world.obj +.\Release\exe\tr_WorldEffects.obj +.\Release\exe\win_gamma.obj +.\Release\exe\win_glimp.obj +.\Release\exe\win_qgl.obj +.\Release\exe\ui_atoms.obj +.\Release\exe\ui_connect.obj +.\Release\exe\ui_debug.obj +.\Release\exe\ui_main.obj +.\Release\exe\ui_shared.obj +.\Release\exe\ui_syscalls.obj +.\Release\exe\jcapimin.obj +.\Release\exe\jccoefct.obj +.\Release\exe\jccolor.obj +.\Release\exe\jcdctmgr.obj +.\Release\exe\jchuff.obj +.\Release\exe\jcinit.obj +.\Release\exe\jcmainct.obj +.\Release\exe\jcmarker.obj +.\Release\exe\jcmaster.obj +.\Release\exe\jcomapi.obj +.\Release\exe\jcparam.obj +.\Release\exe\jcphuff.obj +.\Release\exe\jcprepct.obj +.\Release\exe\jcsample.obj +.\Release\exe\jctrans.obj +.\Release\exe\jdapimin.obj +.\Release\exe\jdapistd.obj +.\Release\exe\jdatadst.obj +.\Release\exe\jdatasrc.obj +.\Release\exe\jdcoefct.obj +.\Release\exe\jdcolor.obj +.\Release\exe\jddctmgr.obj +.\Release\exe\jdhuff.obj +.\Release\exe\jdinput.obj +.\Release\exe\jdmainct.obj +.\Release\exe\jdmarker.obj +.\Release\exe\jdmaster.obj +.\Release\exe\jdpostct.obj +.\Release\exe\jdsample.obj +.\Release\exe\jdtrans.obj +.\Release\exe\jerror.obj +.\Release\exe\jfdctflt.obj +.\Release\exe\jidctflt.obj +.\Release\exe\jmemmgr.obj +.\Release\exe\jmemnobs.obj +.\Release\exe\jutils.obj +.\Release\exe\buffer.obj +.\Release\exe\cpp_interface.obj +.\Release\exe\sockets.obj +.\Release\exe\winquake.res +.\ALut.lib +.\OpenAL32.lib +.\win32\FeelIt\FFC10d.lib +.\win32\FeelIt\FFC10.lib +.\Release\jk2gamex86.lib +] +Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A8C.tmp" +

Output Window

+Compiling... +files.cpp +Linking... + + + +

Results

+jk2sp.exe - 0 error(s), 0 warning(s) +

+--------------------Configuration: starwars - Win32 Debug-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A8F.tmp" with contents +[ +/nologo /G6 /MTd /W4 /Gm /Gi /GX /ZI /Od /D "_DEBUG" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fr".\Debug\exe/" /Fo".\Debug\exe/" /Fd".\Debug\exe/" /FD /c +"C:\projects\jk2\CODE\qcommon\files.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A8F.tmp" +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A90.tmp" with contents +[ +ALut.lib OpenAL32.lib win32/FeelIt/ffc10d.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib /nologo /stack:0x800000 /subsystem:windows /incremental:yes /pdb:".\Debug/jk2sp.pdb" /map:".\Debug\exe/jk2sp.map" /debug /machine:I386 /out:".\Debug/jk2sp.exe" +.\Debug\exe\cl_cgame.obj +.\Debug\exe\cl_cin.obj +.\Debug\exe\cl_console.obj +.\Debug\exe\cl_input.obj +.\Debug\exe\cl_keys.obj +.\Debug\exe\cl_main.obj +.\Debug\exe\cl_mp3.obj +.\Debug\exe\cl_parse.obj +.\Debug\exe\cl_scrn.obj +.\Debug\exe\cl_ui.obj +.\Debug\exe\cm_load.obj +.\Debug\exe\cm_patch.obj +.\Debug\exe\cm_polylib.obj +.\Debug\exe\cm_test.obj +.\Debug\exe\cm_trace.obj +.\Debug\exe\cmd.obj +.\Debug\exe\common.obj +.\Debug\exe\cvar.obj +.\Debug\exe\exe_headers.obj +.\Debug\exe\files.obj +.\Debug\exe\genericparser2.obj +.\Debug\exe\hstring.obj +.\Debug\exe\md4.obj +.\Debug\exe\msg.obj +.\Debug\exe\net_chan.obj +.\Debug\exe\q_math.obj +.\Debug\exe\q_shared.obj +.\Debug\exe\snd_ambient.obj +.\Debug\exe\snd_dma.obj +.\Debug\exe\snd_mem.obj +.\Debug\exe\snd_mix.obj +.\Debug\exe\snd_music.obj +.\Debug\exe\strip.obj +.\Debug\exe\sv_ccmds.obj +.\Debug\exe\sv_client.obj +.\Debug\exe\sv_game.obj +.\Debug\exe\sv_init.obj +.\Debug\exe\sv_main.obj +.\Debug\exe\sv_savegame.obj +.\Debug\exe\sv_snapshot.obj +.\Debug\exe\sv_world.obj +.\Debug\exe\unzip.obj +.\Debug\exe\vmachine.obj +.\Debug\exe\win_input.obj +.\Debug\exe\win_main.obj +.\Debug\exe\win_shared.obj +.\Debug\exe\win_snd.obj +.\Debug\exe\win_syscon.obj +.\Debug\exe\win_video.obj +.\Debug\exe\win_wndproc.obj +.\Debug\exe\cdct.obj +.\Debug\exe\csbt.obj +.\Debug\exe\csbtb.obj +.\Debug\exe\csbtL3.obj +.\Debug\exe\cup.obj +.\Debug\exe\cupini.obj +.\Debug\exe\cupL1.obj +.\Debug\exe\cupl3.obj +.\Debug\exe\cwin.obj +.\Debug\exe\cwinb.obj +.\Debug\exe\cwinm.obj +.\Debug\exe\hwin.obj +.\Debug\exe\l3dq.obj +.\Debug\exe\l3init.obj +.\Debug\exe\mdct.obj +.\Debug\exe\mhead.obj +.\Debug\exe\msis.obj +.\Debug\exe\towave.obj +.\Debug\exe\uph.obj +.\Debug\exe\upsf.obj +.\Debug\exe\wavep.obj +.\Debug\exe\fffx.obj +.\Debug\exe\fffx_feel.obj +.\Debug\exe\G2_API.obj +.\Debug\exe\G2_bolts.obj +.\Debug\exe\G2_bones.obj +.\Debug\exe\G2_misc.obj +.\Debug\exe\G2_surfaces.obj +.\Debug\exe\MatComp.obj +.\Debug\exe\tr_animation.obj +.\Debug\exe\tr_backend.obj +.\Debug\exe\tr_bsp.obj +.\Debug\exe\tr_cmds.obj +.\Debug\exe\tr_curve.obj +.\Debug\exe\tr_draw.obj +.\Debug\exe\tr_font.obj +.\Debug\exe\tr_ghoul2.obj +.\Debug\exe\tr_image.obj +.\Debug\exe\tr_init.obj +.\Debug\exe\tr_jpeg_interface.obj +.\Debug\exe\tr_light.obj +.\Debug\exe\tr_main.obj +.\Debug\exe\tr_marks.obj +.\Debug\exe\tr_mesh.obj +.\Debug\exe\tr_model.obj +.\Debug\exe\tr_noise.obj +.\Debug\exe\tr_quicksprite.obj +.\Debug\exe\tr_scene.obj +.\Debug\exe\tr_shade.obj +.\Debug\exe\tr_shade_calc.obj +.\Debug\exe\tr_shader.obj +.\Debug\exe\tr_shadows.obj +.\Debug\exe\tr_sky.obj +.\Debug\exe\tr_stl.obj +.\Debug\exe\tr_surface.obj +.\Debug\exe\tr_surfacesprites.obj +.\Debug\exe\tr_world.obj +.\Debug\exe\tr_WorldEffects.obj +.\Debug\exe\win_gamma.obj +.\Debug\exe\win_glimp.obj +.\Debug\exe\win_qgl.obj +.\Debug\exe\ui_atoms.obj +.\Debug\exe\ui_connect.obj +.\Debug\exe\ui_debug.obj +.\Debug\exe\ui_main.obj +.\Debug\exe\ui_shared.obj +.\Debug\exe\ui_syscalls.obj +.\Debug\exe\jcapimin.obj +.\Debug\exe\jccoefct.obj +.\Debug\exe\jccolor.obj +.\Debug\exe\jcdctmgr.obj +.\Debug\exe\jchuff.obj +.\Debug\exe\jcinit.obj +.\Debug\exe\jcmainct.obj +.\Debug\exe\jcmarker.obj +.\Debug\exe\jcmaster.obj +.\Debug\exe\jcomapi.obj +.\Debug\exe\jcparam.obj +.\Debug\exe\jcphuff.obj +.\Debug\exe\jcprepct.obj +.\Debug\exe\jcsample.obj +.\Debug\exe\jctrans.obj +.\Debug\exe\jdapimin.obj +.\Debug\exe\jdapistd.obj +.\Debug\exe\jdatadst.obj +.\Debug\exe\jdatasrc.obj +.\Debug\exe\jdcoefct.obj +.\Debug\exe\jdcolor.obj +.\Debug\exe\jddctmgr.obj +.\Debug\exe\jdhuff.obj +.\Debug\exe\jdinput.obj +.\Debug\exe\jdmainct.obj +.\Debug\exe\jdmarker.obj +.\Debug\exe\jdmaster.obj +.\Debug\exe\jdpostct.obj +.\Debug\exe\jdsample.obj +.\Debug\exe\jdtrans.obj +.\Debug\exe\jerror.obj +.\Debug\exe\jfdctflt.obj +.\Debug\exe\jidctflt.obj +.\Debug\exe\jmemmgr.obj +.\Debug\exe\jmemnobs.obj +.\Debug\exe\jutils.obj +.\Debug\exe\buffer.obj +.\Debug\exe\cpp_interface.obj +.\Debug\exe\sockets.obj +.\win32\winquake.res +.\ALut.lib +.\OpenAL32.lib +.\win32\FeelIt\FFC10d.lib +.\win32\FeelIt\FFC10.lib +] +Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A90.tmp" +

Output Window

+Compiling... +files.cpp +Linking... +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A92.tmp" with contents +[ +/nologo /o"Debug/starwars.bsc" +.\Debug\exe\exe_headers.sbr +.\Debug\exe\cl_cgame.sbr +.\Debug\exe\cl_cin.sbr +.\Debug\exe\cl_console.sbr +.\Debug\exe\cl_input.sbr +.\Debug\exe\cl_keys.sbr +.\Debug\exe\cl_main.sbr +.\Debug\exe\cl_mp3.sbr +.\Debug\exe\cl_parse.sbr +.\Debug\exe\cl_scrn.sbr +.\Debug\exe\cl_ui.sbr +.\Debug\exe\cm_load.sbr +.\Debug\exe\cm_patch.sbr +.\Debug\exe\cm_polylib.sbr +.\Debug\exe\cm_test.sbr +.\Debug\exe\cm_trace.sbr +.\Debug\exe\cmd.sbr +.\Debug\exe\common.sbr +.\Debug\exe\cvar.sbr +.\Debug\exe\files.sbr +.\Debug\exe\genericparser2.sbr +.\Debug\exe\hstring.sbr +.\Debug\exe\md4.sbr +.\Debug\exe\msg.sbr +.\Debug\exe\net_chan.sbr +.\Debug\exe\q_math.sbr +.\Debug\exe\q_shared.sbr +.\Debug\exe\snd_ambient.sbr +.\Debug\exe\snd_dma.sbr +.\Debug\exe\snd_mem.sbr +.\Debug\exe\snd_mix.sbr +.\Debug\exe\snd_music.sbr +.\Debug\exe\strip.sbr +.\Debug\exe\sv_ccmds.sbr +.\Debug\exe\sv_client.sbr +.\Debug\exe\sv_game.sbr +.\Debug\exe\sv_init.sbr +.\Debug\exe\sv_main.sbr +.\Debug\exe\sv_savegame.sbr +.\Debug\exe\sv_snapshot.sbr +.\Debug\exe\sv_world.sbr +.\Debug\exe\unzip.sbr +.\Debug\exe\vmachine.sbr +.\Debug\exe\win_input.sbr +.\Debug\exe\win_main.sbr +.\Debug\exe\win_shared.sbr +.\Debug\exe\win_snd.sbr +.\Debug\exe\win_syscon.sbr +.\Debug\exe\win_video.sbr +.\Debug\exe\win_wndproc.sbr +.\Debug\exe\cdct.sbr +.\Debug\exe\csbt.sbr +.\Debug\exe\csbtb.sbr +.\Debug\exe\csbtL3.sbr +.\Debug\exe\cup.sbr +.\Debug\exe\cupini.sbr +.\Debug\exe\cupL1.sbr +.\Debug\exe\cupl3.sbr +.\Debug\exe\cwin.sbr +.\Debug\exe\cwinb.sbr +.\Debug\exe\cwinm.sbr +.\Debug\exe\hwin.sbr +.\Debug\exe\l3dq.sbr +.\Debug\exe\l3init.sbr +.\Debug\exe\mdct.sbr +.\Debug\exe\mhead.sbr +.\Debug\exe\msis.sbr +.\Debug\exe\towave.sbr +.\Debug\exe\uph.sbr +.\Debug\exe\upsf.sbr +.\Debug\exe\wavep.sbr +.\Debug\exe\fffx.sbr +.\Debug\exe\fffx_feel.sbr +.\Debug\exe\G2_API.sbr +.\Debug\exe\G2_bolts.sbr +.\Debug\exe\G2_bones.sbr +.\Debug\exe\G2_misc.sbr +.\Debug\exe\G2_surfaces.sbr +.\Debug\exe\MatComp.sbr +.\Debug\exe\tr_animation.sbr +.\Debug\exe\tr_backend.sbr +.\Debug\exe\tr_bsp.sbr +.\Debug\exe\tr_cmds.sbr +.\Debug\exe\tr_curve.sbr +.\Debug\exe\tr_draw.sbr +.\Debug\exe\tr_font.sbr +.\Debug\exe\tr_ghoul2.sbr +.\Debug\exe\tr_image.sbr +.\Debug\exe\tr_init.sbr +.\Debug\exe\tr_jpeg_interface.sbr +.\Debug\exe\tr_light.sbr +.\Debug\exe\tr_main.sbr +.\Debug\exe\tr_marks.sbr +.\Debug\exe\tr_mesh.sbr +.\Debug\exe\tr_model.sbr +.\Debug\exe\tr_noise.sbr +.\Debug\exe\tr_quicksprite.sbr +.\Debug\exe\tr_scene.sbr +.\Debug\exe\tr_shade.sbr +.\Debug\exe\tr_shade_calc.sbr +.\Debug\exe\tr_shader.sbr +.\Debug\exe\tr_shadows.sbr +.\Debug\exe\tr_sky.sbr +.\Debug\exe\tr_stl.sbr +.\Debug\exe\tr_surface.sbr +.\Debug\exe\tr_surfacesprites.sbr +.\Debug\exe\tr_world.sbr +.\Debug\exe\tr_WorldEffects.sbr +.\Debug\exe\win_gamma.sbr +.\Debug\exe\win_glimp.sbr +.\Debug\exe\win_qgl.sbr +.\Debug\exe\ui_atoms.sbr +.\Debug\exe\ui_connect.sbr +.\Debug\exe\ui_debug.sbr +.\Debug\exe\ui_main.sbr +.\Debug\exe\ui_shared.sbr +.\Debug\exe\ui_syscalls.sbr +.\Debug\exe\jcapimin.sbr +.\Debug\exe\jccoefct.sbr +.\Debug\exe\jccolor.sbr +.\Debug\exe\jcdctmgr.sbr +.\Debug\exe\jchuff.sbr +.\Debug\exe\jcinit.sbr +.\Debug\exe\jcmainct.sbr +.\Debug\exe\jcmarker.sbr +.\Debug\exe\jcmaster.sbr +.\Debug\exe\jcomapi.sbr +.\Debug\exe\jcparam.sbr +.\Debug\exe\jcphuff.sbr +.\Debug\exe\jcprepct.sbr +.\Debug\exe\jcsample.sbr +.\Debug\exe\jctrans.sbr +.\Debug\exe\jdapimin.sbr +.\Debug\exe\jdapistd.sbr +.\Debug\exe\jdatadst.sbr +.\Debug\exe\jdatasrc.sbr +.\Debug\exe\jdcoefct.sbr +.\Debug\exe\jdcolor.sbr +.\Debug\exe\jddctmgr.sbr +.\Debug\exe\jdhuff.sbr +.\Debug\exe\jdinput.sbr +.\Debug\exe\jdmainct.sbr +.\Debug\exe\jdmarker.sbr +.\Debug\exe\jdmaster.sbr +.\Debug\exe\jdpostct.sbr +.\Debug\exe\jdsample.sbr +.\Debug\exe\jdtrans.sbr +.\Debug\exe\jerror.sbr +.\Debug\exe\jfdctflt.sbr +.\Debug\exe\jidctflt.sbr +.\Debug\exe\jmemmgr.sbr +.\Debug\exe\jmemnobs.sbr +.\Debug\exe\jutils.sbr +.\Debug\exe\buffer.sbr +.\Debug\exe\cpp_interface.sbr +.\Debug\exe\sockets.sbr] +Creating command line "bscmake.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A92.tmp" +Creating browse info file... +

Output Window

+ + + +

Results

+jk2sp.exe - 0 error(s), 0 warning(s) +

+--------------------Configuration: starwars - Win32 FinalBuild-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A93.tmp" with contents +[ +/nologo /G6 /MT /W4 /GX /Zi /O2 /D "NDEBUG" /D "FINAL_BUILD" /D "_JK2EXE" /D "WIN32" /D "_WINDOWS" /Fo".\FinalBuild\exe/" /Fd".\FinalBuild\exe/" /FD /c +"C:\projects\jk2\CODE\qcommon\files.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A93.tmp" +Creating temporary file "C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A94.tmp" with contents +[ +ALut.lib OpenAL32.lib win32/FeelIt/ffc10.lib advapi32.lib winmm.lib kernel32.lib user32.lib gdi32.lib ole32.lib wsock32.lib /nologo /stack:0x800000 /subsystem:windows /incremental:no /pdb:".\FinalBuild/jk2sp.pdb" /map:".\FinalBuild\exe/jk2sp.map" /debug /machine:I386 /out:".\FinalBuild/jk2sp.exe" +.\FinalBuild\exe\cl_cgame.obj +.\FinalBuild\exe\cl_cin.obj +.\FinalBuild\exe\cl_console.obj +.\FinalBuild\exe\cl_input.obj +.\FinalBuild\exe\cl_keys.obj +.\FinalBuild\exe\cl_main.obj +.\FinalBuild\exe\cl_mp3.obj +.\FinalBuild\exe\cl_parse.obj +.\FinalBuild\exe\cl_scrn.obj +.\FinalBuild\exe\cl_ui.obj +.\FinalBuild\exe\cm_load.obj +.\FinalBuild\exe\cm_patch.obj +.\FinalBuild\exe\cm_polylib.obj +.\FinalBuild\exe\cm_test.obj +.\FinalBuild\exe\cm_trace.obj +.\FinalBuild\exe\cmd.obj +.\FinalBuild\exe\common.obj +.\FinalBuild\exe\cvar.obj +.\FinalBuild\exe\exe_headers.obj +.\FinalBuild\exe\files.obj +.\FinalBuild\exe\genericparser2.obj +.\FinalBuild\exe\hstring.obj +.\FinalBuild\exe\md4.obj +.\FinalBuild\exe\msg.obj +.\FinalBuild\exe\net_chan.obj +.\FinalBuild\exe\q_math.obj +.\FinalBuild\exe\q_shared.obj +.\FinalBuild\exe\snd_ambient.obj +.\FinalBuild\exe\snd_dma.obj +.\FinalBuild\exe\snd_mem.obj +.\FinalBuild\exe\snd_mix.obj +.\FinalBuild\exe\snd_music.obj +.\FinalBuild\exe\strip.obj +.\FinalBuild\exe\sv_ccmds.obj +.\FinalBuild\exe\sv_client.obj +.\FinalBuild\exe\sv_game.obj +.\FinalBuild\exe\sv_init.obj +.\FinalBuild\exe\sv_main.obj +.\FinalBuild\exe\sv_savegame.obj +.\FinalBuild\exe\sv_snapshot.obj +.\FinalBuild\exe\sv_world.obj +.\FinalBuild\exe\unzip.obj +.\FinalBuild\exe\vmachine.obj +.\FinalBuild\exe\win_input.obj +.\FinalBuild\exe\win_main.obj +.\FinalBuild\exe\win_shared.obj +.\FinalBuild\exe\win_snd.obj +.\FinalBuild\exe\win_syscon.obj +.\FinalBuild\exe\win_video.obj +.\FinalBuild\exe\win_wndproc.obj +.\FinalBuild\exe\cdct.obj +.\FinalBuild\exe\csbt.obj +.\FinalBuild\exe\csbtb.obj +.\FinalBuild\exe\csbtL3.obj +.\FinalBuild\exe\cup.obj +.\FinalBuild\exe\cupini.obj +.\FinalBuild\exe\cupL1.obj +.\FinalBuild\exe\cupl3.obj +.\FinalBuild\exe\cwin.obj +.\FinalBuild\exe\cwinb.obj +.\FinalBuild\exe\cwinm.obj +.\FinalBuild\exe\hwin.obj +.\FinalBuild\exe\l3dq.obj +.\FinalBuild\exe\l3init.obj +.\FinalBuild\exe\mdct.obj +.\FinalBuild\exe\mhead.obj +.\FinalBuild\exe\msis.obj +.\FinalBuild\exe\towave.obj +.\FinalBuild\exe\uph.obj +.\FinalBuild\exe\upsf.obj +.\FinalBuild\exe\wavep.obj +.\FinalBuild\exe\fffx.obj +.\FinalBuild\exe\fffx_feel.obj +.\FinalBuild\exe\G2_API.obj +.\FinalBuild\exe\G2_bolts.obj +.\FinalBuild\exe\G2_bones.obj +.\FinalBuild\exe\G2_misc.obj +.\FinalBuild\exe\G2_surfaces.obj +.\FinalBuild\exe\MatComp.obj +.\FinalBuild\exe\tr_animation.obj +.\FinalBuild\exe\tr_backend.obj +.\FinalBuild\exe\tr_bsp.obj +.\FinalBuild\exe\tr_cmds.obj +.\FinalBuild\exe\tr_curve.obj +.\FinalBuild\exe\tr_draw.obj +.\FinalBuild\exe\tr_font.obj +.\FinalBuild\exe\tr_ghoul2.obj +.\FinalBuild\exe\tr_image.obj +.\FinalBuild\exe\tr_init.obj +.\FinalBuild\exe\tr_jpeg_interface.obj +.\FinalBuild\exe\tr_light.obj +.\FinalBuild\exe\tr_main.obj +.\FinalBuild\exe\tr_marks.obj +.\FinalBuild\exe\tr_mesh.obj +.\FinalBuild\exe\tr_model.obj +.\FinalBuild\exe\tr_noise.obj +.\FinalBuild\exe\tr_quicksprite.obj +.\FinalBuild\exe\tr_scene.obj +.\FinalBuild\exe\tr_shade.obj +.\FinalBuild\exe\tr_shade_calc.obj +.\FinalBuild\exe\tr_shader.obj +.\FinalBuild\exe\tr_shadows.obj +.\FinalBuild\exe\tr_sky.obj +.\FinalBuild\exe\tr_stl.obj +.\FinalBuild\exe\tr_surface.obj +.\FinalBuild\exe\tr_surfacesprites.obj +.\FinalBuild\exe\tr_world.obj +.\FinalBuild\exe\tr_WorldEffects.obj +.\FinalBuild\exe\win_gamma.obj +.\FinalBuild\exe\win_glimp.obj +.\FinalBuild\exe\win_qgl.obj +.\FinalBuild\exe\ui_atoms.obj +.\FinalBuild\exe\ui_connect.obj +.\FinalBuild\exe\ui_debug.obj +.\FinalBuild\exe\ui_main.obj +.\FinalBuild\exe\ui_shared.obj +.\FinalBuild\exe\ui_syscalls.obj +.\FinalBuild\exe\jcapimin.obj +.\FinalBuild\exe\jccoefct.obj +.\FinalBuild\exe\jccolor.obj +.\FinalBuild\exe\jcdctmgr.obj +.\FinalBuild\exe\jchuff.obj +.\FinalBuild\exe\jcinit.obj +.\FinalBuild\exe\jcmainct.obj +.\FinalBuild\exe\jcmarker.obj +.\FinalBuild\exe\jcmaster.obj +.\FinalBuild\exe\jcomapi.obj +.\FinalBuild\exe\jcparam.obj +.\FinalBuild\exe\jcphuff.obj +.\FinalBuild\exe\jcprepct.obj +.\FinalBuild\exe\jcsample.obj +.\FinalBuild\exe\jctrans.obj +.\FinalBuild\exe\jdapimin.obj +.\FinalBuild\exe\jdapistd.obj +.\FinalBuild\exe\jdatadst.obj +.\FinalBuild\exe\jdatasrc.obj +.\FinalBuild\exe\jdcoefct.obj +.\FinalBuild\exe\jdcolor.obj +.\FinalBuild\exe\jddctmgr.obj +.\FinalBuild\exe\jdhuff.obj +.\FinalBuild\exe\jdinput.obj +.\FinalBuild\exe\jdmainct.obj +.\FinalBuild\exe\jdmarker.obj +.\FinalBuild\exe\jdmaster.obj +.\FinalBuild\exe\jdpostct.obj +.\FinalBuild\exe\jdsample.obj +.\FinalBuild\exe\jdtrans.obj +.\FinalBuild\exe\jerror.obj +.\FinalBuild\exe\jfdctflt.obj +.\FinalBuild\exe\jidctflt.obj +.\FinalBuild\exe\jmemmgr.obj +.\FinalBuild\exe\jmemnobs.obj +.\FinalBuild\exe\jutils.obj +.\FinalBuild\exe\buffer.obj +.\FinalBuild\exe\cpp_interface.obj +.\FinalBuild\exe\sockets.obj +.\FinalBuild\exe\winquake.res +.\ALut.lib +.\OpenAL32.lib +.\win32\FeelIt\FFC10d.lib +.\win32\FeelIt\FFC10.lib +.\FinalBuild\jk2gamex86.lib +] +Creating command line "link.exe @C:\DOCUME~1\jmonroe\LOCALS~1\Temp\RSP1A94.tmp" +

Output Window

+Compiling... +files.cpp +Linking... + + + +

Results

+jk2sp.exe - 0 error(s), 0 warning(s) +
+ + diff --git a/code/tonet.bat b/code/tonet.bat new file mode 100644 index 0000000..d004639 --- /dev/null +++ b/code/tonet.bat @@ -0,0 +1,2 @@ +xcopy/d/y release\jk2sp.exe w:\game +xcopy/d/y release\jk2gamex86.dll w:\game diff --git a/code/tosend.bat b/code/tosend.bat new file mode 100644 index 0000000..31ea74d --- /dev/null +++ b/code/tosend.bat @@ -0,0 +1,4 @@ +xcopy/y finalbuild\jk2sp.exe c:\send\game +xcopy/y finalbuild\jk2gamex86.dll c:\send\game +del/s/q c:\send\game\base\saves +rd c:\send\game\base\saves diff --git a/code/ui/mssccprj.scc b/code/ui/mssccprj.scc new file mode 100644 index 0000000..b702cff --- /dev/null +++ b/code/ui/mssccprj.scc @@ -0,0 +1,5 @@ +SCC = This is a Source Code Control file + +[ui.dsp] +SCC_Aux_Path = "\\ravend\vss_projects\StarWars" +SCC_Project_Name = "$/code/ui", XVOAAAAA diff --git a/code/ui/ui.def b/code/ui/ui.def new file mode 100644 index 0000000..b82b7f8 --- /dev/null +++ b/code/ui/ui.def @@ -0,0 +1,4 @@ +EXPORTS + GetUIAPI + vmMain + dllEntry \ No newline at end of file diff --git a/code/ui/ui.dsp b/code/ui/ui.dsp new file mode 100644 index 0000000..8aedec7 --- /dev/null +++ b/code/ui/ui.dsp @@ -0,0 +1,245 @@ +# Microsoft Developer Studio Project File - Name="ui" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=ui - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ui.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ui.mak" CFG="ui - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ui - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "ui - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "ui - Win32 FinalBuild" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/Code/ui", QEMAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ui - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\Release" +# PROP Intermediate_Dir "..\Release\ui" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "UI_EXPORTS" /YX /FD /c +# ADD CPP /nologo /G6 /W4 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "UI_EXPORTS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 /nologo /base:"0x40000000" /dll /map /debug /machine:I386 /out:"../Release/efuix86.dll" + +!ELSEIF "$(CFG)" == "ui - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "ui___Win32_Debug" +# PROP BASE Intermediate_Dir "ui___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "..\Debug" +# PROP Intermediate_Dir "..\Debug\ui" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "UI_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /G6 /W4 /Gm /Gi /GX /ZI /Od /I "..\ICARUS" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "UI_EXPORTS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /base:"0x40000000" /dll /debug /machine:I386 /out:"../Debug/efuix86.dll" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none /map + +!ELSEIF "$(CFG)" == "ui - Win32 FinalBuild" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ui___Win32_FinalBuild" +# PROP BASE Intermediate_Dir "ui___Win32_FinalBuild" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\FinalBuild" +# PROP Intermediate_Dir "..\FinalBuild\ui" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G6 /W3 /GX /Zi /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "UI_EXPORTS" /YX /FD /c +# ADD CPP /nologo /G6 /W3 /GX /Zi /O2 /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "UI_EXPORTS" /D "WIN32" /D "NDEBUG" /D "FINAL_BUILD" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /base:"0x40000000" /dll /map /debug /machine:I386 /out:"../Release/efuix86.dll" +# ADD LINK32 /nologo /base:"0x40000000" /dll /map /debug /machine:I386 /out:"../FinalBuild/efuix86.dll" + +!ENDIF + +# Begin Target + +# Name "ui - Win32 Release" +# Name "ui - Win32 Debug" +# Name "ui - Win32 FinalBuild" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\game\q_math.cpp +# ADD CPP /Yu"common_headers.h" +# End Source File +# Begin Source File + +SOURCE=..\game\q_shared.cpp +# ADD CPP /Yu"common_headers.h" +# End Source File +# Begin Source File + +SOURCE=.\ui_atoms.cpp +# ADD CPP /Yu"ui_local.h" +# End Source File +# Begin Source File + +SOURCE=.\ui_connect.cpp +# ADD CPP /Yu"ui_local.h" +# End Source File +# Begin Source File + +SOURCE=.\ui_headers.cpp +# ADD CPP /Yc"ui_local.h" +# End Source File +# Begin Source File + +SOURCE=.\ui_main.cpp +# ADD CPP /Yu"ui_local.h" +# End Source File +# Begin Source File + +SOURCE=.\ui_shared.cpp +# ADD CPP /Yu"ui_local.h" +# End Source File +# Begin Source File + +SOURCE=.\ui_syscalls.cpp +# ADD CPP /Yu"ui_local.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\game\channels.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\cm_public.h +# End Source File +# Begin Source File + +SOURCE=..\game\g_infostrings.h +# End Source File +# Begin Source File + +SOURCE=.\gameinfo.h +# End Source File +# Begin Source File + +SOURCE=..\game\ghoul2_shared.h +# End Source File +# Begin Source File + +SOURCE=..\client\keycodes.h +# End Source File +# Begin Source File + +SOURCE=.\menudef.h +# End Source File +# Begin Source File + +SOURCE=..\game\q_shared.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qcommon.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\qfiles.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\stv_version.h +# End Source File +# Begin Source File + +SOURCE=..\game\surfaceflags.h +# End Source File +# Begin Source File + +SOURCE=..\qcommon\tags.h +# End Source File +# Begin Source File + +SOURCE=.\ui_headers.h +# End Source File +# Begin Source File + +SOURCE=.\ui_local.h +# End Source File +# Begin Source File + +SOURCE=.\ui_public.h +# End Source File +# Begin Source File + +SOURCE=.\ui_shared.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=.\ui.def +# End Source File +# End Target +# End Project diff --git a/code/ui/ui_atoms.cpp b/code/ui/ui_atoms.cpp index 9ab2ef8..c09eacb 100644 --- a/code/ui/ui_atoms.cpp +++ b/code/ui/ui_atoms.cpp @@ -47,7 +47,7 @@ void UI_SetActiveMenu( const char* menuname,const char *menuID ) { // this should be the ONLY way the menu system is brought up (besides the UI_ConsoleCommand below) - if (!ui.SG_GameAllowedToSaveHere(qtrue)) //don't check full sytem, only if incamera + if (cls.state != CA_DISCONNECTED && !ui.SG_GameAllowedToSaveHere(qtrue)) //don't check full sytem, only if incamera { return; } @@ -213,7 +213,6 @@ void UI_Init( int apiVersion, uiimport_t *uiimport ) ui.Cvar_Create( "cg_drawCrosshair", "1", CVAR_ARCHIVE ); ui.Cvar_Create( "cg_marks", "1", CVAR_ARCHIVE ); - ui.Cvar_Create ("ui_initialsetup", "0", CVAR_ARCHIVE ); ui.Cvar_Create ("s_language", "english", CVAR_ARCHIVE | CVAR_NORESTART); ui.Cvar_Create ("k_language", "", CVAR_ARCHIVE | CVAR_NORESTART); diff --git a/code/ui/ui_debug.cpp b/code/ui/ui_debug.cpp new file mode 100644 index 0000000..5593389 --- /dev/null +++ b/code/ui/ui_debug.cpp @@ -0,0 +1,747 @@ +// Filename:- ui_debug.cpp +// +// an entire temp module just for doing some evil menu hackery during development... +// + + +#include "../server/exe_headers.h" + + +#if 0 // this entire module was special code to StripEd-ify *menu, it isn't needed now, but I'll keep the source around for a while -ste + + +#ifdef _DEBUG +#include +#include "../qcommon/sstring.h" +typedef sstring<4096> sstringBIG_t; +typedef set StringSet_t; + StringSet_t MenusUsed; +typedef map ReferencesAndPackages_t; + ReferencesAndPackages_t ReferencesAndPackage; + + +struct Reference_t +{ + sstringBIG_t sString; + sstring_t sReference; + sstring_t sMenu; + + Reference_t() + { + sString = ""; + sReference = ""; + sMenu = ""; + } + + // sort by menu entry, then by reference within menu... + // + bool operator < (const Reference_t& _X) const + { + int i = stricmp(sMenu.c_str(),_X.sMenu.c_str()); + if (i) + return i<0; + + return !!(stricmp(sReference.c_str(),_X.sReference.c_str()) < 0); + } +}; +#include +typedef list References_t; + References_t BadReferences; + +sstring_t sCurrentMenu; +void UI_Debug_AddMenuFilePath(LPCSTR psMenuFile) // eg "ui/blah.menu" +{ + sCurrentMenu = psMenuFile; + + OutputDebugString(va("Current menu: \"%s\"\n",psMenuFile)); +} + + +typedef struct +{ + // to correct... + // + sstring_t sMenuFile; + sstringBIG_t sTextToFind; // will be either @REFERENCE or "text" + sstringBIG_t sTextToReplaceWith; // will be @NEWREF + // + // to generate new data... + // + sstring_t sStripEdReference; // when NZ, this will create a new StripEd entry... + sstringBIG_t sStripEdText; + sstring_t sStripEdFileRef; // ... in this file reference (eg "SPMENUS%d"), where 0.255 of each all have this in them (for ease of coding) + +} CorrectionDataItem_t; +typedef list CorrectionData_t; + CorrectionData_t CorrectionData; + + +static LPCSTR CreateUniqueReference(LPCSTR psText) +{ + static set ReferencesSoFar; + + static sstringBIG_t NewReference; + + LPCSTR psTextScanPos = psText; + + while(*psTextScanPos) + { + while (isspace(*psTextScanPos)) psTextScanPos++; + + NewReference = psTextScanPos; + + // cap off text at an approx length... + // + const int iApproxReferenceLength = 20; + char *p; + if (iApproxReferenceLength TextConsolidationTable_t; // string and ref + static TextConsolidationTable_t TextConsolidationTable, RefrConsolidationTable; + static int iIndex = 0; // INC'd every time a new StripEd entry is synthesised + + TextConsolidationTable_t::iterator it = TextConsolidationTable.find(psText); + if (it == TextConsolidationTable.end()) + { + // new entry... + // + LPCSTR psNewReference = CreateUniqueReference( (strlen(psReference) > strlen(psText))?psReference:psText ); + + CorrectionDataItem_t CorrectionDataItem; + CorrectionDataItem.sMenuFile = psMenuFile; + CorrectionDataItem.sTextToFind = strlen(psReference) ? ( /* !stricmp(psReference,psNewReference) ? "" :*/ va("@%s",psReference) ) + : va("\"%s\"",psText); + CorrectionDataItem.sTextToReplaceWith = /* !stricmp(psReference,psNewReference) ? "" : */va("@%s",psNewReference); + // + CorrectionDataItem.sStripEdReference = psNewReference; + CorrectionDataItem.sStripEdText = psText; + +// qboolean bIsMulti = !!strstr(psMenuFile,"jk2mp"); +// CorrectionDataItem.sStripEdFileRef = va("%sMENUS%d",bIsMulti?"MP":"SP",iIndex/256); + CorrectionDataItem.sStripEdFileRef = va( "MENUS%d",iIndex/256); + iIndex++; + + CorrectionData.push_back( CorrectionDataItem ); + + TextConsolidationTable[ psText ] = psNewReference; + RefrConsolidationTable[ psText ] = CorrectionDataItem.sStripEdFileRef.c_str(); + } + else + { + // text already entered, so do a little duplicate-resolving... + // + // need to find the reference for the existing version... + // + LPCSTR psNewReference = (*it).second.c_str(); + LPCSTR psPackageRef = (*RefrConsolidationTable.find(psText)).second.c_str(); // yeuch, hack-city + + // only enter correction data if references are different... + // +// if (stricmp(psReference,psNewReference)) + { + CorrectionDataItem_t CorrectionDataItem; + CorrectionDataItem.sMenuFile = psMenuFile; + CorrectionDataItem.sTextToFind = strlen(psReference) ? va("@%s",psReference) : va("\"%s\"",psText); + CorrectionDataItem.sTextToReplaceWith = va("@%s",psNewReference); + // + CorrectionDataItem.sStripEdReference = ""; + CorrectionDataItem.sStripEdText = ""; + CorrectionDataItem.sStripEdFileRef = psPackageRef; + + + CorrectionData.push_back( CorrectionDataItem ); + } + } +} + +static void EnterGoodRef(LPCSTR ps4LetterType, LPCSTR psReference, LPCSTR psPackageReference, LPCSTR psText) +{ + EnterRef(psReference, psText, sCurrentMenu.c_str()); + + ReferencesAndPackage[psReference].insert(psPackageReference); + MenusUsed.insert(psPackageReference); +} + +static bool SendFileToNotepad(LPCSTR psFilename) +{ + bool bReturn = false; + + char sExecString[MAX_PATH]; + + sprintf(sExecString,"notepad %s",psFilename); + + if (WinExec(sExecString, // LPCSTR lpCmdLine, // address of command line + SW_SHOWNORMAL // UINT uCmdShow // window style for new application + ) + >31 // don't ask me, Windoze just uses >31 as OK in this call. + ) + { + // ok... + // + bReturn = true; + } + else + { + assert(0);//ErrorBox("Unable to locate/run NOTEPAD on this machine!\n\n(let me know about this -Ste)"); + } + + return bReturn; +} + +// creates as temp file, then spawns notepad with it... +// +static bool SendStringToNotepad(LPCSTR psWhatever, LPCSTR psLocalFileName) +{ + bool bReturn = false; + + LPCSTR psOutputFileName = va("c:\\%s",psLocalFileName); + + FILE *handle = fopen(psOutputFileName,"wt"); + if (handle) + { + fprintf(handle,"%s",psWhatever); // NOT fprintf(handle,psWhatever), which will try and process built-in %s stuff + fclose(handle); + + bReturn = SendFileToNotepad(psOutputFileName); + } + else + { + assert(0);//ErrorBox(va("Unable to create file \"%s\" for notepad to use!",psOutputFileName)); + } + + return bReturn; +} + + +static qboolean DoFileFindReplace( LPCSTR psMenuFile, LPCSTR psFind, LPCSTR psReplace ) +{ + char *buffer; + + OutputDebugString(va("Loading: \"%s\"\n",psMenuFile)); + + int iLen = FS_ReadFile( psMenuFile,(void **) &buffer); + if (iLen<1) + { + OutputDebugString("Failed!\n"); + assert(0); + return qfalse; + } + + + // find/rep... + // + string str(buffer); + str += "\r\n"; // safety for *(char+1) stuff + + + FS_FreeFile( buffer ); // let go of the buffer + + // originally this kept looping for replacements, but now it only does one (since the find/replace args are repeated + // and this is called again if there are >1 replacements of the same strings to be made... + // +// int iReplacedCount = 0; + char *pFound; + int iSearchPos = 0; + while ( (pFound = strstr(str.c_str()+iSearchPos,psFind)) != NULL) + { + // special check, the next char must be whitespace or carriage return etc, or we're not on a whole-word position... + // + int iFoundLoc = pFound - str.c_str(); + char cAfterFind = pFound[strlen(psFind)]; + if (cAfterFind > 32) + { + // ... then this string was part of a larger one, so ignore it... + // + iSearchPos = iFoundLoc+1; + continue; + } + + str.replace(iFoundLoc, strlen(psFind), psReplace); +// iSearchPos = iFoundLoc+1; +// iReplacedCount++; + break; + } + +// assert(iReplacedCount); +// if (iReplacedCount>1) +// { +// int z=1; +// } + FS_WriteFile( psMenuFile, str.c_str(), strlen(str.c_str())); + + OutputDebugString("Ok\n"); + + return qtrue; +} + +void UI_Dump_f(void) +{ + string sFinalOutput; + vector vStripEdFiles; + +#define OUTPUT sFinalOutput+= +#define OUTPUTSTRIP vStripEdFiles[vStripEdFiles.size()-1] += + + OUTPUT("### UI_Dump(): Top\n"); + + for (ReferencesAndPackages_t::iterator it = ReferencesAndPackage.begin(); it!=ReferencesAndPackage.end(); ++it) + { + if ( (*it).second.size()>1) + { + OUTPUT(va("!!!DUP: Ref \"%s\" exists in:\n",(*it).first.c_str())); + StringSet_t &Set = (*it).second; + for (StringSet_t::iterator itS = Set.begin(); itS!=Set.end(); ++itS) + { + OUTPUT(va("%s\n",(*itS).c_str())); + } + } + } + + OUTPUT("\nSP Package Reference list:\n"); + + for (StringSet_t::iterator itS = MenusUsed.begin(); itS!=MenusUsed.end(); ++itS) + { + OUTPUT(va("%s\n",(*itS).c_str())); + } + + OUTPUT("\nBad Text list:\n"); + + for (References_t::iterator itBad=BadReferences.begin(); itBad!=BadReferences.end();++itBad) + { + Reference_t &BadReference = (*itBad); + + OUTPUT(va("File: %30s \"%s\"\n",BadReference.sMenu.c_str(), BadReference.sString.c_str())); + } + + OUTPUT("\nAdding bad references to final correction list...\n"); + + for (itBad=BadReferences.begin(); itBad!=BadReferences.end();++itBad) + { + Reference_t &BadReference = (*itBad); + + EnterRef("", BadReference.sString.c_str(), BadReference.sMenu.c_str() ); + } + + + OUTPUT("\nFinal correction list:\n"); + +// qboolean bIsMulti = !!strstr((*CorrectionData.begin()).sMenuFile.c_str(),"jk2mp"); + + // actually do the find/replace... + // + for (CorrectionData_t::iterator itCorrectionData = CorrectionData.begin(); itCorrectionData != CorrectionData.end(); ++itCorrectionData) + { + CorrectionDataItem_t &CorrectionDataItem = (*itCorrectionData); + + if (CorrectionDataItem.sTextToFind.c_str()[0] && CorrectionDataItem.sTextToReplaceWith.c_str()[0]) + { + OUTPUT( va("Load File: \"%s\", find \"%s\", replace with \"%s\"\n", + CorrectionDataItem.sMenuFile.c_str(), + CorrectionDataItem.sTextToFind.c_str(), + CorrectionDataItem.sTextToReplaceWith.c_str() + ) + ); + + +// if (strstr(CorrectionDataItem.sTextToReplaceWith.c_str(),"START_A_NEW_GAME")) +// { +// int z=1; +// } + assert( CorrectionDataItem.sTextToReplaceWith.c_str()[0] ); + string sReplace( CorrectionDataItem.sTextToReplaceWith.c_str() ); + sReplace.insert(1,"_"); + sReplace.insert(1,CorrectionDataItem.sStripEdFileRef.c_str()); + + DoFileFindReplace( CorrectionDataItem.sMenuFile.c_str(), + CorrectionDataItem.sTextToFind.c_str(), + sReplace.c_str()//CorrectionDataItem.sTextToReplaceWith.c_str() + ); + } + } + + + // scan in all SP files into one huge string, so I can pick out any foreign translations to add in when generating + // new StripEd files... + // + char **ppsFiles; + char *buffers[1000]; // max # SP files, well-OTT. + int iNumFiles; + int i; + string sStripFiles; + + // scan for shader files + ppsFiles = FS_ListFiles( "strip", ".sp", &iNumFiles ); + if ( !ppsFiles || !iNumFiles ) + { + assert(0); + } + else + { + // load files... + // + for (i=0; i=0; i-- ) + { + sStripFiles += buffers[i]; + sStripFiles += "\r\n"; + + FS_FreeFile( buffers[i] ); + } + } + + int iIndex=0; + for (itCorrectionData = CorrectionData.begin(); itCorrectionData != CorrectionData.end(); ++itCorrectionData) + { + CorrectionDataItem_t &CorrectionDataItem = (*itCorrectionData); + + if (CorrectionDataItem.sStripEdReference.c_str()[0] // skip over duplicate-resolving entries +// && CorrectionDataItem.sStripEdText.c_str()[0] // + ) + { + string strAnyForeignStringsFound; // will be entire line plus CR + string strNotes; // will be just the bit within quotes + + LPCSTR psFoundExisting; + int iInitialSearchPos = 0; + while (iInitialSearchPos < sStripFiles.size() && + (strAnyForeignStringsFound.empty() || strNotes.empty()) + ) + { + if ( (psFoundExisting = strstr( sStripFiles.c_str()+iInitialSearchPos, va("\"%s\"",CorrectionDataItem.sStripEdText.c_str()))) != NULL ) + { + // see if we can find any NOTES entry above this... + // + LPCSTR p; + + if (strNotes.empty()) + { + p = psFoundExisting; + while (p > sStripFiles.c_str() && *p!='{') + { + if (!strnicmp(p,"NOTES",5) && isspace(p[-1]) && isspace(p[5])) + { + p = strchr(p,'"'); + if (!p++) + break; + while (*p != '"') + strNotes += *p++; + break; + } + p--; + } + } + + // now search for any foreign versions we already have translated... + // + if (strAnyForeignStringsFound.empty()) + { + p = psFoundExisting; + LPCSTR psNextBrace = strchr(p,'}'); + assert(psNextBrace); + if (psNextBrace) + { + for (int i=2; i<10; i++) + { + LPCSTR psForeign = strstr(p,va("TEXT_LANGUAGE%d",i)); + if (psForeign && psForeign < psNextBrace) + { + strAnyForeignStringsFound += " "; + while (*psForeign != '\n' && *psForeign != '\0') + { + strAnyForeignStringsFound += *psForeign++; + } + strAnyForeignStringsFound += "\n"; + } + } + } + } + + iInitialSearchPos = psFoundExisting - sStripFiles.c_str(); + iInitialSearchPos++; // one past, so we don't re-find ourselves + } + else + { + break; + } + } + + if (!strNotes.empty()) + { + strNotes = va(" NOTES \"%s\"\n",strNotes.c_str()); + } + + // now do output... + // + if (!(iIndex%256)) + { + string s; + vStripEdFiles.push_back(s); + + OUTPUTSTRIP( va( "VERSION 1\n" + "CONFIG W:\\bin\\striped.cfg\n" + "ID %d\n" + "REFERENCE MENUS%d\n" + "DESCRIPTION \"menu text\"\n" + "COUNT 256\n", // count will need correcting for last one + 250 + (iIndex/256), // 250 range seems to be unused + iIndex/256 + ) + ); + +// OUTPUTSTRIP( va("REFERENCE %s\n", va("%sMENUS%d",bIsMulti?"MP":"SP",iIndex/256)) ); +// OUTPUTSTRIP( va("REFERENCE %s\n", va( "MENUS%d",iIndex/256)) ); + } + + OUTPUTSTRIP( va( "INDEX %d\n" + "{\n" + " REFERENCE %s\n" + "%s" + " TEXT_LANGUAGE1 \"%s\"\n" + "%s" + "}\n", + iIndex%256, + CorrectionDataItem.sStripEdReference.c_str(), + (strNotes.empty()?"":strNotes.c_str()), + CorrectionDataItem.sStripEdText.c_str(), + strAnyForeignStringsFound.c_str() + ) + ); + + iIndex++; + } + } + + OUTPUT("### UI_Dump(): Bottom\n"); + + SendStringToNotepad(sFinalOutput.c_str(), "temp.txt"); + + // output the SP files... + // + for (i=0; i= NUM_CROSSHAIRS) { + uiInfo.currentCrosshair = 0; + } else if (uiInfo.currentCrosshair < 0) { + uiInfo.currentCrosshair = NUM_CROSSHAIRS - 1; + } + Cvar_Set("cg_drawCrosshair", va("%d", uiInfo.currentCrosshair)); + return qtrue; + } + return qfalse; +} + + +static qboolean UI_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key) +{ + + switch (ownerDraw) + { + case UI_CROSSHAIR: + UI_Crosshair_HandleKey(flags, special, key); + break; + default: + break; + } + + return qfalse; +} + + /* ================= UI_Init @@ -851,6 +886,7 @@ void _UI_Init( qboolean inGameLoad ) uiInfo.uiDC.textWidth = &Text_Width; uiInfo.uiDC.feederItemImage = &UI_FeederItemImage; uiInfo.uiDC.feederItemText = &UI_FeederItemText; + uiInfo.uiDC.ownerDrawHandleKey = &UI_OwnerDrawHandleKey; UI_Load(); @@ -1015,13 +1051,18 @@ qboolean Load_Menu(const char **holdBuffer) { return qfalse; } - + if ( *token2 == '}' ) { return qtrue; } +//#ifdef _DEBUG +// extern void UI_Debug_AddMenuFilePath(const char *); +// UI_Debug_AddMenuFilePath(token2); +//#endif UI_ParseMenu(token2); + } return qfalse; } @@ -1115,6 +1156,15 @@ void UI_Load(void) menuDef_t *menu = Menu_GetFocused(); char *menuSet = UI_Cvar_VariableString("ui_menuFiles"); + // sod it, parse every menu strip file until we find a gap in the sequence... + // + for (int i=0; i<10; i++) + { + if (!ui.SP_Register(va("menus%d",i), /*SP_REGISTER_REQUIRED|*/SP_REGISTER_MENU)) + break; + } + + if (menu && menu->window.name) { strcpy(lastName, menu->window.name); @@ -1240,13 +1290,18 @@ qboolean Asset_Parse(char **buffer) return qfalse; } - Q_strncpyz( uiInfo.uiDC.Assets.stripedFile, tempStr, sizeof(uiInfo.uiDC.Assets.stripedFile) ); - - if (!ui.SP_Register(uiInfo.uiDC.Assets.stripedFile, SP_REGISTER_REQUIRED|SP_REGISTER_MENU)) + char sTemp[1024]; + Q_strncpyz( sTemp, tempStr, sizeof(sTemp) ); + if (!ui.SP_Register(sTemp, /*SP_REGISTER_REQUIRED|*/SP_REGISTER_MENU)) { - PC_ParseWarning(va("(.SP file \"%s\" not found)",uiInfo.uiDC.Assets.stripedFile)); + PC_ParseWarning(va("(.SP file \"%s\" not found)",sTemp)); //return qfalse; // hmmm... dunno about this, don't want to break scripts for just missing subtitles } + else + { +// extern void AddMenuPackageRetryKey(const char *); +// AddMenuPackageRetryKey(sTemp); + } continue; } @@ -1440,17 +1495,14 @@ static void UI_Update(const char *name) { case 0: Cvar_SetValue( "ui_r_depthbits", 0 ); - Cvar_SetValue( "ui_r_stencilbits", 8 ); break; case 16: Cvar_SetValue( "ui_r_depthbits", 16 ); - Cvar_SetValue( "ui_r_stencilbits", 0 ); break; case 32: Cvar_SetValue( "ui_r_depthbits", 24 ); - Cvar_SetValue( "ui_r_stencilbits", 8 ); break; } } @@ -1486,38 +1538,38 @@ static void UI_Update(const char *name) Cvar_SetValue( "ui_r_texturebits", 32 ); Cvar_SetValue( "ui_r_fastSky", 0 ); Cvar_SetValue( "ui_r_inGameVideo", 1 ); - Cvar_SetValue( "ui_cg_shadows", 2 );//stencil + //Cvar_SetValue( "ui_cg_shadows", 2 );//stencil Cvar_Set( "ui_r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); break; case 1: // normal Cvar_SetValue( "ui_r_fullScreen", 1 ); - Cvar_SetValue( "ui_r_subdivisions", 12 ); + Cvar_SetValue( "ui_r_subdivisions", 4 ); Cvar_SetValue( "ui_r_lodbias", 0 ); Cvar_SetValue( "ui_r_colorbits", 0 ); Cvar_SetValue( "ui_r_depthbits", 24 ); - Cvar_SetValue( "ui_r_picmip", 0 ); + Cvar_SetValue( "ui_r_picmip", 1 ); Cvar_SetValue( "ui_r_mode", 3 ); Cvar_SetValue( "ui_r_texturebits", 0 ); Cvar_SetValue( "ui_r_fastSky", 0 ); Cvar_SetValue( "ui_r_inGameVideo", 1 ); + //Cvar_SetValue( "ui_cg_shadows", 2 ); Cvar_Set( "ui_r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); - Cvar_SetValue( "ui_cg_shadows", 2 ); break; case 2: // fast Cvar_SetValue( "ui_r_fullScreen", 1 ); - Cvar_SetValue( "ui_r_subdivisions", 8 ); + Cvar_SetValue( "ui_r_subdivisions", 12 ); Cvar_SetValue( "ui_r_lodbias", 1 ); Cvar_SetValue( "ui_r_colorbits", 0 ); Cvar_SetValue( "ui_r_depthbits", 0 ); - Cvar_SetValue( "ui_r_picmip", 1 ); + Cvar_SetValue( "ui_r_picmip", 2 ); Cvar_SetValue( "ui_r_mode", 3 ); Cvar_SetValue( "ui_r_texturebits", 0 ); - Cvar_SetValue( "ui_cg_shadows", 1 ); Cvar_SetValue( "ui_r_fastSky", 1 ); Cvar_SetValue( "ui_r_inGameVideo", 0 ); + //Cvar_SetValue( "ui_cg_shadows", 1 ); Cvar_Set( "ui_r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" ); break; @@ -1529,11 +1581,11 @@ static void UI_Update(const char *name) Cvar_SetValue( "ui_r_colorbits", 16 ); Cvar_SetValue( "ui_r_depthbits", 16 ); Cvar_SetValue( "ui_r_mode", 3 ); - Cvar_SetValue( "ui_r_picmip", 2 ); + Cvar_SetValue( "ui_r_picmip", 3 ); Cvar_SetValue( "ui_r_texturebits", 16 ); - Cvar_SetValue( "ui_cg_shadows", 0 ); Cvar_SetValue( "ui_r_fastSky", 1 ); Cvar_SetValue( "ui_r_inGameVideo", 0 ); + //Cvar_SetValue( "ui_cg_shadows", 0 ); Cvar_Set( "ui_r_texturemode", "GL_LINEAR_MIPMAP_NEAREST" ); break; } @@ -1694,17 +1746,13 @@ static void UI_DrawGLInfo(rectDef_t *rect, float scale, vec4_t color, int textSt char * eptr = buff; const char *lines[MAX_LINES]; int y, numLines=0, i=0; - const char * string; - y = rect->y; - string = ui.SP_GetStringTextString(va("%s_VENDOR",uiInfo.uiDC.Assets.stripedFile)); - Text_Paint(rect->x, y, scale, color, va("%s %s",string,uiInfo.uiDC.glconfig.vendor_string), rect->w, textStyle, iFontIndex); + y = rect->y; + Text_Paint(rect->x, y, scale, color, va("GL_VENDOR: %s",uiInfo.uiDC.glconfig.vendor_string), rect->w, textStyle, iFontIndex); y += 15; - string = ui.SP_GetStringTextString(va("%s_VERSION",uiInfo.uiDC.Assets.stripedFile)); - Text_Paint(rect->x, y, scale, color, va("%s: %s: %s", string,uiInfo.uiDC.glconfig.version_string,uiInfo.uiDC.glconfig.renderer_string), rect->w, textStyle, iFontIndex); + Text_Paint(rect->x, y, scale, color, va("GL_VERSION: %s: %s", uiInfo.uiDC.glconfig.version_string,uiInfo.uiDC.glconfig.renderer_string), rect->w, textStyle, iFontIndex); y += 15; - string = ui.SP_GetStringTextString(va("%s_PIXELFORMAT",uiInfo.uiDC.Assets.stripedFile)); - Text_Paint(rect->x, y, scale, color, string, rect->w, textStyle, iFontIndex); + Text_Paint(rect->x, y, scale, color, "GL_PIXELFORMAT:", rect->w, textStyle, iFontIndex); y += 15; Text_Paint(rect->x, y, scale, color, va ("Color(%d-bits) Z(%d-bits) stencil(%d-bits)",uiInfo.uiDC.glconfig.colorBits, uiInfo.uiDC.glconfig.depthBits, uiInfo.uiDC.glconfig.stencilBits), rect->w, textStyle, iFontIndex); y += 15; @@ -1773,6 +1821,16 @@ static void UI_DataPad_ForcePowers(rectDef_t *rect, float scale, vec4_t color, i } */ +static void UI_DrawCrosshair(rectDef_t *rect, float scale, vec4_t color) { + trap_R_SetColor( color ); + if (uiInfo.currentCrosshair < 0 || uiInfo.currentCrosshair >= NUM_CROSSHAIRS) { + uiInfo.currentCrosshair = 0; + } + UI_DrawHandlePic( rect->x, rect->y, rect->w, rect->h, uiInfo.uiDC.Assets.crosshairShader[uiInfo.currentCrosshair]); + trap_R_SetColor( NULL ); +} + + /* ================= UI_OwnerDraw @@ -1832,8 +1890,7 @@ static void UI_OwnerDraw(float x, float y, float w, float h, float text_x, float // UI_DrawPreviewCinematic(&rect, scale, color); break; case UI_CROSSHAIR: - // FIXME BOB - do we need this? -// UI_DrawCrosshair(&rect, scale, color); + UI_DrawCrosshair(&rect, scale, color); break; case UI_GLINFO: UI_DrawGLInfo(&rect,scale, color, textStyle, iFontIndex); @@ -2040,23 +2097,6 @@ int UI_OwnerDrawWidth(int ownerDraw, float scale) switch (ownerDraw) { - // FIXME BOB - /* - case UI_SKILL: - i = trap_Cvar_VariableValue( "g_spSkill" ); - if (i < 1 || i > numSkillLevels) - { - i = 1; - } - s = skillLevels[i-1]; - break; - case UI_NETSOURCE: - if (ui_netSource.integer < 0 || ui_netSource.integer > uiInfo.numJoinGameTypes) - { - ui_netSource.integer = 0; - } - s = va("Source: %s", netSources[ui_netSource.integer]); - break; */ case UI_KEYBINDSTATUS: if (Display_KeyBindPending()) { @@ -2218,11 +2258,9 @@ void UI_DataPadMenu(void) { int newForcePower,newObjective; - ui.PrecacheScreenshot(); - Menus_CloseByName("mainhud"); - newForcePower = (int)trap_Cvar_VariableValue("cg_updatedDataPadForcePower"); + newForcePower = (int)trap_Cvar_VariableValue("cg_updatedDataPadForcePower1"); newObjective = (int)trap_Cvar_VariableValue("cg_updatedDataPadObjective"); if (newForcePower) @@ -2334,7 +2372,6 @@ you to discard your changes if you did something you didnt want */ void UI_UpdateVideoSetup ( void ) { - Cvar_Set ( "r_glCustom", Cvar_VariableString ( "ui_r_glCustom" ) ); Cvar_Set ( "r_mode", Cvar_VariableString ( "ui_r_mode" ) ); Cvar_Set ( "r_fullscreen", Cvar_VariableString ( "ui_r_fullscreen" ) ); Cvar_Set ( "r_colorbits", Cvar_VariableString ( "ui_r_colorbits" ) ); @@ -2348,6 +2385,7 @@ void UI_UpdateVideoSetup ( void ) Cvar_Set ( "r_subdivisions", Cvar_VariableString ( "ui_r_subdivisions" ) ); Cvar_Set ( "r_fastSky", Cvar_VariableString ( "ui_r_fastSky" ) ); Cvar_Set ( "r_inGameVideo", Cvar_VariableString ( "ui_r_inGameVideo" ) ); + Cvar_Set ( "r_allowExtensions", Cvar_VariableString ( "ui_r_allowExtensions" ) ); Cvar_Set ( "cg_shadows", Cvar_VariableString ( "ui_cg_shadows" ) ); Cvar_Set ( "ui_r_modified", "0" ); @@ -2365,7 +2403,8 @@ interface versions of the cvars. void UI_GetVideoSetup ( void ) { // Make sure the cvars are registered as read only. - Cvar_Register ( NULL, "ui_r_glCustom", "0", CVAR_ROM ); + Cvar_Register ( NULL, "ui_r_glCustom", "4", CVAR_ROM|CVAR_ARCHIVE ); + Cvar_Register ( NULL, "ui_r_mode", "0", CVAR_ROM ); Cvar_Register ( NULL, "ui_r_fullscreen", "0", CVAR_ROM ); Cvar_Register ( NULL, "ui_r_colorbits", "0", CVAR_ROM ); @@ -2379,11 +2418,11 @@ void UI_GetVideoSetup ( void ) Cvar_Register ( NULL, "ui_r_subdivisions", "0", CVAR_ROM ); Cvar_Register ( NULL, "ui_r_fastSky", "0", CVAR_ROM ); Cvar_Register ( NULL, "ui_r_inGameVideo", "0", CVAR_ROM ); + Cvar_Register ( NULL, "ui_r_allowExtensions", "0", CVAR_ROM ); Cvar_Register ( NULL, "ui_cg_shadows", "0", CVAR_ROM ); Cvar_Register ( NULL, "ui_r_modified", "0", CVAR_ROM ); // Copy over the real video cvars into their temporary counterparts - Cvar_Set ( "ui_r_glCustom", Cvar_VariableString ( "r_glCustom" ) ); Cvar_Set ( "ui_r_mode", Cvar_VariableString ( "r_mode" ) ); Cvar_Set ( "ui_r_colorbits", Cvar_VariableString ( "r_colorbits" ) ); Cvar_Set ( "ui_r_fullscreen", Cvar_VariableString ( "r_fullscreen" ) ); @@ -2391,11 +2430,13 @@ void UI_GetVideoSetup ( void ) Cvar_Set ( "ui_r_picmip", Cvar_VariableString ( "r_picmip" ) ); Cvar_Set ( "ui_r_texturebits", Cvar_VariableString ( "r_texturebits" ) ); Cvar_Set ( "ui_r_texturemode", Cvar_VariableString ( "r_texturemode" ) ); + Cvar_Set ( "ui_r_detailtextures", Cvar_VariableString ( "r_detailtextures" ) ); Cvar_Set ( "ui_r_ext_compress_textures", Cvar_VariableString ( "r_ext_compress_textures" ) ); Cvar_Set ( "ui_r_depthbits", Cvar_VariableString ( "r_depthbits" ) ); Cvar_Set ( "ui_r_subdivisions", Cvar_VariableString ( "r_subdivisions" ) ); Cvar_Set ( "ui_r_fastSky", Cvar_VariableString ( "r_fastSky" ) ); Cvar_Set ( "ui_r_inGameVideo", Cvar_VariableString ( "r_inGameVideo" ) ); + Cvar_Set ( "ui_r_allowExtensions", Cvar_VariableString ( "r_allowExtensions" ) ); Cvar_Set ( "ui_cg_shadows", Cvar_VariableString ( "cg_shadows" ) ); Cvar_Set ( "ui_r_modified", "0" ); } @@ -2459,8 +2500,8 @@ UI_ResetDefaults */ void UI_ResetDefaults( void ) { - ui.Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n"); ui.Cmd_ExecuteText( EXEC_APPEND, "cvar_restart\n"); + ui.Cmd_ExecuteText( EXEC_APPEND, "exec default.cfg\n"); ui.Cmd_ExecuteText( EXEC_APPEND, "vid_restart\n" ); Cvar_Set("com_introPlayed", "1" ); } diff --git a/code/ui/ui_shared.cpp b/code/ui/ui_shared.cpp index 1f2355d..5752f5b 100644 --- a/code/ui/ui_shared.cpp +++ b/code/ui/ui_shared.cpp @@ -35,6 +35,7 @@ void ToWindowCoords(float *x, float *y, windowDef_t *window); void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle); int Item_ListBox_ThumbDrawPosition(itemDef_t *item); int Item_ListBox_ThumbPosition(itemDef_t *item); +qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y) ; //static qboolean debugMode = qfalse; static qboolean g_waitingForKey = qfalse; @@ -203,6 +204,11 @@ void PC_SourceError(int handle, char *format, ...) PC_ParseStringMem ================= */ +//static vector RetryPool; +//void AddMenuPackageRetryKey(const char *psSPPackage) +//{ +// RetryPool.push_back(psSPPackage); +//} qboolean PC_ParseStringMem(const char **out) { const char *temp; @@ -214,13 +220,27 @@ qboolean PC_ParseStringMem(const char **out) if (*temp == '@') // Is it a localized text? { - const int ID = SP_GetStringID(va("%s_%s",uiInfo.uiDC.Assets.stripedFile,(temp+1))); // The +1 is to offset the @ at the beginning of the text + int ID = SP_GetStringID(temp+1); // The +1 is to offset the @ at the beginning of the text if (ID != -1) { *(out) = (char*)-ID; return ID; } - PC_ParseWarning(va("Can't find StriP '%s' in %s", temp, uiInfo.uiDC.Assets.stripedFile)); +/* // ok failed, now hopefully this is probably just because of the stupid/wrong way the MP menus were done, so... + // + for (int i=0; istartLocalSound(DC->registerSound(val, qfalse), CHAN_LOCAL_SOUND); + DC->startLocalSound(DC->registerSound(val, qfalse), CHAN_AUTO ); } return qtrue; @@ -2265,6 +2285,11 @@ qboolean ItemParse_focusSound( itemDef_t *item) } + +//#ifdef _DEBUG +//extern void UI_Debug_EnterReference(LPCSTR ps4LetterType, LPCSTR psItemString); +//#endif + /* =============== ItemParse_text @@ -2272,12 +2297,16 @@ ItemParse_text =============== */ qboolean ItemParse_text( itemDef_t *item) -{ +{ if (!PC_ParseStringMem((const char **) &item->text)) { return qfalse; } +//#ifdef _DEBUG +// UI_Debug_EnterReference("TEXT", item->text); +//#endif + return qtrue; } @@ -2294,6 +2323,10 @@ qboolean ItemParse_descText( itemDef_t *item) return qfalse; } +//#ifdef _DEBUG +// UI_Debug_EnterReference("DESC", item->descText); +//#endif + return qtrue; } @@ -2310,6 +2343,10 @@ qboolean ItemParse_text2( itemDef_t *item) return qfalse; } +//#ifdef _DEBUG +// UI_Debug_EnterReference("TXT2", item->text2); +//#endif + return qtrue; } @@ -3244,25 +3281,6 @@ qboolean ItemParse_action( itemDef_t *item) } -/* -=============== -ItemParse_stripedFile -=============== -*/ -qboolean ItemParse_stripedFile( itemDef_t *item) -{ - char *tempStr; - - if (!PC_ParseStringMem((const char **) &tempStr)) - { - return qfalse; - } - - Q_strncpyz( uiInfo.uiDC.Assets.stripedFile, tempStr, sizeof(uiInfo.uiDC.Assets.stripedFile) ); - - return ui.SP_Register(uiInfo.uiDC.Assets.stripedFile, SP_REGISTER_REQUIRED|SP_REGISTER_MENU); -} - /* =============== ItemParse_special @@ -3458,6 +3476,10 @@ qboolean ItemParse_cvarStrList( itemDef_t *item) { multiPtr->cvarList[multiPtr->count] = token; pass = 1; + +//#ifdef _DEBUG +// UI_Debug_EnterReference("CVRF", token); +//#endif } else { @@ -3523,6 +3545,13 @@ qboolean ItemParse_cvarFloatList( itemDef_t *item) } } +//#ifdef _DEBUG +//// if ((int)token < 0) // always do it, then "1024 x 768" would go into SP and can be asianised +// { +// UI_Debug_EnterReference("CVRF", token); +// } +//#endif + multiPtr->cvarList[multiPtr->count] = token; //either a striped ID, or a StringAlloc ptr if (PC_ParseFloat(&multiPtr->cvarValue[multiPtr->count])) { @@ -3737,7 +3766,6 @@ keywordHash_t itemParseKeywords[] = { {"rect", ItemParse_rect, }, {"showCvar", ItemParse_showCvar, }, {"special", ItemParse_special, }, - {"stripedFile", ItemParse_stripedFile, }, {"style", ItemParse_style, }, {"text", ItemParse_text }, {"text2", ItemParse_text2 }, @@ -4590,13 +4618,12 @@ qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag) { char script[1024]; const char *p; - memset(script, 0, sizeof(script)); if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) { char buff[1024]; DC->getCVarString(item->cvarTest, buff, sizeof(buff)); - Q_strcat(script, 1024, item->enableCvar); + Q_strncpyz(script, item->enableCvar, 1024); p = script; while (1) { @@ -5219,7 +5246,7 @@ void BindingFromName(const char *cvar) DC->keynumToStringBuf( b2, g_nameBind2, 32 ); Q_strupr(g_nameBind2); - strcat( g_nameBind1, va(" %s ",ui.SP_GetStringTextString("MENUS_OR")) ); + strcat( g_nameBind1, va(" %s ",ui.SP_GetStringTextString("MENUS3_KEYBIND_OR")) ); strcat( g_nameBind1, g_nameBind2 ); } return; @@ -5236,9 +5263,9 @@ Item_Bind_Paint */ void Item_Bind_Paint(itemDef_t *item) { - vec4_t newColor, lowLight; - float value; - int maxChars = 0; + vec4_t newColor, lowLight; + float value,textScale,textWidth; + int maxChars = 0, textHeight,yAdj,startingXPos; menuDef_t *parent = (menuDef_t*)item->parent; editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData; @@ -5277,7 +5304,28 @@ void Item_Bind_Paint(itemDef_t *item) { Item_Text_Paint(item); BindingFromName(item->cvar); - DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, g_nameBind1, maxChars/*item->textRect.w*/, item->textStyle, item->font); + + // If the text runs past the limit bring the scale down until it fits. + textScale = item->textscale; + textWidth = DC->textWidth(g_nameBind1,(float) textScale, uiInfo.uiDC.Assets.qhMediumFont); + + startingXPos = (item->textRect.x + item->textRect.w + 8); + + while ((startingXPos + textWidth) >= SCREEN_WIDTH) + { + textScale -= .05f; + textWidth = DC->textWidth(g_nameBind1,(float) textScale, uiInfo.uiDC.Assets.qhMediumFont); + } + + // Try to adjust it's y placement if the scale has changed. + yAdj = 0; + if (textScale != item->textscale) + { + textHeight = DC->textHeight(g_nameBind1, item->textscale, uiInfo.uiDC.Assets.qhMediumFont); + yAdj = textHeight - DC->textHeight(g_nameBind1, textScale, uiInfo.uiDC.Assets.qhMediumFont); + } + + DC->drawText(startingXPos, item->textRect.y + yAdj, textScale, newColor, g_nameBind1, maxChars/*item->textRect.w*/, item->textStyle, item->font); } else { @@ -5449,15 +5497,9 @@ void Item_OwnerDraw_Paint(itemDef_t *item) if (item->text) { Item_Text_Paint(item); - if (item->text[0]) - { - // +8 is an offset kludge to properly align owner draw items that have text combined with them - DC->ownerDrawItem(item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle, item->font ); - } - else - { - DC->ownerDrawItem(item->textRect.x + item->textRect.w, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle, item->font ); - } + + // +8 is an offset kludge to properly align owner draw items that have text combined with them + DC->ownerDrawItem(item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textscale, color, item->window.background, item->textStyle, item->font ); } else { @@ -5487,14 +5529,17 @@ void Item_YesNo_Paint(itemDef_t *item) memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t)); } + const char *psYes = ui.SP_GetStringTextString("MENUS0_YES"); + const char *psNo = ui.SP_GetStringTextString("MENUS0_NO"); if (item->text) { Item_Text_Paint(item); - DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, item->textStyle, item->font); + DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textscale, newColor, (value != 0) ? psYes : psNo, 0, item->textStyle, item->font); + } else { - DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, item->textStyle, item->font); + DC->drawText(item->textRect.x, item->textRect.y, item->textscale, newColor, (value != 0) ? psYes : psNo , 0, item->textStyle, item->font); } } @@ -5693,46 +5738,6 @@ void Item_Paint(itemDef_t *item) return; } - if (item->window.flags & WINDOW_MOUSEOVER) - { - if (item->descText) - { - const char *textPtr; - if ((int)item->descText < 0) - { - textPtr = SP_GetStringText(-(int)item->descText); - } - else - { - textPtr = item->descText; - } - - textWidth = DC->textWidth(textPtr,(float) item->textscale, uiInfo.uiDC.Assets.qhMediumFont); // item->font); - - if (parent->descAlignment == ITEM_ALIGN_RIGHT) - { - xPos = parent->descX - textWidth; // Right justify - } - else if (parent->descAlignment == ITEM_ALIGN_CENTER) - { - xPos = parent->descX - (textWidth/2); // Center justify - } - else // Left justify - { - xPos = parent->descX; - } - - vec4_t color = {1, 1, 1, 1}; - Item_TextColor(item, &color); - - if (!parent->descScale) - { - parent->descScale = 1; - } - - DC->drawText(xPos, parent->descY, (float) parent->descScale, parent->descColor, textPtr, 0, 0, uiInfo.uiDC.Assets.qhMediumFont); //item->font); - } - } if (item->window.flags & WINDOW_ORBITING) { @@ -5908,6 +5913,76 @@ void Item_Paint(itemDef_t *item) return; } + if (item->window.flags & WINDOW_MOUSEOVER) + { + if (item->descText && !Display_KeyBindPending()) + { + // Make DOUBLY sure that this item should have desctext. + if (!Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) + { // It isn't something that should, because it isn't live anymore. + item->window.flags &= ~WINDOW_MOUSEOVER; + } + else + { // Draw the desctext + const char *textPtr; + if ((int)item->descText < 0) + { + textPtr = SP_GetStringText(-(int)item->descText); + } + else + { + textPtr = item->descText; + } + + vec4_t color = {1, 1, 1, 1}; + Item_TextColor(item, &color); + + float fDescScale = parent->descScale ? parent->descScale : 1; + float fDescScaleCopy = fDescScale; + while (1) + { + textWidth = DC->textWidth(textPtr, fDescScale, uiInfo.uiDC.Assets.qhMediumFont); // item->font); + + if (parent->descAlignment == ITEM_ALIGN_RIGHT) + { + xPos = parent->descX - textWidth; // Right justify + } + else if (parent->descAlignment == ITEM_ALIGN_CENTER) + { + xPos = parent->descX - (textWidth/2); // Center justify + } + else // Left justify + { + xPos = parent->descX; + } + + if (parent->descAlignment == ITEM_ALIGN_CENTER) + { + // only this one will auto-shrink the scale until we eventually fit... + // + if (xPos + textWidth > (SCREEN_WIDTH-4)) { + fDescScale -= 0.001f; + continue; + } + } + + + // Try to adjust it's y placement if the scale has changed... + // + int iYadj = 0; + if (fDescScale != fDescScaleCopy) + { + int iOriginalTextHeight = DC->textHeight(textPtr, fDescScaleCopy, uiInfo.uiDC.Assets.qhMediumFont); + iYadj = iOriginalTextHeight - DC->textHeight(textPtr, fDescScale, uiInfo.uiDC.Assets.qhMediumFont); + } + + DC->drawText(xPos, parent->descY + iYadj, fDescScale, parent->descColor, textPtr, 0, 0, uiInfo.uiDC.Assets.qhMediumFont); //item->font); + break; + } + } + } + } + // paint the rect first.. Window_Paint(&item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle); @@ -6915,7 +6990,9 @@ void Controls_SetConfig(qboolean restart) //trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue ); //trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue ); //trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue ); - DC->executeText(EXEC_APPEND, "in_restart\n"); +// +// DC->executeText(EXEC_APPEND, "in_restart\n"); +// ^--this is bad, it shows the cursor during map load, if you need to, add it as an exec cmd to use_joy or something. } void Item_Bind_Ungrey(itemDef_t *item) @@ -6946,9 +7023,9 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) int i; menuDef_t *menu; - if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey) + if (key == K_MOUSE1 && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey) { - if (down && (key == K_MOUSE1 || key == K_ENTER)) + if (down) { g_waitingForKey = qtrue; g_bindItem = item; @@ -6965,9 +7042,26 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) } } - else if (down && (key == K_ESCAPE)) + return qtrue; + } + else if (key == K_ENTER && !g_waitingForKey) + { + if (down) { - return qfalse; + g_waitingForKey = qtrue; + g_bindItem = item; + + // Set all others in the menu to grey + menu = (menuDef_t *) item->parent; + for (i=0;iitemCount;++i) + { + if (menu->items[i] == item) + { + continue; + } + menu->items[i]->window.flags |= WINDOW_INACTIVE; + } + } return qtrue; } @@ -6975,7 +7069,7 @@ qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) { if (!g_waitingForKey || g_bindItem == NULL) { - return qtrue; + return qfalse; } if (key & K_CHAR_FLAG) @@ -7917,6 +8011,14 @@ static void Scroll_Slider_ThumbFunc(void *p) scrollInfo_t *si = (scrollInfo_t*)p; editFieldDef_t *editDef = (struct editFieldDef_s *) si->item->typeData; + if (!Rect_ContainsPoint(&si->item->window.rect, DC->cursorx, DC->cursory)) + { + Item_StopCapture(itemCapture); + itemCapture = NULL; + captureFunc = NULL; + captureData = NULL; + } + if (si->item->text) { x = si->item->textRect.x + si->item->textRect.w + 8; @@ -8077,6 +8179,8 @@ int Item_Multi_CountSettings(itemDef_t *item) return multiPtr->count; } + + /* ================= Item_OwnerDraw_HandleKey @@ -8086,7 +8190,7 @@ qboolean Item_OwnerDraw_HandleKey(itemDef_t *item, int key) { if (item && DC->ownerDrawHandleKey) { - return DC->ownerDrawHandleKey(item->window.ownerDraw, item->window.ownerDrawFlags, &item->special, key); + return DC->ownerDrawHandleKey(item->window.ownerDraw, item->window.ownerDrawFlags, &item->special, key); } return qfalse; } @@ -8378,10 +8482,25 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) return; } + // Special Data Pad key handling (gotta love the datapad) + if (!(key & K_CHAR_FLAG) ) + { //only check keys not chars + char b[256]; + DC->getBindingBuf( key, b, 256 ); + if (Q_stricmp(b,"datapad") == 0) // They hit the datapad key again. + { + if (( Q_stricmp(menu->window.name,"datapadMissionMenu") == 0) || + (Q_stricmp(menu->window.name,"datapadWeaponsMenu") == 0) || + (Q_stricmp(menu->window.name,"datapadForcePowersMenu") == 0) || + (Q_stricmp(menu->window.name,"datapadInventoryMenu") == 0)) + { + key = K_ESCAPE; //pop on outta here + } + } + } // default handling switch ( key ) { - case K_F11: if (DC->getCVarValue("developer")) { @@ -8404,8 +8523,8 @@ void Menu_HandleKey(menuDef_t *menu, int key, qboolean down) if (!g_waitingForKey && menu->onESC) { itemDef_t it; - it.parent = menu; - Item_RunScript(&it, menu->onESC); + it.parent = menu; + Item_RunScript(&it, menu->onESC); } break; case K_TAB: diff --git a/code/ui/ui_shared.h b/code/ui/ui_shared.h index f14deba..285d698 100644 --- a/code/ui/ui_shared.h +++ b/code/ui/ui_shared.h @@ -131,7 +131,6 @@ typedef struct { vec4_t shadowColor; float shadowFadeClamp; qboolean fontRegistered; - char stripedFile[MAX_STRING_CHARS]; // player settings qhandle_t fxBasePic; diff --git a/code/ui/vssver.scc b/code/ui/vssver.scc new file mode 100644 index 0000000..228871a Binary files /dev/null and b/code/ui/vssver.scc differ diff --git a/code/unix/Makefile b/code/unix/Makefile new file mode 100644 index 0000000..5c8dda8 --- /dev/null +++ b/code/unix/Makefile @@ -0,0 +1,988 @@ +# +# Quake3 Unix Makefile +# +# Currently build for the following: +# Linux i386 (full client) +# Linux Alpha (dedicated server only) +# SGI IRIX (full client) +# +# Nov '98 by Zoid +# +# GNU Make required +# + +PLATFORM=$(shell uname|tr '[:upper:]' '[:lower:]') +PLATFORM_RELEASE=$(shell uname -r) + +### +### These paths are where you probably want to change things +### + +# Where we are building to, libMesaVoodooGL.so.3.1 should be here, etc. +# the demo pk3 file should be here in demoq3/pak0.pk3 or baseq3/pak0.pk3 +BUILD_DIR=/home/zoid/Quake3 + +# Where we are building from (where the source code should be!) +MOUNT_DIR=/devel/Quake3/q3code + +############################################################################# +## +## You shouldn't have to touch anything below here +## +############################################################################# + +DEMO_PAK=$(BUILD_DIR)/demoq3/pak0.pk3 + +BUILD_DEBUG_DIR=debug$(ARCH)$(GLIBC) +BUILD_RELEASE_DIR=release$(ARCH)$(GLIBC) +CLIENT_DIR=$(MOUNT_DIR)/client +SERVER_DIR=$(MOUNT_DIR)/server +REF_DIR=$(MOUNT_DIR)/renderer +COMMON_DIR=$(MOUNT_DIR)/qcommon +UNIX_DIR=$(MOUNT_DIR)/unix +GAME_DIR=$(MOUNT_DIR)/game +CGAME_DIR=$(MOUNT_DIR)/cgame +NULL_DIR=$(MOUNT_DIR)/null + +#used for linux i386 builds +MESA_DIR=/usr/local/src/Mesa-3.0 + +VERSION=1.05 + +VERSION_FN=$(VERSION)$(GLIBC) +RPM_RELEASE=9 + +############################################################################# +# SETUP AND BUILD +############################################################################# + +ifeq ($(PLATFORM),irix) + +ARCH=mips #default to MIPS +VENDOR=sgi +GLIBC= #libc is irrelevant + +CC=cc +BASE_CFLAGS=-Dstricmp=strcasecmp -Xcpluscomm -woff 1185 -mips3 \ + -nostdinc -I. -I$(ROOT)/usr/include +RELEASE_CFLAGS=$(BASE_CFLAGS) -O3 +DEBUG_CFLAGS=$(BASE_CFLAGS) -g + +SHLIBEXT=so +SHLIBCFLAGS= +SHLIBLDFLAGS=-shared + +LDFLAGS=-ldl -lm +GLLDFLAGS=-L/usr/X11/lib -lGL -lX11 -lXext -lm + +TARGETS=$(BUILDDIR)/sgiquake3 \ + $(BUILDDIR)/qagame$(ARCH).$(SHLIBEXT) \ + $(BUILDDIR)/cgame$(ARCH).$(SHLIBEXT) + +else +ifeq ($(PLATFORM),linux) + +ifneq (,$(findstring libc6,$(shell if [ -e /lib/libc.so.6* ];then echo libc6;fi))) +GLIBC=-glibc +else +GLIBC= +endif #libc6 test + + +ifneq (,$(findstring alpha,$(shell uname -m))) +ARCH=axp +RPMARCH=alpha +VENDOR=dec +else #default to i386 +ARCH=i386 +RPMARCH=i386 +VENDOR=unknown +endif #alpha test + +BASE_CFLAGS=-Dstricmp=strcasecmp -I$(MESA_DIR)/include -I/usr/include/glide \ + -DREF_HARD_LINKED -pipe + +DEBUG_CFLAGS=$(BASE_CFLAGS) -g +ifeq ($(ARCH),axp) +RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O6 -ffast-math -funroll-loops -fomit-frame-pointer -fexpensive-optimizations +else +RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O3 -m486 -fomit-frame-pointer -pipe -ffast-math -fexpensive-optimizations -malign-loops=2 -malign-jumps=2 -malign-functions=2 +endif + +CC=gcc + +SHLIBEXT=so +SHLIBCFLAGS=-fPIC +SHLIBLDFLAGS=-shared + +LDFLAGS=-ldl -lm +GLLDFLAGS=-L/usr/X11R6/lib -L$(MESA_DIR)/lib -lX11 -lXext -lXxf86dga -lXxf86vm +GL_SVGA_LDFLAGS=-L/usr/X11R6/lib -L$(MESA_DIR)/lib -lX11 -lXext -lvga + +ifeq ($(ARCH),axp) +TARGETS=$(BUILDDIR)/linuxq3ded $(BUILDDIR)/qagame$(ARCH).$(SHLIBEXT) +else +# $(BUILDDIR)/linuxquake3.vga +TARGETS=\ + $(BUILDDIR)/linuxquake3 \ + $(BUILDDIR)/qagame$(ARCH).$(SHLIBEXT) \ + $(BUILDDIR)/cgame$(ARCH).$(SHLIBEXT) +#$(BUILDDIR)/quake3 +endif + + +else #generic + +CC=cc +BASE_CFLAGS=-Dstricmp=strcasecmp +DEBUG_CFLAGS=$(BASE_CFLAGS) -g +RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O + +SHLIBEXT=so +SHLIBCFLAGS=-fPIC +SHLIBLDFLAGS=-shared + +LDFLAGS=-ldl -lm + +TARGETS=$(BUILDDIR)/q3ded $(BUILDDIR)/qagame$(ARCH).$(SHLIBEXT) + +endif #Linux +endif #IRIX + +DO_CC=$(CC) $(CFLAGS) -o $@ -c $< +DO_DEBUG_CC=$(CC) $(DEBUG_CFLAGS) -o $@ -c $< +DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $< +DO_SHLIB_DEBUG_CC=$(CC) $(DEBUG_CFLAGS) $(SHLIBCFLAGS) -o $@ -c $< +DO_AS=$(CC) $(CFLAGS) -DELF -x assembler-with-cpp -o $@ -c $< + +#### DEFAULT TARGET +# default: build_release + +build_debug: + $(MAKE) targets BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)" + +build_release: + $(MAKE) targets BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(RELEASE_CFLAGS)" + +#Build both debug and release builds +all: build_debug build_release + +targets: makedirs $(TARGETS) + +makedirs: + @if [ ! -d $(BUILDDIR) ];then mkdir $(BUILDDIR);fi + @if [ ! -d $(BUILDDIR)/client ];then mkdir $(BUILDDIR)/client;fi + @if [ ! -d $(BUILDDIR)/ded ];then mkdir $(BUILDDIR)/ded;fi + @if [ ! -d $(BUILDDIR)/ref ];then mkdir $(BUILDDIR)/ref;fi + @if [ ! -d $(BUILDDIR)/game ];then mkdir $(BUILDDIR)/game;fi + @if [ ! -d $(BUILDDIR)/cgame ];then mkdir $(BUILDDIR)/cgame;fi + +############################################################################# +# CLIENT/SERVER +############################################################################# + +QUAKE3_OBJS = \ + $(BUILDDIR)/client/cl_cgame.o \ + $(BUILDDIR)/client/cl_cin.o \ + $(BUILDDIR)/client/cl_console.o \ + $(BUILDDIR)/client/cl_input.o \ + $(BUILDDIR)/client/cl_keys.o \ + $(BUILDDIR)/client/cl_main.o \ + $(BUILDDIR)/client/cl_parse.o \ + $(BUILDDIR)/client/cl_scrn.o \ + $(BUILDDIR)/client/snd_dma.o \ + $(BUILDDIR)/client/snd_mem.o \ + $(BUILDDIR)/client/snd_mix.o \ + $(BUILDDIR)/client/sv_bot.o \ + $(BUILDDIR)/client/sv_client.o \ + $(BUILDDIR)/client/sv_ccmds.o \ + $(BUILDDIR)/client/sv_game.o \ + $(BUILDDIR)/client/sv_init.o \ + $(BUILDDIR)/client/sv_main.o \ + $(BUILDDIR)/client/sv_snapshot.o \ + $(BUILDDIR)/client/sv_world.o \ + $(BUILDDIR)/client/ui_arena.o \ + $(BUILDDIR)/client/ui_connect.o \ + $(BUILDDIR)/client/ui_controls.o \ + $(BUILDDIR)/client/ui_demo.o \ + $(BUILDDIR)/client/ui_maps.o \ + $(BUILDDIR)/client/ui_menu.o \ + $(BUILDDIR)/client/ui_network.o \ + $(BUILDDIR)/client/ui_preferences.o \ + $(BUILDDIR)/client/ui_qmenu.o \ + $(BUILDDIR)/client/ui_servers.o \ + $(BUILDDIR)/client/ui_startserver.o \ + $(BUILDDIR)/client/ui_video.o \ + \ + $(BUILDDIR)/client/cm_load.o \ + $(BUILDDIR)/client/cm_patch.o \ + $(BUILDDIR)/client/cm_polylib.o \ + $(BUILDDIR)/client/cm_tag.o \ + $(BUILDDIR)/client/cm_test.o \ + $(BUILDDIR)/client/cm_trace.o \ + $(BUILDDIR)/client/cmd.o \ + $(BUILDDIR)/client/common.o \ + $(BUILDDIR)/client/cvar.o \ + $(BUILDDIR)/client/files.o \ + $(BUILDDIR)/client/gameinfo.o \ + $(BUILDDIR)/client/md4.o \ + $(BUILDDIR)/client/msg.o \ + $(BUILDDIR)/client/net_chan.o \ + $(BUILDDIR)/client/vm.o \ + \ + $(BUILDDIR)/client/q_shared.o \ + $(BUILDDIR)/client/q_math.o \ + \ + $(BUILDDIR)/client/tr_backend.o \ + $(BUILDDIR)/client/tr_bsp.o \ + $(BUILDDIR)/client/tr_calc.o \ + $(BUILDDIR)/client/tr_calc_3dnow.o \ + $(BUILDDIR)/client/tr_calc_c.o \ + $(BUILDDIR)/client/tr_calc_kni.o \ + $(BUILDDIR)/client/tr_cmds.o \ + $(BUILDDIR)/client/tr_curve.o \ + $(BUILDDIR)/client/tr_draw.o \ + $(BUILDDIR)/client/tr_flares.o \ + $(BUILDDIR)/client/tr_image.o \ + $(BUILDDIR)/client/tr_init.o \ + $(BUILDDIR)/client/tr_light.o \ + $(BUILDDIR)/client/tr_main.o \ + $(BUILDDIR)/client/tr_mesh.o \ + $(BUILDDIR)/client/tr_misc.o \ + $(BUILDDIR)/client/tr_model.o \ + $(BUILDDIR)/client/tr_noise.o \ + $(BUILDDIR)/client/tr_scene.o \ + $(BUILDDIR)/client/tr_shade.o \ + $(BUILDDIR)/client/tr_shader.o \ + $(BUILDDIR)/client/tr_shade_calc.o \ + $(BUILDDIR)/client/tr_shadows.o \ + $(BUILDDIR)/client/tr_smp.o \ + $(BUILDDIR)/client/tr_sky.o \ + $(BUILDDIR)/client/tr_surf.o \ + $(BUILDDIR)/client/tr_world.o \ + \ + $(BUILDDIR)/client/unix_main.o \ + $(BUILDDIR)/client/unix_net.o \ + $(BUILDDIR)/client/unix_shared.o + +#platform specific objects +ifeq ($(PLATFORM),irix) + QUAKE3_PLATOBJ=\ + $(BUILDDIR)/client/irix_qgl.o \ + $(BUILDDIR)/client/irix_glimp.o \ + $(BUILDDIR)/client/irix_snd.o +else +ifeq ($(PLATFORM),linux) +ifeq ($(ARCH),axp) + QUAKE3_PLATOBJ= +else + QUAKE3_PLATOBJ=\ + $(BUILDDIR)/client/linux_qgl.o \ + $(BUILDDIR)/client/linux_glimp.o \ + $(BUILDDIR)/client/linux_snd.o \ + $(BUILDDIR)/client/snd_mixa.o \ + $(BUILDDIR)/client/matha.o \ + $(BUILDDIR)/client/sys_dosa.o + QUAKE3_VGA=\ + $(BUILDDIR)/client/linux_qgl.o \ + $(BUILDDIR)/client/linux_glimp_vga.o \ + $(BUILDDIR)/client/linux_input_vga.o \ + $(BUILDDIR)/client/linux_snd.o \ + $(BUILDDIR)/client/snd_mixa.o \ + $(BUILDDIR)/client/matha.o \ + $(BUILDDIR)/client/sys_dosa.o + +endif +endif #Linux +endif #IRIX + + +$(BUILDDIR)/linuxquake3 : $(QUAKE3_OBJS) $(QUAKE3_PLATOBJ) + $(CC) $(CFLAGS) -o $@ $(QUAKE3_OBJS) $(QUAKE3_PLATOBJ) $(GLLDFLAGS) $(LDFLAGS) + +ifeq ($(PLATFORM),linux) +ifeq ($(ARCH),i386) +$(BUILDDIR)/linuxquake3.vga : $(QUAKE3_OBJS) $(QUAKE3_VGA) + $(CC) $(CFLAGS) -o $@ $(QUAKE3_OBJS) $(QUAKE3_VGA) $(GL_SVGA_LDFLAGS) $(LDFLAGS) +endif +endif + +$(BUILDDIR)/client/cl_cgame.o : $(CLIENT_DIR)/cl_cgame.c + $(DO_CC) + +$(BUILDDIR)/client/cl_cin.o : $(CLIENT_DIR)/cl_cin.c + $(DO_CC) + +$(BUILDDIR)/client/cl_console.o : $(CLIENT_DIR)/cl_console.c + $(DO_CC) + +$(BUILDDIR)/client/cl_input.o : $(CLIENT_DIR)/cl_input.c + $(DO_CC) + +$(BUILDDIR)/client/cl_keys.o : $(CLIENT_DIR)/cl_keys.c + $(DO_CC) + +$(BUILDDIR)/client/cl_main.o : $(CLIENT_DIR)/cl_main.c + $(DO_CC) + +$(BUILDDIR)/client/cl_parse.o : $(CLIENT_DIR)/cl_parse.c + $(DO_CC) + +$(BUILDDIR)/client/cl_scrn.o : $(CLIENT_DIR)/cl_scrn.c + $(DO_CC) + +$(BUILDDIR)/client/snd_dma.o : $(CLIENT_DIR)/snd_dma.c + $(DO_CC) + +$(BUILDDIR)/client/snd_mem.o : $(CLIENT_DIR)/snd_mem.c + $(DO_CC) + +$(BUILDDIR)/client/snd_mix.o : $(CLIENT_DIR)/snd_mix.c + $(DO_CC) + +$(BUILDDIR)/client/sv_bot.o : $(SERVER_DIR)/sv_bot.c + $(DO_CC) + +$(BUILDDIR)/client/sv_client.o : $(SERVER_DIR)/sv_client.c + $(DO_CC) + +$(BUILDDIR)/client/sv_ccmds.o : $(SERVER_DIR)/sv_ccmds.c + $(DO_CC) + +$(BUILDDIR)/client/sv_game.o : $(SERVER_DIR)/sv_game.c + $(DO_CC) + +$(BUILDDIR)/client/sv_init.o : $(SERVER_DIR)/sv_init.c + $(DO_CC) + +$(BUILDDIR)/client/sv_main.o : $(SERVER_DIR)/sv_main.c + $(DO_CC) + +$(BUILDDIR)/client/sv_snapshot.o : $(SERVER_DIR)/sv_snapshot.c + $(DO_CC) + +$(BUILDDIR)/client/sv_world.o : $(SERVER_DIR)/sv_world.c + $(DO_CC) + +$(BUILDDIR)/client/ui_arena.o : $(CLIENT_DIR)/ui_arena.c + $(DO_CC) + +$(BUILDDIR)/client/ui_connect.o : $(CLIENT_DIR)/ui_connect.c + $(DO_CC) + +$(BUILDDIR)/client/ui_controls.o : $(CLIENT_DIR)/ui_controls.c + $(DO_CC) + +$(BUILDDIR)/client/ui_demo.o : $(CLIENT_DIR)/ui_demo.c + $(DO_CC) + +$(BUILDDIR)/client/ui_maps.o : $(CLIENT_DIR)/ui_maps.c + $(DO_CC) + +$(BUILDDIR)/client/ui_menu.o : $(CLIENT_DIR)/ui_menu.c + $(DO_CC) + +$(BUILDDIR)/client/ui_network.o : $(CLIENT_DIR)/ui_network.c + $(DO_CC) + +$(BUILDDIR)/client/ui_preferences.o : $(CLIENT_DIR)/ui_preferences.c + $(DO_CC) + +$(BUILDDIR)/client/ui_qmenu.o : $(CLIENT_DIR)/ui_qmenu.c + $(DO_CC) + +$(BUILDDIR)/client/ui_servers.o : $(CLIENT_DIR)/ui_servers.c + $(DO_CC) + +$(BUILDDIR)/client/ui_startserver.o : $(CLIENT_DIR)/ui_startserver.c + $(DO_CC) + +$(BUILDDIR)/client/ui_video.o : $(UNIX_DIR)/ui_video.c + $(DO_CC) + +$(BUILDDIR)/client/cm_trace.o : $(COMMON_DIR)/cm_trace.c + $(DO_CC) + +$(BUILDDIR)/client/cm_load.o : $(COMMON_DIR)/cm_load.c + $(DO_CC) + +$(BUILDDIR)/client/cm_test.o : $(COMMON_DIR)/cm_test.c + $(DO_CC) + +$(BUILDDIR)/client/cm_patch.o : $(COMMON_DIR)/cm_patch.c + $(DO_CC) + +$(BUILDDIR)/client/cm_polylib.o : $(COMMON_DIR)/cm_polylib.c + $(DO_CC) + +$(BUILDDIR)/client/cm_tag.o : $(COMMON_DIR)/cm_tag.c + $(DO_CC) + +$(BUILDDIR)/client/cmd.o : $(COMMON_DIR)/cmd.c + $(DO_CC) + +$(BUILDDIR)/client/common.o : $(COMMON_DIR)/common.c + $(DO_CC) + +$(BUILDDIR)/client/cvar.o : $(COMMON_DIR)/cvar.c + $(DO_CC) + +$(BUILDDIR)/client/files.o : $(COMMON_DIR)/files.c + $(DO_CC) + +$(BUILDDIR)/client/gameinfo.o : $(COMMON_DIR)/gameinfo.c + $(DO_CC) + +$(BUILDDIR)/client/md4.o : $(COMMON_DIR)/md4.c + $(DO_CC) + +$(BUILDDIR)/client/msg.o : $(COMMON_DIR)/msg.c + $(DO_CC) + +$(BUILDDIR)/client/net_chan.o : $(COMMON_DIR)/net_chan.c + $(DO_CC) + +$(BUILDDIR)/client/vm.o : $(COMMON_DIR)/vm.c + $(DO_CC) + +$(BUILDDIR)/client/q_shared.o : $(GAME_DIR)/q_shared.c + $(DO_DEBUG_CC) + +$(BUILDDIR)/client/q_math.o : $(GAME_DIR)/q_math.c + $(DO_CC) + +$(BUILDDIR)/client/tr_bsp.o : $(REF_DIR)/tr_bsp.c + $(DO_CC) + +$(BUILDDIR)/client/tr_backend.o : $(REF_DIR)/tr_backend.c + $(DO_CC) + +$(BUILDDIR)/client/tr_calc.o : $(REF_DIR)/tr_calc.c + $(DO_CC) + +$(BUILDDIR)/client/tr_calc_3dnow.o : $(REF_DIR)/tr_calc_3dnow.c + $(DO_CC) + +$(BUILDDIR)/client/tr_calc_c.o : $(REF_DIR)/tr_calc_c.c + $(DO_CC) + +$(BUILDDIR)/client/tr_calc_kni.o : $(REF_DIR)/tr_calc_kni.c + $(DO_CC) + +$(BUILDDIR)/client/tr_cmds.o : $(REF_DIR)/tr_cmds.c + $(DO_CC) + +$(BUILDDIR)/client/tr_curve.o : $(REF_DIR)/tr_curve.c + $(DO_CC) + +$(BUILDDIR)/client/tr_draw.o : $(REF_DIR)/tr_draw.c + $(DO_CC) + +$(BUILDDIR)/client/tr_flares.o : $(REF_DIR)/tr_flares.c + $(DO_CC) + +$(BUILDDIR)/client/tr_image.o : $(REF_DIR)/tr_image.c + $(DO_CC) + +$(BUILDDIR)/client/tr_init.o : $(REF_DIR)/tr_init.c + $(DO_CC) + +$(BUILDDIR)/client/tr_light.o : $(REF_DIR)/tr_light.c + $(DO_CC) + +$(BUILDDIR)/client/tr_main.o : $(REF_DIR)/tr_main.c + $(DO_CC) + +$(BUILDDIR)/client/tr_mesh.o : $(REF_DIR)/tr_mesh.c + $(DO_CC) + +$(BUILDDIR)/client/tr_misc.o : $(REF_DIR)/tr_misc.c + $(DO_CC) + +$(BUILDDIR)/client/tr_model.o : $(REF_DIR)/tr_model.c + $(DO_CC) + +$(BUILDDIR)/client/tr_noise.o : $(REF_DIR)/tr_noise.c + $(DO_CC) + +$(BUILDDIR)/client/tr_scene.o : $(REF_DIR)/tr_scene.c + $(DO_CC) + +$(BUILDDIR)/client/tr_shade.o : $(REF_DIR)/tr_shade.c + $(DO_CC) + +$(BUILDDIR)/client/tr_shader.o : $(REF_DIR)/tr_shader.c + $(DO_CC) + +$(BUILDDIR)/client/tr_shade_calc.o : $(REF_DIR)/tr_shade_calc.c + $(DO_CC) + +$(BUILDDIR)/client/tr_shadows.o : $(REF_DIR)/tr_shadows.c + $(DO_CC) + +$(BUILDDIR)/client/tr_sky.o : $(REF_DIR)/tr_sky.c + $(DO_CC) + +$(BUILDDIR)/client/tr_smp.o : $(REF_DIR)/tr_smp.c + $(DO_CC) + +$(BUILDDIR)/client/tr_stripify.o : $(REF_DIR)/tr_stripify.c + $(DO_CC) + +$(BUILDDIR)/client/tr_subdivide.o : $(REF_DIR)/tr_subdivide.c + $(DO_CC) + +$(BUILDDIR)/client/tr_surf.o : $(REF_DIR)/tr_surf.c + $(DO_CC) + +$(BUILDDIR)/client/tr_world.o : $(REF_DIR)/tr_world.c + $(DO_CC) + +$(BUILDDIR)/client/unix_qgl.o : $(UNIX_DIR)/unix_qgl.c + $(DO_CC) + +$(BUILDDIR)/client/unix_dedicated.o : $(UNIX_DIR)/unix_dedicated.c + $(DO_CC) + +$(BUILDDIR)/client/unix_earlycon.o : $(UNIX_DIR)/unix_earlycon.c + $(DO_CC) + +$(BUILDDIR)/client/unix_main.o : $(UNIX_DIR)/unix_main.c + $(DO_CC) + +$(BUILDDIR)/client/unix_net.o : $(UNIX_DIR)/unix_net.c + $(DO_CC) + +$(BUILDDIR)/client/unix_shared.o : $(UNIX_DIR)/unix_shared.c + $(DO_CC) + +$(BUILDDIR)/client/irix_glimp.o : $(UNIX_DIR)/irix_glimp.c + $(DO_CC) + +$(BUILDDIR)/client/irix_snd.o : $(UNIX_DIR)/irix_snd.c + $(DO_CC) + +$(BUILDDIR)/client/irix_input.o : $(UNIX_DIR)/irix_input.c + $(DO_CC) + +$(BUILDDIR)/client/linux_glimp.o : $(UNIX_DIR)/linux_glimp.c + $(DO_CC) + +$(BUILDDIR)/client/linux_qgl.o : $(UNIX_DIR)/linux_qgl.c + $(DO_CC) + +$(BUILDDIR)/client/linux_input.o : $(UNIX_DIR)/linux_input.c + $(DO_CC) + +$(BUILDDIR)/client/linux_glimp_vga.o : $(UNIX_DIR)/linux_glimp_vga.c + $(DO_CC) + +$(BUILDDIR)/client/linux_snd.o : $(UNIX_DIR)/linux_snd.c + $(DO_CC) + +$(BUILDDIR)/client/snd_mixa.o : $(UNIX_DIR)/snd_mixa.s + $(DO_AS) + +$(BUILDDIR)/client/matha.o : $(UNIX_DIR)/matha.s + $(DO_AS) + +$(BUILDDIR)/client/sys_dosa.o : $(UNIX_DIR)/sys_dosa.s + $(DO_AS) + +$(BUILDDIR)/client/linux_input_vga.o : $(UNIX_DIR)/linux_input_vga.c + $(DO_CC) + +############################################################################# +# DEDICATED SERVER +############################################################################# + +Q3DED_OBJS = \ + $(BUILDDIR)/ded/sv_bot.o \ + $(BUILDDIR)/ded/sv_client.o \ + $(BUILDDIR)/ded/sv_ccmds.o \ + $(BUILDDIR)/ded/sv_game.o \ + $(BUILDDIR)/ded/sv_init.o \ + $(BUILDDIR)/ded/sv_main.o \ + $(BUILDDIR)/ded/sv_snapshot.o \ + $(BUILDDIR)/ded/sv_world.o \ + \ + $(BUILDDIR)/ded/cm_trace.o \ + $(BUILDDIR)/ded/cm_load.o \ + $(BUILDDIR)/ded/cm_test.o \ + $(BUILDDIR)/ded/cm_patch.o \ + $(BUILDDIR)/ded/cm_tag.o \ + $(BUILDDIR)/ded/cmd.o \ + $(BUILDDIR)/ded/common.o \ + $(BUILDDIR)/ded/cvar.o \ + $(BUILDDIR)/ded/files.o \ + $(BUILDDIR)/ded/gameinfo.o \ + $(BUILDDIR)/ded/md4.o \ + $(BUILDDIR)/ded/msg.o \ + $(BUILDDIR)/ded/net_chan.o \ + \ + $(BUILDDIR)/ded/unix_dedicated.o \ + $(BUILDDIR)/ded/unix_main.o \ + $(BUILDDIR)/ded/unix_net.o \ + $(BUILDDIR)/ded/unix_shared.o \ + \ + $(BUILDDIR)/ded/cl_null.o + +$(BUILDDIR)/linuxq3ded : $(Q3DED_OBJS) + $(CC) $(CFLAGS) -o $@ $(Q3DED_OBJS) $(LDFLAGS) + +$(BUILDDIR)/ded/sv_bot.o : $(SERVER_DIR)/sv_bot.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/sv_client.o : $(SERVER_DIR)/sv_client.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/sv_ccmds.o : $(SERVER_DIR)/sv_ccmds.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/sv_game.o : $(SERVER_DIR)/sv_game.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/sv_init.o : $(SERVER_DIR)/sv_init.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/sv_main.o : $(SERVER_DIR)/sv_main.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/sv_snapshot.o : $(SERVER_DIR)/sv_snapshot.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/sv_world.o : $(SERVER_DIR)/sv_world.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/cm_trace.o : $(COMMON_DIR)/cm_trace.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/cm_load.o : $(COMMON_DIR)/cm_load.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/cm_test.o : $(COMMON_DIR)/cm_test.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/cm_patch.o : $(COMMON_DIR)/cm_patch.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/cm_tag.o : $(COMMON_DIR)/cm_tag.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/cmd.o : $(COMMON_DIR)/cmd.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/common.o : $(COMMON_DIR)/common.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/cvar.o : $(COMMON_DIR)/cvar.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/files.o : $(COMMON_DIR)/files.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/gameinfo.o : $(COMMON_DIR)/gameinfo.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/md4.o : $(COMMON_DIR)/md4.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/msg.o : $(COMMON_DIR)/msg.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/net_chan.o : $(COMMON_DIR)/net_chan.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/unix_dedicated.o : $(UNIX_DIR)/unix_dedicated.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/unix_main.o : $(UNIX_DIR)/unix_main.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/unix_net.o : $(UNIX_DIR)/unix_net.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/unix_shared.o : $(UNIX_DIR)/unix_shared.c + $(DO_DED_CC) + +$(BUILDDIR)/ded/cl_null.o : $(NULL_DIR)/cl_null.c + $(DO_DED_CC) + +############################################################################# +# GAME +############################################################################# + +GAME_OBJS = \ + $(BUILDDIR)/game/b_ai.o \ + $(BUILDDIR)/game/b_files.o \ + $(BUILDDIR)/game/b_items.o \ + $(BUILDDIR)/game/b_main.o \ + $(BUILDDIR)/game/b_nav.o \ + $(BUILDDIR)/game/b_navgen.o \ + $(BUILDDIR)/game/bg_misc.o \ + $(BUILDDIR)/game/bg_pmove.o \ + $(BUILDDIR)/game/g_active.o \ + $(BUILDDIR)/game/g_aim.o \ + $(BUILDDIR)/game/g_client.o \ + $(BUILDDIR)/game/g_cmds.o \ + $(BUILDDIR)/game/g_combat.o \ + $(BUILDDIR)/game/g_items.o \ + $(BUILDDIR)/game/g_main.o \ + $(BUILDDIR)/game/g_mem.o \ + $(BUILDDIR)/game/g_misc.o \ + $(BUILDDIR)/game/g_missile.o \ + $(BUILDDIR)/game/g_mover.o \ + $(BUILDDIR)/game/g_spawn.o \ + $(BUILDDIR)/game/g_svcmds.o \ + $(BUILDDIR)/game/g_target.o \ + $(BUILDDIR)/game/g_team.o \ + $(BUILDDIR)/game/g_trigger.o \ + $(BUILDDIR)/game/g_utils.o \ + $(BUILDDIR)/game/g_weapon.o \ + $(BUILDDIR)/game/q_shared.o \ + $(BUILDDIR)/game/q_math.o + +$(BUILDDIR)/qagame$(ARCH).$(SHLIBEXT) : $(GAME_OBJS) + $(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GAME_OBJS) + +$(BUILDDIR)/game/b_ai.o : $(GAME_DIR)/b_ai.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/b_files.o : $(GAME_DIR)/b_files.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/b_items.o : $(GAME_DIR)/b_items.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/b_main.o : $(GAME_DIR)/b_main.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/b_nav.o : $(GAME_DIR)/b_nav.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/b_navgen.o : $(GAME_DIR)/b_navgen.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/bg_misc.o : $(GAME_DIR)/bg_misc.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/bg_pmove.o : $(GAME_DIR)/bg_pmove.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_active.o : $(GAME_DIR)/g_active.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_aim.o : $(GAME_DIR)/g_aim.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_client.o : $(GAME_DIR)/g_client.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_cmds.o : $(GAME_DIR)/g_cmds.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_combat.o : $(GAME_DIR)/g_combat.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_items.o : $(GAME_DIR)/g_items.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_main.o : $(GAME_DIR)/g_main.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_mem.o : $(GAME_DIR)/g_mem.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_misc.o : $(GAME_DIR)/g_misc.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_missile.o : $(GAME_DIR)/g_missile.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_mover.o : $(GAME_DIR)/g_mover.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_spawn.o : $(GAME_DIR)/g_spawn.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_svcmds.o : $(GAME_DIR)/g_svcmds.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_target.o : $(GAME_DIR)/g_target.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_team.o : $(GAME_DIR)/g_team.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_trigger.o : $(GAME_DIR)/g_trigger.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_utils.o : $(GAME_DIR)/g_utils.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/g_weapon.o : $(GAME_DIR)/g_weapon.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/game/q_shared.o : $(GAME_DIR)/q_shared.c + $(DO_SHLIB_DEBUG_CC) + +$(BUILDDIR)/game/q_math.o : $(GAME_DIR)/q_math.c + $(DO_SHLIB_CC) + +############################################################################# +# CGAME +############################################################################# + +CGAME_OBJS = \ + $(BUILDDIR)/cgame/bg_misc.o \ + $(BUILDDIR)/cgame/bg_pmove.o \ + $(BUILDDIR)/cgame/cg_draw.o \ + $(BUILDDIR)/cgame/cg_effects.o \ + $(BUILDDIR)/cgame/cg_ents.o \ + $(BUILDDIR)/cgame/cg_event.o \ + $(BUILDDIR)/cgame/cg_info.o \ + $(BUILDDIR)/cgame/cg_localents.o \ + $(BUILDDIR)/cgame/cg_main.o \ + $(BUILDDIR)/cgame/cg_marks.o \ + $(BUILDDIR)/cgame/cg_menu.o \ + $(BUILDDIR)/cgame/cg_players.o \ + $(BUILDDIR)/cgame/cg_predict.o \ + $(BUILDDIR)/cgame/cg_scoreboard.o \ + $(BUILDDIR)/cgame/cg_snapshot.o \ + $(BUILDDIR)/cgame/cg_view.o \ + $(BUILDDIR)/cgame/cg_weapons.o \ + $(BUILDDIR)/cgame/q_shared.o \ + $(BUILDDIR)/cgame/q_math.o + +$(BUILDDIR)/cgame$(ARCH).$(SHLIBEXT) : $(CGAME_OBJS) + $(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(CGAME_OBJS) + +$(BUILDDIR)/cgame/bg_misc.o : $(GAME_DIR)/bg_misc.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/bg_pmove.o : $(GAME_DIR)/bg_pmove.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_draw.o : $(CGAME_DIR)/cg_draw.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_effects.o : $(CGAME_DIR)/cg_effects.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_ents.o : $(CGAME_DIR)/cg_ents.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_event.o : $(CGAME_DIR)/cg_event.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_info.o : $(CGAME_DIR)/cg_info.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_localents.o : $(CGAME_DIR)/cg_localents.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_main.o : $(CGAME_DIR)/cg_main.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_marks.o : $(CGAME_DIR)/cg_marks.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_menu.o : $(CGAME_DIR)/cg_menu.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_players.o : $(CGAME_DIR)/cg_players.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_predict.o : $(CGAME_DIR)/cg_predict.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_scoreboard.o : $(CGAME_DIR)/cg_scoreboard.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_snapshot.o : $(CGAME_DIR)/cg_snapshot.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_view.o : $(CGAME_DIR)/cg_view.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/cg_weapons.o : $(CGAME_DIR)/cg_weapons.c + $(DO_SHLIB_CC) + +$(BUILDDIR)/cgame/q_shared.o : $(GAME_DIR)/q_shared.c + $(DO_SHLIB_DEBUG_CC) + +$(BUILDDIR)/cgame/q_math.o : $(GAME_DIR)/q_math.c + $(DO_SHLIB_CC) + + +############################################################################# +# RPM +############################################################################# + +###### DISABLED + +TMPDIR=/var/tmp +TARDIR=$(TMPDIR)/q3test +TARFILE = q3test-$(VERSION_FN)-$(RPM_RELEASE).$(ARCH).tar + +tar: + if [ ! -d archives ];then mkdir archives;chmod 755 archives;fi + $(MAKE) copyfiles COPYDIR=$(TARDIR) + cd $(TARDIR)/..; tar cvf $(TARFILE) q3test && gzip -9 $(TARFILE) + mv $(TARDIR)/../$(TARFILE).gz archives/. + chmod 644 archives/$(TARFILE).gz + rm -rf $(TARDIR) + +# Make RPMs. You need to be root to make this work +RPMROOT=/usr/src/redhat +RPM = rpm +RPMFLAGS = -bb +INSTALLDIR = /usr/local/games/q3test +RPMDIR = $(TMPDIR)/q3test-$(VERSION_FN) +DESTDIR= $(RPMDIR)/$(INSTALLDIR) + +rpm: q3test.spec + touch $(RPMROOT)/SOURCES/q3test-$(VERSION_FN).tar.gz + if [ ! -d archives ];then mkdir archives;fi + $(MAKE) copyfiles COPYDIR=$(DESTDIR) + cp $(UNIX_DIR)/quake3.gif $(RPMROOT)/SOURCES/. + cp q3test.spec $(RPMROOT)/SPECS/. + cd $(RPMROOT)/SPECS; $(RPM) $(RPMFLAGS) q3test.spec + rm -rf $(RPMDIR) + mv $(RPMROOT)/RPMS/$(RPMARCH)/q3test-$(VERSION_FN)-$(RPM_RELEASE).$(RPMARCH).rpm archives/q3test-$(VERSION_FN)-$(RPM_RELEASE).$(RPMARCH).rpm + chmod 644 archives/q3test-$(VERSION_FN)-$(RPM_RELEASE).$(RPMARCH).rpm + +copyfiles: + -mkdirhier $(COPYDIR) + cp $(BUILD_RELEASE_DIR)/linuxquake3 $(COPYDIR) + strip $(COPYDIR)/linuxquake3 + chmod 755 $(COPYDIR)/linuxquake3 + cp $(BUILD_RELEASE_DIR)/qagame$(ARCH).$(SHLIBEXT) $(COPYDIR) + chmod 755 $(COPYDIR)/qagame$(ARCH).$(SHLIBEXT) + cp $(BUILD_RELEASE_DIR)/cgame$(ARCH).$(SHLIBEXT) $(COPYDIR) + chmod 755 $(COPYDIR)/cgame$(ARCH).$(SHLIBEXT) + cp $(BUILD_DIR)/libMesaVoodooGL.so.3.1 $(COPYDIR)/. + chmod 755 $(COPYDIR)/libMesaVoodooGL.so.3.1 + -mkdir $(COPYDIR)/demoq3 + chmod 1777 $(COPYDIR)/demoq3 + cp $(DEMO_PAK) $(COPYDIR)/demoq3/pak0.pk3 + cp $(UNIX_DIR)/README.EULA $(COPYDIR) + chmod 644 $(COPYDIR)/README.EULA + cp $(UNIX_DIR)/README.Q3Test $(COPYDIR) + chmod 644 $(COPYDIR)/README.Q3Test + +q3test.spec : $(UNIX_DIR)/q3test.spec.sh Makefile + sh $< $(VERSION_FN) $(RPM_RELEASE) $(ARCH) $(INSTALLDIR) > $@ + +############################################################################# +# MISC +############################################################################# + +clean: clean-debug clean-release + +clean-debug: + $(MAKE) clean2 BUILDDIR=$(BUILD_DEBUG_DIR) CFLAGS="$(DEBUG_CFLAGS)" + +clean-release: + $(MAKE) clean2 BUILDDIR=$(BUILD_RELEASE_DIR) CFLAGS="$(DEBUG_CFLAGS)" + diff --git a/code/unix/linux_glimp.c b/code/unix/linux_glimp.c new file mode 100644 index 0000000..8bfe671 --- /dev/null +++ b/code/unix/linux_glimp.c @@ -0,0 +1,1387 @@ +/* +** GLW_IMP.C +** +** This file contains ALL Linux specific stuff having to do with the +** OpenGL refresh. When a port is being made the following functions +** must be implemented by the port: +** +** GLimp_EndFrame +** GLimp_Init +** GLimp_Shutdown +** GLimp_SwitchFullscreen +** +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include "../qcommon/qcommon.h" +//#include "../client/keys.h" +#include "../renderer/tr_local.h" +#include "../client/client.h" + +#include "unix_glw.h" + +#include + +#include +#include + +#include +#include + +typedef enum { + RSERR_OK, + + RSERR_INVALID_FULLSCREEN, + RSERR_INVALID_MODE, + + RSERR_UNKNOWN +} rserr_t; + +glwstate_t glw_state; + +static Display *dpy = NULL; +static int scrnum; +static Window win = 0; +static GLXContext ctx = NULL; + +static qboolean autorepeaton = qtrue; + +#define KEY_MASK (KeyPressMask | KeyReleaseMask) +#define MOUSE_MASK (ButtonPressMask | ButtonReleaseMask | \ + PointerMotionMask | ButtonMotionMask ) +#define X_MASK (KEY_MASK | MOUSE_MASK | VisibilityChangeMask | StructureNotifyMask ) + +static qboolean mouse_avail; +static qboolean mouse_active; +static int mx, my; + +static cvar_t *in_mouse; +static cvar_t *in_dgamouse; + +static cvar_t *r_fakeFullscreen; + +qboolean dgamouse = qfalse; +qboolean vidmode_ext = qfalse; + +static int win_x, win_y; + +static XF86VidModeModeInfo **vidmodes; +static int default_dotclock_vidmode; +static int num_vidmodes; +static qboolean vidmode_active = qfalse; + +static int mouse_accel_numerator; +static int mouse_accel_denominator; +static int mouse_threshold; + +/*****************************************************************************/ +/* KEYBOARD */ +/*****************************************************************************/ + +static unsigned int keyshift[256]; // key to map to if shift held down in console +static qboolean shift_down=qfalse; + +static char *XLateKey(XKeyEvent *ev, int *key) +{ + static char buf[64]; + KeySym keysym; + static qboolean setup = qfalse; + int i; + + *key = 0; + + XLookupString(ev, buf, sizeof buf, &keysym, 0); + +// ri.Printf( PRINT_ALL, "keysym=%04X\n", (int)keysym); + switch(keysym) + { + case XK_KP_Page_Up: + case XK_KP_9: *key = K_KP_PGUP; break; + case XK_Page_Up: *key = K_PGUP; break; + + case XK_KP_Page_Down: + case XK_KP_3: *key = K_KP_PGDN; break; + case XK_Page_Down: *key = K_PGDN; break; + + case XK_KP_Home: *key = K_KP_HOME; break; + case XK_KP_7: *key = K_KP_HOME; break; + case XK_Home: *key = K_HOME; break; + + case XK_KP_End: + case XK_KP_1: *key = K_KP_END; break; + case XK_End: *key = K_END; break; + + case XK_KP_Left: *key = K_KP_LEFTARROW; break; + case XK_KP_4: *key = K_KP_LEFTARROW; break; + case XK_Left: *key = K_LEFTARROW; break; + + case XK_KP_Right: *key = K_KP_RIGHTARROW; break; + case XK_KP_6: *key = K_KP_RIGHTARROW; break; + case XK_Right: *key = K_RIGHTARROW; break; + + case XK_KP_Down: + case XK_KP_2: *key = K_KP_DOWNARROW; break; + case XK_Down: *key = K_DOWNARROW; break; + + case XK_KP_Up: + case XK_KP_8: *key = K_KP_UPARROW; break; + case XK_Up: *key = K_UPARROW; break; + + case XK_Escape: *key = K_ESCAPE; break; + + case XK_KP_Enter: *key = K_KP_ENTER; break; + case XK_Return: *key = K_ENTER; break; + + case XK_Tab: *key = K_TAB; break; + + case XK_F1: *key = K_F1; break; + + case XK_F2: *key = K_F2; break; + + case XK_F3: *key = K_F3; break; + + case XK_F4: *key = K_F4; break; + + case XK_F5: *key = K_F5; break; + + case XK_F6: *key = K_F6; break; + + case XK_F7: *key = K_F7; break; + + case XK_F8: *key = K_F8; break; + + case XK_F9: *key = K_F9; break; + + case XK_F10: *key = K_F10; break; + + case XK_F11: *key = K_F11; break; + + case XK_F12: *key = K_F12; break; + +// case XK_BackSpace: *key = K_BACKSPACE; break; + case XK_BackSpace: *key = 8; break; // ctrl-h + + case XK_KP_Delete: + case XK_KP_Decimal: *key = K_KP_DEL; break; + case XK_Delete: *key = K_DEL; break; + + case XK_Pause: *key = K_PAUSE; break; + + case XK_Shift_L: + case XK_Shift_R: *key = K_SHIFT; break; + + case XK_Execute: + case XK_Control_L: + case XK_Control_R: *key = K_CTRL; break; + + case XK_Alt_L: + case XK_Meta_L: + case XK_Alt_R: + case XK_Meta_R: *key = K_ALT; break; + + case XK_KP_Begin: *key = K_KP_5; break; + + case XK_Insert: *key = K_INS; break; + case XK_KP_Insert: + case XK_KP_0: *key = K_KP_INS; break; + + case XK_KP_Multiply: *key = '*'; break; + case XK_KP_Add: *key = K_KP_PLUS; break; + case XK_KP_Subtract: *key = K_KP_MINUS; break; + case XK_KP_Divide: *key = K_KP_SLASH; break; + + default: + *key = *(unsigned char *)buf; + if (*key >= 'A' && *key <= 'Z') + *key = *key - 'A' + 'a'; + break; + } + + return buf; +} + +// ======================================================================== +// makes a null cursor +// ======================================================================== + +static Cursor CreateNullCursor(Display *display, Window root) +{ + Pixmap cursormask; + XGCValues xgc; + GC gc; + XColor dummycolour; + Cursor cursor; + + cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/); + xgc.function = GXclear; + gc = XCreateGC(display, cursormask, GCFunction, &xgc); + XFillRectangle(display, cursormask, gc, 0, 0, 1, 1); + dummycolour.pixel = 0; + dummycolour.red = 0; + dummycolour.flags = 04; + cursor = XCreatePixmapCursor(display, cursormask, cursormask, + &dummycolour,&dummycolour, 0,0); + XFreePixmap(display,cursormask); + XFreeGC(display,gc); + return cursor; +} + +static void install_grabs(void) +{ +// inviso cursor + XDefineCursor(dpy, win, CreateNullCursor(dpy, win)); + + XGrabPointer(dpy, win, + False, + MOUSE_MASK, + GrabModeAsync, GrabModeAsync, + win, + None, + CurrentTime); + + XGetPointerControl(dpy, &mouse_accel_numerator, &mouse_accel_denominator, + &mouse_threshold); + + XChangePointerControl(dpy, qtrue, qtrue, 2, 1, 0); + + if (in_dgamouse->value) { + int MajorVersion, MinorVersion; + + if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) { + // unable to query, probalby not supported + ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" ); + ri.Cvar_Set( "in_dgamouse", "0" ); + } else { + dgamouse = qtrue; + XF86DGADirectVideo(dpy, DefaultScreen(dpy), XF86DGADirectMouse); + XWarpPointer(dpy, None, win, 0, 0, 0, 0, 0, 0); + } + } else { + XWarpPointer(dpy, None, win, + 0, 0, 0, 0, + glConfig.vidWidth / 2, glConfig.vidHeight / 2); + } + + XGrabKeyboard(dpy, win, + False, + GrabModeAsync, GrabModeAsync, + CurrentTime); + +// XSync(dpy, True); +} + +static void uninstall_grabs(void) +{ + if (dgamouse) { + dgamouse = qfalse; + XF86DGADirectVideo(dpy, DefaultScreen(dpy), 0); + } + + XChangePointerControl(dpy, qtrue, qtrue, mouse_accel_numerator, + mouse_accel_denominator, mouse_threshold); + + XUngrabPointer(dpy, CurrentTime); + XUngrabKeyboard(dpy, CurrentTime); + +// inviso cursor + XUndefineCursor(dpy, win); + +// XAutoRepeatOn(dpy); + +// XSync(dpy, True); +} + +static void HandleEvents(void) +{ + int b; + int key; + XEvent event; + qboolean dowarp = qfalse; + int mwx = glConfig.vidWidth/2; + int mwy = glConfig.vidHeight/2; + char *p; + + if (!dpy) + return; + + while (XPending(dpy)) { + XNextEvent(dpy, &event); + switch(event.type) { + case KeyPress: + p = XLateKey(&event.xkey, &key); + if (key) + Sys_QueEvent( 0, SE_KEY, key, qtrue, 0, NULL ); + while (*p) + Sys_QueEvent( 0, SE_CHAR, *p++, 0, 0, NULL ); + break; + case KeyRelease: + XLateKey(&event.xkey, &key); + + Sys_QueEvent( 0, SE_KEY, key, qfalse, 0, NULL ); + break; + +#if 0 + case KeyPress: + case KeyRelease: + key = XLateKey(&event.xkey); + + Sys_QueEvent( 0, SE_KEY, key, event.type == KeyPress, 0, NULL ); + if (key == K_SHIFT) + shift_down = (event.type == KeyPress); + if (key < 128 && (event.type == KeyPress)) { + if (shift_down) + key = keyshift[key]; + Sys_QueEvent( 0, SE_CHAR, key, 0, 0, NULL ); + } +#endif + break; + + case MotionNotify: + if (mouse_active) { + if (dgamouse) { + if (abs(event.xmotion.x_root) > 1) + mx += event.xmotion.x_root * 2; + else + mx += event.xmotion.x_root; + if (abs(event.xmotion.y_root) > 1) + my += event.xmotion.y_root * 2; + else + my += event.xmotion.y_root; +// ri.Printf(PRINT_ALL, "mouse (%d,%d) (root=%d,%d)\n", event.xmotion.x + win_x, event.xmotion.y + win_y, event.xmotion.x_root, event.xmotion.y_root); + } + else + { +// ri.Printf(PRINT_ALL, "mouse x=%d,y=%d\n", (int)event.xmotion.x - mwx, (int)event.xmotion.y - mwy); + mx += ((int)event.xmotion.x - mwx); + my += ((int)event.xmotion.y - mwy); + mwx = event.xmotion.x; + mwy = event.xmotion.y; + + if (mx || my) + dowarp = qtrue; + } + } + break; + + case ButtonPress: + b=-1; + if (event.xbutton.button == 1) + b = 0; + else if (event.xbutton.button == 2) + b = 2; + else if (event.xbutton.button == 3) + b = 1; + Sys_QueEvent( 0, SE_KEY, K_MOUSE1 + b, qtrue, 0, NULL ); + break; + + case ButtonRelease: + b=-1; + if (event.xbutton.button == 1) + b = 0; + else if (event.xbutton.button == 2) + b = 2; + else if (event.xbutton.button == 3) + b = 1; + Sys_QueEvent( 0, SE_KEY, K_MOUSE1 + b, qfalse, 0, NULL ); + break; + + case CreateNotify : + win_x = event.xcreatewindow.x; + win_y = event.xcreatewindow.y; + break; + + case ConfigureNotify : + win_x = event.xconfigure.x; + win_y = event.xconfigure.y; + break; + } + } + + if (dowarp) { + /* move the mouse to the window center again */ + XWarpPointer(dpy,None,win,0,0,0,0, + (glConfig.vidWidth/2),(glConfig.vidHeight/2)); + } + +} + +void KBD_Init(void) +{ +} + +void KBD_Close(void) +{ +} + +void IN_ActivateMouse( void ) +{ + if (!mouse_avail || !dpy || !win) + return; + + if (!mouse_active) { + mx = my = 0; // don't spazz + install_grabs(); + mouse_active = qtrue; + } +} + +void IN_DeactivateMouse( void ) +{ + if (!mouse_avail || !dpy || !win) + return; + + if (mouse_active) { + uninstall_grabs(); + mouse_active = qfalse; + } +} +/*****************************************************************************/ + +static qboolean signalcaught = qfalse;; + +static void signal_handler(int sig) +{ + if (signalcaught) { + printf("DOUBLE SIGNAL FAULT: Received signal %d, exiting...\n", sig); + _exit(1); + } + + signalcaught = qtrue; + printf("Received signal %d, exiting...\n", sig); + GLimp_Shutdown(); + _exit(1); +} + +static void InitSig(void) +{ + signal(SIGHUP, signal_handler); + signal(SIGQUIT, signal_handler); + signal(SIGILL, signal_handler); + signal(SIGTRAP, signal_handler); + signal(SIGIOT, signal_handler); + signal(SIGBUS, signal_handler); + signal(SIGFPE, signal_handler); + signal(SIGSEGV, signal_handler); + signal(SIGTERM, signal_handler); +} + +/* +** GLimp_SetGamma +** +** This routine should only be called if glConfig.deviceSupportsGamma is TRUE +*/ +void GLimp_SetGamma( unsigned char red[256], unsigned char green[256], unsigned char blue[256] ) +{ +} + +/* +** GLimp_Shutdown +** +** This routine does all OS specific shutdown procedures for the OpenGL +** subsystem. Under OpenGL this means NULLing out the current DC and +** HGLRC, deleting the rendering context, and releasing the DC acquired +** for the window. The state structure is also nulled out. +** +*/ +void GLimp_Shutdown( void ) +{ + if (!ctx || !dpy) + return; + IN_DeactivateMouse(); + XAutoRepeatOn(dpy); + if (dpy) { + if (ctx) + qglXDestroyContext(dpy, ctx); + if (win) + XDestroyWindow(dpy, win); + if (vidmode_active) + XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[0]); + XCloseDisplay(dpy); + } + vidmode_active = qfalse; + dpy = NULL; + win = 0; + ctx = NULL; + + memset( &glConfig, 0, sizeof( glConfig ) ); + memset( &glState, 0, sizeof( glState ) ); + + QGL_Shutdown(); +} + +/* +** GLimp_LogComment +*/ +void GLimp_LogComment( char *comment ) +{ + if ( glw_state.log_fp ) { + fprintf( glw_state.log_fp, "%s", comment ); + } +} + +/* +** GLW_StartDriverAndSetMode +*/ +static qboolean GLW_StartDriverAndSetMode( const char *drivername, + int mode, + qboolean fullscreen ) +{ + rserr_t err; + + // don't ever bother going into fullscreen with a voodoo card +#if 1 // JDC: I reenabled this + if ( strstr( drivername, "Voodoo" ) ) { + ri.Cvar_Set( "r_fullscreen", "0" ); + r_fullscreen->modified = qfalse; + fullscreen = qfalse; + } +#endif + + err = GLW_SetMode( drivername, mode, fullscreen ); + + switch ( err ) + { + case RSERR_INVALID_FULLSCREEN: + ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" ); + return qfalse; + case RSERR_INVALID_MODE: + ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode ); + return qfalse; + default: + break; + } + return qtrue; +} + +/* +** GLW_SetMode +*/ +int GLW_SetMode( const char *drivername, int mode, qboolean fullscreen ) +{ + int attrib[] = { + GLX_RGBA, // 0 + GLX_RED_SIZE, 4, // 1, 2 + GLX_GREEN_SIZE, 4, // 3, 4 + GLX_BLUE_SIZE, 4, // 5, 6 + GLX_DOUBLEBUFFER, // 7 + GLX_DEPTH_SIZE, 1, // 8, 9 + GLX_STENCIL_SIZE, 1, // 10, 11 + None + }; +// these match in the array +#define ATTR_RED_IDX 2 +#define ATTR_GREEN_IDX 4 +#define ATTR_BLUE_IDX 6 +#define ATTR_DEPTH_IDX 9 +#define ATTR_STENCIL_IDX 11 + Window root; + XVisualInfo *visinfo; + XSetWindowAttributes attr; + unsigned long mask; + int colorbits, depthbits, stencilbits; + int tcolorbits, tdepthbits, tstencilbits; + int MajorVersion, MinorVersion; + int actualWidth, actualHeight; + int i; + + r_fakeFullscreen = ri.Cvar_Get( "r_fakeFullscreen", "0", CVAR_ARCHIVE); + + ri.Printf( PRINT_ALL, "Initializing OpenGL display\n"); + + ri.Printf (PRINT_ALL, "...setting mode %d:", mode ); + + if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) ) + { + ri.Printf( PRINT_ALL, " invalid mode\n" ); + return RSERR_INVALID_MODE; + } + ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight); + + if (!(dpy = XOpenDisplay(NULL))) { + fprintf(stderr, "Error couldn't open the X display\n"); + return RSERR_INVALID_MODE; + } + + scrnum = DefaultScreen(dpy); + root = RootWindow(dpy, scrnum); + + actualWidth = glConfig.vidWidth; + actualHeight = glConfig.vidHeight; + + // Get video mode list + MajorVersion = MinorVersion = 0; + if (!XF86VidModeQueryVersion(dpy, &MajorVersion, &MinorVersion)) { + vidmode_ext = qfalse; + } else { + ri.Printf(PRINT_ALL, "Using XFree86-VidModeExtension Version %d.%d\n", + MajorVersion, MinorVersion); + vidmode_ext = qtrue; + } + + if (vidmode_ext) { + int best_fit, best_dist, dist, x, y; + + XF86VidModeGetAllModeLines(dpy, scrnum, &num_vidmodes, &vidmodes); + + // Are we going fullscreen? If so, let's change video mode + if (fullscreen && !r_fakeFullscreen->integer) { + best_dist = 9999999; + best_fit = -1; + + for (i = 0; i < num_vidmodes; i++) { + if (glConfig.vidWidth > vidmodes[i]->hdisplay || + glConfig.vidHeight > vidmodes[i]->vdisplay) + continue; + + x = glConfig.vidWidth - vidmodes[i]->hdisplay; + y = glConfig.vidHeight - vidmodes[i]->vdisplay; + dist = (x * x) + (y * y); + if (dist < best_dist) { + best_dist = dist; + best_fit = i; + } + } + + if (best_fit != -1) { + actualWidth = vidmodes[best_fit]->hdisplay; + actualHeight = vidmodes[best_fit]->vdisplay; + + // change to the mode + XF86VidModeSwitchToMode(dpy, scrnum, vidmodes[best_fit]); + vidmode_active = qtrue; + + // Move the viewport to top left + XF86VidModeSetViewPort(dpy, scrnum, 0, 0); + } else + fullscreen = 0; + } + } + + + if (!r_colorbits->value) + colorbits = 24; + else + colorbits = r_colorbits->value; + + if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) ) + colorbits = 16; + + if (!r_depthbits->value) + depthbits = 24; + else + depthbits = r_depthbits->value; + stencilbits = r_stencilbits->value; + + for (i = 0; i < 16; i++) { + // 0 - default + // 1 - minus colorbits + // 2 - minus depthbits + // 3 - minus stencil + if ((i % 4) == 0 && i) { + // one pass, reduce + switch (i / 4) { + case 2 : + if (colorbits == 24) + colorbits = 16; + break; + case 1 : + if (depthbits == 24) + depthbits = 16; + else if (depthbits == 16) + depthbits = 8; + case 3 : + if (stencilbits == 24) + stencilbits = 16; + else if (stencilbits == 16) + stencilbits = 8; + } + } + + tcolorbits = colorbits; + tdepthbits = depthbits; + tstencilbits = stencilbits; + + if ((i % 4) == 3) { // reduce colorbits + if (tcolorbits == 24) + tcolorbits = 16; + } + + if ((i % 4) == 2) { // reduce depthbits + if (tdepthbits == 24) + tdepthbits = 16; + else if (tdepthbits == 16) + tdepthbits = 8; + } + + if ((i % 4) == 1) { // reduce stencilbits + if (tstencilbits == 24) + tstencilbits = 16; + else if (tstencilbits == 16) + tstencilbits = 8; + else + tstencilbits = 0; + } + + if (tcolorbits == 24) { + attrib[ATTR_RED_IDX] = 8; + attrib[ATTR_GREEN_IDX] = 8; + attrib[ATTR_BLUE_IDX] = 8; + } else { + // must be 16 bit + attrib[ATTR_RED_IDX] = 4; + attrib[ATTR_GREEN_IDX] = 4; + attrib[ATTR_BLUE_IDX] = 4; + } + + attrib[ATTR_DEPTH_IDX] = tdepthbits; // default to 24 depth + attrib[ATTR_STENCIL_IDX] = tstencilbits; + +#if 0 + ri.Printf( PRINT_DEVELOPER, "Attempting %d/%d/%d Color bits, %d depth, %d stencil display...", + attrib[ATTR_RED_IDX], attrib[ATTR_GREEN_IDX], attrib[ATTR_BLUE_IDX], + attrib[ATTR_DEPTH_IDX], attrib[ATTR_STENCIL_IDX]); +#endif + + visinfo = qglXChooseVisual(dpy, scrnum, attrib); + if (!visinfo) { +#if 0 + ri.Printf( PRINT_DEVELOPER, "failed\n"); +#endif + continue; + } + +#if 0 + ri.Printf( PRINT_DEVELOPER, "Successful\n"); +#endif + + ri.Printf( PRINT_ALL, "Using %d/%d/%d Color bits, %d depth, %d stencil display.\n", + attrib[ATTR_RED_IDX], attrib[ATTR_GREEN_IDX], attrib[ATTR_BLUE_IDX], + attrib[ATTR_DEPTH_IDX], attrib[ATTR_STENCIL_IDX]); + + glConfig.colorBits = tcolorbits; + glConfig.depthBits = tdepthbits; + glConfig.stencilBits = tstencilbits; + break; + } + + if (!visinfo) { + ri.Printf( PRINT_ALL, "Couldn't get a visual\n" ); + return RSERR_INVALID_MODE; + } + + /* window attributes */ + attr.background_pixel = BlackPixel(dpy, scrnum); + attr.border_pixel = 0; + attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone); + attr.event_mask = X_MASK; + if (vidmode_active) { + mask = CWBackPixel | CWColormap | CWSaveUnder | CWBackingStore | + CWEventMask | CWOverrideRedirect; + attr.override_redirect = True; + attr.backing_store = NotUseful; + attr.save_under = False; + } else + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + win = XCreateWindow(dpy, root, 0, 0, + actualWidth, actualHeight, + 0, visinfo->depth, InputOutput, + visinfo->visual, mask, &attr); + XMapWindow(dpy, win); + + if (vidmode_active) + XMoveWindow(dpy, win, 0, 0); + + // Check for DGA + if (in_dgamouse->value) { + if (!XF86DGAQueryVersion(dpy, &MajorVersion, &MinorVersion)) { + // unable to query, probalby not supported + ri.Printf( PRINT_ALL, "Failed to detect XF86DGA Mouse\n" ); + ri.Cvar_Set( "in_dgamouse", "0" ); + } else + ri.Printf( PRINT_ALL, "XF86DGA Mouse (Version %d.%d) initialized\n", + MajorVersion, MinorVersion); + } + + XFlush(dpy); + + ctx = qglXCreateContext(dpy, visinfo, NULL, True); + + qglXMakeCurrent(dpy, win, ctx); + + return RSERR_OK; +} + +/* +** GLW_InitExtensions +*/ +static void GLW_InitExtensions( void ) +{ + // Use modern texture compression extensions + if ( strstr( glConfig.extensions_string, "ARB_texture_compression" ) && strstr( glConfig.extensions_string, "EXT_texture_compression_s3tc" ) ) + { + if ( r_ext_compressed_textures->value ) + { + glConfig.textureCompression = TC_S3TC_DXT; + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_compression_s3tc\n" ); + } + else + { + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_compression_s3tc\n" ); + } + } + // Or check for old ones + else if ( strstr( glConfig.extensions_string, "GL_S3_s3tc" ) ) + { + if ( r_ext_compressed_textures->value ) + { + glConfig.textureCompression = TC_S3TC; + ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" ); + } + else + { + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" ); + } + } + else + { + glConfig.textureCompression = TC_NONE; + ri.Printf( PRINT_ALL, "...no texture compression found\n" ); + } + +#if 0 + // WGL_EXT_swap_control + if ( strstr( glConfig.extensions_string, "WGL_EXT_swap_control" ) ) + { + qwglSwapIntervalEXT = ( BOOL (WINAPI *)(int)) qwglGetProcAddress( "wglSwapIntervalEXT" ); + ri.Printf( PRINT_ALL, "...using WGL_EXT_swap_control\n" ); + } + else + { + ri.Printf( PRINT_ALL, "...WGL_EXT_swap_control not found\n" ); + } +#endif + + // GL_ARB_multitexture + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + if ( strstr( glConfig.extensions_string, "GL_ARB_multitexture" ) ) + { + if ( r_ext_multitexture->value ) + { + qglMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC ) dlsym( glw_state.OpenGLLib, "glMultiTexCoord2fARB" ); + qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glActiveTextureARB" ); + qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC ) dlsym( glw_state.OpenGLLib, "glClientActiveTextureARB" ); + + if ( qglActiveTextureARB ) + { + ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); + } + else + { + ri.Printf( PRINT_ALL, "...blind search for ARB_multitexture failed\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); + } + + // GL_EXT_texture_filter_anisotropic + glConfig.textureFilterAnisotropicAvailable = qfalse; + if ( strstr( glConfig.extensions_string, "EXT_texture_filter_anisotropic" ) ) + { + glConfig.textureFilterAnisotropicAvailable = qtrue; + ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic available\n" ); + + if ( r_ext_texture_filter_anisotropic->integer ) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic\n" ); + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" ); + } + ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "1" ); + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" ); + ri.Cvar_Set( "r_ext_texture_filter_anisotropic_avail", "0" ); + } + + // GL_EXT_compiled_vertex_array + if ( strstr( glConfig.extensions_string, "GL_EXT_compiled_vertex_array" ) ) + { + if ( r_ext_compiled_vertex_array->value ) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" ); + qglLockArraysEXT = ( void ( APIENTRY * )( int, int ) ) dlsym( glw_state.OpenGLLib, "glLockArraysEXT" ); + qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) dlsym( glw_state.OpenGLLib, "glUnlockArraysEXT" ); + if (!qglLockArraysEXT || !qglUnlockArraysEXT) { + ri.Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); + } + +} + +/* +** GLW_LoadOpenGL +** +** GLimp_win.c internal function that that attempts to load and use +** a specific OpenGL DLL. +*/ +static qboolean GLW_LoadOpenGL( const char *name ) +{ + qboolean fullscreen; + + ri.Printf( PRINT_ALL, "...loading %s: ", name ); + + // disable the 3Dfx splash screen and set gamma + // we do this all the time, but it shouldn't hurt anything + // on non-3Dfx stuff + putenv("FX_GLIDE_NO_SPLASH=0"); + + // Mesa VooDoo hacks + putenv("MESA_GLX_FX=fullscreen\n"); + + // load the QGL layer + if ( QGL_Init( name ) ) + { + fullscreen = r_fullscreen->integer; + + // create the window and set up the context + if ( !GLW_StartDriverAndSetMode( name, r_mode->integer, fullscreen ) ) + { + if (r_mode->integer != 3) { + if ( !GLW_StartDriverAndSetMode( name, 3, fullscreen ) ) { + goto fail; + } + } else + goto fail; + } + + return qtrue; + } + else + { + ri.Printf( PRINT_ALL, "failed\n" ); + } +fail: + + QGL_Shutdown(); + + return qfalse; +} + +/* +** GLimp_Init +** +** This routine is responsible for initializing the OS specific portions +** of OpenGL. +*/ +void GLimp_Init( void ) +{ + qboolean attemptedlibGL = qfalse; + qboolean attempted3Dfx = qfalse; + qboolean success = qfalse; + char buf[1024]; + cvar_t *lastValidRenderer = ri.Cvar_Get( "r_lastValidRenderer", "(uninitialized)", CVAR_ARCHIVE ); + cvar_t *cv; + + glConfig.deviceSupportsGamma = qfalse; + + InitSig(); + + // + // load and initialize the specific OpenGL driver + // + if ( !GLW_LoadOpenGL( r_glDriver->string ) ) + { + if ( !Q_stricmp( r_glDriver->string, OPENGL_DRIVER_NAME ) ) + { + attemptedlibGL = qtrue; + } + else if ( !Q_stricmp( r_glDriver->string, _3DFX_DRIVER_NAME ) ) + { + attempted3Dfx = qtrue; + } + + if ( !attempted3Dfx && !success ) + { + attempted3Dfx = qtrue; + if ( GLW_LoadOpenGL( _3DFX_DRIVER_NAME ) ) + { + ri.Cvar_Set( "r_glDriver", _3DFX_DRIVER_NAME ); + r_glDriver->modified = qfalse; + success = qtrue; + } + } + + // try ICD before trying 3Dfx standalone driver + if ( !attemptedlibGL && !success ) + { + attemptedlibGL = qtrue; + if ( GLW_LoadOpenGL( OPENGL_DRIVER_NAME ) ) + { + ri.Cvar_Set( "r_glDriver", OPENGL_DRIVER_NAME ); + r_glDriver->modified = qfalse; + success = qtrue; + } + } + + if (!success) + ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem\n" ); + + } + + // get our config strings + Q_strncpyz( glConfig.vendor_string, qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) ); + Q_strncpyz( glConfig.renderer_string, qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) ); + if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n') + glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0; + Q_strncpyz( glConfig.version_string, qglGetString (GL_VERSION), sizeof( glConfig.version_string ) ); + Q_strncpyz( glConfig.extensions_string, qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) ); + + // + // chipset specific configuration + // + strcpy( buf, glConfig.renderer_string ); + strlwr( buf ); + + if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) ) + { + ri.Cvar_Set( "r_picmip", "1" ); + ri.Cvar_Set( "r_twopartfog", "0" ); + ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); + + // + // voodoo issues + // + if ( strstr( buf, "voodoo" ) && !strstr( buf, "banshee" ) ) + { + ri.Cvar_Set( "r_fakeFullscreen", "1"); + } + + // + // Riva128 issues + // + if ( strstr( buf, "riva 128" ) ) + { + ri.Cvar_Set( "r_twopartfog", "1" ); + } + + // + // Rage Pro issues + // + if ( strstr( buf, "rage pro" ) ) + { + ri.Cvar_Set( "r_mode", "2" ); + ri.Cvar_Set( "r_twopartfog", "1" ); + } + + // + // Permedia2 issues + // + if ( strstr( buf, "permedia2" ) ) + { + ri.Cvar_Set( "r_vertexLight", "1" ); + } + + // + // Riva TNT issues + // + if ( strstr( buf, "riva tnt " ) ) + { + if ( r_texturebits->integer == 32 || + ( ( r_texturebits->integer == 0 ) && glConfig.colorBits > 16 ) ) + { + ri.Cvar_Set( "r_picmip", "1" ); + } + } + + ri.Cvar_Set( "r_lastValidRenderer", glConfig.renderer_string ); + } + + // initialize extensions + GLW_InitExtensions(); + + InitSig(); + + return; +} + + +/* +** GLimp_EndFrame +** +** Responsible for doing a swapbuffers and possibly for other stuff +** as yet to be determined. Probably better not to make this a GLimp +** function and instead do a call to GLimp_SwapBuffers. +*/ +void GLimp_EndFrame (void) +{ +#if 0 + int err; + + if ( !glState.finishCalled ) + qglFinish(); + + // check for errors + if ( !gl_ignore_errors->value ) { + if ( ( err = qglGetError() ) != GL_NO_ERROR ) + { + ri.Error( ERR_FATAL, "GLimp_EndFrame() - glGetError() failed (0x%x)!\n", err ); + } + } +#endif + + // don't flip if drawing to front buffer + if ( stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 ) + { + qglXSwapBuffers(dpy, win); + } + + // check logging + QGL_EnableLogging( r_logFile->value ); + +#if 0 + GLimp_LogComment( "*** RE_EndFrame ***\n" ); + + // decrement log + if ( gl_log->value ) + { + ri.Cvar_Set( "gl_log", va("%i",gl_log->value - 1 ) ); + } +#endif +} + +/* +=========================================================== + +SMP acceleration + +=========================================================== +*/ + +sem_t renderCommandsEvent; +sem_t renderCompletedEvent; +sem_t renderActiveEvent; + +void (*glimpRenderThread)( void ); + +void GLimp_RenderThreadWrapper( void *stub ) { + glimpRenderThread(); + +#if 0 + // unbind the context before we die + qglXMakeCurrent(dpy, None, NULL); +#endif +} + + +/* +======================= +GLimp_SpawnRenderThread +======================= +*/ +pthread_t renderThreadHandle; +qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) { + + sem_init( &renderCommandsEvent, 0, 0 ); + sem_init( &renderCompletedEvent, 0, 0 ); + sem_init( &renderActiveEvent, 0, 0 ); + + glimpRenderThread = function; + + if (pthread_create( &renderThreadHandle, NULL, + GLimp_RenderThreadWrapper, NULL)) { + return qfalse; + } + + return qtrue; +} + +static void *smpData; +static int glXErrors; + +void *GLimp_RendererSleep( void ) { + void *data; + +#if 0 + if ( !qglXMakeCurrent(dpy, None, NULL) ) { + glXErrors++; + } +#endif + +// ResetEvent( renderActiveEvent ); + + // after this, the front end can exit GLimp_FrontEndSleep + sem_post ( &renderCompletedEvent ); + + sem_wait ( &renderCommandsEvent ); + +#if 0 + if ( !qglXMakeCurrent(dpy, win, ctx) ) { + glXErrors++; + } +#endif + +// ResetEvent( renderCompletedEvent ); +// ResetEvent( renderCommandsEvent ); + + data = smpData; + + // after this, the main thread can exit GLimp_WakeRenderer + sem_post ( &renderActiveEvent ); + + return data; +} + + +void GLimp_FrontEndSleep( void ) { + sem_wait ( &renderCompletedEvent ); + +#if 0 + if ( !qglXMakeCurrent(dpy, win, ctx) ) { + glXErrors++; + } +#endif +} + + +void GLimp_WakeRenderer( void *data ) { + smpData = data; + +#if 0 + if ( !qglXMakeCurrent(dpy, None, NULL) ) { + glXErrors++; + } +#endif + + // after this, the renderer can continue through GLimp_RendererSleep + sem_post( &renderCommandsEvent ); + + sem_wait( &renderActiveEvent ); +} + +/*===========================================================*/ + +/*****************************************************************************/ +/* MOUSE */ +/*****************************************************************************/ + +void IN_Init(void) +{ + // mouse variables + in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE); + in_dgamouse = Cvar_Get ("in_dgamouse", "1", CVAR_ARCHIVE); + + if (in_mouse->value) + mouse_avail = qtrue; + else + mouse_avail = qfalse; +} + +void IN_Shutdown(void) +{ + mouse_avail = qfalse; +} + +void IN_MouseMove(void) +{ + if (!mouse_avail || !dpy || !win) + return; + +#if 0 + if (!dgamouse) { + Window root, child; + int root_x, root_y; + int win_x, win_y; + unsigned int mask_return; + int mwx = glConfig.vidWidth/2; + int mwy = glConfig.vidHeight/2; + + XQueryPointer(dpy, win, &root, &child, + &root_x, &root_y, &win_x, &win_y, &mask_return); + + mx = win_x - mwx; + my = win_y - mwy; + + XWarpPointer(dpy,None,win,0,0,0,0, mwx, mwy); + } +#endif + + if (mx || my) + Sys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL ); + mx = my = 0; +} + +void IN_Frame (void) +{ + if ( cls.keyCatchers || cls.state != CA_ACTIVE ) { + // temporarily deactivate if not in the game and + // running on the desktop + // voodoo always counts as full screen + if (Cvar_VariableValue ("r_fullscreen") == 0 + && strcmp( Cvar_VariableString("r_glDriver"), _3DFX_DRIVER_NAME ) ) { + IN_DeactivateMouse (); + return; + } + if (dpy && !autorepeaton) { + XAutoRepeatOn(dpy); + autorepeaton = qtrue; + } + } else if (dpy && autorepeaton) { + XAutoRepeatOff(dpy); + autorepeaton = qfalse; + } + + IN_ActivateMouse(); + + // post events to the system que + IN_MouseMove(); +} + +void IN_Activate(void) +{ +} + +void Sys_SendKeyEvents (void) +{ + XEvent event; + + if (!dpy) + return; + + HandleEvents(); +// while (XCheckMaskEvent(dpy,KEY_MASK|MOUSE_MASK,&event)) +// HandleEvent(&event); +} + diff --git a/code/unix/linux_qgl.c b/code/unix/linux_qgl.c new file mode 100644 index 0000000..3dac0a7 --- /dev/null +++ b/code/unix/linux_qgl.c @@ -0,0 +1,4111 @@ +/* +** LINUX_QGL.C +** +** This file implements the operating system binding of GL to QGL function +** pointers. When doing a port of Quake2 you must implement the following +** two functions: +** +** QGL_Init() - loads libraries, assigns function pointers, etc. +** QGL_Shutdown() - unloads libraries, NULLs function pointers +*/ +#include +#include "../renderer/tr_local.h" +#include "unix_glw.h" + +#include +#include + +#include + +//FX Mesa Functions +fxMesaContext (*qfxMesaCreateContext)(GLuint win, GrScreenResolution_t, GrScreenRefresh_t, const GLint attribList[]); +fxMesaContext (*qfxMesaCreateBestContext)(GLuint win, GLint width, GLint height, const GLint attribList[]); +void (*qfxMesaDestroyContext)(fxMesaContext ctx); +void (*qfxMesaMakeCurrent)(fxMesaContext ctx); +fxMesaContext (*qfxMesaGetCurrentContext)(void); +void (*qfxMesaSwapBuffers)(void); + +//GLX Functions +XVisualInfo * (*qglXChooseVisual)( Display *dpy, int screen, int *attribList ); +GLXContext (*qglXCreateContext)( Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct ); +void (*qglXDestroyContext)( Display *dpy, GLXContext ctx ); +Bool (*qglXMakeCurrent)( Display *dpy, GLXDrawable drawable, GLXContext ctx); +void (*qglXCopyContext)( Display *dpy, GLXContext src, GLXContext dst, GLuint mask ); +void (*qglXSwapBuffers)( Display *dpy, GLXDrawable drawable ); + +void ( APIENTRY * qglAccum )(GLenum op, GLfloat value); +void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref); +GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +void ( APIENTRY * qglArrayElement )(GLint i); +void ( APIENTRY * qglBegin )(GLenum mode); +void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture); +void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor); +void ( APIENTRY * qglCallList )(GLuint list); +void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +void ( APIENTRY * qglClear )(GLbitfield mask); +void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +void ( APIENTRY * qglClearDepth )(GLclampd depth); +void ( APIENTRY * qglClearIndex )(GLfloat c); +void ( APIENTRY * qglClearStencil )(GLint s); +void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation); +void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue); +void ( APIENTRY * qglColor3bv )(const GLbyte *v); +void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue); +void ( APIENTRY * qglColor3dv )(const GLdouble *v); +void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue); +void ( APIENTRY * qglColor3fv )(const GLfloat *v); +void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue); +void ( APIENTRY * qglColor3iv )(const GLint *v); +void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue); +void ( APIENTRY * qglColor3sv )(const GLshort *v); +void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +void ( APIENTRY * qglColor3ubv )(const GLubyte *v); +void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue); +void ( APIENTRY * qglColor3uiv )(const GLuint *v); +void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue); +void ( APIENTRY * qglColor3usv )(const GLushort *v); +void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +void ( APIENTRY * qglColor4bv )(const GLbyte *v); +void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +void ( APIENTRY * qglColor4dv )(const GLdouble *v); +void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglColor4fv )(const GLfloat *v); +void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +void ( APIENTRY * qglColor4iv )(const GLint *v); +void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +void ( APIENTRY * qglColor4sv )(const GLshort *v); +void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +void ( APIENTRY * qglColor4ubv )(const GLubyte *v); +void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +void ( APIENTRY * qglColor4uiv )(const GLuint *v); +void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +void ( APIENTRY * qglColor4usv )(const GLushort *v); +void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode); +void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglCullFace )(GLenum mode); +void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range); +void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures); +void ( APIENTRY * qglDepthFunc )(GLenum func); +void ( APIENTRY * qglDepthMask )(GLboolean flag); +void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar); +void ( APIENTRY * qglDisable )(GLenum cap); +void ( APIENTRY * qglDisableClientState )(GLenum array); +void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count); +void ( APIENTRY * qglDrawBuffer )(GLenum mode); +void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglEdgeFlag )(GLboolean flag); +void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag); +void ( APIENTRY * qglEnable )(GLenum cap); +void ( APIENTRY * qglEnableClientState )(GLenum array); +void ( APIENTRY * qglEnd )(void); +void ( APIENTRY * qglEndList )(void); +void ( APIENTRY * qglEvalCoord1d )(GLdouble u); +void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord1f )(GLfloat u); +void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u); +void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v); +void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v); +void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u); +void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +void ( APIENTRY * qglEvalPoint1 )(GLint i); +void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j); +void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +void ( APIENTRY * qglFinish )(void); +void ( APIENTRY * qglFlush )(void); +void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglFogi )(GLenum pname, GLint param); +void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglFrontFace )(GLenum mode); +void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLuint ( APIENTRY * qglGenLists )(GLsizei range); +void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures); +void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params); +void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation); +void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params); +GLenum ( APIENTRY * qglGetError )(void); +void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params); +void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params); +void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v); +void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v); +void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v); +void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values); +void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values); +void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values); +void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params); +void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask); +const GLubyte * ( APIENTRY * qglGetString )(GLenum name); +void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglHint )(GLenum target, GLenum mode); +void ( APIENTRY * qglIndexMask )(GLuint mask); +void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglIndexd )(GLdouble c); +void ( APIENTRY * qglIndexdv )(const GLdouble *c); +void ( APIENTRY * qglIndexf )(GLfloat c); +void ( APIENTRY * qglIndexfv )(const GLfloat *c); +void ( APIENTRY * qglIndexi )(GLint c); +void ( APIENTRY * qglIndexiv )(const GLint *c); +void ( APIENTRY * qglIndexs )(GLshort c); +void ( APIENTRY * qglIndexsv )(const GLshort *c); +void ( APIENTRY * qglIndexub )(GLubyte c); +void ( APIENTRY * qglIndexubv )(const GLubyte *c); +void ( APIENTRY * qglInitNames )(void); +void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap); +GLboolean ( APIENTRY * qglIsList )(GLuint list); +GLboolean ( APIENTRY * qglIsTexture )(GLuint texture); +void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param); +void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param); +void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param); +void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params); +void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern); +void ( APIENTRY * qglLineWidth )(GLfloat width); +void ( APIENTRY * qglListBase )(GLuint base); +void ( APIENTRY * qglLoadIdentity )(void); +void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m); +void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m); +void ( APIENTRY * qglLoadName )(GLuint name); +void ( APIENTRY * qglLogicOp )(GLenum opcode); +void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param); +void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param); +void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params); +void ( APIENTRY * qglMatrixMode )(GLenum mode); +void ( APIENTRY * qglMultMatrixd )(const GLdouble *m); +void ( APIENTRY * qglMultMatrixf )(const GLfloat *m); +void ( APIENTRY * qglNewList )(GLuint list, GLenum mode); +void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +void ( APIENTRY * qglNormal3bv )(const GLbyte *v); +void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +void ( APIENTRY * qglNormal3dv )(const GLdouble *v); +void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +void ( APIENTRY * qglNormal3fv )(const GLfloat *v); +void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz); +void ( APIENTRY * qglNormal3iv )(const GLint *v); +void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz); +void ( APIENTRY * qglNormal3sv )(const GLshort *v); +void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +void ( APIENTRY * qglPassThrough )(GLfloat token); +void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor); +void ( APIENTRY * qglPointSize )(GLfloat size); +void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode); +void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units); +void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask); +void ( APIENTRY * qglPopAttrib )(void); +void ( APIENTRY * qglPopClientAttrib )(void); +void ( APIENTRY * qglPopMatrix )(void); +void ( APIENTRY * qglPopName )(void); +void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +void ( APIENTRY * qglPushAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushMatrix )(void); +void ( APIENTRY * qglPushName )(GLuint name); +void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y); +void ( APIENTRY * qglRasterPos2iv )(const GLint *v); +void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y); +void ( APIENTRY * qglRasterPos2sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglRasterPos3iv )(const GLint *v); +void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglRasterPos3sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglRasterPos4iv )(const GLint *v); +void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglRasterPos4sv )(const GLshort *v); +void ( APIENTRY * qglReadBuffer )(GLenum mode); +void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2); +void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2); +void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2); +void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2); +GLint ( APIENTRY * qglRenderMode )(GLenum mode); +void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer); +void ( APIENTRY * qglShadeModel )(GLenum mode); +void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask); +void ( APIENTRY * qglStencilMask )(GLuint mask); +void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +void ( APIENTRY * qglTexCoord1d )(GLdouble s); +void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord1f )(GLfloat s); +void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord1i )(GLint s); +void ( APIENTRY * qglTexCoord1iv )(const GLint *v); +void ( APIENTRY * qglTexCoord1s )(GLshort s); +void ( APIENTRY * qglTexCoord1sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t); +void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t); +void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t); +void ( APIENTRY * qglTexCoord2iv )(const GLint *v); +void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t); +void ( APIENTRY * qglTexCoord2sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r); +void ( APIENTRY * qglTexCoord3iv )(const GLint *v); +void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r); +void ( APIENTRY * qglTexCoord3sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +void ( APIENTRY * qglTexCoord4iv )(const GLint *v); +void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +void ( APIENTRY * qglTexCoord4sv )(const GLshort *v); +void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param); +void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param); +void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglVertex2dv )(const GLdouble *v); +void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglVertex2fv )(const GLfloat *v); +void ( APIENTRY * qglVertex2i )(GLint x, GLint y); +void ( APIENTRY * qglVertex2iv )(const GLint *v); +void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y); +void ( APIENTRY * qglVertex2sv )(const GLshort *v); +void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglVertex3dv )(const GLdouble *v); +void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex3fv )(const GLfloat *v); +void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglVertex3iv )(const GLint *v); +void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglVertex3sv )(const GLshort *v); +void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglVertex4dv )(const GLdouble *v); +void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglVertex4fv )(const GLfloat *v); +void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglVertex4iv )(const GLint *v); +void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglVertex4sv )(const GLshort *v); +void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +void ( APIENTRY * qglMultiTexCoord2fARB )( GLenum texture, GLfloat s, GLfloat t ); +void ( APIENTRY * qglActiveTextureARB )( GLenum texture ); +void ( APIENTRY * qglClientActiveTextureARB )( GLenum texture ); + +void ( APIENTRY * qglLockArraysEXT)( int, int); +void ( APIENTRY * qglUnlockArraysEXT) ( void ); + +void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value ); +void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value ); +void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * ); +void ( APIENTRY * qgl3DfxSetPaletteEXT)( GLuint * ); +void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); +void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); + +static void ( APIENTRY * dllAccum )(GLenum op, GLfloat value); +static void ( APIENTRY * dllAlphaFunc )(GLenum func, GLclampf ref); +GLboolean ( APIENTRY * dllAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +static void ( APIENTRY * dllArrayElement )(GLint i); +static void ( APIENTRY * dllBegin )(GLenum mode); +static void ( APIENTRY * dllBindTexture )(GLenum target, GLuint texture); +static void ( APIENTRY * dllBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +static void ( APIENTRY * dllBlendFunc )(GLenum sfactor, GLenum dfactor); +static void ( APIENTRY * dllCallList )(GLuint list); +static void ( APIENTRY * dllCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +static void ( APIENTRY * dllClear )(GLbitfield mask); +static void ( APIENTRY * dllClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +static void ( APIENTRY * dllClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +static void ( APIENTRY * dllClearDepth )(GLclampd depth); +static void ( APIENTRY * dllClearIndex )(GLfloat c); +static void ( APIENTRY * dllClearStencil )(GLint s); +static void ( APIENTRY * dllClipPlane )(GLenum plane, const GLdouble *equation); +static void ( APIENTRY * dllColor3b )(GLbyte red, GLbyte green, GLbyte blue); +static void ( APIENTRY * dllColor3bv )(const GLbyte *v); +static void ( APIENTRY * dllColor3d )(GLdouble red, GLdouble green, GLdouble blue); +static void ( APIENTRY * dllColor3dv )(const GLdouble *v); +static void ( APIENTRY * dllColor3f )(GLfloat red, GLfloat green, GLfloat blue); +static void ( APIENTRY * dllColor3fv )(const GLfloat *v); +static void ( APIENTRY * dllColor3i )(GLint red, GLint green, GLint blue); +static void ( APIENTRY * dllColor3iv )(const GLint *v); +static void ( APIENTRY * dllColor3s )(GLshort red, GLshort green, GLshort blue); +static void ( APIENTRY * dllColor3sv )(const GLshort *v); +static void ( APIENTRY * dllColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +static void ( APIENTRY * dllColor3ubv )(const GLubyte *v); +static void ( APIENTRY * dllColor3ui )(GLuint red, GLuint green, GLuint blue); +static void ( APIENTRY * dllColor3uiv )(const GLuint *v); +static void ( APIENTRY * dllColor3us )(GLushort red, GLushort green, GLushort blue); +static void ( APIENTRY * dllColor3usv )(const GLushort *v); +static void ( APIENTRY * dllColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +static void ( APIENTRY * dllColor4bv )(const GLbyte *v); +static void ( APIENTRY * dllColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +static void ( APIENTRY * dllColor4dv )(const GLdouble *v); +static void ( APIENTRY * dllColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +static void ( APIENTRY * dllColor4fv )(const GLfloat *v); +static void ( APIENTRY * dllColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +static void ( APIENTRY * dllColor4iv )(const GLint *v); +static void ( APIENTRY * dllColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +static void ( APIENTRY * dllColor4sv )(const GLshort *v); +static void ( APIENTRY * dllColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +static void ( APIENTRY * dllColor4ubv )(const GLubyte *v); +static void ( APIENTRY * dllColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +static void ( APIENTRY * dllColor4uiv )(const GLuint *v); +static void ( APIENTRY * dllColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +static void ( APIENTRY * dllColor4usv )(const GLushort *v); +static void ( APIENTRY * dllColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +static void ( APIENTRY * dllColorMaterial )(GLenum face, GLenum mode); +static void ( APIENTRY * dllColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +static void ( APIENTRY * dllCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +static void ( APIENTRY * dllCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +static void ( APIENTRY * dllCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +static void ( APIENTRY * dllCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +static void ( APIENTRY * dllCullFace )(GLenum mode); +static void ( APIENTRY * dllDeleteLists )(GLuint list, GLsizei range); +static void ( APIENTRY * dllDeleteTextures )(GLsizei n, const GLuint *textures); +static void ( APIENTRY * dllDepthFunc )(GLenum func); +static void ( APIENTRY * dllDepthMask )(GLboolean flag); +static void ( APIENTRY * dllDepthRange )(GLclampd zNear, GLclampd zFar); +static void ( APIENTRY * dllDisable )(GLenum cap); +static void ( APIENTRY * dllDisableClientState )(GLenum array); +static void ( APIENTRY * dllDrawArrays )(GLenum mode, GLint first, GLsizei count); +static void ( APIENTRY * dllDrawBuffer )(GLenum mode); +static void ( APIENTRY * dllDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +static void ( APIENTRY * dllDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllEdgeFlag )(GLboolean flag); +static void ( APIENTRY * dllEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllEdgeFlagv )(const GLboolean *flag); +static void ( APIENTRY * dllEnable )(GLenum cap); +static void ( APIENTRY * dllEnableClientState )(GLenum array); +static void ( APIENTRY * dllEnd )(void); +static void ( APIENTRY * dllEndList )(void); +static void ( APIENTRY * dllEvalCoord1d )(GLdouble u); +static void ( APIENTRY * dllEvalCoord1dv )(const GLdouble *u); +static void ( APIENTRY * dllEvalCoord1f )(GLfloat u); +static void ( APIENTRY * dllEvalCoord1fv )(const GLfloat *u); +static void ( APIENTRY * dllEvalCoord2d )(GLdouble u, GLdouble v); +static void ( APIENTRY * dllEvalCoord2dv )(const GLdouble *u); +static void ( APIENTRY * dllEvalCoord2f )(GLfloat u, GLfloat v); +static void ( APIENTRY * dllEvalCoord2fv )(const GLfloat *u); +static void ( APIENTRY * dllEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +static void ( APIENTRY * dllEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +static void ( APIENTRY * dllEvalPoint1 )(GLint i); +static void ( APIENTRY * dllEvalPoint2 )(GLint i, GLint j); +static void ( APIENTRY * dllFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +static void ( APIENTRY * dllFinish )(void); +static void ( APIENTRY * dllFlush )(void); +static void ( APIENTRY * dllFogf )(GLenum pname, GLfloat param); +static void ( APIENTRY * dllFogfv )(GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllFogi )(GLenum pname, GLint param); +static void ( APIENTRY * dllFogiv )(GLenum pname, const GLint *params); +static void ( APIENTRY * dllFrontFace )(GLenum mode); +static void ( APIENTRY * dllFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLuint ( APIENTRY * dllGenLists )(GLsizei range); +static void ( APIENTRY * dllGenTextures )(GLsizei n, GLuint *textures); +static void ( APIENTRY * dllGetBooleanv )(GLenum pname, GLboolean *params); +static void ( APIENTRY * dllGetClipPlane )(GLenum plane, GLdouble *equation); +static void ( APIENTRY * dllGetDoublev )(GLenum pname, GLdouble *params); +GLenum ( APIENTRY * dllGetError )(void); +static void ( APIENTRY * dllGetFloatv )(GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetIntegerv )(GLenum pname, GLint *params); +static void ( APIENTRY * dllGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetLightiv )(GLenum light, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetMapdv )(GLenum target, GLenum query, GLdouble *v); +static void ( APIENTRY * dllGetMapfv )(GLenum target, GLenum query, GLfloat *v); +static void ( APIENTRY * dllGetMapiv )(GLenum target, GLenum query, GLint *v); +static void ( APIENTRY * dllGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetPixelMapfv )(GLenum map, GLfloat *values); +static void ( APIENTRY * dllGetPixelMapuiv )(GLenum map, GLuint *values); +static void ( APIENTRY * dllGetPixelMapusv )(GLenum map, GLushort *values); +static void ( APIENTRY * dllGetPointerv )(GLenum pname, GLvoid* *params); +static void ( APIENTRY * dllGetPolygonStipple )(GLubyte *mask); +const GLubyte * ( APIENTRY * dllGetString )(GLenum name); +static void ( APIENTRY * dllGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +static void ( APIENTRY * dllGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +static void ( APIENTRY * dllGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +static void ( APIENTRY * dllGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +static void ( APIENTRY * dllGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +static void ( APIENTRY * dllHint )(GLenum target, GLenum mode); +static void ( APIENTRY * dllIndexMask )(GLuint mask); +static void ( APIENTRY * dllIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllIndexd )(GLdouble c); +static void ( APIENTRY * dllIndexdv )(const GLdouble *c); +static void ( APIENTRY * dllIndexf )(GLfloat c); +static void ( APIENTRY * dllIndexfv )(const GLfloat *c); +static void ( APIENTRY * dllIndexi )(GLint c); +static void ( APIENTRY * dllIndexiv )(const GLint *c); +static void ( APIENTRY * dllIndexs )(GLshort c); +static void ( APIENTRY * dllIndexsv )(const GLshort *c); +static void ( APIENTRY * dllIndexub )(GLubyte c); +static void ( APIENTRY * dllIndexubv )(const GLubyte *c); +static void ( APIENTRY * dllInitNames )(void); +static void ( APIENTRY * dllInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +GLboolean ( APIENTRY * dllIsEnabled )(GLenum cap); +GLboolean ( APIENTRY * dllIsList )(GLuint list); +GLboolean ( APIENTRY * dllIsTexture )(GLuint texture); +static void ( APIENTRY * dllLightModelf )(GLenum pname, GLfloat param); +static void ( APIENTRY * dllLightModelfv )(GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllLightModeli )(GLenum pname, GLint param); +static void ( APIENTRY * dllLightModeliv )(GLenum pname, const GLint *params); +static void ( APIENTRY * dllLightf )(GLenum light, GLenum pname, GLfloat param); +static void ( APIENTRY * dllLightfv )(GLenum light, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllLighti )(GLenum light, GLenum pname, GLint param); +static void ( APIENTRY * dllLightiv )(GLenum light, GLenum pname, const GLint *params); +static void ( APIENTRY * dllLineStipple )(GLint factor, GLushort pattern); +static void ( APIENTRY * dllLineWidth )(GLfloat width); +static void ( APIENTRY * dllListBase )(GLuint base); +static void ( APIENTRY * dllLoadIdentity )(void); +static void ( APIENTRY * dllLoadMatrixd )(const GLdouble *m); +static void ( APIENTRY * dllLoadMatrixf )(const GLfloat *m); +static void ( APIENTRY * dllLoadName )(GLuint name); +static void ( APIENTRY * dllLogicOp )(GLenum opcode); +static void ( APIENTRY * dllMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +static void ( APIENTRY * dllMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +static void ( APIENTRY * dllMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +static void ( APIENTRY * dllMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +static void ( APIENTRY * dllMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +static void ( APIENTRY * dllMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +static void ( APIENTRY * dllMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +static void ( APIENTRY * dllMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +static void ( APIENTRY * dllMaterialf )(GLenum face, GLenum pname, GLfloat param); +static void ( APIENTRY * dllMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllMateriali )(GLenum face, GLenum pname, GLint param); +static void ( APIENTRY * dllMaterialiv )(GLenum face, GLenum pname, const GLint *params); +static void ( APIENTRY * dllMatrixMode )(GLenum mode); +static void ( APIENTRY * dllMultMatrixd )(const GLdouble *m); +static void ( APIENTRY * dllMultMatrixf )(const GLfloat *m); +static void ( APIENTRY * dllNewList )(GLuint list, GLenum mode); +static void ( APIENTRY * dllNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +static void ( APIENTRY * dllNormal3bv )(const GLbyte *v); +static void ( APIENTRY * dllNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +static void ( APIENTRY * dllNormal3dv )(const GLdouble *v); +static void ( APIENTRY * dllNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +static void ( APIENTRY * dllNormal3fv )(const GLfloat *v); +static void ( APIENTRY * dllNormal3i )(GLint nx, GLint ny, GLint nz); +static void ( APIENTRY * dllNormal3iv )(const GLint *v); +static void ( APIENTRY * dllNormal3s )(GLshort nx, GLshort ny, GLshort nz); +static void ( APIENTRY * dllNormal3sv )(const GLshort *v); +static void ( APIENTRY * dllNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +static void ( APIENTRY * dllPassThrough )(GLfloat token); +static void ( APIENTRY * dllPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +static void ( APIENTRY * dllPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +static void ( APIENTRY * dllPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +static void ( APIENTRY * dllPixelStoref )(GLenum pname, GLfloat param); +static void ( APIENTRY * dllPixelStorei )(GLenum pname, GLint param); +static void ( APIENTRY * dllPixelTransferf )(GLenum pname, GLfloat param); +static void ( APIENTRY * dllPixelTransferi )(GLenum pname, GLint param); +static void ( APIENTRY * dllPixelZoom )(GLfloat xfactor, GLfloat yfactor); +static void ( APIENTRY * dllPointSize )(GLfloat size); +static void ( APIENTRY * dllPolygonMode )(GLenum face, GLenum mode); +static void ( APIENTRY * dllPolygonOffset )(GLfloat factor, GLfloat units); +static void ( APIENTRY * dllPolygonStipple )(const GLubyte *mask); +static void ( APIENTRY * dllPopAttrib )(void); +static void ( APIENTRY * dllPopClientAttrib )(void); +static void ( APIENTRY * dllPopMatrix )(void); +static void ( APIENTRY * dllPopName )(void); +static void ( APIENTRY * dllPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +static void ( APIENTRY * dllPushAttrib )(GLbitfield mask); +static void ( APIENTRY * dllPushClientAttrib )(GLbitfield mask); +static void ( APIENTRY * dllPushMatrix )(void); +static void ( APIENTRY * dllPushName )(GLuint name); +static void ( APIENTRY * dllRasterPos2d )(GLdouble x, GLdouble y); +static void ( APIENTRY * dllRasterPos2dv )(const GLdouble *v); +static void ( APIENTRY * dllRasterPos2f )(GLfloat x, GLfloat y); +static void ( APIENTRY * dllRasterPos2fv )(const GLfloat *v); +static void ( APIENTRY * dllRasterPos2i )(GLint x, GLint y); +static void ( APIENTRY * dllRasterPos2iv )(const GLint *v); +static void ( APIENTRY * dllRasterPos2s )(GLshort x, GLshort y); +static void ( APIENTRY * dllRasterPos2sv )(const GLshort *v); +static void ( APIENTRY * dllRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllRasterPos3dv )(const GLdouble *v); +static void ( APIENTRY * dllRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllRasterPos3fv )(const GLfloat *v); +static void ( APIENTRY * dllRasterPos3i )(GLint x, GLint y, GLint z); +static void ( APIENTRY * dllRasterPos3iv )(const GLint *v); +static void ( APIENTRY * dllRasterPos3s )(GLshort x, GLshort y, GLshort z); +static void ( APIENTRY * dllRasterPos3sv )(const GLshort *v); +static void ( APIENTRY * dllRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +static void ( APIENTRY * dllRasterPos4dv )(const GLdouble *v); +static void ( APIENTRY * dllRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +static void ( APIENTRY * dllRasterPos4fv )(const GLfloat *v); +static void ( APIENTRY * dllRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +static void ( APIENTRY * dllRasterPos4iv )(const GLint *v); +static void ( APIENTRY * dllRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +static void ( APIENTRY * dllRasterPos4sv )(const GLshort *v); +static void ( APIENTRY * dllReadBuffer )(GLenum mode); +static void ( APIENTRY * dllReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +static void ( APIENTRY * dllRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +static void ( APIENTRY * dllRectdv )(const GLdouble *v1, const GLdouble *v2); +static void ( APIENTRY * dllRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +static void ( APIENTRY * dllRectfv )(const GLfloat *v1, const GLfloat *v2); +static void ( APIENTRY * dllRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +static void ( APIENTRY * dllRectiv )(const GLint *v1, const GLint *v2); +static void ( APIENTRY * dllRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +static void ( APIENTRY * dllRectsv )(const GLshort *v1, const GLshort *v2); +GLint ( APIENTRY * dllRenderMode )(GLenum mode); +static void ( APIENTRY * dllRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllScaled )(GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllScalef )(GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +static void ( APIENTRY * dllSelectBuffer )(GLsizei size, GLuint *buffer); +static void ( APIENTRY * dllShadeModel )(GLenum mode); +static void ( APIENTRY * dllStencilFunc )(GLenum func, GLint ref, GLuint mask); +static void ( APIENTRY * dllStencilMask )(GLuint mask); +static void ( APIENTRY * dllStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +static void ( APIENTRY * dllTexCoord1d )(GLdouble s); +static void ( APIENTRY * dllTexCoord1dv )(const GLdouble *v); +static void ( APIENTRY * dllTexCoord1f )(GLfloat s); +static void ( APIENTRY * dllTexCoord1fv )(const GLfloat *v); +static void ( APIENTRY * dllTexCoord1i )(GLint s); +static void ( APIENTRY * dllTexCoord1iv )(const GLint *v); +static void ( APIENTRY * dllTexCoord1s )(GLshort s); +static void ( APIENTRY * dllTexCoord1sv )(const GLshort *v); +static void ( APIENTRY * dllTexCoord2d )(GLdouble s, GLdouble t); +static void ( APIENTRY * dllTexCoord2dv )(const GLdouble *v); +static void ( APIENTRY * dllTexCoord2f )(GLfloat s, GLfloat t); +static void ( APIENTRY * dllTexCoord2fv )(const GLfloat *v); +static void ( APIENTRY * dllTexCoord2i )(GLint s, GLint t); +static void ( APIENTRY * dllTexCoord2iv )(const GLint *v); +static void ( APIENTRY * dllTexCoord2s )(GLshort s, GLshort t); +static void ( APIENTRY * dllTexCoord2sv )(const GLshort *v); +static void ( APIENTRY * dllTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +static void ( APIENTRY * dllTexCoord3dv )(const GLdouble *v); +static void ( APIENTRY * dllTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +static void ( APIENTRY * dllTexCoord3fv )(const GLfloat *v); +static void ( APIENTRY * dllTexCoord3i )(GLint s, GLint t, GLint r); +static void ( APIENTRY * dllTexCoord3iv )(const GLint *v); +static void ( APIENTRY * dllTexCoord3s )(GLshort s, GLshort t, GLshort r); +static void ( APIENTRY * dllTexCoord3sv )(const GLshort *v); +static void ( APIENTRY * dllTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +static void ( APIENTRY * dllTexCoord4dv )(const GLdouble *v); +static void ( APIENTRY * dllTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +static void ( APIENTRY * dllTexCoord4fv )(const GLfloat *v); +static void ( APIENTRY * dllTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +static void ( APIENTRY * dllTexCoord4iv )(const GLint *v); +static void ( APIENTRY * dllTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +static void ( APIENTRY * dllTexCoord4sv )(const GLshort *v); +static void ( APIENTRY * dllTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllTexEnvf )(GLenum target, GLenum pname, GLfloat param); +static void ( APIENTRY * dllTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllTexEnvi )(GLenum target, GLenum pname, GLint param); +static void ( APIENTRY * dllTexEnviv )(GLenum target, GLenum pname, const GLint *params); +static void ( APIENTRY * dllTexGend )(GLenum coord, GLenum pname, GLdouble param); +static void ( APIENTRY * dllTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +static void ( APIENTRY * dllTexGenf )(GLenum coord, GLenum pname, GLfloat param); +static void ( APIENTRY * dllTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllTexGeni )(GLenum coord, GLenum pname, GLint param); +static void ( APIENTRY * dllTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +static void ( APIENTRY * dllTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllTexParameterf )(GLenum target, GLenum pname, GLfloat param); +static void ( APIENTRY * dllTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +static void ( APIENTRY * dllTexParameteri )(GLenum target, GLenum pname, GLint param); +static void ( APIENTRY * dllTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +static void ( APIENTRY * dllTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +static void ( APIENTRY * dllTranslated )(GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllTranslatef )(GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllVertex2d )(GLdouble x, GLdouble y); +static void ( APIENTRY * dllVertex2dv )(const GLdouble *v); +static void ( APIENTRY * dllVertex2f )(GLfloat x, GLfloat y); +static void ( APIENTRY * dllVertex2fv )(const GLfloat *v); +static void ( APIENTRY * dllVertex2i )(GLint x, GLint y); +static void ( APIENTRY * dllVertex2iv )(const GLint *v); +static void ( APIENTRY * dllVertex2s )(GLshort x, GLshort y); +static void ( APIENTRY * dllVertex2sv )(const GLshort *v); +static void ( APIENTRY * dllVertex3d )(GLdouble x, GLdouble y, GLdouble z); +static void ( APIENTRY * dllVertex3dv )(const GLdouble *v); +static void ( APIENTRY * dllVertex3f )(GLfloat x, GLfloat y, GLfloat z); +static void ( APIENTRY * dllVertex3fv )(const GLfloat *v); +static void ( APIENTRY * dllVertex3i )(GLint x, GLint y, GLint z); +static void ( APIENTRY * dllVertex3iv )(const GLint *v); +static void ( APIENTRY * dllVertex3s )(GLshort x, GLshort y, GLshort z); +static void ( APIENTRY * dllVertex3sv )(const GLshort *v); +static void ( APIENTRY * dllVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +static void ( APIENTRY * dllVertex4dv )(const GLdouble *v); +static void ( APIENTRY * dllVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +static void ( APIENTRY * dllVertex4fv )(const GLfloat *v); +static void ( APIENTRY * dllVertex4i )(GLint x, GLint y, GLint z, GLint w); +static void ( APIENTRY * dllVertex4iv )(const GLint *v); +static void ( APIENTRY * dllVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +static void ( APIENTRY * dllVertex4sv )(const GLshort *v); +static void ( APIENTRY * dllVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +static void ( APIENTRY * dllViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +static void APIENTRY logAccum(GLenum op, GLfloat value) +{ + fprintf( glw_state.log_fp, "glAccum\n" ); + dllAccum( op, value ); +} + +static void APIENTRY logAlphaFunc(GLenum func, GLclampf ref) +{ + fprintf( glw_state.log_fp, "glAlphaFunc( 0x%x, %f )\n", func, ref ); + dllAlphaFunc( func, ref ); +} + +static GLboolean APIENTRY logAreTexturesResident(GLsizei n, const GLuint *textures, GLboolean *residences) +{ + fprintf( glw_state.log_fp, "glAreTexturesResident\n" ); + return dllAreTexturesResident( n, textures, residences ); +} + +static void APIENTRY logArrayElement(GLint i) +{ + fprintf( glw_state.log_fp, "glArrayElement\n" ); + dllArrayElement( i ); +} + +static void APIENTRY logBegin(GLenum mode) +{ + fprintf( glw_state.log_fp, "glBegin( 0x%x )\n", mode ); + dllBegin( mode ); +} + +static void APIENTRY logBindTexture(GLenum target, GLuint texture) +{ + fprintf( glw_state.log_fp, "glBindTexture( 0x%x, %u )\n", target, texture ); + dllBindTexture( target, texture ); +} + +static void APIENTRY logBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap) +{ + fprintf( glw_state.log_fp, "glBitmap\n" ); + dllBitmap( width, height, xorig, yorig, xmove, ymove, bitmap ); +} + +static void APIENTRY logBlendFunc(GLenum sfactor, GLenum dfactor) +{ + fprintf( glw_state.log_fp, "glBlendFunc( 0x%x, 0x%x )\n", sfactor, dfactor ); + dllBlendFunc( sfactor, dfactor ); +} + +static void APIENTRY logCallList(GLuint list) +{ + fprintf( glw_state.log_fp, "glCallList( %u )\n", list ); + dllCallList( list ); +} + +static void APIENTRY logCallLists(GLsizei n, GLenum type, const void *lists) +{ + fprintf( glw_state.log_fp, "glCallLists\n" ); + dllCallLists( n, type, lists ); +} + +static void APIENTRY logClear(GLbitfield mask) +{ + fprintf( glw_state.log_fp, "glClear\n" ); + dllClear( mask ); +} + +static void APIENTRY logClearAccum(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + fprintf( glw_state.log_fp, "glClearAccum\n" ); + dllClearAccum( red, green, blue, alpha ); +} + +static void APIENTRY logClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + fprintf( glw_state.log_fp, "glClearColor\n" ); + dllClearColor( red, green, blue, alpha ); +} + +static void APIENTRY logClearDepth(GLclampd depth) +{ + fprintf( glw_state.log_fp, "glClearDepth\n" ); + dllClearDepth( depth ); +} + +static void APIENTRY logClearIndex(GLfloat c) +{ + fprintf( glw_state.log_fp, "glClearIndex\n" ); + dllClearIndex( c ); +} + +static void APIENTRY logClearStencil(GLint s) +{ + fprintf( glw_state.log_fp, "glClearStencil\n" ); + dllClearStencil( s ); +} + +static void APIENTRY logClipPlane(GLenum plane, const GLdouble *equation) +{ + fprintf( glw_state.log_fp, "glClipPlane\n" ); + dllClipPlane( plane, equation ); +} + +static void APIENTRY logColor3b(GLbyte red, GLbyte green, GLbyte blue) +{ + fprintf( glw_state.log_fp, "glColor3b\n" ); + dllColor3b( red, green, blue ); +} + +static void APIENTRY logColor3bv(const GLbyte *v) +{ + fprintf( glw_state.log_fp, "glColor3bv\n" ); + dllColor3bv( v ); +} + +static void APIENTRY logColor3d(GLdouble red, GLdouble green, GLdouble blue) +{ + fprintf( glw_state.log_fp, "glColor3d\n" ); + dllColor3d( red, green, blue ); +} + +static void APIENTRY logColor3dv(const GLdouble *v) +{ + fprintf( glw_state.log_fp, "glColor3dv\n" ); + dllColor3dv( v ); +} + +static void APIENTRY logColor3f(GLfloat red, GLfloat green, GLfloat blue) +{ + fprintf( glw_state.log_fp, "glColor3f\n" ); + dllColor3f( red, green, blue ); +} + +static void APIENTRY logColor3fv(const GLfloat *v) +{ + fprintf( glw_state.log_fp, "glColor3fv\n" ); + dllColor3fv( v ); +} + +static void APIENTRY logColor3i(GLint red, GLint green, GLint blue) +{ + fprintf( glw_state.log_fp, "glColor3i\n" ); + dllColor3i( red, green, blue ); +} + +static void APIENTRY logColor3iv(const GLint *v) +{ + fprintf( glw_state.log_fp, "glColor3iv\n" ); + dllColor3iv( v ); +} + +static void APIENTRY logColor3s(GLshort red, GLshort green, GLshort blue) +{ + fprintf( glw_state.log_fp, "glColor3s\n" ); + dllColor3s( red, green, blue ); +} + +static void APIENTRY logColor3sv(const GLshort *v) +{ + fprintf( glw_state.log_fp, "glColor3sv\n" ); + dllColor3sv( v ); +} + +static void APIENTRY logColor3ub(GLubyte red, GLubyte green, GLubyte blue) +{ + fprintf( glw_state.log_fp, "glColor3ub\n" ); + dllColor3ub( red, green, blue ); +} + +static void APIENTRY logColor3ubv(const GLubyte *v) +{ + fprintf( glw_state.log_fp, "glColor3ubv\n" ); + dllColor3ubv( v ); +} + +#define SIG( x ) fprintf( glw_state.log_fp, x "\n" ) + +static void APIENTRY logColor3ui(GLuint red, GLuint green, GLuint blue) +{ + SIG( "glColor3ui" ); + dllColor3ui( red, green, blue ); +} + +static void APIENTRY logColor3uiv(const GLuint *v) +{ + SIG( "glColor3uiv" ); + dllColor3uiv( v ); +} + +static void APIENTRY logColor3us(GLushort red, GLushort green, GLushort blue) +{ + SIG( "glColor3us" ); + dllColor3us( red, green, blue ); +} + +static void APIENTRY logColor3usv(const GLushort *v) +{ + SIG( "glColor3usv" ); + dllColor3usv( v ); +} + +static void APIENTRY logColor4b(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha) +{ + SIG( "glColor4b" ); + dllColor4b( red, green, blue, alpha ); +} + +static void APIENTRY logColor4bv(const GLbyte *v) +{ + SIG( "glColor4bv" ); + dllColor4bv( v ); +} + +static void APIENTRY logColor4d(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha) +{ + SIG( "glColor4d" ); + dllColor4d( red, green, blue, alpha ); +} +static void APIENTRY logColor4dv(const GLdouble *v) +{ + SIG( "glColor4dv" ); + dllColor4dv( v ); +} +static void APIENTRY logColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) +{ + fprintf( glw_state.log_fp, "glColor4f( %f,%f,%f,%f )\n", red, green, blue, alpha ); + dllColor4f( red, green, blue, alpha ); +} +static void APIENTRY logColor4fv(const GLfloat *v) +{ + fprintf( glw_state.log_fp, "glColor4fv( %f,%f,%f,%f )\n", v[0], v[1], v[2], v[3] ); + dllColor4fv( v ); +} +static void APIENTRY logColor4i(GLint red, GLint green, GLint blue, GLint alpha) +{ + SIG( "glColor4i" ); + dllColor4i( red, green, blue, alpha ); +} +static void APIENTRY logColor4iv(const GLint *v) +{ + SIG( "glColor4iv" ); + dllColor4iv( v ); +} +static void APIENTRY logColor4s(GLshort red, GLshort green, GLshort blue, GLshort alpha) +{ + SIG( "glColor4s" ); + dllColor4s( red, green, blue, alpha ); +} +static void APIENTRY logColor4sv(const GLshort *v) +{ + SIG( "glColor4sv" ); + dllColor4sv( v ); +} +static void APIENTRY logColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) +{ + SIG( "glColor4b" ); + dllColor4b( red, green, blue, alpha ); +} +static void APIENTRY logColor4ubv(const GLubyte *v) +{ + SIG( "glColor4ubv" ); + dllColor4ubv( v ); +} +static void APIENTRY logColor4ui(GLuint red, GLuint green, GLuint blue, GLuint alpha) +{ + SIG( "glColor4ui" ); + dllColor4ui( red, green, blue, alpha ); +} +static void APIENTRY logColor4uiv(const GLuint *v) +{ + SIG( "glColor4uiv" ); + dllColor4uiv( v ); +} +static void APIENTRY logColor4us(GLushort red, GLushort green, GLushort blue, GLushort alpha) +{ + SIG( "glColor4us" ); + dllColor4us( red, green, blue, alpha ); +} +static void APIENTRY logColor4usv(const GLushort *v) +{ + SIG( "glColor4usv" ); + dllColor4usv( v ); +} +static void APIENTRY logColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + SIG( "glColorMask" ); + dllColorMask( red, green, blue, alpha ); +} +static void APIENTRY logColorMaterial(GLenum face, GLenum mode) +{ + SIG( "glColorMaterial" ); + dllColorMaterial( face, mode ); +} + +static void APIENTRY logColorPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glColorPointer" ); + dllColorPointer( size, type, stride, pointer ); +} + +static void APIENTRY logCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) +{ + SIG( "glCopyPixels" ); + dllCopyPixels( x, y, width, height, type ); +} + +static void APIENTRY logCopyTexImage1D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border) +{ + SIG( "glCopyTexImage1D" ); + dllCopyTexImage1D( target, level, internalFormat, x, y, width, border ); +} + +static void APIENTRY logCopyTexImage2D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + SIG( "glCopyTexImage2D" ); + dllCopyTexImage2D( target, level, internalFormat, x, y, width, height, border ); +} + +static void APIENTRY logCopyTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) +{ + SIG( "glCopyTexSubImage1D" ); + dllCopyTexSubImage1D( target, level, xoffset, x, y, width ); +} + +static void APIENTRY logCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + SIG( "glCopyTexSubImage2D" ); + dllCopyTexSubImage2D( target, level, xoffset, yoffset, x, y, width, height ); +} + +static void APIENTRY logCullFace(GLenum mode) +{ + SIG( "glCullFace" ); + dllCullFace( mode ); +} + +static void APIENTRY logDeleteLists(GLuint list, GLsizei range) +{ + SIG( "glDeleteLists" ); + dllDeleteLists( list, range ); +} + +static void APIENTRY logDeleteTextures(GLsizei n, const GLuint *textures) +{ + SIG( "glDeleteTextures" ); + dllDeleteTextures( n, textures ); +} + +static void APIENTRY logDepthFunc(GLenum func) +{ + SIG( "glDepthFunc" ); + dllDepthFunc( func ); +} + +static void APIENTRY logDepthMask(GLboolean flag) +{ + SIG( "glDepthMask" ); + dllDepthMask( flag ); +} + +static void APIENTRY logDepthRange(GLclampd zNear, GLclampd zFar) +{ + SIG( "glDepthRange" ); + dllDepthRange( zNear, zFar ); +} + +static void APIENTRY logDisable(GLenum cap) +{ + fprintf( glw_state.log_fp, "glDisable( 0x%x )\n", cap ); + dllDisable( cap ); +} + +static void APIENTRY logDisableClientState(GLenum array) +{ + SIG( "glDisableClientState" ); + dllDisableClientState( array ); +} + +static void APIENTRY logDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + SIG( "glDrawArrays" ); + dllDrawArrays( mode, first, count ); +} + +static void APIENTRY logDrawBuffer(GLenum mode) +{ + SIG( "glDrawBuffer" ); + dllDrawBuffer( mode ); +} + +static void APIENTRY logDrawElements(GLenum mode, GLsizei count, GLenum type, const void *indices) +{ + SIG( "glDrawElements" ); + dllDrawElements( mode, count, type, indices ); +} + +static void APIENTRY logDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glDrawPixels" ); + dllDrawPixels( width, height, format, type, pixels ); +} + +static void APIENTRY logEdgeFlag(GLboolean flag) +{ + SIG( "glEdgeFlag" ); + dllEdgeFlag( flag ); +} + +static void APIENTRY logEdgeFlagPointer(GLsizei stride, const void *pointer) +{ + SIG( "glEdgeFlagPointer" ); + dllEdgeFlagPointer( stride, pointer ); +} + +static void APIENTRY logEdgeFlagv(const GLboolean *flag) +{ + SIG( "glEdgeFlagv" ); + dllEdgeFlagv( flag ); +} + +static void APIENTRY logEnable(GLenum cap) +{ + fprintf( glw_state.log_fp, "glEnable( 0x%x )\n", cap ); + dllEnable( cap ); +} + +static void APIENTRY logEnableClientState(GLenum array) +{ + SIG( "glEnableClientState" ); + dllEnableClientState( array ); +} + +static void APIENTRY logEnd(void) +{ + SIG( "glEnd" ); + dllEnd(); +} + +static void APIENTRY logEndList(void) +{ + SIG( "glEndList" ); + dllEndList(); +} + +static void APIENTRY logEvalCoord1d(GLdouble u) +{ + SIG( "glEvalCoord1d" ); + dllEvalCoord1d( u ); +} + +static void APIENTRY logEvalCoord1dv(const GLdouble *u) +{ + SIG( "glEvalCoord1dv" ); + dllEvalCoord1dv( u ); +} + +static void APIENTRY logEvalCoord1f(GLfloat u) +{ + SIG( "glEvalCoord1f" ); + dllEvalCoord1f( u ); +} + +static void APIENTRY logEvalCoord1fv(const GLfloat *u) +{ + SIG( "glEvalCoord1fv" ); + dllEvalCoord1fv( u ); +} +static void APIENTRY logEvalCoord2d(GLdouble u, GLdouble v) +{ + SIG( "glEvalCoord2d" ); + dllEvalCoord2d( u, v ); +} +static void APIENTRY logEvalCoord2dv(const GLdouble *u) +{ + SIG( "glEvalCoord2dv" ); + dllEvalCoord2dv( u ); +} +static void APIENTRY logEvalCoord2f(GLfloat u, GLfloat v) +{ + SIG( "glEvalCoord2f" ); + dllEvalCoord2f( u, v ); +} +static void APIENTRY logEvalCoord2fv(const GLfloat *u) +{ + SIG( "glEvalCoord2fv" ); + dllEvalCoord2fv( u ); +} + +static void APIENTRY logEvalMesh1(GLenum mode, GLint i1, GLint i2) +{ + SIG( "glEvalMesh1" ); + dllEvalMesh1( mode, i1, i2 ); +} +static void APIENTRY logEvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2) +{ + SIG( "glEvalMesh2" ); + dllEvalMesh2( mode, i1, i2, j1, j2 ); +} +static void APIENTRY logEvalPoint1(GLint i) +{ + SIG( "glEvalPoint1" ); + dllEvalPoint1( i ); +} +static void APIENTRY logEvalPoint2(GLint i, GLint j) +{ + SIG( "glEvalPoint2" ); + dllEvalPoint2( i, j ); +} + +static void APIENTRY logFeedbackBuffer(GLsizei size, GLenum type, GLfloat *buffer) +{ + SIG( "glFeedbackBuffer" ); + dllFeedbackBuffer( size, type, buffer ); +} + +static void APIENTRY logFinish(void) +{ + SIG( "glFinish" ); + dllFinish(); +} + +static void APIENTRY logFlush(void) +{ + SIG( "glFlush" ); + dllFlush(); +} + +static void APIENTRY logFogf(GLenum pname, GLfloat param) +{ + SIG( "glFogf" ); + dllFogf( pname, param ); +} + +static void APIENTRY logFogfv(GLenum pname, const GLfloat *params) +{ + SIG( "glFogfv" ); + dllFogfv( pname, params ); +} + +static void APIENTRY logFogi(GLenum pname, GLint param) +{ + SIG( "glFogi" ); + dllFogi( pname, param ); +} + +static void APIENTRY logFogiv(GLenum pname, const GLint *params) +{ + SIG( "glFogiv" ); + dllFogiv( pname, params ); +} + +static void APIENTRY logFrontFace(GLenum mode) +{ + SIG( "glFrontFace" ); + dllFrontFace( mode ); +} + +static void APIENTRY logFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) +{ + SIG( "glFrustum" ); + dllFrustum( left, right, bottom, top, zNear, zFar ); +} + +static GLuint APIENTRY logGenLists(GLsizei range) +{ + SIG( "glGenLists" ); + return dllGenLists( range ); +} + +static void APIENTRY logGenTextures(GLsizei n, GLuint *textures) +{ + SIG( "glGenTextures" ); + dllGenTextures( n, textures ); +} + +static void APIENTRY logGetBooleanv(GLenum pname, GLboolean *params) +{ + SIG( "glGetBooleanv" ); + dllGetBooleanv( pname, params ); +} + +static void APIENTRY logGetClipPlane(GLenum plane, GLdouble *equation) +{ + SIG( "glGetClipPlane" ); + dllGetClipPlane( plane, equation ); +} + +static void APIENTRY logGetDoublev(GLenum pname, GLdouble *params) +{ + SIG( "glGetDoublev" ); + dllGetDoublev( pname, params ); +} + +static GLenum APIENTRY logGetError(void) +{ + SIG( "glGetError" ); + return dllGetError(); +} + +static void APIENTRY logGetFloatv(GLenum pname, GLfloat *params) +{ + SIG( "glGetFloatv" ); + dllGetFloatv( pname, params ); +} + +static void APIENTRY logGetIntegerv(GLenum pname, GLint *params) +{ + SIG( "glGetIntegerv" ); + dllGetIntegerv( pname, params ); +} + +static void APIENTRY logGetLightfv(GLenum light, GLenum pname, GLfloat *params) +{ + SIG( "glGetLightfv" ); + dllGetLightfv( light, pname, params ); +} + +static void APIENTRY logGetLightiv(GLenum light, GLenum pname, GLint *params) +{ + SIG( "glGetLightiv" ); + dllGetLightiv( light, pname, params ); +} + +static void APIENTRY logGetMapdv(GLenum target, GLenum query, GLdouble *v) +{ + SIG( "glGetMapdv" ); + dllGetMapdv( target, query, v ); +} + +static void APIENTRY logGetMapfv(GLenum target, GLenum query, GLfloat *v) +{ + SIG( "glGetMapfv" ); + dllGetMapfv( target, query, v ); +} + +static void APIENTRY logGetMapiv(GLenum target, GLenum query, GLint *v) +{ + SIG( "glGetMapiv" ); + dllGetMapiv( target, query, v ); +} + +static void APIENTRY logGetMaterialfv(GLenum face, GLenum pname, GLfloat *params) +{ + SIG( "glGetMaterialfv" ); + dllGetMaterialfv( face, pname, params ); +} + +static void APIENTRY logGetMaterialiv(GLenum face, GLenum pname, GLint *params) +{ + SIG( "glGetMaterialiv" ); + dllGetMaterialiv( face, pname, params ); +} + +static void APIENTRY logGetPixelMapfv(GLenum map, GLfloat *values) +{ + SIG( "glGetPixelMapfv" ); + dllGetPixelMapfv( map, values ); +} + +static void APIENTRY logGetPixelMapuiv(GLenum map, GLuint *values) +{ + SIG( "glGetPixelMapuiv" ); + dllGetPixelMapuiv( map, values ); +} + +static void APIENTRY logGetPixelMapusv(GLenum map, GLushort *values) +{ + SIG( "glGetPixelMapusv" ); + dllGetPixelMapusv( map, values ); +} + +static void APIENTRY logGetPointerv(GLenum pname, GLvoid* *params) +{ + SIG( "glGetPointerv" ); + dllGetPointerv( pname, params ); +} + +static void APIENTRY logGetPolygonStipple(GLubyte *mask) +{ + SIG( "glGetPolygonStipple" ); + dllGetPolygonStipple( mask ); +} + +static const GLubyte * APIENTRY logGetString(GLenum name) +{ + SIG( "glGetString" ); + return dllGetString( name ); +} + +static void APIENTRY logGetTexEnvfv(GLenum target, GLenum pname, GLfloat *params) +{ + SIG( "glGetTexEnvfv" ); + dllGetTexEnvfv( target, pname, params ); +} + +static void APIENTRY logGetTexEnviv(GLenum target, GLenum pname, GLint *params) +{ + SIG( "glGetTexEnviv" ); + dllGetTexEnviv( target, pname, params ); +} + +static void APIENTRY logGetTexGendv(GLenum coord, GLenum pname, GLdouble *params) +{ + SIG( "glGetTexGendv" ); + dllGetTexGendv( coord, pname, params ); +} + +static void APIENTRY logGetTexGenfv(GLenum coord, GLenum pname, GLfloat *params) +{ + SIG( "glGetTexGenfv" ); + dllGetTexGenfv( coord, pname, params ); +} + +static void APIENTRY logGetTexGeniv(GLenum coord, GLenum pname, GLint *params) +{ + SIG( "glGetTexGeniv" ); + dllGetTexGeniv( coord, pname, params ); +} + +static void APIENTRY logGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void *pixels) +{ + SIG( "glGetTexImage" ); + dllGetTexImage( target, level, format, type, pixels ); +} +static void APIENTRY logGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params ) +{ + SIG( "glGetTexLevelParameterfv" ); + dllGetTexLevelParameterfv( target, level, pname, params ); +} + +static void APIENTRY logGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) +{ + SIG( "glGetTexLevelParameteriv" ); + dllGetTexLevelParameteriv( target, level, pname, params ); +} + +static void APIENTRY logGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) +{ + SIG( "glGetTexParameterfv" ); + dllGetTexParameterfv( target, pname, params ); +} + +static void APIENTRY logGetTexParameteriv(GLenum target, GLenum pname, GLint *params) +{ + SIG( "glGetTexParameteriv" ); + dllGetTexParameteriv( target, pname, params ); +} + +static void APIENTRY logHint(GLenum target, GLenum mode) +{ + fprintf( glw_state.log_fp, "glHint( 0x%x, 0x%x )\n", target, mode ); + dllHint( target, mode ); +} + +static void APIENTRY logIndexMask(GLuint mask) +{ + SIG( "glIndexMask" ); + dllIndexMask( mask ); +} + +static void APIENTRY logIndexPointer(GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glIndexPointer" ); + dllIndexPointer( type, stride, pointer ); +} + +static void APIENTRY logIndexd(GLdouble c) +{ + SIG( "glIndexd" ); + dllIndexd( c ); +} + +static void APIENTRY logIndexdv(const GLdouble *c) +{ + SIG( "glIndexdv" ); + dllIndexdv( c ); +} + +static void APIENTRY logIndexf(GLfloat c) +{ + SIG( "glIndexf" ); + dllIndexf( c ); +} + +static void APIENTRY logIndexfv(const GLfloat *c) +{ + SIG( "glIndexfv" ); + dllIndexfv( c ); +} + +static void APIENTRY logIndexi(GLint c) +{ + SIG( "glIndexi" ); + dllIndexi( c ); +} + +static void APIENTRY logIndexiv(const GLint *c) +{ + SIG( "glIndexiv" ); + dllIndexiv( c ); +} + +static void APIENTRY logIndexs(GLshort c) +{ + SIG( "glIndexs" ); + dllIndexs( c ); +} + +static void APIENTRY logIndexsv(const GLshort *c) +{ + SIG( "glIndexsv" ); + dllIndexsv( c ); +} + +static void APIENTRY logIndexub(GLubyte c) +{ + SIG( "glIndexub" ); + dllIndexub( c ); +} + +static void APIENTRY logIndexubv(const GLubyte *c) +{ + SIG( "glIndexubv" ); + dllIndexubv( c ); +} + +static void APIENTRY logInitNames(void) +{ + SIG( "glInitNames" ); + dllInitNames(); +} + +static void APIENTRY logInterleavedArrays(GLenum format, GLsizei stride, const void *pointer) +{ + SIG( "glInterleavedArrays" ); + dllInterleavedArrays( format, stride, pointer ); +} + +static GLboolean APIENTRY logIsEnabled(GLenum cap) +{ + SIG( "glIsEnabled" ); + return dllIsEnabled( cap ); +} +static GLboolean APIENTRY logIsList(GLuint list) +{ + SIG( "glIsList" ); + return dllIsList( list ); +} +static GLboolean APIENTRY logIsTexture(GLuint texture) +{ + SIG( "glIsTexture" ); + return dllIsTexture( texture ); +} + +static void APIENTRY logLightModelf(GLenum pname, GLfloat param) +{ + SIG( "glLightModelf" ); + dllLightModelf( pname, param ); +} + +static void APIENTRY logLightModelfv(GLenum pname, const GLfloat *params) +{ + SIG( "glLightModelfv" ); + dllLightModelfv( pname, params ); +} + +static void APIENTRY logLightModeli(GLenum pname, GLint param) +{ + SIG( "glLightModeli" ); + dllLightModeli( pname, param ); + +} + +static void APIENTRY logLightModeliv(GLenum pname, const GLint *params) +{ + SIG( "glLightModeliv" ); + dllLightModeliv( pname, params ); +} + +static void APIENTRY logLightf(GLenum light, GLenum pname, GLfloat param) +{ + SIG( "glLightf" ); + dllLightf( light, pname, param ); +} + +static void APIENTRY logLightfv(GLenum light, GLenum pname, const GLfloat *params) +{ + SIG( "glLightfv" ); + dllLightfv( light, pname, params ); +} + +static void APIENTRY logLighti(GLenum light, GLenum pname, GLint param) +{ + SIG( "glLighti" ); + dllLighti( light, pname, param ); +} + +static void APIENTRY logLightiv(GLenum light, GLenum pname, const GLint *params) +{ + SIG( "glLightiv" ); + dllLightiv( light, pname, params ); +} + +static void APIENTRY logLineStipple(GLint factor, GLushort pattern) +{ + SIG( "glLineStipple" ); + dllLineStipple( factor, pattern ); +} + +static void APIENTRY logLineWidth(GLfloat width) +{ + SIG( "glLineWidth" ); + dllLineWidth( width ); +} + +static void APIENTRY logListBase(GLuint base) +{ + SIG( "glListBase" ); + dllListBase( base ); +} + +static void APIENTRY logLoadIdentity(void) +{ + SIG( "glLoadIdentity" ); + dllLoadIdentity(); +} + +static void APIENTRY logLoadMatrixd(const GLdouble *m) +{ + SIG( "glLoadMatrixd" ); + dllLoadMatrixd( m ); +} + +static void APIENTRY logLoadMatrixf(const GLfloat *m) +{ + SIG( "glLoadMatrixf" ); + dllLoadMatrixf( m ); +} + +static void APIENTRY logLoadName(GLuint name) +{ + SIG( "glLoadName" ); + dllLoadName( name ); +} + +static void APIENTRY logLogicOp(GLenum opcode) +{ + SIG( "glLogicOp" ); + dllLogicOp( opcode ); +} + +static void APIENTRY logMap1d(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points) +{ + SIG( "glMap1d" ); + dllMap1d( target, u1, u2, stride, order, points ); +} + +static void APIENTRY logMap1f(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points) +{ + SIG( "glMap1f" ); + dllMap1f( target, u1, u2, stride, order, points ); +} + +static void APIENTRY logMap2d(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points) +{ + SIG( "glMap2d" ); + dllMap2d( target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points ); +} + +static void APIENTRY logMap2f(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points) +{ + SIG( "glMap2f" ); + dllMap2f( target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points ); +} + +static void APIENTRY logMapGrid1d(GLint un, GLdouble u1, GLdouble u2) +{ + SIG( "glMapGrid1d" ); + dllMapGrid1d( un, u1, u2 ); +} + +static void APIENTRY logMapGrid1f(GLint un, GLfloat u1, GLfloat u2) +{ + SIG( "glMapGrid1f" ); + dllMapGrid1f( un, u1, u2 ); +} + +static void APIENTRY logMapGrid2d(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2) +{ + SIG( "glMapGrid2d" ); + dllMapGrid2d( un, u1, u2, vn, v1, v2 ); +} +static void APIENTRY logMapGrid2f(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2) +{ + SIG( "glMapGrid2f" ); + dllMapGrid2f( un, u1, u2, vn, v1, v2 ); +} +static void APIENTRY logMaterialf(GLenum face, GLenum pname, GLfloat param) +{ + SIG( "glMaterialf" ); + dllMaterialf( face, pname, param ); +} +static void APIENTRY logMaterialfv(GLenum face, GLenum pname, const GLfloat *params) +{ + SIG( "glMaterialfv" ); + dllMaterialfv( face, pname, params ); +} + +static void APIENTRY logMateriali(GLenum face, GLenum pname, GLint param) +{ + SIG( "glMateriali" ); + dllMateriali( face, pname, param ); +} + +static void APIENTRY logMaterialiv(GLenum face, GLenum pname, const GLint *params) +{ + SIG( "glMaterialiv" ); + dllMaterialiv( face, pname, params ); +} + +static void APIENTRY logMatrixMode(GLenum mode) +{ + SIG( "glMatrixMode" ); + dllMatrixMode( mode ); +} + +static void APIENTRY logMultMatrixd(const GLdouble *m) +{ + SIG( "glMultMatrixd" ); + dllMultMatrixd( m ); +} + +static void APIENTRY logMultMatrixf(const GLfloat *m) +{ + SIG( "glMultMatrixf" ); + dllMultMatrixf( m ); +} + +static void APIENTRY logNewList(GLuint list, GLenum mode) +{ + SIG( "glNewList" ); + dllNewList( list, mode ); +} + +static void APIENTRY logNormal3b(GLbyte nx, GLbyte ny, GLbyte nz) +{ + SIG ("glNormal3b" ); + dllNormal3b( nx, ny, nz ); +} + +static void APIENTRY logNormal3bv(const GLbyte *v) +{ + SIG( "glNormal3bv" ); + dllNormal3bv( v ); +} + +static void APIENTRY logNormal3d(GLdouble nx, GLdouble ny, GLdouble nz) +{ + SIG( "glNormal3d" ); + dllNormal3d( nx, ny, nz ); +} + +static void APIENTRY logNormal3dv(const GLdouble *v) +{ + SIG( "glNormal3dv" ); + dllNormal3dv( v ); +} + +static void APIENTRY logNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) +{ + SIG( "glNormal3f" ); + dllNormal3f( nx, ny, nz ); +} + +static void APIENTRY logNormal3fv(const GLfloat *v) +{ + SIG( "glNormal3fv" ); + dllNormal3fv( v ); +} +static void APIENTRY logNormal3i(GLint nx, GLint ny, GLint nz) +{ + SIG( "glNormal3i" ); + dllNormal3i( nx, ny, nz ); +} +static void APIENTRY logNormal3iv(const GLint *v) +{ + SIG( "glNormal3iv" ); + dllNormal3iv( v ); +} +static void APIENTRY logNormal3s(GLshort nx, GLshort ny, GLshort nz) +{ + SIG( "glNormal3s" ); + dllNormal3s( nx, ny, nz ); +} +static void APIENTRY logNormal3sv(const GLshort *v) +{ + SIG( "glNormal3sv" ); + dllNormal3sv( v ); +} +static void APIENTRY logNormalPointer(GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glNormalPointer" ); + dllNormalPointer( type, stride, pointer ); +} +static void APIENTRY logOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar) +{ + SIG( "glOrtho" ); + dllOrtho( left, right, bottom, top, zNear, zFar ); +} + +static void APIENTRY logPassThrough(GLfloat token) +{ + SIG( "glPassThrough" ); + dllPassThrough( token ); +} + +static void APIENTRY logPixelMapfv(GLenum map, GLsizei mapsize, const GLfloat *values) +{ + SIG( "glPixelMapfv" ); + dllPixelMapfv( map, mapsize, values ); +} + +static void APIENTRY logPixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values) +{ + SIG( "glPixelMapuiv" ); + dllPixelMapuiv( map, mapsize, values ); +} + +static void APIENTRY logPixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values) +{ + SIG( "glPixelMapusv" ); + dllPixelMapusv( map, mapsize, values ); +} +static void APIENTRY logPixelStoref(GLenum pname, GLfloat param) +{ + SIG( "glPixelStoref" ); + dllPixelStoref( pname, param ); +} +static void APIENTRY logPixelStorei(GLenum pname, GLint param) +{ + SIG( "glPixelStorei" ); + dllPixelStorei( pname, param ); +} +static void APIENTRY logPixelTransferf(GLenum pname, GLfloat param) +{ + SIG( "glPixelTransferf" ); + dllPixelTransferf( pname, param ); +} + +static void APIENTRY logPixelTransferi(GLenum pname, GLint param) +{ + SIG( "glPixelTransferi" ); + dllPixelTransferi( pname, param ); +} + +static void APIENTRY logPixelZoom(GLfloat xfactor, GLfloat yfactor) +{ + SIG( "glPixelZoom" ); + dllPixelZoom( xfactor, yfactor ); +} + +static void APIENTRY logPointSize(GLfloat size) +{ + SIG( "glPointSize" ); + dllPointSize( size ); +} + +static void APIENTRY logPolygonMode(GLenum face, GLenum mode) +{ + fprintf( glw_state.log_fp, "glPolygonMode( 0x%x, 0x%x )\n", face, mode ); + dllPolygonMode( face, mode ); +} + +static void APIENTRY logPolygonOffset(GLfloat factor, GLfloat units) +{ + SIG( "glPolygonOffset" ); + dllPolygonOffset( factor, units ); +} +static void APIENTRY logPolygonStipple(const GLubyte *mask ) +{ + SIG( "glPolygonStipple" ); + dllPolygonStipple( mask ); +} +static void APIENTRY logPopAttrib(void) +{ + SIG( "glPopAttrib" ); + dllPopAttrib(); +} + +static void APIENTRY logPopClientAttrib(void) +{ + SIG( "glPopClientAttrib" ); + dllPopClientAttrib(); +} + +static void APIENTRY logPopMatrix(void) +{ + SIG( "glPopMatrix" ); + dllPopMatrix(); +} + +static void APIENTRY logPopName(void) +{ + SIG( "glPopName" ); + dllPopName(); +} + +static void APIENTRY logPrioritizeTextures(GLsizei n, const GLuint *textures, const GLclampf *priorities) +{ + SIG( "glPrioritizeTextures" ); + dllPrioritizeTextures( n, textures, priorities ); +} + +static void APIENTRY logPushAttrib(GLbitfield mask) +{ + SIG( "glPushAttrib" ); + dllPushAttrib( mask ); +} + +static void APIENTRY logPushClientAttrib(GLbitfield mask) +{ + SIG( "glPushClientAttrib" ); + dllPushClientAttrib( mask ); +} + +static void APIENTRY logPushMatrix(void) +{ + SIG( "glPushMatrix" ); + dllPushMatrix(); +} + +static void APIENTRY logPushName(GLuint name) +{ + SIG( "glPushName" ); + dllPushName( name ); +} + +static void APIENTRY logRasterPos2d(GLdouble x, GLdouble y) +{ + SIG ("glRasterPot2d" ); + dllRasterPos2d( x, y ); +} + +static void APIENTRY logRasterPos2dv(const GLdouble *v) +{ + SIG( "glRasterPos2dv" ); + dllRasterPos2dv( v ); +} + +static void APIENTRY logRasterPos2f(GLfloat x, GLfloat y) +{ + SIG( "glRasterPos2f" ); + dllRasterPos2f( x, y ); +} +static void APIENTRY logRasterPos2fv(const GLfloat *v) +{ + SIG( "glRasterPos2dv" ); + dllRasterPos2fv( v ); +} +static void APIENTRY logRasterPos2i(GLint x, GLint y) +{ + SIG( "glRasterPos2if" ); + dllRasterPos2i( x, y ); +} +static void APIENTRY logRasterPos2iv(const GLint *v) +{ + SIG( "glRasterPos2iv" ); + dllRasterPos2iv( v ); +} +static void APIENTRY logRasterPos2s(GLshort x, GLshort y) +{ + SIG( "glRasterPos2s" ); + dllRasterPos2s( x, y ); +} +static void APIENTRY logRasterPos2sv(const GLshort *v) +{ + SIG( "glRasterPos2sv" ); + dllRasterPos2sv( v ); +} +static void APIENTRY logRasterPos3d(GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glRasterPos3d" ); + dllRasterPos3d( x, y, z ); +} +static void APIENTRY logRasterPos3dv(const GLdouble *v) +{ + SIG( "glRasterPos3dv" ); + dllRasterPos3dv( v ); +} +static void APIENTRY logRasterPos3f(GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glRasterPos3f" ); + dllRasterPos3f( x, y, z ); +} +static void APIENTRY logRasterPos3fv(const GLfloat *v) +{ + SIG( "glRasterPos3fv" ); + dllRasterPos3fv( v ); +} +static void APIENTRY logRasterPos3i(GLint x, GLint y, GLint z) +{ + SIG( "glRasterPos3i" ); + dllRasterPos3i( x, y, z ); +} +static void APIENTRY logRasterPos3iv(const GLint *v) +{ + SIG( "glRasterPos3iv" ); + dllRasterPos3iv( v ); +} +static void APIENTRY logRasterPos3s(GLshort x, GLshort y, GLshort z) +{ + SIG( "glRasterPos3s" ); + dllRasterPos3s( x, y, z ); +} +static void APIENTRY logRasterPos3sv(const GLshort *v) +{ + SIG( "glRasterPos3sv" ); + dllRasterPos3sv( v ); +} +static void APIENTRY logRasterPos4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + SIG( "glRasterPos4d" ); + dllRasterPos4d( x, y, z, w ); +} +static void APIENTRY logRasterPos4dv(const GLdouble *v) +{ + SIG( "glRasterPos4dv" ); + dllRasterPos4dv( v ); +} +static void APIENTRY logRasterPos4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + SIG( "glRasterPos4f" ); + dllRasterPos4f( x, y, z, w ); +} +static void APIENTRY logRasterPos4fv(const GLfloat *v) +{ + SIG( "glRasterPos4fv" ); + dllRasterPos4fv( v ); +} +static void APIENTRY logRasterPos4i(GLint x, GLint y, GLint z, GLint w) +{ + SIG( "glRasterPos4i" ); + dllRasterPos4i( x, y, z, w ); +} +static void APIENTRY logRasterPos4iv(const GLint *v) +{ + SIG( "glRasterPos4iv" ); + dllRasterPos4iv( v ); +} +static void APIENTRY logRasterPos4s(GLshort x, GLshort y, GLshort z, GLshort w) +{ + SIG( "glRasterPos4s" ); + dllRasterPos4s( x, y, z, w ); +} +static void APIENTRY logRasterPos4sv(const GLshort *v) +{ + SIG( "glRasterPos4sv" ); + dllRasterPos4sv( v ); +} +static void APIENTRY logReadBuffer(GLenum mode) +{ + SIG( "glReadBuffer" ); + dllReadBuffer( mode ); +} +static void APIENTRY logReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) +{ + SIG( "glReadPixels" ); + dllReadPixels( x, y, width, height, format, type, pixels ); +} + +static void APIENTRY logRectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) +{ + SIG( "glRectd" ); + dllRectd( x1, y1, x2, y2 ); +} + +static void APIENTRY logRectdv(const GLdouble *v1, const GLdouble *v2) +{ + SIG( "glRectdv" ); + dllRectdv( v1, v2 ); +} + +static void APIENTRY logRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) +{ + SIG( "glRectf" ); + dllRectf( x1, y1, x2, y2 ); +} + +static void APIENTRY logRectfv(const GLfloat *v1, const GLfloat *v2) +{ + SIG( "glRectfv" ); + dllRectfv( v1, v2 ); +} +static void APIENTRY logRecti(GLint x1, GLint y1, GLint x2, GLint y2) +{ + SIG( "glRecti" ); + dllRecti( x1, y1, x2, y2 ); +} +static void APIENTRY logRectiv(const GLint *v1, const GLint *v2) +{ + SIG( "glRectiv" ); + dllRectiv( v1, v2 ); +} +static void APIENTRY logRects(GLshort x1, GLshort y1, GLshort x2, GLshort y2) +{ + SIG( "glRects" ); + dllRects( x1, y1, x2, y2 ); +} +static void APIENTRY logRectsv(const GLshort *v1, const GLshort *v2) +{ + SIG( "glRectsv" ); + dllRectsv( v1, v2 ); +} +static GLint APIENTRY logRenderMode(GLenum mode) +{ + SIG( "glRenderMode" ); + return dllRenderMode( mode ); +} +static void APIENTRY logRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glRotated" ); + dllRotated( angle, x, y, z ); +} + +static void APIENTRY logRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glRotatef" ); + dllRotatef( angle, x, y, z ); +} + +static void APIENTRY logScaled(GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glScaled" ); + dllScaled( x, y, z ); +} + +static void APIENTRY logScalef(GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glScalef" ); + dllScalef( x, y, z ); +} + +static void APIENTRY logScissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + SIG( "glScissor" ); + dllScissor( x, y, width, height ); +} + +static void APIENTRY logSelectBuffer(GLsizei size, GLuint *buffer) +{ + SIG( "glSelectBuffer" ); + dllSelectBuffer( size, buffer ); +} + +static void APIENTRY logShadeModel(GLenum mode) +{ + SIG( "glShadeModel" ); + dllShadeModel( mode ); +} + +static void APIENTRY logStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + SIG( "glStencilFunc" ); + dllStencilFunc( func, ref, mask ); +} + +static void APIENTRY logStencilMask(GLuint mask) +{ + SIG( "glStencilMask" ); + dllStencilMask( mask ); +} + +static void APIENTRY logStencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + SIG( "glStencilOp" ); + dllStencilOp( fail, zfail, zpass ); +} + +static void APIENTRY logTexCoord1d(GLdouble s) +{ + SIG( "glTexCoord1d" ); + dllTexCoord1d( s ); +} + +static void APIENTRY logTexCoord1dv(const GLdouble *v) +{ + SIG( "glTexCoord1dv" ); + dllTexCoord1dv( v ); +} + +static void APIENTRY logTexCoord1f(GLfloat s) +{ + SIG( "glTexCoord1f" ); + dllTexCoord1f( s ); +} +static void APIENTRY logTexCoord1fv(const GLfloat *v) +{ + SIG( "glTexCoord1fv" ); + dllTexCoord1fv( v ); +} +static void APIENTRY logTexCoord1i(GLint s) +{ + SIG( "glTexCoord1i" ); + dllTexCoord1i( s ); +} +static void APIENTRY logTexCoord1iv(const GLint *v) +{ + SIG( "glTexCoord1iv" ); + dllTexCoord1iv( v ); +} +static void APIENTRY logTexCoord1s(GLshort s) +{ + SIG( "glTexCoord1s" ); + dllTexCoord1s( s ); +} +static void APIENTRY logTexCoord1sv(const GLshort *v) +{ + SIG( "glTexCoord1sv" ); + dllTexCoord1sv( v ); +} +static void APIENTRY logTexCoord2d(GLdouble s, GLdouble t) +{ + SIG( "glTexCoord2d" ); + dllTexCoord2d( s, t ); +} + +static void APIENTRY logTexCoord2dv(const GLdouble *v) +{ + SIG( "glTexCoord2dv" ); + dllTexCoord2dv( v ); +} +static void APIENTRY logTexCoord2f(GLfloat s, GLfloat t) +{ + SIG( "glTexCoord2f" ); + dllTexCoord2f( s, t ); +} +static void APIENTRY logTexCoord2fv(const GLfloat *v) +{ + SIG( "glTexCoord2fv" ); + dllTexCoord2fv( v ); +} +static void APIENTRY logTexCoord2i(GLint s, GLint t) +{ + SIG( "glTexCoord2i" ); + dllTexCoord2i( s, t ); +} +static void APIENTRY logTexCoord2iv(const GLint *v) +{ + SIG( "glTexCoord2iv" ); + dllTexCoord2iv( v ); +} +static void APIENTRY logTexCoord2s(GLshort s, GLshort t) +{ + SIG( "glTexCoord2s" ); + dllTexCoord2s( s, t ); +} +static void APIENTRY logTexCoord2sv(const GLshort *v) +{ + SIG( "glTexCoord2sv" ); + dllTexCoord2sv( v ); +} +static void APIENTRY logTexCoord3d(GLdouble s, GLdouble t, GLdouble r) +{ + SIG( "glTexCoord3d" ); + dllTexCoord3d( s, t, r ); +} +static void APIENTRY logTexCoord3dv(const GLdouble *v) +{ + SIG( "glTexCoord3dv" ); + dllTexCoord3dv( v ); +} +static void APIENTRY logTexCoord3f(GLfloat s, GLfloat t, GLfloat r) +{ + SIG( "glTexCoord3f" ); + dllTexCoord3f( s, t, r ); +} +static void APIENTRY logTexCoord3fv(const GLfloat *v) +{ + SIG( "glTexCoord3fv" ); + dllTexCoord3fv( v ); +} +static void APIENTRY logTexCoord3i(GLint s, GLint t, GLint r) +{ + SIG( "glTexCoord3i" ); + dllTexCoord3i( s, t, r ); +} +static void APIENTRY logTexCoord3iv(const GLint *v) +{ + SIG( "glTexCoord3iv" ); + dllTexCoord3iv( v ); +} +static void APIENTRY logTexCoord3s(GLshort s, GLshort t, GLshort r) +{ + SIG( "glTexCoord3s" ); + dllTexCoord3s( s, t, r ); +} +static void APIENTRY logTexCoord3sv(const GLshort *v) +{ + SIG( "glTexCoord3sv" ); + dllTexCoord3sv( v ); +} +static void APIENTRY logTexCoord4d(GLdouble s, GLdouble t, GLdouble r, GLdouble q) +{ + SIG( "glTexCoord4d" ); + dllTexCoord4d( s, t, r, q ); +} +static void APIENTRY logTexCoord4dv(const GLdouble *v) +{ + SIG( "glTexCoord4dv" ); + dllTexCoord4dv( v ); +} +static void APIENTRY logTexCoord4f(GLfloat s, GLfloat t, GLfloat r, GLfloat q) +{ + SIG( "glTexCoord4f" ); + dllTexCoord4f( s, t, r, q ); +} +static void APIENTRY logTexCoord4fv(const GLfloat *v) +{ + SIG( "glTexCoord4fv" ); + dllTexCoord4fv( v ); +} +static void APIENTRY logTexCoord4i(GLint s, GLint t, GLint r, GLint q) +{ + SIG( "glTexCoord4i" ); + dllTexCoord4i( s, t, r, q ); +} +static void APIENTRY logTexCoord4iv(const GLint *v) +{ + SIG( "glTexCoord4iv" ); + dllTexCoord4iv( v ); +} +static void APIENTRY logTexCoord4s(GLshort s, GLshort t, GLshort r, GLshort q) +{ + SIG( "glTexCoord4s" ); + dllTexCoord4s( s, t, r, q ); +} +static void APIENTRY logTexCoord4sv(const GLshort *v) +{ + SIG( "glTexCoord4sv" ); + dllTexCoord4sv( v ); +} +static void APIENTRY logTexCoordPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glTexCoordPointer" ); + dllTexCoordPointer( size, type, stride, pointer ); +} + +static void APIENTRY logTexEnvf(GLenum target, GLenum pname, GLfloat param) +{ + fprintf( glw_state.log_fp, "glTexEnvf( 0x%x, 0x%x, %f )\n", target, pname, param ); + dllTexEnvf( target, pname, param ); +} + +static void APIENTRY logTexEnvfv(GLenum target, GLenum pname, const GLfloat *params) +{ + SIG( "glTexEnvfv" ); + dllTexEnvfv( target, pname, params ); +} + +static void APIENTRY logTexEnvi(GLenum target, GLenum pname, GLint param) +{ + fprintf( glw_state.log_fp, "glTexEnvi( 0x%x, 0x%x, 0x%x )\n", target, pname, param ); + dllTexEnvi( target, pname, param ); +} +static void APIENTRY logTexEnviv(GLenum target, GLenum pname, const GLint *params) +{ + SIG( "glTexEnviv" ); + dllTexEnviv( target, pname, params ); +} + +static void APIENTRY logTexGend(GLenum coord, GLenum pname, GLdouble param) +{ + SIG( "glTexGend" ); + dllTexGend( coord, pname, param ); +} + +static void APIENTRY logTexGendv(GLenum coord, GLenum pname, const GLdouble *params) +{ + SIG( "glTexGendv" ); + dllTexGendv( coord, pname, params ); +} + +static void APIENTRY logTexGenf(GLenum coord, GLenum pname, GLfloat param) +{ + SIG( "glTexGenf" ); + dllTexGenf( coord, pname, param ); +} +static void APIENTRY logTexGenfv(GLenum coord, GLenum pname, const GLfloat *params) +{ + SIG( "glTexGenfv" ); + dllTexGenfv( coord, pname, params ); +} +static void APIENTRY logTexGeni(GLenum coord, GLenum pname, GLint param) +{ + SIG( "glTexGeni" ); + dllTexGeni( coord, pname, param ); +} +static void APIENTRY logTexGeniv(GLenum coord, GLenum pname, const GLint *params) +{ + SIG( "glTexGeniv" ); + dllTexGeniv( coord, pname, params ); +} +static void APIENTRY logTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glTexImage1D" ); + dllTexImage1D( target, level, internalformat, width, border, format, type, pixels ); +} +static void APIENTRY logTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glTexImage2D" ); + dllTexImage2D( target, level, internalformat, width, height, border, format, type, pixels ); +} + +static void APIENTRY logTexParameterf(GLenum target, GLenum pname, GLfloat param) +{ + fprintf( glw_state.log_fp, "glTexParameterf( 0x%x, 0x%x, %f )\n", target, pname, param ); + dllTexParameterf( target, pname, param ); +} + +static void APIENTRY logTexParameterfv(GLenum target, GLenum pname, const GLfloat *params) +{ + SIG( "glTexParameterfv" ); + dllTexParameterfv( target, pname, params ); +} +static void APIENTRY logTexParameteri(GLenum target, GLenum pname, GLint param) +{ + fprintf( glw_state.log_fp, "glTexParameteri( 0x%x, 0x%x, 0x%x )\n", target, pname, param ); + dllTexParameteri( target, pname, param ); +} +static void APIENTRY logTexParameteriv(GLenum target, GLenum pname, const GLint *params) +{ + SIG( "glTexParameteriv" ); + dllTexParameteriv( target, pname, params ); +} +static void APIENTRY logTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glTexSubImage1D" ); + dllTexSubImage1D( target, level, xoffset, width, format, type, pixels ); +} +static void APIENTRY logTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + SIG( "glTexSubImage2D" ); + dllTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, pixels ); +} +static void APIENTRY logTranslated(GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glTranslated" ); + dllTranslated( x, y, z ); +} + +static void APIENTRY logTranslatef(GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glTranslatef" ); + dllTranslatef( x, y, z ); +} + +static void APIENTRY logVertex2d(GLdouble x, GLdouble y) +{ + SIG( "glVertex2d" ); + dllVertex2d( x, y ); +} + +static void APIENTRY logVertex2dv(const GLdouble *v) +{ + SIG( "glVertex2dv" ); + dllVertex2dv( v ); +} +static void APIENTRY logVertex2f(GLfloat x, GLfloat y) +{ + SIG( "glVertex2f" ); + dllVertex2f( x, y ); +} +static void APIENTRY logVertex2fv(const GLfloat *v) +{ + SIG( "glVertex2fv" ); + dllVertex2fv( v ); +} +static void APIENTRY logVertex2i(GLint x, GLint y) +{ + SIG( "glVertex2i" ); + dllVertex2i( x, y ); +} +static void APIENTRY logVertex2iv(const GLint *v) +{ + SIG( "glVertex2iv" ); + dllVertex2iv( v ); +} +static void APIENTRY logVertex2s(GLshort x, GLshort y) +{ + SIG( "glVertex2s" ); + dllVertex2s( x, y ); +} +static void APIENTRY logVertex2sv(const GLshort *v) +{ + SIG( "glVertex2sv" ); + dllVertex2sv( v ); +} +static void APIENTRY logVertex3d(GLdouble x, GLdouble y, GLdouble z) +{ + SIG( "glVertex3d" ); + dllVertex3d( x, y, z ); +} +static void APIENTRY logVertex3dv(const GLdouble *v) +{ + SIG( "glVertex3dv" ); + dllVertex3dv( v ); +} +static void APIENTRY logVertex3f(GLfloat x, GLfloat y, GLfloat z) +{ + SIG( "glVertex3f" ); + dllVertex3f( x, y, z ); +} +static void APIENTRY logVertex3fv(const GLfloat *v) +{ + SIG( "glVertex3fv" ); + dllVertex3fv( v ); +} +static void APIENTRY logVertex3i(GLint x, GLint y, GLint z) +{ + SIG( "glVertex3i" ); + dllVertex3i( x, y, z ); +} +static void APIENTRY logVertex3iv(const GLint *v) +{ + SIG( "glVertex3iv" ); + dllVertex3iv( v ); +} +static void APIENTRY logVertex3s(GLshort x, GLshort y, GLshort z) +{ + SIG( "glVertex3s" ); + dllVertex3s( x, y, z ); +} +static void APIENTRY logVertex3sv(const GLshort *v) +{ + SIG( "glVertex3sv" ); + dllVertex3sv( v ); +} +static void APIENTRY logVertex4d(GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + SIG( "glVertex4d" ); + dllVertex4d( x, y, z, w ); +} +static void APIENTRY logVertex4dv(const GLdouble *v) +{ + SIG( "glVertex4dv" ); + dllVertex4dv( v ); +} +static void APIENTRY logVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + SIG( "glVertex4f" ); + dllVertex4f( x, y, z, w ); +} +static void APIENTRY logVertex4fv(const GLfloat *v) +{ + SIG( "glVertex4fv" ); + dllVertex4fv( v ); +} +static void APIENTRY logVertex4i(GLint x, GLint y, GLint z, GLint w) +{ + SIG( "glVertex4i" ); + dllVertex4i( x, y, z, w ); +} +static void APIENTRY logVertex4iv(const GLint *v) +{ + SIG( "glVertex4iv" ); + dllVertex4iv( v ); +} +static void APIENTRY logVertex4s(GLshort x, GLshort y, GLshort z, GLshort w) +{ + SIG( "glVertex4s" ); + dllVertex4s( x, y, z, w ); +} +static void APIENTRY logVertex4sv(const GLshort *v) +{ + SIG( "glVertex4sv" ); + dllVertex4sv( v ); +} +static void APIENTRY logVertexPointer(GLint size, GLenum type, GLsizei stride, const void *pointer) +{ + SIG( "glVertexPointer" ); + dllVertexPointer( size, type, stride, pointer ); +} +static void APIENTRY logViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + SIG( "glViewport" ); + dllViewport( x, y, width, height ); +} + +/* +** QGL_Shutdown +** +** Unloads the specified DLL then nulls out all the proc pointers. +*/ +void QGL_Shutdown( void ) +{ + if ( glw_state.OpenGLLib ) + { + dlclose ( glw_state.OpenGLLib ); + glw_state.OpenGLLib = NULL; + } + + glw_state.OpenGLLib = NULL; + + qglAccum = NULL; + qglAlphaFunc = NULL; + qglAreTexturesResident = NULL; + qglArrayElement = NULL; + qglBegin = NULL; + qglBindTexture = NULL; + qglBitmap = NULL; + qglBlendFunc = NULL; + qglCallList = NULL; + qglCallLists = NULL; + qglClear = NULL; + qglClearAccum = NULL; + qglClearColor = NULL; + qglClearDepth = NULL; + qglClearIndex = NULL; + qglClearStencil = NULL; + qglClipPlane = NULL; + qglColor3b = NULL; + qglColor3bv = NULL; + qglColor3d = NULL; + qglColor3dv = NULL; + qglColor3f = NULL; + qglColor3fv = NULL; + qglColor3i = NULL; + qglColor3iv = NULL; + qglColor3s = NULL; + qglColor3sv = NULL; + qglColor3ub = NULL; + qglColor3ubv = NULL; + qglColor3ui = NULL; + qglColor3uiv = NULL; + qglColor3us = NULL; + qglColor3usv = NULL; + qglColor4b = NULL; + qglColor4bv = NULL; + qglColor4d = NULL; + qglColor4dv = NULL; + qglColor4f = NULL; + qglColor4fv = NULL; + qglColor4i = NULL; + qglColor4iv = NULL; + qglColor4s = NULL; + qglColor4sv = NULL; + qglColor4ub = NULL; + qglColor4ubv = NULL; + qglColor4ui = NULL; + qglColor4uiv = NULL; + qglColor4us = NULL; + qglColor4usv = NULL; + qglColorMask = NULL; + qglColorMaterial = NULL; + qglColorPointer = NULL; + qglCopyPixels = NULL; + qglCopyTexImage1D = NULL; + qglCopyTexImage2D = NULL; + qglCopyTexSubImage1D = NULL; + qglCopyTexSubImage2D = NULL; + qglCullFace = NULL; + qglDeleteLists = NULL; + qglDeleteTextures = NULL; + qglDepthFunc = NULL; + qglDepthMask = NULL; + qglDepthRange = NULL; + qglDisable = NULL; + qglDisableClientState = NULL; + qglDrawArrays = NULL; + qglDrawBuffer = NULL; + qglDrawElements = NULL; + qglDrawPixels = NULL; + qglEdgeFlag = NULL; + qglEdgeFlagPointer = NULL; + qglEdgeFlagv = NULL; + qglEnable = NULL; + qglEnableClientState = NULL; + qglEnd = NULL; + qglEndList = NULL; + qglEvalCoord1d = NULL; + qglEvalCoord1dv = NULL; + qglEvalCoord1f = NULL; + qglEvalCoord1fv = NULL; + qglEvalCoord2d = NULL; + qglEvalCoord2dv = NULL; + qglEvalCoord2f = NULL; + qglEvalCoord2fv = NULL; + qglEvalMesh1 = NULL; + qglEvalMesh2 = NULL; + qglEvalPoint1 = NULL; + qglEvalPoint2 = NULL; + qglFeedbackBuffer = NULL; + qglFinish = NULL; + qglFlush = NULL; + qglFogf = NULL; + qglFogfv = NULL; + qglFogi = NULL; + qglFogiv = NULL; + qglFrontFace = NULL; + qglFrustum = NULL; + qglGenLists = NULL; + qglGenTextures = NULL; + qglGetBooleanv = NULL; + qglGetClipPlane = NULL; + qglGetDoublev = NULL; + qglGetError = NULL; + qglGetFloatv = NULL; + qglGetIntegerv = NULL; + qglGetLightfv = NULL; + qglGetLightiv = NULL; + qglGetMapdv = NULL; + qglGetMapfv = NULL; + qglGetMapiv = NULL; + qglGetMaterialfv = NULL; + qglGetMaterialiv = NULL; + qglGetPixelMapfv = NULL; + qglGetPixelMapuiv = NULL; + qglGetPixelMapusv = NULL; + qglGetPointerv = NULL; + qglGetPolygonStipple = NULL; + qglGetString = NULL; + qglGetTexEnvfv = NULL; + qglGetTexEnviv = NULL; + qglGetTexGendv = NULL; + qglGetTexGenfv = NULL; + qglGetTexGeniv = NULL; + qglGetTexImage = NULL; + qglGetTexLevelParameterfv = NULL; + qglGetTexLevelParameteriv = NULL; + qglGetTexParameterfv = NULL; + qglGetTexParameteriv = NULL; + qglHint = NULL; + qglIndexMask = NULL; + qglIndexPointer = NULL; + qglIndexd = NULL; + qglIndexdv = NULL; + qglIndexf = NULL; + qglIndexfv = NULL; + qglIndexi = NULL; + qglIndexiv = NULL; + qglIndexs = NULL; + qglIndexsv = NULL; + qglIndexub = NULL; + qglIndexubv = NULL; + qglInitNames = NULL; + qglInterleavedArrays = NULL; + qglIsEnabled = NULL; + qglIsList = NULL; + qglIsTexture = NULL; + qglLightModelf = NULL; + qglLightModelfv = NULL; + qglLightModeli = NULL; + qglLightModeliv = NULL; + qglLightf = NULL; + qglLightfv = NULL; + qglLighti = NULL; + qglLightiv = NULL; + qglLineStipple = NULL; + qglLineWidth = NULL; + qglListBase = NULL; + qglLoadIdentity = NULL; + qglLoadMatrixd = NULL; + qglLoadMatrixf = NULL; + qglLoadName = NULL; + qglLogicOp = NULL; + qglMap1d = NULL; + qglMap1f = NULL; + qglMap2d = NULL; + qglMap2f = NULL; + qglMapGrid1d = NULL; + qglMapGrid1f = NULL; + qglMapGrid2d = NULL; + qglMapGrid2f = NULL; + qglMaterialf = NULL; + qglMaterialfv = NULL; + qglMateriali = NULL; + qglMaterialiv = NULL; + qglMatrixMode = NULL; + qglMultMatrixd = NULL; + qglMultMatrixf = NULL; + qglNewList = NULL; + qglNormal3b = NULL; + qglNormal3bv = NULL; + qglNormal3d = NULL; + qglNormal3dv = NULL; + qglNormal3f = NULL; + qglNormal3fv = NULL; + qglNormal3i = NULL; + qglNormal3iv = NULL; + qglNormal3s = NULL; + qglNormal3sv = NULL; + qglNormalPointer = NULL; + qglOrtho = NULL; + qglPassThrough = NULL; + qglPixelMapfv = NULL; + qglPixelMapuiv = NULL; + qglPixelMapusv = NULL; + qglPixelStoref = NULL; + qglPixelStorei = NULL; + qglPixelTransferf = NULL; + qglPixelTransferi = NULL; + qglPixelZoom = NULL; + qglPointSize = NULL; + qglPolygonMode = NULL; + qglPolygonOffset = NULL; + qglPolygonStipple = NULL; + qglPopAttrib = NULL; + qglPopClientAttrib = NULL; + qglPopMatrix = NULL; + qglPopName = NULL; + qglPrioritizeTextures = NULL; + qglPushAttrib = NULL; + qglPushClientAttrib = NULL; + qglPushMatrix = NULL; + qglPushName = NULL; + qglRasterPos2d = NULL; + qglRasterPos2dv = NULL; + qglRasterPos2f = NULL; + qglRasterPos2fv = NULL; + qglRasterPos2i = NULL; + qglRasterPos2iv = NULL; + qglRasterPos2s = NULL; + qglRasterPos2sv = NULL; + qglRasterPos3d = NULL; + qglRasterPos3dv = NULL; + qglRasterPos3f = NULL; + qglRasterPos3fv = NULL; + qglRasterPos3i = NULL; + qglRasterPos3iv = NULL; + qglRasterPos3s = NULL; + qglRasterPos3sv = NULL; + qglRasterPos4d = NULL; + qglRasterPos4dv = NULL; + qglRasterPos4f = NULL; + qglRasterPos4fv = NULL; + qglRasterPos4i = NULL; + qglRasterPos4iv = NULL; + qglRasterPos4s = NULL; + qglRasterPos4sv = NULL; + qglReadBuffer = NULL; + qglReadPixels = NULL; + qglRectd = NULL; + qglRectdv = NULL; + qglRectf = NULL; + qglRectfv = NULL; + qglRecti = NULL; + qglRectiv = NULL; + qglRects = NULL; + qglRectsv = NULL; + qglRenderMode = NULL; + qglRotated = NULL; + qglRotatef = NULL; + qglScaled = NULL; + qglScalef = NULL; + qglScissor = NULL; + qglSelectBuffer = NULL; + qglShadeModel = NULL; + qglStencilFunc = NULL; + qglStencilMask = NULL; + qglStencilOp = NULL; + qglTexCoord1d = NULL; + qglTexCoord1dv = NULL; + qglTexCoord1f = NULL; + qglTexCoord1fv = NULL; + qglTexCoord1i = NULL; + qglTexCoord1iv = NULL; + qglTexCoord1s = NULL; + qglTexCoord1sv = NULL; + qglTexCoord2d = NULL; + qglTexCoord2dv = NULL; + qglTexCoord2f = NULL; + qglTexCoord2fv = NULL; + qglTexCoord2i = NULL; + qglTexCoord2iv = NULL; + qglTexCoord2s = NULL; + qglTexCoord2sv = NULL; + qglTexCoord3d = NULL; + qglTexCoord3dv = NULL; + qglTexCoord3f = NULL; + qglTexCoord3fv = NULL; + qglTexCoord3i = NULL; + qglTexCoord3iv = NULL; + qglTexCoord3s = NULL; + qglTexCoord3sv = NULL; + qglTexCoord4d = NULL; + qglTexCoord4dv = NULL; + qglTexCoord4f = NULL; + qglTexCoord4fv = NULL; + qglTexCoord4i = NULL; + qglTexCoord4iv = NULL; + qglTexCoord4s = NULL; + qglTexCoord4sv = NULL; + qglTexCoordPointer = NULL; + qglTexEnvf = NULL; + qglTexEnvfv = NULL; + qglTexEnvi = NULL; + qglTexEnviv = NULL; + qglTexGend = NULL; + qglTexGendv = NULL; + qglTexGenf = NULL; + qglTexGenfv = NULL; + qglTexGeni = NULL; + qglTexGeniv = NULL; + qglTexImage1D = NULL; + qglTexImage2D = NULL; + qglTexParameterf = NULL; + qglTexParameterfv = NULL; + qglTexParameteri = NULL; + qglTexParameteriv = NULL; + qglTexSubImage1D = NULL; + qglTexSubImage2D = NULL; + qglTranslated = NULL; + qglTranslatef = NULL; + qglVertex2d = NULL; + qglVertex2dv = NULL; + qglVertex2f = NULL; + qglVertex2fv = NULL; + qglVertex2i = NULL; + qglVertex2iv = NULL; + qglVertex2s = NULL; + qglVertex2sv = NULL; + qglVertex3d = NULL; + qglVertex3dv = NULL; + qglVertex3f = NULL; + qglVertex3fv = NULL; + qglVertex3i = NULL; + qglVertex3iv = NULL; + qglVertex3s = NULL; + qglVertex3sv = NULL; + qglVertex4d = NULL; + qglVertex4dv = NULL; + qglVertex4f = NULL; + qglVertex4fv = NULL; + qglVertex4i = NULL; + qglVertex4iv = NULL; + qglVertex4s = NULL; + qglVertex4sv = NULL; + qglVertexPointer = NULL; + qglViewport = NULL; + + qfxMesaCreateContext = NULL; + qfxMesaCreateBestContext = NULL; + qfxMesaDestroyContext = NULL; + qfxMesaMakeCurrent = NULL; + qfxMesaGetCurrentContext = NULL; + qfxMesaSwapBuffers = NULL; + + qglXChooseVisual = NULL; + qglXCreateContext = NULL; + qglXDestroyContext = NULL; + qglXMakeCurrent = NULL; + qglXCopyContext = NULL; + qglXSwapBuffers = NULL; +} + +#define GPA( a ) dlsym( glw_state.OpenGLLib, a ) + +void *qwglGetProcAddress(char *symbol) +{ + if (glw_state.OpenGLLib) + return GPA ( symbol ); + return NULL; +} + +/* +** QGL_Init +** +** This is responsible for binding our qgl function pointers to +** the appropriate GL stuff. In Windows this means doing a +** LoadLibrary and a bunch of calls to GetProcAddress. On other +** operating systems we need to do the right thing, whatever that +** might be. +** +*/ + +qboolean QGL_Init( const char *dllname ) +{ +#if 0 //FIXME + // update 3Dfx gamma irrespective of underlying DLL + { + char envbuffer[1024]; + float g; + + g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F; + Com_sprintf( envbuffer, sizeof(envbuffer), "SSTV2_GAMMA=%f", g ); + putenv( envbuffer ); + Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g ); + putenv( envbuffer ); + } +#endif + + if ( ( glw_state.OpenGLLib = dlopen( dllname, RTLD_LAZY ) ) == 0 ) + { + char fn[1024]; + FILE *fp; + extern uid_t saved_euid; // unix_main.c + +//fprintf(stdout, "uid=%d,euid=%d\n", getuid(), geteuid()); fflush(stdout); + + // if we are not setuid, try current directory + if (getuid() == saved_euid) { + getcwd(fn, sizeof(fn)); + Q_strcat(fn, sizeof(fn), "/"); + Q_strcat(fn, sizeof(fn), dllname); + + if ( ( glw_state.OpenGLLib = dlopen( fn, RTLD_LAZY ) ) == 0 ) { + ri.Printf(PRINT_ALL, "QGL_Init: Can't load %s from /etc/ld.so.conf or current dir: %s\n", dllname, dlerror()); + return qfalse; + } + } else { + ri.Printf(PRINT_ALL, "QGL_Init: Can't load %s from /etc/ld.so.conf: %s\n", dllname, dlerror()); + return qfalse; + } + } + + qglAccum = dllAccum = GPA( "glAccum" ); + qglAlphaFunc = dllAlphaFunc = GPA( "glAlphaFunc" ); + qglAreTexturesResident = dllAreTexturesResident = GPA( "glAreTexturesResident" ); + qglArrayElement = dllArrayElement = GPA( "glArrayElement" ); + qglBegin = dllBegin = GPA( "glBegin" ); + qglBindTexture = dllBindTexture = GPA( "glBindTexture" ); + qglBitmap = dllBitmap = GPA( "glBitmap" ); + qglBlendFunc = dllBlendFunc = GPA( "glBlendFunc" ); + qglCallList = dllCallList = GPA( "glCallList" ); + qglCallLists = dllCallLists = GPA( "glCallLists" ); + qglClear = dllClear = GPA( "glClear" ); + qglClearAccum = dllClearAccum = GPA( "glClearAccum" ); + qglClearColor = dllClearColor = GPA( "glClearColor" ); + qglClearDepth = dllClearDepth = GPA( "glClearDepth" ); + qglClearIndex = dllClearIndex = GPA( "glClearIndex" ); + qglClearStencil = dllClearStencil = GPA( "glClearStencil" ); + qglClipPlane = dllClipPlane = GPA( "glClipPlane" ); + qglColor3b = dllColor3b = GPA( "glColor3b" ); + qglColor3bv = dllColor3bv = GPA( "glColor3bv" ); + qglColor3d = dllColor3d = GPA( "glColor3d" ); + qglColor3dv = dllColor3dv = GPA( "glColor3dv" ); + qglColor3f = dllColor3f = GPA( "glColor3f" ); + qglColor3fv = dllColor3fv = GPA( "glColor3fv" ); + qglColor3i = dllColor3i = GPA( "glColor3i" ); + qglColor3iv = dllColor3iv = GPA( "glColor3iv" ); + qglColor3s = dllColor3s = GPA( "glColor3s" ); + qglColor3sv = dllColor3sv = GPA( "glColor3sv" ); + qglColor3ub = dllColor3ub = GPA( "glColor3ub" ); + qglColor3ubv = dllColor3ubv = GPA( "glColor3ubv" ); + qglColor3ui = dllColor3ui = GPA( "glColor3ui" ); + qglColor3uiv = dllColor3uiv = GPA( "glColor3uiv" ); + qglColor3us = dllColor3us = GPA( "glColor3us" ); + qglColor3usv = dllColor3usv = GPA( "glColor3usv" ); + qglColor4b = dllColor4b = GPA( "glColor4b" ); + qglColor4bv = dllColor4bv = GPA( "glColor4bv" ); + qglColor4d = dllColor4d = GPA( "glColor4d" ); + qglColor4dv = dllColor4dv = GPA( "glColor4dv" ); + qglColor4f = dllColor4f = GPA( "glColor4f" ); + qglColor4fv = dllColor4fv = GPA( "glColor4fv" ); + qglColor4i = dllColor4i = GPA( "glColor4i" ); + qglColor4iv = dllColor4iv = GPA( "glColor4iv" ); + qglColor4s = dllColor4s = GPA( "glColor4s" ); + qglColor4sv = dllColor4sv = GPA( "glColor4sv" ); + qglColor4ub = dllColor4ub = GPA( "glColor4ub" ); + qglColor4ubv = dllColor4ubv = GPA( "glColor4ubv" ); + qglColor4ui = dllColor4ui = GPA( "glColor4ui" ); + qglColor4uiv = dllColor4uiv = GPA( "glColor4uiv" ); + qglColor4us = dllColor4us = GPA( "glColor4us" ); + qglColor4usv = dllColor4usv = GPA( "glColor4usv" ); + qglColorMask = dllColorMask = GPA( "glColorMask" ); + qglColorMaterial = dllColorMaterial = GPA( "glColorMaterial" ); + qglColorPointer = dllColorPointer = GPA( "glColorPointer" ); + qglCopyPixels = dllCopyPixels = GPA( "glCopyPixels" ); + qglCopyTexImage1D = dllCopyTexImage1D = GPA( "glCopyTexImage1D" ); + qglCopyTexImage2D = dllCopyTexImage2D = GPA( "glCopyTexImage2D" ); + qglCopyTexSubImage1D = dllCopyTexSubImage1D = GPA( "glCopyTexSubImage1D" ); + qglCopyTexSubImage2D = dllCopyTexSubImage2D = GPA( "glCopyTexSubImage2D" ); + qglCullFace = dllCullFace = GPA( "glCullFace" ); + qglDeleteLists = dllDeleteLists = GPA( "glDeleteLists" ); + qglDeleteTextures = dllDeleteTextures = GPA( "glDeleteTextures" ); + qglDepthFunc = dllDepthFunc = GPA( "glDepthFunc" ); + qglDepthMask = dllDepthMask = GPA( "glDepthMask" ); + qglDepthRange = dllDepthRange = GPA( "glDepthRange" ); + qglDisable = dllDisable = GPA( "glDisable" ); + qglDisableClientState = dllDisableClientState = GPA( "glDisableClientState" ); + qglDrawArrays = dllDrawArrays = GPA( "glDrawArrays" ); + qglDrawBuffer = dllDrawBuffer = GPA( "glDrawBuffer" ); + qglDrawElements = dllDrawElements = GPA( "glDrawElements" ); + qglDrawPixels = dllDrawPixels = GPA( "glDrawPixels" ); + qglEdgeFlag = dllEdgeFlag = GPA( "glEdgeFlag" ); + qglEdgeFlagPointer = dllEdgeFlagPointer = GPA( "glEdgeFlagPointer" ); + qglEdgeFlagv = dllEdgeFlagv = GPA( "glEdgeFlagv" ); + qglEnable = dllEnable = GPA( "glEnable" ); + qglEnableClientState = dllEnableClientState = GPA( "glEnableClientState" ); + qglEnd = dllEnd = GPA( "glEnd" ); + qglEndList = dllEndList = GPA( "glEndList" ); + qglEvalCoord1d = dllEvalCoord1d = GPA( "glEvalCoord1d" ); + qglEvalCoord1dv = dllEvalCoord1dv = GPA( "glEvalCoord1dv" ); + qglEvalCoord1f = dllEvalCoord1f = GPA( "glEvalCoord1f" ); + qglEvalCoord1fv = dllEvalCoord1fv = GPA( "glEvalCoord1fv" ); + qglEvalCoord2d = dllEvalCoord2d = GPA( "glEvalCoord2d" ); + qglEvalCoord2dv = dllEvalCoord2dv = GPA( "glEvalCoord2dv" ); + qglEvalCoord2f = dllEvalCoord2f = GPA( "glEvalCoord2f" ); + qglEvalCoord2fv = dllEvalCoord2fv = GPA( "glEvalCoord2fv" ); + qglEvalMesh1 = dllEvalMesh1 = GPA( "glEvalMesh1" ); + qglEvalMesh2 = dllEvalMesh2 = GPA( "glEvalMesh2" ); + qglEvalPoint1 = dllEvalPoint1 = GPA( "glEvalPoint1" ); + qglEvalPoint2 = dllEvalPoint2 = GPA( "glEvalPoint2" ); + qglFeedbackBuffer = dllFeedbackBuffer = GPA( "glFeedbackBuffer" ); + qglFinish = dllFinish = GPA( "glFinish" ); + qglFlush = dllFlush = GPA( "glFlush" ); + qglFogf = dllFogf = GPA( "glFogf" ); + qglFogfv = dllFogfv = GPA( "glFogfv" ); + qglFogi = dllFogi = GPA( "glFogi" ); + qglFogiv = dllFogiv = GPA( "glFogiv" ); + qglFrontFace = dllFrontFace = GPA( "glFrontFace" ); + qglFrustum = dllFrustum = GPA( "glFrustum" ); + qglGenLists = dllGenLists = GPA( "glGenLists" ); + qglGenTextures = dllGenTextures = GPA( "glGenTextures" ); + qglGetBooleanv = dllGetBooleanv = GPA( "glGetBooleanv" ); + qglGetClipPlane = dllGetClipPlane = GPA( "glGetClipPlane" ); + qglGetDoublev = dllGetDoublev = GPA( "glGetDoublev" ); + qglGetError = dllGetError = GPA( "glGetError" ); + qglGetFloatv = dllGetFloatv = GPA( "glGetFloatv" ); + qglGetIntegerv = dllGetIntegerv = GPA( "glGetIntegerv" ); + qglGetLightfv = dllGetLightfv = GPA( "glGetLightfv" ); + qglGetLightiv = dllGetLightiv = GPA( "glGetLightiv" ); + qglGetMapdv = dllGetMapdv = GPA( "glGetMapdv" ); + qglGetMapfv = dllGetMapfv = GPA( "glGetMapfv" ); + qglGetMapiv = dllGetMapiv = GPA( "glGetMapiv" ); + qglGetMaterialfv = dllGetMaterialfv = GPA( "glGetMaterialfv" ); + qglGetMaterialiv = dllGetMaterialiv = GPA( "glGetMaterialiv" ); + qglGetPixelMapfv = dllGetPixelMapfv = GPA( "glGetPixelMapfv" ); + qglGetPixelMapuiv = dllGetPixelMapuiv = GPA( "glGetPixelMapuiv" ); + qglGetPixelMapusv = dllGetPixelMapusv = GPA( "glGetPixelMapusv" ); + qglGetPointerv = dllGetPointerv = GPA( "glGetPointerv" ); + qglGetPolygonStipple = dllGetPolygonStipple = GPA( "glGetPolygonStipple" ); + qglGetString = dllGetString = GPA( "glGetString" ); + qglGetTexEnvfv = dllGetTexEnvfv = GPA( "glGetTexEnvfv" ); + qglGetTexEnviv = dllGetTexEnviv = GPA( "glGetTexEnviv" ); + qglGetTexGendv = dllGetTexGendv = GPA( "glGetTexGendv" ); + qglGetTexGenfv = dllGetTexGenfv = GPA( "glGetTexGenfv" ); + qglGetTexGeniv = dllGetTexGeniv = GPA( "glGetTexGeniv" ); + qglGetTexImage = dllGetTexImage = GPA( "glGetTexImage" ); + qglGetTexLevelParameterfv = dllGetTexLevelParameterfv = GPA( "glGetLevelParameterfv" ); + qglGetTexLevelParameteriv = dllGetTexLevelParameteriv = GPA( "glGetLevelParameteriv" ); + qglGetTexParameterfv = dllGetTexParameterfv = GPA( "glGetTexParameterfv" ); + qglGetTexParameteriv = dllGetTexParameteriv = GPA( "glGetTexParameteriv" ); + qglHint = dllHint = GPA( "glHint" ); + qglIndexMask = dllIndexMask = GPA( "glIndexMask" ); + qglIndexPointer = dllIndexPointer = GPA( "glIndexPointer" ); + qglIndexd = dllIndexd = GPA( "glIndexd" ); + qglIndexdv = dllIndexdv = GPA( "glIndexdv" ); + qglIndexf = dllIndexf = GPA( "glIndexf" ); + qglIndexfv = dllIndexfv = GPA( "glIndexfv" ); + qglIndexi = dllIndexi = GPA( "glIndexi" ); + qglIndexiv = dllIndexiv = GPA( "glIndexiv" ); + qglIndexs = dllIndexs = GPA( "glIndexs" ); + qglIndexsv = dllIndexsv = GPA( "glIndexsv" ); + qglIndexub = dllIndexub = GPA( "glIndexub" ); + qglIndexubv = dllIndexubv = GPA( "glIndexubv" ); + qglInitNames = dllInitNames = GPA( "glInitNames" ); + qglInterleavedArrays = dllInterleavedArrays = GPA( "glInterleavedArrays" ); + qglIsEnabled = dllIsEnabled = GPA( "glIsEnabled" ); + qglIsList = dllIsList = GPA( "glIsList" ); + qglIsTexture = dllIsTexture = GPA( "glIsTexture" ); + qglLightModelf = dllLightModelf = GPA( "glLightModelf" ); + qglLightModelfv = dllLightModelfv = GPA( "glLightModelfv" ); + qglLightModeli = dllLightModeli = GPA( "glLightModeli" ); + qglLightModeliv = dllLightModeliv = GPA( "glLightModeliv" ); + qglLightf = dllLightf = GPA( "glLightf" ); + qglLightfv = dllLightfv = GPA( "glLightfv" ); + qglLighti = dllLighti = GPA( "glLighti" ); + qglLightiv = dllLightiv = GPA( "glLightiv" ); + qglLineStipple = dllLineStipple = GPA( "glLineStipple" ); + qglLineWidth = dllLineWidth = GPA( "glLineWidth" ); + qglListBase = dllListBase = GPA( "glListBase" ); + qglLoadIdentity = dllLoadIdentity = GPA( "glLoadIdentity" ); + qglLoadMatrixd = dllLoadMatrixd = GPA( "glLoadMatrixd" ); + qglLoadMatrixf = dllLoadMatrixf = GPA( "glLoadMatrixf" ); + qglLoadName = dllLoadName = GPA( "glLoadName" ); + qglLogicOp = dllLogicOp = GPA( "glLogicOp" ); + qglMap1d = dllMap1d = GPA( "glMap1d" ); + qglMap1f = dllMap1f = GPA( "glMap1f" ); + qglMap2d = dllMap2d = GPA( "glMap2d" ); + qglMap2f = dllMap2f = GPA( "glMap2f" ); + qglMapGrid1d = dllMapGrid1d = GPA( "glMapGrid1d" ); + qglMapGrid1f = dllMapGrid1f = GPA( "glMapGrid1f" ); + qglMapGrid2d = dllMapGrid2d = GPA( "glMapGrid2d" ); + qglMapGrid2f = dllMapGrid2f = GPA( "glMapGrid2f" ); + qglMaterialf = dllMaterialf = GPA( "glMaterialf" ); + qglMaterialfv = dllMaterialfv = GPA( "glMaterialfv" ); + qglMateriali = dllMateriali = GPA( "glMateriali" ); + qglMaterialiv = dllMaterialiv = GPA( "glMaterialiv" ); + qglMatrixMode = dllMatrixMode = GPA( "glMatrixMode" ); + qglMultMatrixd = dllMultMatrixd = GPA( "glMultMatrixd" ); + qglMultMatrixf = dllMultMatrixf = GPA( "glMultMatrixf" ); + qglNewList = dllNewList = GPA( "glNewList" ); + qglNormal3b = dllNormal3b = GPA( "glNormal3b" ); + qglNormal3bv = dllNormal3bv = GPA( "glNormal3bv" ); + qglNormal3d = dllNormal3d = GPA( "glNormal3d" ); + qglNormal3dv = dllNormal3dv = GPA( "glNormal3dv" ); + qglNormal3f = dllNormal3f = GPA( "glNormal3f" ); + qglNormal3fv = dllNormal3fv = GPA( "glNormal3fv" ); + qglNormal3i = dllNormal3i = GPA( "glNormal3i" ); + qglNormal3iv = dllNormal3iv = GPA( "glNormal3iv" ); + qglNormal3s = dllNormal3s = GPA( "glNormal3s" ); + qglNormal3sv = dllNormal3sv = GPA( "glNormal3sv" ); + qglNormalPointer = dllNormalPointer = GPA( "glNormalPointer" ); + qglOrtho = dllOrtho = GPA( "glOrtho" ); + qglPassThrough = dllPassThrough = GPA( "glPassThrough" ); + qglPixelMapfv = dllPixelMapfv = GPA( "glPixelMapfv" ); + qglPixelMapuiv = dllPixelMapuiv = GPA( "glPixelMapuiv" ); + qglPixelMapusv = dllPixelMapusv = GPA( "glPixelMapusv" ); + qglPixelStoref = dllPixelStoref = GPA( "glPixelStoref" ); + qglPixelStorei = dllPixelStorei = GPA( "glPixelStorei" ); + qglPixelTransferf = dllPixelTransferf = GPA( "glPixelTransferf" ); + qglPixelTransferi = dllPixelTransferi = GPA( "glPixelTransferi" ); + qglPixelZoom = dllPixelZoom = GPA( "glPixelZoom" ); + qglPointSize = dllPointSize = GPA( "glPointSize" ); + qglPolygonMode = dllPolygonMode = GPA( "glPolygonMode" ); + qglPolygonOffset = dllPolygonOffset = GPA( "glPolygonOffset" ); + qglPolygonStipple = dllPolygonStipple = GPA( "glPolygonStipple" ); + qglPopAttrib = dllPopAttrib = GPA( "glPopAttrib" ); + qglPopClientAttrib = dllPopClientAttrib = GPA( "glPopClientAttrib" ); + qglPopMatrix = dllPopMatrix = GPA( "glPopMatrix" ); + qglPopName = dllPopName = GPA( "glPopName" ); + qglPrioritizeTextures = dllPrioritizeTextures = GPA( "glPrioritizeTextures" ); + qglPushAttrib = dllPushAttrib = GPA( "glPushAttrib" ); + qglPushClientAttrib = dllPushClientAttrib = GPA( "glPushClientAttrib" ); + qglPushMatrix = dllPushMatrix = GPA( "glPushMatrix" ); + qglPushName = dllPushName = GPA( "glPushName" ); + qglRasterPos2d = dllRasterPos2d = GPA( "glRasterPos2d" ); + qglRasterPos2dv = dllRasterPos2dv = GPA( "glRasterPos2dv" ); + qglRasterPos2f = dllRasterPos2f = GPA( "glRasterPos2f" ); + qglRasterPos2fv = dllRasterPos2fv = GPA( "glRasterPos2fv" ); + qglRasterPos2i = dllRasterPos2i = GPA( "glRasterPos2i" ); + qglRasterPos2iv = dllRasterPos2iv = GPA( "glRasterPos2iv" ); + qglRasterPos2s = dllRasterPos2s = GPA( "glRasterPos2s" ); + qglRasterPos2sv = dllRasterPos2sv = GPA( "glRasterPos2sv" ); + qglRasterPos3d = dllRasterPos3d = GPA( "glRasterPos3d" ); + qglRasterPos3dv = dllRasterPos3dv = GPA( "glRasterPos3dv" ); + qglRasterPos3f = dllRasterPos3f = GPA( "glRasterPos3f" ); + qglRasterPos3fv = dllRasterPos3fv = GPA( "glRasterPos3fv" ); + qglRasterPos3i = dllRasterPos3i = GPA( "glRasterPos3i" ); + qglRasterPos3iv = dllRasterPos3iv = GPA( "glRasterPos3iv" ); + qglRasterPos3s = dllRasterPos3s = GPA( "glRasterPos3s" ); + qglRasterPos3sv = dllRasterPos3sv = GPA( "glRasterPos3sv" ); + qglRasterPos4d = dllRasterPos4d = GPA( "glRasterPos4d" ); + qglRasterPos4dv = dllRasterPos4dv = GPA( "glRasterPos4dv" ); + qglRasterPos4f = dllRasterPos4f = GPA( "glRasterPos4f" ); + qglRasterPos4fv = dllRasterPos4fv = GPA( "glRasterPos4fv" ); + qglRasterPos4i = dllRasterPos4i = GPA( "glRasterPos4i" ); + qglRasterPos4iv = dllRasterPos4iv = GPA( "glRasterPos4iv" ); + qglRasterPos4s = dllRasterPos4s = GPA( "glRasterPos4s" ); + qglRasterPos4sv = dllRasterPos4sv = GPA( "glRasterPos4sv" ); + qglReadBuffer = dllReadBuffer = GPA( "glReadBuffer" ); + qglReadPixels = dllReadPixels = GPA( "glReadPixels" ); + qglRectd = dllRectd = GPA( "glRectd" ); + qglRectdv = dllRectdv = GPA( "glRectdv" ); + qglRectf = dllRectf = GPA( "glRectf" ); + qglRectfv = dllRectfv = GPA( "glRectfv" ); + qglRecti = dllRecti = GPA( "glRecti" ); + qglRectiv = dllRectiv = GPA( "glRectiv" ); + qglRects = dllRects = GPA( "glRects" ); + qglRectsv = dllRectsv = GPA( "glRectsv" ); + qglRenderMode = dllRenderMode = GPA( "glRenderMode" ); + qglRotated = dllRotated = GPA( "glRotated" ); + qglRotatef = dllRotatef = GPA( "glRotatef" ); + qglScaled = dllScaled = GPA( "glScaled" ); + qglScalef = dllScalef = GPA( "glScalef" ); + qglScissor = dllScissor = GPA( "glScissor" ); + qglSelectBuffer = dllSelectBuffer = GPA( "glSelectBuffer" ); + qglShadeModel = dllShadeModel = GPA( "glShadeModel" ); + qglStencilFunc = dllStencilFunc = GPA( "glStencilFunc" ); + qglStencilMask = dllStencilMask = GPA( "glStencilMask" ); + qglStencilOp = dllStencilOp = GPA( "glStencilOp" ); + qglTexCoord1d = dllTexCoord1d = GPA( "glTexCoord1d" ); + qglTexCoord1dv = dllTexCoord1dv = GPA( "glTexCoord1dv" ); + qglTexCoord1f = dllTexCoord1f = GPA( "glTexCoord1f" ); + qglTexCoord1fv = dllTexCoord1fv = GPA( "glTexCoord1fv" ); + qglTexCoord1i = dllTexCoord1i = GPA( "glTexCoord1i" ); + qglTexCoord1iv = dllTexCoord1iv = GPA( "glTexCoord1iv" ); + qglTexCoord1s = dllTexCoord1s = GPA( "glTexCoord1s" ); + qglTexCoord1sv = dllTexCoord1sv = GPA( "glTexCoord1sv" ); + qglTexCoord2d = dllTexCoord2d = GPA( "glTexCoord2d" ); + qglTexCoord2dv = dllTexCoord2dv = GPA( "glTexCoord2dv" ); + qglTexCoord2f = dllTexCoord2f = GPA( "glTexCoord2f" ); + qglTexCoord2fv = dllTexCoord2fv = GPA( "glTexCoord2fv" ); + qglTexCoord2i = dllTexCoord2i = GPA( "glTexCoord2i" ); + qglTexCoord2iv = dllTexCoord2iv = GPA( "glTexCoord2iv" ); + qglTexCoord2s = dllTexCoord2s = GPA( "glTexCoord2s" ); + qglTexCoord2sv = dllTexCoord2sv = GPA( "glTexCoord2sv" ); + qglTexCoord3d = dllTexCoord3d = GPA( "glTexCoord3d" ); + qglTexCoord3dv = dllTexCoord3dv = GPA( "glTexCoord3dv" ); + qglTexCoord3f = dllTexCoord3f = GPA( "glTexCoord3f" ); + qglTexCoord3fv = dllTexCoord3fv = GPA( "glTexCoord3fv" ); + qglTexCoord3i = dllTexCoord3i = GPA( "glTexCoord3i" ); + qglTexCoord3iv = dllTexCoord3iv = GPA( "glTexCoord3iv" ); + qglTexCoord3s = dllTexCoord3s = GPA( "glTexCoord3s" ); + qglTexCoord3sv = dllTexCoord3sv = GPA( "glTexCoord3sv" ); + qglTexCoord4d = dllTexCoord4d = GPA( "glTexCoord4d" ); + qglTexCoord4dv = dllTexCoord4dv = GPA( "glTexCoord4dv" ); + qglTexCoord4f = dllTexCoord4f = GPA( "glTexCoord4f" ); + qglTexCoord4fv = dllTexCoord4fv = GPA( "glTexCoord4fv" ); + qglTexCoord4i = dllTexCoord4i = GPA( "glTexCoord4i" ); + qglTexCoord4iv = dllTexCoord4iv = GPA( "glTexCoord4iv" ); + qglTexCoord4s = dllTexCoord4s = GPA( "glTexCoord4s" ); + qglTexCoord4sv = dllTexCoord4sv = GPA( "glTexCoord4sv" ); + qglTexCoordPointer = dllTexCoordPointer = GPA( "glTexCoordPointer" ); + qglTexEnvf = dllTexEnvf = GPA( "glTexEnvf" ); + qglTexEnvfv = dllTexEnvfv = GPA( "glTexEnvfv" ); + qglTexEnvi = dllTexEnvi = GPA( "glTexEnvi" ); + qglTexEnviv = dllTexEnviv = GPA( "glTexEnviv" ); + qglTexGend = dllTexGend = GPA( "glTexGend" ); + qglTexGendv = dllTexGendv = GPA( "glTexGendv" ); + qglTexGenf = dllTexGenf = GPA( "glTexGenf" ); + qglTexGenfv = dllTexGenfv = GPA( "glTexGenfv" ); + qglTexGeni = dllTexGeni = GPA( "glTexGeni" ); + qglTexGeniv = dllTexGeniv = GPA( "glTexGeniv" ); + qglTexImage1D = dllTexImage1D = GPA( "glTexImage1D" ); + qglTexImage2D = dllTexImage2D = GPA( "glTexImage2D" ); + qglTexParameterf = dllTexParameterf = GPA( "glTexParameterf" ); + qglTexParameterfv = dllTexParameterfv = GPA( "glTexParameterfv" ); + qglTexParameteri = dllTexParameteri = GPA( "glTexParameteri" ); + qglTexParameteriv = dllTexParameteriv = GPA( "glTexParameteriv" ); + qglTexSubImage1D = dllTexSubImage1D = GPA( "glTexSubImage1D" ); + qglTexSubImage2D = dllTexSubImage2D = GPA( "glTexSubImage2D" ); + qglTranslated = dllTranslated = GPA( "glTranslated" ); + qglTranslatef = dllTranslatef = GPA( "glTranslatef" ); + qglVertex2d = dllVertex2d = GPA( "glVertex2d" ); + qglVertex2dv = dllVertex2dv = GPA( "glVertex2dv" ); + qglVertex2f = dllVertex2f = GPA( "glVertex2f" ); + qglVertex2fv = dllVertex2fv = GPA( "glVertex2fv" ); + qglVertex2i = dllVertex2i = GPA( "glVertex2i" ); + qglVertex2iv = dllVertex2iv = GPA( "glVertex2iv" ); + qglVertex2s = dllVertex2s = GPA( "glVertex2s" ); + qglVertex2sv = dllVertex2sv = GPA( "glVertex2sv" ); + qglVertex3d = dllVertex3d = GPA( "glVertex3d" ); + qglVertex3dv = dllVertex3dv = GPA( "glVertex3dv" ); + qglVertex3f = dllVertex3f = GPA( "glVertex3f" ); + qglVertex3fv = dllVertex3fv = GPA( "glVertex3fv" ); + qglVertex3i = dllVertex3i = GPA( "glVertex3i" ); + qglVertex3iv = dllVertex3iv = GPA( "glVertex3iv" ); + qglVertex3s = dllVertex3s = GPA( "glVertex3s" ); + qglVertex3sv = dllVertex3sv = GPA( "glVertex3sv" ); + qglVertex4d = dllVertex4d = GPA( "glVertex4d" ); + qglVertex4dv = dllVertex4dv = GPA( "glVertex4dv" ); + qglVertex4f = dllVertex4f = GPA( "glVertex4f" ); + qglVertex4fv = dllVertex4fv = GPA( "glVertex4fv" ); + qglVertex4i = dllVertex4i = GPA( "glVertex4i" ); + qglVertex4iv = dllVertex4iv = GPA( "glVertex4iv" ); + qglVertex4s = dllVertex4s = GPA( "glVertex4s" ); + qglVertex4sv = dllVertex4sv = GPA( "glVertex4sv" ); + qglVertexPointer = dllVertexPointer = GPA( "glVertexPointer" ); + qglViewport = dllViewport = GPA( "glViewport" ); + + qfxMesaCreateContext = GPA("fxMesaCreateContext"); + qfxMesaCreateBestContext = GPA("fxMesaCreateBestContext"); + qfxMesaDestroyContext = GPA("fxMesaDestroyContext"); + qfxMesaMakeCurrent = GPA("fxMesaMakeCurrent"); + qfxMesaGetCurrentContext = GPA("fxMesaGetCurrentContext"); + qfxMesaSwapBuffers = GPA("fxMesaSwapBuffers"); + + qglXChooseVisual = GPA("glXChooseVisual"); + qglXCreateContext = GPA("glXCreateContext"); + qglXDestroyContext = GPA("glXDestroyContext"); + qglXMakeCurrent = GPA("glXMakeCurrent"); + qglXCopyContext = GPA("glXCopyContext"); + qglXSwapBuffers = GPA("glXSwapBuffers"); + + qglLockArraysEXT = 0; + qglUnlockArraysEXT = 0; + qglPointParameterfEXT = 0; + qglPointParameterfvEXT = 0; + qglColorTableEXT = 0; + qgl3DfxSetPaletteEXT = 0; + qglSelectTextureSGIS = 0; + qglMTexCoord2fSGIS = 0; + qglActiveTextureARB = 0; + qglClientActiveTextureARB = 0; + qglMultiTexCoord2fARB = 0; + + return qtrue; +} + +void QGL_EnableLogging( qboolean enable ) +{ + if ( enable ) + { + if ( !glw_state.log_fp ) + { + struct tm *newtime; + time_t aclock; + char buffer[1024]; + cvar_t *basedir; + + time( &aclock ); + newtime = localtime( &aclock ); + + asctime( newtime ); + + basedir = ri.Cvar_Get( "basedir", "", 0 ); + Com_sprintf( buffer, sizeof(buffer), "%s/gl.log", basedir->string ); + glw_state.log_fp = fopen( buffer, "wt" ); + + fprintf( glw_state.log_fp, "%s\n", asctime( newtime ) ); + } + + qglAccum = logAccum; + qglAlphaFunc = logAlphaFunc; + qglAreTexturesResident = logAreTexturesResident; + qglArrayElement = logArrayElement; + qglBegin = logBegin; + qglBindTexture = logBindTexture; + qglBitmap = logBitmap; + qglBlendFunc = logBlendFunc; + qglCallList = logCallList; + qglCallLists = logCallLists; + qglClear = logClear; + qglClearAccum = logClearAccum; + qglClearColor = logClearColor; + qglClearDepth = logClearDepth; + qglClearIndex = logClearIndex; + qglClearStencil = logClearStencil; + qglClipPlane = logClipPlane; + qglColor3b = logColor3b; + qglColor3bv = logColor3bv; + qglColor3d = logColor3d; + qglColor3dv = logColor3dv; + qglColor3f = logColor3f; + qglColor3fv = logColor3fv; + qglColor3i = logColor3i; + qglColor3iv = logColor3iv; + qglColor3s = logColor3s; + qglColor3sv = logColor3sv; + qglColor3ub = logColor3ub; + qglColor3ubv = logColor3ubv; + qglColor3ui = logColor3ui; + qglColor3uiv = logColor3uiv; + qglColor3us = logColor3us; + qglColor3usv = logColor3usv; + qglColor4b = logColor4b; + qglColor4bv = logColor4bv; + qglColor4d = logColor4d; + qglColor4dv = logColor4dv; + qglColor4f = logColor4f; + qglColor4fv = logColor4fv; + qglColor4i = logColor4i; + qglColor4iv = logColor4iv; + qglColor4s = logColor4s; + qglColor4sv = logColor4sv; + qglColor4ub = logColor4ub; + qglColor4ubv = logColor4ubv; + qglColor4ui = logColor4ui; + qglColor4uiv = logColor4uiv; + qglColor4us = logColor4us; + qglColor4usv = logColor4usv; + qglColorMask = logColorMask; + qglColorMaterial = logColorMaterial; + qglColorPointer = logColorPointer; + qglCopyPixels = logCopyPixels; + qglCopyTexImage1D = logCopyTexImage1D; + qglCopyTexImage2D = logCopyTexImage2D; + qglCopyTexSubImage1D = logCopyTexSubImage1D; + qglCopyTexSubImage2D = logCopyTexSubImage2D; + qglCullFace = logCullFace; + qglDeleteLists = logDeleteLists ; + qglDeleteTextures = logDeleteTextures ; + qglDepthFunc = logDepthFunc ; + qglDepthMask = logDepthMask ; + qglDepthRange = logDepthRange ; + qglDisable = logDisable ; + qglDisableClientState = logDisableClientState ; + qglDrawArrays = logDrawArrays ; + qglDrawBuffer = logDrawBuffer ; + qglDrawElements = logDrawElements ; + qglDrawPixels = logDrawPixels ; + qglEdgeFlag = logEdgeFlag ; + qglEdgeFlagPointer = logEdgeFlagPointer ; + qglEdgeFlagv = logEdgeFlagv ; + qglEnable = logEnable ; + qglEnableClientState = logEnableClientState ; + qglEnd = logEnd ; + qglEndList = logEndList ; + qglEvalCoord1d = logEvalCoord1d ; + qglEvalCoord1dv = logEvalCoord1dv ; + qglEvalCoord1f = logEvalCoord1f ; + qglEvalCoord1fv = logEvalCoord1fv ; + qglEvalCoord2d = logEvalCoord2d ; + qglEvalCoord2dv = logEvalCoord2dv ; + qglEvalCoord2f = logEvalCoord2f ; + qglEvalCoord2fv = logEvalCoord2fv ; + qglEvalMesh1 = logEvalMesh1 ; + qglEvalMesh2 = logEvalMesh2 ; + qglEvalPoint1 = logEvalPoint1 ; + qglEvalPoint2 = logEvalPoint2 ; + qglFeedbackBuffer = logFeedbackBuffer ; + qglFinish = logFinish ; + qglFlush = logFlush ; + qglFogf = logFogf ; + qglFogfv = logFogfv ; + qglFogi = logFogi ; + qglFogiv = logFogiv ; + qglFrontFace = logFrontFace ; + qglFrustum = logFrustum ; + qglGenLists = logGenLists ; + qglGenTextures = logGenTextures ; + qglGetBooleanv = logGetBooleanv ; + qglGetClipPlane = logGetClipPlane ; + qglGetDoublev = logGetDoublev ; + qglGetError = logGetError ; + qglGetFloatv = logGetFloatv ; + qglGetIntegerv = logGetIntegerv ; + qglGetLightfv = logGetLightfv ; + qglGetLightiv = logGetLightiv ; + qglGetMapdv = logGetMapdv ; + qglGetMapfv = logGetMapfv ; + qglGetMapiv = logGetMapiv ; + qglGetMaterialfv = logGetMaterialfv ; + qglGetMaterialiv = logGetMaterialiv ; + qglGetPixelMapfv = logGetPixelMapfv ; + qglGetPixelMapuiv = logGetPixelMapuiv ; + qglGetPixelMapusv = logGetPixelMapusv ; + qglGetPointerv = logGetPointerv ; + qglGetPolygonStipple = logGetPolygonStipple ; + qglGetString = logGetString ; + qglGetTexEnvfv = logGetTexEnvfv ; + qglGetTexEnviv = logGetTexEnviv ; + qglGetTexGendv = logGetTexGendv ; + qglGetTexGenfv = logGetTexGenfv ; + qglGetTexGeniv = logGetTexGeniv ; + qglGetTexImage = logGetTexImage ; + qglGetTexLevelParameterfv = logGetTexLevelParameterfv ; + qglGetTexLevelParameteriv = logGetTexLevelParameteriv ; + qglGetTexParameterfv = logGetTexParameterfv ; + qglGetTexParameteriv = logGetTexParameteriv ; + qglHint = logHint ; + qglIndexMask = logIndexMask ; + qglIndexPointer = logIndexPointer ; + qglIndexd = logIndexd ; + qglIndexdv = logIndexdv ; + qglIndexf = logIndexf ; + qglIndexfv = logIndexfv ; + qglIndexi = logIndexi ; + qglIndexiv = logIndexiv ; + qglIndexs = logIndexs ; + qglIndexsv = logIndexsv ; + qglIndexub = logIndexub ; + qglIndexubv = logIndexubv ; + qglInitNames = logInitNames ; + qglInterleavedArrays = logInterleavedArrays ; + qglIsEnabled = logIsEnabled ; + qglIsList = logIsList ; + qglIsTexture = logIsTexture ; + qglLightModelf = logLightModelf ; + qglLightModelfv = logLightModelfv ; + qglLightModeli = logLightModeli ; + qglLightModeliv = logLightModeliv ; + qglLightf = logLightf ; + qglLightfv = logLightfv ; + qglLighti = logLighti ; + qglLightiv = logLightiv ; + qglLineStipple = logLineStipple ; + qglLineWidth = logLineWidth ; + qglListBase = logListBase ; + qglLoadIdentity = logLoadIdentity ; + qglLoadMatrixd = logLoadMatrixd ; + qglLoadMatrixf = logLoadMatrixf ; + qglLoadName = logLoadName ; + qglLogicOp = logLogicOp ; + qglMap1d = logMap1d ; + qglMap1f = logMap1f ; + qglMap2d = logMap2d ; + qglMap2f = logMap2f ; + qglMapGrid1d = logMapGrid1d ; + qglMapGrid1f = logMapGrid1f ; + qglMapGrid2d = logMapGrid2d ; + qglMapGrid2f = logMapGrid2f ; + qglMaterialf = logMaterialf ; + qglMaterialfv = logMaterialfv ; + qglMateriali = logMateriali ; + qglMaterialiv = logMaterialiv ; + qglMatrixMode = logMatrixMode ; + qglMultMatrixd = logMultMatrixd ; + qglMultMatrixf = logMultMatrixf ; + qglNewList = logNewList ; + qglNormal3b = logNormal3b ; + qglNormal3bv = logNormal3bv ; + qglNormal3d = logNormal3d ; + qglNormal3dv = logNormal3dv ; + qglNormal3f = logNormal3f ; + qglNormal3fv = logNormal3fv ; + qglNormal3i = logNormal3i ; + qglNormal3iv = logNormal3iv ; + qglNormal3s = logNormal3s ; + qglNormal3sv = logNormal3sv ; + qglNormalPointer = logNormalPointer ; + qglOrtho = logOrtho ; + qglPassThrough = logPassThrough ; + qglPixelMapfv = logPixelMapfv ; + qglPixelMapuiv = logPixelMapuiv ; + qglPixelMapusv = logPixelMapusv ; + qglPixelStoref = logPixelStoref ; + qglPixelStorei = logPixelStorei ; + qglPixelTransferf = logPixelTransferf ; + qglPixelTransferi = logPixelTransferi ; + qglPixelZoom = logPixelZoom ; + qglPointSize = logPointSize ; + qglPolygonMode = logPolygonMode ; + qglPolygonOffset = logPolygonOffset ; + qglPolygonStipple = logPolygonStipple ; + qglPopAttrib = logPopAttrib ; + qglPopClientAttrib = logPopClientAttrib ; + qglPopMatrix = logPopMatrix ; + qglPopName = logPopName ; + qglPrioritizeTextures = logPrioritizeTextures ; + qglPushAttrib = logPushAttrib ; + qglPushClientAttrib = logPushClientAttrib ; + qglPushMatrix = logPushMatrix ; + qglPushName = logPushName ; + qglRasterPos2d = logRasterPos2d ; + qglRasterPos2dv = logRasterPos2dv ; + qglRasterPos2f = logRasterPos2f ; + qglRasterPos2fv = logRasterPos2fv ; + qglRasterPos2i = logRasterPos2i ; + qglRasterPos2iv = logRasterPos2iv ; + qglRasterPos2s = logRasterPos2s ; + qglRasterPos2sv = logRasterPos2sv ; + qglRasterPos3d = logRasterPos3d ; + qglRasterPos3dv = logRasterPos3dv ; + qglRasterPos3f = logRasterPos3f ; + qglRasterPos3fv = logRasterPos3fv ; + qglRasterPos3i = logRasterPos3i ; + qglRasterPos3iv = logRasterPos3iv ; + qglRasterPos3s = logRasterPos3s ; + qglRasterPos3sv = logRasterPos3sv ; + qglRasterPos4d = logRasterPos4d ; + qglRasterPos4dv = logRasterPos4dv ; + qglRasterPos4f = logRasterPos4f ; + qglRasterPos4fv = logRasterPos4fv ; + qglRasterPos4i = logRasterPos4i ; + qglRasterPos4iv = logRasterPos4iv ; + qglRasterPos4s = logRasterPos4s ; + qglRasterPos4sv = logRasterPos4sv ; + qglReadBuffer = logReadBuffer ; + qglReadPixels = logReadPixels ; + qglRectd = logRectd ; + qglRectdv = logRectdv ; + qglRectf = logRectf ; + qglRectfv = logRectfv ; + qglRecti = logRecti ; + qglRectiv = logRectiv ; + qglRects = logRects ; + qglRectsv = logRectsv ; + qglRenderMode = logRenderMode ; + qglRotated = logRotated ; + qglRotatef = logRotatef ; + qglScaled = logScaled ; + qglScalef = logScalef ; + qglScissor = logScissor ; + qglSelectBuffer = logSelectBuffer ; + qglShadeModel = logShadeModel ; + qglStencilFunc = logStencilFunc ; + qglStencilMask = logStencilMask ; + qglStencilOp = logStencilOp ; + qglTexCoord1d = logTexCoord1d ; + qglTexCoord1dv = logTexCoord1dv ; + qglTexCoord1f = logTexCoord1f ; + qglTexCoord1fv = logTexCoord1fv ; + qglTexCoord1i = logTexCoord1i ; + qglTexCoord1iv = logTexCoord1iv ; + qglTexCoord1s = logTexCoord1s ; + qglTexCoord1sv = logTexCoord1sv ; + qglTexCoord2d = logTexCoord2d ; + qglTexCoord2dv = logTexCoord2dv ; + qglTexCoord2f = logTexCoord2f ; + qglTexCoord2fv = logTexCoord2fv ; + qglTexCoord2i = logTexCoord2i ; + qglTexCoord2iv = logTexCoord2iv ; + qglTexCoord2s = logTexCoord2s ; + qglTexCoord2sv = logTexCoord2sv ; + qglTexCoord3d = logTexCoord3d ; + qglTexCoord3dv = logTexCoord3dv ; + qglTexCoord3f = logTexCoord3f ; + qglTexCoord3fv = logTexCoord3fv ; + qglTexCoord3i = logTexCoord3i ; + qglTexCoord3iv = logTexCoord3iv ; + qglTexCoord3s = logTexCoord3s ; + qglTexCoord3sv = logTexCoord3sv ; + qglTexCoord4d = logTexCoord4d ; + qglTexCoord4dv = logTexCoord4dv ; + qglTexCoord4f = logTexCoord4f ; + qglTexCoord4fv = logTexCoord4fv ; + qglTexCoord4i = logTexCoord4i ; + qglTexCoord4iv = logTexCoord4iv ; + qglTexCoord4s = logTexCoord4s ; + qglTexCoord4sv = logTexCoord4sv ; + qglTexCoordPointer = logTexCoordPointer ; + qglTexEnvf = logTexEnvf ; + qglTexEnvfv = logTexEnvfv ; + qglTexEnvi = logTexEnvi ; + qglTexEnviv = logTexEnviv ; + qglTexGend = logTexGend ; + qglTexGendv = logTexGendv ; + qglTexGenf = logTexGenf ; + qglTexGenfv = logTexGenfv ; + qglTexGeni = logTexGeni ; + qglTexGeniv = logTexGeniv ; + qglTexImage1D = logTexImage1D ; + qglTexImage2D = logTexImage2D ; + qglTexParameterf = logTexParameterf ; + qglTexParameterfv = logTexParameterfv ; + qglTexParameteri = logTexParameteri ; + qglTexParameteriv = logTexParameteriv ; + qglTexSubImage1D = logTexSubImage1D ; + qglTexSubImage2D = logTexSubImage2D ; + qglTranslated = logTranslated ; + qglTranslatef = logTranslatef ; + qglVertex2d = logVertex2d ; + qglVertex2dv = logVertex2dv ; + qglVertex2f = logVertex2f ; + qglVertex2fv = logVertex2fv ; + qglVertex2i = logVertex2i ; + qglVertex2iv = logVertex2iv ; + qglVertex2s = logVertex2s ; + qglVertex2sv = logVertex2sv ; + qglVertex3d = logVertex3d ; + qglVertex3dv = logVertex3dv ; + qglVertex3f = logVertex3f ; + qglVertex3fv = logVertex3fv ; + qglVertex3i = logVertex3i ; + qglVertex3iv = logVertex3iv ; + qglVertex3s = logVertex3s ; + qglVertex3sv = logVertex3sv ; + qglVertex4d = logVertex4d ; + qglVertex4dv = logVertex4dv ; + qglVertex4f = logVertex4f ; + qglVertex4fv = logVertex4fv ; + qglVertex4i = logVertex4i ; + qglVertex4iv = logVertex4iv ; + qglVertex4s = logVertex4s ; + qglVertex4sv = logVertex4sv ; + qglVertexPointer = logVertexPointer ; + qglViewport = logViewport ; + } + else + { + qglAccum = dllAccum; + qglAlphaFunc = dllAlphaFunc; + qglAreTexturesResident = dllAreTexturesResident; + qglArrayElement = dllArrayElement; + qglBegin = dllBegin; + qglBindTexture = dllBindTexture; + qglBitmap = dllBitmap; + qglBlendFunc = dllBlendFunc; + qglCallList = dllCallList; + qglCallLists = dllCallLists; + qglClear = dllClear; + qglClearAccum = dllClearAccum; + qglClearColor = dllClearColor; + qglClearDepth = dllClearDepth; + qglClearIndex = dllClearIndex; + qglClearStencil = dllClearStencil; + qglClipPlane = dllClipPlane; + qglColor3b = dllColor3b; + qglColor3bv = dllColor3bv; + qglColor3d = dllColor3d; + qglColor3dv = dllColor3dv; + qglColor3f = dllColor3f; + qglColor3fv = dllColor3fv; + qglColor3i = dllColor3i; + qglColor3iv = dllColor3iv; + qglColor3s = dllColor3s; + qglColor3sv = dllColor3sv; + qglColor3ub = dllColor3ub; + qglColor3ubv = dllColor3ubv; + qglColor3ui = dllColor3ui; + qglColor3uiv = dllColor3uiv; + qglColor3us = dllColor3us; + qglColor3usv = dllColor3usv; + qglColor4b = dllColor4b; + qglColor4bv = dllColor4bv; + qglColor4d = dllColor4d; + qglColor4dv = dllColor4dv; + qglColor4f = dllColor4f; + qglColor4fv = dllColor4fv; + qglColor4i = dllColor4i; + qglColor4iv = dllColor4iv; + qglColor4s = dllColor4s; + qglColor4sv = dllColor4sv; + qglColor4ub = dllColor4ub; + qglColor4ubv = dllColor4ubv; + qglColor4ui = dllColor4ui; + qglColor4uiv = dllColor4uiv; + qglColor4us = dllColor4us; + qglColor4usv = dllColor4usv; + qglColorMask = dllColorMask; + qglColorMaterial = dllColorMaterial; + qglColorPointer = dllColorPointer; + qglCopyPixels = dllCopyPixels; + qglCopyTexImage1D = dllCopyTexImage1D; + qglCopyTexImage2D = dllCopyTexImage2D; + qglCopyTexSubImage1D = dllCopyTexSubImage1D; + qglCopyTexSubImage2D = dllCopyTexSubImage2D; + qglCullFace = dllCullFace; + qglDeleteLists = dllDeleteLists ; + qglDeleteTextures = dllDeleteTextures ; + qglDepthFunc = dllDepthFunc ; + qglDepthMask = dllDepthMask ; + qglDepthRange = dllDepthRange ; + qglDisable = dllDisable ; + qglDisableClientState = dllDisableClientState ; + qglDrawArrays = dllDrawArrays ; + qglDrawBuffer = dllDrawBuffer ; + qglDrawElements = dllDrawElements ; + qglDrawPixels = dllDrawPixels ; + qglEdgeFlag = dllEdgeFlag ; + qglEdgeFlagPointer = dllEdgeFlagPointer ; + qglEdgeFlagv = dllEdgeFlagv ; + qglEnable = dllEnable ; + qglEnableClientState = dllEnableClientState ; + qglEnd = dllEnd ; + qglEndList = dllEndList ; + qglEvalCoord1d = dllEvalCoord1d ; + qglEvalCoord1dv = dllEvalCoord1dv ; + qglEvalCoord1f = dllEvalCoord1f ; + qglEvalCoord1fv = dllEvalCoord1fv ; + qglEvalCoord2d = dllEvalCoord2d ; + qglEvalCoord2dv = dllEvalCoord2dv ; + qglEvalCoord2f = dllEvalCoord2f ; + qglEvalCoord2fv = dllEvalCoord2fv ; + qglEvalMesh1 = dllEvalMesh1 ; + qglEvalMesh2 = dllEvalMesh2 ; + qglEvalPoint1 = dllEvalPoint1 ; + qglEvalPoint2 = dllEvalPoint2 ; + qglFeedbackBuffer = dllFeedbackBuffer ; + qglFinish = dllFinish ; + qglFlush = dllFlush ; + qglFogf = dllFogf ; + qglFogfv = dllFogfv ; + qglFogi = dllFogi ; + qglFogiv = dllFogiv ; + qglFrontFace = dllFrontFace ; + qglFrustum = dllFrustum ; + qglGenLists = dllGenLists ; + qglGenTextures = dllGenTextures ; + qglGetBooleanv = dllGetBooleanv ; + qglGetClipPlane = dllGetClipPlane ; + qglGetDoublev = dllGetDoublev ; + qglGetError = dllGetError ; + qglGetFloatv = dllGetFloatv ; + qglGetIntegerv = dllGetIntegerv ; + qglGetLightfv = dllGetLightfv ; + qglGetLightiv = dllGetLightiv ; + qglGetMapdv = dllGetMapdv ; + qglGetMapfv = dllGetMapfv ; + qglGetMapiv = dllGetMapiv ; + qglGetMaterialfv = dllGetMaterialfv ; + qglGetMaterialiv = dllGetMaterialiv ; + qglGetPixelMapfv = dllGetPixelMapfv ; + qglGetPixelMapuiv = dllGetPixelMapuiv ; + qglGetPixelMapusv = dllGetPixelMapusv ; + qglGetPointerv = dllGetPointerv ; + qglGetPolygonStipple = dllGetPolygonStipple ; + qglGetString = dllGetString ; + qglGetTexEnvfv = dllGetTexEnvfv ; + qglGetTexEnviv = dllGetTexEnviv ; + qglGetTexGendv = dllGetTexGendv ; + qglGetTexGenfv = dllGetTexGenfv ; + qglGetTexGeniv = dllGetTexGeniv ; + qglGetTexImage = dllGetTexImage ; + qglGetTexLevelParameterfv = dllGetTexLevelParameterfv ; + qglGetTexLevelParameteriv = dllGetTexLevelParameteriv ; + qglGetTexParameterfv = dllGetTexParameterfv ; + qglGetTexParameteriv = dllGetTexParameteriv ; + qglHint = dllHint ; + qglIndexMask = dllIndexMask ; + qglIndexPointer = dllIndexPointer ; + qglIndexd = dllIndexd ; + qglIndexdv = dllIndexdv ; + qglIndexf = dllIndexf ; + qglIndexfv = dllIndexfv ; + qglIndexi = dllIndexi ; + qglIndexiv = dllIndexiv ; + qglIndexs = dllIndexs ; + qglIndexsv = dllIndexsv ; + qglIndexub = dllIndexub ; + qglIndexubv = dllIndexubv ; + qglInitNames = dllInitNames ; + qglInterleavedArrays = dllInterleavedArrays ; + qglIsEnabled = dllIsEnabled ; + qglIsList = dllIsList ; + qglIsTexture = dllIsTexture ; + qglLightModelf = dllLightModelf ; + qglLightModelfv = dllLightModelfv ; + qglLightModeli = dllLightModeli ; + qglLightModeliv = dllLightModeliv ; + qglLightf = dllLightf ; + qglLightfv = dllLightfv ; + qglLighti = dllLighti ; + qglLightiv = dllLightiv ; + qglLineStipple = dllLineStipple ; + qglLineWidth = dllLineWidth ; + qglListBase = dllListBase ; + qglLoadIdentity = dllLoadIdentity ; + qglLoadMatrixd = dllLoadMatrixd ; + qglLoadMatrixf = dllLoadMatrixf ; + qglLoadName = dllLoadName ; + qglLogicOp = dllLogicOp ; + qglMap1d = dllMap1d ; + qglMap1f = dllMap1f ; + qglMap2d = dllMap2d ; + qglMap2f = dllMap2f ; + qglMapGrid1d = dllMapGrid1d ; + qglMapGrid1f = dllMapGrid1f ; + qglMapGrid2d = dllMapGrid2d ; + qglMapGrid2f = dllMapGrid2f ; + qglMaterialf = dllMaterialf ; + qglMaterialfv = dllMaterialfv ; + qglMateriali = dllMateriali ; + qglMaterialiv = dllMaterialiv ; + qglMatrixMode = dllMatrixMode ; + qglMultMatrixd = dllMultMatrixd ; + qglMultMatrixf = dllMultMatrixf ; + qglNewList = dllNewList ; + qglNormal3b = dllNormal3b ; + qglNormal3bv = dllNormal3bv ; + qglNormal3d = dllNormal3d ; + qglNormal3dv = dllNormal3dv ; + qglNormal3f = dllNormal3f ; + qglNormal3fv = dllNormal3fv ; + qglNormal3i = dllNormal3i ; + qglNormal3iv = dllNormal3iv ; + qglNormal3s = dllNormal3s ; + qglNormal3sv = dllNormal3sv ; + qglNormalPointer = dllNormalPointer ; + qglOrtho = dllOrtho ; + qglPassThrough = dllPassThrough ; + qglPixelMapfv = dllPixelMapfv ; + qglPixelMapuiv = dllPixelMapuiv ; + qglPixelMapusv = dllPixelMapusv ; + qglPixelStoref = dllPixelStoref ; + qglPixelStorei = dllPixelStorei ; + qglPixelTransferf = dllPixelTransferf ; + qglPixelTransferi = dllPixelTransferi ; + qglPixelZoom = dllPixelZoom ; + qglPointSize = dllPointSize ; + qglPolygonMode = dllPolygonMode ; + qglPolygonOffset = dllPolygonOffset ; + qglPolygonStipple = dllPolygonStipple ; + qglPopAttrib = dllPopAttrib ; + qglPopClientAttrib = dllPopClientAttrib ; + qglPopMatrix = dllPopMatrix ; + qglPopName = dllPopName ; + qglPrioritizeTextures = dllPrioritizeTextures ; + qglPushAttrib = dllPushAttrib ; + qglPushClientAttrib = dllPushClientAttrib ; + qglPushMatrix = dllPushMatrix ; + qglPushName = dllPushName ; + qglRasterPos2d = dllRasterPos2d ; + qglRasterPos2dv = dllRasterPos2dv ; + qglRasterPos2f = dllRasterPos2f ; + qglRasterPos2fv = dllRasterPos2fv ; + qglRasterPos2i = dllRasterPos2i ; + qglRasterPos2iv = dllRasterPos2iv ; + qglRasterPos2s = dllRasterPos2s ; + qglRasterPos2sv = dllRasterPos2sv ; + qglRasterPos3d = dllRasterPos3d ; + qglRasterPos3dv = dllRasterPos3dv ; + qglRasterPos3f = dllRasterPos3f ; + qglRasterPos3fv = dllRasterPos3fv ; + qglRasterPos3i = dllRasterPos3i ; + qglRasterPos3iv = dllRasterPos3iv ; + qglRasterPos3s = dllRasterPos3s ; + qglRasterPos3sv = dllRasterPos3sv ; + qglRasterPos4d = dllRasterPos4d ; + qglRasterPos4dv = dllRasterPos4dv ; + qglRasterPos4f = dllRasterPos4f ; + qglRasterPos4fv = dllRasterPos4fv ; + qglRasterPos4i = dllRasterPos4i ; + qglRasterPos4iv = dllRasterPos4iv ; + qglRasterPos4s = dllRasterPos4s ; + qglRasterPos4sv = dllRasterPos4sv ; + qglReadBuffer = dllReadBuffer ; + qglReadPixels = dllReadPixels ; + qglRectd = dllRectd ; + qglRectdv = dllRectdv ; + qglRectf = dllRectf ; + qglRectfv = dllRectfv ; + qglRecti = dllRecti ; + qglRectiv = dllRectiv ; + qglRects = dllRects ; + qglRectsv = dllRectsv ; + qglRenderMode = dllRenderMode ; + qglRotated = dllRotated ; + qglRotatef = dllRotatef ; + qglScaled = dllScaled ; + qglScalef = dllScalef ; + qglScissor = dllScissor ; + qglSelectBuffer = dllSelectBuffer ; + qglShadeModel = dllShadeModel ; + qglStencilFunc = dllStencilFunc ; + qglStencilMask = dllStencilMask ; + qglStencilOp = dllStencilOp ; + qglTexCoord1d = dllTexCoord1d ; + qglTexCoord1dv = dllTexCoord1dv ; + qglTexCoord1f = dllTexCoord1f ; + qglTexCoord1fv = dllTexCoord1fv ; + qglTexCoord1i = dllTexCoord1i ; + qglTexCoord1iv = dllTexCoord1iv ; + qglTexCoord1s = dllTexCoord1s ; + qglTexCoord1sv = dllTexCoord1sv ; + qglTexCoord2d = dllTexCoord2d ; + qglTexCoord2dv = dllTexCoord2dv ; + qglTexCoord2f = dllTexCoord2f ; + qglTexCoord2fv = dllTexCoord2fv ; + qglTexCoord2i = dllTexCoord2i ; + qglTexCoord2iv = dllTexCoord2iv ; + qglTexCoord2s = dllTexCoord2s ; + qglTexCoord2sv = dllTexCoord2sv ; + qglTexCoord3d = dllTexCoord3d ; + qglTexCoord3dv = dllTexCoord3dv ; + qglTexCoord3f = dllTexCoord3f ; + qglTexCoord3fv = dllTexCoord3fv ; + qglTexCoord3i = dllTexCoord3i ; + qglTexCoord3iv = dllTexCoord3iv ; + qglTexCoord3s = dllTexCoord3s ; + qglTexCoord3sv = dllTexCoord3sv ; + qglTexCoord4d = dllTexCoord4d ; + qglTexCoord4dv = dllTexCoord4dv ; + qglTexCoord4f = dllTexCoord4f ; + qglTexCoord4fv = dllTexCoord4fv ; + qglTexCoord4i = dllTexCoord4i ; + qglTexCoord4iv = dllTexCoord4iv ; + qglTexCoord4s = dllTexCoord4s ; + qglTexCoord4sv = dllTexCoord4sv ; + qglTexCoordPointer = dllTexCoordPointer ; + qglTexEnvf = dllTexEnvf ; + qglTexEnvfv = dllTexEnvfv ; + qglTexEnvi = dllTexEnvi ; + qglTexEnviv = dllTexEnviv ; + qglTexGend = dllTexGend ; + qglTexGendv = dllTexGendv ; + qglTexGenf = dllTexGenf ; + qglTexGenfv = dllTexGenfv ; + qglTexGeni = dllTexGeni ; + qglTexGeniv = dllTexGeniv ; + qglTexImage1D = dllTexImage1D ; + qglTexImage2D = dllTexImage2D ; + qglTexParameterf = dllTexParameterf ; + qglTexParameterfv = dllTexParameterfv ; + qglTexParameteri = dllTexParameteri ; + qglTexParameteriv = dllTexParameteriv ; + qglTexSubImage1D = dllTexSubImage1D ; + qglTexSubImage2D = dllTexSubImage2D ; + qglTranslated = dllTranslated ; + qglTranslatef = dllTranslatef ; + qglVertex2d = dllVertex2d ; + qglVertex2dv = dllVertex2dv ; + qglVertex2f = dllVertex2f ; + qglVertex2fv = dllVertex2fv ; + qglVertex2i = dllVertex2i ; + qglVertex2iv = dllVertex2iv ; + qglVertex2s = dllVertex2s ; + qglVertex2sv = dllVertex2sv ; + qglVertex3d = dllVertex3d ; + qglVertex3dv = dllVertex3dv ; + qglVertex3f = dllVertex3f ; + qglVertex3fv = dllVertex3fv ; + qglVertex3i = dllVertex3i ; + qglVertex3iv = dllVertex3iv ; + qglVertex3s = dllVertex3s ; + qglVertex3sv = dllVertex3sv ; + qglVertex4d = dllVertex4d ; + qglVertex4dv = dllVertex4dv ; + qglVertex4f = dllVertex4f ; + qglVertex4fv = dllVertex4fv ; + qglVertex4i = dllVertex4i ; + qglVertex4iv = dllVertex4iv ; + qglVertex4s = dllVertex4s ; + qglVertex4sv = dllVertex4sv ; + qglVertexPointer = dllVertexPointer ; + qglViewport = dllViewport ; + } +} + + +void GLimp_LogNewFrame( void ) +{ + fprintf( glw_state.log_fp, "*** R_BeginFrame ***\n" ); +} + + diff --git a/code/unix/linux_snd.c b/code/unix/linux_snd.c new file mode 100644 index 0000000..77c816a --- /dev/null +++ b/code/unix/linux_snd.c @@ -0,0 +1,244 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../client/snd_local.h" + +int audio_fd; +int snd_inited=0; + +cvar_t *sndbits; +cvar_t *sndspeed; +cvar_t *sndchannels; + +cvar_t *snddevice; + +/* Some devices may work only with 48000 */ +static int tryrates[] = { 22050, 11025, 44100, 48000, 8000 }; + +qboolean SNDDMA_Init(void) +{ + int rc; + int fmt; + int tmp; + int i; + char *s; + struct audio_buf_info info; + int caps; + extern uid_t saved_euid; + + if (snd_inited) + return; + + if (!snddevice) { + sndbits = Cvar_Get("sndbits", "16", CVAR_ARCHIVE); + sndspeed = Cvar_Get("sndspeed", "0", CVAR_ARCHIVE); + sndchannels = Cvar_Get("sndchannels", "2", CVAR_ARCHIVE); + snddevice = Cvar_Get("snddevice", "/dev/dsp", CVAR_ARCHIVE); + } + +// open /dev/dsp, confirm capability to mmap, and get size of dma buffer + if (!audio_fd) { + seteuid(saved_euid); + + audio_fd = open(snddevice->string, O_RDWR); + + seteuid(getuid()); + + if (audio_fd < 0) { + perror(snddevice->string); + Com_Printf("Could not open %s\n", snddevice->string); + return 0; + } + } + +#if 0 + /* Not applicable here */ + rc = ioctl(audio_fd, SNDCTL_DSP_RESET, 0); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not reset %s\n", snddevice->string); + close(audio_fd); + + return 0; + } +#endif + + if (ioctl(audio_fd, SNDCTL_DSP_GETCAPS, &caps) == -1) { + perror(snddevice->string); + Com_Printf("Sound driver too old\n"); + close(audio_fd); + return 0; + } + + if (!(caps & DSP_CAP_TRIGGER) || !(caps & DSP_CAP_MMAP)) { + Com_Printf("Sorry but your soundcard can't do this\n"); + close(audio_fd); + return 0; + } + + +/* SNDCTL_DSP_GETOSPACE moved to be called later */ + +// set sample bits & speed + dma.samplebits = (int)sndbits->value; + if (dma.samplebits != 16 && dma.samplebits != 8) { + ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt); + if (fmt & AFMT_S16_LE) + dma.samplebits = 16; + else if (fmt & AFMT_U8) + dma.samplebits = 8; + } + + dma.speed = (int)sndspeed->value; + if (!dma.speed) { + for (i=0 ; ivalue; + if (dma.channels < 1 || dma.channels > 2) + dma.channels = 2; + +/* mmap() call moved forward */ + + tmp = 0; + if (dma.channels == 2) + tmp = 1; + rc = ioctl(audio_fd, SNDCTL_DSP_STEREO, &tmp); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not set %s to stereo=%d", snddevice->string, dma.channels); + close(audio_fd); + return 0; + } + + if (tmp) + dma.channels = 2; + else + dma.channels = 1; + + rc = ioctl(audio_fd, SNDCTL_DSP_SPEED, &dma.speed); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not set %s speed to %d", snddevice->string, dma.speed); + close(audio_fd); + return 0; + } + + if (dma.samplebits == 16) { + rc = AFMT_S16_LE; + rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not support 16-bit data. Try 8-bit.\n"); + close(audio_fd); + return 0; + } + } else if (dma.samplebits == 8) { + rc = AFMT_U8; + rc = ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rc); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not support 8-bit data.\n"); + close(audio_fd); + return 0; + } + } else { + perror(snddevice->string); + Com_Printf("%d-bit sound not supported.", dma.samplebits); + close(audio_fd); + return 0; + } + + if (ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info)==-1) { + perror("GETOSPACE"); + Com_Printf("Um, can't do GETOSPACE?\n"); + close(audio_fd); + return 0; + } + + dma.samples = info.fragstotal * info.fragsize / (dma.samplebits/8); + dma.submission_chunk = 1; + +// memory map the dma buffer + + if (!dma.buffer) + dma.buffer = (unsigned char *) mmap(NULL, info.fragstotal + * info.fragsize, PROT_WRITE, MAP_FILE|MAP_SHARED, audio_fd, 0); + + if (!dma.buffer) { + perror(snddevice->string); + Com_Printf("Could not mmap %s\n", snddevice->string); + close(audio_fd); + return 0; + } + +// toggle the trigger & start her up + + tmp = 0; + rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not toggle.\n"); + close(audio_fd); + return 0; + } + + tmp = PCM_ENABLE_OUTPUT; + rc = ioctl(audio_fd, SNDCTL_DSP_SETTRIGGER, &tmp); + if (rc < 0) { + perror(snddevice->string); + Com_Printf("Could not toggle.\n"); + close(audio_fd); + + return 0; + } + + snd_inited = 1; + return 1; +} + +int SNDDMA_GetDMAPos(void) +{ + struct count_info count; + + if (!snd_inited) return 0; + + if (ioctl(audio_fd, SNDCTL_DSP_GETOPTR, &count) == -1) { + perror(snddevice->string); + Com_Printf("Uh, sound dead.\n"); + close(audio_fd); + snd_inited = 0; + return 0; + } + return count.ptr / (dma.samplebits / 8); +} + +void SNDDMA_Shutdown(void) +{ +} + +/* +============== +SNDDMA_Submit + +Send sound to device if buffer isn't really the dma buffer +=============== +*/ +void SNDDMA_Submit(void) +{ +} + +void SNDDMA_BeginPainting (void) +{ +} diff --git a/code/unix/matha.s b/code/unix/matha.s new file mode 100644 index 0000000..73174ee --- /dev/null +++ b/code/unix/matha.s @@ -0,0 +1,402 @@ +// +// math.s +// x86 assembly-language math routines. + +#define GLQUAKE 1 // don't include unneeded defs +#include "qasm.h" + + +#if id386 + + .data + + .align 4 +Ljmptab: .long Lcase0, Lcase1, Lcase2, Lcase3 + .long Lcase4, Lcase5, Lcase6, Lcase7 + + .text + +// TODO: rounding needed? +// stack parameter offset +#define val 4 + +.globl C(Invert24To16) +C(Invert24To16): + + movl val(%esp),%ecx + movl $0x100,%edx // 0x10000000000 as dividend + cmpl %edx,%ecx + jle LOutOfRange + + subl %eax,%eax + divl %ecx + + ret + +LOutOfRange: + movl $0xFFFFFFFF,%eax + ret + +#if 0 + +#define in 4 +#define out 8 + + .align 2 +.globl C(TransformVector) +C(TransformVector): + movl in(%esp),%eax + movl out(%esp),%edx + + flds (%eax) // in[0] + fmuls C(vright) // in[0]*vright[0] + flds (%eax) // in[0] | in[0]*vright[0] + fmuls C(vup) // in[0]*vup[0] | in[0]*vright[0] + flds (%eax) // in[0] | in[0]*vup[0] | in[0]*vright[0] + fmuls C(vpn) // in[0]*vpn[0] | in[0]*vup[0] | in[0]*vright[0] + + flds 4(%eax) // in[1] | ... + fmuls C(vright)+4 // in[1]*vright[1] | ... + flds 4(%eax) // in[1] | in[1]*vright[1] | ... + fmuls C(vup)+4 // in[1]*vup[1] | in[1]*vright[1] | ... + flds 4(%eax) // in[1] | in[1]*vup[1] | in[1]*vright[1] | ... + fmuls C(vpn)+4 // in[1]*vpn[1] | in[1]*vup[1] | in[1]*vright[1] | ... + fxch %st(2) // in[1]*vright[1] | in[1]*vup[1] | in[1]*vpn[1] | ... + + faddp %st(0),%st(5) // in[1]*vup[1] | in[1]*vpn[1] | ... + faddp %st(0),%st(3) // in[1]*vpn[1] | ... + faddp %st(0),%st(1) // vpn_accum | vup_accum | vright_accum + + flds 8(%eax) // in[2] | ... + fmuls C(vright)+8 // in[2]*vright[2] | ... + flds 8(%eax) // in[2] | in[2]*vright[2] | ... + fmuls C(vup)+8 // in[2]*vup[2] | in[2]*vright[2] | ... + flds 8(%eax) // in[2] | in[2]*vup[2] | in[2]*vright[2] | ... + fmuls C(vpn)+8 // in[2]*vpn[2] | in[2]*vup[2] | in[2]*vright[2] | ... + fxch %st(2) // in[2]*vright[2] | in[2]*vup[2] | in[2]*vpn[2] | ... + + faddp %st(0),%st(5) // in[2]*vup[2] | in[2]*vpn[2] | ... + faddp %st(0),%st(3) // in[2]*vpn[2] | ... + faddp %st(0),%st(1) // vpn_accum | vup_accum | vright_accum + + fstps 8(%edx) // out[2] + fstps 4(%edx) // out[1] + fstps (%edx) // out[0] + + ret + +#endif + +#define EMINS 4+4 +#define EMAXS 4+8 +#define P 4+12 + + .align 2 +.globl C(BoxOnPlaneSide) +C(BoxOnPlaneSide): + pushl %ebx + + movl P(%esp),%edx + movl EMINS(%esp),%ecx + xorl %eax,%eax + movl EMAXS(%esp),%ebx + movb pl_signbits(%edx),%al + cmpb $8,%al + jge Lerror + flds pl_normal(%edx) // p->normal[0] + fld %st(0) // p->normal[0] | p->normal[0] + jmp Ljmptab(,%eax,4) + + +//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +//dist2= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +Lcase0: + fmuls (%ebx) // p->normal[0]*emaxs[0] | p->normal[0] + flds pl_normal+4(%edx) // p->normal[1] | p->normal[0]*emaxs[0] | + // p->normal[0] + fxch %st(2) // p->normal[0] | p->normal[0]*emaxs[0] | + // p->normal[1] + fmuls (%ecx) // p->normal[0]*emins[0] | + // p->normal[0]*emaxs[0] | p->normal[1] + fxch %st(2) // p->normal[1] | p->normal[0]*emaxs[0] | + // p->normal[0]*emins[0] + fld %st(0) // p->normal[1] | p->normal[1] | + // p->normal[0]*emaxs[0] | + // p->normal[0]*emins[0] + fmuls 4(%ebx) // p->normal[1]*emaxs[1] | p->normal[1] | + // p->normal[0]*emaxs[0] | + // p->normal[0]*emins[0] + flds pl_normal+8(%edx) // p->normal[2] | p->normal[1]*emaxs[1] | + // p->normal[1] | p->normal[0]*emaxs[0] | + // p->normal[0]*emins[0] + fxch %st(2) // p->normal[1] | p->normal[1]*emaxs[1] | + // p->normal[2] | p->normal[0]*emaxs[0] | + // p->normal[0]*emins[0] + fmuls 4(%ecx) // p->normal[1]*emins[1] | + // p->normal[1]*emaxs[1] | + // p->normal[2] | p->normal[0]*emaxs[0] | + // p->normal[0]*emins[0] + fxch %st(2) // p->normal[2] | p->normal[1]*emaxs[1] | + // p->normal[1]*emins[1] | + // p->normal[0]*emaxs[0] | + // p->normal[0]*emins[0] + fld %st(0) // p->normal[2] | p->normal[2] | + // p->normal[1]*emaxs[1] | + // p->normal[1]*emins[1] | + // p->normal[0]*emaxs[0] | + // p->normal[0]*emins[0] + fmuls 8(%ebx) // p->normal[2]*emaxs[2] | + // p->normal[2] | + // p->normal[1]*emaxs[1] | + // p->normal[1]*emins[1] | + // p->normal[0]*emaxs[0] | + // p->normal[0]*emins[0] + fxch %st(5) // p->normal[0]*emins[0] | + // p->normal[2] | + // p->normal[1]*emaxs[1] | + // p->normal[1]*emins[1] | + // p->normal[0]*emaxs[0] | + // p->normal[2]*emaxs[2] + faddp %st(0),%st(3) //p->normal[2] | + // p->normal[1]*emaxs[1] | + // p->normal[1]*emins[1]+p->normal[0]*emins[0]| + // p->normal[0]*emaxs[0] | + // p->normal[2]*emaxs[2] + fmuls 8(%ecx) //p->normal[2]*emins[2] | + // p->normal[1]*emaxs[1] | + // p->normal[1]*emins[1]+p->normal[0]*emins[0]| + // p->normal[0]*emaxs[0] | + // p->normal[2]*emaxs[2] + fxch %st(1) //p->normal[1]*emaxs[1] | + // p->normal[2]*emins[2] | + // p->normal[1]*emins[1]+p->normal[0]*emins[0]| + // p->normal[0]*emaxs[0] | + // p->normal[2]*emaxs[2] + faddp %st(0),%st(3) //p->normal[2]*emins[2] | + // p->normal[1]*emins[1]+p->normal[0]*emins[0]| + // p->normal[0]*emaxs[0]+p->normal[1]*emaxs[1]| + // p->normal[2]*emaxs[2] + fxch %st(3) //p->normal[2]*emaxs[2] + + // p->normal[1]*emins[1]+p->normal[0]*emins[0]| + // p->normal[0]*emaxs[0]+p->normal[1]*emaxs[1]| + // p->normal[2]*emins[2] + faddp %st(0),%st(2) //p->normal[1]*emins[1]+p->normal[0]*emins[0]| + // dist1 | p->normal[2]*emins[2] + + jmp LSetSides + +//dist1= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +Lcase1: + fmuls (%ecx) // emins[0] + flds pl_normal+4(%edx) + fxch %st(2) + fmuls (%ebx) // emaxs[0] + fxch %st(2) + fld %st(0) + fmuls 4(%ebx) // emaxs[1] + flds pl_normal+8(%edx) + fxch %st(2) + fmuls 4(%ecx) // emins[1] + fxch %st(2) + fld %st(0) + fmuls 8(%ebx) // emaxs[2] + fxch %st(5) + faddp %st(0),%st(3) + fmuls 8(%ecx) // emins[2] + fxch %st(1) + faddp %st(0),%st(3) + fxch %st(3) + faddp %st(0),%st(2) + + jmp LSetSides + +//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +//dist2= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +Lcase2: + fmuls (%ebx) // emaxs[0] + flds pl_normal+4(%edx) + fxch %st(2) + fmuls (%ecx) // emins[0] + fxch %st(2) + fld %st(0) + fmuls 4(%ecx) // emins[1] + flds pl_normal+8(%edx) + fxch %st(2) + fmuls 4(%ebx) // emaxs[1] + fxch %st(2) + fld %st(0) + fmuls 8(%ebx) // emaxs[2] + fxch %st(5) + faddp %st(0),%st(3) + fmuls 8(%ecx) // emins[2] + fxch %st(1) + faddp %st(0),%st(3) + fxch %st(3) + faddp %st(0),%st(2) + + jmp LSetSides + +//dist1= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +Lcase3: + fmuls (%ecx) // emins[0] + flds pl_normal+4(%edx) + fxch %st(2) + fmuls (%ebx) // emaxs[0] + fxch %st(2) + fld %st(0) + fmuls 4(%ecx) // emins[1] + flds pl_normal+8(%edx) + fxch %st(2) + fmuls 4(%ebx) // emaxs[1] + fxch %st(2) + fld %st(0) + fmuls 8(%ebx) // emaxs[2] + fxch %st(5) + faddp %st(0),%st(3) + fmuls 8(%ecx) // emins[2] + fxch %st(1) + faddp %st(0),%st(3) + fxch %st(3) + faddp %st(0),%st(2) + + jmp LSetSides + +//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +//dist2= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +Lcase4: + fmuls (%ebx) // emaxs[0] + flds pl_normal+4(%edx) + fxch %st(2) + fmuls (%ecx) // emins[0] + fxch %st(2) + fld %st(0) + fmuls 4(%ebx) // emaxs[1] + flds pl_normal+8(%edx) + fxch %st(2) + fmuls 4(%ecx) // emins[1] + fxch %st(2) + fld %st(0) + fmuls 8(%ecx) // emins[2] + fxch %st(5) + faddp %st(0),%st(3) + fmuls 8(%ebx) // emaxs[2] + fxch %st(1) + faddp %st(0),%st(3) + fxch %st(3) + faddp %st(0),%st(2) + + jmp LSetSides + +//dist1= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +Lcase5: + fmuls (%ecx) // emins[0] + flds pl_normal+4(%edx) + fxch %st(2) + fmuls (%ebx) // emaxs[0] + fxch %st(2) + fld %st(0) + fmuls 4(%ebx) // emaxs[1] + flds pl_normal+8(%edx) + fxch %st(2) + fmuls 4(%ecx) // emins[1] + fxch %st(2) + fld %st(0) + fmuls 8(%ecx) // emins[2] + fxch %st(5) + faddp %st(0),%st(3) + fmuls 8(%ebx) // emaxs[2] + fxch %st(1) + faddp %st(0),%st(3) + fxch %st(3) + faddp %st(0),%st(2) + + jmp LSetSides + +//dist1= p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +//dist2= p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +Lcase6: + fmuls (%ebx) // emaxs[0] + flds pl_normal+4(%edx) + fxch %st(2) + fmuls (%ecx) // emins[0] + fxch %st(2) + fld %st(0) + fmuls 4(%ecx) // emins[1] + flds pl_normal+8(%edx) + fxch %st(2) + fmuls 4(%ebx) // emaxs[1] + fxch %st(2) + fld %st(0) + fmuls 8(%ecx) // emins[2] + fxch %st(5) + faddp %st(0),%st(3) + fmuls 8(%ebx) // emaxs[2] + fxch %st(1) + faddp %st(0),%st(3) + fxch %st(3) + faddp %st(0),%st(2) + + jmp LSetSides + +//dist1= p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +//dist2= p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +Lcase7: + fmuls (%ecx) // emins[0] + flds pl_normal+4(%edx) + fxch %st(2) + fmuls (%ebx) // emaxs[0] + fxch %st(2) + fld %st(0) + fmuls 4(%ecx) // emins[1] + flds pl_normal+8(%edx) + fxch %st(2) + fmuls 4(%ebx) // emaxs[1] + fxch %st(2) + fld %st(0) + fmuls 8(%ecx) // emins[2] + fxch %st(5) + faddp %st(0),%st(3) + fmuls 8(%ebx) // emaxs[2] + fxch %st(1) + faddp %st(0),%st(3) + fxch %st(3) + faddp %st(0),%st(2) + +LSetSides: + +// sides = 0; +// if (dist1 >= p->dist) +// sides = 1; +// if (dist2 < p->dist) +// sides |= 2; + + faddp %st(0),%st(2) // dist1 | dist2 + fcomps pl_dist(%edx) + xorl %ecx,%ecx + fnstsw %ax + fcomps pl_dist(%edx) + andb $1,%ah + xorb $1,%ah + addb %ah,%cl + + fnstsw %ax + andb $1,%ah + addb %ah,%ah + addb %ah,%cl + +// return sides; + + popl %ebx + movl %ecx,%eax // return status + + ret + + +Lerror: + movl 1, %eax + ret + +#endif // id386 diff --git a/code/unix/q3test.spec.sh b/code/unix/q3test.spec.sh new file mode 100644 index 0000000..a50e1f6 --- /dev/null +++ b/code/unix/q3test.spec.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# Generate Quake3 test +# $1 is version +# $2 is release +# $3 is arch +# $4 is install dir (assumed to be in /var/tmp) +cat < +URL: http://www.idsoftware.com/ +Source: q3test-%{version}.tar.gz +Group: Games +Copyright: Restricted +Icon: quake3.gif +BuildRoot: /var/tmp/%{name}-%{version} +Summary: Q3Test for Linux + +%description + +%install + +%files + +%attr(644,root,root) $4/README.EULA +%attr(644,root,root) $4/README.Q3Test +%attr(755,root,root) $4/linuxquake3 +%attr(755,root,root) $4/cgamei386.so +%attr(755,root,root) $4/qagamei386.so +%attr(755,root,root) $4/libMesaVoodooGL.so.3.1 +%attr(644,root,root) $4/demoq3/pak0.pk3 + +EOF + diff --git a/code/unix/qasm.h b/code/unix/qasm.h new file mode 100644 index 0000000..c31b6b8 --- /dev/null +++ b/code/unix/qasm.h @@ -0,0 +1,459 @@ +#ifndef __ASM_I386__ +#define __ASM_I386__ + +#ifdef ELF +#define C(label) label +#else +#define C(label) _##label +#endif + + +//#define GLQUAKE 1 + +#if defined(_WIN32) && !defined(WINDED) + +#if defined(_M_IX86) +#define __i386__ 1 +#endif + +#endif + +#ifdef __i386__ +#define id386 1 +#else +#define id386 0 +#endif + +// !!! must be kept the same as in d_iface.h !!! +#define TRANSPARENT_COLOR 255 + +#ifndef GLQUAKE + .extern C(d_zistepu) + .extern C(d_pzbuffer) + .extern C(d_zistepv) + .extern C(d_zrowbytes) + .extern C(d_ziorigin) + .extern C(r_turb_s) + .extern C(r_turb_t) + .extern C(r_turb_pdest) + .extern C(r_turb_spancount) + .extern C(r_turb_turb) + .extern C(r_turb_pbase) + .extern C(r_turb_sstep) + .extern C(r_turb_tstep) + .extern C(r_bmodelactive) + .extern C(d_sdivzstepu) + .extern C(d_tdivzstepu) + .extern C(d_sdivzstepv) + .extern C(d_tdivzstepv) + .extern C(d_sdivzorigin) + .extern C(d_tdivzorigin) + .extern C(sadjust) + .extern C(tadjust) + .extern C(bbextents) + .extern C(bbextentt) + .extern C(cacheblock) + .extern C(d_viewbuffer) + .extern C(cachewidth) + .extern C(d_pzbuffer) + .extern C(d_zrowbytes) + .extern C(d_zwidth) + .extern C(d_scantable) + .extern C(r_lightptr) + .extern C(r_numvblocks) + .extern C(prowdestbase) + .extern C(pbasesource) + .extern C(r_lightwidth) + .extern C(lightright) + .extern C(lightrightstep) + .extern C(lightdeltastep) + .extern C(lightdelta) + .extern C(lightright) + .extern C(lightdelta) + .extern C(sourcetstep) + .extern C(surfrowbytes) + .extern C(lightrightstep) + .extern C(lightdeltastep) + .extern C(r_sourcemax) + .extern C(r_stepback) + .extern C(colormap) + .extern C(blocksize) + .extern C(sourcesstep) + .extern C(lightleft) + .extern C(blockdivshift) + .extern C(blockdivmask) + .extern C(lightleftstep) + .extern C(r_origin) + .extern C(r_ppn) + .extern C(r_pup) + .extern C(r_pright) + .extern C(ycenter) + .extern C(xcenter) + .extern C(d_vrectbottom_particle) + .extern C(d_vrectright_particle) + .extern C(d_vrecty) + .extern C(d_vrectx) + .extern C(d_pix_shift) + .extern C(d_pix_min) + .extern C(d_pix_max) + .extern C(d_y_aspect_shift) + .extern C(screenwidth) + .extern C(r_leftclipped) + .extern C(r_leftenter) + .extern C(r_rightclipped) + .extern C(r_rightenter) + .extern C(modelorg) + .extern C(xscale) + .extern C(r_refdef) + .extern C(yscale) + .extern C(r_leftexit) + .extern C(r_rightexit) + .extern C(r_lastvertvalid) + .extern C(cacheoffset) + .extern C(newedges) + .extern C(removeedges) + .extern C(r_pedge) + .extern C(r_framecount) + .extern C(r_u1) + .extern C(r_emitted) + .extern C(edge_p) + .extern C(surface_p) + .extern C(surfaces) + .extern C(r_lzi1) + .extern C(r_v1) + .extern C(r_ceilv1) + .extern C(r_nearzi) + .extern C(r_nearzionly) + .extern C(edge_aftertail) + .extern C(edge_tail) + .extern C(current_iv) + .extern C(edge_head_u_shift20) + .extern C(span_p) + .extern C(edge_head) + .extern C(fv) + .extern C(edge_tail_u_shift20) + .extern C(r_apverts) + .extern C(r_anumverts) + .extern C(aliastransform) + .extern C(r_avertexnormals) + .extern C(r_plightvec) + .extern C(r_ambientlight) + .extern C(r_shadelight) + .extern C(aliasxcenter) + .extern C(aliasycenter) + .extern C(a_sstepxfrac) + .extern C(r_affinetridesc) + .extern C(acolormap) + .extern C(d_pcolormap) + .extern C(r_affinetridesc) + .extern C(d_sfrac) + .extern C(d_ptex) + .extern C(d_pedgespanpackage) + .extern C(d_tfrac) + .extern C(d_light) + .extern C(d_zi) + .extern C(d_pdest) + .extern C(d_pz) + .extern C(d_aspancount) + .extern C(erroradjustup) + .extern C(errorterm) + .extern C(d_xdenom) + .extern C(r_p0) + .extern C(r_p1) + .extern C(r_p2) + .extern C(a_tstepxfrac) + .extern C(r_sstepx) + .extern C(r_tstepx) + .extern C(a_ststepxwhole) + .extern C(zspantable) + .extern C(skintable) + .extern C(r_zistepx) + .extern C(erroradjustdown) + .extern C(d_countextrastep) + .extern C(ubasestep) + .extern C(a_ststepxwhole) + .extern C(a_tstepxfrac) + .extern C(r_lstepx) + .extern C(a_spans) + .extern C(erroradjustdown) + .extern C(d_pdestextrastep) + .extern C(d_pzextrastep) + .extern C(d_sfracextrastep) + .extern C(d_ptexextrastep) + .extern C(d_countextrastep) + .extern C(d_tfracextrastep) + .extern C(d_lightextrastep) + .extern C(d_ziextrastep) + .extern C(d_pdestbasestep) + .extern C(d_pzbasestep) + .extern C(d_sfracbasestep) + .extern C(d_ptexbasestep) + .extern C(ubasestep) + .extern C(d_tfracbasestep) + .extern C(d_lightbasestep) + .extern C(d_zibasestep) + .extern C(zspantable) + .extern C(r_lstepy) + .extern C(r_sstepy) + .extern C(r_tstepy) + .extern C(r_zistepy) + .extern C(D_PolysetSetEdgeTable) + .extern C(D_RasterizeAliasPolySmooth) + + .extern float_point5 + .extern Float2ToThe31nd + .extern izistep + .extern izi + .extern FloatMinus2ToThe31nd + .extern float_1 + .extern float_particle_z_clip + .extern float_minus_1 + .extern float_0 + .extern fp_16 + .extern fp_64k + .extern fp_1m + .extern fp_1m_minus_1 + .extern fp_8 + .extern entryvec_table + .extern advancetable + .extern sstep + .extern tstep + .extern pspantemp + .extern counttemp + .extern jumptemp + .extern reciprocal_table + .extern DP_Count + .extern DP_u + .extern DP_v + .extern DP_32768 + .extern DP_Color + .extern DP_Pix + .extern DP_EntryTable + .extern pbase + .extern s + .extern t + .extern sfracf + .extern tfracf + .extern snext + .extern tnext + .extern spancountminus1 + .extern zi16stepu + .extern sdivz16stepu + .extern tdivz16stepu + .extern zi8stepu + .extern sdivz8stepu + .extern tdivz8stepu + .extern reciprocal_table_16 + .extern entryvec_table_16 + .extern ceil_cw + .extern single_cw + .extern fp_64kx64k + .extern pz + .extern spr8entryvec_table +#endif + + .extern C(snd_scaletable) + .extern C(paintbuffer) + .extern C(snd_linear_count) + .extern C(snd_p) + .extern C(snd_vol) + .extern C(snd_out) + .extern C(vright) + .extern C(vup) + .extern C(vpn) + .extern C(BOPS_Error) + +// +// !!! note that this file must match the corresponding C structures at all +// times !!! +// + +// plane_t structure +// !!! if this is changed, it must be changed in model.h too !!! +// !!! if the size of this is changed, the array lookup in SV_HullPointContents +// must be changed too !!! +#define pl_normal 0 +#define pl_dist 12 +#define pl_type 16 +#define pl_signbits 17 +#define pl_pad 18 +#define pl_size 20 + +// hull_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define hu_clipnodes 0 +#define hu_planes 4 +#define hu_firstclipnode 8 +#define hu_lastclipnode 12 +#define hu_clip_mins 16 +#define hu_clip_maxs 28 +#define hu_size 40 + +// dnode_t structure +// !!! if this is changed, it must be changed in bspfile.h too !!! +#define nd_planenum 0 +#define nd_children 4 +#define nd_mins 8 +#define nd_maxs 20 +#define nd_firstface 32 +#define nd_numfaces 36 +#define nd_size 40 + +// sfxcache_t structure +// !!! if this is changed, it much be changed in sound.h too !!! +#define sfxc_length 0 +#define sfxc_loopstart 4 +#define sfxc_speed 8 +#define sfxc_width 12 +#define sfxc_stereo 16 +#define sfxc_data 20 + +// channel_t structure +// !!! if this is changed, it much be changed in sound.h too !!! +#define ch_sfx 0 +#define ch_leftvol 4 +#define ch_rightvol 8 +#define ch_end 12 +#define ch_pos 16 +#define ch_looping 20 +#define ch_entnum 24 +#define ch_entchannel 28 +#define ch_origin 32 +#define ch_dist_mult 44 +#define ch_master_vol 48 +#define ch_size 52 + +// portable_samplepair_t structure +// !!! if this is changed, it much be changed in sound.h too !!! +#define psp_left 0 +#define psp_right 4 +#define psp_size 8 + + +// +// !!! note that this file must match the corresponding C structures at all +// times !!! +// + +// !!! if this is changed, it must be changed in r_local.h too !!! +#define NEAR_CLIP 0.01 + +// !!! if this is changed, it must be changed in r_local.h too !!! +#define CYCLE 128 + +// espan_t structure +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define espan_t_u 0 +#define espan_t_v 4 +#define espan_t_count 8 +#define espan_t_pnext 12 +#define espan_t_size 16 + +// sspan_t structure +// !!! if this is changed, it must be changed in d_local.h too !!! +#define sspan_t_u 0 +#define sspan_t_v 4 +#define sspan_t_count 8 +#define sspan_t_size 12 + +// spanpackage_t structure +// !!! if this is changed, it must be changed in d_polyset.c too !!! +#define spanpackage_t_pdest 0 +#define spanpackage_t_pz 4 +#define spanpackage_t_count 8 +#define spanpackage_t_ptex 12 +#define spanpackage_t_sfrac 16 +#define spanpackage_t_tfrac 20 +#define spanpackage_t_light 24 +#define spanpackage_t_zi 28 +#define spanpackage_t_size 32 + +// edge_t structure +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define et_u 0 +#define et_u_step 4 +#define et_prev 8 +#define et_next 12 +#define et_surfs 16 +#define et_nextremove 20 +#define et_nearzi 24 +#define et_owner 28 +#define et_size 32 + +// surf_t structure +// !!! if this is changed, it must be changed in r_shared.h too !!! +#define SURF_T_SHIFT 6 +#define st_next 0 +#define st_prev 4 +#define st_spans 8 +#define st_key 12 +#define st_last_u 16 +#define st_spanstate 20 +#define st_flags 24 +#define st_data 28 +#define st_entity 32 +#define st_nearzi 36 +#define st_insubmodel 40 +#define st_d_ziorigin 44 +#define st_d_zistepu 48 +#define st_d_zistepv 52 +#define st_pad 56 +#define st_size 64 + +// clipplane_t structure +// !!! if this is changed, it must be changed in r_local.h too !!! +#define cp_normal 0 +#define cp_dist 12 +#define cp_next 16 +#define cp_leftedge 20 +#define cp_rightedge 21 +#define cp_reserved 22 +#define cp_size 24 + +// medge_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define me_v 0 +#define me_cachededgeoffset 4 +#define me_size 8 + +// mvertex_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define mv_position 0 +#define mv_size 12 + +// refdef_t structure +// !!! if this is changed, it must be changed in render.h too !!! +#define rd_vrect 0 +#define rd_aliasvrect 20 +#define rd_vrectright 40 +#define rd_vrectbottom 44 +#define rd_aliasvrectright 48 +#define rd_aliasvrectbottom 52 +#define rd_vrectrightedge 56 +#define rd_fvrectx 60 +#define rd_fvrecty 64 +#define rd_fvrectx_adj 68 +#define rd_fvrecty_adj 72 +#define rd_vrect_x_adj_shift20 76 +#define rd_vrectright_adj_shift20 80 +#define rd_fvrectright_adj 84 +#define rd_fvrectbottom_adj 88 +#define rd_fvrectright 92 +#define rd_fvrectbottom 96 +#define rd_horizontalFieldOfView 100 +#define rd_xOrigin 104 +#define rd_yOrigin 108 +#define rd_vieworg 112 +#define rd_viewangles 124 +#define rd_ambientlight 136 +#define rd_size 140 + +// mtriangle_t structure +// !!! if this is changed, it must be changed in model.h too !!! +#define mtri_facesfront 0 +#define mtri_vertindex 4 +#define mtri_size 16 // !!! if this changes, array indexing in !!! + // !!! d_polysa.s must be changed to match !!! +#define mtri_shift 4 + +#endif diff --git a/code/unix/quake3.gif b/code/unix/quake3.gif new file mode 100644 index 0000000..0e7a01c Binary files /dev/null and b/code/unix/quake3.gif differ diff --git a/code/unix/snd_mixa.s b/code/unix/snd_mixa.s new file mode 100644 index 0000000..d6c2945 --- /dev/null +++ b/code/unix/snd_mixa.s @@ -0,0 +1,197 @@ +// +// snd_mixa.s +// x86 assembly-language sound code +// + +#include "qasm.h" + +#if id386 + + .text + +#if 0 +//---------------------------------------------------------------------- +// 8-bit sound-mixing code +//---------------------------------------------------------------------- + +#define ch 4+16 +#define sc 8+16 +#define count 12+16 + +.globl C(S_PaintChannelFrom8) +C(S_PaintChannelFrom8): + pushl %esi // preserve register variables + pushl %edi + pushl %ebx + pushl %ebp + +// int data; +// short *lscale, *rscale; +// unsigned char *sfx; +// int i; + + movl ch(%esp),%ebx + movl sc(%esp),%esi + +// if (ch->leftvol > 255) +// ch->leftvol = 255; +// if (ch->rightvol > 255) +// ch->rightvol = 255; + movl ch_leftvol(%ebx),%eax + movl ch_rightvol(%ebx),%edx + cmpl $255,%eax + jna LLeftSet + movl $255,%eax +LLeftSet: + cmpl $255,%edx + jna LRightSet + movl $255,%edx +LRightSet: + +// lscale = snd_scaletable[ch->leftvol >> 3]; +// rscale = snd_scaletable[ch->rightvol >> 3]; +// sfx = (signed char *)sc->data + ch->pos; +// ch->pos += count; + andl $0xF8,%eax + addl $20,%esi + movl (%esi),%esi + andl $0xF8,%edx + movl ch_pos(%ebx),%edi + movl count(%esp),%ecx + addl %edi,%esi + shll $7,%eax + addl %ecx,%edi + shll $7,%edx + movl %edi,ch_pos(%ebx) + addl $(C(snd_scaletable)),%eax + addl $(C(snd_scaletable)),%edx + subl %ebx,%ebx + movb -1(%esi,%ecx,1),%bl + + testl $1,%ecx + jz LMix8Loop + + movl (%eax,%ebx,4),%edi + movl (%edx,%ebx,4),%ebp + addl C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size),%edi + addl C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size),%ebp + movl %edi,C(paintbuffer)+psp_left-psp_size(,%ecx,psp_size) + movl %ebp,C(paintbuffer)+psp_right-psp_size(,%ecx,psp_size) + movb -2(%esi,%ecx,1),%bl + + decl %ecx + jz LDone + +// for (i=0 ; i>8; +// if (val > 0x7fff) +// snd_out[i] = 0x7fff; +// else if (val < (short)0x8000) +// snd_out[i] = (short)0x8000; +// else +// snd_out[i] = val; + movl -8(%ebx,%ecx,4),%eax + sarl $8,%eax + cmpl $0x7FFF,%eax + jg LClampHigh + cmpl $0xFFFF8000,%eax + jnl LClampDone + movl $0xFFFF8000,%eax + jmp LClampDone +LClampHigh: + movl $0x7FFF,%eax +LClampDone: + +// val = (snd_p[i+1]*snd_vol)>>8; +// if (val > 0x7fff) +// snd_out[i+1] = 0x7fff; +// else if (val < (short)0x8000) +// snd_out[i+1] = (short)0x8000; +// else +// snd_out[i+1] = val; + movl -4(%ebx,%ecx,4),%edx + sarl $8,%edx + cmpl $0x7FFF,%edx + jg LClampHigh2 + cmpl $0xFFFF8000,%edx + jnl LClampDone2 + movl $0xFFFF8000,%edx + jmp LClampDone2 +LClampHigh2: + movl $0x7FFF,%edx +LClampDone2: + shll $16,%edx + andl $0xFFFF,%eax + orl %eax,%edx + movl %edx,-4(%edi,%ecx,2) + +// } + subl $2,%ecx + jnz LWLBLoopTop + +// snd_p += snd_linear_count; + + popl %ebx + popl %edi + + ret + + +#endif // id386 + diff --git a/code/unix/sys_dosa.s b/code/unix/sys_dosa.s new file mode 100644 index 0000000..cc29312 --- /dev/null +++ b/code/unix/sys_dosa.s @@ -0,0 +1,94 @@ +// +// sys_dosa.s +// x86 assembly-language DOS-dependent routines. + +#include "qasm.h" + + + .data + + .align 4 +fpenv: + .long 0, 0, 0, 0, 0, 0, 0, 0 + + .text + +.globl C(MaskExceptions) +C(MaskExceptions): + fnstenv fpenv + orl $0x3F,fpenv + fldenv fpenv + + ret + +#if 0 +.globl C(unmaskexceptions) +C(unmaskexceptions): + fnstenv fpenv + andl $0xFFFFFFE0,fpenv + fldenv fpenv + + ret +#endif + + .data + + .align 4 +.globl ceil_cw, single_cw, full_cw, cw, pushed_cw +ceil_cw: .long 0 +single_cw: .long 0 +full_cw: .long 0 +cw: .long 0 +pushed_cw: .long 0 + + .text + +.globl C(Sys_LowFPPrecision) +C(Sys_LowFPPrecision): + fldcw single_cw + + ret + +.globl C(Sys_HighFPPrecision) +C(Sys_HighFPPrecision): + fldcw full_cw + + ret + +.globl C(Sys_PushFPCW_SetHigh) +C(Sys_PushFPCW_SetHigh): + fnstcw pushed_cw + fldcw full_cw + + ret + +.globl C(Sys_PopFPCW) +C(Sys_PopFPCW): + fldcw pushed_cw + + ret + +.globl C(Sys_SetFPCW) +C(Sys_SetFPCW): + fnstcw cw + movl cw,%eax +#if id386 + andb $0xF0,%ah + orb $0x03,%ah // round mode, 64-bit precision +#endif + movl %eax,full_cw + +#if id386 + andb $0xF0,%ah + orb $0x0C,%ah // chop mode, single precision +#endif + movl %eax,single_cw + +#if id386 + andb $0xF0,%ah + orb $0x08,%ah // ceil mode, single precision +#endif + movl %eax,ceil_cw + + ret + diff --git a/code/unix/ui_video.c b/code/unix/ui_video.c new file mode 100644 index 0000000..e1a3cce --- /dev/null +++ b/code/unix/ui_video.c @@ -0,0 +1,702 @@ +#include "../client/client.h" +#include "../client/ui_local.h" + +extern void UI_ForceMenuOff( void ); + +static const char *s_driver_names[] = +{ + "[default OpenGL]", + "[Voodoo OpenGL]", + "[Custom ]", + 0 +}; + +static const char *s_drivers[] = +{ + OPENGL_DRIVER_NAME, + _3DFX_DRIVER_NAME, + "", + 0 +}; + +/* +==================================================================== + +MENU INTERACTION + +==================================================================== +*/ +static menuframework_s s_menu; + +static menulist_s s_graphics_options_list; +static menulist_s s_mode_list; +static menulist_s s_driver_list; +static menuslider_s s_tq_slider; +static menulist_s s_fs_box; +static menulist_s s_lighting_box; +static menulist_s s_allow_extensions_box; +static menulist_s s_texturebits_box; +static menulist_s s_colordepth_list; +static menulist_s s_geometry_box; +static menulist_s s_filter_box; +static menuaction_s s_driverinfo_action; +static menuaction_s s_apply_action; +static menuaction_s s_defaults_action; + +typedef struct +{ + int mode; + qboolean fullscreen; + int tq; + int lighting; + int colordepth; + int texturebits; + int geometry; + int filter; + int driver; + qboolean extensions; +} InitialVideoOptions_s; + +static InitialVideoOptions_s s_ivo; + +static InitialVideoOptions_s s_ivo_templates[] = +{ + { + 4, qtrue, 2, 0, 2, 2, 1, 1, 0, qtrue // JDC: this was tq 3 + }, + { + 3, qtrue, 2, 0, 0, 0, 1, 0, 0, qtrue + }, + { + 2, qtrue, 1, 0, 1, 0, 0, 0, 0, qtrue + }, + { + 1, qtrue, 1, 1, 1, 0, 0, 0, 0, qtrue + }, + { + 3, qtrue, 1, 0, 0, 0, 1, 0, 0, qtrue + } +}; + +#define NUM_IVO_TEMPLATES ( sizeof( s_ivo_templates ) / sizeof( s_ivo_templates[0] ) ) + +static void DrvInfo_MenuDraw( void ); +static const char * DrvInfo_MenuKey( int key ); + +static void GetInitialVideoVars( void ) +{ + s_ivo.colordepth = s_colordepth_list.curvalue; + s_ivo.driver = s_driver_list.curvalue; + s_ivo.mode = s_mode_list.curvalue; + s_ivo.fullscreen = s_fs_box.curvalue; + s_ivo.extensions = s_allow_extensions_box.curvalue; + s_ivo.tq = s_tq_slider.curvalue; + s_ivo.lighting = s_lighting_box.curvalue; + s_ivo.geometry = s_geometry_box.curvalue; + s_ivo.filter = s_filter_box.curvalue; + s_ivo.texturebits = s_texturebits_box.curvalue; +} + +static void CheckConfigVsTemplates( void ) +{ + int i; + + for ( i = 0; i < NUM_IVO_TEMPLATES; i++ ) + { + if ( s_driver_list.curvalue != 1 ) + if ( s_ivo_templates[i].colordepth != s_colordepth_list.curvalue ) + continue; +#if 0 + if ( s_ivo_templates[i].driver != s_driver_list.curvalue ) + continue; +#endif + if ( s_ivo_templates[i].mode != s_mode_list.curvalue ) + continue; + if ( s_driver_list.curvalue != 1 ) + if ( s_ivo_templates[i].fullscreen != s_fs_box.curvalue ) + continue; + if ( s_ivo_templates[i].tq != s_tq_slider.curvalue ) + continue; + if ( s_ivo_templates[i].lighting != s_lighting_box.curvalue ) + continue; + if ( s_ivo_templates[i].geometry != s_geometry_box.curvalue ) + continue; + if ( s_ivo_templates[i].filter != s_filter_box.curvalue ) + continue; +// if ( s_ivo_templates[i].texturebits != s_texturebits_box.curvalue ) +// continue; + s_graphics_options_list.curvalue = i; + return; + } + s_graphics_options_list.curvalue = 4; +} + +static void UpdateMenuItemValues( void ) +{ + if ( s_driver_list.curvalue == 1 ) + { + s_fs_box.curvalue = 1; + s_fs_box.generic.flags = QMF_GRAYED; + s_colordepth_list.curvalue = 1; + } + else + { + s_fs_box.generic.flags = 0; + } + + if ( s_fs_box.curvalue == 0 || s_driver_list.curvalue == 1 ) + { + s_colordepth_list.curvalue = 0; + s_colordepth_list.generic.flags = QMF_GRAYED; + } + else + { + s_colordepth_list.generic.flags = 0; + } + + if ( s_allow_extensions_box.curvalue == 0 ) + { + if ( s_texturebits_box.curvalue == 0 ) + { + s_texturebits_box.curvalue = 1; + } + } + + s_apply_action.generic.flags = QMF_GRAYED; + + if ( s_ivo.mode != s_mode_list.curvalue ) + { + s_apply_action.generic.flags = QMF_BLINK; + } + if ( s_ivo.fullscreen != s_fs_box.curvalue ) + { + s_apply_action.generic.flags = QMF_BLINK; + } + if ( s_ivo.extensions != s_allow_extensions_box.curvalue ) + { + s_apply_action.generic.flags = QMF_BLINK; + } + if ( s_ivo.tq != s_tq_slider.curvalue ) + { + s_apply_action.generic.flags = QMF_BLINK; + } + if ( s_ivo.lighting != s_lighting_box.curvalue ) + { + s_apply_action.generic.flags = QMF_BLINK; + } + if ( s_ivo.colordepth != s_colordepth_list.curvalue ) + { + s_apply_action.generic.flags = QMF_BLINK; + } + if ( s_ivo.driver != s_driver_list.curvalue ) + { + s_apply_action.generic.flags = QMF_BLINK; + } + if ( s_ivo.texturebits != s_texturebits_box.curvalue ) + { + s_apply_action.generic.flags = QMF_BLINK; + } + if ( s_ivo.geometry != s_geometry_box.curvalue ) + { + s_apply_action.generic.flags = QMF_BLINK; + } + if ( s_ivo.filter != s_filter_box.curvalue ) + { + s_apply_action.generic.flags = QMF_BLINK; + } + + CheckConfigVsTemplates(); +} + +static void SetMenuItemValues( void ) +{ + s_mode_list.curvalue = Cvar_VariableValue( "r_mode" ); + s_fs_box.curvalue = Cvar_VariableValue("r_fullscreen"); + s_allow_extensions_box.curvalue = Cvar_VariableValue("r_allowExtensions"); + s_tq_slider.curvalue = 3-Cvar_VariableValue( "r_picmip"); + if ( s_tq_slider.curvalue < 0 ) + { + s_tq_slider.curvalue = 0; + } + else if ( s_tq_slider.curvalue > 3 ) + { + s_tq_slider.curvalue = 3; + } + + s_lighting_box.curvalue = Cvar_VariableValue( "r_vertexLight" ) != 0; + switch ( ( int ) Cvar_VariableValue( "r_texturebits" ) ) + { + case 0: + default: + s_texturebits_box.curvalue = 0; + break; + case 16: + s_texturebits_box.curvalue = 1; + break; + case 32: + s_texturebits_box.curvalue = 2; + break; + } + + if ( !Q_stricmp( Cvar_VariableString( "r_textureMode" ), "GL_LINEAR_MIPMAP_NEAREST" ) ) + { + s_filter_box.curvalue = 0; + } + else + { + s_filter_box.curvalue = 1; + } + + if ( Cvar_VariableValue( "r_subdivisions" ) == 999 || + Cvar_VariableValue( "r_lodBias" ) > 0 ) + { + s_geometry_box.curvalue = 0; + } + else + { + s_geometry_box.curvalue = 1; + } + + switch ( ( int ) Cvar_VariableValue( "r_colorbits" ) ) + { + default: + case 0: + s_colordepth_list.curvalue = 0; + break; + case 16: + s_colordepth_list.curvalue = 1; + break; + case 32: + s_colordepth_list.curvalue = 2; + break; + } + + if ( s_fs_box.curvalue == 0 ) + { + s_colordepth_list.curvalue = 0; + } + if ( s_driver_list.curvalue == 1 ) + { + s_colordepth_list.curvalue = 1; + } +} + +static void FullscreenCallback( void *s ) +{ +} + +static void ModeCallback( void *s ) +{ + // clamp 3dfx video modes + if ( s_driver_list.curvalue == 1 ) + { + if ( s_mode_list.curvalue < 2 ) + { + s_mode_list.curvalue = 2; + } + else if ( s_mode_list.curvalue > 6 ) + { + s_mode_list.curvalue = 6; + } + } +} + +static void GraphicsOptionsCallback( void *s ) +{ + InitialVideoOptions_s *ivo = &s_ivo_templates[s_graphics_options_list.curvalue]; + + s_mode_list.curvalue = ivo->mode; + s_tq_slider.curvalue = ivo->tq; + s_lighting_box.curvalue = ivo->lighting; + s_colordepth_list.curvalue = ivo->colordepth; + s_texturebits_box.curvalue = ivo->texturebits; + s_geometry_box.curvalue = ivo->geometry; + s_filter_box.curvalue = ivo->filter; + s_fs_box.curvalue = ivo->fullscreen; +} + +static void TextureDetailCallback( void *s ) +{ +} + +static void TextureQualityCallback( void *s ) +{ +} + +static void ExtensionsCallback( void *s ) +{ +} + +static void ColorDepthCallback( void *s ) +{ +} + +static void DriverInfoCallback( void *s ) +{ + UI_PushMenu( DrvInfo_MenuDraw, DrvInfo_MenuKey ); +} + +static void LightingCallback( void * s ) +{ +} + +static void ApplyChanges( void *unused ) +{ + switch ( s_texturebits_box.curvalue ) + { + case 0: + Cvar_SetValue( "r_texturebits", 0 ); + Cvar_SetValue( "r_ext_compress_textures", 1 ); + break; + case 1: + Cvar_SetValue( "r_texturebits", 16 ); + Cvar_SetValue( "r_ext_compress_textures", 0 ); + break; + case 2: + Cvar_SetValue( "r_texturebits", 32 ); + Cvar_SetValue( "r_ext_compress_textures", 0 ); + break; + } + Cvar_SetValue( "r_picmip", 3 - s_tq_slider.curvalue ); + Cvar_SetValue( "r_allowExtensions", s_allow_extensions_box.curvalue ); + Cvar_SetValue( "r_mode", s_mode_list.curvalue ); + Cvar_SetValue( "r_fullscreen", s_fs_box.curvalue ); + if (*s_drivers[s_driver_list.curvalue] ) + Cvar_Set( "r_glDriver", ( char * ) s_drivers[s_driver_list.curvalue] ); + switch ( s_colordepth_list.curvalue ) + { + case 0: + Cvar_SetValue( "r_colorbits", 0 ); + Cvar_SetValue( "r_depthbits", 0 ); + Cvar_SetValue( "r_stencilbits", 0 ); + break; + case 1: + Cvar_SetValue( "r_colorbits", 16 ); + Cvar_SetValue( "r_depthbits", 16 ); + Cvar_SetValue( "r_stencilbits", 0 ); + break; + case 2: + Cvar_SetValue( "r_colorbits", 32 ); + Cvar_SetValue( "r_depthbits", 24 ); + break; + } + Cvar_SetValue( "r_vertexLight", s_lighting_box.curvalue ); + + if ( s_geometry_box.curvalue ) + { + Cvar_SetValue( "r_lodBias", 0 ); + Cvar_SetValue( "r_subdivisions", 4 ); + } + else + { + Cvar_SetValue( "r_lodBias", 1 ); + Cvar_SetValue( "r_subdivisions", 999 ); + } + + if ( s_filter_box.curvalue ) + { + Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_LINEAR" ); + } + else + { + Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); + } + + UI_ForceMenuOff(); + + CL_Vid_Restart_f(); + + VID_MenuInit(); + +// s_fs_box.curvalue = Cvar_VariableValue( "r_fullscreen" ); +} + +/* +** VID_MenuInit +*/ +void VID_MenuInit( void ) +{ + static const char *tq_names[] = + { + "compressed", + "16-bit", + "32-bit", + 0 + }; + + static const char *s_graphics_options_names[] = + { + "high quality", + "normal", + "fast", + "fastest", + "custom", + 0 + }; + + static const char *lighting_names[] = + { + "lightmap", + "vertex", + 0 + }; + + static const char *colordepth_names[] = + { + "default", + "16-bit", + "32-bit", + 0 + }; + + static const char *resolutions[] = + { + "[320 240 ]", + "[400 300 ]", + "[512 384 ]", + "[640 480 ]", + "[800 600 ]", + "[960 720 ]", + "[1024 768 ]", + "[1152 864 ]", + "[1280 960 ]", + "[1600 1200]", + "[2048 1536]", + "[856 480 W]", + 0 + }; + static const char *filter_names[] = + { + "bilinear", + "trilinear", + 0 + }; + static const char *quality_names[] = + { + "low", + "high", + 0 + }; + static const char *enabled_names[] = + { + "disabled", + "enabled", + 0 + }; + int y = 0; + int i; + char *p; + + s_menu.x = SCREEN_WIDTH * 0.50; + s_menu.nitems = 0; + s_menu.wrapAround = qtrue; + + s_graphics_options_list.generic.type = MTYPE_SPINCONTROL; + s_graphics_options_list.generic.name = "graphics mode"; + s_graphics_options_list.generic.x = 0; + s_graphics_options_list.generic.y = y; + s_graphics_options_list.generic.callback = GraphicsOptionsCallback; + s_graphics_options_list.itemnames = s_graphics_options_names; + + s_driver_list.generic.type = MTYPE_SPINCONTROL; + s_driver_list.generic.name = "driver"; + s_driver_list.generic.x = 0; + s_driver_list.generic.y = y += 18; + + p = Cvar_VariableString( "r_glDriver" ); + for (i = 0; s_drivers[i]; i++) { + if (strcmp(s_drivers[i], p) == 0) + break; + } + if (!s_drivers[i]) + i--; // go back one, to default 'custom' + s_driver_list.curvalue = i; + + s_driver_list.itemnames = s_driver_names; + + // references/modifies "r_allowExtensions" + s_allow_extensions_box.generic.type = MTYPE_SPINCONTROL; + s_allow_extensions_box.generic.x = 0; + s_allow_extensions_box.generic.y = y += 18; + s_allow_extensions_box.generic.name = "OpenGL extensions"; + s_allow_extensions_box.generic.callback = ExtensionsCallback; + s_allow_extensions_box.itemnames = enabled_names; + + // references/modifies "r_mode" + s_mode_list.generic.type = MTYPE_SPINCONTROL; + s_mode_list.generic.name = "video mode"; + s_mode_list.generic.x = 0; + s_mode_list.generic.y = y += 36; + s_mode_list.itemnames = resolutions; + s_mode_list.generic.callback = ModeCallback; + + // references "r_colorbits" + s_colordepth_list.generic.type = MTYPE_SPINCONTROL; + s_colordepth_list.generic.name = "color depth"; + s_colordepth_list.generic.x = 0; + s_colordepth_list.generic.y = y += 18; + s_colordepth_list.itemnames = colordepth_names; + s_colordepth_list.generic.callback = ColorDepthCallback; + + // references/modifies "r_fullscreen" + s_fs_box.generic.type = MTYPE_RADIOBUTTON; + s_fs_box.generic.x = 0; + s_fs_box.generic.y = y += 18; + s_fs_box.generic.name = "fullscreen"; + s_fs_box.generic.callback = FullscreenCallback; + + // references/modifies "r_vertexLight" + s_lighting_box.generic.type = MTYPE_SPINCONTROL; + s_lighting_box.generic.x = 0; + s_lighting_box.generic.y = y += 18; + s_lighting_box.generic.name = "lighting"; + s_lighting_box.itemnames = lighting_names; + s_lighting_box.generic.callback = LightingCallback; + + // references/modifies "r_lodBias" & "subdivisions" + s_geometry_box.generic.type = MTYPE_SPINCONTROL; + s_geometry_box.generic.x = 0; + s_geometry_box.generic.y = y += 18; + s_geometry_box.generic.name = "geometric detail"; + s_geometry_box.itemnames = quality_names; + + // references/modifies "r_picmip" + s_tq_slider.generic.type = MTYPE_SLIDER; + s_tq_slider.generic.x = 0; + s_tq_slider.generic.y = y += 18; + s_tq_slider.generic.name = "texture detail"; + s_tq_slider.generic.callback = TextureDetailCallback; + s_tq_slider.minvalue = 0; + s_tq_slider.maxvalue = 3; + + // references/modifies "r_textureBits" + s_texturebits_box.generic.type = MTYPE_SPINCONTROL; + s_texturebits_box.generic.x = 0; + s_texturebits_box.generic.y = y += 18; + s_texturebits_box.generic.name = "texture quality"; + s_texturebits_box.generic.callback = TextureQualityCallback; + s_texturebits_box.itemnames = tq_names; + + // references/modifies "r_textureMode" + s_filter_box.generic.type = MTYPE_SPINCONTROL; + s_filter_box.generic.x = 0; + s_filter_box.generic.y = y += 18; + s_filter_box.generic.name = "texture filter"; + s_filter_box.itemnames = filter_names; + + s_driverinfo_action.generic.type = MTYPE_ACTION; + s_driverinfo_action.generic.name = "driver information"; + s_driverinfo_action.generic.x = 0; + s_driverinfo_action.generic.y = y += 36; + s_driverinfo_action.generic.callback = DriverInfoCallback; + + s_apply_action.generic.type = MTYPE_ACTION; + s_apply_action.generic.name = "apply"; + s_apply_action.generic.x = 0; + s_apply_action.generic.y = y += 36; + s_apply_action.generic.callback = ApplyChanges; + s_apply_action.generic.flags = QMF_GRAYED; + + SetMenuItemValues(); + GetInitialVideoVars(); + + Menu_AddItem( &s_menu, ( void * ) &s_graphics_options_list ); + Menu_AddItem( &s_menu, ( void * ) &s_driver_list ); + Menu_AddItem( &s_menu, ( void * ) &s_allow_extensions_box ); + Menu_AddItem( &s_menu, ( void * ) &s_mode_list ); + Menu_AddItem( &s_menu, ( void * ) &s_colordepth_list ); + Menu_AddItem( &s_menu, ( void * ) &s_fs_box ); + Menu_AddItem( &s_menu, ( void * ) &s_lighting_box ); + Menu_AddItem( &s_menu, ( void * ) &s_geometry_box ); + Menu_AddItem( &s_menu, ( void * ) &s_tq_slider ); + Menu_AddItem( &s_menu, ( void * ) &s_texturebits_box ); + Menu_AddItem( &s_menu, ( void * ) &s_filter_box ); + + Menu_AddItem( &s_menu, ( void * ) &s_driverinfo_action ); + Menu_AddItem( &s_menu, ( void * ) &s_apply_action ); + + Menu_Center( &s_menu ); + s_menu.y -= 6; +} + +/* +================ +VID_MenuDraw +================ +*/ +void VID_MenuDraw (void) +{ + UpdateMenuItemValues(); + Menu_AdjustCursor( &s_menu, 1 ); + Menu_Draw( &s_menu ); +} + +/* +================ +VID_MenuKey +================ +*/ +const char *VID_MenuKey( int key ) +{ + menuframework_s *m = &s_menu; + static const char *sound = "sound/misc/menu1.wav"; + + if ( key == K_ENTER ) + { + if ( !Menu_SelectItem( m ) ) + ApplyChanges( NULL ); + return NULL; + } + return Default_MenuKey( m, key ); + +} + +static void DrvInfo_MenuDraw( void ) +{ + float labelColor[] = { 0, 1.0, 0, 1.0 }; + float textColor[] = { 1, 1, 1, 1 }; + int i = 14; + char extensionsString[1024], *eptr = extensionsString; + + SCR_DrawBigStringColor( BIGCHAR_WIDTH * 4, BIGCHAR_HEIGHT * 3, "VENDOR:", labelColor ); + SCR_DrawBigStringColor( BIGCHAR_WIDTH * 4, BIGCHAR_HEIGHT * 4, Cvar_VariableString( "gl_vendor" ), textColor ); + SCR_DrawBigStringColor( BIGCHAR_WIDTH * 4, BIGCHAR_HEIGHT * 5.5, "VERSION:", labelColor ); + SCR_DrawBigStringColor( BIGCHAR_WIDTH * 4, BIGCHAR_HEIGHT * 6.5, Cvar_VariableString( "gl_version" ), textColor ); + SCR_DrawBigStringColor( BIGCHAR_WIDTH * 4, BIGCHAR_HEIGHT * 8, "RENDERER:", labelColor ); + SCR_DrawBigStringColor( BIGCHAR_WIDTH * 4, BIGCHAR_HEIGHT * 9, Cvar_VariableString( "gl_renderer" ), textColor ); + SCR_DrawBigStringColor( BIGCHAR_WIDTH * 4, BIGCHAR_HEIGHT * 10.5, "PIXELFORMAT:", labelColor ); + SCR_DrawBigStringColor( BIGCHAR_WIDTH * 4, BIGCHAR_HEIGHT * 11.5, Cvar_VariableString( "gl_pixelformat" ), textColor ); + + SCR_DrawBigStringColor( BIGCHAR_WIDTH * 4, BIGCHAR_HEIGHT * 13, "EXTENSIONS:", labelColor ); + strcpy( extensionsString, Cvar_VariableString( "gl_extensions" ) ); + while ( i < 25 && *eptr ) + { + while ( *eptr ) + { + char buf[2] = " "; + int j = BIGCHAR_WIDTH * 6; + + while ( *eptr && *eptr != ' ' ) + { + buf[0] = *eptr; + SCR_DrawBigStringColor( j, i * BIGCHAR_HEIGHT, buf, textColor ); + j += BIGCHAR_WIDTH; + eptr++; + } + + i++; + + while ( *eptr && *eptr == ' ' ) + eptr++; + } + } +} + +static const char * DrvInfo_MenuKey( int key ) +{ + if ( key == K_ESCAPE ) + UI_PopMenu(); + return NULL; +} + + diff --git a/code/unix/unix_glw.h b/code/unix/unix_glw.h new file mode 100644 index 0000000..41a02f1 --- /dev/null +++ b/code/unix/unix_glw.h @@ -0,0 +1,17 @@ +#ifndef __linux__ +#error You shouldnt be including this file on non-Linux platforms +#endif + +#ifndef __GLW_LINUX_H__ +#define __GLW_LINUX_H__ + +typedef struct +{ + void *OpenGLLib; // instance of OpenGL library + + FILE *log_fp; +} glwstate_t; + +extern glwstate_t glw_state; + +#endif diff --git a/code/unix/unix_main.c b/code/unix/unix_main.c new file mode 100644 index 0000000..d2d415f --- /dev/null +++ b/code/unix/unix_main.c @@ -0,0 +1,809 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../game/q_shared.h" +#include "../qcommon/qcommon.h" +#include "../renderer/tr_public.h" + +cvar_t *nostdout; + +// Structure containing functions exported from refresh DLL +refexport_t re; + +unsigned sys_frame_time; + +uid_t saved_euid; +qboolean stdin_active = qtrue; + +// ======================================================================= +// General routines +// ======================================================================= + +void Sys_BeginProfiling( void ) { +} + +/* +================= +Sys_In_Restart_f + +Restart the input subsystem +================= +*/ +void Sys_In_Restart_f( void ) +{ + IN_Shutdown(); + IN_Init(); +} + +void Sys_ConsoleOutput (char *string) +{ + if (nostdout && nostdout->value) + return; + + fputs(string, stdout); +} + +void Sys_Printf (char *fmt, ...) +{ + va_list argptr; + char text[1024]; + unsigned char *p; + + va_start (argptr,fmt); + vsprintf (text,fmt,argptr); + va_end (argptr); + + if (strlen(text) > sizeof(text)) + Sys_Error("memory overwrite in Sys_Printf"); + + if (nostdout && nostdout->value) + return; + + for (p = (unsigned char *)text; *p; p++) { + *p &= 0x7f; + if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9) + printf("[%02x]", *p); + else + putc(*p, stdout); + } +} + +void Sys_Quit (void) +{ + CL_Shutdown (); + fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); + _exit(0); +} + +void Sys_Init(void) +{ + Cmd_AddCommand ("in_restart", Sys_In_Restart_f); + +#if id386 + Sys_SetFPCW(); +#endif + +#if defined __linux__ +#if defined __i386__ + Cvar_Set( "arch", "linux i386" ); +#elif defined __alpha__ + Cvar_Set( "arch", "linux alpha" ); +#elif defined __sparc__ + Cvar_Set( "arch", "linux sparc" ); +#else + Cvar_Set( "arch", "linux unknown" ); +#endif +#elif defined __sun__ +#if defined __i386__ + Cvar_Set( "arch", "solaris x86" ); +#elif defined __sparc__ + Cvar_Set( "arch", "solaris sparc" ); +#else + Cvar_Set( "arch", "solaris unknown" ); +#endif +#elif defined __sgi__ +#if defined __mips__ + Cvar_Set( "arch", "sgi mips" ); +#else + Cvar_Set( "arch", "sgi unknown" ); +#endif +#else + Cvar_Set( "arch", "unknown" ); +#endif + + IN_Init(); + +} + +void Sys_Error( const char *error, ...) +{ + va_list argptr; + char string[1024]; + +// change stdin to non blocking + fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); + + CL_Shutdown (); + + va_start (argptr,error); + vsprintf (string,error,argptr); + va_end (argptr); + fprintf(stderr, "Error: %s\n", string); + + _exit (1); + +} + +void Sys_Warn (char *warning, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,warning); + vsprintf (string,warning,argptr); + va_end (argptr); + fprintf(stderr, "Warning: %s", string); +} + +/* +============ +Sys_FileTime + +returns -1 if not present +============ +*/ +int Sys_FileTime (char *path) +{ + struct stat buf; + + if (stat (path,&buf) == -1) + return -1; + + return buf.st_mtime; +} + +void floating_point_exception_handler(int whatever) +{ +// Sys_Warn("floating point exception\n"); + signal(SIGFPE, floating_point_exception_handler); +} + +char *Sys_ConsoleInput(void) +{ + static char text[256]; + int len; + fd_set fdset; + struct timeval timeout; + + if (!com_dedicated || !com_dedicated->value) + return NULL; + + if (!stdin_active) + return NULL; + + FD_ZERO(&fdset); + FD_SET(0, &fdset); // stdin + timeout.tv_sec = 0; + timeout.tv_usec = 0; + if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset)) + return NULL; + + len = read (0, text, sizeof(text)); + if (len == 0) { // eof! + stdin_active = qfalse; + return NULL; + } + + if (len < 1) + return NULL; + text[len-1] = 0; // rip off the /n and terminate + + return text; +} + +/*****************************************************************************/ + +static void *game_library; + +#ifdef __i386__ + const char *gamename = "qagamei386.so"; +#elif defined __alpha__ + const char *gamename = "qagameaxp.so"; +#elif defined __mips__ + const char *gamename = "qagamemips.so"; +#else +#error Unknown arch +#endif + +/* +================= +Sys_UnloadGame +================= +*/ +void Sys_UnloadGame (void) +{ + Com_Printf("------ Unloading %s ------\n", gamename); + if (game_library) + dlclose (game_library); + game_library = NULL; +} + +/* +================= +Sys_GetGameAPI + +Loads the game dll +================= +*/ +void *Sys_GetGameAPI (void *parms) +{ + void *(*GetGameAPI) (void *); + + char name[MAX_OSPATH]; + char curpath[MAX_OSPATH]; + char *path; + if (game_library) + Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame"); + + // check the current debug directory first for development purposes + getcwd(curpath, sizeof(curpath)); + + Com_Printf("------- Loading %s -------\n", gamename); + Com_sprintf (name, sizeof(name), "%s/%s", curpath, gamename); + + game_library = dlopen (name, RTLD_LAZY ); + if (game_library) + Com_DPrintf ("LoadLibrary (%s)\n",name); + else { + Com_Printf( "LoadLibrary(\"%s\") failed\n", name); + Com_Printf( "...reason: '%s'\n", dlerror() ); + Com_Error( ERR_FATAL, "Couldn't load game" ); + } + + GetGameAPI = (void *)dlsym (game_library, "GetGameAPI"); + if (!GetGameAPI) + { + Sys_UnloadGame (); + return NULL; + } + + return GetGameAPI (parms); +} + +/*****************************************************************************/ + +static void *cgame_library; + +/* +================= +Sys_UnloadGame +================= +*/ +void Sys_UnloadCGame (void) +{ + if (cgame_library) + dlclose (cgame_library); + cgame_library = NULL; +} + +/* +================= +Sys_GetGameAPI + +Loads the game dll +================= +*/ +void *Sys_GetCGameAPI (void) +{ + void *(*api) (void); + + char name[MAX_OSPATH]; + char curpath[MAX_OSPATH]; +#ifdef __i386__ + const char *cgamename = "cgamei386.so"; +#elif defined __alpha__ + const char *cgamename = "cgameaxp.so"; +#elif defined __mips__ + const char *cgamename = "cgamemips.so"; +#else +#error Unknown arch +#endif + + Sys_UnloadCGame(); + + getcwd(curpath, sizeof(curpath)); + + Com_Printf("------- Loading %s -------\n", cgamename); + + sprintf (name, "%s/%s", curpath, cgamename); + cgame_library = dlopen (name, RTLD_LAZY ); + if (!cgame_library) + { + Com_Printf ("LoadLibrary (%s)\n",name); + Com_Error( ERR_FATAL, "Couldn't load cgame: %s", dlerror() ); + } + + api = (void *)dlsym (cgame_library, "GetCGameAPI"); + if (!api) + { + Com_Error( ERR_FATAL, "dlsym() failed on GetCGameAPI" ); + } + + return api(); +} + +/*****************************************************************************/ + +static void *ui_library; + +/* +================= +Sys_UnloadUI +================= +*/ +void Sys_UnloadUI(void) +{ + if (ui_library) + dlclose (ui_library); + ui_library = NULL; +} + +/* +================= +Sys_GetUIAPI + +Loads the ui dll +================= +*/ +void *Sys_GetUIAPI (void) +{ + void *api; + + char name[MAX_OSPATH]; + char curpath[MAX_OSPATH]; +#ifdef __i386__ + const char *uiname = "uii386.so"; +#elif defined __alpha__ + const char *uiname = "uiaxp.so"; +#elif defined __mips__ + const char *uiname = "uimips.so"; +#else +#error Unknown arch +#endif + + Sys_UnloadUI(); + + getcwd(curpath, sizeof(curpath)); + + Com_Printf("------- Loading %s -------\n", uiname); + + sprintf (name, "%s/%s", curpath, uiname); + ui_library = dlopen (name, RTLD_LAZY ); + if (!ui_library) + { + Com_Printf ("LoadLibrary (%s)\n",name); + Com_Error( ERR_FATAL, "Couldn't load ui: %s", dlerror() ); + } + + api = (void *)dlsym (ui_library, "GetUIAPI"); + if (!api) + { + Com_Error( ERR_FATAL, "dlsym() failed on GetUIAPI" ); + } + + return api; +} + +/*****************************************************************************/ + +void *Sys_GetRefAPI (void *parms) +{ + return (void *)GetRefAPI(REF_API_VERSION, parms); +} + +/* +======================================================================== + +BACKGROUND FILE STREAMING + +======================================================================== +*/ + +typedef struct { +#if 0 + HANDLE threadHandle; + int threadId; + CRITICAL_SECTION crit; +#endif + FILE *file; + byte *buffer; + qboolean eof; + int bufferSize; + int streamPosition; // next byte to be returned by Sys_StreamRead + int threadPosition; // next byte to be read from file +} streamState_t; + +streamState_t stream; + +/* +=============== +Sys_StreamThread + +A thread will be sitting in this loop forever +================ +*/ +void Sys_StreamThread( void ) +{ + int buffer; + int count; + int readCount; + int bufferPoint; + int r; + +//Loop here +// EnterCriticalSection (&stream.crit); + + // if there is any space left in the buffer, fill it up + if ( !stream.eof ) { + count = stream.bufferSize - (stream.threadPosition - stream.streamPosition); + if ( count ) { + bufferPoint = stream.threadPosition % stream.bufferSize; + buffer = stream.bufferSize - bufferPoint; + readCount = buffer < count ? buffer : count; + r = fread( stream.buffer + bufferPoint, 1, readCount, stream.file ); + stream.threadPosition += r; + + if ( r != readCount ) + stream.eof = qtrue; + } + } + +// LeaveCriticalSection (&stream.crit); +} + +/* +=============== +Sys_InitStreamThread + +================ +*/ +void Sys_InitStreamThread( void ) +{ +} + +/* +=============== +Sys_ShutdownStreamThread + +================ +*/ +void Sys_ShutdownStreamThread( void ) +{ +} + + +/* +=============== +Sys_BeginStreamedFile + +================ +*/ +void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) +{ + if ( stream.file ) { + Com_Error( ERR_FATAL, "Sys_BeginStreamedFile: unclosed stream"); + } + + stream.file = f; + stream.buffer = Z_Malloc( readAhead ); + stream.bufferSize = readAhead; + stream.streamPosition = 0; + stream.threadPosition = 0; + stream.eof = qfalse; + + // let the thread start running +// LeaveCriticalSection( &stream.crit ); +} + +/* +=============== +Sys_EndStreamedFile + +================ +*/ +void Sys_EndStreamedFile( FILE *f ) +{ + if ( f != stream.file ) { + Com_Error( ERR_FATAL, "Sys_EndStreamedFile: wrong file"); + } + // don't leave critical section until another stream is started +// EnterCriticalSection( &stream.crit ); + + stream.file = NULL; + Z_Free( stream.buffer ); +} + + +/* +=============== +Sys_StreamedRead + +================ +*/ +int Sys_StreamedRead( void *buffer, int size, int count, FILE *f ) +{ + int available; + int remaining; + int sleepCount; + int copy; + int bufferCount; + int bufferPoint; + byte *dest; + + dest = (byte *)buffer; + remaining = size * count; + + if ( remaining <= 0 ) { + Com_Error( ERR_FATAL, "Streamed read with non-positive size" ); + } + + sleepCount = 0; + while ( remaining > 0 ) { + available = stream.threadPosition - stream.streamPosition; + if ( !available ) { + if (stream.eof) + break; + Sys_StreamThread(); + continue; + } + + bufferPoint = stream.streamPosition % stream.bufferSize; + bufferCount = stream.bufferSize - bufferPoint; + + copy = available < bufferCount ? available : bufferCount; + if ( copy > remaining ) { + copy = remaining; + } + memcpy( dest, stream.buffer + bufferPoint, copy ); + stream.streamPosition += copy; + dest += copy; + remaining -= copy; + } + + return (count * size - remaining) / size; +} + +/* +=============== +Sys_StreamSeek + +================ +*/ +void Sys_StreamSeek( FILE *f, int offset, int origin ) { + + // halt the thread +// EnterCriticalSection( &stream.crit ); + + // clear to that point + fseek( f, offset, origin ); + stream.streamPosition = 0; + stream.threadPosition = 0; + stream.eof = qfalse; + + // let the thread start running at the new position +// LeaveCriticalSection( &stream.crit ); +} + + +/* +======================================================================== + +EVENT LOOP + +======================================================================== +*/ + +#define MAX_QUED_EVENTS 64 +#define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 ) + +sysEvent_t eventQue[MAX_QUED_EVENTS]; +int eventHead, eventTail; +byte sys_packetReceived[MAX_MSGLEN]; + +/* +================ +Sys_QueEvent + +A time of 0 will get the current time +Ptr should either be null, or point to a block of data that can +be freed by the game later. +================ +*/ +void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) { + sysEvent_t *ev; + + ev = &eventQue[ eventHead & MASK_QUED_EVENTS ]; + eventHead++; + + if ( time == 0 ) { + time = Sys_Milliseconds(); + } + + ev->evTime = time; + ev->evType = type; + ev->evValue = value; + ev->evValue2 = value2; + ev->evPtrLength = ptrLength; + ev->evPtr = ptr; +} + +/* +================ +Sys_GetEvent + +================ +*/ +sysEvent_t Sys_GetEvent( void ) { + sysEvent_t ev; + char *s; + msg_t netmsg; + netadr_t adr; + + // return if we have data + if ( eventHead > eventTail ) { + eventTail++; + return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ]; + } + + // pump the message loop + // in vga this calls KBD_Update, under X, it calls GetEvent + Sys_SendKeyEvents (); + + // check for console commands + s = Sys_ConsoleInput(); + if ( s ) { + char *b; + int len; + + len = strlen( s ) + 1; + b = malloc( len ); + strcpy( b, s ); + Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b ); + } + + // check for other input devices + IN_Frame(); + + // check for network packets + MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) ); + if ( Sys_GetPacket ( &adr, &netmsg ) ) { + netadr_t *buf; + int len; + + // copy out to a seperate buffer for qeueing + len = sizeof( netadr_t ) + netmsg.cursize; + buf = malloc( len ); + *buf = adr; + memcpy( buf+1, netmsg.data, netmsg.cursize ); + Sys_QueEvent( 0, SE_PACKET, 0, 0, len, buf ); + } + + // return if we have data + if ( eventHead > eventTail ) { + eventTail++; + return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ]; + } + + // create an empty event to return + + memset( &ev, 0, sizeof( ev ) ); + ev.evTime = Sys_Milliseconds(); + + return ev; +} + +/*****************************************************************************/ + +void Sys_AppActivate (void) +{ +} + +char *Sys_GetClipboardData(void) +{ + return NULL; +} + +void Sys_Print( const char *msg ) +{ + fputs(msg, stderr); +} + +int main (int argc, char **argv) +{ + int oldtime, newtime; + int len, i; + char *cmdline; + void SetProgramPath(char *path); + + // go back to real user for config loads + saved_euid = geteuid(); + seteuid(getuid()); + + SetProgramPath(argv[0]); + + // merge the command line, this is kinda silly + for (len = 1, i = 1; i < argc; i++) + len += strlen(argv[i]) + 1; + cmdline = malloc(len); + *cmdline = 0; + for (i = 1; i < argc; i++) { + if (i > 1) + strcat(cmdline, " "); + strcat(cmdline, argv[i]); + } + Com_Init(cmdline); + NET_Init(); + + fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); + + nostdout = Cvar_Get("nostdout", "0", 0); + if (!nostdout->value) { + fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); +// printf ("Linux Quake -- Version %0.3f\n", LINUX_VERSION); + } + + while (1) + { + // set low precision every frame, because some system calls + // reset it arbitrarily + Sys_LowFPPrecision (); + + Com_Frame (); + } +} + +#if 0 +/* +================ +Sys_MakeCodeWriteable +================ +*/ +void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length) +{ + + int r; + unsigned long addr; + int psize = getpagesize(); + + addr = (startaddr & ~(psize-1)) - psize; + +// fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr, +// addr, startaddr+length, length); + + r = mprotect((char*)addr, length + startaddr - addr + psize, 7); + + if (r < 0) + Sys_Error("Protection change failed\n"); + +} + +#endif diff --git a/code/unix/unix_net.c b/code/unix/unix_net.c new file mode 100644 index 0000000..72806f2 --- /dev/null +++ b/code/unix/unix_net.c @@ -0,0 +1,443 @@ +// unix_net.c + +#include "../game/q_shared.h" +#include "../qcommon/qcommon.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef NeXT +#include +#endif + +static cvar_t *noudp; + +netadr_t net_local_adr; + +int ip_socket; +int ipx_socket; + +#define MAX_IPS 16 +static int numIP; +static byte localIP[MAX_IPS][4]; + +int NET_Socket (char *net_interface, int port); +char *NET_ErrorString (void); + +//============================================================================= + +void NetadrToSockadr (netadr_t *a, struct sockaddr_in *s) +{ + memset (s, 0, sizeof(*s)); + + if (a->type == NA_BROADCAST) + { + s->sin_family = AF_INET; + + s->sin_port = a->port; + *(int *)&s->sin_addr = -1; + } + else if (a->type == NA_IP) + { + s->sin_family = AF_INET; + + *(int *)&s->sin_addr = *(int *)&a->ip; + s->sin_port = a->port; + } +} + +void SockadrToNetadr (struct sockaddr_in *s, netadr_t *a) +{ + *(int *)&a->ip = *(int *)&s->sin_addr; + a->port = s->sin_port; + a->type = NA_IP; +} + +char *NET_BaseAdrToString (netadr_t a) +{ + static char s[64]; + + Com_sprintf (s, sizeof(s), "%i.%i.%i.%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3]); + + return s; +} + +/* +============= +Sys_StringToAdr + +idnewt +192.246.40.70 +============= +*/ +qboolean Sys_StringToSockaddr (const char *s, struct sockaddr *sadr) +{ + struct hostent *h; + char *colon; + + memset (sadr, 0, sizeof(*sadr)); + ((struct sockaddr_in *)sadr)->sin_family = AF_INET; + + ((struct sockaddr_in *)sadr)->sin_port = 0; + + if ( s[0] >= '0' && s[0] <= '9') + { + *(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(s); + } + else + { + if (! (h = gethostbyname(s)) ) + return qfalse; + *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0]; + } + + return qtrue; +} + +/* +============= +Sys_StringToAdr + +localhost +idnewt +idnewt:28000 +192.246.40.70 +192.246.40.70:28000 +============= +*/ +qboolean Sys_StringToAdr (const char *s, netadr_t *a) +{ + struct sockaddr_in sadr; + + if (!Sys_StringToSockaddr (s, (struct sockaddr *)&sadr)) + return qfalse; + + SockadrToNetadr (&sadr, a); + + return qtrue; +} + + +//============================================================================= + +qboolean Sys_GetPacket (netadr_t *net_from, msg_t *net_message) +{ + int ret; + struct sockaddr_in from; + int fromlen; + int net_socket; + int protocol; + int err; + + for (protocol = 0 ; protocol < 2 ; protocol++) + { + if (protocol == 0) + net_socket = ip_socket; + else + net_socket = ipx_socket; + + if (!net_socket) + continue; + + fromlen = sizeof(from); + ret = recvfrom (net_socket, net_message->data, net_message->maxsize + , 0, (struct sockaddr *)&from, &fromlen); + + SockadrToNetadr (&from, net_from); + + if (ret == -1) + { + err = errno; + + if (err == EWOULDBLOCK || err == ECONNREFUSED) + continue; + Com_Printf ("NET_GetPacket: %s from %s\n", NET_ErrorString(), + NET_AdrToString(*net_from)); + continue; + } + + if (ret == net_message->maxsize) + { + Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from)); + continue; + } + + net_message->cursize = ret; + return qtrue; + } + + return qfalse; +} + +//============================================================================= + +void Sys_SendPacket( int length, const void *data, netadr_t to ) +{ + int ret; + struct sockaddr_in addr; + int net_socket; + + if (to.type == NA_BROADCAST) + { + net_socket = ip_socket; + } + else if (to.type == NA_IP) + { + net_socket = ip_socket; + } + else if (to.type == NA_IPX) + { + net_socket = ipx_socket; + } + else if (to.type == NA_BROADCAST_IPX) + { + net_socket = ipx_socket; + } + else { + Com_Error (ERR_FATAL, "NET_SendPacket: bad address type"); + return; + } + + if (!net_socket) + return; + + NetadrToSockadr (&to, &addr); + + ret = sendto (net_socket, data, length, 0, (struct sockaddr *)&addr, sizeof(addr) ); + if (ret == -1) + { + Com_Printf ("NET_SendPacket ERROR: %s to %s\n", NET_ErrorString(), + NET_AdrToString (to)); + } +} + + +//============================================================================= + +/* +================== +Sys_IsLANAddress + +LAN clients will have their rate var ignored +================== +*/ +qboolean Sys_IsLANAddress (netadr_t adr) { + int i; + if ( adr.type == NA_LOOPBACK ) { + return qtrue; + } + + // FIXME: ipx? + + if ( adr.type == NA_IP ) { + for ( i = 0 ; i < numIP ; i++ ) { + // assuming a class C network, which may not be smart... + if ( adr.ip[0] == localIP[i][0] + && adr.ip[1] == localIP[i][1] + && adr.ip[2] == localIP[i][2] ) { + return qtrue; + } + } + } + + return qfalse; +} + +/* +===================== +NET_GetLocalAddress +===================== +*/ +void NET_GetLocalAddress( void ) { + char hostname[256]; + struct hostent *hostInfo; + int error; + char *p; + int ip; + int n; + + if ( gethostname( hostname, 256 ) == -1 ) { + return; + } + + hostInfo = gethostbyname( hostname ); + if ( !hostInfo ) { + return; + } + + Com_Printf( "Hostname: %s\n", hostInfo->h_name ); + n = 0; + while( ( p = hostInfo->h_aliases[n++] ) != NULL ) { + Com_Printf( "Alias: %s\n", p ); + } + + if ( hostInfo->h_addrtype != AF_INET ) { + return; + } + + numIP = 0; + while( ( p = hostInfo->h_addr_list[numIP++] ) != NULL && numIP < MAX_IPS ) { + ip = ntohl( *(int *)p ); + localIP[ numIP ][0] = p[0]; + localIP[ numIP ][1] = p[1]; + localIP[ numIP ][2] = p[2]; + localIP[ numIP ][3] = p[3]; + Com_Printf( "IP: %i.%i.%i.%i\n", ( ip >> 24 ) & 0xff, ( ip >> 16 ) & 0xff, ( ip >> 8 ) & 0xff, ip & 0xff ); + } +} + +/* +==================== +NET_OpenIP +==================== +*/ +void NET_OpenIP (void) +{ + cvar_t *ip; + int port; + int i; + + ip = Cvar_Get ("net_ip", "localhost", 0); + + port = Cvar_Get("net_port", va("%i", PORT_SERVER), 0)->value; + + for ( i = 0 ; i < 10 ; i++ ) { + ip_socket = NET_IPSocket (ip->string, port + i); + if ( ip_socket ) { + Cvar_SetValue( "net_port", port + i ); + NET_GetLocalAddress(); + return; + } + } + Com_Error (ERR_FATAL, "Couldn't allocate IP port"); +} + + +/* +==================== +NET_Init +==================== +*/ +void NET_Init (void) +{ + noudp = Cvar_Get ("net_noudp", "0", 0); + // open sockets + if (! noudp->value) { + NET_OpenIP (); + } +} + + +/* +==================== +NET_Socket +==================== +*/ +int NET_IPSocket (char *net_interface, int port) +{ + int newsocket; + struct sockaddr_in address; + qboolean _qtrue = qtrue; + int i = 1; + + if ( net_interface ) { + Com_Printf("Opening IP socket: %s:%i\n", net_interface, port ); + } else { + Com_Printf("Opening IP socket: localhost:%i\n", port ); + } + + if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + { + Com_Printf ("ERROR: UDP_OpenSocket: socket: %s", NET_ErrorString()); + return 0; + } + + // make it non-blocking + if (ioctl (newsocket, FIONBIO, &_qtrue) == -1) + { + Com_Printf ("ERROR: UDP_OpenSocket: ioctl FIONBIO:%s\n", NET_ErrorString()); + return 0; + } + + // make it broadcast capable + if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1) + { + Com_Printf ("ERROR: UDP_OpenSocket: setsockopt SO_BROADCAST:%s\n", NET_ErrorString()); + return 0; + } + + if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost")) + address.sin_addr.s_addr = INADDR_ANY; + else + Sys_StringToSockaddr (net_interface, (struct sockaddr *)&address); + + if (port == PORT_ANY) + address.sin_port = 0; + else + address.sin_port = htons((short)port); + + address.sin_family = AF_INET; + + if( bind (newsocket, (void *)&address, sizeof(address)) == -1) + { + Com_Printf ("ERROR: UDP_OpenSocket: bind: %s\n", NET_ErrorString()); + close (newsocket); + return 0; + } + + return newsocket; +} + +/* +==================== +NET_Shutdown +==================== +*/ +void NET_Shutdown (void) +{ + if (ip_socket) { + close(ip_socket); + ip_socket = 0; + } +} + + +/* +==================== +NET_ErrorString +==================== +*/ +char *NET_ErrorString (void) +{ + int code; + + code = errno; + return strerror (code); +} + +// sleeps msec or until net socket is ready +void NET_Sleep(int msec) +{ + struct timeval timeout; + fd_set fdset; + extern qboolean stdin_active; + + if (!ip_socket || !com_dedicated->integer) + return; // we're not a server, just run full speed + + FD_ZERO(&fdset); + if (stdin_active) + FD_SET(0, &fdset); // stdin is processed too + FD_SET(ip_socket, &fdset); // network socket + timeout.tv_sec = msec/1000; + timeout.tv_usec = (msec%1000)*1000; + select(ip_socket+1, &fdset, NULL, NULL, &timeout); +} + diff --git a/code/unix/unix_shared.c b/code/unix/unix_shared.c new file mode 100644 index 0000000..558d7d9 --- /dev/null +++ b/code/unix/unix_shared.c @@ -0,0 +1,369 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../game/q_shared.h" +#include "../qcommon/qcommon.h" + +//=============================================================================== + +// Used to determine CD Path +static char programpath[MAX_OSPATH]; + +/* +================ +Sys_Milliseconds +================ +*/ +int curtime; +int sys_timeBase; +int Sys_Milliseconds (void) +{ + struct timeval tp; + struct timezone tzp; + + gettimeofday(&tp, &tzp); + + if (!sys_timeBase) + { + sys_timeBase = tp.tv_sec; + return tp.tv_usec/1000; + } + + curtime = (tp.tv_sec - sys_timeBase)*1000 + tp.tv_usec/1000; + + return curtime; +} + +void Sys_Mkdir( const char *path ) +{ + mkdir (path, 0777); +} + +char *strlwr (char *s) +{ + while (*s) { + *s = tolower(*s); + s++; + } +} + +//============================================ + +/* Like glob_match, but match PATTERN against any final segment of TEXT. */ +static int glob_match_after_star(char *pattern, char *text) +{ + register char *p = pattern, *t = text; + register char c, c1; + + while ((c = *p++) == '?' || c == '*') + if (c == '?' && *t++ == '\0') + return 0; + + if (c == '\0') + return 1; + + if (c == '\\') + c1 = *p; + else + c1 = c; + + while (1) { + if ((c == '[' || *t == c1) && glob_match(p - 1, t)) + return 1; + if (*t++ == '\0') + return 0; + } +} + +/* Return nonzero if PATTERN has any special globbing chars in it. */ +static int glob_pattern_p(char *pattern) +{ + register char *p = pattern; + register char c; + int open = 0; + + while ((c = *p++) != '\0') + switch (c) { + case '?': + case '*': + return 1; + + case '[': /* Only accept an open brace if there is a close */ + open++; /* brace to match it. Bracket expressions must be */ + continue; /* complete, according to Posix.2 */ + case ']': + if (open) + return 1; + continue; + + case '\\': + if (*p++ == '\0') + return 0; + } + + return 0; +} + +/* Match the pattern PATTERN against the string TEXT; + return 1 if it matches, 0 otherwise. + + A match means the entire string TEXT is used up in matching. + + In the pattern string, `*' matches any sequence of characters, + `?' matches any character, [SET] matches any character in the specified set, + [!SET] matches any character not in the specified set. + + A set is composed of characters or ranges; a range looks like + character hyphen character (as in 0-9 or A-Z). + [0-9a-zA-Z_] is the set of characters allowed in C identifiers. + Any other character in the pattern must be matched exactly. + + To suppress the special syntactic significance of any of `[]*?!-\', + and match the character exactly, precede it with a `\'. +*/ + +int glob_match(char *pattern, char *text) +{ + register char *p = pattern, *t = text; + register char c; + + while ((c = *p++) != '\0') + switch (c) { + case '?': + if (*t == '\0') + return 0; + else + ++t; + break; + + case '\\': + if (*p++ != *t++) + return 0; + break; + + case '*': + return glob_match_after_star(p, t); + + case '[': + { + register char c1 = *t++; + int invert; + + if (!c1) + return (0); + + invert = ((*p == '!') || (*p == '^')); + if (invert) + p++; + + c = *p++; + while (1) { + register char cstart = c, cend = c; + + if (c == '\\') { + cstart = *p++; + cend = cstart; + } + if (c == '\0') + return 0; + + c = *p++; + if (c == '-' && *p != ']') { + cend = *p++; + if (cend == '\\') + cend = *p++; + if (cend == '\0') + return 0; + c = *p++; + } + if (c1 >= cstart && c1 <= cend) + goto match; + if (c == ']') + break; + } + if (!invert) + return 0; + break; + + match: + /* Skip the rest of the [...] construct that already matched. */ + while (c != ']') { + if (c == '\0') + return 0; + c = *p++; + if (c == '\0') + return 0; + else if (c == '\\') + ++p; + } + if (invert) + return 0; + break; + } + + default: + if (c != *t++) + return 0; + } + + return *t == '\0'; +} + +//============================================ + +#define MAX_FOUND_FILES 0x1000 + +char **Sys_ListFiles( const char *directory, const char *extension, int *numfiles, qboolean wantsubs ) +{ + struct dirent *d; + char *p; + DIR *fdir; + qboolean dironly = wantsubs; + char search[MAX_OSPATH]; + int nfiles; + char **listCopy; + char *list[MAX_FOUND_FILES]; + int flag; + int i; + struct stat st; + + int extLen; + + if ( !extension) + extension = ""; + + if ( extension[0] == '/' && extension[1] == 0 ) { + extension = ""; + dironly = qtrue; + } + + extLen = strlen( extension ); + + // search + nfiles = 0; + + if ((fdir = opendir(directory)) == NULL) { + *numfiles = 0; + return NULL; + } + + while ((d = readdir(fdir)) != NULL) { + Com_sprintf(search, sizeof(search), "%s/%s", directory, d->d_name); + if (stat(search, &st) == -1) + continue; + if ((dironly && !(st.st_mode & S_IFDIR)) || + (!dironly && (st.st_mode & S_IFDIR))) + continue; + + if (*extension) { + if ( strlen( d->d_name ) < strlen( extension ) || + Q_stricmp( + d->d_name + strlen( d->d_name ) - strlen( extension ), + extension ) ) { + continue; // didn't match + } + } + + if ( nfiles == MAX_FOUND_FILES - 1 ) + break; + list[ nfiles ] = CopyString( d->d_name ); + nfiles++; + } + + list[ nfiles ] = 0; + + closedir(fdir); + + // return a copy of the list + *numfiles = nfiles; + + if ( !nfiles ) { + return NULL; + } + + listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) ); + for ( i = 0 ; i < nfiles ; i++ ) { + listCopy[i] = list[i]; + } + listCopy[i] = NULL; + + return listCopy; +} + +void Sys_FreeFileList( char **list ) { + int i; + + if ( !list ) { + return; + } + + for ( i = 0 ; list[i] ; i++ ) { + Z_Free( list[i] ); + } + + Z_Free( list ); +} + +char *Sys_Cwd( void ) +{ + static char cwd[MAX_OSPATH]; + + getcwd( cwd, sizeof( cwd ) - 1 ); + cwd[MAX_OSPATH-1] = 0; + + return cwd; +} + +void SetProgramPath(char *path) +{ + char *p; + + Q_strncpyz(programpath, path, sizeof(programpath)); + if ((p = strrchr(programpath, '/')) != NULL) + *p = 0; // remove program name, leave only path +} + +char *Sys_DefaultCDPath(void) +{ + if (*programpath) + return programpath; + else + return Sys_Cwd(); +} + +char *Sys_DefaultBasePath(void) +{ + char *p; + static char basepath[MAX_OSPATH]; + int e; + + if ((p = getenv("HOME")) != NULL) { + Q_strncpyz(basepath, p, sizeof(basepath)); + Q_strcat(basepath, sizeof(basepath), "/.q3a"); + if (mkdir(basepath, 0777)) { + if (errno != EEXIST) + Sys_Error("Unable to create directory \"%s\", error is %s(%d)\n", basepath, strerror(errno), errno); + } + return basepath; + } + return ""; // assume current dir +} + +//============================================ + +int Sys_GetProcessorId( void ) +{ + return CPUID_GENERIC; +} + +void Sys_ShowConsole( int visLevel, qboolean quitOnClose ) +{ +} + + diff --git a/code/unix/vssver.scc b/code/unix/vssver.scc new file mode 100644 index 0000000..f15a2c5 Binary files /dev/null and b/code/unix/vssver.scc differ diff --git a/code/vssver.scc b/code/vssver.scc new file mode 100644 index 0000000..892875b Binary files /dev/null and b/code/vssver.scc differ diff --git a/code/win32/background.bmp b/code/win32/background.bmp new file mode 100644 index 0000000..88b3dab Binary files /dev/null and b/code/win32/background.bmp differ diff --git a/code/win32/bink.h b/code/win32/bink.h new file mode 100644 index 0000000..4a4b273 --- /dev/null +++ b/code/win32/bink.h @@ -0,0 +1,620 @@ +#ifndef BINKH +#define BINKH + +#define BINKVERSION "1.0p" +#define BINKDATE "2000-06-26" + +#ifndef __RADRES__ + +#include "rad.h" + +RADDEFSTART + +typedef struct BINK PTR4* HBINK; + +typedef s32 (RADLINK PTR4* BINKIOOPEN) (struct BINKIO PTR4* Bnkio, const char PTR4 *name, u32 flags); +typedef u32 (RADLINK PTR4* BINKIOREADHEADER) (struct BINKIO PTR4* Bnkio, s32 Offset, void PTR4* Dest,u32 Size); +typedef u32 (RADLINK PTR4* BINKIOREADFRAME) (struct BINKIO PTR4* Bnkio, u32 Framenum,s32 origofs,void PTR4* dest,u32 size); +typedef u32 (RADLINK PTR4* BINKIOGETBUFFERSIZE)(struct BINKIO PTR4* Bnkio, u32 Size); +typedef void (RADLINK PTR4* BINKIOSETINFO) (struct BINKIO PTR4* Bnkio, void PTR4* Buf,u32 Size,u32 FileSize,u32 simulate); +typedef u32 (RADLINK PTR4* BINKIOIDLE) (struct BINKIO PTR4* Bnkio); +typedef void (RADLINK PTR4* BINKIOCLOSE) (struct BINKIO PTR4* Bnkio); + +typedef struct BINKIO { + BINKIOREADHEADER ReadHeader; + BINKIOREADFRAME ReadFrame; + BINKIOGETBUFFERSIZE GetBufferSize; + BINKIOSETINFO SetInfo; + BINKIOIDLE Idle; + BINKIOCLOSE Close; + HBINK bink; + volatile u32 ReadError; + volatile u32 DoingARead; + volatile u32 BytesRead; + volatile u32 Working; + volatile u32 TotalTime; + volatile u32 ForegroundTime; + volatile u32 IdleTime; + volatile u32 ThreadTime; + volatile u32 BufSize; + volatile u32 BufHighUsed; + volatile u32 CurBufSize; + volatile u32 CurBufUsed; + volatile u8 iodata[128]; +} BINKIO; + +typedef s32 (RADLINK PTR4* BINKSNDOPEN) (struct BINKSND PTR4* BnkSnd, u32 freq, s32 bits, s32 chans, u32 flags, HBINK bink); +typedef s32 (RADLINK PTR4* BINKSNDREADY) (struct BINKSND PTR4* BnkSnd); +typedef s32 (RADLINK PTR4* BINKSNDLOCK) (struct BINKSND PTR4* BnkSnd, u8 PTR4* PTR4* addr, u32 PTR4* len); +typedef s32 (RADLINK PTR4* BINKSNDUNLOCK) (struct BINKSND PTR4* BnkSnd, u32 filled); +typedef void (RADLINK PTR4* BINKSNDVOLUME) (struct BINKSND PTR4* BnkSnd, s32 volume); +typedef void (RADLINK PTR4* BINKSNDPAN) (struct BINKSND PTR4* BnkSnd, s32 pan); +typedef s32 (RADLINK PTR4* BINKSNDONOFF) (struct BINKSND PTR4* BnkSnd, s32 status); +typedef s32 (RADLINK PTR4* BINKSNDPAUSE) (struct BINKSND PTR4* BnkSnd, s32 status); +typedef void (RADLINK PTR4* BINKSNDCLOSE) (struct BINKSND PTR4* BnkSnd); + +typedef BINKSNDOPEN (RADLINK PTR4* BINKSNDSYSOPEN) (u32 param); + +typedef struct BINKSND { + BINKSNDREADY Ready; + BINKSNDLOCK Lock; + BINKSNDUNLOCK Unlock; + BINKSNDVOLUME Volume; + BINKSNDPAN Pan; + BINKSNDPAUSE Pause; + BINKSNDONOFF SetOnOff; + BINKSNDCLOSE Close; + u32 BestSizeIn16; + u32 SoundDroppedOut; + s32 OnOff; + u32 Latency; + u32 freq; + s32 bits,chans; + u8 snddata[128]; +} BINKSND; + +typedef struct BINKRECT { + s32 Left,Top,Width,Height; +} BINKRECT; + +#define BINKMAXDIRTYRECTS 8 + +typedef struct BUNDLEPOINTERS { + void* typeptr; + void* type16ptr; + void* colorptr; + void* bits2ptr; + void* motionXptr; + void* motionYptr; + void* dctptr; + void* mdctptr; + void* patptr; +} BUNDLEPOINTERS; + + +typedef struct BINK { + u32 Width; // Width (1 based, 640 for example) + u32 Height; // Height (1 based, 480 for example) + u32 Frames; // Number of frames (1 based, 100 = 100 frames) + u32 FrameNum; // Frame to *be* displayed (1 based) + u32 LastFrameNum; // Last frame decompressed or skipped (1 based) + + u32 FrameRate; // Frame Rate Numerator + u32 FrameRateDiv; // Frame Rate Divisor (frame rate=numerator/divisor) + + u32 ReadError; // Non-zero if a read error has ocurred + u32 OpenFlags; // flags used on open + u32 BinkType; // Bink flags + + u32 Size; // size of file + u32 FrameSize; // The current frame's size in bytes + u32 SndSize; // The current frame sound tracks' size in bytes + + BINKRECT FrameRects[BINKMAXDIRTYRECTS];// Dirty rects from BinkGetRects + s32 NumRects; + + u32 PlaneNum; // which set of planes is current + void PTR4* YPlane[2]; // pointer to the uncompressed Y (Cr and Cr follow) + void PTR4* APlane[2]; // decompressed alpha plane (if present) + u32 YWidth; // widths and heights of the video planes + u32 YHeight; + u32 UVWidth; + u32 UVHeight; + + void PTR4* MaskPlane; // pointer to the mask plane (Ywidth/16*Yheight/16) + u32 MaskPitch; // Mask Pitch + u32 MaskLength; // total length of the mask plane + + u32 LargestFrameSize; // Largest frame size + u32 InternalFrames; // how many frames were potentially compressed + + s32 NumTracks; // how many tracks + + u32 Highest1SecRate; // Highest 1 sec data rate + u32 Highest1SecFrame; // Highest 1 sec data rate starting frame + + s32 Paused; // is the bink movie paused? + + u32 BackgroundThread; // handle to background thread + + // everything below is for internal Bink use + + void PTR4* compframe; // compressed frame data + void PTR4* preloadptr; // preloaded compressed frame data + u32* frameoffsets; // offsets of each of the frames + + BINKIO bio; // IO structure + u8 PTR4* ioptr; // io buffer ptr + u32 iosize; // io buffer size + u32 decompwidth; // width not include scaling + u32 decompheight; // height not include scaling + + s32 trackindex; // track index + u32 PTR4* tracksizes; // largest single frame of track + u32 PTR4* tracktypes; // type of each sound track + s32 PTR4* trackIDs; // external track numbers + + u32 numrects; // number of rects from BinkGetRects + + u32 playedframes; // how many frames have we played + u32 firstframetime; // very first frame start + u32 startframetime; // start frame start + u32 startblittime; // start of blit period + u32 startsynctime; // start of synched time + u32 startsyncframe; // frame of startsynctime + u32 twoframestime; // two frames worth of time + u32 entireframetime; // entire frame time + + u32 slowestframetime; // slowest frame in ms + u32 slowestframe; // slowest frame number + u32 slowest2frametime; // second slowest frame in ms + u32 slowest2frame; // second slowest frame + + u32 soundon; // sound turned on? + u32 videoon; // video turned on? + + u32 totalmem; // total memory used + u32 timevdecomp; // total time decompressing video + u32 timeadecomp; // total time decompressing audio + u32 timeblit; // total time blitting + u32 timeopen; // total open time + + u32 fileframerate; // frame rate originally in the file + u32 fileframeratediv; + + volatile u32 threadcontrol; // controls the background reading thread + + u32 runtimeframes; // max frames for runtime analysis + u32 runtimemoveamt; // bytes to move each frame + u32 PTR4* rtframetimes; // start times for runtime frames + u32 PTR4* rtadecomptimes; // decompress times for runtime frames + u32 PTR4* rtvdecomptimes; // decompress times for runtime frames + u32 PTR4* rtblittimes; // blit times for runtime frames + u32 PTR4* rtreadtimes; // read times for runtime frames + u32 PTR4* rtidlereadtimes; // idle read times for runtime frames + u32 PTR4* rtthreadreadtimes;// thread read times for runtime frames + + u32 lastblitflags; // flags used on last blit + u32 lastdecompframe; // last frame number decompressed + + u32 sndbufsize; // sound buffer size + u8 PTR4* sndbuf; // sound buffer + u8 PTR4* sndend; // end of the sound buffer + u8 PTR4* sndwritepos; // current write position + u8 PTR4* sndreadpos; // current read position + u32 sndcomp; // sound compression handle + u32 sndamt; // amount of sound currently in the buffer + volatile u32 sndreenter; // re-entrancy check on the sound + u32 sndconvert8; // convert back to 8-bit sound at runtime + BINKSND bsnd; // SND structure + u32 skippedlastblit; // skipped last frame? + u32 skippedblits; // how many blits were skipped + u32 soundskips; // number of sound stops + u32 sndendframe; // frame number that the sound ends on + u32 sndprime; // amount of data to prime the playahead + u32 sndpad; // padded this much audio + + BUNDLEPOINTERS bunp; // pointers to internal temporary memory +} BINK; + + +typedef struct BINKSUMMARY { + u32 Width; // Width of frames + u32 Height; // Height of frames + u32 TotalTime; // total time (ms) + u32 FileFrameRate; // frame rate + u32 FileFrameRateDiv; // frame rate divisor + u32 FrameRate; // frame rate + u32 FrameRateDiv; // frame rate divisor + u32 TotalOpenTime; // Time to open and prepare for decompression + u32 TotalFrames; // Total Frames + u32 TotalPlayedFrames; // Total Frames played + u32 SkippedFrames; // Total number of skipped frames + u32 SkippedBlits; // Total number of skipped blits + u32 SoundSkips; // Total number of sound skips + u32 TotalBlitTime; // Total time spent blitting + u32 TotalReadTime; // Total time spent reading + u32 TotalVideoDecompTime; // Total time spent decompressing video + u32 TotalAudioDecompTime; // Total time spent decompressing audio + u32 TotalIdleReadTime; // Total time spent reading while idle + u32 TotalBackReadTime; // Total time spent reading in background + u32 TotalReadSpeed; // Total io speed (bytes/second) + u32 SlowestFrameTime; // Slowest single frame time (ms) + u32 Slowest2FrameTime; // Second slowest single frame time (ms) + u32 SlowestFrameNum; // Slowest single frame number + u32 Slowest2FrameNum; // Second slowest single frame number + u32 AverageDataRate; // Average data rate of the movie + u32 AverageFrameSize; // Average size of the frame + u32 HighestMemAmount; // Highest amount of memory allocated + u32 TotalIOMemory; // Total extra memory allocated + u32 HighestIOUsed; // Highest extra memory actually used + u32 Highest1SecRate; // Highest 1 second rate + u32 Highest1SecFrame; // Highest 1 second start frame +} BINKSUMMARY; + + +typedef struct BINKREALTIME { + u32 FrameNum; // Current frame number + u32 FrameRate; // frame rate + u32 FrameRateDiv; // frame rate divisor + u32 Frames; // frames in this sample period + u32 FramesTime; // time is ms for these frames + u32 FramesVideoDecompTime; // time decompressing these frames + u32 FramesAudioDecompTime; // time decompressing these frames + u32 FramesReadTime; // time reading these frames + u32 FramesIdleReadTime; // time reading these frames at idle + u32 FramesThreadReadTime; // time reading these frames in background + u32 FramesBlitTime; // time blitting these frames + u32 ReadBufferSize; // size of read buffer + u32 ReadBufferUsed; // amount of read buffer currently used + u32 FramesDataRate; // data rate for these frames +} BINKREALTIME; + +#define BINKMARKER1 'fKIB' +#define BINKMARKER2 'gKIB' // new Bink files use this tag +#define BINKMARKER3 'hKIB' // newer Bink files use this tag +#define BINKMARKER4 'iKIB' // even newer Bink files use this tag + +typedef struct BINKHDR { + u32 Marker; // Bink marker + u32 Size; // size of the file-8 + u32 Frames; // Number of frames (1 based, 100 = 100 frames) + u32 LargestFrameSize; // Size in bytes of largest frame + u32 InternalFrames; // Number of internal frames + + u32 Width; // Width (1 based, 640 for example) + u32 Height; // Height (1 based, 480 for example) + u32 FrameRate; // frame rate + u32 FrameRateDiv; // frame rate divisor (framerate/frameratediv=fps) + + u32 Flags; // height compression options + u32 NumTracks; // number of tracks +} BINKHDR; + + +//======================================================================= +#define BINKFRAMERATE 0x00001000L // Override fr (call BinkFrameRate first) +#define BINKPRELOADALL 0x00002000L // Preload the entire animation +#define BINKSNDTRACK 0x00004000L // Set the track number to play +#define BINKOLDFRAMEFORMAT 0x00008000L // using the old Bink frame format (internal use only) +#define BINKRBINVERT 0x00010000L // use reversed R and B planes (internal use only) +#define BINKGRAYSCALE 0x00020000L // Force Bink to use grayscale +#define BINKNOMMX 0x00040000L // Don't use MMX +#define BINKNOSKIP 0x00080000L // Don't skip frames if falling behind +#define BINKALPHA 0x00100000L // Decompress alpha plane (if present) +#define BINKNOFILLIOBUF 0x00200000L // Fill the IO buffer in SmackOpen +#define BINKSIMULATE 0x00400000L // Simulate the speed (call BinkSim first) +#define BINKFILEHANDLE 0x00800000L // Use when passing in a file handle +#define BINKIOSIZE 0x01000000L // Set an io size (call BinkIOSize first) +#define BINKIOPROCESSOR 0x02000000L // Set an io processor (call BinkIO first) +#define BINKFROMMEMORY 0x04000000L // Use when passing in a pointer to the file +#define BINKNOTHREADEDIO 0x08000000L // Don't use a background thread for IO + +#define BINKSURFACEFAST 0x00000000L +#define BINKSURFACESLOW 0x08000000L +#define BINKSURFACEDIRECT 0x04000000L + +#define BINKCOPYALL 0x80000000L // copy all pixels (not just changed) +#define BINKCOPY2XH 0x10000000L // Force doubling height scaling +#define BINKCOPY2XHI 0x20000000L // Force interleaving height scaling +#define BINKCOPY2XW 0x30000000L // copy the width zoomed by two +#define BINKCOPY2XWH 0x40000000L // copy the width and height zoomed by two +#define BINKCOPY2XWHI 0x50000000L // copy the width and height zoomed by two +#define BINKCOPY1XI 0x60000000L // copy the width and height zoomed by two +#define BINKCOPYNOSCALING 0x70000000L // Force scaling off + +//#define BINKALPHA 0x00100000L // Decompress alpha plane (if present) +//#define BINKNOSKIP 0x00080000L // don't skip the blit if behind in sound +//#define BINKNOMMX 0x00040000L // Don't skip frames if falling behind +//#define BINKGRAYSCALE 0x00020000L // force Bink to use grayscale +//#define BINKRBINVERT 0x00010000L // use reversed R and B planes + +#define BINKSURFACE8P 0 +#define BINKSURFACE24 1 +#define BINKSURFACE24R 2 +#define BINKSURFACE32 3 +#define BINKSURFACE32R 4 +#define BINKSURFACE32A 5 +#define BINKSURFACE32RA 6 +#define BINKSURFACE4444 7 +#define BINKSURFACE5551 8 +#define BINKSURFACE555 9 +#define BINKSURFACE565 10 +#define BINKSURFACE655 11 +#define BINKSURFACE664 12 +#define BINKSURFACEYUY2 13 +#define BINKSURFACEUYVY 14 +#define BINKSURFACEYV12 15 +#define BINKSURFACEMASK 15 + +#define BINKGOTOQUICK 1 + +#define BINKGETKEYPREVIOUS 0 +#define BINKGETKEYNEXT 1 +#define BINKGETKEYCLOSEST 2 +#define BINKGETKEYNOTEQUAL 128 + +//======================================================================= + +#ifdef __RADMAC__ + #include + + #pragma export on + + RADEXPFUNC HBINK RADEXPLINK BinkMacOpen(FSSpec* fsp,u32 flags); +#endif + +RADEXPFUNC void PTR4* RADEXPLINK BinkLogoAddress(void); + +RADEXPFUNC void RADEXPLINK BinkSetError(const char PTR4* err); +RADEXPFUNC char PTR4* RADEXPLINK BinkGetError(void); + +RADEXPFUNC HBINK RADEXPLINK BinkOpen(const char PTR4* name,u32 flags); + +RADEXPFUNC s32 RADEXPLINK BinkDoFrame(HBINK bnk); +RADEXPFUNC void RADEXPLINK BinkNextFrame(HBINK bnk); +RADEXPFUNC s32 RADEXPLINK BinkWait(HBINK bnk); +RADEXPFUNC void RADEXPLINK BinkClose(HBINK bnk); +RADEXPFUNC s32 RADEXPLINK BinkPause(HBINK bnk,s32 pause); +RADEXPFUNC s32 RADEXPLINK BinkCopyToBuffer(HBINK bnk,void* dest,s32 destpitch,u32 destheight,u32 destx,u32 desty,u32 flags); +RADEXPFUNC s32 RADEXPLINK BinkGetRects(HBINK bnk,u32 flags); +RADEXPFUNC void RADEXPLINK BinkGoto(HBINK bnk,u32 frame,s32 flags); // use 1 for the first frame +RADEXPFUNC u32 RADEXPLINK BinkGetKeyFrame(HBINK bnk,u32 frame,s32 flags); + +RADEXPFUNC s32 RADEXPLINK BinkSetVideoOnOff(HBINK bnk,s32 onoff); +RADEXPFUNC s32 RADEXPLINK BinkSetSoundOnOff(HBINK bnk,s32 onoff); +RADEXPFUNC void RADEXPLINK BinkSetVolume(HBINK bnk,s32 volume); +RADEXPFUNC void RADEXPLINK BinkSetPan(HBINK bnk,s32 pan); +RADEXPFUNC void RADEXPLINK BinkService(HBINK bink); + +typedef struct BINKTRACK PTR4* HBINKTRACK; + +typedef struct BINKTRACK +{ + u32 Frequency; + u32 Bits; + u32 Channels; + u32 MaxSize; + + HBINK bink; + u32 sndcomp; + s32 trackindex; +} BINKTRACK; + + +RADEXPFUNC HBINKTRACK RADEXPLINK BinkOpenTrack(HBINK bnk,u32 trackindex); +RADEXPFUNC void RADEXPLINK BinkCloseTrack(HBINKTRACK bnkt); +RADEXPFUNC u32 RADEXPLINK BinkGetTrackData(HBINKTRACK bnkt,void PTR4* dest); + +RADEXPFUNC u32 RADEXPLINK BinkGetTrackType(HBINK bnk,u32 trackindex); +RADEXPFUNC u32 RADEXPLINK BinkGetTrackMaxSize(HBINK bnk,u32 trackindex); +RADEXPFUNC u32 RADEXPLINK BinkGetTrackID(HBINK bnk,u32 trackindex); +RADEXPFUNC u32 RADEXPLINK BinkGetTrackLargest(HBINK bnk,u32 trackindex); + +RADEXPFUNC void RADEXPLINK BinkGetSummary(HBINK bnk,BINKSUMMARY PTR4* sum); +RADEXPFUNC void RADEXPLINK BinkGetRealtime(HBINK bink,BINKREALTIME PTR4* run,u32 frames); + +#define BINKNOSOUND 0xffffffff + +RADEXPFUNC void RADEXPLINK BinkSetSoundTrack(u32 track); +RADEXPFUNC void RADEXPLINK BinkSetIO(BINKIOOPEN io); +RADEXPFUNC void RADEXPLINK BinkSetFrameRate(u32 forcerate,u32 forceratediv); +RADEXPFUNC void RADEXPLINK BinkSetSimulate(u32 sim); +RADEXPFUNC void RADEXPLINK BinkSetIOSize(u32 iosize); + +RADEXPFUNC s32 RADEXPLINK BinkSetSoundSystem(BINKSNDSYSOPEN open, u32 param); + +#ifdef __RADWIN__ + + RADEXPFUNC BINKSNDOPEN RADEXPLINK BinkOpenDirectSound(u32 param); // don't call directly + #define BinkSoundUseDirectSound(lpDS) BinkSetSoundSystem(BinkOpenDirectSound,(u32)lpDS) + + RADEXPFUNC BINKSNDOPEN RADEXPLINK BinkOpenWaveOut(u32 param); // don't call directly + #define BinkSoundUseWaveOut() BinkSetSoundSystem(BinkOpenWaveOut,0) + + #define INCLUDE_MMSYSTEM_H + #include "windows.h" + #include "windowsx.h" + + #ifdef __RADNT__ // to combat WIN32_LEAN_AND_MEAN + #include "mmsystem.h" + #endif + +#endif + + +#ifndef __RADMAC__ + + RADEXPFUNC BINKSNDOPEN RADEXPLINK BinkOpenMiles(u32 param); // don't call directly + #define BinkSoundUseMiles(hdigdriver) BinkSetSoundSystem(BinkOpenMiles,(u32)hdigdriver) + +#endif + + +#ifdef __RADMAC__ + + RADEXPFUNC BINKSNDOPEN RADEXPLINK BinkOpenSoundManager(u32 param); // don't call directly + #define BinkSoundUseSoundManager() BinkSetSoundSystem(BinkOpenSoundManager,0) + +#endif + + +// The BinkBuffer API isn't currently implemented on DOS +#if !defined(__RADDOS__) + +//========================================================================= +typedef struct BINKBUFFER * HBINKBUFFER; + +#define BINKBUFFERSTRETCHXINT 0x80000000 +#define BINKBUFFERSTRETCHX 0x40000000 +#define BINKBUFFERSHRINKXINT 0x20000000 +#define BINKBUFFERSHRINKX 0x10000000 +#define BINKBUFFERSTRETCHYINT 0x08000000 +#define BINKBUFFERSTRETCHY 0x04000000 +#define BINKBUFFERSHRINKYINT 0x02000000 +#define BINKBUFFERSHRINKY 0x01000000 +#define BINKBUFFERSCALES 0xff000000 +#define BINKBUFFERRESOLUTION 0x00800000 + +#ifdef __RADMAC__ + +#include +#include +#include + +typedef struct BINKBUFFER { + u32 Width; + u32 Height; + u32 WindowWidth; + u32 WindowHeight; + u32 SurfaceType; + void* Buffer; + s32 BufferPitch; + u32 ScreenWidth; + u32 ScreenHeight; + u32 ScreenDepth; + u32 ScaleFlags; + + s32 destx,desty; + s32 wndx,wndy; + u32 wnd; + + s32 noclipping; + u32 type; + s32 issoftcur; + u32 cursorcount; + +} BINKBUFFER; + + +#define BINKBUFFERAUTO 0 +#define BINKBUFFERDIRECT 1 +#define BINKBUFFERGWORLD 2 +#define BINKBUFFERTYPEMASK 31 + +RADEXPFUNC HBINKBUFFER RADEXPLINK BinkBufferOpen( WindowPtr wnd, u32 width, u32 height, u32 bufferflags); +RADEXPFUNC s32 RADEXPLINK BinkGDSurfaceType( GDHandle gd ); +RADEXPFUNC s32 RADEXPLINK BinkIsSoftwareCursor(GDHandle gd); +RADEXPFUNC s32 RADEXPLINK BinkCheckCursor(WindowPtr wp,s32 x,s32 y,s32 w,s32 h); + +#else + +typedef struct BINKBUFFER { + u32 Width; + u32 Height; + u32 WindowWidth; + u32 WindowHeight; + u32 SurfaceType; + void* Buffer; + s32 BufferPitch; + s32 ClientOffsetX; + s32 ClientOffsetY; + u32 ScreenWidth; + u32 ScreenHeight; + u32 ScreenDepth; + u32 ExtraWindowWidth; + u32 ExtraWindowHeight; + u32 ScaleFlags; + u32 StretchWidth; + u32 StretchHeight; + + s32 surface; + void* ddsurface; + void* ddclipper; + s32 destx,desty; + s32 wndx,wndy; + u32 wnd; + s32 ddoverlay; + s32 ddoffscreen; + s32 lastovershow; + + s32 issoftcur; + u32 cursorcount; + void* buffertop; + u32 type; + s32 noclipping; + + s32 loadeddd; + s32 loadedwin; + + void* dibh; + void* dibbuffer; + s32 dibpitch; + void* dibinfo; + u32 dibdc; + u32 diboldbitmap; + +} BINKBUFFER; + + +#define BINKBUFFERAUTO 0 +#define BINKBUFFERPRIMARY 1 +#define BINKBUFFERDIBSECTION 2 +#define BINKBUFFERYV12OVERLAY 3 +#define BINKBUFFERYUY2OVERLAY 4 +#define BINKBUFFERUYVYOVERLAY 5 +#define BINKBUFFERYV12OFFSCREEN 6 +#define BINKBUFFERYUY2OFFSCREEN 7 +#define BINKBUFFERUYVYOFFSCREEN 8 +#define BINKBUFFERRGBOFFSCREENVIDEO 9 +#define BINKBUFFERRGBOFFSCREENSYSTEM 10 +#define BINKBUFFERLAST 10 +#define BINKBUFFERTYPEMASK 31 + +RADEXPFUNC HBINKBUFFER RADEXPLINK BinkBufferOpen( HWND wnd, u32 width, u32 height, u32 bufferflags); +RADEXPFUNC s32 RADEXPLINK BinkBufferSetHWND( HBINKBUFFER buf, HWND newwnd); +RADEXPFUNC s32 RADEXPLINK BinkDDSurfaceType(void PTR4* lpDDS); +RADEXPFUNC s32 RADEXPLINK BinkIsSoftwareCursor(void PTR4* lpDDSP,HCURSOR cur); +RADEXPFUNC s32 RADEXPLINK BinkCheckCursor(HWND wnd,s32 x,s32 y,s32 w,s32 h); +RADEXPFUNC s32 RADEXPLINK BinkBufferSetDirectDraw(void PTR4* lpDirectDraw, void PTR4* lpPrimary); + +#endif + +RADEXPFUNC void RADEXPLINK BinkBufferClose( HBINKBUFFER buf); +RADEXPFUNC s32 RADEXPLINK BinkBufferLock( HBINKBUFFER buf); +RADEXPFUNC s32 RADEXPLINK BinkBufferUnlock( HBINKBUFFER buf); +RADEXPFUNC void RADEXPLINK BinkBufferSetResolution( s32 w, s32 h, s32 bits); +RADEXPFUNC void RADEXPLINK BinkBufferCheckWinPos( HBINKBUFFER buf, s32 PTR4* NewWindowX, s32 PTR4* NewWindowY); +RADEXPFUNC s32 RADEXPLINK BinkBufferSetOffset( HBINKBUFFER buf, s32 destx, s32 desty); +RADEXPFUNC void RADEXPLINK BinkBufferBlit( HBINKBUFFER buf, BINKRECT PTR4* rects, u32 numrects ); +RADEXPFUNC s32 RADEXPLINK BinkBufferSetScale( HBINKBUFFER buf, u32 w, u32 h); +RADEXPFUNC char PTR4* RADEXPLINK BinkBufferGetDescription( HBINKBUFFER buf); +RADEXPFUNC char PTR4* RADEXPLINK BinkBufferGetError(); +RADEXPFUNC s32 RADEXPLINK BinkBufferClear(HBINKBUFFER buf, u32 RGB); + +RADEXPFUNC void RADEXPLINK BinkRestoreCursor(s32 checkcount); + +#endif + +#ifdef __RADMAC__ + +#pragma export off + +#endif + +RADDEFEND + +#endif + +#endif + diff --git a/code/win32/binkw32.lib b/code/win32/binkw32.lib new file mode 100644 index 0000000..75369a3 Binary files /dev/null and b/code/win32/binkw32.lib differ diff --git a/code/win32/clear.bmp b/code/win32/clear.bmp new file mode 100644 index 0000000..1451638 Binary files /dev/null and b/code/win32/clear.bmp differ diff --git a/code/win32/feelit/ffc10.dll b/code/win32/feelit/ffc10.dll new file mode 100644 index 0000000..0536f23 Binary files /dev/null and b/code/win32/feelit/ffc10.dll differ diff --git a/code/win32/feelit/ffc10.lib b/code/win32/feelit/ffc10.lib new file mode 100644 index 0000000..54ca7f4 Binary files /dev/null and b/code/win32/feelit/ffc10.lib differ diff --git a/code/win32/feelit/ffc10d.dll b/code/win32/feelit/ffc10d.dll new file mode 100644 index 0000000..1f546c2 Binary files /dev/null and b/code/win32/feelit/ffc10d.dll differ diff --git a/code/win32/feelit/ffc10d.lib b/code/win32/feelit/ffc10d.lib new file mode 100644 index 0000000..786d23d Binary files /dev/null and b/code/win32/feelit/ffc10d.lib differ diff --git a/code/win32/feelit/vssver.scc b/code/win32/feelit/vssver.scc new file mode 100644 index 0000000..e025e3c Binary files /dev/null and b/code/win32/feelit/vssver.scc differ diff --git a/code/win32/rad.h b/code/win32/rad.h new file mode 100644 index 0000000..e669360 --- /dev/null +++ b/code/win32/rad.h @@ -0,0 +1,962 @@ +#ifndef __RAD__ +#define __RAD__ + +#define RADCOPYRIGHT "Copyright (C) 1994-2000, RAD Game Tools, Inc." + +#ifndef __RADRES__ + +// __RAD16__ means 16 bit code (Win16) +// __RAD32__ means 32 bit code (DOS, Win386, Win32s, Mac) + +// __RADDOS__ means DOS code (16 or 32 bit) +// __RADWIN__ means Windows code (Win16, Win386, Win32s) +// __RADWINEXT__ means Windows 386 extender (Win386) +// __RADNT__ means Win32s code +// __RADMAC__ means Macintosh + +// __RADX86__ means Intel x86 +// __RADMMX__ means Intel x86 MMX instructions are allowed +// __RAD68K__ means 68K +// __RADPPC__ means PowerPC + +// __RADLITTLEENDIAN__ means processor is little-endian (x86) +// __RADBIGENDIAN__ means processor is big-endian (680x0, PPC) + +// __RADALLOWINLINES__ means this compiler allows inline function declarations +// use RADINLINE for the appropriate keyword + + +#if (defined(__MWERKS__) && !defined(__INTEL__)) || defined(__MRC__) || defined(THINK_C) || defined(powerc) || defined(macintosh) || defined(__powerc) + + #define __RADMAC__ + #if defined(powerc) || defined(__powerc) + #define __RADPPC__ + #else + #define __RAD68K__ + #endif + + #define __RAD32__ + + #define __RADBIGENDIAN__ + + #if defined(__MWERKS__) + #if (defined(__cplusplus) || ! __option(only_std_keywords)) + #define __RADALLOWINLINES__ + #define RADINLINE inline + #endif + #elif defined(__MRC__) + #if defined(__cplusplus) + #define __RADALLOWINLINES__ + #define RADINLINE inline + #endif + #endif + +#else + + #define __RADX86__ + #define __RADMMX__ + + #ifdef __MWERKS__ + #define _WIN32 + #endif + + #ifdef __DOS__ + #define __RADDOS__ + #endif + + #ifdef __386__ + #define __RAD32__ + #endif + + #ifdef _Windows //For Borland + #ifdef __WIN32__ + #define WIN32 + #else + #define __WINDOWS__ + #endif + #endif + + #ifdef _WINDOWS //For MS + #ifndef _WIN32 + #define __WINDOWS__ + #endif + #endif + + #ifdef _WIN32 + #define __RADWIN__ + #define __RADNT__ + #define __RAD32__ + #else + #ifdef __NT__ + #define __RADWIN__ + #define __RADNT__ + #define __RAD32__ + #else + #ifdef __WINDOWS_386__ + #define __RADWIN__ + #define __RADWINEXT__ + #define __RAD32__ + #else + #ifdef __WINDOWS__ + #define __RADWIN__ + #define __RAD16__ + #else + #ifdef WIN32 + #define __RADWIN__ + #define __RADNT__ + #define __RAD32__ + #endif + #endif + #endif + #endif + #endif + + #define __RADLITTLEENDIAN__ + + // TODO - make sure these are set correctly for non-Mac versions + #define __RADALLOWINLINES__ + #define RADINLINE __inline + +#endif + +#ifndef __RADALLOWINLINES__ + #define RADINLINE +#endif + +#if (!defined(__RADDOS__) && !defined(__RADWIN__) && !defined(__RADMAC__)) + #error RAD.H did not detect your platform. Define __DOS__, __WINDOWS__, WIN32, macintosh, or powerc. +#endif + +#ifdef __RADMAC__ + + // this define is for CodeWarrior 11's stupid new libs (even though + // we don't use longlong's). + + #define __MSL_LONGLONG_SUPPORT__ + + #define RADLINK + #define RADEXPLINK + + #ifdef __CFM68K__ + #ifdef __RADINDLL__ + #define RADEXPFUNC RADDEFFUNC __declspec(export) + #else + #define RADEXPFUNC RADDEFFUNC __declspec(import) + #endif + #else + #define RADEXPFUNC RADDEFFUNC + #endif + #define RADASMLINK + +#else + + #ifdef __RADNT__ + #ifndef _WIN32 + #define _WIN32 + #endif + #ifndef WIN32 + #define WIN32 + #endif + #endif + + #ifdef __RADWIN__ + #ifdef __RAD32__ + #ifdef __RADNT__ + + #define RADLINK __stdcall + #define RADEXPLINK __stdcall + + #ifdef __RADINEXE__ + #define RADEXPFUNC RADDEFFUNC + #else + #ifndef __RADINDLL__ + #define RADEXPFUNC RADDEFFUNC __declspec(dllimport) + #ifdef __BORLANDC__ + #if __BORLANDC__<=0x460 + #undef RADEXPFUNC + #define RADEXPFUNC RADDEFFUNC + #endif + #endif + #else + #define RADEXPFUNC RADDEFFUNC __declspec(dllexport) + #endif + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __far __pascal + #define RADEXPFUNC RADDEFFUNC + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __far __pascal __export + #define RADEXPFUNC RADDEFFUNC + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __pascal + #define RADEXPFUNC RADDEFFUNC + #endif + + #define RADASMLINK __cdecl + +#endif + +#ifdef __RADWIN__ + #ifndef _WINDOWS + #define _WINDOWS + #endif +#endif + +#ifdef __cplusplus + #define RADDEFFUNC extern "C" + #define RADDEFSTART extern "C" { + #define RADDEFEND } +#else + #define RADDEFFUNC + #define RADDEFSTART + #define RADDEFEND +#endif + + +RADDEFSTART + +#define s8 signed char +#define u8 unsigned char +#define u32 unsigned long +#define s32 signed long +#define f32 float +#define f64 double + +#if defined(__MWERKS__) || defined(__MRC__) +#define u64 unsigned long long +#define s64 signed long long +#else +#define u64 unsigned __int64 +#define s64 signed __int64 +#endif + +/* 32 bit implementations */ + +#ifdef __RAD32__ + #define PTR4 + + #define u16 unsigned short + #define s16 signed short + + #ifdef __RADMAC__ + + #include + #include + #include + #include + #ifdef __MRC__ + #include "intrinsics.h" + #endif + + void radconv32a(void* p, u32 n); + + u32 radloadu32(u32 a); + + u32 radloadu32ptr(u32* p); + + #define radstrcpy strcpy + + #define radstrcat strcat + + #define radmemcpy(dest,source,size) BlockMoveData((Ptr)(source),(Ptr)(dest),size) + + #define radmemcpydb(dest,source,size) BlockMoveData((Ptr)(source),(Ptr)(dest),size) + + #define radmemcmp memcmp + + #define radmemset memset + + #define radstrlen strlen + + #define radstrchr strchr + + #define radtoupper toupper + + #define radstru32(s) ((u32)atol(s)) + + //s8 radstricmp(const void* s1,const void* s2); + + #define radstrcmp strcmp + + //char* radstrupr(void* s1); + + //char* radstrlwr(void* s1); + + u32 radsqr(u32 a); + + u32 mult64anddiv(u32 m1,u32 m2,u32 d); + + s32 radabs(s32 ab); + + #define radabs32 radabs + + //char* radstpcpy(void* dest,const void* source); + + //char* radstpcpyrs(void* dest,const void* source); + + void radmemset16(void* dest,u16 value,u32 size); + + //void radmemset32(void* dest,u32 value,u32 size); + + #define BreakPoint() DebugStr("\pBreakPoint() was called") + + //u8 radinp(u16 p); + + //void radoutp(u16 p,u8 v); + + //u32 RADsqrt(u32 sq); + + u32 RADCycleTimerAvail(void); + + void RADCycleTimerStartAddr(u32* addr); + + u32 RADCycleTimerDeltaAddr(u32* addr); + + void RADCycleTimerStartAddr64(u64* addr); + + void RADCycleTimerDeltaAddr64(u64* addr); + + #define RADCycleTimerStart(var) RADCycleTimerStartAddr(&var) + + #define RADCycleTimerDelta(var) RADCycleTimerDeltaAddr(&var) + + #define RADCycleTimerStart64(var) RADCycleTimerStartAddr64(&var) + + #define RADCycleTimerDelta64(var) RADCycleTimerDeltaAddr64(&var) + + + #ifdef __RAD68K__ + #pragma parameter radconv32a(__A0,__D0) + void radconv32a(void* p,u32 n) ={0x4A80,0x600C,0x2210,0xE059,0x4841,0xE059,0x20C1,0x5380,0x6EF2}; + // tst.l d0 bra.s @loope @loop: move.l (a0),d1 ror.w #8,d1 swap d1 ror.w #8,d1 move.l d1,(a0)+ sub.l #1,d0 bgt.s @loop @loope: + #endif + + #ifdef __RADALLOWINLINES__ + #if defined __RADPPC__ && defined(__MWERKS__) && (__MWERKS__ >= 0x2301) && 0 + u32 RADINLINE radloadu32(register u32 x) { + register u32 t1, t2; + asm { // x = aa bb cc dd + rlwinm t1,x,24,0,23 // t1 = dd aa bb 00 + rlwinm t2,x,8,24,31 // t2 = 00 00 00 aa + rlwimi t1,x,8, 8,15 // t1 = dd cc bb 00 + or x,t1,t2 // x = dd cc bb aa + } + return x; + } + #else + u32 RADINLINE radloadu32(register u32 x) { + return (((x << 24) & 0xFF000000) | + ((x << 8) & 0x00FF0000) | + ((x >> 8) & 0x0000FF00) | + ((x >> 24) & 0x000000FF)); + } + #endif + #endif + + #if defined(__RADPPC__) && (defined(__MWERKS__) || defined(__MRC__)) + #define radloadu32ptr(p) (u32) __lwbrx((p),0) + #else + #define radloadu32ptr(p) radloadu32(*(u32*)(p)); + #endif + + #ifdef __RADALLOWINLINES__ + u32 RADINLINE radsqr(u32 a) { return(a*a); } + #endif + + #ifdef __RAD68K__ + #pragma parameter __D0 mult64anddiv(__D0,__D1,__D2) + u32 mult64anddiv(u32 m1,u32 m2,u32 d) ={0x4C01,0x0C01,0x4C42,0x0C01}; + // muls.l d1,d1:d0 divs.l d2,d1:d0 + #endif + + #if defined(__RADPPC__) && (defined(__MWERKS__) || defined(__MRC__)) + #define radabs(ab) __abs((s32)(ab)) + #elif defined(__RADALLOWINLINES__) + s32 RADINLINE radabs(s32 ab) { return (ab < 0) ? -ab : ab; } + #endif + + #else + + #define radconv32a(p,n) ((void)0) + + #define radloadu32(a) ((u32)(a)) + + #define radloadu32ptr(p) *((u32*)(p)) + + #ifdef __WATCOMC__ + + u32 radsqr(s32 a); + #pragma aux radsqr = "mul eax" parm [eax] modify [EDX eax]; + + u32 mult64anddiv(u32 m1,u32 m2,u32 d); + #pragma aux mult64anddiv = "mul ecx" "div ebx" parm [eax] [ecx] [ebx] modify [EDX eax]; + + s32 radabs(s32 ab); + #pragma aux radabs = "test eax,eax" "jge skip" "neg eax" "skip:" parm [eax]; + + #define radabs32 radabs + + u32 DOSOut(const char* str); + #pragma aux DOSOut = "cld" "mov ecx,0xffffffff" "xor eax,eax" "mov edx,edi" "repne scasb" "not ecx" "dec ecx" "mov ebx,1" "mov ah,0x40" "int 0x21" parm [EDI] modify [EAX EBX ECX EDX EDI] value [ecx]; + + void DOSOutNum(const char* str,u32 len); + #pragma aux DOSOutNum = "mov ah,0x40" "mov ebx,1" "int 0x21" parm [edx] [ecx] modify [eax ebx]; + + u32 ErrOut(const char* str); + #pragma aux ErrOut = "cld" "mov ecx,0xffffffff" "xor eax,eax" "mov edx,edi" "repne scasb" "not ecx" "dec ecx" "xor ebx,ebx" "mov ah,0x40" "int 0x21" parm [EDI] modify [EAX EBX ECX EDX EDI] value [ecx]; + + void ErrOutNum(const char* str,u32 len); + #pragma aux ErrOutNum = "mov ah,0x40" "xor ebx,ebx" "int 0x21" parm [edx] [ecx] modify [eax ebx]; + + void radmemset16(void* dest,u16 value,u32 size); + #pragma aux radmemset16 = "cld" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,1" "rep stosd" "mov cl,bl" "and cl,1" "rep stosw" parm [EDI] [EAX] [ECX] modify [EAX EDX EBX ECX EDI]; + + void radmemset(void* dest,u8 value,u32 size); + #pragma aux radmemset = "cld" "mov ah,al" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,2" "and bl,3" "rep stosd" "mov cl,bl" "rep stosb" parm [EDI] [AL] [ECX] modify [EAX EDX EBX ECX EDI]; + + void radmemset32(void* dest,u32 value,u32 size); + #pragma aux radmemset32 = "cld" "rep stosd" parm [EDI] [EAX] [ECX] modify [EAX EDX EBX ECX EDI]; + + void radmemcpy(void* dest,const void* source,u32 size); + #pragma aux radmemcpy = "cld" "mov bl,cl" "shr ecx,2" "rep movsd" "mov cl,bl" "and cl,3" "rep movsb" parm [EDI] [ESI] [ECX] modify [EBX ECX EDI ESI]; + + void __far *radfmemcpy(void __far* dest,const void __far* source,u32 size); + #pragma aux radfmemcpy = "cld" "push es" "push ds" "mov es,cx" "mov ds,dx" "mov ecx,eax" "shr ecx,2" "rep movsd" "mov cl,al" "and cl,3" "rep movsb" "pop ds" "pop es" parm [CX EDI] [DX ESI] [EAX] modify [ECX EDI ESI] value [CX EDI]; + + void radmemcpydb(void* dest,const void* source,u32 size); //Destination bigger + #pragma aux radmemcpydb = "std" "mov bl,cl" "lea esi,[esi+ecx-4]" "lea edi,[edi+ecx-4]" "shr ecx,2" "rep movsd" "and bl,3" "jz dne" "add esi,3" "add edi,3" "mov cl,bl" "rep movsb" "dne:" "cld" parm [EDI] [ESI] [ECX] modify [EBX ECX EDI ESI]; + + char* radstrcpy(void* dest,const void* source); + #pragma aux radstrcpy = "cld" "mov edx,edi" "lp:" "mov al,[esi]" "inc esi" "mov [edi],al" "inc edi" "cmp al,0" "jne lp" parm [EDI] [ESI] modify [EAX EDX EDI ESI] value [EDX]; + + char __far* radfstrcpy(void __far* dest,const void __far* source); + #pragma aux radfstrcpy = "cld" "push es" "push ds" "mov es,cx" "mov ds,dx" "mov edx,edi" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "pop ds" "pop es" parm [CX EDI] [DX ESI] modify [EAX EDX EDI ESI] value [CX EDX]; + + char* radstpcpy(void* dest,const void* source); + #pragma aux radstpcpy = "cld" "lp:" "mov al,[esi]" "inc esi" "mov [edi],al" "inc edi" "cmp al,0" "jne lp" "dec edi" parm [EDI] [ESI] modify [EAX EDI ESI] value [EDI]; + + char* radstpcpyrs(void* dest,const void* source); + #pragma aux radstpcpyrs = "cld" "lp:" "mov al,[esi]" "inc esi" "mov [edi],al" "inc edi" "cmp al,0" "jne lp" "dec esi" parm [EDI] [ESI] modify [EAX EDI ESI] value [ESI]; + + u32 radstrlen(const void* dest); + #pragma aux radstrlen = "cld" "mov ecx,0xffffffff" "xor eax,eax" "repne scasb" "not ecx" "dec ecx" parm [EDI] modify [EAX ECX EDI] value [ECX]; + + char* radstrcat(void* dest,const void* source); + #pragma aux radstrcat = "cld" "mov ecx,0xffffffff" "mov edx,edi" "xor eax,eax" "repne scasb" "dec edi" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" \ + parm [EDI] [ESI] modify [EAX ECX EDI ESI] value [EDX]; + + char* radstrchr(const void* dest,char chr); + #pragma aux radstrchr = "cld" "lp:" "lodsb" "cmp al,dl" "je fnd" "cmp al,0" "jnz lp" "mov esi,1" "fnd:" "dec esi" parm [ESI] [DL] modify [EAX ESI] value [esi]; + + s8 radmemcmp(const void* s1,const void* s2,u32 len); + #pragma aux radmemcmp = "cld" "rep cmpsb" "setne al" "jbe end" "neg al" "end:" parm [EDI] [ESI] [ECX] modify [ECX EDI ESI]; + + s8 radstrcmp(const void* s1,const void* s2); + #pragma aux radstrcmp = "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,ah" "jne set" "cmp al,0" "je set" "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" \ + parm [EDI] [ESI] modify [EAX EDI ESI]; + + s8 radstricmp(const void* s1,const void* s2); + #pragma aux radstricmp = "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" "cmp ah,'a'" "jb c2" "cmp ah,'z'" "ja c2" "sub ah,32" "c2:" "cmp al,ah" "jne set" "cmp al,0" "je set" \ + "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" \ + parm [EDI] [ESI] modify [EAX EDI ESI]; + + s8 radstrnicmp(const void* s1,const void* s2,u32 len); + #pragma aux radstrnicmp = "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" "cmp ah,'a'" "jb c2" "cmp ah,'z'" "ja c2" "sub ah,32" "c2:" "cmp al,ah" "jne set" "cmp al,0" "je set" \ + "dec ecx" "jz set" "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" \ + parm [EDI] [ESI] [ECX] modify [EAX ECX EDI ESI]; + + char* radstrupr(void* s1); + #pragma aux radstrupr = "mov ecx,edi" "lp:" "mov al,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub [edi],32" "c1:" "inc edi" "cmp al,0" "jne lp" parm [EDI] modify [EAX EDI] value [ecx]; + + char* radstrlwr(void* s1); + #pragma aux radstrlwr = "mov ecx,edi" "lp:" "mov al,[edi]" "cmp al,'A'" "jb c1" "cmp al,'Z'" "ja c1" "add [edi],32" "c1:" "inc edi" "cmp al,0" "jne lp" parm [EDI] modify [EAX EDI] value [ecx]; + + u32 radstru32(const void* dest); + #pragma aux radstru32 = "cld" "xor ecx,ecx" "xor ebx,ebx" "xor edi,edi" "lodsb" "cmp al,45" "jne skip2" "mov edi,1" "jmp skip" "lp:" "mov eax,10" "mul ecx" "lea ecx,[eax+ebx]" \ + "skip:" "lodsb" "skip2:" "cmp al,0x39" "ja dne" "cmp al,0x30" "jb dne" "mov bl,al" "sub bl,0x30" "jmp lp" "dne:" "test edi,1" "jz pos" "neg ecx" "pos:" \ + parm [ESI] modify [EAX EBX EDX EDI ESI] value [ecx]; + + u16 GetDS(); + #pragma aux GetDS = "mov ax,ds" value [ax]; + + #ifdef __RADWINEXT__ + + #define _16To32(ptr16) ((void*)(((GetSelectorBase((u16)(((u32)(ptr16))>>16))+((u16)(u32)(ptr16)))-GetSelectorBase(GetDS())))) + + #endif + + #ifndef __RADWIN__ + #define int86 int386 + #define int86x int386x + #endif + + #define u32regs x + #define u16regs w + + #else + + #define radstrcpy strcpy + #define radstrcat strcat + #define radmemcpy memcpy + #define radmemcpydb memmove + #define radmemcmp memcmp + #define radmemset memset + #define radstrlen strlen + #define radstrchr strchr + #define radtoupper toupper + #define radstru32(s) ((u32)atol(s)) + #define radstricmp _stricmp + #define radstrcmp strcmp + #define radstrupr _strupr + #define radstrlwr _strlwr + #define BreakPoint() __asm {int 3} + #define DOSOut(str) + + #ifdef _MSC_VER + + #pragma warning( disable : 4035) + + typedef char* RADPCHAR; + + u32 __inline radsqr(u32 m) { + __asm { + mov eax,[m] + mul eax + } + } + + u32 __inline mult64anddiv(u32 m1,u32 m2, u32 d) { + __asm { + mov eax,[m1] + mov ecx,[m2] + mul ecx + mov ecx,[d] + div ecx + } + } + + s32 __inline radabs(s32 ab) { + __asm { + mov eax,[ab] + test eax,eax + jge skip + neg eax + skip: + } + } + + u8 __inline radinp(u16 p) { + __asm { + mov dx,[p] + in al,dx + } + } + + void __inline radoutp(u16 p,u8 v) { + __asm { + mov dx,[p] + mov al,[v] + out dx,al + } + } + + RADPCHAR __inline radstpcpy(char* p1, char* p2) { + __asm { + mov edx,[p1] + mov ecx,[p2] + cld + lp: + mov al,[ecx] + inc ecx + mov [edx],al + inc edx + cmp al,0 + jne lp + dec edx + mov eax,edx + } + } + + RADPCHAR __inline radstpcpyrs(char* p1, char* p2) { + __asm { + mov edx,[p1] + mov ecx,[p2] + cld + lp: + mov al,[ecx] + inc ecx + mov [edx],al + inc edx + cmp al,0 + jne lp + dec ecx + mov eax,ecx + } + } + + void __inline radmemset16(void* dest,u16 value,u32 sizeb) { + __asm { + mov edi,[dest] + mov ax,[value] + mov ecx,[sizeb] + shl eax,16 + cld + mov ax,[value] + mov bl,cl + shr ecx,1 + rep stosd + mov cl,bl + and cl,1 + rep stosw + } + } + + void __inline radmemset32(void* dest,u32 value,u32 sizeb) { + __asm { + mov edi,[dest] + mov eax,[value] + mov ecx,[sizeb] + cld + rep stosd + } + } + + u32 __inline __stdcall RADsqrt(u32 sq) { + __asm { + fild dword ptr [sq] + fsqrt + fistp word ptr [sq] + movzx eax,word ptr [sq] + } + } + + u32 __inline RADCycleTimerAvail(void) + { + u32 rdtscavail=(u32)-1; + __try + { + __asm + { +#ifdef __MWERKS__ + rdtsc +#else +#if _MSC_VER<=1100 + __emit 0xf + __emit 0x31 +#else + rdtsc +#endif +#endif + } + rdtscavail=1; + } + __except (1) + { + rdtscavail=(u32)-1; + } + return rdtscavail; + } + + void __inline RADCycleTimerStartAddr(u32* addr) + { + __asm { + mov ecx,[addr] +#ifdef __MWERKS__ + rdtsc +#else +#if _MSC_VER<=1100 + __emit 0xf + __emit 0x31 +#else + rdtsc +#endif +#endif + mov [ecx],eax + } + } + + u32 __inline RADCycleTimerDeltaAddr(u32* addr) + { + __asm { +#ifdef __MWERKS__ + rdtsc +#else +#if _MSC_VER<=1100 + __emit 0xf + __emit 0x31 +#else + rdtsc +#endif +#endif + mov ecx,[addr] + mov edx,eax + sub eax,[ecx] + mov [ecx],eax + } + } + + void __inline RADCycleTimerStartAddr64(u64* addr) + { + __asm { + mov ecx,[addr] +#ifdef __MWERKS__ + rdtsc +#else +#if _MSC_VER<=1100 + __emit 0xf + __emit 0x31 +#else + rdtsc +#endif +#endif + mov [ecx],eax + mov [ecx+4],edx + } + } + + void __inline RADCycleTimerDeltaAddr64(u64* addr) + { + __asm { +#ifdef __MWERKS__ + rdtsc +#else +#if _MSC_VER<=1100 + __emit 0xf + __emit 0x31 +#else + rdtsc +#endif +#endif + mov ecx,[addr] + sub eax,[ecx] + sbb edx,[ecx+4] + mov [ecx],eax + mov [ecx+4],edx + } + } + + #define RADCycleTimerStart(var) RADCycleTimerStartAddr(&var) + #define RADCycleTimerDelta(var) RADCycleTimerDeltaAddr(&var) + + #define RADCycleTimerStart64(var) RADCycleTimerStartAddr64(&var) + #define RADCycleTimerDelta64(var) RADCycleTimerDeltaAddr64(&var) + + #pragma warning( default : 4035) + + #endif + + #endif + + #endif + +#else + + #define PTR4 __far + + #define u16 unsigned int + #define s16 signed int + + #ifdef __WATCOMC__ + + u32 radsqr(s32 a); + #pragma aux radsqr = "shl edx,16" "mov dx,ax" "mov eax,edx" "xor edx,edx" "mul eax" "shld edx,eax,16" parm [dx ax] modify [DX ax] value [dx ax]; + + s16 radabs(s16 ab); + #pragma aux radabs = "test ax,ax" "jge skip" "neg ax" "skip:" parm [ax] value [ax]; + + s32 radabs32(s32 ab); + #pragma aux radabs32 = "test dx,dx" "jge skip" "neg dx" "neg ax" "sbb dx,0" "skip:" parm [dx ax] value [dx ax]; + + u32 DOSOut(const char far* dest); + #pragma aux DOSOut = "cld" "and edi,0xffff" "mov dx,di" "mov ecx,0xffffffff" "xor eax,eax" 0x67 "repne scasb" "not ecx" "dec ecx" "mov bx,1" "push ds" "push es" "pop ds" "mov ah,0x40" "int 0x21" "pop ds" "movzx eax,cx" "shr ecx,16" \ + parm [ES DI] modify [AX BX CX DX DI ES] value [CX AX]; + + void DOSOutNum(const char far* str,u16 len); + #pragma aux DOSOutNum = "push ds" "mov ds,cx" "mov cx,bx" "mov ah,0x40" "mov bx,1" "int 0x21" "pop ds" parm [cx dx] [bx] modify [ax bx cx]; + + u32 ErrOut(const char far* dest); + #pragma aux ErrOut = "cld" "and edi,0xffff" "mov dx,di" "mov ecx,0xffffffff" "xor eax,eax" 0x67 "repne scasb" "not ecx" "dec ecx" "xor bx,bx" "push ds" "push es" "pop ds" "mov ah,0x40" "int 0x21" "pop ds" "movzx eax,cx" "shr ecx,16" \ + parm [ES DI] modify [AX BX CX DX DI ES] value [CX AX]; + + void ErrOutNum(const char far* str,u16 len); + #pragma aux ErrOutNum = "push ds" "mov ds,cx" "mov cx,bx" "mov ah,0x40" "xor bx,bx" "int 0x21" "pop ds" parm [cx dx] [bx] modify [ax bx cx]; + + void radmemset(void far *dest,u8 value,u32 size); + #pragma aux radmemset = "cld" "and edi,0ffffh" "shl ecx,16" "mov cx,bx" "mov ah,al" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,2" 0x67 "rep stosd" "mov cl,bl" "and cl,3" "rep stosb" parm [ES DI] [AL] [CX BX]; + + void radmemset16(void far* dest,u16 value,u32 size); + #pragma aux radmemset16 = "cld" "and edi,0ffffh" "shl ecx,16" "mov cx,bx" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,1" "rep stosd" "mov cl,bl" "and cl,1" "rep stosw" parm [ES DI] [AX] [CX BX]; + + void radmemcpy(void far* dest,const void far* source,u32 size); + #pragma aux radmemcpy = "cld" "push ds" "mov ds,dx" "and esi,0ffffh" "and edi,0ffffh" "shl ecx,16" "mov cx,bx" "shr ecx,2" 0x67 "rep movsd" "mov cl,bl" "and cl,3" "rep movsb" "pop ds" parm [ES DI] [DX SI] [CX BX] modify [CX SI DI ES]; + + s8 radmemcmp(const void far* s1,const void far* s2,u32 len); + #pragma aux radmemcmp = "cld" "push ds" "mov ds,dx" "shl ecx,16" "mov cx,bx" "rep cmpsb" "setne al" "jbe end" "neg al" "end:" "pop ds" parm [ES DI] [DX SI] [CX BX] modify [CX SI DI ES]; + + char far* radstrcpy(void far* dest,const void far* source); + #pragma aux radstrcpy = "cld" "push ds" "mov ds,dx" "and esi,0xffff" "and edi,0xffff" "mov dx,di" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "pop ds" parm [ES DI] [DX SI] modify [AX DX DI SI ES] value [es dx]; + + char far* radstpcpy(void far* dest,const void far* source); + #pragma aux radstpcpy = "cld" "push ds" "mov ds,dx" "and esi,0xffff" "and edi,0xffff" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "dec di" "pop ds" parm [ES DI] [DX SI] modify [DI SI ES] value [es di]; + + u32 radstrlen(const void far* dest); + #pragma aux radstrlen = "cld" "and edi,0xffff" "mov ecx,0xffffffff" "xor eax,eax" 0x67 "repne scasb" "not ecx" "dec ecx" "movzx eax,cx" "shr ecx,16" parm [ES DI] modify [AX CX DI ES] value [CX AX]; + + char far* radstrcat(void far* dest,const void far* source); + #pragma aux radstrcat = "cld" "and edi,0xffff" "mov ecx,0xffffffff" "and esi,0xffff" "push ds" "mov ds,dx" "mov dx,di" "xor eax,eax" 0x67 "repne scasb" "dec edi" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "pop ds" \ + parm [ES DI] [DX SI] modify [AX CX DI SI ES] value [es dx]; + + char far* radstrchr(const void far* dest,char chr); + #pragma aux radstrchr = "cld" "lp:" 0x26 "lodsb" "cmp al,dl" "je fnd" "cmp al,0" "jnz lp" "xor ax,ax" "mov es,ax" "mov si,1" "fnd:" "dec si" parm [ES SI] [DL] modify [AX SI ES] value [es si]; + + s8 radstricmp(const void far* s1,const void far* s2); + #pragma aux radstricmp = "and edi,0xffff" "push ds" "mov ds,dx" "and esi,0xffff" "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" \ + "cmp ah,'a'" "jb c2" "cmp ah,'z'" "ja c2" "sub ah,32" "c2:" "cmp al,ah" "jne set" "cmp al,0" "je set" \ + "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" "pop ds" \ + parm [ES DI] [DX SI] modify [AX DI SI]; + + u32 radstru32(const void far* dest); + #pragma aux radstru32 = "cld" "xor ecx,ecx" "xor ebx,ebx" "xor edi,edi" 0x26 "lodsb" "cmp al,45" "jne skip2" "mov edi,1" "jmp skip" "lp:" "mov eax,10" "mul ecx" "lea ecx,[eax+ebx]" \ + "skip:" 0x26 "lodsb" "skip2:" "cmp al,0x39" "ja dne" "cmp al,0x30" "jb dne" "mov bl,al" "sub bl,0x30" "jmp lp" "dne:" "test edi,1" "jz pos" "neg ecx" "pos:" \ + "movzx eax,cx" "shr ecx,16" parm [ES SI] modify [AX BX DX DI SI] value [cx ax]; + + u32 mult64anddiv(u32 m1,u32 m2,u32 d); + #pragma aux mult64anddiv = "shl ecx,16" "mov cx,ax" "shrd eax,edx,16" "mov ax,si" "mul ecx" "shl edi,16" "mov di,bx" "div edi" "shld edx,eax,16" "and edx,0xffff" "and eax,0xffff" parm [cx ax] [dx si] [di bx] \ + modify [ax bx cx dx si di] value [dx ax]; + + #endif + +#endif + +RADDEFEND + +#define u32neg1 ((u32)(s32)-1) +#define RAD_align(var) var; u8 junk##var[4-(sizeof(var)&3)]; +#define RAD_align_after(var) u8 junk##var[4-(sizeof(var)&3)]={0}; +#define RAD_align_init(var,val) var=val; u8 junk##var[4-(sizeof(var)&3)]={0}; +#define RAD_align_array(var,num) var[num]; u8 junk##var[4-(sizeof(var)&3)]; +#define RAD_align_string(var,str) char var[]=str; u8 junk##var[4-(sizeof(var)&3)]={0}; + + +typedef void PTR4* (RADLINK PTR4* RADMEMALLOC) (u32 bytes); +typedef void (RADLINK PTR4* RADMEMFREE) (void PTR4* ptr); + +#ifdef __RADMAC__ + #pragma export on +#endif +RADEXPFUNC void RADEXPLINK RADSetMemory(RADMEMALLOC a,RADMEMFREE f); +#ifdef __RADMAC__ + #pragma export off +#endif + +RADEXPFUNC void PTR4* RADEXPLINK radmalloc(u32 numbytes); +RADEXPFUNC void RADEXPLINK radfree(void PTR4* ptr); + +#ifdef __RADDOS__ + + RADDEFSTART + extern void* RADTimerSetupAddr; + extern void* RADTimerReadAddr; + extern void* RADTimerDoneAddr; + RADDEFEND + + typedef void RADEXPLINK (*RADTimerSetupType)(void); + typedef u32 RADEXPLINK (*RADTimerReadType)(void); + typedef void RADEXPLINK (*RADTimerDoneType)(void); + + #define RADTimerSetup() ((RADTimerSetupType)(RADTimerSetupAddr))() + #define RADTimerRead() ((RADTimerReadType)(RADTimerReadAddr))() + #define RADTimerDone() ((RADTimerDoneType)(RADTimerDoneAddr))() + +#else + + #define RADTimerSetup() + #define RADTimerDone() + + #if (defined(__RAD16__) || defined(__RADWINEXT__)) + + #define RADTimerRead timeGetTime + + #else + + RADEXPFUNC u32 RADEXPLINK RADTimerRead(void); + + #endif + +#endif + + +#ifdef __WATCOMC__ + + char bkbhit(); + #pragma aux bkbhit = "mov ah,1" "int 0x16" "lahf" "shr eax,14" "and eax,1" "xor al,1" ; + + char bgetch(); + #pragma aux bgetch = "xor ah,ah" "int 0x16" "test al,0xff" "jnz done" "mov al,ah" "or al,0x80" "done:" modify [AX]; + + void BreakPoint(); + #pragma aux BreakPoint = "int 3"; + + u8 radinp(u16 p); + #pragma aux radinp = "in al,dx" parm [DX]; + + u8 radtoupper(u8 p); + #pragma aux radtoupper = "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" parm [al] value [al]; + + void radoutp(u16 p,u8 v); + #pragma aux radoutp = "out dx,al" parm [DX] [AL]; + +#else + +// for multi-processor machines + +#ifdef __RADNT__ + #define LockedIncrement(var) __asm { lock inc [var] } + #define LockedDecrement(var) __asm { lock dec [var] } + void __inline LockedIncrementFunc(void PTR4* var) { + __asm { + mov eax,[var] + lock inc [eax] + } + } + + void __inline LockedDecrementFunc(void PTR4* var) { + __asm { + mov eax,[var] + lock dec [eax] + } + } + +#else + + #ifdef __RADMAC__ + + #define LockedIncrement(var) {++(var);} + #define LockedDecrement(var) {--(var);} + + #define LockedIncrementFunc(ptr) {++(*((u32*)(ptr)));} + #define LockedDecrementFunc(ptr) {--(*((u32*)(ptr)));} + + #else + + #define LockedIncrement(var) __asm { inc [var] } + #define LockedDecrement(var) __asm { dec [var] } + void __inline LockedIncrementFunc(void PTR4* var) { __asm { mov eax,[var] + inc [eax] } } + void __inline LockedDecrementFunc(void PTR4* var) { __asm { mov eax,[var] + dec [eax] } } + #endif + +#endif + +#endif + +#endif + +#endif + diff --git a/code/win32/vssver.scc b/code/win32/vssver.scc new file mode 100644 index 0000000..6303e82 Binary files /dev/null and b/code/win32/vssver.scc differ diff --git a/code/win32/win_glimp.cpp b/code/win32/win_glimp.cpp index 434c301..b09947e 100644 --- a/code/win32/win_glimp.cpp +++ b/code/win32/win_glimp.cpp @@ -76,7 +76,7 @@ static qboolean GLW_StartDriverAndSetMode( int mode, { rserr_t err; - err = GLW_SetMode( r_mode->integer, colorbits, cdsFullscreen ); + err = GLW_SetMode( mode, colorbits, cdsFullscreen ); switch ( err ) { @@ -896,12 +896,14 @@ static rserr_t GLW_SetMode( int mode, ri.Printf( PRINT_ALL, "...restoring display settings\n" ); ChangeDisplaySettings( 0, 0 ); +/* jfm: i took out the following code to allow fallback to mode 3, with this code it goes half windowed and just doesn't work. glw_state.cdsFullscreen = qfalse; glConfig.isFullscreen = qfalse; if ( !GLW_CreateWindow( glConfig.vidWidth, glConfig.vidHeight, colorbits, qfalse) ) { return RSERR_INVALID_MODE; } +*/ return RSERR_INVALID_FULLSCREEN; } } @@ -1417,6 +1419,14 @@ void GLimp_Init( void ) ri.Error( ERR_FATAL, "GLimp_Init() - Invalid GL Driver\n" ); } + // OpenGL driver constants + qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &glConfig.maxTextureSize ); + // stubbed or broken drivers may have reported 0... + if ( glConfig.maxTextureSize <= 0 ) + { + glConfig.maxTextureSize = 0; + } + // // chipset specific configuration // @@ -1428,39 +1438,42 @@ void GLimp_Init( void ) // to be overridden when testing driver fixes, etc. but only sets // them to their default state when the hardware is first installed/run. // +extern qboolean Sys_LowPhysicalMemory(); if ( Q_stricmp( lastValidRenderer->string, glConfig.renderer_string ) ) { - ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); - - // VOODOO GRAPHICS w/ 2MB -/* if ( strstr( buf, "voodoo graphics/1 tmu/2 mb" ) ) + if (Sys_LowPhysicalMemory()) { - ri.Cvar_Set( "r_picmip", "2" ); + ri.Cvar_Set("s_khz", "11");// this will get called before S_Init + ri.Cvar_Set("cg_VariantSoundCap", "2"); + ri.Cvar_Set("s_allowDynamicMusic","0"); + } + //reset to defaults + ri.Cvar_Set( "r_picmip", "1" ); + + if ( strstr( buf, "matrox" )) { + ri.Cvar_Set( "r_allowExtensions", "0"); } else -*/ { - ri.Cvar_Set( "r_picmip", "1" ); + // Savage3D and Savage4 should always have trilinear enabled + if ( strstr( buf, "savage3d" ) || strstr( buf, "s3 savage4" ) || strstr( buf, "geforce" )) + { + ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); + } + else + { + ri.Cvar_Set( "r_textureMode", "GL_LINEAR_MIPMAP_NEAREST" ); + } -/* if ( strstr( buf, "rage 128" ) || strstr( buf, "rage128" ) ) - { - ri.Cvar_Set( "r_finish", "0" ); - } - // Savage3D and Savage4 should always have trilinear enabled - else -*/ if ( strstr( buf, "savage3d" ) || strstr( buf, "s3 savage4" ) ) - { - ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); - } - else if ( strstr( buf, "geforce" ) || strstr( buf, "quadro" ) ) - { - ri.Cvar_Set( "r_picmip", "0" ); - ri.Cvar_Set( "r_texturemode", "GL_LINEAR_MIPMAP_LINEAR" ); - } -/* else if ( strstr( buf, "rage pro" ) || strstr( buf, "riva 128" ) ) - { - ri.Cvar_Set( "r_detailtextures", "0"); - } -*/ + GLW_InitExtensions(); + + //this must be a really sucky card! + if ( (glConfig.textureCompression == TC_NONE) || (glConfig.maxActiveTextures < 2) || (glConfig.maxTextureSize <= 512) ) + { + ri.Cvar_Set( "r_picmip", "2"); + ri.Cvar_Set( "r_colorbits", "16"); + ri.Cvar_Set( "r_texturebits", "16"); + ri.Cvar_Set( "r_mode", "3"); //force 640 + Cmd_ExecuteString ("exec low.cfg\n"); //get the rest which can be pulled in after init } } diff --git a/code/win32/win_input.cpp b/code/win32/win_input.cpp index 99a4b51..0dab7e5 100644 --- a/code/win32/win_input.cpp +++ b/code/win32/win_input.cpp @@ -718,7 +718,7 @@ void IN_Frame (void) { if ( cls.keyCatchers & KEYCATCH_CONSOLE ) { // temporarily deactivate if not in the game and // running on the desktop - if (Cvar_VariableValue ("r_fullscreen") == 0 ) { + if (Cvar_VariableIntegerValue ("r_fullscreen") == 0 ) { IN_DeactivateMouse (); return; } @@ -1077,7 +1077,7 @@ static void MidiInfo_f( void ) Com_Printf( "number of devices: %d\n", s_midiInfo.numDevices ); for ( i = 0; i < s_midiInfo.numDevices; i++ ) { - if ( i == Cvar_VariableValue( "in_mididevice" ) ) + if ( i == Cvar_VariableIntegerValue( "in_mididevice" ) ) Com_Printf( "***" ); else Com_Printf( "..." ); @@ -1093,7 +1093,7 @@ static void IN_StartupMIDI( void ) { int i; - if ( !Cvar_VariableValue( "in_midi" ) ) + if ( !Cvar_VariableIntegerValue( "in_midi" ) ) return; // diff --git a/code/win32/win_main.cpp b/code/win32/win_main.cpp index d343c12..622f371 100644 --- a/code/win32/win_main.cpp +++ b/code/win32/win_main.cpp @@ -19,7 +19,7 @@ #define CD_BASEDIR "gamedata\\gamedata" #define CD_EXE "jk2sp.exe" -#define MEM_THRESHOLD 192*1024*1024 +#define MEM_THRESHOLD 128*1024*1024 static char sys_cmdline[MAX_STRING_CHARS]; diff --git a/code/win32/win_syscon.cpp b/code/win32/win_syscon.cpp index 2adce86..dec3b7b 100644 --- a/code/win32/win_syscon.cpp +++ b/code/win32/win_syscon.cpp @@ -98,9 +98,9 @@ static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara break; case WM_CLOSE: - cmdString = CopyString( "quit" ); - Sys_QueEvent( 0, SE_CONSOLE, 0, 0, strlen( cmdString ) + 1, cmdString ); -/* if ( s_wcd.quitOnClose ) + //cmdString = CopyString( "quit" ); + //Sys_QueEvent( 0, SE_CONSOLE, 0, 0, strlen( cmdString ) + 1, cmdString ); + if ( s_wcd.quitOnClose ) { PostQuitMessage( 0 ); } @@ -109,13 +109,12 @@ static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara Sys_ShowConsole( 0, qfalse ); Cvar_Set( "viewlog", "0" ); } -*/ return 0; + return 0; case WM_CTLCOLORSTATIC: if ( ( HWND ) lParam == s_wcd.hwndBuffer ) { - SetBkColor( ( HDC ) wParam, RGB( 230, 100, 230 ) ); - SetTextColor( ( HDC ) wParam, RGB( 0x00, 0x00, 0xF0 ) ); - + SetBkColor( ( HDC ) wParam, RGB( 0, 0, 0 ) ); + SetTextColor( ( HDC ) wParam, RGB( 249, 249, 000 ) ); return ( long ) s_wcd.hbrEditBackground; } else if ( ( HWND ) lParam == s_wcd.hwndErrorBox ) @@ -161,7 +160,7 @@ static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara } break; case WM_CREATE: - s_wcd.hbrEditBackground = CreateSolidBrush( RGB( 230, 100, 230 ) ); + s_wcd.hbrEditBackground = CreateSolidBrush( RGB( 0x00, 0x00, 0x00 ) ); s_wcd.hbrErrorBackground = CreateSolidBrush( RGB( 0x80, 0x80, 0x80 ) ); SetTimer( hWnd, 1, 1000, NULL ); break; @@ -222,7 +221,7 @@ void Sys_CreateConsole( void ) HDC hDC; WNDCLASS wc; RECT rect; - const char *DEDCLASS = "Q3 WinConsole"; + const char *DEDCLASS = "JK2MP WinConsole"; int nHeight; int swidth, sheight; int DEDSTYLE = WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX; @@ -236,7 +235,7 @@ void Sys_CreateConsole( void ) wc.hInstance = g_wv.hInstance; wc.hIcon = LoadIcon( g_wv.hInstance, MAKEINTRESOURCE(IDI_ICON1)); wc.hCursor = LoadCursor (NULL,IDC_ARROW); - wc.hbrBackground = (HBRUSH__ *)COLOR_WINDOW; + wc.hbrBackground = (HBRUSH__ *)COLOR_INACTIVEBORDER;//(HBRUSH__ *)COLOR_WINDOW; wc.lpszMenuName = 0; wc.lpszClassName = DEDCLASS; @@ -245,7 +244,7 @@ void Sys_CreateConsole( void ) } rect.left = 0; - rect.right = 580; + rect.right = 600; rect.top = 0; rect.bottom = 450; AdjustWindowRect( &rect, DEDSTYLE, FALSE ); @@ -260,7 +259,7 @@ void Sys_CreateConsole( void ) s_wcd.hWnd = CreateWindowEx( 0, DEDCLASS, - "Console", + "Jedi Knight 2: Jedi Outcast SP Console", DEDSTYLE, ( swidth - 600 ) / 2, ( sheight - 450 ) / 2 , rect.right - rect.left + 1, rect.bottom - rect.top + 1, NULL, @@ -301,7 +300,7 @@ void Sys_CreateConsole( void ) // s_wcd.hwndInputLine = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL, - 6, 400, 528, 20, + 6, 400, s_wcd.windowWidth-20, 20, s_wcd.hWnd, ( HMENU ) INPUT_ID, // child window ID g_wv.hInstance, NULL ); @@ -324,7 +323,7 @@ void Sys_CreateConsole( void ) SendMessage( s_wcd.hwndButtonClear, WM_SETTEXT, 0, ( LPARAM ) "clear" ); s_wcd.hwndButtonQuit = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, - 462, 425, 72, 24, + s_wcd.windowWidth-92, 425, 72, 24, s_wcd.hWnd, ( HMENU ) QUIT_ID, // child window ID g_wv.hInstance, NULL ); @@ -336,7 +335,7 @@ void Sys_CreateConsole( void ) // s_wcd.hwndBuffer = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY, - 6, 40, 526, 354, + 6, 40, s_wcd.windowWidth-20, 354, s_wcd.hWnd, ( HMENU ) EDIT_ID, // child window ID g_wv.hInstance, NULL ); @@ -344,6 +343,7 @@ void Sys_CreateConsole( void ) s_wcd.SysInputLineWndProc = ( WNDPROC ) SetWindowLong( s_wcd.hwndInputLine, GWL_WNDPROC, ( long ) InputLineWndProc ); SendMessage( s_wcd.hwndInputLine, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 ); + SendMessage( s_wcd.hwndBuffer, EM_LIMITTEXT, ( WPARAM ) 0x7fff, 0 ); ShowWindow( s_wcd.hWnd, SW_SHOWDEFAULT); UpdateWindow( s_wcd.hWnd ); @@ -523,7 +523,7 @@ void Sys_SetErrorText( const char *buf ) if ( !s_wcd.hwndErrorBox ) { s_wcd.hwndErrorBox = CreateWindow( "static", NULL, WS_CHILD | WS_VISIBLE | SS_SUNKEN, - 6, 5, 526, 30, + 6, 5, s_wcd.windowWidth-20, 30, s_wcd.hWnd, ( HMENU ) ERRORBOX_ID, // child window ID g_wv.hInstance, NULL ); diff --git a/code/win32/win_wndproc.cpp b/code/win32/win_wndproc.cpp index ac09dac..78a205d 100644 --- a/code/win32/win_wndproc.cpp +++ b/code/win32/win_wndproc.cpp @@ -151,7 +151,7 @@ static byte s_scantokey_french[128] = 0 , 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', ')', '=', K_BACKSPACE, 9, // 0 'a', 'z', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '^', '$', 13 , K_CTRL, 'q', 's', // 1 + 'o', 'p', '^', '$', 13 , K_CTRL, 'q', 's', // 1 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', '%' , '`', K_SHIFT,'*', 'w', 'x', 'c', 'v', // 2 'b', 'n', ',', ';', ':', '!', K_SHIFT,'*', diff --git a/code/win32/winquake.aps b/code/win32/winquake.aps new file mode 100644 index 0000000..8e6257d Binary files /dev/null and b/code/win32/winquake.aps differ diff --git a/ui/vssver.scc b/ui/vssver.scc new file mode 100644 index 0000000..3fe239c Binary files /dev/null and b/ui/vssver.scc differ