Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1279 lines
30 KiB

/***
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* This source code contains proprietary and confidential information of
* Valve LLC and its suppliers. Access to this code is restricted to
* persons who have executed a written SDK license with Valve. Any access,
* use or distribution of this code by or to any unlicensed person is illegal.
*
****/
//=========================================================
// Generic Monster - purely for scripted sequence work.
//=========================================================
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "schedule.h"
#include "player.h"
#include "weapons.h"
#define GENEWORM_LEVEL0 0
#define GENEWORM_LEVEL1 1
#define GENEWORM_LEVEL0_HEIGHT 244
#define GENEWORM_LEVEL1_HEIGHT 304
#define GENEWORM_SKIN_EYE_OPEN 0
#define GENEWORM_SKIN_EYE_LEFT 1
#define GENEWORM_SKIN_EYE_RIGHT 2
#define GENEWORM_SKIN_EYE_CLOSED 3
#define GENEWORM_ATTACHMENT_MOUTH 0
#define GENEWORM_ATTACHMENT_SPAWN 1
#define GENEWORM_ATTACHMENT_RIGHTEYE 1
#define GENEWORM_ATTACHMENT_LEFTEYE 1
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
#define GENEWORM_AE_BEAM ( 0 ) // Toxic beam attack (sprite trail)
#define GENEWORM_AE_PORTAL ( 2 ) // Create a portal that spawns an enemy.
#define GENEWORM_AE_MELEE_LEFT1 ( 3 ) // Play hit sound
#define GENEWORM_AE_MELEE_LEFT2 ( 4 ) // Activates the trigger_geneworm_hit
#define GENEWORM_AE_MELEE_RIGHT1 ( 5 ) // Play hit sound
#define GENEWORM_AE_MELEE_RIGHT2 ( 6 ) // Activates the trigger_geneworm_hit
#define GENEWORM_AE_MELEE_FORWARD1 ( 7 ) // Play hit sound
#define GENEWORM_AE_MELEE_FORWARD2 ( 8 ) // Activates the trigger_geneworm_hit
#define GENEWORM_AE_MAD ( 9 ) // Room starts shaking!
#define GENEWORM_AE_EYEPAIN ( 1012 ) // Still put here (In case we need to toggle eye pain status)
//=========================================================
// CGeneWormCloud
//=========================================================
class CGeneWormCloud : public CBaseEntity
{
public:
void Spawn();
void Precache();
void TurnOn();
void RunGeneWormCloud(float frames);
static CGeneWormCloud *LaunchCloud(const Vector origin, const Vector aim, float velocity, edict_t *pOwner, float fadeTime);
void CreateCloud(const Vector origin);
virtual int Save(CSave &save);
virtual int Restore(CRestore &restore);
static TYPEDESCRIPTION m_SaveData[];
void EXPORT GeneWormCloudThink();
void EXPORT CloudTouch( CBaseEntity *pOther );
int m_maxFrame;
float m_fadeScale;
float m_fadeRender;
float m_lastTime;
float m_birthtime;
BOOL m_bLaunched;
};
LINK_ENTITY_TO_CLASS(env_genewormcloud, CGeneWormCloud)
TYPEDESCRIPTION CGeneWormCloud::m_SaveData[] =
{
DEFINE_FIELD(CGeneWormCloud, m_maxFrame, FIELD_INTEGER),
DEFINE_FIELD(CGeneWormCloud, m_fadeScale, FIELD_FLOAT),
DEFINE_FIELD(CGeneWormCloud, m_fadeRender, FIELD_FLOAT),
DEFINE_FIELD(CGeneWormCloud, m_birthtime, FIELD_TIME),
DEFINE_FIELD(CGeneWormCloud, m_lastTime, FIELD_TIME),
DEFINE_FIELD(CGeneWormCloud, m_bLaunched, FIELD_BOOLEAN),
};
IMPLEMENT_SAVERESTORE(CGeneWormCloud, CBaseEntity)
void CGeneWormCloud::Precache()
{
PRECACHE_MODEL("sprites/ballsmoke.spr");
}
void CGeneWormCloud::Spawn()
{
Precache();
pev->solid = SOLID_BBOX;
pev->effects = 0;
pev->frame = 0;
UTIL_SetSize(pev, Vector(0,0,0), Vector(0,0,0));
SET_MODEL(ENT(pev), "sprites/ballsmoke.spr");
m_maxFrame = MODEL_FRAMES(pev->modelindex)-1;
pev->scale = 0.01;
m_lastTime = gpGlobals->time;
m_birthtime = gpGlobals->time;
m_fadeScale = 0;
m_bLaunched = FALSE;
SetTouch(&CGeneWormCloud::CloudTouch);
SetThink(&CGeneWormCloud::GeneWormCloudThink);
pev->nextthink = gpGlobals->time;
}
void CGeneWormCloud::CloudTouch(CBaseEntity *pOther)
{
if (ENT(pOther->pev) == pev->owner || (ENT(pOther->pev) == VARS(pev->owner)->owner))
return;
if(pOther->pev->takedamage)
pOther->TakeDamage(pev, pev, 5, DMG_ACID);
pev->nextthink = gpGlobals->time;
SetThink(NULL);
UTIL_Remove(this);
}
void CGeneWormCloud::TurnOn()
{
pev->effects = 0;
if(pev->framerate != 0 && m_maxFrame > 1 && pev->spawnflags & FL_SWIM)
{
m_lastTime = gpGlobals->time;
pev->nextthink = gpGlobals->time;
pev->frame = 0;
}
else
pev->frame = 0;
}
void CGeneWormCloud::RunGeneWormCloud(float frames)
{
if(m_bLaunched)
{
pev->renderamt -= m_fadeRender;
if(pev->scale >= 4.5)
{
pev->scale = 0;
UTIL_Remove(this);
return;
}
else
pev->scale += 0.1;
pev->frame += frames;
if(pev->frame > m_maxFrame && m_maxFrame > 0)
{
pev->frame = m_maxFrame;
}
}
}
void CGeneWormCloud::GeneWormCloudThink()
{
TraceResult tr;
float frames = (gpGlobals->time - m_lastTime) * pev->framerate;
UTIL_TraceHull(pev->origin, pev->origin, ignore_monsters, point_hull, ENT(pev), &tr);
if(tr.fAllSolid && tr.fStartSolid && gpGlobals->time - m_birthtime >= 0.75)
{
UTIL_Remove(this);
}
RunGeneWormCloud(frames);
pev->nextthink = gpGlobals->time + 0.1;
m_lastTime = gpGlobals->time;
}
CGeneWormCloud *CGeneWormCloud::LaunchCloud(const Vector origin, const Vector aim, float velocity, edict_t *pOwner, float fadeTime)
{
CGeneWormCloud *pCloud = GetClassPtr((CGeneWormCloud*)NULL);
UTIL_SetOrigin(pCloud->pev, origin);
pCloud->Spawn();
UTIL_MakeVectors(aim);
pCloud->pev->owner = pOwner;
pCloud->pev->skin = 0;
pCloud->pev->body = 0;
pCloud->pev->aiment = 0;
pCloud->pev->movetype = MOVETYPE_NOCLIP;
pCloud->pev->velocity = aim * velocity;
pCloud->m_fadeScale = 2.5 / fadeTime;
pCloud->m_fadeRender = (pCloud->pev->renderamt - 7) / fadeTime;
pCloud->m_bLaunched = TRUE;
return pCloud;
}
void CGeneWormCloud::CreateCloud(const Vector origin)
{
UTIL_SetOrigin(pev, origin);
SetThink(&CGeneWormCloud::GeneWormCloudThink);
SetTouch(&CGeneWormCloud::CloudTouch);
}
//========================================================
// CGeneWormSpawn
//========================================================
class CGeneWormSpawn : public CBaseEntity
{
public:
void Spawn();
void Precache();
virtual int Save(CSave &save);
virtual int Restore(CRestore &restore);
static CGeneWormSpawn *LaunchSpawn(Vector origin, Vector aim, float speed, edict_t *pOwner);
void EXPORT SpawnTouch(CBaseEntity *pOther) { }
void EXPORT SpawnThink();
static TYPEDESCRIPTION m_SaveData[];
float m_flBirthTime;
int m_maxFrame;
BOOL m_bTrooperDropped;
};
LINK_ENTITY_TO_CLASS(env_genewormspawn, CGeneWormSpawn)
TYPEDESCRIPTION CGeneWormSpawn::m_SaveData[] =
{
DEFINE_FIELD(CGeneWormSpawn, m_flBirthTime, FIELD_TIME),
DEFINE_FIELD(CGeneWormSpawn, m_bTrooperDropped, FIELD_BOOLEAN),
DEFINE_FIELD(CGeneWormSpawn, m_maxFrame, FIELD_INTEGER),
};
IMPLEMENT_SAVERESTORE(CGeneWormSpawn, CBaseEntity)
void CGeneWormSpawn::Precache()
{
PRECACHE_MODEL("sprites/tele1.spr");
PRECACHE_MODEL("sprites/boss_glow.spr");
}
void CGeneWormSpawn::Spawn()
{
Precache();
pev->classname = MAKE_STRING("env_genewormspawn");
pev->solid = SOLID_BBOX;
pev->movetype = MOVETYPE_NOCLIP;
pev->effects = 0;
pev->frame = 0;
pev->scale = 1.5;
pev->rendermode = kRenderTransAdd;
pev->renderamt = 255;
SET_MODEL(ENT(pev), "sprites/tele1.spr");
UTIL_SetSize(pev, g_vecZero, g_vecZero);
m_maxFrame = g_engfuncs.pfnModelFrames(pev->modelindex) - 1;
if(pev->angles.y != 0 && pev->angles.z == 0)
{
pev->angles.z = pev->angles.y;
pev->angles.y = 0;
}
m_bTrooperDropped = FALSE;
m_flBirthTime = gpGlobals->time;
SetTouch(&CGeneWormSpawn::SpawnTouch);
SetThink(&CGeneWormSpawn::SpawnThink);
pev->nextthink = gpGlobals->time + 0.1;
}
void CGeneWormSpawn::SpawnThink()
{
CBaseEntity *player;
pev->effects = 0;
pev->framerate = 10;
if((pev->origin - pev->owner->v.origin).Length() > 1050)
{
pev->velocity = g_vecZero;
if(gpGlobals->time - m_flBirthTime >= 2.5)
{
if(!m_bTrooperDropped)
{
EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "debris/beamstart2.wav", 1, 0.4, 0, 100);
Create("monster_shocktrooper", pev->origin, pev->angles, ENT(pev));
m_bTrooperDropped = TRUE;
}
else
pev->scale -= 0.25;
}
}
if(pev->scale <= 0)
UTIL_Remove(this);
if(pev->frame >= m_maxFrame)
pev->frame = 0;
else
pev->frame++;
if(pev->scale < 3.2)
pev->scale += 0.1;
if((player = UTIL_FindEntityByClassname(0, "player")))
{
if((player->pev->origin - pev->origin).Length() <= 96)
player->TakeDamage(VARS(player->pev), VARS(player->pev), 5, DMG_SHOCK);
}
pev->nextthink = gpGlobals->time + 0.1;
}
CGeneWormSpawn *CGeneWormSpawn::LaunchSpawn(Vector origin, Vector aim, float speed, edict_t *pOwner)
{
CGeneWormSpawn *WormSpawn = GetClassPtr((CGeneWormSpawn*)NULL);
UTIL_MakeVectors(aim);
UTIL_SetOrigin(WormSpawn->pev, origin);
WormSpawn->Spawn();
WormSpawn->pev->velocity = aim * speed;
WormSpawn->pev->owner = pOwner;
return WormSpawn;
}
//=========================================================
// CGeneWorm
//=========================================================
class CGeneWorm : public CBaseMonster
{
public:
int Save(CSave &save);
int Restore(CRestore &restore);
static TYPEDESCRIPTION m_SaveData[];
void Spawn(void);
void Precache(void);
int Classify(void) { return CLASS_ALIEN_MONSTER; }
void Killed(entvars_t *pevAttacker, int iGib);
void TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
void FireHurtTargets(const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void SetObjectCollisionBox(void)
{
pev->absmin = pev->origin + Vector( -437, -720, -332 );
pev->absmax = pev->origin + Vector( 425, 164, 355 );
}
void HandleAnimEvent(MonsterEvent_t *pEvent);
void EXPORT StartThink(void);
void EXPORT HuntThink(void);
void EXPORT CrashTouch(CBaseEntity *pOther);
void EXPORT DyingThink(void);
void EXPORT NullThink(void);
void EXPORT CommandUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
void EXPORT HitTouch( CBaseEntity *pOther );
void NextActivity(void);
void TrackHead();
int TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
void PainSound(void);
void DeathSound(void);
void IdleSound(void);
BOOL ClawAttack();
Vector m_posTarget;
CGeneWormCloud *m_pCloud;
CGeneWormSpawn *m_orificeGlow;
CSprite *m_pBall;
float m_flLastSeen;
float m_flOrificeOpenTime;
float m_flSpitStartTime;
float m_flMadDelayTime;
float m_flTakeHitTime;
float m_flHitTime;
float m_flNextMeleeTime;
float m_flNextRangeTime;
float m_flDeathStart;
BOOL m_fActivated;
BOOL m_fRightEyeHit;
BOOL m_fLeftEyeHit;
BOOL m_fGetMad;
BOOL m_fOrificeHit;
BOOL m_fSpiting;
BOOL m_fSpawningTrooper;
BOOL m_fHasEntered;
int m_iHitTimes;
int m_iMaxHitTimes;
int m_iWasHit;
static const char *pAttackSounds[];
static const char *pDeathSounds[];
static const char *pEntrySounds[];
static const char *pPainSounds[];
static const char *pIdleSounds[];
static const char *pEyePainSounds[];
};
LINK_ENTITY_TO_CLASS(monster_geneworm, CGeneWorm)
TYPEDESCRIPTION CGeneWorm::m_SaveData[] =
{
DEFINE_FIELD(CGeneWorm, m_posTarget, FIELD_POSITION_VECTOR),
DEFINE_FIELD(CGeneWorm, m_flLastSeen, FIELD_TIME),
DEFINE_FIELD(CGeneWorm, m_pCloud, FIELD_CLASSPTR),
DEFINE_FIELD(CGeneWorm, m_orificeGlow, FIELD_CLASSPTR),
DEFINE_FIELD(CGeneWorm, m_pBall, FIELD_CLASSPTR),
DEFINE_FIELD(CGeneWorm, m_iHitTimes, FIELD_INTEGER),
DEFINE_FIELD(CGeneWorm, m_iMaxHitTimes, FIELD_INTEGER),
DEFINE_FIELD(CGeneWorm, m_iWasHit, FIELD_INTEGER),
DEFINE_FIELD(CGeneWorm, m_flNextMeleeTime, FIELD_TIME),
DEFINE_FIELD(CGeneWorm, m_flNextRangeTime, FIELD_TIME),
DEFINE_FIELD(CGeneWorm, m_fRightEyeHit, FIELD_BOOLEAN),
DEFINE_FIELD(CGeneWorm, m_fLeftEyeHit, FIELD_BOOLEAN),
DEFINE_FIELD(CGeneWorm, m_fOrificeHit, FIELD_BOOLEAN),
DEFINE_FIELD(CGeneWorm, m_flOrificeOpenTime, FIELD_TIME),
DEFINE_FIELD(CGeneWorm, m_fSpawningTrooper, FIELD_BOOLEAN),
DEFINE_FIELD(CGeneWorm, m_fActivated, FIELD_BOOLEAN),
DEFINE_FIELD(CGeneWorm, m_flDeathStart, FIELD_TIME),
DEFINE_FIELD(CGeneWorm, m_fHasEntered, FIELD_BOOLEAN),
DEFINE_FIELD(CGeneWorm, m_flMadDelayTime, FIELD_TIME),
DEFINE_FIELD(CGeneWorm, m_fGetMad, FIELD_BOOLEAN),
DEFINE_FIELD(CGeneWorm, m_fSpiting, FIELD_BOOLEAN),
DEFINE_FIELD(CGeneWorm, m_flSpitStartTime, FIELD_TIME),
};
IMPLEMENT_SAVERESTORE(CGeneWorm, CBaseMonster)
//=========================================================
//=========================================================
const char *CGeneWorm::pAttackSounds[] =
{
"geneworm/geneworm_attack_mounted_gun.wav",
"geneworm/geneworm_attack_mounted_rocket.wav",
"geneworm/geneworm_beam_attack.wav",
"geneworm/geneworm_big_attack_forward.wav",
};
const char *CGeneWorm::pDeathSounds[] =
{
"geneworm/geneworm_death.wav",
};
const char *CGeneWorm::pEntrySounds[] =
{
"geneworm/geneworm_entry.wav",
};
const char *CGeneWorm::pPainSounds[] =
{
"geneworm/geneworm_final_pain1.wav",
"geneworm/geneworm_final_pain2.wav",
"geneworm/geneworm_final_pain3.wav",
"geneworm/geneworm_final_pain4.wav",
};
const char *CGeneWorm::pIdleSounds[] =
{
"geneworm/geneworm_idle1.wav",
"geneworm/geneworm_idle2.wav",
"geneworm/geneworm_idle3.wav",
"geneworm/geneworm_idle4.wav",
};
const char *CGeneWorm::pEyePainSounds[] =
{
"geneworm/geneworm_shot_in_eye.wav",
};
//=========================================================
// Spawn
//=========================================================
void CGeneWorm::Spawn()
{
Precache();
// motor
pev->movetype = MOVETYPE_FLY;
pev->solid = SOLID_NOT;
SET_MODEL(ENT(pev), "models/geneworm.mdl");
UTIL_SetSize(pev, Vector( -437, -720, -332 ), Vector( 425, 164, 355 ));
UTIL_SetOrigin(pev, pev->origin);
pev->flags |= FL_MONSTER;
pev->takedamage = DAMAGE_AIM;
pev->health = gSkillData.gwormHealth;
pev->view_ofs = Vector(0, 0, 192);
pev->sequence = 0;
ResetSequenceInfo();
InitBoneControllers();
pev->deadflag = DEAD_NO;
pev->renderamt = 0;
pev->rendermode = kRenderTransTexture;
pev->effects = 0;
m_bloodColor = BLOOD_COLOR_GREEN;
m_iHitTimes = 0;
m_iMaxHitTimes = 5;
m_MonsterState = MONSTERSTATE_IDLE;
m_flSpitStartTime = gpGlobals->time;
m_flOrificeOpenTime = gpGlobals->time;
m_flMadDelayTime = gpGlobals->time;
m_flTakeHitTime = 0;
m_flHitTime = 0;
m_iWasHit = FALSE;
m_fRightEyeHit = FALSE;
m_fLeftEyeHit = FALSE;
m_fGetMad = FALSE;
m_fOrificeHit = FALSE;
m_fActivated = FALSE;
m_fHasEntered = FALSE;
m_pCloud = NULL;
UTIL_SetOrigin(pev, pev->origin);
SetThink(&CGeneWorm::StartThink);
pev->nextthink = gpGlobals->time + 0.1;
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CGeneWorm::Precache()
{
PRECACHE_MODEL("models/geneworm.mdl");
PRECACHE_SOUND_ARRAY(pAttackSounds);
PRECACHE_SOUND_ARRAY(pDeathSounds);
PRECACHE_SOUND_ARRAY(pEntrySounds);
PRECACHE_SOUND_ARRAY(pPainSounds);
PRECACHE_SOUND_ARRAY(pIdleSounds);
PRECACHE_SOUND_ARRAY(pEyePainSounds);
PRECACHE_SOUND("debris/beamstart7.wav");
PRECACHE_SOUND("debris/beamstart2.wav");
PRECACHE_MODEL("sprites/tele1.spr");
PRECACHE_MODEL("sprites/ballsmoke.spr");
PRECACHE_MODEL("sprites/boss_glow.spr");
UTIL_PrecacheOther("monster_shocktrooper");
}
//=========================================================
//
//=========================================================
void CGeneWorm::StartThink(void)
{
Vector vecEyePos, vecEyeAng;
GetAttachment(0, vecEyePos, vecEyeAng);
pev->view_ofs = vecEyePos - pev->origin;
pev->frame = 0;
pev->sequence = LookupSequence("entry");
ResetSequenceInfo();
m_flNextMeleeTime = gpGlobals->time;
m_flNextRangeTime = gpGlobals->time;
SetUse(&CGeneWorm::CommandUse);
SetTouch(&CGeneWorm::HitTouch);
SetThink(&CGeneWorm::HuntThink);
pev->nextthink = gpGlobals->time + 0.1;
}
void CGeneWorm::HitTouch( CBaseEntity *pOther )
{
TraceResult tr = UTIL_GetGlobalTrace();
if( pOther->pev->modelindex == pev->modelindex )
return;
if( m_flHitTime > gpGlobals->time )
return;
// only look at the ones where the player hit me
if( tr.pHit == NULL || tr.pHit->v.modelindex != pev->modelindex )
return;
if( tr.iHitgroup == 0 )
{
pOther->TakeDamage( pev, pev, 20, DMG_CRUSH );
}
}
void CGeneWorm::Killed(entvars_t *pevAttacker, int iGib)
{
CBaseMonster::Killed(pevAttacker, iGib);
}
void CGeneWorm::DyingThink(void)
{
pev->nextthink = gpGlobals->time + 0.1;
GlowShellUpdate();
DispatchAnimEvents();
StudioFrameAdvance();
if(pev->deadflag == DEAD_DYING)
{
pev->renderamt--;
if( pev->renderamt == 0 )
UTIL_Remove( this );
if(gpGlobals->time - m_flDeathStart >= 15)
{
CBaseEntity* player = UTIL_FindEntityByClassname(0, "player");
if (player)
{
CBaseEntity* teleport = UTIL_FindEntityByTargetname(0, "GeneWormTeleport");
if (teleport)
teleport->Touch(player);
FireTargets("GeneWormTeleport", player, player, USE_ON, 1.0);
}
m_flDeathStart = gpGlobals->time + 999;
}
}
if(pev->deadflag == DEAD_NO)
{
pev->frame = 0;
pev->sequence = LookupSequence("death");
ResetSequenceInfo();
pev->renderfx = 0;
pev->rendermode = kRenderTransTexture;
pev->renderamt = 255;
pev->solid = SOLID_NOT;
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "geneworm/geneworm_death.wav", 1, 0.1, 0, 100);
FireTargets("GeneWormDead", this, this, USE_TOGGLE, 0);
m_flDeathStart = gpGlobals->time;
pev->deadflag = DEAD_DYING;
if(m_pCloud)
{
UTIL_Remove(m_pCloud);
m_pCloud = NULL;
}
if(m_orificeGlow)
{
UTIL_Remove(m_orificeGlow);
m_orificeGlow = NULL;
}
if(m_pBall)
{
UTIL_Remove(m_pBall);
m_pBall = NULL;
}
CBaseEntity* entity = NULL;
while((entity = UTIL_FindEntityByClassname(entity, "monster_shocktrooper")))
entity->SUB_StartFadeOut();
}
}
//=========================================================
//=========================================================
void CGeneWorm::FireHurtTargets(const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
edict_t *pentTarget = NULL;
if( !targetName )
return;
ALERT( at_aiconsole, "Firing: (%s)\n", targetName );
for( ; ; )
{
pentTarget = FIND_ENTITY_BY_TARGETNAME( pentTarget, targetName );
if( FNullEnt( pentTarget ) )
break;
CBaseEntity *pTarget = CBaseEntity::Instance( pentTarget );
if( pTarget && !( pTarget->pev->flags & FL_NOTARGET ) )
{
ALERT( at_aiconsole, "Found: %s, firing (%s)\n", STRING( pTarget->pev->classname ), targetName );
pTarget->Use( pActivator, pCaller, useType, value );
}
}
}
//=========================================================
//=========================================================
void CGeneWorm::NextActivity(void)
{
if (m_flLastSeen + 15 < gpGlobals->time)
{
if (m_hEnemy != 0)
{
if ((pev->origin - m_hEnemy->pev->origin).Length() > 700)
m_hEnemy = NULL;
}
}
if (m_hEnemy == 0)
{
Look(4096);
m_hEnemy = BestVisibleEnemy();
}
if(m_fGetMad)
{
pev->sequence = LookupSequence("mad");
m_flMadDelayTime = gpGlobals->time;
m_fGetMad = FALSE;
return;
}
if(m_fRightEyeHit && m_fLeftEyeHit)
{
if(gpGlobals->time <= m_flOrificeOpenTime && !m_fOrificeHit)
{
pev->sequence = LookupSequence("bigpain2");
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "geneworm/geneworm_final_pain2.wav", VOL_NORM, 0.1, 0, 100);
return;
}
m_flOrificeOpenTime = gpGlobals->time;
if(!m_fSpawningTrooper)
{
pev->sequence = LookupSequence("bigpain4");
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "geneworm/geneworm_final_pain4.wav", VOL_NORM, 0.1, 0, 100);
m_fSpawningTrooper = TRUE;
return;
}
m_fLeftEyeHit = FALSE;
m_fRightEyeHit = FALSE;
m_fOrificeHit = FALSE;
m_fSpawningTrooper = FALSE;
pev->skin = 0;
}
if(ClawAttack())
return;
pev->sequence = LookupSequence("idle");
}
void CGeneWorm::TrackHead()
{
Vector vecMouthPos, vecMouthAngle;
GetAttachment(0, vecMouthPos, vecMouthAngle);
Vector angles = UTIL_VecToAngles(m_posTarget - vecMouthPos);
float diff = UTIL_AngleDiff(angles.y, pev->angles.y);
if (diff < -30)
{
diff = -30;
}
else if (diff > 30)
{
diff = 30;
}
SetBoneController(0, diff);
}
BOOL CGeneWorm::ClawAttack()
{
Vector targetAngle;
const char *sound;
if(m_hEnemy)
{
m_posTarget = m_hEnemy->pev->origin;
targetAngle = UTIL_VecToAngles(m_posTarget - pev->origin);
float AngleDiff = UTIL_AngleDiff(targetAngle.y, pev->angles.y);
if(m_flNextRangeTime <= gpGlobals->time)
{
if((m_posTarget - pev->origin).Length() >= 1200)
pev->sequence = LookupSequence("dattack1");
else if(AngleDiff > 10)
pev->sequence = LookupSequence("dattack2");
else if(AngleDiff < 0)
pev->sequence = LookupSequence("dattack3");
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "geneworm/geneworm_beam_attack.wav", 1, 0.1, 0, 100);
m_flNextRangeTime = gpGlobals->time + RANDOM_FLOAT(10,15);
return TRUE;
}
if(m_flNextMeleeTime <= gpGlobals->time)
{
if(m_posTarget.z <= pev->origin.z)
pev->sequence = LookupSequence("melee3");
else
{
if(AngleDiff >= 10)
{
pev->sequence = LookupSequence("melee1");
sound = "geneworm/geneworm_attack_mounted_rocket.wav";
}
else if(AngleDiff <= -2)
{
pev->sequence = LookupSequence("melee2");
sound = "geneworm/geneworm_big_attack_forward.wav";
}
else
{
pev->sequence = LookupSequence("melee3");
sound = "geneworm/geneworm_attack_mounted_gun.wav";
}
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, sound, 1, 0.1, 0, 100);
m_flNextMeleeTime = gpGlobals->time + RANDOM_FLOAT(3,5);
return TRUE;
}
}
}
return FALSE;
}
void CGeneWorm::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
{
if(FClassnameIs(pevAttacker, "monster_penguin"))
{
pev->health = 0;
SetThink(&CGeneWorm::DyingThink);
return;
}
if(gpGlobals->time <= m_flTakeHitTime)
return;
if(ptr->iHitgroup != 5 && ptr->iHitgroup != 4 && ptr->iHitgroup != 6)
{
if(pev->dmgtime != gpGlobals->time|| RANDOM_LONG(0, 10) <= 0)
{
if(FClassnameIs(pevAttacker, "env_laser"))
{
UTIL_Sparks(ptr->vecEndPos);
}
else if(bitsDamageType & DMG_BULLET)
{
UTIL_Ricochet(ptr->vecEndPos, RANDOM_LONG(1, 2));
}
pev->dmgtime = gpGlobals->time;
}
return;
}
if(FClassnameIs(pevAttacker, "env_laser"))
{
if(!m_fHasEntered)
return;
if(ptr->iHitgroup == 4 && !m_fLeftEyeHit && FStrEq("left_eye_laser", STRING(pevAttacker->targetname)))
{
m_fLeftEyeHit = TRUE;
m_iWasHit = 1;
if(!m_fRightEyeHit)
{
pev->skin = GENEWORM_SKIN_EYE_LEFT;
if(gpGlobals->time - m_flMadDelayTime >= 6)
m_fGetMad = TRUE;
}
else
{
pev->skin = GENEWORM_SKIN_EYE_CLOSED;
m_flOrificeOpenTime = gpGlobals->time + 20;
m_fGetMad = FALSE;
}
UTIL_BloodDrips(ptr->vecEndPos, ptr->vecEndPos, m_bloodColor, 256);
}
if(ptr->iHitgroup == 5 && !m_fRightEyeHit && FStrEq("right_eye_laser", STRING(pevAttacker->targetname)))
{
m_fRightEyeHit = TRUE;
m_iWasHit = 1;
if(!m_fLeftEyeHit)
{
pev->skin = GENEWORM_SKIN_EYE_RIGHT;
if(gpGlobals->time - m_flMadDelayTime >= 6)
m_fGetMad = TRUE;
}
else
{
pev->skin = GENEWORM_SKIN_EYE_CLOSED;
m_flOrificeOpenTime = gpGlobals->time + 20;
m_fGetMad = FALSE;
}
UTIL_BloodDrips(ptr->vecEndPos, ptr->vecEndPos, m_bloodColor, 256);
}
}
if(m_flOrificeOpenTime >= gpGlobals->time && m_pBall && ptr->iHitgroup == 6 && !m_fOrificeHit)
{
pev->health -= flDamage;
if(pev->health <= 0)
{
if(m_iHitTimes < m_iMaxHitTimes)
{
UTIL_BloodDecalTrace(ptr, m_bloodColor);
pev->health = gSkillData.gwormHealth;
m_iHitTimes++;
m_fOrificeHit = TRUE;
m_flOrificeOpenTime = gpGlobals->time;
m_iWasHit = 1;
}
else
{
m_iWasHit = 2;
SetThink(&CGeneWorm::DyingThink);
}
}
}
}
void CGeneWorm::HuntThink(void)
{
pev->nextthink = gpGlobals->time + 0.1;
GlowShellUpdate();
if(!m_fActivated)
return;
DispatchAnimEvents();
StudioFrameAdvance();
if (m_iWasHit > 1)
return;
if(pev->rendermode == kRenderTransTexture)
{
if(pev->renderamt < 248)
pev->renderamt += 3;
else
{
pev->renderamt = 255;
pev->renderfx = 0;
pev->rendermode = kRenderNormal;
}
}
if (!m_iWasHit)
{
if(m_fSequenceFinished)
{
m_fHasEntered = TRUE;
int oldSeq = pev->sequence;
NextActivity();
if (pev->sequence != oldSeq || !m_fSequenceLoops)
{
pev->frame = 0;
ResetSequenceInfo();
}
}
}
else if (m_iWasHit == 1)
{
UTIL_Remove(m_pCloud);
m_pCloud = NULL;
m_fSpiting = FALSE;
int iDir = 1;
const char* painAnimation = 0;
const char* painSound = "geneworm/geneworm_shot_in_eye.wav";
if (m_fLeftEyeHit && m_fRightEyeHit)
{
if (!m_fOrificeHit)
{
painAnimation = "bigpain1";
painSound = "geneworm/geneworm_final_pain1.wav";
if(!m_pBall)
{
Vector pos, angle;
GetAttachment(GENEWORM_ATTACHMENT_SPAWN, pos, angle);
m_pBall = CSprite::SpriteCreate( "sprites/boss_glow.spr", pos, TRUE );
if( m_pBall )
{
m_pBall->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxNoDissipation );
m_pBall->SetAttachment( edict(), 2 );
m_pBall->SetScale( 1.5 );
m_pBall->pev->framerate = 10.0;
m_pBall->TurnOn();
}
}
}
else
{
painAnimation = "bigpain3";
painSound = "geneworm/geneworm_final_pain3.wav";
}
}
else if (m_fLeftEyeHit)
{
painAnimation = "eyepain1";
}
else if (m_fRightEyeHit)
{
painAnimation = "eyepain2";
}
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, painSound, VOL_NORM, 0.1, 0, 100);
if (painAnimation)
{
pev->sequence = FindTransition(pev->sequence, LookupSequence(painAnimation), &iDir);
if (iDir > 0)
{
pev->frame = 0;
}
else
{
pev->frame = 255;
}
ResetSequenceInfo();
}
m_iWasHit = 0;
}
if (!m_fRightEyeHit)
{
Vector vecOrigin, vecAngles;
GetAttachment(GENEWORM_ATTACHMENT_RIGHTEYE, vecOrigin, vecAngles);
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
WRITE_BYTE( TE_ELIGHT );
WRITE_SHORT( entindex() ); // entity, attachment
WRITE_COORD( vecOrigin.x ); // origin
WRITE_COORD( vecOrigin.y );
WRITE_COORD( vecOrigin.z );
WRITE_COORD( 48 ); // radius
WRITE_BYTE( 128 ); // R
WRITE_BYTE( 255 ); // G
WRITE_BYTE( 128 ); // B
WRITE_BYTE( 1 ); // life * 10
WRITE_COORD( 2 ); // decay
MESSAGE_END();
}
if (!m_fLeftEyeHit)
{
Vector vecOrigin, vecAngles;
GetAttachment(GENEWORM_ATTACHMENT_LEFTEYE, vecOrigin, vecAngles);
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
WRITE_BYTE( TE_ELIGHT );
WRITE_SHORT( entindex() ); // entity, attachment
WRITE_COORD( vecOrigin.x ); // origin
WRITE_COORD( vecOrigin.y );
WRITE_COORD( vecOrigin.z );
WRITE_COORD( 48 ); // radius
WRITE_BYTE( 128 ); // R
WRITE_BYTE( 255 ); // G
WRITE_BYTE( 128 ); // B
WRITE_BYTE( 1 ); // life * 10
WRITE_COORD( 1 ); // decay
MESSAGE_END();
}
if (m_pBall)
{
Vector pos, angle;
GetAttachment(GENEWORM_ATTACHMENT_SPAWN, pos, angle);
UTIL_SetOrigin(m_pBall->pev, pos);
}
if(m_hEnemy)
{
m_posTarget = m_hEnemy->pev->origin;
m_posTarget.z += 24;
TrackHead();
if(m_fSpiting && gpGlobals->time - m_flSpitStartTime <= 2)
{
Vector pos, angle;
GetAttachment(0, pos, angle);
angle = (m_hEnemy->pev->origin - pos).Normalize();
m_pCloud = CGeneWormCloud::LaunchCloud(pos, angle, 700, ENT(pev), 0.15);
m_pCloud->pev->rendermode = 3;
m_pCloud->pev->rendercolor.x = 0;
m_pCloud->pev->rendercolor.y = 255;
m_pCloud->pev->rendercolor.z = 0;
m_pCloud->pev->renderfx = 14;
m_pCloud = NULL;
}
else
{
m_fSpiting = FALSE;
}
}
else
{
SetBoneController(0, 0);
}
}
//=========================================================
//=========================================================
void CGeneWorm::HandleAnimEvent(MonsterEvent_t *pEvent)
{
switch (pEvent->event)
{
case GENEWORM_AE_BEAM:
m_fSpiting = TRUE;
m_flSpitStartTime = gpGlobals->time;
break;
case GENEWORM_AE_PORTAL:
{
Vector vecPos, vecAng;
if(m_pBall)
{
UTIL_Remove(m_pBall);
m_pBall = NULL;
GetAttachment(GENEWORM_ATTACHMENT_SPAWN, vecPos, vecAng);
vecAng = pev->angles;
m_orificeGlow = CGeneWormSpawn::LaunchSpawn(vecPos, -vecAng, 1.25, ENT(pev));
pev->health = gSkillData.gwormHealth;
m_orificeGlow = NULL;
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "debris/beamstart7.wav", 1, 0.1, 0, RANDOM_LONG(-5, 5)+100);
}
break;
}
case GENEWORM_AE_MELEE_LEFT1:
FireHurtTargets("GeneWormLeftSlash", this, this, USE_TOGGLE, 1);
break;
case GENEWORM_AE_MELEE_LEFT2:
FireHurtTargets("GeneWormLeftSlash", this, this, USE_TOGGLE, 0);
break;
case GENEWORM_AE_MELEE_RIGHT1:
FireHurtTargets("GeneWormRightSlash", this, this, USE_TOGGLE, 1);
break;
case GENEWORM_AE_MELEE_RIGHT2:
FireHurtTargets("GeneWormRightSlash", this, this, USE_TOGGLE, 0);
break;
case GENEWORM_AE_MELEE_FORWARD1:
FireHurtTargets("GeneWormCenterSlash", this, this, USE_TOGGLE, 1);
break;
case GENEWORM_AE_MELEE_FORWARD2:
FireHurtTargets("GeneWormCenterSlash", this, this, USE_TOGGLE, 0);
break;
case GENEWORM_AE_MAD:
FireHurtTargets("GeneWormWallHit", this, this, USE_TOGGLE, 0);
UTIL_ScreenShake(pev->origin, 24, 3, 5, 2048);
break;
default:
break;
}
}
void CGeneWorm::CommandUse(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
if(useType == USE_TOGGLE && !m_fActivated)
{
pev->sequence = LookupSequence("entry");
pev->frame = 0;
ResetSequenceInfo();
pev->rendermode = kRenderTransTexture;
pev->renderfx = 0;
pev->renderamt = 0;
m_fActivated = TRUE;
pev->solid = SOLID_BBOX;
UTIL_SetOrigin(pev, pev->origin);
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, pEntrySounds[0], 1, 0.1, 0, 100);
}
}
int CGeneWorm::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType)
{
return 0;
}
void CGeneWorm::PainSound(void)
{
}
void CGeneWorm::DeathSound(void)
{
EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pDeathSounds), 2, ATTN_NORM);
}
void CGeneWorm::IdleSound(void)
{
EMIT_SOUND(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pIdleSounds), VOL_NORM, ATTN_NORM);
}