void G_UpdateTeamMapData_Player( gentity_t* ent, qboolean forceAllied, qboolean forceAxis ) {
	int num = ent - g_entities;
	mapEntityData_Team_t* teamList;
	mapEntityData_t *mEnt;

	if ( ent->client ) {
		switch ( ent->client->sess.sessionTeam ) {
		case TEAM_AXIS:
			forceAxis = qtrue;
			break;

		case TEAM_ALLIES:
			forceAllied = qtrue;
			break;

		default:
			break;
		}
	}

	if ( forceAxis && ent->client && !( ent->client->ps.pm_flags & PMF_LIMBO ) /*ent->health > 0*/ ) {
		teamList = &mapEntityData[0];
		mEnt = G_FindMapEntityData( teamList, num );
		if ( !mEnt ) {
			mEnt = G_AllocMapEntityData( teamList );
			mEnt->entNum = num;
		}
		VectorCopy( ent->client->ps.origin, mEnt->org );
		mEnt->yaw = ent->client->ps.viewangles[YAW];
		mEnt->data = num;
		mEnt->startTime = level.time;

		if ( ent->health <= 0 ) {
			mEnt->type = ME_PLAYER_REVIVE;
		} else {
			mEnt->type = ME_PLAYER;
		}
	}

	if ( forceAllied && ent->client && !( ent->client->ps.pm_flags & PMF_LIMBO ) /*ent->health > 0*/ ) {
		teamList = &mapEntityData[1];
		mEnt = G_FindMapEntityData( teamList, num );
		if ( !mEnt ) {
			mEnt = G_AllocMapEntityData( teamList );
			mEnt->entNum = num;
		}

		VectorCopy( ent->client->ps.origin, mEnt->org );
		mEnt->yaw = ent->client->ps.viewangles[YAW];
		mEnt->data = num;
		mEnt->startTime = level.time;
		if ( ent->health <= 0 ) {
			mEnt->type = ME_PLAYER_REVIVE;
		} else {
			mEnt->type = ME_PLAYER;
		}
	}
}
Exemple #2
0
// spawn a constructible indicator
void constructible_indicator_think(gentity_t *ent)
{
	gentity_t *parent        = &g_entities[ent->r.ownerNum];
	gentity_t *constructible = parent->target_ent;

	if (parent->chain)
	{
		// use the target that has the same team as the indicator
		if (constructible->s.teamNum != ent->s.teamNum)
		{
			constructible = parent->chain;
		}
	}

	if (!parent->inuse || !parent->r.linked || (constructible && constructible->s.angles2[1] != 0))
	{
		// update our map
		{
			mapEntityData_t      *mEnt;
			mapEntityData_Team_t *teamList;

			if (parent->spawnflags & 8)
			{
				if ((mEnt = G_FindMapEntityData(&mapEntityData[0], ent - g_entities)) != NULL)
				{
					G_FreeMapEntityData(&mapEntityData[0], mEnt);
				}
				if ((mEnt = G_FindMapEntityData(&mapEntityData[1], ent - g_entities)) != NULL)
				{
					G_FreeMapEntityData(&mapEntityData[1], mEnt);
				}
			}
			else
			{
				teamList = ent->s.teamNum == TEAM_AXIS ? &mapEntityData[0] : &mapEntityData[1];
				if ((mEnt = G_FindMapEntityData(teamList, ent - g_entities)) != NULL)
				{
					G_FreeMapEntityData(teamList, mEnt);
				}
			}
		}

		parent->count2 = 0;
		G_FreeEntity(ent);
		return;
	}

	if (ent->s.eType == ET_TANK_INDICATOR || ent->s.eType == ET_TANK_INDICATOR_DEAD)
	{
		VectorCopy(ent->parent->r.currentOrigin, ent->s.pos.trBase);
	}
	ent->s.effect1Time = parent->constructibleStats.weaponclass;
	ent->nextthink     = level.time + FRAMETIME;
}
void G_UpdateTeamMapData_LandMine(gentity_t* ent, qboolean forceAllied, qboolean forceAxis) {
//void G_UpdateTeamMapData_LandMine(gentity_t* ent) {
	int num = ent-g_entities;
	mapEntityData_Team_t* teamList;
	mapEntityData_t *mEnt;

	// inversed teamlists, we want to see the enemy mines
	switch(ent->s.teamNum % 4) {
		case TEAM_AXIS:
			forceAxis = qtrue;
			break;

		case TEAM_ALLIES:
			forceAllied = qtrue;
			break;
	}

	if(forceAxis && (ent->s.teamNum < 4 || ent->s.teamNum >= 8) ) {
		teamList = &mapEntityData[0];
		mEnt = G_FindMapEntityData( teamList, num );
		if( !mEnt ) {
			mEnt = G_AllocMapEntityData( teamList );
			mEnt->entNum = num;
		}

		VectorCopy( ent->r.currentOrigin, mEnt->org );
		//mEnt->data = TEAM_AXIS;
		mEnt->data = (ent->s.teamNum % 4);
		mEnt->startTime = level.time;
		//if( ent->s.teamNum < 4 )
			mEnt->type = ME_LANDMINE;
		//else if( ent->s.teamNum >= 8 )
		//	mEnt->type = ME_LANDMINE_ARMED;
	} 

	if(forceAllied && (ent->s.teamNum < 4 || ent->s.teamNum >= 8) ) {
		teamList = &mapEntityData[1];
		mEnt = G_FindMapEntityData( teamList, num );
		if( !mEnt ) {
			mEnt = G_AllocMapEntityData( teamList );
			mEnt->entNum = num;
		}
	
		VectorCopy( ent->r.currentOrigin, mEnt->org );
		//mEnt->data = TEAM_ALLIES;
		mEnt->data = (ent->s.teamNum % 4);
		mEnt->startTime = level.time;
		//if( ent->s.teamNum < 4 )
			mEnt->type = ME_LANDMINE;
		//else if( ent->s.teamNum >= 8 )
		//	mEnt->type = ME_LANDMINE_ARMED;
	}
}
void G_UpdateTeamMapData_Construct(gentity_t *ent)
{
	int                  num = ent - g_entities;
	mapEntityData_Team_t *teamList;
	mapEntityData_t      *mEnt;

	switch (ent->s.teamNum)
	{
	case TEAM_SPECTATOR: // both teams - do twice
	{
		teamList = &mapEntityData[0];
		mEnt     = G_FindMapEntityData(teamList, num);
		if (!mEnt)
		{
			mEnt         = G_AllocMapEntityData(teamList);
			mEnt->entNum = num;
		}
		VectorCopy(ent->s.pos.trBase, mEnt->org);
		mEnt->data      = mEnt->entNum; //ent->s.modelindex2;
		mEnt->type      = ME_CONSTRUCT;
		mEnt->startTime = level.time;
		mEnt->yaw       = 0;

		teamList = &mapEntityData[1];
		break;
	}
	case TEAM_AXIS:
	{
		teamList = &mapEntityData[0];
		break;
	}
	case TEAM_ALLIES:
	{
		teamList = &mapEntityData[1];

		break;
	}
	default:
		return;
	}

	mEnt = G_FindMapEntityData(teamList, num);
	if (!mEnt)
	{
		mEnt         = G_AllocMapEntityData(teamList);
		mEnt->entNum = num;
	}
	VectorCopy(ent->s.pos.trBase, mEnt->org);
	mEnt->data      = mEnt->entNum; //ent->s.modelindex2;
	mEnt->type      = ME_CONSTRUCT;
	mEnt->startTime = level.time;
	mEnt->yaw       = 0;
}
Exemple #5
0
/**
 * @brief G_UpdateTeamMapData_CommandmapMarker
 * @param[in] ent
 */
