/*
===========================================================================
Copyright (C) 2000 - 2013, Raven Software, Inc.
Copyright (C) 2001 - 2013, Activision, Inc.
Copyright (C) 2013 - 2015, OpenJK contributors
This file is part of the OpenJK source code.
OpenJK is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see .
===========================================================================
*/
#include "bg_public.h"
#include "b_local.h"
//custom anims:
//both_attack1 - running attack
//both_attack2 - crouched attack
//both_attack3 - standing attack
//both_stand1idle1 - idle
//both_crouch2stand1 - uncrouch
//both_death4 - running death
#define ASSASSIN_SHIELD_SIZE 75
#define TURN_ON 0x00000000
#define TURN_OFF 0x00000100
////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////
bool BubbleShield_IsOn()
{
return (NPC->flags&FL_SHIELDED);
}
////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////
void BubbleShield_TurnOn()
{
if (!BubbleShield_IsOn())
{
NPC->flags |= FL_SHIELDED;
NPC->client->ps.powerups[PW_GALAK_SHIELD] = Q3_INFINITE;
gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "force_shield", TURN_ON );
}
}
////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////
void BubbleShield_TurnOff()
{
if ( BubbleShield_IsOn())
{
NPC->flags &= ~FL_SHIELDED;
NPC->client->ps.powerups[PW_GALAK_SHIELD] = 0;
gi.G2API_SetSurfaceOnOff( &NPC->ghoul2[NPC->playerModel], "force_shield", TURN_OFF );
}
}
////////////////////////////////////////////////////////////////////////////////////////
// Push A Particular Ent
////////////////////////////////////////////////////////////////////////////////////////
void BubbleShield_PushEnt(gentity_t* pushed, vec3_t smackDir)
{
G_Damage(pushed, NPC, NPC, smackDir, NPC->currentOrigin, (g_spskill->integer+1)*Q_irand( 5, 10), DAMAGE_NO_KNOCKBACK, MOD_ELECTROCUTE);
G_Throw(pushed, smackDir, 10);
// Make Em Electric
//------------------
pushed->s.powerups |= (1 << PW_SHOCKED);
if (pushed->client)
{
pushed->client->ps.powerups[PW_SHOCKED] = level.time + 1000;
}
}
////////////////////////////////////////////////////////////////////////////////////////
// Go Through All The Ents Within The Radius Of The Shield And Push Them
////////////////////////////////////////////////////////////////////////////////////////
void BubbleShield_PushRadiusEnts()
{
int numEnts;
gentity_t* radiusEnts[128];
const float radius = ASSASSIN_SHIELD_SIZE;
vec3_t mins, maxs;
vec3_t smackDir;
float smackDist;
for (int i = 0; i < 3; i++ )
{
mins[i] = NPC->currentOrigin[i] - radius;
maxs[i] = NPC->currentOrigin[i] + radius;
}
numEnts = gi.EntitiesInBox(mins, maxs, radiusEnts, 128);
for (int entIndex=0; entIndexclient)
{
continue;
}
// Don't Push Away Other Assassin Droids
//---------------------------------------
if (radiusEnts[entIndex]->client->NPC_class==NPC->client->NPC_class)
{
continue;
}
// Should Have Already Pushed The Enemy If He Touched Us
//-------------------------------------------------------
if (NPC->enemy && NPCInfo->touchedByPlayer==NPC->enemy && radiusEnts[entIndex]==NPC->enemy)
{
continue;
}
// Do The Vector Distance Test
//-----------------------------
VectorSubtract(radiusEnts[entIndex]->currentOrigin, NPC->currentOrigin, smackDir);
smackDist = VectorNormalize(smackDir);
if (smackDisthealth<=0)
{
if (BubbleShield_IsOn())
{
BubbleShield_TurnOff();
}
return;
}
// Recharge Shields
//------------------
NPC->client->ps.stats[STAT_ARMOR] += 1;
if (NPC->client->ps.stats[STAT_ARMOR]>250)
{
NPC->client->ps.stats[STAT_ARMOR] = 250;
}
// If We Have Enough Armor And Are Not Shooting Right Now, Kick The Shield On
//----------------------------------------------------------------------------
if (NPC->client->ps.stats[STAT_ARMOR]>100 && TIMER_Done(NPC, "ShieldsDown"))
{
// Check On Timers To Raise And Lower Shields
//--------------------------------------------
if ((level.time - NPCInfo->enemyLastSeenTime)<1000 && TIMER_Done(NPC, "ShieldsUp"))
{
TIMER_Set(NPC, "ShieldsDown", 2000); // Drop Shields
TIMER_Set(NPC, "ShieldsUp", Q_irand(4000, 5000)); // Then Bring Them Back Up For At Least 3 sec
}
BubbleShield_TurnOn();
if (BubbleShield_IsOn())
{
// Update Our Shader Value
//-------------------------
NPC->client->renderInfo.customRGBA[0] =
NPC->client->renderInfo.customRGBA[1] =
NPC->client->renderInfo.customRGBA[2] =
NPC->client->renderInfo.customRGBA[3] = (NPC->client->ps.stats[STAT_ARMOR] - 100);
// If Touched By An Enemy, ALWAYS Shove Them
//-------------------------------------------
if (NPC->enemy && NPCInfo->touchedByPlayer==NPC->enemy)
{
vec3_t dir;
VectorSubtract(NPC->enemy->currentOrigin, NPC->currentOrigin, dir);
VectorNormalize(dir);
BubbleShield_PushEnt(NPC->enemy, dir);
}
// Push Anybody Else Near
//------------------------
BubbleShield_PushRadiusEnts();
}
}
// Shields Gone
//--------------
else
{
BubbleShield_TurnOff();
}
}