This member has provided no bio about themself...

Report article RSS Feed ScrGold/Coding: HL1 Flamethrower Experiement

Posted by PanSartre on Feb 22nd, 2013

weapon.h
//=========================================================
// Flamethrower
//=========================================================
class CFlamethrower : public CBasePlayerWeapon
{
public:

    void Spawn( void );
    void Precache( void );
    int iItemSlot( void ) { return 2; }
    int GetItemInfo(ItemInfo *p);
    int AddToPlayer( CBasePlayer *pPlayer );
    void PrimaryAttack( void );

    void StartThrow (void);
    void Throw (void);
    void StopThrow(void);

    BOOL Deploy( void );
    void Holster( int skiplocal = 0 );
    void WeaponIdle( void );
    void UpdateTrace( void );
   
    float m_flThrowTime;
    int    m_iStartThrow;
    int m_iThrowCount;
    int m_iFlameRange;
    //int m_iFlameSprite;

    virtual BOOL UseDecrement( void )
    {
#if defined( CLIENT_WEAPONS )
        return TRUE;
#else
        return FALSE;
#endif
    }

private:
    unsigned short m_usThrowerFire;
    unsigned short m_usThrowerStop;
    unsigned short m_usThrowerFlame;
};

//=========================================================
// Flamethrower FireBall
//=========================================================
class CFireBall : public CBaseMonster
{
public:
    int        Save( CSave &save );
    int        Restore( CRestore &restore );
    static    TYPEDESCRIPTION m_SaveData[];    //weapon.cpp
    void Spawn( void );
    void Precache( void );
    void EXPORT AnimateThink( void );
    void Smoke( void );
    void Damage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType );
    void EXPORT TouchThink( CBaseEntity *pOther );
    static CFireBall *CreateFireBall( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CFlamethrower *pLauncher );

private:
    int m_iFlametrail;
    int    m_maxFrame;
    float  m_flFlameTime;
    CFlamethrower *m_pLauncher;// pointer back to the launcher that fired me. MAYBE NOT NEEDED
};

flamethrower.cpp
//=========================================================
// Flamethrower
//=========================================================
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "gamerules.h"
#include "decals.h"
#include "effects.h"
#include "customentity.h"

#define FIRE_BALL_SPRITE        "sprites/fireball01.spr" //"sprites/flameball.spr"
#define FIRE_BALL_SPRITE2        "sprites/fireball02.spr" //"sprites/flameball.spr"
#define FIRE_BALL_SPRITE3        "sprites/fireball03.spr" //"sprites/flameball.spr"
#define FIRE_BEAM_SPRITE        "sprites/xbeam3.spr"
extern DLL_GLOBAL    short    g_sModelIndexSteam;
//#define SMOKE_BALL_SPRITE        "sprites/stmbal1.spr"

enum flamethrower_e {
    FLAME_IDLE1 = 0,
    FLAME_START_SHOOT,
    FLAME_SHOOT,
    FLAME_STOP_SHOOT,
    FLAME_DRAW,
    FLAME_HOLSTER,    //no animation
};

//EGON ANIMATION

//enum flamethrower_e {
//    FLAME_IDLE1 = 0,
//    FLAME_FIDGET,
//    FLAME_FIREON,
//    FLAME_FIRECYCLE,
//    FLAME_FIREOFF,
//    FLAME_FIRE1,    //no animation
//    FLAME_FIRE2,    //no animation
//    FLAME_FIRE3,
//    FLAME_FIRE4,
//    FLAME_DRAW,
//    FLAME_HOLSTER
//};

#ifndef CLIENT_DLL
//=========================================================
// Flamethrower FlameBall
//=========================================================

LINK_ENTITY_TO_CLASS( ft_fireball, CFireBall );