void G_UpdateTeamMapData_CommandmapMarker(gentity_t *ent)
{
	if (!ent->parent)
	{
		return;
	}

	if (ent->entstate != STATE_DEFAULT)
	{
		return;
	}

	if (ent->parent->spawnflags & (ALLIED_OBJECTIVE | AXIS_OBJECTIVE))
	{
		int                  num = ent - g_entities;
		mapEntityData_Team_t *teamList;
		mapEntityData_t      *mEnt;

		// alies
		teamList = &mapEntityData[0];
		mEnt     = G_FindMapEntityData(teamList, num);
		if (!mEnt)
		{
			mEnt         = G_AllocMapEntityData(teamList);
			mEnt->entNum = num;
		}
		VectorCopy(ent->s.origin, mEnt->org);
		mEnt->data      = ent->parent ? ent->parent->s.teamNum : -1;
		mEnt->startTime = level.time;
		mEnt->type      = ME_COMMANDMAP_MARKER;
		mEnt->yaw       = 0;


		// axis
		teamList = &mapEntityData[1];
		mEnt     = G_FindMapEntityData(teamList, num);
		if (!mEnt)
		{
			mEnt         = G_AllocMapEntityData(teamList);
			mEnt->entNum = num;
		}
		VectorCopy(ent->s.origin, mEnt->org);
		mEnt->data      = ent->parent ? ent->parent->s.teamNum : -1;
		mEnt->startTime = level.time;
		mEnt->type      = ME_COMMANDMAP_MARKER;
		mEnt->yaw       = 0;
	}
}
void G_UpdateTeamMapData_Tank(gentity_t *ent)
{
	int                  num       = ent - g_entities;
	mapEntityData_Team_t *teamList = &mapEntityData[0];
	mapEntityData_t      *mEnt;

	mEnt = G_FindMapEntityData(teamList, num);

	if (!mEnt)
	{
		mEnt         = G_AllocMapEntityData(teamList);
		mEnt->entNum = num;
	}
	VectorCopy(ent->s.pos.trBase, mEnt->org);
	mEnt->data      = ent->s.modelindex2;
	mEnt->startTime = level.time;
	if (ent->s.eType == ET_TANK_INDICATOR_DEAD)
	{
		mEnt->type = ME_TANK_DEAD;
	}
	else
	{
		mEnt->type = ME_TANK;
	}
	mEnt->yaw = 0;

	teamList = &mapEntityData[1];
	mEnt     = G_FindMapEntityData(teamList, num);
	if (!mEnt)
	{
		mEnt         = G_AllocMapEntityData(teamList);
		mEnt->entNum = num;
	}
	VectorCopy(ent->s.pos.trBase, mEnt->org);
	mEnt->data      = ent->s.modelindex2;
	mEnt->startTime = level.time;
	if (ent->s.eType == ET_TANK_INDICATOR_DEAD)
	{
		mEnt->type = ME_TANK_DEAD;
	}
	else
	{
		mEnt->type = ME_TANK;
	}
	mEnt->yaw = 0;
}
Exemple #7
0
// NERVE - SMF - spawn an explosive indicator
void explosive_indicator_think(gentity_t * ent)
{
	gentity_t      *parent;

	parent = &g_entities[ent->r.ownerNum];

	if(!parent->inuse || (parent->s.eType == ET_CONSTRUCTIBLE && !parent->r.linked))
	{

		// update our map
		{
			mapEntityData_t *mEnt;

			if((mEnt = G_FindMapEntityData(&mapEntityData[0], ent - g_entities)) != NULL)
			{
				G_FreeMapEntityData(&mapEntityData[0], mEnt);
			}
			if((mEnt = G_FindMapEntityData(&mapEntityData[1], ent - g_entities)) != NULL)
			{
				G_FreeMapEntityData(&mapEntityData[1], mEnt);
			}
		}

		//ent->think = G_FreeEntity;
		//ent->nextthink = level.time + FRAMETIME;
		G_FreeEntity(ent);
		return;
	}

	if(ent->s.eType == ET_TANK_INDICATOR || ent->s.eType == ET_TANK_INDICATOR_DEAD)
	{
		VectorCopy(ent->parent->r.currentOrigin, ent->s.pos.trBase);
	}
	ent->nextthink = level.time + FRAMETIME;

	if(parent->s.eType == ET_OID_TRIGGER && parent->target_ent)
	{
		ent->s.effect1Time = parent->target_ent->constructibleStats.weaponclass;
	}
	else
	{
		ent->s.effect1Time = parent->constructibleStats.weaponclass;
	}
}
void G_UpdateTeamMapData_LandMine(gentity_t *ent)
{
	int                  num = ent - g_entities;
	mapEntityData_Team_t *teamList;
	mapEntityData_t      *mEnt;
	int                  team = ent->s.teamNum & 3;    //ent->s.teamNum % 4

	if (!(ent->s.teamNum < 4 || ent->s.teamNum >= 8))
	{
		return;                                                 // must be armed..

	}
	// inversed teamlists, we want to see the enemy mines
	if (ent->s.modelindex2)     // must be spotted..
	{
		teamList = &mapEntityData[(team == TEAM_AXIS) ? 1 : 0];
		mEnt     = G_FindMapEntityData(teamList, num);
		if (!mEnt)
		{
			mEnt         = G_AllocMapEntityData(teamList);
			mEnt->entNum = num;
		}
		VectorCopy(ent->r.currentOrigin, mEnt->org);
		mEnt->data      = team;
		mEnt->startTime = level.time;
		mEnt->type      = ME_LANDMINE;
	}

	// team mines..
	teamList = &mapEntityData[(team == TEAM_AXIS) ? 0 : 1];
	mEnt     = G_FindMapEntityData(teamList, num);
	if (!mEnt)
	{
		mEnt         = G_AllocMapEntityData(teamList);
		mEnt->entNum = num;
	}
	VectorCopy(ent->r.currentOrigin, mEnt->org);
	mEnt->data      = team;
	mEnt->startTime = level.time;
	mEnt->type      = ME_LANDMINE;
}
void G_UpdateTeamMapData_Destruct(gentity_t* ent) {
	int num = ent-g_entities;
	mapEntityData_Team_t* teamList;
	mapEntityData_t *mEnt;

	if( ent->s.teamNum == TEAM_AXIS ) {
		teamList = &mapEntityData[1];	// inverted
		mEnt = G_FindMapEntityData( teamList, num );
		if( !mEnt ) {
			mEnt = G_AllocMapEntityData( teamList );
			mEnt->entNum = num;
		}
		VectorCopy( ent->s.pos.trBase, mEnt->org );
		mEnt->data = mEnt->entNum; //ent->s.modelindex2;
		mEnt->startTime = level.time;
		mEnt->type = ME_DESTRUCT;
		mEnt->yaw = 0;
	} else {
		if( ent->parent->target_ent && ( ent->parent->target_ent->s.eType == ET_CONSTRUCTIBLE || ent->parent->target_ent->s.eType == ET_EXPLOSIVE ) ) {
			if( ent->parent->spawnflags & ((1 << 6) | (1 << 4))) {
				teamList = &mapEntityData[1];	// inverted
				mEnt = G_FindMapEntityData( teamList, num );
				if( !mEnt ) {
					mEnt = G_AllocMapEntityData( teamList );
					mEnt->entNum = num;
				}
				VectorCopy( ent->s.pos.trBase, mEnt->org );
				mEnt->data = mEnt->entNum; //ent->s.modelindex2;
				mEnt->startTime = level.time;
				mEnt->type = ME_DESTRUCT_2;
				mEnt->yaw = 0;
			}
		}
	}

	if(ent->s.teamNum == TEAM_ALLIES  ) {
		teamList = &mapEntityData[0];	// inverted
		mEnt = G_FindMapEntityData( teamList, num );
		if( !mEnt ) {
			mEnt = G_AllocMapEntityData( teamList );
			mEnt->entNum = num;
		}
		VectorCopy( ent->s.pos.trBase, mEnt->org );
		mEnt->data = mEnt->entNum; //ent->s.modelindex2;
		mEnt->startTime = level.time;
		mEnt->type = ME_DESTRUCT;
		mEnt->yaw = 0;
	} else {
		if( ent->parent->target_ent && ( ent->parent->target_ent->s.eType == ET_CONSTRUCTIBLE || ent->parent->target_ent->s.eType == ET_EXPLOSIVE ) ) {
			if( ent->parent->spawnflags & ((1 << 6) | (1 << 4)) ) {
				teamList = &mapEntityData[0];	// inverted
				mEnt = G_FindMapEntityData( teamList, num );
				if( !mEnt ) {
					mEnt = G_AllocMapEntityData( teamList );
					mEnt->entNum = num;
				}
				VectorCopy( ent->s.pos.trBase, mEnt->org );
				mEnt->data = mEnt->entNum; //ent->s.modelindex2;
				mEnt->startTime = level.time;
				mEnt->type = ME_DESTRUCT_2;
				mEnt->yaw = 0;
			}
		}
	}
}
void G_UpdateTeamMapData_Construct(gentity_t* ent) {
	int num = ent-g_entities;
	mapEntityData_Team_t* teamList;
	mapEntityData_t *mEnt;

	if( ent->s.teamNum == 3 ) {
		teamList = &mapEntityData[0];
		mEnt = G_FindMapEntityData( teamList, num );
		if( !mEnt ) {
			mEnt = G_AllocMapEntityData( teamList );
			mEnt->entNum = num;
		}
		VectorCopy( ent->s.pos.trBase, mEnt->org );
		mEnt->data = mEnt->entNum; //ent->s.modelindex2;
		mEnt->type = ME_CONSTRUCT;
		mEnt->startTime = level.time;
		mEnt->yaw = 0;

		teamList = &mapEntityData[1];
		mEnt = G_FindMapEntityData( teamList, num );
		if( !mEnt ) {
			mEnt = G_AllocMapEntityData( teamList );
			mEnt->entNum = num;
		}
		VectorCopy( ent->s.pos.trBase, mEnt->org );
		mEnt->data = mEnt->entNum; //ent->s.modelindex2;
		mEnt->type = ME_CONSTRUCT;
		mEnt->startTime = level.time;
		mEnt->yaw = 0;

		return;
	}

	if( ent->s.teamNum == TEAM_AXIS ) {
		teamList = &mapEntityData[0];
		mEnt = G_FindMapEntityData( teamList, num );
		if( !mEnt ) {
			mEnt = G_AllocMapEntityData( teamList );
			mEnt->entNum = num;
		}
		VectorCopy( ent->s.pos.trBase, mEnt->org );
		mEnt->data = mEnt->entNum; //ent->s.modelindex2;
		mEnt->type = ME_CONSTRUCT;
		mEnt->startTime = level.time;
		mEnt->yaw = 0;
	} else {
	}

	if( ent->s.teamNum == TEAM_ALLIES ) {
		teamList = &mapEntityData[1];
		mEnt = G_FindMapEntityData( teamList, num );
		if( !mEnt ) {
			mEnt = G_AllocMapEntityData( teamList );
			mEnt->entNum = num;
		}
		VectorCopy( ent->s.pos.trBase, mEnt->org );
		mEnt->data = mEnt->entNum; //ent->s.modelindex2;
		mEnt->type = ME_CONSTRUCT;
		mEnt->startTime = level.time;
		mEnt->yaw = 0;
	} else {
	}
}
Exemple #11
0
void G_UpdateTeamMapData(void) {
	int             i, j;
	gentity_t       *ent, *ent2;
	mapEntityData_t *mEnt;

	if (level.time - level.lastMapEntityUpdate < 500) {
		return;
	}
	level.lastMapEntityUpdate = level.time;

	for (i = 0, ent = g_entities; i < level.num_entities; i++, ent++) {
		if (!ent->inuse) {
			continue;
		}

		switch (ent->s.eType) {
		case ET_PLAYER:
			G_UpdateTeamMapData_Player(ent, qfalse, qfalse);
			for (j = 0; j < 2; j++) {
				mapEntityData_Team_t *teamList = &mapEntityData[j];

				mEnt = G_FindMapEntityDataSingleClient(teamList, NULL, ent->s.number, -1);

				while (mEnt) {
					VectorCopy(ent->client->ps.origin, mEnt->org);
					mEnt->yaw = ent->client->ps.viewangles[YAW];
					mEnt      = G_FindMapEntityDataSingleClient(teamList, mEnt, ent->s.number, -1);
				}
			}
			break;
		case ET_CONSTRUCTIBLE_INDICATOR:
			if (ent->parent && ent->parent->entstate == STATE_DEFAULT) {
				G_UpdateTeamMapData_Construct(ent);
			}
			break;
		case ET_EXPLOSIVE_INDICATOR:
			if (ent->parent && ent->parent->entstate == STATE_DEFAULT) {
				G_UpdateTeamMapData_Destruct(ent);
			}
			break;
		case ET_TANK_INDICATOR:
		case ET_TANK_INDICATOR_DEAD:
			G_UpdateTeamMapData_Tank(ent);
			break;
		case ET_MISSILE:
			break;
		case ET_COMMANDMAP_MARKER:
			G_UpdateTeamMapData_CommandmapMarker(ent);
			break;
		default:
			break;
		}
	}

	for (i = 0, ent = g_entities; i < level.num_entities; i++, ent++) {
		qboolean f1, f2;
		if (!ent->inuse || !ent->client) {
			continue;
		}
		if (ent->client->sess.playerType == PC_COVERTOPS && ent->health > 0) {
			f1 = ent->client->sess.sessionTeam == TEAM_ALLIES ? qtrue : qfalse;
			f2 = ent->client->sess.sessionTeam == TEAM_AXIS ?   qtrue : qfalse;

			G_SetupFrustum(ent);

			for (j = 0, ent2 = g_entities; j < level.num_entities; j++, ent2++) {
				if (!ent2->inuse || ent2 == ent) {
					continue;
				}

				switch (ent2->s.eType) {
				case ET_PLAYER:
				{
					vec3_t pos[3];
					VectorCopy(ent2->client->ps.origin, pos[0]);
					pos[0][2] += ent2->client->ps.mins[2];
					VectorCopy(ent2->client->ps.origin, pos[1]);
					VectorCopy(ent2->client->ps.origin, pos[2]);
					pos[2][2] += ent2->client->ps.maxs[2];
					if (ent2->health > 0 && (G_VisibleFromBinoculars(ent, ent2, pos[0]) ||
					                         G_VisibleFromBinoculars(ent, ent2, pos[1]) ||
					                         G_VisibleFromBinoculars(ent, ent2, pos[2]))) {
						if (ent2->client->sess.sessionTeam != ent->client->sess.sessionTeam) {
							int k;

							switch (ent2->client->sess.sessionTeam) {
							case TEAM_AXIS:
								mEnt = G_FindMapEntityData(&mapEntityData[0], ent2 - g_entities);
								if (mEnt && level.time - mEnt->startTime > 5000) {
									for (k = 0; k < MAX_CLIENTS; k++) {
										if (g_entities[k].inuse && g_entities[k].client && g_entities[k].client->sess.sessionTeam == ent->client->sess.sessionTeam) {
											trap_SendServerCommand(k, va("tt \"ENEMY SPOTTED <STOP> CHECK COMMAND MAP FOR DETAILS <STOP>\"\n"));
										}
									}
								}
								break;

							case TEAM_ALLIES:
								mEnt = G_FindMapEntityData(&mapEntityData[1], ent2 - g_entities);
								if (mEnt && level.time - mEnt->startTime > 5000) {
									for (k = 0; k < MAX_CLIENTS; k++) {
										if (g_entities[k].inuse && g_entities[k].client && g_entities[k].client->sess.sessionTeam == ent->client->sess.sessionTeam) {
											trap_SendServerCommand(k, va("tt \"ENEMY SPOTTED <STOP> CHECK COMMAND MAP FOR DETAILS <STOP>\"\n"));
										}
									}
								}
								break;

							default:
								break;
							}
						}

						G_UpdateTeamMapData_Player(ent2, f1, f2);
					}
					break;
				}
				default:
					break;
				}
			}

			if (ent->client->ps.eFlags & EF_ZOOMING) {
				G_SetupFrustum_ForBinoculars(ent);

				for (j = 0, ent2 = g_entities; j < level.num_entities; j++, ent2++) {
					if (!ent2->inuse || ent2 == ent) {
						continue;
					}

					switch (ent2->s.eType) {
					case ET_MISSILE:
						break;
					default:
						break;
					}
				}
			}
		}
	}
}
void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) {
	int			contents = 0, i, killer = ENTITYNUM_WORLD;
	char		*killerName = "<world>";
	qboolean	nogib = qtrue;
	gitem_t		*item = NULL;
	gentity_t	*ent;
	qboolean	killedintank = qfalse;

	//float			timeLived;
	weapon_t	weap = BG_WeaponForMOD( meansOfDeath );

//	G_Printf( "player_die\n" );

	if(attacker == self) {
		if(self->client) {
			self->client->pers.playerStats.suicides++;
			trap_PbStat ( self - g_entities , "suicide" , 
				va ( "%d %d %d" , self->client->sess.sessionTeam , self->client->sess.playerType , weap ) ) ;
		}
	} else if(OnSameTeam( self, attacker )) {
		G_LogTeamKill(	attacker,	weap );
	} else {
		G_LogDeath( self,		weap );
		G_LogKill(	attacker,	weap );

		if( g_gamestate.integer == GS_PLAYING ) {
			if( attacker->client ) {
				attacker->client->combatState |= (1<<COMBATSTATE_KILLEDPLAYER);
			}
		}
	}

	// RF, record this death in AAS system so that bots avoid areas which have high death rates
	if( !OnSameTeam( self, attacker ) )
	{
// LC - not needed
//		BotRecordTeamDeath( self->s.number );

		self->isProp = qfalse;	// were we teamkilled or not?
	} else {
		self->isProp = qtrue;
	}	

	// if we got killed by a landmine, update our map
	if( self->client && meansOfDeath == MOD_LANDMINE ) {
		// if it's an enemy mine, update both teamlists
		/*int teamNum;
		mapEntityData_t	*mEnt;
		mapEntityData_Team_t *teamList;
	
		teamNum = inflictor->s.teamNum % 4;

		teamList = self->client->sess.sessionTeam == TEAM_AXIS ? &mapEntityData[0] : &mapEntityData[1];
		if((mEnt = G_FindMapEntityData(teamList, inflictor-g_entities)) != NULL) {
			G_FreeMapEntityData( teamList, mEnt );
		}

		if( teamNum != self->client->sess.sessionTeam ) {
			teamList = self->client->sess.sessionTeam == TEAM_AXIS ? &mapEntityData[1] : &mapEntityData[0];
			if((mEnt = G_FindMapEntityData(teamList, inflictor-g_entities)) != NULL) {
				G_FreeMapEntityData( teamList, mEnt );
			}
		}*/
		mapEntityData_t	*mEnt;

		if((mEnt = G_FindMapEntityData(&mapEntityData[0], inflictor-g_entities)) != NULL) {
			G_FreeMapEntityData( &mapEntityData[0], mEnt );
		}

		if((mEnt = G_FindMapEntityData(&mapEntityData[1], inflictor-g_entities)) != NULL) {
			G_FreeMapEntityData( &mapEntityData[1], mEnt );
		}
	}

	{
		mapEntityData_t	*mEnt;
		mapEntityData_Team_t *teamList = self->client->sess.sessionTeam == TEAM_AXIS ? &mapEntityData[1] : &mapEntityData[0];	// swapped, cause enemy team

		mEnt = G_FindMapEntityDataSingleClient( teamList, NULL, self->s.number, -1 );
		
		while( mEnt ) {
			if( mEnt->type == ME_PLAYER_DISGUISED ) {
				mapEntityData_t* mEntFree = mEnt;

				mEnt = G_FindMapEntityDataSingleClient( teamList, mEnt, self->s.number, -1 );

				G_FreeMapEntityData( teamList, mEntFree );
			} else {
				mEnt = G_FindMapEntityDataSingleClient( teamList, mEnt, self->s.number, -1 );
			}
		}
	}

	if( self->tankLink ) {
		G_LeaveTank( self, qfalse );

		killedintank = qtrue;
	}

	if( self->client->ps.pm_type == PM_DEAD || g_gamestate.integer == GS_INTERMISSION ) {
		return;
	}

	// OSP - death stats handled out-of-band of G_Damage for external calls
	G_addStats(self, attacker, damage, meansOfDeath);
	// OSP

	self->client->ps.pm_type = PM_DEAD;

	G_AddEvent( self, EV_STOPSTREAMINGSOUND, 0);

	if(attacker) {
		killer = attacker->s.number;
		killerName = (attacker->client) ? attacker->client->pers.netname : "<non-client>";
	}

	if(attacker == 0 || killer < 0 || killer >= MAX_CLIENTS) {
		killer = ENTITYNUM_WORLD;
		killerName = "<world>";
	}

	if(g_gamestate.integer == GS_PLAYING) {
		char *obit;

		if(meansOfDeath < 0 || meansOfDeath >= sizeof(modNames) / sizeof(modNames[0])) {
			obit = "<bad obituary>";
		} else {
			obit = modNames[meansOfDeath];
		}

		G_LogPrintf("Kill: %i %i %i: %s killed %s by %s\n", killer, self->s.number, meansOfDeath, killerName, self->client->pers.netname, obit );
	}


	// broadcast the death event to everyone
	ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
	ent->s.eventParm = meansOfDeath;
	ent->s.otherEntityNum = self->s.number;
	ent->s.otherEntityNum2 = killer;
	ent->r.svFlags = SVF_BROADCAST;	// send to everyone

	self->enemy = attacker;

	self->client->ps.persistant[PERS_KILLED]++;

	// JPW NERVE -- if player is holding ticking grenade, drop it
	if ((self->client->ps.grenadeTimeLeft) && (self->s.weapon != WP_DYNAMITE) && (self->s.weapon != WP_LANDMINE) && (self->s.weapon != WP_SATCHEL) && (self->s.weapon != WP_TRIPMINE)) {
		vec3_t launchvel, launchspot;

		launchvel[0] = crandom();
		launchvel[1] = crandom();
		launchvel[2] = random();
		VectorScale( launchvel, 160, launchvel );
		VectorCopy(self->r.currentOrigin, launchspot);
		launchspot[2] += 40;
		
		{
			// Gordon: fixes premature grenade explosion, ta bani ;)
			gentity_t *m = fire_grenade(self, launchspot, launchvel, self->s.weapon);
			m->damage = 0;
		}
	}

	if (attacker && attacker->client) {
		if ( attacker == self || OnSameTeam (self, attacker ) ) {

			// DHM - Nerve :: Complaint lodging
			if( attacker != self && level.warmupTime <= 0 && g_gamestate.integer == GS_PLAYING) {
				if( attacker->client->pers.localClient ) {
					trap_SendServerCommand( self-g_entities, "complaint -4" );
				} else {
					if( meansOfDeath != MOD_CRUSH_CONSTRUCTION && meansOfDeath != MOD_CRUSH_CONSTRUCTIONDEATH && meansOfDeath != MOD_CRUSH_CONSTRUCTIONDEATH_NOATTACKER ) {
						if( g_complaintlimit.integer ) {

							if( !(meansOfDeath == MOD_LANDMINE && g_disableComplaints.integer & TKFL_MINES ) &&
								!((meansOfDeath == MOD_ARTY || meansOfDeath == MOD_AIRSTRIKE) && g_disableComplaints.integer & TKFL_AIRSTRIKE ) &&
								!(meansOfDeath == MOD_MORTAR && g_disableComplaints.integer & TKFL_MORTAR ) ) {
								trap_SendServerCommand( self-g_entities, va( "complaint %i", attacker->s.number ) );
								self->client->pers.complaintClient = attacker->s.clientNum;
								self->client->pers.complaintEndTime = level.time + 20500;
							}
						}
					}
				}
			}

			// high penalty to offset medic heal
/*			AddScore( attacker, WOLF_FRIENDLY_PENALTY ); */

			if( g_gametype.integer == GT_WOLF_LMS ) {
				AddKillScore( attacker, WOLF_FRIENDLY_PENALTY );
			}
		} else {

			//G_AddExperience( attacker, 1 );

			// JPW NERVE -- mostly added as conveneience so we can tweak from the #defines all in one place
			AddScore(attacker, WOLF_FRAG_BONUS);

			if( g_gametype.integer == GT_WOLF_LMS ) {
				if( level.firstbloodTeam == -1 )
					level.firstbloodTeam = attacker->client->sess.sessionTeam;

				AddKillScore( attacker, WOLF_FRAG_BONUS );
			}

			attacker->client->lastKillTime = level.time;
		}
	} else {
		AddScore( self, -1 );

		if( g_gametype.integer == GT_WOLF_LMS )
			AddKillScore( self, -1 );
	}

	// Add team bonuses
	Team_FragBonuses(self, inflictor, attacker);

	// drop flag regardless
	if (self->client->ps.powerups[PW_REDFLAG]) {
		item = BG_FindItem("Red Flag");
		if (!item)
			item = BG_FindItem("Objective");

		self->client->ps.powerups[PW_REDFLAG] = 0;
	}
	if (self->client->ps.powerups[PW_BLUEFLAG]) {
		item = BG_FindItem("Blue Flag");
		if (!item)
			item = BG_FindItem("Objective");

		self->client->ps.powerups[PW_BLUEFLAG] = 0;
	}

	if (item) {
		vec3_t launchvel = { 0, 0, 0 };
		gentity_t *flag = LaunchItem(item, self->r.currentOrigin, launchvel, self->s.number);

		flag->s.modelindex2 = self->s.otherEntityNum2;// JPW NERVE FIXME set player->otherentitynum2 with old modelindex2 from flag and restore here
		flag->message = self->message;	// DHM - Nerve :: also restore item name
		// Clear out player's temp copies
		self->s.otherEntityNum2 = 0;
		self->message = NULL;
	}

	// send a fancy "MEDIC!" scream.  Sissies, ain' they?
	if (self->client != NULL) {
		if( self->health > GIB_HEALTH && meansOfDeath != MOD_SUICIDE && meansOfDeath != MOD_SWITCHTEAM ) {
			G_AddEvent( self, EV_MEDIC_CALL, 0 );
		}
	}

	Cmd_Score_f( self );		// show scores

	// send updated scores to any clients that are following this one,
	// or they would get stale scoreboards
	for(i=0; i<level.numConnectedClients; i++) {
		gclient_t *client = &level.clients[level.sortedClients[i]];

		if(client->pers.connected != CON_CONNECTED) continue;
		if(client->sess.sessionTeam != TEAM_SPECTATOR) continue;

		if(client->sess.spectatorClient == self->s.number) {
			Cmd_Score_f(g_entities + level.sortedClients[i]);
		}
	}

	self->takedamage = qtrue;	// can still be gibbed
	self->r.contents = CONTENTS_CORPSE;

	//self->s.angles[2] = 0;
	self->s.powerups = 0;
	self->s.loopSound = 0;
	
	self->client->limboDropWeapon = self->s.weapon; // store this so it can be dropped in limbo

	LookAtKiller( self, inflictor, attacker );
	self->client->ps.viewangles[0] = 0;
	self->client->ps.viewangles[2] = 0;
	//VectorCopy( self->s.angles, self->client->ps.viewangles );

//	trap_UnlinkEntity( self );
	self->r.maxs[2] = self->client->ps.crouchMaxZ;	//%	0;			// ydnar: so bodies don't clip into world
	self->client->ps.maxs[2] = self->client->ps.crouchMaxZ;	//%	0;	// ydnar: so bodies don't clip into world
	trap_LinkEntity( self );

	// don't allow respawn until the death anim is done
	// g_forcerespawn may force spawning at some later time
	self->client->respawnTime = level.timeCurrent + 800;

	// remove powerups
	memset( self->client->ps.powerups, 0, sizeof(self->client->ps.powerups) );

	// never gib in a nodrop
	// FIXME: contents is always 0 here
	if ( self->health <= GIB_HEALTH && !(contents & CONTENTS_NODROP) ) {
		GibEntity( self, killer );
		nogib = qfalse;
	}

	if(nogib){
		// normal death
		// for the no-blood option, we need to prevent the health
		// from going to gib level
		if ( self->health <= GIB_HEALTH ) {
			self->health = GIB_HEALTH + 1;
		}

		// Arnout: re-enable this for flailing
/*		if( self->client->ps.groundEntityNum == ENTITYNUM_NONE ) {
			self->client->ps.pm_flags |= PMF_FLAILING;
			self->client->ps.pm_time = 750;
			BG_AnimScriptAnimation( &self->client->ps, ANIM_MT_FLAILING, qtrue );

			// Face explosion directory
			{
				vec3_t angles;

				vectoangles( self->client->ps.velocity, angles );
				self->client->ps.viewangles[YAW] = angles[YAW];
				SetClientViewAngle( self, self->client->ps.viewangles );
			}
		} else*/

			// DHM - Play death animation, and set pm_time to delay 'fallen' animation
			//if( G_IsSinglePlayerGame() && self->client->sess.sessionTeam == TEAM_ALLIES ) {
			//	// play "falldown" animation since allies bots won't ever die completely
			//	self->client->ps.pm_time = BG_AnimScriptEvent( &self->client->ps, self->client->pers.character->animModelInfo, ANIM_ET_FALLDOWN, qfalse, qtrue );
			//	G_StartPlayerAppropriateSound(self, "death");
			//} else {
				self->client->ps.pm_time = BG_AnimScriptEvent( &self->client->ps, self->client->pers.character->animModelInfo, ANIM_ET_DEATH, qfalse, qtrue );
				// death animation script already contains sound
			//}

			// record the death animation to be used later on by the corpse
			self->client->torsoDeathAnim = self->client->ps.torsoAnim;
			self->client->legsDeathAnim = self->client->ps.legsAnim;

			G_AddEvent( self, EV_DEATH1 + 1, killer );

		// the body can still be gibbed
		self->die = body_die;
	}

	if( meansOfDeath == MOD_MACHINEGUN ) {
		switch( self->client->sess.sessionTeam ) {
			case TEAM_AXIS:
				level.axisMG42Counter = level.time;
				break;
			case TEAM_ALLIES:
				level.alliesMG42Counter = level.time;
				break;
		}
	}

	G_FadeItems( self, MOD_SATCHEL );

	CalculateRanks();

	if( killedintank /*Gordon: automatically go to limbo from tank*/ ) {
		limbo( self, qfalse ); // but no corpse
	} else if ( (meansOfDeath == MOD_SUICIDE && g_gamestate.integer == GS_PLAYING) ) {
		limbo( self, qtrue );
	} else if( g_gametype.integer == GT_WOLF_LMS ) {
		if( !G_CountTeamMedics( self->client->sess.sessionTeam, qtrue ) ) {
			limbo( self, qtrue );
		}
	}
}
void G_UpdateTeamMapData_Player(gentity_t *ent, qboolean forceAllied, qboolean forceAxis)
{
	int                  num = ent - g_entities;
	mapEntityData_Team_t *teamList;
	mapEntityData_t      *mEnt;

	if (!ent->client)
	{
		return;
	}

	if (ent->client->ps.pm_flags & PMF_LIMBO)
	{
		return;
	}

	if (ent->client->sess.sessionTeam == TEAM_AXIS)
	{
		forceAxis = qtrue;
	}
	else if (ent->client->sess.sessionTeam == TEAM_ALLIES)
	{
		forceAllied = qtrue;
	}

	if (forceAxis)
	{
		teamList = &mapEntityData[0];
		mEnt     = G_FindMapEntityData(teamList, num);
		if (!mEnt)
		{
			mEnt         = G_AllocMapEntityData(teamList);
			mEnt->entNum = num;
		}
		VectorCopy(ent->client->ps.origin, mEnt->org);
		mEnt->yaw       = ent->client->ps.viewangles[YAW];
		mEnt->data      = num;
		mEnt->startTime = level.time;

		if (ent->health <= 0)
		{
			mEnt->type = ME_PLAYER_REVIVE;
		}
		else if (ent->client->ps.powerups[PW_REDFLAG] || ent->client->ps.powerups[PW_BLUEFLAG])
		{
			mEnt->type = ME_PLAYER_OBJECTIVE;
		}
		else
		{
			mEnt->type = ME_PLAYER;
		}
	}

	if (forceAllied)
	{
		teamList = &mapEntityData[1];
		mEnt     = G_FindMapEntityData(teamList, num);
		if (!mEnt)
		{
			mEnt         = G_AllocMapEntityData(teamList);
			mEnt->entNum = num;
		}

		VectorCopy(ent->client->ps.origin, mEnt->org);
		mEnt->yaw       = ent->client->ps.viewangles[YAW];
		mEnt->data      = num;
		mEnt->startTime = level.time;
		if (ent->health <= 0)
		{
			mEnt->type = ME_PLAYER_REVIVE;
		}
		else if (ent->client->ps.powerups[PW_REDFLAG] || ent->client->ps.powerups[PW_BLUEFLAG])
		{
			mEnt->type = ME_PLAYER_OBJECTIVE;
		}
		else
		{
			mEnt->type = ME_PLAYER;
		}
	}
}
Exemple #14
0
/*
===========
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 *flag = NULL;
	gitem_t   *item = NULL;
	vec3_t    launchvel;
	int       i;

	ent = g_entities + clientNum;
	if (!ent->client) {
		return;
	}

	G_RemoveClientFromFireteams(clientNum, qtrue, qfalse);
	G_RemoveFromAllIgnoreLists(clientNum);
	G_LeaveTank(ent, qfalse);

	// Nico, remove the client from all specInvited lists
	for (i = 0; i < level.numConnectedClients; ++i) {
		COM_BitClear(level.clients[level.sortedClients[i]].sess.specInvitedClients, clientNum);
	}

	// stop any following clients
	for (i = 0 ; i < level.numConnectedClients ; i++) {
		flag = g_entities + level.sortedClients[i];
		if (flag->client->sess.sessionTeam == TEAM_SPECTATOR
		    && flag->client->sess.spectatorState == SPECTATOR_FOLLOW
		    && flag->client->sess.spectatorClient == clientNum) {
			StopFollowing(flag);
		}
		if (flag->client->ps.pm_flags & PMF_LIMBO
		    && flag->client->sess.spectatorClient == clientNum) {
			Cmd_FollowCycle_f(flag, 1);
		}
	}

	G_FadeItems(ent, MOD_SATCHEL);

	// remove ourself from teamlists
	{
		mapEntityData_t      *mEnt;
		mapEntityData_Team_t *teamList;

		for (i = 0; i < 2; i++) {
			teamList = &mapEntityData[i];

			if ((mEnt = G_FindMapEntityData(&mapEntityData[0], ent - g_entities)) != NULL) {
				G_FreeMapEntityData(teamList, mEnt);
			}

			mEnt = G_FindMapEntityDataSingleClient(teamList, NULL, ent->s.number, -1);

			while (mEnt) {
				mapEntityData_t *mEntFree = mEnt;

				mEnt = G_FindMapEntityDataSingleClient(teamList, mEnt, ent->s.number, -1);

				G_FreeMapEntityData(teamList, mEntFree);
			}
		}
	}

	// send effect if they were completely connected
	if (ent->client->pers.connected == CON_CONNECTED
	    && ent->client->sess.sessionTeam != TEAM_SPECTATOR
	    && !(ent->client->ps.pm_flags & PMF_LIMBO)) {

		// They don't get to take powerups with them!
		// Especially important for stuff like CTF flags
		// New code for tossing flags
		if (ent->client->ps.powerups[PW_REDFLAG]) {
			item = BG_FindItem("Red Flag");
			if (!item) {
				item = BG_FindItem("Objective");
			}

			ent->client->ps.powerups[PW_REDFLAG] = 0;
		}
		if (ent->client->ps.powerups[PW_BLUEFLAG]) {
			item = BG_FindItem("Blue Flag");
			if (!item) {
				item = BG_FindItem("Objective");
			}

			ent->client->ps.powerups[PW_BLUEFLAG] = 0;
		}

		if (item) {
			// OSP - fix for suicide drop exploit through walls/gates
			launchvel[0] = 0;    //crandom()*20;
			launchvel[1] = 0;    //crandom()*20;
			launchvel[2] = 0;    //10+random()*10;

			flag                = LaunchItem(item, ent->r.currentOrigin, launchvel, ent - g_entities);
			flag->s.modelindex2 = ent->s.otherEntityNum2;    // JPW NERVE FIXME set player->otherentitynum2 with old modelindex2 from flag and restore here
			flag->message       = ent->message; // DHM - Nerve :: also restore item name
			// Clear out player's temp copies
			ent->s.otherEntityNum2 = 0;
			ent->message           = NULL;
		}
	}

	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;
	i                                     = ent->client->sess.sessionTeam;
	ent->client->sess.sessionTeam         = TEAM_FREE;
	ent->active                           = 0;

	trap_SetConfigstring(CS_PLAYERS + clientNum, "");

	CalculateRanks();
}
void G_UpdateTeamMapData( void ) {
	int i, j/*, k*/;
	gentity_t *ent, *ent2;
	mapEntityData_t	*mEnt;

	if(level.time - level.lastMapEntityUpdate < 500) {
		return;
	}
	level.lastMapEntityUpdate = level.time;

	for(i = 0, ent = g_entities; i < level.num_entities; i++, ent++) {
		if(!ent->inuse) {
//			mapEntityData[0][i].valid = qfalse;
//			mapEntityData[1][i].valid = qfalse;
			continue;
		}

		switch(ent->s.eType) {
			case ET_PLAYER:
				G_UpdateTeamMapData_Player( ent, qfalse, qfalse );
				for( j = 0; j < 2; j++ ) {
					mapEntityData_Team_t *teamList = &mapEntityData[j];

					mEnt = G_FindMapEntityDataSingleClient( teamList, NULL, ent->s.number, -1 );
					
					while( mEnt ) {
						VectorCopy( ent->client->ps.origin, mEnt->org );
						mEnt->yaw = ent->client->ps.viewangles[YAW];
						mEnt = G_FindMapEntityDataSingleClient( teamList, mEnt, ent->s.number, -1 );
					}
				}
				break;
			case ET_CONSTRUCTIBLE_INDICATOR:
				if( ent->parent && ent->parent->entstate == STATE_DEFAULT ) {
					G_UpdateTeamMapData_Construct(ent);
				}
				break;
			case ET_EXPLOSIVE_INDICATOR:
				if( ent->parent && ent->parent->entstate == STATE_DEFAULT ) {
					G_UpdateTeamMapData_Destruct(ent);
				}
				break;
			case ET_TANK_INDICATOR:
			case ET_TANK_INDICATOR_DEAD:
				G_UpdateTeamMapData_Tank(ent);
				break;
			case ET_MISSILE:
				if( ent->methodOfDeath == MOD_LANDMINE) {
					G_UpdateTeamMapData_LandMine(ent, qfalse, qfalse);
				}
				break;
			case ET_COMMANDMAP_MARKER:
				G_UpdateTeamMapData_CommandmapMarker( ent );
				break;
			default:
				break;
		}
	}

	//for(i = 0, ent = g_entities; i < MAX_CLIENTS; i++, ent++) {
	for( i = 0, ent = g_entities; i < level.num_entities; i++, ent++ ) {
		qboolean f1, f2;
		if( !ent->inuse || !ent->client ) {
			continue;
		}

		if( ent->client->sess.playerType == PC_RECON ) {
			if( ent->health > 0 ) {
				f1 = ent->client->sess.sessionTeam == TEAM_ALLIES ? qtrue : qfalse;
				f2 = ent->client->sess.sessionTeam == TEAM_AXIS ?	qtrue : qfalse;

				G_SetupFrustum( ent );

				for( j = 0, ent2 = g_entities; j < level.num_entities; j++, ent2++ ) {
					if( !ent2->inuse || ent2 == ent ) {
						continue;
					}

					switch(ent2->s.eType) {
					case ET_PLAYER:
						{
						vec3_t pos[3];
						VectorCopy( ent2->client->ps.origin, pos[0] );
						pos[0][2] += ent2->client->ps.mins[2];
						VectorCopy( ent2->client->ps.origin, pos[1] );
						VectorCopy( ent2->client->ps.origin, pos[2] );
						pos[2][2] += ent2->client->ps.maxs[2];
						if(ent2->health > 0 && (G_VisibleFromBinoculars( ent, ent2, pos[0] ) ||
												G_VisibleFromBinoculars( ent, ent2, pos[1] ) ||
												G_VisibleFromBinoculars( ent, ent2, pos[2] ) ) ) {
							if(ent2->client->sess.sessionTeam != ent->client->sess.sessionTeam) {
								int k;

								switch(ent2->client->sess.sessionTeam) {
								case TEAM_AXIS:
									mEnt = G_FindMapEntityData( &mapEntityData[0], ent2-g_entities );
									if( mEnt && level.time - mEnt->startTime > 5000) {
										for( k = 0; k < MAX_CLIENTS; k++ ) {
											if(g_entities[k].inuse && g_entities[k].client && g_entities[k].client->sess.sessionTeam == ent->client->sess.sessionTeam) {
												trap_SendServerCommand( k, va( "tt \"ENEMY SPOTTED <STOP> CHECK COMMAND MAP FOR DETAILS <STOP>\"\n" ));
											}
										}
									}
									break;

								case TEAM_ALLIES:
									mEnt = G_FindMapEntityData( &mapEntityData[1], ent2-g_entities );
									if( mEnt && level.time - mEnt->startTime > 5000) {
										for( k = 0; k < MAX_CLIENTS; k++ ) {
											if(g_entities[k].inuse && g_entities[k].client && g_entities[k].client->sess.sessionTeam == ent->client->sess.sessionTeam) {
												trap_SendServerCommand( k, va( "tt \"ENEMY SPOTTED <STOP> CHECK COMMAND MAP FOR DETAILS <STOP>\"\n" ));
											}
										}
									}
									break;
								}
							}

							G_UpdateTeamMapData_Player(ent2, f1, f2);
						}
						break;
						}
					default:
						break;
					}
				}

				if(ent->client->ps.eFlags & EF_ZOOMING) {
					G_SetupFrustum_ForBinoculars( ent );

					for(j = 0, ent2 = g_entities; j < level.num_entities; j++, ent2++) {
						if(!ent2->inuse || ent2 == ent) {
							continue;
						}

						switch(ent2->s.eType) {
						case ET_MISSILE:
							if( ent2->methodOfDeath == MOD_LANDMINE) {
								if( (ent2->s.teamNum < 4 || ent2->s.teamNum >= 8) && (ent2->s.teamNum%4 != ent->client->sess.sessionTeam) ) 
								{
									// TAT - as before, we can only detect a mine if we can see it from our binoculars
									if (G_VisibleFromBinoculars( ent, ent2, ent2->r.currentOrigin ))
									{
										G_UpdateTeamMapData_LandMine(ent2, f1, f2);

										switch(ent2->s.teamNum%4) {
										case TEAM_AXIS:
											if( !ent2->s.modelindex2 ) {
												ent->client->landmineSpottedTime = level.time;
												ent->client->landmineSpotted = ent2;
												ent2->s.density = ent-g_entities+1;
												ent2->missionLevel = level.time;

												ent->client->landmineSpotted->count2 += 50;
												if(ent->client->landmineSpotted->count2 >= 250) {
//													int k;
													ent->client->landmineSpotted->count2 = 250;

													ent->client->landmineSpotted->s.modelindex2 = 1;

													// for marker
													ent->client->landmineSpotted->s.frame = rand() % 20;
													ent->client->landmineSpotted->r.contents = CONTENTS_CORPSE;
													trap_LinkEntity( ent->client->landmineSpotted );

													{
														gentity_t* pm = G_PopupMessage( PM_MINES );
														VectorCopy( ent->client->landmineSpotted->r.currentOrigin, pm->s.origin );
														pm->s.effect2Time = TEAM_AXIS;
														pm->s.effect3Time = ent-g_entities;
													}

/*													for( k = 0; k < MAX_CLIENTS; k++ ) {
														if(g_entities[k].inuse && g_entities[k].client && g_entities[k].client->sess.sessionTeam == ent->client->sess.sessionTeam) {
															trap_SendServerCommand( k, va( "tt \"LANDMINES SPOTTED BY %s^0<STOP> CHECK COMMAND MAP FOR DETAILS <STOP>\"\n", ent->client->pers.netname));
														}
													}*/

													trap_SendServerCommand( ent-g_entities, "cp \"Landmine Revealed\n\"" );

													AddScore( ent, 1 );
													//G_AddExperience( ent, 1.f );

													G_AddSkillPoints( ent, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 3.f );
													G_DebugAddSkillPoints( ent, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 3.f, "spotting a landmine" );
												}
											}
											break;

										case TEAM_ALLIES:
											if( !ent2->s.modelindex2 ) {
												ent->client->landmineSpottedTime = level.time;
												ent->client->landmineSpotted = ent2;
												ent2->s.density = ent-g_entities+1;
												ent2->missionLevel = level.time;

												ent->client->landmineSpotted->count2 += 50;
												if(ent->client->landmineSpotted->count2 >= 250) {
//													int k;
													ent->client->landmineSpotted->count2 = 250;

													ent->client->landmineSpotted->s.modelindex2 = 1;

													// for marker
													ent->client->landmineSpotted->s.frame = rand() % 20;
													ent->client->landmineSpotted->r.contents = CONTENTS_CORPSE;
													trap_LinkEntity( ent->client->landmineSpotted );

													{
														gentity_t* pm = G_PopupMessage( PM_MINES );
														VectorCopy( ent->client->landmineSpotted->r.currentOrigin, pm->s.origin );

														pm->s.effect2Time = TEAM_ALLIES;
														pm->s.effect3Time = ent-g_entities;
													}

/*													for( k = 0; k < MAX_CLIENTS; k++ ) {
														if(g_entities[k].inuse && g_entities[k].client && g_entities[k].client->sess.sessionTeam == ent->client->sess.sessionTeam) {
															trap_SendServerCommand( k, va( "tt \"LANDMINES SPOTTED BY %s^0<STOP> CHECK COMMAND MAP FOR DETAILS <STOP>\"\n", ent->client->pers.netname));
														}
													}*/

													trap_SendServerCommand( ent-g_entities, "cp \"Landmine Revealed\n\"" );

													AddScore( ent, 1 );
													//G_AddExperience( ent, 1.f );

													G_AddSkillPoints( ent, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 3.f );
													G_DebugAddSkillPoints( ent, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 3.f, "spotting a landmine" );
												}
											}
											break;
										} // end switch
									} // end (G_VisibleFromBinoculars( ent, ent2, ent2->r.currentOrigin ))
									else
									{
										// TAT - if we can't see the mine from our binoculars, make sure we clear out the landmineSpotted ptr,
										//		because bots looking for mines are getting confused
										ent->client->landmineSpotted = NULL;
									}
								}
							}
							break;
						default:
							break;
						}
					}

/*					if(ent->client->landmineSpotted && !ent->client->landmineSpotted->s.modelindex2) {
						ent->client->landmineSpotted->count2 += 10;
						if(ent->client->landmineSpotted->count2 >= 250) {
							int k;
							ent->client->landmineSpotted->count2 = 250;

							ent->client->landmineSpotted->s.modelindex2 = 1;

							// for marker
							ent->client->landmineSpotted->s.frame = rand() % 20;

							for( k = 0; k < MAX_CLIENTS; k++ ) {
								if(g_entities[k].inuse && g_entities[k].client && g_entities[k].client->sess.sessionTeam == ent->client->sess.sessionTeam) {
									trap_SendServerCommand( k, va( "tt \"LANDMINES SPOTTED <STOP> CHECK COMMAND MAP FOR DETAILS <STOP>\"\n" ));
								}
							}
							trap_SendServerCommand( ent-g_entities, "cp \"Landmine Revealed\n\"" );

							AddScore( ent, 1 );
							//G_AddExperience( ent, 1.f );

							G_AddSkillPoints( ent, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 3.f );
							G_DebugAddSkillPoints( ent, SK_MILITARY_INTELLIGENCE_AND_SCOPED_WEAPONS, 3.f, "spotting a landmine" );
						}
					}*/

/*					{
						// find any landmines that don't actually exist anymore, see if the covert ops can see the spot and if so - wipe them
						mapEntityData_Team_t *teamList = ent->client->sess.sessionTeam == TEAM_AXIS ? &mapEntityData[0] : &mapEntityData[1];

						mEnt = teamList->activeMapEntityData.next;
						while( mEnt && mEnt != &teamList->activeMapEntityData ) {
							if( mEnt->type == ME_LANDMINE && mEnt->entNum == -1 ) {
								if( G_VisibleFromBinoculars( ent, NULL, mEnt->org ) ) {
									mEnt = G_FreeMapEntityData( teamList, mEnt );

									trap_SendServerCommand( ent-g_entities, "print \"Old Landmine Cleared\n\"" );
									AddScore( ent, 1 );
									continue;
								}
							}

							mEnt = mEnt->next;
						}
					}*/
				}
			}
		}
	}

