From ef5d1d446e3c078b81882c2eda6525aee7ccfa1e Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Sat, 10 Dec 2005 03:18:22 +0000 Subject: * Moved existing src directory out the way whilst I merge ioq3 --- src/cgame/cg_animation.c | 101 - src/cgame/cg_animmapobj.c | 193 -- src/cgame/cg_attachment.c | 395 --- src/cgame/cg_buildable.c | 1051 ------- src/cgame/cg_consolecmds.c | 279 -- src/cgame/cg_draw.c | 3393 ----------------------- src/cgame/cg_drawtools.c | 308 --- src/cgame/cg_ents.c | 1225 --------- src/cgame/cg_event.c | 1011 ------- src/cgame/cg_local.h | 2003 -------------- src/cgame/cg_main.c | 1801 ------------ src/cgame/cg_marks.c | 280 -- src/cgame/cg_mem.c | 191 -- src/cgame/cg_particles.c | 2551 ----------------- src/cgame/cg_players.c | 2575 ----------------- src/cgame/cg_playerstate.c | 308 --- src/cgame/cg_predict.c | 615 ----- src/cgame/cg_ptr.c | 71 - src/cgame/cg_public.h | 227 -- src/cgame/cg_scanner.c | 355 --- src/cgame/cg_servercmds.c | 1130 -------- src/cgame/cg_snapshot.c | 402 --- src/cgame/cg_syscalls.asm | 105 - src/cgame/cg_syscalls.c | 507 ---- src/cgame/cg_trails.c | 1489 ---------- src/cgame/cg_view.c | 1330 --------- src/cgame/cg_weapons.c | 1810 ------------ src/cgame/tr_types.h | 225 -- src/game/bg_lib.c | 1940 ------------- src/game/bg_lib.h | 92 - src/game/bg_local.h | 80 - src/game/bg_misc.c | 5248 ----------------------------------- src/game/bg_pmove.c | 3471 ----------------------- src/game/bg_public.h | 1299 --------- src/game/bg_slidemove.c | 408 --- src/game/g_active.c | 1524 ----------- src/game/g_buildable.c | 2987 -------------------- src/game/g_client.c | 1593 ----------- src/game/g_cmds.c | 2305 ---------------- src/game/g_combat.c | 1322 --------- src/game/g_local.h | 1139 -------- src/game/g_main.c | 2207 --------------- src/game/g_maprotation.c | 709 ----- src/game/g_mem.c | 201 -- src/game/g_misc.c | 411 --- src/game/g_missile.c | 803 ------ src/game/g_mover.c | 2468 ----------------- src/game/g_physics.c | 161 -- src/game/g_ptr.c | 167 -- src/game/g_public.h | 419 --- src/game/g_session.c | 150 - src/game/g_spawn.c | 701 ----- src/game/g_svcmds.c | 581 ---- src/game/g_syscalls.asm | 61 - src/game/g_syscalls.c | 264 -- src/game/g_target.c | 432 --- src/game/g_team.c | 249 -- src/game/g_trigger.c | 1037 ------- src/game/g_utils.c | 1071 -------- src/game/g_weapon.c | 1553 ----------- src/game/q_math.c | 1482 ---------- src/game/q_shared.c | 1286 --------- src/game/q_shared.h | 1422 ---------- src/game/surfaceflags.h | 84 - src/game/tremulous.h | 572 ---- src/ui/keycodes.h | 157 -- src/ui/ui_atoms.c | 517 ---- src/ui/ui_gameinfo.c | 293 -- src/ui/ui_local.h | 1208 -------- src/ui/ui_main.c | 6553 -------------------------------------------- src/ui/ui_players.c | 1362 --------- src/ui/ui_public.h | 187 -- src/ui/ui_shared.c | 6071 ---------------------------------------- src/ui/ui_shared.h | 444 --- src/ui/ui_syscalls.asm | 103 - src/ui/ui_syscalls.c | 392 --- 76 files changed, 85117 deletions(-) delete mode 100644 src/cgame/cg_animation.c delete mode 100644 src/cgame/cg_animmapobj.c delete mode 100644 src/cgame/cg_attachment.c delete mode 100644 src/cgame/cg_buildable.c delete mode 100644 src/cgame/cg_consolecmds.c delete mode 100644 src/cgame/cg_draw.c delete mode 100644 src/cgame/cg_drawtools.c delete mode 100644 src/cgame/cg_ents.c delete mode 100644 src/cgame/cg_event.c delete mode 100644 src/cgame/cg_local.h delete mode 100644 src/cgame/cg_main.c delete mode 100644 src/cgame/cg_marks.c delete mode 100644 src/cgame/cg_mem.c delete mode 100644 src/cgame/cg_particles.c delete mode 100644 src/cgame/cg_players.c delete mode 100644 src/cgame/cg_playerstate.c delete mode 100644 src/cgame/cg_predict.c delete mode 100644 src/cgame/cg_ptr.c delete mode 100644 src/cgame/cg_public.h delete mode 100644 src/cgame/cg_scanner.c delete mode 100644 src/cgame/cg_servercmds.c delete mode 100644 src/cgame/cg_snapshot.c delete mode 100644 src/cgame/cg_syscalls.asm delete mode 100644 src/cgame/cg_syscalls.c delete mode 100644 src/cgame/cg_trails.c delete mode 100644 src/cgame/cg_view.c delete mode 100644 src/cgame/cg_weapons.c delete mode 100644 src/cgame/tr_types.h delete mode 100644 src/game/bg_lib.c delete mode 100644 src/game/bg_lib.h delete mode 100644 src/game/bg_local.h delete mode 100644 src/game/bg_misc.c delete mode 100644 src/game/bg_pmove.c delete mode 100644 src/game/bg_public.h delete mode 100644 src/game/bg_slidemove.c delete mode 100644 src/game/g_active.c delete mode 100644 src/game/g_buildable.c delete mode 100644 src/game/g_client.c delete mode 100644 src/game/g_cmds.c delete mode 100644 src/game/g_combat.c delete mode 100644 src/game/g_local.h delete mode 100644 src/game/g_main.c delete mode 100644 src/game/g_maprotation.c delete mode 100644 src/game/g_mem.c delete mode 100644 src/game/g_misc.c delete mode 100644 src/game/g_missile.c delete mode 100644 src/game/g_mover.c delete mode 100644 src/game/g_physics.c delete mode 100644 src/game/g_ptr.c delete mode 100644 src/game/g_public.h delete mode 100644 src/game/g_session.c delete mode 100644 src/game/g_spawn.c delete mode 100644 src/game/g_svcmds.c delete mode 100644 src/game/g_syscalls.asm delete mode 100644 src/game/g_syscalls.c delete mode 100644 src/game/g_target.c delete mode 100644 src/game/g_team.c delete mode 100644 src/game/g_trigger.c delete mode 100644 src/game/g_utils.c delete mode 100644 src/game/g_weapon.c delete mode 100644 src/game/q_math.c delete mode 100644 src/game/q_shared.c delete mode 100644 src/game/q_shared.h delete mode 100644 src/game/surfaceflags.h delete mode 100644 src/game/tremulous.h delete mode 100644 src/ui/keycodes.h delete mode 100644 src/ui/ui_atoms.c delete mode 100644 src/ui/ui_gameinfo.c delete mode 100644 src/ui/ui_local.h delete mode 100644 src/ui/ui_main.c delete mode 100644 src/ui/ui_players.c delete mode 100644 src/ui/ui_public.h delete mode 100644 src/ui/ui_shared.c delete mode 100644 src/ui/ui_shared.h delete mode 100644 src/ui/ui_syscalls.asm delete mode 100644 src/ui/ui_syscalls.c (limited to 'src') diff --git a/src/cgame/cg_animation.c b/src/cgame/cg_animation.c deleted file mode 100644 index 5295998e..00000000 --- a/src/cgame/cg_animation.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -/* -=============== -CG_RunLerpFrame - -Sets cg.snap, cg.oldFrame, and cg.backlerp -cg.time should be between oldFrameTime and frameTime after exit -=============== -*/ -void CG_RunLerpFrame( lerpFrame_t *lf ) -{ - int f, numFrames; - animation_t *anim; - - // debugging tool to get no animations - if( cg_animSpeed.integer == 0 ) - { - lf->oldFrame = lf->frame = lf->backlerp = 0; - return; - } - - // if we have passed the current frame, move it to - // oldFrame and calculate a new frame - if( cg.time >= lf->frameTime ) - { - lf->oldFrame = lf->frame; - lf->oldFrameTime = lf->frameTime; - - // get the next frame based on the animation - anim = lf->animation; - if( !anim->frameLerp ) - return; // shouldn't happen - - if( cg.time < lf->animationTime ) - lf->frameTime = lf->animationTime; // initial lerp - else - lf->frameTime = lf->oldFrameTime + anim->frameLerp; - - f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp; - numFrames = anim->numFrames; - if( anim->flipflop ) - numFrames *= 2; - - if( f >= numFrames ) - { - f -= numFrames; - if( anim->loopFrames ) - { - f %= anim->loopFrames; - f += anim->numFrames - anim->loopFrames; - } - else - { - f = numFrames - 1; - // the animation is stuck at the end, so it - // can immediately transition to another sequence - lf->frameTime = cg.time; - } - } - - if( anim->reversed ) - lf->frame = anim->firstFrame + anim->numFrames - 1 - f; - else if( anim->flipflop && f >= anim->numFrames ) - lf->frame = anim->firstFrame + anim->numFrames - 1 - ( f % anim->numFrames ); - else - lf->frame = anim->firstFrame + f; - - if( cg.time > lf->frameTime ) - { - lf->frameTime = cg.time; - if( cg_debugAnim.integer ) - CG_Printf( "Clamp lf->frameTime\n" ); - } - } - - if( lf->frameTime > cg.time + 200 ) - lf->frameTime = cg.time; - - if( lf->oldFrameTime > cg.time ) - lf->oldFrameTime = cg.time; - - // calculate current lerp value - if( lf->frameTime == lf->oldFrameTime ) - lf->backlerp = 0; - else - lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime ); -} diff --git a/src/cgame/cg_animmapobj.c b/src/cgame/cg_animmapobj.c deleted file mode 100644 index f0e964bf..00000000 --- a/src/cgame/cg_animmapobj.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - - -/* -=============== -CG_DoorAnimation -=============== -*/ -static void CG_DoorAnimation( centity_t *cent, int *old, int *now, float *backLerp ) -{ - CG_RunLerpFrame( ¢->lerpFrame ); - - *old = cent->lerpFrame.oldFrame; - *now = cent->lerpFrame.frame; - *backLerp = cent->lerpFrame.backlerp; -} - - -/* -=============== -CG_ModelDoor -=============== -*/ -void CG_ModelDoor( centity_t *cent ) -{ - refEntity_t ent; - entityState_t *es; - animation_t anim; - lerpFrame_t *lf = ¢->lerpFrame; - - es = ¢->currentState; - - if( !es->modelindex ) - return; - - //create the render entity - memset( &ent, 0, sizeof( ent ) ); - VectorCopy( cent->lerpOrigin, ent.origin ); - VectorCopy( cent->lerpOrigin, ent.oldorigin ); - AnglesToAxis( cent->lerpAngles, ent.axis ); - - ent.renderfx = RF_NOSHADOW; - - //add the door model - ent.skinNum = 0; - ent.hModel = cgs.gameModels[ es->modelindex ]; - - //scale the door - VectorScale( ent.axis[ 0 ], es->origin2[ 0 ], ent.axis[ 0 ] ); - VectorScale( ent.axis[ 1 ], es->origin2[ 1 ], ent.axis[ 1 ] ); - VectorScale( ent.axis[ 2 ], es->origin2[ 2 ], ent.axis[ 2 ] ); - ent.nonNormalizedAxes = qtrue; - - //setup animation - anim.firstFrame = es->powerups; - anim.numFrames = es->weapon; - anim.reversed = !es->legsAnim; - anim.flipflop = qfalse; - anim.loopFrames = 0; - anim.frameLerp = 1000 / es->torsoAnim; - anim.initialLerp = 1000 / es->torsoAnim; - - //door changed state - if( es->legsAnim != cent->doorState ) - { - lf->animationTime = lf->frameTime + anim.initialLerp; - cent->doorState = es->legsAnim; - } - - lf->animation = &anim; - - //run animation - CG_DoorAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp ); - - trap_R_AddRefEntityToScene( &ent ); -} - - -/* -=============== -CG_AMOAnimation -=============== -*/ -static void CG_AMOAnimation( centity_t *cent, int *old, int *now, float *backLerp ) -{ - if( !( cent->currentState.eFlags & EF_MOVER_STOP ) ) - { - int delta = cg.time - cent->miscTime; - - //hack to prevent "pausing" mucking up the lerping - if( delta > 900 ) - { - cent->lerpFrame.oldFrameTime += delta; - cent->lerpFrame.frameTime += delta; - } - - CG_RunLerpFrame( ¢->lerpFrame ); - cent->miscTime = cg.time; - } - - *old = cent->lerpFrame.oldFrame; - *now = cent->lerpFrame.frame; - *backLerp = cent->lerpFrame.backlerp; -} - - -/* -================== -CG_animMapObj -================== -*/ -void CG_AnimMapObj( centity_t *cent ) -{ - refEntity_t ent; - entityState_t *es; - float scale; - animation_t anim; - - es = ¢->currentState; - - // if set to invisible, skip - if( !es->modelindex || ( es->eFlags & EF_NODRAW ) ) - return; - - memset( &ent, 0, sizeof( ent ) ); - - VectorCopy( es->angles, cent->lerpAngles ); - AnglesToAxis( cent->lerpAngles, ent.axis ); - - ent.hModel = cgs.gameModels[ es->modelindex ]; - - VectorCopy( cent->lerpOrigin, ent.origin); - VectorCopy( cent->lerpOrigin, ent.oldorigin); - - ent.nonNormalizedAxes = qfalse; - - //scale the model - if( es->angles2[ 0 ] ) - { - scale = es->angles2[ 0 ]; - VectorScale( ent.axis[ 0 ], scale, ent.axis[ 0 ] ); - VectorScale( ent.axis[ 1 ], scale, ent.axis[ 1 ] ); - VectorScale( ent.axis[ 2 ], scale, ent.axis[ 2 ] ); - ent.nonNormalizedAxes = qtrue; - } - - //setup animation - anim.firstFrame = es->powerups; - anim.numFrames = es->weapon; - anim.reversed = qfalse; - anim.flipflop = qfalse; - - // if numFrames is negative the animation is reversed - if( anim.numFrames < 0 ) - { - anim.numFrames = -anim.numFrames; - anim.reversed = qtrue; - } - - anim.loopFrames = es->torsoAnim; - - if( !es->legsAnim ) - { - anim.frameLerp = 1000; - anim.initialLerp = 1000; - } - else - { - anim.frameLerp = 1000 / es->legsAnim; - anim.initialLerp = 1000 / es->legsAnim; - } - - cent->lerpFrame.animation = &anim; - - //run animation - CG_AMOAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp ); - - // add to refresh list - trap_R_AddRefEntityToScene(&ent); -} diff --git a/src/cgame/cg_attachment.c b/src/cgame/cg_attachment.c deleted file mode 100644 index a256318b..00000000 --- a/src/cgame/cg_attachment.c +++ /dev/null @@ -1,395 +0,0 @@ -// cg_attachment.c -- an abstract attachment system - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -/* -=============== -CG_AttachmentPoint - -Return the attachment point -=============== -*/ -qboolean CG_AttachmentPoint( attachment_t *a, vec3_t v ) -{ - centity_t *cent; - - if( !a ) - return qfalse; - - // if it all breaks, then use the last point we know was correct - VectorCopy( a->lastValidAttachmentPoint, v ); - - switch( a->type ) - { - case AT_STATIC: - if( !a->staticValid ) - return qfalse; - - VectorCopy( a->origin, v ); - break; - - case AT_TAG: - if( !a->tagValid ) - return qfalse; - - AxisCopy( axisDefault, a->re.axis ); - CG_PositionRotatedEntityOnTag( &a->re, &a->parent, - a->model, a->tagName ); - VectorCopy( a->re.origin, v ); - break; - - case AT_CENT: - if( !a->centValid ) - return qfalse; - - if( a->centNum == cg.predictedPlayerState.clientNum ) - { - // this is smoother if it's the local client - VectorCopy( cg.predictedPlayerState.origin, v ); - } - else - { - cent = &cg_entities[ a->centNum ]; - VectorCopy( cent->lerpOrigin, v ); - } - break; - - case AT_PARTICLE: - if( !a->particleValid ) - return qfalse; - - if( !a->particle->valid ) - { - a->particleValid = qfalse; - return qfalse; - } - else - VectorCopy( a->particle->origin, v ); - break; - - default: - CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" ); - break; - } - - if( a->hasOffset ) - VectorAdd( v, a->offset, v ); - - VectorCopy( v, a->lastValidAttachmentPoint ); - - return qtrue; -} - -/* -=============== -CG_AttachmentDir - -Return the attachment direction -=============== -*/ -qboolean CG_AttachmentDir( attachment_t *a, vec3_t v ) -{ - vec3_t forward; - centity_t *cent; - - if( !a ) - return qfalse; - - switch( a->type ) - { - case AT_STATIC: - return qfalse; - break; - - case AT_TAG: - if( !a->tagValid ) - return qfalse; - - VectorCopy( a->re.axis[ 0 ], v ); - break; - - case AT_CENT: - if( !a->centValid ) - return qfalse; - - cent = &cg_entities[ a->centNum ]; - AngleVectors( cent->lerpAngles, forward, NULL, NULL ); - VectorCopy( forward, v ); - break; - - case AT_PARTICLE: - if( !a->particleValid ) - return qfalse; - - if( !a->particle->valid ) - { - a->particleValid = qfalse; - return qfalse; - } - else - VectorCopy( a->particle->velocity, v ); - break; - - default: - CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" ); - break; - } - - VectorNormalize( v ); - return qtrue; -} - -/* -=============== -CG_AttachmentAxis - -Return the attachment axis -=============== -*/ -qboolean CG_AttachmentAxis( attachment_t *a, vec3_t axis[ 3 ] ) -{ - centity_t *cent; - - if( !a ) - return qfalse; - - switch( a->type ) - { - case AT_STATIC: - return qfalse; - break; - - case AT_TAG: - if( !a->tagValid ) - return qfalse; - - AxisCopy( a->re.axis, axis ); - break; - - case AT_CENT: - if( !a->centValid ) - return qfalse; - - cent = &cg_entities[ a->centNum ]; - AnglesToAxis( cent->lerpAngles, axis ); - break; - - case AT_PARTICLE: - return qfalse; - break; - - default: - CG_Printf( S_COLOR_RED "ERROR: Invalid attachmentType_t in attachment\n" ); - break; - } - - return qtrue; -} - -/* -=============== -CG_AttachmentVelocity - -If the attachment can have velocity, return it -=============== -*/ -qboolean CG_AttachmentVelocity( attachment_t *a, vec3_t v ) -{ - if( !a ) - return qfalse; - - if( a->particleValid && a->particle->valid ) - { - VectorCopy( a->particle->velocity, v ); - return qtrue; - } - else if( a->centValid ) - { - centity_t *cent = &cg_entities[ a->centNum ]; - - VectorCopy( cent->currentState.pos.trDelta, v ); - return qtrue; - } - - return qfalse; -} - -/* -=============== -CG_AttachmentCentNum - -If the attachment has a centNum, return it -=============== -*/ -int CG_AttachmentCentNum( attachment_t *a ) -{ - if( !a || !a->centValid ) - return -1; - - return a->centNum; -} - -/* -=============== -CG_Attached - -If the attachment is valid, return qtrue -=============== -*/ -qboolean CG_Attached( attachment_t *a ) -{ - if( !a ) - return qfalse; - - return a->attached; -} - -/* -=============== -CG_AttachToPoint - -Attach to a point in space -=============== -*/ -void CG_AttachToPoint( attachment_t *a ) -{ - if( !a || !a->staticValid ) - return; - - a->type = AT_STATIC; - a->attached = qtrue; -} - -/* -=============== -CG_AttachToCent - -Attach to a centity_t -=============== -*/ -void CG_AttachToCent( attachment_t *a ) -{ - if( !a || !a->centValid ) - return; - - a->type = AT_CENT; - a->attached = qtrue; -} - -/* -=============== -CG_AttachToTag - -Attach to a model tag -=============== -*/ -void CG_AttachToTag( attachment_t *a ) -{ - if( !a || !a->tagValid ) - return; - - a->type = AT_TAG; - a->attached = qtrue; -} - -/* -=============== -CG_AttachToParticle - -Attach to a particle -=============== -*/ -void CG_AttachToParticle( attachment_t *a ) -{ - if( !a || !a->particleValid ) - return; - - a->type = AT_PARTICLE; - a->attached = qtrue; -} - -/* -=============== -CG_SetAttachmentPoint -=============== -*/ -void CG_SetAttachmentPoint( attachment_t *a, vec3_t v ) -{ - if( !a ) - return; - - VectorCopy( v, a->origin ); - a->staticValid = qtrue; -} - -/* -=============== -CG_SetAttachmentCent -=============== -*/ -void CG_SetAttachmentCent( attachment_t *a, centity_t *cent ) -{ - if( !a || !cent ) - return; - - a->centNum = cent->currentState.number; - a->centValid = qtrue; -} - -/* -=============== -CG_SetAttachmentTag -=============== -*/ -void CG_SetAttachmentTag( attachment_t *a, refEntity_t parent, - qhandle_t model, char *tagName ) -{ - if( !a ) - return; - - a->parent = parent; - a->model = model; - strncpy( a->tagName, tagName, MAX_STRING_CHARS ); - a->tagValid = qtrue; -} - -/* -=============== -CG_SetAttachmentParticle -=============== -*/ -void CG_SetAttachmentParticle( attachment_t *a, particle_t *p ) -{ - if( !a ) - return; - - a->particle = p; - a->particleValid = qtrue; -} - -/* -=============== -CG_SetAttachmentOffset -=============== -*/ -void CG_SetAttachmentOffset( attachment_t *a, vec3_t v ) -{ - if( !a ) - return; - - VectorCopy( v, a->offset ); - a->hasOffset = qtrue; -} diff --git a/src/cgame/cg_buildable.c b/src/cgame/cg_buildable.c deleted file mode 100644 index 348bb433..00000000 --- a/src/cgame/cg_buildable.c +++ /dev/null @@ -1,1051 +0,0 @@ -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -char *cg_buildableSoundNames[ MAX_BUILDABLE_ANIMATIONS ] = -{ - "construct1.wav", - "construct2.wav", - "idle1.wav", - "idle2.wav", - "idle3.wav", - "attack1.wav", - "attack2.wav", - "spawn1.wav", - "spawn2.wav", - "pain1.wav", - "pain2.wav", - "destroy1.wav", - "destroy2.wav", - "destroyed.wav" -}; - -static sfxHandle_t defaultAlienSounds[ MAX_BUILDABLE_ANIMATIONS ]; -static sfxHandle_t defaultHumanSounds[ MAX_BUILDABLE_ANIMATIONS ]; - -/* -=================== -CG_AlienBuildableExplosion - -Generated a bunch of gibs launching out from a location -=================== -*/ -void CG_AlienBuildableExplosion( vec3_t origin, vec3_t dir ) -{ - particleSystem_t *ps; - - trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.alienBuildableExplosion ); - - //particle system - ps = CG_SpawnNewParticleSystem( cgs.media.alienBuildableDestroyedPS ); - - if( CG_IsParticleSystemValid( &ps ) ) - { - CG_SetAttachmentPoint( &ps->attachment, origin ); - CG_SetParticleSystemNormal( ps, dir ); - CG_AttachToPoint( &ps->attachment ); - } -} - -/* -================= -CG_HumanBuildableExplosion - -Called for human buildables as they are destroyed -================= -*/ -void CG_HumanBuildableExplosion( vec3_t origin, vec3_t dir ) -{ - particleSystem_t *ps; - - trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.humanBuildableExplosion ); - - //particle system - ps = CG_SpawnNewParticleSystem( cgs.media.humanBuildableDestroyedPS ); - - if( CG_IsParticleSystemValid( &ps ) ) - { - CG_SetAttachmentPoint( &ps->attachment, origin ); - CG_SetParticleSystemNormal( ps, dir ); - CG_AttachToPoint( &ps->attachment ); - } -} - - -#define CREEP_SIZE 64.0f - -/* -================== -CG_Creep -================== -*/ -static void CG_Creep( centity_t *cent ) -{ - int msec; - float size, frac; - trace_t tr; - vec3_t temp, origin; - int scaleUpTime = BG_FindBuildTimeForBuildable( cent->currentState.modelindex ); - int time; - - time = cent->currentState.time; - - //should the creep be growing or receding? - if( time >= 0 ) - { - msec = cg.time - time; - if( msec >= 0 && msec < scaleUpTime ) - frac = (float)msec / scaleUpTime; - else - frac = 1.0f; - } - else if( time < 0 ) - { - msec = cg.time + time; - if( msec >= 0 && msec < CREEP_SCALEDOWN_TIME ) - frac = 1.0f - ( (float)msec / CREEP_SCALEDOWN_TIME ); - else - frac = 0.0f; - } - - VectorCopy( cent->currentState.origin2, temp ); - VectorScale( temp, -4096, temp ); - VectorAdd( temp, cent->lerpOrigin, temp ); - - CG_Trace( &tr, cent->lerpOrigin, NULL, NULL, temp, cent->currentState.number, MASK_SOLID ); - - VectorCopy( tr.endpos, origin ); - - size = CREEP_SIZE * frac; - - if( size > 0.0f ) - CG_ImpactMark( cgs.media.creepShader, origin, cent->currentState.origin2, - 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, size, qtrue ); -} - -/* -====================== -CG_ParseBuildableAnimationFile - -Read a configuration file containing animation counts and rates -models/buildables/hivemind/animation.cfg, etc -====================== -*/ -static qboolean CG_ParseBuildableAnimationFile( const char *filename, buildable_t buildable ) -{ - char *text_p; - int len; - int i; - char *token; - float fps; - char text[ 20000 ]; - fileHandle_t f; - animation_t *animations; - - animations = cg_buildables[ buildable ].animations; - - // load the file - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - if( len <= 0 ) - return qfalse; - - if( len >= sizeof( text ) - 1 ) - { - CG_Printf( "File %s too long\n", filename ); - return qfalse; - } - - trap_FS_Read( text, len, f ); - text[ len ] = 0; - trap_FS_FCloseFile( f ); - - // parse the text - text_p = text; - - // read information for each frame - for( i = BANIM_NONE + 1; i < MAX_BUILDABLE_ANIMATIONS; i++ ) - { - - token = COM_Parse( &text_p ); - if( !*token ) - break; - - animations[ i ].firstFrame = atoi( token ); - - token = COM_Parse( &text_p ); - if( !*token ) - break; - - animations[ i ].numFrames = atoi( token ); - animations[ i ].reversed = qfalse; - animations[ i ].flipflop = qfalse; - - // if numFrames is negative the animation is reversed - if( animations[ i ].numFrames < 0 ) - { - animations[ i ].numFrames = -animations[ i ].numFrames; - animations[ i ].reversed = qtrue; - } - - token = COM_Parse( &text_p ); - if ( !*token ) - break; - - animations[i].loopFrames = atoi( token ); - - token = COM_Parse( &text_p ); - if( !*token ) - break; - - fps = atof( token ); - if( fps == 0 ) - fps = 1; - - animations[ i ].frameLerp = 1000 / fps; - animations[ i ].initialLerp = 1000 / fps; - } - - if( i != MAX_BUILDABLE_ANIMATIONS ) - { - CG_Printf( "Error parsing animation file: %s\n", filename ); - return qfalse; - } - - return qtrue; -} - -/* -====================== -CG_ParseBuildableSoundFile - -Read a configuration file containing sound properties -sound/buildables/hivemind/sound.cfg, etc -====================== -*/ -static qboolean CG_ParseBuildableSoundFile( const char *filename, buildable_t buildable ) -{ - char *text_p; - int len; - int i; - char *token; - char text[ 20000 ]; - fileHandle_t f; - sound_t *sounds; - - sounds = cg_buildables[ buildable ].sounds; - - // load the file - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - if ( len <= 0 ) - return qfalse; - - if ( len >= sizeof( text ) - 1 ) - { - CG_Printf( "File %s too long\n", filename ); - return qfalse; - } - - trap_FS_Read( text, len, f ); - text[len] = 0; - trap_FS_FCloseFile( f ); - - // parse the text - text_p = text; - - // read information for each frame - for( i = BANIM_NONE + 1; i < MAX_BUILDABLE_ANIMATIONS; i++ ) - { - - token = COM_Parse( &text_p ); - if ( !*token ) - break; - - sounds[ i ].enabled = atoi( token ); - - token = COM_Parse( &text_p ); - if ( !*token ) - break; - - sounds[ i ].looped = atoi( token ); - - } - - if( i != MAX_BUILDABLE_ANIMATIONS ) - { - CG_Printf( "Error parsing sound file: %s\n", filename ); - return qfalse; - } - - return qtrue; -} -/* -=============== -CG_InitBuildables - -Initialises the animation db -=============== -*/ -void CG_InitBuildables( void ) -{ - char filename[ MAX_QPATH ]; - char soundfile[ MAX_QPATH ]; - char *buildableName; - char *modelFile; - int i; - int j; - fileHandle_t f; - - memset( cg_buildables, 0, sizeof( cg_buildables ) ); - - //default sounds - for( j = BANIM_NONE + 1; j < MAX_BUILDABLE_ANIMATIONS; j++ ) - { - strcpy( soundfile, cg_buildableSoundNames[ j - 1 ] ); - - Com_sprintf( filename, sizeof( filename ), "sound/buildables/alien/%s", soundfile ); - defaultAlienSounds[ j ] = trap_S_RegisterSound( filename, qfalse ); - - Com_sprintf( filename, sizeof( filename ), "sound/buildables/human/%s", soundfile ); - defaultHumanSounds[ j ] = trap_S_RegisterSound( filename, qfalse ); - } - - cg.buildablesFraction = 0.0f; - - for( i = BA_NONE + 1; i < BA_NUM_BUILDABLES; i++ ) - { - buildableName = BG_FindNameForBuildable( i ); - - //animation.cfg - Com_sprintf( filename, sizeof( filename ), "models/buildables/%s/animation.cfg", buildableName ); - if ( !CG_ParseBuildableAnimationFile( filename, i ) ) - Com_Printf( S_COLOR_YELLOW "WARNING: failed to load animation file %s\n", filename ); - - //sound.cfg - Com_sprintf( filename, sizeof( filename ), "sound/buildables/%s/sound.cfg", buildableName ); - if ( !CG_ParseBuildableSoundFile( filename, i ) ) - Com_Printf( S_COLOR_YELLOW "WARNING: failed to load sound file %s\n", filename ); - - //models - for( j = 0; j <= 3; j++ ) - { - if( ( modelFile = BG_FindModelsForBuildable( i, j ) ) ) - cg_buildables[ i ].models[ j ] = trap_R_RegisterModel( modelFile ); - } - - //sounds - for( j = BANIM_NONE + 1; j < MAX_BUILDABLE_ANIMATIONS; j++ ) - { - strcpy( soundfile, cg_buildableSoundNames[ j - 1 ] ); - Com_sprintf( filename, sizeof( filename ), "sound/buildables/%s/%s", buildableName, soundfile ); - - if( cg_buildables[ i ].sounds[ j ].enabled ) - { - if( trap_FS_FOpenFile( filename, &f, FS_READ ) > 0 ) - { - //file exists so close it - trap_FS_FCloseFile( f ); - - cg_buildables[ i ].sounds[ j ].sound = trap_S_RegisterSound( filename, qfalse ); - } - else - { - //file doesn't exist - use default - if( BG_FindTeamForBuildable( i ) == BIT_ALIENS ) - cg_buildables[ i ].sounds[ j ].sound = defaultAlienSounds[ j ]; - else - cg_buildables[ i ].sounds[ j ].sound = defaultHumanSounds[ j ]; - } - } - } - - cg.buildablesFraction = (float)i / (float)( BA_NUM_BUILDABLES - 1 ); - trap_UpdateScreen( ); - } - - cgs.media.teslaZapTS = CG_RegisterTrailSystem( "models/buildables/tesla/zap" ); -} - -/* -=============== -CG_SetBuildableLerpFrameAnimation - -may include ANIM_TOGGLEBIT -=============== -*/ -static void CG_SetBuildableLerpFrameAnimation( buildable_t buildable, lerpFrame_t *lf, int newAnimation ) -{ - animation_t *anim; - - lf->animationNumber = newAnimation; - - if( newAnimation < 0 || newAnimation >= MAX_BUILDABLE_ANIMATIONS ) - CG_Error( "Bad animation number: %i", newAnimation ); - - anim = &cg_buildables[ buildable ].animations[ newAnimation ]; - - //this item has just spawned so lf->frameTime will be zero - if( !lf->animation ) - lf->frameTime = cg.time + 1000; //1 sec delay before starting the spawn anim - - lf->animation = anim; - lf->animationTime = lf->frameTime + anim->initialLerp; - - if( cg_debugAnim.integer ) - CG_Printf( "Anim: %i\n", newAnimation ); -} - -/* -=============== -CG_RunBuildableLerpFrame - -Sets cg.snap, cg.oldFrame, and cg.backlerp -cg.time should be between oldFrameTime and frameTime after exit -=============== -*/ -static void CG_RunBuildableLerpFrame( centity_t *cent ) -{ - int f, numFrames; - buildable_t buildable = cent->currentState.modelindex; - lerpFrame_t *lf = ¢->lerpFrame; - animation_t *anim; - buildableAnimNumber_t newAnimation = cent->buildableAnim & ~( ANIM_TOGGLEBIT|ANIM_FORCEBIT ); - - // debugging tool to get no animations - if( cg_animSpeed.integer == 0 ) - { - lf->oldFrame = lf->frame = lf->backlerp = 0; - return; - } - - // see if the animation sequence is switching - if( newAnimation != lf->animationNumber || !lf->animation ) - { - if( cg_debugRandom.integer ) - CG_Printf( "newAnimation: %d lf->animationNumber: %d lf->animation: %d\n", - newAnimation, lf->animationNumber, lf->animation ); - - CG_SetBuildableLerpFrameAnimation( buildable, lf, newAnimation ); - - if( !cg_buildables[ buildable ].sounds[ newAnimation ].looped && - cg_buildables[ buildable ].sounds[ newAnimation ].enabled ) - { - if( cg_debugRandom.integer ) - CG_Printf( "Sound for animation %d for a %s\n", - newAnimation, BG_FindHumanNameForBuildable( buildable ) ); - - trap_S_StartSound( cent->lerpOrigin, cent->currentState.number, CHAN_AUTO, - cg_buildables[ buildable ].sounds[ newAnimation ].sound ); - } - } - - if( cg_buildables[ buildable ].sounds[ lf->animationNumber ].looped && - cg_buildables[ buildable ].sounds[ lf->animationNumber ].enabled ) - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, - cg_buildables[ buildable ].sounds[ lf->animationNumber ].sound ); - - // if we have passed the current frame, move it to - // oldFrame and calculate a new frame - if( cg.time >= lf->frameTime ) - { - lf->oldFrame = lf->frame; - lf->oldFrameTime = lf->frameTime; - - // get the next frame based on the animation - anim = lf->animation; - if( !anim->frameLerp ) - return; // shouldn't happen - - if ( cg.time < lf->animationTime ) - lf->frameTime = lf->animationTime; // initial lerp - else - lf->frameTime = lf->oldFrameTime + anim->frameLerp; - - f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp; - numFrames = anim->numFrames; - if(anim->flipflop) - numFrames *= 2; - - if( f >= numFrames ) - { - f -= numFrames; - if( anim->loopFrames ) - { - f %= anim->loopFrames; - f += anim->numFrames - anim->loopFrames; - } - else - { - f = numFrames - 1; - // the animation is stuck at the end, so it - // can immediately transition to another sequence - lf->frameTime = cg.time; - cent->buildableAnim = cent->currentState.torsoAnim; - } - } - - if( anim->reversed ) - lf->frame = anim->firstFrame + anim->numFrames - 1 - f; - else if( anim->flipflop && f >= anim->numFrames ) - lf->frame = anim->firstFrame + anim->numFrames - 1 - ( f % anim->numFrames ); - else - lf->frame = anim->firstFrame + f; - - if( cg.time > lf->frameTime ) - { - lf->frameTime = cg.time; - if( cg_debugAnim.integer ) - CG_Printf( "Clamp lf->frameTime\n"); - } - } - - if( lf->frameTime > cg.time + 200 ) - lf->frameTime = cg.time; - - if( lf->oldFrameTime > cg.time ) - lf->oldFrameTime = cg.time; - - // calculate current lerp value - if( lf->frameTime == lf->oldFrameTime ) - lf->backlerp = 0; - else - lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime ); -} - -/* -=============== -CG_BuildableAnimation -=============== -*/ -static void CG_BuildableAnimation( centity_t *cent, int *old, int *now, float *backLerp ) -{ - entityState_t *es = ¢->currentState; - - //if no animation is set default to idle anim - if( cent->buildableAnim == BANIM_NONE ) - cent->buildableAnim = es->torsoAnim; - - //display the first frame of the construction anim if not yet spawned - if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) ) - { - animation_t *anim = &cg_buildables[ es->modelindex ].animations[ BANIM_CONSTRUCT1 ]; - - //so that when animation starts for real it has sensible numbers - cent->lerpFrame.oldFrameTime = - cent->lerpFrame.frameTime = - cent->lerpFrame.animationTime = - cg.time; - - *old = cent->lerpFrame.oldFrame = anim->firstFrame; - *now = cent->lerpFrame.frame = anim->firstFrame; - *backLerp = cent->lerpFrame.backlerp = 0.0f; - - //ensure that an animation is triggered once the buildable has spawned - cent->oldBuildableAnim = BANIM_NONE; - } - else - { - if( ( cent->oldBuildableAnim ^ es->legsAnim ) & ANIM_TOGGLEBIT ) - { - if( cg_debugAnim.integer ) - CG_Printf( "%d->%d l:%d t:%d %s(%d)\n", - cent->oldBuildableAnim, cent->buildableAnim, - es->legsAnim, es->torsoAnim, - BG_FindHumanNameForBuildable( es->modelindex ), es->number ); - - if( cent->buildableAnim == es->torsoAnim || es->legsAnim & ANIM_FORCEBIT ) - cent->buildableAnim = cent->oldBuildableAnim = es->legsAnim; - else - cent->buildableAnim = cent->oldBuildableAnim = es->torsoAnim; - } - - CG_RunBuildableLerpFrame( cent ); - - *old = cent->lerpFrame.oldFrame; - *now = cent->lerpFrame.frame; - *backLerp = cent->lerpFrame.backlerp; - } -} - -#define TRACE_DEPTH 64.0f - -/* -=============== -CG_PositionAndOrientateBuildable -=============== -*/ -static void CG_PositionAndOrientateBuildable( const vec3_t angles, const vec3_t inOrigin, - const vec3_t normal, const int skipNumber, - const vec3_t mins, const vec3_t maxs, - vec3_t outAxis[ 3 ], vec3_t outOrigin ) -{ - vec3_t forward, start, end; - trace_t tr; - - AngleVectors( angles, forward, NULL, NULL ); - VectorCopy( normal, outAxis[ 2 ] ); - ProjectPointOnPlane( outAxis[ 0 ], forward, outAxis[ 2 ] ); - - if( !VectorNormalize( outAxis[ 0 ] ) ) - { - AngleVectors( angles, NULL, NULL, forward ); - ProjectPointOnPlane( outAxis[ 0 ], forward, outAxis[ 2 ] ); - VectorNormalize( outAxis[ 0 ] ); - } - - CrossProduct( outAxis[ 0 ], outAxis[ 2 ], outAxis[ 1 ] ); - outAxis[ 1 ][ 0 ] = -outAxis[ 1 ][ 0 ]; - outAxis[ 1 ][ 1 ] = -outAxis[ 1 ][ 1 ]; - outAxis[ 1 ][ 2 ] = -outAxis[ 1 ][ 2 ]; - - VectorMA( inOrigin, -TRACE_DEPTH, normal, end ); - VectorMA( inOrigin, 1.0f, normal, start ); - CG_CapTrace( &tr, start, mins, maxs, end, skipNumber, MASK_SOLID ); - - if( tr.fraction == 1.0f ) - { - //erm we missed completely - try again with a box trace - CG_Trace( &tr, start, mins, maxs, end, skipNumber, MASK_SOLID ); - } - - VectorMA( inOrigin, tr.fraction * -TRACE_DEPTH, normal, outOrigin ); -} - -/* -================== -CG_GhostBuildable -================== -*/ -void CG_GhostBuildable( buildable_t buildable ) -{ - refEntity_t ent; - playerState_t *ps; - vec3_t angles, entity_origin; - vec3_t mins, maxs; - trace_t tr; - float scale; - - ps = &cg.predictedPlayerState; - - memset( &ent, 0, sizeof( ent ) ); - - BG_FindBBoxForBuildable( buildable, mins, maxs ); - - BG_PositionBuildableRelativeToPlayer( ps, mins, maxs, CG_Trace, entity_origin, angles, &tr ); - - CG_PositionAndOrientateBuildable( ps->viewangles, entity_origin, tr.plane.normal, ps->clientNum, - mins, maxs, ent.axis, ent.origin ); - - //offset on the Z axis if required - VectorMA( ent.origin, BG_FindZOffsetForBuildable( buildable ), tr.plane.normal, ent.origin ); - - VectorCopy( ent.origin, ent.lightingOrigin ); - VectorCopy( ent.origin, ent.oldorigin ); // don't positionally lerp at all - - ent.hModel = cg_buildables[ buildable ].models[ 0 ]; - - if( ps->stats[ STAT_BUILDABLE ] & SB_VALID_TOGGLEBIT ) - ent.customShader = cgs.media.greenBuildShader; - else - ent.customShader = cgs.media.redBuildShader; - - //rescale the model - scale = BG_FindModelScaleForBuildable( buildable ); - - if( scale != 1.0f ) - { - VectorScale( ent.axis[ 0 ], scale, ent.axis[ 0 ] ); - VectorScale( ent.axis[ 1 ], scale, ent.axis[ 1 ] ); - VectorScale( ent.axis[ 2 ], scale, ent.axis[ 2 ] ); - - ent.nonNormalizedAxes = qtrue; - } - else - ent.nonNormalizedAxes = qfalse; - - // add to refresh list - trap_R_AddRefEntityToScene( &ent ); -} - -/* -================== -CG_BuildableParticleEffects -================== -*/ -static void CG_BuildableParticleEffects( centity_t *cent ) -{ - entityState_t *es = ¢->currentState; - buildableTeam_t team = BG_FindTeamForBuildable( es->modelindex ); - int health = es->generic1 & ~( B_POWERED_TOGGLEBIT | B_DCCED_TOGGLEBIT | B_SPAWNED_TOGGLEBIT ); - float healthFrac = (float)health / B_HEALTH_SCALE; - - if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) ) - return; - - if( team == BIT_HUMANS ) - { - if( healthFrac < 0.33f && !CG_IsParticleSystemValid( ¢->buildablePS ) ) - { - cent->buildablePS = CG_SpawnNewParticleSystem( cgs.media.humanBuildableDamagedPS ); - - if( CG_IsParticleSystemValid( ¢->buildablePS ) ) - { - CG_SetAttachmentCent( ¢->buildablePS->attachment, cent ); - CG_AttachToCent( ¢->buildablePS->attachment ); - } - } - else if( healthFrac >= 0.33f && CG_IsParticleSystemValid( ¢->buildablePS ) ) - CG_DestroyParticleSystem( ¢->buildablePS ); - } - else if( team == BIT_ALIENS ) - { - if( healthFrac < 0.33f && !CG_IsParticleSystemValid( ¢->buildablePS ) ) - { - cent->buildablePS = CG_SpawnNewParticleSystem( cgs.media.alienBuildableDamagedPS ); - - if( CG_IsParticleSystemValid( ¢->buildablePS ) ) - { - CG_SetAttachmentCent( ¢->buildablePS->attachment, cent ); - CG_SetParticleSystemNormal( cent->buildablePS, es->origin2 ); - CG_AttachToCent( ¢->buildablePS->attachment ); - } - } - else if( healthFrac >= 0.33f && CG_IsParticleSystemValid( ¢->buildablePS ) ) - CG_DestroyParticleSystem( ¢->buildablePS ); - } -} - - -#define HEALTH_BAR_WIDTH 50.0f -#define HEALTH_BAR_HEIGHT 5.0f - -/* -================== -CG_BuildableHealthBar -================== -*/ -static void CG_BuildableHealthBar( centity_t *cent ) -{ - vec3_t origin, origin2, down, right, back, downLength, rightLength; - float rimWidth = HEALTH_BAR_HEIGHT / 15.0f; - float doneWidth, leftWidth, progress; - int health; - qhandle_t shader; - entityState_t *es; - vec3_t mins, maxs; - - es = ¢->currentState; - - health = es->generic1 & ~( B_POWERED_TOGGLEBIT | B_DCCED_TOGGLEBIT | B_SPAWNED_TOGGLEBIT ); - progress = (float)health / B_HEALTH_SCALE; - - if( progress < 0.0f ) - progress = 0.0f; - else if( progress > 1.0f ) - progress = 1.0f; - - if( progress < 0.33f ) - shader = cgs.media.redBuildShader; - else - shader = cgs.media.greenBuildShader; - - doneWidth = ( HEALTH_BAR_WIDTH - 2 * rimWidth ) * progress; - leftWidth = ( HEALTH_BAR_WIDTH - 2 * rimWidth ) - doneWidth; - - VectorCopy( cg.refdef.viewaxis[ 2 ], down ); - VectorInverse( down ); - VectorCopy( cg.refdef.viewaxis[ 1 ], right ); - VectorInverse( right ); - VectorSubtract( cg.refdef.vieworg, cent->lerpOrigin, back ); - VectorNormalize( back ); - VectorCopy( cent->lerpOrigin, origin ); - - BG_FindBBoxForBuildable( es->modelindex, mins, maxs ); - VectorMA( origin, 48.0f, es->origin2, origin ); - VectorMA( origin, -HEALTH_BAR_WIDTH / 2.0f, right, origin ); - VectorMA( origin, maxs[ 0 ] + 8.0f, back, origin ); - - VectorCopy( origin, origin2 ); - VectorScale( right, rimWidth + doneWidth, rightLength ); - VectorScale( down, HEALTH_BAR_HEIGHT, downLength ); - CG_DrawPlane( origin2, downLength, rightLength, shader ); - - VectorMA( origin, rimWidth + doneWidth, right, origin2 ); - VectorScale( right, leftWidth, rightLength ); - VectorScale( down, rimWidth, downLength ); - CG_DrawPlane( origin2, downLength, rightLength, shader ); - - VectorMA( origin, rimWidth + doneWidth, right, origin2 ); - VectorMA( origin2, HEALTH_BAR_HEIGHT - rimWidth, down, origin2 ); - VectorScale( right, leftWidth, rightLength ); - VectorScale( down, rimWidth, downLength ); - CG_DrawPlane( origin2, downLength, rightLength, shader ); - - VectorMA( origin, HEALTH_BAR_WIDTH - rimWidth, right, origin2 ); - VectorScale( right, rimWidth, rightLength ); - VectorScale( down, HEALTH_BAR_HEIGHT, downLength ); - CG_DrawPlane( origin2, downLength, rightLength, shader ); - - if( !( es->generic1 & B_POWERED_TOGGLEBIT ) && - BG_FindTeamForBuildable( es->modelindex ) == BIT_HUMANS ) - { - VectorMA( origin, 15.0f, right, origin2 ); - VectorMA( origin2, HEALTH_BAR_HEIGHT + 5.0f, down, origin2 ); - VectorScale( right, HEALTH_BAR_WIDTH / 2.0f - 5.0f, rightLength ); - VectorScale( down, HEALTH_BAR_WIDTH / 2.0f - 5.0f, downLength ); - CG_DrawPlane( origin2, downLength, rightLength, cgs.media.noPowerShader ); - } -} - -#define BUILDABLE_SOUND_PERIOD 500 - -/* -================== -CG_Buildable -================== -*/ -void CG_Buildable( centity_t *cent ) -{ - refEntity_t ent; - entityState_t *es = ¢->currentState; - vec3_t angles; - vec3_t surfNormal, xNormal, mins, maxs; - vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; - float rotAngle; - buildableTeam_t team = BG_FindTeamForBuildable( es->modelindex ); - float scale; - int health; - float healthScale; - - //must be before EF_NODRAW check - if( team == BIT_ALIENS ) - CG_Creep( cent ); - - // if set to invisible, skip - if( es->eFlags & EF_NODRAW ) - { - if( CG_IsParticleSystemValid( ¢->buildablePS ) ) - CG_DestroyParticleSystem( ¢->buildablePS ); - - return; - } - - memset ( &ent, 0, sizeof( ent ) ); - - VectorCopy( cent->lerpOrigin, ent.origin ); - VectorCopy( cent->lerpOrigin, ent.oldorigin ); - VectorCopy( cent->lerpOrigin, ent.lightingOrigin ); - - VectorCopy( es->origin2, surfNormal ); - - VectorCopy( es->angles, angles ); - BG_FindBBoxForBuildable( es->modelindex, mins, maxs ); - - if( es->pos.trType == TR_STATIONARY ) - CG_PositionAndOrientateBuildable( angles, ent.origin, surfNormal, es->number, - mins, maxs, ent.axis, ent.origin ); - - //offset on the Z axis if required - VectorMA( ent.origin, BG_FindZOffsetForBuildable( es->modelindex ), surfNormal, ent.origin ); - - VectorCopy( ent.origin, ent.oldorigin ); // don't positionally lerp at all - VectorCopy( ent.origin, ent.lightingOrigin ); - - ent.hModel = cg_buildables[ es->modelindex ].models[ 0 ]; - - if( !( es->generic1 & B_SPAWNED_TOGGLEBIT ) ) - { - sfxHandle_t prebuildSound = cgs.media.humanBuildablePrebuild; - - if( team == BIT_HUMANS ) - { - ent.customShader = cgs.media.humanSpawningShader; - prebuildSound = cgs.media.humanBuildablePrebuild; - } - else if( team == BIT_ALIENS ) - prebuildSound = cgs.media.alienBuildablePrebuild; - - trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, prebuildSound ); - } - - CG_BuildableAnimation( cent, &ent.oldframe, &ent.frame, &ent.backlerp ); - - //rescale the model - scale = BG_FindModelScaleForBuildable( es->modelindex ); - - if( scale != 1.0f ) - { - VectorScale( ent.axis[ 0 ], scale, ent.axis[ 0 ] ); - VectorScale( ent.axis[ 1 ], scale, ent.axis[ 1 ] ); - VectorScale( ent.axis[ 2 ], scale, ent.axis[ 2 ] ); - - ent.nonNormalizedAxes = qtrue; - } - else - ent.nonNormalizedAxes = qfalse; - - - //add to refresh list - trap_R_AddRefEntityToScene( &ent ); - - CrossProduct( surfNormal, refNormal, xNormal ); - VectorNormalize( xNormal ); - rotAngle = RAD2DEG( acos( DotProduct( surfNormal, refNormal ) ) ); - - //turret barrel bit - if( cg_buildables[ es->modelindex ].models[ 1 ] ) - { - refEntity_t turretBarrel; - vec3_t flatAxis[ 3 ]; - - memset( &turretBarrel, 0, sizeof( turretBarrel ) ); - - turretBarrel.hModel = cg_buildables[ es->modelindex ].models[ 1 ]; - - CG_PositionEntityOnTag( &turretBarrel, &ent, ent.hModel, "tag_turret" ); - VectorCopy( cent->lerpOrigin, turretBarrel.lightingOrigin ); - AnglesToAxis( es->angles2, flatAxis ); - - RotatePointAroundVector( turretBarrel.axis[ 0 ], xNormal, flatAxis[ 0 ], -rotAngle ); - RotatePointAroundVector( turretBarrel.axis[ 1 ], xNormal, flatAxis[ 1 ], -rotAngle ); - RotatePointAroundVector( turretBarrel.axis[ 2 ], xNormal, flatAxis[ 2 ], -rotAngle ); - - turretBarrel.oldframe = ent.oldframe; - turretBarrel.frame = ent.frame; - turretBarrel.backlerp = ent.backlerp; - - turretBarrel.customShader = ent.customShader; - - if( scale != 1.0f ) - { - VectorScale( turretBarrel.axis[ 0 ], scale, turretBarrel.axis[ 0 ] ); - VectorScale( turretBarrel.axis[ 1 ], scale, turretBarrel.axis[ 1 ] ); - VectorScale( turretBarrel.axis[ 2 ], scale, turretBarrel.axis[ 2 ] ); - - turretBarrel.nonNormalizedAxes = qtrue; - } - else - turretBarrel.nonNormalizedAxes = qfalse; - - trap_R_AddRefEntityToScene( &turretBarrel ); - } - - //turret barrel bit - if( cg_buildables[ es->modelindex ].models[ 2 ] ) - { - refEntity_t turretTop; - vec3_t flatAxis[ 3 ]; - vec3_t swivelAngles; - - memset( &turretTop, 0, sizeof( turretTop ) ); - - VectorCopy( es->angles2, swivelAngles ); - swivelAngles[ PITCH ] = 0.0f; - - turretTop.hModel = cg_buildables[ es->modelindex ].models[ 2 ]; - - CG_PositionRotatedEntityOnTag( &turretTop, &ent, ent.hModel, "tag_turret" ); - VectorCopy( cent->lerpOrigin, turretTop.lightingOrigin ); - AnglesToAxis( swivelAngles, flatAxis ); - - RotatePointAroundVector( turretTop.axis[ 0 ], xNormal, flatAxis[ 0 ], -rotAngle ); - RotatePointAroundVector( turretTop.axis[ 1 ], xNormal, flatAxis[ 1 ], -rotAngle ); - RotatePointAroundVector( turretTop.axis[ 2 ], xNormal, flatAxis[ 2 ], -rotAngle ); - - turretTop.oldframe = ent.oldframe; - turretTop.frame = ent.frame; - turretTop.backlerp = ent.backlerp; - - turretTop.customShader = ent.customShader; - - if( scale != 1.0f ) - { - VectorScale( turretTop.axis[ 0 ], scale, turretTop.axis[ 0 ] ); - VectorScale( turretTop.axis[ 1 ], scale, turretTop.axis[ 1 ] ); - VectorScale( turretTop.axis[ 2 ], scale, turretTop.axis[ 2 ] ); - - turretTop.nonNormalizedAxes = qtrue; - } - else - turretTop.nonNormalizedAxes = qfalse; - - trap_R_AddRefEntityToScene( &turretTop ); - } - - switch( cg.predictedPlayerState.weapon ) - { - case WP_ABUILD: - case WP_ABUILD2: - case WP_HBUILD: - case WP_HBUILD2: - if( BG_FindTeamForBuildable( es->modelindex ) == - BG_FindTeamForWeapon( cg.predictedPlayerState.weapon ) ) - CG_BuildableHealthBar( cent ); - break; - - default: - break; - } - - //weapon effects for turrets - if( es->eFlags & EF_FIRING ) - { - weaponInfo_t *weapon = &cg_weapons[ es->weapon ]; - - if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME || - BG_FindProjTypeForBuildable( es->modelindex ) == WP_TESLAGEN ) - { - if( weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ] || - weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ] || - weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 2 ] ) - { - trap_R_AddLightToScene( cent->lerpOrigin, 300 + ( rand( ) & 31 ), - weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 0 ], - weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 1 ], - weapon->wim[ WPM_PRIMARY ].flashDlightColor[ 2 ] ); - } - } - - if( weapon->wim[ WPM_PRIMARY ].firingSound ) - { - trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, - weapon->wim[ WPM_PRIMARY ].firingSound ); - } - else if( weapon->readySound ) - trap_S_AddLoopingSound( es->number, cent->lerpOrigin, vec3_origin, weapon->readySound ); - } - - health = es->generic1 & ~( B_POWERED_TOGGLEBIT | B_DCCED_TOGGLEBIT | B_SPAWNED_TOGGLEBIT ); - healthScale = (float)health / B_HEALTH_SCALE; - - if( healthScale < cent->lastBuildableHealthScale && ( es->generic1 & B_SPAWNED_TOGGLEBIT ) ) - { - if( cent->lastBuildableDamageSoundTime + BUILDABLE_SOUND_PERIOD < cg.time ) - { - if( team == BIT_HUMANS ) - { - int i = rand( ) % 4; - trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.humanBuildableDamage[ i ] ); - } - else if( team == BIT_ALIENS ) - trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienBuildableDamage ); - - cent->lastBuildableDamageSoundTime = cg.time; - } - } - - cent->lastBuildableHealthScale = healthScale; - - //smoke etc for damaged buildables - CG_BuildableParticleEffects( cent ); -} diff --git a/src/cgame/cg_consolecmds.c b/src/cgame/cg_consolecmds.c deleted file mode 100644 index c875fa48..00000000 --- a/src/cgame/cg_consolecmds.c +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_consolecmds.c -- text commands typed in at the local console, or -// executed by a key binding - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - - - -void CG_TargetCommand_f( void ) -{ - int targetNum; - char test[ 4 ]; - - targetNum = CG_CrosshairPlayer( ); - if( !targetNum ) - return; - - trap_Argv( 1, test, 4 ); - trap_SendConsoleCommand( va( "gc %i %i", targetNum, atoi( test ) ) ); -} - - - -/* -================= -CG_SizeUp_f - -Keybinding command -================= -*/ -static void CG_SizeUp_f( void ) -{ - trap_Cvar_Set( "cg_viewsize", va( "%i", (int)( cg_viewsize.integer + 10 ) ) ); -} - - -/* -================= -CG_SizeDown_f - -Keybinding command -================= -*/ -static void CG_SizeDown_f( void ) -{ - trap_Cvar_Set( "cg_viewsize", va( "%i", (int)( cg_viewsize.integer - 10 ) ) ); -} - - -/* -============= -CG_Viewpos_f - -Debugging command to print the current position -============= -*/ -static void CG_Viewpos_f( void ) -{ - CG_Printf( "(%i %i %i) : %i\n", (int)cg.refdef.vieworg[ 0 ], - (int)cg.refdef.vieworg[ 1 ], (int)cg.refdef.vieworg[ 2 ], - (int)cg.refdefViewAngles[ YAW ] ); -} - - -static void CG_ScoresDown_f( void ) -{ - if( cg.scoresRequestTime + 2000 < cg.time ) - { - // the scores are more than two seconds out of data, - // so request new ones - cg.scoresRequestTime = cg.time; - //TA: added \n SendClientCommand doesn't call flush( )? - trap_SendClientCommand( "score\n" ); - - // leave the current scores up if they were already - // displayed, but if this is the first hit, clear them out - if( !cg.showScores ) - { - if( cg_debugRandom.integer ) - CG_Printf( "CG_ScoresDown_f: scores out of date\n" ); - - cg.showScores = qtrue; - cg.numScores = 0; - } - } - else - { - // show the cached contents even if they just pressed if it - // is within two seconds - cg.showScores = qtrue; - } -} - -static void CG_ScoresUp_f( void ) -{ - if( cg.showScores ) - { - cg.showScores = qfalse; - cg.scoreFadeTime = cg.time; - } -} - -static void CG_TellTarget_f( void ) -{ - int clientNum; - char command[ 128 ]; - char message[ 128 ]; - - clientNum = CG_CrosshairPlayer( ); - if( clientNum == -1 ) - return; - - trap_Args( message, 128 ); - Com_sprintf( command, 128, "tell %i %s", clientNum, message ); - trap_SendClientCommand( command ); -} - -static void CG_TellAttacker_f( void ) -{ - int clientNum; - char command[ 128 ]; - char message[ 128 ]; - - clientNum = CG_LastAttacker( ); - if( clientNum == -1 ) - return; - - trap_Args( message, 128 ); - Com_sprintf( command, 128, "tell %i %s", clientNum, message ); - trap_SendClientCommand( command ); -} - -typedef struct -{ - char *cmd; - void (*function)( void ); -} consoleCommand_t; - -static consoleCommand_t commands[ ] = -{ - { "testgun", CG_TestGun_f }, - { "testmodel", CG_TestModel_f }, - { "nextframe", CG_TestModelNextFrame_f }, - { "prevframe", CG_TestModelPrevFrame_f }, - { "nextskin", CG_TestModelNextSkin_f }, - { "prevskin", CG_TestModelPrevSkin_f }, - { "viewpos", CG_Viewpos_f }, - { "+scores", CG_ScoresDown_f }, - { "-scores", CG_ScoresUp_f }, - { "+zoom", CG_ZoomDown_f }, - { "-zoom", CG_ZoomUp_f }, - { "sizeup", CG_SizeUp_f }, - { "sizedown", CG_SizeDown_f }, - { "weapnext", CG_NextWeapon_f }, - { "weapprev", CG_PrevWeapon_f }, - { "weapon", CG_Weapon_f }, - { "tell_target", CG_TellTarget_f }, - { "tell_attacker", CG_TellAttacker_f }, - { "tcmd", CG_TargetCommand_f }, - { "testPS", CG_TestPS_f }, - { "destroyTestPS", CG_DestroyTestPS_f }, - { "testTS", CG_TestTS_f }, - { "destroyTestTS", CG_DestroyTestTS_f }, -}; - - -/* -================= -CG_ConsoleCommand - -The string has been tokenized and can be retrieved with -Cmd_Argc() / Cmd_Argv() -================= -*/ -qboolean CG_ConsoleCommand( void ) -{ - const char *cmd; - const char *arg1; - int i; - - cmd = CG_Argv( 0 ); - - //TA: ugly hacky special case - if( !Q_stricmp( cmd, "ui_menu" ) ) - { - arg1 = CG_Argv( 1 ); - trap_SendConsoleCommand( va( "menu %s\n", arg1 ) ); - return qtrue; - } - - for( i = 0; i < sizeof( commands ) / sizeof( commands[ 0 ] ); i++ ) - { - if( !Q_stricmp( cmd, commands[ i ].cmd ) ) - { - commands[ i ].function( ); - return qtrue; - } - } - - return qfalse; -} - - -/* -================= -CG_InitConsoleCommands - -Let the client system know about all of our commands -so it can perform tab completion -================= -*/ -void CG_InitConsoleCommands( void ) -{ - int i; - - for( i = 0 ; i < sizeof( commands ) / sizeof( commands[ 0 ] ) ; i++ ) - trap_AddCommand( commands[ i ].cmd ); - - // - // the game server will interpret these commands, which will be automatically - // forwarded to the server after they are not recognized locally - // - trap_AddCommand( "kill" ); - trap_AddCommand( "say" ); - trap_AddCommand( "say_team" ); - trap_AddCommand( "tell" ); - trap_AddCommand( "vsay" ); - trap_AddCommand( "vsay_team" ); - trap_AddCommand( "vtell" ); - trap_AddCommand( "vtaunt" ); - trap_AddCommand( "vosay" ); - trap_AddCommand( "vosay_team" ); - trap_AddCommand( "votell" ); - trap_AddCommand( "give" ); - trap_AddCommand( "god" ); - trap_AddCommand( "notarget" ); - trap_AddCommand( "noclip" ); - trap_AddCommand( "team" ); - trap_AddCommand( "follow" ); - trap_AddCommand( "levelshot" ); - trap_AddCommand( "addbot" ); - trap_AddCommand( "setviewpos" ); - trap_AddCommand( "callvote" ); - trap_AddCommand( "vote" ); - trap_AddCommand( "callteamvote" ); - trap_AddCommand( "teamvote" ); - trap_AddCommand( "stats" ); - trap_AddCommand( "teamtask" ); - trap_AddCommand( "class" ); - trap_AddCommand( "build" ); - trap_AddCommand( "buy" ); - trap_AddCommand( "sell" ); - trap_AddCommand( "reload" ); - trap_AddCommand( "itemact" ); - trap_AddCommand( "itemdeact" ); - trap_AddCommand( "itemtoggle" ); - trap_AddCommand( "destroy" ); - trap_AddCommand( "deconstruct" ); - trap_AddCommand( "menu" ); - trap_AddCommand( "ui_menu" ); - trap_AddCommand( "mapRotation" ); - trap_AddCommand( "stopMapRotation" ); - trap_AddCommand( "alienWin" ); - trap_AddCommand( "humanWin" ); -} diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c deleted file mode 100644 index d7c07036..00000000 --- a/src/cgame/cg_draw.c +++ /dev/null @@ -1,3393 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_draw.c -- draw all of the graphical elements during -// active (after loading) gameplay - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" -#include "../ui/ui_shared.h" - -// used for scoreboard -extern displayContextDef_t cgDC; -menuDef_t *menuScoreboard = NULL; - -int drawTeamOverlayModificationCount = -1; - -int sortedTeamPlayers[ TEAM_MAXOVERLAY ]; -int numSortedTeamPlayers; -char systemChat[ 256 ]; -char teamChat1[ 256 ]; -char teamChat2[ 256 ]; - -//TA UI -int CG_Text_Width( const char *text, float scale, int limit ) -{ - int count,len; - float out; - glyphInfo_t *glyph; - float useScale; -// FIXME: see ui_main.c, same problem -// const unsigned char *s = text; - const char *s = text; - fontInfo_t *font = &cgDC.Assets.textFont; - - if( scale <= cg_smallFont.value ) - font = &cgDC.Assets.smallFont; - else if( scale > cg_bigFont.value ) - font = &cgDC.Assets.bigFont; - - useScale = scale * font->glyphScale; - out = 0; - - if( text ) - { - len = strlen( text ); - if( limit > 0 && len > limit ) - len = limit; - - count = 0; - while( s && *s && count < len ) - { - if( Q_IsColorString( s ) ) - { - s += 2; - continue; - } - else - { - glyph = &font->glyphs[ (int)*s ]; - //TTimo: FIXME: getting nasty warnings without the cast, - //hopefully this doesn't break the VM build - out += glyph->xSkip; - s++; - count++; - } - } - } - - return out * useScale; -} - -int CG_Text_Height( const char *text, float scale, int limit ) -{ - int len, count; - float max; - glyphInfo_t *glyph; - float useScale; -// TTimo: FIXME -// const unsigned char *s = text; - const char *s = text; - fontInfo_t *font = &cgDC.Assets.textFont; - - if( scale <= cg_smallFont.value ) - font = &cgDC.Assets.smallFont; - else if( scale > cg_bigFont.value ) - font = &cgDC.Assets.bigFont; - - useScale = scale * font->glyphScale; - max = 0; - - if( text ) - { - len = strlen( text ); - if( limit > 0 && len > limit ) - len = limit; - - count = 0; - while( s && *s && count < len ) - { - if( Q_IsColorString( s ) ) - { - s += 2; - continue; - } - else - { - glyph = &font->glyphs[ (int)*s ]; - //TTimo: FIXME: getting nasty warnings without the cast, - //hopefully this doesn't break the VM build - if( max < glyph->height ) - max = glyph->height; - - s++; - count++; - } - } - } - - return max * useScale; -} - -void CG_Text_PaintChar( float x, float y, float width, float height, float scale, - float s, float t, float s2, float t2, qhandle_t hShader ) -{ - float w, h; - w = width * scale; - h = height * scale; - CG_AdjustFrom640( &x, &y, &w, &h ); - trap_R_DrawStretchPic( x, y, w, h, s, t, s2, t2, hShader ); -} - -void CG_Text_Paint( float x, float y, float scale, vec4_t color, const char *text, - float adjust, int limit, int style ) -{ - int len, count; - vec4_t newColor; - glyphInfo_t *glyph; - float useScale; - fontInfo_t *font = &cgDC.Assets.textFont; - - if( scale <= cg_smallFont.value ) - font = &cgDC.Assets.smallFont; - else if( scale > cg_bigFont.value ) - font = &cgDC.Assets.bigFont; - - useScale = scale * font->glyphScale; - if( text ) - { -// TTimo: FIXME -// const unsigned char *s = text; - const char *s = text; - - trap_R_SetColor( color ); - memcpy( &newColor[ 0 ], &color[ 0 ], sizeof( vec4_t ) ); - len = strlen( text ); - - if( limit > 0 && len > limit ) - len = limit; - - count = 0; - while( s && *s && count < len ) - { - glyph = &font->glyphs[ (int)*s ]; - //TTimo: FIXME: getting nasty warnings without the cast, - //hopefully this doesn't break the VM build - - if( Q_IsColorString( s ) ) - { - memcpy( newColor, g_color_table[ ColorIndex( *( s + 1 ) ) ], sizeof( newColor ) ); - newColor[ 3 ] = color[ 3 ]; - trap_R_SetColor( newColor ); - s += 2; - continue; - } - else - { - float yadj = useScale * glyph->top; - if( style == ITEM_TEXTSTYLE_SHADOWED || - style == ITEM_TEXTSTYLE_SHADOWEDMORE ) - { - int ofs = style == ITEM_TEXTSTYLE_SHADOWED ? 1 : 2; - colorBlack[ 3 ] = newColor[ 3 ]; - trap_R_SetColor( colorBlack ); - CG_Text_PaintChar( x + ofs, y - yadj + ofs, - glyph->imageWidth, - glyph->imageHeight, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph ); - - colorBlack[ 3 ] = 1.0; - trap_R_SetColor( newColor ); - } - else if( style == ITEM_TEXTSTYLE_NEON ) - { - vec4_t glow, outer, inner, white; - - glow[ 0 ] = newColor[ 0 ] * 0.5; - glow[ 1 ] = newColor[ 1 ] * 0.5; - glow[ 2 ] = newColor[ 2 ] * 0.5; - glow[ 3 ] = newColor[ 3 ] * 0.2; - - outer[ 0 ] = newColor[ 0 ]; - outer[ 1 ] = newColor[ 1 ]; - outer[ 2 ] = newColor[ 2 ]; - outer[ 3 ] = newColor[ 3 ]; - - inner[ 0 ] = newColor[ 0 ] * 1.5 > 1.0f ? 1.0f : newColor[ 0 ] * 1.5; - inner[ 1 ] = newColor[ 1 ] * 1.5 > 1.0f ? 1.0f : newColor[ 1 ] * 1.5; - inner[ 2 ] = newColor[ 2 ] * 1.5 > 1.0f ? 1.0f : newColor[ 2 ] * 1.5; - inner[ 3 ] = newColor[ 3 ]; - - white[ 0 ] = white[ 1 ] = white[ 2 ] = white[ 3 ] = 1.0f; - - trap_R_SetColor( glow ); - CG_Text_PaintChar( x - 3, y - yadj - 3, - glyph->imageWidth + 6, - glyph->imageHeight + 6, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph ); - - trap_R_SetColor( outer ); - CG_Text_PaintChar( x - 1, y - yadj - 1, - glyph->imageWidth + 2, - glyph->imageHeight + 2, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph ); - - trap_R_SetColor( inner ); - CG_Text_PaintChar( x - 0.5, y - yadj - 0.5, - glyph->imageWidth + 1, - glyph->imageHeight + 1, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph ); - - trap_R_SetColor( white ); - } - - - CG_Text_PaintChar( x, y - yadj, - glyph->imageWidth, - glyph->imageHeight, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph ); - - x += ( glyph->xSkip * useScale ) + adjust; - s++; - count++; - } - } - - trap_R_SetColor( NULL ); - } -} - -/* -============== -CG_DrawFieldPadded - -Draws large numbers for status bar and powerups -============== -*/ -static void CG_DrawFieldPadded( int x, int y, int width, int cw, int ch, int value ) -{ - char num[ 16 ], *ptr; - int l, orgL; - int frame; - int charWidth, charHeight; - - if( !( charWidth = cw ) ) - charWidth = CHAR_WIDTH; - - if( !( charHeight = ch ) ) - charWidth = CHAR_HEIGHT; - - if( width < 1 ) - return; - - // draw number string - if( width > 4 ) - width = 4; - - switch( width ) - { - case 1: - value = value > 9 ? 9 : value; - value = value < 0 ? 0 : value; - break; - case 2: - value = value > 99 ? 99 : value; - value = value < -9 ? -9 : value; - break; - case 3: - value = value > 999 ? 999 : value; - value = value < -99 ? -99 : value; - break; - case 4: - value = value > 9999 ? 9999 : value; - value = value < -999 ? -999 : value; - break; - } - - Com_sprintf( num, sizeof( num ), "%d", value ); - l = strlen( num ); - - if( l > width ) - l = width; - - orgL = l; - - x += 2; - - ptr = num; - while( *ptr && l ) - { - if( width > orgL ) - { - CG_DrawPic( x,y, charWidth, charHeight, cgs.media.numberShaders[ 0 ] ); - width--; - x += charWidth; - continue; - } - - if( *ptr == '-' ) - frame = STAT_MINUS; - else - frame = *ptr - '0'; - - CG_DrawPic( x,y, charWidth, charHeight, cgs.media.numberShaders[ frame ] ); - x += charWidth; - ptr++; - l--; - } -} - -/* -============== -CG_DrawField - -Draws large numbers for status bar and powerups -============== -*/ -static void CG_DrawField( int x, int y, int width, int cw, int ch, int value ) -{ - char num[ 16 ], *ptr; - int l; - int frame; - int charWidth, charHeight; - - if( !( charWidth = cw ) ) - charWidth = CHAR_WIDTH; - - if( !( charHeight = ch ) ) - charWidth = CHAR_HEIGHT; - - if( width < 1 ) - return; - - // draw number string - if( width > 4 ) - width = 4; - - switch( width ) - { - case 1: - value = value > 9 ? 9 : value; - value = value < 0 ? 0 : value; - break; - case 2: - value = value > 99 ? 99 : value; - value = value < -9 ? -9 : value; - break; - case 3: - value = value > 999 ? 999 : value; - value = value < -99 ? -99 : value; - break; - case 4: - value = value > 9999 ? 9999 : value; - value = value < -999 ? -999 : value; - break; - } - - Com_sprintf( num, sizeof( num ), "%d", value ); - l = strlen( num ); - - if( l > width ) - l = width; - - x += 2 + charWidth * ( width - l ); - - ptr = num; - while( *ptr && l ) - { - if( *ptr == '-' ) - frame = STAT_MINUS; - else - frame = *ptr -'0'; - - CG_DrawPic( x,y, charWidth, charHeight, cgs.media.numberShaders[ frame ] ); - x += charWidth; - ptr++; - l--; - } -} - -static void CG_DrawProgressBar( rectDef_t *rect, vec4_t color, float scale, - int align, int textStyle, int special, float progress ) -{ - float rimWidth = rect->h / 20.0f; - float doneWidth, leftWidth; - float tx, ty, tw, th; - char textBuffer[ 8 ]; - - if( rimWidth < 0.6f ) - rimWidth = 0.6f; - - if( special >= 0.0f ) - rimWidth = special; - - if( progress < 0.0f ) - progress = 0.0f; - else if( progress > 1.0f ) - progress = 1.0f; - - doneWidth = ( rect->w - 2 * rimWidth ) * progress; - leftWidth = ( rect->w - 2 * rimWidth ) - doneWidth; - - trap_R_SetColor( color ); - - //draw rim and bar - if( align == ITEM_ALIGN_RIGHT ) - { - CG_DrawPic( rect->x, rect->y, rimWidth, rect->h, cgs.media.whiteShader ); - CG_DrawPic( rect->x + rimWidth, rect->y, - leftWidth, rimWidth, cgs.media.whiteShader ); - CG_DrawPic( rect->x + rimWidth, rect->y + rect->h - rimWidth, - leftWidth, rimWidth, cgs.media.whiteShader ); - CG_DrawPic( rect->x + rimWidth + leftWidth, rect->y, - rimWidth + doneWidth, rect->h, cgs.media.whiteShader ); - } - else - { - CG_DrawPic( rect->x, rect->y, rimWidth + doneWidth, rect->h, cgs.media.whiteShader ); - CG_DrawPic( rimWidth + rect->x + doneWidth, rect->y, - leftWidth, rimWidth, cgs.media.whiteShader ); - CG_DrawPic( rimWidth + rect->x + doneWidth, rect->y + rect->h - rimWidth, - leftWidth, rimWidth, cgs.media.whiteShader ); - CG_DrawPic( rect->x + rect->w - rimWidth, rect->y, rimWidth, rect->h, cgs.media.whiteShader ); - } - - trap_R_SetColor( NULL ); - - //draw text - if( scale > 0.0 ) - { - Com_sprintf( textBuffer, sizeof( textBuffer ), "%d%%", (int)( progress * 100 ) ); - tw = CG_Text_Width( textBuffer, scale, 0 ); - th = scale * 40.0f; - - switch( align ) - { - case ITEM_ALIGN_LEFT: - tx = rect->x + ( rect->w / 10.0f ); - ty = rect->y + ( rect->h / 2.0f ) + ( th / 2.0f ); - break; - - case ITEM_ALIGN_RIGHT: - tx = rect->x + rect->w - ( rect->w / 10.0f ) - tw; - ty = rect->y + ( rect->h / 2.0f ) + ( th / 2.0f ); - break; - - case ITEM_ALIGN_CENTER: - tx = rect->x + ( rect->w / 2.0f ) - ( tw / 2.0f ); - ty = rect->y + ( rect->h / 2.0f ) + ( th / 2.0f ); - break; - - default: - tx = ty = 0.0f; - } - - CG_Text_Paint( tx, ty, scale, color, textBuffer, 0, 0, textStyle ); - } -} - -//=============== TA: was cg_newdraw.c - -void CG_InitTeamChat( void ) -{ - memset( teamChat1, 0, sizeof( teamChat1 ) ); - memset( teamChat2, 0, sizeof( teamChat2 ) ); - memset( systemChat, 0, sizeof( systemChat ) ); -} - -void CG_SetPrintString( int type, const char *p ) -{ - if( type == SYSTEM_PRINT ) - { - strcpy( systemChat, p ); - } - else - { - strcpy( teamChat2, teamChat1 ); - strcpy( teamChat1, p ); - } -} - -/* -=============== -CG_AtHighestClass - -Is the local client at the highest class possible? -=============== -*/ -static qboolean CG_AtHighestClass( void ) -{ - int i; - qboolean superiorClasses = qfalse; - - for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ ) - { - if( BG_ClassCanEvolveFromTo( - cg.predictedPlayerState.stats[ STAT_PCLASS ], i, - ALIEN_MAX_KILLS, 0 ) >= 0 && - BG_FindStagesForClass( i, cgs.alienStage ) - /*FIXME && G_ClassIsAllowed( i )*/ ) - { - superiorClasses = qtrue; - break; - } - } - - return !superiorClasses; -} - -#define NO_CREDITS_TIME 2000 - -static void CG_DrawPlayerCreditsValue( rectDef_t *rect, vec4_t color, qboolean padding ) -{ - int value; - playerState_t *ps; - centity_t *cent; - - cent = &cg_entities[ cg.snap->ps.clientNum ]; - ps = &cg.snap->ps; - - //if the build timer pie is showing don't show this - if( ( cent->currentState.weapon == WP_ABUILD || - cent->currentState.weapon == WP_ABUILD2 ) && ps->stats[ STAT_MISC ] ) - return; - - value = ps->persistant[ PERS_CREDIT ]; - if( value > -1 ) - { - if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS && - !CG_AtHighestClass( ) ) - { - if( cg.time - cg.lastEvolveAttempt <= NO_CREDITS_TIME ) - { - if( ( ( cg.time - cg.lastEvolveAttempt ) / 300 ) % 2 ) - color[ 3 ] = 0.0f; - } - } - - trap_R_SetColor( color ); - - if( padding ) - CG_DrawFieldPadded( rect->x, rect->y, 4, rect->w / 4, rect->h, value ); - else - CG_DrawField( rect->x, rect->y, 1, rect->w, rect->h, value ); - - trap_R_SetColor( NULL ); - } -} - -static void CG_DrawPlayerBankValue( rectDef_t *rect, vec4_t color, qboolean padding ) -{ - int value; - playerState_t *ps; - - ps = &cg.snap->ps; - - value = ps->persistant[ PERS_BANK ]; - if( value > -1 ) - { - trap_R_SetColor( color ); - - if( padding ) - CG_DrawFieldPadded( rect->x, rect->y, 4, rect->w / 4, rect->h, value ); - else - CG_DrawField( rect->x, rect->y, 1, rect->w, rect->h, value ); - - trap_R_SetColor( NULL ); - } -} - -#define HH_MIN_ALPHA 0.2f -#define HH_MAX_ALPHA 0.8f -#define HH_ALPHA_DIFF (HH_MAX_ALPHA-HH_MIN_ALPHA) - -#define AH_MIN_ALPHA 0.2f -#define AH_MAX_ALPHA 0.8f -#define AH_ALPHA_DIFF (AH_MAX_ALPHA-AH_MIN_ALPHA) - -/* -============== -CG_DrawPlayerStamina1 -============== -*/ -static void CG_DrawPlayerStamina1( rectDef_t *rect, vec4_t color, qhandle_t shader ) -{ - playerState_t *ps = &cg.snap->ps; - float stamina = ps->stats[ STAT_STAMINA ]; - float maxStaminaBy3 = (float)MAX_STAMINA / 3.0f; - float progress; - - stamina -= ( 2 * (int)maxStaminaBy3 ); - progress = stamina / maxStaminaBy3; - - if( progress > 1.0f ) - progress = 1.0f; - else if( progress < 0.0f ) - progress = 0.0f; - - color[ 3 ] = HH_MIN_ALPHA + ( progress * HH_ALPHA_DIFF ); - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); -} - -/* -============== -CG_DrawPlayerStamina2 -============== -*/ -static void CG_DrawPlayerStamina2( rectDef_t *rect, vec4_t color, qhandle_t shader ) -{ - playerState_t *ps = &cg.snap->ps; - float stamina = ps->stats[ STAT_STAMINA ]; - float maxStaminaBy3 = (float)MAX_STAMINA / 3.0f; - float progress; - - stamina -= (int)maxStaminaBy3; - progress = stamina / maxStaminaBy3; - - if( progress > 1.0f ) - progress = 1.0f; - else if( progress < 0.0f ) - progress = 0.0f; - - color[ 3 ] = HH_MIN_ALPHA + ( progress * HH_ALPHA_DIFF ); - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); -} - -/* -============== -CG_DrawPlayerStamina3 -============== -*/ -static void CG_DrawPlayerStamina3( rectDef_t *rect, vec4_t color, qhandle_t shader ) -{ - playerState_t *ps = &cg.snap->ps; - float stamina = ps->stats[ STAT_STAMINA ]; - float maxStaminaBy3 = (float)MAX_STAMINA / 3.0f; - float progress; - - progress = stamina / maxStaminaBy3; - - if( progress > 1.0f ) - progress = 1.0f; - else if( progress < 0.0f ) - progress = 0.0f; - - color[ 3 ] = HH_MIN_ALPHA + ( progress * HH_ALPHA_DIFF ); - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); -} - -/* -============== -CG_DrawPlayerStamina4 -============== -*/ -static void CG_DrawPlayerStamina4( rectDef_t *rect, vec4_t color, qhandle_t shader ) -{ - playerState_t *ps = &cg.snap->ps; - float stamina = ps->stats[ STAT_STAMINA ]; - float progress; - - stamina += (float)MAX_STAMINA; - progress = stamina / (float)MAX_STAMINA; - - if( progress > 1.0f ) - progress = 1.0f; - else if( progress < 0.0f ) - progress = 0.0f; - - color[ 3 ] = HH_MIN_ALPHA + ( progress * HH_ALPHA_DIFF ); - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); -} - -/* -============== -CG_DrawPlayerStaminaBolt -============== -*/ -static void CG_DrawPlayerStaminaBolt( rectDef_t *rect, vec4_t color, qhandle_t shader ) -{ - playerState_t *ps = &cg.snap->ps; - float stamina = ps->stats[ STAT_STAMINA ]; - - if( stamina < 0 ) - color[ 3 ] = HH_MIN_ALPHA; - else - color[ 3 ] = HH_MAX_ALPHA; - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); -} - -/* -============== -CG_DrawPlayerClipsRing -============== -*/ -static void CG_DrawPlayerClipsRing( rectDef_t *rect, vec4_t color, qhandle_t shader ) -{ - playerState_t *ps = &cg.snap->ps; - centity_t *cent; - float buildTime = ps->stats[ STAT_MISC ]; - float progress; - float maxDelay; - - cent = &cg_entities[ cg.snap->ps.clientNum ]; - - switch( cent->currentState.weapon ) - { - case WP_ABUILD: - case WP_ABUILD2: - case WP_HBUILD: - case WP_HBUILD2: - maxDelay = (float)BG_FindBuildDelayForWeapon( cent->currentState.weapon ); - - if( buildTime > maxDelay ) - buildTime = maxDelay; - - progress = ( maxDelay - buildTime ) / maxDelay; - - color[ 3 ] = HH_MIN_ALPHA + ( progress * HH_ALPHA_DIFF ); - break; - - default: - if( ps->weaponstate == WEAPON_RELOADING ) - { - maxDelay = (float)BG_FindReloadTimeForWeapon( cent->currentState.weapon ); - progress = ( maxDelay - (float)ps->weaponTime ) / maxDelay; - - color[ 3 ] = HH_MIN_ALPHA + ( progress * HH_ALPHA_DIFF ); - } - break; - } - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); -} - -/* -============== -CG_DrawPlayerBuildTimerRing -============== -*/ -static void CG_DrawPlayerBuildTimerRing( rectDef_t *rect, vec4_t color, qhandle_t shader ) -{ - playerState_t *ps = &cg.snap->ps; - centity_t *cent; - float buildTime = ps->stats[ STAT_MISC ]; - float progress; - float maxDelay; - - cent = &cg_entities[ cg.snap->ps.clientNum ]; - - maxDelay = (float)BG_FindBuildDelayForWeapon( cent->currentState.weapon ); - - if( buildTime > maxDelay ) - buildTime = maxDelay; - - progress = ( maxDelay - buildTime ) / maxDelay; - - color[ 3 ] = AH_MIN_ALPHA + ( progress * AH_ALPHA_DIFF ); - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); -} - -/* -============== -CG_DrawPlayerBoosted -============== -*/ -static void CG_DrawPlayerBoosted( rectDef_t *rect, vec4_t color, qhandle_t shader ) -{ - playerState_t *ps = &cg.snap->ps; - qboolean boosted = ps->stats[ STAT_STATE ] & SS_BOOSTED; - - if( boosted ) - color[ 3 ] = AH_MAX_ALPHA; - else - color[ 3 ] = AH_MIN_ALPHA; - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); -} - -/* -============== -CG_DrawPlayerBoosterBolt -============== -*/ -static void CG_DrawPlayerBoosterBolt( rectDef_t *rect, vec4_t color, qhandle_t shader ) -{ - playerState_t *ps = &cg.snap->ps; - qboolean boosted = ps->stats[ STAT_STATE ] & SS_BOOSTED; - vec4_t localColor; - - Vector4Copy( color, localColor ); - - if( boosted ) - { - if( ps->stats[ STAT_BOOSTTIME ] > BOOST_TIME - 3000 ) - { - qboolean flash = ( ps->stats[ STAT_BOOSTTIME ] / 500 ) % 2; - - if( flash ) - localColor[ 3 ] = 1.0f; - } - } - - trap_R_SetColor( localColor ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); -} - -/* -============== -CG_DrawPlayerPoisonBarbs -============== -*/ -static void CG_DrawPlayerPoisonBarbs( rectDef_t *rect, vec4_t color, qhandle_t shader ) -{ - playerState_t *ps = &cg.snap->ps; - int x = rect->x; - int y = rect->y; - int width = rect->w; - int height = rect->h; - qboolean vertical; - int iconsize, numBarbs, i; - - BG_UnpackAmmoArray( ps->weapon, ps->ammo, ps->powerups, &numBarbs, NULL ); - - if( height > width ) - { - vertical = qtrue; - iconsize = width; - } - else if( height <= width ) - { - vertical = qfalse; - iconsize = height; - } - - if( color[ 3 ] != 0.0 ) - trap_R_SetColor( color ); - - for( i = 0; i < numBarbs; i ++ ) - { - if( vertical ) - y += iconsize; - else - x += iconsize; - - CG_DrawPic( x, y, iconsize, iconsize, shader ); - } - - trap_R_SetColor( NULL ); -} - -/* -============== -CG_DrawPlayerWallclimbing -============== -*/ -static void CG_DrawPlayerWallclimbing( rectDef_t *rect, vec4_t color, qhandle_t shader ) -{ - playerState_t *ps = &cg.snap->ps; - qboolean ww = ps->stats[ STAT_STATE ] & SS_WALLCLIMBING; - - if( ww ) - color[ 3 ] = AH_MAX_ALPHA; - else - color[ 3 ] = AH_MIN_ALPHA; - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); -} - -static void CG_DrawPlayerStamina( rectDef_t *rect, vec4_t color, float scale, - int align, int textStyle, int special ) -{ - playerState_t *ps = &cg.snap->ps; - int stamina = ps->stats[ STAT_STAMINA ]; - float progress = ( (float)stamina + (float)MAX_STAMINA ) / ( (float)MAX_STAMINA * 2.0f ); - - CG_DrawProgressBar( rect, color, scale, align, textStyle, special, progress ); -} - -static void CG_DrawPlayerAmmoValue( rectDef_t *rect, vec4_t color ) -{ - int value; - centity_t *cent; - playerState_t *ps; - - cent = &cg_entities[ cg.snap->ps.clientNum ]; - ps = &cg.snap->ps; - - if( cent->currentState.weapon ) - { - switch( cent->currentState.weapon ) - { - case WP_ABUILD: - case WP_ABUILD2: - //percentage of BP remaining - value = cgs.alienBuildPoints; - break; - - case WP_HBUILD: - case WP_HBUILD2: - //percentage of BP remaining - value = cgs.humanBuildPoints; - break; - - default: - BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &value, NULL ); - break; - } - - if( value > 999 ) - value = 999; - - if( value > -1 ) - { - trap_R_SetColor( color ); - CG_DrawField( rect->x, rect->y, 4, rect->w / 4, rect->h, value ); - trap_R_SetColor( NULL ); - } - } -} - - -/* -============== -CG_DrawAlienSense -============== -*/ -static void CG_DrawAlienSense( rectDef_t *rect ) -{ - if( BG_ClassHasAbility( cg.snap->ps.stats[ STAT_PCLASS ], SCA_ALIENSENSE ) ) - CG_AlienSense( rect ); -} - - -/* -============== -CG_DrawHumanScanner -============== -*/ -static void CG_DrawHumanScanner( rectDef_t *rect, qhandle_t shader, vec4_t color ) -{ - if( BG_InventoryContainsUpgrade( UP_HELMET, cg.snap->ps.stats ) ) - CG_Scanner( rect, shader, color ); -} - - -/* -============== -CG_DrawUsableBuildable -============== -*/ -static void CG_DrawUsableBuildable( rectDef_t *rect, qhandle_t shader, vec4_t color ) -{ - vec3_t view, point; - trace_t trace; - entityState_t *es; - - AngleVectors( cg.refdefViewAngles, view, NULL, NULL ); - VectorMA( cg.refdef.vieworg, 64, view, point ); - CG_Trace( &trace, cg.refdef.vieworg, NULL, NULL, - point, cg.predictedPlayerState.clientNum, MASK_SHOT ); - - es = &cg_entities[ trace.entityNum ].currentState; - - if( es->eType == ET_BUILDABLE && BG_FindUsableForBuildable( es->modelindex ) && - cg.predictedPlayerState.stats[ STAT_PTEAM ] == BG_FindTeamForBuildable( es->modelindex ) ) - { - //hack to prevent showing the usable buildable when you aren't carrying an energy weapon - if( ( es->modelindex == BA_H_REACTOR || es->modelindex == BA_H_REPEATER ) && - ( !BG_FindUsesEnergyForWeapon( cg.snap->ps.weapon ) || - BG_FindInfinteAmmoForWeapon( cg.snap->ps.weapon ) ) ) - return; - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); - } -} - - -#define BUILD_DELAY_TIME 2000 - -static void CG_DrawPlayerBuildTimer( rectDef_t *rect, vec4_t color ) -{ - float progress; - int index; - centity_t *cent; - playerState_t *ps; - - cent = &cg_entities[ cg.snap->ps.clientNum ]; - ps = &cg.snap->ps; - - if( cent->currentState.weapon ) - { - switch( cent->currentState.weapon ) - { - case WP_ABUILD: - progress = (float)ps->stats[ STAT_MISC ] / (float)ABUILDER_BASE_DELAY; - break; - - case WP_ABUILD2: - progress = (float)ps->stats[ STAT_MISC ] / (float)ABUILDER_ADV_DELAY; - break; - - case WP_HBUILD: - progress = (float)ps->stats[ STAT_MISC ] / (float)HBUILD_DELAY; - break; - - case WP_HBUILD2: - progress = (float)ps->stats[ STAT_MISC ] / (float)HBUILD2_DELAY; - break; - - default: - return; - break; - } - - if( !ps->stats[ STAT_MISC ] ) - return; - - index = (int)( progress * 8.0f ); - - if( index > 7 ) - index = 7; - else if( index < 0 ) - index = 0; - - if( cg.time - cg.lastBuildAttempt <= BUILD_DELAY_TIME ) - { - if( ( ( cg.time - cg.lastBuildAttempt ) / 300 ) % 2 ) - { - color[ 0 ] = 1.0f; - color[ 1 ] = color[ 2 ] = 0.0f; - color[ 3 ] = 1.0f; - } - } - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, - cgs.media.buildWeaponTimerPie[ index ] ); - trap_R_SetColor( NULL ); - } -} - -static void CG_DrawPlayerClipsValue( rectDef_t *rect, vec4_t color ) -{ - int value; - centity_t *cent; - playerState_t *ps; - - cent = &cg_entities[ cg.snap->ps.clientNum ]; - ps = &cg.snap->ps; - - if( cent->currentState.weapon ) - { - switch( cent->currentState.weapon ) - { - case WP_ABUILD: - case WP_ABUILD2: - case WP_HBUILD: - case WP_HBUILD2: - break; - - default: - BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, NULL, &value ); - - if( value > -1 ) - { - trap_R_SetColor( color ); - CG_DrawField( rect->x, rect->y, 4, rect->w / 4, rect->h, value ); - trap_R_SetColor( NULL ); - } - break; - } - } -} - -static void CG_DrawPlayerHealthValue( rectDef_t *rect, vec4_t color ) -{ - playerState_t *ps; - int value; - - ps = &cg.snap->ps; - - value = ps->stats[ STAT_HEALTH ]; - - trap_R_SetColor( color ); - CG_DrawField( rect->x, rect->y, 4, rect->w / 4, rect->h, value ); - trap_R_SetColor( NULL ); -} - -static void CG_DrawPlayerHealthBar( rectDef_t *rect, vec4_t color, float scale, - int align, int textStyle, int special ) -{ - playerState_t *ps; - float total; - - ps = &cg.snap->ps; - - total = ( (float)ps->stats[ STAT_HEALTH ] / (float)ps->stats[ STAT_MAX_HEALTH ] ); - CG_DrawProgressBar( rect, color, scale, align, textStyle, special, total ); -} - -/* -============== -CG_DrawPlayerHealthCross -============== -*/ -static void CG_DrawPlayerHealthCross( rectDef_t *rect, vec4_t color, qhandle_t shader ) -{ - playerState_t *ps = &cg.snap->ps; - int health = ps->stats[ STAT_HEALTH ]; - - if( health < 10 ) - { - color[ 0 ] = 1.0f; - color[ 1 ] = color[ 2 ] = 0.0f; - } - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); -} - -static void CG_DrawProgressLabel( rectDef_t *rect, float text_x, float text_y, vec4_t color, - float scale, int align, const char *s, float fraction ) -{ - vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f }; - float tx, tw = CG_Text_Width( s, scale, 0 ); - - switch( align ) - { - case ITEM_ALIGN_LEFT: - tx = 0.0f; - break; - - case ITEM_ALIGN_RIGHT: - tx = rect->w - tw; - break; - - case ITEM_ALIGN_CENTER: - tx = ( rect->w / 2.0f ) - ( tw / 2.0f ); - break; - - default: - tx = 0.0f; - } - - if( fraction < 1.0f ) - CG_Text_Paint( rect->x + text_x + tx, rect->y + text_y, scale, white, - s, 0, 0, ITEM_TEXTSTYLE_NORMAL ); - else - CG_Text_Paint( rect->x + text_x + tx, rect->y + text_y, scale, color, - s, 0, 0, ITEM_TEXTSTYLE_NEON ); -} - -static void CG_DrawMediaProgress( rectDef_t *rect, vec4_t color, float scale, - int align, int textStyle, int special ) -{ - CG_DrawProgressBar( rect, color, scale, align, textStyle, special, cg.mediaFraction ); -} - -static void CG_DrawMediaProgressLabel( rectDef_t *rect, float text_x, float text_y, - vec4_t color, float scale, int align ) -{ - CG_DrawProgressLabel( rect, text_x, text_y, color, scale, align, "Map and Textures", cg.mediaFraction ); -} - -static void CG_DrawBuildablesProgress( rectDef_t *rect, vec4_t color, float scale, - int align, int textStyle, int special ) -{ - CG_DrawProgressBar( rect, color, scale, align, textStyle, special, cg.buildablesFraction ); -} - -static void CG_DrawBuildablesProgressLabel( rectDef_t *rect, float text_x, float text_y, - vec4_t color, float scale, int align ) -{ - CG_DrawProgressLabel( rect, text_x, text_y, color, scale, align, "Buildable Models", cg.buildablesFraction ); -} - -static void CG_DrawCharModelProgress( rectDef_t *rect, vec4_t color, float scale, - int align, int textStyle, int special ) -{ - CG_DrawProgressBar( rect, color, scale, align, textStyle, special, cg.charModelFraction ); -} - -static void CG_DrawCharModelProgressLabel( rectDef_t *rect, float text_x, float text_y, - vec4_t color, float scale, int align ) -{ - CG_DrawProgressLabel( rect, text_x, text_y, color, scale, align, "Character Models", cg.charModelFraction ); -} - -static void CG_DrawOverallProgress( rectDef_t *rect, vec4_t color, float scale, - int align, int textStyle, int special ) -{ - float total; - - total = ( cg.charModelFraction + cg.buildablesFraction + cg.mediaFraction ) / 3.0f; - CG_DrawProgressBar( rect, color, scale, align, textStyle, special, total ); -} - -static void CG_DrawLevelShot( rectDef_t *rect ) -{ - const char *s; - const char *info; - qhandle_t levelshot; - qhandle_t detail; - - info = CG_ConfigString( CS_SERVERINFO ); - s = Info_ValueForKey( info, "mapname" ); - levelshot = trap_R_RegisterShaderNoMip( va( "levelshots/%s.tga", s ) ); - - if( !levelshot ) - levelshot = trap_R_RegisterShaderNoMip( "gfx/2d/load_screen" ); - - trap_R_SetColor( NULL ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, levelshot ); - - // blend a detail texture over it - detail = trap_R_RegisterShader( "levelShotDetail" ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, detail ); -} - -static void CG_DrawLoadingString( rectDef_t *rect, float text_x, float text_y, vec4_t color, - float scale, int align, int textStyle, const char *s ) -{ - float tw, th, tx; - int pos, i; - char buffer[ 1024 ]; - char *end; - - if( !s[ 0 ] ) - return; - - strcpy( buffer, s ); - tw = CG_Text_Width( s, scale, 0 ); - th = scale * 40.0f; - - pos = i = 0; - - while( pos < strlen( s ) ) - { - strcpy( buffer, &s[ pos ] ); - tw = CG_Text_Width( buffer, scale, 0 ); - - while( tw > rect->w ) - { - end = strrchr( buffer, ' ' ); - - if( end == NULL ) - break; - - *end = '\0'; - tw = CG_Text_Width( buffer, scale, 0 ); - } - - switch( align ) - { - case ITEM_ALIGN_LEFT: - tx = rect->x; - break; - - case ITEM_ALIGN_RIGHT: - tx = rect->x + rect->w - tw; - break; - - case ITEM_ALIGN_CENTER: - tx = rect->x + ( rect->w / 2.0f ) - ( tw / 2.0f ); - break; - - default: - tx = 0.0f; - } - - CG_Text_Paint( tx + text_x, rect->y + text_y + i * ( th + 3 ), scale, color, - buffer, 0, 0, textStyle ); - - pos += strlen( buffer ) + 1; - i++; - } -} - -static void CG_DrawLevelName( rectDef_t *rect, float text_x, float text_y, - vec4_t color, float scale, int align, int textStyle ) -{ - const char *s; - - s = CG_ConfigString( CS_MESSAGE ); - - CG_DrawLoadingString( rect, text_x, text_y, color, scale, align, textStyle, s ); -} - -static void CG_DrawMOTD( rectDef_t *rect, float text_x, float text_y, - vec4_t color, float scale, int align, int textStyle ) -{ - const char *s; - - s = CG_ConfigString( CS_MOTD ); - - CG_DrawLoadingString( rect, text_x, text_y, color, scale, align, textStyle, s ); -} - -static void CG_DrawHostname( rectDef_t *rect, float text_x, float text_y, - vec4_t color, float scale, int align, int textStyle ) -{ - char buffer[ 1024 ]; - const char *info; - - info = CG_ConfigString( CS_SERVERINFO ); - - Q_strncpyz( buffer, Info_ValueForKey( info, "sv_hostname" ), 1024 ); - Q_CleanStr( buffer ); - - CG_DrawLoadingString( rect, text_x, text_y, color, scale, align, textStyle, buffer ); -} - -/* -====================== -CG_UpdateMediaFraction - -====================== -*/ -void CG_UpdateMediaFraction( float newFract ) -{ - cg.mediaFraction = newFract; - - trap_UpdateScreen( ); -} - -/* -==================== -CG_DrawLoadingScreen - -Draw all the status / pacifier stuff during level loading -==================== -*/ -void CG_DrawLoadingScreen( void ) -{ - Menu_Paint( Menus_FindByName( "Loading" ), qtrue ); -} - -float CG_GetValue( int ownerDraw ) -{ - centity_t *cent; - playerState_t *ps; - - cent = &cg_entities[ cg.snap->ps.clientNum ]; - ps = &cg.snap->ps; - - switch( ownerDraw ) - { - case CG_PLAYER_AMMO_VALUE: - if( cent->currentState.weapon ) - { - int value; - - BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, - &value, NULL ); - - return value; - } - break; - case CG_PLAYER_CLIPS_VALUE: - if( cent->currentState.weapon ) - { - int value; - - BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, - NULL, &value ); - - return value; - } - break; - case CG_PLAYER_HEALTH: - return ps->stats[ STAT_HEALTH ]; - break; - default: - break; - } - - return -1; -} - -static void CG_DrawAreaSystemChat( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader ) -{ - CG_Text_Paint( rect->x, rect->y + rect->h, scale, color, systemChat, 0, 0, 0 ); -} - -static void CG_DrawAreaTeamChat( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader ) -{ - CG_Text_Paint( rect->x, rect->y + rect->h, scale, color,teamChat1, 0, 0, 0 ); -} - -static void CG_DrawAreaChat(rectDef_t *rect, float scale, vec4_t color, qhandle_t shader) -{ - CG_Text_Paint(rect->x, rect->y + rect->h, scale, color, teamChat2, 0, 0, 0); -} - -const char *CG_GetKillerText( ) -{ - const char *s = ""; - if( cg.killerName[ 0 ] ) - s = va( "Fragged by %s", cg.killerName ); - - return s; -} - - -static void CG_DrawKiller( rectDef_t *rect, float scale, vec4_t color, - qhandle_t shader, int textStyle ) -{ - // fragged by ... line - if( cg.killerName[ 0 ] ) - { - int x = rect->x + rect->w / 2; - CG_Text_Paint( x - CG_Text_Width( CG_GetKillerText( ), scale, 0 ) / 2, - rect->y + rect->h, scale, color, CG_GetKillerText( ), 0, 0, textStyle ); - } -} - - -static void CG_Text_Paint_Limit( float *maxX, float x, float y, float scale, - vec4_t color, const char* text, float adjust, int limit ) -{ - int len, count; - vec4_t newColor; - glyphInfo_t *glyph; - - if( text ) - { -// TTimo: FIXME -// const unsigned char *s = text; // bk001206 - unsigned - const char *s = text; - float max = *maxX; - float useScale; - fontInfo_t *font = &cgDC.Assets.textFont; - - if( scale <= cg_smallFont.value ) - font = &cgDC.Assets.smallFont; - else if( scale > cg_bigFont.value ) - font = &cgDC.Assets.bigFont; - - useScale = scale * font->glyphScale; - trap_R_SetColor( color ); - len = strlen( text ); - - if( limit > 0 && len > limit ) - len = limit; - - count = 0; - - while( s && *s && count < len ) - { - glyph = &font->glyphs[ (int)*s ]; - //TTimo: FIXME: getting nasty warnings without the cast, - //hopefully this doesn't break the VM build - - if( Q_IsColorString( s ) ) - { - memcpy( newColor, g_color_table[ ColorIndex( *(s+1) ) ], sizeof( newColor ) ); - newColor[ 3 ] = color[ 3 ]; - trap_R_SetColor( newColor ); - s += 2; - continue; - } - else - { - float yadj = useScale * glyph->top; - - if( CG_Text_Width( s, useScale, 1 ) + x > max ) - { - *maxX = 0; - break; - } - - CG_Text_PaintChar( x, y - yadj, - glyph->imageWidth, - glyph->imageHeight, - useScale, - glyph->s, - glyph->t, - glyph->s2, - glyph->t2, - glyph->glyph ); - x += ( glyph->xSkip * useScale ) + adjust; - *maxX = x; - count++; - s++; - } - } - - trap_R_SetColor( NULL ); - } -} - -static void CG_DrawTeamSpectators( rectDef_t *rect, float scale, vec4_t color, qhandle_t shader ) -{ - if( cg.spectatorLen ) - { - float maxX; - - if( cg.spectatorWidth == -1 ) - { - cg.spectatorWidth = 0; - cg.spectatorPaintX = rect->x + 1; - cg.spectatorPaintX2 = -1; - } - - if( cg.spectatorOffset > cg.spectatorLen ) - { - cg.spectatorOffset = 0; - cg.spectatorPaintX = rect->x + 1; - cg.spectatorPaintX2 = -1; - } - - if( cg.time > cg.spectatorTime ) - { - cg.spectatorTime = cg.time + 10; - - if( cg.spectatorPaintX <= rect->x + 2 ) - { - if( cg.spectatorOffset < cg.spectatorLen ) - { - //TA: skip colour directives - if( Q_IsColorString( &cg.spectatorList[ cg.spectatorOffset ] ) ) - cg.spectatorOffset += 2; - else - { - cg.spectatorPaintX += CG_Text_Width( &cg.spectatorList[ cg.spectatorOffset ], scale, 1 ) - 1; - cg.spectatorOffset++; - } - } - else - { - cg.spectatorOffset = 0; - - if( cg.spectatorPaintX2 >= 0 ) - cg.spectatorPaintX = cg.spectatorPaintX2; - else - cg.spectatorPaintX = rect->x + rect->w - 2; - - cg.spectatorPaintX2 = -1; - } - } - else - { - cg.spectatorPaintX--; - - if( cg.spectatorPaintX2 >= 0 ) - cg.spectatorPaintX2--; - } - } - - maxX = rect->x + rect->w - 2; - - CG_Text_Paint_Limit( &maxX, cg.spectatorPaintX, rect->y + rect->h - 3, scale, color, - &cg.spectatorList[ cg.spectatorOffset ], 0, 0 ); - - if( cg.spectatorPaintX2 >= 0 ) - { - float maxX2 = rect->x + rect->w - 2; - CG_Text_Paint_Limit( &maxX2, cg.spectatorPaintX2, rect->y + rect->h - 3, scale, - color, cg.spectatorList, 0, cg.spectatorOffset ); - } - - if( cg.spectatorOffset && maxX > 0 ) - { - // if we have an offset ( we are skipping the first part of the string ) and we fit the string - if( cg.spectatorPaintX2 == -1 ) - cg.spectatorPaintX2 = rect->x + rect->w - 2; - } - else - cg.spectatorPaintX2 = -1; - } -} - -/* -================== -CG_DrawStageReport -================== -*/ -static void CG_DrawStageReport( rectDef_t *rect, float text_x, float text_y, - vec4_t color, float scale, int align, int textStyle ) -{ - char s[ MAX_TOKEN_CHARS ]; - int tx, w, kills; - - if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR && !cg.intermissionStarted ) - return; - - if( cg.intermissionStarted ) - { - Com_sprintf( s, MAX_TOKEN_CHARS, - "Stage %d" //PH34R MY MAD-LEET CODING SKILLZ - " " - "Stage %d", - cgs.alienStage + 1, cgs.humanStage + 1 ); - } - else if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - kills = cgs.alienNextStageThreshold - cgs.alienKills; - - if( cgs.alienNextStageThreshold < 0 ) - Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d", cgs.alienStage + 1 ); - else if( kills == 1 ) - Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d, %d kill for next stage", - cgs.alienStage + 1, kills ); - else - Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d, %d kills for next stage", - cgs.alienStage + 1, kills ); - } - else if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - kills = cgs.humanNextStageThreshold - cgs.humanKills; - - if( cgs.humanNextStageThreshold < 0 ) - Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d", cgs.humanStage + 1 ); - else if( kills == 1 ) - Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d, %d kill for next stage", - cgs.humanStage + 1, kills ); - else - Com_sprintf( s, MAX_TOKEN_CHARS, "Stage %d, %d kills for next stage", - cgs.humanStage + 1, kills ); - } - - w = CG_Text_Width( s, scale, 0 ); - - switch( align ) - { - case ITEM_ALIGN_LEFT: - tx = rect->x; - break; - - case ITEM_ALIGN_RIGHT: - tx = rect->x + rect->w - w; - break; - - case ITEM_ALIGN_CENTER: - tx = rect->x + ( rect->w / 2.0f ) - ( w / 2.0f ); - break; - - default: - tx = 0.0f; - } - - CG_Text_Paint( text_x + tx, rect->y + text_y, scale, color, s, 0, 0, textStyle ); -} - -/* -================== -CG_DrawFPS -================== -*/ -//TA: personally i think this should be longer - it should really be a cvar -#define FPS_FRAMES 20 -#define FPS_STRING "fps" -static void CG_DrawFPS( rectDef_t *rect, float text_x, float text_y, - float scale, vec4_t color, int align, int textStyle, - qboolean scalableText ) -{ - char *s; - int tx, w, totalWidth, strLength; - static int previousTimes[ FPS_FRAMES ]; - static int index; - int i, total; - int fps; - static int previous; - int t, frameTime; - - if( !cg_drawFPS.integer ) - return; - - // don't use serverTime, because that will be drifting to - // correct for internet lag changes, timescales, timedemos, etc - t = trap_Milliseconds( ); - frameTime = t - previous; - previous = t; - - previousTimes[ index % FPS_FRAMES ] = frameTime; - index++; - - if( index > FPS_FRAMES ) - { - // average multiple frames together to smooth changes out a bit - total = 0; - - for( i = 0 ; i < FPS_FRAMES ; i++ ) - total += previousTimes[ i ]; - - if( !total ) - total = 1; - - fps = 1000 * FPS_FRAMES / total; - - s = va( "%d", fps ); - w = CG_Text_Width( "0", scale, 0 ); - strLength = CG_DrawStrlen( s ); - totalWidth = CG_Text_Width( FPS_STRING, scale, 0 ) + w * strLength; - - switch( align ) - { - case ITEM_ALIGN_LEFT: - tx = rect->x; - break; - - case ITEM_ALIGN_RIGHT: - tx = rect->x + rect->w - totalWidth; - break; - - case ITEM_ALIGN_CENTER: - tx = rect->x + ( rect->w / 2.0f ) - ( totalWidth / 2.0f ); - break; - - default: - tx = 0.0f; - } - - if( scalableText ) - { - for( i = 0; i < strLength; i++ ) - { - char c[ 2 ]; - - c[ 0 ] = s[ i ]; - c[ 1 ] = '\0'; - - CG_Text_Paint( text_x + tx + i * w, rect->y + text_y, scale, color, c, 0, 0, textStyle ); - } - } - else - { - trap_R_SetColor( color ); - CG_DrawField( rect->x, rect->y, 3, rect->w / 3, rect->h, fps ); - trap_R_SetColor( NULL ); - } - - if( scalableText ) - CG_Text_Paint( text_x + tx + i * w, rect->y + text_y, scale, color, FPS_STRING, 0, 0, textStyle ); - } -} - - -/* -================= -CG_DrawTimerMins -================= -*/ -static void CG_DrawTimerMins( rectDef_t *rect, vec4_t color ) -{ - int mins, seconds; - int msec; - - if( !cg_drawTimer.integer ) - return; - - msec = cg.time - cgs.levelStartTime; - - seconds = msec / 1000; - mins = seconds / 60; - seconds -= mins * 60; - - trap_R_SetColor( color ); - CG_DrawField( rect->x, rect->y, 3, rect->w / 3, rect->h, mins ); - trap_R_SetColor( NULL ); -} - - -/* -================= -CG_DrawTimerSecs -================= -*/ -static void CG_DrawTimerSecs( rectDef_t *rect, vec4_t color ) -{ - int mins, seconds; - int msec; - - if( !cg_drawTimer.integer ) - return; - - msec = cg.time - cgs.levelStartTime; - - seconds = msec / 1000; - mins = seconds / 60; - seconds -= mins * 60; - - trap_R_SetColor( color ); - CG_DrawFieldPadded( rect->x, rect->y, 2, rect->w / 2, rect->h, seconds ); - trap_R_SetColor( NULL ); -} - - -/* -================= -CG_DrawTimer -================= -*/ -static void CG_DrawTimer( rectDef_t *rect, float text_x, float text_y, - float scale, vec4_t color, int align, int textStyle ) -{ - char *s; - int i, tx, w, totalWidth, strLength; - int mins, seconds, tens; - int msec; - - if( !cg_drawTimer.integer ) - return; - - msec = cg.time - cgs.levelStartTime; - - seconds = msec / 1000; - mins = seconds / 60; - seconds -= mins * 60; - tens = seconds / 10; - seconds -= tens * 10; - - s = va( "%d:%d%d", mins, tens, seconds ); - w = CG_Text_Width( "0", scale, 0 ); - strLength = CG_DrawStrlen( s ); - totalWidth = w * strLength; - - switch( align ) - { - case ITEM_ALIGN_LEFT: - tx = rect->x; - break; - - case ITEM_ALIGN_RIGHT: - tx = rect->x + rect->w - totalWidth; - break; - - case ITEM_ALIGN_CENTER: - tx = rect->x + ( rect->w / 2.0f ) - ( totalWidth / 2.0f ); - break; - - default: - tx = 0.0f; - } - - for( i = 0; i < strLength; i++ ) - { - char c[ 2 ]; - - c[ 0 ] = s[ i ]; - c[ 1 ] = '\0'; - - CG_Text_Paint( text_x + tx + i * w, rect->y + text_y, scale, color, c, 0, 0, textStyle ); - } -} - -/* -================== -CG_DrawSnapshot -================== -*/ -static void CG_DrawSnapshot( rectDef_t *rect, float text_x, float text_y, - float scale, vec4_t color, int align, int textStyle ) -{ - char *s; - int w, tx; - - if( !cg_drawSnapshot.integer ) - return; - - s = va( "time:%d snap:%d cmd:%d", cg.snap->serverTime, - cg.latestSnapshotNum, cgs.serverCommandSequence ); - w = CG_Text_Width( s, scale, 0 ); - - switch( align ) - { - case ITEM_ALIGN_LEFT: - tx = rect->x; - break; - - case ITEM_ALIGN_RIGHT: - tx = rect->x + rect->w - w; - break; - - case ITEM_ALIGN_CENTER: - tx = rect->x + ( rect->w / 2.0f ) - ( w / 2.0f ); - break; - - default: - tx = 0.0f; - } - - CG_Text_Paint( text_x + tx, rect->y + text_y, scale, color, s, 0, 0, textStyle ); -} - -/* -=============================================================================== - -LAGOMETER - -=============================================================================== -*/ - -#define LAG_SAMPLES 128 - -typedef struct -{ - int frameSamples[ LAG_SAMPLES ]; - int frameCount; - int snapshotFlags[ LAG_SAMPLES ]; - int snapshotSamples[ LAG_SAMPLES ]; - int snapshotCount; -} lagometer_t; - -lagometer_t lagometer; - -/* -============== -CG_AddLagometerFrameInfo - -Adds the current interpolate / extrapolate bar for this frame -============== -*/ -void CG_AddLagometerFrameInfo( void ) -{ - int offset; - - offset = cg.time - cg.latestSnapshotTime; - lagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1 ) ] = offset; - lagometer.frameCount++; -} - -/* -============== -CG_AddLagometerSnapshotInfo - -Each time a snapshot is received, log its ping time and -the number of snapshots that were dropped before it. - -Pass NULL for a dropped packet. -============== -*/ -void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) -{ - // dropped packet - if( !snap ) - { - lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1 ) ] = -1; - lagometer.snapshotCount++; - return; - } - - // add this snapshot's info - lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1 ) ] = snap->ping; - lagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1 ) ] = snap->snapFlags; - lagometer.snapshotCount++; -} - -/* -============== -CG_DrawDisconnect - -Should we draw something differnet for long lag vs no packets? -============== -*/ -static void CG_DrawDisconnect( void ) -{ - float x, y; - int cmdNum; - usercmd_t cmd; - const char *s; - int w; - vec4_t color = { 1.0f, 1.0f, 1.0f, 1.0f }; - - // draw the phone jack if we are completely past our buffers - cmdNum = trap_GetCurrentCmdNumber( ) - CMD_BACKUP + 1; - trap_GetUserCmd( cmdNum, &cmd ); - - // special check for map_restart - if( cmd.serverTime <= cg.snap->ps.commandTime || cmd.serverTime > cg.time ) - return; - - // also add text in center of screen - s = "Connection Interrupted"; - w = CG_Text_Width( s, 0.7f, 0 ); - CG_Text_Paint( 320 - w / 2, 100, 0.7f, color, s, 0, 0, ITEM_TEXTSTYLE_SHADOWED ); - - // blink the icon - if( ( cg.time >> 9 ) & 1 ) - return; - - x = 640 - 48; - y = 480 - 48; - - CG_DrawPic( x, y, 48, 48, trap_R_RegisterShader( "gfx/2d/net.tga" ) ); -} - -#define MAX_LAGOMETER_PING 900 -#define MAX_LAGOMETER_RANGE 300 - -#define PING_FRAMES 40 - -/* -============== -CG_DrawLagometer -============== -*/ -static void CG_DrawLagometer( rectDef_t *rect, float text_x, float text_y, - float scale, vec4_t textColor ) -{ - int a, x, y, i; - float v; - float ax, ay, aw, ah, mid, range; - int color; - vec4_t adjustedColor; - float vscale; - vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f }; - - if( cg.snap->ps.pm_type == PM_INTERMISSION ) - return; - - if( !cg_lagometer.integer ) - return; - - if( cg.demoPlayback ) - return; - - Vector4Copy( textColor, adjustedColor ); - adjustedColor[ 3 ] = 0.25f; - - trap_R_SetColor( adjustedColor ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cgs.media.whiteShader ); - trap_R_SetColor( NULL ); - - // - // draw the graph - // - ax = x = rect->x; - ay = y = rect->y; - aw = rect->w; - ah = rect->h; - - trap_R_SetColor( NULL ); - - CG_AdjustFrom640( &ax, &ay, &aw, &ah ); - - color = -1; - range = ah / 3; - mid = ay + range; - - vscale = range / MAX_LAGOMETER_RANGE; - - // draw the frame interpoalte / extrapolate graph - for( a = 0 ; a < aw ; a++ ) - { - i = ( lagometer.frameCount - 1 - a ) & ( LAG_SAMPLES - 1 ); - v = lagometer.frameSamples[ i ]; - v *= vscale; - - if( v > 0 ) - { - if( color != 1 ) - { - color = 1; - trap_R_SetColor( g_color_table[ ColorIndex( COLOR_YELLOW ) ] ); - } - - if( v > range ) - v = range; - - trap_R_DrawStretchPic( ax + aw - a, mid - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader ); - } - else if( v < 0 ) - { - if( color != 2 ) - { - color = 2; - trap_R_SetColor( g_color_table[ ColorIndex( COLOR_BLUE ) ] ); - } - - v = -v; - if( v > range ) - v = range; - - trap_R_DrawStretchPic( ax + aw - a, mid, 1, v, 0, 0, 0, 0, cgs.media.whiteShader ); - } - } - - // draw the snapshot latency / drop graph - range = ah / 2; - vscale = range / MAX_LAGOMETER_PING; - - for( a = 0 ; a < aw ; a++ ) - { - i = ( lagometer.snapshotCount - 1 - a ) & ( LAG_SAMPLES - 1 ); - v = lagometer.snapshotSamples[ i ]; - - if( v > 0 ) - { - if( lagometer.snapshotFlags[ i ] & SNAPFLAG_RATE_DELAYED ) - { - if( color != 5 ) - { - color = 5; // YELLOW for rate delay - trap_R_SetColor( g_color_table[ ColorIndex( COLOR_YELLOW ) ] ); - } - } - else - { - if( color != 3 ) - { - color = 3; - - trap_R_SetColor( g_color_table[ ColorIndex( COLOR_GREEN ) ] ); - } - } - - v = v * vscale; - - if( v > range ) - v = range; - - trap_R_DrawStretchPic( ax + aw - a, ay + ah - v, 1, v, 0, 0, 0, 0, cgs.media.whiteShader ); - } - else if( v < 0 ) - { - if( color != 4 ) - { - color = 4; // RED for dropped snapshots - trap_R_SetColor( g_color_table[ ColorIndex( COLOR_RED ) ] ); - } - - trap_R_DrawStretchPic( ax + aw - a, ay + ah - range, 1, range, 0, 0, 0, 0, cgs.media.whiteShader ); - } - } - - trap_R_SetColor( NULL ); - - if( cg_nopredict.integer || cg_synchronousClients.integer ) - CG_Text_Paint( ax, ay, 0.5, white, "snc", 0, 0, ITEM_TEXTSTYLE_NORMAL ); - else - { - static int previousPings[ PING_FRAMES ]; - static int index; - int i, ping = 0; - char *s; - - previousPings[ index++ ] = cg.snap->ping; - index = index % PING_FRAMES; - - for( i = 0; i < PING_FRAMES; i++ ) - ping += previousPings[ i ]; - - ping /= PING_FRAMES; - - s = va( "%d", ping ); - ax = rect->x + ( rect->w / 2.0f ) - ( CG_Text_Width( s, scale, 0 ) / 2.0f ) + text_x; - ay = rect->y + ( rect->h / 2.0f ) + ( CG_Text_Height( s, scale, 0 ) / 2.0f ) + text_y; - - Vector4Copy( textColor, adjustedColor ); - adjustedColor[ 3 ] = 0.5f; - CG_Text_Paint( ax, ay, scale, adjustedColor, s, 0, 0, ITEM_TEXTSTYLE_NORMAL ); - } - - CG_DrawDisconnect( ); -} - -/* -============== -CG_DrawConsole -============== -*/ -static void CG_DrawConsole( rectDef_t *rect, float text_x, float text_y, vec4_t color, - float scale, int align, int textStyle ) -{ - float x, y, w, h; - - //for some reason if these are stored locally occasionally rendering fails - //even though they are both live until the end of the function, hence static - //possible compiler bug?? - static menuDef_t dummyParent; - static itemDef_t textItem; - - //offset the text - x = rect->x; - y = rect->y; - w = rect->w - ( 16 + ( 2 * text_x ) ); //16 to ensure text within frame - h = rect->h; - - textItem.text = cg.consoleText; - - textItem.parent = &dummyParent; - memcpy( textItem.window.foreColor, color, sizeof( vec4_t ) ); - textItem.window.flags = 0; - - switch( align ) - { - case ITEM_ALIGN_LEFT: - textItem.window.rect.x = x; - break; - - case ITEM_ALIGN_RIGHT: - textItem.window.rect.x = x + w; - break; - - case ITEM_ALIGN_CENTER: - textItem.window.rect.x = x + ( w / 2 ); - break; - - default: - textItem.window.rect.x = x; - break; - } - - textItem.window.rect.y = y; - textItem.window.rect.w = w; - textItem.window.rect.h = h; - textItem.window.borderSize = 0; - textItem.textRect.x = 0; - textItem.textRect.y = 0; - textItem.textRect.w = 0; - textItem.textRect.h = 0; - textItem.textalignment = align; - textItem.textalignx = text_x; - textItem.textaligny = text_y; - textItem.textscale = scale; - textItem.textStyle = textStyle; - - //hack to utilise existing autowrap code - Item_Text_AutoWrapped_Paint( &textItem ); -} - -/* -=================== -CG_DrawWeaponIcon -=================== -*/ -void CG_DrawWeaponIcon( rectDef_t *rect, vec4_t color ) -{ - int ammo, clips, maxAmmo; - centity_t *cent; - playerState_t *ps; - - cent = &cg_entities[ cg.snap->ps.clientNum ]; - ps = &cg.snap->ps; - - BG_UnpackAmmoArray( cent->currentState.weapon, ps->ammo, ps->powerups, &ammo, &clips ); - BG_FindAmmoForWeapon( cent->currentState.weapon, &maxAmmo, NULL ); - - // don't display if dead - if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 ) - return; - - if( cent->currentState.weapon == 0 ) - return; - - CG_RegisterWeapon( cent->currentState.weapon ); - - if( clips == 0 && !BG_FindInfinteAmmoForWeapon( cent->currentState.weapon ) ) - { - float ammoPercent = (float)ammo / (float)maxAmmo; - - if( ammoPercent < 0.33f ) - { - color[ 0 ] = 1.0f; - color[ 1 ] = color[ 2 ] = 0.0f; - } - } - - if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS && CG_AtHighestClass( ) ) - { - if( cg.time - cg.lastEvolveAttempt <= NO_CREDITS_TIME ) - { - if( ( ( cg.time - cg.lastEvolveAttempt ) / 300 ) % 2 ) - color[ 3 ] = 0.0f; - } - } - - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, cg_weapons[ cent->currentState.weapon ].weaponIcon ); - trap_R_SetColor( NULL ); -} - - - -/* -================================================================================ - -CROSSHAIR - -================================================================================ -*/ - - -/* -================= -CG_DrawCrosshair -================= -*/ -static void CG_DrawCrosshair( void ) -{ - float w, h; - qhandle_t hShader; - float x, y; - weaponInfo_t *wi; - - if( !cg_drawCrosshair.integer ) - return; - - if( ( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) || - ( cg.snap->ps.stats[ STAT_STATE ] & SS_INFESTING ) || - ( cg.snap->ps.stats[ STAT_STATE ] & SS_HOVELING ) ) - return; - - if( cg.renderingThirdPerson ) - return; - - wi = &cg_weapons[ cg.snap->ps.weapon ]; - - w = h = wi->crossHairSize; - - x = cg_crosshairX.integer; - y = cg_crosshairY.integer; - CG_AdjustFrom640( &x, &y, &w, &h ); - - hShader = wi->crossHair; - - if( hShader != 0 ) - { - trap_R_DrawStretchPic( x + cg.refdef.x + 0.5 * ( cg.refdef.width - w ), - y + cg.refdef.y + 0.5 * ( cg.refdef.height - h ), - w, h, 0, 0, 1, 1, hShader ); - } -} - - - -/* -================= -CG_ScanForCrosshairEntity -================= -*/ -static void CG_ScanForCrosshairEntity( void ) -{ - trace_t trace; - vec3_t start, end; - int content; - pTeam_t team; - - VectorCopy( cg.refdef.vieworg, start ); - VectorMA( start, 131072, cg.refdef.viewaxis[ 0 ], end ); - - CG_Trace( &trace, start, vec3_origin, vec3_origin, end, - cg.snap->ps.clientNum, CONTENTS_SOLID|CONTENTS_BODY ); - - if( trace.entityNum >= MAX_CLIENTS ) - return; - - // if the player is in fog, don't show it - content = trap_CM_PointContents( trace.endpos, 0 ); - if( content & CONTENTS_FOG ) - return; - - team = cgs.clientinfo[ trace.entityNum ].team; - - if( cg.snap->ps.persistant[ PERS_TEAM ] != TEAM_SPECTATOR ) - { - //only display team names of those on the same team as this player - if( team != cg.snap->ps.stats[ STAT_PTEAM ] ) - return; - } - - // update the fade timer - cg.crosshairClientNum = trace.entityNum; - cg.crosshairClientTime = cg.time; -} - - -/* -===================== -CG_DrawCrosshairNames -===================== -*/ -static void CG_DrawCrosshairNames( rectDef_t *rect, float scale, int textStyle ) -{ - float *color; - char *name; - float w, x; - - if( !cg_drawCrosshair.integer ) - return; - - if( !cg_drawCrosshairNames.integer ) - return; - - if( cg.renderingThirdPerson ) - return; - - // scan the known entities to see if the crosshair is sighted on one - CG_ScanForCrosshairEntity( ); - - // draw the name of the player being looked at - color = CG_FadeColor( cg.crosshairClientTime, 1000 ); - if( !color ) - { - trap_R_SetColor( NULL ); - return; - } - - name = cgs.clientinfo[ cg.crosshairClientNum ].name; - w = CG_Text_Width( name, scale, 0 ); - x = rect->x + rect->w / 2; - CG_Text_Paint( x - w / 2, rect->y + rect->h, scale, color, name, 0, 0, textStyle ); - trap_R_SetColor( NULL ); -} - - -/* -=============== -CG_OwnerDraw - -Draw an owner drawn item -=============== -*/ -void CG_OwnerDraw( float x, float y, float w, float h, float text_x, - float text_y, int ownerDraw, int ownerDrawFlags, - int align, float special, float scale, vec4_t color, - qhandle_t shader, int textStyle ) -{ - rectDef_t rect; - - if( cg_drawStatus.integer == 0 ) - return; - - rect.x = x; - rect.y = y; - rect.w = w; - rect.h = h; - - switch( ownerDraw ) - { - case CG_PLAYER_CREDITS_VALUE: - CG_DrawPlayerCreditsValue( &rect, color, qtrue ); - break; - case CG_PLAYER_BANK_VALUE: - CG_DrawPlayerBankValue( &rect, color, qtrue ); - break; - case CG_PLAYER_CREDITS_VALUE_NOPAD: - CG_DrawPlayerCreditsValue( &rect, color, qfalse ); - break; - case CG_PLAYER_BANK_VALUE_NOPAD: - CG_DrawPlayerBankValue( &rect, color, qfalse ); - break; - case CG_PLAYER_STAMINA: - CG_DrawPlayerStamina( &rect, color, scale, align, textStyle, special ); - break; - case CG_PLAYER_STAMINA_1: - CG_DrawPlayerStamina1( &rect, color, shader ); - break; - case CG_PLAYER_STAMINA_2: - CG_DrawPlayerStamina2( &rect, color, shader ); - break; - case CG_PLAYER_STAMINA_3: - CG_DrawPlayerStamina3( &rect, color, shader ); - break; - case CG_PLAYER_STAMINA_4: - CG_DrawPlayerStamina4( &rect, color, shader ); - break; - case CG_PLAYER_STAMINA_BOLT: - CG_DrawPlayerStaminaBolt( &rect, color, shader ); - break; - case CG_PLAYER_AMMO_VALUE: - CG_DrawPlayerAmmoValue( &rect, color ); - break; - case CG_PLAYER_CLIPS_VALUE: - CG_DrawPlayerClipsValue( &rect, color ); - break; - case CG_PLAYER_BUILD_TIMER: - CG_DrawPlayerBuildTimer( &rect, color ); - break; - case CG_PLAYER_HEALTH: - CG_DrawPlayerHealthValue( &rect, color ); - break; - case CG_PLAYER_HEALTH_BAR: - CG_DrawPlayerHealthBar( &rect, color, scale, align, textStyle, special ); - break; - case CG_PLAYER_HEALTH_CROSS: - CG_DrawPlayerHealthCross( &rect, color, shader ); - break; - case CG_PLAYER_CLIPS_RING: - CG_DrawPlayerClipsRing( &rect, color, shader ); - break; - case CG_PLAYER_BUILD_TIMER_RING: - CG_DrawPlayerBuildTimerRing( &rect, color, shader ); - break; - case CG_PLAYER_WALLCLIMBING: - CG_DrawPlayerWallclimbing( &rect, color, shader ); - break; - case CG_PLAYER_BOOSTED: - CG_DrawPlayerBoosted( &rect, color, shader ); - break; - case CG_PLAYER_BOOST_BOLT: - CG_DrawPlayerBoosterBolt( &rect, color, shader ); - break; - case CG_PLAYER_POISON_BARBS: - CG_DrawPlayerPoisonBarbs( &rect, color, shader ); - break; - case CG_PLAYER_ALIEN_SENSE: - CG_DrawAlienSense( &rect ); - break; - case CG_PLAYER_HUMAN_SCANNER: - CG_DrawHumanScanner( &rect, shader, color ); - break; - case CG_PLAYER_USABLE_BUILDABLE: - CG_DrawUsableBuildable( &rect, shader, color ); - break; - case CG_AREA_SYSTEMCHAT: - CG_DrawAreaSystemChat( &rect, scale, color, shader ); - break; - case CG_AREA_TEAMCHAT: - CG_DrawAreaTeamChat( &rect, scale, color, shader ); - break; - case CG_AREA_CHAT: - CG_DrawAreaChat( &rect, scale, color, shader ); - break; - case CG_KILLER: - CG_DrawKiller( &rect, scale, color, shader, textStyle ); - break; - case CG_PLAYER_SELECT: - CG_DrawItemSelect( &rect, color ); - break; - case CG_PLAYER_WEAPONICON: - CG_DrawWeaponIcon( &rect, color ); - break; - case CG_PLAYER_SELECTTEXT: - CG_DrawItemSelectText( &rect, scale, textStyle ); - break; - case CG_SPECTATORS: - CG_DrawTeamSpectators( &rect, scale, color, shader ); - break; - case CG_PLAYER_CROSSHAIRNAMES: - CG_DrawCrosshairNames( &rect, scale, textStyle ); - break; - case CG_STAGE_REPORT_TEXT: - CG_DrawStageReport( &rect, text_x, text_y, color, scale, align, textStyle ); - break; - - //loading screen - case CG_LOAD_LEVELSHOT: - CG_DrawLevelShot( &rect ); - break; - case CG_LOAD_MEDIA: - CG_DrawMediaProgress( &rect, color, scale, align, textStyle, special ); - break; - case CG_LOAD_MEDIA_LABEL: - CG_DrawMediaProgressLabel( &rect, text_x, text_y, color, scale, align ); - break; - case CG_LOAD_BUILDABLES: - CG_DrawBuildablesProgress( &rect, color, scale, align, textStyle, special ); - break; - case CG_LOAD_BUILDABLES_LABEL: - CG_DrawBuildablesProgressLabel( &rect, text_x, text_y, color, scale, align ); - break; - case CG_LOAD_CHARMODEL: - CG_DrawCharModelProgress( &rect, color, scale, align, textStyle, special ); - break; - case CG_LOAD_CHARMODEL_LABEL: - CG_DrawCharModelProgressLabel( &rect, text_x, text_y, color, scale, align ); - break; - case CG_LOAD_OVERALL: - CG_DrawOverallProgress( &rect, color, scale, align, textStyle, special ); - break; - case CG_LOAD_LEVELNAME: - CG_DrawLevelName( &rect, text_x, text_y, color, scale, align, textStyle ); - break; - case CG_LOAD_MOTD: - CG_DrawMOTD( &rect, text_x, text_y, color, scale, align, textStyle ); - break; - case CG_LOAD_HOSTNAME: - CG_DrawHostname( &rect, text_x, text_y, color, scale, align, textStyle ); - break; - - case CG_FPS: - CG_DrawFPS( &rect, text_x, text_y, scale, color, align, textStyle, qtrue ); - break; - case CG_FPS_FIXED: - CG_DrawFPS( &rect, text_x, text_y, scale, color, align, textStyle, qfalse ); - break; - case CG_TIMER: - CG_DrawTimer( &rect, text_x, text_y, scale, color, align, textStyle ); - break; - case CG_TIMER_MINS: - CG_DrawTimerMins( &rect, color ); - break; - case CG_TIMER_SECS: - CG_DrawTimerSecs( &rect, color ); - break; - case CG_SNAPSHOT: - CG_DrawSnapshot( &rect, text_x, text_y, scale, color, align, textStyle ); - break; - case CG_LAGOMETER: - CG_DrawLagometer( &rect, text_x, text_y, scale, color ); - break; - - case CG_CONSOLE: - CG_DrawConsole( &rect, text_x, text_y, color, scale, align, textStyle ); - break; - - default: - break; - } -} - -void CG_MouseEvent( int x, int y ) -{ - int n; - - if( ( cg.predictedPlayerState.pm_type == PM_NORMAL || - cg.predictedPlayerState.pm_type == PM_SPECTATOR ) && - cg.showScores == qfalse ) - { - trap_Key_SetCatcher( 0 ); - return; - } - - cgs.cursorX += x; - if( cgs.cursorX < 0 ) - cgs.cursorX = 0; - else if( cgs.cursorX > 640 ) - cgs.cursorX = 640; - - cgs.cursorY += y; - if( cgs.cursorY < 0 ) - cgs.cursorY = 0; - else if( cgs.cursorY > 480 ) - cgs.cursorY = 480; - - n = Display_CursorType( cgs.cursorX, cgs.cursorY ); - cgs.activeCursor = 0; - if( n == CURSOR_ARROW ) - cgs.activeCursor = cgs.media.selectCursor; - else if( n == CURSOR_SIZER ) - cgs.activeCursor = cgs.media.sizeCursor; - - if( cgs.capturedItem ) - Display_MouseMove( cgs.capturedItem, x, y ); - else - Display_MouseMove( NULL, cgs.cursorX, cgs.cursorY ); -} - -/* -================== -CG_HideTeamMenus -================== - -*/ -void CG_HideTeamMenu( ) -{ - Menus_CloseByName( "teamMenu" ); - Menus_CloseByName( "getMenu" ); -} - -/* -================== -CG_ShowTeamMenus -================== - -*/ -void CG_ShowTeamMenu( ) -{ - Menus_OpenByName( "teamMenu" ); -} - -/* -================== -CG_EventHandling -================== - type 0 - no event handling - 1 - team menu - 2 - hud editor - -*/ -void CG_EventHandling( int type ) -{ - cgs.eventHandling = type; - - if( type == CGAME_EVENT_NONE ) - CG_HideTeamMenu( ); -} - - - -void CG_KeyEvent( int key, qboolean down ) -{ - if( !down ) - return; - - if( cg.predictedPlayerState.pm_type == PM_NORMAL || - ( cg.predictedPlayerState.pm_type == PM_SPECTATOR && - cg.showScores == qfalse ) ) - { - CG_EventHandling( CGAME_EVENT_NONE ); - trap_Key_SetCatcher( 0 ); - return; - } - - Display_HandleKey( key, down, cgs.cursorX, cgs.cursorY ); - - if( cgs.capturedItem ) - cgs.capturedItem = NULL; - else - { - if( key == K_MOUSE2 && down ) - cgs.capturedItem = Display_CaptureItem( cgs.cursorX, cgs.cursorY ); - } -} - -int CG_ClientNumFromName( const char *p ) -{ - int i; - - for( i = 0; i < cgs.maxclients; i++ ) - { - if( cgs.clientinfo[ i ].infoValid && - Q_stricmp( cgs.clientinfo[ i ].name, p ) == 0 ) - return i; - } - - return -1; -} - -void CG_RunMenuScript( char **args ) -{ -} - - -void CG_GetTeamColor( vec4_t *color ) -{ - (*color)[ 0 ] = (*color)[ 2 ] = 0.0f; - (*color)[ 1 ] = 0.17f; - (*color)[ 3 ] = 0.25f; -} -//END TA UI - - -/* -================ -CG_DrawLighting - -================ -*/ -static void CG_DrawLighting( void ) -{ - centity_t *cent; - - cent = &cg_entities[ cg.snap->ps.clientNum ]; - - //fade to black if stamina is low - if( ( cg.snap->ps.stats[ STAT_STAMINA ] < -800 ) && - ( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) ) - { - vec4_t black = { 0, 0, 0, 0 }; - black[ 3 ] = 1.0 - ( (float)( cg.snap->ps.stats[ STAT_STAMINA ] + 1000 ) / 200.0f ); - trap_R_SetColor( black ); - CG_DrawPic( 0, 0, 640, 480, cgs.media.whiteShader ); - trap_R_SetColor( NULL ); - } -} - -/* -=============================================================================== - -CENTER PRINTING - -=============================================================================== -*/ - - -/* -============== -CG_CenterPrint - -Called for important messages that should stay in the center of the screen -for a few moments -============== -*/ -void CG_CenterPrint( const char *str, int y, int charWidth ) -{ - char *s; - - Q_strncpyz( cg.centerPrint, str, sizeof( cg.centerPrint ) ); - - cg.centerPrintTime = cg.time; - cg.centerPrintY = y; - cg.centerPrintCharWidth = charWidth; - - // count the number of lines for centering - cg.centerPrintLines = 1; - s = cg.centerPrint; - while( *s ) - { - if( *s == '\n' ) - cg.centerPrintLines++; - - s++; - } -} - - -/* -=================== -CG_DrawCenterString -=================== -*/ -static void CG_DrawCenterString( void ) -{ - char *start; - int l; - int x, y, w; - int h; - float *color; - - if( !cg.centerPrintTime ) - return; - - color = CG_FadeColor( cg.centerPrintTime, 1000 * cg_centertime.value ); - if( !color ) - return; - - trap_R_SetColor( color ); - - start = cg.centerPrint; - - y = cg.centerPrintY - cg.centerPrintLines * BIGCHAR_HEIGHT / 2; - - while( 1 ) - { - char linebuffer[ 1024 ]; - - for( l = 0; l < 50; l++ ) - { - if( !start[ l ] || start[ l ] == '\n' ) - break; - - linebuffer[ l ] = start[ l ]; - } - - linebuffer[ l ] = 0; - - w = CG_Text_Width( linebuffer, 0.5, 0 ); - h = CG_Text_Height( linebuffer, 0.5, 0 ); - x = ( SCREEN_WIDTH - w ) / 2; - CG_Text_Paint( x, y + h, 0.5, color, linebuffer, 0, 0, ITEM_TEXTSTYLE_SHADOWEDMORE ); - y += h + 6; - - while( *start && ( *start != '\n' ) ) - start++; - - if( !*start ) - break; - - start++; - } - - trap_R_SetColor( NULL ); -} - - - - - -//============================================================================== - -//FIXME: both vote notes are hardcoded, change to ownerdrawn? - -/* -================= -CG_DrawVote -================= -*/ -static void CG_DrawVote( void ) -{ - char *s; - int sec; - vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f }; - - if( !cgs.voteTime ) - return; - - // play a talk beep whenever it is modified - if( cgs.voteModified ) - { - cgs.voteModified = qfalse; - trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); - } - - sec = ( VOTE_TIME - ( cg.time - cgs.voteTime ) ) / 1000; - - if( sec < 0 ) - sec = 0; - - s = va( "VOTE(%i): \"%s\" Yes:%i No:%i", sec, cgs.voteString, cgs.voteYes, cgs.voteNo ); - CG_Text_Paint( 8, 340, 0.3f, white, s, 0, 0, ITEM_TEXTSTYLE_NORMAL ); -} - -/* -================= -CG_DrawTeamVote -================= -*/ -static void CG_DrawTeamVote( void ) -{ - char *s; - int sec, cs_offset; - vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f }; - - if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS ) - cs_offset = 0; - else if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS ) - cs_offset = 1; - else - return; - - if( !cgs.teamVoteTime[ cs_offset ] ) - return; - - // play a talk beep whenever it is modified - if ( cgs.teamVoteModified[ cs_offset ] ) - { - cgs.teamVoteModified[ cs_offset ] = qfalse; - trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); - } - - sec = ( VOTE_TIME - ( cg.time - cgs.teamVoteTime[ cs_offset ] ) ) / 1000; - - if( sec < 0 ) - sec = 0; - - s = va( "TEAMVOTE(%i): \"%s\" Yes:%i No:%i", sec, cgs.teamVoteString[ cs_offset ], - cgs.teamVoteYes[cs_offset], cgs.teamVoteNo[ cs_offset ] ); - - CG_Text_Paint( 8, 360, 0.3f, white, s, 0, 0, ITEM_TEXTSTYLE_NORMAL ); -} - - -static qboolean CG_DrawScoreboard( void ) -{ - static qboolean firstTime = qtrue; - float fade, *fadeColor; - - if( menuScoreboard ) - menuScoreboard->window.flags &= ~WINDOW_FORCED; - - if( cg_paused.integer ) - { - cg.deferredPlayerLoading = 0; - firstTime = qtrue; - return qfalse; - } - - if( cg.showScores || - cg.predictedPlayerState.pm_type == PM_INTERMISSION ) - { - fade = 1.0; - fadeColor = colorWhite; - } - else - { - cg.deferredPlayerLoading = 0; - cg.killerName[ 0 ] = 0; - firstTime = qtrue; - return qfalse; - } - - - if( menuScoreboard == NULL ) - menuScoreboard = Menus_FindByName( "teamscore_menu" ); - - if( menuScoreboard ) - { - if( firstTime ) - { - CG_SetScoreSelection( menuScoreboard ); - firstTime = qfalse; - } - - Menu_Paint( menuScoreboard, qtrue ); - } - - return qtrue; -} - -/* -================= -CG_DrawIntermission -================= -*/ -static void CG_DrawIntermission( void ) -{ - if( cg_drawStatus.integer ) - Menu_Paint( Menus_FindByName( "default_hud" ), qtrue ); - - cg.scoreFadeTime = cg.time; - cg.scoreBoardShowing = CG_DrawScoreboard( ); -} - -#define FOLLOWING_STRING "following " - -/* -================= -CG_DrawFollow -================= -*/ -static qboolean CG_DrawFollow( void ) -{ - float w; - vec4_t color; - char buffer[ MAX_STRING_CHARS ]; - - if( !( cg.snap->ps.pm_flags & PMF_FOLLOW ) ) - return qfalse; - - color[ 0 ] = 1; - color[ 1 ] = 1; - color[ 2 ] = 1; - color[ 3 ] = 1; - - strcpy( buffer, FOLLOWING_STRING ); - strcat( buffer, cgs.clientinfo[ cg.snap->ps.clientNum ].name ); - - w = CG_Text_Width( buffer, 0.7f, 0 ); - CG_Text_Paint( 320 - w / 2, 400, 0.7f, color, buffer, 0, 0, ITEM_TEXTSTYLE_SHADOWED ); - - return qtrue; -} - -/* -================= -CG_DrawQueue -================= -*/ -static qboolean CG_DrawQueue( void ) -{ - float w; - vec4_t color; - char buffer[ MAX_STRING_CHARS ]; - - if( !( cg.snap->ps.pm_flags & PMF_QUEUED ) ) - return qfalse; - - color[ 0 ] = 1; - color[ 1 ] = 1; - color[ 2 ] = 1; - color[ 3 ] = 1; - - Com_sprintf( buffer, MAX_STRING_CHARS, "You are in position %d of the spawn queue.", - cg.snap->ps.persistant[ PERS_QUEUEPOS ] + 1 ); - - w = CG_Text_Width( buffer, 0.7f, 0 ); - CG_Text_Paint( 320 - w / 2, 360, 0.7f, color, buffer, 0, 0, ITEM_TEXTSTYLE_SHADOWED ); - - if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - if( cgs.numAlienSpawns == 1 ) - Com_sprintf( buffer, MAX_STRING_CHARS, "There is 1 spawn remaining." ); - else - Com_sprintf( buffer, MAX_STRING_CHARS, "There are %d spawns remaining.", - cgs.numAlienSpawns ); - } - else if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - if( cgs.numHumanSpawns == 1 ) - Com_sprintf( buffer, MAX_STRING_CHARS, "There is 1 spawn remaining." ); - else - Com_sprintf( buffer, MAX_STRING_CHARS, "There are %d spawns remaining.", - cgs.numHumanSpawns ); - } - - w = CG_Text_Width( buffer, 0.7f, 0 ); - CG_Text_Paint( 320 - w / 2, 400, 0.7f, color, buffer, 0, 0, ITEM_TEXTSTYLE_SHADOWED ); - - return qtrue; -} - -//================================================================================== - -#define SPECTATOR_STRING "SPECTATOR" -/* -================= -CG_Draw2D -================= -*/ -static void CG_Draw2D( void ) -{ - vec4_t color; - float w; - menuDef_t *menu = NULL, *defaultMenu; - - color[ 0 ] = color[ 1 ] = color[ 2 ] = color[ 3 ] = 1.0f; - - // if we are taking a levelshot for the menu, don't draw anything - if( cg.levelShot ) - return; - - if( cg_draw2D.integer == 0 ) - return; - - if( cg.snap->ps.pm_type == PM_INTERMISSION ) - { - CG_DrawIntermission( ); - return; - } - - //TA: draw the lighting effects e.g. nvg - CG_DrawLighting( ); - - - defaultMenu = Menus_FindByName( "default_hud" ); - - if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) - { - w = CG_Text_Width( SPECTATOR_STRING, 0.7f, 0 ); - CG_Text_Paint( 320 - w / 2, 440, 0.7f, color, SPECTATOR_STRING, 0, 0, ITEM_TEXTSTYLE_SHADOWED ); - } - else - menu = Menus_FindByName( BG_FindHudNameForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] ) ); - - if( !( cg.snap->ps.stats[ STAT_STATE ] & SS_INFESTING ) && - !( cg.snap->ps.stats[ STAT_STATE ] & SS_HOVELING ) && menu && - ( cg.snap->ps.stats[ STAT_HEALTH ] > 0 ) ) - { - if( cg_drawStatus.integer ) - Menu_Paint( menu, qtrue ); - - CG_DrawCrosshair( ); - } - else if( cg_drawStatus.integer ) - Menu_Paint( defaultMenu, qtrue ); - - CG_DrawVote( ); - CG_DrawTeamVote( ); - CG_DrawFollow( ); - CG_DrawQueue( ); - - // don't draw center string if scoreboard is up - cg.scoreBoardShowing = CG_DrawScoreboard( ); - - if( !cg.scoreBoardShowing ) - CG_DrawCenterString( ); -} - -#define PAINBLEND_BORDER_W 0.15f -#define PAINBLEND_BORDER_H 0.07f - -/* -=============== -CG_PainBlend -=============== -*/ -static void CG_PainBlend( void ) -{ - vec4_t color; - int damage; - float damageAsFracOfMax; - qhandle_t shader = cgs.media.viewBloodShader; - float x, y, w, h; - - damage = cg.lastHealth - cg.snap->ps.stats[ STAT_HEALTH ]; - - if( damage < 0 ) - damage = 0; - - damageAsFracOfMax = (float)damage / cg.snap->ps.stats[ STAT_MAX_HEALTH ]; - cg.lastHealth = cg.snap->ps.stats[ STAT_HEALTH ]; - - cg.painBlendValue += damageAsFracOfMax * cg_painBlendScale.value; - - if( cg.painBlendValue > 0.0f ) - { - cg.painBlendValue -= ( cg.frametime / 1000.0f ) * - cg_painBlendDownRate.value; - } - - if( cg.painBlendValue > 1.0f ) - cg.painBlendValue = 1.0f; - else if( cg.painBlendValue <= 0.0f ) - { - cg.painBlendValue = 0.0f; - return; - } - - if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - VectorSet( color, 0.43f, 0.8f, 0.37f ); - else if( cg.snap->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - VectorSet( color, 0.8f, 0.0f, 0.0f ); - - if( cg.painBlendValue > cg.painBlendTarget ) - { - cg.painBlendTarget += ( cg.frametime / 1000.0f ) * - cg_painBlendUpRate.value; - } - else if( cg.painBlendValue < cg.painBlendTarget ) - cg.painBlendTarget = cg.painBlendValue; - - if( cg.painBlendTarget > cg_painBlendMax.value ) - cg.painBlendTarget = cg_painBlendMax.value; - - color[ 3 ] = cg.painBlendTarget; - - trap_R_SetColor( color ); - - //left - x = 0.0f; y = 0.0f; - w = PAINBLEND_BORDER_W * 640.0f; h = 480.0f; - CG_AdjustFrom640( &x, &y, &w, &h ); - trap_R_DrawStretchPic( x, y, w, h, - cg_painBlendZoom.value, cg_painBlendZoom.value, - cg_painBlendZoom.value + PAINBLEND_BORDER_W, 1.0f - cg_painBlendZoom.value, - shader ); - - //right - x = 640.0f - ( PAINBLEND_BORDER_W * 640.0f ); y = 0.0f; - w = PAINBLEND_BORDER_W * 640.0f; h = 480.0f; - CG_AdjustFrom640( &x, &y, &w, &h ); - trap_R_DrawStretchPic( x, y, w, h, - 1.0f - cg_painBlendZoom.value - PAINBLEND_BORDER_W, cg_painBlendZoom.value, - 1.0f - cg_painBlendZoom.value, 1.0f - cg_painBlendZoom.value, - shader ); - - //top - x = PAINBLEND_BORDER_W * 640.0f; y = 0.0f; - w = 640.0f - ( 2 * PAINBLEND_BORDER_W * 640.0f ); h = PAINBLEND_BORDER_H * 480.0f; - CG_AdjustFrom640( &x, &y, &w, &h ); - trap_R_DrawStretchPic( x, y, w, h, - cg_painBlendZoom.value + PAINBLEND_BORDER_W, cg_painBlendZoom.value, - 1.0f - cg_painBlendZoom.value - PAINBLEND_BORDER_W, cg_painBlendZoom.value + PAINBLEND_BORDER_H, - shader ); - - //bottom - x = PAINBLEND_BORDER_W * 640.0f; y = 480.0f - ( PAINBLEND_BORDER_H * 480.0f ); - w = 640.0f - ( 2 * PAINBLEND_BORDER_W * 640.0f ); h = PAINBLEND_BORDER_H * 480.0f; - CG_AdjustFrom640( &x, &y, &w, &h ); - trap_R_DrawStretchPic( x, y, w, h, - cg_painBlendZoom.value + PAINBLEND_BORDER_W, 1.0f - cg_painBlendZoom.value - PAINBLEND_BORDER_H, - 1.0f - cg_painBlendZoom.value - PAINBLEND_BORDER_W, 1.0f - cg_painBlendZoom.value, - shader ); - - trap_R_SetColor( NULL ); -} - -/* -===================== -CG_ResetPainBlend -===================== -*/ -void CG_ResetPainBlend( void ) -{ - cg.painBlendValue = 0.0f; - cg.painBlendTarget = 0.0f; - cg.lastHealth = cg.snap->ps.stats[ STAT_MAX_HEALTH ]; -} - -/* -===================== -CG_DrawActive - -Perform all drawing needed to completely fill the screen -===================== -*/ -void CG_DrawActive( stereoFrame_t stereoView ) -{ - float separation; - vec3_t baseOrg; - - // optionally draw the info screen instead - if( !cg.snap ) - return; - - switch ( stereoView ) - { - case STEREO_CENTER: - separation = 0; - break; - case STEREO_LEFT: - separation = -cg_stereoSeparation.value / 2; - break; - case STEREO_RIGHT: - separation = cg_stereoSeparation.value / 2; - break; - default: - separation = 0; - CG_Error( "CG_DrawActive: Undefined stereoView" ); - } - - // clear around the rendered view if sized down - CG_TileClear( ); - - // offset vieworg appropriately if we're doing stereo separation - VectorCopy( cg.refdef.vieworg, baseOrg ); - - if( separation != 0 ) - VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[ 1 ], - cg.refdef.vieworg ); - - // draw 3D view - trap_R_RenderScene( &cg.refdef ); - - // restore original viewpoint if running stereo - if( separation != 0 ) - VectorCopy( baseOrg, cg.refdef.vieworg ); - - // first person blend blobs, done after AnglesToAxis - if( !cg.renderingThirdPerson ) - CG_PainBlend( ); - - // draw status bar and other floating elements - CG_Draw2D( ); -} - - diff --git a/src/cgame/cg_drawtools.c b/src/cgame/cg_drawtools.c deleted file mode 100644 index b1f0d9ab..00000000 --- a/src/cgame/cg_drawtools.c +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -/* -=============== -CG_DrawPlane - -Draw a quad in 3 space - basically CG_DrawPic in 3 space -=============== -*/ -void CG_DrawPlane( vec3_t origin, vec3_t down, vec3_t right, qhandle_t shader ) -{ - polyVert_t verts[ 4 ]; - vec3_t temp; - - VectorCopy( origin, verts[ 0 ].xyz ); - verts[ 0 ].st[ 0 ] = 0; - verts[ 0 ].st[ 1 ] = 0; - verts[ 0 ].modulate[ 0 ] = 255; - verts[ 0 ].modulate[ 1 ] = 255; - verts[ 0 ].modulate[ 2 ] = 255; - verts[ 0 ].modulate[ 3 ] = 255; - - VectorAdd( origin, right, temp ); - VectorCopy( temp, verts[ 1 ].xyz ); - verts[ 1 ].st[ 0 ] = 1; - verts[ 1 ].st[ 1 ] = 0; - verts[ 1 ].modulate[ 0 ] = 255; - verts[ 1 ].modulate[ 1 ] = 255; - verts[ 1 ].modulate[ 2 ] = 255; - verts[ 1 ].modulate[ 3 ] = 255; - - VectorAdd( origin, right, temp ); - VectorAdd( temp, down, temp ); - VectorCopy( temp, verts[ 2 ].xyz ); - verts[ 2 ].st[ 0 ] = 1; - verts[ 2 ].st[ 1 ] = 1; - verts[ 2 ].modulate[ 0 ] = 255; - verts[ 2 ].modulate[ 1 ] = 255; - verts[ 2 ].modulate[ 2 ] = 255; - verts[ 2 ].modulate[ 3 ] = 255; - - VectorAdd( origin, down, temp ); - VectorCopy( temp, verts[ 3 ].xyz ); - verts[ 3 ].st[ 0 ] = 0; - verts[ 3 ].st[ 1 ] = 1; - verts[ 3 ].modulate[ 0 ] = 255; - verts[ 3 ].modulate[ 1 ] = 255; - verts[ 3 ].modulate[ 2 ] = 255; - verts[ 3 ].modulate[ 3 ] = 255; - - trap_R_AddPolyToScene( shader, 4, verts ); -} - -/* -================ -CG_AdjustFrom640 - -Adjusted for resolution and screen aspect ratio -================ -*/ -void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) -{ -#if 0 - // adjust for wide screens - if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) { - *x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) ); - } -#endif - // scale for screen sizes - *x *= cgs.screenXScale; - *y *= cgs.screenYScale; - *w *= cgs.screenXScale; - *h *= cgs.screenYScale; -} - -/* -================ -CG_FillRect - -Coordinates are 640*480 virtual values -================= -*/ -void CG_FillRect( float x, float y, float width, float height, const float *color ) -{ - trap_R_SetColor( color ); - - CG_AdjustFrom640( &x, &y, &width, &height ); - trap_R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cgs.media.whiteShader ); - - trap_R_SetColor( NULL ); -} - - -/* -================ -CG_DrawSides - -Coords are virtual 640x480 -================ -*/ -void CG_DrawSides( float x, float y, float w, float h, float size ) -{ - CG_AdjustFrom640( &x, &y, &w, &h ); - size *= cgs.screenXScale; - trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader ); - trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader ); -} - -void CG_DrawTopBottom( float x, float y, float w, float h, float size ) -{ - CG_AdjustFrom640( &x, &y, &w, &h ); - size *= cgs.screenYScale; - trap_R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, cgs.media.whiteShader ); - trap_R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, cgs.media.whiteShader ); -} - - -/* -================ -CG_DrawRect - -Coordinates are 640*480 virtual values -================= -*/ -void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ) -{ - trap_R_SetColor( color ); - - CG_DrawTopBottom( x, y, width, height, size ); - CG_DrawSides( x, y, width, height, size ); - - trap_R_SetColor( NULL ); -} - - -/* -================ -CG_DrawPic - -Coordinates are 640*480 virtual values -================= -*/ -void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) -{ - CG_AdjustFrom640( &x, &y, &width, &height ); - trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader ); -} - - - -/* -================ -CG_DrawFadePic - -Coordinates are 640*480 virtual values -================= -*/ -void CG_DrawFadePic( float x, float y, float width, float height, vec4_t fcolor, - vec4_t tcolor, float amount, qhandle_t hShader ) -{ - vec4_t finalcolor; - float inverse; - - inverse = 100 - amount; - - CG_AdjustFrom640( &x, &y, &width, &height ); - - finalcolor[ 0 ] = ( ( inverse * fcolor[ 0 ] ) + ( amount * tcolor[ 0 ] ) ) / 100; - finalcolor[ 1 ] = ( ( inverse * fcolor[ 1 ] ) + ( amount * tcolor[ 1 ] ) ) / 100; - finalcolor[ 2 ] = ( ( inverse * fcolor[ 2 ] ) + ( amount * tcolor[ 2 ] ) ) / 100; - finalcolor[ 3 ] = ( ( inverse * fcolor[ 3 ] ) + ( amount * tcolor[ 3 ] ) ) / 100; - - trap_R_SetColor( finalcolor ); - trap_R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader ); - trap_R_SetColor( NULL ); -} - -/* -================= -CG_DrawStrlen - -Returns character count, skiping color escape codes -================= -*/ -int CG_DrawStrlen( const char *str ) -{ - const char *s = str; - int count = 0; - - while( *s ) - { - if( Q_IsColorString( s ) ) - s += 2; - else - { - count++; - s++; - } - } - - return count; -} - -/* -============= -CG_TileClearBox - -This repeats a 64*64 tile graphic to fill the screen around a sized down -refresh window. -============= -*/ -static void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader ) -{ - float s1, t1, s2, t2; - - s1 = x / 64.0; - t1 = y / 64.0; - s2 = ( x + w ) / 64.0; - t2 = ( y + h ) / 64.0; - trap_R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader ); -} - - - -/* -============== -CG_TileClear - -Clear around a sized down screen -============== -*/ -void CG_TileClear( void ) -{ - int top, bottom, left, right; - int w, h; - - w = cgs.glconfig.vidWidth; - h = cgs.glconfig.vidHeight; - - if( cg.refdef.x == 0 && cg.refdef.y == 0 && - cg.refdef.width == w && cg.refdef.height == h ) - return; // full screen rendering - - top = cg.refdef.y; - bottom = top + cg.refdef.height - 1; - left = cg.refdef.x; - right = left + cg.refdef.width - 1; - - // clear above view screen - CG_TileClearBox( 0, 0, w, top, cgs.media.backTileShader ); - - // clear below view screen - CG_TileClearBox( 0, bottom, w, h - bottom, cgs.media.backTileShader ); - - // clear left of view screen - CG_TileClearBox( 0, top, left, bottom - top + 1, cgs.media.backTileShader ); - - // clear right of view screen - CG_TileClearBox( right, top, w - right, bottom - top + 1, cgs.media.backTileShader ); -} - - - -/* -================ -CG_FadeColor -================ -*/ -float *CG_FadeColor( int startMsec, int totalMsec ) -{ - static vec4_t color; - int t; - - if( startMsec == 0 ) - return NULL; - - t = cg.time - startMsec; - - if( t >= totalMsec ) - return NULL; - - // fade out - if( totalMsec - t < FADE_TIME ) - color[ 3 ] = ( totalMsec - t ) * 1.0 / FADE_TIME; - else - color[ 3 ] = 1.0; - - color[ 0 ] = color[ 1 ] = color[ 2 ] = 1; - - return color; -} diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c deleted file mode 100644 index b622d2f3..00000000 --- a/src/cgame/cg_ents.c +++ /dev/null @@ -1,1225 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_ents.c -- present snapshot entities, happens every single frame - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -/* -====================== -CG_DrawBoxFace - -Draws a bounding box face -====================== -*/ -static void CG_DrawBoxFace( vec3_t a, vec3_t b, vec3_t c, vec3_t d ) -{ - polyVert_t verts[ 4 ]; - vec4_t color = { 255.0f, 0.0f, 0.0f, 128.0f }; - - VectorCopy( d, verts[ 0 ].xyz ); - verts[ 0 ].st[ 0 ] = 1; - verts[ 0 ].st[ 1 ] = 1; - Vector4Copy( color, verts[ 0 ].modulate ); - - VectorCopy( c, verts[ 1 ].xyz ); - verts[ 1 ].st[ 0 ] = 1; - verts[ 1 ].st[ 1 ] = 0; - Vector4Copy( color, verts[ 1 ].modulate ); - - VectorCopy( b, verts[ 2 ].xyz ); - verts[ 2 ].st[ 0 ] = 0; - verts[ 2 ].st[ 1 ] = 0; - Vector4Copy( color, verts[ 2 ].modulate ); - - VectorCopy( a, verts[ 3 ].xyz ); - verts[ 3 ].st[ 0 ] = 0; - verts[ 3 ].st[ 1 ] = 1; - Vector4Copy( color, verts[ 3 ].modulate ); - - trap_R_AddPolyToScene( cgs.media.outlineShader, 4, verts ); -} - -/* -====================== -CG_DrawBoundingBox - -Draws a bounding box -====================== -*/ -void CG_DrawBoundingBox( vec3_t origin, vec3_t mins, vec3_t maxs ) -{ - vec3_t ppp, mpp, mmp, pmp; - vec3_t mmm, pmm, ppm, mpm; - - ppp[ 0 ] = origin[ 0 ] + maxs[ 0 ]; - ppp[ 1 ] = origin[ 1 ] + maxs[ 1 ]; - ppp[ 2 ] = origin[ 2 ] + maxs[ 2 ]; - - mpp[ 0 ] = origin[ 0 ] + mins[ 0 ]; - mpp[ 1 ] = origin[ 1 ] + maxs[ 1 ]; - mpp[ 2 ] = origin[ 2 ] + maxs[ 2 ]; - - mmp[ 0 ] = origin[ 0 ] + mins[ 0 ]; - mmp[ 1 ] = origin[ 1 ] + mins[ 1 ]; - mmp[ 2 ] = origin[ 2 ] + maxs[ 2 ]; - - pmp[ 0 ] = origin[ 0 ] + maxs[ 0 ]; - pmp[ 1 ] = origin[ 1 ] + mins[ 1 ]; - pmp[ 2 ] = origin[ 2 ] + maxs[ 2 ]; - - ppm[ 0 ] = origin[ 0 ] + maxs[ 0 ]; - ppm[ 1 ] = origin[ 1 ] + maxs[ 1 ]; - ppm[ 2 ] = origin[ 2 ] + mins[ 2 ]; - - mpm[ 0 ] = origin[ 0 ] + mins[ 0 ]; - mpm[ 1 ] = origin[ 1 ] + maxs[ 1 ]; - mpm[ 2 ] = origin[ 2 ] + mins[ 2 ]; - - mmm[ 0 ] = origin[ 0 ] + mins[ 0 ]; - mmm[ 1 ] = origin[ 1 ] + mins[ 1 ]; - mmm[ 2 ] = origin[ 2 ] + mins[ 2 ]; - - pmm[ 0 ] = origin[ 0 ] + maxs[ 0 ]; - pmm[ 1 ] = origin[ 1 ] + mins[ 1 ]; - pmm[ 2 ] = origin[ 2 ] + mins[ 2 ]; - - //phew! - - CG_DrawBoxFace( ppp, mpp, mmp, pmp ); - CG_DrawBoxFace( ppp, pmp, pmm, ppm ); - CG_DrawBoxFace( mpp, ppp, ppm, mpm ); - CG_DrawBoxFace( mmp, mpp, mpm, mmm ); - CG_DrawBoxFace( pmp, mmp, mmm, pmm ); - CG_DrawBoxFace( mmm, mpm, ppm, pmm ); -} - - -/* -====================== -CG_PositionEntityOnTag - -Modifies the entities position and axis by the given -tag location -====================== -*/ -void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent, - qhandle_t parentModel, char *tagName ) -{ - int i; - orientation_t lerped; - - // lerp the tag - trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame, - 1.0 - parent->backlerp, tagName ); - - // FIXME: allow origin offsets along tag? - VectorCopy( parent->origin, entity->origin ); - for( i = 0; i < 3; i++ ) - VectorMA( entity->origin, lerped.origin[ i ], parent->axis[ i ], entity->origin ); - - // had to cast away the const to avoid compiler problems... - MatrixMultiply( lerped.axis, ( (refEntity_t *)parent )->axis, entity->axis ); - entity->backlerp = parent->backlerp; -} - - -/* -====================== -CG_PositionRotatedEntityOnTag - -Modifies the entities position and axis by the given -tag location -====================== -*/ -void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent, - qhandle_t parentModel, char *tagName ) -{ - int i; - orientation_t lerped; - vec3_t tempAxis[ 3 ]; - -//AxisClear( entity->axis ); - // lerp the tag - trap_R_LerpTag( &lerped, parentModel, parent->oldframe, parent->frame, - 1.0 - parent->backlerp, tagName ); - - // FIXME: allow origin offsets along tag? - VectorCopy( parent->origin, entity->origin ); - for( i = 0; i < 3; i++ ) - VectorMA( entity->origin, lerped.origin[ i ], parent->axis[ i ], entity->origin ); - - // had to cast away the const to avoid compiler problems... - MatrixMultiply( entity->axis, lerped.axis, tempAxis ); - MatrixMultiply( tempAxis, ( (refEntity_t *)parent )->axis, entity->axis ); -} - - - -/* -========================================================================== - -FUNCTIONS CALLED EACH FRAME - -========================================================================== -*/ - -/* -====================== -CG_SetEntitySoundPosition - -Also called by event processing code -====================== -*/ -void CG_SetEntitySoundPosition( centity_t *cent ) -{ - if( cent->currentState.solid == SOLID_BMODEL ) - { - vec3_t origin; - float *v; - - v = cgs.inlineModelMidpoints[ cent->currentState.modelindex ]; - VectorAdd( cent->lerpOrigin, v, origin ); - trap_S_UpdateEntityPosition( cent->currentState.number, origin ); - } - else - trap_S_UpdateEntityPosition( cent->currentState.number, cent->lerpOrigin ); -} - -/* -================== -CG_EntityEffects - -Add continuous entity effects, like local entity emission and lighting -================== -*/ -static void CG_EntityEffects( centity_t *cent ) -{ - // update sound origins - CG_SetEntitySoundPosition( cent ); - - // add loop sound - if( cent->currentState.loopSound ) - { - if( cent->currentState.eType != ET_SPEAKER ) - { - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, - cgs.gameSounds[ cent->currentState.loopSound ] ); - } - else - { - trap_S_AddRealLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, - cgs.gameSounds[ cent->currentState.loopSound ] ); - } - } - - - // constant light glow - if ( cent->currentState.constantLight ) - { - int cl; - int i, r, g, b; - - cl = cent->currentState.constantLight; - r = cl & 255; - g = ( cl >> 8 ) & 255; - b = ( cl >> 16 ) & 255; - i = ( ( cl >> 24 ) & 255 ) * 4; - trap_R_AddLightToScene( cent->lerpOrigin, i, r, g, b ); - } - - if( cg.time > cent->muzzleTSDeathTime && CG_IsTrailSystemValid( ¢->muzzleTS ) ) - CG_DestroyTrailSystem( ¢->muzzleTS ); -} - - -/* -================== -CG_General -================== -*/ -static void CG_General( centity_t *cent ) -{ - refEntity_t ent; - entityState_t *s1; - - s1 = ¢->currentState; - - // if set to invisible, skip - if( !s1->modelindex ) - return; - - memset( &ent, 0, sizeof( ent ) ); - - // set frame - - ent.frame = s1->frame; - ent.oldframe = ent.frame; - ent.backlerp = 0; - - VectorCopy( cent->lerpOrigin, ent.origin); - VectorCopy( cent->lerpOrigin, ent.oldorigin); - - ent.hModel = cgs.gameModels[ s1->modelindex ]; - - // player model - if( s1->number == cg.snap->ps.clientNum ) - ent.renderfx |= RF_THIRD_PERSON; // only draw from mirrors - - // convert angles to axis - AnglesToAxis( cent->lerpAngles, ent.axis ); - - // add to refresh list - trap_R_AddRefEntityToScene( &ent ); -} - -/* -================== -CG_Speaker - -Speaker entities can automatically play sounds -================== -*/ -static void CG_Speaker( centity_t *cent ) -{ - if( ! cent->currentState.clientNum ) - { // FIXME: use something other than clientNum... - return; // not auto triggering - } - - if( cg.time < cent->miscTime ) - return; - - trap_S_StartSound( NULL, cent->currentState.number, CHAN_ITEM, cgs.gameSounds[ cent->currentState.eventParm ] ); - - // ent->s.frame = ent->wait * 10; - // ent->s.clientNum = ent->random * 10; - cent->miscTime = cg.time + cent->currentState.frame * 100 + cent->currentState.clientNum * 100 * crandom( ); -} - - -//============================================================================ - -/* -=============== -CG_LaunchMissile -=============== -*/ -static void CG_LaunchMissile( centity_t *cent ) -{ - entityState_t *es; - const weaponInfo_t *wi; - particleSystem_t *ps; - trailSystem_t *ts; - weapon_t weapon; - weaponMode_t weaponMode; - - es = ¢->currentState; - - weapon = es->weapon; - if( weapon > WP_NUM_WEAPONS ) - weapon = WP_NONE; - - wi = &cg_weapons[ weapon ]; - weaponMode = es->generic1; - - if( wi->wim[ weaponMode ].missileParticleSystem ) - { - ps = CG_SpawnNewParticleSystem( wi->wim[ weaponMode ].missileParticleSystem ); - - if( CG_IsParticleSystemValid( &ps ) ) - { - CG_SetAttachmentCent( &ps->attachment, cent ); - CG_AttachToCent( &ps->attachment ); - } - } - - if( wi->wim[ weaponMode ].missileTrailSystem ) - { - ts = CG_SpawnNewTrailSystem( wi->wim[ weaponMode ].missileTrailSystem ); - - if( CG_IsTrailSystemValid( &ts ) ) - { - CG_SetAttachmentCent( &ts->frontAttachment, cent ); - CG_AttachToCent( &ts->frontAttachment ); - } - } -} - -/* -=============== -CG_Missile -=============== -*/ -static void CG_Missile( centity_t *cent ) -{ - refEntity_t ent; - entityState_t *es; - const weaponInfo_t *wi; - weapon_t weapon; - weaponMode_t weaponMode; - const weaponInfoMode_t *wim; - - es = ¢->currentState; - - weapon = es->weapon; - if( weapon > WP_NUM_WEAPONS ) - weapon = WP_NONE; - - wi = &cg_weapons[ weapon ]; - weaponMode = es->generic1; - - wim = &wi->wim[ weaponMode ]; - - // calculate the axis - VectorCopy( es->angles, cent->lerpAngles ); - - // add dynamic light - if( wim->missileDlight ) - { - trap_R_AddLightToScene( cent->lerpOrigin, wim->missileDlight, - wim->missileDlightColor[ 0 ], - wim->missileDlightColor[ 1 ], - wim->missileDlightColor[ 2 ] ); - } - - // add missile sound - if( wim->missileSound ) - { - vec3_t velocity; - - BG_EvaluateTrajectoryDelta( ¢->currentState.pos, cg.time, velocity ); - - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, wim->missileSound ); - } - - // create the render entity - memset( &ent, 0, sizeof( ent ) ); - VectorCopy( cent->lerpOrigin, ent.origin ); - VectorCopy( cent->lerpOrigin, ent.oldorigin ); - - if( wim->usesSpriteMissle ) - { - ent.reType = RT_SPRITE; - ent.radius = wim->missileSpriteSize; - ent.rotation = 0; - ent.customShader = wim->missileSprite; - ent.shaderRGBA[ 0 ] = 0xFF; - ent.shaderRGBA[ 1 ] = 0xFF; - ent.shaderRGBA[ 2 ] = 0xFF; - ent.shaderRGBA[ 3 ] = 0xFF; - } - else - { - ent.hModel = wim->missileModel; - ent.renderfx = wim->missileRenderfx | RF_NOSHADOW; - - // convert direction of travel into axis - if( VectorNormalize2( es->pos.trDelta, ent.axis[ 0 ] ) == 0 ) - ent.axis[ 0 ][ 2 ] = 1; - - // spin as it moves - if( es->pos.trType != TR_STATIONARY && wim->missileRotates ) - RotateAroundDirection( ent.axis, cg.time / 4 ); - else - RotateAroundDirection( ent.axis, es->time ); - - if( wim->missileAnimates ) - { - int timeSinceStart = cg.time - es->time; - - if( wim->missileAnimLooping ) - { - ent.frame = wim->missileAnimStartFrame + - (int)( ( timeSinceStart / 1000.0f ) * wim->missileAnimFrameRate ) % - wim->missileAnimNumFrames; - } - else - { - ent.frame = wim->missileAnimStartFrame + - (int)( ( timeSinceStart / 1000.0f ) * wim->missileAnimFrameRate ); - - if( ent.frame > ( wim->missileAnimStartFrame + wim->missileAnimNumFrames ) ) - ent.frame = wim->missileAnimStartFrame + wim->missileAnimNumFrames; - } - } - } - - //only refresh if there is something to display - if( wim->missileSprite || wim->missileModel ) - trap_R_AddRefEntityToScene( &ent ); -} - -/* -=============== -CG_Mover -=============== -*/ -static void CG_Mover( centity_t *cent ) -{ - refEntity_t ent; - entityState_t *s1; - - s1 = ¢->currentState; - - // create the render entity - memset( &ent, 0, sizeof( ent ) ); - VectorCopy( cent->lerpOrigin, ent.origin ); - VectorCopy( cent->lerpOrigin, ent.oldorigin ); - AnglesToAxis( cent->lerpAngles, ent.axis ); - - ent.renderfx = RF_NOSHADOW; - - // flicker between two skins (FIXME?) - ent.skinNum = ( cg.time >> 6 ) & 1; - - // get the model, either as a bmodel or a modelindex - if( s1->solid == SOLID_BMODEL ) - ent.hModel = cgs.inlineDrawModel[ s1->modelindex ]; - else - ent.hModel = cgs.gameModels[ s1->modelindex ]; - - // add to refresh list - trap_R_AddRefEntityToScene( &ent ); - - // add the secondary model - if( s1->modelindex2 ) - { - ent.skinNum = 0; - ent.hModel = cgs.gameModels[ s1->modelindex2 ]; - trap_R_AddRefEntityToScene( &ent ); - } - -} - -/* -=============== -CG_Beam - -Also called as an event -=============== -*/ -void CG_Beam( centity_t *cent ) -{ - refEntity_t ent; - entityState_t *s1; - - s1 = ¢->currentState; - - // create the render entity - memset( &ent, 0, sizeof( ent ) ); - VectorCopy( s1->pos.trBase, ent.origin ); - VectorCopy( s1->origin2, ent.oldorigin ); - AxisClear( ent.axis ); - ent.reType = RT_BEAM; - - ent.renderfx = RF_NOSHADOW; - - // add to refresh list - trap_R_AddRefEntityToScene( &ent ); -} - - -/* -=============== -CG_Portal -=============== -*/ -static void CG_Portal( centity_t *cent ) -{ - refEntity_t ent; - entityState_t *s1; - - s1 = ¢->currentState; - - // create the render entity - memset( &ent, 0, sizeof( ent ) ); - VectorCopy( cent->lerpOrigin, ent.origin ); - VectorCopy( s1->origin2, ent.oldorigin ); - ByteToDir( s1->eventParm, ent.axis[ 0 ] ); - PerpendicularVector( ent.axis[ 1 ], ent.axis[ 0 ] ); - - // negating this tends to get the directions like they want - // we really should have a camera roll value - VectorSubtract( vec3_origin, ent.axis[ 1 ], ent.axis[ 1 ] ); - - CrossProduct( ent.axis[ 0 ], ent.axis[ 1 ], ent.axis[ 2 ] ); - ent.reType = RT_PORTALSURFACE; - ent.oldframe = s1->powerups; - ent.frame = s1->frame; // rotation speed - ent.skinNum = s1->clientNum / 256.0 * 360; // roll offset - - // add to refresh list - trap_R_AddRefEntityToScene( &ent ); -} - -//============================================================================ - -#define SETBOUNDS(v1,v2,r) ((v1)[0]=(-r/2),(v1)[1]=(-r/2),(v1)[2]=(-r/2),\ - (v2)[0]=(r/2),(v2)[1]=(r/2),(v2)[2]=(r/2)) -#define RADIUSSTEP 0.5f - -#define FLARE_OFF 0 -#define FLARE_NOFADE 1 -#define FLARE_TIMEFADE 2 -#define FLARE_REALFADE 3 - -/* -========================= -CG_LightFlare -========================= -*/ -static void CG_LightFlare( centity_t *cent ) -{ - refEntity_t flare; - entityState_t *es; - vec3_t forward, delta; - float len; - trace_t tr; - float maxAngle; - vec3_t mins, maxs, start, end; - float srcRadius, srLocal, ratio = 1.0f; - int entityNum; - - es = ¢->currentState; - - if( cg.renderingThirdPerson ) - entityNum = MAGIC_TRACE_HACK; - else - entityNum = cg.predictedPlayerState.clientNum; - - //don't draw light flares - if( cg_lightFlare.integer == FLARE_OFF ) - return; - - //flare is "off" - if( es->eFlags & EF_NODRAW ) - return; - - CG_Trace( &tr, cg.refdef.vieworg, NULL, NULL, es->angles2, - entityNum, MASK_SHOT ); - - //if there is no los between the view and the flare source - //it definately cannot be seen - if( tr.fraction < 1.0f || tr.allsolid ) - return; - - memset( &flare, 0, sizeof( flare ) ); - - flare.reType = RT_SPRITE; - flare.customShader = cgs.gameShaders[ es->modelindex ]; - flare.shaderRGBA[ 0 ] = 0xFF; - flare.shaderRGBA[ 1 ] = 0xFF; - flare.shaderRGBA[ 2 ] = 0xFF; - flare.shaderRGBA[ 3 ] = 0xFF; - - //flares always drawn before the rest of the scene - flare.renderfx |= RF_DEPTHHACK; - - //bunch of geometry - AngleVectors( es->angles, forward, NULL, NULL ); - VectorCopy( cent->lerpOrigin, flare.origin ); - VectorSubtract( flare.origin, cg.refdef.vieworg, delta ); - len = VectorLength( delta ); - VectorNormalize( delta ); - - //flare is too close to camera to be drawn - if( len < es->generic1 ) - return; - - //don't bother for flares behind the view plane - if( DotProduct( delta, cg.refdef.viewaxis[ 0 ] ) < 0.0 ) - return; - - //only recalculate radius and ratio every three frames - if( !( cg.clientFrame % 2 ) ) - { - //can only see the flare when in front of it - flare.radius = len / es->origin2[ 0 ]; - - if( es->origin2[ 2 ] == 0 ) - srcRadius = srLocal = flare.radius / 2.0f; - else - srcRadius = srLocal = len / es->origin2[ 2 ]; - - maxAngle = es->origin2[ 1 ]; - - if( maxAngle > 0.0f ) - { - float radiusMod = 1.0f - ( 180.0f - RAD2DEG( - acos( DotProduct( delta, forward ) ) ) ) / maxAngle; - - if( es->eFlags & EF_NODRAW ) - flare.radius *= radiusMod; - else if( radiusMod < 0.0f ) - flare.radius = 0.0f; - } - - if( flare.radius < 0.0f ) - flare.radius = 0.0f; - - VectorMA( flare.origin, -flare.radius, delta, end ); - VectorMA( cg.refdef.vieworg, flare.radius, delta, start ); - - if( cg_lightFlare.integer == FLARE_REALFADE ) - { - //draw "correct" albeit inefficient flares - srLocal = cent->lfs.lastSrcRadius; - - //flare radius is likely to be the same as last frame so start with it - do - { - srLocal += RADIUSSTEP; - SETBOUNDS( mins, maxs, srLocal ); - CG_Trace( &tr, start, mins, maxs, end, - entityNum, MASK_SHOT ); - - } while( ( tr.fraction == 1.0f && !tr.startsolid ) && ( srLocal < srcRadius ) ); - - srLocal -= RADIUSSTEP; - - //shink the flare until there is a los - do - { - SETBOUNDS( mins, maxs, srLocal ); - CG_Trace( &tr, start, mins, maxs, end, - entityNum, MASK_SHOT ); - - srLocal -= RADIUSSTEP; - } while( ( tr.fraction < 1.0f || tr.startsolid ) && ( srLocal > 0.0f ) ); - - ratio = srLocal / srcRadius; - - cent->lfs.lastSrcRadius = srLocal; - } - else if( cg_lightFlare.integer == FLARE_TIMEFADE ) - { - //draw timed flares - SETBOUNDS( mins, maxs, srcRadius ); - CG_Trace( &tr, start, mins, maxs, end, - entityNum, MASK_SHOT ); - - if( ( tr.fraction < 1.0f || tr.startsolid ) && cent->lfs.status ) - { - cent->lfs.status = qfalse; - cent->lfs.lastTime = cg.time; - } - else if( ( tr.fraction == 1.0f && !tr.startsolid ) && !cent->lfs.status ) - { - cent->lfs.status = qtrue; - cent->lfs.lastTime = cg.time; - } - - //fade flare up - if( cent->lfs.status ) - { - if( cent->lfs.lastTime + es->time > cg.time ) - ratio = (float)( cg.time - cent->lfs.lastTime ) / es->time; - } - - //fade flare down - if( !cent->lfs.status ) - { - if( cent->lfs.lastTime + es->time > cg.time ) - { - ratio = (float)( cg.time - cent->lfs.lastTime ) / es->time; - ratio = 1.0f - ratio; - } - else - ratio = 0.0f; - } - } - else if( cg_lightFlare.integer == FLARE_NOFADE ) - { - //draw nofade flares - SETBOUNDS( mins, maxs, srcRadius ); - CG_Trace( &tr, start, mins, maxs, end, - entityNum, MASK_SHOT ); - - //flare source occluded - if( ( tr.fraction < 1.0f || tr.startsolid ) ) - ratio = 0.0f; - } - } - else - { - ratio = cent->lfs.lastRatio; - flare.radius = cent->lfs.lastRadius; - } - - cent->lfs.lastRatio = ratio; - cent->lfs.lastRadius = flare.radius; - - if( ratio < 1.0f ) - { - flare.radius *= ratio; - flare.shaderRGBA[ 3 ] = (byte)( (float)flare.shaderRGBA[ 3 ] * ratio ); - } - - if( flare.radius <= 0.0f ) - return; - - trap_R_AddRefEntityToScene( &flare ); -} - -/* -========================= -CG_Lev2ZapChain -========================= -*/ -static void CG_Lev2ZapChain( centity_t *cent ) -{ - int i; - entityState_t *es; - centity_t *source, *target; - - es = ¢->currentState; - - for( i = 0; i <= 2; i++ ) - { - switch( i ) - { - case 0: - if( es->time <= 0 ) - continue; - - source = &cg_entities[ es->powerups ]; - target = &cg_entities[ es->time ]; - break; - - case 1: - if( es->time2 <= 0 ) - continue; - - source = &cg_entities[ es->time ]; - target = &cg_entities[ es->time2 ]; - break; - - case 2: - if( es->constantLight <= 0 ) - continue; - - source = &cg_entities[ es->time2 ]; - target = &cg_entities[ es->constantLight ]; - break; - } - - if( !CG_IsTrailSystemValid( ¢->level2ZapTS[ i ] ) ) - cent->level2ZapTS[ i ] = CG_SpawnNewTrailSystem( cgs.media.level2ZapTS ); - - if( CG_IsTrailSystemValid( ¢->level2ZapTS[ i ] ) ) - { - CG_SetAttachmentCent( ¢->level2ZapTS[ i ]->frontAttachment, source ); - CG_SetAttachmentCent( ¢->level2ZapTS[ i ]->backAttachment, target ); - CG_AttachToCent( ¢->level2ZapTS[ i ]->frontAttachment ); - CG_AttachToCent( ¢->level2ZapTS[ i ]->backAttachment ); - } - } -} - -/* -========================= -CG_AdjustPositionForMover - -Also called by client movement prediction code -========================= -*/ -void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ) -{ - centity_t *cent; - vec3_t oldOrigin, origin, deltaOrigin; - vec3_t oldAngles, angles, deltaAngles; - - if( moverNum <= 0 || moverNum >= ENTITYNUM_MAX_NORMAL ) - { - VectorCopy( in, out ); - return; - } - - cent = &cg_entities[ moverNum ]; - - if( cent->currentState.eType != ET_MOVER ) - { - VectorCopy( in, out ); - return; - } - - BG_EvaluateTrajectory( ¢->currentState.pos, fromTime, oldOrigin ); - BG_EvaluateTrajectory( ¢->currentState.apos, fromTime, oldAngles ); - - BG_EvaluateTrajectory( ¢->currentState.pos, toTime, origin ); - BG_EvaluateTrajectory( ¢->currentState.apos, toTime, angles ); - - VectorSubtract( origin, oldOrigin, deltaOrigin ); - VectorSubtract( angles, oldAngles, deltaAngles ); - - VectorAdd( in, deltaOrigin, out ); - - // FIXME: origin change when on a rotating object -} - - -/* -============================= -CG_InterpolateEntityPosition -============================= -*/ -static void CG_InterpolateEntityPosition( centity_t *cent ) -{ - vec3_t current, next; - float f; - - // it would be an internal error to find an entity that interpolates without - // a snapshot ahead of the current one - if( cg.nextSnap == NULL ) - CG_Error( "CG_InterpoateEntityPosition: cg.nextSnap == NULL" ); - - f = cg.frameInterpolation; - - // this will linearize a sine or parabolic curve, but it is important - // to not extrapolate player positions if more recent data is available - BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, current ); - BG_EvaluateTrajectory( ¢->nextState.pos, cg.nextSnap->serverTime, next ); - - cent->lerpOrigin[ 0 ] = current[ 0 ] + f * ( next[ 0 ] - current[ 0 ] ); - cent->lerpOrigin[ 1 ] = current[ 1 ] + f * ( next[ 1 ] - current[ 1 ] ); - cent->lerpOrigin[ 2 ] = current[ 2 ] + f * ( next[ 2 ] - current[ 2 ] ); - - BG_EvaluateTrajectory( ¢->currentState.apos, cg.snap->serverTime, current ); - BG_EvaluateTrajectory( ¢->nextState.apos, cg.nextSnap->serverTime, next ); - - cent->lerpAngles[ 0 ] = LerpAngle( current[ 0 ], next[ 0 ], f ); - cent->lerpAngles[ 1 ] = LerpAngle( current[ 1 ], next[ 1 ], f ); - cent->lerpAngles[ 2 ] = LerpAngle( current[ 2 ], next[ 2 ], f ); - -} - -/* -=============== -CG_CalcEntityLerpPositions - -=============== -*/ -static void CG_CalcEntityLerpPositions( centity_t *cent ) -{ - // if this player does not want to see extrapolated players - if( !cg_smoothClients.integer ) - { - // make sure the clients use TR_INTERPOLATE - if( cent->currentState.number < MAX_CLIENTS ) - { - cent->currentState.pos.trType = TR_INTERPOLATE; - cent->nextState.pos.trType = TR_INTERPOLATE; - } - } - - if( cent->interpolate && cent->currentState.pos.trType == TR_INTERPOLATE ) - { - CG_InterpolateEntityPosition( cent ); - return; - } - - // first see if we can interpolate between two snaps for - // linear extrapolated clients - if( cent->interpolate && cent->currentState.pos.trType == TR_LINEAR_STOP && - cent->currentState.number < MAX_CLIENTS ) - { - CG_InterpolateEntityPosition( cent ); - return; - } - - // just use the current frame and evaluate as best we can - BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin ); - BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles ); - - // adjust for riding a mover if it wasn't rolled into the predicted - // player state - if( cent != &cg.predictedPlayerEntity ) - { - CG_AdjustPositionForMover( cent->lerpOrigin, cent->currentState.groundEntityNum, - cg.snap->serverTime, cg.time, cent->lerpOrigin ); - } -} - - -/* -=============== -CG_CEntityPVSEnter - -=============== -*/ -static void CG_CEntityPVSEnter( centity_t *cent ) -{ - entityState_t *es = ¢->currentState; - - if( cg_debugPVS.integer ) - CG_Printf( "Entity %d entered PVS\n", cent->currentState.number ); - - switch( es->eType ) - { - case ET_MISSILE: - CG_LaunchMissile( cent ); - break; - } - - //clear any particle systems from previous uses of this centity_t - cent->muzzlePS = NULL; - cent->muzzlePsTrigger = qfalse; - cent->jetPackPS = NULL; - cent->jetPackState = JPS_OFF; - cent->buildablePS = NULL; - cent->entityPS = NULL; - cent->entityPSMissing = qfalse; - - //make sure that the buildable animations are in a consistent state - //when a buildable enters the PVS - cent->buildableAnim = cent->lerpFrame.animationNumber = BANIM_NONE; - cent->oldBuildableAnim = es->legsAnim; -} - - -/* -=============== -CG_CEntityPVSLeave - -=============== -*/ -static void CG_CEntityPVSLeave( centity_t *cent ) -{ - int i; - entityState_t *es = ¢->currentState; - - if( cg_debugPVS.integer ) - CG_Printf( "Entity %d left PVS\n", cent->currentState.number ); - - switch( es->eType ) - { - case ET_LEV2_ZAP_CHAIN: - for( i = 0; i <= 2; i++ ) - { - if( CG_IsTrailSystemValid( ¢->level2ZapTS[ i ] ) ) - CG_DestroyTrailSystem( ¢->level2ZapTS[ i ] ); - } - break; - } -} - - -/* -=============== -CG_AddCEntity - -=============== -*/ -static void CG_AddCEntity( centity_t *cent ) -{ - // event-only entities will have been dealt with already - if( cent->currentState.eType >= ET_EVENTS ) - return; - - // calculate the current origin - CG_CalcEntityLerpPositions( cent ); - - // add automatic effects - CG_EntityEffects( cent ); - - switch( cent->currentState.eType ) - { - default: - CG_Error( "Bad entity type: %i\n", cent->currentState.eType ); - break; - - case ET_INVISIBLE: - case ET_PUSH_TRIGGER: - case ET_TELEPORT_TRIGGER: - break; - - case ET_GENERAL: - CG_General( cent ); - break; - - case ET_CORPSE: - CG_Corpse( cent ); - break; - - case ET_PLAYER: - CG_Player( cent ); - break; - - case ET_BUILDABLE: - CG_Buildable( cent ); - break; - - case ET_MISSILE: - CG_Missile( cent ); - break; - - case ET_MOVER: - CG_Mover( cent ); - break; - - case ET_BEAM: - CG_Beam( cent ); - break; - - case ET_PORTAL: - CG_Portal( cent ); - break; - - case ET_SPEAKER: - CG_Speaker( cent ); - break; - - case ET_PARTICLE_SYSTEM: - CG_ParticleSystemEntity( cent ); - break; - - case ET_ANIMMAPOBJ: - CG_AnimMapObj( cent ); - break; - - case ET_MODELDOOR: - CG_ModelDoor( cent ); - break; - - case ET_LIGHTFLARE: - CG_LightFlare( cent ); - break; - - case ET_LEV2_ZAP_CHAIN: - CG_Lev2ZapChain( cent ); - break; - } -} - -/* -=============== -CG_AddPacketEntities - -=============== -*/ -void CG_AddPacketEntities( void ) -{ - int num; - centity_t *cent; - playerState_t *ps; - - // set cg.frameInterpolation - if( cg.nextSnap ) - { - int delta; - - delta = ( cg.nextSnap->serverTime - cg.snap->serverTime ); - - if( delta == 0 ) - cg.frameInterpolation = 0; - else - cg.frameInterpolation = (float)( cg.time - cg.snap->serverTime ) / delta; - } - else - { - cg.frameInterpolation = 0; // actually, it should never be used, because - // no entities should be marked as interpolating - } - - // the auto-rotating items will all have the same axis - cg.autoAngles[ 0 ] = 0; - cg.autoAngles[ 1 ] = ( cg.time & 2047 ) * 360 / 2048.0; - cg.autoAngles[ 2 ] = 0; - - cg.autoAnglesFast[ 0 ] = 0; - cg.autoAnglesFast[ 1 ] = ( cg.time & 1023 ) * 360 / 1024.0f; - cg.autoAnglesFast[ 2 ] = 0; - - AnglesToAxis( cg.autoAngles, cg.autoAxis ); - AnglesToAxis( cg.autoAnglesFast, cg.autoAxisFast ); - - // generate and add the entity from the playerstate - ps = &cg.predictedPlayerState; - BG_PlayerStateToEntityState( ps, &cg.predictedPlayerEntity.currentState, qfalse ); - cg.predictedPlayerEntity.valid = qtrue; - CG_AddCEntity( &cg.predictedPlayerEntity ); - - // lerp the non-predicted value for lightning gun origins - CG_CalcEntityLerpPositions( &cg_entities[ cg.snap->ps.clientNum ] ); - - // scanner - CG_UpdateEntityPositions( ); - - for( num = 0; num < MAX_GENTITIES; num++ ) - cg_entities[ num ].valid = qfalse; - - // add each entity sent over by the server - for( num = 0; num < cg.snap->numEntities; num++ ) - { - cent = &cg_entities[ cg.snap->entities[ num ].number ]; - cent->valid = qtrue; - } - - for( num = 0; num < MAX_GENTITIES; num++ ) - { - cent = &cg_entities[ num ]; - - if( cent->valid && !cent->oldValid ) - CG_CEntityPVSEnter( cent ); - else if( !cent->valid && cent->oldValid ) - CG_CEntityPVSLeave( cent ); - - cent->oldValid = cent->valid; - } - - // add each entity sent over by the server - for( num = 0; num < cg.snap->numEntities; num++ ) - { - cent = &cg_entities[ cg.snap->entities[ num ].number ]; - CG_AddCEntity( cent ); - } - - //make an attempt at drawing bounding boxes of selected entity types - if( cg_drawBBOX.integer ) - { - for( num = 0; num < cg.snap->numEntities; num++ ) - { - float x, zd, zu; - vec3_t mins, maxs; - entityState_t *es; - - cent = &cg_entities[ cg.snap->entities[ num ].number ]; - es = ¢->currentState; - - switch( es->eType ) - { - case ET_BUILDABLE: - case ET_MISSILE: - case ET_CORPSE: - x = ( es->solid & 255 ); - zd = ( ( es->solid >> 8 ) & 255 ); - zu = ( ( es->solid >> 16 ) & 255 ) - 32; - - mins[ 0 ] = mins[ 1 ] = -x; - maxs[ 0 ] = maxs[ 1 ] = x; - mins[ 2 ] = -zd; - maxs[ 2 ] = zu; - - CG_DrawBoundingBox( cent->lerpOrigin, mins, maxs ); - break; - - default: - break; - } - } - } -} - diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c deleted file mode 100644 index b89c8e7c..00000000 --- a/src/cgame/cg_event.c +++ /dev/null @@ -1,1011 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_event.c -- handle entity events at snapshot or playerstate transitions - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -/* -============= -CG_Obituary -============= -*/ -static void CG_Obituary( entityState_t *ent ) -{ - int mod; - int target, attacker; - char *message; - char *message2; - const char *targetInfo; - const char *attackerInfo; - char targetName[ 32 ]; - char attackerName[ 32 ]; - char className[ 64 ]; - gender_t gender; - clientInfo_t *ci; - - target = ent->otherEntityNum; - attacker = ent->otherEntityNum2; - mod = ent->eventParm; - - if( target < 0 || target >= MAX_CLIENTS ) - CG_Error( "CG_Obituary: target out of range" ); - - ci = &cgs.clientinfo[ target ]; - - if( attacker < 0 || attacker >= MAX_CLIENTS ) - { - attacker = ENTITYNUM_WORLD; - attackerInfo = NULL; - } - else - attackerInfo = CG_ConfigString( CS_PLAYERS + attacker ); - - targetInfo = CG_ConfigString( CS_PLAYERS + target ); - - if( !targetInfo ) - return; - - Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof( targetName ) - 2 ); - strcat( targetName, S_COLOR_WHITE ); - - message2 = ""; - - // check for single client messages - - switch( mod ) - { - case MOD_SUICIDE: - message = "suicides"; - break; - case MOD_FALLING: - message = "fell fowl to gravity"; - break; - case MOD_CRUSH: - message = "was squished"; - break; - case MOD_WATER: - message = "forgot to pack a snorkel"; - break; - case MOD_SLIME: - message = "melted"; - break; - case MOD_LAVA: - message = "does a back flip into the lava"; - break; - case MOD_TARGET_LASER: - message = "saw the light"; - break; - case MOD_TRIGGER_HURT: - message = "was in the wrong place"; - break; - case MOD_HSPAWN: - message = "should have ran further"; - break; - case MOD_ASPAWN: - message = "shouldn't have trod in the acid"; - break; - case MOD_MGTURRET: - message = "was gunned down by a turret"; - break; - case MOD_TESLAGEN: - message = "was zapped by a tesla generator"; - break; - case MOD_ATUBE: - message = "was melted by an acid tube"; - break; - case MOD_OVERMIND: - message = "got too close to the overmind"; - break; - case MOD_REACTOR: - message = "got too close to the reactor"; - break; - case MOD_SLOWBLOB: - message = "should have visited a medical station"; - break; - case MOD_SWARM: - message = "was hunted down by the swarm"; - break; - default: - message = NULL; - break; - } - - if( attacker == target ) - { - gender = ci->gender; - switch( mod ) - { - case MOD_FLAMER_SPLASH: - if( gender == GENDER_FEMALE ) - message = "toasted herself"; - else if( gender == GENDER_NEUTER ) - message = "toasted itself"; - else - message = "toasted himself"; - break; - - case MOD_LCANNON_SPLASH: - if( gender == GENDER_FEMALE ) - message = "irradiated herself"; - else if( gender == GENDER_NEUTER ) - message = "irradiated itself"; - else - message = "irradiated himself"; - break; - - case MOD_GRENADE: - if( gender == GENDER_FEMALE ) - message = "blew herself up"; - else if( gender == GENDER_NEUTER ) - message = "blew itself up"; - else - message = "blew himself up"; - break; - - default: - if( gender == GENDER_FEMALE ) - message = "killed herself"; - else if( gender == GENDER_NEUTER ) - message = "killed itself"; - else - message = "killed himself"; - break; - } - } - - if( message ) - { - CG_Printf( "%s %s.\n", targetName, message ); - return; - } - - // check for double client messages - if( !attackerInfo ) - { - attacker = ENTITYNUM_WORLD; - strcpy( attackerName, "noname" ); - } - else - { - Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof( attackerName ) - 2); - strcat( attackerName, S_COLOR_WHITE ); - // check for kill messages about the current clientNum - if( target == cg.snap->ps.clientNum ) - Q_strncpyz( cg.killerName, attackerName, sizeof( cg.killerName ) ); - } - - if( attacker != ENTITYNUM_WORLD ) - { - switch( mod ) - { - case MOD_PAINSAW: - message = "was sawn by"; - break; - case MOD_BLASTER: - message = "was blasted by"; - break; - case MOD_MACHINEGUN: - message = "was machinegunned by"; - break; - case MOD_CHAINGUN: - message = "was chaingunned by"; - break; - case MOD_SHOTGUN: - message = "was gunned down by"; - break; - case MOD_PRIFLE: - message = "was pulse rifled by"; - break; - case MOD_MDRIVER: - message = "was mass driven by"; - break; - case MOD_LASGUN: - message = "was lasgunned by"; - break; - case MOD_FLAMER: - message = "was grilled by"; - message2 = "'s flamer"; - break; - case MOD_FLAMER_SPLASH: - message = "was toasted by"; - message2 = "'s flamer"; - break; - case MOD_LCANNON: - message = "felt the full force of"; - message2 = "'s lucifer cannon"; - break; - case MOD_LCANNON_SPLASH: - message = "was caught in the fallout of"; - message2 = "'s lucifer cannon"; - break; - case MOD_GRENADE: - message = "couldn't escape"; - message2 = "'s grenade"; - break; - - case MOD_ABUILDER_CLAW: - message = "should leave"; - message2 = "'s buildings alone"; - break; - case MOD_LEVEL0_BITE: - message = "was bitten by"; - break; - case MOD_LEVEL1_CLAW: - message = "was swiped by"; - Com_sprintf( className, 64, "'s %s", - BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL1 ) ); - message2 = className; - break; - case MOD_LEVEL2_CLAW: - message = "was clawed by"; - Com_sprintf( className, 64, "'s %s", - BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL2 ) ); - message2 = className; - break; - case MOD_LEVEL2_ZAP: - message = "was zapped by"; - Com_sprintf( className, 64, "'s %s", - BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL2 ) ); - message2 = className; - break; - case MOD_LEVEL3_CLAW: - message = "was chomped by"; - Com_sprintf( className, 64, "'s %s", - BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL3 ) ); - message2 = className; - break; - case MOD_LEVEL3_POUNCE: - message = "was pounced upon by"; - Com_sprintf( className, 64, "'s %s", - BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL3 ) ); - message2 = className; - break; - case MOD_LEVEL3_BOUNCEBALL: - message = "was sniped by"; - Com_sprintf( className, 64, "'s %s", - BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL3 ) ); - message2 = className; - break; - case MOD_LEVEL4_CLAW: - message = "was mauled by"; - Com_sprintf( className, 64, "'s %s", - BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL4 ) ); - message2 = className; - break; - case MOD_LEVEL4_CHARGE: - message = "should have gotten out of the way of"; - Com_sprintf( className, 64, "'s %s", - BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL4 ) ); - message2 = className; - break; - - case MOD_POISON: - message = "should have used a medkit against"; - message2 = "'s poison"; - break; - case MOD_LEVEL1_PCLOUD: - message = "was gassed by"; - Com_sprintf( className, 64, "'s %s", - BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL1 ) ); - message2 = className; - break; - - - case MOD_TELEFRAG: - message = "tried to invade"; - message2 = "'s personal space"; - break; - default: - message = "was killed by"; - break; - } - - if( message ) - { - CG_Printf( "%s %s %s%s\n", - targetName, message, attackerName, message2 ); - return; - } - } - - // we don't know what it was - CG_Printf( "%s died.\n", targetName ); -} - -//========================================================================== - -/* -================ -CG_PainEvent - -Also called by playerstate transition -================ -*/ -void CG_PainEvent( centity_t *cent, int health ) -{ - char *snd; - - // don't do more than two pain sounds a second - if( cg.time - cent->pe.painTime < 500 ) - return; - - if( health < 25 ) - snd = "*pain25_1.wav"; - else if( health < 50 ) - snd = "*pain50_1.wav"; - else if( health < 75 ) - snd = "*pain75_1.wav"; - else - snd = "*pain100_1.wav"; - - trap_S_StartSound( NULL, cent->currentState.number, CHAN_VOICE, - CG_CustomSound( cent->currentState.number, snd ) ); - - // save pain time for programitic twitch animation - cent->pe.painTime = cg.time; - cent->pe.painDirection ^= 1; -} - -/* -============== -CG_EntityEvent - -An entity has an event value -also called by CG_CheckPlayerstateEvents -============== -*/ -#define DEBUGNAME(x) if(cg_debugEvents.integer){CG_Printf(x"\n");} -void CG_EntityEvent( centity_t *cent, vec3_t position ) -{ - entityState_t *es; - int event; - vec3_t dir; - const char *s; - int clientNum; - clientInfo_t *ci; - int steptime; - - if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) - steptime = 200; - else - steptime = BG_FindSteptimeForClass( cg.snap->ps.stats[ STAT_PCLASS ] ); - - es = ¢->currentState; - event = es->event & ~EV_EVENT_BITS; - - if( cg_debugEvents.integer ) - CG_Printf( "ent:%3i event:%3i ", es->number, event ); - - if( !event ) - { - DEBUGNAME("ZEROEVENT"); - return; - } - - clientNum = es->clientNum; - if( clientNum < 0 || clientNum >= MAX_CLIENTS ) - clientNum = 0; - - ci = &cgs.clientinfo[ clientNum ]; - - switch( event ) - { - // - // movement generated events - // - case EV_FOOTSTEP: - DEBUGNAME( "EV_FOOTSTEP" ); - if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE ) - { - if( ci->footsteps == FOOTSTEP_CUSTOM ) - trap_S_StartSound( NULL, es->number, CHAN_BODY, - ci->customFootsteps[ rand( ) & 3 ] ); - else - trap_S_StartSound( NULL, es->number, CHAN_BODY, - cgs.media.footsteps[ ci->footsteps ][ rand( ) & 3 ] ); - } - break; - - case EV_FOOTSTEP_METAL: - DEBUGNAME( "EV_FOOTSTEP_METAL" ); - if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE ) - { - if( ci->footsteps == FOOTSTEP_CUSTOM ) - trap_S_StartSound( NULL, es->number, CHAN_BODY, - ci->customMetalFootsteps[ rand( ) & 3 ] ); - else - trap_S_StartSound( NULL, es->number, CHAN_BODY, - cgs.media.footsteps[ FOOTSTEP_METAL ][ rand( ) & 3 ] ); - } - break; - - case EV_FOOTSTEP_SQUELCH: - DEBUGNAME( "EV_FOOTSTEP_SQUELCH" ); - if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE ) - { - trap_S_StartSound( NULL, es->number, CHAN_BODY, - cgs.media.footsteps[ FOOTSTEP_FLESH ][ rand( ) & 3 ] ); - } - break; - - case EV_FOOTSPLASH: - DEBUGNAME( "EV_FOOTSPLASH" ); - if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE ) - { - trap_S_StartSound( NULL, es->number, CHAN_BODY, - cgs.media.footsteps[ FOOTSTEP_SPLASH ][ rand( ) & 3 ] ); - } - break; - - case EV_FOOTWADE: - DEBUGNAME( "EV_FOOTWADE" ); - if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE ) - { - trap_S_StartSound( NULL, es->number, CHAN_BODY, - cgs.media.footsteps[ FOOTSTEP_SPLASH ][ rand( ) & 3 ] ); - } - break; - - case EV_SWIM: - DEBUGNAME( "EV_SWIM" ); - if( cg_footsteps.integer && ci->footsteps != FOOTSTEP_NONE ) - { - trap_S_StartSound( NULL, es->number, CHAN_BODY, - cgs.media.footsteps[ FOOTSTEP_SPLASH ][ rand( ) & 3 ] ); - } - break; - - - case EV_FALL_SHORT: - DEBUGNAME( "EV_FALL_SHORT" ); - trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.landSound ); - - if( clientNum == cg.predictedPlayerState.clientNum ) - { - // smooth landing z changes - cg.landChange = -8; - cg.landTime = cg.time; - } - break; - - case EV_FALL_MEDIUM: - DEBUGNAME( "EV_FALL_MEDIUM" ); - // use normal pain sound - trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*pain100_1.wav" ) ); - - if( clientNum == cg.predictedPlayerState.clientNum ) - { - // smooth landing z changes - cg.landChange = -16; - cg.landTime = cg.time; - } - break; - - case EV_FALL_FAR: - DEBUGNAME( "EV_FALL_FAR" ); - trap_S_StartSound (NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*fall1.wav" ) ); - cent->pe.painTime = cg.time; // don't play a pain sound right after this - - if( clientNum == cg.predictedPlayerState.clientNum ) - { - // smooth landing z changes - cg.landChange = -24; - cg.landTime = cg.time; - } - break; - - case EV_FALLING: - DEBUGNAME( "EV_FALLING" ); - trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*falling1.wav" ) ); - break; - - case EV_STEP_4: - case EV_STEP_8: - case EV_STEP_12: - case EV_STEP_16: // smooth out step up transitions - case EV_STEPDN_4: - case EV_STEPDN_8: - case EV_STEPDN_12: - case EV_STEPDN_16: // smooth out step down transitions - DEBUGNAME( "EV_STEP" ); - { - float oldStep; - int delta; - int step; - - if( clientNum != cg.predictedPlayerState.clientNum ) - break; - - // if we are interpolating, we don't need to smooth steps - if( cg.demoPlayback || ( cg.snap->ps.pm_flags & PMF_FOLLOW ) || - cg_nopredict.integer || cg_synchronousClients.integer ) - break; - - // check for stepping up before a previous step is completed - delta = cg.time - cg.stepTime; - - if( delta < steptime ) - oldStep = cg.stepChange * ( steptime - delta ) / steptime; - else - oldStep = 0; - - // add this amount - if( event >= EV_STEPDN_4 ) - { - step = 4 * ( event - EV_STEPDN_4 + 1 ); - cg.stepChange = oldStep - step; - } - else - { - step = 4 * ( event - EV_STEP_4 + 1 ); - cg.stepChange = oldStep + step; - } - - if( cg.stepChange > MAX_STEP_CHANGE ) - cg.stepChange = MAX_STEP_CHANGE; - else if( cg.stepChange < -MAX_STEP_CHANGE ) - cg.stepChange = -MAX_STEP_CHANGE; - - cg.stepTime = cg.time; - break; - } - - case EV_JUMP: - DEBUGNAME( "EV_JUMP" ); - trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*jump1.wav" ) ); - - if( BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_PCLASS ], SCA_WALLJUMPER ) ) - { - vec3_t surfNormal, refNormal = { 0.0f, 0.0f, 1.0f }; - vec3_t rotAxis; - - if( clientNum != cg.predictedPlayerState.clientNum ) - break; - - //set surfNormal - VectorCopy( cg.predictedPlayerState.grapplePoint, surfNormal ); - - //if we are moving from one surface to another smooth the transition - if( !VectorCompare( surfNormal, cg.lastNormal ) && surfNormal[ 2 ] != 1.0f ) - { - CrossProduct( refNormal, surfNormal, rotAxis ); - VectorNormalize( rotAxis ); - - //add the op - CG_addSmoothOp( rotAxis, 15.0f, 1.0f ); - } - - //copy the current normal to the lastNormal - VectorCopy( surfNormal, cg.lastNormal ); - } - - break; - - case EV_LEV1_GRAB: - DEBUGNAME( "EV_LEV1_GRAB" ); - trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL1Grab ); - break; - - case EV_LEV4_CHARGE_PREPARE: - DEBUGNAME( "EV_LEV4_CHARGE_PREPARE" ); - trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargePrepare ); - break; - - case EV_LEV4_CHARGE_START: - DEBUGNAME( "EV_LEV4_CHARGE_START" ); - //FIXME: stop cgs.media.alienL4ChargePrepare playing here - trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.media.alienL4ChargeStart ); - break; - - case EV_TAUNT: - DEBUGNAME( "EV_TAUNT" ); - trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, "*taunt.wav" ) ); - break; - - case EV_WATER_TOUCH: - DEBUGNAME( "EV_WATER_TOUCH" ); - trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrInSound ); - break; - - case EV_WATER_LEAVE: - DEBUGNAME( "EV_WATER_LEAVE" ); - trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrOutSound ); - break; - - case EV_WATER_UNDER: - DEBUGNAME( "EV_WATER_UNDER" ); - trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.watrUnSound ); - break; - - case EV_WATER_CLEAR: - DEBUGNAME( "EV_WATER_CLEAR" ); - trap_S_StartSound( NULL, es->number, CHAN_AUTO, CG_CustomSound( es->number, "*gasp.wav" ) ); - break; - - // - // weapon events - // - case EV_NOAMMO: - DEBUGNAME( "EV_NOAMMO" ); - { - } - break; - - case EV_CHANGE_WEAPON: - DEBUGNAME( "EV_CHANGE_WEAPON" ); - trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.selectSound ); - break; - - case EV_FIRE_WEAPON: - DEBUGNAME( "EV_FIRE_WEAPON" ); - CG_FireWeapon( cent, WPM_PRIMARY ); - break; - - case EV_FIRE_WEAPON2: - DEBUGNAME( "EV_FIRE_WEAPON2" ); - CG_FireWeapon( cent, WPM_SECONDARY ); - break; - - case EV_FIRE_WEAPON3: - DEBUGNAME( "EV_FIRE_WEAPON3" ); - CG_FireWeapon( cent, WPM_TERTIARY ); - break; - - //================================================================= - - // - // other events - // - case EV_PLAYER_TELEPORT_IN: - DEBUGNAME( "EV_PLAYER_TELEPORT_IN" ); - //deprecated - break; - - case EV_PLAYER_TELEPORT_OUT: - DEBUGNAME( "EV_PLAYER_TELEPORT_OUT" ); - CG_PlayerDisconnect( position ); - break; - - case EV_BUILD_CONSTRUCT: - DEBUGNAME( "EV_BUILD_CONSTRUCT" ); - //do something useful here - break; - - case EV_BUILD_DESTROY: - DEBUGNAME( "EV_BUILD_DESTROY" ); - //do something useful here - break; - - case EV_RPTUSE_SOUND: - DEBUGNAME( "EV_RPTUSE_SOUND" ); - trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.repeaterUseSound ); - break; - - case EV_GRENADE_BOUNCE: - DEBUGNAME( "EV_GRENADE_BOUNCE" ); - if( rand( ) & 1 ) - trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.hgrenb1aSound ); - else - trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.hgrenb2aSound ); - break; - - // - // missile impacts - // - case EV_MISSILE_HIT: - DEBUGNAME( "EV_MISSILE_HIT" ); - ByteToDir( es->eventParm, dir ); - CG_MissileHitPlayer( es->weapon, es->generic1, position, dir, es->otherEntityNum ); - break; - - case EV_MISSILE_MISS: - DEBUGNAME( "EV_MISSILE_MISS" ); - ByteToDir( es->eventParm, dir ); - CG_MissileHitWall( es->weapon, es->generic1, 0, position, dir, IMPACTSOUND_DEFAULT ); - break; - - case EV_MISSILE_MISS_METAL: - DEBUGNAME( "EV_MISSILE_MISS_METAL" ); - ByteToDir( es->eventParm, dir ); - CG_MissileHitWall( es->weapon, es->generic1, 0, position, dir, IMPACTSOUND_METAL ); - break; - - case EV_HUMAN_BUILDABLE_EXPLOSION: - DEBUGNAME( "EV_HUMAN_BUILDABLE_EXPLOSION" ); - ByteToDir( es->eventParm, dir ); - CG_HumanBuildableExplosion( position, dir ); - break; - - case EV_ALIEN_BUILDABLE_EXPLOSION: - DEBUGNAME( "EV_ALIEN_BUILDABLE_EXPLOSION" ); - ByteToDir( es->eventParm, dir ); - CG_AlienBuildableExplosion( position, dir ); - break; - - case EV_TESLATRAIL: - DEBUGNAME( "EV_TESLATRAIL" ); - cent->currentState.weapon = WP_TESLAGEN; - { - centity_t *source = &cg_entities[ es->generic1 ]; - centity_t *target = &cg_entities[ es->clientNum ]; - vec3_t sourceOffset = { 0.0f, 0.0f, 28.0f }; - - if( !CG_IsTrailSystemValid( &source->muzzleTS ) ) - { - source->muzzleTS = CG_SpawnNewTrailSystem( cgs.media.teslaZapTS ); - - if( CG_IsTrailSystemValid( &source->muzzleTS ) ) - { - CG_SetAttachmentCent( &source->muzzleTS->frontAttachment, source ); - CG_SetAttachmentCent( &source->muzzleTS->backAttachment, target ); - CG_AttachToCent( &source->muzzleTS->frontAttachment ); - CG_AttachToCent( &source->muzzleTS->backAttachment ); - CG_SetAttachmentOffset( &source->muzzleTS->frontAttachment, sourceOffset ); - - source->muzzleTSDeathTime = cg.time + cg_teslaTrailTime.integer; - } - } - } - break; - - case EV_BULLET_HIT_WALL: - DEBUGNAME( "EV_BULLET_HIT_WALL" ); - ByteToDir( es->eventParm, dir ); - CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qfalse, ENTITYNUM_WORLD ); - break; - - case EV_BULLET_HIT_FLESH: - DEBUGNAME( "EV_BULLET_HIT_FLESH" ); - CG_Bullet( es->pos.trBase, es->otherEntityNum, dir, qtrue, es->eventParm ); - break; - - case EV_SHOTGUN: - DEBUGNAME( "EV_SHOTGUN" ); - CG_ShotgunFire( es ); - break; - - case EV_GENERAL_SOUND: - DEBUGNAME( "EV_GENERAL_SOUND" ); - if( cgs.gameSounds[ es->eventParm ] ) - trap_S_StartSound( NULL, es->number, CHAN_VOICE, cgs.gameSounds[ es->eventParm ] ); - else - { - s = CG_ConfigString( CS_SOUNDS + es->eventParm ); - trap_S_StartSound( NULL, es->number, CHAN_VOICE, CG_CustomSound( es->number, s ) ); - } - break; - - case EV_GLOBAL_SOUND: // play from the player's head so it never diminishes - DEBUGNAME( "EV_GLOBAL_SOUND" ); - if( cgs.gameSounds[ es->eventParm ] ) - trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, cgs.gameSounds[ es->eventParm ] ); - else - { - s = CG_ConfigString( CS_SOUNDS + es->eventParm ); - trap_S_StartSound( NULL, cg.snap->ps.clientNum, CHAN_AUTO, CG_CustomSound( es->number, s ) ); - } - break; - - case EV_PAIN: - // local player sounds are triggered in CG_CheckLocalSounds, - // so ignore events on the player - DEBUGNAME( "EV_PAIN" ); - if( cent->currentState.number != cg.snap->ps.clientNum ) - CG_PainEvent( cent, es->eventParm ); - break; - - case EV_DEATH1: - case EV_DEATH2: - case EV_DEATH3: - DEBUGNAME( "EV_DEATHx" ); - trap_S_StartSound( NULL, es->number, CHAN_VOICE, - CG_CustomSound( es->number, va( "*death%i.wav", event - EV_DEATH1 + 1 ) ) ); - break; - - case EV_OBITUARY: - DEBUGNAME( "EV_OBITUARY" ); - CG_Obituary( es ); - break; - - case EV_GIB_PLAYER: - DEBUGNAME( "EV_GIB_PLAYER" ); - // no gibbing - break; - - case EV_STOPLOOPINGSOUND: - DEBUGNAME( "EV_STOPLOOPINGSOUND" ); - trap_S_StopLoopingSound( es->number ); - es->loopSound = 0; - break; - - case EV_DEBUG_LINE: - DEBUGNAME( "EV_DEBUG_LINE" ); - CG_Beam( cent ); - break; - - case EV_BUILD_DELAY: - DEBUGNAME( "EV_BUILD_DELAY" ); - if( clientNum == cg.predictedPlayerState.clientNum ) - { - trap_S_StartLocalSound( cgs.media.buildableRepairedSound, CHAN_LOCAL_SOUND ); - cg.lastBuildAttempt = cg.time; - } - break; - - case EV_BUILD_REPAIR: - DEBUGNAME( "EV_BUILD_REPAIR" ); - trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.buildableRepairSound ); - break; - - case EV_BUILD_REPAIRED: - DEBUGNAME( "EV_BUILD_REPAIRED" ); - trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.buildableRepairedSound ); - break; - - case EV_OVERMIND_ATTACK: - DEBUGNAME( "EV_OVERMIND_ATTACK" ); - if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - trap_S_StartLocalSound( cgs.media.alienOvermindAttack, CHAN_ANNOUNCER ); - CG_CenterPrint( "The Overmind is under attack!", 200, GIANTCHAR_WIDTH * 4 ); - } - break; - - case EV_OVERMIND_DYING: - DEBUGNAME( "EV_OVERMIND_DYING" ); - if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - trap_S_StartLocalSound( cgs.media.alienOvermindDying, CHAN_ANNOUNCER ); - CG_CenterPrint( "The Overmind is dying!", 200, GIANTCHAR_WIDTH * 4 ); - } - break; - - case EV_DCC_ATTACK: - DEBUGNAME( "EV_DCC_ATTACK" ); - if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - //trap_S_StartLocalSound( cgs.media.humanDCCAttack, CHAN_ANNOUNCER ); - CG_CenterPrint( "Our base is under attack!", 200, GIANTCHAR_WIDTH * 4 ); - } - break; - - case EV_OVERMIND_SPAWNS: - DEBUGNAME( "EV_OVERMIND_SPAWNS" ); - if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - trap_S_StartLocalSound( cgs.media.alienOvermindSpawns, CHAN_ANNOUNCER ); - CG_CenterPrint( "The Overmind needs spawns!", 200, GIANTCHAR_WIDTH * 4 ); - } - break; - - case EV_ALIEN_EVOLVE: - DEBUGNAME( "EV_ALIEN_EVOLVE" ); - trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.alienEvolveSound ); - { - particleSystem_t *ps = CG_SpawnNewParticleSystem( cgs.media.alienEvolvePS ); - - if( CG_IsParticleSystemValid( &ps ) ) - { - CG_SetAttachmentCent( &ps->attachment, cent ); - CG_AttachToCent( &ps->attachment ); - } - } - - if( es->number == cg.clientNum ) - { - CG_ResetPainBlend( ); - cg.spawnTime = cg.time; - } - break; - - case EV_ALIEN_EVOLVE_FAILED: - DEBUGNAME( "EV_ALIEN_EVOLVE_FAILED" ); - if( clientNum == cg.predictedPlayerState.clientNum ) - { - //FIXME: change to "negative" sound - trap_S_StartLocalSound( cgs.media.buildableRepairedSound, CHAN_LOCAL_SOUND ); - cg.lastEvolveAttempt = cg.time; - } - break; - - case EV_ALIEN_ACIDTUBE: - DEBUGNAME( "EV_ALIEN_ACIDTUBE" ); - { - particleSystem_t *ps = CG_SpawnNewParticleSystem( cgs.media.alienAcidTubePS ); - - if( CG_IsParticleSystemValid( &ps ) ) - { - CG_SetAttachmentCent( &ps->attachment, cent ); - ByteToDir( es->eventParm, dir ); - CG_SetParticleSystemNormal( ps, dir ); - CG_AttachToCent( &ps->attachment ); - } - } - break; - - case EV_MEDKIT_USED: - DEBUGNAME( "EV_MEDKIT_USED" ); - trap_S_StartSound( NULL, es->number, CHAN_AUTO, cgs.media.medkitUseSound ); - break; - - case EV_PLAYER_RESPAWN: - DEBUGNAME( "EV_PLAYER_RESPAWN" ); - if( es->number == cg.clientNum ) - cg.spawnTime = cg.time; - break; - - default: - DEBUGNAME( "UNKNOWN" ); - CG_Error( "Unknown event: %i", event ); - break; - } -} - - -/* -============== -CG_CheckEvents - -============== -*/ -void CG_CheckEvents( centity_t *cent ) -{ - entity_event_t event; - entity_event_t oldEvent = EV_NONE; - - // check for event-only entities - if( cent->currentState.eType > ET_EVENTS ) - { - event = cent->currentState.eType - ET_EVENTS; - - if( cent->previousEvent ) - return; // already fired - - cent->previousEvent = 1; - - cent->currentState.event = cent->currentState.eType - ET_EVENTS; - - // Move the pointer to the entity that the - // event was originally attached to - if( cent->currentState.eFlags & EF_PLAYER_EVENT ) - { - cent = &cg_entities[ cent->currentState.otherEntityNum ]; - oldEvent = cent->currentState.event; - cent->currentState.event = event; - } - } - else - { - // check for events riding with another entity - if( cent->currentState.event == cent->previousEvent ) - return; - - cent->previousEvent = cent->currentState.event; - if( ( cent->currentState.event & ~EV_EVENT_BITS ) == 0 ) - return; - } - - // calculate the position at exactly the frame time - BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, cent->lerpOrigin ); - CG_SetEntitySoundPosition( cent ); - - CG_EntityEvent( cent, cent->lerpOrigin ); - - // If this was a reattached spilled event, restore the original event - if( oldEvent != EV_NONE ) - cent->currentState.event = oldEvent; -} - diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h deleted file mode 100644 index 88df61ba..00000000 --- a/src/cgame/cg_local.h +++ /dev/null @@ -1,2003 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "../game/q_shared.h" -#include "tr_types.h" -#include "../game/bg_public.h" -#include "cg_public.h" -#include "../ui/ui_shared.h" - -// The entire cgame module is unloaded and reloaded on each level change, -// so there is NO persistant data between levels on the client side. -// If you absolutely need something stored, it can either be kept -// by the server in the server stored userinfos, or stashed in a cvar. - -#define CG_FONT_THRESHOLD 0.1 - -#define POWERUP_BLINKS 5 - -#define POWERUP_BLINK_TIME 1000 -#define FADE_TIME 200 -#define PULSE_TIME 200 -#define DAMAGE_DEFLECT_TIME 100 -#define DAMAGE_RETURN_TIME 400 -#define DAMAGE_TIME 500 -#define LAND_DEFLECT_TIME 150 -#define LAND_RETURN_TIME 300 -#define DUCK_TIME 100 -#define PAIN_TWITCH_TIME 200 -#define WEAPON_SELECT_TIME 1400 -#define ITEM_SCALEUP_TIME 1000 -#define ZOOM_TIME 150 -#define ITEM_BLOB_TIME 200 -#define MUZZLE_FLASH_TIME 20 -#define SINK_TIME 1000 // time for fragments to sink into ground before going away -#define ATTACKER_HEAD_TIME 10000 -#define REWARD_TIME 3000 - -#define PULSE_SCALE 1.5 // amount to scale up the icons when activating - -#define MAX_STEP_CHANGE 32 - -#define MAX_VERTS_ON_POLY 10 -#define MAX_MARK_POLYS 256 - -#define STAT_MINUS 10 // num frame for '-' stats digit - -#define ICON_SIZE 48 -#define CHAR_WIDTH 32 -#define CHAR_HEIGHT 48 -#define TEXT_ICON_SPACE 4 - -#define TEAMCHAT_WIDTH 80 -#define TEAMCHAT_HEIGHT 8 - -// very large characters -#define GIANT_WIDTH 32 -#define GIANT_HEIGHT 48 - -#define NUM_CROSSHAIRS 10 - -#define TEAM_OVERLAY_MAXNAME_WIDTH 12 -#define TEAM_OVERLAY_MAXLOCATION_WIDTH 16 - -#define DEFAULT_MODEL "sarge" -#define DEFAULT_TEAM_MODEL "sarge" -#define DEFAULT_TEAM_HEAD "sarge" - -#define DEFAULT_REDTEAM_NAME "Stroggs" -#define DEFAULT_BLUETEAM_NAME "Pagans" - -typedef enum -{ - FOOTSTEP_NORMAL, - FOOTSTEP_BOOT, - FOOTSTEP_FLESH, - FOOTSTEP_MECH, - FOOTSTEP_ENERGY, - FOOTSTEP_METAL, - FOOTSTEP_SPLASH, - FOOTSTEP_CUSTOM, - FOOTSTEP_NONE, - - FOOTSTEP_TOTAL -} footstep_t; - -typedef enum -{ - IMPACTSOUND_DEFAULT, - IMPACTSOUND_METAL, - IMPACTSOUND_FLESH -} impactSound_t; - -typedef enum -{ - JPS_OFF, - JPS_DESCENDING, - JPS_HOVERING, - JPS_ASCENDING -} jetPackState_t; - -//====================================================================== - -// when changing animation, set animationTime to frameTime + lerping time -// The current lerp will finish out, then it will lerp to the new animation -typedef struct -{ - int oldFrame; - int oldFrameTime; // time when ->oldFrame was exactly on - - int frame; - int frameTime; // time when ->frame will be exactly on - - float backlerp; - - float yawAngle; - qboolean yawing; - float pitchAngle; - qboolean pitching; - - int animationNumber; // may include ANIM_TOGGLEBIT - animation_t *animation; - int animationTime; // time when the first frame of the animation will be exact -} lerpFrame_t; - -//====================================================================== - -//attachment system -typedef enum -{ - AT_STATIC, - AT_TAG, - AT_CENT, - AT_PARTICLE -} attachmentType_t; - -//forward declaration for particle_t -struct particle_s; - -typedef struct attachment_s -{ - attachmentType_t type; - qboolean attached; - - qboolean staticValid; - qboolean tagValid; - qboolean centValid; - qboolean particleValid; - - qboolean hasOffset; - vec3_t offset; - - vec3_t lastValidAttachmentPoint; - - //AT_STATIC - vec3_t origin; - - //AT_TAG - refEntity_t re; //FIXME: should be pointers? - refEntity_t parent; // - qhandle_t model; - char tagName[ MAX_STRING_CHARS ]; - - //AT_CENT - int centNum; - - //AT_PARTICLE - struct particle_s *particle; -} attachment_t; - -//====================================================================== - -//particle system stuff -#define MAX_PS_SHADER_FRAMES 32 -#define MAX_PS_MODELS 8 -#define MAX_EJECTORS_PER_SYSTEM 4 -#define MAX_PARTICLES_PER_EJECTOR 4 - -#define MAX_BASEPARTICLE_SYSTEMS 192 -#define MAX_BASEPARTICLE_EJECTORS MAX_BASEPARTICLE_SYSTEMS*MAX_EJECTORS_PER_SYSTEM -#define MAX_BASEPARTICLES MAX_BASEPARTICLE_EJECTORS*MAX_PARTICLES_PER_EJECTOR - -#define MAX_PARTICLE_SYSTEMS 48 -#define MAX_PARTICLE_EJECTORS MAX_PARTICLE_SYSTEMS*MAX_EJECTORS_PER_SYSTEM -#define MAX_PARTICLES MAX_PARTICLE_EJECTORS*5 - -#define PARTICLES_INFINITE -1 -#define PARTICLES_SAME_AS_INITIAL -2 - -//COMPILE TIME STRUCTURES -typedef enum -{ - PMT_STATIC, - PMT_STATIC_TRANSFORM, - PMT_TAG, - PMT_CENT_ANGLES, - PMT_NORMAL -} pMoveType_t; - -typedef enum -{ - PMD_LINEAR, - PMD_POINT -} pDirType_t; - -typedef struct pMoveValues_u -{ - pDirType_t dirType; - - //PMD_LINEAR - vec3_t dir; - float dirRandAngle; - - //PMD_POINT - vec3_t point; - float pointRandAngle; - - float mag; - float magRandFrac; - - float parentVelFrac; - float parentVelFracRandFrac; -} pMoveValues_t; - -typedef struct pLerpValues_s -{ - int delay; - float delayRandFrac; - - float initial; - float initialRandFrac; - - float final; - float finalRandFrac; - - float randFrac; -} pLerpValues_t; - -//particle template -typedef struct baseParticle_s -{ - vec3_t displacement; - float randDisplacement; - float normalDisplacement; - - pMoveType_t velMoveType; - pMoveValues_t velMoveValues; - - pMoveType_t accMoveType; - pMoveValues_t accMoveValues; - - int lifeTime; - float lifeTimeRandFrac; - - float bounceFrac; - float bounceFracRandFrac; - qboolean bounceCull; - - char bounceMarkName[ MAX_QPATH ]; - qhandle_t bounceMark; - float bounceMarkRadius; - float bounceMarkRadiusRandFrac; - float bounceMarkCount; - float bounceMarkCountRandFrac; - - char bounceSoundName[ MAX_QPATH ]; - qhandle_t bounceSound; - float bounceSoundCount; - float bounceSoundCountRandFrac; - - pLerpValues_t radius; - pLerpValues_t alpha; - pLerpValues_t rotation; - - qboolean dynamicLight; - pLerpValues_t dLightRadius; - byte dLightColor[ 3 ]; - - int colorDelay; - float colorDelayRandFrac; - byte initialColor[ 3 ]; - byte finalColor[ 3 ]; - - char childSystemName[ MAX_QPATH ]; - qhandle_t childSystemHandle; - - char onDeathSystemName[ MAX_QPATH ]; - qhandle_t onDeathSystemHandle; - - char childTrailSystemName[ MAX_QPATH ]; - qhandle_t childTrailSystemHandle; - - //particle invariant stuff - char shaderNames[ MAX_PS_SHADER_FRAMES ][ MAX_QPATH ]; - qhandle_t shaders[ MAX_PS_SHADER_FRAMES ]; - int numFrames; - float framerate; - - char modelNames[ MAX_PS_MODELS ][ MAX_QPATH ]; - qhandle_t models[ MAX_PS_MODELS ]; - int numModels; - animation_t modelAnimation; - - qboolean overdrawProtection; - qboolean realLight; - qboolean cullOnStartSolid; -} baseParticle_t; - - -//ejector template -typedef struct baseParticleEjector_s -{ - baseParticle_t *particles[ MAX_PARTICLES_PER_EJECTOR ]; - int numParticles; - - pLerpValues_t eject; //zero period indicates creation of all particles at once - - int totalParticles; //can be infinite - float totalParticlesRandFrac; -} baseParticleEjector_t; - - -//particle system template -typedef struct baseParticleSystem_s -{ - char name[ MAX_QPATH ]; - baseParticleEjector_t *ejectors[ MAX_EJECTORS_PER_SYSTEM ]; - int numEjectors; - - qboolean thirdPersonOnly; - qboolean registered; //whether or not the assets for this particle have been loaded -} baseParticleSystem_t; - - -//RUN TIME STRUCTURES -typedef struct particleSystem_s -{ - baseParticleSystem_t *class; - - attachment_t attachment; - - qboolean valid; - qboolean lazyRemove; //mark this system for later removal - - //for PMT_NORMAL - qboolean normalValid; - vec3_t normal; -} particleSystem_t; - - -typedef struct particleEjector_s -{ - baseParticleEjector_t *class; - particleSystem_t *parent; - - pLerpValues_t ejectPeriod; - - int count; - int totalParticles; - - int nextEjectionTime; - - qboolean valid; -} particleEjector_t; - - -//used for actual particle evaluation -typedef struct particle_s -{ - baseParticle_t *class; - particleEjector_t *parent; - - int birthTime; - int lifeTime; - - float bounceMarkRadius; - int bounceMarkCount; - int bounceSoundCount; - qboolean atRest; - - vec3_t origin; - vec3_t velocity; - - pMoveType_t accMoveType; - pMoveValues_t accMoveValues; - - int lastEvalTime; - - int nextChildTime; - - pLerpValues_t radius; - pLerpValues_t alpha; - pLerpValues_t rotation; - - pLerpValues_t dLightRadius; - - int colorDelay; - - qhandle_t model; - lerpFrame_t lf; - vec3_t lastAxis[ 3 ]; - - qboolean valid; - int frameWhenInvalidated; - - int sortKey; -} particle_t; - -//====================================================================== - -//trail system stuff -#define MAX_BEAMS_PER_SYSTEM 4 - -#define MAX_BASETRAIL_SYSTEMS 64 -#define MAX_BASETRAIL_BEAMS MAX_BASETRAIL_SYSTEMS*MAX_BEAMS_PER_SYSTEM - -#define MAX_TRAIL_SYSTEMS 32 -#define MAX_TRAIL_BEAMS MAX_TRAIL_SYSTEMS*MAX_BEAMS_PER_SYSTEM -#define MAX_TRAIL_BEAM_NODES 128 - -#define MAX_TRAIL_BEAM_JITTERS 4 - -typedef enum -{ - TBTT_STRETCH, - TBTT_REPEAT -} trailBeamTextureType_t; - -typedef struct baseTrailJitter_s -{ - float magnitude; - int period; -} baseTrailJitter_t; - -//beam template -typedef struct baseTrailBeam_s -{ - int numSegments; - float frontWidth; - float backWidth; - float frontAlpha; - float backAlpha; - byte frontColor[ 3 ]; - byte backColor[ 3 ]; - - // the time it takes for a segment to vanish (single attached only) - int segmentTime; - - // the time it takes for a beam to fade out (double attached only) - int fadeOutTime; - - char shaderName[ MAX_QPATH ]; - qhandle_t shader; - - trailBeamTextureType_t textureType; - - //TBTT_STRETCH - float frontTextureCoord; - float backTextureCoord; - - //TBTT_REPEAT - float repeatLength; - qboolean clampToBack; - - qboolean realLight; - - int numJitters; - baseTrailJitter_t jitters[ MAX_TRAIL_BEAM_JITTERS ]; - qboolean jitterAttachments; -} baseTrailBeam_t; - - -//trail system template -typedef struct baseTrailSystem_s -{ - char name[ MAX_QPATH ]; - baseTrailBeam_t *beams[ MAX_BEAMS_PER_SYSTEM ]; - int numBeams; - - qboolean thirdPersonOnly; - qboolean registered; //whether or not the assets for this trail have been loaded -} baseTrailSystem_t; - -typedef struct trailSystem_s -{ - baseTrailSystem_t *class; - - attachment_t frontAttachment; - attachment_t backAttachment; - - int destroyTime; - qboolean valid; -} trailSystem_t; - -typedef struct trailBeamNode_s -{ - vec3_t refPosition; - vec3_t position; - - int timeLeft; - - float textureCoord; - float halfWidth; - byte alpha; - byte color[ 3 ]; - - vec2_t jitters[ MAX_TRAIL_BEAM_JITTERS ]; - - struct trailBeamNode_s *prev; - struct trailBeamNode_s *next; - - qboolean used; -} trailBeamNode_t; - -typedef struct trailBeam_s -{ - baseTrailBeam_t *class; - trailSystem_t *parent; - - trailBeamNode_t nodePool[ MAX_TRAIL_BEAM_NODES ]; - trailBeamNode_t *nodes; - - int lastEvalTime; - - qboolean valid; - - int nextJitterTimes[ MAX_TRAIL_BEAM_JITTERS ]; -} trailBeam_t; - -//====================================================================== - -// player entities need to track more information -// than any other type of entity. - -// note that not every player entity is a client entity, -// because corpses after respawn are outside the normal -// client numbering range - -//TA: smoothing of view and model for WW transitions -#define MAXSMOOTHS 32 - -typedef struct -{ - float time; - float timeMod; - - vec3_t rotAxis; - float rotAngle; -} smooth_t; - - -typedef struct -{ - lerpFrame_t legs, torso, flag, nonseg; - int painTime; - int painDirection; // flip from 0 to 1 - - // machinegun spinning - float barrelAngle; - int barrelTime; - qboolean barrelSpinning; - - vec3_t lastNormal; - vec3_t lastAxis[ 3 ]; - smooth_t sList[ MAXSMOOTHS ]; -} playerEntity_t; - -typedef struct lightFlareStatus_s -{ - float lastSrcRadius; //caching of likely flare source radius - float lastRadius; //caching of likely flare radius - float lastRatio; //caching of likely flare ratio - int lastTime; //last time flare was visible/occluded - qboolean status; //flare is visble? -} lightFlareStatus_t; - -//================================================= - -// centity_t have a direct corespondence with gentity_t in the game, but -// only the entityState_t is directly communicated to the cgame -typedef struct centity_s -{ - entityState_t currentState; // from cg.frame - entityState_t nextState; // from cg.nextFrame, if available - qboolean interpolate; // true if next is valid to interpolate to - qboolean currentValid; // true if cg.frame holds this entity - - int muzzleFlashTime; // move to playerEntity? - int muzzleFlashTime2; // move to playerEntity? - int muzzleFlashTime3; // move to playerEntity? - int previousEvent; - int teleportFlag; - - int trailTime; // so missile trails can handle dropped initial packets - int dustTrailTime; - int miscTime; - int snapShotTime; // last time this entity was found in a snapshot - - playerEntity_t pe; - - int errorTime; // decay the error from this time - vec3_t errorOrigin; - vec3_t errorAngles; - - qboolean extrapolated; // false if origin / angles is an interpolation - vec3_t rawOrigin; - vec3_t rawAngles; - - vec3_t beamEnd; - - // exact interpolated position of entity on this frame - vec3_t lerpOrigin; - vec3_t lerpAngles; - - lerpFrame_t lerpFrame; - - //TA: - buildableAnimNumber_t buildableAnim; //persistant anim number - buildableAnimNumber_t oldBuildableAnim; //to detect when new anims are set - particleSystem_t *buildablePS; - float lastBuildableHealthScale; - int lastBuildableDamageSoundTime; - - lightFlareStatus_t lfs; - - qboolean doorState; - - particleSystem_t *muzzlePS; - qboolean muzzlePsTrigger; - - particleSystem_t *jetPackPS; - jetPackState_t jetPackState; - - particleSystem_t *entityPS; - qboolean entityPSMissing; - - trailSystem_t *level2ZapTS[ 3 ]; - - trailSystem_t *muzzleTS; //used for the tesla and reactor - int muzzleTSDeathTime; - - qboolean valid; - qboolean oldValid; -} centity_t; - - -//====================================================================== - -typedef struct markPoly_s -{ - struct markPoly_s *prevMark, *nextMark; - int time; - qhandle_t markShader; - qboolean alphaFade; // fade alpha instead of rgb - float color[ 4 ]; - poly_t poly; - polyVert_t verts[ MAX_VERTS_ON_POLY ]; -} markPoly_t; - -//====================================================================== - - -typedef struct -{ - int client; - int score; - int ping; - int time; - int team; - weapon_t weapon; - upgrade_t upgrade; -} score_t; - -// each client has an associated clientInfo_t -// that contains media references necessary to present the -// client model and other color coded effects -// this is regenerated each time a client's configstring changes, -// usually as a result of a userinfo (name, model, etc) change -#define MAX_CUSTOM_SOUNDS 32 -typedef struct -{ - qboolean infoValid; - - char name[ MAX_QPATH ]; - pTeam_t team; - - int botSkill; // 0 = not bot, 1-5 = bot - - vec3_t color1; - vec3_t color2; - - int score; // updated by score servercmds - int location; // location index for team mode - int health; // you only get this info about your teammates - int armor; - int curWeapon; - - int handicap; - int wins, losses; // in tourney mode - - int teamTask; // task in teamplay (offence/defence) - qboolean teamLeader; // true when this is a team leader - - int powerups; // so can display quad/flag status - - int medkitUsageTime; - int invulnerabilityStartTime; - int invulnerabilityStopTime; - - int breathPuffTime; - - // when clientinfo is changed, the loading of models/skins/sounds - // can be deferred until you are dead, to prevent hitches in - // gameplay - char modelName[ MAX_QPATH ]; - char skinName[ MAX_QPATH ]; - char headModelName[ MAX_QPATH ]; - char headSkinName[ MAX_QPATH ]; - char redTeam[ MAX_TEAMNAME ]; - char blueTeam[ MAX_TEAMNAME ]; - - qboolean newAnims; // true if using the new mission pack animations - qboolean fixedlegs; // true if legs yaw is always the same as torso yaw - qboolean fixedtorso; // true if torso never changes yaw - qboolean nonsegmented; // true if model is Q2 style nonsegmented - - vec3_t headOffset; // move head in icon views - footstep_t footsteps; - gender_t gender; // from model - - qhandle_t legsModel; - qhandle_t legsSkin; - - qhandle_t torsoModel; - qhandle_t torsoSkin; - - qhandle_t headModel; - qhandle_t headSkin; - - qhandle_t nonSegModel; //non-segmented model system - qhandle_t nonSegSkin; //non-segmented model system - - qhandle_t modelIcon; - - animation_t animations[ MAX_PLAYER_TOTALANIMATIONS ]; - - sfxHandle_t sounds[ MAX_CUSTOM_SOUNDS ]; - - sfxHandle_t customFootsteps[ 4 ]; - sfxHandle_t customMetalFootsteps[ 4 ]; -} clientInfo_t; - - -typedef struct weaponInfoMode_s -{ - float flashDlight; - vec3_t flashDlightColor; - sfxHandle_t flashSound[ 4 ]; // fast firing weapons randomly choose - qboolean continuousFlash; - - qhandle_t missileModel; - sfxHandle_t missileSound; - float missileDlight; - vec3_t missileDlightColor; - int missileRenderfx; - qboolean usesSpriteMissle; - qhandle_t missileSprite; - int missileSpriteSize; - qhandle_t missileParticleSystem; - qhandle_t missileTrailSystem; - qboolean missileRotates; - qboolean missileAnimates; - int missileAnimStartFrame; - int missileAnimNumFrames; - int missileAnimFrameRate; - int missileAnimLooping; - - sfxHandle_t firingSound; - qboolean loopFireSound; - - qhandle_t muzzleParticleSystem; - - qboolean alwaysImpact; - qhandle_t impactParticleSystem; - qhandle_t impactMark; - qhandle_t impactMarkSize; - sfxHandle_t impactSound[ 4 ]; //random impact sound - sfxHandle_t impactFleshSound[ 4 ]; //random impact sound -} weaponInfoMode_t; - -// each WP_* weapon enum has an associated weaponInfo_t -// that contains media references necessary to present the -// weapon and its effects -typedef struct weaponInfo_s -{ - qboolean registered; - char *humanName; - - qhandle_t handsModel; // the hands don't actually draw, they just position the weapon - qhandle_t weaponModel; - qhandle_t barrelModel; - qhandle_t flashModel; - - vec3_t weaponMidpoint; // so it will rotate centered instead of by tag - - qhandle_t weaponIcon; - qhandle_t ammoIcon; - - qhandle_t crossHair; - int crossHairSize; - - sfxHandle_t readySound; - - qboolean disableIn3rdPerson; - - weaponInfoMode_t wim[ WPM_NUM_WEAPONMODES ]; -} weaponInfo_t; - -typedef struct upgradeInfo_s -{ - qboolean registered; - char *humanName; - - qhandle_t upgradeIcon; -} upgradeInfo_t; - -typedef struct -{ - qboolean looped; - qboolean enabled; - - sfxHandle_t sound; -} sound_t; - -typedef struct -{ - qhandle_t models[ MAX_BUILDABLE_MODELS ]; - animation_t animations[ MAX_BUILDABLE_ANIMATIONS ]; - - //same number of sounds as animations - sound_t sounds[ MAX_BUILDABLE_ANIMATIONS ]; -} buildableInfo_t; - -#define MAX_REWARDSTACK 10 -#define MAX_SOUNDBUFFER 20 - -//====================================================================== - -//TA: -typedef struct -{ - vec3_t alienBuildablePos[ MAX_GENTITIES ]; - int alienBuildableTimes[ MAX_GENTITIES ]; - int numAlienBuildables; - - vec3_t humanBuildablePos[ MAX_GENTITIES ]; - int numHumanBuildables; - - vec3_t alienClientPos[ MAX_CLIENTS ]; - int numAlienClients; - - vec3_t humanClientPos[ MAX_CLIENTS ]; - int numHumanClients; - - int lastUpdateTime; - vec3_t origin; - vec3_t vangles; -} entityPos_t; - -typedef struct -{ - int time; - int length; -} consoleLine_t; - -#define MAX_CONSOLE_TEXT 8192 -#define MAX_CONSOLE_LINES 32 - -// all cg.stepTime, cg.duckTime, cg.landTime, etc are set to cg.time when the action -// occurs, and they will have visible effects for #define STEP_TIME or whatever msec after - -#define MAX_PREDICTED_EVENTS 16 - -typedef struct -{ - int clientFrame; // incremented each frame - - int clientNum; - - qboolean demoPlayback; - qboolean levelShot; // taking a level menu screenshot - int deferredPlayerLoading; - qboolean loading; // don't defer players at initial startup - qboolean intermissionStarted; // don't play voice rewards, because game will end shortly - - // there are only one or two snapshot_t that are relevent at a time - int latestSnapshotNum; // the number of snapshots the client system has received - int latestSnapshotTime; // the time from latestSnapshotNum, so we don't need to read the snapshot yet - - snapshot_t *snap; // cg.snap->serverTime <= cg.time - snapshot_t *nextSnap; // cg.nextSnap->serverTime > cg.time, or NULL - snapshot_t activeSnapshots[ 2 ]; - - float frameInterpolation; // (float)( cg.time - cg.frame->serverTime ) / - // (cg.nextFrame->serverTime - cg.frame->serverTime) - - qboolean thisFrameTeleport; - qboolean nextFrameTeleport; - - int frametime; // cg.time - cg.oldTime - - int time; // this is the time value that the client - // is rendering at. - int oldTime; // time at last frame, used for missile trails and prediction checking - - int physicsTime; // either cg.snap->time or cg.nextSnap->time - - int timelimitWarnings; // 5 min, 1 min, overtime - int fraglimitWarnings; - - qboolean mapRestart; // set on a map restart to set back the weapon - - qboolean renderingThirdPerson; // during deaths, chasecams, etc - - // prediction state - qboolean hyperspace; // true if prediction has hit a trigger_teleport - playerState_t predictedPlayerState; - centity_t predictedPlayerEntity; - qboolean validPPS; // clear until the first call to CG_PredictPlayerState - int predictedErrorTime; - vec3_t predictedError; - - int eventSequence; - int predictableEvents[MAX_PREDICTED_EVENTS]; - - float stepChange; // for stair up smoothing - int stepTime; - - float duckChange; // for duck viewheight smoothing - int duckTime; - - float landChange; // for landing hard - int landTime; - - // input state sent to server - int weaponSelect; - - // auto rotating items - vec3_t autoAngles; - vec3_t autoAxis[ 3 ]; - vec3_t autoAnglesFast; - vec3_t autoAxisFast[ 3 ]; - - // view rendering - refdef_t refdef; - vec3_t refdefViewAngles; // will be converted to refdef.viewaxis - - // zoom key - qboolean zoomed; - int zoomTime; - float zoomSensitivity; - - // information screen text during loading - char infoScreenText[ MAX_STRING_CHARS ]; - - // scoreboard - int scoresRequestTime; - int numScores; - int selectedScore; - int teamScores[ 2 ]; - score_t scores[MAX_CLIENTS]; - qboolean showScores; - qboolean scoreBoardShowing; - int scoreFadeTime; - char killerName[ MAX_NAME_LENGTH ]; - char spectatorList[ MAX_STRING_CHARS ]; // list of names - int spectatorLen; // length of list - float spectatorWidth; // width in device units - int spectatorTime; // next time to offset - int spectatorPaintX; // current paint x - int spectatorPaintX2; // current paint x - int spectatorOffset; // current offset from start - int spectatorPaintLen; // current offset from start - - // centerprinting - int centerPrintTime; - int centerPrintCharWidth; - int centerPrintY; - char centerPrint[ 1024 ]; - int centerPrintLines; - - // low ammo warning state - int lowAmmoWarning; // 1 = low, 2 = empty - - // kill timers for carnage reward - int lastKillTime; - - // crosshair client ID - int crosshairClientNum; - int crosshairClientTime; - - // powerup active flashing - int powerupActive; - int powerupTime; - - // attacking player - int attackerTime; - int voiceTime; - - // reward medals - int rewardStack; - int rewardTime; - int rewardCount[ MAX_REWARDSTACK ]; - qhandle_t rewardShader[ MAX_REWARDSTACK ]; - qhandle_t rewardSound[ MAX_REWARDSTACK ]; - - // sound buffer mainly for announcer sounds - int soundBufferIn; - int soundBufferOut; - int soundTime; - qhandle_t soundBuffer[ MAX_SOUNDBUFFER ]; - - // for voice chat buffer - int voiceChatTime; - int voiceChatBufferIn; - int voiceChatBufferOut; - - // warmup countdown - int warmup; - int warmupCount; - - //========================== - - int itemPickup; - int itemPickupTime; - int itemPickupBlendTime; // the pulse around the crosshair is timed seperately - - int weaponSelectTime; - int weaponAnimation; - int weaponAnimationTime; - - // blend blobs - float damageTime; - float damageX, damageY, damageValue; - - // status bar head - float headYaw; - float headEndPitch; - float headEndYaw; - int headEndTime; - float headStartPitch; - float headStartYaw; - int headStartTime; - - // view movement - float v_dmg_time; - float v_dmg_pitch; - float v_dmg_roll; - - vec3_t kick_angles; // weapon kicks - vec3_t kick_origin; - - // temp working variables for player view - float bobfracsin; - int bobcycle; - float xyspeed; - int nextOrbitTime; - - // development tool - refEntity_t testModelEntity; - refEntity_t testModelBarrelEntity; - char testModelName[MAX_QPATH]; - char testModelBarrelName[MAX_QPATH]; - qboolean testGun; - - int spawnTime; //TA: fovwarp - int weapon1Time; //TA: time when BUTTON_ATTACK went t->f f->t - int weapon2Time; //TA: time when BUTTON_ATTACK2 went t->f f->t - int weapon3Time; //TA: time when BUTTON_USE_HOLDABLE went t->f f->t - qboolean weapon1Firing; - qboolean weapon2Firing; - qboolean weapon3Firing; - - int poisonedTime; - - vec3_t lastNormal; //TA: view smoothage - vec3_t lastVangles; //TA: view smoothage - smooth_t sList[ MAXSMOOTHS ]; //TA: WW smoothing - - int forwardMoveTime; //TA: for struggling - int rightMoveTime; - int upMoveTime; - - float charModelFraction; //TA: loading percentages - float mediaFraction; - float buildablesFraction; - - int lastBuildAttempt; - int lastEvolveAttempt; - - char consoleText[ MAX_CONSOLE_TEXT ]; - consoleLine_t consoleLines[ MAX_CONSOLE_LINES ]; - int numConsoleLines; - qboolean consoleValid; - - particleSystem_t *poisonCloudPS; - - float painBlendValue; - float painBlendTarget; - int lastHealth; -} cg_t; - - -// all of the model, shader, and sound references that are -// loaded at gamestate time are stored in cgMedia_t -// Other media that can be tied to clients, weapons, or items are -// stored in the clientInfo_t, itemInfo_t, weaponInfo_t, and powerupInfo_t -typedef struct -{ - qhandle_t charsetShader; - qhandle_t whiteShader; - qhandle_t outlineShader; - - qhandle_t level2ZapTS; - - qhandle_t balloonShader; - qhandle_t connectionShader; - - qhandle_t selectShader; - qhandle_t viewBloodShader; - qhandle_t tracerShader; - qhandle_t crosshairShader[ WP_NUM_WEAPONS ]; - qhandle_t backTileShader; - - qhandle_t creepShader; - - qhandle_t scannerShader; - qhandle_t scannerBlipShader; - qhandle_t scannerLineShader; - - - qhandle_t numberShaders[ 11 ]; - - qhandle_t shadowMarkShader; - qhandle_t wakeMarkShader; - - // buildable shaders - qhandle_t greenBuildShader; - qhandle_t redBuildShader; - qhandle_t noPowerShader; - qhandle_t humanSpawningShader; - - // disconnect - qhandle_t disconnectPS; - qhandle_t disconnectSound; - - // sounds - sfxHandle_t tracerSound; - sfxHandle_t selectSound; - sfxHandle_t footsteps[ FOOTSTEP_TOTAL ][ 4 ]; - sfxHandle_t talkSound; - sfxHandle_t landSound; - sfxHandle_t fallSound; - - sfxHandle_t hgrenb1aSound; - sfxHandle_t hgrenb2aSound; - - sfxHandle_t voteNow; - sfxHandle_t votePassed; - sfxHandle_t voteFailed; - - sfxHandle_t watrInSound; - sfxHandle_t watrOutSound; - sfxHandle_t watrUnSound; - - sfxHandle_t jetpackDescendSound; - sfxHandle_t jetpackIdleSound; - sfxHandle_t jetpackAscendSound; - - qhandle_t jetPackDescendPS; - qhandle_t jetPackHoverPS; - qhandle_t jetPackAscendPS; - - sfxHandle_t medkitUseSound; - - sfxHandle_t alienStageTransition; - sfxHandle_t humanStageTransition; - - sfxHandle_t alienOvermindAttack; - sfxHandle_t alienOvermindDying; - sfxHandle_t alienOvermindSpawns; - - sfxHandle_t alienBuildableExplosion; - sfxHandle_t alienBuildableDamage; - sfxHandle_t alienBuildablePrebuild; - sfxHandle_t humanBuildableExplosion; - sfxHandle_t humanBuildablePrebuild; - sfxHandle_t humanBuildableDamage[ 4 ]; - - sfxHandle_t alienL1Grab; - sfxHandle_t alienL4ChargePrepare; - sfxHandle_t alienL4ChargeStart; - - qhandle_t cursor; - qhandle_t selectCursor; - qhandle_t sizeCursor; - - //light armour - qhandle_t larmourHeadSkin; - qhandle_t larmourLegsSkin; - qhandle_t larmourTorsoSkin; - - qhandle_t jetpackModel; - qhandle_t jetpackFlashModel; - qhandle_t battpackModel; - - sfxHandle_t repeaterUseSound; - - sfxHandle_t buildableRepairSound; - sfxHandle_t buildableRepairedSound; - - qhandle_t poisonCloudPS; - qhandle_t alienEvolvePS; - qhandle_t alienAcidTubePS; - - sfxHandle_t alienEvolveSound; - - qhandle_t humanBuildableDamagedPS; - qhandle_t humanBuildableDestroyedPS; - qhandle_t alienBuildableDamagedPS; - qhandle_t alienBuildableDestroyedPS; - - qhandle_t alienBleedPS; - qhandle_t humanBleedPS; - - qhandle_t teslaZapTS; - - sfxHandle_t lCannonWarningSound; - - qhandle_t buildWeaponTimerPie[ 8 ]; - qhandle_t upgradeClassIconShader; -} cgMedia_t; - - -// The client game static (cgs) structure hold everything -// loaded or calculated from the gamestate. It will NOT -// be cleared when a tournement restart is done, allowing -// all clients to begin playing instantly -typedef struct -{ - gameState_t gameState; // gamestate from server - glconfig_t glconfig; // rendering configuration - float screenXScale; // derived from glconfig - float screenYScale; - float screenXBias; - - int serverCommandSequence; // reliable command stream counter - int processedSnapshotNum; // the number of snapshots cgame has requested - - qboolean localServer; // detected on startup by checking sv_running - - // parsed from serverinfo - int dmflags; - int teamflags; - int timelimit; - int maxclients; - char mapname[ MAX_QPATH ]; - - int voteTime; - int voteYes; - int voteNo; - qboolean voteModified; // beep whenever changed - char voteString[ MAX_STRING_TOKENS ]; - - int teamVoteTime[ 2 ]; - int teamVoteYes[ 2 ]; - int teamVoteNo[ 2 ]; - qboolean teamVoteModified[ 2 ]; // beep whenever changed - char teamVoteString[ 2 ][ MAX_STRING_TOKENS ]; - - int levelStartTime; - - int scores1, scores2; // from configstrings - - qboolean newHud; - - int alienBuildPoints; - int alienBuildPointsTotal; - int humanBuildPoints; - int humanBuildPointsTotal; - int humanBuildPointsPowered; - - int alienStage; - int humanStage; - int alienKills; - int humanKills; - int alienNextStageThreshold; - int humanNextStageThreshold; - - int numAlienSpawns; - int numHumanSpawns; - - // - // locally derived information from gamestate - // - qhandle_t gameModels[ MAX_MODELS ]; - qhandle_t gameShaders[ MAX_SHADERS ]; - qhandle_t gameParticleSystems[ MAX_GAME_PARTICLE_SYSTEMS ]; - sfxHandle_t gameSounds[ MAX_SOUNDS ]; - - int numInlineModels; - qhandle_t inlineDrawModel[ MAX_MODELS ]; - vec3_t inlineModelMidpoints[ MAX_MODELS ]; - - clientInfo_t clientinfo[ MAX_CLIENTS ]; - - //TA: corpse info - clientInfo_t corpseinfo[ MAX_CLIENTS ]; - - // teamchat width is *3 because of embedded color codes - char teamChatMsgs[ TEAMCHAT_HEIGHT ][ TEAMCHAT_WIDTH * 3 + 1 ]; - int teamChatMsgTimes[ TEAMCHAT_HEIGHT ]; - int teamChatPos; - int teamLastChatPos; - - int cursorX; - int cursorY; - qboolean eventHandling; - qboolean mouseCaptured; - qboolean sizingHud; - void *capturedItem; - qhandle_t activeCursor; - - // media - cgMedia_t media; -} cgs_t; - -//============================================================================== - -extern cgs_t cgs; -extern cg_t cg; -extern centity_t cg_entities[ MAX_GENTITIES ]; - -//TA: weapon limit expanded: -//extern weaponInfo_t cg_weapons[MAX_WEAPONS]; -extern weaponInfo_t cg_weapons[ 32 ]; -//TA: upgrade infos: -extern upgradeInfo_t cg_upgrades[ 32 ]; - -//TA: buildable infos: -extern buildableInfo_t cg_buildables[ BA_NUM_BUILDABLES ]; - -extern markPoly_t cg_markPolys[ MAX_MARK_POLYS ]; - -extern vmCvar_t cg_centertime; -extern vmCvar_t cg_runpitch; -extern vmCvar_t cg_runroll; -extern vmCvar_t cg_bobup; -extern vmCvar_t cg_bobpitch; -extern vmCvar_t cg_bobroll; -extern vmCvar_t cg_swingSpeed; -extern vmCvar_t cg_shadows; -extern vmCvar_t cg_gibs; -extern vmCvar_t cg_drawTimer; -extern vmCvar_t cg_drawFPS; -extern vmCvar_t cg_drawSnapshot; -extern vmCvar_t cg_draw3dIcons; -extern vmCvar_t cg_drawIcons; -extern vmCvar_t cg_drawAmmoWarning; -extern vmCvar_t cg_drawCrosshair; -extern vmCvar_t cg_drawCrosshairNames; -extern vmCvar_t cg_drawRewards; -extern vmCvar_t cg_drawTeamOverlay; -extern vmCvar_t cg_teamOverlayUserinfo; -extern vmCvar_t cg_crosshairX; -extern vmCvar_t cg_crosshairY; -extern vmCvar_t cg_drawStatus; -extern vmCvar_t cg_draw2D; -extern vmCvar_t cg_animSpeed; -extern vmCvar_t cg_debugAnim; -extern vmCvar_t cg_debugPosition; -extern vmCvar_t cg_debugEvents; -extern vmCvar_t cg_teslaTrailTime; -extern vmCvar_t cg_railTrailTime; -extern vmCvar_t cg_errorDecay; -extern vmCvar_t cg_nopredict; -extern vmCvar_t cg_debugMove; -extern vmCvar_t cg_noPlayerAnims; -extern vmCvar_t cg_showmiss; -extern vmCvar_t cg_footsteps; -extern vmCvar_t cg_addMarks; -extern vmCvar_t cg_brassTime; -extern vmCvar_t cg_gun_frame; -extern vmCvar_t cg_gun_x; -extern vmCvar_t cg_gun_y; -extern vmCvar_t cg_gun_z; -extern vmCvar_t cg_drawGun; -extern vmCvar_t cg_viewsize; -extern vmCvar_t cg_tracerChance; -extern vmCvar_t cg_tracerWidth; -extern vmCvar_t cg_tracerLength; -extern vmCvar_t cg_autoswitch; -extern vmCvar_t cg_ignore; -extern vmCvar_t cg_simpleItems; -extern vmCvar_t cg_fov; -extern vmCvar_t cg_zoomFov; -extern vmCvar_t cg_thirdPersonRange; -extern vmCvar_t cg_thirdPersonAngle; -extern vmCvar_t cg_thirdPerson; -extern vmCvar_t cg_stereoSeparation; -extern vmCvar_t cg_lagometer; -extern vmCvar_t cg_drawAttacker; -extern vmCvar_t cg_synchronousClients; -extern vmCvar_t cg_teamChatTime; -extern vmCvar_t cg_teamChatHeight; -extern vmCvar_t cg_stats; -extern vmCvar_t cg_forceModel; -extern vmCvar_t cg_buildScript; -extern vmCvar_t cg_paused; -extern vmCvar_t cg_blood; -extern vmCvar_t cg_predictItems; -extern vmCvar_t cg_deferPlayers; -extern vmCvar_t cg_drawFriend; -extern vmCvar_t cg_teamChatsOnly; -extern vmCvar_t cg_noVoiceChats; -extern vmCvar_t cg_noVoiceText; -extern vmCvar_t cg_scorePlum; -extern vmCvar_t cg_smoothClients; -extern vmCvar_t pmove_fixed; -extern vmCvar_t pmove_msec; -//extern vmCvar_t cg_pmove_fixed; -extern vmCvar_t cg_cameraOrbit; -extern vmCvar_t cg_cameraOrbitDelay; -extern vmCvar_t cg_timescaleFadeEnd; -extern vmCvar_t cg_timescaleFadeSpeed; -extern vmCvar_t cg_timescale; -extern vmCvar_t cg_cameraMode; -extern vmCvar_t cg_smallFont; -extern vmCvar_t cg_bigFont; -extern vmCvar_t cg_noTaunt; -extern vmCvar_t cg_noProjectileTrail; -extern vmCvar_t cg_oldRail; -extern vmCvar_t cg_oldRocket; -extern vmCvar_t cg_oldPlasma; -extern vmCvar_t cg_trueLightning; -extern vmCvar_t cg_creepRes; -extern vmCvar_t cg_drawSurfNormal; -extern vmCvar_t cg_drawBBOX; -extern vmCvar_t cg_debugAlloc; -extern vmCvar_t cg_wwSmoothTime; -extern vmCvar_t cg_wwFollow; -extern vmCvar_t cg_wwToggle; -extern vmCvar_t cg_depthSortParticles; -extern vmCvar_t cg_consoleLatency; -extern vmCvar_t cg_lightFlare; -extern vmCvar_t cg_debugParticles; -extern vmCvar_t cg_debugTrails; -extern vmCvar_t cg_debugPVS; -extern vmCvar_t cg_disableWarningDialogs; -extern vmCvar_t cg_disableScannerPlane; - -extern vmCvar_t cg_painBlendUpRate; -extern vmCvar_t cg_painBlendDownRate; -extern vmCvar_t cg_painBlendMax; -extern vmCvar_t cg_painBlendScale; -extern vmCvar_t cg_painBlendZoom; - -//TA: hack to get class an carriage through to UI module -extern vmCvar_t ui_currentClass; -extern vmCvar_t ui_carriage; -extern vmCvar_t ui_stages; -extern vmCvar_t ui_dialog; -extern vmCvar_t ui_loading; -extern vmCvar_t ui_voteActive; -extern vmCvar_t ui_alienTeamVoteActive; -extern vmCvar_t ui_humanTeamVoteActive; - -extern vmCvar_t cg_debugRandom; - -// -// cg_main.c -// -const char *CG_ConfigString( int index ); -const char *CG_Argv( int arg ); - -void CG_TAUIConsole( const char *text ); -void QDECL CG_Printf( const char *msg, ... ); -void QDECL CG_Error( const char *msg, ... ); - -void CG_StartMusic( void ); - -void CG_UpdateCvars( void ); - -int CG_CrosshairPlayer( void ); -int CG_LastAttacker( void ); -void CG_LoadMenus( const char *menuFile ); -void CG_KeyEvent( int key, qboolean down ); -void CG_MouseEvent( int x, int y ); -void CG_EventHandling( int type ); -void CG_SetScoreSelection( void *menu ); -void CG_BuildSpectatorString( void ); - -qboolean CG_FileExists( char *filename ); -void CG_RemoveConsoleLine( void ); - - -// -// cg_view.c -// -void CG_addSmoothOp( vec3_t rotAxis, float rotAngle, float timeMod ); //TA -void CG_TestModel_f( void ); -void CG_TestGun_f( void ); -void CG_TestModelNextFrame_f( void ); -void CG_TestModelPrevFrame_f( void ); -void CG_TestModelNextSkin_f( void ); -void CG_TestModelPrevSkin_f( void ); -void CG_ZoomDown_f( void ); -void CG_ZoomUp_f( void ); -void CG_AddBufferedSound( sfxHandle_t sfx ); -void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ); - - -// -// cg_drawtools.c -// -void CG_DrawPlane( vec3_t origin, vec3_t down, vec3_t right, qhandle_t shader ); -void CG_AdjustFrom640( float *x, float *y, float *w, float *h ); -void CG_FillRect( float x, float y, float width, float height, const float *color ); -void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader ); -void CG_DrawFadePic( float x, float y, float width, float height, vec4_t fcolor, - vec4_t tcolor, float amount, qhandle_t hShader ); - -int CG_DrawStrlen( const char *str ); - -float *CG_FadeColor( int startMsec, int totalMsec ); -void CG_TileClear( void ); -void CG_ColorForHealth( vec4_t hcolor ); -void CG_GetColorForHealth( int health, int armor, vec4_t hcolor ); - -void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ); -void CG_DrawSides(float x, float y, float w, float h, float size); -void CG_DrawTopBottom(float x, float y, float w, float h, float size); - - -// -// cg_draw.c -// -extern int sortedTeamPlayers[ TEAM_MAXOVERLAY ]; -extern int numSortedTeamPlayers; -extern char systemChat[ 256 ]; -extern char teamChat1[ 256 ]; -extern char teamChat2[ 256 ]; - -void CG_AddLagometerFrameInfo( void ); -void CG_AddLagometerSnapshotInfo( snapshot_t *snap ); -void CG_CenterPrint( const char *str, int y, int charWidth ); -void CG_DrawActive( stereoFrame_t stereoView ); -void CG_OwnerDraw( float x, float y, float w, float h, float text_x, float text_y, - int ownerDraw, int ownerDrawFlags, int align, float special, - float scale, vec4_t color, qhandle_t shader, int textStyle); -void CG_Text_Paint( float x, float y, float scale, vec4_t color, const char *text, float adjust, int limit, int style ); -int CG_Text_Width( const char *text, float scale, int limit ); -int CG_Text_Height( const char *text, float scale, int limit ); -float CG_GetValue(int ownerDraw); -void CG_RunMenuScript(char **args); -void CG_SetPrintString( int type, const char *p ); -void CG_InitTeamChat( void ); -void CG_GetTeamColor( vec4_t *color ); -const char *CG_GetKillerText(); -void CG_Text_PaintChar( float x, float y, float width, float height, float scale, - float s, float t, float s2, float t2, qhandle_t hShader ); -void CG_DrawLoadingScreen( void ); -void CG_UpdateMediaFraction( float newFract ); -void CG_ResetPainBlend( void ); - -// -// cg_players.c -// -void CG_Player( centity_t *cent ); -void CG_Corpse( centity_t *cent ); -void CG_ResetPlayerEntity( centity_t *cent ); -void CG_AddRefEntityWithPowerups( refEntity_t *ent, int powerups, int team ); -void CG_NewClientInfo( int clientNum ); -void CG_PrecacheClientInfo( pClass_t class, char *model, char *skin ); -sfxHandle_t CG_CustomSound( int clientNum, const char *soundName ); -void CG_PlayerDisconnect( vec3_t org ); -void CG_Bleed( vec3_t origin, vec3_t normal, int entityNum ); - -// -// cg_buildable.c -// -void CG_GhostBuildable( buildable_t buildable ); -void CG_Buildable( centity_t *cent ); -void CG_InitBuildables( void ); -void CG_HumanBuildableExplosion( vec3_t origin, vec3_t dir ); -void CG_AlienBuildableExplosion( vec3_t origin, vec3_t dir ); - -// -// cg_animation.c -// -void CG_RunLerpFrame( lerpFrame_t *lf ); - -// -// cg_animmapobj.c -// -void CG_AnimMapObj( centity_t *cent ); -void CG_ModelDoor( centity_t *cent ); - -// -// cg_predict.c -// - -#define MAGIC_TRACE_HACK -2 - -void CG_BuildSolidList( void ); -int CG_PointContents( const vec3_t point, int passEntityNum ); -void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, - int skipNumber, int mask ); -void CG_CapTrace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, - int skipNumber, int mask ); -void CG_PredictPlayerState( void ); - - -// -// cg_events.c -// -void CG_CheckEvents( centity_t *cent ); -void CG_EntityEvent( centity_t *cent, vec3_t position ); -void CG_PainEvent( centity_t *cent, int health ); - - -// -// cg_ents.c -// -void CG_DrawBoundingBox( vec3_t origin, vec3_t mins, vec3_t maxs ); -void CG_SetEntitySoundPosition( centity_t *cent ); -void CG_AddPacketEntities( void ); -void CG_Beam( centity_t *cent ); -void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ); - -void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent, - qhandle_t parentModel, char *tagName ); -void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent, - qhandle_t parentModel, char *tagName ); - - - - -// -// cg_weapons.c -// -void CG_NextWeapon_f( void ); -void CG_PrevWeapon_f( void ); -void CG_Weapon_f( void ); - -void CG_InitUpgrades( ); -void CG_RegisterUpgrade( int upgradeNum ); -void CG_InitWeapons( ); -void CG_RegisterWeapon( int weaponNum ); - -void CG_FireWeapon( centity_t *cent, weaponMode_t weaponMode ); -void CG_MissileHitWall( weapon_t weapon, weaponMode_t weaponMode, int clientNum, - vec3_t origin, vec3_t dir, impactSound_t soundType ); -void CG_MissileHitPlayer( weapon_t weapon, weaponMode_t weaponMode, vec3_t origin, vec3_t dir, int entityNum ); -void CG_Bullet( vec3_t origin, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ); -void CG_ShotgunFire( entityState_t *es ); - -void CG_AddViewWeapon (playerState_t *ps); -void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent ); -void CG_DrawItemSelect( rectDef_t *rect, vec4_t color ); -void CG_DrawItemSelectText( rectDef_t *rect, float scale, int textStyle ); - - -// -// cg_scanner.c -// -void CG_UpdateEntityPositions( void ); -void CG_Scanner( rectDef_t *rect, qhandle_t shader, vec4_t color ); -void CG_AlienSense( rectDef_t *rect ); - -// -// cg_marks.c -// -void CG_InitMarkPolys( void ); -void CG_AddMarks( void ); -void CG_ImpactMark( qhandle_t markShader, - const vec3_t origin, const vec3_t dir, - float orientation, - float r, float g, float b, float a, - qboolean alphaFade, - float radius, qboolean temporary ); - -// -// cg_snapshot.c -// -void CG_ProcessSnapshots( void ); - -// -// cg_consolecmds.c -// -qboolean CG_ConsoleCommand( void ); -void CG_InitConsoleCommands( void ); - -// -// cg_servercmds.c -// -void CG_ExecuteNewServerCommands( int latestSequence ); -void CG_ParseServerinfo( void ); -void CG_SetConfigValues( void ); -void CG_ShaderStateChanged(void); - -// -// cg_playerstate.c -// -void CG_Respawn( void ); -void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ); -void CG_CheckChangedPredictableEvents( playerState_t *ps ); - -// -// cg_mem.c -// -void CG_InitMemory( void ); -void *CG_Alloc( int size ); -void CG_Free( void *ptr ); -void CG_DefragmentMemory( void ); - -// -// cg_attachment.c -// -qboolean CG_AttachmentPoint( attachment_t *a, vec3_t v ); -qboolean CG_AttachmentDir( attachment_t *a, vec3_t v ); -qboolean CG_AttachmentAxis( attachment_t *a, vec3_t axis[ 3 ] ); -qboolean CG_AttachmentVelocity( attachment_t *a, vec3_t v ); -int CG_AttachmentCentNum( attachment_t *a ); - -qboolean CG_Attached( attachment_t *a ); - -void CG_AttachToPoint( attachment_t *a ); -void CG_AttachToCent( attachment_t *a ); -void CG_AttachToTag( attachment_t *a ); -void CG_AttachToParticle( attachment_t *a ); -void CG_SetAttachmentPoint( attachment_t *a, vec3_t v ); -void CG_SetAttachmentCent( attachment_t *a, centity_t *cent ); -void CG_SetAttachmentTag( attachment_t *a, refEntity_t parent, - qhandle_t model, char *tagName ); -void CG_SetAttachmentParticle( attachment_t *a, particle_t *p ); - -void CG_SetAttachmentOffset( attachment_t *a, vec3_t v ); - -// -// cg_particles.c -// -void CG_LoadParticleSystems( void ); -qhandle_t CG_RegisterParticleSystem( char *name ); - -particleSystem_t *CG_SpawnNewParticleSystem( qhandle_t psHandle ); -void CG_DestroyParticleSystem( particleSystem_t **ps ); - -qboolean CG_IsParticleSystemInfinite( particleSystem_t *ps ); -qboolean CG_IsParticleSystemValid( particleSystem_t **ps ); - -void CG_SetParticleSystemNormal( particleSystem_t *ps, vec3_t normal ); - -void CG_AddParticles( void ); - -void CG_ParticleSystemEntity( centity_t *cent ); - -void CG_TestPS_f( void ); -void CG_DestroyTestPS_f( void ); - -// -// cg_trails.c -// -void CG_LoadTrailSystems( void ); -qhandle_t CG_RegisterTrailSystem( char *name ); - -trailSystem_t *CG_SpawnNewTrailSystem( qhandle_t psHandle ); -void CG_DestroyTrailSystem( trailSystem_t **ts ); - -qboolean CG_IsTrailSystemValid( trailSystem_t **ts ); - -void CG_AddTrails( void ); - -void CG_TestTS_f( void ); -void CG_DestroyTestTS_f( void ); - -// -// cg_ptr.c -// -int CG_ReadPTRCode( void ); -void CG_WritePTRCode( int code ); - -// -//=============================================== - -// -// system traps -// These functions are how the cgame communicates with the main game system -// - - -// print message on the local console -void trap_Print( const char *fmt ); - -// abort the game -void trap_Error( const char *fmt ); - -// milliseconds should only be used for performance tuning, never -// for anything game related. Get time from the CG_DrawActiveFrame parameter -int trap_Milliseconds( void ); - -// console variable interaction -void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ); -void trap_Cvar_Update( vmCvar_t *vmCvar ); -void trap_Cvar_Set( const char *var_name, const char *value ); -void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ); - -// ServerCommand and ConsoleCommand parameter access -int trap_Argc( void ); -void trap_Argv( int n, char *buffer, int bufferLength ); -void trap_Args( char *buffer, int bufferLength ); - -// filesystem access -// returns length of file -int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ); -void trap_FS_Read( void *buffer, int len, fileHandle_t f ); -void trap_FS_Write( const void *buffer, int len, fileHandle_t f ); -void trap_FS_FCloseFile( fileHandle_t f ); -void trap_FS_Seek( fileHandle_t f, long offset, fsOrigin_t origin ); // fsOrigin_t - -// add commands to the local console as if they were typed in -// for map changing, etc. The command is not executed immediately, -// but will be executed in order the next time console commands -// are processed -void trap_SendConsoleCommand( const char *text ); - -// register a command name so the console can perform command completion. -// FIXME: replace this with a normal console command "defineCommand"? -void trap_AddCommand( const char *cmdName ); - -// send a string to the server over the network -void trap_SendClientCommand( const char *s ); - -// force a screen update, only used during gamestate load -void trap_UpdateScreen( void ); - -// model collision -void trap_CM_LoadMap( const char *mapname ); -int trap_CM_NumInlineModels( void ); -clipHandle_t trap_CM_InlineModel( int index ); // 0 = world, 1+ = bmodels -clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ); -int trap_CM_PointContents( const vec3_t p, clipHandle_t model ); -int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles ); -void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end, - const vec3_t mins, const vec3_t maxs, - clipHandle_t model, int brushmask ); -void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end, - const vec3_t mins, const vec3_t maxs, - clipHandle_t model, int brushmask, - const vec3_t origin, const vec3_t angles ); -void trap_CM_CapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end, - const vec3_t mins, const vec3_t maxs, - clipHandle_t model, int brushmask ); -void trap_CM_TransformedCapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end, - const vec3_t mins, const vec3_t maxs, - clipHandle_t model, int brushmask, - const vec3_t origin, const vec3_t angles ); - -// Returns the projection of a polygon onto the solid brushes in the world -int trap_CM_MarkFragments( int numPoints, const vec3_t *points, - const vec3_t projection, - int maxPoints, vec3_t pointBuffer, - int maxFragments, markFragment_t *fragmentBuffer ); - -// normal sounds will have their volume dynamically changed as their entity -// moves and the listener moves -void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ); -void trap_S_StopLoopingSound( int entnum ); - -// a local sound is always played full volume -void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ); -void trap_S_ClearLoopingSounds( qboolean killall ); -void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ); -void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ); -void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin ); - -// respatialize recalculates the volumes of sound as they should be heard by the -// given entityNum and position -void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater ); -sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ); // returns buzz if not found -void trap_S_StartBackgroundTrack( const char *intro, const char *loop ); // empty name stops music -void trap_S_StopBackgroundTrack( void ); - - -void trap_R_LoadWorldMap( const char *mapname ); - -// all media should be registered during level startup to prevent -// hitches during gameplay -qhandle_t trap_R_RegisterModel( const char *name ); // returns rgb axis if not found -qhandle_t trap_R_RegisterSkin( const char *name ); // returns all white if not found -qhandle_t trap_R_RegisterShader( const char *name ); // returns all white if not found -qhandle_t trap_R_RegisterShaderNoMip( const char *name ); // returns all white if not found - -// a scene is built up by calls to R_ClearScene and the various R_Add functions. -// Nothing is drawn until R_RenderScene is called. -void trap_R_ClearScene( void ); -void trap_R_AddRefEntityToScene( const refEntity_t *re ); - -// polys are intended for simple wall marks, not really for doing -// significant construction -void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ); -void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int numPolys ); -void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ); -void trap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ); -int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ); -void trap_R_RenderScene( const refdef_t *fd ); -void trap_R_SetColor( const float *rgba ); // NULL = 1,1,1,1 -void trap_R_DrawStretchPic( float x, float y, float w, float h, - float s1, float t1, float s2, float t2, qhandle_t hShader ); -void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ); -int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, - float frac, const char *tagName ); -void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ); - -// The glconfig_t will not change during the life of a cgame. -// If it needs to change, the entire cgame will be restarted, because -// all the qhandle_t are then invalid. -void trap_GetGlconfig( glconfig_t *glconfig ); - -// the gamestate should be grabbed at startup, and whenever a -// configstring changes -void trap_GetGameState( gameState_t *gamestate ); - -// cgame will poll each frame to see if a newer snapshot has arrived -// that it is interested in. The time is returned seperately so that -// snapshot latency can be calculated. -void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ); - -// a snapshot get can fail if the snapshot (or the entties it holds) is so -// old that it has fallen out of the client system queue -qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ); - -// retrieve a text command from the server stream -// the current snapshot will hold the number of the most recent command -// qfalse can be returned if the client system handled the command -// argc() / argv() can be used to examine the parameters of the command -qboolean trap_GetServerCommand( int serverCommandNumber ); - -// returns the most recent command number that can be passed to GetUserCmd -// this will always be at least one higher than the number in the current -// snapshot, and it may be quite a few higher if it is a fast computer on -// a lagged connection -int trap_GetCurrentCmdNumber( void ); - -qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd ); - -// used for the weapon select and zoom -void trap_SetUserCmdValue( int stateValue, float sensitivityScale ); - -// aids for VM testing -void testPrintInt( char *string, int i ); -void testPrintFloat( char *string, float f ); - -int trap_MemoryRemaining( void ); -void trap_R_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font); -qboolean trap_Key_IsDown( int keynum ); -int trap_Key_GetCatcher( void ); -void trap_Key_SetCatcher( int catcher ); -int trap_Key_GetKey( const char *binding ); - -typedef enum -{ - SYSTEM_PRINT, - CHAT_PRINT, - TEAMCHAT_PRINT -} q3print_t; - - -int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits ); -e_status trap_CIN_StopCinematic( int handle ); -e_status trap_CIN_RunCinematic( int handle ); -void trap_CIN_DrawCinematic( int handle ); -void trap_CIN_SetExtents( int handle, int x, int y, int w, int h ); - -void trap_SnapVector( float *v ); - -qboolean trap_loadCamera( const char *name ); -void trap_startCamera( int time ); -qboolean trap_getCameraInfo( int time, vec3_t *origin, vec3_t *angles ); - -qboolean trap_GetEntityToken( char *buffer, int bufferSize ); diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c deleted file mode 100644 index 81470e0e..00000000 --- a/src/cgame/cg_main.c +++ /dev/null @@ -1,1801 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_main.c -- initialization and primary entry point for cgame - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -#include "../ui/ui_shared.h" -// display context for new ui stuff -displayContextDef_t cgDC; - -int forceModelModificationCount = -1; - -void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ); -void CG_Shutdown( void ); - -/* -================ -vmMain - -This is the only way control passes into the module. -This must be the very first function compiled into the .q3vm file -================ -*/ -long vmMain( long command, long arg0, long arg1, long arg2, long arg3, - long arg4, long arg5, long arg6, long arg7, - long arg8, long arg9, long arg10, long arg11 ) -{ - switch( command ) - { - case CG_INIT: - CG_Init( arg0, arg1, arg2 ); - return 0; - - case CG_SHUTDOWN: - CG_Shutdown( ); - return 0; - - case CG_CONSOLE_COMMAND: - return CG_ConsoleCommand( ); - - case CG_DRAW_ACTIVE_FRAME: - CG_DrawActiveFrame( arg0, arg1, arg2 ); - return 0; - - case CG_CROSSHAIR_PLAYER: - return CG_CrosshairPlayer( ); - - case CG_LAST_ATTACKER: - return CG_LastAttacker( ); - - case CG_KEY_EVENT: - CG_KeyEvent( arg0, arg1 ); - return 0; - - case CG_MOUSE_EVENT: - cgDC.cursorx = cgs.cursorX; - cgDC.cursory = cgs.cursorY; - CG_MouseEvent( arg0, arg1 ); - return 0; - - case CG_EVENT_HANDLING: - CG_EventHandling( arg0 ); - return 0; - - default: - CG_Error( "vmMain: unknown command %i", command ); - break; - } - - return -1; -} - - -cg_t cg; -cgs_t cgs; -centity_t cg_entities[ MAX_GENTITIES ]; - -//TA: weapons limit expanded: -//weaponInfo_t cg_weapons[MAX_WEAPONS]; -weaponInfo_t cg_weapons[ 32 ]; -upgradeInfo_t cg_upgrades[ 32 ]; - -buildableInfo_t cg_buildables[ BA_NUM_BUILDABLES ]; - -vmCvar_t cg_teslaTrailTime; -vmCvar_t cg_railTrailTime; -vmCvar_t cg_centertime; -vmCvar_t cg_runpitch; -vmCvar_t cg_runroll; -vmCvar_t cg_bobup; -vmCvar_t cg_bobpitch; -vmCvar_t cg_bobroll; -vmCvar_t cg_swingSpeed; -vmCvar_t cg_shadows; -vmCvar_t cg_gibs; -vmCvar_t cg_drawTimer; -vmCvar_t cg_drawFPS; -vmCvar_t cg_drawSnapshot; -vmCvar_t cg_draw3dIcons; -vmCvar_t cg_drawIcons; -vmCvar_t cg_drawAmmoWarning; -vmCvar_t cg_drawCrosshair; -vmCvar_t cg_drawCrosshairNames; -vmCvar_t cg_drawRewards; -vmCvar_t cg_crosshairX; -vmCvar_t cg_crosshairY; -vmCvar_t cg_draw2D; -vmCvar_t cg_drawStatus; -vmCvar_t cg_animSpeed; -vmCvar_t cg_debugAnim; -vmCvar_t cg_debugPosition; -vmCvar_t cg_debugEvents; -vmCvar_t cg_errorDecay; -vmCvar_t cg_nopredict; -vmCvar_t cg_debugMove; -vmCvar_t cg_noPlayerAnims; -vmCvar_t cg_showmiss; -vmCvar_t cg_footsteps; -vmCvar_t cg_addMarks; -vmCvar_t cg_brassTime; -vmCvar_t cg_viewsize; -vmCvar_t cg_drawGun; -vmCvar_t cg_gun_frame; -vmCvar_t cg_gun_x; -vmCvar_t cg_gun_y; -vmCvar_t cg_gun_z; -vmCvar_t cg_tracerChance; -vmCvar_t cg_tracerWidth; -vmCvar_t cg_tracerLength; -vmCvar_t cg_autoswitch; -vmCvar_t cg_ignore; -vmCvar_t cg_simpleItems; -vmCvar_t cg_fov; -vmCvar_t cg_zoomFov; -vmCvar_t cg_thirdPerson; -vmCvar_t cg_thirdPersonRange; -vmCvar_t cg_thirdPersonAngle; -vmCvar_t cg_stereoSeparation; -vmCvar_t cg_lagometer; -vmCvar_t cg_drawAttacker; -vmCvar_t cg_synchronousClients; -vmCvar_t cg_teamChatTime; -vmCvar_t cg_teamChatHeight; -vmCvar_t cg_stats; -vmCvar_t cg_buildScript; -vmCvar_t cg_forceModel; -vmCvar_t cg_paused; -vmCvar_t cg_blood; -vmCvar_t cg_predictItems; -vmCvar_t cg_deferPlayers; -vmCvar_t cg_drawTeamOverlay; -vmCvar_t cg_teamOverlayUserinfo; -vmCvar_t cg_drawFriend; -vmCvar_t cg_teamChatsOnly; -vmCvar_t cg_noVoiceChats; -vmCvar_t cg_noVoiceText; -vmCvar_t cg_hudFiles; -vmCvar_t cg_scorePlum; -vmCvar_t cg_smoothClients; -vmCvar_t pmove_fixed; -//vmCvar_t cg_pmove_fixed; -vmCvar_t pmove_msec; -vmCvar_t cg_pmove_msec; -vmCvar_t cg_cameraMode; -vmCvar_t cg_cameraOrbit; -vmCvar_t cg_cameraOrbitDelay; -vmCvar_t cg_timescaleFadeEnd; -vmCvar_t cg_timescaleFadeSpeed; -vmCvar_t cg_timescale; -vmCvar_t cg_smallFont; -vmCvar_t cg_bigFont; -vmCvar_t cg_noTaunt; -vmCvar_t cg_noProjectileTrail; -vmCvar_t cg_oldRail; -vmCvar_t cg_oldRocket; -vmCvar_t cg_oldPlasma; -vmCvar_t cg_trueLightning; -vmCvar_t cg_creepRes; -vmCvar_t cg_drawSurfNormal; -vmCvar_t cg_drawBBOX; -vmCvar_t cg_debugAlloc; -vmCvar_t cg_wwSmoothTime; -vmCvar_t cg_wwFollow; -vmCvar_t cg_wwToggle; -vmCvar_t cg_depthSortParticles; -vmCvar_t cg_consoleLatency; -vmCvar_t cg_lightFlare; -vmCvar_t cg_debugParticles; -vmCvar_t cg_debugTrails; -vmCvar_t cg_debugPVS; -vmCvar_t cg_disableWarningDialogs; -vmCvar_t cg_disableScannerPlane; - -vmCvar_t cg_painBlendUpRate; -vmCvar_t cg_painBlendDownRate; -vmCvar_t cg_painBlendMax; -vmCvar_t cg_painBlendScale; -vmCvar_t cg_painBlendZoom; - -//TA: hack to get class and carriage through to UI module -vmCvar_t ui_currentClass; -vmCvar_t ui_carriage; -vmCvar_t ui_stages; -vmCvar_t ui_dialog; -vmCvar_t ui_loading; -vmCvar_t ui_voteActive; -vmCvar_t ui_alienTeamVoteActive; -vmCvar_t ui_humanTeamVoteActive; - -vmCvar_t cg_debugRandom; - - -typedef struct -{ - vmCvar_t *vmCvar; - char *cvarName; - char *defaultString; - int cvarFlags; -} cvarTable_t; - -static cvarTable_t cvarTable[ ] = -{ - { &cg_ignore, "cg_ignore", "0", 0 }, // used for debugging - { &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE }, - { &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE }, - { &cg_zoomFov, "cg_zoomfov", "22.5", CVAR_ARCHIVE }, - { &cg_fov, "cg_fov", "90", CVAR_ARCHIVE }, - { &cg_viewsize, "cg_viewsize", "100", CVAR_ARCHIVE }, - { &cg_stereoSeparation, "cg_stereoSeparation", "0.4", CVAR_ARCHIVE }, - { &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE }, - { &cg_gibs, "cg_gibs", "1", CVAR_ARCHIVE }, - { &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE }, - { &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE }, - { &cg_drawTimer, "cg_drawTimer", "1", CVAR_ARCHIVE }, - { &cg_drawFPS, "cg_drawFPS", "1", CVAR_ARCHIVE }, - { &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE }, - { &cg_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE }, - { &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE }, - { &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE }, - { &cg_drawAttacker, "cg_drawAttacker", "1", CVAR_ARCHIVE }, - { &cg_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE }, - { &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE }, - { &cg_drawRewards, "cg_drawRewards", "1", CVAR_ARCHIVE }, - { &cg_crosshairX, "cg_crosshairX", "0", CVAR_ARCHIVE }, - { &cg_crosshairY, "cg_crosshairY", "0", CVAR_ARCHIVE }, - { &cg_brassTime, "cg_brassTime", "2500", CVAR_ARCHIVE }, - { &cg_simpleItems, "cg_simpleItems", "0", CVAR_ARCHIVE }, - { &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE }, - { &cg_lagometer, "cg_lagometer", "0", CVAR_ARCHIVE }, - { &cg_teslaTrailTime, "cg_teslaTrailTime", "250", CVAR_ARCHIVE }, - { &cg_railTrailTime, "cg_railTrailTime", "400", CVAR_ARCHIVE }, - { &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT }, - { &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT }, - { &cg_gun_z, "cg_gunZ", "0", CVAR_CHEAT }, - { &cg_centertime, "cg_centertime", "3", CVAR_CHEAT }, - { &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE}, - { &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE }, - { &cg_bobup , "cg_bobup", "0.005", CVAR_CHEAT }, - { &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE }, - { &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE }, - { &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT }, - { &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT }, - { &cg_debugAnim, "cg_debuganim", "0", CVAR_CHEAT }, - { &cg_debugPosition, "cg_debugposition", "0", CVAR_CHEAT }, - { &cg_debugEvents, "cg_debugevents", "0", CVAR_CHEAT }, - { &cg_errorDecay, "cg_errordecay", "100", 0 }, - { &cg_nopredict, "cg_nopredict", "0", 0 }, - { &cg_debugMove, "cg_debugMove", "0", 0 }, - { &cg_noPlayerAnims, "cg_noplayeranims", "0", CVAR_CHEAT }, - { &cg_showmiss, "cg_showmiss", "0", 0 }, - { &cg_footsteps, "cg_footsteps", "1", CVAR_CHEAT }, - { &cg_tracerChance, "cg_tracerchance", "0.4", CVAR_CHEAT }, - { &cg_tracerWidth, "cg_tracerwidth", "1", CVAR_CHEAT }, - { &cg_tracerLength, "cg_tracerlength", "100", CVAR_CHEAT }, - { &cg_thirdPersonRange, "cg_thirdPersonRange", "40", CVAR_CHEAT }, - { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_CHEAT }, - { &cg_thirdPerson, "cg_thirdPerson", "0", CVAR_CHEAT }, - { &cg_teamChatTime, "cg_teamChatTime", "3000", CVAR_ARCHIVE }, - { &cg_teamChatHeight, "cg_teamChatHeight", "0", CVAR_ARCHIVE }, - { &cg_forceModel, "cg_forceModel", "0", CVAR_ARCHIVE }, - { &cg_predictItems, "cg_predictItems", "1", CVAR_ARCHIVE }, - { &cg_deferPlayers, "cg_deferPlayers", "1", CVAR_ARCHIVE }, - { &cg_drawTeamOverlay, "cg_drawTeamOverlay", "0", CVAR_ARCHIVE }, - { &cg_teamOverlayUserinfo, "teamoverlay", "0", CVAR_ROM | CVAR_USERINFO }, - { &cg_stats, "cg_stats", "0", 0 }, - { &cg_drawFriend, "cg_drawFriend", "1", CVAR_ARCHIVE }, - { &cg_teamChatsOnly, "cg_teamChatsOnly", "0", CVAR_ARCHIVE }, - { &cg_noVoiceChats, "cg_noVoiceChats", "0", CVAR_ARCHIVE }, - { &cg_noVoiceText, "cg_noVoiceText", "0", CVAR_ARCHIVE }, - { &cg_creepRes, "cg_creepRes", "16", CVAR_ARCHIVE }, - { &cg_drawSurfNormal, "cg_drawSurfNormal", "0", CVAR_CHEAT }, - { &cg_drawBBOX, "cg_drawBBOX", "0", CVAR_CHEAT }, - { &cg_debugAlloc, "cg_debugAlloc", "0", 0 }, - { &cg_wwSmoothTime, "cg_wwSmoothTime", "300", CVAR_ARCHIVE }, - { &cg_wwFollow, "cg_wwFollow", "1", CVAR_ARCHIVE|CVAR_USERINFO }, - { &cg_wwToggle, "cg_wwToggle", "1", CVAR_ARCHIVE|CVAR_USERINFO }, - { &cg_depthSortParticles, "cg_depthSortParticles", "1", CVAR_ARCHIVE }, - { &cg_consoleLatency, "cg_consoleLatency", "3000", CVAR_ARCHIVE }, - { &cg_lightFlare, "cg_lightFlare", "3", CVAR_ARCHIVE }, - { &cg_debugParticles, "cg_debugParticles", "0", CVAR_CHEAT }, - { &cg_debugTrails, "cg_debugTrails", "0", CVAR_CHEAT }, - { &cg_debugPVS, "cg_debugPVS", "0", CVAR_CHEAT }, - { &cg_disableWarningDialogs, "cg_disableWarningDialogs", "0", CVAR_ARCHIVE }, - { &cg_disableScannerPlane, "cg_disableScannerPlane", "0", CVAR_ARCHIVE }, - { &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE}, - - { &cg_painBlendUpRate, "cg_painBlendUpRate", "10.0", 0 }, - { &cg_painBlendDownRate, "cg_painBlendDownRate", "0.5", 0 }, - { &cg_painBlendMax, "cg_painBlendMax", "0.7", 0 }, - { &cg_painBlendScale, "cg_painBlendScale", "7.0", 0 }, - { &cg_painBlendZoom, "cg_painBlendZoom", "0.18", 0 }, - - { &ui_currentClass, "ui_currentClass", "0", 0 }, - { &ui_carriage, "ui_carriage", "", 0 }, - { &ui_stages, "ui_stages", "0 0", 0 }, - { &ui_dialog, "ui_dialog", "Text not set", 0 }, - { &ui_loading, "ui_loading", "0", 0 }, - { &ui_voteActive, "ui_voteActive", "0", 0 }, - { &ui_humanTeamVoteActive, "ui_humanTeamVoteActive", "0", 0 }, - { &ui_alienTeamVoteActive, "ui_alienTeamVoteActive", "0", 0 }, - - { &cg_debugRandom, "cg_debugRandom", "0", 0 }, - - // the following variables are created in other parts of the system, - // but we also reference them here - - { &cg_buildScript, "com_buildScript", "0", 0 }, // force loading of all possible data amd error on failures - { &cg_paused, "cl_paused", "0", CVAR_ROM }, - { &cg_blood, "com_blood", "1", CVAR_ARCHIVE }, - { &cg_synchronousClients, "g_synchronousClients", "0", 0 }, // communicated by systeminfo - { &cg_cameraOrbit, "cg_cameraOrbit", "0", CVAR_CHEAT}, - { &cg_cameraOrbitDelay, "cg_cameraOrbitDelay", "50", CVAR_ARCHIVE}, - { &cg_timescaleFadeEnd, "cg_timescaleFadeEnd", "1", 0}, - { &cg_timescaleFadeSpeed, "cg_timescaleFadeSpeed", "0", 0}, - { &cg_timescale, "timescale", "1", 0}, - { &cg_scorePlum, "cg_scorePlums", "1", CVAR_USERINFO | CVAR_ARCHIVE}, - { &cg_smoothClients, "cg_smoothClients", "0", CVAR_USERINFO | CVAR_ARCHIVE}, - { &cg_cameraMode, "com_cameraMode", "0", CVAR_CHEAT}, - - { &pmove_fixed, "pmove_fixed", "0", 0}, - { &pmove_msec, "pmove_msec", "8", 0}, - { &cg_noTaunt, "cg_noTaunt", "0", CVAR_ARCHIVE}, - { &cg_noProjectileTrail, "cg_noProjectileTrail", "0", CVAR_ARCHIVE}, - { &cg_smallFont, "ui_smallFont", "0.2", CVAR_ARCHIVE}, - { &cg_bigFont, "ui_bigFont", "0.5", CVAR_ARCHIVE}, - { &cg_oldRail, "cg_oldRail", "1", CVAR_ARCHIVE}, - { &cg_oldRocket, "cg_oldRocket", "1", CVAR_ARCHIVE}, - { &cg_oldPlasma, "cg_oldPlasma", "1", CVAR_ARCHIVE}, - { &cg_trueLightning, "cg_trueLightning", "0.0", CVAR_ARCHIVE} -// { &cg_pmove_fixed, "cg_pmove_fixed", "0", CVAR_USERINFO | CVAR_ARCHIVE } -}; - -static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] ); - -/* -================= -CG_RegisterCvars -================= -*/ -void CG_RegisterCvars( void ) -{ - int i; - cvarTable_t *cv; - char var[ MAX_TOKEN_CHARS ]; - - for( i = 0, cv = cvarTable; i < cvarTableSize; i++, cv++ ) - { - trap_Cvar_Register( cv->vmCvar, cv->cvarName, - cv->defaultString, cv->cvarFlags ); - } - - //repress standard Q3 console - trap_Cvar_Set( "con_notifytime", "-2" ); - - // see if we are also running the server on this machine - trap_Cvar_VariableStringBuffer( "sv_running", var, sizeof( var ) ); - cgs.localServer = atoi( var ); - forceModelModificationCount = cg_forceModel.modificationCount; - - trap_Cvar_Register( NULL, "model", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE ); - trap_Cvar_Register( NULL, "headmodel", DEFAULT_MODEL, CVAR_USERINFO | CVAR_ARCHIVE ); - trap_Cvar_Register( NULL, "team_model", DEFAULT_TEAM_MODEL, CVAR_USERINFO | CVAR_ARCHIVE ); - trap_Cvar_Register( NULL, "team_headmodel", DEFAULT_TEAM_HEAD, CVAR_USERINFO | CVAR_ARCHIVE ); -} - - -/* -=================== -CG_ForceModelChange -=================== -*/ -static void CG_ForceModelChange( void ) -{ - int i; - - for( i = 0; i < MAX_CLIENTS; i++ ) - { - const char *clientInfo; - - clientInfo = CG_ConfigString( CS_PLAYERS + i ); - - if( !clientInfo[ 0 ] ) - continue; - - CG_NewClientInfo( i ); - } -} - - -/* -================= -CG_UpdateCvars -================= -*/ -void CG_UpdateCvars( void ) -{ - int i; - cvarTable_t *cv; - - for( i = 0, cv = cvarTable; i < cvarTableSize; i++, cv++ ) - trap_Cvar_Update( cv->vmCvar ); - - // check for modications here - - // if force model changed - if( forceModelModificationCount != cg_forceModel.modificationCount ) - { - forceModelModificationCount = cg_forceModel.modificationCount; - CG_ForceModelChange( ); - } -} - - -int CG_CrosshairPlayer( void ) -{ - if( cg.time > ( cg.crosshairClientTime + 1000 ) ) - return -1; - - return cg.crosshairClientNum; -} - - -int CG_LastAttacker( void ) -{ - if( !cg.attackerTime ) - return -1; - - return cg.snap->ps.persistant[ PERS_ATTACKER ]; -} - -void CG_RemoveConsoleLine( void ) -{ - int i, offset, totalLength; - - if( cg.numConsoleLines == 0 ) - return; - - offset = cg.consoleLines[ 0 ].length; - totalLength = strlen( cg.consoleText ) - offset; - - //slide up consoleText - for( i = 0; i <= totalLength; i++ ) - cg.consoleText[ i ] = cg.consoleText[ i + offset ]; - - //pop up the first consoleLine - for( i = 0; i < cg.numConsoleLines; i++ ) - cg.consoleLines[ i ] = cg.consoleLines[ i + 1 ]; - - cg.numConsoleLines--; -} - -//TA: team arena UI based console -void CG_TAUIConsole( const char *text ) -{ - if( cg.numConsoleLines == MAX_CONSOLE_LINES ) - CG_RemoveConsoleLine( ); - - if( cg.consoleValid ) - { - strcat( cg.consoleText, text ); - cg.consoleLines[ cg.numConsoleLines ].time = cg.time; - cg.consoleLines[ cg.numConsoleLines ].length = strlen( text ); - cg.numConsoleLines++; - } - -} - -void QDECL CG_Printf( const char *msg, ... ) -{ - va_list argptr; - char text[ 1024 ]; - - va_start( argptr, msg ); - vsprintf( text, msg, argptr ); - va_end( argptr ); - - CG_TAUIConsole( text ); - - trap_Print( text ); -} - -void QDECL CG_Error( const char *msg, ... ) -{ - va_list argptr; - char text[ 1024 ]; - - va_start( argptr, msg ); - vsprintf( text, msg, argptr ); - va_end( argptr ); - - trap_Error( text ); -} - -void QDECL Com_Error( int level, const char *error, ... ) -{ - va_list argptr; - char text[1024]; - - va_start( argptr, error ); - vsprintf( text, error, argptr ); - va_end( argptr ); - - CG_Error( "%s", text ); -} - -void QDECL Com_Printf( const char *msg, ... ) { - va_list argptr; - char text[1024]; - - va_start (argptr, msg); - vsprintf (text, msg, argptr); - va_end (argptr); - - //TA: team arena UI based console - if( cg.numConsoleLines == MAX_CONSOLE_LINES ) - CG_RemoveConsoleLine( ); - - if( cg.consoleValid ) - { - strcat( cg.consoleText, text ); - cg.consoleLines[ cg.numConsoleLines ].time = cg.time; - cg.consoleLines[ cg.numConsoleLines ].length = strlen( text ); - cg.numConsoleLines++; - } - - CG_Printf ("%s", text); -} - - - -/* -================ -CG_Argv -================ -*/ -const char *CG_Argv( int arg ) -{ - static char buffer[ MAX_STRING_CHARS ]; - - trap_Argv( arg, buffer, sizeof( buffer ) ); - - return buffer; -} - - -//======================================================================== - -/* -================= -CG_FileExists - -Test if a specific file exists or not -================= -*/ -qboolean CG_FileExists( char *filename ) -{ - fileHandle_t f; - - if( trap_FS_FOpenFile( filename, &f, FS_READ ) > 0 ) - { - //file exists so close it - trap_FS_FCloseFile( f ); - - return qtrue; - } - else - return qfalse; -} - -/* -================= -CG_RegisterSounds - -called during a precache command -================= -*/ -static void CG_RegisterSounds( void ) -{ - int i; - char name[ MAX_QPATH ]; - const char *soundName; - - cgs.media.alienStageTransition = trap_S_RegisterSound( "sound/announcements/overmindevolved.wav", qtrue ); - cgs.media.humanStageTransition = trap_S_RegisterSound( "sound/announcements/reinforcement.wav", qtrue ); - - cgs.media.alienOvermindAttack = trap_S_RegisterSound( "sound/announcements/overmindattack.wav", qtrue ); - cgs.media.alienOvermindDying = trap_S_RegisterSound( "sound/announcements/overminddying.wav", qtrue ); - cgs.media.alienOvermindSpawns = trap_S_RegisterSound( "sound/announcements/overmindspawns.wav", qtrue ); - - cgs.media.alienL1Grab = trap_S_RegisterSound( "sound/player/level1/grab.wav", qtrue ); - cgs.media.alienL4ChargePrepare = trap_S_RegisterSound( "sound/player/level4/charge_prepare.wav", qtrue ); - cgs.media.alienL4ChargeStart = trap_S_RegisterSound( "sound/player/level4/charge_start.wav", qtrue ); - - cgs.media.tracerSound = trap_S_RegisterSound( "sound/weapons/machinegun/buletby1.wav", qfalse ); //FIXME - cgs.media.selectSound = trap_S_RegisterSound( "sound/weapons/change.wav", qfalse ); - - cgs.media.talkSound = trap_S_RegisterSound( "sound/player/talk.wav", qfalse ); //FIXME - cgs.media.landSound = trap_S_RegisterSound( "sound/player/land1.wav", qfalse ); //FIXME - - cgs.media.watrInSound = trap_S_RegisterSound( "sound/player/watr_in.wav", qfalse ); //FIXME - cgs.media.watrOutSound = trap_S_RegisterSound( "sound/player/watr_out.wav", qfalse ); //FIXME - cgs.media.watrUnSound = trap_S_RegisterSound( "sound/player/watr_un.wav", qfalse ); //FIXME - - cgs.media.disconnectSound = trap_S_RegisterSound( "sound/world/telein.wav", qfalse ); //FIXME - - //FIXME - for( i = 0; i < 4; i++ ) - { - Com_sprintf( name, sizeof( name ), "sound/player/footsteps/step%i.wav", i + 1 ); - cgs.media.footsteps[ FOOTSTEP_NORMAL ][ i ] = trap_S_RegisterSound( name, qfalse ); - - Com_sprintf( name, sizeof( name ), "sound/player/footsteps/boot%i.wav", i + 1 ); - cgs.media.footsteps[ FOOTSTEP_BOOT ][ i ] = trap_S_RegisterSound( name, qfalse ); - - Com_sprintf( name, sizeof( name ), "sound/player/footsteps/flesh%i.wav", i + 1 ); - cgs.media.footsteps[ FOOTSTEP_FLESH ][ i ] = trap_S_RegisterSound( name, qfalse ); - - Com_sprintf( name, sizeof( name ), "sound/player/footsteps/mech%i.wav", i + 1 ); - cgs.media.footsteps[ FOOTSTEP_MECH ][ i ] = trap_S_RegisterSound( name, qfalse ); - - Com_sprintf( name, sizeof( name ), "sound/player/footsteps/energy%i.wav", i + 1 ); - cgs.media.footsteps[ FOOTSTEP_ENERGY ][ i ] = trap_S_RegisterSound( name, qfalse ); - - Com_sprintf( name, sizeof( name ), "sound/player/footsteps/splash%i.wav", i + 1 ); - cgs.media.footsteps[ FOOTSTEP_SPLASH ][ i ] = trap_S_RegisterSound( name, qfalse ); - - Com_sprintf( name, sizeof( name ), "sound/player/footsteps/clank%i.wav", i + 1 ); - cgs.media.footsteps[ FOOTSTEP_METAL ][ i ] = trap_S_RegisterSound( name, qfalse ); - } - - for( i = 1 ; i < MAX_SOUNDS ; i++ ) - { - soundName = CG_ConfigString( CS_SOUNDS + i ); - - if( !soundName[ 0 ] ) - break; - - if( soundName[ 0 ] == '*' ) - continue; // custom sound - - cgs.gameSounds[ i ] = trap_S_RegisterSound( soundName, qfalse ); - } - - cgs.media.jetpackDescendSound = trap_S_RegisterSound( "sound/upgrades/jetpack/low.wav", qfalse ); - cgs.media.jetpackIdleSound = trap_S_RegisterSound( "sound/upgrades/jetpack/idle.wav", qfalse ); - cgs.media.jetpackAscendSound = trap_S_RegisterSound( "sound/upgrades/jetpack/hi.wav", qfalse ); - - cgs.media.medkitUseSound = trap_S_RegisterSound( "sound/upgrades/medkit/medkit.wav", qfalse ); - - cgs.media.alienEvolveSound = trap_S_RegisterSound( "sound/player/alienevolve.wav", qfalse ); - - cgs.media.alienBuildableExplosion = trap_S_RegisterSound( "sound/buildables/alien/explosion.wav", qfalse ); - cgs.media.alienBuildableDamage = trap_S_RegisterSound( "sound/buildables/alien/damage.wav", qfalse ); - cgs.media.alienBuildablePrebuild = trap_S_RegisterSound( "sound/buildables/alien/prebuild.wav", qfalse ); - - cgs.media.humanBuildableExplosion = trap_S_RegisterSound( "sound/buildables/human/explosion.wav", qfalse ); - cgs.media.humanBuildablePrebuild = trap_S_RegisterSound( "sound/buildables/human/prebuild.wav", qfalse ); - - for( i = 0; i < 4; i++ ) - cgs.media.humanBuildableDamage[ i ] = trap_S_RegisterSound( - va( "sound/buildables/human/damage%d.wav", i ), qfalse ); - - cgs.media.hgrenb1aSound = trap_S_RegisterSound( "sound/weapons/grenade/hgrenb1a.wav", qfalse ); //FIXME - cgs.media.hgrenb2aSound = trap_S_RegisterSound( "sound/weapons/grenade/hgrenb2a.wav", qfalse ); //FIXME - - cgs.media.repeaterUseSound = trap_S_RegisterSound( "sound/buildables/repeater/use.wav", qfalse ); - - cgs.media.buildableRepairSound = trap_S_RegisterSound( "sound/buildables/human/repair.wav", qfalse ); - cgs.media.buildableRepairedSound = trap_S_RegisterSound( "sound/buildables/human/repaired.wav", qfalse ); - - cgs.media.lCannonWarningSound = trap_S_RegisterSound( "models/weapons/lcannon/warning.wav", qfalse ); -} - - -//=================================================================================== - - -/* -================= -CG_RegisterGraphics - -This function may execute for a couple of minutes with a slow disk. -================= -*/ -static void CG_RegisterGraphics( void ) -{ - int i; - static char *sb_nums[ 11 ] = - { - "gfx/2d/numbers/zero_32b", - "gfx/2d/numbers/one_32b", - "gfx/2d/numbers/two_32b", - "gfx/2d/numbers/three_32b", - "gfx/2d/numbers/four_32b", - "gfx/2d/numbers/five_32b", - "gfx/2d/numbers/six_32b", - "gfx/2d/numbers/seven_32b", - "gfx/2d/numbers/eight_32b", - "gfx/2d/numbers/nine_32b", - "gfx/2d/numbers/minus_32b", - }; - static char *buildWeaponTimerPieShaders[ 8 ] = - { - "ui/assets/neutral/1_5pie", - "ui/assets/neutral/3_0pie", - "ui/assets/neutral/4_5pie", - "ui/assets/neutral/6_0pie", - "ui/assets/neutral/7_5pie", - "ui/assets/neutral/9_0pie", - "ui/assets/neutral/10_5pie", - "ui/assets/neutral/12_0pie", - }; - - // clear any references to old media - memset( &cg.refdef, 0, sizeof( cg.refdef ) ); - trap_R_ClearScene( ); - - trap_R_LoadWorldMap( cgs.mapname ); - CG_UpdateMediaFraction( 0.66f ); - - for( i = 0; i < 11; i++ ) - cgs.media.numberShaders[ i ] = trap_R_RegisterShader( sb_nums[ i ] ); - - cgs.media.viewBloodShader = trap_R_RegisterShader( "gfx/damage/fullscreen_painblend" ); //FIXME - - cgs.media.connectionShader = trap_R_RegisterShader( "disconnected" ); //FIXME? - - cgs.media.creepShader = trap_R_RegisterShader( "creep" ); - - cgs.media.scannerBlipShader = trap_R_RegisterShader( "gfx/2d/blip" ); - cgs.media.scannerLineShader = trap_R_RegisterShader( "gfx/2d/stalk" ); - - cgs.media.tracerShader = trap_R_RegisterShader( "gfx/misc/tracer" ); //FIXME - cgs.media.selectShader = trap_R_RegisterShader( "gfx/2d/select" ); - - cgs.media.backTileShader = trap_R_RegisterShader( "gfx/2d/backtile" ); //FIXME - - - //TA: building shaders - cgs.media.greenBuildShader = trap_R_RegisterShader("gfx/2d/greenbuild" ); - cgs.media.redBuildShader = trap_R_RegisterShader("gfx/2d/redbuild" ); - cgs.media.noPowerShader = trap_R_RegisterShader("gfx/2d/nopower" ); - cgs.media.humanSpawningShader = trap_R_RegisterShader("models/buildables/telenode/rep_cyl" ); - - for( i = 0; i < 8; i++ ) - cgs.media.buildWeaponTimerPie[ i ] = trap_R_RegisterShader( buildWeaponTimerPieShaders[ i ] ); - - cgs.media.upgradeClassIconShader = trap_R_RegisterShader( "icons/icona_upgrade.tga" ); - - cgs.media.balloonShader = trap_R_RegisterShader( "sprites/balloon3" ); //FIXME? - - cgs.media.disconnectPS = CG_RegisterParticleSystem( "disconnectPS" ); - - CG_UpdateMediaFraction( 0.7f ); - - memset( cg_weapons, 0, sizeof( cg_weapons ) ); - memset( cg_upgrades, 0, sizeof( cg_upgrades ) ); - - cgs.media.shadowMarkShader = trap_R_RegisterShader( "markShadow" ); //FIXME - cgs.media.wakeMarkShader = trap_R_RegisterShader( "wake" ); //FIXME - - cgs.media.poisonCloudPS = CG_RegisterParticleSystem( "poisonCloudPS" ); - cgs.media.alienEvolvePS = CG_RegisterParticleSystem( "alienEvolvePS" ); - cgs.media.alienAcidTubePS = CG_RegisterParticleSystem( "alienAcidTubePS" ); - - cgs.media.jetPackDescendPS = CG_RegisterParticleSystem( "jetPackDescendPS" ); - cgs.media.jetPackHoverPS = CG_RegisterParticleSystem( "jetPackHoverPS" ); - cgs.media.jetPackAscendPS = CG_RegisterParticleSystem( "jetPackAscendPS" ); - - cgs.media.humanBuildableDamagedPS = CG_RegisterParticleSystem( "humanBuildableDamagedPS" ); - cgs.media.alienBuildableDamagedPS = CG_RegisterParticleSystem( "alienBuildableDamagedPS" ); - cgs.media.humanBuildableDestroyedPS = CG_RegisterParticleSystem( "humanBuildableDestroyedPS" ); - cgs.media.alienBuildableDestroyedPS = CG_RegisterParticleSystem( "alienBuildableDestroyedPS" ); - - cgs.media.alienBleedPS = CG_RegisterParticleSystem( "alienBleedPS" ); - cgs.media.humanBleedPS = CG_RegisterParticleSystem( "humanBleedPS" ); - - // register the inline models - cgs.numInlineModels = trap_CM_NumInlineModels( ); - - for( i = 1; i < cgs.numInlineModels; i++ ) - { - char name[ 10 ]; - vec3_t mins, maxs; - int j; - - Com_sprintf( name, sizeof( name ), "*%i", i ); - - cgs.inlineDrawModel[ i ] = trap_R_RegisterModel( name ); - trap_R_ModelBounds( cgs.inlineDrawModel[ i ], mins, maxs ); - - for( j = 0 ; j < 3 ; j++ ) - cgs.inlineModelMidpoints[ i ][ j ] = mins[ j ] + 0.5 * ( maxs[ j ] - mins[ j ] ); - } - - // register all the server specified models - for( i = 1; i < MAX_MODELS; i++ ) - { - const char *modelName; - - modelName = CG_ConfigString( CS_MODELS + i ); - - if( !modelName[ 0 ] ) - break; - - cgs.gameModels[ i ] = trap_R_RegisterModel( modelName ); - } - - CG_UpdateMediaFraction( 0.8f ); - - // register all the server specified shaders - for( i = 1; i < MAX_SHADERS; i++ ) - { - const char *shaderName; - - shaderName = CG_ConfigString( CS_SHADERS + i ); - - if( !shaderName[ 0 ] ) - break; - - cgs.gameShaders[ i ] = trap_R_RegisterShader( shaderName ); - } - - CG_UpdateMediaFraction( 0.9f ); - - // register all the server specified particle systems - for( i = 1; i < MAX_GAME_PARTICLE_SYSTEMS; i++ ) - { - const char *psName; - - psName = CG_ConfigString( CS_PARTICLE_SYSTEMS + i ); - - if( !psName[ 0 ] ) - break; - - cgs.gameParticleSystems[ i ] = CG_RegisterParticleSystem( (char *)psName ); - } -} - - -/* -======================= -CG_BuildSpectatorString - -======================= -*/ -void CG_BuildSpectatorString( void ) -{ - int i; - - cg.spectatorList[ 0 ] = 0; - - for( i = 0; i < MAX_CLIENTS; i++ ) - { - if( cgs.clientinfo[ i ].infoValid && cgs.clientinfo[ i ].team == PTE_NONE ) - Q_strcat( cg.spectatorList, sizeof( cg.spectatorList ), va( "%s " S_COLOR_WHITE, cgs.clientinfo[ i ].name ) ); - } - - i = strlen( cg.spectatorList ); - - if( i != cg.spectatorLen ) - { - cg.spectatorLen = i; - cg.spectatorWidth = -1; - } -} - - - -/* -=================== -CG_RegisterClients - -=================== -*/ -static void CG_RegisterClients( void ) -{ - int i; - - cg.charModelFraction = 0.0f; - - //precache all the models/sounds/etc - for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ ) - { - CG_PrecacheClientInfo( i, BG_FindModelNameForClass( i ), - BG_FindSkinNameForClass( i ) ); - - cg.charModelFraction = (float)i / (float)PCL_NUM_CLASSES; - trap_UpdateScreen( ); - } - - cgs.media.larmourHeadSkin = trap_R_RegisterSkin( "models/players/human_base/head_light.skin" ); - cgs.media.larmourLegsSkin = trap_R_RegisterSkin( "models/players/human_base/lower_light.skin" ); - cgs.media.larmourTorsoSkin = trap_R_RegisterSkin( "models/players/human_base/upper_light.skin" ); - - cgs.media.jetpackModel = trap_R_RegisterModel( "models/players/human_base/jetpack.md3" ); - cgs.media.jetpackFlashModel = trap_R_RegisterModel( "models/players/human_base/jetpack_flash.md3" ); - cgs.media.battpackModel = trap_R_RegisterModel( "models/players/human_base/battpack.md3" ); - - cg.charModelFraction = 1.0f; - trap_UpdateScreen( ); - - //load all the clientinfos of clients already connected to the server - for( i = 0; i < MAX_CLIENTS; i++ ) - { - const char *clientInfo; - - clientInfo = CG_ConfigString( CS_PLAYERS + i ); - if( !clientInfo[ 0 ] ) - continue; - - CG_NewClientInfo( i ); - } - - CG_BuildSpectatorString( ); -} - -//=========================================================================== - -/* -================= -CG_ConfigString -================= -*/ -const char *CG_ConfigString( int index ) -{ - if( index < 0 || index >= MAX_CONFIGSTRINGS ) - CG_Error( "CG_ConfigString: bad index: %i", index ); - - return cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ]; -} - -//================================================================== - -/* -====================== -CG_StartMusic - -====================== -*/ -void CG_StartMusic( void ) -{ - char *s; - char parm1[ MAX_QPATH ], parm2[ MAX_QPATH ]; - - // start the background music - s = (char *)CG_ConfigString( CS_MUSIC ); - Q_strncpyz( parm1, COM_Parse( &s ), sizeof( parm1 ) ); - Q_strncpyz( parm2, COM_Parse( &s ), sizeof( parm2 ) ); - - trap_S_StartBackgroundTrack( parm1, parm2 ); -} - -// -// ============================== -// new hud stuff ( mission pack ) -// ============================== -// -char *CG_GetMenuBuffer( const char *filename ) -{ - int len; - fileHandle_t f; - static char buf[ MAX_MENUFILE ]; - - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - - if( !f ) - { - trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) ); - return NULL; - } - - if( len >= MAX_MENUFILE ) - { - trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", - filename, len, MAX_MENUFILE ) ); - trap_FS_FCloseFile( f ); - return NULL; - } - - trap_FS_Read( buf, len, f ); - buf[len] = 0; - trap_FS_FCloseFile( f ); - - return buf; -} - -qboolean CG_Asset_Parse( int handle ) -{ - pc_token_t token; - const char *tempStr; - - if( !trap_PC_ReadToken( handle, &token ) ) - return qfalse; - - if( Q_stricmp( token.string, "{" ) != 0 ) - return qfalse; - - while( 1 ) - { - if( !trap_PC_ReadToken( handle, &token ) ) - return qfalse; - - if( Q_stricmp( token.string, "}" ) == 0 ) - return qtrue; - - // font - if( Q_stricmp( token.string, "font" ) == 0 ) - { - int pointSize; - - if( !PC_String_Parse( handle, &tempStr ) || !PC_Int_Parse( handle, &pointSize ) ) - return qfalse; - - cgDC.registerFont( tempStr, pointSize, &cgDC.Assets.textFont ); - continue; - } - - // smallFont - if( Q_stricmp( token.string, "smallFont" ) == 0 ) - { - int pointSize; - - if( !PC_String_Parse( handle, &tempStr ) || !PC_Int_Parse( handle, &pointSize ) ) - return qfalse; - - cgDC.registerFont( tempStr, pointSize, &cgDC.Assets.smallFont ); - continue; - } - - // font - if( Q_stricmp( token.string, "bigfont" ) == 0 ) - { - int pointSize; - - if( !PC_String_Parse( handle, &tempStr ) || !PC_Int_Parse( handle, &pointSize ) ) - return qfalse; - - cgDC.registerFont( tempStr, pointSize, &cgDC.Assets.bigFont ); - continue; - } - - // gradientbar - if( Q_stricmp( token.string, "gradientbar" ) == 0 ) - { - if( !PC_String_Parse( handle, &tempStr ) ) - return qfalse; - - cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( tempStr ); - continue; - } - - // enterMenuSound - if( Q_stricmp( token.string, "menuEnterSound" ) == 0 ) - { - if( !PC_String_Parse( handle, &tempStr ) ) - return qfalse; - - cgDC.Assets.menuEnterSound = trap_S_RegisterSound( tempStr, qfalse ); - continue; - } - - // exitMenuSound - if( Q_stricmp( token.string, "menuExitSound" ) == 0 ) - { - if( !PC_String_Parse( handle, &tempStr ) ) - return qfalse; - - cgDC.Assets.menuExitSound = trap_S_RegisterSound( tempStr, qfalse ); - continue; - } - - // itemFocusSound - if( Q_stricmp( token.string, "itemFocusSound" ) == 0 ) - { - if( !PC_String_Parse( handle, &tempStr ) ) - return qfalse; - - cgDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr, qfalse ); - continue; - } - - // menuBuzzSound - if( Q_stricmp( token.string, "menuBuzzSound" ) == 0 ) - { - if( !PC_String_Parse( handle, &tempStr ) ) - return qfalse; - - cgDC.Assets.menuBuzzSound = trap_S_RegisterSound( tempStr, qfalse ); - continue; - } - - if( Q_stricmp( token.string, "cursor" ) == 0 ) - { - if( !PC_String_Parse( handle, &cgDC.Assets.cursorStr ) ) - return qfalse; - - cgDC.Assets.cursor = trap_R_RegisterShaderNoMip( cgDC.Assets.cursorStr ); - continue; - } - - if( Q_stricmp( token.string, "fadeClamp" ) == 0 ) - { - if( !PC_Float_Parse( handle, &cgDC.Assets.fadeClamp ) ) - return qfalse; - - continue; - } - - if( Q_stricmp( token.string, "fadeCycle" ) == 0 ) - { - if( !PC_Int_Parse( handle, &cgDC.Assets.fadeCycle ) ) - return qfalse; - - continue; - } - - if( Q_stricmp( token.string, "fadeAmount" ) == 0 ) - { - if( !PC_Float_Parse( handle, &cgDC.Assets.fadeAmount ) ) - return qfalse; - - continue; - } - - if( Q_stricmp( token.string, "shadowX" ) == 0 ) - { - if( !PC_Float_Parse( handle, &cgDC.Assets.shadowX ) ) - return qfalse; - - continue; - } - - if( Q_stricmp( token.string, "shadowY" ) == 0 ) - { - if( !PC_Float_Parse( handle, &cgDC.Assets.shadowY ) ) - return qfalse; - - continue; - } - - if( Q_stricmp( token.string, "shadowColor" ) == 0 ) - { - if( !PC_Color_Parse( handle, &cgDC.Assets.shadowColor ) ) - return qfalse; - - cgDC.Assets.shadowFadeClamp = cgDC.Assets.shadowColor[ 3 ]; - continue; - } - } - - return qfalse; // bk001204 - why not? -} - -void CG_ParseMenu( const char *menuFile ) -{ - pc_token_t token; - int handle; - - handle = trap_PC_LoadSource( menuFile ); - - if( !handle ) - handle = trap_PC_LoadSource( "ui/testhud.menu" ); - - if( !handle ) - return; - - while( 1 ) - { - if( !trap_PC_ReadToken( handle, &token ) ) - break; - - //if ( Q_stricmp( token, "{" ) ) { - // Com_Printf( "Missing { in menu file\n" ); - // break; - //} - - //if ( menuCount == MAX_MENUS ) { - // Com_Printf( "Too many menus!\n" ); - // break; - //} - - if( token.string[ 0 ] == '}' ) - break; - - if( Q_stricmp( token.string, "assetGlobalDef" ) == 0 ) - { - if( CG_Asset_Parse( handle ) ) - continue; - else - break; - } - - - if( Q_stricmp( token.string, "menudef" ) == 0 ) - { - // start a new menu - Menu_New( handle ); - } - } - - trap_PC_FreeSource( handle ); -} - -qboolean CG_Load_Menu( char **p ) -{ - char *token; - - token = COM_ParseExt( p, qtrue ); - - if( token[ 0 ] != '{' ) - return qfalse; - - while( 1 ) - { - token = COM_ParseExt( p, qtrue ); - - if( Q_stricmp( token, "}" ) == 0 ) - return qtrue; - - if( !token || token[ 0 ] == 0 ) - return qfalse; - - CG_ParseMenu( token ); - } - return qfalse; -} - - - -void CG_LoadMenus( const char *menuFile ) -{ - char *token; - char *p; - int len, start; - fileHandle_t f; - static char buf[ MAX_MENUDEFFILE ]; - - start = trap_Milliseconds( ); - - len = trap_FS_FOpenFile( menuFile, &f, FS_READ ); - - if( !f ) - { - trap_Error( va( S_COLOR_YELLOW "menu file not found: %s, using default\n", menuFile ) ); - len = trap_FS_FOpenFile( "ui/hud.txt", &f, FS_READ ); - - if( !f ) - trap_Error( va( S_COLOR_RED "default menu file not found: ui/hud.txt, unable to continue!\n", menuFile ) ); - } - - if( len >= MAX_MENUDEFFILE ) - { - trap_Error( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", - menuFile, len, MAX_MENUDEFFILE ) ); - trap_FS_FCloseFile( f ); - return; - } - - trap_FS_Read( buf, len, f ); - buf[ len ] = 0; - trap_FS_FCloseFile( f ); - - COM_Compress( buf ); - - Menu_Reset( ); - - p = buf; - - while( 1 ) - { - token = COM_ParseExt( &p, qtrue ); - - if( !token || token[ 0 ] == 0 || token[ 0 ] == '}' ) - break; - - if( Q_stricmp( token, "}" ) == 0 ) - break; - - if( Q_stricmp( token, "loadmenu" ) == 0 ) - { - if( CG_Load_Menu( &p ) ) - continue; - else - break; - } - } - - Com_Printf( "UI menu load time = %d milli seconds\n", trap_Milliseconds( ) - start ); -} - - - -static qboolean CG_OwnerDrawHandleKey( int ownerDraw, int flags, float *special, int key ) -{ - return qfalse; -} - - -static int CG_FeederCount( float feederID ) -{ - int i, count = 0; - - if( feederID == FEEDER_ALIENTEAM_LIST ) - { - for( i = 0; i < cg.numScores; i++ ) - { - if( cg.scores[ i ].team == PTE_ALIENS ) - count++; - } - } - else if( feederID == FEEDER_HUMANTEAM_LIST ) - { - for( i = 0; i < cg.numScores; i++ ) - { - if( cg.scores[ i ].team == PTE_HUMANS ) - count++; - } - } - - return count; -} - - -void CG_SetScoreSelection( void *p ) -{ - menuDef_t *menu = (menuDef_t*)p; - playerState_t *ps = &cg.snap->ps; - int i, alien, human; - int feeder; - - alien = human = 0; - - for( i = 0; i < cg.numScores; i++ ) - { - if( cg.scores[ i ].team == PTE_ALIENS ) - alien++; - else if( cg.scores[ i ].team == PTE_HUMANS ) - human++; - - if( ps->clientNum == cg.scores[ i ].client ) - cg.selectedScore = i; - } - - if( menu == NULL ) - // just interested in setting the selected score - return; - - feeder = FEEDER_ALIENTEAM_LIST; - i = alien; - - if( cg.scores[ cg.selectedScore ].team == PTE_HUMANS ) - { - feeder = FEEDER_HUMANTEAM_LIST; - i = human; - } - - Menu_SetFeederSelection(menu, feeder, i, NULL); -} - -// FIXME: might need to cache this info -static clientInfo_t * CG_InfoFromScoreIndex( int index, int team, int *scoreIndex ) -{ - int i, count; - count = 0; - - for( i = 0; i < cg.numScores; i++ ) - { - if( cg.scores[ i ].team == team ) - { - if( count == index ) - { - *scoreIndex = i; - return &cgs.clientinfo[ cg.scores[ i ].client ]; - } - count++; - } - } - - *scoreIndex = index; - return &cgs.clientinfo[ cg.scores[ index ].client ]; -} - -static const char *CG_FeederItemText( float feederID, int index, int column, qhandle_t *handle ) -{ - int scoreIndex = 0; - clientInfo_t *info = NULL; - int team = -1; - score_t *sp = NULL; - qboolean showIcons = qfalse; - - *handle = -1; - - if( feederID == FEEDER_ALIENTEAM_LIST ) - team = PTE_ALIENS; - else if( feederID == FEEDER_HUMANTEAM_LIST ) - team = PTE_HUMANS; - - info = CG_InfoFromScoreIndex( index, team, &scoreIndex ); - sp = &cg.scores[ scoreIndex ]; - - if( ( atoi( CG_ConfigString( CS_CLIENTS_READY ) ) & ( 1 << sp->client ) ) && - cg.intermissionStarted ) - showIcons = qfalse; - else if( cg.snap->ps.pm_type == PM_SPECTATOR || cg.snap->ps.pm_flags & PMF_FOLLOW || - team == cg.snap->ps.stats[ STAT_PTEAM ] || cg.intermissionStarted ) - showIcons = qtrue; - - if( info && info->infoValid ) - { - switch( column ) - { - case 0: - if( showIcons ) - { - if( sp->weapon != WP_NONE ) - *handle = cg_weapons[ sp->weapon ].weaponIcon; - } - break; - - case 1: - if( showIcons ) - { - if( sp->team == PTE_HUMANS && sp->upgrade != UP_NONE ) - *handle = cg_upgrades[ sp->upgrade ].upgradeIcon; - else if( sp->team == PTE_ALIENS ) - { - switch( sp->weapon ) - { - case WP_ABUILD2: - case WP_ALEVEL1_UPG: - case WP_ALEVEL2_UPG: - case WP_ALEVEL3_UPG: - *handle = cgs.media.upgradeClassIconShader; - break; - - default: - break; - } - } - } - break; - - case 2: - if( ( atoi( CG_ConfigString( CS_CLIENTS_READY ) ) & ( 1 << sp->client ) ) && - cg.intermissionStarted ) - return "Ready"; - break; - - case 3: - return info->name; - break; - - case 4: - return va( "%d", info->score ); - break; - - case 5: - return va( "%4d", sp->time ); - break; - - case 6: - if( sp->ping == -1 ) - return "connecting"; - - return va( "%4d", sp->ping ); - break; - } - } - - return ""; -} - -static qhandle_t CG_FeederItemImage( float feederID, int index ) -{ - return 0; -} - -static void CG_FeederSelection( float feederID, int index ) -{ - int i, count; - int team = ( feederID == FEEDER_ALIENTEAM_LIST ) ? PTE_ALIENS : PTE_HUMANS; - count = 0; - - for( i = 0; i < cg.numScores; i++ ) - { - if( cg.scores[ i ].team == team ) - { - if( index == count ) - cg.selectedScore = i; - - count++; - } - } -} - -static float CG_Cvar_Get( const char *cvar ) -{ - char buff[ 128 ]; - - memset( buff, 0, sizeof( buff ) ); - trap_Cvar_VariableStringBuffer( cvar, buff, sizeof( buff ) ); - return atof( buff ); -} - -void CG_Text_PaintWithCursor( float x, float y, float scale, vec4_t color, const char *text, - int cursorPos, char cursor, int limit, int style ) -{ - CG_Text_Paint( x, y, scale, color, text, 0, limit, style ); -} - -static int CG_OwnerDrawWidth( int ownerDraw, float scale ) -{ - switch( ownerDraw ) - { - case CG_KILLER: - return CG_Text_Width( CG_GetKillerText( ), scale, 0 ); - break; - } - - return 0; -} - -static int CG_PlayCinematic( const char *name, float x, float y, float w, float h ) -{ - return trap_CIN_PlayCinematic( name, x, y, w, h, CIN_loop ); -} - -static void CG_StopCinematic( int handle ) -{ - trap_CIN_StopCinematic( handle ); -} - -static void CG_DrawCinematic( int handle, float x, float y, float w, float h ) -{ - trap_CIN_SetExtents( handle, x, y, w, h ); - trap_CIN_DrawCinematic( handle ); -} - -static void CG_RunCinematicFrame( int handle ) -{ - trap_CIN_RunCinematic( handle ); -} - -//TA: hack to prevent warning -static qboolean CG_OwnerDrawVisible( int parameter ) -{ - return qfalse; -} - -/* -================= -CG_LoadHudMenu -================= -*/ -void CG_LoadHudMenu( void ) -{ - char buff[ 1024 ]; - const char *hudSet; - - cgDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip; - cgDC.setColor = &trap_R_SetColor; - cgDC.drawHandlePic = &CG_DrawPic; - cgDC.drawStretchPic = &trap_R_DrawStretchPic; - cgDC.drawText = &CG_Text_Paint; - cgDC.textWidth = &CG_Text_Width; - cgDC.textHeight = &CG_Text_Height; - cgDC.registerModel = &trap_R_RegisterModel; - cgDC.modelBounds = &trap_R_ModelBounds; - cgDC.fillRect = &CG_FillRect; - cgDC.drawRect = &CG_DrawRect; - cgDC.drawSides = &CG_DrawSides; - cgDC.drawTopBottom = &CG_DrawTopBottom; - cgDC.clearScene = &trap_R_ClearScene; - cgDC.addRefEntityToScene = &trap_R_AddRefEntityToScene; - cgDC.renderScene = &trap_R_RenderScene; - cgDC.registerFont = &trap_R_RegisterFont; - cgDC.ownerDrawItem = &CG_OwnerDraw; - cgDC.getValue = &CG_GetValue; - cgDC.ownerDrawVisible = &CG_OwnerDrawVisible; - cgDC.runScript = &CG_RunMenuScript; - cgDC.getTeamColor = &CG_GetTeamColor; - cgDC.setCVar = trap_Cvar_Set; - cgDC.getCVarString = trap_Cvar_VariableStringBuffer; - cgDC.getCVarValue = CG_Cvar_Get; - cgDC.drawTextWithCursor = &CG_Text_PaintWithCursor; - //cgDC.setOverstrikeMode = &trap_Key_SetOverstrikeMode; - //cgDC.getOverstrikeMode = &trap_Key_GetOverstrikeMode; - cgDC.startLocalSound = &trap_S_StartLocalSound; - cgDC.ownerDrawHandleKey = &CG_OwnerDrawHandleKey; - cgDC.feederCount = &CG_FeederCount; - cgDC.feederItemImage = &CG_FeederItemImage; - cgDC.feederItemText = &CG_FeederItemText; - cgDC.feederSelection = &CG_FeederSelection; - //cgDC.setBinding = &trap_Key_SetBinding; - //cgDC.getBindingBuf = &trap_Key_GetBindingBuf; - //cgDC.keynumToStringBuf = &trap_Key_KeynumToStringBuf; - //cgDC.executeText = &trap_Cmd_ExecuteText; - cgDC.Error = &Com_Error; - cgDC.Print = &Com_Printf; - cgDC.ownerDrawWidth = &CG_OwnerDrawWidth; - //cgDC.Pause = &CG_Pause; - cgDC.registerSound = &trap_S_RegisterSound; - cgDC.startBackgroundTrack = &trap_S_StartBackgroundTrack; - cgDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack; - cgDC.playCinematic = &CG_PlayCinematic; - cgDC.stopCinematic = &CG_StopCinematic; - cgDC.drawCinematic = &CG_DrawCinematic; - cgDC.runCinematicFrame = &CG_RunCinematicFrame; - - Init_Display( &cgDC ); - - Menu_Reset( ); - - trap_Cvar_VariableStringBuffer( "cg_hudFiles", buff, sizeof( buff ) ); - hudSet = buff; - - if( hudSet[ 0 ] == '\0' ) - hudSet = "ui/hud.txt"; - - CG_LoadMenus( hudSet ); -} - -void CG_AssetCache( void ) -{ - cgDC.Assets.gradientBar = trap_R_RegisterShaderNoMip( ASSET_GRADIENTBAR ); - cgDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR ); - cgDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN ); - cgDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP ); - cgDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT ); - cgDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT ); - cgDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB ); - cgDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR ); - cgDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB ); -} - -/* -================= -CG_Init - -Called after every level change or subsystem restart -Will perform callbacks to make the loading info screen update. -================= -*/ -void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) -{ - const char *s; - - // clear everything - memset( &cgs, 0, sizeof( cgs ) ); - memset( &cg, 0, sizeof( cg ) ); - memset( cg_entities, 0, sizeof( cg_entities ) ); - - cg.clientNum = clientNum; - - cgs.processedSnapshotNum = serverMessageNum; - cgs.serverCommandSequence = serverCommandSequence; - - // load a few needed things before we do any screen updates - cgs.media.whiteShader = trap_R_RegisterShader( "white" ); - cgs.media.charsetShader = trap_R_RegisterShader( "gfx/2d/bigchars" ); - cgs.media.outlineShader = trap_R_RegisterShader( "outline" ); - - //inform UI to repress cursor whilst loading - trap_Cvar_Set( "ui_loading", "1" ); - - //TA: load overrides - BG_InitClassOverrides( ); - BG_InitBuildableOverrides( ); - - //TA: dyn memory - CG_InitMemory( ); - - CG_RegisterCvars( ); - - CG_InitConsoleCommands( ); - - //TA: moved up for LoadHudMenu - String_Init( ); - - //TA: TA UI - CG_AssetCache( ); - CG_LoadHudMenu( ); // load new hud stuff - - cg.weaponSelect = WP_NONE; - - // old servers - - // get the rendering configuration from the client system - trap_GetGlconfig( &cgs.glconfig ); - cgs.screenXScale = cgs.glconfig.vidWidth / 640.0; - cgs.screenYScale = cgs.glconfig.vidHeight / 480.0; - - // get the gamestate from the client system - trap_GetGameState( &cgs.gameState ); - - // check version - s = CG_ConfigString( CS_GAME_VERSION ); - - if( strcmp( s, GAME_VERSION ) ) - CG_Error( "Client/Server game mismatch: %s/%s", GAME_VERSION, s ); - - s = CG_ConfigString( CS_LEVEL_START_TIME ); - cgs.levelStartTime = atoi( s ); - - CG_ParseServerinfo( ); - - // load the new map - trap_CM_LoadMap( cgs.mapname ); - - cg.loading = qtrue; // force players to load instead of defer - - CG_LoadTrailSystems( ); - CG_UpdateMediaFraction( 0.05f ); - - CG_LoadParticleSystems( ); - CG_UpdateMediaFraction( 0.05f ); - - CG_RegisterSounds( ); - CG_UpdateMediaFraction( 0.60f ); - - CG_RegisterGraphics( ); - CG_UpdateMediaFraction( 0.90f ); - - CG_InitWeapons( ); - CG_UpdateMediaFraction( 0.95f ); - - CG_InitUpgrades( ); - CG_UpdateMediaFraction( 1.0f ); - - //TA: - CG_InitBuildables( ); - - CG_RegisterClients( ); // if low on memory, some clients will be deferred - - cg.loading = qfalse; // future players will be deferred - - CG_InitMarkPolys( ); - - // remove the last loading update - cg.infoScreenText[ 0 ] = 0; - - // Make sure we have update values (scores) - CG_SetConfigValues( ); - - CG_StartMusic( ); - - CG_ShaderStateChanged( ); - - trap_S_ClearLoopingSounds( qtrue ); - - cg.consoleValid = qtrue; - - trap_Cvar_Set( "ui_loading", "0" ); -} - -/* -================= -CG_Shutdown - -Called before every level change or subsystem restart -================= -*/ -void CG_Shutdown( void ) -{ - // some mods may need to do cleanup work here, - // like closing files or archiving session data -} diff --git a/src/cgame/cg_marks.c b/src/cgame/cg_marks.c deleted file mode 100644 index cc8979de..00000000 --- a/src/cgame/cg_marks.c +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_marks.c -- wall marks - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -/* -=================================================================== - -MARK POLYS - -=================================================================== -*/ - - -markPoly_t cg_activeMarkPolys; // double linked list -markPoly_t *cg_freeMarkPolys; // single linked list -markPoly_t cg_markPolys[ MAX_MARK_POLYS ]; -static int markTotal; - -/* -=================== -CG_InitMarkPolys - -This is called at startup and for tournement restarts -=================== -*/ -void CG_InitMarkPolys( void ) -{ - int i; - - memset( cg_markPolys, 0, sizeof( cg_markPolys ) ); - - cg_activeMarkPolys.nextMark = &cg_activeMarkPolys; - cg_activeMarkPolys.prevMark = &cg_activeMarkPolys; - cg_freeMarkPolys = cg_markPolys; - - for( i = 0; i < MAX_MARK_POLYS - 1; i++ ) - cg_markPolys[ i ].nextMark = &cg_markPolys[ i + 1 ]; -} - - -/* -================== -CG_FreeMarkPoly -================== -*/ -void CG_FreeMarkPoly( markPoly_t *le ) -{ - if( !le->prevMark ) - CG_Error( "CG_FreeLocalEntity: not active" ); - - // remove from the doubly linked active list - le->prevMark->nextMark = le->nextMark; - le->nextMark->prevMark = le->prevMark; - - // the free list is only singly linked - le->nextMark = cg_freeMarkPolys; - cg_freeMarkPolys = le; -} - -/* -=================== -CG_AllocMark - -Will allways succeed, even if it requires freeing an old active mark -=================== -*/ -markPoly_t *CG_AllocMark( void ) -{ - markPoly_t *le; - int time; - - if( !cg_freeMarkPolys ) - { - // no free entities, so free the one at the end of the chain - // remove the oldest active entity - time = cg_activeMarkPolys.prevMark->time; - - while( cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time ) - CG_FreeMarkPoly( cg_activeMarkPolys.prevMark ); - } - - le = cg_freeMarkPolys; - cg_freeMarkPolys = cg_freeMarkPolys->nextMark; - - memset( le, 0, sizeof( *le ) ); - - // link into the active list - le->nextMark = cg_activeMarkPolys.nextMark; - le->prevMark = &cg_activeMarkPolys; - cg_activeMarkPolys.nextMark->prevMark = le; - cg_activeMarkPolys.nextMark = le; - return le; -} - - - -/* -================= -CG_ImpactMark - -origin should be a point within a unit of the plane -dir should be the plane normal - -temporary marks will not be stored or randomly oriented, but immediately -passed to the renderer. -================= -*/ -#define MAX_MARK_FRAGMENTS 128 -#define MAX_MARK_POINTS 384 - -void CG_ImpactMark( qhandle_t markShader, const vec3_t origin, const vec3_t dir, - float orientation, float red, float green, float blue, float alpha, - qboolean alphaFade, float radius, qboolean temporary ) -{ - vec3_t axis[ 3 ]; - float texCoordScale; - vec3_t originalPoints[ 4 ]; - byte colors[ 4 ]; - int i, j; - int numFragments; - markFragment_t markFragments[ MAX_MARK_FRAGMENTS ], *mf; - vec3_t markPoints[ MAX_MARK_POINTS ]; - vec3_t projection; - - if( !cg_addMarks.integer ) - return; - - if( radius <= 0 ) - CG_Error( "CG_ImpactMark called with <= 0 radius" ); - - //if ( markTotal >= MAX_MARK_POLYS ) { - // return; - //} - - // create the texture axis - VectorNormalize2( dir, axis[ 0 ] ); - PerpendicularVector( axis[ 1 ], axis[ 0 ] ); - RotatePointAroundVector( axis[ 2 ], axis[ 0 ], axis[ 1 ], orientation ); - CrossProduct( axis[ 0 ], axis[ 2 ], axis[ 1 ] ); - - texCoordScale = 0.5 * 1.0 / radius; - - // create the full polygon - for( i = 0; i < 3; i++ ) - { - originalPoints[ 0 ][ i ] = origin[ i ] - radius * axis[ 1 ][ i ] - radius * axis[ 2 ][ i ]; - originalPoints[ 1 ][ i ] = origin[ i ] + radius * axis[ 1 ][ i ] - radius * axis[ 2 ][ i ]; - originalPoints[ 2 ][ i ] = origin[ i ] + radius * axis[ 1 ][ i ] + radius * axis[ 2 ][ i ]; - originalPoints[ 3 ][ i ] = origin[ i ] - radius * axis[ 1 ][ i ] + radius * axis[ 2 ][ i ]; - } - - // get the fragments - VectorScale( dir, -20, projection ); - numFragments = trap_CM_MarkFragments( 4, (void *)originalPoints, - projection, MAX_MARK_POINTS, markPoints[ 0 ], - MAX_MARK_FRAGMENTS, markFragments ); - - colors[ 0 ] = red * 255; - colors[ 1 ] = green * 255; - colors[ 2 ] = blue * 255; - colors[ 3 ] = alpha * 255; - - for( i = 0, mf = markFragments; i < numFragments; i++, mf++ ) - { - polyVert_t *v; - polyVert_t verts[ MAX_VERTS_ON_POLY ]; - markPoly_t *mark; - - // we have an upper limit on the complexity of polygons - // that we store persistantly - if( mf->numPoints > MAX_VERTS_ON_POLY ) - mf->numPoints = MAX_VERTS_ON_POLY; - - for( j = 0, v = verts; j < mf->numPoints; j++, v++ ) - { - vec3_t delta; - - VectorCopy( markPoints[ mf->firstPoint + j ], v->xyz ); - - VectorSubtract( v->xyz, origin, delta ); - v->st[ 0 ] = 0.5 + DotProduct( delta, axis[ 1 ] ) * texCoordScale; - v->st[ 1 ] = 0.5 + DotProduct( delta, axis[ 2 ] ) * texCoordScale; - *(int *)v->modulate = *(int *)colors; - } - - // if it is a temporary (shadow) mark, add it immediately and forget about it - if( temporary ) - { - trap_R_AddPolyToScene( markShader, mf->numPoints, verts ); - continue; - } - - // otherwise save it persistantly - mark = CG_AllocMark( ); - mark->time = cg.time; - mark->alphaFade = alphaFade; - mark->markShader = markShader; - mark->poly.numVerts = mf->numPoints; - mark->color[ 0 ] = red; - mark->color[ 1 ] = green; - mark->color[ 2 ] = blue; - mark->color[ 3 ] = alpha; - memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[ 0 ] ) ); - markTotal++; - } -} - - -/* -=============== -CG_AddMarks -=============== -*/ -#define MARK_TOTAL_TIME 10000 -#define MARK_FADE_TIME 1000 - -void CG_AddMarks( void ) -{ - int j; - markPoly_t *mp, *next; - int t; - int fade; - - if( !cg_addMarks.integer ) - return; - - mp = cg_activeMarkPolys.nextMark; - for ( ; mp != &cg_activeMarkPolys; mp = next ) - { - // grab next now, so if the local entity is freed we - // still have it - next = mp->nextMark; - - // see if it is time to completely remove it - if( cg.time > mp->time + MARK_TOTAL_TIME ) - { - CG_FreeMarkPoly( mp ); - continue; - } - - // fade all marks out with time - t = mp->time + MARK_TOTAL_TIME - cg.time; - if( t < MARK_FADE_TIME ) - { - fade = 255 * t / MARK_FADE_TIME; - if( mp->alphaFade ) - { - for( j = 0; j < mp->poly.numVerts; j++ ) - mp->verts[ j ].modulate[ 3 ] = fade; - } - else - { - for( j = 0; j < mp->poly.numVerts; j++ ) - { - mp->verts[ j ].modulate[ 0 ] = mp->color[ 0 ] * fade; - mp->verts[ j ].modulate[ 1 ] = mp->color[ 1 ] * fade; - mp->verts[ j ].modulate[ 2 ] = mp->color[ 2 ] * fade; - } - } - } - - trap_R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts ); - } -} - diff --git a/src/cgame/cg_mem.c b/src/cgame/cg_mem.c deleted file mode 100644 index 959bd4b0..00000000 --- a/src/cgame/cg_mem.c +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// -// cg_mem.c -// -// Golliwog: All rewritten to allow deallocation -// -// TA: (very) minor changes for client side operation -// thanks to Golliwog of Quake 3 Fortress ( http://www.q3f.com ) -// for this. - - -#include "cg_local.h" - -#define POOLSIZE (256 * 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 *CG_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 ) - CG_Error( "CG_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( cg_debugAlloc.integer ) - CG_Printf( "CG_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 ); - } - - CG_Error( "CG_Alloc: failed on allocation of %i bytes\n", size ); - return( NULL ); -} - -void CG_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( cg_debugAlloc.integer ) - CG_Printf( "CG_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 CG_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 CG_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 ) - CG_Error( "CG_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 - } -} diff --git a/src/cgame/cg_particles.c b/src/cgame/cg_particles.c deleted file mode 100644 index 64587360..00000000 --- a/src/cgame/cg_particles.c +++ /dev/null @@ -1,2551 +0,0 @@ -// cg_particles.c -- the particle system - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -static baseParticleSystem_t baseParticleSystems[ MAX_BASEPARTICLE_SYSTEMS ]; -static baseParticleEjector_t baseParticleEjectors[ MAX_BASEPARTICLE_EJECTORS ]; -static baseParticle_t baseParticles[ MAX_BASEPARTICLES ]; -static int numBaseParticleSystems = 0; -static int numBaseParticleEjectors = 0; -static int numBaseParticles = 0; - -static particleSystem_t particleSystems[ MAX_PARTICLE_SYSTEMS ]; -static particleEjector_t particleEjectors[ MAX_PARTICLE_EJECTORS ]; -static particle_t particles[ MAX_PARTICLES ]; -static particle_t *sortedParticles[ MAX_PARTICLES ]; -static particle_t *radixBuffer[ MAX_PARTICLES ]; - -/* -=============== -CG_LerpValues - -Lerp between two values -=============== -*/ -static float CG_LerpValues( float a, float b, float f ) -{ - if( b == PARTICLES_SAME_AS_INITIAL ) - return a; - else - return ( (a) + (f) * ( (b) - (a) ) ); -} - -/* -=============== -CG_RandomiseValue - -Randomise some value by some variance -=============== -*/ -static float CG_RandomiseValue( float value, float variance ) -{ - if( value != 0.0f ) - return value * ( 1.0f + ( random( ) * variance ) ); - else - return random( ) * variance; -} - -/* -=============== -CG_SpreadVector - -Randomly spread a vector by some amount -=============== -*/ -static void CG_SpreadVector( vec3_t v, float spread ) -{ - vec3_t p, r1, r2; - float randomSpread = crandom( ) * spread; - float randomRotation = random( ) * 360.0f; - - PerpendicularVector( p, v ); - - RotatePointAroundVector( r1, p, v, randomSpread ); - RotatePointAroundVector( r2, v, r1, randomRotation ); - - VectorCopy( r2, v ); -} - -/* -=============== -CG_DestroyParticle - -Destroy an individual particle -=============== -*/ -static void CG_DestroyParticle( particle_t *p, vec3_t impactNormal ) -{ - //this particle has an onDeath particle system attached - if( p->class->onDeathSystemName[ 0 ] != '\0' ) - { - particleSystem_t *ps; - - ps = CG_SpawnNewParticleSystem( p->class->onDeathSystemHandle ); - - if( CG_IsParticleSystemValid( &ps ) ) - { - if( impactNormal ) - CG_SetParticleSystemNormal( ps, impactNormal ); - - CG_SetAttachmentPoint( &ps->attachment, p->origin ); - CG_AttachToPoint( &ps->attachment ); - } - } - - p->valid = qfalse; - - //this gives other systems a couple of - //frames to realise the particle is gone - p->frameWhenInvalidated = cg.clientFrame; -} - -/* -=============== -CG_SpawnNewParticle - -Introduce a new particle into the world -=============== -*/ -static particle_t *CG_SpawnNewParticle( baseParticle_t *bp, particleEjector_t *parent ) -{ - int i, j; - particle_t *p = NULL; - particleEjector_t *pe = parent; - particleSystem_t *ps = parent->parent; - vec3_t attachmentPoint, attachmentVelocity; - vec3_t transform[ 3 ]; - - for( i = 0; i < MAX_PARTICLES; i++ ) - { - p = &particles[ i ]; - - //FIXME: the + 1 may be unnecessary - if( !p->valid && cg.clientFrame > p->frameWhenInvalidated + 1 ) - { - memset( p, 0, sizeof( particle_t ) ); - - //found a free slot - p->class = bp; - p->parent = pe; - - p->birthTime = cg.time; - p->lifeTime = (int)CG_RandomiseValue( (float)bp->lifeTime, bp->lifeTimeRandFrac ); - - p->radius.delay = (int)CG_RandomiseValue( (float)bp->radius.delay, bp->radius.delayRandFrac ); - p->radius.initial = CG_RandomiseValue( bp->radius.initial, bp->radius.initialRandFrac ); - p->radius.final = CG_RandomiseValue( bp->radius.final, bp->radius.finalRandFrac ); - - p->alpha.delay = (int)CG_RandomiseValue( (float)bp->alpha.delay, bp->alpha.delayRandFrac ); - p->alpha.initial = CG_RandomiseValue( bp->alpha.initial, bp->alpha.initialRandFrac ); - p->alpha.final = CG_RandomiseValue( bp->alpha.final, bp->alpha.finalRandFrac ); - - p->rotation.delay = (int)CG_RandomiseValue( (float)bp->rotation.delay, bp->rotation.delayRandFrac ); - p->rotation.initial = CG_RandomiseValue( bp->rotation.initial, bp->rotation.initialRandFrac ); - p->rotation.final = CG_RandomiseValue( bp->rotation.final, bp->rotation.finalRandFrac ); - - p->dLightRadius.delay = - (int)CG_RandomiseValue( (float)bp->dLightRadius.delay, bp->dLightRadius.delayRandFrac ); - p->dLightRadius.initial = - CG_RandomiseValue( bp->dLightRadius.initial, bp->dLightRadius.initialRandFrac ); - p->dLightRadius.final = - CG_RandomiseValue( bp->dLightRadius.final, bp->dLightRadius.finalRandFrac ); - - p->colorDelay = CG_RandomiseValue( bp->colorDelay, bp->colorDelayRandFrac ); - - p->bounceMarkRadius = CG_RandomiseValue( bp->bounceMarkRadius, bp->bounceMarkRadiusRandFrac ); - p->bounceMarkCount = - round( CG_RandomiseValue( (float)bp->bounceMarkCount, bp->bounceMarkCountRandFrac ) ); - p->bounceSoundCount = - round( CG_RandomiseValue( (float)bp->bounceSoundCount, bp->bounceSoundCountRandFrac ) ); - - if( bp->numModels ) - { - p->model = bp->models[ rand( ) % bp->numModels ]; - - if( bp->modelAnimation.frameLerp < 0 ) - { - bp->modelAnimation.frameLerp = p->lifeTime / bp->modelAnimation.numFrames; - bp->modelAnimation.initialLerp = p->lifeTime / bp->modelAnimation.numFrames; - } - } - - if( !CG_AttachmentPoint( &ps->attachment, attachmentPoint ) ) - return NULL; - - VectorCopy( attachmentPoint, p->origin ); - - if( CG_AttachmentAxis( &ps->attachment, transform ) ) - { - vec3_t transDisplacement; - - VectorMatrixMultiply( bp->displacement, transform, transDisplacement ); - VectorAdd( p->origin, transDisplacement, p->origin ); - } - else - VectorAdd( p->origin, bp->displacement, p->origin ); - - for( j = 0; j <= 2; j++ ) - p->origin[ j ] += ( crandom( ) * bp->randDisplacement ); - - switch( bp->velMoveType ) - { - case PMT_STATIC: - if( bp->velMoveValues.dirType == PMD_POINT ) - VectorSubtract( bp->velMoveValues.point, p->origin, p->velocity ); - else if( bp->velMoveValues.dirType == PMD_LINEAR ) - VectorCopy( bp->velMoveValues.dir, p->velocity ); - break; - - case PMT_STATIC_TRANSFORM: - if( !CG_AttachmentAxis( &ps->attachment, transform ) ) - { - CG_Printf( S_COLOR_RED "ERROR: a particle with velocityType " - "static_transform is not attached to something which can " - "provide a transformation\n" ); - return NULL; - } - - if( bp->velMoveValues.dirType == PMD_POINT ) - { - vec3_t transPoint; - - VectorMatrixMultiply( bp->velMoveValues.point, transform, transPoint ); - VectorSubtract( transPoint, p->origin, p->velocity ); - } - else if( bp->velMoveValues.dirType == PMD_LINEAR ) - VectorMatrixMultiply( bp->velMoveValues.dir, transform, p->velocity ); - break; - - case PMT_TAG: - case PMT_CENT_ANGLES: - if( bp->velMoveValues.dirType == PMD_POINT ) - VectorSubtract( attachmentPoint, p->origin, p->velocity ); - else if( bp->velMoveValues.dirType == PMD_LINEAR ) - { - if( !CG_AttachmentDir( &ps->attachment, p->velocity ) ) - return NULL; - } - break; - - case PMT_NORMAL: - if( !ps->normalValid ) - { - CG_Printf( S_COLOR_RED "ERROR: a particle with velocityType " - "normal has no normal\n" ); - return NULL; - } - - VectorCopy( ps->normal, p->velocity ); - - //normal displacement - VectorNormalize( p->velocity ); - VectorMA( p->origin, bp->normalDisplacement, p->velocity, p->origin ); - break; - } - - VectorNormalize( p->velocity ); - CG_SpreadVector( p->velocity, bp->velMoveValues.dirRandAngle ); - VectorScale( p->velocity, - CG_RandomiseValue( bp->velMoveValues.mag, bp->velMoveValues.magRandFrac ), - p->velocity ); - - if( CG_AttachmentVelocity( &ps->attachment, attachmentVelocity ) ) - { - VectorMA( p->velocity, - CG_RandomiseValue( bp->velMoveValues.parentVelFrac, - bp->velMoveValues.parentVelFracRandFrac ), attachmentVelocity, p->velocity ); - } - - p->lastEvalTime = cg.time; - - p->valid = qtrue; - - //this particle has a child particle system attached - if( bp->childSystemName[ 0 ] != '\0' ) - { - particleSystem_t *ps = CG_SpawnNewParticleSystem( bp->childSystemHandle ); - - if( CG_IsParticleSystemValid( &ps ) ) - { - CG_SetAttachmentParticle( &ps->attachment, p ); - CG_AttachToParticle( &ps->attachment ); - } - } - - //this particle has a child trail system attached - if( bp->childTrailSystemName[ 0 ] != '\0' ) - { - trailSystem_t *ts = CG_SpawnNewTrailSystem( bp->childTrailSystemHandle ); - - if( CG_IsTrailSystemValid( &ts ) ) - { - CG_SetAttachmentParticle( &ts->frontAttachment, p ); - CG_AttachToParticle( &ts->frontAttachment ); - } - } - - break; - } - } - - return p; -} - - -/* -=============== -CG_SpawnNewParticles - -Check if there are any ejectors that should be -introducing new particles -=============== -*/ -static void CG_SpawnNewParticles( void ) -{ - int i, j; - particle_t *p; - particleSystem_t *ps; - particleEjector_t *pe; - baseParticleEjector_t *bpe; - float lerpFrac; - int count; - - for( i = 0; i < MAX_PARTICLE_EJECTORS; i++ ) - { - pe = &particleEjectors[ i ]; - ps = pe->parent; - - if( pe->valid ) - { - //a non attached particle system can't make particles - if( !CG_Attached( &ps->attachment ) ) - continue; - - bpe = particleEjectors[ i ].class; - - //if this system is scheduled for removal don't make any new particles - if( !ps->lazyRemove ) - { - while( pe->nextEjectionTime <= cg.time && - ( pe->count > 0 || pe->totalParticles == PARTICLES_INFINITE ) ) - { - for( j = 0; j < bpe->numParticles; j++ ) - CG_SpawnNewParticle( bpe->particles[ j ], pe ); - - if( pe->count > 0 ) - pe->count--; - - //calculate next ejection time - lerpFrac = 1.0 - ( (float)pe->count / (float)pe->totalParticles ); - pe->nextEjectionTime = cg.time + (int)CG_RandomiseValue( - CG_LerpValues( pe->ejectPeriod.initial, - pe->ejectPeriod.final, - lerpFrac ), - pe->ejectPeriod.randFrac ); - } - } - - if( pe->count == 0 || ps->lazyRemove ) - { - count = 0; - - //wait for child particles to die before declaring this pe invalid - for( j = 0; j < MAX_PARTICLES; j++ ) - { - p = &particles[ j ]; - - if( p->valid && p->parent == pe ) - count++; - } - - if( !count ) - pe->valid = qfalse; - } - } - } -} - - -/* -=============== -CG_SpawnNewParticleEjector - -Allocate a new particle ejector -=============== -*/ -static particleEjector_t *CG_SpawnNewParticleEjector( baseParticleEjector_t *bpe, - particleSystem_t *parent ) -{ - int i; - particleEjector_t *pe = NULL; - particleSystem_t *ps = parent; - - for( i = 0; i < MAX_PARTICLE_EJECTORS; i++ ) - { - pe = &particleEjectors[ i ]; - - if( !pe->valid ) - { - memset( pe, 0, sizeof( particleEjector_t ) ); - - //found a free slot - pe->class = bpe; - pe->parent = ps; - - pe->ejectPeriod.initial = bpe->eject.initial; - pe->ejectPeriod.final = bpe->eject.final; - pe->ejectPeriod.randFrac = bpe->eject.randFrac; - - pe->nextEjectionTime = cg.time + - (int)CG_RandomiseValue( (float)bpe->eject.delay, bpe->eject.delayRandFrac ); - pe->count = pe->totalParticles = - (int)round( CG_RandomiseValue( (float)bpe->totalParticles, bpe->totalParticlesRandFrac ) ); - - pe->valid = qtrue; - - if( cg_debugParticles.integer >= 1 ) - CG_Printf( "PE %s created\n", ps->class->name ); - - break; - } - } - - return pe; -} - - -/* -=============== -CG_SpawnNewParticleSystem - -Allocate a new particle system -=============== -*/ -particleSystem_t *CG_SpawnNewParticleSystem( qhandle_t psHandle ) -{ - int i, j; - particleSystem_t *ps = NULL; - baseParticleSystem_t *bps = &baseParticleSystems[ psHandle - 1 ]; - - if( !bps->registered ) - { - CG_Printf( S_COLOR_RED "ERROR: a particle system has not been registered yet\n" ); - return NULL; - } - - for( i = 0; i < MAX_PARTICLE_SYSTEMS; i++ ) - { - ps = &particleSystems[ i ]; - - if( !ps->valid ) - { - memset( ps, 0, sizeof( particleSystem_t ) ); - - //found a free slot - ps->class = bps; - - ps->valid = qtrue; - ps->lazyRemove = qfalse; - - for( j = 0; j < bps->numEjectors; j++ ) - CG_SpawnNewParticleEjector( bps->ejectors[ j ], ps ); - - if( cg_debugParticles.integer >= 1 ) - CG_Printf( "PS %s created\n", bps->name ); - - break; - } - } - - return ps; -} - -/* -=============== -CG_RegisterParticleSystem - -Load the shaders required for a particle system -=============== -*/ -qhandle_t CG_RegisterParticleSystem( char *name ) -{ - int i, j, k, l; - baseParticleSystem_t *bps; - baseParticleEjector_t *bpe; - baseParticle_t *bp; - - for( i = 0; i < MAX_BASEPARTICLE_SYSTEMS; i++ ) - { - bps = &baseParticleSystems[ i ]; - - if( !Q_stricmpn( bps->name, name, MAX_QPATH ) ) - { - //already registered - if( bps->registered ) - return i + 1; - - for( j = 0; j < bps->numEjectors; j++ ) - { - bpe = bps->ejectors[ j ]; - - for( l = 0; l < bpe->numParticles; l++ ) - { - bp = bpe->particles[ l ]; - - for( k = 0; k < bp->numFrames; k++ ) - bp->shaders[ k ] = trap_R_RegisterShader( bp->shaderNames[ k ] ); - - for( k = 0; k < bp->numModels; k++ ) - bp->models[ k ] = trap_R_RegisterModel( bp->modelNames[ k ] ); - - if( bp->bounceMarkName[ 0 ] != '\0' ) - bp->bounceMark = trap_R_RegisterShader( bp->bounceMarkName ); - - if( bp->bounceSoundName[ 0 ] != '\0' ) - bp->bounceSound = trap_S_RegisterSound( bp->bounceSoundName, qfalse ); - - //recursively register any children - if( bp->childSystemName[ 0 ] != '\0' ) - { - //don't care about a handle for children since - //the system deals with it - CG_RegisterParticleSystem( bp->childSystemName ); - } - - if( bp->onDeathSystemName[ 0 ] != '\0' ) - { - //don't care about a handle for children since - //the system deals with it - CG_RegisterParticleSystem( bp->onDeathSystemName ); - } - - if( bp->childTrailSystemName[ 0 ] != '\0' ) - bp->childTrailSystemHandle = CG_RegisterTrailSystem( bp->childTrailSystemName ); - } - } - - if( cg_debugParticles.integer >= 1 ) - CG_Printf( "Registered particle system %s\n", name ); - - bps->registered = qtrue; - - //avoid returning 0 - return i + 1; - } - } - - CG_Printf( S_COLOR_RED "ERROR: failed to register particle system %s\n", name ); - return 0; -} - - -/* -=============== -CG_ParseValueAndVariance - -Parse a value and its random variance -=============== -*/ -static void CG_ParseValueAndVariance( char *token, float *value, float *variance, qboolean allowNegative ) -{ - char valueBuffer[ 16 ]; - char varianceBuffer[ 16 ]; - char *variancePtr = NULL, *varEndPointer = NULL; - float localValue = 0.0f; - float localVariance = 0.0f; - - Q_strncpyz( valueBuffer, token, sizeof( valueBuffer ) ); - Q_strncpyz( varianceBuffer, token, sizeof( varianceBuffer ) ); - - variancePtr = strchr( valueBuffer, '~' ); - - //variance included - if( variancePtr ) - { - variancePtr[ 0 ] = '\0'; - variancePtr++; - - localValue = atof_neg( valueBuffer, allowNegative ); - - varEndPointer = strchr( variancePtr, '%' ); - - if( varEndPointer ) - { - varEndPointer[ 0 ] = '\0'; - localVariance = atof_neg( variancePtr, qfalse ) / 100.0f; - } - else - { - if( localValue != 0.0f ) - localVariance = atof_neg( variancePtr, qfalse ) / localValue; - else - localVariance = atof_neg( variancePtr, qfalse ); - } - } - else - localValue = atof_neg( valueBuffer, allowNegative ); - - if( value != NULL ) - *value = localValue; - - if( variance != NULL ) - *variance = localVariance; -} - -/* -=============== -CG_ParseColor -=============== -*/ -static qboolean CG_ParseColor( byte *c, char **text_p ) -{ - char *token; - int i; - - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( text_p ); - - if( !Q_stricmp( token, "" ) ) - return qfalse; - - c[ i ] = (int)( (float)0xFF * atof_neg( token, qfalse ) ); - } - - return qtrue; -} - -/* -=============== -CG_ParseParticle - -Parse a particle section -=============== -*/ -static qboolean CG_ParseParticle( baseParticle_t *bp, char **text_p ) -{ - char *token; - float number, randFrac; - int i; - - // read optional parameters - while( 1 ) - { - token = COM_Parse( text_p ); - - if( !token ) - break; - - if( !Q_stricmp( token, "" ) ) - return qfalse; - - if( !Q_stricmp( token, "bounce" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "cull" ) ) - { - bp->bounceCull = qtrue; - - bp->bounceFrac = -1.0f; - bp->bounceFracRandFrac = 0.0f; - } - else - { - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->bounceFrac = number; - bp->bounceFracRandFrac = randFrac; - } - - continue; - } - else if( !Q_stricmp( token, "bounceMark" ) ) - { - token = COM_Parse( text_p ); - if( !*token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->bounceMarkCount = number; - bp->bounceMarkCountRandFrac = randFrac; - - token = COM_Parse( text_p ); - if( !*token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->bounceMarkRadius = number; - bp->bounceMarkRadiusRandFrac = randFrac; - - token = COM_ParseExt( text_p, qfalse ); - if( !*token ) - break; - - Q_strncpyz( bp->bounceMarkName, token, MAX_QPATH ); - - continue; - } - else if( !Q_stricmp( token, "bounceSound" ) ) - { - token = COM_Parse( text_p ); - if( !*token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->bounceSoundCount = number; - bp->bounceSoundCountRandFrac = randFrac; - - token = COM_Parse( text_p ); - if( !*token ) - break; - - Q_strncpyz( bp->bounceSoundName, token, MAX_QPATH ); - - continue; - } - else if( !Q_stricmp( token, "shader" ) ) - { - if( bp->numModels > 0 ) - { - CG_Printf( S_COLOR_RED "ERROR: 'shader' not allowed in " - "conjunction with 'model'\n", token ); - break; - } - - token = COM_Parse( text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "sync" ) ) - bp->framerate = 0.0f; - else - bp->framerate = atof_neg( token, qfalse ); - - token = COM_ParseExt( text_p, qfalse ); - if( !*token ) - break; - - while( *token && bp->numFrames < MAX_PS_SHADER_FRAMES ) - { - Q_strncpyz( bp->shaderNames[ bp->numFrames++ ], token, MAX_QPATH ); - token = COM_ParseExt( text_p, qfalse ); - } - - continue; - } - else if( !Q_stricmp( token, "model" ) ) - { - if( bp->numFrames > 0 ) - { - CG_Printf( S_COLOR_RED "ERROR: 'model' not allowed in " - "conjunction with 'shader'\n", token ); - break; - } - - token = COM_ParseExt( text_p, qfalse ); - if( !*token ) - break; - - while( *token && bp->numModels < MAX_PS_MODELS ) - { - Q_strncpyz( bp->modelNames[ bp->numModels++ ], token, MAX_QPATH ); - token = COM_ParseExt( text_p, qfalse ); - } - - continue; - } - else if( !Q_stricmp( token, "modelAnimation" ) ) - { - token = COM_Parse( text_p ); - if( !*token ) - break; - - bp->modelAnimation.firstFrame = atoi_neg( token, qfalse ); - - token = COM_Parse( text_p ); - if( !*token ) - break; - - bp->modelAnimation.numFrames = atoi( token ); - bp->modelAnimation.reversed = qfalse; - bp->modelAnimation.flipflop = qfalse; - - // if numFrames is negative the animation is reversed - if( bp->modelAnimation.numFrames < 0 ) - { - bp->modelAnimation.numFrames = -bp->modelAnimation.numFrames; - bp->modelAnimation.reversed = qtrue; - } - - token = COM_Parse( text_p ); - if( !*token ) - break; - - bp->modelAnimation.loopFrames = atoi( token ); - - token = COM_Parse( text_p ); - if( !*token ) - break; - - if( !Q_stricmp( token, "sync" ) ) - { - bp->modelAnimation.frameLerp = -1; - bp->modelAnimation.initialLerp = -1; - } - else - { - float fps = atof_neg( token, qfalse ); - - if( fps == 0.0f ) - fps = 1.0f; - - bp->modelAnimation.frameLerp = 1000 / fps; - bp->modelAnimation.initialLerp = 1000 / fps; - } - - continue; - } - /// - else if( !Q_stricmp( token, "velocityType" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "static" ) ) - bp->velMoveType = PMT_STATIC; - else if( !Q_stricmp( token, "static_transform" ) ) - bp->velMoveType = PMT_STATIC_TRANSFORM; - else if( !Q_stricmp( token, "tag" ) ) - bp->velMoveType = PMT_TAG; - else if( !Q_stricmp( token, "cent" ) ) - bp->velMoveType = PMT_CENT_ANGLES; - else if( !Q_stricmp( token, "normal" ) ) - bp->velMoveType = PMT_NORMAL; - - continue; - } - else if( !Q_stricmp( token, "velocityDir" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "linear" ) ) - bp->velMoveValues.dirType = PMD_LINEAR; - else if( !Q_stricmp( token, "point" ) ) - bp->velMoveValues.dirType = PMD_POINT; - - continue; - } - else if( !Q_stricmp( token, "velocityMagnitude" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->velMoveValues.mag = number; - bp->velMoveValues.magRandFrac = randFrac; - - continue; - } - else if( !Q_stricmp( token, "parentVelocityFraction" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->velMoveValues.parentVelFrac = number; - bp->velMoveValues.parentVelFracRandFrac = randFrac; - - continue; - } - else if( !Q_stricmp( token, "velocity" ) ) - { - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - bp->velMoveValues.dir[ i ] = atof_neg( token, qtrue ); - } - - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, NULL, &randFrac, qfalse ); - - bp->velMoveValues.dirRandAngle = randFrac; - - continue; - } - else if( !Q_stricmp( token, "velocityPoint" ) ) - { - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - bp->velMoveValues.point[ i ] = atof_neg( token, qtrue ); - } - - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, NULL, &randFrac, qfalse ); - - bp->velMoveValues.pointRandAngle = randFrac; - - continue; - } - /// - else if( !Q_stricmp( token, "accelerationType" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "static" ) ) - bp->accMoveType = PMT_STATIC; - else if( !Q_stricmp( token, "static_transform" ) ) - bp->accMoveType = PMT_STATIC_TRANSFORM; - else if( !Q_stricmp( token, "tag" ) ) - bp->accMoveType = PMT_TAG; - else if( !Q_stricmp( token, "cent" ) ) - bp->accMoveType = PMT_CENT_ANGLES; - else if( !Q_stricmp( token, "normal" ) ) - bp->accMoveType = PMT_NORMAL; - - continue; - } - else if( !Q_stricmp( token, "accelerationDir" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "linear" ) ) - bp->accMoveValues.dirType = PMD_LINEAR; - else if( !Q_stricmp( token, "point" ) ) - bp->accMoveValues.dirType = PMD_POINT; - - continue; - } - else if( !Q_stricmp( token, "accelerationMagnitude" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->accMoveValues.mag = number; - bp->accMoveValues.magRandFrac = randFrac; - - continue; - } - else if( !Q_stricmp( token, "acceleration" ) ) - { - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - bp->accMoveValues.dir[ i ] = atof_neg( token, qtrue ); - } - - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, NULL, &randFrac, qfalse ); - - bp->accMoveValues.dirRandAngle = randFrac; - - continue; - } - else if( !Q_stricmp( token, "accelerationPoint" ) ) - { - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - bp->accMoveValues.point[ i ] = atof_neg( token, qtrue ); - } - - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, NULL, &randFrac, qfalse ); - - bp->accMoveValues.pointRandAngle = randFrac; - - continue; - } - /// - else if( !Q_stricmp( token, "displacement" ) ) - { - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - bp->displacement[ i ] = atof_neg( token, qtrue ); - } - - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, NULL, &randFrac, qfalse ); - - bp->randDisplacement = randFrac; - - continue; - } - else if( !Q_stricmp( token, "normalDisplacement" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - bp->normalDisplacement = atof_neg( token, qtrue ); - - continue; - } - else if( !Q_stricmp( token, "overdrawProtection" ) ) - { - bp->overdrawProtection = qtrue; - - continue; - } - else if( !Q_stricmp( token, "realLight" ) ) - { - bp->realLight = qtrue; - - continue; - } - else if( !Q_stricmp( token, "dynamicLight" ) ) - { - bp->dynamicLight = qtrue; - - token = COM_Parse( text_p ); - if( !*token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->dLightRadius.delay = (int)number; - bp->dLightRadius.delayRandFrac = randFrac; - - token = COM_Parse( text_p ); - if( !*token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->dLightRadius.initial = number; - bp->dLightRadius.initialRandFrac = randFrac; - - token = COM_Parse( text_p ); - if( !*token ) - break; - - if( !Q_stricmp( token, "-" ) ) - { - bp->dLightRadius.final = PARTICLES_SAME_AS_INITIAL; - bp->dLightRadius.finalRandFrac = 0.0f; - } - else - { - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->dLightRadius.final = number; - bp->dLightRadius.finalRandFrac = randFrac; - } - - token = COM_Parse( text_p ); - if( !*token ) - break; - - if( !Q_stricmp( token, "{" ) ) - { - if( !CG_ParseColor( bp->dLightColor, text_p ) ) - break; - - token = COM_Parse( text_p ); - if( Q_stricmp( token, "}" ) ) - { - CG_Printf( S_COLOR_RED "ERROR: missing '}'\n" ); - break; - } - } - - continue; - } - else if( !Q_stricmp( token, "cullOnStartSolid" ) ) - { - bp->cullOnStartSolid = qtrue; - - continue; - } - else if( !Q_stricmp( token, "radius" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->radius.delay = (int)number; - bp->radius.delayRandFrac = randFrac; - - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->radius.initial = number; - bp->radius.initialRandFrac = randFrac; - - token = COM_Parse( text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "-" ) ) - { - bp->radius.final = PARTICLES_SAME_AS_INITIAL; - bp->radius.finalRandFrac = 0.0f; - } - else - { - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->radius.final = number; - bp->radius.finalRandFrac = randFrac; - } - - continue; - } - else if( !Q_stricmp( token, "alpha" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->alpha.delay = (int)number; - bp->alpha.delayRandFrac = randFrac; - - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->alpha.initial = number; - bp->alpha.initialRandFrac = randFrac; - - token = COM_Parse( text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "-" ) ) - { - bp->alpha.final = PARTICLES_SAME_AS_INITIAL; - bp->alpha.finalRandFrac = 0.0f; - } - else - { - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->alpha.final = number; - bp->alpha.finalRandFrac = randFrac; - } - - continue; - } - else if( !Q_stricmp( token, "color" ) ) - { - token = COM_Parse( text_p ); - if( !*token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->colorDelay = (int)number; - bp->colorDelayRandFrac = randFrac; - - token = COM_Parse( text_p ); - if( !*token ) - break; - - if( !Q_stricmp( token, "{" ) ) - { - if( !CG_ParseColor( bp->initialColor, text_p ) ) - break; - - token = COM_Parse( text_p ); - if( Q_stricmp( token, "}" ) ) - { - CG_Printf( S_COLOR_RED "ERROR: missing '}'\n" ); - break; - } - - token = COM_Parse( text_p ); - if( !*token ) - break; - - if( !Q_stricmp( token, "-" ) ) - { - bp->finalColor[ 0 ] = bp->initialColor[ 0 ]; - bp->finalColor[ 1 ] = bp->initialColor[ 1 ]; - bp->finalColor[ 2 ] = bp->initialColor[ 2 ]; - } - else if( !Q_stricmp( token, "{" ) ) - { - if( !CG_ParseColor( bp->finalColor, text_p ) ) - break; - - token = COM_Parse( text_p ); - if( Q_stricmp( token, "}" ) ) - { - CG_Printf( S_COLOR_RED "ERROR: missing '}'\n" ); - break; - } - } - else - { - CG_Printf( S_COLOR_RED "ERROR: missing '{'\n" ); - break; - } - } - else - { - CG_Printf( S_COLOR_RED "ERROR: missing '{'\n" ); - break; - } - - continue; - } - else if( !Q_stricmp( token, "rotation" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->rotation.delay = (int)number; - bp->rotation.delayRandFrac = randFrac; - - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qtrue ); - - bp->rotation.initial = number; - bp->rotation.initialRandFrac = randFrac; - - token = COM_Parse( text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "-" ) ) - { - bp->rotation.final = PARTICLES_SAME_AS_INITIAL; - bp->rotation.finalRandFrac = 0.0f; - } - else - { - CG_ParseValueAndVariance( token, &number, &randFrac, qtrue ); - - bp->rotation.final = number; - bp->rotation.finalRandFrac = randFrac; - } - - continue; - } - else if( !Q_stricmp( token, "lifeTime" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bp->lifeTime = (int)number; - bp->lifeTimeRandFrac = randFrac; - - continue; - } - else if( !Q_stricmp( token, "childSystem" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - Q_strncpyz( bp->childSystemName, token, MAX_QPATH ); - - continue; - } - else if( !Q_stricmp( token, "onDeathSystem" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - Q_strncpyz( bp->onDeathSystemName, token, MAX_QPATH ); - - continue; - } - else if( !Q_stricmp( token, "childTrailSystem" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - Q_strncpyz( bp->childTrailSystemName, token, MAX_QPATH ); - - continue; - } - else if( !Q_stricmp( token, "}" ) ) - return qtrue; //reached the end of this particle - else - { - CG_Printf( S_COLOR_RED "ERROR: unknown token '%s' in particle\n", token ); - return qfalse; - } - } - - return qfalse; -} - -/* -=============== -CG_InitialiseBaseParticle -=============== -*/ -static void CG_InitialiseBaseParticle( baseParticle_t *bp ) -{ - memset( bp, 0, sizeof( baseParticle_t ) ); - - memset( bp->initialColor, 0xFF, sizeof( bp->initialColor ) ); - memset( bp->finalColor, 0xFF, sizeof( bp->finalColor ) ); -} - -/* -=============== -CG_ParseParticleEjector - -Parse a particle ejector section -=============== -*/ -static qboolean CG_ParseParticleEjector( baseParticleEjector_t *bpe, char **text_p ) -{ - char *token; - float number, randFrac; - - // read optional parameters - while( 1 ) - { - token = COM_Parse( text_p ); - - if( !token ) - break; - - if( !Q_stricmp( token, "" ) ) - return qfalse; - - if( !Q_stricmp( token, "{" ) ) - { - CG_InitialiseBaseParticle( &baseParticles[ numBaseParticles ] ); - - if( !CG_ParseParticle( &baseParticles[ numBaseParticles ], text_p ) ) - { - CG_Printf( S_COLOR_RED "ERROR: failed to parse particle\n" ); - return qfalse; - } - - if( bpe->numParticles == MAX_PARTICLES_PER_EJECTOR ) - { - CG_Printf( S_COLOR_RED "ERROR: ejector has > %d particles\n", MAX_PARTICLES_PER_EJECTOR ); - return qfalse; - } - else if( numBaseParticles == MAX_BASEPARTICLES ) - { - CG_Printf( S_COLOR_RED "ERROR: maximum number of particles (%d) reached\n", MAX_BASEPARTICLES ); - return qfalse; - } - else - { - //start parsing particles again - bpe->particles[ bpe->numParticles ] = &baseParticles[ numBaseParticles ]; - bpe->numParticles++; - numBaseParticles++; - } - continue; - } - else if( !Q_stricmp( token, "delay" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bpe->eject.delay = (int)number; - bpe->eject.delayRandFrac = randFrac; - - continue; - } - else if( !Q_stricmp( token, "period" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - bpe->eject.initial = atoi_neg( token, qfalse ); - - token = COM_Parse( text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "-" ) ) - bpe->eject.final = PARTICLES_SAME_AS_INITIAL; - else - bpe->eject.final = atoi_neg( token, qfalse ); - - token = COM_Parse( text_p ); - if( !token ) - break; - - CG_ParseValueAndVariance( token, NULL, &bpe->eject.randFrac, qfalse ); - - continue; - } - else if( !Q_stricmp( token, "count" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "infinite" ) ) - { - bpe->totalParticles = PARTICLES_INFINITE; - bpe->totalParticlesRandFrac = 0.0f; - } - else - { - CG_ParseValueAndVariance( token, &number, &randFrac, qfalse ); - - bpe->totalParticles = (int)number; - bpe->totalParticlesRandFrac = randFrac; - } - - continue; - } - else if( !Q_stricmp( token, "particle" ) ) //acceptable text - continue; - else if( !Q_stricmp( token, "}" ) ) - return qtrue; //reached the end of this particle ejector - else - { - CG_Printf( S_COLOR_RED "ERROR: unknown token '%s' in particle ejector\n", token ); - return qfalse; - } - } - - return qfalse; -} - - -/* -=============== -CG_ParseParticleSystem - -Parse a particle system section -=============== -*/ -static qboolean CG_ParseParticleSystem( baseParticleSystem_t *bps, char **text_p, const char *name ) -{ - char *token; - baseParticleEjector_t *bpe; - - // read optional parameters - while( 1 ) - { - token = COM_Parse( text_p ); - - if( !token ) - break; - - if( !Q_stricmp( token, "" ) ) - return qfalse; - - if( !Q_stricmp( token, "{" ) ) - { - if( !CG_ParseParticleEjector( &baseParticleEjectors[ numBaseParticleEjectors ], text_p ) ) - { - CG_Printf( S_COLOR_RED "ERROR: failed to parse particle ejector\n" ); - return qfalse; - } - - bpe = &baseParticleEjectors[ numBaseParticleEjectors ]; - - //check for infinite count + zero period - if( bpe->totalParticles == PARTICLES_INFINITE && - ( bpe->eject.initial == 0.0f || bpe->eject.final == 0.0f ) ) - { - CG_Printf( S_COLOR_RED "ERROR: ejector with 'count infinite' potentially has zero period\n" ); - return qfalse; - } - - if( bps->numEjectors == MAX_EJECTORS_PER_SYSTEM ) - { - CG_Printf( S_COLOR_RED "ERROR: particle system has > %d ejectors\n", MAX_EJECTORS_PER_SYSTEM ); - return qfalse; - } - else if( numBaseParticleEjectors == MAX_BASEPARTICLE_EJECTORS ) - { - CG_Printf( S_COLOR_RED "ERROR: maximum number of particle ejectors (%d) reached\n", - MAX_BASEPARTICLE_EJECTORS ); - return qfalse; - } - else - { - //start parsing ejectors again - bps->ejectors[ bps->numEjectors ] = &baseParticleEjectors[ numBaseParticleEjectors ]; - bps->numEjectors++; - numBaseParticleEjectors++; - } - continue; - } - else if( !Q_stricmp( token, "thirdPersonOnly" ) ) - bps->thirdPersonOnly = qtrue; - else if( !Q_stricmp( token, "ejector" ) ) //acceptable text - continue; - else if( !Q_stricmp( token, "}" ) ) - { - if( cg_debugParticles.integer >= 1 ) - CG_Printf( "Parsed particle system %s\n", name ); - - return qtrue; //reached the end of this particle system - } - else - { - CG_Printf( S_COLOR_RED "ERROR: unknown token '%s' in particle system %s\n", token, bps->name ); - return qfalse; - } - } - - return qfalse; -} - -/* -=============== -CG_ParseParticleFile - -Load the particle systems from a particle file -=============== -*/ -static qboolean CG_ParseParticleFile( const char *fileName ) -{ - char *text_p; - int i; - int len; - char *token; - char text[ 32000 ]; - char psName[ MAX_QPATH ]; - qboolean psNameSet = qfalse; - fileHandle_t f; - - // load the file - len = trap_FS_FOpenFile( fileName, &f, FS_READ ); - if( len <= 0 ) - return qfalse; - - if( len >= sizeof( text ) - 1 ) - { - CG_Printf( S_COLOR_RED "ERROR: particle file %s too long\n", fileName ); - return qfalse; - } - - trap_FS_Read( text, len, f ); - text[ len ] = 0; - trap_FS_FCloseFile( f ); - - // parse the text - text_p = text; - - // read optional parameters - while( 1 ) - { - token = COM_Parse( &text_p ); - - if( !Q_stricmp( token, "" ) ) - break; - - if( !Q_stricmp( token, "{" ) ) - { - if( psNameSet ) - { - //check for name space clashes - for( i = 0; i < numBaseParticleSystems; i++ ) - { - if( !Q_stricmp( baseParticleSystems[ i ].name, psName ) ) - { - CG_Printf( S_COLOR_RED "ERROR: a particle system is already named %s\n", psName ); - return qfalse; - } - } - - Q_strncpyz( baseParticleSystems[ numBaseParticleSystems ].name, psName, MAX_QPATH ); - - if( !CG_ParseParticleSystem( &baseParticleSystems[ numBaseParticleSystems ], &text_p, psName ) ) - { - CG_Printf( S_COLOR_RED "ERROR: %s: failed to parse particle system %s\n", fileName, psName ); - return qfalse; - } - - //start parsing particle systems again - psNameSet = qfalse; - - if( numBaseParticleSystems == MAX_BASEPARTICLE_SYSTEMS ) - { - CG_Printf( S_COLOR_RED "ERROR: maximum number of particle systems (%d) reached\n", - MAX_BASEPARTICLE_SYSTEMS ); - return qfalse; - } - else - numBaseParticleSystems++; - - continue; - } - else - { - CG_Printf( S_COLOR_RED "ERROR: unamed particle system\n" ); - return qfalse; - } - } - - if( !psNameSet ) - { - Q_strncpyz( psName, token, sizeof( psName ) ); - psNameSet = qtrue; - } - else - { - CG_Printf( S_COLOR_RED "ERROR: particle system already named\n" ); - return qfalse; - } - } - - return qtrue; -} - - -/* -=============== -CG_LoadParticleSystems - -Load particle systems from .particle files -=============== -*/ -void CG_LoadParticleSystems( void ) -{ - int i, j; - const char *s[ MAX_PARTICLE_FILES ]; - - //clear out the old - numBaseParticleSystems = 0; - numBaseParticleEjectors = 0; - numBaseParticles = 0; - - for( i = 0; i < MAX_BASEPARTICLE_SYSTEMS; i++ ) - { - baseParticleSystem_t *bps = &baseParticleSystems[ i ]; - memset( bps, 0, sizeof( baseParticleSystem_t ) ); - } - - for( i = 0; i < MAX_BASEPARTICLE_EJECTORS; i++ ) - { - baseParticleEjector_t *bpe = &baseParticleEjectors[ i ]; - memset( bpe, 0, sizeof( baseParticleEjector_t ) ); - } - - for( i = 0; i < MAX_BASEPARTICLES; i++ ) - { - baseParticle_t *bp = &baseParticles[ i ]; - memset( bp, 0, sizeof( baseParticle_t ) ); - } - - - //and bring in the new - for( i = 0; i < MAX_PARTICLE_FILES; i++ ) - { - s[ i ] = CG_ConfigString( CS_PARTICLE_FILES + i ); - - if( strlen( s[ i ] ) > 0 ) - { - CG_Printf( "...loading '%s'\n", s[ i ] ); - CG_ParseParticleFile( s[ i ] ); - } - else - break; - } - - //connect any child systems to their psHandle - for( i = 0; i < numBaseParticles; i++ ) - { - baseParticle_t *bp = &baseParticles[ i ]; - - if( bp->childSystemName[ 0 ] ) - { - //particle class has a child, resolve the name - for( j = 0; j < numBaseParticleSystems; j++ ) - { - baseParticleSystem_t *bps = &baseParticleSystems[ j ]; - - if( !Q_stricmp( bps->name, bp->childSystemName ) ) - { - //FIXME: add checks for cycles and infinite children - - bp->childSystemHandle = j + 1; - - break; - } - } - - if( j == numBaseParticleSystems ) - { - //couldn't find named particle system - CG_Printf( S_COLOR_YELLOW "WARNING: failed to find child %s\n", bp->childSystemName ); - bp->childSystemName[ 0 ] = '\0'; - } - } - - if( bp->onDeathSystemName[ 0 ] ) - { - //particle class has a child, resolve the name - for( j = 0; j < numBaseParticleSystems; j++ ) - { - baseParticleSystem_t *bps = &baseParticleSystems[ j ]; - - if( !Q_stricmp( bps->name, bp->onDeathSystemName ) ) - { - //FIXME: add checks for cycles and infinite children - - bp->onDeathSystemHandle = j + 1; - - break; - } - } - - if( j == numBaseParticleSystems ) - { - //couldn't find named particle system - CG_Printf( S_COLOR_YELLOW "WARNING: failed to find onDeath system %s\n", bp->onDeathSystemName ); - bp->onDeathSystemName[ 0 ] = '\0'; - } - } - } -} - -/* -=============== -CG_SetParticleSystemNormal -=============== -*/ -void CG_SetParticleSystemNormal( particleSystem_t *ps, vec3_t normal ) -{ - if( ps == NULL || !ps->valid ) - { - CG_Printf( S_COLOR_YELLOW "WARNING: tried to modify a NULL particle system\n" ); - return; - } - - ps->normalValid = qtrue; - VectorCopy( normal, ps->normal ); - VectorNormalize( ps->normal ); -} - - -/* -=============== -CG_DestroyParticleSystem - -Destroy a particle system - -This doesn't actually invalidate anything, it just stops -particle ejectors from producing new particles so the -garbage collector will eventually remove this system. -However is does set the pointer to NULL so the user is -unable to manipulate this particle system any longer. -=============== -*/ -void CG_DestroyParticleSystem( particleSystem_t **ps ) -{ - int i; - particleEjector_t *pe; - - if( *ps == NULL || !(*ps)->valid ) - { - CG_Printf( S_COLOR_YELLOW "WARNING: tried to destroy a NULL particle system\n" ); - return; - } - - if( cg_debugParticles.integer >= 1 ) - CG_Printf( "PS destroyed\n" ); - - for( i = 0; i < MAX_PARTICLE_EJECTORS; i++ ) - { - pe = &particleEjectors[ i ]; - - if( pe->valid && pe->parent == *ps ) - pe->totalParticles = pe->count = 0; - } - - *ps = NULL; -} - -/* -=============== -CG_IsParticleSystemInfinite - -Test a particle system for 'count infinite' ejectors -=============== -*/ -qboolean CG_IsParticleSystemInfinite( particleSystem_t *ps ) -{ - int i; - particleEjector_t *pe; - - if( ps == NULL ) - { - CG_Printf( S_COLOR_YELLOW "WARNING: tried to test a NULL particle system\n" ); - return qfalse; - } - - if( !ps->valid ) - { - CG_Printf( S_COLOR_YELLOW "WARNING: tried to test an invalid particle system\n" ); - return qfalse; - } - - //don't bother checking already invalid systems - if( !ps->valid ) - return qfalse; - - for( i = 0; i < MAX_PARTICLE_EJECTORS; i++ ) - { - pe = &particleEjectors[ i ]; - - if( pe->valid && pe->parent == ps ) - { - if( pe->totalParticles == PARTICLES_INFINITE ) - return qtrue; - } - } - - return qfalse; -} - -/* -=============== -CG_IsParticleSystemValid - -Test a particle system for validity -=============== -*/ -qboolean CG_IsParticleSystemValid( particleSystem_t **ps ) -{ - if( *ps == NULL || ( *ps && !(*ps)->valid ) ) - { - if( *ps && !(*ps)->valid ) - *ps = NULL; - - return qfalse; - } - - return qtrue; -} - -/* -=============== -CG_GarbageCollectParticleSystems - -Destroy inactive particle systems -=============== -*/ -static void CG_GarbageCollectParticleSystems( void ) -{ - int i, j, count; - particleSystem_t *ps; - particleEjector_t *pe; - int centNum; - - for( i = 0; i < MAX_PARTICLE_SYSTEMS; i++ ) - { - ps = &particleSystems[ i ]; - count = 0; - - //don't bother checking already invalid systems - if( !ps->valid ) - continue; - - for( j = 0; j < MAX_PARTICLE_EJECTORS; j++ ) - { - pe = &particleEjectors[ j ]; - - if( pe->valid && pe->parent == ps ) - count++; - } - - if( !count ) - ps->valid = qfalse; - - //check systems where the parent cent has left the PVS - //( local player entity is always valid ) - if( ( centNum = CG_AttachmentCentNum( &ps->attachment ) ) >= 0 && - centNum != cg.snap->ps.clientNum ) - { - if( !cg_entities[ centNum ].valid ) - ps->lazyRemove = qtrue; - } - - if( cg_debugParticles.integer >= 1 && !ps->valid ) - CG_Printf( "PS %s garbage collected\n", ps->class->name ); - } -} - - -/* -=============== -CG_CalculateTimeFrac - -Calculate the fraction of time passed -=============== -*/ -static float CG_CalculateTimeFrac( int birth, int life, int delay ) -{ - float frac; - - frac = ( (float)cg.time - (float)( birth + delay ) ) / (float)( life - delay ); - - if( frac < 0.0f ) - frac = 0.0f; - else if( frac > 1.0f ) - frac = 1.0f; - - return frac; -} - -/* -=============== -CG_EvaluateParticlePhysics - -Compute the physics on a specific particle -=============== -*/ -static void CG_EvaluateParticlePhysics( particle_t *p ) -{ - particleSystem_t *ps = p->parent->parent; - baseParticle_t *bp = p->class; - vec3_t acceleration, newOrigin; - vec3_t mins, maxs; - float deltaTime, bounce, radius, dot; - trace_t trace; - vec3_t transform[ 3 ]; - - if( p->atRest ) - { - VectorClear( p->velocity ); - return; - } - - switch( bp->accMoveType ) - { - case PMT_STATIC: - if( bp->accMoveValues.dirType == PMD_POINT ) - VectorSubtract( bp->accMoveValues.point, p->origin, acceleration ); - else if( bp->accMoveValues.dirType == PMD_LINEAR ) - VectorCopy( bp->accMoveValues.dir, acceleration ); - - break; - - case PMT_STATIC_TRANSFORM: - if( !CG_AttachmentAxis( &ps->attachment, transform ) ) - { - CG_Printf( S_COLOR_RED "ERROR: a particle with accelerationType " - "static_transform is not attached to something which can " - "provide a transformation\n" ); - return; - } - - if( bp->accMoveValues.dirType == PMD_POINT ) - { - vec3_t transPoint; - - VectorMatrixMultiply( bp->accMoveValues.point, transform, transPoint ); - VectorSubtract( transPoint, p->origin, acceleration ); - } - else if( bp->accMoveValues.dirType == PMD_LINEAR ) - VectorMatrixMultiply( bp->accMoveValues.dir, transform, acceleration ); - break; - - case PMT_TAG: - case PMT_CENT_ANGLES: - if( bp->accMoveValues.dirType == PMD_POINT ) - { - vec3_t point; - - if( !CG_AttachmentPoint( &ps->attachment, point ) ) - return; - - VectorSubtract( point, p->origin, acceleration ); - } - else if( bp->accMoveValues.dirType == PMD_LINEAR ) - { - if( !CG_AttachmentDir( &ps->attachment, acceleration ) ) - return; - } - break; - - case PMT_NORMAL: - if( !ps->normalValid ) - return; - - VectorCopy( ps->normal, acceleration ); - - break; - } - -#define MAX_ACC_RADIUS 1000.0f - - if( bp->accMoveValues.dirType == PMD_POINT ) - { - //FIXME: so this fall off is a bit... odd -- it works.. - float r2 = DotProduct( acceleration, acceleration ); // = radius^2 - float scale = ( MAX_ACC_RADIUS - r2 ) / MAX_ACC_RADIUS; - - if( scale > 1.0f ) - scale = 1.0f; - else if( scale < 0.1f ) - scale = 0.1f; - - scale *= CG_RandomiseValue( bp->accMoveValues.mag, bp->accMoveValues.magRandFrac ); - - VectorNormalize( acceleration ); - CG_SpreadVector( acceleration, bp->accMoveValues.dirRandAngle ); - VectorScale( acceleration, scale, acceleration ); - } - else if( bp->accMoveValues.dirType == PMD_LINEAR ) - { - VectorNormalize( acceleration ); - CG_SpreadVector( acceleration, bp->accMoveValues.dirRandAngle ); - VectorScale( acceleration, - CG_RandomiseValue( bp->accMoveValues.mag, bp->accMoveValues.magRandFrac ), - acceleration ); - } - - radius = CG_LerpValues( p->radius.initial, - p->radius.final, - CG_CalculateTimeFrac( p->birthTime, - p->lifeTime, - p->radius.delay ) ); - - VectorSet( mins, -radius, -radius, -radius ); - VectorSet( maxs, radius, radius, radius ); - - bounce = CG_RandomiseValue( bp->bounceFrac, bp->bounceFracRandFrac ); - - deltaTime = (float)( cg.time - p->lastEvalTime ) * 0.001; - VectorMA( p->velocity, deltaTime, acceleration, p->velocity ); - VectorMA( p->origin, deltaTime, p->velocity, newOrigin ); - p->lastEvalTime = cg.time; - - CG_Trace( &trace, p->origin, mins, maxs, newOrigin, - CG_AttachmentCentNum( &ps->attachment ), CONTENTS_SOLID ); - - //not hit anything or not a collider - if( trace.fraction == 1.0f || bounce == 0.0f ) - { - VectorCopy( newOrigin, p->origin ); - return; - } - - //remove particles that get into a CONTENTS_NODROP brush - if( ( trap_CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) || - ( bp->cullOnStartSolid && trace.startsolid ) ) - { - CG_DestroyParticle( p, NULL ); - return; - } - else if( bp->bounceCull ) - { - CG_DestroyParticle( p, trace.plane.normal ); - return; - } - - //reflect the velocity on the trace plane - dot = DotProduct( p->velocity, trace.plane.normal ); - VectorMA( p->velocity, -2.0f * dot, trace.plane.normal, p->velocity ); - - VectorScale( p->velocity, bounce, p->velocity ); - - if( trace.plane.normal[ 2 ] > 0.5f && - ( p->velocity[ 2 ] < 40.0f || - p->velocity[ 2 ] < -cg.frametime * p->velocity[ 2 ] ) ) - p->atRest = qtrue; - - if( bp->bounceMarkName[ 0 ] && p->bounceMarkCount > 0 ) - { - CG_ImpactMark( bp->bounceMark, trace.endpos, trace.plane.normal, - random( ) * 360, 1, 1, 1, 1, qtrue, bp->bounceMarkRadius, qfalse ); - p->bounceMarkCount--; - } - - if( bp->bounceSoundName[ 0 ] && p->bounceSoundCount > 0 ) - { - trap_S_StartSound( trace.endpos, ENTITYNUM_WORLD, CHAN_AUTO, bp->bounceSound ); - p->bounceSoundCount--; - } - - VectorCopy( trace.endpos, p->origin ); -} - - -#define GETKEY(x,y) (((x)>>y)&0xFF) - -/* -=============== -CG_Radix -=============== -*/ -static void CG_Radix( int bits, int size, particle_t **source, particle_t **dest ) -{ - int count[ 256 ]; - int index[ 256 ]; - int i; - - memset( count, 0, sizeof( count ) ); - - for( i = 0; i < size; i++ ) - count[ GETKEY( source[ i ]->sortKey, bits ) ]++; - - index[ 0 ] = 0; - - for( i = 1; i < 256; i++ ) - index[ i ] = index[ i - 1 ] + count[ i - 1 ]; - - for( i = 0; i < size; i++ ) - dest[ index[ GETKEY( source[ i ]->sortKey, bits ) ]++ ] = source[ i ]; -} - -/* -=============== -CG_RadixSort - -Radix sort with 4 byte size buckets -=============== -*/ -static void CG_RadixSort( particle_t **source, particle_t **temp, int size ) -{ - CG_Radix( 0, size, source, temp ); - CG_Radix( 8, size, temp, source ); - CG_Radix( 16, size, source, temp ); - CG_Radix( 24, size, temp, source ); -} - -/* -=============== -CG_CompactAndSortParticles - -Depth sort the particles -=============== -*/ -static void CG_CompactAndSortParticles( void ) -{ - int i, j = 0; - int numParticles; - vec3_t delta; - - for( i = 0; i < MAX_PARTICLES; i++ ) - sortedParticles[ i ] = &particles[ i ]; - - for( i = MAX_PARTICLES - 1; i >= 0; i-- ) - { - if( sortedParticles[ i ]->valid ) - { - //find the first hole - while( sortedParticles[ j ]->valid ) - j++; - - //no more holes - if( j >= i ) - break; - - sortedParticles[ j ] = sortedParticles[ i ]; - } - } - - numParticles = i; - - //set sort keys - for( i = 0; i < numParticles; i++ ) - { - VectorSubtract( sortedParticles[ i ]->origin, cg.refdef.vieworg, delta ); - sortedParticles[ i ]->sortKey = (int)DotProduct( delta, delta ); - } - - CG_RadixSort( sortedParticles, radixBuffer, numParticles ); - - //FIXME: wtf? - //reverse order of particles array - for( i = 0; i < numParticles; i++ ) - radixBuffer[ i ] = sortedParticles[ numParticles - i - 1 ]; - - for( i = 0; i < numParticles; i++ ) - sortedParticles[ i ] = radixBuffer[ i ]; -} - -/* -=============== -CG_RenderParticle - -Actually render a particle -=============== -*/ -static void CG_RenderParticle( particle_t *p ) -{ - refEntity_t re; - float timeFrac, scale; - int index; - baseParticle_t *bp = p->class; - particleSystem_t *ps = p->parent->parent; - baseParticleSystem_t *bps = ps->class; - vec3_t alight, dlight, lightdir; - int i; - vec3_t up = { 0.0f, 0.0f, 1.0f }; - - memset( &re, 0, sizeof( refEntity_t ) ); - - timeFrac = CG_CalculateTimeFrac( p->birthTime, p->lifeTime, 0 ); - - scale = CG_LerpValues( p->radius.initial, - p->radius.final, - CG_CalculateTimeFrac( p->birthTime, - p->lifeTime, - p->radius.delay ) ); - - re.shaderTime = p->birthTime / 1000.0f; - - if( bp->numFrames ) //shader based - { - re.reType = RT_SPRITE; - - //apply environmental lighting to the particle - if( bp->realLight ) - { - trap_R_LightForPoint( p->origin, alight, dlight, lightdir ); - for( i = 0; i <= 2; i++ ) - re.shaderRGBA[ i ] = (byte)alight[ i ]; - } - else - { - vec3_t colorRange; - - VectorSubtract( bp->finalColor, - bp->initialColor, colorRange ); - - VectorMA( bp->initialColor, - CG_CalculateTimeFrac( p->birthTime, - p->lifeTime, - p->colorDelay ), - colorRange, re.shaderRGBA ); - } - - re.shaderRGBA[ 3 ] = (byte)( (float)0xFF * - CG_LerpValues( p->alpha.initial, - p->alpha.final, - CG_CalculateTimeFrac( p->birthTime, - p->lifeTime, - p->alpha.delay ) ) ); - - re.radius = scale; - - re.rotation = CG_LerpValues( p->rotation.initial, - p->rotation.final, - CG_CalculateTimeFrac( p->birthTime, - p->lifeTime, - p->rotation.delay ) ); - - // if the view would be "inside" the sprite, kill the sprite - // so it doesn't add too much overdraw - if( Distance( p->origin, cg.refdef.vieworg ) < re.radius && bp->overdrawProtection ) - return; - - if( bp->framerate == 0.0f ) - { - //sync animation time to lifeTime of particle - index = (int)( timeFrac * ( bp->numFrames + 1 ) ); - - if( index >= bp->numFrames ) - index = bp->numFrames - 1; - - re.customShader = bp->shaders[ index ]; - } - else - { - //looping animation - index = (int)( bp->framerate * timeFrac * p->lifeTime * 0.001 ) % bp->numFrames; - re.customShader = bp->shaders[ index ]; - } - - } - else if( bp->numModels ) //model based - { - re.reType = RT_MODEL; - - re.hModel = p->model; - - if( p->atRest ) - AxisCopy( p->lastAxis, re.axis ); - else - { - // convert direction of travel into axis - VectorNormalize2( p->velocity, re.axis[ 0 ] ); - - if( re.axis[ 0 ][ 0 ] == 0.0f && re.axis[ 0 ][ 1 ] == 0.0f ) - AxisCopy( axisDefault, re.axis ); - else - { - ProjectPointOnPlane( re.axis[ 2 ], up, re.axis[ 0 ] ); - VectorNormalize( re.axis[ 2 ] ); - CrossProduct( re.axis[ 2 ], re.axis[ 0 ], re.axis[ 1 ] ); - } - - AxisCopy( re.axis, p->lastAxis ); - } - - if( scale != 1.0f ) - { - VectorScale( re.axis[ 0 ], scale, re.axis[ 0 ] ); - VectorScale( re.axis[ 1 ], scale, re.axis[ 1 ] ); - VectorScale( re.axis[ 2 ], scale, re.axis[ 2 ] ); - re.nonNormalizedAxes = qtrue; - } - else - re.nonNormalizedAxes = qfalse; - - p->lf.animation = &bp->modelAnimation; - - //run animation - CG_RunLerpFrame( &p->lf ); - - re.oldframe = p->lf.oldFrame; - re.frame = p->lf.frame; - re.backlerp = p->lf.backlerp; - } - - if( bps->thirdPersonOnly && - CG_AttachmentCentNum( &ps->attachment ) == cg.snap->ps.clientNum && - !cg.renderingThirdPerson ) - re.renderfx |= RF_THIRD_PERSON; - - if( bp->dynamicLight && !( re.renderfx & RF_THIRD_PERSON ) ) - { - trap_R_AddLightToScene( p->origin, - CG_LerpValues( p->dLightRadius.initial, p->dLightRadius.final, - CG_CalculateTimeFrac( p->birthTime, p->lifeTime, p->dLightRadius.delay ) ), - (float)bp->dLightColor[ 0 ] / (float)0xFF, - (float)bp->dLightColor[ 1 ] / (float)0xFF, - (float)bp->dLightColor[ 2 ] / (float)0xFF ); - } - - VectorCopy( p->origin, re.origin ); - - trap_R_AddRefEntityToScene( &re ); -} - -/* -=============== -CG_AddParticles - -Add particles to the scene -=============== -*/ -void CG_AddParticles( void ) -{ - int i; - particle_t *p; - int numPS = 0, numPE = 0, numP = 0; - - //remove expired particle systems - CG_GarbageCollectParticleSystems( ); - - //check each ejector and introduce any new particles - CG_SpawnNewParticles( ); - - //sorting - if( cg_depthSortParticles.integer ) - CG_CompactAndSortParticles( ); - - for( i = 0; i < MAX_PARTICLES; i++ ) - { - p = sortedParticles[ i ]; - - if( p->valid ) - { - if( p->birthTime + p->lifeTime > cg.time ) - { - //particle is active - CG_EvaluateParticlePhysics( p ); - CG_RenderParticle( p ); - } - else - CG_DestroyParticle( p, NULL ); - } - } - - if( cg_debugParticles.integer >= 2 ) - { - for( i = 0; i < MAX_PARTICLE_SYSTEMS; i++ ) - if( particleSystems[ i ].valid ) - numPS++; - - for( i = 0; i < MAX_PARTICLE_EJECTORS; i++ ) - if( particleEjectors[ i ].valid ) - numPE++; - - for( i = 0; i < MAX_PARTICLES; i++ ) - if( particles[ i ].valid ) - numP++; - - CG_Printf( "PS: %d PE: %d P: %d\n", numPS, numPE, numP ); - } -} - -/* -=============== -CG_ParticleSystemEntity - -Particle system entity client code -=============== -*/ -void CG_ParticleSystemEntity( centity_t *cent ) -{ - entityState_t *es; - - es = ¢->currentState; - - if( es->eFlags & EF_NODRAW ) - { - if( CG_IsParticleSystemValid( ¢->entityPS ) && CG_IsParticleSystemInfinite( cent->entityPS ) ) - CG_DestroyParticleSystem( ¢->entityPS ); - - return; - } - - if( !CG_IsParticleSystemValid( ¢->entityPS ) && !cent->entityPSMissing ) - { - cent->entityPS = CG_SpawnNewParticleSystem( cgs.gameParticleSystems[ es->modelindex ] ); - - if( CG_IsParticleSystemValid( ¢->entityPS ) ) - { - CG_SetAttachmentPoint( ¢->entityPS->attachment, cent->lerpOrigin ); - CG_SetAttachmentCent( ¢->entityPS->attachment, cent ); - CG_AttachToPoint( ¢->entityPS->attachment ); - } - else - cent->entityPSMissing = qtrue; - } -} - -static particleSystem_t *testPS; -static qhandle_t testPSHandle; - -/* -=============== -CG_DestroyTestPS_f - -Destroy the test a particle system -=============== -*/ -void CG_DestroyTestPS_f( void ) -{ - if( CG_IsParticleSystemValid( &testPS ) ) - CG_DestroyParticleSystem( &testPS ); -} - -/* -=============== -CG_TestPS_f - -Test a particle system -=============== -*/ -void CG_TestPS_f( void ) -{ - vec3_t origin; - vec3_t up = { 0.0f, 0.0f, 1.0f }; - char psName[ MAX_QPATH ]; - - if( trap_Argc( ) < 2 ) - return; - - Q_strncpyz( psName, CG_Argv( 1 ), MAX_QPATH ); - testPSHandle = CG_RegisterParticleSystem( psName ); - - if( testPSHandle ) - { - CG_DestroyTestPS_f( ); - - testPS = CG_SpawnNewParticleSystem( testPSHandle ); - - VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[ 0 ], origin ); - - if( CG_IsParticleSystemValid( &testPS ) ) - { - CG_SetAttachmentPoint( &testPS->attachment, origin ); - CG_SetParticleSystemNormal( testPS, up ); - CG_AttachToPoint( &testPS->attachment ); - } - } -} diff --git a/src/cgame/cg_players.c b/src/cgame/cg_players.c deleted file mode 100644 index ac1ec181..00000000 --- a/src/cgame/cg_players.c +++ /dev/null @@ -1,2575 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_players.c -- handle the media and animation for player entities - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -char *cg_customSoundNames[ MAX_CUSTOM_SOUNDS ] = -{ - "*death1.wav", - "*death2.wav", - "*death3.wav", - "*jump1.wav", - "*pain25_1.wav", - "*pain50_1.wav", - "*pain75_1.wav", - "*pain100_1.wav", - "*falling1.wav", - "*gasp.wav", - "*drown.wav", - "*fall1.wav", - "*taunt.wav" -}; - - -/* -================ -CG_CustomSound - -================ -*/ -sfxHandle_t CG_CustomSound( int clientNum, const char *soundName ) -{ - clientInfo_t *ci; - int i; - - if( soundName[ 0 ] != '*' ) - return trap_S_RegisterSound( soundName, qfalse ); - - if( clientNum < 0 || clientNum >= MAX_CLIENTS ) - clientNum = 0; - - ci = &cgs.clientinfo[ clientNum ]; - - for( i = 0; i < MAX_CUSTOM_SOUNDS && cg_customSoundNames[ i ]; i++ ) - { - if( !strcmp( soundName, cg_customSoundNames[ i ] ) ) - return ci->sounds[ i ]; - } - - CG_Error( "Unknown custom sound: %s", soundName ); - return 0; -} - - - -/* -============================================================================= - -CLIENT INFO - -============================================================================= -*/ - -/* -====================== -CG_ParseAnimationFile - -Read a configuration file containing animation coutns and rates -models/players/visor/animation.cfg, etc -====================== -*/ -static qboolean CG_ParseAnimationFile( const char *filename, clientInfo_t *ci ) -{ - char *text_p, *prev; - int len; - int i; - char *token; - float fps; - int skip; - char text[ 20000 ]; - fileHandle_t f; - animation_t *animations; - - animations = ci->animations; - - // load the file - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - if( len <= 0 ) - return qfalse; - - if( len >= sizeof( text ) - 1 ) - { - CG_Printf( "File %s too long\n", filename ); - trap_FS_FCloseFile( f ); - return qfalse; - } - - trap_FS_Read( text, len, f ); - text[ len ] = 0; - trap_FS_FCloseFile( f ); - - // parse the text - text_p = text; - skip = 0; // quite the compiler warning - - ci->footsteps = FOOTSTEP_NORMAL; - VectorClear( ci->headOffset ); - ci->gender = GENDER_MALE; - ci->fixedlegs = qfalse; - ci->fixedtorso = qfalse; - ci->nonsegmented = qfalse; - - // read optional parameters - while( 1 ) - { - prev = text_p; // so we can unget - token = COM_Parse( &text_p ); - - if( !token ) - break; - - if( !Q_stricmp( token, "footsteps" ) ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - if( !Q_stricmp( token, "default" ) || !Q_stricmp( token, "normal" ) ) - ci->footsteps = FOOTSTEP_NORMAL; - else if( !Q_stricmp( token, "boot" ) ) - ci->footsteps = FOOTSTEP_BOOT; - else if( !Q_stricmp( token, "flesh" ) ) - ci->footsteps = FOOTSTEP_FLESH; - else if( !Q_stricmp( token, "mech" ) ) - ci->footsteps = FOOTSTEP_MECH; - else if( !Q_stricmp( token, "energy" ) ) - ci->footsteps = FOOTSTEP_ENERGY; - else if( !Q_stricmp( token, "none" ) ) - ci->footsteps = FOOTSTEP_NONE; - else if( !Q_stricmp( token, "custom" ) ) - ci->footsteps = FOOTSTEP_CUSTOM; - else - CG_Printf( "Bad footsteps parm in %s: %s\n", filename, token ); - - continue; - } - else if( !Q_stricmp( token, "headoffset" ) ) - { - for( i = 0 ; i < 3 ; i++ ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - ci->headOffset[ i ] = atof( token ); - } - - continue; - } - else if( !Q_stricmp( token, "sex" ) ) - { - token = COM_Parse( &text_p ); - - if( !token ) - break; - - if( token[ 0 ] == 'f' || token[ 0 ] == 'F' ) - ci->gender = GENDER_FEMALE; - else if( token[ 0 ] == 'n' || token[ 0 ] == 'N' ) - ci->gender = GENDER_NEUTER; - else - ci->gender = GENDER_MALE; - - continue; - } - else if( !Q_stricmp( token, "fixedlegs" ) ) - { - ci->fixedlegs = qtrue; - continue; - } - else if( !Q_stricmp( token, "fixedtorso" ) ) - { - ci->fixedtorso = qtrue; - continue; - } - else if( !Q_stricmp( token, "nonsegmented" ) ) - { - ci->nonsegmented = qtrue; - continue; - } - - // if it is a number, start parsing animations - if( token[ 0 ] >= '0' && token[ 0 ] <= '9' ) - { - text_p = prev; // unget the token - break; - } - - Com_Printf( "unknown token '%s' is %s\n", token, filename ); - } - - if( !ci->nonsegmented ) - { - // read information for each frame - for( i = 0; i < MAX_PLAYER_ANIMATIONS; i++ ) - { - token = COM_Parse( &text_p ); - - if( !*token ) - { - if( i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE ) - { - animations[ i ].firstFrame = animations[ TORSO_GESTURE ].firstFrame; - animations[ i ].frameLerp = animations[ TORSO_GESTURE ].frameLerp; - animations[ i ].initialLerp = animations[ TORSO_GESTURE ].initialLerp; - animations[ i ].loopFrames = animations[ TORSO_GESTURE ].loopFrames; - animations[ i ].numFrames = animations[ TORSO_GESTURE ].numFrames; - animations[ i ].reversed = qfalse; - animations[ i ].flipflop = qfalse; - continue; - } - - break; - } - - animations[ i ].firstFrame = atoi( token ); - - // leg only frames are adjusted to not count the upper body only frames - if( i == LEGS_WALKCR ) - skip = animations[ LEGS_WALKCR ].firstFrame - animations[ TORSO_GESTURE ].firstFrame; - - if( i >= LEGS_WALKCR && inonsegmented ) - { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName ); - ci->legsSkin = trap_R_RegisterSkin( filename ); - if( !ci->legsSkin ) - Com_Printf( "Leg skin load failure: %s\n", filename ); - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName ); - ci->torsoSkin = trap_R_RegisterSkin( filename ); - if( !ci->torsoSkin ) - Com_Printf( "Torso skin load failure: %s\n", filename ); - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/head_%s.skin", modelName, skinName ); - ci->headSkin = trap_R_RegisterSkin( filename ); - if( !ci->headSkin ) - Com_Printf( "Head skin load failure: %s\n", filename ); - - if( !ci->legsSkin || !ci->torsoSkin || !ci->headSkin ) - return qfalse; - } - else - { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/nonseg_%s.skin", modelName, skinName ); - ci->nonSegSkin = trap_R_RegisterSkin( filename ); - if( !ci->nonSegSkin ) - Com_Printf( "Non-segmented skin load failure: %s\n", filename ); - - if( !ci->nonSegSkin ) - return qfalse; - } - - return qtrue; -} - -/* -========================== -CG_RegisterClientModelname -========================== -*/ -static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName ) -{ - char filename[ MAX_QPATH * 2 ]; - - //TA: do this first so the nonsegmented property is set - // load the animations - Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName ); - if( !CG_ParseAnimationFile( filename, ci ) ) - { - Com_Printf( "Failed to load animation file %s\n", filename ); - return qfalse; - } - - // load cmodels before models so filecache works - - if( !ci->nonsegmented ) - { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName ); - ci->legsModel = trap_R_RegisterModel( filename ); - if( !ci->legsModel ) - { - Com_Printf( "Failed to load model file %s\n", filename ); - return qfalse; - } - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName ); - ci->torsoModel = trap_R_RegisterModel( filename ); - if( !ci->torsoModel ) - { - Com_Printf( "Failed to load model file %s\n", filename ); - return qfalse; - } - - Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", modelName ); - ci->headModel = trap_R_RegisterModel( filename ); - if( !ci->headModel ) - { - Com_Printf( "Failed to load model file %s\n", filename ); - return qfalse; - } - } - else - { - Com_sprintf( filename, sizeof( filename ), "models/players/%s/nonseg.md3", modelName ); - ci->nonSegModel = trap_R_RegisterModel( filename ); - if( !ci->nonSegModel ) - { - Com_Printf( "Failed to load model file %s\n", filename ); - return qfalse; - } - } - - // if any skins failed to load, return failure - if( !CG_RegisterClientSkin( ci, modelName, skinName ) ) - { - Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName ); - return qfalse; - } - - //FIXME: skins do not load without icon present. do we want icons anyway? -/* Com_sprintf( filename, sizeof( filename ), "models/players/%s/icon_%s.tga", modelName, skinName ); - ci->modelIcon = trap_R_RegisterShaderNoMip( filename ); - if( !ci->modelIcon ) - { - Com_Printf( "Failed to load icon file: %s\n", filename ); - return qfalse; - }*/ - - return qtrue; -} - -/* -==================== -CG_ColorFromString -==================== -*/ -static void CG_ColorFromString( const char *v, vec3_t color ) -{ - int val; - - VectorClear( color ); - - val = atoi( v ); - - if( val < 1 || val > 7 ) - { - VectorSet( color, 1, 1, 1 ); - return; - } - - if( val & 1 ) - color[ 2 ] = 1.0f; - - if( val & 2 ) - color[ 1 ] = 1.0f; - - if( val & 4 ) - color[ 0 ] = 1.0f; -} - - -/* -=================== -CG_LoadClientInfo - -Load it now, taking the disk hits -=================== -*/ -static void CG_LoadClientInfo( clientInfo_t *ci ) -{ - const char *dir, *fallback; - int i; - const char *s; - int clientNum; - - if( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName ) ) - { - if( cg_buildScript.integer ) - CG_Error( "CG_RegisterClientModelname( %s, %s ) failed", ci->modelName, ci->skinName ); - - // fall back - if( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default" ) ) - CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL ); - } - - // sounds - dir = ci->modelName; - fallback = DEFAULT_MODEL; - - for( i = 0; i < MAX_CUSTOM_SOUNDS; i++ ) - { - s = cg_customSoundNames[ i ]; - - if( !s ) - break; - - // fanny about a bit with sounds that are missing - if( !CG_FileExists( va( "sound/player/%s/%s", dir, s + 1 ) ) ) - { - //file doesn't exist - - if( i == 11 || i == 8 ) //fall or falling - { - ci->sounds[ i ] = trap_S_RegisterSound( "sound/null.wav", qfalse ); - } - else - { - if( i == 9 ) //gasp - s = cg_customSoundNames[ 7 ]; //pain100_1 - else if( i == 10 ) //drown - s = cg_customSoundNames[ 0 ]; //death1 - - ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", dir, s + 1 ), qfalse ); - if( !ci->sounds[ i ] ) - ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", fallback, s + 1 ), qfalse ); - } - } - else - { - ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", dir, s + 1 ), qfalse ); - if( !ci->sounds[ i ] ) - ci->sounds[ i ] = trap_S_RegisterSound( va( "sound/player/%s/%s", fallback, s + 1 ), qfalse ); - } - } - - if( ci->footsteps == FOOTSTEP_CUSTOM ) - { - for( i = 0; i < 4; i++ ) - { - ci->customFootsteps[ i ] = trap_S_RegisterSound( va( "sound/player/%s/step%d.wav", dir, i + 1 ), qfalse ); - if( !ci->customFootsteps[ i ] ) - ci->customFootsteps[ i ] = trap_S_RegisterSound( va( "sound/player/footsteps/step%d.wav", i + 1 ), qfalse ); - - ci->customMetalFootsteps[ i ] = trap_S_RegisterSound( va( "sound/player/%s/clank%d.wav", dir, i + 1 ), qfalse ); - if( !ci->customMetalFootsteps[ i ] ) - ci->customMetalFootsteps[ i ] = trap_S_RegisterSound( va( "sound/player/footsteps/clank%d.wav", i + 1 ), qfalse ); - } - } - - // reset any existing players and bodies, because they might be in bad - // frames for this new model - clientNum = ci - cgs.clientinfo; - for( i = 0; i < MAX_GENTITIES; i++ ) - { - if( cg_entities[ i ].currentState.clientNum == clientNum && - cg_entities[ i ].currentState.eType == ET_PLAYER ) - CG_ResetPlayerEntity( &cg_entities[ i ] ); - } -} - -/* -====================== -CG_CopyClientInfoModel -====================== -*/ -static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) -{ - VectorCopy( from->headOffset, to->headOffset ); - to->footsteps = from->footsteps; - to->gender = from->gender; - - to->legsModel = from->legsModel; - to->legsSkin = from->legsSkin; - to->torsoModel = from->torsoModel; - to->torsoSkin = from->torsoSkin; - to->headModel = from->headModel; - to->headSkin = from->headSkin; - to->nonSegModel = from->nonSegModel; - to->nonSegSkin = from->nonSegSkin; - to->nonsegmented = from->nonsegmented; - to->modelIcon = from->modelIcon; - - memcpy( to->animations, from->animations, sizeof( to->animations ) ); - memcpy( to->sounds, from->sounds, sizeof( to->sounds ) ); - memcpy( to->customFootsteps, from->customFootsteps, sizeof( to->customFootsteps ) ); - memcpy( to->customMetalFootsteps, from->customMetalFootsteps, sizeof( to->customMetalFootsteps ) ); -} - - -/* -====================== -CG_GetCorpseNum -====================== -*/ -static int CG_GetCorpseNum( pClass_t class ) -{ - int i; - clientInfo_t *match; - char *modelName; - char *skinName; - - modelName = BG_FindModelNameForClass( class ); - skinName = BG_FindSkinNameForClass( class ); - - for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ ) - { - match = &cgs.corpseinfo[ i ]; - - if( !match->infoValid ) - continue; - - if( !Q_stricmp( modelName, match->modelName ) - && !Q_stricmp( skinName, match->skinName ) ) - { - // this clientinfo is identical, so use it's handles - return i; - } - } - - //something has gone horribly wrong - return -1; -} - - -/* -====================== -CG_ScanForExistingClientInfo -====================== -*/ -static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) -{ - int i; - clientInfo_t *match; - - for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ ) - { - match = &cgs.corpseinfo[ i ]; - - if( !match->infoValid ) - continue; - - if( !Q_stricmp( ci->modelName, match->modelName ) && - !Q_stricmp( ci->skinName, match->skinName ) ) - { - // this clientinfo is identical, so use it's handles - CG_CopyClientInfoModel( match, ci ); - - return qtrue; - } - } - - //TA: shouldn't happen - return qfalse; -} - - -/* -====================== -CG_PrecacheClientInfo -====================== -*/ -void CG_PrecacheClientInfo( pClass_t class, char *model, char *skin ) -{ - clientInfo_t *ci; - clientInfo_t newInfo; - - ci = &cgs.corpseinfo[ class ]; - - // the old value - memset( &newInfo, 0, sizeof( newInfo ) ); - - // model - Q_strncpyz( newInfo.modelName, model, sizeof( newInfo.modelName ) ); - Q_strncpyz( newInfo.headModelName, model, sizeof( newInfo.headModelName ) ); - - // modelName didn not include a skin name - if( !skin ) - { - Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) ); - Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) ); - } - else - { - Q_strncpyz( newInfo.skinName, skin, sizeof( newInfo.skinName ) ); - Q_strncpyz( newInfo.headSkinName, skin, sizeof( newInfo.headSkinName ) ); - } - - newInfo.infoValid = qtrue; - - //TA: actually register the models - *ci = newInfo; - CG_LoadClientInfo( ci ); -} - - -/* -====================== -CG_NewClientInfo -====================== -*/ -void CG_NewClientInfo( int clientNum ) -{ - clientInfo_t *ci; - clientInfo_t newInfo; - const char *configstring; - const char *v; - char *slash; - - ci = &cgs.clientinfo[ clientNum ]; - - configstring = CG_ConfigString( clientNum + CS_PLAYERS ); - if( !configstring[ 0 ] ) - { - memset( ci, 0, sizeof( *ci ) ); - return; // player just left - } - - // the old value - memset( &newInfo, 0, sizeof( newInfo ) ); - - // isolate the player's name - v = Info_ValueForKey( configstring, "n" ); - Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) ); - - // colors - v = Info_ValueForKey( configstring, "c1" ); - CG_ColorFromString( v, newInfo.color1 ); - - v = Info_ValueForKey( configstring, "c2" ); - CG_ColorFromString( v, newInfo.color2 ); - - // bot skill - v = Info_ValueForKey( configstring, "skill" ); - newInfo.botSkill = atoi( v ); - - // handicap - v = Info_ValueForKey( configstring, "hc" ); - newInfo.handicap = atoi( v ); - - // wins - v = Info_ValueForKey( configstring, "w" ); - newInfo.wins = atoi( v ); - - // losses - v = Info_ValueForKey( configstring, "l" ); - newInfo.losses = atoi( v ); - - // team - v = Info_ValueForKey( configstring, "t" ); - newInfo.team = atoi( v ); - - // team task - v = Info_ValueForKey( configstring, "tt" ); - newInfo.teamTask = atoi( v ); - - // team leader - v = Info_ValueForKey( configstring, "tl" ); - newInfo.teamLeader = atoi( v ); - - v = Info_ValueForKey( configstring, "g_redteam" ); - Q_strncpyz( newInfo.redTeam, v, MAX_TEAMNAME ); - - v = Info_ValueForKey( configstring, "g_blueteam" ); - Q_strncpyz( newInfo.blueTeam, v, MAX_TEAMNAME ); - - // model - v = Info_ValueForKey( configstring, "model" ); - Q_strncpyz( newInfo.modelName, v, sizeof( newInfo.modelName ) ); - - slash = strchr( newInfo.modelName, '/' ); - - if( !slash ) - { - // modelName didn not include a skin name - Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) ); - } - else - { - Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) ); - // truncate modelName - *slash = 0; - } - - //CG_Printf( "NCI: %s\n", v ); - - // head model - v = Info_ValueForKey( configstring, "hmodel" ); - Q_strncpyz( newInfo.headModelName, v, sizeof( newInfo.headModelName ) ); - - slash = strchr( newInfo.headModelName, '/' ); - - if( !slash ) - { - // modelName didn not include a skin name - Q_strncpyz( newInfo.headSkinName, "default", sizeof( newInfo.headSkinName ) ); - } - else - { - Q_strncpyz( newInfo.headSkinName, slash + 1, sizeof( newInfo.headSkinName ) ); - // truncate modelName - *slash = 0; - } - - // replace whatever was there with the new one - newInfo.infoValid = qtrue; - *ci = newInfo; - - // scan for an existing clientinfo that matches this modelname - // so we can avoid loading checks if possible - if( !CG_ScanForExistingClientInfo( ci ) ) - CG_LoadClientInfo( ci ); -} - - - -/* -============================================================================= - -PLAYER ANIMATION - -============================================================================= -*/ - - -/* -=============== -CG_SetLerpFrameAnimation - -may include ANIM_TOGGLEBIT -=============== -*/ -static void CG_SetLerpFrameAnimation( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation ) -{ - animation_t *anim; - - lf->animationNumber = newAnimation; - newAnimation &= ~ANIM_TOGGLEBIT; - - if( newAnimation < 0 || newAnimation >= MAX_PLAYER_TOTALANIMATIONS ) - CG_Error( "Bad animation number: %i", newAnimation ); - - anim = &ci->animations[ newAnimation ]; - - lf->animation = anim; - lf->animationTime = lf->frameTime + anim->initialLerp; - - if( cg_debugAnim.integer ) - CG_Printf( "Anim: %i\n", newAnimation ); -} - -/* -=============== -CG_RunPlayerLerpFrame - -Sets cg.snap, cg.oldFrame, and cg.backlerp -cg.time should be between oldFrameTime and frameTime after exit -=============== -*/ -static void CG_RunPlayerLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int newAnimation, float speedScale ) -{ - int f, numFrames; - animation_t *anim; - - // debugging tool to get no animations - if( cg_animSpeed.integer == 0 ) - { - lf->oldFrame = lf->frame = lf->backlerp = 0; - return; - } - - // see if the animation sequence is switching - if( newAnimation != lf->animationNumber || !lf->animation ) - { - CG_SetLerpFrameAnimation( ci, lf, newAnimation ); - } - - // if we have passed the current frame, move it to - // oldFrame and calculate a new frame - if( cg.time >= lf->frameTime ) - { - lf->oldFrame = lf->frame; - lf->oldFrameTime = lf->frameTime; - - // get the next frame based on the animation - anim = lf->animation; - if( !anim->frameLerp ) - return; // shouldn't happen - - if( cg.time < lf->animationTime ) - lf->frameTime = lf->animationTime; // initial lerp - else - lf->frameTime = lf->oldFrameTime + anim->frameLerp; - - f = ( lf->frameTime - lf->animationTime ) / anim->frameLerp; - f *= speedScale; // adjust for haste, etc - numFrames = anim->numFrames; - - if( anim->flipflop ) - numFrames *= 2; - - if( f >= numFrames ) - { - f -= numFrames; - if( anim->loopFrames ) - { - f %= anim->loopFrames; - f += anim->numFrames - anim->loopFrames; - } - else - { - f = numFrames - 1; - // the animation is stuck at the end, so it - // can immediately transition to another sequence - lf->frameTime = cg.time; - } - } - - if( anim->reversed ) - lf->frame = anim->firstFrame + anim->numFrames - 1 - f; - else if( anim->flipflop && f>=anim->numFrames ) - lf->frame = anim->firstFrame + anim->numFrames - 1 - ( f % anim->numFrames ); - else - lf->frame = anim->firstFrame + f; - - if( cg.time > lf->frameTime ) - { - lf->frameTime = cg.time; - - if( cg_debugAnim.integer ) - CG_Printf( "Clamp lf->frameTime\n" ); - } - } - - if( lf->frameTime > cg.time + 200 ) - lf->frameTime = cg.time; - - if( lf->oldFrameTime > cg.time ) - lf->oldFrameTime = cg.time; - - // calculate current lerp value - if( lf->frameTime == lf->oldFrameTime ) - lf->backlerp = 0; - else - lf->backlerp = 1.0 - (float)( cg.time - lf->oldFrameTime ) / ( lf->frameTime - lf->oldFrameTime ); -} - - -/* -=============== -CG_ClearLerpFrame -=============== -*/ -static void CG_ClearLerpFrame( clientInfo_t *ci, lerpFrame_t *lf, int animationNumber ) -{ - lf->frameTime = lf->oldFrameTime = cg.time; - CG_SetLerpFrameAnimation( ci, lf, animationNumber ); - lf->oldFrame = lf->frame = lf->animation->firstFrame; -} - - -/* -=============== -CG_PlayerAnimation -=============== -*/ -static void CG_PlayerAnimation( centity_t *cent, int *legsOld, int *legs, float *legsBackLerp, - int *torsoOld, int *torso, float *torsoBackLerp ) -{ - clientInfo_t *ci; - int clientNum; - float speedScale = 1.0f; - - clientNum = cent->currentState.clientNum; - - if( cg_noPlayerAnims.integer ) - { - *legsOld = *legs = *torsoOld = *torso = 0; - return; - } - - ci = &cgs.clientinfo[ clientNum ]; - - // do the shuffle turn frames locally - if( cent->pe.legs.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == LEGS_IDLE ) - CG_RunPlayerLerpFrame( ci, ¢->pe.legs, LEGS_TURN, speedScale ); - else - CG_RunPlayerLerpFrame( ci, ¢->pe.legs, cent->currentState.legsAnim, speedScale ); - - *legsOld = cent->pe.legs.oldFrame; - *legs = cent->pe.legs.frame; - *legsBackLerp = cent->pe.legs.backlerp; - - CG_RunPlayerLerpFrame( ci, ¢->pe.torso, cent->currentState.torsoAnim, speedScale ); - - *torsoOld = cent->pe.torso.oldFrame; - *torso = cent->pe.torso.frame; - *torsoBackLerp = cent->pe.torso.backlerp; -} - - -/* -=============== -CG_PlayerNonSegAnimation -=============== -*/ -static void CG_PlayerNonSegAnimation( centity_t *cent, int *nonSegOld, - int *nonSeg, float *nonSegBackLerp ) -{ - clientInfo_t *ci; - int clientNum; - float speedScale = 1.0f; - - clientNum = cent->currentState.clientNum; - - if( cg_noPlayerAnims.integer ) - { - *nonSegOld = *nonSeg = 0; - return; - } - - ci = &cgs.clientinfo[ clientNum ]; - - // do the shuffle turn frames locally - if( cent->pe.nonseg.yawing && ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) == NSPA_STAND ) - CG_RunPlayerLerpFrame( ci, ¢->pe.nonseg, NSPA_TURN, speedScale ); - else - CG_RunPlayerLerpFrame( ci, ¢->pe.nonseg, cent->currentState.legsAnim, speedScale ); - - *nonSegOld = cent->pe.nonseg.oldFrame; - *nonSeg = cent->pe.nonseg.frame; - *nonSegBackLerp = cent->pe.nonseg.backlerp; -} - -/* -============================================================================= - -PLAYER ANGLES - -============================================================================= -*/ - -/* -================== -CG_SwingAngles -================== -*/ -static void CG_SwingAngles( float destination, float swingTolerance, float clampTolerance, - float speed, float *angle, qboolean *swinging ) -{ - float swing; - float move; - float scale; - - if( !*swinging ) - { - // see if a swing should be started - swing = AngleSubtract( *angle, destination ); - - if( swing > swingTolerance || swing < -swingTolerance ) - *swinging = qtrue; - } - - if( !*swinging ) - return; - - // modify the speed depending on the delta - // so it doesn't seem so linear - swing = AngleSubtract( destination, *angle ); - scale = fabs( swing ); - - if( scale < swingTolerance * 0.5 ) - scale = 0.5; - else if( scale < swingTolerance ) - scale = 1.0; - else - scale = 2.0; - - // swing towards the destination angle - if( swing >= 0 ) - { - move = cg.frametime * scale * speed; - - if( move >= swing ) - { - move = swing; - *swinging = qfalse; - } - *angle = AngleMod( *angle + move ); - } - else if( swing < 0 ) - { - move = cg.frametime * scale * -speed; - - if( move <= swing ) - { - move = swing; - *swinging = qfalse; - } - *angle = AngleMod( *angle + move ); - } - - // clamp to no more than tolerance - swing = AngleSubtract( destination, *angle ); - if( swing > clampTolerance ) - *angle = AngleMod( destination - ( clampTolerance - 1 ) ); - else if( swing < -clampTolerance ) - *angle = AngleMod( destination + ( clampTolerance - 1 ) ); -} - -/* -================= -CG_AddPainTwitch -================= -*/ -static void CG_AddPainTwitch( centity_t *cent, vec3_t torsoAngles ) -{ - int t; - float f; - - t = cg.time - cent->pe.painTime; - - if( t >= PAIN_TWITCH_TIME ) - return; - - f = 1.0 - (float)t / PAIN_TWITCH_TIME; - - if( cent->pe.painDirection ) - torsoAngles[ ROLL ] += 20 * f; - else - torsoAngles[ ROLL ] -= 20 * f; -} - - -/* -=============== -CG_PlayerAngles - -Handles seperate torso motion - - legs pivot based on direction of movement - - head always looks exactly at cent->lerpAngles - - if motion < 20 degrees, show in head only - if < 45 degrees, also show in torso -=============== -*/ -static void CG_PlayerAngles( centity_t *cent, vec3_t srcAngles, - vec3_t legs[ 3 ], vec3_t torso[ 3 ], vec3_t head[ 3 ] ) -{ - vec3_t legsAngles, torsoAngles, headAngles; - float dest; - static int movementOffsets[ 8 ] = { 0, 22, 45, -22, 0, 22, -45, -22 }; - vec3_t velocity; - float speed; - int dir, clientNum; - clientInfo_t *ci; - - VectorCopy( srcAngles, headAngles ); - headAngles[ YAW ] = AngleMod( headAngles[ YAW ] ); - VectorClear( legsAngles ); - VectorClear( torsoAngles ); - - // --------- yaw ------------- - - // allow yaw to drift a bit - if( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != LEGS_IDLE || - ( cent->currentState.torsoAnim & ~ANIM_TOGGLEBIT ) != TORSO_STAND ) - { - // if not standing still, always point all in the same direction - cent->pe.torso.yawing = qtrue; // always center - cent->pe.torso.pitching = qtrue; // always center - cent->pe.legs.yawing = qtrue; // always center - } - - // adjust legs for movement dir - if( cent->currentState.eFlags & EF_DEAD ) - { - // don't let dead bodies twitch - dir = 0; - } - else - { - //TA: did use angles2.. now uses time2.. looks a bit funny but time2 isn't used othwise - dir = cent->currentState.time2; - if( dir < 0 || dir > 7 ) - CG_Error( "Bad player movement angle" ); - } - - legsAngles[ YAW ] = headAngles[ YAW ] + movementOffsets[ dir ]; - torsoAngles[ YAW ] = headAngles[ YAW ] + 0.25 * movementOffsets[ dir ]; - - // torso - if( cent->currentState.eFlags & EF_DEAD ) - { - CG_SwingAngles( torsoAngles[ YAW ], 0, 0, cg_swingSpeed.value, - ¢->pe.torso.yawAngle, ¢->pe.torso.yawing ); - CG_SwingAngles( legsAngles[ YAW ], 0, 0, cg_swingSpeed.value, - ¢->pe.legs.yawAngle, ¢->pe.legs.yawing ); - } - else - { - CG_SwingAngles( torsoAngles[ YAW ], 25, 90, cg_swingSpeed.value, - ¢->pe.torso.yawAngle, ¢->pe.torso.yawing ); - CG_SwingAngles( legsAngles[ YAW ], 40, 90, cg_swingSpeed.value, - ¢->pe.legs.yawAngle, ¢->pe.legs.yawing ); - } - - torsoAngles[ YAW ] = cent->pe.torso.yawAngle; - legsAngles[ YAW ] = cent->pe.legs.yawAngle; - - // --------- pitch ------------- - - // only show a fraction of the pitch angle in the torso - if( headAngles[ PITCH ] > 180 ) - dest = ( -360 + headAngles[ PITCH ] ) * 0.75f; - else - dest = headAngles[ PITCH ] * 0.75f; - - CG_SwingAngles( dest, 15, 30, 0.1f, ¢->pe.torso.pitchAngle, ¢->pe.torso.pitching ); - torsoAngles[ PITCH ] = cent->pe.torso.pitchAngle; - - // - clientNum = cent->currentState.clientNum; - - if( clientNum >= 0 && clientNum < MAX_CLIENTS ) - { - ci = &cgs.clientinfo[ clientNum ]; - if( ci->fixedtorso ) - torsoAngles[ PITCH ] = 0.0f; - } - - // --------- roll ------------- - - - // lean towards the direction of travel - VectorCopy( cent->currentState.pos.trDelta, velocity ); - speed = VectorNormalize( velocity ); - - if( speed ) - { - vec3_t axis[ 3 ]; - float side; - - speed *= 0.05f; - - AnglesToAxis( legsAngles, axis ); - side = speed * DotProduct( velocity, axis[ 1 ] ); - legsAngles[ ROLL ] -= side; - - side = speed * DotProduct( velocity, axis[ 0 ] ); - legsAngles[ PITCH ] += side; - } - - // - clientNum = cent->currentState.clientNum; - - if( clientNum >= 0 && clientNum < MAX_CLIENTS ) - { - ci = &cgs.clientinfo[ clientNum ]; - - if( ci->fixedlegs ) - { - legsAngles[ YAW ] = torsoAngles[ YAW ]; - legsAngles[ PITCH ] = 0.0f; - legsAngles[ ROLL ] = 0.0f; - } - } - - // pain twitch - CG_AddPainTwitch( cent, torsoAngles ); - - // pull the angles back out of the hierarchial chain - AnglesSubtract( headAngles, torsoAngles, headAngles ); - AnglesSubtract( torsoAngles, legsAngles, torsoAngles ); - AnglesToAxis( legsAngles, legs ); - AnglesToAxis( torsoAngles, torso ); - AnglesToAxis( headAngles, head ); -} - -#define MODEL_WWSMOOTHTIME 200 - -/* -=============== -CG_PlayerWWSmoothing - -Smooth the angles of transitioning wall walkers -=============== -*/ -static void CG_PlayerWWSmoothing( centity_t *cent, vec3_t in[ 3 ], vec3_t out[ 3 ] ) -{ - entityState_t *es = ¢->currentState; - int i; - vec3_t surfNormal, rotAxis, temp; - vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; - vec3_t ceilingNormal = { 0.0f, 0.0f, -1.0f }; - float stLocal, sFraction, rotAngle; - vec3_t inAxis[ 3 ], lastAxis[ 3 ], outAxis[ 3 ]; - - //set surfNormal - if( !(es->eFlags & EF_WALLCLIMB ) ) - VectorCopy( refNormal, surfNormal ); - else if( !( es->eFlags & EF_WALLCLIMBCEILING ) ) - VectorCopy( es->angles2, surfNormal ); - else - VectorCopy( ceilingNormal, surfNormal ); - - AxisCopy( in, inAxis ); - - if( !VectorCompare( surfNormal, cent->pe.lastNormal ) ) - { - //if we moving from the ceiling to the floor special case - //( x product of colinear vectors is undefined) - if( VectorCompare( ceilingNormal, cent->pe.lastNormal ) && - VectorCompare( refNormal, surfNormal ) ) - { - VectorCopy( in[ 1 ], rotAxis ); - rotAngle = 180.0f; - } - else - { - AxisCopy( cent->pe.lastAxis, lastAxis ); - rotAngle = DotProduct( inAxis[ 0 ], lastAxis[ 0 ] ) + - DotProduct( inAxis[ 1 ], lastAxis[ 1 ] ) + - DotProduct( inAxis[ 2 ], lastAxis[ 2 ] ); - - rotAngle = RAD2DEG( acos( ( rotAngle - 1.0f ) / 2.0f ) ); - - CrossProduct( lastAxis[ 0 ], inAxis[ 0 ], temp ); - VectorCopy( temp, rotAxis ); - CrossProduct( lastAxis[ 1 ], inAxis[ 1 ], temp ); - VectorAdd( rotAxis, temp, rotAxis ); - CrossProduct( lastAxis[ 2 ], inAxis[ 2 ], temp ); - VectorAdd( rotAxis, temp, rotAxis ); - - VectorNormalize( rotAxis ); - } - - //iterate through smooth array - for( i = 0; i < MAXSMOOTHS; i++ ) - { - //found an unused index in the smooth array - if( cent->pe.sList[ i ].time + MODEL_WWSMOOTHTIME < cg.time ) - { - //copy to array and stop - VectorCopy( rotAxis, cent->pe.sList[ i ].rotAxis ); - cent->pe.sList[ i ].rotAngle = rotAngle; - cent->pe.sList[ i ].time = cg.time; - break; - } - } - } - - //iterate through ops - for( i = MAXSMOOTHS - 1; i >= 0; i-- ) - { - //if this op has time remaining, perform it - if( cg.time < cent->pe.sList[ i ].time + MODEL_WWSMOOTHTIME ) - { - stLocal = 1.0f - ( ( ( cent->pe.sList[ i ].time + MODEL_WWSMOOTHTIME ) - cg.time ) / MODEL_WWSMOOTHTIME ); - sFraction = -( cos( stLocal * M_PI ) + 1.0f ) / 2.0f; - - RotatePointAroundVector( outAxis[ 0 ], cent->pe.sList[ i ].rotAxis, - inAxis[ 0 ], sFraction * cent->pe.sList[ i ].rotAngle ); - RotatePointAroundVector( outAxis[ 1 ], cent->pe.sList[ i ].rotAxis, - inAxis[ 1 ], sFraction * cent->pe.sList[ i ].rotAngle ); - RotatePointAroundVector( outAxis[ 2 ], cent->pe.sList[ i ].rotAxis, - inAxis[ 2 ], sFraction * cent->pe.sList[ i ].rotAngle ); - - AxisCopy( outAxis, inAxis ); - } - } - - //outAxis has been copied to inAxis - AxisCopy( inAxis, out ); -} - -/* -=============== -CG_PlayerNonSegAngles - -Resolve angles for non-segmented models -=============== -*/ -static void CG_PlayerNonSegAngles( centity_t *cent, vec3_t srcAngles, vec3_t nonSegAxis[ 3 ] ) -{ - vec3_t localAngles; - vec3_t velocity; - float speed; - int dir; - entityState_t *es = ¢->currentState; - vec3_t surfNormal; - vec3_t ceilingNormal = { 0.0f, 0.0f, -1.0f }; - - VectorCopy( srcAngles, localAngles ); - localAngles[ YAW ] = AngleMod( localAngles[ YAW ] ); - localAngles[ PITCH ] = 0.0f; - localAngles[ ROLL ] = 0.0f; - - //set surfNormal - if( !( es->eFlags & EF_WALLCLIMBCEILING ) ) - VectorCopy( es->angles2, surfNormal ); - else - VectorCopy( ceilingNormal, surfNormal ); - - //make sure that WW transitions don't cause the swing stuff to go nuts - if( !VectorCompare( surfNormal, cent->pe.lastNormal ) ) - { - //stop CG_SwingAngles having an eppy - cent->pe.nonseg.yawAngle = localAngles[ YAW ]; - cent->pe.nonseg.yawing = qfalse; - } - - // --------- yaw ------------- - - // allow yaw to drift a bit - if( ( cent->currentState.legsAnim & ~ANIM_TOGGLEBIT ) != NSPA_STAND ) - { - // if not standing still, always point all in the same direction - cent->pe.nonseg.yawing = qtrue; // always center - } - - // adjust legs for movement dir - if( cent->currentState.eFlags & EF_DEAD ) - { - // don't let dead bodies twitch - dir = 0; - } - else - { - //TA: did use angles2.. now uses time2.. looks a bit funny but time2 isn't used othwise - dir = cent->currentState.time2; - if( dir < 0 || dir > 7 ) - CG_Error( "Bad player movement angle" ); - } - - // torso - if( cent->currentState.eFlags & EF_DEAD ) - { - CG_SwingAngles( localAngles[ YAW ], 0, 0, cg_swingSpeed.value, - ¢->pe.nonseg.yawAngle, ¢->pe.nonseg.yawing ); - } - else - { - CG_SwingAngles( localAngles[ YAW ], 40, 90, cg_swingSpeed.value, - ¢->pe.nonseg.yawAngle, ¢->pe.nonseg.yawing ); - } - - localAngles[ YAW ] = cent->pe.nonseg.yawAngle; - - // --------- pitch ------------- - - //NO PITCH! - - - // --------- roll ------------- - - - // lean towards the direction of travel - VectorCopy( cent->currentState.pos.trDelta, velocity ); - speed = VectorNormalize( velocity ); - - if( speed ) - { - vec3_t axis[ 3 ]; - float side; - - //much less than with the regular model system - speed *= 0.01f; - - AnglesToAxis( localAngles, axis ); - side = speed * DotProduct( velocity, axis[ 1 ] ); - localAngles[ ROLL ] -= side; - - side = speed * DotProduct( velocity, axis[ 0 ] ); - localAngles[ PITCH ] += side; - } - - //FIXME: PAIN[123] animations? - // pain twitch - //CG_AddPainTwitch( cent, torsoAngles ); - - AnglesToAxis( localAngles, nonSegAxis ); -} - - -//========================================================================== - -/* -=============== -CG_PlayerUpgrade -=============== -*/ -static void CG_PlayerUpgrades( centity_t *cent, refEntity_t *torso ) -{ - int held, active; - refEntity_t jetpack; - refEntity_t battpack; - refEntity_t flash; - entityState_t *es = ¢->currentState; - - held = es->modelindex; - active = es->modelindex2; - - if( held & ( 1 << UP_JETPACK ) ) - { - memset( &jetpack, 0, sizeof( jetpack ) ); - VectorCopy( torso->lightingOrigin, jetpack.lightingOrigin ); - jetpack.shadowPlane = torso->shadowPlane; - jetpack.renderfx = torso->renderfx; - - jetpack.hModel = cgs.media.jetpackModel; - - //identity matrix - AxisCopy( axisDefault, jetpack.axis ); - - //FIXME: change to tag_back when it exists - CG_PositionRotatedEntityOnTag( &jetpack, torso, torso->hModel, "tag_head" ); - - trap_R_AddRefEntityToScene( &jetpack ); - - if( active & ( 1 << UP_JETPACK ) ) - { - if( es->pos.trDelta[ 2 ] > 10.0f ) - { - if( cent->jetPackState != JPS_ASCENDING ) - { - if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - CG_DestroyParticleSystem( ¢->jetPackPS ); - - cent->jetPackPS = CG_SpawnNewParticleSystem( cgs.media.jetPackAscendPS ); - cent->jetPackState = JPS_ASCENDING; - } - - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, - vec3_origin, cgs.media.jetpackAscendSound ); - } - else if( es->pos.trDelta[ 2 ] < -10.0f ) - { - if( cent->jetPackState != JPS_DESCENDING ) - { - if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - CG_DestroyParticleSystem( ¢->jetPackPS ); - - cent->jetPackPS = CG_SpawnNewParticleSystem( cgs.media.jetPackDescendPS ); - cent->jetPackState = JPS_DESCENDING; - } - - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, - vec3_origin, cgs.media.jetpackDescendSound ); - } - else - { - if( cent->jetPackState != JPS_HOVERING ) - { - if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - CG_DestroyParticleSystem( ¢->jetPackPS ); - - cent->jetPackPS = CG_SpawnNewParticleSystem( cgs.media.jetPackHoverPS ); - cent->jetPackState = JPS_HOVERING; - } - - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, - vec3_origin, cgs.media.jetpackIdleSound ); - } - - memset( &flash, 0, sizeof( flash ) ); - VectorCopy( torso->lightingOrigin, flash.lightingOrigin ); - flash.shadowPlane = torso->shadowPlane; - flash.renderfx = torso->renderfx; - - flash.hModel = cgs.media.jetpackFlashModel; - if( !flash.hModel ) - return; - - AxisCopy( axisDefault, flash.axis ); - - CG_PositionRotatedEntityOnTag( &flash, &jetpack, jetpack.hModel, "tag_flash" ); - trap_R_AddRefEntityToScene( &flash ); - - if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - { - CG_SetAttachmentTag( ¢->jetPackPS->attachment, - jetpack, jetpack.hModel, "tag_flash" ); - CG_SetAttachmentCent( ¢->jetPackPS->attachment, cent ); - CG_AttachToTag( ¢->jetPackPS->attachment ); - } - } - else if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - { - CG_DestroyParticleSystem( ¢->jetPackPS ); - cent->jetPackState = JPS_OFF; - } - } - else if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - { - CG_DestroyParticleSystem( ¢->jetPackPS ); - cent->jetPackState = JPS_OFF; - } - - if( held & ( 1 << UP_BATTPACK ) ) - { - memset( &battpack, 0, sizeof( battpack ) ); - VectorCopy( torso->lightingOrigin, battpack.lightingOrigin ); - battpack.shadowPlane = torso->shadowPlane; - battpack.renderfx = torso->renderfx; - - battpack.hModel = cgs.media.battpackModel; - - //identity matrix - AxisCopy( axisDefault, battpack.axis ); - - //FIXME: change to tag_back when it exists - CG_PositionRotatedEntityOnTag( &battpack, torso, torso->hModel, "tag_head" ); - - trap_R_AddRefEntityToScene( &battpack ); - } - - if( es->eFlags & EF_BLOBLOCKED ) - { - vec3_t temp, origin, up = { 0.0f, 0.0f, 1.0f }; - trace_t tr; - float size; - - VectorCopy( es->pos.trBase, temp ); - temp[ 2 ] -= 4096.0f; - - CG_Trace( &tr, es->pos.trBase, NULL, NULL, temp, es->number, MASK_SOLID ); - VectorCopy( tr.endpos, origin ); - - size = 32.0f; - - if( size > 0.0f ) - CG_ImpactMark( cgs.media.creepShader, origin, up, - 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, size, qtrue ); - } -} - - -/* -=============== -CG_PlayerFloatSprite - -Float a sprite over the player's head -=============== -*/ -static void CG_PlayerFloatSprite( centity_t *cent, qhandle_t shader ) -{ - int rf; - refEntity_t ent; - - if( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) - rf = RF_THIRD_PERSON; // only show in mirrors - else - rf = 0; - - memset( &ent, 0, sizeof( ent ) ); - VectorCopy( cent->lerpOrigin, ent.origin ); - ent.origin[ 2 ] += 48; - ent.reType = RT_SPRITE; - ent.customShader = shader; - ent.radius = 10; - ent.renderfx = rf; - ent.shaderRGBA[ 0 ] = 255; - ent.shaderRGBA[ 1 ] = 255; - ent.shaderRGBA[ 2 ] = 255; - ent.shaderRGBA[ 3 ] = 255; - trap_R_AddRefEntityToScene( &ent ); -} - - - -/* -=============== -CG_PlayerSprites - -Float sprites over the player's head -=============== -*/ -static void CG_PlayerSprites( centity_t *cent ) -{ - if( cent->currentState.eFlags & EF_CONNECTION ) - { - CG_PlayerFloatSprite( cent, cgs.media.connectionShader ); - return; - } - - if( cent->currentState.eFlags & EF_TALK ) - { - //TA: the masses have decreed this to be wrong -/* CG_PlayerFloatSprite( cent, cgs.media.balloonShader ); - return;*/ - } -} - -/* -=============== -CG_PlayerShadow - -Returns the Z component of the surface being shadowed - - should it return a full plane instead of a Z? -=============== -*/ -#define SHADOW_DISTANCE 128 -static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane, pClass_t class ) -{ - vec3_t end, mins, maxs; - trace_t trace; - float alpha; - entityState_t *es = ¢->currentState; - vec3_t surfNormal = { 0.0f, 0.0f, 1.0f }; - - BG_FindBBoxForClass( class, mins, maxs, NULL, NULL, NULL ); - mins[ 2 ] = 0.0f; - maxs[ 2 ] = 2.0f; - - if( es->eFlags & EF_WALLCLIMB ) - { - if( es->eFlags & EF_WALLCLIMBCEILING ) - VectorSet( surfNormal, 0.0f, 0.0f, -1.0f ); - else - VectorCopy( es->angles2, surfNormal ); - } - - *shadowPlane = 0; - - if( cg_shadows.integer == 0 ) - return qfalse; - - // send a trace down from the player to the ground - VectorCopy( cent->lerpOrigin, end ); - VectorMA( cent->lerpOrigin, -SHADOW_DISTANCE, surfNormal, end ); - - trap_CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID ); - - // no shadow if too high - if( trace.fraction == 1.0 || trace.startsolid || trace.allsolid ) - return qfalse; - - //TA: FIXME: stencil shadows will be broken for walls. - // Unfortunately there isn't much that can be - // done since Q3 references only the Z coord - // of the shadowPlane - if( surfNormal[ 2 ] < 0.0f ) - *shadowPlane = trace.endpos[ 2 ] - 1.0f; - else - *shadowPlane = trace.endpos[ 2 ] + 1.0f; - - if( cg_shadows.integer != 1 ) // no mark for stencil or projection shadows - return qtrue; - - // fade the shadow out with height - alpha = 1.0 - trace.fraction; - - // add the mark as a temporary, so it goes directly to the renderer - // without taking a spot in the cg_marks array - CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal, - cent->pe.legs.yawAngle, alpha, alpha, alpha, 1, qfalse, - 24.0f * BG_FindShadowScaleForClass( class ), qtrue ); - - return qtrue; -} - - -/* -=============== -CG_PlayerSplash - -Draw a mark at the water surface -=============== -*/ -static void CG_PlayerSplash( centity_t *cent ) -{ - vec3_t start, end; - trace_t trace; - int contents; - polyVert_t verts[ 4 ]; - - if( !cg_shadows.integer ) - return; - - VectorCopy( cent->lerpOrigin, end ); - end[ 2 ] -= 24; - - // if the feet aren't in liquid, don't make a mark - // this won't handle moving water brushes, but they wouldn't draw right anyway... - contents = trap_CM_PointContents( end, 0 ); - - if( !( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) - return; - - VectorCopy( cent->lerpOrigin, start ); - start[ 2 ] += 32; - - // if the head isn't out of liquid, don't make a mark - contents = trap_CM_PointContents( start, 0 ); - - if( contents & ( CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) - return; - - // trace down to find the surface - trap_CM_BoxTrace( &trace, start, end, NULL, NULL, 0, ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ); - - if( trace.fraction == 1.0 ) - return; - - // create a mark polygon - VectorCopy( trace.endpos, verts[ 0 ].xyz ); - verts[ 0 ].xyz[ 0 ] -= 32; - verts[ 0 ].xyz[ 1 ] -= 32; - verts[ 0 ].st[ 0 ] = 0; - verts[ 0 ].st[ 1 ] = 0; - verts[ 0 ].modulate[ 0 ] = 255; - verts[ 0 ].modulate[ 1 ] = 255; - verts[ 0 ].modulate[ 2 ] = 255; - verts[ 0 ].modulate[ 3 ] = 255; - - VectorCopy( trace.endpos, verts[ 1 ].xyz ); - verts[ 1 ].xyz[ 0 ] -= 32; - verts[ 1 ].xyz[ 1 ] += 32; - verts[ 1 ].st[ 0 ] = 0; - verts[ 1 ].st[ 1 ] = 1; - verts[ 1 ].modulate[ 0 ] = 255; - verts[ 1 ].modulate[ 1 ] = 255; - verts[ 1 ].modulate[ 2 ] = 255; - verts[ 1 ].modulate[ 3 ] = 255; - - VectorCopy( trace.endpos, verts[ 2 ].xyz ); - verts[ 2 ].xyz[ 0 ] += 32; - verts[ 2 ].xyz[ 1 ] += 32; - verts[ 2 ].st[ 0 ] = 1; - verts[ 2 ].st[ 1 ] = 1; - verts[ 2 ].modulate[ 0 ] = 255; - verts[ 2 ].modulate[ 1 ] = 255; - verts[ 2 ].modulate[ 2 ] = 255; - verts[ 2 ].modulate[ 3 ] = 255; - - VectorCopy( trace.endpos, verts[ 3 ].xyz ); - verts[ 3 ].xyz[ 0 ] += 32; - verts[ 3 ].xyz[ 1 ] -= 32; - verts[ 3 ].st[ 0 ] = 1; - verts[ 3 ].st[ 1 ] = 0; - verts[ 3 ].modulate[ 0 ] = 255; - verts[ 3 ].modulate[ 1 ] = 255; - verts[ 3 ].modulate[ 2 ] = 255; - verts[ 3 ].modulate[ 3 ] = 255; - - trap_R_AddPolyToScene( cgs.media.wakeMarkShader, 4, verts ); -} - - -/* -================= -CG_LightVerts -================= -*/ -int CG_LightVerts( vec3_t normal, int numVerts, polyVert_t *verts ) -{ - int i, j; - float incoming; - vec3_t ambientLight; - vec3_t lightDir; - vec3_t directedLight; - - trap_R_LightForPoint( verts[ 0 ].xyz, ambientLight, directedLight, lightDir ); - - for( i = 0; i < numVerts; i++ ) - { - incoming = DotProduct( normal, lightDir ); - - if( incoming <= 0 ) - { - verts[ i ].modulate[ 0 ] = ambientLight[ 0 ]; - verts[ i ].modulate[ 1 ] = ambientLight[ 1 ]; - verts[ i ].modulate[ 2 ] = ambientLight[ 2 ]; - verts[ i ].modulate[ 3 ] = 255; - continue; - } - - j = ( ambientLight[ 0 ] + incoming * directedLight[ 0 ] ); - - if( j > 255 ) - j = 255; - - verts[ i ].modulate[ 0 ] = j; - - j = ( ambientLight[ 1 ] + incoming * directedLight[ 1 ] ); - - if( j > 255 ) - j = 255; - - verts[ i ].modulate[ 1 ] = j; - - j = ( ambientLight[ 2 ] + incoming * directedLight[ 2 ] ); - - if( j > 255 ) - j = 255; - - verts[ i ].modulate[ 2 ] = j; - - verts[ i ].modulate[ 3 ] = 255; - } - return qtrue; -} - - -/* -================= -CG_LightFromDirection -================= -*/ -int CG_LightFromDirection( vec3_t point, vec3_t direction ) -{ - int j; - float incoming; - vec3_t ambientLight; - vec3_t lightDir; - vec3_t directedLight; - vec3_t result; - - trap_R_LightForPoint( point, ambientLight, directedLight, lightDir ); - - incoming = DotProduct( direction, lightDir ); - - if( incoming <= 0 ) - { - result[ 0 ] = ambientLight[ 0 ]; - result[ 1 ] = ambientLight[ 1 ]; - result[ 2 ] = ambientLight[ 2 ]; - return (int)( (float)( result[ 0 ] + result[ 1 ] + result[ 2 ] ) / 3.0f ); - } - - j = ( ambientLight[ 0 ] + incoming * directedLight[ 0 ] ); - - if( j > 255 ) - j = 255; - - result[ 0 ] = j; - - j = ( ambientLight[ 1 ] + incoming * directedLight[ 1 ] ); - - if( j > 255 ) - j = 255; - - result[ 1 ] = j; - - j = ( ambientLight[ 2 ] + incoming * directedLight[ 2 ] ); - - if( j > 255 ) - j = 255; - - result[ 2 ] = j; - - return (int)((float)( result[ 0 ] + result[ 1 ] + result[ 2 ] ) / 3.0f ); -} - - -/* -================= -CG_AmbientLight -================= -*/ -int CG_AmbientLight( vec3_t point ) -{ - vec3_t ambientLight; - vec3_t lightDir; - vec3_t directedLight; - vec3_t result; - - trap_R_LightForPoint( point, ambientLight, directedLight, lightDir ); - - result[ 0 ] = ambientLight[ 0 ]; - result[ 1 ] = ambientLight[ 1 ]; - result[ 2 ] = ambientLight[ 2 ]; - return (int)((float)( result[ 0 ] + result[ 1 ] + result[ 2 ] ) / 3.0f ); -} - -#define TRACE_DEPTH 32.0f - -/* -=============== -CG_Player -=============== -*/ -void CG_Player( centity_t *cent ) -{ - clientInfo_t *ci; - - //TA: NOTE: legs is used for nonsegmented models - // this helps reduce code to be changed - refEntity_t legs; - refEntity_t torso; - refEntity_t head; - int clientNum; - int renderfx; - qboolean shadow = qfalse; - float shadowPlane; - entityState_t *es = ¢->currentState; - pClass_t class = ( es->powerups >> 8 ) & 0xFF; - float scale; - vec3_t tempAxis[ 3 ], tempAxis2[ 3 ]; - vec3_t angles; - int held = es->modelindex; - vec3_t surfNormal = { 0.0f, 0.0f, 1.0f }; - - // the client number is stored in clientNum. It can't be derived - // from the entity number, because a single client may have - // multiple corpses on the level using the same clientinfo - clientNum = es->clientNum; - if( clientNum < 0 || clientNum >= MAX_CLIENTS ) - CG_Error( "Bad clientNum on player entity" ); - - ci = &cgs.clientinfo[ clientNum ]; - - // it is possible to see corpses from disconnected players that may - // not have valid clientinfo - if( !ci->infoValid ) - return; - - //don't draw - if( es->eFlags & EF_NODRAW ) - return; - - // get the player model information - renderfx = 0; - if( es->number == cg.snap->ps.clientNum ) - { - if( !cg.renderingThirdPerson ) - renderfx = RF_THIRD_PERSON; // only draw in mirrors - else if( cg_cameraMode.integer ) - return; - } - - if( cg_drawBBOX.integer ) - { - vec3_t mins, maxs; - - BG_FindBBoxForClass( class, mins, maxs, NULL, NULL, NULL ); - CG_DrawBoundingBox( cent->lerpOrigin, mins, maxs ); - } - - memset( &legs, 0, sizeof( legs ) ); - memset( &torso, 0, sizeof( torso ) ); - memset( &head, 0, sizeof( head ) ); - - VectorCopy( cent->lerpAngles, angles ); - AnglesToAxis( cent->lerpAngles, tempAxis ); - - //rotate lerpAngles to floor - if( es->eFlags & EF_WALLCLIMB && - BG_RotateAxis( es->angles2, tempAxis, tempAxis2, qtrue, es->eFlags & EF_WALLCLIMBCEILING ) ) - AxisToAngles( tempAxis2, angles ); - else - VectorCopy( cent->lerpAngles, angles ); - - //normalise the pitch - if( angles[ PITCH ] < -180.0f ) - angles[ PITCH ] += 360.0f; - - // get the rotation information - if( !ci->nonsegmented ) - CG_PlayerAngles( cent, angles, legs.axis, torso.axis, head.axis ); - else - CG_PlayerNonSegAngles( cent, angles, legs.axis ); - - AxisCopy( legs.axis, tempAxis ); - - //rotate the legs axis to back to the wall - if( es->eFlags & EF_WALLCLIMB && - BG_RotateAxis( es->angles2, legs.axis, tempAxis, qfalse, es->eFlags & EF_WALLCLIMBCEILING ) ) - AxisCopy( tempAxis, legs.axis ); - - //smooth out WW transitions so the model doesn't hop around - CG_PlayerWWSmoothing( cent, legs.axis, legs.axis ); - - AxisCopy( tempAxis, cent->pe.lastAxis ); - - // get the animation state (after rotation, to allow feet shuffle) - if( !ci->nonsegmented ) - CG_PlayerAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp, - &torso.oldframe, &torso.frame, &torso.backlerp ); - else - CG_PlayerNonSegAnimation( cent, &legs.oldframe, &legs.frame, &legs.backlerp ); - - // add the talk baloon or disconnect icon - CG_PlayerSprites( cent ); - - // add the shadow - if( ( es->number == cg.snap->ps.clientNum && cg.renderingThirdPerson ) || - es->number != cg.snap->ps.clientNum ) - shadow = CG_PlayerShadow( cent, &shadowPlane, class ); - - // add a water splash if partially in and out of water - CG_PlayerSplash( cent ); - - if( cg_shadows.integer == 3 && shadow ) - renderfx |= RF_SHADOW_PLANE; - - renderfx |= RF_LIGHTING_ORIGIN; // use the same origin for all - - // - // add the legs - // - if( !ci->nonsegmented ) - { - legs.hModel = ci->legsModel; - - if( held & ( 1 << UP_LIGHTARMOUR ) ) - legs.customSkin = cgs.media.larmourLegsSkin; - else - legs.customSkin = ci->legsSkin; - } - else - { - legs.hModel = ci->nonSegModel; - legs.customSkin = ci->nonSegSkin; - } - - VectorCopy( cent->lerpOrigin, legs.origin ); - - VectorCopy( cent->lerpOrigin, legs.lightingOrigin ); - legs.shadowPlane = shadowPlane; - legs.renderfx = renderfx; - VectorCopy( legs.origin, legs.oldorigin ); // don't positionally lerp at all - - //move the origin closer into the wall with a CapTrace - if( es->eFlags & EF_WALLCLIMB && !( es->eFlags & EF_DEAD ) && !( cg.intermissionStarted ) ) - { - vec3_t start, end, mins, maxs; - trace_t tr; - - if( es->eFlags & EF_WALLCLIMBCEILING ) - VectorSet( surfNormal, 0.0f, 0.0f, -1.0f ); - else - VectorCopy( es->angles2, surfNormal ); - - BG_FindBBoxForClass( class, mins, maxs, NULL, NULL, NULL ); - - VectorMA( legs.origin, -TRACE_DEPTH, surfNormal, end ); - VectorMA( legs.origin, 1.0f, surfNormal, start ); - CG_CapTrace( &tr, start, mins, maxs, end, es->number, MASK_PLAYERSOLID ); - - //if the trace misses completely then just use legs.origin - //apparently capsule traces are "smaller" than box traces - if( tr.fraction != 1.0f ) - VectorMA( legs.origin, tr.fraction * -TRACE_DEPTH, surfNormal, legs.origin ); - - VectorCopy( legs.origin, legs.lightingOrigin ); - VectorCopy( legs.origin, legs.oldorigin ); // don't positionally lerp at all - } - - //rescale the model - scale = BG_FindModelScaleForClass( class ); - - if( scale != 1.0f ) - { - VectorScale( legs.axis[ 0 ], scale, legs.axis[ 0 ] ); - VectorScale( legs.axis[ 1 ], scale, legs.axis[ 1 ] ); - VectorScale( legs.axis[ 2 ], scale, legs.axis[ 2 ] ); - - legs.nonNormalizedAxes = qtrue; - } - - //offset on the Z axis if required - VectorMA( legs.origin, BG_FindZOffsetForClass( class ), surfNormal, legs.origin ); - VectorCopy( legs.origin, legs.lightingOrigin ); - VectorCopy( legs.origin, legs.oldorigin ); // don't positionally lerp at all - - trap_R_AddRefEntityToScene( &legs ); - - // if the model failed, allow the default nullmodel to be displayed - if( !legs.hModel ) - return; - - if( !ci->nonsegmented ) - { - // - // add the torso - // - torso.hModel = ci->torsoModel; - - if( held & ( 1 << UP_LIGHTARMOUR ) ) - torso.customSkin = cgs.media.larmourTorsoSkin; - else - torso.customSkin = ci->torsoSkin; - - if( !torso.hModel ) - return; - - VectorCopy( cent->lerpOrigin, torso.lightingOrigin ); - - CG_PositionRotatedEntityOnTag( &torso, &legs, ci->legsModel, "tag_torso" ); - - torso.shadowPlane = shadowPlane; - torso.renderfx = renderfx; - - trap_R_AddRefEntityToScene( &torso ); - - // - // add the head - // - head.hModel = ci->headModel; - - if( held & ( 1 << UP_HELMET ) ) - head.customSkin = cgs.media.larmourHeadSkin; - else - head.customSkin = ci->headSkin; - - if( !head.hModel ) - return; - - VectorCopy( cent->lerpOrigin, head.lightingOrigin ); - - CG_PositionRotatedEntityOnTag( &head, &torso, ci->torsoModel, "tag_head" ); - - head.shadowPlane = shadowPlane; - head.renderfx = renderfx; - - trap_R_AddRefEntityToScene( &head ); - } - - // - // add the gun / barrel / flash - // - if( es->weapon != WP_NONE ) - { - if( !ci->nonsegmented ) - CG_AddPlayerWeapon( &torso, NULL, cent ); - else - CG_AddPlayerWeapon( &legs, NULL, cent ); - } - - CG_PlayerUpgrades( cent, &torso ); - - //sanity check that particle systems are stopped when dead - if( es->eFlags & EF_DEAD ) - { - if( CG_IsParticleSystemValid( ¢->muzzlePS ) ) - CG_DestroyParticleSystem( ¢->muzzlePS ); - - if( CG_IsParticleSystemValid( ¢->jetPackPS ) ) - CG_DestroyParticleSystem( ¢->jetPackPS ); - } - - VectorCopy( surfNormal, cent->pe.lastNormal ); -} - -/* -=============== -CG_Corpse -=============== -*/ -void CG_Corpse( centity_t *cent ) -{ - clientInfo_t *ci; - refEntity_t legs; - refEntity_t torso; - refEntity_t head; - entityState_t *es = ¢->currentState; - int corpseNum; - int renderfx; - qboolean shadow = qfalse; - float shadowPlane; - vec3_t origin, liveZ, deadZ; - float scale; - - corpseNum = CG_GetCorpseNum( es->clientNum ); - - if( corpseNum < 0 || corpseNum >= MAX_CLIENTS ) - CG_Error( "Bad corpseNum on corpse entity: %d", corpseNum ); - - ci = &cgs.corpseinfo[ corpseNum ]; - - // it is possible to see corpses from disconnected players that may - // not have valid clientinfo - if( !ci->infoValid ) - return; - - memset( &legs, 0, sizeof( legs ) ); - memset( &torso, 0, sizeof( torso ) ); - memset( &head, 0, sizeof( head ) ); - - VectorCopy( cent->lerpOrigin, origin ); - BG_FindBBoxForClass( es->clientNum, liveZ, NULL, NULL, deadZ, NULL ); - origin[ 2 ] -= ( liveZ[ 2 ] - deadZ[ 2 ] ); - - VectorCopy( es->angles, cent->lerpAngles ); - - // get the rotation information - if( !ci->nonsegmented ) - CG_PlayerAngles( cent, cent->lerpAngles, legs.axis, torso.axis, head.axis ); - else - CG_PlayerNonSegAngles( cent, cent->lerpAngles, legs.axis ); - - //set the correct frame (should always be dead) - if( cg_noPlayerAnims.integer ) - legs.oldframe = legs.frame = torso.oldframe = torso.frame = 0; - else if( !ci->nonsegmented ) - { - memset( ¢->pe.legs, 0, sizeof( lerpFrame_t ) ); - CG_RunPlayerLerpFrame( ci, ¢->pe.legs, es->legsAnim, 1 ); - legs.oldframe = cent->pe.legs.oldFrame; - legs.frame = cent->pe.legs.frame; - legs.backlerp = cent->pe.legs.backlerp; - - memset( ¢->pe.torso, 0, sizeof( lerpFrame_t ) ); - CG_RunPlayerLerpFrame( ci, ¢->pe.torso, es->torsoAnim, 1 ); - torso.oldframe = cent->pe.torso.oldFrame; - torso.frame = cent->pe.torso.frame; - torso.backlerp = cent->pe.torso.backlerp; - } - else - { - memset( ¢->pe.nonseg, 0, sizeof( lerpFrame_t ) ); - CG_RunPlayerLerpFrame( ci, ¢->pe.nonseg, es->legsAnim, 1 ); - legs.oldframe = cent->pe.nonseg.oldFrame; - legs.frame = cent->pe.nonseg.frame; - legs.backlerp = cent->pe.nonseg.backlerp; - } - - // add the shadow - shadow = CG_PlayerShadow( cent, &shadowPlane, es->clientNum ); - - // get the player model information - renderfx = 0; - - if( cg_shadows.integer == 3 && shadow ) - renderfx |= RF_SHADOW_PLANE; - - renderfx |= RF_LIGHTING_ORIGIN; // use the same origin for all - - // - // add the legs - // - if( !ci->nonsegmented ) - { - legs.hModel = ci->legsModel; - legs.customSkin = ci->legsSkin; - } - else - { - legs.hModel = ci->nonSegModel; - legs.customSkin = ci->nonSegSkin; - } - - VectorCopy( origin, legs.origin ); - - VectorCopy( origin, legs.lightingOrigin ); - legs.shadowPlane = shadowPlane; - legs.renderfx = renderfx; - legs.origin[ 2 ] += BG_FindZOffsetForClass( es->clientNum ); - VectorCopy( legs.origin, legs.oldorigin ); // don't positionally lerp at all - - //rescale the model - scale = BG_FindModelScaleForClass( es->clientNum ); - - if( scale != 1.0f ) - { - VectorScale( legs.axis[ 0 ], scale, legs.axis[ 0 ] ); - VectorScale( legs.axis[ 1 ], scale, legs.axis[ 1 ] ); - VectorScale( legs.axis[ 2 ], scale, legs.axis[ 2 ] ); - - legs.nonNormalizedAxes = qtrue; - } - - //CG_AddRefEntityWithPowerups( &legs, es->powerups, ci->team ); - trap_R_AddRefEntityToScene( &legs ); - - // if the model failed, allow the default nullmodel to be displayed - if( !legs.hModel ) - return; - - if( !ci->nonsegmented ) - { - // - // add the torso - // - torso.hModel = ci->torsoModel; - if( !torso.hModel ) - return; - - torso.customSkin = ci->torsoSkin; - - VectorCopy( origin, torso.lightingOrigin ); - - CG_PositionRotatedEntityOnTag( &torso, &legs, ci->legsModel, "tag_torso" ); - - torso.shadowPlane = shadowPlane; - torso.renderfx = renderfx; - - //CG_AddRefEntityWithPowerups( &torso, es->powerups, ci->team ); - trap_R_AddRefEntityToScene( &torso ); - - // - // add the head - // - head.hModel = ci->headModel; - if( !head.hModel ) - return; - - head.customSkin = ci->headSkin; - - VectorCopy( origin, head.lightingOrigin ); - - CG_PositionRotatedEntityOnTag( &head, &torso, ci->torsoModel, "tag_head"); - - head.shadowPlane = shadowPlane; - head.renderfx = renderfx; - - //CG_AddRefEntityWithPowerups( &head, es->powerups, ci->team ); - trap_R_AddRefEntityToScene( &head ); - } -} - - -//===================================================================== - -/* -=============== -CG_ResetPlayerEntity - -A player just came into view or teleported, so reset all animation info -=============== -*/ -void CG_ResetPlayerEntity( centity_t *cent ) -{ - cent->errorTime = -99999; // guarantee no error decay added - cent->extrapolated = qfalse; - - CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], - ¢->pe.legs, cent->currentState.legsAnim ); - CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], - ¢->pe.torso, cent->currentState.torsoAnim ); - CG_ClearLerpFrame( &cgs.clientinfo[ cent->currentState.clientNum ], - ¢->pe.nonseg, cent->currentState.legsAnim ); - - BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin ); - BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles ); - - VectorCopy( cent->lerpOrigin, cent->rawOrigin ); - VectorCopy( cent->lerpAngles, cent->rawAngles ); - - memset( ¢->pe.legs, 0, sizeof( cent->pe.legs ) ); - cent->pe.legs.yawAngle = cent->rawAngles[ YAW ]; - cent->pe.legs.yawing = qfalse; - cent->pe.legs.pitchAngle = 0; - cent->pe.legs.pitching = qfalse; - - memset( ¢->pe.torso, 0, sizeof( cent->pe.legs ) ); - cent->pe.torso.yawAngle = cent->rawAngles[ YAW ]; - cent->pe.torso.yawing = qfalse; - cent->pe.torso.pitchAngle = cent->rawAngles[ PITCH ]; - cent->pe.torso.pitching = qfalse; - - memset( ¢->pe.nonseg, 0, sizeof( cent->pe.nonseg ) ); - cent->pe.nonseg.yawAngle = cent->rawAngles[ YAW ]; - cent->pe.nonseg.yawing = qfalse; - cent->pe.nonseg.pitchAngle = cent->rawAngles[ PITCH ]; - cent->pe.nonseg.pitching = qfalse; - - if( cg_debugPosition.integer ) - CG_Printf( "%i ResetPlayerEntity yaw=%i\n", cent->currentState.number, cent->pe.torso.yawAngle ); -} - -/* -================== -CG_PlayerDisconnect - -Player disconnecting -================== -*/ -void CG_PlayerDisconnect( vec3_t org ) -{ - particleSystem_t *ps; - - trap_S_StartSound( org, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.disconnectSound ); - - ps = CG_SpawnNewParticleSystem( cgs.media.disconnectPS ); - - if( CG_IsParticleSystemValid( &ps ) ) - { - CG_SetAttachmentPoint( &ps->attachment, org ); - CG_AttachToPoint( &ps->attachment ); - } -} - -/* -================= -CG_Bleed - -This is the spurt of blood when a character gets hit -================= -*/ -void CG_Bleed( vec3_t origin, vec3_t normal, int entityNum ) -{ - pTeam_t team = cgs.clientinfo[ entityNum ].team; - qhandle_t bleedPS; - particleSystem_t *ps; - - if( !cg_blood.integer ) - return; - - if( team == PTE_ALIENS ) - bleedPS = cgs.media.alienBleedPS; - else if( team == PTE_HUMANS ) - bleedPS = cgs.media.humanBleedPS; - else - return; - - ps = CG_SpawnNewParticleSystem( bleedPS ); - - if( CG_IsParticleSystemValid( &ps ) ) - { - CG_SetAttachmentPoint( &ps->attachment, origin ); - CG_SetAttachmentCent( &ps->attachment, &cg_entities[ entityNum ] ); - CG_AttachToPoint( &ps->attachment ); - - CG_SetParticleSystemNormal( ps, normal ); - } -} diff --git a/src/cgame/cg_playerstate.c b/src/cgame/cg_playerstate.c deleted file mode 100644 index 489b024d..00000000 --- a/src/cgame/cg_playerstate.c +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_playerstate.c -- this file acts on changes in a new playerState_t -// With normal play, this will be done after local prediction, but when -// following another player or playing back a demo, it will be checked -// when the snapshot transitions like all the other entities - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -/* -============== -CG_DamageFeedback -============== -*/ -void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) -{ - float left, front, up; - float kick; - int health; - float scale; - vec3_t dir; - vec3_t angles; - float dist; - float yaw, pitch; - - // show the attacking player's head and name in corner - cg.attackerTime = cg.time; - - // the lower on health you are, the greater the view kick will be - health = cg.snap->ps.stats[STAT_HEALTH]; - - if( health < 40 ) - scale = 1; - else - scale = 40.0 / health; - - kick = damage * scale; - - if( kick < 5 ) - kick = 5; - - if( kick > 10 ) - kick = 10; - - // if yaw and pitch are both 255, make the damage always centered (falling, etc) - if( yawByte == 255 && pitchByte == 255 ) - { - cg.damageX = 0; - cg.damageY = 0; - cg.v_dmg_roll = 0; - cg.v_dmg_pitch = -kick; - } - else - { - // positional - pitch = pitchByte / 255.0 * 360; - yaw = yawByte / 255.0 * 360; - - angles[ PITCH ] = pitch; - angles[ YAW ] = yaw; - angles[ ROLL ] = 0; - - AngleVectors( angles, dir, NULL, NULL ); - VectorSubtract( vec3_origin, dir, dir ); - - front = DotProduct( dir, cg.refdef.viewaxis[ 0 ] ); - left = DotProduct( dir, cg.refdef.viewaxis[ 1 ] ); - up = DotProduct( dir, cg.refdef.viewaxis[ 2 ] ); - - dir[ 0 ] = front; - dir[ 1 ] = left; - dir[ 2 ] = 0; - dist = VectorLength( dir ); - - if( dist < 0.1f ) - dist = 0.1f; - - cg.v_dmg_roll = kick * left; - - cg.v_dmg_pitch = -kick * front; - - if( front <= 0.1 ) - front = 0.1f; - - cg.damageX = -left / front; - cg.damageY = up / dist; - } - - // clamp the position - if( cg.damageX > 1.0 ) - cg.damageX = 1.0; - - if( cg.damageX < - 1.0 ) - cg.damageX = -1.0; - - if( cg.damageY > 1.0 ) - cg.damageY = 1.0; - - if( cg.damageY < - 1.0 ) - cg.damageY = -1.0; - - // don't let the screen flashes vary as much - if( kick > 10 ) - kick = 10; - - cg.damageValue = kick; - cg.v_dmg_time = cg.time + DAMAGE_TIME; - cg.damageTime = cg.snap->serverTime; -} - - - - -/* -================ -CG_Respawn - -A respawn happened this snapshot -================ -*/ -void CG_Respawn( void ) -{ - // no error decay on player movement - cg.thisFrameTeleport = qtrue; - - // display weapons available - cg.weaponSelectTime = cg.time; - - // select the weapon the server says we are using - cg.weaponSelect = cg.snap->ps.weapon; - - CG_ResetPainBlend( ); -} - -/* -============== -CG_CheckPlayerstateEvents - -============== -*/ -void CG_CheckPlayerstateEvents( playerState_t *ps, playerState_t *ops ) -{ - int i; - int event; - centity_t *cent; - - if( ps->externalEvent && ps->externalEvent != ops->externalEvent ) - { - cent = &cg_entities[ ps->clientNum ]; - cent->currentState.event = ps->externalEvent; - cent->currentState.eventParm = ps->externalEventParm; - CG_EntityEvent( cent, cent->lerpOrigin ); - } - - cent = &cg.predictedPlayerEntity; // cg_entities[ ps->clientNum ]; - - // go through the predictable events buffer - for( i = ps->eventSequence - MAX_PS_EVENTS; i < ps->eventSequence; i++ ) - { - // if we have a new predictable event - if( i >= ops->eventSequence || - // or the server told us to play another event instead of a predicted event we already issued - // or something the server told us changed our prediction causing a different event - ( i > ops->eventSequence - MAX_PS_EVENTS && ps->events[ i & ( MAX_PS_EVENTS - 1 ) ] != - ops->events[ i & ( MAX_PS_EVENTS - 1 ) ] ) ) - { - event = ps->events[ i & ( MAX_PS_EVENTS - 1 ) ]; - - cent->currentState.event = event; - cent->currentState.eventParm = ps->eventParms[ i & ( MAX_PS_EVENTS - 1 ) ]; - CG_EntityEvent( cent, cent->lerpOrigin ); - cg.predictableEvents[ i & ( MAX_PREDICTED_EVENTS - 1 ) ] = event; - - cg.eventSequence++; - } - } -} - - -/* -================== -CG_CheckChangedPredictableEvents -================== -*/ -void CG_CheckChangedPredictableEvents( playerState_t *ps ) -{ - int i; - int event; - centity_t *cent; - - cent = &cg.predictedPlayerEntity; - - for( i = ps->eventSequence - MAX_PS_EVENTS; i < ps->eventSequence; i++ ) - { - // - if( i >= cg.eventSequence ) - continue; - - // if this event is not further back in than the maximum predictable events we remember - if( i > cg.eventSequence - MAX_PREDICTED_EVENTS ) - { - // if the new playerstate event is different from a previously predicted one - if( ps->events[ i & ( MAX_PS_EVENTS - 1 ) ] != cg.predictableEvents[ i & ( MAX_PREDICTED_EVENTS - 1 ) ] ) - { - event = ps->events[ i & ( MAX_PS_EVENTS - 1 ) ]; - cent->currentState.event = event; - cent->currentState.eventParm = ps->eventParms[ i & ( MAX_PS_EVENTS - 1 ) ]; - CG_EntityEvent( cent, cent->lerpOrigin ); - - cg.predictableEvents[ i & ( MAX_PREDICTED_EVENTS - 1 ) ] = event; - - if( cg_showmiss.integer ) - CG_Printf( "WARNING: changed predicted event\n" ); - } - } - } -} - -/* -================== -CG_CheckLocalSounds -================== -*/ -void CG_CheckLocalSounds( playerState_t *ps, playerState_t *ops ) -{ - int reward; - - // don't play the sounds if the player just changed teams - if( ps->persistant[ PERS_TEAM ] != ops->persistant[ PERS_TEAM ] ) - return; - - // health changes of more than -1 should make pain sounds - if( ps->stats[ STAT_HEALTH ] < ops->stats[ STAT_HEALTH ] - 1 ) - { - if( ps->stats[ STAT_HEALTH ] > 0 ) - CG_PainEvent( &cg.predictedPlayerEntity, ps->stats[ STAT_HEALTH ] ); - } - - - // if we are going into the intermission, don't start any voices - if( cg.intermissionStarted ) - return; - - // reward sounds - reward = qfalse; -} - - -/* -=============== -CG_TransitionPlayerState - -=============== -*/ -void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) -{ - // check for changing follow mode - if( ps->clientNum != ops->clientNum ) - { - cg.thisFrameTeleport = qtrue; - // make sure we don't get any unwanted transition effects - *ops = *ps; - - CG_ResetPainBlend( ); - } - - // damage events (player is getting wounded) - if( ps->damageEvent != ops->damageEvent && ps->damageCount ) - CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount ); - - // respawning - if( ps->persistant[ PERS_SPAWN_COUNT ] != ops->persistant[ PERS_SPAWN_COUNT ] ) - CG_Respawn( ); - - if( cg.mapRestart ) - { - CG_Respawn( ); - cg.mapRestart = qfalse; - } - - if( cg.snap->ps.pm_type != PM_INTERMISSION && - ps->persistant[ PERS_TEAM ] != TEAM_SPECTATOR ) - CG_CheckLocalSounds( ps, ops ); - - // run events - CG_CheckPlayerstateEvents( ps, ops ); - - // smooth the ducking viewheight change - if( ps->viewheight != ops->viewheight ) - { - cg.duckChange = ps->viewheight - ops->viewheight; - cg.duckTime = cg.time; - } -} - diff --git a/src/cgame/cg_predict.c b/src/cgame/cg_predict.c deleted file mode 100644 index dc6c9dd5..00000000 --- a/src/cgame/cg_predict.c +++ /dev/null @@ -1,615 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_predict.c -- this file generates cg.predictedPlayerState by either -// interpolating between snapshots from the server or locally predicting -// ahead the client's movement. -// It also handles local physics interaction, like fragments bouncing off walls - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -static pmove_t cg_pmove; - -static int cg_numSolidEntities; -static centity_t *cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT]; -static int cg_numTriggerEntities; -static centity_t *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT]; - -/* -==================== -CG_BuildSolidList - -When a new cg.snap has been set, this function builds a sublist -of the entities that are actually solid, to make for more -efficient collision detection -==================== -*/ -void CG_BuildSolidList( void ) -{ - int i; - centity_t *cent; - snapshot_t *snap; - entityState_t *ent; - - cg_numSolidEntities = 0; - cg_numTriggerEntities = 0; - - if( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) - snap = cg.nextSnap; - else - snap = cg.snap; - - for( i = 0; i < snap->numEntities; i++ ) - { - cent = &cg_entities[ snap->entities[ i ].number ]; - ent = ¢->currentState; - - if( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) - { - cg_triggerEntities[ cg_numTriggerEntities ] = cent; - cg_numTriggerEntities++; - continue; - } - - if( cent->nextState.solid && ent->eType != ET_MISSILE ) - { - cg_solidEntities[ cg_numSolidEntities ] = cent; - cg_numSolidEntities++; - continue; - } - } -} - -/* -==================== -CG_ClipMoveToEntities - -==================== -*/ -static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, - int skipNumber, int mask, trace_t *tr, qboolean capsule ) -{ - int i, j, x, zd, zu; - trace_t trace; - entityState_t *ent; - clipHandle_t cmodel; - vec3_t bmins, bmaxs; - vec3_t origin, angles; - centity_t *cent; - - //SUPAR HACK - //this causes a trace to collide with the local player - if( skipNumber == MAGIC_TRACE_HACK ) - j = cg_numSolidEntities + 1; - else - j = cg_numSolidEntities; - - for( i = 0; i < j; i++ ) - { - if( i < cg_numSolidEntities ) - cent = cg_solidEntities[ i ]; - else - cent = &cg.predictedPlayerEntity; - - ent = ¢->currentState; - - if( ent->number == skipNumber ) - continue; - - if( ent->solid == SOLID_BMODEL ) - { - // special value for bmodel - cmodel = trap_CM_InlineModel( ent->modelindex ); - VectorCopy( cent->lerpAngles, angles ); - BG_EvaluateTrajectory( ¢->currentState.pos, cg.physicsTime, origin ); - } - else - { - // encoded bbox - x = ( ent->solid & 255 ); - zd = ( ( ent->solid >> 8 ) & 255 ); - zu = ( ( ent->solid >> 16 ) & 255 ) - 32; - - bmins[ 0 ] = bmins[ 1 ] = -x; - bmaxs[ 0 ] = bmaxs[ 1 ] = x; - bmins[ 2 ] = -zd; - bmaxs[ 2 ] = zu; - - if( i == cg_numSolidEntities ) - BG_FindBBoxForClass( ( ent->powerups >> 8 ) & 0xFF, bmins, bmaxs, NULL, NULL, NULL ); - - cmodel = trap_CM_TempBoxModel( bmins, bmaxs ); - VectorCopy( vec3_origin, angles ); - VectorCopy( cent->lerpOrigin, origin ); - } - - - if( capsule ) - { - trap_CM_TransformedCapsuleTrace ( &trace, start, end, - mins, maxs, cmodel, mask, origin, angles ); - } - else - { - trap_CM_TransformedBoxTrace ( &trace, start, end, - mins, maxs, cmodel, mask, origin, angles ); - } - - if( trace.allsolid || trace.fraction < tr->fraction ) - { - trace.entityNum = ent->number; - *tr = trace; - } - else if( trace.startsolid ) - tr->startsolid = qtrue; - - if( tr->allsolid ) - return; - } -} - -/* -================ -CG_Trace -================ -*/ -void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, - int skipNumber, int mask ) -{ - trace_t t; - - trap_CM_BoxTrace( &t, start, end, mins, maxs, 0, mask ); - t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE; - // check all other solid models - CG_ClipMoveToEntities( start, mins, maxs, end, skipNumber, mask, &t, qfalse ); - - *result = t; -} - -/* -================ -CG_CapTrace -================ -*/ -void CG_CapTrace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, - int skipNumber, int mask ) -{ - trace_t t; - - trap_CM_CapsuleTrace( &t, start, end, mins, maxs, 0, mask ); - t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE; - // check all other solid models - CG_ClipMoveToEntities( start, mins, maxs, end, skipNumber, mask, &t, qtrue ); - - *result = t; -} - -/* -================ -CG_PointContents -================ -*/ -int CG_PointContents( const vec3_t point, int passEntityNum ) -{ - int i; - entityState_t *ent; - centity_t *cent; - clipHandle_t cmodel; - int contents; - - contents = trap_CM_PointContents (point, 0); - - for( i = 0; i < cg_numSolidEntities; i++ ) - { - cent = cg_solidEntities[ i ]; - - ent = ¢->currentState; - - if( ent->number == passEntityNum ) - continue; - - if( ent->solid != SOLID_BMODEL ) // special value for bmodel - continue; - - cmodel = trap_CM_InlineModel( ent->modelindex ); - - if( !cmodel ) - continue; - - contents |= trap_CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles ); - } - - return contents; -} - - -/* -======================== -CG_InterpolatePlayerState - -Generates cg.predictedPlayerState by interpolating between -cg.snap->player_state and cg.nextFrame->player_state -======================== -*/ -static void CG_InterpolatePlayerState( qboolean grabAngles ) -{ - float f; - int i; - playerState_t *out; - snapshot_t *prev, *next; - - out = &cg.predictedPlayerState; - prev = cg.snap; - next = cg.nextSnap; - - *out = cg.snap->ps; - - // if we are still allowing local input, short circuit the view angles - if( grabAngles ) - { - usercmd_t cmd; - int cmdNum; - - cmdNum = trap_GetCurrentCmdNumber( ); - trap_GetUserCmd( cmdNum, &cmd ); - - PM_UpdateViewAngles( out, &cmd ); - } - - // if the next frame is a teleport, we can't lerp to it - if( cg.nextFrameTeleport ) - return; - - if( !next || next->serverTime <= prev->serverTime ) - return; - - f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime ); - - i = next->ps.bobCycle; - if( i < prev->ps.bobCycle ) - i += 256; // handle wraparound - - out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle ); - - for( i = 0; i < 3; i++ ) - { - out->origin[ i ] = prev->ps.origin[ i ] + f * ( next->ps.origin[ i ] - prev->ps.origin[ i ] ); - - if( !grabAngles ) - out->viewangles[ i ] = LerpAngle( prev->ps.viewangles[ i ], next->ps.viewangles[ i ], f ); - - out->velocity[ i ] = prev->ps.velocity[ i ] + - f * (next->ps.velocity[ i ] - prev->ps.velocity[ i ] ); - } -} - - -/* -========================= -CG_TouchTriggerPrediction - -Predict push triggers and items -========================= -*/ -static void CG_TouchTriggerPrediction( void ) -{ - int i; - trace_t trace; - entityState_t *ent; - clipHandle_t cmodel; - centity_t *cent; - qboolean spectator; - - // dead clients don't activate triggers - if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 ) - return; - - spectator = ( cg.predictedPlayerState.pm_type == PM_SPECTATOR ); - - if( cg.predictedPlayerState.pm_type != PM_NORMAL && !spectator ) - return; - - for( i = 0; i < cg_numTriggerEntities; i++ ) - { - cent = cg_triggerEntities[ i ]; - ent = ¢->currentState; - - if( ent->solid != SOLID_BMODEL ) - continue; - - cmodel = trap_CM_InlineModel( ent->modelindex ); - if( !cmodel ) - continue; - - trap_CM_BoxTrace( &trace, cg.predictedPlayerState.origin, cg.predictedPlayerState.origin, - cg_pmove.mins, cg_pmove.maxs, cmodel, -1 ); - - if( !trace.startsolid ) - continue; - - if( ent->eType == ET_TELEPORT_TRIGGER ) - cg.hyperspace = qtrue; - } - - // if we didn't touch a jump pad this pmove frame - if( cg.predictedPlayerState.jumppad_frame != cg.predictedPlayerState.pmove_framecount ) - { - cg.predictedPlayerState.jumppad_frame = 0; - cg.predictedPlayerState.jumppad_ent = 0; - } -} - - - -/* -================= -CG_PredictPlayerState - -Generates cg.predictedPlayerState for the current cg.time -cg.predictedPlayerState is guaranteed to be valid after exiting. - -For demo playback, this will be an interpolation between two valid -playerState_t. - -For normal gameplay, it will be the result of predicted usercmd_t on -top of the most recent playerState_t received from the server. - -Each new snapshot will usually have one or more new usercmd over the last, -but we simulate all unacknowledged commands each time, not just the new ones. -This means that on an internet connection, quite a few pmoves may be issued -each frame. - -OPTIMIZE: don't re-simulate unless the newly arrived snapshot playerState_t -differs from the predicted one. Would require saving all intermediate -playerState_t during prediction. - -We detect prediction errors and allow them to be decayed off over several frames -to ease the jerk. -================= -*/ -void CG_PredictPlayerState( void ) -{ - int cmdNum, current, i; - playerState_t oldPlayerState; - qboolean moved; - usercmd_t oldestCmd; - usercmd_t latestCmd; - - cg.hyperspace = qfalse; // will be set if touching a trigger_teleport - - // if this is the first frame we must guarantee - // predictedPlayerState is valid even if there is some - // other error condition - if( !cg.validPPS ) - { - cg.validPPS = qtrue; - cg.predictedPlayerState = cg.snap->ps; - } - - - // demo playback just copies the moves - if( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_FOLLOW) ) - { - CG_InterpolatePlayerState( qfalse ); - return; - } - - // non-predicting local movement will grab the latest angles - if( cg_nopredict.integer || cg_synchronousClients.integer ) - { - CG_InterpolatePlayerState( qtrue ); - return; - } - - // prepare for pmove - cg_pmove.ps = &cg.predictedPlayerState; - cg_pmove.trace = CG_Trace; - cg_pmove.pointcontents = CG_PointContents; - cg_pmove.debugLevel = cg_debugMove.integer; - - if( cg_pmove.ps->pm_type == PM_DEAD ) - cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; - else - cg_pmove.tracemask = MASK_PLAYERSOLID; - - if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) - cg_pmove.tracemask &= ~CONTENTS_BODY; // spectators can fly through bodies - - cg_pmove.noFootsteps = 0; - - // save the state before the pmove so we can detect transitions - oldPlayerState = cg.predictedPlayerState; - - current = trap_GetCurrentCmdNumber( ); - - // if we don't have the commands right after the snapshot, we - // can't accurately predict a current position, so just freeze at - // the last good position we had - cmdNum = current - CMD_BACKUP + 1; - trap_GetUserCmd( cmdNum, &oldestCmd ); - - if( oldestCmd.serverTime > cg.snap->ps.commandTime && - oldestCmd.serverTime < cg.time ) - { // special check for map_restart - if( cg_showmiss.integer ) - CG_Printf( "exceeded PACKET_BACKUP on commands\n" ); - - return; - } - - // get the latest command so we can know which commands are from previous map_restarts - trap_GetUserCmd( current, &latestCmd ); - - // get the most recent information we have, even if - // the server time is beyond our current cg.time, - // because predicted player positions are going to - // be ahead of everything else anyway - if( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) - { - cg.predictedPlayerState = cg.nextSnap->ps; - cg.physicsTime = cg.nextSnap->serverTime; - } - else - { - cg.predictedPlayerState = cg.snap->ps; - cg.physicsTime = cg.snap->serverTime; - } - - if( pmove_msec.integer < 8 ) - trap_Cvar_Set( "pmove_msec", "8" ); - else if( pmove_msec.integer > 33 ) - trap_Cvar_Set( "pmove_msec", "33" ); - - cg_pmove.pmove_fixed = pmove_fixed.integer;// | cg_pmove_fixed.integer; - cg_pmove.pmove_msec = pmove_msec.integer; - - // run cmds - moved = qfalse; - - for( cmdNum = current - CMD_BACKUP + 1; cmdNum <= current; cmdNum++ ) - { - // get the command - trap_GetUserCmd( cmdNum, &cg_pmove.cmd ); - - if( cg_pmove.pmove_fixed ) - PM_UpdateViewAngles( cg_pmove.ps, &cg_pmove.cmd ); - - // don't do anything if the time is before the snapshot player time - if( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) - continue; - - // don't do anything if the command was from a previous map_restart - if( cg_pmove.cmd.serverTime > latestCmd.serverTime ) - continue; - - // check for a prediction error from last frame - // on a lan, this will often be the exact value - // from the snapshot, but on a wan we will have - // to predict several commands to get to the point - // we want to compare - if( cg.predictedPlayerState.commandTime == oldPlayerState.commandTime ) - { - vec3_t delta; - float len; - - if( cg.thisFrameTeleport ) - { - // a teleport will not cause an error decay - VectorClear( cg.predictedError ); - - if( cg_showmiss.integer ) - CG_Printf( "PredictionTeleport\n" ); - - cg.thisFrameTeleport = qfalse; - } - else - { - vec3_t adjusted; - CG_AdjustPositionForMover( cg.predictedPlayerState.origin, - cg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted ); - - if( cg_showmiss.integer ) - { - if( !VectorCompare( oldPlayerState.origin, adjusted ) ) - CG_Printf("prediction error\n"); - } - - VectorSubtract( oldPlayerState.origin, adjusted, delta ); - len = VectorLength( delta ); - - if( len > 0.1 ) - { - if( cg_showmiss.integer ) - CG_Printf( "Prediction miss: %f\n", len ); - - if( cg_errorDecay.integer ) - { - int t; - float f; - - t = cg.time - cg.predictedErrorTime; - f = ( cg_errorDecay.value - t ) / cg_errorDecay.value; - - if( f < 0 ) - f = 0; - - if( f > 0 && cg_showmiss.integer ) - CG_Printf( "Double prediction decay: %f\n", f ); - - VectorScale( cg.predictedError, f, cg.predictedError ); - } - else - VectorClear( cg.predictedError ); - - VectorAdd( delta, cg.predictedError, cg.predictedError ); - cg.predictedErrorTime = cg.oldTime; - } - } - } - - // don't predict gauntlet firing, which is only supposed to happen - // when it actually inflicts damage - for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) - cg_pmove.autoWeaponHit[ i ] = qfalse; - - if( cg_pmove.pmove_fixed ) - cg_pmove.cmd.serverTime = ( ( cg_pmove.cmd.serverTime + pmove_msec.integer - 1 ) / - pmove_msec.integer ) * pmove_msec.integer; - - Pmove( &cg_pmove ); - - moved = qtrue; - - // add push trigger movement effects - CG_TouchTriggerPrediction( ); - - // check for predictable events that changed from previous predictions - //CG_CheckChangedPredictableEvents(&cg.predictedPlayerState); - } - - if( cg_showmiss.integer > 1 ) - CG_Printf( "[%i : %i] ", cg_pmove.cmd.serverTime, cg.time ); - - if( !moved ) - { - if( cg_showmiss.integer ) - CG_Printf( "not moved\n" ); - - return; - } - - // adjust for the movement of the groundentity - CG_AdjustPositionForMover( cg.predictedPlayerState.origin, - cg.predictedPlayerState.groundEntityNum, - cg.physicsTime, cg.time, cg.predictedPlayerState.origin ); - - if( cg_showmiss.integer ) - { - if( cg.predictedPlayerState.eventSequence > oldPlayerState.eventSequence + MAX_PS_EVENTS ) - CG_Printf( "WARNING: dropped event\n" ); - } - - // fire events and other transition triggered things - CG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState ); - - if( cg_showmiss.integer ) - { - if( cg.eventSequence > cg.predictedPlayerState.eventSequence ) - { - CG_Printf( "WARNING: double event\n" ); - cg.eventSequence = cg.predictedPlayerState.eventSequence; - } - } -} diff --git a/src/cgame/cg_ptr.c b/src/cgame/cg_ptr.c deleted file mode 100644 index c31e5e40..00000000 --- a/src/cgame/cg_ptr.c +++ /dev/null @@ -1,71 +0,0 @@ -// cg_ptr.c -- post timeout restoration handling - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -#define PTRC_FILE "ptrc.cfg" - -/* -=============== -CG_ReadPTRCode - -Read a PTR code from disk -=============== -*/ -int CG_ReadPTRCode( void ) -{ - int len; - char text[ 16 ]; - fileHandle_t f; - - // load the file - len = trap_FS_FOpenFile( PTRC_FILE, &f, FS_READ ); - if( len <= 0 ) - return 0; - - // should never happen - malformed write - if( len >= sizeof( text ) - 1 ) - return 0; - - trap_FS_Read( text, len, f ); - text[ len ] = 0; - trap_FS_FCloseFile( f ); - - return atoi( text ); -} - -/* -=============== -CG_WritePTRCode - -Write a PTR code to disk -=============== -*/ -void CG_WritePTRCode( int code ) -{ - char text[ 16 ]; - fileHandle_t f; - - Com_sprintf( text, 16, "%d", code ); - - // open file - if( trap_FS_FOpenFile( PTRC_FILE, &f, FS_WRITE ) < 0 ) - return; - - // write the code - trap_FS_Write( text, strlen( text ), f ); - - trap_FS_FCloseFile( f ); -} diff --git a/src/cgame/cg_public.h b/src/cgame/cg_public.h deleted file mode 100644 index 39d1a402..00000000 --- a/src/cgame/cg_public.h +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#define CMD_BACKUP 64 -#define CMD_MASK (CMD_BACKUP - 1) -// allow a lot of command backups for very fast systems -// multiple commands may be combined into a single packet, so this -// needs to be larger than PACKET_BACKUP - - -#define MAX_ENTITIES_IN_SNAPSHOT 256 - -// snapshots are a view of the server at a given time - -// Snapshots are generated at regular time intervals by the server, -// but they may not be sent if a client's rate level is exceeded, or -// they may be dropped by the network. -typedef struct -{ - int snapFlags; // SNAPFLAG_RATE_DELAYED, etc - int ping; - - int serverTime; // server time the message is valid for (in msec) - - byte areamask[ MAX_MAP_AREA_BYTES ]; // portalarea visibility bits - - playerState_t ps; // complete information about the current player at this time - - int numEntities; // all of the entities that need to be presented - entityState_t entities[ MAX_ENTITIES_IN_SNAPSHOT ]; // at the time of this snapshot - - int numServerCommands; // text based server commands to execute when this - int serverCommandSequence; // snapshot becomes current -} snapshot_t; - -enum -{ - CGAME_EVENT_NONE, - CGAME_EVENT_TEAMMENU, - CGAME_EVENT_SCOREBOARD, - CGAME_EVENT_EDITHUD -}; - -/* -================================================================== - -functions imported from the main executable - -================================================================== -*/ - -#define CGAME_IMPORT_API_VERSION 4 - -typedef enum -{ - CG_PRINT, - CG_ERROR, - CG_MILLISECONDS, - CG_CVAR_REGISTER, - CG_CVAR_UPDATE, - CG_CVAR_SET, - CG_CVAR_VARIABLESTRINGBUFFER, - CG_ARGC, - CG_ARGV, - CG_ARGS, - CG_FS_FOPENFILE, - CG_FS_READ, - CG_FS_WRITE, - CG_FS_FCLOSEFILE, - CG_SENDCONSOLECOMMAND, - CG_ADDCOMMAND, - CG_SENDCLIENTCOMMAND, - CG_UPDATESCREEN, - CG_CM_LOADMAP, - CG_CM_NUMINLINEMODELS, - CG_CM_INLINEMODEL, - CG_CM_LOADMODEL, - CG_CM_TEMPBOXMODEL, - CG_CM_POINTCONTENTS, - CG_CM_TRANSFORMEDPOINTCONTENTS, - CG_CM_BOXTRACE, - CG_CM_TRANSFORMEDBOXTRACE, - CG_CM_MARKFRAGMENTS, - CG_S_STARTSOUND, - CG_S_STARTLOCALSOUND, - CG_S_CLEARLOOPINGSOUNDS, - CG_S_ADDLOOPINGSOUND, - CG_S_UPDATEENTITYPOSITION, - CG_S_RESPATIALIZE, - CG_S_REGISTERSOUND, - CG_S_STARTBACKGROUNDTRACK, - CG_R_LOADWORLDMAP, - CG_R_REGISTERMODEL, - CG_R_REGISTERSKIN, - CG_R_REGISTERSHADER, - CG_R_CLEARSCENE, - CG_R_ADDREFENTITYTOSCENE, - CG_R_ADDPOLYTOSCENE, - CG_R_ADDLIGHTTOSCENE, - CG_R_RENDERSCENE, - CG_R_SETCOLOR, - CG_R_DRAWSTRETCHPIC, - CG_R_MODELBOUNDS, - CG_R_LERPTAG, - CG_GETGLCONFIG, - CG_GETGAMESTATE, - CG_GETCURRENTSNAPSHOTNUMBER, - CG_GETSNAPSHOT, - CG_GETSERVERCOMMAND, - CG_GETCURRENTCMDNUMBER, - CG_GETUSERCMD, - CG_SETUSERCMDVALUE, - CG_R_REGISTERSHADERNOMIP, - CG_MEMORY_REMAINING, - CG_R_REGISTERFONT, - CG_KEY_ISDOWN, - CG_KEY_GETCATCHER, - CG_KEY_SETCATCHER, - CG_KEY_GETKEY, - CG_PC_ADD_GLOBAL_DEFINE, - CG_PC_LOAD_SOURCE, - CG_PC_FREE_SOURCE, - CG_PC_READ_TOKEN, - CG_PC_SOURCE_FILE_AND_LINE, - CG_S_STOPBACKGROUNDTRACK, - CG_REAL_TIME, - CG_SNAPVECTOR, - CG_REMOVECOMMAND, - CG_R_LIGHTFORPOINT, - CG_CIN_PLAYCINEMATIC, - CG_CIN_STOPCINEMATIC, - CG_CIN_RUNCINEMATIC, - CG_CIN_DRAWCINEMATIC, - CG_CIN_SETEXTENTS, - CG_R_REMAP_SHADER, - CG_S_ADDREALLOOPINGSOUND, - CG_S_STOPLOOPINGSOUND, - - CG_CM_TEMPCAPSULEMODEL, - CG_CM_CAPSULETRACE, - CG_CM_TRANSFORMEDCAPSULETRACE, - CG_R_ADDADDITIVELIGHTTOSCENE, - CG_GET_ENTITY_TOKEN, - CG_R_ADDPOLYSTOSCENE, - CG_R_INPVS, - CG_FS_SEEK, - - CG_MEMSET = 100, - CG_MEMCPY, - CG_STRNCPY, - CG_SIN, - CG_COS, - CG_ATAN2, - CG_SQRT, - CG_FLOOR, - CG_CEIL, - - CG_TESTPRINTINT, - CG_TESTPRINTFLOAT, - CG_ACOS -} cgameImport_t; - - -/* -================================================================== - -functions exported to the main executable - -================================================================== -*/ - -typedef enum -{ - CG_INIT, - // void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ) - // called when the level loads or when the renderer is restarted - // all media should be registered at this time - // cgame will display loading status by calling SCR_Update, which - // will call CG_DrawInformation during the loading process - // reliableCommandSequence will be 0 on fresh loads, but higher for - // demos, tourney restarts, or vid_restarts - - CG_SHUTDOWN, - // void (*CG_Shutdown)( void ); - // oportunity to flush and close any open files - - CG_CONSOLE_COMMAND, - // qboolean (*CG_ConsoleCommand)( void ); - // a console command has been issued locally that is not recognized by the - // main game system. - // use Cmd_Argc() / Cmd_Argv() to read the command, return qfalse if the - // command is not known to the game - - CG_DRAW_ACTIVE_FRAME, - // void (*CG_DrawActiveFrame)( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ); - // Generates and draws a game scene and status information at the given time. - // If demoPlayback is set, local movement prediction will not be enabled - - CG_CROSSHAIR_PLAYER, - // int (*CG_CrosshairPlayer)( void ); - - CG_LAST_ATTACKER, - // int (*CG_LastAttacker)( void ); - - CG_KEY_EVENT, - // void (*CG_KeyEvent)( int key, qboolean down ); - - CG_MOUSE_EVENT, - // void (*CG_MouseEvent)( int dx, int dy ); - CG_EVENT_HANDLING - // void (*CG_EventHandling)(int type); -} cgameExport_t; - -//---------------------------------------------- diff --git a/src/cgame/cg_scanner.c b/src/cgame/cg_scanner.c deleted file mode 100644 index 6c2a9997..00000000 --- a/src/cgame/cg_scanner.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -static entityPos_t entityPositions; - -#define HUMAN_SCANNER_UPDATE_PERIOD 700 - -/* -============= -CG_UpdateEntityPositions - -Update this client's perception of entity positions -============= -*/ -void CG_UpdateEntityPositions( void ) -{ - centity_t *cent = NULL; - int i; - - if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - if( entityPositions.lastUpdateTime + HUMAN_SCANNER_UPDATE_PERIOD > cg.time ) - return; - } - - VectorCopy( cg.refdef.vieworg, entityPositions.origin ); - VectorCopy( cg.refdefViewAngles, entityPositions.vangles ); - entityPositions.lastUpdateTime = cg.time; - - entityPositions.numAlienBuildables = 0; - entityPositions.numHumanBuildables = 0; - entityPositions.numAlienClients = 0; - entityPositions.numHumanClients = 0; - - for( i = 0; i < cg.snap->numEntities; i++ ) - { - cent = &cg_entities[ cg.snap->entities[ i ].number ]; - - if( cent->currentState.eType == ET_BUILDABLE ) - { - //TA: add to list of item positions (for creep) - if( cent->currentState.modelindex2 == BIT_ALIENS ) - { - VectorCopy( cent->lerpOrigin, entityPositions.alienBuildablePos[ - entityPositions.numAlienBuildables ] ); - entityPositions.alienBuildableTimes[ - entityPositions.numAlienBuildables ] = cent->miscTime; - - if( entityPositions.numAlienBuildables < MAX_GENTITIES ) - entityPositions.numAlienBuildables++; - } - else if( cent->currentState.modelindex2 == BIT_HUMANS ) - { - VectorCopy( cent->lerpOrigin, entityPositions.humanBuildablePos[ - entityPositions.numHumanBuildables ] ); - - if( entityPositions.numHumanBuildables < MAX_GENTITIES ) - entityPositions.numHumanBuildables++; - } - } - else if( cent->currentState.eType == ET_PLAYER ) - { - int team = cent->currentState.powerups & 0x00FF; - - if( team == PTE_ALIENS ) - { - VectorCopy( cent->lerpOrigin, entityPositions.alienClientPos[ - entityPositions.numAlienClients ] ); - - if( entityPositions.numAlienClients < MAX_CLIENTS ) - entityPositions.numAlienClients++; - } - else if( team == PTE_HUMANS ) - { - VectorCopy( cent->lerpOrigin, entityPositions.humanClientPos[ - entityPositions.numHumanClients ] ); - - if( entityPositions.numHumanClients < MAX_CLIENTS ) - entityPositions.numHumanClients++; - } - } - } -} - -#define STALKWIDTH 2.0f -#define BLIPX 16.0f -#define BLIPY 8.0f -#define FAR_ALPHA 0.8f -#define NEAR_ALPHA 1.2f - -/* -============= -CG_DrawBlips - -Draw blips and stalks for the human scanner -============= -*/ -static void CG_DrawBlips( rectDef_t *rect, vec3_t origin, vec4_t colour ) -{ - vec3_t drawOrigin; - vec3_t up = { 0, 0, 1 }; - float alphaMod = 1.0f; - float timeFractionSinceRefresh = 1.0f - - ( (float)( cg.time - entityPositions.lastUpdateTime ) / - (float)HUMAN_SCANNER_UPDATE_PERIOD ); - vec4_t localColour; - - Vector4Copy( colour, localColour ); - - RotatePointAroundVector( drawOrigin, up, origin, -entityPositions.vangles[ 1 ] - 90 ); - drawOrigin[ 0 ] /= ( 2 * HELMET_RANGE / rect->w ); - drawOrigin[ 1 ] /= ( 2 * HELMET_RANGE / rect->h ); - drawOrigin[ 2 ] /= ( 2 * HELMET_RANGE / rect->w ); - - alphaMod = FAR_ALPHA + - ( ( drawOrigin[ 1 ] + ( rect->h / 2.0f ) ) / rect->h ) * ( NEAR_ALPHA - FAR_ALPHA ); - - localColour[ 3 ] *= alphaMod; - localColour[ 3 ] *= ( 0.5f + ( timeFractionSinceRefresh * 0.5f ) ); - - if( localColour[ 3 ] > 1.0f ) - localColour[ 3 ] = 1.0f; - else if( localColour[ 3 ] < 0.0f ) - localColour[ 3 ] = 0.0f; - - trap_R_SetColor( localColour ); - - if( drawOrigin[ 2 ] > 0 ) - CG_DrawPic( rect->x + ( rect->w / 2 ) - ( STALKWIDTH / 2 ) - drawOrigin[ 0 ], - rect->y + ( rect->h / 2 ) + drawOrigin[ 1 ] - drawOrigin[ 2 ], - STALKWIDTH, drawOrigin[ 2 ], cgs.media.scannerLineShader ); - else - CG_DrawPic( rect->x + ( rect->w / 2 ) - ( STALKWIDTH / 2 ) - drawOrigin[ 0 ], - rect->y + ( rect->h / 2 ) + drawOrigin[ 1 ], - STALKWIDTH, -drawOrigin[ 2 ], cgs.media.scannerLineShader ); - - CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX / 2 ) - drawOrigin[ 0 ], - rect->y + ( rect->h / 2 ) - ( BLIPY / 2 ) + drawOrigin[ 1 ] - drawOrigin[ 2 ], - BLIPX, BLIPY, cgs.media.scannerBlipShader ); - trap_R_SetColor( NULL ); -} - -#define BLIPX2 24.0f -#define BLIPY2 24.0f - -/* -============= -CG_DrawDir - -Draw dot marking the direction to an enemy -============= -*/ -static void CG_DrawDir( rectDef_t *rect, vec3_t origin, vec4_t colour ) -{ - vec3_t drawOrigin; - vec3_t noZOrigin; - vec3_t normal, antinormal, normalDiff; - vec3_t view, noZview; - vec3_t up = { 0.0f, 0.0f, 1.0f }; - vec3_t top = { 0.0f, -1.0f, 0.0f }; - float angle; - playerState_t *ps = &cg.snap->ps; - - if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) - { - if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) - VectorSet( normal, 0.0f, 0.0f, -1.0f ); - else - VectorCopy( ps->grapplePoint, normal ); - } - else - VectorSet( normal, 0.0f, 0.0f, 1.0f ); - - AngleVectors( entityPositions.vangles, view, NULL, NULL ); - - ProjectPointOnPlane( noZOrigin, origin, normal ); - ProjectPointOnPlane( noZview, view, normal ); - VectorNormalize( noZOrigin ); - VectorNormalize( noZview ); - - //calculate the angle between the images of the blip and the view - angle = RAD2DEG( acos( DotProduct( noZOrigin, noZview ) ) ); - CrossProduct( noZOrigin, noZview, antinormal ); - VectorNormalize( antinormal ); - - //decide which way to rotate - VectorSubtract( normal, antinormal, normalDiff ); - if( VectorLength( normalDiff ) < 1.0f ) - angle = 360.0f - angle; - - RotatePointAroundVector( drawOrigin, up, top, angle ); - - trap_R_SetColor( colour ); - CG_DrawPic( rect->x + ( rect->w / 2 ) - ( BLIPX2 / 2 ) - drawOrigin[ 0 ] * ( rect->w / 2 ), - rect->y + ( rect->h / 2 ) - ( BLIPY2 / 2 ) + drawOrigin[ 1 ] * ( rect->h / 2 ), - BLIPX2, BLIPY2, cgs.media.scannerBlipShader ); - trap_R_SetColor( NULL ); -} - -/* -============= -CG_AlienSense -============= -*/ -void CG_AlienSense( rectDef_t *rect ) -{ - int i; - vec3_t origin; - vec3_t relOrigin; - vec4_t buildable = { 1.0f, 0.0f, 0.0f, 0.7f }; - vec4_t client = { 0.0f, 0.0f, 1.0f, 0.7f }; - - VectorCopy( entityPositions.origin, origin ); - - //draw human buildables - for( i = 0; i < entityPositions.numHumanBuildables; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < ALIENSENSE_RANGE ) - CG_DrawDir( rect, relOrigin, buildable ); - } - - //draw human clients - for( i = 0; i < entityPositions.numHumanClients; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < ALIENSENSE_RANGE ) - CG_DrawDir( rect, relOrigin, client ); - } -} - -/* -============= -CG_Scanner -============= -*/ -void CG_Scanner( rectDef_t *rect, qhandle_t shader, vec4_t color ) -{ - int i; - vec3_t origin; - vec3_t relOrigin; - vec4_t hIabove; - vec4_t hIbelow; - vec4_t aIabove = { 1.0f, 0.0f, 0.0f, 0.75f }; - vec4_t aIbelow = { 1.0f, 0.0f, 0.0f, 0.5f }; - - Vector4Copy( color, hIabove ); - hIabove[ 3 ] *= 1.5f; - Vector4Copy( color, hIbelow ); - - VectorCopy( entityPositions.origin, origin ); - - //draw human buildables below scanner plane - for( i = 0; i < entityPositions.numHumanBuildables; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) ) - CG_DrawBlips( rect, relOrigin, hIbelow ); - } - - //draw alien buildables below scanner plane - for( i = 0; i < entityPositions.numAlienBuildables; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( entityPositions.alienBuildablePos[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) ) - CG_DrawBlips( rect, relOrigin, aIbelow ); - } - - //draw human clients below scanner plane - for( i = 0; i < entityPositions.numHumanClients; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) ) - CG_DrawBlips( rect, relOrigin, hIbelow ); - } - - //draw alien buildables below scanner plane - for( i = 0; i < entityPositions.numAlienClients; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] < 0 ) ) - CG_DrawBlips( rect, relOrigin, aIbelow ); - } - - if( !cg_disableScannerPlane.integer ) - { - trap_R_SetColor( color ); - CG_DrawPic( rect->x, rect->y, rect->w, rect->h, shader ); - trap_R_SetColor( NULL ); - } - - //draw human buildables above scanner plane - for( i = 0; i < entityPositions.numHumanBuildables; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( entityPositions.humanBuildablePos[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) ) - CG_DrawBlips( rect, relOrigin, hIabove ); - } - - //draw alien buildables above scanner plane - for( i = 0; i < entityPositions.numAlienBuildables; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( entityPositions.alienBuildablePos[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) ) - CG_DrawBlips( rect, relOrigin, aIabove ); - } - - //draw human clients above scanner plane - for( i = 0; i < entityPositions.numHumanClients; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( entityPositions.humanClientPos[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) ) - CG_DrawBlips( rect, relOrigin, hIabove ); - } - - //draw alien clients above scanner plane - for( i = 0; i < entityPositions.numAlienClients; i++ ) - { - VectorClear( relOrigin ); - VectorSubtract( entityPositions.alienClientPos[ i ], origin, relOrigin ); - - if( VectorLength( relOrigin ) < HELMET_RANGE && ( relOrigin[ 2 ] > 0 ) ) - CG_DrawBlips( rect, relOrigin, aIabove ); - } -} diff --git a/src/cgame/cg_servercmds.c b/src/cgame/cg_servercmds.c deleted file mode 100644 index 71fbaac9..00000000 --- a/src/cgame/cg_servercmds.c +++ /dev/null @@ -1,1130 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_servercmds.c -- reliably sequenced text commands sent by the server -// these are processed at snapshot transition time, so there will definately -// be a valid snapshot this frame - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -/* -================= -CG_ParseScores - -================= -*/ -static void CG_ParseScores( void ) -{ - int i; - - cg.numScores = atoi( CG_Argv( 1 ) ); - - if( cg.numScores > MAX_CLIENTS ) - cg.numScores = MAX_CLIENTS; - - cg.teamScores[ 0 ] = atoi( CG_Argv( 2 ) ); - cg.teamScores[ 1 ] = atoi( CG_Argv( 3 ) ); - - memset( cg.scores, 0, sizeof( cg.scores ) ); - - if( cg_debugRandom.integer ) - CG_Printf( "cg.numScores: %d\n", cg.numScores ); - - for( i = 0; i < cg.numScores; i++ ) - { - // - cg.scores[ i ].client = atoi( CG_Argv( i * 6 + 4 ) ); - cg.scores[ i ].score = atoi( CG_Argv( i * 6 + 5 ) ); - cg.scores[ i ].ping = atoi( CG_Argv( i * 6 + 6 ) ); - cg.scores[ i ].time = atoi( CG_Argv( i * 6 + 7 ) ); - cg.scores[ i ].weapon = atoi( CG_Argv( i * 6 + 8 ) ); - cg.scores[ i ].upgrade = atoi( CG_Argv( i * 6 + 9 ) ); - - if( cg.scores[ i ].client < 0 || cg.scores[ i ].client >= MAX_CLIENTS ) - cg.scores[ i ].client = 0; - - cgs.clientinfo[ cg.scores[ i ].client ].score = cg.scores[ i ].score; - cgs.clientinfo[ cg.scores[ i ].client ].powerups = 0; - - cg.scores[ i ].team = cgs.clientinfo[ cg.scores[ i ].client ].team; - } -} - -/* -================= -CG_ParseTeamInfo - -================= -*/ -static void CG_ParseTeamInfo( void ) -{ - int i; - int client; - - numSortedTeamPlayers = atoi( CG_Argv( 1 ) ); - - for( i = 0; i < numSortedTeamPlayers; i++ ) - { - client = atoi( CG_Argv( i * 6 + 2 ) ); - - sortedTeamPlayers[ i ] = client; - - cgs.clientinfo[ client ].location = atoi( CG_Argv( i * 6 + 3 ) ); - cgs.clientinfo[ client ].health = atoi( CG_Argv( i * 6 + 4 ) ); - cgs.clientinfo[ client ].armor = atoi( CG_Argv( i * 6 + 5 ) ); - cgs.clientinfo[ client ].curWeapon = atoi( CG_Argv( i * 6 + 6 ) ); - cgs.clientinfo[ client ].powerups = atoi( CG_Argv( i * 6 + 7 ) ); - } -} - - -/* -================ -CG_ParseServerinfo - -This is called explicitly when the gamestate is first received, -and whenever the server updates any serverinfo flagged cvars -================ -*/ -void CG_ParseServerinfo( void ) -{ - const char *info; - char *mapname; - - info = CG_ConfigString( CS_SERVERINFO ); - cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) ); - cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) ); - cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) ); - cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) ); - mapname = Info_ValueForKey( info, "mapname" ); - Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname ); -} - -/* -================== -CG_ParseWarmup -================== -*/ -static void CG_ParseWarmup( void ) -{ - const char *info; - int warmup; - - info = CG_ConfigString( CS_WARMUP ); - - warmup = atoi( info ); - cg.warmupCount = -1; - - if( warmup == 0 && cg.warmup ) - { - } - - cg.warmup = warmup; -} - -/* -================ -CG_SetConfigValues - -Called on load to set the initial values from configure strings -================ -*/ -void CG_SetConfigValues( void ) -{ - cgs.scores1 = atoi( CG_ConfigString( CS_SCORES1 ) ); - cgs.scores2 = atoi( CG_ConfigString( CS_SCORES2 ) ); - - sscanf( CG_ConfigString( CS_BUILDPOINTS ), - "%d %d %d %d %d", &cgs.alienBuildPoints, - &cgs.alienBuildPointsTotal, - &cgs.humanBuildPoints, - &cgs.humanBuildPointsTotal, - &cgs.humanBuildPointsPowered ); - - sscanf( CG_ConfigString( CS_STAGES ), "%d %d %d %d %d %d", &cgs.alienStage, &cgs.humanStage, - &cgs.alienKills, &cgs.humanKills, &cgs.alienNextStageThreshold, &cgs.humanNextStageThreshold ); - sscanf( CG_ConfigString( CS_SPAWNS ), "%d %d", &cgs.numAlienSpawns, &cgs.numHumanSpawns ); - - cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) ); - cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) ); -} - - -/* -===================== -CG_ShaderStateChanged -===================== -*/ -void CG_ShaderStateChanged( void ) -{ - char originalShader[ MAX_QPATH ]; - char newShader[ MAX_QPATH ]; - char timeOffset[ 16 ]; - const char *o; - char *n, *t; - - o = CG_ConfigString( CS_SHADERSTATE ); - - while( o && *o ) - { - n = strstr( o, "=" ); - - if( n && *n ) - { - strncpy( originalShader, o, n - o ); - originalShader[ n - o ] = 0; - n++; - t = strstr( n, ":" ); - - if( t && *t ) - { - strncpy( newShader, n, t - n ); - newShader[ t - n ] = 0; - } - else - break; - - t++; - o = strstr( t, "@" ); - - if( o ) - { - strncpy( timeOffset, t, o - t ); - timeOffset[ o - t ] = 0; - o++; - trap_R_RemapShader( originalShader, newShader, timeOffset ); - } - } - else - break; - } -} - -/* -================ -CG_AnnounceAlienStageTransistion -================ -*/ -static void CG_AnnounceAlienStageTransistion( stage_t from, stage_t to ) -{ - if( cg.predictedPlayerState.stats[ STAT_PTEAM ] != PTE_ALIENS ) - return; - - trap_S_StartLocalSound( cgs.media.alienStageTransition, CHAN_ANNOUNCER ); - CG_CenterPrint( "We have evolved!", 200, GIANTCHAR_WIDTH * 4 ); -} - -/* -================ -CG_AnnounceHumanStageTransistion -================ -*/ -static void CG_AnnounceHumanStageTransistion( stage_t from, stage_t to ) -{ - if( cg.predictedPlayerState.stats[ STAT_PTEAM ] != PTE_HUMANS ) - return; - - trap_S_StartLocalSound( cgs.media.humanStageTransition, CHAN_ANNOUNCER ); - CG_CenterPrint( "Reinforcements have arrived!", 200, GIANTCHAR_WIDTH * 4 ); -} - -/* -================ -CG_ConfigStringModified - -================ -*/ -static void CG_ConfigStringModified( void ) -{ - const char *str; - int num; - - num = atoi( CG_Argv( 1 ) ); - - // get the gamestate from the client system, which will have the - // new configstring already integrated - trap_GetGameState( &cgs.gameState ); - - // look up the individual string that was modified - str = CG_ConfigString( num ); - - // do something with it if necessary - if( num == CS_MUSIC ) - CG_StartMusic( ); - else if( num == CS_SERVERINFO ) - CG_ParseServerinfo( ); - else if( num == CS_WARMUP ) - CG_ParseWarmup( ); - else if( num == CS_SCORES1 ) - cgs.scores1 = atoi( str ); - else if( num == CS_SCORES2 ) - cgs.scores2 = atoi( str ); - else if( num == CS_BUILDPOINTS ) - sscanf( str, "%d %d %d %d %d", &cgs.alienBuildPoints, - &cgs.alienBuildPointsTotal, - &cgs.humanBuildPoints, - &cgs.humanBuildPointsTotal, - &cgs.humanBuildPointsPowered ); - else if( num == CS_STAGES ) - { - stage_t oldAlienStage = cgs.alienStage; - stage_t oldHumanStage = cgs.humanStage; - - sscanf( str, "%d %d %d %d %d %d", - &cgs.alienStage, &cgs.humanStage, - &cgs.alienKills, &cgs.humanKills, - &cgs.alienNextStageThreshold, &cgs.humanNextStageThreshold ); - - if( cgs.alienStage != oldAlienStage ) - CG_AnnounceAlienStageTransistion( oldAlienStage, cgs.alienStage ); - - if( cgs.humanStage != oldHumanStage ) - CG_AnnounceHumanStageTransistion( oldHumanStage, cgs.humanStage ); - } - else if( num == CS_SPAWNS ) - sscanf( str, "%d %d", &cgs.numAlienSpawns, &cgs.numHumanSpawns ); - else if( num == CS_LEVEL_START_TIME ) - cgs.levelStartTime = atoi( str ); - else if( num == CS_VOTE_TIME ) - { - cgs.voteTime = atoi( str ); - cgs.voteModified = qtrue; - - if( cgs.voteTime ) - trap_Cvar_Set( "ui_voteActive", "1" ); - else - trap_Cvar_Set( "ui_voteActive", "0" ); - } - else if( num == CS_VOTE_YES ) - { - cgs.voteYes = atoi( str ); - cgs.voteModified = qtrue; - } - else if( num == CS_VOTE_NO ) - { - cgs.voteNo = atoi( str ); - cgs.voteModified = qtrue; - } - else if( num == CS_VOTE_STRING ) - Q_strncpyz( cgs.voteString, str, sizeof( cgs.voteString ) ); - else if( num >= CS_TEAMVOTE_TIME && num <= CS_TEAMVOTE_TIME + 1 ) - { - int cs_offset = num - CS_TEAMVOTE_TIME; - - cgs.teamVoteTime[ cs_offset ] = atoi( str ); - cgs.teamVoteModified[ cs_offset ] = qtrue; - - if( cs_offset == 0 ) - { - if( cgs.teamVoteTime[ cs_offset ] ) - trap_Cvar_Set( "ui_humanTeamVoteActive", "1" ); - else - trap_Cvar_Set( "ui_humanTeamVoteActive", "0" ); - } - else if( cs_offset == 1 ) - { - if( cgs.teamVoteTime[ cs_offset ] ) - trap_Cvar_Set( "ui_alienTeamVoteActive", "1" ); - else - trap_Cvar_Set( "ui_alienTeamVoteActive", "0" ); - } - } - else if( num >= CS_TEAMVOTE_YES && num <= CS_TEAMVOTE_YES + 1 ) - { - cgs.teamVoteYes[ num - CS_TEAMVOTE_YES ] = atoi( str ); - cgs.teamVoteModified[ num - CS_TEAMVOTE_YES ] = qtrue; - } - else if( num >= CS_TEAMVOTE_NO && num <= CS_TEAMVOTE_NO + 1 ) - { - cgs.teamVoteNo[ num - CS_TEAMVOTE_NO ] = atoi( str ); - cgs.teamVoteModified[ num - CS_TEAMVOTE_NO ] = qtrue; - } - else if( num >= CS_TEAMVOTE_STRING && num <= CS_TEAMVOTE_STRING + 1 ) - Q_strncpyz( cgs.teamVoteString[ num - CS_TEAMVOTE_STRING ], str, sizeof( cgs.teamVoteString ) ); - else if( num == CS_INTERMISSION ) - cg.intermissionStarted = atoi( str ); - else if( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) - cgs.gameModels[ num - CS_MODELS ] = trap_R_RegisterModel( str ); - else if( num >= CS_SHADERS && num < CS_SHADERS+MAX_SHADERS ) - cgs.gameShaders[ num - CS_SHADERS ] = trap_R_RegisterShader( str ); - else if( num >= CS_PARTICLE_SYSTEMS && num < CS_PARTICLE_SYSTEMS+MAX_GAME_PARTICLE_SYSTEMS ) - cgs.gameParticleSystems[ num - CS_PARTICLE_SYSTEMS ] = CG_RegisterParticleSystem( (char *)str ); - else if( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) - { - if( str[ 0 ] != '*' ) - { // player specific sounds don't register here - cgs.gameSounds[ num - CS_SOUNDS ] = trap_S_RegisterSound( str, qfalse ); - } - } - else if( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) - { - CG_NewClientInfo( num - CS_PLAYERS ); - CG_BuildSpectatorString( ); - } - else if( num == CS_FLAGSTATUS ) - { - } - else if( num == CS_SHADERSTATE ) - { - CG_ShaderStateChanged( ); - } -} - - -/* -======================= -CG_AddToTeamChat - -======================= -*/ -static void CG_AddToTeamChat( const char *str ) -{ - int len; - char *p, *ls; - int lastcolor; - int chatHeight; - - if( cg_teamChatHeight.integer < TEAMCHAT_HEIGHT ) - chatHeight = cg_teamChatHeight.integer; - else - chatHeight = TEAMCHAT_HEIGHT; - - if( chatHeight <= 0 || cg_teamChatTime.integer <= 0 ) - { - // team chat disabled, dump into normal chat - cgs.teamChatPos = cgs.teamLastChatPos = 0; - return; - } - - len = 0; - - p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight]; - *p = 0; - - lastcolor = '7'; - - ls = NULL; - while( *str ) - { - if( len > TEAMCHAT_WIDTH - 1 ) - { - if( ls ) - { - str -= ( p - ls ); - str++; - p -= ( p - ls ); - } - - *p = 0; - - cgs.teamChatMsgTimes[ cgs.teamChatPos % chatHeight ] = cg.time; - - cgs.teamChatPos++; - p = cgs.teamChatMsgs[ cgs.teamChatPos % chatHeight ]; - *p = 0; - *p++ = Q_COLOR_ESCAPE; - *p++ = lastcolor; - len = 0; - ls = NULL; - } - - if( Q_IsColorString( str ) ) - { - *p++ = *str++; - lastcolor = *str; - *p++ = *str++; - continue; - } - - if( *str == ' ' ) - ls = p; - - *p++ = *str++; - len++; - } - *p = 0; - - cgs.teamChatMsgTimes[ cgs.teamChatPos % chatHeight ] = cg.time; - cgs.teamChatPos++; - - if( cgs.teamChatPos - cgs.teamLastChatPos > chatHeight ) - cgs.teamLastChatPos = cgs.teamChatPos - chatHeight; -} - - - -/* -=============== -CG_MapRestart - -The server has issued a map_restart, so the next snapshot -is completely new and should not be interpolated to. - -A tournement restart will clear everything, but doesn't -require a reload of all the media -=============== -*/ -static void CG_MapRestart( void ) -{ - if( cg_showmiss.integer ) - CG_Printf( "CG_MapRestart\n" ); - - CG_InitMarkPolys( ); - - // make sure the "3 frags left" warnings play again - cg.fraglimitWarnings = 0; - - cg.timelimitWarnings = 0; - - cg.intermissionStarted = qfalse; - - cgs.voteTime = 0; - - cg.mapRestart = qtrue; - - CG_StartMusic( ); - - trap_S_ClearLoopingSounds( qtrue ); - - // we really should clear more parts of cg here and stop sounds - - // play the "fight" sound if this is a restart without warmup - if( cg.warmup == 0 ) - CG_CenterPrint( "FIGHT!", 120, GIANTCHAR_WIDTH * 2 ); - - trap_Cvar_Set( "cg_thirdPerson", "0" ); -} - -/* -================= -CG_RemoveChatEscapeChar -================= -*/ -static void CG_RemoveChatEscapeChar( char *text ) -{ - int i, l; - - l = 0; - for( i = 0; text[ i ]; i++ ) - { - if( text[ i ] == '\x19' ) - continue; - - text[ l++ ] = text[ i ]; - } - - text[ l ] = '\0'; -} - -/* -=============== -CG_SetUIVars - -Set some cvars used by the UI -=============== -*/ -static void CG_SetUIVars( void ) -{ - int i; - char carriageCvar[ MAX_TOKEN_CHARS ]; - - *carriageCvar = 0; - - //determine what the player is carrying - for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) - { - if( BG_InventoryContainsWeapon( i, cg.snap->ps.stats ) && - BG_FindPurchasableForWeapon( i ) ) - strcat( carriageCvar, va( "W%d ", i ) ); - } - for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) - { - if( BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) && - BG_FindPurchasableForUpgrade( i ) ) - strcat( carriageCvar, va( "U%d ", i ) ); - } - strcat( carriageCvar, "$" ); - - trap_Cvar_Set( "ui_carriage", carriageCvar ); - - trap_Cvar_Set( "ui_stages", va( "%d %d", cgs.alienStage, cgs.humanStage ) ); -} - - -/* -============== -CG_Menu -============== -*/ -void CG_Menu( int menu ) -{ - CG_SetUIVars( ); - - switch( menu ) - { - case MN_TEAM: trap_SendConsoleCommand( "menu tremulous_teamselect\n" ); break; - case MN_A_CLASS: trap_SendConsoleCommand( "menu tremulous_alienclass\n" ); break; - case MN_H_SPAWN: trap_SendConsoleCommand( "menu tremulous_humanitem\n" ); break; - case MN_A_BUILD: trap_SendConsoleCommand( "menu tremulous_alienbuild\n" ); break; - case MN_H_BUILD: trap_SendConsoleCommand( "menu tremulous_humanbuild\n" ); break; - case MN_H_ARMOURY: trap_SendConsoleCommand( "menu tremulous_humanarmoury\n" ); break; - - case MN_A_TEAMFULL: - trap_Cvar_Set( "ui_dialog", "The alien team has too many players. Please wait until " - "slots become available or join the human team." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - break; - - case MN_H_TEAMFULL: - trap_Cvar_Set( "ui_dialog", "The human team has too many players. Please wait until " - "slots become available or join the alien team." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - break; - - case MN_H_NOROOM: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "There is no room to build here. Move until the buildable turns " - "translucent green indicating a valid build location." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "There is no room to build here\n" ); - - break; - - case MN_H_NOPOWER: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "There is no power remaining. Free up power by destroying existing " - "buildable objects." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "There is no power remaining\n" ); - - break; - - case MN_H_NOTPOWERED: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "This buildable is not powered. Build a Reactor and/or Repeater in " - "order to power it." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "This buildable is not powered\n" ); - - break; - - case MN_H_NORMAL: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "Cannot build on this surface. The surface is too steep or unsuitable " - "to build on. Please choose another site for this structure." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "Cannot build on this surface\n" ); - - break; - - case MN_H_REACTOR: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "There can only be one Reactor. Destroy the existing one if you " - "wish to move it." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "There can only be one Reactor\n" ); - - break; - - case MN_H_REPEATER: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "There is no power here. If available, a Repeater may be used to " - "transmit power to this location." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "There is no power here\n" ); - - break; - - case MN_H_NODCC: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "There is no Defense Computer. A Defense Computer is needed to build " - "this." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "There is no Defense Computer\n" ); - - break; - - case MN_H_TNODEWARN: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "WARNING: This Telenode will not be powered. Build near a power " - "structure to prevent seeing this message again." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "This Telenode will not be powered\n" ); - - break; - - case MN_H_RPTWARN: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "WARNING: This Repeater will not be powered as there is no parent " - "Reactor providing power. Build a Reactor." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "This Repeater will not be powered\n" ); - - break; - - case MN_H_RPTWARN2: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "This area already has power. A Repeater is not required here." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "This area already has power\n" ); - - break; - - case MN_H_NOSLOTS: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "You have no room to carry this. Please sell any conflicting " - "upgrades before purchasing this item." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "You have no room to carry this\n" ); - - break; - - case MN_H_NOFUNDS: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "Insufficient funds. You do not have enough credits to perform this " - "action." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "Insufficient funds\n" ); - - break; - - case MN_H_ITEMHELD: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "You already hold this item. It is not possible to carry multiple items " - "of the same type." ); - trap_SendConsoleCommand( "menu tremulous_human_dialog\n" ); - } - else - CG_Printf( "You already hold this item\n" ); - - break; - - - //=============================== - - - case MN_A_NOROOM: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "There is no room to build here. Move until the structure turns " - "translucent green indicating a valid build location." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "There is no room to build here\n" ); - - break; - - case MN_A_NOCREEP: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "There is no creep here. You must build near existing Eggs or " - "the Overmind. Alien structures will not support themselves." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "There is no creep here\n" ); - - break; - - case MN_A_NOOVMND: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "There is no Overmind. An Overmind must be built to control " - "the structure you tried to place" ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "There is no Overmind\n" ); - - break; - - case MN_A_OVERMIND: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "There can only be one Overmind. Destroy the existing one if you " - "wish to move it." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "There can only be one Overmind\n" ); - - break; - - case MN_A_HOVEL: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "There can only be one Hovel. Destroy the existing one if you " - "wish to move it." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "There can only be one Hovel\n" ); - - break; - - case MN_A_NOASSERT: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "The Overmind cannot control any more structures. Destroy existing " - "structures to build more." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "The Overmind cannot control any more structures\n" ); - - break; - - case MN_A_SPWNWARN: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "WARNING: This spawn will not be controlled by an Overmind. " - "Build an Overmind to prevent seeing this message again." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "This spawn will not be controlled by an Overmind\n" ); - - break; - - case MN_A_NORMAL: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "Cannot build on this surface. This surface is too steep or unsuitable " - "to build on. Please choose another site for this structure." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "Cannot build on this surface\n" ); - - break; - - case MN_A_NOEROOM: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "There is no room to evolve here. Move away from walls or other " - "nearby objects and try again." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "There is no room to evolve here\n" ); - - break; - - case MN_A_TOOCLOSE: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "This location is too close to the enemy to evolve. " - "Move away until you are no longer aware of the enemy's " - "presence and try again." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "This location is too close to the enemy to evolve\n" ); - - break; - - case MN_A_NOOVMND_EVOLVE: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "There is no Overmind. An Overmind must be built to allow " - "you to upgrade." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "There is no Overmind\n" ); - - break; - - case MN_A_HOVEL_OCCUPIED: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "This Hovel is occupied by another builder. Please find or build " - "another." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "This Hovel is occupied by another builder\n" ); - - break; - - case MN_A_HOVEL_BLOCKED: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "The exit to this Hovel is currently blocked. Please wait until it " - "becomes clear then try again." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "The exit to this Hovel is currently blocked\n" ); - - break; - - case MN_A_HOVEL_EXIT: - if( !cg_disableWarningDialogs.integer ) - { - trap_Cvar_Set( "ui_dialog", "The exit to this Hovel would always be blocked. Please choose " - "a more suitable location." ); - trap_SendConsoleCommand( "menu tremulous_alien_dialog\n" ); - } - else - CG_Printf( "The exit to this Hovel would always be blocked\n" ); - - break; - - case MN_A_INFEST: - trap_Cvar_Set( "ui_currentClass", va( "%d %d", cg.snap->ps.stats[ STAT_PCLASS ], - cg.snap->ps.persistant[ PERS_CREDIT ] ) ); - trap_SendConsoleCommand( "menu tremulous_alienupgrade\n" ); - break; - - default: - Com_Printf( "cgame: debug: no such menu %d\n", menu ); - } -} - -/* -================= -CG_ServerCommand - -The string has been tokenized and can be retrieved with -Cmd_Argc() / Cmd_Argv() -================= -*/ -static void CG_ServerCommand( void ) -{ - const char *cmd; - char text[ MAX_SAY_TEXT ]; - - cmd = CG_Argv( 0 ); - - if( !cmd[ 0 ] ) - { - // server claimed the command - return; - } - - if( !strcmp( cmd, "cp" ) ) - { - CG_CenterPrint( CG_Argv( 1 ), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); - return; - } - - if( !strcmp( cmd, "cs" ) ) - { - CG_ConfigStringModified( ); - return; - } - - if( !strcmp( cmd, "print" ) ) - { - CG_Printf( "%s", CG_Argv( 1 ) ); - return; - } - - if( !strcmp( cmd, "chat" ) ) - { - if( !cg_teamChatsOnly.integer ) - { - trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); - Q_strncpyz( text, CG_Argv( 1 ), MAX_SAY_TEXT ); - CG_RemoveChatEscapeChar( text ); - CG_Printf( "%s\n", text ); - } - - return; - } - - if( !strcmp( cmd, "tchat" ) ) - { - trap_S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND ); - Q_strncpyz( text, CG_Argv( 1 ), MAX_SAY_TEXT ); - CG_RemoveChatEscapeChar( text ); - CG_AddToTeamChat( text ); - CG_Printf( "%s\n", text ); - return; - } - - if( !strcmp( cmd, "scores" ) ) - { - CG_ParseScores( ); - return; - } - - if( !strcmp( cmd, "tinfo" ) ) - { - CG_ParseTeamInfo( ); - return; - } - - if( !strcmp( cmd, "map_restart" ) ) - { - CG_MapRestart( ); - return; - } - - if( Q_stricmp( cmd, "remapShader" ) == 0 ) - { - if( trap_Argc( ) == 4 ) - trap_R_RemapShader( CG_Argv( 1 ), CG_Argv( 2 ), CG_Argv( 3 ) ); - } - - // clientLevelShot is sent before taking a special screenshot for - // the menu system during development - if( !strcmp( cmd, "clientLevelShot" ) ) - { - cg.levelShot = qtrue; - return; - } - - //enable G_Printfs from the server to appear in the TA console - if( !strcmp( cmd, "gprintf" ) ) - { - if( trap_Argc( ) == 2 ) - CG_TAUIConsole( CG_Argv( 1 ) ); - - return; - } - - //the server has triggered a menu - if( !strcmp( cmd, "servermenu" ) ) - { - if( trap_Argc( ) == 2 && !cg.demoPlayback ) - CG_Menu( atoi( CG_Argv( 1 ) ) ); - - return; - } - - //the server thinks this client should close all menus - if( !strcmp( cmd, "serverclosemenus" ) ) - { - trap_SendConsoleCommand( "closemenus\n" ); - return; - } - - //poison cloud effect needs to be reliable - if( !strcmp( cmd, "poisoncloud" ) ) - { - cg.poisonedTime = cg.time; - - if( CG_IsParticleSystemValid( &cg.poisonCloudPS ) ) - { - cg.poisonCloudPS = CG_SpawnNewParticleSystem( cgs.media.poisonCloudPS ); - CG_SetAttachmentCent( &cg.poisonCloudPS->attachment, &cg.predictedPlayerEntity ); - CG_AttachToCent( &cg.poisonCloudPS->attachment ); - } - - return; - } - - if( !strcmp( cmd, "weaponswitch" ) ) - { - CG_Printf( "client weaponswitch\n" ); - if( trap_Argc( ) == 2 ) - { - cg.weaponSelect = atoi( CG_Argv( 1 ) ); - cg.weaponSelectTime = cg.time; - } - - return; - } - - // server requests a ptrc - if( !strcmp( cmd, "ptrcrequest" ) ) - { - int code = CG_ReadPTRCode( ); - - trap_SendClientCommand( va( "ptrcverify %d", code ) ); - return; - } - - // server issues a ptrc - if( !strcmp( cmd, "ptrcissue" ) ) - { - if( trap_Argc( ) == 2 ) - { - int code = atoi( CG_Argv( 1 ) ); - - CG_WritePTRCode( code ); - } - - return; - } - - // reply to ptrcverify - if( !strcmp( cmd, "ptrcconfirm" ) ) - { - trap_SendConsoleCommand( "menu ptrc_popmenu\n" ); - - return; - } - - CG_Printf( "Unknown client game command: %s\n", cmd ); -} - - -/* -==================== -CG_ExecuteNewServerCommands - -Execute all of the server commands that were received along -with this this snapshot. -==================== -*/ -void CG_ExecuteNewServerCommands( int latestSequence ) -{ - while( cgs.serverCommandSequence < latestSequence ) - { - if( trap_GetServerCommand( ++cgs.serverCommandSequence ) ) - CG_ServerCommand( ); - } -} diff --git a/src/cgame/cg_snapshot.c b/src/cgame/cg_snapshot.c deleted file mode 100644 index 4a5722ae..00000000 --- a/src/cgame/cg_snapshot.c +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_snapshot.c -- things that happen on snapshot transition, -// not necessarily every single rendered frame - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -/* -================== -CG_ResetEntity -================== -*/ -static void CG_ResetEntity( centity_t *cent ) -{ - // if the previous snapshot this entity was updated in is at least - // an event window back in time then we can reset the previous event - if( cent->snapShotTime < cg.time - EVENT_VALID_MSEC ) - cent->previousEvent = 0; - - cent->trailTime = cg.snap->serverTime; - - VectorCopy( cent->currentState.origin, cent->lerpOrigin ); - VectorCopy( cent->currentState.angles, cent->lerpAngles ); - - if( cent->currentState.eType == ET_PLAYER ) - CG_ResetPlayerEntity( cent ); -} - -/* -=============== -CG_TransitionEntity - -cent->nextState is moved to cent->currentState and events are fired -=============== -*/ -static void CG_TransitionEntity( centity_t *cent ) -{ - cent->currentState = cent->nextState; - cent->currentValid = qtrue; - - // reset if the entity wasn't in the last frame or was teleported - if( !cent->interpolate ) - CG_ResetEntity( cent ); - - // clear the next state. if will be set by the next CG_SetNextSnap - cent->interpolate = qfalse; - - // check for events - CG_CheckEvents( cent ); -} - - -/* -================== -CG_SetInitialSnapshot - -This will only happen on the very first snapshot, or -on tourney restarts. All other times will use -CG_TransitionSnapshot instead. - -FIXME: Also called by map_restart? -================== -*/ -void CG_SetInitialSnapshot( snapshot_t *snap ) -{ - int i; - centity_t *cent; - entityState_t *state; - - cg.snap = snap; - - BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse ); - - // sort out solid entities - CG_BuildSolidList( ); - - CG_ExecuteNewServerCommands( snap->serverCommandSequence ); - - // set our local weapon selection pointer to - // what the server has indicated the current weapon is - CG_Respawn( ); - - for( i = 0; i < cg.snap->numEntities; i++ ) - { - state = &cg.snap->entities[ i ]; - cent = &cg_entities[ state->number ]; - - memcpy( ¢->currentState, state, sizeof( entityState_t ) ); - //cent->currentState = *state; - cent->interpolate = qfalse; - cent->currentValid = qtrue; - - CG_ResetEntity( cent ); - - // check for events - CG_CheckEvents( cent ); - } -} - - -/* -=================== -CG_TransitionSnapshot - -The transition point from snap to nextSnap has passed -=================== -*/ -static void CG_TransitionSnapshot( void ) -{ - centity_t *cent; - snapshot_t *oldFrame; - int i; - - if( !cg.snap ) - CG_Error( "CG_TransitionSnapshot: NULL cg.snap" ); - - if( !cg.nextSnap ) - CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" ); - - // execute any server string commands before transitioning entities - CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence ); - - // if we had a map_restart, set everthing with initial - if( !cg.snap ) { } //TA: ? - - // clear the currentValid flag for all entities in the existing snapshot - for( i = 0; i < cg.snap->numEntities; i++ ) - { - cent = &cg_entities[ cg.snap->entities[ i ].number ]; - cent->currentValid = qfalse; - } - - // move nextSnap to snap and do the transitions - oldFrame = cg.snap; - cg.snap = cg.nextSnap; - - BG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse ); - cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse; - - for( i = 0; i < cg.snap->numEntities; i++ ) - { - cent = &cg_entities[ cg.snap->entities[ i ].number ]; - CG_TransitionEntity( cent ); - - // remember time of snapshot this entity was last updated in - cent->snapShotTime = cg.snap->serverTime; - } - - cg.nextSnap = NULL; - - // check for playerstate transition events - if( oldFrame ) - { - playerState_t *ops, *ps; - - ops = &oldFrame->ps; - ps = &cg.snap->ps; - // teleporting checks are irrespective of prediction - if( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT ) - cg.thisFrameTeleport = qtrue; // will be cleared by prediction code - - // if we are not doing client side movement prediction for any - // reason, then the client events and view changes will be issued now - if( cg.demoPlayback || ( cg.snap->ps.pm_flags & PMF_FOLLOW ) || - cg_nopredict.integer || cg_synchronousClients.integer ) - CG_TransitionPlayerState( ps, ops ); - } -} - - -/* -=================== -CG_SetNextSnap - -A new snapshot has just been read in from the client system. -=================== -*/ -static void CG_SetNextSnap( snapshot_t *snap ) -{ - int num; - entityState_t *es; - centity_t *cent; - - cg.nextSnap = snap; - - BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse ); - cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue; - - // check for extrapolation errors - for( num = 0 ; num < snap->numEntities ; num++ ) - { - es = &snap->entities[ num ]; - cent = &cg_entities[ es->number ]; - - memcpy( ¢->nextState, es, sizeof( entityState_t ) ); - //cent->nextState = *es; - - // if this frame is a teleport, or the entity wasn't in the - // previous frame, don't interpolate - if( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) ) - cent->interpolate = qfalse; - else - cent->interpolate = qtrue; - } - - // if the next frame is a teleport for the playerstate, we - // can't interpolate during demos - if( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) - cg.nextFrameTeleport = qtrue; - else - cg.nextFrameTeleport = qfalse; - - // if changing follow mode, don't interpolate - if( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) - cg.nextFrameTeleport = qtrue; - - // if changing server restarts, don't interpolate - if( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) - cg.nextFrameTeleport = qtrue; - - // sort out solid entities - CG_BuildSolidList( ); -} - - -/* -======================== -CG_ReadNextSnapshot - -This is the only place new snapshots are requested -This may increment cgs.processedSnapshotNum multiple -times if the client system fails to return a -valid snapshot. -======================== -*/ -static snapshot_t *CG_ReadNextSnapshot( void ) -{ - qboolean r; - snapshot_t *dest; - - if( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) - { - CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i", - cg.latestSnapshotNum, cgs.processedSnapshotNum ); - } - - while( cgs.processedSnapshotNum < cg.latestSnapshotNum ) - { - // decide which of the two slots to load it into - if( cg.snap == &cg.activeSnapshots[ 0 ] ) - dest = &cg.activeSnapshots[ 1 ]; - else - dest = &cg.activeSnapshots[ 0 ]; - - // try to read the snapshot from the client system - cgs.processedSnapshotNum++; - r = trap_GetSnapshot( cgs.processedSnapshotNum, dest ); - - // FIXME: why would trap_GetSnapshot return a snapshot with the same server time - if( cg.snap && r && dest->serverTime == cg.snap->serverTime ) - { - //continue; - } - - // if it succeeded, return - if( r ) - { - CG_AddLagometerSnapshotInfo( dest ); - return dest; - } - - // a GetSnapshot will return failure if the snapshot - // never arrived, or is so old that its entities - // have been shoved off the end of the circular - // buffer in the client system. - - // record as a dropped packet - CG_AddLagometerSnapshotInfo( NULL ); - - // If there are additional snapshots, continue trying to - // read them. - } - - // nothing left to read - return NULL; -} - - -/* -============ -CG_ProcessSnapshots - -We are trying to set up a renderable view, so determine -what the simulated time is, and try to get snapshots -both before and after that time if available. - -If we don't have a valid cg.snap after exiting this function, -then a 3D game view cannot be rendered. This should only happen -right after the initial connection. After cg.snap has been valid -once, it will never turn invalid. - -Even if cg.snap is valid, cg.nextSnap may not be, if the snapshot -hasn't arrived yet (it becomes an extrapolating situation instead -of an interpolating one) - -============ -*/ -void CG_ProcessSnapshots( void ) -{ - snapshot_t *snap; - int n; - - // see what the latest snapshot the client system has is - trap_GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime ); - - if( n != cg.latestSnapshotNum ) - { - if( n < cg.latestSnapshotNum ) - { - // this should never happen - CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" ); - } - - cg.latestSnapshotNum = n; - } - - // If we have yet to receive a snapshot, check for it. - // Once we have gotten the first snapshot, cg.snap will - // always have valid data for the rest of the game - while( !cg.snap ) - { - snap = CG_ReadNextSnapshot( ); - - if( !snap ) - { - // we can't continue until we get a snapshot - return; - } - - // set our weapon selection to what - // the playerstate is currently using - if( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) - CG_SetInitialSnapshot( snap ); - } - - // loop until we either have a valid nextSnap with a serverTime - // greater than cg.time to interpolate towards, or we run - // out of available snapshots - do - { - // if we don't have a nextframe, try and read a new one in - if( !cg.nextSnap ) - { - snap = CG_ReadNextSnapshot( ); - - // if we still don't have a nextframe, we will just have to - // extrapolate - if( !snap ) - break; - - CG_SetNextSnap( snap ); - - // if time went backwards, we have a level restart - if( cg.nextSnap->serverTime < cg.snap->serverTime ) - CG_Error( "CG_ProcessSnapshots: Server time went backwards" ); - } - - // if our time is < nextFrame's, we have a nice interpolating state - if( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime ) - break; - - // we have passed the transition from nextFrame to frame - CG_TransitionSnapshot( ); - } while( 1 ); - - // assert our valid conditions upon exiting - if( cg.snap == NULL ) - CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" ); - - if( cg.time < cg.snap->serverTime ) - { - // this can happen right after a vid_restart - cg.time = cg.snap->serverTime; - } - - if( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) - CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" ); -} - diff --git a/src/cgame/cg_syscalls.asm b/src/cgame/cg_syscalls.asm deleted file mode 100644 index 9da1dade..00000000 --- a/src/cgame/cg_syscalls.asm +++ /dev/null @@ -1,105 +0,0 @@ -code - -equ trap_Print -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_VariableStringBuffer -7 -equ trap_Argc -8 -equ trap_Argv -9 -equ trap_Args -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_AddCommand -16 -equ trap_SendClientCommand -17 -equ trap_UpdateScreen -18 -equ trap_CM_LoadMap -19 -equ trap_CM_NumInlineModels -20 -equ trap_CM_InlineModel -21 -equ trap_CM_LoadModel -22 -equ trap_CM_TempBoxModel -23 -equ trap_CM_PointContents -24 -equ trap_CM_TransformedPointContents -25 -equ trap_CM_BoxTrace -26 -equ trap_CM_TransformedBoxTrace -27 -equ trap_CM_MarkFragments -28 -equ trap_S_StartSound -29 -equ trap_S_StartLocalSound -30 -equ trap_S_ClearLoopingSounds -31 -equ trap_S_AddLoopingSound -32 -equ trap_S_UpdateEntityPosition -33 -equ trap_S_Respatialize -34 -equ trap_S_RegisterSound -35 -equ trap_S_StartBackgroundTrack -36 -equ trap_R_LoadWorldMap -37 -equ trap_R_RegisterModel -38 -equ trap_R_RegisterSkin -39 -equ trap_R_RegisterShader -40 -equ trap_R_ClearScene -41 -equ trap_R_AddRefEntityToScene -42 -equ trap_R_AddPolyToScene -43 -equ trap_R_AddLightToScene -44 -equ trap_R_RenderScene -45 -equ trap_R_SetColor -46 -equ trap_R_DrawStretchPic -47 -equ trap_R_ModelBounds -48 -equ trap_R_LerpTag -49 -equ trap_GetGlconfig -50 -equ trap_GetGameState -51 -equ trap_GetCurrentSnapshotNumber -52 -equ trap_GetSnapshot -53 -equ trap_GetServerCommand -54 -equ trap_GetCurrentCmdNumber -55 -equ trap_GetUserCmd -56 -equ trap_SetUserCmdValue -57 -equ trap_R_RegisterShaderNoMip -58 -equ trap_MemoryRemaining -59 -equ trap_R_RegisterFont -60 -equ trap_Key_IsDown -61 -equ trap_Key_GetCatcher -62 -equ trap_Key_SetCatcher -63 -equ trap_Key_GetKey -64 -equ trap_PC_AddGlobalDefine -65 -equ trap_PC_LoadSource -66 -equ trap_PC_FreeSource -67 -equ trap_PC_ReadToken -68 -equ trap_PC_SourceFileAndLine -69 -equ trap_S_StopBackgroundTrack -70 -equ trap_RealTime -71 -equ trap_SnapVector -72 -equ trap_RemoveCommand -73 -equ trap_R_LightForPoint -74 -equ trap_CIN_PlayCinematic -75 -equ trap_CIN_StopCinematic -76 -equ trap_CIN_RunCinematic -77 -equ trap_CIN_DrawCinematic -78 -equ trap_CIN_SetExtents -79 -equ trap_R_RemapShader -80 -equ trap_S_AddRealLoopingSound -81 -equ trap_S_StopLoopingSound -82 -equ trap_CM_TempCapsuleModel -83 -equ trap_CM_CapsuleTrace -84 -equ trap_CM_TransformedCapsuleTrace -85 -equ trap_R_AddAdditiveLightToScene -86 -equ trap_GetEntityToken -87 -equ trap_R_AddPolysToScene -88 -equ trap_R_inPVS -89 -equ trap_FS_Seek -90 - -equ memset -101 -equ memcpy -102 -equ strncpy -103 -equ sin -104 -equ cos -105 -equ atan2 -106 -equ sqrt -107 -equ floor -108 -equ ceil -109 -equ testPrintInt -110 -equ testPrintFloat -111 - diff --git a/src/cgame/cg_syscalls.c b/src/cgame/cg_syscalls.c deleted file mode 100644 index 3e8c5849..00000000 --- a/src/cgame/cg_syscalls.c +++ /dev/null @@ -1,507 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_syscalls.c -- this file is only included when building a dll -// cg_syscalls.asm is included instead when building a qvm - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -static long (QDECL *syscall)( long arg, ... ) = (long (QDECL *)( long, ...))-1; - - -void dllEntry( long (QDECL *syscallptr)( long arg,... ) ) -{ - syscall = syscallptr; -} - - -int PASSFLOAT( float x ) -{ - float floatTemp; - floatTemp = x; - return *(int *)&floatTemp; -} - -void trap_Print( const char *fmt ) -{ - syscall( CG_PRINT, fmt ); -} - -void trap_Error( const char *fmt ) -{ - syscall( CG_ERROR, fmt ); -} - -int trap_Milliseconds( void ) -{ - return syscall( CG_MILLISECONDS ); -} - -void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) -{ - syscall( CG_CVAR_REGISTER, vmCvar, varName, defaultValue, flags ); -} - -void trap_Cvar_Update( vmCvar_t *vmCvar ) -{ - syscall( CG_CVAR_UPDATE, vmCvar ); -} - -void trap_Cvar_Set( const char *var_name, const char *value ) -{ - syscall( CG_CVAR_SET, var_name, value ); -} - -void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ) -{ - syscall( CG_CVAR_VARIABLESTRINGBUFFER, var_name, buffer, bufsize ); -} - -int trap_Argc( void ) -{ - return syscall( CG_ARGC ); -} - -void trap_Argv( int n, char *buffer, int bufferLength ) -{ - syscall( CG_ARGV, n, buffer, bufferLength ); -} - -void trap_Args( char *buffer, int bufferLength ) -{ - syscall( CG_ARGS, buffer, bufferLength ); -} - -int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) -{ - return syscall( CG_FS_FOPENFILE, qpath, f, mode ); -} - -void trap_FS_Read( void *buffer, int len, fileHandle_t f ) -{ - syscall( CG_FS_READ, buffer, len, f ); -} - -void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) -{ - syscall( CG_FS_WRITE, buffer, len, f ); -} - -void trap_FS_FCloseFile( fileHandle_t f ) -{ - syscall( CG_FS_FCLOSEFILE, f ); -} - -void trap_FS_Seek( fileHandle_t f, long offset, fsOrigin_t origin ) -{ - syscall( CG_FS_SEEK, f, offset, origin ); -} - -void trap_SendConsoleCommand( const char *text ) -{ - syscall( CG_SENDCONSOLECOMMAND, text ); -} - -void trap_AddCommand( const char *cmdName ) -{ - syscall( CG_ADDCOMMAND, cmdName ); -} - -void trap_RemoveCommand( const char *cmdName ) -{ - syscall( CG_REMOVECOMMAND, cmdName ); -} - -void trap_SendClientCommand( const char *s ) -{ - syscall( CG_SENDCLIENTCOMMAND, s ); -} - -void trap_UpdateScreen( void ) -{ - syscall( CG_UPDATESCREEN ); -} - -void trap_CM_LoadMap( const char *mapname ) -{ - syscall( CG_CM_LOADMAP, mapname ); -} - -int trap_CM_NumInlineModels( void ) -{ - return syscall( CG_CM_NUMINLINEMODELS ); -} - -clipHandle_t trap_CM_InlineModel( int index ) -{ - return syscall( CG_CM_INLINEMODEL, index ); -} - -clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) -{ - return syscall( CG_CM_TEMPBOXMODEL, mins, maxs ); -} - -clipHandle_t trap_CM_TempCapsuleModel( const vec3_t mins, const vec3_t maxs ) -{ - return syscall( CG_CM_TEMPCAPSULEMODEL, mins, maxs ); -} - -int trap_CM_PointContents( const vec3_t p, clipHandle_t model ) -{ - return syscall( CG_CM_POINTCONTENTS, p, model ); -} - -int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, - const vec3_t angles ) -{ - return syscall( CG_CM_TRANSFORMEDPOINTCONTENTS, p, model, origin, angles ); -} - -void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end, - const vec3_t mins, const vec3_t maxs, - clipHandle_t model, int brushmask ) -{ - syscall( CG_CM_BOXTRACE, results, start, end, mins, maxs, model, brushmask ); -} - -void trap_CM_CapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end, - const vec3_t mins, const vec3_t maxs, - clipHandle_t model, int brushmask ) -{ - syscall( CG_CM_CAPSULETRACE, results, start, end, mins, maxs, model, brushmask ); -} - -void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end, - const vec3_t mins, const vec3_t maxs, - clipHandle_t model, int brushmask, - const vec3_t origin, const vec3_t angles ) -{ - syscall( CG_CM_TRANSFORMEDBOXTRACE, results, start, end, mins, maxs, model, brushmask, origin, angles ); -} - -void trap_CM_TransformedCapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end, - const vec3_t mins, const vec3_t maxs, - clipHandle_t model, int brushmask, - const vec3_t origin, const vec3_t angles ) -{ - syscall( CG_CM_TRANSFORMEDCAPSULETRACE, results, start, end, mins, maxs, model, brushmask, origin, angles ); -} - -int trap_CM_MarkFragments( int numPoints, const vec3_t *points, - const vec3_t projection, - int maxPoints, vec3_t pointBuffer, - int maxFragments, markFragment_t *fragmentBuffer ) -{ - return syscall( CG_CM_MARKFRAGMENTS, numPoints, points, projection, maxPoints, - pointBuffer, maxFragments, fragmentBuffer ); -} - -void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx ) -{ - syscall( CG_S_STARTSOUND, origin, entityNum, entchannel, sfx ); -} - -void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ) -{ - syscall( CG_S_STARTLOCALSOUND, sfx, channelNum ); -} - -void trap_S_ClearLoopingSounds( qboolean killall ) -{ - syscall( CG_S_CLEARLOOPINGSOUNDS, killall ); -} - -void trap_S_AddLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) -{ - syscall( CG_S_ADDLOOPINGSOUND, entityNum, origin, velocity, sfx ); -} - -void trap_S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx ) -{ - syscall( CG_S_ADDREALLOOPINGSOUND, entityNum, origin, velocity, sfx ); -} - -void trap_S_StopLoopingSound( int entityNum ) -{ - syscall( CG_S_STOPLOOPINGSOUND, entityNum ); -} - -void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin ) -{ - syscall( CG_S_UPDATEENTITYPOSITION, entityNum, origin ); -} - -void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater ) -{ - syscall( CG_S_RESPATIALIZE, entityNum, origin, axis, inwater ); -} - -sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ) -{ - return syscall( CG_S_REGISTERSOUND, sample, compressed ); -} - -void trap_S_StartBackgroundTrack( const char *intro, const char *loop ) -{ - syscall( CG_S_STARTBACKGROUNDTRACK, intro, loop ); -} - -void trap_R_LoadWorldMap( const char *mapname ) -{ - syscall( CG_R_LOADWORLDMAP, mapname ); -} - -qhandle_t trap_R_RegisterModel( const char *name ) -{ - return syscall( CG_R_REGISTERMODEL, name ); -} - -qhandle_t trap_R_RegisterSkin( const char *name ) -{ - return syscall( CG_R_REGISTERSKIN, name ); -} - -qhandle_t trap_R_RegisterShader( const char *name ) -{ - return syscall( CG_R_REGISTERSHADER, name ); -} - -qhandle_t trap_R_RegisterShaderNoMip( const char *name ) -{ - return syscall( CG_R_REGISTERSHADERNOMIP, name ); -} - -void trap_R_RegisterFont( const char *fontName, int pointSize, fontInfo_t *font ) -{ - syscall(CG_R_REGISTERFONT, fontName, pointSize, font ); -} - -void trap_R_ClearScene( void ) -{ - syscall( CG_R_CLEARSCENE ); -} - -void trap_R_AddRefEntityToScene( const refEntity_t *re ) -{ - syscall( CG_R_ADDREFENTITYTOSCENE, re ); -} - -void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ) -{ - syscall( CG_R_ADDPOLYTOSCENE, hShader, numVerts, verts ); -} - -void trap_R_AddPolysToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts, int num ) -{ - syscall( CG_R_ADDPOLYSTOSCENE, hShader, numVerts, verts, num ); -} - -int trap_R_LightForPoint( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir ) -{ - return syscall( CG_R_LIGHTFORPOINT, point, ambientLight, directedLight, lightDir ); -} - -void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) -{ - syscall( CG_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) ); -} - -void trap_R_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ) -{ - syscall( CG_R_ADDADDITIVELIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) ); -} - -void trap_R_RenderScene( const refdef_t *fd ) -{ - syscall( CG_R_RENDERSCENE, fd ); -} - -void trap_R_SetColor( const float *rgba ) -{ - syscall( CG_R_SETCOLOR, rgba ); -} - -void trap_R_DrawStretchPic( float x, float y, float w, float h, - float s1, float t1, float s2, float t2, qhandle_t hShader ) -{ - syscall( CG_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), - PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), hShader ); -} - -void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) { - syscall( CG_R_MODELBOUNDS, model, mins, maxs ); -} - -int trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, - float frac, const char *tagName ) -{ - return syscall( CG_R_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName ); -} - -void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ) -{ - syscall( CG_R_REMAP_SHADER, oldShader, newShader, timeOffset ); -} - -void trap_GetGlconfig( glconfig_t *glconfig ) -{ - syscall( CG_GETGLCONFIG, glconfig ); -} - -void trap_GetGameState( gameState_t *gamestate ) -{ - syscall( CG_GETGAMESTATE, gamestate ); -} - -void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) -{ - syscall( CG_GETCURRENTSNAPSHOTNUMBER, snapshotNumber, serverTime ); -} - -qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) -{ - return syscall( CG_GETSNAPSHOT, snapshotNumber, snapshot ); -} - -qboolean trap_GetServerCommand( int serverCommandNumber ) -{ - return syscall( CG_GETSERVERCOMMAND, serverCommandNumber ); -} - -int trap_GetCurrentCmdNumber( void ) -{ - return syscall( CG_GETCURRENTCMDNUMBER ); -} - -qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) -{ - return syscall( CG_GETUSERCMD, cmdNumber, ucmd ); -} - -void trap_SetUserCmdValue( int stateValue, float sensitivityScale ) -{ - syscall( CG_SETUSERCMDVALUE, stateValue, PASSFLOAT( sensitivityScale ) ); -} - -void testPrintInt( char *string, int i ) -{ - syscall( CG_TESTPRINTINT, string, i ); -} - -void testPrintFloat( char *string, float f ) -{ - syscall( CG_TESTPRINTFLOAT, string, PASSFLOAT(f) ); -} - -int trap_MemoryRemaining( void ) -{ - return syscall( CG_MEMORY_REMAINING ); -} - -qboolean trap_Key_IsDown( int keynum ) -{ - return syscall( CG_KEY_ISDOWN, keynum ); -} - -int trap_Key_GetCatcher( void ) -{ - return syscall( CG_KEY_GETCATCHER ); -} - -void trap_Key_SetCatcher( int catcher ) -{ - syscall( CG_KEY_SETCATCHER, catcher ); -} - -int trap_Key_GetKey( const char *binding ) -{ - return syscall( CG_KEY_GETKEY, binding ); -} - -int trap_PC_AddGlobalDefine( char *define ) -{ - return syscall( CG_PC_ADD_GLOBAL_DEFINE, define ); -} - -int trap_PC_LoadSource( const char *filename ) -{ - return syscall( CG_PC_LOAD_SOURCE, filename ); -} - -int trap_PC_FreeSource( int handle ) -{ - return syscall( CG_PC_FREE_SOURCE, handle ); -} - -int trap_PC_ReadToken( int handle, pc_token_t *pc_token ) -{ - return syscall( CG_PC_READ_TOKEN, handle, pc_token ); -} - -int trap_PC_SourceFileAndLine( int handle, char *filename, int *line ) -{ - return syscall( CG_PC_SOURCE_FILE_AND_LINE, handle, filename, line ); -} - -void trap_S_StopBackgroundTrack( void ) -{ - syscall( CG_S_STOPBACKGROUNDTRACK ); -} - -int trap_RealTime(qtime_t *qtime) -{ - return syscall( CG_REAL_TIME, qtime ); -} - -void trap_SnapVector( float *v ) -{ - syscall( CG_SNAPVECTOR, v ); -} - -// this returns a handle. arg0 is the name in the format "idlogo.roq", set arg1 to NULL, alteredstates to qfalse (do not alter gamestate) -int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits ) -{ - return syscall(CG_CIN_PLAYCINEMATIC, arg0, xpos, ypos, width, height, bits); -} - -// stops playing the cinematic and ends it. should always return FMV_EOF -// cinematics must be stopped in reverse order of when they are started -e_status trap_CIN_StopCinematic( int handle ) -{ - return syscall(CG_CIN_STOPCINEMATIC, handle); -} - - -// will run a frame of the cinematic but will not draw it. Will return FMV_EOF if the end of the cinematic has been reached. -e_status trap_CIN_RunCinematic( int handle ) -{ - return syscall(CG_CIN_RUNCINEMATIC, handle); -} - - -// draws the current frame -void trap_CIN_DrawCinematic( int handle ) -{ - syscall(CG_CIN_DRAWCINEMATIC, handle); -} - - -// allows you to resize the animation dynamically -void trap_CIN_SetExtents( int handle, int x, int y, int w, int h ) -{ - syscall(CG_CIN_SETEXTENTS, handle, x, y, w, h); -} - diff --git a/src/cgame/cg_trails.c b/src/cgame/cg_trails.c deleted file mode 100644 index 3ef19f00..00000000 --- a/src/cgame/cg_trails.c +++ /dev/null @@ -1,1489 +0,0 @@ -// cg_trails.c -- the trail system - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -static baseTrailSystem_t baseTrailSystems[ MAX_BASETRAIL_SYSTEMS ]; -static baseTrailBeam_t baseTrailBeams[ MAX_BASETRAIL_BEAMS ]; -static int numBaseTrailSystems = 0; -static int numBaseTrailBeams = 0; - -static trailSystem_t trailSystems[ MAX_TRAIL_SYSTEMS ]; -static trailBeam_t trailBeams[ MAX_TRAIL_BEAMS ]; - -/* -=============== -CG_CalculateBeamNodeProperties - -Fills in trailBeamNode_t.textureCoord -=============== -*/ -static void CG_CalculateBeamNodeProperties( trailBeam_t *tb ) -{ - trailBeamNode_t *i = NULL; - trailSystem_t *ts; - baseTrailBeam_t *btb; - float nodeDistances[ MAX_TRAIL_BEAM_NODES ]; - float totalDistance = 0.0f, position = 0.0f; - int j, numNodes = 0; - float TCRange, widthRange, alphaRange; - vec3_t colorRange; - float fadeAlpha = 1.0f; - - if( !tb || !tb->nodes ) - return; - - ts = tb->parent; - btb = tb->class; - - if( ts->destroyTime > 0 && btb->fadeOutTime ) - { - fadeAlpha -= ( cg.time - ts->destroyTime ) / btb->fadeOutTime; - - if( fadeAlpha < 0.0f ) - fadeAlpha = 0.0f; - } - - TCRange = tb->class->backTextureCoord - - tb->class->frontTextureCoord; - widthRange = tb->class->backWidth - - tb->class->frontWidth; - alphaRange = tb->class->backAlpha - - tb->class->frontAlpha; - VectorSubtract( tb->class->backColor, - tb->class->frontColor, colorRange ); - - for( i = tb->nodes; i && i->next; i = i->next ) - { - nodeDistances[ numNodes++ ] = - Distance( i->position, i->next->position ); - } - - for( j = 0; j < numNodes; j++ ) - totalDistance += nodeDistances[ j ]; - - for( j = 0, i = tb->nodes; i; i = i->next, j++ ) - { - if( tb->class->textureType == TBTT_STRETCH ) - { - i->textureCoord = tb->class->frontTextureCoord + - ( ( position / totalDistance ) * TCRange ); - } - else if( tb->class->textureType == TBTT_REPEAT ) - { - if( tb->class->clampToBack ) - i->textureCoord = ( totalDistance - position ) / - tb->class->repeatLength; - else - i->textureCoord = position / tb->class->repeatLength; - } - - i->halfWidth = ( tb->class->frontWidth + - ( ( position / totalDistance ) * widthRange ) ) / 2.0f; - i->alpha = (byte)( (float)0xFF * ( tb->class->frontAlpha + - ( ( position / totalDistance ) * alphaRange ) ) * fadeAlpha ); - VectorMA( tb->class->frontColor, ( position / totalDistance ), - colorRange, i->color ); - - position += nodeDistances[ j ]; - } -} - -/* -=============== -CG_LightVertex - -Lights a particular vertex -=============== -*/ -static void CG_LightVertex( vec3_t point, byte alpha, byte *rgba ) -{ - int i; - vec3_t alight, dlight, lightdir; - - trap_R_LightForPoint( point, alight, dlight, lightdir ); - for( i = 0; i <= 2; i++ ) - rgba[ i ] = (int)alight[ i ]; - - rgba[ 3 ] = alpha; -} - -/* -=============== -CG_RenderBeam - -Renders a beam -=============== -*/ -static void CG_RenderBeam( trailBeam_t *tb ) -{ - trailBeamNode_t *i = NULL; - trailBeamNode_t *prev = NULL; - trailBeamNode_t *next = NULL; - vec3_t up; - polyVert_t verts[ ( MAX_TRAIL_BEAM_NODES - 1 ) * 4 ]; - int numVerts = 0; - baseTrailBeam_t *btb; - trailSystem_t *ts; - baseTrailSystem_t *bts; - - if( !tb || !tb->nodes ) - return; - - btb = tb->class; - ts = tb->parent; - bts = ts->class; - - if( bts->thirdPersonOnly && - ( CG_AttachmentCentNum( &ts->frontAttachment ) == cg.snap->ps.clientNum || - CG_AttachmentCentNum( &ts->backAttachment ) == cg.snap->ps.clientNum ) && - !cg.renderingThirdPerson ) - return; - - CG_CalculateBeamNodeProperties( tb ); - - i = tb->nodes; - - do - { - prev = i->prev; - next = i->next; - - if( prev && next ) - { - //this node has two neighbours - GetPerpendicularViewVector( cg.refdef.vieworg, next->position, prev->position, up ); - } - else if( !prev && next ) - { - //this is the front - GetPerpendicularViewVector( cg.refdef.vieworg, next->position, i->position, up ); - } - else if( prev && !next ) - { - //this is the back - GetPerpendicularViewVector( cg.refdef.vieworg, i->position, prev->position, up ); - } - else - break; - - if( prev ) - { - VectorMA( i->position, i->halfWidth, up, verts[ numVerts ].xyz ); - verts[ numVerts ].st[ 0 ] = i->textureCoord; - verts[ numVerts ].st[ 1 ] = 1.0f; - - if( btb->realLight ) - CG_LightVertex( verts[ numVerts ].xyz, i->alpha, verts[ numVerts ].modulate ); - else - { - VectorCopy( i->color, verts[ numVerts ].modulate ); - verts[ numVerts ].modulate[ 3 ] = i->alpha; - } - - numVerts++; - - VectorMA( i->position, -i->halfWidth, up, verts[ numVerts ].xyz ); - verts[ numVerts ].st[ 0 ] = i->textureCoord; - verts[ numVerts ].st[ 1 ] = 0.0f; - - if( btb->realLight ) - CG_LightVertex( verts[ numVerts ].xyz, i->alpha, verts[ numVerts ].modulate ); - else - { - VectorCopy( i->color, verts[ numVerts ].modulate ); - verts[ numVerts ].modulate[ 3 ] = i->alpha; - } - - numVerts++; - } - - if( next ) - { - VectorMA( i->position, -i->halfWidth, up, verts[ numVerts ].xyz ); - verts[ numVerts ].st[ 0 ] = i->textureCoord; - verts[ numVerts ].st[ 1 ] = 0.0f; - - if( btb->realLight ) - CG_LightVertex( verts[ numVerts ].xyz, i->alpha, verts[ numVerts ].modulate ); - else - { - VectorCopy( i->color, verts[ numVerts ].modulate ); - verts[ numVerts ].modulate[ 3 ] = i->alpha; - } - - numVerts++; - - VectorMA( i->position, i->halfWidth, up, verts[ numVerts ].xyz ); - verts[ numVerts ].st[ 0 ] = i->textureCoord; - verts[ numVerts ].st[ 1 ] = 1.0f; - - if( btb->realLight ) - CG_LightVertex( verts[ numVerts ].xyz, i->alpha, verts[ numVerts ].modulate ); - else - { - VectorCopy( i->color, verts[ numVerts ].modulate ); - verts[ numVerts ].modulate[ 3 ] = i->alpha; - } - - numVerts++; - } - - i = i->next; - } while( i ); - - trap_R_AddPolysToScene( tb->class->shader, 4, &verts[ 0 ], numVerts / 4 ); -} - -/* -=============== -CG_AllocateBeamNode - -Allocates a trailBeamNode_t from a trailBeam_t's nodePool -=============== -*/ -static trailBeamNode_t *CG_AllocateBeamNode( trailBeam_t *tb ) -{ - baseTrailBeam_t *btb = tb->class; - int i; - trailBeamNode_t *tbn; - - for( i = 0; i < MAX_TRAIL_BEAM_NODES; i++ ) - { - tbn = &tb->nodePool[ i ]; - if( !tbn->used ) - { - tbn->timeLeft = btb->segmentTime; - tbn->prev = NULL; - tbn->next = NULL; - tbn->used = qtrue; - return tbn; - } - } - - // no space left - return NULL; -} - -/* -=============== -CG_DestroyBeamNode - -Removes a node from a beam -Returns the new head -=============== -*/ -static trailBeamNode_t *CG_DestroyBeamNode( trailBeamNode_t *tbn ) -{ - trailBeamNode_t *newHead = NULL; - - if( tbn->prev ) - { - if( tbn->next ) - { - // node is in the middle - tbn->prev->next = tbn->next; - tbn->next->prev = tbn->prev; - } - else // node is at the back - tbn->prev->next = NULL; - - // find the new head (shouldn't have changed) - newHead = tbn->prev; - - while( newHead->prev ) - newHead = newHead->prev; - } - else if( tbn->next ) - { - //node is at the front - tbn->next->prev = NULL; - newHead = tbn->next; - } - - tbn->prev = NULL; - tbn->next = NULL; - tbn->used = qfalse; - - return newHead; -} - -/* -=============== -CG_FindLastBeamNode - -Returns the last beam node in a beam -=============== -*/ -static trailBeamNode_t *CG_FindLastBeamNode( trailBeam_t *tb ) -{ - trailBeamNode_t *i = tb->nodes; - - while( i && i->next ) - i = i->next; - - return i; -} - -/* -=============== -CG_CountBeamNodes - -Returns the number of nodes in a beam -=============== -*/ -static int CG_CountBeamNodes( trailBeam_t *tb ) -{ - trailBeamNode_t *i = tb->nodes; - int numNodes = 0; - - while( i ) - { - numNodes++; - i = i->next; - } - - return numNodes; -} - -/* -=============== -CG_PrependBeamNode - -Prepend a new beam node to the front of a beam -Returns the new node -=============== -*/ -static trailBeamNode_t *CG_PrependBeamNode( trailBeam_t *tb ) -{ - trailBeamNode_t *i; - - if( tb->nodes ) - { - // prepend another node - i = CG_AllocateBeamNode( tb ); - - if( i ) - { - i->next = tb->nodes; - tb->nodes->prev = i; - tb->nodes = i; - } - } - else //add first node - { - i = CG_AllocateBeamNode( tb ); - - if( i ) - tb->nodes = i; - } - - return i; -} - -/* -=============== -CG_AppendBeamNode - -Append a new beam node to the back of a beam -Returns the new node -=============== -*/ -static trailBeamNode_t *CG_AppendBeamNode( trailBeam_t *tb ) -{ - trailBeamNode_t *last, *i; - - if( tb->nodes ) - { - // append another node - last = CG_FindLastBeamNode( tb ); - i = CG_AllocateBeamNode( tb ); - - if( i ) - { - last->next = i; - i->prev = last; - i->next = NULL; - } - } - else //add first node - { - i = CG_AllocateBeamNode( tb ); - - if( i ) - tb->nodes = i; - } - - return i; -} - -/* -=============== -CG_ApplyJitters -=============== -*/ -static void CG_ApplyJitters( trailBeam_t *tb ) -{ - trailBeamNode_t *i = NULL; - int j; - baseTrailBeam_t *btb; - trailSystem_t *ts; - trailBeamNode_t *start; - trailBeamNode_t *end; - - if( !tb || !tb->nodes ) - return; - - btb = tb->class; - ts = tb->parent; - - for( j = 0; j < btb->numJitters; j++ ) - { - if( tb->nextJitterTimes[ j ] <= cg.time ) - { - for( i = tb->nodes; i; i = i->next ) - { - i->jitters[ j ][ 0 ] = ( crandom( ) * btb->jitters[ j ].magnitude ); - i->jitters[ j ][ 1 ] = ( crandom( ) * btb->jitters[ j ].magnitude ); - } - - tb->nextJitterTimes[ j ] = cg.time + btb->jitters[ j ].period; - } - } - - start = tb->nodes; - end = CG_FindLastBeamNode( tb ); - - if( !btb->jitterAttachments ) - { - if( CG_Attached( &ts->frontAttachment ) && start->next ) - start = start->next; - - if( CG_Attached( &ts->backAttachment ) && end->prev ) - end = end->prev; - } - - for( i = start; i; i = i->next ) - { - vec3_t forward, right, up; - trailBeamNode_t *prev; - trailBeamNode_t *next; - float upJitter = 0.0f, rightJitter = 0.0f; - - prev = i->prev; - next = i->next; - - if( prev && next ) - { - //this node has two neighbours - GetPerpendicularViewVector( cg.refdef.vieworg, next->position, prev->position, up ); - VectorSubtract( next->position, prev->position, forward ); - } - else if( !prev && next ) - { - //this is the front - GetPerpendicularViewVector( cg.refdef.vieworg, next->position, i->position, up ); - VectorSubtract( next->position, i->position, forward ); - } - else if( prev && !next ) - { - //this is the back - GetPerpendicularViewVector( cg.refdef.vieworg, i->position, prev->position, up ); - VectorSubtract( i->position, prev->position, forward ); - } - - VectorNormalize( forward ); - CrossProduct( forward, up, right ); - VectorNormalize( right ); - - for( j = 0; j < btb->numJitters; j++ ) - { - upJitter += i->jitters[ j ][ 0 ]; - rightJitter += i->jitters[ j ][ 1 ]; - } - - VectorMA( i->position, upJitter, up, i->position ); - VectorMA( i->position, rightJitter, right, i->position ); - - if( i == end ) - break; - } -} - -/* -=============== -CG_UpdateBeam - -Updates a beam -=============== -*/ -static void CG_UpdateBeam( trailBeam_t *tb ) -{ - baseTrailBeam_t *btb; - trailSystem_t *ts; - trailBeamNode_t *i; - int deltaTime; - int nodesToAdd; - int j; - int numNodes; - - if( !tb ) - return; - - btb = tb->class; - ts = tb->parent; - - deltaTime = cg.time - tb->lastEvalTime; - tb->lastEvalTime = cg.time; - - // first make sure this beam has enough nodes - if( ts->destroyTime <= 0 ) - { - nodesToAdd = btb->numSegments - CG_CountBeamNodes( tb ) + 1; - - while( nodesToAdd-- ) - { - i = CG_AppendBeamNode( tb ); - - if( !tb->nodes->next && CG_Attached( &ts->frontAttachment ) ) - { - // this is the first node to be added - if( !CG_AttachmentPoint( &ts->frontAttachment, i->refPosition ) ) - CG_DestroyTrailSystem( &ts ); - } - else - VectorCopy( i->prev->refPosition, i->refPosition ); - } - } - - numNodes = CG_CountBeamNodes( tb ); - - for( i = tb->nodes; i; i = i->next ) - VectorCopy( i->refPosition, i->position ); - - if( CG_Attached( &ts->frontAttachment ) && CG_Attached( &ts->backAttachment ) ) - { - // beam between two attachments - vec3_t dir, front, back; - - if( ts->destroyTime > 0 && ( cg.time - ts->destroyTime ) >= btb->fadeOutTime ) - { - tb->valid = qfalse; - return; - } - - if( !CG_AttachmentPoint( &ts->frontAttachment, front ) ) - CG_DestroyTrailSystem( &ts ); - - if( !CG_AttachmentPoint( &ts->backAttachment, back ) ) - CG_DestroyTrailSystem( &ts ); - - VectorSubtract( back, front, dir ); - - for( j = 0, i = tb->nodes; i; i = i->next, j++ ) - { - float scale = (float)j / (float)( numNodes - 1 ); - - VectorMA( front, scale, dir, i->position ); - } - } - else if( CG_Attached( &ts->frontAttachment ) ) - { - // beam from one attachment - - // cull the trail tail - i = CG_FindLastBeamNode( tb ); - - if( i && i->timeLeft >= 0 ) - { - i->timeLeft -= deltaTime; - - if( i->timeLeft < 0 ) - { - tb->nodes = CG_DestroyBeamNode( i ); - - if( !tb->nodes ) - { - tb->valid = qfalse; - return; - } - - // if the ts has been destroyed, stop creating new nodes - if( ts->destroyTime <= 0 ) - CG_PrependBeamNode( tb ); - } - else if( i->timeLeft >= 0 && i->prev ) - { - vec3_t dir; - float length; - - VectorSubtract( i->refPosition, i->prev->refPosition, dir ); - length = VectorNormalize( dir ) * - ( (float)i->timeLeft / (float)tb->class->segmentTime ); - - VectorMA( i->prev->refPosition, length, dir, i->position ); - } - } - - if( tb->nodes ) - { - if( !CG_AttachmentPoint( &ts->frontAttachment, tb->nodes->refPosition ) ) - CG_DestroyTrailSystem( &ts ); - - VectorCopy( tb->nodes->refPosition, tb->nodes->position ); - } - } - - CG_ApplyJitters( tb ); -} - -/* -=============== -CG_ParseTrailBeamColor -=============== -*/ -static qboolean CG_ParseTrailBeamColor( byte *c, char **text_p ) -{ - char *token; - int i; - - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( text_p ); - - if( !Q_stricmp( token, "" ) ) - return qfalse; - - c[ i ] = (int)( (float)0xFF * atof_neg( token, qfalse ) ); - } - - return qtrue; -} - -/* -=============== -CG_ParseTrailBeam - -Parse a trail beam -=============== -*/ -static qboolean CG_ParseTrailBeam( baseTrailBeam_t *btb, char **text_p ) -{ - char *token; - - // read optional parameters - while( 1 ) - { - token = COM_Parse( text_p ); - - if( !Q_stricmp( token, "" ) ) - return qfalse; - - if( !Q_stricmp( token, "segments" ) ) - { - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - btb->numSegments = atoi_neg( token, qfalse ); - - if( btb->numSegments >= MAX_TRAIL_BEAM_NODES ) - { - btb->numSegments = MAX_TRAIL_BEAM_NODES - 1; - CG_Printf( S_COLOR_YELLOW "WARNING: too many segments in trail beam\n" ); - } - continue; - } - else if( !Q_stricmp( token, "width" ) ) - { - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - btb->frontWidth = atof_neg( token, qfalse ); - - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - if( !Q_stricmp( token, "-" ) ) - btb->backWidth = btb->frontWidth; - else - btb->backWidth = atof_neg( token, qfalse ); - continue; - } - else if( !Q_stricmp( token, "alpha" ) ) - { - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - btb->frontAlpha = atof_neg( token, qfalse ); - - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - if( !Q_stricmp( token, "-" ) ) - btb->backAlpha = btb->frontAlpha; - else - btb->backAlpha = atof_neg( token, qfalse ); - continue; - } - else if( !Q_stricmp( token, "color" ) ) - { - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - if( !Q_stricmp( token, "{" ) ) - { - if( !CG_ParseTrailBeamColor( btb->frontColor, text_p ) ) - break; - - token = COM_Parse( text_p ); - if( Q_stricmp( token, "}" ) ) - { - CG_Printf( S_COLOR_RED "ERROR: missing '}'\n" ); - break; - } - - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - if( !Q_stricmp( token, "-" ) ) - { - btb->backColor[ 0 ] = btb->frontColor[ 0 ]; - btb->backColor[ 1 ] = btb->frontColor[ 1 ]; - btb->backColor[ 2 ] = btb->frontColor[ 2 ]; - } - else if( !Q_stricmp( token, "{" ) ) - { - if( !CG_ParseTrailBeamColor( btb->backColor, text_p ) ) - break; - - token = COM_Parse( text_p ); - if( Q_stricmp( token, "}" ) ) - { - CG_Printf( S_COLOR_RED "ERROR: missing '}'\n" ); - break; - } - } - else - { - CG_Printf( S_COLOR_RED "ERROR: missing '{'\n" ); - break; - } - } - else - { - CG_Printf( S_COLOR_RED "ERROR: missing '{'\n" ); - break; - } - - continue; - } - else if( !Q_stricmp( token, "segmentTime" ) ) - { - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - btb->segmentTime = atoi_neg( token, qfalse ); - continue; - } - else if( !Q_stricmp( token, "fadeOutTime" ) ) - { - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - btb->fadeOutTime = atoi_neg( token, qfalse ); - continue; - } - else if( !Q_stricmp( token, "shader" ) ) - { - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - Q_strncpyz( btb->shaderName, token, MAX_QPATH ); - - continue; - } - else if( !Q_stricmp( token, "textureType" ) ) - { - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - if( !Q_stricmp( token, "stretch" ) ) - { - btb->textureType = TBTT_STRETCH; - - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - btb->frontTextureCoord = atof_neg( token, qfalse ); - - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - btb->backTextureCoord = atof_neg( token, qfalse ); - } - else if( !Q_stricmp( token, "repeat" ) ) - { - btb->textureType = TBTT_REPEAT; - - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - if( !Q_stricmp( token, "front" ) ) - btb->clampToBack = qfalse; - else if( !Q_stricmp( token, "back" ) ) - btb->clampToBack = qtrue; - else - { - CG_Printf( S_COLOR_RED "ERROR: unknown textureType clamp \"%s\"\n", token ); - break; - } - - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - btb->repeatLength = atof_neg( token, qfalse ); - } - else - { - CG_Printf( S_COLOR_RED "ERROR: unknown textureType \"%s\"\n", token ); - break; - } - - continue; - } - else if( !Q_stricmp( token, "realLight" ) ) - { - btb->realLight = qtrue; - - continue; - } - else if( !Q_stricmp( token, "jitter" ) ) - { - if( btb->numJitters == MAX_TRAIL_BEAM_JITTERS ) - { - CG_Printf( S_COLOR_RED "ERROR: too many jitters\n", token ); - break; - } - - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - btb->jitters[ btb->numJitters ].magnitude = atof_neg( token, qfalse ); - - token = COM_Parse( text_p ); - if( !Q_stricmp( token, "" ) ) - break; - - btb->jitters[ btb->numJitters ].period = atoi_neg( token, qfalse ); - - btb->numJitters++; - - continue; - } - else if( !Q_stricmp( token, "jitterAttachments" ) ) - { - btb->jitterAttachments = qtrue; - - continue; - } - else if( !Q_stricmp( token, "}" ) ) - return qtrue; //reached the end of this trail beam - else - { - CG_Printf( S_COLOR_RED "ERROR: unknown token '%s' in trail beam\n", token ); - return qfalse; - } - } - - return qfalse; -} - -/* -=============== -CG_InitialiseBaseTrailBeam -=============== -*/ -static void CG_InitialiseBaseTrailBeam( baseTrailBeam_t *btb ) -{ - memset( btb, 0, sizeof( baseTrailBeam_t ) ); - - btb->numSegments = 1; - btb->frontWidth = btb->backWidth = 1.0f; - btb->frontAlpha = btb->backAlpha = 1.0f; - memset( btb->frontColor, 0xFF, sizeof( btb->frontColor ) ); - memset( btb->backColor, 0xFF, sizeof( btb->backColor ) ); - - btb->segmentTime = 100; - - btb->textureType = TBTT_STRETCH; - btb->frontTextureCoord = 0.0f; - btb->backTextureCoord = 1.0f; -} - -/* -=============== -CG_ParseTrailSystem - -Parse a trail system section -=============== -*/ -static qboolean CG_ParseTrailSystem( baseTrailSystem_t *bts, char **text_p, const char *name ) -{ - char *token; - - // read optional parameters - while( 1 ) - { - token = COM_Parse( text_p ); - - if( !Q_stricmp( token, "" ) ) - return qfalse; - - if( !Q_stricmp( token, "{" ) ) - { - CG_InitialiseBaseTrailBeam( &baseTrailBeams[ numBaseTrailBeams ] ); - - if( !CG_ParseTrailBeam( &baseTrailBeams[ numBaseTrailBeams ], text_p ) ) - { - CG_Printf( S_COLOR_RED "ERROR: failed to parse trail beam\n" ); - return qfalse; - } - - if( bts->numBeams == MAX_BEAMS_PER_SYSTEM ) - { - CG_Printf( S_COLOR_RED "ERROR: trail system has > %d beams\n", MAX_BEAMS_PER_SYSTEM ); - return qfalse; - } - else if( numBaseTrailBeams == MAX_BASETRAIL_BEAMS ) - { - CG_Printf( S_COLOR_RED "ERROR: maximum number of trail beams (%d) reached\n", - MAX_BASETRAIL_BEAMS ); - return qfalse; - } - else - { - //start parsing beams again - bts->beams[ bts->numBeams ] = &baseTrailBeams[ numBaseTrailBeams ]; - bts->numBeams++; - numBaseTrailBeams++; - } - continue; - } - else if( !Q_stricmp( token, "thirdPersonOnly" ) ) - bts->thirdPersonOnly = qtrue; - else if( !Q_stricmp( token, "beam" ) ) //acceptable text - continue; - else if( !Q_stricmp( token, "}" ) ) - { - if( cg_debugTrails.integer >= 1 ) - CG_Printf( "Parsed trail system %s\n", name ); - - return qtrue; //reached the end of this trail system - } - else - { - CG_Printf( S_COLOR_RED "ERROR: unknown token '%s' in trail system %s\n", token, bts->name ); - return qfalse; - } - } - - return qfalse; -} - -/* -=============== -CG_ParseTrailFile - -Load the trail systems from a trail file -=============== -*/ -static qboolean CG_ParseTrailFile( const char *fileName ) -{ - char *text_p; - int i; - int len; - char *token; - char text[ 32000 ]; - char tsName[ MAX_QPATH ]; - qboolean tsNameSet = qfalse; - fileHandle_t f; - - // load the file - len = trap_FS_FOpenFile( fileName, &f, FS_READ ); - if( len <= 0 ) - return qfalse; - - if( len >= sizeof( text ) - 1 ) - { - CG_Printf( S_COLOR_RED "ERROR: trail file %s too long\n", fileName ); - return qfalse; - } - - trap_FS_Read( text, len, f ); - text[ len ] = 0; - trap_FS_FCloseFile( f ); - - // parse the text - text_p = text; - - // read optional parameters - while( 1 ) - { - token = COM_Parse( &text_p ); - - if( !Q_stricmp( token, "" ) ) - break; - - if( !Q_stricmp( token, "{" ) ) - { - if( tsNameSet ) - { - //check for name space clashes - for( i = 0; i < numBaseTrailSystems; i++ ) - { - if( !Q_stricmp( baseTrailSystems[ i ].name, tsName ) ) - { - CG_Printf( S_COLOR_RED "ERROR: a trail system is already named %s\n", tsName ); - return qfalse; - } - } - - Q_strncpyz( baseTrailSystems[ numBaseTrailSystems ].name, tsName, MAX_QPATH ); - - if( !CG_ParseTrailSystem( &baseTrailSystems[ numBaseTrailSystems ], &text_p, tsName ) ) - { - CG_Printf( S_COLOR_RED "ERROR: %s: failed to parse trail system %s\n", fileName, tsName ); - return qfalse; - } - - //start parsing trail systems again - tsNameSet = qfalse; - - if( numBaseTrailSystems == MAX_BASETRAIL_SYSTEMS ) - { - CG_Printf( S_COLOR_RED "ERROR: maximum number of trail systems (%d) reached\n", - MAX_BASETRAIL_SYSTEMS ); - return qfalse; - } - else - numBaseTrailSystems++; - - continue; - } - else - { - CG_Printf( S_COLOR_RED "ERROR: unamed trail system\n" ); - return qfalse; - } - } - - if( !tsNameSet ) - { - Q_strncpyz( tsName, token, sizeof( tsName ) ); - tsNameSet = qtrue; - } - else - { - CG_Printf( S_COLOR_RED "ERROR: trail system already named\n" ); - return qfalse; - } - } - - return qtrue; -} - -/* -=============== -CG_LoadTrailSystems - -Load trail system templates -=============== -*/ -void CG_LoadTrailSystems( void ) -{ - int i; - /*const char *s[ MAX_TRAIL_FILES ];*/ - - //clear out the old - numBaseTrailSystems = 0; - numBaseTrailBeams = 0; - - for( i = 0; i < MAX_BASETRAIL_SYSTEMS; i++ ) - { - baseTrailSystem_t *bts = &baseTrailSystems[ i ]; - memset( bts, 0, sizeof( baseTrailSystem_t ) ); - } - - for( i = 0; i < MAX_BASETRAIL_BEAMS; i++ ) - { - baseTrailBeam_t *btb = &baseTrailBeams[ i ]; - memset( btb, 0, sizeof( baseTrailBeam_t ) ); - } - - //and bring in the new -/* for( i = 0; i < MAX_TRAIL_FILES; i++ ) - { - s[ i ] = CG_ConfigString( CS_TRAIL_FILES + i ); - - if( strlen( s[ i ] ) > 0 ) - { - CG_Printf( "...loading '%s'\n", s[ i ] ); - CG_ParseTrailFile( s[ i ] ); - } - else - break; - }*/ - CG_Printf( "trail.trail: %d\n", CG_ParseTrailFile( "scripts/trail.trail" ) ); -} - -/* -=============== -CG_RegisterTrailSystem - -Load the media that a trail system needs -=============== -*/ -qhandle_t CG_RegisterTrailSystem( char *name ) -{ - int i, j; - baseTrailSystem_t *bts; - baseTrailBeam_t *btb; - - for( i = 0; i < MAX_BASETRAIL_SYSTEMS; i++ ) - { - bts = &baseTrailSystems[ i ]; - - if( !Q_stricmp( bts->name, name ) ) - { - //already registered - if( bts->registered ) - return i + 1; - - for( j = 0; j < bts->numBeams; j++ ) - { - btb = bts->beams[ j ]; - - btb->shader = trap_R_RegisterShader( btb->shaderName ); - } - - if( cg_debugTrails.integer >= 1 ) - CG_Printf( "Registered trail system %s\n", name ); - - bts->registered = qtrue; - - //avoid returning 0 - return i + 1; - } - } - - CG_Printf( S_COLOR_RED "ERROR: failed to register trail system %s\n", name ); - return 0; -} - - -/* -=============== -CG_SpawnNewTrailBeam - -Allocate a new trail beam -=============== -*/ -static trailBeam_t *CG_SpawnNewTrailBeam( baseTrailBeam_t *btb, - trailSystem_t *parent ) -{ - int i; - trailBeam_t *tb = NULL; - trailSystem_t *ts = parent; - - for( i = 0; i < MAX_TRAIL_BEAMS; i++ ) - { - tb = &trailBeams[ i ]; - - if( !tb->valid ) - { - memset( tb, 0, sizeof( trailBeam_t ) ); - - //found a free slot - tb->class = btb; - tb->parent = ts; - - tb->valid = qtrue; - - if( cg_debugTrails.integer >= 1 ) - CG_Printf( "TB %s created\n", ts->class->name ); - - break; - } - } - - return tb; -} - - -/* -=============== -CG_SpawnNewTrailSystem - -Spawns a new trail system -=============== -*/ -trailSystem_t *CG_SpawnNewTrailSystem( qhandle_t psHandle ) -{ - int i, j; - trailSystem_t *ts = NULL; - baseTrailSystem_t *bts = &baseTrailSystems[ psHandle - 1 ]; - - if( !bts->registered ) - { - CG_Printf( S_COLOR_RED "ERROR: a trail system has not been registered yet\n" ); - return NULL; - } - - for( i = 0; i < MAX_TRAIL_SYSTEMS; i++ ) - { - ts = &trailSystems[ i ]; - - if( !ts->valid ) - { - memset( ts, 0, sizeof( trailSystem_t ) ); - - //found a free slot - ts->class = bts; - - ts->valid = qtrue; - ts->destroyTime = -1; - - for( j = 0; j < bts->numBeams; j++ ) - CG_SpawnNewTrailBeam( bts->beams[ j ], ts ); - - if( cg_debugTrails.integer >= 1 ) - CG_Printf( "TS %s created\n", bts->name ); - - break; - } - } - - return ts; -} - -/* -=============== -CG_DestroyTrailSystem - -Destroy a trail system -=============== -*/ -void CG_DestroyTrailSystem( trailSystem_t **ts ) -{ - (*ts)->destroyTime = cg.time; - - if( CG_Attached( &(*ts)->frontAttachment ) && - !CG_Attached( &(*ts)->backAttachment ) ) - { - vec3_t v; - - // attach the trail head to a static point - CG_AttachmentPoint( &(*ts)->frontAttachment, v ); - CG_SetAttachmentPoint( &(*ts)->frontAttachment, v ); - CG_AttachToPoint( &(*ts)->frontAttachment ); - - (*ts)->frontAttachment.centValid = qfalse; // a bit naughty - } - - ts = NULL; -} - -/* -=============== -CG_IsTrailSystemValid - -Test a trail system for validity -=============== -*/ -qboolean CG_IsTrailSystemValid( trailSystem_t **ts ) -{ - if( *ts == NULL || ( *ts && !(*ts)->valid ) ) - { - if( *ts && !(*ts)->valid ) - *ts = NULL; - - return qfalse; - } - - return qtrue; -} - -/* -=============== -CG_GarbageCollectTrailSystems - -Destroy inactive trail systems -=============== -*/ -static void CG_GarbageCollectTrailSystems( void ) -{ - int i, j, count; - trailSystem_t *ts; - trailBeam_t *tb; - int centNum; - - for( i = 0; i < MAX_TRAIL_SYSTEMS; i++ ) - { - ts = &trailSystems[ i ]; - count = 0; - - //don't bother checking already invalid systems - if( !ts->valid ) - continue; - - for( j = 0; j < MAX_TRAIL_BEAMS; j++ ) - { - tb = &trailBeams[ j ]; - - if( tb->valid && tb->parent == ts ) - count++; - } - - if( !count ) - ts->valid = qfalse; - - //check systems where the parent cent has left the PVS - //( local player entity is always valid ) - if( ( centNum = CG_AttachmentCentNum( &ts->frontAttachment ) ) >= 0 && - centNum != cg.snap->ps.clientNum ) - { - trailSystem_t *tempTS = ts; - - if( !cg_entities[ centNum ].valid ) - CG_DestroyTrailSystem( &tempTS ); - } - - if( ( centNum = CG_AttachmentCentNum( &ts->backAttachment ) ) >= 0 && - centNum != cg.snap->ps.clientNum ) - { - trailSystem_t *tempTS = ts; - - if( !cg_entities[ centNum ].valid ) - CG_DestroyTrailSystem( &tempTS ); - } - - if( cg_debugTrails.integer >= 1 && !ts->valid ) - CG_Printf( "TS %s garbage collected\n", ts->class->name ); - } -} - -/* -=============== -CG_AddTrails - -Add trails to the scene -=============== -*/ -void CG_AddTrails( void ) -{ - int i; - trailBeam_t *tb; - int numTS = 0, numTB = 0; - - //remove expired trail systems - CG_GarbageCollectTrailSystems( ); - - for( i = 0; i < MAX_TRAIL_BEAMS; i++ ) - { - tb = &trailBeams[ i ]; - - if( tb->valid ) - { - CG_UpdateBeam( tb ); - CG_RenderBeam( tb ); - } - } - - if( cg_debugTrails.integer >= 2 ) - { - for( i = 0; i < MAX_TRAIL_SYSTEMS; i++ ) - if( trailSystems[ i ].valid ) - numTS++; - - for( i = 0; i < MAX_TRAIL_BEAMS; i++ ) - if( trailBeams[ i ].valid ) - numTB++; - - CG_Printf( "TS: %d TB: %d\n", numTS, numTB ); - } -} - -static trailSystem_t *testTS; -static qhandle_t testTSHandle; - -/* -=============== -CG_DestroyTestTS_f - -Destroy the test a trail system -=============== -*/ -void CG_DestroyTestTS_f( void ) -{ - if( CG_IsTrailSystemValid( &testTS ) ) - CG_DestroyTrailSystem( &testTS ); -} - -/* -=============== -CG_TestTS_f - -Test a trail system -=============== -*/ -void CG_TestTS_f( void ) -{ - char tsName[ MAX_QPATH ]; - - if( trap_Argc( ) < 2 ) - return; - - Q_strncpyz( tsName, CG_Argv( 1 ), MAX_QPATH ); - testTSHandle = CG_RegisterTrailSystem( tsName ); - - if( testTSHandle ) - { - CG_DestroyTestTS_f( ); - - testTS = CG_SpawnNewTrailSystem( testTSHandle ); - - if( CG_IsTrailSystemValid( &testTS ) ) - { - CG_SetAttachmentCent( &testTS->frontAttachment, &cg_entities[ 0 ] ); - CG_AttachToCent( &testTS->frontAttachment ); - } - } -} diff --git a/src/cgame/cg_view.c b/src/cgame/cg_view.c deleted file mode 100644 index 324646c9..00000000 --- a/src/cgame/cg_view.c +++ /dev/null @@ -1,1330 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_view.c -- setup all the parameters (position, angle, etc) -// for a 3D rendering - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - - -/* -============================================================================= - - MODEL TESTING - -The viewthing and gun positioning tools from Q2 have been integrated and -enhanced into a single model testing facility. - -Model viewing can begin with either "testmodel " or "testgun ". - -The names must be the full pathname after the basedir, like -"models/weapons/v_launch/tris.md3" or "players/male/tris.md3" - -Testmodel will create a fake entity 100 units in front of the current view -position, directly facing the viewer. It will remain immobile, so you can -move around it to view it from different angles. - -Testgun will cause the model to follow the player around and supress the real -view weapon model. The default frame 0 of most guns is completely off screen, -so you will probably have to cycle a couple frames to see it. - -"nextframe", "prevframe", "nextskin", and "prevskin" commands will change the -frame or skin of the testmodel. These are bound to F5, F6, F7, and F8 in -q3default.cfg. - -If a gun is being tested, the "gun_x", "gun_y", and "gun_z" variables will let -you adjust the positioning. - -Note that none of the model testing features update while the game is paused, so -it may be convenient to test with deathmatch set to 1 so that bringing down the -console doesn't pause the game. - -============================================================================= -*/ - -/* -================= -CG_TestModel_f - -Creates an entity in front of the current position, which -can then be moved around -================= -*/ -void CG_TestModel_f( void ) -{ - vec3_t angles; - - memset( &cg.testModelEntity, 0, sizeof( cg.testModelEntity ) ); - memset( &cg.testModelBarrelEntity, 0, sizeof( cg.testModelBarrelEntity ) ); - - if( trap_Argc( ) < 2 ) - return; - - Q_strncpyz( cg.testModelName, CG_Argv( 1 ), MAX_QPATH ); - cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName ); - - Q_strncpyz( cg.testModelBarrelName, CG_Argv( 1 ), MAX_QPATH ); - cg.testModelBarrelName[ strlen( cg.testModelBarrelName ) - 4 ] = '\0'; - Q_strcat( cg.testModelBarrelName, MAX_QPATH, "_barrel.md3" ); - cg.testModelBarrelEntity.hModel = trap_R_RegisterModel( cg.testModelBarrelName ); - - if( trap_Argc( ) == 3 ) - { - cg.testModelEntity.backlerp = atof( CG_Argv( 2 ) ); - cg.testModelEntity.frame = 1; - cg.testModelEntity.oldframe = 0; - } - - if( !cg.testModelEntity.hModel ) - { - CG_Printf( "Can't register model\n" ); - return; - } - - VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[ 0 ], cg.testModelEntity.origin ); - - angles[ PITCH ] = 0; - angles[ YAW ] = 180 + cg.refdefViewAngles[ 1 ]; - angles[ ROLL ] = 0; - - AnglesToAxis( angles, cg.testModelEntity.axis ); - cg.testGun = qfalse; - - if( cg.testModelBarrelEntity.hModel ) - { - angles[ YAW ] = 0; - angles[ PITCH ] = 0; - angles[ ROLL ] = 0; - AnglesToAxis( angles, cg.testModelBarrelEntity.axis ); - } -} - -/* -================= -CG_TestGun_f - -Replaces the current view weapon with the given model -================= -*/ -void CG_TestGun_f( void ) -{ - CG_TestModel_f( ); - cg.testGun = qtrue; - cg.testModelEntity.renderfx = RF_MINLIGHT | RF_DEPTHHACK | RF_FIRST_PERSON; -} - - -void CG_TestModelNextFrame_f( void ) -{ - cg.testModelEntity.frame++; - CG_Printf( "frame %i\n", cg.testModelEntity.frame ); -} - -void CG_TestModelPrevFrame_f( void ) -{ - cg.testModelEntity.frame--; - - if( cg.testModelEntity.frame < 0 ) - cg.testModelEntity.frame = 0; - - CG_Printf( "frame %i\n", cg.testModelEntity.frame ); -} - -void CG_TestModelNextSkin_f( void ) -{ - cg.testModelEntity.skinNum++; - CG_Printf( "skin %i\n", cg.testModelEntity.skinNum ); -} - -void CG_TestModelPrevSkin_f( void ) -{ - cg.testModelEntity.skinNum--; - - if( cg.testModelEntity.skinNum < 0 ) - cg.testModelEntity.skinNum = 0; - - CG_Printf( "skin %i\n", cg.testModelEntity.skinNum ); -} - -static void CG_AddTestModel( void ) -{ - int i; - - // re-register the model, because the level may have changed - cg.testModelEntity.hModel = trap_R_RegisterModel( cg.testModelName ); - cg.testModelBarrelEntity.hModel = trap_R_RegisterModel( cg.testModelBarrelName ); - - if( !cg.testModelEntity.hModel ) - { - CG_Printf( "Can't register model\n" ); - return; - } - - // if testing a gun, set the origin reletive to the view origin - if( cg.testGun ) - { - VectorCopy( cg.refdef.vieworg, cg.testModelEntity.origin ); - VectorCopy( cg.refdef.viewaxis[ 0 ], cg.testModelEntity.axis[ 0 ] ); - VectorCopy( cg.refdef.viewaxis[ 1 ], cg.testModelEntity.axis[ 1 ] ); - VectorCopy( cg.refdef.viewaxis[ 2 ], cg.testModelEntity.axis[ 2 ] ); - - // allow the position to be adjusted - for( i = 0; i < 3; i++ ) - { - cg.testModelEntity.origin[ i ] += cg.refdef.viewaxis[ 0 ][ i ] * cg_gun_x.value; - cg.testModelEntity.origin[ i ] += cg.refdef.viewaxis[ 1 ][ i ] * cg_gun_y.value; - cg.testModelEntity.origin[ i ] += cg.refdef.viewaxis[ 2 ][ i ] * cg_gun_z.value; - } - } - - trap_R_AddRefEntityToScene( &cg.testModelEntity ); - - if( cg.testModelBarrelEntity.hModel ) - { - CG_PositionEntityOnTag( &cg.testModelBarrelEntity, &cg.testModelEntity, - cg.testModelEntity.hModel, "tag_barrel" ); - - trap_R_AddRefEntityToScene( &cg.testModelBarrelEntity ); - } -} - - - -//============================================================================ - - -/* -================= -CG_CalcVrect - -Sets the coordinates of the rendered window -================= -*/ -static void CG_CalcVrect( void ) -{ - int size; - - // the intermission should allways be full screen - if( cg.snap->ps.pm_type == PM_INTERMISSION ) - size = 100; - else - { - // bound normal viewsize - if( cg_viewsize.integer < 30 ) - { - trap_Cvar_Set( "cg_viewsize", "30" ); - size = 30; - } - else if( cg_viewsize.integer > 100 ) - { - trap_Cvar_Set( "cg_viewsize","100" ); - size = 100; - } - else - size = cg_viewsize.integer; - } - - cg.refdef.width = cgs.glconfig.vidWidth * size / 100; - cg.refdef.width &= ~1; - - cg.refdef.height = cgs.glconfig.vidHeight * size / 100; - cg.refdef.height &= ~1; - - cg.refdef.x = ( cgs.glconfig.vidWidth - cg.refdef.width ) / 2; - cg.refdef.y = ( cgs.glconfig.vidHeight - cg.refdef.height ) / 2; -} - -//============================================================================== - - -/* -=============== -CG_OffsetThirdPersonView - -=============== -*/ -#define FOCUS_DISTANCE 512 -static void CG_OffsetThirdPersonView( void ) -{ - vec3_t forward, right, up; - vec3_t view; - vec3_t focusAngles; - trace_t trace; - static vec3_t mins = { -8, -8, -8 }; - static vec3_t maxs = { 8, 8, 8 }; - vec3_t focusPoint; - float focusDist; - float forwardScale, sideScale; - vec3_t surfNormal; - - if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) - { - if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) - VectorSet( surfNormal, 0.0f, 0.0f, -1.0f ); - else - VectorCopy( cg.predictedPlayerState.grapplePoint, surfNormal ); - } - else - VectorSet( surfNormal, 0.0f, 0.0f, 1.0f ); - - VectorMA( cg.refdef.vieworg, cg.predictedPlayerState.viewheight, surfNormal, cg.refdef.vieworg ); - - VectorCopy( cg.refdefViewAngles, focusAngles ); - - // if dead, look at killer - if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 ) - { - focusAngles[ YAW ] = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ]; - cg.refdefViewAngles[ YAW ] = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ]; - } - - //if ( focusAngles[PITCH] > 45 ) { - // focusAngles[PITCH] = 45; // don't go too far overhead - //} - AngleVectors( focusAngles, forward, NULL, NULL ); - - VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint ); - - VectorCopy( cg.refdef.vieworg, view ); - - VectorMA( view, 12, surfNormal, view ); - - //cg.refdefViewAngles[PITCH] *= 0.5; - - AngleVectors( cg.refdefViewAngles, forward, right, up ); - - forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI ); - sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI ); - VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view ); - VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view ); - - // trace a ray from the origin to the viewpoint to make sure the view isn't - // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything - - if( !cg_cameraMode.integer ) - { - CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID ); - - if( trace.fraction != 1.0 ) - { - VectorCopy( trace.endpos, view ); - view[ 2 ] += ( 1.0 - trace.fraction ) * 32; - // try another trace to this position, because a tunnel may have the ceiling - // close enogh that this is poking out - - CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID ); - VectorCopy( trace.endpos, view ); - } - } - - VectorCopy( view, cg.refdef.vieworg ); - - // select pitch to look at focus point from vieword - VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint ); - focusDist = sqrt( focusPoint[ 0 ] * focusPoint[ 0 ] + focusPoint[ 1 ] * focusPoint[ 1 ] ); - if ( focusDist < 1 ) { - focusDist = 1; // should never happen - } - cg.refdefViewAngles[ PITCH ] = -180 / M_PI * atan2( focusPoint[ 2 ], focusDist ); - cg.refdefViewAngles[ YAW ] -= cg_thirdPersonAngle.value; -} - - -// this causes a compiler bug on mac MrC compiler -static void CG_StepOffset( void ) -{ - float steptime; - int timeDelta; - vec3_t normal; - playerState_t *ps = &cg.predictedPlayerState; - - if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) - { - if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) - VectorSet( normal, 0.0f, 0.0f, -1.0f ); - else - VectorCopy( ps->grapplePoint, normal ); - } - else - VectorSet( normal, 0.0f, 0.0f, 1.0f ); - - steptime = BG_FindSteptimeForClass( ps->stats[ STAT_PCLASS ] ); - - // smooth out stair climbing - timeDelta = cg.time - cg.stepTime; - if( timeDelta < steptime ) - { - float stepChange = cg.stepChange - * (steptime - timeDelta) / steptime; - - if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) - VectorMA( cg.refdef.vieworg, -stepChange, normal, cg.refdef.vieworg ); - else - cg.refdef.vieworg[ 2 ] -= stepChange; - } -} - -#define PCLOUD_ROLL_AMPLITUDE 25.0f -#define PCLOUD_ROLL_FREQUENCY 0.4f -#define PCLOUD_ZOOM_AMPLITUDE 15 -#define PCLOUD_ZOOM_FREQUENCY 0.7f - - -/* -=============== -CG_OffsetFirstPersonView - -=============== -*/ -static void CG_OffsetFirstPersonView( void ) -{ - float *origin; - float *angles; - float bob; - float ratio; - float delta; - float speed; - float f; - vec3_t predictedVelocity; - int timeDelta; - float bob2; - vec3_t normal, baseOrigin; - playerState_t *ps = &cg.predictedPlayerState; - - if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) - { - if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) - VectorSet( normal, 0.0f, 0.0f, -1.0f ); - else - VectorCopy( ps->grapplePoint, normal ); - } - else - VectorSet( normal, 0.0f, 0.0f, 1.0f ); - - - if( cg.snap->ps.pm_type == PM_INTERMISSION ) - return; - - origin = cg.refdef.vieworg; - angles = cg.refdefViewAngles; - - VectorCopy( origin, baseOrigin ); - - // if dead, fix the angle and don't add any kick - if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ) - { - angles[ ROLL ] = 40; - angles[ PITCH ] = -15; - angles[ YAW ] = cg.snap->ps.stats[ STAT_VIEWLOCK ]; - origin[ 2 ] += cg.predictedPlayerState.viewheight; - return; - } - - // add angles based on weapon kick - VectorAdd( angles, cg.kick_angles, angles ); - - // add angles based on damage kick - if( cg.damageTime ) - { - ratio = cg.time - cg.damageTime; - if( ratio < DAMAGE_DEFLECT_TIME ) - { - ratio /= DAMAGE_DEFLECT_TIME; - angles[ PITCH ] += ratio * cg.v_dmg_pitch; - angles[ ROLL ] += ratio * cg.v_dmg_roll; - } - else - { - ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME; - if( ratio > 0 ) - { - angles[ PITCH ] += ratio * cg.v_dmg_pitch; - angles[ ROLL ] += ratio * cg.v_dmg_roll; - } - } - } - - // add pitch based on fall kick -#if 0 - ratio = ( cg.time - cg.landTime) / FALL_TIME; - if (ratio < 0) - ratio = 0; - angles[PITCH] += ratio * cg.fall_value; -#endif - - // add angles based on velocity - VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity ); - - delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 0 ] ); - angles[ PITCH ] += delta * cg_runpitch.value; - - delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 1 ] ); - angles[ ROLL ] -= delta * cg_runroll.value; - - // add angles based on bob - //TA: bob amount is class dependant - - if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) - bob2 = 0.0f; - else - bob2 = BG_FindBobForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] ); - - -#define LEVEL4_FEEDBACK 10.0f - - //give a charging player some feedback - if( ps->weapon == WP_ALEVEL4 ) - { - if( ps->stats[ STAT_MISC ] > 0 ) - { - float fraction = (float)ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME; - - if( fraction > 1.0f ) - fraction = 1.0f; - - bob2 *= ( 1.0f + fraction * LEVEL4_FEEDBACK ); - } - } - - if( bob2 != 0.0f ) - { - // make sure the bob is visible even at low speeds - speed = cg.xyspeed > 200 ? cg.xyspeed : 200; - - delta = cg.bobfracsin * ( bob2 ) * speed; - if( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) - delta *= 3; // crouching - - angles[ PITCH ] += delta; - delta = cg.bobfracsin * ( bob2 ) * speed; - if( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) - delta *= 3; // crouching accentuates roll - - if( cg.bobcycle & 1 ) - delta = -delta; - - angles[ ROLL ] += delta; - } - -#define LEVEL3_FEEDBACK 20.0f - - //provide some feedback for pouncing - if( cg.predictedPlayerState.weapon == WP_ALEVEL3 || - cg.predictedPlayerState.weapon == WP_ALEVEL3_UPG ) - { - if( cg.predictedPlayerState.stats[ STAT_MISC ] > 0 ) - { - float fraction1, fraction2; - vec3_t forward; - - AngleVectors( angles, forward, NULL, NULL ); - VectorNormalize( forward ); - - fraction1 = (float)( cg.time - cg.weapon2Time ) / (float)LEVEL3_POUNCE_CHARGE_TIME; - - if( fraction1 > 1.0f ) - fraction1 = 1.0f; - - fraction2 = -sin( fraction1 * M_PI / 2 ); - - VectorMA( origin, LEVEL3_FEEDBACK * fraction2, forward, origin ); - } - } - -#define STRUGGLE_DIST 5.0f -#define STRUGGLE_TIME 250 - - //allow the player to struggle a little whilst grabbed - if( cg.predictedPlayerState.pm_type == PM_GRABBED ) - { - vec3_t forward, right, up; - usercmd_t cmd; - int cmdNum; - float fFraction, rFraction, uFraction; - float fFraction2, rFraction2, uFraction2; - - cmdNum = trap_GetCurrentCmdNumber(); - trap_GetUserCmd( cmdNum, &cmd ); - - AngleVectors( angles, forward, right, up ); - - fFraction = (float)( cg.time - cg.forwardMoveTime ) / STRUGGLE_TIME; - rFraction = (float)( cg.time - cg.rightMoveTime ) / STRUGGLE_TIME; - uFraction = (float)( cg.time - cg.upMoveTime ) / STRUGGLE_TIME; - - if( fFraction > 1.0f ) - fFraction = 1.0f; - if( rFraction > 1.0f ) - rFraction = 1.0f; - if( uFraction > 1.0f ) - uFraction = 1.0f; - - fFraction2 = -sin( fFraction * M_PI / 2 ); - rFraction2 = -sin( rFraction * M_PI / 2 ); - uFraction2 = -sin( uFraction * M_PI / 2 ); - - if( cmd.forwardmove > 0 ) - VectorMA( origin, STRUGGLE_DIST * fFraction, forward, origin ); - else if( cmd.forwardmove < 0 ) - VectorMA( origin, -STRUGGLE_DIST * fFraction, forward, origin ); - else - cg.forwardMoveTime = cg.time; - - if( cmd.rightmove > 0 ) - VectorMA( origin, STRUGGLE_DIST * rFraction, right, origin ); - else if( cmd.rightmove < 0 ) - VectorMA( origin, -STRUGGLE_DIST * rFraction, right, origin ); - else - cg.rightMoveTime = cg.time; - - if( cmd.upmove > 0 ) - VectorMA( origin, STRUGGLE_DIST * uFraction, up, origin ); - else if( cmd.upmove < 0 ) - VectorMA( origin, -STRUGGLE_DIST * uFraction, up, origin ); - else - cg.upMoveTime = cg.time; - } - - if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED && - !( cg.snap->ps.pm_flags & PMF_FOLLOW ) ) - { - float fraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 2 * PCLOUD_ROLL_FREQUENCY ); - float pitchFraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 5 * PCLOUD_ROLL_FREQUENCY ); - - fraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME ); - pitchFraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME ); - - angles[ ROLL ] += fraction * PCLOUD_ROLL_AMPLITUDE; - angles[ YAW ] += fraction * PCLOUD_ROLL_AMPLITUDE; - angles[ PITCH ] += pitchFraction * PCLOUD_ROLL_AMPLITUDE / 2.0f; - } - - //TA: this *feels* more realisitic for humans - if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - angles[PITCH] += cg.bobfracsin * bob2 * 0.5; - - //TA: heavy breathing effects //FIXME: sound - if( cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 ) - { - float deltaBreath = (float)( - cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 ? - -cg.predictedPlayerState.stats[ STAT_STAMINA ] : - cg.predictedPlayerState.stats[ STAT_STAMINA ] ) / 200.0; - float deltaAngle = cos( (float)cg.time/150.0 ) * deltaBreath; - - deltaAngle += ( deltaAngle < 0 ? -deltaAngle : deltaAngle ) * 0.5; - - angles[ PITCH ] -= deltaAngle; - } - } - -//=================================== - - // add view height - //TA: when wall climbing the viewheight is not straight up - if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) - VectorMA( origin, ps->viewheight, normal, origin ); - else - origin[ 2 ] += cg.predictedPlayerState.viewheight; - - // smooth out duck height changes - timeDelta = cg.time - cg.duckTime; - if( timeDelta < DUCK_TIME) - { - cg.refdef.vieworg[ 2 ] -= cg.duckChange - * ( DUCK_TIME - timeDelta ) / DUCK_TIME; - } - - // add bob height - bob = cg.bobfracsin * cg.xyspeed * bob2; - - if( bob > 6 ) - bob = 6; - - //TA: likewise for bob - if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) - VectorMA( origin, bob, normal, origin ); - else - origin[ 2 ] += bob; - - - // add fall height - delta = cg.time - cg.landTime; - - if( delta < LAND_DEFLECT_TIME ) - { - f = delta / LAND_DEFLECT_TIME; - cg.refdef.vieworg[ 2 ] += cg.landChange * f; - } - else if( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) - { - delta -= LAND_DEFLECT_TIME; - f = 1.0 - ( delta / LAND_RETURN_TIME ); - cg.refdef.vieworg[ 2 ] += cg.landChange * f; - } - - // add step offset - CG_StepOffset( ); - - // add kick offset - - VectorAdd (origin, cg.kick_origin, origin); -} - -//====================================================================== - -void CG_ZoomDown_f( void ) -{ - if( cg.zoomed ) - return; - - cg.zoomed = qtrue; - cg.zoomTime = cg.time; -} - -void CG_ZoomUp_f( void ) -{ - if( !cg.zoomed ) - return; - - cg.zoomed = qfalse; - cg.zoomTime = cg.time; -} - - -/* -==================== -CG_CalcFov - -Fixed fov at intermissions, otherwise account for fov variable and zooms. -==================== -*/ -#define WAVE_AMPLITUDE 1 -#define WAVE_FREQUENCY 0.4 - -#define FOVWARPTIME 400.0 - -static int CG_CalcFov( void ) -{ - float x; - float phase; - float v; - int contents; - float fov_x, fov_y; - float zoomFov; - float f; - int inwater; - int attribFov; - - if( cg.predictedPlayerState.pm_type == PM_INTERMISSION || - ( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) ) - { - // if in intermission, use a fixed value - fov_x = 90; - } - else - { - //TA: don't lock the fov globally - we need to be able to change it - attribFov = BG_FindFovForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] ); - fov_x = attribFov; - - if ( fov_x < 1 ) - fov_x = 1; - else if ( fov_x > 160 ) - fov_x = 160; - - if( cg.spawnTime > ( cg.time - FOVWARPTIME ) && - BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_PCLASS ], SCA_FOVWARPS ) ) - { - float temp, temp2; - - temp = (float)( cg.time - cg.spawnTime ) / FOVWARPTIME; - temp2 = ( 180 - fov_x ) * temp; - - //Com_Printf( "%f %f\n", temp*100, temp2*100 ); - - fov_x = 180 - temp2; - } - - // account for zooms - zoomFov = BG_FindZoomFovForWeapon( cg.predictedPlayerState.weapon ); - if ( zoomFov < 1 ) - zoomFov = 1; - else if ( zoomFov > attribFov ) - zoomFov = attribFov; - - //TA: only do all the zoom stuff if the client CAN zoom - if( BG_WeaponCanZoom( cg.predictedPlayerState.weapon ) ) - { - if ( cg.zoomed ) - { - f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME; - - if ( f > 1.0 ) - fov_x = zoomFov; - else - fov_x = fov_x + f * ( zoomFov - fov_x ); - } - else - { - f = ( cg.time - cg.zoomTime ) / (float)ZOOM_TIME; - - if ( f > 1.0 ) - fov_x = fov_x; - else - fov_x = zoomFov + f * ( fov_x - zoomFov ); - } - } - } - - x = cg.refdef.width / tan( fov_x / 360 * M_PI ); - fov_y = atan2( cg.refdef.height, x ); - fov_y = fov_y * 360 / M_PI; - - // warp if underwater - contents = CG_PointContents( cg.refdef.vieworg, -1 ); - - if( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) - { - phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2; - v = WAVE_AMPLITUDE * sin( phase ); - fov_x += v; - fov_y -= v; - inwater = qtrue; - } - else - inwater = qfalse; - - if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED && - cg.predictedPlayerState.stats[ STAT_HEALTH ] > 0 && - !( cg.snap->ps.pm_flags & PMF_FOLLOW ) ) - { - phase = cg.time / 1000.0 * PCLOUD_ZOOM_FREQUENCY * M_PI * 2; - v = PCLOUD_ZOOM_AMPLITUDE * sin( phase ); - v *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME ); - fov_x += v; - fov_y += v; - } - - - // set it - cg.refdef.fov_x = fov_x; - cg.refdef.fov_y = fov_y; - - if( !cg.zoomed ) - cg.zoomSensitivity = 1; - else - cg.zoomSensitivity = cg.refdef.fov_y / 75.0; - - return inwater; -} - - - -#define NORMAL_HEIGHT 64.0f -#define NORMAL_WIDTH 6.0f - -/* -=============== -CG_DrawSurfNormal - -Draws a vector against -the surface player is looking at -=============== -*/ -static void CG_DrawSurfNormal( void ) -{ - trace_t tr; - vec3_t end, temp; - polyVert_t normal[ 4 ]; - vec4_t color = { 0.0f, 255.0f, 0.0f, 128.0f }; - - VectorMA( cg.refdef.vieworg, 8192, cg.refdef.viewaxis[ 0 ], end ); - - CG_Trace( &tr, cg.refdef.vieworg, NULL, NULL, end, cg.predictedPlayerState.clientNum, MASK_SOLID ); - - VectorCopy( tr.endpos, normal[ 0 ].xyz ); - normal[ 0 ].st[ 0 ] = 0; - normal[ 0 ].st[ 1 ] = 0; - Vector4Copy( color, normal[ 0 ].modulate ); - - VectorMA( tr.endpos, NORMAL_WIDTH, cg.refdef.viewaxis[ 1 ], temp ); - VectorCopy( temp, normal[ 1 ].xyz); - normal[ 1 ].st[ 0 ] = 0; - normal[ 1 ].st[ 1 ] = 1; - Vector4Copy( color, normal[ 1 ].modulate ); - - VectorMA( tr.endpos, NORMAL_HEIGHT, tr.plane.normal, temp ); - VectorMA( temp, NORMAL_WIDTH, cg.refdef.viewaxis[ 1 ], temp ); - VectorCopy( temp, normal[ 2 ].xyz ); - normal[ 2 ].st[ 0 ] = 1; - normal[ 2 ].st[ 1 ] = 1; - Vector4Copy( color, normal[ 2 ].modulate ); - - VectorMA( tr.endpos, NORMAL_HEIGHT, tr.plane.normal, temp ); - VectorCopy( temp, normal[ 3 ].xyz ); - normal[ 3 ].st[ 0 ] = 1; - normal[ 3 ].st[ 1 ] = 0; - Vector4Copy( color, normal[ 3 ].modulate ); - - trap_R_AddPolyToScene( cgs.media.outlineShader, 4, normal ); -} - -/* -=============== -CG_addSmoothOp -=============== -*/ -void CG_addSmoothOp( vec3_t rotAxis, float rotAngle, float timeMod ) -{ - int i; - - //iterate through smooth array - for( i = 0; i < MAXSMOOTHS; i++ ) - { - //found an unused index in the smooth array - if( cg.sList[ i ].time + cg_wwSmoothTime.integer < cg.time ) - { - //copy to array and stop - VectorCopy( rotAxis, cg.sList[ i ].rotAxis ); - cg.sList[ i ].rotAngle = rotAngle; - cg.sList[ i ].time = cg.time; - cg.sList[ i ].timeMod = timeMod; - return; - } - } - - //no free indices in the smooth array -} - -/* -=============== -CG_smoothWWTransitions -=============== -*/ -static void CG_smoothWWTransitions( playerState_t *ps, const vec3_t in, vec3_t out ) -{ - vec3_t surfNormal, rotAxis, temp; - vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; - vec3_t ceilingNormal = { 0.0f, 0.0f, -1.0f }; - int i; - float stLocal, sFraction, rotAngle; - float smoothTime, timeMod; - qboolean performed = qfalse; - vec3_t inAxis[ 3 ], lastAxis[ 3 ], outAxis[ 3 ]; - - if( cg.snap->ps.pm_flags & PMF_FOLLOW ) - { - VectorCopy( in, out ); - return; - } - - //set surfNormal - if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) ) - VectorCopy( ps->grapplePoint, surfNormal ); - else - VectorCopy( ceilingNormal, surfNormal ); - - AnglesToAxis( in, inAxis ); - - //if we are moving from one surface to another smooth the transition - if( !VectorCompare( surfNormal, cg.lastNormal ) ) - { - //if we moving from the ceiling to the floor special case - //( x product of colinear vectors is undefined) - if( VectorCompare( ceilingNormal, cg.lastNormal ) && - VectorCompare( refNormal, surfNormal ) ) - { - AngleVectors( in, temp, NULL, NULL ); - ProjectPointOnPlane( rotAxis, temp, refNormal ); - VectorNormalize( rotAxis ); - rotAngle = 180.0f; - timeMod = 1.5f; - } - else - { - AnglesToAxis( cg.lastVangles, lastAxis ); - rotAngle = DotProduct( inAxis[ 0 ], lastAxis[ 0 ] ) + - DotProduct( inAxis[ 1 ], lastAxis[ 1 ] ) + - DotProduct( inAxis[ 2 ], lastAxis[ 2 ] ); - - rotAngle = RAD2DEG( acos( ( rotAngle - 1.0f ) / 2.0f ) ); - - CrossProduct( lastAxis[ 0 ], inAxis[ 0 ], temp ); - VectorCopy( temp, rotAxis ); - CrossProduct( lastAxis[ 1 ], inAxis[ 1 ], temp ); - VectorAdd( rotAxis, temp, rotAxis ); - CrossProduct( lastAxis[ 2 ], inAxis[ 2 ], temp ); - VectorAdd( rotAxis, temp, rotAxis ); - - VectorNormalize( rotAxis ); - - timeMod = 1.0f; - } - - //add the op - CG_addSmoothOp( rotAxis, rotAngle, timeMod ); - } - - //iterate through ops - for( i = MAXSMOOTHS - 1; i >= 0; i-- ) - { - smoothTime = (int)( cg_wwSmoothTime.integer * cg.sList[ i ].timeMod ); - - //if this op has time remaining, perform it - if( cg.time < cg.sList[ i ].time + smoothTime ) - { - stLocal = 1.0f - ( ( ( cg.sList[ i ].time + smoothTime ) - cg.time ) / smoothTime ); - sFraction = -( cos( stLocal * M_PI ) + 1.0f ) / 2.0f; - - RotatePointAroundVector( outAxis[ 0 ], cg.sList[ i ].rotAxis, - inAxis[ 0 ], sFraction * cg.sList[ i ].rotAngle ); - RotatePointAroundVector( outAxis[ 1 ], cg.sList[ i ].rotAxis, - inAxis[ 1 ], sFraction * cg.sList[ i ].rotAngle ); - RotatePointAroundVector( outAxis[ 2 ], cg.sList[ i ].rotAxis, - inAxis[ 2 ], sFraction * cg.sList[ i ].rotAngle ); - - AxisCopy( outAxis, inAxis ); - performed = qtrue; - } - } - - //if we performed any ops then return the smoothed angles - //otherwise simply return the in angles - if( performed ) - AxisToAngles( outAxis, out ); - else - VectorCopy( in, out ); - - //copy the current normal to the lastNormal - VectorCopy( in, cg.lastVangles ); - VectorCopy( surfNormal, cg.lastNormal ); -} - -/* -=============== -CG_smoothWJTransitions -=============== -*/ -static void CG_smoothWJTransitions( playerState_t *ps, const vec3_t in, vec3_t out ) -{ - int i; - float stLocal, sFraction; - qboolean performed = qfalse; - vec3_t inAxis[ 3 ], outAxis[ 3 ]; - - if( cg.snap->ps.pm_flags & PMF_FOLLOW ) - { - VectorCopy( in, out ); - return; - } - - AnglesToAxis( in, inAxis ); - - //iterate through ops - for( i = MAXSMOOTHS - 1; i >= 0; i-- ) - { - //if this op has time remaining, perform it - if( cg.time < cg.sList[ i ].time + cg_wwSmoothTime.integer ) - { - stLocal = ( ( cg.sList[ i ].time + cg_wwSmoothTime.integer ) - cg.time ) / cg_wwSmoothTime.integer; - sFraction = 1.0f - ( ( cos( stLocal * M_PI * 2.0f ) + 1.0f ) / 2.0f ); - - RotatePointAroundVector( outAxis[ 0 ], cg.sList[ i ].rotAxis, - inAxis[ 0 ], sFraction * cg.sList[ i ].rotAngle ); - RotatePointAroundVector( outAxis[ 1 ], cg.sList[ i ].rotAxis, - inAxis[ 1 ], sFraction * cg.sList[ i ].rotAngle ); - RotatePointAroundVector( outAxis[ 2 ], cg.sList[ i ].rotAxis, - inAxis[ 2 ], sFraction * cg.sList[ i ].rotAngle ); - - AxisCopy( outAxis, inAxis ); - performed = qtrue; - } - } - - //if we performed any ops then return the smoothed angles - //otherwise simply return the in angles - if( performed ) - AxisToAngles( outAxis, out ); - else - VectorCopy( in, out ); -} - - -/* -=============== -CG_CalcViewValues - -Sets cg.refdef view values -=============== -*/ -static int CG_CalcViewValues( void ) -{ - playerState_t *ps; - - memset( &cg.refdef, 0, sizeof( cg.refdef ) ); - - // calculate size of 3D view - CG_CalcVrect( ); - - ps = &cg.predictedPlayerState; - - // intermission view - if( ps->pm_type == PM_INTERMISSION ) - { - VectorCopy( ps->origin, cg.refdef.vieworg ); - VectorCopy( ps->viewangles, cg.refdefViewAngles ); - AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); - - return CG_CalcFov( ); - } - - cg.bobcycle = ( ps->bobCycle & 128 ) >> 7; - cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) ); - cg.xyspeed = sqrt( ps->velocity[ 0 ] * ps->velocity[ 0 ] + - ps->velocity[ 1 ] * ps->velocity[ 1 ] ); - - VectorCopy( ps->origin, cg.refdef.vieworg ); - - if( BG_ClassHasAbility( ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) ) - CG_smoothWWTransitions( ps, ps->viewangles, cg.refdefViewAngles ); - else if( BG_ClassHasAbility( ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) ) - CG_smoothWJTransitions( ps, ps->viewangles, cg.refdefViewAngles ); - else - VectorCopy( ps->viewangles, cg.refdefViewAngles ); - - //clumsy logic, but it needs to be this way round because the CS propogation - //delay screws things up otherwise - if( !BG_ClassHasAbility( ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) ) - { - if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ) - VectorSet( cg.lastNormal, 0.0f, 0.0f, 1.0f ); - } - - // add error decay - if( cg_errorDecay.value > 0 ) - { - int t; - float f; - - t = cg.time - cg.predictedErrorTime; - f = ( cg_errorDecay.value - t ) / cg_errorDecay.value; - - if( f > 0 && f < 1 ) - VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg ); - else - cg.predictedErrorTime = 0; - } - - //shut off the poison cloud effect if it's still on the go - if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ) - { - if( CG_IsParticleSystemValid( &cg.poisonCloudPS ) ) - CG_DestroyParticleSystem( &cg.poisonCloudPS ); - } - - if( cg.renderingThirdPerson ) - { - // back away from character - CG_OffsetThirdPersonView( ); - } - else - { - // offset for local bobbing and kicks - CG_OffsetFirstPersonView( ); - } - - // position eye reletive to origin - AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); - - if( cg.hyperspace ) - cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE; - - //draw the surface normal looking at - if( cg_drawSurfNormal.integer ) - CG_DrawSurfNormal( ); - - // field of view - return CG_CalcFov( ); -} - -/* -===================== -CG_AddBufferedSound -===================== -*/ -void CG_AddBufferedSound( sfxHandle_t sfx ) -{ - if( !sfx ) - return; - - cg.soundBuffer[ cg.soundBufferIn ] = sfx; - cg.soundBufferIn = ( cg.soundBufferIn + 1 ) % MAX_SOUNDBUFFER; - - if( cg.soundBufferIn == cg.soundBufferOut ) - cg.soundBufferOut++; -} - -/* -===================== -CG_PlayBufferedSounds -===================== -*/ -static void CG_PlayBufferedSounds( void ) -{ - if( cg.soundTime < cg.time ) - { - if( cg.soundBufferOut != cg.soundBufferIn && cg.soundBuffer[ cg.soundBufferOut ] ) - { - trap_S_StartLocalSound( cg.soundBuffer[ cg.soundBufferOut ], CHAN_ANNOUNCER ); - cg.soundBuffer[ cg.soundBufferOut ] = 0; - cg.soundBufferOut = ( cg.soundBufferOut + 1 ) % MAX_SOUNDBUFFER; - cg.soundTime = cg.time + 750; - } - } -} - -//========================================================================= - -/* -================= -CG_DrawActiveFrame - -Generates and draws a game scene and status information at the given time. -================= -*/ -void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) -{ - int inwater; - - cg.time = serverTime; - cg.demoPlayback = demoPlayback; - - // update cvars - CG_UpdateCvars( ); - - // if we are only updating the screen as a loading - // pacifier, don't even try to read snapshots - if( cg.infoScreenText[ 0 ] != 0 ) - { - CG_DrawLoadingScreen( ); - return; - } - - // any looped sounds will be respecified as entities - // are added to the render list - trap_S_ClearLoopingSounds( qfalse ); - - // clear all the render lists - trap_R_ClearScene( ); - - // set up cg.snap and possibly cg.nextSnap - CG_ProcessSnapshots( ); - - // if we haven't received any snapshots yet, all - // we can draw is the information screen - if( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) - { - CG_DrawLoadingScreen( ); - return; - } - - // let the client system know what our weapon and zoom settings are - trap_SetUserCmdValue( cg.weaponSelect, cg.zoomSensitivity ); - - // this counter will be bumped for every valid scene we generate - cg.clientFrame++; - - // update cg.predictedPlayerState - CG_PredictPlayerState( ); - - // decide on third person view - cg.renderingThirdPerson = cg_thirdPerson.integer || ( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ); - - // build cg.refdef - inwater = CG_CalcViewValues( ); - - // build the render lists - if( !cg.hyperspace ) - { - CG_AddPacketEntities( ); // after calcViewValues, so predicted player state is correct - CG_AddMarks( ); - } - - CG_AddViewWeapon( &cg.predictedPlayerState ); - - //after CG_AddViewWeapon - if( !cg.hyperspace ) - { - CG_AddParticles( ); - CG_AddTrails( ); - } - - // add buffered sounds - CG_PlayBufferedSounds( ); - - // finish up the rest of the refdef - if( cg.testModelEntity.hModel ) - CG_AddTestModel( ); - - cg.refdef.time = cg.time; - memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) ); - - //remove expired console lines - if( cg.consoleLines[ 0 ].time + cg_consoleLatency.integer < cg.time && cg_consoleLatency.integer > 0 ) - CG_RemoveConsoleLine( ); - - // update audio positions - trap_S_Respatialize( cg.snap->ps.clientNum, cg.refdef.vieworg, cg.refdef.viewaxis, inwater ); - - // make sure the lagometerSample and frame timing isn't done twice when in stereo - if( stereoView != STEREO_RIGHT ) - { - cg.frametime = cg.time - cg.oldTime; - - if( cg.frametime < 0 ) - cg.frametime = 0; - - cg.oldTime = cg.time; - CG_AddLagometerFrameInfo( ); - } - - if( cg_timescale.value != cg_timescaleFadeEnd.value ) - { - if( cg_timescale.value < cg_timescaleFadeEnd.value ) - { - cg_timescale.value += cg_timescaleFadeSpeed.value * ( (float)cg.frametime ) / 1000; - if( cg_timescale.value > cg_timescaleFadeEnd.value ) - cg_timescale.value = cg_timescaleFadeEnd.value; - } - else - { - cg_timescale.value -= cg_timescaleFadeSpeed.value * ( (float)cg.frametime ) / 1000; - if( cg_timescale.value < cg_timescaleFadeEnd.value ) - cg_timescale.value = cg_timescaleFadeEnd.value; - } - - if( cg_timescaleFadeSpeed.value ) - trap_Cvar_Set( "timescale", va( "%f", cg_timescale.value ) ); - } - - // actually issue the rendering calls - CG_DrawActive( stereoView ); - - if( cg_stats.integer ) - CG_Printf( "cg.clientFrame:%i\n", cg.clientFrame ); -} - diff --git a/src/cgame/cg_weapons.c b/src/cgame/cg_weapons.c deleted file mode 100644 index 7297c518..00000000 --- a/src/cgame/cg_weapons.c +++ /dev/null @@ -1,1810 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// cg_weapons.c -- events and effects dealing with weapons - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "cg_local.h" - -/* -================= -CG_RegisterUpgrade - -The server says this item is used on this level -================= -*/ -void CG_RegisterUpgrade( int upgradeNum ) -{ - upgradeInfo_t *upgradeInfo; - char *icon; - - upgradeInfo = &cg_upgrades[ upgradeNum ]; - - if( upgradeNum == 0 ) - return; - - if( upgradeInfo->registered ) - return; - - memset( upgradeInfo, 0, sizeof( *upgradeInfo ) ); - upgradeInfo->registered = qtrue; - - if( !BG_FindNameForUpgrade( upgradeNum ) ) - CG_Error( "Couldn't find upgrade %i", upgradeNum ); - - upgradeInfo->humanName = BG_FindHumanNameForUpgrade( upgradeNum ); - - //la la la la la, i'm not listening! - if( upgradeNum == UP_GRENADE ) - upgradeInfo->upgradeIcon = cg_weapons[ WP_GRENADE ].weaponIcon; - else if( ( icon = BG_FindIconForUpgrade( upgradeNum ) ) ) - upgradeInfo->upgradeIcon = trap_R_RegisterShader( icon ); -} - -/* -=============== -CG_InitUpgrades - -Precaches upgrades -=============== -*/ -void CG_InitUpgrades( void ) -{ - int i; - - memset( cg_upgrades, 0, sizeof( cg_upgrades ) ); - - for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) - CG_RegisterUpgrade( i ); -} - - -/* -=============== -CG_ParseWeaponModeSection - -Parse a weapon mode section -=============== -*/ -static qboolean CG_ParseWeaponModeSection( weaponInfoMode_t *wim, char **text_p ) -{ - char *token; - int i; - - // read optional parameters - while( 1 ) - { - token = COM_Parse( text_p ); - - if( !token ) - break; - - if( !Q_stricmp( token, "" ) ) - return qfalse; - - if( !Q_stricmp( token, "missileModel" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->missileModel = trap_R_RegisterModel( token ); - - if( !wim->missileModel ) - CG_Printf( S_COLOR_RED "ERROR: missile model not found %s\n", token ); - - continue; - } - else if( !Q_stricmp( token, "missileSprite" ) ) - { - int size = 0; - - token = COM_Parse( text_p ); - if( !token ) - break; - - size = atoi( token ); - - if( size < 0 ) - size = 0; - - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->missileSprite = trap_R_RegisterShader( token ); - wim->missileSpriteSize = size; - wim->usesSpriteMissle = qtrue; - - if( !wim->missileSprite ) - CG_Printf( S_COLOR_RED "ERROR: missile sprite not found %s\n", token ); - - continue; - } - else if( !Q_stricmp( token, "missileRotates" ) ) - { - wim->missileRotates = qtrue; - - continue; - } - else if( !Q_stricmp( token, "missileAnimates" ) ) - { - wim->missileAnimates = qtrue; - - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->missileAnimStartFrame = atoi( token ); - - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->missileAnimNumFrames = atoi( token ); - - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->missileAnimFrameRate = atoi( token ); - - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->missileAnimLooping = atoi( token ); - - continue; - } - else if( !Q_stricmp( token, "missileParticleSystem" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->missileParticleSystem = CG_RegisterParticleSystem( token ); - - if( !wim->missileParticleSystem ) - CG_Printf( S_COLOR_RED "ERROR: missile particle system not found %s\n", token ); - - continue; - } - else if( !Q_stricmp( token, "missileTrailSystem" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->missileTrailSystem = CG_RegisterTrailSystem( token ); - - if( !wim->missileTrailSystem ) - CG_Printf( S_COLOR_RED "ERROR: missile trail system not found %s\n", token ); - - continue; - } - else if( !Q_stricmp( token, "muzzleParticleSystem" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->muzzleParticleSystem = CG_RegisterParticleSystem( token ); - - if( !wim->muzzleParticleSystem ) - CG_Printf( S_COLOR_RED "ERROR: muzzle particle system not found %s\n", token ); - - continue; - } - else if( !Q_stricmp( token, "impactParticleSystem" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->impactParticleSystem = CG_RegisterParticleSystem( token ); - - if( !wim->impactParticleSystem ) - CG_Printf( S_COLOR_RED "ERROR: impact particle system not found %s\n", token ); - - continue; - } - else if( !Q_stricmp( token, "impactMark" ) ) - { - int size = 0; - - token = COM_Parse( text_p ); - if( !token ) - break; - - size = atoi( token ); - - if( size < 0 ) - size = 0; - - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->impactMark = trap_R_RegisterShader( token ); - wim->impactMarkSize = size; - - if( !wim->impactMark ) - CG_Printf( S_COLOR_RED "ERROR: impact mark shader not found %s\n", token ); - - continue; - } - else if( !Q_stricmp( token, "impactSound" ) ) - { - int index = 0; - - token = COM_Parse( text_p ); - if( !token ) - break; - - index = atoi( token ); - - if( index < 0 ) - index = 0; - else if( index > 3 ) - index = 3; - - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->impactSound[ index ] = trap_S_RegisterSound( token, qfalse ); - - continue; - } - else if( !Q_stricmp( token, "impactFleshSound" ) ) - { - int index = 0; - - token = COM_Parse( text_p ); - if( !token ) - break; - - index = atoi( token ); - - if( index < 0 ) - index = 0; - else if( index > 3 ) - index = 3; - - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->impactFleshSound[ index ] = trap_S_RegisterSound( token, qfalse ); - - continue; - } - else if( !Q_stricmp( token, "alwaysImpact" ) ) - { - wim->alwaysImpact = qtrue; - - continue; - } - else if( !Q_stricmp( token, "flashDLightColor" ) ) - { - for( i = 0 ; i < 3 ; i++ ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->flashDlightColor[ i ] = atof( token ); - } - - continue; - } - else if( !Q_stricmp( token, "continuousFlash" ) ) - { - wim->continuousFlash = qtrue; - - continue; - } - else if( !Q_stricmp( token, "missileDlightColor" ) ) - { - for( i = 0 ; i < 3 ; i++ ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->missileDlightColor[ i ] = atof( token ); - } - - continue; - } - else if( !Q_stricmp( token, "missileDlight" ) ) - { - int size = 0; - - token = COM_Parse( text_p ); - if( !token ) - break; - - size = atoi( token ); - - if( size < 0 ) - size = 0; - - wim->missileDlight = size; - - continue; - } - else if( !Q_stricmp( token, "firingSound" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->firingSound = trap_S_RegisterSound( token, qfalse ); - - continue; - } - else if( !Q_stricmp( token, "missileSound" ) ) - { - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->missileSound = trap_S_RegisterSound( token, qfalse ); - - continue; - } - else if( !Q_stricmp( token, "flashSound" ) ) - { - int index = 0; - - token = COM_Parse( text_p ); - if( !token ) - break; - - index = atoi( token ); - - if( index < 0 ) - index = 0; - else if( index > 3 ) - index = 3; - - token = COM_Parse( text_p ); - if( !token ) - break; - - wim->flashSound[ index ] = trap_S_RegisterSound( token, qfalse ); - - continue; - } - else if( !Q_stricmp( token, "}" ) ) - return qtrue; //reached the end of this weapon section - else - { - CG_Printf( S_COLOR_RED "ERROR: unknown token '%s' in weapon section\n", token ); - return qfalse; - } - } - - return qfalse; -} - - -/* -====================== -CG_ParseWeaponFile - -Parses a configuration file describing a weapon -====================== -*/ -static qboolean CG_ParseWeaponFile( const char *filename, weaponInfo_t *wi ) -{ - char *text_p; - int len; - char *token; - char text[ 20000 ]; - fileHandle_t f; - weaponMode_t weaponMode = WPM_NONE; - - // load the file - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - if( len <= 0 ) - return qfalse; - - if( len >= sizeof( text ) - 1 ) - { - CG_Printf( "File %s too long\n", filename ); - return qfalse; - } - - trap_FS_Read( text, len, f ); - text[ len ] = 0; - trap_FS_FCloseFile( f ); - - // parse the text - text_p = text; - - // read optional parameters - while( 1 ) - { - token = COM_Parse( &text_p ); - - if( !token ) - break; - - if( !Q_stricmp( token, "" ) ) - break; - - if( !Q_stricmp( token, "{" ) ) - { - if( weaponMode == WPM_NONE ) - { - CG_Printf( S_COLOR_RED "ERROR: weapon mode section started without a declaration\n" ); - return qfalse; - } - else if( !CG_ParseWeaponModeSection( &wi->wim[ weaponMode ], &text_p ) ) - { - CG_Printf( S_COLOR_RED "ERROR: failed to parse weapon mode section\n" ); - return qfalse; - } - - //start parsing ejectors again - weaponMode = WPM_NONE; - - continue; - } - else if( !Q_stricmp( token, "primary" ) ) - { - weaponMode = WPM_PRIMARY; - continue; - } - else if( !Q_stricmp( token, "secondary" ) ) - { - weaponMode = WPM_SECONDARY; - continue; - } - else if( !Q_stricmp( token, "tertiary" ) ) - { - weaponMode = WPM_TERTIARY; - continue; - } - else if( !Q_stricmp( token, "weaponModel" ) ) - { - char path[ MAX_QPATH ]; - - token = COM_Parse( &text_p ); - if( !token ) - break; - - wi->weaponModel = trap_R_RegisterModel( token ); - - if( !wi->weaponModel ) - CG_Printf( S_COLOR_RED "ERROR: weapon model not found %s\n", token ); - - strcpy( path, token ); - COM_StripExtension( path, path ); - strcat( path, "_flash.md3" ); - wi->flashModel = trap_R_RegisterModel( path ); - - strcpy( path, token ); - COM_StripExtension( path, path ); - strcat( path, "_barrel.md3" ); - wi->barrelModel = trap_R_RegisterModel( path ); - - strcpy( path, token ); - COM_StripExtension( path, path ); - strcat( path, "_hand.md3" ); - wi->handsModel = trap_R_RegisterModel( path ); - - if( !wi->handsModel ) - wi->handsModel = trap_R_RegisterModel( "models/weapons2/shotgun/shotgun_hand.md3" ); - - continue; - } - else if( !Q_stricmp( token, "idleSound" ) ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - wi->readySound = trap_S_RegisterSound( token, qfalse ); - - continue; - } - else if( !Q_stricmp( token, "icon" ) ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - wi->weaponIcon = wi->ammoIcon = trap_R_RegisterShader( token ); - - if( !wi->weaponIcon ) - CG_Printf( S_COLOR_RED "ERROR: weapon icon not found %s\n", token ); - - continue; - } - else if( !Q_stricmp( token, "crosshair" ) ) - { - int size = 0; - - token = COM_Parse( &text_p ); - if( !token ) - break; - - size = atoi( token ); - - if( size < 0 ) - size = 0; - - token = COM_Parse( &text_p ); - if( !token ) - break; - - wi->crossHair = trap_R_RegisterShader( token ); - wi->crossHairSize = size; - - if( !wi->crossHair ) - CG_Printf( S_COLOR_RED "ERROR: weapon crosshair not found %s\n", token ); - - continue; - } - else if( !Q_stricmp( token, "disableIn3rdPerson" ) ) - { - wi->disableIn3rdPerson = qtrue; - - continue; - } - - Com_Printf( S_COLOR_RED "ERROR: unknown token '%s'\n", token ); - return qfalse; - } - - return qtrue; -} - -/* -================= -CG_RegisterWeapon -================= -*/ -void CG_RegisterWeapon( int weaponNum ) -{ - weaponInfo_t *weaponInfo; - char path[ MAX_QPATH ]; - vec3_t mins, maxs; - int i; - - weaponInfo = &cg_weapons[ weaponNum ]; - - if( weaponNum == 0 ) - return; - - if( weaponInfo->registered ) - return; - - memset( weaponInfo, 0, sizeof( *weaponInfo ) ); - weaponInfo->registered = qtrue; - - if( !BG_FindNameForWeapon( weaponNum ) ) - CG_Error( "Couldn't find weapon %i", weaponNum ); - - Com_sprintf( path, MAX_QPATH, "models/weapons/%s/weapon.cfg", BG_FindNameForWeapon( weaponNum ) ); - - weaponInfo->humanName = BG_FindHumanNameForWeapon( weaponNum ); - - if( !CG_ParseWeaponFile( path, weaponInfo ) ) - Com_Printf( S_COLOR_RED "ERROR: failed to parse %s\n", path ); - - // calc midpoint for rotation - trap_R_ModelBounds( weaponInfo->weaponModel, mins, maxs ); - for( i = 0 ; i < 3 ; i++ ) - weaponInfo->weaponMidpoint[ i ] = mins[ i ] + 0.5 * ( maxs[ i ] - mins[ i ] ); - - //FIXME: - for( i = WPM_NONE + 1; i < WPM_NUM_WEAPONMODES; i++ ) - weaponInfo->wim[ i ].loopFireSound = qfalse; -} - -/* -=============== -CG_InitWeapons - -Precaches weapons -=============== -*/ -void CG_InitWeapons( void ) -{ - int i; - - memset( cg_weapons, 0, sizeof( cg_weapons ) ); - - for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) - CG_RegisterWeapon( i ); - - cgs.media.level2ZapTS = CG_RegisterTrailSystem( "models/weapons/lev2zap/lightning" ); -} - - -/* -======================================================================================== - -VIEW WEAPON - -======================================================================================== -*/ - -/* -================= -CG_MapTorsoToWeaponFrame - -================= -*/ -static int CG_MapTorsoToWeaponFrame( clientInfo_t *ci, int frame ) -{ - - // change weapon - if( frame >= ci->animations[ TORSO_DROP ].firstFrame && - frame < ci->animations[ TORSO_DROP ].firstFrame + 9 ) - return frame - ci->animations[ TORSO_DROP ].firstFrame + 6; - - // stand attack - if( frame >= ci->animations[ TORSO_ATTACK ].firstFrame && - frame < ci->animations[ TORSO_ATTACK ].firstFrame + 6 ) - return 1 + frame - ci->animations[ TORSO_ATTACK ].firstFrame; - - // stand attack 2 - if( frame >= ci->animations[ TORSO_ATTACK2 ].firstFrame && - frame < ci->animations[ TORSO_ATTACK2 ].firstFrame + 6 ) - return 1 + frame - ci->animations[ TORSO_ATTACK2 ].firstFrame; - - return 0; -} - - -/* -============== -CG_CalculateWeaponPosition -============== -*/ -static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) -{ - float scale; - int delta; - float fracsin; - float bob; - - VectorCopy( cg.refdef.vieworg, origin ); - VectorCopy( cg.refdefViewAngles, angles ); - - // on odd legs, invert some angles - if( cg.bobcycle & 1 ) - scale = -cg.xyspeed; - else - scale = cg.xyspeed; - - // gun angles from bobbing - //TA: bob amount is class dependant - bob = BG_FindBobForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] ); - - if( bob != 0 ) - { - angles[ ROLL ] += scale * cg.bobfracsin * 0.005; - angles[ YAW ] += scale * cg.bobfracsin * 0.01; - angles[ PITCH ] += cg.xyspeed * cg.bobfracsin * 0.005; - } - - // drop the weapon when landing - if( !BG_ClassHasAbility( cg.predictedPlayerState.stats[ STAT_PCLASS ], SCA_NOWEAPONDRIFT ) ) - { - delta = cg.time - cg.landTime; - if( delta < LAND_DEFLECT_TIME ) - origin[ 2 ] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME; - else if( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) - origin[ 2 ] += cg.landChange*0.25 * - ( LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta ) / LAND_RETURN_TIME; - - // idle drift - scale = cg.xyspeed + 40; - fracsin = sin( cg.time * 0.001 ); - angles[ ROLL ] += scale * fracsin * 0.01; - angles[ YAW ] += scale * fracsin * 0.01; - angles[ PITCH ] += scale * fracsin * 0.01; - } -} - - -/* -====================== -CG_MachinegunSpinAngle -====================== -*/ -#define SPIN_SPEED 0.9 -#define COAST_TIME 1000 -static float CG_MachinegunSpinAngle( centity_t *cent ) -{ - int delta; - float angle; - float speed; - - delta = cg.time - cent->pe.barrelTime; - if( cent->pe.barrelSpinning ) - angle = cent->pe.barrelAngle + delta * SPIN_SPEED; - else - { - if( delta > COAST_TIME ) - delta = COAST_TIME; - - speed = 0.5 * ( SPIN_SPEED + (float)( COAST_TIME - delta ) / COAST_TIME ); - angle = cent->pe.barrelAngle + delta * speed; - } - - if( cent->pe.barrelSpinning == !( cent->currentState.eFlags & EF_FIRING ) ) - { - cent->pe.barrelTime = cg.time; - cent->pe.barrelAngle = AngleMod( angle ); - cent->pe.barrelSpinning = !!( cent->currentState.eFlags & EF_FIRING ); - //TA: um? - } - - return angle; -} - - -/* -============= -CG_AddPlayerWeapon - -Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL) -The main player will have this called for BOTH cases, so effects like light and -sound should only be done on the world model case. -============= -*/ -void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent ) -{ - refEntity_t gun; - refEntity_t barrel; - refEntity_t flash; - vec3_t angles; - weapon_t weaponNum; - weaponMode_t weaponMode; - weaponInfo_t *weapon; - qboolean noGunModel; - qboolean firing; - - weaponNum = cent->currentState.weapon; - weaponMode = cent->currentState.generic1; - - if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES ) - weaponMode = WPM_PRIMARY; - - if( ( ( cent->currentState.eFlags & EF_FIRING ) && weaponMode == WPM_PRIMARY ) || - ( ( cent->currentState.eFlags & EF_FIRING2 ) && weaponMode == WPM_SECONDARY ) || - ( ( cent->currentState.eFlags & EF_FIRING3 ) && weaponMode == WPM_TERTIARY ) ) - firing = qtrue; - else - firing = qfalse; - - CG_RegisterWeapon( weaponNum ); - weapon = &cg_weapons[ weaponNum ]; - - // add the weapon - memset( &gun, 0, sizeof( gun ) ); - VectorCopy( parent->lightingOrigin, gun.lightingOrigin ); - gun.shadowPlane = parent->shadowPlane; - gun.renderfx = parent->renderfx; - - // set custom shading for railgun refire rate - if( ps ) - { - gun.shaderRGBA[ 0 ] = 255; - gun.shaderRGBA[ 1 ] = 255; - gun.shaderRGBA[ 2 ] = 255; - gun.shaderRGBA[ 3 ] = 255; - - //set weapon[1/2]Time when respective buttons change state - if( cg.weapon1Firing != ( cg.predictedPlayerState.eFlags & EF_FIRING ) ) - { - cg.weapon1Time = cg.time; - cg.weapon1Firing = ( cg.predictedPlayerState.eFlags & EF_FIRING ); - } - - if( cg.weapon2Firing != ( cg.predictedPlayerState.eFlags & EF_FIRING2 ) ) - { - cg.weapon2Time = cg.time; - cg.weapon2Firing = ( cg.predictedPlayerState.eFlags & EF_FIRING2 ); - } - - if( cg.weapon3Firing != ( cg.predictedPlayerState.eFlags & EF_FIRING3 ) ) - { - cg.weapon3Time = cg.time; - cg.weapon3Firing = ( cg.predictedPlayerState.eFlags & EF_FIRING3 ); - } - } - - gun.hModel = weapon->weaponModel; - - noGunModel = ( ( !ps || cg.renderingThirdPerson ) && weapon->disableIn3rdPerson ) || !gun.hModel; - - if( !ps ) - { - // add weapon ready sound - if( firing && weapon->wim[ weaponMode ].firingSound ) - { - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, - weapon->wim[ weaponMode ].firingSound ); - } - else if( weapon->readySound ) - trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound ); - } - - if( !noGunModel ) - { - CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon" ); - - trap_R_AddRefEntityToScene( &gun ); - - // add the spinning barrel - if( weapon->barrelModel ) - { - memset( &barrel, 0, sizeof( barrel ) ); - VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); - barrel.shadowPlane = parent->shadowPlane; - barrel.renderfx = parent->renderfx; - - barrel.hModel = weapon->barrelModel; - angles[ YAW ] = 0; - angles[ PITCH ] = 0; - angles[ ROLL ] = CG_MachinegunSpinAngle( cent ); - AnglesToAxis( angles, barrel.axis ); - - CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" ); - - trap_R_AddRefEntityToScene( &barrel ); - } - } - - if( CG_IsParticleSystemValid( ¢->muzzlePS ) ) - { - if( ps || cg.renderingThirdPerson || - cent->currentState.number != cg.predictedPlayerState.clientNum ) - { - if( noGunModel ) - CG_SetAttachmentTag( ¢->muzzlePS->attachment, *parent, parent->hModel, "tag_weapon" ); - else - CG_SetAttachmentTag( ¢->muzzlePS->attachment, gun, weapon->weaponModel, "tag_flash" ); - } - - //if the PS is infinite disable it when not firing - if( !firing && CG_IsParticleSystemInfinite( cent->muzzlePS ) ) - CG_DestroyParticleSystem( ¢->muzzlePS ); - } - - // add the flash - if( !weapon->wim[ weaponMode ].continuousFlash || !firing ) - { - // impulse flash - if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME ) - return; - } - - memset( &flash, 0, sizeof( flash ) ); - VectorCopy( parent->lightingOrigin, flash.lightingOrigin ); - flash.shadowPlane = parent->shadowPlane; - flash.renderfx = parent->renderfx; - - flash.hModel = weapon->flashModel; - if( flash.hModel ) - { - angles[ YAW ] = 0; - angles[ PITCH ] = 0; - angles[ ROLL ] = crandom( ) * 10; - AnglesToAxis( angles, flash.axis ); - - if( noGunModel ) - CG_PositionRotatedEntityOnTag( &flash, parent, parent->hModel, "tag_weapon" ); - else - CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash" ); - - trap_R_AddRefEntityToScene( &flash ); - } - - if( ps || cg.renderingThirdPerson || - cent->currentState.number != cg.predictedPlayerState.clientNum ) - { - if( weapon->wim[ weaponMode ].muzzleParticleSystem && cent->muzzlePsTrigger ) - { - cent->muzzlePS = CG_SpawnNewParticleSystem( weapon->wim[ weaponMode ].muzzleParticleSystem ); - - if( CG_IsParticleSystemValid( ¢->muzzlePS ) ) - { - if( noGunModel ) - CG_SetAttachmentTag( ¢->muzzlePS->attachment, *parent, parent->hModel, "tag_weapon" ); - else - CG_SetAttachmentTag( ¢->muzzlePS->attachment, gun, weapon->weaponModel, "tag_flash" ); - - CG_SetAttachmentCent( ¢->muzzlePS->attachment, cent ); - CG_AttachToTag( ¢->muzzlePS->attachment ); - } - - cent->muzzlePsTrigger = qfalse; - } - - // make a dlight for the flash - if( weapon->wim[ weaponMode ].flashDlightColor[ 0 ] || - weapon->wim[ weaponMode ].flashDlightColor[ 1 ] || - weapon->wim[ weaponMode ].flashDlightColor[ 2 ] ) - { - trap_R_AddLightToScene( flash.origin, 300 + ( rand( ) & 31 ), - weapon->wim[ weaponMode ].flashDlightColor[ 0 ], - weapon->wim[ weaponMode ].flashDlightColor[ 1 ], - weapon->wim[ weaponMode ].flashDlightColor[ 2 ] ); - } - } -} - -/* -============== -CG_AddViewWeapon - -Add the weapon, and flash for the player's view -============== -*/ -void CG_AddViewWeapon( playerState_t *ps ) -{ - refEntity_t hand; - centity_t *cent; - clientInfo_t *ci; - float fovOffset; - vec3_t angles; - weaponInfo_t *wi; - weapon_t weapon = ps->weapon; - weaponMode_t weaponMode = ps->generic1; - - if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES ) - weaponMode = WPM_PRIMARY; - - CG_RegisterWeapon( weapon ); - wi = &cg_weapons[ weapon ]; - cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum]; - - if( ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) || - ( ps->stats[ STAT_STATE ] & SS_INFESTING ) || - ( ps->stats[ STAT_STATE ] & SS_HOVELING ) ) - return; - - //TA: no weapon carried - can't draw it - if( weapon == WP_NONE ) - return; - - if( ps->pm_type == PM_INTERMISSION ) - return; - - //TA: draw a prospective buildable infront of the player - if( ( ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) > BA_NONE ) - CG_GhostBuildable( ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ); - - if( weapon == WP_LUCIFER_CANNON && ps->stats[ STAT_MISC ] > 0 ) - { - if( ps->stats[ STAT_MISC ] > ( LCANNON_TOTAL_CHARGE - ( LCANNON_TOTAL_CHARGE / 3 ) ) ) - trap_S_AddLoopingSound( ps->clientNum, ps->origin, vec3_origin, cgs.media.lCannonWarningSound ); - } - - // no gun if in third person view - if( cg.renderingThirdPerson ) - return; - - // allow the gun to be completely removed - if( !cg_drawGun.integer ) - { - vec3_t origin; - - VectorCopy( cg.refdef.vieworg, origin ); - VectorMA( origin, -8, cg.refdef.viewaxis[ 2 ], origin ); - - if( cent->muzzlePS ) - CG_SetAttachmentPoint( ¢->muzzlePS->attachment, origin ); - - //check for particle systems - if( wi->wim[ weaponMode ].muzzleParticleSystem && cent->muzzlePsTrigger ) - { - cent->muzzlePS = CG_SpawnNewParticleSystem( wi->wim[ weaponMode ].muzzleParticleSystem ); - - if( CG_IsParticleSystemValid( ¢->muzzlePS ) ) - { - CG_SetAttachmentPoint( ¢->muzzlePS->attachment, origin ); - CG_SetAttachmentCent( ¢->muzzlePS->attachment, cent ); - CG_AttachToPoint( ¢->muzzlePS->attachment ); - } - cent->muzzlePsTrigger = qfalse; - } - - return; - } - - // don't draw if testing a gun model - if( cg.testGun ) - return; - - // drop gun lower at higher fov - //if ( cg_fov.integer > 90 ) { - //TA: the client side variable isn't used ( shouldn't iD have done this anyway? ) - if( cg.refdef.fov_y > 90 ) - fovOffset = -0.4 * ( cg.refdef.fov_y - 90 ); - else - fovOffset = 0; - - memset( &hand, 0, sizeof( hand ) ); - - // set up gun position - CG_CalculateWeaponPosition( hand.origin, angles ); - - VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[ 0 ], hand.origin ); - VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[ 1 ], hand.origin ); - VectorMA( hand.origin, ( cg_gun_z.value + fovOffset ), cg.refdef.viewaxis[ 2 ], hand.origin ); - - if( weapon == WP_LUCIFER_CANNON && ps->stats[ STAT_MISC ] > 0 ) - { - float fraction = (float)ps->stats[ STAT_MISC ] / (float)LCANNON_TOTAL_CHARGE; - - VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 0 ], hand.origin ); - VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 1 ], hand.origin ); - } - - AnglesToAxis( angles, hand.axis ); - - // map torso animations to weapon animations - if( cg_gun_frame.integer ) - { - // development tool - hand.frame = hand.oldframe = cg_gun_frame.integer; - hand.backlerp = 0; - } - else - { - // get clientinfo for animation map - ci = &cgs.clientinfo[ cent->currentState.clientNum ]; - hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame ); - hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame ); - hand.backlerp = cent->pe.torso.backlerp; - } - - hand.hModel = wi->handsModel; - hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT; - - // add everything onto the hand - CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity ); -} - -/* -============================================================================== - -WEAPON SELECTION - -============================================================================== -*/ - -/* -=============== -CG_WeaponSelectable -=============== -*/ -static qboolean CG_WeaponSelectable( weapon_t weapon ) -{ - //int ammo, clips; - // - //BG_UnpackAmmoArray( i, cg.snap->ps.ammo, cg.snap->ps.powerups, &ammo, &clips ); - // - //TA: this is a pain in the ass - //if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( i ) ) - // return qfalse; - - if( !BG_InventoryContainsWeapon( weapon, cg.snap->ps.stats ) ) - return qfalse; - - return qtrue; -} - - -/* -=============== -CG_UpgradeSelectable -=============== -*/ -static qboolean CG_UpgradeSelectable( upgrade_t upgrade ) -{ - if( !BG_InventoryContainsUpgrade( upgrade, cg.snap->ps.stats ) ) - return qfalse; - - return qtrue; -} - - -#define ICON_BORDER 4 - -/* -=================== -CG_DrawItemSelect -=================== -*/ -void CG_DrawItemSelect( rectDef_t *rect, vec4_t color ) -{ - int i; - int x = rect->x; - int y = rect->y; - int width = rect->w; - int height = rect->h; - int iconsize; - int items[ 64 ]; - int numItems = 0, selectedItem = 0; - int length; - int selectWindow; - qboolean vertical; - centity_t *cent; - playerState_t *ps; - - cent = &cg_entities[ cg.snap->ps.clientNum ]; - ps = &cg.snap->ps; - - // don't display if dead - if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 ) - return; - - if( !( cg.snap->ps.pm_flags & PMF_FOLLOW ) ) - { - // first make sure that whatever it selected is actually selectable - if( cg.weaponSelect <= 32 && !CG_WeaponSelectable( cg.weaponSelect ) ) - CG_NextWeapon_f( ); - else if( cg.weaponSelect > 32 && !CG_UpgradeSelectable( cg.weaponSelect ) ) - CG_NextWeapon_f( ); - } - - // showing weapon select clears pickup item display, but not the blend blob - cg.itemPickupTime = 0; - - if( height > width ) - { - vertical = qtrue; - iconsize = width; - length = height / width; - } - else if( height <= width ) - { - vertical = qfalse; - iconsize = height; - length = width / height; - } - - selectWindow = length / 2; - - for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) - { - if( !BG_InventoryContainsWeapon( i, cg.snap->ps.stats ) ) - continue; - - if( i == cg.weaponSelect ) - selectedItem = numItems; - - CG_RegisterWeapon( i ); - items[ numItems ] = i; - numItems++; - } - - for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) - { - if( !BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) ) - continue; - - if( i == cg.weaponSelect - 32 ) - selectedItem = numItems; - - CG_RegisterUpgrade( i ); - items[ numItems ] = i + 32; - numItems++; - } - - for( i = 0; i < length; i++ ) - { - int displacement = i - selectWindow; - int item = displacement + selectedItem; - - if( ( item >= 0 ) && ( item < numItems ) ) - { - trap_R_SetColor( color ); - - if( items[ item ] <= 32 ) - CG_DrawPic( x, y, iconsize, iconsize, cg_weapons[ items[ item ] ].weaponIcon ); - else if( items[ item ] > 32 ) - CG_DrawPic( x, y, iconsize, iconsize, cg_upgrades[ items[ item ] - 32 ].upgradeIcon ); - - trap_R_SetColor( NULL ); - -/* if( displacement == 0 ) - CG_DrawPic( x, y, iconsize, iconsize, cgs.media.selectShader );*/ - } - - if( vertical ) - y += iconsize; - else - x += iconsize; - } -} - - -/* -=================== -CG_DrawItemSelectText -=================== -*/ -void CG_DrawItemSelectText( rectDef_t *rect, float scale, int textStyle ) -{ - int x, w; - char *name; - float *color; - - color = CG_FadeColor( cg.weaponSelectTime, WEAPON_SELECT_TIME ); - if( !color ) - return; - - trap_R_SetColor( color ); - - // draw the selected name - if( cg.weaponSelect <= 32 ) - { - if( cg_weapons[ cg.weaponSelect ].registered && - BG_InventoryContainsWeapon( cg.weaponSelect, cg.snap->ps.stats ) ) - { - if( ( name = cg_weapons[ cg.weaponSelect ].humanName ) ) - { - w = CG_Text_Width( name, scale, 0 ); - x = rect->x + rect->w / 2; - CG_Text_Paint( x - w / 2, rect->y + rect->h, scale, color, name, 0, 0, textStyle ); - } - } - } - else if( cg.weaponSelect > 32 ) - { - if( cg_upgrades[ cg.weaponSelect - 32 ].registered && - BG_InventoryContainsUpgrade( cg.weaponSelect - 32, cg.snap->ps.stats ) ) - { - if( ( name = cg_upgrades[ cg.weaponSelect - 32 ].humanName ) ) - { - w = CG_Text_Width( name, scale, 0 ); - x = rect->x + rect->w / 2; - CG_Text_Paint( x - w / 2, rect->y + rect->h, scale, color, name, 0, 0, textStyle ); - } - } - } - - trap_R_SetColor( NULL ); -} - - -/* -=============== -CG_NextWeapon_f -=============== -*/ -void CG_NextWeapon_f( void ) -{ - int i; - int original; - - if( !cg.snap ) - return; - - if( cg.snap->ps.pm_flags & PMF_FOLLOW ) - { - trap_SendClientCommand( "followprev\n" ); - return; - } - - cg.weaponSelectTime = cg.time; - original = cg.weaponSelect; - - for( i = 0; i < 64; i++ ) - { - cg.weaponSelect++; - if( cg.weaponSelect == 64 ) - cg.weaponSelect = 0; - - if( cg.weaponSelect <= 32 ) - { - if( CG_WeaponSelectable( cg.weaponSelect ) ) - break; - } - else if( cg.weaponSelect > 32 ) - { - if( CG_UpgradeSelectable( cg.weaponSelect - 32 ) ) - break; - } - } - - if( i == 64 ) - cg.weaponSelect = original; -} - -/* -=============== -CG_PrevWeapon_f -=============== -*/ -void CG_PrevWeapon_f( void ) -{ - int i; - int original; - - if( !cg.snap ) - return; - - if( cg.snap->ps.pm_flags & PMF_FOLLOW ) - { - trap_SendClientCommand( "follownext\n" ); - return; - } - - cg.weaponSelectTime = cg.time; - original = cg.weaponSelect; - - for( i = 0; i < 64; i++ ) - { - cg.weaponSelect--; - if( cg.weaponSelect == -1 ) - cg.weaponSelect = 63; - - if( cg.weaponSelect <= 32 ) - { - if( CG_WeaponSelectable( cg.weaponSelect ) ) - break; - } - else if( cg.weaponSelect > 32 ) - { - if( CG_UpgradeSelectable( cg.weaponSelect - 32 ) ) - break; - } - } - - if( i == 64 ) - cg.weaponSelect = original; -} - -/* -=============== -CG_Weapon_f -=============== -*/ -void CG_Weapon_f( void ) -{ - int num; - - if( !cg.snap ) - return; - - if( cg.snap->ps.pm_flags & PMF_FOLLOW ) - return; - - num = atoi( CG_Argv( 1 ) ); - - if( num < 1 || num > 31 ) - return; - - cg.weaponSelectTime = cg.time; - - if( !BG_InventoryContainsWeapon( num, cg.snap->ps.stats ) ) - return; // don't have the weapon - - cg.weaponSelect = num; -} - - -/* -=================================================================================================== - -WEAPON EVENTS - -=================================================================================================== -*/ - -/* -================ -CG_FireWeapon - -Caused by an EV_FIRE_WEAPON event -================ -*/ -void CG_FireWeapon( centity_t *cent, weaponMode_t weaponMode ) -{ - entityState_t *es; - int c; - weaponInfo_t *wi; - weapon_t weaponNum; - - es = ¢->currentState; - - weaponNum = es->weapon; - - if( weaponNum == WP_NONE ) - return; - - if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES ) - weaponMode = WPM_PRIMARY; - - if( weaponNum >= WP_NUM_WEAPONS ) - { - CG_Error( "CG_FireWeapon: ent->weapon >= WP_NUM_WEAPONS" ); - return; - } - - wi = &cg_weapons[ weaponNum ]; - - // mark the entity as muzzle flashing, so when it is added it will - // append the flash to the weapon model - cent->muzzleFlashTime = cg.time; - - if( wi->wim[ weaponMode ].muzzleParticleSystem ) - { - if( !CG_IsParticleSystemValid( ¢->muzzlePS ) || - !CG_IsParticleSystemInfinite( cent->muzzlePS ) ) - cent->muzzlePsTrigger = qtrue; - } - - // play a sound - for( c = 0; c < 4; c++ ) - { - if( !wi->wim[ weaponMode ].flashSound[ c ] ) - break; - } - - if( c > 0 ) - { - c = rand( ) % c; - if( wi->wim[ weaponMode ].flashSound[ c ] ) - trap_S_StartSound( NULL, es->number, CHAN_WEAPON, wi->wim[ weaponMode ].flashSound[ c ] ); - } -} - - -/* -================= -CG_MissileHitWall - -Caused by an EV_MISSILE_MISS event, or directly by local bullet tracing -================= -*/ -void CG_MissileHitWall( weapon_t weaponNum, weaponMode_t weaponMode, int clientNum, - vec3_t origin, vec3_t dir, impactSound_t soundType ) -{ - qhandle_t mark = 0; - qhandle_t ps = 0; - int c; - float radius = 1.0f; - weaponInfo_t *weapon = &cg_weapons[ weaponNum ]; - - if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES ) - weaponMode = WPM_PRIMARY; - - mark = weapon->wim[ weaponMode ].impactMark; - radius = weapon->wim[ weaponMode ].impactMarkSize; - ps = weapon->wim[ weaponMode ].impactParticleSystem; - - if( soundType == IMPACTSOUND_FLESH ) - { - //flesh sound - for( c = 0; c < 4; c++ ) - { - if( !weapon->wim[ weaponMode ].impactFleshSound[ c ] ) - break; - } - - if( c > 0 ) - { - c = rand( ) % c; - if( weapon->wim[ weaponMode ].impactFleshSound[ c ] ) - trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, weapon->wim[ weaponMode ].impactFleshSound[ c ] ); - } - } - else - { - //normal sound - for( c = 0; c < 4; c++ ) - { - if( !weapon->wim[ weaponMode ].impactSound[ c ] ) - break; - } - - if( c > 0 ) - { - c = rand( ) % c; - if( weapon->wim[ weaponMode ].impactSound[ c ] ) - trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, weapon->wim[ weaponMode ].impactSound[ c ] ); - } - } - - //create impact particle system - if( ps ) - { - particleSystem_t *partSystem = CG_SpawnNewParticleSystem( ps ); - - if( CG_IsParticleSystemValid( &partSystem ) ) - { - CG_SetAttachmentPoint( &partSystem->attachment, origin ); - CG_SetParticleSystemNormal( partSystem, dir ); - CG_AttachToPoint( &partSystem->attachment ); - } - } - - // - // impact mark - // - if( radius > 0.0f ) - CG_ImpactMark( mark, origin, dir, random( ) * 360, 1, 1, 1, 1, qfalse, radius, qfalse ); -} - - -/* -================= -CG_MissileHitPlayer -================= -*/ -void CG_MissileHitPlayer( weapon_t weaponNum, weaponMode_t weaponMode, - vec3_t origin, vec3_t dir, int entityNum ) -{ - vec3_t normal; - weaponInfo_t *weapon = &cg_weapons[ weaponNum ]; - - VectorCopy( dir, normal ); - VectorInverse( normal ); - - CG_Bleed( origin, normal, entityNum ); - - if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES ) - weaponMode = WPM_PRIMARY; - - if( weapon->wim[ weaponMode ].alwaysImpact ) - CG_MissileHitWall( weaponNum, weaponMode, 0, origin, dir, IMPACTSOUND_FLESH ); -} - - -/* -============================================================================ - -BULLETS - -============================================================================ -*/ - - -/* -=============== -CG_Tracer -=============== -*/ -void CG_Tracer( vec3_t source, vec3_t dest ) -{ - vec3_t forward, right; - polyVert_t verts[ 4 ]; - vec3_t line; - float len, begin, end; - vec3_t start, finish; - vec3_t midpoint; - - // tracer - VectorSubtract( dest, source, forward ); - len = VectorNormalize( forward ); - - // start at least a little ways from the muzzle - if( len < 100 ) - return; - - begin = 50 + random( ) * ( len - 60 ); - end = begin + cg_tracerLength.value; - if( end > len ) - end = len; - - VectorMA( source, begin, forward, start ); - VectorMA( source, end, forward, finish ); - - line[ 0 ] = DotProduct( forward, cg.refdef.viewaxis[ 1 ] ); - line[ 1 ] = DotProduct( forward, cg.refdef.viewaxis[ 2 ] ); - - VectorScale( cg.refdef.viewaxis[ 1 ], line[ 1 ], right ); - VectorMA( right, -line[ 0 ], cg.refdef.viewaxis[ 2 ], right ); - VectorNormalize( right ); - - VectorMA( finish, cg_tracerWidth.value, right, verts[ 0 ].xyz ); - verts[ 0 ].st[ 0 ] = 0; - verts[ 0 ].st[ 1 ] = 1; - verts[ 0 ].modulate[ 0 ] = 255; - verts[ 0 ].modulate[ 1 ] = 255; - verts[ 0 ].modulate[ 2 ] = 255; - verts[ 0 ].modulate[ 3 ] = 255; - - VectorMA( finish, -cg_tracerWidth.value, right, verts[ 1 ].xyz ); - verts[ 1 ].st[ 0 ] = 1; - verts[ 1 ].st[ 1 ] = 0; - verts[ 1 ].modulate[ 0 ] = 255; - verts[ 1 ].modulate[ 1 ] = 255; - verts[ 1 ].modulate[ 2 ] = 255; - verts[ 1 ].modulate[ 3 ] = 255; - - VectorMA( start, -cg_tracerWidth.value, right, verts[ 2 ].xyz ); - verts[ 2 ].st[ 0 ] = 1; - verts[ 2 ].st[ 1 ] = 1; - verts[ 2 ].modulate[ 0 ] = 255; - verts[ 2 ].modulate[ 1 ] = 255; - verts[ 2 ].modulate[ 2 ] = 255; - verts[ 2 ].modulate[ 3 ] = 255; - - VectorMA( start, cg_tracerWidth.value, right, verts[ 3 ].xyz ); - verts[ 3 ].st[ 0 ] = 0; - verts[ 3 ].st[ 1 ] = 0; - verts[ 3 ].modulate[ 0 ] = 255; - verts[ 3 ].modulate[ 1 ] = 255; - verts[ 3 ].modulate[ 2 ] = 255; - verts[ 3 ].modulate[ 3 ] = 255; - - trap_R_AddPolyToScene( cgs.media.tracerShader, 4, verts ); - - midpoint[ 0 ] = ( start[ 0 ] + finish[ 0 ] ) * 0.5; - midpoint[ 1 ] = ( start[ 1 ] + finish[ 1 ] ) * 0.5; - midpoint[ 2 ] = ( start[ 2 ] + finish[ 2 ] ) * 0.5; - - // add the tracer sound - trap_S_StartSound( midpoint, ENTITYNUM_WORLD, CHAN_AUTO, cgs.media.tracerSound ); -} - - -/* -====================== -CG_CalcMuzzlePoint -====================== -*/ -static qboolean CG_CalcMuzzlePoint( int entityNum, vec3_t muzzle ) -{ - vec3_t forward; - centity_t *cent; - int anim; - - if( entityNum == cg.snap->ps.clientNum ) - { - VectorCopy( cg.snap->ps.origin, muzzle ); - muzzle[ 2 ] += cg.snap->ps.viewheight; - AngleVectors( cg.snap->ps.viewangles, forward, NULL, NULL ); - VectorMA( muzzle, 14, forward, muzzle ); - return qtrue; - } - - cent = &cg_entities[entityNum]; - - if( !cent->currentValid ) - return qfalse; - - VectorCopy( cent->currentState.pos.trBase, muzzle ); - - AngleVectors( cent->currentState.apos.trBase, forward, NULL, NULL ); - anim = cent->currentState.legsAnim & ~ANIM_TOGGLEBIT; - - if( anim == LEGS_WALKCR || anim == LEGS_IDLECR ) - muzzle[ 2 ] += CROUCH_VIEWHEIGHT; - else - muzzle[ 2 ] += DEFAULT_VIEWHEIGHT; - - VectorMA( muzzle, 14, forward, muzzle ); - - return qtrue; - -} - - -/* -====================== -CG_Bullet - -Renders bullet effects. -====================== -*/ -void CG_Bullet( vec3_t end, int sourceEntityNum, vec3_t normal, qboolean flesh, int fleshEntityNum ) -{ - vec3_t start; - - // if the shooter is currently valid, calc a source point and possibly - // do trail effects - if( sourceEntityNum >= 0 && cg_tracerChance.value > 0 ) - { - if( CG_CalcMuzzlePoint( sourceEntityNum, start ) ) - { - // draw a tracer - if( random( ) < cg_tracerChance.value ) - CG_Tracer( start, end ); - } - } - - // impact splash and mark - if( flesh ) - CG_Bleed( end, normal, fleshEntityNum ); - else - CG_MissileHitWall( WP_MACHINEGUN, WPM_PRIMARY, 0, end, normal, IMPACTSOUND_DEFAULT ); -} - -/* -============================================================================ - -SHOTGUN TRACING - -============================================================================ -*/ - -/* -================ -CG_ShotgunPattern - -Perform the same traces the server did to locate the -hit splashes -================ -*/ -static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, int otherEntNum ) -{ - int i; - float r, u; - vec3_t end; - vec3_t forward, right, up; - trace_t tr; - - // derive the right and up vectors from the forward vector, because - // the client won't have any other information - VectorNormalize2( origin2, forward ); - PerpendicularVector( right, forward ); - CrossProduct( forward, right, up ); - - // generate the "random" spread pattern - for( i = 0; i < SHOTGUN_PELLETS; i++ ) - { - r = Q_crandom( &seed ) * SHOTGUN_SPREAD * 16; - u = Q_crandom( &seed ) * SHOTGUN_SPREAD * 16; - VectorMA( origin, 8192 * 16, forward, end ); - VectorMA( end, r, right, end ); - VectorMA( end, u, up, end ); - - CG_Trace( &tr, origin, NULL, NULL, end, otherEntNum, MASK_SHOT ); - - if( !( tr.surfaceFlags & SURF_NOIMPACT ) ) - { - if( cg_entities[ tr.entityNum ].currentState.eType == ET_PLAYER ) - CG_MissileHitPlayer( WP_SHOTGUN, WPM_PRIMARY, tr.endpos, tr.plane.normal, tr.entityNum ); - else if( tr.surfaceFlags & SURF_METALSTEPS ) - CG_MissileHitWall( WP_SHOTGUN, WPM_PRIMARY, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_METAL ); - else - CG_MissileHitWall( WP_SHOTGUN, WPM_PRIMARY, 0, tr.endpos, tr.plane.normal, IMPACTSOUND_DEFAULT ); - } - } -} - -/* -============== -CG_ShotgunFire -============== -*/ -void CG_ShotgunFire( entityState_t *es ) -{ - vec3_t v; - - VectorSubtract( es->origin2, es->pos.trBase, v ); - VectorNormalize( v ); - VectorScale( v, 32, v ); - VectorAdd( es->pos.trBase, v, v ); - - CG_ShotgunPattern( es->pos.trBase, es->origin2, es->eventParm, es->otherEntityNum ); -} - diff --git a/src/cgame/tr_types.h b/src/cgame/tr_types.h deleted file mode 100644 index 26240a2f..00000000 --- a/src/cgame/tr_types.h +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#ifndef __TR_TYPES_H -#define __TR_TYPES_H - - -#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces -#define MAX_ENTITIES 1023 // can't be increased without changing drawsurf bit packing - -// renderfx flags -#define RF_MINLIGHT 1 // allways have some light (viewmodel, some items) -#define RF_THIRD_PERSON 2 // don't draw through eyes, only mirrors (player bodies, chat sprites) -#define RF_FIRST_PERSON 4 // only draw through eyes (view weapon, damage blood blob) -#define RF_DEPTHHACK 8 // for view weapon Z crunching -#define RF_NOSHADOW 64 // don't add stencil shadows - -#define RF_LIGHTING_ORIGIN 128 // use refEntity->lightingOrigin instead of refEntity->origin - // for lighting. This allows entities to sink into the floor - // with their origin going solid, and allows all parts of a - // player to get the same lighting -#define RF_SHADOW_PLANE 256 // use refEntity->shadowPlane -#define RF_WRAP_FRAMES 512 // mod the model frames by the maxframes to allow continuous - // animation without needing to know the frame count - -// refdef flags -#define RDF_NOWORLDMODEL 1 // used for player configuration screen -#define RDF_HYPERSPACE 4 // teleportation effect - -typedef struct -{ - vec3_t xyz; - float st[ 2 ]; - byte modulate[ 4 ]; -} polyVert_t; - -typedef struct poly_s -{ - qhandle_t hShader; - int numVerts; - polyVert_t *verts; -} poly_t; - -typedef enum -{ - RT_MODEL, - RT_POLY, - RT_SPRITE, - RT_BEAM, - RT_RAIL_CORE, - RT_RAIL_RINGS, - RT_LIGHTNING, - RT_PORTALSURFACE, // doesn't draw anything, just info for portals - - RT_MAX_REF_ENTITY_TYPE -} refEntityType_t; - -typedef struct -{ - refEntityType_t reType; - int renderfx; - - qhandle_t hModel; // opaque type outside refresh - - // most recent data - vec3_t lightingOrigin; // so multi-part models can be lit identically (RF_LIGHTING_ORIGIN) - float shadowPlane; // projection shadows go here, stencils go slightly lower - - vec3_t axis[ 3 ]; // rotation vectors - qboolean nonNormalizedAxes; // axis are not normalized, i.e. they have scale - float origin[ 3 ]; // also used as MODEL_BEAM's "from" - int frame; // also used as MODEL_BEAM's diameter - - // previous data for frame interpolation - float oldorigin[ 3 ]; // also used as MODEL_BEAM's "to" - int oldframe; - float backlerp; // 0.0 = current, 1.0 = old - - // texturing - int skinNum; // inline skin index - qhandle_t customSkin; // NULL for default skin - qhandle_t customShader; // use one image for the entire thing - - // misc - byte shaderRGBA[ 4 ]; // colors used by rgbgen entity shaders - float shaderTexCoord[ 2 ];// texture coordinates used by tcMod entity modifiers - float shaderTime; // subtracted from refdef time to control effect start times - - // extra sprite information - float radius; - float rotation; -} refEntity_t; - - -#define MAX_RENDER_STRINGS 8 -#define MAX_RENDER_STRING_LENGTH 32 - -typedef struct -{ - int x, y, width, height; - float fov_x, fov_y; - vec3_t vieworg; - vec3_t viewaxis[ 3 ]; // transformation matrix - - // time in milliseconds for shader effects and other time dependent rendering issues - int time; - - int rdflags; // RDF_NOWORLDMODEL, etc - - // 1 bits will prevent the associated area from rendering at all - byte areamask[ MAX_MAP_AREA_BYTES ]; - - // text messages for deform text shaders - char text[ MAX_RENDER_STRINGS ][ MAX_RENDER_STRING_LENGTH ]; -} refdef_t; - - -typedef enum -{ - STEREO_CENTER, - STEREO_LEFT, - STEREO_RIGHT -} stereoFrame_t; - - -/* -** glconfig_t -** -** Contains variables specific to the OpenGL configuration -** being run right now. These are constant once the OpenGL -** subsystem is initialized. -*/ -typedef enum -{ - TC_NONE, - TC_S3TC -} textureCompression_t; - -typedef enum -{ - GLDRV_ICD, // driver is integrated with window system - // WARNING: there are tests that check for - // > GLDRV_ICD for minidriverness, so this - // should always be the lowest value in this - // enum set - GLDRV_STANDALONE, // driver is a non-3Dfx standalone driver - GLDRV_VOODOO // driver is a 3Dfx standalone driver -} glDriverType_t; - -typedef enum -{ - GLHW_GENERIC, // where everthing works the way it should - GLHW_3DFX_2D3D, // Voodoo Banshee or Voodoo3, relevant since if this is - // the hardware type then there can NOT exist a secondary - // display adapter - GLHW_RIVA128, // where you can't interpolate alpha - GLHW_RAGEPRO, // where you can't modulate alpha on alpha textures - GLHW_PERMEDIA2 // where you don't have src*dst -} glHardwareType_t; - -typedef struct -{ - char renderer_string[ MAX_STRING_CHARS ]; - char vendor_string[ MAX_STRING_CHARS ]; - char version_string[ MAX_STRING_CHARS ]; - char extensions_string[ BIG_INFO_STRING ]; - - int maxTextureSize; // queried from GL - int maxActiveTextures; // multitexture ability - - int colorBits, depthBits, stencilBits; - - glDriverType_t driverType; - glHardwareType_t hardwareType; - - qboolean deviceSupportsGamma; - textureCompression_t textureCompression; - qboolean textureEnvAddAvailable; - - int vidWidth, vidHeight; - - // aspect is the screen's physical width / height, which may be different - // than scrWidth / scrHeight if the pixels are non-square - // normal screens should be 4/3, but wide aspect monitors may be 16/9 - float windowAspect; - - int displayFrequency; - - // synonymous with "does rendering consume the entire screen?", therefore - // a Voodoo or Voodoo2 will have this set to TRUE, as will a Win32 ICD that - // used CDS. - qboolean isFullscreen; - qboolean stereoEnabled; - qboolean smpActive; // dual processor -} glconfig_t; - - -#if !defined _WIN32 - -#define _3DFX_DRIVER_NAME "libMesaVoodooGL.so" -// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=524 -#define OPENGL_DRIVER_NAME "libGL.so.1" - -#else - -#define _3DFX_DRIVER_NAME "3dfxvgl" -#define OPENGL_DRIVER_NAME "opengl32" - -#endif // !defined _WIN32 - - -#endif // __TR_TYPES_H diff --git a/src/game/bg_lib.c b/src/game/bg_lib.c deleted file mode 100644 index d940c6d8..00000000 --- a/src/game/bg_lib.c +++ /dev/null @@ -1,1940 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_lib,c -- standard C library replacement routines used by code -// compiled for the virtual machine - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "q_shared.h" - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "bg_lib.h" - -#if defined(LIBC_SCCS) && !defined(lint) -#if 0 -static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93"; -#endif -static const char rcsid[] = - "$Id$"; -#endif /* LIBC_SCCS and not lint */ - -// bk001127 - needed for DLL's -#if !defined( Q3_VM ) -typedef int cmp_t(const void *, const void *); -#endif - -static char* med3(char *, char *, char *, cmp_t *); -static void swapfunc(char *, char *, int, int); - -#ifndef min -#define min(a, b) (a) < (b) ? a : b -#endif - -/* - * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". - */ -#define swapcode(TYPE, parmi, parmj, n) { \ - long i = (n) / sizeof (TYPE); \ - register TYPE *pi = (TYPE *) (parmi); \ - register TYPE *pj = (TYPE *) (parmj); \ - do { \ - register TYPE t = *pi; \ - *pi++ = *pj; \ - *pj++ = t; \ - } while (--i > 0); \ -} - -#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ - es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; - -static void -swapfunc(a, b, n, swaptype) - char *a, *b; - int n, swaptype; -{ - if(swaptype <= 1) - swapcode(long, a, b, n) - else - swapcode(char, a, b, n) -} - -#define swap(a, b) \ - if (swaptype == 0) { \ - long t = *(long *)(a); \ - *(long *)(a) = *(long *)(b); \ - *(long *)(b) = t; \ - } else \ - swapfunc(a, b, es, swaptype) - -#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) - -static char * -med3(a, b, c, cmp) - char *a, *b, *c; - cmp_t *cmp; -{ - return cmp(a, b) < 0 ? - (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) - :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); -} - -void -qsort(a, n, es, cmp) - void *a; - size_t n, es; - cmp_t *cmp; -{ - char *pa, *pb, *pc, *pd, *pl, *pm, *pn; - int d, r, swaptype, swap_cnt; - -loop: SWAPINIT(a, es); - swap_cnt = 0; - if (n < 7) { - for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) - for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - pm = (char *)a + (n / 2) * es; - if (n > 7) { - pl = a; - pn = (char *)a + (n - 1) * es; - if (n > 40) { - d = (n / 8) * es; - pl = med3(pl, pl + d, pl + 2 * d, cmp); - pm = med3(pm - d, pm, pm + d, cmp); - pn = med3(pn - 2 * d, pn - d, pn, cmp); - } - pm = med3(pl, pm, pn, cmp); - } - swap(a, pm); - pa = pb = (char *)a + es; - - pc = pd = (char *)a + (n - 1) * es; - for (;;) { - while (pb <= pc && (r = cmp(pb, a)) <= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pa, pb); - pa += es; - } - pb += es; - } - while (pb <= pc && (r = cmp(pc, a)) >= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pc, pd); - pd -= es; - } - pc -= es; - } - if (pb > pc) - break; - swap(pb, pc); - swap_cnt = 1; - pb += es; - pc -= es; - } - if (swap_cnt == 0) { /* Switch to insertion sort */ - for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) - for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - - pn = (char *)a + n * es; - r = min(pa - (char *)a, pb - pa); - vecswap(a, pb - r, r); - r = min(pd - pc, pn - pd - es); - vecswap(pb, pn - r, r); - if ((r = pb - pa) > es) - qsort(a, r / es, es, cmp); - if ((r = pd - pc) > es) { - /* Iterate rather than recurse to save stack space */ - a = pn - r; - n = r / es; - goto loop; - } -/* qsort(pn - r, r / es, es, cmp);*/ -} - -//================================================================================== - - -// this file is excluded from release builds because of intrinsics - -// bk001211 - gcc errors on compiling strcpy: parse error before `__extension__' -#if defined ( Q3_VM ) - -size_t strlen( const char *string ) -{ - const char *s; - - s = string; - while( *s ) - s++; - - return s - string; -} - - -char *strcat( char *strDestination, const char *strSource ) -{ - char *s; - - s = strDestination; - while( *s ) - s++; - - while( *strSource ) - *s++ = *strSource++; - - *s = 0; - return strDestination; -} - -char *strcpy( char *strDestination, const char *strSource ) -{ - char *s; - - s = strDestination; - - while( *strSource ) - *s++ = *strSource++; - - *s = 0; - return strDestination; -} - - -int strcmp( const char *string1, const char *string2 ) -{ - while( *string1 == *string2 && *string1 && *string2 ) - { - string1++; - string2++; - } - - return *string1 - *string2; -} - -//TA: -char *strrchr( const char *string, int c ) -{ - int i, length = strlen( string ); - char *p; - - for( i = length - 1; i >= 0; i-- ) - { - p = (char *)&string[ i ]; - - if( *p == c ) - return (char *)p; - } - - return (char *)0; -} - -char *strchr( const char *string, int c ) -{ - while( *string ) - { - if( *string == c ) - return ( char * )string; - - string++; - } - return (char *)0; -} - -char *strstr( const char *string, const char *strCharSet ) -{ - while( *string ) - { - int i; - - for( i = 0; strCharSet[ i ]; i++ ) - { - if( string[ i ] != strCharSet[ i ] ) - break; - } - - if( !strCharSet[ i ] ) - return (char *)string; - - string++; - } - return (char *)0; -} - -#endif // bk001211 - -#if defined ( Q3_VM ) - -int tolower( int c ) -{ - if( c >= 'A' && c <= 'Z' ) - c += 'a' - 'A'; - - return c; -} - - -int toupper( int c ) -{ - if( c >= 'a' && c <= 'z' ) - c += 'A' - 'a'; - - return c; -} - -#endif - -void *memmove( void *dest, const void *src, size_t count ) -{ - int i; - - if( dest > src ) - { - for( i = count - 1; i >= 0; i-- ) - ( (char *)dest )[ i ] = ( (char *)src )[ i ]; - } - else - { - for( i = 0; i < count; i++ ) - ( (char *)dest )[ i ] = ( (char *)src )[ i ]; - } - - return dest; -} - - -#if 0 - -double floor( double x ) { - return (int)(x + 0x40000000) - 0x40000000; -} - -void *memset( void *dest, int c, size_t count ) { - while ( count-- ) { - ((char *)dest)[count] = c; - } - return dest; -} - -void *memcpy( void *dest, const void *src, size_t count ) { - while ( count-- ) { - ((char *)dest)[count] = ((char *)src)[count]; - } - return dest; -} - -char *strncpy( char *strDest, const char *strSource, size_t count ) { - char *s; - - s = strDest; - while ( *strSource && count ) { - *s++ = *strSource++; - count--; - } - while ( count-- ) { - *s++ = 0; - } - return strDest; -} - -double sqrt( double x ) { - float y; - float delta; - float maxError; - - if ( x <= 0 ) { - return 0; - } - - // initial guess - y = x / 2; - - // refine - maxError = x * 0.001; - - do { - delta = ( y * y ) - x; - y -= delta / ( 2 * y ); - } while ( delta > maxError || delta < -maxError ); - - return y; -} - - -float sintable[1024] = { -0.000000,0.001534,0.003068,0.004602,0.006136,0.007670,0.009204,0.010738, -0.012272,0.013805,0.015339,0.016873,0.018407,0.019940,0.021474,0.023008, -0.024541,0.026075,0.027608,0.029142,0.030675,0.032208,0.033741,0.035274, -0.036807,0.038340,0.039873,0.041406,0.042938,0.044471,0.046003,0.047535, -0.049068,0.050600,0.052132,0.053664,0.055195,0.056727,0.058258,0.059790, -0.061321,0.062852,0.064383,0.065913,0.067444,0.068974,0.070505,0.072035, -0.073565,0.075094,0.076624,0.078153,0.079682,0.081211,0.082740,0.084269, -0.085797,0.087326,0.088854,0.090381,0.091909,0.093436,0.094963,0.096490, -0.098017,0.099544,0.101070,0.102596,0.104122,0.105647,0.107172,0.108697, -0.110222,0.111747,0.113271,0.114795,0.116319,0.117842,0.119365,0.120888, -0.122411,0.123933,0.125455,0.126977,0.128498,0.130019,0.131540,0.133061, -0.134581,0.136101,0.137620,0.139139,0.140658,0.142177,0.143695,0.145213, -0.146730,0.148248,0.149765,0.151281,0.152797,0.154313,0.155828,0.157343, -0.158858,0.160372,0.161886,0.163400,0.164913,0.166426,0.167938,0.169450, -0.170962,0.172473,0.173984,0.175494,0.177004,0.178514,0.180023,0.181532, -0.183040,0.184548,0.186055,0.187562,0.189069,0.190575,0.192080,0.193586, -0.195090,0.196595,0.198098,0.199602,0.201105,0.202607,0.204109,0.205610, -0.207111,0.208612,0.210112,0.211611,0.213110,0.214609,0.216107,0.217604, -0.219101,0.220598,0.222094,0.223589,0.225084,0.226578,0.228072,0.229565, -0.231058,0.232550,0.234042,0.235533,0.237024,0.238514,0.240003,0.241492, -0.242980,0.244468,0.245955,0.247442,0.248928,0.250413,0.251898,0.253382, -0.254866,0.256349,0.257831,0.259313,0.260794,0.262275,0.263755,0.265234, -0.266713,0.268191,0.269668,0.271145,0.272621,0.274097,0.275572,0.277046, -0.278520,0.279993,0.281465,0.282937,0.284408,0.285878,0.287347,0.288816, -0.290285,0.291752,0.293219,0.294685,0.296151,0.297616,0.299080,0.300543, -0.302006,0.303468,0.304929,0.306390,0.307850,0.309309,0.310767,0.312225, -0.313682,0.315138,0.316593,0.318048,0.319502,0.320955,0.322408,0.323859, -0.325310,0.326760,0.328210,0.329658,0.331106,0.332553,0.334000,0.335445, -0.336890,0.338334,0.339777,0.341219,0.342661,0.344101,0.345541,0.346980, -0.348419,0.349856,0.351293,0.352729,0.354164,0.355598,0.357031,0.358463, -0.359895,0.361326,0.362756,0.364185,0.365613,0.367040,0.368467,0.369892, -0.371317,0.372741,0.374164,0.375586,0.377007,0.378428,0.379847,0.381266, -0.382683,0.384100,0.385516,0.386931,0.388345,0.389758,0.391170,0.392582, -0.393992,0.395401,0.396810,0.398218,0.399624,0.401030,0.402435,0.403838, -0.405241,0.406643,0.408044,0.409444,0.410843,0.412241,0.413638,0.415034, -0.416430,0.417824,0.419217,0.420609,0.422000,0.423390,0.424780,0.426168, -0.427555,0.428941,0.430326,0.431711,0.433094,0.434476,0.435857,0.437237, -0.438616,0.439994,0.441371,0.442747,0.444122,0.445496,0.446869,0.448241, -0.449611,0.450981,0.452350,0.453717,0.455084,0.456449,0.457813,0.459177, -0.460539,0.461900,0.463260,0.464619,0.465976,0.467333,0.468689,0.470043, -0.471397,0.472749,0.474100,0.475450,0.476799,0.478147,0.479494,0.480839, -0.482184,0.483527,0.484869,0.486210,0.487550,0.488889,0.490226,0.491563, -0.492898,0.494232,0.495565,0.496897,0.498228,0.499557,0.500885,0.502212, -0.503538,0.504863,0.506187,0.507509,0.508830,0.510150,0.511469,0.512786, -0.514103,0.515418,0.516732,0.518045,0.519356,0.520666,0.521975,0.523283, -0.524590,0.525895,0.527199,0.528502,0.529804,0.531104,0.532403,0.533701, -0.534998,0.536293,0.537587,0.538880,0.540171,0.541462,0.542751,0.544039, -0.545325,0.546610,0.547894,0.549177,0.550458,0.551738,0.553017,0.554294, -0.555570,0.556845,0.558119,0.559391,0.560662,0.561931,0.563199,0.564466, -0.565732,0.566996,0.568259,0.569521,0.570781,0.572040,0.573297,0.574553, -0.575808,0.577062,0.578314,0.579565,0.580814,0.582062,0.583309,0.584554, -0.585798,0.587040,0.588282,0.589521,0.590760,0.591997,0.593232,0.594466, -0.595699,0.596931,0.598161,0.599389,0.600616,0.601842,0.603067,0.604290, -0.605511,0.606731,0.607950,0.609167,0.610383,0.611597,0.612810,0.614022, -0.615232,0.616440,0.617647,0.618853,0.620057,0.621260,0.622461,0.623661, -0.624859,0.626056,0.627252,0.628446,0.629638,0.630829,0.632019,0.633207, -0.634393,0.635578,0.636762,0.637944,0.639124,0.640303,0.641481,0.642657, -0.643832,0.645005,0.646176,0.647346,0.648514,0.649681,0.650847,0.652011, -0.653173,0.654334,0.655493,0.656651,0.657807,0.658961,0.660114,0.661266, -0.662416,0.663564,0.664711,0.665856,0.667000,0.668142,0.669283,0.670422, -0.671559,0.672695,0.673829,0.674962,0.676093,0.677222,0.678350,0.679476, -0.680601,0.681724,0.682846,0.683965,0.685084,0.686200,0.687315,0.688429, -0.689541,0.690651,0.691759,0.692866,0.693971,0.695075,0.696177,0.697278, -0.698376,0.699473,0.700569,0.701663,0.702755,0.703845,0.704934,0.706021, -0.707107,0.708191,0.709273,0.710353,0.711432,0.712509,0.713585,0.714659, -0.715731,0.716801,0.717870,0.718937,0.720003,0.721066,0.722128,0.723188, -0.724247,0.725304,0.726359,0.727413,0.728464,0.729514,0.730563,0.731609, -0.732654,0.733697,0.734739,0.735779,0.736817,0.737853,0.738887,0.739920, -0.740951,0.741980,0.743008,0.744034,0.745058,0.746080,0.747101,0.748119, -0.749136,0.750152,0.751165,0.752177,0.753187,0.754195,0.755201,0.756206, -0.757209,0.758210,0.759209,0.760207,0.761202,0.762196,0.763188,0.764179, -0.765167,0.766154,0.767139,0.768122,0.769103,0.770083,0.771061,0.772036, -0.773010,0.773983,0.774953,0.775922,0.776888,0.777853,0.778817,0.779778, -0.780737,0.781695,0.782651,0.783605,0.784557,0.785507,0.786455,0.787402, -0.788346,0.789289,0.790230,0.791169,0.792107,0.793042,0.793975,0.794907, -0.795837,0.796765,0.797691,0.798615,0.799537,0.800458,0.801376,0.802293, -0.803208,0.804120,0.805031,0.805940,0.806848,0.807753,0.808656,0.809558, -0.810457,0.811355,0.812251,0.813144,0.814036,0.814926,0.815814,0.816701, -0.817585,0.818467,0.819348,0.820226,0.821103,0.821977,0.822850,0.823721, -0.824589,0.825456,0.826321,0.827184,0.828045,0.828904,0.829761,0.830616, -0.831470,0.832321,0.833170,0.834018,0.834863,0.835706,0.836548,0.837387, -0.838225,0.839060,0.839894,0.840725,0.841555,0.842383,0.843208,0.844032, -0.844854,0.845673,0.846491,0.847307,0.848120,0.848932,0.849742,0.850549, -0.851355,0.852159,0.852961,0.853760,0.854558,0.855354,0.856147,0.856939, -0.857729,0.858516,0.859302,0.860085,0.860867,0.861646,0.862424,0.863199, -0.863973,0.864744,0.865514,0.866281,0.867046,0.867809,0.868571,0.869330, -0.870087,0.870842,0.871595,0.872346,0.873095,0.873842,0.874587,0.875329, -0.876070,0.876809,0.877545,0.878280,0.879012,0.879743,0.880471,0.881197, -0.881921,0.882643,0.883363,0.884081,0.884797,0.885511,0.886223,0.886932, -0.887640,0.888345,0.889048,0.889750,0.890449,0.891146,0.891841,0.892534, -0.893224,0.893913,0.894599,0.895284,0.895966,0.896646,0.897325,0.898001, -0.898674,0.899346,0.900016,0.900683,0.901349,0.902012,0.902673,0.903332, -0.903989,0.904644,0.905297,0.905947,0.906596,0.907242,0.907886,0.908528, -0.909168,0.909806,0.910441,0.911075,0.911706,0.912335,0.912962,0.913587, -0.914210,0.914830,0.915449,0.916065,0.916679,0.917291,0.917901,0.918508, -0.919114,0.919717,0.920318,0.920917,0.921514,0.922109,0.922701,0.923291, -0.923880,0.924465,0.925049,0.925631,0.926210,0.926787,0.927363,0.927935, -0.928506,0.929075,0.929641,0.930205,0.930767,0.931327,0.931884,0.932440, -0.932993,0.933544,0.934093,0.934639,0.935184,0.935726,0.936266,0.936803, -0.937339,0.937872,0.938404,0.938932,0.939459,0.939984,0.940506,0.941026, -0.941544,0.942060,0.942573,0.943084,0.943593,0.944100,0.944605,0.945107, -0.945607,0.946105,0.946601,0.947094,0.947586,0.948075,0.948561,0.949046, -0.949528,0.950008,0.950486,0.950962,0.951435,0.951906,0.952375,0.952842, -0.953306,0.953768,0.954228,0.954686,0.955141,0.955594,0.956045,0.956494, -0.956940,0.957385,0.957826,0.958266,0.958703,0.959139,0.959572,0.960002, -0.960431,0.960857,0.961280,0.961702,0.962121,0.962538,0.962953,0.963366, -0.963776,0.964184,0.964590,0.964993,0.965394,0.965793,0.966190,0.966584, -0.966976,0.967366,0.967754,0.968139,0.968522,0.968903,0.969281,0.969657, -0.970031,0.970403,0.970772,0.971139,0.971504,0.971866,0.972226,0.972584, -0.972940,0.973293,0.973644,0.973993,0.974339,0.974684,0.975025,0.975365, -0.975702,0.976037,0.976370,0.976700,0.977028,0.977354,0.977677,0.977999, -0.978317,0.978634,0.978948,0.979260,0.979570,0.979877,0.980182,0.980485, -0.980785,0.981083,0.981379,0.981673,0.981964,0.982253,0.982539,0.982824, -0.983105,0.983385,0.983662,0.983937,0.984210,0.984480,0.984749,0.985014, -0.985278,0.985539,0.985798,0.986054,0.986308,0.986560,0.986809,0.987057, -0.987301,0.987544,0.987784,0.988022,0.988258,0.988491,0.988722,0.988950, -0.989177,0.989400,0.989622,0.989841,0.990058,0.990273,0.990485,0.990695, -0.990903,0.991108,0.991311,0.991511,0.991710,0.991906,0.992099,0.992291, -0.992480,0.992666,0.992850,0.993032,0.993212,0.993389,0.993564,0.993737, -0.993907,0.994075,0.994240,0.994404,0.994565,0.994723,0.994879,0.995033, -0.995185,0.995334,0.995481,0.995625,0.995767,0.995907,0.996045,0.996180, -0.996313,0.996443,0.996571,0.996697,0.996820,0.996941,0.997060,0.997176, -0.997290,0.997402,0.997511,0.997618,0.997723,0.997825,0.997925,0.998023, -0.998118,0.998211,0.998302,0.998390,0.998476,0.998559,0.998640,0.998719, -0.998795,0.998870,0.998941,0.999011,0.999078,0.999142,0.999205,0.999265, -0.999322,0.999378,0.999431,0.999481,0.999529,0.999575,0.999619,0.999660, -0.999699,0.999735,0.999769,0.999801,0.999831,0.999858,0.999882,0.999905, -0.999925,0.999942,0.999958,0.999971,0.999981,0.999989,0.999995,0.999999 -}; - -double sin( double x ) { - int index; - int quad; - - index = 1024 * x / (M_PI * 0.5); - quad = ( index >> 10 ) & 3; - index &= 1023; - switch ( quad ) { - case 0: - return sintable[index]; - case 1: - return sintable[1023-index]; - case 2: - return -sintable[index]; - case 3: - return -sintable[1023-index]; - } - return 0; -} - - -double cos( double x ) { - int index; - int quad; - - index = 1024 * x / (M_PI * 0.5); - quad = ( index >> 10 ) & 3; - index &= 1023; - switch ( quad ) { - case 3: - return sintable[index]; - case 0: - return sintable[1023-index]; - case 1: - return -sintable[index]; - case 2: - return -sintable[1023-index]; - } - return 0; -} - - -/* -void create_acostable( void ) { - int i; - FILE *fp; - float a; - - fp = fopen("c:\\acostable.txt", "w"); - fprintf(fp, "float acostable[] = {"); - for (i = 0; i < 1024; i++) { - if (!(i & 7)) - fprintf(fp, "\n"); - a = acos( (float) -1 + i / 512 ); - fprintf(fp, "%1.8f,", a); - } - fprintf(fp, "\n}\n"); - fclose(fp); -} -*/ - - -float acostable[] = { -3.14159265,3.07908248,3.05317551,3.03328655,3.01651113,3.00172442,2.98834964,2.97604422, -2.96458497,2.95381690,2.94362719,2.93393068,2.92466119,2.91576615,2.90720289,2.89893629, -2.89093699,2.88318015,2.87564455,2.86831188,2.86116621,2.85419358,2.84738169,2.84071962, -2.83419760,2.82780691,2.82153967,2.81538876,2.80934770,2.80341062,2.79757211,2.79182724, -2.78617145,2.78060056,2.77511069,2.76969824,2.76435988,2.75909250,2.75389319,2.74875926, -2.74368816,2.73867752,2.73372510,2.72882880,2.72398665,2.71919677,2.71445741,2.70976688, -2.70512362,2.70052613,2.69597298,2.69146283,2.68699438,2.68256642,2.67817778,2.67382735, -2.66951407,2.66523692,2.66099493,2.65678719,2.65261279,2.64847088,2.64436066,2.64028133, -2.63623214,2.63221238,2.62822133,2.62425835,2.62032277,2.61641398,2.61253138,2.60867440, -2.60484248,2.60103507,2.59725167,2.59349176,2.58975488,2.58604053,2.58234828,2.57867769, -2.57502832,2.57139977,2.56779164,2.56420354,2.56063509,2.55708594,2.55355572,2.55004409, -2.54655073,2.54307530,2.53961750,2.53617701,2.53275354,2.52934680,2.52595650,2.52258238, -2.51922417,2.51588159,2.51255441,2.50924238,2.50594525,2.50266278,2.49939476,2.49614096, -2.49290115,2.48967513,2.48646269,2.48326362,2.48007773,2.47690482,2.47374472,2.47059722, -2.46746215,2.46433933,2.46122860,2.45812977,2.45504269,2.45196720,2.44890314,2.44585034, -2.44280867,2.43977797,2.43675809,2.43374890,2.43075025,2.42776201,2.42478404,2.42181622, -2.41885841,2.41591048,2.41297232,2.41004380,2.40712480,2.40421521,2.40131491,2.39842379, -2.39554173,2.39266863,2.38980439,2.38694889,2.38410204,2.38126374,2.37843388,2.37561237, -2.37279910,2.36999400,2.36719697,2.36440790,2.36162673,2.35885335,2.35608768,2.35332964, -2.35057914,2.34783610,2.34510044,2.34237208,2.33965094,2.33693695,2.33423003,2.33153010, -2.32883709,2.32615093,2.32347155,2.32079888,2.31813284,2.31547337,2.31282041,2.31017388, -2.30753373,2.30489988,2.30227228,2.29965086,2.29703556,2.29442632,2.29182309,2.28922580, -2.28663439,2.28404881,2.28146900,2.27889490,2.27632647,2.27376364,2.27120637,2.26865460, -2.26610827,2.26356735,2.26103177,2.25850149,2.25597646,2.25345663,2.25094195,2.24843238, -2.24592786,2.24342836,2.24093382,2.23844420,2.23595946,2.23347956,2.23100444,2.22853408, -2.22606842,2.22360742,2.22115104,2.21869925,2.21625199,2.21380924,2.21137096,2.20893709, -2.20650761,2.20408248,2.20166166,2.19924511,2.19683280,2.19442469,2.19202074,2.18962092, -2.18722520,2.18483354,2.18244590,2.18006225,2.17768257,2.17530680,2.17293493,2.17056692, -2.16820274,2.16584236,2.16348574,2.16113285,2.15878367,2.15643816,2.15409630,2.15175805, -2.14942338,2.14709226,2.14476468,2.14244059,2.14011997,2.13780279,2.13548903,2.13317865, -2.13087163,2.12856795,2.12626757,2.12397047,2.12167662,2.11938600,2.11709859,2.11481435, -2.11253326,2.11025530,2.10798044,2.10570867,2.10343994,2.10117424,2.09891156,2.09665185, -2.09439510,2.09214129,2.08989040,2.08764239,2.08539725,2.08315496,2.08091550,2.07867884, -2.07644495,2.07421383,2.07198545,2.06975978,2.06753681,2.06531651,2.06309887,2.06088387, -2.05867147,2.05646168,2.05425445,2.05204979,2.04984765,2.04764804,2.04545092,2.04325628, -2.04106409,2.03887435,2.03668703,2.03450211,2.03231957,2.03013941,2.02796159,2.02578610, -2.02361292,2.02144204,2.01927344,2.01710710,2.01494300,2.01278113,2.01062146,2.00846399, -2.00630870,2.00415556,2.00200457,1.99985570,1.99770895,1.99556429,1.99342171,1.99128119, -1.98914271,1.98700627,1.98487185,1.98273942,1.98060898,1.97848051,1.97635399,1.97422942, -1.97210676,1.96998602,1.96786718,1.96575021,1.96363511,1.96152187,1.95941046,1.95730088, -1.95519310,1.95308712,1.95098292,1.94888050,1.94677982,1.94468089,1.94258368,1.94048818, -1.93839439,1.93630228,1.93421185,1.93212308,1.93003595,1.92795046,1.92586659,1.92378433, -1.92170367,1.91962459,1.91754708,1.91547113,1.91339673,1.91132385,1.90925250,1.90718266, -1.90511432,1.90304746,1.90098208,1.89891815,1.89685568,1.89479464,1.89273503,1.89067683, -1.88862003,1.88656463,1.88451060,1.88245794,1.88040664,1.87835668,1.87630806,1.87426076, -1.87221477,1.87017008,1.86812668,1.86608457,1.86404371,1.86200412,1.85996577,1.85792866, -1.85589277,1.85385809,1.85182462,1.84979234,1.84776125,1.84573132,1.84370256,1.84167495, -1.83964848,1.83762314,1.83559892,1.83357582,1.83155381,1.82953289,1.82751305,1.82549429, -1.82347658,1.82145993,1.81944431,1.81742973,1.81541617,1.81340362,1.81139207,1.80938151, -1.80737194,1.80536334,1.80335570,1.80134902,1.79934328,1.79733848,1.79533460,1.79333164, -1.79132959,1.78932843,1.78732817,1.78532878,1.78333027,1.78133261,1.77933581,1.77733985, -1.77534473,1.77335043,1.77135695,1.76936428,1.76737240,1.76538132,1.76339101,1.76140148, -1.75941271,1.75742470,1.75543743,1.75345090,1.75146510,1.74948002,1.74749565,1.74551198, -1.74352900,1.74154672,1.73956511,1.73758417,1.73560389,1.73362426,1.73164527,1.72966692, -1.72768920,1.72571209,1.72373560,1.72175971,1.71978441,1.71780969,1.71583556,1.71386199, -1.71188899,1.70991653,1.70794462,1.70597325,1.70400241,1.70203209,1.70006228,1.69809297, -1.69612416,1.69415584,1.69218799,1.69022062,1.68825372,1.68628727,1.68432127,1.68235571, -1.68039058,1.67842588,1.67646160,1.67449772,1.67253424,1.67057116,1.66860847,1.66664615, -1.66468420,1.66272262,1.66076139,1.65880050,1.65683996,1.65487975,1.65291986,1.65096028, -1.64900102,1.64704205,1.64508338,1.64312500,1.64116689,1.63920905,1.63725148,1.63529416, -1.63333709,1.63138026,1.62942366,1.62746728,1.62551112,1.62355517,1.62159943,1.61964388, -1.61768851,1.61573332,1.61377831,1.61182346,1.60986877,1.60791422,1.60595982,1.60400556, -1.60205142,1.60009739,1.59814349,1.59618968,1.59423597,1.59228235,1.59032882,1.58837536, -1.58642196,1.58446863,1.58251535,1.58056211,1.57860891,1.57665574,1.57470259,1.57274945, -1.57079633,1.56884320,1.56689007,1.56493692,1.56298375,1.56103055,1.55907731,1.55712403, -1.55517069,1.55321730,1.55126383,1.54931030,1.54735668,1.54540297,1.54344917,1.54149526, -1.53954124,1.53758710,1.53563283,1.53367843,1.53172389,1.52976919,1.52781434,1.52585933, -1.52390414,1.52194878,1.51999323,1.51803748,1.51608153,1.51412537,1.51216900,1.51021240, -1.50825556,1.50629849,1.50434117,1.50238360,1.50042576,1.49846765,1.49650927,1.49455060, -1.49259163,1.49063237,1.48867280,1.48671291,1.48475270,1.48279215,1.48083127,1.47887004, -1.47690845,1.47494650,1.47298419,1.47102149,1.46905841,1.46709493,1.46513106,1.46316677, -1.46120207,1.45923694,1.45727138,1.45530538,1.45333893,1.45137203,1.44940466,1.44743682, -1.44546850,1.44349969,1.44153038,1.43956057,1.43759024,1.43561940,1.43364803,1.43167612, -1.42970367,1.42773066,1.42575709,1.42378296,1.42180825,1.41983295,1.41785705,1.41588056, -1.41390346,1.41192573,1.40994738,1.40796840,1.40598877,1.40400849,1.40202755,1.40004594, -1.39806365,1.39608068,1.39409701,1.39211264,1.39012756,1.38814175,1.38615522,1.38416795, -1.38217994,1.38019117,1.37820164,1.37621134,1.37422025,1.37222837,1.37023570,1.36824222, -1.36624792,1.36425280,1.36225684,1.36026004,1.35826239,1.35626387,1.35426449,1.35226422, -1.35026307,1.34826101,1.34625805,1.34425418,1.34224937,1.34024364,1.33823695,1.33622932, -1.33422072,1.33221114,1.33020059,1.32818904,1.32617649,1.32416292,1.32214834,1.32013273, -1.31811607,1.31609837,1.31407960,1.31205976,1.31003885,1.30801684,1.30599373,1.30396951, -1.30194417,1.29991770,1.29789009,1.29586133,1.29383141,1.29180031,1.28976803,1.28773456, -1.28569989,1.28366400,1.28162688,1.27958854,1.27754894,1.27550809,1.27346597,1.27142257, -1.26937788,1.26733189,1.26528459,1.26323597,1.26118602,1.25913471,1.25708205,1.25502803, -1.25297262,1.25091583,1.24885763,1.24679802,1.24473698,1.24267450,1.24061058,1.23854519, -1.23647833,1.23440999,1.23234015,1.23026880,1.22819593,1.22612152,1.22404557,1.22196806, -1.21988898,1.21780832,1.21572606,1.21364219,1.21155670,1.20946958,1.20738080,1.20529037, -1.20319826,1.20110447,1.19900898,1.19691177,1.19481283,1.19271216,1.19060973,1.18850553, -1.18639955,1.18429178,1.18218219,1.18007079,1.17795754,1.17584244,1.17372548,1.17160663, -1.16948589,1.16736324,1.16523866,1.16311215,1.16098368,1.15885323,1.15672081,1.15458638, -1.15244994,1.15031147,1.14817095,1.14602836,1.14388370,1.14173695,1.13958808,1.13743709, -1.13528396,1.13312866,1.13097119,1.12881153,1.12664966,1.12448556,1.12231921,1.12015061, -1.11797973,1.11580656,1.11363107,1.11145325,1.10927308,1.10709055,1.10490563,1.10271831, -1.10052856,1.09833638,1.09614174,1.09394462,1.09174500,1.08954287,1.08733820,1.08513098, -1.08292118,1.08070879,1.07849378,1.07627614,1.07405585,1.07183287,1.06960721,1.06737882, -1.06514770,1.06291382,1.06067715,1.05843769,1.05619540,1.05395026,1.05170226,1.04945136, -1.04719755,1.04494080,1.04268110,1.04041841,1.03815271,1.03588399,1.03361221,1.03133735, -1.02905939,1.02677830,1.02449407,1.02220665,1.01991603,1.01762219,1.01532509,1.01302471, -1.01072102,1.00841400,1.00610363,1.00378986,1.00147268,0.99915206,0.99682798,0.99450039, -0.99216928,0.98983461,0.98749636,0.98515449,0.98280898,0.98045980,0.97810691,0.97575030, -0.97338991,0.97102573,0.96865772,0.96628585,0.96391009,0.96153040,0.95914675,0.95675912, -0.95436745,0.95197173,0.94957191,0.94716796,0.94475985,0.94234754,0.93993099,0.93751017, -0.93508504,0.93265556,0.93022170,0.92778341,0.92534066,0.92289341,0.92044161,0.91798524, -0.91552424,0.91305858,0.91058821,0.90811309,0.90563319,0.90314845,0.90065884,0.89816430, -0.89566479,0.89316028,0.89065070,0.88813602,0.88561619,0.88309116,0.88056088,0.87802531, -0.87548438,0.87293806,0.87038629,0.86782901,0.86526619,0.86269775,0.86012366,0.85754385, -0.85495827,0.85236686,0.84976956,0.84716633,0.84455709,0.84194179,0.83932037,0.83669277, -0.83405893,0.83141877,0.82877225,0.82611928,0.82345981,0.82079378,0.81812110,0.81544172, -0.81275556,0.81006255,0.80736262,0.80465570,0.80194171,0.79922057,0.79649221,0.79375655, -0.79101352,0.78826302,0.78550497,0.78273931,0.77996593,0.77718475,0.77439569,0.77159865, -0.76879355,0.76598029,0.76315878,0.76032891,0.75749061,0.75464376,0.75178826,0.74892402, -0.74605092,0.74316887,0.74027775,0.73737744,0.73446785,0.73154885,0.72862033,0.72568217, -0.72273425,0.71977644,0.71680861,0.71383064,0.71084240,0.70784376,0.70483456,0.70181469, -0.69878398,0.69574231,0.69268952,0.68962545,0.68654996,0.68346288,0.68036406,0.67725332, -0.67413051,0.67099544,0.66784794,0.66468783,0.66151492,0.65832903,0.65512997,0.65191753, -0.64869151,0.64545170,0.64219789,0.63892987,0.63564741,0.63235028,0.62903824,0.62571106, -0.62236849,0.61901027,0.61563615,0.61224585,0.60883911,0.60541564,0.60197515,0.59851735, -0.59504192,0.59154856,0.58803694,0.58450672,0.58095756,0.57738911,0.57380101,0.57019288, -0.56656433,0.56291496,0.55924437,0.55555212,0.55183778,0.54810089,0.54434099,0.54055758, -0.53675018,0.53291825,0.52906127,0.52517867,0.52126988,0.51733431,0.51337132,0.50938028, -0.50536051,0.50131132,0.49723200,0.49312177,0.48897987,0.48480547,0.48059772,0.47635573, -0.47207859,0.46776530,0.46341487,0.45902623,0.45459827,0.45012983,0.44561967,0.44106652, -0.43646903,0.43182577,0.42713525,0.42239588,0.41760600,0.41276385,0.40786755,0.40291513, -0.39790449,0.39283339,0.38769946,0.38250016,0.37723277,0.37189441,0.36648196,0.36099209, -0.35542120,0.34976542,0.34402054,0.33818204,0.33224495,0.32620390,0.32005298,0.31378574, -0.30739505,0.30087304,0.29421096,0.28739907,0.28042645,0.27328078,0.26594810,0.25841250, -0.25065566,0.24265636,0.23438976,0.22582651,0.21693146,0.20766198,0.19796546,0.18777575, -0.17700769,0.16554844,0.15324301,0.13986823,0.12508152,0.10830610,0.08841715,0.06251018, -}; - -double acos( double x ) { - int index; - - if (x < -1) - x = -1; - if (x > 1) - x = 1; - index = (float) (1.0 + x) * 511.9; - return acostable[index]; -} - - -double atan2( double y, double x ) { - float base; - float temp; - float dir; - float test; - int i; - - if ( x < 0 ) { - if ( y >= 0 ) { - // quad 1 - base = M_PI / 2; - temp = x; - x = y; - y = -temp; - } else { - // quad 2 - base = M_PI; - x = -x; - y = -y; - } - } else { - if ( y < 0 ) { - // quad 3 - base = 3 * M_PI / 2; - temp = x; - x = -y; - y = temp; - } - } - - if ( y > x ) { - base += M_PI/2; - temp = x; - x = y; - y = temp; - dir = -1; - } else { - dir = 1; - } - - // calcualte angle in octant 0 - if ( x == 0 ) { - return base; - } - y /= x; - - for ( i = 0 ; i < 512 ; i++ ) { - test = sintable[i] / sintable[1023-i]; - if ( test > y ) { - break; - } - } - - return base + dir * i * ( M_PI/2048); -} - - -#endif - -#ifdef Q3_VM -// bk001127 - guarded this tan replacement -// ld: undefined versioned symbol name tan@@GLIBC_2.0 -double tan( double x ) -{ - return sin( x ) / cos( x ); -} - -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -typedef union -{ - float value; - unsigned int word; -} ieee_float_shape_type; - -/* Get a 32 bit int from a float. */ - -#define GET_FLOAT_WORD(i,d) \ -do { \ - ieee_float_shape_type gf_u; \ - gf_u.value = (d); \ - (i) = gf_u.word; \ -} while (0) - -/* Set a float from a 32 bit int. */ - -#define SET_FLOAT_WORD(d,i) \ -do { \ - ieee_float_shape_type sf_u; \ - sf_u.word = (i); \ - (d) = sf_u.value; \ -} while (0) - -/* A union which permits us to convert between a float and a 32 bit - int. */ - -//acos -static const float -pi = 3.1415925026e+00, /* 0x40490fda */ -pio2_hi = 1.5707962513e+00, /* 0x3fc90fda */ -pio2_lo = 7.5497894159e-08, /* 0x33a22168 */ -pS0 = 1.6666667163e-01, /* 0x3e2aaaab */ -pS1 = -3.2556581497e-01, /* 0xbea6b090 */ -pS2 = 2.0121252537e-01, /* 0x3e4e0aa8 */ -pS3 = -4.0055535734e-02, /* 0xbd241146 */ -pS4 = 7.9153501429e-04, /* 0x3a4f7f04 */ -pS5 = 3.4793309169e-05, /* 0x3811ef08 */ -qS1 = -2.4033949375e+00, /* 0xc019d139 */ -qS2 = 2.0209457874e+00, /* 0x4001572d */ -qS3 = -6.8828397989e-01, /* 0xbf303361 */ -qS4 = 7.7038154006e-02; /* 0x3d9dc62e */ - -/* -================== -acos -================== -*/ -double acos( double x ) -{ - float z, subp, p, q, r, w, s, c, df; - int hx, ix; - - GET_FLOAT_WORD( hx, x ); - ix = hx & 0x7fffffff; - - if( ix == 0x3f800000 ) - { // |x|==1 - if( hx > 0 ) - return 0.0; // acos(1) = 0 - else - return pi + (float)2.0 * pio2_lo; // acos(-1)= pi - } - else if( ix > 0x3f800000 ) - { // |x| >= 1 - return (x-x)/(x-x); // acos(|x|>1) is NaN - } - - if( ix < 0x3f000000 ) - { // |x| < 0.5 - if( ix <= 0x23000000 ) - return pio2_hi + pio2_lo;//if|x|<2**-57 - - z = x * x; - subp = pS3 + z * ( pS4 + z * pS5 ); - // chop up expression to keep mac register based stack happy - p = z * ( pS0 + z * ( pS1 + z * ( pS2 + z * subp ) ) ); - q = 1.0 + z * ( qS1 + z * ( qS2 + z * ( qS3 + z * qS4 ) ) ); - r = p / q; - return pio2_hi - ( x - ( pio2_lo - x * r ) ); - } - else if( hx < 0 ) - { // x < -0.5 - z = ( 1.0 + x ) * (float)0.5; - subp = pS3 + z * ( pS4 + z * pS5 ); - // chop up expression to keep mac register based stack happy - p = z * ( pS0 + z * ( pS1 + z * ( pS2 + z * subp ) ) ); - q = 1.0 + z * ( qS1 + z * ( qS2 + z * ( qS3 + z * qS4 ) ) ); - s = sqrt( z ); - r = p / q; - w = r * s - pio2_lo; - return pi - (float)2.0 * ( s + w ); - } - else - { // x > 0.5 - int idf; - z = ( 1.0 - x ) * (float)0.5; - s = sqrt( z ); - df = s; - GET_FLOAT_WORD( idf, df ); - SET_FLOAT_WORD( df, idf & 0xfffff000 ); - c = ( z - df * df ) / ( s + df ); - subp = pS3 + z * ( pS4 + z * pS5 ); - // chop up expression to keep mac register based stack happy - p = z * ( pS0 + z * ( pS1 + z * ( pS2 + z * subp ) ) ); - q = 1.0 + z * ( qS1 + z * ( qS2 + z * ( qS3 + z * qS4 ) ) ); - r = p / q; - w = r * s + c; - return (double)( 2.0 * ( df + w ) ); - } -} - -//pow -static const float -bp[ ] = { 1.0, 1.5, }, -dp_h[ ] = { 0.0, 5.84960938e-01, }, /* 0x3f15c000 */ -dp_l[ ] = { 0.0, 1.56322085e-06, }, /* 0x35d1cfdc */ -huge = 1.0e+30, -tiny = 1.0e-30, -zero = 0.0, -one = 1.0, -two = 2.0, -two24 = 16777216.0, /* 0x4b800000 */ -two25 = 3.355443200e+07, /* 0x4c000000 */ -twom25 = 2.9802322388e-08, /* 0x33000000 */ - /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ -L1 = 6.0000002384e-01, /* 0x3f19999a */ -L2 = 4.2857143283e-01, /* 0x3edb6db7 */ -L3 = 3.3333334327e-01, /* 0x3eaaaaab */ -L4 = 2.7272811532e-01, /* 0x3e8ba305 */ -L5 = 2.3066075146e-01, /* 0x3e6c3255 */ -L6 = 2.0697501302e-01, /* 0x3e53f142 */ -P1 = 1.6666667163e-01, /* 0x3e2aaaab */ -P2 = -2.7777778450e-03, /* 0xbb360b61 */ -P3 = 6.6137559770e-05, /* 0x388ab355 */ -P4 = -1.6533901999e-06, /* 0xb5ddea0e */ -P5 = 4.1381369442e-08, /* 0x3331bb4c */ -lg2 = 6.9314718246e-01, /* 0x3f317218 */ -lg2_h = 6.93145752e-01, /* 0x3f317200 */ -lg2_l = 1.42860654e-06, /* 0x35bfbe8c */ -ovt = 4.2995665694e-08, /* -(128-log2(ovfl+.5ulp)) */ -cp = 9.6179670095e-01, /* 0x3f76384f =2/(3ln2) */ -cp_h = 9.6179199219e-01, /* 0x3f763800 =head of cp */ -cp_l = 4.7017383622e-06, /* 0x369dc3a0 =tail of cp_h */ -ivln2 = 1.4426950216e+00, /* 0x3fb8aa3b =1/ln2 */ -ivln2_h = 1.4426879883e+00, /* 0x3fb8aa00 =16b 1/ln2*/ -ivln2_l = 7.0526075433e-06; /* 0x36eca570 =1/ln2 tail*/ - -/* -================== -copysignf -================== -*/ -static float copysignf( float x, float y ) -{ - unsigned int ix, iy; - - GET_FLOAT_WORD( ix, x ); - GET_FLOAT_WORD( iy, y ); - SET_FLOAT_WORD( x, ( ix & 0x7fffffff ) | ( iy & 0x80000000 ) ); - return x; -} - -/* -================== -__scalbnf -================== -*/ -static float __scalbnf( float x, int n ) -{ - int k, ix; - - GET_FLOAT_WORD( ix, x ); - - k = ( ix & 0x7f800000 ) >> 23; /* extract exponent */ - - if( k == 0 ) - { /* 0 or subnormal x */ - if( ( ix & 0x7fffffff ) == 0 ) - return x; /* +-0 */ - - x *= two25; - GET_FLOAT_WORD( ix, x ); - k = ( ( ix & 0x7f800000 ) >> 23 ) - 25; - } - if( k == 0xff ) - return x+x; /* NaN or Inf */ - - k = k + n; - - if( n > 50000 || k > 0xfe ) - return huge * copysignf( huge, x ); /* overflow */ - if ( n < -50000 ) - return tiny * copysignf( tiny, x ); /*underflow*/ - if( k > 0 ) /* normal result */ - { - SET_FLOAT_WORD( x, ( ix & 0x807fffff ) | ( k << 23 ) ); - return x; - } - if( k <= -25 ) - return tiny * copysignf( tiny, x ); /*underflow*/ - - k += 25; /* subnormal result */ - SET_FLOAT_WORD( x, ( ix & 0x807fffff ) | ( k << 23 ) ); - return x * twom25; -} - -/* -================== -pow -================== -*/ -float pow( float x, float y ) -{ - float z, ax, z_h, z_l, p_h, p_l; - float y1, subt1, t1, t2, subr, r, s, t, u, v, w; - int i, j, k, yisint, n; - int hx, hy, ix, iy, is; - - /*TA: for some reason the Q3 VM goes apeshit when x = 1.0 - and y > 1.0. Curiously this doesn't happen with gcc - hence this hack*/ - if( x == 1.0 ) - return x; - - GET_FLOAT_WORD( hx, x ); - GET_FLOAT_WORD( hy, y ); - ix = hx & 0x7fffffff; - iy = hy & 0x7fffffff; - - /* y==zero: x**0 = 1 */ - if( iy == 0 ) - return one; - - /* +-NaN return x+y */ - if( ix > 0x7f800000 || iy > 0x7f800000 ) - return x + y; - - /* determine if y is an odd int when x < 0 - * yisint = 0 ... y is not an integer - * yisint = 1 ... y is an odd int - * yisint = 2 ... y is an even int - */ - yisint = 0; - if( hx < 0 ) - { - if( iy >= 0x4b800000 ) - yisint = 2; /* even integer y */ - else if( iy >= 0x3f800000 ) - { - k = ( iy >> 23 ) - 0x7f; /* exponent */ - j = iy >> ( 23 - k ); - if( ( j << ( 23 - k ) ) == iy ) - yisint = 2 - ( j & 1 ); - } - } - - /* special value of y */ - if( iy == 0x7f800000 ) - { /* y is +-inf */ - if( ix == 0x3f800000 ) - return y - y; /* inf**+-1 is NaN */ - else if( ix > 0x3f800000 )/* (|x|>1)**+-inf = inf,0 */ - return ( hy >= 0 ) ? y : zero; - else /* (|x|<1)**-,+inf = inf,0 */ - return ( hy < 0 ) ? -y : zero; - } - - if( iy == 0x3f800000 ) - { /* y is +-1 */ - if( hy < 0 ) - return one / x; - else - return x; - } - - if( hy == 0x40000000 ) - return x * x; /* y is 2 */ - - if( hy == 0x3f000000 ) - { /* y is 0.5 */ - if( hx >= 0 ) /* x >= +0 */ - return sqrt( x ); - } - - ax = fabs( x ); - - /* special value of x */ - if( ix == 0x7f800000 || ix == 0 || ix == 0x3f800000 ) - { - z = ax; /*x is +-0,+-inf,+-1*/ - if( hy < 0 ) - z = one / z; /* z = (1/|x|) */ - if( hx < 0 ) - { - if( ( ( ix - 0x3f800000 ) | yisint ) == 0 ) - z = ( z - z ) / ( z - z ); /* (-1)**non-int is NaN */ - else if( yisint == 1 ) - z = -z; /* (x<0)**odd = -(|x|**odd) */ - } - - return z; - } - - /* (x<0)**(non-int) is NaN */ - if( ( ( ( (unsigned int)hx >> 31 ) - 1 ) | yisint ) == 0 ) - return ( x - x ) / ( x - x ); - - /* |y| is huge */ - if( iy > 0x4d000000 ) - { /* if |y| > 2**27 */ - /* over/underflow if x is not close to one */ - if( ix < 0x3f7ffff8 ) - return ( hy < 0 ) ? huge * huge : tiny * tiny; - - if( ix > 0x3f800007 ) - return ( hy > 0 ) ? huge * huge : tiny * tiny; - /* now |1-x| is tiny <= 2**-20, suffice to compute - log(x) by x-x^2/2+x^3/3-x^4/4 */ - t = x - 1; /* t has 20 trailing zeros */ - w = ( t * t ) * ( (float)0.5 - t * ( (float)0.333333333333 - t * (float)0.25 ) ); - u = ivln2_h * t; /* ivln2_h has 16 sig. bits */ - v = t * ivln2_l - w * ivln2; - t1 = u + v; - GET_FLOAT_WORD( is, t1 ); - SET_FLOAT_WORD( t1, is & 0xfffff000 ); - t2 = v - ( t1 - u ); - } - else - { - float s2, s_h, s_l, t_h, t_l; - n = 0; - /* take care subnormal number */ - if( ix < 0x00800000 ) - { - ax *= two24; - n -= 24; - GET_FLOAT_WORD( ix, ax ); - } - - n += ( ( ix ) >> 23 ) - 0x7f; - j = ix & 0x007fffff; - - /* determine interval */ - ix = j | 0x3f800000; /* normalize ix */ - if( j <= 0x1cc471 ) - k = 0; /* |x|> 1 ) | 0x20000000 ) + 0x0040000 + ( k << 21 ) ); - t_l = ax - ( t_h - bp[ k ] ); - s_l = v * ( ( u - s_h * t_h ) - s_h * t_l ); - /* compute log(ax) */ - s2 = s * s; - subr = L3 + s2 * ( L4 + s2 * ( L5 + s2 * L6 ) ); - // chop up expression to keep mac register based stack happy - r = s2 * s2 * ( L1 + s2 * ( L2 + s2 * subr ) ); - r += s_l * ( s_h + s ); - s2 = s_h * s_h; - t_h = (float)3.0 + s2 + r; - GET_FLOAT_WORD( is, t_h ); - SET_FLOAT_WORD( t_h, is & 0xfffff000 ); - t_l = r - ( ( t_h - (float)3.0 ) - s2 ); - /* u+v = s*(1+...) */ - u = s_h * t_h; - v = s_l * t_h + t_l * s; - /* 2/(3log2)*(s+...) */ - p_h = u + v; - GET_FLOAT_WORD( is, p_h ); - SET_FLOAT_WORD( p_h, is & 0xfffff000 ); - p_l = v - ( p_h - u ); - z_h = cp_h * p_h; /* cp_h+cp_l = 2/(3*log2) */ - z_l = cp_l * p_h + p_l * cp + dp_l[ k ]; - /* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */ - t = (float)n; - t1 = ( ( ( z_h + z_l ) + dp_h[ k ] ) + t ); - GET_FLOAT_WORD( is, t1 ); - SET_FLOAT_WORD( t1, is & 0xfffff000 ); - t2 = z_l - ( ( ( t1 - t ) - dp_h[ k ] ) - z_h ); - } - - s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ - if( ( ( ( (unsigned int)hx >> 31 ) - 1 ) | ( yisint - 1 ) ) == 0 ) - s = -one; /* (-ve)**(odd int) */ - - /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ - GET_FLOAT_WORD( is, y ); - SET_FLOAT_WORD( y1, is & 0xfffff000 ); - p_l = ( y - y1 ) * t1 + y * t2; - p_h = y1 * t1; - z = p_l + p_h; - GET_FLOAT_WORD( j, z ); - - if( j > 0x43000000 ) /* if z > 128 */ - return s * huge * huge; /* overflow */ - else if( j == 0x43000000 ) - { /* if z == 128 */ - if( p_l + ovt > z - p_h ) - return s * huge * huge; /* overflow */ - } - else if( ( j & 0x7fffffff ) > 0x43160000 ) /* z <= -150 */ - return s * tiny * tiny; /* underflow */ - else if( (unsigned int)j == 0xc3160000 ) - { /* z == -150 */ - if( p_l <= z - p_h ) - return s * tiny * tiny; /* underflow */ - } - - /* - * compute 2**(p_h+p_l) - */ - i = j & 0x7fffffff; - k = ( i >> 23 ) - 0x7f; - n = 0; - - if( i > 0x3f000000 ) - { /* if |z| > 0.5, set n = [z+0.5] */ - n = j + ( 0x00800000 >> ( k + 1 ) ); - k = ( ( n & 0x7fffffff ) >> 23 ) - 0x7f; /* new k for n */ - SET_FLOAT_WORD( t, n & ~( 0x007fffff >> k ) ); - n = ( ( n & 0x007fffff ) | 0x00800000 ) >> ( 23 - k ); - - if( j < 0 ) - n = -n; - - p_h -= t; - } - - t = p_l + p_h; - GET_FLOAT_WORD( is, t ); - SET_FLOAT_WORD( t, is & 0xfffff000 ); - u = t * lg2_h; - v = ( p_l - ( t - p_h ) ) * lg2 + t * lg2_l; - z = u + v; - w = v - ( z - u ); - t = z * z; - subt1 = P3 + t * ( P4 + t * P5 ); - // chop up expression to keep mac register based stack happy - t1 = z - t * ( P1 + t * ( P2 + t * subt1 ) ); - r = ( z * t1 ) / ( t1 - two ) - ( w + z * w ); - z = one - ( r - z ); - GET_FLOAT_WORD( j, z ); - j += (n << 23 ); - - if( ( j >> 23 ) <= 0 ) - z = __scalbnf( z, n ); /* subnormal output */ - else - SET_FLOAT_WORD( z, j ); - - return s * z; -} - -#endif - - - -static int randSeed = 0; - -void srand( unsigned seed ) -{ - randSeed = seed; -} - -int rand( void ) -{ - randSeed = ( 69069 * randSeed + 1 ); - return randSeed & 0x7fff; -} - -double atof( const char *string ) -{ - float sign; - float value; - int c; - - // skip whitespace - while( *string <= ' ' ) - { - if( !*string ) - return 0; - - string++; - } - - // check sign - switch( *string ) - { - case '+': - string++; - sign = 1; - break; - - case '-': - string++; - sign = -1; - break; - - default: - sign = 1; - break; - } - - // read digits - value = 0; - c = string[ 0 ]; - - if( c != '.' ) - { - do - { - c = *string++; - if( c < '0' || c > '9' ) - break; - - c -= '0'; - value = value * 10 + c; - } while( 1 ); - } - else - string++; - - // check for decimal point - if( c == '.' ) - { - double fraction; - - fraction = 0.1; - do - { - c = *string++; - if( c < '0' || c > '9' ) - break; - - c -= '0'; - value += c * fraction; - fraction *= 0.1; - } while( 1 ); - - } - - // not handling 10e10 notation... - - return value * sign; -} - -double _atof( const char **stringPtr ) -{ - const char *string; - float sign; - float value; - int c = '0'; // bk001211 - uninitialized use possible - - string = *stringPtr; - - // skip whitespace - while( *string <= ' ' ) - { - if( !*string ) - { - *stringPtr = string; - return 0; - } - - string++; - } - - // check sign - switch( *string ) - { - case '+': - string++; - sign = 1; - break; - - case '-': - string++; - sign = -1; - break; - - default: - sign = 1; - break; - } - - // read digits - value = 0; - if( string[ 0 ] != '.' ) - { - do - { - c = *string++; - if( c < '0' || c > '9' ) - break; - - c -= '0'; - value = value * 10 + c; - } while( 1 ); - } - - // check for decimal point - if( c == '.' ) - { - double fraction; - - fraction = 0.1; - do - { - c = *string++; - if( c < '0' || c > '9' ) - break; - - c -= '0'; - value += c * fraction; - fraction *= 0.1; - } while( 1 ); - - } - - // not handling 10e10 notation... - *stringPtr = string; - - return value * sign; -} - - -#if defined ( Q3_VM ) - -int atoi( const char *string ) -{ - int sign; - int value; - int c; - - // skip whitespace - while( *string <= ' ' ) - { - if( !*string ) - return 0; - - string++; - } - - // check sign - switch( *string ) - { - case '+': - string++; - sign = 1; - break; - - case '-': - string++; - sign = -1; - break; - - default: - sign = 1; - break; - } - - // read digits - value = 0; - do - { - c = *string++; - if( c < '0' || c > '9' ) - break; - - c -= '0'; - value = value * 10 + c; - } while( 1 ); - - // not handling 10e10 notation... - - return value * sign; -} - - -int _atoi( const char **stringPtr ) -{ - int sign; - int value; - int c; - const char *string; - - string = *stringPtr; - - // skip whitespace - while( *string <= ' ' ) - { - if( !*string ) - return 0; - - string++; - } - - // check sign - switch( *string ) - { - case '+': - string++; - sign = 1; - break; - - case '-': - string++; - sign = -1; - break; - - default: - sign = 1; - break; - } - - // read digits - value = 0; - do - { - c = *string++; - if( c < '0' || c > '9' ) - break; - - c -= '0'; - value = value * 10 + c; - } while( 1 ); - - // not handling 10e10 notation... - - *stringPtr = string; - - return value * sign; -} - -int abs( int n ) -{ - return n < 0 ? -n : n; -} - -double fabs( double x ) -{ - return x < 0 ? -x : x; -} - - - -//========================================================= - - -#define ALT 0x00000001 /* alternate form */ -#define HEXPREFIX 0x00000002 /* add 0x or 0X prefix */ -#define LADJUST 0x00000004 /* left adjustment */ -#define LONGDBL 0x00000008 /* long double */ -#define LONGINT 0x00000010 /* long integer */ -#define QUADINT 0x00000020 /* quad integer */ -#define SHORTINT 0x00000040 /* short integer */ -#define ZEROPAD 0x00000080 /* zero (as opposed to blank) pad */ -#define FPT 0x00000100 /* floating point number */ - -#define to_digit(c) ((c) - '0') -#define is_digit(c) ((unsigned)to_digit(c) <= 9) -#define to_char(n) ((n) + '0') - -void AddInt( char **buf_p, int val, int width, int flags ) -{ - char text[ 32 ]; - int digits; - int signedVal; - char *buf; - - digits = 0; - signedVal = val; - if( val < 0 ) - val = -val; - - do - { - text[ digits++ ] = '0' + val % 10; - val /= 10; - } while( val ); - - if( signedVal < 0 ) - text[ digits++ ] = '-'; - - buf = *buf_p; - - if( !( flags & LADJUST ) ) - { - while( digits < width ) - { - *buf++ = ( flags & ZEROPAD ) ? '0' : ' '; - width--; - } - } - - while( digits-- ) - { - *buf++ = text[ digits ]; - width--; - } - - if( flags & LADJUST ) - { - while( width-- ) - *buf++ = ( flags & ZEROPAD ) ? '0' : ' '; - } - - *buf_p = buf; -} - -void AddFloat( char **buf_p, float fval, int width, int prec ) -{ - char text[ 32 ]; - int digits; - float signedVal; - char *buf; - int val; - - // get the sign - signedVal = fval; - if( fval < 0 ) - fval = -fval; - - // write the float number - digits = 0; - val = (int)fval; - - do - { - text[ digits++ ] = '0' + val % 10; - val /= 10; - } while( val ); - - if( signedVal < 0 ) - text[digits++] = '-'; - - buf = *buf_p; - - while( digits < width ) - *buf++ = ' '; - width--; - - while( digits-- ) - *buf++ = text[ digits ]; - - *buf_p = buf; - - if( prec < 0 ) - prec = 6; - - // write the fraction - digits = 0; - - while( digits < prec ) - { - fval -= (int)fval; - fval *= 10.0; - val = (int)fval; - text[ digits++ ] = '0' + val % 10; - } - - if( digits > 0 ) - { - buf = *buf_p; - *buf++ = '.'; - for( prec = 0; prec < digits; prec++ ) - *buf++ = text[ prec ]; - - *buf_p = buf; - } -} - -void AddVec3_t( char **buf_p, vec3_t v, int width, int prec ) -{ - char *buf; - - buf = *buf_p; - - *buf++ = '['; - - AddFloat( &buf, v[ 0 ], width, prec ); - buf += width; - *buf++ = ' '; - - AddFloat( &buf, v[ 1 ], width, prec ); - buf += width; - *buf++ = ' '; - - AddFloat( &buf, v[ 2 ], width, prec ); - buf += width; - *buf++ = ']'; - - *buf_p = buf; -} - -void AddString( char **buf_p, char *string, int width, int prec ) -{ - int size; - char *buf; - - buf = *buf_p; - - if( string == NULL ) - { - string = "(null)"; - prec = -1; - } - - if( prec >= 0 ) - { - for( size = 0; size < prec; size++ ) - { - if( string[ size ] == '\0' ) - break; - } - } - else - size = strlen( string ); - - width -= size; - - while( size-- ) - *buf++ = *string++; - - while( width-- > 0 ) - *buf++ = ' '; - - *buf_p = buf; -} - -/* -vsprintf - -I'm not going to support a bunch of the more arcane stuff in here -just to keep it simpler. For example, the '*' and '$' are not -currently supported. I've tried to make it so that it will just -parse and ignore formats we don't support. -*/ -int vsprintf( char *buffer, const char *fmt, va_list argptr ) -{ - int *arg; - char *buf_p; - char ch; - int flags; - int width; - int prec; - int n; - char sign; - - buf_p = buffer; - arg = (int *)argptr; - - while( qtrue ) - { - // run through the format string until we hit a '%' or '\0' - for( ch = *fmt; ( ch = *fmt ) != '\0' && ch != '%'; fmt++ ) - *buf_p++ = ch; - - if( ch == '\0' ) - goto done; - - // skip over the '%' - fmt++; - - // reset formatting state - flags = 0; - width = 0; - prec = -1; - sign = '\0'; - -rflag: - ch = *fmt++; -reswitch: - switch( ch ) - { - case '-': - flags |= LADJUST; - goto rflag; - - case '.': - n = 0; - while( is_digit( ( ch = *fmt++ ) ) ) - n = 10 * n + ( ch - '0' ); - - prec = n < 0 ? -1 : n; - goto reswitch; - - case '0': - flags |= ZEROPAD; - goto rflag; - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - n = 0; - do - { - n = 10 * n + ( ch - '0' ); - ch = *fmt++; - } while( is_digit( ch ) ); - - width = n; - goto reswitch; - - case 'c': - *buf_p++ = (char)*arg; - arg++; - break; - - case 'd': - case 'i': - AddInt( &buf_p, *arg, width, flags ); - arg++; - break; - - case 'f': - AddFloat( &buf_p, *(double *)arg, width, prec ); -#ifdef Q3_VM - arg += 1; // everything is 32 bit in my compiler -#else - arg += 2; -#endif - break; - - case 's': - AddString( &buf_p, (char *)*arg, width, prec ); - arg++; - break; - - case 'v': - AddVec3_t( &buf_p, (vec_t *)*arg, width, prec ); - arg++; - break; - - case '%': - *buf_p++ = ch; - break; - - default: - *buf_p++ = (char)*arg; - arg++; - break; - } - } - -done: - *buf_p = 0; - return buf_p - buffer; -} - - -/* this is really crappy */ -int sscanf( const char *buffer, const char *fmt, ... ) -{ - int cmd; - int **arg; - int count; - - arg = (int **)&fmt + 1; - count = 0; - - while( *fmt ) - { - if( fmt[ 0 ] != '%' ) - { - fmt++; - continue; - } - - cmd = fmt[ 1 ]; - fmt += 2; - - switch( cmd ) - { - case 'i': - case 'd': - case 'u': - **arg = _atoi( &buffer ); - break; - case 'f': - *(float *)*arg = _atof( &buffer ); - break; - } - - arg++; - } - - return count; -} - -#endif diff --git a/src/game/bg_lib.h b/src/game/bg_lib.h deleted file mode 100644 index 61d64025..00000000 --- a/src/game/bg_lib.h +++ /dev/null @@ -1,92 +0,0 @@ -// 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 - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -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 ); - -#endif // BG_LIB_H diff --git a/src/game/bg_local.h b/src/game/bg_local.h deleted file mode 100644 index 7e5ea46f..00000000 --- a/src/game/bg_local.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_local.h -- local definitions for the bg (both games) files - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#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 ); diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c deleted file mode 100644 index 727190af..00000000 --- a/src/game/bg_misc.c +++ /dev/null @@ -1,5248 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_misc.c -- both games misc functions, all completely stateless - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "q_shared.h" -#include "bg_public.h" - -int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ); -void trap_FS_Read( void *buffer, int len, fileHandle_t f ); -void trap_FS_Write( const void *buffer, int len, fileHandle_t f ); -void trap_FS_FCloseFile( fileHandle_t f ); -void trap_FS_Seek( fileHandle_t f, long offset, fsOrigin_t origin ); // fsOrigin_t - -buildableAttributes_t bg_buildableList[ ] = -{ - { - BA_A_SPAWN, //int buildNum; - "eggpod", //char *buildName; - "Egg", //char *humanName; - "team_alien_spawn", //char *entityName; - { "models/buildables/eggpod/eggpod.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -15, -15, -15 }, //vec3_t mins; - { 15, 15, 15 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - ASPAWN_BP, //int buildPoints; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - ASPAWN_HEALTH, //int health; - ASPAWN_REGEN, //int regenRate; - ASPAWN_SPLASHDAMAGE, //int splashDamage; - ASPAWN_SPLASHRADIUS, //int splashRadius; - MOD_ASPAWN, //int meansOfDeath; - BIT_ALIENS, //int team; - ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 100, //int nextthink; - ASPAWN_BT, //int buildTime; - qfalse, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_NONE, //weapon_t turretProjType; - 0.5f, //float minNormal; - qtrue, //qboolean invertNormal; - qfalse, //qboolean creepTest; - ASPAWN_CREEPSIZE, //int creepSize; - qfalse, //qboolean dccTest; - qfalse //qboolean reactorTest; - }, - { - BA_A_BARRICADE, //int buildNum; - "barricade", //char *buildName; - "Barricade", //char *humanName; - "team_alien_barricade",//char *entityName; - { "models/buildables/barricade/barricade.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -35, -35, -15 }, //vec3_t mins; - { 35, 35, 60 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - BARRICADE_BP, //int buildPoints; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - BARRICADE_HEALTH, //int health; - BARRICADE_REGEN, //int regenRate; - BARRICADE_SPLASHDAMAGE,//int splashDamage; - BARRICADE_SPLASHRADIUS,//int splashRadius; - MOD_ASPAWN, //int meansOfDeath; - BIT_ALIENS, //int team; - ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 100, //int nextthink; - BARRICADE_BT, //int buildTime; - qfalse, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_NONE, //weapon_t turretProjType; - 0.707f, //float minNormal; - qfalse, //qboolean invertNormal; - qtrue, //qboolean creepTest; - BARRICADE_CREEPSIZE, //int creepSize; - qfalse, //qboolean dccTest; - qfalse //qboolean reactorTest; - }, - { - BA_A_BOOSTER, //int buildNum; - "booster", //char *buildName; - "Booster", //char *humanName; - "team_alien_booster", //char *entityName; - { "models/buildables/booster/booster.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -26, -26, -9 }, //vec3_t mins; - { 26, 26, 9 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - BOOSTER_BP, //int buildPoints; - ( 1 << S2 )|( 1 << S3 ), //int stages - BOOSTER_HEALTH, //int health; - BOOSTER_REGEN, //int regenRate; - BOOSTER_SPLASHDAMAGE, //int splashDamage; - BOOSTER_SPLASHRADIUS, //int splashRadius; - MOD_ASPAWN, //int meansOfDeath; - BIT_ALIENS, //int team; - ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 100, //int nextthink; - BOOSTER_BT, //int buildTime; - qfalse, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_NONE, //weapon_t turretProjType; - 0.707f, //float minNormal; - qfalse, //qboolean invertNormal; - qtrue, //qboolean creepTest; - BOOSTER_CREEPSIZE, //int creepSize; - qfalse, //qboolean dccTest; - qfalse //qboolean reactorTest; - }, - { - BA_A_ACIDTUBE, //int buildNum; - "acid_tube", //char *buildName; - "Acid Tube", //char *humanName; - "team_alien_acid_tube",//char *entityName; - { "models/buildables/acid_tube/acid_tube.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -25, -25, -25 }, //vec3_t mins; - { 25, 25, 25 }, //vec3_t maxs; - -15.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - ACIDTUBE_BP, //int buildPoints; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - ACIDTUBE_HEALTH, //int health; - ACIDTUBE_REGEN, //int regenRate; - ACIDTUBE_SPLASHDAMAGE, //int splashDamage; - ACIDTUBE_SPLASHRADIUS, //int splashRadius; - MOD_ATUBE, //int meansOfDeath; - BIT_ALIENS, //int team; - ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 200, //int nextthink; - ACIDTUBE_BT, //int buildTime; - qfalse, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_NONE, //weapon_t turretProjType; - 0.0f, //float minNormal; - qtrue, //qboolean invertNormal; - qtrue, //qboolean creepTest; - ACIDTUBE_CREEPSIZE, //int creepSize; - qfalse, //qboolean dccTest; - qfalse //qboolean reactorTest; - }, - { - BA_A_HIVE, //int buildNum; - "hive", //char *buildName; - "Hive", //char *humanName; - "team_alien_hive", //char *entityName; - { "models/buildables/acid_tube/acid_tube.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -35, -35, -25 }, //vec3_t mins; - { 35, 35, 25 }, //vec3_t maxs; - -15.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - HIVE_BP, //int buildPoints; - ( 1 << S3 ), //int stages - HIVE_HEALTH, //int health; - HIVE_REGEN, //int regenRate; - HIVE_SPLASHDAMAGE, //int splashDamage; - HIVE_SPLASHRADIUS, //int splashRadius; - MOD_ASPAWN, //int meansOfDeath; - BIT_ALIENS, //int team; - ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 500, //int nextthink; - HIVE_BT, //int buildTime; - qfalse, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_HIVE, //weapon_t turretProjType; - 0.0f, //float minNormal; - qtrue, //qboolean invertNormal; - qtrue, //qboolean creepTest; - HIVE_CREEPSIZE, //int creepSize; - qfalse, //qboolean dccTest; - qfalse //qboolean reactorTest; - }, - { - BA_A_TRAPPER, //int buildNum; - "trapper", //char *buildName; - "Trapper", //char *humanName; - "team_alien_trapper", //char *entityName; - { "models/buildables/trapper/trapper.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -15, -15, -15 }, //vec3_t mins; - { 15, 15, 15 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - TRAPPER_BP, //int buildPoints; - ( 1 << S2 )|( 1 << S3 ), //int stages //NEEDS ADV BUILDER SO S2 AND UP - TRAPPER_HEALTH, //int health; - TRAPPER_REGEN, //int regenRate; - TRAPPER_SPLASHDAMAGE, //int splashDamage; - TRAPPER_SPLASHRADIUS, //int splashRadius; - MOD_ASPAWN, //int meansOfDeath; - BIT_ALIENS, //int team; - ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 100, //int nextthink; - TRAPPER_BT, //int buildTime; - qfalse, //qboolean usable; - TRAPPER_RANGE, //int turretRange; - TRAPPER_REPEAT, //int turretFireSpeed; - WP_LOCKBLOB_LAUNCHER, //weapon_t turretProjType; - 0.0f, //float minNormal; - qtrue, //qboolean invertNormal; - qtrue, //qboolean creepTest; - TRAPPER_CREEPSIZE, //int creepSize; - qfalse, //qboolean dccTest; - qfalse //qboolean reactorTest; - }, - { - BA_A_OVERMIND, //int buildNum; - "overmind", //char *buildName; - "Overmind", //char *humanName; - "team_alien_overmind", //char *entityName; - { "models/buildables/overmind/overmind.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -45, -45, -15 }, //vec3_t mins; - { 45, 45, 95 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - OVERMIND_BP, //int buildPoints; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - OVERMIND_HEALTH, //int health; - OVERMIND_REGEN, //int regenRate; - OVERMIND_SPLASHDAMAGE, //int splashDamage; - OVERMIND_SPLASHRADIUS, //int splashRadius; - MOD_ASPAWN, //int meansOfDeath; - BIT_ALIENS, //int team; - ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - OVERMIND_ATTACK_REPEAT,//int nextthink; - OVERMIND_BT, //int buildTime; - qfalse, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_NONE, //weapon_t turretProjType; - 0.95f, //float minNormal; - qfalse, //qboolean invertNormal; - qfalse, //qboolean creepTest; - OVERMIND_CREEPSIZE, //int creepSize; - qfalse, //qboolean dccTest; - qtrue //qboolean reactorTest; - }, - { - BA_A_HOVEL, //int buildNum; - "hovel", //char *buildName; - "Hovel", //char *humanName; - "team_alien_hovel", //char *entityName; - { "models/buildables/hovel/hovel.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -50, -50, -20 }, //vec3_t mins; - { 50, 50, 20 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - HOVEL_BP, //int buildPoints; - ( 1 << S3 ), //int stages - HOVEL_HEALTH, //int health; - HOVEL_REGEN, //int regenRate; - HOVEL_SPLASHDAMAGE, //int splashDamage; - HOVEL_SPLASHRADIUS, //int splashRadius; - MOD_ASPAWN, //int meansOfDeath; - BIT_ALIENS, //int team; - ( 1 << WP_ABUILD )|( 1 << WP_ABUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 150, //int nextthink; - HOVEL_BT, //int buildTime; - qtrue, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_NONE, //weapon_t turretProjType; - 0.95f, //float minNormal; - qfalse, //qboolean invertNormal; - qtrue, //qboolean creepTest; - HOVEL_CREEPSIZE, //int creepSize; - qfalse, //qboolean dccTest; - qtrue //qboolean reactorTest; - }, - { - BA_H_SPAWN, //int buildNum; - "telenode", //char *buildName; - "Telenode", //char *humanName; - "team_human_spawn", //char *entityName; - { "models/buildables/telenode/telenode.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -40, -40, -4 }, //vec3_t mins; - { 40, 40, 4 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - HSPAWN_BP, //int buildPoints; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - HSPAWN_HEALTH, //int health; - 0, //int regenRate; - HSPAWN_SPLASHDAMAGE, //int splashDamage; - HSPAWN_SPLASHRADIUS, //int splashRadius; - MOD_HSPAWN, //int meansOfDeath; - BIT_HUMANS, //int team; - ( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 100, //int nextthink; - HSPAWN_BT, //int buildTime; - qfalse, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_NONE, //weapon_t turretProjType; - 0.95f, //float minNormal; - qfalse, //qboolean invertNormal; - qfalse, //qboolean creepTest; - 0, //int creepSize; - qfalse, //qboolean dccTest; - qfalse //qboolean reactorTest; - }, - { - BA_H_MEDISTAT, //int buildNum; - "medistat", //char *buildName; - "Medistation", //char *humanName; - "team_human_medistat", //char *entityName; - { "models/buildables/medistat/medistat.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -35, -35, -7 }, //vec3_t mins; - { 35, 35, 7 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - MEDISTAT_BP, //int buildPoints; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - MEDISTAT_HEALTH, //int health; - 0, //int regenRate; - MEDISTAT_SPLASHDAMAGE, //int splashDamage; - MEDISTAT_SPLASHRADIUS, //int splashRadius; - MOD_HSPAWN, //int meansOfDeath; - BIT_HUMANS, //int team; - ( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 100, //int nextthink; - MEDISTAT_BT, //int buildTime; - qfalse, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_NONE, //weapon_t turretProjType; - 0.95f, //float minNormal; - qfalse, //qboolean invertNormal; - qfalse, //qboolean creepTest; - 0, //int creepSize; - qfalse, //qboolean dccTest; - qfalse //qboolean reactorTest; - }, - { - BA_H_MGTURRET, //int buildNum; - "mgturret", //char *buildName; - "Machinegun Turret", //char *humanName; - "team_human_mgturret", //char *entityName; - { "models/buildables/mgturret/turret_base.md3", - "models/buildables/mgturret/turret_barrel.md3", - "models/buildables/mgturret/turret_top.md3", 0 }, - 1.0f, //float modelScale; - { -25, -25, -20 }, //vec3_t mins; - { 25, 25, 20 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - MGTURRET_BP, //int buildPoints; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - MGTURRET_HEALTH, //int health; - 0, //int regenRate; - MGTURRET_SPLASHDAMAGE, //int splashDamage; - MGTURRET_SPLASHRADIUS, //int splashRadius; - MOD_HSPAWN, //int meansOfDeath; - BIT_HUMANS, //int team; - ( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 50, //int nextthink; - MGTURRET_BT, //int buildTime; - qfalse, //qboolean usable; - MGTURRET_RANGE, //int turretRange; - MGTURRET_REPEAT, //int turretFireSpeed; - WP_MGTURRET, //weapon_t turretProjType; - 0.95f, //float minNormal; - qfalse, //qboolean invertNormal; - qfalse, //qboolean creepTest; - 0, //int creepSize; - qfalse, //qboolean dccTest; - qfalse //qboolean reactorTest; - }, - { - BA_H_TESLAGEN, //int buildNum; - "tesla", //char *buildName; - "Tesla Generator", //char *humanName; - "team_human_tesla", //char *entityName; - { "models/buildables/tesla/tesla.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -22, -22, -40 }, //vec3_t mins; - { 22, 22, 40 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - TESLAGEN_BP, //int buildPoints; - ( 1 << S3 ), //int stages - TESLAGEN_HEALTH, //int health; - 0, //int regenRate; - TESLAGEN_SPLASHDAMAGE, //int splashDamage; - TESLAGEN_SPLASHRADIUS, //int splashRadius; - MOD_HSPAWN, //int meansOfDeath; - BIT_HUMANS, //int team; - ( 1 << WP_HBUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 150, //int nextthink; - TESLAGEN_BT, //int buildTime; - qfalse, //qboolean usable; - TESLAGEN_RANGE, //int turretRange; - TESLAGEN_REPEAT, //int turretFireSpeed; - WP_TESLAGEN, //weapon_t turretProjType; - 0.95f, //float minNormal; - qfalse, //qboolean invertNormal; - qfalse, //qboolean creepTest; - 0, //int creepSize; - qtrue, //qboolean dccTest; - qfalse //qboolean reactorTest; - }, - { - BA_H_DCC, //int buildNum; - "dcc", //char *buildName; - "Defence Computer", //char *humanName; - "team_human_dcc", //char *entityName; - { "models/buildables/dcc/dcc.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -35, -35, -13 }, //vec3_t mins; - { 35, 35, 47 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - DC_BP, //int buildPoints; - ( 1 << S2 )|( 1 << S3 ), //int stages - DC_HEALTH, //int health; - 0, //int regenRate; - DC_SPLASHDAMAGE, //int splashDamage; - DC_SPLASHRADIUS, //int splashRadius; - MOD_HSPAWN, //int meansOfDeath; - BIT_HUMANS, //int team; - ( 1 << WP_HBUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 100, //int nextthink; - DC_BT, //int buildTime; - qfalse, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_NONE, //weapon_t turretProjType; - 0.95f, //float minNormal; - qfalse, //qboolean invertNormal; - qfalse, //qboolean creepTest; - 0, //int creepSize; - qfalse, //qboolean dccTest; - qfalse //qboolean reactorTest; - }, - { - BA_H_ARMOURY, //int buildNum; - "arm", //char *buildName; - "Armoury", //char *humanName; - "team_human_armoury", //char *entityName; - { "models/buildables/arm/arm.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -40, -40, -13 }, //vec3_t mins; - { 40, 40, 50 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - ARMOURY_BP, //int buildPoints; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - ARMOURY_HEALTH, //int health; - 0, //int regenRate; - ARMOURY_SPLASHDAMAGE, //int splashDamage; - ARMOURY_SPLASHRADIUS, //int splashRadius; - MOD_HSPAWN, //int meansOfDeath; - BIT_HUMANS, //int team; - ( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 100, //int nextthink; - ARMOURY_BT, //int buildTime; - qtrue, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_NONE, //weapon_t turretProjType; - 0.95f, //float minNormal; - qfalse, //qboolean invertNormal; - qfalse, //qboolean creepTest; - 0, //int creepSize; - qfalse, //qboolean dccTest; - qfalse //qboolean reactorTest; - }, - { - BA_H_REACTOR, //int buildNum; - "reactor", //char *buildName; - "Reactor", //char *humanName; - "team_human_reactor", //char *entityName; - { "models/buildables/reactor/reactor.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -50, -50, -15 }, //vec3_t mins; - { 50, 50, 95 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - REACTOR_BP, //int buildPoints; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - REACTOR_HEALTH, //int health; - 0, //int regenRate; - REACTOR_SPLASHDAMAGE, //int splashDamage; - REACTOR_SPLASHRADIUS, //int splashRadius; - MOD_HSPAWN, //int meansOfDeath; - BIT_HUMANS, //int team; - ( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - REACTOR_ATTACK_REPEAT, //int nextthink; - REACTOR_BT, //int buildTime; - qtrue, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_NONE, //weapon_t turretProjType; - 0.95f, //float minNormal; - qfalse, //qboolean invertNormal; - qfalse, //qboolean creepTest; - 0, //int creepSize; - qfalse, //qboolean dccTest; - qtrue //qboolean reactorTest; - }, - { - BA_H_REPEATER, //int buildNum; - "repeater", //char *buildName; - "Repeater", //char *humanName; - "team_human_repeater", //char *entityName; - { "models/buildables/repeater/repeater.md3", 0, 0, 0 }, - 1.0f, //float modelScale; - { -15, -15, -15 }, //vec3_t mins; - { 15, 15, 25 }, //vec3_t maxs; - 0.0f, //float zOffset; - TR_GRAVITY, //trType_t traj; - 0.0, //float bounce; - REPEATER_BP, //int buildPoints; - ( 1 << S2 )|( 1 << S3 ), //int stages - REPEATER_HEALTH, //int health; - 0, //int regenRate; - REPEATER_SPLASHDAMAGE, //int splashDamage; - REPEATER_SPLASHRADIUS, //int splashRadius; - MOD_HSPAWN, //int meansOfDeath; - BIT_HUMANS, //int team; - ( 1 << WP_HBUILD )|( 1 << WP_HBUILD2 ), //weapon_t buildWeapon; - BANIM_IDLE1, //int idleAnim; - 100, //int nextthink; - REPEATER_BT, //int buildTime; - qtrue, //qboolean usable; - 0, //int turretRange; - 0, //int turretFireSpeed; - WP_NONE, //weapon_t turretProjType; - 0.95f, //float minNormal; - qfalse, //qboolean invertNormal; - qfalse, //qboolean creepTest; - 0, //int creepSize; - qfalse, //qboolean dccTest; - qfalse //qboolean reactorTest; - } -}; - -int bg_numBuildables = sizeof( bg_buildableList ) / sizeof( bg_buildableList[ 0 ] ); - -//separate from bg_buildableList to work around char struct init bug -buildableAttributeOverrides_t bg_buildableOverrideList[ BA_NUM_BUILDABLES ]; - -/* -============== -BG_FindBuildNumForName -============== -*/ -int BG_FindBuildNumForName( char *name ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( !Q_stricmp( bg_buildableList[ i ].buildName, name ) ) - return bg_buildableList[ i ].buildNum; - } - - //wimp out - return BA_NONE; -} - -/* -============== -BG_FindBuildNumForEntityName -============== -*/ -int BG_FindBuildNumForEntityName( char *name ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( !Q_stricmp( bg_buildableList[ i ].entityName, name ) ) - return bg_buildableList[ i ].buildNum; - } - - //wimp out - return BA_NONE; -} - -/* -============== -BG_FindNameForBuildNum -============== -*/ -char *BG_FindNameForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - return bg_buildableList[ i ].buildName; - } - - //wimp out - return 0; -} - -/* -============== -BG_FindHumanNameForBuildNum -============== -*/ -char *BG_FindHumanNameForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - return bg_buildableList[ i ].humanName; - } - - //wimp out - return 0; -} - -/* -============== -BG_FindEntityNameForBuildNum -============== -*/ -char *BG_FindEntityNameForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - return bg_buildableList[ i ].entityName; - } - - //wimp out - return 0; -} - -/* -============== -BG_FindModelsForBuildNum -============== -*/ -char *BG_FindModelsForBuildable( int bclass, int modelNum ) -{ - int i; - - if( bg_buildableOverrideList[ bclass ].models[ modelNum ][ 0 ] != 0 ) - return bg_buildableOverrideList[ bclass ].models[ modelNum ]; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - return bg_buildableList[ i ].models[ modelNum ]; - } - - //wimp out - return 0; -} - -/* -============== -BG_FindModelScaleForBuildable -============== -*/ -float BG_FindModelScaleForBuildable( int bclass ) -{ - int i; - - if( bg_buildableOverrideList[ bclass ].modelScale != 0.0f ) - return bg_buildableOverrideList[ bclass ].modelScale; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - return bg_buildableList[ i ].modelScale; - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindModelScaleForBuildable( %d )\n", bclass ); - return 1.0f; -} - -/* -============== -BG_FindBBoxForBuildable -============== -*/ -void BG_FindBBoxForBuildable( int bclass, vec3_t mins, vec3_t maxs ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - if( mins != NULL ) - { - VectorCopy( bg_buildableList[ i ].mins, mins ); - - if( VectorLength( bg_buildableOverrideList[ bclass ].mins ) ) - VectorCopy( bg_buildableOverrideList[ bclass ].mins, mins ); - } - - if( maxs != NULL ) - { - VectorCopy( bg_buildableList[ i ].maxs, maxs ); - - if( VectorLength( bg_buildableOverrideList[ bclass ].maxs ) ) - VectorCopy( bg_buildableOverrideList[ bclass ].maxs, maxs ); - } - - return; - } - } - - if( mins != NULL ) - VectorCopy( bg_buildableList[ 0 ].mins, mins ); - - if( maxs != NULL ) - VectorCopy( bg_buildableList[ 0 ].maxs, maxs ); -} - -/* -============== -BG_FindZOffsetForBuildable -============== -*/ -float BG_FindZOffsetForBuildable( int bclass ) -{ - int i; - - if( bg_buildableOverrideList[ bclass ].zOffset != 0.0f ) - return bg_buildableOverrideList[ bclass ].zOffset; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].zOffset; - } - } - - return 0.0f; -} - -/* -============== -BG_FindTrajectoryForBuildable -============== -*/ -trType_t BG_FindTrajectoryForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].traj; - } - } - - return TR_GRAVITY; -} - -/* -============== -BG_FindBounceForBuildable -============== -*/ -float BG_FindBounceForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].bounce; - } - } - - return 0.0; -} - -/* -============== -BG_FindBuildPointsForBuildable -============== -*/ -int BG_FindBuildPointsForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].buildPoints; - } - } - - return 1000; -} - -/* -============== -BG_FindStagesForBuildable -============== -*/ -qboolean BG_FindStagesForBuildable( int bclass, stage_t stage ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - if( bg_buildableList[ i ].stages & ( 1 << stage ) ) - return qtrue; - else - return qfalse; - } - } - - return qfalse; -} - -/* -============== -BG_FindHealthForBuildable -============== -*/ -int BG_FindHealthForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].health; - } - } - - return 1000; -} - -/* -============== -BG_FindRegenRateForBuildable -============== -*/ -int BG_FindRegenRateForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].regenRate; - } - } - - return 0; -} - -/* -============== -BG_FindSplashDamageForBuildable -============== -*/ -int BG_FindSplashDamageForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].splashDamage; - } - } - - return 50; -} - -/* -============== -BG_FindSplashRadiusForBuildable -============== -*/ -int BG_FindSplashRadiusForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].splashRadius; - } - } - - return 200; -} - -/* -============== -BG_FindMODForBuildable -============== -*/ -int BG_FindMODForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].meansOfDeath; - } - } - - return MOD_UNKNOWN; -} - -/* -============== -BG_FindTeamForBuildable -============== -*/ -int BG_FindTeamForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].team; - } - } - - return BIT_NONE; -} - -/* -============== -BG_FindBuildWeaponForBuildable -============== -*/ -weapon_t BG_FindBuildWeaponForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].buildWeapon; - } - } - - return BA_NONE; -} - -/* -============== -BG_FindAnimForBuildable -============== -*/ -int BG_FindAnimForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].idleAnim; - } - } - - return BANIM_IDLE1; -} - -/* -============== -BG_FindNextThinkForBuildable -============== -*/ -int BG_FindNextThinkForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].nextthink; - } - } - - return 100; -} - -/* -============== -BG_FindBuildTimeForBuildable -============== -*/ -int BG_FindBuildTimeForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].buildTime; - } - } - - return 10000; -} - -/* -============== -BG_FindUsableForBuildable -============== -*/ -qboolean BG_FindUsableForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].usable; - } - } - - return qfalse; -} - -/* -============== -BG_FindFireSpeedForBuildable -============== -*/ -int BG_FindFireSpeedForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].turretFireSpeed; - } - } - - return 1000; -} - -/* -============== -BG_FindRangeForBuildable -============== -*/ -int BG_FindRangeForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].turretRange; - } - } - - return 1000; -} - -/* -============== -BG_FindProjTypeForBuildable -============== -*/ -weapon_t BG_FindProjTypeForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].turretProjType; - } - } - - return WP_NONE; -} - -/* -============== -BG_FindMinNormalForBuildable -============== -*/ -float BG_FindMinNormalForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].minNormal; - } - } - - return 0.707f; -} - -/* -============== -BG_FindInvertNormalForBuildable -============== -*/ -qboolean BG_FindInvertNormalForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].invertNormal; - } - } - - return qfalse; -} - -/* -============== -BG_FindCreepTestForBuildable -============== -*/ -int BG_FindCreepTestForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].creepTest; - } - } - - return qfalse; -} - -/* -============== -BG_FindCreepSizeForBuildable -============== -*/ -int BG_FindCreepSizeForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].creepSize; - } - } - - return CREEP_BASESIZE; -} - -/* -============== -BG_FindDCCTestForBuildable -============== -*/ -int BG_FindDCCTestForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].dccTest; - } - } - - return qfalse; -} - -/* -============== -BG_FindUniqueTestForBuildable -============== -*/ -int BG_FindUniqueTestForBuildable( int bclass ) -{ - int i; - - for( i = 0; i < bg_numBuildables; i++ ) - { - if( bg_buildableList[ i ].buildNum == bclass ) - { - return bg_buildableList[ i ].reactorTest; - } - } - - return qfalse; -} - -/* -============== -BG_FindOverrideForBuildable -============== -*/ -static buildableAttributeOverrides_t *BG_FindOverrideForBuildable( int bclass ) -{ - return &bg_buildableOverrideList[ bclass ]; -} - -/* -====================== -BG_ParseBuildableFile - -Parses a configuration file describing a builable -====================== -*/ -static qboolean BG_ParseBuildableFile( const char *filename, buildableAttributeOverrides_t *bao ) -{ - char *text_p; - int i; - int len; - char *token; - char text[ 20000 ]; - fileHandle_t f; - float scale; - - - // load the file - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - if( len <= 0 ) - return qfalse; - - if( len >= sizeof( text ) - 1 ) - { - Com_Printf( S_COLOR_RED "ERROR: Buildable file %s too long\n", filename ); - return qfalse; - } - - trap_FS_Read( text, len, f ); - text[ len ] = 0; - trap_FS_FCloseFile( f ); - - // parse the text - text_p = text; - - // read optional parameters - while( 1 ) - { - token = COM_Parse( &text_p ); - - if( !token ) - break; - - if( !Q_stricmp( token, "" ) ) - break; - - if( !Q_stricmp( token, "model" ) ) - { - int index = 0; - - token = COM_Parse( &text_p ); - if( !token ) - break; - - index = atoi( token ); - - if( index < 0 ) - index = 0; - else if( index > 3 ) - index = 3; - - token = COM_Parse( &text_p ); - if( !token ) - break; - - Q_strncpyz( bao->models[ index ], token, sizeof( bao->models[ 0 ] ) ); - - continue; - } - else if( !Q_stricmp( token, "modelScale" ) ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - scale = atof( token ); - - if( scale < 0.0f ) - scale = 0.0f; - - bao->modelScale = scale; - - continue; - } - else if( !Q_stricmp( token, "mins" ) ) - { - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - bao->mins[ i ] = atof( token ); - } - - continue; - } - else if( !Q_stricmp( token, "maxs" ) ) - { - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - bao->maxs[ i ] = atof( token ); - } - - continue; - } - else if( !Q_stricmp( token, "zOffset" ) ) - { - float offset; - - token = COM_Parse( &text_p ); - if( !token ) - break; - - offset = atof( token ); - - bao->zOffset = offset; - - continue; - } - - - Com_Printf( S_COLOR_RED "ERROR: unknown token '%s'\n", token ); - return qfalse; - } - - return qtrue; -} - -/* -=============== -BG_InitBuildableOverrides - -Set any overrides specfied by file -=============== -*/ -void BG_InitBuildableOverrides( void ) -{ - int i; - buildableAttributeOverrides_t *bao; - - for( i = BA_NONE + 1; i < BA_NUM_BUILDABLES; i++ ) - { - bao = BG_FindOverrideForBuildable( i ); - - BG_ParseBuildableFile( va( "overrides/buildables/%s.cfg", BG_FindNameForBuildable( i ) ), bao ); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -classAttributes_t bg_classList[ ] = -{ - { - PCL_NONE, //int classnum; - "spectator", //char *className; - "Spectator", //char *humanName; - "", //char *modelname; - 1.0f, //float modelScale; - "", //char *skinname; - 1.0f, //float shadowScale; - "", //char *hudname; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - { -15, -15, -15 }, //vec3_t mins; - { 15, 15, 15 }, //vec3_t maxs; - { 15, 15, 15 }, //vec3_t crouchmaxs; - { -15, -15, -15 }, //vec3_t deadmins; - { 15, 15, 15 }, //vec3_t deadmaxs; - 0.0f, //float zOffset - 0, 0, //int viewheight, crouchviewheight; - 0, //int health; - 0.0f, //float fallDamage; - 0, //int regenRate; - 0, //int abilities; - WP_NONE, //weapon_t startWeapon - 0.0f, //float buildDist; - 90, //int fov; - 0.000f, //float bob; - 1.0f, //float bobCycle; - 0, //int steptime; - 600, //float speed; - 10.0f, //float acceleration; - 1.0f, //float airAcceleration; - 6.0f, //float friction; - 100.0f, //float stopSpeed; - 270.0f, //float jumpMagnitude; - 1.0f, //float knockbackScale; - { PCL_NONE, PCL_NONE, PCL_NONE }, //int children[ 3 ]; - 0, //int cost; - 0 //int value; - }, - { - PCL_ALIEN_BUILDER0, //int classnum; - "builder", //char *className; - "Builder", //char *humanName; - "builder", //char *modelname; - 1.0f, //float modelScale; - "default", //char *skinname; - 1.0f, //float shadowScale; - "alien_builder_hud", //char *hudname; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - { -15, -15, -20 }, //vec3_t mins; - { 15, 15, 20 }, //vec3_t maxs; - { 15, 15, 20 }, //vec3_t crouchmaxs; - { -15, -15, -4 }, //vec3_t deadmins; - { 15, 15, 4 }, //vec3_t deadmaxs; - 0.0f, //float zOffset - 0, 0, //int viewheight, crouchviewheight; - ABUILDER_HEALTH, //int health; - 0.2f, //float fallDamage; - ABUILDER_REGEN, //int regenRate; - SCA_TAKESFALLDAMAGE|SCA_FOVWARPS|SCA_ALIENSENSE,//int abilities; - WP_ABUILD, //weapon_t startWeapon - 95.0f, //float buildDist; - 80, //int fov; - 0.001f, //float bob; - 2.0f, //float bobCycle; - 150, //int steptime; - ABUILDER_SPEED, //float speed; - 10.0f, //float acceleration; - 1.0f, //float airAcceleration; - 6.0f, //float friction; - 100.0f, //float stopSpeed; - 195.0f, //float jumpMagnitude; - 1.0f, //float knockbackScale; - { PCL_ALIEN_BUILDER0_UPG, PCL_ALIEN_LEVEL0, PCL_NONE }, //int children[ 3 ]; - ABUILDER_COST, //int cost; - ABUILDER_VALUE //int value; - }, - { - PCL_ALIEN_BUILDER0_UPG, //int classnum; - "builderupg", //char *classname; - "Advanced Builder", //char *humanname; - "builder", //char *modelname; - 1.0f, //float modelScale; - "advanced", //char *skinname; - 1.0f, //float shadowScale; - "alien_builder_hud", //char *hudname; - ( 1 << S2 )|( 1 << S3 ), //int stages - { -20, -20, -20 }, //vec3_t mins; - { 20, 20, 20 }, //vec3_t maxs; - { 20, 20, 20 }, //vec3_t crouchmaxs; - { -20, -20, -4 }, //vec3_t deadmins; - { 20, 20, 4 }, //vec3_t deadmaxs; - 0.0f, //float zOffset - 0, 0, //int viewheight, crouchviewheight; - ABUILDER_UPG_HEALTH, //int health; - 0.0f, //float fallDamage; - ABUILDER_UPG_REGEN, //int regenRate; - SCA_FOVWARPS|SCA_WALLCLIMBER|SCA_ALIENSENSE, //int abilities; - WP_ABUILD2, //weapon_t startWeapon - 105.0f, //float buildDist; - 110, //int fov; - 0.001f, //float bob; - 2.0f, //float bobCycle; - 100, //int steptime; - ABUILDER_UPG_SPEED, //float speed; - 10.0f, //float acceleration; - 1.0f, //float airAcceleration; - 6.0f, //float friction; - 100.0f, //float stopSpeed; - 270.0f, //float jumpMagnitude; - 1.0f, //float knockbackScale; - { PCL_ALIEN_LEVEL0, PCL_NONE, PCL_NONE }, //int children[ 3 ]; - ABUILDER_UPG_COST, //int cost; - ABUILDER_UPG_VALUE //int value; - }, - { - PCL_ALIEN_LEVEL0, //int classnum; - "level0", //char *classname; - "Soldier", //char *humanname; - "jumper", //char *modelname; - 0.2f, //float modelScale; - "default", //char *skinname; - 0.3f, //float shadowScale; - "alien_general_hud", //char *hudname; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - { -15, -15, -15 }, //vec3_t mins; - { 15, 15, 15 }, //vec3_t maxs; - { 15, 15, 15 }, //vec3_t crouchmaxs; - { -15, -15, -4 }, //vec3_t deadmins; - { 15, 15, 4 }, //vec3_t deadmaxs; - -8.0f, //float zOffset - 0, 0, //int viewheight, crouchviewheight; - LEVEL0_HEALTH, //int health; - 0.0f, //float fallDamage; - LEVEL0_REGEN, //int regenRate; - SCA_WALLCLIMBER|SCA_NOWEAPONDRIFT| - SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities; - WP_ALEVEL0, //weapon_t startWeapon - 0.0f, //float buildDist; - 140, //int fov; - 0.0f, //float bob; - 2.5f, //float bobCycle; - 25, //int steptime; - LEVEL0_SPEED, //float speed; - 10.0f, //float acceleration; - 1.0f, //float airAcceleration; - 6.0f, //float friction; - 400.0f, //float stopSpeed; - 250.0f, //float jumpMagnitude; - 2.0f, //float knockbackScale; - { PCL_ALIEN_LEVEL1, PCL_NONE, PCL_NONE }, //int children[ 3 ]; - LEVEL0_COST, //int cost; - LEVEL0_VALUE //int value; - }, - { - PCL_ALIEN_LEVEL1, //int classnum; - "level1", //char *classname; - "Hydra", //char *humanname; - "spitter", //char *modelname; - 0.6f, //float modelScale; - "default", //char *skinname; - 1.0f, //float shadowScale; - "alien_general_hud", //char *hudname; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - { -18, -18, -18 }, //vec3_t mins; - { 18, 18, 18 }, //vec3_t maxs; - { 18, 18, 18 }, //vec3_t crouchmaxs; - { -18, -18, -4 }, //vec3_t deadmins; - { 18, 18, 4 }, //vec3_t deadmaxs; - 0.0f, //float zOffset - 0, 0, //int viewheight, crouchviewheight; - LEVEL1_HEALTH, //int health; - 0.0f, //float fallDamage; - LEVEL1_REGEN, //int regenRate; - SCA_NOWEAPONDRIFT| - SCA_FOVWARPS|SCA_WALLCLIMBER|SCA_ALIENSENSE, //int abilities; - WP_ALEVEL1, //weapon_t startWeapon - 0.0f, //float buildDist; - 120, //int fov; - 0.001f, //float bob; - 1.8f, //float bobCycle; - 60, //int steptime; - LEVEL1_SPEED, //float speed; - 10.0f, //float acceleration; - 1.0f, //float airAcceleration; - 6.0f, //float friction; - 300.0f, //float stopSpeed; - 270.0f, //float jumpMagnitude; - 1.2f, //float knockbackScale; - { PCL_ALIEN_LEVEL2, PCL_ALIEN_LEVEL1_UPG, PCL_NONE }, //int children[ 3 ]; - LEVEL1_COST, //int cost; - LEVEL1_VALUE //int value; - }, - { - PCL_ALIEN_LEVEL1_UPG, //int classnum; - "level1upg", //char *classname; - "Hydra Upgrade", //char *humanname; - "spitter", //char *modelname; - 0.7f, //float modelScale; - "blue", //char *skinname; - 1.0f, //float shadowScale; - "alien_general_hud", //char *hudname; - ( 1 << S2 )|( 1 << S3 ), //int stages - { -20, -20, -20 }, //vec3_t mins; - { 20, 20, 20 }, //vec3_t maxs; - { 20, 20, 20 }, //vec3_t crouchmaxs; - { -20, -20, -4 }, //vec3_t deadmins; - { 20, 20, 4 }, //vec3_t deadmaxs; - 0.0f, //float zOffset - 0, 0, //int viewheight, crouchviewheight; - LEVEL1_UPG_HEALTH, //int health; - 0.0f, //float fallDamage; - LEVEL1_UPG_REGEN, //int regenRate; - SCA_NOWEAPONDRIFT|SCA_FOVWARPS| - SCA_WALLCLIMBER|SCA_ALIENSENSE, //int abilities; - WP_ALEVEL1_UPG, //weapon_t startWeapon - 0.0f, //float buildDist; - 120, //int fov; - 0.001f, //float bob; - 1.8f, //float bobCycle; - 60, //int steptime; - LEVEL1_UPG_SPEED, //float speed; - 10.0f, //float acceleration; - 1.0f, //float airAcceleration; - 6.0f, //float friction; - 300.0f, //float stopSpeed; - 270.0f, //float jumpMagnitude; - 1.1f, //float knockbackScale; - { PCL_ALIEN_LEVEL2, PCL_NONE, PCL_NONE }, //int children[ 3 ]; - LEVEL1_UPG_COST, //int cost; - LEVEL1_UPG_VALUE //int value; - }, - { - PCL_ALIEN_LEVEL2, //int classnum; - "level2", //char *classname; - "Chimera", //char *humanname; - "tarantula", //char *modelname; - 0.75f, //float modelScale; - "default", //char *skinname; - 1.0f, //float shadowScale; - "alien_general_hud", //char *hudname; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - { -22, -22, -22 }, //vec3_t mins; - { 22, 22, 22 }, //vec3_t maxs; - { 22, 22, 22 }, //vec3_t crouchmaxs; - { -22, -22, -4 }, //vec3_t deadmins; - { 22, 22, 4 }, //vec3_t deadmaxs; - 0.0f, //float zOffset - 10, 10, //int viewheight, crouchviewheight; - LEVEL2_HEALTH, //int health; - 0.0f, //float fallDamage; - LEVEL2_REGEN, //int regenRate; - SCA_NOWEAPONDRIFT|SCA_WALLJUMPER| - SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities; - WP_ALEVEL2, //weapon_t startWeapon - 0.0f, //float buildDist; - 90, //int fov; - 0.001f, //float bob; - 1.5f, //float bobCycle; - 80, //int steptime; - LEVEL2_SPEED, //float speed; - 10.0f, //float acceleration; - 2.0f, //float airAcceleration; - 6.0f, //float friction; - 100.0f, //float stopSpeed; - 400.0f, //float jumpMagnitude; - 0.8f, //float knockbackScale; - { PCL_ALIEN_LEVEL3, PCL_ALIEN_LEVEL2_UPG, PCL_NONE }, //int children[ 3 ]; - LEVEL2_COST, //int cost; - LEVEL2_VALUE //int value; - }, - { - PCL_ALIEN_LEVEL2_UPG, //int classnum; - "level2upg", //char *classname; - "Chimera Upgrade", //char *humanname; - "tarantula", //char *modelname; - 0.9f, //float modelScale; - "red", //char *skinname; - 1.0f, //float shadowScale; - "alien_general_hud", //char *hudname; - ( 1 << S2 )|( 1 << S3 ), //int stages - { -24, -24, -24 }, //vec3_t mins; - { 24, 24, 24 }, //vec3_t maxs; - { 24, 24, 24 }, //vec3_t crouchmaxs; - { -24, -24, -4 }, //vec3_t deadmins; - { 24, 24, 4 }, //vec3_t deadmaxs; - 0.0f, //float zOffset - 12, 12, //int viewheight, crouchviewheight; - LEVEL2_UPG_HEALTH, //int health; - 0.0f, //float fallDamage; - LEVEL2_UPG_REGEN, //int regenRate; - SCA_NOWEAPONDRIFT|SCA_WALLJUMPER| - SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities; - WP_ALEVEL2_UPG, //weapon_t startWeapon - 0.0f, //float buildDist; - 90, //int fov; - 0.001f, //float bob; - 1.5f, //float bobCycle; - 80, //int steptime; - LEVEL2_UPG_SPEED, //float speed; - 10.0f, //float acceleration; - 2.0f, //float airAcceleration; - 6.0f, //float friction; - 100.0f, //float stopSpeed; - 400.0f, //float jumpMagnitude; - 0.7f, //float knockbackScale; - { PCL_ALIEN_LEVEL3, PCL_NONE, PCL_NONE }, //int children[ 3 ]; - LEVEL2_UPG_COST, //int cost; - LEVEL2_UPG_VALUE //int value; - }, - { - PCL_ALIEN_LEVEL3, //int classnum; - "level3", //char *classname; - "Dragoon", //char *humanname; - "prowl", //char *modelname; - 1.0f, //float modelScale; - "default", //char *skinname; - 1.0f, //float shadowScale; - "alien_general_hud", //char *hudname; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - { -32, -32, -21 }, //vec3_t mins; - { 32, 32, 21 }, //vec3_t maxs; - { 32, 32, 21 }, //vec3_t crouchmaxs; - { -32, -32, -4 }, //vec3_t deadmins; - { 32, 32, 4 }, //vec3_t deadmaxs; - 0.0f, //float zOffset - 24, 24, //int viewheight, crouchviewheight; - LEVEL3_HEALTH, //int health; - 0.0f, //float fallDamage; - LEVEL3_REGEN, //int regenRate; - SCA_NOWEAPONDRIFT| - SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities; - WP_ALEVEL3, //weapon_t startWeapon - 0.0f, //float buildDist; - 110, //int fov; - 0.0005f, //float bob; - 1.3f, //float bobCycle; - 90, //int steptime; - LEVEL3_SPEED, //float speed; - 10.0f, //float acceleration; - 1.0f, //float airAcceleration; - 6.0f, //float friction; - 200.0f, //float stopSpeed; - 270.0f, //float jumpMagnitude; - 0.5f, //float knockbackScale; - { PCL_ALIEN_LEVEL4, PCL_ALIEN_LEVEL3_UPG, PCL_NONE }, //int children[ 3 ]; - LEVEL3_COST, //int cost; - LEVEL3_VALUE //int value; - }, - { - PCL_ALIEN_LEVEL3_UPG, //int classnum; - "level3upg", //char *classname; - "Dragoon Upgrade", //char *humanname; - "prowl", //char *modelname; - 1.0f, //float modelScale; - "default", //char *skinname; - 1.0f, //float shadowScale; - "alien_general_hud", //char *hudname; - ( 1 << S3 ), //int stages - { -32, -32, -21 }, //vec3_t mins; - { 32, 32, 21 }, //vec3_t maxs; - { 32, 32, 21 }, //vec3_t crouchmaxs; - { -32, -32, -4 }, //vec3_t deadmins; - { 32, 32, 4 }, //vec3_t deadmaxs; - 0.0f, //float zOffset - 27, 27, //int viewheight, crouchviewheight; - LEVEL3_UPG_HEALTH, //int health; - 0.0f, //float fallDamage; - LEVEL3_UPG_REGEN, //int regenRate; - SCA_NOWEAPONDRIFT| - SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities; - WP_ALEVEL3_UPG, //weapon_t startWeapon - 0.0f, //float buildDist; - 110, //int fov; - 0.0005f, //float bob; - 1.3f, //float bobCycle; - 90, //int steptime; - LEVEL3_UPG_SPEED, //float speed; - 10.0f, //float acceleration; - 1.0f, //float airAcceleration; - 6.0f, //float friction; - 200.0f, //float stopSpeed; - 270.0f, //float jumpMagnitude; - 0.4f, //float knockbackScale; - { PCL_ALIEN_LEVEL4, PCL_NONE, PCL_NONE }, //int children[ 3 ]; - LEVEL3_UPG_COST, //int cost; - LEVEL3_UPG_VALUE //int value; - }, - { - PCL_ALIEN_LEVEL4, //int classnum; - "level4", //char *classname; - "Big Mofo", //char *humanname; - "mofo", //char *modelname; - 1.0f, //float modelScale; - "default", //char *skinname; - 2.0f, //float shadowScale; - "alien_general_hud", //char *hudname; - ( 1 << S3 ), //int stages - { -30, -30, -20 }, //vec3_t mins; - { 30, 30, 20 }, //vec3_t maxs; - { 30, 30, 20 }, //vec3_t crouchmaxs; - { -15, -15, -4 }, //vec3_t deadmins; - { 15, 15, 4 }, //vec3_t deadmaxs; - 0.0f, //float zOffset - 35, 35, //int viewheight, crouchviewheight; - LEVEL4_HEALTH, //int health; - 0.0f, //float fallDamage; - LEVEL4_REGEN, //int regenRate; - SCA_NOWEAPONDRIFT| - SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities; - WP_ALEVEL4, //weapon_t startWeapon - 0.0f, //float buildDist; - 90, //int fov; - 0.001f, //float bob; - 1.1f, //float bobCycle; - 100, //int steptime; - LEVEL4_SPEED, //float speed; - 10.0f, //float acceleration; - 1.0f, //float airAcceleration; - 6.0f, //float friction; - 100.0f, //float stopSpeed; - 170.0f, //float jumpMagnitude; - 0.1f, //float knockbackScale; - { PCL_NONE, PCL_NONE, PCL_NONE }, //int children[ 3 ]; - LEVEL4_COST, //int cost; - LEVEL4_VALUE //int value; - }, - { - PCL_HUMAN, //int classnum; - "human_base", //char *classname; - "Human", //char *humanname; - "sarge", //char *modelname; - 1.0f, //float modelScale; - "default", //char *skinname; - 1.0f, //float shadowScale; - "human_hud", //char *hudname; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - { -15, -15, -24 }, //vec3_t mins; - { 15, 15, 32 }, //vec3_t maxs; - { 15, 15, 16 }, //vec3_t crouchmaxs; - { -15, -15, -4 }, //vec3_t deadmins; - { 15, 15, 4 }, //vec3_t deadmaxs; - 0.0f, //float zOffset - 26, 12, //int viewheight, crouchviewheight; - 100, //int health; - 1.0f, //float fallDamage; - 0, //int regenRate; - SCA_TAKESFALLDAMAGE| - SCA_CANUSELADDERS, //int abilities; - WP_NONE, //special-cased in g_client.c //weapon_t startWeapon - 110.0f, //float buildDist; - 90, //int fov; - 0.002f, //float bob; - 1.0f, //float bobCycle; - 100, //int steptime; - 1.0f, //float speed; - 10.0f, //float acceleration; - 1.0f, //float airAcceleration; - 6.0f, //float friction; - 100.0f, //float stopSpeed; - 220.0f, //float jumpMagnitude; - 1.0f, //float knockbackScale; - { PCL_NONE, PCL_NONE, PCL_NONE }, //int children[ 3 ]; - 0, //int cost; - 0 //int value; - }, - { - //this isn't a real class, but a dummy to force the client to precache the model - //FIXME: one day do this in a less hacky fashion - PCL_HUMAN_BSUIT, "human_bsuit", "bsuit", - - "keel", - 1.0f, - "default", - 1.0f, - - "bsuit", ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), { 0, 0, 0 }, { 0, 0, 0, }, - { 0, 0, 0, }, { 0, 0, 0, }, { 0, 0, 0, }, 0.0f, 0, 0, 0, 0.0f, 0, 0, WP_NONE, 0.0f, 0, - 0.0f, 1.0f, 0, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 270.0f, 1.0f, { PCL_NONE, PCL_NONE, PCL_NONE }, 0, 0 - } -}; - -int bg_numPclasses = sizeof( bg_classList ) / sizeof( bg_classList[ 0 ] ); - -//separate from bg_classList to work around char struct init bug -classAttributeOverrides_t bg_classOverrideList[ PCL_NUM_CLASSES ]; - -/* -============== -BG_FindClassNumForName -============== -*/ -int BG_FindClassNumForName( char *name ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( !Q_stricmp( bg_classList[ i ].className, name ) ) - return bg_classList[ i ].classNum; - } - - //wimp out - return PCL_NONE; -} - -/* -============== -BG_FindNameForClassNum -============== -*/ -char *BG_FindNameForClassNum( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - return bg_classList[ i ].className; - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindNameForClassNum\n" ); - //wimp out - return 0; -} - -/* -============== -BG_FindHumanNameForClassNum -============== -*/ -char *BG_FindHumanNameForClassNum( int pclass ) -{ - int i; - - if( bg_classOverrideList[ pclass ].humanName[ 0 ] != 0 ) - return bg_classOverrideList[ pclass ].humanName; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - return bg_classList[ i ].humanName; - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindHumanNameForClassNum\n" ); - //wimp out - return 0; -} - -/* -============== -BG_FindModelNameForClass -============== -*/ -char *BG_FindModelNameForClass( int pclass ) -{ - int i; - - if( bg_classOverrideList[ pclass ].modelName[ 0 ] != 0 ) - return bg_classOverrideList[ pclass ].modelName; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - return bg_classList[ i ].modelName; - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindModelNameForClass\n" ); - //note: must return a valid modelName! - return bg_classList[ 0 ].modelName; -} - -/* -============== -BG_FindModelScaleForClass -============== -*/ -float BG_FindModelScaleForClass( int pclass ) -{ - int i; - - if( bg_classOverrideList[ pclass ].modelScale != 0.0f ) - return bg_classOverrideList[ pclass ].modelScale; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].modelScale; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindModelScaleForClass( %d )\n", pclass ); - return 1.0f; -} - -/* -============== -BG_FindSkinNameForClass -============== -*/ -char *BG_FindSkinNameForClass( int pclass ) -{ - int i; - - if( bg_classOverrideList[ pclass ].skinName[ 0 ] != 0 ) - return bg_classOverrideList[ pclass ].skinName; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - return bg_classList[ i ].skinName; - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindSkinNameForClass\n" ); - //note: must return a valid modelName! - return bg_classList[ 0 ].skinName; -} - -/* -============== -BG_FindShadowScaleForClass -============== -*/ -float BG_FindShadowScaleForClass( int pclass ) -{ - int i; - - if( bg_classOverrideList[ pclass ].shadowScale != 0.0f ) - return bg_classOverrideList[ pclass ].shadowScale; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].shadowScale; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindShadowScaleForClass( %d )\n", pclass ); - return 1.0f; -} - -/* -============== -BG_FindHudNameForClass -============== -*/ -char *BG_FindHudNameForClass( int pclass ) -{ - int i; - - if( bg_classOverrideList[ pclass ].hudName[ 0 ] != 0 ) - return bg_classOverrideList[ pclass ].hudName; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - return bg_classList[ i ].hudName; - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindHudNameForClass\n" ); - //note: must return a valid hudName! - return bg_classList[ 0 ].hudName; -} - -/* -============== -BG_FindStagesForClass -============== -*/ -qboolean BG_FindStagesForClass( int pclass, stage_t stage ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - if( bg_classList[ i ].stages & ( 1 << stage ) ) - return qtrue; - else - return qfalse; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindStagesForClass\n" ); - return qfalse; -} - -/* -============== -BG_FindBBoxForClass -============== -*/ -void BG_FindBBoxForClass( int pclass, vec3_t mins, vec3_t maxs, vec3_t cmaxs, vec3_t dmins, vec3_t dmaxs ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - if( mins != NULL ) - { - VectorCopy( bg_classList[ i ].mins, mins ); - - if( VectorLength( bg_classOverrideList[ pclass ].mins ) ) - VectorCopy( bg_classOverrideList[ pclass ].mins, mins ); - } - - if( maxs != NULL ) - { - VectorCopy( bg_classList[ i ].maxs, maxs ); - - if( VectorLength( bg_classOverrideList[ pclass ].maxs ) ) - VectorCopy( bg_classOverrideList[ pclass ].maxs, maxs ); - } - - if( cmaxs != NULL ) - { - VectorCopy( bg_classList[ i ].crouchMaxs, cmaxs ); - - if( VectorLength( bg_classOverrideList[ pclass ].crouchMaxs ) ) - VectorCopy( bg_classOverrideList[ pclass ].crouchMaxs, cmaxs ); - } - - if( dmins != NULL ) - { - VectorCopy( bg_classList[ i ].deadMins, dmins ); - - if( VectorLength( bg_classOverrideList[ pclass ].deadMins ) ) - VectorCopy( bg_classOverrideList[ pclass ].deadMins, dmins ); - } - - if( dmaxs != NULL ) - { - VectorCopy( bg_classList[ i ].deadMaxs, dmaxs ); - - if( VectorLength( bg_classOverrideList[ pclass ].deadMaxs ) ) - VectorCopy( bg_classOverrideList[ pclass ].deadMaxs, dmaxs ); - } - - return; - } - } - - if( mins != NULL ) - VectorCopy( bg_classList[ 0 ].mins, mins ); - - if( maxs != NULL ) - VectorCopy( bg_classList[ 0 ].maxs, maxs ); - - if( cmaxs != NULL ) - VectorCopy( bg_classList[ 0 ].crouchMaxs, cmaxs ); - - if( dmins != NULL ) - VectorCopy( bg_classList[ 0 ].deadMins, dmins ); - - if( dmaxs != NULL ) - VectorCopy( bg_classList[ 0 ].deadMaxs, dmaxs ); -} - -/* -============== -BG_FindZOffsetForClass -============== -*/ -float BG_FindZOffsetForClass( int pclass ) -{ - int i; - - if( bg_classOverrideList[ pclass ].zOffset != 0.0f ) - return bg_classOverrideList[ pclass ].zOffset; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].zOffset; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindZOffsetForClass\n" ); - return 0.0f; -} - -/* -============== -BG_FindViewheightForClass -============== -*/ -void BG_FindViewheightForClass( int pclass, int *viewheight, int *cViewheight ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - if( viewheight != NULL ) - *viewheight = bg_classList[ i ].viewheight; - - if( cViewheight != NULL ) - *cViewheight = bg_classList[ i ].crouchViewheight; - - return; - } - } - - if( viewheight != NULL ) - *viewheight = bg_classList[ 0 ].viewheight; - - if( cViewheight != NULL ) - *cViewheight = bg_classList[ 0 ].crouchViewheight; -} - -/* -============== -BG_FindHealthForClass -============== -*/ -int BG_FindHealthForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].health; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindHealthForClass\n" ); - return 100; -} - -/* -============== -BG_FindFallDamageForClass -============== -*/ -float BG_FindFallDamageForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].fallDamage; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindFallDamageForClass\n" ); - return 100; -} - -/* -============== -BG_FindRegenRateForClass -============== -*/ -int BG_FindRegenRateForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].regenRate; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindRegenRateForClass\n" ); - return 0; -} - -/* -============== -BG_FindFovForClass -============== -*/ -int BG_FindFovForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].fov; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindFovForClass\n" ); - return 90; -} - -/* -============== -BG_FindBobForClass -============== -*/ -float BG_FindBobForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].bob; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindBobForClass\n" ); - return 0.002; -} - -/* -============== -BG_FindBobCycleForClass -============== -*/ -float BG_FindBobCycleForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].bobCycle; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindBobCycleForClass\n" ); - return 1.0f; -} - -/* -============== -BG_FindSpeedForClass -============== -*/ -float BG_FindSpeedForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].speed; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindSpeedForClass\n" ); - return 1.0f; -} - -/* -============== -BG_FindAccelerationForClass -============== -*/ -float BG_FindAccelerationForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].acceleration; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindAccelerationForClass\n" ); - return 10.0f; -} - -/* -============== -BG_FindAirAccelerationForClass -============== -*/ -float BG_FindAirAccelerationForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].airAcceleration; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindAirAccelerationForClass\n" ); - return 1.0f; -} - -/* -============== -BG_FindFrictionForClass -============== -*/ -float BG_FindFrictionForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].friction; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindFrictionForClass\n" ); - return 6.0f; -} - -/* -============== -BG_FindStopSpeedForClass -============== -*/ -float BG_FindStopSpeedForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].stopSpeed; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindStopSpeedForClass\n" ); - return 100.0f; -} - -/* -============== -BG_FindJumpMagnitudeForClass -============== -*/ -float BG_FindJumpMagnitudeForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].jumpMagnitude; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindJumpMagnitudeForClass\n" ); - return 270.0f; -} - -/* -============== -BG_FindKnockbackScaleForClass -============== -*/ -float BG_FindKnockbackScaleForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].knockbackScale; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindKnockbackScaleForClass\n" ); - return 1.0f; -} - -/* -============== -BG_FindSteptimeForClass -============== -*/ -int BG_FindSteptimeForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].steptime; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindSteptimeForClass\n" ); - return 200; -} - -/* -============== -BG_ClassHasAbility -============== -*/ -qboolean BG_ClassHasAbility( int pclass, int ability ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return ( bg_classList[ i ].abilities & ability ); - } - } - - return qfalse; -} - -/* -============== -BG_FindStartWeaponForClass -============== -*/ -weapon_t BG_FindStartWeaponForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].startWeapon; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindStartWeaponForClass\n" ); - return WP_NONE; -} - -/* -============== -BG_FindBuildDistForClass -============== -*/ -float BG_FindBuildDistForClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].buildDist; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindBuildDistForClass\n" ); - return 0.0f; -} - -/* -============== -BG_ClassCanEvolveFromTo -============== -*/ -int BG_ClassCanEvolveFromTo( int fclass, int tclass, int credits, int num ) -{ - int i, j, cost; - - cost = BG_FindCostOfClass( tclass ); - - //base case - if( credits < cost ) - return -1; - - if( fclass == PCL_NONE || tclass == PCL_NONE ) - return -1; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == fclass ) - { - for( j = 0; j < 3; j++ ) - if( bg_classList[ i ].children[ j ] == tclass ) - return num + cost; - - for( j = 0; j < 3; j++ ) - { - int sub; - - cost = BG_FindCostOfClass( bg_classList[ i ].children[ j ] ); - sub = BG_ClassCanEvolveFromTo( bg_classList[ i ].children[ j ], - tclass, credits - cost, num + cost ); - if( sub >= 0 ) - return sub; - } - - return -1; //may as well return by this point - } - } - - return -1; -} - -/* -============== -BG_FindValueOfClass -============== -*/ -int BG_FindValueOfClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].value; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindValueOfClass\n" ); - return 0; -} - -/* -============== -BG_FindCostOfClass -============== -*/ -int BG_FindCostOfClass( int pclass ) -{ - int i; - - for( i = 0; i < bg_numPclasses; i++ ) - { - if( bg_classList[ i ].classNum == pclass ) - { - return bg_classList[ i ].cost; - } - } - - Com_Printf( S_COLOR_YELLOW "WARNING: fallthrough in BG_FindCostOfClass\n" ); - return 0; -} - -/* -============== -BG_FindOverrideForClass -============== -*/ -static classAttributeOverrides_t *BG_FindOverrideForClass( int pclass ) -{ - return &bg_classOverrideList[ pclass ]; -} - -/* -====================== -BG_ParseClassFile - -Parses a configuration file describing a class -====================== -*/ -static qboolean BG_ParseClassFile( const char *filename, classAttributeOverrides_t *cao ) -{ - char *text_p; - int i; - int len; - char *token; - char text[ 20000 ]; - fileHandle_t f; - float scale = 0.0f; - - - // load the file - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - if( len <= 0 ) - return qfalse; - - if( len >= sizeof( text ) - 1 ) - { - Com_Printf( S_COLOR_RED "ERROR: Class file %s too long\n", filename ); - return qfalse; - } - - trap_FS_Read( text, len, f ); - text[ len ] = 0; - trap_FS_FCloseFile( f ); - - // parse the text - text_p = text; - - // read optional parameters - while( 1 ) - { - token = COM_Parse( &text_p ); - - if( !token ) - break; - - if( !Q_stricmp( token, "" ) ) - break; - - if( !Q_stricmp( token, "model" ) ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - Q_strncpyz( cao->modelName, token, sizeof( cao->modelName ) ); - - continue; - } - else if( !Q_stricmp( token, "skin" ) ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - Q_strncpyz( cao->skinName, token, sizeof( cao->skinName ) ); - - continue; - } - else if( !Q_stricmp( token, "hud" ) ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - Q_strncpyz( cao->hudName, token, sizeof( cao->hudName ) ); - - continue; - } - else if( !Q_stricmp( token, "modelScale" ) ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - scale = atof( token ); - - if( scale < 0.0f ) - scale = 0.0f; - - cao->modelScale = scale; - - continue; - } - else if( !Q_stricmp( token, "shadowScale" ) ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - scale = atof( token ); - - if( scale < 0.0f ) - scale = 0.0f; - - cao->shadowScale = scale; - - continue; - } - else if( !Q_stricmp( token, "mins" ) ) - { - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - cao->mins[ i ] = atof( token ); - } - - continue; - } - else if( !Q_stricmp( token, "maxs" ) ) - { - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - cao->maxs[ i ] = atof( token ); - } - - continue; - } - else if( !Q_stricmp( token, "deadMins" ) ) - { - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - cao->deadMins[ i ] = atof( token ); - } - - continue; - } - else if( !Q_stricmp( token, "deadMaxs" ) ) - { - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - cao->deadMaxs[ i ] = atof( token ); - } - - continue; - } - else if( !Q_stricmp( token, "crouchMaxs" ) ) - { - for( i = 0; i <= 2; i++ ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - cao->crouchMaxs[ i ] = atof( token ); - } - - continue; - } - else if( !Q_stricmp( token, "zOffset" ) ) - { - float offset; - - token = COM_Parse( &text_p ); - if( !token ) - break; - - offset = atof( token ); - - cao->zOffset = offset; - - continue; - } - else if( !Q_stricmp( token, "name" ) ) - { - token = COM_Parse( &text_p ); - if( !token ) - break; - - Q_strncpyz( cao->humanName, token, sizeof( cao->humanName ) ); - - continue; - } - - - Com_Printf( S_COLOR_RED "ERROR: unknown token '%s'\n", token ); - return qfalse; - } - - return qtrue; -} - -/* -=============== -BG_InitClassOverrides - -Set any overrides specfied by file -=============== -*/ -void BG_InitClassOverrides( void ) -{ - int i; - classAttributeOverrides_t *cao; - - for( i = PCL_NONE + 1; i < PCL_NUM_CLASSES; i++ ) - { - cao = BG_FindOverrideForClass( i ); - - BG_ParseClassFile( va( "overrides/classes/%s.cfg", BG_FindNameForClassNum( i ) ), cao ); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -weaponAttributes_t bg_weapons[ ] = -{ - { - WP_BLASTER, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - 0, //int slots; - "blaster", //char *weaponName; - "Blaster", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - BLASTER_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_MACHINEGUN, //int weaponNum; - RIFLE_PRICE, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "rifle", //char *weaponName; - "Rifle", //char *weaponHumanName; - RIFLE_CLIPSIZE, //int maxAmmo; - RIFLE_MAXCLIPS, //int maxClips; - qfalse, //int infiniteAmmo; - qfalse, //int usesEnergy; - RIFLE_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - RIFLE_RELOAD, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qtrue, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_SHOTGUN, //int weaponNum; - SHOTGUN_PRICE, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "shotgun", //char *weaponName; - "Shotgun", //char *weaponHumanName; - SHOTGUN_SHELLS, //int maxAmmo; - SHOTGUN_MAXCLIPS, //int maxClips; - qfalse, //int infiniteAmmo; - qfalse, //int usesEnergy; - SHOTGUN_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - SHOTGUN_RELOAD, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qtrue, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_FLAMER, //int weaponNum; - FLAMER_PRICE, //int price; - ( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "flamer", //char *weaponName; - "Flame Thrower", //char *weaponHumanName; - FLAMER_GAS, //int maxAmmo; - 0, //int maxClips; - qfalse, //int infiniteAmmo; - qfalse, //int usesEnergy; - FLAMER_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qtrue, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_CHAINGUN, //int weaponNum; - CHAINGUN_PRICE, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "chaingun", //char *weaponName; - "Chaingun", //char *weaponHumanName; - CHAINGUN_BULLETS, //int maxAmmo; - 0, //int maxClips; - qfalse, //int infiniteAmmo; - qfalse, //int usesEnergy; - CHAINGUN_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qtrue, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_MASS_DRIVER, //int weaponNum; - MDRIVER_PRICE, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "mdriver", //char *weaponName; - "Mass Driver", //char *weaponHumanName; - MDRIVER_CLIPSIZE, //int maxAmmo; - MDRIVER_MAXCLIPS, //int maxClips; - qfalse, //int infiniteAmmo; - qtrue, //int usesEnergy; - MDRIVER_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - MDRIVER_RELOAD, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qtrue, //qboolean canZoom; - 20.0f, //float zoomFov; - qtrue, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_PULSE_RIFLE, //int weaponNum; - PRIFLE_PRICE, //int price; - ( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "prifle", //char *weaponName; - "Pulse Rifle", //char *weaponHumanName; - PRIFLE_CLIPS, //int maxAmmo; - PRIFLE_MAXCLIPS, //int maxClips; - qfalse, //int infiniteAmmo; - qtrue, //int usesEnergy; - PRIFLE_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - PRIFLE_RELOAD, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qtrue, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_LUCIFER_CANNON, //int weaponNum; - LCANNON_PRICE, //int price; - ( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "lcannon", //char *weaponName; - "Lucifer Cannon", //char *weaponHumanName; - LCANNON_AMMO, //int maxAmmo; - 0, //int maxClips; - qfalse, //int infiniteAmmo; - qtrue, //int usesEnergy; - LCANNON_REPEAT, //int repeatRate1; - LCANNON_CHARGEREPEAT, //int repeatRate2; - 0, //int repeatRate3; - LCANNON_RELOAD, //int reloadTime; - qtrue, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qtrue, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_LAS_GUN, //int weaponNum; - LASGUN_PRICE, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "lgun", //char *weaponName; - "Las Gun", //char *weaponHumanName; - LASGUN_AMMO, //int maxAmmo; - 0, //int maxClips; - qfalse, //int infiniteAmmo; - qtrue, //int usesEnergy; - LASGUN_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - LASGUN_RELOAD, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qtrue, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_PAIN_SAW, //int weaponNum; - PAINSAW_PRICE, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "psaw", //char *weaponName; - "Pain Saw", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - PAINSAW_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qtrue, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_GRENADE, //int weaponNum; - GRENADE_PRICE, //int price; - ( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_NONE, //int slots; - "grenade", //char *weaponName; - "Grenade", //char *weaponHumanName; - 1, //int maxAmmo; - 0, //int maxClips; - qfalse, //int infiniteAmmo; - qfalse, //int usesEnergy; - GRENADE_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_HBUILD, //int weaponNum; - HBUILD_PRICE, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "ckit", //char *weaponName; - "Construction Kit", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - HBUILD_REPEAT, //int repeatRate1; - HBUILD_REPEAT, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qtrue, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qtrue, //qboolean purchasable; - HBUILD_DELAY, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_HBUILD2, //int weaponNum; - HBUILD2_PRICE, //int price; - ( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "ackit", //char *weaponName; - "Adv Construction Kit",//char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - HBUILD2_REPEAT, //int repeatRate1; - HBUILD2_REPEAT, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qtrue, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qtrue, //qboolean purchasable; - HBUILD2_DELAY, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_ABUILD, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "abuild", //char *weaponName; - "Alien build weapon", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - ABUILDER_BUILD_REPEAT,//int repeatRate1; - ABUILDER_BUILD_REPEAT,//int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qtrue, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qtrue, //qboolean purchasable; - ABUILDER_BASE_DELAY, //int buildDelay; - WUT_ALIENS //WUTeam_t team; - }, - { - WP_ABUILD2, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "abuild2", //char *weaponName; - "Alien build weapon2",//char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - ABUILDER_BUILD_REPEAT,//int repeatRate1; - ABUILDER_CLAW_REPEAT, //int repeatRate2; - ABUILDER_BLOB_REPEAT, //int repeatRate3; - 0, //int reloadTime; - qtrue, //qboolean hasAltMode; - qtrue, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qtrue, //qboolean purchasable; - ABUILDER_ADV_DELAY, //int buildDelay; - WUT_ALIENS //WUTeam_t team; - }, - { - WP_ALEVEL0, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "bite", //char *weaponName; - "Bite", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - LEVEL0_BITE_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_ALIENS //WUTeam_t team; - }, - { - WP_ALEVEL3, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "pounce", //char *weaponName; - "Claw and pounce", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - LEVEL3_CLAW_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_ALIENS //WUTeam_t team; - }, - { - WP_ALEVEL3_UPG, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "pounce_upgrade", //char *weaponName; - "Claw and pounce (upgrade)", //char *weaponHumanName; - 3, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - LEVEL3_CLAW_U_REPEAT,//int repeatRate1; - 0, //int repeatRate2; - LEVEL3_BOUNCEBALL_REPEAT,//int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qtrue, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_ALIENS //WUTeam_t team; - }, - { - WP_ALEVEL1, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "grabandclaw", //char *weaponName; - "Claws", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - LEVEL1_CLAW_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_ALIENS //WUTeam_t team; - }, - { - WP_ALEVEL1_UPG, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "grabandclaw_upgrade",//char *weaponName; - "Claws Upgrade", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - LEVEL1_CLAW_U_REPEAT, //int repeatRate1; - LEVEL1_PCLOUD_REPEAT, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qtrue, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_ALIENS //WUTeam_t team; - }, - { - WP_ALEVEL2, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "areazap", //char *weaponName; - "Area Zap", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - LEVEL2_CLAW_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_ALIENS //WUTeam_t team; - }, - { - WP_ALEVEL2_UPG, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "directzap", //char *weaponName; - "Directed Zap", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - LEVEL2_CLAW_U_REPEAT,//int repeatRate1; - LEVEL2_AREAZAP_REPEAT,//int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qtrue, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_ALIENS //WUTeam_t team; - }, - { - WP_ALEVEL4, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "charge", //char *weaponName; - "Charge", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - LEVEL4_CLAW_REPEAT, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_ALIENS //WUTeam_t team; - }, - { - WP_LOCKBLOB_LAUNCHER, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "lockblob", //char *weaponName; - "Lock Blob", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - 500, //int repeatRate1; - 500, //int repeatRate2; - 500, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_ALIENS //WUTeam_t team; - }, - { - WP_HIVE, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "hive", //char *weaponName; - "Hive", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - 500, //int repeatRate1; - 500, //int repeatRate2; - 500, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_ALIENS //WUTeam_t team; - }, - { - WP_MGTURRET, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "mgturret", //char *weaponName; - "Machinegun Turret", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qfalse, //int usesEnergy; - 0, //int repeatRate1; - 0, //int repeatRate2; - 0, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - }, - { - WP_TESLAGEN, //int weaponNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_WEAPON, //int slots; - "teslagen", //char *weaponName; - "Tesla Generator", //char *weaponHumanName; - 0, //int maxAmmo; - 0, //int maxClips; - qtrue, //int infiniteAmmo; - qtrue, //int usesEnergy; - 500, //int repeatRate1; - 500, //int repeatRate2; - 500, //int repeatRate3; - 0, //int reloadTime; - qfalse, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; - qfalse, //qboolean purchasable; - 0, //int buildDelay; - WUT_HUMANS //WUTeam_t team; - } -}; - -int bg_numWeapons = sizeof( bg_weapons ) / sizeof( bg_weapons[ 0 ] ); - -/* -============== -BG_FindPriceForWeapon -============== -*/ -int BG_FindPriceForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - return bg_weapons[ i ].price; - } - } - - return 100; -} - -/* -============== -BG_FindStagesForWeapon -============== -*/ -qboolean BG_FindStagesForWeapon( int weapon, stage_t stage ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - if( bg_weapons[ i ].stages & ( 1 << stage ) ) - return qtrue; - else - return qfalse; - } - } - - return qfalse; -} - -/* -============== -BG_FindSlotsForWeapon -============== -*/ -int BG_FindSlotsForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - return bg_weapons[ i ].slots; - } - } - - return SLOT_WEAPON; -} - -/* -============== -BG_FindNameForWeapon -============== -*/ -char *BG_FindNameForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - return bg_weapons[ i ].weaponName; - } - - //wimp out - return 0; -} - -/* -============== -BG_FindWeaponNumForName -============== -*/ -int BG_FindWeaponNumForName( char *name ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( !Q_stricmp( bg_weapons[ i ].weaponName, name ) ) - return bg_weapons[ i ].weaponNum; - } - - //wimp out - return WP_NONE; -} - -/* -============== -BG_FindHumanNameForWeapon -============== -*/ -char *BG_FindHumanNameForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - return bg_weapons[ i ].weaponHumanName; - } - - //wimp out - return 0; -} - -/* -============== -BG_FindAmmoForWeapon -============== -*/ -void BG_FindAmmoForWeapon( int weapon, int *maxAmmo, int *maxClips ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - if( maxAmmo != NULL ) - *maxAmmo = bg_weapons[ i ].maxAmmo; - if( maxClips != NULL ) - *maxClips = bg_weapons[ i ].maxClips; - - //no need to keep going - break; - } - } -} - -/* -============== -BG_FindInfinteAmmoForWeapon -============== -*/ -qboolean BG_FindInfinteAmmoForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - return bg_weapons[ i ].infiniteAmmo; - } - } - - return qfalse; -} - -/* -============== -BG_FindUsesEnergyForWeapon -============== -*/ -qboolean BG_FindUsesEnergyForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - return bg_weapons[ i ].usesEnergy; - } - } - - return qfalse; -} - -/* -============== -BG_FindRepeatRate1ForWeapon -============== -*/ -int BG_FindRepeatRate1ForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - return bg_weapons[ i ].repeatRate1; - } - - return 1000; -} - -/* -============== -BG_FindRepeatRate2ForWeapon -============== -*/ -int BG_FindRepeatRate2ForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - return bg_weapons[ i ].repeatRate2; - } - - return 1000; -} - -/* -============== -BG_FindRepeatRate3ForWeapon -============== -*/ -int BG_FindRepeatRate3ForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - return bg_weapons[ i ].repeatRate3; - } - - return 1000; -} - -/* -============== -BG_FindReloadTimeForWeapon -============== -*/ -int BG_FindReloadTimeForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - return bg_weapons[ i ].reloadTime; - } - } - - return 1000; -} - -/* -============== -BG_WeaponHasAltMode -============== -*/ -qboolean BG_WeaponHasAltMode( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - return bg_weapons[ i ].hasAltMode; - } - } - - return qfalse; -} - -/* -============== -BG_WeaponHasThirdMode -============== -*/ -qboolean BG_WeaponHasThirdMode( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - return bg_weapons[ i ].hasThirdMode; - } - } - - return qfalse; -} - -/* -============== -BG_WeaponCanZoom -============== -*/ -qboolean BG_WeaponCanZoom( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - return bg_weapons[ i ].canZoom; - } - } - - return qfalse; -} - -/* -============== -BG_FindZoomFovForWeapon -============== -*/ -float BG_FindZoomFovForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - return bg_weapons[ i ].zoomFov; - } - } - - return qfalse; -} - -/* -============== -BG_FindPurchasableForWeapon -============== -*/ -qboolean BG_FindPurchasableForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - return bg_weapons[ i ].purchasable; - } - } - - return qfalse; -} - -/* -============== -BG_FindBuildDelayForWeapon -============== -*/ -int BG_FindBuildDelayForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - return bg_weapons[ i ].buildDelay; - } - } - - return 0; -} - -/* -============== -BG_FindTeamForWeapon -============== -*/ -WUTeam_t BG_FindTeamForWeapon( int weapon ) -{ - int i; - - for( i = 0; i < bg_numWeapons; i++ ) - { - if( bg_weapons[ i ].weaponNum == weapon ) - { - return bg_weapons[ i ].team; - } - } - - return WUT_NONE; -} - -//////////////////////////////////////////////////////////////////////////////// - -upgradeAttributes_t bg_upgrades[ ] = -{ - { - UP_LIGHTARMOUR, //int upgradeNum; - LIGHTARMOUR_PRICE, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_TORSO|SLOT_ARMS|SLOT_LEGS, //int slots; - "larmour", //char *upgradeName; - "Light Armour", //char *upgradeHumanName; - "icons/iconu_larmour", - qtrue, //qboolean purchasable - WUT_HUMANS //WUTeam_t team; - }, - { - UP_HELMET, //int upgradeNum; - HELMET_PRICE, //int price; - ( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_HEAD, //int slots; - "helmet", //char *upgradeName; - "Helmet", //char *upgradeHumanName; - "icons/iconu_helmet", - qtrue, //qboolean purchasable - WUT_HUMANS //WUTeam_t team; - }, - { - UP_MEDKIT, //int upgradeNum; - MEDKIT_PRICE, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_NONE, //int slots; - "medkit", //char *upgradeName; - "Medkit", //char *upgradeHumanName; - "icons/iconu_atoxin", - qfalse, //qboolean purchasable - WUT_HUMANS //WUTeam_t team; - }, - { - UP_BATTPACK, //int upgradeNum; - BATTPACK_PRICE, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_BACKPACK, //int slots; - "battpack", //char *upgradeName; - "Battery Pack", //char *upgradeHumanName; - "icons/iconu_battpack", - qtrue, //qboolean purchasable - WUT_HUMANS //WUTeam_t team; - }, - { - UP_JETPACK, //int upgradeNum; - JETPACK_PRICE, //int price; - ( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_BACKPACK, //int slots; - "jetpack", //char *upgradeName; - "Jet Pack", //char *upgradeHumanName; - "icons/iconu_jetpack", - qtrue, //qboolean purchasable - WUT_HUMANS //WUTeam_t team; - }, - { - UP_BATTLESUIT, //int upgradeNum; - BSUIT_PRICE, //int price; - ( 1 << S3 ), //int stages - SLOT_HEAD|SLOT_TORSO|SLOT_ARMS|SLOT_LEGS|SLOT_BACKPACK, //int slots; - "bsuit", //char *upgradeName; - "Battlesuit", //char *upgradeHumanName; - "icons/iconu_bsuit", - qtrue, //qboolean purchasable - WUT_HUMANS //WUTeam_t team; - }, - { - UP_GRENADE, //int upgradeNum; - GRENADE_PRICE, //int price; - ( 1 << S2 )|( 1 << S3 ),//int stages - SLOT_NONE, //int slots; - "gren", //char *upgradeName; - "Grenade", //char *upgradeHumanName; - 0, - qtrue, //qboolean purchasable - WUT_HUMANS //WUTeam_t team; - }, - { - UP_AMMO, //int upgradeNum; - 0, //int price; - ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages - SLOT_NONE, //int slots; - "ammo", //char *upgradeName; - "Ammunition", //char *upgradeHumanName; - 0, - qtrue, //qboolean purchasable - WUT_HUMANS //WUTeam_t team; - } -}; - -int bg_numUpgrades = sizeof( bg_upgrades ) / sizeof( bg_upgrades[ 0 ] ); - -/* -============== -BG_FindPriceForUpgrade -============== -*/ -int BG_FindPriceForUpgrade( int upgrade ) -{ - int i; - - for( i = 0; i < bg_numUpgrades; i++ ) - { - if( bg_upgrades[ i ].upgradeNum == upgrade ) - { - return bg_upgrades[ i ].price; - } - } - - return 100; -} - -/* -============== -BG_FindStagesForUpgrade -============== -*/ -qboolean BG_FindStagesForUpgrade( int upgrade, stage_t stage ) -{ - int i; - - for( i = 0; i < bg_numUpgrades; i++ ) - { - if( bg_upgrades[ i ].upgradeNum == upgrade ) - { - if( bg_upgrades[ i ].stages & ( 1 << stage ) ) - return qtrue; - else - return qfalse; - } - } - - return qfalse; -} - -/* -============== -BG_FindSlotsForUpgrade -============== -*/ -int BG_FindSlotsForUpgrade( int upgrade ) -{ - int i; - - for( i = 0; i < bg_numUpgrades; i++ ) - { - if( bg_upgrades[ i ].upgradeNum == upgrade ) - { - return bg_upgrades[ i ].slots; - } - } - - return SLOT_NONE; -} - -/* -============== -BG_FindNameForUpgrade -============== -*/ -char *BG_FindNameForUpgrade( int upgrade ) -{ - int i; - - for( i = 0; i < bg_numUpgrades; i++ ) - { - if( bg_upgrades[ i ].upgradeNum == upgrade ) - return bg_upgrades[ i ].upgradeName; - } - - //wimp out - return 0; -} - -/* -============== -BG_FindUpgradeNumForName -============== -*/ -int BG_FindUpgradeNumForName( char *name ) -{ - int i; - - for( i = 0; i < bg_numUpgrades; i++ ) - { - if( !Q_stricmp( bg_upgrades[ i ].upgradeName, name ) ) - return bg_upgrades[ i ].upgradeNum; - } - - //wimp out - return UP_NONE; -} - -/* -============== -BG_FindHumanNameForUpgrade -============== -*/ -char *BG_FindHumanNameForUpgrade( int upgrade ) -{ - int i; - - for( i = 0; i < bg_numUpgrades; i++ ) - { - if( bg_upgrades[ i ].upgradeNum == upgrade ) - return bg_upgrades[ i ].upgradeHumanName; - } - - //wimp out - return 0; -} - -/* -============== -BG_FindIconForUpgrade -============== -*/ -char *BG_FindIconForUpgrade( int upgrade ) -{ - int i; - - for( i = 0; i < bg_numUpgrades; i++ ) - { - if( bg_upgrades[ i ].upgradeNum == upgrade ) - return bg_upgrades[ i ].icon; - } - - //wimp out - return 0; -} - -/* -============== -BG_FindPurchasableForUpgrade -============== -*/ -qboolean BG_FindPurchasableForUpgrade( int upgrade ) -{ - int i; - - for( i = 0; i < bg_numUpgrades; i++ ) - { - if( bg_upgrades[ i ].upgradeNum == upgrade ) - return bg_upgrades[ i ].purchasable; - } - - return qfalse; -} - -/* -============== -BG_FindTeamForUpgrade -============== -*/ -WUTeam_t BG_FindTeamForUpgrade( int upgrade ) -{ - int i; - - for( i = 0; i < bg_numUpgrades; i++ ) - { - if( bg_upgrades[ i ].upgradeNum == upgrade ) - { - return bg_upgrades[ i ].team; - } - } - - return WUT_NONE; -} - -//////////////////////////////////////////////////////////////////////////////// - -/* -================ -BG_EvaluateTrajectory - -================ -*/ -void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) -{ - float deltaTime; - float phase; - - switch( tr->trType ) - { - case TR_STATIONARY: - case TR_INTERPOLATE: - VectorCopy( tr->trBase, result ); - break; - - case TR_LINEAR: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - break; - - case TR_SINE: - deltaTime = ( atTime - tr->trTime ) / (float)tr->trDuration; - phase = sin( deltaTime * M_PI * 2 ); - VectorMA( tr->trBase, phase, tr->trDelta, result ); - break; - - case TR_LINEAR_STOP: - if( atTime > tr->trTime + tr->trDuration ) - atTime = tr->trTime + tr->trDuration; - - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - if( deltaTime < 0 ) - deltaTime = 0; - - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - break; - - case TR_GRAVITY: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - result[ 2 ] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime; // FIXME: local gravity... - break; - - case TR_BUOYANCY: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); - result[ 2 ] += 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime; // FIXME: local gravity... - break; - - default: - Com_Error( ERR_DROP, "BG_EvaluateTrajectory: unknown trType: %i", tr->trTime ); - break; - } -} - -/* -================ -BG_EvaluateTrajectoryDelta - -For determining velocity at a given time -================ -*/ -void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ) -{ - float deltaTime; - float phase; - - switch( tr->trType ) - { - case TR_STATIONARY: - case TR_INTERPOLATE: - VectorClear( result ); - break; - - case TR_LINEAR: - VectorCopy( tr->trDelta, result ); - break; - - case TR_SINE: - deltaTime = ( atTime - tr->trTime ) / (float)tr->trDuration; - phase = cos( deltaTime * M_PI * 2 ); // derivative of sin = cos - phase *= 0.5; - VectorScale( tr->trDelta, phase, result ); - break; - - case TR_LINEAR_STOP: - if( atTime > tr->trTime + tr->trDuration ) - { - VectorClear( result ); - return; - } - VectorCopy( tr->trDelta, result ); - break; - - case TR_GRAVITY: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorCopy( tr->trDelta, result ); - result[ 2 ] -= DEFAULT_GRAVITY * deltaTime; // FIXME: local gravity... - break; - - case TR_BUOYANCY: - deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds - VectorCopy( tr->trDelta, result ); - result[ 2 ] += DEFAULT_GRAVITY * deltaTime; // FIXME: local gravity... - break; - - default: - Com_Error( ERR_DROP, "BG_EvaluateTrajectoryDelta: unknown trType: %i", tr->trTime ); - break; - } -} - -char *eventnames[ ] = -{ - "EV_NONE", - - "EV_FOOTSTEP", - "EV_FOOTSTEP_METAL", - "EV_FOOTSTEP_SQUELCH", - "EV_FOOTSPLASH", - "EV_FOOTWADE", - "EV_SWIM", - - "EV_STEP_4", - "EV_STEP_8", - "EV_STEP_12", - "EV_STEP_16", - - "EV_STEPDN_4", - "EV_STEPDN_8", - "EV_STEPDN_12", - "EV_STEPDN_16", - - "EV_FALL_SHORT", - "EV_FALL_MEDIUM", - "EV_FALL_FAR", - "EV_FALLING", - - "EV_JUMP", - "EV_WATER_TOUCH", // foot touches - "EV_WATER_LEAVE", // foot leaves - "EV_WATER_UNDER", // head touches - "EV_WATER_CLEAR", // head leaves - - "EV_NOAMMO", - "EV_CHANGE_WEAPON", - "EV_FIRE_WEAPON", - "EV_FIRE_WEAPON2", - "EV_FIRE_WEAPON3", - - "EV_PLAYER_RESPAWN", //TA: for fovwarp effects - "EV_PLAYER_TELEPORT_IN", - "EV_PLAYER_TELEPORT_OUT", - - "EV_GRENADE_BOUNCE", // eventParm will be the soundindex - - "EV_GENERAL_SOUND", - "EV_GLOBAL_SOUND", // no attenuation - - "EV_BULLET_HIT_FLESH", - "EV_BULLET_HIT_WALL", - - "EV_SHOTGUN", - - "EV_MISSILE_HIT", - "EV_MISSILE_MISS", - "EV_MISSILE_MISS_METAL", - "EV_TESLATRAIL", - "EV_BULLET", // otherEntity is the shooter - - "EV_LEV1_GRAB", - "EV_LEV4_CHARGE_PREPARE", - "EV_LEV4_CHARGE_START", - - "EV_PAIN", - "EV_DEATH1", - "EV_DEATH2", - "EV_DEATH3", - "EV_OBITUARY", - - "EV_GIB_PLAYER", // gib a previously living player - - "EV_BUILD_CONSTRUCT", //TA - "EV_BUILD_DESTROY", //TA - "EV_BUILD_DELAY", //TA: can't build yet - "EV_BUILD_REPAIR", //TA: repairing buildable - "EV_BUILD_REPAIRED", //TA: buildable has full health - "EV_HUMAN_BUILDABLE_EXPLOSION", - "EV_ALIEN_BUILDABLE_EXPLOSION", - "EV_ALIEN_ACIDTUBE", - - "EV_MEDKIT_USED", - - "EV_ALIEN_EVOLVE", - "EV_ALIEN_EVOLVE_FAILED", - - "EV_DEBUG_LINE", - "EV_STOPLOOPINGSOUND", - "EV_TAUNT", - - "EV_OVERMIND_ATTACK", //TA: overmind under attack - "EV_OVERMIND_DYING", //TA: overmind close to death - "EV_OVERMIND_SPAWNS", //TA: overmind needs spawns - - "EV_DCC_ATTACK", //TA: dcc under attack - - "EV_RPTUSE_SOUND" //TA: trigger a sound -}; - -/* -=============== -BG_AddPredictableEventToPlayerstate - -Handles the sequence numbers -=============== -*/ - -void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ); - -void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ) -{ -#ifdef _DEBUG - { - char buf[ 256 ]; - trap_Cvar_VariableStringBuffer( "showevents", buf, sizeof( buf ) ); - - if( atof( buf ) != 0 ) - { -#ifdef QAGAME - Com_Printf( " game event svt %5d -> %5d: num = %20s parm %d\n", - ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[ newEvent ], eventParm); -#else - Com_Printf( "Cgame event svt %5d -> %5d: num = %20s parm %d\n", - ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[ newEvent ], eventParm); -#endif - } - } -#endif - ps->events[ ps->eventSequence & ( MAX_PS_EVENTS - 1 ) ] = newEvent; - ps->eventParms[ ps->eventSequence & ( MAX_PS_EVENTS - 1 ) ] = eventParm; - ps->eventSequence++; -} - - -/* -======================== -BG_PlayerStateToEntityState - -This is done after each set of usercmd_t on the server, -and after local prediction on the client -======================== -*/ -void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ) -{ - int i; - - if( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR || ps->pm_type == PM_FREEZE ) - s->eType = ET_INVISIBLE; - else if( ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) - s->eType = ET_INVISIBLE; - else - s->eType = ET_PLAYER; - - s->number = ps->clientNum; - - s->pos.trType = TR_INTERPOLATE; - VectorCopy( ps->origin, s->pos.trBase ); - - if( snap ) - SnapVector( s->pos.trBase ); - - //set the trDelta for flag direction - VectorCopy( ps->velocity, s->pos.trDelta ); - - s->apos.trType = TR_INTERPOLATE; - VectorCopy( ps->viewangles, s->apos.trBase ); - - if( snap ) - SnapVector( s->apos.trBase ); - - //TA: i need for other things :) - //s->angles2[YAW] = ps->movementDir; - s->time2 = ps->movementDir; - s->legsAnim = ps->legsAnim; - s->torsoAnim = ps->torsoAnim; - s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number - // so corpses can also reference the proper config - s->eFlags = ps->eFlags; - if( ps->stats[STAT_HEALTH] <= 0 ) - s->eFlags |= EF_DEAD; - else - s->eFlags &= ~EF_DEAD; - - if( ps->stats[ STAT_STATE ] & SS_BLOBLOCKED ) - s->eFlags |= EF_BLOBLOCKED; - else - s->eFlags &= ~EF_BLOBLOCKED; - - if( ps->externalEvent ) - { - s->event = ps->externalEvent; - s->eventParm = ps->externalEventParm; - } - else if( ps->entityEventSequence < ps->eventSequence ) - { - int seq; - - if( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS ) - ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS; - - seq = ps->entityEventSequence & ( MAX_PS_EVENTS - 1 ); - s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 ); - s->eventParm = ps->eventParms[ seq ]; - ps->entityEventSequence++; - } - - s->weapon = ps->weapon; - s->groundEntityNum = ps->groundEntityNum; - - //store items held and active items in otherEntityNum - s->modelindex = 0; - s->modelindex2 = 0; - for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) - { - if( BG_InventoryContainsUpgrade( i, ps->stats ) ) - { - s->modelindex |= 1 << i; - - if( BG_UpgradeIsActive( i, ps->stats ) ) - s->modelindex2 |= 1 << i; - } - } - - //TA: use powerups field to store team/class info: - s->powerups = ps->stats[ STAT_PTEAM ] | ( ps->stats[ STAT_PCLASS ] << 8 ); - - //TA: have to get the surfNormal thru somehow... - VectorCopy( ps->grapplePoint, s->angles2 ); - if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) - s->eFlags |= EF_WALLCLIMBCEILING; - - s->loopSound = ps->loopSound; - s->generic1 = ps->generic1; - - if( s->generic1 <= WPM_NONE || s->generic1 >= WPM_NUM_WEAPONMODES ) - s->generic1 = WPM_PRIMARY; -} - - -/* -======================== -BG_PlayerStateToEntityStateExtraPolate - -This is done after each set of usercmd_t on the server, -and after local prediction on the client -======================== -*/ -void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ) -{ - int i; - - if( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR || ps->pm_type == PM_FREEZE ) - s->eType = ET_INVISIBLE; - else if( ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) - s->eType = ET_INVISIBLE; - else - s->eType = ET_PLAYER; - - s->number = ps->clientNum; - - s->pos.trType = TR_LINEAR_STOP; - VectorCopy( ps->origin, s->pos.trBase ); - - if( snap ) - SnapVector( s->pos.trBase ); - - // set the trDelta for flag direction and linear prediction - VectorCopy( ps->velocity, s->pos.trDelta ); - // set the time for linear prediction - s->pos.trTime = time; - // set maximum extra polation time - s->pos.trDuration = 50; // 1000 / sv_fps (default = 20) - - s->apos.trType = TR_INTERPOLATE; - VectorCopy( ps->viewangles, s->apos.trBase ); - if( snap ) - SnapVector( s->apos.trBase ); - - //TA: i need for other things :) - //s->angles2[YAW] = ps->movementDir; - s->time2 = ps->movementDir; - s->legsAnim = ps->legsAnim; - s->torsoAnim = ps->torsoAnim; - s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number - // so corpses can also reference the proper config - s->eFlags = ps->eFlags; - - if( ps->stats[STAT_HEALTH] <= 0 ) - s->eFlags |= EF_DEAD; - else - s->eFlags &= ~EF_DEAD; - - if( ps->stats[ STAT_STATE ] & SS_BLOBLOCKED ) - s->eFlags |= EF_BLOBLOCKED; - else - s->eFlags &= ~EF_BLOBLOCKED; - - if( ps->externalEvent ) - { - s->event = ps->externalEvent; - s->eventParm = ps->externalEventParm; - } - else if( ps->entityEventSequence < ps->eventSequence ) - { - int seq; - - if( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS ) - ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS; - - seq = ps->entityEventSequence & ( MAX_PS_EVENTS - 1 ); - s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 ); - s->eventParm = ps->eventParms[ seq ]; - ps->entityEventSequence++; - } - - s->weapon = ps->weapon; - s->groundEntityNum = ps->groundEntityNum; - - //store items held and active items in otherEntityNum - s->modelindex = 0; - s->modelindex2 = 0; - - for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) - { - if( BG_InventoryContainsUpgrade( i, ps->stats ) ) - { - s->modelindex |= 1 << i; - - if( BG_UpgradeIsActive( i, ps->stats ) ) - s->modelindex2 |= 1 << i; - } - } - - //TA: use powerups field to store team/class info: - s->powerups = ps->stats[ STAT_PTEAM ] | ( ps->stats[ STAT_PCLASS ] << 8 ); - - //TA: have to get the surfNormal thru somehow... - VectorCopy( ps->grapplePoint, s->angles2 ); - if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) - s->eFlags |= EF_WALLCLIMBCEILING; - - s->loopSound = ps->loopSound; - s->generic1 = ps->generic1; - - if( s->generic1 <= WPM_NONE || s->generic1 >= WPM_NUM_WEAPONMODES ) - s->generic1 = WPM_PRIMARY; -} - -/* -======================== -BG_UnpackAmmoArray - -Extract the ammo quantity from the array -======================== -*/ -void BG_UnpackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int *ammo, int *clips ) -{ - int ammoarray[ 32 ]; - int i; - - for( i = 0; i <= 15; i++ ) - ammoarray[ i ] = psAmmo[ i ]; - - for( i = 16; i <= 31; i++ ) - ammoarray[ i ] = psAmmo2[ i - 16 ]; - - if( ammo != NULL ) - *ammo = ammoarray[ weapon ] & 0x0FFF; - - if( clips != NULL ) - *clips = ( ammoarray[ weapon ] >> 12 ) & 0x0F; -} - -/* -======================== -BG_PackAmmoArray - -Pack the ammo quantity into the array -======================== -*/ -void BG_PackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int ammo, int clips ) -{ - int weaponvalue; - - weaponvalue = ammo | ( clips << 12 ); - - if( weapon <= 15 ) - psAmmo[ weapon ] = weaponvalue; - else if( weapon >= 16 ) - psAmmo2[ weapon - 16 ] = weaponvalue; -} - -/* -======================== -BG_WeaponIsFull - -Check if a weapon has full ammo -======================== -*/ -qboolean BG_WeaponIsFull( weapon_t weapon, int stats[ ], int psAmmo[ ], int psAmmo2[ ] ) -{ - int maxAmmo, maxClips; - int ammo, clips; - - BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips ); - BG_UnpackAmmoArray( weapon, psAmmo, psAmmo2, &ammo, &clips ); - - if( BG_InventoryContainsUpgrade( UP_BATTPACK, stats ) ) - maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER ); - - return ( maxAmmo == ammo ) && ( maxClips == clips ); -} - -/* -======================== -BG_AddWeaponToInventory - -Give a player a weapon -======================== -*/ -void BG_AddWeaponToInventory( int weapon, int stats[ ] ) -{ - int weaponList; - - weaponList = ( stats[ STAT_WEAPONS ] & 0x0000FFFF ) | ( ( stats[ STAT_WEAPONS2 ] << 16 ) & 0xFFFF0000 ); - - weaponList |= ( 1 << weapon ); - - stats[ STAT_WEAPONS ] = weaponList & 0x0000FFFF; - stats[ STAT_WEAPONS2 ] = ( weaponList & 0xFFFF0000 ) >> 16; - - if( stats[ STAT_SLOTS ] & BG_FindSlotsForWeapon( weapon ) ) - Com_Printf( S_COLOR_YELLOW "WARNING: Held items conflict with weapon %d\n", weapon ); - - stats[ STAT_SLOTS ] |= BG_FindSlotsForWeapon( weapon ); -} - -/* -======================== -BG_RemoveWeaponToInventory - -Take a weapon from a player -======================== -*/ -void BG_RemoveWeaponFromInventory( int weapon, int stats[ ] ) -{ - int weaponList; - - weaponList = ( stats[ STAT_WEAPONS ] & 0x0000FFFF ) | ( ( stats[ STAT_WEAPONS2 ] << 16 ) & 0xFFFF0000 ); - - weaponList &= ~( 1 << weapon ); - - stats[ STAT_WEAPONS ] = weaponList & 0x0000FFFF; - stats[ STAT_WEAPONS2 ] = ( weaponList & 0xFFFF0000 ) >> 16; - - stats[ STAT_SLOTS ] &= ~BG_FindSlotsForWeapon( weapon ); -} - -/* -======================== -BG_InventoryContainsWeapon - -Does the player hold a weapon? -======================== -*/ -qboolean BG_InventoryContainsWeapon( int weapon, int stats[ ] ) -{ - int weaponList; - - weaponList = ( stats[ STAT_WEAPONS ] & 0x0000FFFF ) | ( ( stats[ STAT_WEAPONS2 ] << 16 ) & 0xFFFF0000 ); - - return( weaponList & ( 1 << weapon ) ); -} - -/* -======================== -BG_AddUpgradeToInventory - -Give the player an upgrade -======================== -*/ -void BG_AddUpgradeToInventory( int item, int stats[ ] ) -{ - stats[ STAT_ITEMS ] |= ( 1 << item ); - - if( stats[ STAT_SLOTS ] & BG_FindSlotsForUpgrade( item ) ) - Com_Printf( S_COLOR_YELLOW "WARNING: Held items conflict with upgrade %d\n", item ); - - stats[ STAT_SLOTS ] |= BG_FindSlotsForUpgrade( item ); -} - -/* -======================== -BG_RemoveUpgradeFromInventory - -Take an upgrade from the player -======================== -*/ -void BG_RemoveUpgradeFromInventory( int item, int stats[ ] ) -{ - stats[ STAT_ITEMS ] &= ~( 1 << item ); - - stats[ STAT_SLOTS ] &= ~BG_FindSlotsForUpgrade( item ); -} - -/* -======================== -BG_InventoryContainsUpgrade - -Does the player hold an upgrade? -======================== -*/ -qboolean BG_InventoryContainsUpgrade( int item, int stats[ ] ) -{ - return( stats[ STAT_ITEMS ] & ( 1 << item ) ); -} - -/* -======================== -BG_ActivateUpgrade - -Activates an upgrade -======================== -*/ -void BG_ActivateUpgrade( int item, int stats[ ] ) -{ - stats[ STAT_ACTIVEITEMS ] |= ( 1 << item ); -} - -/* -======================== -BG_DeactivateUpgrade - -Deactivates an upgrade -======================== -*/ -void BG_DeactivateUpgrade( int item, int stats[ ] ) -{ - stats[ STAT_ACTIVEITEMS ] &= ~( 1 << item ); -} - -/* -======================== -BG_UpgradeIsActive - -Is this upgrade active? -======================== -*/ -qboolean BG_UpgradeIsActive( int item, int stats[ ] ) -{ - return( stats[ STAT_ACTIVEITEMS ] & ( 1 << item ) ); -} - -/* -=============== -BG_RotateAxis - -Shared axis rotation function -=============== -*/ -qboolean BG_RotateAxis( vec3_t surfNormal, vec3_t inAxis[ 3 ], - vec3_t outAxis[ 3 ], qboolean inverse, qboolean ceiling ) -{ - vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; - vec3_t ceilingNormal = { 0.0f, 0.0f, -1.0f }; - vec3_t localNormal, xNormal; - float rotAngle; - - //the grapplePoint being a surfNormal rotation Normal hack... see above :) - if( ceiling ) - { - VectorCopy( ceilingNormal, localNormal ); - VectorCopy( surfNormal, xNormal ); - } - else - { - //cross the reference normal and the surface normal to get the rotation axis - VectorCopy( surfNormal, localNormal ); - CrossProduct( localNormal, refNormal, xNormal ); - VectorNormalize( xNormal ); - } - - //can't rotate with no rotation vector - if( VectorLength( xNormal ) != 0.0f ) - { - rotAngle = RAD2DEG( acos( DotProduct( localNormal, refNormal ) ) ); - - if( inverse ) - rotAngle = -rotAngle; - - AngleNormalize180( rotAngle ); - - //hmmm could get away with only one rotation and some clever stuff later... but i'm lazy - RotatePointAroundVector( outAxis[ 0 ], xNormal, inAxis[ 0 ], -rotAngle ); - RotatePointAroundVector( outAxis[ 1 ], xNormal, inAxis[ 1 ], -rotAngle ); - RotatePointAroundVector( outAxis[ 2 ], xNormal, inAxis[ 2 ], -rotAngle ); - } - else - return qfalse; - - return qtrue; -} - -/* -=============== -BG_PositionBuildableRelativeToPlayer - -Find a place to build a buildable -=============== -*/ -void BG_PositionBuildableRelativeToPlayer( const playerState_t *ps, - const vec3_t mins, const vec3_t maxs, - void (*trace)( trace_t *, const vec3_t, const vec3_t, - const vec3_t, const vec3_t, int, int ), - vec3_t outOrigin, vec3_t outAngles, trace_t *tr ) -{ - vec3_t forward, entityOrigin, targetOrigin; - vec3_t angles, playerOrigin, playerNormal; - float buildDist; - - if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) - { - if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) - VectorSet( playerNormal, 0.0f, 0.0f, -1.0f ); - else - VectorCopy( ps->grapplePoint, playerNormal ); - } - else - VectorSet( playerNormal, 0.0f, 0.0f, 1.0f ); - - VectorCopy( ps->viewangles, angles ); - VectorCopy( ps->origin, playerOrigin ); - buildDist = BG_FindBuildDistForClass( ps->stats[ STAT_PCLASS ] ); - - AngleVectors( angles, forward, NULL, NULL ); - ProjectPointOnPlane( forward, forward, playerNormal ); - VectorNormalize( forward ); - - VectorMA( playerOrigin, buildDist, forward, entityOrigin ); - - VectorCopy( entityOrigin, targetOrigin ); - - //so buildings can be placed facing slopes - VectorMA( entityOrigin, 32, playerNormal, entityOrigin ); - - //so buildings drop to floor - VectorMA( targetOrigin, -128, playerNormal, targetOrigin ); - - (*trace)( tr, entityOrigin, mins, maxs, targetOrigin, ps->clientNum, MASK_PLAYERSOLID ); - VectorCopy( tr->endpos, entityOrigin ); - VectorMA( entityOrigin, 0.1f, playerNormal, outOrigin ); - vectoangles( forward, outAngles ); -} - -/* -=============== -BG_GetValueOfHuman - -Returns the kills value of some human player -=============== -*/ -int BG_GetValueOfHuman( playerState_t *ps ) -{ - int i, worth = 0; - float portion; - - for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) - { - if( BG_InventoryContainsUpgrade( i, ps->stats ) ) - worth += BG_FindPriceForUpgrade( i ); - } - - for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) - { - if( BG_InventoryContainsWeapon( i, ps->stats ) ) - worth += BG_FindPriceForWeapon( i ); - } - - portion = worth / (float)HUMAN_MAXED; - - if( portion < 0.01f ) - portion = 0.01f; - else if( portion > 1.0f ) - portion = 1.0f; - - return ceil( ALIEN_MAX_SINGLE_KILLS * portion ); -} - -/* -=============== -atof_neg - -atof with an allowance for negative values -=============== -*/ -float atof_neg( char *token, qboolean allowNegative ) -{ - float value; - - value = atof( token ); - - if( !allowNegative && value < 0.0f ) - value = 1.0f; - - return value; -} - -/* -=============== -atoi_neg - -atoi with an allowance for negative values -=============== -*/ -int atoi_neg( char *token, qboolean allowNegative ) -{ - int value; - - value = atoi( token ); - - if( !allowNegative && value < 0 ) - value = 1; - - return value; -} - -/* -=============== -BG_ParseCSVEquipmentList -=============== -*/ -void BG_ParseCSVEquipmentList( const char *string, weapon_t *weapons, int weaponsSize, - upgrade_t *upgrades, int upgradesSize ) -{ - char buffer[ MAX_STRING_CHARS ]; - int i = 0, j = 0; - char *p, *q; - qboolean EOS = qfalse; - - Q_strncpyz( buffer, string, MAX_STRING_CHARS ); - - p = q = buffer; - - while( *p != '\0' ) - { - //skip to first , or EOS - while( *p != ',' && *p != '\0' ) - p++; - - if( *p == '\0' ) - EOS = qtrue; - - *p = '\0'; - - //strip leading whitespace - while( *q == ' ' ) - q++; - - if( weaponsSize ) - weapons[ i ] = BG_FindWeaponNumForName( q ); - - if( upgradesSize ) - upgrades[ j ] = BG_FindUpgradeNumForName( q ); - - if( weaponsSize && weapons[ i ] == WP_NONE && - upgradesSize && upgrades[ j ] == UP_NONE ) - Com_Printf( S_COLOR_YELLOW "WARNING: unknown equipment %s\n", q ); - else if( weaponsSize && weapons[ i ] != WP_NONE ) - i++; - else if( upgradesSize && upgrades[ j ] != UP_NONE ) - j++; - - if( !EOS ) - { - p++; - q = p; - } - else - break; - - if( i == ( weaponsSize - 1 ) || j == ( upgradesSize - 1 ) ) - break; - } - - if( weaponsSize ) - weapons[ i ] = WP_NONE; - - if( upgradesSize ) - upgrades[ j ] = UP_NONE; -} - -/* -=============== -BG_ParseCSVClassList -=============== -*/ -void BG_ParseCSVClassList( const char *string, pClass_t *classes, int classesSize ) -{ - char buffer[ MAX_STRING_CHARS ]; - int i = 0; - char *p, *q; - qboolean EOS = qfalse; - - Q_strncpyz( buffer, string, MAX_STRING_CHARS ); - - p = q = buffer; - - while( *p != '\0' ) - { - //skip to first , or EOS - while( *p != ',' && *p != '\0' ) - p++; - - if( *p == '\0' ) - EOS = qtrue; - - *p = '\0'; - - //strip leading whitespace - while( *q == ' ' ) - q++; - - classes[ i ] = BG_FindClassNumForName( q ); - - if( classes[ i ] == PCL_NONE ) - Com_Printf( S_COLOR_YELLOW "WARNING: unknown class %s\n", q ); - else - i++; - - if( !EOS ) - { - p++; - q = p; - } - else - break; - } - - classes[ i ] = PCL_NONE; -} - -/* -=============== -BG_ParseCSVBuildableList -=============== -*/ -void BG_ParseCSVBuildableList( const char *string, buildable_t *buildables, int buildablesSize ) -{ - char buffer[ MAX_STRING_CHARS ]; - int i = 0; - char *p, *q; - qboolean EOS = qfalse; - - Q_strncpyz( buffer, string, MAX_STRING_CHARS ); - - p = q = buffer; - - while( *p != '\0' ) - { - //skip to first , or EOS - while( *p != ',' && *p != '\0' ) - p++; - - if( *p == '\0' ) - EOS = qtrue; - - *p = '\0'; - - //strip leading whitespace - while( *q == ' ' ) - q++; - - buildables[ i ] = BG_FindClassNumForName( q ); - - if( buildables[ i ] == BA_NONE ) - Com_Printf( S_COLOR_YELLOW "WARNING: unknown buildable %s\n", q ); - else - i++; - - if( !EOS ) - { - p++; - q = p; - } - else - break; - } - - buildables[ i ] = BA_NONE; -} diff --git a/src/game/bg_pmove.c b/src/game/bg_pmove.c deleted file mode 100644 index 88432f81..00000000 --- a/src/game/bg_pmove.c +++ /dev/null @@ -1,3471 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_pmove.c -- both games player movement code -// takes a playerstate and a usercmd as input and returns a modifed playerstate - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "q_shared.h" -#include "bg_public.h" -#include "bg_local.h" - -pmove_t *pm; -pml_t pml; - -// movement parameters -float pm_stopspeed = 100.0f; -float pm_duckScale = 0.25f; -float pm_swimScale = 0.50f; -float pm_wadeScale = 0.70f; - -float pm_accelerate = 10.0f; -float pm_airaccelerate = 1.0f; -float pm_wateraccelerate = 4.0f; -float pm_flyaccelerate = 4.0f; - -float pm_friction = 6.0f; -float pm_waterfriction = 1.0f; -float pm_flightfriction = 6.0f; -float pm_spectatorfriction = 5.0f; - -int c_pmove = 0; - -/* -=============== -PM_AddEvent - -=============== -*/ -void PM_AddEvent( int newEvent ) -{ - BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps ); -} - -/* -=============== -PM_AddTouchEnt -=============== -*/ -void PM_AddTouchEnt( int entityNum ) -{ - int i; - - if( entityNum == ENTITYNUM_WORLD ) - return; - - if( pm->numtouch == MAXTOUCH ) - return; - - // see if it is already added - for( i = 0 ; i < pm->numtouch ; i++ ) - { - if( pm->touchents[ i ] == entityNum ) - return; - } - - // add it - pm->touchents[ pm->numtouch ] = entityNum; - pm->numtouch++; -} - -/* -=================== -PM_StartTorsoAnim -=================== -*/ -static void PM_StartTorsoAnim( int anim ) -{ - if( pm->ps->pm_type >= PM_DEAD ) - return; - - pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) - | anim; -} - -/* -=================== -PM_StartLegsAnim -=================== -*/ -static void PM_StartLegsAnim( int anim ) -{ - if( pm->ps->pm_type >= PM_DEAD ) - return; - - //legsTimer is clamped too tightly for nonsegmented models - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - { - if( pm->ps->legsTimer > 0 ) - return; // a high priority animation is running - } - else - { - if( pm->ps->torsoTimer > 0 ) - return; // a high priority animation is running - } - - pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) - | anim; -} - -/* -=================== -PM_ContinueLegsAnim -=================== -*/ -static void PM_ContinueLegsAnim( int anim ) -{ - if( ( pm->ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim ) - return; - - //legsTimer is clamped too tightly for nonsegmented models - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - { - if( pm->ps->legsTimer > 0 ) - return; // a high priority animation is running - } - else - { - if( pm->ps->torsoTimer > 0 ) - return; // a high priority animation is running - } - - PM_StartLegsAnim( anim ); -} - -/* -=================== -PM_ContinueTorsoAnim -=================== -*/ -static void PM_ContinueTorsoAnim( int anim ) -{ - if( ( pm->ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim ) - return; - - if( pm->ps->torsoTimer > 0 ) - return; // a high priority animation is running - - PM_StartTorsoAnim( anim ); -} - -/* -=================== -PM_ForceLegsAnim -=================== -*/ -static void PM_ForceLegsAnim( int anim ) -{ - //legsTimer is clamped too tightly for nonsegmented models - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - pm->ps->legsTimer = 0; - else - pm->ps->torsoTimer = 0; - - PM_StartLegsAnim( anim ); -} - - -/* -================== -PM_ClipVelocity - -Slide off of the impacting surface -================== -*/ -void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) -{ - float backoff; - float change; - int i; - - backoff = DotProduct( in, normal ); - - //Com_Printf( "%1.0f ", backoff ); - - if( backoff < 0 ) - backoff *= overbounce; - else - backoff /= overbounce; - - for( i = 0; i < 3; i++ ) - { - change = normal[ i ] * backoff; - //Com_Printf( "%1.0f ", change ); - out[ i ] = in[ i ] - change; - } - - //Com_Printf( " " ); -} - - -/* -================== -PM_Friction - -Handles both ground friction and water friction -================== -*/ -static void PM_Friction( void ) -{ - vec3_t vec; - float *vel; - float speed, newspeed, control; - float drop; - - vel = pm->ps->velocity; - - //TA: make sure vertical velocity is NOT set to zero when wall climbing - VectorCopy( vel, vec ); - if( pml.walking && !( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ) - vec[ 2 ] = 0; // ignore slope movement - - speed = VectorLength( vec ); - - if( speed < 1 ) - { - vel[ 0 ] = 0; - vel[ 1 ] = 0; // allow sinking underwater - // FIXME: still have z friction underwater? - return; - } - - drop = 0; - - // apply ground friction - if( pm->waterlevel <= 1 ) - { - if( ( pml.walking || pml.ladder ) && !( pml.groundTrace.surfaceFlags & SURF_SLICK ) ) - { - // if getting knocked back, no friction - if( !( pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) ) - { - float stopSpeed = BG_FindStopSpeedForClass( pm->ps->stats[ STAT_PCLASS ] ); - - control = speed < stopSpeed ? stopSpeed : speed; - drop += control * BG_FindFrictionForClass( pm->ps->stats[ STAT_PCLASS ] ) * pml.frametime; - } - } - } - - // apply water friction even if just wading - if( pm->waterlevel ) - drop += speed * pm_waterfriction * pm->waterlevel * pml.frametime; - - // apply flying friction - if( pm->ps->pm_type == PM_JETPACK ) - drop += speed * pm_flightfriction * pml.frametime; - - if( pm->ps->pm_type == PM_SPECTATOR ) - drop += speed * pm_spectatorfriction * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - if( newspeed < 0 ) - newspeed = 0; - - newspeed /= speed; - - vel[ 0 ] = vel[ 0 ] * newspeed; - vel[ 1 ] = vel[ 1 ] * newspeed; - vel[ 2 ] = vel[ 2 ] * newspeed; -} - - -/* -============== -PM_Accelerate - -Handles user intended acceleration -============== -*/ -static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) -{ -#if 1 - // q2 style - int i; - float addspeed, accelspeed, currentspeed; - - currentspeed = DotProduct( pm->ps->velocity, wishdir ); - addspeed = wishspeed - currentspeed; - if( addspeed <= 0 ) - return; - - accelspeed = accel * pml.frametime * wishspeed; - if( accelspeed > addspeed ) - accelspeed = addspeed; - - for( i = 0; i < 3; i++ ) - pm->ps->velocity[ i ] += accelspeed * wishdir[ i ]; -#else - // proper way (avoids strafe jump maxspeed bug), but feels bad - vec3_t wishVelocity; - vec3_t pushDir; - float pushLen; - float canPush; - - VectorScale( wishdir, wishspeed, wishVelocity ); - VectorSubtract( wishVelocity, pm->ps->velocity, pushDir ); - pushLen = VectorNormalize( pushDir ); - - canPush = accel * pml.frametime * wishspeed; - if( canPush > pushLen ) - canPush = pushLen; - - VectorMA( pm->ps->velocity, canPush, pushDir, pm->ps->velocity ); -#endif -} - - - -/* -============ -PM_CmdScale - -Returns the scale factor to apply to cmd movements -This allows the clients to use axial -127 to 127 values for all directions -without getting a sqrt(2) distortion in speed. -============ -*/ -static float PM_CmdScale( usercmd_t *cmd ) -{ - int max; - float total; - float scale; - float modifier = 1.0f; - - if( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS && pm->ps->pm_type == PM_NORMAL ) - { - if( pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST ) - modifier *= HUMAN_SPRINT_MODIFIER; - else - modifier *= HUMAN_JOG_MODIFIER; - - if( cmd->forwardmove < 0 ) - { - //can't run backwards - modifier *= HUMAN_BACK_MODIFIER; - } - else if( cmd->rightmove ) - { - //can't move that fast sideways - modifier *= HUMAN_SIDE_MODIFIER; - } - - //must have +ve stamina to jump - if( pm->ps->stats[ STAT_STAMINA ] < 0 ) - cmd->upmove = 0; - - //slow down once stamina depletes - if( pm->ps->stats[ STAT_STAMINA ] <= -500 ) - modifier *= (float)( pm->ps->stats[ STAT_STAMINA ] + 1000 ) / 500.0f; - - if( pm->ps->stats[ STAT_STATE ] & SS_CREEPSLOWED ) - { - if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, pm->ps->stats ) || - BG_InventoryContainsUpgrade( UP_BATTLESUIT, pm->ps->stats ) ) - modifier *= CREEP_ARMOUR_MODIFIER; - else - modifier *= CREEP_MODIFIER; - } - } - - if( pm->ps->weapon == WP_ALEVEL4 && pm->ps->pm_flags & PMF_CHARGE ) - modifier *= ( 1.0f + ( pm->ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME ) * - ( LEVEL4_CHARGE_SPEED - 1.0f ) ); - - //slow player if charging up for a pounce - if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG ) && - cmd->buttons & BUTTON_ATTACK2 ) - modifier *= LEVEL3_POUNCE_SPEED_MOD; - - //slow the player if slow locked - if( pm->ps->stats[ STAT_STATE ] & SS_SLOWLOCKED ) - modifier *= ABUILDER_BLOB_SPEED_MOD; - - if( pm->ps->pm_type == PM_GRABBED ) - modifier = 0.0f; - - if( pm->ps->pm_type != PM_SPECTATOR && pm->ps->pm_type != PM_NOCLIP ) - { - if( BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ) == 0.0f ) - cmd->upmove = 0; - - //prevent speed distortions for non ducking classes - if( !( pm->ps->pm_flags & PMF_DUCKED ) && pm->ps->pm_type != PM_JETPACK && cmd->upmove < 0 ) - cmd->upmove = 0; - } - - max = abs( cmd->forwardmove ); - if( abs( cmd->rightmove ) > max ) - max = abs( cmd->rightmove ); - - if( abs( cmd->upmove ) > max ) - max = abs( cmd->upmove ); - - if( !max ) - return 0; - - total = sqrt( cmd->forwardmove * cmd->forwardmove - + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove ); - - scale = (float)pm->ps->speed * max / ( 127.0 * total ) * modifier; - - return scale; -} - - -/* -================ -PM_SetMovementDir - -Determine the rotation of the legs reletive -to the facing dir -================ -*/ -static void PM_SetMovementDir( void ) -{ - if( pm->cmd.forwardmove || pm->cmd.rightmove ) - { - if( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 ) - pm->ps->movementDir = 0; - else if( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 ) - pm->ps->movementDir = 1; - else if( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 ) - pm->ps->movementDir = 2; - else if( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 ) - pm->ps->movementDir = 3; - else if( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 ) - pm->ps->movementDir = 4; - else if( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 ) - pm->ps->movementDir = 5; - else if( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 ) - pm->ps->movementDir = 6; - else if( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 ) - pm->ps->movementDir = 7; - } - else - { - // if they aren't actively going directly sideways, - // change the animation to the diagonal so they - // don't stop too crooked - if( pm->ps->movementDir == 2 ) - pm->ps->movementDir = 1; - else if( pm->ps->movementDir == 6 ) - pm->ps->movementDir = 7; - } -} - - -/* -============= -PM_CheckCharge -============= -*/ -static void PM_CheckCharge( void ) -{ - if( pm->ps->weapon != WP_ALEVEL4 ) - return; - - if( pm->cmd.buttons & BUTTON_ATTACK2 && - !( pm->ps->stats[ STAT_STATE ] & SS_CHARGING ) ) - { - pm->ps->pm_flags &= ~PMF_CHARGE; - return; - } - - if( pm->ps->stats[ STAT_MISC ] > 0 ) - pm->ps->pm_flags |= PMF_CHARGE; - else - pm->ps->pm_flags &= ~PMF_CHARGE; -} - -/* -============= -PM_CheckPounce -============= -*/ -static qboolean PM_CheckPounce( void ) -{ - if( pm->ps->weapon != WP_ALEVEL3 && - pm->ps->weapon != WP_ALEVEL3_UPG ) - return qfalse; - - if( pm->cmd.buttons & BUTTON_ATTACK2 ) - { - pm->ps->pm_flags &= ~PMF_CHARGE; - return qfalse; - } - - if( pm->ps->pm_flags & PMF_CHARGE ) - return qfalse; - - if( pm->ps->stats[ STAT_MISC ] == 0 ) - return qfalse; - - pml.groundPlane = qfalse; // jumping away - pml.walking = qfalse; - - pm->ps->pm_flags |= PMF_CHARGE; - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - - VectorMA( pm->ps->velocity, pm->ps->stats[ STAT_MISC ], pml.forward, pm->ps->velocity ); - - PM_AddEvent( EV_JUMP ); - - if( pm->cmd.forwardmove >= 0 ) - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ForceLegsAnim( LEGS_JUMP ); - else - PM_ForceLegsAnim( NSPA_JUMP ); - - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ForceLegsAnim( LEGS_JUMPB ); - else - PM_ForceLegsAnim( NSPA_JUMPBACK ); - - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } - - return qtrue; -} - -/* -============= -PM_CheckWallJump -============= -*/ -static qboolean PM_CheckWallJump( void ) -{ - vec3_t dir, forward, right; - vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; - float normalFraction = 1.5f; - float cmdFraction = 1.0f; - float upFraction = 1.5f; - - if( pm->ps->pm_flags & PMF_RESPAWNED ) - return qfalse; // don't allow jump until all buttons are up - - if( pm->cmd.upmove < 10 ) - // not holding jump - return qfalse; - - if( pm->ps->pm_flags & PMF_TIME_WALLJUMP ) - return qfalse; - - // must wait for jump to be released - if( pm->ps->pm_flags & PMF_JUMP_HELD && - pm->ps->grapplePoint[ 2 ] == 1.0f ) - { - // clear upmove so cmdscale doesn't lower running speed - pm->cmd.upmove = 0; - return qfalse; - } - - pm->ps->pm_flags |= PMF_TIME_WALLJUMP; - pm->ps->pm_time = 200; - - pml.groundPlane = qfalse; // jumping away - pml.walking = qfalse; - pm->ps->pm_flags |= PMF_JUMP_HELD; - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - - ProjectPointOnPlane( forward, pml.forward, pm->ps->grapplePoint ); - ProjectPointOnPlane( right, pml.right, pm->ps->grapplePoint ); - - VectorScale( pm->ps->grapplePoint, normalFraction, dir ); - - if( pm->cmd.forwardmove > 0 ) - VectorMA( dir, cmdFraction, forward, dir ); - else if( pm->cmd.forwardmove < 0 ) - VectorMA( dir, -cmdFraction, forward, dir ); - - if( pm->cmd.rightmove > 0 ) - VectorMA( dir, cmdFraction, right, dir ); - else if( pm->cmd.rightmove < 0 ) - VectorMA( dir, -cmdFraction, right, dir ); - - VectorMA( dir, upFraction, refNormal, dir ); - VectorNormalize( dir ); - - VectorMA( pm->ps->velocity, BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ), - dir, pm->ps->velocity ); - - //for a long run of wall jumps the velocity can get pretty large, this caps it - if( VectorLength( pm->ps->velocity ) > LEVEL2_WALLJUMP_MAXSPEED ) - { - VectorNormalize( pm->ps->velocity ); - VectorScale( pm->ps->velocity, LEVEL2_WALLJUMP_MAXSPEED, pm->ps->velocity ); - } - - PM_AddEvent( EV_JUMP ); - - if( pm->cmd.forwardmove >= 0 ) - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ForceLegsAnim( LEGS_JUMP ); - else - PM_ForceLegsAnim( NSPA_JUMP ); - - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ForceLegsAnim( LEGS_JUMPB ); - else - PM_ForceLegsAnim( NSPA_JUMPBACK ); - - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } - - return qtrue; -} - -/* -============= -PM_CheckJump -============= -*/ -static qboolean PM_CheckJump( void ) -{ - if( BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ) == 0.0f ) - return qfalse; - - if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) ) - return PM_CheckWallJump( ); - - //can't jump and pounce at the same time - if( ( pm->ps->weapon == WP_ALEVEL3 || - pm->ps->weapon == WP_ALEVEL3_UPG ) && - pm->ps->stats[ STAT_MISC ] > 0 ) - return qfalse; - - //can't jump and charge at the same time - if( ( pm->ps->weapon == WP_ALEVEL4 ) && - pm->ps->stats[ STAT_MISC ] > 0 ) - return qfalse; - - if( ( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS ) && - ( pm->ps->stats[ STAT_STAMINA ] < 0 ) ) - return qfalse; - - if( pm->ps->pm_flags & PMF_RESPAWNED ) - return qfalse; // don't allow jump until all buttons are up - - if( pm->cmd.upmove < 10 ) - // not holding jump - return qfalse; - - //can't jump whilst grabbed - if( pm->ps->pm_type == PM_GRABBED ) - { - pm->cmd.upmove = 0; - return qfalse; - } - - // must wait for jump to be released - if( pm->ps->pm_flags & PMF_JUMP_HELD ) - { - // clear upmove so cmdscale doesn't lower running speed - pm->cmd.upmove = 0; - return qfalse; - } - - pml.groundPlane = qfalse; // jumping away - pml.walking = qfalse; - pm->ps->pm_flags |= PMF_JUMP_HELD; - - //TA: take some stamina off - if( pm->ps->stats[ STAT_PTEAM ] == PTE_HUMANS ) - pm->ps->stats[ STAT_STAMINA ] -= 500; - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - - //TA: jump away from wall - if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) - { - vec3_t normal = { 0, 0, -1 }; - - if( !( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) ) - VectorCopy( pm->ps->grapplePoint, normal ); - - VectorMA( pm->ps->velocity, BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ), - normal, pm->ps->velocity ); - } - else - pm->ps->velocity[ 2 ] = BG_FindJumpMagnitudeForClass( pm->ps->stats[ STAT_PCLASS ] ); - - PM_AddEvent( EV_JUMP ); - - if( pm->cmd.forwardmove >= 0 ) - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ForceLegsAnim( LEGS_JUMP ); - else - PM_ForceLegsAnim( NSPA_JUMP ); - - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ForceLegsAnim( LEGS_JUMPB ); - else - PM_ForceLegsAnim( NSPA_JUMPBACK ); - - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } - - return qtrue; -} - -/* -============= -PM_CheckWaterJump -============= -*/ -static qboolean PM_CheckWaterJump( void ) -{ - vec3_t spot; - int cont; - vec3_t flatforward; - - if( pm->ps->pm_time ) - return qfalse; - - // check for water jump - if( pm->waterlevel != 2 ) - return qfalse; - - flatforward[ 0 ] = pml.forward[ 0 ]; - flatforward[ 1 ] = pml.forward[ 1 ]; - flatforward[ 2 ] = 0; - VectorNormalize( flatforward ); - - VectorMA( pm->ps->origin, 30, flatforward, spot ); - spot[ 2 ] += 4; - cont = pm->pointcontents( spot, pm->ps->clientNum ); - - if( !( cont & CONTENTS_SOLID ) ) - return qfalse; - - spot[ 2 ] += 16; - cont = pm->pointcontents( spot, pm->ps->clientNum ); - - if( cont ) - return qfalse; - - // jump out of water - VectorScale( pml.forward, 200, pm->ps->velocity ); - pm->ps->velocity[ 2 ] = 350; - - pm->ps->pm_flags |= PMF_TIME_WATERJUMP; - pm->ps->pm_time = 2000; - - return qtrue; -} - -//============================================================================ - - -/* -=================== -PM_WaterJumpMove - -Flying out of the water -=================== -*/ -static void PM_WaterJumpMove( void ) -{ - // waterjump has no control, but falls - - PM_StepSlideMove( qtrue, qfalse ); - - pm->ps->velocity[ 2 ] -= pm->ps->gravity * pml.frametime; - if( pm->ps->velocity[ 2 ] < 0 ) - { - // cancel as soon as we are falling down again - pm->ps->pm_flags &= ~PMF_ALL_TIMES; - pm->ps->pm_time = 0; - } -} - -/* -=================== -PM_WaterMove - -=================== -*/ -static void PM_WaterMove( void ) -{ - int i; - vec3_t wishvel; - float wishspeed; - vec3_t wishdir; - float scale; - float vel; - - if( PM_CheckWaterJump( ) ) - { - PM_WaterJumpMove(); - return; - } -#if 0 - // jump = head for surface - if ( pm->cmd.upmove >= 10 ) { - if (pm->ps->velocity[2] > -300) { - if ( pm->watertype == CONTENTS_WATER ) { - pm->ps->velocity[2] = 100; - } else if (pm->watertype == CONTENTS_SLIME) { - pm->ps->velocity[2] = 80; - } else { - pm->ps->velocity[2] = 50; - } - } - } -#endif - PM_Friction( ); - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if( !scale ) - { - wishvel[ 0 ] = 0; - wishvel[ 1 ] = 0; - wishvel[ 2 ] = -60; // sink towards bottom - } - else - { - for( i = 0; i < 3; i++ ) - wishvel[ i ] = scale * pml.forward[ i ] * pm->cmd.forwardmove + scale * pml.right[ i ] * pm->cmd.rightmove; - - wishvel[ 2 ] += scale * pm->cmd.upmove; - } - - VectorCopy( wishvel, wishdir ); - wishspeed = VectorNormalize( wishdir ); - - if( wishspeed > pm->ps->speed * pm_swimScale ) - wishspeed = pm->ps->speed * pm_swimScale; - - PM_Accelerate( wishdir, wishspeed, pm_wateraccelerate ); - - // make sure we can go up slopes easily under water - if( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) - { - vel = VectorLength( pm->ps->velocity ); - // slide along the ground plane - PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - - VectorNormalize( pm->ps->velocity ); - VectorScale( pm->ps->velocity, vel, pm->ps->velocity ); - } - - PM_SlideMove( qfalse ); -} - -/* -=================== -PM_JetPackMove - -Only with the jetpack -=================== -*/ -static void PM_JetPackMove( void ) -{ - int i; - vec3_t wishvel; - float wishspeed; - vec3_t wishdir; - float scale; - - //normal slowdown - PM_Friction( ); - - scale = PM_CmdScale( &pm->cmd ); - - // user intentions - for( i = 0; i < 2; i++ ) - wishvel[ i ] = scale * pml.forward[ i ] * pm->cmd.forwardmove + scale * pml.right[ i ] * pm->cmd.rightmove; - - if( pm->cmd.upmove > 0.0f ) - wishvel[ 2 ] = JETPACK_FLOAT_SPEED; - if( pm->cmd.upmove < 0.0f ) - wishvel[ 2 ] = -JETPACK_SINK_SPEED; - - VectorCopy( wishvel, wishdir ); - wishspeed = VectorNormalize( wishdir ); - - PM_Accelerate( wishdir, wishspeed, pm_flyaccelerate ); - - PM_StepSlideMove( qfalse, qfalse ); - - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ContinueLegsAnim( LEGS_LAND ); - else - PM_ContinueLegsAnim( NSPA_LAND ); -} - - - - -/* -=================== -PM_FlyMove - -Only with the flight powerup -=================== -*/ -static void PM_FlyMove( void ) -{ - int i; - vec3_t wishvel; - float wishspeed; - vec3_t wishdir; - float scale; - - // normal slowdown - PM_Friction( ); - - scale = PM_CmdScale( &pm->cmd ); - // - // user intentions - // - if( !scale ) - { - wishvel[ 0 ] = 0; - wishvel[ 1 ] = 0; - wishvel[ 2 ] = 0; - } - else - { - for( i = 0; i < 3; i++ ) - wishvel[ i ] = scale * pml.forward[ i ] * pm->cmd.forwardmove + scale * pml.right[ i ] * pm->cmd.rightmove; - - wishvel[ 2 ] += scale * pm->cmd.upmove; - } - - VectorCopy( wishvel, wishdir ); - wishspeed = VectorNormalize( wishdir ); - - PM_Accelerate( wishdir, wishspeed, pm_flyaccelerate ); - - PM_StepSlideMove( qfalse, qfalse ); -} - - -/* -=================== -PM_AirMove - -=================== -*/ -static void PM_AirMove( void ) -{ - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - float scale; - usercmd_t cmd; - - PM_Friction( ); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - PM_SetMovementDir( ); - - // project moves down to flat plane - pml.forward[ 2 ] = 0; - pml.right[ 2 ] = 0; - VectorNormalize( pml.forward ); - VectorNormalize( pml.right ); - - for( i = 0; i < 2; i++ ) - wishvel[ i ] = pml.forward[ i ] * fmove + pml.right[ i ] * smove; - - wishvel[ 2 ] = 0; - - VectorCopy( wishvel, wishdir ); - wishspeed = VectorNormalize( wishdir ); - wishspeed *= scale; - - // not on ground, so little effect on velocity - PM_Accelerate( wishdir, wishspeed, - BG_FindAirAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] ) ); - - // we may have a ground plane that is very steep, even - // though we don't have a groundentity - // slide along the steep plane - if( pml.groundPlane ) - PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - - PM_StepSlideMove( qtrue, qfalse ); -} - -/* -=================== -PM_ClimbMove - -=================== -*/ -static void PM_ClimbMove( void ) -{ - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - float scale; - usercmd_t cmd; - float accelerate; - float vel; - - if( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) - { - // begin swimming - PM_WaterMove( ); - return; - } - - - if( PM_CheckJump( ) || PM_CheckPounce( ) ) - { - // jumped away - if( pm->waterlevel > 1 ) - PM_WaterMove( ); - else - PM_AirMove( ); - - return; - } - - PM_Friction( ); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - PM_SetMovementDir( ); - - // project the forward and right directions onto the ground plane - PM_ClipVelocity( pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP ); - PM_ClipVelocity( pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP ); - // - VectorNormalize( pml.forward ); - VectorNormalize( pml.right ); - - for( i = 0; i < 3; i++ ) - wishvel[ i ] = pml.forward[ i ] * fmove + pml.right[ i ] * smove; - - // when going up or down slopes the wish velocity should Not be zero -// wishvel[2] = 0; - - VectorCopy( wishvel, wishdir ); - wishspeed = VectorNormalize( wishdir ); - wishspeed *= scale; - - // clamp the speed lower if ducking - if( pm->ps->pm_flags & PMF_DUCKED ) - { - if( wishspeed > pm->ps->speed * pm_duckScale ) - wishspeed = pm->ps->speed * pm_duckScale; - } - - // clamp the speed lower if wading or walking on the bottom - if( pm->waterlevel ) - { - float waterScale; - - waterScale = pm->waterlevel / 3.0; - waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale; - if( wishspeed > pm->ps->speed * waterScale ) - wishspeed = pm->ps->speed * waterScale; - } - - // when a player gets hit, they temporarily lose - // full control, which allows them to be moved a bit - if( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) - accelerate = BG_FindAirAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] ); - else - accelerate = BG_FindAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] ); - - PM_Accelerate( wishdir, wishspeed, accelerate ); - - if( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) - pm->ps->velocity[ 2 ] -= pm->ps->gravity * pml.frametime; - - vel = VectorLength( pm->ps->velocity ); - - // slide along the ground plane - PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - - // don't decrease velocity when going up or down a slope - VectorNormalize( pm->ps->velocity ); - VectorScale( pm->ps->velocity, vel, pm->ps->velocity ); - - // don't do anything if standing still - if( !pm->ps->velocity[ 0 ] && !pm->ps->velocity[ 1 ] && !pm->ps->velocity[ 2 ] ) - return; - - PM_StepSlideMove( qfalse, qfalse ); -} - - -/* -=================== -PM_WalkMove - -=================== -*/ -static void PM_WalkMove( void ) -{ - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - float scale; - usercmd_t cmd; - float accelerate; - float vel; - - if( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) - { - // begin swimming - PM_WaterMove( ); - return; - } - - - if( PM_CheckJump( ) || PM_CheckPounce( ) ) - { - // jumped away - if( pm->waterlevel > 1 ) - PM_WaterMove( ); - else - PM_AirMove( ); - - return; - } - - //charging - PM_CheckCharge( ); - - PM_Friction( ); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - cmd = pm->cmd; - scale = PM_CmdScale( &cmd ); - - // set the movementDir so clients can rotate the legs for strafing - PM_SetMovementDir( ); - - // project moves down to flat plane - pml.forward[ 2 ] = 0; - pml.right[ 2 ] = 0; - - // project the forward and right directions onto the ground plane - PM_ClipVelocity( pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP ); - PM_ClipVelocity( pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP ); - // - VectorNormalize( pml.forward ); - VectorNormalize( pml.right ); - - for( i = 0; i < 3; i++ ) - wishvel[ i ] = pml.forward[ i ] * fmove + pml.right[ i ] * smove; - - // when going up or down slopes the wish velocity should Not be zero -// wishvel[2] = 0; - - VectorCopy( wishvel, wishdir ); - wishspeed = VectorNormalize( wishdir ); - wishspeed *= scale; - - // clamp the speed lower if ducking - if( pm->ps->pm_flags & PMF_DUCKED ) - { - if( wishspeed > pm->ps->speed * pm_duckScale ) - wishspeed = pm->ps->speed * pm_duckScale; - } - - // clamp the speed lower if wading or walking on the bottom - if( pm->waterlevel ) - { - float waterScale; - - waterScale = pm->waterlevel / 3.0; - waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale; - if( wishspeed > pm->ps->speed * waterScale ) - wishspeed = pm->ps->speed * waterScale; - } - - // when a player gets hit, they temporarily lose - // full control, which allows them to be moved a bit - if( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) - accelerate = BG_FindAirAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] ); - else - accelerate = BG_FindAccelerationForClass( pm->ps->stats[ STAT_PCLASS ] ); - - PM_Accelerate( wishdir, wishspeed, accelerate ); - - //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]); - //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity)); - - if( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) - pm->ps->velocity[ 2 ] -= pm->ps->gravity * pml.frametime; - else - { - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - } - - vel = VectorLength( pm->ps->velocity ); - - // slide along the ground plane - PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - - // don't decrease velocity when going up or down a slope - VectorNormalize( pm->ps->velocity ); - VectorScale( pm->ps->velocity, vel, pm->ps->velocity ); - - // don't do anything if standing still - if( !pm->ps->velocity[ 0 ] && !pm->ps->velocity[ 1 ] ) - return; - - PM_StepSlideMove( qfalse, qfalse ); - - //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity)); - -} - - -/* -=================== -PM_LadderMove - -Basically a rip of PM_WaterMove with a few changes -=================== -*/ -static void PM_LadderMove( void ) -{ - int i; - vec3_t wishvel; - float wishspeed; - vec3_t wishdir; - float scale; - float vel; - - PM_Friction( ); - - scale = PM_CmdScale( &pm->cmd ); - - for( i = 0; i < 3; i++ ) - wishvel[ i ] = scale * pml.forward[ i ] * pm->cmd.forwardmove + scale * pml.right[ i ] * pm->cmd.rightmove; - - wishvel[ 2 ] += scale * pm->cmd.upmove; - - VectorCopy( wishvel, wishdir ); - wishspeed = VectorNormalize( wishdir ); - - if( wishspeed > pm->ps->speed * pm_swimScale ) - wishspeed = pm->ps->speed * pm_swimScale; - - PM_Accelerate( wishdir, wishspeed, pm_accelerate ); - - //slanty ladders - if( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0.0f ) - { - vel = VectorLength( pm->ps->velocity ); - - // slide along the ground plane - PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, - pm->ps->velocity, OVERCLIP ); - - VectorNormalize( pm->ps->velocity ); - VectorScale( pm->ps->velocity, vel, pm->ps->velocity ); - } - - PM_SlideMove( qfalse ); -} - - -/* -============= -PM_CheckLadder - -Check to see if the player is on a ladder or not -============= -*/ -static void PM_CheckLadder( void ) -{ - vec3_t forward, end; - trace_t trace; - - //test if class can use ladders - if( !BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_CANUSELADDERS ) ) - { - pml.ladder = qfalse; - return; - } - - VectorCopy( pml.forward, forward ); - forward[ 2 ] = 0.0f; - - VectorMA( pm->ps->origin, 1.0f, forward, end ); - - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, MASK_PLAYERSOLID ); - - if( ( trace.fraction < 1.0f ) && ( trace.surfaceFlags & SURF_LADDER ) ) - pml.ladder = qtrue; - else - pml.ladder = qfalse; -} - - -/* -============== -PM_DeadMove -============== -*/ -static void PM_DeadMove( void ) -{ - float forward; - - if( !pml.walking ) - return; - - // extra friction - - forward = VectorLength( pm->ps->velocity ); - forward -= 20; - - if( forward <= 0 ) - VectorClear( pm->ps->velocity ); - else - { - VectorNormalize( pm->ps->velocity ); - VectorScale( pm->ps->velocity, forward, pm->ps->velocity ); - } -} - - -/* -=============== -PM_NoclipMove -=============== -*/ -static void PM_NoclipMove( void ) -{ - float speed, drop, friction, control, newspeed; - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - float scale; - - pm->ps->viewheight = DEFAULT_VIEWHEIGHT; - - // friction - - speed = VectorLength( pm->ps->velocity ); - - if( speed < 1 ) - { - VectorCopy( vec3_origin, pm->ps->velocity ); - } - else - { - drop = 0; - - friction = pm_friction * 1.5; // extra friction - control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control * friction * pml.frametime; - - // scale the velocity - newspeed = speed - drop; - - if( newspeed < 0 ) - newspeed = 0; - - newspeed /= speed; - - VectorScale( pm->ps->velocity, newspeed, pm->ps->velocity ); - } - - // accelerate - scale = PM_CmdScale( &pm->cmd ); - - fmove = pm->cmd.forwardmove; - smove = pm->cmd.rightmove; - - for( i = 0; i < 3; i++ ) - wishvel[ i ] = pml.forward[ i ] * fmove + pml.right[ i ] * smove; - - wishvel[ 2 ] += pm->cmd.upmove; - - VectorCopy( wishvel, wishdir ); - wishspeed = VectorNormalize( wishdir ); - wishspeed *= scale; - - PM_Accelerate( wishdir, wishspeed, pm_accelerate ); - - // move - VectorMA( pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin ); -} - -//============================================================================ - -/* -================ -PM_FootstepForSurface - -Returns an event number apropriate for the groundsurface -================ -*/ -static int PM_FootstepForSurface( void ) -{ - //TA: - if( pm->ps->stats[ STAT_STATE ] & SS_CREEPSLOWED ) - return EV_FOOTSTEP_SQUELCH; - - if( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) - return 0; - - if( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) - return EV_FOOTSTEP_METAL; - - return EV_FOOTSTEP; -} - - -/* -================= -PM_CrashLand - -Check for hard landings that generate sound events -================= -*/ -static void PM_CrashLand( void ) -{ - float delta; - float dist; - float vel, acc; - float t; - float a, b, c, den; - - // decide which landing animation to use - if( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ForceLegsAnim( LEGS_LANDB ); - else - PM_ForceLegsAnim( NSPA_LANDBACK ); - } - else - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ForceLegsAnim( LEGS_LAND ); - else - PM_ForceLegsAnim( NSPA_LAND ); - } - - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - pm->ps->legsTimer = TIMER_LAND; - else - pm->ps->torsoTimer = TIMER_LAND; - - // calculate the exact velocity on landing - dist = pm->ps->origin[ 2 ] - pml.previous_origin[ 2 ]; - vel = pml.previous_velocity[ 2 ]; - acc = -pm->ps->gravity; - - a = acc / 2; - b = vel; - c = -dist; - - den = b * b - 4 * a * c; - if( den < 0 ) - return; - - t = (-b - sqrt( den ) ) / ( 2 * a ); - - delta = vel + t * acc; - delta = delta*delta * 0.0001; - - // ducking while falling doubles damage - if( pm->ps->pm_flags & PMF_DUCKED ) - delta *= 2; - - // never take falling damage if completely underwater - if( pm->waterlevel == 3 ) - return; - - // reduce falling damage if there is standing water - if( pm->waterlevel == 2 ) - delta *= 0.25; - - if( pm->waterlevel == 1 ) - delta *= 0.5; - - if( delta < 1 ) - return; - - // create a local entity event to play the sound - - // SURF_NODAMAGE is used for bounce pads where you don't ever - // want to take damage or play a crunch sound - if( !( pml.groundTrace.surfaceFlags & SURF_NODAMAGE ) ) - { - pm->ps->stats[ STAT_FALLDIST ] = delta; - - if( delta > AVG_FALL_DISTANCE ) - { - PM_AddEvent( EV_FALL_FAR ); - } - else if( delta > MIN_FALL_DISTANCE ) - { - // this is a pain grunt, so don't play it if dead - if( pm->ps->stats[STAT_HEALTH] > 0 ) - PM_AddEvent( EV_FALL_MEDIUM ); - } - else - { - if( delta > 7 ) - PM_AddEvent( EV_FALL_SHORT ); - else - PM_AddEvent( PM_FootstepForSurface( ) ); - } - } - - // start footstep cycle over - pm->ps->bobCycle = 0; -} - - -/* -============= -PM_CorrectAllSolid -============= -*/ -static int PM_CorrectAllSolid( trace_t *trace ) -{ - int i, j, k; - vec3_t point; - - if( pm->debugLevel ) - Com_Printf("%i:allsolid\n", c_pmove); - - // jitter around - for( i = -1; i <= 1; i++ ) - { - for( j = -1; j <= 1; j++ ) - { - for( k = -1; k <= 1; k++ ) - { - VectorCopy( pm->ps->origin, point ); - point[ 0 ] += (float)i; - point[ 1 ] += (float)j; - point[ 2 ] += (float)k; - pm->trace( trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); - - if( !trace->allsolid ) - { - point[ 0 ] = pm->ps->origin[ 0 ]; - point[ 1 ] = pm->ps->origin[ 1 ]; - point[ 2 ] = pm->ps->origin[ 2 ] - 0.25; - - pm->trace( trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); - pml.groundTrace = *trace; - return qtrue; - } - } - } - } - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = qfalse; - pml.walking = qfalse; - - return qfalse; -} - - -/* -============= -PM_GroundTraceMissed - -The ground trace didn't hit a surface, so we are in freefall -============= -*/ -static void PM_GroundTraceMissed( void ) -{ - trace_t trace; - vec3_t point; - - if( pm->ps->groundEntityNum != ENTITYNUM_NONE ) - { - // we just transitioned into freefall - if( pm->debugLevel ) - Com_Printf( "%i:lift\n", c_pmove ); - - // if they aren't in a jumping animation and the ground is a ways away, force into it - // if we didn't do the trace, the player would be backflipping down staircases - VectorCopy( pm->ps->origin, point ); - point[ 2 ] -= 64.0f; - - pm->trace( &trace, pm->ps->origin, NULL, NULL, point, pm->ps->clientNum, pm->tracemask ); - if( trace.fraction == 1.0f ) - { - if( pm->cmd.forwardmove >= 0 ) - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ForceLegsAnim( LEGS_JUMP ); - else - PM_ForceLegsAnim( NSPA_JUMP ); - - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ForceLegsAnim( LEGS_JUMPB ); - else - PM_ForceLegsAnim( NSPA_JUMPBACK ); - - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } - } - } - - if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_TAKESFALLDAMAGE ) ) - { - if( pm->ps->velocity[ 2 ] < FALLING_THRESHOLD && pml.previous_velocity[ 2 ] >= FALLING_THRESHOLD ) - PM_AddEvent( EV_FALLING ); - } - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = qfalse; - pml.walking = qfalse; -} - - -/* -============= -PM_GroundClimbTrace -============= -*/ -static void PM_GroundClimbTrace( void ) -{ - vec3_t surfNormal, movedir, lookdir, point; - vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; - vec3_t ceilingNormal = { 0.0f, 0.0f, -1.0f }; - vec3_t toAngles, surfAngles; - trace_t trace; - int i; - - //used for delta correction - vec3_t traceCROSSsurf, traceCROSSref, surfCROSSref; - float traceDOTsurf, traceDOTref, surfDOTref, rTtDOTrTsTt; - float traceANGsurf, traceANGref, surfANGref; - vec3_t horizontal = { 1.0f, 0.0f, 0.0f }; //arbituary vector perpendicular to refNormal - vec3_t refTOtrace, refTOsurfTOtrace, tempVec; - int rTtANGrTsTt; - float ldDOTtCs, d; - vec3_t abc; - - //TA: If we're on the ceiling then grapplePoint is a rotation normal.. otherwise its a surface normal. - // would have been nice if Carmack had left a few random variables in the ps struct for mod makers - if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) - VectorCopy( ceilingNormal, surfNormal ); - else - VectorCopy( pm->ps->grapplePoint, surfNormal ); - - //construct a vector which reflects the direction the player is looking wrt the surface normal - ProjectPointOnPlane( movedir, pml.forward, surfNormal ); - VectorNormalize( movedir ); - - VectorCopy( movedir, lookdir ); - - if( pm->cmd.forwardmove < 0 ) - VectorNegate( movedir, movedir ); - - //allow strafe transitions - if( pm->cmd.rightmove ) - { - VectorCopy( pml.right, movedir ); - - if( pm->cmd.rightmove < 0 ) - VectorNegate( movedir, movedir ); - } - - for( i = 0; i <= 4; i++ ) - { - switch ( i ) - { - case 0: - //we are going to step this frame so skip the transition test - if( PM_PredictStepMove( ) ) - continue; - - //trace into direction we are moving - VectorMA( pm->ps->origin, 0.25f, movedir, point ); - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); - break; - - case 1: - //trace straight down anto "ground" surface - VectorMA( pm->ps->origin, -0.25f, surfNormal, point ); - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); - break; - - case 2: - if( pml.groundPlane != qfalse && PM_PredictStepMove( ) ) - { - //step down - VectorMA( pm->ps->origin, -STEPSIZE, surfNormal, point ); - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); - } - else - continue; - break; - - case 3: - //trace "underneath" BBOX so we can traverse angles > 180deg - if( pml.groundPlane != qfalse ) - { - VectorMA( pm->ps->origin, -16.0f, surfNormal, point ); - VectorMA( point, -16.0f, movedir, point ); - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); - } - else - continue; - break; - - case 4: - //fall back so we don't have to modify PM_GroundTrace too much - VectorCopy( pm->ps->origin, point ); - point[ 2 ] = pm->ps->origin[ 2 ] - 0.25f; - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); - break; - } - - //if we hit something - if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) && - !( trace.entityNum != ENTITYNUM_WORLD && i != 4 ) ) - { - if( i == 2 || i == 3 ) - { - if( i == 2 ) - PM_StepEvent( pm->ps->origin, trace.endpos, surfNormal ); - - VectorCopy( trace.endpos, pm->ps->origin ); - } - - //calculate a bunch of stuff... - CrossProduct( trace.plane.normal, surfNormal, traceCROSSsurf ); - VectorNormalize( traceCROSSsurf ); - - CrossProduct( trace.plane.normal, refNormal, traceCROSSref ); - VectorNormalize( traceCROSSref ); - - CrossProduct( surfNormal, refNormal, surfCROSSref ); - VectorNormalize( surfCROSSref ); - - //calculate angle between surf and trace - traceDOTsurf = DotProduct( trace.plane.normal, surfNormal ); - traceANGsurf = RAD2DEG( acos( traceDOTsurf ) ); - - if( traceANGsurf > 180.0f ) - traceANGsurf -= 180.0f; - - //calculate angle between trace and ref - traceDOTref = DotProduct( trace.plane.normal, refNormal ); - traceANGref = RAD2DEG( acos( traceDOTref ) ); - - if( traceANGref > 180.0f ) - traceANGref -= 180.0f; - - //calculate angle between surf and ref - surfDOTref = DotProduct( surfNormal, refNormal ); - surfANGref = RAD2DEG( acos( surfDOTref ) ); - - if( surfANGref > 180.0f ) - surfANGref -= 180.0f; - - //if the trace result and old surface normal are different then we must have transided to a new - //surface... do some stuff... - if( !VectorCompare( trace.plane.normal, surfNormal ) ) - { - //if the trace result or the old vector is not the floor or ceiling correct the YAW angle - if( !VectorCompare( trace.plane.normal, refNormal ) && !VectorCompare( surfNormal, refNormal ) && - !VectorCompare( trace.plane.normal, ceilingNormal ) && !VectorCompare( surfNormal, ceilingNormal ) ) - { - //behold the evil mindfuck from hell - //it has fucked mind like nothing has fucked mind before - - //calculate reference rotated through to trace plane - RotatePointAroundVector( refTOtrace, traceCROSSref, horizontal, -traceANGref ); - - //calculate reference rotated through to surf plane then to trace plane - RotatePointAroundVector( tempVec, surfCROSSref, horizontal, -surfANGref ); - RotatePointAroundVector( refTOsurfTOtrace, traceCROSSsurf, tempVec, -traceANGsurf ); - - //calculate angle between refTOtrace and refTOsurfTOtrace - rTtDOTrTsTt = DotProduct( refTOtrace, refTOsurfTOtrace ); - rTtANGrTsTt = ANGLE2SHORT( RAD2DEG( acos( rTtDOTrTsTt ) ) ); - - if( rTtANGrTsTt > 32768 ) - rTtANGrTsTt -= 32768; - - CrossProduct( refTOtrace, refTOsurfTOtrace, tempVec ); - VectorNormalize( tempVec ); - if( DotProduct( trace.plane.normal, tempVec ) > 0.0f ) - rTtANGrTsTt = -rTtANGrTsTt; - - //phew! - correct the angle - pm->ps->delta_angles[ YAW ] -= rTtANGrTsTt; - } - - //construct a plane dividing the surf and trace normals - CrossProduct( traceCROSSsurf, surfNormal, abc ); - VectorNormalize( abc ); - d = DotProduct( abc, pm->ps->origin ); - - //construct a point representing where the player is looking - VectorAdd( pm->ps->origin, lookdir, point ); - - //check whether point is on one side of the plane, if so invert the correction angle - if( ( abc[ 0 ] * point[ 0 ] + abc[ 1 ] * point[ 1 ] + abc[ 2 ] * point[ 2 ] - d ) > 0 ) - traceANGsurf = -traceANGsurf; - - //find the . product of the lookdir and traceCROSSsurf - if( ( ldDOTtCs = DotProduct( lookdir, traceCROSSsurf ) ) < 0.0f ) - { - VectorInverse( traceCROSSsurf ); - ldDOTtCs = DotProduct( lookdir, traceCROSSsurf ); - } - - //set the correction angle - traceANGsurf *= 1.0f - ldDOTtCs; - - if( !( pm->ps->persistant[ PERS_STATE ] & PS_WALLCLIMBINGFOLLOW ) ) - { - //correct the angle - pm->ps->delta_angles[ PITCH ] -= ANGLE2SHORT( traceANGsurf ); - } - - //transition from wall to ceiling - //normal for subsequent viewangle rotations - if( VectorCompare( trace.plane.normal, ceilingNormal ) ) - { - CrossProduct( surfNormal, trace.plane.normal, pm->ps->grapplePoint ); - VectorNormalize( pm->ps->grapplePoint ); - pm->ps->stats[ STAT_STATE ] |= SS_WALLCLIMBINGCEILING; - } - - //transition from ceiling to wall - //we need to do some different angle correction here cos GPISROTVEC - if( VectorCompare( surfNormal, ceilingNormal ) ) - { - vectoangles( trace.plane.normal, toAngles ); - vectoangles( pm->ps->grapplePoint, surfAngles ); - - pm->ps->delta_angles[ 1 ] -= ANGLE2SHORT( ( ( surfAngles[ 1 ] - toAngles[ 1 ] ) * 2 ) - 180.0f ); - } - } - - pml.groundTrace = trace; - - //so everything knows where we're wallclimbing (ie client side) - pm->ps->eFlags |= EF_WALLCLIMB; - - //if we're not stuck to the ceiling then set grapplePoint to be a surface normal - if( !VectorCompare( trace.plane.normal, ceilingNormal ) ) - { - //so we know what surface we're stuck to - VectorCopy( trace.plane.normal, pm->ps->grapplePoint ); - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING; - } - - //IMPORTANT: break out of the for loop if we've hit something - break; - } - else if( trace.allsolid ) - { - // do something corrective if the trace starts in a solid... - if( !PM_CorrectAllSolid( &trace ) ) - return; - } - } - - if( trace.fraction >= 1.0f ) - { - // if the trace didn't hit anything, we are in free fall - PM_GroundTraceMissed( ); - pml.groundPlane = qfalse; - pml.walking = qfalse; - pm->ps->eFlags &= ~EF_WALLCLIMB; - - //just transided from ceiling to floor... apply delta correction - if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) - { - vec3_t forward, rotated, angles; - - AngleVectors( pm->ps->viewangles, forward, NULL, NULL ); - - RotatePointAroundVector( rotated, pm->ps->grapplePoint, forward, 180.0f ); - vectoangles( rotated, angles ); - - pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( angles[ YAW ] - pm->ps->viewangles[ YAW ] ); - } - - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING; - - //we get very bizarre effects if we don't do this :0 - VectorCopy( refNormal, pm->ps->grapplePoint ); - return; - } - - pml.groundPlane = qtrue; - pml.walking = qtrue; - - // hitting solid ground will end a waterjump - if( pm->ps->pm_flags & PMF_TIME_WATERJUMP ) - { - pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND); - pm->ps->pm_time = 0; - } - - pm->ps->groundEntityNum = trace.entityNum; - - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - - PM_AddTouchEnt( trace.entityNum ); -} - - -/* -============= -PM_GroundTrace -============= -*/ -static void PM_GroundTrace( void ) -{ - vec3_t point; - vec3_t movedir; - vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; - trace_t trace; - - if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) ) - { - if( pm->ps->persistant[ PERS_STATE ] & PS_WALLCLIMBINGTOGGLE ) - { - //toggle wall climbing if holding crouch - if( pm->cmd.upmove < 0 && !( pm->ps->pm_flags & PMF_CROUCH_HELD ) ) - { - if( !( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ) - pm->ps->stats[ STAT_STATE ] |= SS_WALLCLIMBING; - else if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING; - - pm->ps->pm_flags |= PMF_CROUCH_HELD; - } - else if( pm->cmd.upmove >= 0 ) - pm->ps->pm_flags &= ~PMF_CROUCH_HELD; - } - else - { - if( pm->cmd.upmove < 0 ) - pm->ps->stats[ STAT_STATE ] |= SS_WALLCLIMBING; - else if( pm->cmd.upmove >= 0 ) - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING; - } - - if( pm->ps->pm_type == PM_DEAD ) - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING; - - if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) - { - PM_GroundClimbTrace( ); - return; - } - - //just transided from ceiling to floor... apply delta correction - if( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) - { - vec3_t forward, rotated, angles; - - AngleVectors( pm->ps->viewangles, forward, NULL, NULL ); - - RotatePointAroundVector( rotated, pm->ps->grapplePoint, forward, 180.0f ); - vectoangles( rotated, angles ); - - pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( angles[ YAW ] - pm->ps->viewangles[ YAW ] ); - } - } - - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBING; - pm->ps->stats[ STAT_STATE ] &= ~SS_WALLCLIMBINGCEILING; - pm->ps->eFlags &= ~EF_WALLCLIMB; - - point[ 0 ] = pm->ps->origin[ 0 ]; - point[ 1 ] = pm->ps->origin[ 1 ]; - point[ 2 ] = pm->ps->origin[ 2 ] - 0.25f; - - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); - - pml.groundTrace = trace; - - // do something corrective if the trace starts in a solid... - if( trace.allsolid ) - if( !PM_CorrectAllSolid( &trace ) ) - return; - - //make sure that the surfNormal is reset to the ground - VectorCopy( refNormal, pm->ps->grapplePoint ); - - // if the trace didn't hit anything, we are in free fall - if( trace.fraction == 1.0f ) - { - qboolean steppedDown = qfalse; - - // try to step down - if( pml.groundPlane != qfalse && PM_PredictStepMove( ) ) - { - //step down - point[ 0 ] = pm->ps->origin[ 0 ]; - point[ 1 ] = pm->ps->origin[ 1 ]; - point[ 2 ] = pm->ps->origin[ 2 ] - STEPSIZE; - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); - - //if we hit something - if( trace.fraction < 1.0f ) - { - PM_StepEvent( pm->ps->origin, trace.endpos, refNormal ); - VectorCopy( trace.endpos, pm->ps->origin ); - steppedDown = qtrue; - } - } - - if( !steppedDown ) - { - PM_GroundTraceMissed( ); - pml.groundPlane = qfalse; - pml.walking = qfalse; - - if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) ) - { - ProjectPointOnPlane( movedir, pml.forward, refNormal ); - VectorNormalize( movedir ); - - if( pm->cmd.forwardmove < 0 ) - VectorNegate( movedir, movedir ); - - //allow strafe transitions - if( pm->cmd.rightmove ) - { - VectorCopy( pml.right, movedir ); - - if( pm->cmd.rightmove < 0 ) - VectorNegate( movedir, movedir ); - } - - //trace into direction we are moving - VectorMA( pm->ps->origin, 0.25f, movedir, point ); - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask ); - - if( trace.fraction < 1.0f && !( trace.surfaceFlags & ( SURF_SKY | SURF_SLICK ) ) && - ( trace.entityNum == ENTITYNUM_WORLD ) ) - { - if( !VectorCompare( trace.plane.normal, pm->ps->grapplePoint ) ) - { - VectorCopy( trace.plane.normal, pm->ps->grapplePoint ); - PM_CheckWallJump( ); - } - } - } - - return; - } - } - - // check if getting thrown off the ground - if( pm->ps->velocity[ 2 ] > 0.0f && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10.0f ) - { - if( pm->debugLevel ) - Com_Printf( "%i:kickoff\n", c_pmove ); - - // go into jump animation - if( pm->cmd.forwardmove >= 0 ) - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ForceLegsAnim( LEGS_JUMP ); - else - PM_ForceLegsAnim( NSPA_JUMP ); - - pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP; - } - else - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ForceLegsAnim( LEGS_JUMPB ); - else - PM_ForceLegsAnim( NSPA_JUMPBACK ); - - pm->ps->pm_flags |= PMF_BACKWARDS_JUMP; - } - - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = qfalse; - pml.walking = qfalse; - return; - } - - // slopes that are too steep will not be considered onground - if( trace.plane.normal[ 2 ] < MIN_WALK_NORMAL ) - { - if( pm->debugLevel ) - Com_Printf( "%i:steep\n", c_pmove ); - - // FIXME: if they can't slide down the slope, let them - // walk (sharp crevices) - pm->ps->groundEntityNum = ENTITYNUM_NONE; - pml.groundPlane = qtrue; - pml.walking = qfalse; - return; - } - - pml.groundPlane = qtrue; - pml.walking = qtrue; - - // hitting solid ground will end a waterjump - if( pm->ps->pm_flags & PMF_TIME_WATERJUMP ) - { - pm->ps->pm_flags &= ~( PMF_TIME_WATERJUMP | PMF_TIME_LAND ); - pm->ps->pm_time = 0; - } - - if( pm->ps->groundEntityNum == ENTITYNUM_NONE ) - { - // just hit the ground - if( pm->debugLevel ) - Com_Printf( "%i:Land\n", c_pmove ); - - if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_TAKESFALLDAMAGE ) ) - PM_CrashLand( ); - - // don't do landing time if we were just going down a slope - if( pml.previous_velocity[ 2 ] < -200 ) - { - // don't allow another jump for a little while - pm->ps->pm_flags |= PMF_TIME_LAND; - pm->ps->pm_time = 250; - } - } - - pm->ps->groundEntityNum = trace.entityNum; - - // don't reset the z velocity for slopes -// pm->ps->velocity[2] = 0; - - PM_AddTouchEnt( trace.entityNum ); -} - - -/* -============= -PM_SetWaterLevel FIXME: avoid this twice? certainly if not moving -============= -*/ -static void PM_SetWaterLevel( void ) -{ - vec3_t point; - int cont; - int sample1; - int sample2; - - // - // get waterlevel, accounting for ducking - // - pm->waterlevel = 0; - pm->watertype = 0; - - point[ 0 ] = pm->ps->origin[ 0 ]; - point[ 1 ] = pm->ps->origin[ 1 ]; - point[ 2 ] = pm->ps->origin[ 2 ] + MINS_Z + 1; - cont = pm->pointcontents( point, pm->ps->clientNum ); - - if( cont & MASK_WATER ) - { - sample2 = pm->ps->viewheight - MINS_Z; - sample1 = sample2 / 2; - - pm->watertype = cont; - pm->waterlevel = 1; - point[ 2 ] = pm->ps->origin[ 2 ] + MINS_Z + sample1; - cont = pm->pointcontents( point, pm->ps->clientNum ); - - if( cont & MASK_WATER ) - { - pm->waterlevel = 2; - point[ 2 ] = pm->ps->origin[ 2 ] + MINS_Z + sample2; - cont = pm->pointcontents( point, pm->ps->clientNum ); - - if( cont & MASK_WATER ) - pm->waterlevel = 3; - } - } -} - - - -/* -============== -PM_CheckDuck - -Sets mins, maxs, and pm->ps->viewheight -============== -*/ -static void PM_CheckDuck (void) -{ - trace_t trace; - vec3_t PCmins, PCmaxs, PCcmaxs; - int PCvh, PCcvh; - - BG_FindBBoxForClass( pm->ps->stats[ STAT_PCLASS ], PCmins, PCmaxs, PCcmaxs, NULL, NULL ); - BG_FindViewheightForClass( pm->ps->stats[ STAT_PCLASS ], &PCvh, &PCcvh ); - - //TA: iD bug? you can still crouch when you're a spectator - if( pm->ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) - PCcvh = PCvh; - - pm->mins[ 0 ] = PCmins[ 0 ]; - pm->mins[ 1 ] = PCmins[ 1 ]; - - pm->maxs[ 0 ] = PCmaxs[ 0 ]; - pm->maxs[ 1 ] = PCmaxs[ 1 ]; - - pm->mins[ 2 ] = PCmins[ 2 ]; - - if( pm->ps->pm_type == PM_DEAD ) - { - pm->maxs[ 2 ] = -8; - pm->ps->viewheight = DEAD_VIEWHEIGHT; - return; - } - - //TA: If the standing and crouching viewheights are the same the class can't crouch - if( ( pm->cmd.upmove < 0 ) && ( PCvh != PCcvh ) && - pm->ps->pm_type != PM_JETPACK && - !BG_InventoryContainsUpgrade( UP_BATTLESUIT, pm->ps->stats ) ) - { - // duck - pm->ps->pm_flags |= PMF_DUCKED; - } - else - { - // stand up if possible - if( pm->ps->pm_flags & PMF_DUCKED ) - { - // try to stand up - pm->maxs[ 2 ] = PCmaxs[ 2 ]; - pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask ); - if( !trace.allsolid ) - pm->ps->pm_flags &= ~PMF_DUCKED; - } - } - - if( pm->ps->pm_flags & PMF_DUCKED ) - { - pm->maxs[ 2 ] = PCcmaxs[ 2 ]; - pm->ps->viewheight = PCcvh; - } - else - { - pm->maxs[ 2 ] = PCmaxs[ 2 ]; - pm->ps->viewheight = PCvh; - } -} - - - -//=================================================================== - - -/* -=============== -PM_Footsteps -=============== -*/ -static void PM_Footsteps( void ) -{ - float bobmove; - int old; - qboolean footstep; - - // - // calculate speed and cycle to be used for - // all cyclic walking effects - // - if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) && ( pml.groundPlane ) ) - { - //TA: FIXME: yes yes i know this is wrong - pm->xyspeed = sqrt( pm->ps->velocity[ 0 ] * pm->ps->velocity[ 0 ] - + pm->ps->velocity[ 1 ] * pm->ps->velocity[ 1 ] - + pm->ps->velocity[ 2 ] * pm->ps->velocity[ 2 ] ); - } - else - pm->xyspeed = sqrt( pm->ps->velocity[ 0 ] * pm->ps->velocity[ 0 ] - + pm->ps->velocity[ 1 ] * pm->ps->velocity[ 1 ] ); - - if( pm->ps->groundEntityNum == ENTITYNUM_NONE ) - { - // airborne leaves position in cycle intact, but doesn't advance - if( pm->waterlevel > 1 ) - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ContinueLegsAnim( LEGS_SWIM ); - else - PM_ContinueLegsAnim( NSPA_SWIM ); - } - - return; - } - - // if not trying to move - if( !pm->cmd.forwardmove && !pm->cmd.rightmove ) - { - if( pm->xyspeed < 5 ) - { - pm->ps->bobCycle = 0; // start at beginning of cycle again - if( pm->ps->pm_flags & PMF_DUCKED ) - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ContinueLegsAnim( LEGS_IDLECR ); - else - PM_ContinueLegsAnim( NSPA_STAND ); - } - else - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ContinueLegsAnim( LEGS_IDLE ); - else - PM_ContinueLegsAnim( NSPA_STAND ); - } - } - return; - } - - - footstep = qfalse; - - if( pm->ps->pm_flags & PMF_DUCKED ) - { - bobmove = 0.5; // ducked characters bob much faster - - if( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ContinueLegsAnim( LEGS_BACKCR ); - else - { - if( pm->cmd.rightmove > 0 && !pm->cmd.forwardmove ) - PM_ContinueLegsAnim( NSPA_WALKRIGHT ); - else if( pm->cmd.rightmove < 0 && !pm->cmd.forwardmove ) - PM_ContinueLegsAnim( NSPA_WALKLEFT ); - else - PM_ContinueLegsAnim( NSPA_WALKBACK ); - } - } - else - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ContinueLegsAnim( LEGS_WALKCR ); - else - { - if( pm->cmd.rightmove > 0 && !pm->cmd.forwardmove ) - PM_ContinueLegsAnim( NSPA_WALKRIGHT ); - else if( pm->cmd.rightmove < 0 && !pm->cmd.forwardmove ) - PM_ContinueLegsAnim( NSPA_WALKLEFT ); - else - PM_ContinueLegsAnim( NSPA_WALK ); - } - } - - // ducked characters never play footsteps - } - else - { - if( !( pm->cmd.buttons & BUTTON_WALKING ) ) - { - bobmove = 0.4f; // faster speeds bob faster - - if( pm->ps->weapon == WP_ALEVEL4 && pm->ps->pm_flags & PMF_CHARGE ) - PM_ContinueLegsAnim( NSPA_CHARGE ); - else if( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ContinueLegsAnim( LEGS_BACK ); - else - { - if( pm->cmd.rightmove > 0 && !pm->cmd.forwardmove ) - PM_ContinueLegsAnim( NSPA_RUNRIGHT ); - else if( pm->cmd.rightmove < 0 && !pm->cmd.forwardmove ) - PM_ContinueLegsAnim( NSPA_RUNLEFT ); - else - PM_ContinueLegsAnim( NSPA_RUNBACK ); - } - } - else - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ContinueLegsAnim( LEGS_RUN ); - else - { - if( pm->cmd.rightmove > 0 && !pm->cmd.forwardmove ) - PM_ContinueLegsAnim( NSPA_RUNRIGHT ); - else if( pm->cmd.rightmove < 0 && !pm->cmd.forwardmove ) - PM_ContinueLegsAnim( NSPA_RUNLEFT ); - else - PM_ContinueLegsAnim( NSPA_RUN ); - } - } - - footstep = qtrue; - } - else - { - bobmove = 0.3f; // walking bobs slow - if( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ContinueLegsAnim( LEGS_BACKWALK ); - else - { - if( pm->cmd.rightmove > 0 && !pm->cmd.forwardmove ) - PM_ContinueLegsAnim( NSPA_WALKRIGHT ); - else if( pm->cmd.rightmove < 0 && !pm->cmd.forwardmove ) - PM_ContinueLegsAnim( NSPA_WALKLEFT ); - else - PM_ContinueLegsAnim( NSPA_WALKBACK ); - } - } - else - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_ContinueLegsAnim( LEGS_WALK ); - else - { - if( pm->cmd.rightmove > 0 && !pm->cmd.forwardmove ) - PM_ContinueLegsAnim( NSPA_WALKRIGHT ); - else if( pm->cmd.rightmove < 0 && !pm->cmd.forwardmove ) - PM_ContinueLegsAnim( NSPA_WALKLEFT ); - else - PM_ContinueLegsAnim( NSPA_WALK ); - } - } - } - } - - bobmove *= BG_FindBobCycleForClass( pm->ps->stats[ STAT_PCLASS ] ); - - if( pm->ps->stats[ STAT_STATE ] & SS_SPEEDBOOST ) - bobmove *= HUMAN_SPRINT_MODIFIER; - - // check for footstep / splash sounds - old = pm->ps->bobCycle; - pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255; - - // if we just crossed a cycle boundary, play an apropriate footstep event - if( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) - { - if( pm->waterlevel == 0 ) - { - // on ground will only play sounds if running - if( footstep && !pm->noFootsteps ) - PM_AddEvent( PM_FootstepForSurface( ) ); - } - else if( pm->waterlevel == 1 ) - { - // splashing - PM_AddEvent( EV_FOOTSPLASH ); - } - else if( pm->waterlevel == 2 ) - { - // wading / swimming at surface - PM_AddEvent( EV_SWIM ); - } - else if( pm->waterlevel == 3 ) - { - // no sound when completely underwater - } - } -} - -/* -============== -PM_WaterEvents - -Generate sound events for entering and leaving water -============== -*/ -static void PM_WaterEvents( void ) -{ - // FIXME? - // - // if just entered a water volume, play a sound - // - if( !pml.previous_waterlevel && pm->waterlevel ) - PM_AddEvent( EV_WATER_TOUCH ); - - // - // if just completely exited a water volume, play a sound - // - if( pml.previous_waterlevel && !pm->waterlevel ) - PM_AddEvent( EV_WATER_LEAVE ); - - // - // check for head just going under water - // - if( pml.previous_waterlevel != 3 && pm->waterlevel == 3 ) - PM_AddEvent( EV_WATER_UNDER ); - - // - // check for head just coming out of water - // - if( pml.previous_waterlevel == 3 && pm->waterlevel != 3 ) - PM_AddEvent( EV_WATER_CLEAR ); -} - - -/* -=============== -PM_BeginWeaponChange -=============== -*/ -static void PM_BeginWeaponChange( int weapon ) -{ - if( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) - return; - - if( !BG_InventoryContainsWeapon( weapon, pm->ps->stats ) && weapon != WP_NONE ) - return; - - if( pm->ps->weaponstate == WEAPON_DROPPING ) - return; - - PM_AddEvent( EV_CHANGE_WEAPON ); - pm->ps->weaponstate = WEAPON_DROPPING; - pm->ps->weaponTime += 200; - pm->ps->persistant[ PERS_NEWWEAPON ] = weapon; - - //reset build weapon - pm->ps->stats[ STAT_BUILDABLE ] = BA_NONE; - - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_StartTorsoAnim( TORSO_DROP ); -} - - -/* -=============== -PM_FinishWeaponChange -=============== -*/ -static void PM_FinishWeaponChange( void ) -{ - int weapon; - - weapon = pm->ps->persistant[ PERS_NEWWEAPON ]; - if( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) - weapon = WP_NONE; - - if( !BG_InventoryContainsWeapon( weapon, pm->ps->stats ) ) - weapon = WP_NONE; - - pm->ps->weapon = weapon; - pm->ps->weaponstate = WEAPON_RAISING; - pm->ps->weaponTime += 250; - - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - PM_StartTorsoAnim( TORSO_RAISE ); -} - - -/* -============== -PM_TorsoAnimation - -============== -*/ -static void PM_TorsoAnimation( void ) -{ - if( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) - return; - - if( pm->ps->weaponstate == WEAPON_READY ) - { - if( pm->ps->weapon == WP_BLASTER ) - PM_ContinueTorsoAnim( TORSO_STAND2 ); - else - PM_ContinueTorsoAnim( TORSO_STAND ); - } -} - - -/* -============== -PM_Weapon - -Generates weapon events and modifes the weapon counter -============== -*/ -static void PM_Weapon( void ) -{ - int addTime = 200; //default addTime - should never be used - int ammo, clips, maxClips; - qboolean attack1 = qfalse; - qboolean attack2 = qfalse; - qboolean attack3 = qfalse; - - // don't allow attack until all buttons are up - if( pm->ps->pm_flags & PMF_RESPAWNED ) - return; - - // ignore if spectator - if( pm->ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) - return; - - if( pm->ps->stats[ STAT_STATE ] & SS_INFESTING ) - return; - - if( pm->ps->stats[ STAT_STATE ] & SS_HOVELING ) - return; - - // check for dead player - if( pm->ps->stats[ STAT_HEALTH ] <= 0 ) - { - pm->ps->weapon = WP_NONE; - return; - } - - // make weapon function - if( pm->ps->weaponTime > 0 ) - pm->ps->weaponTime -= pml.msec; - - // check for weapon change - // can't change if weapon is firing, but can change - // again if lowering or raising - if( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) - { - //TA: must press use to switch weapons - if( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) - { - if( !( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) - { - if( pm->cmd.weapon <= 32 ) - { - //if trying to select a weapon, select it - if( pm->ps->weapon != pm->cmd.weapon ) - PM_BeginWeaponChange( pm->cmd.weapon ); - } - else if( pm->cmd.weapon > 32 ) - { - //if trying to toggle an upgrade, toggle it - if( BG_InventoryContainsUpgrade( pm->cmd.weapon - 32, pm->ps->stats ) ) //sanity check - { - if( BG_UpgradeIsActive( pm->cmd.weapon - 32, pm->ps->stats ) ) - BG_DeactivateUpgrade( pm->cmd.weapon - 32, pm->ps->stats ); - else - BG_ActivateUpgrade( pm->cmd.weapon - 32, pm->ps->stats ); - } - } - pm->ps->pm_flags |= PMF_USE_ITEM_HELD; - } - } - else - pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD; - - //something external thinks a weapon change is necessary - if( pm->ps->pm_flags & PMF_WEAPON_SWITCH ) - { - pm->ps->pm_flags &= ~PMF_WEAPON_SWITCH; - PM_BeginWeaponChange( pm->ps->persistant[ PERS_NEWWEAPON ] ); - } - } - - if( pm->ps->weaponTime > 0 ) - return; - - // change weapon if time - if( pm->ps->weaponstate == WEAPON_DROPPING ) - { - PM_FinishWeaponChange( ); - return; - } - - if( pm->ps->weaponstate == WEAPON_RAISING ) - { - pm->ps->weaponstate = WEAPON_READY; - - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - { - if( pm->ps->weapon == WP_BLASTER ) - PM_ContinueTorsoAnim( TORSO_STAND2 ); - else - PM_ContinueTorsoAnim( TORSO_STAND ); - } - - return; - } - - // start the animation even if out of ammo - - BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips ); - BG_FindAmmoForWeapon( pm->ps->weapon, NULL, &maxClips ); - - // check for out of ammo - if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) - { - PM_AddEvent( EV_NOAMMO ); - pm->ps->weaponTime += 200; - return; - } - - //done reloading so give em some ammo - if( pm->ps->weaponstate == WEAPON_RELOADING ) - { - if( maxClips > 0 ) - { - clips--; - BG_FindAmmoForWeapon( pm->ps->weapon, &ammo, NULL ); - } - - if( BG_FindUsesEnergyForWeapon( pm->ps->weapon ) && - BG_InventoryContainsUpgrade( UP_BATTPACK, pm->ps->stats ) ) - ammo = (int)( (float)ammo * BATTPACK_MODIFIER ); - - BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips ); - - //allow some time for the weapon to be raised - pm->ps->weaponstate = WEAPON_RAISING; - PM_StartTorsoAnim( TORSO_RAISE ); - pm->ps->weaponTime += 250; - return; - } - - // check for end of clip - if( ( !ammo || pm->ps->pm_flags & PMF_WEAPON_RELOAD ) && clips ) - { - pm->ps->pm_flags &= ~PMF_WEAPON_RELOAD; - - pm->ps->weaponstate = WEAPON_RELOADING; - - //drop the weapon - PM_StartTorsoAnim( TORSO_DROP ); - - addTime = BG_FindReloadTimeForWeapon( pm->ps->weapon ); - - pm->ps->weaponTime += addTime; - return; - } - - //check if non-auto primary/secondary attacks are permited - switch( pm->ps->weapon ) - { - case WP_ALEVEL0: - //venom is only autohit - attack1 = attack2 = attack3 = qfalse; - - if( !pm->autoWeaponHit[ pm->ps->weapon ] ) - { - pm->ps->weaponTime = 0; - pm->ps->weaponstate = WEAPON_READY; - return; - } - break; - - case WP_ALEVEL3: - case WP_ALEVEL3_UPG: - //pouncing has primary secondary AND autohit procedures - attack1 = pm->cmd.buttons & BUTTON_ATTACK; - attack2 = pm->cmd.buttons & BUTTON_ATTACK2; - attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE; - - if( !pm->autoWeaponHit[ pm->ps->weapon ] && !attack1 && !attack2 && !attack3 ) - { - pm->ps->weaponTime = 0; - pm->ps->weaponstate = WEAPON_READY; - return; - } - break; - - case WP_LUCIFER_CANNON: - attack1 = pm->cmd.buttons & BUTTON_ATTACK; - attack2 = pm->cmd.buttons & BUTTON_ATTACK2; - attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE; - - if( ( attack1 || pm->ps->stats[ STAT_MISC ] == 0 ) && !attack2 && !attack3 ) - { - if( pm->ps->stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE ) - { - pm->ps->weaponTime = 0; - pm->ps->weaponstate = WEAPON_READY; - return; - } - else - attack1 = !attack1; - } - - //erp this looks confusing - if( pm->ps->stats[ STAT_MISC ] > 0 ) - attack1 = !attack1; - break; - - default: - //by default primary and secondary attacks are allowed - attack1 = pm->cmd.buttons & BUTTON_ATTACK; - attack2 = pm->cmd.buttons & BUTTON_ATTACK2; - attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE; - - if( !attack1 && !attack2 && !attack3 ) - { - pm->ps->weaponTime = 0; - pm->ps->weaponstate = WEAPON_READY; - return; - } - break; - } - - //TA: fire events for non auto weapons - if( attack3 ) - { - if( BG_WeaponHasThirdMode( pm->ps->weapon ) ) - { - //hacky special case for slowblob - if( pm->ps->weapon == WP_ALEVEL3_UPG && !ammo ) - { - PM_AddEvent( EV_NOAMMO ); - pm->ps->weaponTime += 200; - return; - } - - pm->ps->generic1 = WPM_TERTIARY; - PM_AddEvent( EV_FIRE_WEAPON3 ); - addTime = BG_FindRepeatRate3ForWeapon( pm->ps->weapon ); - } - else - { - pm->ps->weaponTime = 0; - pm->ps->weaponstate = WEAPON_READY; - return; - } - } - else if( attack2 ) - { - if( BG_WeaponHasAltMode( pm->ps->weapon ) ) - { - pm->ps->generic1 = WPM_SECONDARY; - PM_AddEvent( EV_FIRE_WEAPON2 ); - addTime = BG_FindRepeatRate2ForWeapon( pm->ps->weapon ); - } - else - { - pm->ps->weaponTime = 0; - pm->ps->weaponstate = WEAPON_READY; - return; - } - } - else if( attack1 ) - { - pm->ps->generic1 = WPM_PRIMARY; - PM_AddEvent( EV_FIRE_WEAPON ); - addTime = BG_FindRepeatRate1ForWeapon( pm->ps->weapon ); - } - - //TA: fire events for autohit weapons - if( pm->autoWeaponHit[ pm->ps->weapon ] ) - { - switch( pm->ps->weapon ) - { - case WP_ALEVEL0: - pm->ps->generic1 = WPM_PRIMARY; - PM_AddEvent( EV_FIRE_WEAPON ); - addTime = BG_FindRepeatRate1ForWeapon( pm->ps->weapon ); - break; - - case WP_ALEVEL3: - case WP_ALEVEL3_UPG: - pm->ps->generic1 = WPM_SECONDARY; - PM_AddEvent( EV_FIRE_WEAPON2 ); - addTime = BG_FindRepeatRate2ForWeapon( pm->ps->weapon ); - break; - - default: - break; - } - } - - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - { - //FIXME: this should be an option in the client weapon.cfg - switch( pm->ps->weapon ) - { - case WP_FLAMER: - if( pm->ps->weaponstate == WEAPON_READY ) - { - PM_StartTorsoAnim( TORSO_ATTACK ); - } - break; - - case WP_BLASTER: - PM_StartTorsoAnim( TORSO_ATTACK2 ); - break; - - default: - PM_StartTorsoAnim( TORSO_ATTACK ); - break; - } - } - else - { - if( pm->ps->weapon == WP_ALEVEL4 ) - { - //hack to get random attack animations - //FIXME: does pm->ps->weaponTime cycle enough? - int num = abs( pm->ps->weaponTime ) % 3; - - if( num == 0 ) - PM_ForceLegsAnim( NSPA_ATTACK1 ); - else if( num == 1 ) - PM_ForceLegsAnim( NSPA_ATTACK2 ); - else if( num == 2 ) - PM_ForceLegsAnim( NSPA_ATTACK3 ); - } - else - { - if( attack1 ) - PM_ForceLegsAnim( NSPA_ATTACK1 ); - else if( attack2 ) - PM_ForceLegsAnim( NSPA_ATTACK2 ); - else if( attack3 ) - PM_ForceLegsAnim( NSPA_ATTACK3 ); - } - - pm->ps->torsoTimer = TIMER_ATTACK; - } - - pm->ps->weaponstate = WEAPON_FIRING; - - // take an ammo away if not infinite - if( !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) - { - //special case for lCanon - if( pm->ps->weapon == WP_LUCIFER_CANNON && attack1 ) - { - ammo -= (int)( ceil( ( (float)pm->ps->stats[ STAT_MISC ] / (float)LCANNON_TOTAL_CHARGE ) * 10.0f ) ); - - //stay on the safe side - if( ammo < 0 ) - ammo = 0; - } - else - ammo--; - - BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips ); - } - else if( pm->ps->weapon == WP_ALEVEL3_UPG && attack3 ) - { - //special case for slowblob - ammo--; - BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips ); - } - - //FIXME: predicted angles miss a problem?? - if( pm->ps->weapon == WP_CHAINGUN ) - { - if( pm->ps->pm_flags & PMF_DUCKED || - BG_InventoryContainsUpgrade( UP_BATTLESUIT, pm->ps->stats ) ) - { - pm->ps->delta_angles[ PITCH ] -= ANGLE2SHORT( ( ( random() * 0.5 ) - 0.125 ) * ( 30 / (float)addTime ) ); - pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( ( ( random() * 0.5 ) - 0.25 ) * ( 30.0 / (float)addTime ) ); - } - else - { - pm->ps->delta_angles[ PITCH ] -= ANGLE2SHORT( ( ( random() * 8 ) - 2 ) * ( 30.0 / (float)addTime ) ); - pm->ps->delta_angles[ YAW ] -= ANGLE2SHORT( ( ( random() * 8 ) - 4 ) * ( 30.0 / (float)addTime ) ); - } - } - - pm->ps->weaponTime += addTime; -} - -/* -================ -PM_Animate -================ -*/ -static void PM_Animate( void ) -{ - if( pm->cmd.buttons & BUTTON_GESTURE ) - { - if( !( pm->ps->persistant[ PERS_STATE ] & PS_NONSEGMODEL ) ) - { - if( pm->ps->torsoTimer == 0 ) - { - PM_StartTorsoAnim( TORSO_GESTURE ); - pm->ps->torsoTimer = TIMER_GESTURE; - - PM_AddEvent( EV_TAUNT ); - } - } - else - { - if( pm->ps->torsoTimer == 0 ) - { - PM_ForceLegsAnim( NSPA_GESTURE ); - pm->ps->torsoTimer = TIMER_GESTURE; - - PM_AddEvent( EV_TAUNT ); - } - } - } -} - - -/* -================ -PM_DropTimers -================ -*/ -static void PM_DropTimers( void ) -{ - // drop misc timing counter - if( pm->ps->pm_time ) - { - if( pml.msec >= pm->ps->pm_time ) - { - pm->ps->pm_flags &= ~PMF_ALL_TIMES; - pm->ps->pm_time = 0; - } - else - pm->ps->pm_time -= pml.msec; - } - - // drop animation counter - if( pm->ps->legsTimer > 0 ) - { - pm->ps->legsTimer -= pml.msec; - - if( pm->ps->legsTimer < 0 ) - pm->ps->legsTimer = 0; - } - - if( pm->ps->torsoTimer > 0 ) - { - pm->ps->torsoTimer -= pml.msec; - - if( pm->ps->torsoTimer < 0 ) - pm->ps->torsoTimer = 0; - } -} - - -/* -================ -PM_UpdateViewAngles - -This can be used as another entry point when only the viewangles -are being updated instead of a full move -================ -*/ -void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) -{ - short temp[ 3 ]; - int i; - vec3_t axis[ 3 ], rotaxis[ 3 ]; - vec3_t tempang; - - if( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPINTERMISSION ) - return; // no view changes at all - - if( ps->pm_type != PM_SPECTATOR && ps->stats[ STAT_HEALTH ] <= 0 ) - return; // no view changes at all - - // circularly clamp the angles with deltas - for( i = 0; i < 3; i++ ) - { - temp[ i ] = cmd->angles[ i ] + ps->delta_angles[ i ]; - - if( i == PITCH ) - { - // don't let the player look up or down more than 90 degrees - if( temp[ i ] > 16000 ) - { - ps->delta_angles[ i ] = 16000 - cmd->angles[ i ]; - temp[ i ] = 16000; - } - else if( temp[ i ] < -16000 ) - { - ps->delta_angles[ i ] = -16000 - cmd->angles[ i ]; - temp[ i ] = -16000; - } - } - tempang[ i ] = SHORT2ANGLE( temp[ i ] ); - } - - //convert viewangles -> axis - AnglesToAxis( tempang, axis ); - - if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) || - !BG_RotateAxis( ps->grapplePoint, axis, rotaxis, qfalse, - ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) ) - AxisCopy( axis, rotaxis ); - - //convert the new axis back to angles - AxisToAngles( rotaxis, tempang ); - - //force angles to -180 <= x <= 180 - for( i = 0; i < 3; i++ ) - { - while( tempang[ i ] > 180 ) - tempang[ i ] -= 360; - - while( tempang[ i ] < 180 ) - tempang[ i ] += 360; - } - - //actually set the viewangles - for( i = 0; i < 3; i++ ) - ps->viewangles[ i ] = tempang[ i ]; - - //pull the view into the lock point - if( ps->pm_type == PM_GRABBED && !BG_InventoryContainsUpgrade( UP_BATTLESUIT, ps->stats ) ) - { - vec3_t dir, angles; - - ByteToDir( ps->stats[ STAT_VIEWLOCK ], dir ); - vectoangles( dir, angles ); - - for( i = 0; i < 3; i++ ) - { - float diff = AngleSubtract( ps->viewangles[ i ], angles[ i ] ); - - while( diff > 180.0f ) - diff -= 360.0f; - while( diff < -180.0f ) - diff += 360.0f; - - if( diff < -90.0f ) - ps->delta_angles[ i ] += ANGLE2SHORT( fabs( diff ) - 90.0f ); - else if( diff > 90.0f ) - ps->delta_angles[ i ] -= ANGLE2SHORT( fabs( diff ) - 90.0f ); - - if( diff < 0.0f ) - ps->delta_angles[ i ] += ANGLE2SHORT( fabs( diff ) * 0.05f ); - else if( diff > 0.0f ) - ps->delta_angles[ i ] -= ANGLE2SHORT( fabs( diff ) * 0.05f ); - } - } -} - - -/* -================ -PmoveSingle - -================ -*/ -void trap_SnapVector( float *v ); - -void PmoveSingle( pmove_t *pmove ) -{ - int ammo, clips; - - pm = pmove; - - BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips ); - - // this counter lets us debug movement problems with a journal - // by setting a conditional breakpoint fot the previous frame - c_pmove++; - - // clear results - pm->numtouch = 0; - pm->watertype = 0; - pm->waterlevel = 0; - - if( pm->ps->stats[ STAT_HEALTH ] <= 0 ) - pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies - - // make sure walking button is clear if they are running, to avoid - // proxy no-footsteps cheats - if( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) - pm->cmd.buttons &= ~BUTTON_WALKING; - - // set the talk balloon flag - if( pm->cmd.buttons & BUTTON_TALK ) - pm->ps->eFlags |= EF_TALK; - else - pm->ps->eFlags &= ~EF_TALK; - - // set the firing flag for continuous beam weapons - if( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION && - ( pm->cmd.buttons & BUTTON_ATTACK ) && - ( ( ammo > 0 || clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) ) - pm->ps->eFlags |= EF_FIRING; - else - pm->ps->eFlags &= ~EF_FIRING; - - // set the firing flag for continuous beam weapons - if( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION && - ( pm->cmd.buttons & BUTTON_ATTACK2 ) && - ( ( ammo > 0 || clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) ) - pm->ps->eFlags |= EF_FIRING2; - else - pm->ps->eFlags &= ~EF_FIRING2; - - // set the firing flag for continuous beam weapons - if( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION && - ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) && - ( ( ammo > 0 || clips > 0 ) || BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) ) - pm->ps->eFlags |= EF_FIRING3; - else - pm->ps->eFlags &= ~EF_FIRING3; - - - // clear the respawned flag if attack and use are cleared - if( pm->ps->stats[STAT_HEALTH] > 0 && - !( pm->cmd.buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) ) - pm->ps->pm_flags &= ~PMF_RESPAWNED; - - // if talk button is down, dissallow all other input - // this is to prevent any possible intercept proxy from - // adding fake talk balloons - if( pmove->cmd.buttons & BUTTON_TALK ) - { - pmove->cmd.buttons = BUTTON_TALK; - pmove->cmd.forwardmove = 0; - pmove->cmd.rightmove = 0; - pmove->cmd.upmove = 0; - } - - // clear all pmove local vars - memset( &pml, 0, sizeof( pml ) ); - - // determine the time - pml.msec = pmove->cmd.serverTime - pm->ps->commandTime; - - if( pml.msec < 1 ) - pml.msec = 1; - else if( pml.msec > 200 ) - pml.msec = 200; - - pm->ps->commandTime = pmove->cmd.serverTime; - - // save old org in case we get stuck - VectorCopy( pm->ps->origin, pml.previous_origin ); - - // save old velocity for crashlanding - VectorCopy( pm->ps->velocity, pml.previous_velocity ); - - pml.frametime = pml.msec * 0.001; - - AngleVectors( pm->ps->viewangles, pml.forward, pml.right, pml.up ); - - if( pm->cmd.upmove < 10 ) - { - // not holding jump - pm->ps->pm_flags &= ~PMF_JUMP_HELD; - } - - // decide if backpedaling animations should be used - if( pm->cmd.forwardmove < 0 ) - pm->ps->pm_flags |= PMF_BACKWARDS_RUN; - else if( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) - pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN; - - if( pm->ps->pm_type >= PM_DEAD ) - { - pm->cmd.forwardmove = 0; - pm->cmd.rightmove = 0; - pm->cmd.upmove = 0; - } - - if( pm->ps->pm_type == PM_SPECTATOR ) - { - // update the viewangles - PM_UpdateViewAngles( pm->ps, &pm->cmd ); - PM_CheckDuck( ); - PM_FlyMove( ); - PM_DropTimers( ); - return; - } - - if( pm->ps->pm_type == PM_NOCLIP ) - { - PM_UpdateViewAngles( pm->ps, &pm->cmd ); - PM_NoclipMove( ); - PM_DropTimers( ); - return; - } - - if( pm->ps->pm_type == PM_FREEZE) - return; // no movement at all - - if( pm->ps->pm_type == PM_INTERMISSION || pm->ps->pm_type == PM_SPINTERMISSION ) - return; // no movement at all - - // set watertype, and waterlevel - PM_SetWaterLevel( ); - pml.previous_waterlevel = pmove->waterlevel; - - // set mins, maxs, and viewheight - PM_CheckDuck( ); - - PM_CheckLadder( ); - - // set groundentity - PM_GroundTrace( ); - - // update the viewangles - PM_UpdateViewAngles( pm->ps, &pm->cmd ); - - if( pm->ps->pm_type == PM_DEAD || pm->ps->pm_type == PM_GRABBED ) - PM_DeadMove( ); - - PM_DropTimers( ); - - if( pm->ps->pm_type == PM_JETPACK ) - PM_JetPackMove( ); - else if( pm->ps->pm_flags & PMF_TIME_WATERJUMP ) - PM_WaterJumpMove( ); - else if( pm->waterlevel > 1 ) - PM_WaterMove( ); - else if( pml.ladder ) - PM_LadderMove( ); - else if( pml.walking ) - { - if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) && - ( pm->ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ) - PM_ClimbMove( ); //TA: walking on any surface - else - PM_WalkMove( ); // walking on ground - } - else - PM_AirMove( ); - - PM_Animate( ); - - // set groundentity, watertype, and waterlevel - PM_GroundTrace( ); - //TA: must update after every GroundTrace() - yet more clock cycles down the drain :( (14 vec rotations/frame) - // update the viewangles - PM_UpdateViewAngles( pm->ps, &pm->cmd ); - - PM_SetWaterLevel( ); - - // weapons - PM_Weapon( ); - - // torso animation - PM_TorsoAnimation( ); - - // footstep events / legs animations - PM_Footsteps( ); - - // entering / leaving water splashes - PM_WaterEvents( ); - - // snap some parts of playerstate to save network bandwidth - trap_SnapVector( pm->ps->velocity ); -} - - -/* -================ -Pmove - -Can be called by either the server or the client -================ -*/ -void Pmove( pmove_t *pmove ) -{ - int finalTime; - - finalTime = pmove->cmd.serverTime; - - if( finalTime < pmove->ps->commandTime ) - return; // should not happen - - if( finalTime > pmove->ps->commandTime + 1000 ) - pmove->ps->commandTime = finalTime - 1000; - - pmove->ps->pmove_framecount = ( pmove->ps->pmove_framecount + 1 ) & ( ( 1 << PS_PMOVEFRAMECOUNTBITS ) - 1 ); - - // chop the move up if it is too long, to prevent framerate - // dependent behavior - while( pmove->ps->commandTime != finalTime ) - { - int msec; - - msec = finalTime - pmove->ps->commandTime; - - if( pmove->pmove_fixed ) - { - if( msec > pmove->pmove_msec ) - msec = pmove->pmove_msec; - } - else - { - if( msec > 66 ) - msec = 66; - } - - - pmove->cmd.serverTime = pmove->ps->commandTime + msec; - PmoveSingle( pmove ); - - if( pmove->ps->pm_flags & PMF_JUMP_HELD ) - pmove->cmd.upmove = 20; - } -} diff --git a/src/game/bg_public.h b/src/game/bg_public.h deleted file mode 100644 index fa84b440..00000000 --- a/src/game/bg_public.h +++ /dev/null @@ -1,1299 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_public.h -- definitions shared by both the server game and client game modules - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -//tremulous balance header -#include "tremulous.h" - -// because games can change separately from the main system version, we need a -// second version that must match between game and cgame -#define GAME_VERSION "tremulous" - -#define DEFAULT_GRAVITY 800 - -#define SCORE_NOT_PRESENT -9999 // for the CS_SCORES[12] when only one player is present - -#define VOTE_TIME 30000 // 30 seconds before vote times out - -#define MINS_Z -24 -#define DEFAULT_VIEWHEIGHT 26 -#define CROUCH_VIEWHEIGHT 12 -#define DEAD_VIEWHEIGHT -14 //TA: watch for mins[ 2 ] less than this causing - -// -// config strings are a general means of communicating variable length strings -// from the server to all connected clients. -// - -// CS_SERVERINFO and CS_SYSTEMINFO are defined in q_shared.h -#define CS_MUSIC 2 -#define CS_MESSAGE 3 // from the map worldspawn's message field -#define CS_MOTD 4 // g_motd string for server message of the day -#define CS_WARMUP 5 // server time when the match will be restarted -#define CS_SCORES1 6 -#define CS_SCORES2 7 -#define CS_VOTE_TIME 8 -#define CS_VOTE_STRING 9 -#define CS_VOTE_YES 10 -#define CS_VOTE_NO 11 - -#define CS_TEAMVOTE_TIME 12 -#define CS_TEAMVOTE_STRING 14 -#define CS_TEAMVOTE_YES 16 -#define CS_TEAMVOTE_NO 18 - -#define CS_GAME_VERSION 20 -#define CS_LEVEL_START_TIME 21 // so the timer only shows the current level -#define CS_INTERMISSION 22 // when 1, fraglimit/timelimit has been hit and intermission will start in a second or two -#define CS_FLAGSTATUS 23 // string indicating flag status in CTF -#define CS_SHADERSTATE 24 -#define CS_BOTINFO 25 -#define CS_CLIENTS_READY 26 //TA: following suggestion in STAT_ enum STAT_CLIENTS_READY becomes a configstring - -//TA: extra stuff: -#define CS_BUILDPOINTS 28 -#define CS_STAGES 29 -#define CS_SPAWNS 30 - -#define CS_MODELS 33 -#define CS_SOUNDS (CS_MODELS+MAX_MODELS) -#define CS_SHADERS (CS_SOUNDS+MAX_SOUNDS) -#define CS_PARTICLE_SYSTEMS (CS_SHADERS+MAX_SHADERS) -#define CS_PLAYERS (CS_PARTICLE_SYSTEMS+MAX_GAME_PARTICLE_SYSTEMS) -#define CS_PRECACHES (CS_PLAYERS+MAX_CLIENTS) -#define CS_LOCATIONS (CS_PRECACHES+MAX_CLIENTS) -#define CS_PARTICLE_FILES (CS_LOCATIONS+MAX_LOCATIONS) - -#define CS_MAX (CS_PARTICLE_FILES+MAX_PARTICLE_FILES) - -#if (CS_MAX) > MAX_CONFIGSTRINGS -#error overflow: (CS_MAX) > MAX_CONFIGSTRINGS -#endif - -typedef enum -{ - GENDER_MALE, - GENDER_FEMALE, - GENDER_NEUTER -} gender_t; - -/* -=================================================================================== - -PMOVE MODULE - -The pmove code takes a player_state_t and a usercmd_t and generates a new player_state_t -and some other output data. Used for local prediction on the client game and true -movement on the server game. -=================================================================================== -*/ - -typedef enum -{ - PM_NORMAL, // can accelerate and turn - PM_NOCLIP, // noclip movement - PM_SPECTATOR, // still run into walls - PM_JETPACK, // jetpack physics - PM_GRABBED, // like dead, but for when the player is still live - PM_DEAD, // no acceleration or turning, but free falling - PM_FREEZE, // stuck in place with no control - PM_INTERMISSION, // no movement or status bar - PM_SPINTERMISSION // no movement or status bar -} pmtype_t; - -typedef enum -{ - WEAPON_READY, - WEAPON_RAISING, - WEAPON_DROPPING, - WEAPON_FIRING, - WEAPON_RELOADING -} weaponstate_t; - -// pmove->pm_flags -#define PMF_DUCKED 1 -#define PMF_JUMP_HELD 2 -#define PMF_CROUCH_HELD 4 -#define PMF_BACKWARDS_JUMP 8 // go into backwards land -#define PMF_BACKWARDS_RUN 16 // coast down to backwards run -#define PMF_TIME_LAND 32 // pm_time is time before rejump -#define PMF_TIME_KNOCKBACK 64 // pm_time is an air-accelerate only time -#define PMF_TIME_WATERJUMP 256 // pm_time is waterjump -#define PMF_RESPAWNED 512 // clear after attack and jump buttons come up -#define PMF_USE_ITEM_HELD 1024 -#define PMF_WEAPON_RELOAD 2048 //TA: force a weapon switch -#define PMF_FOLLOW 4096 // spectate following another player -#define PMF_QUEUED 8192 //TA: player is queued -#define PMF_TIME_WALLJUMP 16384 //TA: for limiting wall jumping -#define PMF_CHARGE 32768 //TA: keep track of pouncing -#define PMF_WEAPON_SWITCH 65536 //TA: force a weapon switch - - -#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK|PMF_TIME_WALLJUMP) - -#define MAXTOUCH 32 -typedef struct -{ - // state (in / out) - playerState_t *ps; - - // command (in) - usercmd_t cmd; - int tracemask; // collide against these types of surfaces - int debugLevel; // if set, diagnostic output will be printed - qboolean noFootsteps; // if the game is setup for no footsteps by the server - qboolean autoWeaponHit[ 32 ]; //FIXME: TA: remind myself later this might be a problem - - int framecount; - - // results (out) - int numtouch; - int touchents[ MAXTOUCH ]; - - vec3_t mins, maxs; // bounding box size - - int watertype; - int waterlevel; - - float xyspeed; - - // for fixed msec Pmove - int pmove_fixed; - int pmove_msec; - - // callbacks to test the world - // these will be different functions during game and cgame - /*void (*trace)( trace_t *results, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask );*/ - void (*trace)( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, - const vec3_t end, int passEntityNum, int contentMask ); - - - int (*pointcontents)( const vec3_t point, int passEntityNum ); -} pmove_t; - -// if a full pmove isn't done on the client, you can just update the angles -void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ); -void Pmove( pmove_t *pmove ); - -//=================================================================================== - - -// player_state->stats[] indexes -typedef enum -{ - STAT_HEALTH, - STAT_ITEMS, - STAT_SLOTS, //TA: tracks the amount of stuff human players are carrying - STAT_ACTIVEITEMS, - STAT_WEAPONS, // 16 bit fields - STAT_WEAPONS2, //TA: another 16 bits to push the max weapon count up - STAT_MAX_HEALTH, // health / armor limit, changable by handicap - STAT_PCLASS, //TA: player class (for aliens AND humans) - STAT_PTEAM, //TA: player team - STAT_STAMINA, //TA: stamina (human only) - STAT_STATE, //TA: client states e.g. wall climbing - STAT_MISC, //TA: for uh...misc stuff - STAT_BUILDABLE, //TA: which ghost model to display for building - STAT_BOOSTTIME, //TA: time left for boost (alien only) - STAT_FALLDIST, //TA: the distance the player fell - STAT_VIEWLOCK //TA: direction to lock the view in -} statIndex_t; - -#define SCA_WALLCLIMBER 0x00000001 -#define SCA_TAKESFALLDAMAGE 0x00000002 -#define SCA_CANZOOM 0x00000004 -#define SCA_NOWEAPONDRIFT 0x00000008 -#define SCA_FOVWARPS 0x00000010 -#define SCA_ALIENSENSE 0x00000020 -#define SCA_CANUSELADDERS 0x00000040 -#define SCA_WALLJUMPER 0x00000080 - -#define SS_WALLCLIMBING 0x00000001 -#define SS_WALLCLIMBINGCEILING 0x00000002 -#define SS_CREEPSLOWED 0x00000004 -#define SS_SPEEDBOOST 0x00000008 -#define SS_INFESTING 0x00000010 -#define SS_GRABBED 0x00000020 -#define SS_BLOBLOCKED 0x00000040 -#define SS_POISONED 0x00000080 -#define SS_HOVELING 0x00000100 -#define SS_BOOSTED 0x00000200 -#define SS_SLOWLOCKED 0x00000400 -#define SS_POISONCLOUDED 0x00000800 -#define SS_MEDKIT_ACTIVE 0x00001000 -#define SS_CHARGING 0x00002000 - -#define SB_VALID_TOGGLEBIT 0x00004000 - -#define MAX_STAMINA 1000 - -#define BOOST_TIME 20000 - -// player_state->persistant[] indexes -// these fields are the only part of player_state that isn't -// cleared on respawn -typedef enum -{ - PERS_SCORE, // !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!! - PERS_HITS, // total points damage inflicted so damage beeps can sound on change - PERS_RANK, - PERS_TEAM, - PERS_SPAWN_COUNT, // incremented every respawn - PERS_ATTACKER, // clientnum of last damage inflicter - PERS_KILLED, // count of the number of times you died - - //TA: - PERS_STATE, - PERS_CREDIT, // human credit - PERS_BANK, // human credit in the bank - PERS_QUEUEPOS, // position in the spawn queue - PERS_NEWWEAPON // weapon to switch to -} persEnum_t; - -#define PS_WALLCLIMBINGFOLLOW 0x00000001 -#define PS_WALLCLIMBINGTOGGLE 0x00000002 -#define PS_NONSEGMODEL 0x00000004 - -// entityState_t->eFlags -#define EF_DEAD 0x00000001 // don't draw a foe marker over players with EF_DEAD -#define EF_TELEPORT_BIT 0x00000002 // toggled every time the origin abruptly changes -#define EF_PLAYER_EVENT 0x00000004 -#define EF_BOUNCE 0x00000008 // for missiles -#define EF_BOUNCE_HALF 0x00000010 // for missiles -#define EF_NO_BOUNCE_SOUND 0x00000020 // for missiles -#define EF_WALLCLIMB 0x00000040 // TA: wall walking -#define EF_WALLCLIMBCEILING 0x00000080 // TA: wall walking ceiling hack -#define EF_NODRAW 0x00000100 // may have an event, but no model (unspawned items) -#define EF_FIRING 0x00000200 // for lightning gun -#define EF_FIRING2 0x00000400 // alt fire -#define EF_FIRING3 0x00000800 // third fire -#define EF_MOVER_STOP 0x00001000 // will push otherwise -#define EF_TALK 0x00002000 // draw a talk balloon -#define EF_CONNECTION 0x00004000 // draw a connection trouble sprite -#define EF_VOTED 0x00008000 // already cast a vote -#define EF_TEAMVOTED 0x00010000 // already cast a vote -#define EF_BLOBLOCKED 0x00020000 // TA: caught by a trapper -#define EF_REAL_LIGHT 0x00040000 // TA: light sprites according to ambient light - -typedef enum -{ - PW_NONE, - - PW_QUAD, - PW_BATTLESUIT, - PW_HASTE, - PW_INVIS, - PW_REGEN, - PW_FLIGHT, - - PW_REDFLAG, - PW_BLUEFLAG, - PW_BALL, - - PW_NUM_POWERUPS -} powerup_t; - -typedef enum -{ - HI_NONE, - - HI_TELEPORTER, - HI_MEDKIT, - - HI_NUM_HOLDABLE -} holdable_t; - -typedef enum -{ - WPM_NONE, - - WPM_PRIMARY, - WPM_SECONDARY, - WPM_TERTIARY, - - WPM_NUM_WEAPONMODES -} weaponMode_t; - -typedef enum -{ - WP_NONE, - - WP_ALEVEL0, - WP_ALEVEL1, - WP_ALEVEL1_UPG, - WP_ALEVEL2, - WP_ALEVEL2_UPG, - WP_ALEVEL3, - WP_ALEVEL3_UPG, - WP_ALEVEL4, - - WP_BLASTER, - WP_MACHINEGUN, - WP_PAIN_SAW, - WP_SHOTGUN, - WP_LAS_GUN, - WP_MASS_DRIVER, - WP_CHAINGUN, - WP_PULSE_RIFLE, - WP_FLAMER, - WP_LUCIFER_CANNON, - WP_GRENADE, - - WP_LOCKBLOB_LAUNCHER, - WP_HIVE, - WP_TESLAGEN, - WP_MGTURRET, - - //build weapons must remain in a block - WP_ABUILD, - WP_ABUILD2, - WP_HBUILD2, - WP_HBUILD, - //ok? - - WP_NUM_WEAPONS -} weapon_t; - -typedef enum -{ - UP_NONE, - - UP_LIGHTARMOUR, - UP_HELMET, - UP_MEDKIT, - UP_BATTPACK, - UP_JETPACK, - UP_BATTLESUIT, - UP_GRENADE, - - UP_AMMO, - - UP_NUM_UPGRADES -} upgrade_t; - -typedef enum -{ - WUT_NONE, - - WUT_ALIENS, - WUT_HUMANS, - - WUT_NUM_TEAMS -} WUTeam_t; - -//TA: bitmasks for upgrade slots -#define SLOT_NONE 0x00000000 -#define SLOT_HEAD 0x00000001 -#define SLOT_TORSO 0x00000002 -#define SLOT_ARMS 0x00000004 -#define SLOT_LEGS 0x00000008 -#define SLOT_BACKPACK 0x00000010 -#define SLOT_WEAPON 0x00000020 -#define SLOT_SIDEARM 0x00000040 - -typedef enum -{ - BA_NONE, - - BA_A_SPAWN, - BA_A_OVERMIND, - - BA_A_BARRICADE, - BA_A_ACIDTUBE, - BA_A_TRAPPER, - BA_A_BOOSTER, - BA_A_HIVE, - - BA_A_HOVEL, - - BA_H_SPAWN, - - BA_H_MGTURRET, - BA_H_TESLAGEN, - - BA_H_ARMOURY, - BA_H_DCC, - BA_H_MEDISTAT, - - BA_H_REACTOR, - BA_H_REPEATER, - - BA_NUM_BUILDABLES -} buildable_t; - -typedef enum -{ - BIT_NONE, - - BIT_ALIENS, - BIT_HUMANS, - - BIT_NUM_TEAMS -} buildableTeam_t; - -#define B_HEALTH_BITS 5 -#define B_HEALTH_SCALE (float)((1<persistant[PERS_PLAYEREVENTS]) -#define PLAYEREVENT_DENIEDREWARD 0x0001 -#define PLAYEREVENT_GAUNTLETREWARD 0x0002 -#define PLAYEREVENT_HOLYSHIT 0x0004 - -// entityState_t->event values -// entity events are for effects that take place reletive -// to an existing entities origin. Very network efficient. - -// two bits at the top of the entityState->event field -// will be incremented with each change in the event so -// that an identical event started twice in a row can -// be distinguished. And off the value with ~EV_EVENT_BITS -// to retrieve the actual event number -#define EV_EVENT_BIT1 0x00000100 -#define EV_EVENT_BIT2 0x00000200 -#define EV_EVENT_BITS (EV_EVENT_BIT1|EV_EVENT_BIT2) - -#define EVENT_VALID_MSEC 300 - -typedef enum -{ - EV_NONE, - - EV_FOOTSTEP, - EV_FOOTSTEP_METAL, - EV_FOOTSTEP_SQUELCH, - EV_FOOTSPLASH, - EV_FOOTWADE, - EV_SWIM, - - EV_STEP_4, - EV_STEP_8, - EV_STEP_12, - EV_STEP_16, - - EV_STEPDN_4, - EV_STEPDN_8, - EV_STEPDN_12, - EV_STEPDN_16, - - EV_FALL_SHORT, - EV_FALL_MEDIUM, - EV_FALL_FAR, - EV_FALLING, - - EV_JUMP, - EV_WATER_TOUCH, // foot touches - EV_WATER_LEAVE, // foot leaves - EV_WATER_UNDER, // head touches - EV_WATER_CLEAR, // head leaves - - EV_NOAMMO, - EV_CHANGE_WEAPON, - EV_FIRE_WEAPON, - EV_FIRE_WEAPON2, - EV_FIRE_WEAPON3, - - EV_PLAYER_RESPAWN, //TA: for fovwarp effects - EV_PLAYER_TELEPORT_IN, - EV_PLAYER_TELEPORT_OUT, - - EV_GRENADE_BOUNCE, // eventParm will be the soundindex - - EV_GENERAL_SOUND, - EV_GLOBAL_SOUND, // no attenuation - - EV_BULLET_HIT_FLESH, - EV_BULLET_HIT_WALL, - - EV_SHOTGUN, - - EV_MISSILE_HIT, - EV_MISSILE_MISS, - EV_MISSILE_MISS_METAL, - EV_TESLATRAIL, - EV_BULLET, // otherEntity is the shooter - - EV_LEV1_GRAB, - EV_LEV4_CHARGE_PREPARE, - EV_LEV4_CHARGE_START, - - EV_PAIN, - EV_DEATH1, - EV_DEATH2, - EV_DEATH3, - EV_OBITUARY, - - EV_GIB_PLAYER, // gib a previously living player - - EV_BUILD_CONSTRUCT, //TA - EV_BUILD_DESTROY, //TA - EV_BUILD_DELAY, //TA: can't build yet - EV_BUILD_REPAIR, //TA: repairing buildable - EV_BUILD_REPAIRED, //TA: buildable has full health - EV_HUMAN_BUILDABLE_EXPLOSION, - EV_ALIEN_BUILDABLE_EXPLOSION, - EV_ALIEN_ACIDTUBE, - - EV_MEDKIT_USED, - - EV_ALIEN_EVOLVE, - EV_ALIEN_EVOLVE_FAILED, - - EV_DEBUG_LINE, - EV_STOPLOOPINGSOUND, - EV_TAUNT, - - EV_OVERMIND_ATTACK, //TA: overmind under attack - EV_OVERMIND_DYING, //TA: overmind close to death - EV_OVERMIND_SPAWNS, //TA: overmind needs spawns - - EV_DCC_ATTACK, //TA: dcc under attack - - EV_RPTUSE_SOUND //TA: trigger a sound -} entity_event_t; - -typedef enum -{ - MN_TEAM, - MN_A_TEAMFULL, - MN_H_TEAMFULL, - - //alien stuff - MN_A_CLASS, - MN_A_BUILD, - MN_A_INFEST, - MN_A_HOVEL_OCCUPIED, - MN_A_HOVEL_BLOCKED, - MN_A_NOEROOM, - MN_A_TOOCLOSE, - MN_A_NOOVMND_EVOLVE, - - //alien build - MN_A_SPWNWARN, - MN_A_OVERMIND, - MN_A_NOASSERT, - MN_A_NOCREEP, - MN_A_NOOVMND, - MN_A_NOROOM, - MN_A_NORMAL, - MN_A_HOVEL, - MN_A_HOVEL_EXIT, - - //human stuff - MN_H_SPAWN, - MN_H_BUILD, - MN_H_ARMOURY, - MN_H_NOSLOTS, - MN_H_NOFUNDS, - MN_H_ITEMHELD, - - //human build - MN_H_REPEATER, - MN_H_NOPOWER, - MN_H_NOTPOWERED, - MN_H_NODCC, - MN_H_REACTOR, - MN_H_NOROOM, - MN_H_NORMAL, - MN_H_TNODEWARN, - MN_H_RPTWARN, - MN_H_RPTWARN2 -} dynMenu_t; - -// animations -typedef enum -{ - BOTH_DEATH1, - BOTH_DEAD1, - BOTH_DEATH2, - BOTH_DEAD2, - BOTH_DEATH3, - BOTH_DEAD3, - - TORSO_GESTURE, - - TORSO_ATTACK, - TORSO_ATTACK2, - - TORSO_DROP, - TORSO_RAISE, - - TORSO_STAND, - TORSO_STAND2, - - LEGS_WALKCR, - LEGS_WALK, - LEGS_RUN, - LEGS_BACK, - LEGS_SWIM, - - LEGS_JUMP, - LEGS_LAND, - - LEGS_JUMPB, - LEGS_LANDB, - - LEGS_IDLE, - LEGS_IDLECR, - - LEGS_TURN, - - TORSO_GETFLAG, - TORSO_GUARDBASE, - TORSO_PATROL, - TORSO_FOLLOWME, - TORSO_AFFIRMATIVE, - TORSO_NEGATIVE, - - MAX_PLAYER_ANIMATIONS, - - LEGS_BACKCR, - LEGS_BACKWALK, - FLAG_RUN, - FLAG_STAND, - FLAG_STAND2RUN, - - MAX_PLAYER_TOTALANIMATIONS -} playerAnimNumber_t; - -// nonsegmented animations -typedef enum -{ - NSPA_STAND, - - NSPA_GESTURE, - - NSPA_WALK, - NSPA_RUN, - NSPA_RUNBACK, - NSPA_CHARGE, - - NSPA_RUNLEFT, - NSPA_WALKLEFT, - NSPA_RUNRIGHT, - NSPA_WALKRIGHT, - - NSPA_SWIM, - - NSPA_JUMP, - NSPA_LAND, - NSPA_JUMPBACK, - NSPA_LANDBACK, - - NSPA_TURN, - - NSPA_ATTACK1, - NSPA_ATTACK2, - NSPA_ATTACK3, - - NSPA_PAIN1, - NSPA_PAIN2, - - NSPA_DEATH1, - NSPA_DEAD1, - NSPA_DEATH2, - NSPA_DEAD2, - NSPA_DEATH3, - NSPA_DEAD3, - - MAX_NONSEG_PLAYER_ANIMATIONS, - - NSPA_WALKBACK, - - MAX_NONSEG_PLAYER_TOTALANIMATIONS -} nonSegPlayerAnimNumber_t; - -//TA: for buildable animations -typedef enum -{ - BANIM_NONE, - - BANIM_CONSTRUCT1, - BANIM_CONSTRUCT2, - - BANIM_IDLE1, - BANIM_IDLE2, - BANIM_IDLE3, - - BANIM_ATTACK1, - BANIM_ATTACK2, - - BANIM_SPAWN1, - BANIM_SPAWN2, - - BANIM_PAIN1, - BANIM_PAIN2, - - BANIM_DESTROY1, - BANIM_DESTROY2, - BANIM_DESTROYED, - - MAX_BUILDABLE_ANIMATIONS -} buildableAnimNumber_t; - -typedef struct animation_s -{ - int firstFrame; - int numFrames; - int loopFrames; // 0 to numFrames - int frameLerp; // msec between frames - int initialLerp; // msec to get to first frame - int reversed; // true if animation is reversed - int flipflop; // true if animation should flipflop back to base -} animation_t; - - -// flip the togglebit every time an animation -// changes so a restart of the same anim can be detected -#define ANIM_TOGGLEBIT 0x80 -#define ANIM_FORCEBIT 0x40 - - -typedef enum -{ - TEAM_FREE, - TEAM_SPECTATOR, - - TEAM_NUM_TEAMS -} team_t; - -// Time between location updates -#define TEAM_LOCATION_UPDATE_TIME 1000 - -// How many players on the overlay -#define TEAM_MAXOVERLAY 32 - -//TA: player classes -typedef enum -{ - PCL_NONE, - - //builder classes - PCL_ALIEN_BUILDER0, - PCL_ALIEN_BUILDER0_UPG, - - //offensive classes - PCL_ALIEN_LEVEL0, - PCL_ALIEN_LEVEL1, - PCL_ALIEN_LEVEL1_UPG, - PCL_ALIEN_LEVEL2, - PCL_ALIEN_LEVEL2_UPG, - PCL_ALIEN_LEVEL3, - PCL_ALIEN_LEVEL3_UPG, - PCL_ALIEN_LEVEL4, - - //human class - PCL_HUMAN, - PCL_HUMAN_BSUIT, - - PCL_NUM_CLASSES -} pClass_t; - - -//TA: player teams -typedef enum -{ - PTE_NONE, - PTE_ALIENS, - PTE_HUMANS, - - PTE_NUM_TEAMS -} pTeam_t; - - -// means of death -typedef enum -{ - MOD_UNKNOWN, - MOD_SHOTGUN, - MOD_BLASTER, - MOD_PAINSAW, - MOD_MACHINEGUN, - MOD_CHAINGUN, - MOD_PRIFLE, - MOD_MDRIVER, - MOD_LASGUN, - MOD_LCANNON, - MOD_LCANNON_SPLASH, - MOD_FLAMER, - MOD_FLAMER_SPLASH, - MOD_GRENADE, - MOD_WATER, - MOD_SLIME, - MOD_LAVA, - MOD_CRUSH, - MOD_TELEFRAG, - MOD_FALLING, - MOD_SUICIDE, - MOD_TARGET_LASER, - MOD_TRIGGER_HURT, - - MOD_ABUILDER_CLAW, - MOD_LEVEL0_BITE, - MOD_LEVEL1_CLAW, - MOD_LEVEL1_PCLOUD, - MOD_LEVEL3_CLAW, - MOD_LEVEL3_POUNCE, - MOD_LEVEL3_BOUNCEBALL, - MOD_LEVEL2_CLAW, - MOD_LEVEL2_ZAP, - MOD_LEVEL4_CLAW, - MOD_LEVEL4_CHARGE, - - MOD_SLOWBLOB, - MOD_POISON, - MOD_SWARM, - - MOD_HSPAWN, - MOD_TESLAGEN, - MOD_MGTURRET, - MOD_REACTOR, - - MOD_ASPAWN, - MOD_ATUBE, - MOD_OVERMIND -} meansOfDeath_t; - - -//--------------------------------------------------------- - -//TA: player class record -typedef struct -{ - int classNum; - - char *className; - char *humanName; - - char *modelName; - float modelScale; - char *skinName; - float shadowScale; - - char *hudName; - - int stages; - - vec3_t mins; - vec3_t maxs; - vec3_t crouchMaxs; - vec3_t deadMins; - vec3_t deadMaxs; - float zOffset; - - int viewheight; - int crouchViewheight; - - int health; - float fallDamage; - int regenRate; - - int abilities; - - weapon_t startWeapon; - - float buildDist; - - int fov; - float bob; - float bobCycle; - int steptime; - - float speed; - float acceleration; - float airAcceleration; - float friction; - float stopSpeed; - float jumpMagnitude; - float knockbackScale; - - int children[ 3 ]; - int cost; - int value; -} classAttributes_t; - -typedef struct -{ - char modelName[ MAX_QPATH ]; - float modelScale; - char skinName[ MAX_QPATH ]; - float shadowScale; - char hudName[ MAX_QPATH ]; - char humanName[ MAX_STRING_CHARS ]; - - vec3_t mins; - vec3_t maxs; - vec3_t crouchMaxs; - vec3_t deadMins; - vec3_t deadMaxs; - float zOffset; -} classAttributeOverrides_t; - -//stages -typedef enum -{ - S1, - S2, - S3 -} stage_t; - -#define MAX_BUILDABLE_MODELS 4 - -//TA: buildable item record -typedef struct -{ - int buildNum; - - char *buildName; - char *humanName; - char *entityName; - - char *models[ MAX_BUILDABLE_MODELS ]; - float modelScale; - - vec3_t mins; - vec3_t maxs; - float zOffset; - - trType_t traj; - float bounce; - - int buildPoints; - int stages; - - int health; - int regenRate; - - int splashDamage; - int splashRadius; - - int meansOfDeath; - - int team; - weapon_t buildWeapon; - - int idleAnim; - - int nextthink; - int buildTime; - qboolean usable; - - int turretRange; - int turretFireSpeed; - weapon_t turretProjType; - - float minNormal; - qboolean invertNormal; - - qboolean creepTest; - int creepSize; - - qboolean dccTest; - qboolean reactorTest; -} buildableAttributes_t; - -typedef struct -{ - char models[ MAX_BUILDABLE_MODELS ][ MAX_QPATH ]; - - float modelScale; - vec3_t mins; - vec3_t maxs; - float zOffset; -} buildableAttributeOverrides_t; - -//TA: weapon record -typedef struct -{ - int weaponNum; - - int price; - int stages; - - int slots; - - char *weaponName; - char *weaponHumanName; - - int maxAmmo; - int maxClips; - qboolean infiniteAmmo; - qboolean usesEnergy; - - int repeatRate1; - int repeatRate2; - int repeatRate3; - int reloadTime; - - qboolean hasAltMode; - qboolean hasThirdMode; - - qboolean canZoom; - float zoomFov; - - qboolean purchasable; - - int buildDelay; - - WUTeam_t team; -} weaponAttributes_t; - -//TA: upgrade record -typedef struct -{ - int upgradeNum; - - int price; - int stages; - - int slots; - - char *upgradeName; - char *upgradeHumanName; - - char *icon; - - qboolean purchasable; - - WUTeam_t team; -} upgradeAttributes_t; - - -//TA: -void BG_UnpackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int *ammo, int *clips ); -void BG_PackAmmoArray( int weapon, int psAmmo[ ], int psAmmo2[ ], int ammo, int clips ); -qboolean BG_WeaponIsFull( weapon_t weapon, int stats[ ], int psAmmo[ ], int psAmmo2[ ] ); -void BG_AddWeaponToInventory( int weapon, int stats[ ] ); -void BG_RemoveWeaponFromInventory( int weapon, int stats[ ] ); -qboolean BG_InventoryContainsWeapon( int weapon, int stats[ ] ); -void BG_AddUpgradeToInventory( int item, int stats[ ] ); -void BG_RemoveUpgradeFromInventory( int item, int stats[ ] ); -qboolean BG_InventoryContainsUpgrade( int item, int stats[ ] ); -void BG_ActivateUpgrade( int item, int stats[ ] ); -void BG_DeactivateUpgrade( int item, int stats[ ] ); -qboolean BG_UpgradeIsActive( int item, int stats[ ] ); -qboolean BG_RotateAxis( vec3_t surfNormal, vec3_t inAxis[ 3 ], - vec3_t outAxis[ 3 ], qboolean inverse, qboolean ceiling ); -void BG_PositionBuildableRelativeToPlayer( const playerState_t *ps, - const vec3_t mins, const vec3_t maxs, - void (*trace)( trace_t *, const vec3_t, const vec3_t, - const vec3_t, const vec3_t, int, int ), - vec3_t outOrigin, vec3_t outAngles, trace_t *tr ); -int BG_GetValueOfHuman( playerState_t *ps ); - -int BG_FindBuildNumForName( char *name ); -int BG_FindBuildNumForEntityName( char *name ); -char *BG_FindNameForBuildable( int bclass ); -char *BG_FindHumanNameForBuildable( int bclass ); -char *BG_FindEntityNameForBuildable( int bclass ); -char *BG_FindModelsForBuildable( int bclass, int modelNum ); -float BG_FindModelScaleForBuildable( int bclass ); -void BG_FindBBoxForBuildable( int bclass, vec3_t mins, vec3_t maxs ); -float BG_FindZOffsetForBuildable( int pclass ); -int BG_FindHealthForBuildable( int bclass ); -int BG_FindRegenRateForBuildable( int bclass ); -trType_t BG_FindTrajectoryForBuildable( int bclass ); -float BG_FindBounceForBuildable( int bclass ); -int BG_FindBuildPointsForBuildable( int bclass ); -qboolean BG_FindStagesForBuildable( int bclass, stage_t stage ); -int BG_FindSplashDamageForBuildable( int bclass ); -int BG_FindSplashRadiusForBuildable( int bclass ); -int BG_FindMODForBuildable( int bclass ); -int BG_FindTeamForBuildable( int bclass ); -weapon_t BG_FindBuildWeaponForBuildable( int bclass ); -int BG_FindAnimForBuildable( int bclass ); -int BG_FindNextThinkForBuildable( int bclass ); -int BG_FindBuildTimeForBuildable( int bclass ); -qboolean BG_FindUsableForBuildable( int bclass ); -int BG_FindRangeForBuildable( int bclass ); -int BG_FindFireSpeedForBuildable( int bclass ); -weapon_t BG_FindProjTypeForBuildable( int bclass ); -float BG_FindMinNormalForBuildable( int bclass ); -qboolean BG_FindInvertNormalForBuildable( int bclass ); -int BG_FindCreepTestForBuildable( int bclass ); -int BG_FindCreepSizeForBuildable( int bclass ); -int BG_FindDCCTestForBuildable( int bclass ); -int BG_FindUniqueTestForBuildable( int bclass ); -void BG_InitBuildableOverrides( void ); - -int BG_FindClassNumForName( char *name ); -char *BG_FindNameForClassNum( int pclass ); -char *BG_FindHumanNameForClassNum( int pclass ); -char *BG_FindModelNameForClass( int pclass ); -float BG_FindModelScaleForClass( int pclass ); -char *BG_FindSkinNameForClass( int pclass ); -float BG_FindShadowScaleForClass( int pclass ); -char *BG_FindHudNameForClass( int pclass ); -qboolean BG_FindStagesForClass( int pclass, stage_t stage ); -void BG_FindBBoxForClass( int pclass, vec3_t mins, vec3_t maxs, vec3_t cmaxs, vec3_t dmins, vec3_t dmaxs ); -float BG_FindZOffsetForClass( int pclass ); -void BG_FindViewheightForClass( int pclass, int *viewheight, int *cViewheight ); -int BG_FindHealthForClass( int pclass ); -float BG_FindFallDamageForClass( int pclass ); -int BG_FindRegenRateForClass( int pclass ); -int BG_FindFovForClass( int pclass ); -float BG_FindBobForClass( int pclass ); -float BG_FindBobCycleForClass( int pclass ); -float BG_FindSpeedForClass( int pclass ); -float BG_FindAccelerationForClass( int pclass ); -float BG_FindAirAccelerationForClass( int pclass ); -float BG_FindFrictionForClass( int pclass ); -float BG_FindStopSpeedForClass( int pclass ); -float BG_FindJumpMagnitudeForClass( int pclass ); -float BG_FindKnockbackScaleForClass( int pclass ); -int BG_FindSteptimeForClass( int pclass ); -qboolean BG_ClassHasAbility( int pclass, int ability ); -weapon_t BG_FindStartWeaponForClass( int pclass ); -float BG_FindBuildDistForClass( int pclass ); -int BG_ClassCanEvolveFromTo( int fclass, int tclass, int credits, int num ); -int BG_FindCostOfClass( int pclass ); -int BG_FindValueOfClass( int pclass ); -void BG_InitClassOverrides( void ); - -int BG_FindPriceForWeapon( int weapon ); -qboolean BG_FindStagesForWeapon( int weapon, stage_t stage ); -int BG_FindSlotsForWeapon( int weapon ); -char *BG_FindNameForWeapon( int weapon ); -int BG_FindWeaponNumForName( char *name ); -char *BG_FindHumanNameForWeapon( int weapon ); -char *BG_FindModelsForWeapon( int weapon, int modelNum ); -char *BG_FindIconForWeapon( int weapon ); -char *BG_FindCrosshairForWeapon( int weapon ); -int BG_FindCrosshairSizeForWeapon( int weapon ); -void BG_FindAmmoForWeapon( int weapon, int *maxAmmo, int *maxClips ); -qboolean BG_FindInfinteAmmoForWeapon( int weapon ); -qboolean BG_FindUsesEnergyForWeapon( int weapon ); -int BG_FindRepeatRate1ForWeapon( int weapon ); -int BG_FindRepeatRate2ForWeapon( int weapon ); -int BG_FindRepeatRate3ForWeapon( int weapon ); -int BG_FindReloadTimeForWeapon( int weapon ); -qboolean BG_WeaponHasAltMode( int weapon ); -qboolean BG_WeaponHasThirdMode( int weapon ); -qboolean BG_WeaponCanZoom( int weapon ); -float BG_FindZoomFovForWeapon( int weapon ); -qboolean BG_FindPurchasableForWeapon( int weapon ); -int BG_FindBuildDelayForWeapon( int weapon ); -WUTeam_t BG_FindTeamForWeapon( int weapon ); - -int BG_FindPriceForUpgrade( int upgrade ); -qboolean BG_FindStagesForUpgrade( int upgrade, stage_t stage ); -int BG_FindSlotsForUpgrade( int upgrade ); -char *BG_FindNameForUpgrade( int upgrade ); -int BG_FindUpgradeNumForName( char *name ); -char *BG_FindHumanNameForUpgrade( int upgrade ); -char *BG_FindIconForUpgrade( int upgrade ); -qboolean BG_FindPurchasableForUpgrade( int upgrade ); -WUTeam_t BG_FindTeamForUpgrade( int upgrade ); - -// content masks -#define MASK_ALL (-1) -#define MASK_SOLID (CONTENTS_SOLID) -#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY) -#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP) -#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME) -#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA) -#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_BODY) - - -// -// entityState_t->eType -// -typedef enum -{ - ET_GENERAL, - ET_PLAYER, - ET_ITEM, - - ET_BUILDABLE, //TA: buildable type - - ET_MISSILE, - ET_MOVER, - ET_BEAM, - ET_PORTAL, - ET_SPEAKER, - ET_PUSH_TRIGGER, - ET_TELEPORT_TRIGGER, - ET_INVISIBLE, - ET_GRAPPLE, // grapple hooked on wall - - ET_CORPSE, - ET_PARTICLE_SYSTEM, - ET_ANIMMAPOBJ, - ET_MODELDOOR, - ET_LIGHTFLARE, - ET_LEV2_ZAP_CHAIN, - - ET_EVENTS // any of the EV_* events can be added freestanding - // by setting eType to ET_EVENTS + eventNum - // this avoids having to set eFlags and eventNum -} entityType_t; - -void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ); -void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ); - -void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ); - -void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ); -void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ); - -qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ); - -#define ARENAS_PER_TIER 4 -#define MAX_ARENAS 1024 -#define MAX_ARENAS_TEXT 8192 - -#define MAX_BOTS 1024 -#define MAX_BOTS_TEXT 8192 - -//TA: conceptually should live in q_shared.h -void AxisToAngles( vec3_t axis[3], vec3_t angles ); -#define Vector2Set(v, x, y) ((v)[0]=(x), (v)[1]=(y)) -float pointToLineDistance( const vec3_t point, const vec3_t p1, const vec3_t p2 ); -#define MAX(x,y) (x)>(y)?(x):(y) -#define MIN(x,y) (x)<(y)?(x):(y) - - -// Ridah -void GetPerpendicularViewVector( const vec3_t point, const vec3_t p1, - const vec3_t p2, vec3_t up ); -void ProjectPointOntoVector( vec3_t point, vec3_t vStart, - vec3_t vEnd, vec3_t vProj ); -float VectorDistance( vec3_t v1, vec3_t v2 ); -// done. - -//call roundf in place of round on non VM platforms -#ifdef Q3_VM -#define roundf round -#else -#define round roundf -#endif - -#define M_ROOT3 1.732050808f -float VectorMinComponent( vec3_t v ); -float VectorMaxComponent( vec3_t v ); -float round( float v ); - -float atof_neg( char *token, qboolean allowNegative ); -int atoi_neg( char *token, qboolean allowNegative ); - -void BG_ParseCSVEquipmentList( const char *string, weapon_t *weapons, int weaponsSize, - upgrade_t *upgrades, int upgradesSize ); -void BG_ParseCSVClassList( const char *string, pClass_t *classes, int classesSize ); -void BG_ParseCSVBuildableList( const char *string, buildable_t *buildables, int buildablesSize ); diff --git a/src/game/bg_slidemove.c b/src/game/bg_slidemove.c deleted file mode 100644 index 47f1ec04..00000000 --- a/src/game/bg_slidemove.c +++ /dev/null @@ -1,408 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// bg_slidemove.c -- part of bg_pmove functionality - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "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; -} diff --git a/src/game/g_active.c b/src/game/g_active.c deleted file mode 100644 index fc66ccff..00000000 --- a/src/game/g_active.c +++ /dev/null @@ -1,1524 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "g_local.h" - -/* -=============== -G_DamageFeedback - -Called just before a snapshot is sent to the given player. -Totals up all damage and generates both the player_state_t -damage values to that client for pain blends and kicks, and -global pain sound events for all clients. -=============== -*/ -void P_DamageFeedback( gentity_t *player ) -{ - gclient_t *client; - float count; - vec3_t angles; - - client = player->client; - if( client->ps.pm_type == PM_DEAD ) - return; - - // total points of damage shot at the player this frame - count = client->damage_blood + client->damage_armor; - if( count == 0 ) - return; // didn't take any damage - - if( count > 255 ) - count = 255; - - // send the information to the client - - // world damage (falling, slime, etc) uses a special code - // to make the blend blob centered instead of positional - if( client->damage_fromWorld ) - { - client->ps.damagePitch = 255; - client->ps.damageYaw = 255; - - client->damage_fromWorld = qfalse; - } - else - { - vectoangles( client->damage_from, angles ); - client->ps.damagePitch = angles[ PITCH ] / 360.0 * 256; - client->ps.damageYaw = angles[ YAW ] / 360.0 * 256; - } - - // play an apropriate pain sound - if( ( level.time > player->pain_debounce_time ) && !( player->flags & FL_GODMODE ) ) - { - player->pain_debounce_time = level.time + 700; - G_AddEvent( player, EV_PAIN, player->health ); - client->ps.damageEvent++; - } - - - client->ps.damageCount = count; - - // - // clear totals - // - client->damage_blood = 0; - client->damage_armor = 0; - client->damage_knockback = 0; -} - - - -/* -============= -P_WorldEffects - -Check for lava / slime contents and drowning -============= -*/ -void P_WorldEffects( gentity_t *ent ) -{ - int waterlevel; - - if( ent->client->noclip ) - { - ent->client->airOutTime = level.time + 12000; // don't need air - return; - } - - waterlevel = ent->waterlevel; - - // - // check for drowning - // - if( waterlevel == 3 ) - { - // if out of air, start drowning - if( ent->client->airOutTime < level.time) - { - // drown! - ent->client->airOutTime += 1000; - if( ent->health > 0 ) - { - // take more damage the longer underwater - ent->damage += 2; - if( ent->damage > 15 ) - ent->damage = 15; - - // play a gurp sound instead of a normal pain sound - if( ent->health <= ent->damage ) - G_Sound( ent, CHAN_VOICE, G_SoundIndex( "*drown.wav" ) ); - else if( rand( ) & 1 ) - G_Sound( ent, CHAN_VOICE, G_SoundIndex( "sound/player/gurp1.wav" ) ); - else - G_Sound( ent, CHAN_VOICE, G_SoundIndex( "sound/player/gurp2.wav" ) ); - - // don't play a normal pain sound - ent->pain_debounce_time = level.time + 200; - - G_Damage( ent, NULL, NULL, NULL, NULL, - ent->damage, DAMAGE_NO_ARMOR, MOD_WATER ); - } - } - } - else - { - ent->client->airOutTime = level.time + 12000; - ent->damage = 2; - } - - // - // check for sizzle damage (move to pmove?) - // - if( waterlevel && - ( ent->watertype & ( CONTENTS_LAVA | CONTENTS_SLIME ) ) ) - { - if( ent->health > 0 && - ent->pain_debounce_time <= level.time ) - { - if( ent->watertype & CONTENTS_LAVA ) - { - G_Damage( ent, NULL, NULL, NULL, NULL, - 30 * waterlevel, 0, MOD_LAVA ); - } - - if( ent->watertype & CONTENTS_SLIME ) - { - G_Damage( ent, NULL, NULL, NULL, NULL, - 10 * waterlevel, 0, MOD_SLIME ); - } - } - } -} - - - -/* -=============== -G_SetClientSound -=============== -*/ -void G_SetClientSound( gentity_t *ent ) -{ - if( ent->waterlevel && ( ent->watertype & ( CONTENTS_LAVA | CONTENTS_SLIME ) ) ) - ent->client->ps.loopSound = level.snd_fry; - else - ent->client->ps.loopSound = 0; -} - - - -//============================================================== - -/* -============== -ClientImpacts -============== -*/ -void ClientImpacts( gentity_t *ent, pmove_t *pm ) -{ - int i, j; - trace_t trace; - gentity_t *other; - - memset( &trace, 0, sizeof( trace ) ); - - for( i = 0; i < pm->numtouch; i++ ) - { - for( j = 0; j < i; j++ ) - { - if( pm->touchents[ j ] == pm->touchents[ i ] ) - break; - } - - if( j != i ) - continue; // duplicated - - other = &g_entities[ pm->touchents[ i ] ]; - - if( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) - ent->touch( ent, other, &trace ); - - //charge attack - if( ent->client->ps.weapon == WP_ALEVEL4 && - ent->client->ps.stats[ STAT_MISC ] > 0 && - ent->client->charging ) - ChargeAttack( ent, other ); - - if( !other->touch ) - continue; - - other->touch( other, ent, &trace ); - } -} - -/* -============ -G_TouchTriggers - -Find all trigger entities that ent's current position touches. -Spectators will only interact with teleporters. -============ -*/ -void G_TouchTriggers( gentity_t *ent ) -{ - int i, num; - int touch[MAX_GENTITIES]; - gentity_t *hit; - trace_t trace; - vec3_t mins, maxs; - vec3_t pmins, pmaxs; - static vec3_t range = { 10, 10, 10 }; - - if( !ent->client ) - return; - - // dead clients don't activate triggers! - if( ent->client->ps.stats[ STAT_HEALTH ] <= 0 ) - return; - - BG_FindBBoxForClass( ent->client->ps.stats[ STAT_PCLASS ], - pmins, pmaxs, NULL, NULL, NULL ); - - VectorAdd( ent->client->ps.origin, pmins, mins ); - VectorAdd( ent->client->ps.origin, pmaxs, maxs ); - - VectorSubtract( mins, range, mins ); - VectorAdd( maxs, range, maxs ); - - num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES ); - - // can't use ent->absmin, because that has a one unit pad - VectorAdd( ent->client->ps.origin, ent->r.mins, mins ); - VectorAdd( ent->client->ps.origin, ent->r.maxs, maxs ); - - for( i = 0; i < num; i++ ) - { - hit = &g_entities[ touch[ i ] ]; - - if( !hit->touch && !ent->touch ) - continue; - - if( !( hit->r.contents & CONTENTS_TRIGGER ) ) - continue; - - // ignore most entities if a spectator - if( ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) || - ( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) || - ( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING ) ) - { - if( hit->s.eType != ET_TELEPORT_TRIGGER && - // this is ugly but adding a new ET_? type will - // most likely cause network incompatibilities - hit->touch != Touch_DoorTrigger ) - { - //check for manually triggered doors - manualTriggerSpectator( hit, ent ); - continue; - } - } - - if( !trap_EntityContact( mins, maxs, hit ) ) - continue; - - memset( &trace, 0, sizeof( trace ) ); - - if( hit->touch ) - hit->touch( hit, ent, &trace ); - - if( ( ent->r.svFlags & SVF_BOT ) && ( ent->touch ) ) - ent->touch( ent, hit, &trace ); - } - - // if we didn't touch a jump pad this pmove frame - if( ent->client->ps.jumppad_frame != ent->client->ps.pmove_framecount ) - { - ent->client->ps.jumppad_frame = 0; - ent->client->ps.jumppad_ent = 0; - } -} - -/* -================= -SpectatorThink -================= -*/ -void SpectatorThink( gentity_t *ent, usercmd_t *ucmd ) -{ - pmove_t pm; - gclient_t *client; - - client = ent->client; - - client->oldbuttons = client->buttons; - client->buttons = ucmd->buttons; - - if( client->sess.spectatorState != SPECTATOR_FOLLOW ) - { - if( client->sess.spectatorState == SPECTATOR_LOCKED ) - client->ps.pm_type = PM_FREEZE; - else - client->ps.pm_type = PM_SPECTATOR; - - client->ps.speed = BG_FindSpeedForClass( client->ps.stats[ STAT_PCLASS ] ); - - client->ps.stats[ STAT_STAMINA ] = 0; - client->ps.stats[ STAT_MISC ] = 0; - client->ps.stats[ STAT_BUILDABLE ] = 0; - client->ps.stats[ STAT_PCLASS ] = PCL_NONE; - client->ps.weapon = WP_NONE; - - // set up for pmove - memset( &pm, 0, sizeof( pm ) ); - pm.ps = &client->ps; - pm.cmd = *ucmd; - pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; // spectators can fly through bodies - pm.trace = trap_Trace; - pm.pointcontents = trap_PointContents; - - // perform a pmove - Pmove( &pm ); - - // save results of pmove - VectorCopy( client->ps.origin, ent->s.origin ); - - G_TouchTriggers( ent ); - trap_UnlinkEntity( ent ); - - if( ( client->buttons & BUTTON_ATTACK ) && !( client->oldbuttons & BUTTON_ATTACK ) ) - { - //if waiting in a queue remove from the queue - if( client->ps.pm_flags & PMF_QUEUED ) - { - if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - G_RemoveFromSpawnQueue( &level.alienSpawnQueue, client->ps.clientNum ); - else if( client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - G_RemoveFromSpawnQueue( &level.humanSpawnQueue, client->ps.clientNum ); - - client->pers.classSelection = PCL_NONE; - client->ps.stats[ STAT_PCLASS ] = PCL_NONE; - } - else if( client->pers.classSelection == PCL_NONE ) - { - if( client->pers.teamSelection == PTE_NONE ) - G_TriggerMenu( client->ps.clientNum, MN_TEAM ); - else if( client->pers.teamSelection == PTE_ALIENS ) - G_TriggerMenu( client->ps.clientNum, MN_A_CLASS ); - else if( client->pers.teamSelection == PTE_HUMANS ) - G_TriggerMenu( client->ps.clientNum, MN_H_SPAWN ); - } - } - - //set the queue position for the client side - if( client->ps.pm_flags & PMF_QUEUED ) - { - if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - client->ps.persistant[ PERS_QUEUEPOS ] = - G_GetPosInSpawnQueue( &level.alienSpawnQueue, client->ps.clientNum ); - } - else if( client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - client->ps.persistant[ PERS_QUEUEPOS ] = - G_GetPosInSpawnQueue( &level.humanSpawnQueue, client->ps.clientNum ); - } - } - } - - if( ( client->buttons & BUTTON_USE_HOLDABLE ) && !( client->oldbuttons & BUTTON_USE_HOLDABLE ) ) - Cmd_Follow_f( ent, qtrue ); -} - - - -/* -================= -ClientInactivityTimer - -Returns qfalse if the client is dropped -================= -*/ -qboolean ClientInactivityTimer( gclient_t *client ) -{ - if( ! g_inactivity.integer ) - { - // give everyone some time, so if the operator sets g_inactivity during - // gameplay, everyone isn't kicked - client->inactivityTime = level.time + 60 * 1000; - client->inactivityWarning = qfalse; - } - else if( client->pers.cmd.forwardmove || - client->pers.cmd.rightmove || - client->pers.cmd.upmove || - ( client->pers.cmd.buttons & BUTTON_ATTACK ) ) - { - client->inactivityTime = level.time + g_inactivity.integer * 1000; - client->inactivityWarning = qfalse; - } - else if( !client->pers.localClient ) - { - if( level.time > client->inactivityTime ) - { - trap_DropClient( client - level.clients, "Dropped due to inactivity" ); - return qfalse; - } - - if( level.time > client->inactivityTime - 10000 && !client->inactivityWarning ) - { - client->inactivityWarning = qtrue; - G_SendCommandFromServer( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" ); - } - } - - return qtrue; -} - -/* -================== -ClientTimerActions - -Actions that happen once a second -================== -*/ -void ClientTimerActions( gentity_t *ent, int msec ) -{ - gclient_t *client; - usercmd_t *ucmd; - int aForward, aRight; - - ucmd = &ent->client->pers.cmd; - - aForward = abs( ucmd->forwardmove ); - aRight = abs( ucmd->rightmove ); - - client = ent->client; - client->time100 += msec; - client->time1000 += msec; - client->time10000 += msec; - - while ( client->time100 >= 100 ) - { - client->time100 -= 100; - - //if not trying to run then not trying to sprint - if( aForward <= 64 ) - client->ps.stats[ STAT_STATE ] &= ~SS_SPEEDBOOST; - - if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) && BG_UpgradeIsActive( UP_JETPACK, client->ps.stats ) ) - client->ps.stats[ STAT_STATE ] &= ~SS_SPEEDBOOST; - - if( ( client->ps.stats[ STAT_STATE ] & SS_SPEEDBOOST ) && ucmd->upmove >= 0 ) - { - //subtract stamina - if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, client->ps.stats ) ) - client->ps.stats[ STAT_STAMINA ] -= STAMINA_LARMOUR_TAKE; - else - client->ps.stats[ STAT_STAMINA ] -= STAMINA_SPRINT_TAKE; - - if( client->ps.stats[ STAT_STAMINA ] < -MAX_STAMINA ) - client->ps.stats[ STAT_STAMINA ] = -MAX_STAMINA; - } - - if( ( aForward <= 64 && aForward > 5 ) || ( aRight <= 64 && aRight > 5 ) ) - { - //restore stamina - client->ps.stats[ STAT_STAMINA ] += STAMINA_WALK_RESTORE; - - if( client->ps.stats[ STAT_STAMINA ] > MAX_STAMINA ) - client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA; - } - else if( aForward <= 5 && aRight <= 5 ) - { - //restore stamina faster - client->ps.stats[ STAT_STAMINA ] += STAMINA_STOP_RESTORE; - - if( client->ps.stats[ STAT_STAMINA ] > MAX_STAMINA ) - client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA; - } - - //client is charging up for a pounce - if( client->ps.weapon == WP_ALEVEL3 || client->ps.weapon == WP_ALEVEL3_UPG ) - { - int pounceSpeed = 0; - - if( client->ps.weapon == WP_ALEVEL3 ) - pounceSpeed = LEVEL3_POUNCE_SPEED; - else if( client->ps.weapon == WP_ALEVEL3_UPG ) - pounceSpeed = LEVEL3_POUNCE_UPG_SPEED; - - if( client->ps.stats[ STAT_MISC ] < pounceSpeed && ucmd->buttons & BUTTON_ATTACK2 ) - client->ps.stats[ STAT_MISC ] += ( 100.0f / (float)LEVEL3_POUNCE_CHARGE_TIME ) * pounceSpeed; - - if( !( ucmd->buttons & BUTTON_ATTACK2 ) ) - { - if( client->ps.stats[ STAT_MISC ] > 0 ) - { - client->allowedToPounce = qtrue; - client->pouncePayload = client->ps.stats[ STAT_MISC ]; - } - - client->ps.stats[ STAT_MISC ] = 0; - } - - if( client->ps.stats[ STAT_MISC ] > pounceSpeed ) - client->ps.stats[ STAT_MISC ] = pounceSpeed; - } - - //client is charging up for a... charge - if( client->ps.weapon == WP_ALEVEL4 ) - { - if( client->ps.stats[ STAT_MISC ] < LEVEL4_CHARGE_TIME && ucmd->buttons & BUTTON_ATTACK2 && - !client->charging ) - { - client->charging = qfalse; //should already be off, just making sure - client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING; - - if( ucmd->forwardmove > 0 ) - { - //trigger charge sound...is quite annoying - //if( client->ps.stats[ STAT_MISC ] <= 0 ) - // G_AddEvent( ent, EV_LEV4_CHARGE_PREPARE, 0 ); - - client->ps.stats[ STAT_MISC ] += (int)( 100 * (float)LEVEL4_CHARGE_CHARGE_RATIO ); - - if( client->ps.stats[ STAT_MISC ] > LEVEL4_CHARGE_TIME ) - client->ps.stats[ STAT_MISC ] = LEVEL4_CHARGE_TIME; - } - else - client->ps.stats[ STAT_MISC ] = 0; - } - - if( !( ucmd->buttons & BUTTON_ATTACK2 ) || client->charging || - client->ps.stats[ STAT_MISC ] == LEVEL4_CHARGE_TIME ) - { - if( client->ps.stats[ STAT_MISC ] > LEVEL4_MIN_CHARGE_TIME ) - { - client->ps.stats[ STAT_MISC ] -= 100; - - if( client->charging == qfalse ) - G_AddEvent( ent, EV_LEV4_CHARGE_START, 0 ); - - client->charging = qtrue; - client->ps.stats[ STAT_STATE ] |= SS_CHARGING; - - //if the charger has stopped moving take a chunk of charge away - if( VectorLength( client->ps.velocity ) < 64.0f || aRight ) - client->ps.stats[ STAT_MISC ] = client->ps.stats[ STAT_MISC ] / 2; - - //can't charge backwards - if( ucmd->forwardmove < 0 ) - client->ps.stats[ STAT_MISC ] = 0; - } - else - client->ps.stats[ STAT_MISC ] = 0; - - - if( client->ps.stats[ STAT_MISC ] <= 0 ) - { - client->ps.stats[ STAT_MISC ] = 0; - client->charging = qfalse; - client->ps.stats[ STAT_STATE ] &= ~SS_CHARGING; - } - } - } - - //client is charging up an lcannon - if( client->ps.weapon == WP_LUCIFER_CANNON ) - { - int ammo; - - BG_UnpackAmmoArray( WP_LUCIFER_CANNON, client->ps.ammo, client->ps.powerups, &ammo, NULL ); - - if( client->ps.stats[ STAT_MISC ] < LCANNON_TOTAL_CHARGE && ucmd->buttons & BUTTON_ATTACK ) - client->ps.stats[ STAT_MISC ] += ( 100.0f / LCANNON_CHARGE_TIME ) * LCANNON_TOTAL_CHARGE; - - if( client->ps.stats[ STAT_MISC ] > LCANNON_TOTAL_CHARGE ) - client->ps.stats[ STAT_MISC ] = LCANNON_TOTAL_CHARGE; - - if( client->ps.stats[ STAT_MISC ] > ( ammo * LCANNON_TOTAL_CHARGE ) / 10 ) - client->ps.stats[ STAT_MISC ] = ammo * LCANNON_TOTAL_CHARGE / 10; - } - - switch( client->ps.weapon ) - { - case WP_ABUILD: - case WP_ABUILD2: - case WP_HBUILD: - case WP_HBUILD2: - //set validity bit on buildable - if( ( client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) > BA_NONE ) - { - int dist = BG_FindBuildDistForClass( ent->client->ps.stats[ STAT_PCLASS ] ); - vec3_t dummy; - - if( G_itemFits( ent, client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT, - dist, dummy ) == IBE_NONE ) - client->ps.stats[ STAT_BUILDABLE ] |= SB_VALID_TOGGLEBIT; - else - client->ps.stats[ STAT_BUILDABLE ] &= ~SB_VALID_TOGGLEBIT; - } - - //update build timer - if( client->ps.stats[ STAT_MISC ] > 0 ) - client->ps.stats[ STAT_MISC ] -= 100; - - if( client->ps.stats[ STAT_MISC ] < 0 ) - client->ps.stats[ STAT_MISC ] = 0; - break; - - default: - break; - } - - if( client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE ) - { - int remainingStartupTime = MEDKIT_STARTUP_TIME - ( level.time - client->lastMedKitTime ); - - if( remainingStartupTime < 0 ) - { - if( ent->health < ent->client->ps.stats[ STAT_MAX_HEALTH ] && - ent->client->medKitHealthToRestore && - ent->client->ps.pm_type != PM_DEAD ) - { - ent->client->medKitHealthToRestore--; - ent->health++; - } - else - ent->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE; - } - else - { - if( ent->health < ent->client->ps.stats[ STAT_MAX_HEALTH ] && - ent->client->medKitHealthToRestore && - ent->client->ps.pm_type != PM_DEAD ) - { - //partial increase - if( level.time > client->medKitIncrementTime ) - { - ent->client->medKitHealthToRestore--; - ent->health++; - - client->medKitIncrementTime = level.time + - ( remainingStartupTime / MEDKIT_STARTUP_SPEED ); - } - } - else - ent->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE; - } - } - } - - while( client->time1000 >= 1000 ) - { - client->time1000 -= 1000; - - //client is poison clouded - if( client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED ) - G_Damage( ent, client->lastPoisonCloudedClient, client->lastPoisonCloudedClient, NULL, NULL, - LEVEL1_PCLOUD_DMG, 0, MOD_LEVEL1_PCLOUD ); - - //client is poisoned - if( client->ps.stats[ STAT_STATE ] & SS_POISONED ) - { - int i; - int seconds = ( ( level.time - client->lastPoisonTime ) / 1000 ) + 1; - int damage = ALIEN_POISON_DMG, damage2 = 0; - - for( i = 0; i < seconds; i++ ) - { - if( i == seconds - 1 ) - damage2 = damage; - - damage *= ALIEN_POISON_DIVIDER; - } - - damage = damage2 - damage; - - G_Damage( ent, client->lastPoisonClient, client->lastPoisonClient, NULL, NULL, - damage, 0, MOD_POISON ); - } - - //replenish alien health - if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - int entityList[ MAX_GENTITIES ]; - vec3_t range = { LEVEL4_REGEN_RANGE, LEVEL4_REGEN_RANGE, LEVEL4_REGEN_RANGE }; - vec3_t mins, maxs; - int i, num; - gentity_t *boostEntity; - float modifier = 1.0f; - - VectorAdd( client->ps.origin, range, maxs ); - VectorSubtract( client->ps.origin, range, mins ); - - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - for( i = 0; i < num; i++ ) - { - boostEntity = &g_entities[ entityList[ i ] ]; - - if( boostEntity->client && boostEntity->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS && - boostEntity->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL4 ) - { - modifier = LEVEL4_REGEN_MOD; - break; - } - else if( boostEntity->s.eType == ET_BUILDABLE && - boostEntity->s.modelindex == BA_A_BOOSTER && - boostEntity->spawned ) - { - modifier = BOOSTER_REGEN_MOD; - break; - } - } - - if( ent->health > 0 && ent->health < client->ps.stats[ STAT_MAX_HEALTH ] && - ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time ) - ent->health += BG_FindRegenRateForClass( client->ps.stats[ STAT_PCLASS ] ) * modifier; - - if( ent->health > client->ps.stats[ STAT_MAX_HEALTH ] ) - ent->health = client->ps.stats[ STAT_MAX_HEALTH ]; - } - } - - while( client->time10000 >= 10000 ) - { - client->time10000 -= 10000; - - if( client->ps.weapon == WP_ALEVEL3_UPG ) - { - int ammo, maxAmmo; - - BG_FindAmmoForWeapon( WP_ALEVEL3_UPG, &maxAmmo, NULL ); - BG_UnpackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, &ammo, NULL ); - - if( ammo < maxAmmo ) - { - ammo++; - BG_PackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, ammo, 0 ); - } - } - } -} - -/* -==================== -ClientIntermissionThink -==================== -*/ -void ClientIntermissionThink( gclient_t *client ) -{ - client->ps.eFlags &= ~EF_TALK; - client->ps.eFlags &= ~EF_FIRING; - client->ps.eFlags &= ~EF_FIRING2; - - // the level will exit when everyone wants to or after timeouts - - // swap and latch button actions - client->oldbuttons = client->buttons; - client->buttons = client->pers.cmd.buttons; - if( client->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) & ( client->oldbuttons ^ client->buttons ) ) - client->readyToExit = 1; -} - - -/* -================ -ClientEvents - -Events will be passed on to the clients for presentation, -but any server game effects are handled here -================ -*/ -void ClientEvents( gentity_t *ent, int oldEventSequence ) -{ - int i; - int event; - gclient_t *client; - int damage; - vec3_t dir; - vec3_t point, mins; - float fallDistance; - pClass_t class; - - client = ent->client; - class = client->ps.stats[ STAT_PCLASS ]; - - if( oldEventSequence < client->ps.eventSequence - MAX_PS_EVENTS ) - oldEventSequence = client->ps.eventSequence - MAX_PS_EVENTS; - - for( i = oldEventSequence; i < client->ps.eventSequence; i++ ) - { - event = client->ps.events[ i & ( MAX_PS_EVENTS - 1 ) ]; - - switch( event ) - { - case EV_FALL_MEDIUM: - case EV_FALL_FAR: - if( ent->s.eType != ET_PLAYER ) - break; // not in the player model - - fallDistance = ( (float)client->ps.stats[ STAT_FALLDIST ] - MIN_FALL_DISTANCE ) / - ( MAX_FALL_DISTANCE - MIN_FALL_DISTANCE ); - - if( fallDistance < 0.0f ) - fallDistance = 0.0f; - else if( fallDistance > 1.0f ) - fallDistance = 1.0f; - - damage = (int)( (float)BG_FindHealthForClass( class ) * - BG_FindFallDamageForClass( class ) * fallDistance ); - - VectorSet( dir, 0, 0, 1 ); - BG_FindBBoxForClass( class, mins, NULL, NULL, NULL, NULL ); - mins[ 0 ] = mins[ 1 ] = 0.0f; - VectorAdd( client->ps.origin, mins, point ); - - ent->pain_debounce_time = level.time + 200; // no normal pain sound - G_Damage( ent, NULL, NULL, dir, point, damage, DAMAGE_NO_LOCDAMAGE, MOD_FALLING ); - break; - - case EV_FIRE_WEAPON: - FireWeapon( ent ); - break; - - case EV_FIRE_WEAPON2: - FireWeapon2( ent ); - break; - - case EV_FIRE_WEAPON3: - FireWeapon3( ent ); - break; - - case EV_NOAMMO: - //if we just ran out of grenades, remove the inventory item - if( ent->s.weapon == WP_GRENADE ) - { - int j; - - BG_RemoveWeaponFromInventory( ent->s.weapon, ent->client->ps.stats ); - - //switch to the first non blaster weapon - for( j = WP_NONE + 1; j < WP_NUM_WEAPONS; j++ ) - { - if( j == WP_BLASTER ) - continue; - - if( BG_InventoryContainsWeapon( j, ent->client->ps.stats ) ) - { - G_ForceWeaponChange( ent, j ); - break; - } - } - - //only got the blaster to switch to - if( j == WP_NUM_WEAPONS ) - G_ForceWeaponChange( ent, WP_BLASTER ); - - //update ClientInfo - ClientUserinfoChanged( ent->client->ps.clientNum ); - } - - break; - - default: - break; - } - } -} - - -/* -============== -SendPendingPredictableEvents -============== -*/ -void SendPendingPredictableEvents( playerState_t *ps ) -{ - gentity_t *t; - int event, seq; - int extEvent, number; - - // if there are still events pending - if( ps->entityEventSequence < ps->eventSequence ) - { - // create a temporary entity for this event which is sent to everyone - // except the client who generated the event - seq = ps->entityEventSequence & ( MAX_PS_EVENTS - 1 ); - event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 ); - // set external event to zero before calling BG_PlayerStateToEntityState - extEvent = ps->externalEvent; - ps->externalEvent = 0; - // create temporary entity for event - t = G_TempEntity( ps->origin, event ); - number = t->s.number; - BG_PlayerStateToEntityState( ps, &t->s, qtrue ); - t->s.number = number; - t->s.eType = ET_EVENTS + event; - t->s.eFlags |= EF_PLAYER_EVENT; - t->s.otherEntityNum = ps->clientNum; - // send to everyone except the client who generated the event - t->r.svFlags |= SVF_NOTSINGLECLIENT; - t->r.singleClient = ps->clientNum; - // set back external event - ps->externalEvent = extEvent; - } -} - -/* -============== -ClientThink - -This will be called once for each client frame, which will -usually be a couple times for each server frame on fast clients. - -If "g_synchronousClients 1" is set, this will be called exactly -once for each server frame, which makes for smooth demo recording. -============== -*/ -void ClientThink_real( gentity_t *ent ) -{ - gclient_t *client; - pmove_t pm; - int oldEventSequence; - int msec; - usercmd_t *ucmd; - - client = ent->client; - - // don't think if the client is not yet connected (and thus not yet spawned in) - if( client->pers.connected != CON_CONNECTED ) - return; - - // mark the time, so the connection sprite can be removed - ucmd = &ent->client->pers.cmd; - - // sanity check the command time to prevent speedup cheating - if( ucmd->serverTime > level.time + 200 ) - { - ucmd->serverTime = level.time + 200; -// G_Printf("serverTime <<<<<\n" ); - } - - if( ucmd->serverTime < level.time - 1000 ) - { - ucmd->serverTime = level.time - 1000; -// G_Printf("serverTime >>>>>\n" ); - } - - msec = ucmd->serverTime - client->ps.commandTime; - // following others may result in bad times, but we still want - // to check for follow toggles - if( msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW ) - return; - - if( msec > 200 ) - msec = 200; - - if( pmove_msec.integer < 8 ) - trap_Cvar_Set( "pmove_msec", "8" ); - else if( pmove_msec.integer > 33 ) - trap_Cvar_Set( "pmove_msec", "33" ); - - if( pmove_fixed.integer || client->pers.pmoveFixed ) - { - ucmd->serverTime = ( ( ucmd->serverTime + pmove_msec.integer - 1 ) / pmove_msec.integer ) * pmove_msec.integer; - //if (ucmd->serverTime - client->ps.commandTime <= 0) - // return; - } - - // - // check for exiting intermission - // - if( level.intermissiontime ) - { - ClientIntermissionThink( client ); - return; - } - - // spectators don't do much - if( client->sess.sessionTeam == TEAM_SPECTATOR ) - { - if( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) - return; - - SpectatorThink( ent, ucmd ); - return; - } - - G_UpdatePTRConnection( client ); - - // check for inactivity timer, but never drop the local client of a non-dedicated server - if( !ClientInactivityTimer( client ) ) - return; - - if( client->noclip ) - client->ps.pm_type = PM_NOCLIP; - else if( client->ps.stats[ STAT_HEALTH ] <= 0 ) - client->ps.pm_type = PM_DEAD; - else if( client->ps.stats[ STAT_STATE ] & SS_INFESTING || - client->ps.stats[ STAT_STATE ] & SS_HOVELING ) - client->ps.pm_type = PM_FREEZE; - else if( client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED || - client->ps.stats[ STAT_STATE ] & SS_GRABBED ) - client->ps.pm_type = PM_GRABBED; - else if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) && BG_UpgradeIsActive( UP_JETPACK, client->ps.stats ) ) - client->ps.pm_type = PM_JETPACK; - else - client->ps.pm_type = PM_NORMAL; - - if( client->ps.stats[ STAT_STATE ] & SS_GRABBED && - client->grabExpiryTime < level.time ) - client->ps.stats[ STAT_STATE ] &= ~SS_GRABBED; - - if( client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED && - client->lastLockTime + 5000 < level.time ) - client->ps.stats[ STAT_STATE ] &= ~SS_BLOBLOCKED; - - if( client->ps.stats[ STAT_STATE ] & SS_SLOWLOCKED && - client->lastLockTime + ABUILDER_BLOB_TIME < level.time ) - client->ps.stats[ STAT_STATE ] &= ~SS_SLOWLOCKED; - - client->ps.stats[ STAT_BOOSTTIME ] = level.time - client->lastBoostedTime; - - if( client->ps.stats[ STAT_STATE ] & SS_BOOSTED && - client->lastBoostedTime + BOOST_TIME < level.time ) - client->ps.stats[ STAT_STATE ] &= ~SS_BOOSTED; - - if( client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED && - client->lastPoisonCloudedTime + LEVEL1_PCLOUD_TIME < level.time ) - client->ps.stats[ STAT_STATE ] &= ~SS_POISONCLOUDED; - - if( client->ps.stats[ STAT_STATE ] & SS_POISONED && - client->lastPoisonTime + ALIEN_POISON_TIME < level.time ) - client->ps.stats[ STAT_STATE ] &= ~SS_POISONED; - - client->ps.gravity = g_gravity.value; - - if( BG_InventoryContainsUpgrade( UP_MEDKIT, client->ps.stats ) && - BG_UpgradeIsActive( UP_MEDKIT, client->ps.stats ) ) - { - //if currently using a medkit or have no need for a medkit now - if( client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE || - ( client->ps.stats[ STAT_HEALTH ] == client->ps.stats[ STAT_MAX_HEALTH ] && - !( client->ps.stats[ STAT_STATE ] & SS_POISONED ) ) ) - { - BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats ); - } - else if( client->ps.stats[ STAT_HEALTH ] > 0 ) - { - //remove anti toxin - BG_DeactivateUpgrade( UP_MEDKIT, client->ps.stats ); - BG_RemoveUpgradeFromInventory( UP_MEDKIT, client->ps.stats ); - - client->ps.stats[ STAT_STATE ] &= ~SS_POISONED; - client->poisonImmunityTime = level.time + MEDKIT_POISON_IMMUNITY_TIME; - - client->ps.stats[ STAT_STATE ] |= SS_MEDKIT_ACTIVE; - client->lastMedKitTime = level.time; - client->medKitHealthToRestore = - client->ps.stats[ STAT_MAX_HEALTH ] - client->ps.stats[ STAT_HEALTH ]; - client->medKitIncrementTime = level.time + - ( MEDKIT_STARTUP_TIME / MEDKIT_STARTUP_SPEED ); - - G_AddEvent( ent, EV_MEDKIT_USED, 0 ); - } - } - - if( BG_InventoryContainsUpgrade( UP_GRENADE, client->ps.stats ) && - BG_UpgradeIsActive( UP_GRENADE, client->ps.stats ) ) - { - int lastWeapon = ent->s.weapon; - - //remove grenade - BG_DeactivateUpgrade( UP_GRENADE, client->ps.stats ); - BG_RemoveUpgradeFromInventory( UP_GRENADE, client->ps.stats ); - - //M-M-M-M-MONSTER HACK - ent->s.weapon = WP_GRENADE; - FireWeapon( ent ); - ent->s.weapon = lastWeapon; - } - - // set speed - client->ps.speed = g_speed.value * BG_FindSpeedForClass( client->ps.stats[ STAT_PCLASS ] ); - - if( client->lastCreepSlowTime + CREEP_TIMEOUT < level.time ) - client->ps.stats[ STAT_STATE ] &= ~SS_CREEPSLOWED; - - //randomly disable the jet pack if damaged - if( BG_InventoryContainsUpgrade( UP_JETPACK, client->ps.stats ) && - BG_UpgradeIsActive( UP_JETPACK, client->ps.stats ) ) - { - if( ent->lastDamageTime + JETPACK_DISABLE_TIME > level.time ) - { - if( random( ) > JETPACK_DISABLE_CHANCE ) - client->ps.pm_type = PM_NORMAL; - } - - //switch jetpack off if no reactor - if( !level.reactorPresent ) - BG_DeactivateUpgrade( UP_JETPACK, client->ps.stats ); - } - - // set up for pmove - oldEventSequence = client->ps.eventSequence; - - memset( &pm, 0, sizeof( pm ) ); - - if( !( ucmd->buttons & BUTTON_TALK ) ) //&& client->ps.weaponTime <= 0 ) //TA: erk more server load - { - switch( client->ps.weapon ) - { - case WP_ALEVEL0: - if( client->ps.weaponTime <= 0 ) - pm.autoWeaponHit[ client->ps.weapon ] = CheckVenomAttack( ent ); - break; - - case WP_ALEVEL1: - case WP_ALEVEL1_UPG: - CheckGrabAttack( ent ); - break; - - case WP_ALEVEL3: - case WP_ALEVEL3_UPG: - if( client->ps.weaponTime <= 0 ) - pm.autoWeaponHit[ client->ps.weapon ] = CheckPounceAttack( ent ); - break; - - default: - break; - } - } - - if( ent->flags & FL_FORCE_GESTURE ) - { - ent->flags &= ~FL_FORCE_GESTURE; - ent->client->pers.cmd.buttons |= BUTTON_GESTURE; - } - - pm.ps = &client->ps; - pm.cmd = *ucmd; - - if( pm.ps->pm_type == PM_DEAD ) - pm.tracemask = MASK_PLAYERSOLID; // & ~CONTENTS_BODY; - - if( pm.ps->stats[ STAT_STATE ] & SS_INFESTING || - pm.ps->stats[ STAT_STATE ] & SS_HOVELING ) - pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; - else - pm.tracemask = MASK_PLAYERSOLID; - - pm.trace = trap_Trace; - pm.pointcontents = trap_PointContents; - pm.debugLevel = g_debugMove.integer; - pm.noFootsteps = 0; - - pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed; - pm.pmove_msec = pmove_msec.integer; - - VectorCopy( client->ps.origin, client->oldOrigin ); - - // moved from after Pmove -- potentially the cause of - // future triggering bugs - if( !ent->client->noclip ) - G_TouchTriggers( ent ); - - Pmove( &pm ); - - // save results of pmove - if( ent->client->ps.eventSequence != oldEventSequence ) - ent->eventTime = level.time; - - if( g_smoothClients.integer ) - BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue ); - else - BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue ); - - SendPendingPredictableEvents( &ent->client->ps ); - - if( !( ent->client->ps.eFlags & EF_FIRING ) ) - client->fireHeld = qfalse; // for grapple - if( !( ent->client->ps.eFlags & EF_FIRING2 ) ) - client->fire2Held = qfalse; - - // use the snapped origin for linking so it matches client predicted versions - VectorCopy( ent->s.pos.trBase, ent->r.currentOrigin ); - - VectorCopy( pm.mins, ent->r.mins ); - VectorCopy( pm.maxs, ent->r.maxs ); - - ent->waterlevel = pm.waterlevel; - ent->watertype = pm.watertype; - - // execute client events - ClientEvents( ent, oldEventSequence ); - - // link entity now, after any personal teleporters have been used - trap_LinkEntity( ent ); - - // NOTE: now copy the exact origin over otherwise clients can be snapped into solid - VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); - VectorCopy( ent->client->ps.origin, ent->s.origin ); - - // touch other objects - ClientImpacts( ent, &pm ); - - // save results of triggers and client events - if( ent->client->ps.eventSequence != oldEventSequence ) - ent->eventTime = level.time; - - // swap and latch button actions - client->oldbuttons = client->buttons; - client->buttons = ucmd->buttons; - client->latched_buttons |= client->buttons & ~client->oldbuttons; - - if( ( client->buttons & BUTTON_GETFLAG ) && !( client->oldbuttons & BUTTON_GETFLAG ) && - client->ps.stats[ STAT_HEALTH ] > 0 ) - { - trace_t trace; - vec3_t view, point; - gentity_t *traceEnt; - - if( client->ps.stats[ STAT_STATE ] & SS_HOVELING ) - { - gentity_t *hovel = client->hovel; - - //only let the player out if there is room - if( !AHovel_Blocked( hovel, ent, qtrue ) ) - { - //prevent lerping - client->ps.eFlags ^= EF_TELEPORT_BIT; - client->ps.eFlags &= ~EF_NODRAW; - - //client leaves hovel - client->ps.stats[ STAT_STATE ] &= ~SS_HOVELING; - - //hovel is empty - G_setBuildableAnim( hovel, BANIM_ATTACK2, qfalse ); - hovel->active = qfalse; - } - else - { - //exit is blocked - G_TriggerMenu( ent->client->ps.clientNum, MN_A_HOVEL_BLOCKED ); - } - } - else - { -#define USE_OBJECT_RANGE 64 - - int entityList[ MAX_GENTITIES ]; - vec3_t range = { USE_OBJECT_RANGE, USE_OBJECT_RANGE, USE_OBJECT_RANGE }; - vec3_t mins, maxs; - int i, num; - int j; - qboolean upgrade = qfalse; - - //TA: look for object infront of player - AngleVectors( client->ps.viewangles, view, NULL, NULL ); - VectorMA( client->ps.origin, USE_OBJECT_RANGE, view, point ); - trap_Trace( &trace, client->ps.origin, NULL, NULL, point, ent->s.number, MASK_SHOT ); - - traceEnt = &g_entities[ trace.entityNum ]; - - if( traceEnt && traceEnt->biteam == client->ps.stats[ STAT_PTEAM ] && traceEnt->use ) - traceEnt->use( traceEnt, ent, ent ); //other and activator are the same in this context - else - { - //no entity in front of player - do a small area search - - VectorAdd( client->ps.origin, range, maxs ); - VectorSubtract( client->ps.origin, range, mins ); - - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - for( i = 0; i < num; i++ ) - { - traceEnt = &g_entities[ entityList[ i ] ]; - - if( traceEnt && traceEnt->biteam == client->ps.stats[ STAT_PTEAM ] && traceEnt->use ) - { - traceEnt->use( traceEnt, ent, ent ); //other and activator are the same in this context - break; - } - } - - if( i == num && client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - for( j = PCL_NONE + 1; j < PCL_NUM_CLASSES; j++ ) - { - if( BG_ClassCanEvolveFromTo( client->ps.stats[ STAT_PCLASS ], j, - client->ps.persistant[ PERS_CREDIT ], 0 ) >= 0 && - BG_FindStagesForClass( j, g_alienStage.integer ) && G_ClassIsAllowed( j ) ) - { - upgrade = qtrue; - break; - } - } - - if( upgrade ) - { - //no nearby objects and alien - show class menu - G_TriggerMenu( ent->client->ps.clientNum, MN_A_INFEST ); - } - else - { - //flash frags - G_AddEvent( ent, EV_ALIEN_EVOLVE_FAILED, 0 ); - } - } - } - } - } - - // check for respawning - if( client->ps.stats[ STAT_HEALTH ] <= 0 ) - { - // wait for the attack button to be pressed - if( level.time > client->respawnTime ) - { - // forcerespawn is to prevent users from waiting out powerups - if( g_forcerespawn.integer > 0 && - ( level.time - client->respawnTime ) > 0 ) - { - respawn( ent ); - return; - } - - // pressing attack or use is the normal respawn method - if( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) - { - respawn( ent ); - } - } - return; - } - - if( level.framenum > client->retriggerArmouryMenu && client->retriggerArmouryMenu ) - { - G_TriggerMenu( client->ps.clientNum, MN_H_ARMOURY ); - - client->retriggerArmouryMenu = 0; - } - - // Give clients some credit periodically - if( ent->client->lastKillTime + FREEKILL_PERIOD < level.time ) - { - if( g_suddenDeathTime.integer && - ( level.time - level.startTime >= g_suddenDeathTime.integer * 60000 ) ) - { - //gotta love logic like this eh? - } - else if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - G_AddCreditToClient( ent->client, FREEKILL_ALIEN, qtrue ); - else if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - G_AddCreditToClient( ent->client, FREEKILL_HUMAN, qtrue ); - - ent->client->lastKillTime = level.time; - } - - // perform once-a-second actions - ClientTimerActions( ent, msec ); - - if( ent->suicideTime > 0 && ent->suicideTime < level.time ) - { - ent->flags &= ~FL_GODMODE; - ent->client->ps.stats[ STAT_HEALTH ] = ent->health = 0; - player_die( ent, ent, ent, 100000, MOD_SUICIDE ); - - ent->suicideTime = 0; - } -} - -/* -================== -ClientThink - -A new command has arrived from the client -================== -*/ -void ClientThink( int clientNum ) -{ - gentity_t *ent; - - ent = g_entities + clientNum; - trap_GetUsercmd( clientNum, &ent->client->pers.cmd ); - - // mark the time we got info, so we can display the - // phone jack if they don't get any for a while - ent->client->lastCmdTime = level.time; - - if( !(ent->r.svFlags & SVF_BOT) && !g_synchronousClients.integer ) - ClientThink_real( ent ); -} - - -void G_RunClient( gentity_t *ent ) -{ - if( !( ent->r.svFlags & SVF_BOT ) && !g_synchronousClients.integer ) - return; - - ent->client->pers.cmd.serverTime = level.time; - ClientThink_real( ent ); -} - - -/* -================== -SpectatorClientEndFrame - -================== -*/ -void SpectatorClientEndFrame( gentity_t *ent ) -{ - gclient_t *cl; - int clientNum, flags; - - // if we are doing a chase cam or a remote view, grab the latest info - if( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) - { - clientNum = ent->client->sess.spectatorClient; - - if( clientNum >= 0 ) - { - cl = &level.clients[ clientNum ]; - - if( cl->pers.connected == CON_CONNECTED && cl->sess.sessionTeam != TEAM_SPECTATOR ) - { - flags = ( cl->ps.eFlags & ~( EF_VOTED | EF_TEAMVOTED ) ) | - ( ent->client->ps.eFlags & ( EF_VOTED | EF_TEAMVOTED ) ); - ent->client->ps = cl->ps; - ent->client->ps.pm_flags |= PMF_FOLLOW; - ent->client->ps.eFlags = flags; - } - } - } -} - -/* -============== -ClientEndFrame - -Called at the end of each server frame for each connected client -A fast client will have multiple ClientThink for each ClientEdFrame, -while a slow client may have multiple ClientEndFrame between ClientThink. -============== -*/ -void ClientEndFrame( gentity_t *ent ) -{ - clientPersistant_t *pers; - - if( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) - { - SpectatorClientEndFrame( ent ); - return; - } - - pers = &ent->client->pers; - - // - // If the end of unit layout is displayed, don't give - // the player any normal movement attributes - // - if( level.intermissiontime ) - return; - - // burn from lava, etc - P_WorldEffects( ent ); - - // apply all the damage taken this frame - P_DamageFeedback( ent ); - - // add the EF_CONNECTION flag if we haven't gotten commands recently - if( level.time - ent->client->lastCmdTime > 1000 ) - ent->s.eFlags |= EF_CONNECTION; - else - ent->s.eFlags &= ~EF_CONNECTION; - - ent->client->ps.stats[ STAT_HEALTH ] = ent->health; // FIXME: get rid of ent->health... - - G_SetClientSound( ent ); - - // set the latest infor - if( g_smoothClients.integer ) - BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue ); - else - BG_PlayerStateToEntityState( &ent->client->ps, &ent->s, qtrue ); - - SendPendingPredictableEvents( &ent->client->ps ); -} - - diff --git a/src/game/g_buildable.c b/src/game/g_buildable.c deleted file mode 100644 index 083e0662..00000000 --- a/src/game/g_buildable.c +++ /dev/null @@ -1,2987 +0,0 @@ -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "g_local.h" - -/* -================ -G_setBuildableAnim - -Triggers an animation client side -================ -*/ -void G_setBuildableAnim( gentity_t *ent, buildableAnimNumber_t anim, qboolean force ) -{ - int localAnim = anim; - - if( force ) - localAnim |= ANIM_FORCEBIT; - - localAnim |= ( ( ent->s.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ); - - ent->s.legsAnim = localAnim; -} - -/* -================ -G_setIdleBuildableAnim - -Set the animation to use whilst no other animations are running -================ -*/ -void G_setIdleBuildableAnim( gentity_t *ent, buildableAnimNumber_t anim ) -{ - ent->s.torsoAnim = anim; -} - -/* -=============== -G_CheckSpawnPoint - -Check if a spawn at a specified point is valid -=============== -*/ -gentity_t *G_CheckSpawnPoint( int spawnNum, vec3_t origin, vec3_t normal, - buildable_t spawn, vec3_t spawnOrigin ) -{ - float displacement; - vec3_t mins, maxs; - vec3_t cmins, cmaxs; - vec3_t localOrigin; - trace_t tr; - - BG_FindBBoxForBuildable( spawn, mins, maxs ); - - if( spawn == BA_A_SPAWN ) - { - VectorSet( cmins, -MAX_ALIEN_BBOX, -MAX_ALIEN_BBOX, -MAX_ALIEN_BBOX ); - VectorSet( cmaxs, MAX_ALIEN_BBOX, MAX_ALIEN_BBOX, MAX_ALIEN_BBOX ); - - displacement = ( maxs[ 2 ] + MAX_ALIEN_BBOX ) * M_ROOT3; - VectorMA( origin, displacement, normal, localOrigin ); - - trap_Trace( &tr, origin, NULL, NULL, localOrigin, spawnNum, MASK_SHOT ); - - if( tr.entityNum != ENTITYNUM_NONE ) - return &g_entities[ tr.entityNum ]; - - trap_Trace( &tr, localOrigin, cmins, cmaxs, localOrigin, -1, MASK_SHOT ); - - if( tr.entityNum == ENTITYNUM_NONE ) - { - if( spawnOrigin != NULL ) - VectorCopy( localOrigin, spawnOrigin ); - - return NULL; - } - else - return &g_entities[ tr.entityNum ]; - } - else if( spawn == BA_H_SPAWN ) - { - BG_FindBBoxForClass( PCL_HUMAN, cmins, cmaxs, NULL, NULL, NULL ); - - VectorCopy( origin, localOrigin ); - localOrigin[ 2 ] += maxs[ 2 ] + fabs( cmins[ 2 ] ) + 1.0f; - - trap_Trace( &tr, origin, NULL, NULL, localOrigin, spawnNum, MASK_SHOT ); - - if( tr.entityNum != ENTITYNUM_NONE ) - return &g_entities[ tr.entityNum ]; - - trap_Trace( &tr, localOrigin, cmins, cmaxs, localOrigin, -1, MASK_SHOT ); - - if( tr.entityNum == ENTITYNUM_NONE ) - { - if( spawnOrigin != NULL ) - VectorCopy( localOrigin, spawnOrigin ); - - return NULL; - } - else - return &g_entities[ tr.entityNum ]; - } - - return NULL; -} - -/* -================ -G_NumberOfDependants - -Return number of entities that depend on this one -================ -*/ -static int G_NumberOfDependants( gentity_t *self ) -{ - int i, n = 0; - gentity_t *ent; - - for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ ) - { - if( ent->s.eType != ET_BUILDABLE ) - continue; - - if( ent->parentNode == self ) - n++; - } - - return n; -} - -#define POWER_REFRESH_TIME 2000 - -/* -================ -findPower - -attempt to find power for self, return qtrue if successful -================ -*/ -static qboolean findPower( gentity_t *self ) -{ - int i; - gentity_t *ent; - gentity_t *closestPower = NULL; - int distance = 0; - int minDistance = 10000; - vec3_t temp_v; - qboolean foundPower = qfalse; - - if( self->biteam != BIT_HUMANS ) - return qfalse; - - //reactor is always powered - if( self->s.modelindex == BA_H_REACTOR ) - return qtrue; - - //if this already has power then stop now - if( self->parentNode && self->parentNode->powered ) - return qtrue; - - //reset parent - self->parentNode = NULL; - - //iterate through entities - for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ ) - { - if( ent->s.eType != ET_BUILDABLE ) - continue; - - //if entity is a power item calculate the distance to it - if( ( ent->s.modelindex == BA_H_REACTOR || ent->s.modelindex == BA_H_REPEATER ) && - ent->spawned ) - { - VectorSubtract( self->s.origin, ent->s.origin, temp_v ); - distance = VectorLength( temp_v ); - if( distance < minDistance && ent->powered ) - { - closestPower = ent; - minDistance = distance; - foundPower = qtrue; - } - } - } - - //if there were no power items nearby give up - if( !foundPower ) - return qfalse; - - //bleh - if( ( closestPower->s.modelindex == BA_H_REACTOR && ( minDistance <= REACTOR_BASESIZE ) ) || - ( closestPower->s.modelindex == BA_H_REPEATER && ( minDistance <= REPEATER_BASESIZE ) && - closestPower->powered ) ) - { - self->parentNode = closestPower; - - return qtrue; - } - else - return qfalse; -} - -/* -================ -G_isPower - -Simple wrapper to findPower to check if a location has power -================ -*/ -qboolean G_isPower( vec3_t origin ) -{ - gentity_t dummy; - - dummy.parentNode = NULL; - dummy.biteam = BIT_HUMANS; - VectorCopy( origin, dummy.s.origin ); - - return findPower( &dummy ); -} - -/* -================ -findDCC - -attempt to find a controlling DCC for self, return qtrue if successful -================ -*/ -static qboolean findDCC( gentity_t *self ) -{ - int i; - gentity_t *ent; - gentity_t *closestDCC = NULL; - int distance = 0; - int minDistance = 10000; - vec3_t temp_v; - qboolean foundDCC = qfalse; - - if( self->biteam != BIT_HUMANS ) - return qfalse; - - //if this already has dcc then stop now - if( self->dccNode && self->dccNode->powered ) - return qtrue; - - //reset parent - self->dccNode = NULL; - - //iterate through entities - for( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ ) - { - if( ent->s.eType != ET_BUILDABLE ) - continue; - - //if entity is a dcc calculate the distance to it - if( ent->s.modelindex == BA_H_DCC && ent->spawned ) - { - VectorSubtract( self->s.origin, ent->s.origin, temp_v ); - distance = VectorLength( temp_v ); - if( distance < minDistance && ent->powered ) - { - closestDCC = ent; - minDistance = distance; - foundDCC = qtrue; - } - } - } - - //if there were no power items nearby give up - if( !foundDCC ) - return qfalse; - - self->dccNode = closestDCC; - - return qtrue; -} - -/* -================ -G_isDCC - -simple wrapper to findDCC to check for a dcc -================ -*/ -qboolean G_isDCC( void ) -{ - gentity_t dummy; - - dummy.dccNode = NULL; - dummy.biteam = BIT_HUMANS; - - return findDCC( &dummy ); -} - -/* -================ -findOvermind - -Attempt to find an overmind for self -================ -*/ -static qboolean findOvermind( gentity_t *self ) -{ - int i; - gentity_t *ent; - - if( self->biteam != BIT_ALIENS ) - return qfalse; - - //if this already has overmind then stop now - if( self->overmindNode && self->overmindNode->health > 0 ) - return qtrue; - - //reset parent - self->overmindNode = NULL; - - //iterate through entities - for( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ ) - { - if( ent->s.eType != ET_BUILDABLE ) - continue; - - //if entity is an overmind calculate the distance to it - if( ent->s.modelindex == BA_A_OVERMIND && ent->spawned && ent->health > 0 ) - { - self->overmindNode = ent; - return qtrue; - } - } - - return qfalse; -} - -/* -================ -G_isOvermind - -Simple wrapper to findOvermind to check if a location has an overmind -================ -*/ -qboolean G_isOvermind( void ) -{ - gentity_t dummy; - - dummy.overmindNode = NULL; - dummy.biteam = BIT_ALIENS; - - return findOvermind( &dummy ); -} - -/* -================ -findCreep - -attempt to find creep for self, return qtrue if successful -================ -*/ -static qboolean findCreep( gentity_t *self ) -{ - int i; - gentity_t *ent; - gentity_t *closestSpawn = NULL; - int distance = 0; - int minDistance = 10000; - vec3_t temp_v; - - //don't check for creep if flying through the air - if( self->s.groundEntityNum == -1 ) - return qtrue; - - //if self does not have a parentNode or it's parentNode is invalid find a new one - if( ( self->parentNode == NULL ) || !self->parentNode->inuse ) - { - for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ ) - { - if( ent->s.eType != ET_BUILDABLE ) - continue; - - if( ( ent->s.modelindex == BA_A_SPAWN || ent->s.modelindex == BA_A_OVERMIND ) && - ent->spawned ) - { - VectorSubtract( self->s.origin, ent->s.origin, temp_v ); - distance = VectorLength( temp_v ); - if( distance < minDistance ) - { - closestSpawn = ent; - minDistance = distance; - } - } - } - - if( minDistance <= CREEP_BASESIZE ) - { - self->parentNode = closestSpawn; - return qtrue; - } - else - return qfalse; - } - - //if we haven't returned by now then we must already have a valid parent - return qtrue; -} - -/* -================ -isCreep - -simple wrapper to findCreep to check if a location has creep -================ -*/ -static qboolean isCreep( vec3_t origin ) -{ - gentity_t dummy; - - dummy.parentNode = NULL; - VectorCopy( origin, dummy.s.origin ); - - return findCreep( &dummy ); -} - -/* -================ -creepSlow - -Set any nearby humans' SS_CREEPSLOWED flag -================ -*/ -static void creepSlow( gentity_t *self ) -{ - int entityList[ MAX_GENTITIES ]; - vec3_t range; - vec3_t mins, maxs; - int i, num; - gentity_t *enemy; - buildable_t buildable = self->s.modelindex; - float creepSize = (float)BG_FindCreepSizeForBuildable( buildable ); - - VectorSet( range, creepSize, creepSize, creepSize ); - - VectorAdd( self->s.origin, range, maxs ); - VectorSubtract( self->s.origin, range, mins ); - - //find humans - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - for( i = 0; i < num; i++ ) - { - enemy = &g_entities[ entityList[ i ] ]; - - if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS && - enemy->client->ps.groundEntityNum != ENTITYNUM_NONE && - G_Visible( self, enemy ) ) - { - enemy->client->ps.stats[ STAT_STATE ] |= SS_CREEPSLOWED; - enemy->client->lastCreepSlowTime = level.time; - } - } -} - -/* -================ -nullDieFunction - -hack to prevent compilers complaining about function pointer -> NULL conversion -================ -*/ -static void nullDieFunction( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ -} - -/* -================ -freeBuildable -================ -*/ -static void freeBuildable( gentity_t *self ) -{ - G_FreeEntity( self ); -} - - -//================================================================================== - - - -/* -================ -A_CreepRecede - -Called when an alien spawn dies -================ -*/ -void A_CreepRecede( gentity_t *self ) -{ - //if the creep just died begin the recession - if( !( self->s.eFlags & EF_DEAD ) ) - { - self->s.eFlags |= EF_DEAD; - G_AddEvent( self, EV_BUILD_DESTROY, 0 ); - - if( self->spawned ) - self->s.time = -level.time; - else - self->s.time = -( level.time - - (int)( (float)CREEP_SCALEDOWN_TIME * - ( 1.0f - ( (float)( level.time - self->buildTime ) / - (float)BG_FindBuildTimeForBuildable( self->s.modelindex ) ) ) ) ); - } - - //creep is still receeding - if( ( self->timestamp + 10000 ) > level.time ) - self->nextthink = level.time + 500; - else //creep has died - G_FreeEntity( self ); -} - - - - -//================================================================================== - - - - -/* -================ -ASpawn_Melt - -Called when an alien spawn dies -================ -*/ -void ASpawn_Melt( gentity_t *self ) -{ - G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS ); - - //start creep recession - if( !( self->s.eFlags & EF_DEAD ) ) - { - self->s.eFlags |= EF_DEAD; - G_AddEvent( self, EV_BUILD_DESTROY, 0 ); - - if( self->spawned ) - self->s.time = -level.time; - else - self->s.time = -( level.time - - (int)( (float)CREEP_SCALEDOWN_TIME * - ( 1.0f - ( (float)( level.time - self->buildTime ) / - (float)BG_FindBuildTimeForBuildable( self->s.modelindex ) ) ) ) ); - } - - //not dead yet - if( ( self->timestamp + 10000 ) > level.time ) - self->nextthink = level.time + 500; - else //dead now - G_FreeEntity( self ); -} - -/* -================ -ASpawn_Blast - -Called when an alien spawn dies -================ -*/ -void ASpawn_Blast( gentity_t *self ) -{ - vec3_t dir; - - VectorCopy( self->s.origin2, dir ); - - //do a bit of radius damage - G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS ); - - //pretty events and item cleanup - self->s.eFlags |= EF_NODRAW; //don't draw the model once it's destroyed - G_AddEvent( self, EV_ALIEN_BUILDABLE_EXPLOSION, DirToByte( dir ) ); - self->timestamp = level.time; - self->think = ASpawn_Melt; - self->nextthink = level.time + 500; //wait .5 seconds before damaging others - - self->r.contents = 0; //stop collisions... - trap_LinkEntity( self ); //...requires a relink -} - -/* -================ -ASpawn_Die - -Called when an alien spawn dies -================ -*/ -void ASpawn_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ - G_setBuildableAnim( self, BANIM_DESTROY1, qtrue ); - G_setIdleBuildableAnim( self, BANIM_DESTROYED ); - - self->die = nullDieFunction; - self->think = ASpawn_Blast; - - if( self->spawned ) - self->nextthink = level.time + 5000; - else - self->nextthink = level.time; //blast immediately - - self->s.eFlags &= ~EF_FIRING; //prevent any firing effects - - if( attacker && attacker->client && attacker->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - if( self->s.modelindex == BA_A_OVERMIND ) - G_AddCreditToClient( attacker->client, OVERMIND_VALUE, qtrue ); - else if( self->s.modelindex == BA_A_SPAWN ) - G_AddCreditToClient( attacker->client, ASPAWN_VALUE, qtrue ); - } -} - -/* -================ -ASpawn_Think - -think function for Alien Spawn -================ -*/ -void ASpawn_Think( gentity_t *self ) -{ - gentity_t *ent; - - if( self->spawned ) - { - //only suicide if at rest - if( self->s.groundEntityNum ) - { - if( ( ent = G_CheckSpawnPoint( self->s.number, self->s.origin, - self->s.origin2, BA_A_SPAWN, NULL ) ) != NULL ) - { - if( ent->s.eType == ET_BUILDABLE || ent->s.number == ENTITYNUM_WORLD || - ent->s.eType == ET_MOVER ) - { - G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE ); - return; - } - - if( ent->s.eType == ET_CORPSE ) - G_FreeEntity( ent ); //quietly remove - } - } - } - - creepSlow( self ); - - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); -} - -/* -================ -ASpawn_Pain - -pain function for Alien Spawn -================ -*/ -void ASpawn_Pain( gentity_t *self, gentity_t *attacker, int damage ) -{ - G_setBuildableAnim( self, BANIM_PAIN1, qfalse ); -} - - - - - -//================================================================================== - - - - - -#define OVERMIND_ATTACK_PERIOD 10000 -#define OVERMIND_DYING_PERIOD 5000 -#define OVERMIND_SPAWNS_PERIOD 30000 - -/* -================ -AOvermind_Think - -Think function for Alien Overmind -================ -*/ -void AOvermind_Think( gentity_t *self ) -{ - int entityList[ MAX_GENTITIES ]; - vec3_t range = { OVERMIND_ATTACK_RANGE, OVERMIND_ATTACK_RANGE, OVERMIND_ATTACK_RANGE }; - vec3_t mins, maxs; - int i, num; - gentity_t *enemy; - - VectorAdd( self->s.origin, range, maxs ); - VectorSubtract( self->s.origin, range, mins ); - - if( self->spawned && ( self->health > 0 ) ) - { - //do some damage - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - for( i = 0; i < num; i++ ) - { - enemy = &g_entities[ entityList[ i ] ]; - - if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - self->timestamp = level.time; - G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage, - self->splashRadius, self, MOD_OVERMIND, PTE_ALIENS ); - G_setBuildableAnim( self, BANIM_ATTACK1, qfalse ); - } - } - - //low on spawns - if( level.numAlienSpawns <= 0 && level.time > self->overmindSpawnsTimer ) - { - self->overmindSpawnsTimer = level.time + OVERMIND_SPAWNS_PERIOD; - G_BroadcastEvent( EV_OVERMIND_SPAWNS, 0 ); - } - - //overmind dying - if( self->health < ( OVERMIND_HEALTH / 10.0f ) && level.time > self->overmindDyingTimer ) - { - self->overmindDyingTimer = level.time + OVERMIND_DYING_PERIOD; - G_BroadcastEvent( EV_OVERMIND_DYING, 0 ); - } - - //overmind under attack - if( self->health < self->lastHealth && level.time > self->overmindAttackTimer ) - { - self->overmindAttackTimer = level.time + OVERMIND_ATTACK_PERIOD; - G_BroadcastEvent( EV_OVERMIND_ATTACK, 0 ); - } - - self->lastHealth = self->health; - } - else - self->overmindSpawnsTimer = level.time + OVERMIND_SPAWNS_PERIOD; - - creepSlow( self ); - - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); -} - - - - - - -//================================================================================== - - - - - -/* -================ -ABarricade_Pain - -pain function for Alien Spawn -================ -*/ -void ABarricade_Pain( gentity_t *self, gentity_t *attacker, int damage ) -{ - if( rand( ) % 1 ) - G_setBuildableAnim( self, BANIM_PAIN1, qfalse ); - else - G_setBuildableAnim( self, BANIM_PAIN2, qfalse ); -} - -/* -================ -ABarricade_Blast - -Called when an alien spawn dies -================ -*/ -void ABarricade_Blast( gentity_t *self ) -{ - vec3_t dir; - - VectorCopy( self->s.origin2, dir ); - - //do a bit of radius damage - G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS ); - - //pretty events and item cleanup - self->s.eFlags |= EF_NODRAW; //don't draw the model once its destroyed - G_AddEvent( self, EV_ALIEN_BUILDABLE_EXPLOSION, DirToByte( dir ) ); - self->timestamp = level.time; - self->think = A_CreepRecede; - self->nextthink = level.time + 500; //wait .5 seconds before damaging others - - self->r.contents = 0; //stop collisions... - trap_LinkEntity( self ); //...requires a relink -} - -/* -================ -ABarricade_Die - -Called when an alien spawn dies -================ -*/ -void ABarricade_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ - G_setBuildableAnim( self, BANIM_DESTROY1, qtrue ); - G_setIdleBuildableAnim( self, BANIM_DESTROYED ); - - self->die = nullDieFunction; - self->think = ABarricade_Blast; - self->s.eFlags &= ~EF_FIRING; //prevent any firing effects - - if( self->spawned ) - self->nextthink = level.time + 5000; - else - self->nextthink = level.time; //blast immediately -} - -/* -================ -ABarricade_Think - -Think function for Alien Barricade -================ -*/ -void ABarricade_Think( gentity_t *self ) -{ - //if there is no creep nearby die - if( !findCreep( self ) ) - { - G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE ); - return; - } - - creepSlow( self ); - - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); -} - - - - -//================================================================================== - - - - -void AAcidTube_Think( gentity_t *self ); - -/* -================ -AAcidTube_Damage - -Damage function for Alien Acid Tube -================ -*/ -void AAcidTube_Damage( gentity_t *self ) -{ - if( self->spawned ) - { - if( !( self->s.eFlags & EF_FIRING ) ) - { - self->s.eFlags |= EF_FIRING; - G_AddEvent( self, EV_ALIEN_ACIDTUBE, DirToByte( self->s.origin2 ) ); - } - - if( ( self->timestamp + ACIDTUBE_REPEAT ) > level.time ) - self->think = AAcidTube_Damage; - else - { - self->think = AAcidTube_Think; - self->s.eFlags &= ~EF_FIRING; - } - - //do some damage - G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS ); - } - - creepSlow( self ); - - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); -} - -/* -================ -AAcidTube_Think - -Think function for Alien Acid Tube -================ -*/ -void AAcidTube_Think( gentity_t *self ) -{ - int entityList[ MAX_GENTITIES ]; - vec3_t range = { ACIDTUBE_RANGE, ACIDTUBE_RANGE, ACIDTUBE_RANGE }; - vec3_t mins, maxs; - int i, num; - gentity_t *enemy; - - VectorAdd( self->s.origin, range, maxs ); - VectorSubtract( self->s.origin, range, mins ); - - //if there is no creep nearby die - if( !findCreep( self ) ) - { - G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE ); - return; - } - - if( self->spawned && findOvermind( self ) ) - { - //do some damage - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - for( i = 0; i < num; i++ ) - { - enemy = &g_entities[ entityList[ i ] ]; - - if( !G_Visible( self, enemy ) ) - continue; - - if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - self->timestamp = level.time; - self->think = AAcidTube_Damage; - self->nextthink = level.time + 100; - G_setBuildableAnim( self, BANIM_ATTACK1, qfalse ); - return; - } - } - } - - creepSlow( self ); - - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); -} - - - - -//================================================================================== - - - - -/* -================ -AHive_Think - -Think function for Alien Hive -================ -*/ -void AHive_Think( gentity_t *self ) -{ - int entityList[ MAX_GENTITIES ]; - vec3_t range = { ACIDTUBE_RANGE, ACIDTUBE_RANGE, ACIDTUBE_RANGE }; - vec3_t mins, maxs; - int i, num; - gentity_t *enemy; - vec3_t dirToTarget; - - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); - - VectorAdd( self->s.origin, range, maxs ); - VectorSubtract( self->s.origin, range, mins ); - - //if there is no creep nearby die - if( !findCreep( self ) ) - { - G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE ); - return; - } - - if( self->timestamp < level.time ) - self->active = qfalse; //nothing has returned in HIVE_REPEAT seconds, forget about it - - if( self->spawned && !self->active && findOvermind( self ) ) - { - //do some damage - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - for( i = 0; i < num; i++ ) - { - enemy = &g_entities[ entityList[ i ] ]; - - if( enemy->health <= 0 ) - continue; - - if( !G_Visible( self, enemy ) ) - continue; - - if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - self->active = qtrue; - self->target_ent = enemy; - self->timestamp = level.time + HIVE_REPEAT; - - VectorSubtract( enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget ); - VectorNormalize( dirToTarget ); - vectoangles( dirToTarget, self->turretAim ); - - //fire at target - FireWeapon( self ); - G_setBuildableAnim( self, BANIM_ATTACK1, qfalse ); - return; - } - } - } - - creepSlow( self ); -} - - - - -//================================================================================== - - - - -#define HOVEL_TRACE_DEPTH 128.0f - -/* -================ -AHovel_Blocked - -Is this hovel entrance blocked? -================ -*/ -qboolean AHovel_Blocked( gentity_t *hovel, gentity_t *player, qboolean provideExit ) -{ - vec3_t forward, normal, origin, start, end, angles, hovelMaxs; - vec3_t mins, maxs; - float displacement; - trace_t tr; - - BG_FindBBoxForBuildable( BA_A_HOVEL, NULL, hovelMaxs ); - BG_FindBBoxForClass( player->client->ps.stats[ STAT_PCLASS ], - mins, maxs, NULL, NULL, NULL ); - - VectorCopy( hovel->s.origin2, normal ); - AngleVectors( hovel->s.angles, forward, NULL, NULL ); - VectorInverse( forward ); - - displacement = VectorMaxComponent( maxs ) * M_ROOT3 + - VectorMaxComponent( hovelMaxs ) * M_ROOT3 + 1.0f; - - VectorMA( hovel->s.origin, displacement, forward, origin ); - vectoangles( forward, angles ); - - VectorMA( origin, HOVEL_TRACE_DEPTH, normal, start ); - - //compute a place up in the air to start the real trace - trap_Trace( &tr, origin, mins, maxs, start, player->s.number, MASK_PLAYERSOLID ); - VectorMA( origin, ( HOVEL_TRACE_DEPTH * tr.fraction ) - 1.0f, normal, start ); - VectorMA( origin, -HOVEL_TRACE_DEPTH, normal, end ); - - trap_Trace( &tr, start, mins, maxs, end, player->s.number, MASK_PLAYERSOLID ); - - if( tr.startsolid ) - return qtrue; - - VectorCopy( tr.endpos, origin ); - - trap_Trace( &tr, origin, mins, maxs, origin, player->s.number, MASK_PLAYERSOLID ); - - if( provideExit ) - { - G_SetOrigin( player, origin ); - VectorCopy( origin, player->client->ps.origin ); - VectorCopy( vec3_origin, player->client->ps.velocity ); - SetClientViewAngle( player, angles ); - } - - if( tr.fraction < 1.0f ) - return qtrue; - else - return qfalse; -} - -/* -================ -APropHovel_Blocked - -Wrapper to test a hovel placement for validity -================ -*/ -static qboolean APropHovel_Blocked( vec3_t origin, vec3_t angles, vec3_t normal, - gentity_t *player ) -{ - gentity_t hovel; - - VectorCopy( origin, hovel.s.origin ); - VectorCopy( angles, hovel.s.angles ); - VectorCopy( normal, hovel.s.origin2 ); - - return AHovel_Blocked( &hovel, player, qfalse ); -} - -/* -================ -AHovel_Use - -Called when an alien uses a hovel -================ -*/ -void AHovel_Use( gentity_t *self, gentity_t *other, gentity_t *activator ) -{ - vec3_t hovelOrigin, hovelAngles, inverseNormal; - - if( self->spawned && findOvermind( self ) ) - { - if( self->active ) - { - //this hovel is in use - G_TriggerMenu( activator->client->ps.clientNum, MN_A_HOVEL_OCCUPIED ); - } - else if( ( ( activator->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0 ) || - ( activator->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_BUILDER0_UPG ) ) && - activator->health > 0 && self->health > 0 ) - { - if( AHovel_Blocked( self, activator, qfalse ) ) - { - //you can get in, but you can't get out - G_TriggerMenu( activator->client->ps.clientNum, MN_A_HOVEL_BLOCKED ); - return; - } - - self->active = qtrue; - G_setBuildableAnim( self, BANIM_ATTACK1, qfalse ); - - //prevent lerping - activator->client->ps.eFlags ^= EF_TELEPORT_BIT; - activator->client->ps.eFlags |= EF_NODRAW; - - activator->client->ps.stats[ STAT_STATE ] |= SS_HOVELING; - activator->client->hovel = self; - self->builder = activator; - - VectorCopy( self->s.pos.trBase, hovelOrigin ); - VectorMA( hovelOrigin, 128.0f, self->s.origin2, hovelOrigin ); - - VectorCopy( self->s.origin2, inverseNormal ); - VectorInverse( inverseNormal ); - vectoangles( inverseNormal, hovelAngles ); - - VectorCopy( activator->s.pos.trBase, activator->client->hovelOrigin ); - - G_SetOrigin( activator, hovelOrigin ); - VectorCopy( hovelOrigin, activator->client->ps.origin ); - SetClientViewAngle( activator, hovelAngles ); - } - } -} - - -/* -================ -AHovel_Think - -Think for alien hovel -================ -*/ -void AHovel_Think( gentity_t *self ) -{ - if( self->spawned ) - { - if( self->active ) - G_setIdleBuildableAnim( self, BANIM_IDLE2 ); - else - G_setIdleBuildableAnim( self, BANIM_IDLE1 ); - } - - creepSlow( self ); - - self->nextthink = level.time + 200; -} - -/* -================ -AHovel_Die - -Die for alien hovel -================ -*/ -void AHovel_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ - vec3_t dir; - - VectorCopy( self->s.origin2, dir ); - - //do a bit of radius damage - G_SelectiveRadiusDamage( self->s.pos.trBase, self, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath, PTE_ALIENS ); - - //pretty events and item cleanup - self->s.eFlags |= EF_NODRAW; //don't draw the model once its destroyed - G_AddEvent( self, EV_ALIEN_BUILDABLE_EXPLOSION, DirToByte( dir ) ); - self->s.eFlags &= ~EF_FIRING; //prevent any firing effects - self->timestamp = level.time; - self->think = ASpawn_Melt; - self->nextthink = level.time + 500; //wait .5 seconds before damaging others - - //if the hovel is occupied free the occupant - if( self->active ) - { - gentity_t *builder = self->builder; - vec3_t newOrigin; - vec3_t newAngles; - - VectorCopy( self->s.angles, newAngles ); - newAngles[ ROLL ] = 0; - - VectorCopy( self->s.origin, newOrigin ); - VectorMA( newOrigin, 1.0f, self->s.origin2, newOrigin ); - - //prevent lerping - builder->client->ps.eFlags ^= EF_TELEPORT_BIT; - builder->client->ps.eFlags &= ~EF_NODRAW; - - G_SetOrigin( builder, newOrigin ); - VectorCopy( newOrigin, builder->client->ps.origin ); - SetClientViewAngle( builder, newAngles ); - - //client leaves hovel - builder->client->ps.stats[ STAT_STATE ] &= ~SS_HOVELING; - } - - self->r.contents = 0; //stop collisions... - trap_LinkEntity( self ); //...requires a relink -} - - - - - -//================================================================================== - - - - -/* -================ -ABooster_Touch - -Called when an alien touches a booster -================ -*/ -void ABooster_Touch( gentity_t *self, gentity_t *other, trace_t *trace ) -{ - gclient_t *client = other->client; - - if( !self->spawned ) - return; - - if( !findOvermind( self ) ) - return; - - if( !client ) - return; - - if( client && client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - return; - - //only allow boostage once every 30 seconds - if( client->lastBoostedTime + BOOSTER_INTERVAL > level.time ) - return; - - if( !( client->ps.stats[ STAT_STATE ] & SS_BOOSTED ) ) - { - client->ps.stats[ STAT_STATE ] |= SS_BOOSTED; - client->lastBoostedTime = level.time; - } -} - - - - -//================================================================================== - -#define TRAPPER_ACCURACY 10 // lower is better - -/* -================ -ATrapper_FireOnEnemy - -Used by ATrapper_Think to fire at enemy -================ -*/ -void ATrapper_FireOnEnemy( gentity_t *self, int firespeed, float range ) -{ - gentity_t *enemy = self->enemy; - vec3_t dirToTarget; - vec3_t halfAcceleration, thirdJerk; - float distanceToTarget = BG_FindRangeForBuildable( self->s.modelindex ); - int lowMsec = 0; - int highMsec = (int)( ( - ( ( distanceToTarget * LOCKBLOB_SPEED ) + - ( distanceToTarget * BG_FindSpeedForClass( enemy->client->ps.stats[ STAT_PCLASS ] ) ) ) / - ( LOCKBLOB_SPEED * LOCKBLOB_SPEED ) ) * 1000.0f ); - - VectorScale( enemy->acceleration, 1.0f / 2.0f, halfAcceleration ); - VectorScale( enemy->jerk, 1.0f / 3.0f, thirdJerk ); - - // highMsec and lowMsec can only move toward - // one another, so the loop must terminate - while( highMsec - lowMsec > TRAPPER_ACCURACY ) - { - int partitionMsec = ( highMsec + lowMsec ) / 2; - float time = (float)partitionMsec / 1000.0f; - float projectileDistance = LOCKBLOB_SPEED * time; - - VectorMA( enemy->s.pos.trBase, time, enemy->s.pos.trDelta, dirToTarget ); - VectorMA( dirToTarget, time * time, halfAcceleration, dirToTarget ); - VectorMA( dirToTarget, time * time * time, thirdJerk, dirToTarget ); - VectorSubtract( dirToTarget, self->s.pos.trBase, dirToTarget ); - distanceToTarget = VectorLength( dirToTarget ); - - if( projectileDistance < distanceToTarget ) - lowMsec = partitionMsec; - else if( projectileDistance > distanceToTarget ) - highMsec = partitionMsec; - else if( projectileDistance == distanceToTarget ) - break; // unlikely to happen - } - - VectorNormalize( dirToTarget ); - vectoangles( dirToTarget, self->turretAim ); - - //fire at target - FireWeapon( self ); - G_setBuildableAnim( self, BANIM_ATTACK1, qfalse ); - self->count = level.time + firespeed; -} - -/* -================ -ATrapper_CheckTarget - -Used by ATrapper_Think to check enemies for validity -================ -*/ -qboolean ATrapper_CheckTarget( gentity_t *self, gentity_t *target, int range ) -{ - vec3_t distance; - trace_t trace; - - if( !target ) // Do we have a target? - return qfalse; - if( !target->inuse ) // Does the target still exist? - return qfalse; - if( target == self ) // is the target us? - return qfalse; - if( !target->client ) // is the target a bot or player? - return qfalse; - if( target->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) // one of us? - return qfalse; - if( target->client->sess.sessionTeam == TEAM_SPECTATOR ) // is the target alive? - return qfalse; - if( target->health <= 0 ) // is the target still alive? - return qfalse; - if( target->client->ps.stats[ STAT_STATE ] & SS_BLOBLOCKED ) // locked? - return qfalse; - - VectorSubtract( target->r.currentOrigin, self->r.currentOrigin, distance ); - if( VectorLength( distance ) > range ) // is the target within range? - return qfalse; - - //only allow a narrow field of "vision" - VectorNormalize( distance ); //is now direction of target - if( DotProduct( distance, self->s.origin2 ) < LOCKBLOB_DOT ) - return qfalse; - - trap_Trace( &trace, self->s.pos.trBase, NULL, NULL, target->s.pos.trBase, self->s.number, MASK_SHOT ); - if ( trace.contents & CONTENTS_SOLID ) // can we see the target? - return qfalse; - - return qtrue; -} - -/* -================ -ATrapper_FindEnemy - -Used by ATrapper_Think to locate enemy gentities -================ -*/ -void ATrapper_FindEnemy( gentity_t *ent, int range ) -{ - gentity_t *target; - - //iterate through entities - for( target = g_entities; target < &g_entities[ level.num_entities ]; target++ ) - { - //if target is not valid keep searching - if( !ATrapper_CheckTarget( ent, target, range ) ) - continue; - - //we found a target - ent->enemy = target; - return; - } - - //couldn't find a target - ent->enemy = NULL; -} - -/* -================ -ATrapper_Think - -think function for Alien Defense -================ -*/ -void ATrapper_Think( gentity_t *self ) -{ - int range = BG_FindRangeForBuildable( self->s.modelindex ); - int firespeed = BG_FindFireSpeedForBuildable( self->s.modelindex ); - - creepSlow( self ); - - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); - - //if there is no creep nearby die - if( !findCreep( self ) ) - { - G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE ); - return; - } - - if( self->spawned && findOvermind( self ) ) - { - //if the current target is not valid find a new one - if( !ATrapper_CheckTarget( self, self->enemy, range ) ) - ATrapper_FindEnemy( self, range ); - - //if a new target cannot be found don't do anything - if( !self->enemy ) - return; - - //if we are pointing at our target and we can fire shoot it - if( self->count < level.time ) - ATrapper_FireOnEnemy( self, firespeed, range ); - } -} - - - -//================================================================================== - - - -/* -================ -HRepeater_Think - -Think for human power repeater -================ -*/ -void HRepeater_Think( gentity_t *self ) -{ - int i; - qboolean reactor = qfalse; - gentity_t *ent; - - if( self->spawned ) - { - //iterate through entities - for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ ) - { - if( ent->s.eType != ET_BUILDABLE ) - continue; - - if( ent->s.modelindex == BA_H_REACTOR && ent->spawned ) - reactor = qtrue; - } - } - - if( G_NumberOfDependants( self ) == 0 ) - { - //if no dependants for x seconds then disappear - if( self->count < 0 ) - self->count = level.time; - else if( self->count > 0 && ( ( level.time - self->count ) > REPEATER_INACTIVE_TIME ) ) - G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE ); - } - else - self->count = -1; - - self->powered = reactor; - - self->nextthink = level.time + POWER_REFRESH_TIME; -} - -/* -================ -HRepeater_Use - -Use for human power repeater -================ -*/ -void HRepeater_Use( gentity_t *self, gentity_t *other, gentity_t *activator ) -{ - if( self->health <= 0 ) - return; - - if( !self->spawned ) - return; - - if( other ) - G_GiveClientMaxAmmo( other, qtrue ); -} - - -#define DCC_ATTACK_PERIOD 10000 - -/* -================ -HReactor_Think - -Think function for Human Reactor -================ -*/ -void HReactor_Think( gentity_t *self ) -{ - int entityList[ MAX_GENTITIES ]; - vec3_t range = { REACTOR_ATTACK_RANGE, REACTOR_ATTACK_RANGE, REACTOR_ATTACK_RANGE }; - vec3_t mins, maxs; - int i, num; - gentity_t *enemy, *tent; - - VectorAdd( self->s.origin, range, maxs ); - VectorSubtract( self->s.origin, range, mins ); - - if( self->spawned && ( self->health > 0 ) ) - { - //do some damage - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - for( i = 0; i < num; i++ ) - { - enemy = &g_entities[ entityList[ i ] ]; - - if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - self->timestamp = level.time; - G_SelectiveRadiusDamage( self->s.pos.trBase, self, REACTOR_ATTACK_DAMAGE, - REACTOR_ATTACK_RANGE, self, MOD_REACTOR, PTE_HUMANS ); - - tent = G_TempEntity( enemy->s.pos.trBase, EV_TESLATRAIL ); - - VectorCopy( self->s.pos.trBase, tent->s.origin2 ); - - tent->s.generic1 = self->s.number; //src - tent->s.clientNum = enemy->s.number; //dest - } - } - - //reactor under attack - if( self->health < self->lastHealth && - level.time > level.humanBaseAttackTimer && G_isDCC( ) ) - { - level.humanBaseAttackTimer = level.time + DCC_ATTACK_PERIOD; - G_BroadcastEvent( EV_DCC_ATTACK, 0 ); - } - - self->lastHealth = self->health; - } - - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); -} - -//================================================================================== - - - -/* -================ -HArmoury_Activate - -Called when a human activates an Armoury -================ -*/ -void HArmoury_Activate( gentity_t *self, gentity_t *other, gentity_t *activator ) -{ - if( self->spawned ) - { - //only humans can activate this - if( activator->client->ps.stats[ STAT_PTEAM ] != PTE_HUMANS ) - return; - - //if this is powered then call the armoury menu - if( self->powered ) - G_TriggerMenu( activator->client->ps.clientNum, MN_H_ARMOURY ); - else - G_TriggerMenu( activator->client->ps.clientNum, MN_H_NOTPOWERED ); - } -} - -/* -================ -HArmoury_Think - -Think for armoury -================ -*/ -void HArmoury_Think( gentity_t *self ) -{ - //make sure we have power - self->nextthink = level.time + POWER_REFRESH_TIME; - - self->powered = findPower( self ); -} - - - - -//================================================================================== - - - - - -/* -================ -HDCC_Think - -Think for dcc -================ -*/ -void HDCC_Think( gentity_t *self ) -{ - //make sure we have power - self->nextthink = level.time + POWER_REFRESH_TIME; - - self->powered = findPower( self ); -} - - - - -//================================================================================== - -/* -================ -HMedistat_Think - -think function for Human Medistation -================ -*/ -void HMedistat_Think( gentity_t *self ) -{ - int entityList[ MAX_GENTITIES ]; - vec3_t mins, maxs; - int i, num; - gentity_t *player; - qboolean occupied = qfalse; - - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); - - //make sure we have power - if( !( self->powered = findPower( self ) ) ) - { - self->nextthink = level.time + POWER_REFRESH_TIME; - return; - } - - if( self->spawned ) - { - VectorAdd( self->s.origin, self->r.maxs, maxs ); - VectorAdd( self->s.origin, self->r.mins, mins ); - - mins[ 2 ] += fabs( self->r.mins[ 2 ] ) + self->r.maxs[ 2 ]; - maxs[ 2 ] += 60; //player height - - //if active use the healing idle - if( self->active ) - G_setIdleBuildableAnim( self, BANIM_IDLE2 ); - - //check if a previous occupier is still here - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - for( i = 0; i < num; i++ ) - { - player = &g_entities[ entityList[ i ] ]; - - if( player->client && player->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - if( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] && - player->client->ps.pm_type != PM_DEAD && - self->enemy == player ) - occupied = qtrue; - } - } - - if( !occupied ) - { - self->enemy = NULL; - - //look for something to heal - for( i = 0; i < num; i++ ) - { - player = &g_entities[ entityList[ i ] ]; - - if( player->client && player->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - if( player->health < player->client->ps.stats[ STAT_MAX_HEALTH ] && - player->client->ps.pm_type != PM_DEAD ) - { - self->enemy = player; - - //start the heal anim - if( !self->active ) - { - G_setBuildableAnim( self, BANIM_ATTACK1, qfalse ); - self->active = qtrue; - } - } - else if( !BG_InventoryContainsUpgrade( UP_MEDKIT, player->client->ps.stats ) ) - BG_AddUpgradeToInventory( UP_MEDKIT, player->client->ps.stats ); - } - } - } - - //nothing left to heal so go back to idling - if( !self->enemy && self->active ) - { - G_setBuildableAnim( self, BANIM_CONSTRUCT2, qtrue ); - G_setIdleBuildableAnim( self, BANIM_IDLE1 ); - - self->active = qfalse; - } - else if( self->enemy ) //heal! - { - if( self->enemy->client && self->enemy->client->ps.stats[ STAT_STATE ] & SS_POISONED ) - self->enemy->client->ps.stats[ STAT_STATE ] &= ~SS_POISONED; - - if( self->enemy->client && self->enemy->client->ps.stats[ STAT_STATE ] & SS_MEDKIT_ACTIVE ) - self->enemy->client->ps.stats[ STAT_STATE ] &= ~SS_MEDKIT_ACTIVE; - - self->enemy->health++; - - //if they're completely healed, give them a medkit - if( self->enemy->health >= self->enemy->client->ps.stats[ STAT_MAX_HEALTH ] && - !BG_InventoryContainsUpgrade( UP_MEDKIT, self->enemy->client->ps.stats ) ) - BG_AddUpgradeToInventory( UP_MEDKIT, self->enemy->client->ps.stats ); - } - } -} - - - - -//================================================================================== - - - - -/* -================ -HMGTurret_TrackEnemy - -Used by HMGTurret_Think to track enemy location -================ -*/ -qboolean HMGTurret_TrackEnemy( gentity_t *self ) -{ - vec3_t dirToTarget, dttAdjusted, angleToTarget, angularDiff, xNormal; - vec3_t refNormal = { 0.0f, 0.0f, 1.0f }; - float temp, rotAngle; - float accuracyTolerance, angularSpeed; - - if( self->lev1Grabbed ) - { - //can't turn fast if grabbed - accuracyTolerance = MGTURRET_GRAB_ACCURACYTOLERANCE; - angularSpeed = MGTURRET_GRAB_ANGULARSPEED; - } - else if( self->dcced ) - { - accuracyTolerance = MGTURRET_DCC_ACCURACYTOLERANCE; - angularSpeed = MGTURRET_DCC_ANGULARSPEED; - } - else - { - accuracyTolerance = MGTURRET_ACCURACYTOLERANCE; - angularSpeed = MGTURRET_ANGULARSPEED; - } - - VectorSubtract( self->enemy->s.pos.trBase, self->s.pos.trBase, dirToTarget ); - - VectorNormalize( dirToTarget ); - - CrossProduct( self->s.origin2, refNormal, xNormal ); - VectorNormalize( xNormal ); - rotAngle = RAD2DEG( acos( DotProduct( self->s.origin2, refNormal ) ) ); - RotatePointAroundVector( dttAdjusted, xNormal, dirToTarget, rotAngle ); - - vectoangles( dttAdjusted, angleToTarget ); - - angularDiff[ PITCH ] = AngleSubtract( self->s.angles2[ PITCH ], angleToTarget[ PITCH ] ); - angularDiff[ YAW ] = AngleSubtract( self->s.angles2[ YAW ], angleToTarget[ YAW ] ); - - //if not pointing at our target then move accordingly - if( angularDiff[ PITCH ] < (-accuracyTolerance) ) - self->s.angles2[ PITCH ] += angularSpeed; - else if( angularDiff[ PITCH ] > accuracyTolerance ) - self->s.angles2[ PITCH ] -= angularSpeed; - else - self->s.angles2[ PITCH ] = angleToTarget[ PITCH ]; - - //disallow vertical movement past a certain limit - temp = fabs( self->s.angles2[ PITCH ] ); - if( temp > 180 ) - temp -= 360; - - if( temp < -MGTURRET_VERTICALCAP ) - self->s.angles2[ PITCH ] = (-360) + MGTURRET_VERTICALCAP; - - //if not pointing at our target then move accordingly - if( angularDiff[ YAW ] < (-accuracyTolerance) ) - self->s.angles2[ YAW ] += angularSpeed; - else if( angularDiff[ YAW ] > accuracyTolerance ) - self->s.angles2[ YAW ] -= angularSpeed; - else - self->s.angles2[ YAW ] = angleToTarget[ YAW ]; - - AngleVectors( self->s.angles2, dttAdjusted, NULL, NULL ); - RotatePointAroundVector( dirToTarget, xNormal, dttAdjusted, -rotAngle ); - vectoangles( dirToTarget, self->turretAim ); - - //if pointing at our target return true - if( abs( angleToTarget[ YAW ] - self->s.angles2[ YAW ] ) <= accuracyTolerance && - abs( angleToTarget[ PITCH ] - self->s.angles2[ PITCH ] ) <= accuracyTolerance ) - return qtrue; - - return qfalse; -} - - -/* -================ -HMGTurret_CheckTarget - -Used by HMGTurret_Think to check enemies for validity -================ -*/ -qboolean HMGTurret_CheckTarget( gentity_t *self, gentity_t *target, qboolean ignorePainted ) -{ - trace_t trace; - gentity_t *traceEnt; - - if( !target ) - return qfalse; - - if( !target->client ) - return qfalse; - - if( target->client->ps.stats[ STAT_STATE ] & SS_HOVELING ) - return qfalse; - - if( target->health <= 0 ) - return qfalse; - - if( Distance( self->s.origin, target->s.pos.trBase ) > MGTURRET_RANGE ) - return qfalse; - - //some turret has already selected this target - if( self->dcced && target->targeted && target->targeted->powered && !ignorePainted ) - return qfalse; - - trap_Trace( &trace, self->s.pos.trBase, NULL, NULL, target->s.pos.trBase, self->s.number, MASK_SHOT ); - - traceEnt = &g_entities[ trace.entityNum ]; - - if( !traceEnt->client ) - return qfalse; - - if( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS ) - return qfalse; - - return qtrue; -} - - -/* -================ -HMGTurret_FindEnemy - -Used by HMGTurret_Think to locate enemy gentities -================ -*/ -void HMGTurret_FindEnemy( gentity_t *self ) -{ - int entityList[ MAX_GENTITIES ]; - vec3_t range; - vec3_t mins, maxs; - int i, num; - gentity_t *target; - - VectorSet( range, MGTURRET_RANGE, MGTURRET_RANGE, MGTURRET_RANGE ); - VectorAdd( self->s.origin, range, maxs ); - VectorSubtract( self->s.origin, range, mins ); - - //find aliens - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - for( i = 0; i < num; i++ ) - { - target = &g_entities[ entityList[ i ] ]; - - if( target->client && target->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - //if target is not valid keep searching - if( !HMGTurret_CheckTarget( self, target, qfalse ) ) - continue; - - //we found a target - self->enemy = target; - return; - } - } - - if( self->dcced ) - { - //check again, this time ignoring painted targets - for( i = 0; i < num; i++ ) - { - target = &g_entities[ entityList[ i ] ]; - - if( target->client && target->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - //if target is not valid keep searching - if( !HMGTurret_CheckTarget( self, target, qtrue ) ) - continue; - - //we found a target - self->enemy = target; - return; - } - } - } - - //couldn't find a target - self->enemy = NULL; -} - - -/* -================ -HMGTurret_Think - -Think function for MG turret -================ -*/ -void HMGTurret_Think( gentity_t *self ) -{ - int firespeed = BG_FindFireSpeedForBuildable( self->s.modelindex ); - - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); - - //used for client side muzzle flashes - self->s.eFlags &= ~EF_FIRING; - - //if not powered don't do anything and check again for power next think - if( !( self->powered = findPower( self ) ) ) - { - self->nextthink = level.time + POWER_REFRESH_TIME; - return; - } - - if( self->spawned ) - { - //find a dcc for self - self->dcced = findDCC( self ); - - //if the current target is not valid find a new one - if( !HMGTurret_CheckTarget( self, self->enemy, qfalse ) ) - { - if( self->enemy ) - self->enemy->targeted = NULL; - - HMGTurret_FindEnemy( self ); - } - - //if a new target cannot be found don't do anything - if( !self->enemy ) - return; - - self->enemy->targeted = self; - - //if we are pointing at our target and we can fire shoot it - if( HMGTurret_TrackEnemy( self ) && ( self->count < level.time ) ) - { - //fire at target - FireWeapon( self ); - - self->s.eFlags |= EF_FIRING; - G_AddEvent( self, EV_FIRE_WEAPON, 0 ); - G_setBuildableAnim( self, BANIM_ATTACK1, qfalse ); - - self->count = level.time + firespeed; - } - } -} - - - - -//================================================================================== - - - - -/* -================ -HTeslaGen_Think - -Think function for Tesla Generator -================ -*/ -void HTeslaGen_Think( gentity_t *self ) -{ - int entityList[ MAX_GENTITIES ]; - vec3_t range; - vec3_t mins, maxs; - vec3_t dir; - int i, num; - gentity_t *enemy; - - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); - - //if not powered don't do anything and check again for power next think - if( !( self->powered = findPower( self ) ) || !( self->dcced = findDCC( self ) ) ) - { - self->s.eFlags &= ~EF_FIRING; - self->nextthink = level.time + POWER_REFRESH_TIME; - return; - } - - if( self->spawned && self->count < level.time ) - { - //used to mark client side effects - self->s.eFlags &= ~EF_FIRING; - - VectorSet( range, TESLAGEN_RANGE, TESLAGEN_RANGE, TESLAGEN_RANGE ); - VectorAdd( self->s.origin, range, maxs ); - VectorSubtract( self->s.origin, range, mins ); - - //find aliens - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - for( i = 0; i < num; i++ ) - { - enemy = &g_entities[ entityList[ i ] ]; - - if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS && - enemy->health > 0 ) - { - VectorSubtract( enemy->s.pos.trBase, self->s.pos.trBase, dir ); - VectorNormalize( dir ); - vectoangles( dir, self->turretAim ); - - //fire at target - FireWeapon( self ); - } - } - - if( self->s.eFlags & EF_FIRING ) - { - G_AddEvent( self, EV_FIRE_WEAPON, 0 ); - - //doesn't really need an anim - //G_setBuildableAnim( self, BANIM_ATTACK1, qfalse ); - - self->count = level.time + TESLAGEN_REPEAT; - } - } -} - - - - -//================================================================================== - - - - -/* -================ -HSpawn_Disappear - -Called when a human spawn is destroyed before it is spawned -think function -================ -*/ -void HSpawn_Disappear( gentity_t *self ) -{ - vec3_t dir; - - // we don't have a valid direction, so just point straight up - dir[ 0 ] = dir[ 1 ] = 0; - dir[ 2 ] = 1; - - self->s.eFlags |= EF_NODRAW; //don't draw the model once its destroyed - self->timestamp = level.time; - - self->think = freeBuildable; - self->nextthink = level.time + 100; - - self->r.contents = 0; //stop collisions... - trap_LinkEntity( self ); //...requires a relink -} - - -/* -================ -HSpawn_blast - -Called when a human spawn explodes -think function -================ -*/ -void HSpawn_Blast( gentity_t *self ) -{ - vec3_t dir; - - // we don't have a valid direction, so just point straight up - dir[ 0 ] = dir[ 1 ] = 0; - dir[ 2 ] = 1; - - self->s.eFlags |= EF_NODRAW; //don't draw the model once its destroyed - G_AddEvent( self, EV_HUMAN_BUILDABLE_EXPLOSION, DirToByte( dir ) ); - self->timestamp = level.time; - - //do some radius damage - G_RadiusDamage( self->s.pos.trBase, self, self->splashDamage, - self->splashRadius, self, self->splashMethodOfDeath ); - - self->think = freeBuildable; - self->nextthink = level.time + 100; - - self->r.contents = 0; //stop collisions... - trap_LinkEntity( self ); //...requires a relink -} - - -/* -================ -HSpawn_die - -Called when a human spawn dies -================ -*/ -void HSpawn_Die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) -{ - //pretty events and cleanup - G_setBuildableAnim( self, BANIM_DESTROY1, qtrue ); - G_setIdleBuildableAnim( self, BANIM_DESTROYED ); - - self->die = nullDieFunction; - self->powered = qfalse; //free up power - self->s.eFlags &= ~EF_FIRING; //prevent any firing effects - - if( self->spawned ) - { - self->think = HSpawn_Blast; - self->nextthink = level.time + HUMAN_DETONATION_DELAY; - } - else - { - self->think = HSpawn_Disappear; - self->nextthink = level.time; //blast immediately - } - - if( attacker && attacker->client && attacker->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - if( self->s.modelindex == BA_H_REACTOR ) - G_AddCreditToClient( attacker->client, REACTOR_VALUE, qtrue ); - else if( self->s.modelindex == BA_H_SPAWN ) - G_AddCreditToClient( attacker->client, HSPAWN_VALUE, qtrue ); - } -} - -/* -================ -HSpawn_Think - -Think for human spawn -================ -*/ -void HSpawn_Think( gentity_t *self ) -{ - gentity_t *ent; - - //make sure we have power - self->powered = findPower( self ); - - if( self->spawned ) - { - //only suicide if at rest - if( self->s.groundEntityNum ) - { - if( ( ent = G_CheckSpawnPoint( self->s.number, self->s.origin, - self->s.origin2, BA_H_SPAWN, NULL ) ) != NULL ) - { - if( ent->s.eType == ET_BUILDABLE || ent->s.number == ENTITYNUM_WORLD || - ent->s.eType == ET_MOVER ) - { - G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE ); - return; - } - - if( ent->s.eType == ET_CORPSE ) - G_FreeEntity( ent ); //quietly remove - } - } - - //spawn under attack - if( self->health < self->lastHealth && - level.time > level.humanBaseAttackTimer && G_isDCC( ) ) - { - level.humanBaseAttackTimer = level.time + DCC_ATTACK_PERIOD; - G_BroadcastEvent( EV_DCC_ATTACK, 0 ); - } - - self->lastHealth = self->health; - } - - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); -} - - - - -//================================================================================== - - -/* -============ -G_BuildableTouchTriggers - -Find all trigger entities that a buildable touches. -============ -*/ -void G_BuildableTouchTriggers( gentity_t *ent ) -{ - int i, num; - int touch[ MAX_GENTITIES ]; - gentity_t *hit; - trace_t trace; - vec3_t mins, maxs; - vec3_t bmins, bmaxs; - static vec3_t range = { 10, 10, 10 }; - - // dead buildables don't activate triggers! - if( ent->health <= 0 ) - return; - - BG_FindBBoxForBuildable( ent->s.modelindex, bmins, bmaxs ); - - VectorAdd( ent->s.origin, bmins, mins ); - VectorAdd( ent->s.origin, bmaxs, maxs ); - - VectorSubtract( mins, range, mins ); - VectorAdd( maxs, range, maxs ); - - num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES ); - - VectorAdd( ent->s.origin, bmins, mins ); - VectorAdd( ent->s.origin, bmaxs, maxs ); - - for( i = 0; i < num; i++ ) - { - hit = &g_entities[ touch[ i ] ]; - - if( !hit->touch ) - continue; - - if( !( hit->r.contents & CONTENTS_TRIGGER ) ) - continue; - - //ignore buildables not yet spawned - if( !ent->spawned ) - continue; - - if( !trap_EntityContact( mins, maxs, hit ) ) - continue; - - memset( &trace, 0, sizeof( trace ) ); - - if( hit->touch ) - hit->touch( hit, ent, &trace ); - } -} - - -/* -=============== -G_BuildableThink - -General think function for buildables -=============== -*/ -void G_BuildableThink( gentity_t *ent, int msec ) -{ - int bHealth = BG_FindHealthForBuildable( ent->s.modelindex ); - int bRegen = BG_FindRegenRateForBuildable( ent->s.modelindex ); - int bTime = BG_FindBuildTimeForBuildable( ent->s.modelindex ); - - //pack health, power and dcc - - //toggle spawned flag for buildables - if( !ent->spawned ) - { - if( ent->buildTime + bTime < level.time ) - ent->spawned = qtrue; - } - - ent->s.generic1 = (int)( ( (float)ent->health / (float)bHealth ) * B_HEALTH_SCALE ); - - if( ent->s.generic1 < 0 ) - ent->s.generic1 = 0; - - if( ent->powered ) - ent->s.generic1 |= B_POWERED_TOGGLEBIT; - - if( ent->dcced ) - ent->s.generic1 |= B_DCCED_TOGGLEBIT; - - if( ent->spawned ) - ent->s.generic1 |= B_SPAWNED_TOGGLEBIT; - - ent->time1000 += msec; - - if( ent->time1000 >= 1000 ) - { - ent->time1000 -= 1000; - - if( !ent->spawned ) - ent->health += (int)( ceil( (float)bHealth / (float)( bTime * 0.001 ) ) ); - else if( ent->biteam == BIT_ALIENS && ent->health > 0 && ent->health < bHealth && - bRegen && ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time ) - ent->health += bRegen; - - if( ent->health > bHealth ) - ent->health = bHealth; - } - - if( ent->lev1Grabbed && ent->lev1GrabTime + LEVEL1_GRAB_TIME < level.time ) - ent->lev1Grabbed = qfalse; - - if( ent->clientSpawnTime > 0 ) - ent->clientSpawnTime -= msec; - - if( ent->clientSpawnTime < 0 ) - ent->clientSpawnTime = 0; - - //check if this buildable is touching any triggers - G_BuildableTouchTriggers( ent ); - - //fall back on normal physics routines - G_Physics( ent, msec ); -} - - -/* -=============== -G_BuildableRange - -Check whether a point is within some range of a type of buildable -=============== -*/ -qboolean G_BuildableRange( vec3_t origin, float r, buildable_t buildable ) -{ - int entityList[ MAX_GENTITIES ]; - vec3_t range; - vec3_t mins, maxs; - int i, num; - gentity_t *ent; - - VectorSet( range, r, r, r ); - VectorAdd( origin, range, maxs ); - VectorSubtract( origin, range, mins ); - - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - for( i = 0; i < num; i++ ) - { - ent = &g_entities[ entityList[ i ] ]; - - if( ent->s.eType != ET_BUILDABLE ) - continue; - - if( ent->biteam == BIT_HUMANS && !ent->powered ) - continue; - - if( ent->s.modelindex == buildable && ent->spawned ) - return qtrue; - } - - return qfalse; -} - - -/* -================ -G_itemFits - -Checks to see if an item fits in a specific area -================ -*/ -itemBuildError_t G_itemFits( gentity_t *ent, buildable_t buildable, int distance, vec3_t origin ) -{ - vec3_t angles; - vec3_t entity_origin, normal; - vec3_t mins, maxs; - trace_t tr1, tr2, tr3; - int i; - itemBuildError_t reason = IBE_NONE; - gentity_t *tempent; - float minNormal; - qboolean invert; - int contents; - playerState_t *ps = &ent->client->ps; - - BG_FindBBoxForBuildable( buildable, mins, maxs ); - - BG_PositionBuildableRelativeToPlayer( ps, mins, maxs, trap_Trace, entity_origin, angles, &tr1 ); - - trap_Trace( &tr2, entity_origin, mins, maxs, entity_origin, ent->s.number, MASK_PLAYERSOLID ); - trap_Trace( &tr3, ps->origin, NULL, NULL, entity_origin, ent->s.number, MASK_PLAYERSOLID ); - - VectorCopy( entity_origin, origin ); - - //this item does not fit here - if( tr2.fraction < 1.0 || tr3.fraction < 1.0 ) - return IBE_NOROOM; //NO other reason is allowed to override this - - VectorCopy( tr1.plane.normal, normal ); - minNormal = BG_FindMinNormalForBuildable( buildable ); - invert = BG_FindInvertNormalForBuildable( buildable ); - - //can we build at this angle? - if( !( normal[ 2 ] >= minNormal || ( invert && normal[ 2 ] <= -minNormal ) ) ) - return IBE_NORMAL; - - if( tr1.entityNum != ENTITYNUM_WORLD ) - return IBE_NORMAL; - - //check there is enough room to spawn from (presuming this is a spawn) - if( G_CheckSpawnPoint( -1, origin, normal, buildable, NULL ) != NULL ) - return IBE_NORMAL; - - contents = trap_PointContents( entity_origin, -1 ); - - if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - //alien criteria - - if( buildable == BA_A_HOVEL ) - { - vec3_t builderMins, builderMaxs; - - //this assumes the adv builder is the biggest thing that'll use the hovel - BG_FindBBoxForClass( PCL_ALIEN_BUILDER0_UPG, builderMins, builderMaxs, NULL, NULL, NULL ); - - if( APropHovel_Blocked( angles, origin, normal, ent ) ) - reason = IBE_HOVELEXIT; - } - - //check there is creep near by for building on - if( BG_FindCreepTestForBuildable( buildable ) ) - { - if( !isCreep( entity_origin ) ) - reason = IBE_NOCREEP; - } - - //check permission to build here - if( tr1.surfaceFlags & SURF_NOALIENBUILD || tr1.surfaceFlags & SURF_NOBUILD || - contents & CONTENTS_NOALIENBUILD || contents & CONTENTS_NOBUILD ) - reason = IBE_PERMISSION; - - //look for a hivemind - for ( i = 1, tempent = g_entities + i; i < level.num_entities; i++, tempent++ ) - { - if( tempent->s.eType != ET_BUILDABLE ) - continue; - if( tempent->s.modelindex == BA_A_OVERMIND && tempent->spawned ) - break; - } - - //if none found... - if( i >= level.num_entities && buildable != BA_A_OVERMIND ) - reason = IBE_NOOVERMIND; - - //can we only have one of these? - if( BG_FindUniqueTestForBuildable( buildable ) ) - { - for ( i = 1, tempent = g_entities + i; i < level.num_entities; i++, tempent++ ) - { - if( tempent->s.eType != ET_BUILDABLE ) - continue; - - if( tempent->s.modelindex == buildable ) - { - switch( buildable ) - { - case BA_A_OVERMIND: - reason = IBE_OVERMIND; - break; - - case BA_A_HOVEL: - reason = IBE_HOVEL; - break; - - default: - Com_Error( ERR_FATAL, "No reason for denying build of %d\n", buildable ); - break; - } - - break; - } - } - } - - if( level.alienBuildPoints - BG_FindBuildPointsForBuildable( buildable ) < 0 ) - reason = IBE_NOASSERT; - } - else if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - //human criteria - if( !G_isPower( entity_origin ) ) - { - //tell player to build a repeater to provide power - if( buildable != BA_H_REACTOR && buildable != BA_H_REPEATER ) - reason = IBE_REPEATER; - } - - //this buildable requires a DCC - if( BG_FindDCCTestForBuildable( buildable ) && !G_isDCC( ) ) - reason = IBE_NODCC; - - //check that there is a parent reactor when building a repeater - if( buildable == BA_H_REPEATER ) - { - for ( i = 1, tempent = g_entities + i; i < level.num_entities; i++, tempent++ ) - { - if( tempent->s.eType != ET_BUILDABLE ) - continue; - - if( tempent->s.modelindex == BA_H_REACTOR ) - break; - } - - if( i >= level.num_entities ) - { - //no reactor present - - //check for other nearby repeaters - for ( i = 1, tempent = g_entities + i; i < level.num_entities; i++, tempent++ ) - { - if( tempent->s.eType != ET_BUILDABLE ) - continue; - - if( tempent->s.modelindex == BA_H_REPEATER && - Distance( tempent->s.origin, entity_origin ) < REPEATER_BASESIZE ) - { - reason = IBE_RPTWARN2; - break; - } - } - - if( reason == IBE_NONE ) - reason = IBE_RPTWARN; - } - else if( G_isPower( entity_origin ) ) - reason = IBE_RPTWARN2; - } - - //check permission to build here - if( tr1.surfaceFlags & SURF_NOHUMANBUILD || tr1.surfaceFlags & SURF_NOBUILD || - contents & CONTENTS_NOHUMANBUILD || contents & CONTENTS_NOBUILD ) - reason = IBE_PERMISSION; - - //can we only build one of these? - if( BG_FindUniqueTestForBuildable( buildable ) ) - { - for ( i = 1, tempent = g_entities + i; i < level.num_entities; i++, tempent++ ) - { - if( tempent->s.eType != ET_BUILDABLE ) - continue; - - if( tempent->s.modelindex == BA_H_REACTOR ) - { - reason = IBE_REACTOR; - break; - } - } - } - - if( level.humanBuildPoints - BG_FindBuildPointsForBuildable( buildable ) < 0 ) - reason = IBE_NOPOWER; - } - - return reason; -} - - -/* -================ -G_buildItem - -Spawns a buildable -================ -*/ -gentity_t *G_buildItem( gentity_t *builder, buildable_t buildable, vec3_t origin, vec3_t angles ) -{ - gentity_t *built; - vec3_t normal; - - //spawn the buildable - built = G_Spawn(); - - built->s.eType = ET_BUILDABLE; - - built->classname = BG_FindEntityNameForBuildable( buildable ); - - built->s.modelindex = buildable; //so we can tell what this is on the client side - built->biteam = built->s.modelindex2 = BG_FindTeamForBuildable( buildable ); - - BG_FindBBoxForBuildable( buildable, built->r.mins, built->r.maxs ); - built->health = 1; - - built->splashDamage = BG_FindSplashDamageForBuildable( buildable ); - built->splashRadius = BG_FindSplashRadiusForBuildable( buildable ); - built->splashMethodOfDeath = BG_FindMODForBuildable( buildable ); - - built->nextthink = BG_FindNextThinkForBuildable( buildable ); - - built->takedamage = qtrue; - built->spawned = qfalse; - built->buildTime = built->s.time = level.time; - - //things that vary for each buildable that aren't in the dbase - switch( buildable ) - { - case BA_A_SPAWN: - built->die = ASpawn_Die; - built->think = ASpawn_Think; - built->pain = ASpawn_Pain; - break; - - case BA_A_BARRICADE: - built->die = ABarricade_Die; - built->think = ABarricade_Think; - built->pain = ABarricade_Pain; - break; - - case BA_A_BOOSTER: - built->die = ABarricade_Die; - built->think = ABarricade_Think; - built->pain = ABarricade_Pain; - built->touch = ABooster_Touch; - break; - - case BA_A_ACIDTUBE: - built->die = ABarricade_Die; - built->think = AAcidTube_Think; - built->pain = ASpawn_Pain; - break; - - case BA_A_HIVE: - built->die = ABarricade_Die; - built->think = AHive_Think; - built->pain = ASpawn_Pain; - break; - - case BA_A_TRAPPER: - built->die = ABarricade_Die; - built->think = ATrapper_Think; - built->pain = ASpawn_Pain; - break; - - case BA_A_OVERMIND: - built->die = ASpawn_Die; - built->think = AOvermind_Think; - built->pain = ASpawn_Pain; - break; - - case BA_A_HOVEL: - built->die = AHovel_Die; - built->use = AHovel_Use; - built->think = AHovel_Think; - built->pain = ASpawn_Pain; - break; - - case BA_H_SPAWN: - built->die = HSpawn_Die; - built->think = HSpawn_Think; - break; - - case BA_H_MGTURRET: - built->die = HSpawn_Die; - built->think = HMGTurret_Think; - break; - - case BA_H_TESLAGEN: - built->die = HSpawn_Die; - built->think = HTeslaGen_Think; - break; - - case BA_H_ARMOURY: - built->think = HArmoury_Think; - built->die = HSpawn_Die; - built->use = HArmoury_Activate; - break; - - case BA_H_DCC: - built->think = HDCC_Think; - built->die = HSpawn_Die; - break; - - case BA_H_MEDISTAT: - built->think = HMedistat_Think; - built->die = HSpawn_Die; - break; - - case BA_H_REACTOR: - built->think = HReactor_Think; - built->die = HSpawn_Die; - built->use = HRepeater_Use; - built->powered = built->active = qtrue; - break; - - case BA_H_REPEATER: - built->think = HRepeater_Think; - built->die = HSpawn_Die; - built->use = HRepeater_Use; - built->count = -1; - break; - - default: - //erk - break; - } - - built->s.number = built - g_entities; - built->r.contents = CONTENTS_BODY; - built->clipmask = MASK_PLAYERSOLID; - built->enemy = NULL; - built->s.weapon = BG_FindProjTypeForBuildable( buildable ); - - if( builder->client ) - built->builtBy = builder->client->ps.clientNum; - else - built->builtBy = -1; - - G_SetOrigin( built, origin ); - VectorCopy( angles, built->s.angles ); - built->s.angles[ PITCH ] = 0.0f; - built->s.angles2[ YAW ] = angles[ YAW ]; - built->s.pos.trType = BG_FindTrajectoryForBuildable( buildable ); - built->s.pos.trTime = level.time; - built->physicsBounce = BG_FindBounceForBuildable( buildable ); - built->s.groundEntityNum = -1; - - if( builder->client && builder->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBING ) - { - if( builder->client->ps.stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) - VectorSet( normal, 0.0f, 0.0f, -1.0f ); - else - VectorCopy( builder->client->ps.grapplePoint, normal ); - - //gently nudge the buildable onto the surface :) - VectorScale( normal, -50.0f, built->s.pos.trDelta ); - } - else - VectorSet( normal, 0.0f, 0.0f, 1.0f ); - - built->s.generic1 = (int)( ( (float)built->health / - (float)BG_FindHealthForBuildable( buildable ) ) * B_HEALTH_SCALE ); - - if( built->s.generic1 < 0 ) - built->s.generic1 = 0; - - if( ( built->powered = findPower( built ) ) ) - built->s.generic1 |= B_POWERED_TOGGLEBIT; - - if( ( built->dcced = findDCC( built ) ) ) - built->s.generic1 |= B_DCCED_TOGGLEBIT; - - built->s.generic1 &= ~B_SPAWNED_TOGGLEBIT; - - VectorCopy( normal, built->s.origin2 ); - - G_AddEvent( built, EV_BUILD_CONSTRUCT, 0 ); - - G_setIdleBuildableAnim( built, BG_FindAnimForBuildable( buildable ) ); - - if( built->builtBy >= 0 ) - G_setBuildableAnim( built, BANIM_CONSTRUCT1, qtrue ); - - trap_LinkEntity( built ); - - return built; -} - -/* -================= -G_ValidateBuild -================= -*/ -qboolean G_ValidateBuild( gentity_t *ent, buildable_t buildable ) -{ - float dist; - vec3_t origin; - - dist = BG_FindBuildDistForClass( ent->client->ps.stats[ STAT_PCLASS ] ); - - switch( G_itemFits( ent, buildable, dist, origin ) ) - { - case IBE_NONE: - G_buildItem( ent, buildable, origin, ent->s.apos.trBase ); - return qtrue; - - case IBE_NOASSERT: - G_TriggerMenu( ent->client->ps.clientNum, MN_A_NOASSERT ); - return qfalse; - - case IBE_NOOVERMIND: - G_TriggerMenu( ent->client->ps.clientNum, MN_A_NOOVMND ); - return qfalse; - - case IBE_NOCREEP: - G_TriggerMenu( ent->client->ps.clientNum, MN_A_NOCREEP ); - return qfalse; - - case IBE_OVERMIND: - G_TriggerMenu( ent->client->ps.clientNum, MN_A_OVERMIND ); - return qfalse; - - case IBE_HOVEL: - G_TriggerMenu( ent->client->ps.clientNum, MN_A_HOVEL ); - return qfalse; - - case IBE_HOVELEXIT: - G_TriggerMenu( ent->client->ps.clientNum, MN_A_HOVEL_EXIT ); - return qfalse; - - case IBE_NORMAL: - if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - G_TriggerMenu( ent->client->ps.clientNum, MN_H_NORMAL ); - else - G_TriggerMenu( ent->client->ps.clientNum, MN_A_NORMAL ); - return qfalse; - - case IBE_PERMISSION: - if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - G_TriggerMenu( ent->client->ps.clientNum, MN_H_NORMAL ); - else - G_TriggerMenu( ent->client->ps.clientNum, MN_A_NORMAL ); - return qfalse; - - case IBE_REACTOR: - G_TriggerMenu( ent->client->ps.clientNum, MN_H_REACTOR ); - return qfalse; - - case IBE_REPEATER: - G_TriggerMenu( ent->client->ps.clientNum, MN_H_REPEATER ); - return qfalse; - - case IBE_NOROOM: - if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOROOM ); - else - G_TriggerMenu( ent->client->ps.clientNum, MN_A_NOROOM ); - return qfalse; - - case IBE_NOPOWER: - G_TriggerMenu( ent->client->ps.clientNum, MN_H_NOPOWER ); - return qfalse; - - case IBE_NODCC: - G_TriggerMenu( ent->client->ps.clientNum, MN_H_NODCC ); - return qfalse; - - case IBE_SPWNWARN: - G_TriggerMenu( ent->client->ps.clientNum, MN_A_SPWNWARN ); - G_buildItem( ent, buildable, origin, ent->s.apos.trBase ); - return qtrue; - - case IBE_TNODEWARN: - G_TriggerMenu( ent->client->ps.clientNum, MN_H_TNODEWARN ); - G_buildItem( ent, buildable, origin, ent->s.apos.trBase ); - return qtrue; - - case IBE_RPTWARN: - G_TriggerMenu( ent->client->ps.clientNum, MN_H_RPTWARN ); - G_buildItem( ent, buildable, origin, ent->s.apos.trBase ); - return qtrue; - - case IBE_RPTWARN2: - G_TriggerMenu( ent->client->ps.clientNum, MN_H_RPTWARN2 ); - return qfalse; - - default: - break; - } - - return qfalse; -} - -/* -================ -FinishSpawningBuildable - -Traces down to find where an item should rest, instead of letting them -free fall from their spawn points -================ -*/ -void FinishSpawningBuildable( gentity_t *ent ) -{ - trace_t tr; - vec3_t dest; - gentity_t *built; - buildable_t buildable = ent->s.modelindex; - - built = G_buildItem( ent, buildable, ent->s.pos.trBase, ent->s.angles ); - G_FreeEntity( ent ); - - built->takedamage = qtrue; - built->spawned = qtrue; //map entities are already spawned - built->health = BG_FindHealthForBuildable( buildable ); - built->s.generic1 |= B_SPAWNED_TOGGLEBIT; - - // drop to floor - if( buildable != BA_NONE && BG_FindTrajectoryForBuildable( buildable ) == TR_BUOYANCY ) - VectorSet( dest, built->s.origin[ 0 ], built->s.origin[ 1 ], built->s.origin[ 2 ] + 4096 ); - else - VectorSet( dest, built->s.origin[ 0 ], built->s.origin[ 1 ], built->s.origin[ 2 ] - 4096 ); - - trap_Trace( &tr, built->s.origin, built->r.mins, built->r.maxs, dest, built->s.number, built->clipmask ); - - if( tr.startsolid ) - { - G_Printf( S_COLOR_YELLOW "FinishSpawningBuildable: %s startsolid at %s\n", built->classname, vtos( built->s.origin ) ); - G_FreeEntity( built ); - return; - } - - //point items in the correct direction - VectorCopy( tr.plane.normal, built->s.origin2 ); - - // allow to ride movers - built->s.groundEntityNum = tr.entityNum; - - G_SetOrigin( built, tr.endpos ); - - trap_LinkEntity( built ); -} - -/* -============ -G_SpawnBuildable - -Sets the clipping size and plants the object on the floor. - -Items can't be immediately dropped to floor, because they might -be on an entity that hasn't spawned yet. -============ -*/ -void G_SpawnBuildable( gentity_t *ent, buildable_t buildable ) -{ - ent->s.modelindex = buildable; - - // some movers spawn on the second frame, so delay item - // spawns until the third frame so they can ride trains - ent->nextthink = level.time + FRAMETIME * 2; - ent->think = FinishSpawningBuildable; -} diff --git a/src/game/g_client.c b/src/game/g_client.c deleted file mode 100644 index e86439c4..00000000 --- a/src/game/g_client.c +++ /dev/null @@ -1,1593 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "g_local.h" - -// g_client.c -- client functions that don't happen every frame - -static vec3_t playerMins = {-15, -15, -24}; -static vec3_t playerMaxs = {15, 15, 32}; - -/*QUAKED info_player_deathmatch (1 0 1) (-16 -16 -24) (16 16 32) initial -potential spawning position for deathmatch games. -The first time a player enters the game, they will be at an 'initial' spot. -Targets will be fired when someone spawns in on them. -"nobots" will prevent bots from using this spot. -"nohumans" will prevent non-bots from using this spot. -*/ -void SP_info_player_deathmatch( gentity_t *ent ) -{ - int i; - - G_SpawnInt( "nobots", "0", &i); - - if( i ) - ent->flags |= FL_NO_BOTS; - - G_SpawnInt( "nohumans", "0", &i ); - if( i ) - ent->flags |= FL_NO_HUMANS; -} - -/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32) -equivelant to info_player_deathmatch -*/ -void SP_info_player_start( gentity_t *ent ) -{ - ent->classname = "info_player_deathmatch"; - SP_info_player_deathmatch( ent ); -} - -/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32) -The intermission will be viewed from this point. Target an info_notnull for the view direction. -*/ -void SP_info_player_intermission( gentity_t *ent ) -{ -} - -/*QUAKED info_alien_intermission (1 0 1) (-16 -16 -24) (16 16 32) -The intermission will be viewed from this point. Target an info_notnull for the view direction. -*/ -void SP_info_alien_intermission( gentity_t *ent ) -{ -} - -/*QUAKED info_human_intermission (1 0 1) (-16 -16 -24) (16 16 32) -The intermission will be viewed from this point. Target an info_notnull for the view direction. -*/ -void SP_info_human_intermission( gentity_t *ent ) -{ -} - -/* -=============== -G_AddCreditToClient -=============== -*/ -void G_AddCreditToClient( gclient_t *client, short credit, qboolean cap ) -{ - if( !client ) - return; - - //if we're already at the max and trying to add credit then stop - if( cap ) - { - if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - if( client->ps.persistant[ PERS_CREDIT ] >= ALIEN_MAX_KILLS && - credit > 0 ) - return; - } - else if( client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - if( client->ps.persistant[ PERS_CREDIT ] >= HUMAN_MAX_CREDITS && - credit > 0 ) - return; - } - } - - client->ps.persistant[ PERS_CREDIT ] += credit; - - if( cap ) - { - if( client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - if( client->ps.persistant[ PERS_CREDIT ] > ALIEN_MAX_KILLS ) - client->ps.persistant[ PERS_CREDIT ] = ALIEN_MAX_KILLS; - } - else if( client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - if( client->ps.persistant[ PERS_CREDIT ] > HUMAN_MAX_CREDITS ) - client->ps.persistant[ PERS_CREDIT ] = HUMAN_MAX_CREDITS; - } - } - - if( client->ps.persistant[ PERS_CREDIT ] < 0 ) - client->ps.persistant[ PERS_CREDIT ] = 0; -} - - -/* -======================================================================= - - SelectSpawnPoint - -======================================================================= -*/ - -/* -================ -SpotWouldTelefrag - -================ -*/ -qboolean SpotWouldTelefrag( gentity_t *spot ) -{ - int i, num; - int touch[ MAX_GENTITIES ]; - gentity_t *hit; - vec3_t mins, maxs; - - VectorAdd( spot->s.origin, playerMins, mins ); - VectorAdd( spot->s.origin, playerMaxs, maxs ); - num = trap_EntitiesInBox( mins, maxs, touch, MAX_GENTITIES ); - - for( i = 0; i < num; i++ ) - { - hit = &g_entities[ touch[ i ] ]; - //if ( hit->client && hit->client->ps.stats[STAT_HEALTH] > 0 ) { - if( hit->client ) - return qtrue; - } - - return qfalse; -} - -/* -================ -SelectNearestDeathmatchSpawnPoint - -Find the spot that we DON'T want to use -================ -*/ -#define MAX_SPAWN_POINTS 128 -gentity_t *SelectNearestDeathmatchSpawnPoint( vec3_t from ) -{ - gentity_t *spot; - vec3_t delta; - float dist, nearestDist; - gentity_t *nearestSpot; - - nearestDist = 999999; - nearestSpot = NULL; - spot = NULL; - - while( (spot = G_Find( spot, FOFS( classname ), "info_player_deathmatch" ) ) != NULL ) - { - VectorSubtract( spot->s.origin, from, delta ); - dist = VectorLength( delta ); - - if( dist < nearestDist ) - { - nearestDist = dist; - nearestSpot = spot; - } - } - - return nearestSpot; -} - - -/* -================ -SelectRandomDeathmatchSpawnPoint - -go to a random point that doesn't telefrag -================ -*/ -#define MAX_SPAWN_POINTS 128 -gentity_t *SelectRandomDeathmatchSpawnPoint( void ) -{ - gentity_t *spot; - int count; - int selection; - gentity_t *spots[ MAX_SPAWN_POINTS ]; - - count = 0; - spot = NULL; - - while( ( spot = G_Find( spot, FOFS( classname ), "info_player_deathmatch" ) ) != NULL ) - { - if( SpotWouldTelefrag( spot ) ) - continue; - - spots[ count ] = spot; - count++; - } - - if( !count ) // no spots that won't telefrag - return G_Find( NULL, FOFS( classname ), "info_player_deathmatch" ); - - selection = rand( ) % count; - return spots[ selection ]; -} - - -/* -=========== -SelectRandomFurthestSpawnPoint - -Chooses a player start, deathmatch start, etc -============ -*/ -gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) -{ - gentity_t *spot; - vec3_t delta; - float dist; - float list_dist[ 64 ]; - gentity_t *list_spot[ 64 ]; - int numSpots, rnd, i, j; - - numSpots = 0; - spot = NULL; - - while( ( spot = G_Find( spot, FOFS( classname ), "info_player_deathmatch" ) ) != NULL ) - { - if( SpotWouldTelefrag( spot ) ) - continue; - - VectorSubtract( spot->s.origin, avoidPoint, delta ); - dist = VectorLength( delta ); - - for( i = 0; i < numSpots; i++ ) - { - if( dist > list_dist[ i ] ) - { - if( numSpots >= 64 ) - numSpots = 64 - 1; - - for( j = numSpots; j > i; j-- ) - { - list_dist[ j ] = list_dist[ j - 1 ]; - list_spot[ j ] = list_spot[ j - 1 ]; - } - - list_dist[ i ] = dist; - list_spot[ i ] = spot; - numSpots++; - - if( numSpots > 64 ) - numSpots = 64; - - break; - } - } - - if( i >= numSpots && numSpots < 64 ) - { - list_dist[ numSpots ] = dist; - list_spot[ numSpots ] = spot; - numSpots++; - } - } - - if( !numSpots ) - { - spot = G_Find( NULL, FOFS( classname ), "info_player_deathmatch" ); - - if( !spot ) - G_Error( "Couldn't find a spawn point" ); - - VectorCopy( spot->s.origin, origin ); - origin[ 2 ] += 9; - VectorCopy( spot->s.angles, angles ); - return spot; - } - - // select a random spot from the spawn points furthest away - rnd = random( ) * ( numSpots / 2 ); - - VectorCopy( list_spot[ rnd ]->s.origin, origin ); - origin[ 2 ] += 9; - VectorCopy( list_spot[ rnd ]->s.angles, angles ); - - return list_spot[ rnd ]; -} - - -/* -================ -SelectAlienSpawnPoint - -go to a random point that doesn't telefrag -================ -*/ -gentity_t *SelectAlienSpawnPoint( vec3_t preference ) -{ - gentity_t *spot; - int count; - gentity_t *spots[ MAX_SPAWN_POINTS ]; - - if( level.numAlienSpawns <= 0 ) - return NULL; - - count = 0; - spot = NULL; - - while( ( spot = G_Find( spot, FOFS( classname ), - BG_FindEntityNameForBuildable( BA_A_SPAWN ) ) ) != NULL ) - { - if( !spot->spawned ) - continue; - - if( spot->health <= 0 ) - continue; - - if( !spot->s.groundEntityNum ) - continue; - - if( spot->clientSpawnTime > 0 ) - continue; - - if( G_CheckSpawnPoint( spot->s.number, spot->s.origin, - spot->s.origin2, BA_A_SPAWN, NULL ) != NULL ) - continue; - - spots[ count ] = spot; - count++; - } - - if( !count ) - return NULL; - - return G_ClosestEnt( preference, spots, count ); -} - - -/* -================ -SelectHumanSpawnPoint - -go to a random point that doesn't telefrag -================ -*/ -gentity_t *SelectHumanSpawnPoint( vec3_t preference ) -{ - gentity_t *spot; - int count; - gentity_t *spots[ MAX_SPAWN_POINTS ]; - - if( level.numHumanSpawns <= 0 ) - return NULL; - - count = 0; - spot = NULL; - - while( ( spot = G_Find( spot, FOFS( classname ), - BG_FindEntityNameForBuildable( BA_H_SPAWN ) ) ) != NULL ) - { - if( !spot->spawned ) - continue; - - if( spot->health <= 0 ) - continue; - - if( !spot->s.groundEntityNum ) - continue; - - if( spot->clientSpawnTime > 0 ) - continue; - - if( G_CheckSpawnPoint( spot->s.number, spot->s.origin, - spot->s.origin2, BA_H_SPAWN, NULL ) != NULL ) - continue; - - spots[ count ] = spot; - count++; - } - - if( !count ) - return NULL; - - return G_ClosestEnt( preference, spots, count ); -} - - -/* -=========== -SelectSpawnPoint - -Chooses a player start, deathmatch start, etc -============ -*/ -gentity_t *SelectSpawnPoint( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) -{ - return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles ); -} - - -/* -=========== -SelectTremulousSpawnPoint - -Chooses a player start, deathmatch start, etc -============ -*/ -gentity_t *SelectTremulousSpawnPoint( pTeam_t team, vec3_t preference, vec3_t origin, vec3_t angles ) -{ - gentity_t *spot = NULL; - - if( team == PTE_ALIENS ) - spot = SelectAlienSpawnPoint( preference ); - else if( team == PTE_HUMANS ) - spot = SelectHumanSpawnPoint( preference ); - - //no available spots - if( !spot ) - return NULL; - - if( team == PTE_ALIENS ) - G_CheckSpawnPoint( spot->s.number, spot->s.origin, spot->s.origin2, BA_A_SPAWN, origin ); - else if( team == PTE_HUMANS ) - G_CheckSpawnPoint( spot->s.number, spot->s.origin, spot->s.origin2, BA_H_SPAWN, origin ); - - VectorCopy( spot->s.angles, angles ); - angles[ ROLL ] = 0; - - return spot; - -} - - -/* -=========== -SelectInitialSpawnPoint - -Try to find a spawn point marked 'initial', otherwise -use normal spawn selection. -============ -*/ -gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles ) -{ - gentity_t *spot; - - spot = NULL; - while( ( spot = G_Find( spot, FOFS( classname ), "info_player_deathmatch" ) ) != NULL ) - { - if( spot->spawnflags & 1 ) - break; - } - - if( !spot || SpotWouldTelefrag( spot ) ) - { - return SelectSpawnPoint( vec3_origin, origin, angles ); - } - - VectorCopy( spot->s.origin, origin ); - origin[ 2 ] += 9; - VectorCopy( spot->s.angles, angles ); - - return spot; -} - -/* -=========== -SelectSpectatorSpawnPoint - -============ -*/ -gentity_t *SelectSpectatorSpawnPoint( vec3_t origin, vec3_t angles ) -{ - FindIntermissionPoint( ); - - VectorCopy( level.intermission_origin, origin ); - VectorCopy( level.intermission_angle, angles ); - - return NULL; -} - - -/* -=========== -SelectAlienLockSpawnPoint - -Try to find a spawn point for alien intermission otherwise -use normal intermission spawn. -============ -*/ -gentity_t *SelectAlienLockSpawnPoint( vec3_t origin, vec3_t angles ) -{ - gentity_t *spot; - - spot = NULL; - spot = G_Find( spot, FOFS( classname ), "info_alien_intermission" ); - - if( !spot ) - return SelectSpectatorSpawnPoint( origin, angles ); - - VectorCopy( spot->s.origin, origin ); - VectorCopy( spot->s.angles, angles ); - - return spot; -} - - -/* -=========== -SelectHumanLockSpawnPoint - -Try to find a spawn point for human intermission otherwise -use normal intermission spawn. -============ -*/ -gentity_t *SelectHumanLockSpawnPoint( vec3_t origin, vec3_t angles ) -{ - gentity_t *spot; - - spot = NULL; - spot = G_Find( spot, FOFS( classname ), "info_human_intermission" ); - - if( !spot ) - return SelectSpectatorSpawnPoint( origin, angles ); - - VectorCopy( spot->s.origin, origin ); - VectorCopy( spot->s.angles, angles ); - - return spot; -} - - -/* -======================================================================= - -BODYQUE - -======================================================================= -*/ - - -/* -============= -BodySink - -After sitting around for five seconds, fall into the ground and dissapear -============= -*/ -void BodySink( gentity_t *ent ) -{ - //run on first BodySink call - if( !ent->active ) - { - ent->active = qtrue; - - //sinking bodies can't be infested - ent->killedBy = ent->s.powerups = MAX_CLIENTS; - ent->timestamp = level.time; - } - - if( level.time - ent->timestamp > 6500 ) - { - G_FreeEntity( ent ); - return; - } - - ent->nextthink = level.time + 100; - ent->s.pos.trBase[ 2 ] -= 1; -} - - -/* -============= -BodyFree - -After sitting around for a while the body becomes a freebie -============= -*/ -void BodyFree( gentity_t *ent ) -{ - ent->killedBy = -1; - - //if not claimed in the next minute destroy - ent->think = BodySink; - ent->nextthink = level.time + 60000; -} - - -/* -============= -SpawnCorpse - -A player is respawning, so make an entity that looks -just like the existing corpse to leave behind. -============= -*/ -void SpawnCorpse( gentity_t *ent ) -{ - gentity_t *body; - int contents; - vec3_t origin, dest; - trace_t tr; - float vDiff; - - VectorCopy( ent->r.currentOrigin, origin ); - - trap_UnlinkEntity( ent ); - - // if client is in a nodrop area, don't leave the body - contents = trap_PointContents( origin, -1 ); - if( contents & CONTENTS_NODROP ) - return; - - body = G_Spawn( ); - - VectorCopy( ent->s.apos.trBase, body->s.angles ); - body->s.eFlags = EF_DEAD; - body->s.eType = ET_CORPSE; - body->s.number = body - g_entities; - body->timestamp = level.time; - body->s.event = 0; - body->r.contents = CONTENTS_CORPSE; - body->s.clientNum = ent->client->ps.stats[ STAT_PCLASS ]; - body->nonSegModel = ent->client->ps.persistant[ PERS_STATE ] & PS_NONSEGMODEL; - - if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - body->classname = "humanCorpse"; - else - body->classname = "alienCorpse"; - - body->s.powerups = MAX_CLIENTS; - - body->think = BodySink; - body->nextthink = level.time + 20000; - - body->s.legsAnim = ent->s.legsAnim; - - if( !body->nonSegModel ) - { - switch( body->s.legsAnim & ~ANIM_TOGGLEBIT ) - { - case BOTH_DEATH1: - case BOTH_DEAD1: - body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD1; - break; - case BOTH_DEATH2: - case BOTH_DEAD2: - body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD2; - break; - case BOTH_DEATH3: - case BOTH_DEAD3: - default: - body->s.torsoAnim = body->s.legsAnim = BOTH_DEAD3; - break; - } - } - else - { - switch( body->s.legsAnim & ~ANIM_TOGGLEBIT ) - { - case NSPA_DEATH1: - case NSPA_DEAD1: - body->s.legsAnim = NSPA_DEAD1; - break; - case NSPA_DEATH2: - case NSPA_DEAD2: - body->s.legsAnim = NSPA_DEAD2; - break; - case NSPA_DEATH3: - case NSPA_DEAD3: - default: - body->s.legsAnim = NSPA_DEAD3; - break; - } - } - - body->takedamage = qfalse; - - body->health = ent->health = ent->client->ps.stats[ STAT_HEALTH ]; - ent->health = 0; - - //change body dimensions - BG_FindBBoxForClass( ent->client->ps.stats[ STAT_PCLASS ], NULL, NULL, NULL, body->r.mins, body->r.maxs ); - vDiff = body->r.mins[ 2 ] - ent->r.mins[ 2 ]; - - //drop down to match the *model* origins of ent and body - VectorSet( dest, origin[ 0 ], origin[ 1 ], origin[ 2 ] - vDiff ); - trap_Trace( &tr, origin, body->r.mins, body->r.maxs, dest, body->s.number, body->clipmask ); - VectorCopy( tr.endpos, origin ); - - G_SetOrigin( body, origin ); - VectorCopy( origin, body->s.origin ); - body->s.pos.trType = TR_GRAVITY; - body->s.pos.trTime = level.time; - VectorCopy( ent->client->ps.velocity, body->s.pos.trDelta ); - - VectorCopy ( body->s.pos.trBase, body->r.currentOrigin ); - trap_LinkEntity( body ); -} - -//====================================================================== - - -/* -================== -SetClientViewAngle - -================== -*/ -void SetClientViewAngle( gentity_t *ent, vec3_t angle ) -{ - int i; - - // set the delta angle - for( i = 0; i < 3; i++ ) - { - int cmdAngle; - - cmdAngle = ANGLE2SHORT( angle[ i ] ); - ent->client->ps.delta_angles[ i ] = cmdAngle - ent->client->pers.cmd.angles[ i ]; - } - - VectorCopy( angle, ent->s.angles ); - VectorCopy( ent->s.angles, ent->client->ps.viewangles ); -} - -/* -================ -respawn -================ -*/ -void respawn( gentity_t *ent ) -{ - SpawnCorpse( ent ); - - //TA: Clients can't respawn - they must go thru the class cmd - ClientSpawn( ent, NULL, NULL, NULL ); -} - -/* -================ -TeamCount - -Returns number of players on a team -================ -*/ -team_t TeamCount( int ignoreClientNum, int team ) -{ - int i; - int count = 0; - - for( i = 0 ; i < level.maxclients ; i++ ) - { - if( i == ignoreClientNum ) - continue; - - if( level.clients[ i ].pers.connected == CON_DISCONNECTED ) - continue; - - if( level.clients[ i ].sess.sessionTeam == team ) - count++; - } - - return count; -} - - -/* -=========== -ClientCheckName -============ -*/ -static void ClientCleanName( const char *in, char *out, int outSize ) -{ - int len, colorlessLen; - char ch; - char *p; - int spaces; - - //save room for trailing null byte - outSize--; - - len = 0; - colorlessLen = 0; - p = out; - *p = 0; - spaces = 0; - - while( 1 ) - { - ch = *in++; - if( !ch ) - break; - - // don't allow leading spaces - if( !*p && ch == ' ' ) - continue; - - // check colors - if( ch == Q_COLOR_ESCAPE ) - { - // solo trailing carat is not a color prefix - if( !*in ) - break; - - // don't allow black in a name, period - if( ColorIndex( *in ) == 0 ) - { - in++; - continue; - } - - // make sure room in dest for both chars - if( len > outSize - 2 ) - break; - - *out++ = ch; - *out++ = *in++; - len += 2; - continue; - } - - // don't allow too many consecutive spaces - if( ch == ' ' ) - { - spaces++; - if( spaces > 3 ) - continue; - } - else - spaces = 0; - - if( len > outSize - 1 ) - break; - - *out++ = ch; - colorlessLen++; - len++; - } - - *out = 0; - - // don't allow empty names - if( *p == 0 || colorlessLen == 0 ) - Q_strncpyz( p, "UnnamedPlayer", outSize ); -} - - -/* -====================== -G_NonSegModel - -Reads an animation.cfg to check for nonsegmentation -====================== -*/ -static qboolean G_NonSegModel( const char *filename ) -{ - char *text_p; - int len; - char *token; - char text[ 20000 ]; - fileHandle_t f; - - // load the file - len = trap_FS_FOpenFile( filename, &f, FS_READ ); - if( !f ) - { - G_Printf( "File not found: %s\n", filename ); - return qfalse; - } - - if( len <= 0 ) - return qfalse; - - if( len >= sizeof( text ) - 1 ) - { - G_Printf( "File %s too long\n", filename ); - return qfalse; - } - - trap_FS_Read( text, len, f ); - text[ len ] = 0; - trap_FS_FCloseFile( f ); - - // parse the text - text_p = text; - - // read optional parameters - while( 1 ) - { - token = COM_Parse( &text_p ); - - //EOF - if( !token[ 0 ] ) - break; - - if( !Q_stricmp( token, "nonsegmented" ) ) - return qtrue; - } - - return qfalse; -} - -/* -=========== -ClientUserInfoChanged - -Called from ClientConnect when the player first connects and -directly by the server system when the player updates a userinfo variable. - -The game can override any of the settings and call trap_SetUserinfo -if desired. -============ -*/ -void ClientUserinfoChanged( int clientNum ) -{ - gentity_t *ent; - int teamTask, teamLeader, health; - char *s; - char model[ MAX_QPATH ]; - char buffer[ MAX_QPATH ]; - char filename[ MAX_QPATH ]; - char oldname[ MAX_STRING_CHARS ]; - gclient_t *client; - char c1[ MAX_INFO_STRING ]; - char c2[ MAX_INFO_STRING ]; - char redTeam[ MAX_INFO_STRING ]; - char blueTeam[ MAX_INFO_STRING ]; - char userinfo[ MAX_INFO_STRING ]; - team_t team; - - ent = g_entities + clientNum; - client = ent->client; - - trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); - - // check for malformed or illegal info strings - if( !Info_Validate(userinfo) ) - strcpy( userinfo, "\\name\\badinfo" ); - - // check for local client - s = Info_ValueForKey( userinfo, "ip" ); - - if( !strcmp( s, "localhost" ) ) - client->pers.localClient = qtrue; - - // check the item prediction - s = Info_ValueForKey( userinfo, "cg_predictItems" ); - - if( !atoi( s ) ) - client->pers.predictItemPickup = qfalse; - else - client->pers.predictItemPickup = qtrue; - - // set name - Q_strncpyz( oldname, client->pers.netname, sizeof( oldname ) ); - s = Info_ValueForKey( userinfo, "name" ); - ClientCleanName( s, client->pers.netname, sizeof( client->pers.netname ) ); - - if( client->sess.sessionTeam == TEAM_SPECTATOR ) - { - if( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) - Q_strncpyz( client->pers.netname, "scoreboard", sizeof( client->pers.netname ) ); - } - - if( client->pers.connected == CON_CONNECTED ) - { - if( strcmp( oldname, client->pers.netname ) ) - { - G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname, - client->pers.netname ) ); - } - } - - // set max health - health = atoi( Info_ValueForKey( userinfo, "handicap" ) ); - client->pers.maxHealth = health; - - if( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) - client->pers.maxHealth = 100; - - //hack to force a client update if the config string does not change between spawning - if( client->pers.classSelection == PCL_NONE ) - client->pers.maxHealth = 0; - - // set model - if( client->ps.stats[ STAT_PCLASS ] == PCL_HUMAN && BG_InventoryContainsUpgrade( UP_BATTLESUIT, client->ps.stats ) ) - { - Com_sprintf( buffer, MAX_QPATH, "%s/%s", BG_FindModelNameForClass( PCL_HUMAN_BSUIT ), - BG_FindSkinNameForClass( PCL_HUMAN_BSUIT ) ); - } - else if( client->pers.classSelection == PCL_NONE ) - { - //This looks hacky and frankly it is. The clientInfo string needs to hold different - //model details to that of the spawning class or the info change will not be - //registered and an axis appears instead of the player model. There is zero chance - //the player can spawn with the battlesuit, hence this choice. - Com_sprintf( buffer, MAX_QPATH, "%s/%s", BG_FindModelNameForClass( PCL_HUMAN_BSUIT ), - BG_FindSkinNameForClass( PCL_HUMAN_BSUIT ) ); - } - else - { - Com_sprintf( buffer, MAX_QPATH, "%s/%s", BG_FindModelNameForClass( client->pers.classSelection ), - BG_FindSkinNameForClass( client->pers.classSelection ) ); - } - Q_strncpyz( model, buffer, sizeof( model ) ); - - //don't bother setting model type if spectating - if( client->pers.classSelection != PCL_NONE ) - { - //model segmentation - Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", - BG_FindModelNameForClass( client->pers.classSelection ) ); - - if( G_NonSegModel( filename ) ) - client->ps.persistant[ PERS_STATE ] |= PS_NONSEGMODEL; - else - client->ps.persistant[ PERS_STATE ] &= ~PS_NONSEGMODEL; - } - - // wallwalk follow - s = Info_ValueForKey( userinfo, "cg_wwFollow" ); - - if( atoi( s ) ) - client->ps.persistant[ PERS_STATE ] |= PS_WALLCLIMBINGFOLLOW; - else - client->ps.persistant[ PERS_STATE ] &= ~PS_WALLCLIMBINGFOLLOW; - - // wallwalk toggle - s = Info_ValueForKey( userinfo, "cg_wwToggle" ); - - if( atoi( s ) ) - client->ps.persistant[ PERS_STATE ] |= PS_WALLCLIMBINGTOGGLE; - else - client->ps.persistant[ PERS_STATE ] &= ~PS_WALLCLIMBINGTOGGLE; - - // teamInfo - s = Info_ValueForKey( userinfo, "teamoverlay" ); - - if( ! *s || atoi( s ) != 0 ) - client->pers.teamInfo = qtrue; - else - client->pers.teamInfo = qfalse; - - // team task (0 = none, 1 = offence, 2 = defence) - teamTask = atoi( Info_ValueForKey( userinfo, "teamtask" ) ); - // team Leader (1 = leader, 0 is normal player) - teamLeader = client->sess.teamLeader; - - // colors - strcpy( c1, Info_ValueForKey( userinfo, "color1" ) ); - strcpy( c2, Info_ValueForKey( userinfo, "color2" ) ); - strcpy( redTeam, "humans" ); - strcpy( blueTeam, "aliens" ); - - if( client->ps.pm_flags & PMF_FOLLOW ) - team = PTE_NONE; - else - team = client->ps.stats[ STAT_PTEAM ]; - - // send over a subset of the userinfo keys so other clients can - // print scoreboards, display models, and play custom sounds - s = va( "n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\g_redteam\\%s\\g_blueteam\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d", - client->pers.netname, team, model, model, redTeam, blueTeam, c1, c2, - client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader); - - trap_SetConfigstring( CS_PLAYERS + clientNum, s ); - - /*G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s );*/ -} - - -/* -=========== -ClientConnect - -Called when a player begins connecting to the server. -Called again for every map change or tournement restart. - -The session information will be valid after exit. - -Return NULL if the client should be allowed, otherwise return -a string with the reason for denial. - -Otherwise, the client will be sent the current gamestate -and will eventually get to ClientBegin. - -firstTime will be qtrue the very first time a client connects -to the server machine, but qfalse on map changes and tournement -restarts. -============ -*/ -char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) -{ - char *value; - gclient_t *client; - char userinfo[ MAX_INFO_STRING ]; - gentity_t *ent; - - ent = &g_entities[ clientNum ]; - - trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); - - // IP filtering - // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=500 - // recommanding PB based IP / GUID banning, the builtin system is pretty limited - // check to see if they are on the banned IP list - value = Info_ValueForKey( userinfo, "ip" ); - if( G_FilterPacket( value ) ) - return "You are banned from this server."; - - // check for a password - value = Info_ValueForKey( userinfo, "password" ); - - if( g_password.string[ 0 ] && Q_stricmp( g_password.string, "none" ) && - strcmp( g_password.string, value ) != 0 ) - return "Invalid password"; - - // they can connect - ent->client = level.clients + clientNum; - client = ent->client; - - memset( client, 0, sizeof(*client) ); - - client->pers.connected = CON_CONNECTING; - - // read or initialize the session data - if( firstTime || level.newSession ) - G_InitSessionData( client, userinfo ); - - G_ReadSessionData( client ); - - // get and distribute relevent paramters - G_LogPrintf( "ClientConnect: %i\n", clientNum ); - ClientUserinfoChanged( clientNum ); - - // don't do the "xxx connected" messages if they were caried over from previous level - if( firstTime ) - G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname ) ); - - // count current clients and rank for scoreboard - CalculateRanks( ); - - return NULL; -} - -/* -=========== -ClientBegin - -called when a client has finished connecting, and is ready -to be placed into the level. This will happen every level load, -and on transition between teams, but doesn't happen on respawns -============ -*/ -void ClientBegin( int clientNum ) -{ - gentity_t *ent; - gclient_t *client; - int flags; - - ent = g_entities + clientNum; - - client = level.clients + clientNum; - - if( ent->r.linked ) - trap_UnlinkEntity( ent ); - - G_InitGentity( ent ); - ent->touch = 0; - ent->pain = 0; - ent->client = client; - - client->pers.connected = CON_CONNECTED; - client->pers.enterTime = level.time; - client->pers.teamState.state = TEAM_BEGIN; - - // save eflags around this, because changing teams will - // cause this to happen with a valid entity, and we - // want to make sure the teleport bit is set right - // so the viewpoint doesn't interpolate through the - // world to the new position - flags = client->ps.eFlags; - memset( &client->ps, 0, sizeof( client->ps ) ); - client->ps.eFlags = flags; - - // locate ent at a spawn point - - ClientSpawn( ent, NULL, NULL, NULL ); - - G_InitCommandQueue( clientNum ); - - G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " entered the game\n\"", client->pers.netname ) ); - - // request the clients PTR code - G_SendCommandFromServer( ent - g_entities, "ptrcrequest" ); - - G_LogPrintf( "ClientBegin: %i\n", clientNum ); - - // count current clients and rank for scoreboard - CalculateRanks( ); -} - -/* -=========== -ClientSpawn - -Called every time a client is placed fresh in the world: -after the first ClientBegin, and after each respawn -Initializes all non-persistant parts of playerState -============ -*/ -void ClientSpawn( gentity_t *ent, gentity_t *spawn, vec3_t origin, vec3_t angles ) -{ - int index; - vec3_t spawn_origin, spawn_angles; - gclient_t *client; - int i; - clientPersistant_t saved; - clientSession_t savedSess; - int persistant[ MAX_PERSISTANT ]; - gentity_t *spawnPoint = NULL; - int flags; - int savedPing; - int teamLocal; - int eventSequence; - char userinfo[ MAX_INFO_STRING ]; - vec3_t up = { 0.0f, 0.0f, 1.0f }; - int maxAmmo, maxClips; - weapon_t weapon; - - - index = ent - g_entities; - client = ent->client; - - teamLocal = client->pers.teamSelection; - - //TA: only start client if chosen a class and joined a team - if( client->pers.classSelection == PCL_NONE && teamLocal == PTE_NONE ) - { - client->sess.sessionTeam = TEAM_SPECTATOR; - client->sess.spectatorState = SPECTATOR_FREE; - } - else if( client->pers.classSelection == PCL_NONE ) - { - client->sess.sessionTeam = TEAM_SPECTATOR; - client->sess.spectatorState = SPECTATOR_LOCKED; - } - - if( origin != NULL ) - VectorCopy( origin, spawn_origin ); - - if( angles != NULL ) - VectorCopy( angles, spawn_angles ); - - // find a spawn point - // do it before setting health back up, so farthest - // ranging doesn't count this client - if( client->sess.sessionTeam == TEAM_SPECTATOR ) - { - if( teamLocal == PTE_NONE ) - spawnPoint = SelectSpectatorSpawnPoint( spawn_origin, spawn_angles ); - else if( teamLocal == PTE_ALIENS ) - spawnPoint = SelectAlienLockSpawnPoint( spawn_origin, spawn_angles ); - else if( teamLocal == PTE_HUMANS ) - spawnPoint = SelectHumanLockSpawnPoint( spawn_origin, spawn_angles ); - } - else - { - if( spawn == NULL ) - { - G_Error( "ClientSpawn: spawn is NULL\n" ); - return; - } - - spawnPoint = spawn; - - if( ent != spawn ) - { - //start spawn animation on spawnPoint - G_setBuildableAnim( spawnPoint, BANIM_SPAWN1, qtrue ); - - if( spawnPoint->biteam == PTE_ALIENS ) - spawnPoint->clientSpawnTime = ALIEN_SPAWN_REPEAT_TIME; - else if( spawnPoint->biteam == PTE_HUMANS ) - spawnPoint->clientSpawnTime = HUMAN_SPAWN_REPEAT_TIME; - } - } - client->pers.teamState.state = TEAM_ACTIVE; - - // toggle the teleport bit so the client knows to not lerp - flags = ent->client->ps.eFlags & ( EF_TELEPORT_BIT | EF_VOTED | EF_TEAMVOTED ); - flags ^= EF_TELEPORT_BIT; - - // clear everything but the persistant data - - saved = client->pers; - savedSess = client->sess; - savedPing = client->ps.ping; - - for( i = 0; i < MAX_PERSISTANT; i++ ) - persistant[ i ] = client->ps.persistant[ i ]; - - eventSequence = client->ps.eventSequence; - memset( client, 0, sizeof( *client ) ); - - client->pers = saved; - client->sess = savedSess; - client->ps.ping = savedPing; - client->lastkilled_client = -1; - - for( i = 0; i < MAX_PERSISTANT; i++ ) - client->ps.persistant[ i ] = persistant[ i ]; - - client->ps.eventSequence = eventSequence; - - // increment the spawncount so the client will detect the respawn - client->ps.persistant[ PERS_SPAWN_COUNT ]++; - client->ps.persistant[ PERS_TEAM ] = client->sess.sessionTeam; - - client->airOutTime = level.time + 12000; - - trap_GetUserinfo( index, userinfo, sizeof( userinfo ) ); - client->ps.eFlags = flags; - - //Com_Printf( "ent->client->pers->pclass = %i\n", ent->client->pers.classSelection ); - - ent->s.groundEntityNum = ENTITYNUM_NONE; - ent->client = &level.clients[ index ]; - ent->takedamage = qtrue; - ent->inuse = qtrue; - ent->classname = "player"; - ent->r.contents = CONTENTS_BODY; - ent->clipmask = MASK_PLAYERSOLID; - ent->die = player_die; - ent->waterlevel = 0; - ent->watertype = 0; - ent->flags = 0; - - //TA: calculate each client's acceleration - ent->evaluateAcceleration = qtrue; - - client->ps.stats[ STAT_WEAPONS ] = 0; - client->ps.stats[ STAT_WEAPONS2 ] = 0; - client->ps.stats[ STAT_SLOTS ] = 0; - - client->ps.eFlags = flags; - client->ps.clientNum = index; - - BG_FindBBoxForClass( ent->client->pers.classSelection, ent->r.mins, ent->r.maxs, NULL, NULL, NULL ); - - if( client->sess.sessionTeam != TEAM_SPECTATOR ) - client->pers.maxHealth = client->ps.stats[ STAT_MAX_HEALTH ] = - BG_FindHealthForClass( ent->client->pers.classSelection ); - else - client->pers.maxHealth = client->ps.stats[ STAT_MAX_HEALTH ] = 100; - - // clear entity values - if( ent->client->pers.classSelection == PCL_HUMAN ) - { - BG_AddWeaponToInventory( WP_BLASTER, client->ps.stats ); - BG_AddUpgradeToInventory( UP_MEDKIT, client->ps.stats ); - weapon = client->pers.humanItemSelection; - } - else if( client->sess.sessionTeam != TEAM_SPECTATOR ) - weapon = BG_FindStartWeaponForClass( ent->client->pers.classSelection ); - else - weapon = WP_NONE; - - BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips ); - BG_AddWeaponToInventory( weapon, client->ps.stats ); - BG_PackAmmoArray( weapon, client->ps.ammo, client->ps.powerups, maxAmmo, maxClips ); - - ent->client->ps.stats[ STAT_PCLASS ] = ent->client->pers.classSelection; - ent->client->ps.stats[ STAT_PTEAM ] = ent->client->pers.teamSelection; - - ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE; - ent->client->ps.stats[ STAT_STATE ] = 0; - VectorSet( ent->client->ps.grapplePoint, 0.0f, 0.0f, 1.0f ); - - // health will count down towards max_health - ent->health = client->ps.stats[ STAT_HEALTH ] = client->ps.stats[ STAT_MAX_HEALTH ]; //* 1.25; - - //if evolving scale health - if( ent == spawn ) - { - ent->health *= ent->client->pers.evolveHealthFraction; - client->ps.stats[ STAT_HEALTH ] *= ent->client->pers.evolveHealthFraction; - } - - //clear the credits array - for( i = 0; i < MAX_CLIENTS; i++ ) - ent->credits[ i ] = 0; - - client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA; - - G_SetOrigin( ent, spawn_origin ); - VectorCopy( spawn_origin, client->ps.origin ); - -#define UP_VEL 150.0f -#define F_VEL 50.0f - - //give aliens some spawn velocity - if( client->sess.sessionTeam != TEAM_SPECTATOR && - client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - { - if( ent == spawn ) - { - //evolution particle system - G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, DirToByte( up ) ); - } - else - { - spawn_angles[ YAW ] += 180.0f; - AngleNormalize360( spawn_angles[ YAW ] ); - - if( spawnPoint->s.origin2[ 2 ] > 0.0f ) - { - vec3_t forward, dir; - - AngleVectors( spawn_angles, forward, NULL, NULL ); - VectorScale( forward, F_VEL, forward ); - VectorAdd( spawnPoint->s.origin2, forward, dir ); - VectorNormalize( dir ); - - VectorScale( dir, UP_VEL, client->ps.velocity ); - } - - G_AddPredictableEvent( ent, EV_PLAYER_RESPAWN, 0 ); - } - } - else if( client->sess.sessionTeam != TEAM_SPECTATOR && - client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - spawn_angles[ YAW ] += 180.0f; - AngleNormalize360( spawn_angles[ YAW ] ); - } - - // the respawned flag will be cleared after the attack and jump keys come up - client->ps.pm_flags |= PMF_RESPAWNED; - - trap_GetUsercmd( client - level.clients, &ent->client->pers.cmd ); - SetClientViewAngle( ent, spawn_angles ); - - if( !( client->sess.sessionTeam == TEAM_SPECTATOR ) ) - { - /*G_KillBox( ent );*/ //blame this if a newly spawned client gets stuck in another - trap_LinkEntity( ent ); - - // force the base weapon up - client->ps.weapon = WP_NONE; - client->ps.weaponstate = WEAPON_READY; - } - - // don't allow full run speed for a bit - client->ps.pm_flags |= PMF_TIME_KNOCKBACK; - client->ps.pm_time = 100; - - client->respawnTime = level.time; - client->lastKillTime = level.time; - - client->inactivityTime = level.time + g_inactivity.integer * 1000; - client->latched_buttons = 0; - - // set default animations - client->ps.torsoAnim = TORSO_STAND; - client->ps.legsAnim = LEGS_IDLE; - - if( level.intermissiontime ) - MoveClientToIntermission( ent ); - else - { - // fire the targets of the spawn point - if( !spawn ) - G_UseTargets( spawnPoint, ent ); - - // select the highest weapon number available, after any - // spawn given items have fired - client->ps.weapon = 1; - - for( i = WP_NUM_WEAPONS - 1; i > 0 ; i-- ) - { - if( BG_InventoryContainsWeapon( i, client->ps.stats ) ) - { - client->ps.weapon = i; - break; - } - } - } - - // run a client frame to drop exactly to the floor, - // initialize animations and other things - client->ps.commandTime = level.time - 100; - ent->client->pers.cmd.serverTime = level.time; - ClientThink( ent-g_entities ); - - // positively link the client, even if the command times are weird - if( client->sess.sessionTeam != TEAM_SPECTATOR ) - { - BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); - VectorCopy( ent->client->ps.origin, ent->r.currentOrigin ); - trap_LinkEntity( ent ); - } - - //TA: must do this here so the number of active clients is calculated - CalculateRanks( ); - - // run the presend to set anything else - ClientEndFrame( ent ); - - // clear entity state values - BG_PlayerStateToEntityState( &client->ps, &ent->s, qtrue ); -} - - -/* -=========== -ClientDisconnect - -Called when a player drops from the server. -Will not be called between levels. - -This should NOT be called directly by any game logic, -call trap_DropClient(), which will call this and do -server system housekeeping. -============ -*/ -void ClientDisconnect( int clientNum ) -{ - gentity_t *ent; - gentity_t *tent; - int i; - - ent = g_entities + clientNum; - - if( !ent->client ) - return; - - // stop any following clients - for( i = 0; i < level.maxclients; i++ ) - { - if( level.clients[ i ].sess.sessionTeam == TEAM_SPECTATOR && - level.clients[ i ].sess.spectatorState == SPECTATOR_FOLLOW && - level.clients[ i ].sess.spectatorClient == clientNum ) - { - if( !G_FollowNewClient( &g_entities[ i ], 1 ) ) - G_StopFollowing( &g_entities[ i ] ); - } - } - - // send effect if they were completely connected - if( ent->client->pers.connected == CON_CONNECTED && - ent->client->sess.sessionTeam != TEAM_SPECTATOR ) - { - tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_OUT ); - tent->s.clientNum = ent->s.clientNum; - } - - G_LogPrintf( "ClientDisconnect: %i\n", clientNum ); - - trap_UnlinkEntity( ent ); - ent->s.modelindex = 0; - ent->inuse = qfalse; - ent->classname = "disconnected"; - ent->client->pers.connected = CON_DISCONNECTED; - ent->client->ps.persistant[ PERS_TEAM ] = TEAM_FREE; - ent->client->sess.sessionTeam = TEAM_FREE; - - trap_SetConfigstring( CS_PLAYERS + clientNum, ""); - - CalculateRanks( ); -} diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c deleted file mode 100644 index 819fbb75..00000000 --- a/src/game/g_cmds.c +++ /dev/null @@ -1,2305 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "g_local.h" - -/* -================== -G_SanitiseName - -Remove case and control characters from a player name -================== -*/ -void G_SanitiseName( char *in, char *out ) -{ - while( *in ) - { - if( *in == 27 ) - { - in += 2; // skip color code - continue; - } - - if( *in < 32 ) - { - in++; - continue; - } - - *out++ = tolower( *in++ ); - } - - *out = 0; -} - -/* -================== -G_ClientNumberFromString - -Returns a player number for either a number or name string -Returns -1 if invalid -================== -*/ -int G_ClientNumberFromString( gentity_t *to, char *s ) -{ - gclient_t *cl; - int idnum; - char s2[ MAX_STRING_CHARS ]; - char n2[ MAX_STRING_CHARS ]; - - // numeric values are just slot numbers - if( s[ 0 ] >= '0' && s[ 0 ] <= '9' ) - { - idnum = atoi( s ); - - if( idnum < 0 || idnum >= level.maxclients ) - { - G_SendCommandFromServer( to - g_entities, va( "print \"Bad client slot: %i\n\"", idnum ) ); - return -1; - } - - cl = &level.clients[ idnum ]; - - if( cl->pers.connected != CON_CONNECTED ) - { - G_SendCommandFromServer( to - g_entities, va( "print \"Client %i is not active\n\"", idnum ) ); - return -1; - } - - return idnum; - } - - // check for a name match - G_SanitiseName( s, s2 ); - - for( idnum = 0, cl = level.clients; idnum < level.maxclients; idnum++, cl++ ) - { - if( cl->pers.connected != CON_CONNECTED ) - continue; - - G_SanitiseName( cl->pers.netname, n2 ); - - if( !strcmp( n2, s2 ) ) - return idnum; - } - - G_SendCommandFromServer( to - g_entities, va( "print \"User %s is not on the server\n\"", s ) ); - return -1; -} - -/* -================== -ScoreboardMessage - -================== -*/ -void ScoreboardMessage( gentity_t *ent ) -{ - char entry[ 1024 ]; - char string[ 1400 ]; - int stringlength; - int i, j; - gclient_t *cl; - int numSorted; - weapon_t weapon = WP_NONE; - upgrade_t upgrade = UP_NONE; - - // send the latest information on all clients - string[ 0 ] = 0; - stringlength = 0; - - numSorted = level.numConnectedClients; - - for( i = 0; i < numSorted; i++ ) - { - int ping; - - cl = &level.clients[ level.sortedClients[ i ] ]; - - if( cl->pers.connected == CON_CONNECTING ) - ping = -1; - else - ping = cl->ps.ping < 999 ? cl->ps.ping : 999; - - if( cl->ps.stats[ STAT_HEALTH ] > 0 ) - { - weapon = cl->ps.weapon; - - if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, cl->ps.stats ) ) - upgrade = UP_BATTLESUIT; - else if( BG_InventoryContainsUpgrade( UP_JETPACK, cl->ps.stats ) ) - upgrade = UP_JETPACK; - else if( BG_InventoryContainsUpgrade( UP_BATTPACK, cl->ps.stats ) ) - upgrade = UP_BATTPACK; - else if( BG_InventoryContainsUpgrade( UP_HELMET, cl->ps.stats ) ) - upgrade = UP_HELMET; - else if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, cl->ps.stats ) ) - upgrade = UP_LIGHTARMOUR; - else - upgrade = UP_NONE; - } - else - { - weapon = WP_NONE; - upgrade = UP_NONE; - } - - Com_sprintf( entry, sizeof( entry ), - " %d %d %d %d %d %d", level.sortedClients[ i ], cl->ps.persistant[ PERS_SCORE ], - ping, ( level.time - cl->pers.enterTime ) / 60000, weapon, upgrade ); - - j = strlen( entry ); - - if( stringlength + j > 1024 ) - break; - - strcpy( string + stringlength, entry ); - stringlength += j; - } - - G_SendCommandFromServer( ent-g_entities, va( "scores %i %i %i%s", i, - level.alienKills, level.humanKills, string ) ); -} - - -/* -================== -Cmd_Score_f - -Request current scoreboard information -================== -*/ -void Cmd_Score_f( gentity_t *ent ) -{ - ScoreboardMessage( ent ); -} - - - -/* -================== -CheatsOk -================== -*/ -qboolean CheatsOk( gentity_t *ent ) -{ - if( !g_cheats.integer ) - { - G_SendCommandFromServer( ent-g_entities, va( "print \"Cheats are not enabled on this server\n\"" ) ); - return qfalse; - } - - if( ent->health <= 0 ) - { - G_SendCommandFromServer( ent-g_entities, va( "print \"You must be alive to use this command\n\"" ) ); - return qfalse; - } - - return qtrue; -} - - -/* -================== -ConcatArgs -================== -*/ -char *ConcatArgs( int start ) -{ - int i, c, tlen; - static char line[ MAX_STRING_CHARS ]; - int len; - char arg[ MAX_STRING_CHARS ]; - - len = 0; - c = trap_Argc( ); - - for( i = start; i < c; i++ ) - { - trap_Argv( i, arg, sizeof( arg ) ); - tlen = strlen( arg ); - - if( len + tlen >= MAX_STRING_CHARS - 1 ) - break; - - memcpy( line + len, arg, tlen ); - len += tlen; - - if( i != c - 1 ) - { - line[ len ] = ' '; - len++; - } - } - - line[ len ] = 0; - - return line; -} - - -/* -================== -Cmd_Give_f - -Give items to a client -================== -*/ -void Cmd_Give_f( gentity_t *ent ) -{ - char *name; - qboolean give_all; - - if( !CheatsOk( ent ) ) - return; - - name = ConcatArgs( 1 ); - - if( Q_stricmp( name, "all" ) == 0 ) - give_all = qtrue; - else - give_all = qfalse; - - if( give_all || Q_stricmp( name, "health" ) == 0 ) - { - ent->health = ent->client->ps.stats[ STAT_MAX_HEALTH ]; - if( !give_all ) - return; - } - - if( give_all || Q_stricmpn( name, "funds", 5 ) == 0 ) - { - int credits = atoi( name + 6 ); - - if( !credits ) - G_AddCreditToClient( ent->client, 1, qtrue ); - else - G_AddCreditToClient( ent->client, credits, qtrue ); - - if( !give_all ) - return; - } -} - - -/* -================== -Cmd_God_f - -Sets client to godmode - -argv(0) god -================== -*/ -void Cmd_God_f( gentity_t *ent ) -{ - char *msg; - - if( !CheatsOk( ent ) ) - return; - - ent->flags ^= FL_GODMODE; - - if( !( ent->flags & FL_GODMODE ) ) - msg = "godmode OFF\n"; - else - msg = "godmode ON\n"; - - G_SendCommandFromServer( ent - g_entities, va( "print \"%s\"", msg ) ); -} - - -/* -================== -Cmd_Notarget_f - -Sets client to notarget - -argv(0) notarget -================== -*/ -void Cmd_Notarget_f( gentity_t *ent ) -{ - char *msg; - - if( !CheatsOk( ent ) ) - return; - - ent->flags ^= FL_NOTARGET; - - if( !( ent->flags & FL_NOTARGET ) ) - msg = "notarget OFF\n"; - else - msg = "notarget ON\n"; - - G_SendCommandFromServer( ent - g_entities, va( "print \"%s\"", msg ) ); -} - - -/* -================== -Cmd_Noclip_f - -argv(0) noclip -================== -*/ -void Cmd_Noclip_f( gentity_t *ent ) -{ - char *msg; - - if( !CheatsOk( ent ) ) - return; - - if( ent->client->noclip ) - msg = "noclip OFF\n"; - else - msg = "noclip ON\n"; - - ent->client->noclip = !ent->client->noclip; - - G_SendCommandFromServer( ent - g_entities, va( "print \"%s\"", msg ) ); -} - - -/* -================== -Cmd_LevelShot_f - -This is just to help generate the level pictures -for the menus. It goes to the intermission immediately -and sends over a command to the client to resize the view, -hide the scoreboard, and take a special screenshot -================== -*/ -void Cmd_LevelShot_f( gentity_t *ent ) -{ - if( !CheatsOk( ent ) ) - return; - - BeginIntermission( ); - G_SendCommandFromServer( ent - g_entities, "clientLevelShot" ); -} - -/* -================= -Cmd_Kill_f -================= -*/ -void Cmd_Kill_f( gentity_t *ent ) -{ - if( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) - return; - - if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_NONE ) - return; - - if( ent->client->ps.stats[ STAT_STATE ] & SS_INFESTING ) - return; - - if( ent->client->ps.stats[ STAT_STATE ] & SS_HOVELING ) - { - G_SendCommandFromServer( ent-g_entities, "print \"Leave the hovel first (use your destroy key)\n\"" ); - return; - } - - if( ent->health <= 0 ) - return; - - if( g_cheats.integer ) - { - ent->flags &= ~FL_GODMODE; - ent->client->ps.stats[ STAT_HEALTH ] = ent->health = 0; - player_die( ent, ent, ent, 100000, MOD_SUICIDE ); - } - else - { - if( ent->suicideTime == 0 ) - { - G_SendCommandFromServer( ent-g_entities, "print \"You will suicide in 20 seconds\n\"" ); - ent->suicideTime = level.time + 20000; - } - else if( ent->suicideTime > level.time ) - { - G_SendCommandFromServer( ent-g_entities, "print \"Suicide cancelled\n\"" ); - ent->suicideTime = 0; - } - } -} - -/* -================= -G_ChangeTeam -================= -*/ -void G_ChangeTeam( gentity_t *ent, pTeam_t newTeam ) -{ - pTeam_t oldTeam = ent->client->pers.teamSelection; - - ent->client->pers.teamSelection = newTeam; - - if( oldTeam != newTeam ) - { - //if the client is in a queue make sure they are removed from it before changing - if( oldTeam == PTE_ALIENS ) - G_RemoveFromSpawnQueue( &level.alienSpawnQueue, ent->client->ps.clientNum ); - else if( oldTeam == PTE_HUMANS ) - G_RemoveFromSpawnQueue( &level.humanSpawnQueue, ent->client->ps.clientNum ); - - level.bankCredits[ ent->client->ps.clientNum ] = 0; - ent->client->ps.persistant[ PERS_CREDIT ] = 0; - ent->client->ps.persistant[ PERS_SCORE ] = 0; - ent->client->pers.classSelection = PCL_NONE; - ClientSpawn( ent, NULL, NULL, NULL ); - } - - ent->client->pers.joinedATeam = qtrue; - - //update ClientInfo - ClientUserinfoChanged( ent->client->ps.clientNum ); -} - -/* -================= -Cmd_Team_f -================= -*/ -void Cmd_Team_f( gentity_t *ent ) -{ - pTeam_t team; - char s[ MAX_TOKEN_CHARS ]; - - trap_Argv( 1, s, sizeof( s ) ); - - if( !strlen( s ) ) - { - G_SendCommandFromServer( ent-g_entities, va("print \"team: %i\n\"", ent->client->pers.teamSelection ) ); - return; - } - - if( !Q_stricmp( s, "spectate" ) ) - team = PTE_NONE; - else if( !Q_stricmp( s, "aliens" ) ) - { - if( g_teamForceBalance.integer && level.numAlienClients > level.numHumanClients ) - { - G_TriggerMenu( ent->client->ps.clientNum, MN_A_TEAMFULL ); - return; - } - - team = PTE_ALIENS; - } - else if( !Q_stricmp( s, "humans" ) ) - { - if( g_teamForceBalance.integer && level.numHumanClients > level.numAlienClients ) - { - G_TriggerMenu( ent->client->ps.clientNum, MN_H_TEAMFULL ); - return; - } - - team = PTE_HUMANS; - } - else if( !Q_stricmp( s, "auto" ) ) - { - if( level.numHumanClients > level.numAlienClients ) - team = PTE_ALIENS; - else if( level.numHumanClients < level.numAlienClients ) - team = PTE_HUMANS; - else - team = PTE_ALIENS + ( rand( ) % 2 ); - } - else - { - G_SendCommandFromServer( ent-g_entities, va( "print \"Unknown team: %s\n\"", s ) ); - return; - } - - G_ChangeTeam( ent, team ); - - if( team == PTE_ALIENS ) - G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " joined the aliens\n\"", ent->client->pers.netname ) ); - else if( team == PTE_HUMANS ) - G_SendCommandFromServer( -1, va( "print \"%s" S_COLOR_WHITE " joined the humans\n\"", ent->client->pers.netname ) ); -} - - -/* -================== -G_Say -================== -*/ -static void G_SayTo( gentity_t *ent, gentity_t *other, int mode, int color, const char *name, const char *message ) -{ - if( !other ) - return; - - if( !other->inuse ) - return; - - if( !other->client ) - return; - - if( other->client->pers.connected != CON_CONNECTED ) - return; - - if( mode == SAY_TEAM && !OnSameTeam( ent, other ) ) - return; - - G_SendCommandFromServer( other-g_entities, va( "%s \"%s%c%c%s\"", - mode == SAY_TEAM ? "tchat" : "chat", - name, Q_COLOR_ESCAPE, color, message ) ); -} - -#define EC "\x19" - -void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText ) -{ - int j; - gentity_t *other; - int color; - char name[ 64 ]; - // don't let text be too long for malicious reasons - char text[ MAX_SAY_TEXT ]; - char location[ 64 ]; - - switch( mode ) - { - default: - case SAY_ALL: - G_LogPrintf( "say: %s: %s\n", ent->client->pers.netname, chatText ); - Com_sprintf( name, sizeof( name ), "%s%c%c"EC": ", ent->client->pers.netname, - Q_COLOR_ESCAPE, COLOR_WHITE ); - color = COLOR_GREEN; - break; - - case SAY_TEAM: - G_LogPrintf( "sayteam: %s: %s\n", ent->client->pers.netname, chatText ); - if( Team_GetLocationMsg( ent, location, sizeof( location ) ) ) - Com_sprintf( name, sizeof( name ), EC"(%s%c%c"EC") (%s)"EC": ", - ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location ); - else - Com_sprintf( name, sizeof( name ), EC"(%s%c%c"EC")"EC": ", - ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); - color = COLOR_CYAN; - break; - - case SAY_TELL: - if( target && - target->client->ps.stats[ STAT_PTEAM ] == ent->client->ps.stats[ STAT_PTEAM ] && - Team_GetLocationMsg( ent, location, sizeof( location ) ) ) - Com_sprintf( name, sizeof( name ), EC"[%s%c%c"EC"] (%s)"EC": ", - ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE, location ); - else - Com_sprintf( name, sizeof( name ), EC"[%s%c%c"EC"]"EC": ", - ent->client->pers.netname, Q_COLOR_ESCAPE, COLOR_WHITE ); - color = COLOR_MAGENTA; - break; - } - - Q_strncpyz( text, chatText, sizeof( text ) ); - - if( target ) - { - G_SayTo( ent, target, mode, color, name, text ); - return; - } - - // echo the text to the console - if( g_dedicated.integer ) - G_Printf( "%s%s\n", name, text); - - // send it to all the apropriate clients - for( j = 0; j < level.maxclients; j++ ) - { - other = &g_entities[ j ]; - G_SayTo( ent, other, mode, color, name, text ); - } -} - - -/* -================== -Cmd_Say_f -================== -*/ -static void Cmd_Say_f( gentity_t *ent, int mode, qboolean arg0 ) -{ - char *p; - - if( trap_Argc( ) < 2 && !arg0 ) - return; - - if( arg0 ) - p = ConcatArgs( 0 ); - else - p = ConcatArgs( 1 ); - - G_Say( ent, NULL, mode, p ); -} - -/* -================== -Cmd_Tell_f -================== -*/ -static void Cmd_Tell_f( gentity_t *ent ) -{ - int targetNum; - gentity_t *target; - char *p; - char arg[MAX_TOKEN_CHARS]; - - if( trap_Argc( ) < 2 ) - return; - - trap_Argv( 1, arg, sizeof( arg ) ); - targetNum = atoi( arg ); - - if( targetNum < 0 || targetNum >= level.maxclients ) - return; - - target = &g_entities[ targetNum ]; - if( !target || !target->inuse || !target->client ) - return; - - p = ConcatArgs( 2 ); - - G_LogPrintf( "tell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, p ); - G_Say( ent, target, SAY_TELL, p ); - // don't tell to the player self if it was already directed to this player - // also don't send the chat back to a bot - if( ent != target && !( ent->r.svFlags & SVF_BOT ) ) - G_Say( ent, ent, SAY_TELL, p ); -} - -/* -================== -Cmd_Where_f -================== -*/ -void Cmd_Where_f( gentity_t *ent ) -{ - G_SendCommandFromServer( ent-g_entities, va( "print \"%s\n\"", vtos( ent->s.origin ) ) ); -} - -/* -================== -Cmd_CallVote_f -================== -*/ -void Cmd_CallVote_f( gentity_t *ent ) -{ - int i; - char arg1[ MAX_STRING_TOKENS ]; - char arg2[ MAX_STRING_TOKENS ]; - - if( !g_allowVote.integer ) - { - G_SendCommandFromServer( ent-g_entities, "print \"Voting not allowed here\n\"" ); - return; - } - - if( level.voteTime ) - { - G_SendCommandFromServer( ent-g_entities, "print \"A vote is already in progress\n\"" ); - return; - } - - if( ent->client->pers.voteCount >= MAX_VOTE_COUNT ) - { - G_SendCommandFromServer( ent-g_entities, "print \"You have called the maximum number of votes\n\"" ); - return; - } - - if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_NONE ) - { - G_SendCommandFromServer( ent-g_entities, "print \"Not allowed to call a vote as spectator\n\"" ); - return; - } - - // make sure it is a valid command to vote on - trap_Argv( 1, arg1, sizeof( arg1 ) ); - trap_Argv( 2, arg2, sizeof( arg2 ) ); - - if( strchr( arg1, ';' ) || strchr( arg2, ';' ) ) - { - G_SendCommandFromServer( ent-g_entities, "print \"Invalid vote string\n\"" ); - return; - } - - if( !Q_stricmp( arg1, "map_restart" ) ) { } - else if( !Q_stricmp( arg1, "nextmap" ) ) { } - else if( !Q_stricmp( arg1, "map" ) ) { } - else if( !Q_stricmp( arg1, "kick" ) ) { } - else if( !Q_stricmp( arg1, "clientkick" ) ) { } - else if( !Q_stricmp( arg1, "timelimit" ) ) { } - else - { - G_SendCommandFromServer( ent-g_entities, "print \"Invalid vote string\n\"" ); - G_SendCommandFromServer( ent-g_entities, "print \"Vote commands are: map_restart, nextmap, map , " - "kick , clientkick , " - "timelimit