2011-02-18 14:31:32 +00:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
2021-03-24 20:13:01 +00:00
|
|
|
Copyright (C) 2002-2021 Q3Rally Team (Per Thormann - q3rally@gmail.com)
|
2011-02-18 14:31:32 +00:00
|
|
|
|
|
|
|
This file is part of q3rally source code.
|
|
|
|
|
|
|
|
q3rally source code is free software; you can redistribute it
|
|
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
q3rally source code is distributed in the hope that it will be
|
|
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with q3rally; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "g_local.h"
|
|
|
|
|
|
|
|
#define SPLASH_RADIUS_SCALE 16.0f
|
|
|
|
#define MAX_SPLASH_RADIUS 14.0f
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
qboolean G_FrictionCalc( const carPoint_t *point, float *sCOF, float *kCOF )
|
|
|
|
{
|
|
|
|
gentity_t *ent;
|
|
|
|
int entityList[MAX_GENTITIES];
|
|
|
|
int numListedEntities;
|
|
|
|
vec3_t mins, maxs;
|
|
|
|
float radius;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
radius = point->radius + SPLASH_RADIUS_SCALE * MAX_SPLASH_RADIUS;
|
|
|
|
|
|
|
|
for ( i = 0 ; i < 3 ; i++ ) {
|
|
|
|
mins[i] = point->r[i] - radius;
|
|
|
|
maxs[i] = point->r[i] + radius;
|
|
|
|
}
|
|
|
|
|
|
|
|
numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
|
|
|
|
|
|
|
|
for ( i = 0 ; i < numListedEntities ; i++ ) {
|
|
|
|
ent = &g_entities[entityList[ i ]];
|
|
|
|
|
|
|
|
if( ent->s.eType != ET_EVENTS + EV_HAZARD ) continue;
|
|
|
|
if( ent->s.weapon != HT_OIL ) continue;
|
|
|
|
|
|
|
|
radius = ( ent->splashRadius * SPLASH_RADIUS_SCALE ) + point->radius;
|
|
|
|
radius *= radius;
|
|
|
|
if( DistanceSquared( ent->r.currentOrigin, point->r ) > radius ) continue;
|
|
|
|
|
|
|
|
*sCOF = CP_OIL_SCOF;
|
|
|
|
*kCOF = CP_OIL_KCOF;
|
|
|
|
|
|
|
|
return qtrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return qfalse;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
FireHazard_Think
|
|
|
|
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void FireHazard_Think (gentity_t *self ){
|
|
|
|
self->nextthink = level.time + 200;
|
|
|
|
|
|
|
|
if (self->freeAfterTime < level.time){
|
|
|
|
self->think = G_FreeEntity;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_RadiusDamage_NoKnockBack(self->r.currentOrigin, self, self->damage, SPLASH_RADIUS_SCALE * self->splashRadius, self, MOD_FIRE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
CreateFireHazard
|
|
|
|
|
|
|
|
owner - the entity that caused this hazard. If the hazard is from a weapon
|
|
|
|
the owner is the player who fired the weapon.
|
|
|
|
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void CreateFireHazard (gentity_t *owner, vec3_t origin){
|
|
|
|
gentity_t *ent;
|
|
|
|
gentity_t *other;
|
|
|
|
vec3_t dist;
|
|
|
|
|
|
|
|
other = NULL;
|
|
|
|
while ((other = G_Find(other, FOFS(classname), "fire")) != NULL){
|
|
|
|
VectorSubtract(other->r.currentOrigin, origin, dist);
|
|
|
|
if (VectorLength(dist) < 16){
|
|
|
|
// G_FreeEntity(other);
|
|
|
|
other->freeAfterTime = level.time + 10000;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ent = G_TempRallyEntity( origin, EV_HAZARD );
|
|
|
|
|
|
|
|
ent->splashRadius = 1;
|
|
|
|
|
|
|
|
ent->s.weapon = HT_FIRE;
|
|
|
|
ent->s.otherEntityNum = owner->s.number;
|
|
|
|
ent->parent = owner;
|
|
|
|
ent->classname = "fire";
|
|
|
|
ent->think = FireHazard_Think;
|
|
|
|
ent->damage = 15;
|
|
|
|
ent->nextthink = level.time;
|
|
|
|
ent->freeAfterTime = level.time + 10000;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
BioHazard_Think
|
|
|
|
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void BioHazard_Think (gentity_t *self ){
|
|
|
|
self->nextthink = level.time + 200;
|
|
|
|
|
|
|
|
if (self->freeAfterTime < level.time){
|
|
|
|
self->think = G_FreeEntity;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_RadiusDamage_NoKnockBack(self->r.currentOrigin, self, self->damage, 0.75f * SPLASH_RADIUS_SCALE * self->splashRadius, self, MOD_BIOHAZARD);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
CreateBioHazard
|
|
|
|
|
|
|
|
owner - the entity that caused this hazard. If the hazard is from a weapon
|
|
|
|
the owner is the player who fired the weapon.
|
|
|
|
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void CreateBioHazard (gentity_t *owner, vec3_t origin){
|
|
|
|
gentity_t *ent;
|
|
|
|
gentity_t *other;
|
|
|
|
vec3_t dist;
|
|
|
|
int highest;
|
|
|
|
|
|
|
|
other = NULL;
|
|
|
|
highest = 0;
|
|
|
|
while ((other = G_Find(other, FOFS(classname), "radiation")) != NULL){
|
|
|
|
VectorSubtract(other->r.currentOrigin, origin, dist);
|
|
|
|
if (VectorLength(dist) < other->splashRadius * 8){
|
|
|
|
if (other->splashRadius > highest)
|
|
|
|
highest = other->splashRadius;
|
|
|
|
|
|
|
|
G_FreeEntity(other);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ent = G_TempRallyEntity( origin, EV_HAZARD );
|
|
|
|
|
|
|
|
if (highest){
|
|
|
|
ent->splashRadius = highest + 1;
|
|
|
|
|
|
|
|
if (ent->splashRadius > MAX_SPLASH_RADIUS)
|
|
|
|
ent->splashRadius = MAX_SPLASH_RADIUS;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ent->splashRadius = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
ent->s.eventParm = ent->splashRadius;
|
|
|
|
|
|
|
|
ent->s.weapon = HT_BIO;
|
|
|
|
ent->s.otherEntityNum = owner->s.number;
|
|
|
|
ent->parent = owner;
|
|
|
|
ent->classname = "radiation";
|
|
|
|
ent->think = BioHazard_Think;
|
|
|
|
ent->damage = 10;
|
|
|
|
ent->nextthink = level.time;
|
|
|
|
ent->freeAfterTime = level.time + 10000;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
CheckForOil
|
|
|
|
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void CheckForOil(vec3_t origin, float radius){
|
|
|
|
gentity_t *other;
|
|
|
|
vec3_t dist;
|
|
|
|
vec3_t newOrigin;
|
|
|
|
float length;
|
|
|
|
|
|
|
|
other = NULL;
|
|
|
|
while ((other = G_Find(other, FOFS(classname), "oil")) != NULL){
|
|
|
|
if (other->count > 5) continue;
|
|
|
|
|
|
|
|
VectorSubtract(origin, other->r.currentOrigin, dist);
|
|
|
|
length = VectorLength(dist);
|
|
|
|
if (length < radius + MAX_SPLASH_RADIUS * SPLASH_RADIUS_SCALE){
|
|
|
|
if (length < other->splashRadius * SPLASH_RADIUS_SCALE){
|
|
|
|
CreateFireHazard(other, origin);
|
|
|
|
other->count++;
|
|
|
|
}
|
|
|
|
else if (length < radius + other->splashRadius * SPLASH_RADIUS_SCALE){
|
|
|
|
VectorMA(other->r.currentOrigin, length / (radius + other->splashRadius * SPLASH_RADIUS_SCALE), dist, newOrigin);
|
|
|
|
CreateFireHazard(other, newOrigin);
|
|
|
|
other->count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
OilHazard_Think
|
|
|
|
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void OilHazard_Think (gentity_t *self ){
|
|
|
|
self->nextthink = level.time + 200;
|
|
|
|
|
|
|
|
if (self->freeAfterTime < level.time){
|
|
|
|
self->think = G_FreeEntity;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
CreateOilHazard
|
|
|
|
|
|
|
|
owner - the entity that caused this hazard. If the hazard is from a weapon
|
|
|
|
the owner is the player who fired the weapon.
|
|
|
|
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void CreateOilHazard (gentity_t *owner, vec3_t origin){
|
|
|
|
gentity_t *ent;
|
|
|
|
gentity_t *other;
|
|
|
|
vec3_t dist;
|
|
|
|
int highest;
|
|
|
|
|
|
|
|
other = NULL;
|
|
|
|
highest = 0;
|
|
|
|
|
|
|
|
ent = G_TempRallyEntity( origin, EV_HAZARD );
|
|
|
|
|
|
|
|
while ((other = G_Find(other, FOFS(classname), "oil")) != NULL){
|
|
|
|
VectorSubtract(other->r.currentOrigin, origin, dist);
|
|
|
|
if (VectorLength(dist) < other->splashRadius * 8){
|
|
|
|
if (other->splashRadius > highest){
|
|
|
|
highest = other->splashRadius;
|
|
|
|
// ent->count = other->count;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_FreeEntity(other);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (highest){
|
|
|
|
ent->splashRadius = highest + 1;
|
|
|
|
|
|
|
|
if (ent->splashRadius > MAX_SPLASH_RADIUS)
|
|
|
|
ent->splashRadius = MAX_SPLASH_RADIUS;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ent->splashRadius = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
ent->s.eventParm = ent->splashRadius;
|
|
|
|
|
|
|
|
ent->s.weapon = HT_OIL;
|
|
|
|
ent->s.otherEntityNum = owner->s.number;
|
|
|
|
ent->parent = owner;
|
|
|
|
ent->classname = "oil";
|
|
|
|
ent->think = OilHazard_Think;
|
|
|
|
ent->nextthink = level.time;
|
|
|
|
ent->freeAfterTime = level.time + 10000;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
PoisonHazard_Think
|
|
|
|
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void PoisonHazard_Think (gentity_t *self ){
|
|
|
|
self->nextthink = level.time + 200;
|
|
|
|
|
|
|
|
if (self->freeAfterTime < level.time){
|
|
|
|
self->think = G_FreeEntity;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_RadiusDamage_NoKnockBack(self->r.currentOrigin, self, self->damage, SPLASH_RADIUS_SCALE * self->splashRadius, self, MOD_POISON);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
CreatePoisonHazard
|
|
|
|
|
|
|
|
owner - the entity that caused this hazard. If the hazard is from a weapon
|
|
|
|
the owner is the player who fired the weapon.
|
|
|
|
|
|
|
|
used with rear weapons
|
|
|
|
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
|
|
|
|
void CreatePoisonHazard (gentity_t *owner, vec3_t origin){
|
|
|
|
gentity_t *ent;
|
|
|
|
|
|
|
|
ent = G_TempRallyEntity( origin, EV_HAZARD );
|
|
|
|
|
|
|
|
ent->splashRadius = 3;
|
|
|
|
ent->s.weapon = HT_POISON;
|
|
|
|
ent->s.otherEntityNum = owner->s.number;
|
|
|
|
ent->parent = owner;
|
|
|
|
ent->classname = "poison";
|
|
|
|
ent->think = PoisonHazard_Think;
|
|
|
|
ent->damage = 2;
|
|
|
|
ent->nextthink = level.time;
|
|
|
|
ent->freeAfterTime = level.time + 10000;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
CreatePoisonCloudHazard
|
|
|
|
|
|
|
|
owner - the entity that caused this hazard. If the hazard is from a weapon
|
|
|
|
the owner is the player who fired the weapon.
|
|
|
|
|
|
|
|
used with barrels
|
|
|
|
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
|
2011-03-08 09:07:05 +00:00
|
|
|
void CreatePoisonCloudHazard (gentity_t *owner, vec3_t origin) {
|
2011-02-18 14:31:32 +00:00
|
|
|
gentity_t *ent;
|
|
|
|
|
|
|
|
ent = G_TempEntity( origin, EV_HAZARD );
|
|
|
|
ent->s.weapon = HT_POISON;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
CreateSmokeHazard
|
|
|
|
|
|
|
|
owner - the entity that caused this hazard. If the hazard is from a weapon
|
|
|
|
the owner is the player who fired the weapon.
|
|
|
|
|
|
|
|
used with barrels
|
|
|
|
|
|
|
|
============
|
|
|
|
*/
|
|
|
|
|
2011-03-08 09:07:05 +00:00
|
|
|
void CreateSmokeHazard (gentity_t *owner, vec3_t origin) {
|
2011-02-18 14:31:32 +00:00
|
|
|
gentity_t *ent;
|
|
|
|
|
|
|
|
ent = G_TempEntity( origin, EV_HAZARD );
|
|
|
|
ent->s.weapon = HT_SMOKE;
|
|
|
|
}
|