//	G_SendAllMapEntityInfo();
}
void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,  vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
	gclient_t	*client;
	int			take;
	int			save;
	int			knockback;
	qboolean	headShot;
	qboolean	wasAlive;
	hitRegion_t	hr = HR_NUM_HITREGIONS;

	if (!targ->takedamage) {
		return;
	}

#ifdef SAVEGAME_SUPPORT
	if( g_gametype.integer == GT_SINGLE_PLAYER && ( g_reloading.integer || saveGamePending ) )
		return;
#endif // SAVEGAME_SUPPORT

//	trap_SendServerCommand( -1, va("print \"%i\n\"\n", targ->health) );

	// the intermission has allready been qualified for, so don't
	// allow any extra scoring
	if ( level.intermissionQueued || (g_gamestate.integer != GS_PLAYING && match_warmupDamage.integer == 0)) {
		return;
	}

	if ( !inflictor ) {
		inflictor = &g_entities[ENTITYNUM_WORLD];
	}
	if ( !attacker ) {
		attacker = &g_entities[ENTITYNUM_WORLD];
	}

	// Arnout: invisible entities can't be damaged
	if( targ->entstate == STATE_INVISIBLE ||
		targ->entstate == STATE_UNDERCONSTRUCTION ) {
		return;
	}

	// xkan, 12/23/2002 - was the bot alive before applying any damage?
	wasAlive = (targ->health > 0);

	// Arnout: combatstate
	if( targ->client && attacker && attacker->client && attacker != targ ) {
		/*vec_t dist = -1.f;

		if( targ->client->combatState < COMBATSTATE_HOT ) {
			vec3_t shotvec;

			VectorSubtract( targ->r.currentOrigin, attacker->r.currentOrigin, shotvec );
			dist = VectorLengthSquared( shotvec );

			if( dist < Square(1500.f) && targ->client->combatState == COMBATSTATE_WARM )
				targ->client->combatState = COMBATSTATE_HOT;
		}

		if( attacker->client->combatState < COMBATSTATE_HOT ) {
			if( dist < 0.f ) {
				vec3_t shotvec;

				VectorSubtract( targ->r.currentOrigin, attacker->r.currentOrigin, shotvec );
				dist = VectorLengthSquared( shotvec );
			}

			if( dist > Square(1500.f) )
				attacker->client->combatState = COMBATSTATE_WARM;
			else if( attacker->client->combatState == COMBATSTATE_WARM )
				attacker->client->combatState = COMBATSTATE_HOT;
		}*/

		if( g_gamestate.integer == GS_PLAYING ) {
			if( !OnSameTeam( attacker, targ ) ) {
				targ->client->combatState |= (1<<COMBATSTATE_DAMAGERECEIVED);
				attacker->client->combatState |= (1<<COMBATSTATE_DAMAGEDEALT);
			}
		}
	}

