From 888483b5c4aeb41f0f6d451d86452cc22edea353 Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 13 Jan 2018 01:47:39 +0500 Subject: [PATCH] Upload reverse-engineered Azure Sheep source code. --- cl_dll/Android.mk | 16 +- cl_dll/CMakeLists.txt | 20 +- cl_dll/ammohistory.h | 2 +- cl_dll/ev_hldm.cpp | 644 +---------- cl_dll/health.cpp | 2 +- cl_dll/hl/hl_baseentity.cpp | 2 +- cl_dll/hl/hl_events.cpp | 20 - cl_dll/hl/hl_objects.cpp | 46 - cl_dll/hl/hl_weapons.cpp | 156 --- cl_dll/hud.cpp | 4 +- cl_dll/hud.h | 4 +- cl_dll/hud_msg.cpp | 5 - dlls/Android.mk | 20 +- dlls/CMakeLists.txt | 15 +- dlls/agrunt.cpp | 15 +- dlls/apache.cpp | 2 +- dlls/asheep/adrian.cpp | 842 -------------- dlls/asheep/alienpanther.cpp | 866 -------------- dlls/asheep/archer.cpp | 839 +++----------- dlls/asheep/barneyglock.cpp | 78 ++ dlls/asheep/barneyhg.cpp | 81 ++ dlls/asheep/barneymp5.cpp | 78 ++ dlls/asheep/barneyshotgun.cpp | 82 ++ dlls/asheep/barniel.cpp | 707 ++---------- dlls/asheep/beretta.cpp | 43 +- dlls/asheep/bodypart.cpp | 106 ++ dlls/asheep/garbage.cpp | 186 +++ dlls/asheep/gordon.cpp | 844 -------------- dlls/asheep/gordonnadrian.cpp | 495 ++++++++ dlls/asheep/hevbarn.cpp | 839 -------------- dlls/asheep/kate.cpp | 832 +++++--------- dlls/asheep/kmedkit.cpp | 368 ++++++ dlls/asheep/m41a.cpp | 85 +- dlls/asheep/panther.cpp | 517 +++++++++ dlls/asheep/poolstick.cpp | 97 +- dlls/asheep/spforce.cpp | 2023 +-------------------------------- dlls/asheep/terror.cpp | 1553 +------------------------ dlls/asheep/toad.cpp | 219 +++- dlls/barney.cpp | 151 +-- dlls/barney.h | 94 ++ dlls/cbase.h | 18 - dlls/cdll_dll.h | 2 +- dlls/combat.cpp | 14 +- dlls/crossbow.cpp | 109 +- dlls/crowbar.cpp | 59 +- dlls/effects.cpp | 108 +- dlls/egon.cpp | 79 +- dlls/gauss.cpp | 41 +- dlls/genericmonster.cpp | 49 +- dlls/ggrenade.cpp | 4 +- dlls/glock.cpp | 39 +- dlls/h_battery.cpp | 27 +- dlls/handgrenade.cpp | 29 +- dlls/headcrab.cpp | 38 +- dlls/headcrab.h | 50 + dlls/healthkit.cpp | 22 +- dlls/hgrunt.cpp | 158 ++- dlls/hgrunt.h | 98 ++ dlls/hornet.cpp | 13 + dlls/hornetgun.cpp | 55 +- dlls/ichthyosaur.cpp | 92 +- dlls/ichthyosaur.h | 108 ++ dlls/islave.cpp | 128 +-- dlls/islave.h | 96 ++ dlls/items.cpp | 63 +- dlls/monstermaker.cpp | 77 +- dlls/mortar.cpp | 2 +- dlls/mp5.cpp | 72 +- dlls/multiplay_gamerules.cpp | 6 +- dlls/nihilanth.cpp | 2 +- dlls/plats.cpp | 43 +- dlls/player.cpp | 110 +- dlls/player.h | 5 +- dlls/playermonster.cpp | 2 +- dlls/python.cpp | 46 +- dlls/rat.cpp | 226 +++- dlls/rpg.cpp | 50 +- dlls/satchel.cpp | 36 +- dlls/scientist.cpp | 180 +-- dlls/shotgun.cpp | 52 +- dlls/sound.cpp | 84 +- dlls/squeakgrenade.cpp | 42 +- dlls/talkmonster.cpp | 5 +- dlls/talkmonster.h | 2 +- dlls/trains.h | 1 + dlls/triggers.cpp | 176 ++- dlls/tripmine.cpp | 32 +- dlls/util.cpp | 203 ++++ dlls/util.h | 6 + dlls/weapons.cpp | 43 +- dlls/weapons.h | 136 ++- dlls/zombie.cpp | 16 +- 92 files changed, 5509 insertions(+), 10643 deletions(-) delete mode 100644 dlls/asheep/adrian.cpp delete mode 100644 dlls/asheep/alienpanther.cpp create mode 100644 dlls/asheep/barneyglock.cpp create mode 100644 dlls/asheep/barneyhg.cpp create mode 100644 dlls/asheep/barneymp5.cpp create mode 100644 dlls/asheep/barneyshotgun.cpp create mode 100644 dlls/asheep/bodypart.cpp create mode 100644 dlls/asheep/garbage.cpp delete mode 100644 dlls/asheep/gordon.cpp create mode 100644 dlls/asheep/gordonnadrian.cpp delete mode 100644 dlls/asheep/hevbarn.cpp create mode 100644 dlls/asheep/kmedkit.cpp create mode 100644 dlls/asheep/panther.cpp create mode 100644 dlls/barney.h create mode 100644 dlls/headcrab.h create mode 100644 dlls/hgrunt.h create mode 100644 dlls/ichthyosaur.h create mode 100644 dlls/islave.h diff --git a/cl_dll/Android.mk b/cl_dll/Android.mk index 68917633..ccff9620 100755 --- a/cl_dll/Android.mk +++ b/cl_dll/Android.mk @@ -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 \ diff --git a/cl_dll/CMakeLists.txt b/cl_dll/CMakeLists.txt index 08741920..d531e94b 100644 --- a/cl_dll/CMakeLists.txt +++ b/cl_dll/CMakeLists.txt @@ -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 diff --git a/cl_dll/ammohistory.h b/cl_dll/ammohistory.h index 44edc916..9a08aa49 100644 --- a/cl_dll/ammohistory.h +++ b/cl_dll/ammohistory.h @@ -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 { diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index 89466e75..e178fac3 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -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 ); diff --git a/cl_dll/health.cpp b/cl_dll/health.cpp index d4979c35..93775b58 100644 --- a/cl_dll/health.cpp +++ b/cl_dll/health.cpp @@ -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 ); diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp index 38978f6a..237e12c1 100644 --- a/cl_dll/hl/hl_baseentity.cpp +++ b/cl_dll/hl/hl_baseentity.cpp @@ -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 ){ } diff --git a/cl_dll/hl/hl_events.cpp b/cl_dll/hl/hl_events.cpp index acd88370..09055ec0 100644 --- a/cl_dll/hl/hl_events.cpp +++ b/cl_dll/hl/hl_events.cpp @@ -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 ); diff --git a/cl_dll/hl/hl_objects.cpp b/cl_dll/hl/hl_objects.cpp index b51ee693..dfeb4e1f 100644 --- a/cl_dll/hl/hl_objects.cpp +++ b/cl_dll/hl/hl_objects.cpp @@ -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(); } diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp index 117f8332..c0f9720a 100644 --- a/cl_dll/hl/hl_weapons.cpp +++ b/cl_dll/hl/hl_weapons.cpp @@ -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; diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp index 05bda284..8a5be12f 100644 --- a/cl_dll/hud.cpp +++ b/cl_dll/hud.cpp @@ -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; diff --git a/cl_dll/hud.h b/cl_dll/hud.h index 0ead395c..04899300 100644 --- a/cl_dll/hud.h +++ b/cl_dll/hud.h @@ -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" diff --git a/cl_dll/hud_msg.cpp b/cl_dll/hud_msg.cpp index 47f8bc92..966011a7 100644 --- a/cl_dll/hud_msg.cpp +++ b/cl_dll/hud_msg.cpp @@ -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 ) diff --git a/dlls/Android.mk b/dlls/Android.mk index 1dc79616..5ca277cb 100644 --- a/dlls/Android.mk +++ b/dlls/Android.mk @@ -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 diff --git a/dlls/CMakeLists.txt b/dlls/CMakeLists.txt index e031900c..cc478d0e 100644 --- a/dlls/CMakeLists.txt +++ b/dlls/CMakeLists.txt @@ -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 diff --git a/dlls/agrunt.cpp b/dlls/agrunt.cpp index cb47ac65..83ab9ebf 100644 --- a/dlls/agrunt.cpp +++ b/dlls/agrunt.cpp @@ -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 ) diff --git a/dlls/apache.cpp b/dlls/apache.cpp index b3cfcf87..7b49188f 100644 --- a/dlls/apache.cpp +++ b/dlls/apache.cpp @@ -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" ); diff --git a/dlls/asheep/adrian.cpp b/dlls/asheep/adrian.cpp deleted file mode 100644 index 349bdfd5..00000000 --- a/dlls/asheep/adrian.cpp +++ /dev/null @@ -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(); -} diff --git a/dlls/asheep/alienpanther.cpp b/dlls/asheep/alienpanther.cpp deleted file mode 100644 index bc5ae32d..00000000 --- a/dlls/asheep/alienpanther.cpp +++ /dev/null @@ -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" ); -} diff --git a/dlls/asheep/archer.cpp b/dlls/asheep/archer.cpp index 21dc403a..7733ec72 100644 --- a/dlls/asheep/archer.cpp +++ b/dlls/asheep/archer.cpp @@ -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. @@ -15,7 +15,7 @@ #if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD ) //========================================================= -// icthyosaur - evin, satan fish monster +// archer //========================================================= #include "extdll.h" @@ -23,16 +23,17 @@ #include "cbase.h" #include "monsters.h" #include "schedule.h" -#include "flyingmonster.h" +#include "flyingmonster.h" #include "nodes.h" #include "soundent.h" #include "animation.h" #include "effects.h" #include "weapons.h" +#include "ichthyosaur.h" #define SEARCH_RETRY 16 -#define ARCHER_SPEED 75 +#define ARCHER_SPEED 40 extern CGraph WorldGraph; @@ -42,71 +43,25 @@ extern CGraph WorldGraph; #define EYE_BACK 3 #define EYE_LOOK 4 - - //========================================================= // Monster's Anim Events Go Here //========================================================= // UNDONE: Save/restore here -class CArcher : public CFlyingMonster +class CArcher : public CIchthyosaur { 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[]; + void Spawn( void ); + void Precache( void ); + void HandleAnimEvent( MonsterEvent_t *pEvent ); Schedule_t *GetSchedule( void ); - Schedule_t *GetScheduleOfType ( int Type ); - void Killed( entvars_t *pevAttacker, int iGib ); - void BecomeDead( void ); + void StartTask( Task_t *pTask ); - 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; + void MonsterThink( void ); + void Stop( void ); + void Swim( void ); static const char *pIdleSounds[]; static const char *pAlertSounds[]; @@ -123,51 +78,34 @@ public: void PainSound( void ); }; -LINK_ENTITY_TO_CLASS( monster_archer, CArcher ); +LINK_ENTITY_TO_CLASS( monster_archer, CArcher ) -TYPEDESCRIPTION CArcher::m_SaveData[] = -{ - DEFINE_FIELD( CArcher, m_SaveVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CArcher, m_idealDist, FIELD_FLOAT ), - DEFINE_FIELD( CArcher, m_flBlink, FIELD_FLOAT ), - DEFINE_FIELD( CArcher, m_flEnemyTouched, FIELD_FLOAT ), - DEFINE_FIELD( CArcher, m_bOnAttack, FIELD_BOOLEAN ), - DEFINE_FIELD( CArcher, m_flMaxSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CArcher, m_flMinSpeed, FIELD_FLOAT ), - DEFINE_FIELD( CArcher, m_flMaxDist, FIELD_FLOAT ), - DEFINE_FIELD( CArcher, m_flNextAlert, FIELD_TIME ), -}; - -IMPLEMENT_SAVERESTORE( CArcher, CFlyingMonster ); - - -const char *CArcher::pIdleSounds[] = +const char *CArcher::pIdleSounds[] = { "archer/arch_idle1.wav", "archer/arch_idle2.wav", "archer/arch_idle3.wav", - //"arch/arch_idle4.wav", }; -const char *CArcher::pAlertSounds[] = +const char *CArcher::pAlertSounds[] = { "archer/arch_alert1.wav", "archer/arch_alert2.wav", }; -const char *CArcher::pAttackSounds[] = +const char *CArcher::pAttackSounds[] = { "archer/arch_attack1.wav", "archer/arch_attack2.wav", }; -const char *CArcher::pBiteSounds[] = +const char *CArcher::pBiteSounds[] = { "archer/arch_bite1.wav", "archer/arch_bite2.wav", }; -const char *CArcher::pPainSounds[] = +const char *CArcher::pPainSounds[] = { "archer/arch_pain1.wav", "archer/arch_pain2.wav", @@ -175,252 +113,64 @@ const char *CArcher::pPainSounds[] = "archer/arch_pain4.wav", }; -const char *CArcher::pDieSounds[] = +const char *CArcher::pDieSounds[] = { "archer/arch_die1.wav", "archer/arch_die2.wav", "archer/arch_die3.wav", }; -#define EMIT_ARCH_SOUND( chan, array ) \ - EMIT_SOUND_DYN ( ENT(pev), chan , array [ RANDOM_LONG(0,ARRAYSIZE( array )-1) ], 1.0, 0.6, 0, RANDOM_LONG(95,105) ); //see here Alex +#define EMIT_ICKY_SOUND( chan, array ) \ + EMIT_SOUND_DYN( ENT( pev ), chan , array[RANDOM_LONG( 0, ARRAYSIZE( array ) - 1 )], 1.0, 0.6, 0, RANDOM_LONG( 95, 105 ) ); - -void CArcher :: IdleSound( void ) +void CArcher::IdleSound( void ) { - EMIT_ARCH_SOUND( CHAN_VOICE, pIdleSounds ); + EMIT_ICKY_SOUND( CHAN_VOICE, pIdleSounds ); } -void CArcher :: AlertSound( void ) -{ - EMIT_ARCH_SOUND( CHAN_VOICE, pAlertSounds ); +void CArcher::AlertSound( void ) +{ + EMIT_ICKY_SOUND( CHAN_VOICE, pAlertSounds ); } -void CArcher :: AttackSound( void ) +void CArcher::AttackSound( void ) { - EMIT_ARCH_SOUND( CHAN_VOICE, pAttackSounds ); + EMIT_ICKY_SOUND( CHAN_VOICE, pAttackSounds ); } -void CArcher :: BiteSound( void ) +void CArcher::BiteSound( void ) { - EMIT_ARCH_SOUND( CHAN_WEAPON, pBiteSounds ); + EMIT_ICKY_SOUND( CHAN_WEAPON, pBiteSounds ); } -void CArcher :: DeathSound( void ) +void CArcher::DeathSound( void ) { - EMIT_ARCH_SOUND( CHAN_VOICE, pDieSounds ); + EMIT_ICKY_SOUND( CHAN_VOICE, pDieSounds ); } -void CArcher :: PainSound( void ) +void CArcher::PainSound( void ) { - EMIT_ARCH_SOUND( CHAN_VOICE, pPainSounds ); + EMIT_ICKY_SOUND( CHAN_VOICE, pPainSounds ); } //========================================================= // monster-specific tasks and states //========================================================= -enum +enum { TASK_ARCHER_CIRCLE_ENEMY = LAST_COMMON_TASK + 1, TASK_ARCHER_SWIM, - TASK_ARCHER_FLOAT, + TASK_ARCHER_FLOAT }; -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -static Task_t tlSwimAround[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_WALK }, - { TASK_ARCHER_SWIM, 0.0 }, -}; - -static Schedule_t slSwimAround[] = -{ - { - tlSwimAround, - ARRAYSIZE(tlSwimAround), - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND, - bits_SOUND_PLAYER | - bits_SOUND_COMBAT, - "SwimAround" - }, -}; - -static Task_t tlSwimAgitated[] = -{ - { TASK_STOP_MOVING, (float) 0 }, - { TASK_SET_ACTIVITY, (float)ACT_RUN }, - { TASK_WAIT, (float)2.0 }, -}; - -static Schedule_t slSwimAgitated[] = -{ - { - tlSwimAgitated, - ARRAYSIZE(tlSwimAgitated), - 0, - 0, - "SwimAgitated" - }, -}; - - -static Task_t tlCircleEnemy[] = -{ - { TASK_SET_ACTIVITY, (float)ACT_WALK }, - { TASK_ARCHER_CIRCLE_ENEMY, 0.0 }, -}; - -static Schedule_t slCircleEnemy[] = -{ - { - tlCircleEnemy, - ARRAYSIZE(tlCircleEnemy), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK1, - 0, - "CircleEnemy" - }, -}; - - -Task_t tlTwitchDieArcher[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SOUND_DIE, (float)0 }, - { TASK_DIE, (float)0 }, - { TASK_ARCHER_FLOAT, (float)0 }, -}; - -Schedule_t slTwitchDieArcher[] = -{ - { - tlTwitchDieArcher, - ARRAYSIZE( tlTwitchDieArcher ), - 0, - 0, - "Die" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES(CArcher) -{ - slSwimAround, - slSwimAgitated, - slCircleEnemy, - slTwitchDieArcher, -}; -IMPLEMENT_CUSTOM_SCHEDULES(CArcher, CFlyingMonster); - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CArcher :: Classify ( void ) -{ - return CLASS_ALIEN_MONSTER; -} - - -//========================================================= -// CheckMeleeAttack1 -//========================================================= -BOOL CArcher :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - if ( flDot >= 0.7 && m_flEnemyTouched > gpGlobals->time - 0.2 ) - { - return TRUE; - } - return FALSE; -} - -void CArcher::BiteTouch( CBaseEntity *pOther ) -{ - // bite if we hit who we want to eat - if ( pOther == m_hEnemy ) - { - m_flEnemyTouched = gpGlobals->time; - m_bOnAttack = TRUE; - } -} - -void CArcher::CombatUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !ShouldToggle( useType, m_bOnAttack ) ) - return; - - if (m_bOnAttack) - { - m_bOnAttack = 0; - } - else - { - m_bOnAttack = 1; - } -} - -//========================================================= -// CheckRangeAttack1 - swim in for a chomp -// -//========================================================= -BOOL CArcher :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( flDot > -0.7 && (m_bOnAttack || ( flDist <= 192 && m_idealDist <= 192))) - { - return TRUE; - } - - return FALSE; -} - -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CArcher :: SetYawSpeed ( void ) -{ - pev->yaw_speed = 100; -} - - - -//========================================================= -// Killed - overrides CFlyingMonster. -// -void CArcher :: Killed( entvars_t *pevAttacker, int iGib ) -{ - CBaseMonster::Killed( pevAttacker, iGib ); - pev->velocity = Vector( 0, 0, 0 ); -} - -void CArcher::BecomeDead( void ) -{ - pev->takedamage = DAMAGE_YES;// don't let autoaim aim at corpses. - - // give the corpse half of the monster's original maximum health. - pev->health = pev->max_health / 2; - pev->max_health = 5; // max_health now becomes a counter for how many blood decals the corpse can place. -} - #define ARCHER_AE_SHAKE_RIGHT 1 #define ARCHER_AE_SHAKE_LEFT 2 - //========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. //========================================================= -void CArcher :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CArcher::HandleAnimEvent( MonsterEvent_t *pEvent ) { int bDidAttack = FALSE; switch( pEvent->event ) @@ -428,30 +178,30 @@ void CArcher :: HandleAnimEvent( MonsterEvent_t *pEvent ) case ARCHER_AE_SHAKE_RIGHT: case ARCHER_AE_SHAKE_LEFT: { - if (m_hEnemy != NULL && FVisible( m_hEnemy )) + if( m_hEnemy != 0 && FVisible( m_hEnemy ) ) { CBaseEntity *pHurt = m_hEnemy; - if (m_flEnemyTouched < gpGlobals->time - 0.2 && (m_hEnemy->BodyTarget( pev->origin ) - pev->origin).Length() > (32+16+32)) + if( m_flEnemyTouched < gpGlobals->time - 0.2 && ( m_hEnemy->BodyTarget( pev->origin ) - pev->origin).Length() > ( 32 + 16 + 32 ) ) break; Vector vecShootDir = ShootAtEnemy( pev->origin ); - UTIL_MakeAimVectors ( pev->angles ); + UTIL_MakeAimVectors( pev->angles ); - if (DotProduct( vecShootDir, gpGlobals->v_forward ) > 0.707) + if( DotProduct( vecShootDir, gpGlobals->v_forward ) > 0.707 ) { m_bOnAttack = TRUE; pHurt->pev->punchangle.z = -18; pHurt->pev->punchangle.x = 5; pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 300; - if (pHurt->IsPlayer()) + if( pHurt->IsPlayer() ) { pHurt->pev->angles.x += RANDOM_FLOAT( -35, 35 ); pHurt->pev->angles.y += RANDOM_FLOAT( -90, 90 ); pHurt->pev->angles.z = 0; pHurt->pev->fixangle = TRUE; } - pHurt->TakeDamage( pev, pev, gSkillData.ichthyosaurDmgShake, DMG_SLASH ); + pHurt->TakeDamage( pev, pev, gSkillData.ichthyosaurDmgShake / 2, DMG_SLASH ); } } BiteSound(); @@ -464,7 +214,7 @@ void CArcher :: HandleAnimEvent( MonsterEvent_t *pEvent ) break; } - if (bDidAttack) + if( bDidAttack ) { Vector vecSrc = pev->origin + gpGlobals->v_forward * 32; UTIL_Bubbles( vecSrc - Vector( 8, 8, 8 ), vecSrc + Vector( 8, 8, 8 ), 16 ); @@ -474,18 +224,18 @@ void CArcher :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= // Spawn //========================================================= -void CArcher :: Spawn() +void CArcher::Spawn() { - Precache( ); + Precache(); - SET_MODEL(ENT(pev), "models/archer.mdl"); - UTIL_SetSize( pev, Vector( -32, -32, -32 ), Vector( 32, 32, 32 ) ); + SET_MODEL( ENT( pev ), "models/archer.mdl" ); + UTIL_SetSize( pev, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ) ); - pev->solid = SOLID_BBOX; + pev->solid = SOLID_BBOX; pev->movetype = MOVETYPE_FLY; m_bloodColor = BLOOD_COLOR_GREEN; - pev->health = gSkillData.ichthyosaurHealth; - pev->view_ofs = Vector ( 0, 0, 16 ); + pev->health = gSkillData.ichthyosaurHealth * 0.5f; + pev->view_ofs = Vector( 0, 0, 16 ); m_flFieldOfView = VIEW_FIELD_WIDE; m_MonsterState = MONSTERSTATE_NONE; SetBits(pev->flags, FL_SWIM); @@ -500,12 +250,12 @@ void CArcher :: Spawn() SetUse( &CArcher::CombatUse ); m_idealDist = 384; - m_flMinSpeed = 80; - m_flMaxSpeed = 300; + m_flMinSpeed = 40; + m_flMaxSpeed = 50; m_flMaxDist = 384; Vector Forward; - UTIL_MakeVectorsPrivate(pev->angles, Forward, 0, 0); + UTIL_MakeVectorsPrivate( pev->angles, Forward, 0, 0 ); pev->velocity = m_flightSpeed * Forward.Normalize(); m_SaveVelocity = pev->velocity; } @@ -513,9 +263,9 @@ void CArcher :: Spawn() //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CArcher :: Precache() +void CArcher::Precache() { - PRECACHE_MODEL("models/archer.mdl"); + PRECACHE_MODEL( "models/archer.mdl" ); PRECACHE_SOUND_ARRAY( pIdleSounds ); PRECACHE_SOUND_ARRAY( pAlertSounds ); @@ -531,405 +281,132 @@ void CArcher :: Precache() Schedule_t* CArcher::GetSchedule() { // ALERT( at_console, "GetSchedule( )\n" ); - switch(m_MonsterState) + switch( m_MonsterState ) { case MONSTERSTATE_IDLE: - m_flightSpeed = 80; + m_flightSpeed = 75; return GetScheduleOfType( SCHED_IDLE_WALK ); - + break; case MONSTERSTATE_ALERT: - m_flightSpeed = 150; + m_flightSpeed = 90; return GetScheduleOfType( SCHED_IDLE_WALK ); - + break; case MONSTERSTATE_COMBAT: - m_flMaxSpeed = 400; + m_flMaxSpeed = 200; // eat them - if ( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) + if( HasConditions( bits_COND_CAN_MELEE_ATTACK1 ) ) { return GetScheduleOfType( SCHED_MELEE_ATTACK1 ); } + // chase them down and eat them - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) + if( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) ) { return GetScheduleOfType( SCHED_CHASE_ENEMY ); } - if ( HasConditions( bits_COND_HEAVY_DAMAGE ) ) + if( HasConditions( bits_COND_HEAVY_DAMAGE ) ) { m_bOnAttack = TRUE; } - if ( pev->health < pev->max_health - 20 ) + if( pev->health < pev->max_health - 20 ) { m_bOnAttack = TRUE; } return GetScheduleOfType( SCHED_STANDOFF ); + break; + default: + break; } - return CFlyingMonster :: GetSchedule(); + return CFlyingMonster::GetSchedule(); } - -//========================================================= -//========================================================= -Schedule_t* CArcher :: GetScheduleOfType ( int Type ) -{ - // ALERT( at_console, "GetScheduleOfType( %d ) %d\n", Type, m_bOnAttack ); - switch ( Type ) - { - case SCHED_IDLE_WALK: - return slSwimAround; - case SCHED_STANDOFF: - return slCircleEnemy; - case SCHED_FAIL: - return slSwimAgitated; - case SCHED_DIE: - return slTwitchDieArcher; - case SCHED_CHASE_ENEMY: - AttackSound( ); - } - - return CBaseMonster :: GetScheduleOfType( Type ); -} - - - //========================================================= // Start task - selects the correct activity and performs // any necessary calculations to start the next task on the // schedule. //========================================================= -void CArcher::StartTask(Task_t *pTask) +void CArcher::StartTask( Task_t *pTask ) { - switch (pTask->iTask) + switch( pTask->iTask ) { - case TASK_ARCHER_CIRCLE_ENEMY: - break; - case TASK_ARCHER_SWIM: - break; - case TASK_SMALL_FLINCH: - if (m_idealDist > 128) - { - m_flMaxDist = 512; - m_idealDist = 512; - } - else - { - m_bOnAttack = TRUE; - } - CFlyingMonster::StartTask(pTask); - break; - case TASK_ARCHER_FLOAT: - pev->skin = EYE_BASE; - SetSequenceByName( "bellyup" ); + SetSequenceByName( RANDOM_LONG( 0, 1 ) ? "die2" : "die1" ); break; - default: - CFlyingMonster::StartTask(pTask); + CIchthyosaur::StartTask( pTask ); break; } } -void CArcher :: RunTask ( Task_t *pTask ) +void CArcher::MonsterThink( void ) { - switch ( pTask->iTask ) + CFlyingMonster::MonsterThink(); + + if( pev->deadflag == DEAD_NO ) { - case TASK_ARCHER_CIRCLE_ENEMY: - if (m_hEnemy == NULL) + if( m_MonsterState != MONSTERSTATE_SCRIPT ) { - TaskComplete( ); - } - else if (FVisible( m_hEnemy )) - { - Vector vecFrom = m_hEnemy->EyePosition( ); - - Vector vecDelta = (pev->origin - vecFrom).Normalize( ); - Vector vecSwim = CrossProduct( vecDelta, Vector( 0, 0, 1 ) ).Normalize( ); - - if (DotProduct( vecSwim, m_SaveVelocity ) < 0) - vecSwim = vecSwim * -1.0; - - Vector vecPos = vecFrom + vecDelta * m_idealDist + vecSwim * 32; - - // ALERT( at_console, "vecPos %.0f %.0f %.0f\n", vecPos.x, vecPos.y, vecPos.z ); - - TraceResult tr; - - UTIL_TraceHull( vecFrom, vecPos, ignore_monsters, large_hull, m_hEnemy->edict(), &tr ); - - if (tr.flFraction > 0.5) - vecPos = tr.vecEndPos; - - m_SaveVelocity = m_SaveVelocity * 0.8 + 0.2 * (vecPos - pev->origin).Normalize() * m_flightSpeed; - - // ALERT( at_console, "m_SaveVelocity %.2f %.2f %.2f\n", m_SaveVelocity.x, m_SaveVelocity.y, m_SaveVelocity.z ); - - if (HasConditions( bits_COND_ENEMY_FACING_ME ) && m_hEnemy->FVisible( this )) - { - m_flNextAlert -= 0.1; - - if (m_idealDist < m_flMaxDist) - { - m_idealDist += 4; - } - if (m_flightSpeed > m_flMinSpeed) - { - m_flightSpeed -= 2; - } - else if (m_flightSpeed < m_flMinSpeed) - { - m_flightSpeed += 2; - } - if (m_flMinSpeed < m_flMaxSpeed) - { - m_flMinSpeed += 0.5; - } - } - else - { - m_flNextAlert += 0.1; - - if (m_idealDist > 128) - { - m_idealDist -= 4; - } - if (m_flightSpeed < m_flMaxSpeed) - { - m_flightSpeed += 4; - } - } - // ALERT( at_console, "%.0f\n", m_idealDist ); - } - else - { - m_flNextAlert = gpGlobals->time + 0.2; - } - - if (m_flNextAlert < gpGlobals->time) - { - // ALERT( at_console, "AlertSound()\n"); - AlertSound( ); - m_flNextAlert = gpGlobals->time + RANDOM_FLOAT( 3, 5 ); - } - - break; - case TASK_ARCHER_SWIM: - if (m_fSequenceFinished) - { - TaskComplete( ); - } - break; - case TASK_DIE: - if ( m_fSequenceFinished ) - { - pev->deadflag = DEAD_DEAD; - - TaskComplete( ); - } - break; - - case TASK_ARCHER_FLOAT: - pev->angles.x = UTIL_ApproachAngle( 0, pev->angles.x, 20 ); - pev->velocity = pev->velocity * 0.8; - if (pev->waterlevel > 1 && pev->velocity.z < 64) - { - pev->velocity.z += 8; - } - else - { - pev->velocity.z -= 8; - } - // ALERT( at_console, "%f\n", pev->velocity.z ); - break; - - default: - CFlyingMonster :: RunTask ( pTask ); - break; - } -} - - - -float CArcher::VectorToPitch( const Vector &vec ) -{ - float pitch; - if (vec.z == 0 && vec.x == 0) - pitch = 0; - else - { - pitch = (int) (atan2(vec.z, sqrt(vec.x*vec.x+vec.y*vec.y)) * 180 / M_PI); - if (pitch < 0) - pitch += 360; - } - return pitch; -} - -//========================================================= -void CArcher::Move(float flInterval) -{ - CFlyingMonster::Move( flInterval ); -} - -float CArcher::FlPitchDiff( void ) -{ - float flPitchDiff; - float flCurrentPitch; - - flCurrentPitch = UTIL_AngleMod( pev->angles.z ); - - if ( flCurrentPitch == pev->idealpitch ) - { - return 0; - } - - flPitchDiff = pev->idealpitch - flCurrentPitch; - - if ( pev->idealpitch > flCurrentPitch ) - { - if (flPitchDiff >= 180) - flPitchDiff = flPitchDiff - 360; - } - else - { - if (flPitchDiff <= -180) - flPitchDiff = flPitchDiff + 360; - } - return flPitchDiff; -} - -float CArcher :: ChangePitch( int speed ) -{ - if ( pev->movetype == MOVETYPE_FLY ) - { - float diff = FlPitchDiff(); - float target = 0; - if ( m_IdealActivity != GetStoppedActivity() ) - { - if (diff < -20) - target = 45; - else if (diff > 20) - target = -45; - } - pev->angles.x = UTIL_Approach(target, pev->angles.x, 220.0 * 0.1 ); - } - return 0; -} - -float CArcher::ChangeYaw( int speed ) -{ - if ( pev->movetype == MOVETYPE_FLY ) - { - float diff = FlYawDiff(); - float target = 0; - - if ( m_IdealActivity != GetStoppedActivity() ) - { - if ( diff < -20 ) - target = 20; - else if ( diff > 20 ) - target = -20; - } - pev->angles.z = UTIL_Approach( target, pev->angles.z, 220.0 * 0.1 ); - } - return CFlyingMonster::ChangeYaw( speed ); -} - - -Activity CArcher:: GetStoppedActivity( void ) -{ - if ( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else - return ACT_IDLE; - return ACT_WALK; -} - -void CArcher::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) -{ - m_SaveVelocity = vecDir * m_flightSpeed; -} - - -void CArcher::MonsterThink ( void ) -{ - CFlyingMonster::MonsterThink( ); - - if (pev->deadflag == DEAD_NO) - { - if (m_MonsterState != MONSTERSTATE_SCRIPT) - { - Swim( ); - - // blink the eye - if (m_flBlink < gpGlobals->time) - { - pev->skin = EYE_CLOSED; - if (m_flBlink + 0.2 < gpGlobals->time) - { - m_flBlink = gpGlobals->time + RANDOM_FLOAT( 3, 4 ); - if (m_bOnAttack) - pev->skin = EYE_MAD; - else - pev->skin = EYE_BASE; - } - } + Swim(); } } } -void CArcher :: Stop( void ) +void CArcher::Stop( void ) { - if (!m_bOnAttack) - m_flightSpeed = 80.0; + if( !m_bOnAttack ) + m_flightSpeed = 40.0; } -void CArcher::Swim( ) +void CArcher::Swim() { - int retValue = 0; + //int retValue = 0; Vector start = pev->origin; Vector Angles; Vector Forward, Right, Up; - if (FBitSet( pev->flags, FL_ONGROUND)) + if( FBitSet( pev->flags, FL_ONGROUND ) ) { pev->angles.x = 0; pev->angles.y += RANDOM_FLOAT( -45, 45 ); ClearBits( pev->flags, FL_ONGROUND ); Angles = Vector( -pev->angles.x, pev->angles.y, pev->angles.z ); - UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); + UTIL_MakeVectorsPrivate( Angles, Forward, Right, Up ); pev->velocity = Forward * 200 + Up * 200; return; } - if (m_bOnAttack && m_flightSpeed < m_flMaxSpeed) + if( m_bOnAttack && m_flightSpeed < m_flMaxSpeed ) { m_flightSpeed += 40; } - if (m_flightSpeed < 180) + if( m_flightSpeed < 90 ) { - if (m_IdealActivity == ACT_RUN) + if( m_IdealActivity == ACT_RUN ) SetActivity( ACT_WALK ); - if (m_IdealActivity == ACT_WALK) + if( m_IdealActivity == ACT_WALK ) pev->framerate = m_flightSpeed / 150.0; // ALERT( at_console, "walk %.2f\n", pev->framerate ); } else { - if (m_IdealActivity == ACT_WALK) + if( m_IdealActivity == ACT_WALK ) SetActivity( ACT_RUN ); - if (m_IdealActivity == ACT_RUN) - pev->framerate = m_flightSpeed / 150.0; + if( m_IdealActivity == ACT_RUN) + pev->framerate = m_flightSpeed / 75.0; // ALERT( at_console, "run %.2f\n", pev->framerate ); } - /* - if (!m_pBeam) + if( !m_pBeam ) { m_pBeam = CBeam::BeamCreate( "sprites/laserbeam.spr", 80 ); - m_pBeam->PointEntInit( pev->origin + m_SaveVelocity, entindex( ) ); + m_pBeam->PointEntInit( pev->origin + m_SaveVelocity, entindex() ); m_pBeam->SetEndAttachment( 1 ); m_pBeam->SetColor( 255, 180, 96 ); m_pBeam->SetBrightness( 192 ); @@ -938,66 +415,65 @@ void CArcher::Swim( ) #define PROBE_LENGTH 150 Angles = UTIL_VecToAngles( m_SaveVelocity ); Angles.x = -Angles.x; - UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); + UTIL_MakeVectorsPrivate( Angles, Forward, Right, Up ); Vector f, u, l, r, d; - f = DoProbe(start + PROBE_LENGTH * Forward); - r = DoProbe(start + PROBE_LENGTH/3 * Forward+Right); - l = DoProbe(start + PROBE_LENGTH/3 * Forward-Right); - u = DoProbe(start + PROBE_LENGTH/3 * Forward+Up); - d = DoProbe(start + PROBE_LENGTH/3 * Forward-Up); + f = DoProbe( start + PROBE_LENGTH * Forward ); + r = DoProbe( start + PROBE_LENGTH / 3 * Forward + Right ); + l = DoProbe( start + PROBE_LENGTH / 3 * Forward - Right ); + u = DoProbe( start + PROBE_LENGTH / 3 * Forward + Up ); + d = DoProbe( start + PROBE_LENGTH / 3 * Forward - Up ); - Vector SteeringVector = f+r+l+u+d; - m_SaveVelocity = (m_SaveVelocity + SteeringVector/2).Normalize(); + Vector SteeringVector = f + r + l + u + d; + m_SaveVelocity = ( m_SaveVelocity + SteeringVector / 2 ).Normalize(); Angles = Vector( -pev->angles.x, pev->angles.y, pev->angles.z ); - UTIL_MakeVectorsPrivate(Angles, Forward, Right, Up); + UTIL_MakeVectorsPrivate( Angles, Forward, Right, Up ); // ALERT( at_console, "%f : %f\n", Angles.x, Forward.z ); float flDot = DotProduct( Forward, m_SaveVelocity ); - if (flDot > 0.5) + if( flDot > 0.5 ) pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed; - else if (flDot > 0) - pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed * (flDot + 0.5); + else if( flDot > 0 ) + pev->velocity = m_SaveVelocity = m_SaveVelocity * m_flightSpeed * ( flDot + 0.5 ); else - pev->velocity = m_SaveVelocity = m_SaveVelocity * 80; + pev->velocity = m_SaveVelocity = m_SaveVelocity * 40; // ALERT( at_console, "%.0f %.0f\n", m_flightSpeed, pev->velocity.Length() ); - // ALERT( at_console, "Steer %f %f %f\n", SteeringVector.x, SteeringVector.y, SteeringVector.z ); - /* m_pBeam->SetStartPos( pev->origin + pev->velocity ); - m_pBeam->RelinkBeam( ); + m_pBeam->RelinkBeam(); */ - // ALERT( at_console, "speed %f\n", m_flightSpeed ); - + Angles = UTIL_VecToAngles( m_SaveVelocity ); // Smooth Pitch // - if (Angles.x > 180) + if( Angles.x > 180 ) Angles.x = Angles.x - 360; - pev->angles.x = UTIL_Approach(Angles.x, pev->angles.x, 50 * 0.1 ); - if (pev->angles.x < -80) pev->angles.x = -80; - if (pev->angles.x > 80) pev->angles.x = 80; + pev->angles.x = UTIL_Approach( Angles.x, pev->angles.x, 50 * 0.1 ); + if( pev->angles.x < -180 ) + pev->angles.x = -180; + if( pev->angles.x > 180 ) + pev->angles.x = 180; // Smooth Yaw and generate Roll // float turn = 360; // ALERT( at_console, "Y %.0f %.0f\n", Angles.y, pev->angles.y ); - if (fabs(Angles.y - pev->angles.y) < fabs(turn)) + if( fabs( Angles.y - pev->angles.y ) < fabs( turn ) ) { turn = Angles.y - pev->angles.y; } - if (fabs(Angles.y - pev->angles.y + 360) < fabs(turn)) + if( fabs( Angles.y - pev->angles.y + 360 ) < fabs( turn ) ) { turn = Angles.y - pev->angles.y + 360; } - if (fabs(Angles.y - pev->angles.y - 360) < fabs(turn)) + if( fabs( Angles.y - pev->angles.y - 360 ) < fabs( turn ) ) { turn = Angles.y - pev->angles.y - 360; } @@ -1005,9 +481,9 @@ void CArcher::Swim( ) float speed = m_flightSpeed * 0.1; // ALERT( at_console, "speed %.0f %f\n", turn, speed ); - if (fabs(turn) > speed) + if( fabs( turn ) > speed ) { - if (turn < 0.0) + if( turn < 0.0 ) { turn = -speed; } @@ -1018,7 +494,7 @@ void CArcher::Swim( ) } pev->angles.y += turn; pev->angles.z -= turn; - pev->angles.y = fmod((pev->angles.y + 360.0), 360.0); + pev->angles.y = fmod( ( pev->angles.y + 360.0 ), 360.0 ); static float yaw_adj; @@ -1031,26 +507,27 @@ void CArcher::Swim( ) // Roll Smoothing // turn = 360; - if (fabs(Angles.z - pev->angles.z) < fabs(turn)) + if( fabs( Angles.z - pev->angles.z ) < fabs( turn ) ) { turn = Angles.z - pev->angles.z; } - if (fabs(Angles.z - pev->angles.z + 360) < fabs(turn)) + if( fabs( Angles.z - pev->angles.z + 360 ) < fabs( turn ) ) { turn = Angles.z - pev->angles.z + 360; } - if (fabs(Angles.z - pev->angles.z - 360) < fabs(turn)) + if( fabs( Angles.z - pev->angles.z - 360 ) < fabs( turn ) ) { turn = Angles.z - pev->angles.z - 360; } - speed = m_flightSpeed/2 * 0.1; - if (fabs(turn) < speed) + speed = m_flightSpeed / 2 * 0.1; + + if( fabs( turn ) < speed ) { pev->angles.z += turn; } else { - if (turn < 0.0) + if( turn < 0.0 ) { pev->angles.z -= speed; } @@ -1059,52 +536,14 @@ void CArcher::Swim( ) pev->angles.z += speed; } } - if (pev->angles.z < -20) pev->angles.z = -20; - if (pev->angles.z > 20) pev->angles.z = 20; - UTIL_MakeVectorsPrivate( Vector( -Angles.x, Angles.y, Angles.z ), Forward, Right, Up); + if( pev->angles.z < -20 ) + pev->angles.z = -20; + if( pev->angles.z > 20 ) + pev->angles.z = 20; - // UTIL_MoveToOrigin ( ENT(pev), pev->origin + Forward * speed, speed, MOVE_STRAFE ); + UTIL_MakeVectorsPrivate( Vector( -Angles.x, Angles.y, Angles.z ), Forward, Right, Up ); + + // UTIL_MoveToOrigin ( ENT( pev ), pev->origin + Forward * speed, speed, MOVE_STRAFE ); } - - -Vector CArcher::DoProbe(const Vector &Probe) -{ - Vector WallNormal = Vector(0,0,-1); // WATER normal is Straight Down for fish. - float frac; - BOOL bBumpedSomething = ProbeZ(pev->origin, Probe, &frac); - - TraceResult tr; - TRACE_MONSTER_HULL(edict(), pev->origin, Probe, dont_ignore_monsters, edict(), &tr); - if ( tr.fAllSolid || tr.flFraction < 0.99 ) - { - if (tr.flFraction < 0.0) tr.flFraction = 0.0; - if (tr.flFraction > 1.0) tr.flFraction = 1.0; - if (tr.flFraction < frac) - { - frac = tr.flFraction; - bBumpedSomething = TRUE; - WallNormal = tr.vecPlaneNormal; - } - } - - if (bBumpedSomething && (m_hEnemy == NULL || tr.pHit != m_hEnemy->edict())) - { - Vector ProbeDir = Probe - pev->origin; - - Vector NormalToProbeAndWallNormal = CrossProduct(ProbeDir, WallNormal); - Vector SteeringVector = CrossProduct( NormalToProbeAndWallNormal, ProbeDir); - - float SteeringForce = m_flightSpeed * (1-frac) * (DotProduct(WallNormal.Normalize(), m_SaveVelocity.Normalize())); - if (SteeringForce < 0.0) - { - SteeringForce = -SteeringForce; - } - SteeringVector = SteeringForce * SteeringVector.Normalize(); - - return SteeringVector; - } - return Vector(0, 0, 0); -} - #endif diff --git a/dlls/asheep/barneyglock.cpp b/dlls/asheep/barneyglock.cpp new file mode 100644 index 00000000..f9d13312 --- /dev/null +++ b/dlls/asheep/barneyglock.cpp @@ -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 ); +} diff --git a/dlls/asheep/barneyhg.cpp b/dlls/asheep/barneyhg.cpp new file mode 100644 index 00000000..f375658a --- /dev/null +++ b/dlls/asheep/barneyhg.cpp @@ -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" ); +} diff --git a/dlls/asheep/barneymp5.cpp b/dlls/asheep/barneymp5.cpp new file mode 100644 index 00000000..8ac84d3c --- /dev/null +++ b/dlls/asheep/barneymp5.cpp @@ -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" ); +} diff --git a/dlls/asheep/barneyshotgun.cpp b/dlls/asheep/barneyshotgun.cpp new file mode 100644 index 00000000..f70b9e67 --- /dev/null +++ b/dlls/asheep/barneyshotgun.cpp @@ -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" ); +} diff --git a/dlls/asheep/barniel.cpp b/dlls/asheep/barniel.cpp index 42572cf2..052b06c0 100644 --- a/dlls/asheep/barniel.cpp +++ b/dlls/asheep/barniel.cpp @@ -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 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 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); - // Override these to set behavior - Schedule_t *GetScheduleOfType ( int Type ); - Schedule_t *GetSchedule ( void ); - MONSTERSTATE GetIdealState ( void ); + void DeclineFollowing( void ); - void DeathSound( void ); - void PainSound( void ); - - void TalkInit( void ); + // Override these to set behavior + Schedule_t *GetSchedule( 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[]; + void DeathSound( void ); + void PainSound( void ); - BOOL m_fGunDrawn; - float m_painTime; - float m_checkAttackTime; - BOOL m_lastAttackCheck; + void TalkInit( void ); - // 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"); - - // every new barniel must call this, otherwise + PRECACHE_SOUND( "barniel/bn_die1.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(); 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_WOUND] = "BN_WOUND"; - m_szGrp[TLK_MORTAL] = "BN_MORTAL"; + m_szGrp[TLK_SMELL] = "BN_SMELL"; - // get voice for head - just one barniel voice for now + m_szGrp[TLK_WOUND] = "BN_WOUND"; + m_szGrp[TLK_MORTAL] = "BN_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); + 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); + 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()); - + 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(); -} - - diff --git a/dlls/asheep/beretta.cpp b/dlls/asheep/beretta.cpp index 02291377..45b02f11 100644 --- a/dlls/asheep/beretta.cpp +++ b/dlls/asheep/beretta.cpp @@ -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 ); diff --git a/dlls/asheep/bodypart.cpp b/dlls/asheep/bodypart.cpp new file mode 100644 index 00000000..cf5994f2 --- /dev/null +++ b/dlls/asheep/bodypart.cpp @@ -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 ) ); +} diff --git a/dlls/asheep/garbage.cpp b/dlls/asheep/garbage.cpp new file mode 100644 index 00000000..bf4aab2c --- /dev/null +++ b/dlls/asheep/garbage.cpp @@ -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 ) ); +} diff --git a/dlls/asheep/gordon.cpp b/dlls/asheep/gordon.cpp deleted file mode 100644 index 9ae9b7b2..00000000 --- a/dlls/asheep/gordon.cpp +++ /dev/null @@ -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(); -} - - diff --git a/dlls/asheep/gordonnadrian.cpp b/dlls/asheep/gordonnadrian.cpp new file mode 100644 index 00000000..53817781 --- /dev/null +++ b/dlls/asheep/gordonnadrian.cpp @@ -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 ); +} diff --git a/dlls/asheep/hevbarn.cpp b/dlls/asheep/hevbarn.cpp deleted file mode 100644 index a15bf8f7..00000000 --- a/dlls/asheep/hevbarn.cpp +++ /dev/null @@ -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(); -} diff --git a/dlls/asheep/kate.cpp b/dlls/asheep/kate.cpp index 8aa23479..9217f60e 100644 --- a/dlls/asheep/kate.cpp +++ b/dlls/asheep/kate.cpp @@ -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,125 @@ #include "scripted.h" #include "weapons.h" #include "soundent.h" +#include "barney.h" +#include "animation.h" + +#define KATE_LIMP_HEALTH 40 //========================================================= // Monster's Anim Events Go Here //========================================================= -// first flag is kate dying for scripted sequences? -#define KATE_AE_DRAW ( 2 ) -#define KATE_AE_SHOOT ( 3 ) -#define KATE_AE_HOLSTER ( 4 ) +// first flag is barney dying for scripted sequences? -#define KATE_BODY_GUNHOLSTERED 0 -#define KATE_BODY_GUNDRAWN 1 -#define KATE_BODY_GUNGONE 2 - -class CKate : public CTalkMonster +class CKate : public CBarney { public: - void Spawn( void ); - void Precache( void ); - void SetYawSpeed( void ); - int ISoundMask( void ); - void KateFirePistol( 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 ); + 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* CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ); + int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType); + void SetActivity( Activity NewActivity ); - // Override these to set behavior - Schedule_t *GetScheduleOfType ( int Type ); - Schedule_t *GetSchedule ( void ); - MONSTERSTATE GetIdealState ( void ); + void DeclineFollowing( void ); - void DeathSound( void ); - void PainSound( void ); - - void TalkInit( void ); + // Override these to set behavior + Schedule_t *GetSchedule( 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[]; + void DeathSound( void ); + void PainSound( void ); - BOOL m_fGunDrawn; - float m_painTime; - float m_checkAttackTime; - BOOL m_lastAttackCheck; + void TalkInit( void ); - // 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_kate, CKate ); +LINK_ENTITY_TO_CLASS( monster_kate, CKate ) -TYPEDESCRIPTION CKate::m_SaveData[] = -{ - DEFINE_FIELD( CKate, m_fGunDrawn, FIELD_BOOLEAN ), - DEFINE_FIELD( CKate, m_painTime, FIELD_TIME ), - DEFINE_FIELD( CKate, m_checkAttackTime, FIELD_TIME ), - DEFINE_FIELD( CKate, m_lastAttackCheck, FIELD_BOOLEAN ), - DEFINE_FIELD( CKate, m_flPlayerDamage, FIELD_FLOAT ), -}; - -IMPLEMENT_SAVERESTORE( CKate, 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 tlKtFollow[] = -{ - { TASK_MOVE_TO_TARGET_RANGE,(float)128 }, // Move within 128 of target ent (client) - { TASK_SET_SCHEDULE, (float)SCHED_TARGET_FACE }, -}; - -Schedule_t slKtFollow[] = +void CKate::AlertSound( void ) { + if( m_hEnemy != 0 ) { - tlKtFollow, - ARRAYSIZE ( tlKtFollow ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_PROVOKED, - bits_SOUND_DANGER, - "Follow" - }, -}; - -//========================================================= -// KateDraw- much better looking draw schedule for when -// kate knows who he's gonna attack. -//========================================================= -Task_t tlKateEnemyDraw[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, 0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float) ACT_ARM }, -}; - -Schedule_t slKateEnemyDraw[] = -{ - { - tlKateEnemyDraw, - ARRAYSIZE ( tlKateEnemyDraw ), - 0, - 0, - "Kate Enemy Draw" - } -}; - -Task_t tlKtFaceTarget[] = -{ - { 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 slKtFaceTarget[] = -{ - { - tlKtFaceTarget, - ARRAYSIZE ( tlKtFaceTarget ), - 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 tlIdleKtStand[] = -{ - { 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 slIdleKtStand[] = -{ - { - tlIdleKtStand, - ARRAYSIZE ( tlIdleKtStand ), - 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( CKate ) -{ - slKtFollow, - slKateEnemyDraw, - slKtFaceTarget, - slIdleKtStand, -}; - - -IMPLEMENT_CUSTOM_SCHEDULES( CKate, CTalkMonster ); - -void CKate :: StartTask( Task_t *pTask ) -{ - CTalkMonster::StartTask( pTask ); -} - -void CKate :: 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 CKate :: 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 CKate :: Classify ( void ) -{ - return CLASS_PLAYER_ALLY; -} - -//========================================================= -// ALertSound - kate says "Freeze!" -//========================================================= -void CKate :: AlertSound( void ) -{ - if ( m_hEnemy != NULL ) - { - if ( FOkToSpeak() ) - { - PlaySentence( "KA_ATTACK", RANDOM_FLOAT(2.8, 3.2), VOL_NORM, ATTN_IDLE ); + PlaySentence( "KA_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 CKate :: SetYawSpeed ( void ) + +int CKate::IRelationship( CBaseEntity *pTarget ) { - 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; + if( FClassnameIs( pTarget->pev, "monster_archer" ) || FClassnameIs( pTarget->pev, "monster_ichthyosaur" ) ) + { + return R_NO; + } + + return CTalkMonster::IRelationship( pTarget ); } - -//========================================================= -// CheckRangeAttack1 -//========================================================= -BOOL CKate :: CheckRangeAttack1 ( float flDot, float flDist ) +CBaseEntity* CKate::CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ) { - 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; + 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 CKate::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; +} //========================================================= -// KateFirePistol - shoots one round from the pistol at -// the enemy kate is facing. +// BarneyFirePistol - shoots one round from the pistol at +// the enemy barney is facing. //========================================================= -void CKate :: KateFirePistol ( void ) +void CKate::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 +153,196 @@ void CKate :: KateFirePistol ( 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, "kate/ka_attack2.wav", 1, ATTN_NORM, 0, 100 + pitchShift ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_WEAPON, "kate/ka_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 CKate :: HandleAnimEvent( MonsterEvent_t *pEvent ) +void CKate::HandleAnimEvent( MonsterEvent_t *pEvent ) { + CBaseEntity *pHurt; + switch( pEvent->event ) { - case KATE_AE_SHOOT: - KateFirePistol(); - break; + case BARNEY_AE_KICK: + pHurt = CheckTraceHullAttack( 70, 0, DMG_GENERIC ); + if( pHurt ) + { + const char *pszSound; + if( m_iCombatState == -1 ) + { + pszSound = "common/kick.wav"; + } + else + { + ++m_iCombatState; + if( m_iCombatState == 3 ) + pszSound = "common/kick.wav"; + else + pszSound = "common/punch.wav"; + } + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, pszSound, 1, ATTN_NORM, 0, PITCH_NORM ); + UTIL_MakeVectors( pev->angles ); - case KATE_AE_DRAW: - // kate's bodygroup switches here so he can pull gun from holster - pev->body = KATE_BODY_GUNDRAWN; - m_fGunDrawn = TRUE; + 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; - - case KATE_AE_HOLSTER: - // change bodygroup to replace gun in holster - pev->body = KATE_BODY_GUNHOLSTERED; - m_fGunDrawn = FALSE; - break; - default: - CTalkMonster::HandleAnimEvent( pEvent ); + CBarney::HandleAnimEvent( pEvent ); + break; } } //========================================================= // Spawn //========================================================= -void CKate :: Spawn() +void CKate::Spawn() { - Precache( ); + Precache(); + SET_MODEL( ENT( pev ), "models/kate.mdl" ); + UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX ); - SET_MODEL(ENT(pev), "models/kate.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.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->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; - 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( &CKate::FollowerUse ); + SetUse( &CTalkMonster::FollowerUse ); } //========================================================= // Precache - precaches all resources this monster needs //========================================================= -void CKate :: Precache() +void CKate::Precache() { - PRECACHE_MODEL("models/kate.mdl"); + PRECACHE_MODEL( "models/kate.mdl" ); - PRECACHE_SOUND("kate/ka_attack1.wav" ); - PRECACHE_SOUND("kate/ka_attack2.wav" ); + PRECACHE_SOUND( "kate/ka_attack1.wav" ); + PRECACHE_SOUND( "kate/ka_attack2.wav" ); - PRECACHE_SOUND("kate/ka_pain1.wav"); - PRECACHE_SOUND("kate/ka_pain2.wav"); -// PRECACHE_SOUND("kate/ka_pain3.wav"); + PRECACHE_SOUND( "kate/ka_pain1.wav" ); + PRECACHE_SOUND( "kate/ka_pain2.wav" ); + //PRECACHE_SOUND( "kate/ka_pain3.wav" ); - PRECACHE_SOUND("kate/ka_die1.wav"); -// PRECACHE_SOUND("kate/ka_die2.wav"); -// PRECACHE_SOUND("kate/ka_die3.wav"); - - // every new kate must call this, otherwise + PRECACHE_SOUND( "kate/ka_die1.wav" ); + //PRECACHE_SOUND( "kate/ka_die2.wav" ); + //PRECACHE_SOUND( "kate/ka_die3.wav" ); + + PRECACHE_SOUND( "weapons/reload3.wav" ); + + PRECACHE_SOUND( "zombie/claw_miss1.wav" ); + PRECACHE_SOUND( "zombie/claw_miss2.wav" ); + PRECACHE_SOUND( "common/kick.wav" ); + PRECACHE_SOUND( "common/punch.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 CKate :: TalkInit() +void CKate::TalkInit() { - CTalkMonster::TalkInit(); // scientists speach group names (group names are in sentences.txt) - - m_szGrp[TLK_ANSWER] = "KA_ANSWER"; + m_szGrp[TLK_ANSWER] = "KA_ANSWER"; m_szGrp[TLK_QUESTION] = "KA_QUESTION"; - m_szGrp[TLK_IDLE] = "KA_IDLE"; - m_szGrp[TLK_STARE] = "KA_STARE"; - m_szGrp[TLK_USE] = "KA_OK"; - m_szGrp[TLK_UNUSE] = "KA_WAIT"; - m_szGrp[TLK_STOP] = "KA_STOP"; + m_szGrp[TLK_IDLE] = "KA_IDLE"; + m_szGrp[TLK_STARE] = "KA_STARE"; + m_szGrp[TLK_USE] = "KA_OK"; + m_szGrp[TLK_UNUSE] = "KA_WAIT"; + m_szGrp[TLK_STOP] = "KA_STOP"; - m_szGrp[TLK_NOSHOOT] = "KA_SCARED"; - m_szGrp[TLK_HELLO] = "KA_HELLO"; + m_szGrp[TLK_NOSHOOT] = "KA_SCARED"; + m_szGrp[TLK_HELLO] = "KA_HELLO"; - m_szGrp[TLK_PLHURT1] = "!KA_CUREA"; - m_szGrp[TLK_PLHURT2] = "!KA_CUREB"; - m_szGrp[TLK_PLHURT3] = "!KA_CUREC"; + m_szGrp[TLK_PLHURT1] = "!KA_CUREA"; + m_szGrp[TLK_PLHURT2] = "!KA_CUREB"; + m_szGrp[TLK_PLHURT3] = "!KA_CUREC"; - m_szGrp[TLK_PHELLO] = NULL; //"KA_PHELLO"; // UNDONE - m_szGrp[TLK_PIDLE] = NULL; //"KA_PIDLE"; // UNDONE + m_szGrp[TLK_PHELLO] = NULL; //"KA_PHELLO"; // UNDONE + m_szGrp[TLK_PIDLE] = NULL; //"KA_PIDLE"; // UNDONE m_szGrp[TLK_PQUESTION] = "KA_PQUEST"; // UNDONE - m_szGrp[TLK_SMELL] = "KA_SMELL"; - - m_szGrp[TLK_WOUND] = "KA_WOUND"; - m_szGrp[TLK_MORTAL] = "KA_MORTAL"; + m_szGrp[TLK_SMELL] = "KA_SMELL"; - // get voice for head - just one kate voice for now - m_voicePitch = 100; + m_szGrp[TLK_WOUND] = "KA_WOUND"; + m_szGrp[TLK_MORTAL] = "KA_MORTAL"; + + // get voice for head - just one barney voice for now + m_voicePitch = 98; } - 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 CKate :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) +int CKate::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( "KA_MAD", 4, VOL_NORM, ATTN_NORM ); @@ -537,7 +357,7 @@ int CKate :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float Remember( bits_MEMORY_SUSPICIOUS ); } } - else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO ) + else if( !( m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO ) { PlaySentence( "KA_SHOT", 4, VOL_NORM, ATTN_NORM ); } @@ -546,135 +366,96 @@ int CKate :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float return ret; } - //========================================================= // PainSound //========================================================= -void CKate :: PainSound ( void ) +void CKate::PainSound( void ) { - if (gpGlobals->time < m_painTime) + if( gpGlobals->time < m_painTime ) return; - - m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75); - //switch (RANDOM_LONG(0,2)) -// { - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "kate/ka_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); -// case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "kate/ka_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; -// case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "kate/ka_pain3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; -// } + m_painTime = gpGlobals->time + RANDOM_FLOAT( 0.5, 0.75 ); + + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, RANDOM_LONG( 0, 1 ) ? "kate/ka_pain1.wav" : "kate/ka_pain2.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); } //========================================================= // DeathSound //========================================================= -void CKate :: DeathSound ( void ) +void CKate::DeathSound( void ) { - //switch (RANDOM_LONG(0,2)) - //{ - //case 0: - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "kate/ka_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); //break;//edit Alex, only 1 sound - //case 1: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "kate/ka_die2.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - //case 2: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "kate/ka_die3.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; - //} -} - - -void CKate::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 CKate::Killed( entvars_t *pevAttacker, int iGib ) -{ - if ( pev->body < KATE_BODY_GUNGONE ) - {// drop the gun! - Vector vecGunPos; - Vector vecGunAngles; - - pev->body = KATE_BODY_GUNGONE; - - GetAttachment( 0, vecGunPos, vecGunAngles ); - - CBaseEntity *pGun = DropItem( "weapon_barney9mmhg", vecGunPos, vecGunAngles ); - } - - SetUse( NULL ); - CTalkMonster::Killed( pevAttacker, iGib ); + EMIT_SOUND_DYN( ENT( pev ), CHAN_VOICE, "kate/ka_die1.wav", 1, ATTN_NORM, 0, GetVoicePitch() ); } //========================================================= -// AI Schedules Specific to this monster +// SetActivity //========================================================= - -Schedule_t* CKate :: GetScheduleOfType ( int Type ) +void CKate::SetActivity( Activity NewActivity ) { - Schedule_t *psched; + int iSequence = ACTIVITY_NOT_AVAILABLE; + //void *pmodel = GET_MODEL_PTR( ENT( pev ) ); - switch( Type ) + switch( NewActivity ) { - case SCHED_ARM_WEAPON: - if ( m_hEnemy != NULL ) + case ACT_RUN: + if( pev->health <= KATE_LIMP_HEALTH ) { - // face enemy, then draw. - return slKateEnemyDraw; + // limp! + iSequence = LookupActivity( ACT_RUN_HURT ); + } + else + { + iSequence = LookupActivity( NewActivity ); } break; - - // Hook these to make a looping schedule - case SCHED_TARGET_FACE: - // call base class default so that kate will talk - // when 'used' - psched = CTalkMonster::GetScheduleOfType(Type); - - if (psched == slIdleStand) - return slKtFaceTarget; // override this for different target face behavior - else - return psched; - - case SCHED_TARGET_CHASE: - return slKtFollow; - - case SCHED_IDLE_STAND: - // call base class default so that scientist will talk - // when standing during idle - psched = CTalkMonster::GetScheduleOfType(Type); - - if (psched == slIdleStand) + case ACT_WALK: + if( pev->health <= KATE_LIMP_HEALTH ) { - // just look straight ahead. - return slIdleKtStand; + // limp! + iSequence = LookupActivity( ACT_WALK_HURT ); } else - return psched; + { + iSequence = LookupActivity( NewActivity ); + } + break; + case ACT_MELEE_ATTACK1: + if( RANDOM_LONG( 0, 2 ) ) + { + m_iCombatState = -1; + iSequence = LookupSequence( "karate_hit" ); + } + else + { + m_iCombatState = 0; + iSequence = LookupSequence( "karate_bighit" ); + } + break; + default: + iSequence = LookupActivity( NewActivity ); + break; } - return CTalkMonster::GetScheduleOfType( Type ); + m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present + + // Set to the desired anim, or default anim if the desired is not present + if( iSequence > ACTIVITY_NOT_AVAILABLE ) + { + if( pev->sequence != iSequence || !m_fSequenceLoops ) + { + pev->frame = 0; + } + + pev->sequence = iSequence; // Set to the reset anim (if it's there) + ResetSequenceInfo(); + SetYawSpeed(); + } + else + { + // Not available try to get default anim + ALERT( at_console, "%s has no sequence for act:%d\n", STRING( pev->classname ), NewActivity ); + pev->sequence = 0; // Set to the reset anim (if it's there) + } } //========================================================= @@ -683,18 +464,18 @@ Schedule_t* CKate :: GetScheduleOfType ( int Type ) // monster's member function to get a pointer to a schedule // of the proper type. //========================================================= -Schedule_t *CKate :: GetSchedule ( void ) +Schedule_t *CKate::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( "KA_KILL", 4, VOL_NORM, ATTN_NORM ); } @@ -703,37 +484,42 @@ Schedule_t *CKate :: 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_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)) + 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 ); @@ -741,7 +527,7 @@ Schedule_t *CKate :: GetSchedule ( void ) } else { - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) + if( HasConditions( bits_COND_CLIENT_PUSH ) ) { return GetScheduleOfType( SCHED_MOVE_AWAY_FOLLOW ); } @@ -749,7 +535,7 @@ Schedule_t *CKate :: GetSchedule ( void ) } } - if ( HasConditions( bits_COND_CLIENT_PUSH ) ) + if( HasConditions( bits_COND_CLIENT_PUSH ) ) { return GetScheduleOfType( SCHED_MOVE_AWAY ); } @@ -757,86 +543,14 @@ Schedule_t *CKate :: GetSchedule ( void ) // try to say something about smells TrySmellTalk(); break; + default: + break; } - + return CTalkMonster::GetSchedule(); } -MONSTERSTATE CKate :: GetIdealState ( void ) -{ - return CTalkMonster::GetIdealState(); -} - - - void CKate::DeclineFollowing( void ) { PlaySentence( "KA_POK", 2, VOL_NORM, ATTN_NORM ); } - - - - - -//========================================================= -// DEAD KATE 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 CDeadKate : 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 *CDeadKate::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" }; - -void CDeadKate::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_kate_dead, CDeadKate ); - -//========================================================= -// ********** DeadKate SPAWN ********** -//========================================================= -void CDeadKate :: Spawn( ) -{ - PRECACHE_MODEL("models/kate.mdl"); - SET_MODEL(ENT(pev), "models/kate.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 kate with bad pose\n" ); - } - // Corpses have less health - pev->health = 8;//gSkillData.kateHealth; - - MonsterInitDead(); -} - - diff --git a/dlls/asheep/kmedkit.cpp b/dlls/asheep/kmedkit.cpp new file mode 100644 index 00000000..669af060 --- /dev/null +++ b/dlls/asheep/kmedkit.cpp @@ -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 ); + } +} diff --git a/dlls/asheep/m41a.cpp b/dlls/asheep/m41a.cpp index cd81b1c3..52350e21 100644 --- a/dlls/asheep/m41a.cpp +++ b/dlls/asheep/m41a.cpp @@ -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; +} diff --git a/dlls/asheep/panther.cpp b/dlls/asheep/panther.cpp new file mode 100644 index 00000000..06c6d30f --- /dev/null +++ b/dlls/asheep/panther.cpp @@ -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" ); +} diff --git a/dlls/asheep/poolstick.cpp b/dlls/asheep/poolstick.cpp index 40d0c4a3..b2762856 100644 --- a/dlls/asheep/poolstick.cpp +++ b/dlls/asheep/poolstick.cpp @@ -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,31 +191,40 @@ 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 ); } } 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 ); + } +} diff --git a/dlls/asheep/spforce.cpp b/dlls/asheep/spforce.cpp index d1733c43..677d6445 100644 --- a/dlls/asheep/spforce.cpp +++ b/dlls/asheep/spforce.cpp @@ -41,6 +41,7 @@ #include "soundent.h" #include "effects.h" #include "customentity.h" +#include "hgrunt.h" int g_fSPForceQuestion; // true if an idle SPForce asked a question. Cleared when someone answers. @@ -61,19 +62,17 @@ extern DLL_GLOBAL int g_iSkillLevel; #define SPFORCE_M41A ( 1 << 0) #define SPFORCE_HANDGRENADE ( 1 << 1) #define SPFORCE_GRENADELAUNCHER ( 1 << 2) -#define SPFORCE_SHOTGUN ( 1 << 3) -#define SPFORCE_BERETTA ( 1 << 4) +#define SPFORCE_BERETTA ( 1 << 3) #define HEAD_GROUP 1 #define HEAD_SPForce 0 #define HEAD_COMMANDER 1 -#define HEAD_SHOTGUN 2 +#define HEAD_BERETTA 2 #define HEAD_M203 3 -#define GUN_GROUP 3 +#define GUN_GROUP 2 #define GUN_M41A 0 -#define GUN_SHOTGUN 1 -#define GUN_BERETTA 2 -#define GUN_NONE 3 +#define GUN_BERETTA 1 +#define GUN_NONE 2 //========================================================= // Monster's Anim Events Go Here @@ -122,143 +121,23 @@ enum //========================================================= #define bits_COND_SPFORCE_NOFIRE ( bits_COND_SPECIAL1 ) -class CSPForce : public CSquadMonster +class CSPForce : public CHGrunt { 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 Beretta ( 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 *pSPForceSentences[]; }; LINK_ENTITY_TO_CLASS( monster_human_spforce, CSPForce ); -TYPEDESCRIPTION CSPForce::m_SaveData[] = -{ - DEFINE_FIELD( CSPForce, m_flNextGrenadeCheck, FIELD_TIME ), - DEFINE_FIELD( CSPForce, m_flNextPainTime, FIELD_TIME ), -// DEFINE_FIELD( CSPForce, m_flLastEnemySightTime, FIELD_TIME ), // don't save, go to zero - DEFINE_FIELD( CSPForce, m_vecTossVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CSPForce, m_fThrowGrenade, FIELD_BOOLEAN ), - DEFINE_FIELD( CSPForce, m_fStanding, FIELD_BOOLEAN ), - DEFINE_FIELD( CSPForce, m_fFirstEncounter, FIELD_BOOLEAN ), - DEFINE_FIELD( CSPForce, m_cClipSize, FIELD_INTEGER ), - DEFINE_FIELD( CSPForce, m_voicePitch, FIELD_INTEGER ), -// DEFINE_FIELD( CShotgun, m_iBrassShell, FIELD_INTEGER ), -// DEFINE_FIELD( CShotgun, m_iShotgunShell, FIELD_INTEGER ), - DEFINE_FIELD( CSPForce, m_iSentence, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CSPForce, CSquadMonster ); - -const char *CSPForce::pSPForceSentences[] = -{ - "HG_GREN", // grenade scared SPForce - "HG_ALERT", // sees player - "HG_MONSTER", // sees monster - "HG_COVER", // running to cover - "HG_THROW", // about to throw grenade - "HG_CHARGE", // running out to get the enemy - "HG_TAUNT", // say rude things -}; - -enum -{ - SPFORCE_SENT_NONE = -1, - SPFORCE_SENT_GREN = 0, - SPFORCE_SENT_ALERT, - SPFORCE_SENT_MONSTER, - SPFORCE_SENT_COVER, - SPFORCE_SENT_THROW, - SPFORCE_SENT_CHARGE, - SPFORCE_SENT_TAUNT, -} SPFORCE_SENTENCE_TYPES; - -//========================================================= -// Speak Sentence - say your cued up sentence. -// -// Some SPForce sentences (take cover and charge) rely on actually -// being able to execute the intended action. It's really lame -// when a SPForce says 'COVER ME' and then doesn't move. The problem -// is that the sentences were played when the decision to TRY -// to move to cover was made. Now the sentence is played after -// we know for sure that there is a valid path. The schedule -// may still fail but in most cases, well after the SPForce has -// started moving. -//========================================================= -void CSPForce :: SpeakSentence( void ) -{ - if ( m_iSentence == SPFORCE_SENT_NONE ) - { - // no sentence cued up. - return; - } - - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz( ENT(pev), pSPForceSentences[ m_iSentence ], SPFORCE_SENTENCE_VOLUME, SPFORCE_ATTN, 0, m_voicePitch); - JustSpoke(); - } -} - //========================================================= // IRelationship - overridden because Alien Grunts are // Human grunt's nemesis. @@ -269,6 +148,10 @@ int CSPForce::IRelationship ( CBaseEntity *pTarget ) { return R_NM; } + else if( FClassnameIs( pTarget->pev, "monster_human_grunt" ) ) + { + return R_HT; + } return CSquadMonster::IRelationship( pTarget ); } @@ -286,12 +169,8 @@ void CSPForce :: GibMonster ( void ) GetAttachment( 0, vecGunPos, vecGunAngles ); CBaseEntity *pGun; - if (FBitSet( pev->weapons, SPFORCE_SHOTGUN )) - { - pGun = DropItem( "weapon_barneyshotgun", vecGunPos, vecGunAngles ); - } //Alex994 begin - for beretta spawning - else if (FBitSet( pev->weapons, SPFORCE_BERETTA )) + if (FBitSet( pev->weapons, SPFORCE_BERETTA )) { pGun = DropItem( "weapon_beretta", vecGunPos, vecGunAngles ); } @@ -320,318 +199,6 @@ void CSPForce :: GibMonster ( void ) CBaseMonster :: GibMonster(); } -//========================================================= -// ISoundMask - Overidden for human SPForces because they -// hear the DANGER sound that is made by hand grenades and -// other dangerous items. -//========================================================= -int CSPForce :: ISoundMask ( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER | - bits_SOUND_DANGER; -} - -//========================================================= -// someone else is talking - don't speak -//========================================================= -BOOL CSPForce :: FOkToSpeak( void ) -{ -// if someone else is talking, don't speak - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) - return FALSE; - - if ( pev->spawnflags & SF_MONSTER_GAG ) - { - if ( m_MonsterState != MONSTERSTATE_COMBAT ) - { - // no talking outside of combat if gagged. - return FALSE; - } - } - - // if player is not in pvs, don't speak -// if (FNullEnt(FIND_CLIENT_IN_PVS(edict()))) -// return FALSE; - - return TRUE; -} - -//========================================================= -//========================================================= -void CSPForce :: JustSpoke( void ) -{ - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(1.5, 2.0); - m_iSentence = SPFORCE_SENT_NONE; -} - -//========================================================= -// PrescheduleThink - this function runs after conditions -// are collected and before scheduling code is run. -//========================================================= -void CSPForce :: PrescheduleThink ( void ) -{ - if ( InSquad() && m_hEnemy != NULL ) - { - if ( HasConditions ( bits_COND_SEE_ENEMY ) ) - { - // update the squad's last enemy sighting time. - MySquadLeader()->m_flLastEnemySightTime = gpGlobals->time; - } - else - { - if ( gpGlobals->time - MySquadLeader()->m_flLastEnemySightTime > 5 ) - { - // been a while since we've seen the enemy - MySquadLeader()->m_fEnemyEluded = TRUE; - } - } - } -} - -//========================================================= -// FCanCheckAttacks - this is overridden for human SPForces -// because they can throw/shoot grenades when they can't see their -// target and the base class doesn't check attacks if the monster -// cannot see its enemy. -// -// !!!BUGBUG - this gets called before a 3-round burst is fired -// which means that a friendly can still be hit with up to 2 rounds. -// ALSO, grenades will not be tossed if there is a friendly in front, -// this is a bad bug. Friendly machine gun fire avoidance -// will unecessarily prevent the throwing of a grenade as well. -//========================================================= -BOOL CSPForce :: FCanCheckAttacks ( void ) -{ - if ( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) - { - return TRUE; - } - else - { - return FALSE; - } -} - - -//========================================================= -// CheckMeleeAttack1 -//========================================================= -BOOL CSPForce :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - CBaseMonster *pEnemy; - - if ( m_hEnemy != NULL ) - { - 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; -} - -//========================================================= -// CheckRangeAttack1 - overridden for SPForce, cause -// FCanCheckAttacks() doesn't disqualify all attacks based -// on whether or not the enemy is occluded because unlike -// the base class, the SPForce can attack when the enemy is -// occluded (throw grenade over wall, etc). We must -// disqualify the machine gun attack if the enemy is occluded. -//========================================================= -BOOL CSPForce :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 2048 && flDot >= 0.5 && NoFriendlyFire() ) - { - TraceResult tr; - - if ( !m_hEnemy->IsPlayer() && flDist <= 64 ) - { - // kick nonclients, but don't shoot at them. - return FALSE; - } - - Vector vecSrc = GetGunPosition(); - - // verify that a bullet fired from the gun will hit the enemy before the world. - UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget(vecSrc), ignore_monsters, ignore_glass, ENT(pev), &tr); - - if ( tr.flFraction == 1.0 ) - { - return TRUE; - } - } - - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 - this checks the SPForce's grenade -// attack. -//========================================================= -BOOL CSPForce :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - if (! FBitSet(pev->weapons, (SPFORCE_HANDGRENADE | SPFORCE_GRENADELAUNCHER))) - { - return FALSE; - } - - // if the SPForce isn't moving, it's ok to check. - if ( m_flGroundSpeed != 0 ) - { - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - // assume things haven't changed too much since last time - if (gpGlobals->time < m_flNextGrenadeCheck ) - { - return m_fThrowGrenade; - } - - if ( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) && m_hEnemy->pev->waterlevel == 0 && m_vecEnemyLKP.z > pev->absmax.z ) - { - //!!!BUGBUG - we should make this check movetype and make sure it isn't FLY? Players who jump a lot are unlikely to - // be grenaded. - // don't throw grenades at anything that isn't on the ground! - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - Vector vecTarget; - - if (FBitSet( pev->weapons, SPFORCE_HANDGRENADE)) - { - // find feet - if (RANDOM_LONG(0,1)) - { - // magically know where they are - vecTarget = Vector( m_hEnemy->pev->origin.x, m_hEnemy->pev->origin.y, m_hEnemy->pev->absmin.z ); - } - else - { - // toss it to where you last saw them - vecTarget = m_vecEnemyLKP; - } - // vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin); - // estimate position - // vecTarget = vecTarget + m_hEnemy->pev->velocity * 2; - } - else - { - // find target - // vecTarget = m_hEnemy->BodyTarget( pev->origin ); - vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin); - // estimate position - if (HasConditions( bits_COND_SEE_ENEMY)) - vecTarget = vecTarget + ((vecTarget - pev->origin).Length() / gSkillData.hgruntGrenadeSpeed) * m_hEnemy->pev->velocity; - } - - // are any of my squad members near the intended grenade impact area? - if ( InSquad() ) - { - if (SquadMemberInRange( vecTarget, 256 )) - { - // crap, I might blow my own guy up. Don't throw a grenade and don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - m_fThrowGrenade = FALSE; - } - } - - if ( ( vecTarget - pev->origin ).Length2D() <= 256 ) - { - // crap, I don't want to blow myself up - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - - if (FBitSet( pev->weapons, SPFORCE_HANDGRENADE)) - { - Vector vecToss = VecCheckToss( pev, GetGunPosition(), vecTarget, 0.5 ); - - if ( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time; // 1/3 second. - } - else - { - // don't throw - m_fThrowGrenade = FALSE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - } - } - else - { - Vector vecToss = VecCheckThrow( pev, GetGunPosition(), vecTarget, gSkillData.hgruntGrenadeSpeed, 0.5 ); - - if ( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 0.3; // 1/3 second. - } - else - { - // don't throw - m_fThrowGrenade = FALSE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - } - } - - - - return m_fThrowGrenade; -} - - -//========================================================= -// TraceAttack - make sure we're not taking it in the helmet -//========================================================= -void CSPForce :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - // check for helmet shot - if (ptr->iHitgroup == 11) - { - // make sure we're wearing one - if (GetBodygroup( 1 ) == HEAD_SPForce && (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB))) - { - // absorb damage - flDamage -= 20; - if (flDamage <= 0) - { - UTIL_Ricochet( ptr->vecEndPos, 1.0 ); - flDamage = 0.01; - } - } - // it's head shot anyways - ptr->iHitgroup = HITGROUP_HEAD; - } - CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - - //========================================================= // TakeDamage - overridden for the SPForce because the SPForce // needs to forget that he is in cover if he's hurt. (Obviously @@ -644,154 +211,6 @@ int CSPForce :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, flo return CSquadMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CSPForce :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 150; - break; - case ACT_RUN: - ys = 150; - break; - case ACT_WALK: - ys = 180; - break; - case ACT_RANGE_ATTACK1: - ys = 120; - break; - case ACT_RANGE_ATTACK2: - ys = 120; - break; - case ACT_MELEE_ATTACK1: - ys = 120; - break; - case ACT_MELEE_ATTACK2: - ys = 120; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 180; - break; - case ACT_GLIDE: - case ACT_FLY: - ys = 30; - break; - default: - ys = 90; - break; - } - - pev->yaw_speed = ys; -} - -void CSPForce :: IdleSound( void ) -{ - if (FOkToSpeak() && (g_fSPForceQuestion || RANDOM_LONG(0,1))) - { - if (!g_fSPForceQuestion) - { - // ask question or make statement - switch (RANDOM_LONG(0,2)) - { - case 0: // check in - SENTENCEG_PlayRndSz(ENT(pev), "HG_CHECK", SPFORCE_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - g_fSPForceQuestion = 1; - break; - case 1: // question - SENTENCEG_PlayRndSz(ENT(pev), "HG_QUEST", SPFORCE_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - g_fSPForceQuestion = 2; - break; - case 2: // statement - SENTENCEG_PlayRndSz(ENT(pev), "HG_IDLE", SPFORCE_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - break; - } - } - else - { - switch (g_fSPForceQuestion) - { - case 1: // check in - SENTENCEG_PlayRndSz(ENT(pev), "HG_CLEAR", SPFORCE_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - break; - case 2: // question - SENTENCEG_PlayRndSz(ENT(pev), "HG_ANSWER", SPFORCE_SENTENCE_VOLUME, ATTN_NORM, 0, m_voicePitch); - break; - } - g_fSPForceQuestion = 0; - } - JustSpoke(); - } -} - -//========================================================= -// CheckAmmo - overridden for the SPForce because he actually -// uses ammo! (base class doesn't) -//========================================================= -void CSPForce :: CheckAmmo ( void ) -{ - if ( m_cAmmoLoaded <= 0 ) - { - SetConditions(bits_COND_NO_AMMO_LOADED); - } -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CSPForce :: Classify ( void ) -{ - if(FClassnameIs(pev,"monster_human_spforce")) - return CLASS_HUMAN_MILITARY; - else - return CLASS_ALIEN_MILITARY; -} - -//========================================================= -//========================================================= -CBaseEntity *CSPForce :: Kick( void ) -{ - TraceResult tr; - - UTIL_MakeVectors( pev->angles ); - Vector vecStart = pev->origin; - vecStart.z += pev->size.z * 0.5; - Vector vecEnd = vecStart + (gpGlobals->v_forward * 70); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if ( tr.pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - return pEntity; - } - - return NULL; -} - -//========================================================= -// GetGunPosition return the end of the barrel -//========================================================= - -Vector CSPForce :: GetGunPosition( ) -{ - if (m_fStanding ) - { - return pev->origin + Vector( 0, 0, 60 ); - } - else - { - return pev->origin + Vector( 0, 0, 48 ); - } -} - //========================================================= // Shoot //========================================================= @@ -809,14 +228,7 @@ void CSPForce :: Shoot ( void ) Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iBrassShell, TE_BOUNCE_SHELL); - if (FBitSet( pev->weapons, SPFORCE_BERETTA )) - { - FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_BERETTA ); // shoot +-5 degrees - } - else - { - FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_10DEGREES, 2048, BULLET_PLAYER_M41A ); // shoot +-5 degrees - } + FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_10DEGREES, 2048, BULLET_MONSTER_MP5); // shoot +-5 degrees pev->effects |= EF_MUZZLEFLASH; @@ -829,7 +241,7 @@ void CSPForce :: Shoot ( void ) //========================================================= // Shoot //========================================================= -void CSPForce :: Shotgun ( void ) +void CSPForce :: Beretta ( void ) { if (m_hEnemy == NULL) { @@ -842,8 +254,8 @@ void CSPForce :: Shotgun ( void ) UTIL_MakeVectors ( pev->angles ); Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); - EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iShotgunShell, TE_BOUNCE_SHOTSHELL); - FireBullets(gSkillData.hgruntShotgunPellets, vecShootOrigin, vecShootDir, VECTOR_CONE_15DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0 ); // shoot +-7.5 degrees + EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iBrassShell, TE_BOUNCE_SHELL); + FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_4DEGREES, 2048, BULLET_MONSTER_9MM, 0 ); // shoot +-7.5 degrees pev->effects |= EF_MUZZLEFLASH; @@ -874,13 +286,8 @@ void CSPForce :: HandleAnimEvent( MonsterEvent_t *pEvent ) // switch to body group with no gun. SetBodygroup( GUN_GROUP, GUN_NONE ); - // now spawn a gun. - if (FBitSet( pev->weapons, SPFORCE_SHOTGUN )) - { - DropItem( "weapon_barneyshotgun", vecGunPos, vecGunAngles ); - } //Alex begin - else if (FBitSet( pev->weapons, SPFORCE_BERETTA )) + if (FBitSet( pev->weapons, SPFORCE_BERETTA )) { DropItem( "weapon_beretta", vecGunPos, vecGunAngles ); } @@ -898,16 +305,15 @@ void CSPForce :: HandleAnimEvent( MonsterEvent_t *pEvent ) break; case SPFORCE_AE_RELOAD: - //EMIT_SOUND( ENT(pev), CHAN_WEAPON, "hgrunt/spf_reload1.wav", 1, ATTN_NORM ); // the first round of the three round burst plays the sound and puts a sound in the world sound list. - if ( RANDOM_LONG(0,1) ) - { - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "spforce/spf_reload1.wav", 1, ATTN_NORM ); - } - else - { - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "spforce/spf_reload2.wav", 1, ATTN_NORM ); - } + if ( FBitSet( pev->weapons, SPFORCE_BERETTA ) ) + { + EMIT_SOUND( ENT(pev), CHAN_WEAPON, "spforce/spf_reload2.wav", 1, ATTN_NORM ); + } + else + { + EMIT_SOUND( ENT(pev), CHAN_WEAPON, "spforce/spf_reload1.wav", 1, ATTN_NORM ); + } m_cAmmoLoaded = m_cClipSize; ClearConditions(bits_COND_NO_AMMO_LOADED); @@ -936,7 +342,7 @@ void CSPForce :: HandleAnimEvent( MonsterEvent_t *pEvent ) { EMIT_SOUND( ENT(pev), CHAN_WEAPON, "weapons/m41aglauncher2.wav", 0.8, ATTN_NORM ); } - CGrenade::ShootContact( pev, GetGunPosition(), m_vecTossVelocity ); + CGrenade::ShootContact( pev, GetGunPosition(), m_vecTossVelocity, gSkillData.plrDmgM41AGrenade ); 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 @@ -969,19 +375,13 @@ void CSPForce :: HandleAnimEvent( MonsterEvent_t *pEvent ) } } //Alex begin - else if ( FBitSet( pev->weapons, SPFORCE_BERETTA )) - { - Shoot(); - // the first round of the three round burst plays the sound and puts a sound in the world sound list. - EMIT_SOUND( ENT(pev), CHAN_WEAPON, "weapons/beretta_fire1.wav", 1, ATTN_NORM ); - - } - //Alex end else { - Shotgun( ); + Beretta(); - EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/sbarrel1.wav", 1, ATTN_NORM ); + // the first round of the three round burst plays the sound and puts a sound in the world sound list. + EMIT_SOUND( ENT(pev), CHAN_WEAPON, "weapons/beretta_fire1.wav", 1, ATTN_NORM ); + } CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 384, 0.3 ); @@ -1000,6 +400,7 @@ void CSPForce :: 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; @@ -1015,9 +416,8 @@ void CSPForce :: HandleAnimEvent( MonsterEvent_t *pEvent ) SENTENCEG_PlayRndSz(ENT(pev), "HG_ALERT", SPFORCE_SENTENCE_VOLUME, SPFORCE_ATTN, 0, m_voicePitch); JustSpoke(); } - } - + break; default: CSquadMonster::HandleAnimEvent( pEvent ); break; @@ -1043,7 +443,7 @@ void CSPForce :: Spawn() m_MonsterState = MONSTERSTATE_NONE; m_flNextGrenadeCheck = gpGlobals->time + 1; m_flNextPainTime = gpGlobals->time; - m_iSentence = SPFORCE_SENT_NONE; + m_iSentence = HGRUNT_SENT_NONE; m_afCapability = bits_CAP_SQUAD | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; @@ -1060,30 +460,24 @@ void CSPForce :: Spawn() // pev->weapons = SPFORCE_9MMAR | SPFORCE_GRENADELAUNCHER; } - if (FBitSet( pev->weapons, SPFORCE_SHOTGUN )) + if (FBitSet( pev->weapons, SPFORCE_BERETTA )) { - SetBodygroup( GUN_GROUP, GUN_SHOTGUN ); - m_cClipSize = 8; + SetBodygroup( GUN_GROUP, GUN_BERETTA ); + m_cClipSize = 15; } else { - m_cClipSize = SPFORCE_CLIP_SIZE; + m_cClipSize = 45; } m_cAmmoLoaded = m_cClipSize; - if (RANDOM_LONG( 0, 99 ) < 80) - pev->skin = 0; // light skin - else - pev->skin = 1; // dark skin - - if (FBitSet( pev->weapons, SPFORCE_SHOTGUN )) + if (FBitSet( pev->weapons, SPFORCE_BERETTA )) { - SetBodygroup( HEAD_GROUP, HEAD_SHOTGUN); + SetBodygroup( HEAD_GROUP, HEAD_BERETTA); } else if (FBitSet( pev->weapons, SPFORCE_GRENADELAUNCHER )) { SetBodygroup( HEAD_GROUP, HEAD_M203 ); - pev->skin = 1; // alway dark skin } CTalkMonster::g_talkWaitTime = 0; @@ -1096,8 +490,11 @@ void CSPForce :: Spawn() //========================================================= void CSPForce :: Precache() { - PRECACHE_MODEL("models/spforce.mdl"); - + PRECACHE_MODEL( "models/spforce.mdl" ); + + PRECACHE_SOUND( "weapons/m41ahks1.wav" ); + PRECACHE_SOUND( "weapons/m41ahks2.wav" ); + PRECACHE_SOUND( "hgrunt/gr_die1.wav" ); PRECACHE_SOUND( "hgrunt/gr_die2.wav" ); PRECACHE_SOUND( "hgrunt/gr_die3.wav" ); @@ -1114,1332 +511,16 @@ void CSPForce :: Precache() PRECACHE_SOUND( "weapons/m41aglauncher.wav" ); PRECACHE_SOUND( "weapons/m41aglauncher2.wav" ); - PRECACHE_SOUND( "weapons/m41ahks1.wav" ); - PRECACHE_SOUND( "weapons/m41ahks2.wav" ); - - PRECACHE_SOUND( "weapons/sbarrel1.wav" ); - - PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event + PRECACHE_SOUND( "weapons/beretta_fire1.wav" ); + 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); - else - m_voicePitch = 100; + m_voicePitch = 92 + RANDOM_LONG( 0, 6 ); - m_iBrassShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell - m_iShotgunShell = PRECACHE_MODEL ("models/shotgunshell.mdl"); + m_iBrassShell = PRECACHE_MODEL( "models/shell.mdl" );// brass shell } -//========================================================= -// start task -//========================================================= -void CSPForce :: StartTask ( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch ( pTask->iTask ) - { - case TASK_SPFORCE_CHECK_FIRE: - if ( !NoFriendlyFire() ) - { - SetConditions( bits_COND_SPFORCE_NOFIRE ); - } - TaskComplete(); - break; - - case TASK_SPFORCE_SPEAK_SENTENCE: - SpeakSentence(); - TaskComplete(); - break; - - case TASK_WALK_PATH: - case TASK_RUN_PATH: - // SPForce no longer assumes he is covered if he moves - Forget( bits_MEMORY_INCOVER ); - CSquadMonster ::StartTask( pTask ); - break; - - case TASK_RELOAD: - m_IdealActivity = ACT_RELOAD; - break; - - case TASK_SPFORCE_FACE_TOSS_DIR: - break; - - case TASK_FACE_IDEAL: - case TASK_FACE_ENEMY: - CSquadMonster :: StartTask( pTask ); - if (pev->movetype == MOVETYPE_FLY) - { - m_IdealActivity = ACT_GLIDE; - } - break; - - default: - CSquadMonster :: StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CSPForce :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_SPFORCE_FACE_TOSS_DIR: - { - // project a point along the toss vector and turn to face that point. - MakeIdealYaw( pev->origin + m_vecTossVelocity * 64 ); - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - m_iTaskStatus = TASKSTATUS_COMPLETE; - } - break; - } - default: - { - CSquadMonster :: RunTask( pTask ); - break; - } - } -} - -//========================================================= -// PainSound -//========================================================= -void CSPForce :: PainSound ( void ) -{ - if ( gpGlobals->time > m_flNextPainTime ) - { -#if 0 - if ( RANDOM_LONG(0,99) < 5 ) - { - // pain sentences are rare - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz(ENT(pev), "HG_PAIN", SPFORCE_SENTENCE_VOLUME, ATTN_NORM, 0, PITCH_NORM); - JustSpoke(); - return; - } - } -#endif - switch ( RANDOM_LONG(0,6) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain3.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain4.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain5.wav", 1, ATTN_NORM ); - break; - case 3: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain1.wav", 1, ATTN_NORM ); - break; - case 4: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain2.wav", 1, ATTN_NORM ); - break; - } - - m_flNextPainTime = gpGlobals->time + 1; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CSPForce :: DeathSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die1.wav", 1, ATTN_IDLE ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die2.wav", 1, ATTN_IDLE ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die3.wav", 1, ATTN_IDLE ); - break; - } -} - -//========================================================= -// AI Schedules Specific to this monster -//========================================================= - -//========================================================= -// SPForceFail -//========================================================= -Task_t tlSPForceFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slSPForceFail[] = -{ - { - tlSPForceFail, - ARRAYSIZE ( tlSPForceFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2, - 0, - "SPForce Fail" - }, -}; - -//========================================================= -// SPForce Combat Fail -//========================================================= -Task_t tlSPForceCombatFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slSPForceCombatFail[] = -{ - { - tlSPForceCombatFail, - ARRAYSIZE ( tlSPForceCombatFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2, - 0, - "SPForce Combat Fail" - }, -}; - -//========================================================= -// Victory dance! -//========================================================= -Task_t tlSPForceVictoryDance[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1.5 }, - { TASK_GET_PATH_TO_ENEMY_CORPSE, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, -}; - -Schedule_t slSPForceVictoryDance[] = -{ - { - tlSPForceVictoryDance, - ARRAYSIZE ( tlSPForceVictoryDance ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "SPForceVictoryDance" - }, -}; - -//========================================================= -// Establish line of fire - move to a position that allows -// the SPForce to attack. -//========================================================= -Task_t tlSPForceEstablishLineOfFire[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_SPFORCE_ELOF_FAIL }, - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_SPFORCE_SPEAK_SENTENCE,(float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slSPForceEstablishLineOfFire[] = -{ - { - tlSPForceEstablishLineOfFire, - ARRAYSIZE ( tlSPForceEstablishLineOfFire ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "SPForceEstablishLineOfFire" - }, -}; - -//========================================================= -// SPForceFoundEnemy - SPForce established sight with an enemy -// that was hiding from the squad. -//========================================================= -Task_t tlSPForceFoundEnemy[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_SIGNAL1 }, -}; - -Schedule_t slSPForceFoundEnemy[] = -{ - { - tlSPForceFoundEnemy, - ARRAYSIZE ( tlSPForceFoundEnemy ), - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "SPForceFoundEnemy" - }, -}; - -//========================================================= -// SPForceCombatFace Schedule -//========================================================= -Task_t tlSPForceCombatFace1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1.5 }, - { TASK_SET_SCHEDULE, (float)SCHED_SPFORCE_SWEEP }, -}; - -Schedule_t slSPForceCombatFace[] = -{ - { - tlSPForceCombatFace1, - ARRAYSIZE ( tlSPForceCombatFace1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2, - 0, - "Combat Face" - }, -}; - -//========================================================= -// Suppressing fire - don't stop shooting until the clip is -// empty or SPForce gets hurt. -//========================================================= -Task_t tlSPForceSignalSuppress[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_SIGNAL2 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slSPForceSignalSuppress[] = -{ - { - tlSPForceSignalSuppress, - ARRAYSIZE ( tlSPForceSignalSuppress ), - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SPFORCE_NOFIRE | - bits_COND_NO_AMMO_LOADED, - - bits_SOUND_DANGER, - "SignalSuppress" - }, -}; - -Task_t tlSPForceSuppress[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slSPForceSuppress[] = -{ - { - tlSPForceSuppress, - ARRAYSIZE ( tlSPForceSuppress ), - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_SPFORCE_NOFIRE | - bits_COND_NO_AMMO_LOADED, - - bits_SOUND_DANGER, - "Suppress" - }, -}; - - -//========================================================= -// SPForce wait in cover - we don't allow danger or the ability -// to attack to break a SPForce's run to cover schedule, but -// when a SPForce is in cover, we do want them to attack if they can. -//========================================================= -Task_t tlSPForceWaitInCover[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)1 }, -}; - -Schedule_t slSPForceWaitInCover[] = -{ - { - tlSPForceWaitInCover, - ARRAYSIZE ( tlSPForceWaitInCover ), - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2, - - bits_SOUND_DANGER, - "SPForceWaitInCover" - }, -}; - -//========================================================= -// run to cover. -// !!!BUGBUG - set a decent fail schedule here. -//========================================================= -Task_t tlSPForceTakeCover1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_SPFORCE_TAKECOVER_FAILED }, - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_SPFORCE_SPEAK_SENTENCE, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_SET_SCHEDULE, (float)SCHED_SPFORCE_WAIT_FACE_ENEMY }, -}; - -Schedule_t slSPForceTakeCover[] = -{ - { - tlSPForceTakeCover1, - ARRAYSIZE ( tlSPForceTakeCover1 ), - 0, - 0, - "TakeCover" - }, -}; - -//========================================================= -// drop grenade then run to cover. -//========================================================= -Task_t tlSPForceGrenadeCover1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)99 }, - { TASK_FIND_FAR_NODE_COVER_FROM_ENEMY, (float)384 }, - { TASK_PLAY_SEQUENCE, (float)ACT_SPECIAL_ATTACK1 }, - { TASK_CLEAR_MOVE_WAIT, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_SPFORCE_WAIT_FACE_ENEMY }, -}; - -Schedule_t slSPForceGrenadeCover[] = -{ - { - tlSPForceGrenadeCover1, - ARRAYSIZE ( tlSPForceGrenadeCover1 ), - 0, - 0, - "GrenadeCover" - }, -}; - - -//========================================================= -// drop grenade then run to cover. -//========================================================= -Task_t tlSPForceTossGrenadeCover1[] = -{ - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK2, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, -}; - -Schedule_t slSPForceTossGrenadeCover[] = -{ - { - tlSPForceTossGrenadeCover1, - ARRAYSIZE ( tlSPForceTossGrenadeCover1 ), - 0, - 0, - "TossGrenadeCover" - }, -}; - -//========================================================= -// hide from the loudest sound source (to run from grenade) -//========================================================= -Task_t tlSPForceTakeCoverFromBestSound[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_COWER },// duck and cover if cannot move from explosion - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_TURN_LEFT, (float)179 }, -}; - -Schedule_t slSPForceTakeCoverFromBestSound[] = -{ - { - tlSPForceTakeCoverFromBestSound, - ARRAYSIZE ( tlSPForceTakeCoverFromBestSound ), - 0, - 0, - "SPForceTakeCoverFromBestSound" - }, -}; - -//========================================================= -// SPForce reload schedule -//========================================================= -Task_t tlSPForceHideReload[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RELOAD }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_RELOAD }, -}; - -Schedule_t slSPForceHideReload[] = -{ - { - tlSPForceHideReload, - ARRAYSIZE ( tlSPForceHideReload ), - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "SPForceHideReload" - } -}; - -//========================================================= -// Do a turning sweep of the area -//========================================================= -Task_t tlSPForceSweep[] = -{ - { TASK_TURN_LEFT, (float)179 }, - { TASK_WAIT, (float)1 }, - { TASK_TURN_LEFT, (float)179 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slSPForceSweep[] = -{ - { - tlSPForceSweep, - ARRAYSIZE ( tlSPForceSweep ), - - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_HEAR_SOUND, - - bits_SOUND_WORLD |// sound flags - bits_SOUND_DANGER | - bits_SOUND_PLAYER, - - "SPForce Sweep" - }, -}; - -//========================================================= -// primary range attack. Overriden because base class stops attacking when the enemy is occluded. -// SPForce's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlSPForceRangeAttack1A[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCH }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slSPForceRangeAttack1A[] = -{ - { - tlSPForceRangeAttack1A, - ARRAYSIZE ( tlSPForceRangeAttack1A ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_HEAR_SOUND | - bits_COND_SPFORCE_NOFIRE | - bits_COND_NO_AMMO_LOADED, - - bits_SOUND_DANGER, - "Range Attack1A" - }, -}; - - -//========================================================= -// primary range attack. Overriden because base class stops attacking when the enemy is occluded. -// SPForce's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlSPForceRangeAttack1B[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_IDLE_ANGRY }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_SPFORCE_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slSPForceRangeAttack1B[] = -{ - { - tlSPForceRangeAttack1B, - ARRAYSIZE ( tlSPForceRangeAttack1B ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED | - bits_COND_SPFORCE_NOFIRE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Range Attack1B" - }, -}; - -//========================================================= -// secondary range attack. Overriden because base class stops attacking when the enemy is occluded. -// SPForce's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlSPForceRangeAttack2[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SPFORCE_FACE_TOSS_DIR, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_RANGE_ATTACK2 }, - { TASK_SET_SCHEDULE, (float)SCHED_SPFORCE_WAIT_FACE_ENEMY },// don't run immediately after throwing grenade. -}; - -Schedule_t slSPForceRangeAttack2[] = -{ - { - tlSPForceRangeAttack2, - ARRAYSIZE ( tlSPForceRangeAttack2 ), - 0, - 0, - "RangeAttack2" - }, -}; - - -//========================================================= -// repel -//========================================================= -Task_t tlSPForceRepel[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_GLIDE }, -}; - -Schedule_t slSPForceRepel[] = -{ - { - tlSPForceRepel, - ARRAYSIZE ( tlSPForceRepel ), - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER, - "Repel" - }, -}; - - -//========================================================= -// repel -//========================================================= -Task_t tlSPForceRepelAttack[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_FLY }, -}; - -Schedule_t slSPForceRepelAttack[] = -{ - { - tlSPForceRepelAttack, - ARRAYSIZE ( tlSPForceRepelAttack ), - bits_COND_ENEMY_OCCLUDED, - 0, - "Repel Attack" - }, -}; - -//========================================================= -// repel land -//========================================================= -Task_t tlSPForceRepelLand[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_LAND }, - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slSPForceRepelLand[] = -{ - { - tlSPForceRepelLand, - ARRAYSIZE ( tlSPForceRepelLand ), - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER, - "Repel Land" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CSPForce ) -{ - slSPForceFail, - slSPForceCombatFail, - slSPForceVictoryDance, - slSPForceEstablishLineOfFire, - slSPForceFoundEnemy, - slSPForceCombatFace, - slSPForceSignalSuppress, - slSPForceSuppress, - slSPForceWaitInCover, - slSPForceTakeCover, - slSPForceGrenadeCover, - slSPForceTossGrenadeCover, - slSPForceTakeCoverFromBestSound, - slSPForceHideReload, - slSPForceSweep, - slSPForceRangeAttack1A, - slSPForceRangeAttack1B, - slSPForceRangeAttack2, - slSPForceRepel, - slSPForceRepelAttack, - slSPForceRepelLand, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CSPForce, CSquadMonster ); - -//========================================================= -// SetActivity -//========================================================= -void CSPForce :: SetActivity ( Activity NewActivity ) -{ - int iSequence = ACTIVITY_NOT_AVAILABLE; - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - switch ( NewActivity) - { - case ACT_RANGE_ATTACK1: - // SPForce is either shooting standing or shooting crouched - if (FBitSet( pev->weapons, SPFORCE_M41A)) - { - if ( m_fStanding ) - { - // get aimable sequence - iSequence = LookupSequence( "standing_mp5" ); - } - else - { - // get crouching shoot - iSequence = LookupSequence( "crouching_mp5" ); - } - } - //Alex begin - else if (FBitSet( pev->weapons, SPFORCE_BERETTA)) - { - if ( m_fStanding ) - { - // get aimable sequence - iSequence = LookupSequence( "standing_beretta" ); - } - else - { - // get crouching shoot - iSequence = LookupSequence( "crouching_beretta" ); - } - } - //Alex end - else - { - if ( m_fStanding ) - { - // get aimable sequence - iSequence = LookupSequence( "standing_shotgun" ); - } - else - { - // get crouching shoot - iSequence = LookupSequence( "crouching_shotgun" ); - } - } - break; - case ACT_RANGE_ATTACK2: - // SPForce is going to a secondary long range attack. This may be a thrown - // grenade or fired grenade, we must determine which and pick proper sequence - if ( pev->weapons & SPFORCE_HANDGRENADE ) - { - // get toss anim - iSequence = LookupSequence( "throwgrenade" ); - } - else - { - // get launch anim - iSequence = LookupSequence( "launchgrenade" ); - } - break; - case ACT_RUN: - if ( pev->health <= SPFORCE_LIMP_HEALTH ) - { - // limp! - iSequence = LookupActivity ( ACT_RUN_HURT ); - } - else - { - iSequence = LookupActivity ( NewActivity ); - } - break; - case ACT_WALK: - if ( pev->health <= SPFORCE_LIMP_HEALTH ) - { - // limp! - iSequence = LookupActivity ( ACT_WALK_HURT ); - } - else - { - iSequence = LookupActivity ( NewActivity ); - } - break; - case ACT_IDLE: - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - { - NewActivity = ACT_IDLE_ANGRY; - } - iSequence = LookupActivity ( NewActivity ); - break; - default: - iSequence = LookupActivity ( NewActivity ); - break; - } - - m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present - - // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) - { - if ( pev->sequence != iSequence || !m_fSequenceLoops ) - { - pev->frame = 0; - } - - pev->sequence = iSequence; // Set to the reset anim (if it's there) - ResetSequenceInfo( ); - SetYawSpeed(); - } - else - { - // Not available try to get default anim - ALERT ( at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity ); - pev->sequence = 0; // Set to the reset anim (if it's there) - } -} - -//========================================================= -// Get Schedule! -//========================================================= -Schedule_t *CSPForce :: GetSchedule( void ) -{ - - // clear old sentence - m_iSentence = SPFORCE_SENT_NONE; - - // flying? If PRONE, barnacle has me. IF not, it's assumed I am rapelling. - if ( pev->movetype == MOVETYPE_FLY && m_MonsterState != MONSTERSTATE_PRONE ) - { - if (pev->flags & FL_ONGROUND) - { - // just landed - pev->movetype = MOVETYPE_STEP; - return GetScheduleOfType ( SCHED_SPFORCE_REPEL_LAND ); - } - else - { - // repel down a rope, - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - return GetScheduleOfType ( SCHED_SPFORCE_REPEL_ATTACK ); - else - return GetScheduleOfType ( SCHED_SPFORCE_REPEL ); - } - } - - // SPForces place HIGH priority on running away from danger sounds. - if ( HasConditions(bits_COND_HEAR_SOUND) ) - { - CSound *pSound; - pSound = PBestSound(); - - ASSERT( pSound != NULL ); - if ( pSound) - { - if (pSound->m_iType & bits_SOUND_DANGER) - { - // dangerous sound nearby! - - //!!!KELLY - currently, this is the SPForce's signal that a grenade has landed nearby, - // and the SPForce should find cover from the blast - // good place for "SHIT!" or some other colorful verbal indicator of dismay. - // It's not safe to play a verbal order here "Scatter", etc cause - // this may only affect a single individual in a squad. - - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz( ENT(pev), "HG_GREN", SPFORCE_SENTENCE_VOLUME, SPFORCE_ATTN, 0, m_voicePitch); - JustSpoke(); - } - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_BEST_SOUND ); - } - /* - if (!HasConditions( bits_COND_SEE_ENEMY ) && ( pSound->m_iType & (bits_SOUND_PLAYER | bits_SOUND_COMBAT) )) - { - MakeIdealYaw( pSound->m_vecOrigin ); - } - */ - } - } - 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(); - } - -// new enemy - if ( HasConditions(bits_COND_NEW_ENEMY) ) - { - if ( InSquad() ) - { - MySquadLeader()->m_fEnemyEluded = FALSE; - - if ( !IsLeader() ) - { - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); - } - else - { - //!!!KELLY - the leader of a squad of SPForces has just seen the player or a - // monster and has made it the squad's enemy. You - // can check pev->flags for FL_CLIENT to determine whether this is the player - // or a monster. He's going to immediately start - // firing, though. If you'd like, we can make an alternate "first sight" - // schedule where the leader plays a handsign anim - // that gives us enough time to hear a short sentence or spoken command - // before he starts pluggin away. - if (FOkToSpeak())// && RANDOM_LONG(0,1)) - { - if ((m_hEnemy != NULL) && m_hEnemy->IsPlayer()) - // player - SENTENCEG_PlayRndSz( ENT(pev), "HG_ALERT", SPFORCE_SENTENCE_VOLUME, SPFORCE_ATTN, 0, m_voicePitch); - else if ((m_hEnemy != NULL) && - (m_hEnemy->Classify() != CLASS_PLAYER_ALLY) && - (m_hEnemy->Classify() != CLASS_HUMAN_PASSIVE) && - (m_hEnemy->Classify() != CLASS_MACHINE)) - // monster - SENTENCEG_PlayRndSz( ENT(pev), "HG_MONST", SPFORCE_SENTENCE_VOLUME, SPFORCE_ATTN, 0, m_voicePitch); - - JustSpoke(); - } - - if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_SPFORCE_SUPPRESS ); - } - else - { - return GetScheduleOfType ( SCHED_SPFORCE_ESTABLISH_LINE_OF_FIRE ); - } - } - } - } -// no ammo - else if ( HasConditions ( bits_COND_NO_AMMO_LOADED ) ) - { - //!!!KELLY - this individual just realized he's out of bullet ammo. - // He's going to try to find cover to run to and reload, but rarely, if - // none is available, he'll drop and reload in the open here. - return GetScheduleOfType ( SCHED_SPFORCE_COVER_AND_RELOAD ); - } - -// damaged just a little - else if ( HasConditions( bits_COND_LIGHT_DAMAGE ) ) - { - // if hurt: - // 90% chance of taking cover - // 10% chance of flinch. - int iPercent = RANDOM_LONG(0,99); - - if ( iPercent <= 90 && m_hEnemy != NULL ) - { - // only try to take cover if we actually have an enemy! - - //!!!KELLY - this SPForce was hit and is going to run to cover. - if (FOkToSpeak()) // && RANDOM_LONG(0,1)) - { - //SENTENCEG_PlayRndSz( ENT(pev), "HG_COVER", SPFORCE_SENTENCE_VOLUME, SPFORCE_ATTN, 0, m_voicePitch); - m_iSentence = SPFORCE_SENT_COVER; - //JustSpoke(); - } - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - else - { - return GetScheduleOfType( SCHED_SMALL_FLINCH ); - } - } -// can kick - else if ( HasConditions ( bits_COND_CAN_MELEE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_MELEE_ATTACK1 ); - } -// can grenade launch - - else if ( FBitSet( pev->weapons, SPFORCE_GRENADELAUNCHER) && HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - // shoot a grenade if you can - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } -// can shoot - else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - if ( InSquad() ) - { - // if the enemy has eluded the squad and a squad member has just located the enemy - // and the enemy does not see the squad member, issue a call to the squad to waste a - // little time and give the player a chance to turn. - if ( MySquadLeader()->m_fEnemyEluded && !HasConditions ( bits_COND_ENEMY_FACING_ME ) ) - { - MySquadLeader()->m_fEnemyEluded = FALSE; - return GetScheduleOfType ( SCHED_SPFORCE_FOUND_ENEMY ); - } - } - - if ( OccupySlot ( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - // try to take an available ENGAGE slot - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - else if ( HasConditions ( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - // throw a grenade if can and no engage slots are available - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - else - { - // hide! - return GetScheduleOfType( SCHED_TAKE_COVER_FROM_ENEMY ); - } - } -// can't see enemy - else if ( HasConditions( bits_COND_ENEMY_OCCLUDED ) ) - { - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - //!!!KELLY - this SPForce is about to throw or fire a grenade at the player. Great place for "fire in the hole" "frag out" etc - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz( ENT(pev), "HG_THROW", SPFORCE_SENTENCE_VOLUME, SPFORCE_ATTN, 0, m_voicePitch); - JustSpoke(); - } - return GetScheduleOfType( SCHED_RANGE_ATTACK2 ); - } - else if ( OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - //!!!KELLY - SPForce cannot see the enemy and has just decided to - // charge the enemy's position. - if (FOkToSpeak())// && RANDOM_LONG(0,1)) - { - //SENTENCEG_PlayRndSz( ENT(pev), "HG_CHARGE", SPFORCE_SENTENCE_VOLUME, SPFORCE_ATTN, 0, m_voicePitch); - m_iSentence = SPFORCE_SENT_CHARGE; - //JustSpoke(); - } - - return GetScheduleOfType( SCHED_SPFORCE_ESTABLISH_LINE_OF_FIRE ); - } - else - { - //!!!KELLY - SPForce is going to stay put for a couple seconds to see if - // the enemy wanders back out into the open, or approaches the - // SPForce's covered position. Good place for a taunt, I guess? - if (FOkToSpeak() && RANDOM_LONG(0,1)) - { - SENTENCEG_PlayRndSz( ENT(pev), "HG_TAUNT", SPFORCE_SENTENCE_VOLUME, SPFORCE_ATTN, 0, m_voicePitch); - JustSpoke(); - } - return GetScheduleOfType( SCHED_STANDOFF ); - } - } - - if ( HasConditions( bits_COND_SEE_ENEMY ) && !HasConditions ( bits_COND_CAN_RANGE_ATTACK1 ) ) - { - return GetScheduleOfType ( SCHED_SPFORCE_ESTABLISH_LINE_OF_FIRE ); - } - } - } - - // no special cases here, call the base class - return CSquadMonster :: GetSchedule(); -} - -//========================================================= -//========================================================= -Schedule_t* CSPForce :: GetScheduleOfType ( int Type ) -{ - switch ( Type ) - { - case SCHED_TAKE_COVER_FROM_ENEMY: - { - if ( InSquad() ) - { - if ( g_iSkillLevel == SKILL_HARD && HasConditions( bits_COND_CAN_RANGE_ATTACK2 ) && OccupySlot( bits_SLOTS_HGRUNT_GRENADE ) ) - { - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz( ENT(pev), "HG_THROW", SPFORCE_SENTENCE_VOLUME, SPFORCE_ATTN, 0, m_voicePitch); - JustSpoke(); - } - return slSPForceTossGrenadeCover; - } - else - { - return &slSPForceTakeCover[ 0 ]; - } - } - else - { - if ( RANDOM_LONG(0,1) ) - { - return &slSPForceTakeCover[ 0 ]; - } - else - { - return &slSPForceGrenadeCover[ 0 ]; - } - } - } - case SCHED_TAKE_COVER_FROM_BEST_SOUND: - { - return &slSPForceTakeCoverFromBestSound[ 0 ]; - } - case SCHED_SPFORCE_TAKECOVER_FAILED: - { - if ( HasConditions( bits_COND_CAN_RANGE_ATTACK1 ) && OccupySlot( bits_SLOTS_HGRUNT_ENGAGE ) ) - { - return GetScheduleOfType( SCHED_RANGE_ATTACK1 ); - } - - return GetScheduleOfType ( SCHED_FAIL ); - } - break; - case SCHED_SPFORCE_ELOF_FAIL: - { - // human SPForce is unable to move to a position that allows him to attack the enemy. - return GetScheduleOfType ( SCHED_TAKE_COVER_FROM_ENEMY ); - } - break; - case SCHED_SPFORCE_ESTABLISH_LINE_OF_FIRE: - { - return &slSPForceEstablishLineOfFire[ 0 ]; - } - break; - case SCHED_RANGE_ATTACK1: - { - // randomly stand or crouch - if (RANDOM_LONG(0,9) == 0) - m_fStanding = RANDOM_LONG(0,1); - - if (m_fStanding) - return &slSPForceRangeAttack1B[ 0 ]; - else - return &slSPForceRangeAttack1A[ 0 ]; - } - case SCHED_RANGE_ATTACK2: - { - return &slSPForceRangeAttack2[ 0 ]; - } - case SCHED_COMBAT_FACE: - { - return &slSPForceCombatFace[ 0 ]; - } - case SCHED_SPFORCE_WAIT_FACE_ENEMY: - { - return &slSPForceWaitInCover[ 0 ]; - } - case SCHED_SPFORCE_SWEEP: - { - return &slSPForceSweep[ 0 ]; - } - case SCHED_SPFORCE_COVER_AND_RELOAD: - { - return &slSPForceHideReload[ 0 ]; - } - case SCHED_SPFORCE_FOUND_ENEMY: - { - return &slSPForceFoundEnemy[ 0 ]; - } - case SCHED_VICTORY_DANCE: - { - if ( InSquad() ) - { - if ( !IsLeader() ) - { - return &slSPForceFail[ 0 ]; - } - } - - return &slSPForceVictoryDance[ 0 ]; - } - case SCHED_SPFORCE_SUPPRESS: - { - if ( m_hEnemy->IsPlayer() && m_fFirstEncounter ) - { - m_fFirstEncounter = FALSE;// after first encounter, leader won't issue handsigns anymore when he has a new enemy - return &slSPForceSignalSuppress[ 0 ]; - } - else - { - return &slSPForceSuppress[ 0 ]; - } - } - case SCHED_FAIL: - { - if ( m_hEnemy != NULL ) - { - // SPForce has an enemy, so pick a different default fail schedule most likely to help recover. - return &slSPForceCombatFail[ 0 ]; - } - - return &slSPForceFail[ 0 ]; - } - case SCHED_SPFORCE_REPEL: - { - if (pev->velocity.z > -128) - pev->velocity.z -= 32; - return &slSPForceRepel[ 0 ]; - } - case SCHED_SPFORCE_REPEL_ATTACK: - { - if (pev->velocity.z > -128) - pev->velocity.z -= 32; - return &slSPForceRepelAttack[ 0 ]; - } - case SCHED_SPFORCE_REPEL_LAND: - { - return &slSPForceRepelLand[ 0 ]; - } - default: - { - return CSquadMonster :: GetScheduleOfType ( Type ); - } - } -} - - //========================================================= // CSPForceRepel - when triggered, spawns a monster_human_spforce // repelling down a line. @@ -2511,10 +592,10 @@ public: void KeyValue( KeyValueData *pkvd ); int m_iPose;// which sequence to display -- temporary, don't need to save - static char *m_szPoses[3]; + static const char *m_szPoses[3]; }; -char *CDeadSPForce::m_szPoses[] = { "deadstomach", "deadside", "deadsitting" }; +const char *CDeadSPForce::m_szPoses[] = { "deadstomach", "deadside", "deadsitting" }; void CDeadSPForce::KeyValue( KeyValueData *pkvd ) { diff --git a/dlls/asheep/terror.cpp b/dlls/asheep/terror.cpp index 525774c1..5eb28a32 100644 --- a/dlls/asheep/terror.cpp +++ b/dlls/asheep/terror.cpp @@ -41,6 +41,7 @@ #include "soundent.h" #include "effects.h" #include "customentity.h" +#include "hgrunt.h" int g_fTerrorQuestion; // true if an idle grunt asked a question. Cleared when someone answers. @@ -120,93 +121,28 @@ enum //========================================================= #define bits_COND_TERROR_NOFIRE ( bits_COND_SPECIAL1 ) -class CTerror : public CSquadMonster +class CTerror : public CHGrunt { public: void Spawn( void ); void Precache( void ); - void SetYawSpeed ( void ); - int Classify ( void ); - int ISoundMask ( void ); + //int Classify ( 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 *pTerrorSentences[]; }; LINK_ENTITY_TO_CLASS( monster_human_terror, CTerror ); -TYPEDESCRIPTION CTerror::m_SaveData[] = -{ - DEFINE_FIELD( CTerror, m_flNextGrenadeCheck, FIELD_TIME ), - DEFINE_FIELD( CTerror, m_flNextPainTime, FIELD_TIME ), -// DEFINE_FIELD( CTerror, m_flLastEnemySightTime, FIELD_TIME ), // don't save, go to zero - DEFINE_FIELD( CTerror, m_vecTossVelocity, FIELD_VECTOR ), - DEFINE_FIELD( CTerror, m_fThrowGrenade, FIELD_BOOLEAN ), - DEFINE_FIELD( CTerror, m_fStanding, FIELD_BOOLEAN ), - DEFINE_FIELD( CTerror, m_fFirstEncounter, FIELD_BOOLEAN ), - DEFINE_FIELD( CTerror, m_cClipSize, FIELD_INTEGER ), - DEFINE_FIELD( CTerror, m_voicePitch, FIELD_INTEGER ), -// DEFINE_FIELD( CShotgun, m_iBrassShell, FIELD_INTEGER ), -// DEFINE_FIELD( CShotgun, m_iShotgunShell, FIELD_INTEGER ), - DEFINE_FIELD( CTerror, m_iSentence, FIELD_INTEGER ), -}; - -IMPLEMENT_SAVERESTORE( CTerror, CSquadMonster ); - const char *CTerror::pTerrorSentences[] = { "TR_GREN", // grenade scared grunt @@ -276,7 +212,7 @@ int CTerror::IRelationship ( CBaseEntity *pTarget ) //========================================================= void CTerror :: GibMonster ( void ) { - Vector vecGunPos; +/* Vector vecGunPos; Vector vecGunAngles; if ( GetBodygroup( 2 ) != 2 ) @@ -308,322 +244,10 @@ void CTerror :: GibMonster ( void ) } } } - +*/ CBaseMonster :: GibMonster(); } -//========================================================= -// ISoundMask - Overidden for human grunts because they -// hear the DANGER sound that is made by hand grenades and -// other dangerous items. -//========================================================= -int CTerror :: ISoundMask ( void ) -{ - return bits_SOUND_WORLD | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER | - bits_SOUND_DANGER; -} - -//========================================================= -// someone else is talking - don't speak -//========================================================= -BOOL CTerror :: FOkToSpeak( void ) -{ -// if someone else is talking, don't speak - if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) - return FALSE; - - if ( pev->spawnflags & SF_MONSTER_GAG ) - { - if ( m_MonsterState != MONSTERSTATE_COMBAT ) - { - // no talking outside of combat if gagged. - return FALSE; - } - } - - // if player is not in pvs, don't speak -// if (FNullEnt(FIND_CLIENT_IN_PVS(edict()))) -// return FALSE; - - return TRUE; -} - -//========================================================= -//========================================================= -void CTerror :: JustSpoke( void ) -{ - CTalkMonster::g_talkWaitTime = gpGlobals->time + RANDOM_FLOAT(1.5, 2.0); - m_iSentence = TERROR_SENT_NONE; -} - -//========================================================= -// PrescheduleThink - this function runs after conditions -// are collected and before scheduling code is run. -//========================================================= -void CTerror :: PrescheduleThink ( void ) -{ - if ( InSquad() && m_hEnemy != NULL ) - { - if ( HasConditions ( bits_COND_SEE_ENEMY ) ) - { - // update the squad's last enemy sighting time. - MySquadLeader()->m_flLastEnemySightTime = gpGlobals->time; - } - else - { - if ( gpGlobals->time - MySquadLeader()->m_flLastEnemySightTime > 5 ) - { - // been a while since we've seen the enemy - MySquadLeader()->m_fEnemyEluded = TRUE; - } - } - } -} - -//========================================================= -// FCanCheckAttacks - this is overridden for human grunts -// because they can throw/shoot grenades when they can't see their -// target and the base class doesn't check attacks if the monster -// cannot see its enemy. -// -// !!!BUGBUG - this gets called before a 3-round burst is fired -// which means that a friendly can still be hit with up to 2 rounds. -// ALSO, grenades will not be tossed if there is a friendly in front, -// this is a bad bug. Friendly machine gun fire avoidance -// will unecessarily prevent the throwing of a grenade as well. -//========================================================= -BOOL CTerror :: FCanCheckAttacks ( void ) -{ - if ( !HasConditions( bits_COND_ENEMY_TOOFAR ) ) - { - return TRUE; - } - else - { - return FALSE; - } -} - - -//========================================================= -// CheckMeleeAttack1 -//========================================================= -BOOL CTerror :: CheckMeleeAttack1 ( float flDot, float flDist ) -{ - CBaseMonster *pEnemy; - - if ( m_hEnemy != NULL ) - { - 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; -} - -//========================================================= -// CheckRangeAttack1 - overridden for Terror, cause -// FCanCheckAttacks() doesn't disqualify all attacks based -// on whether or not the enemy is occluded because unlike -// the base class, the Terror can attack when the enemy is -// occluded (throw grenade over wall, etc). We must -// disqualify the machine gun attack if the enemy is occluded. -//========================================================= -BOOL CTerror :: CheckRangeAttack1 ( float flDot, float flDist ) -{ - if ( !HasConditions( bits_COND_ENEMY_OCCLUDED ) && flDist <= 2048 && flDot >= 0.5 && NoFriendlyFire() ) - { - TraceResult tr; - - if ( !m_hEnemy->IsPlayer() && flDist <= 64 ) - { - // kick nonclients, but don't shoot at them. - return FALSE; - } - - Vector vecSrc = GetGunPosition(); - - // verify that a bullet fired from the gun will hit the enemy before the world. - UTIL_TraceLine( vecSrc, m_hEnemy->BodyTarget(vecSrc), ignore_monsters, ignore_glass, ENT(pev), &tr); - - if ( tr.flFraction == 1.0 ) - { - return TRUE; - } - } - - return FALSE; -} - -//========================================================= -// CheckRangeAttack2 - this checks the Terror's grenade -// attack. -//========================================================= -BOOL CTerror :: CheckRangeAttack2 ( float flDot, float flDist ) -{ - if (! FBitSet(pev->weapons, (TERROR_HANDGRENADE | TERROR_GRENADELAUNCHER))) - { - return FALSE; - } - - // if the grunt isn't moving, it's ok to check. - if ( m_flGroundSpeed != 0 ) - { - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - // assume things haven't changed too much since last time - if (gpGlobals->time < m_flNextGrenadeCheck ) - { - return m_fThrowGrenade; - } - - if ( !FBitSet ( m_hEnemy->pev->flags, FL_ONGROUND ) && m_hEnemy->pev->waterlevel == 0 && m_vecEnemyLKP.z > pev->absmax.z ) - { - //!!!BUGBUG - we should make this check movetype and make sure it isn't FLY? Players who jump a lot are unlikely to - // be grenaded. - // don't throw grenades at anything that isn't on the ground! - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - Vector vecTarget; - - if (FBitSet( pev->weapons, TERROR_HANDGRENADE)) - { - // find feet - if (RANDOM_LONG(0,1)) - { - // magically know where they are - vecTarget = Vector( m_hEnemy->pev->origin.x, m_hEnemy->pev->origin.y, m_hEnemy->pev->absmin.z ); - } - else - { - // toss it to where you last saw them - vecTarget = m_vecEnemyLKP; - } - // vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin); - // estimate position - // vecTarget = vecTarget + m_hEnemy->pev->velocity * 2; - } - else - { - // find target - // vecTarget = m_hEnemy->BodyTarget( pev->origin ); - vecTarget = m_vecEnemyLKP + (m_hEnemy->BodyTarget( pev->origin ) - m_hEnemy->pev->origin); - // estimate position - if (HasConditions( bits_COND_SEE_ENEMY)) - vecTarget = vecTarget + ((vecTarget - pev->origin).Length() / gSkillData.hgruntGrenadeSpeed) * m_hEnemy->pev->velocity; - } - - // are any of my squad members near the intended grenade impact area? - if ( InSquad() ) - { - if (SquadMemberInRange( vecTarget, 256 )) - { - // crap, I might blow my own guy up. Don't throw a grenade and don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - m_fThrowGrenade = FALSE; - } - } - - if ( ( vecTarget - pev->origin ).Length2D() <= 256 ) - { - // crap, I don't want to blow myself up - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - m_fThrowGrenade = FALSE; - return m_fThrowGrenade; - } - - - if (FBitSet( pev->weapons, TERROR_HANDGRENADE)) - { - Vector vecToss = VecCheckToss( pev, GetGunPosition(), vecTarget, 0.5 ); - - if ( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time; // 1/3 second. - } - else - { - // don't throw - m_fThrowGrenade = FALSE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - } - } - else - { - Vector vecToss = VecCheckThrow( pev, GetGunPosition(), vecTarget, gSkillData.hgruntGrenadeSpeed, 0.5 ); - - if ( vecToss != g_vecZero ) - { - m_vecTossVelocity = vecToss; - - // throw a hand grenade - m_fThrowGrenade = TRUE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 0.3; // 1/3 second. - } - else - { - // don't throw - m_fThrowGrenade = FALSE; - // don't check again for a while. - m_flNextGrenadeCheck = gpGlobals->time + 1; // one full second. - } - } - - - - return m_fThrowGrenade; -} - - -//========================================================= -// TraceAttack - make sure we're not taking it in the helmet -//========================================================= -void CTerror :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) -{ - // check for helmet shot - if (ptr->iHitgroup == 11) - { - // make sure we're wearing one - if (GetBodygroup( 1 ) == HEAD_TERROR && (bitsDamageType & (DMG_BULLET | DMG_SLASH | DMG_BLAST | DMG_CLUB))) - { - // absorb damage - flDamage -= 20; - if (flDamage <= 0) - { - UTIL_Ricochet( ptr->vecEndPos, 1.0 ); - flDamage = 0.01; - } - } - // it's head shot anyways - ptr->iHitgroup = HITGROUP_HEAD; - } - CSquadMonster::TraceAttack( pevAttacker, flDamage, vecDir, ptr, bitsDamageType ); -} - - //========================================================= // TakeDamage - overridden for the grunt because the grunt // needs to forget that he is in cover if he's hurt. (Obviously @@ -636,53 +260,6 @@ int CTerror :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, floa return CSquadMonster :: TakeDamage ( pevInflictor, pevAttacker, flDamage, bitsDamageType ); } -//========================================================= -// SetYawSpeed - allows each sequence to have a different -// turn rate associated with it. -//========================================================= -void CTerror :: SetYawSpeed ( void ) -{ - int ys; - - switch ( m_Activity ) - { - case ACT_IDLE: - ys = 150; - break; - case ACT_RUN: - ys = 150; - break; - case ACT_WALK: - ys = 180; - break; - case ACT_RANGE_ATTACK1: - ys = 120; - break; - case ACT_RANGE_ATTACK2: - ys = 120; - break; - case ACT_MELEE_ATTACK1: - ys = 120; - break; - case ACT_MELEE_ATTACK2: - ys = 120; - break; - case ACT_TURN_LEFT: - case ACT_TURN_RIGHT: - ys = 180; - break; - case ACT_GLIDE: - case ACT_FLY: - ys = 30; - break; - default: - ys = 90; - break; - } - - pev->yaw_speed = ys; -} - void CTerror :: IdleSound( void ) { if (FOkToSpeak() && (g_fTerrorQuestion || RANDOM_LONG(0,1))) @@ -722,122 +299,6 @@ void CTerror :: IdleSound( void ) } } -//========================================================= -// CheckAmmo - overridden for the grunt because he actually -// uses ammo! (base class doesn't) -//========================================================= -void CTerror :: CheckAmmo ( void ) -{ - if ( m_cAmmoLoaded <= 0 ) - { - SetConditions(bits_COND_NO_AMMO_LOADED); - } -} - -//========================================================= -// Classify - indicates this monster's place in the -// relationship table. -//========================================================= -int CTerror :: Classify ( void ) -{ - if ( FClassnameIs(pev, "monster_human_terror")) - return CLASS_HUMAN_MILITARY; -else - return CLASS_ALIEN_MILITARY; -} - -//========================================================= -//========================================================= -CBaseEntity *CTerror :: Kick( void ) -{ - TraceResult tr; - - UTIL_MakeVectors( pev->angles ); - Vector vecStart = pev->origin; - vecStart.z += pev->size.z * 0.5; - Vector vecEnd = vecStart + (gpGlobals->v_forward * 70); - - UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); - - if ( tr.pHit ) - { - CBaseEntity *pEntity = CBaseEntity::Instance( tr.pHit ); - return pEntity; - } - - return NULL; -} - -//========================================================= -// GetGunPosition return the end of the barrel -//========================================================= - -Vector CTerror :: GetGunPosition( ) -{ - if (m_fStanding ) - { - return pev->origin + Vector( 0, 0, 60 ); - } - else - { - return pev->origin + Vector( 0, 0, 48 ); - } -} - -//========================================================= -// Shoot -//========================================================= -void CTerror :: Shoot ( void ) -{ - if (m_hEnemy == NULL) - { - return; - } - - Vector vecShootOrigin = GetGunPosition(); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - UTIL_MakeVectors ( pev->angles ); - - Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); - EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iBrassShell, TE_BOUNCE_SHELL); - FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_10DEGREES, 2048, BULLET_MONSTER_MP5 ); // shoot +-5 degrees - - pev->effects |= EF_MUZZLEFLASH; - - m_cAmmoLoaded--;// take away a bullet! - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); -} - -//========================================================= -// Shoot -//========================================================= -void CTerror :: Shotgun ( void ) -{ - if (m_hEnemy == NULL) - { - return; - } - - Vector vecShootOrigin = GetGunPosition(); - Vector vecShootDir = ShootAtEnemy( vecShootOrigin ); - - UTIL_MakeVectors ( pev->angles ); - - Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40,90) + gpGlobals->v_up * RANDOM_FLOAT(75,200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); - EjectBrass ( vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iShotgunShell, TE_BOUNCE_SHOTSHELL); - FireBullets(gSkillData.hgruntShotgunPellets, vecShootOrigin, vecShootDir, VECTOR_CONE_15DEGREES, 2048, BULLET_PLAYER_BUCKSHOT, 0 ); // shoot +-7.5 degrees - - pev->effects |= EF_MUZZLEFLASH; - - m_cAmmoLoaded--;// take away a bullet! - - Vector angDir = UTIL_VecToAngles( vecShootDir ); - SetBlending( 0, angDir.x ); -} - //========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. @@ -850,30 +311,6 @@ void CTerror :: HandleAnimEvent( MonsterEvent_t *pEvent ) switch( pEvent->event ) { case TERROR_AE_DROP_GUN: - { - Vector vecGunPos; - Vector vecGunAngles; - - GetAttachment( 0, vecGunPos, vecGunAngles ); - - // switch to body group with no gun. - SetBodygroup( GUN_GROUP, GUN_NONE ); - - // now spawn a gun. - if (FBitSet( pev->weapons, TERROR_SHOTGUN )) - { - DropItem( "weapon_barneyshotgun", vecGunPos, vecGunAngles ); - } - else - { - DropItem( "weapon_barney9mmar", vecGunPos, vecGunAngles ); - } - if (FBitSet( pev->weapons, TERROR_GRENADELAUNCHER )) - { - DropItem( "ammo_ARgrenades", BodyTarget( pev->origin ), vecGunAngles ); - } - - } break; case TERROR_AE_RELOAD: @@ -897,7 +334,7 @@ void CTerror :: HandleAnimEvent( MonsterEvent_t *pEvent ) case TERROR_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 @@ -967,9 +404,8 @@ void CTerror :: HandleAnimEvent( MonsterEvent_t *pEvent ) SENTENCEG_PlayRndSz(ENT(pev), "TR_ALERT", TERROR_SENTENCE_VOLUME, TERROR_ATTN, 0, m_voicePitch); JustSpoke(); } - } - + break; default: CSquadMonster::HandleAnimEvent( pEvent ); break; @@ -1019,15 +455,10 @@ void CTerror :: Spawn() } else { - m_cClipSize = TERROR_CLIP_SIZE; + m_cClipSize = 48; } m_cAmmoLoaded = m_cClipSize; - if (RANDOM_LONG( 0, 99 ) < 80) - pev->skin = 0; // light skin - else - pev->skin = 1; // dark skin - if (FBitSet( pev->weapons, TERROR_SHOTGUN )) { SetBodygroup( HEAD_GROUP, HEAD_SHOTGUN); @@ -1035,7 +466,6 @@ void CTerror :: Spawn() else if (FBitSet( pev->weapons, TERROR_GRENADELAUNCHER )) { SetBodygroup( HEAD_GROUP, HEAD_M203 ); - pev->skin = 1; // alway dark skin } CTalkMonster::g_talkWaitTime = 0; @@ -1067,910 +497,43 @@ void CTerror :: Precache() PRECACHE_SOUND( "weapons/glauncher.wav" ); - //PRECACHE_SOUND( "weapons/sbarrel1.wav" ); + PRECACHE_SOUND( "weapons/sbarrel1.wav" ); PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event // get voice pitch - if (RANDOM_LONG(0,1)) - m_voicePitch = 109 + RANDOM_LONG(0,7); - else - m_voicePitch = 100; + m_voicePitch = 120 + RANDOM_LONG(0,2); m_iBrassShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell m_iShotgunShell = PRECACHE_MODEL ("models/shotgunshell.mdl"); } -//========================================================= -// start task -//========================================================= -void CTerror :: StartTask ( Task_t *pTask ) -{ - m_iTaskStatus = TASKSTATUS_RUNNING; - - switch ( pTask->iTask ) - { - case TASK_TERROR_CHECK_FIRE: - if ( !NoFriendlyFire() ) - { - SetConditions( bits_COND_TERROR_NOFIRE ); - } - TaskComplete(); - break; - - case TASK_TERROR_SPEAK_SENTENCE: - SpeakSentence(); - TaskComplete(); - break; - - case TASK_WALK_PATH: - case TASK_RUN_PATH: - // grunt no longer assumes he is covered if he moves - Forget( bits_MEMORY_INCOVER ); - CSquadMonster ::StartTask( pTask ); - break; - - case TASK_RELOAD: - m_IdealActivity = ACT_RELOAD; - break; - - case TASK_TERROR_FACE_TOSS_DIR: - break; - - case TASK_FACE_IDEAL: - case TASK_FACE_ENEMY: - CSquadMonster :: StartTask( pTask ); - if (pev->movetype == MOVETYPE_FLY) - { - m_IdealActivity = ACT_GLIDE; - } - break; - - default: - CSquadMonster :: StartTask( pTask ); - break; - } -} - -//========================================================= -// RunTask -//========================================================= -void CTerror :: RunTask ( Task_t *pTask ) -{ - switch ( pTask->iTask ) - { - case TASK_TERROR_FACE_TOSS_DIR: - { - // project a point along the toss vector and turn to face that point. - MakeIdealYaw( pev->origin + m_vecTossVelocity * 64 ); - ChangeYaw( pev->yaw_speed ); - - if ( FacingIdeal() ) - { - m_iTaskStatus = TASKSTATUS_COMPLETE; - } - break; - } - default: - { - CSquadMonster :: RunTask( pTask ); - break; - } - } -} - -//========================================================= -// PainSound -//========================================================= -void CTerror :: PainSound ( void ) -{ - if ( gpGlobals->time > m_flNextPainTime ) - { -#if 0 - if ( RANDOM_LONG(0,99) < 5 ) - { - // pain sentences are rare - if (FOkToSpeak()) - { - SENTENCEG_PlayRndSz(ENT(pev), "TR_PAIN", TERROR_SENTENCE_VOLUME, ATTN_NORM, 0, PITCH_NORM); - JustSpoke(); - return; - } - } -#endif - switch ( RANDOM_LONG(0,6) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain3.wav", 1, ATTN_NORM ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain4.wav", 1, ATTN_NORM ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain5.wav", 1, ATTN_NORM ); - break; - case 3: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain1.wav", 1, ATTN_NORM ); - break; - case 4: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_pain2.wav", 1, ATTN_NORM ); - break; - } - - m_flNextPainTime = gpGlobals->time + 1; - } -} - -//========================================================= -// DeathSound -//========================================================= -void CTerror :: DeathSound ( void ) -{ - switch ( RANDOM_LONG(0,2) ) - { - case 0: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die1.wav", 1, ATTN_IDLE ); - break; - case 1: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die2.wav", 1, ATTN_IDLE ); - break; - case 2: - EMIT_SOUND( ENT(pev), CHAN_VOICE, "hgrunt/gr_die3.wav", 1, ATTN_IDLE ); - break; - } -} - //========================================================= // AI Schedules Specific to this monster //========================================================= -//========================================================= -// TerrorFail -//========================================================= -Task_t tlTerrorFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slTerrorFail[] = -{ - { - tlTerrorFail, - ARRAYSIZE ( tlTerrorFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2, - 0, - "Terror Fail" - }, -}; - -//========================================================= -// Terror Combat Fail -//========================================================= -Task_t tlTerrorCombatFail[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)2 }, - { TASK_WAIT_PVS, (float)0 }, -}; - -Schedule_t slTerrorCombatFail[] = -{ - { - tlTerrorCombatFail, - ARRAYSIZE ( tlTerrorCombatFail ), - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2, - 0, - "Terror Combat Fail" - }, -}; - -//========================================================= -// Victory dance! -//========================================================= -Task_t tlTerrorVictoryDance[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1.5 }, - { TASK_GET_PATH_TO_ENEMY_CORPSE, (float)0 }, - { TASK_WALK_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_VICTORY_DANCE }, -}; - -Schedule_t slTerrorVictoryDance[] = -{ - { - tlTerrorVictoryDance, - ARRAYSIZE ( tlTerrorVictoryDance ), - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE, - 0, - "TerrorVictoryDance" - }, -}; - -//========================================================= -// Establish line of fire - move to a position that allows -// the grunt to attack. -//========================================================= -Task_t tlTerrorEstablishLineOfFire[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TERROR_ELOF_FAIL }, - { TASK_GET_PATH_TO_ENEMY, (float)0 }, - { TASK_TERROR_SPEAK_SENTENCE,(float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, -}; - -Schedule_t slTerrorEstablishLineOfFire[] = -{ - { - tlTerrorEstablishLineOfFire, - ARRAYSIZE ( tlTerrorEstablishLineOfFire ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK2 | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "TerrorEstablishLineOfFire" - }, -}; - -//========================================================= -// TerrorFoundEnemy - grunt established sight with an enemy -// that was hiding from the squad. -//========================================================= -Task_t tlTerrorFoundEnemy[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_SIGNAL1 }, -}; - -Schedule_t slTerrorFoundEnemy[] = -{ - { - tlTerrorFoundEnemy, - ARRAYSIZE ( tlTerrorFoundEnemy ), - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "TerrorFoundEnemy" - }, -}; - -//========================================================= -// TerrorCombatFace Schedule -//========================================================= -Task_t tlTerrorCombatFace1[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_WAIT, (float)1.5 }, - { TASK_SET_SCHEDULE, (float)SCHED_TERROR_SWEEP }, -}; - -Schedule_t slTerrorCombatFace[] = -{ - { - tlTerrorCombatFace1, - ARRAYSIZE ( tlTerrorCombatFace1 ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2, - 0, - "Combat Face" - }, -}; - -//========================================================= -// Suppressing fire - don't stop shooting until the clip is -// empty or grunt gets hurt. -//========================================================= -Task_t tlTerrorSignalSuppress[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_SIGNAL2 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slTerrorSignalSuppress[] = -{ - { - tlTerrorSignalSuppress, - ARRAYSIZE ( tlTerrorSignalSuppress ), - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_TERROR_NOFIRE | - bits_COND_NO_AMMO_LOADED, - - bits_SOUND_DANGER, - "SignalSuppress" - }, -}; - -Task_t tlTerrorSuppress[] = -{ - { TASK_STOP_MOVING, 0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slTerrorSuppress[] = -{ - { - tlTerrorSuppress, - ARRAYSIZE ( tlTerrorSuppress ), - bits_COND_ENEMY_DEAD | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND | - bits_COND_TERROR_NOFIRE | - bits_COND_NO_AMMO_LOADED, - - bits_SOUND_DANGER, - "Suppress" - }, -}; - - -//========================================================= -// grunt wait in cover - we don't allow danger or the ability -// to attack to break a grunt's run to cover schedule, but -// when a grunt is in cover, we do want them to attack if they can. -//========================================================= -Task_t tlTerrorWaitInCover[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_ACTIVITY, (float)ACT_IDLE }, - { TASK_WAIT_FACE_ENEMY, (float)1 }, -}; - -Schedule_t slTerrorWaitInCover[] = -{ - { - tlTerrorWaitInCover, - ARRAYSIZE ( tlTerrorWaitInCover ), - bits_COND_NEW_ENEMY | - bits_COND_HEAR_SOUND | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_CAN_MELEE_ATTACK1 | - bits_COND_CAN_MELEE_ATTACK2, - - bits_SOUND_DANGER, - "TerrorWaitInCover" - }, -}; - -//========================================================= -// run to cover. -// !!!BUGBUG - set a decent fail schedule here. -//========================================================= -Task_t tlTerrorTakeCover1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_TERROR_TAKECOVER_FAILED }, - { TASK_WAIT, (float)0.2 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_TERROR_SPEAK_SENTENCE, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_SET_SCHEDULE, (float)SCHED_TERROR_WAIT_FACE_ENEMY }, -}; - -Schedule_t slTerrorTakeCover[] = -{ - { - tlTerrorTakeCover1, - ARRAYSIZE ( tlTerrorTakeCover1 ), - 0, - 0, - "TakeCover" - }, -}; - -//========================================================= -// drop grenade then run to cover. -//========================================================= -Task_t tlTerrorGrenadeCover1[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_ENEMY, (float)99 }, - { TASK_FIND_FAR_NODE_COVER_FROM_ENEMY, (float)384 }, - { TASK_PLAY_SEQUENCE, (float)ACT_SPECIAL_ATTACK1 }, - { TASK_CLEAR_MOVE_WAIT, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_TERROR_WAIT_FACE_ENEMY }, -}; - -Schedule_t slTerrorGrenadeCover[] = -{ - { - tlTerrorGrenadeCover1, - ARRAYSIZE ( tlTerrorGrenadeCover1 ), - 0, - 0, - "GrenadeCover" - }, -}; - - -//========================================================= -// drop grenade then run to cover. -//========================================================= -Task_t tlTerrorTossGrenadeCover1[] = -{ - { TASK_FACE_ENEMY, (float)0 }, - { TASK_RANGE_ATTACK2, (float)0 }, - { TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY }, -}; - -Schedule_t slTerrorTossGrenadeCover[] = -{ - { - tlTerrorTossGrenadeCover1, - ARRAYSIZE ( tlTerrorTossGrenadeCover1 ), - 0, - 0, - "TossGrenadeCover" - }, -}; - -//========================================================= -// hide from the loudest sound source (to run from grenade) -//========================================================= -Task_t tlTerrorTakeCoverFromBestSound[] = -{ - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_COWER },// duck and cover if cannot move from explosion - { TASK_STOP_MOVING, (float)0 }, - { TASK_FIND_COVER_FROM_BEST_SOUND, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_TURN_LEFT, (float)179 }, -}; - -Schedule_t slTerrorTakeCoverFromBestSound[] = -{ - { - tlTerrorTakeCoverFromBestSound, - ARRAYSIZE ( tlTerrorTakeCoverFromBestSound ), - 0, - 0, - "TerrorTakeCoverFromBestSound" - }, -}; - -//========================================================= -// Terror reload schedule -//========================================================= -Task_t tlTerrorHideReload[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_SET_FAIL_SCHEDULE, (float)SCHED_RELOAD }, - { TASK_FIND_COVER_FROM_ENEMY, (float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_REMEMBER, (float)bits_MEMORY_INCOVER }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_RELOAD }, -}; - -Schedule_t slTerrorHideReload[] = -{ - { - tlTerrorHideReload, - ARRAYSIZE ( tlTerrorHideReload ), - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "TerrorHideReload" - } -}; - -//========================================================= -// Do a turning sweep of the area -//========================================================= -Task_t tlTerrorSweep[] = -{ - { TASK_TURN_LEFT, (float)179 }, - { TASK_WAIT, (float)1 }, - { TASK_TURN_LEFT, (float)179 }, - { TASK_WAIT, (float)1 }, -}; - -Schedule_t slTerrorSweep[] = -{ - { - tlTerrorSweep, - ARRAYSIZE ( tlTerrorSweep ), - - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_CAN_RANGE_ATTACK1 | - bits_COND_CAN_RANGE_ATTACK2 | - bits_COND_HEAR_SOUND, - - bits_SOUND_WORLD |// sound flags - bits_SOUND_DANGER | - bits_SOUND_PLAYER, - - "Terror Sweep" - }, -}; - -//========================================================= -// primary range attack. Overriden because base class stops attacking when the enemy is occluded. -// grunt's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlTerrorRangeAttack1A[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY, (float)ACT_CROUCH }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slTerrorRangeAttack1A[] = -{ - { - tlTerrorRangeAttack1A, - ARRAYSIZE ( tlTerrorRangeAttack1A ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_HEAR_SOUND | - bits_COND_TERROR_NOFIRE | - bits_COND_NO_AMMO_LOADED, - - bits_SOUND_DANGER, - "Range Attack1A" - }, -}; - - -//========================================================= -// primary range attack. Overriden because base class stops attacking when the enemy is occluded. -// grunt's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlTerrorRangeAttack1B[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE_FACE_ENEMY,(float)ACT_IDLE_ANGRY }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_TERROR_CHECK_FIRE, (float)0 }, - { TASK_RANGE_ATTACK1, (float)0 }, -}; - -Schedule_t slTerrorRangeAttack1B[] = -{ - { - tlTerrorRangeAttack1B, - ARRAYSIZE ( tlTerrorRangeAttack1B ), - bits_COND_NEW_ENEMY | - bits_COND_ENEMY_DEAD | - bits_COND_HEAVY_DAMAGE | - bits_COND_ENEMY_OCCLUDED | - bits_COND_NO_AMMO_LOADED | - bits_COND_TERROR_NOFIRE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER, - "Range Attack1B" - }, -}; - -//========================================================= -// secondary range attack. Overriden because base class stops attacking when the enemy is occluded. -// grunt's grenade toss requires the enemy be occluded. -//========================================================= -Task_t tlTerrorRangeAttack2[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_TERROR_FACE_TOSS_DIR, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_RANGE_ATTACK2 }, - { TASK_SET_SCHEDULE, (float)SCHED_TERROR_WAIT_FACE_ENEMY },// don't run immediately after throwing grenade. -}; - -Schedule_t slTerrorRangeAttack2[] = -{ - { - tlTerrorRangeAttack2, - ARRAYSIZE ( tlTerrorRangeAttack2 ), - 0, - 0, - "RangeAttack2" - }, -}; - - -//========================================================= -// repel -//========================================================= -Task_t tlTerrorRepel[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_IDEAL, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_GLIDE }, -}; - -Schedule_t slTerrorRepel[] = -{ - { - tlTerrorRepel, - ARRAYSIZE ( tlTerrorRepel ), - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER, - "Repel" - }, -}; - - -//========================================================= -// repel -//========================================================= -Task_t tlTerrorRepelAttack[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_FACE_ENEMY, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_FLY }, -}; - -Schedule_t slTerrorRepelAttack[] = -{ - { - tlTerrorRepelAttack, - ARRAYSIZE ( tlTerrorRepelAttack ), - bits_COND_ENEMY_OCCLUDED, - 0, - "Repel Attack" - }, -}; - -//========================================================= -// repel land -//========================================================= -Task_t tlTerrorRepelLand[] = -{ - { TASK_STOP_MOVING, (float)0 }, - { TASK_PLAY_SEQUENCE, (float)ACT_LAND }, - { TASK_GET_PATH_TO_LASTPOSITION,(float)0 }, - { TASK_RUN_PATH, (float)0 }, - { TASK_WAIT_FOR_MOVEMENT, (float)0 }, - { TASK_CLEAR_LASTPOSITION, (float)0 }, -}; - -Schedule_t slTerrorRepelLand[] = -{ - { - tlTerrorRepelLand, - ARRAYSIZE ( tlTerrorRepelLand ), - bits_COND_SEE_ENEMY | - bits_COND_NEW_ENEMY | - bits_COND_LIGHT_DAMAGE | - bits_COND_HEAVY_DAMAGE | - bits_COND_HEAR_SOUND, - - bits_SOUND_DANGER | - bits_SOUND_COMBAT | - bits_SOUND_PLAYER, - "Repel Land" - }, -}; - - -DEFINE_CUSTOM_SCHEDULES( CTerror ) -{ - slTerrorFail, - slTerrorCombatFail, - slTerrorVictoryDance, - slTerrorEstablishLineOfFire, - slTerrorFoundEnemy, - slTerrorCombatFace, - slTerrorSignalSuppress, - slTerrorSuppress, - slTerrorWaitInCover, - slTerrorTakeCover, - slTerrorGrenadeCover, - slTerrorTossGrenadeCover, - slTerrorTakeCoverFromBestSound, - slTerrorHideReload, - slTerrorSweep, - slTerrorRangeAttack1A, - slTerrorRangeAttack1B, - slTerrorRangeAttack2, - slTerrorRepel, - slTerrorRepelAttack, - slTerrorRepelLand, -}; - -IMPLEMENT_CUSTOM_SCHEDULES( CTerror, CSquadMonster ); - -//========================================================= -// SetActivity -//========================================================= -void CTerror :: SetActivity ( Activity NewActivity ) -{ - int iSequence = ACTIVITY_NOT_AVAILABLE; - void *pmodel = GET_MODEL_PTR( ENT(pev) ); - - switch ( NewActivity) - { - case ACT_RANGE_ATTACK1: - // grunt is either shooting standing or shooting crouched - if (FBitSet( pev->weapons, TERROR_MP5)) - { - if ( m_fStanding ) - { - // get aimable sequence - iSequence = LookupSequence( "standing_mp5" ); - } - else - { - // get crouching shoot - iSequence = LookupSequence( "crouching_mp5" ); - } - } - else - { - if ( m_fStanding ) - { - // get aimable sequence - iSequence = LookupSequence( "standing_shotgun" ); - } - else - { - // get crouching shoot - iSequence = LookupSequence( "crouching_shotgun" ); - } - } - break; - case ACT_RANGE_ATTACK2: - // grunt is going to a secondary long range attack. This may be a thrown - // grenade or fired grenade, we must determine which and pick proper sequence - if ( pev->weapons & TERROR_HANDGRENADE ) - { - // get toss anim - iSequence = LookupSequence( "throwgrenade" ); - } - else - { - // get launch anim - iSequence = LookupSequence( "launchgrenade" ); - } - break; - case ACT_RUN: - if ( pev->health <= TERROR_LIMP_HEALTH ) - { - // limp! - iSequence = LookupActivity ( ACT_RUN_HURT ); - } - else - { - iSequence = LookupActivity ( NewActivity ); - } - break; - case ACT_WALK: - if ( pev->health <= TERROR_LIMP_HEALTH ) - { - // limp! - iSequence = LookupActivity ( ACT_WALK_HURT ); - } - else - { - iSequence = LookupActivity ( NewActivity ); - } - break; - case ACT_IDLE: - if ( m_MonsterState == MONSTERSTATE_COMBAT ) - { - NewActivity = ACT_IDLE_ANGRY; - } - iSequence = LookupActivity ( NewActivity ); - break; - default: - iSequence = LookupActivity ( NewActivity ); - break; - } - - m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present - - // Set to the desired anim, or default anim if the desired is not present - if ( iSequence > ACTIVITY_NOT_AVAILABLE ) - { - if ( pev->sequence != iSequence || !m_fSequenceLoops ) - { - pev->frame = 0; - } - - pev->sequence = iSequence; // Set to the reset anim (if it's there) - ResetSequenceInfo( ); - SetYawSpeed(); - } - else - { - // Not available try to get default anim - ALERT ( at_console, "%s has no sequence for act:%d\n", STRING(pev->classname), NewActivity ); - pev->sequence = 0; // Set to the reset anim (if it's there) - } -} +extern Schedule_t slIdleStand[]; +extern Schedule_t slGruntFail[]; +extern Schedule_t slGruntCombatFail[]; +extern Schedule_t slGruntVictoryDance[]; +extern Schedule_t slGruntEstablishLineOfFire[]; +extern Schedule_t slGruntFoundEnemy[]; +extern Schedule_t slGruntCombatFace[]; +extern Schedule_t slGruntSignalSuppress[]; +extern Schedule_t slGruntSuppress[]; +extern Schedule_t slGruntWaitInCover[]; +extern Schedule_t slGruntTakeCover[]; +extern Schedule_t slGruntGrenadeCover[]; +extern Schedule_t slGruntTossGrenadeCover[]; +extern Schedule_t slGruntTakeCoverFromBestSound[]; +extern Schedule_t slGruntHideReload[]; +extern Schedule_t slGruntSweep[]; +extern Schedule_t slGruntRangeAttack1A[]; +extern Schedule_t slGruntRangeAttack1B[]; +extern Schedule_t slGruntRangeAttack2[]; +extern Schedule_t slGruntRepel[]; +extern Schedule_t slGruntRepelAttack[]; +extern Schedule_t slGruntRepelLand[]; //========================================================= // Get Schedule! @@ -2215,6 +778,8 @@ Schedule_t *CTerror :: GetSchedule( void ) return GetScheduleOfType ( SCHED_TERROR_ESTABLISH_LINE_OF_FIRE ); } } + default: + break; } // no special cases here, call the base class @@ -2238,28 +803,28 @@ Schedule_t* CTerror :: GetScheduleOfType ( int Type ) SENTENCEG_PlayRndSz( ENT(pev), "TR_THROW", TERROR_SENTENCE_VOLUME, TERROR_ATTN, 0, m_voicePitch); JustSpoke(); } - return slTerrorTossGrenadeCover; + return slGruntTossGrenadeCover; } else { - return &slTerrorTakeCover[ 0 ]; + return &slGruntTakeCover[ 0 ]; } } else { if ( RANDOM_LONG(0,1) ) { - return &slTerrorTakeCover[ 0 ]; + return &slGruntTakeCover[ 0 ]; } else { - return &slTerrorGrenadeCover[ 0 ]; + return &slGruntGrenadeCover[ 0 ]; } } } case SCHED_TAKE_COVER_FROM_BEST_SOUND: { - return &slTerrorTakeCoverFromBestSound[ 0 ]; + return &slGruntTakeCoverFromBestSound[ 0 ]; } case SCHED_TERROR_TAKECOVER_FAILED: { @@ -2279,7 +844,7 @@ Schedule_t* CTerror :: GetScheduleOfType ( int Type ) break; case SCHED_TERROR_ESTABLISH_LINE_OF_FIRE: { - return &slTerrorEstablishLineOfFire[ 0 ]; + return &slGruntEstablishLineOfFire[ 0 ]; } break; case SCHED_RANGE_ATTACK1: @@ -2289,33 +854,33 @@ Schedule_t* CTerror :: GetScheduleOfType ( int Type ) m_fStanding = RANDOM_LONG(0,1); if (m_fStanding) - return &slTerrorRangeAttack1B[ 0 ]; + return &slGruntRangeAttack1B[ 0 ]; else - return &slTerrorRangeAttack1A[ 0 ]; + return &slGruntRangeAttack1A[ 0 ]; } case SCHED_RANGE_ATTACK2: { - return &slTerrorRangeAttack2[ 0 ]; + return &slGruntRangeAttack2[ 0 ]; } case SCHED_COMBAT_FACE: { - return &slTerrorCombatFace[ 0 ]; + return &slGruntCombatFace[ 0 ]; } case SCHED_TERROR_WAIT_FACE_ENEMY: { - return &slTerrorWaitInCover[ 0 ]; + return &slGruntWaitInCover[ 0 ]; } case SCHED_TERROR_SWEEP: { - return &slTerrorSweep[ 0 ]; + return &slGruntSweep[ 0 ]; } case SCHED_TERROR_COVER_AND_RELOAD: { - return &slTerrorHideReload[ 0 ]; + return &slGruntHideReload[ 0 ]; } case SCHED_TERROR_FOUND_ENEMY: { - return &slTerrorFoundEnemy[ 0 ]; + return &slGruntFoundEnemy[ 0 ]; } case SCHED_VICTORY_DANCE: { @@ -2323,22 +888,22 @@ Schedule_t* CTerror :: GetScheduleOfType ( int Type ) { if ( !IsLeader() ) { - return &slTerrorFail[ 0 ]; + return &slGruntFail[ 0 ]; } } - return &slTerrorVictoryDance[ 0 ]; + return &slGruntVictoryDance[ 0 ]; } case SCHED_TERROR_SUPPRESS: { if ( m_hEnemy->IsPlayer() && m_fFirstEncounter ) { m_fFirstEncounter = FALSE;// after first encounter, leader won't issue handsigns anymore when he has a new enemy - return &slTerrorSignalSuppress[ 0 ]; + return &slGruntSignalSuppress[ 0 ]; } else { - return &slTerrorSuppress[ 0 ]; + return &slGruntSuppress[ 0 ]; } } case SCHED_FAIL: @@ -2346,26 +911,26 @@ Schedule_t* CTerror :: GetScheduleOfType ( int Type ) if ( m_hEnemy != NULL ) { // grunt has an enemy, so pick a different default fail schedule most likely to help recover. - return &slTerrorCombatFail[ 0 ]; + return &slGruntCombatFail[ 0 ]; } - return &slTerrorFail[ 0 ]; + return &slGruntFail[ 0 ]; } case SCHED_TERROR_REPEL: { if (pev->velocity.z > -128) pev->velocity.z -= 32; - return &slTerrorRepel[ 0 ]; + return &slGruntRepel[ 0 ]; } case SCHED_TERROR_REPEL_ATTACK: { if (pev->velocity.z > -128) pev->velocity.z -= 32; - return &slTerrorRepelAttack[ 0 ]; + return &slGruntRepelAttack[ 0 ]; } case SCHED_TERROR_REPEL_LAND: { - return &slTerrorRepelLand[ 0 ]; + return &slGruntRepelLand[ 0 ]; } default: { @@ -2443,10 +1008,10 @@ public: void KeyValue( KeyValueData *pkvd ); int m_iPose;// which sequence to display -- temporary, don't need to save - static char *m_szPoses[3]; + static const char *m_szPoses[3]; }; -char *CDeadTerror::m_szPoses[] = { "deadstomach", "deadside", "deadsitting" }; +const char *CDeadTerror::m_szPoses[] = { "deadstomach", "deadside", "deadsitting" }; void CDeadTerror::KeyValue( KeyValueData *pkvd ) { diff --git a/dlls/asheep/toad.cpp b/dlls/asheep/toad.cpp index 5dbab550..8ae3354f 100644 --- a/dlls/asheep/toad.cpp +++ b/dlls/asheep/toad.cpp @@ -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 diff --git a/dlls/barney.cpp b/dlls/barney.cpp index f2dc66bb..6ea7e8d1 100644 --- a/dlls/barney.cpp +++ b/dlls/barney.cpp @@ -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; diff --git a/dlls/barney.h b/dlls/barney.h new file mode 100644 index 00000000..1e1951b4 --- /dev/null +++ b/dlls/barney.h @@ -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 diff --git a/dlls/cbase.h b/dlls/cbase.h index 4cf40abd..a0980264 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -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 diff --git a/dlls/cdll_dll.h b/dlls/cdll_dll.h index 0aafafbd..a124359b 100644 --- a/dlls/cdll_dll.h +++ b/dlls/cdll_dll.h @@ -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 ) diff --git a/dlls/combat.cpp b/dlls/combat.cpp index 9f221cc9..2b2f9c42 100644 --- a/dlls/combat.cpp +++ b/dlls/combat.cpp @@ -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 ); diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index 12d0ff8c..e4fe9fb8 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -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(); diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index 4cc48d97..828eaf2d 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -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 diff --git a/dlls/effects.cpp b/dlls/effects.cpp index bd12f8aa..180ff76b 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -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; +} diff --git a/dlls/egon.cpp b/dlls/egon.cpp index b83c9086..c9ca852d 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -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(); diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index 62af08e1..e2954133 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -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 diff --git a/dlls/genericmonster.cpp b/dlls/genericmonster.cpp index 3cc0acc6..6f7d5800 100644 --- a/dlls/genericmonster.cpp +++ b/dlls/genericmonster.cpp @@ -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 ); +} diff --git a/dlls/ggrenade.cpp b/dlls/ggrenade.cpp index 0ca516c4..93c48cf4 100644 --- a/dlls/ggrenade.cpp +++ b/dlls/ggrenade.cpp @@ -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; } diff --git a/dlls/glock.cpp b/dlls/glock.cpp index c9f9f2a2..b079c49e 100644 --- a/dlls/glock.cpp +++ b/dlls/glock.cpp @@ -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 ); diff --git a/dlls/h_battery.cpp b/dlls/h_battery.cpp index 976a5733..61ee1e1a 100644 --- a/dlls/h_battery.cpp +++ b/dlls/h_battery.cpp @@ -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 ) { diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index fce77193..e4cf2633 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -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; } diff --git a/dlls/headcrab.cpp b/dlls/headcrab.cpp index 60e03c10..c8efb833 100644 --- a/dlls/headcrab.cpp +++ b/dlls/headcrab.cpp @@ -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 ) diff --git a/dlls/headcrab.h b/dlls/headcrab.h new file mode 100644 index 00000000..0578a9c0 --- /dev/null +++ b/dlls/headcrab.h @@ -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[]; +}; diff --git a/dlls/healthkit.cpp b/dlls/healthkit.cpp index 99d53d35..a5690cd4 100644 --- a/dlls/healthkit.cpp +++ b/dlls/healthkit.cpp @@ -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; diff --git a/dlls/hgrunt.cpp b/dlls/hgrunt.cpp index 62c947f1..a41a5540 100644 --- a/dlls/hgrunt.cpp +++ b/dlls/hgrunt.cpp @@ -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, diff --git a/dlls/hgrunt.h b/dlls/hgrunt.h new file mode 100644 index 00000000..f33a35a0 --- /dev/null +++ b/dlls/hgrunt.h @@ -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[]; +}; diff --git a/dlls/hornet.cpp b/dlls/hornet.cpp index 758ba7e9..e734badd 100644 --- a/dlls/hornet.cpp +++ b/dlls/hornet.cpp @@ -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; diff --git a/dlls/hornetgun.cpp b/dlls/hornetgun.cpp index cc63d6db..22bae88e 100644 --- a/dlls/hornetgun.cpp +++ b/dlls/hornetgun.cpp @@ -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() ) diff --git a/dlls/ichthyosaur.cpp b/dlls/ichthyosaur.cpp index 53f57a27..e796dfe4 100644 --- a/dlls/ichthyosaur.cpp +++ b/dlls/ichthyosaur.cpp @@ -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 ) diff --git a/dlls/ichthyosaur.h b/dlls/ichthyosaur.h new file mode 100644 index 00000000..1dd1a474 --- /dev/null +++ b/dlls/ichthyosaur.h @@ -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 ); +}; diff --git a/dlls/islave.cpp b/dlls/islave.cpp index 9004ddde..d5867cf2 100644 --- a/dlls/islave.cpp +++ b/dlls/islave.cpp @@ -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++; diff --git a/dlls/islave.h b/dlls/islave.h new file mode 100644 index 00000000..228634be --- /dev/null +++ b/dlls/islave.h @@ -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[]; +}; diff --git a/dlls/items.cpp b/dlls/items.cpp index e6881c67..696b4e5e 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -174,7 +174,40 @@ void CItem::Materialize( void ) class CItemSuit : public CItem { void Spawn( void ) - { + { + Precache(); + SET_MODEL( ENT( pev ), "models/w_blue_suit.mdl" ); + CItem::Spawn(); + } + void Precache( void ) + { + PRECACHE_MODEL( "models/w_blue_suit.mdl" ); + } + BOOL MyTouch( CBasePlayer *pPlayer ) + { + 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 + + 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(); @@ -182,25 +215,24 @@ class CItemSuit : public CItem void Precache( void ) { PRECACHE_MODEL( "models/w_suit.mdl" ); + PRECACHE_SOUND( "armor/pickup.wav" ); } BOOL MyTouch( CBasePlayer *pPlayer ) { - if( pPlayer->pev->weapons & ( 1<pev->weapons & ( 1 << WEAPON_SUIT ) ) return FALSE; - 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 + 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; } }; - -LINK_ENTITY_TO_CLASS( item_suit, CItemSuit ) //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 ) diff --git a/dlls/monstermaker.cpp b/dlls/monstermaker.cpp index 38173d41..975eb17b 100644 --- a/dlls/monstermaker.cpp +++ b/dlls/monstermaker.cpp @@ -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. @@ -51,7 +52,7 @@ public: string_t m_iszMonsterClassname;// classname of the monster(s) that will be created. int m_cNumMonsters;// max number of monsters this ent can create - + int m_cLiveChildren;// how many monsters made by this monster maker that are currently alive int m_iMaxLiveChildren;// max number of monsters that this maker may have out at one time. @@ -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--; diff --git a/dlls/mortar.cpp b/dlls/mortar.cpp index 7faf3e56..f8e57b3f 100644 --- a/dlls/mortar.cpp +++ b/dlls/mortar.cpp @@ -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. diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp index ce9d74be..47b16694 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -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 ); diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 39a27e5c..9bcf5d7d 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -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; diff --git a/dlls/nihilanth.cpp b/dlls/nihilanth.cpp index 1d072db4..f087ff3e 100644 --- a/dlls/nihilanth.cpp +++ b/dlls/nihilanth.cpp @@ -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" ); diff --git a/dlls/plats.cpp b/dlls/plats.cpp index b3e1c683..fad34ac5 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -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 ) diff --git a/dlls/player.cpp b/dlls/player.cpp index 083c0e2a..c64aed18 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -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; } diff --git a/dlls/player.h b/dlls/player.h index 6fc06dbb..e7ebc51d 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -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. }; diff --git a/dlls/playermonster.cpp b/dlls/playermonster.cpp index cd3484ab..8747b3c0 100644 --- a/dlls/playermonster.cpp +++ b/dlls/playermonster.cpp @@ -82,7 +82,7 @@ void CPlayerMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) //========================================================= int CPlayerMonster::ISoundMask( void ) { - return NULL; + return 0; } //========================================================= diff --git a/dlls/python.cpp b/dlls/python.cpp index 90606c50..de4b88f5 100644 --- a/dlls/python.cpp +++ b/dlls/python.cpp @@ -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 ); diff --git a/dlls/rat.cpp b/dlls/rat.cpp index dd9a5905..985d4727 100644 --- a/dlls/rat.cpp +++ b/dlls/rat.cpp @@ -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 //========================================================= diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index fe1fd8a9..b884c4c7 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -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() ) diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index dc8724bd..fec7364c 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -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; diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index 317dd66a..887581e1 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -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 ) diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp index 66180822..28a2379b 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -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 ); diff --git a/dlls/sound.cpp b/dlls/sound.cpp index 8139a669..167b81a1 100644 --- a/dlls/sound.cpp +++ b/dlls/sound.cpp @@ -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; diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index bfe17ed1..ba62ec70 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -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; diff --git a/dlls/talkmonster.cpp b/dlls/talkmonster.cpp index 19fbc1c3..b66c26e4 100644 --- a/dlls/talkmonster.cpp +++ b/dlls/talkmonster.cpp @@ -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" }; //========================================================= diff --git a/dlls/talkmonster.h b/dlls/talkmonster.h index 882a67f8..69489c3b 100644 --- a/dlls/talkmonster.h +++ b/dlls/talkmonster.h @@ -38,7 +38,7 @@ #define bit_saidHeard (1<<6) #define bit_saidSmelled (1<<7) -#define TLK_CFRIENDS 7 +#define TLK_CFRIENDS 10 typedef enum { diff --git a/dlls/trains.h b/dlls/trains.h index f740e2ea..7075fa36 100644 --- a/dlls/trains.h +++ b/dlls/trains.h @@ -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 diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index 6d8fef04..cab4d777 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -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(); + } + } +} diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index 94907bcd..d90b8c1d 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -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; diff --git a/dlls/util.cpp b/dlls/util.cpp index 94c8c68c..0924cf18 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -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 ) { diff --git a/dlls/util.h b/dlls/util.h index 7f9dea70..de1829a9 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -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 diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 332cbe3c..0ab75479 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -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 ) diff --git a/dlls/weapons.h b/dlls/weapons.h index 58772c26..6ff379e9 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -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<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] );