void CFireBall :: Spawn( void )
{
    Precache( );
    pev->classname = MAKE_STRING("ft_fireball");
    pev->movetype = MOVETYPE_FLY; //MOVETYPE_FLY;
    pev->solid = SOLID_BBOX;
    //pev->effects = EF_BRIGHTLIGHT;    //only a test

    switch ( RANDOM_LONG( 0, 2 ) )
    {
    case 0:
        SET_MODEL(ENT(pev), FIRE_BALL_SPRITE);
        break;
    case 1:
        SET_MODEL(ENT(pev), FIRE_BALL_SPRITE2);
        break;
    case 2:
        SET_MODEL(ENT(pev), FIRE_BALL_SPRITE3);
        break;
    }

    pev->rendermode = kRenderTransAdd;
    pev->renderamt = 255;
    pev->avelocity.z = RANDOM_FLOAT(-180,180);
    pev->scale = RANDOM_FLOAT( 0.10, 0.15); //0.30;
    pev->frame = 0;

    // flame trail
    MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
        WRITE_BYTE( TE_BEAMFOLLOW );
        WRITE_SHORT(entindex());    // entity
        WRITE_SHORT(m_iFlametrail );    // model
        WRITE_BYTE( 2 ); // life
        WRITE_BYTE( 10 );  // width
        WRITE_BYTE( 205 );   // r, g, b
        WRITE_BYTE( 147 );   // r, g, b
        WRITE_BYTE( 49 );   // r, g, b
        WRITE_BYTE( 225 );    // brightness
    MESSAGE_END();  // move PHS/PVS data sending into here (SEND_ALL, SEND_PVS, SEND_PHS)

    UTIL_SetSize(pev, Vector( 0, 0, 0), Vector(0, 0, 0));

    //pev->velocity = gpGlobals->v_forward * RANDOM_FLOAT( 600, 750); //700;
    m_flFlameTime = gpGlobals->time;

    m_maxFrame = (float) MODEL_FRAMES( pev->modelindex ) - 1;
    pev->dmg = gSkillData.plrDmgFlame;

}

//test
void CFireBall :: Damage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType )
{
    CBaseEntity *pEntity = NULL;
    TraceResult    tr;
    float        flAdjustedDamage, falloff;
    Vector        vecSpot;

    if ( flRadius )
        falloff = flDamage / flRadius;
    else
        falloff = 1.0;

    int bInWater = (UTIL_PointContents ( vecSrc ) == CONTENTS_WATER);

    vecSrc.z += 1;// in case grenade is lying on the ground

    if ( !pevAttacker )
        pevAttacker = pevInflictor;

    // iterate on all entities in the vicinity.
    while ((pEntity = UTIL_FindEntityInSphere( pEntity, vecSrc, flRadius )) != NULL)
    {
        if ( pEntity->pev->takedamage != DAMAGE_NO )
        {
            // UNDONE: this should check a damage mask, not an ignore
            if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore )
            {// houndeyes don't hurt other houndeyes with their attack
                continue;
            }

            // blast's don't tavel into or out of water
            if (bInWater && pEntity->pev->waterlevel == 0)
                continue;
            if (!bInWater && pEntity->pev->waterlevel == 3)
                continue;

            vecSpot = pEntity->BodyTarget( vecSrc );
           
            UTIL_TraceLine ( vecSrc, vecSpot, dont_ignore_monsters, ENT(pevInflictor), &tr );

            if ( tr.flFraction == 1.0 || tr.pHit == pEntity->edict() )
            {// the explosion can 'see' this entity, so hurt them!
                if (tr.fStartSolid)
                {
                    // if we're stuck inside them, fixup the position and distance
                    tr.vecEndPos = vecSrc;
                    tr.flFraction = 0.0;
                }
               
                // decrease damage for an ent that's farther from the bomb.
                flAdjustedDamage = ( vecSrc - tr.vecEndPos ).Length() * falloff;
                flAdjustedDamage = flDamage - flAdjustedDamage;
           
                if ( flAdjustedDamage < 0 )
                {
                    flAdjustedDamage = 0;
                }
           
                // ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) );
                if (tr.flFraction != 1.0)
                {
                    ClearMultiDamage( );
                    pEntity->TraceAttack( pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize( ), &tr, bitsDamageType );
                    ApplyMultiDamage( pevInflictor, pevAttacker );
                }
                else
                {
                    pEntity->TakeDamage ( pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType );
                }
            }
        }
    }
}

