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

332 lines
7.3 KiB
C++

/*
================================================================
GUIDED MISSILE LAUNCHER
================================================================
Copyright (C) 1998 by 2015, Inc.
All rights reserved.
This source is may not be distributed and/or modified without
expressly written permission by 2015, Inc.
*/
#include "guidedmissile.h"
#include "explosion.h"
#include "surface.h"
#include "misc.h"
#define ROCKET_RADIUS 150
#define MISSILE_TIME 40
#define MISSILE_AFTER_TIME 0.5
Event EV_Missile_Explode("explode");
Event EV_Missile_StartOpen("startopen");
Event EV_Missile_FinishOpen("finishopen");
//=================================================================
CLASS_DECLARATION( Entity, MissileView, NULL );
ResponseDef MissileView::Responses[] =
{
{NULL, NULL}
};
MissileView::MissileView()
{
removetime = 0;
}
MissileView::~MissileView()
{
if(!owner)
return;
// return player's view back to normal
if(owner->isSubclassOf(Player))
{
((Player *)owner.Ptr())->SetViewMode(oldviewmode, NULL);
// turn on the missile overlay
((Player *)owner.Ptr())->MissileOverlayOff();
}
}
void MissileView::Setup(Entity *missile, int owner, viewmode_t oldvmode)
{
setSolidType(SOLID_NOT);
setMoveType(MOVETYPE_FLY);
setModel("sprites/null.spr");
hideModel();
StopAnimating();
this->owner = G_GetEntity(owner);
this->missile = missile;
oldviewmode = oldvmode;
starttime = level.time + 1;
// set the player as this model's owner
edict->owner = this->owner->edict;
edict->svflags |= SVF_ONLYPARENT;
}
void MissileView::SetupMissile(void)
{
if(!missile)
{
angles.AngleVectors(&velocity, NULL, NULL);
velocity *= -24;
// check remove timmer
if(!removetime)
{
removetime = level.time + MISSILE_AFTER_TIME;
setOrigin(origin + velocity*4);
}
else if(removetime < level.time)
{
if(!owner)
return;
// return player's view back to normal
if(owner->isSubclassOf(Player))
{
((Player *)owner.Ptr())->SetViewMode(oldviewmode, NULL);
// turn on the missile overlay
((Player *)owner.Ptr())->MissileOverlayOff();
}
owner = NULL;
PostEvent(EV_Remove, 0.1);
return;
}
return;
}
missile->velocity = velocity;
missile->setAngles(angles);
missile->setOrigin(origin);
// the player pressed the attack button again, blow the missile
if((starttime < level.time) && (((Player *)owner.Ptr())->Buttons() & BUTTON_ATTACK))
{
Event *ev;
ev = new Event(EV_Missile_Explode);
ev->AddEntity(world);
missile->ProcessEvent(ev);
return;
}
}
//=================================================================
// guided missile
CLASS_DECLARATION( Projectile, Missile, NULL );
ResponseDef Missile::Responses[] =
{
{&EV_Touch, (Response)Missile::Explode},
{&EV_Killed, (Response)Missile::Explode},
{&EV_Missile_Explode, (Response)Missile::Explode},
{&EV_Missile_StartOpen, (Response)Missile::StartOpen},
{&EV_Missile_FinishOpen, (Response)Missile::FinishOpen},
{NULL, NULL}
};
void Missile::Explode (Event *ev)
{
int damg;
Vector v;
Entity *other;
Vector norm;
Entity *owner;
other = ev->GetEntity(1);
assert(other);
if(other->isSubclassOf(Teleporter))
return;
if(other->entnum == this->owner)
return;
owner = G_GetEntity(this->owner);
stopsound(CHAN_VOICE);
setSolidType(SOLID_NOT);
hideModel();
if (HitSky())
{
PostEvent(EV_Remove, 0);
return;
}
setSolidType(SOLID_NOT);
takedamage = DAMAGE_NO;
damg = 130 + (int)G_Random(20);
if(health <= 0) // it was shot down
{
// other is actually the one that shot it down, so don't just damage him, hehe
other = this;
}
else // it hit something
{
if (other->takedamage)
other->Damage(this, owner, damg, origin, velocity, level.impact_trace.plane.normal, 0, 0, MOD_MISSILE, -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 = origin - v * 24;
CreateExplosion( v, damg, 1.0f, true, this, owner, other, MOD_MISSILESPLASH, 0.75);
PostEvent(EV_Remove, 0.1);
}
void Missile::StartOpen(Event *ev)
{
RandomAnimate("ready", EV_Missile_FinishOpen);
// make missile damagable now that some time has passed since firing
takedamage = DAMAGE_YES;
}
void Missile::FinishOpen(Event *ev)
{
RandomAnimate("idle", NULL);
}
void Missile::Setup (Entity *owner, Vector pos, Vector dir)
{
Event *ev;
this->owner = owner->entnum;
edict->owner = owner->edict;
setMoveType(MOVETYPE_FLYMISSILE);
setSolidType(SOLID_BBOX);
edict->clipmask = MASK_PROJECTILE;
angles = dir.toAngles();
angles[PITCH] = -angles[PITCH];
setAngles(angles);
speed = MISSILE_SPEED;
velocity = dir * MISSILE_SPEED;
// set missile duration
ev = new Event(EV_Missile_Explode);
ev->AddEntity( world );
PostEvent( ev, MISSILE_TIME );
// will become damagable later
takedamage = DAMAGE_NO;
health = 10;
setModel("missile.def");
RandomAnimate("ready", NULL);
StopAnimating();
PostEvent(EV_Missile_StartOpen, 0.5);
edict->s.renderfx |= RF_DLIGHT;
edict->s.effects |= EF_ROCKET;
gravity = 0;
edict->s.color_r = 0.8;
edict->s.color_g = 0.4;
edict->s.color_b = 0;
edict->s.radius = 200;
// give it a heat signature
edict->s.effects |= EF_WARM;
// pick a skin
if(G_Random() < 0.75)
edict->s.skinnum = 0;
else
edict->s.skinnum = 1;
// setup ambient thrust
ev = new Event(EV_RandomEntitySound);
ev->AddString("thrust");
ProcessEvent(ev);
setSize( "-6 -6 -6", "6 6 6" );
setOrigin( pos );
worldorigin.copyTo(edict->s.old_origin);
// till/if I can fix the (insert swear word here) PVS thing
missileview = new MissileView;
missileview->Setup(this, owner->entnum, ((Player *)owner)->ViewMode());
missileview->setOrigin(origin);
missileview->setAngles(angles);
// set player's view to follow the missile
((Player *)owner)->SetViewMode(MISSILE_VIEW, missileview);
// turn on the missile overlay
((Player *)owner)->MissileOverlayOn();
}
//=================================================================
// guided missile launcher
CLASS_DECLARATION(Weapon, MissileLauncher, "weapon_missilelauncher");
ResponseDef MissileLauncher::Responses[] =
{
{&EV_Weapon_Shoot, (Response)MissileLauncher::Shoot},
{&EV_Weapon_SecondaryUse, (Response)MissileLauncher::SecondaryUse},
{NULL, NULL}
};
MissileLauncher::MissileLauncher()
{
SetModels("missile_w.def", "view_missile.def");
modelIndex("missile.def");
modelIndex("sprites/null.spr");
SetAmmo("Missiles", 1, 0);
SetRank(71, 0);
SetType(WEAPON_2HANDED_LO);
SetMinRange(ROCKET_RADIUS);
SetProjectileSpeed(MISSILE_SPEED);
}
void MissileLauncher::SecondaryUse (Event *ev)
{
if (weaponstate != WEAPON_READY)
return;
// make sure he has it
if(!owner->HasItem("RocketLauncher"))
owner->giveWeapon("RocketLauncher");
owner->useWeapon("RocketLauncher");
}
void MissileLauncher::Shoot (Event *ev)
{
Missile *missile;
Vector pos, dir;
assert(owner);
if (!owner)
return;
GetMuzzlePosition( &pos, &dir );
missile = new Missile;
missile->Setup(owner, pos, dir);
NextAttack(2);
}