jkxr/Projects/Android/jni/OpenJK/code/game/wp_trip_mine.cpp

320 lines
9 KiB
C++
Raw Normal View History

/*
===========================================================================
Copyright (C) 2000 - 2013, Raven Software, Inc.
Copyright (C) 2001 - 2013, Activision, Inc.
Copyright (C) 2013 - 2015, OpenJK contributors
This file is part of the OpenJK source code.
OpenJK is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/
#include "g_local.h"
#include "b_local.h"
#include "g_functions.h"
#include "wp_saber.h"
#include "w_local.h"
//-----------------------
// Laser Trip Mine
//-----------------------
#define PROXIMITY_STYLE 1
#define TRIPWIRE_STYLE 2
//---------------------------------------------------------
void touchLaserTrap( gentity_t *ent, gentity_t *other, trace_t *trace )
//---------------------------------------------------------
{
ent->s.eType = ET_GENERAL;
// a tripwire so add draw line flag
VectorCopy( trace->plane.normal, ent->movedir );
// make it shootable
VectorSet( ent->mins, -4, -4, -4 );
VectorSet( ent->maxs, 4, 4, 4 );
ent->clipmask = MASK_SHOT;
ent->contents = CONTENTS_SHOTCLIP;
ent->takedamage = qtrue;
ent->health = 15;
ent->e_DieFunc = dieF_WP_ExplosiveDie;
ent->e_TouchFunc = touchF_NULL;
// so we can trip it too
ent->activator = ent->owner;
ent->owner = NULL;
WP_Stick( ent, trace );
if ( ent->count == TRIPWIRE_STYLE )
{
vec3_t mins = {-4,-4,-4}, maxs = {4,4,4};//FIXME: global these
trace_t tr;
VectorMA( ent->currentOrigin, 32, ent->movedir, ent->s.origin2 );
gi.trace( &tr, ent->s.origin2, mins, maxs, ent->currentOrigin, ent->s.number, MASK_SHOT, G2_RETURNONHIT, 0 );
VectorCopy( tr.endpos, ent->s.origin2 );
ent->e_ThinkFunc = thinkF_laserTrapThink;
}
else
{
ent->e_ThinkFunc = thinkF_WP_prox_mine_think;
}
ent->nextthink = level.time + LT_ACTIVATION_DELAY;
}
// copied from flechette prox above...which will not be used if this gets approved
//---------------------------------------------------------
void WP_prox_mine_think( gentity_t *ent )
//---------------------------------------------------------
{
int count;
qboolean blow = qfalse;
// first time through?
if ( ent->count )
{
// play activated warning
ent->count = 0;
ent->s.eFlags |= EF_PROX_TRIP;
G_Sound( ent, G_SoundIndex( "sound/weapons/laser_trap/warning.wav" ));
}
// if it isn't time to auto-explode, do a small proximity check
if ( ent->delay > level.time )
{
count = G_RadiusList( ent->currentOrigin, PROX_MINE_RADIUS_CHECK, ent, qtrue, ent_list );
for ( int i = 0; i < count; i++ )
{
if ( ent_list[i]->client && ent_list[i]->health > 0 && ent->activator && ent_list[i]->s.number != ent->activator->s.number )
{
blow = qtrue;
break;
}
}
}
else
{
// well, we must die now
blow = qtrue;
}
if ( blow )
{
// G_Sound( ent, G_SoundIndex( "sound/weapons/flechette/warning.wav" ));
ent->e_ThinkFunc = thinkF_WP_Explode;
ent->nextthink = level.time + 200;
}
else
{
// we probably don't need to do this thinking logic very often...maybe this is fast enough?
ent->nextthink = level.time + 500;
}
}
//---------------------------------------------------------
void laserTrapThink( gentity_t *ent )
//---------------------------------------------------------
{
gentity_t *traceEnt;
vec3_t end, mins = {-4,-4,-4}, maxs = {4,4,4};
trace_t tr;
// turn on the beam effect
if ( !(ent->s.eFlags & EF_FIRING ))
{
// arm me
G_Sound( ent, G_SoundIndex( "sound/weapons/laser_trap/warning.wav" ));
ent->s.loopSound = G_SoundIndex( "sound/weapons/laser_trap/hum_loop.wav" );
ent->s.eFlags |= EF_FIRING;
}
ent->e_ThinkFunc = thinkF_laserTrapThink;
ent->nextthink = level.time + FRAMETIME;
// Find the main impact point
VectorMA( ent->s.pos.trBase, 2048, ent->movedir, end );
gi.trace( &tr, ent->s.origin2, mins, maxs, end, ent->s.number, MASK_SHOT, G2_RETURNONHIT, 0 );
traceEnt = &g_entities[ tr.entityNum ];
// Adjust this so that the effect has a relatively fresh endpoint
VectorCopy( tr.endpos, ent->pos4 );
if ( traceEnt->client || tr.startsolid )
{
// go boom
WP_Explode( ent );
ent->s.eFlags &= ~EF_FIRING; // don't draw beam if we are dead
}
else
{
/*
// FIXME: they need to avoid the beam!
AddSoundEvent( ent->owner, ent->currentOrigin, ent->splashRadius*2, AEL_DANGER );
AddSightEvent( ent->owner, ent->currentOrigin, ent->splashRadius*2, AEL_DANGER, 50 );
*/
}
}
//---------------------------------------------------------
void CreateLaserTrap( gentity_t *laserTrap, vec3_t start, gentity_t *owner )
//---------------------------------------------------------
{
if ( !VALIDSTRING( laserTrap->classname ))
{
// since we may be coming from a map placed trip mine, we don't want to override that class name....
// That would be bad because the player drop code tries to limit number of placed items...so it would have removed map placed ones as well.
laserTrap->classname = "tripmine";
}
laserTrap->splashDamage = weaponData[WP_TRIP_MINE].splashDamage;
laserTrap->splashRadius = weaponData[WP_TRIP_MINE].splashRadius;
laserTrap->damage = weaponData[WP_TRIP_MINE].damage;
laserTrap->methodOfDeath = MOD_LASERTRIP;
laserTrap->splashMethodOfDeath = MOD_LASERTRIP;//? SPLASH;
laserTrap->s.eType = ET_MISSILE;
laserTrap->svFlags = SVF_USE_CURRENT_ORIGIN;
laserTrap->s.weapon = WP_TRIP_MINE;
laserTrap->owner = owner;
// VectorSet( laserTrap->mins, -LT_SIZE, -LT_SIZE, -LT_SIZE );
// VectorSet( laserTrap->maxs, LT_SIZE, LT_SIZE, LT_SIZE );
laserTrap->clipmask = (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_SHOTCLIP);//MASK_SHOT;
laserTrap->s.pos.trTime = level.time; // move a bit on the very first frame
VectorCopy( start, laserTrap->s.pos.trBase );
VectorCopy( start, laserTrap->currentOrigin);
VectorCopy( start, laserTrap->pos2 ); // ?? wtf ?
laserTrap->fxID = G_EffectIndex( "tripMine/explosion" );
laserTrap->e_TouchFunc = touchF_touchLaserTrap;
laserTrap->s.radius = 60;
VectorSet( laserTrap->s.modelScale, 1.0f, 1.0f, 1.0f );
gi.G2API_InitGhoul2Model( laserTrap->ghoul2, weaponData[WP_TRIP_MINE].missileMdl, G_ModelIndex( weaponData[WP_TRIP_MINE].missileMdl ),
NULL_HANDLE, NULL_HANDLE, 0, 0);
}
//---------------------------------------------------------
static void WP_RemoveOldTraps( gentity_t *ent )
//---------------------------------------------------------
{
gentity_t *found = NULL;
int trapcount = 0, i;
int foundLaserTraps[MAX_GENTITIES] = {ENTITYNUM_NONE};
int trapcount_org, lowestTimeStamp;
int removeMe;
// see how many there are now
while (( found = G_Find( found, FOFS(classname), "tripmine" )) != NULL )
{
if ( found->activator != ent ) // activator is really the owner?
{
continue;
}
foundLaserTraps[trapcount++] = found->s.number;
}
// now remove first ones we find until there are only 9 left
found = NULL;
trapcount_org = trapcount;
lowestTimeStamp = level.time;
while ( trapcount > 9 )
{
removeMe = -1;
for ( i = 0; i < trapcount_org; i++ )
{
if ( foundLaserTraps[i] == ENTITYNUM_NONE )
{
continue;
}
found = &g_entities[foundLaserTraps[i]];
if ( found->setTime < lowestTimeStamp )
{
removeMe = i;
lowestTimeStamp = found->setTime;
}
}
if ( removeMe != -1 )
{
//remove it... or blow it?
if ( &g_entities[foundLaserTraps[removeMe]] == NULL )
{
break;
}
else
{
G_FreeEntity( &g_entities[foundLaserTraps[removeMe]] );
}
foundLaserTraps[removeMe] = ENTITYNUM_NONE;
trapcount--;
}
else
{
break;
}
}
}
//---------------------------------------------------------
void WP_PlaceLaserTrap( gentity_t *ent, qboolean alt_fire )
//---------------------------------------------------------
{
vec3_t start;
gentity_t *laserTrap;
// limit to 10 placed at any one time
WP_RemoveOldTraps( ent );
//FIXME: surface must be within 64
laserTrap = G_Spawn();
if ( laserTrap )
{
// now make the new one
VectorCopy( muzzle, start );
WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall
CreateLaserTrap( laserTrap, start, ent );
// set player-created-specific fields
laserTrap->setTime = level.time;//remember when we placed it
laserTrap->s.eFlags |= EF_MISSILE_STICK;
laserTrap->s.pos.trType = TR_GRAVITY;
VectorScale( forwardVec, LT_VELOCITY, laserTrap->s.pos.trDelta );
if ( alt_fire )
{
laserTrap->count = PROXIMITY_STYLE;
laserTrap->delay = level.time + 40000; // will auto-blow in 40 seconds.
laserTrap->methodOfDeath = MOD_LASERTRIP_ALT;
laserTrap->splashMethodOfDeath = MOD_LASERTRIP_ALT;//? SPLASH;
}
else
{
laserTrap->count = TRIPWIRE_STYLE;
}
}
}