Changed line endings to UNIX.
This commit is contained in:
1 parent
7acbb8c956
commit
fc0f4ac57c
52 files changed
+53864
-53864
No files matched your search
+2031
-2031
File diff suppressed because it is too large.
Load diff
+104
-104
@@ -1,104 +1,104 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// bg_lib.h -- standard C library replacement routines used by code
|
||||
// compiled for the virtual machine
|
||||
|
||||
// This file is NOT included on native builds
|
||||
#ifndef BG_LIB_H
|
||||
#define BG_LIB_H
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
typedef int size_t;
|
||||
|
||||
typedef char * va_list;
|
||||
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
|
||||
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
|
||||
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
|
||||
#define va_end(ap) ( ap = (va_list)0 )
|
||||
|
||||
#define CHAR_BIT 8 /* number of bits in a char */
|
||||
#define SCHAR_MIN (-128) /* minimum signed char value */
|
||||
#define SCHAR_MAX 127 /* maximum signed char value */
|
||||
#define UCHAR_MAX 0xff /* maximum unsigned char value */
|
||||
|
||||
#define SHRT_MIN (-32768) /* minimum (signed) short value */
|
||||
#define SHRT_MAX 32767 /* maximum (signed) short value */
|
||||
#define USHRT_MAX 0xffff /* maximum unsigned short value */
|
||||
#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */
|
||||
#define INT_MAX 2147483647 /* maximum (signed) int value */
|
||||
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
|
||||
#define LONG_MIN (-2147483647L - 1) /* minimum (signed) long value */
|
||||
#define LONG_MAX 2147483647L /* maximum (signed) long value */
|
||||
#define ULONG_MAX 0xffffffffUL /* maximum unsigned long value */
|
||||
|
||||
// Misc functions
|
||||
typedef int cmp_t( const void *, const void * );
|
||||
void qsort( void *a, size_t n, size_t es, cmp_t *cmp );
|
||||
void srand( unsigned seed );
|
||||
int rand( void );
|
||||
|
||||
// String functions
|
||||
size_t strlen( const char *string );
|
||||
char *strcat( char *strDestination, const char *strSource );
|
||||
char *strcpy( char *strDestination, const char *strSource );
|
||||
int strcmp( const char *string1, const char *string2 );
|
||||
char *strchr( const char *string, int c );
|
||||
char *strrchr( const char *string, int c );
|
||||
char *strstr( const char *string, const char *strCharSet );
|
||||
char *strncpy( char *strDest, const char *strSource, size_t count );
|
||||
int tolower( int c );
|
||||
int toupper( int c );
|
||||
|
||||
double atof( const char *string );
|
||||
double _atof( const char **stringPtr );
|
||||
int atoi( const char *string );
|
||||
int _atoi( const char **stringPtr );
|
||||
|
||||
|
||||
int vsprintf( char *buffer, const char *fmt, va_list argptr );
|
||||
int sscanf( const char *buffer, const char *fmt, ... );
|
||||
|
||||
// Memory functions
|
||||
void *memmove( void *dest, const void *src, size_t count );
|
||||
void *memset( void *dest, int c, size_t count );
|
||||
void *memcpy( void *dest, const void *src, size_t count );
|
||||
|
||||
// Math functions
|
||||
double ceil( double x );
|
||||
double floor( double x );
|
||||
double sqrt( double x );
|
||||
double sin( double x );
|
||||
double cos( double x );
|
||||
double atan2( double y, double x );
|
||||
double tan( double x );
|
||||
int abs( int n );
|
||||
double fabs( double x );
|
||||
double acos( double x );
|
||||
float pow( float x, float y );
|
||||
double rint( double v );
|
||||
|
||||
#endif // BG_LIB_H
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// bg_lib.h -- standard C library replacement routines used by code
|
||||
// compiled for the virtual machine
|
||||
|
||||
// This file is NOT included on native builds
|
||||
#ifndef BG_LIB_H
|
||||
#define BG_LIB_H
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
typedef int size_t;
|
||||
|
||||
typedef char * va_list;
|
||||
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
|
||||
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
|
||||
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
|
||||
#define va_end(ap) ( ap = (va_list)0 )
|
||||
|
||||
#define CHAR_BIT 8 /* number of bits in a char */
|
||||
#define SCHAR_MIN (-128) /* minimum signed char value */
|
||||
#define SCHAR_MAX 127 /* maximum signed char value */
|
||||
#define UCHAR_MAX 0xff /* maximum unsigned char value */
|
||||
|
||||
#define SHRT_MIN (-32768) /* minimum (signed) short value */
|
||||
#define SHRT_MAX 32767 /* maximum (signed) short value */
|
||||
#define USHRT_MAX 0xffff /* maximum unsigned short value */
|
||||
#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */
|
||||
#define INT_MAX 2147483647 /* maximum (signed) int value */
|
||||
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
|
||||
#define LONG_MIN (-2147483647L - 1) /* minimum (signed) long value */
|
||||
#define LONG_MAX 2147483647L /* maximum (signed) long value */
|
||||
#define ULONG_MAX 0xffffffffUL /* maximum unsigned long value */
|
||||
|
||||
// Misc functions
|
||||
typedef int cmp_t( const void *, const void * );
|
||||
void qsort( void *a, size_t n, size_t es, cmp_t *cmp );
|
||||
void srand( unsigned seed );
|
||||
int rand( void );
|
||||
|
||||
// String functions
|
||||
size_t strlen( const char *string );
|
||||
char *strcat( char *strDestination, const char *strSource );
|
||||
char *strcpy( char *strDestination, const char *strSource );
|
||||
int strcmp( const char *string1, const char *string2 );
|
||||
char *strchr( const char *string, int c );
|
||||
char *strrchr( const char *string, int c );
|
||||
char *strstr( const char *string, const char *strCharSet );
|
||||
char *strncpy( char *strDest, const char *strSource, size_t count );
|
||||
int tolower( int c );
|
||||
int toupper( int c );
|
||||
|
||||
double atof( const char *string );
|
||||
double _atof( const char **stringPtr );
|
||||
int atoi( const char *string );
|
||||
int _atoi( const char **stringPtr );
|
||||
|
||||
|
||||
int vsprintf( char *buffer, const char *fmt, va_list argptr );
|
||||
int sscanf( const char *buffer, const char *fmt, ... );
|
||||
|
||||
// Memory functions
|
||||
void *memmove( void *dest, const void *src, size_t count );
|
||||
void *memset( void *dest, int c, size_t count );
|
||||
void *memcpy( void *dest, const void *src, size_t count );
|
||||
|
||||
// Math functions
|
||||
double ceil( double x );
|
||||
double floor( double x );
|
||||
double sqrt( double x );
|
||||
double sin( double x );
|
||||
double cos( double x );
|
||||
double atan2( double y, double x );
|
||||
double tan( double x );
|
||||
int abs( int n );
|
||||
double fabs( double x );
|
||||
double acos( double x );
|
||||
float pow( float x, float y );
|
||||
double rint( double v );
|
||||
|
||||
#endif // BG_LIB_H
|
||||
+88
-88
@@ -1,88 +1,88 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// bg_local.h -- local definitions for the bg (both games) files
|
||||
|
||||
#define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes
|
||||
|
||||
#define STEPSIZE 18
|
||||
|
||||
#define TIMER_LAND 130
|
||||
#define TIMER_GESTURE (34*66+50)
|
||||
#define TIMER_ATTACK 500 //nonsegmented models
|
||||
|
||||
#define OVERCLIP 1.001f
|
||||
|
||||
#define FALLING_THRESHOLD -900.0f //what vertical speed to start falling sound at
|
||||
|
||||
|
||||
// all of the locals will be zeroed before each
|
||||
// pmove, just to make damn sure we don't have
|
||||
// any differences when running on client or server
|
||||
typedef struct
|
||||
{
|
||||
vec3_t forward, right, up;
|
||||
float frametime;
|
||||
|
||||
int msec;
|
||||
|
||||
qboolean walking;
|
||||
qboolean groundPlane;
|
||||
qboolean ladder;
|
||||
trace_t groundTrace;
|
||||
|
||||
float impactSpeed;
|
||||
|
||||
vec3_t previous_origin;
|
||||
vec3_t previous_velocity;
|
||||
int previous_waterlevel;
|
||||
} pml_t;
|
||||
|
||||
extern pmove_t *pm;
|
||||
extern pml_t pml;
|
||||
|
||||
// movement parameters
|
||||
extern float pm_stopspeed;
|
||||
extern float pm_duckScale;
|
||||
extern float pm_swimScale;
|
||||
extern float pm_wadeScale;
|
||||
|
||||
extern float pm_accelerate;
|
||||
extern float pm_airaccelerate;
|
||||
extern float pm_wateraccelerate;
|
||||
extern float pm_flyaccelerate;
|
||||
|
||||
extern float pm_friction;
|
||||
extern float pm_waterfriction;
|
||||
extern float pm_flightfriction;
|
||||
|
||||
extern int c_pmove;
|
||||
|
||||
void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce );
|
||||
void PM_AddTouchEnt( int entityNum );
|
||||
void PM_AddEvent( int newEvent );
|
||||
|
||||
qboolean PM_SlideMove( qboolean gravity );
|
||||
void PM_StepEvent( vec3_t from, vec3_t to, vec3_t normal );
|
||||
qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive );
|
||||
qboolean PM_PredictStepMove( void );
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// bg_local.h -- local definitions for the bg (both games) files
|
||||
|
||||
#define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes
|
||||
|
||||
#define STEPSIZE 18
|
||||
|
||||
#define TIMER_LAND 130
|
||||
#define TIMER_GESTURE (34*66+50)
|
||||
#define TIMER_ATTACK 500 //nonsegmented models
|
||||
|
||||
#define OVERCLIP 1.001f
|
||||
|
||||
#define FALLING_THRESHOLD -900.0f //what vertical speed to start falling sound at
|
||||
|
||||
|
||||
// all of the locals will be zeroed before each
|
||||
// pmove, just to make damn sure we don't have
|
||||
// any differences when running on client or server
|
||||
typedef struct
|
||||
{
|
||||
vec3_t forward, right, up;
|
||||
float frametime;
|
||||
|
||||
int msec;
|
||||
|
||||
qboolean walking;
|
||||
qboolean groundPlane;
|
||||
qboolean ladder;
|
||||
trace_t groundTrace;
|
||||
|
||||
float impactSpeed;
|
||||
|
||||
vec3_t previous_origin;
|
||||
vec3_t previous_velocity;
|
||||
int previous_waterlevel;
|
||||
} pml_t;
|
||||
|
||||
extern pmove_t *pm;
|
||||
extern pml_t pml;
|
||||
|
||||
// movement parameters
|
||||
extern float pm_stopspeed;
|
||||
extern float pm_duckScale;
|
||||
extern float pm_swimScale;
|
||||
extern float pm_wadeScale;
|
||||
|
||||
extern float pm_accelerate;
|
||||
extern float pm_airaccelerate;
|
||||
extern float pm_wateraccelerate;
|
||||
extern float pm_flyaccelerate;
|
||||
|
||||
extern float pm_friction;
|
||||
extern float pm_waterfriction;
|
||||
extern float pm_flightfriction;
|
||||
|
||||
extern int c_pmove;
|
||||
|
||||
void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce );
|
||||
void PM_AddTouchEnt( int entityNum );
|
||||
void PM_AddEvent( int newEvent );
|
||||
|
||||
qboolean PM_SlideMove( qboolean gravity );
|
||||
void PM_StepEvent( vec3_t from, vec3_t to, vec3_t normal );
|
||||
qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive );
|
||||
qboolean PM_PredictStepMove( void );
|
||||
+416
-416
@@ -1,416 +1,416 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// bg_slidemove.c -- part of bg_pmove functionality
|
||||
|
||||
#include "../qcommon/q_shared.h"
|
||||
#include "bg_public.h"
|
||||
#include "bg_local.h"
|
||||
|
||||
/*
|
||||
|
||||
input: origin, velocity, bounds, groundPlane, trace function
|
||||
|
||||
output: origin, velocity, impacts, stairup boolean
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
==================
|
||||
PM_SlideMove
|
||||
|
||||
Returns qtrue if the velocity was clipped in some way
|
||||
==================
|
||||
*/
|
||||
#define MAX_CLIP_PLANES 5
|
||||
qboolean PM_SlideMove( qboolean gravity )
|
||||
{
|
||||
int bumpcount, numbumps;
|
||||
vec3_t dir;
|
||||
float d;
|
||||
int numplanes;
|
||||
vec3_t planes[MAX_CLIP_PLANES];
|
||||
vec3_t primal_velocity;
|
||||
vec3_t clipVelocity;
|
||||
int i, j, k;
|
||||
trace_t trace;
|
||||
vec3_t end;
|
||||
float time_left;
|
||||
float into;
|
||||
vec3_t endVelocity;
|
||||
vec3_t endClipVelocity;
|
||||
|
||||
numbumps = 4;
|
||||
|
||||
VectorCopy( pm->ps->velocity, primal_velocity );
|
||||
|
||||
if( gravity )
|
||||
{
|
||||
VectorCopy( pm->ps->velocity, endVelocity );
|
||||
endVelocity[ 2 ] -= pm->ps->gravity * pml.frametime;
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
time_left = pml.frametime;
|
||||
|
||||
// never turn against the ground plane
|
||||
if( pml.groundPlane )
|
||||
{
|
||||
numplanes = 1;
|
||||
VectorCopy( pml.groundTrace.plane.normal, planes[ 0 ] );
|
||||
}
|
||||
else
|
||||
numplanes = 0;
|
||||
|
||||
// never turn against original velocity
|
||||
VectorNormalize2( pm->ps->velocity, planes[ numplanes ] );
|
||||
numplanes++;
|
||||
|
||||
for( bumpcount = 0; bumpcount < numbumps; bumpcount++ )
|
||||
{
|
||||
// calculate position we are trying to move to
|
||||
VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );
|
||||
|
||||
// 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
|
||||
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 == 1 )
|
||||
break; // moved the entire distance
|
||||
|
||||
// save entity for contact
|
||||
PM_AddTouchEnt( trace.entityNum );
|
||||
|
||||
time_left -= time_left * trace.fraction;
|
||||
|
||||
if( numplanes >= MAX_CLIP_PLANES )
|
||||
{
|
||||
// this shouldn't really happen
|
||||
VectorClear( pm->ps->velocity );
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
//
|
||||
// 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 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( i < numplanes )
|
||||
continue;
|
||||
|
||||
VectorCopy( trace.plane.normal, planes[ numplanes ] );
|
||||
numplanes++;
|
||||
|
||||
//
|
||||
// modify velocity so it parallels all of the clip planes
|
||||
//
|
||||
|
||||
// find a plane that it enters
|
||||
for( i = 0; i < numplanes; i++ )
|
||||
{
|
||||
into = DotProduct( pm->ps->velocity, planes[ i ] );
|
||||
if( into >= 0.1 )
|
||||
continue; // move doesn't interact with the plane
|
||||
|
||||
// see how hard we are hitting things
|
||||
if( -into > pml.impactSpeed )
|
||||
pml.impactSpeed = -into;
|
||||
|
||||
// slide along the plane
|
||||
PM_ClipVelocity( pm->ps->velocity, planes[ i ], clipVelocity, OVERCLIP );
|
||||
|
||||
// slide along the plane
|
||||
PM_ClipVelocity( endVelocity, planes[ i ], endClipVelocity, OVERCLIP );
|
||||
|
||||
// see if there is a second plane that the new move enters
|
||||
for( j = 0; j < numplanes; j++ )
|
||||
{
|
||||
if( j == i )
|
||||
continue;
|
||||
|
||||
if( DotProduct( clipVelocity, planes[ j ] ) >= 0.1 )
|
||||
continue; // move doesn't interact with the plane
|
||||
|
||||
// try clipping the move to the plane
|
||||
PM_ClipVelocity( clipVelocity, planes[ j ], clipVelocity, OVERCLIP );
|
||||
PM_ClipVelocity( endClipVelocity, planes[ j ], endClipVelocity, OVERCLIP );
|
||||
|
||||
// see if it goes back into the first clip plane
|
||||
if( DotProduct( clipVelocity, planes[ i ] ) >= 0 )
|
||||
continue;
|
||||
|
||||
// slide the original velocity along the crease
|
||||
CrossProduct( planes[ i ], planes[ j ], dir );
|
||||
VectorNormalize( dir );
|
||||
d = DotProduct( dir, pm->ps->velocity );
|
||||
VectorScale( dir, d, clipVelocity );
|
||||
|
||||
CrossProduct( planes[ i ], planes[ j ], dir);
|
||||
VectorNormalize( dir );
|
||||
d = DotProduct( dir, endVelocity );
|
||||
VectorScale( dir, d, endClipVelocity );
|
||||
|
||||
// see if there is a third plane the the new move enters
|
||||
for( k = 0; k < numplanes; k++ )
|
||||
{
|
||||
if( k == i || k == j )
|
||||
continue;
|
||||
|
||||
if( DotProduct( clipVelocity, planes[ k ] ) >= 0.1 )
|
||||
continue; // move doesn't interact with the plane
|
||||
|
||||
// stop dead at a tripple plane interaction
|
||||
VectorClear( pm->ps->velocity );
|
||||
return qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have fixed all interactions, try another move
|
||||
VectorCopy( clipVelocity, pm->ps->velocity );
|
||||
VectorCopy( endClipVelocity, endVelocity );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( gravity )
|
||||
VectorCopy( endVelocity, pm->ps->velocity );
|
||||
|
||||
// don't change velocity if in a timer (FIXME: is this correct?)
|
||||
if( pm->ps->pm_time )
|
||||
VectorCopy( primal_velocity, pm->ps->velocity );
|
||||
|
||||
return ( bumpcount != 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
PM_StepEvent
|
||||
==================
|
||||
*/
|
||||
void PM_StepEvent( vec3_t from, vec3_t to, vec3_t normal )
|
||||
{
|
||||
float size;
|
||||
vec3_t delta, dNormal;
|
||||
|
||||
VectorSubtract( from, to, delta );
|
||||
VectorCopy( delta, dNormal );
|
||||
VectorNormalize( dNormal );
|
||||
|
||||
size = DotProduct( normal, dNormal ) * VectorLength( delta );
|
||||
|
||||
if( size > 0.0f )
|
||||
{
|
||||
if( size > 2.0f )
|
||||
{
|
||||
if( size < 7.0f )
|
||||
PM_AddEvent( EV_STEPDN_4 );
|
||||
else if( size < 11.0f )
|
||||
PM_AddEvent( EV_STEPDN_8 );
|
||||
else if( size < 15.0f )
|
||||
PM_AddEvent( EV_STEPDN_12 );
|
||||
else
|
||||
PM_AddEvent( EV_STEPDN_16 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size = fabs( size );
|
||||
|
||||
if( size > 2.0f )
|
||||
{
|
||||
if( size < 7.0f )
|
||||
PM_AddEvent( EV_STEP_4 );
|
||||
else if( size < 11.0f )
|
||||
PM_AddEvent( EV_STEP_8 );
|
||||
else if( size < 15.0f )
|
||||
PM_AddEvent( EV_STEP_12 );
|
||||
else
|
||||
PM_AddEvent( EV_STEP_16 );
|
||||
}
|
||||
}
|
||||
|
||||
if( pm->debugLevel )
|
||||
Com_Printf( "%i:stepped\n", c_pmove );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
PM_StepSlideMove
|
||||
==================
|
||||
*/
|
||||
qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive )
|
||||
{
|
||||
vec3_t start_o, start_v;
|
||||
vec3_t down_o, down_v;
|
||||
trace_t trace;
|
||||
vec3_t normal;
|
||||
vec3_t step_v, step_vNormal;
|
||||
vec3_t up, down;
|
||||
float stepSize;
|
||||
qboolean stepped = qfalse;
|
||||
|
||||
if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
|
||||
{
|
||||
if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
|
||||
VectorSet( normal, 0.0f, 0.0f, -1.0f );
|
||||
else
|
||||
VectorCopy( pm->ps->grapplePoint, normal );
|
||||
}
|
||||
else
|
||||
VectorSet( normal, 0.0f, 0.0f, 1.0f );
|
||||
|
||||
VectorCopy( pm->ps->origin, start_o );
|
||||
VectorCopy( pm->ps->velocity, start_v );
|
||||
|
||||
if( PM_SlideMove( gravity ) == 0 )
|
||||
{
|
||||
VectorCopy( start_o, down );
|
||||
VectorMA( down, -STEPSIZE, normal, down );
|
||||
pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );
|
||||
|
||||
//we can step down
|
||||
if( trace.fraction > 0.01f && trace.fraction < 1.0f &&
|
||||
!trace.allsolid && pml.groundPlane != qfalse )
|
||||
{
|
||||
if( pm->debugLevel )
|
||||
Com_Printf( "%d: step down\n", c_pmove );
|
||||
|
||||
stepped = qtrue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy( start_o, down );
|
||||
VectorMA( down, -STEPSIZE, normal, down );
|
||||
pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );
|
||||
// never step up when you still have up velocity
|
||||
if( DotProduct( trace.plane.normal, pm->ps->velocity ) > 0.0f &&
|
||||
( trace.fraction == 1.0f || DotProduct( trace.plane.normal, normal ) < 0.7f ) )
|
||||
{
|
||||
return stepped;
|
||||
}
|
||||
|
||||
VectorCopy( pm->ps->origin, down_o );
|
||||
VectorCopy( pm->ps->velocity, down_v );
|
||||
|
||||
VectorCopy( start_o, up );
|
||||
VectorMA( up, STEPSIZE, normal, up );
|
||||
|
||||
// test the player position if they were a stepheight higher
|
||||
pm->trace( &trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask );
|
||||
if( trace.allsolid )
|
||||
{
|
||||
if( pm->debugLevel )
|
||||
Com_Printf( "%i:bend can't step\n", c_pmove );
|
||||
|
||||
return stepped; // can't step up
|
||||
}
|
||||
|
||||
VectorSubtract( trace.endpos, start_o, step_v );
|
||||
VectorCopy( step_v, step_vNormal );
|
||||
VectorNormalize( step_vNormal );
|
||||
|
||||
stepSize = DotProduct( normal, step_vNormal ) * VectorLength( step_v );
|
||||
// try slidemove from this position
|
||||
VectorCopy( trace.endpos, pm->ps->origin );
|
||||
VectorCopy( start_v, pm->ps->velocity );
|
||||
|
||||
if( PM_SlideMove( gravity ) == 0 )
|
||||
{
|
||||
if( pm->debugLevel )
|
||||
Com_Printf( "%d: step up\n", c_pmove );
|
||||
|
||||
stepped = qtrue;
|
||||
}
|
||||
|
||||
// push down the final amount
|
||||
VectorCopy( pm->ps->origin, down );
|
||||
VectorMA( down, -stepSize, normal, down );
|
||||
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.fraction < 1.0f )
|
||||
PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
|
||||
}
|
||||
|
||||
if( !predictive && stepped )
|
||||
PM_StepEvent( start_o, pm->ps->origin, normal );
|
||||
|
||||
return stepped;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
PM_PredictStepMove
|
||||
==================
|
||||
*/
|
||||
qboolean PM_PredictStepMove( void )
|
||||
{
|
||||
vec3_t velocity, origin;
|
||||
float impactSpeed;
|
||||
qboolean stepped = qfalse;
|
||||
|
||||
VectorCopy( pm->ps->velocity, velocity );
|
||||
VectorCopy( pm->ps->origin, origin );
|
||||
impactSpeed = pml.impactSpeed;
|
||||
|
||||
if( PM_StepSlideMove( qfalse, qtrue ) )
|
||||
stepped = qtrue;
|
||||
|
||||
VectorCopy( velocity, pm->ps->velocity );
|
||||
VectorCopy( origin, pm->ps->origin );
|
||||
pml.impactSpeed = impactSpeed;
|
||||
|
||||
return stepped;
|
||||
}
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// bg_slidemove.c -- part of bg_pmove functionality
|
||||
|
||||
#include "../qcommon/q_shared.h"
|
||||
#include "bg_public.h"
|
||||
#include "bg_local.h"
|
||||
|
||||
/*
|
||||
|
||||
input: origin, velocity, bounds, groundPlane, trace function
|
||||
|
||||
output: origin, velocity, impacts, stairup boolean
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
==================
|
||||
PM_SlideMove
|
||||
|
||||
Returns qtrue if the velocity was clipped in some way
|
||||
==================
|
||||
*/
|
||||
#define MAX_CLIP_PLANES 5
|
||||
qboolean PM_SlideMove( qboolean gravity )
|
||||
{
|
||||
int bumpcount, numbumps;
|
||||
vec3_t dir;
|
||||
float d;
|
||||
int numplanes;
|
||||
vec3_t planes[MAX_CLIP_PLANES];
|
||||
vec3_t primal_velocity;
|
||||
vec3_t clipVelocity;
|
||||
int i, j, k;
|
||||
trace_t trace;
|
||||
vec3_t end;
|
||||
float time_left;
|
||||
float into;
|
||||
vec3_t endVelocity;
|
||||
vec3_t endClipVelocity;
|
||||
|
||||
numbumps = 4;
|
||||
|
||||
VectorCopy( pm->ps->velocity, primal_velocity );
|
||||
|
||||
if( gravity )
|
||||
{
|
||||
VectorCopy( pm->ps->velocity, endVelocity );
|
||||
endVelocity[ 2 ] -= pm->ps->gravity * pml.frametime;
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
time_left = pml.frametime;
|
||||
|
||||
// never turn against the ground plane
|
||||
if( pml.groundPlane )
|
||||
{
|
||||
numplanes = 1;
|
||||
VectorCopy( pml.groundTrace.plane.normal, planes[ 0 ] );
|
||||
}
|
||||
else
|
||||
numplanes = 0;
|
||||
|
||||
// never turn against original velocity
|
||||
VectorNormalize2( pm->ps->velocity, planes[ numplanes ] );
|
||||
numplanes++;
|
||||
|
||||
for( bumpcount = 0; bumpcount < numbumps; bumpcount++ )
|
||||
{
|
||||
// calculate position we are trying to move to
|
||||
VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end );
|
||||
|
||||
// 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
|
||||
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 == 1 )
|
||||
break; // moved the entire distance
|
||||
|
||||
// save entity for contact
|
||||
PM_AddTouchEnt( trace.entityNum );
|
||||
|
||||
time_left -= time_left * trace.fraction;
|
||||
|
||||
if( numplanes >= MAX_CLIP_PLANES )
|
||||
{
|
||||
// this shouldn't really happen
|
||||
VectorClear( pm->ps->velocity );
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
//
|
||||
// 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 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( i < numplanes )
|
||||
continue;
|
||||
|
||||
VectorCopy( trace.plane.normal, planes[ numplanes ] );
|
||||
numplanes++;
|
||||
|
||||
//
|
||||
// modify velocity so it parallels all of the clip planes
|
||||
//
|
||||
|
||||
// find a plane that it enters
|
||||
for( i = 0; i < numplanes; i++ )
|
||||
{
|
||||
into = DotProduct( pm->ps->velocity, planes[ i ] );
|
||||
if( into >= 0.1 )
|
||||
continue; // move doesn't interact with the plane
|
||||
|
||||
// see how hard we are hitting things
|
||||
if( -into > pml.impactSpeed )
|
||||
pml.impactSpeed = -into;
|
||||
|
||||
// slide along the plane
|
||||
PM_ClipVelocity( pm->ps->velocity, planes[ i ], clipVelocity, OVERCLIP );
|
||||
|
||||
// slide along the plane
|
||||
PM_ClipVelocity( endVelocity, planes[ i ], endClipVelocity, OVERCLIP );
|
||||
|
||||
// see if there is a second plane that the new move enters
|
||||
for( j = 0; j < numplanes; j++ )
|
||||
{
|
||||
if( j == i )
|
||||
continue;
|
||||
|
||||
if( DotProduct( clipVelocity, planes[ j ] ) >= 0.1 )
|
||||
continue; // move doesn't interact with the plane
|
||||
|
||||
// try clipping the move to the plane
|
||||
PM_ClipVelocity( clipVelocity, planes[ j ], clipVelocity, OVERCLIP );
|
||||
PM_ClipVelocity( endClipVelocity, planes[ j ], endClipVelocity, OVERCLIP );
|
||||
|
||||
// see if it goes back into the first clip plane
|
||||
if( DotProduct( clipVelocity, planes[ i ] ) >= 0 )
|
||||
continue;
|
||||
|
||||
// slide the original velocity along the crease
|
||||
CrossProduct( planes[ i ], planes[ j ], dir );
|
||||
VectorNormalize( dir );
|
||||
d = DotProduct( dir, pm->ps->velocity );
|
||||
VectorScale( dir, d, clipVelocity );
|
||||
|
||||
CrossProduct( planes[ i ], planes[ j ], dir);
|
||||
VectorNormalize( dir );
|
||||
d = DotProduct( dir, endVelocity );
|
||||
VectorScale( dir, d, endClipVelocity );
|
||||
|
||||
// see if there is a third plane the the new move enters
|
||||
for( k = 0; k < numplanes; k++ )
|
||||
{
|
||||
if( k == i || k == j )
|
||||
continue;
|
||||
|
||||
if( DotProduct( clipVelocity, planes[ k ] ) >= 0.1 )
|
||||
continue; // move doesn't interact with the plane
|
||||
|
||||
// stop dead at a tripple plane interaction
|
||||
VectorClear( pm->ps->velocity );
|
||||
return qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have fixed all interactions, try another move
|
||||
VectorCopy( clipVelocity, pm->ps->velocity );
|
||||
VectorCopy( endClipVelocity, endVelocity );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( gravity )
|
||||
VectorCopy( endVelocity, pm->ps->velocity );
|
||||
|
||||
// don't change velocity if in a timer (FIXME: is this correct?)
|
||||
if( pm->ps->pm_time )
|
||||
VectorCopy( primal_velocity, pm->ps->velocity );
|
||||
|
||||
return ( bumpcount != 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
PM_StepEvent
|
||||
==================
|
||||
*/
|
||||
void PM_StepEvent( vec3_t from, vec3_t to, vec3_t normal )
|
||||
{
|
||||
float size;
|
||||
vec3_t delta, dNormal;
|
||||
|
||||
VectorSubtract( from, to, delta );
|
||||
VectorCopy( delta, dNormal );
|
||||
VectorNormalize( dNormal );
|
||||
|
||||
size = DotProduct( normal, dNormal ) * VectorLength( delta );
|
||||
|
||||
if( size > 0.0f )
|
||||
{
|
||||
if( size > 2.0f )
|
||||
{
|
||||
if( size < 7.0f )
|
||||
PM_AddEvent( EV_STEPDN_4 );
|
||||
else if( size < 11.0f )
|
||||
PM_AddEvent( EV_STEPDN_8 );
|
||||
else if( size < 15.0f )
|
||||
PM_AddEvent( EV_STEPDN_12 );
|
||||
else
|
||||
PM_AddEvent( EV_STEPDN_16 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size = fabs( size );
|
||||
|
||||
if( size > 2.0f )
|
||||
{
|
||||
if( size < 7.0f )
|
||||
PM_AddEvent( EV_STEP_4 );
|
||||
else if( size < 11.0f )
|
||||
PM_AddEvent( EV_STEP_8 );
|
||||
else if( size < 15.0f )
|
||||
PM_AddEvent( EV_STEP_12 );
|
||||
else
|
||||
PM_AddEvent( EV_STEP_16 );
|
||||
}
|
||||
}
|
||||
|
||||
if( pm->debugLevel )
|
||||
Com_Printf( "%i:stepped\n", c_pmove );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
PM_StepSlideMove
|
||||
==================
|
||||
*/
|
||||
qboolean PM_StepSlideMove( qboolean gravity, qboolean predictive )
|
||||
{
|
||||
vec3_t start_o, start_v;
|
||||
vec3_t down_o, down_v;
|
||||
trace_t trace;
|
||||
vec3_t normal;
|
||||
vec3_t step_v, step_vNormal;
|
||||
vec3_t up, down;
|
||||
float stepSize;
|
||||
qboolean stepped = qfalse;
|
||||
|
||||
if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING )
|
||||
{
|
||||
if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING )
|
||||
VectorSet( normal, 0.0f, 0.0f, -1.0f );
|
||||
else
|
||||
VectorCopy( pm->ps->grapplePoint, normal );
|
||||
}
|
||||
else
|
||||
VectorSet( normal, 0.0f, 0.0f, 1.0f );
|
||||
|
||||
VectorCopy( pm->ps->origin, start_o );
|
||||
VectorCopy( pm->ps->velocity, start_v );
|
||||
|
||||
if( PM_SlideMove( gravity ) == 0 )
|
||||
{
|
||||
VectorCopy( start_o, down );
|
||||
VectorMA( down, -STEPSIZE, normal, down );
|
||||
pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );
|
||||
|
||||
//we can step down
|
||||
if( trace.fraction > 0.01f && trace.fraction < 1.0f &&
|
||||
!trace.allsolid && pml.groundPlane != qfalse )
|
||||
{
|
||||
if( pm->debugLevel )
|
||||
Com_Printf( "%d: step down\n", c_pmove );
|
||||
|
||||
stepped = qtrue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy( start_o, down );
|
||||
VectorMA( down, -STEPSIZE, normal, down );
|
||||
pm->trace( &trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask );
|
||||
// never step up when you still have up velocity
|
||||
if( DotProduct( trace.plane.normal, pm->ps->velocity ) > 0.0f &&
|
||||
( trace.fraction == 1.0f || DotProduct( trace.plane.normal, normal ) < 0.7f ) )
|
||||
{
|
||||
return stepped;
|
||||
}
|
||||
|
||||
VectorCopy( pm->ps->origin, down_o );
|
||||
VectorCopy( pm->ps->velocity, down_v );
|
||||
|
||||
VectorCopy( start_o, up );
|
||||
VectorMA( up, STEPSIZE, normal, up );
|
||||
|
||||
// test the player position if they were a stepheight higher
|
||||
pm->trace( &trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask );
|
||||
if( trace.allsolid )
|
||||
{
|
||||
if( pm->debugLevel )
|
||||
Com_Printf( "%i:bend can't step\n", c_pmove );
|
||||
|
||||
return stepped; // can't step up
|
||||
}
|
||||
|
||||
VectorSubtract( trace.endpos, start_o, step_v );
|
||||
VectorCopy( step_v, step_vNormal );
|
||||
VectorNormalize( step_vNormal );
|
||||
|
||||
stepSize = DotProduct( normal, step_vNormal ) * VectorLength( step_v );
|
||||
// try slidemove from this position
|
||||
VectorCopy( trace.endpos, pm->ps->origin );
|
||||
VectorCopy( start_v, pm->ps->velocity );
|
||||
|
||||
if( PM_SlideMove( gravity ) == 0 )
|
||||
{
|
||||
if( pm->debugLevel )
|
||||
Com_Printf( "%d: step up\n", c_pmove );
|
||||
|
||||
stepped = qtrue;
|
||||
}
|
||||
|
||||
// push down the final amount
|
||||
VectorCopy( pm->ps->origin, down );
|
||||
VectorMA( down, -stepSize, normal, down );
|
||||
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.fraction < 1.0f )
|
||||
PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP );
|
||||
}
|
||||
|
||||
if( !predictive && stepped )
|
||||
PM_StepEvent( start_o, pm->ps->origin, normal );
|
||||
|
||||
return stepped;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
PM_PredictStepMove
|
||||
==================
|
||||
*/
|
||||
qboolean PM_PredictStepMove( void )
|
||||
{
|
||||
vec3_t velocity, origin;
|
||||
float impactSpeed;
|
||||
qboolean stepped = qfalse;
|
||||
|
||||
VectorCopy( pm->ps->velocity, velocity );
|
||||
VectorCopy( pm->ps->origin, origin );
|
||||
impactSpeed = pml.impactSpeed;
|
||||
|
||||
if( PM_StepSlideMove( qfalse, qtrue ) )
|
||||
stepped = qtrue;
|
||||
|
||||
VectorCopy( velocity, pm->ps->velocity );
|
||||
VectorCopy( origin, pm->ps->origin );
|
||||
pml.impactSpeed = impactSpeed;
|
||||
|
||||
return stepped;
|
||||
}
|
||||
+743
-743
File diff suppressed because it is too large.
Load diff
+216
-216
@@ -1,216 +1,216 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
#define POOLSIZE ( 1024 * 1024 )
|
||||
#define FREEMEMCOOKIE ((int)0xDEADBE3F) // Any unlikely to be used value
|
||||
#define ROUNDBITS 31 // Round to 32 bytes
|
||||
|
||||
struct freememnode
|
||||
{
|
||||
// Size of ROUNDBITS
|
||||
int cookie, size; // Size includes node (obviously)
|
||||
struct freememnode *prev, *next;
|
||||
};
|
||||
|
||||
static char memoryPool[POOLSIZE];
|
||||
static struct freememnode *freehead;
|
||||
static int freemem;
|
||||
|
||||
void *G_Alloc( int size )
|
||||
{
|
||||
// Find a free block and allocate.
|
||||
// Does two passes, attempts to fill same-sized free slot first.
|
||||
|
||||
struct freememnode *fmn, *prev, *next, *smallest;
|
||||
int allocsize, smallestsize;
|
||||
char *endptr;
|
||||
int *ptr;
|
||||
|
||||
allocsize = ( size + sizeof(int) + ROUNDBITS ) & ~ROUNDBITS; // Round to 32-byte boundary
|
||||
ptr = NULL;
|
||||
|
||||
smallest = NULL;
|
||||
smallestsize = POOLSIZE + 1; // Guaranteed not to miss any slots :)
|
||||
for( fmn = freehead; fmn; fmn = fmn->next )
|
||||
{
|
||||
if( fmn->cookie != FREEMEMCOOKIE )
|
||||
G_Error( "G_Alloc: Memory corruption detected!\n" );
|
||||
|
||||
if( fmn->size >= allocsize )
|
||||
{
|
||||
// We've got a block
|
||||
if( fmn->size == allocsize )
|
||||
{
|
||||
// Same size, just remove
|
||||
|
||||
prev = fmn->prev;
|
||||
next = fmn->next;
|
||||
if( prev )
|
||||
prev->next = next; // Point previous node to next
|
||||
if( next )
|
||||
next->prev = prev; // Point next node to previous
|
||||
if( fmn == freehead )
|
||||
freehead = next; // Set head pointer to next
|
||||
ptr = (int *) fmn;
|
||||
break; // Stop the loop, this is fine
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep track of the smallest free slot
|
||||
if( fmn->size < smallestsize )
|
||||
{
|
||||
smallest = fmn;
|
||||
smallestsize = fmn->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !ptr && smallest )
|
||||
{
|
||||
// We found a slot big enough
|
||||
smallest->size -= allocsize;
|
||||
endptr = (char *) smallest + smallest->size;
|
||||
ptr = (int *) endptr;
|
||||
}
|
||||
|
||||
if( ptr )
|
||||
{
|
||||
freemem -= allocsize;
|
||||
if( g_debugAlloc.integer )
|
||||
G_Printf( "G_Alloc of %i bytes (%i left)\n", allocsize, freemem );
|
||||
memset( ptr, 0, allocsize );
|
||||
*ptr++ = allocsize; // Store a copy of size for deallocation
|
||||
return( (void *) ptr );
|
||||
}
|
||||
|
||||
G_Error( "G_Alloc: failed on allocation of %i bytes\n", size );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
void G_Free( void *ptr )
|
||||
{
|
||||
// Release allocated memory, add it to the free list.
|
||||
|
||||
struct freememnode *fmn;
|
||||
char *freeend;
|
||||
int *freeptr;
|
||||
|
||||
freeptr = ptr;
|
||||
freeptr--;
|
||||
|
||||
freemem += *freeptr;
|
||||
if( g_debugAlloc.integer )
|
||||
G_Printf( "G_Free of %i bytes (%i left)\n", *freeptr, freemem );
|
||||
|
||||
for( fmn = freehead; fmn; fmn = fmn->next )
|
||||
{
|
||||
freeend = ((char *) fmn) + fmn->size;
|
||||
if( freeend == (char *) freeptr )
|
||||
{
|
||||
// Released block can be merged to an existing node
|
||||
|
||||
fmn->size += *freeptr; // Add size of node.
|
||||
return;
|
||||
}
|
||||
}
|
||||
// No merging, add to head of list
|
||||
|
||||
fmn = (struct freememnode *) freeptr;
|
||||
fmn->size = *freeptr; // Set this first to avoid corrupting *freeptr
|
||||
fmn->cookie = FREEMEMCOOKIE;
|
||||
fmn->prev = NULL;
|
||||
fmn->next = freehead;
|
||||
freehead->prev = fmn;
|
||||
freehead = fmn;
|
||||
}
|
||||
|
||||
void G_InitMemory( void )
|
||||
{
|
||||
// Set up the initial node
|
||||
|
||||
freehead = (struct freememnode *)memoryPool;
|
||||
freehead->cookie = FREEMEMCOOKIE;
|
||||
freehead->size = POOLSIZE;
|
||||
freehead->next = NULL;
|
||||
freehead->prev = NULL;
|
||||
freemem = sizeof( memoryPool );
|
||||
}
|
||||
|
||||
void G_DefragmentMemory( void )
|
||||
{
|
||||
// If there's a frenzy of deallocation and we want to
|
||||
// allocate something big, this is useful. Otherwise...
|
||||
// not much use.
|
||||
|
||||
struct freememnode *startfmn, *endfmn, *fmn;
|
||||
|
||||
for( startfmn = freehead; startfmn; )
|
||||
{
|
||||
endfmn = (struct freememnode *)(((char *) startfmn) + startfmn->size);
|
||||
for( fmn = freehead; fmn; )
|
||||
{
|
||||
if( fmn->cookie != FREEMEMCOOKIE )
|
||||
G_Error( "G_DefragmentMemory: Memory corruption detected!\n" );
|
||||
|
||||
if( fmn == endfmn )
|
||||
{
|
||||
// We can add fmn onto startfmn.
|
||||
|
||||
if( fmn->prev )
|
||||
fmn->prev->next = fmn->next;
|
||||
if( fmn->next )
|
||||
{
|
||||
if( !(fmn->next->prev = fmn->prev) )
|
||||
freehead = fmn->next; // We're removing the head node
|
||||
}
|
||||
startfmn->size += fmn->size;
|
||||
memset( fmn, 0, sizeof(struct freememnode) ); // A redundant call, really.
|
||||
|
||||
startfmn = freehead;
|
||||
endfmn = fmn = NULL; // Break out of current loop
|
||||
}
|
||||
else
|
||||
fmn = fmn->next;
|
||||
}
|
||||
|
||||
if( endfmn )
|
||||
startfmn = startfmn->next; // endfmn acts as a 'restart' flag here
|
||||
}
|
||||
}
|
||||
|
||||
void Svcmd_GameMem_f( void )
|
||||
{
|
||||
// Give a breakdown of memory
|
||||
|
||||
struct freememnode *fmn;
|
||||
|
||||
G_Printf( "Game memory status: %i out of %i bytes allocated\n", POOLSIZE - freemem, POOLSIZE );
|
||||
|
||||
for( fmn = freehead; fmn; fmn = fmn->next )
|
||||
G_Printf( " %dd: %d bytes free.\n", fmn, fmn->size );
|
||||
G_Printf( "Status complete.\n" );
|
||||
}
|
||||
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
#define POOLSIZE ( 1024 * 1024 )
|
||||
#define FREEMEMCOOKIE ((int)0xDEADBE3F) // Any unlikely to be used value
|
||||
#define ROUNDBITS 31 // Round to 32 bytes
|
||||
|
||||
struct freememnode
|
||||
{
|
||||
// Size of ROUNDBITS
|
||||
int cookie, size; // Size includes node (obviously)
|
||||
struct freememnode *prev, *next;
|
||||
};
|
||||
|
||||
static char memoryPool[POOLSIZE];
|
||||
static struct freememnode *freehead;
|
||||
static int freemem;
|
||||
|
||||
void *G_Alloc( int size )
|
||||
{
|
||||
// Find a free block and allocate.
|
||||
// Does two passes, attempts to fill same-sized free slot first.
|
||||
|
||||
struct freememnode *fmn, *prev, *next, *smallest;
|
||||
int allocsize, smallestsize;
|
||||
char *endptr;
|
||||
int *ptr;
|
||||
|
||||
allocsize = ( size + sizeof(int) + ROUNDBITS ) & ~ROUNDBITS; // Round to 32-byte boundary
|
||||
ptr = NULL;
|
||||
|
||||
smallest = NULL;
|
||||
smallestsize = POOLSIZE + 1; // Guaranteed not to miss any slots :)
|
||||
for( fmn = freehead; fmn; fmn = fmn->next )
|
||||
{
|
||||
if( fmn->cookie != FREEMEMCOOKIE )
|
||||
G_Error( "G_Alloc: Memory corruption detected!\n" );
|
||||
|
||||
if( fmn->size >= allocsize )
|
||||
{
|
||||
// We've got a block
|
||||
if( fmn->size == allocsize )
|
||||
{
|
||||
// Same size, just remove
|
||||
|
||||
prev = fmn->prev;
|
||||
next = fmn->next;
|
||||
if( prev )
|
||||
prev->next = next; // Point previous node to next
|
||||
if( next )
|
||||
next->prev = prev; // Point next node to previous
|
||||
if( fmn == freehead )
|
||||
freehead = next; // Set head pointer to next
|
||||
ptr = (int *) fmn;
|
||||
break; // Stop the loop, this is fine
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep track of the smallest free slot
|
||||
if( fmn->size < smallestsize )
|
||||
{
|
||||
smallest = fmn;
|
||||
smallestsize = fmn->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !ptr && smallest )
|
||||
{
|
||||
// We found a slot big enough
|
||||
smallest->size -= allocsize;
|
||||
endptr = (char *) smallest + smallest->size;
|
||||
ptr = (int *) endptr;
|
||||
}
|
||||
|
||||
if( ptr )
|
||||
{
|
||||
freemem -= allocsize;
|
||||
if( g_debugAlloc.integer )
|
||||
G_Printf( "G_Alloc of %i bytes (%i left)\n", allocsize, freemem );
|
||||
memset( ptr, 0, allocsize );
|
||||
*ptr++ = allocsize; // Store a copy of size for deallocation
|
||||
return( (void *) ptr );
|
||||
}
|
||||
|
||||
G_Error( "G_Alloc: failed on allocation of %i bytes\n", size );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
void G_Free( void *ptr )
|
||||
{
|
||||
// Release allocated memory, add it to the free list.
|
||||
|
||||
struct freememnode *fmn;
|
||||
char *freeend;
|
||||
int *freeptr;
|
||||
|
||||
freeptr = ptr;
|
||||
freeptr--;
|
||||
|
||||
freemem += *freeptr;
|
||||
if( g_debugAlloc.integer )
|
||||
G_Printf( "G_Free of %i bytes (%i left)\n", *freeptr, freemem );
|
||||
|
||||
for( fmn = freehead; fmn; fmn = fmn->next )
|
||||
{
|
||||
freeend = ((char *) fmn) + fmn->size;
|
||||
if( freeend == (char *) freeptr )
|
||||
{
|
||||
// Released block can be merged to an existing node
|
||||
|
||||
fmn->size += *freeptr; // Add size of node.
|
||||
return;
|
||||
}
|
||||
}
|
||||
// No merging, add to head of list
|
||||
|
||||
fmn = (struct freememnode *) freeptr;
|
||||
fmn->size = *freeptr; // Set this first to avoid corrupting *freeptr
|
||||
fmn->cookie = FREEMEMCOOKIE;
|
||||
fmn->prev = NULL;
|
||||
fmn->next = freehead;
|
||||
freehead->prev = fmn;
|
||||
freehead = fmn;
|
||||
}
|
||||
|
||||
void G_InitMemory( void )
|
||||
{
|
||||
// Set up the initial node
|
||||
|
||||
freehead = (struct freememnode *)memoryPool;
|
||||
freehead->cookie = FREEMEMCOOKIE;
|
||||
freehead->size = POOLSIZE;
|
||||
freehead->next = NULL;
|
||||
freehead->prev = NULL;
|
||||
freemem = sizeof( memoryPool );
|
||||
}
|
||||
|
||||
void G_DefragmentMemory( void )
|
||||
{
|
||||
// If there's a frenzy of deallocation and we want to
|
||||
// allocate something big, this is useful. Otherwise...
|
||||
// not much use.
|
||||
|
||||
struct freememnode *startfmn, *endfmn, *fmn;
|
||||
|
||||
for( startfmn = freehead; startfmn; )
|
||||
{
|
||||
endfmn = (struct freememnode *)(((char *) startfmn) + startfmn->size);
|
||||
for( fmn = freehead; fmn; )
|
||||
{
|
||||
if( fmn->cookie != FREEMEMCOOKIE )
|
||||
G_Error( "G_DefragmentMemory: Memory corruption detected!\n" );
|
||||
|
||||
if( fmn == endfmn )
|
||||
{
|
||||
// We can add fmn onto startfmn.
|
||||
|
||||
if( fmn->prev )
|
||||
fmn->prev->next = fmn->next;
|
||||
if( fmn->next )
|
||||
{
|
||||
if( !(fmn->next->prev = fmn->prev) )
|
||||
freehead = fmn->next; // We're removing the head node
|
||||
}
|
||||
startfmn->size += fmn->size;
|
||||
memset( fmn, 0, sizeof(struct freememnode) ); // A redundant call, really.
|
||||
|
||||
startfmn = freehead;
|
||||
endfmn = fmn = NULL; // Break out of current loop
|
||||
}
|
||||
else
|
||||
fmn = fmn->next;
|
||||
}
|
||||
|
||||
if( endfmn )
|
||||
startfmn = startfmn->next; // endfmn acts as a 'restart' flag here
|
||||
}
|
||||
}
|
||||
|
||||
void Svcmd_GameMem_f( void )
|
||||
{
|
||||
// Give a breakdown of memory
|
||||
|
||||
struct freememnode *fmn;
|
||||
|
||||
G_Printf( "Game memory status: %i out of %i bytes allocated\n", POOLSIZE - freemem, POOLSIZE );
|
||||
|
||||
for( fmn = freehead; fmn; fmn = fmn->next )
|
||||
G_Printf( " %dd: %d bytes free.\n", fmn, fmn->size );
|
||||
G_Printf( "Status complete.\n" );
|
||||
}
|
||||
|
||||
+436
-436
@@ -1,436 +1,436 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
|
||||
/*QUAKED func_group (0 0 0) ?
|
||||
Used to group brushes together just for editor convenience. They are turned into normal brushes by the utilities.
|
||||
*/
|
||||
|
||||
|
||||
/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
|
||||
Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
|
||||
*/
|
||||
void SP_info_null( gentity_t *self )
|
||||
{
|
||||
G_FreeEntity( self );
|
||||
}
|
||||
|
||||
|
||||
/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
|
||||
Used as a positional target for in-game calculation, like jumppad targets.
|
||||
target_position does the same thing
|
||||
*/
|
||||
void SP_info_notnull( gentity_t *self )
|
||||
{
|
||||
G_SetOrigin( self, self->s.origin );
|
||||
}
|
||||
|
||||
|
||||
/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) linear
|
||||
Non-displayed light.
|
||||
"light" overrides the default 300 intensity.
|
||||
Linear checbox gives linear falloff instead of inverse square
|
||||
Lights pointed at a target will be spotlights.
|
||||
"radius" overrides the default 64 unit radius of a spotlight at the target point.
|
||||
*/
|
||||
void SP_light( gentity_t *self )
|
||||
{
|
||||
G_FreeEntity( self );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=================================================================================
|
||||
|
||||
TELEPORTERS
|
||||
|
||||
=================================================================================
|
||||
*/
|
||||
|
||||
void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles )
|
||||
{
|
||||
// unlink to make sure it can't possibly interfere with G_KillBox
|
||||
trap_UnlinkEntity( player );
|
||||
|
||||
VectorCopy( origin, player->client->ps.origin );
|
||||
player->client->ps.origin[ 2 ] += 1;
|
||||
|
||||
// spit the player out
|
||||
AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
|
||||
VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
|
||||
player->client->ps.pm_time = 160; // hold time
|
||||
player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
|
||||
|
||||
// toggle the teleport bit so the client knows to not lerp
|
||||
player->client->ps.eFlags ^= EF_TELEPORT_BIT;
|
||||
G_UnlaggedClear( player );
|
||||
|
||||
// set angles
|
||||
SetClientViewAngle( player, angles );
|
||||
|
||||
// kill anything at the destination
|
||||
if( player->client->sess.sessionTeam != TEAM_SPECTATOR )
|
||||
G_KillBox( player );
|
||||
|
||||
// save results of pmove
|
||||
BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );
|
||||
|
||||
// use the precise origin for linking
|
||||
VectorCopy( player->client->ps.origin, player->r.currentOrigin );
|
||||
|
||||
if( player->client->sess.sessionTeam != TEAM_SPECTATOR )
|
||||
trap_LinkEntity (player);
|
||||
}
|
||||
|
||||
|
||||
/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
|
||||
Point teleporters at these.
|
||||
Now that we don't have teleport destination pads, this is just
|
||||
an info_notnull
|
||||
*/
|
||||
void SP_misc_teleporter_dest( gentity_t *ent )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//===========================================================
|
||||
|
||||
/*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16)
|
||||
"model" arbitrary .md3 file to display
|
||||
*/
|
||||
void SP_misc_model( gentity_t *ent )
|
||||
{
|
||||
#if 0
|
||||
ent->s.modelindex = G_ModelIndex( ent->model );
|
||||
VectorSet (ent->mins, -16, -16, -16);
|
||||
VectorSet (ent->maxs, 16, 16, 16);
|
||||
trap_LinkEntity (ent);
|
||||
|
||||
G_SetOrigin( ent, ent->s.origin );
|
||||
VectorCopy( ent->s.angles, ent->s.apos.trBase );
|
||||
#else
|
||||
G_FreeEntity( ent );
|
||||
#endif
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
|
||||
void locateCamera( gentity_t *ent )
|
||||
{
|
||||
vec3_t dir;
|
||||
gentity_t *target;
|
||||
gentity_t *owner;
|
||||
|
||||
owner = G_PickTarget( ent->target );
|
||||
if( !owner )
|
||||
{
|
||||
G_Printf( "Couldn't find target for misc_portal_surface\n" );
|
||||
G_FreeEntity( ent );
|
||||
return;
|
||||
}
|
||||
ent->r.ownerNum = owner->s.number;
|
||||
|
||||
// frame holds the rotate speed
|
||||
if( owner->spawnflags & 1 )
|
||||
ent->s.frame = 25;
|
||||
else if( owner->spawnflags & 2 )
|
||||
ent->s.frame = 75;
|
||||
|
||||
// swing camera ?
|
||||
if( owner->spawnflags & 4 )
|
||||
{
|
||||
// set to 0 for no rotation at all
|
||||
ent->s.powerups = 0;
|
||||
}
|
||||
else
|
||||
ent->s.powerups = 1;
|
||||
|
||||
// clientNum holds the rotate offset
|
||||
ent->s.clientNum = owner->s.clientNum;
|
||||
|
||||
VectorCopy( owner->s.origin, ent->s.origin2 );
|
||||
|
||||
// see if the portal_camera has a target
|
||||
target = G_PickTarget( owner->target );
|
||||
if( target )
|
||||
{
|
||||
VectorSubtract( target->s.origin, owner->s.origin, dir );
|
||||
VectorNormalize( dir );
|
||||
}
|
||||
else
|
||||
G_SetMovedir( owner->s.angles, dir );
|
||||
|
||||
ent->s.eventParm = DirToByte( dir );
|
||||
}
|
||||
|
||||
/*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)
|
||||
The portal surface nearest this entity will show a view from the targeted misc_portal_camera, or a mirror view if untargeted.
|
||||
This must be within 64 world units of the surface!
|
||||
*/
|
||||
void SP_misc_portal_surface( gentity_t *ent )
|
||||
{
|
||||
VectorClear( ent->r.mins );
|
||||
VectorClear( ent->r.maxs );
|
||||
trap_LinkEntity( ent );
|
||||
|
||||
ent->r.svFlags = SVF_PORTAL;
|
||||
ent->s.eType = ET_PORTAL;
|
||||
|
||||
if( !ent->target )
|
||||
{
|
||||
VectorCopy( ent->s.origin, ent->s.origin2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->think = locateCamera;
|
||||
ent->nextthink = level.time + 100;
|
||||
}
|
||||
}
|
||||
|
||||
/*QUAKED misc_portal_camera (0 0 1) (-8 -8 -8) (8 8 8) slowrotate fastrotate noswing
|
||||
|
||||
The target for a misc_portal_director. You can set either angles or target another entity to determine the direction of view.
|
||||
"roll" an angle modifier to orient the camera around the target vector;
|
||||
*/
|
||||
void SP_misc_portal_camera( gentity_t *ent )
|
||||
{
|
||||
float roll;
|
||||
|
||||
VectorClear( ent->r.mins );
|
||||
VectorClear( ent->r.maxs );
|
||||
trap_LinkEntity( ent );
|
||||
|
||||
G_SpawnFloat( "roll", "0", &roll );
|
||||
|
||||
ent->s.clientNum = roll / 360.0f * 256;
|
||||
}
|
||||
|
||||
/*
|
||||
======================================================================
|
||||
|
||||
NEAT EFFECTS AND STUFF FOR TREMULOUS
|
||||
|
||||
======================================================================
|
||||
*/
|
||||
|
||||
void SP_toggle_particle_system( gentity_t *self )
|
||||
{
|
||||
//toggle EF_NODRAW
|
||||
self->s.eFlags ^= EF_NODRAW;
|
||||
|
||||
self->nextthink = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_use_particle_system
|
||||
|
||||
Use function for particle_system
|
||||
===============
|
||||
*/
|
||||
void SP_use_particle_system( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
SP_toggle_particle_system( self );
|
||||
|
||||
if( self->wait > 0.0f )
|
||||
{
|
||||
self->think = SP_toggle_particle_system;
|
||||
self->nextthink = level.time + (int)( self->wait * 1000 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_spawn_particle_system
|
||||
|
||||
Spawn function for particle system
|
||||
===============
|
||||
*/
|
||||
void SP_misc_particle_system( gentity_t *self )
|
||||
{
|
||||
char *s;
|
||||
|
||||
G_SetOrigin( self, self->s.origin );
|
||||
|
||||
G_SpawnString( "psName", "", &s );
|
||||
G_SpawnFloat( "wait", "0", &self->wait );
|
||||
|
||||
//add the particle system to the client precache list
|
||||
self->s.modelindex = G_ParticleSystemIndex( s );
|
||||
|
||||
if( self->spawnflags & 1 )
|
||||
self->s.eFlags |= EF_NODRAW;
|
||||
|
||||
self->use = SP_use_particle_system;
|
||||
self->s.eType = ET_PARTICLE_SYSTEM;
|
||||
trap_LinkEntity( self );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_use_anim_model
|
||||
|
||||
Use function for anim model
|
||||
===============
|
||||
*/
|
||||
void SP_use_anim_model( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
if( self->spawnflags & 1 )
|
||||
{
|
||||
//if spawnflag 1 is set
|
||||
//toggle EF_NODRAW
|
||||
if( self->s.eFlags & EF_NODRAW )
|
||||
self->s.eFlags &= ~EF_NODRAW;
|
||||
else
|
||||
self->s.eFlags |= EF_NODRAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if the animation loops then toggle the animation
|
||||
//toggle EF_MOVER_STOP
|
||||
if( self->s.eFlags & EF_MOVER_STOP )
|
||||
self->s.eFlags &= ~EF_MOVER_STOP;
|
||||
else
|
||||
self->s.eFlags |= EF_MOVER_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_misc_anim_model
|
||||
|
||||
Spawn function for anim model
|
||||
===============
|
||||
*/
|
||||
void SP_misc_anim_model( gentity_t *self )
|
||||
{
|
||||
self->s.powerups = (int)self->animation[ 0 ];
|
||||
self->s.weapon = (int)self->animation[ 1 ];
|
||||
self->s.torsoAnim = (int)self->animation[ 2 ];
|
||||
self->s.legsAnim = (int)self->animation[ 3 ];
|
||||
|
||||
self->s.angles2[ 0 ] = self->pos2[ 0 ];
|
||||
|
||||
//add the model to the client precache list
|
||||
self->s.modelindex = G_ModelIndex( self->model );
|
||||
|
||||
self->use = SP_use_anim_model;
|
||||
|
||||
self->s.eType = ET_ANIMMAPOBJ;
|
||||
|
||||
// spawn with animation stopped
|
||||
if( self->spawnflags & 2 )
|
||||
self->s.eFlags |= EF_MOVER_STOP;
|
||||
|
||||
trap_LinkEntity( self );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_use_light_flare
|
||||
|
||||
Use function for light flare
|
||||
===============
|
||||
*/
|
||||
void SP_use_light_flare( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
self->s.eFlags ^= EF_NODRAW;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
findEmptySpot
|
||||
|
||||
Finds an empty spot radius units from origin
|
||||
==============
|
||||
*/
|
||||
static void findEmptySpot( vec3_t origin, float radius, vec3_t spot )
|
||||
{
|
||||
int i, j, k;
|
||||
vec3_t delta, test, total;
|
||||
trace_t tr;
|
||||
|
||||
VectorClear( total );
|
||||
|
||||
//54(!) traces to test for empty spots
|
||||
for( i = -1; i <= 1; i++ )
|
||||
{
|
||||
for( j = -1; j <= 1; j++ )
|
||||
{
|
||||
for( k = -1; k <= 1; k++ )
|
||||
{
|
||||
VectorSet( delta, ( i * radius ),
|
||||
( j * radius ),
|
||||
( k * radius ) );
|
||||
|
||||
VectorAdd( origin, delta, test );
|
||||
|
||||
trap_Trace( &tr, test, NULL, NULL, test, -1, MASK_SOLID );
|
||||
|
||||
if( !tr.allsolid )
|
||||
{
|
||||
trap_Trace( &tr, test, NULL, NULL, origin, -1, MASK_SOLID );
|
||||
VectorScale( delta, tr.fraction, delta );
|
||||
VectorAdd( total, delta, total );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VectorNormalize( total );
|
||||
VectorScale( total, radius, total );
|
||||
VectorAdd( origin, total, spot );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_misc_light_flare
|
||||
|
||||
Spawn function for light flare
|
||||
===============
|
||||
*/
|
||||
void SP_misc_light_flare( gentity_t *self )
|
||||
{
|
||||
self->s.eType = ET_LIGHTFLARE;
|
||||
self->s.modelindex = G_ShaderIndex( self->targetShaderName );
|
||||
VectorCopy( self->pos2, self->s.origin2 );
|
||||
|
||||
//try to find a spot near to the flare which is empty. This
|
||||
//is used to facilitate visibility testing
|
||||
findEmptySpot( self->s.origin, 8.0f, self->s.angles2 );
|
||||
|
||||
self->use = SP_use_light_flare;
|
||||
|
||||
G_SpawnFloat( "speed", "200", &self->speed );
|
||||
self->s.time = self->speed;
|
||||
|
||||
G_SpawnInt( "mindist", "0", &self->s.generic1 );
|
||||
|
||||
if( self->spawnflags & 1 )
|
||||
self->s.eFlags |= EF_NODRAW;
|
||||
|
||||
trap_LinkEntity( self );
|
||||
}
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
|
||||
/*QUAKED func_group (0 0 0) ?
|
||||
Used to group brushes together just for editor convenience. They are turned into normal brushes by the utilities.
|
||||
*/
|
||||
|
||||
|
||||
/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4)
|
||||
Used as a positional target for calculations in the utilities (spotlights, etc), but removed during gameplay.
|
||||
*/
|
||||
void SP_info_null( gentity_t *self )
|
||||
{
|
||||
G_FreeEntity( self );
|
||||
}
|
||||
|
||||
|
||||
/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
|
||||
Used as a positional target for in-game calculation, like jumppad targets.
|
||||
target_position does the same thing
|
||||
*/
|
||||
void SP_info_notnull( gentity_t *self )
|
||||
{
|
||||
G_SetOrigin( self, self->s.origin );
|
||||
}
|
||||
|
||||
|
||||
/*QUAKED light (0 1 0) (-8 -8 -8) (8 8 8) linear
|
||||
Non-displayed light.
|
||||
"light" overrides the default 300 intensity.
|
||||
Linear checbox gives linear falloff instead of inverse square
|
||||
Lights pointed at a target will be spotlights.
|
||||
"radius" overrides the default 64 unit radius of a spotlight at the target point.
|
||||
*/
|
||||
void SP_light( gentity_t *self )
|
||||
{
|
||||
G_FreeEntity( self );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=================================================================================
|
||||
|
||||
TELEPORTERS
|
||||
|
||||
=================================================================================
|
||||
*/
|
||||
|
||||
void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles )
|
||||
{
|
||||
// unlink to make sure it can't possibly interfere with G_KillBox
|
||||
trap_UnlinkEntity( player );
|
||||
|
||||
VectorCopy( origin, player->client->ps.origin );
|
||||
player->client->ps.origin[ 2 ] += 1;
|
||||
|
||||
// spit the player out
|
||||
AngleVectors( angles, player->client->ps.velocity, NULL, NULL );
|
||||
VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity );
|
||||
player->client->ps.pm_time = 160; // hold time
|
||||
player->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
|
||||
|
||||
// toggle the teleport bit so the client knows to not lerp
|
||||
player->client->ps.eFlags ^= EF_TELEPORT_BIT;
|
||||
G_UnlaggedClear( player );
|
||||
|
||||
// set angles
|
||||
SetClientViewAngle( player, angles );
|
||||
|
||||
// kill anything at the destination
|
||||
if( player->client->sess.sessionTeam != TEAM_SPECTATOR )
|
||||
G_KillBox( player );
|
||||
|
||||
// save results of pmove
|
||||
BG_PlayerStateToEntityState( &player->client->ps, &player->s, qtrue );
|
||||
|
||||
// use the precise origin for linking
|
||||
VectorCopy( player->client->ps.origin, player->r.currentOrigin );
|
||||
|
||||
if( player->client->sess.sessionTeam != TEAM_SPECTATOR )
|
||||
trap_LinkEntity (player);
|
||||
}
|
||||
|
||||
|
||||
/*QUAKED misc_teleporter_dest (1 0 0) (-32 -32 -24) (32 32 -16)
|
||||
Point teleporters at these.
|
||||
Now that we don't have teleport destination pads, this is just
|
||||
an info_notnull
|
||||
*/
|
||||
void SP_misc_teleporter_dest( gentity_t *ent )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//===========================================================
|
||||
|
||||
/*QUAKED misc_model (1 0 0) (-16 -16 -16) (16 16 16)
|
||||
"model" arbitrary .md3 file to display
|
||||
*/
|
||||
void SP_misc_model( gentity_t *ent )
|
||||
{
|
||||
#if 0
|
||||
ent->s.modelindex = G_ModelIndex( ent->model );
|
||||
VectorSet (ent->mins, -16, -16, -16);
|
||||
VectorSet (ent->maxs, 16, 16, 16);
|
||||
trap_LinkEntity (ent);
|
||||
|
||||
G_SetOrigin( ent, ent->s.origin );
|
||||
VectorCopy( ent->s.angles, ent->s.apos.trBase );
|
||||
#else
|
||||
G_FreeEntity( ent );
|
||||
#endif
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
|
||||
void locateCamera( gentity_t *ent )
|
||||
{
|
||||
vec3_t dir;
|
||||
gentity_t *target;
|
||||
gentity_t *owner;
|
||||
|
||||
owner = G_PickTarget( ent->target );
|
||||
if( !owner )
|
||||
{
|
||||
G_Printf( "Couldn't find target for misc_portal_surface\n" );
|
||||
G_FreeEntity( ent );
|
||||
return;
|
||||
}
|
||||
ent->r.ownerNum = owner->s.number;
|
||||
|
||||
// frame holds the rotate speed
|
||||
if( owner->spawnflags & 1 )
|
||||
ent->s.frame = 25;
|
||||
else if( owner->spawnflags & 2 )
|
||||
ent->s.frame = 75;
|
||||
|
||||
// swing camera ?
|
||||
if( owner->spawnflags & 4 )
|
||||
{
|
||||
// set to 0 for no rotation at all
|
||||
ent->s.powerups = 0;
|
||||
}
|
||||
else
|
||||
ent->s.powerups = 1;
|
||||
|
||||
// clientNum holds the rotate offset
|
||||
ent->s.clientNum = owner->s.clientNum;
|
||||
|
||||
VectorCopy( owner->s.origin, ent->s.origin2 );
|
||||
|
||||
// see if the portal_camera has a target
|
||||
target = G_PickTarget( owner->target );
|
||||
if( target )
|
||||
{
|
||||
VectorSubtract( target->s.origin, owner->s.origin, dir );
|
||||
VectorNormalize( dir );
|
||||
}
|
||||
else
|
||||
G_SetMovedir( owner->s.angles, dir );
|
||||
|
||||
ent->s.eventParm = DirToByte( dir );
|
||||
}
|
||||
|
||||
/*QUAKED misc_portal_surface (0 0 1) (-8 -8 -8) (8 8 8)
|
||||
The portal surface nearest this entity will show a view from the targeted misc_portal_camera, or a mirror view if untargeted.
|
||||
This must be within 64 world units of the surface!
|
||||
*/
|
||||
void SP_misc_portal_surface( gentity_t *ent )
|
||||
{
|
||||
VectorClear( ent->r.mins );
|
||||
VectorClear( ent->r.maxs );
|
||||
trap_LinkEntity( ent );
|
||||
|
||||
ent->r.svFlags = SVF_PORTAL;
|
||||
ent->s.eType = ET_PORTAL;
|
||||
|
||||
if( !ent->target )
|
||||
{
|
||||
VectorCopy( ent->s.origin, ent->s.origin2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->think = locateCamera;
|
||||
ent->nextthink = level.time + 100;
|
||||
}
|
||||
}
|
||||
|
||||
/*QUAKED misc_portal_camera (0 0 1) (-8 -8 -8) (8 8 8) slowrotate fastrotate noswing
|
||||
|
||||
The target for a misc_portal_director. You can set either angles or target another entity to determine the direction of view.
|
||||
"roll" an angle modifier to orient the camera around the target vector;
|
||||
*/
|
||||
void SP_misc_portal_camera( gentity_t *ent )
|
||||
{
|
||||
float roll;
|
||||
|
||||
VectorClear( ent->r.mins );
|
||||
VectorClear( ent->r.maxs );
|
||||
trap_LinkEntity( ent );
|
||||
|
||||
G_SpawnFloat( "roll", "0", &roll );
|
||||
|
||||
ent->s.clientNum = roll / 360.0f * 256;
|
||||
}
|
||||
|
||||
/*
|
||||
======================================================================
|
||||
|
||||
NEAT EFFECTS AND STUFF FOR TREMULOUS
|
||||
|
||||
======================================================================
|
||||
*/
|
||||
|
||||
void SP_toggle_particle_system( gentity_t *self )
|
||||
{
|
||||
//toggle EF_NODRAW
|
||||
self->s.eFlags ^= EF_NODRAW;
|
||||
|
||||
self->nextthink = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_use_particle_system
|
||||
|
||||
Use function for particle_system
|
||||
===============
|
||||
*/
|
||||
void SP_use_particle_system( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
SP_toggle_particle_system( self );
|
||||
|
||||
if( self->wait > 0.0f )
|
||||
{
|
||||
self->think = SP_toggle_particle_system;
|
||||
self->nextthink = level.time + (int)( self->wait * 1000 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_spawn_particle_system
|
||||
|
||||
Spawn function for particle system
|
||||
===============
|
||||
*/
|
||||
void SP_misc_particle_system( gentity_t *self )
|
||||
{
|
||||
char *s;
|
||||
|
||||
G_SetOrigin( self, self->s.origin );
|
||||
|
||||
G_SpawnString( "psName", "", &s );
|
||||
G_SpawnFloat( "wait", "0", &self->wait );
|
||||
|
||||
//add the particle system to the client precache list
|
||||
self->s.modelindex = G_ParticleSystemIndex( s );
|
||||
|
||||
if( self->spawnflags & 1 )
|
||||
self->s.eFlags |= EF_NODRAW;
|
||||
|
||||
self->use = SP_use_particle_system;
|
||||
self->s.eType = ET_PARTICLE_SYSTEM;
|
||||
trap_LinkEntity( self );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_use_anim_model
|
||||
|
||||
Use function for anim model
|
||||
===============
|
||||
*/
|
||||
void SP_use_anim_model( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
if( self->spawnflags & 1 )
|
||||
{
|
||||
//if spawnflag 1 is set
|
||||
//toggle EF_NODRAW
|
||||
if( self->s.eFlags & EF_NODRAW )
|
||||
self->s.eFlags &= ~EF_NODRAW;
|
||||
else
|
||||
self->s.eFlags |= EF_NODRAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if the animation loops then toggle the animation
|
||||
//toggle EF_MOVER_STOP
|
||||
if( self->s.eFlags & EF_MOVER_STOP )
|
||||
self->s.eFlags &= ~EF_MOVER_STOP;
|
||||
else
|
||||
self->s.eFlags |= EF_MOVER_STOP;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_misc_anim_model
|
||||
|
||||
Spawn function for anim model
|
||||
===============
|
||||
*/
|
||||
void SP_misc_anim_model( gentity_t *self )
|
||||
{
|
||||
self->s.powerups = (int)self->animation[ 0 ];
|
||||
self->s.weapon = (int)self->animation[ 1 ];
|
||||
self->s.torsoAnim = (int)self->animation[ 2 ];
|
||||
self->s.legsAnim = (int)self->animation[ 3 ];
|
||||
|
||||
self->s.angles2[ 0 ] = self->pos2[ 0 ];
|
||||
|
||||
//add the model to the client precache list
|
||||
self->s.modelindex = G_ModelIndex( self->model );
|
||||
|
||||
self->use = SP_use_anim_model;
|
||||
|
||||
self->s.eType = ET_ANIMMAPOBJ;
|
||||
|
||||
// spawn with animation stopped
|
||||
if( self->spawnflags & 2 )
|
||||
self->s.eFlags |= EF_MOVER_STOP;
|
||||
|
||||
trap_LinkEntity( self );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_use_light_flare
|
||||
|
||||
Use function for light flare
|
||||
===============
|
||||
*/
|
||||
void SP_use_light_flare( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
self->s.eFlags ^= EF_NODRAW;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
findEmptySpot
|
||||
|
||||
Finds an empty spot radius units from origin
|
||||
==============
|
||||
*/
|
||||
static void findEmptySpot( vec3_t origin, float radius, vec3_t spot )
|
||||
{
|
||||
int i, j, k;
|
||||
vec3_t delta, test, total;
|
||||
trace_t tr;
|
||||
|
||||
VectorClear( total );
|
||||
|
||||
//54(!) traces to test for empty spots
|
||||
for( i = -1; i <= 1; i++ )
|
||||
{
|
||||
for( j = -1; j <= 1; j++ )
|
||||
{
|
||||
for( k = -1; k <= 1; k++ )
|
||||
{
|
||||
VectorSet( delta, ( i * radius ),
|
||||
( j * radius ),
|
||||
( k * radius ) );
|
||||
|
||||
VectorAdd( origin, delta, test );
|
||||
|
||||
trap_Trace( &tr, test, NULL, NULL, test, -1, MASK_SOLID );
|
||||
|
||||
if( !tr.allsolid )
|
||||
{
|
||||
trap_Trace( &tr, test, NULL, NULL, origin, -1, MASK_SOLID );
|
||||
VectorScale( delta, tr.fraction, delta );
|
||||
VectorAdd( total, delta, total );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VectorNormalize( total );
|
||||
VectorScale( total, radius, total );
|
||||
VectorAdd( origin, total, spot );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_misc_light_flare
|
||||
|
||||
Spawn function for light flare
|
||||
===============
|
||||
*/
|
||||
void SP_misc_light_flare( gentity_t *self )
|
||||
{
|
||||
self->s.eType = ET_LIGHTFLARE;
|
||||
self->s.modelindex = G_ShaderIndex( self->targetShaderName );
|
||||
VectorCopy( self->pos2, self->s.origin2 );
|
||||
|
||||
//try to find a spot near to the flare which is empty. This
|
||||
//is used to facilitate visibility testing
|
||||
findEmptySpot( self->s.origin, 8.0f, self->s.angles2 );
|
||||
|
||||
self->use = SP_use_light_flare;
|
||||
|
||||
G_SpawnFloat( "speed", "200", &self->speed );
|
||||
self->s.time = self->speed;
|
||||
|
||||
G_SpawnInt( "mindist", "0", &self->s.generic1 );
|
||||
|
||||
if( self->spawnflags & 1 )
|
||||
self->s.eFlags |= EF_NODRAW;
|
||||
|
||||
trap_LinkEntity( self );
|
||||
}
|
||||
+2479
-2479
File diff suppressed because it is too large.
Load diff
+170
-170
@@ -1,170 +1,170 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
/*
|
||||
================
|
||||
G_Bounce
|
||||
|
||||
================
|
||||
*/
|
||||
static void G_Bounce( gentity_t *ent, trace_t *trace )
|
||||
{
|
||||
vec3_t velocity;
|
||||
float dot;
|
||||
int hitTime;
|
||||
float minNormal;
|
||||
qboolean invert = qfalse;
|
||||
|
||||
// reflect the velocity on the trace plane
|
||||
hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
|
||||
BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
|
||||
dot = DotProduct( velocity, trace->plane.normal );
|
||||
VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
|
||||
|
||||
if( ent->s.eType == ET_BUILDABLE )
|
||||
{
|
||||
minNormal = BG_FindMinNormalForBuildable( ent->s.modelindex );
|
||||
invert = BG_FindInvertNormalForBuildable( ent->s.modelindex );
|
||||
}
|
||||
else
|
||||
minNormal = 0.707f;
|
||||
|
||||
// cut the velocity to keep from bouncing forever
|
||||
if( ( trace->plane.normal[ 2 ] >= minNormal ||
|
||||
( invert && trace->plane.normal[ 2 ] <= -minNormal ) ) &&
|
||||
trace->entityNum == ENTITYNUM_WORLD )
|
||||
VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta );
|
||||
else
|
||||
VectorScale( ent->s.pos.trDelta, 0.3f, ent->s.pos.trDelta );
|
||||
|
||||
if( VectorLength( ent->s.pos.trDelta ) < 10 )
|
||||
{
|
||||
VectorMA( trace->endpos, 0.5f, trace->plane.normal, trace->endpos ); // make sure it is off ground
|
||||
// Never allow origin to be snapped lower (buildables fall through map bug)
|
||||
trace->endpos[2] = (float)ceil(trace->endpos[2]);
|
||||
SnapVector( trace->endpos );
|
||||
G_SetOrigin( ent, trace->endpos );
|
||||
ent->s.groundEntityNum = trace->entityNum;
|
||||
VectorCopy( trace->plane.normal, ent->s.origin2 );
|
||||
VectorSet( ent->s.pos.trDelta, 0.0f, 0.0f, 0.0f );
|
||||
return;
|
||||
}
|
||||
|
||||
VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
|
||||
VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
|
||||
ent->s.pos.trTime = level.time;
|
||||
}
|
||||
|
||||
#define PHYSICS_TIME 200
|
||||
|
||||
/*
|
||||
================
|
||||
G_Physics
|
||||
|
||||
================
|
||||
*/
|
||||
void G_Physics( gentity_t *ent, int msec )
|
||||
{
|
||||
vec3_t origin;
|
||||
trace_t tr;
|
||||
int contents;
|
||||
int mask;
|
||||
|
||||
// if groundentity has been set to -1, it may have been pushed off an edge
|
||||
if( ent->s.groundEntityNum == -1 )
|
||||
{
|
||||
if( ent->s.eType == ET_BUILDABLE )
|
||||
{
|
||||
if( ent->s.pos.trType != BG_FindTrajectoryForBuildable( ent->s.modelindex ) )
|
||||
{
|
||||
ent->s.pos.trType = BG_FindTrajectoryForBuildable( ent->s.modelindex );
|
||||
ent->s.pos.trTime = level.time;
|
||||
}
|
||||
}
|
||||
else if( ent->s.pos.trType != TR_GRAVITY )
|
||||
{
|
||||
ent->s.pos.trType = TR_GRAVITY;
|
||||
ent->s.pos.trTime = level.time;
|
||||
}
|
||||
}
|
||||
|
||||
// trace a line from the previous position to the current position
|
||||
if( ent->clipmask )
|
||||
mask = ent->clipmask;
|
||||
else
|
||||
mask = MASK_PLAYERSOLID & ~CONTENTS_BODY;//MASK_SOLID;
|
||||
|
||||
if( ent->s.pos.trType == TR_STATIONARY )
|
||||
{
|
||||
// check think function
|
||||
G_RunThink( ent );
|
||||
|
||||
//check floor infrequently
|
||||
if( ent->nextPhysicsTime < level.time )
|
||||
{
|
||||
VectorCopy( ent->r.currentOrigin, origin );
|
||||
|
||||
VectorMA( origin, -2.0f, ent->s.origin2, origin );
|
||||
|
||||
trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, ent->s.number, mask );
|
||||
|
||||
if( tr.fraction == 1.0f )
|
||||
ent->s.groundEntityNum = -1;
|
||||
|
||||
ent->nextPhysicsTime = level.time + PHYSICS_TIME;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// get current position
|
||||
BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
|
||||
|
||||
trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, ent->s.number, mask );
|
||||
|
||||
VectorCopy( tr.endpos, ent->r.currentOrigin );
|
||||
|
||||
if( tr.startsolid )
|
||||
tr.fraction = 0;
|
||||
|
||||
trap_LinkEntity( ent ); // FIXME: avoid this for stationary?
|
||||
|
||||
// check think function
|
||||
G_RunThink( ent );
|
||||
|
||||
if( tr.fraction == 1.0f )
|
||||
return;
|
||||
|
||||
// if it is in a nodrop volume, remove it
|
||||
contents = trap_PointContents( ent->r.currentOrigin, -1 );
|
||||
if( contents & CONTENTS_NODROP )
|
||||
{
|
||||
G_FreeEntity( ent );
|
||||
return;
|
||||
}
|
||||
|
||||
G_Bounce( ent, &tr );
|
||||
}
|
||||
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
/*
|
||||
================
|
||||
G_Bounce
|
||||
|
||||
================
|
||||
*/
|
||||
static void G_Bounce( gentity_t *ent, trace_t *trace )
|
||||
{
|
||||
vec3_t velocity;
|
||||
float dot;
|
||||
int hitTime;
|
||||
float minNormal;
|
||||
qboolean invert = qfalse;
|
||||
|
||||
// reflect the velocity on the trace plane
|
||||
hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
|
||||
BG_EvaluateTrajectoryDelta( &ent->s.pos, hitTime, velocity );
|
||||
dot = DotProduct( velocity, trace->plane.normal );
|
||||
VectorMA( velocity, -2*dot, trace->plane.normal, ent->s.pos.trDelta );
|
||||
|
||||
if( ent->s.eType == ET_BUILDABLE )
|
||||
{
|
||||
minNormal = BG_FindMinNormalForBuildable( ent->s.modelindex );
|
||||
invert = BG_FindInvertNormalForBuildable( ent->s.modelindex );
|
||||
}
|
||||
else
|
||||
minNormal = 0.707f;
|
||||
|
||||
// cut the velocity to keep from bouncing forever
|
||||
if( ( trace->plane.normal[ 2 ] >= minNormal ||
|
||||
( invert && trace->plane.normal[ 2 ] <= -minNormal ) ) &&
|
||||
trace->entityNum == ENTITYNUM_WORLD )
|
||||
VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta );
|
||||
else
|
||||
VectorScale( ent->s.pos.trDelta, 0.3f, ent->s.pos.trDelta );
|
||||
|
||||
if( VectorLength( ent->s.pos.trDelta ) < 10 )
|
||||
{
|
||||
VectorMA( trace->endpos, 0.5f, trace->plane.normal, trace->endpos ); // make sure it is off ground
|
||||
// Never allow origin to be snapped lower (buildables fall through map bug)
|
||||
trace->endpos[2] = (float)ceil(trace->endpos[2]);
|
||||
SnapVector( trace->endpos );
|
||||
G_SetOrigin( ent, trace->endpos );
|
||||
ent->s.groundEntityNum = trace->entityNum;
|
||||
VectorCopy( trace->plane.normal, ent->s.origin2 );
|
||||
VectorSet( ent->s.pos.trDelta, 0.0f, 0.0f, 0.0f );
|
||||
return;
|
||||
}
|
||||
|
||||
VectorCopy( ent->r.currentOrigin, ent->s.pos.trBase );
|
||||
VectorAdd( ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
|
||||
ent->s.pos.trTime = level.time;
|
||||
}
|
||||
|
||||
#define PHYSICS_TIME 200
|
||||
|
||||
/*
|
||||
================
|
||||
G_Physics
|
||||
|
||||
================
|
||||
*/
|
||||
void G_Physics( gentity_t *ent, int msec )
|
||||
{
|
||||
vec3_t origin;
|
||||
trace_t tr;
|
||||
int contents;
|
||||
int mask;
|
||||
|
||||
// if groundentity has been set to -1, it may have been pushed off an edge
|
||||
if( ent->s.groundEntityNum == -1 )
|
||||
{
|
||||
if( ent->s.eType == ET_BUILDABLE )
|
||||
{
|
||||
if( ent->s.pos.trType != BG_FindTrajectoryForBuildable( ent->s.modelindex ) )
|
||||
{
|
||||
ent->s.pos.trType = BG_FindTrajectoryForBuildable( ent->s.modelindex );
|
||||
ent->s.pos.trTime = level.time;
|
||||
}
|
||||
}
|
||||
else if( ent->s.pos.trType != TR_GRAVITY )
|
||||
{
|
||||
ent->s.pos.trType = TR_GRAVITY;
|
||||
ent->s.pos.trTime = level.time;
|
||||
}
|
||||
}
|
||||
|
||||
// trace a line from the previous position to the current position
|
||||
if( ent->clipmask )
|
||||
mask = ent->clipmask;
|
||||
else
|
||||
mask = MASK_PLAYERSOLID & ~CONTENTS_BODY;//MASK_SOLID;
|
||||
|
||||
if( ent->s.pos.trType == TR_STATIONARY )
|
||||
{
|
||||
// check think function
|
||||
G_RunThink( ent );
|
||||
|
||||
//check floor infrequently
|
||||
if( ent->nextPhysicsTime < level.time )
|
||||
{
|
||||
VectorCopy( ent->r.currentOrigin, origin );
|
||||
|
||||
VectorMA( origin, -2.0f, ent->s.origin2, origin );
|
||||
|
||||
trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, ent->s.number, mask );
|
||||
|
||||
if( tr.fraction == 1.0f )
|
||||
ent->s.groundEntityNum = -1;
|
||||
|
||||
ent->nextPhysicsTime = level.time + PHYSICS_TIME;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// get current position
|
||||
BG_EvaluateTrajectory( &ent->s.pos, level.time, origin );
|
||||
|
||||
trap_Trace( &tr, ent->r.currentOrigin, ent->r.mins, ent->r.maxs, origin, ent->s.number, mask );
|
||||
|
||||
VectorCopy( tr.endpos, ent->r.currentOrigin );
|
||||
|
||||
if( tr.startsolid )
|
||||
tr.fraction = 0;
|
||||
|
||||
trap_LinkEntity( ent ); // FIXME: avoid this for stationary?
|
||||
|
||||
// check think function
|
||||
G_RunThink( ent );
|
||||
|
||||
if( tr.fraction == 1.0f )
|
||||
return;
|
||||
|
||||
// if it is in a nodrop volume, remove it
|
||||
contents = trap_PointContents( ent->r.currentOrigin, -1 );
|
||||
if( contents & CONTENTS_NODROP )
|
||||
{
|
||||
G_FreeEntity( ent );
|
||||
return;
|
||||
}
|
||||
|
||||
G_Bounce( ent, &tr );
|
||||
}
|
||||
|
||||
+180
-180
@@ -1,180 +1,180 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// g_ptr.c -- post timeout restoration handling
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
static connectionRecord_t connections[ MAX_CLIENTS ];
|
||||
|
||||
/*
|
||||
===============
|
||||
G_CheckForUniquePTRC
|
||||
|
||||
Callback to detect ptrc clashes
|
||||
===============
|
||||
*/
|
||||
static qboolean G_CheckForUniquePTRC( int code )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( code == 0 )
|
||||
return qfalse;
|
||||
|
||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||
{
|
||||
if( connections[ i ].ptrCode == code )
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_UpdatePTRConnection
|
||||
|
||||
Update the data in a connection record
|
||||
===============
|
||||
*/
|
||||
void G_UpdatePTRConnection( gclient_t *client )
|
||||
{
|
||||
if( client && client->pers.connection )
|
||||
{
|
||||
client->pers.connection->clientTeam = client->pers.teamSelection;
|
||||
if( client->pers.teamSelection == PTE_NONE )
|
||||
client->pers.connection->clientCredit = client->pers.savedCredit;
|
||||
else
|
||||
client->pers.connection->clientCredit = client->ps.persistant[ PERS_CREDIT ];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_GenerateNewConnection
|
||||
|
||||
Generates a new connection
|
||||
===============
|
||||
*/
|
||||
connectionRecord_t *G_GenerateNewConnection( gclient_t *client )
|
||||
{
|
||||
int code = 0;
|
||||
int i;
|
||||
|
||||
// this should be really random
|
||||
srand( trap_Milliseconds( ) );
|
||||
|
||||
// there is a very very small possibility that this
|
||||
// will loop infinitely
|
||||
do
|
||||
{
|
||||
code = rand( );
|
||||
} while( !G_CheckForUniquePTRC( code ) );
|
||||
|
||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||
{
|
||||
//found an unused slot
|
||||
if( !connections[ i ].ptrCode )
|
||||
{
|
||||
connections[ i ].ptrCode = code;
|
||||
connections[ i ].clientNum = client->ps.clientNum;
|
||||
client->pers.connection = &connections[ i ];
|
||||
G_UpdatePTRConnection( client );
|
||||
|
||||
return &connections[ i ];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_VerifyPTRC
|
||||
|
||||
Check a PTR code for validity
|
||||
===============
|
||||
*/
|
||||
qboolean G_VerifyPTRC( int code )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( code == 0 )
|
||||
return qfalse;
|
||||
|
||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||
{
|
||||
if( connections[ i ].ptrCode == code )
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_FindConnectionForCode
|
||||
|
||||
Finds a connection for a given code
|
||||
===============
|
||||
*/
|
||||
connectionRecord_t *G_FindConnectionForCode( int code )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( code == 0 )
|
||||
return NULL;
|
||||
|
||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||
{
|
||||
if( connections[ i ].ptrCode == code )
|
||||
return &connections[ i ];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_DeletePTRConnection
|
||||
|
||||
Finds a connection and deletes it
|
||||
===============
|
||||
*/
|
||||
void G_DeletePTRConnection( connectionRecord_t *connection )
|
||||
{
|
||||
if( connection )
|
||||
memset( connection, 0, sizeof( connectionRecord_t ) );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_ResetPTRConnections
|
||||
|
||||
Invalidate any existing codes
|
||||
===============
|
||||
*/
|
||||
void G_ResetPTRConnections( void )
|
||||
{
|
||||
memset( connections, 0, sizeof( connectionRecord_t ) * MAX_CLIENTS );
|
||||
}
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// g_ptr.c -- post timeout restoration handling
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
static connectionRecord_t connections[ MAX_CLIENTS ];
|
||||
|
||||
/*
|
||||
===============
|
||||
G_CheckForUniquePTRC
|
||||
|
||||
Callback to detect ptrc clashes
|
||||
===============
|
||||
*/
|
||||
static qboolean G_CheckForUniquePTRC( int code )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( code == 0 )
|
||||
return qfalse;
|
||||
|
||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||
{
|
||||
if( connections[ i ].ptrCode == code )
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_UpdatePTRConnection
|
||||
|
||||
Update the data in a connection record
|
||||
===============
|
||||
*/
|
||||
void G_UpdatePTRConnection( gclient_t *client )
|
||||
{
|
||||
if( client && client->pers.connection )
|
||||
{
|
||||
client->pers.connection->clientTeam = client->pers.teamSelection;
|
||||
if( client->pers.teamSelection == PTE_NONE )
|
||||
client->pers.connection->clientCredit = client->pers.savedCredit;
|
||||
else
|
||||
client->pers.connection->clientCredit = client->ps.persistant[ PERS_CREDIT ];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_GenerateNewConnection
|
||||
|
||||
Generates a new connection
|
||||
===============
|
||||
*/
|
||||
connectionRecord_t *G_GenerateNewConnection( gclient_t *client )
|
||||
{
|
||||
int code = 0;
|
||||
int i;
|
||||
|
||||
// this should be really random
|
||||
srand( trap_Milliseconds( ) );
|
||||
|
||||
// there is a very very small possibility that this
|
||||
// will loop infinitely
|
||||
do
|
||||
{
|
||||
code = rand( );
|
||||
} while( !G_CheckForUniquePTRC( code ) );
|
||||
|
||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||
{
|
||||
//found an unused slot
|
||||
if( !connections[ i ].ptrCode )
|
||||
{
|
||||
connections[ i ].ptrCode = code;
|
||||
connections[ i ].clientNum = client->ps.clientNum;
|
||||
client->pers.connection = &connections[ i ];
|
||||
G_UpdatePTRConnection( client );
|
||||
|
||||
return &connections[ i ];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_VerifyPTRC
|
||||
|
||||
Check a PTR code for validity
|
||||
===============
|
||||
*/
|
||||
qboolean G_VerifyPTRC( int code )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( code == 0 )
|
||||
return qfalse;
|
||||
|
||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||
{
|
||||
if( connections[ i ].ptrCode == code )
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_FindConnectionForCode
|
||||
|
||||
Finds a connection for a given code
|
||||
===============
|
||||
*/
|
||||
connectionRecord_t *G_FindConnectionForCode( int code )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( code == 0 )
|
||||
return NULL;
|
||||
|
||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||
{
|
||||
if( connections[ i ].ptrCode == code )
|
||||
return &connections[ i ];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_DeletePTRConnection
|
||||
|
||||
Finds a connection and deletes it
|
||||
===============
|
||||
*/
|
||||
void G_DeletePTRConnection( connectionRecord_t *connection )
|
||||
{
|
||||
if( connection )
|
||||
memset( connection, 0, sizeof( connectionRecord_t ) );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_ResetPTRConnections
|
||||
|
||||
Invalidate any existing codes
|
||||
===============
|
||||
*/
|
||||
void G_ResetPTRConnections( void )
|
||||
{
|
||||
memset( connections, 0, sizeof( connectionRecord_t ) * MAX_CLIENTS );
|
||||
}
|
||||
+262
-262
@@ -1,262 +1,262 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// g_public.h -- game module information visible to server
|
||||
|
||||
#define GAME_API_VERSION 8
|
||||
|
||||
// entity->svFlags
|
||||
// the server does not know how to interpret most of the values
|
||||
// in entityStates (level eType), so the game must explicitly flag
|
||||
// special server behaviors
|
||||
#define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects
|
||||
|
||||
// TTimo
|
||||
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=551
|
||||
#define SVF_CLIENTMASK 0x00000002
|
||||
|
||||
#define SVF_BROADCAST 0x00000020 // send to all connected clients
|
||||
#define SVF_PORTAL 0x00000040 // merge a second pvs at origin2 into snapshots
|
||||
#define SVF_USE_CURRENT_ORIGIN 0x00000080 // entity->r.currentOrigin instead of entity->s.origin
|
||||
// for link position (missiles and movers)
|
||||
#define SVF_SINGLECLIENT 0x00000100 // only send to a single client (entityShared_t->singleClient)
|
||||
#define SVF_NOSERVERINFO 0x00000200 // don't send CS_SERVERINFO updates to this client
|
||||
// so that it can be updated for ping tools without
|
||||
// lagging clients
|
||||
#define SVF_CAPSULE 0x00000400 // use capsule for collision detection instead of bbox
|
||||
#define SVF_NOTSINGLECLIENT 0x00000800 // send entity to everyone but one client
|
||||
// (entityShared_t->singleClient)
|
||||
|
||||
//===============================================================
|
||||
|
||||
|
||||
typedef struct {
|
||||
entityState_t s; // communicated by server to clients
|
||||
|
||||
qboolean linked; // qfalse if not in any good cluster
|
||||
int linkcount;
|
||||
|
||||
int svFlags; // SVF_NOCLIENT, SVF_BROADCAST, etc
|
||||
int singleClient; // only send to this client when SVF_SINGLECLIENT is set
|
||||
|
||||
qboolean bmodel; // if false, assume an explicit mins / maxs bounding box
|
||||
// only set by trap_SetBrushModel
|
||||
vec3_t mins, maxs;
|
||||
int contents; // CONTENTS_TRIGGER, CONTENTS_SOLID, CONTENTS_BODY, etc
|
||||
// a non-solid entity should set to 0
|
||||
|
||||
vec3_t absmin, absmax; // derived from mins/maxs and origin + rotation
|
||||
|
||||
// currentOrigin will be used for all collision detection and world linking.
|
||||
// it will not necessarily be the same as the trajectory evaluation for the current
|
||||
// time, because each entity must be moved one at a time after time is advanced
|
||||
// to avoid simultanious collision issues
|
||||
vec3_t currentOrigin;
|
||||
vec3_t currentAngles;
|
||||
|
||||
// when a trace call is made and passEntityNum != ENTITYNUM_NONE,
|
||||
// an ent will be excluded from testing if:
|
||||
// ent->s.number == passEntityNum (don't interact with self)
|
||||
// ent->s.ownerNum = passEntityNum (don't interact with your own missiles)
|
||||
// entity[ent->s.ownerNum].ownerNum = passEntityNum (don't interact with other missiles from owner)
|
||||
int ownerNum;
|
||||
} entityShared_t;
|
||||
|
||||
|
||||
|
||||
// the server looks at a sharedEntity, which is the start of the game's gentity_t structure
|
||||
typedef struct {
|
||||
entityState_t s; // communicated by server to clients
|
||||
entityShared_t r; // shared by both the server system and game
|
||||
} sharedEntity_t;
|
||||
|
||||
|
||||
|
||||
//===============================================================
|
||||
|
||||
//
|
||||
// system traps provided by the main engine
|
||||
//
|
||||
typedef enum {
|
||||
//============== general Quake services ==================
|
||||
|
||||
G_PRINT, // ( const char *string );
|
||||
// print message on the local console
|
||||
|
||||
G_ERROR, // ( const char *string );
|
||||
// abort the game
|
||||
|
||||
G_MILLISECONDS, // ( void );
|
||||
// get current time for profiling reasons
|
||||
// this should NOT be used for any game related tasks,
|
||||
// because it is not journaled
|
||||
|
||||
// console variable interaction
|
||||
G_CVAR_REGISTER, // ( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
|
||||
G_CVAR_UPDATE, // ( vmCvar_t *vmCvar );
|
||||
G_CVAR_SET, // ( const char *var_name, const char *value );
|
||||
G_CVAR_VARIABLE_INTEGER_VALUE, // ( const char *var_name );
|
||||
|
||||
G_CVAR_VARIABLE_STRING_BUFFER, // ( const char *var_name, char *buffer, int bufsize );
|
||||
|
||||
G_ARGC, // ( void );
|
||||
// ClientCommand and ServerCommand parameter access
|
||||
|
||||
G_ARGV, // ( int n, char *buffer, int bufferLength );
|
||||
|
||||
G_FS_FOPEN_FILE, // ( const char *qpath, fileHandle_t *file, fsMode_t mode );
|
||||
G_FS_READ, // ( void *buffer, int len, fileHandle_t f );
|
||||
G_FS_WRITE, // ( const void *buffer, int len, fileHandle_t f );
|
||||
G_FS_FCLOSE_FILE, // ( fileHandle_t f );
|
||||
|
||||
G_SEND_CONSOLE_COMMAND, // ( const char *text );
|
||||
// add commands to the console as if they were typed in
|
||||
// for map changing, etc
|
||||
|
||||
|
||||
//=========== server specific functionality =============
|
||||
|
||||
G_LOCATE_GAME_DATA, // ( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
|
||||
// playerState_t *clients, int sizeofGameClient );
|
||||
// the game needs to let the server system know where and how big the gentities
|
||||
// are, so it can look at them directly without going through an interface
|
||||
|
||||
G_DROP_CLIENT, // ( int clientNum, const char *reason );
|
||||
// kick a client off the server with a message
|
||||
|
||||
G_SEND_SERVER_COMMAND, // ( int clientNum, const char *fmt, ... );
|
||||
// reliably sends a command string to be interpreted by the given
|
||||
// client. If clientNum is -1, it will be sent to all clients
|
||||
|
||||
G_SET_CONFIGSTRING, // ( int num, const char *string );
|
||||
// config strings hold all the index strings, and various other information
|
||||
// that is reliably communicated to all clients
|
||||
// All of the current configstrings are sent to clients when
|
||||
// they connect, and changes are sent to all connected clients.
|
||||
// All confgstrings are cleared at each level start.
|
||||
|
||||
G_GET_CONFIGSTRING, // ( int num, char *buffer, int bufferSize );
|
||||
|
||||
G_GET_USERINFO, // ( int num, char *buffer, int bufferSize );
|
||||
// userinfo strings are maintained by the server system, so they
|
||||
// are persistant across level loads, while all other game visible
|
||||
// data is completely reset
|
||||
|
||||
G_SET_USERINFO, // ( int num, const char *buffer );
|
||||
|
||||
G_GET_SERVERINFO, // ( char *buffer, int bufferSize );
|
||||
// the serverinfo info string has all the cvars visible to server browsers
|
||||
|
||||
G_SET_BRUSH_MODEL, // ( gentity_t *ent, const char *name );
|
||||
// sets mins and maxs based on the brushmodel name
|
||||
|
||||
G_TRACE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
|
||||
// collision detection against all linked entities
|
||||
|
||||
G_POINT_CONTENTS, // ( const vec3_t point, int passEntityNum );
|
||||
// point contents against all linked entities
|
||||
|
||||
G_IN_PVS, // ( const vec3_t p1, const vec3_t p2 );
|
||||
|
||||
G_IN_PVS_IGNORE_PORTALS, // ( const vec3_t p1, const vec3_t p2 );
|
||||
|
||||
G_ADJUST_AREA_PORTAL_STATE, // ( gentity_t *ent, qboolean open );
|
||||
|
||||
G_AREAS_CONNECTED, // ( int area1, int area2 );
|
||||
|
||||
G_LINKENTITY, // ( gentity_t *ent );
|
||||
// an entity will never be sent to a client or used for collision
|
||||
// if it is not passed to linkentity. If the size, position, or
|
||||
// solidity changes, it must be relinked.
|
||||
|
||||
G_UNLINKENTITY, // ( gentity_t *ent );
|
||||
// call before removing an interactive entity
|
||||
|
||||
G_ENTITIES_IN_BOX, // ( const vec3_t mins, const vec3_t maxs, gentity_t **list, int maxcount );
|
||||
// EntitiesInBox will return brush models based on their bounding box,
|
||||
// so exact determination must still be done with EntityContact
|
||||
|
||||
G_ENTITY_CONTACT, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
|
||||
// perform an exact check against inline brush models of non-square shape
|
||||
|
||||
G_GET_USERCMD, // ( int clientNum, usercmd_t *cmd )
|
||||
|
||||
G_GET_ENTITY_TOKEN, // qboolean ( char *buffer, int bufferSize )
|
||||
// Retrieves the next string token from the entity spawn text, returning
|
||||
// false when all tokens have been parsed.
|
||||
// This should only be done at GAME_INIT time.
|
||||
|
||||
G_FS_GETFILELIST,
|
||||
G_REAL_TIME,
|
||||
G_SNAPVECTOR,
|
||||
|
||||
G_TRACECAPSULE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
|
||||
G_ENTITY_CONTACTCAPSULE, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
|
||||
|
||||
// 1.32
|
||||
G_FS_SEEK,
|
||||
|
||||
G_PARSE_ADD_GLOBAL_DEFINE,
|
||||
G_PARSE_LOAD_SOURCE,
|
||||
G_PARSE_FREE_SOURCE,
|
||||
G_PARSE_READ_TOKEN,
|
||||
G_PARSE_SOURCE_FILE_AND_LINE,
|
||||
|
||||
G_SEND_GAMESTAT
|
||||
} gameImport_t;
|
||||
|
||||
|
||||
//
|
||||
// functions exported by the game subsystem
|
||||
//
|
||||
typedef enum {
|
||||
GAME_INIT, // ( int levelTime, int randomSeed, int restart );
|
||||
// init and shutdown will be called every single level
|
||||
// The game should call G_GET_ENTITY_TOKEN to parse through all the
|
||||
// entity configuration text and spawn gentities.
|
||||
|
||||
GAME_SHUTDOWN, // (void);
|
||||
|
||||
GAME_CLIENT_CONNECT, // ( int clientNum, qboolean firstTime );
|
||||
// return NULL if the client is allowed to connect, otherwise return
|
||||
// a text string with the reason for denial
|
||||
|
||||
GAME_CLIENT_BEGIN, // ( int clientNum );
|
||||
|
||||
GAME_CLIENT_USERINFO_CHANGED, // ( int clientNum );
|
||||
|
||||
GAME_CLIENT_DISCONNECT, // ( int clientNum );
|
||||
|
||||
GAME_CLIENT_COMMAND, // ( int clientNum );
|
||||
|
||||
GAME_CLIENT_THINK, // ( int clientNum );
|
||||
|
||||
GAME_RUN_FRAME, // ( int levelTime );
|
||||
|
||||
GAME_CONSOLE_COMMAND // ( void );
|
||||
// ConsoleCommand will be called when a command has been issued
|
||||
// that is not recognized as a builtin function.
|
||||
// The game can issue trap_argc() / trap_argv() commands to get the command
|
||||
// and parameters. Return qfalse if the game doesn't recognize it as a command.
|
||||
} gameExport_t;
|
||||
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// g_public.h -- game module information visible to server
|
||||
|
||||
#define GAME_API_VERSION 8
|
||||
|
||||
// entity->svFlags
|
||||
// the server does not know how to interpret most of the values
|
||||
// in entityStates (level eType), so the game must explicitly flag
|
||||
// special server behaviors
|
||||
#define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects
|
||||
|
||||
// TTimo
|
||||
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=551
|
||||
#define SVF_CLIENTMASK 0x00000002
|
||||
|
||||
#define SVF_BROADCAST 0x00000020 // send to all connected clients
|
||||
#define SVF_PORTAL 0x00000040 // merge a second pvs at origin2 into snapshots
|
||||
#define SVF_USE_CURRENT_ORIGIN 0x00000080 // entity->r.currentOrigin instead of entity->s.origin
|
||||
// for link position (missiles and movers)
|
||||
#define SVF_SINGLECLIENT 0x00000100 // only send to a single client (entityShared_t->singleClient)
|
||||
#define SVF_NOSERVERINFO 0x00000200 // don't send CS_SERVERINFO updates to this client
|
||||
// so that it can be updated for ping tools without
|
||||
// lagging clients
|
||||
#define SVF_CAPSULE 0x00000400 // use capsule for collision detection instead of bbox
|
||||
#define SVF_NOTSINGLECLIENT 0x00000800 // send entity to everyone but one client
|
||||
// (entityShared_t->singleClient)
|
||||
|
||||
//===============================================================
|
||||
|
||||
|
||||
typedef struct {
|
||||
entityState_t s; // communicated by server to clients
|
||||
|
||||
qboolean linked; // qfalse if not in any good cluster
|
||||
int linkcount;
|
||||
|
||||
int svFlags; // SVF_NOCLIENT, SVF_BROADCAST, etc
|
||||
int singleClient; // only send to this client when SVF_SINGLECLIENT is set
|
||||
|
||||
qboolean bmodel; // if false, assume an explicit mins / maxs bounding box
|
||||
// only set by trap_SetBrushModel
|
||||
vec3_t mins, maxs;
|
||||
int contents; // CONTENTS_TRIGGER, CONTENTS_SOLID, CONTENTS_BODY, etc
|
||||
// a non-solid entity should set to 0
|
||||
|
||||
vec3_t absmin, absmax; // derived from mins/maxs and origin + rotation
|
||||
|
||||
// currentOrigin will be used for all collision detection and world linking.
|
||||
// it will not necessarily be the same as the trajectory evaluation for the current
|
||||
// time, because each entity must be moved one at a time after time is advanced
|
||||
// to avoid simultanious collision issues
|
||||
vec3_t currentOrigin;
|
||||
vec3_t currentAngles;
|
||||
|
||||
// when a trace call is made and passEntityNum != ENTITYNUM_NONE,
|
||||
// an ent will be excluded from testing if:
|
||||
// ent->s.number == passEntityNum (don't interact with self)
|
||||
// ent->s.ownerNum = passEntityNum (don't interact with your own missiles)
|
||||
// entity[ent->s.ownerNum].ownerNum = passEntityNum (don't interact with other missiles from owner)
|
||||
int ownerNum;
|
||||
} entityShared_t;
|
||||
|
||||
|
||||
|
||||
// the server looks at a sharedEntity, which is the start of the game's gentity_t structure
|
||||
typedef struct {
|
||||
entityState_t s; // communicated by server to clients
|
||||
entityShared_t r; // shared by both the server system and game
|
||||
} sharedEntity_t;
|
||||
|
||||
|
||||
|
||||
//===============================================================
|
||||
|
||||
//
|
||||
// system traps provided by the main engine
|
||||
//
|
||||
typedef enum {
|
||||
//============== general Quake services ==================
|
||||
|
||||
G_PRINT, // ( const char *string );
|
||||
// print message on the local console
|
||||
|
||||
G_ERROR, // ( const char *string );
|
||||
// abort the game
|
||||
|
||||
G_MILLISECONDS, // ( void );
|
||||
// get current time for profiling reasons
|
||||
// this should NOT be used for any game related tasks,
|
||||
// because it is not journaled
|
||||
|
||||
// console variable interaction
|
||||
G_CVAR_REGISTER, // ( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
|
||||
G_CVAR_UPDATE, // ( vmCvar_t *vmCvar );
|
||||
G_CVAR_SET, // ( const char *var_name, const char *value );
|
||||
G_CVAR_VARIABLE_INTEGER_VALUE, // ( const char *var_name );
|
||||
|
||||
G_CVAR_VARIABLE_STRING_BUFFER, // ( const char *var_name, char *buffer, int bufsize );
|
||||
|
||||
G_ARGC, // ( void );
|
||||
// ClientCommand and ServerCommand parameter access
|
||||
|
||||
G_ARGV, // ( int n, char *buffer, int bufferLength );
|
||||
|
||||
G_FS_FOPEN_FILE, // ( const char *qpath, fileHandle_t *file, fsMode_t mode );
|
||||
G_FS_READ, // ( void *buffer, int len, fileHandle_t f );
|
||||
G_FS_WRITE, // ( const void *buffer, int len, fileHandle_t f );
|
||||
G_FS_FCLOSE_FILE, // ( fileHandle_t f );
|
||||
|
||||
G_SEND_CONSOLE_COMMAND, // ( const char *text );
|
||||
// add commands to the console as if they were typed in
|
||||
// for map changing, etc
|
||||
|
||||
|
||||
//=========== server specific functionality =============
|
||||
|
||||
G_LOCATE_GAME_DATA, // ( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
|
||||
// playerState_t *clients, int sizeofGameClient );
|
||||
// the game needs to let the server system know where and how big the gentities
|
||||
// are, so it can look at them directly without going through an interface
|
||||
|
||||
G_DROP_CLIENT, // ( int clientNum, const char *reason );
|
||||
// kick a client off the server with a message
|
||||
|
||||
G_SEND_SERVER_COMMAND, // ( int clientNum, const char *fmt, ... );
|
||||
// reliably sends a command string to be interpreted by the given
|
||||
// client. If clientNum is -1, it will be sent to all clients
|
||||
|
||||
G_SET_CONFIGSTRING, // ( int num, const char *string );
|
||||
// config strings hold all the index strings, and various other information
|
||||
// that is reliably communicated to all clients
|
||||
// All of the current configstrings are sent to clients when
|
||||
// they connect, and changes are sent to all connected clients.
|
||||
// All confgstrings are cleared at each level start.
|
||||
|
||||
G_GET_CONFIGSTRING, // ( int num, char *buffer, int bufferSize );
|
||||
|
||||
G_GET_USERINFO, // ( int num, char *buffer, int bufferSize );
|
||||
// userinfo strings are maintained by the server system, so they
|
||||
// are persistant across level loads, while all other game visible
|
||||
// data is completely reset
|
||||
|
||||
G_SET_USERINFO, // ( int num, const char *buffer );
|
||||
|
||||
G_GET_SERVERINFO, // ( char *buffer, int bufferSize );
|
||||
// the serverinfo info string has all the cvars visible to server browsers
|
||||
|
||||
G_SET_BRUSH_MODEL, // ( gentity_t *ent, const char *name );
|
||||
// sets mins and maxs based on the brushmodel name
|
||||
|
||||
G_TRACE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
|
||||
// collision detection against all linked entities
|
||||
|
||||
G_POINT_CONTENTS, // ( const vec3_t point, int passEntityNum );
|
||||
// point contents against all linked entities
|
||||
|
||||
G_IN_PVS, // ( const vec3_t p1, const vec3_t p2 );
|
||||
|
||||
G_IN_PVS_IGNORE_PORTALS, // ( const vec3_t p1, const vec3_t p2 );
|
||||
|
||||
G_ADJUST_AREA_PORTAL_STATE, // ( gentity_t *ent, qboolean open );
|
||||
|
||||
G_AREAS_CONNECTED, // ( int area1, int area2 );
|
||||
|
||||
G_LINKENTITY, // ( gentity_t *ent );
|
||||
// an entity will never be sent to a client or used for collision
|
||||
// if it is not passed to linkentity. If the size, position, or
|
||||
// solidity changes, it must be relinked.
|
||||
|
||||
G_UNLINKENTITY, // ( gentity_t *ent );
|
||||
// call before removing an interactive entity
|
||||
|
||||
G_ENTITIES_IN_BOX, // ( const vec3_t mins, const vec3_t maxs, gentity_t **list, int maxcount );
|
||||
// EntitiesInBox will return brush models based on their bounding box,
|
||||
// so exact determination must still be done with EntityContact
|
||||
|
||||
G_ENTITY_CONTACT, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
|
||||
// perform an exact check against inline brush models of non-square shape
|
||||
|
||||
G_GET_USERCMD, // ( int clientNum, usercmd_t *cmd )
|
||||
|
||||
G_GET_ENTITY_TOKEN, // qboolean ( char *buffer, int bufferSize )
|
||||
// Retrieves the next string token from the entity spawn text, returning
|
||||
// false when all tokens have been parsed.
|
||||
// This should only be done at GAME_INIT time.
|
||||
|
||||
G_FS_GETFILELIST,
|
||||
G_REAL_TIME,
|
||||
G_SNAPVECTOR,
|
||||
|
||||
G_TRACECAPSULE, // ( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask );
|
||||
G_ENTITY_CONTACTCAPSULE, // ( const vec3_t mins, const vec3_t maxs, const gentity_t *ent );
|
||||
|
||||
// 1.32
|
||||
G_FS_SEEK,
|
||||
|
||||
G_PARSE_ADD_GLOBAL_DEFINE,
|
||||
G_PARSE_LOAD_SOURCE,
|
||||
G_PARSE_FREE_SOURCE,
|
||||
G_PARSE_READ_TOKEN,
|
||||
G_PARSE_SOURCE_FILE_AND_LINE,
|
||||
|
||||
G_SEND_GAMESTAT
|
||||
} gameImport_t;
|
||||
|
||||
|
||||
//
|
||||
// functions exported by the game subsystem
|
||||
//
|
||||
typedef enum {
|
||||
GAME_INIT, // ( int levelTime, int randomSeed, int restart );
|
||||
// init and shutdown will be called every single level
|
||||
// The game should call G_GET_ENTITY_TOKEN to parse through all the
|
||||
// entity configuration text and spawn gentities.
|
||||
|
||||
GAME_SHUTDOWN, // (void);
|
||||
|
||||
GAME_CLIENT_CONNECT, // ( int clientNum, qboolean firstTime );
|
||||
// return NULL if the client is allowed to connect, otherwise return
|
||||
// a text string with the reason for denial
|
||||
|
||||
GAME_CLIENT_BEGIN, // ( int clientNum );
|
||||
|
||||
GAME_CLIENT_USERINFO_CHANGED, // ( int clientNum );
|
||||
|
||||
GAME_CLIENT_DISCONNECT, // ( int clientNum );
|
||||
|
||||
GAME_CLIENT_COMMAND, // ( int clientNum );
|
||||
|
||||
GAME_CLIENT_THINK, // ( int clientNum );
|
||||
|
||||
GAME_RUN_FRAME, // ( int levelTime );
|
||||
|
||||
GAME_CONSOLE_COMMAND // ( void );
|
||||
// ConsoleCommand will be called when a command has been issued
|
||||
// that is not recognized as a builtin function.
|
||||
// The game can issue trap_argc() / trap_argv() commands to get the command
|
||||
// and parameters. Return qfalse if the game doesn't recognize it as a command.
|
||||
} gameExport_t;
|
||||
|
||||
+65
-65
@@ -1,65 +1,65 @@
|
||||
code
|
||||
|
||||
equ trap_Printf -1
|
||||
equ trap_Error -2
|
||||
equ trap_Milliseconds -3
|
||||
equ trap_Cvar_Register -4
|
||||
equ trap_Cvar_Update -5
|
||||
equ trap_Cvar_Set -6
|
||||
equ trap_Cvar_VariableIntegerValue -7
|
||||
equ trap_Cvar_VariableStringBuffer -8
|
||||
equ trap_Argc -9
|
||||
equ trap_Argv -10
|
||||
equ trap_FS_FOpenFile -11
|
||||
equ trap_FS_Read -12
|
||||
equ trap_FS_Write -13
|
||||
equ trap_FS_FCloseFile -14
|
||||
equ trap_SendConsoleCommand -15
|
||||
equ trap_LocateGameData -16
|
||||
equ trap_DropClient -17
|
||||
equ trap_SendServerCommand -18
|
||||
equ trap_SetConfigstring -19
|
||||
equ trap_GetConfigstring -20
|
||||
equ trap_GetUserinfo -21
|
||||
equ trap_SetUserinfo -22
|
||||
equ trap_GetServerinfo -23
|
||||
equ trap_SetBrushModel -24
|
||||
equ trap_Trace -25
|
||||
equ trap_PointContents -26
|
||||
equ trap_InPVS -27
|
||||
equ trap_InPVSIgnorePortals -28
|
||||
equ trap_AdjustAreaPortalState -29
|
||||
equ trap_AreasConnected -30
|
||||
equ trap_LinkEntity -31
|
||||
equ trap_UnlinkEntity -32
|
||||
equ trap_EntitiesInBox -33
|
||||
equ trap_EntityContact -34
|
||||
equ trap_GetUsercmd -35
|
||||
equ trap_GetEntityToken -36
|
||||
equ trap_FS_GetFileList -37
|
||||
equ trap_RealTime -38
|
||||
equ trap_SnapVector -39
|
||||
equ trap_TraceCapsule -40
|
||||
equ trap_EntityContactCapsule -41
|
||||
equ trap_FS_Seek -42
|
||||
|
||||
equ trap_Parse_AddGlobalDefine -43
|
||||
equ trap_Parse_LoadSource -44
|
||||
equ trap_Parse_FreeSource -45
|
||||
equ trap_Parse_ReadToken -46
|
||||
equ trap_Parse_SourceFileAndLine -47
|
||||
|
||||
equ trap_SendGameStat -48
|
||||
|
||||
|
||||
equ memset -101
|
||||
equ memcpy -102
|
||||
equ strncpy -103
|
||||
equ sin -104
|
||||
equ cos -105
|
||||
equ atan2 -106
|
||||
equ sqrt -107
|
||||
equ floor -111
|
||||
equ ceil -112
|
||||
equ testPrintInt -113
|
||||
equ testPrintFloat -114
|
||||
code
|
||||
|
||||
equ trap_Printf -1
|
||||
equ trap_Error -2
|
||||
equ trap_Milliseconds -3
|
||||
equ trap_Cvar_Register -4
|
||||
equ trap_Cvar_Update -5
|
||||
equ trap_Cvar_Set -6
|
||||
equ trap_Cvar_VariableIntegerValue -7
|
||||
equ trap_Cvar_VariableStringBuffer -8
|
||||
equ trap_Argc -9
|
||||
equ trap_Argv -10
|
||||
equ trap_FS_FOpenFile -11
|
||||
equ trap_FS_Read -12
|
||||
equ trap_FS_Write -13
|
||||
equ trap_FS_FCloseFile -14
|
||||
equ trap_SendConsoleCommand -15
|
||||
equ trap_LocateGameData -16
|
||||
equ trap_DropClient -17
|
||||
equ trap_SendServerCommand -18
|
||||
equ trap_SetConfigstring -19
|
||||
equ trap_GetConfigstring -20
|
||||
equ trap_GetUserinfo -21
|
||||
equ trap_SetUserinfo -22
|
||||
equ trap_GetServerinfo -23
|
||||
equ trap_SetBrushModel -24
|
||||
equ trap_Trace -25
|
||||
equ trap_PointContents -26
|
||||
equ trap_InPVS -27
|
||||
equ trap_InPVSIgnorePortals -28
|
||||
equ trap_AdjustAreaPortalState -29
|
||||
equ trap_AreasConnected -30
|
||||
equ trap_LinkEntity -31
|
||||
equ trap_UnlinkEntity -32
|
||||
equ trap_EntitiesInBox -33
|
||||
equ trap_EntityContact -34
|
||||
equ trap_GetUsercmd -35
|
||||
equ trap_GetEntityToken -36
|
||||
equ trap_FS_GetFileList -37
|
||||
equ trap_RealTime -38
|
||||
equ trap_SnapVector -39
|
||||
equ trap_TraceCapsule -40
|
||||
equ trap_EntityContactCapsule -41
|
||||
equ trap_FS_Seek -42
|
||||
|
||||
equ trap_Parse_AddGlobalDefine -43
|
||||
equ trap_Parse_LoadSource -44
|
||||
equ trap_Parse_FreeSource -45
|
||||
equ trap_Parse_ReadToken -46
|
||||
equ trap_Parse_SourceFileAndLine -47
|
||||
|
||||
equ trap_SendGameStat -48
|
||||
|
||||
|
||||
equ memset -101
|
||||
equ memcpy -102
|
||||
equ strncpy -103
|
||||
equ sin -104
|
||||
equ cos -105
|
||||
equ atan2 -106
|
||||
equ sqrt -107
|
||||
equ floor -111
|
||||
equ ceil -112
|
||||
equ testPrintInt -113
|
||||
equ testPrintFloat -114
|
||||
+284
-284
@@ -1,284 +1,284 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
// this file is only included when building a dll
|
||||
// g_syscalls.asm is included instead when building a qvm
|
||||
|
||||
static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;
|
||||
|
||||
|
||||
void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) )
|
||||
{
|
||||
syscall = syscallptr;
|
||||
}
|
||||
|
||||
int PASSFLOAT( float x )
|
||||
{
|
||||
float floatTemp;
|
||||
floatTemp = x;
|
||||
return *(int *)&floatTemp;
|
||||
}
|
||||
|
||||
void trap_Printf( const char *fmt )
|
||||
{
|
||||
syscall( G_PRINT, fmt );
|
||||
}
|
||||
|
||||
void trap_Error( const char *fmt )
|
||||
{
|
||||
syscall( G_ERROR, fmt );
|
||||
}
|
||||
|
||||
int trap_Milliseconds( void )
|
||||
{
|
||||
return syscall( G_MILLISECONDS );
|
||||
}
|
||||
int trap_Argc( void )
|
||||
{
|
||||
return syscall( G_ARGC );
|
||||
}
|
||||
|
||||
void trap_Argv( int n, char *buffer, int bufferLength )
|
||||
{
|
||||
syscall( G_ARGV, n, buffer, bufferLength );
|
||||
}
|
||||
|
||||
int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode )
|
||||
{
|
||||
return syscall( G_FS_FOPEN_FILE, qpath, f, mode );
|
||||
}
|
||||
|
||||
void trap_FS_Read( void *buffer, int len, fileHandle_t f )
|
||||
{
|
||||
syscall( G_FS_READ, buffer, len, f );
|
||||
}
|
||||
|
||||
void trap_FS_Write( const void *buffer, int len, fileHandle_t f )
|
||||
{
|
||||
syscall( G_FS_WRITE, buffer, len, f );
|
||||
}
|
||||
|
||||
void trap_FS_FCloseFile( fileHandle_t f )
|
||||
{
|
||||
syscall( G_FS_FCLOSE_FILE, f );
|
||||
}
|
||||
|
||||
int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize )
|
||||
{
|
||||
return syscall( G_FS_GETFILELIST, path, extension, listbuf, bufsize );
|
||||
}
|
||||
|
||||
void trap_SendConsoleCommand( int exec_when, const char *text )
|
||||
{
|
||||
syscall( G_SEND_CONSOLE_COMMAND, exec_when, text );
|
||||
}
|
||||
|
||||
void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags )
|
||||
{
|
||||
syscall( G_CVAR_REGISTER, cvar, var_name, value, flags );
|
||||
}
|
||||
|
||||
void trap_Cvar_Update( vmCvar_t *cvar )
|
||||
{
|
||||
syscall( G_CVAR_UPDATE, cvar );
|
||||
}
|
||||
|
||||
void trap_Cvar_Set( const char *var_name, const char *value )
|
||||
{
|
||||
syscall( G_CVAR_SET, var_name, value );
|
||||
}
|
||||
|
||||
int trap_Cvar_VariableIntegerValue( const char *var_name )
|
||||
{
|
||||
return syscall( G_CVAR_VARIABLE_INTEGER_VALUE, var_name );
|
||||
}
|
||||
|
||||
void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize )
|
||||
{
|
||||
syscall( G_CVAR_VARIABLE_STRING_BUFFER, var_name, buffer, bufsize );
|
||||
}
|
||||
|
||||
|
||||
void trap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
|
||||
playerState_t *clients, int sizeofGClient )
|
||||
{
|
||||
syscall( G_LOCATE_GAME_DATA, gEnts, numGEntities, sizeofGEntity_t, clients, sizeofGClient );
|
||||
}
|
||||
|
||||
void trap_DropClient( int clientNum, const char *reason )
|
||||
{
|
||||
syscall( G_DROP_CLIENT, clientNum, reason );
|
||||
}
|
||||
|
||||
void trap_SendServerCommand( int clientNum, const char *text )
|
||||
{
|
||||
syscall( G_SEND_SERVER_COMMAND, clientNum, text );
|
||||
}
|
||||
|
||||
void trap_SetConfigstring( int num, const char *string )
|
||||
{
|
||||
syscall( G_SET_CONFIGSTRING, num, string );
|
||||
}
|
||||
|
||||
void trap_GetConfigstring( int num, char *buffer, int bufferSize )
|
||||
{
|
||||
syscall( G_GET_CONFIGSTRING, num, buffer, bufferSize );
|
||||
}
|
||||
|
||||
void trap_GetUserinfo( int num, char *buffer, int bufferSize )
|
||||
{
|
||||
syscall( G_GET_USERINFO, num, buffer, bufferSize );
|
||||
}
|
||||
|
||||
void trap_SetUserinfo( int num, const char *buffer )
|
||||
{
|
||||
syscall( G_SET_USERINFO, num, buffer );
|
||||
}
|
||||
|
||||
void trap_GetServerinfo( char *buffer, int bufferSize )
|
||||
{
|
||||
syscall( G_GET_SERVERINFO, buffer, bufferSize );
|
||||
}
|
||||
|
||||
void trap_SetBrushModel( gentity_t *ent, const char *name )
|
||||
{
|
||||
syscall( G_SET_BRUSH_MODEL, ent, name );
|
||||
}
|
||||
|
||||
void trap_Trace( trace_t *results, const vec3_t start, const vec3_t mins,
|
||||
const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask )
|
||||
{
|
||||
syscall( G_TRACE, results, start, mins, maxs, end, passEntityNum, contentmask );
|
||||
}
|
||||
|
||||
void trap_TraceCapsule( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask )
|
||||
{
|
||||
syscall( G_TRACECAPSULE, results, start, mins, maxs, end, passEntityNum, contentmask );
|
||||
}
|
||||
|
||||
int trap_PointContents( const vec3_t point, int passEntityNum )
|
||||
{
|
||||
return syscall( G_POINT_CONTENTS, point, passEntityNum );
|
||||
}
|
||||
|
||||
|
||||
qboolean trap_InPVS( const vec3_t p1, const vec3_t p2 )
|
||||
{
|
||||
return syscall( G_IN_PVS, p1, p2 );
|
||||
}
|
||||
|
||||
qboolean trap_InPVSIgnorePortals( const vec3_t p1, const vec3_t p2 )
|
||||
{
|
||||
return syscall( G_IN_PVS_IGNORE_PORTALS, p1, p2 );
|
||||
}
|
||||
|
||||
void trap_AdjustAreaPortalState( gentity_t *ent, qboolean open )
|
||||
{
|
||||
syscall( G_ADJUST_AREA_PORTAL_STATE, ent, open );
|
||||
}
|
||||
|
||||
qboolean trap_AreasConnected( int area1, int area2 )
|
||||
{
|
||||
return syscall( G_AREAS_CONNECTED, area1, area2 );
|
||||
}
|
||||
|
||||
void trap_LinkEntity( gentity_t *ent )
|
||||
{
|
||||
syscall( G_LINKENTITY, ent );
|
||||
}
|
||||
|
||||
void trap_UnlinkEntity( gentity_t *ent )
|
||||
{
|
||||
syscall( G_UNLINKENTITY, ent );
|
||||
}
|
||||
|
||||
|
||||
int trap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *list, int maxcount )
|
||||
{
|
||||
return syscall( G_ENTITIES_IN_BOX, mins, maxs, list, maxcount );
|
||||
}
|
||||
|
||||
qboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent )
|
||||
{
|
||||
return syscall( G_ENTITY_CONTACT, mins, maxs, ent );
|
||||
}
|
||||
|
||||
qboolean trap_EntityContactCapsule( const vec3_t mins, const vec3_t maxs, const gentity_t *ent )
|
||||
{
|
||||
return syscall( G_ENTITY_CONTACTCAPSULE, mins, maxs, ent );
|
||||
}
|
||||
|
||||
void trap_GetUsercmd( int clientNum, usercmd_t *cmd )
|
||||
{
|
||||
syscall( G_GET_USERCMD, clientNum, cmd );
|
||||
}
|
||||
|
||||
qboolean trap_GetEntityToken( char *buffer, int bufferSize )
|
||||
{
|
||||
return syscall( G_GET_ENTITY_TOKEN, buffer, bufferSize );
|
||||
}
|
||||
|
||||
int trap_RealTime( qtime_t *qtime )
|
||||
{
|
||||
return syscall( G_REAL_TIME, qtime );
|
||||
}
|
||||
|
||||
void trap_SnapVector( float *v )
|
||||
{
|
||||
syscall( G_SNAPVECTOR, v );
|
||||
return;
|
||||
}
|
||||
|
||||
void trap_SendGameStat( const char *data )
|
||||
{
|
||||
syscall( G_SEND_GAMESTAT, data );
|
||||
return;
|
||||
}
|
||||
|
||||
int trap_Parse_AddGlobalDefine( char *define )
|
||||
{
|
||||
return syscall( G_PARSE_ADD_GLOBAL_DEFINE, define );
|
||||
}
|
||||
|
||||
int trap_Parse_LoadSource( const char *filename )
|
||||
{
|
||||
return syscall( G_PARSE_LOAD_SOURCE, filename );
|
||||
}
|
||||
|
||||
int trap_Parse_FreeSource( int handle )
|
||||
{
|
||||
return syscall( G_PARSE_FREE_SOURCE, handle );
|
||||
}
|
||||
|
||||
int trap_Parse_ReadToken( int handle, pc_token_t *pc_token )
|
||||
{
|
||||
return syscall( G_PARSE_READ_TOKEN, handle, pc_token );
|
||||
}
|
||||
|
||||
int trap_Parse_SourceFileAndLine( int handle, char *filename, int *line )
|
||||
{
|
||||
return syscall( G_PARSE_SOURCE_FILE_AND_LINE, handle, filename, line );
|
||||
}
|
||||
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
// this file is only included when building a dll
|
||||
// g_syscalls.asm is included instead when building a qvm
|
||||
|
||||
static intptr_t (QDECL *syscall)( intptr_t arg, ... ) = (intptr_t (QDECL *)( intptr_t, ...))-1;
|
||||
|
||||
|
||||
void dllEntry( intptr_t (QDECL *syscallptr)( intptr_t arg,... ) )
|
||||
{
|
||||
syscall = syscallptr;
|
||||
}
|
||||
|
||||
int PASSFLOAT( float x )
|
||||
{
|
||||
float floatTemp;
|
||||
floatTemp = x;
|
||||
return *(int *)&floatTemp;
|
||||
}
|
||||
|
||||
void trap_Printf( const char *fmt )
|
||||
{
|
||||
syscall( G_PRINT, fmt );
|
||||
}
|
||||
|
||||
void trap_Error( const char *fmt )
|
||||
{
|
||||
syscall( G_ERROR, fmt );
|
||||
}
|
||||
|
||||
int trap_Milliseconds( void )
|
||||
{
|
||||
return syscall( G_MILLISECONDS );
|
||||
}
|
||||
int trap_Argc( void )
|
||||
{
|
||||
return syscall( G_ARGC );
|
||||
}
|
||||
|
||||
void trap_Argv( int n, char *buffer, int bufferLength )
|
||||
{
|
||||
syscall( G_ARGV, n, buffer, bufferLength );
|
||||
}
|
||||
|
||||
int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode )
|
||||
{
|
||||
return syscall( G_FS_FOPEN_FILE, qpath, f, mode );
|
||||
}
|
||||
|
||||
void trap_FS_Read( void *buffer, int len, fileHandle_t f )
|
||||
{
|
||||
syscall( G_FS_READ, buffer, len, f );
|
||||
}
|
||||
|
||||
void trap_FS_Write( const void *buffer, int len, fileHandle_t f )
|
||||
{
|
||||
syscall( G_FS_WRITE, buffer, len, f );
|
||||
}
|
||||
|
||||
void trap_FS_FCloseFile( fileHandle_t f )
|
||||
{
|
||||
syscall( G_FS_FCLOSE_FILE, f );
|
||||
}
|
||||
|
||||
int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize )
|
||||
{
|
||||
return syscall( G_FS_GETFILELIST, path, extension, listbuf, bufsize );
|
||||
}
|
||||
|
||||
void trap_SendConsoleCommand( int exec_when, const char *text )
|
||||
{
|
||||
syscall( G_SEND_CONSOLE_COMMAND, exec_when, text );
|
||||
}
|
||||
|
||||
void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags )
|
||||
{
|
||||
syscall( G_CVAR_REGISTER, cvar, var_name, value, flags );
|
||||
}
|
||||
|
||||
void trap_Cvar_Update( vmCvar_t *cvar )
|
||||
{
|
||||
syscall( G_CVAR_UPDATE, cvar );
|
||||
}
|
||||
|
||||
void trap_Cvar_Set( const char *var_name, const char *value )
|
||||
{
|
||||
syscall( G_CVAR_SET, var_name, value );
|
||||
}
|
||||
|
||||
int trap_Cvar_VariableIntegerValue( const char *var_name )
|
||||
{
|
||||
return syscall( G_CVAR_VARIABLE_INTEGER_VALUE, var_name );
|
||||
}
|
||||
|
||||
void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize )
|
||||
{
|
||||
syscall( G_CVAR_VARIABLE_STRING_BUFFER, var_name, buffer, bufsize );
|
||||
}
|
||||
|
||||
|
||||
void trap_LocateGameData( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t,
|
||||
playerState_t *clients, int sizeofGClient )
|
||||
{
|
||||
syscall( G_LOCATE_GAME_DATA, gEnts, numGEntities, sizeofGEntity_t, clients, sizeofGClient );
|
||||
}
|
||||
|
||||
void trap_DropClient( int clientNum, const char *reason )
|
||||
{
|
||||
syscall( G_DROP_CLIENT, clientNum, reason );
|
||||
}
|
||||
|
||||
void trap_SendServerCommand( int clientNum, const char *text )
|
||||
{
|
||||
syscall( G_SEND_SERVER_COMMAND, clientNum, text );
|
||||
}
|
||||
|
||||
void trap_SetConfigstring( int num, const char *string )
|
||||
{
|
||||
syscall( G_SET_CONFIGSTRING, num, string );
|
||||
}
|
||||
|
||||
void trap_GetConfigstring( int num, char *buffer, int bufferSize )
|
||||
{
|
||||
syscall( G_GET_CONFIGSTRING, num, buffer, bufferSize );
|
||||
}
|
||||
|
||||
void trap_GetUserinfo( int num, char *buffer, int bufferSize )
|
||||
{
|
||||
syscall( G_GET_USERINFO, num, buffer, bufferSize );
|
||||
}
|
||||
|
||||
void trap_SetUserinfo( int num, const char *buffer )
|
||||
{
|
||||
syscall( G_SET_USERINFO, num, buffer );
|
||||
}
|
||||
|
||||
void trap_GetServerinfo( char *buffer, int bufferSize )
|
||||
{
|
||||
syscall( G_GET_SERVERINFO, buffer, bufferSize );
|
||||
}
|
||||
|
||||
void trap_SetBrushModel( gentity_t *ent, const char *name )
|
||||
{
|
||||
syscall( G_SET_BRUSH_MODEL, ent, name );
|
||||
}
|
||||
|
||||
void trap_Trace( trace_t *results, const vec3_t start, const vec3_t mins,
|
||||
const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask )
|
||||
{
|
||||
syscall( G_TRACE, results, start, mins, maxs, end, passEntityNum, contentmask );
|
||||
}
|
||||
|
||||
void trap_TraceCapsule( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask )
|
||||
{
|
||||
syscall( G_TRACECAPSULE, results, start, mins, maxs, end, passEntityNum, contentmask );
|
||||
}
|
||||
|
||||
int trap_PointContents( const vec3_t point, int passEntityNum )
|
||||
{
|
||||
return syscall( G_POINT_CONTENTS, point, passEntityNum );
|
||||
}
|
||||
|
||||
|
||||
qboolean trap_InPVS( const vec3_t p1, const vec3_t p2 )
|
||||
{
|
||||
return syscall( G_IN_PVS, p1, p2 );
|
||||
}
|
||||
|
||||
qboolean trap_InPVSIgnorePortals( const vec3_t p1, const vec3_t p2 )
|
||||
{
|
||||
return syscall( G_IN_PVS_IGNORE_PORTALS, p1, p2 );
|
||||
}
|
||||
|
||||
void trap_AdjustAreaPortalState( gentity_t *ent, qboolean open )
|
||||
{
|
||||
syscall( G_ADJUST_AREA_PORTAL_STATE, ent, open );
|
||||
}
|
||||
|
||||
qboolean trap_AreasConnected( int area1, int area2 )
|
||||
{
|
||||
return syscall( G_AREAS_CONNECTED, area1, area2 );
|
||||
}
|
||||
|
||||
void trap_LinkEntity( gentity_t *ent )
|
||||
{
|
||||
syscall( G_LINKENTITY, ent );
|
||||
}
|
||||
|
||||
void trap_UnlinkEntity( gentity_t *ent )
|
||||
{
|
||||
syscall( G_UNLINKENTITY, ent );
|
||||
}
|
||||
|
||||
|
||||
int trap_EntitiesInBox( const vec3_t mins, const vec3_t maxs, int *list, int maxcount )
|
||||
{
|
||||
return syscall( G_ENTITIES_IN_BOX, mins, maxs, list, maxcount );
|
||||
}
|
||||
|
||||
qboolean trap_EntityContact( const vec3_t mins, const vec3_t maxs, const gentity_t *ent )
|
||||
{
|
||||
return syscall( G_ENTITY_CONTACT, mins, maxs, ent );
|
||||
}
|
||||
|
||||
qboolean trap_EntityContactCapsule( const vec3_t mins, const vec3_t maxs, const gentity_t *ent )
|
||||
{
|
||||
return syscall( G_ENTITY_CONTACTCAPSULE, mins, maxs, ent );
|
||||
}
|
||||
|
||||
void trap_GetUsercmd( int clientNum, usercmd_t *cmd )
|
||||
{
|
||||
syscall( G_GET_USERCMD, clientNum, cmd );
|
||||
}
|
||||
|
||||
qboolean trap_GetEntityToken( char *buffer, int bufferSize )
|
||||
{
|
||||
return syscall( G_GET_ENTITY_TOKEN, buffer, bufferSize );
|
||||
}
|
||||
|
||||
int trap_RealTime( qtime_t *qtime )
|
||||
{
|
||||
return syscall( G_REAL_TIME, qtime );
|
||||
}
|
||||
|
||||
void trap_SnapVector( float *v )
|
||||
{
|
||||
syscall( G_SNAPVECTOR, v );
|
||||
return;
|
||||
}
|
||||
|
||||
void trap_SendGameStat( const char *data )
|
||||
{
|
||||
syscall( G_SEND_GAMESTAT, data );
|
||||
return;
|
||||
}
|
||||
|
||||
int trap_Parse_AddGlobalDefine( char *define )
|
||||
{
|
||||
return syscall( G_PARSE_ADD_GLOBAL_DEFINE, define );
|
||||
}
|
||||
|
||||
int trap_Parse_LoadSource( const char *filename )
|
||||
{
|
||||
return syscall( G_PARSE_LOAD_SOURCE, filename );
|
||||
}
|
||||
|
||||
int trap_Parse_FreeSource( int handle )
|
||||
{
|
||||
return syscall( G_PARSE_FREE_SOURCE, handle );
|
||||
}
|
||||
|
||||
int trap_Parse_ReadToken( int handle, pc_token_t *pc_token )
|
||||
{
|
||||
return syscall( G_PARSE_READ_TOKEN, handle, pc_token );
|
||||
}
|
||||
|
||||
int trap_Parse_SourceFileAndLine( int handle, char *filename, int *line )
|
||||
{
|
||||
return syscall( G_PARSE_SOURCE_FILE_AND_LINE, handle, filename, line );
|
||||
}
|
||||
|
||||
+472
-472
@@ -1,472 +1,472 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
//==========================================================
|
||||
|
||||
/*QUAKED target_delay (1 0 0) (-8 -8 -8) (8 8 8)
|
||||
"wait" seconds to pause before firing targets.
|
||||
"random" delay variance, total delay = delay +/- random seconds
|
||||
*/
|
||||
void Think_Target_Delay( gentity_t *ent )
|
||||
{
|
||||
G_UseTargets( ent, ent->activator );
|
||||
}
|
||||
|
||||
void Use_Target_Delay( gentity_t *ent, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
ent->nextthink = level.time + ( ent->wait + ent->random * crandom( ) ) * 1000;
|
||||
ent->think = Think_Target_Delay;
|
||||
ent->activator = activator;
|
||||
}
|
||||
|
||||
void SP_target_delay( gentity_t *ent )
|
||||
{
|
||||
// check delay for backwards compatability
|
||||
if( !G_SpawnFloat( "delay", "0", &ent->wait ) )
|
||||
G_SpawnFloat( "wait", "1", &ent->wait );
|
||||
|
||||
if( !ent->wait )
|
||||
ent->wait = 1;
|
||||
|
||||
ent->use = Use_Target_Delay;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================
|
||||
|
||||
/*QUAKED target_score (1 0 0) (-8 -8 -8) (8 8 8)
|
||||
"count" number of points to add, default 1
|
||||
|
||||
The activator is given this many points.
|
||||
*/
|
||||
void Use_Target_Score( gentity_t *ent, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
AddScore( activator, ent->count );
|
||||
}
|
||||
|
||||
void SP_target_score( gentity_t *ent )
|
||||
{
|
||||
if( !ent->count )
|
||||
ent->count = 1;
|
||||
|
||||
ent->use = Use_Target_Score;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================
|
||||
|
||||
/*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) humanteam alienteam private
|
||||
"message" text to print
|
||||
If "private", only the activator gets the message. If no checks, all clients get the message.
|
||||
*/
|
||||
void Use_Target_Print( gentity_t *ent, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
if( activator->client && ( ent->spawnflags & 4 ) )
|
||||
{
|
||||
trap_SendServerCommand( activator-g_entities, va( "cp \"%s\"", ent->message ) );
|
||||
return;
|
||||
}
|
||||
|
||||
if( ent->spawnflags & 3 )
|
||||
{
|
||||
if( ent->spawnflags & 1 )
|
||||
G_TeamCommand( PTE_HUMANS, va( "cp \"%s\"", ent->message ) );
|
||||
if( ent->spawnflags & 2 )
|
||||
G_TeamCommand( PTE_ALIENS, va( "cp \"%s\"", ent->message ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ) );
|
||||
}
|
||||
|
||||
void SP_target_print( gentity_t *ent )
|
||||
{
|
||||
ent->use = Use_Target_Print;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================
|
||||
|
||||
|
||||
/*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off global activator
|
||||
"noise" wav file to play
|
||||
|
||||
A global sound will play full volume throughout the level.
|
||||
Activator sounds will play on the player that activated the target.
|
||||
Global and activator sounds can't be combined with looping.
|
||||
Normal sounds play each time the target is used.
|
||||
Looped sounds will be toggled by use functions.
|
||||
Multiple identical looping sounds will just increase volume without any speed cost.
|
||||
"wait" : Seconds between auto triggerings, 0 = don't auto trigger
|
||||
"random" wait variance, default is 0
|
||||
*/
|
||||
void Use_Target_Speaker( gentity_t *ent, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
if( ent->spawnflags & 3 )
|
||||
{ // looping sound toggles
|
||||
if( ent->s.loopSound )
|
||||
ent->s.loopSound = 0; // turn it off
|
||||
else
|
||||
ent->s.loopSound = ent->noise_index; // start it
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal sound
|
||||
if( ent->spawnflags & 8 )
|
||||
G_AddEvent( activator, EV_GENERAL_SOUND, ent->noise_index );
|
||||
else if( ent->spawnflags & 4 )
|
||||
G_AddEvent( ent, EV_GLOBAL_SOUND, ent->noise_index );
|
||||
else
|
||||
G_AddEvent( ent, EV_GENERAL_SOUND, ent->noise_index );
|
||||
}
|
||||
}
|
||||
|
||||
void SP_target_speaker( gentity_t *ent )
|
||||
{
|
||||
char buffer[ MAX_QPATH ];
|
||||
char *s;
|
||||
|
||||
G_SpawnFloat( "wait", "0", &ent->wait );
|
||||
G_SpawnFloat( "random", "0", &ent->random );
|
||||
|
||||
if( !G_SpawnString( "noise", "NOSOUND", &s ) )
|
||||
G_Error( "target_speaker without a noise key at %s", vtos( ent->s.origin ) );
|
||||
|
||||
// force all client reletive sounds to be "activator" speakers that
|
||||
// play on the entity that activates it
|
||||
if( s[ 0 ] == '*' )
|
||||
ent->spawnflags |= 8;
|
||||
|
||||
if( !strstr( s, ".wav" ) )
|
||||
Com_sprintf( buffer, sizeof( buffer ), "%s.wav", s );
|
||||
else
|
||||
Q_strncpyz( buffer, s, sizeof( buffer ) );
|
||||
|
||||
ent->noise_index = G_SoundIndex( buffer );
|
||||
|
||||
// a repeating speaker can be done completely client side
|
||||
ent->s.eType = ET_SPEAKER;
|
||||
ent->s.eventParm = ent->noise_index;
|
||||
ent->s.frame = ent->wait * 10;
|
||||
ent->s.clientNum = ent->random * 10;
|
||||
|
||||
|
||||
// check for prestarted looping sound
|
||||
if( ent->spawnflags & 1 )
|
||||
ent->s.loopSound = ent->noise_index;
|
||||
|
||||
ent->use = Use_Target_Speaker;
|
||||
|
||||
if( ent->spawnflags & 4 )
|
||||
ent->r.svFlags |= SVF_BROADCAST;
|
||||
|
||||
VectorCopy( ent->s.origin, ent->s.pos.trBase );
|
||||
|
||||
// must link the entity so we get areas and clusters so
|
||||
// the server can determine who to send updates to
|
||||
trap_LinkEntity( ent );
|
||||
}
|
||||
|
||||
//==========================================================
|
||||
|
||||
void target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
gentity_t *dest;
|
||||
|
||||
if( !activator->client )
|
||||
return;
|
||||
|
||||
dest = G_PickTarget( self->target );
|
||||
|
||||
if( !dest )
|
||||
{
|
||||
G_Printf( "Couldn't find teleporter destination\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
TeleportPlayer( activator, dest->s.origin, dest->s.angles );
|
||||
}
|
||||
|
||||
/*QUAKED target_teleporter (1 0 0) (-8 -8 -8) (8 8 8)
|
||||
The activator will be teleported away.
|
||||
*/
|
||||
void SP_target_teleporter( gentity_t *self )
|
||||
{
|
||||
if( !self->targetname )
|
||||
G_Printf( "untargeted %s at %s\n", self->classname, vtos( self->s.origin ) );
|
||||
|
||||
self->use = target_teleporter_use;
|
||||
}
|
||||
|
||||
//==========================================================
|
||||
|
||||
|
||||
/*QUAKED target_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) RED_ONLY BLUE_ONLY RANDOM
|
||||
This doesn't perform any actions except fire its targets.
|
||||
The activator can be forced to be from a certain team.
|
||||
if RANDOM is checked, only one of the targets will be fired, not all of them
|
||||
*/
|
||||
void target_relay_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
if( ( self->spawnflags & 1 ) && activator->client &&
|
||||
activator->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS )
|
||||
return;
|
||||
|
||||
if( ( self->spawnflags & 2 ) && activator->client &&
|
||||
activator->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS )
|
||||
return;
|
||||
|
||||
if( self->spawnflags & 4 )
|
||||
{
|
||||
gentity_t *ent;
|
||||
|
||||
ent = G_PickTarget( self->target );
|
||||
if( ent && ent->use )
|
||||
ent->use( ent, self, activator );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
G_UseTargets( self, activator );
|
||||
}
|
||||
|
||||
void SP_target_relay( gentity_t *self )
|
||||
{
|
||||
self->use = target_relay_use;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================
|
||||
|
||||
/*QUAKED target_kill (.5 .5 .5) (-8 -8 -8) (8 8 8)
|
||||
Kills the activator.
|
||||
*/
|
||||
void target_kill_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
G_Damage( activator, NULL, NULL, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG );
|
||||
}
|
||||
|
||||
void SP_target_kill( gentity_t *self )
|
||||
{
|
||||
self->use = target_kill_use;
|
||||
}
|
||||
|
||||
/*QUAKED target_position (0 0.5 0) (-4 -4 -4) (4 4 4)
|
||||
Used as a positional target for in-game calculation, like jumppad targets.
|
||||
*/
|
||||
void SP_target_position( gentity_t *self )
|
||||
{
|
||||
G_SetOrigin( self, self->s.origin );
|
||||
}
|
||||
|
||||
static void target_location_linkup( gentity_t *ent )
|
||||
{
|
||||
int i;
|
||||
int n;
|
||||
|
||||
if( level.locationLinked )
|
||||
return;
|
||||
|
||||
level.locationLinked = qtrue;
|
||||
|
||||
level.locationHead = NULL;
|
||||
|
||||
trap_SetConfigstring( CS_LOCATIONS, "unknown" );
|
||||
|
||||
for( i = 0, ent = g_entities, n = 1; i < level.num_entities; i++, ent++)
|
||||
{
|
||||
if( ent->classname && !Q_stricmp( ent->classname, "target_location" ) )
|
||||
{
|
||||
// lets overload some variables!
|
||||
ent->health = n; // use for location marking
|
||||
trap_SetConfigstring( CS_LOCATIONS + n, ent->message );
|
||||
n++;
|
||||
ent->nextTrain = level.locationHead;
|
||||
level.locationHead = ent;
|
||||
}
|
||||
}
|
||||
// All linked together now
|
||||
}
|
||||
|
||||
/*QUAKED target_location (0 0.5 0) (-8 -8 -8) (8 8 8)
|
||||
Set "message" to the name of this location.
|
||||
Set "count" to 0-7 for color.
|
||||
0:white 1:red 2:green 3:yellow 4:blue 5:cyan 6:magenta 7:white
|
||||
|
||||
Closest target_location in sight used for the location, if none
|
||||
in site, closest in distance
|
||||
*/
|
||||
void SP_target_location( gentity_t *self )
|
||||
{
|
||||
self->think = target_location_linkup;
|
||||
self->nextthink = level.time + 200; // Let them all spawn first
|
||||
|
||||
G_SetOrigin( self, self->s.origin );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
target_rumble_think
|
||||
===============
|
||||
*/
|
||||
void target_rumble_think( gentity_t *self )
|
||||
{
|
||||
int i;
|
||||
gentity_t *ent;
|
||||
|
||||
if( self->last_move_time < level.time )
|
||||
self->last_move_time = level.time + 0.5;
|
||||
|
||||
for( i = 0, ent = g_entities + i; i < level.num_entities; i++, ent++ )
|
||||
{
|
||||
if( !ent->inuse )
|
||||
continue;
|
||||
|
||||
if( !ent->client )
|
||||
continue;
|
||||
|
||||
if( ent->client->ps.groundEntityNum == ENTITYNUM_NONE )
|
||||
continue;
|
||||
|
||||
ent->client->ps.groundEntityNum = ENTITYNUM_NONE;
|
||||
ent->client->ps.velocity[ 0 ] += crandom( ) * 150;
|
||||
ent->client->ps.velocity[ 1 ] += crandom( ) * 150;
|
||||
ent->client->ps.velocity[ 2 ] = self->speed;
|
||||
}
|
||||
|
||||
if( level.time < self->timestamp )
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
target_rumble_use
|
||||
===============
|
||||
*/
|
||||
void target_rumble_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
self->timestamp = level.time + ( self->count * FRAMETIME );
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
self->activator = activator;
|
||||
self->last_move_time = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_target_rumble
|
||||
===============
|
||||
*/
|
||||
void SP_target_rumble( gentity_t *self )
|
||||
{
|
||||
if( !self->targetname )
|
||||
{
|
||||
G_Printf( S_COLOR_YELLOW "WARNING: untargeted %s at %s\n", self->classname,
|
||||
vtos( self->s.origin ) );
|
||||
}
|
||||
|
||||
if( !self->count )
|
||||
self->count = 10;
|
||||
|
||||
if( !self->speed )
|
||||
self->speed = 100;
|
||||
|
||||
self->think = target_rumble_think;
|
||||
self->use = target_rumble_use;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
target_alien_win_use
|
||||
===============
|
||||
*/
|
||||
void target_alien_win_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
level.uncondAlienWin = qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_target_alien_win
|
||||
===============
|
||||
*/
|
||||
void SP_target_alien_win( gentity_t *self )
|
||||
{
|
||||
self->use = target_alien_win_use;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
target_human_win_use
|
||||
===============
|
||||
*/
|
||||
void target_human_win_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
level.uncondHumanWin = qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_target_human_win
|
||||
===============
|
||||
*/
|
||||
void SP_target_human_win( gentity_t *self )
|
||||
{
|
||||
self->use = target_human_win_use;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
target_hurt_use
|
||||
===============
|
||||
*/
|
||||
void target_hurt_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
// hurt the activator
|
||||
if( !activator->takedamage )
|
||||
return;
|
||||
|
||||
G_Damage( activator, self, self, NULL, NULL, self->damage, 0, MOD_TRIGGER_HURT );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_target_hurt
|
||||
===============
|
||||
*/
|
||||
void SP_target_hurt( gentity_t *self )
|
||||
{
|
||||
if( !self->targetname )
|
||||
{
|
||||
G_Printf( S_COLOR_YELLOW "WARNING: untargeted %s at %s\n", self->classname,
|
||||
vtos( self->s.origin ) );
|
||||
}
|
||||
|
||||
if( !self->damage )
|
||||
self->damage = 5;
|
||||
|
||||
self->use = target_hurt_use;
|
||||
}
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2000-2006 Tim Angus
|
||||
|
||||
This file is part of Tremulous.
|
||||
|
||||
Tremulous is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Tremulous is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Tremulous; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "g_local.h"
|
||||
|
||||
//==========================================================
|
||||
|
||||
/*QUAKED target_delay (1 0 0) (-8 -8 -8) (8 8 8)
|
||||
"wait" seconds to pause before firing targets.
|
||||
"random" delay variance, total delay = delay +/- random seconds
|
||||
*/
|
||||
void Think_Target_Delay( gentity_t *ent )
|
||||
{
|
||||
G_UseTargets( ent, ent->activator );
|
||||
}
|
||||
|
||||
void Use_Target_Delay( gentity_t *ent, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
ent->nextthink = level.time + ( ent->wait + ent->random * crandom( ) ) * 1000;
|
||||
ent->think = Think_Target_Delay;
|
||||
ent->activator = activator;
|
||||
}
|
||||
|
||||
void SP_target_delay( gentity_t *ent )
|
||||
{
|
||||
// check delay for backwards compatability
|
||||
if( !G_SpawnFloat( "delay", "0", &ent->wait ) )
|
||||
G_SpawnFloat( "wait", "1", &ent->wait );
|
||||
|
||||
if( !ent->wait )
|
||||
ent->wait = 1;
|
||||
|
||||
ent->use = Use_Target_Delay;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================
|
||||
|
||||
/*QUAKED target_score (1 0 0) (-8 -8 -8) (8 8 8)
|
||||
"count" number of points to add, default 1
|
||||
|
||||
The activator is given this many points.
|
||||
*/
|
||||
void Use_Target_Score( gentity_t *ent, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
AddScore( activator, ent->count );
|
||||
}
|
||||
|
||||
void SP_target_score( gentity_t *ent )
|
||||
{
|
||||
if( !ent->count )
|
||||
ent->count = 1;
|
||||
|
||||
ent->use = Use_Target_Score;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================
|
||||
|
||||
/*QUAKED target_print (1 0 0) (-8 -8 -8) (8 8 8) humanteam alienteam private
|
||||
"message" text to print
|
||||
If "private", only the activator gets the message. If no checks, all clients get the message.
|
||||
*/
|
||||
void Use_Target_Print( gentity_t *ent, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
if( activator->client && ( ent->spawnflags & 4 ) )
|
||||
{
|
||||
trap_SendServerCommand( activator-g_entities, va( "cp \"%s\"", ent->message ) );
|
||||
return;
|
||||
}
|
||||
|
||||
if( ent->spawnflags & 3 )
|
||||
{
|
||||
if( ent->spawnflags & 1 )
|
||||
G_TeamCommand( PTE_HUMANS, va( "cp \"%s\"", ent->message ) );
|
||||
if( ent->spawnflags & 2 )
|
||||
G_TeamCommand( PTE_ALIENS, va( "cp \"%s\"", ent->message ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
trap_SendServerCommand( -1, va("cp \"%s\"", ent->message ) );
|
||||
}
|
||||
|
||||
void SP_target_print( gentity_t *ent )
|
||||
{
|
||||
ent->use = Use_Target_Print;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================
|
||||
|
||||
|
||||
/*QUAKED target_speaker (1 0 0) (-8 -8 -8) (8 8 8) looped-on looped-off global activator
|
||||
"noise" wav file to play
|
||||
|
||||
A global sound will play full volume throughout the level.
|
||||
Activator sounds will play on the player that activated the target.
|
||||
Global and activator sounds can't be combined with looping.
|
||||
Normal sounds play each time the target is used.
|
||||
Looped sounds will be toggled by use functions.
|
||||
Multiple identical looping sounds will just increase volume without any speed cost.
|
||||
"wait" : Seconds between auto triggerings, 0 = don't auto trigger
|
||||
"random" wait variance, default is 0
|
||||
*/
|
||||
void Use_Target_Speaker( gentity_t *ent, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
if( ent->spawnflags & 3 )
|
||||
{ // looping sound toggles
|
||||
if( ent->s.loopSound )
|
||||
ent->s.loopSound = 0; // turn it off
|
||||
else
|
||||
ent->s.loopSound = ent->noise_index; // start it
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal sound
|
||||
if( ent->spawnflags & 8 )
|
||||
G_AddEvent( activator, EV_GENERAL_SOUND, ent->noise_index );
|
||||
else if( ent->spawnflags & 4 )
|
||||
G_AddEvent( ent, EV_GLOBAL_SOUND, ent->noise_index );
|
||||
else
|
||||
G_AddEvent( ent, EV_GENERAL_SOUND, ent->noise_index );
|
||||
}
|
||||
}
|
||||
|
||||
void SP_target_speaker( gentity_t *ent )
|
||||
{
|
||||
char buffer[ MAX_QPATH ];
|
||||
char *s;
|
||||
|
||||
G_SpawnFloat( "wait", "0", &ent->wait );
|
||||
G_SpawnFloat( "random", "0", &ent->random );
|
||||
|
||||
if( !G_SpawnString( "noise", "NOSOUND", &s ) )
|
||||
G_Error( "target_speaker without a noise key at %s", vtos( ent->s.origin ) );
|
||||
|
||||
// force all client reletive sounds to be "activator" speakers that
|
||||
// play on the entity that activates it
|
||||
if( s[ 0 ] == '*' )
|
||||
ent->spawnflags |= 8;
|
||||
|
||||
if( !strstr( s, ".wav" ) )
|
||||
Com_sprintf( buffer, sizeof( buffer ), "%s.wav", s );
|
||||
else
|
||||
Q_strncpyz( buffer, s, sizeof( buffer ) );
|
||||
|
||||
ent->noise_index = G_SoundIndex( buffer );
|
||||
|
||||
// a repeating speaker can be done completely client side
|
||||
ent->s.eType = ET_SPEAKER;
|
||||
ent->s.eventParm = ent->noise_index;
|
||||
ent->s.frame = ent->wait * 10;
|
||||
ent->s.clientNum = ent->random * 10;
|
||||
|
||||
|
||||
// check for prestarted looping sound
|
||||
if( ent->spawnflags & 1 )
|
||||
ent->s.loopSound = ent->noise_index;
|
||||
|
||||
ent->use = Use_Target_Speaker;
|
||||
|
||||
if( ent->spawnflags & 4 )
|
||||
ent->r.svFlags |= SVF_BROADCAST;
|
||||
|
||||
VectorCopy( ent->s.origin, ent->s.pos.trBase );
|
||||
|
||||
// must link the entity so we get areas and clusters so
|
||||
// the server can determine who to send updates to
|
||||
trap_LinkEntity( ent );
|
||||
}
|
||||
|
||||
//==========================================================
|
||||
|
||||
void target_teleporter_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
gentity_t *dest;
|
||||
|
||||
if( !activator->client )
|
||||
return;
|
||||
|
||||
dest = G_PickTarget( self->target );
|
||||
|
||||
if( !dest )
|
||||
{
|
||||
G_Printf( "Couldn't find teleporter destination\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
TeleportPlayer( activator, dest->s.origin, dest->s.angles );
|
||||
}
|
||||
|
||||
/*QUAKED target_teleporter (1 0 0) (-8 -8 -8) (8 8 8)
|
||||
The activator will be teleported away.
|
||||
*/
|
||||
void SP_target_teleporter( gentity_t *self )
|
||||
{
|
||||
if( !self->targetname )
|
||||
G_Printf( "untargeted %s at %s\n", self->classname, vtos( self->s.origin ) );
|
||||
|
||||
self->use = target_teleporter_use;
|
||||
}
|
||||
|
||||
//==========================================================
|
||||
|
||||
|
||||
/*QUAKED target_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) RED_ONLY BLUE_ONLY RANDOM
|
||||
This doesn't perform any actions except fire its targets.
|
||||
The activator can be forced to be from a certain team.
|
||||
if RANDOM is checked, only one of the targets will be fired, not all of them
|
||||
*/
|
||||
void target_relay_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
if( ( self->spawnflags & 1 ) && activator->client &&
|
||||
activator->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS )
|
||||
return;
|
||||
|
||||
if( ( self->spawnflags & 2 ) && activator->client &&
|
||||
activator->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS )
|
||||
return;
|
||||
|
||||
if( self->spawnflags & 4 )
|
||||
{
|
||||
gentity_t *ent;
|
||||
|
||||
ent = G_PickTarget( self->target );
|
||||
if( ent && ent->use )
|
||||
ent->use( ent, self, activator );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
G_UseTargets( self, activator );
|
||||
}
|
||||
|
||||
void SP_target_relay( gentity_t *self )
|
||||
{
|
||||
self->use = target_relay_use;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================
|
||||
|
||||
/*QUAKED target_kill (.5 .5 .5) (-8 -8 -8) (8 8 8)
|
||||
Kills the activator.
|
||||
*/
|
||||
void target_kill_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
G_Damage( activator, NULL, NULL, NULL, NULL, 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG );
|
||||
}
|
||||
|
||||
void SP_target_kill( gentity_t *self )
|
||||
{
|
||||
self->use = target_kill_use;
|
||||
}
|
||||
|
||||
/*QUAKED target_position (0 0.5 0) (-4 -4 -4) (4 4 4)
|
||||
Used as a positional target for in-game calculation, like jumppad targets.
|
||||
*/
|
||||
void SP_target_position( gentity_t *self )
|
||||
{
|
||||
G_SetOrigin( self, self->s.origin );
|
||||
}
|
||||
|
||||
static void target_location_linkup( gentity_t *ent )
|
||||
{
|
||||
int i;
|
||||
int n;
|
||||
|
||||
if( level.locationLinked )
|
||||
return;
|
||||
|
||||
level.locationLinked = qtrue;
|
||||
|
||||
level.locationHead = NULL;
|
||||
|
||||
trap_SetConfigstring( CS_LOCATIONS, "unknown" );
|
||||
|
||||
for( i = 0, ent = g_entities, n = 1; i < level.num_entities; i++, ent++)
|
||||
{
|
||||
if( ent->classname && !Q_stricmp( ent->classname, "target_location" ) )
|
||||
{
|
||||
// lets overload some variables!
|
||||
ent->health = n; // use for location marking
|
||||
trap_SetConfigstring( CS_LOCATIONS + n, ent->message );
|
||||
n++;
|
||||
ent->nextTrain = level.locationHead;
|
||||
level.locationHead = ent;
|
||||
}
|
||||
}
|
||||
// All linked together now
|
||||
}
|
||||
|
||||
/*QUAKED target_location (0 0.5 0) (-8 -8 -8) (8 8 8)
|
||||
Set "message" to the name of this location.
|
||||
Set "count" to 0-7 for color.
|
||||
0:white 1:red 2:green 3:yellow 4:blue 5:cyan 6:magenta 7:white
|
||||
|
||||
Closest target_location in sight used for the location, if none
|
||||
in site, closest in distance
|
||||
*/
|
||||
void SP_target_location( gentity_t *self )
|
||||
{
|
||||
self->think = target_location_linkup;
|
||||
self->nextthink = level.time + 200; // Let them all spawn first
|
||||
|
||||
G_SetOrigin( self, self->s.origin );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
target_rumble_think
|
||||
===============
|
||||
*/
|
||||
void target_rumble_think( gentity_t *self )
|
||||
{
|
||||
int i;
|
||||
gentity_t *ent;
|
||||
|
||||
if( self->last_move_time < level.time )
|
||||
self->last_move_time = level.time + 0.5;
|
||||
|
||||
for( i = 0, ent = g_entities + i; i < level.num_entities; i++, ent++ )
|
||||
{
|
||||
if( !ent->inuse )
|
||||
continue;
|
||||
|
||||
if( !ent->client )
|
||||
continue;
|
||||
|
||||
if( ent->client->ps.groundEntityNum == ENTITYNUM_NONE )
|
||||
continue;
|
||||
|
||||
ent->client->ps.groundEntityNum = ENTITYNUM_NONE;
|
||||
ent->client->ps.velocity[ 0 ] += crandom( ) * 150;
|
||||
ent->client->ps.velocity[ 1 ] += crandom( ) * 150;
|
||||
ent->client->ps.velocity[ 2 ] = self->speed;
|
||||
}
|
||||
|
||||
if( level.time < self->timestamp )
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
target_rumble_use
|
||||
===============
|
||||
*/
|
||||
void target_rumble_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
self->timestamp = level.time + ( self->count * FRAMETIME );
|
||||
self->nextthink = level.time + FRAMETIME;
|
||||
self->activator = activator;
|
||||
self->last_move_time = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_target_rumble
|
||||
===============
|
||||
*/
|
||||
void SP_target_rumble( gentity_t *self )
|
||||
{
|
||||
if( !self->targetname )
|
||||
{
|
||||
G_Printf( S_COLOR_YELLOW "WARNING: untargeted %s at %s\n", self->classname,
|
||||
vtos( self->s.origin ) );
|
||||
}
|
||||
|
||||
if( !self->count )
|
||||
self->count = 10;
|
||||
|
||||
if( !self->speed )
|
||||
self->speed = 100;
|
||||
|
||||
self->think = target_rumble_think;
|
||||
self->use = target_rumble_use;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
target_alien_win_use
|
||||
===============
|
||||
*/
|
||||
void target_alien_win_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
level.uncondAlienWin = qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_target_alien_win
|
||||
===============
|
||||
*/
|
||||
void SP_target_alien_win( gentity_t *self )
|
||||
{
|
||||
self->use = target_alien_win_use;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
target_human_win_use
|
||||
===============
|
||||
*/
|
||||
void target_human_win_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
level.uncondHumanWin = qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_target_human_win
|
||||
===============
|
||||
*/
|
||||
void SP_target_human_win( gentity_t *self )
|
||||
{
|
||||
self->use = target_human_win_use;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
target_hurt_use
|
||||
===============
|
||||
*/
|
||||
void target_hurt_use( gentity_t *self, gentity_t *other, gentity_t *activator )
|
||||
{
|
||||
// hurt the activator
|
||||
if( !activator->takedamage )
|
||||
return;
|
||||
|
||||
G_Damage( activator, self, self, NULL, NULL, self->damage, 0, MOD_TRIGGER_HURT );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SP_target_hurt
|
||||
===============
|
||||
*/
|
||||
void SP_target_hurt( gentity_t *self )
|
||||
{
|
||||
if( !self->targetname )
|
||||
{
|
||||
G_Printf( S_COLOR_YELLOW "WARNING: untargeted %s at %s\n", self->classname,
|
||||
vtos( self->s.origin ) );
|
||||
}
|
||||
|
||||
if( !self->damage )
|
||||
self->damage = 5;
|
||||
|
||||
self->use = target_hurt_use;
|
||||
}
|
||||
+1141
-1141
File diff suppressed because it is too large.
Load diff
+848
-848
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user