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

330 lines
7.2 KiB
C++

/*
================================================================
BOB MONSTER
================================================================
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 "bob.h"
#include "specialfx.h"
#include "player.h"
//Vector bobfieldmin (-64, -64, -64);
//Vector bobfieldmax (64, 64, 64);
#define BOB_CONCUSSION_RANGE 175
//===============================================================
// BOB
//===============================================================
Event EV_Bob_Concussion("fireconcussion");
CLASS_DECLARATION(Actor, Bob, "monster_bob");
ResponseDef Bob::Responses[] =
{
{&EV_Bob_Concussion, (Response)Bob::FireConcussion},
{&EV_Concussion_Effect, (Response)Bob::ConcussionEffect},
{&EV_Killed, (Response)Bob::Killed},
{NULL, NULL}
};
Bob::Bob()
{
concussiontime = level.time + 2;
}
void Bob::Prethink(void)
{
// do a check for something to concussion
if(concussiontime < level.time)
{
Entity *ent;
ent = NULL;
while(ent = findradius(ent, worldorigin, BOB_CONCUSSION_RANGE))
{
if(ent == this)
continue;
if (
(!ent->isSubclassOf(Projectile)) &&
(!(ent->isSubclassOf(Player) && ent->takedamage))
)
{
continue;
}
if(ent->isSubclassOf(Projectile)) // do an extra check for Projectiles
{
Entity *entowner;
entowner = ((Projectile *)ent)->Owner();
assert(entowner);
if(entowner->isSubclassOf(Bob))
{
continue;
}
}
// make sure that it's infront
if(InConcussionFOV(ent->centroid) && CanSeeFrom(worldorigin, ent))
{
FireConcussion(NULL);
concussiontime = level.time + 1.5;
break; // stop looking for a reason to fire
}
}
// if we didn't fire at anything, add a bit of a recheck delay
if(concussiontime < level.time)
{
concussiontime = level.time + 0.15;
}
}
//
// call our superclass
//
Actor::Prethink();
}
void Bob::Killed (Event *ev)
{
// make Bob go down in flames
edict->s.effects |= EF_DEATHFLAMES;
// call actual killed function
Actor::Killed(ev);
}
inline qboolean Bob::InConcussionFOV (Vector pos)
{
Vector delta;
float dot;
delta = pos - EyePosition();
if(!delta.x && !delta.y)
{
// special case for straight up and down
return true;
}
// give better vertical vision
delta.z = 0;
delta.normalize();
dot = DotProduct(orientation[0], delta.vec3());
return (dot > CONCUSSION_ARC);
}
void Bob::FireConcussion(Event *ev)
{
Vector pos;
ConcussionRing *ring;
lastfirepos = worldorigin;
lastfiredir = Vector(orientation[0]);
// apply kick back
velocity -= lastfiredir * CONCUSSION_KICKBACK * 0.25;
// make blast ring
pos = lastfirepos + lastfiredir*8;
ring = new ConcussionRing;
ring->Setup(pos, lastfiredir);
ring->velocity = lastfiredir*500;
ring->edict->s.scale = 0.05;
ring->edict->s.alpha = 0.75;
ring->PostEvent(EV_ConcussionRing_Animate2, FRAMETIME);
ring->PostEvent(EV_Remove, 1);
// make firing sound
sound("weapons/concussion/fire5b.wav", 1, CHAN_WEAPON);
blastcount = 0;
ProcessEvent(EV_Concussion_Effect);
}
void Bob::ConcussionEffect (Event *ev)
{
Entity *tmpent = NULL;
ConcussionRing *ring;
Vector targvec, vec;
Vector end;
trace_t trace;
float d, f, targdist;
if(health <= 0)
{
return;
}
tmpent = NULL;
while(tmpent = findradius(tmpent, lastfirepos, CONCUSSION_DIST * 0.75))
{
if(tmpent == this)
continue;
// only effect damagable things and projectiles
// don't effect BSP model entities
if(
((!tmpent->takedamage) &&
(!tmpent->isSubclassOf(Projectile))) ||
(tmpent->edict->solid == SOLID_BSP)
)
continue;
// don't effect bob projectiles
if(tmpent->isSubclassOf(Projectile))
{
Entity *entowner;
entowner = ((Projectile *)tmpent)->Owner();
assert(entowner);
if(entowner->isSubclassOf(Bob))
continue;
}
targvec = tmpent->origin + (tmpent->mins + tmpent->maxs)*0.5;
trace = G_Trace(lastfirepos, Vector(0, 0, 0), Vector(0, 0, 0), targvec, this, MASK_SOLIDNONFENCE, "ConcussionGun::BlastEffect");
if(trace.fraction < 1)
continue;
vec = targvec - lastfirepos;
targdist = vec.normalize2();
d = DotProduct(vec, lastfiredir);
if(d < CONCUSSION_ARC)
continue;
if(tmpent->concussion_debounce < level.time)
{
// make a visible indication of a hit
end = targvec - lastfiredir*32;
ring = new ConcussionRing;
ring->Setup(end, lastfiredir);
ring->velocity = lastfiredir*50;
ring->edict->s.scale = 0.02;
ring->edict->s.alpha = 0.75;
ring->PostEvent(EV_ConcussionRing_Animate3, FRAMETIME);
ring->PostEvent(EV_Remove, 0.4);
}
tmpent->concussion_debounce = level.time + 0.3;
f = (CONCUSSION_PUSH * 0.9) - (targdist * CONCUSSION_PUSH_DECAY);
// scale the force by the directional dot product
f *= d;
// scale the force by the mass of the target
if(tmpent->mass > 20)
f *= 1/(tmpent->mass*0.005);
else
f = 2000;
if(f < 0)
f = 0;
if(f > 2000)
f = 2000;
//apply force, but not to script objects and models
if((f > 0) && (!tmpent->isSubclassOf(ScriptSlave)))
{
tmpent->velocity += vec * f;
if(tmpent->velocity.length() > 1500)
{
tmpent->velocity.normalize();
tmpent->velocity *= 1500;
}
if(tmpent->velocity[2] <= 0)
tmpent->velocity[2] = 50;
else
tmpent->velocity[2] += 50;
// set info for wall splatting damage
tmpent->concussioner = this;
if(tmpent->isSubclassOf(Player))
{
Player *player;
player = (Player *)tmpent;
player->concussion_timer = level.time + 1;
// jitter the poor sucker's view
f = f/CONCUSSION_PUSH;
player->SetAngleJitter(f*10, f*30, level.time);
player->SetOffsetJitter(f*5, f*20, level.time + 0.1);
}
}
// do some damage if applicable
f = CONCUSSION_DAMG - (targdist * CONCUSSION_DAMG_DECAY);
// scale the damage by the directional dot product
f *= d;
if(f < 0)
f = 0;
if(tmpent->takedamage)
tmpent->Damage(this, this, f, tmpent->origin, lastfiredir, level.impact_trace.plane.normal, 32, 0, MOD_CONCUSSION, -1, -1, 1.0f);
}
// set effect counter as needed
if(blastcount < CONCUSSION_COUNT)
{
// do effect again
PostEvent(EV_Concussion_Effect, 0.1);
blastcount++;
}
}
//===============================================================
// BOB'S WEAPON
//===============================================================
CLASS_DECLARATION(Weapon, BobBow, "");
ResponseDef BobBow::Responses[] =
{
{&EV_Weapon_Shoot, (Response)BobBow::Shoot},
{NULL, NULL}
};
BobBow::BobBow()
{
SetModels(NULL, "view_bobbow.def");
modelIndex("bobbolt.def");
modelIndex("sprites/cbshot.spr");
SetAmmo("BulletPulse", 10, 90);
SetType(WEAPON_2HANDED_HI);
SetMinRange(50);
SetProjectileSpeed(1000);
}
void BobBow::Shoot(Event *ev)
{
PBolt *bolt;
Vector pos, dir;
assert(owner);
if(!owner)
return;
GetMuzzlePosition( &pos, &dir, NULL, NULL);
bolt = new PBolt;
bolt->Setup(owner, pos, dir, -1);
NextAttack(1.8);
}