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.
351 lines
8.1 KiB
351 lines
8.1 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. |
|
* |
|
* Use, distribution, and modification of this source code and/or resulting |
|
* object code is restricted to non-commercial enhancements to products from |
|
* Valve LLC. All other use, distribution, or modification is prohibited |
|
* without written permission from Valve LLC. |
|
* |
|
****/ |
|
|
|
|
|
#include "extdll.h" |
|
#include "util.h" |
|
#include "cbase.h" |
|
#include "monsters.h" |
|
#include "weapons.h" |
|
#include "schedule.h" |
|
#include "nodes.h" |
|
#include "effects.h" |
|
#include "decals.h" |
|
#include "soundent.h" |
|
#include "game.h" |
|
#include "xenspit.h" |
|
|
|
LINK_ENTITY_TO_CLASS(xensmallspit, CXenSmallSpit); |
|
|
|
TYPEDESCRIPTION CXenSmallSpit::m_SaveData[] = |
|
{ |
|
DEFINE_FIELD(CXenSmallSpit, m_iTrail, FIELD_INTEGER), |
|
DEFINE_FIELD(CXenSmallSpit, m_flCycle, FIELD_FLOAT), |
|
DEFINE_FIELD(CXenSmallSpit, m_pBeam, FIELD_CLASSPTR), |
|
DEFINE_FIELD(CXenSmallSpit, m_vecOldVelocity, FIELD_VECTOR), |
|
}; |
|
|
|
IMPLEMENT_SAVERESTORE(CXenSmallSpit, CBaseEntity); |
|
|
|
void CXenSmallSpit::Spawn(void) |
|
{ |
|
Precache(); |
|
|
|
pev->movetype = MOVETYPE_FLY; |
|
pev->classname = MAKE_STRING("xensmallspit"); |
|
|
|
pev->solid = SOLID_BBOX; |
|
pev->rendermode = kRenderTransAdd; |
|
pev->renderamt = 255; |
|
|
|
SET_MODEL(ENT(pev), "sprites/hotglow.spr"); |
|
pev->frame = 0; |
|
pev->scale = 0.5; |
|
pev->gravity = 0; |
|
pev->dmg = gSkillData.plrDmgGauss; |
|
|
|
UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); |
|
|
|
// trail |
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY ); |
|
WRITE_BYTE( TE_BEAMFOLLOW ); |
|
WRITE_SHORT( entindex() ); // entity |
|
WRITE_SHORT( m_iTrail ); // model |
|
WRITE_BYTE( 10 ); // life |
|
WRITE_BYTE( 4 ); // width |
|
WRITE_BYTE( 161 ); // r, g, b |
|
WRITE_BYTE( 188 ); // r, g, b |
|
WRITE_BYTE( 0 ); // r, g, b |
|
WRITE_BYTE( 128 ); // brightness |
|
|
|
MESSAGE_END(); |
|
|
|
m_pBeam = NULL; |
|
m_pParent = NULL; |
|
} |
|
|
|
void CXenSmallSpit::Precache() |
|
{ |
|
PRECACHE_MODEL("sprites/hotglow.spr"); |
|
|
|
m_iTrail = PRECACHE_MODEL("sprites/laserbeam.spr"); |
|
|
|
PRECACHE_MODEL("sprites/laserbeam.spr"); |
|
} |
|
|
|
CXenSmallSpit* CXenSmallSpit::ShootStraight(entvars_t *pevOwner, Vector vecStart, Vector vecAngles, Vector vecVelocity) |
|
{ |
|
CXenSmallSpit *pSpit = GetClassPtr((CXenSmallSpit *)NULL); |
|
pSpit->Spawn(); |
|
|
|
UTIL_SetOrigin(pSpit->pev, vecStart); |
|
pSpit->pev->angles = vecAngles; |
|
pSpit->pev->velocity = vecVelocity; |
|
pSpit->pev->owner = ENT(pevOwner); |
|
pSpit->m_vecOldVelocity = vecVelocity; |
|
|
|
pSpit->m_flCycle = 0.0f; |
|
pSpit->m_pParent = NULL; |
|
|
|
pSpit->SetThink(&CXenSmallSpit::StraightThink); |
|
pSpit->pev->nextthink = gpGlobals->time + 0.01; |
|
|
|
return pSpit; |
|
} |
|
|
|
CXenSmallSpit* CXenSmallSpit::ShootCycle(entvars_t *pevOwner, Vector vecStart, Vector vecAngles, Vector vecVelocity, CBaseEntity* pParent, float flCycle) |
|
{ |
|
CXenSmallSpit *pSpit = GetClassPtr((CXenSmallSpit *)NULL); |
|
pSpit->Spawn(); |
|
|
|
UTIL_SetOrigin(pSpit->pev, vecStart); |
|
pSpit->pev->angles = vecAngles; |
|
pSpit->pev->velocity = vecVelocity; |
|
pSpit->pev->owner = ENT(pevOwner); |
|
pSpit->m_vecOldVelocity = vecVelocity; |
|
|
|
pSpit->m_flCycle = flCycle; |
|
pSpit->m_pParent = pParent; |
|
|
|
pSpit->SetThink(&CXenSmallSpit::CycleThink); |
|
pSpit->pev->nextthink = gpGlobals->time + 0.01; |
|
|
|
return pSpit; |
|
} |
|
|
|
void CXenSmallSpit::Touch(CBaseEntity *pOther) |
|
{ |
|
if (m_pParent != NULL) |
|
return; |
|
|
|
if (FClassnameIs(pOther->pev, STRING(pev->classname))) |
|
return; |
|
|
|
// ALERT(at_console, " CXenSmallSpit::Touch START\n"); |
|
|
|
TraceResult tr; |
|
|
|
RadiusDamage(pev->origin, pev, pev, pev->dmg, 80, CLASS_NONE, DMG_POISON | DMG_ALWAYSGIB); |
|
|
|
if (!pOther->pev->takedamage) |
|
{ |
|
// make a splat on the wall |
|
UTIL_TraceLine(pev->origin, pev->origin + pev->velocity * 10, dont_ignore_monsters, ENT(pev), &tr); |
|
UTIL_DecalTrace(&tr, DECAL_SMALLSCORCH1 + RANDOM_LONG(0, 2)); |
|
} |
|
|
|
if (m_pBeam) |
|
{ |
|
UTIL_Remove(m_pBeam); |
|
m_pBeam = NULL; |
|
} |
|
|
|
// light. |
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin); |
|
WRITE_BYTE(TE_DLIGHT); |
|
WRITE_COORD(pev->origin.x); // X |
|
WRITE_COORD(pev->origin.y); // Y |
|
WRITE_COORD(pev->origin.z); // Z |
|
WRITE_BYTE(8); // radius * 0.1 |
|
WRITE_BYTE(161); // r |
|
WRITE_BYTE(188); // g |
|
WRITE_BYTE(0); // b |
|
WRITE_BYTE(10); // time * 10 |
|
WRITE_BYTE(2); // decay * 0.1 |
|
MESSAGE_END(); |
|
|
|
m_pParent = NULL; |
|
|
|
SetThink(&CXenSmallSpit::SUB_Remove); |
|
SetTouch(NULL); |
|
pev->nextthink = gpGlobals->time; |
|
|
|
// ALERT(at_console, " CXenSmallSpit::Touch END\n"); |
|
} |
|
|
|
void CXenSmallSpit::StraightThink(void) |
|
{ |
|
pev->nextthink = gpGlobals->time + 0.01f; |
|
|
|
m_flCycle += 0.02f; |
|
|
|
if (m_flCycle >= 1) |
|
m_flCycle = 0; |
|
|
|
pev->velocity.z = m_vecOldVelocity.z + sin(m_flCycle * 2 * M_PI) * 16; |
|
} |
|
|
|
void CXenSmallSpit::CycleThink(void) |
|
{ |
|
pev->nextthink = gpGlobals->time + 0.01f; |
|
|
|
m_flCycle += 0.02f; |
|
|
|
if (m_flCycle >= 1) |
|
m_flCycle = 0; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS(xenlargespit, CXenLargeSpit); |
|
|
|
TYPEDESCRIPTION CXenLargeSpit::m_SaveData[] = |
|
{ |
|
DEFINE_FIELD(CXenLargeSpit, m_iChildCount, FIELD_INTEGER), |
|
DEFINE_ARRAY(CXenLargeSpit, m_pChildren, FIELD_CLASSPTR, XENSPIT_MAX_PROJECTILES), |
|
}; |
|
|
|
IMPLEMENT_SAVERESTORE(CXenLargeSpit, CBaseEntity); |
|
|
|
|
|
void CXenLargeSpit::Spawn(void) |
|
{ |
|
Precache(); |
|
|
|
pev->movetype = MOVETYPE_FLY; |
|
pev->classname = MAKE_STRING("xenlargespit"); |
|
|
|
pev->solid = SOLID_BBOX; |
|
pev->rendermode = kRenderTransAdd; |
|
pev->renderamt = 255; |
|
|
|
SET_MODEL(ENT(pev), "sprites/glow02.spr"); |
|
pev->frame = 0; |
|
pev->scale = 0.5; |
|
pev->gravity = 0; |
|
pev->dmg = gSkillData.plrDmgGauss; |
|
|
|
pev->renderamt = 0; |
|
|
|
UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0)); |
|
|
|
for (int i = 0; i < XENSPIT_MAX_PROJECTILES; i++) |
|
m_pChildren[i] = NULL; |
|
} |
|
|
|
void CXenLargeSpit::Precache() |
|
{ |
|
PRECACHE_MODEL("sprites/glow02.spr"); |
|
} |
|
|
|
CXenLargeSpit* CXenLargeSpit::Shoot(entvars_t *pevOwner, Vector vecStart, Vector vecAngles, Vector vecVelocity) |
|
{ |
|
CXenLargeSpit *pSpit = GetClassPtr((CXenLargeSpit *)NULL); |
|
pSpit->Spawn(); |
|
|
|
UTIL_SetOrigin(pSpit->pev, vecStart); |
|
pSpit->pev->angles = vecAngles; |
|
pSpit->pev->velocity = vecVelocity; |
|
pSpit->pev->owner = ENT(pevOwner); |
|
|
|
pSpit->SetThink(&CXenLargeSpit::CycleThink); |
|
pSpit->pev->nextthink = gpGlobals->time + 0.01; |
|
|
|
return pSpit; |
|
} |
|
|
|
void CXenLargeSpit::Touch(CBaseEntity *pOther) |
|
{ |
|
// ALERT(at_console, " CXenLargeSpit::Touch START\n"); |
|
|
|
float damage = max(pev->dmg, pev->dmg * m_iChildCount); |
|
|
|
RadiusDamage(pev->origin, pev, pev, damage, 110, CLASS_NONE, DMG_POISON | DMG_ALWAYSGIB); |
|
|
|
TraceResult tr; |
|
|
|
if (!pOther->pev->takedamage) |
|
{ |
|
// make a splat on the wall |
|
UTIL_TraceLine(pev->origin, pev->origin + pev->velocity * 10, dont_ignore_monsters, ENT(pev), &tr); |
|
UTIL_DecalTrace(&tr, DECAL_SMALLSCORCH1 + RANDOM_LONG(0, 2)); |
|
} |
|
|
|
for (int i = 0; i < m_iChildCount; i++) |
|
{ |
|
if (m_pChildren[i]) |
|
{ |
|
UTIL_Remove(m_pChildren[i]); |
|
m_pChildren[i] = NULL; |
|
} |
|
} |
|
|
|
m_iChildCount = 0; |
|
|
|
// light. |
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin); |
|
WRITE_BYTE(TE_DLIGHT); |
|
WRITE_COORD(pev->origin.x); // X |
|
WRITE_COORD(pev->origin.y); // Y |
|
WRITE_COORD(pev->origin.z); // Z |
|
WRITE_BYTE(12); // radius * 0.1 |
|
WRITE_BYTE(161); // r |
|
WRITE_BYTE(188); // g |
|
WRITE_BYTE(0); // b |
|
WRITE_BYTE(10); // time * 10 |
|
WRITE_BYTE(2); // decay * 0.1 |
|
MESSAGE_END(); |
|
|
|
SetThink(&CXenLargeSpit::SUB_Remove); |
|
SetTouch(NULL); |
|
pev->nextthink = gpGlobals->time + 0.1f; |
|
|
|
// ALERT(at_console, " CXenLargeSpit::Touch START\n"); |
|
} |
|
|
|
void CXenLargeSpit::CycleThink(void) |
|
{ |
|
pev->nextthink = gpGlobals->time + 0.1f; |
|
|
|
Vector src, forward, right, up, cross; |
|
|
|
forward = pev->velocity.Normalize(); |
|
|
|
Vector horizontal = Vector(pev->velocity.x, pev->velocity.y, 0).Normalize(); |
|
Vector direction = forward; |
|
|
|
float flDot = DotProduct(direction, horizontal); |
|
if (flDot < 0.5) |
|
cross = Vector(1, 0, 0); |
|
else |
|
cross = Vector(0, 0, 1); |
|
|
|
right = CrossProduct(direction, cross); |
|
up = CrossProduct(right, direction); |
|
|
|
for (int i = 0; i < m_iChildCount; i++) |
|
{ |
|
CXenSmallSpit* pSpit = (CXenSmallSpit*)m_pChildren[i]; |
|
if (pSpit) |
|
{ |
|
float cs, sn, dist; |
|
cs = cos(pSpit->m_flCycle * 2 * M_PI); |
|
sn = sin(pSpit->m_flCycle * 2 * M_PI); |
|
dist = max(2, 2 * m_iChildCount); |
|
|
|
// ALERT(at_console, "cs: %.2f. sn: %.2f\n", cs, sn); |
|
|
|
Vector target = (right * cs * dist) + (up * sn * dist); |
|
|
|
src = pev->origin + target * -2; |
|
pSpit->pev->origin = src; |
|
pSpit->pev->velocity = pev->velocity; |
|
} |
|
} |
|
} |
|
|
|
|
|
|