// JPW NERVE
	if ((targ->waterlevel >= 3) && (mod == MOD_FLAMETHROWER))
		return;
// jpw

	// shootable doors / buttons don't actually have any health
	if ( targ->s.eType == ET_MOVER && !(targ->isProp) && !targ->scriptName) {
		if ( targ->use && targ->moverState == MOVER_POS1 ) {
			G_UseEntity( targ, inflictor, attacker );
		}
		return;
	}


	// TAT 11/22/2002
	//		In the old code, this check wasn't done for props, so I put that check back in to make props_statue properly work	
	// 4 means destructible
	if ( targ->s.eType == ET_MOVER && (targ->spawnflags & 4) && !targ->isProp ) 
	{
		/*switch (mod) {
		case MOD_GRENADE:
		case MOD_GRENADE_LAUNCHER:
		case MOD_ROCKET:
		case MOD_AIRSTRIKE:
		case MOD_ARTY:
		case MOD_GRENADE_PINEAPPLE:
		case MOD_MAPMORTAR:
		case MOD_EXPLOSIVE:
		case MOD_DYNAMITE:
		case MOD_LANDMINE:
		case MOD_GPG40:
		case MOD_M7:
		case MOD_TELEFRAG:
		case MOD_PANZERFAUST:
		case MOD_SATCHEL:
			break;
		default:
			return;	// no damage from other weapons
		}*/
		if( !G_WeaponIsExplosive( mod ) ) {
			return;
		}

		// check for team
		if( G_GetTeamFromEntity( inflictor ) == G_GetTeamFromEntity( targ ) ) {
			return;
		}
	} else if ( targ->s.eType == ET_EXPLOSIVE ) {
		/*// 32 Explosive
		// 64 Dynamite only
		// 256 Airstrike/artillery only
		// 512 Satchel only
		if ((targ->spawnflags & 32) || (targ->spawnflags & 64) || (targ->spawnflags & 256) || (targ->spawnflags & 512))
		{
			switch (mod) {
			case MOD_GRENADE:
			case MOD_GRENADE_LAUNCHER:
			case MOD_ROCKET:
			case MOD_GRENADE_PINEAPPLE:
			case MOD_MAPMORTAR:
			case MOD_EXPLOSIVE:
			case MOD_LANDMINE:
			case MOD_GPG40:
			case MOD_M7:
				if( !(targ->spawnflags & 32) )
					return;
				break;
			case MOD_SATCHEL:
				if( !(targ->spawnflags & 512) )
					return;
				break;
			case MOD_ARTY:
			case MOD_AIRSTRIKE:
				if( !(targ->spawnflags & 256) )
					return;
				break;
			case MOD_DYNAMITE:
				if( !(targ->spawnflags & 64) )
					return;
				break;
			default: 
				return;
			}

			// check for team
			if( targ->s.teamNum == inflictor->s.teamNum ) {
				return;
			}
		}*/
		
		if( targ->parent && G_GetWeaponClassForMOD( mod ) == 2 ) {
			return;
		}

		// check for team
//		if( G_GetWeaponClassForMOD( mod ) != -1 && targ->s.teamNum == inflictor->s.teamNum ) {
//			return;
//		}
		if( G_GetTeamFromEntity( inflictor ) == G_GetTeamFromEntity( targ ) ) {
			return;
		}

		if( G_GetWeaponClassForMOD( mod ) < targ->constructibleStats.weaponclass ) {
			return;
		}
	}
	else if ( targ->s.eType == ET_MISSILE && targ->methodOfDeath == MOD_LANDMINE ) {
		if( targ->s.modelindex2 ) {
			if( G_WeaponIsExplosive( mod ) ) {
				mapEntityData_t	*mEnt;

				if((mEnt = G_FindMapEntityData(&mapEntityData[0], targ-g_entities)) != NULL) {
					G_FreeMapEntityData( &mapEntityData[0], mEnt );
				}

				if((mEnt = G_FindMapEntityData(&mapEntityData[1], targ-g_entities)) != NULL) {
					G_FreeMapEntityData( &mapEntityData[1], mEnt );
				}

				if( attacker && attacker->client ) {
					AddScore( attacker, 1 );
					//G_AddExperience( attacker, 1.f );
				}

				G_ExplodeMissile(targ);
			}
		}
		return;
	} else if ( targ->s.eType == ET_CONSTRUCTIBLE ) {

		if( G_GetTeamFromEntity( inflictor ) == G_GetTeamFromEntity( targ ) ) {
			return;
		}

		if( G_GetWeaponClassForMOD( mod ) < targ->constructibleStats.weaponclass ) {
			return;
		}
	}

	client = targ->client;

	if ( client ) {
		if ( client->noclip || client->ps.powerups[PW_INVULNERABLE] ) {
			return;
		}
	}

	// check for godmode
	if ( targ->flags & FL_GODMODE ) {
		return;
	}

	if ( !dir ) {
		dflags |= DAMAGE_NO_KNOCKBACK;
	} else {
		VectorNormalize(dir);
	}

	knockback = damage;
	if ( knockback > 200 ) {
		knockback = 200;
	}
	if ( targ->flags & FL_NO_KNOCKBACK ) {
		knockback = 0;
	}
	if ( dflags & DAMAGE_NO_KNOCKBACK ) {
		knockback = 0;
	} else if( dflags & DAMAGE_HALF_KNOCKBACK ) {
		knockback *= 0.5f;
	}
	
	// ydnar: set weapons means less knockback
	if( client && (client->ps.weapon == WP_MORTAR_SET || client->ps.weapon == WP_MOBILE_MG42_SET) )
		knockback *= 0.5;

	if( targ->client && g_friendlyFire.integer && OnSameTeam(targ, attacker) ) {
		knockback = 0;
	}
	
	// figure momentum add, even if the damage won't be taken
	if ( knockback && targ->client ) {
		vec3_t	kvel;
		float	mass;

		mass = 200;

		VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
		VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);

		/*if( mod == MOD_GRENADE ||
			mod == MOD_GRENADE_LAUNCHER ||
			mod == MOD_DYNAMITE ||
			mod == MOD_GPG40 ||
			mod == MOD_M7 ||
 			mod == MOD_LANDMINE ) {
			targ->client->ps.velocity[2] *= 2.f;				// gimme air baby!
			targ->client->ps.groundEntityNum = ENTITYNUM_NONE;	// flying high!
		} else if( mod == MOD_ROCKET ) {
			targ->client->ps.velocity[2] *= .75f;				// but not to the moon please!
			targ->client->ps.groundEntityNum = ENTITYNUM_NONE;	// flying high!
		}*/

		if (targ == attacker && !(	mod != MOD_ROCKET &&
									mod != MOD_GRENADE &&
									mod != MOD_GRENADE_LAUNCHER &&
									mod != MOD_DYNAMITE
									&& mod != MOD_GPG40
									&& mod != MOD_M7
									&& mod != MOD_LANDMINE
									))
		{
			targ->client->ps.velocity[2] *= 0.25;
		}

		// set the timer so that the other client can't cancel
		// out the movement immediately
		if ( !targ->client->ps.pm_time ) {
			int		t;

			t = knockback * 2;
			if ( t < 50 ) {
				t = 50;
			}
			if ( t > 200 ) {
				t = 200;
			}
			targ->client->ps.pm_time = t;
			targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
		}
	}

	// check for completely getting out of the damage
	if ( !(dflags & DAMAGE_NO_PROTECTION) ) {

		// if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
		// if the attacker was on the same team
		if ( targ != attacker && OnSameTeam (targ, attacker)  ) {
			if ( (g_gamestate.integer != GS_PLAYING && match_warmupDamage.integer == 1)) {
				return;
			}
			else if (!g_friendlyFire.integer)
			{
				return;
			}
		}
	}

	// add to the attacker's hit counter
	if ( attacker->client && targ != attacker && targ->health > 0 ) {
		if ( OnSameTeam( targ, attacker ) ) {
			attacker->client->ps.persistant[PERS_HITS] -= damage;
		} else {
			attacker->client->ps.persistant[PERS_HITS] += damage;
		}
	}

	if ( damage < 1 ) {
		damage = 1;
	}
	take = damage;
	save = 0;

	// adrenaline junkie!
	if( targ->client && targ->client->ps.powerups[PW_ADRENALINE] ) {
		take *= .5f;
	}

	// save some from flak jacket
	if( targ->client && targ->client->sess.skill[SK_EXPLOSIVES_AND_CONSTRUCTION] >= 4 && targ->client->sess.playerType == PC_ENGINEER ) {
		if( mod == MOD_GRENADE ||
			mod == MOD_GRENADE_LAUNCHER ||
			mod == MOD_ROCKET ||
			mod == MOD_GRENADE_PINEAPPLE ||
			mod == MOD_MAPMORTAR ||
			mod == MOD_MAPMORTAR_SPLASH || 
			mod == MOD_EXPLOSIVE ||
			mod == MOD_LANDMINE ||
			mod == MOD_GPG40 ||
			mod == MOD_M7 ||
			mod == MOD_SATCHEL ||
			mod == MOD_ARTY ||
			mod == MOD_AIRSTRIKE ||
			mod == MOD_DYNAMITE ||
			mod == MOD_MORTAR ||
			mod == MOD_PANZERFAUST ||
			mod == MOD_MAPMORTAR ) {
			take -= take * .5f;
		}
	}

	headShot = IsHeadShot(targ, dir, point, mod);
	if ( headShot ) {
		if( take * 2 < 50 ) // head shots, all weapons, do minimum 50 points damage
			take = 50;
		else
			take *= 2; // sniper rifles can do full-kill (and knock into limbo)

		if( dflags & DAMAGE_DISTANCEFALLOFF ) {
			vec_t dist;
			vec3_t shotvec;

			VectorSubtract( point, muzzleTrace, shotvec );
			dist = VectorLength( shotvec );

			if( dist > 1500.f ) {
				if( dist > 2500.f ) {
					take *= 0.2f;
				} else {
					float scale = 1.f - 0.2f * (1000.f / (dist - 1000.f));

					take *= scale;
				}
			}
		}

		if( !(targ->client->ps.eFlags & EF_HEADSHOT) ) {	// only toss hat on first headshot
			G_AddEvent( targ, EV_LOSE_HAT, DirToByte(dir) );

			if( mod != MOD_K43_SCOPE &&
				mod != MOD_GARAND_SCOPE ) {
				take *= .8f;	// helmet gives us some protection
			}
		}

		targ->client->ps.eFlags |= EF_HEADSHOT;

		// OSP - Record the headshot
		if(client && attacker && attacker->client
#ifndef DEBUG_STATS
		  && attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam
#endif
		  ) {
			G_addStatsHeadShot(attacker, mod);
		}

		if( g_debugBullets.integer ) {
			trap_SendServerCommand( attacker-g_entities, "print \"Head Shot\n\"\n");
		}
		G_LogRegionHit( attacker, HR_HEAD );
		hr = HR_HEAD;
	} else if ( IsLegShot(targ, dir, point, mod) ) {
		G_LogRegionHit( attacker, HR_LEGS );
		hr = HR_LEGS;
		if( g_debugBullets.integer ) {
			trap_SendServerCommand( attacker-g_entities, "print \"Leg Shot\n\"\n");
		}
	} else if ( IsArmShot(targ, attacker, point, mod) ) {
		G_LogRegionHit( attacker, HR_ARMS );
		hr = HR_ARMS;
		if( g_debugBullets.integer ) {
			trap_SendServerCommand( attacker-g_entities, "print \"Arm Shot\n\"\n");
		}
	} else if (targ->client && targ->health > 0 && IsHeadShotWeapon( mod ) ) {
		G_LogRegionHit( attacker, HR_BODY );
		hr = HR_BODY;
		if( g_debugBullets.integer ) {
			trap_SendServerCommand( attacker-g_entities, "print \"Body Shot\n\"\n");
		}
	}

