/*** * * 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 "cmbase.h" #include "cmbasemonster.h" #include "monsters.h" #include "customentity.h" #include "effects.h" #include "weapons.h" #include "decals.h" #include "func_break.h" #include "shake.h" #define SF_GIBSHOOTER_REPEATABLE 1 // allows a gibshooter to be refired #define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them. // -------------------------------------------------- // // Beams // // -------------------------------------------------- void CMBeam::Spawn( void ) { pev->solid = SOLID_NOT; // Remove model & collisions Precache( ); } void CMBeam::Precache( void ) { if ( pev->owner ) SetStartEntity( ENTINDEX( pev->owner ) ); if ( pev->aiment ) SetEndEntity( ENTINDEX( pev->aiment ) ); } void CMBeam::SetStartEntity( int entityIndex ) { pev->sequence = (entityIndex & 0x0FFF) | ((pev->sequence&0xF000)<<12); pev->owner = g_engfuncs.pfnPEntityOfEntIndex( entityIndex ); } void CMBeam::SetEndEntity( int entityIndex ) { pev->skin = (entityIndex & 0x0FFF) | ((pev->skin&0xF000)<<12); pev->aiment = g_engfuncs.pfnPEntityOfEntIndex( entityIndex ); } // These don't take attachments into account const Vector &CMBeam::GetStartPos( void ) { if ( GetType() == BEAM_ENTS ) { edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetStartEntity() ); return pent->v.origin; } return pev->origin; } const Vector &CMBeam::GetEndPos( void ) { int type = GetType(); if ( type == BEAM_POINTS || type == BEAM_HOSE ) { return pev->angles; } edict_t *pent = g_engfuncs.pfnPEntityOfEntIndex( GetEndEntity() ); if ( pent ) return pent->v.origin; return pev->angles; } CMBeam *CMBeam::BeamCreate( const char *pSpriteName, int width ) { // Create a new entity with CMBeam private data CMBeam *pBeam = CreateClassPtr( (CMBeam *)NULL ); if (pBeam == NULL) return NULL; pBeam->pev->classname = MAKE_STRING("beam"); pBeam->BeamInit( pSpriteName, width ); return pBeam; } void CMBeam::BeamInit( const char *pSpriteName, int width ) { pev->flags |= FL_CUSTOMENTITY; SetColor( 255, 255, 255 ); SetBrightness( 255 ); SetNoise( 0 ); SetFrame( 0 ); SetScrollRate( 0 ); pev->model = MAKE_STRING( pSpriteName ); SetTexture( PRECACHE_MODEL( (char *)pSpriteName ) ); SetWidth( width ); pev->skin = 0; pev->sequence = 0; pev->rendermode = 0; } void CMBeam::PointsInit( const Vector &start, const Vector &end ) { SetType( BEAM_POINTS ); SetStartPos( start ); SetEndPos( end ); SetStartAttachment( 0 ); SetEndAttachment( 0 ); RelinkBeam(); } void CMBeam::HoseInit( const Vector &start, const Vector &direction ) { SetType( BEAM_HOSE ); SetStartPos( start ); SetEndPos( direction ); SetStartAttachment( 0 ); SetEndAttachment( 0 ); RelinkBeam(); } void CMBeam::PointEntInit( const Vector &start, int endIndex ) { SetType( BEAM_ENTPOINT ); SetStartPos( start ); SetEndEntity( endIndex ); SetStartAttachment( 0 ); SetEndAttachment( 0 ); RelinkBeam(); } void CMBeam::EntsInit( int startIndex, int endIndex ) { SetType( BEAM_ENTS ); SetStartEntity( startIndex ); SetEndEntity( endIndex ); SetStartAttachment( 0 ); SetEndAttachment( 0 ); RelinkBeam(); } void CMBeam::RelinkBeam( void ) { const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); pev->mins.x = min( startPos.x, endPos.x ); pev->mins.y = min( startPos.y, endPos.y ); pev->mins.z = min( startPos.z, endPos.z ); pev->maxs.x = max( startPos.x, endPos.x ); pev->maxs.y = max( startPos.y, endPos.y ); pev->maxs.z = max( startPos.z, endPos.z ); pev->mins = pev->mins - pev->origin; pev->maxs = pev->maxs - pev->origin; UTIL_SetSize( pev, pev->mins, pev->maxs ); UTIL_SetOrigin( pev, pev->origin ); } #if 0 void CMBeam::SetObjectCollisionBox( void ) { const Vector &startPos = GetStartPos(), &endPos = GetEndPos(); pev->absmin.x = min( startPos.x, endPos.x ); pev->absmin.y = min( startPos.y, endPos.y ); pev->absmin.z = min( startPos.z, endPos.z ); pev->absmax.x = max( startPos.x, endPos.x ); pev->absmax.y = max( startPos.y, endPos.y ); pev->absmax.z = max( startPos.z, endPos.z ); } #endif void CMBeam::TriggerTouch( edict_t *pOther ) { if ( pOther->v.flags & (FL_CLIENT | FL_MONSTER) ) { if ( pev->owner ) { if (pev->owner->v.euser4 != NULL) { CMBaseEntity *pOwner = GetClassPtr((CMBaseEntity *)VARS(pev->owner)); pOwner->Use( pOther, this->edict(), USE_TOGGLE, 0 ); } } ALERT( at_console, "Firing targets!!!\n" ); } } edict_t *CMBeam::RandomTargetname( const char *szName ) { int total = 0; edict_t *pEntity = NULL; edict_t *pNewEntity = NULL; while ((pNewEntity = UTIL_FindEntityByTargetname( pNewEntity, szName )) != NULL) { total++; if (RANDOM_LONG(0,total-1) < 1) pEntity = pNewEntity; } return pEntity; } void CMBeam::DoSparks( const Vector &start, const Vector &end ) { if ( pev->spawnflags & (SF_BEAM_SPARKSTART|SF_BEAM_SPARKEND) ) { if ( pev->spawnflags & SF_BEAM_SPARKSTART ) { UTIL_Sparks( start ); } if ( pev->spawnflags & SF_BEAM_SPARKEND ) { UTIL_Sparks( end ); } } } void CMBeam::BeamDamage( TraceResult *ptr ) { RelinkBeam(); if ( ptr->flFraction != 1.0 && ptr->pHit != NULL ) { if (UTIL_IsPlayer(ptr->pHit)) { ClearMultiDamage(); UTIL_TraceAttack(ptr->pHit, pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM ); ApplyMultiDamage( pev, pev ); if ( pev->spawnflags & SF_BEAM_DECALS ) { if ( UTIL_IsBSPModel(ptr->pHit) ) UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) ); } } else if (ptr->pHit->v.euser4 != NULL) { ClearMultiDamage(); CMBaseEntity *pMonster = GetClassPtr((CMBaseEntity *)VARS(ptr->pHit)); pMonster->TraceAttack( pev, pev->dmg * (gpGlobals->time - pev->dmgtime), (ptr->vecEndPos - pev->origin).Normalize(), ptr, DMG_ENERGYBEAM ); ApplyMultiDamage( pev, pev ); if ( pev->spawnflags & SF_BEAM_DECALS ) { if ( pMonster->IsBSPModel() ) UTIL_DecalTrace( ptr, DECAL_BIGSHOT1 + RANDOM_LONG(0,4) ); } } } pev->dmgtime = gpGlobals->time; } void CMSprite::Spawn( void ) { pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_NONE; pev->effects = 0; pev->frame = 0; Precache(); SET_MODEL( ENT(pev), STRING(pev->model) ); m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1; if ( pev->targetname && !(pev->spawnflags & SF_SPRITE_STARTON) ) TurnOff(); else TurnOn(); // Worldcraft only sets y rotation, copy to Z if ( pev->angles.y != 0 && pev->angles.z == 0 ) { pev->angles.z = pev->angles.y; pev->angles.y = 0; } } void CMSprite::Precache( void ) { PRECACHE_MODEL( (char *)STRING(pev->model) ); // Reset attachment after save/restore if ( pev->aiment ) SetAttachment( pev->aiment, pev->body ); else { // Clear attachment pev->skin = 0; pev->body = 0; } } void CMSprite::SpriteInit( const char *pSpriteName, const Vector &origin ) { pev->model = MAKE_STRING(pSpriteName); pev->origin = origin; Spawn(); } CMSprite *CMSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) { CMSprite *pSprite = CreateClassPtr( (CMSprite *)NULL ); pSprite->SpriteInit( pSpriteName, origin ); pSprite->pev->classname = MAKE_STRING("env_sprite"); pSprite->pev->solid = SOLID_NOT; pSprite->pev->movetype = MOVETYPE_NOCLIP; if ( animate ) pSprite->TurnOn(); return pSprite; } void CMSprite::AnimateThink( void ) { Animate( pev->framerate * (gpGlobals->time - m_lastTime) ); pev->nextthink = gpGlobals->time + 0.1; m_lastTime = gpGlobals->time; } void CMSprite::AnimateUntilDead( void ) { if ( gpGlobals->time > pev->dmgtime ) UTIL_Remove(this->edict()); else { AnimateThink(); pev->nextthink = gpGlobals->time; } } void CMSprite::Expand( float scaleSpeed, float fadeSpeed ) { pev->speed = scaleSpeed; pev->health = fadeSpeed; SetThink( &CMSprite::ExpandThink ); pev->nextthink = gpGlobals->time; m_lastTime = gpGlobals->time; } void CMSprite::ExpandThink( void ) { float frametime = gpGlobals->time - m_lastTime; pev->scale += pev->speed * frametime; pev->renderamt -= pev->health * frametime; if ( pev->renderamt <= 0 ) { pev->renderamt = 0; UTIL_Remove( this->edict() ); } else { pev->nextthink = gpGlobals->time + 0.1; m_lastTime = gpGlobals->time; } } void CMSprite::Animate( float frames ) { pev->frame += frames; if ( pev->frame > m_maxFrame ) { if ( pev->spawnflags & SF_SPRITE_ONCE ) { TurnOff(); } else { if ( m_maxFrame > 0 ) pev->frame = fmod( pev->frame, m_maxFrame ); } } } void CMSprite::TurnOff( void ) { pev->effects = EF_NODRAW; pev->nextthink = 0; } void CMSprite::TurnOn( void ) { pev->effects = 0; if ( (pev->framerate && m_maxFrame > 1.0) || (pev->spawnflags & SF_SPRITE_ONCE) ) { SetThink( &CMSprite::AnimateThink ); pev->nextthink = gpGlobals->time; m_lastTime = gpGlobals->time; } pev->frame = 0; } void CMSprite::Use( edict_t *pActivator, edict_t *pCaller, USE_TYPE useType, float value ) { int on = pev->effects != EF_NODRAW; if ( ShouldToggle( useType, on ) ) { if ( on ) { TurnOff(); } else { TurnOn(); } } }