/*
================================================================
INFORMER GUN
================================================================

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 "informergun.h"
#include "worldspawn.h"
#include "specialfx.h"

CLASS_DECLARATION(Beam, InformerBeam, NULL);

Event EV_InformerBeam_FadeBeam("fadebeam");

ResponseDef InformerBeam::Responses[] =
{
	{ &EV_InformerBeam_FadeBeam, ( Response )&InformerBeam::FadeBeam },
	{ NULL, NULL }
};

InformerBeam::InformerBeam()
{
	hideModel();
	edict->s.frame = 0;
	edict->s.skinnum = 0;

	setMoveType( MOVETYPE_NONE );
	setSolidType( SOLID_NOT );

	edict->s.renderfx |= RF_BEAM;
	edict->s.modelindex = 1;			// must be non-zero
}

void InformerBeam::setBeam
	(
	Vector startpos,
	Vector endpos,
	int diameter,
	float r,
	float g,
	float b,
	float alpha,
	float lifespan
	)
	
{
	showModel();
	
	if ( lifespan )
	{
		PostEvent( EV_Remove, lifespan );
	}
	
	start = startpos;
	end = endpos;
	
	setOrigin( start );
	
	edict->s.old_origin[ 0 ] = end[ 0 ];
	edict->s.old_origin[ 1 ] = end[ 1 ];
	edict->s.old_origin[ 2 ] = end[ 2 ];
	
	edict->s.frame = diameter;
	edict->s.skinnum = 255;
	
	edict->s.color_r = r;
	edict->s.color_g = g;
	edict->s.color_b = b;
	edict->s.alpha = alpha;
	
	link();
}

void InformerBeam::FadeBeam(Event *ev)
{
	Vector beamvec, newstart, newend;
	float newalpha;
	
	edict->s.renderfx |= RF_TRANSLUCENT;
	beamvec = end - start;
	switch(beamstate)
	{
	case 1:
		newalpha = 0.3;
		newstart = start;
		newend = start + beamvec*0.5;
		break;
	case 2:
		newalpha = 0.25;
		newstart = start + beamvec*0.25;
		newend = start + beamvec*0.75;
		break;
	case 3:
		newalpha = 0.2;
		newstart = start + beamvec*0.5;
		newend = start + beamvec;
		break;
	default:
		PostEvent(EV_Remove, 0);
		return;
		break;
	}
	
	beamstate++;
	
	setOrigin(newstart);
	
	edict->s.old_origin[0] = newend[0];
	edict->s.old_origin[1] = newend[1];
	edict->s.old_origin[2] = newend[2];

	edict->s.frame = 2;
	edict->s.skinnum = 255;

	edict->s.color_r = 0.3;
	edict->s.color_g = 0.3;
	edict->s.color_b = 1;
	edict->s.alpha = newalpha;

	link();
	
	PostEvent(EV_InformerBeam_FadeBeam, 0.1);
}

//========================================================

CLASS_DECLARATION( Weapon, InformerGun, NULL );

ResponseDef InformerGun::Responses[] =
{
	{ &EV_Weapon_Shoot,	( Response )&InformerGun::Shoot },
	{ NULL, NULL }
};

InformerGun::InformerGun()
{
	SetModels( "informergun.def", "view_informergun.def" );
	SetAmmo(NULL, 0, 0);
	SetRank( 0, 0 );
	SetType( WEAPON_2HANDED_LO );
}

void InformerGun::Informify(Entity *ent)
{
	char userinfo[MAX_INFO_STRING];
	int i;
	edict_t *tmpent;

	// first make owner not the informer
	owner->client->resp.informer = false;
	// correct the owner's model and skin
	memcpy(userinfo, owner->client->pers.userinfo, sizeof(userinfo));
	G_ClientUserinfoChanged(owner->edict, userinfo);

	// now make our victim into the informer
	ent->client->resp.informer = true;
	// correct the victim's model and skin
	memcpy(userinfo, ent->client->pers.userinfo, sizeof(userinfo));
	G_ClientUserinfoChanged(ent->edict, userinfo);
	// make the "I'm the informer" effects
	ent->sound("environment/levelsnds/druglab/ping-sound.wav", 0.75, CHAN_BODY, ATTN_IDLE);
	SpawnTeleportEffect(ent->centroid, 165);

	// broadcast a messages about who the new informer is
	for(i = 1; i <= maxclients->value; i++)
	{
		if(!g_edicts[i].inuse)
		{
			continue;
		}

		tmpent = &g_edicts[i];

		if(tmpent == ent->edict)
			gi.centerprintf(tmpent, "jcx yv -80 boxtext \"You are the Informer!\"");
		else
			gi.centerprintf(tmpent, "jcx yv -80 string \"%s is the Informer!\"", ent->client->pers.netname);
	}
}

void InformerGun::Shoot (Event *ev)
{
	Vector pos;
	Vector dir;
	Vector end;
	trace_t trace;
	InformerBeam *beam;
	Vector right, up;
	int mask;

	assert( owner );
	if ( !owner )
	{
		return;
	}

	NextAttack( 0.8 );

	GetMuzzlePosition( &pos, &dir, &right, &up);
	pos -= up*4;

	if(!fadingbeam)
	{
		beam = new InformerBeam;
		fadingbeam = beam;
	}
	else
	{
		beam = (InformerBeam *)fadingbeam.Ptr();
	}
	beamstate = 1;

	mask = MASK_PROJECTILE;
	mask &= ~CONTENTS_FENCE;
	end = pos + dir*8192;
	trace = G_Trace(pos, vec_zero, vec_zero, end, owner, mask, "InformerGun::Shoot");
	beamstart = pos;
	beamvec = Vector(trace.endpos) - pos;
	if(trace.ent)
	{
		Entity *ent;

		ent = trace.ent->entity;

		if(ent->isClient() && !ent->deadflag)
		{
			// informify the poor bastard
			Informify(ent);
		}
		else
		{
			ent->Damage(owner, owner, 15 + G_Random(5), Vector(trace.endpos), dir, vec_zero, 0, 0, 0, -1, -1, 0);
		}
	}
	else
	{
		trace = G_Trace(pos, Vector(-4, -4, -4), Vector(4, 4, 4), end, owner, mask, "InformerGun::Shoot");
		beamstart = pos;
		beamvec = Vector(trace.endpos) - pos;
		if(trace.ent)
		{
			Entity *ent;
			
			ent = trace.ent->entity;
			
			if(ent->isClient() && !ent->deadflag)
			{
				// informify the poor bastard
				Informify(ent);
			}
			else
			{
				ent->Damage(owner, owner, 15 + G_Random(5), Vector(trace.endpos), dir, vec_zero, 0, 0, 0, -1, -1, 0);
			}
		}
		else
		{
			trace = G_Trace(pos, Vector(-8, -8, -8), Vector(8, 8, 8), end, owner, mask, "InformerGun::Shoot");
			beamstart = pos;
			beamvec = Vector(trace.endpos) - pos;
			if(trace.ent)
			{
				Entity *ent;
				
				ent = trace.ent->entity;
				
				if(ent->isClient() && !ent->deadflag)
				{
					// informify the poor bastard
					Informify(ent);
				}
				else
				{
					ent->Damage(owner, owner, 15 + G_Random(5), Vector(trace.endpos), dir, vec_zero, 0, 0, 0, -1, -1, 0);
				}
			}
		}
	}

	pos = beamstart + beamvec;
	beam->setBeam(beamstart, pos, 4, 0.5, 0.5, 1, 0.5, 0.5);
	beam->beamstate = 1;
	beam->CancelEventsOfType(EV_InformerBeam_FadeBeam);
	beam->PostEvent(EV_InformerBeam_FadeBeam, 0.1);
}

qboolean InformerGun::AutoChange (void)
{
	return false;
}

// Don't drop informerguns
qboolean InformerGun::Drop (void)
{
	return false;
}

qboolean InformerGun::ReadyToChange (void)	
{
	return false;
}