#ifndef DEBUG_STATS
	if ( g_debugDamage.integer )
#endif
	{
		G_Printf( "client:%i health:%i damage:%i mod:%s\n", targ->s.number, targ->health, take, modNames[mod] );
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if ( client ) {
		if ( attacker ) {
			client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
		} else {
			client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
		}
		client->damage_blood += take;
		client->damage_knockback += knockback;

		if ( dir ) {
			VectorCopy ( dir, client->damage_from );
			client->damage_fromWorld = qfalse;
		} else {
			VectorCopy ( targ->r.currentOrigin, client->damage_from );
			client->damage_fromWorld = qtrue;
		}
	}

	// See if it's the player hurting the emeny flag carrier
//	Team_CheckHurtCarrier(targ, attacker);

	if (targ->client) {
		// set the last client who damaged the target
		targ->client->lasthurt_client = attacker->s.number;
		targ->client->lasthurt_mod = mod;
	}

	// do the damage
	if( take ) {
		targ->health -= take;

		// Gordon: don't ever gib POWS
		if( ( targ->health <= 0 ) && ( targ->r.svFlags & SVF_POW ) ) {
			targ->health = -1;
		}

		// Ridah, can't gib with bullet weapons (except VENOM)
		// Arnout: attacker == inflictor can happen in other cases as well! (movers trying to gib things)
		//if ( attacker == inflictor && targ->health <= GIB_HEALTH) {
		if( targ->health <= GIB_HEALTH ) {
			if( !G_WeaponIsExplosive( mod ) ) {
				targ->health = GIB_HEALTH + 1;
			}
		}

// JPW NERVE overcome previous chunk of code for making grenades work again
//		if ((take > 190)) // 190 is greater than 2x mauser headshot, so headshots don't gib
		// Arnout: only player entities! messes up ents like func_constructibles and func_explosives otherwise
		if( ( (targ->s.number < MAX_CLIENTS) && (take > 190) ) && !(targ->r.svFlags & SVF_POW) ) {
			targ->health = GIB_HEALTH - 1;
		}

		if( targ->s.eType == ET_MOVER && !Q_stricmp( targ->classname, "script_mover" ) ) {
			targ->s.dl_intensity = 255.f * (targ->health / (float)targ->count);	// send it to the client
		}

		//G_Printf("health at: %d\n", targ->health);
		if( targ->health <= 0 ) {
			if( client && !wasAlive ) {
				targ->flags |= FL_NO_KNOCKBACK;
				// OSP - special hack to not count attempts for body gibbage
				if( targ->client->ps.pm_type == PM_DEAD ) {
					G_addStats(targ, attacker, take, mod);
				}

				if( (targ->health < FORCE_LIMBO_HEALTH) && (targ->health > GIB_HEALTH) ) {
					limbo(targ, qtrue);
				}

				// xkan, 1/13/2003 - record the time we died.
				if (!client->deathTime)
					client->deathTime = level.time;
			} else {


				targ->sound1to2 = hr;
				targ->sound2to1 = mod;
				targ->sound2to3 = (dflags & DAMAGE_RADIUS) ? 1 : 0;

				if( client ) {
					if( G_GetTeamFromEntity( inflictor ) != G_GetTeamFromEntity( targ ) ) {
						G_AddKillSkillPoints( attacker, mod, hr, (dflags & DAMAGE_RADIUS) );
					}
				}

				if( targ->health < -999 ) {
					targ->health = -999;
				}


				targ->enemy = attacker;
				targ->deathType = mod;

				// Ridah, mg42 doesn't have die func (FIXME)
				if( targ->die ) {	
					// Kill the entity.  Note that this funtion can set ->die to another
					// function pointer, so that next time die is applied to the dead body.
					targ->die( targ, inflictor, attacker, take, mod );
					// OSP - kill stats in player_die function
				}

				if( targ->s.eType == ET_MOVER && !Q_stricmp( targ->classname, "script_mover" ) && (targ->spawnflags & 8) ) {
					return;	// reseructable script mover doesn't unlink itself but we don't want a second death script to be called
				}

				// if we freed ourselves in death function
				if (!targ->inuse)
					return;

				// RF, entity scripting
				if (targ->health <= 0)
				{	// might have revived itself in death function
					if ((targ->s.eType != ET_CONSTRUCTIBLE && targ->s.eType != ET_EXPLOSIVE) ||	(targ->s.eType == ET_CONSTRUCTIBLE && !targ->desstages))
					{ // call manually if using desstages
						G_Script_ScriptEvent( targ, "death", "" );
					}
				}
			}

		}
		else if ( targ->pain )
		{
			if (dir) {	// Ridah, had to add this to fix NULL dir crash
				VectorCopy (dir, targ->rotate);
				VectorCopy (point, targ->pos3); // this will pass loc of hit
			} else {
				VectorClear( targ->rotate );
				VectorClear( targ->pos3 );
			}

			targ->pain (targ, attacker, take, point);
		} else {
			// OSP - update weapon/dmg stats
			G_addStats(targ, attacker, take, mod);
			// OSP
		}

		// RF, entity scripting
		G_Script_ScriptEvent( targ, "pain", va("%d %d", targ->health, targ->health+take) );

		// Ridah, this needs to be done last, incase the health is altered in one of the event calls
		if ( targ->client ) {
			targ->client->ps.stats[STAT_HEALTH] = targ->health;
		}
	}
}
Exemple #17
0
// Dini, Note, this is where damage etc is dealt out!
void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,  vec3_t dir, vec3_t point, int damage, int dflags, int mod ) {
	gclient_t	*client;
	int			take;
	int			save;
	int			knockback;
	qboolean	headShot;
	qboolean	wasAlive;
	hitRegion_t	hr = HR_NUM_HITREGIONS;

	if (!targ->takedamage) {
		return;
	}

	// the intermission has already been qualified for, so don't
	// allow any extra scoring
	// CHRUKER: b024 - Don't do damage if at warmup and warmupdamage is set to 'None' and the target is a client.
	if ( level.intermissionQueued || (g_gamestate.integer != GS_PLAYING && targ->client)) {
		return;
	}

	if ( !inflictor ) {
		inflictor = &g_entities[ENTITYNUM_WORLD];
	}
	if ( !attacker ) {
		attacker = &g_entities[ENTITYNUM_WORLD];
	}

	// Arnout: invisible entities can't be damaged
	if( targ->entstate == STATE_INVISIBLE ||
		targ->entstate == STATE_UNDERCONSTRUCTION ) {
		return;
	}

	// xkan, 12/23/2002 - was the bot alive before applying any damage?
	wasAlive = (targ->health > 0);

	// Arnout: combatstate
	if( targ->client && attacker && attacker->client && attacker != targ ) {
		if( g_gamestate.integer == GS_PLAYING ) {
			if( !OnSameTeam( attacker, targ ) ) {
				targ->client->combatState |= (1<<COMBATSTATE_DAMAGERECEIVED);
				attacker->client->combatState |= (1<<COMBATSTATE_DAMAGEDEALT);
			}
		}
	}

// JPW NERVE
	if ((targ->waterlevel >= 3) && (mod == MOD_FLAMETHROWER))
		return;
// jpw

	// shootable doors / buttons don't actually have any health
	if ( targ->s.eType == ET_MOVER && !(targ->isProp) && !targ->scriptName) {
		if ( targ->use && targ->moverState == MOVER_POS1 ) {
			G_UseEntity( targ, inflictor, attacker );
		}
		return;
	}

	// 4 means destructible
	if ( targ->s.eType == ET_MOVER && (targ->spawnflags & 4) && !targ->isProp ) 
	{
		if( !G_WeaponIsExplosive( mod ) ) {
			return;
		}

		// check for team
		if( G_GetTeamFromEntity( inflictor ) == G_GetTeamFromEntity( targ ) ) {
			return;
		}
	} else if ( targ->s.eType == ET_EXPLOSIVE ) {
		if( targ->parent && G_GetWeaponClassForMOD( mod ) == 2 ) {
			return;
		}

		if( G_GetTeamFromEntity( inflictor ) == G_GetTeamFromEntity( targ ) ) {
			return;
		}

		if( G_GetWeaponClassForMOD( mod ) < targ->constructibleStats.weaponclass ) {
			return;
		}
	}
	else if ( targ->s.eType == ET_MISSILE && targ->methodOfDeath == MOD_LANDMINE ) {
		if( targ->s.modelindex2 ) {
			if( G_WeaponIsExplosive( mod ) ) {
				mapEntityData_t	*mEnt;

				if((mEnt = G_FindMapEntityData(&mapEntityData[0], targ-g_entities)) != NULL) {
					G_FreeMapEntityData( &mapEntityData[0], mEnt );
				}

				if((mEnt = G_FindMapEntityData(&mapEntityData[1], targ-g_entities)) != NULL) {
					G_FreeMapEntityData( &mapEntityData[1], mEnt );
				}

				if( attacker && attacker->client ) {
					AddScore( attacker, 1 );
				}

				G_ExplodeMissile(targ);
			}
		}
		return;
	} else if ( targ->s.eType == ET_CONSTRUCTIBLE ) {

		if( G_GetTeamFromEntity( inflictor ) == G_GetTeamFromEntity( targ ) ) {
			return;
		}

		if( G_GetWeaponClassForMOD( mod ) < targ->constructibleStats.weaponclass ) {
			return;
		}
		//bani - fix #238
		if ( mod == MOD_DYNAMITE ) {
			if( !( inflictor->etpro_misc_1 & 1 ) )
				return;
		}
	}

	client = targ->client;

	// Dini, Note, Noclip..
	if ( client ) {
		if ( client->noclip || client->ps.powerups[PW_INVULNERABLE] ) {
			return;
		}
	}

	// check for godmode
	if ( targ->flags & FL_GODMODE ) {
		return;
	}

	if ( !dir ) {
		dflags |= DAMAGE_NO_KNOCKBACK;
	} else {
		VectorNormalize(dir);
	}

	
	// Only do knockback to yourself
	if (attacker->client == targ->client)
		knockback = 1;
	else
		knockback = 0;

	// figure momentum add, even if the damage won't be taken
	if ( knockback && targ->client ) {
		vec3_t	kvel;
		int		knock;

		if (mod == MOD_PANZERFAUST)
			knock = 500;
		else
			knock = 1000;

		// Dini, Note, Fix this sometime..
		VectorScale (dir, knock, kvel);
		VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);

		if (targ == attacker && !(	mod != MOD_ROCKET &&
									mod != MOD_GRENADE &&
									mod != MOD_GRENADE_LAUNCHER &&
									mod != MOD_DYNAMITE
									&& mod != MOD_GPG40
									&& mod != MOD_M7
									&& mod != MOD_LANDMINE
									))
		{
			targ->client->ps.velocity[2] *= 0.25;
		}

		// set the timer so that the other client can't cancel
		// out the movement immediately
		if ( !targ->client->ps.pm_time ) {
			int		t;

			t = knockback * 2;
			if ( t < 50 ) {
				t = 50;
			}
			if ( t > 200 ) {
				t = 200;
			}
			targ->client->ps.pm_time = t;
			targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
		}
	}

	// check for completely getting out of the damage
	if ( !(dflags & DAMAGE_NO_PROTECTION) ) {
		// Dini, disable damage taking for players, aka if they're on a team
		if (OnAnyTeam (targ, attacker) && !tjg_damage.integer)
			return;

		// if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
		// if the attacker was on the same team
		if ( targ != attacker && OnSameTeam (targ, attacker)  ) {
			if ( (g_gamestate.integer != GS_PLAYING)) {
				return;
			}
			else if (!g_friendlyFire.integer) {
				return;
			}
		}
	}

	// add to the attacker's hit counter
	if ( attacker->client && targ != attacker && targ->health > 0 ) {
		if ( OnSameTeam( targ, attacker ) ) {
			attacker->client->ps.persistant[PERS_HITS] -= damage;
		} else {
			attacker->client->ps.persistant[PERS_HITS] += damage;
		}
	}

	if ( damage < 1 ) {
		damage = 1;
	}
	take = damage;
	save = 0;

	headShot = IsHeadShot(targ, dir, point, mod);
	if ( headShot ) {
		if( take * 2 < 50 ) // head shots, all weapons, do minimum 50 points damage
			take = 50;
		else
			take *= 2; // sniper rifles can do full-kill (and knock into limbo)

		if( dflags & DAMAGE_DISTANCEFALLOFF ) {
			vec_t dist;
			vec3_t shotvec;
			float scale;

			VectorSubtract( point, muzzleTrace, shotvec );
			dist = VectorLength( shotvec );

			// zinx - start at 100% at 1500 units (and before),
			// and go to 20% at 2500 units (and after)

			// 1500 to 2500 -> 0.0 to 1.0
			scale = (dist - 1500.f) / (2500.f - 1500.f);
			// 0.0 to 1.0 -> 0.0 to 0.8
			scale *= 0.8f;
			// 0.0 to 0.8 -> 1.0 to 0.2
			scale = 1.0f - scale;

			// And, finally, cap it.
			if (scale > 1.0f) scale = 1.0f;
			else if (scale < 0.2f) scale = 0.2f;

			take *= scale;
		}

		if( !(targ->client->ps.eFlags & EF_HEADSHOT) ) {	// only toss hat on first headshot
			G_AddEvent( targ, EV_LOSE_HAT, DirToByte(dir) );

			if( mod != MOD_K43_SCOPE &&
				mod != MOD_GARAND_SCOPE ) {
				take *= .8f;	// helmet gives us some protection
			}
		}

		targ->client->ps.eFlags |= EF_HEADSHOT;

		// OSP - Record the headshot
		if(client && attacker && attacker->client
#ifndef DEBUG_STATS
		  && attacker->client->sess.sessionTeam != targ->client->sess.sessionTeam
#endif
		  ) {
			G_addStatsHeadShot(attacker, mod);
		}

		if( g_debugBullets.integer ) {
			trap_SendServerCommand( attacker-g_entities, "print \"Head Shot\n\"\n");
		}
		G_LogRegionHit( attacker, HR_HEAD );
		hr = HR_HEAD;
	} else if ( IsLegShot(targ, dir, point, mod) ) {
		G_LogRegionHit( attacker, HR_LEGS );
		hr = HR_LEGS;
		if( g_debugBullets.integer ) {
			trap_SendServerCommand( attacker-g_entities, "print \"Leg Shot\n\"\n");
		}
	} else if ( IsArmShot(targ, attacker, point, mod) ) {
		G_LogRegionHit( attacker, HR_ARMS );
		hr = HR_ARMS;
		if( g_debugBullets.integer ) {
			trap_SendServerCommand( attacker-g_entities, "print \"Arm Shot\n\"\n");
		}
	} else if (targ->client && targ->health > 0 && IsHeadShotWeapon( mod ) ) {
		G_LogRegionHit( attacker, HR_BODY );
		hr = HR_BODY;
		if( g_debugBullets.integer ) {
			trap_SendServerCommand( attacker-g_entities, "print \"Body Shot\n\"\n");
		}
	}