void CFireBall :: AnimateThink( void )
{
    if( UTIL_PointContents(pev->origin) == CONTENTS_WATER )
    {
        Smoke();
        SetThink ( &CBaseEntity::SUB_Remove );
        pev->nextthink = gpGlobals->time;
    }

    //if( UTIL_PointContents(pev->origin) == CONTENTS_SLIME || CONTENTS_LAVA )
    //{
    //    pev->velocity = 0;
    //}

    pev->nextthink = gpGlobals->time + 0.05;
    pev->velocity = pev->velocity * 0.97;
    pev->scale = pev->scale += 0.04;

    //CBaseEntity *pHurt = CheckTraceHullAttack( 32, 1, DMG_BURN ); //works, but not perfect
    entvars_t *pevOwner;
    if ( pev->owner )
        pevOwner = VARS( pev->owner );
    else
        pevOwner = NULL;

    pev->owner = NULL; // can't traceline attack owner if this is set
   
    if ( gpGlobals->time - m_flFlameTime >= 0.1 )
    {
        Damage( pev->origin, pev, pev, 1, pev->scale * 64, CLASS_NONE, DMG_BURN );
    }
   
    //if ( RANDOM_FLOAT( 0.0 , 0.6 ) + ( gpGlobals->time - m_flFlameTime ) >= 0.9  )
    //{
    //        Smoke();
    //}

    if ( pev->frame++ || gpGlobals->time - m_flFlameTime > 0.90)
    {
        if ( pev->frame > m_maxFrame || gpGlobals->time - m_flFlameTime > 0.90 )    //pev->frame > m_maxFrame ||
        {
            pev->frame = m_maxFrame;
            SetThink ( &CBaseEntity::SUB_Remove );
            pev->nextthink = gpGlobals->time;
        }
    }

    if ( gpGlobals->time - m_flFlameTime >= 0.3 )
    {
        //pev->velocity = pev->velocity / RANDOM_FLOAT( 2,3);
        if ( pev->movetype != MOVETYPE_TOSS )
        {
            pev->movetype = MOVETYPE_TOSS;
            pev->gravity = RANDOM_FLOAT( 0.4 , 0.5 );
            //pev->gravity = RANDOM_FLOAT(-4,-1);
        }

    }
}

void CFireBall :: Smoke( void )
{
        MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, pev->origin );
            WRITE_BYTE( TE_SMOKE );
            WRITE_COORD( pev->origin.x + RANDOM_FLOAT( -16, 16 ));
            WRITE_COORD( pev->origin.y + RANDOM_FLOAT( -16, 16 ));
            WRITE_COORD( pev->origin.z + RANDOM_FLOAT( 32, 16 ));
            WRITE_SHORT( g_sModelIndexSteam );
            WRITE_BYTE( RANDOM_FLOAT( 32 , 36 ));
            WRITE_BYTE( 35  ); // framerate
        MESSAGE_END();
}

void CFireBall :: Precache( void )
{
    PRECACHE_MODEL( FIRE_BALL_SPRITE );
    PRECACHE_MODEL( FIRE_BALL_SPRITE2 );
    PRECACHE_MODEL( FIRE_BALL_SPRITE3 );
    m_iFlametrail = PRECACHE_MODEL("sprites/smoke.spr");
}

CFireBall *CFireBall::CreateFireBall( Vector vecOrigin, Vector vecAngles, CBaseEntity *pOwner, CFlamethrower *pLauncher )
{
    CFireBall *pFireBall = GetClassPtr( (CFireBall *)NULL );

    UTIL_SetOrigin( pFireBall->pev, vecOrigin );
    pFireBall->pev->angles = vecAngles;
    pFireBall->Spawn();
    pFireBall->SetTouch( &CFireBall :: TouchThink );
    pFireBall->m_pLauncher = pLauncher;// remember what RPG fired me.
    pFireBall->pev->owner = pOwner->edict();
    pFireBall->pev->nextthink = gpGlobals->time;
    pFireBall->SetThink( &CFireBall::AnimateThink );
   
    return pFireBall;
}

