mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
420 lines
No EOL
11 KiB
C++
420 lines
No EOL
11 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
|
|
This file is part of Quake III Arena source code.
|
|
|
|
Quake III Arena source code is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
Quake III Arena source code is distributed in the hope that it will be
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Quake III Arena source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
//
|
|
// bg_misc.c -- both games misc functions, all completely stateless
|
|
|
|
#include "../qcommon/q_shared.h"
|
|
#include "bg_public.h"
|
|
|
|
/*
|
|
================
|
|
BG_EvaluateTrajectoryDelta
|
|
For determining velocity at a given time
|
|
================
|
|
*/
|
|
void BG_EvaluateTrajectoryDelta(const trajectory_t *tr, int atTime, vec3_t result) {}
|
|
|
|
// FIXME: OLD Q3 CODE
|
|
#if 0
|
|
|
|
/*
|
|
================
|
|
BG_CanItemBeGrabbed
|
|
|
|
Returns false if the item should not be picked up.
|
|
This needs to be the same for client side prediction and server use.
|
|
================
|
|
*/
|
|
qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps )
|
|
{
|
|
|
|
gitem_t *item;
|
|
# ifdef MISSIONPACK
|
|
int upperBound;
|
|
# endif
|
|
|
|
if ( ent->modelindex < 1 || ent->modelindex >= bg_numItems ) {
|
|
Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: index out of range" );
|
|
}
|
|
|
|
item = &bg_itemlist[ent->modelindex];
|
|
|
|
switch( item->giType ) {
|
|
case IT_WEAPON:
|
|
return qtrue; // weapons are always picked up
|
|
|
|
case IT_AMMO:
|
|
if ( ps->ammo[ item->giTag ] >= 200 ) {
|
|
return qfalse; // can't hold any more
|
|
}
|
|
return qtrue;
|
|
|
|
case IT_ARMOR:
|
|
# ifdef MISSIONPACK
|
|
if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_SCOUT ) {
|
|
return qfalse;
|
|
}
|
|
|
|
// we also clamp armor to the maxhealth for handicapping
|
|
if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
|
|
upperBound = ps->stats[STAT_MAX_HEALTH];
|
|
}
|
|
else {
|
|
upperBound = ps->stats[STAT_MAX_HEALTH] * 2;
|
|
}
|
|
|
|
if ( ps->stats[STAT_ARMOR] >= upperBound ) {
|
|
return qfalse;
|
|
}
|
|
# else
|
|
if ( ps->stats[STAT_ARMOR] >= ps->stats[STAT_MAX_HEALTH] * 2 ) {
|
|
return qfalse;
|
|
}
|
|
# endif
|
|
return qtrue;
|
|
|
|
case IT_HEALTH:
|
|
// small and mega healths will go over the max, otherwise
|
|
// don't pick up if already at max
|
|
# ifdef MISSIONPACK
|
|
if( bg_itemlist[ps->stats[STAT_PERSISTANT_POWERUP]].giTag == PW_GUARD ) {
|
|
upperBound = ps->stats[STAT_MAX_HEALTH];
|
|
}
|
|
else
|
|
# endif
|
|
if ( item->quantity == 5 || item->quantity == 100 ) {
|
|
if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] * 2 ) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] ) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
|
|
case IT_POWERUP:
|
|
return qtrue; // powerups are always picked up
|
|
|
|
# ifdef MISSIONPACK
|
|
case IT_PERSISTANT_POWERUP:
|
|
// can only hold one item at a time
|
|
if ( ps->stats[STAT_PERSISTANT_POWERUP] ) {
|
|
return qfalse;
|
|
}
|
|
|
|
// check team only
|
|
if( ( ent->generic1 & 2 ) && ( ps->stats[STAT_TEAM] != TEAM_RED ) ) {
|
|
return qfalse;
|
|
}
|
|
if( ( ent->generic1 & 4 ) && ( ps->stats[STAT_TEAM] != TEAM_BLUE ) ) {
|
|
return qfalse;
|
|
}
|
|
|
|
return qtrue;
|
|
# endif
|
|
|
|
case IT_TEAM: // team items, such as flags
|
|
# ifdef MISSIONPACK
|
|
if( gametype == GT_1FCTF ) {
|
|
// neutral flag can always be picked up
|
|
if( item->giTag == PW_NEUTRALFLAG ) {
|
|
return qtrue;
|
|
}
|
|
if (ps->stats[STAT_TEAM] == TEAM_RED) {
|
|
if (item->giTag == PW_BLUEFLAG && ps->powerups[PW_NEUTRALFLAG] ) {
|
|
return qtrue;
|
|
}
|
|
} else if (ps->stats[STAT_TEAM] == TEAM_BLUE) {
|
|
if (item->giTag == PW_REDFLAG && ps->powerups[PW_NEUTRALFLAG] ) {
|
|
return qtrue;
|
|
}
|
|
}
|
|
}
|
|
# endif
|
|
if( gametype == GT_CTF ) {
|
|
// ent->modelindex2 is non-zero on items if they are dropped
|
|
// we need to know this because we can pick up our dropped flag (and return it)
|
|
// but we can't pick up our flag at base
|
|
if (ps->stats[STAT_TEAM] == TEAM_RED) {
|
|
if (item->giTag == PW_BLUEFLAG ||
|
|
(item->giTag == PW_REDFLAG && ent->modelindex2) ||
|
|
(item->giTag == PW_REDFLAG && ps->powerups[PW_BLUEFLAG]) )
|
|
return qtrue;
|
|
} else if (ps->stats[STAT_TEAM] == TEAM_BLUE) {
|
|
if (item->giTag == PW_REDFLAG ||
|
|
(item->giTag == PW_BLUEFLAG && ent->modelindex2) ||
|
|
(item->giTag == PW_BLUEFLAG && ps->powerups[PW_REDFLAG]) )
|
|
return qtrue;
|
|
}
|
|
}
|
|
|
|
# ifdef MISSIONPACK
|
|
if( gametype == GT_HARVESTER ) {
|
|
return qtrue;
|
|
}
|
|
# endif
|
|
return qfalse;
|
|
|
|
case IT_HOLDABLE:
|
|
// can only hold one item at a time
|
|
if ( ps->stats[STAT_HOLDABLE_ITEM] ) {
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
|
|
case IT_BAD:
|
|
Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: IT_BAD" );
|
|
default:
|
|
# ifndef Q3_VM
|
|
# ifndef NDEBUG
|
|
Com_Printf("BG_CanItemBeGrabbed: unknown enum %d\n", item->giType );
|
|
# endif
|
|
# endif
|
|
break;
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
//======================================================================
|
|
|
|
/*
|
|
================
|
|
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;
|
|
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;
|
|
default:
|
|
Com_Error( ERR_DROP, "BG_EvaluateTrajectoryDelta: unknown trType: %i", tr->trTime );
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
========================
|
|
BG_TouchJumpPad
|
|
========================
|
|
*/
|
|
void BG_TouchJumpPad(playerState_t *ps, entityState_t *jumppad) {}
|
|
|
|
/*
|
|
========================
|
|
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)
|
|
{
|
|
if (ps->pm_type == PM_NOCLIP) {
|
|
s->eType = 0; //ET_INVISIBLE;
|
|
//} else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) {
|
|
// s->eType = 0;//ET_INVISIBLE;
|
|
} else {
|
|
s->eType = ET_PLAYER;
|
|
}
|
|
|
|
s->number = ps->clientNum;
|
|
|
|
VectorCopy(ps->origin, s->origin);
|
|
if (snap) {
|
|
SnapVector(s->origin);
|
|
}
|
|
// set the trDelta for flag direction
|
|
VectorCopy(ps->velocity, s->pos.trDelta);
|
|
|
|
VectorCopy(ps->viewangles, s->angles);
|
|
if (snap) {
|
|
SnapVector(s->angles);
|
|
}
|
|
|
|
//s->angles2[YAW] = ps->movementDir;
|
|
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;
|
|
//}
|
|
|
|
s->groundEntityNum = ps->groundEntityNum;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
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)
|
|
{
|
|
if (ps->pm_type == PM_NOCLIP) {
|
|
s->eType = 0; //ET_INVISIBLE;
|
|
//} else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) {
|
|
// s->eType = 0;//ET_INVISIBLE;
|
|
} else {
|
|
s->eType = ET_PLAYER;
|
|
}
|
|
|
|
s->number = ps->clientNum;
|
|
|
|
VectorCopy(ps->origin, s->origin);
|
|
if (snap) {
|
|
SnapVector(s->origin);
|
|
}
|
|
// 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;
|
|
|
|
VectorCopy(ps->viewangles, s->angles);
|
|
if (snap) {
|
|
SnapVector(s->angles);
|
|
}
|
|
s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number
|
|
// so corpses can also reference the proper config
|
|
|
|
s->groundEntityNum = ps->groundEntityNum;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
BG_MapCGMToProtocol
|
|
|
|
This is done after each set of usercmd_t on the server,
|
|
and after local prediction on the client
|
|
========================
|
|
*/
|
|
int BG_MapCGMToProtocol(int protocol, int messageNumber)
|
|
{
|
|
int newMessageNumber = messageNumber;
|
|
|
|
if (protocol >= PROTOCOL_MOHTA_MIN) {
|
|
// no need translation
|
|
return messageNumber;
|
|
}
|
|
|
|
if (messageNumber > 40) {
|
|
// unsupported...
|
|
return messageNumber;
|
|
}
|
|
|
|
if (messageNumber >= 17) {
|
|
return messageNumber - 3;
|
|
}
|
|
|
|
if (messageNumber == 15 || messageNumber == 16) {
|
|
// return explosion effect number 2
|
|
return 14;
|
|
}
|
|
|
|
if (messageNumber > 10) {
|
|
return messageNumber - 1;
|
|
}
|
|
|
|
return newMessageNumber;
|
|
} |