#ifndef DEBUG_STATS
	if ( g_debugDamage.integer )
#endif
	{
		G_Printf( "client:%i health:%i damage:%i mod:%s\n", targ->s.number, targ->health, take, modNames[mod] );
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if ( client ) {
		if ( attacker ) {
			client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
		} else {
			client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
		}
		client->damage_blood += take;
		// Dini, removed for now.
		//client->damage_knockback += knockback;

		if ( dir ) {
			VectorCopy ( dir, client->damage_from );
			client->damage_fromWorld = qfalse;
		} else {
			VectorCopy ( targ->r.currentOrigin, client->damage_from );
			client->damage_fromWorld = qtrue;
		}
	}

	// See if it's the player hurting the emeny flag carrier
//	Team_CheckHurtCarrier(targ, attacker);

	if (targ->client) {
		// set the last client who damaged the target
		targ->client->lasthurt_client = attacker->s.number;
		targ->client->lasthurt_mod = mod;
	}

	// do the damage
	if( take ) {
		targ->health -= take;

		// Gordon: don't ever gib POWS
		if( ( targ->health <= 0 ) && ( targ->r.svFlags & SVF_POW ) ) {
			targ->health = -1;
		}

		// Ridah, can't gib with bullet weapons (except VENOM)
		// Arnout: attacker == inflictor can happen in other cases as well! (movers trying to gib things)
		//if ( attacker == inflictor && targ->health <= GIB_HEALTH) {
		/*if( targ->health <= GIB_HEALTH ) {
			if( !G_WeaponIsExplosive( mod ) ) {
				targ->health = GIB_HEALTH + 1;
			}
		}*/

// JPW NERVE overcome previous chunk of code for making grenades work again
//		if ((take > 190)) // 190 is greater than 2x mauser headshot, so headshots don't gib
		// Arnout: only player entities! messes up ents like func_constructibles and func_explosives otherwise
		if( ( (targ->s.number < MAX_CLIENTS) && (take > 190) ) && !(targ->r.svFlags & SVF_POW) ) {
			targ->health = GIB_HEALTH - 1;
		}

		if( targ->s.eType == ET_MOVER && !Q_stricmp( targ->classname, "script_mover" ) ) {
			targ->s.dl_intensity = 255.f * (targ->health / (float)targ->count);	// send it to the client
		}

		//G_Printf("health at: %d\n", targ->health);
		if( targ->health <= 0 ) {
			if( client && !wasAlive ) {
				targ->flags |= FL_NO_KNOCKBACK;
				// OSP - special hack to not count attempts for body gibbage
				if( targ->client->ps.pm_type == PM_DEAD ) {
					G_addStats(targ, attacker, take, mod);
				}

				/*if( (targ->health < FORCE_LIMBO_HEALTH) && (targ->health > GIB_HEALTH) ) {
					limbo(targ, qtrue);
				}*/
						
				if (targ->health <= 0 && targ->s.number < MAX_CLIENTS && !(targ->r.svFlags & SVF_POW))
				{
					targ->health = GIB_HEALTH - 1;
				}

				// xkan, 1/13/2003 - record the time we died.
				if (!client->deathTime)
					client->deathTime = level.time;
			} else {


				targ->sound1to2 = hr;
				targ->sound2to1 = mod;
				targ->sound2to3 = (dflags & DAMAGE_RADIUS) ? 1 : 0;

				if( client ) {
					if( G_GetTeamFromEntity( inflictor ) != G_GetTeamFromEntity( targ ) ) {
						G_AddKillSkillPoints( attacker, mod, hr, (dflags & DAMAGE_RADIUS) );
					}
				}

				if( targ->health < -999 ) {
					targ->health = -999;
				}


				targ->enemy = attacker;
				targ->deathType = mod;

				// Ridah, mg42 doesn't have die func (FIXME)
				if( targ->die ) {	
					// Kill the entity.  Note that this funtion can set ->die to another
					// function pointer, so that next time die is applied to the dead body.
					targ->die( targ, inflictor, attacker, take, mod );
					// OSP - kill stats in player_die function
				}

				if( targ->s.eType == ET_MOVER && !Q_stricmp( targ->classname, "script_mover" ) && (targ->spawnflags & 8) ) {
					return;	// reseructable script mover doesn't unlink itself but we don't want a second death script to be called
				}

				// if we freed ourselves in death function
				if (!targ->inuse)
					return;

				// RF, entity scripting
				if ( targ->health <= 0) {	// might have revived itself in death function
					if(	( targ->s.eType != ET_CONSTRUCTIBLE && targ->s.eType != ET_EXPLOSIVE ) ||
								( targ->s.eType == ET_CONSTRUCTIBLE && !targ->desstages ) )	{ // call manually if using desstages
						G_Script_ScriptEvent( targ, "death", "" );
					}
				}
			}

		} else if ( targ->pain ) {
			if (dir) {	// Ridah, had to add this to fix NULL dir crash
				VectorCopy (dir, targ->rotate);
				VectorCopy (point, targ->pos3); // this will pass loc of hit
			} else {
				VectorClear( targ->rotate );
				VectorClear( targ->pos3 );
			}

			targ->pain (targ, attacker, take, point);
		} else {
			// OSP - update weapon/dmg stats
			G_addStats(targ, attacker, take, mod);
			// OSP
		}

		// RF, entity scripting
		G_Script_ScriptEvent( targ, "pain", va("%d %d", targ->health, targ->health+take) );

		// Ridah, this needs to be done last, incase the health is altered in one of the event calls
		if ( targ->client ) {
			targ->client->ps.stats[STAT_HEALTH] = targ->health;
		}
	}
}
/*
================
G_SetEntState

  sets the entstate of an entity.
================
*/
void G_SetEntState( gentity_t *ent, entState_t state ) {
	if ( ent->entstate == state ) {
		G_DPrintf( "entity %i already in desired state [%i]\n", ent->s.number, state );
		return;
	}

	switch ( state ) {
	case STATE_DEFAULT:             if ( ent->entstate == STATE_UNDERCONSTRUCTION ) {
			ent->clipmask = ent->realClipmask;
			ent->r.contents = ent->realContents;
			if ( !ent->realNonSolidBModel ) {
				ent->s.eFlags &= ~EF_NONSOLID_BMODEL;
			}
	}

		ent->entstate = STATE_DEFAULT;
		ent->s.powerups = STATE_DEFAULT;

		if ( ent->s.eType == ET_WOLF_OBJECTIVE ) {
			char cs[MAX_STRING_CHARS];
			trap_GetConfigstring( ent->count, cs, sizeof( cs ) );
			ent->count2 &= ~256;
			Info_SetValueForKey( cs, "t", va( "%i", ent->count2 ) );
			trap_SetConfigstring( ent->count, cs );
		}

		if ( ent->s.eType != ET_COMMANDMAP_MARKER ) {
			trap_LinkEntity( ent );
		}

		// deal with any entities in the solid
		{
			int listedEntities, e;
			int entityList[MAX_GENTITIES];
			gentity_t *check, *block;

			listedEntities = trap_EntitiesInBox( ent->r.absmin, ent->r.absmax, entityList, MAX_GENTITIES );

			for ( e = 0; e < listedEntities; e++ ) {
				check = &g_entities[entityList[e]];

				// ignore everything but items, players and missiles (grenades too)
				if ( check->s.eType != ET_MISSILE && check->s.eType != ET_ITEM && check->s.eType != ET_PLAYER && !check->physicsObject ) {
					continue;
				}

				if ( ( block = G_TestEntityPosition( check ) ) == NULL ) {
					continue;
				}

				if ( block != ent ) {
					// the entity is blocked by another entity - that block this should take care of this itself
					continue;
				}

				if ( check->client || check->s.eType == ET_CORPSE ) {
					// gibs anything player like
					G_Damage( check, ent, ent, NULL, NULL, 9999, DAMAGE_NO_PROTECTION, MOD_CRUSH_CONSTRUCTIONDEATH_NOATTACKER );
				} else if ( check->s.eType == ET_ITEM && check->item->giType == IT_TEAM ) {
					// see if it's a critical entity, one that we can't just simply kill (basically flags)
					Team_DroppedFlagThink( check );
				} else {
					// remove the landmine from both teamlists
					if ( check->s.eType == ET_MISSILE && check->methodOfDeath == MOD_LANDMINE ) {
						mapEntityData_t *mEnt;

						if ( ( mEnt = G_FindMapEntityData( &mapEntityData[0], check - g_entities ) ) != NULL ) {
							G_FreeMapEntityData( &mapEntityData[0], mEnt );
						}

						if ( ( mEnt = G_FindMapEntityData( &mapEntityData[1], check - g_entities ) ) != NULL ) {
							G_FreeMapEntityData( &mapEntityData[1], mEnt );
						}
					}

					// just get rid of it
					G_TempEntity( check->s.origin, EV_ITEM_POP );
					G_FreeEntity( check );
				}
			}
		}

		// if this is an mg42, then we should try and calculate mg42 spots again
		BotCalculateMg42Spots();

		break;
	case STATE_UNDERCONSTRUCTION:   ent->entstate = STATE_UNDERCONSTRUCTION;
		ent->s.powerups = STATE_UNDERCONSTRUCTION;
		ent->realClipmask = ent->clipmask;
		if ( ent->s.eType != ET_CONSTRUCTIBLE ) {                           // don't make nonsolid as we want to make them partially solid for staged construction
			ent->clipmask = 0;
		}
		ent->realContents = ent->r.contents;
		if ( ent->s.eType != ET_CONSTRUCTIBLE ) {
			ent->r.contents = 0;
		}
		if ( ent->s.eFlags & EF_NONSOLID_BMODEL ) {
			ent->realNonSolidBModel = qtrue;
		} else
		if ( ent->s.eType != ET_CONSTRUCTIBLE ) {
			ent->s.eFlags |= EF_NONSOLID_BMODEL;
		}

		if ( !Q_stricmp( ent->classname, "misc_mg42" ) ) {
			// stop using the mg42
			mg42_stopusing( ent );
		}

		if ( ent->s.eType == ET_COMMANDMAP_MARKER ) {
			mapEntityData_t *mEnt;

			if ( ( mEnt = G_FindMapEntityData( &mapEntityData[0], ent - g_entities ) ) != NULL ) {
				G_FreeMapEntityData( &mapEntityData[0], mEnt );
			}
			if ( ( mEnt = G_FindMapEntityData( &mapEntityData[1], ent - g_entities ) ) != NULL ) {
				G_FreeMapEntityData( &mapEntityData[1], mEnt );
			}
		}

		trap_LinkEntity( ent );
		break;
	case STATE_INVISIBLE:           if ( ent->entstate == STATE_UNDERCONSTRUCTION ) {
			ent->clipmask = ent->realClipmask;
			ent->r.contents = ent->realContents;
			if ( !ent->realNonSolidBModel ) {
				ent->s.eFlags &= ~EF_NONSOLID_BMODEL;
			}
	}

		ent->entstate = STATE_INVISIBLE;
		ent->s.powerups = STATE_INVISIBLE;

		if ( !Q_stricmp( ent->classname, "misc_mg42" ) ) {
			mg42_stopusing( ent );
		} else if ( ent->s.eType == ET_WOLF_OBJECTIVE ) {
			char cs[MAX_STRING_CHARS];
			trap_GetConfigstring( ent->count, cs, sizeof( cs ) );
			ent->count2 |= 256;
			Info_SetValueForKey( cs, "t", va( "%i", ent->count2 ) );
			trap_SetConfigstring( ent->count, cs );
		}

		if ( ent->s.eType == ET_COMMANDMAP_MARKER ) {
			mapEntityData_t *mEnt;

			if ( ( mEnt = G_FindMapEntityData( &mapEntityData[0], ent - g_entities ) ) != NULL ) {
				G_FreeMapEntityData( &mapEntityData[0], mEnt );
			}
			if ( ( mEnt = G_FindMapEntityData( &mapEntityData[1], ent - g_entities ) ) != NULL ) {
				G_FreeMapEntityData( &mapEntityData[1], mEnt );
			}
		}

		trap_UnlinkEntity( ent );
		break;
	}
}
Exemple #19
0
void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, const vec3_t in_dir, vec3_t point, int damage, int dflags, int mod ) {
	gclient_t	*client;
	int			take;
	int			save;
	int			knockback;
	qboolean	wasAlive;
	hitRegion_t	hr = HR_NUM_HITREGIONS;
	int			limbo_health;

	limbo_health = FORCE_LIMBO_HEALTH;

	if (!targ->takedamage) {
		return;
	}

	// the intermission has already been qualified for, so don't
	// allow any extra scoring
	// CHRUKER: b024 - Don't do damage if at warmup and warmupdamage is set to 'None' and the target is a client.
	if ( level.intermissionQueued || (cvars::gameState.ivalue != GS_PLAYING && match_warmupDamage.integer == 0 && targ->client)) {
		return;
	}

	if ( !inflictor ) {
		inflictor = &g_entities[ENTITYNUM_WORLD];
	}
	if ( !attacker ) {
		attacker = &g_entities[ENTITYNUM_WORLD];
	}

	// Arnout: invisible entities can't be damaged
	if( targ->entstate == STATE_INVISIBLE ||
		targ->entstate == STATE_UNDERCONSTRUCTION ) {
		return;
	}

	// xkan, 12/23/2002 - was the bot alive before applying any damage?
	wasAlive = (targ->health > 0) ? qtrue : qfalse;

	// Arnout: combatstate
	if( targ->client && attacker && attacker->client && attacker != targ ) {
		if( cvars::gameState.ivalue == GS_PLAYING ) {
			if( !OnSameTeam( attacker, targ ) ) {
				targ->client->combatState = (combatstate_t)( targ->client->combatState | (1<<COMBATSTATE_DAMAGERECEIVED) );
				attacker->client->combatState = (combatstate_t)( attacker->client->combatState | (1<<COMBATSTATE_DAMAGEDEALT) );
			}
		}
	}

    // JPW NERVE
    if ((targ->waterlevel >= 3) && (mod == MOD_FLAMETHROWER))
        return;
    // jpw

	// shootable doors / buttons don't actually have any health
	if ( targ->s.eType == ET_MOVER && !(targ->isProp) && !targ->scriptName) {
		if ( targ->use && targ->moverState == MOVER_POS1 ) {
			G_UseEntity( targ, inflictor, attacker );
		}
		return;
	}

	// TAT 11/22/2002
	//		In the old code, this check wasn't done for props, so I put that check back in to make props_statue properly work	
	// 4 means destructible
	if ( targ->s.eType == ET_MOVER && (targ->spawnflags & 4) && !targ->isProp ) 
	{
		if( !G_WeaponIsExplosive( (meansOfDeath_t)mod ) ) {
			return;
		}

		// check for team
		if( G_GetTeamFromEntity( inflictor ) == G_GetTeamFromEntity( targ ) ) {
			return;
		}
	} else if ( targ->s.eType == ET_EXPLOSIVE ) {
		if( targ->parent && G_GetWeaponClassForMOD( (meansOfDeath_t)mod ) == 2 ) {
			return;
		}

		if( G_GetTeamFromEntity( inflictor ) == G_GetTeamFromEntity( targ ) ) {
			return;
		}

		if( G_GetWeaponClassForMOD( (meansOfDeath_t)mod ) < targ->constructibleStats.weaponclass ) {
			return;
		}
	}
	else if ( targ->s.eType == ET_MISSILE && targ->methodOfDeath == MOD_LANDMINE ) {
		if( targ->s.modelindex2 ) {
			if( G_WeaponIsExplosive( (meansOfDeath_t)mod ) ) {
				mapEntityData_t	*mEnt;

				if((mEnt = G_FindMapEntityData(&mapEntityData[0], targ-g_entities)) != NULL) {
					G_FreeMapEntityData( &mapEntityData[0], mEnt );
				}

				if((mEnt = G_FindMapEntityData(&mapEntityData[1], targ-g_entities)) != NULL) {
					G_FreeMapEntityData( &mapEntityData[1], mEnt );
				}

				if( attacker && attacker->client ) {
					AddScore( attacker, 1 );
				}

				G_ExplodeMissile(targ);
			}
		}
		return;
	} else if ( targ->s.eType == ET_CONSTRUCTIBLE ) {

		if( G_GetTeamFromEntity( inflictor ) == G_GetTeamFromEntity( targ ) ) {
			return;
		}

		if( G_GetWeaponClassForMOD( (meansOfDeath_t)mod ) < targ->constructibleStats.weaponclass ) {
			return;
		}
		//bani - fix #238
		if ( mod == MOD_DYNAMITE ) {
			if( !( inflictor->etpro_misc_1 & 1 ) )
				return;
		}
	}

	client = targ->client;

	if ( client ) {
		if ( client->noclip || ( client->ps.powerups[PW_INVULNERABLE] && !( dflags & DAMAGE_JAY_NO_PROTECTION ))) {
			return;
		}
	}

	// check for godmode
	if ( targ->flags & FL_GODMODE ) {
		return;
	}

    // ugly-ass code but we do this to make in_dir read-only
    vec3_t dir;

	if ( !in_dir ) {
		dflags |= DAMAGE_NO_KNOCKBACK;
	} else {
        VectorCopy( in_dir, dir );
		VectorNormalize( dir );
	}

	knockback = damage;
	if ( knockback > 200 ) {
		knockback = 200;
	}
	if ( targ->flags & FL_NO_KNOCKBACK ) {
		knockback = 0;
	}
	if ( dflags & DAMAGE_NO_KNOCKBACK ) {
		knockback = 0;
	} else if( dflags & DAMAGE_HALF_KNOCKBACK ) {
		knockback = int( knockback * 0.5f );
	}
	
	// ydnar: set weapons means less knockback
	if( client && (client->ps.weapon == WP_MORTAR_SET || client->ps.weapon == WP_MOBILE_MG42_SET) )
		knockback = int( knockback * 0.5f );

	if( targ->client && g_friendlyFire.integer && OnSameTeam(targ, attacker) ) {
		knockback = 0;
	}
	
	// figure momentum add, even if the damage won't be taken
	if ( knockback && targ->client ) {
		vec3_t	kvel;
		float	mass;

		mass = 200;

		VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
		VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);

        // From NoQuarter, I'm not sure I need this
		if ( attacker && attacker->client && ( targ->client->ps.groundEntityNum != ENTITYNUM_NONE || G_WeaponIsExplosive((meansOfDeath_t)mod) )){
			targ->client->pmext.wasShoved = qtrue;
			targ->client->pmext.shover = attacker - g_entities;
		}

		if (targ == attacker && !(	mod != MOD_ROCKET &&
									mod != MOD_GRENADE &&
									mod != MOD_GRENADE_LAUNCHER &&
									mod != MOD_DYNAMITE
									&& mod != MOD_GPG40
									&& mod != MOD_M7
									&& mod != MOD_LANDMINE
									))
		{
			targ->client->ps.velocity[2] *= 0.25;
		}

		// set the timer so that the other client can't cancel
		// out the movement immediately
		if ( !targ->client->ps.pm_time ) {
			int		t;

			t = knockback * 2;
			if ( t < 50 ) {
				t = 50;
			}
			if ( t > 200 ) {
				t = 200;
			}
			targ->client->ps.pm_time = t;
			targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
		}
	}

    // skip damage if friendly fire is disabled
    if (!(dflags & DAMAGE_NO_PROTECTION)
        && targ != attacker
        && OnSameTeam( targ, attacker )
        && !g_friendlyFire.integer)
    {
        return;
    }

	if (damage < 1)
		damage = 1;

	take = damage;
	save = 0;

	if ( attacker->client && targ->client && targ != attacker && targ->health > 0 ) {
		// Jaybird - Hitsounds
		// vsay "hold your fire" on the first hit of a teammate
		// only applies if the player has been hurt before
		// and the match is not in warmup.
		if( OnSameTeam( targ, attacker )) {
			if(( !client->lasthurt_mod || client->lasthurt_client != attacker->s.number ) && cvars::gameState.ivalue == GS_PLAYING && ( targ->health - take ) > limbo_health ) {
				if( client->sess.sessionTeam == TEAM_AXIS )
					G_ClientSound( attacker, "sound/chat/axis/26a.wav" );
				else	
					G_ClientSound( attacker, "sound/chat/allies/26a.wav" );
			}

			if (mod != MOD_GOOMBA && mod != MOD_POISON_SYRINGE) {
				g_clientObjects[attacker->s.number].recordHit( AbstractHitVolume::ZONE_BODY, true );
			}
		} else {
			if (mod != MOD_GOOMBA && mod != MOD_POISON_SYRINGE) {
				g_clientObjects[attacker->s.number].recordHit( AbstractHitVolume::ZONE_BODY, false );
			}
		}
	}

	// adrenaline junkie!
	if( targ->client && targ->client->ps.powerups[PW_ADRENALINE] ) {
		take = int( take * 0.5f );
	}

	// save some from flak jacket
	// Jaybird - engineer class carryover
	if( targ->client && targ->client->sess.skill[SK_EXPLOSIVES_AND_CONSTRUCTION] >= 4 && ( targ->client->sess.playerType == PC_ENGINEER || ( cvars::bg_skills.ivalue & SBS_ENGI ))) {
		if( mod == MOD_GRENADE ||
			mod == MOD_GRENADE_LAUNCHER ||
			mod == MOD_ROCKET ||
			mod == MOD_GRENADE_PINEAPPLE ||
			mod == MOD_MAPMORTAR ||
			mod == MOD_MAPMORTAR_SPLASH || 
			mod == MOD_EXPLOSIVE ||
			mod == MOD_LANDMINE ||
			mod == MOD_GPG40 ||
			mod == MOD_M7 ||
			mod == MOD_SATCHEL ||
			mod == MOD_ARTY ||
			mod == MOD_AIRSTRIKE ||
			mod == MOD_DYNAMITE ||
			mod == MOD_MORTAR ||
			mod == MOD_PANZERFAUST ||
			mod == MOD_MAPMORTAR ) {
			take -= int( take * 0.5f );
		}
	}

