This member has provided no bio about themself...

Blog RSS Feed Report abuse ScrGold/Coding: func_pushable speeds up player

0 comments by PanSartre on Jun 9th, 2013

Here is the Problem: If the player "uses" ( push USE-Key) on a func_pushable, he can speed up himself by strafing or he can push it very fast away ignoring friction of the entity. Here is my fix. New/changed entries are pink.

Open func_break.cpp and go to CPushable::Move:

void CPushable :: Move( CBaseEntity *pOther, int push )
{
entvars_t* pevToucher = pOther->pev;
int playerTouch = 0;

// Is entity standing on this pushable ?
if ( FBitSet(pevToucher->flags,FL_ONGROUND) && pevToucher->groundentity && VARS(pevToucher->groundentity) == pev )
{
// Only push if floating
if ( pev->waterlevel > 0 )
pev->velocity.z += pevToucher->velocity.z * 0.1;

return;
}

if ( pOther->IsPlayer() )
{
if ( push && !(pevToucher->button & (IN_FORWARD|IN_USE)) ) // Don't push unless the player is pushing forward and NOT use (pull)
return;
playerTouch = 1;
}

float factor;

if ( playerTouch )
{
if ( !(pevToucher->flags & FL_ONGROUND) ) // Don't push away from jumping/falling players unless in water
{
if ( pev->waterlevel < 1 )
return;
else
factor = 0.1;
}
else
factor = 1;
}
else
factor = 0.25;

pev->velocity.x += pevToucher->velocity.x * factor;
pev->velocity.y += pevToucher->velocity.y * factor;

float length = sqrt( pev->velocity.x * pev->velocity.x + pev->velocity.y * pev->velocity.y );

if ( length > MaxSpeed() ) //if ( push && (length > MaxSpeed()) ) <- this is the old entry. why no fricition (maxspeed) if player uses ( means "push = 0" ) the func_pushable? delete this!
{
pev->velocity.x = (pev->velocity.x * MaxSpeed() / length );
pev->velocity.y = (pev->velocity.y * MaxSpeed() / length );
}

if ( playerTouch )
{
if ( pevToucher->button & IN_FORWARD ) //we need this! without the entity doesnt stop when player halts. no player movement = no entity movement.
{
pevToucher->velocity.x = pev->velocity.x;
pevToucher->velocity.y = pev->velocity.y;
}

if ( (gpGlobals->time - m_soundTime) > 0.7 )
{
m_soundTime = gpGlobals->time;
if ( length > 0 && FBitSet(pev->flags,FL_ONGROUND) )
{
m_lastSound = RANDOM_LONG(0,2);
EMIT_SOUND(ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound], 0.5, ATTN_NORM);
// SetThink( StopSound );
// pev->nextthink = pev->ltime + 0.1;
}
else
STOP_SOUND( ENT(pev), CHAN_WEAPON, m_soundNames[m_lastSound] );
}
}
}

Report abuse ScrGold/Coding: water+trigger_push = impossible?

0 comments by PanSartre on Apr 20th, 2013

Do you know this problem? Since a previous HL update (1.1.1.0 ? in times of WON) it isn't possible to push the player underwater. The combination of func_water and trigger_push didn't work anymore. Consequently original maps like c2a4b or c2a5 are missing the nice streaming effect of the old shipped version from 1998. Interestingly it still works in Opposing Force, Blue Shift and Uplink.
At the moment I am working on this problem and I already have a solution which isn't perfect. New/changed entries are pink.

Open pm_shared.c and go to PM_WaterMove:

