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

334 lines
7.3 KiB
C++

/*
================================================================
FLASHLIGHT
================================================================
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 "q_shared.h"
#include "flashlight.h"
#include "specialfx.h"
#include "player.h"
#include "hoverbike.h"
#define FLASHLIGHT_RANGE 1000
CLASS_DECLARATION(InventoryItem, Flashlight, "powerups_flashlight");
Event EV_Flashlight_EmitLight("flashlight_emitlight");
ResponseDef Flashlight::Responses[] =
{
{&EV_Flashlight_EmitLight, (Response)Flashlight::EmitLight},
{&EV_Item_Pickup, (Response)Flashlight::Pickup},
{NULL, NULL}
};
Flashlight::Flashlight()
{
setModel("flashlight.def");
gi.soundindex("environment/switch/smallsw1.wav");
gi.soundindex("environment/switch/metalsw3.wav");
Set(300);
setRespawnTime(20);
lighton = 0;
lightent = NULL;
lightent2 = NULL;
}
Flashlight::~Flashlight()
{
if(lightent)
{
lightent->ProcessEvent(EV_Remove);
lightent = NULL;
}
if(lightent2)
{
lightent2->ProcessEvent(EV_Remove);
lightent2 = NULL;
}
}
// toggles the flashlight on and off
void Flashlight::Use(Event *ev)
{
assert(owner);
assert(amount);
// don't allow turning it off in a flashlight on DM game
if((lighton > 0) && !(DM_FLAG(DF_FLASHLIGHTON)))
{
lighton *= -1;
CancelEventsOfType(EV_Flashlight_EmitLight);
owner->sound("environment/switch/metalsw3.wav", 1, CHAN_ITEM, ATTN_NORM);
if(lightent)
{
lightent->PostEvent(EV_Remove, 0);
lightent = NULL;
}
if(lightent2)
{
lightent2->PostEvent(EV_Remove, 0);
lightent2 = NULL;
}
}
else
{
if(lighton < 0)
lighton *= -1;
PostEvent(EV_Flashlight_EmitLight, 0.1);
owner->sound("environment/switch/smallsw1.wav", 1, CHAN_ITEM, ATTN_NORM);
}
}
void Flashlight::EmitLight(Event *ev)
{
Vector dir, start, pos;
trace_t trace;
float dist, tmpflt;
int mask;
Entity *ignoreent;
static int flashlight_sound_count = 0;
// check on our owner
if(!owner || owner->deadflag)
{
PostEvent(EV_Remove, 0);
return;
}
lighton++;
if(lighton > 10)
{
lighton = 1;
// don't drain flashlight in a flashlight DM game
if(!(DM_FLAG(DF_FLASHLIGHT)))
{
if(!(owner->flags & FL_GODMODE))
amount--;
if(amount <= 0)
{
// also remove the light entitys
if(lightent)
{
lightent->PostEvent(EV_Remove, 0);
lightent = NULL;
}
if(lightent2)
{
lightent2->PostEvent(EV_Remove, 0);
lightent2 = NULL;
}
owner->RemoveItem(this);
return;
}
}
}
// place beam entity
dir = owner->orientation[0];
// do the flashlight a bit differently if owner is on a bike
if(owner->isClient() && owner->IsOnBike())
{
Hoverbike *bike;
Vector tmpvec;
start = owner->origin + Vector(0,0,owner->viewheight) + dir*40;
// recalc dir based apon player's view direction
tmpvec = ((Player *)owner.Ptr())->GetVAngle();
tmpvec.AngleVectors(&dir, NULL, NULL);
pos = start + dir*FLASHLIGHT_RANGE;
bike = ((Player *)owner.Ptr())->GetHoverbike();
ignoreent = bike->frontbox;
}
else
{
start = owner->origin + Vector(0,0,owner->viewheight);
pos = start + dir*FLASHLIGHT_RANGE;
ignoreent = owner;
}
mask = (MASK_PLAYERSOLID | MASK_WATER) & ~(CONTENTS_WINDOW | CONTENTS_FENCE);
trace = G_Trace(start, vec_zero, vec_zero, pos, ignoreent, mask, "Flashlight::EmitLight");
pos = start - Vector(trace.endpos);
dist = FLASHLIGHT_RANGE - pos.length();
if(dist < 1)
tmpflt = 0;
else
tmpflt = dist/FLASHLIGHT_RANGE;
// make sure we have entities here
if(!lightent)
lightent = new Entity;
lightent->setModel("sprites/null.spr");
lightent->setMoveType(MOVETYPE_NONE);
lightent->setSolidType(SOLID_NOT);
lightent->edict->s.renderfx |= RF_DLIGHT;
lightent->edict->s.radius = 250 - tmpflt*125;
lightent->edict->s.color_b = 0.1 + tmpflt*0.5;
tmpflt = 0.25 + tmpflt*0.75;
if(tmpflt > 1)
tmpflt = 1;
lightent->edict->s.color_r = tmpflt;
lightent->edict->s.color_g = tmpflt;
lightent->setOrigin(trace.endpos);
// have the beam light entity generate a movement sound
if(flashlight_sound_count++ > 10)
{
float r2, dist2;
int n, i;
Sentient *ent;
Vector delta;
if(!(owner->flags & FL_NOTARGET))
{
r2 = SOUND_MOVEMENT_RADIUS * SOUND_MOVEMENT_RADIUS;
n = SentientList.NumObjects();
for( i = 1; i <= n; i++ )
{
ent = SentientList.ObjectAt( i );
if ( ent->deadflag || ( ent == owner ) )
{
continue;
}
delta = lightent->worldorigin - ent->centroid;
// dot product returns length squared
dist2 = delta * delta;
if (
( dist2 <= r2 ) &&
(
( lightent->edict->areanum == ent->edict->areanum ) ||
( gi.AreasConnected( lightent->edict->areanum, ent->edict->areanum ) )
)
)
{
ev = new Event(EV_HeardMovement);
ev->AddEntity(owner);
ev->AddVector(lightent->worldorigin);
ent->PostEvent(ev, 0);
}
}
}
if(flashlight_sound_count > 15)
flashlight_sound_count = 0;
}
// place the near area light entity if not in deathmatch
if(!deathmatch->value)
{
start = owner->origin + Vector(0,0,owner->viewheight);
pos = start + dir*100;
trace = G_Trace(start, vec_zero, vec_zero, pos, owner, mask, "Flashlight::EmitLight");
if(!lightent2)
lightent2 = new Entity;
lightent2->setModel("sprites/null.spr");
lightent2->setMoveType(MOVETYPE_NONE);
lightent2->setSolidType(SOLID_NOT);
lightent2->edict->s.renderfx |= RF_DLIGHT;
lightent2->edict->s.radius = 150;
lightent2->edict->s.color_b = 0.15;
lightent2->edict->s.color_r = 0.35;
lightent2->edict->s.color_g = 0.35;
lightent2->setOrigin(trace.endpos);
}
PostEvent(EV_Flashlight_EmitLight, 0.1);
}
void Flashlight::Pickup (Event * ev)
{
ItemPickup(ev->GetEntity(1));
}
qboolean Flashlight::Pickupable (Entity *other)
{
if ( !other->isSubclassOf( Sentient ) )
{
return false;
}
Sentient * sent;
Item * item;
sent = ( Sentient * )other;
item = sent->FindItem( getClassname() );
if ( item && ( item->Amount() >= item->MaxAmount() ) )
{
return false;
}
// Mutants can't pick up anything but health
if(other->flags & (FL_MUTANT|FL_SP_MUTANT))
{
return false;
}
return true;
}
Item *Flashlight::ItemPickup (Entity *other)
{
Sentient * sent;
Item * item;
str realname;
if ( !Pickupable( other ) )
{
return NULL;
}
sent = ( Sentient * )other;
item = sent->giveItem( getClassname(), Amount(), icon_index );
if ( !item )
return NULL;
realname = GetRandomAlias( "snd_pickup" );
if ( realname.length() > 1 )
sent->sound( realname, 1, CHAN_ITEM, ATTN_NORM );
if ( !Removable() )
{
// leave the item for others to pickup
return item;
}
CancelEventsOfType( EV_Item_DropToFloor );
CancelEventsOfType( EV_Item_Respawn );
CancelEventsOfType( EV_FadeOut );
setSolidType( SOLID_NOT );
hideModel();
if ( Respawnable() )
{
PostEvent( EV_Item_Respawn, RespawnTime() );
}
else
{
PostEvent( EV_Remove, 0.1 );
}
return item;
}