#ifndef DEBUG_STATS
	if ( g_debugDamage.integer )
#endif
	{
		G_Printf( "client:%i health:%i damage:%i mod:%s\n", targ->s.number, targ->health, take, modNames[mod] );
	}

	if( targ && targ->client && attacker && attacker->client && targ != attacker && targ->health > 0 && OnSameTeam( targ, attacker ) && g_friendlyFire.integer == 2 && IsReflectable( mod )) {
		int ffDamage;

		// Percentage based reflect
		ffDamage = int( take * g_reflectFriendlyFire.value / 100.f );
		if( ffDamage <= 0 ) {
			ffDamage = 0;
		}
		attacker->health -= ffDamage;

		// Give them pain!
		attacker->client->damage_blood += take;
		attacker->client->damage_knockback += knockback;

		// Set the lasthurt stuff so hitsounds do not replay
		targ->client->lasthurt_mod = mod;
		targ->client->lasthurt_client = attacker - g_entities;

		// Kill the player if necessary
		if( attacker->health <= 0 ) {
			attacker->deathType = MOD_REFLECTED_FF;
			attacker->enemy = attacker;
			if( attacker->die ) {
				attacker->die( attacker, attacker, attacker, ffDamage, MOD_REFLECTED_FF );
			}
		}
	}

	// add to the damage inflicted on a player this frame
	// the total will be turned into screen blends and view angle kicks
	// at the end of the frame
	if ( client ) {
		if ( attacker ) {
			client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
		} else {
			client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
		}
		client->damage_blood += take;
		client->damage_knockback += knockback;

		if ( dir ) {
			VectorCopy ( dir, client->damage_from );
			client->damage_fromWorld = qfalse;
		} else {
			VectorCopy ( targ->r.currentOrigin, client->damage_from );
			client->damage_fromWorld = qtrue;
		}
	}

	// See if it's the player hurting the emeny flag carrier
