Upload reverse-engineered Azure Sheep source code.

This commit is contained in:
Night Owl 2018-01-13 01:47:39 +05:00
parent 4078ca6ad8
commit 888483b5c4
92 changed files with 5509 additions and 10643 deletions

View File

@ -24,25 +24,11 @@ LOCAL_CFLAGS += -DCLIENT_DLL=1
SRCS=
SRCS_C=
SRCS+=../dlls/crossbow.cpp
SRCS+=../dlls/crowbar.cpp
SRCS+=../dlls/egon.cpp
SRCS+=./ev_hldm.cpp
SRCS+=../dlls/gauss.cpp
SRCS+=../dlls/handgrenade.cpp
SRCS+=./hl/hl_baseentity.cpp
SRCS+=./hl/hl_events.cpp
SRCS+=./hl/hl_objects.cpp
SRCS+=./hl/hl_weapons.cpp
SRCS+=../dlls/hornetgun.cpp
SRCS+=../dlls/mp5.cpp
SRCS+=../dlls/python.cpp
SRCS+=../dlls/rpg.cpp
SRCS+=../dlls/satchel.cpp
SRCS+=../dlls/shotgun.cpp
SRCS+=../dlls/squeakgrenade.cpp
SRCS+=../dlls/tripmine.cpp
SRCS+=../dlls/glock.cpp
#SRCS+=../game_shared/voice_banmgr.cpp
#SRCS+=../game_shared/voice_status.cpp
SRCS+=./ammo.cpp
@ -92,7 +78,7 @@ SRCS+=./input_xash3d.cpp
SRCS+=./scoreboard.cpp
SRCS+=./MOTD.cpp
INCLUDES = -I../common -I. -I../game_shared -I../pm_shared -I../engine -I../dlls -I../utils/false_vgui/include
DEFINES = -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w
DEFINES = -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -DCLIENT_DLL -w
LOCAL_C_INCLUDES := $(LOCAL_PATH)/. \
$(LOCAL_PATH)/../common \

View File

@ -25,31 +25,13 @@ project (CLDLL)
set (CLDLL_LIBRARY client)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_WEAPONS -DCLIENT_DLL -w")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-write-strings -DLINUX -D_LINUX -Dstricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -DCLIENT_DLL -w")
if (GOLDSOURCE_SUPPORT)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGOLDSOURCE_SUPPORT")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}")
set (CLDLL_SOURCES
../dlls/crossbow.cpp
../dlls/crowbar.cpp
../dlls/egon.cpp
../dlls/gauss.cpp
../dlls/handgrenade.cpp
../dlls/hornetgun.cpp
../dlls/mp5.cpp
../dlls/python.cpp
../dlls/rpg.cpp
../dlls/satchel.cpp
../dlls/shotgun.cpp
../dlls/squeakgrenade.cpp
../dlls/tripmine.cpp
../dlls/glock.cpp
../dlls/asheep/beretta.cpp
../dlls/asheep/m41a.cpp
../dlls/asheep/poolstick.cpp
../dlls/asheep/toad.cpp
ev_hldm.cpp
hl/hl_baseentity.cpp
hl/hl_events.cpp

View File

@ -20,7 +20,7 @@
#define AMMOHISTORY_H
// this is the max number of items in each bucket
#define MAX_WEAPON_POSITIONS MAX_WEAPON_SLOTS
#define MAX_WEAPON_POSITIONS MAX_WEAPON_SLOTS + 1
class WeaponsResource
{

View File

@ -55,19 +55,9 @@ void EV_FireGlock2( struct event_args_s *args );
void EV_FireShotGunSingle( struct event_args_s *args );
void EV_FireShotGunDouble( struct event_args_s *args );
void EV_FireMP5( struct event_args_s *args );
void EV_FireMP52( struct event_args_s *args );
void EV_FirePython( struct event_args_s *args );
void EV_FireGauss( struct event_args_s *args );
void EV_SpinGauss( struct event_args_s *args );
void EV_Crowbar( struct event_args_s *args );
void EV_FireCrossbow( struct event_args_s *args );
void EV_FireCrossbow2( struct event_args_s *args );
void EV_FireRpg( struct event_args_s *args );
void EV_EgonFire( struct event_args_s *args );
void EV_EgonStop( struct event_args_s *args );
void EV_HornetGunFire( struct event_args_s *args );
void EV_TripmineFire( struct event_args_s *args );
void EV_SnarkFire( struct event_args_s *args );
//Begin Alex
void EV_FireM41A( struct event_args_s *args );
@ -402,28 +392,16 @@ void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int
vec3_t vecDir, vecEnd;
float x, y, z;
//We randomize for the Shotgun.
if( iBulletType == BULLET_PLAYER_BUCKSHOT )
{
do{
x = gEngfuncs.pfnRandomFloat( -0.5, 0.5 ) + gEngfuncs.pfnRandomFloat( -0.5, 0.5 );
y = gEngfuncs.pfnRandomFloat( -0.5, 0.5 ) + gEngfuncs.pfnRandomFloat( -0.5, 0.5 );
z = x * x + y * y;
}while( z > 1 );
do{
x = gEngfuncs.pfnRandomFloat( -0.5, 0.5 ) + gEngfuncs.pfnRandomFloat( -0.5, 0.5 );
y = gEngfuncs.pfnRandomFloat( -0.5, 0.5 ) + gEngfuncs.pfnRandomFloat( -0.5, 0.5 );
z = x * x + y * y;
}while( z > 1 );
for( i = 0 ; i < 3; i++ )
{
vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[i] + y * flSpreadY * up [i];
vecEnd[i] = vecSrc[i] + flDistance * vecDir[i];
}
}//But other guns already have their spread randomized in the synched spread.
else
for( i = 0 ; i < 3; i++ )
{
for( i = 0 ; i < 3; i++ )
{
vecDir[i] = vecDirShooting[i] + flSpreadX * right[i] + flSpreadY * up [i];
vecEnd[i] = vecSrc[i] + flDistance * vecDir[i];
}
vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[i] + y * flSpreadY * up [i];
vecEnd[i] = vecSrc[i] + flDistance * vecDir[i];
}
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true );
@ -746,32 +724,6 @@ void EV_FireMP5( event_args_t *args )
}
}
// We only predict the animation and sound
// The grenade is still launched from the server.
void EV_FireMP52( event_args_t *args )
{
int idx;
vec3_t origin;
idx = args->entindex;
VectorCopy( args->origin, origin );
if( EV_IsLocal( idx ) )
{
gEngfuncs.pEventAPI->EV_WeaponAnimation( MP5_LAUNCH, 2 );
V_PunchAxis( 0, -10 );
}
switch( gEngfuncs.pfnRandomLong( 0, 1 ) )
{
case 0:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/glauncher.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) );
break;
case 1:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/glauncher2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) );
break;
}
}
//======================
// MP5 END
//======================
@ -1144,571 +1096,6 @@ void EV_FireGauss( event_args_t *args )
// GAUSS END
//======================
//======================
// CROWBAR START
//======================
enum crowbar_e
{
CROWBAR_IDLE = 0,
CROWBAR_DRAW,
CROWBAR_HOLSTER,
CROWBAR_ATTACK1HIT,
CROWBAR_ATTACK1MISS,
CROWBAR_ATTACK2MISS,
CROWBAR_ATTACK2HIT,
CROWBAR_ATTACK3MISS,
#ifndef CROWBAR_IDLE_ANIM
CROWBAR_ATTACK3HIT
#else
CROWBAR_ATTACK3HIT,
CROWBAR_IDLE2,
CROWBAR_IDLE3
#endif
};
int g_iSwing;
//Only predict the miss sounds, hit sounds are still played
//server side, so players don't get the wrong idea.
void EV_Crowbar( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
idx = args->entindex;
VectorCopy( args->origin, origin );
//Play Swing sound
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, PITCH_NORM );
if( EV_IsLocal( idx ) )
{
switch( (g_iSwing++) % 3 )
{
case 0:
gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK1MISS, 1 );
break;
case 1:
gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK2MISS, 1 );
break;
case 2:
gEngfuncs.pEventAPI->EV_WeaponAnimation( CROWBAR_ATTACK3MISS, 1 );
break;
}
}
}
//======================
// CROWBAR END
//======================
//======================
// CROSSBOW START
//======================
enum crossbow_e
{
CROSSBOW_IDLE1 = 0, // full
CROSSBOW_IDLE2, // empty
CROSSBOW_FIDGET1, // full
CROSSBOW_FIDGET2, // empty
CROSSBOW_FIRE1, // full
CROSSBOW_FIRE2, // reload
CROSSBOW_FIRE3, // empty
CROSSBOW_RELOAD, // from empty
CROSSBOW_DRAW1, // full
CROSSBOW_DRAW2, // empty
CROSSBOW_HOLSTER1, // full
CROSSBOW_HOLSTER2 // empty
};
//=====================
// EV_BoltCallback
// This function is used to correct the origin and angles
// of the bolt, so it looks like it's stuck on the wall.
//=====================
void EV_BoltCallback( struct tempent_s *ent, float frametime, float currenttime )
{
ent->entity.origin = ent->entity.baseline.vuser1;
ent->entity.angles = ent->entity.baseline.vuser2;
}
void EV_FireCrossbow2( event_args_t *args )
{
vec3_t vecSrc, vecEnd;
vec3_t up, right, forward;
pmtrace_t tr;
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
EV_GetGunPosition( args, vecSrc, origin );
VectorMA( vecSrc, 8192, forward, vecEnd );
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0xF ) );
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat( 0.95, 1.0 ), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0xF ) );
if( EV_IsLocal( idx ) )
{
if( args->iparam1 )
gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 );
else if( args->iparam2 )
gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 );
}
// Store off the old count
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr );
//We hit something
if( tr.fraction < 1.0 )
{
physent_t *pe = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent );
//Not the world, let's assume we hit something organic ( dog, cat, uncle joe, etc ).
if( pe->solid != SOLID_BSP )
{
switch( gEngfuncs.pfnRandomLong( 0, 1 ) )
{
case 0:
gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod1.wav", 1, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
gEngfuncs.pEventAPI->EV_PlaySound( idx, tr.endpos, CHAN_BODY, "weapons/xbow_hitbod2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
break;
}
}
//Stick to world but don't stick to glass, it might break and leave the bolt floating. It can still stick to other non-transparent breakables though.
else if( pe->rendermode == kRenderNormal )
{
gEngfuncs.pEventAPI->EV_PlaySound( 0, tr.endpos, CHAN_BODY, "weapons/xbow_hit1.wav", gEngfuncs.pfnRandomFloat( 0.95, 1.0 ), ATTN_NORM, 0, PITCH_NORM );
//Not underwater, do some sparks...
if( gEngfuncs.PM_PointContents( tr.endpos, NULL ) != CONTENTS_WATER )
gEngfuncs.pEfxAPI->R_SparkShower( tr.endpos );
vec3_t vBoltAngles;
int iModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/crossbow_bolt.mdl" );
VectorAngles( forward, vBoltAngles );
TEMPENTITY *bolt = gEngfuncs.pEfxAPI->R_TempModel( tr.endpos - forward * 10, Vector( 0, 0, 0 ), vBoltAngles , 5, iModelIndex, TE_BOUNCE_NULL );
if( bolt )
{
bolt->flags |= ( FTENT_CLIENTCUSTOM ); //So it calls the callback function.
bolt->entity.baseline.vuser1 = tr.endpos - forward * 10; // Pull out a little bit
bolt->entity.baseline.vuser2 = vBoltAngles; //Look forward!
bolt->callback = EV_BoltCallback; //So we can set the angles and origin back. (Stick the bolt to the wall)
}
}
}
gEngfuncs.pEventAPI->EV_PopPMStates();
}
//TODO: Fully predict the fliying bolt.
void EV_FireCrossbow( event_args_t *args )
{
int idx;
vec3_t origin;
idx = args->entindex;
VectorCopy( args->origin, origin );
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0xF ) );
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat( 0.95, 1.0 ), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0xF ) );
//Only play the weapon anims if I shot it.
if( EV_IsLocal( idx ) )
{
if( args->iparam1 )
gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE1, 1 );
else if ( args->iparam2 )
gEngfuncs.pEventAPI->EV_WeaponAnimation( CROSSBOW_FIRE3, 1 );
V_PunchAxis( 0, -2.0 );
}
}
//======================
// CROSSBOW END
//======================
//======================
// RPG START
//======================
enum rpg_e
{
RPG_IDLE = 0,
RPG_FIDGET,
RPG_RELOAD, // to reload
RPG_FIRE2, // to empty
RPG_HOLSTER1, // loaded
RPG_DRAW1, // loaded
RPG_HOLSTER2, // unloaded
RPG_DRAW_UL, // unloaded
RPG_IDLE_UL, // unloaded idle
RPG_FIDGET_UL // unloaded fidget
};
void EV_FireRpg( event_args_t *args )
{
int idx;
vec3_t origin;
idx = args->entindex;
VectorCopy( args->origin, origin );
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/rocketfire1.wav", 0.9, ATTN_NORM, 0, PITCH_NORM );
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/glauncher.wav", 0.7, ATTN_NORM, 0, PITCH_NORM );
//Only play the weapon anims if I shot it.
if( EV_IsLocal( idx ) )
{
gEngfuncs.pEventAPI->EV_WeaponAnimation( RPG_FIRE2, 1 );
V_PunchAxis( 0, -5.0 );
}
}
//======================
// RPG END
//======================
//======================
// EGON END
//======================
enum egon_e
{
EGON_IDLE1 = 0,
EGON_FIDGET1,
EGON_ALTFIREON,
EGON_ALTFIRECYCLE,
EGON_ALTFIREOFF,
EGON_FIRE1,
EGON_FIRE2,
EGON_FIRE3,
EGON_FIRE4,
EGON_DRAW,
EGON_HOLSTER
};
int g_fireAnims1[] = { EGON_FIRE1, EGON_FIRE2, EGON_FIRE3, EGON_FIRE4 };
int g_fireAnims2[] = { EGON_ALTFIRECYCLE };
enum EGON_FIRESTATE
{
FIRE_OFF,
FIRE_CHARGE
};
enum EGON_FIREMODE
{
FIRE_NARROW,
FIRE_WIDE
};
#define EGON_PRIMARY_VOLUME 450
#define EGON_BEAM_SPRITE "sprites/xbeam1.spr"
#define EGON_FLARE_SPRITE "sprites/XSpark1.spr"
#define EGON_SOUND_OFF "weapons/egon_off1.wav"
#define EGON_SOUND_RUN "weapons/egon_run3.wav"
#define EGON_SOUND_STARTUP "weapons/egon_windup2.wav"
#define ARRAYSIZE(p) ( sizeof(p) /sizeof(p[0]) )
BEAM *pBeam;
BEAM *pBeam2;
void EV_EgonFire( event_args_t *args )
{
int idx, /*iFireState,*/ iFireMode;
vec3_t origin;
idx = args->entindex;
VectorCopy( args->origin, origin );
//iFireState = args->iparam1;
iFireMode = args->iparam2;
int iStartup = args->bparam1;
if( iStartup )
{
if( iFireMode == FIRE_WIDE )
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.98, ATTN_NORM, 0, 125 );
else
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.9, ATTN_NORM, 0, 100 );
}
else
{
// If there is any sound playing already, kill it. - Solokiller
// This is necessary because multiple sounds can play on the same channel at the same time.
// In some cases, more than 1 run sound plays when the egon stops firing, in which case only the earliest entry in the list is stopped.
// This ensures no more than 1 of those is ever active at the same time.
gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EGON_SOUND_RUN );
if( iFireMode == FIRE_WIDE )
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 );
else
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.9, ATTN_NORM, 0, 100 );
}
//Only play the weapon anims if I shot it.
if( EV_IsLocal( idx ) )
gEngfuncs.pEventAPI->EV_WeaponAnimation( g_fireAnims1[gEngfuncs.pfnRandomLong( 0, 3 )], 1 );
if( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 && cl_lw->value ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction.
{
vec3_t vecSrc, vecEnd, angles, forward, right, up;
pmtrace_t tr;
cl_entity_t *pl = gEngfuncs.GetEntityByIndex( idx );
if( pl )
{
VectorCopy( gHUD.m_vecAngles, angles );
AngleVectors( angles, forward, right, up );
EV_GetGunPosition( args, vecSrc, pl->origin );
VectorMA( vecSrc, 2048, forward, vecEnd );
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true );
// Store off the old count
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr );
gEngfuncs.pEventAPI->EV_PopPMStates();
int iBeamModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( EGON_BEAM_SPRITE );
float r = 50.0f;
float g = 50.0f;
float b = 125.0f;
if( IEngineStudio.IsHardware() )
{
r /= 100.0f;
g /= 100.0f;
}
pBeam = gEngfuncs.pEfxAPI->R_BeamEntPoint( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 3.5, 0.2, 0.7, 55, 0, 0, r, g, b );
if( pBeam )
pBeam->flags |= ( FBEAM_SINENOISE );
pBeam2 = gEngfuncs.pEfxAPI->R_BeamEntPoint( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 5.0, 0.08, 0.7, 25, 0, 0, r, g, b );
}
}
}
void EV_EgonStop( event_args_t *args )
{
int idx;
vec3_t origin;
idx = args->entindex;
VectorCopy( args->origin, origin );
gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EGON_SOUND_RUN );
if( args->iparam1 )
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_OFF, 0.98, ATTN_NORM, 0, 100 );
if( EV_IsLocal( idx ) )
{
if( pBeam )
{
pBeam->die = 0.0;
pBeam = NULL;
}
if( pBeam2 )
{
pBeam2->die = 0.0;
pBeam2 = NULL;
}
}
}
//======================
// EGON END
//======================
//======================
// HORNET START
//======================
enum hgun_e
{
HGUN_IDLE1 = 0,
HGUN_FIDGETSWAY,
HGUN_FIDGETSHAKE,
HGUN_DOWN,
HGUN_UP,
HGUN_SHOOT
};
void EV_HornetGunFire( event_args_t *args )
{
int idx; //, iFireMode;
vec3_t origin, angles, vecSrc, forward, right, up;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
//iFireMode = args->iparam1;
//Only play the weapon anims if I shot it.
if( EV_IsLocal( idx ) )
{
V_PunchAxis( 0, gEngfuncs.pfnRandomLong( 0, 2 ) );
gEngfuncs.pEventAPI->EV_WeaponAnimation( HGUN_SHOOT, 1 );
}
switch( gEngfuncs.pfnRandomLong( 0, 2 ) )
{
case 0:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM, 0, 100 );
break;
case 1:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire2.wav", 1, ATTN_NORM, 0, 100 );
break;
case 2:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "agrunt/ag_fire3.wav", 1, ATTN_NORM, 0, 100 );
break;
}
}
//======================
// HORNET END
//======================
//======================
// TRIPMINE START
//======================
enum tripmine_e
{
TRIPMINE_IDLE1 = 0,
TRIPMINE_IDLE2,
TRIPMINE_ARM1,
TRIPMINE_ARM2,
TRIPMINE_FIDGET,
TRIPMINE_HOLSTER,
TRIPMINE_DRAW,
TRIPMINE_WORLD,
TRIPMINE_GROUND
};
//We only check if it's possible to put a trip mine
//and if it is, then we play the animation. Server still places it.
void EV_TripmineFire( event_args_t *args )
{
int idx;
vec3_t vecSrc, angles, view_ofs, forward;
pmtrace_t tr;
idx = args->entindex;
VectorCopy( args->origin, vecSrc );
VectorCopy( args->angles, angles );
AngleVectors( angles, forward, NULL, NULL );
if( !EV_IsLocal ( idx ) )
return;
// Grab predicted result for local player
gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs );
vecSrc = vecSrc + view_ofs;
// Store off the old count
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecSrc + forward * 128, PM_NORMAL, -1, &tr );
//Hit something solid
if( tr.fraction < 1.0 )
gEngfuncs.pEventAPI->EV_WeaponAnimation ( TRIPMINE_DRAW, 0 );
gEngfuncs.pEventAPI->EV_PopPMStates();
}
//======================
// TRIPMINE END
//======================
//======================
// SQUEAK START
//======================
enum squeak_e
{
SQUEAK_IDLE1 = 0,
SQUEAK_FIDGETFIT,
SQUEAK_FIDGETNIP,
SQUEAK_DOWN,
SQUEAK_UP,
SQUEAK_THROW
};
#define VEC_HULL_MIN Vector( -16, -16, -36 )
#define VEC_DUCK_HULL_MIN Vector( -16, -16, -18 )
void EV_SnarkFire( event_args_t *args )
{
int idx;
vec3_t vecSrc, angles, view_ofs, forward;
pmtrace_t tr;
idx = args->entindex;
VectorCopy( args->origin, vecSrc );
VectorCopy( args->angles, angles );
AngleVectors( angles, forward, NULL, NULL );
if( !EV_IsLocal ( idx ) )
return;
if( args->ducking )
vecSrc = vecSrc - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN );
// Store off the old count
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc + forward * 20, vecSrc + forward * 64, PM_NORMAL, -1, &tr );
//Find space to drop the thing.
if( tr.allsolid == 0 && tr.startsolid == 0 && tr.fraction > 0.25 )
gEngfuncs.pEventAPI->EV_WeaponAnimation( SQUEAK_THROW, 0 );
gEngfuncs.pEventAPI->EV_PopPMStates();
}
//======================
// SQUEAK END
//======================
void EV_TrainPitchAdjust( event_args_t *args )
{
int idx;
@ -1899,7 +1286,8 @@ enum m41a_e
M41A_DEPLOY,
M41A_FIRE1,
M41A_FIRE2,
//M41A_FIRE3,
M41A_FIRE3,
M41A_HOLSTER
};
void EV_FireM41A( event_args_t *args )
@ -1929,7 +1317,7 @@ void EV_FireM41A( event_args_t *args )
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( M41A_FIRE1 + gEngfuncs.pfnRandomLong( 0, 1 ), 2 );
gEngfuncs.pEventAPI->EV_WeaponAnimation( M41A_FIRE1 + gEngfuncs.pfnRandomLong( 0, 2 ), 2 );
V_PunchAxis( 0, gEngfuncs.pfnRandomFloat( -2, 2 ) );
}
@ -1938,15 +1326,7 @@ void EV_FireM41A( event_args_t *args )
EV_EjectBrass( ShellOrigin, ShellVelocity, angles[YAW], shell, TE_BOUNCE_SHELL );
switch( gEngfuncs.pfnRandomLong( 0, 1 ) )
{
case 0:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/m41ahks1.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) );
break;
case 1:
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/m41ahks2.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) );
break;
}
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/m41ahks1.wav", 1, ATTN_NORM, 0, 94 + gEngfuncs.pfnRandomLong( 0, 0xf ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );

View File

@ -231,7 +231,7 @@ int CHudHealth::Draw( float flTime )
int iHeight = gHUD.m_iFontHeight;
int iWidth = HealthWidth / 10;
FillRGBA( x, y, iWidth, iHeight, 255, 160, 0, a );
FillRGBA( x, y, iWidth, iHeight, r, g, b, a );
}
DrawDamage( flTime );

View File

@ -96,7 +96,7 @@ void CGrenade::Explode( TraceResult *, int ) { }
void CGrenade::Killed( entvars_t *, int ) { }
void CGrenade::Spawn( void ) { }
CGrenade *CGrenade::ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ){ return 0; }
CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ){ return 0; }
CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float flDmg ){ return 0; }
void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ){ }
void UTIL_Remove( CBaseEntity *pEntity ){ }

View File

@ -25,19 +25,9 @@ void EV_FireGlock2( struct event_args_s *args );
void EV_FireShotGunSingle( struct event_args_s *args );
void EV_FireShotGunDouble( struct event_args_s *args );
void EV_FireMP5( struct event_args_s *args );
void EV_FireMP52( struct event_args_s *args );
void EV_FirePython( struct event_args_s *args );
void EV_FireGauss( struct event_args_s *args );
void EV_SpinGauss( struct event_args_s *args );
void EV_Crowbar( struct event_args_s *args );
void EV_FireCrossbow( struct event_args_s *args );
void EV_FireCrossbow2( struct event_args_s *args );
void EV_FireRpg( struct event_args_s *args );
void EV_EgonFire( struct event_args_s *args );
void EV_EgonStop( struct event_args_s *args );
void EV_HornetGunFire( struct event_args_s *args );
void EV_TripmineFire( struct event_args_s *args );
void EV_SnarkFire( struct event_args_s *args );
void EV_TrainPitchAdjust( struct event_args_s *args );
@ -68,20 +58,10 @@ void Game_HookEvents( void )
gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle );
gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble );
gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 );
gEngfuncs.pfnHookEvent( "events/mp52.sc", EV_FireMP52 );
gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython );
gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss );
gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss );
gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust );
gEngfuncs.pfnHookEvent( "events/crowbar.sc", EV_Crowbar );
gEngfuncs.pfnHookEvent( "events/crossbow1.sc", EV_FireCrossbow );
gEngfuncs.pfnHookEvent( "events/crossbow2.sc", EV_FireCrossbow2 );
gEngfuncs.pfnHookEvent( "events/rpg.sc", EV_FireRpg );
gEngfuncs.pfnHookEvent( "events/egon_fire.sc", EV_EgonFire );
gEngfuncs.pfnHookEvent( "events/egon_stop.sc", EV_EgonStop );
gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire );
gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire );
gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire );
//begin Alex
gEngfuncs.pfnHookEvent( "events/m41a.sc", EV_FireM41A );
gEngfuncs.pfnHookEvent( "events/beretta1.sc", EV_FireBeretta1 );

View File

@ -27,54 +27,10 @@
#include "entity_types.h"
#include "r_efx.h"
extern BEAM *pBeam;
extern BEAM *pBeam2;
void HUD_GetLastOrg( float *org );
void UpdateBeams( void )
{
vec3_t forward, vecSrc, vecEnd, origin, angles, right, up;
vec3_t view_ofs;
pmtrace_t tr;
cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer();
int idx = pthisplayer->index;
// Get our exact viewangles from engine
gEngfuncs.GetViewAngles( (float *)angles );
// Determine our last predicted origin
HUD_GetLastOrg( (float *)&origin );
AngleVectors( angles, forward, right, up );
VectorCopy( origin, vecSrc );
VectorMA( vecSrc, 2048, forward, vecEnd );
gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true );
// Store off the old count
gEngfuncs.pEventAPI->EV_PushPMStates();
// Now add in all of the players.
gEngfuncs.pEventAPI->EV_SetSolidPlayers( idx - 1 );
gEngfuncs.pEventAPI->EV_SetTraceHull( 2 );
gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr );
gEngfuncs.pEventAPI->EV_PopPMStates();
if( pBeam )
{
pBeam->target = tr.endpos;
pBeam->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case.
}
if( pBeam2 )
{
pBeam2->target = tr.endpos;
pBeam2->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case.
}
}
/*
@ -86,6 +42,4 @@ Add game specific, client-side objects here
*/
void Game_AddObjects( void )
{
if( pBeam && pBeam2 )
UpdateBeams();
}

View File

@ -52,28 +52,6 @@ int g_irunninggausspred = 0;
vec3_t previousorigin;
// HLDM Weapon placeholder entities.
CGlock g_Glock;
CCrowbar g_Crowbar;
CPython g_Python;
CMP5 g_Mp5;
CCrossbow g_Crossbow;
CShotgun g_Shotgun;
CRpg g_Rpg;
CGauss g_Gauss;
CEgon g_Egon;
CHgun g_HGun;
CHandGrenade g_HandGren;
CSatchel g_Satchel;
CTripmine g_Tripmine;
CSqueak g_Snark;
//begin Alex
CBeretta g_Beretta;
CM41A g_M41A;
CPoolstick g_Poolstick;
CToad g_Toad;
//end Alex
/*
======================
AlertMessage
@ -606,28 +584,6 @@ void HUD_InitClientWeapons( void )
// Allocate a slot for the local player
HUD_PrepEntity( &player, NULL );
// Allocate slot(s) for each weapon that we are going to be predicting
HUD_PrepEntity( &g_Glock, &player );
HUD_PrepEntity( &g_Crowbar, &player );
HUD_PrepEntity( &g_Python, &player );
HUD_PrepEntity( &g_Mp5, &player );
HUD_PrepEntity( &g_Crossbow, &player );
HUD_PrepEntity( &g_Shotgun, &player );
HUD_PrepEntity( &g_Rpg, &player );
HUD_PrepEntity( &g_Gauss, &player );
HUD_PrepEntity( &g_Egon, &player );
HUD_PrepEntity( &g_HGun, &player );
HUD_PrepEntity( &g_HandGren, &player );
HUD_PrepEntity( &g_Satchel, &player );
HUD_PrepEntity( &g_Tripmine, &player );
HUD_PrepEntity( &g_Snark, &player );
//begin Alex
HUD_PrepEntity( &g_M41A, &player );
HUD_PrepEntity( &g_Beretta, &player );
HUD_PrepEntity( &g_Toad, &player );
HUD_PrepEntity( &g_Poolstick, &player );
//end Alex
}
/*
@ -687,68 +643,6 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm
// Get current clock
gpGlobals->time = time;
// Fill in data based on selected weapon
// FIXME, make this a method in each weapon? where you pass in an entity_state_t *?
switch( from->client.m_iId )
{
case WEAPON_CROWBAR:
pWeapon = &g_Crowbar;
break;
case WEAPON_GLOCK:
pWeapon = &g_Glock;
break;
case WEAPON_PYTHON:
pWeapon = &g_Python;
break;
case WEAPON_MP5:
pWeapon = &g_Mp5;
break;
case WEAPON_CROSSBOW:
pWeapon = &g_Crossbow;
break;
case WEAPON_SHOTGUN:
pWeapon = &g_Shotgun;
break;
case WEAPON_RPG:
pWeapon = &g_Rpg;
break;
case WEAPON_GAUSS:
pWeapon = &g_Gauss;
break;
case WEAPON_EGON:
pWeapon = &g_Egon;
break;
case WEAPON_HORNETGUN:
pWeapon = &g_HGun;
break;
case WEAPON_HANDGRENADE:
pWeapon = &g_HandGren;
break;
case WEAPON_SATCHEL:
pWeapon = &g_Satchel;
break;
case WEAPON_TRIPMINE:
pWeapon = &g_Tripmine;
break;
case WEAPON_SNARK:
pWeapon = &g_Snark;
break;
// begin Alex
case WEAPON_M41A:
pWeapon = &g_M41A;
break;
case WEAPON_BERETTA:
pWeapon = &g_Beretta;
break;
case WEAPON_TOAD:
pWeapon = &g_Toad;
break;
case WEAPON_POOLSTICK:
pWeapon = &g_Poolstick;
break;
// end Alex
}
// Store pointer to our destination entity_state_t so we can get our origin, etc. from it
// for setting up events on the client
g_finalstate = to;
@ -792,11 +686,6 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm
pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack;
pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle;
pCurrent->pev->fuser1 = pfrom->fuser1;
pCurrent->m_flStartThrow = pfrom->fuser2;
pCurrent->m_flReleaseThrow = pfrom->fuser3;
pCurrent->m_chargeReady = pfrom->iuser1;
pCurrent->m_fInAttack = pfrom->iuser2;
pCurrent->m_fireState = pfrom->iuser3;
pCurrent->m_iSecondaryAmmoType = (int)from->client.vuser3[2];
pCurrent->m_iPrimaryAmmoType = (int)from->client.vuser4[0];
@ -835,15 +724,6 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm
player.m_flNextAmmoBurn = from->client.fuser2;
player.m_flAmmoStartCharge = from->client.fuser3;
//Stores all our ammo info, so the client side weapons can use them.
player.ammo_9mm = (int)from->client.vuser1[0];
player.ammo_357 = (int)from->client.vuser1[1];
player.ammo_argrens = (int)from->client.vuser1[2];
player.ammo_bolts = (int)from->client.ammo_nails; //is an int anyways...
player.ammo_buckshot = (int)from->client.ammo_shells;
player.ammo_uranium = (int)from->client.ammo_cells;
player.ammo_hornets = (int)from->client.vuser2[0];
player.ammo_rockets = (int)from->client.ammo_rockets;
// Point to current weapon object
if( from->client.m_iId )
@ -851,12 +731,6 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm
player.m_pActiveItem = g_pWpns[from->client.m_iId];
}
if( player.m_pActiveItem->m_iId == WEAPON_RPG )
{
( (CRpg *)player.m_pActiveItem )->m_fSpotActive = (int)from->client.vuser2[1];
( (CRpg *)player.m_pActiveItem )->m_cActiveRockets = (int)from->client.vuser2[2];
}
// Don't go firing anything if we have died.
// Or if we don't have a weapon model deployed
if( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) &&
@ -908,37 +782,12 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm
to->client.fuser3 = player.m_flAmmoStartCharge;
to->client.maxspeed = player.pev->maxspeed;
//HL Weapons
to->client.vuser1[0] = player.ammo_9mm;
to->client.vuser1[1] = player.ammo_357;
to->client.vuser1[2] = player.ammo_argrens;
to->client.ammo_nails = player.ammo_bolts;
to->client.ammo_shells = player.ammo_buckshot;
to->client.ammo_cells = player.ammo_uranium;
to->client.vuser2[0] = player.ammo_hornets;
to->client.ammo_rockets = player.ammo_rockets;
if( player.m_pActiveItem->m_iId == WEAPON_RPG )
{
from->client.vuser2[1] = ( (CRpg *)player.m_pActiveItem)->m_fSpotActive;
from->client.vuser2[2] = ( (CRpg *)player.m_pActiveItem)->m_cActiveRockets;
}
// Make sure that weapon animation matches what the game .dll is telling us
// over the wire ( fixes some animation glitches )
if( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) )
{
int body = 2;
//Pop the model to body 0.
if( pWeapon == &g_Tripmine )
body = 0;
//Show laser sight/scope combo
if( pWeapon == &g_Python && bIsMultiplayer() )
body = 1;
// Force a fixed anim down to viewmodel
HUD_SendWeaponAnim( to->client.weaponanim, body, 1 );
}
@ -963,11 +812,6 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm
pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack;
pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle;
pto->fuser1 = pCurrent->pev->fuser1;
pto->fuser2 = pCurrent->m_flStartThrow;
pto->fuser3 = pCurrent->m_flReleaseThrow;
pto->iuser1 = pCurrent->m_chargeReady;
pto->iuser2 = pCurrent->m_fInAttack;
pto->iuser3 = pCurrent->m_fireState;
// Decrement weapon counters, server does this at same time ( during post think, after doing everything else )
pto->m_flNextReload -= cmd->msec / 1000.0;

View File

@ -514,8 +514,8 @@ int CHud::MsgFunc_SetFOV( const char *pszName, int iSize, void *pbuf )
int def_fov = CVAR_GET_FLOAT( "default_fov" );
//Weapon prediction already takes care of changing the fog. ( g_lastFOV ).
if( cl_lw && cl_lw->value )
return 1;
//if( cl_lw && cl_lw->value )
// return 1;
g_lastFOV = newfov;

View File

@ -22,9 +22,9 @@
#pragma once
#ifndef HUD_H
#define HUD_H
#define RGB_YELLOWISH 0x00555EFF //85,94,255 Blue Azure Sheep hud
#define RGB_YELLOWISH 0x004040FF //64,64,255 Blue Azure Sheep hud
#define RGB_REDISH 0x00FF1010 //255,160,0
#define RGB_GREENISH 0x0000A000 //0,160,0
#define RGB_GREENISH 0x008080FF //128,128,255
#include "wrect.h"
#include "cl_dll.h"

View File

@ -23,8 +23,6 @@
#define MAX_CLIENTS 32
extern BEAM *pBeam;
extern BEAM *pBeam2;
/// USER-DEFINED SERVER MESSAGE HANDLERS
@ -69,9 +67,6 @@ void CHud::MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf )
pList->p->InitHUDData();
pList = pList->pNext;
}
//Probably not a good place to put this.
pBeam = pBeam2 = NULL;
}
int CHud::MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf )

View File

@ -13,7 +13,7 @@ ifeq ($(TARGET_ARCH_ABI),armeabi-v7a-hard)
LOCAL_MODULE_FILENAME = libserver_hardfp
endif
LOCAL_CFLAGS += -D_LINUX -DCLIENT_WEAPONS -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf \
LOCAL_CFLAGS += -D_LINUX -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf \
-fno-exceptions -DNO_VOICEGAMEMGR -w
LOCAL_CPPFLAGS := $(LOCAL_CFLAGS)
@ -126,6 +126,24 @@ LOCAL_SRC_FILES := agrunt.cpp airtank.cpp \
world.cpp \
xen.cpp \
zombie.cpp \
asheep/panther.cpp \
asheep/archer.cpp \
asheep/barneyglock.cpp \
asheep/barneyhg.cpp \
asheep/barneymp5.cpp \
asheep/barneyshotgun.cpp \
asheep/barniel.cpp \
asheep/beretta.cpp \
asheep/bodypart.cpp \
asheep/garbage.cpp \
asheep/gordonnadrian.cpp \
asheep/kate.cpp \
asheep/kmedkit.cpp \
asheep/m41a.cpp \
asheep/poolstick.cpp \
asheep/spforce.cpp \
asheep/terror.cpp \
asheep/toad.cpp \
../pm_shared/pm_debug.c \
../pm_shared/pm_math.c \
../pm_shared/pm_shared.c

View File

@ -25,7 +25,7 @@ project (SVDLL)
set (SVDLL_LIBRARY server)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_LINUX -DCLIENT_WEAPONS -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -fno-exceptions -w")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_LINUX -Dstricmp=strcasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -fno-exceptions -w")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}")
set (SVDLL_SOURCES
@ -128,14 +128,19 @@ set (SVDLL_SOURCES
world.cpp
xen.cpp
zombie.cpp
asheep/adrian.cpp
asheep/alienpanther.cpp
asheep/panther.cpp
asheep/archer.cpp
asheep/barneyglock.cpp
asheep/barneyhg.cpp
asheep/barneymp5.cpp
asheep/barneyshotgun.cpp
asheep/barniel.cpp
asheep/beretta.cpp
asheep/gordon.cpp
asheep/hevbarn.cpp
asheep/bodypart.cpp
asheep/garbage.cpp
asheep/gordonnadrian.cpp
asheep/kate.cpp
asheep/kmedkit.cpp
asheep/m41a.cpp
asheep/poolstick.cpp
asheep/spforce.cpp

View File

@ -193,7 +193,7 @@ const char *CAGrunt::pAlertSounds[] =
//=========================================================
int CAGrunt::IRelationship( CBaseEntity *pTarget )
{
if( FClassnameIs( pTarget->pev, "monster_human_grunt" ) )
if( FClassnameIs( pTarget->pev, "monster_human_grunt" ) || FClassnameIs( pTarget->pev, "monster_human_spforce" ) )
{
return R_NM;
}
@ -466,19 +466,6 @@ void CAGrunt::HandleAnimEvent( MonsterEvent_t *pEvent )
UTIL_MakeVectors ( pHornet->pev->angles );
pHornet->pev->velocity = gpGlobals->v_forward * 300;
switch( RANDOM_LONG ( 0 , 2 ) )
{
case 0:
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "agrunt/ag_fire1.wav", 1.0, ATTN_NORM, 0, 100 );
break;
case 1:
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "agrunt/ag_fire2.wav", 1.0, ATTN_NORM, 0, 100 );
break;
case 2:
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "agrunt/ag_fire3.wav", 1.0, ATTN_NORM, 0, 100 );
break;
}
CBaseMonster *pHornetMonster = pHornet->MyMonsterPointer();
if( pHornetMonster )

View File

@ -167,7 +167,7 @@ void CApache::Precache( void )
PRECACHE_SOUND( "turret/tu_fire1.wav" );
PRECACHE_MODEL( "sprites/lgtning.spr" );
// PRECACHE_MODEL( "sprites/lgtning.spr" );
m_iExplode = PRECACHE_MODEL( "sprites/fexplo.spr" );
m_iBodyGibs = PRECACHE_MODEL( "models/metalplategibs_green.mdl" );

View File

@ -1,842 +0,0 @@
/***
*
* 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.
*
****/
//=========================================================
// monster template
//=========================================================
// UNDONE: Holster weapon?
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "talkmonster.h"
#include "schedule.h"
#include "defaultai.h"
#include "scripted.h"
#include "weapons.h"
#include "soundent.h"
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
// first flag is barney dying for scripted sequences?
#define ADRIAN_AE_DRAW ( 2 )
#define ADRIAN_AE_SHOOT ( 3 )
#define ADRIAN_AE_HOLSTER ( 4 )
#define ADRIAN_BODY_GUNHOLSTERED 0
#define ADRIAN_BODY_GUNDRAWN 1
#define ADRIAN_BODY_GUNGONE 2
class CAdrian : public CTalkMonster
{
public:
void Spawn( void );
void Precache( void );
void SetYawSpeed( void );
int ISoundMask( void );
void AdrianFirePistol( void );
void AlertSound( void );
int Classify ( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
void RunTask( Task_t *pTask );
void StartTask( Task_t *pTask );
virtual int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; }
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
BOOL CheckRangeAttack1 ( float flDot, float flDist );
void DeclineFollowing( void );
// Override these to set behavior
Schedule_t *GetScheduleOfType ( int Type );
Schedule_t *GetSchedule ( void );
MONSTERSTATE GetIdealState ( void );
void DeathSound( void );
void PainSound( void );
void TalkInit( void );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
void Killed( entvars_t *pevAttacker, int iGib );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
BOOL m_fGunDrawn;
float m_painTime;
float m_checkAttackTime;
BOOL m_lastAttackCheck;
// UNDONE: What is this for? It isn't used?
float m_flPlayerDamage;// how much pain has the player inflicted on me?
CUSTOM_SCHEDULES;
};
LINK_ENTITY_TO_CLASS( monster_adrian, CAdrian );
TYPEDESCRIPTION CAdrian::m_SaveData[] =
{
DEFINE_FIELD( CAdrian, m_fGunDrawn, FIELD_BOOLEAN ),
DEFINE_FIELD( CAdrian, m_painTime, FIELD_TIME ),
DEFINE_FIELD( CAdrian, m_checkAttackTime, FIELD_TIME ),
DEFINE_FIELD( CAdrian, m_lastAttackCheck, FIELD_BOOLEAN ),
DEFINE_FIELD( CAdrian, m_flPlayerDamage, FIELD_FLOAT ),
};
IMPLEMENT_SAVERESTORE( CAdrian, CTalkMonster );
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
Task_t tlAdrFollow[] =
{
{ TASK_MOVE_TO_TARGET_RANGE,(float)128 }, // Move within 128 of target ent (client)
{ TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE },
};
Schedule_t slAdrFollow[] =
{
{
tlAdrFollow,
ARRAYSIZE ( tlAdrFollow ),
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND |
bits_COND_PROVOKED,
bits_SOUND_DANGER,
"Follow"
},
};
//=========================================================
// AdrianDraw- much better looking draw schedule for when
// barney knows who he's gonna attack.
//=========================================================
Task_t tlAdrianEnemyDraw[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_FACE_ENEMY, 0 },
{ TASK_PLAY_SEQUENCE_FACE_ENEMY, (float) ACT_ARM },
};
Schedule_t slAdrianEnemyDraw[] =
{
{
tlAdrianEnemyDraw,
ARRAYSIZE ( tlAdrianEnemyDraw ),
0,
0,
"Adrian Enemy Draw"
}
};
Task_t tlAdrFaceTarget[] =
{
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_FACE_TARGET, (float)0 },
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE },
};
Schedule_t slAdrFaceTarget[] =
{
{
tlAdrFaceTarget,
ARRAYSIZE ( tlAdrFaceTarget ),
bits_COND_CLIENT_PUSH |
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND |
bits_COND_PROVOKED,
bits_SOUND_DANGER,
"FaceTarget"
},
};
Task_t tlIdleAdrStand[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds.
{ TASK_TLK_HEADRESET, (float)0 }, // reset head position
};
Schedule_t slIdleAdrStand[] =
{
{
tlIdleAdrStand,
ARRAYSIZE ( tlIdleAdrStand ),
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND |
bits_COND_SMELL |
bits_COND_PROVOKED,
bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code.
//bits_SOUND_PLAYER |
//bits_SOUND_WORLD |
bits_SOUND_DANGER |
bits_SOUND_MEAT |// scents
bits_SOUND_CARCASS |
bits_SOUND_GARBAGE,
"IdleStand"
},
};
DEFINE_CUSTOM_SCHEDULES( CAdrian )
{
slAdrFollow,
slAdrianEnemyDraw,
slAdrFaceTarget,
slIdleAdrStand,
};
IMPLEMENT_CUSTOM_SCHEDULES( CAdrian, CTalkMonster );
void CAdrian :: StartTask( Task_t *pTask )
{
CTalkMonster::StartTask( pTask );
}
void CAdrian :: RunTask( Task_t *pTask )
{
switch ( pTask->iTask )
{
case TASK_RANGE_ATTACK1:
if (m_hEnemy != NULL && (m_hEnemy->IsPlayer()))
{
pev->framerate = 1.5;
}
CTalkMonster::RunTask( pTask );
break;
default:
CTalkMonster::RunTask( pTask );
break;
}
}
//=========================================================
// ISoundMask - returns a bit mask indicating which types
// of sounds this monster regards.
//=========================================================
int CAdrian :: ISoundMask ( void)
{
return bits_SOUND_WORLD |
bits_SOUND_COMBAT |
bits_SOUND_CARCASS |
bits_SOUND_MEAT |
bits_SOUND_GARBAGE |
bits_SOUND_DANGER |
bits_SOUND_PLAYER;
}
//=========================================================
// Classify - indicates this monster's place in the
// relationship table.
//=========================================================
int CAdrian :: Classify ( void )
{
return CLASS_PLAYER_ALLY;
}
//=========================================================
// ALertSound - barney says "Freeze!"
//=========================================================
void CAdrian :: AlertSound( void )
{
if ( m_hEnemy != NULL )
{
if ( FOkToSpeak() )
{
PlaySentence( "BA_ATTACK", RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE );
}
}
}
//=========================================================
// SetYawSpeed - allows each sequence to have a different
// turn rate associated with it.
//=========================================================
void CAdrian :: SetYawSpeed ( void )
{
int ys;
ys = 0;
switch ( m_Activity )
{
case ACT_IDLE:
ys = 70;
break;
case ACT_WALK:
ys = 70;
break;
case ACT_RUN:
ys = 90;
break;
default:
ys = 70;
break;
}
pev->yaw_speed = ys;
}
//=========================================================
// CheckRangeAttack1
//=========================================================
BOOL CAdrian :: CheckRangeAttack1 ( float flDot, float flDist )
{
if ( flDist <= 1024 && flDot >= 0.5 )
{
if ( gpGlobals->time > m_checkAttackTime )
{
TraceResult tr;
Vector shootOrigin = pev->origin + Vector( 0, 0, 55 );
CBaseEntity *pEnemy = m_hEnemy;
Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP );
UTIL_TraceLine( shootOrigin, shootTarget, dont_ignore_monsters, ENT(pev), &tr );
m_checkAttackTime = gpGlobals->time + 1;
if ( tr.flFraction == 1.0 || (tr.pHit != NULL && CBaseEntity::Instance(tr.pHit) == pEnemy) )
m_lastAttackCheck = TRUE;
else
m_lastAttackCheck = FALSE;
m_checkAttackTime = gpGlobals->time + 1.5;
}
return m_lastAttackCheck;
}
return FALSE;
}
//=========================================================
// AdrianFirePistol - shoots one round from the pistol at
// the enemy barney is facing.
//=========================================================
void CAdrian :: AdrianFirePistol ( void )
{
Vector vecShootOrigin;
UTIL_MakeVectors(pev->angles);
vecShootOrigin = pev->origin + Vector( 0, 0, 55 );
Vector vecShootDir = ShootAtEnemy( vecShootOrigin );
Vector angDir = UTIL_VecToAngles( vecShootDir );
SetBlending( 0, angDir.x );
pev->effects = EF_MUZZLEFLASH;
FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_9MM );
int pitchShift = RANDOM_LONG( 0, 20 );
// Only shift about half the time
if ( pitchShift > 10 )
pitchShift = 0;
else
pitchShift -= 5;
EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "barney/ba_attack2.wav", 1, ATTN_NORM, 0, 100 + pitchShift );
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 );
// UNDONE: Reload?
m_cAmmoLoaded--;// take away a bullet!
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CAdrian :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
switch( pEvent->event )
{
case ADRIAN_AE_SHOOT:
AdrianFirePistol();
break;
case ADRIAN_AE_DRAW:
// barney's bodygroup switches here so he can pull gun from holster
pev->body = ADRIAN_BODY_GUNDRAWN;
m_fGunDrawn = TRUE;
break;
case ADRIAN_AE_HOLSTER:
// change bodygroup to replace gun in holster
pev->body = ADRIAN_BODY_GUNHOLSTERED;
m_fGunDrawn = FALSE;
break;
default:
CTalkMonster::HandleAnimEvent( pEvent );
}
}
//=========================================================
// Spawn
//=========================================================
void CAdrian :: Spawn()
{
Precache( );
SET_MODEL(ENT(pev), "models/adrian.mdl");
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
pev->health = gSkillData.barneyHealth;
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE;
pev->body = 0; // gun in holster
m_fGunDrawn = FALSE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
MonsterInit();
SetUse( &CAdrian::FollowerUse );
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CAdrian :: Precache()
{
PRECACHE_MODEL("models/adrian.mdl");
PRECACHE_SOUND("barney/ba_attack1.wav" );
PRECACHE_SOUND("barney/ba_attack2.wav" );
PRECACHE_SOUND("barney/ba_pain1.wav");
PRECACHE_SOUND("barney/ba_pain2.wav");
PRECACHE_SOUND("barney/ba_pain3.wav");
PRECACHE_SOUND("barney/ba_die1.wav");
PRECACHE_SOUND("barney/ba_die2.wav");
PRECACHE_SOUND("barney/ba_die3.wav");
PRECACHE_SOUND("barney/ba_duty.wav");
PRECACHE_SOUND("barney/ba_post.wav");
PRECACHE_SOUND("barney/goon.wav");
// every new barney must call this, otherwise
// when a level is loaded, nobody will talk (time is reset to 0)
TalkInit();
CTalkMonster::Precache();
}
// Init talk data
void CAdrian :: TalkInit()
{
CTalkMonster::TalkInit();
// scientists speach group names (group names are in sentences.txt)
m_szGrp[TLK_ANSWER] = "BA_ANSWER";
m_szGrp[TLK_QUESTION] = "BA_QUESTION";
m_szGrp[TLK_IDLE] = "BA_IDLE";
m_szGrp[TLK_STARE] = "BA_STARE";
m_szGrp[TLK_USE] = "BA_OK";
m_szGrp[TLK_UNUSE] = "BA_WAIT";
m_szGrp[TLK_STOP] = "BA_STOP";
m_szGrp[TLK_NOSHOOT] = "BA_SCARED";
m_szGrp[TLK_HELLO] = "BA_HELLO";
m_szGrp[TLK_PLHURT1] = "!BA_CUREA";
m_szGrp[TLK_PLHURT2] = "!BA_CUREB";
m_szGrp[TLK_PLHURT3] = "!BA_CUREC";
m_szGrp[TLK_PHELLO] = NULL; //"BA_PHELLO"; // UNDONE
m_szGrp[TLK_PIDLE] = NULL; //"BA_PIDLE"; // UNDONE
m_szGrp[TLK_PQUESTION] = "BA_PQUEST"; // UNDONE
m_szGrp[TLK_SMELL] = "BA_SMELL";
m_szGrp[TLK_WOUND] = "BA_WOUND";
m_szGrp[TLK_MORTAL] = "BA_MORTAL";
// get voice for head - just one barney voice for now
m_voicePitch = 100;
}
static BOOL IsFacing( entvars_t *pevTest, const Vector &reference )
{
Vector vecDir = (reference - pevTest->origin);
vecDir.z = 0;
vecDir = vecDir.Normalize();
Vector forward, angle;
angle = pevTest->v_angle;
angle.x = 0;
UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL );
// He's facing me, he meant it
if ( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so
{
return TRUE;
}
return FALSE;
}
int CAdrian :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType)
{
// make sure friends talk about it if player hurts talkmonsters...
int ret = CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
if ( !IsAlive() || pev->deadflag == DEAD_DYING )
return ret;
if ( m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT) )
{
m_flPlayerDamage += flDamage;
// This is a heurstic to determine if the player intended to harm me
// If I have an enemy, we can't establish intent (may just be crossfire)
if ( m_hEnemy == NULL )
{
// If the player was facing directly at me, or I'm already suspicious, get mad
if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || IsFacing( pevAttacker, pev->origin ) )
{
// Alright, now I'm pissed!
PlaySentence( "BA_MAD", 4, VOL_NORM, ATTN_NORM );
Remember( bits_MEMORY_PROVOKED );
StopFollowing( TRUE );
}
else
{
// Hey, be careful with that
PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM );
Remember( bits_MEMORY_SUSPICIOUS );
}
}
else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO )
{
PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM );
}
}
return ret;
}
//=========================================================
// PainSound
//=========================================================
void CAdrian :: PainSound ( void )
{
if (gpGlobals->time < m_painTime)
return;
m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75);
switch (RANDOM_LONG(0,2))
{
case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
}
}
//=========================================================
// DeathSound
//=========================================================
void CAdrian :: DeathSound ( void )
{
switch (RANDOM_LONG(0,2))
{
case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
}
}
void CAdrian::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
{
switch( ptr->iHitgroup)
{
case HITGROUP_CHEST:
case HITGROUP_STOMACH:
if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST))
{
flDamage = flDamage / 2;
}
break;
case 10:
if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB))
{
flDamage -= 20;
if (flDamage <= 0)
{
UTIL_Ricochet( ptr->vecEndPos, 1.0 );
flDamage = 0.01;
}
}
// always a head shot
ptr->iHitgroup = HITGROUP_HEAD;
break;
}
CTalkMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
}
void CAdrian::Killed( entvars_t *pevAttacker, int iGib )
{
if ( pev->body < ADRIAN_BODY_GUNGONE )
{// drop the gun!
Vector vecGunPos;
Vector vecGunAngles;
pev->body = ADRIAN_BODY_GUNGONE;
GetAttachment( 0, vecGunPos, vecGunAngles );
CBaseEntity *pGun = DropItem( "weapon_barney9mmhg", vecGunPos, vecGunAngles );
}
SetUse( NULL );
CTalkMonster::Killed( pevAttacker, iGib );
}
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
Schedule_t* CAdrian :: GetScheduleOfType ( int Type )
{
Schedule_t *psched;
switch( Type )
{
case SCHED_ARM_WEAPON:
if ( m_hEnemy != NULL )
{
// face enemy, then draw.
return slAdrianEnemyDraw;
}
break;
// Hook these to make a looping schedule
case SCHED_TARGET_FACE:
// call base class default so that barney will talk
// when 'used'
psched = CTalkMonster::GetScheduleOfType(Type);
if (psched == slIdleStand)
return slAdrFaceTarget; // override this for different target face behavior
else
return psched;
case SCHED_TARGET_CHASE:
return slAdrFollow;
case SCHED_IDLE_STAND:
// call base class default so that scientist will talk
// when standing during idle
psched = CTalkMonster::GetScheduleOfType(Type);
if (psched == slIdleStand)
{
// just look straight ahead.
return slIdleAdrStand;
}
else
return psched;
}
return CTalkMonster::GetScheduleOfType( Type );
}
//=========================================================
// GetSchedule - Decides which type of schedule best suits
// the monster's current state and conditions. Then calls
// monster's member function to get a pointer to a schedule
// of the proper type.
//=========================================================
Schedule_t *CAdrian :: GetSchedule ( void )
{
if ( HasConditions( bits_COND_HEAR_SOUND ) )
{
CSound *pSound;
pSound = PBestSound();
ASSERT( pSound != NULL );
if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) )
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND );
}
if ( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() )
{
PlaySentence( "BA_KILL", 4, VOL_NORM, ATTN_NORM );
}
switch( m_MonsterState )
{
case MONSTERSTATE_COMBAT:
{
// dead enemy
if ( HasConditions( bits_COND_ENEMY_DEAD ) )
{
// call base class, all code to handle dead enemies is centralized there.
return CBaseMonster :: GetSchedule();
}
// always act surprized with a new enemy
if ( HasConditions( bits_COND_NEW_ENEMY ) && HasConditions( bits_COND_LIGHT_DAMAGE) )
return GetScheduleOfType( SCHED_SMALL_FLINCH );
// wait for one schedule to draw gun
if (!m_fGunDrawn )
return GetScheduleOfType( SCHED_ARM_WEAPON );
if ( HasConditions( bits_COND_HEAVY_DAMAGE ) )
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
}
break;
case MONSTERSTATE_ALERT:
case MONSTERSTATE_IDLE:
if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE))
{
// flinch if hurt
return GetScheduleOfType( SCHED_SMALL_FLINCH );
}
if ( m_hEnemy == NULL && IsFollowing() )
{
if ( !m_hTargetEnt->IsAlive() )
{
// UNDONE: Comment about the recently dead player here?
StopFollowing( FALSE );
break;
}
else
{
if ( HasConditions( bits_COND_CLIENT_PUSH ) )
{
return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW );
}
return GetScheduleOfType( SCHED_TARGET_FACE );
}
}
if ( HasConditions( bits_COND_CLIENT_PUSH ) )
{
return GetScheduleOfType( SCHED_MOVE_AWAY );
}
// try to say something about smells
TrySmellTalk();
break;
}
return CTalkMonster::GetSchedule();
}
MONSTERSTATE CAdrian :: GetIdealState ( void )
{
return CTalkMonster::GetIdealState();
}
void CAdrian::DeclineFollowing( void )
{
PlaySentence( "BA_POK", 2, VOL_NORM, ATTN_NORM );
}
//=========================================================
// DEAD ADRIAN PROP
//
// Designer selects a pose in worldcraft, 0 through num_poses-1
// this value is added to what is selected as the 'first dead pose'
// among the monster's normal animations. All dead poses must
// appear sequentially in the model file. Be sure and set
// the m_iFirstPose properly!
//
//=========================================================
class CDeadAdrian : public CBaseMonster
{
public:
void Spawn( void );
int Classify ( void ) { return CLASS_PLAYER_ALLY; }
void KeyValue( KeyValueData *pkvd );
int m_iPose;// which sequence to display -- temporary, don't need to save
static char *m_szPoses[3];
};
char *CDeadAdrian::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" };
void CDeadAdrian::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "pose"))
{
m_iPose = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseMonster::KeyValue( pkvd );
}
LINK_ENTITY_TO_CLASS( monster_adrian_dead, CDeadAdrian );
//=========================================================
// ********** DeadAdrian SPAWN **********
//=========================================================
void CDeadAdrian :: Spawn( )
{
PRECACHE_MODEL("models/adrian.mdl");
SET_MODEL(ENT(pev), "models/adrian.mdl");
pev->effects = 0;
pev->yaw_speed = 8;
pev->sequence = 0;
m_bloodColor = BLOOD_COLOR_RED;
pev->sequence = LookupSequence( m_szPoses[m_iPose] );
if (pev->sequence == -1)
{
ALERT ( at_console, "Dead barney with bad pose\n" );
}
// Corpses have less health
pev->health = 8;//gSkillData.barneyHealth;
MonsterInitDead();
}

View File

@ -1,866 +0,0 @@
/***
*
* 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.
*
****/
//=========================================================
// Alien panther monster
//=========================================================
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "squadmonster.h"
#include "schedule.h"
#include "effects.h"
#include "weapons.h"
#include "soundent.h"
extern DLL_GLOBAL int g_iSkillLevel;
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
#define APANTHER_AE_CLAW ( 1 )
#define APANTHER_AE_CLAWRAKE ( 2 )
#define APANTHER_AE_ZAP_POWERUP ( 3 )
#define APANTHER_AE_ZAP_SHOOT ( 4 )
#define APANTHER_AE_ZAP_DONE ( 5 )
#define APANTHER_MAX_BEAMS 8
class CAlienPanther : public CSquadMonster
{
public:
void Spawn( void );
void Precache( void );
void SetYawSpeed( void );
int ISoundMask( void );
int Classify ( void );
int IRelationship( CBaseEntity *pTarget );
void HandleAnimEvent( MonsterEvent_t *pEvent );
BOOL CheckRangeAttack1 ( float flDot, float flDist );
BOOL CheckRangeAttack2 ( float flDot, float flDist );
void CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
void DeathSound( void );
void PainSound( void );
void AlertSound( void );
void IdleSound( void );
void Killed( entvars_t *pevAttacker, int iGib );
void StartTask ( Task_t *pTask );
Schedule_t *GetSchedule( void );
Schedule_t *GetScheduleOfType ( int Type );
CUSTOM_SCHEDULES;
int Save( CSave &save );
int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
void ClearBeams( );
void ArmBeam( int side );
void WackBeam( int side, CBaseEntity *pEntity );
void ZapBeam( int side );
void BeamGlow( void );
int m_iBravery;
CBeam *m_pBeam[APANTHER_MAX_BEAMS];
int m_iBeams;
float m_flNextAttack;
int m_voicePitch;
EHANDLE m_hDead;
static const char *pAttackHitSounds[];
static const char *pAttackMissSounds[];
static const char *pPainSounds[];
static const char *pDeathSounds[];
};
LINK_ENTITY_TO_CLASS( monster_alien_panther, CAlienPanther );
TYPEDESCRIPTION CAlienPanther::m_SaveData[] =
{
DEFINE_FIELD( CAlienPanther, m_iBravery, FIELD_INTEGER ),
DEFINE_ARRAY( CAlienPanther, m_pBeam, FIELD_CLASSPTR, APANTHER_MAX_BEAMS ),
DEFINE_FIELD( CAlienPanther, m_iBeams, FIELD_INTEGER ),
DEFINE_FIELD( CAlienPanther, m_flNextAttack, FIELD_TIME ),
DEFINE_FIELD( CAlienPanther, m_voicePitch, FIELD_INTEGER ),
DEFINE_FIELD( CAlienPanther, m_hDead, FIELD_EHANDLE ),
};
IMPLEMENT_SAVERESTORE( CAlienPanther, CSquadMonster );
const char *CAlienPanther::pAttackHitSounds[] =
{
"panther/pclaw_strike1.wav",
"panther/pclaw_strike2.wav",
"panther/pclaw_strike3.wav",
};
const char *CAlienPanther::pAttackMissSounds[] =
{
"panther/pclaw_miss1.wav",
"panther/pclaw_miss2.wav",
};
const char *CAlienPanther::pPainSounds[] =
{
"panther/p_pain1.wav",
"panther/p_pain2.wav",
};
const char *CAlienPanther::pDeathSounds[] =
{
"panther/p_die1.wav",
"panther/p_die2.wav",
};
//=========================================================
// Classify - indicates this monster's place in the
// relationship table.
//=========================================================
int CAlienPanther :: Classify ( void )
{
return CLASS_ALIEN_MILITARY;
}
int CAlienPanther::IRelationship( CBaseEntity *pTarget )
{
if ( (pTarget->IsPlayer()) )
if ( (pev->spawnflags & SF_MONSTER_WAIT_UNTIL_PROVOKED ) && ! (m_afMemory & bits_MEMORY_PROVOKED ))
return R_NO;
return CBaseMonster::IRelationship( pTarget );
}
void CAlienPanther :: CallForHelp( char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation )
{
// ALERT( at_aiconsole, "help " );
// skip ones not on my netname
if ( FStringNull( pev->netname ))
return;
CBaseEntity *pEntity = NULL;
while ((pEntity = UTIL_FindEntityByString( pEntity, "netname", STRING( pev->netname ))) != NULL)
{
float d = (pev->origin - pEntity->pev->origin).Length();
if (d < flDist)
{
CBaseMonster *pMonster = pEntity->MyMonsterPointer( );
if (pMonster)
{
pMonster->m_afMemory |= bits_MEMORY_PROVOKED;
pMonster->PushEnemy( hEnemy, vecLocation );
}
}
}
}
//=========================================================
// ALertSound - scream
//=========================================================
void CAlienPanther :: AlertSound( void )
{
if ( m_hEnemy != NULL )
{
SENTENCEG_PlayRndSz(ENT(pev), "SLV_ALERT", 0.85, ATTN_NORM, 0, m_voicePitch);
CallForHelp( "monster_alien_panther", 512, m_hEnemy, m_vecEnemyLKP );
}
}
//=========================================================
// IdleSound
//=========================================================
void CAlienPanther :: IdleSound( void )
{
if (RANDOM_LONG( 0, 2 ) == 0)
{
SENTENCEG_PlayRndSz(ENT(pev), "P_IDLE", 0.85, ATTN_NORM, 0, m_voicePitch);
}
#if 0
int side = RANDOM_LONG( 0, 1 ) * 2 - 1;
ClearBeams( );
ArmBeam( side );
UTIL_MakeAimVectors( pev->angles );
Vector vecSrc = pev->origin + gpGlobals->v_right * 2 * side;
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc );
WRITE_BYTE(TE_DLIGHT);
WRITE_COORD(vecSrc.x); // X
WRITE_COORD(vecSrc.y); // Y
WRITE_COORD(vecSrc.z); // Z
WRITE_BYTE( 8 ); // radius * 0.1
WRITE_BYTE( 255 ); // r
WRITE_BYTE( 180 ); // g
WRITE_BYTE( 96 ); // b
WRITE_BYTE( 10 ); // time * 10
WRITE_BYTE( 0 ); // decay * 0.1
MESSAGE_END( );
EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "panther/p_zap1.wav", 1, ATTN_NORM, 0, 100 );
#endif
}
//=========================================================
// PainSound
//=========================================================
void CAlienPanther :: PainSound( void )
{
if (RANDOM_LONG( 0, 2 ) == 0)
{
EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pPainSounds[ RANDOM_LONG(0,ARRAYSIZE(pPainSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch );
}
}
//=========================================================
// DieSound
//=========================================================
void CAlienPanther :: DeathSound( void )
{
EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pDeathSounds[ RANDOM_LONG(0,ARRAYSIZE(pDeathSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch );
}
//=========================================================
// ISoundMask - returns a bit mask indicating which types
// of sounds this monster regards.
//=========================================================
int CAlienPanther :: ISoundMask ( void)
{
return bits_SOUND_WORLD |
bits_SOUND_COMBAT |
bits_SOUND_DANGER |
bits_SOUND_PLAYER;
}
void CAlienPanther::Killed( entvars_t *pevAttacker, int iGib )
{
ClearBeams( );
CSquadMonster::Killed( pevAttacker, iGib );
}
//=========================================================
// SetYawSpeed - allows each sequence to have a different
// turn rate associated with it.
//=========================================================
void CAlienPanther :: SetYawSpeed ( void )
{
int ys;
switch ( m_Activity )
{
case ACT_WALK:
ys = 50;
break;
case ACT_RUN:
ys = 70;
break;
case ACT_IDLE:
ys = 50;
break;
default:
ys = 90;
break;
}
pev->yaw_speed = ys;
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CAlienPanther :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
// ALERT( at_console, "event %d : %f\n", pEvent->event, pev->frame );
switch( pEvent->event )
{
case APANTHER_AE_CLAW:
{
// SOUND HERE!
CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.pantherDmgClaw, DMG_SLASH );
if ( pHurt )
{
if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) )
{
pHurt->pev->punchangle.z = -18;
pHurt->pev->punchangle.x = 5;
}
// Play a random attack hit sound
EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch );
}
else
{
// Play a random attack miss sound
EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch );
}
}
break;
case APANTHER_AE_CLAWRAKE:
{
CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.pantherDmgClawRake, DMG_SLASH );
if ( pHurt )
{
if ( pHurt->pev->flags & (FL_MONSTER|FL_CLIENT) )
{
pHurt->pev->punchangle.z = -18;
pHurt->pev->punchangle.x = 5;
}
EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackHitSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackHitSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch );
}
else
{
EMIT_SOUND_DYN ( ENT(pev), CHAN_WEAPON, pAttackMissSounds[ RANDOM_LONG(0,ARRAYSIZE(pAttackMissSounds)-1) ], 1.0, ATTN_NORM, 0, m_voicePitch );
}
}
break;
case APANTHER_AE_ZAP_POWERUP:
{
// speed up attack when on hard
if (g_iSkillLevel == SKILL_HARD)
pev->framerate = 1.5;
UTIL_MakeAimVectors( pev->angles );
if (m_iBeams == 0)
{
Vector vecSrc = pev->origin + gpGlobals->v_forward * 2;
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc );
WRITE_BYTE(TE_DLIGHT);
WRITE_COORD(vecSrc.x); // X
WRITE_COORD(vecSrc.y); // Y
WRITE_COORD(vecSrc.z); // Z
WRITE_BYTE( 12 ); // radius * 0.1
WRITE_BYTE( 255 ); // r
WRITE_BYTE( 180 ); // g
WRITE_BYTE( 96 ); // b
WRITE_BYTE( 20 / pev->framerate ); // time * 10
WRITE_BYTE( 0 ); // decay * 0.1
MESSAGE_END( );
}
if (m_hDead != NULL)
{
WackBeam( -1, m_hDead );
WackBeam( 1, m_hDead );
}
else
{
ArmBeam( -1 );
ArmBeam( 1 );
BeamGlow( );
}
EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "panther/p_zap2.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 );
pev->skin = m_iBeams / 2;
}
break;
case APANTHER_AE_ZAP_SHOOT:
{
ClearBeams( );
if (m_hDead != NULL)
{
Vector vecDest = m_hDead->pev->origin + Vector( 0, 0, 38 );
TraceResult trace;
UTIL_TraceHull( vecDest, vecDest, dont_ignore_monsters, human_hull, m_hDead->edict(), &trace );
if ( !trace.fStartSolid )
{
CBaseEntity *pNew = Create( "monster_alien_panther", m_hDead->pev->origin, m_hDead->pev->angles );
CBaseMonster *pNewMonster = pNew->MyMonsterPointer( );
pNew->pev->spawnflags |= 1;
WackBeam( -1, pNew );
WackBeam( 1, pNew );
UTIL_Remove( m_hDead );
EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "panther/p_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) );
/*
CBaseEntity *pEffect = Create( "test_effect", pNew->Center(), pev->angles );
pEffect->Use( this, this, USE_ON, 1 );
*/
break;
}
}
ClearMultiDamage();
UTIL_MakeAimVectors( pev->angles );
ZapBeam( -1 );
ZapBeam( 1 );
EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "panther/p_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) );
// STOP_SOUND( ENT(pev), CHAN_WEAPON, "debris/zap4.wav" );
ApplyMultiDamage(pev, pev);
m_flNextAttack = gpGlobals->time + RANDOM_FLOAT( 0.5, 4.0 );
}
break;
case APANTHER_AE_ZAP_DONE:
{
ClearBeams( );
}
break;
default:
CSquadMonster::HandleAnimEvent( pEvent );
break;
}
}
//=========================================================
// CheckRangeAttack1 - normal beam attack
//=========================================================
BOOL CAlienPanther :: CheckRangeAttack1 ( float flDot, float flDist )
{
if (m_flNextAttack > gpGlobals->time)
{
return FALSE;
}
return CSquadMonster::CheckRangeAttack1( flDot, flDist );
}
//=========================================================
// CheckRangeAttack2 - check bravery and try to resurect dead comrades
//=========================================================
BOOL CAlienPanther :: CheckRangeAttack2 ( float flDot, float flDist )
{
return FALSE;
if (m_flNextAttack > gpGlobals->time)
{
return FALSE;
}
m_hDead = NULL;
m_iBravery = 0;
CBaseEntity *pEntity = NULL;
while ((pEntity = UTIL_FindEntityByClassname( pEntity, "monster_alien_panther" )) != NULL)
{
TraceResult tr;
UTIL_TraceLine( EyePosition( ), pEntity->EyePosition( ), ignore_monsters, ENT(pev), &tr );
if (tr.flFraction == 1.0 || tr.pHit == pEntity->edict())
{
if (pEntity->pev->deadflag == DEAD_DEAD)
{
float d = (pev->origin - pEntity->pev->origin).Length();
if (d < flDist)
{
m_hDead = pEntity;
flDist = d;
}
m_iBravery--;
}
else
{
m_iBravery++;
}
}
}
if (m_hDead != NULL)
return TRUE;
else
return FALSE;
}
//=========================================================
// StartTask
//=========================================================
void CAlienPanther :: StartTask ( Task_t *pTask )
{
ClearBeams( );
CSquadMonster :: StartTask ( pTask );
}
//=========================================================
// Spawn
//=========================================================
void CAlienPanther :: Spawn()
{
Precache( );
SET_MODEL(ENT(pev), "models/panther.mdl");
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
pev->effects = 0;
pev->health = gSkillData.pantherHealth;
pev->view_ofs = Vector ( 0, 0, 64 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_RANGE_ATTACK2 | bits_CAP_DOORS_GROUP;
m_voicePitch = RANDOM_LONG( 85, 110 );
MonsterInit();
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CAlienPanther :: Precache()
{
int i;
PRECACHE_MODEL("models/panther.mdl");
PRECACHE_MODEL("sprites/lgtning.spr");
PRECACHE_SOUND("panther/p_zap1.wav");
PRECACHE_SOUND("panther/p_zap2.wav");
PRECACHE_SOUND("panther/p_electro1.wav");
PRECACHE_SOUND("panther/p_shoot1.wav");
PRECACHE_SOUND("panther/p_pain1.wav");
PRECACHE_SOUND("panther/p_pain2.wav");
PRECACHE_SOUND("panther/p_headbite.wav");
//PRECACHE_SOUND("weapons/cbar_miss1.wav");
for ( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND((char *)pAttackHitSounds[i]);
for ( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
PRECACHE_SOUND((char *)pAttackMissSounds[i]);
for ( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND((char *)pPainSounds[i]);
for ( i = 0; i < ARRAYSIZE( pDeathSounds ); i++ )
PRECACHE_SOUND((char *)pDeathSounds[i]);
UTIL_PrecacheOther( "test_effect" );
}
//=========================================================
// TakeDamage - get provoked when injured
//=========================================================
int CAlienPanther :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType)
{
// don't slash one of your own
if ((bitsDamageType & DMG_SLASH) && pevAttacker && IRelationship( Instance(pevAttacker) ) < R_DL)
return 0;
m_afMemory |= bits_MEMORY_PROVOKED;
return CSquadMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
}
void CAlienPanther::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
{
if (bitsDamageType & DMG_SHOCK)
return;
CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
}
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
// primary range attack
Task_t tlPantherAttack1[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_FACE_IDEAL, (float)0 },
{ TASK_RANGE_ATTACK1, (float)0 },
};
Schedule_t slPantherAttack1[] =
{
{
tlPantherAttack1,
ARRAYSIZE ( tlPantherAttack1 ),
bits_COND_CAN_MELEE_ATTACK1 |
bits_COND_HEAR_SOUND |
bits_COND_HEAVY_DAMAGE,
bits_SOUND_DANGER,
"Panther Range Attack1"
},
};
DEFINE_CUSTOM_SCHEDULES( CAlienPanther )
{
slPantherAttack1,
};
IMPLEMENT_CUSTOM_SCHEDULES( CAlienPanther, CSquadMonster );
//=========================================================
//=========================================================
Schedule_t *CAlienPanther :: GetSchedule( void )
{
ClearBeams( );
/*
if (pev->spawnflags)
{
pev->spawnflags = 0;
return GetScheduleOfType( SCHED_RELOAD );
}
*/
if ( HasConditions( bits_COND_HEAR_SOUND ) )
{
CSound *pSound;
pSound = PBestSound();
ASSERT( pSound != NULL );
if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) )
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND );
if ( pSound->m_iType & bits_SOUND_COMBAT )
m_afMemory |= bits_MEMORY_PROVOKED;
}
switch (m_MonsterState)
{
case MONSTERSTATE_COMBAT:
// dead enemy
if ( HasConditions( bits_COND_ENEMY_DEAD ) )
{
// call base class, all code to handle dead enemies is centralized there.
return CBaseMonster :: GetSchedule();
}
if (pev->health < 20 || m_iBravery < 0)
{
if (!HasConditions( bits_COND_CAN_MELEE_ATTACK1 ))
{
m_failSchedule = SCHED_CHASE_ENEMY;
if (HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE))
{
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
}
if ( HasConditions ( bits_COND_SEE_ENEMY ) && HasConditions ( bits_COND_ENEMY_FACING_ME ) )
{
// ALERT( at_console, "exposed\n");
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
}
}
}
break;
}
return CSquadMonster::GetSchedule( );
}
Schedule_t *CAlienPanther :: GetScheduleOfType ( int Type )
{
switch ( Type )
{
case SCHED_FAIL:
if (HasConditions( bits_COND_CAN_MELEE_ATTACK1 ))
{
return CSquadMonster :: GetScheduleOfType( SCHED_MELEE_ATTACK1 ); ;
}
break;
case SCHED_RANGE_ATTACK1:
return slPantherAttack1;
case SCHED_RANGE_ATTACK2:
return slPantherAttack1;
}
return CSquadMonster :: GetScheduleOfType( Type );
}
//=========================================================
// ArmBeam - small beam from arm to nearby geometry
//=========================================================
void CAlienPanther :: ArmBeam( int side )
{
TraceResult tr;
float flDist = 1.0;
if (m_iBeams >= APANTHER_MAX_BEAMS)
return;
UTIL_MakeAimVectors( pev->angles );
Vector vecSrc = pev->origin + gpGlobals->v_up * 36 + gpGlobals->v_right * side * 16 + gpGlobals->v_forward * 32;
for (int i = 0; i < 3; i++)
{
Vector vecAim = gpGlobals->v_right * side * RANDOM_FLOAT( 0, 1 ) + gpGlobals->v_up * RANDOM_FLOAT( -1, 1 );
TraceResult tr1;
UTIL_TraceLine ( vecSrc, vecSrc + vecAim * 512, dont_ignore_monsters, ENT( pev ), &tr1);
if (flDist > tr1.flFraction)
{
tr = tr1;
flDist = tr.flFraction;
}
}
// Couldn't find anything close enough
if ( flDist == 1.0 )
return;
DecalGunshot( &tr, BULLET_PLAYER_CROWBAR );
m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 );
if (!m_pBeam[m_iBeams])
return;
m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex( ) );
m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 );
// m_pBeam[m_iBeams]->SetColor( 180, 255, 96 );
m_pBeam[m_iBeams]->SetColor( 255, 0, 20 );//edit Alex
m_pBeam[m_iBeams]->SetBrightness( 64 );
m_pBeam[m_iBeams]->SetNoise( 80 );
m_iBeams++;
}
//=========================================================
// BeamGlow - brighten all beams
//=========================================================
void CAlienPanther :: BeamGlow( )
{
int b = m_iBeams * 32;
if (b > 255)
b = 255;
for (int i = 0; i < m_iBeams; i++)
{
if (m_pBeam[i]->GetBrightness() != 255)
{
m_pBeam[i]->SetBrightness( b );
}
}
}
//=========================================================
// WackBeam - regenerate dead colleagues
//=========================================================
void CAlienPanther :: WackBeam( int side, CBaseEntity *pEntity )
{
Vector vecDest;
float flDist = 1.0;
if (m_iBeams >= APANTHER_MAX_BEAMS)
return;
if (pEntity == NULL)
return;
m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 );
if (!m_pBeam[m_iBeams])
return;
m_pBeam[m_iBeams]->PointEntInit( pEntity->Center(), entindex( ) );
m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 );
m_pBeam[m_iBeams]->SetColor( 255, 0, 20 );
m_pBeam[m_iBeams]->SetBrightness( 255 );
m_pBeam[m_iBeams]->SetNoise( 80 );
m_iBeams++;
}
//=========================================================
// ZapBeam - heavy damage directly forward
//=========================================================
void CAlienPanther :: ZapBeam( int side )
{
Vector vecSrc, vecAim;
TraceResult tr;
CBaseEntity *pEntity;
if (m_iBeams >= APANTHER_MAX_BEAMS)
return;
vecSrc = pev->origin + gpGlobals->v_up * 36;
vecAim = ShootAtEnemy( vecSrc );
float deflection = 0.01;
vecAim = vecAim + side * gpGlobals->v_right * RANDOM_FLOAT( 0, deflection ) + gpGlobals->v_up * RANDOM_FLOAT( -deflection, deflection );
UTIL_TraceLine ( vecSrc, vecSrc + vecAim * 1024, dont_ignore_monsters, ENT( pev ), &tr);
m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 50 );
if (!m_pBeam[m_iBeams])
return;
m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex( ) );
m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 );
m_pBeam[m_iBeams]->SetColor( 255, 0, 20 );//modified Alex, was (180, 255, 96)
m_pBeam[m_iBeams]->SetBrightness( 255 );
m_pBeam[m_iBeams]->SetNoise( 20 );
m_iBeams++;
pEntity = CBaseEntity::Instance(tr.pHit);
if (pEntity != NULL && pEntity->pev->takedamage)
{
pEntity->TraceAttack( pev, gSkillData.pantherDmgZap, vecAim, &tr, DMG_SHOCK );
}
UTIL_EmitAmbientSound( ENT(pev), tr.vecEndPos, "panther/p_electro1.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) );
}
//=========================================================
// ClearBeams - remove all beams
//=========================================================
void CAlienPanther :: ClearBeams( )
{
for (int i = 0; i < APANTHER_MAX_BEAMS; i++)
{
if (m_pBeam[i])
{
UTIL_Remove( m_pBeam[i] );
m_pBeam[i] = NULL;
}
}
m_iBeams = 0;
pev->skin = 0;
STOP_SOUND( ENT(pev), CHAN_WEAPON, "panther/p_zap1.wav" );
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,78 @@
/***
*
* Copyright (c) 1996-2002, 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 "nodes.h"
#include "player.h"
enum barneyglock_e
{
BARNEYGLOCK_IDLE1 = 0,
BARNEYGLOCK_IDLE2,
BARNEYGLOCK_IDLE3,
BARNEYGLOCK_SHOOT,
BARNEYGLOCK_SHOOT_EMPTY,
BARNEYGLOCK_RELOAD,
BARNEYGLOCK_RELOAD_NOT_EMPTY,
BARNEYGLOCK_DRAW,
BARNEYGLOCK_HOLSTER,
BARNEYGLOCK_ADD_SILENCER
};
LINK_ENTITY_TO_CLASS( weapon_barney9mmhg, CBarneyGlock )
void CBarneyGlock::Spawn()
{
Precache();
m_iId = WEAPON_BARNEYGLOCK;
SET_MODEL( ENT( pev ), "models/w_9mmhandgun.mdl" );
m_iDefaultAmmo = GLOCK_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
void CBarneyGlock::Precache( void )
{
PRECACHE_MODEL( "models/v_barney9mmhg.mdl" );
CGlock::Precache();
}
int CBarneyGlock::GetItemInfo( ItemInfo *p )
{
p->pszName = STRING( pev->classname );
p->pszAmmo1 = "9mm";
p->iMaxAmmo1 = _9MM_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = GLOCK_MAX_CLIP;
p->iSlot = 1;
p->iPosition = 1;
p->iFlags = 0;
p->iId = m_iId = WEAPON_BARNEYGLOCK;
p->iWeight = GLOCK_WEIGHT;
return 1;
}
BOOL CBarneyGlock::Deploy()
{
// pev->body = 1;
return DefaultDeploy( "models/v_barney9mmhg.mdl", "models/p_9mmhandgun.mdl", BARNEYGLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 );
}

81
dlls/asheep/barneyhg.cpp Normal file
View File

@ -0,0 +1,81 @@
/***
*
* Copyright (c) 1996-2002, 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 "nodes.h"
#include "player.h"
#define HANDGRENADE_PRIMARY_VOLUME 450
enum barneyhandgrenade_e
{
BARNEYHANDGRENADE_IDLE = 0,
BARNEYHANDGRENADE_FIDGET,
BARNEYHANDGRENADE_PINPULL,
BARNEYHANDGRENADE_THROW1, // toss
BARNEYHANDGRENADE_THROW2, // medium
BARNEYHANDGRENADE_THROW3, // hard
BARNEYHANDGRENADE_HOLSTER,
BARNEYHANDGRENADE_DRAW
};
LINK_ENTITY_TO_CLASS( weapon_barneyhandgrenade, CBarneyHandGrenade )
void CBarneyHandGrenade::Spawn()
{
Precache();
m_iId = WEAPON_BARNEYHANDGRENADE;
SET_MODEL( ENT( pev ), "models/w_grenade.mdl" );
#ifndef CLIENT_DLL
pev->dmg = gSkillData.plrDmgHandGrenade;
#endif
m_iDefaultAmmo = HANDGRENADE_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
void CBarneyHandGrenade::Precache( void )
{
PRECACHE_MODEL( "models/v_barneygrenade.mdl" );
CHandGrenade::Precache();
}
int CBarneyHandGrenade::GetItemInfo( ItemInfo *p )
{
p->pszName = STRING( pev->classname );
p->pszAmmo1 = "Hand Grenade";
p->iMaxAmmo1 = HANDGRENADE_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 4;
p->iPosition = 1;
p->iId = m_iId = WEAPON_BARNEYHANDGRENADE;
p->iWeight = HANDGRENADE_WEIGHT;
p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE;
return 1;
}
BOOL CBarneyHandGrenade::Deploy()
{
m_flReleaseThrow = -1;
return DefaultDeploy( "models/v_barneygrenade.mdl", "models/p_grenade.mdl", BARNEYHANDGRENADE_DRAW, "crowbar" );
}

78
dlls/asheep/barneymp5.cpp Normal file
View File

@ -0,0 +1,78 @@
/***
*
* Copyright (c) 1996-2002, 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 "nodes.h"
#include "player.h"
#include "soundent.h"
#include "gamerules.h"
enum barneymp5_e
{
BARNEYMP5_LONGIDLE = 0,
BARNEYMP5_IDLE1,
BARNEYMP5_LAUNCH,
BARNEYMP5_RELOAD,
BARNEYMP5_DEPLOY,
BARNEYMP5_FIRE1,
BARNEYMP5_FIRE2,
BARNEYMP5_FIRE3,
BARNEYMP5_HOLSTER
};
LINK_ENTITY_TO_CLASS( weapon_barney9mmar, CBarneyMP5 )
void CBarneyMP5::Spawn()
{
Precache();
SET_MODEL( ENT( pev ), "models/w_9mmAR.mdl" );
m_iId = WEAPON_BARNEYMP5;
m_iDefaultAmmo = MP5_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
void CBarneyMP5::Precache( void )
{
PRECACHE_MODEL( "models/v_barney9mmar.mdl" );
CMP5::Precache();
}
int CBarneyMP5::GetItemInfo( ItemInfo *p )
{
p->pszName = STRING( pev->classname );
p->pszAmmo1 = "9mm";
p->iMaxAmmo1 = _9MM_MAX_CARRY;
p->pszAmmo2 = "ARgrenades";
p->iMaxAmmo2 = M203_GRENADE_MAX_CARRY;
p->iMaxClip = MP5_MAX_CLIP;
p->iSlot = 2;
p->iPosition = 1;
p->iFlags = 0;
p->iId = m_iId = WEAPON_BARNEYMP5;
p->iWeight = MP5_WEIGHT;
return 1;
}
BOOL CBarneyMP5::Deploy()
{
return DefaultDeploy( "models/v_barney9mmar.mdl", "models/p_9mmAR.mdl", BARNEYMP5_DEPLOY, "barneymp5" );
}

View File

@ -0,0 +1,82 @@
/***
*
* Copyright (c) 1996-2002, 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 "nodes.h"
#include "player.h"
#include "gamerules.h"
// special deathmatch shotgun spreads
#define VECTOR_CONE_DM_SHOTGUN Vector( 0.08716, 0.04362, 0.00 )// 10 degrees by 5 degrees
#define VECTOR_CONE_DM_DOUBLESHOTGUN Vector( 0.17365, 0.04362, 0.00 ) // 20 degrees by 5 degrees
enum barneyshotgun_e
{
BARNEYSHOTGUN_IDLE = 0,
BARNEYSHOTGUN_FIRE,
BARNEYSHOTGUN_FIRE2,
BARNEYSHOTGUN_RELOAD,
BARNEYSHOTGUN_PUMP,
BARNEYSHOTGUN_START_RELOAD,
BARNEYSHOTGUN_DRAW,
BARNEYSHOTGUN_HOLSTER,
BARNEYSHOTGUN_IDLE4,
BARNEYSHOTGUN_IDLE_DEEP
};
LINK_ENTITY_TO_CLASS( weapon_barneyshotgun, CBarneyShotgun )
void CBarneyShotgun::Spawn()
{
Precache();
m_iId = WEAPON_BARNEYSHOTGUN;
SET_MODEL( ENT( pev ), "models/w_shotgun.mdl" );
m_iDefaultAmmo = SHOTGUN_DEFAULT_GIVE;
FallInit();// get ready to fall
}
void CBarneyShotgun::Precache( void )
{
PRECACHE_MODEL( "models/v_barneyshotgun.mdl" );
CShotgun::Precache();
}
int CBarneyShotgun::GetItemInfo( ItemInfo *p )
{
p->pszName = STRING( pev->classname );
p->pszAmmo1 = "buckshot";
p->iMaxAmmo1 = BUCKSHOT_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = SHOTGUN_MAX_CLIP;
p->iSlot = 2;
p->iPosition = 3;
p->iFlags = 0;
p->iId = m_iId = WEAPON_BARNEYSHOTGUN;
p->iWeight = SHOTGUN_WEIGHT;
return 1;
}
BOOL CBarneyShotgun::Deploy()
{
return DefaultDeploy( "models/v_barneyshotgun.mdl", "models/p_shotgun.mdl", BARNEYSHOTGUN_DRAW, "shotgun" );
}

View File

@ -1,6 +1,6 @@
/***
*
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
@ -27,324 +27,67 @@
#include "scripted.h"
#include "weapons.h"
#include "soundent.h"
#include "barney.h"
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
// first flag is barniel dying for scripted sequences?
#define BARNIEL_AE_DRAW ( 2 )
#define BARNIEL_AE_SHOOT ( 3 )
#define BARNIEL_AE_HOLSTER ( 4 )
// first flag is barney dying for scripted sequences?
#define BARNIEL_BODY_GUNHOLSTERED 0
#define BARNIEL_BODY_GUNDRAWN 1
#define BARNIEL_BODY_GUNGONE 2
class CBarniel : public CTalkMonster
class CBarniel : public CBarney
{
public:
void Spawn( void );
void Precache( void );
void SetYawSpeed( void );
int ISoundMask( void );
void BarnielFirePistol( void );
void AlertSound( void );
int Classify ( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
void Spawn( void );
void Precache( void );
void BarneyFirePistol( void );
void AlertSound( void );
CBaseEntity* CheckTraceHullAttack( float flDist, int iDamage, int iDmgType );
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
void RunTask( Task_t *pTask );
void StartTask( Task_t *pTask );
virtual int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; }
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
BOOL CheckRangeAttack1 ( float flDot, float flDist );
void DeclineFollowing( void );
void DeclineFollowing( void );
// Override these to set behavior
Schedule_t *GetSchedule( void );
// Override these to set behavior
Schedule_t *GetScheduleOfType ( int Type );
Schedule_t *GetSchedule ( void );
MONSTERSTATE GetIdealState ( void );
void DeathSound( void );
void PainSound( void );
void DeathSound( void );
void PainSound( void );
void TalkInit( void );
void TalkInit( void );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
void Killed( entvars_t *pevAttacker, int iGib );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
BOOL m_fGunDrawn;
float m_painTime;
float m_checkAttackTime;
BOOL m_lastAttackCheck;
// UNDONE: What is this for? It isn't used?
float m_flPlayerDamage;// how much pain has the player inflicted on me?
CUSTOM_SCHEDULES;
int m_iCombatState;
};
LINK_ENTITY_TO_CLASS( monster_barniel, CBarniel );
LINK_ENTITY_TO_CLASS( monster_barniel, CBarniel )
TYPEDESCRIPTION CBarniel::m_SaveData[] =
{
DEFINE_FIELD( CBarniel, m_fGunDrawn, FIELD_BOOLEAN ),
DEFINE_FIELD( CBarniel, m_painTime, FIELD_TIME ),
DEFINE_FIELD( CBarniel, m_checkAttackTime, FIELD_TIME ),
DEFINE_FIELD( CBarniel, m_lastAttackCheck, FIELD_BOOLEAN ),
DEFINE_FIELD( CBarniel, m_flPlayerDamage, FIELD_FLOAT ),
};
IMPLEMENT_SAVERESTORE( CBarniel, CTalkMonster );
extern Schedule_t slBaFollow[];
extern Schedule_t slBarneyEnemyDraw[];
extern Schedule_t slBaFaceTarget[];
extern Schedule_t slIdleBaStand[];
extern Schedule_t slGruntHideReload[];
//=========================================================
// AI Schedules Specific to this monster
// ALertSound - barney says "Freeze!"
//=========================================================
Task_t tlBa1Follow[] =
{
{ TASK_MOVE_TO_TARGET_RANGE,(float)128 }, // Move within 128 of target ent (client)
{ TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE },
};
Schedule_t slBa1Follow[] =
void CBarniel::AlertSound( void )
{
if( m_hEnemy != 0 )
{
tlBa1Follow,
ARRAYSIZE ( tlBa1Follow ),
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND |
bits_COND_PROVOKED,
bits_SOUND_DANGER,
"Follow"
},
};
//=========================================================
// BarnielDraw- much better looking draw schedule for when
// barniel knows who he's gonna attack.
//=========================================================
Task_t tlBarnielEnemyDraw[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_FACE_ENEMY, 0 },
{ TASK_PLAY_SEQUENCE_FACE_ENEMY, (float) ACT_ARM },
};
Schedule_t slBarnielEnemyDraw[] =
{
{
tlBarnielEnemyDraw,
ARRAYSIZE ( tlBarnielEnemyDraw ),
0,
0,
"Barniel Enemy Draw"
}
};
Task_t tlBa1FaceTarget[] =
{
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_FACE_TARGET, (float)0 },
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE },
};
Schedule_t slBa1FaceTarget[] =
{
{
tlBa1FaceTarget,
ARRAYSIZE ( tlBa1FaceTarget ),
bits_COND_CLIENT_PUSH |
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND |
bits_COND_PROVOKED,
bits_SOUND_DANGER,
"FaceTarget"
},
};
Task_t tlIdleBa1Stand[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds.
{ TASK_TLK_HEADRESET, (float)0 }, // reset head position
};
Schedule_t slIdleBa1Stand[] =
{
{
tlIdleBa1Stand,
ARRAYSIZE ( tlIdleBa1Stand ),
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND |
bits_COND_SMELL |
bits_COND_PROVOKED,
bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code.
//bits_SOUND_PLAYER |
//bits_SOUND_WORLD |
bits_SOUND_DANGER |
bits_SOUND_MEAT |// scents
bits_SOUND_CARCASS |
bits_SOUND_GARBAGE,
"IdleStand"
},
};
DEFINE_CUSTOM_SCHEDULES( CBarniel )
{
slBa1Follow,
slBarnielEnemyDraw,
slBa1FaceTarget,
slIdleBa1Stand,
};
IMPLEMENT_CUSTOM_SCHEDULES( CBarniel, CTalkMonster );
void CBarniel :: StartTask( Task_t *pTask )
{
CTalkMonster::StartTask( pTask );
}
void CBarniel :: RunTask( Task_t *pTask )
{
switch ( pTask->iTask )
{
case TASK_RANGE_ATTACK1:
if (m_hEnemy != NULL && (m_hEnemy->IsPlayer()))
if( FOkToSpeak() )
{
pev->framerate = 1.5;
}
CTalkMonster::RunTask( pTask );
break;
default:
CTalkMonster::RunTask( pTask );
break;
}
}
//=========================================================
// ISoundMask - returns a bit mask indicating which types
// of sounds this monster regards.
//=========================================================
int CBarniel :: ISoundMask ( void)
{
return bits_SOUND_WORLD |
bits_SOUND_COMBAT |
bits_SOUND_CARCASS |
bits_SOUND_MEAT |
bits_SOUND_GARBAGE |
bits_SOUND_DANGER |
bits_SOUND_PLAYER;
}
//=========================================================
// Classify - indicates this monster's place in the
// relationship table.
//=========================================================
int CBarniel :: Classify ( void )
{
return CLASS_PLAYER_ALLY;
}
//=========================================================
// ALertSound - barniel says "Freeze!"
//=========================================================
void CBarniel :: AlertSound( void )
{
if ( m_hEnemy != NULL )
{
if ( FOkToSpeak() )
{
PlaySentence( "BN_ATTACK", RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE );
PlaySentence( "BN_ATTACK", RANDOM_FLOAT( 2.8, 3.2 ), VOL_NORM, ATTN_IDLE );
}
}
}
//=========================================================
// SetYawSpeed - allows each sequence to have a different
// turn rate associated with it.
//=========================================================
void CBarniel :: SetYawSpeed ( void )
{
int ys;
ys = 0;
switch ( m_Activity )
{
case ACT_IDLE:
ys = 70;
break;
case ACT_WALK:
ys = 70;
break;
case ACT_RUN:
ys = 90;
break;
default:
ys = 70;
break;
}
pev->yaw_speed = ys;
}
//=========================================================
// CheckRangeAttack1
// BarneyFirePistol - shoots one round from the pistol at
// the enemy barney is facing.
//=========================================================
BOOL CBarniel :: CheckRangeAttack1 ( float flDot, float flDist )
{
if ( flDist <= 1024 && flDot >= 0.5 )
{
if ( gpGlobals->time > m_checkAttackTime )
{
TraceResult tr;
Vector shootOrigin = pev->origin + Vector( 0, 0, 55 );
CBaseEntity *pEnemy = m_hEnemy;
Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP );
UTIL_TraceLine( shootOrigin, shootTarget, dont_ignore_monsters, ENT(pev), &tr );
m_checkAttackTime = gpGlobals->time + 1;
if ( tr.flFraction == 1.0 || (tr.pHit != NULL && CBaseEntity::Instance(tr.pHit) == pEnemy) )
m_lastAttackCheck = TRUE;
else
m_lastAttackCheck = FALSE;
m_checkAttackTime = gpGlobals->time + 1.5;
}
return m_lastAttackCheck;
}
return FALSE;
}
//=========================================================
// BarnielFirePistol - shoots one round from the pistol at
// the enemy barniel is facing.
//=========================================================
void CBarniel :: BarnielFirePistol ( void )
void CBarniel::BarneyFirePistol( void )
{
Vector vecShootOrigin;
UTIL_MakeVectors(pev->angles);
UTIL_MakeVectors( pev->angles );
vecShootOrigin = pev->origin + Vector( 0, 0, 55 );
Vector vecShootDir = ShootAtEnemy( vecShootOrigin );
@ -352,177 +95,144 @@ void CBarniel :: BarnielFirePistol ( void )
SetBlending( 0, angDir.x );
pev->effects = EF_MUZZLEFLASH;
FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_9MM );
FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_9MM );
int pitchShift = RANDOM_LONG( 0, 20 );
// Only shift about half the time
if ( pitchShift > 10 )
if( pitchShift > 10 )
pitchShift = 0;
else
pitchShift -= 5;
EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "barniel/bn_attack2.wav", 1, ATTN_NORM, 0, 100 + pitchShift );
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "barniel/bn_attack2.wav", 1, ATTN_NORM, 0, 100 + pitchShift );
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 );
CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, 384, 0.3 );
// UNDONE: Reload?
m_cAmmoLoaded--;// take away a bullet!
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CBarniel :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
switch( pEvent->event )
{
case BARNIEL_AE_SHOOT:
BarnielFirePistol();
break;
case BARNIEL_AE_DRAW:
// barniel's bodygroup switches here so he can pull gun from holster
pev->body = BARNIEL_BODY_GUNDRAWN;
m_fGunDrawn = TRUE;
break;
case BARNIEL_AE_HOLSTER:
// change bodygroup to replace gun in holster
pev->body = BARNIEL_BODY_GUNHOLSTERED;
m_fGunDrawn = FALSE;
break;
default:
CTalkMonster::HandleAnimEvent( pEvent );
}
}
//=========================================================
// Spawn
//=========================================================
void CBarniel :: Spawn()
void CBarniel::Spawn()
{
Precache( );
Precache();
SET_MODEL( ENT( pev ), "models/barniel.mdl" );
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
SET_MODEL(ENT(pev), "models/barniel.mdl");
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
pev->health = gSkillData.barneyHealth;
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE;
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
pev->health = gSkillData.barneyHealth;
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE;
pev->body = 0; // gun in holster
m_fGunDrawn = FALSE;
pev->body = 0; // gun in holster
m_fGunDrawn = FALSE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
m_cAmmoLoaded = GLOCK_MAX_CLIP;
m_iCombatState = -1;
MonsterInit();
SetUse( &CBarniel::FollowerUse );
SetUse( &CTalkMonster::FollowerUse );
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CBarniel :: Precache()
void CBarniel::Precache()
{
PRECACHE_MODEL("models/barniel.mdl");
PRECACHE_MODEL( "models/barniel.mdl" );
PRECACHE_SOUND("barniel/bn_attack1.wav" );
PRECACHE_SOUND("barniel/bn_attack2.wav" );
PRECACHE_SOUND( "barniel/bn_attack1.wav" );
PRECACHE_SOUND( "barniel/bn_attack2.wav" );
PRECACHE_SOUND("barniel/bn_pain1.wav");
//PRECACHE_SOUND("barniel/bn_pain2.wav");
//PRECACHE_SOUND("barniel/bn_pain3.wav");
PRECACHE_SOUND( "barniel/bn_pain1.wav" );
PRECACHE_SOUND("barniel/bn_die1.wav");
//PRECACHE_SOUND("barniel/bn_die2.wav");
//PRECACHE_SOUND("barniel/bn_die3.wav");
PRECACHE_SOUND( "barniel/bn_die1.wav" );
// every new barniel must call this, otherwise
PRECACHE_SOUND( "weapons/reload3.wav" );
// every new barney must call this, otherwise
// when a level is loaded, nobody will talk (time is reset to 0)
TalkInit();
CTalkMonster::Precache();
}
// Init talk data
void CBarniel :: TalkInit()
void CBarniel::TalkInit()
{
CTalkMonster::TalkInit();
// scientists speach group names (group names are in sentences.txt)
m_szGrp[TLK_ANSWER] = "BN_ANSWER";
m_szGrp[TLK_ANSWER] = "BN_ANSWER";
m_szGrp[TLK_QUESTION] = "BN_QUESTION";
m_szGrp[TLK_IDLE] = "BN_IDLE";
m_szGrp[TLK_STARE] = "BN_STARE";
m_szGrp[TLK_USE] = "BN_OK";
m_szGrp[TLK_UNUSE] = "BN_WAIT";
m_szGrp[TLK_STOP] = "BN_STOP";
m_szGrp[TLK_IDLE] = "BN_IDLE";
m_szGrp[TLK_STARE] = "BN_STARE";
m_szGrp[TLK_USE] = "BN_OK";
m_szGrp[TLK_UNUSE] = "BN_WAIT";
m_szGrp[TLK_STOP] = "BN_STOP";
m_szGrp[TLK_NOSHOOT] = "BN_SCARED";
m_szGrp[TLK_HELLO] = "BN_HELLO";
m_szGrp[TLK_NOSHOOT] = "BN_SCARED";
m_szGrp[TLK_HELLO] = "BN_HELLO";
m_szGrp[TLK_PLHURT1] = "!BN_CUREA";
m_szGrp[TLK_PLHURT2] = "!BN_CUREB";
m_szGrp[TLK_PLHURT3] = "!BN_CUREC";
m_szGrp[TLK_PLHURT1] = "!BN_CUREA";
m_szGrp[TLK_PLHURT2] = "!BN_CUREB";
m_szGrp[TLK_PLHURT3] = "!BN_CUREC";
m_szGrp[TLK_PHELLO] = NULL; //"BN_PHELLO"; // UNDONE
m_szGrp[TLK_PIDLE] = NULL; //"BN_PIDLE"; // UNDONE
m_szGrp[TLK_PHELLO] = "BN_PHELLO"; // UNDONE
m_szGrp[TLK_PIDLE] = "BN_PIDLE"; // UNDONE
m_szGrp[TLK_PQUESTION] = "BN_PQUEST"; // UNDONE
m_szGrp[TLK_SMELL] = "BN_SMELL";
m_szGrp[TLK_SMELL] = "BN_SMELL";
m_szGrp[TLK_WOUND] = "BN_WOUND";
m_szGrp[TLK_MORTAL] = "BN_MORTAL";
m_szGrp[TLK_WOUND] = "BN_WOUND";
m_szGrp[TLK_MORTAL] = "BN_MORTAL";
// get voice for head - just one barniel voice for now
// get voice for head - just one barney voice for now
m_voicePitch = 100;
}
static BOOL IsFacing( entvars_t *pevTest, const Vector &reference )
{
Vector vecDir = (reference - pevTest->origin);
Vector vecDir = reference - pevTest->origin;
vecDir.z = 0;
vecDir = vecDir.Normalize();
Vector forward, angle;
angle = pevTest->v_angle;
angle.x = 0;
UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL );
// He's facing me, he meant it
if ( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so
if( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so
{
return TRUE;
}
return FALSE;
}
int CBarniel :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType)
int CBarniel::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
// make sure friends talk about it if player hurts talkmonsters...
int ret = CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
if ( !IsAlive() || pev->deadflag == DEAD_DYING )
int ret = CTalkMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
if( !IsAlive() || pev->deadflag == DEAD_DYING )
return ret;
if ( m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT) )
if( m_MonsterState != MONSTERSTATE_PRONE && ( pevAttacker->flags & FL_CLIENT ) )
{
m_flPlayerDamage += flDamage;
// This is a heurstic to determine if the player intended to harm me
// If I have an enemy, we can't establish intent (may just be crossfire)
if ( m_hEnemy == NULL )
if( m_hEnemy == 0 )
{
// If the player was facing directly at me, or I'm already suspicious, get mad
if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || IsFacing( pevAttacker, pev->origin ) )
if( ( m_afMemory & bits_MEMORY_SUSPICIOUS ) || IsFacing( pevAttacker, pev->origin ) )
{
// Alright, now I'm pissed!
PlaySentence( "BN_MAD", 4, VOL_NORM, ATTN_NORM );
@ -537,7 +247,7 @@ int CBarniel :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, flo
Remember( bits_MEMORY_SUSPICIOUS );
}
}
else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO )
else if( !( m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO )
{
PlaySentence( "BN_SHOT", 4, VOL_NORM, ATTN_NORM );
}
@ -546,128 +256,25 @@ int CBarniel :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, flo
return ret;
}
//=========================================================
// PainSound
//=========================================================
void CBarniel :: PainSound ( void )
void CBarniel::PainSound( void )
{
if (gpGlobals->time < m_painTime)
if( gpGlobals->time < m_painTime )
return;
m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75);
EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barniel/bn_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch());
m_painTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 0.75 );
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "barniel/bn_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch() );
}
//=========================================================
// DeathSound
//=========================================================
void CBarniel :: DeathSound ( void )
void CBarniel::DeathSound( void )
{
EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barniel/bn_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch());
}
void CBarniel::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
{
switch( ptr->iHitgroup)
{
case HITGROUP_CHEST:
case HITGROUP_STOMACH:
if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST))
{
flDamage = flDamage / 2;
}
break;
case 10:
if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB))
{
flDamage -= 20;
if (flDamage <= 0)
{
UTIL_Ricochet( ptr->vecEndPos, 1.0 );
flDamage = 0.01;
}
}
// always a head shot
ptr->iHitgroup = HITGROUP_HEAD;
break;
}
CTalkMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
}
void CBarniel::Killed( entvars_t *pevAttacker, int iGib )
{
if ( pev->body < BARNIEL_BODY_GUNGONE )
{// drop the gun!
Vector vecGunPos;
Vector vecGunAngles;
pev->body = BARNIEL_BODY_GUNGONE;
GetAttachment( 0, vecGunPos, vecGunAngles );
CBaseEntity *pGun = DropItem( "weapon_barney9mmhg", vecGunPos, vecGunAngles );
}
SetUse( NULL );
CTalkMonster::Killed( pevAttacker, iGib );
}
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
Schedule_t* CBarniel :: GetScheduleOfType ( int Type )
{
Schedule_t *psched;
switch( Type )
{
case SCHED_ARM_WEAPON:
if ( m_hEnemy != NULL )
{
// face enemy, then draw.
return slBarnielEnemyDraw;
}
break;
// Hook these to make a looping schedule
case SCHED_TARGET_FACE:
// call base class default so that barniel will talk
// when 'used'
psched = CTalkMonster::GetScheduleOfType(Type);
if (psched == slIdleStand)
return slBa1FaceTarget; // override this for different target face behavior
else
return psched;
case SCHED_TARGET_CHASE:
return slBa1Follow;
case SCHED_IDLE_STAND:
// call base class default so that scientist will talk
// when standing during idle
psched = CTalkMonster::GetScheduleOfType(Type);
if (psched == slIdleStand)
{
// just look straight ahead.
return slIdleBa1Stand;
}
else
return psched;
}
return CTalkMonster::GetScheduleOfType( Type );
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "barniel/bn_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch() );
}
//=========================================================
@ -676,18 +283,18 @@ Schedule_t* CBarniel :: GetScheduleOfType ( int Type )
// monster's member function to get a pointer to a schedule
// of the proper type.
//=========================================================
Schedule_t *CBarniel :: GetSchedule ( void )
Schedule_t *CBarniel::GetSchedule( void )
{
if ( HasConditions( bits_COND_HEAR_SOUND ) )
if( HasConditions( bits_COND_HEAR_SOUND ) )
{
CSound *pSound;
pSound = PBestSound();
ASSERT( pSound != NULL );
if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) )
if( pSound && (pSound->m_iType & bits_SOUND_DANGER) )
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND );
}
if ( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() )
if( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() )
{
PlaySentence( "BN_KILL", 4, VOL_NORM, ATTN_NORM );
}
@ -696,37 +303,39 @@ Schedule_t *CBarniel :: GetSchedule ( void )
{
case MONSTERSTATE_COMBAT:
{
// dead enemy
if ( HasConditions( bits_COND_ENEMY_DEAD ) )
// dead enemy
if( HasConditions( bits_COND_ENEMY_DEAD ) )
{
// call base class, all code to handle dead enemies is centralized there.
return CBaseMonster :: GetSchedule();
return CBaseMonster::GetSchedule();
}
// always act surprized with a new enemy
if ( HasConditions( bits_COND_NEW_ENEMY ) && HasConditions( bits_COND_LIGHT_DAMAGE) )
if( HasConditions( bits_COND_NEW_ENEMY ) && HasConditions( bits_COND_LIGHT_DAMAGE ) )
return GetScheduleOfType( SCHED_SMALL_FLINCH );
// wait for one schedule to draw gun
if (!m_fGunDrawn )
if( !m_fGunDrawn )
return GetScheduleOfType( SCHED_ARM_WEAPON );
if ( HasConditions( bits_COND_HEAVY_DAMAGE ) )
if( HasConditions( bits_COND_HEAVY_DAMAGE ) )
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
if( HasConditions( bits_COND_NO_AMMO_LOADED ) )
return GetScheduleOfType( SCHED_BARNEY_COVER_AND_RELOAD );
}
break;
case MONSTERSTATE_ALERT:
case MONSTERSTATE_IDLE:
if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE))
if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) )
{
// flinch if hurt
return GetScheduleOfType( SCHED_SMALL_FLINCH );
}
if ( m_hEnemy == NULL && IsFollowing() )
if( m_hEnemy == 0 && IsFollowing() )
{
if ( !m_hTargetEnt->IsAlive() )
if( !m_hTargetEnt->IsAlive() )
{
// UNDONE: Comment about the recently dead player here?
StopFollowing( FALSE );
@ -734,7 +343,7 @@ Schedule_t *CBarniel :: GetSchedule ( void )
}
else
{
if ( HasConditions( bits_COND_CLIENT_PUSH ) )
if( HasConditions( bits_COND_CLIENT_PUSH ) )
{
return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW );
}
@ -742,7 +351,7 @@ Schedule_t *CBarniel :: GetSchedule ( void )
}
}
if ( HasConditions( bits_COND_CLIENT_PUSH ) )
if( HasConditions( bits_COND_CLIENT_PUSH ) )
{
return GetScheduleOfType( SCHED_MOVE_AWAY );
}
@ -750,86 +359,14 @@ Schedule_t *CBarniel :: GetSchedule ( void )
// try to say something about smells
TrySmellTalk();
break;
default:
break;
}
return CTalkMonster::GetSchedule();
}
MONSTERSTATE CBarniel :: GetIdealState ( void )
{
return CTalkMonster::GetIdealState();
}
void CBarniel::DeclineFollowing( void )
{
PlaySentence( "BN_POK", 2, VOL_NORM, ATTN_NORM );
}
//=========================================================
// DEAD BARNIEL PROP
//
// Designer selects a pose in worldcraft, 0 through num_poses-1
// this value is added to what is selected as the 'first dead pose'
// among the monster's normal animations. All dead poses must
// appear sequentially in the model file. Be sure and set
// the m_iFirstPose properly!
//
//=========================================================
class CDeadBarniel : public CBaseMonster
{
public:
void Spawn( void );
int Classify ( void ) { return CLASS_PLAYER_ALLY; }
void KeyValue( KeyValueData *pkvd );
int m_iPose;// which sequence to display -- temporary, don't need to save
static char *m_szPoses[3];
};
char *CDeadBarniel::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" };
void CDeadBarniel::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "pose"))
{
m_iPose = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseMonster::KeyValue( pkvd );
}
LINK_ENTITY_TO_CLASS( monster_barniel_dead, CDeadBarniel );
//=========================================================
// ********** DeadBarniel SPAWN **********
//=========================================================
void CDeadBarniel :: Spawn( )
{
PRECACHE_MODEL("models/barniel.mdl");
SET_MODEL(ENT(pev), "models/barniel.mdl");
pev->effects = 0;
pev->yaw_speed = 8;
pev->sequence = 0;
m_bloodColor = BLOOD_COLOR_RED;
pev->sequence = LookupSequence( m_szPoses[m_iPose] );
if (pev->sequence == -1)
{
ALERT ( at_console, "Dead barniel with bad pose\n" );
}
// Corpses have less health
pev->health = 8;//gSkillData.barnielHealth;
MonsterInitDead();
}

View File

@ -94,6 +94,11 @@ BOOL CBeretta::Deploy( )
return DefaultDeploy( "models/v_9mmberetta.mdl", "models/p_9mmberetta.mdl", BERETTA_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 );
}
void CBeretta::Holster( int skiplocal /* = 0 */ )
{
DefaultHolster( BERETTA_HOLSTER, 1.2 );
}
void CBeretta::SecondaryAttack( void )
{
BerettaFire( 0.1, 0.2, FALSE );
@ -106,12 +111,18 @@ void CBeretta::PrimaryAttack( void )
void CBeretta::BerettaFire( float flSpread , float flCycleTime, BOOL fUseAutoAim )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if (m_iClip <= 0)
{
if (m_fFireOnEmpty)
{
PlayEmptySound();
m_flNextPrimaryAttack = GetNextAttackDelay(0.2);
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2f;
}
return;
@ -162,7 +173,7 @@ void CBeretta::BerettaFire( float flSpread , float flCycleTime, BOOL fUseAutoAim
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireBeretta1 : m_usFireBeretta2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 );
m_flNextPrimaryAttack = m_flNextSecondaryAttack = GetNextAttackDelay(flCycleTime);
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + flCycleTime;
if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
// HEV suit - indicate out of ammo condition
@ -174,15 +185,21 @@ void CBeretta::BerettaFire( float flSpread , float flCycleTime, BOOL fUseAutoAim
void CBeretta::Reload( void )
{
if ( m_pPlayer->ammo_9mm <= 0 )
return;
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == BERETTA_MAX_CLIP )
return;
int iResult;
if (m_iClip == 0)
iResult = DefaultReload( 17, BERETTA_RELOAD, 1.5 );
iResult = DefaultReload( BERETTA_MAX_CLIP, BERETTA_RELOAD, 1.5 );
else
iResult = DefaultReload( 17, BERETTA_RELOAD_NOT_EMPTY, 1.5 );
iResult = DefaultReload( BERETTA_MAX_CLIP, BERETTA_RELOAD_NOT_EMPTY, 1.5 );
if (iResult)
{
@ -190,11 +207,19 @@ void CBeretta::Reload( void )
}
}
void CBeretta::WeaponIdle( void )
{
ResetEmptySound( );
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
ResetEmptySound();
m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );

106
dlls/asheep/bodypart.cpp Normal file
View File

@ -0,0 +1,106 @@
/***
*
* 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 "basemonster.h"
#define SF_BODYPART_RANDOMYAW (1U << 3)
class CBodyPart : public CBaseMonster
{
public:
void Spawn();
void Precache();
int Classify();
};
LINK_ENTITY_TO_CLASS( monster_bodypart, CBodyPart )
int CBodyPart::Classify()
{
return CLASS_INSECT;
}
void CBodyPart::Spawn()
{
Precache();
SET_MODEL( ENT( pev ), STRING( pev->model ) );
pev->movetype = MOVETYPE_NONE;
pev->solid = SOLID_NOT;
m_bloodColor = BLOOD_COLOR_RED;
m_MonsterState = MONSTERSTATE_NONE;
pev->health = 80000; // !!!
pev->takedamage = DAMAGE_NO;
pev->deadflag = DEAD_DEAD;
pev->effects = 0;
pev->sequence = 0;
if( FBitSet( pev->spawnflags, SF_BODYPART_RANDOMYAW ) )
{
pev->angles = Vector( 0, RANDOM_LONG( 0, 360 ), 0 );
}
}
void CBodyPart::Precache()
{
int iRand;
switch( pev->body )
{
default:
case 0:
iRand = RANDOM_LONG( 0, 8 );
if( iRand == 8 )
{
pev->model = MAKE_STRING( "models/gib_hgrunt.mdl" );
pev->body = 0;
}
else
{
pev->model = MAKE_STRING( "models/hgibs.mdl" );
pev->body = ( iRand == 7 ) ? RANDOM_LONG( 7, 10 ) : iRand;
}
break;
case 1:
pev->model = MAKE_STRING( "models/hgibs.mdl" );
iRand = RANDOM_LONG( 0, 7 );
pev->body = ( iRand == 7 ) ? RANDOM_LONG( 7, 10 ) : iRand;
break;
case 2:
pev->model = MAKE_STRING( "models/gib_hgrunt.mdl" );
pev->body = 0;
break;
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
pev->model = MAKE_STRING( "models/hgibs.mdl" );
pev->body -= 3;
break;
}
PRECACHE_MODEL( STRING( pev->model ) );
}

186
dlls/asheep/garbage.cpp Normal file
View File

@ -0,0 +1,186 @@
/***
*
* 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 "basemonster.h"
#define SF_GARBAGE_RANDOMYAW (1U << 3)
// garbage's bodygroups
#define STRAINEDPAPER1 0
#define STRAINEDPAPER2 1
#define STRAINEDPAPER3 2
#define GLASS 4
#define SANDWICH 5
#define APPLE 6
#define BANANA 7
#define MAGAZINE 8
#define BROWNPAPER 9
#define BLUECAN 11
class CGarbage : public CBaseMonster
{
public:
void Spawn();
void Precache();
int Classify();
};
LINK_ENTITY_TO_CLASS( monster_garbage, CGarbage )
int CGarbage::Classify()
{
return CLASS_INSECT;
}
void CGarbage::Spawn()
{
Precache();
SET_MODEL( ENT( pev ), STRING( pev->model ) );
pev->movetype = MOVETYPE_NONE;
pev->solid = SOLID_NOT;
m_bloodColor = DONT_BLEED;
m_MonsterState = MONSTERSTATE_NONE;
pev->health = 80000; // !!!
pev->takedamage = DAMAGE_NO;
pev->deadflag = DEAD_DEAD;
pev->effects = 0;
pev->sequence = 0;
if( FBitSet( pev->spawnflags, SF_GARBAGE_RANDOMYAW ) )
{
pev->angles = Vector( 0, RANDOM_LONG( 0, 360 ), 0 );
}
}
void CGarbage::Precache()
{
int iRand;
switch( pev->body )
{
default:
case 0:
iRand = RANDOM_LONG( 0, 8 );
pev->model = MAKE_STRING( "models/garbagegibs.mdl" );
switch( iRand )
{
case 1:
pev->body = STRAINEDPAPER1;
break;
case 2:
case 3:
pev->body = STRAINEDPAPER2;
break;
case 4:
pev->body = GLASS;
break;
case 5:
case 6:
case 7:
pev->body = iRand + 1;
break;
default:
pev->body = BROWNPAPER;
break;
}
break;
case 1:
pev->body = RANDOM_LONG( 0, 2 );
pev->model = MAKE_STRING( "models/garbagegibs.mdl" );
break;
case 2:
iRand = RANDOM_LONG( 4, 8 );
if( iRand == 8 )
{
if( RANDOM_LONG( 0, 1 ) )
{
pev->model = MAKE_STRING( "models/garbagegibs.mdl" );
pev->body = 11;
}
else
{
pev->model = MAKE_STRING( "models/can.mdl" );
pev->body = 0;
pev->skin = RANDOM_LONG( 0, 5 );
}
}
else
{
pev->model = MAKE_STRING( "models/garbagegibs.mdl" );
pev->body = iRand;
}
break;
case 3:
pev->model = MAKE_STRING( "models/garbagegibs.mdl" );
pev->body = RANDOM_LONG( 8, 9 );
break;
case 4:
iRand = RANDOM_LONG( 0, 6 );
if( iRand == 6 )
{
pev->model = MAKE_STRING( "models/garbagegibs.mdl" );
pev->body = BLUECAN;
}
else
{
pev->model = MAKE_STRING( "models/can.mdl" );
pev->body = 0;
pev->skin = iRand;
}
break;
case 5:
pev->model = MAKE_STRING( "models/garbagegibs.mdl" );
pev->body = STRAINEDPAPER1;
break;
case 6:
case 7:
pev->model = MAKE_STRING( "models/garbagegibs.mdl" );
pev->body = STRAINEDPAPER2;
break;
case 8:
case 9:
case 10:
case 11:
pev->model = MAKE_STRING( "models/garbagegibs.mdl" );
pev->body -= 4;
break;
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
pev->model = MAKE_STRING( "models/can.mdl" );
pev->skin = pev->body - 12;
pev->body = 0;
break;
case 18:
pev->model = MAKE_STRING( "models/garbagegibs.mdl" );
pev->body = BLUECAN;
break;
case 19:
case 20:
pev->model = MAKE_STRING( "models/garbagegibs.mdl" );
pev->body -= 11;
break;
}
PRECACHE_MODEL( STRING( pev->model ) );
}

View File

@ -1,844 +0,0 @@
/***
*
* 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.
*
****/
//=========================================================
// monster template
//=========================================================
// UNDONE: Holster weapon?
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "talkmonster.h"
#include "schedule.h"
#include "defaultai.h"
#include "scripted.h"
#include "weapons.h"
#include "soundent.h"
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
// first flag is barney dying for scripted sequences?
#define GORDON_AE_DRAW ( 2 )
#define GORDON_AE_SHOOT ( 3 )
#define GORDON_AE_HOLSTER ( 4 )
#define GORDON_BODY_GUNHOLSTERED 0
#define GORDON_BODY_GUNDRAWN 1
#define GORDON_BODY_GUNGONE 2
class CGordon : public CTalkMonster
{
public:
void Spawn( void );
void Precache( void );
void SetYawSpeed( void );
int ISoundMask( void );
void GordonFirePistol( void );
void AlertSound( void );
int Classify ( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
void RunTask( Task_t *pTask );
void StartTask( Task_t *pTask );
virtual int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; }
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
BOOL CheckRangeAttack1 ( float flDot, float flDist );
void DeclineFollowing( void );
// Override these to set behavior
Schedule_t *GetScheduleOfType ( int Type );
Schedule_t *GetSchedule ( void );
MONSTERSTATE GetIdealState ( void );
void DeathSound( void );
void PainSound( void );
void TalkInit( void );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
void Killed( entvars_t *pevAttacker, int iGib );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
BOOL m_fGunDrawn;
float m_painTime;
float m_checkAttackTime;
BOOL m_lastAttackCheck;
// UNDONE: What is this for? It isn't used?
float m_flPlayerDamage;// how much pain has the player inflicted on me?
CUSTOM_SCHEDULES;
};
LINK_ENTITY_TO_CLASS( monster_gordon, CGordon );
TYPEDESCRIPTION CGordon::m_SaveData[] =
{
DEFINE_FIELD( CGordon, m_fGunDrawn, FIELD_BOOLEAN ),
DEFINE_FIELD( CGordon, m_painTime, FIELD_TIME ),
DEFINE_FIELD( CGordon, m_checkAttackTime, FIELD_TIME ),
DEFINE_FIELD( CGordon, m_lastAttackCheck, FIELD_BOOLEAN ),
DEFINE_FIELD( CGordon, m_flPlayerDamage, FIELD_FLOAT ),
};
IMPLEMENT_SAVERESTORE( CGordon, CTalkMonster );
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
Task_t tlGoFollow[] =
{
{ TASK_MOVE_TO_TARGET_RANGE,(float)128 }, // Move within 128 of target ent (client)
{ TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE },
};
Schedule_t slGoFollow[] =
{
{
tlGoFollow,
ARRAYSIZE ( tlGoFollow ),
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND |
bits_COND_PROVOKED,
bits_SOUND_DANGER,
"Follow"
},
};
//=========================================================
// GordonDraw- much better looking draw schedule for when
// barney knows who he's gonna attack.
//=========================================================
Task_t tlGordonEnemyDraw[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_FACE_ENEMY, 0 },
{ TASK_PLAY_SEQUENCE_FACE_ENEMY, (float) ACT_ARM },
};
Schedule_t slGordonEnemyDraw[] =
{
{
tlGordonEnemyDraw,
ARRAYSIZE ( tlGordonEnemyDraw ),
0,
0,
"Gordon Enemy Draw"
}
};
Task_t tlGoFaceTarget[] =
{
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_FACE_TARGET, (float)0 },
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE },
};
Schedule_t slGoFaceTarget[] =
{
{
tlGoFaceTarget,
ARRAYSIZE ( tlGoFaceTarget ),
bits_COND_CLIENT_PUSH |
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND |
bits_COND_PROVOKED,
bits_SOUND_DANGER,
"FaceTarget"
},
};
Task_t tlIdleGoStand[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds.
{ TASK_TLK_HEADRESET, (float)0 }, // reset head position
};
Schedule_t slIdleGoStand[] =
{
{
tlIdleGoStand,
ARRAYSIZE ( tlIdleGoStand ),
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND |
bits_COND_SMELL |
bits_COND_PROVOKED,
bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code.
//bits_SOUND_PLAYER |
//bits_SOUND_WORLD |
bits_SOUND_DANGER |
bits_SOUND_MEAT |// scents
bits_SOUND_CARCASS |
bits_SOUND_GARBAGE,
"IdleStand"
},
};
DEFINE_CUSTOM_SCHEDULES( CGordon )
{
slGoFollow,
slGordonEnemyDraw,
slGoFaceTarget,
slIdleGoStand,
};
IMPLEMENT_CUSTOM_SCHEDULES( CGordon, CTalkMonster );
void CGordon :: StartTask( Task_t *pTask )
{
CTalkMonster::StartTask( pTask );
}
void CGordon :: RunTask( Task_t *pTask )
{
switch ( pTask->iTask )
{
case TASK_RANGE_ATTACK1:
if (m_hEnemy != NULL && (m_hEnemy->IsPlayer()))
{
pev->framerate = 1.5;
}
CTalkMonster::RunTask( pTask );
break;
default:
CTalkMonster::RunTask( pTask );
break;
}
}
//=========================================================
// ISoundMask - returns a bit mask indicating which types
// of sounds this monster regards.
//=========================================================
int CGordon :: ISoundMask ( void)
{
return bits_SOUND_WORLD |
bits_SOUND_COMBAT |
bits_SOUND_CARCASS |
bits_SOUND_MEAT |
bits_SOUND_GARBAGE |
bits_SOUND_DANGER |
bits_SOUND_PLAYER;
}
//=========================================================
// Classify - indicates this monster's place in the
// relationship table.
//=========================================================
int CGordon :: Classify ( void )
{
return CLASS_PLAYER_ALLY;
}
//=========================================================
// ALertSound - barney says "Freeze!"
//=========================================================
void CGordon :: AlertSound( void )
{
if ( m_hEnemy != NULL )
{
if ( FOkToSpeak() )
{
PlaySentence( "GO_ATTACK", RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE );
}
}
}
//=========================================================
// SetYawSpeed - allows each sequence to have a different
// turn rate associated with it.
//=========================================================
void CGordon :: SetYawSpeed ( void )
{
int ys;
ys = 0;
switch ( m_Activity )
{
case ACT_IDLE:
ys = 70;
break;
case ACT_WALK:
ys = 70;
break;
case ACT_RUN:
ys = 90;
break;
default:
ys = 70;
break;
}
pev->yaw_speed = ys;
}
//=========================================================
// CheckRangeAttack1
//=========================================================
BOOL CGordon :: CheckRangeAttack1 ( float flDot, float flDist )
{
if ( flDist <= 1024 && flDot >= 0.5 )
{
if ( gpGlobals->time > m_checkAttackTime )
{
TraceResult tr;
Vector shootOrigin = pev->origin + Vector( 0, 0, 55 );
CBaseEntity *pEnemy = m_hEnemy;
Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP );
UTIL_TraceLine( shootOrigin, shootTarget, dont_ignore_monsters, ENT(pev), &tr );
m_checkAttackTime = gpGlobals->time + 1;
if ( tr.flFraction == 1.0 || (tr.pHit != NULL && CBaseEntity::Instance(tr.pHit) == pEnemy) )
m_lastAttackCheck = TRUE;
else
m_lastAttackCheck = FALSE;
m_checkAttackTime = gpGlobals->time + 1.5;
}
return m_lastAttackCheck;
}
return FALSE;
}
//=========================================================
// GordonFirePistol - shoots one round from the pistol at
// the enemy barney is facing.
//=========================================================
void CGordon :: GordonFirePistol ( void )
{
Vector vecShootOrigin;
UTIL_MakeVectors(pev->angles);
vecShootOrigin = pev->origin + Vector( 0, 0, 55 );
Vector vecShootDir = ShootAtEnemy( vecShootOrigin );
Vector angDir = UTIL_VecToAngles( vecShootDir );
SetBlending( 0, angDir.x );
pev->effects = EF_MUZZLEFLASH;
FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_9MM );
int pitchShift = RANDOM_LONG( 0, 20 );
// Only shift about half the time
if ( pitchShift > 10 )
pitchShift = 0;
else
pitchShift -= 5;
EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "gordon/go_attack2.wav", 1, ATTN_NORM, 0, 100 + pitchShift );
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 );
// UNDONE: Reload?
m_cAmmoLoaded--;// take away a bullet!
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CGordon :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
switch( pEvent->event )
{
case GORDON_AE_SHOOT:
GordonFirePistol();
break;
case GORDON_AE_DRAW:
// barney's bodygroup switches here so he can pull gun from holster
pev->body = GORDON_BODY_GUNDRAWN;
m_fGunDrawn = TRUE;
break;
case GORDON_AE_HOLSTER:
// change bodygroup to replace gun in holster
pev->body = GORDON_BODY_GUNHOLSTERED;
m_fGunDrawn = FALSE;
break;
default:
CTalkMonster::HandleAnimEvent( pEvent );
}
}
//=========================================================
// Spawn
//=========================================================
void CGordon :: Spawn()
{
Precache( );
SET_MODEL(ENT(pev), "models/freeman.mdl");
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
pev->health = gSkillData.barneyHealth;
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE;
pev->body = 0; // gun in holster
m_fGunDrawn = FALSE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
MonsterInit();
SetUse( &CGordon::FollowerUse );
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CGordon :: Precache()
{
PRECACHE_MODEL("models/freeman.mdl");
PRECACHE_SOUND("gordon/go_attack1.wav" );
PRECACHE_SOUND("gordon/go_attack2.wav" );
PRECACHE_SOUND("gordon/go_pain1.wav");
PRECACHE_SOUND("gordon/go_pain2.wav");
PRECACHE_SOUND("gordon/go_pain3.wav");
PRECACHE_SOUND("gordon/go_die1.wav");
PRECACHE_SOUND("gordon/go_die2.wav");
PRECACHE_SOUND("gordon/go_die3.wav");
PRECACHE_SOUND("gordon/go_duty.wav");
PRECACHE_SOUND("gordon/go_post.wav");
//PRECACHE_SOUND("gordon/goon.wav");
// every new barney must call this, otherwise
// when a level is loaded, nobody will talk (time is reset to 0)
TalkInit();
CTalkMonster::Precache();
}
// Init talk data
void CGordon :: TalkInit()
{
CTalkMonster::TalkInit();
// scientists speach group names (group names are in sentences.txt)
m_szGrp[TLK_ANSWER] = "GO_ANSWER";
m_szGrp[TLK_QUESTION] = "GO_QUESTION";
m_szGrp[TLK_IDLE] = "GO_IDLE";
m_szGrp[TLK_STARE] = "GO_STARE";
m_szGrp[TLK_USE] = "GO_OK";
m_szGrp[TLK_UNUSE] = "GO_WAIT";
m_szGrp[TLK_STOP] = "GO_STOP";
m_szGrp[TLK_NOSHOOT] = "GO_SCARED";
m_szGrp[TLK_HELLO] = "GO_HELLO";
m_szGrp[TLK_PLHURT1] = "!BA_CUREA";
m_szGrp[TLK_PLHURT2] = "!BA_CUREB";
m_szGrp[TLK_PLHURT3] = "!BA_CUREC";
m_szGrp[TLK_PHELLO] = NULL; //"GO_PHELLO"; // UNDONE
m_szGrp[TLK_PIDLE] = NULL; //"GO_PIDLE"; // UNDONE
m_szGrp[TLK_PQUESTION] = "GO_PQUEST"; // UNDONE
m_szGrp[TLK_SMELL] = "GO_SMELL";
m_szGrp[TLK_WOUND] = "GO_WOUND";
m_szGrp[TLK_MORTAL] = "GO_MORTAL";
// get voice for head - just one barney voice for now
m_voicePitch = 100;
}
static BOOL IsFacing( entvars_t *pevTest, const Vector &reference )
{
Vector vecDir = (reference - pevTest->origin);
vecDir.z = 0;
vecDir = vecDir.Normalize();
Vector forward, angle;
angle = pevTest->v_angle;
angle.x = 0;
UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL );
// He's facing me, he meant it
if ( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so
{
return TRUE;
}
return FALSE;
}
int CGordon :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType)
{
// make sure friends talk about it if player hurts talkmonsters...
int ret = CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
if ( !IsAlive() || pev->deadflag == DEAD_DYING )
return ret;
if ( m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT) )
{
m_flPlayerDamage += flDamage;
// This is a heurstic to determine if the player intended to harm me
// If I have an enemy, we can't establish intent (may just be crossfire)
if ( m_hEnemy == NULL )
{
// If the player was facing directly at me, or I'm already suspicious, get mad
if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || IsFacing( pevAttacker, pev->origin ) )
{
// Alright, now I'm pissed!
PlaySentence( "GO_MAD", 4, VOL_NORM, ATTN_NORM );
Remember( bits_MEMORY_PROVOKED );
StopFollowing( TRUE );
}
else
{
// Hey, be careful with that
PlaySentence( "GO_SHOT", 4, VOL_NORM, ATTN_NORM );
Remember( bits_MEMORY_SUSPICIOUS );
}
}
else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO )
{
PlaySentence( "GO_SHOT", 4, VOL_NORM, ATTN_NORM );
}
}
return ret;
}
//=========================================================
// PainSound
//=========================================================
void CGordon :: PainSound ( void )
{
if (gpGlobals->time < m_painTime)
return;
m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75);
switch (RANDOM_LONG(0,2))
{
case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "gordon/go_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "gordon/go_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "gordon/go_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
}
}
//=========================================================
// DeathSound
//=========================================================
void CGordon :: DeathSound ( void )
{
switch (RANDOM_LONG(0,2))
{
case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "gordon/go_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "gordon/go_die2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "gordon/go_die3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
}
}
void CGordon::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
{
switch( ptr->iHitgroup)
{
case HITGROUP_CHEST:
case HITGROUP_STOMACH:
if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST))
{
flDamage = flDamage / 2;
}
break;
case 10:
if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB))
{
flDamage -= 20;
if (flDamage <= 0)
{
UTIL_Ricochet( ptr->vecEndPos, 1.0 );
flDamage = 0.01;
}
}
// always a head shot
ptr->iHitgroup = HITGROUP_HEAD;
break;
}
CTalkMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
}
void CGordon::Killed( entvars_t *pevAttacker, int iGib )
{
if ( pev->body < GORDON_BODY_GUNGONE )
{// drop the gun!
Vector vecGunPos;
Vector vecGunAngles;
pev->body = GORDON_BODY_GUNGONE;
GetAttachment( 0, vecGunPos, vecGunAngles );
CBaseEntity *pGun = DropItem( "weapon_barney9mmhg", vecGunPos, vecGunAngles );
}
SetUse( NULL );
CTalkMonster::Killed( pevAttacker, iGib );
}
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
Schedule_t* CGordon :: GetScheduleOfType ( int Type )
{
Schedule_t *psched;
switch( Type )
{
case SCHED_ARM_WEAPON:
if ( m_hEnemy != NULL )
{
// face enemy, then draw.
return slGordonEnemyDraw;
}
break;
// Hook these to make a looping schedule
case SCHED_TARGET_FACE:
// call base class default so that barney will talk
// when 'used'
psched = CTalkMonster::GetScheduleOfType(Type);
if (psched == slIdleStand)
return slGoFaceTarget; // override this for different target face behavior
else
return psched;
case SCHED_TARGET_CHASE:
return slGoFollow;
case SCHED_IDLE_STAND:
// call base class default so that scientist will talk
// when standing during idle
psched = CTalkMonster::GetScheduleOfType(Type);
if (psched == slIdleStand)
{
// just look straight ahead.
return slIdleGoStand;
}
else
return psched;
}
return CTalkMonster::GetScheduleOfType( Type );
}
//=========================================================
// GetSchedule - Decides which type of schedule best suits
// the monster's current state and conditions. Then calls
// monster's member function to get a pointer to a schedule
// of the proper type.
//=========================================================
Schedule_t *CGordon :: GetSchedule ( void )
{
if ( HasConditions( bits_COND_HEAR_SOUND ) )
{
CSound *pSound;
pSound = PBestSound();
ASSERT( pSound != NULL );
if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) )
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND );
}
if ( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() )
{
PlaySentence( "GO_KILL", 4, VOL_NORM, ATTN_NORM );
}
switch( m_MonsterState )
{
case MONSTERSTATE_COMBAT:
{
// dead enemy
if ( HasConditions( bits_COND_ENEMY_DEAD ) )
{
// call base class, all code to handle dead enemies is centralized there.
return CBaseMonster :: GetSchedule();
}
// always act surprized with a new enemy
if ( HasConditions( bits_COND_NEW_ENEMY ) && HasConditions( bits_COND_LIGHT_DAMAGE) )
return GetScheduleOfType( SCHED_SMALL_FLINCH );
// wait for one schedule to draw gun
if (!m_fGunDrawn )
return GetScheduleOfType( SCHED_ARM_WEAPON );
if ( HasConditions( bits_COND_HEAVY_DAMAGE ) )
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
}
break;
case MONSTERSTATE_ALERT:
case MONSTERSTATE_IDLE:
if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE))
{
// flinch if hurt
return GetScheduleOfType( SCHED_SMALL_FLINCH );
}
if ( m_hEnemy == NULL && IsFollowing() )
{
if ( !m_hTargetEnt->IsAlive() )
{
// UNDONE: Comment about the recently dead player here?
StopFollowing( FALSE );
break;
}
else
{
if ( HasConditions( bits_COND_CLIENT_PUSH ) )
{
return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW );
}
return GetScheduleOfType( SCHED_TARGET_FACE );
}
}
if ( HasConditions( bits_COND_CLIENT_PUSH ) )
{
return GetScheduleOfType( SCHED_MOVE_AWAY );
}
// try to say something about smells
TrySmellTalk();
break;
}
return CTalkMonster::GetSchedule();
}
MONSTERSTATE CGordon :: GetIdealState ( void )
{
return CTalkMonster::GetIdealState();
}
void CGordon::DeclineFollowing( void )
{
PlaySentence( "GO_POK", 2, VOL_NORM, ATTN_NORM );
}
//=========================================================
// DEAD GORDON PROP
//
// Designer selects a pose in worldcraft, 0 through num_poses-1
// this value is added to what is selected as the 'first dead pose'
// among the monster's normal animations. All dead poses must
// appear sequentially in the model file. Be sure and set
// the m_iFirstPose properly!
//
//=========================================================
class CDeadGordon : public CBaseMonster
{
public:
void Spawn( void );
int Classify ( void ) { return CLASS_PLAYER_ALLY; }
void KeyValue( KeyValueData *pkvd );
int m_iPose;// which sequence to display -- temporary, don't need to save
static char *m_szPoses[3];
};
char *CDeadGordon::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" };
void CDeadGordon::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "pose"))
{
m_iPose = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseMonster::KeyValue( pkvd );
}
LINK_ENTITY_TO_CLASS( monster_gordon_dead, CDeadGordon );
//=========================================================
// ********** DeadGordon SPAWN **********
//=========================================================
void CDeadGordon :: Spawn( )
{
PRECACHE_MODEL("models/freeman.mdl");
SET_MODEL(ENT(pev), "models/freeman.mdl");
pev->effects = 0;
pev->yaw_speed = 8;
pev->sequence = 0;
m_bloodColor = BLOOD_COLOR_RED;
pev->sequence = LookupSequence( m_szPoses[m_iPose] );
if (pev->sequence == -1)
{
ALERT ( at_console, "Dead barney with bad pose\n" );
}
// Corpses have less health
pev->health = 8;//gSkillData.barneyHealth;
MonsterInitDead();
}

View File

@ -0,0 +1,495 @@
/***
*
* Copyright (c) 1996-2002, 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.
*
****/
//=========================================================
// monster template
//=========================================================
// UNDONE: Holster weapon?
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "talkmonster.h"
#include "schedule.h"
#include "defaultai.h"
#include "scripted.h"
#include "weapons.h"
#include "soundent.h"
#include "barney.h"
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
// first flag is barney dying for scripted sequences?
class CGordon : public CBarney
{
public:
void Spawn( void );
void Precache( void );
void BarneyFirePistol( void );
void AlertSound( void );
BOOL CheckMeleeAttack1( float flDot, float flDist );
void HandleAnimEvent( MonsterEvent_t *pEvent );
int IRelationship( CBaseEntity *pTarget );
CBaseEntity* AdrianCheckTraceHullAttack( float flDist, int iDamage, int iDmgType );
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
void DeclineFollowing( void );
// Override these to set behavior
Schedule_t *GetSchedule( void );
void DeathSound( void );
void PainSound( void );
void TalkInit( void );
};
LINK_ENTITY_TO_CLASS( monster_gordon, CGordon )
LINK_ENTITY_TO_CLASS( monster_adrian, CGordon )
extern Schedule_t slBaFollow[];
extern Schedule_t slBarneyEnemyDraw[];
extern Schedule_t slBaFaceTarget[];
extern Schedule_t slIdleBaStand[];
extern Schedule_t slGruntHideReload[];
//=========================================================
// ALertSound - barney says "Freeze!"
//=========================================================
void CGordon::AlertSound( void )
{
if( m_hEnemy != 0 )
{
if( FOkToSpeak() )
{
PlaySentence( "GO_ATTACK", RANDOM_FLOAT( 2.8, 3.2 ), VOL_NORM, ATTN_IDLE );
}
}
}
int CGordon::IRelationship( CBaseEntity *pTarget )
{
if( FClassnameIs( pev, "monster_adrian" ) && FClassnameIs( pTarget->pev, "monster_human_grunt" ) )
{
return R_AL;
}
return CTalkMonster::IRelationship( pTarget );
}
CBaseEntity* CGordon::AdrianCheckTraceHullAttack( float flDist, int iDamage, int iDmgType )
{
TraceResult tr;
UTIL_MakeVectors( pev->angles );
Vector vecStart = pev->origin;
vecStart.z += pev->size.z * 0.5;
Vector vecEnd = vecStart + ( gpGlobals->v_forward * flDist );
UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT( pev ), &tr );
if( tr.pHit )
return CBaseEntity::Instance( tr.pHit );
return NULL;
}
BOOL CGordon::CheckMeleeAttack1( float flDot, float flDist )
{
CBaseMonster *pEnemy = 0;
if( m_hEnemy != 0 )
{
pEnemy = m_hEnemy->MyMonsterPointer();
if( !pEnemy )
{
return FALSE;
}
}
if( flDist <= 64 && flDot >= 0.7 &&
pEnemy->Classify() != CLASS_ALIEN_BIOWEAPON &&
pEnemy->Classify() != CLASS_PLAYER_BIOWEAPON )
{
return TRUE;
}
return FALSE;
}
//=========================================================
// BarneyFirePistol - shoots one round from the pistol at
// the enemy barney is facing.
//=========================================================
void CGordon::BarneyFirePistol( void )
{
Vector vecShootOrigin;
UTIL_MakeVectors( pev->angles );
vecShootOrigin = pev->origin + Vector( 0, 0, 55 );
Vector vecShootDir = ShootAtEnemy( vecShootOrigin );
Vector angDir = UTIL_VecToAngles( vecShootDir );
SetBlending( 0, angDir.x );
pev->effects = EF_MUZZLEFLASH;
FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_9MM );
int pitchShift = RANDOM_LONG( 0, 20 );
// Only shift about half the time
if( pitchShift > 10 )
pitchShift = 0;
else
pitchShift -= 5;
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "gordon/go_attack2.wav", 1, ATTN_NORM, 0, 100 + pitchShift );
CSoundEnt::InsertSound( bits_SOUND_COMBAT, pev->origin, 384, 0.3 );
// UNDONE: Reload?
m_cAmmoLoaded--;// take away a bullet!
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CGordon::HandleAnimEvent( MonsterEvent_t *pEvent )
{
CBaseEntity *pHurt;
switch( pEvent->event )
{
case BARNEY_AE_KICK:
pHurt = AdrianCheckTraceHullAttack( 70, 0, DMG_GENERIC );
if( pHurt )
{
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "common/kick.wav", 1, ATTN_NORM, 0, PITCH_NORM );
UTIL_MakeVectors( pev->angles );
pHurt->pev->punchangle.x = 5;
pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_forward * 100 + gpGlobals->v_up * 50;
pHurt->TakeDamage( pev, pev, gSkillData.hgruntDmgKick, DMG_CLUB );
}
break;
default:
CBarney::HandleAnimEvent( pEvent );
break;
}
}
//=========================================================
// Spawn
//=========================================================
void CGordon::Spawn()
{
Precache();
SET_MODEL( ENT( pev ), STRING( pev->model ) );
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
pev->health = gSkillData.kateHealth;
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE;
pev->body = 0; // gun in holster
m_fGunDrawn = FALSE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
m_cAmmoLoaded = GLOCK_MAX_CLIP;
MonsterInit();
SetUse( &CTalkMonster::FollowerUse );
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CGordon::Precache()
{
if( FClassnameIs( pev, "monster_adrian" ) )
pev->model = MAKE_STRING( "models/adrian.mdl" );
else
pev->model = MAKE_STRING( "models/freeman.mdl" );
PRECACHE_MODEL( STRING( pev->model ) );
PRECACHE_SOUND( "gordon/go_attack1.wav" );
PRECACHE_SOUND( "gordon/go_attack2.wav" );
PRECACHE_SOUND( "gordon/go_pain1.wav" );
PRECACHE_SOUND( "gordon/go_pain2.wav" );
PRECACHE_SOUND( "gordon/go_pain3.wav" );
PRECACHE_SOUND( "gordon/go_die1.wav" );
PRECACHE_SOUND( "gordon/go_die2.wav" );
PRECACHE_SOUND( "gordon/go_die3.wav" );
PRECACHE_SOUND( "weapons/reload3.wav" );
PRECACHE_SOUND( "zombie/claw_miss1.wav" );
PRECACHE_SOUND( "zombie/claw_miss2.wav" );
PRECACHE_SOUND( "common/kick.wav" );
// every new barney must call this, otherwise
// when a level is loaded, nobody will talk (time is reset to 0)
TalkInit();
CTalkMonster::Precache();
}
// Init talk data
void CGordon::TalkInit()
{
CTalkMonster::TalkInit();
// scientists speach group names (group names are in sentences.txt)
m_szGrp[TLK_ANSWER] = "GO_ANSWER";
m_szGrp[TLK_QUESTION] = "GO_QUESTION";
m_szGrp[TLK_IDLE] = "GO_IDLE";
m_szGrp[TLK_STARE] = "GO_STARE";
m_szGrp[TLK_USE] = "GO_OK";
m_szGrp[TLK_UNUSE] = "GO_WAIT";
m_szGrp[TLK_STOP] = "GO_STOP";
m_szGrp[TLK_NOSHOOT] = "GO_SCARED";
m_szGrp[TLK_HELLO] = "GO_HELLO";
m_szGrp[TLK_PLHURT1] = "!HM_CUREA";
m_szGrp[TLK_PLHURT2] = "!HM_CUREB";
m_szGrp[TLK_PLHURT3] = "!HM_CUREC";
m_szGrp[TLK_PHELLO] = NULL; //"GO_PHELLO"; // UNDONE
m_szGrp[TLK_PIDLE] = NULL; //"GO_PIDLE"; // UNDONE
m_szGrp[TLK_PQUESTION] = "GO_PQUEST"; // UNDONE
m_szGrp[TLK_SMELL] = "GO_SMELL";
m_szGrp[TLK_WOUND] = "GO_WOUND";
m_szGrp[TLK_MORTAL] = "GO_MORTAL";
// get voice for head - just one barney voice for now
if( FClassnameIs( pev, "monster_adrian" ) )
m_voicePitch = 95;
else
m_voicePitch = 100;
}
static BOOL IsFacing( entvars_t *pevTest, const Vector &reference )
{
Vector vecDir = reference - pevTest->origin;
vecDir.z = 0;
vecDir = vecDir.Normalize();
Vector forward, angle;
angle = pevTest->v_angle;
angle.x = 0;
UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL );
// He's facing me, he meant it
if( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so
{
return TRUE;
}
return FALSE;
}
int CGordon::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
// make sure friends talk about it if player hurts talkmonsters...
int ret = CTalkMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
if( !IsAlive() || pev->deadflag == DEAD_DYING )
return ret;
if( m_MonsterState != MONSTERSTATE_PRONE && ( pevAttacker->flags & FL_CLIENT ) )
{
m_flPlayerDamage += flDamage;
// This is a heurstic to determine if the player intended to harm me
// If I have an enemy, we can't establish intent (may just be crossfire)
if( m_hEnemy == 0 )
{
// If the player was facing directly at me, or I'm already suspicious, get mad
if( ( m_afMemory & bits_MEMORY_SUSPICIOUS ) || IsFacing( pevAttacker, pev->origin ) )
{
// Alright, now I'm pissed!
PlaySentence( "GO_MAD", 4, VOL_NORM, ATTN_NORM );
Remember( bits_MEMORY_PROVOKED );
StopFollowing( TRUE );
}
else
{
// Hey, be careful with that
PlaySentence( "GO_SHOT", 4, VOL_NORM, ATTN_NORM );
Remember( bits_MEMORY_SUSPICIOUS );
}
}
else if( !( m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO )
{
PlaySentence( "GO_SHOT", 4, VOL_NORM, ATTN_NORM );
}
}
return ret;
}
//=========================================================
// PainSound
//=========================================================
void CGordon::PainSound( void )
{
if( gpGlobals->time < m_painTime )
return;
m_painTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 0.75 );
switch( RANDOM_LONG( 0, 2 ) )
{
case 0:
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "gordon/go_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch() );
break;
case 1:
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "gordon/go_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch() );
break;
case 2:
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "gordon/go_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch() );
break;
}
}
//=========================================================
// DeathSound
//=========================================================
void CGordon::DeathSound( void )
{
switch( RANDOM_LONG( 0, 2 ) )
{
case 0:
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "gordon/go_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch() );
break;
case 1:
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "gordon/go_die2.wav", 1, ATTN_NORM, 0, GetVoicePitch() );
break;
case 2:
EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "gordon/go_die3.wav", 1, ATTN_NORM, 0, GetVoicePitch() );
break;
}
}
//=========================================================
// GetSchedule - Decides which type of schedule best suits
// the monster's current state and conditions. Then calls
// monster's member function to get a pointer to a schedule
// of the proper type.
//=========================================================
Schedule_t *CGordon::GetSchedule( void )
{
if( HasConditions( bits_COND_HEAR_SOUND ) )
{
CSound *pSound;
pSound = PBestSound();
ASSERT( pSound != NULL );
if( pSound && (pSound->m_iType & bits_SOUND_DANGER) )
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND );
}
if( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() )
{
PlaySentence( "GO_KILL", 4, VOL_NORM, ATTN_NORM );
}
switch( m_MonsterState )
{
case MONSTERSTATE_COMBAT:
{
// dead enemy
if( HasConditions( bits_COND_ENEMY_DEAD ) )
{
// call base class, all code to handle dead enemies is centralized there.
return CBaseMonster::GetSchedule();
}
// always act surprized with a new enemy
if( HasConditions( bits_COND_NEW_ENEMY ) && HasConditions( bits_COND_LIGHT_DAMAGE ) )
return GetScheduleOfType( SCHED_SMALL_FLINCH );
// wait for one schedule to draw gun
if( !m_fGunDrawn )
return GetScheduleOfType( SCHED_ARM_WEAPON );
if( HasConditions( bits_COND_HEAVY_DAMAGE ) )
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) )
return GetScheduleOfType( SCHED_MELEE_ATTACK1 );
if( HasConditions( bits_COND_NO_AMMO_LOADED ) )
return GetScheduleOfType( SCHED_BARNEY_COVER_AND_RELOAD );
}
break;
case MONSTERSTATE_ALERT:
case MONSTERSTATE_IDLE:
if( HasConditions( bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE ) )
{
// flinch if hurt
return GetScheduleOfType( SCHED_SMALL_FLINCH );
}
if( m_hEnemy == 0 && IsFollowing() )
{
if( !m_hTargetEnt->IsAlive() )
{
// UNDONE: Comment about the recently dead player here?
StopFollowing( FALSE );
break;
}
else
{
if( HasConditions( bits_COND_CLIENT_PUSH ) )
{
return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW );
}
return GetScheduleOfType( SCHED_TARGET_FACE );
}
}
if( HasConditions( bits_COND_CLIENT_PUSH ) )
{
return GetScheduleOfType( SCHED_MOVE_AWAY );
}
// try to say something about smells
TrySmellTalk();
break;
default:
break;
}
return CTalkMonster::GetSchedule();
}
void CGordon::DeclineFollowing( void )
{
PlaySentence( "GO_POK", 2, VOL_NORM, ATTN_NORM );
}

View File

@ -1,839 +0,0 @@
/***
*
* 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.
*
****/
//=========================================================
// monster template
//=========================================================
// UNDONE: Holster weapon?
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "talkmonster.h"
#include "schedule.h"
#include "defaultai.h"
#include "scripted.h"
#include "weapons.h"
#include "soundent.h"
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
// first flag is hevbarn dying for scripted sequences?
#define HEVBARN_AE_DRAW ( 2 )
#define HEVBARN_AE_SHOOT ( 3 )
#define HEVBARN_AE_HOLSTER ( 4 )
#define HEVBARN_BODY_GUNHOLSTERED 0
#define HEVBARN_BODY_GUNDRAWN 1
#define HEVBARN_BODY_GUNGONE 2
class CHevbarn : public CTalkMonster
{
public:
void Spawn( void );
void Precache( void );
void SetYawSpeed( void );
int ISoundMask( void );
void HevbarnFirePistol( void );
void AlertSound( void );
int Classify ( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
void RunTask( Task_t *pTask );
void StartTask( Task_t *pTask );
virtual int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; }
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
BOOL CheckRangeAttack1 ( float flDot, float flDist );
void DeclineFollowing( void );
// Override these to set behavior
Schedule_t *GetScheduleOfType ( int Type );
Schedule_t *GetSchedule ( void );
MONSTERSTATE GetIdealState ( void );
void DeathSound( void );
void PainSound( void );
void TalkInit( void );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
void Killed( entvars_t *pevAttacker, int iGib );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
BOOL m_fGunDrawn;
float m_painTime;
float m_checkAttackTime;
BOOL m_lastAttackCheck;
// UNDONE: What is this for? It isn't used?
float m_flPlayerDamage;// how much pain has the player inflicted on me?
CUSTOM_SCHEDULES;
};
LINK_ENTITY_TO_CLASS( monster_hevbarn, CHevbarn );
TYPEDESCRIPTION CHevbarn::m_SaveData[] =
{
DEFINE_FIELD( CHevbarn, m_fGunDrawn, FIELD_BOOLEAN ),
DEFINE_FIELD( CHevbarn, m_painTime, FIELD_TIME ),
DEFINE_FIELD( CHevbarn, m_checkAttackTime, FIELD_TIME ),
DEFINE_FIELD( CHevbarn, m_lastAttackCheck, FIELD_BOOLEAN ),
DEFINE_FIELD( CHevbarn, m_flPlayerDamage, FIELD_FLOAT ),
};
IMPLEMENT_SAVERESTORE( CHevbarn, CTalkMonster );
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
Task_t tlHvBaFollow[] =
{
{ TASK_MOVE_TO_TARGET_RANGE,(float)128 }, // Move within 128 of target ent (client)
{ TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE },
};
Schedule_t slHvBaFollow[] =
{
{
tlHvBaFollow,
ARRAYSIZE ( tlHvBaFollow ),
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND |
bits_COND_PROVOKED,
bits_SOUND_DANGER,
"Follow"
},
};
//=========================================================
// HevbarnDraw- much better looking draw schedule for when
// hevbarn knows who he's gonna attack.
//=========================================================
Task_t tlHevbarnEnemyDraw[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_FACE_ENEMY, 0 },
{ TASK_PLAY_SEQUENCE_FACE_ENEMY, (float) ACT_ARM },
};
Schedule_t slHevbarnEnemyDraw[] =
{
{
tlHevbarnEnemyDraw,
ARRAYSIZE ( tlHevbarnEnemyDraw ),
0,
0,
"Hevbarn Enemy Draw"
}
};
Task_t tlHvBaFaceTarget[] =
{
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_FACE_TARGET, (float)0 },
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_SET_SCHEDULE, (float)SCHED_TARGET_CHASE },
};
Schedule_t slHvBaFaceTarget[] =
{
{
tlHvBaFaceTarget,
ARRAYSIZE ( tlHvBaFaceTarget ),
bits_COND_CLIENT_PUSH |
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND |
bits_COND_PROVOKED,
bits_SOUND_DANGER,
"FaceTarget"
},
};
Task_t tlIdleHvBaStand[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds.
{ TASK_TLK_HEADRESET, (float)0 }, // reset head position
};
Schedule_t slIdleHvBaStand[] =
{
{
tlIdleHvBaStand,
ARRAYSIZE ( tlIdleHvBaStand ),
bits_COND_NEW_ENEMY |
bits_COND_LIGHT_DAMAGE |
bits_COND_HEAVY_DAMAGE |
bits_COND_HEAR_SOUND |
bits_COND_SMELL |
bits_COND_PROVOKED,
bits_SOUND_COMBAT |// sound flags - change these, and you'll break the talking code.
//bits_SOUND_PLAYER |
//bits_SOUND_WORLD |
bits_SOUND_DANGER |
bits_SOUND_MEAT |// scents
bits_SOUND_CARCASS |
bits_SOUND_GARBAGE,
"IdleStand"
},
};
DEFINE_CUSTOM_SCHEDULES( CHevbarn )
{
slHvBaFollow,
slHevbarnEnemyDraw,
slHvBaFaceTarget,
slIdleHvBaStand,
};
IMPLEMENT_CUSTOM_SCHEDULES( CHevbarn, CTalkMonster );
void CHevbarn :: StartTask( Task_t *pTask )
{
CTalkMonster::StartTask( pTask );
}
void CHevbarn :: RunTask( Task_t *pTask )
{
switch ( pTask->iTask )
{
case TASK_RANGE_ATTACK1:
if (m_hEnemy != NULL && (m_hEnemy->IsPlayer()))
{
pev->framerate = 1.5;
}
CTalkMonster::RunTask( pTask );
break;
default:
CTalkMonster::RunTask( pTask );
break;
}
}
//=========================================================
// ISoundMask - returns a bit mask indicating which types
// of sounds this monster regards.
//=========================================================
int CHevbarn :: ISoundMask ( void)
{
return bits_SOUND_WORLD |
bits_SOUND_COMBAT |
bits_SOUND_CARCASS |
bits_SOUND_MEAT |
bits_SOUND_GARBAGE |
bits_SOUND_DANGER |
bits_SOUND_PLAYER;
}
//=========================================================
// Classify - indicates this monster's place in the
// relationship table.
//=========================================================
int CHevbarn :: Classify ( void )
{
return CLASS_PLAYER_ALLY;
}
//=========================================================
// ALertSound - hevbarn says "Freeze!"
//=========================================================
void CHevbarn :: AlertSound( void )
{
if ( m_hEnemy != NULL )
{
if ( FOkToSpeak() )
{
PlaySentence( "BA_ATTACK", RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE );
}
}
}
//=========================================================
// SetYawSpeed - allows each sequence to have a different
// turn rate associated with it.
//=========================================================
void CHevbarn :: SetYawSpeed ( void )
{
int ys;
ys = 0;
switch ( m_Activity )
{
case ACT_IDLE:
ys = 70;
break;
case ACT_WALK:
ys = 70;
break;
case ACT_RUN:
ys = 90;
break;
default:
ys = 70;
break;
}
pev->yaw_speed = ys;
}
//=========================================================
// CheckRangeAttack1
//=========================================================
BOOL CHevbarn :: CheckRangeAttack1 ( float flDot, float flDist )
{
if ( flDist <= 1024 && flDot >= 0.5 )
{
if ( gpGlobals->time > m_checkAttackTime )
{
TraceResult tr;
Vector shootOrigin = pev->origin + Vector( 0, 0, 55 );
CBaseEntity *pEnemy = m_hEnemy;
Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->pev->origin) + m_vecEnemyLKP );
UTIL_TraceLine( shootOrigin, shootTarget, dont_ignore_monsters, ENT(pev), &tr );
m_checkAttackTime = gpGlobals->time + 1;
if ( tr.flFraction == 1.0 || (tr.pHit != NULL && CBaseEntity::Instance(tr.pHit) == pEnemy) )
m_lastAttackCheck = TRUE;
else
m_lastAttackCheck = FALSE;
m_checkAttackTime = gpGlobals->time + 1.5;
}
return m_lastAttackCheck;
}
return FALSE;
}
//=========================================================
// HevbarnFirePistol - shoots one round from the pistol at
// the enemy hevbarn is facing.
//=========================================================
void CHevbarn :: HevbarnFirePistol ( void )
{
Vector vecShootOrigin;
UTIL_MakeVectors(pev->angles);
vecShootOrigin = pev->origin + Vector( 0, 0, 55 );
Vector vecShootDir = ShootAtEnemy( vecShootOrigin );
Vector angDir = UTIL_VecToAngles( vecShootDir );
SetBlending( 0, angDir.x );
pev->effects = EF_MUZZLEFLASH;
FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, BULLET_MONSTER_9MM );
int pitchShift = RANDOM_LONG( 0, 20 );
// Only shift about half the time
if ( pitchShift > 10 )
pitchShift = 0;
else
pitchShift -= 5;
EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, "barney/ba_attack2.wav", 1, ATTN_NORM, 0, 100 + pitchShift );
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 );
// UNDONE: Reload?
m_cAmmoLoaded--;// take away a bullet!
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CHevbarn :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
switch( pEvent->event )
{
case HEVBARN_AE_SHOOT:
HevbarnFirePistol();
break;
case HEVBARN_AE_DRAW:
// hevbarn's bodygroup switches here so he can pull gun from holster
pev->body = HEVBARN_BODY_GUNDRAWN;
m_fGunDrawn = TRUE;
break;
case HEVBARN_AE_HOLSTER:
// change bodygroup to replace gun in holster
pev->body = HEVBARN_BODY_GUNHOLSTERED;
m_fGunDrawn = FALSE;
break;
default:
CTalkMonster::HandleAnimEvent( pEvent );
}
}
//=========================================================
// Spawn
//=========================================================
void CHevbarn :: Spawn()
{
Precache( );
SET_MODEL(ENT(pev), "models/hev_barney.mdl");
UTIL_SetSize(pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX);
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
pev->health = gSkillData.barneyHealth;
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE;
pev->body = 0; // gun in holster
m_fGunDrawn = FALSE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
MonsterInit();
SetUse( &CHevbarn::FollowerUse );
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CHevbarn :: Precache()
{
PRECACHE_MODEL("models/hev_barney.mdl");
PRECACHE_SOUND("barney/ba_attack1.wav" );
PRECACHE_SOUND("barney/ba_attack2.wav" );
PRECACHE_SOUND("barney/ba_pain1.wav");
PRECACHE_SOUND("barney/ba_pain2.wav");
PRECACHE_SOUND("barney/ba_pain3.wav");
PRECACHE_SOUND("barney/ba_die1.wav");
PRECACHE_SOUND("barney/ba_die2.wav");
PRECACHE_SOUND("barney/ba_die3.wav");
// every new hevbarn must call this, otherwise
// when a level is loaded, nobody will talk (time is reset to 0)
TalkInit();
CTalkMonster::Precache();
}
// Init talk data
void CHevbarn :: TalkInit()
{
CTalkMonster::TalkInit();
// scientists speach group names (group names are in sentences.txt)
m_szGrp[TLK_ANSWER] = "BA_ANSWER";
m_szGrp[TLK_QUESTION] = "BA_QUESTION";
m_szGrp[TLK_IDLE] = "BA_IDLE";
m_szGrp[TLK_STARE] = "BA_STARE";
m_szGrp[TLK_USE] = "BA_OK";
m_szGrp[TLK_UNUSE] = "BA_WAIT";
m_szGrp[TLK_STOP] = "BA_STOP";
m_szGrp[TLK_NOSHOOT] = "BA_SCARED";
m_szGrp[TLK_HELLO] = "BA_HELLO";
m_szGrp[TLK_PLHURT1] = "!BA_CUREA";
m_szGrp[TLK_PLHURT2] = "!BA_CUREB";
m_szGrp[TLK_PLHURT3] = "!BA_CUREC";
m_szGrp[TLK_PHELLO] = NULL; //"BA_PHELLO"; // UNDONE
m_szGrp[TLK_PIDLE] = NULL; //"BA_PIDLE"; // UNDONE
m_szGrp[TLK_PQUESTION] = "BA_PQUEST"; // UNDONE
m_szGrp[TLK_SMELL] = "BA_SMELL";
m_szGrp[TLK_WOUND] = "BA_WOUND";
m_szGrp[TLK_MORTAL] = "BA_MORTAL";
// get voice for head - just one hevbarn voice for now
m_voicePitch = 100;
}
static BOOL IsFacing( entvars_t *pevTest, const Vector &reference )
{
Vector vecDir = (reference - pevTest->origin);
vecDir.z = 0;
vecDir = vecDir.Normalize();
Vector forward, angle;
angle = pevTest->v_angle;
angle.x = 0;
UTIL_MakeVectorsPrivate( angle, forward, NULL, NULL );
// He's facing me, he meant it
if ( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so
{
return TRUE;
}
return FALSE;
}
int CHevbarn :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType)
{
// make sure friends talk about it if player hurts talkmonsters...
int ret = CTalkMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
if ( !IsAlive() || pev->deadflag == DEAD_DYING )
return ret;
if ( m_MonsterState != MONSTERSTATE_PRONE && (pevAttacker->flags & FL_CLIENT) )
{
m_flPlayerDamage += flDamage;
// This is a heurstic to determine if the player intended to harm me
// If I have an enemy, we can't establish intent (may just be crossfire)
if ( m_hEnemy == NULL )
{
// If the player was facing directly at me, or I'm already suspicious, get mad
if ( (m_afMemory & bits_MEMORY_SUSPICIOUS) || IsFacing( pevAttacker, pev->origin ) )
{
// Alright, now I'm pissed!
PlaySentence( "BA_MAD", 4, VOL_NORM, ATTN_NORM );
Remember( bits_MEMORY_PROVOKED );
StopFollowing( TRUE );
}
else
{
// Hey, be careful with that
PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM );
Remember( bits_MEMORY_SUSPICIOUS );
}
}
else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO )
{
PlaySentence( "BA_SHOT", 4, VOL_NORM, ATTN_NORM );
}
}
return ret;
}
//=========================================================
// PainSound
//=========================================================
void CHevbarn :: PainSound ( void )
{
if (gpGlobals->time < m_painTime)
return;
m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75);
switch (RANDOM_LONG(0,2))
{
case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
}
}
//=========================================================
// DeathSound
//=========================================================
void CHevbarn :: DeathSound ( void )
{
switch (RANDOM_LONG(0,2))
{
case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barney/ba_die3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break;
}
}
void CHevbarn::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType)
{
switch( ptr->iHitgroup)
{
case HITGROUP_CHEST:
case HITGROUP_STOMACH:
if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST))
{
flDamage = flDamage / 2;
}
break;
case 10:
if (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_CLUB))
{
flDamage -= 20;
if (flDamage <= 0)
{
UTIL_Ricochet( ptr->vecEndPos, 1.0 );
flDamage = 0.01;
}
}
// always a head shot
ptr->iHitgroup = HITGROUP_HEAD;
break;
}
CTalkMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
}
void CHevbarn::Killed( entvars_t *pevAttacker, int iGib )
{
if ( pev->body < HEVBARN_BODY_GUNGONE )
{// drop the gun!
Vector vecGunPos;
Vector vecGunAngles;
pev->body = HEVBARN_BODY_GUNGONE;
GetAttachment( 0, vecGunPos, vecGunAngles );
CBaseEntity *pGun = DropItem( "weapon_barney9mmhg", vecGunPos, vecGunAngles );
}
SetUse( NULL );
CTalkMonster::Killed( pevAttacker, iGib );
}
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
Schedule_t* CHevbarn :: GetScheduleOfType ( int Type )
{
Schedule_t *psched;
switch( Type )
{
case SCHED_ARM_WEAPON:
if ( m_hEnemy != NULL )
{
// face enemy, then draw.
return slHevbarnEnemyDraw;
}
break;
// Hook these to make a looping schedule
case SCHED_TARGET_FACE:
// call base class default so that hevbarn will talk
// when 'used'
psched = CTalkMonster::GetScheduleOfType(Type);
if (psched == slIdleStand)
return slHvBaFaceTarget; // override this for different target face behavior
else
return psched;
case SCHED_TARGET_CHASE:
return slHvBaFollow;
case SCHED_IDLE_STAND:
// call base class default so that scientist will talk
// when standing during idle
psched = CTalkMonster::GetScheduleOfType(Type);
if (psched == slIdleStand)
{
// just look straight ahead.
return slIdleHvBaStand;
}
else
return psched;
}
return CTalkMonster::GetScheduleOfType( Type );
}
//=========================================================
// GetSchedule - Decides which type of schedule best suits
// the monster's current state and conditions. Then calls
// monster's member function to get a pointer to a schedule
// of the proper type.
//=========================================================
Schedule_t *CHevbarn :: GetSchedule ( void )
{
if ( HasConditions( bits_COND_HEAR_SOUND ) )
{
CSound *pSound;
pSound = PBestSound();
ASSERT( pSound != NULL );
if ( pSound && (pSound->m_iType & bits_SOUND_DANGER) )
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND );
}
if ( HasConditions( bits_COND_ENEMY_DEAD ) && FOkToSpeak() )
{
PlaySentence( "BA_KILL", 4, VOL_NORM, ATTN_NORM );
}
switch( m_MonsterState )
{
case MONSTERSTATE_COMBAT:
{
// dead enemy
if ( HasConditions( bits_COND_ENEMY_DEAD ) )
{
// call base class, all code to handle dead enemies is centralized there.
return CBaseMonster :: GetSchedule();
}
// always act surprized with a new enemy
if ( HasConditions( bits_COND_NEW_ENEMY ) && HasConditions( bits_COND_LIGHT_DAMAGE) )
return GetScheduleOfType( SCHED_SMALL_FLINCH );
// wait for one schedule to draw gun
if (!m_fGunDrawn )
return GetScheduleOfType( SCHED_ARM_WEAPON );
if ( HasConditions( bits_COND_HEAVY_DAMAGE ) )
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
}
break;
case MONSTERSTATE_ALERT:
case MONSTERSTATE_IDLE:
if ( HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE))
{
// flinch if hurt
return GetScheduleOfType( SCHED_SMALL_FLINCH );
}
if ( m_hEnemy == NULL && IsFollowing() )
{
if ( !m_hTargetEnt->IsAlive() )
{
// UNDONE: Comment about the recently dead player here?
StopFollowing( FALSE );
break;
}
else
{
if ( HasConditions( bits_COND_CLIENT_PUSH ) )
{
return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW );
}
return GetScheduleOfType( SCHED_TARGET_FACE );
}
}
if ( HasConditions( bits_COND_CLIENT_PUSH ) )
{
return GetScheduleOfType( SCHED_MOVE_AWAY );
}
// try to say something about smells
TrySmellTalk();
break;
}
return CTalkMonster::GetSchedule();
}
MONSTERSTATE CHevbarn :: GetIdealState ( void )
{
return CTalkMonster::GetIdealState();
}
void CHevbarn::DeclineFollowing( void )
{
PlaySentence( "BA_POK", 2, VOL_NORM, ATTN_NORM );
}
//=========================================================
// DEAD HEVBARN PROP
//
// Designer selects a pose in worldcraft, 0 through num_poses-1
// this value is added to what is selected as the 'first dead pose'
// among the monster's normal animations. All dead poses must
// appear sequentially in the model file. Be sure and set
// the m_iFirstPose properly!
//
//=========================================================
class CDeadHevbarn : public CBaseMonster
{
public:
void Spawn( void );
int Classify ( void ) { return CLASS_PLAYER_ALLY; }
void KeyValue( KeyValueData *pkvd );
int m_iPose;// which sequence to display -- temporary, don't need to save
static char *m_szPoses[3];
};
char *CDeadHevbarn::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" };
void CDeadHevbarn::KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "pose"))
{
m_iPose = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CBaseMonster::KeyValue( pkvd );
}
LINK_ENTITY_TO_CLASS( monster_hevbarn_dead, CDeadHevbarn );
//=========================================================
// ********** DeadHevbarn SPAWN **********
//=========================================================
void CDeadHevbarn :: Spawn( )
{
PRECACHE_MODEL("models/hev_barney.mdl");
SET_MODEL(ENT(pev), "models/hev_barney.mdl");
pev->effects = 0;
pev->yaw_speed = 8;
pev->sequence = 0;
m_bloodColor = BLOOD_COLOR_RED;
pev->sequence = LookupSequence( m_szPoses[m_iPose] );
if (pev->sequence == -1)
{
ALERT ( at_console, "Dead hevbarn with bad pose\n" );
}
// Corpses have less health
pev->health = 8;//gSkillData.hevbarnHealth;
MonsterInitDead();
}

File diff suppressed because it is too large Load Diff

368
dlls/asheep/kmedkit.cpp Normal file
View File

@ -0,0 +1,368 @@
/***
*
* Copyright (c) 1996-2002, 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 "nodes.h"
#include "player.h"
#include "gamerules.h"
#define CROWBAR_BODYHIT_VOLUME 128
#define CROWBAR_WALLHIT_VOLUME 512
LINK_ENTITY_TO_CLASS( weapon_kmedkit, CKMedKit )
enum kmedkit_e
{
KMEDKIT_IDLE1 = 0,
KMEDKIT_IDLE2,
KMEDKIT_LONGIDLE,
KMEDKIT_LONGUSE,
KMEDKIT_SHORTUSE,
KMEDKIT_HOLSTER,
KMEDKIT_DEPLOY
};
void CKMedKit::Spawn()
{
Precache();
m_iId = WEAPON_KMEDKIT;
SET_MODEL( ENT( pev ), "models/w_kmedkit.mdl" );
m_iDefaultAmmo = KMEDKIT_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
void CKMedKit::Precache( void )
{
PRECACHE_MODEL( "models/v_kmedkit.mdl" );
PRECACHE_MODEL( "models/w_kmedkit.mdl" );
PRECACHE_MODEL( "models/p_kmedkit.mdl" );
PRECACHE_SOUND( "weapons/kmedkit_miss.wav" );
PRECACHE_SOUND( "weapons/kmedkit_heal.wav" );
}
int CKMedKit::GetItemInfo( ItemInfo *p )
{
p->pszName = STRING( pev->classname );
p->pszAmmo1 = "katemedickit";
p->iMaxAmmo1 = KMEDKIT_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 0;
p->iPosition = 2;
p->iId = WEAPON_KMEDKIT;
p->iWeight = KMEDKIT_WEIGHT;
p->iFlags = ITEM_FLAG_SELECTONEMPTY | ITEM_FLAG_NOAUTORELOAD | ITEM_FLAG_NOAUTOSWITCHEMPTY;
return 1;
}
int CKMedKit::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 CKMedKit::Deploy()
{
return DefaultDeploy( "models/v_kmedkit.mdl", "models/p_kmedkit.mdl", KMEDKIT_DEPLOY, "kmedkit" );
}
void CKMedKit::Holster( int skiplocal /* = 0 */ )
{
DefaultHolster( KMEDKIT_HOLSTER, 0.5 );
}
extern void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity );
/*
void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity )
{
int i, j, k;
float distance;
float *minmaxs[2] = {mins, maxs};
TraceResult tmpTrace;
Vector vecHullEnd = tr.vecEndPos;
Vector vecEnd;
distance = 1e6f;
vecHullEnd = vecSrc + ( ( vecHullEnd - vecSrc ) * 2 );
UTIL_TraceLine( vecSrc, vecHullEnd, dont_ignore_monsters, pEntity, &tmpTrace );
if( tmpTrace.flFraction < 1.0 )
{
tr = tmpTrace;
return;
}
for( i = 0; i < 2; i++ )
{
for( j = 0; j < 2; j++ )
{
for( k = 0; k < 2; k++ )
{
vecEnd.x = vecHullEnd.x + minmaxs[i][0];
vecEnd.y = vecHullEnd.y + minmaxs[j][1];
vecEnd.z = vecHullEnd.z + minmaxs[k][2];
UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, pEntity, &tmpTrace );
if( tmpTrace.flFraction < 1.0 )
{
float thisDistance = ( tmpTrace.vecEndPos - vecSrc ).Length();
if( thisDistance < distance )
{
tr = tmpTrace;
distance = thisDistance;
}
}
}
}
}
}
*/
void CKMedKit::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0 )
{
UseMedkit( 1 );
}
else
{
EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/kmedkit_miss.wav", 1, ATTN_NORM, 0, 94 + RANDOM_LONG( 0, 15 ) );
m_flNextPrimaryAttack = gpGlobals->time + 0.5f;
m_flNextSecondaryAttack = gpGlobals->time + 0.1f;
}
}
void CKMedKit::SecondaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_flNextPrimaryAttack <= UTIL_WeaponTimeBase() )
UseMedkit( 2 );
}
void CKMedKit::UseMedkit( int fMode )
{
TraceResult tr;
UTIL_MakeVectors( m_pPlayer->pev->v_angle );
Vector vecSrc = m_pPlayer->GetGunPosition();
Vector vecEnd = vecSrc + gpGlobals->v_forward * 32;
UTIL_TraceLine( vecSrc, vecEnd, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr );
#ifndef CLIENT_DLL
if( tr.flFraction >= 1.0 )
{
UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, head_hull, ENT( m_pPlayer->pev ), &tr );
if( tr.flFraction < 1.0 )
{
// Calculate the point of intersection of the line (or hull) and the object we hit
// This is and approximation of the "best" intersection
CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit );
if( !pHit || pHit->IsBSPModel() )
FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict() );
vecEnd = tr.vecEndPos; // This is the point on the actual surface (the hull could have hit space)
}
}
#endif
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
if( tr.flFraction < 1.0 )
{
CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit );
if( pEntity )
{
if( FClassnameIs( ENT( pEntity->pev ), "monster_kate" ) )
{
if( fMode == 2 )
{
if( !m_bIsStateChanged )
{
m_bIsStateChanged = TRUE;
m_iState = 0;
m_iKateHealth = pEntity->pev->health;
SendWeaponAnim( KMEDKIT_LONGUSE, 0 );
SetThink( &CKMedKit::SayKateHealth );
pev->nextthink = gpGlobals->time + 0.1f;
m_flTimeWeaponIdle = gpGlobals->time + 2.4f;
}
}
else
{
if( pEntity->pev->health == gSkillData.kateHealth || pEntity->pev->dmg )
goto miss;
SendWeaponAnim( KMEDKIT_SHORTUSE, 0 );
m_flTimeWeaponIdle = gpGlobals->time + 1.1f;
pEntity->pev->health = gSkillData.healthkitCapacity + pEntity->pev->health;
if( pEntity->pev->health > gSkillData.kateHealth )
pEntity->pev->health = gSkillData.kateHealth;
SetThink( &CKMedKit::SayKateHealth );
pev->nextthink = gpGlobals->time + 1.5f;
m_bIsStateChanged = TRUE;
m_iState = 1;
m_iKateHealth = pEntity->pev->health;
--m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType];
EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/kmedkit_heal.wav", 1, ATTN_NORM );
}
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + 100.0f;
}
return;
}
}
miss:
// miss
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + 0.5f;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
SendWeaponAnim( KMEDKIT_IDLE1, 0 );
EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/kmedkit_miss.wav", 1, ATTN_NORM, 0, 94 + RANDOM_LONG( 0, 15 ) );
}
void CKMedKit::SayKateHealth()
{
if( m_bIsStateChanged )
{
char szSentence[64];
const char *pszSentence;
switch( m_iState )
{
case 0:
pszSentence = "!KA_HEALTHST1";
++m_iState;
pev->nextthink = gpGlobals->time + 1.8f;
break;
case 1:
pszSentence = "!KA_HEALTHST2";
++m_iState;
pev->nextthink = gpGlobals->time + 2.0f;
break;
case 2:
UTIL_ShowKateHealth( m_iKateHealth );
if( m_iKateHealth < 100 )
{
if( m_iKateHealth >= 20 )
{
sprintf( szSentence, "!KA_HEALTH%d0", m_iKateHealth / 10 );
pszSentence = szSentence;
pev->nextthink = gpGlobals->time + 1.5f;
++m_iState;
if( m_iKateHealth % 10 == 0 )
++m_iState;
}
else
{
sprintf( szSentence, "!KA_HEALTH%d", m_iKateHealth );
pszSentence = szSentence;
pev->nextthink = gpGlobals->time + 1.6f;
m_iState += 2;
}
}
else
{
pszSentence = "!KA_HEALTH00";
pev->nextthink = gpGlobals->time + 1.2f;
m_iState += 2;
}
break;
case 3:
sprintf( szSentence, "!KA_HEALTH%d", m_iKateHealth % 10 );
pszSentence = szSentence;
pev->nextthink = gpGlobals->time + 1.0f;
++m_iState;
break;
case 4:
pszSentence = "!KA_HEALTHED";
pev->nextthink = gpGlobals->time + 1.0f;
++m_iState;
break;
case 5:
m_bIsStateChanged = FALSE;
m_flNextPrimaryAttack = m_flNextSecondaryAttack = m_flTimeWeaponIdle = gpGlobals->time + 0.1f;
default:
return;
}
EMIT_SOUND_SUIT( m_pPlayer->edict(), pszSentence );
}
}
void CKMedKit::WeaponIdle()
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
if( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() )
{
int iAnim, iRand = RANDOM_LONG( 0, 2 );
if( iRand == 0 )
{
iAnim = KMEDKIT_LONGIDLE;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.7f;
}
else if( iRand == 1 )
{
iAnim = KMEDKIT_IDLE2;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.3f;
}
else
{
iAnim = KMEDKIT_IDLE1;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
SendWeaponAnim( iAnim );
}
}

View File

@ -32,11 +32,11 @@ enum m41a_e
M41A_DEPLOY,
M41A_FIRE1,
M41A_FIRE2,
//M41A_FIRE3,
M41A_FIRE3,
M41A_HOLSTER
};
LINK_ENTITY_TO_CLASS( weapon_9mmm41a, CM41A );
//=========================================================
@ -76,15 +76,13 @@ void CM41A::Precache( void )
PRECACHE_SOUND("items/cliprelease1.wav");
PRECACHE_SOUND ("weapons/m41ahks1.wav");// H to the K
PRECACHE_SOUND ("weapons/m41ahks2.wav");// H to the K
PRECACHE_SOUND( "weapons/m41aglauncher.wav" );
PRECACHE_SOUND( "weapons/m41aglauncher2.wav" );
PRECACHE_SOUND ("weapons/357_cock1.wav");
m_usM41A = PRECACHE_EVENT( 1, "events/M41A.sc" );
m_usM41A2 = PRECACHE_EVENT( 1, "events/M41A.sc" );
m_usM41A = PRECACHE_EVENT( 1, "events/m41a.sc" );
}
int CM41A::GetItemInfo(ItemInfo *p)
@ -96,10 +94,10 @@ int CM41A::GetItemInfo(ItemInfo *p)
p->iMaxAmmo2 = M203_GRENADE_MAX_CARRY;
p->iMaxClip = MP5_MAX_CLIP;
p->iSlot = 2;
p->iPosition = 3;
p->iPosition = 5;
p->iFlags = 0;
p->iId = m_iId = WEAPON_M41A;
p->iWeight = MP5_WEIGHT;
p->iWeight = M41A_WEIGHT;
return 1;
}
@ -121,21 +119,31 @@ BOOL CM41A::Deploy( )
return DefaultDeploy( "models/v_9mmm41a.mdl", "models/p_9mmm41a.mdl", M41A_DEPLOY, "M41A" );
}
void CM41A::Holster( int skiplocal /* = 0 */ )
{
DefaultHolster( M41A_HOLSTER, 0.9 );
}
void CM41A::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
// don't fire underwater
if (m_pPlayer->pev->waterlevel == 3)
{
PlayEmptySound( );
m_flNextPrimaryAttack = 0.15;
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
return;
}
if (m_iClip <= 0)
{
PlayEmptySound();
m_flNextPrimaryAttack = 0.15;
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
return;
}
@ -161,12 +169,12 @@ void CM41A::PrimaryAttack()
#endif
{
// optimized multiplayer. Widened to make it easier to hit a moving player
vecDir = m_pPlayer->FireBulletsPlayer( 4, vecSrc, vecAiming, VECTOR_CONE_2DEGREES, 8192, BULLET_PLAYER_M41A, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed );
vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_M41A, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed );
}
else
{
// single player spread
vecDir = m_pPlayer->FireBulletsPlayer( 4, vecSrc, vecAiming, VECTOR_CONE_1DEGREES, 8192, BULLET_PLAYER_M41A, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed );
vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, 8192, BULLET_PLAYER_M41A, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed );
}
int flags;
@ -182,7 +190,7 @@ void CM41A::PrimaryAttack()
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
m_flNextPrimaryAttack = GetNextAttackDelay(0.1);
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1;
if ( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() )
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1;
@ -194,11 +202,17 @@ void CM41A::PrimaryAttack()
void CM41A::SecondaryAttack( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
// don't fire underwater
if (m_pPlayer->pev->waterlevel == 3)
{
PlayEmptySound( );
m_flNextPrimaryAttack = 0.15;
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
return;
}
@ -216,45 +230,59 @@ void CM41A::SecondaryAttack( void )
m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]--;
SendWeaponAnim( M41A_LAUNCH );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
// play this sound through BODY channel so we can hear it if player didn't stop firing MP3
EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, RANDOM_LONG( 0, 1 ) ? "weapons/m41aglauncher.wav" : "weapons/m41aglauncher2.wav", 0.8, ATTN_NORM );
UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle );
// we don't add in player velocity anymore.
CGrenade::ShootContact( m_pPlayer->pev,
m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16,
gpGlobals->v_forward * 800 );
gpGlobals->v_forward * 800, gSkillData.plrDmgM41AGrenade );
int flags;
#if defined( CLIENT_WEAPONS )
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usM41A2 );
m_flNextPrimaryAttack = GetNextAttackDelay(1);
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5;// idle pretty soon after shooting.
if (!m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType])
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
m_pPlayer->pev->punchangle.x -= 10;
}
void CM41A::Reload( void )
{
if ( m_pPlayer->ammo_9mm <= 0 )
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == MP5_MAX_CLIP )
return;
DefaultReload( MP5_MAX_CLIP, M41A_RELOAD, 1.5 );
DefaultReload( MP5_MAX_CLIP, M41A_RELOAD, 2.0 );
}
void CM41A::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
ResetEmptySound( );
m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
@ -280,3 +308,8 @@ void CM41A::WeaponIdle( void )
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); // how long till we do this again.
}
BOOL CM41A::IsUseable()
{
//Can be used if the player has AR grenades. - Solokiller
return CBasePlayerWeapon::IsUseable() || m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] > 0;
}

517
dlls/asheep/panther.cpp Normal file
View File

@ -0,0 +1,517 @@
/***
*
* Copyright (c) 1996-2002, 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.
*
****/
//=========================================================
// Alien slave monster
//=========================================================
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "squadmonster.h"
#include "schedule.h"
#include "effects.h"
#include "weapons.h"
#include "soundent.h"
#include "islave.h"
class CPanther : public CISlave
{
public:
void Spawn( void );
void Precache( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
void DeathSound( void );
void PainSound( void );
void AlertSound( void );
void IdleSound( void );
void ClearBeams();
void ArmBeam( int side );
void WackBeam( int side, CBaseEntity *pEntity );
void ZapBeam( int side );
static const char *pAttackHitSounds[];
static const char *pAttackMissSounds[];
static const char *pPainSounds[];
static const char *pDeathSounds[];
static const char *pIdleSounds[];
static const char *pAlertSounds[];
};
LINK_ENTITY_TO_CLASS( monster_alien_panther, CPanther )
const char *CPanther::pAttackHitSounds[] =
{
"panther/pclaw_strike1.wav",
"panther/pclaw_strike2.wav",
"panther/pclaw_strike3.wav",
};
const char *CPanther::pAttackMissSounds[] =
{
"panther/pclaw_miss1.wav",
"panther/pclaw_miss2.wav",
};
const char *CPanther::pPainSounds[] =
{
"panther/p_pain1.wav",
"panther/p_pain2.wav",
};
const char *CPanther::pDeathSounds[] =
{
"panther/p_die1.wav",
"panther/p_die2.wav",
};
const char *CPanther::pIdleSounds[] =
{
"panther/p_idle1.wav",
"panther/p_idle2.wav",
};
const char *CPanther::pAlertSounds[] =
{
"panther/p_alert1.wav",
"panther/p_alert2.wav",
};
//=========================================================
// ALertSound - scream
//=========================================================
void CPanther::AlertSound( void )
{
if( m_hEnemy != 0 )
{
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAlertSounds[RANDOM_LONG( 0, ARRAYSIZE( pDeathSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch );
}
}
//=========================================================
// IdleSound
//=========================================================
void CPanther::IdleSound( void )
{
if( RANDOM_LONG( 0, 2 ) == 0 )
{
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pIdleSounds[RANDOM_LONG( 0, ARRAYSIZE( pDeathSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch );
}
#if 0
int side = RANDOM_LONG( 0, 1 ) * 2 - 1;
ClearBeams();
ArmBeam( side );
UTIL_MakeAimVectors( pev->angles );
Vector vecSrc = pev->origin + gpGlobals->v_right * 2 * side;
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc );
WRITE_BYTE( TE_DLIGHT );
WRITE_COORD( vecSrc.x ); // X
WRITE_COORD( vecSrc.y ); // Y
WRITE_COORD( vecSrc.z ); // Z
WRITE_BYTE( 8 ); // radius * 0.1
WRITE_BYTE( 255 ); // r
WRITE_BYTE( 180 ); // g
WRITE_BYTE( 96 ); // b
WRITE_BYTE( 10 ); // time * 10
WRITE_BYTE( 0 ); // decay * 0.1
MESSAGE_END();
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "debris/zap1.wav", 1, ATTN_NORM, 0, 100 );
#endif
}
//=========================================================
// PainSound
//=========================================================
void CPanther::PainSound( void )
{
if( RANDOM_LONG( 0, 2 ) == 0 )
{
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pPainSounds[RANDOM_LONG( 0, ARRAYSIZE( pPainSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch );
}
}
//=========================================================
// DieSound
//=========================================================
void CPanther::DeathSound( void )
{
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pDeathSounds[RANDOM_LONG( 0, ARRAYSIZE( pDeathSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch );
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CPanther::HandleAnimEvent( MonsterEvent_t *pEvent )
{
// ALERT( at_console, "event %d : %f\n", pEvent->event, pev->frame );
switch( pEvent->event )
{
case ISLAVE_AE_CLAW:
{
// SOUND HERE!
CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.pantherDmgClaw, DMG_SLASH );
if( pHurt )
{
if( pHurt->pev->flags & ( FL_MONSTER | FL_CLIENT ) )
{
pHurt->pev->punchangle.z = -18;
pHurt->pev->punchangle.x = 5;
}
// Play a random attack hit sound
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackHitSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackHitSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch );
}
else
{
// Play a random attack miss sound
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackMissSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackMissSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch );
}
}
break;
case ISLAVE_AE_CLAWRAKE:
{
CBaseEntity *pHurt = CheckTraceHullAttack( 70, gSkillData.pantherDmgClawRake, DMG_SLASH );
if( pHurt )
{
if( pHurt->pev->flags & ( FL_MONSTER | FL_CLIENT ) )
{
pHurt->pev->punchangle.z = -18;
pHurt->pev->punchangle.x = 5;
}
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, pAttackHitSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackHitSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch );
}
else
{
EMIT_SOUND_DYN( ENT(pev), CHAN_WEAPON, pAttackMissSounds[RANDOM_LONG( 0, ARRAYSIZE( pAttackMissSounds ) - 1 )], 1.0, ATTN_NORM, 0, m_voicePitch );
}
}
break;
case ISLAVE_AE_ZAP_POWERUP:
{
// speed up attack when on hard
if( g_iSkillLevel == SKILL_HARD )
pev->framerate = 1.5;
UTIL_MakeAimVectors( pev->angles );
if( m_iBeams == 0 )
{
Vector vecSrc = pev->origin + gpGlobals->v_forward * 2;
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc );
WRITE_BYTE( TE_DLIGHT );
WRITE_COORD( vecSrc.x ); // X
WRITE_COORD( vecSrc.y ); // Y
WRITE_COORD( vecSrc.z ); // Z
WRITE_BYTE( 12 ); // radius * 0.1
WRITE_BYTE( 192 ); // r
WRITE_BYTE( 64 ); // g
WRITE_BYTE( 8 ); // b
WRITE_BYTE( 20 / pev->framerate ); // time * 10
WRITE_BYTE( 0 ); // decay * 0.1
MESSAGE_END();
}
if( m_hDead != 0 )
{
WackBeam( -1, m_hDead );
WackBeam( 1, m_hDead );
}
else
{
ArmBeam( -1 );
ArmBeam( 1 );
BeamGlow();
}
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "panther/p_zap2.wav", 1, ATTN_NORM, 0, 100 + m_iBeams * 10 );
pev->skin = m_iBeams / 2;
}
break;
case ISLAVE_AE_ZAP_SHOOT:
{
ClearBeams();
if( m_hDead != 0 )
{
Vector vecDest = m_hDead->pev->origin + Vector( 0, 0, 38 );
TraceResult trace;
UTIL_TraceHull( vecDest, vecDest, dont_ignore_monsters, human_hull, m_hDead->edict(), &trace );
if( !trace.fStartSolid )
{
CBaseEntity *pNew = Create( STRING( pev->classname ), m_hDead->pev->origin, m_hDead->pev->angles );
//CBaseMonster *pNewMonster = pNew->MyMonsterPointer();
pNew->pev->spawnflags |= 1;
WackBeam( -1, pNew );
WackBeam( 1, pNew );
UTIL_Remove( m_hDead );
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "panther/p_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) );
/*
CBaseEntity *pEffect = Create( "test_effect", pNew->Center(), pev->angles );
pEffect->Use( this, this, USE_ON, 1 );
*/
break;
}
}
ClearMultiDamage();
UTIL_MakeAimVectors( pev->angles );
ZapBeam( -1 );
ZapBeam( 1 );
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "panther/p_shoot1.wav", 1, ATTN_NORM, 0, RANDOM_LONG( 130, 160 ) );
// STOP_SOUND( ENT( pev ), CHAN_WEAPON, "panther/p_zap2.wav" );
ApplyMultiDamage( pev, pev );
m_flNextAttack = gpGlobals->time + RANDOM_FLOAT( 0.5, 4.0 );
}
break;
case ISLAVE_AE_ZAP_DONE:
{
ClearBeams();
}
break;
default:
CSquadMonster::HandleAnimEvent( pEvent );
break;
}
}
//=========================================================
// Spawn
//=========================================================
void CPanther::Spawn()
{
Precache();
SET_MODEL( ENT( pev ), "models/panther.mdl" );
UTIL_SetSize( pev, Vector( -32, -32, 0 ), Vector( 32, 32, 64 ) );
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
pev->effects = 0;
pev->health = gSkillData.pantherHealth;
m_bloodColor = BLOOD_COLOR_GREEN;
m_voicePitch = RANDOM_LONG( 85, 110 );
pev->view_ofs = Vector( 0, 0, 80 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_RANGE_ATTACK2 | bits_CAP_DOORS_GROUP;
MonsterInit();
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CPanther::Precache()
{
size_t i;
PRECACHE_MODEL( "models/panther.mdl" );
PRECACHE_SOUND( "panther/p_zap1.wav" );
PRECACHE_SOUND( "panther/p_zap2.wav" );
PRECACHE_SOUND( "panther/p_electro1.wav" );
PRECACHE_SOUND( "panther/p_shoot1.wav" );
PRECACHE_SOUND( "panther/p_pain2.wav" );
PRECACHE_SOUND( "panther/p_headbite.wav" );
PRECACHE_SOUND( "panther/pclaw_miss1.wav" );
for( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND( pAttackHitSounds[i] );
for( i = 0; i < ARRAYSIZE( pAttackMissSounds ); i++ )
PRECACHE_SOUND( pAttackMissSounds[i] );
for( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND( pIdleSounds[i] );
for( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND( pAlertSounds[i] );
for( i = 0; i < ARRAYSIZE( pPainSounds ); i++ )
PRECACHE_SOUND( pPainSounds[i] );
for( i = 0; i < ARRAYSIZE( pDeathSounds ); i++ )
PRECACHE_SOUND( pDeathSounds[i] );
UTIL_PrecacheOther( "test_effect" );
}
void CPanther::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
{
if( bitsDamageType & DMG_SHOCK )
return;
if( ptr->iHitgroup != HITGROUP_HEAD )
{
if( bitsDamageType & ( DMG_BULLET | DMG_SLASH | DMG_CLUB ) )
{
UTIL_Ricochet( ptr->vecEndPos, 1.0 );
flDamage = 0.01;
}
}
CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
}
//=========================================================
// ArmBeam - small beam from arm to nearby geometry
//=========================================================
void CPanther::ArmBeam( int side )
{
TraceResult tr;
int r, g, b;
float flDist = 1.0;
if( m_iBeams >= ISLAVE_MAX_BEAMS )
return;
UTIL_MakeAimVectors( pev->angles );
Vector vecSrc = pev->origin + gpGlobals->v_up * 36 + gpGlobals->v_right * side * 16 + gpGlobals->v_forward * 32;
for( int i = 0; i < 3; i++ )
{
Vector vecAim = gpGlobals->v_right * side * RANDOM_FLOAT( 0, 1 ) + gpGlobals->v_up * RANDOM_FLOAT( -1, 1 );
TraceResult tr1;
UTIL_TraceLine( vecSrc, vecSrc + vecAim * 512, dont_ignore_monsters, ENT( pev ), &tr1 );
if( flDist > tr1.flFraction )
{
tr = tr1;
flDist = tr.flFraction;
}
}
// Couldn't find anything close enough
if( flDist == 1.0 )
return;
DecalGunshot( &tr, BULLET_PLAYER_CROWBAR );
m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 );
if( !m_pBeam[m_iBeams] )
return;
m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex() );
m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 );
// m_pBeam[m_iBeams]->SetColor( 180, 255, 96 );
r = 192, g = 64, b = 8;
m_pBeam[m_iBeams]->SetColor( r, g, b );
m_pBeam[m_iBeams]->SetBrightness( 64 );
m_pBeam[m_iBeams]->SetNoise( 80 );
m_iBeams++;
}
//=========================================================
// WackBeam - regenerate dead colleagues
//=========================================================
void CPanther::WackBeam( int side, CBaseEntity *pEntity )
{
//Vector vecDest;
//float flDist = 1.0;
int r, g, b;
if( m_iBeams >= ISLAVE_MAX_BEAMS )
return;
if( pEntity == NULL )
return;
m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 30 );
if( !m_pBeam[m_iBeams] )
return;
m_pBeam[m_iBeams]->PointEntInit( pEntity->Center(), entindex() );
m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 );
r = 192, g = 64, b = 8;
m_pBeam[m_iBeams]->SetColor( r, g, b );
m_pBeam[m_iBeams]->SetBrightness( 255 );
m_pBeam[m_iBeams]->SetNoise( 80 );
m_iBeams++;
}
//=========================================================
// ZapBeam - heavy damage directly forward
//=========================================================
void CPanther::ZapBeam( int side )
{
Vector vecSrc, vecAim;
int r, g, b;
TraceResult tr;
CBaseEntity *pEntity;
if( m_iBeams >= ISLAVE_MAX_BEAMS )
return;
vecSrc = pev->origin + gpGlobals->v_up * 36;
vecAim = ShootAtEnemy( vecSrc );
float deflection = 0.01;
vecAim = vecAim + side * gpGlobals->v_right * RANDOM_FLOAT( 0, deflection ) + gpGlobals->v_up * RANDOM_FLOAT( -deflection, deflection );
UTIL_TraceLine( vecSrc, vecSrc + vecAim * 1024, dont_ignore_monsters, ENT( pev ), &tr );
m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.spr", 50 );
if( !m_pBeam[m_iBeams] )
return;
m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex() );
m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 );
r = 192, g = 64, b = 8;
m_pBeam[m_iBeams]->SetColor( r, g, b );
m_pBeam[m_iBeams]->SetBrightness( 255 );
m_pBeam[m_iBeams]->SetNoise( 20 );
m_iBeams++;
pEntity = CBaseEntity::Instance( tr.pHit );
if( pEntity != NULL && pEntity->pev->takedamage )
{
pEntity->TraceAttack( pev, gSkillData.pantherDmgZap, vecAim, &tr, DMG_SHOCK );
}
UTIL_EmitAmbientSound( ENT( pev ), tr.vecEndPos, "panther/p_electro1.wav", 0.5, ATTN_NORM, 0, RANDOM_LONG( 140, 160 ) );
}
//=========================================================
// ClearBeams - remove all beams
//=========================================================
void CPanther::ClearBeams()
{
for( int i = 0; i < ISLAVE_MAX_BEAMS; i++ )
{
if( m_pBeam[i] )
{
UTIL_Remove( m_pBeam[i] );
m_pBeam[i] = NULL;
}
}
m_iBeams = 0;
pev->skin = 0;
STOP_SOUND( ENT( pev ), CHAN_WEAPON, "panther/p_zap2.wav" );
}

View File

@ -26,8 +26,7 @@
#define POOLSTICK_BODYHIT_VOLUME 128
#define POOLSTICK_WALLHIT_VOLUME 512
LINK_ENTITY_TO_CLASS( weapon_poolstick, CPoolstick );
LINK_ENTITY_TO_CLASS( weapon_poolstick, CPoolstick )
enum poolstick_e {
@ -39,7 +38,9 @@ enum poolstick_e {
POOLSTICK_ATTACK2MISS,
POOLSTICK_ATTACK2HIT,
POOLSTICK_ATTACK3MISS,
POOLSTICK_ATTACK3HIT
POOLSTICK_ATTACK3HIT,
POOLSTICK_IDLE2,
POOLSTICK_IDLE3
};
@ -65,8 +66,6 @@ void CPoolstick::Precache( void )
PRECACHE_SOUND("weapons/pstk_hitbod2.wav");
PRECACHE_SOUND("weapons/pstk_hitbod3.wav");
PRECACHE_SOUND("weapons/pstk_miss1.wav");
m_usPoolstick = PRECACHE_EVENT ( 1, "events/crowbar.sc" );
}
int CPoolstick::GetItemInfo(ItemInfo *p)
@ -78,7 +77,7 @@ int CPoolstick::GetItemInfo(ItemInfo *p)
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 0;
p->iPosition = 2;
p->iPosition = 1;
p->iId = WEAPON_POOLSTICK;
p->iWeight = CROWBAR_WEIGHT;
return 1;
@ -93,12 +92,11 @@ BOOL CPoolstick::Deploy( )
void CPoolstick::Holster( int skiplocal /* = 0 */ )
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
SendWeaponAnim( POOLSTICK_HOLSTER );
DefaultHolster( POOLSTICK_HOLSTER, 0.7 );
}
void FindHullIntersection2( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity )
extern void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity );
/*void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity )
{
int i, j, k;
float distance;
@ -141,10 +139,16 @@ void FindHullIntersection2( const Vector &vecSrc, TraceResult &tr, float *mins,
}
}
}
*/
void CPoolstick::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if (! Swing( 1 ))
{
SetThink( &CPoolstick::SwingAgain );
@ -187,23 +191,32 @@ int CPoolstick::Swing( int fFirst )
// This is and approximation of the "best" intersection
CBaseEntity *pHit = CBaseEntity::Instance( tr.pHit );
if ( !pHit || pHit->IsBSPModel() )
FindHullIntersection2( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict() );
FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, m_pPlayer->edict() );
vecEnd = tr.vecEndPos; // This is the point on the actual surface (the hull could have hit space)
}
}
#endif
PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usPoolstick,
0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, 0,
0.0, 0, 0.0 );
if ( tr.flFraction >= 1.0 )
{
if (fFirst)
{
// miss
m_flNextPrimaryAttack = GetNextAttackDelay(0.5);
switch( ( m_iSwing++ ) % 3 )
{
case 0:
SendWeaponAnim( POOLSTICK_ATTACK1MISS );
break;
case 1:
SendWeaponAnim( POOLSTICK_ATTACK2MISS );
break;
case 2:
SendWeaponAnim( POOLSTICK_ATTACK3MISS );
break;
}
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;
EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/pstk_miss1.wav", 1, ATTN_NORM, 0, 94 + RANDOM_LONG( 0, 0xF ) );
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
@ -211,7 +224,7 @@ int CPoolstick::Swing( int fFirst )
}
else
{
switch( ((m_iSwing++) % 2) + 1 )
switch( (m_iSwing++) % 3)
{
case 0:
SendWeaponAnim( POOLSTICK_ATTACK1HIT ); break;
@ -224,7 +237,6 @@ int CPoolstick::Swing( int fFirst )
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
#ifndef CLIENT_DLL
// hit
fDidHit = TRUE;
@ -303,14 +315,49 @@ int CPoolstick::Swing( int fFirst )
}
m_pPlayer->m_iWeaponVolume = flVol * POOLSTICK_WALLHIT_VOLUME;
#endif
m_flNextPrimaryAttack = GetNextAttackDelay(0.25);
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25;
SetThink( &CPoolstick::Smack );
pev->nextthink = UTIL_WeaponTimeBase() + 0.2;
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
return fDidHit;
}
void CPoolstick::WeaponIdle()
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
if( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() )
{
int iAnim;
float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 );
if( flRand > 0.9 )
{
iAnim = POOLSTICK_IDLE2;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 160.0 / 30.0;
}
else
{
if( flRand > 0.5 )
{
iAnim = POOLSTICK_IDLE;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 70.0 / 30.0;
}
else
{
iAnim = POOLSTICK_IDLE3;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 160.0 / 30.0;
}
}
SendWeaponAnim( iAnim );
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -28,11 +28,12 @@ enum w_toad_e {
WTOAD_IDLE1 = 0,
WTOAD_FIDGET,
WTOAD_JUMP,
WTOAD_RUN,
WTOAD_RUN
};
enum toad_e {
TOAD_IDLE1 = 0,
TOAD_IDLE2,
TOAD_FIDGETFIT,
TOAD_FIDGETNIP,
TOAD_DOWN,
@ -41,7 +42,6 @@ enum toad_e {
};
#ifndef CLIENT_DLL
class CToadGrenade : public CGrenade
{
void Spawn( void );
@ -51,7 +51,7 @@ class CToadGrenade : public CGrenade
void EXPORT HuntThink( void );
int BloodColor( void ) { return BLOOD_COLOR_YELLOW; }
void Killed( entvars_t *pevAttacker, int iGib );
// void GibMonster( void );
void GibMonster( void );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
@ -70,6 +70,7 @@ class CToadGrenade : public CGrenade
int m_iMyClass;
};
extern int gEvilImpulse101;
float CToadGrenade::m_flNextBounceSoundTime = 0;
LINK_ENTITY_TO_CLASS( monster_toad, CToadGrenade );
@ -150,7 +151,7 @@ void CToadGrenade::Precache( void )
{
PRECACHE_MODEL("models/w_toad.mdl");
PRECACHE_SOUND("toad/toad_blast1.wav");
// PRECACHE_SOUND("common/bodysplat.wav");
PRECACHE_SOUND("common/bodysplat.wav");
PRECACHE_SOUND("toad/toad_die1.wav");
PRECACHE_SOUND("toad/toad_hunt1.wav");
PRECACHE_SOUND("toad/toad_hunt2.wav");
@ -173,7 +174,7 @@ void CToadGrenade :: Killed( entvars_t *pevAttacker, int iGib )
pev->takedamage = DAMAGE_NO;
// play squeek blast
EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "squeek/toad_blast1.wav", 1, 0.5, 0, PITCH_NORM);
EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "toad/toad_blast1.wav", 1, 0.5, 0, PITCH_NORM);
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, SMALL_EXPLOSION_VOLUME, 3.0 );
@ -191,10 +192,10 @@ void CToadGrenade :: Killed( entvars_t *pevAttacker, int iGib )
CBaseMonster :: Killed( pevAttacker, GIB_ALWAYS );
}
/* void CToadGrenade :: GibMonster( void )
void CToadGrenade :: GibMonster( void )
{
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200);
} */
}
@ -232,7 +233,7 @@ void CToadGrenade::HuntThink( void )
pev->velocity = pev->velocity * 0.9;
pev->velocity.z += 8.0;
}
else if (pev->movetype = MOVETYPE_FLY)
else if (pev->movetype == MOVETYPE_FLY)
{
pev->movetype = MOVETYPE_BOUNCE;
}
@ -263,7 +264,7 @@ void CToadGrenade::HuntThink( void )
// squeek if it's about time blow up
if ((m_flDie - gpGlobals->time <= 0.5) && (m_flDie - gpGlobals->time >= 0.3))
{
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "squeek/toad_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG(0,0x3F));
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "toad/toad_die1.wav", 1, ATTN_NORM, 0, 100 + RANDOM_LONG(0,0x3F));
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 256, 0.25 );
}
@ -364,7 +365,7 @@ void CToadGrenade::SuperBounceTouch( CBaseEntity *pOther )
// m_flDie += 2.0; // add more life
// make bite sound
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "squeek/toad_deploy1.wav", 1.0, ATTN_NORM, 0, (int)flpitch);
EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, "toad/toad_deploy1.wav", 1.0, ATTN_NORM, 0, (int)flpitch);
m_flNextAttack = gpGlobals->time + 0.5;
}
}
@ -422,25 +423,28 @@ void CToad::Spawn( )
FallInit();//get ready to fall down.
m_iDefaultAmmo = SNARK_DEFAULT_GIVE;
m_iDefaultAmmo = TOAD_DEFAULT_GIVE;
pev->sequence = 1;
pev->animtime = gpGlobals->time;
pev->framerate = 1.0;
SetThink( &CToad::ToadIdle );
pev->nextthink = gpGlobals->time + 0.2f;
m_flNextTrace = 0;
m_flNextHunt = 0;
m_flDie = 0;
}
void CToad::Precache( void )
{
PRECACHE_MODEL("models/toad_nest.mdl");
PRECACHE_MODEL("models/toad_nestt.mdl");
PRECACHE_MODEL("models/v_toad.mdl");
PRECACHE_MODEL("models/p_toad.mdl");
PRECACHE_SOUND("toad/toad_hunt2.wav");
PRECACHE_SOUND("toad/toad_hunt3.wav");
UTIL_PrecacheOther("monster_toad");
m_usToadFire = PRECACHE_EVENT ( 1, "events/snarkfire.sc" );
}
@ -453,7 +457,7 @@ int CToad::GetItemInfo(ItemInfo *p)
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 4;
p->iPosition = 4;
p->iPosition = 5;
p->iId = m_iId = WEAPON_TOAD;
p->iWeight = SNARK_WEIGHT;
p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE;
@ -465,16 +469,20 @@ int CToad::GetItemInfo(ItemInfo *p)
BOOL CToad::Deploy( )
{
// play hunt sound
float flRndSound = RANDOM_FLOAT ( 0 , 1 );
if( !gEvilImpulse101 )
{
// play hunt sound
float flRndSound = RANDOM_FLOAT( 0, 1 );
if ( flRndSound <= 0.5 )
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "toad/toad_hunt2.wav", 1, ATTN_NORM, 0, 100);
else
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "toad/toad_hunt3.wav", 1, ATTN_NORM, 0, 100);
if ( flRndSound <= 0.5 )
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "toad/toad_hunt2.wav", 1, ATTN_NORM, 0, 100);
else
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "toad/toad_hunt3.wav", 1, ATTN_NORM, 0, 100);
m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
}
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.1;
return DefaultDeploy( "models/v_toad.mdl", "models/p_toad.mdl", TOAD_UP, "toad" );
}
@ -491,13 +499,19 @@ void CToad::Holster( int skiplocal /* = 0 */ )
return;
}
SendWeaponAnim( TOAD_DOWN );
DefaultHolster( TOAD_DOWN, 1.5 );
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM);
}
void CToad::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] )
{
UTIL_MakeVectors( m_pPlayer->pev->v_angle );
@ -515,17 +529,10 @@ void CToad::PrimaryAttack()
// find place to toss monster
UTIL_TraceLine( trace_origin + gpGlobals->v_forward * 20, trace_origin + gpGlobals->v_forward * 64, dont_ignore_monsters, NULL, &tr );
int flags;
#ifdef CLIENT_WEAPONS
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usToadFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 );
if ( tr.fAllSolid == 0 && tr.fStartSolid == 0 && tr.flFraction > 0.25 )
{
SendWeaponAnim( TOAD_THROW );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
@ -557,12 +564,26 @@ void CToad::PrimaryAttack()
void CToad::SecondaryAttack( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
}
void CToad::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
return;
@ -581,24 +602,130 @@ void CToad::WeaponIdle( void )
return;
}
int iAnim;
float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 );
if (flRand <= 0.75)
{
iAnim = TOAD_IDLE1;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2);
}
else if (flRand <= 0.875)
int iAnim, iRand = RANDOM_LONG( 0, 5 );
switch( iRand )
{
case 0:
iAnim = TOAD_IDLE2;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.2f;
break;
case 1:
iAnim = TOAD_FIDGETFIT;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 70.0 / 16.0;
}
else
{
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.18f;
break;
case 2:
iAnim = TOAD_FIDGETNIP;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 16.0;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.9f;
break;
default:
iAnim = TOAD_IDLE1;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.2f;
break;
}
SendWeaponAnim( iAnim );
}
void CToad::ToadIdle()
{
int i;
float flDist;
CBaseEntity *pPlayer = UTIL_PlayerByIndex( 1 );
if( !pPlayer )
return;
flDist = ( pPlayer->Center() - this->Center() ).Length();
if( !pPlayer->FVisible( this ) || flDist >= 256.0f )
{
if( pev->sequence != 1 )
{
pev->sequence = 1;
pev->framerate = 0.5;
ResetSequenceInfo();
}
if( !RANDOM_LONG( 0, 10 ) )
HuntSound( true );
pev->nextthink = gpGlobals->time + 0.2f;
return;
}
if( flDist >= 50.0f )
{
TraceResult tr;
m_flDie = 1;
pev->movetype = MOVETYPE_STEP;
StudioFrameAdvance( 0.0 );
if( pev->sequence != 1 )
{
if( m_flNextTrace <= gpGlobals->time )
{
Vector vecSrc, vecEnd;
Vector vecDist2D = ( Center() - pPlayer->Center() ).Normalize();
vecDist2D.z = 0;
m_posNext = pev->origin + vecDist2D * 128;
vecSrc = EyePosition();
vecEnd = vecSrc + vecDist2D * 68;
UTIL_TraceLine( vecSrc, vecEnd, ignore_monsters, 0, &tr );
if( tr.flFraction < 1.0f )
{
Vector vecDist, vecForward, vecAngle;
vecDist = ( EyePosition() - tr.vecEndPos ).Normalize();
vecAngle = Vector( 0, UTIL_AngleMod( UTIL_VecToAngles( vecDist ).y ) + 195.0f, 0 );
UTIL_MakeVectorsPrivate( vecAngle, vecForward, 0, 0 );
m_posNext = pev->origin - vecForward * 128;
}
m_flNextTrace = gpGlobals->time + 0.5f;
}
Vector newPos = m_posNext - Center();
newPos.z = 0;
pev->angles = UTIL_VecToAngles( newPos );
UTIL_MoveToOrigin( ENT( pev ), newPos * 256.0f, 200.0f / m_flGroundSpeed, MOVE_STRAFE );
HuntSound( false );
pev->nextthink = gpGlobals->time + 0.2f;
return;
}
pev->sequence = 0;
pev->frame = 0;
ResetSequenceInfo();
pev->framerate = 3.0;
HuntSound( true );
pev->nextthink = gpGlobals->time + 0.2f;
return;
}
if( m_flDie == 1 )
{
for( i = 0; i < m_iDefaultAmmo; i++ )
( (CBasePlayer*)pPlayer )->GiveNamedItem( "weapon_toad" );
SetThink( &CBaseEntity::SUB_Remove );
pev->nextthink = gpGlobals->time + 0.1f;
}
}
void CToad::HuntSound( bool force )
{
const char *pszSound;
if( ( m_flNextHunt <= gpGlobals->time ) || force )
{
int iRand = RANDOM_LONG( 0, 2 );
if( iRand == 2 )
{
pszSound = "toad/toad_hunt3.wav";
}
else if( iRand == 1 )
{
pszSound = "toad/toad_hunt2.wav";
}
else
{
pszSound = "toad/toad_hunt1.wav";
}
EMIT_SOUND( ENT( pev ), CHAN_VOICE, pszSound, RANDOM_FLOAT( 0.5, 0.8 ), ATTN_NORM );
m_flNextHunt = gpGlobals->time + RANDOM_FLOAT( 3.0, 4.0 );
}
}
#endif

View File

@ -27,68 +27,11 @@
#include "scripted.h"
#include "weapons.h"
#include "soundent.h"
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
// first flag is barney dying for scripted sequences?
#define BARNEY_AE_DRAW ( 2 )
#define BARNEY_AE_SHOOT ( 3 )
#define BARNEY_AE_HOLSTER ( 4 )
#define BARNEY_BODY_GUNHOLSTERED 0
#define BARNEY_BODY_GUNDRAWN 1
#define BARNEY_BODY_GUNGONE 2
class CBarney : public CTalkMonster
{
public:
void Spawn( void );
void Precache( void );
void SetYawSpeed( void );
int ISoundMask( void );
void BarneyFirePistol( void );
void AlertSound( void );
int Classify( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
void RunTask( Task_t *pTask );
void StartTask( Task_t *pTask );
virtual int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; }
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
BOOL CheckRangeAttack1( float flDot, float flDist );
void DeclineFollowing( void );
// Override these to set behavior
Schedule_t *GetScheduleOfType( int Type );
Schedule_t *GetSchedule( void );
MONSTERSTATE GetIdealState( void );
void DeathSound( void );
void PainSound( void );
void TalkInit( void );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
void Killed( entvars_t *pevAttacker, int iGib );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
BOOL m_fGunDrawn;
float m_painTime;
float m_checkAttackTime;
BOOL m_lastAttackCheck;
// UNDONE: What is this for? It isn't used?
float m_flPlayerDamage;// how much pain has the player inflicted on me?
CUSTOM_SCHEDULES
};
#include "barney.h"
LINK_ENTITY_TO_CLASS( monster_barney, CBarney )
LINK_ENTITY_TO_CLASS( monster_hevbarn, CBarney )
LINK_ENTITY_TO_CLASS( monster_myself, CBarney )
TYPEDESCRIPTION CBarney::m_SaveData[] =
{
@ -174,6 +117,7 @@ Schedule_t slBaFaceTarget[] =
Task_t tlIdleBaStand[] =
{
{ TASK_STOP_MOVING, 0 },
{ TASK_SET_ACTIVITY, (float)ACT_DISARM },
{ TASK_SET_ACTIVITY, (float)ACT_IDLE },
{ TASK_WAIT, (float)2 }, // repick IDLESTAND every two seconds.
{ TASK_TLK_HEADRESET, (float)0 }, // reset head position
@ -201,12 +145,15 @@ Schedule_t slIdleBaStand[] =
},
};
extern Schedule_t slGruntHideReload[];
DEFINE_CUSTOM_SCHEDULES( CBarney )
{
slBaFollow,
slBarneyEnemyDraw,
slBaFaceTarget,
slIdleBaStand,
slGruntHideReload
};
IMPLEMENT_CUSTOM_SCHEDULES( CBarney, CTalkMonster )
@ -370,6 +317,11 @@ void CBarney::HandleAnimEvent( MonsterEvent_t *pEvent )
{
switch( pEvent->event )
{
case BARNEY_AE_RELOAD:
EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "weapons/reload3.wav", 1, ATTN_NORM, 0, 100 );
m_cAmmoLoaded = GLOCK_MAX_CLIP;
ClearConditions( bits_COND_NO_AMMO_LOADED );
break;
case BARNEY_AE_SHOOT:
BarneyFirePistol();
break;
@ -395,22 +347,27 @@ void CBarney::Spawn()
{
Precache();
SET_MODEL( ENT( pev ), "models/barney.mdl" );
SET_MODEL( ENT( pev ), STRING( pev->model ) );
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
pev->health = gSkillData.barneyHealth;
if( FClassnameIs( pev, "monster_hevbarn" ) )
pev->health = gSkillData.barneyHealth * 1.5;
else
pev->health = gSkillData.barneyHealth;
pev->view_ofs = Vector ( 0, 0, 50 );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_MonsterState = MONSTERSTATE_NONE;
pev->body = 0; // gun in holster
pev->body = FBitSet( pev->spawnflags, SF_BARNEY_CARDS_BARNEY ) ? BARNEY_BODY_GUNDRAWN : BARNEY_BODY_GUNHOLSTERED;
m_fGunDrawn = FALSE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
m_cAmmoLoaded = GLOCK_MAX_CLIP;
MonsterInit();
SetUse( &CTalkMonster::FollowerUse );
}
@ -420,7 +377,18 @@ void CBarney::Spawn()
//=========================================================
void CBarney::Precache()
{
PRECACHE_MODEL( "models/barney.mdl" );
if( FClassnameIs( pev, "monster_myself" ) )
pev->model = MAKE_STRING( "models/myself.mdl" );
else if( FClassnameIs( pev, "monster_hevbarn" ) )
pev->model = MAKE_STRING( "models/hev_barney.mdl" );
else if( pev->spawnflags & SF_BARNEY_LAZY_BARNEY )
pev->model = MAKE_STRING( "models/lazybarney.mdl" );
else if( pev->spawnflags & SF_BARNEY_CARDS_BARNEY )
pev->model = MAKE_STRING( "models/cardsbarney.mdl" );
else
pev->model = MAKE_STRING( "models/barney.mdl" );
PRECACHE_MODEL( STRING( pev->model ) );
PRECACHE_SOUND( "barney/ba_attack1.wav" );
PRECACHE_SOUND( "barney/ba_attack2.wav" );
@ -433,6 +401,8 @@ void CBarney::Precache()
PRECACHE_SOUND( "barney/ba_die2.wav" );
PRECACHE_SOUND( "barney/ba_die3.wav" );
PRECACHE_SOUND( "weapons/reload3.wav" );
// every new barney must call this, otherwise
// when a level is loaded, nobody will talk (time is reset to 0)
TalkInit();
@ -460,8 +430,8 @@ void CBarney::TalkInit()
m_szGrp[TLK_PLHURT2] = "!BA_CUREB";
m_szGrp[TLK_PLHURT3] = "!BA_CUREC";
m_szGrp[TLK_PHELLO] = NULL; //"BA_PHELLO"; // UNDONE
m_szGrp[TLK_PIDLE] = NULL; //"BA_PIDLE"; // UNDONE
m_szGrp[TLK_PHELLO] = "BA_PHELLO"; // UNDONE
m_szGrp[TLK_PIDLE] = "BA_PIDLE"; // UNDONE
m_szGrp[TLK_PQUESTION] = "BA_PQUEST"; // UNDONE
m_szGrp[TLK_SMELL] = "BA_SMELL";
@ -473,6 +443,18 @@ void CBarney::TalkInit()
m_voicePitch = 100;
}
//=========================================================
// CheckAmmo - overridden for the barney because he actually
// uses ammo! (base class doesn't)
//=========================================================
void CBarney::CheckAmmo( void )
{
if( m_cAmmoLoaded <= 0 )
{
SetConditions( bits_COND_NO_AMMO_LOADED );
}
}
static BOOL IsFacing( entvars_t *pevTest, const Vector &reference )
{
Vector vecDir = reference - pevTest->origin;
@ -611,12 +593,17 @@ void CBarney::Killed( entvars_t *pevAttacker, int iGib )
// drop the gun!
Vector vecGunPos;
Vector vecGunAngles;
const char *pszName;
pev->body = BARNEY_BODY_GUNGONE;
GetAttachment( 0, vecGunPos, vecGunAngles );
DropItem( "weapon_barney9mmhg", vecGunPos, vecGunAngles ); // edit Alex, in Azure Sheep entity is named another way
if( FBitSet( pev->spawnflags, SF_BARNEY_HAVESUIT ) )
pszName = "weapon_9mmhandgun";
else
pszName = "weapon_barney9mmhg";
DropItem( pszName, vecGunPos, vecGunAngles );
}
SetUse( NULL );
@ -632,6 +619,8 @@ Schedule_t *CBarney::GetScheduleOfType( int Type )
switch( Type )
{
case SCHED_BARNEY_COVER_AND_RELOAD:
return slGruntHideReload;
case SCHED_ARM_WEAPON:
if( m_hEnemy != 0 )
{
@ -711,6 +700,9 @@ Schedule_t *CBarney::GetSchedule( void )
if( HasConditions( bits_COND_HEAVY_DAMAGE ) )
return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY );
if( HasConditions( bits_COND_NO_AMMO_LOADED ) )
return GetScheduleOfType( SCHED_BARNEY_COVER_AND_RELOAD );
}
break;
case MONSTERSTATE_ALERT:
@ -800,14 +792,35 @@ void CDeadBarney::KeyValue( KeyValueData *pkvd )
}
LINK_ENTITY_TO_CLASS( monster_barney_dead, CDeadBarney )
LINK_ENTITY_TO_CLASS( monster_hevbarn_dead, CDeadBarney )
LINK_ENTITY_TO_CLASS( monster_myself_dead, CDeadBarney )
LINK_ENTITY_TO_CLASS( monster_barniel_dead, CDeadBarney )
LINK_ENTITY_TO_CLASS( monster_adrian_dead, CDeadBarney )
LINK_ENTITY_TO_CLASS( monster_gordon_dead, CDeadBarney )
LINK_ENTITY_TO_CLASS( monster_kate_dead, CDeadBarney )
//=========================================================
// ********** DeadBarney SPAWN **********
//=========================================================
void CDeadBarney::Spawn()
{
PRECACHE_MODEL( "models/barney.mdl" );
SET_MODEL( ENT( pev ), "models/barney.mdl" );
if( FClassnameIs( pev, "monster_adrian_dead" ) )
pev->model = MAKE_STRING( "models/adrian.mdl" );
else if( FClassnameIs( pev, "monster_gordon_dead" ) )
pev->model = MAKE_STRING( "models/gordon.mdl" );
else if( FClassnameIs( pev, "monster_barniel_dead" ) )
pev->model = MAKE_STRING( "models/barniel.mdl" );
else if( FClassnameIs( pev, "monster_kate_dead" ) )
pev->model = MAKE_STRING( "models/kate.mdl" );
else if( FClassnameIs( pev, "monster_myself_dead" ) )
pev->model = MAKE_STRING( "models/myself.mdl" );
else if( FClassnameIs( pev, "monster_hevbarn_dead" ) )
pev->model = MAKE_STRING( "models/hev_barney.mdl" );
else
pev->model = MAKE_STRING( "models/barney.mdl" );
PRECACHE_MODEL( STRING( pev->model ) );
SET_MODEL( ENT( pev ), STRING( pev->model ) );
pev->effects = 0;
pev->yaw_speed = 8;

94
dlls/barney.h Normal file
View File

@ -0,0 +1,94 @@
/***
*
* Copyright (c) 1996-2002, 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.
*
****/
//=========================================================
// monster template
//=========================================================
#ifndef BARNEY_H
#define BARNEY_H
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
// first flag is barney dying for scripted sequences?
#define BARNEY_AE_DRAW ( 2 )
#define BARNEY_AE_SHOOT ( 3 )
#define BARNEY_AE_HOLSTER ( 4 )
#define BARNEY_AE_RELOAD ( 5 )
#define BARNEY_AE_KICK ( 6 )
#define BARNEY_BODY_GUNHOLSTERED 0
#define BARNEY_BODY_GUNDRAWN 1
#define BARNEY_BODY_GUNGONE 2
#define SF_BARNEY_HAVESUIT 8
#define SF_BARNEY_LAZY_BARNEY 32
#define SF_BARNEY_CARDS_BARNEY 64
enum
{
SCHED_BARNEY_COVER_AND_RELOAD = LAST_COMMON_SCHEDULE + 1
};
//=========================================================
// CBarney
//=========================================================
class CBarney : public CTalkMonster
{
public:
virtual void Spawn( void );
virtual void Precache( void );
void SetYawSpeed( void );
int ISoundMask( void );
virtual void BarneyFirePistol( void );
virtual void AlertSound( void );
int Classify( void );
virtual void HandleAnimEvent( MonsterEvent_t *pEvent );
void RunTask( Task_t *pTask );
void StartTask( Task_t *pTask );
virtual int ObjectCaps( void ) { return CTalkMonster :: ObjectCaps() | FCAP_IMPULSE_USE; }
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType);
BOOL CheckRangeAttack1( float flDot, float flDist );
virtual void DeclineFollowing( void );
// Override these to set behavior
Schedule_t *GetScheduleOfType( int Type );
virtual Schedule_t *GetSchedule( void );
MONSTERSTATE GetIdealState( void );
virtual void DeathSound( void );
virtual void PainSound( void );
virtual void TalkInit( void );
void CheckAmmo( void );
virtual void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
virtual void Killed( entvars_t *pevAttacker, int iGib );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
BOOL m_fGunDrawn;
float m_painTime;
float m_checkAttackTime;
BOOL m_lastAttackCheck;
// UNDONE: What is this for? It isn't used?
float m_flPlayerDamage;// how much pain has the player inflicted on me?
CUSTOM_SCHEDULES
};
#endif

View File

@ -333,24 +333,6 @@ public:
virtual BOOL FVisible( CBaseEntity *pEntity );
virtual BOOL FVisible( const Vector &vecOrigin );
//We use this variables to store each ammo count.
int ammo_9mm;
int ammo_357;
int ammo_bolts;
int ammo_buckshot;
int ammo_rockets;
int ammo_uranium;
int ammo_hornets;
int ammo_argrens;
//Special stuff for grenades and satchels.
float m_flStartThrow;
float m_flReleaseThrow;
int m_chargeReady;
int m_fInAttack;
enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE };
int m_fireState;
};
// Ugly technique to override base member functions

View File

@ -25,7 +25,7 @@
#define MAX_WEAPON_SLOTS 5 // hud item selection slots
#define MAX_ITEM_TYPES 6 // hud item selection slots
#define MAX_ITEMS 5 // hard coded item types
#define MAX_ITEMS 6 // hard coded item types
#define HIDEHUD_WEAPONS ( 1<<0 )
#define HIDEHUD_FLASHLIGHT ( 1<<1 )

View File

@ -302,8 +302,14 @@ void CBaseMonster::GibMonster( void )
EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "common/bodysplat.wav", 1, ATTN_NORM );
if( FClassnameIs( pev, "monster_exp_alien_slave" ) )
{
if( CVAR_GET_FLOAT( "violence_hgibs" ) != 0 )
CGib::SpawnRandomGibs( pev, 4, 1 );
gibbed = TRUE;
}
// only humans throw skulls !!!UNDONE - eventually monsters will have their own sets of gibs
if( HasHumanGibs() )
else if( HasHumanGibs() )
{
if( CVAR_GET_FLOAT( "violence_hgibs" ) != 0 ) // Only the player will ever get here
{
@ -1536,6 +1542,12 @@ Vector CBaseEntity::FireBulletsPlayer( ULONG cShots, Vector vecSrc, Vector vecDi
case BULLET_PLAYER_357:
pEntity->TraceAttack( pevAttacker, gSkillData.plrDmg357, vecDir, &tr, DMG_BULLET );
break;
case BULLET_PLAYER_M41A:
pEntity->TraceAttack( pevAttacker, gSkillData.plrDmgM41A, vecDir, &tr, DMG_BULLET );
break;
case BULLET_PLAYER_BERETTA:
pEntity->TraceAttack( pevAttacker, gSkillData.plrDmgBeretta, vecDir, &tr, DMG_BULLET );
break;
case BULLET_NONE: // FIX
pEntity->TraceAttack( pevAttacker, 50, vecDir, &tr, DMG_CLUB );
TEXTURETYPE_PlaySound( &tr, vecSrc, vecEnd, iBulletType );

View File

@ -291,9 +291,6 @@ void CCrossbow::Precache( void )
PRECACHE_SOUND( "weapons/xbow_reload1.wav" );
UTIL_PrecacheOther( "crossbow_bolt" );
m_usCrossbow = PRECACHE_EVENT( 1, "events/crossbow1.sc" );
m_usCrossbow2 = PRECACHE_EVENT( 1, "events/crossbow2.sc" );
}
int CCrossbow::GetItemInfo( ItemInfo *p )
@ -305,7 +302,7 @@ int CCrossbow::GetItemInfo( ItemInfo *p )
p->iMaxAmmo2 = -1;
p->iMaxClip = CROSSBOW_MAX_CLIP;
p->iSlot = 2;
p->iPosition = 2;
p->iPosition = 4;
p->iId = WEAPON_CROSSBOW;
p->iFlags = 0;
p->iWeight = CROSSBOW_WEIGHT;
@ -321,22 +318,25 @@ BOOL CCrossbow::Deploy()
void CCrossbow::Holster( int skiplocal /* = 0 */ )
{
m_fInReload = FALSE;// cancel any reload in progress.
if( m_fInZoom )
{
SecondaryAttack();
}
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
if( m_iClip )
SendWeaponAnim( CROSSBOW_HOLSTER1 );
DefaultHolster( CROSSBOW_HOLSTER1, 0.7 );
else
SendWeaponAnim( CROSSBOW_HOLSTER2 );
DefaultHolster( CROSSBOW_HOLSTER2, 0.7 );
}
void CCrossbow::PrimaryAttack( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
#ifdef CLIENT_DLL
if( m_fInZoom && bIsMultiplayer() )
#else
@ -353,7 +353,7 @@ void CCrossbow::PrimaryAttack( void )
// this function only gets called in multiplayer
void CCrossbow::FireSniperBolt()
{
m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75;
if( m_iClip == 0 )
{
@ -366,14 +366,16 @@ void CCrossbow::FireSniperBolt()
m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
m_iClip--;
int flags;
#if defined( CLIENT_WEAPONS )
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrossbow2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType], 0, 0 );
EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/xbow_fire1.wav", RANDOM_FLOAT( 0.95, 1.0 ), ATTN_NORM, 0, 93 + RANDOM_LONG( 0, 0xF ) );
if( m_iClip )
{
EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/xbow_reload1.wav", RANDOM_FLOAT( 0.95, 1.0 ), ATTN_NORM, 0, 93 + RANDOM_LONG( 0, 0xF ) );
SendWeaponAnim( CROSSBOW_FIRE1 );
}
else if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] == 0 )
{
SendWeaponAnim( CROSSBOW_FIRE3 );
}
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
@ -388,10 +390,38 @@ void CCrossbow::FireSniperBolt()
#ifndef CLIENT_DLL
if( tr.pHit->v.takedamage )
{
EMIT_SOUND( tr.pHit, CHAN_BODY, RANDOM_LONG( 0, 1 ) ? "weapons/xbow_hitbod2.wav" : "weapons/xbow_hitbod1.wav", 1, ATTN_NORM );
ClearMultiDamage();
CBaseEntity::Instance( tr.pHit )->TraceAttack( m_pPlayer->pev, 120, vecDir, &tr, DMG_BULLET | DMG_NEVERGIB );
ApplyMultiDamage( pev, m_pPlayer->pev );
}
else
{
// create a bolt
CCrossbowBolt *pBolt = CCrossbowBolt::BoltCreate();
pBolt->pev->origin = tr.vecEndPos - vecDir * 10;
pBolt->pev->angles = UTIL_VecToAngles( vecDir );
pBolt->pev->solid = SOLID_NOT;
pBolt->SetTouch( NULL );
pBolt->SetThink( &CBaseEntity::SUB_Remove );
EMIT_SOUND( pBolt->edict(), CHAN_WEAPON, "weapons/xbow_hit1.wav", RANDOM_FLOAT( 0.95, 1.0 ), ATTN_NORM );
if( UTIL_PointContents( tr.vecEndPos ) != CONTENTS_WATER )
{
UTIL_Sparks( tr.vecEndPos );
}
if( FClassnameIs( tr.pHit, "worldspawn" ) )
{
// let the bolt sit around for a while if it hit static architecture
pBolt->pev->nextthink = gpGlobals->time + 5.0;
}
else
{
pBolt->pev->nextthink = gpGlobals->time;
}
}
#endif
}
@ -409,14 +439,15 @@ void CCrossbow::FireBolt()
m_iClip--;
int flags;
#if defined( CLIENT_WEAPONS )
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrossbow, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType], 0, 0 );
if( m_iClip )
{
EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/xbow_reload1.wav", RANDOM_FLOAT( 0.95, 1.0 ), ATTN_NORM, 0, 93 + RANDOM_LONG( 0, 0xF ) );
SendWeaponAnim( CROSSBOW_FIRE1 );
}
else if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] == 0 )
{
SendWeaponAnim( CROSSBOW_FIRE3 );
}
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
@ -452,7 +483,7 @@ void CCrossbow::FireBolt()
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 );
m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75;
@ -460,10 +491,18 @@ void CCrossbow::FireBolt()
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0;
else
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75;
m_pPlayer->pev->punchangle.x -= 2;
}
void CCrossbow::SecondaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_pPlayer->pev->fov != 0 )
{
m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov
@ -481,6 +520,12 @@ void CCrossbow::SecondaryAttack()
void CCrossbow::Reload( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == CROSSBOW_MAX_CLIP )
return;
@ -497,6 +542,16 @@ void CCrossbow::Reload( void )
void CCrossbow::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
m_pPlayer->GetAutoaimVector( AUTOAIM_2DEGREES ); // get the autoaim vector but ignore it; used for autoaim crosshair in DM
ResetEmptySound();

View File

@ -37,13 +37,9 @@ enum crowbar_e
CROWBAR_ATTACK2MISS,
CROWBAR_ATTACK2HIT,
CROWBAR_ATTACK3MISS,
#ifndef CROWBAR_IDLE_ANIM
CROWBAR_ATTACK3HIT
#else
CROWBAR_ATTACK3HIT,
CROWBAR_IDLE2,
CROWBAR_IDLE3
#endif
};
void CCrowbar::Spawn()
@ -67,8 +63,6 @@ void CCrowbar::Precache( void )
PRECACHE_SOUND( "weapons/cbar_hitbod2.wav" );
PRECACHE_SOUND( "weapons/cbar_hitbod3.wav" );
PRECACHE_SOUND( "weapons/cbar_miss1.wav" );
m_usCrowbar = PRECACHE_EVENT( 1, "events/crowbar.sc" );
}
int CCrowbar::GetItemInfo( ItemInfo *p )
@ -105,8 +99,7 @@ BOOL CCrowbar::Deploy()
void CCrowbar::Holster( int skiplocal /* = 0 */ )
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
SendWeaponAnim( CROWBAR_HOLSTER );
DefaultHolster( CROWBAR_HOLSTER, 0.7 );
}
void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, float *maxs, edict_t *pEntity )
@ -155,6 +148,12 @@ void FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mins, f
void CCrowbar::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( !Swing( 1 ) )
{
#ifndef CLIENT_DLL
@ -201,29 +200,33 @@ int CCrowbar::Swing( int fFirst )
}
}
#endif
if( fFirst )
{
PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usCrowbar,
0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, 0,
0, 0, 0 );
}
if( tr.flFraction >= 1.0 )
{
if( fFirst )
{
// miss
m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 );
#ifdef CROWBAR_IDLE_ANIM
switch( ( m_iSwing++ ) % 3 )
{
case 0:
SendWeaponAnim( CROWBAR_ATTACK1MISS );
break;
case 1:
SendWeaponAnim( CROWBAR_ATTACK2MISS );
break;
case 2:
SendWeaponAnim( CROWBAR_ATTACK3MISS );
break;
}
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;
EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, 94 + RANDOM_LONG( 0, 0xF ) );
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
#endif
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
}
}
else
{
switch( ( ( m_iSwing++ ) % 2 ) + 1 )
switch( ( m_iSwing++ ) % 3 )
{
case 0:
SendWeaponAnim( CROWBAR_ATTACK1HIT );
@ -330,17 +333,26 @@ int CCrowbar::Swing( int fFirst )
SetThink( &CCrowbar::Smack );
pev->nextthink = UTIL_WeaponTimeBase() + 0.2;
#endif
m_flNextPrimaryAttack = GetNextAttackDelay( 0.25 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25;
}
#ifdef CROWBAR_IDLE_ANIM
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
#endif
return fDidHit;
}
#ifdef CROWBAR_IDLE_ANIM
void CCrowbar::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
if( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() )
{
int iAnim;
@ -366,4 +378,3 @@ void CCrowbar::WeaponIdle( void )
SendWeaponAnim( iAnim );
}
}
#endif

View File

@ -1569,7 +1569,7 @@ void CTestEffect::Spawn( void )
void CTestEffect::Precache( void )
{
PRECACHE_MODEL( "sprites/lgtning.spr" );
// PRECACHE_MODEL( "sprites/lgtning.spr" );
}
void CTestEffect::TestThink( void )
@ -2233,3 +2233,109 @@ void CItemSoda::CanTouch( CBaseEntity *pOther )
SetThink( &CBaseEntity::SUB_Remove );
pev->nextthink = gpGlobals->time;
}
class CEnvPawnEffect : public CPointEntity
{
public:
int Save( CSave &save );
int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
void Spawn( void );
void Precache( void );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void KeyValue( KeyValueData *pkvd );
private:
int m_iLightRad;
//int m_iLightingModelIndex;
int m_iSpawnType;
int m_iBeamCount;
float m_flSpriteScale;
float m_flSpawnSoundRad;
float m_flSpawnVol;
};
LINK_ENTITY_TO_CLASS( env_spawnereffect, CEnvPawnEffect )
TYPEDESCRIPTION CEnvPawnEffect::m_SaveData[] =
{
DEFINE_FIELD( CEnvPawnEffect, m_iLightRad, FIELD_INTEGER ),
DEFINE_FIELD( CEnvPawnEffect, m_iSpawnType, FIELD_INTEGER ),
DEFINE_FIELD( CEnvPawnEffect, m_iBeamCount, FIELD_INTEGER ),
DEFINE_FIELD( CEnvPawnEffect, m_flSpriteScale, FIELD_FLOAT ),
DEFINE_FIELD( CEnvPawnEffect, m_flSpawnSoundRad, FIELD_FLOAT ),
DEFINE_FIELD( CEnvPawnEffect, m_flSpawnVol, FIELD_FLOAT ),
};
IMPLEMENT_SAVERESTORE( CEnvPawnEffect, CPointEntity )
void CEnvPawnEffect::Spawn()
{
Precache();
pev->solid = SOLID_NOT;
pev->movetype = MOVETYPE_NONE;
}
void CEnvPawnEffect::Precache()
{
PRECACHE_SOUND( "ambience/spawnsnd.wav" );
PRECACHE_MODEL( "sprites/xflare1.spr" );
PRECACHE_MODEL( "sprites/fexplo1.spr" );
}
void CEnvPawnEffect::KeyValue( KeyValueData *pkvd )
{
if( FStrEq( pkvd->szKeyName, "spawntype" ) )
{
m_iSpawnType = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if( FStrEq( pkvd->szKeyName, "beamcount" ) )
{
m_iBeamCount = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if( FStrEq( pkvd->szKeyName, "spritescale" ) )
{
m_flSpriteScale = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if( FStrEq( pkvd->szKeyName, "spawnsoundrad" ) )
{
switch( atoi( pkvd->szValue ) )
{
case 3:
m_flSpawnSoundRad = ATTN_NONE;
break;
case 2:
m_flSpawnSoundRad = ATTN_NORM;
break;
case 1:
m_flSpawnSoundRad = ATTN_IDLE;
break;
default:
m_flSpawnSoundRad = ATTN_STATIC;
break;
}
pkvd->fHandled = TRUE;
}
else if( FStrEq( pkvd->szKeyName, "spawnvol" ) )
{
m_flSpawnVol = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if( FStrEq( pkvd->szKeyName, "lightrad" ) )
{
m_iLightRad = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else
pkvd->fHandled = FALSE;
}
void CEnvPawnEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
UTIL_CreateWarpball( ENT( pev ), pev->origin, m_flSpawnVol, m_flSpawnSoundRad, m_iBeamCount, m_iSpawnType, m_flSpriteScale, m_iLightRad );
SetThink( &CBaseEntity::SUB_Remove );
pev->nextthink = gpGlobals->time;
}

View File

@ -51,6 +51,9 @@ enum egon_e {
LINK_ENTITY_TO_CLASS( weapon_egon, CEgon )
int CEgon::g_fireAnims1[] = { EGON_FIRE1, EGON_FIRE2, EGON_FIRE3, EGON_FIRE4 };
int CEgon::g_fireAnims2[] = { EGON_ALTFIRECYCLE };
void CEgon::Spawn()
{
Precache();
@ -79,15 +82,12 @@ void CEgon::Precache( void )
PRECACHE_MODEL( EGON_FLARE_SPRITE );
PRECACHE_SOUND( "weapons/357_cock1.wav" );
m_usEgonFire = PRECACHE_EVENT( 1, "events/egon_fire.sc" );
m_usEgonStop = PRECACHE_EVENT( 1, "events/egon_stop.sc" );
}
BOOL CEgon::Deploy( void )
{
m_deployed = FALSE;
m_fireState = FIRE_OFF;
// m_fireState = FIRE_OFF;
return DefaultDeploy( "models/v_egon.mdl", "models/p_egon.mdl", EGON_DRAW, "egon" );
}
@ -105,9 +105,7 @@ int CEgon::AddToPlayer( CBasePlayer *pPlayer )
void CEgon::Holster( int skiplocal /* = 0 */ )
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
SendWeaponAnim( EGON_HOLSTER );
DefaultHolster( EGON_HOLSTER, 0.7 );
EndAttack();
}
@ -162,7 +160,7 @@ void CEgon::Attack( void )
// don't fire underwater
if( m_pPlayer->pev->waterlevel == 3 )
{
if( m_fireState != FIRE_OFF || m_pBeam )
if( m_pBeam )
{
EndAttack();
}
@ -197,13 +195,21 @@ void CEgon::Attack( void )
m_flAmmoUseTime = gpGlobals->time;// start using ammo ASAP.
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 1, 0 );
SendWeaponAnim( g_fireAnims1[ RANDOM_LONG( 0, ARRAYSIZE( g_fireAnims1 ) - 1 ) ] );
m_shakeTime = 0;
m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1;
pev->fuser1 = UTIL_WeaponTimeBase() + 2;
m_shootTime = gpGlobals->time + 2;
if( m_fireMode == FIRE_WIDE )
{
EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, EGON_SOUND_STARTUP, 0.98, ATTN_NORM, 0, 125 );
}
else
{
EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, EGON_SOUND_STARTUP, 0.9, ATTN_NORM, 0, 100 );
}
pev->dmgtime = gpGlobals->time + GetPulseInterval();
m_fireState = FIRE_CHARGE;
@ -214,15 +220,23 @@ void CEgon::Attack( void )
Fire( vecSrc, vecAiming );
m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME;
if( pev->fuser1 <= UTIL_WeaponTimeBase() )
if( m_shootTime != 0 && gpGlobals->time > m_shootTime )
{
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 0, 0 );
pev->fuser1 = 1000;
if( m_fireMode == FIRE_WIDE )
{
EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 );
}
else
{
EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_STATIC, EGON_SOUND_RUN, 0.9, ATTN_NORM, 0, 100 );
}
m_shootTime = 0;
}
if( !HasAmmo() )
{
EndAttack();
m_fireState = FIRE_OFF;
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0;
}
break;
@ -232,6 +246,12 @@ void CEgon::Attack( void )
void CEgon::PrimaryAttack( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
m_fireMode = FIRE_WIDE;
Attack();
}
@ -407,8 +427,8 @@ void CEgon::CreateEffect( void )
m_pBeam->SetFlags( BEAM_FSINE );
m_pBeam->SetEndAttachment( 1 );
m_pBeam->pev->spawnflags |= SF_BEAM_TEMPORARY; // Flag these to be destroyed on save/restore or level transition
m_pBeam->pev->flags |= FL_SKIPLOCALHOST;
m_pBeam->pev->owner = m_pPlayer->edict();
// m_pBeam->pev->flags |= FL_SKIPLOCALHOST;
// m_pBeam->pev->owner = m_pPlayer->edict();
m_pNoise = CBeam::BeamCreate( EGON_BEAM_SPRITE, 55 );
m_pNoise->PointEntInit( pev->origin, m_pPlayer->entindex() );
@ -416,15 +436,15 @@ void CEgon::CreateEffect( void )
m_pNoise->SetBrightness( 100 );
m_pNoise->SetEndAttachment( 1 );
m_pNoise->pev->spawnflags |= SF_BEAM_TEMPORARY;
m_pNoise->pev->flags |= FL_SKIPLOCALHOST;
m_pNoise->pev->owner = m_pPlayer->edict();
// m_pNoise->pev->flags |= FL_SKIPLOCALHOST;
// m_pNoise->pev->owner = m_pPlayer->edict();
m_pSprite = CSprite::SpriteCreate( EGON_FLARE_SPRITE, pev->origin, FALSE );
m_pSprite->pev->scale = 1.0;
m_pSprite->SetTransparency( kRenderGlow, 255, 255, 255, 255, kRenderFxNoDissipation );
m_pSprite->pev->spawnflags |= SF_SPRITE_TEMPORARY;
m_pSprite->pev->flags |= FL_SKIPLOCALHOST;
m_pSprite->pev->owner = m_pPlayer->edict();
// m_pSprite->pev->flags |= FL_SKIPLOCALHOST;
// m_pSprite->pev->owner = m_pPlayer->edict();
if( m_fireMode == FIRE_WIDE )
{
@ -470,6 +490,16 @@ void CEgon::DestroyEffect( void )
void CEgon::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
ResetEmptySound();
if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
@ -499,16 +529,11 @@ void CEgon::WeaponIdle( void )
void CEgon::EndAttack( void )
{
bool bMakeNoise = false;
if( m_fireState != FIRE_OFF ) //Checking the button just in case!.
bMakeNoise = true;
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, m_pPlayer->edict(), m_usEgonStop, 0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, bMakeNoise, 0, 0, 0 );
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0;
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5;
STOP_SOUND( ENT( m_pPlayer->pev ), CHAN_STATIC, EGON_SOUND_RUN );
EMIT_SOUND_DYN( ENT( m_pPlayer->pev ), CHAN_WEAPON, EGON_SOUND_OFF, 0.98, ATTN_NORM, 0, 100 );
m_fireState = FIRE_OFF;
DestroyEffect();

View File

@ -138,21 +138,24 @@ BOOL CGauss::Deploy()
void CGauss::Holster( int skiplocal /* = 0 */ )
{
PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_GLOBAL, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 );
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
SendWeaponAnim( GAUSS_HOLSTER );
DefaultHolster( GAUSS_HOLSTER, 0.9 );
m_fInAttack = 0;
EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM );
}
void CGauss::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
// don't fire underwater
if( m_pPlayer->pev->waterlevel == 3 )
{
PlayEmptySound();
m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay( 0.15 );
m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
return;
}
@ -176,6 +179,12 @@ void CGauss::PrimaryAttack()
void CGauss::SecondaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
// don't fire underwater
if( m_pPlayer->pev->waterlevel == 3 )
{
@ -190,7 +199,7 @@ void CGauss::SecondaryAttack()
PlayEmptySound();
}
m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 );
m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;
return;
}
@ -217,7 +226,7 @@ void CGauss::SecondaryAttack()
m_pPlayer->m_flStartCharge = gpGlobals->time;
m_pPlayer->m_flAmmoStartCharge = UTIL_WeaponTimeBase() + GetFullChargeTime();
PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 110, 0, 0, 0 );
PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 110, 0, 0, 0 );
m_iSoundState = SND_CHANGE_PITCH;
}
@ -281,7 +290,7 @@ void CGauss::SecondaryAttack()
if( m_iSoundState == 0 )
ALERT( at_console, "sound state %d\n", m_iSoundState );
PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, pitch, 0, ( m_iSoundState == SND_CHANGE_PITCH ) ? 1 : 0, 0 );
PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, pitch, 0, ( m_iSoundState == SND_CHANGE_PITCH ) ? 1 : 0, 0 );
m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions
@ -389,13 +398,13 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage )
g_irunninggausspred = true;
#endif
// The main firing event is sent unreliably so it won't be delayed.
PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussFire, 0.0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, flDamage, 0.0, 0, 0, m_fPrimaryFire ? 1 : 0, 0 );
PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usGaussFire, 0.0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, flDamage, 0.0, 0, 0, m_fPrimaryFire ? 1 : 0, 0 );
// This reliable event is used to stop the spinning sound
// It's delayed by a fraction of second to make sure it is delayed by 1 frame on the client
// It's sent reliably anyway, which could lead to other delays
PLAYBACK_EVENT_FULL( FEV_NOTHOST | FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 );
PLAYBACK_EVENT_FULL( FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 );
/*ALERT( at_console, "%f %f %f\n%f %f %f\n",
vecSrc.x, vecSrc.y, vecSrc.z,
@ -545,6 +554,16 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage )
void CGauss::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
ResetEmptySound();
// play aftershock static discharge

View File

@ -20,10 +20,11 @@
#include "cbase.h"
#include "monsters.h"
#include "schedule.h"
#include "weapons.h"
// For holograms, make them not solid so the player can walk through them
#define SF_GENERICMONSTER_NOTSOLID 4
#define SF_GENERICMONSTER_DONTBLEED 8
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
@ -37,6 +38,8 @@ public:
int Classify( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
int ISoundMask( void );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
};
LINK_ENTITY_TO_CLASS( monster_generic, CGenericMonster )
@ -112,8 +115,16 @@ void CGenericMonster::Spawn()
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_RED;
pev->health = 8;
if( pev->spawnflags & SF_GENERICMONSTER_DONTBLEED )
{
m_bloodColor = DONT_BLEED;
pev->health = 100;
}
else
{
m_bloodColor = BLOOD_COLOR_RED;
pev->health = 8;
}
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE;
@ -134,6 +145,38 @@ void CGenericMonster::Precache()
PRECACHE_MODEL( STRING( pev->model ) );
}
void CGenericMonster::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType )
{
if( pev->spawnflags & SF_GENERICMONSTER_DONTBLEED )
{
UTIL_Ricochet( ptr->vecEndPos, 1.0f );
AddMultiDamage( pevAttacker, this, flDamage, bitsDamageType );
return;
}
CBaseMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType );
}
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
int CGenericMonster::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
if( pev->spawnflags & SF_GENERICMONSTER_DONTBLEED )
{
pev->health = pev->max_health / 2; // always trigger the 50% damage aitrigger
if( flDamage > 0 )
{
SetConditions( bits_COND_LIGHT_DAMAGE );
}
if( flDamage >= 20 )
{
SetConditions( bits_COND_HEAVY_DAMAGE );
}
return TRUE;
}
return CBaseMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
}

View File

@ -356,7 +356,7 @@ void CGrenade::Spawn( void )
m_fRegisteredSound = FALSE;
}
CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity )
CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float flDmg )
{
CGrenade *pGrenade = GetClassPtr( (CGrenade *)NULL );
pGrenade->Spawn();
@ -377,7 +377,7 @@ CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector v
// Explode on contact
pGrenade->SetTouch( &CGrenade::ExplodeTouch );
pGrenade->pev->dmg = gSkillData.plrDmgM203Grenade;
pGrenade->pev->dmg = flDmg;
return pGrenade;
}

View File

@ -37,10 +37,10 @@ enum glock_e
LINK_ENTITY_TO_CLASS( weapon_glock, CGlock )
LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock )
LINK_ENTITY_TO_CLASS( weapon_barney9mmnh, CGlock )
void CGlock::Spawn()
{
pev->classname = MAKE_STRING( "weapon_barney9mmhg" ); // hack to allow for old names
pev->classname = MAKE_STRING( "weapon_9mmhandgun" ); // hack to allow for old names
Precache();
m_iId = WEAPON_GLOCK;
SET_MODEL( ENT( pev ), "models/w_9mmhandgun.mdl" );
@ -52,7 +52,7 @@ void CGlock::Spawn()
void CGlock::Precache( void )
{
PRECACHE_MODEL( "models/v_barney9mmhg.mdl" );
PRECACHE_MODEL( "models/v_9mmhandgun.mdl" );
PRECACHE_MODEL( "models/w_9mmhandgun.mdl" );
PRECACHE_MODEL( "models/p_9mmhandgun.mdl" );
@ -101,7 +101,12 @@ int CGlock::AddToPlayer( CBasePlayer *pPlayer )
BOOL CGlock::Deploy()
{
// pev->body = 1;
return DefaultDeploy( "models/v_barney9mmhg.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 );
return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 );
}
void CGlock::Holster( int skiplocal /* = 0 */ )
{
DefaultHolster( GLOCK_HOLSTER, 1.2 );
}
void CGlock::SecondaryAttack( void )
@ -116,12 +121,18 @@ void CGlock::PrimaryAttack( void )
void CGlock::GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_iClip <= 0 )
{
if( m_fFireOnEmpty )
{
PlayEmptySound();
m_flNextPrimaryAttack = GetNextAttackDelay( 0.2 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2;
}
return;
@ -170,7 +181,7 @@ void CGlock::GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim )
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireGlock1 : m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 );
m_flNextPrimaryAttack = m_flNextSecondaryAttack = GetNextAttackDelay( flCycleTime );
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + flCycleTime;
if( !m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 )
// HEV suit - indicate out of ammo condition
@ -181,6 +192,12 @@ void CGlock::GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim )
void CGlock::Reload( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == GLOCK_MAX_CLIP )
return;
@ -199,6 +216,16 @@ void CGlock::Reload( void )
void CGlock::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
ResetEmptySound();
m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );

View File

@ -47,6 +47,7 @@ public:
int m_iJuice;
int m_iOn; // 0 = off, 1 = startup, 2 = going
float m_flSoundTime;
float m_flMessageTime;
};
TYPEDESCRIPTION CRecharge::m_SaveData[] =
@ -104,8 +105,14 @@ void CRecharge::Precache()
void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// Make sure that we have a caller
if( !pActivator )
return;
m_hActivator = pActivator;
// if it's not a player, ignore
if( !FClassnameIs( pActivator->pev, "player" ) )
if( !m_hActivator->IsPlayer() )
return;
// if there is no juice left, turn it off
@ -116,13 +123,19 @@ void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use
}
// if the player doesn't have the suit, or there is no juice left, make the deny noise
if( ( m_iJuice <= 0 ) || ( !( pActivator->pev->weapons & ( 1 << WEAPON_SUIT ) ) ) )
if( ( m_iJuice <= 0 ) || ( !( m_hActivator->pev->weapons & ( 1 << WEAPON_SUIT ) ) || !UTIL_HasSuit( m_hActivator ) ) )
{
if( m_flSoundTime <= gpGlobals->time )
{
m_flSoundTime = gpGlobals->time + 0.62;
EMIT_SOUND( ENT( pev ), CHAN_ITEM, "items/suitchargeno1.wav", 0.85, ATTN_NORM );
}
if( !UTIL_HasSuit( m_hActivator ) && m_flMessageTime < gpGlobals->time )
{
m_flMessageTime = gpGlobals->time + 4.0f;
UTIL_ShowMessageAll( "NOHEVRECHARGE" );
}
return;
}
@ -133,16 +146,6 @@ void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE use
if( m_flNextCharge >= gpGlobals->time )
return;
// Make sure that we have a caller
if( !pActivator )
return;
m_hActivator = pActivator;
//only recharge the player
if( !m_hActivator->IsPlayer() )
return;
// Play the on sound or the looping charging sound
if( !m_iOn )
{

View File

@ -36,7 +36,6 @@ enum handgrenade_e
};
LINK_ENTITY_TO_CLASS( weapon_handgrenade, CHandGrenade )
LINK_ENTITY_TO_CLASS( weapon_barneyhandgrenade, CHandGrenade ) // edit for Azure Sheep
void CHandGrenade::Spawn()
{
@ -54,8 +53,8 @@ void CHandGrenade::Spawn()
void CHandGrenade::Precache( void )
{
PRECACHE_MODEL( "models/v_grenade.mdl" );
PRECACHE_MODEL( "models/w_grenade.mdl" );
PRECACHE_MODEL( "models/v_barneygrenade.mdl" );
PRECACHE_MODEL( "models/p_grenade.mdl" );
}
@ -79,7 +78,7 @@ int CHandGrenade::GetItemInfo( ItemInfo *p )
BOOL CHandGrenade::Deploy()
{
m_flReleaseThrow = -1;
return DefaultDeploy( "models/v_barneygrenade.mdl", "models/p_grenade.mdl", HANDGRENADE_DRAW, "crowbar" );
return DefaultDeploy( "models/v_grenade.mdl", "models/p_grenade.mdl", HANDGRENADE_DRAW, "crowbar" );
}
BOOL CHandGrenade::CanHolster( void )
@ -90,11 +89,9 @@ BOOL CHandGrenade::CanHolster( void )
void CHandGrenade::Holster( int skiplocal /* = 0 */ )
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] )
{
SendWeaponAnim( HANDGRENADE_HOLSTER );
DefaultHolster( HANDGRENADE_HOLSTER, 0.7 );
}
else
{
@ -114,6 +111,12 @@ void CHandGrenade::Holster( int skiplocal /* = 0 */ )
void CHandGrenade::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( !m_flStartThrow && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0 )
{
m_flStartThrow = gpGlobals->time;
@ -126,6 +129,16 @@ void CHandGrenade::PrimaryAttack()
void CHandGrenade::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
if( m_flReleaseThrow == 0 && m_flStartThrow )
m_flReleaseThrow = gpGlobals->time;
@ -176,7 +189,7 @@ void CHandGrenade::WeaponIdle( void )
m_flReleaseThrow = 0;
m_flStartThrow = 0;
m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5;
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
@ -186,7 +199,7 @@ void CHandGrenade::WeaponIdle( void )
// just threw last grenade
// set attack times in the future, and weapon idle in the future so we can see the whole throw
// animation, weapon idle will automatically retire the weapon for us.
m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 );// ensure that the animation can finish playing
m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;// ensure that the animation can finish playing
}
return;
}

View File

@ -22,6 +22,7 @@
#include "monsters.h"
#include "schedule.h"
#include "game.h"
#include "headcrab.h"
//=========================================================
// Monster's Anim Events Go Here
@ -70,43 +71,6 @@ Schedule_t slHCRangeAttack1Fast[] =
},
};
class CHeadCrab : public CBaseMonster
{
public:
void Spawn( void );
void Precache( void );
void RunTask ( Task_t *pTask );
void StartTask ( Task_t *pTask );
void SetYawSpeed ( void );
void EXPORT LeapTouch ( CBaseEntity *pOther );
Vector Center( void );
Vector BodyTarget( const Vector &posSrc );
void PainSound( void );
void DeathSound( void );
void IdleSound( void );
void AlertSound( void );
void PrescheduleThink( void );
int Classify ( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
BOOL CheckRangeAttack1 ( float flDot, float flDist );
BOOL CheckRangeAttack2 ( float flDot, float flDist );
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
virtual float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite; }
virtual int GetVoicePitch( void ) { return 100; }
virtual float GetSoundVolue( void ) { return 1.0; }
Schedule_t* GetScheduleOfType ( int Type );
CUSTOM_SCHEDULES
static const char *pIdleSounds[];
static const char *pAlertSounds[];
static const char *pPainSounds[];
static const char *pAttackSounds[];
static const char *pDeathSounds[];
static const char *pBiteSounds[];
};
LINK_ENTITY_TO_CLASS( monster_headcrab, CHeadCrab )
DEFINE_CUSTOM_SCHEDULES( CHeadCrab )

50
dlls/headcrab.h Normal file
View File

@ -0,0 +1,50 @@
/***
*
* Copyright (c) 1996-2002, 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.
*
****/
class CHeadCrab : public CBaseMonster
{
public:
virtual void Spawn( void );
virtual void Precache( void );
void RunTask ( Task_t *pTask );
virtual void StartTask ( Task_t *pTask );
void SetYawSpeed ( void );
void EXPORT LeapTouch ( CBaseEntity *pOther );
Vector Center( void );
Vector BodyTarget( const Vector &posSrc );
virtual void PainSound( void );
virtual void DeathSound( void );
virtual void IdleSound( void );
virtual void AlertSound( void );
void PrescheduleThink( void );
virtual int Classify( void );
virtual void HandleAnimEvent( MonsterEvent_t *pEvent );
BOOL CheckRangeAttack1( float flDot, float flDist );
BOOL CheckRangeAttack2( float flDot, float flDist );
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
virtual float GetDamageAmount( void ) { return gSkillData.headcrabDmgBite; }
virtual int GetVoicePitch( void ) { return 100; }
virtual float GetSoundVolue( void ) { return 1.0; }
Schedule_t* GetScheduleOfType ( int Type );
CUSTOM_SCHEDULES
static const char *pIdleSounds[];
static const char *pAlertSounds[];
static const char *pPainSounds[];
static const char *pAttackSounds[];
static const char *pDeathSounds[];
static const char *pBiteSounds[];
};

View File

@ -60,10 +60,13 @@ void CHealthKit::Precache( void )
{
PRECACHE_MODEL( "models/w_medkit.mdl" );
PRECACHE_SOUND( "items/smallmedkit1.wav" );
PRECACHE_SOUND( "items/smallmedkit3.wav" );
}
BOOL CHealthKit::MyTouch( CBasePlayer *pPlayer )
{
const char *pszSound;
if( pPlayer->pev->deadflag != DEAD_NO )
{
return FALSE;
@ -75,7 +78,12 @@ BOOL CHealthKit::MyTouch( CBasePlayer *pPlayer )
WRITE_STRING( STRING( pev->classname ) );
MESSAGE_END();
EMIT_SOUND( ENT( pPlayer->pev ), CHAN_ITEM, "items/smallmedkit1.wav", 1, ATTN_NORM );
if( UTIL_HasSuit( pPlayer ) )
pszSound = "items/smallmedkit1.wav";
else
pszSound = "items/smallmedkit3.wav";
EMIT_SOUND( ENT( pPlayer->pev ), CHAN_ITEM, pszSound, 1, ATTN_NORM );
if( g_pGameRules->ItemShouldRespawn( this ) )
{
@ -168,10 +176,13 @@ void CWallHealth::Precache()
PRECACHE_SOUND( "items/medshot4.wav" );
PRECACHE_SOUND( "items/medshotno1.wav" );
PRECACHE_SOUND( "items/medcharge4.wav" );
PRECACHE_SOUND( "items/medcharge5.wav" );
}
void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
const char *pszSound;
// Make sure that we have a caller
if( !pActivator )
return;
@ -214,7 +225,11 @@ void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE u
if( ( m_iOn == 1 ) && ( m_flSoundTime <= gpGlobals->time ) )
{
m_iOn++;
EMIT_SOUND( ENT( pev ), CHAN_STATIC, "items/medcharge4.wav", 1.0, ATTN_NORM );
if( UTIL_HasSuit( pActivator ) )
pszSound = "items/medcharge4.wav";
else
pszSound = "items/medcharge5.wav";
EMIT_SOUND( ENT( pev ), CHAN_STATIC, pszSound, 1.0, ATTN_NORM );
}
// charge the player
@ -239,7 +254,10 @@ void CWallHealth::Off( void )
{
// Stop looping sound.
if( m_iOn > 1 )
{
STOP_SOUND( ENT( pev ), CHAN_STATIC, "items/medcharge4.wav" );
STOP_SOUND( ENT( pev ), CHAN_STATIC, "items/medcharge5.wav" );
}
m_iOn = 0;

View File

@ -40,6 +40,7 @@
#include "soundent.h"
#include "effects.h"
#include "customentity.h"
#include "hgrunt.h"
int g_fGruntQuestion; // true if an idle grunt asked a question. Cleared when someone answers.
@ -72,6 +73,9 @@ extern DLL_GLOBAL int g_iSkillLevel;
#define GUN_SHOTGUN 1
#define GUN_NONE 2
#define SF_BARNEY_HAVESUIT ( 1 << 3 )
#define SF_FRIENDLY_GRUNT ( 1 << 6 )
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
@ -119,73 +123,6 @@ enum
//=========================================================
#define bits_COND_GRUNT_NOFIRE ( bits_COND_SPECIAL1 )
class CHGrunt : public CSquadMonster
{
public:
void Spawn( void );
void Precache( void );
void SetYawSpeed( void );
int Classify( void );
int ISoundMask( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
BOOL FCanCheckAttacks( void );
BOOL CheckMeleeAttack1( float flDot, float flDist );
BOOL CheckRangeAttack1( float flDot, float flDist );
BOOL CheckRangeAttack2( float flDot, float flDist );
void CheckAmmo( void );
void SetActivity( Activity NewActivity );
void StartTask( Task_t *pTask );
void RunTask( Task_t *pTask );
void DeathSound( void );
void PainSound( void );
void IdleSound( void );
Vector GetGunPosition( void );
void Shoot( void );
void Shotgun( void );
void PrescheduleThink( void );
void GibMonster( void );
void SpeakSentence( void );
int Save( CSave &save );
int Restore( CRestore &restore );
CBaseEntity *Kick( void );
Schedule_t *GetSchedule( void );
Schedule_t *GetScheduleOfType( int Type );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
int IRelationship( CBaseEntity *pTarget );
BOOL FOkToSpeak( void );
void JustSpoke( void );
CUSTOM_SCHEDULES
static TYPEDESCRIPTION m_SaveData[];
// checking the feasibility of a grenade toss is kind of costly, so we do it every couple of seconds,
// not every server frame.
float m_flNextGrenadeCheck;
float m_flNextPainTime;
float m_flLastEnemySightTime;
Vector m_vecTossVelocity;
BOOL m_fThrowGrenade;
BOOL m_fStanding;
BOOL m_fFirstEncounter;// only put on the handsign show in the squad's first encounter.
int m_cClipSize;
int m_voicePitch;
int m_iBrassShell;
int m_iShotgunShell;
int m_iSentence;
static const char *pGruntSentences[];
};
LINK_ENTITY_TO_CLASS( monster_human_grunt, CHGrunt )
TYPEDESCRIPTION CHGrunt::m_SaveData[] =
@ -217,18 +154,6 @@ const char *CHGrunt::pGruntSentences[] =
"HG_TAUNT", // say rude things
};
typedef enum
{
HGRUNT_SENT_NONE = -1,
HGRUNT_SENT_GREN = 0,
HGRUNT_SENT_ALERT,
HGRUNT_SENT_MONSTER,
HGRUNT_SENT_COVER,
HGRUNT_SENT_THROW,
HGRUNT_SENT_CHARGE,
HGRUNT_SENT_TAUNT
} HGRUNT_SENTENCE_TYPES;
//=========================================================
// Speak Sentence - say your cued up sentence.
//
@ -266,10 +191,40 @@ int CHGrunt::IRelationship( CBaseEntity *pTarget )
{
return R_NM;
}
else if( FClassnameIs( pTarget->pev, "monster_human_spforce" ) )
{
return R_HT;
}
else if( FClassnameIs( pTarget->pev, "monster_adrian" ) )
{
return R_AL;
}
else if( FBitSet( pev->spawnflags, SF_FRIENDLY_GRUNT )
&& pTarget->IsPlayer()
&& IsNotProvoked() )
{
return R_AL;
}
return CSquadMonster::IRelationship( pTarget );
}
BOOL CHGrunt::IsNotProvoked()
{
CBaseEntity *pEntity = UTIL_FindEntityByTargetname( 0, "adrianmm" );
if( pEntity )
return !FBitSet( m_afMemory,bits_MEMORY_PROVOKED );
else
return FALSE;
}
void CHGrunt::Provoke()
{
CBaseEntity *pEntity = UTIL_FindEntityByTargetname( 0, "adrianmm" );
if( pEntity )
SetBits( m_afMemory,bits_MEMORY_PROVOKED );
}
//=========================================================
// GibMonster - make gun fly through the air.
//=========================================================
@ -284,16 +239,26 @@ void CHGrunt::GibMonster( void )
GetAttachment( 0, vecGunPos, vecGunAngles );
CBaseEntity *pGun;
const char *pszWeapon;
if( FBitSet( pev->weapons, HGRUNT_SHOTGUN ) )
{
pGun = DropItem( "weapon_shotgun", vecGunPos, vecGunAngles );
if( FBitSet( pev->spawnflags, SF_BARNEY_HAVESUIT ) )
pszWeapon = "weapon_shotgun";
else
pszWeapon = "weapon_barneyshotgun";
}
else if( FBitSet( pev->spawnflags, SF_BARNEY_HAVESUIT ) )
{
pszWeapon = "weapon_9mmAR";
}
else
{
pGun = DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles );
pszWeapon = "weapon_barney9mmar";
}
pGun = DropItem( pszWeapon, vecGunPos, vecGunAngles );
if( pGun )
{
pGun->pev->velocity = Vector( RANDOM_FLOAT( -100, 100 ), RANDOM_FLOAT( -100, 100 ), RANDOM_FLOAT( 200, 300 ) );
@ -627,6 +592,15 @@ void CHGrunt::TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir
//=========================================================
int CHGrunt::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
{
if( FBitSet( pev->spawnflags, SF_FRIENDLY_GRUNT )
&& pev->movetype != MOVETYPE_FLY
&& FBitSet( pevAttacker->flags, EF_DIMLIGHT )
&& m_hEnemy == 0 )
{
SENTENCEG_PlayRndSz( ENT( pev ), "HG_ALERT", HGRUNT_SENTENCE_VOLUME, GRUNT_ATTN, 0, m_voicePitch );
Provoke();
}
Forget( bits_MEMORY_INCOVER );
return CSquadMonster::TakeDamage( pevInflictor, pevAttacker, flDamage, bitsDamageType );
@ -851,6 +825,7 @@ void CHGrunt::HandleAnimEvent( MonsterEvent_t *pEvent )
{
Vector vecGunPos;
Vector vecGunAngles;
const char *pszWeapon;
GetAttachment( 0, vecGunPos, vecGunAngles );
@ -860,13 +835,22 @@ void CHGrunt::HandleAnimEvent( MonsterEvent_t *pEvent )
// now spawn a gun.
if( FBitSet( pev->weapons, HGRUNT_SHOTGUN ) )
{
DropItem( "weapon_shotgun", vecGunPos, vecGunAngles );
if( FBitSet( pev->spawnflags, SF_BARNEY_HAVESUIT ) )
pszWeapon = "weapon_shotgun";
else
pszWeapon = "weapon_barneyshotgun";
}
else if( FBitSet( pev->spawnflags, SF_BARNEY_HAVESUIT ) )
{
pszWeapon = "weapon_9mmAR";
}
else
{
DropItem( "weapon_9mmAR", vecGunPos, vecGunAngles );
pszWeapon = "weapon_barney9mmar";
}
DropItem( pszWeapon, vecGunPos, vecGunAngles );
if( FBitSet( pev->weapons, HGRUNT_GRENADELAUNCHER ) )
{
DropItem( "ammo_ARgrenades", BodyTarget( pev->origin ), vecGunAngles );
@ -892,7 +876,7 @@ void CHGrunt::HandleAnimEvent( MonsterEvent_t *pEvent )
case HGRUNT_AE_GREN_LAUNCH:
{
EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/glauncher.wav", 0.8, ATTN_NORM );
CGrenade::ShootContact( pev, GetGunPosition(), m_vecTossVelocity );
CGrenade::ShootContact( pev, GetGunPosition(), m_vecTossVelocity, gSkillData.plrDmgM203Grenade );
m_fThrowGrenade = FALSE;
if( g_iSkillLevel == SKILL_HARD )
m_flNextGrenadeCheck = gpGlobals->time + RANDOM_FLOAT( 2, 5 );// wait a random amount of time before shooting again
@ -943,6 +927,7 @@ void CHGrunt::HandleAnimEvent( MonsterEvent_t *pEvent )
if( pHurt )
{
// SOUND HERE!
EMIT_SOUND( ENT(pev), CHAN_WEAPON, "common/kick.wav", 1, ATTN_NORM );
UTIL_MakeVectors( pev->angles );
pHurt->pev->punchangle.x = 15;
pHurt->pev->velocity = pHurt->pev->velocity + gpGlobals->v_forward * 100 + gpGlobals->v_up * 50;
@ -1061,6 +1046,8 @@ void CHGrunt::Precache()
PRECACHE_SOUND( "zombie/claw_miss2.wav" );// because we use the basemonster SWIPE animation event
PRECACHE_SOUND( "common/kick.wav" );
// get voice pitch
if( RANDOM_LONG( 0, 1 ) )
m_voicePitch = 109 + RANDOM_LONG( 0, 7 );
@ -1801,7 +1788,6 @@ Schedule_t slGruntRepelLand[] =
},
};
DEFINE_CUSTOM_SCHEDULES( CHGrunt )
{
slGruntFail,

98
dlls/hgrunt.h Normal file
View File

@ -0,0 +1,98 @@
/***
*
* Copyright (c) 1996-2002, 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.
*
****/
//=========================================================
// hgrunt
//=========================================================
typedef enum
{
HGRUNT_SENT_NONE = -1,
HGRUNT_SENT_GREN = 0,
HGRUNT_SENT_ALERT,
HGRUNT_SENT_MONSTER,
HGRUNT_SENT_COVER,
HGRUNT_SENT_THROW,
HGRUNT_SENT_CHARGE,
HGRUNT_SENT_TAUNT
} HGRUNT_SENTENCE_TYPES;
class CHGrunt : public CSquadMonster
{
public:
virtual void Spawn( void );
virtual void Precache( void );
void SetYawSpeed( void );
int Classify( void );
int ISoundMask( void );
virtual void HandleAnimEvent( MonsterEvent_t *pEvent );
BOOL FCanCheckAttacks( void );
BOOL CheckMeleeAttack1( float flDot, float flDist );
BOOL CheckRangeAttack1( float flDot, float flDist );
BOOL CheckRangeAttack2( float flDot, float flDist );
void CheckAmmo( void );
void SetActivity( Activity NewActivity );
void StartTask( Task_t *pTask );
void RunTask( Task_t *pTask );
void DeathSound( void );
void PainSound( void );
virtual void IdleSound( void );
Vector GetGunPosition( void );
virtual void Shoot( void );
virtual void Shotgun( void );
void PrescheduleThink( void );
virtual void GibMonster( void );
virtual void SpeakSentence( void );
int Save( CSave &save );
int Restore( CRestore &restore );
CBaseEntity *Kick( void );
virtual Schedule_t *GetSchedule( void );
virtual Schedule_t *GetScheduleOfType( int Type );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);
virtual int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );
virtual int IRelationship( CBaseEntity *pTarget );
BOOL FOkToSpeak( void );
void JustSpoke( void );
BOOL IsNotProvoked();
void Provoke();
CUSTOM_SCHEDULES
static TYPEDESCRIPTION m_SaveData[];
// checking the feasibility of a grenade toss is kind of costly, so we do it every couple of seconds,
// not every server frame.
float m_flNextGrenadeCheck;
float m_flNextPainTime;
float m_flLastEnemySightTime;
Vector m_vecTossVelocity;
BOOL m_fThrowGrenade;
BOOL m_fStanding;
BOOL m_fFirstEncounter;// only put on the handsign show in the squad's first encounter.
int m_cClipSize;
int m_voicePitch;
int m_iBrassShell;
int m_iShotgunShell;
int m_iSentence;
static const char *pGruntSentences[];
};

View File

@ -99,6 +99,19 @@ void CHornet::Spawn( void )
if( !pSoundEnt )
pSoundEnt = edict();
switch( RANDOM_LONG( 0, 2 ) )
{
case 0:
EMIT_SOUND( pSoundEnt, CHAN_WEAPON, "agrunt/ag_fire1.wav", 1, ATTN_NORM );
break;
case 1:
EMIT_SOUND( pSoundEnt, CHAN_WEAPON, "agrunt/ag_fire2.wav", 1, ATTN_NORM );
break;
case 2:
EMIT_SOUND( pSoundEnt, CHAN_WEAPON, "agrunt/ag_fire3.wav", 1, ATTN_NORM );
break;
}
if( !FNullEnt( pev->owner ) && ( pev->owner->v.flags & FL_CLIENT ) )
{
pev->dmg = gSkillData.plrDmgHornet;

View File

@ -65,8 +65,6 @@ void CHgun::Precache( void )
PRECACHE_MODEL( "models/w_hgun.mdl" );
PRECACHE_MODEL( "models/p_hgun.mdl" );
m_usHornetFire = PRECACHE_EVENT( 1, "events/firehornet.sc" );
UTIL_PrecacheOther( "hornet" );
}
@ -113,8 +111,7 @@ BOOL CHgun::Deploy()
void CHgun::Holster( int skiplocal /* = 0 */ )
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
SendWeaponAnim( HGUN_DOWN );
DefaultHolster( HGUN_DOWN, 1.3 );
//!!!HACKHACK - can't select hornetgun if it's empty! no way to get ammo for it, either.
if( !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] )
@ -125,6 +122,11 @@ void CHgun::Holster( int skiplocal /* = 0 */ )
void CHgun::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
Reload();
if(m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
@ -144,13 +146,7 @@ void CHgun::PrimaryAttack()
m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;
int flags;
#if defined( CLIENT_WEAPONS )
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_TRACK, 0, 0, 0 );
SendWeaponAnim( HGUN_SHOOT );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
@ -167,6 +163,11 @@ void CHgun::PrimaryAttack()
void CHgun::SecondaryAttack( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
Reload();
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 )
@ -175,7 +176,6 @@ void CHgun::SecondaryAttack( void )
}
//Wouldn't be a bad idea to completely predict these, since they fly so fast...
#ifndef CLIENT_DLL
CBaseEntity *pHornet;
Vector vecSrc;
@ -223,29 +223,30 @@ void CHgun::SecondaryAttack( void )
pHornet->SetThink( &CHornet::StartDart );
m_flRechargeTime = gpGlobals->time + 0.5;
#endif
int flags;
#if defined( CLIENT_WEAPONS )
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_FAST, 0, 0, 0 );
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;
m_flRechargeTime = gpGlobals->time + 0.5;
SendWeaponAnim( HGUN_SHOOT );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.1;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
m_pPlayer->pev->punchangle.x = RANDOM_FLOAT( 0, 2 );
}
void CHgun::Reload( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] >= HORNET_MAX_CARRY )
return;
@ -258,6 +259,16 @@ void CHgun::Reload( void )
void CHgun::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
Reload();
if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )

View File

@ -29,97 +29,7 @@
#include "animation.h"
#include "effects.h"
#include "weapons.h"
#define SEARCH_RETRY 16
#define ICHTHYOSAUR_SPEED 150
extern CGraph WorldGraph;
#define EYE_MAD 0
#define EYE_BASE 1
#define EYE_CLOSED 2
#define EYE_BACK 3
#define EYE_LOOK 4
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
// UNDONE: Save/restore here
class CIchthyosaur : public CFlyingMonster
{
public:
void Spawn( void );
void Precache( void );
void SetYawSpeed( void );
int Classify( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
CUSTOM_SCHEDULES
int Save( CSave &save );
int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
Schedule_t *GetSchedule( void );
Schedule_t *GetScheduleOfType ( int Type );
void Killed( entvars_t *pevAttacker, int iGib );
void BecomeDead( void );
void EXPORT CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void EXPORT BiteTouch( CBaseEntity *pOther );
void StartTask( Task_t *pTask );
void RunTask( Task_t *pTask );
BOOL CheckMeleeAttack1( float flDot, float flDist );
BOOL CheckRangeAttack1( float flDot, float flDist );
float ChangeYaw( int speed );
Activity GetStoppedActivity( void );
void Move( float flInterval );
void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval );
void MonsterThink( void );
void Stop( void );
void Swim( void );
Vector DoProbe(const Vector &Probe );
float VectorToPitch( const Vector &vec );
float FlPitchDiff( void );
float ChangePitch( int speed );
Vector m_SaveVelocity;
float m_idealDist;
float m_flBlink;
float m_flEnemyTouched;
BOOL m_bOnAttack;
float m_flMaxSpeed;
float m_flMinSpeed;
float m_flMaxDist;
CBeam *m_pBeam;
float m_flNextAlert;
static const char *pIdleSounds[];
static const char *pAlertSounds[];
static const char *pAttackSounds[];
static const char *pBiteSounds[];
static const char *pDieSounds[];
static const char *pPainSounds[];
void IdleSound( void );
void AlertSound( void );
void AttackSound( void );
void BiteSound( void );
void DeathSound( void );
void PainSound( void );
};
#include "ichthyosaur.h"
LINK_ENTITY_TO_CLASS( monster_ichthyosaur, CIchthyosaur )

108
dlls/ichthyosaur.h Normal file
View File

@ -0,0 +1,108 @@
/***
*
* Copyright (c) 1996-2002, 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.
*
****/
//=========================================================
// icthyosaur - evin, satan fish monster
//=========================================================
#define SEARCH_RETRY 16
#define ICHTHYOSAUR_SPEED 150
extern CGraph WorldGraph;
#define EYE_MAD 0
#define EYE_BASE 1
#define EYE_CLOSED 2
#define EYE_BACK 3
#define EYE_LOOK 4
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
// UNDONE: Save/restore here
class CIchthyosaur : public CFlyingMonster
{
public:
virtual void Spawn( void );
virtual void Precache( void );
void SetYawSpeed( void );
int Classify( void );
virtual void HandleAnimEvent( MonsterEvent_t *pEvent );
CUSTOM_SCHEDULES
int Save( CSave &save );
int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
virtual Schedule_t *GetSchedule( void );
Schedule_t *GetScheduleOfType ( int Type );
void Killed( entvars_t *pevAttacker, int iGib );
void BecomeDead( void );
void EXPORT CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void EXPORT BiteTouch( CBaseEntity *pOther );
virtual void StartTask( Task_t *pTask );
void RunTask( Task_t *pTask );
BOOL CheckMeleeAttack1( float flDot, float flDist );
BOOL CheckRangeAttack1( float flDot, float flDist );
float ChangeYaw( int speed );
Activity GetStoppedActivity( void );
void Move( float flInterval );
void MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval );
virtual void MonsterThink( void );
virtual void Stop( void );
virtual void Swim( void );
Vector DoProbe(const Vector &Probe );
float VectorToPitch( const Vector &vec );
float FlPitchDiff( void );
float ChangePitch( int speed );
Vector m_SaveVelocity;
float m_idealDist;
float m_flBlink;
float m_flEnemyTouched;
BOOL m_bOnAttack;
float m_flMaxSpeed;
float m_flMinSpeed;
float m_flMaxDist;
CBeam *m_pBeam;
float m_flNextAlert;
static const char *pIdleSounds[];
static const char *pAlertSounds[];
static const char *pAttackSounds[];
static const char *pBiteSounds[];
static const char *pDieSounds[];
static const char *pPainSounds[];
virtual void IdleSound( void );
virtual void AlertSound( void );
virtual void AttackSound( void );
virtual void BiteSound( void );
virtual void DeathSound( void );
virtual void PainSound( void );
};

View File

@ -25,75 +25,7 @@
#include "effects.h"
#include "weapons.h"
#include "soundent.h"
extern DLL_GLOBAL int g_iSkillLevel;
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
#define ISLAVE_AE_CLAW ( 1 )
#define ISLAVE_AE_CLAWRAKE ( 2 )
#define ISLAVE_AE_ZAP_POWERUP ( 3 )
#define ISLAVE_AE_ZAP_SHOOT ( 4 )
#define ISLAVE_AE_ZAP_DONE ( 5 )
#define ISLAVE_MAX_BEAMS 8
class CISlave : public CSquadMonster
{
public:
void Spawn( void );
void Precache( void );
void UpdateOnRemove();
void SetYawSpeed( void );
int ISoundMask( void );
int Classify( void );
int IRelationship( CBaseEntity *pTarget );
void HandleAnimEvent( MonsterEvent_t *pEvent );
BOOL CheckRangeAttack1( float flDot, float flDist );
BOOL CheckRangeAttack2( float flDot, float flDist );
void CallForHelp( const char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
void DeathSound( void );
void PainSound( void );
void AlertSound( void );
void IdleSound( void );
void Killed( entvars_t *pevAttacker, int iGib );
void StartTask( Task_t *pTask );
Schedule_t *GetSchedule( void );
Schedule_t *GetScheduleOfType( int Type );
CUSTOM_SCHEDULES
int Save( CSave &save );
int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
void ClearBeams();
void ArmBeam( int side );
void WackBeam( int side, CBaseEntity *pEntity );
void ZapBeam( int side );
void BeamGlow( void );
int m_iBravery;
CBeam *m_pBeam[ISLAVE_MAX_BEAMS];
int m_iBeams;
float m_flNextAttack;
int m_voicePitch;
EHANDLE m_hDead;
static const char *pAttackHitSounds[];
static const char *pAttackMissSounds[];
static const char *pPainSounds[];
static const char *pDeathSounds[];
};
#include "islave.h"
LINK_ENTITY_TO_CLASS( monster_alien_slave, CISlave )
LINK_ENTITY_TO_CLASS( monster_exp_alien_slave, CISlave )//new Azure Sheep vortigaunt
@ -191,7 +123,7 @@ void CISlave::AlertSound( void )
{
SENTENCEG_PlayRndSz( ENT( pev ), "SLV_ALERT", 0.85, ATTN_NORM, 0, m_voicePitch );
CallForHelp( "monster_alien_slave", 512, m_hEnemy, m_vecEnemyLKP );
CallForHelp( STRING( pev->classname ), 512, m_hEnemy, m_vecEnemyLKP );
}
}
@ -353,16 +285,23 @@ void CISlave::HandleAnimEvent( MonsterEvent_t *pEvent )
if( m_iBeams == 0 )
{
int r, g, b;
Vector vecSrc = pev->origin + gpGlobals->v_forward * 2;
if( FClassnameIs( pev, "monster_exp_alien_slave" ) )
r = 255, g = 128, b = 255;
else
r = 255, g = 180, b = 96;
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc );
WRITE_BYTE( TE_DLIGHT );
WRITE_COORD( vecSrc.x ); // X
WRITE_COORD( vecSrc.y ); // Y
WRITE_COORD( vecSrc.z ); // Z
WRITE_BYTE( 12 ); // radius * 0.1
WRITE_BYTE( 255 ); // r
WRITE_BYTE( 180 ); // g
WRITE_BYTE( 96 ); // b
WRITE_BYTE( r ); // r
WRITE_BYTE( g ); // g
WRITE_BYTE( b ); // b
WRITE_BYTE( 20 / pev->framerate ); // time * 10
WRITE_BYTE( 0 ); // decay * 0.1
MESSAGE_END();
@ -395,7 +334,7 @@ void CISlave::HandleAnimEvent( MonsterEvent_t *pEvent )
if( !trace.fStartSolid )
{
CBaseEntity *pNew = Create( "monster_alien_slave", m_hDead->pev->origin, m_hDead->pev->angles );
CBaseEntity *pNew = Create( STRING( pev->classname ), m_hDead->pev->origin, m_hDead->pev->angles );
//CBaseMonster *pNewMonster = pNew->MyMonsterPointer();
pNew->pev->spawnflags |= 1;
WackBeam( -1, pNew );
@ -463,7 +402,7 @@ BOOL CISlave::CheckRangeAttack2( float flDot, float flDist )
m_iBravery = 0;
CBaseEntity *pEntity = NULL;
while( ( pEntity = UTIL_FindEntityByClassname( pEntity, "monster_alien_slave" ) ) != NULL )
while( ( pEntity = UTIL_FindEntityByClassname( pEntity, STRING( pev->classname ) ) ) != NULL )
{
TraceResult tr;
@ -510,15 +449,21 @@ void CISlave::Spawn()
Precache();
if( FClassnameIs( pev, "monster_exp_alien_slave" ) )
{
SET_MODEL( ENT( pev ), "models/sslave.mdl" );
m_bloodColor = BLOOD_COLOR_RED;
m_voicePitch = RANDOM_LONG( 110, 120 );
}
else
{
SET_MODEL( ENT( pev ), "models/islave.mdl" );
m_bloodColor = BLOOD_COLOR_GREEN;
m_voicePitch = RANDOM_LONG( 85, 110 );
}
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
pev->effects = 0;
pev->health = gSkillData.slaveHealth;
pev->view_ofs = Vector( 0, 0, 64 );// position of the eyes relative to monster's origin.
@ -526,8 +471,6 @@ void CISlave::Spawn()
m_MonsterState = MONSTERSTATE_NONE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_RANGE_ATTACK2 | bits_CAP_DOORS_GROUP;
m_voicePitch = RANDOM_LONG( 85, 110 );
MonsterInit();
}
@ -708,6 +651,7 @@ Schedule_t *CISlave::GetScheduleOfType( int Type )
void CISlave::ArmBeam( int side )
{
TraceResult tr;
int r, g, b;
float flDist = 1.0;
if( m_iBeams >= ISLAVE_MAX_BEAMS )
@ -741,7 +685,13 @@ void CISlave::ArmBeam( int side )
m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex() );
m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 );
// m_pBeam[m_iBeams]->SetColor( 180, 255, 96 );
m_pBeam[m_iBeams]->SetColor( 96, 128, 16 );
if( FClassnameIs( pev, "monster_exp_alien_slave" ) )
r = 255, g = 128, b = 255;
else
r = 96, g = 128, b = 16;
m_pBeam[m_iBeams]->SetColor( r, g, b );
m_pBeam[m_iBeams]->SetBrightness( 64 );
m_pBeam[m_iBeams]->SetNoise( 80 );
m_iBeams++;
@ -772,6 +722,7 @@ void CISlave::WackBeam( int side, CBaseEntity *pEntity )
{
//Vector vecDest;
//float flDist = 1.0;
int r, g, b;
if( m_iBeams >= ISLAVE_MAX_BEAMS )
return;
@ -785,7 +736,13 @@ void CISlave::WackBeam( int side, CBaseEntity *pEntity )
m_pBeam[m_iBeams]->PointEntInit( pEntity->Center(), entindex() );
m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 );
m_pBeam[m_iBeams]->SetColor( 180, 255, 96 );
if( FClassnameIs( pev, "monster_exp_alien_slave" ) )
r = 255, g = 128, b = 255;
else
r = 180, g = 255, b = 96;
m_pBeam[m_iBeams]->SetColor( r, g, b );
m_pBeam[m_iBeams]->SetBrightness( 255 );
m_pBeam[m_iBeams]->SetNoise( 80 );
m_iBeams++;
@ -797,6 +754,7 @@ void CISlave::WackBeam( int side, CBaseEntity *pEntity )
void CISlave::ZapBeam( int side )
{
Vector vecSrc, vecAim;
int r, g, b;
TraceResult tr;
CBaseEntity *pEntity;
@ -815,7 +773,13 @@ void CISlave::ZapBeam( int side )
m_pBeam[m_iBeams]->PointEntInit( tr.vecEndPos, entindex() );
m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 );
m_pBeam[m_iBeams]->SetColor( 180, 255, 96 );
if( FClassnameIs( pev, "monster_exp_alien_slave" ) )
r = 255, g = 128, b = 255;
else
r = 180, g = 255, b = 96;
m_pBeam[m_iBeams]->SetColor( r, g, b );
m_pBeam[m_iBeams]->SetBrightness( 255 );
m_pBeam[m_iBeams]->SetNoise( 20 );
m_iBeams++;

96
dlls/islave.h Normal file
View File

@ -0,0 +1,96 @@
/***
*
* Copyright (c) 1996-2002, 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.
*
****/
//=========================================================
// Alien slave monster
//=========================================================
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "monsters.h"
#include "squadmonster.h"
#include "schedule.h"
#include "effects.h"
#include "weapons.h"
#include "soundent.h"
//#include "islave.h"
extern DLL_GLOBAL int g_iSkillLevel;
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
#define ISLAVE_AE_CLAW ( 1 )
#define ISLAVE_AE_CLAWRAKE ( 2 )
#define ISLAVE_AE_ZAP_POWERUP ( 3 )
#define ISLAVE_AE_ZAP_SHOOT ( 4 )
#define ISLAVE_AE_ZAP_DONE ( 5 )
#define ISLAVE_MAX_BEAMS 8
class CISlave : public CSquadMonster
{
public:
void Spawn( void );
void Precache( void );
void UpdateOnRemove();
void SetYawSpeed( void );
int ISoundMask( void );
int Classify( void );
int IRelationship( CBaseEntity *pTarget );
void HandleAnimEvent( MonsterEvent_t *pEvent );
BOOL CheckRangeAttack1( float flDot, float flDist );
BOOL CheckRangeAttack2( float flDot, float flDist );
void CallForHelp( const char *szClassname, float flDist, EHANDLE hEnemy, Vector &vecLocation );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType );
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
void DeathSound( void );
void PainSound( void );
void AlertSound( void );
void IdleSound( void );
void Killed( entvars_t *pevAttacker, int iGib );
void StartTask( Task_t *pTask );
Schedule_t *GetSchedule( void );
Schedule_t *GetScheduleOfType( int Type );
CUSTOM_SCHEDULES
int Save( CSave &save );
int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
virtual void ClearBeams();
virtual void ArmBeam( int side );
virtual void WackBeam( int side, CBaseEntity *pEntity );
void ZapBeam( int side );
void BeamGlow( void );
int m_iBravery;
CBeam *m_pBeam[ISLAVE_MAX_BEAMS];
int m_iBeams;
float m_flNextAttack;
int m_voicePitch;
EHANDLE m_hDead;
static const char *pAttackHitSounds[];
static const char *pAttackMissSounds[];
static const char *pPainSounds[];
static const char *pDeathSounds[];
};

View File

@ -176,31 +176,63 @@ class CItemSuit : public CItem
void Spawn( void )
{
Precache();
SET_MODEL( ENT( pev ), "models/w_suit.mdl" );
SET_MODEL( ENT( pev ), "models/w_blue_suit.mdl" );
CItem::Spawn();
}
void Precache( void )
{
PRECACHE_MODEL( "models/w_suit.mdl" );
PRECACHE_MODEL( "models/w_blue_suit.mdl" );
}
BOOL MyTouch( CBasePlayer *pPlayer )
{
if( pPlayer->pev->weapons & ( 1<<WEAPON_SUIT ) )
return FALSE;
if( !FBitSet( pPlayer->pev->weapons, 1 << WEAPON_SUIT ) )
pPlayer->pev->weapons |= ( 1 << WEAPON_SUIT );
pPlayer->m_bHaveSuit = TRUE;
if( gEvilImpulse101 )
return TRUE;
if( pev->spawnflags & SF_SUIT_SHORTLOGON )
EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_A0" ); // short version of suit logon,
else
EMIT_SOUND_SUIT( pPlayer->edict(), "!HEV_AAx" ); // long version of suit logon
pPlayer->pev->weapons |= ( 1 << WEAPON_SUIT );
return TRUE;
}
};
LINK_ENTITY_TO_CLASS( item_suit, CItemSuit )
class CItemArmor : public CItem
{
void Spawn( void )
{
Precache();
SET_MODEL( ENT( pev ), "models/w_suit.mdl" );
CItem::Spawn();
}
void Precache( void )
{
PRECACHE_MODEL( "models/w_suit.mdl" );
PRECACHE_SOUND( "armor/pickup.wav" );
}
BOOL MyTouch( CBasePlayer *pPlayer )
{
if( pPlayer->pev->weapons & ( 1 << WEAPON_SUIT ) )
return FALSE;
EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "armor/pickup.wav", 1, ATTN_NORM );
pPlayer->pev->armorvalue += gSkillData.batteryCapacity;
pPlayer->pev->armorvalue = Q_min( pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY );
pPlayer->pev->weapons |= ( 1 << WEAPON_SUIT );
return TRUE;
}
};
//begin Alex
LINK_ENTITY_TO_CLASS( item_armor, CItemSuit ) // for Azure Sheep
LINK_ENTITY_TO_CLASS( item_armor, CItemArmor ) // for Azure Sheep
//end Alex
class CItemBattery : public CItem
@ -215,6 +247,7 @@ class CItemBattery : public CItem
{
PRECACHE_MODEL( "models/w_battery.mdl" );
PRECACHE_SOUND( "items/gunpickup2.wav" );
PRECACHE_SOUND( "barney/nope.wav" );
}
BOOL MyTouch( CBasePlayer *pPlayer )
{
@ -224,7 +257,7 @@ class CItemBattery : public CItem
}
if( ( pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY ) &&
( pPlayer->pev->weapons & ( 1 << WEAPON_SUIT ) ) )
( pPlayer->pev->weapons & ( 1 << WEAPON_SUIT ) ) && pPlayer->m_bHaveSuit )
{
int pct;
char szcharge[64];
@ -238,6 +271,9 @@ class CItemBattery : public CItem
WRITE_STRING( STRING( pev->classname ) );
MESSAGE_END();
if( gEvilImpulse101 )
return TRUE;
// Suit reports new power level
// For some reason this wasn't working in release build -- round it.
pct = (int)( (float)( pPlayer->pev->armorvalue * 100.0 ) * ( 1.0 / MAX_NORMAL_BATTERY ) + 0.5 );
@ -251,8 +287,15 @@ class CItemBattery : public CItem
pPlayer->SetSuitUpdate( szcharge, FALSE, SUIT_NEXT_IN_30SEC);
return TRUE;
}
else if( NextMessageTime < gpGlobals->time && !pPlayer->m_bHaveSuit )
{
EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "barney/nope.wav", 1, ATTN_NORM );
UTIL_ShowMessageAll( "NOHEVBATTERY" );
NextMessageTime < gpGlobals->time + 4.0;
}
return FALSE;
}
float NextMessageTime;
};
LINK_ENTITY_TO_CLASS( item_battery, CItemBattery )

View File

@ -27,6 +27,7 @@
#define SF_MONSTERMAKER_START_ON 1 // start active ( if has targetname )
#define SF_MONSTERMAKER_CYCLIC 4 // drop one monster every time fired.
#define SF_MONSTERMAKER_MONSTERCLIP 8 // Children are blocked by monsterclip
#define SF_MONSTERMAKER_WARPBALL 16 // Children are made by warpball
//=========================================================
// MonsterMaker - this ent creates monsters during the game.
@ -59,6 +60,12 @@ public:
BOOL m_fActive;
BOOL m_fFadeChildren;// should we make the children fadeout?
int m_iSpawnType;
int m_iBeamCount;
float m_flSpriteScale;
float m_flSpawnSoundRad;
float m_flSpawnVol;
};
LINK_ENTITY_TO_CLASS( monstermaker, CMonsterMaker )
@ -72,6 +79,11 @@ TYPEDESCRIPTION CMonsterMaker::m_SaveData[] =
DEFINE_FIELD( CMonsterMaker, m_iMaxLiveChildren, FIELD_INTEGER ),
DEFINE_FIELD( CMonsterMaker, m_fActive, FIELD_BOOLEAN ),
DEFINE_FIELD( CMonsterMaker, m_fFadeChildren, FIELD_BOOLEAN ),
DEFINE_FIELD( CMonsterMaker, m_iSpawnType, FIELD_INTEGER ),
DEFINE_FIELD( CMonsterMaker, m_iBeamCount, FIELD_INTEGER ),
DEFINE_FIELD( CMonsterMaker, m_flSpriteScale, FIELD_FLOAT ),
DEFINE_FIELD( CMonsterMaker, m_flSpawnSoundRad, FIELD_FLOAT ),
DEFINE_FIELD( CMonsterMaker, m_flSpawnVol, FIELD_FLOAT ),
};
IMPLEMENT_SAVERESTORE( CMonsterMaker, CBaseMonster )
@ -93,7 +105,45 @@ void CMonsterMaker::KeyValue( KeyValueData *pkvd )
m_iszMonsterClassname = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else
else if( FStrEq( pkvd->szKeyName, "spawntype" ) )
{
m_iSpawnType = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if( FStrEq( pkvd->szKeyName, "beamcount" ) )
{
m_iBeamCount = atoi( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if( FStrEq( pkvd->szKeyName, "spritescale" ) )
{
m_flSpriteScale = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if( FStrEq( pkvd->szKeyName, "spawnsoundrad" ) )
{
switch( atoi( pkvd->szValue ) )
{
case 3:
m_flSpawnSoundRad = ATTN_NONE;
break;
case 2:
m_flSpawnSoundRad = ATTN_NORM;
break;
case 1:
m_flSpawnSoundRad = ATTN_IDLE;
break;
default:
m_flSpawnSoundRad = ATTN_STATIC;
break;
}
pkvd->fHandled = TRUE;
}
else if( FStrEq( pkvd->szKeyName, "spawnvol" ) )
{
m_flSpawnVol = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
CBaseMonster::KeyValue( pkvd );
}
@ -149,6 +199,9 @@ void CMonsterMaker::Spawn()
void CMonsterMaker::Precache( void )
{
if( FBitSet( pev->spawnflags, SF_MONSTERMAKER_WARPBALL ) )
UTIL_PrecacheOther( "env_spawnereffect" );
CBaseMonster::Precache();
UTIL_PrecacheOther( STRING( m_iszMonsterClassname ) );
@ -208,6 +261,10 @@ void CMonsterMaker::MakeMonster( void )
pevCreate = VARS( pent );
pevCreate->origin = pev->origin;
pevCreate->angles = pev->angles;
if( FBitSet( pev->spawnflags, SF_MONSTERMAKER_WARPBALL ) )
pevCreate->origin.z -= 16;
SetBits( pevCreate->spawnflags, SF_MONSTER_FALL_TO_GROUND );
// Children hit monsterclip brushes
@ -223,6 +280,22 @@ void CMonsterMaker::MakeMonster( void )
pevCreate->targetname = pev->netname;
}
if( FBitSet( pev->spawnflags, SF_MONSTERMAKER_WARPBALL ) )
{
int iLightRad;
float height = ( pevCreate->absmax.z - pevCreate->absmin.z ) * 0.5f;
if( FClassnameIs( pevCreate, "monster_alien_slave" )
|| FClassnameIs( pevCreate, "monster_exp_alien_slave" ) )
iLightRad = 24;
else if( FClassnameIs( pevCreate, "monster_alien_grunt" ))
iLightRad = 32;
else
iLightRad = pevCreate->size.z / 3;
UTIL_CreateWarpball( ENT( pevCreate ), pevCreate->origin + Vector( 0, 0, height ), m_flSpawnVol, m_flSpawnSoundRad, m_iBeamCount, m_iSpawnType, m_flSpriteScale, iLightRad );
}
m_cLiveChildren++;// count this monster
m_cNumMonsters--;

View File

@ -111,7 +111,7 @@ void CFuncMortarField::Precache( void )
{
PRECACHE_SOUND( "weapons/mortar.wav" );
PRECACHE_SOUND( "weapons/mortarhit.wav" );
PRECACHE_MODEL( "sprites/lgtning.spr" );
//PRECACHE_MODEL( "sprites/lgtning.spr" );
}
// If connected to a table, then use the table controllers, else hit where the trigger is.

View File

@ -32,12 +32,12 @@ enum mp5_e
MP5_DEPLOY,
MP5_FIRE1,
MP5_FIRE2,
MP5_FIRE3
MP5_FIRE3,
MP5_HOLSTER
};
LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 )
LINK_ENTITY_TO_CLASS( weapon_9mmAR, CMP5 )
LINK_ENTITY_TO_CLASS( weapon_barney9mmar, CMP5 )
//=========================================================
//=========================================================
@ -48,7 +48,7 @@ int CMP5::SecondaryAmmoIndex( void )
void CMP5::Spawn()
{
pev->classname = MAKE_STRING( "weapon_barney9mmar" ); // hack to allow for old names
pev->classname = MAKE_STRING( "weapon_9mmAR" ); // hack to allow for old names
Precache();
SET_MODEL( ENT( pev ), "models/w_9mmAR.mdl" );
m_iId = WEAPON_MP5;
@ -60,7 +60,7 @@ void CMP5::Spawn()
void CMP5::Precache( void )
{
PRECACHE_MODEL( "models/v_barney9mmar.mdl" );
PRECACHE_MODEL( "models/v_9mmAR.mdl" );
PRECACHE_MODEL( "models/w_9mmAR.mdl" );
PRECACHE_MODEL( "models/p_9mmAR.mdl" );
@ -84,7 +84,7 @@ void CMP5::Precache( void )
PRECACHE_SOUND( "weapons/357_cock1.wav" );
m_usMP5 = PRECACHE_EVENT( 1, "events/mp5.sc" );
m_usMP52 = PRECACHE_EVENT( 1, "events/mp52.sc" );
// m_usMP52 = PRECACHE_EVENT( 1, "events/mp52.sc" );
}
int CMP5::GetItemInfo( ItemInfo *p )
@ -118,23 +118,34 @@ int CMP5::AddToPlayer( CBasePlayer *pPlayer )
BOOL CMP5::Deploy()
{
return DefaultDeploy( "models/v_barney9mmAR.mdl", "models/p_9mmAR.mdl", MP5_DEPLOY, "mp5" );
return DefaultDeploy( "models/v_9mmAR.mdl", "models/p_9mmAR.mdl", MP5_DEPLOY, "mp5" );
}
void CMP5::Holster( int skiplocal /* = 0 */ )
{
DefaultHolster( MP5_HOLSTER, 0.9 );
}
void CMP5::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
// don't fire underwater
if( m_pPlayer->pev->waterlevel == 3 )
{
PlayEmptySound();
m_flNextPrimaryAttack = 0.15;
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
return;
}
if( m_iClip <= 0 )
{
PlayEmptySound();
m_flNextPrimaryAttack = 0.15;
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
return;
}
@ -178,7 +189,7 @@ void CMP5::PrimaryAttack()
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 );
m_flNextPrimaryAttack = GetNextAttackDelay( 0.1 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1;
if( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() )
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1;
@ -188,11 +199,17 @@ void CMP5::PrimaryAttack()
void CMP5::SecondaryAttack( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
// don't fire underwater
if( m_pPlayer->pev->waterlevel == 3 )
{
PlayEmptySound( );
m_flNextPrimaryAttack = 0.15;
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
return;
}
@ -210,35 +227,40 @@ void CMP5::SecondaryAttack( void )
m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]--;
SendWeaponAnim( MP5_LAUNCH );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
// play this sound through BODY channel so we can hear it if player didn't stop firing MP3
EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, RANDOM_LONG( 0, 1 ) ? "weapons/glauncher.wav" : "weapons/glauncher2.wav", 0.8, ATTN_NORM );
UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle );
// we don't add in player velocity anymore.
CGrenade::ShootContact( m_pPlayer->pev,
m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16,
gpGlobals->v_forward * 800 );
gpGlobals->v_forward * 800, gSkillData.plrDmgM203Grenade );
int flags;
#if defined( CLIENT_WEAPONS )
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usMP52 );
m_flNextPrimaryAttack = GetNextAttackDelay( 1 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5;// idle pretty soon after shooting.
if( !m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] )
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 );
m_pPlayer->pev->punchangle.x -= 10;
}
void CMP5::Reload( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == MP5_MAX_CLIP )
return;
@ -247,6 +269,16 @@ void CMP5::Reload( void )
void CMP5::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
ResetEmptySound();
m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );

View File

@ -146,13 +146,13 @@ void CHalfLifeMultiplay::RefreshSkillData( void )
gSkillData.plrDmgCrowbar = 25;
// Poolstick
gSkillData.plrDmgPoolstick = 10;//Alex
gSkillData.plrDmgPoolstick = 12;//Alex
// Glock Round
gSkillData.plrDmg9MM = 12;
// Beretta Round
gSkillData.plrDmgBeretta = 10;
gSkillData.plrDmgBeretta = 14;
// 357 Round
gSkillData.plrDmg357 = 40;
@ -161,7 +161,7 @@ void CHalfLifeMultiplay::RefreshSkillData( void )
gSkillData.plrDmgMP5 = 12;
// M41A Round
gSkillData.plrDmgM41A = 8;
gSkillData.plrDmgM41A = 14;
// M41A M203 grenade
gSkillData.plrDmgM41AGrenade = 105;

View File

@ -331,7 +331,7 @@ void CNihilanth::Spawn( void )
void CNihilanth::Precache( void )
{
PRECACHE_MODEL( "models/nihilanth.mdl" );
PRECACHE_MODEL( "sprites/lgtning.spr" );
// PRECACHE_MODEL( "sprites/lgtning.spr" );
UTIL_PrecacheOther( "nihilanth_energy_ball" );
UTIL_PrecacheOther( "monster_alien_controller" );
UTIL_PrecacheOther( "monster_alien_slave" );

View File

@ -1053,17 +1053,18 @@ void CFuncTrackTrain::StopSound( void )
// if sound playing, stop it
if( m_soundPlaying && pev->noise )
{
unsigned short us_encode;
/* unsigned short us_encode;
unsigned short us_sound = ( (unsigned short)( m_sounds ) & 0x0007 ) << 12;
us_encode = us_sound;
PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0,
(float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 1, 0 );
/*
(float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 1, 0 );*/
STOP_SOUND( ENT( pev ), CHAN_STATIC, STRING( pev->noise ) );
*/
EMIT_SOUND_DYN( ENT( pev ), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100 );
if( m_sounds < 7 && !FBitSet( pev->spawnflags, SF_TRACKTRAIN_CAR ) )
EMIT_SOUND_DYN( ENT( pev ), CHAN_ITEM, "plats/ttrain_brake1.wav", m_flVolume, ATTN_NORM, 0, 100 );
}
m_soundPlaying = 0;
@ -1079,26 +1080,34 @@ void CFuncTrackTrain::UpdateSound( void )
if( !pev->noise )
return;
flpitch = TRAIN_STARTPITCH + ( fabs( pev->speed ) * ( TRAIN_MAXPITCH - TRAIN_STARTPITCH ) / TRAIN_MAXSPEED );
if( m_sounds > 7 && m_sounds <= 10 )
{
flpitch = PITCH_NORM;
}
else
{
flpitch = TRAIN_STARTPITCH + ( fabs( pev->speed ) * ( TRAIN_MAXPITCH - TRAIN_STARTPITCH ) / TRAIN_MAXSPEED );
}
if( !m_soundPlaying )
{
// play startup sound for train
EMIT_SOUND_DYN( ENT( pev ), CHAN_ITEM, "plats/ttrain_start1.wav", m_flVolume, ATTN_NORM, 0, 100 );
if( m_sounds < 7 && !FBitSet( pev->spawnflags, SF_TRACKTRAIN_CAR ) )
EMIT_SOUND_DYN( ENT( pev ), CHAN_ITEM, "plats/ttrain_start1.wav", m_flVolume, ATTN_NORM, 0, 100 );
EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noise ), m_flVolume, ATTN_NORM, 0, (int)flpitch );
m_soundPlaying = 1;
}
else
{
/*
// update pitch
EMIT_SOUND_DYN( ENT( pev ), CHAN_STATIC, STRING( pev->noise ), m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, (int)flpitch );
*/
// volume 0.0 - 1.0 - 6 bits
// m_sounds 3 bits
// flpitch = 6 bits
// 15 bits total
/*
unsigned short us_encode;
unsigned short us_sound = ( ( unsigned short )( m_sounds ) & 0x0007 ) << 12;
unsigned short us_pitch = ( ( unsigned short )( flpitch / 10.0 ) & 0x003f ) << 6;
@ -1107,7 +1116,7 @@ void CFuncTrackTrain::UpdateSound( void )
us_encode = us_sound | us_pitch | us_volume;
PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_UPDATE, edict(), m_usAdjustPitch, 0.0,
(float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 0, 0 );
(float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, us_encode, 0, 0, 0 );*/
}
}
@ -1500,6 +1509,18 @@ void CFuncTrackTrain::Precache( void )
case 6:
pszSound = "plats/ttrain7.wav";
break;
case 7:
pszSound = "plats/theli1.wav";
break;
case 8:
pszSound = "ambience/cardrive2.wav";
break;
case 9:
pszSound = "ambience/jeep_start.wav";
break;
case 10:
pszSound = "ambience/jeep_drive.wav";
break;
}
if( pszSound )

View File

@ -119,6 +119,8 @@ TYPEDESCRIPTION CBasePlayer::m_playerSaveData[] =
DEFINE_FIELD( CBasePlayer, m_iHideHUD, FIELD_INTEGER ),
DEFINE_FIELD( CBasePlayer, m_iFOV, FIELD_INTEGER ),
DEFINE_FIELD( CBasePlayer, m_bHaveSuit, FIELD_BOOLEAN ),
DEFINE_FIELD( CBasePlayer, m_bIsHolster, FIELD_BOOLEAN ),
//DEFINE_FIELD( CBasePlayer, m_fDeadTime, FIELD_FLOAT ), // only used in multiplayer games
//DEFINE_FIELD( CBasePlayer, m_fGameHUDInitialized, FIELD_INTEGER ), // only used in multiplayer games
//DEFINE_FIELD( CBasePlayer, m_flStopExtraSoundTime, FIELD_TIME ),
@ -356,7 +358,10 @@ void CBasePlayer::DeathSound( void )
}
// play one of the suit death alarms
EMIT_GROUPNAME_SUIT( ENT( pev ), "HEV_DEAD" );
if( m_bHaveSuit )
EMIT_GROUPNAME_SUIT( ENT( pev ), "HEV_DEAD" );
else
EMIT_GROUPNAME_SUIT( ENT( pev ), "HEV_NHEVDEAD" );
}
// override takehealth
@ -785,7 +790,8 @@ void CBasePlayer::RemoveAllItems( BOOL removeSuit )
if( m_pActiveItem )
{
ResetAutoaim();
m_pActiveItem->Holster();
Holster();
m_bIsHolster = FALSE;
m_pActiveItem = NULL;
}
@ -849,8 +855,7 @@ void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib )
CSound *pSound;
// Holster weapon immediately, to allow it to cleanup
if( m_pActiveItem )
m_pActiveItem->Holster();
Holster();
g_pGameRules->PlayerKilled( this, pevAttacker, g_pevLastInflictor );
@ -1087,25 +1092,6 @@ void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim )
ResetSequenceInfo();
}
/*
===========
TabulateAmmo
This function is used to find and store
all the ammo we have into the ammo vars.
============
*/
void CBasePlayer::TabulateAmmo()
{
ammo_9mm = AmmoInventory( GetAmmoIndex( "9mm" ) );
ammo_357 = AmmoInventory( GetAmmoIndex( "357" ) );
ammo_argrens = AmmoInventory( GetAmmoIndex( "ARgrenades" ) );
ammo_bolts = AmmoInventory( GetAmmoIndex( "bolts" ) );
ammo_buckshot = AmmoInventory( GetAmmoIndex( "buckshot" ) );
ammo_rockets = AmmoInventory( GetAmmoIndex( "rockets" ) );
ammo_uranium = AmmoInventory( GetAmmoIndex( "uranium" ) );
ammo_hornets = AmmoInventory( GetAmmoIndex( "Hornets" ) );
}
/*
===========
WaterMove
@ -1394,8 +1380,7 @@ void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle )
MESSAGE_END();
// Holster weapon immediately, to allow it to cleanup
if( m_pActiveItem )
m_pActiveItem->Holster();
Holster();
if( m_pTank != 0 )
m_pTank->Use( this, this, USE_OFF, 0 );
@ -2815,6 +2800,8 @@ void CBasePlayer::Spawn( void )
m_flgeigerDelay = gpGlobals->time + 2.0; // wait a few seconds until user-defined message registrations
// are recieved by all clients
m_bIsHolster = FALSE;
m_bHaveSuit = FALSE;
m_flTimeStepSound = 0;
m_iStepLeft = 0;
m_flFieldOfView = 0.5;// some monsters use this to determine whether or not the player is looking at them.
@ -2996,6 +2983,15 @@ int CBasePlayer::Restore( CRestore &restore )
return status;
}
void CBasePlayer::Holster()
{
if( m_pActiveItem )
{
m_pActiveItem->Holster();
m_bIsHolster = TRUE;
}
}
void CBasePlayer::SelectNextItem( int iItem )
{
CBasePlayerItem *pItem;
@ -3028,14 +3024,11 @@ void CBasePlayer::SelectNextItem( int iItem )
ResetAutoaim();
// FIX, this needs to queue them up and delay
if( m_pActiveItem )
{
m_pActiveItem->Holster();
}
Holster();
m_pActiveItem = pItem;
if( m_pActiveItem )
if( !m_bIsHolster )
{
m_pActiveItem->Deploy();
m_pActiveItem->UpdateItemInfo();
@ -3076,13 +3069,12 @@ void CBasePlayer::SelectItem( const char *pstr )
ResetAutoaim();
// FIX, this needs to queue them up and delay
if( m_pActiveItem )
m_pActiveItem->Holster();
Holster();
m_pLastItem = m_pActiveItem;
m_pActiveItem = pItem;
if( m_pActiveItem )
if( !m_bIsHolster )
{
m_pActiveItem->Deploy();
m_pActiveItem->UpdateItemInfo();
@ -3104,12 +3096,12 @@ void CBasePlayer::SelectLastItem( void )
ResetAutoaim();
// FIX, this needs to queue them up and delay
if( m_pActiveItem )
m_pActiveItem->Holster();
Holster();
CBasePlayerItem *pTemp = m_pActiveItem;
m_pActiveItem = m_pLastItem;
m_pLastItem = pTemp;
m_pActiveItem->Deploy();
m_pActiveItem->UpdateItemInfo();
}
@ -3443,20 +3435,47 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse )
Create( "monster_human_grunt", pev->origin + gpGlobals->v_forward * 128, pev->angles );
}
break;
case 77:
pEntity = UTIL_FindEntityByTargetname( 0, "katemm" );
if( pEntity )
{
FireTargets( STRING( pEntity->pev->message ), this, this, USE_TOGGLE, 0 );
ALERT( at_console, "impulse 77: Kate spawned!\n" );
}
else
ALERT( at_console, "impulse 77: Didn't find Kate spawner!\n" );
break;
case 78:
pEntity = UTIL_FindEntityByTargetname( 0, "katemmspw" );
if( pEntity )
UTIL_ShowKateHealth( pEntity->pev->health );
else
ALERT( at_console, "impulse 78: Didn't find Kate (katemm)!\n" );
break;
case 101:
ALERT( at_console, "Cheater...\n" );
gEvilImpulse101 = TRUE;
GiveNamedItem( "item_suit" );
GiveNamedItem( "item_battery" );
GiveNamedItem( "weapon_crowbar" );
GiveNamedItem( "weapon_barney9mmhg" ); // Alex for new 9mm handgun
GiveNamedItem( "weapon_9mmhandgun" );
GiveNamedItem( "weapon_beretta" );
GiveNamedItem( "ammo_9mmclip" );
GiveNamedItem( "weapon_barneyshotgun" ); // Alex for new shotgun
GiveNamedItem( "weapon_shotgun" );
GiveNamedItem( "ammo_buckshot" );
GiveNamedItem( "weapon_barney9mmar" ); // Alex for new 9mm ar
GiveNamedItem( "weapon_9mmAR" );
GiveNamedItem( "weapon_9mmm41a" );
GiveNamedItem( "ammo_9mmAR" );
GiveNamedItem( "ammo_ARgrenades" );
GiveNamedItem( "weapon_barneyhandgrenade" ); // Alex for new handgrenade
GiveNamedItem( "weapon_handgrenade" );
GiveNamedItem( "weapon_tripmine" );
GiveNamedItem( "weapon_barney9mmhg" );
GiveNamedItem( "weapon_barneyshotgun" );
GiveNamedItem( "weapon_barney9mmar" );
GiveNamedItem( "weapon_barneyhandgrenade" );
GiveNamedItem( "weapon_poolstick" );
GiveNamedItem( "weapon_toad" );
GiveNamedItem( "weapon_kmedkit" );
#ifndef OEM_BUILD
GiveNamedItem( "weapon_357" );
GiveNamedItem( "ammo_357" );
@ -3610,7 +3629,7 @@ int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem )
// ugly hack to update clip w/o an update clip message
pInsert->UpdateItemInfo();
if( m_pActiveItem )
if( !m_bIsHolster )
m_pActiveItem->UpdateItemInfo();
pItem->Kill();
@ -3660,6 +3679,7 @@ int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem, bool bCallHolster )
if( bCallHolster )
pItem->Holster();
m_pActiveItem = NULL;
m_bIsHolster = FALSE;
pev->viewmodel = 0;
pev->weaponmodel = 0;
}
@ -3729,8 +3749,6 @@ int CBasePlayer::GiveAmmo( int iCount, const char *szName, int iMax )
MESSAGE_END();
}
TabulateAmmo();
return i;
}
@ -4556,13 +4574,11 @@ BOOL CBasePlayer::SwitchWeapon( CBasePlayerItem *pWeapon )
ResetAutoaim();
if( m_pActiveItem )
{
m_pActiveItem->Holster();
}
Holster();
m_pActiveItem = pWeapon;
pWeapon->Deploy();
if( !m_bIsHolster )
pWeapon->Deploy();
return TRUE;
}

View File

@ -305,8 +305,6 @@ public:
void SetCustomDecalFrames( int nFrames );
int GetCustomDecalFrames( void );
void TabulateAmmo( void );
Vector m_vecLastViewAngles;
float m_flStartCharge;
@ -325,6 +323,9 @@ public:
float m_flNextChatTime;
void Holster();
BOOL m_bHaveSuit;
BOOL m_bIsHolster;
bool m_bSentBhopcap; // If false, the player just joined and needs a bhopcap message.
};

View File

@ -82,7 +82,7 @@ void CPlayerMonster :: HandleAnimEvent( MonsterEvent_t *pEvent )
//=========================================================
int CPlayerMonster::ISoundMask( void )
{
return NULL;
return 0;
}
//=========================================================

View File

@ -47,7 +47,7 @@ int CPython::GetItemInfo( ItemInfo *p )
p->iMaxClip = PYTHON_MAX_CLIP;
p->iFlags = 0;
p->iSlot = 1;
p->iPosition = 1;
p->iPosition = 3;
p->iId = m_iId = WEAPON_PYTHON;
p->iWeight = PYTHON_WEIGHT;
@ -116,20 +116,20 @@ BOOL CPython::Deploy()
void CPython::Holster( int skiplocal /* = 0 */ )
{
m_fInReload = FALSE;// cancel any reload in progress.
if( m_fInZoom )
{
SecondaryAttack();
}
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
SendWeaponAnim( PYTHON_HOLSTER );
DefaultHolster( PYTHON_HOLSTER, 1.0 );
}
void CPython::SecondaryAttack( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
#ifdef CLIENT_DLL
if( !bIsMultiplayer() )
#else
@ -155,11 +155,17 @@ void CPython::SecondaryAttack( void )
void CPython::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
// don't fire underwater
if( m_pPlayer->pev->waterlevel == 3 )
{
PlayEmptySound();
m_flNextPrimaryAttack = 0.15;
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
return;
}
@ -170,7 +176,7 @@ void CPython::PrimaryAttack()
else
{
PlayEmptySound();
m_flNextPrimaryAttack = 0.15;
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
}
return;
@ -206,12 +212,18 @@ void CPython::PrimaryAttack()
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate( "!HEV_AMO0", FALSE, 0 );
m_flNextPrimaryAttack = 0.75;
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
void CPython::Reload( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == PYTHON_MAX_CLIP )
return;
@ -229,12 +241,22 @@ void CPython::Reload( void )
#endif
if( DefaultReload( PYTHON_MAX_CLIP, PYTHON_RELOAD, 2.0, bUseScope ) )
{
m_flSoundDelay = 1.5;
m_flSoundDelay = UTIL_WeaponTimeBase() + 1.5;
}
}
void CPython::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
ResetEmptySound();
m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );

View File

@ -21,48 +21,77 @@
#include "cbase.h"
#include "monsters.h"
#include "schedule.h"
#include "headcrab.h"
#include "game.h"
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
#define RAT_AE_JUMPATTACK ( 2 )
class CRat : public CBaseMonster
class CRat : public CHeadCrab
{
public:
void Spawn( void );
void Precache( void );
void SetYawSpeed( void );
int Classify( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
void EXPORT RatLeapTouch( CBaseEntity *pOther );
void StartTask( Task_t *pTask );
void PainSound( void );
void DeathSound( void );
void IdleSound( void );
void AlertSound( void );
static const char *pIdleSounds[];
static const char *pAlertSounds[];
static const char *pPainSounds[];
static const char *pAttackSounds[];
static const char *pDeathSounds[];
static const char *pBiteSounds[];
};
LINK_ENTITY_TO_CLASS( monster_rat, CRat )
const char *CRat::pIdleSounds[] =
{
"rat/rat_idle.wav"
};
const char *CRat::pAlertSounds[] =
{
"rat/rat_alert.wav"
};
const char *CRat::pPainSounds[] =
{
"rat/rat_pain.wav"
};
const char *CRat::pAttackSounds[] =
{
"rat/rat_attack.wav"
};
const char *CRat::pDeathSounds[] =
{
"rat/rat_die.wav"
};
const char *CRat::pBiteSounds[] =
{
"rat/rat_headbite.wav"
};
//=========================================================
// Classify - indicates this monster's place in the
// relationship table.
//=========================================================
int CRat::Classify( void )
{
return CLASS_INSECT;
}
//=========================================================
// SetYawSpeed - allows each sequence to have a different
// turn rate associated with it.
//=========================================================
void CRat::SetYawSpeed( void )
{
int ys;
switch( m_Activity )
{
case ACT_IDLE:
default:
ys = 45;
break;
}
pev->yaw_speed = ys;
return CLASS_HUMAN_MILITARY;
}
//=========================================================
@ -73,7 +102,10 @@ void CRat::Spawn()
Precache();
SET_MODEL( ENT( pev ), "models/bigrat.mdl" );
UTIL_SetSize( pev, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ) );
if( !strncmp( STRING( gpGlobals->mapname ), "asmap", 5 ) )
UTIL_SetSize( pev, Vector( -12, -12, 0 ), Vector( 12, 12, 24 ) );
else
UTIL_SetSize( pev, g_vecZero, g_vecZero );
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
@ -91,9 +123,157 @@ void CRat::Spawn()
//=========================================================
void CRat::Precache()
{
PRECACHE_SOUND_ARRAY( pIdleSounds );
PRECACHE_SOUND_ARRAY( pAlertSounds );
PRECACHE_SOUND_ARRAY( pPainSounds );
PRECACHE_SOUND_ARRAY( pAttackSounds );
PRECACHE_SOUND_ARRAY( pDeathSounds );
PRECACHE_SOUND_ARRAY( pBiteSounds );
PRECACHE_MODEL( "models/bigrat.mdl" );
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//=========================================================
void CRat::HandleAnimEvent( MonsterEvent_t *pEvent )
{
switch( pEvent->event )
{
case RAT_AE_JUMPATTACK:
{
ClearBits( pev->flags, FL_ONGROUND );
UTIL_SetOrigin( pev, pev->origin + Vector( 0, 0, 1 ) );// take him off ground so engine doesn't instantly reset onground
UTIL_MakeVectors( pev->angles );
Vector vecJumpDir;
if( m_hEnemy != 0 )
{
float gravity = g_psv_gravity->value;
if( gravity <= 1 )
gravity = 1;
// How fast does the headcrab need to travel to reach that height given gravity?
float height = m_hEnemy->pev->origin.z + m_hEnemy->pev->view_ofs.z - pev->origin.z;
if( height < 16 )
height = 16;
float speed = sqrt( 2 * gravity * height );
float time = speed / gravity;
// Scale the sideways velocity to get there at the right time
vecJumpDir = m_hEnemy->pev->origin + m_hEnemy->pev->view_ofs - pev->origin;
vecJumpDir = vecJumpDir * ( 1.0 / time );
// Speed to offset gravity at the desired height
vecJumpDir.z = speed;
// Don't jump too far/fast
float distance = vecJumpDir.Length();
if( distance > 650 )
{
vecJumpDir = vecJumpDir * ( 650.0 / distance );
}
}
else
{
// jump hop, don't care where
vecJumpDir = Vector( gpGlobals->v_forward.x, gpGlobals->v_forward.y, gpGlobals->v_up.z ) * 350;
}
EMIT_SOUND_DYN( edict(), CHAN_VOICE, pAttackSounds[0], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
pev->velocity = vecJumpDir;
m_flNextAttack = gpGlobals->time + 2;
}
break;
default:
CBaseMonster::HandleAnimEvent( pEvent );
break;
}
}
//=========================================================
// LeapTouch - this is the rat's touch function when it
// is in the air
//=========================================================
void CRat::RatLeapTouch( CBaseEntity *pOther )
{
if( !pOther->pev->takedamage )
{
return;
}
if( pOther->Classify() == Classify() )
{
return;
}
// Don't hit if back on ground
if( !FBitSet( pev->flags, FL_ONGROUND ) )
{
EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY( pBiteSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
pOther->TakeDamage( pev, pev, GetDamageAmount(), DMG_SLASH );
}
SetTouch( NULL );
}
void CRat::StartTask( Task_t *pTask )
{
m_iTaskStatus = TASKSTATUS_RUNNING;
switch( pTask->iTask )
{
case TASK_RANGE_ATTACK1:
{
EMIT_SOUND_DYN( edict(), CHAN_WEAPON, pAttackSounds[0], GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
m_IdealActivity = ACT_RANGE_ATTACK1;
SetTouch( &CRat::RatLeapTouch );
break;
}
default:
{
CBaseMonster::StartTask( pTask );
}
}
}
//=========================================================
// IdleSound
//=========================================================
void CRat::IdleSound( void )
{
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pIdleSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
}
//=========================================================
// AlertSound
//=========================================================
void CRat::AlertSound( void )
{
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pAlertSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
}
//=========================================================
// AlertSound
//=========================================================
void CRat::PainSound( void )
{
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pPainSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
}
//=========================================================
// DeathSound
//=========================================================
void CRat::DeathSound( void )
{
EMIT_SOUND_DYN( edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY( pDeathSounds ), GetSoundVolue(), ATTN_IDLE, 0, GetVoicePitch() );
}
//=========================================================
// AI Schedules Specific to this monster
//=========================================================

View File

@ -281,6 +281,12 @@ void CRpgRocket::FollowThink( void )
void CRpg::Reload( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
int iResult = 0;
// don't bother with any of this if don't need to reload.
@ -297,7 +303,7 @@ void CRpg::Reload( void )
// Set the next attack time into the future so that WeaponIdle will get called more often
// than reload, allowing the RPG LTD to be updated
m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;
if( m_cActiveRockets && m_fSpotActive )
{
@ -360,7 +366,7 @@ void CRpg::Precache( void )
PRECACHE_SOUND( "weapons/rocketfire1.wav" );
PRECACHE_SOUND( "weapons/glauncher.wav" ); // alternative fire sound
m_usRpg = PRECACHE_EVENT( 1, "events/rpg.sc" );
//m_usRpg = PRECACHE_EVENT( 1, "events/rpg.sc" );
}
int CRpg::GetItemInfo( ItemInfo *p )
@ -415,12 +421,10 @@ BOOL CRpg::CanHolster( void )
void CRpg::Holster( int skiplocal /* = 0 */ )
{
m_fInReload = FALSE;// cancel any reload in progress.
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
SendWeaponAnim( RPG_HOLSTER1 );
if( m_iClip )
DefaultHolster( RPG_HOLSTER1, 0.8 );
else
DefaultHolster( RPG_HOLSTER2, 0.8 );
#ifndef CLIENT_DLL
if( m_pSpot )
{
@ -432,12 +436,20 @@ void CRpg::Holster( int skiplocal /* = 0 */ )
void CRpg::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_iClip )
{
m_pPlayer->m_iWeaponVolume = LOUD_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH;
#ifndef CLIENT_DLL
SendWeaponAnim( RPG_FIRE2 );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
@ -459,12 +471,14 @@ void CRpg::PrimaryAttack()
#else
flags = 0;
#endif
PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usRpg );
EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "weapons/rocketfire1.wav", 0.9, ATTN_NORM );
EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/glauncher.wav", 0.7, ATTN_NORM );
m_iClip--;
m_flNextPrimaryAttack = GetNextAttackDelay( 1.5 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5;
m_pPlayer->pev->punchangle.x -= 5;
ResetEmptySound();
}
@ -478,6 +492,12 @@ void CRpg::PrimaryAttack()
void CRpg::SecondaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
m_fSpotActive = !m_fSpotActive;
#ifndef CLIENT_DLL
@ -492,6 +512,16 @@ void CRpg::SecondaryAttack()
void CRpg::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
UpdateSpot();
if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )

View File

@ -258,7 +258,7 @@ int CSatchel::GetItemInfo( ItemInfo *p )
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 4;
p->iPosition = 1;
p->iPosition = 2;
p->iFlags = ITEM_FLAG_SELECTONEMPTY | ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE;
p->iId = m_iId = WEAPON_SATCHEL;
p->iWeight = SATCHEL_WEIGHT;
@ -305,15 +305,13 @@ BOOL CSatchel::Deploy()
void CSatchel::Holster( int skiplocal /* = 0 */ )
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
if( m_chargeReady )
{
SendWeaponAnim( SATCHEL_RADIO_HOLSTER );
DefaultHolster( SATCHEL_RADIO_HOLSTER, 0.7 );
}
else
{
SendWeaponAnim( SATCHEL_DROP );
DefaultHolster( SATCHEL_DROP, 0.7 );
}
EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM );
@ -326,6 +324,12 @@ void CSatchel::Holster( int skiplocal /* = 0 */ )
void CSatchel::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
switch( m_chargeReady )
{
case SATCHEL_IDLE:
@ -353,7 +357,7 @@ void CSatchel::PrimaryAttack()
}
m_chargeReady = SATCHEL_RELOAD;
m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5;
break;
@ -366,6 +370,12 @@ void CSatchel::PrimaryAttack()
void CSatchel::SecondaryAttack( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_chargeReady != SATCHEL_RELOAD )
{
Throw();
@ -400,13 +410,23 @@ void CSatchel::Throw( void )
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
m_flNextPrimaryAttack = GetNextAttackDelay( 1.0 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5;
}
}
void CSatchel::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
return;
@ -441,7 +461,7 @@ void CSatchel::WeaponIdle( void )
// use tripmine animations
strcpy( m_pPlayer->m_szAnimExtention, "trip" );
m_flNextPrimaryAttack = GetNextAttackDelay( 0.5 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5;
m_chargeReady = SATCHEL_IDLE;
break;

View File

@ -442,13 +442,19 @@ Activity CScientist::GetStoppedActivity( void )
void CScientist::StartTask( Task_t *pTask )
{
const char *pszSentence;
switch( pTask->iTask )
{
case TASK_SAY_HEAL:
//if( FOkToSpeak() )
Talk( 2 );
m_hTalkTarget = m_hTargetEnt;
PlaySentence( "SC_HEAL", 2, VOL_NORM, ATTN_IDLE );
if( FClassnameIs( pev, "monster_worker" ) )
pszSentence = "WK_HEAL";
else
pszSentence = "SC_HEAL";
PlaySentence( pszSentence, 2, VOL_NORM, ATTN_IDLE );
TaskComplete();
break;
case TASK_SCREAM:
@ -469,9 +475,18 @@ void CScientist::StartTask( Task_t *pTask )
//The enemy can be null here. - Solokiller
//Discovered while testing the barnacle grapple on headcrabs with scientists in view.
if( m_hEnemy != 0 && m_hEnemy->IsPlayer() )
PlaySentence( "SC_PLFEAR", 5, VOL_NORM, ATTN_NORM );
{
if( FClassnameIs( pev, "monster_worker" ) )
pszSentence = "WK_PLFEAR";
else
pszSentence = "SC_PLFEAR";
}
else if( FClassnameIs( pev, "monster_worker" ) )
pszSentence = "WK_FEAR";
else
PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM );
pszSentence = "SC_FEAR";
PlaySentence( pszSentence, 5, VOL_NORM, ATTN_NORM );
}
TaskComplete();
break;
@ -639,10 +654,7 @@ void CScientist::HandleAnimEvent( MonsterEvent_t *pEvent )
void CScientist::Spawn( void )
{
Precache();
if( FClassnameIs( pev, "monster_worker" ) )
SET_MODEL( ENT( pev ), "models/gus.mdl" );
else
SET_MODEL( ENT( pev ), "models/scientist.mdl" );
SET_MODEL( ENT( pev ), STRING( pev->model ) );
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
@ -661,15 +673,18 @@ void CScientist::Spawn( void )
// White hands
pev->skin = 0;
if( pev->body == -1 )
if( !FClassnameIs( pev, "monster_worker" ) )
{
// -1 chooses a random head
pev->body = RANDOM_LONG( 0, NUM_SCIENTIST_HEADS - 1 );// pick a head, any head
}
if( pev->body == -1 )
{
// -1 chooses a random head
pev->body = RANDOM_LONG( 0, NUM_SCIENTIST_HEADS - 1 );// pick a head, any head
}
// Luther is black, make his hands black
if( pev->body == HEAD_LUTHER )
pev->skin = 1;
// Luther is black, make his hands black
if( pev->body == HEAD_LUTHER )
pev->skin = 1;
}
MonsterInit();
SetUse( &CTalkMonster::FollowerUse );
@ -681,10 +696,10 @@ void CScientist::Spawn( void )
void CScientist::Precache( void )
{
if( FClassnameIs( pev, "monster_worker" ) )
PRECACHE_MODEL( "models/gus.mdl" );
pev->model = MAKE_STRING( "models/gus.mdl" );
else
PRECACHE_MODEL( "models/scientist.mdl" );
pev->model = MAKE_STRING( "models/scientist.mdl" );
PRECACHE_MODEL( STRING( pev->model ) );
PRECACHE_SOUND( "scientist/sci_pain1.wav" );
PRECACHE_SOUND( "scientist/sci_pain2.wav" );
PRECACHE_SOUND( "scientist/sci_pain3.wav" );
@ -711,45 +726,73 @@ void CScientist::TalkInit()
// scientists speach group names (group names are in sentences.txt)
m_szGrp[TLK_ANSWER] = "SC_ANSWER";
m_szGrp[TLK_QUESTION] = "SC_QUESTION";
m_szGrp[TLK_IDLE] = "SC_IDLE";
m_szGrp[TLK_STARE] = "SC_STARE";
m_szGrp[TLK_USE] = "SC_OK";
m_szGrp[TLK_UNUSE] = "SC_WAIT";
m_szGrp[TLK_STOP] = "SC_STOP";
m_szGrp[TLK_NOSHOOT] = "SC_SCARED";
m_szGrp[TLK_HELLO] = "SC_HELLO";
if( FClassnameIs( pev, "monster_worker" ) )
{
m_szGrp[TLK_ANSWER] = "WK_ANSWER";
m_szGrp[TLK_QUESTION] = "WK_QUESTION";
m_szGrp[TLK_IDLE] = "WK_IDLE";
m_szGrp[TLK_STARE] = "WK_STARE";
m_szGrp[TLK_USE] = "WK_OK";
m_szGrp[TLK_UNUSE] = "WK_WAIT";
m_szGrp[TLK_STOP] = "WK_STOP";
m_szGrp[TLK_NOSHOOT] = "WK_SCARED";
m_szGrp[TLK_HELLO] = "WK_HELLO";
m_szGrp[TLK_PLHURT1] = "!SC_CUREA";
m_szGrp[TLK_PLHURT2] = "!SC_CUREB";
m_szGrp[TLK_PLHURT3] = "!SC_CUREC";
m_szGrp[TLK_PLHURT1] = "!WK_CUREA";
m_szGrp[TLK_PLHURT2] = "!WK_CUREB";
m_szGrp[TLK_PLHURT3] = "!WK_CUREC";
m_szGrp[TLK_SMELL] = "WK_SMELL";
m_szGrp[TLK_WOUND] = "WK_WOUND";
m_szGrp[TLK_MORTAL] = "WK_MORTAL";
m_voicePitch = 90;
}
else
{
m_szGrp[TLK_ANSWER] = "SC_ANSWER";
m_szGrp[TLK_QUESTION] = "SC_QUESTION";
m_szGrp[TLK_IDLE] = "SC_IDLE";
m_szGrp[TLK_STARE] = "SC_STARE";
m_szGrp[TLK_USE] = "SC_OK";
m_szGrp[TLK_UNUSE] = "SC_WAIT";
m_szGrp[TLK_STOP] = "SC_STOP";
m_szGrp[TLK_NOSHOOT] = "SC_SCARED";
m_szGrp[TLK_HELLO] = "SC_HELLO";
m_szGrp[TLK_PLHURT1] = "!SC_CUREA";
m_szGrp[TLK_PLHURT2] = "!SC_CUREB";
m_szGrp[TLK_PLHURT3] = "!SC_CUREC";
m_szGrp[TLK_SMELL] = "SC_SMELL";
m_szGrp[TLK_WOUND] = "SC_WOUND";
m_szGrp[TLK_MORTAL] = "SC_MORTAL";
// get voice for head
switch( pev->body % 3 )
{
default:
case HEAD_GLASSES:
m_voicePitch = 105;
break; //glasses
case HEAD_EINSTEIN:
m_voicePitch = 100;
break; //einstein
case HEAD_LUTHER:
m_voicePitch = 95;
break; //luther
case HEAD_SLICK:
m_voicePitch = 100;
break; //slick
}
}
m_szGrp[TLK_PHELLO] = "SC_PHELLO";
m_szGrp[TLK_PIDLE] = "SC_PIDLE";
m_szGrp[TLK_PQUESTION] = "SC_PQUEST";
m_szGrp[TLK_SMELL] = "SC_SMELL";
m_szGrp[TLK_WOUND] = "SC_WOUND";
m_szGrp[TLK_MORTAL] = "SC_MORTAL";
// get voice for head
switch( pev->body % 3 )
{
default:
case HEAD_GLASSES:
m_voicePitch = 105;
break; //glasses
case HEAD_EINSTEIN:
m_voicePitch = 100;
break; //einstein
case HEAD_LUTHER:
m_voicePitch = 95;
break; //luther
case HEAD_SLICK:
m_voicePitch = 100;
break; //slick
}
}
int CScientist::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
@ -1139,15 +1182,13 @@ LINK_ENTITY_TO_CLASS( monster_scientist_dead, CDeadScientist )
void CDeadScientist::Spawn()
{
if( FClassnameIs( pev, "monster_worker" ) )
{
PRECACHE_MODEL( "models/gus.mdl" );
SET_MODEL( ENT( pev ), "models/gus.mdl" );
}
pev->model = MAKE_STRING( "models/construction.mdl" );
else
{
PRECACHE_MODEL( "models/scientist.mdl" );
SET_MODEL( ENT( pev ), "models/scientist.mdl" );
}
pev->model = MAKE_STRING( "models/scientist.mdl" );
PRECACHE_MODEL( STRING( pev->model ) );
SET_MODEL( ENT( pev ), STRING( pev->model ) );
pev->effects = 0;
pev->sequence = 0;
@ -1156,17 +1197,20 @@ void CDeadScientist::Spawn()
m_bloodColor = BLOOD_COLOR_RED;
if( pev->body == -1 )
{
// -1 chooses a random head
pev->body = RANDOM_LONG( 0, NUM_SCIENTIST_HEADS - 1 );// pick a head, any head
}
pev->skin = 0;
// Luther is black, make his hands black
if( pev->body == HEAD_LUTHER )
pev->skin = 1;
else
pev->skin = 0;
if( !FClassnameIs( pev, "monster_worker" ) )
{
if( pev->body == -1 )
{
// -1 chooses a random head
pev->body = RANDOM_LONG( 0, NUM_SCIENTIST_HEADS - 1 );// pick a head, any head
}
// Luther is black, make his hands black
if( pev->body == HEAD_LUTHER )
pev->skin = 1;
}
pev->sequence = LookupSequence( m_szPoses[m_iPose] );
if( pev->sequence == -1 )

View File

@ -41,7 +41,6 @@ enum shotgun_e
};
LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun )
LINK_ENTITY_TO_CLASS( weapon_barneyshotgun, CShotgun )
void CShotgun::Spawn()
{
@ -56,7 +55,7 @@ void CShotgun::Spawn()
void CShotgun::Precache( void )
{
PRECACHE_MODEL( "models/v_barneyshotgun.mdl" );
PRECACHE_MODEL( "models/v_shotgun.mdl" );
PRECACHE_MODEL( "models/w_shotgun.mdl" );
PRECACHE_MODEL( "models/p_shotgun.mdl" );
@ -101,7 +100,7 @@ int CShotgun::GetItemInfo( ItemInfo *p )
p->iMaxAmmo2 = -1;
p->iMaxClip = SHOTGUN_MAX_CLIP;
p->iSlot = 2;
p->iPosition = 1;
p->iPosition = 2;
p->iFlags = 0;
p->iId = m_iId = WEAPON_SHOTGUN;
p->iWeight = SHOTGUN_WEIGHT;
@ -111,16 +110,27 @@ int CShotgun::GetItemInfo( ItemInfo *p )
BOOL CShotgun::Deploy()
{
return DefaultDeploy( "models/v_barneyshotgun.mdl", "models/p_shotgun.mdl", SHOTGUN_DRAW, "shotgun" );
return DefaultDeploy( "models/v_shotgun.mdl", "models/p_shotgun.mdl", SHOTGUN_DRAW, "shotgun" );
}
void CShotgun::Holster( int skiplocal /* = 0 */ )
{
DefaultHolster( SHOTGUN_HOLSTER, 0.4 );
}
void CShotgun::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
// don't fire underwater
if( m_pPlayer->pev->waterlevel == 3 )
{
PlayEmptySound();
m_flNextPrimaryAttack = GetNextAttackDelay( 0.15 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
return;
}
@ -176,7 +186,7 @@ void CShotgun::PrimaryAttack()
//if( m_iClip != 0 )
m_flPumpTime = gpGlobals->time + 0.5;
m_flNextPrimaryAttack = GetNextAttackDelay( 0.75 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75;
if( m_iClip != 0 )
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0;
@ -187,11 +197,17 @@ void CShotgun::PrimaryAttack()
void CShotgun::SecondaryAttack( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
// don't fire underwater
if( m_pPlayer->pev->waterlevel == 3 )
{
PlayEmptySound();
m_flNextPrimaryAttack = GetNextAttackDelay( 0.15 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15;
return;
}
@ -247,18 +263,24 @@ void CShotgun::SecondaryAttack( void )
//if( m_iClip != 0 )
m_flPumpTime = gpGlobals->time + 0.95;
m_flNextPrimaryAttack = GetNextAttackDelay( 1.5 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5;
if( m_iClip != 0 )
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 6.0;
else
m_flTimeWeaponIdle = 1.5;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5;
m_fInSpecialReload = 0;
}
void CShotgun::Reload( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 || m_iClip == SHOTGUN_MAX_CLIP )
return;
@ -273,7 +295,7 @@ void CShotgun::Reload( void )
m_fInSpecialReload = 1;
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.6;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.6;
m_flNextPrimaryAttack = GetNextAttackDelay( 1.0 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0;
m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0;
return;
}
@ -315,6 +337,16 @@ void CShotgun::WeaponTick()
void CShotgun::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
ResetEmptySound();
m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );

View File

@ -936,6 +936,8 @@ void CEnvSound::Think( void )
{
if( flRange < pPlayer->m_flSndRange || pPlayer->m_flSndRange == 0 )
{
ALERT( at_console, "env_sound: set to %d - %s \n", (int)m_flRoomtype, UTIL_GetSoundRoomTypeName( m_flRoomtype ) );
// new entity is closer to player, so it wins.
pPlayer->m_pentSndLast = ENT( pev );
pPlayer->m_flSndRoomtype = m_flRoomtype;
@ -979,81 +981,6 @@ void CEnvSound::Spawn()
// spread think times
pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.0, 0.5 );
}
//=====================
//LRC - trigger_sound
//=====================
class CTriggerSound : public CBaseDelay
{
public:
void KeyValue( KeyValueData* pkvd );
void Spawn( void );
void Touch( CBaseEntity *pOther );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
virtual int ObjectCaps( void ) { return CBaseDelay :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
float m_flRoomtype;
string_t m_iszMaster;
};
LINK_ENTITY_TO_CLASS( trigger_sound, CTriggerSound );
TYPEDESCRIPTION CTriggerSound::m_SaveData[] =
{
DEFINE_FIELD( CTriggerSound, m_flRoomtype, FIELD_FLOAT ),
DEFINE_FIELD( CTriggerSound, m_iszMaster, FIELD_FLOAT ),
};
IMPLEMENT_SAVERESTORE( CTriggerSound, CBaseDelay );
void CTriggerSound::KeyValue( KeyValueData *pkvd )
{
if( FStrEq( pkvd->szKeyName, "roomtype" ) )
{
m_flRoomtype = atof( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else if ( FStrEq(pkvd->szKeyName, "master" ) )
{
m_iszMaster = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else
CBaseEntity::KeyValue( pkvd );
}
void CTriggerSound::Touch( CBaseEntity *pOther )
{
if( !UTIL_IsMasterTriggered( m_iszMaster, pOther ) ) return;
if( pOther->IsPlayer() )
{
CBasePlayer *pPlayer = (CBasePlayer*)pOther;
if( pPlayer->m_pentSndLast != this->edict() )
{
pPlayer->m_pentSndLast = ENT( pev );
pPlayer->m_flSndRoomtype = m_flRoomtype;
pPlayer->m_flSndRange = 0;
MESSAGE_BEGIN( MSG_ONE, SVC_ROOMTYPE, NULL, pPlayer->edict() ); // use the magic #1 for "one client"
WRITE_SHORT( (short)m_flRoomtype ); // sequence number
MESSAGE_END();
SUB_UseTargets( pPlayer, USE_TOGGLE, 0 );
}
}
}
void CTriggerSound::Spawn()
{
pev->solid = SOLID_TRIGGER;
pev->movetype = MOVETYPE_NONE;
SET_MODEL( ENT( pev ), STRING( pev->model ) ); // set size and link into world
SetBits( pev->effects, EF_NODRAW );
}
// ==================== SENTENCE GROUPS, UTILITY FUNCTIONS ======================================
#define CSENTENCE_LRU_MAX 32 // max number of elements per sentence group
@ -1067,7 +994,7 @@ typedef struct sentenceg
unsigned char rgblru[CSENTENCE_LRU_MAX];
} SENTENCEG;
#define CSENTENCEG_MAX 500 // max number of sentence groups
#define CSENTENCEG_MAX 210 // max number of sentence groups
// globals
SENTENCEG rgsentenceg[CSENTENCEG_MAX];
@ -1481,6 +1408,9 @@ void EMIT_SOUND_DYN( edict_t *entity, int channel, const char *sample, float vol
void EMIT_SOUND_SUIT( edict_t *entity, const char *sample )
{
if( !UTIL_HasSuit( CBaseEntity::Instance( entity ) ) )
return;
float fvol;
int pitch = PITCH_NORM;
@ -1809,7 +1739,7 @@ float TEXTURETYPE_PlaySound( TraceResult *ptr, Vector vecSrc, Vector vecEnd, in
cnt = 3;
break;
case CHAR_TEX_FLESH:
if( iBulletType == BULLET_PLAYER_CROWBAR )
if( iBulletType == BULLET_PLAYER_CROWBAR || iBulletType == BULLET_PLAYER_POOLSTICK )
return 0.0; // crowbar already makes this sound
fvol = 1.0;
fvolbar = 0.2;

View File

@ -433,7 +433,7 @@ void CSqueak::Precache( void )
PRECACHE_SOUND( "squeek/sqk_hunt3.wav" );
UTIL_PrecacheOther( "monster_snark" );
m_usSnarkFire = PRECACHE_EVENT( 1, "events/snarkfire.sc" );
// m_usSnarkFire = PRECACHE_EVENT( 1, "events/snarkfire.sc" );
}
int CSqueak::GetItemInfo( ItemInfo *p )
@ -445,7 +445,7 @@ int CSqueak::GetItemInfo( ItemInfo *p )
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 4;
p->iPosition = 3;
p->iPosition = 4;
p->iId = m_iId = WEAPON_SNARK;
p->iWeight = SNARK_WEIGHT;
p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE;
@ -470,8 +470,6 @@ BOOL CSqueak::Deploy()
void CSqueak::Holster( int skiplocal /* = 0 */ )
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
if( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] )
{
m_pPlayer->pev->weapons &= ~( 1 << WEAPON_SNARK );
@ -479,12 +477,18 @@ void CSqueak::Holster( int skiplocal /* = 0 */ )
return;
}
SendWeaponAnim( SQUEAK_DOWN );
DefaultHolster( SQUEAK_DOWN, 1.5 );
EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM );
}
void CSqueak::PrimaryAttack()
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] )
{
UTIL_MakeVectors( m_pPlayer->pev->v_angle );
@ -502,16 +506,10 @@ void CSqueak::PrimaryAttack()
// find place to toss monster
UTIL_TraceLine( trace_origin + gpGlobals->v_forward * 20, trace_origin + gpGlobals->v_forward * 64, dont_ignore_monsters, NULL, &tr );
int flags;
#ifdef CLIENT_WEAPONS
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSnarkFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 );
if( tr.fAllSolid == 0 && tr.fStartSolid == 0 && tr.flFraction > 0.25 )
{
SendWeaponAnim( SQUEAK_THROW );
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
#ifndef CLIENT_DLL
@ -532,7 +530,7 @@ void CSqueak::PrimaryAttack()
m_fJustThrown = 1;
m_flNextPrimaryAttack = GetNextAttackDelay( 0.3 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0;
}
}
@ -540,11 +538,25 @@ void CSqueak::PrimaryAttack()
void CSqueak::SecondaryAttack( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
}
void CSqueak::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
return;

View File

@ -59,7 +59,10 @@ const char *CTalkMonster::m_szFriends[TLK_CFRIENDS] =
"monster_barniel",
"monster_hevbarn",
"monster_kate",
"monster_worker"
"monster_worker",
"monster_myself",
"monster_gordon",
"monster_adrian"
};
//=========================================================

View File

@ -38,7 +38,7 @@
#define bit_saidHeard (1<<6)
#define bit_saidSmelled (1<<7)
#define TLK_CFRIENDS 7
#define TLK_CFRIENDS 10
typedef enum
{

View File

@ -21,6 +21,7 @@
#define SF_TRACKTRAIN_NOCONTROL 0x0002
#define SF_TRACKTRAIN_FORWARDONLY 0x0004
#define SF_TRACKTRAIN_PASSABLE 0x0008
#define SF_TRACKTRAIN_CAR 0x0010
// Spawnflag for CPathTrack
#define SF_PATH_DISABLED 0x00000001

View File

@ -27,6 +27,7 @@
#include "saverestore.h"
#include "trains.h" // trigger_camera has train functionality
#include "gamerules.h"
#include "skill.h"
#define SF_TRIGGER_PUSH_START_OFF 2//spawnflag that makes trigger_push spawn turned OFF
#define SF_TRIGGER_HURT_TARGETONCE 1// Only fire hurt target once
@ -1095,8 +1096,15 @@ void CBaseTrigger::MultiTouch( CBaseEntity *pOther )
pevToucher = pOther->pev;
if( FBitSet( pev->spawnflags, SF_TRIGGER_KATEONLY ) )
{
if( FClassnameIs( pevToucher, "monster_kate" ) )
{
ActivateMultiTrigger( pOther );
}
}
// Only touch clients, monsters, or pushables (depending on flags)
if( ( ( pevToucher->flags & FL_CLIENT ) && !( pev->spawnflags & SF_TRIGGER_NOCLIENTS ) ) ||
else if( ( ( pevToucher->flags & FL_CLIENT ) && !( pev->spawnflags & SF_TRIGGER_NOCLIENTS ) ) ||
( ( pevToucher->flags & FL_MONSTER ) && (pev->spawnflags & SF_TRIGGER_ALLOWMONSTERS ) ) ||
( ( pev->spawnflags & SF_TRIGGER_PUSHABLES ) && FClassnameIs( pevToucher,"func_pushable" ) ) )
{
@ -2381,3 +2389,169 @@ void CTriggerCamera::Move()
float fraction = 2 * gpGlobals->frametime;
pev->velocity = ( ( pev->movedir * pev->speed ) * fraction ) + ( pev->velocity * ( 1 - fraction ) );
}
class CTriggerDie : public CBaseTrigger
{
public:
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
int Save( CSave &save );
int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
private:
string_t m_szMonsterName;
};
LINK_ENTITY_TO_CLASS( trigger_die, CTriggerDie )
TYPEDESCRIPTION CTriggerDie::m_SaveData[] =
{
DEFINE_FIELD( CTriggerDie, m_szMonsterName, FIELD_STRING ),
};
IMPLEMENT_SAVERESTORE( CTriggerDie, CBaseTrigger )
void CTriggerDie::KeyValue( KeyValueData *pkvd )
{
if( FStrEq( pkvd->szKeyName, "monstername" ) )
{
m_szMonsterName = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else
CBaseTrigger::KeyValue( pkvd );
}
void CTriggerDie::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
CBaseEntity *pEntity = UTIL_FindEntityByTargetname( 0, STRING( m_szMonsterName ) );
if( pEntity )
{
float flDmg = pEntity->pev->health + 1.0f;
pEntity->TakeDamage( pev, pev, flDmg, 0 );
}
else
{
ALERT( at_console, "trigger_die: didn't find monster!\n" );
}
}
class CTriggerLoadHazard : public CBaseTrigger
{
public:
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
};
LINK_ENTITY_TO_CLASS( trigger_loadhazard, CTriggerLoadHazard )
void CTriggerLoadHazard::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if( pActivator && pActivator->IsPlayer() )
{
ALERT( at_console, "trigger_loadhazard: loading t0a0 - Hazard Course\n" );
CHANGE_LEVEL( "t0a0", 0 );
}
else
{
ALERT( at_console, "trigger_loadhazard: not player activate\n" );
}
}
class CTriggerKateHealth : public CBaseTrigger
{
public:
void KeyValue( KeyValueData *pkvd );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
int Save( CSave &save );
int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
private:
string_t m_szKateName;
};
LINK_ENTITY_TO_CLASS( trigger_katehealth, CTriggerKateHealth )
TYPEDESCRIPTION CTriggerKateHealth::m_SaveData[] =
{
DEFINE_FIELD( CTriggerKateHealth, m_szKateName, FIELD_STRING ),
};
IMPLEMENT_SAVERESTORE( CTriggerKateHealth, CBaseTrigger )
void CTriggerKateHealth::KeyValue( KeyValueData *pkvd )
{
if( FStrEq( pkvd->szKeyName, "katename" ) )
{
m_szKateName = ALLOC_STRING( pkvd->szValue );
pkvd->fHandled = TRUE;
}
else
CBaseTrigger::KeyValue( pkvd );
}
void CTriggerKateHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
CBaseEntity *pEntity = UTIL_FindEntityByTargetname( 0, STRING( m_szKateName ) );
if( pEntity )
{
ALERT( at_console, "trigger_katehealth: Kate health before: %f\n", pEntity->pev->health );
pEntity->pev->health = gSkillData.kateHealth;
ALERT( at_console, "trigger_katehealth: Kate health after: %f\n", pEntity->pev->health );
}
else
{
ALERT( at_console, "trigger_katehealth: didn't find kate!\n" );
}
}
class CTriggerSound : public CBaseTrigger
{
public:
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void Touch( CBaseEntity *pOther );
void ChangeSoundRoom( float roomtype, float range );
};
LINK_ENTITY_TO_CLASS( trigger_sound, CTriggerSound )
void CTriggerSound::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
ChangeSoundRoom( pev->health, 64.0f );
}
void CTriggerSound::Touch( CBaseEntity *pOther )
{
if( pOther->IsPlayer() )
ChangeSoundRoom( pev->health, 64.0f );
}
void CTriggerSound::ChangeSoundRoom( float roomtype, float range )
{
CBasePlayer *pPlayer = (CBasePlayer *)UTIL_FindEntityByClassname( 0, "player" );
if( pPlayer->m_flSndRoomtype != roomtype )
{
if( pPlayer->pev->waterlevel == 3 )
{
ALERT( at_console, "trigger_sound: underwater not setting to %d - %s\n", (int)roomtype, UTIL_GetSoundRoomTypeName( roomtype ) );
pPlayer->m_flSndRoomtype = 0;
}
else
{
pPlayer->m_pentSndLast = ENT( pev );
pPlayer->m_flSndRoomtype = roomtype;
pPlayer->m_flSndRange = range;
ALERT( at_console, "trigger_sound: set to %d - %s \n", (int)roomtype, UTIL_GetSoundRoomTypeName( roomtype ) );
MESSAGE_BEGIN( MSG_ONE, SVC_ROOMTYPE, 0, pPlayer->edict() ); // use the magic #1 for "one client"
WRITE_SHORT( (short)roomtype ); // sequence number
MESSAGE_END();
}
}
}

View File

@ -384,7 +384,7 @@ void CTripmine::Precache( void )
PRECACHE_MODEL( "models/p_tripmine.mdl" );
UTIL_PrecacheOther( "monster_tripmine" );
m_usTripFire = PRECACHE_EVENT( 1, "events/tripfire.sc" );
//m_usTripFire = PRECACHE_EVENT( 1, "events/tripfire.sc" );
}
int CTripmine::GetItemInfo( ItemInfo *p )
@ -396,7 +396,7 @@ int CTripmine::GetItemInfo( ItemInfo *p )
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 4;
p->iPosition = 2;
p->iPosition = 3;
p->iId = m_iId = WEAPON_TRIPMINE;
p->iWeight = TRIPMINE_WEIGHT;
p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE;
@ -421,12 +421,18 @@ void CTripmine::Holster( int skiplocal /* = 0 */ )
DestroyItem();
}
SendWeaponAnim( TRIPMINE_HOLSTER );
DefaultHolster( TRIPMINE_HOLSTER, 0.7 );
EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM );
}
void CTripmine::PrimaryAttack( void )
{
if( m_pPlayer->m_bIsHolster )
{
WeaponIdle();
return;
}
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 )
return;
@ -438,14 +444,6 @@ void CTripmine::PrimaryAttack( void )
UTIL_TraceLine( vecSrc, vecSrc + vecAiming * 128, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr );
int flags;
#ifdef CLIENT_WEAPONS
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usTripFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 );
if( tr.flFraction < 1.0 )
{
CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit );
@ -477,12 +475,22 @@ void CTripmine::PrimaryAttack( void )
}*/
m_flNextPrimaryAttack = GetNextAttackDelay( 0.3 );
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
void CTripmine::WeaponIdle( void )
{
if( m_pPlayer->m_bIsHolster )
{
if( m_flTimeWeaponIdle <= UTIL_WeaponTimeBase() )
{
m_pPlayer->m_bIsHolster = FALSE;
Deploy();
}
return;
}
if( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
return;

View File

@ -30,6 +30,209 @@
#include "player.h"
#include "weapons.h"
#include "gamerules.h"
#include "soundent.h"
void UTIL_CreateWarpball( edict_t *ent, Vector vecSrc, float spawnVol, float spawnSoundRad, int beamCount, int spawnType, float spriteScale, int lightRad )
{
Vector vecBeamColor, vecFlareColor, vecExpColor, vecDir, vecEnd;
TraceResult tr;
if( spawnType == 1 )
{
vecBeamColor = Vector( 255, 128, 255 );
vecFlareColor = vecBeamColor;
vecExpColor = Vector( 128, 0, 128 );
}
else
{
vecBeamColor = Vector( 197, 243, 169 );
vecFlareColor = Vector( 77, 210, 130 );
vecExpColor = Vector( 184, 250, 214 );
}
if( beamCount < 1 )
beamCount = 16;
if( spriteScale <= 0.0f )
spriteScale = 1.0f;
if( spawnSoundRad != ATTN_NONE
&& spawnSoundRad != ATTN_NORM
&& spawnSoundRad != ATTN_IDLE
&& spawnSoundRad != ATTN_STATIC )
spawnSoundRad = ATTN_NORM;
if( spawnVol <= 0.0f || spawnVol > 1.0f )
spawnVol = 1.0f;
if( lightRad <= 0 )
lightRad = 24;
UTIL_EmitAmbientSound( ent, vecSrc, "ambience/spawnsnd.wav", spawnVol, spawnSoundRad, 0, PITCH_NORM );
CSoundEnt::InsertSound( bits_SOUND_COMBAT, vecSrc, 384, 0.3 );
while( beamCount > 0 )
{
vecDir = Vector( RANDOM_LONG( -1.0f, 1.0f ), RANDOM_LONG( -1.0f, 1.0f ), RANDOM_LONG( -1.0f, 1.0f ) );
vecDir = vecDir.Normalize();
UTIL_TraceLine( vecSrc, vecSrc + vecDir * 1024, ignore_monsters, ent, &tr );
vecEnd = tr.vecEndPos;
if( ( vecEnd - vecSrc ).Length() >= ( 1024 * 0.1f ) && tr.flFraction != 1.0 )
{
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
WRITE_BYTE( TE_BEAMPOINTS );
WRITE_COORD( vecSrc.x );
WRITE_COORD( vecSrc.y );
WRITE_COORD( vecSrc.z );
WRITE_COORD( vecEnd.x );
WRITE_COORD( vecEnd.y );
WRITE_COORD( vecEnd.z );
WRITE_SHORT( g_sModelIndexLightning );
WRITE_BYTE( RANDOM_LONG( 0, 3 ) );
WRITE_BYTE( 10 );
WRITE_BYTE( 8 );
WRITE_BYTE( 18 );
WRITE_BYTE( 65 );
WRITE_BYTE( vecBeamColor.x );
WRITE_BYTE( vecBeamColor.y );
WRITE_BYTE( vecBeamColor.z );
WRITE_BYTE( 150 );
WRITE_BYTE( 35 );
MESSAGE_END();
}
--beamCount;
}
MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSrc );
WRITE_BYTE( TE_DLIGHT );
WRITE_COORD( vecSrc.x ); // X
WRITE_COORD( vecSrc.y ); // Y
WRITE_COORD( vecSrc.z ); // Z
WRITE_BYTE( lightRad ); // radius * 0.1
WRITE_BYTE( vecFlareColor.x ); // r
WRITE_BYTE( vecFlareColor.y ); // g
WRITE_BYTE( vecFlareColor.z ); // b
WRITE_BYTE( 16 ); // time * 10
WRITE_BYTE( 0 ); // decay * 0.1
MESSAGE_END();
UTIL_CreateSprite( "sprites/xflare1.spr", vecSrc, vecFlareColor, spriteScale );
UTIL_CreateSprite( "sprites/fexplo1.spr", vecSrc, vecExpColor, spriteScale );
}
void UTIL_CreateSprite( const char *spriteName, Vector origin, Vector color, float scale )
{
CSprite *pSprite = CSprite::SpriteCreate( spriteName, origin, TRUE );
pSprite->AnimateAndDie( 10 );
pSprite->SetTransparency( kRenderTransAdd, color.x, color.y, color.z, 255, kRenderFxNoDissipation );
pSprite->SetScale( scale );
}
bool UTIL_HasSuit( CBaseEntity *pEntity )
{
return ( (CBasePlayer*)pEntity )->m_bHaveSuit;
}
void UTIL_ShowKateHealth( int health )
{
hudtextparms_t textParams;
char msg[32];
textParams.channel = 1;
textParams.x = 0.03f;
textParams.y = 0.9f;
textParams.effect = 0;
if( health > 40 )
{
textParams.a1 = 100;
textParams.r1 = 64;
textParams.g1 = 64;
textParams.b1 = 255;
}
else
{
textParams.a1 = 0;
textParams.r1 = 255;
textParams.g1 = 0;
textParams.b1 = 0;
}
textParams.fadeinTime = 0.0f;
textParams.fadeoutTime = 0.5f;
textParams.holdTime = 3.0f;
textParams.fxTime = 0.25f;
sprintf( msg, "Kate's health: %d", health );
UTIL_HudMessageAll( textParams, msg );
}
const char *UTIL_GetSoundRoomTypeName( int number )
{
switch( number )
{
case 0:
return "Normal (off)";
case 1:
return "Generic";
case 2:
return "Metal Small";
case 3:
return "Metal Medium";
case 4:
return "Metal Large";
case 5:
return "Tunnel Small";
case 6:
return "Tunnel Medium";
case 7:
return "Tunnel Large";
case 8:
return "Chamber Small";
case 9:
return "Chamber Medium";
case 10:
return "Chamber Large";
case 11:
return "Bright Small";
case 12:
return "Bright Medium";
case 13:
return "Bright Large";
case 14:
return "Water 1";
case 15:
return "Water 2";
case 16:
return "Water 3";
case 17:
return "Concrete Small";
case 18:
return "Concrete Medium";
case 19:
return "Concrete Large";
case 20:
return "Big 1";
case 21:
return "Big 2";
case 22:
return "Big 3";
case 23:
return "Cavern Small";
case 24:
return "Cavern Medium";
case 25:
return "Cavern Large";
case 26:
return "Pipe Medium";
case 27:
return "Pipe Small";
case 28:
return "Pipe Big?";
default:
return "????";
}
}
float UTIL_WeaponTimeBase( void )
{

View File

@ -471,6 +471,7 @@ extern DLL_GLOBAL int g_Language;
#define SF_TRIGGER_ALLOWMONSTERS 1// monsters allowed to fire this trigger
#define SF_TRIGGER_NOCLIENTS 2// players not allowed to fire this trigger
#define SF_TRIGGER_PUSHABLES 4// only pushables can fire this trigger
#define SF_TRIGGER_KATEONLY 8
// func breakable
#define SF_BREAK_TRIGGER_ONLY 1// may only be broken by trigger
@ -578,4 +579,9 @@ int UTIL_SharedRandomLong( unsigned int seed, int low, int high );
float UTIL_SharedRandomFloat( unsigned int seed, float low, float high );
float UTIL_WeaponTimeBase( void );
const char *UTIL_GetSoundRoomTypeName( int number );
void UTIL_CreateWarpball( edict_t *ent, Vector vecSrc, float spawnVol, float spawnSoundRad, int beamCount, int spawnType, float spriteScale, int lightRad );
bool UTIL_HasSuit( CBaseEntity *pEntity );
void UTIL_ShowKateHealth( int health );
void UTIL_CreateSprite( const char *spriteName, Vector origin, Vector color, float scale );
#endif // UTIL_H

View File

@ -45,6 +45,7 @@ DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the underwater e
DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model
DLL_GLOBAL short g_sModelIndexBloodDrop;// holds the sprite index for the initial blood
DLL_GLOBAL short g_sModelIndexBloodSpray;// holds the sprite index for splattered blood
DLL_GLOBAL short g_sModelIndexLightning;// holds the sprite index for lightning
ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS];
AmmoInfo CBasePlayerItem::AmmoInfoArray[MAX_AMMO_SLOTS];
@ -168,9 +169,9 @@ void DecalGunshot( TraceResult *pTrace, int iBulletType )
case BULLET_PLAYER_MP5:
case BULLET_MONSTER_MP5:
case BULLET_PLAYER_BUCKSHOT:
case BULLET_PLAYER_BERETTA:
case BULLET_PLAYER_357:
case BULLET_PLAYER_M41A: // Alex
case BULLET_MONSTER_M41A: // Alex
default:
// smoke and decal
UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) );
@ -180,6 +181,7 @@ void DecalGunshot( TraceResult *pTrace, int iBulletType )
UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) );
break;
case BULLET_PLAYER_CROWBAR:
case BULLET_PLAYER_POOLSTICK:
// wall decal
UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) );
break;
@ -296,6 +298,7 @@ void W_Precache( void )
// custom items...
// common world objects
UTIL_PrecacheOther( "item_armor" );
UTIL_PrecacheOther( "item_suit" );
UTIL_PrecacheOther( "item_healthkit" );
UTIL_PrecacheOther( "item_battery" );
@ -322,6 +325,12 @@ void W_Precache( void )
UTIL_PrecacheOther( "ammo_9mmAR" );
UTIL_PrecacheOther( "ammo_ARgrenades" );
// Weapons with Barney's hands.
UTIL_PrecacheOtherWeapon( "weapon_barney9mmhg" );
UTIL_PrecacheOtherWeapon( "weapon_barneyshotgun" );
UTIL_PrecacheOtherWeapon( "weapon_barneyhandgrenade" );
UTIL_PrecacheOtherWeapon( "weapon_barney9mmar" );
// begin Alex
// m41a
UTIL_PrecacheOtherWeapon( "weapon_9mmm41a" );
@ -368,6 +377,9 @@ void W_Precache( void )
// toad
UTIL_PrecacheOtherWeapon( "weapon_toad" ); // Alex
// Kate's medickit
UTIL_PrecacheOtherWeapon( "weapon_kmedkit" );
// hornetgun
UTIL_PrecacheOtherWeapon( "weapon_hornetgun" );
@ -385,6 +397,7 @@ void W_Precache( void )
g_sModelIndexLaser = PRECACHE_MODEL( g_pModelNameLaser );
g_sModelIndexLaserDot = PRECACHE_MODEL( "sprites/laserdot.spr" );
g_sModelIndexLightning = PRECACHE_MODEL( "sprites/lgtning.spr" );
// used by explosions
PRECACHE_MODEL( "models/grenade.mdl" );
@ -629,16 +642,14 @@ void CBasePlayerWeapon::ItemPostFrame( void )
m_iClip += j;
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j;
m_pPlayer->TabulateAmmo();
m_fInReload = FALSE;
}
if( !(m_pPlayer->pev->button & IN_ATTACK ) )
/* if( !(m_pPlayer->pev->button & IN_ATTACK ) )
{
m_flLastFireTime = 0.0f;
}
*/
if( ( m_pPlayer->pev->button & IN_ATTACK2 ) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) )
{
if( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] )
@ -646,7 +657,6 @@ void CBasePlayerWeapon::ItemPostFrame( void )
m_fFireOnEmpty = TRUE;
}
m_pPlayer->TabulateAmmo();
SecondaryAttack();
m_pPlayer->pev->button &= ~IN_ATTACK2;
}
@ -657,7 +667,6 @@ void CBasePlayerWeapon::ItemPostFrame( void )
m_fFireOnEmpty = TRUE;
}
m_pPlayer->TabulateAmmo();
PrimaryAttack();
}
else if( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload )
@ -962,7 +971,6 @@ BOOL CBasePlayerWeapon::DefaultDeploy( const char *szViewModel, const char *szWe
if( !CanDeploy() )
return FALSE;
m_pPlayer->TabulateAmmo();
m_pPlayer->pev->viewmodel = MAKE_STRING( szViewModel );
m_pPlayer->pev->weaponmodel = MAKE_STRING( szWeaponModel );
strcpy( m_pPlayer->m_szAnimExtention, szAnimExt );
@ -970,11 +978,19 @@ BOOL CBasePlayerWeapon::DefaultDeploy( const char *szViewModel, const char *szWe
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0;
m_flLastFireTime = 0.0f;
// m_flLastFireTime = 0.0f;
return TRUE;
}
void CBasePlayerWeapon::DefaultHolster( int iAnim, float fDelay )
{
m_fInReload = FALSE;
SendWeaponAnim( iAnim );
m_flNextPrimaryAttack = m_flNextSecondaryAttack = m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + fDelay;
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay;
}
BOOL CBasePlayerWeapon::DefaultReload( int iClipSize, int iAnim, float fDelay, int body )
{
if( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 )
@ -1644,3 +1660,12 @@ TYPEDESCRIPTION CSatchel::m_SaveData[] =
};
IMPLEMENT_SAVERESTORE( CSatchel, CBasePlayerWeapon )
TYPEDESCRIPTION CKMedKit::m_SaveData[] =
{
DEFINE_FIELD( CKMedKit, m_bIsStateChanged, FIELD_BOOLEAN ),
DEFINE_FIELD( CKMedKit, m_iState, FIELD_INTEGER ),
DEFINE_FIELD( CKMedKit, m_iKateHealth, FIELD_INTEGER ),
};
IMPLEMENT_SAVERESTORE( CKMedKit, CBasePlayerWeapon )

View File

@ -32,7 +32,7 @@ public:
typedef enum { SATCHEL_DETONATE = 0, SATCHEL_RELEASE } SATCHELCODE;
static CGrenade *ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time );
static CGrenade *ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity );
static CGrenade *ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float flDmg );
static CGrenade *ShootSatchelCharge( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity );
static void UseSatchelCharges( entvars_t *pevOwner, SATCHELCODE code );
@ -80,11 +80,15 @@ public:
#define WEAPON_SNARK 15
//begin Alex
#define WEAPON_M41A 16
#define WEAPON_BERETTA 17
#define WEAPON_POOLSTICK 18
#define WEAPON_TOAD 19
#define WEAPON_KMEDKIT 20
#define WEAPON_TOAD 17
#define WEAPON_BERETTA 18
#define WEAPON_POOLSTICK 19
//end Alex
#define WEAPON_BARNEYGLOCK 20
#define WEAPON_BARNEYMP5 21
#define WEAPON_BARNEYHANDGRENADE 22
#define WEAPON_BARNEYSHOTGUN 23
#define WEAPON_KMEDKIT 24
#define WEAPON_ALLWEAPONS (~(1<<WEAPON_SUIT))
@ -109,8 +113,9 @@ public:
#define SNARK_WEIGHT 5
#define SATCHEL_WEIGHT -10
#define TRIPMINE_WEIGHT -10
#define TOAD_WEIGHT 10 // Alex
#define KMEDKIT_WEIGHT 10 // Alex
#define TOAD_WEIGHT 8 // Alex
#define KMEDKIT_WEIGHT 0 // Alex
#define M41A_WEIGHT 18
// weapon clip/carry ammo capacities
#define URANIUM_MAX_CARRY 100
@ -125,8 +130,8 @@ public:
#define SNARK_MAX_CARRY 15
#define HORNET_MAX_CARRY 8
#define M203_GRENADE_MAX_CARRY 10
#define TOAD_MAX_CARRY 250 // Alex
#define KMEDKIT_MAX_CARRY 250 // Alex
#define TOAD_MAX_CARRY 12 // Alex
#define KMEDKIT_MAX_CARRY 3 // Alex
// the maximum amount of ammo each weapon's clip can hold
#define WEAPON_NOCLIP -1
@ -147,7 +152,7 @@ public:
#define TRIPMINE_MAX_CLIP WEAPON_NOCLIP
#define SNARK_MAX_CLIP WEAPON_NOCLIP
#define BERETTA_MAX_CLIP 15
#define KMEDKIT_MAX_CLIP 1
#define KMEDKIT_MAX_CLIP WEAPON_NOCLIP
// the default amount of ammo that comes with each gun when it spawns
#define GLOCK_DEFAULT_GIVE 17
@ -167,6 +172,7 @@ public:
#define HIVEHAND_DEFAULT_GIVE 8
#define BERETTA_DEFAULT_GIVE 15 // Alex
#define KMEDKIT_DEFAULT_GIVE 1 // Alex
#define TOAD_DEFAULT_GIVE 1
// The amount of ammo given to a player by an ammo item.
#define AMMO_URANIUMBOX_GIVE 20
@ -197,7 +203,6 @@ typedef enum
BULLET_MONSTER_9MM,
BULLET_MONSTER_MP5,
BULLET_MONSTER_12MM,
BULLET_MONSTER_M41A // M41A
} Bullet;
#define ITEM_FLAG_SELECTONEMPTY 1
@ -331,6 +336,7 @@ public:
virtual BOOL CanDeploy( void );
virtual BOOL IsUseable( void );
BOOL DefaultDeploy( const char *szViewModel, const char *szWeaponModel, int iAnim, const char *szAnimExt, int skiplocal = 0, int body = 0 );
void DefaultHolster( int iAnim, float fDelay );
int DefaultReload( int iClipSize, int iAnim, float fDelay, int body = 0 );
virtual void ItemPostFrame( void ); // called each frame by the player PostThink
@ -394,6 +400,7 @@ extern DLL_GLOBAL short g_sModelIndexWExplosion;// holds the index for the under
extern DLL_GLOBAL short g_sModelIndexBubbles;// holds the index for the bubbles model
extern DLL_GLOBAL short g_sModelIndexBloodDrop;// holds the sprite index for blood drops
extern DLL_GLOBAL short g_sModelIndexBloodSpray;// holds the sprite index for blood spray (bigger)
extern DLL_GLOBAL short g_sModelIndexLightning;// holds the sprite index for lightning
extern void ClearMultiDamage(void);
extern void ApplyMultiDamage(entvars_t* pevInflictor, entvars_t* pevAttacker );
@ -490,6 +497,7 @@ public:
void SecondaryAttack( void );
void GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim );
BOOL Deploy( void );
void Holster( int skiplocal = 0 );
void Reload( void );
void WeaponIdle( void );
@ -502,7 +510,7 @@ public:
#endif
}
private:
//private:
int m_iShell;
unsigned short m_usFireGlock1;
@ -524,9 +532,8 @@ public:
int Swing( int fFirst );
BOOL Deploy( void );
void Holster( int skiplocal = 0 );
#ifdef CROWBAR_IDLE_ANIM
void WeaponIdle();
#endif
int m_iSwing;
TraceResult m_trHit;
@ -539,7 +546,6 @@ public:
#endif
}
private:
unsigned short m_usCrowbar;
};
class CPython : public CBasePlayerWeapon
@ -586,6 +592,7 @@ public:
void SecondaryAttack( void );
int SecondaryAmmoIndex( void );
BOOL Deploy( void );
void Holster( int skiplocal = 0 );
void Reload( void );
void WeaponIdle( void );
BOOL IsUseable();
@ -603,7 +610,6 @@ public:
private:
unsigned short m_usMP5;
unsigned short m_usMP52;
};
class CCrossbow : public CBasePlayerWeapon
@ -636,8 +642,6 @@ public:
}
private:
unsigned short m_usCrossbow;
unsigned short m_usCrossbow2;
};
class CShotgun : public CBasePlayerWeapon
@ -657,6 +661,7 @@ public:
void PrimaryAttack( void );
void SecondaryAttack( void );
BOOL Deploy( );
void Holster( int skiplocal = 0 );
void Reload( void );
void WeaponTick();
void WeaponIdle( void );
@ -732,7 +737,6 @@ public:
}
private:
unsigned short m_usRpg;
};
class CRpgRocket : public CGrenade
@ -777,6 +781,7 @@ public:
void StartFire( void );
void Fire( Vector vecOrigSrc, Vector vecDirShooting, float flDamage );
float GetFullChargeTime( void );
int m_fInAttack;
int m_iBalls;
int m_iGlow;
int m_iBeam;
@ -838,6 +843,9 @@ public:
void UseAmmo( int count );
static int g_fireAnims1[];
static int g_fireAnims2[];
enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE };
enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE};
CBeam *m_pBeam;
@ -859,11 +867,10 @@ private:
#ifndef CLIENT_DLL
float m_shootTime;
#endif
EGON_FIRESTATE m_fireState;
EGON_FIREMODE m_fireMode;
float m_shakeTime;
BOOL m_deployed;
unsigned short m_usEgonFire;
};
class CHgun : public CBasePlayerWeapon
@ -902,7 +909,6 @@ public:
#endif
}
private:
unsigned short m_usHornetFire;
};
class CHandGrenade : public CBasePlayerWeapon
@ -927,6 +933,8 @@ public:
return FALSE;
#endif
}
float m_flStartThrow;
float m_flReleaseThrow;
};
class CSatchel : public CBasePlayerWeapon
@ -961,6 +969,8 @@ public:
return FALSE;
#endif
}
private:
int m_chargeReady;
};
class CTripmine : public CBasePlayerWeapon
@ -992,7 +1002,6 @@ public:
}
private:
unsigned short m_usTripFire;
};
class CSqueak : public CBasePlayerWeapon
@ -1020,24 +1029,38 @@ public:
}
private:
unsigned short m_usSnarkFire;
};
// Added by Alex
class CKMedkit : public CBasePlayerWeapon
class CKMedKit : public CBasePlayerWeapon
{
public:
#ifndef CLIENT_DLL
int Save( CSave &save );
int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
#endif
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 2; }
int iItemSlot( void ) { return 1; }
int GetItemInfo(ItemInfo *p);
int AddToPlayer( CBasePlayer *pPlayer );
void Holster( int skiplocal /* = 0 */ );
void PrimaryAttack( void );
void SecondaryAttack( void );
void KMedkitFire( float flSpread, float flCycleTime, BOOL fUseAutoAim );
void UseMedkit( int fMode );
void EXPORT SayKateHealth();
BOOL Deploy( void );
void Reload( void );
void WeaponIdle( void );
BOOL IsUseable()
{
return TRUE;
}
BOOL CanDeploy()
{
return TRUE;
}
virtual BOOL UseDecrement( void )
{
@ -1049,8 +1072,9 @@ public:
}
private:
unsigned short m_usUseKMedkit;
BOOL m_bIsStateChanged;
int m_iState;
int m_iKateHealth;
};
// end
@ -1069,6 +1093,7 @@ public:
BOOL Deploy( void );
void Reload( void );
void WeaponIdle( void );
void Holster( int skiplocal /* = 0 */ );
virtual BOOL UseDecrement( void )
{
@ -1101,6 +1126,8 @@ public:
int Swing( int fFirst );
BOOL Deploy( void );
void Holster( int skiplocal = 0 );
void WeaponIdle();
int m_iSwing;
TraceResult m_trHit;
@ -1113,7 +1140,6 @@ public:
#endif
}
private:
unsigned short m_usPoolstick;
};
// Alex end
// Added by Alex
@ -1125,6 +1151,7 @@ public:
int iItemSlot( void ) { return 3; }
int GetItemInfo(ItemInfo *p);
int AddToPlayer( CBasePlayer *pPlayer );
void Holster( int skiplocal /* = 0 */ );
void PrimaryAttack( void );
void SecondaryAttack( void );
@ -1132,6 +1159,8 @@ public:
BOOL Deploy( void );
void Reload( void );
void WeaponIdle( void );
BOOL IsUseable();
float m_flNextAnimTime;
int m_iShell;
@ -1146,7 +1175,6 @@ public:
private:
unsigned short m_usM41A;
unsigned short m_usM41A2;
};
// end
// alex
@ -1157,6 +1185,8 @@ public:
void Precache( void );
int iItemSlot( void ) { return 5; }
int GetItemInfo(ItemInfo *p);
void EXPORT ToadIdle();
void HuntSound( bool force );
void PrimaryAttack( void );
void SecondaryAttack( void );
@ -1173,9 +1203,47 @@ public:
return FALSE;
#endif
}
private:
unsigned short m_usToadFire;
Vector m_posNext;
float m_flNextTrace;
float m_flNextHunt;
float m_flDie;
};
// alex
class CBarneyGlock : public CGlock
{
public:
void Spawn();
void Precache();
int GetItemInfo( ItemInfo *p );
BOOL Deploy();
};
class CBarneyShotgun : public CShotgun
{
public:
void Spawn();
void Precache();
int GetItemInfo( ItemInfo *p );
BOOL Deploy();
};
class CBarneyMP5 : public CMP5
{
public:
void Spawn();
void Precache();
int GetItemInfo( ItemInfo *p );
BOOL Deploy();
};
class CBarneyHandGrenade : public CHandGrenade
{
public:
void Spawn();
void Precache();
int GetItemInfo( ItemInfo *p );
BOOL Deploy();
};
#endif // WEAPONS_H

View File

@ -266,17 +266,17 @@ void CZombie::HandleAnimEvent( MonsterEvent_t *pEvent )
void CZombie::Spawn()
{
Precache();
if( FClassnameIs( pev, "monster_zombie" ) )
SET_MODEL( ENT( pev ), "models/zombie.mdl" );
else
SET_MODEL( ENT( pev ), "models/zbarnie.mdl" );
SET_MODEL( ENT( pev ), STRING( pev->model ) );
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
pev->solid = SOLID_SLIDEBOX;
pev->movetype = MOVETYPE_STEP;
m_bloodColor = BLOOD_COLOR_GREEN;
pev->health = gSkillData.zombieHealth;
if( FClassnameIs( pev, "monster_zombie" ) )
pev->health = gSkillData.zombieHealth;
else
pev->health = gSkillData.zombieHealth * 1.25;
pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin.
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_MonsterState = MONSTERSTATE_NONE;
@ -293,9 +293,11 @@ void CZombie::Precache()
size_t i;
if( FClassnameIs( pev, "monster_zombie" ) )
PRECACHE_MODEL( "models/zombie.mdl" );
pev->model = MAKE_STRING( "models/zombie.mdl" );
else
PRECACHE_MODEL( "models/zbarnie.mdl" );
pev->model = MAKE_STRING( "models/zbarney.mdl" );
PRECACHE_MODEL( STRING( pev->model ) );
for( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND( pAttackHitSounds[i] );