sin-2015/shotrocketlauncher.cpp
1999-04-22 00:00:00 +00:00

323 lines
6.2 KiB
C++

// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// DESCRIPTION:
// ShotRocketLauncher - Shoots slow moving shootable rockets
#include "g_local.h"
#include "explosion.h"
#include "shotrocketlauncher.h"
#include "rocket_turret.h"
#include "misc.h"
#include "surface.h"
CLASS_DECLARATION( Projectile, ShotRocket, NULL );
Event EV_ShotRocket_Explode( "explode" );
Event EV_ShotRocket_HeatSeek( "heatseek" );
ResponseDef ShotRocket::Responses[] =
{
{ &EV_Touch, ( Response )ShotRocket::Explode },
{ &EV_Damage, ( Response )ShotRocket::DamageEvent },
{ &EV_ShotRocket_Explode, ( Response )ShotRocket::Explode },
{ &EV_ShotRocket_HeatSeek, ( Response )ShotRocket::HeatSeek },
{ NULL, NULL }
};
EXPORT_FROM_DLL void ShotRocket::DamageEvent
(
Event *ev
)
{
Entity *other;
Event *event;
int damage;
damage = ev->GetInteger(1);
if (damage <= 0)
return;
other = ev->GetEntity(2);
event = new Event(EV_ShotRocket_Explode);
event->AddEntity(other);
ProcessEvent(event);
}
EXPORT_FROM_DLL void ShotRocket::Explode
(
Event *ev
)
{
int damg;
Vector v;
Entity *other;
Entity *owner;
other = ev->GetEntity( 1 );
assert( other );
owner = G_GetEntity( this->owner );
if ( !owner )
owner = world;
if ( other->isSubclassOf( Teleporter ) )
{
return;
}
if ( other == owner )
{
return;
}
stopsound( CHAN_VOICE );
setSolidType( SOLID_NOT );
hideModel();
if ( HitSky() )
{
PostEvent( EV_Remove, 0 );
return;
}
damg = 100 + ( int )G_Random( 20 );
takedamage = DAMAGE_NO;
if (other->takedamage)
other->Damage( this, owner, damg, worldorigin, velocity, level.impact_trace.plane.normal, 32, 0, MOD_SHOTROCKET, -1, -1, 1.0f );
SpawnBlastDamage( &level.impact_trace, damg, owner );
v = velocity;
v.normalize();
// don't do radius damage to the other, because all the damage
// was done in the impact
v = worldorigin - v * 36;
CreateExplosion( v, damg, 1.0f, true, this, owner, other );
PostEvent( EV_Remove, 0.1 );
}
float ShotRocket::Distance
(
Entity *targ
)
{
Vector delta;
delta = worldorigin - targ->centroid;
return delta.length();
}
qboolean ShotRocket::CanSee
(
Entity *ent
)
{
Vector delta;
Vector start;
Vector end;
trace_t trace;
start = worldorigin;
end = ent->centroid;
// Check if he's visible
trace = G_Trace( start, vec_zero, vec_zero, end, this, MASK_OPAQUE, "ShotRocket::CanSee" );
if ( trace.fraction == 1.0 || trace.ent == ent->edict )
{
return true;
}
return false;
}
void ShotRocket::HeatSeek
(
Event *ev
)
{
// Seek out the closest client
Entity *ent;
edict_t *ed;
int i;
float dist;
float bestdist = 99999;
Entity *bestent;
Vector delta;
bestent = NULL;
for( i = 0; i < game.maxclients; i++ )
{
ed = &g_edicts[ 1 + i ];
if ( !ed->inuse || !ed->entity )
{
continue;
}
ent = ed->entity;
if ( ( ent->health < 0 ) || ( ent->flags & FL_NOTARGET ) )
{
continue;
}
dist = Distance( ent );
if ( ( dist < bestdist ) && CanSee( ent ) )
{
bestent = ent;
bestdist = dist;
}
}
if (!bestent)
{
PostEvent( ev, FRAMETIME );
return;
}
if ( bestdist < 16 )
{
Event * ev;
ev = new Event( EV_ShotRocket_Explode );
ev->AddEntity( bestent );
PostEvent( ev, 0 );
}
delta = bestent->centroid - worldorigin;
delta.normalize();
velocity = delta * speed;
angles = delta.toAngles();
angles[ PITCH ] = - angles[ PITCH ];
setAngles( angles );
PostEvent( ev, FRAMETIME );
}
void ShotRocket::Setup
(
Entity *owner,
Vector pos,
Vector dir
)
{
Event *ev;
RocketTurret *turret;
this->owner = owner->entnum;
edict->owner = owner->edict;
if ( owner->isSubclassOf( RocketTurret ) )
{
turret = ( RocketTurret * )owner;
speed = turret->speed;
}
else
{
turret = NULL;
speed = 500;
}
setMoveType( MOVETYPE_FLYMISSILE );
setSolidType( SOLID_BBOX );
edict->clipmask = MASK_PROJECTILE;
angles = dir.toAngles();
angles[ PITCH ] = - angles[ PITCH ];
setAngles( angles );
velocity = dir * speed;
// set missile duration
ev = new Event( EV_ShotRocket_Explode );
ev->AddEntity( world );
PostEvent( ev, 15 );
takedamage = DAMAGE_YES;
health = 1;
setModel( "rocket.def" );
edict->s.effects |= EF_ROCKET;
edict->s.effects |= EF_EVERYFRAME;
edict->s.angles[ROLL] = rand() % 360;
avelocity = "0 0 90";
gravity = 0;
edict->svflags |= SVF_USEBBOX;
//### give it a heat signature
edict->s.effects |= EF_WARM;
//###
// setup ambient thrust
ev = new Event( EV_RandomEntitySound );
ev->AddString( "thrust" );
ProcessEvent( ev );
setSize( "-8 -8 -8", "8 8 8" );
setOrigin( pos );
worldorigin.copyTo(edict->s.old_origin);
ev = new Event( EV_ShotRocket_HeatSeek );
PostEvent( ev, FRAMETIME );
}
CLASS_DECLARATION( Weapon, ShotRocketLauncher, "weapon_shotrocketlauncher" );
ResponseDef ShotRocketLauncher::Responses[] =
{
{ &EV_Weapon_Shoot, ( Response )ShotRocketLauncher::Shoot },
{ NULL, NULL }
};
ShotRocketLauncher::ShotRocketLauncher()
{
SetModels( "rlaunch.def", "view_rlaunch.def" );
modelIndex( "rockets.def" );
modelIndex( "rocket.def" );
modelIndex( "sprites/blastmark.spr" );
SetAmmo( "Rockets", 1, 5 );
SetRank( 70, 50 );
}
void ShotRocketLauncher::Shoot
(
Event *ev
)
{
ShotRocket *rocket;
Vector pos;
Vector dir;
RocketTurret *turret;
assert( owner );
if ( !owner )
{
return;
}
turret = ( RocketTurret * )( Entity *)owner;
GetMuzzlePosition( &pos, &dir );
rocket = new ShotRocket;
rocket->Setup( owner, pos, dir );
MuzzleFlash( 1.0, 0.1, 0, 400, 0.6, 0.2 );
NextAttack( turret->rate );
}