void PM_WaterMove (void)
{
int i;
vec3_t wishvel;
float wishspeed;
vec3_t wishdir;
vec3_t start, dest;
vec3_t temp;
pmtrace_t trace;

float speed, newspeed, addspeed, accelspeed;

vec3_t basevec;
float basevel;

//
// user intentions
//

VectorCopy (pmove->basevelocity, basevec);
basevel = VectorNormalize(basevec);

for (i=0 ; i<3 ; i++)
{
wishvel[i]= pmove->forward[i]*pmove->cmd.forwardmove + pmove->right[i]*pmove->cmd.sidemove;
}

// Sinking after no other movement occurs
if (!pmove->cmd.forwardmove && !pmove->cmd.sidemove && !pmove->cmd.upmove && !basevel) //no sinking if there is basevelocity (e.g. trigger_push)
wishvel[2] -= 60; // drift towards bottom
else // Go straight up by upmove amount.
wishvel[2] += pmove->cmd.upmove;

// Copy it over and determine speed
VectorCopy (wishvel, wishdir);
wishspeed = VectorNormalize(wishdir);

// Cap speed.
if (wishspeed > pmove->maxspeed)
{
VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel);
wishspeed = pmove->maxspeed;
}
// Slow us down a bit.
wishspeed *= 0.8;

//VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity); //entry moved. you can even delete it
//Water friction
VectorCopy(pmove->velocity, temp);
speed = VectorNormalize(temp);
if (speed)
{
newspeed = speed - pmove->frametime * speed * pmove->movevars->friction * pmove->friction;

if (newspeed < 0.1f)
newspeed = 0;
VectorScale (pmove->velocity, newspeed/speed, pmove->velocity);
}
else
newspeed = 0;

//
// water acceleration
//
if (wishspeed >= 0.1f)
{
addspeed = wishspeed - newspeed;
if (addspeed > 0)
{

VectorNormalize(wishvel);
accelspeed = pmove->movevars->accelerate * wishspeed * pmove->frametime * pmove->friction;
if (accelspeed > addspeed)
accelspeed = addspeed;

for (i = 0; i < 3; i++)
{
pmove->velocity[i]+= accelspeed * wishvel[i];
//float deltaSpeed = accelspeed * wishvel[i];
//pmove->velocity[i]+= deltaSpeed;
//wishvel[i]+= deltaSpeed;
}

}
}
// HACKHACK: to reduce water pushspeed and imitate original waterfriction scale basevelocity; this solve the water + trigger_push bug
VectorScale (pmove->basevelocity, 0.30, pmove->basevelocity);
VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity);

// Now move
// assume it is a stair or a slope, so press down from stepheight above
VectorMA (pmove->origin, pmove->frametime, pmove->velocity, dest);
VectorCopy (dest, start);
start[2] += pmove->movevars->stepsize + 1;
trace = pmove->PM_PlayerTrace (start, dest, PM_NORMAL, -1 );
if (!trace.startsolid && !trace.allsolid) // FIXME: check steep slope?
{ // walked up the step, so just keep result and exit
VectorCopy (trace.endpos, pmove->origin);
return;
}

// Try moving straight along out normal path.
PM_FlyMove ();
}

Report abuse ScrGold/Coding: view acceleration for trigger_camera

0 comments by PanSartre on Apr 15th, 2013

You want to script a nice camera intro in HL but the rotating speed is too slow? Here is the easy way to set the view acceleration for trigger_camera in hammer by adding a new variable in the SDK. (new entries are bold)

Open triggers.cpp and introduce a new variable like this:
[...]
float m_acceleration;
float m_deceleration;
float m_viewacceleration;
int m_state;
[...]

The game should be able to save the new variable:
[...]
DEFINE_FIELD( CTriggerCamera, m_acceleration, FIELD_FLOAT ),
DEFINE_FIELD( CTriggerCamera, m_deceleration, FIELD_FLOAT ),
DEFINE_FIELD( CTriggerCamera, m_viewacceleration, FIELD_FLOAT ),
DEFINE_FIELD( CTriggerCamera, m_state, FIELD_INTEGER ),
[...]

Add a new keyvalue (for hammer):
[...]
else if (FStrEq(pkvd->szKeyName, "deceleration"))
{
m_deceleration = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "viewacceleration"))
{
m_viewacceleration = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}