//	Team_CheckHurtCarrier(targ, attacker);

	if (targ->client) {
		// set the last client who damaged the target
		targ->client->lasthurt_client = attacker->s.number;
		targ->client->lasthurt_mod = mod;
		targ->client->lasthurt_time = level.time;
	}

	// do the damage
	if( take ) {
		targ->health -= take;

		// Gordon: don't ever gib POWS
		if( ( targ->health <= 0 ) && ( targ->r.svFlags & SVF_POW ) ) {
			targ->health = -1;
		}

		// Ridah, can't gib with bullet weapons (except VENOM)
		// Arnout: attacker == inflictor can happen in other cases as well! (movers trying to gib things)
		//if ( attacker == inflictor && targ->health <= GIB_HEALTH) {
		if( targ->health <= GIB_HEALTH ) {
			if( !G_WeaponIsExplosive( (meansOfDeath_t)mod ) ) {
				targ->health = GIB_HEALTH + 1;
			}
		}

		if( g_damagexp.integer && client && G_GetTeamFromEntity( inflictor ) != G_GetTeamFromEntity( targ )) {
			// Jaybird - give them some per hit
			// They get 1 XP per 50 damage, so multiple .02 * take
			int skill = G_SkillForMOD( mod );
			if( skill >= 0 )
				G_AddSkillPoints( attacker, (skillType_t)skill, take * .02 );
		}

// JPW NERVE overcome previous chunk of code for making grenades work again
//		if ((take > 190)) // 190 is greater than 2x mauser headshot, so headshots don't gib
		// Arnout: only player entities! messes up ents like func_constructibles and func_explosives otherwise
		if( ( (targ->s.number < MAX_CLIENTS) && (take > 190) ) && !(targ->r.svFlags & SVF_POW) ) {
			targ->health = GIB_HEALTH - 1;
		}

		if( targ->s.eType == ET_MOVER && !Q_stricmp( targ->classname, "script_mover" ) ) {
			targ->s.dl_intensity = int( 255.f * (targ->health / (float)targ->count) );	// send it to the client
		}

		//G_Printf("health at: %d\n", targ->health);
		if( targ->health <= 0 ) {
			if( client && !wasAlive ) {
				targ->flags |= FL_NO_KNOCKBACK;
				// OSP - special hack to not count attempts for body gibbage
				if( targ->client->ps.pm_type == PM_DEAD ) {
					G_addStats(targ, attacker, take, mod);
				}

				if( (targ->health < FORCE_LIMBO_HEALTH) && (targ->health > GIB_HEALTH) ) {
					limbo(targ, qtrue);
				}
				// xkan, 1/13/2003 - record the time we died.
				if (!client->deathTime)
					client->deathTime = level.time;

				//bani - #389
				if( targ->health <= GIB_HEALTH ) {
					GibEntity( targ, 0 );
				}
			} else {
				targ->sound1to2 = hr;
				targ->sound2to1 = mod;
				targ->sound2to3 = (dflags & DAMAGE_RADIUS) ? 1 : 0;

				if( client ) {
					if( G_GetTeamFromEntity( inflictor ) != G_GetTeamFromEntity( targ ) ) {
						G_AddKillSkillPoints( attacker, (meansOfDeath_t)mod, hr, (qboolean)(dflags & DAMAGE_RADIUS)  );
					}
				}

				if( targ->health < -999 ) {
					targ->health = -999;
				}


				targ->enemy = attacker;
				targ->deathType = (meansOfDeath_t)mod;

				// Ridah, mg42 doesn't have die func (FIXME)
				if( targ->die ) {	
					// Kill the entity.  Note that this funtion can set ->die to another
					// function pointer, so that next time die is applied to the dead body.
					targ->die( targ, inflictor, attacker, take, mod );
					// OSP - kill stats in player_die function
				}

				if( targ->s.eType == ET_MOVER && !Q_stricmp( targ->classname, "script_mover" ) && (targ->spawnflags & 8) ) {
					return;	// reseructable script mover doesn't unlink itself but we don't want a second death script to be called
				}

				// if we freed ourselves in death function
				if (!targ->inuse)
					return;

				// RF, entity scripting
				if ( targ->health <= 0) {	// might have revived itself in death function
					if( targ->r.svFlags & SVF_BOT ) {
                        // Removed
					} else if(	( targ->s.eType != ET_CONSTRUCTIBLE && targ->s.eType != ET_EXPLOSIVE ) ||
								( targ->s.eType == ET_CONSTRUCTIBLE && !targ->desstages ) )	{ // call manually if using desstages
						G_Script_ScriptEvent( targ, "death", "" );
					}
				}
			}

		} else if ( targ->pain ) {
			if (dir) {	// Ridah, had to add this to fix NULL dir crash
				VectorCopy (dir, targ->rotate);
				VectorCopy (point, targ->pos3); // this will pass loc of hit
			} else {
				VectorClear( targ->rotate );
				VectorClear( targ->pos3 );
			}

			targ->pain (targ, attacker, take, point);
		} else {
			// OSP - update weapon/dmg stats
			G_addStats(targ, attacker, take, mod);
			// OSP
		}

		// RF, entity scripting
		G_Script_ScriptEvent( targ, "pain", va("%d %d", targ->health, targ->health+take) );

		// RF, record bot pain
		if (targ->s.number < level.maxclients)
		{
			// notify omni-bot framework
			Bot_Event_TakeDamage(targ-g_entities, attacker);
		}

		// Ridah, this needs to be done last, incase the health is altered in one of the event calls
		// Jaybird - playdead check
		if ( targ->client ) {
			targ->client->ps.stats[STAT_HEALTH] = targ->health;
		}

        // Cheap way to ID inflictor entity as poison smoke.
		if (inflictor->poisonGasAlarm && mod == MOD_POISON_GAS && targ->health >= 0)
			G_AddEvent(targ, EV_COUGH, 0);
	}
}