Changed line endings to UNIX.

This commit is contained in:
Paradox460 committed 2008-01-05 21:51:54 +00:00
1 parent 7acbb8c956
commit fc0f4ac57c
52 files changed
+53864 -53864

No files matched your search

+2031 -2031
View File
File diff suppressed because it is too large. Load diff
+104 -104
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+216 -216
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+170 -170
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large. Load diff
+848 -848
View File
File diff suppressed because it is too large. Load diff