else

CBaseDelay::KeyValue( pkvd );
[...]

Go to the spawn function and add this:
[...]
if ( m_acceleration == 0 )
m_acceleration = 500;
if ( m_deceleration == 0 )
m_deceleration = 500;
if ( m_viewacceleration == 0 )
m_viewacceleration = 40;

}
[...]


Here comes the importent part in function CTriggerCamera::FollowTarget( ). Go to:
pev->avelocity.x = dx * 40 * gpGlobals->frametime;
pev->avelocity.y = dy * 40 * gpGlobals->frametime;
and change it to:
pev->avelocity.x = dx * m_viewacceleration * gpGlobals->frametime;
pev->avelocity.y = dy * m_viewacceleration * gpGlobals->frametime;

At least add the new keyvalue in your fdg-file at the trigger_camera entity:

[...]
speed(string) : "Initial Speed" : "0"
acceleration(string) : "Acceleration units/sec^2" : "500"
deceleration(string) : "Stop Deceleration units/sec^2" : "500"
viewacceleration(string) : "View Acceleration" : "40"
[...]

That's it!

Here is my example:

with default value:

Report abuse ScrGold/Coding: no reset between scripted_sequences

0 comments by PanSartre on Apr 2nd, 2013

Maybe some mappers already had the problem working on a nice scripted sequence and at one point realizing there is no possibility to put a monster in a idle-animation by a trigger. After the levelstart the monster plays the Idle Animation of the scripted_sequence only until it is triggered. The only way to fake a triggerable idle-animation is to enter the name of the animation in the field Action Animation and retrigger the scripted_sequence as long as it is needed. Short: creating a loop with scripted_sequence. But the next unsightly effect is after each scripted_sequence the monster going back in is default-Activity (mostly ACT_IDLE). So if you have a monster lying on the floor it "stands up" after the animation is done before it restart the animation. This happens because the monsters activity is reseted after the last frame of the animation. Opposing Force and Sven Coop already create soluation for fluent transitions between scripted_sequences with a new Entity-Flag: No Reset Entity. I don't know how they do it but here is my way (new entries are bold)

Create a new flag in scripted.h:
[...]
#define SF_SCRIPT_NOINTERRUPT 32
#define SF_SCRIPT_OVERRIDESTATE 64
#define SF_SCRIPT_NOSCRIPTMOVEMENT 128
#define SF_SCRIPT_NORESET 256
[...]

->by the way, now its compatible with Opfor/SC

Open the scripted.cpp and go to the function CCineMonster :: SequenceDone

[...]
pMonster->CineCleanup( );

if ( !( pev->spawnflags & SF_SCRIPT_NORESET ) )
FixScriptMonsterSchedule( pMonster );
[...]

->so the schedule will only fixed if flag NORESET is NOT selected

Go to the function BOOL CBaseMonster :: CineCleanup( )
[...]
if ( !( pOldCine->pev->spawnflags & SF_SCRIPT_NORESET ) )
m_Activity = ACT_RESET;

[...]

At least you only have to edit the scripted_sequence in your fgd-file for hammer:
[...]
spawnflags(Flags) =
[
4 : "Repeatable" : 0
8 : "Leave Corpse" : 0
32: "No Interruptions" : 0
64: "Override AI" : 0
128: "No Script Movement" : 0
256: "No Reset" : 0
]
[...]

Thats all! Maybe it could be buggy if the last scripted_sequence to exit a loop is flaged with NORESET. Try it and send me your report.

Report abuse ScrGold/Coding: HL1 Flamethrower Experiement

0 comments 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 );
}

Level
93%
Gamer
7
Avatar
Avatar
Offline Since
Aug 15, 2014
Country
Germany Germany
Gender
Male
Member Watch
Track this member
Blog Statistics
Articles
5
Views
383
Views Today
2