void CFireBall :: TouchThink ( CBaseEntity *pOther )
{
    TraceResult tr;

    if ( !pOther->pev->takedamage )
    {
        return;
    }
    else
    {
        return;
    }
        //if ( pOther->pev->health <= 0 )
        //    return;
        //pOther->TakeDamage ( pev, pev, gSkillData.plrDmgFlame, DMG_BURN );
        //Boom();
    SetThink ( &CBaseEntity::SUB_Remove );
    pev->nextthink = gpGlobals->time;
}
#endif

//=========================================================
// Flamethrower
//=========================================================

LINK_ENTITY_TO_CLASS( weapon_flamethrower, CFlamethrower );

void CFlamethrower::Spawn( )
{
    //pev->classname = MAKE_STRING("weapon_flamethrower"); // hack to allow for old names
    Precache( );
    m_iId = WEAPON_FLAMETHROWER;
    SET_MODEL(ENT(pev), "models/w_flamethrower.mdl");

    m_iDefaultAmmo = FLAMETHROWER_DEFAULT_GIVE;

    FallInit();// get ready to fall down.
}

void CFlamethrower::Precache( void )
{
    PRECACHE_MODEL("models/v_flamethrower.mdl");
    PRECACHE_MODEL("models/w_flamethrower.mdl");
    PRECACHE_MODEL("models/p_flamethrower.mdl");

    PRECACHE_MODEL("sprites/flame_idle.spr");

    PRECACHE_MODEL( FIRE_BEAM_SPRITE );
   
    PRECACHE_SOUND("items/9mmclip1.wav"); 

    UTIL_PrecacheOther( "ft_fireball" );

    PRECACHE_SOUND ("weapons/357_cock1.wav");

    m_usThrowerFire = PRECACHE_EVENT( 1, "events/thrower_start.sc" );
    m_usThrowerStop = PRECACHE_EVENT( 1, "events/thrower_stop.sc" );
    m_usThrowerFlame = PRECACHE_EVENT( 1, "events/thrower_flame.sc" );
}

int CFlamethrower::GetItemInfo(ItemInfo *p)
{
    p->pszName = STRING(pev->classname);
    p->pszAmmo1 = "uranium";
    p->iMaxAmmo1 = URANIUM_MAX_CARRY;
    p->pszAmmo2 = NULL;
    p->iMaxAmmo2 = -1;
    p->iMaxClip = WEAPON_NOCLIP;
    p->iSlot = 5;
    p->iPosition = 1;
    p->iId = m_iId = WEAPON_FLAMETHROWER;
    p->iFlags = 0;
    p->iWeight = FLAMETHROWER_WEIGHT;

    return 1;
}

int CFlamethrower::AddToPlayer( CBasePlayer *pPlayer )
{
    if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) )
    {
        MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev );
            WRITE_BYTE( m_iId );
        MESSAGE_END();
        return TRUE;
    }
    return FALSE;
}

BOOL CFlamethrower::Deploy( )
{
    return DefaultDeploy( "models/v_flamethrower.mdl", "models/p_flamethrower.mdl", FLAME_DRAW, "shotgun" );   
}

void CFlamethrower::Holster( int skiplocal /* = 0 */ )
{
    m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 16/30;
    SendWeaponAnim( FLAME_HOLSTER );
}
void CFlamethrower::PrimaryAttack()
{
    // don't fire underwater
    if (m_pPlayer->pev->waterlevel == 3)
    {
        PlayEmptySound( );
        m_flNextPrimaryAttack = 0.15;
        return;
    }

    int flags;
#if defined( CLIENT_WEAPONS )
    flags = FEV_NOTHOST;
#else
    flags = 0;
#endif

    if ( m_iStartThrow == 1 )
    {
        if ( gpGlobals->time - m_flThrowTime >= 0.2 )
        {
            Throw();
        }
        else
        {
            //StartThrow();
            Throw();
            //m_iFlameRange = m_iFlameRange + 12;
        }
    }
    else
    {
        //StartThrow();
        Throw();
        m_flThrowTime = gpGlobals->time;
        m_iStartThrow = 1;
        m_iThrowCount = 0;
        //m_iFlameRange = m_iFlameRange + 12;
    }

    m_flTimeWeaponIdle = m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.03;
}

void CFlamethrower::StartThrow()
{
#ifndef CLIENT_DLL
    ALERT ( at_console, "start throwing \n" );
#endif
}

void CFlamethrower::Throw()
{
    float degree = 0.03;
    Vector vecAiming = gpGlobals->v_forward;
    Vector vecDir = gpGlobals->v_forward + Vector( RANDOM_FLOAT( -degree, degree ), RANDOM_FLOAT( -degree, degree ), RANDOM_FLOAT( -degree, degree ) );

    if ( m_iStartThrow == 0  && m_iFlameRange != 38 )
        m_iFlameRange = 38;

    UTIL_MakeVectors( m_pPlayer->pev->v_angle );

    //m_pPlayer->    // if player crouched??
    Vector vecSrc = m_pPlayer->GetGunPosition( ) + gpGlobals->v_right * 4 + gpGlobals->v_up * -8; // + gpGlobals->v_up * -9; //+ gpGlobals->v_forward * 32

    TraceResult tr;
    UTIL_TraceLine ( vecSrc, vecSrc + vecAiming * m_iFlameRange, dont_ignore_monsters, ENT(m_pPlayer->pev), &tr );

#ifndef CLIENT_DLL
    ALERT ( at_console, "throwing \n" );
    CFireBall *pFireBall = CFireBall::CreateFireBall( tr.vecEndPos, m_pPlayer->pev->v_angle, m_pPlayer, this );//+ gpGlobals->v_right * RANDOM_FLOAT(-5,5) + gpGlobals->v_up * RANDOM_FLOAT(-5,5)

    UTIL_MakeVectors( m_pPlayer->pev->v_angle );// RpgRocket::Create stomps on globals, so remake.
    //pRocket->pev->velocity = pRocket->pev->velocity + gpGlobals->v_forward * DotProduct( m_pPlayer->pev->velocity, gpGlobals->v_forward );
    pFireBall->pev->velocity = ( vecDir * RANDOM_FLOAT( 600, 750) ) + ( gpGlobals->v_forward * DotProduct( m_pPlayer->pev->velocity, gpGlobals->v_forward ) ); //throw direction + random speed + speed of player
#endif
}

void CFlamethrower::StopThrow()
{
#ifndef CLIENT_DLL
    ALERT ( at_console, "stop throwing \n" );
#endif

    m_flThrowTime = 0;
    m_iStartThrow = 0;
    m_iThrowCount = 0;
}

void CFlamethrower::WeaponIdle( void )
{
    ResetEmptySound( );

    m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );

    if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
        return;
   
    if ( m_iStartThrow == 1 )
    {
        StopThrow();
    }

    int iAnim;
    switch ( RANDOM_LONG( 0, 1 ) )
    {
    case 0:   
        iAnim = FLAME_IDLE1;   
        break;
                           
    default:
    case 1:
        iAnim = FLAME_IDLE1;
        break;
    }
   
    SendWeaponAnim( iAnim );
}

Post a Comment
click to sign in

You are not logged in, your comment will be anonymous unless you join the community today (totally free - or sign in with your social account on the right) which we encourage all contributors to do.

2000 characters limit; HTML formatting and smileys are not supported - text only

Level
88%
Gamer
7
Avatar
Avatar
Offline Since
Jul 30, 2014
Country
Germany Germany
Gender
Male
Member Watch
Track this member
Blog
Browse
Blogs
Views
40 (1 today)
Report Abuse
Report article