📄 g_combat.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 Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// g_combat.c
#include "g_local.h"
/*
============
ScorePlum
============
*/
void ScorePlum( gentity_t *ent, vec3_t origin, int score ) {
gentity_t *plum;
plum = G_TempEntity( origin, EV_SCOREPLUM );
// only send this temp entity to a single client
plum->r.svFlags |= SVF_SINGLECLIENT;
plum->r.singleClient = ent->s.number;
//
plum->s.otherEntityNum = ent->s.number;
plum->s.time = score;
}
/*
============
AddScore
Adds score to both the client and his team
============
*/
void AddScore( gentity_t *ent, vec3_t origin, int score ) {
if ( !ent->client ) {
return;
}
// no scoring during pre-match warmup
if ( level.warmupTime ) {
return;
}
// show score plum
ScorePlum(ent, origin, score);
//
ent->client->ps.persistant[PERS_SCORE] += score;
if ( g_gametype.integer == GT_TEAM )
level.teamScores[ ent->client->ps.persistant[PERS_TEAM] ] += score;
CalculateRanks();
}
/*
=================
TossClientItems
Toss the weapon and powerups for the killed player
=================
*/
void TossClientItems( gentity_t *self ) {
gitem_t *item;
int weapon;
float angle;
int i;
gentity_t *drop;
// drop the weapon if not a gauntlet or machinegun
weapon = self->s.weapon;
// make a special check to see if they are changing to a new
// weapon that isn't the mg or gauntlet. Without this, a client
// can pick up a weapon, be killed, and not drop the weapon because
// their weapon change hasn't completed yet and they are still holding the MG.
if ( weapon == WP_MACHINEGUN || weapon == WP_GRAPPLING_HOOK ) {
if ( self->client->ps.weaponstate == WEAPON_DROPPING ) {
weapon = self->client->pers.cmd.weapon;
}
if ( !( self->client->ps.stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
weapon = WP_NONE;
}
}
if ( weapon > WP_MACHINEGUN && weapon != WP_GRAPPLING_HOOK &&
self->client->ps.ammo[ weapon ] ) {
// find the item type for this weapon
item = BG_FindItemForWeapon( weapon );
// spawn the item
Drop_Item( self, item, 0 );
}
// drop all the powerups if not in teamplay
if ( g_gametype.integer != GT_TEAM ) {
angle = 45;
for ( i = 1 ; i < PW_NUM_POWERUPS ; i++ ) {
if ( self->client->ps.powerups[ i ] > level.time ) {
item = BG_FindItemForPowerup( i );
if ( !item ) {
continue;
}
drop = Drop_Item( self, item, angle );
// decide how many seconds it has left
drop->count = ( self->client->ps.powerups[ i ] - level.time ) / 1000;
if ( drop->count < 1 ) {
drop->count = 1;
}
angle += 45;
}
}
}
}
#ifdef MISSIONPACK
/*
=================
TossClientCubes
=================
*/
extern gentity_t *neutralObelisk;
void TossClientCubes( gentity_t *self ) {
gitem_t *item;
gentity_t *drop;
vec3_t velocity;
vec3_t angles;
vec3_t origin;
self->client->ps.generic1 = 0;
// this should never happen but we should never
// get the server to crash due to skull being spawned in
if (!G_EntitiesFree()) {
return;
}
if( self->client->sess.sessionTeam == TEAM_RED ) {
item = BG_FindItem( "Red Cube" );
}
else {
item = BG_FindItem( "Blue Cube" );
}
angles[YAW] = (float)(level.time % 360);
angles[PITCH] = 0; // always forward
angles[ROLL] = 0;
AngleVectors( angles, velocity, NULL, NULL );
VectorScale( velocity, 150, velocity );
velocity[2] += 200 + crandom() * 50;
if( neutralObelisk ) {
VectorCopy( neutralObelisk->s.pos.trBase, origin );
origin[2] += 44;
} else {
VectorClear( origin ) ;
}
drop = LaunchItem( item, origin, velocity );
drop->nextthink = level.time + g_cubeTimeout.integer * 1000;
drop->think = G_FreeEntity;
drop->spawnflags = self->client->sess.sessionTeam;
}
/*
=================
TossClientPersistantPowerups
=================
*/
void TossClientPersistantPowerups( gentity_t *ent ) {
gentity_t *powerup;
if( !ent->client ) {
return;
}
if( !ent->client->persistantPowerup ) {
return;
}
powerup = ent->client->persistantPowerup;
powerup->r.svFlags &= ~SVF_NOCLIENT;
powerup->s.eFlags &= ~EF_NODRAW;
powerup->r.contents = CONTENTS_TRIGGER;
trap_LinkEntity( powerup );
ent->client->ps.stats[STAT_PERSISTANT_POWERUP] = 0;
ent->client->persistantPowerup = NULL;
}
#endif
/*
==================
LookAtKiller
==================
*/
void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) {
vec3_t dir;
vec3_t angles;
if ( attacker && attacker != self ) {
VectorSubtract (attacker->s.pos.trBase, self->s.pos.trBase, dir);
} else if ( inflictor && inflictor != self ) {
VectorSubtract (inflictor->s.pos.trBase, self->s.pos.trBase, dir);
} else {
self->client->ps.stats[STAT_DEAD_YAW] = self->s.angles[YAW];
return;
}
self->client->ps.stats[STAT_DEAD_YAW] = vectoyaw ( dir );
angles[YAW] = vectoyaw ( dir );
angles[PITCH] = 0;
angles[ROLL] = 0;
}
/*
==================
GibEntity
==================
*/
void GibEntity( gentity_t *self, int killer ) {
gentity_t *ent;
int i;
//if this entity still has kamikaze
if (self->s.eFlags & EF_KAMIKAZE) {
// check if there is a kamikaze timer around for this owner
for (i = 0; i < MAX_GENTITIES; i++) {
ent = &g_entities[i];
if (!ent->inuse)
continue;
if (ent->activator != self)
continue;
if (strcmp(ent->classname, "kamikaze timer"))
continue;
G_FreeEntity(ent);
break;
}
}
G_AddEvent( self, EV_GIB_PLAYER, killer );
self->takedamage = qfalse;
self->s.eType = ET_INVISIBLE;
self->r.contents = 0;
}
/*
==================
body_die
==================
*/
void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
if ( self->health > GIB_HEALTH ) {
return;
}
if ( !g_blood.integer ) {
self->health = GIB_HEALTH+1;
return;
}
GibEntity( self, 0 );
}
// these are just for logging, the client prints its own messages
char *modNames[] = {
"MOD_UNKNOWN",
"MOD_SHOTGUN",
"MOD_GAUNTLET",
"MOD_MACHINEGUN",
"MOD_GRENADE",
"MOD_GRENADE_SPLASH",
"MOD_ROCKET",
"MOD_ROCKET_SPLASH",
"MOD_PLASMA",
"MOD_PLASMA_SPLASH",
"MOD_RAILGUN",
"MOD_LIGHTNING",
"MOD_BFG",
"MOD_BFG_SPLASH",
"MOD_WATER",
"MOD_SLIME",
"MOD_LAVA",
"MOD_CRUSH",
"MOD_TELEFRAG",
"MOD_FALLING",
"MOD_SUICIDE",
"MOD_TARGET_LASER",
"MOD_TRIGGER_HURT",
#ifdef MISSIONPACK
"MOD_NAIL",
"MOD_CHAINGUN",
"MOD_PROXIMITY_MINE",
"MOD_KAMIKAZE",
"MOD_JUICED",
#endif
"MOD_GRAPPLE"
};
#ifdef MISSIONPACK
/*
==================
Kamikaze_DeathActivate
==================
*/
void Kamikaze_DeathActivate( gentity_t *ent ) {
G_StartKamikaze(ent);
G_FreeEntity(ent);
}
/*
==================
Kamikaze_DeathTimer
==================
*/
void Kamikaze_DeathTimer( gentity_t *self ) {
gentity_t *ent;
ent = G_Spawn();
ent->classname = "kamikaze timer";
VectorCopy(self->s.pos.trBase, ent->s.pos.trBase);
ent->r.svFlags |= SVF_NOCLIENT;
ent->think = Kamikaze_DeathActivate;
ent->nextthink = level.time + 5 * 1000;
ent->activator = self;
}
#endif
/*
==================
CheckAlmostCapture
==================
*/
void CheckAlmostCapture( gentity_t *self, gentity_t *attacker ) {
gentity_t *ent;
vec3_t dir;
char *classname;
// if this player was carrying a flag
if ( self->client->ps.powerups[PW_REDFLAG] ||
self->client->ps.powerups[PW_BLUEFLAG] ||
self->client->ps.powerups[PW_NEUTRALFLAG] ) {
// get the goal flag this player should have been going for
if ( g_gametype.integer == GT_CTF ) {
if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
classname = "team_CTF_blueflag";
}
else {
classname = "team_CTF_redflag";
}
}
else {
if ( self->client->sess.sessionTeam == TEAM_BLUE ) {
classname = "team_CTF_redflag";
}
else {
classname = "team_CTF_blueflag";
}
}
ent = NULL;
do
{
ent = G_Find(ent, FOFS(classname), classname);
} while (ent && (ent->flags & FL_DROPPED_ITEM));
// if we found the destination flag and it's not picked up
if (ent && !(ent->r.svFlags & SVF_NOCLIENT) ) {
// if the player was *very* close
VectorSubtract( self->client->ps.origin, ent->s.origin, dir );
if ( VectorLength(dir) < 200 ) {
self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
if ( attacker->client ) {
attacker->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_HOLYSHIT;
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -