Merge @Alex3474247's patches for "Azure Sheep".

This commit is contained in:
Night Owl 2018-01-03 02:45:25 +05:00
parent bc1bb3e358
commit de17a74a3a
41 changed files with 13499 additions and 35 deletions

View File

@ -46,6 +46,10 @@ set (CLDLL_SOURCES
../dlls/squeakgrenade.cpp
../dlls/tripmine.cpp
../dlls/glock.cpp
../dlls/asheep/beretta.cpp
../dlls/asheep/m41a.cpp
../dlls/asheep/poolstick.cpp
../dlls/asheep/toad.cpp
ev_hldm.cpp
hl/hl_baseentity.cpp
hl/hl_events.cpp

View File

@ -69,6 +69,12 @@ 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 );
void EV_FireBeretta1( struct event_args_s *args );
void EV_FireBeretta2( struct event_args_s *args );
//end Alex
void EV_TrainPitchAdjust( struct event_args_s *args );
}
@ -312,8 +318,13 @@ void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType )
switch( iBulletType )
{
case BULLET_PLAYER_9MM:
case BULLET_PLAYER_BERETTA: //Alex
case BULLET_MONSTER_9MM:
case BULLET_PLAYER_MP5:
//alex begin
case BULLET_PLAYER_M41A:
case BULLET_MONSTER_M41A:
//alex end
case BULLET_MONSTER_MP5:
case BULLET_PLAYER_BUCKSHOT:
case BULLET_PLAYER_357:
@ -357,6 +368,10 @@ int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, flo
{
case BULLET_PLAYER_MP5:
case BULLET_MONSTER_MP5:
// Alex begin
case BULLET_PLAYER_M41A:
case BULLET_MONSTER_M41A:
// Alex end
case BULLET_MONSTER_9MM:
case BULLET_MONSTER_12MM:
default:
@ -430,10 +445,14 @@ void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int
switch( iBulletType )
{
default:
case BULLET_PLAYER_BERETTA: // Alex
case BULLET_PLAYER_9MM:
EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType );
EV_HLDM_DecalGunshot( &tr, iBulletType );
break;
// Alex begin
case BULLET_PLAYER_M41A:
// Alex end
case BULLET_PLAYER_MP5:
if( !tracer )
{
@ -1753,3 +1772,188 @@ int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 )
{
return 0;
}
//begin Alex
//======================
// BERETTA START
//======================
enum beretta_e {
BERETTA_IDLE1 = 0,
BERETTA_IDLE2,
BERETTA_IDLE3,
BERETTA_SHOOT,
BERETTA_SHOOT_EMPTY,
BERETTA_RELOAD,
BERETTA_RELOAD_NOT_EMPTY,
BERETTA_DRAW,
BERETTA_HOLSTER,
BERETTA_ADD_SILENCER
};
void EV_FireBeretta1( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
int empty;
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
vec3_t vecSrc, vecAiming;
vec3_t up, right, forward;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
empty = args->bparam1;
AngleVectors( angles, forward, right, up );
shell = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/shell.mdl" );// brass shell
if( EV_IsLocal( idx ) )
{
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? BERETTA_SHOOT_EMPTY : BERETTA_SHOOT, 2 );
V_PunchAxis( 0, -2.0 );
}
EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 );
EV_EjectBrass( ShellOrigin, ShellVelocity, angles[YAW], shell, TE_BOUNCE_SHELL );
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/beretta_fire1.wav", gEngfuncs.pfnRandomFloat( 0.92, 1.0 ), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_BERETTA, 0, 0, args->fparam1, args->fparam2 );
}
void EV_FireBeretta2( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
int empty;
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
vec3_t vecSrc, vecAiming;
vec3_t vecSpread;
vec3_t up, right, forward;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
empty = args->bparam1;
AngleVectors( angles, forward, right, up );
shell = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/shell.mdl" );// brass shell
if( EV_IsLocal( idx ) )
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( empty ? BERETTA_SHOOT_EMPTY : BERETTA_SHOOT, 2 );
V_PunchAxis( 0, -2.0 );
}
EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 );
EV_EjectBrass( ShellOrigin, ShellVelocity, angles[YAW], shell, TE_BOUNCE_SHELL );
gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/beretta_fire1.wav", gEngfuncs.pfnRandomFloat( 0.92, 1.0 ), ATTN_NORM, 0, 98 + gEngfuncs.pfnRandomLong( 0, 3 ) );
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_BERETTA, 0, &g_tracerCount[idx-1], args->fparam1, args->fparam2 );
}
//======================
// BERETTA END
//======================
//end Alex
//Alex begin
//======================
// M41A START
//======================
enum m41a_e
{
M41A_LONGIDLE = 0,
M41A_IDLE1,
M41A_LAUNCH,
M41A_RELOAD,
M41A_DEPLOY,
M41A_FIRE1,
M41A_FIRE2,
//M41A_FIRE3,
};
void EV_FireM41A( event_args_t *args )
{
int idx;
vec3_t origin;
vec3_t angles;
vec3_t velocity;
vec3_t ShellVelocity;
vec3_t ShellOrigin;
int shell;
vec3_t vecSrc, vecAiming;
vec3_t up, right, forward;
float flSpread = 0.01;
idx = args->entindex;
VectorCopy( args->origin, origin );
VectorCopy( args->angles, angles );
VectorCopy( args->velocity, velocity );
AngleVectors( angles, forward, right, up );
shell = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/shell.mdl" );// brass shell
if( EV_IsLocal( idx ) )
{
// Add muzzle flash to current weapon model
EV_MuzzleFlash();
gEngfuncs.pEventAPI->EV_WeaponAnimation( M41A_FIRE1 + gEngfuncs.pfnRandomLong( 0, 1 ), 2 );
V_PunchAxis( 0, gEngfuncs.pfnRandomFloat( -2, 2 ) );
}
EV_GetDefaultShellInfo( args, origin, velocity, ShellVelocity, ShellOrigin, forward, right, up, 20, -12, 4 );
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;
}
EV_GetGunPosition( args, vecSrc, origin );
VectorCopy( forward, vecAiming );
EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_M41A, 2, &tracerCount[idx-1], args->fparam1, args->fparam2 );
}
//======================
// M41A END
//======================
//Alex end

View File

@ -18,10 +18,14 @@ typedef enum
BULLET_PLAYER_357, // python
BULLET_PLAYER_BUCKSHOT, // shotgun
BULLET_PLAYER_CROWBAR, // crowbar swipe
//begin Alex
BULLET_PLAYER_M41A,
BULLET_PLAYER_BERETTA,
//end Alex
BULLET_MONSTER_9MM,
BULLET_MONSTER_MP5,
BULLET_MONSTER_12MM
BULLET_MONSTER_M41A, // Alex
}Bullet;
enum glock_e

View File

@ -40,6 +40,12 @@ void EV_TripmineFire( struct event_args_s *args );
void EV_SnarkFire( struct event_args_s *args );
void EV_TrainPitchAdjust( struct event_args_s *args );
//Begin Alex
void EV_FireM41A( struct event_args_s *args );
void EV_FireBeretta1( struct event_args_s *args );
void EV_FireBeretta2( struct event_args_s *args );
//end Alex
}
/*
@ -76,4 +82,9 @@ void Game_HookEvents( void )
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 );
gEngfuncs.pfnHookEvent( "events/beretta2.sc", EV_FireBeretta2 );
//end Alex
}

View File

@ -67,6 +67,12 @@ 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
/*
======================
@ -616,6 +622,12 @@ void HUD_InitClientWeapons( void )
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
}
/*
@ -721,6 +733,20 @@ void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cm
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

View File

@ -22,7 +22,7 @@
#pragma once
#ifndef HUD_H
#define HUD_H
#define RGB_YELLOWISH 0x00FFA000 //255,160,0
#define RGB_YELLOWISH 0x00555EFF //85,94,255 Blue Azure Sheep hud
#define RGB_REDISH 0x00FF1010 //255,160,0
#define RGB_GREENISH 0x0000A000 //0,160,0

View File

@ -1317,17 +1317,23 @@ int V_FindViewModelByWeaponModel( int weaponindex )
{ "models/p_crowbar.mdl", "models/v_crowbar.mdl" },
{ "models/p_egon.mdl", "models/v_egon.mdl" },
{ "models/p_gauss.mdl", "models/v_gauss.mdl" },
{ "models/p_9mmhandgun.mdl", "models/v_9mmhandgun.mdl" },
{ "models/p_grenade.mdl", "models/v_grenade.mdl" },
{ "models/p_9mmhandgun.mdl", "models/v_barney9mmhg.mdl" },
{ "models/p_grenade.mdl", "models/v_barneygrenade.mdl" },
{ "models/p_hgun.mdl", "models/v_hgun.mdl" },
{ "models/p_9mmAR.mdl", "models/v_9mmAR.mdl" },
{ "models/p_9mmAR.mdl", "models/v_barney9mmar.mdl" },
{ "models/p_357.mdl", "models/v_357.mdl" },
{ "models/p_rpg.mdl", "models/v_rpg.mdl" },
{ "models/p_shotgun.mdl", "models/v_shotgun.mdl" },
{ "models/p_shotgun.mdl", "models/v_barneyshotgun.mdl" },
{ "models/p_squeak.mdl", "models/v_squeak.mdl" },
{ "models/p_tripmine.mdl", "models/v_tripmine.mdl" },
{ "models/p_satchel_radio.mdl", "models/v_satchel_radio.mdl" },
{ "models/p_satchel.mdl", "models/v_satchel.mdl" },
// Alex begin
{ "models/p_toad.mdl", "models/v_toad.mdl" },
{ "models/p_9mmm41a.mdl", "models/v_9mmm41a.mdl" },
{ "models/p_9mmberetta.mdl", "models/v_9mmberetta.mdl" },
{ "models/p_poolstick.mdl", "models/v_poolstick.mdl" },
// Alex end
{ NULL, NULL }
};

View File

@ -128,6 +128,19 @@ set (SVDLL_SOURCES
world.cpp
xen.cpp
zombie.cpp
asheep/adrian.cpp
asheep/alienpanther.cpp
asheep/archer.cpp
asheep/barniel.cpp
asheep/beretta.cpp
asheep/gordon.cpp
asheep/hevbarn.cpp
asheep/kate.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

842
dlls/asheep/adrian.cpp Normal file
View File

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

View File

@ -0,0 +1,866 @@
/***
*
* 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" );
}

1110
dlls/asheep/archer.cpp Normal file

File diff suppressed because it is too large Load Diff

835
dlls/asheep/barniel.cpp Normal file
View File

@ -0,0 +1,835 @@
/***
*
* 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 barniel dying for scripted sequences?
#define BARNIEL_AE_DRAW ( 2 )
#define BARNIEL_AE_SHOOT ( 3 )
#define BARNIEL_AE_HOLSTER ( 4 )
#define BARNIEL_BODY_GUNHOLSTERED 0
#define BARNIEL_BODY_GUNDRAWN 1
#define BARNIEL_BODY_GUNGONE 2
class CBarniel : public CTalkMonster
{
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 );
// 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_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 );
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
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[] =
{
{
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()))
{
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 );
}
}
}
//=========================================================
// 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
//=========================================================
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 )
{
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, "barniel/bn_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 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()
{
Precache( );
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->body = 0; // gun in holster
m_fGunDrawn = FALSE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
MonsterInit();
SetUse( &CBarniel::FollowerUse );
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CBarniel :: Precache()
{
PRECACHE_MODEL("models/barniel.mdl");
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_die1.wav");
//PRECACHE_SOUND("barniel/bn_die2.wav");
//PRECACHE_SOUND("barniel/bn_die3.wav");
// every new barniel 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()
{
CTalkMonster::TalkInit();
// scientists speach group names (group names are in sentences.txt)
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_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_PHELLO] = NULL; //"BN_PHELLO"; // UNDONE
m_szGrp[TLK_PIDLE] = NULL; //"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";
// get voice for head - just one barniel 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 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 )
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( "BN_MAD", 4, VOL_NORM, ATTN_NORM );
Remember( bits_MEMORY_PROVOKED );
StopFollowing( TRUE );
}
else
{
// Hey, be careful with that
PlaySentence( "BN_SHOT", 4, VOL_NORM, ATTN_NORM );
Remember( bits_MEMORY_SUSPICIOUS );
}
}
else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO )
{
PlaySentence( "BN_SHOT", 4, VOL_NORM, ATTN_NORM );
}
}
return ret;
}
//=========================================================
// PainSound
//=========================================================
void CBarniel :: PainSound ( void )
{
if (gpGlobals->time < m_painTime)
return;
m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75);
EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "barniel/bn_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch());
}
//=========================================================
// DeathSound
//=========================================================
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 );
}
//=========================================================
// 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 *CBarniel :: 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( "BN_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 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();
}

228
dlls/asheep/beretta.cpp Normal file
View File

@ -0,0 +1,228 @@
/***
*
* 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 "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
enum beretta_e {
BERETTA_IDLE1 = 0,
BERETTA_IDLE2,
BERETTA_IDLE3,
BERETTA_SHOOT,
BERETTA_SHOOT_EMPTY,
BERETTA_RELOAD,
BERETTA_RELOAD_NOT_EMPTY,
BERETTA_DRAW,
BERETTA_HOLSTER,
BERETTA_ADD_SILENCER
};
LINK_ENTITY_TO_CLASS( weapon_beretta, CBeretta );
void CBeretta::Spawn( )
{
pev->classname = MAKE_STRING("weapon_beretta"); // hack to allow for old names
Precache( );
m_iId = WEAPON_BERETTA;
SET_MODEL(ENT(pev), "models/w_9mmberetta.mdl");
m_iDefaultAmmo = BERETTA_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
void CBeretta::Precache( void )
{
PRECACHE_MODEL("models/v_9mmberetta.mdl");
PRECACHE_MODEL("models/w_9mmberetta.mdl");
PRECACHE_MODEL("models/p_9mmberetta.mdl");
m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell
PRECACHE_SOUND("items/9mmclip1.wav");
PRECACHE_SOUND("items/9mmclip2.wav");
/* PRECACHE_SOUND ("weapons/pl_gun1.wav");//silenced handgun
PRECACHE_SOUND ("weapons/pl_gun2.wav");//silenced handgun
PRECACHE_SOUND ("weapons/pl_gun3.wav");//handgun */
PRECACHE_SOUND ("weapons/beretta_fire1.wav");//single fire Beretta
m_usFireBeretta1 = PRECACHE_EVENT( 1, "events/Beretta1.sc" );
m_usFireBeretta2 = PRECACHE_EVENT( 1, "events/Beretta2.sc" );
}
int CBeretta::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = "9mm";
p->iMaxAmmo1 = _9MM_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = BERETTA_MAX_CLIP;
p->iSlot = 1;
p->iPosition = 2;
p->iFlags = 0;
p->iId = m_iId = WEAPON_BERETTA;
p->iWeight = GLOCK_WEIGHT;
return 1;
}
BOOL CBeretta::Deploy( )
{
// pev->body = 1;
return DefaultDeploy( "models/v_9mmberetta.mdl", "models/p_9mmberetta.mdl", BERETTA_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 );
}
void CBeretta::SecondaryAttack( void )
{
BerettaFire( 0.1, 0.2, FALSE );
}
void CBeretta::PrimaryAttack( void )
{
BerettaFire( 0.01, 0.3, TRUE );
}
void CBeretta::BerettaFire( float flSpread , float flCycleTime, BOOL fUseAutoAim )
{
if (m_iClip <= 0)
{
if (m_fFireOnEmpty)
{
PlayEmptySound();
m_flNextPrimaryAttack = GetNextAttackDelay(0.2);
}
return;
}
m_iClip--;
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
int flags;
#if defined( CLIENT_WEAPONS )
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
// silenced
if (pev->body == 1)
{
m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH;
}
else
{
// non-silenced
m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
}
Vector vecSrc = m_pPlayer->GetGunPosition( );
Vector vecAiming;
if ( fUseAutoAim )
{
vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );
}
else
{
vecAiming = gpGlobals->v_forward;
}
Vector vecDir;
vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_BERETTA, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed );
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);
if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
void CBeretta::Reload( void )
{
if ( m_pPlayer->ammo_9mm <= 0 )
return;
int iResult;
if (m_iClip == 0)
iResult = DefaultReload( 17, BERETTA_RELOAD, 1.5 );
else
iResult = DefaultReload( 17, BERETTA_RELOAD_NOT_EMPTY, 1.5 );
if (iResult)
{
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
}
void CBeretta::WeaponIdle( void )
{
ResetEmptySound( );
m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES );
if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
return;
// only idle if the slid isn't back
if (m_iClip != 0)
{
int iAnim;
float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0, 1.0 );
if (flRand <= 0.3 + 0 * 0.75)
{
iAnim = BERETTA_IDLE3;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 49.0 / 16;
}
else if (flRand <= 0.6 + 0 * 0.875)
{
iAnim = BERETTA_IDLE1;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 16.0;
}
else
{
iAnim = BERETTA_IDLE2;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0;
}
SendWeaponAnim( iAnim, 1 );
}
}

844
dlls/asheep/gordon.cpp Normal file
View File

@ -0,0 +1,844 @@
/***
*
* 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();
}

839
dlls/asheep/hevbarn.cpp Normal file
View File

@ -0,0 +1,839 @@
/***
*
* 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();
}

842
dlls/asheep/kate.cpp Normal file
View File

@ -0,0 +1,842 @@
/***
*
* 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 kate dying for scripted sequences?
#define KATE_AE_DRAW ( 2 )
#define KATE_AE_SHOOT ( 3 )
#define KATE_AE_HOLSTER ( 4 )
#define KATE_BODY_GUNHOLSTERED 0
#define KATE_BODY_GUNDRAWN 1
#define KATE_BODY_GUNGONE 2
class CKate : public CTalkMonster
{
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 );
// 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_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 );
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
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[] =
{
{
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()))
{
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 );
}
}
}
//=========================================================
// SetYawSpeed - allows each sequence to have a different
// turn rate associated with it.
//=========================================================
void CKate :: 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 CKate :: 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;
}
//=========================================================
// KateFirePistol - shoots one round from the pistol at
// the enemy kate is facing.
//=========================================================
void CKate :: KateFirePistol ( 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, "kate/ka_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 CKate :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
switch( pEvent->event )
{
case KATE_AE_SHOOT:
KateFirePistol();
break;
case KATE_AE_DRAW:
// kate's bodygroup switches here so he can pull gun from holster
pev->body = KATE_BODY_GUNDRAWN;
m_fGunDrawn = TRUE;
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 );
}
}
//=========================================================
// Spawn
//=========================================================
void CKate :: Spawn()
{
Precache( );
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->body = 0; // gun in holster
m_fGunDrawn = FALSE;
m_afCapability = bits_CAP_HEAR | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP;
MonsterInit();
SetUse( &CKate::FollowerUse );
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CKate :: Precache()
{
PRECACHE_MODEL("models/kate.mdl");
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_die1.wav");
// PRECACHE_SOUND("kate/ka_die2.wav");
// PRECACHE_SOUND("kate/ka_die3.wav");
// every new kate 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()
{
CTalkMonster::TalkInit();
// scientists speach group names (group names are in sentences.txt)
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_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_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";
// get voice for head - just one kate 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 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 )
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( "KA_MAD", 4, VOL_NORM, ATTN_NORM );
Remember( bits_MEMORY_PROVOKED );
StopFollowing( TRUE );
}
else
{
// Hey, be careful with that
PlaySentence( "KA_SHOT", 4, VOL_NORM, ATTN_NORM );
Remember( bits_MEMORY_SUSPICIOUS );
}
}
else if ( !(m_hEnemy->IsPlayer()) && pev->deadflag == DEAD_NO )
{
PlaySentence( "KA_SHOT", 4, VOL_NORM, ATTN_NORM );
}
}
return ret;
}
//=========================================================
// PainSound
//=========================================================
void CKate :: PainSound ( void )
{
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;
// }
}
//=========================================================
// DeathSound
//=========================================================
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 );
}
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
Schedule_t* CKate :: GetScheduleOfType ( int Type )
{
Schedule_t *psched;
switch( Type )
{
case SCHED_ARM_WEAPON:
if ( m_hEnemy != NULL )
{
// face enemy, then draw.
return slKateEnemyDraw;
}
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)
{
// just look straight ahead.
return slIdleKtStand;
}
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 *CKate :: 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( "KA_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 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();
}

282
dlls/asheep/m41a.cpp Normal file
View File

@ -0,0 +1,282 @@
/***
*
* 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 "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "soundent.h"
#include "gamerules.h"
enum m41a_e
{
M41A_LONGIDLE = 0,
M41A_IDLE1,
M41A_LAUNCH,
M41A_RELOAD,
M41A_DEPLOY,
M41A_FIRE1,
M41A_FIRE2,
//M41A_FIRE3,
};
LINK_ENTITY_TO_CLASS( weapon_9mmm41a, CM41A );
//=========================================================
//=========================================================
int CM41A::SecondaryAmmoIndex( void )
{
return m_iSecondaryAmmoType;
}
void CM41A::Spawn( )
{
pev->classname = MAKE_STRING("weapon_9mmm41a"); // hack to allow for old names
Precache( );
SET_MODEL(ENT(pev), "models/w_9mmm41a.mdl");
m_iId = WEAPON_M41A;
m_iDefaultAmmo = MP5_DEFAULT_GIVE;
FallInit();// get ready to fall down.
}
void CM41A::Precache( void )
{
PRECACHE_MODEL("models/v_9mmM41A.mdl");
PRECACHE_MODEL("models/w_9mmM41A.mdl");
PRECACHE_MODEL("models/p_9mmM41A.mdl");
m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shellTE_MODEL
PRECACHE_MODEL("models/grenade.mdl"); // grenade
PRECACHE_MODEL("models/w_9mmARclip.mdl");
PRECACHE_SOUND("items/9mmclip1.wav");
PRECACHE_SOUND("items/clipinsert1.wav");
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" );
}
int CM41A::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 = 3;
p->iFlags = 0;
p->iId = m_iId = WEAPON_M41A;
p->iWeight = MP5_WEIGHT;
return 1;
}
int CM41A::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 CM41A::Deploy( )
{
return DefaultDeploy( "models/v_9mmm41a.mdl", "models/p_9mmm41a.mdl", M41A_DEPLOY, "M41A" );
}
void CM41A::PrimaryAttack()
{
// don't fire underwater
if (m_pPlayer->pev->waterlevel == 3)
{
PlayEmptySound( );
m_flNextPrimaryAttack = 0.15;
return;
}
if (m_iClip <= 0)
{
PlayEmptySound();
m_flNextPrimaryAttack = 0.15;
return;
}
m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
m_iClip--;
m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH;
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
Vector vecSrc = m_pPlayer->GetGunPosition( );
Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
Vector vecDir;
#ifdef CLIENT_DLL
if ( !bIsMultiplayer() )
#else
if ( !g_pGameRules->IsMultiplayer() )
#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 );
}
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 );
}
int flags;
#if defined( CLIENT_WEAPONS )
flags = FEV_NOTHOST;
#else
flags = 0;
#endif
PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usM41A, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 );
if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
// HEV suit - indicate out of ammo condition
m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
m_flNextPrimaryAttack = GetNextAttackDelay(0.1);
if ( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() )
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
}
void CM41A::SecondaryAttack( void )
{
// don't fire underwater
if (m_pPlayer->pev->waterlevel == 3)
{
PlayEmptySound( );
m_flNextPrimaryAttack = 0.15;
return;
}
if (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] == 0)
{
PlayEmptySound( );
return;
}
m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH;
m_pPlayer->m_iExtraSoundTypes = bits_SOUND_DANGER;
m_pPlayer->m_flStopExtraSoundTime = UTIL_WeaponTimeBase() + 0.2;
m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]--;
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
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 );
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_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);
}
void CM41A::Reload( void )
{
if ( m_pPlayer->ammo_9mm <= 0 )
return;
DefaultReload( MP5_MAX_CLIP, M41A_RELOAD, 1.5 );
}
void CM41A::WeaponIdle( void )
{
ResetEmptySound( );
m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
return;
int iAnim;
switch ( RANDOM_LONG( 0, 1 ) )
{
case 0:
iAnim = M41A_LONGIDLE;
break;
default:
case 1:
iAnim = M41A_IDLE1;
break;
}
SendWeaponAnim( iAnim );
m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); // how long till we do this again.
}

316
dlls/asheep/poolstick.cpp Normal file
View File

@ -0,0 +1,316 @@
/***
*
* 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 "monsters.h"
#include "weapons.h"
#include "nodes.h"
#include "player.h"
#include "gamerules.h"
#define POOLSTICK_BODYHIT_VOLUME 128
#define POOLSTICK_WALLHIT_VOLUME 512
LINK_ENTITY_TO_CLASS( weapon_poolstick, CPoolstick );
enum poolstick_e {
POOLSTICK_IDLE = 0,
POOLSTICK_DRAW,
POOLSTICK_HOLSTER,
POOLSTICK_ATTACK1HIT,
POOLSTICK_ATTACK1MISS,
POOLSTICK_ATTACK2MISS,
POOLSTICK_ATTACK2HIT,
POOLSTICK_ATTACK3MISS,
POOLSTICK_ATTACK3HIT
};
void CPoolstick::Spawn( )
{
Precache( );
m_iId = WEAPON_POOLSTICK;
SET_MODEL(ENT(pev), "models/w_poolstick.mdl");
m_iClip = -1;
FallInit();// get ready to fall down.
}
void CPoolstick::Precache( void )
{
PRECACHE_MODEL("models/v_poolstick.mdl");
PRECACHE_MODEL("models/w_poolstick.mdl");
PRECACHE_MODEL("models/p_poolstick.mdl");
PRECACHE_SOUND("weapons/pstk_hit1.wav");
PRECACHE_SOUND("weapons/pstk_hit2.wav");
PRECACHE_SOUND("weapons/pstk_hitbod1.wav");
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)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = NULL;
p->iMaxAmmo1 = -1;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 0;
p->iPosition = 2;
p->iId = WEAPON_POOLSTICK;
p->iWeight = CROWBAR_WEIGHT;
return 1;
}
BOOL CPoolstick::Deploy( )
{
return DefaultDeploy( "models/v_poolstick.mdl", "models/p_poolstick.mdl", POOLSTICK_DRAW, "poolstick" );
}
void CPoolstick::Holster( int skiplocal /* = 0 */ )
{
m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5;
SendWeaponAnim( POOLSTICK_HOLSTER );
}
void FindHullIntersection2( 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 CPoolstick::PrimaryAttack()
{
if (! Swing( 1 ))
{
SetThink( &CPoolstick::SwingAgain );
pev->nextthink = gpGlobals->time + 0.1;
}
}
void CPoolstick::Smack( )
{
DecalGunshot( &m_trHit, BULLET_PLAYER_POOLSTICK );
}
void CPoolstick::SwingAgain( void )
{
Swing( 0 );
}
int CPoolstick::Swing( int fFirst )
{
int fDidHit = FALSE;
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() )
FindHullIntersection2( 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);
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
}
}
else
{
switch( ((m_iSwing++) % 2) + 1 )
{
case 0:
SendWeaponAnim( POOLSTICK_ATTACK1HIT ); break;
case 1:
SendWeaponAnim( POOLSTICK_ATTACK2HIT ); break;
case 2:
SendWeaponAnim( POOLSTICK_ATTACK3HIT ); break;
}
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
#ifndef CLIENT_DLL
// hit
fDidHit = TRUE;
CBaseEntity *pEntity = CBaseEntity::Instance(tr.pHit);
ClearMultiDamage( );
if ( (m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() )
{
// first swing does full damage
pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgPoolstick, gpGlobals->v_forward, &tr, DMG_CLUB );
}
else
{
// subsequent swings do half
pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgPoolstick / 2, gpGlobals->v_forward, &tr, DMG_CLUB );
}
ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev );
// play thwack, smack, or dong sound
float flVol = 1.0;
int fHitWorld = TRUE;
if (pEntity)
{
if ( pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE )
{
// play thwack or smack sound
switch( RANDOM_LONG(0,2) )
{
case 0:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/pstk_hitbod1.wav", 1, ATTN_NORM); break;
case 1:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/pstk_hitbod2.wav", 1, ATTN_NORM); break;
case 2:
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/pstk_hitbod3.wav", 1, ATTN_NORM); break;
}
m_pPlayer->m_iWeaponVolume = POOLSTICK_BODYHIT_VOLUME;
if ( !pEntity->IsAlive() )
return TRUE;
else
flVol = 0.1;
fHitWorld = FALSE;
}
}
// play texture hit sound
// UNDONE: Calculate the correct point of intersection when we hit with the hull instead of the line
if (fHitWorld)
{
float fvolbar = TEXTURETYPE_PlaySound(&tr, vecSrc, vecSrc + (vecEnd-vecSrc)*2, BULLET_PLAYER_POOLSTICK);
if ( g_pGameRules->IsMultiplayer() )
{
// override the volume here, cause we don't play texture sounds in multiplayer,
// and fvolbar is going to be 0 from the above call.
fvolbar = 1;
}
// also play poolstick strike
switch( RANDOM_LONG(0,1) )
{
case 0:
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/pstk_hit1.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
break;
case 1:
EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/pstk_hit2.wav", fvolbar, ATTN_NORM, 0, 98 + RANDOM_LONG(0,3));
break;
}
// delay the decal a bit
m_trHit = tr;
}
m_pPlayer->m_iWeaponVolume = flVol * POOLSTICK_WALLHIT_VOLUME;
#endif
m_flNextPrimaryAttack = GetNextAttackDelay(0.25);
SetThink( &CPoolstick::Smack );
pev->nextthink = UTIL_WeaponTimeBase() + 0.2;
}
return fDidHit;
}

2585
dlls/asheep/spforce.cpp Normal file

File diff suppressed because it is too large Load Diff

2517
dlls/asheep/terror.cpp Normal file

File diff suppressed because it is too large Load Diff

604
dlls/asheep/toad.cpp Normal file
View File

@ -0,0 +1,604 @@
/***
*
* 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.
*
****/
#if !defined( OEM_BUILD ) && !defined( HLDEMO_BUILD )
#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 w_toad_e {
WTOAD_IDLE1 = 0,
WTOAD_FIDGET,
WTOAD_JUMP,
WTOAD_RUN,
};
enum toad_e {
TOAD_IDLE1 = 0,
TOAD_FIDGETFIT,
TOAD_FIDGETNIP,
TOAD_DOWN,
TOAD_UP,
TOAD_THROW
};
#ifndef CLIENT_DLL
class CToadGrenade : public CGrenade
{
void Spawn( void );
void Precache( void );
int Classify( void );
void EXPORT SuperBounceTouch( CBaseEntity *pOther );
void EXPORT HuntThink( void );
int BloodColor( void ) { return BLOOD_COLOR_YELLOW; }
void Killed( entvars_t *pevAttacker, int iGib );
// void GibMonster( void );
virtual int Save( CSave &save );
virtual int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
static float m_flNextBounceSoundTime;
// CBaseEntity *m_pTarget;
float m_flDie;
Vector m_vecTarget;
float m_flNextHunt;
float m_flNextHit;
Vector m_posPrev;
EHANDLE m_hOwner;
int m_iMyClass;
};
float CToadGrenade::m_flNextBounceSoundTime = 0;
LINK_ENTITY_TO_CLASS( monster_toad, CToadGrenade );
TYPEDESCRIPTION CToadGrenade::m_SaveData[] =
{
DEFINE_FIELD( CToadGrenade, m_flDie, FIELD_TIME ),
DEFINE_FIELD( CToadGrenade, m_vecTarget, FIELD_VECTOR ),
DEFINE_FIELD( CToadGrenade, m_flNextHunt, FIELD_TIME ),
DEFINE_FIELD( CToadGrenade, m_flNextHit, FIELD_TIME ),
DEFINE_FIELD( CToadGrenade, m_posPrev, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( CToadGrenade, m_hOwner, FIELD_EHANDLE ),
};
IMPLEMENT_SAVERESTORE( CToadGrenade, CGrenade );
#define TOAD_DETONATE_DELAY 15.0
int CToadGrenade :: Classify ( void )
{
if (m_iMyClass != 0)
return m_iMyClass; // protect against recursion
if (m_hEnemy != NULL)
{
m_iMyClass = CLASS_INSECT; // no one cares about it
switch( m_hEnemy->Classify( ) )
{
case CLASS_PLAYER:
case CLASS_HUMAN_PASSIVE:
case CLASS_HUMAN_MILITARY:
m_iMyClass = 0;
return CLASS_ALIEN_MILITARY; // barney's get mad, grunts get mad at it
}
m_iMyClass = 0;
}
return CLASS_ALIEN_BIOWEAPON;
}
void CToadGrenade :: Spawn( void )
{
Precache( );
// motor
pev->movetype = MOVETYPE_BOUNCE;
pev->solid = SOLID_BBOX;
SET_MODEL(ENT(pev), "models/w_toad.mdl");
UTIL_SetSize(pev, Vector( -4, -4, 0), Vector(4, 4, 8));
UTIL_SetOrigin( pev, pev->origin );
SetTouch( &CToadGrenade::SuperBounceTouch );
SetThink( &CToadGrenade::HuntThink );
pev->nextthink = gpGlobals->time + 0.1;
m_flNextHunt = gpGlobals->time + 1E6;
pev->flags |= FL_MONSTER;
pev->takedamage = DAMAGE_AIM;
pev->health = gSkillData.toadHealth;
pev->gravity = 0.5;
pev->friction = 0.5;
pev->dmg = gSkillData.toadDmgPop;
m_flDie = gpGlobals->time + TOAD_DETONATE_DELAY;
m_flFieldOfView = 0; // 180 degrees
if ( pev->owner )
m_hOwner = Instance( pev->owner );
m_flNextBounceSoundTime = gpGlobals->time;// reset each time a snark is spawned.
pev->sequence = WTOAD_RUN;
ResetSequenceInfo( );
}
void CToadGrenade::Precache( void )
{
PRECACHE_MODEL("models/w_toad.mdl");
PRECACHE_SOUND("toad/toad_blast1.wav");
// PRECACHE_SOUND("common/bodysplat.wav");
PRECACHE_SOUND("toad/toad_die1.wav");
PRECACHE_SOUND("toad/toad_hunt1.wav");
PRECACHE_SOUND("toad/toad_hunt2.wav");
PRECACHE_SOUND("toad/toad_hunt3.wav");
PRECACHE_SOUND("toad/toad_deploy1.wav");
}
void CToadGrenade :: Killed( entvars_t *pevAttacker, int iGib )
{
pev->model = iStringNull;// make invisible
SetThink( &CToadGrenade::SUB_Remove );
// ResetTouch( );
SetTouch( NULL );
pev->nextthink = gpGlobals->time + 0.1;
// since toad grenades never leave a body behind, clear out their takedamage now.
// Squeaks do a bit of radius damage when they pop, and that radius damage will
// continue to call this function unless we acknowledge the Squeak's death now. (sjb)
pev->takedamage = DAMAGE_NO;
// play squeek blast
EMIT_SOUND_DYN(ENT(pev), CHAN_ITEM, "squeek/toad_blast1.wav", 1, 0.5, 0, PITCH_NORM);
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, SMALL_EXPLOSION_VOLUME, 3.0 );
UTIL_BloodDrips( pev->origin, g_vecZero, BloodColor(), 80 );
if (m_hOwner != NULL)
RadiusDamage ( pev, m_hOwner->pev, pev->dmg, CLASS_NONE, DMG_BLAST );
else
RadiusDamage ( pev, pev, pev->dmg, CLASS_NONE, DMG_BLAST );
// reset owner so death message happens
if (m_hOwner != NULL)
pev->owner = m_hOwner->edict();
CBaseMonster :: Killed( pevAttacker, GIB_ALWAYS );
}
/* void CToadGrenade :: GibMonster( void )
{
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "common/bodysplat.wav", 0.75, ATTN_NORM, 0, 200);
} */
void CToadGrenade::HuntThink( void )
{
// ALERT( at_console, "think\n" );
if (!IsInWorld())
{
// ResetTouch( );
SetTouch( NULL );
UTIL_Remove( this );
return;
}
StudioFrameAdvance( );
pev->nextthink = gpGlobals->time + 0.1;
// explode when ready
if (gpGlobals->time >= m_flDie)
{
g_vecAttackDir = pev->velocity.Normalize( );
pev->health = -1;
Killed( pev, 0 );
return;
}
// float
if (pev->waterlevel != 0)
{
if (pev->movetype == MOVETYPE_BOUNCE)
{
pev->movetype = MOVETYPE_FLY;
}
pev->velocity = pev->velocity * 0.9;
pev->velocity.z += 8.0;
}
else if (pev->movetype = MOVETYPE_FLY)
{
pev->movetype = MOVETYPE_BOUNCE;
}
// return if not time to hunt
if (m_flNextHunt > gpGlobals->time)
return;
m_flNextHunt = gpGlobals->time + 2.0;
CBaseEntity *pOther = NULL;
Vector vecDir;
TraceResult tr;
Vector vecFlat = pev->velocity;
vecFlat.z = 0;
vecFlat = vecFlat.Normalize( );
UTIL_MakeVectors( pev->angles );
if (m_hEnemy == NULL || !m_hEnemy->IsAlive())
{
// find target, bounce a bit towards it.
Look( 512 );
m_hEnemy = BestVisibleEnemy( );
}
// 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));
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 256, 0.25 );
}
// higher pitch as squeeker gets closer to detonation time
float flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / TOAD_DETONATE_DELAY);
if (flpitch < 80)
flpitch = 80;
if (m_hEnemy != NULL)
{
if (FVisible( m_hEnemy ))
{
vecDir = m_hEnemy->EyePosition() - pev->origin;
m_vecTarget = vecDir.Normalize( );
}
float flVel = pev->velocity.Length();
float flAdj = 50.0 / (flVel + 10.0);
if (flAdj > 1.2)
flAdj = 1.2;
// ALERT( at_console, "think : enemy\n");
// ALERT( at_console, "%.0f %.2f %.2f %.2f\n", flVel, m_vecTarget.x, m_vecTarget.y, m_vecTarget.z );
pev->velocity = pev->velocity * flAdj + m_vecTarget * 300;
}
if (pev->flags & FL_ONGROUND)
{
pev->avelocity = Vector( 0, 0, 0 );
}
else
{
if (pev->avelocity == Vector( 0, 0, 0))
{
pev->avelocity.x = RANDOM_FLOAT( -100, 100 );
pev->avelocity.z = RANDOM_FLOAT( -100, 100 );
}
}
if ((pev->origin - m_posPrev).Length() < 1.0)
{
pev->velocity.x = RANDOM_FLOAT( -100, 100 );
pev->velocity.y = RANDOM_FLOAT( -100, 100 );
}
m_posPrev = pev->origin;
pev->angles = UTIL_VecToAngles( pev->velocity );
pev->angles.z = 0;
pev->angles.x = 0;
}
void CToadGrenade::SuperBounceTouch( CBaseEntity *pOther )
{
float flpitch;
TraceResult tr = UTIL_GetGlobalTrace( );
// don't hit the guy that launched this grenade
if ( pev->owner && pOther->edict() == pev->owner )
return;
// at least until we've bounced once
pev->owner = NULL;
pev->angles.x = 0;
pev->angles.z = 0;
// avoid bouncing too much
if (m_flNextHit > gpGlobals->time)
return;
// higher pitch as squeeker gets closer to detonation time
flpitch = 155.0 - 60.0 * ((m_flDie - gpGlobals->time) / TOAD_DETONATE_DELAY);
if ( pOther->pev->takedamage && m_flNextAttack < gpGlobals->time )
{
// attack!
// make sure it's me who has touched them
if (tr.pHit == pOther->edict())
{
// and it's not another toadgrenade
if (tr.pHit->v.modelindex != pev->modelindex)
{
// ALERT( at_console, "hit enemy\n");
ClearMultiDamage( );
pOther->TraceAttack(pev, gSkillData.toadDmgBite, gpGlobals->v_forward, &tr, DMG_SLASH );
if (m_hOwner != NULL)
ApplyMultiDamage( pev, m_hOwner->pev );
else
ApplyMultiDamage( pev, pev );
pev->dmg += gSkillData.toadDmgPop; // add more explosion damage
// 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);
m_flNextAttack = gpGlobals->time + 0.5;
}
}
else
{
// ALERT( at_console, "been hit\n");
}
}
m_flNextHit = gpGlobals->time + 0.1;
m_flNextHunt = gpGlobals->time;
if ( g_pGameRules->IsMultiplayer() )
{
// in multiplayer, we limit how often snarks can make their bounce sounds to prevent overflows.
if ( gpGlobals->time < m_flNextBounceSoundTime )
{
// too soon!
return;
}
}
if (!(pev->flags & FL_ONGROUND))
{
// play bounce sound
float flRndSound = RANDOM_FLOAT ( 0 , 1 );
if ( flRndSound <= 0.33 )
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "toad/toad_hunt1.wav", 1, ATTN_NORM, 0, (int)flpitch);
else if (flRndSound <= 0.66)
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "toad/toad_hunt2.wav", 1, ATTN_NORM, 0, (int)flpitch);
else
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "toad/toad_hunt3.wav", 1, ATTN_NORM, 0, (int)flpitch);
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 256, 0.25 );
}
else
{
// skittering sound
CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, 100, 0.1 );
}
m_flNextBounceSoundTime = gpGlobals->time + 0.5;// half second.
}
#endif
LINK_ENTITY_TO_CLASS( weapon_toad, CToad );
void CToad::Spawn( )
{
Precache( );
m_iId = WEAPON_TOAD;
SET_MODEL(ENT(pev), "models/toad_nest.mdl");
FallInit();//get ready to fall down.
m_iDefaultAmmo = SNARK_DEFAULT_GIVE;
pev->sequence = 1;
pev->animtime = gpGlobals->time;
pev->framerate = 1.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" );
}
int CToad::GetItemInfo(ItemInfo *p)
{
p->pszName = STRING(pev->classname);
p->pszAmmo1 = "Toads";
p->iMaxAmmo1 = TOAD_MAX_CARRY;
p->pszAmmo2 = NULL;
p->iMaxAmmo2 = -1;
p->iMaxClip = WEAPON_NOCLIP;
p->iSlot = 4;
p->iPosition = 4;
p->iId = m_iId = WEAPON_TOAD;
p->iWeight = SNARK_WEIGHT;
p->iFlags = ITEM_FLAG_LIMITINWORLD | ITEM_FLAG_EXHAUSTIBLE;
return 1;
}
BOOL CToad::Deploy( )
{
// 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);
m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
return DefaultDeploy( "models/v_toad.mdl", "models/p_toad.mdl", TOAD_UP, "toad" );
}
void CToad::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_TOAD);
SetThink( &CToad::DestroyItem );
pev->nextthink = gpGlobals->time + 0.1;
return;
}
SendWeaponAnim( TOAD_DOWN );
EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM);
}
void CToad::PrimaryAttack()
{
if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] )
{
UTIL_MakeVectors( m_pPlayer->pev->v_angle );
TraceResult tr;
Vector trace_origin;
// HACK HACK: Ugly hacks to handle change in origin based on new physics code for players
// Move origin up if crouched and start trace a bit outside of body ( 20 units instead of 16 )
trace_origin = m_pPlayer->pev->origin;
if ( m_pPlayer->pev->flags & FL_DUCKING )
{
trace_origin = trace_origin - ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN );
}
// 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 )
{
// player "shoot" animation
m_pPlayer->SetAnimation( PLAYER_ATTACK1 );
#ifndef CLIENT_DLL
CBaseEntity *pToad = CBaseEntity::Create( "monster_toad", tr.vecEndPos, m_pPlayer->pev->v_angle, m_pPlayer->edict() );
pToad->pev->velocity = gpGlobals->v_forward * 200 + m_pPlayer->pev->velocity;
#endif
// 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, 105);
else
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "toad/toad_hunt3.wav", 1, ATTN_NORM, 0, 105);
m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME;
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;
m_fJustThrown = 1;
m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0;
}
}
}
void CToad::SecondaryAttack( void )
{
}
void CToad::WeaponIdle( void )
{
if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() )
return;
if (m_fJustThrown)
{
m_fJustThrown = 0;
if ( !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] )
{
RetireWeapon();
return;
}
SendWeaponAnim( TOAD_UP );
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );
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)
{
iAnim = TOAD_FIDGETFIT;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 70.0 / 16.0;
}
else
{
iAnim = TOAD_FIDGETNIP;
m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 16.0;
}
SendWeaponAnim( iAnim );
}
#endif

View File

@ -616,7 +616,7 @@ void CBarney::Killed( entvars_t *pevAttacker, int iGib )
GetAttachment( 0, vecGunPos, vecGunAngles );
DropItem( "weapon_9mmhandgun", vecGunPos, vecGunAngles );
DropItem( "weapon_barney9mmhg", vecGunPos, vecGunAngles ); // edit Alex, in Azure Sheep entity is named another way
}
SetUse( NULL );

View File

@ -58,6 +58,13 @@ const char *CBreakable::pSpawnObjects[] =
"weapon_satchel", // 19
"weapon_snark", // 20
"weapon_hornetgun", // 21
//begin Alex
"weapon_9mmm41a", // 22
//"weapon_kmedkit", // 23
"weapon_beretta", // 24
"weapon_toad", // 25
"weapon_poolstick", // 26
// end Alex
};
void CBreakable::KeyValue( KeyValueData* pkvd )

View File

@ -276,7 +276,29 @@ cvar_t sk_sentry_health1 = {"sk_sentry_health1","0"};
cvar_t sk_sentry_health2 = {"sk_sentry_health2","0"};
cvar_t sk_sentry_health3 = {"sk_sentry_health3","0"};
// PLAYER WEAPONS
// Alex begin
// Kate
cvar_t sk_kate_health1 = {"sk_kate_health1","0"};
cvar_t sk_kate_health2 = {"sk_kate_health2","0"};
cvar_t sk_kate_health3 = {"sk_kate_health3","0"};
// Panther
cvar_t sk_panther_health1 = {"sk_panther_health1","0"};
cvar_t sk_panther_health2 = {"sk_panther_health2","0"};
cvar_t sk_panther_health3 = {"sk_panther_health3","0"};
cvar_t sk_panther_dmg_claw1 = {"sk_panther_dmg_claw1","0"};
cvar_t sk_panther_dmg_claw2 = {"sk_panther_dmg_claw2","0"};
cvar_t sk_panther_dmg_claw3 = {"sk_panther_dmg_claw3","0"};
cvar_t sk_panther_dmg_clawrake1 = {"sk_panther_dmg_clawrake1","0"};
cvar_t sk_panther_dmg_clawrake2 = {"sk_panther_dmg_clawrake2","0"};
cvar_t sk_panther_dmg_clawrake3 = {"sk_panther_dmg_clawrake3","0"};
cvar_t sk_panther_dmg_zap1 = {"sk_panther_dmg_zap1","0"};
cvar_t sk_panther_dmg_zap2 = {"sk_panther_dmg_zap2","0"};
cvar_t sk_panther_dmg_zap3 = {"sk_panther_dmg_zap3","0"};
// end Alex
// Crowbar whack
cvar_t sk_plr_crowbar1 = {"sk_plr_crowbar1","0"};
@ -360,6 +382,44 @@ cvar_t sk_plr_tripmine1 = {"sk_plr_tripmine1","0"};
cvar_t sk_plr_tripmine2 = {"sk_plr_tripmine2","0"};
cvar_t sk_plr_tripmine3 = {"sk_plr_tripmine3","0"};
// Alex begin
// Toad
cvar_t sk_toad_health1 = {"sk_toad_health1","0"};
cvar_t sk_toad_health2 = {"sk_toad_health2","0"};
cvar_t sk_toad_health3 = {"sk_toad_health3","0"};
cvar_t sk_toad_dmg_bite1 = {"sk_toad_dmg_bite1","0"};
cvar_t sk_toad_dmg_bite2 = {"sk_toad_dmg_bite2","0"};
cvar_t sk_toad_dmg_bite3 = {"sk_toad_dmg_bite3","0"};
cvar_t sk_toad_dmg_pop1 = {"sk_toad_dmg_pop1","0"};
cvar_t sk_toad_dmg_pop2 = {"sk_toad_dmg_pop2","0"};
cvar_t sk_toad_dmg_pop3 = {"sk_toad_dmg_pop3","0"};
// Alex end
//Alex begin
// poolstick
cvar_t sk_plr_poolstick1 = {"sk_plr_poolstick1","0"};
cvar_t sk_plr_poolstick2 = {"sk_plr_poolstick2","0"};
cvar_t sk_plr_poolstick3 = {"sk_plr_poolstick3","0"};
//Alex end
//Alex
// beretta Round
cvar_t sk_plr_beretta_bullet1 = {"sk_plr_beretta_bullet1","0"};
cvar_t sk_plr_beretta_bullet2 = {"sk_plr_beretta_bullet2","0"};
cvar_t sk_plr_beretta_bullet3 = {"sk_plr_beretta_bullet3","0"};
// 9mmm41a Round
cvar_t sk_plr_9mmM41A_bullet1 = {"sk_plr_9mmM41A_bullet1","0"};
cvar_t sk_plr_9mmM41A_bullet2 = {"sk_plr_9mmM41A_bullet2","0"};
cvar_t sk_plr_9mmM41A_bullet3 = {"sk_plr_9mmM41A_bullet3","0"};
// 9mmm41a Grenade
cvar_t sk_plr_9mmM41A_grenade1 = {"sk_plr_9mmM41A_grenade1","0"};
cvar_t sk_plr_9mmM41A_grenade2 = {"sk_plr_9mmM41A_grenade2","0"};
cvar_t sk_plr_9mmM41A_grenade3 = {"sk_plr_9mmM41A_grenade3","0"};
// Alex
// WORLD WEAPONS
cvar_t sk_12mm_bullet1 = {"sk_12mm_bullet1","0"};
@ -700,6 +760,27 @@ void GameDLLInit( void )
CVAR_REGISTER( &sk_sentry_health2 );// {"sk_sentry_health2","0"};
CVAR_REGISTER( &sk_sentry_health3 );// {"sk_sentry_health3","0"};
// Kate
CVAR_REGISTER ( &sk_kate_health1 );// {"sk_barney_health1","0"};
CVAR_REGISTER ( &sk_kate_health2 );// {"sk_barney_health2","0"};
CVAR_REGISTER ( &sk_kate_health3 );// {"sk_barney_health3","0"};
// Panther
CVAR_REGISTER( &sk_panther_health1 );// {"sk_panther_health1","0"};
CVAR_REGISTER( &sk_panther_health2 );// {"sk_panther_health2","0"};
CVAR_REGISTER( &sk_panther_health3 );// {"sk_panther_health3","0"};
CVAR_REGISTER( &sk_panther_dmg_claw1 );// {"sk_panther_dmg_claw1","0"};
CVAR_REGISTER( &sk_panther_dmg_claw2 );// {"sk_panther_dmg_claw2","0"};
CVAR_REGISTER( &sk_panther_dmg_claw3 );// {"sk_panther_dmg_claw3","0"};
CVAR_REGISTER( &sk_panther_dmg_clawrake1 );// {"sk_panther_dmg_clawrake1","0"};
CVAR_REGISTER( &sk_panther_dmg_clawrake2 );// {"sk_panther_dmg_clawrake2","0"};
CVAR_REGISTER( &sk_panther_dmg_clawrake3 );// {"sk_panther_dmg_clawrake3","0"};
CVAR_REGISTER( &sk_panther_dmg_zap1 );// {"sk_panther_dmg_zap1","0"};
CVAR_REGISTER( &sk_panther_dmg_zap2 );// {"sk_panther_dmg_zap2","0"};
CVAR_REGISTER( &sk_panther_dmg_zap3 );// {"sk_panther_dmg_zap3","0"};
// PLAYER WEAPONS
@ -776,6 +857,41 @@ void GameDLLInit( void )
CVAR_REGISTER( &sk_plr_tripmine2 );// {"sk_plr_tripmine2","0"};
CVAR_REGISTER( &sk_plr_tripmine3 );// {"sk_plr_tripmine3","0"};
// Alex begin
// Toad
CVAR_REGISTER( &sk_toad_health1 );// {"sk_toad_health1","0"};
CVAR_REGISTER( &sk_toad_health2 );// {"sk_toad_health2","0"};
CVAR_REGISTER( &sk_toad_health3 );// {"sk_toad_health3","0"};
CVAR_REGISTER( &sk_toad_dmg_bite1 );// {"sk_toad_dmg_bite1","0"};
CVAR_REGISTER( &sk_toad_dmg_bite2 );// {"sk_toad_dmg_bite2","0"};
CVAR_REGISTER( &sk_toad_dmg_bite3 );// {"sk_toad_dmg_bite3","0"};
CVAR_REGISTER( &sk_toad_dmg_pop1 );// {"sk_snark_dmg_pop1","0"};
CVAR_REGISTER( &sk_toad_dmg_pop2 );// {"sk_snark_dmg_pop2","0"};
CVAR_REGISTER( &sk_toad_dmg_pop3 );// {"sk_snark_dmg_pop3","0"};
// Alex end
// Poolstick
CVAR_REGISTER( &sk_plr_poolstick1 );// {"sk_plr_crowbar1","0"};
CVAR_REGISTER( &sk_plr_poolstick2 );// {"sk_plr_crowbar2","0"};
CVAR_REGISTER( &sk_plr_poolstick3 );// {"sk_plr_crowbar3","0"};
// Beretta Round
CVAR_REGISTER( &sk_plr_beretta_bullet1 );// {"sk_plr_beretta_bullet1","0"};
CVAR_REGISTER( &sk_plr_beretta_bullet2 );// {"sk_plr_beretta_bullet2","0"};
CVAR_REGISTER( &sk_plr_beretta_bullet3 );// {"sk_plr_beretta_bullet3","0"};
// M41A Round
CVAR_REGISTER( &sk_plr_9mmM41A_bullet1 );// {"sk_plr_9mmm41a_bullet1","0"};
CVAR_REGISTER( &sk_plr_9mmM41A_bullet2 );// {"sk_plr_9mmm41a_bullet2","0"};
CVAR_REGISTER( &sk_plr_9mmM41A_bullet3 );// {"sk_plr_9mmm41a_bullet3","0"};
// M41A M203 grenade
CVAR_REGISTER( &sk_plr_9mmM41A_grenade1 );// {"sk_plr_9mmAR_grenade1","0"};
CVAR_REGISTER( &sk_plr_9mmM41A_grenade2 );// {"sk_plr_9mmAR_grenade2","0"};
CVAR_REGISTER( &sk_plr_9mmM41A_grenade3 );// {"sk_plr_9mmAR_grenade3","0"};
// WORLD WEAPONS
CVAR_REGISTER( &sk_12mm_bullet1 );// {"sk_12mm_bullet1","0"};
CVAR_REGISTER( &sk_12mm_bullet2 );// {"sk_12mm_bullet2","0"};

View File

@ -140,6 +140,9 @@ void CGameRules::RefreshSkillData ( void )
// Barney
gSkillData.barneyHealth = GetSkillCvar( "sk_barney_health" );
// Kate
gSkillData.kateHealth = GetSkillCvar( "sk_kate_health" );
// Big Momma
gSkillData.bigmommaHealthFactor = GetSkillCvar( "sk_bigmomma_health_factor" );
gSkillData.bigmommaDmgSlash = GetSkillCvar( "sk_bigmomma_dmg_slash" );
@ -200,6 +203,12 @@ void CGameRules::RefreshSkillData ( void )
gSkillData.nihilanthHealth = GetSkillCvar( "sk_nihilanth_health" );
gSkillData.nihilanthZap = GetSkillCvar( "sk_nihilanth_zap" );
// Panther
gSkillData.pantherHealth = GetSkillCvar( "sk_panther_health" );
gSkillData.pantherDmgClaw = GetSkillCvar( "sk_panther_dmg_claw" );
gSkillData.pantherDmgClawRake = GetSkillCvar( "sk_panther_dmg_clawrake" );
gSkillData.pantherDmgZap = GetSkillCvar( "sk_panther_dmg_zap" );
// Scientist
gSkillData.scientistHealth = GetSkillCvar( "sk_scientist_health" );
@ -265,6 +274,21 @@ void CGameRules::RefreshSkillData ( void )
// Tripmine
gSkillData.plrDmgTripmine = GetSkillCvar( "sk_plr_tripmine" );
// Alex begin
// Toad
gSkillData.toadHealth = GetSkillCvar( "sk_toad_health" );
gSkillData.toadDmgBite = GetSkillCvar( "sk_toad_dmg_bite" );
gSkillData.toadDmgPop = GetSkillCvar( "sk_toad_dmg_pop" );
// Alex end
// M41A
gSkillData.plrDmgM41A = GetSkillCvar( "sk_plr_9mmM41A_bullet" );// Alex
gSkillData.plrDmgPoolstick = GetSkillCvar( "sk_plr_poolstick" );// Alex
gSkillData.plrDmgBeretta = GetSkillCvar( "sk_plr_beretta_bullet" );// Alex
// M203 grenade for M41A
gSkillData.plrDmgM41AGrenade = GetSkillCvar( "sk_plr_9mmM41A_grenade");
// MONSTER WEAPONS
gSkillData.monDmg12MM = GetSkillCvar( "sk_12mm_bullet" );
gSkillData.monDmgMP5 = GetSkillCvar ("sk_9mmAR_bullet" );

View File

@ -37,10 +37,10 @@ enum glock_e
LINK_ENTITY_TO_CLASS( weapon_glock, CGlock )
LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock )
LINK_ENTITY_TO_CLASS( weapon_barney9mmnh, CGlock )
void CGlock::Spawn()
{
pev->classname = MAKE_STRING( "weapon_9mmhandgun" ); // hack to allow for old names
pev->classname = MAKE_STRING( "weapon_barney9mmhg" ); // 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_9mmhandgun.mdl" );
PRECACHE_MODEL( "models/v_barney9mmhg.mdl" );
PRECACHE_MODEL( "models/w_9mmhandgun.mdl" );
PRECACHE_MODEL( "models/p_9mmhandgun.mdl" );
@ -101,7 +101,7 @@ int CGlock::AddToPlayer( CBasePlayer *pPlayer )
BOOL CGlock::Deploy()
{
// pev->body = 1;
return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 );
return DefaultDeploy( "models/v_barney9mmhg.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 );
}
void CGlock::SecondaryAttack( void )

View File

@ -36,6 +36,7 @@ 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,7 +55,7 @@ void CHandGrenade::Spawn()
void CHandGrenade::Precache( void )
{
PRECACHE_MODEL( "models/w_grenade.mdl" );
PRECACHE_MODEL( "models/v_grenade.mdl" );
PRECACHE_MODEL( "models/v_barneygrenade.mdl" );
PRECACHE_MODEL( "models/p_grenade.mdl" );
}
@ -78,7 +79,7 @@ int CHandGrenade::GetItemInfo( ItemInfo *p )
BOOL CHandGrenade::Deploy()
{
m_flReleaseThrow = -1;
return DefaultDeploy( "models/v_grenade.mdl", "models/p_grenade.mdl", HANDGRENADE_DRAW, "crowbar" );
return DefaultDeploy( "models/v_barneygrenade.mdl", "models/p_grenade.mdl", HANDGRENADE_DRAW, "crowbar" );
}
BOOL CHandGrenade::CanHolster( void )

View File

@ -96,6 +96,7 @@ public:
};
LINK_ENTITY_TO_CLASS( monster_alien_slave, CISlave )
LINK_ENTITY_TO_CLASS( monster_exp_alien_slave, CISlave )//new Azure Sheep vortigaunt
LINK_ENTITY_TO_CLASS( monster_vortigaunt, CISlave )
TYPEDESCRIPTION CISlave::m_SaveData[] =
@ -508,7 +509,11 @@ void CISlave::Spawn()
{
Precache();
SET_MODEL( ENT( pev ), "models/islave.mdl" );
if( FClassNameIs( pev, "monster_exp_alien_slave" ) )
SET_MODEL( ENT( pev ), "models/sslave.mdl" );
else
SET_MODEL( ENT( pev ), "models/islave.mdl" );
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
pev->solid = SOLID_SLIDEBOX;
@ -534,6 +539,7 @@ void CISlave::Precache()
size_t i;
PRECACHE_MODEL( "models/islave.mdl" );
PRECACHE_MODEL( "models/sslave.mdl" );//violet Aslave
PRECACHE_MODEL( "sprites/lgtning.spr" );
PRECACHE_SOUND( "debris/zap1.wav" );
PRECACHE_SOUND( "debris/zap4.wav" );

View File

@ -199,6 +199,9 @@ class CItemSuit : public CItem
};
LINK_ENTITY_TO_CLASS( item_suit, CItemSuit )
//begin Alex
LINK_ENTITY_TO_CLASS( item_armor, CItemSuit ) // for Azure Sheep
//end Alex
class CItemBattery : public CItem
{

View File

@ -37,6 +37,7 @@ enum mp5_e
LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 )
LINK_ENTITY_TO_CLASS( weapon_9mmAR, CMP5 )
LINK_ENTITY_TO_CLASS( weapon_barney9mmar, CMP5 )
//=========================================================
//=========================================================
@ -47,7 +48,7 @@ int CMP5::SecondaryAmmoIndex( void )
void CMP5::Spawn()
{
pev->classname = MAKE_STRING( "weapon_9mmAR" ); // hack to allow for old names
pev->classname = MAKE_STRING( "weapon_barney9mmar" ); // hack to allow for old names
Precache();
SET_MODEL( ENT( pev ), "models/w_9mmAR.mdl" );
m_iId = WEAPON_MP5;
@ -59,7 +60,7 @@ void CMP5::Spawn()
void CMP5::Precache( void )
{
PRECACHE_MODEL( "models/v_9mmAR.mdl" );
PRECACHE_MODEL( "models/v_barney9mmar.mdl" );
PRECACHE_MODEL( "models/w_9mmAR.mdl" );
PRECACHE_MODEL( "models/p_9mmAR.mdl" );
@ -117,7 +118,7 @@ int CMP5::AddToPlayer( CBasePlayer *pPlayer )
BOOL CMP5::Deploy()
{
return DefaultDeploy( "models/v_9mmAR.mdl", "models/p_9mmAR.mdl", MP5_DEPLOY, "mp5" );
return DefaultDeploy( "models/v_barney9mmAR.mdl", "models/p_9mmAR.mdl", MP5_DEPLOY, "mp5" );
}
void CMP5::PrimaryAttack()

View File

@ -145,15 +145,27 @@ void CHalfLifeMultiplay::RefreshSkillData( void )
// Crowbar whack
gSkillData.plrDmgCrowbar = 25;
// Poolstick
gSkillData.plrDmgPoolstick = 10;//Alex
// Glock Round
gSkillData.plrDmg9MM = 12;
// Beretta Round
gSkillData.plrDmgBeretta = 10;
// 357 Round
gSkillData.plrDmg357 = 40;
// MP5 Round
gSkillData.plrDmgMP5 = 12;
// M41A Round
gSkillData.plrDmgM41A = 8;
// M41A M203 grenade
gSkillData.plrDmgM41AGrenade = 105;
// M203 grenade
gSkillData.plrDmgM203Grenade = 100;

View File

@ -3448,14 +3448,14 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse )
GiveNamedItem( "item_suit" );
GiveNamedItem( "item_battery" );
GiveNamedItem( "weapon_crowbar" );
GiveNamedItem( "weapon_9mmhandgun" );
GiveNamedItem( "weapon_barney9mmhg" ); // Alex for new 9mm handgun
GiveNamedItem( "ammo_9mmclip" );
GiveNamedItem( "weapon_shotgun" );
GiveNamedItem( "weapon_barneyshotgun" ); // Alex for new shotgun
GiveNamedItem( "ammo_buckshot" );
GiveNamedItem( "weapon_9mmAR" );
GiveNamedItem( "weapon_barney9mmar" ); // Alex for new 9mm ar
GiveNamedItem( "ammo_9mmAR" );
GiveNamedItem( "ammo_ARgrenades" );
GiveNamedItem( "weapon_handgrenade" );
GiveNamedItem( "weapon_barneyhandgrenade" ); // Alex for new handgrenade
GiveNamedItem( "weapon_tripmine" );
#ifndef OEM_BUILD
GiveNamedItem( "weapon_357" );

View File

@ -119,6 +119,7 @@ private:
};
LINK_ENTITY_TO_CLASS( monster_scientist, CScientist )
LINK_ENTITY_TO_CLASS( monster_worker, CScientist ) // Alex
TYPEDESCRIPTION CScientist::m_SaveData[] =
{
@ -638,8 +639,11 @@ 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 ), "models/scientist.mdl" );
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
pev->solid = SOLID_SLIDEBOX;
@ -676,7 +680,11 @@ void CScientist::Spawn( void )
//=========================================================
void CScientist::Precache( void )
{
PRECACHE_MODEL( "models/scientist.mdl" );
if( FClassnameIs( pev, "monster_worker" ) )
PRECACHE_MODEL( "models/gus.mdl" );
else
PRECACHE_MODEL( "models/scientist.mdl" );
PRECACHE_SOUND( "scientist/sci_pain1.wav" );
PRECACHE_SOUND( "scientist/sci_pain2.wav" );
PRECACHE_SOUND( "scientist/sci_pain3.wav" );
@ -1052,7 +1060,10 @@ MONSTERSTATE CScientist::GetIdealState( void )
}
BOOL CScientist::CanHeal( void )
{
{
if( FClassnameIs( pev, "monster_worker" ) )
return FALSE;
if( ( m_healTime > gpGlobals->time ) || ( m_hTargetEnt == 0 ) || ( m_hTargetEnt->pev->health > ( m_hTargetEnt->pev->max_health * 0.5 ) ) )
return FALSE;
@ -1127,9 +1138,16 @@ LINK_ENTITY_TO_CLASS( monster_scientist_dead, CDeadScientist )
//
void CDeadScientist::Spawn()
{
PRECACHE_MODEL( "models/scientist.mdl" );
SET_MODEL( ENT( pev ), "models/scientist.mdl" );
if( FClassnameIs( pev, "monster_worker" ) )
{
PRECACHE_MODEL( "models/gus.mdl" );
SET_MODEL( ENT( pev ), "models/gus.mdl" );
}
else
{
PRECACHE_MODEL( "models/scientist.mdl" );
SET_MODEL( ENT( pev ), "models/scientist.mdl" );
}
pev->effects = 0;
pev->sequence = 0;

View File

@ -41,6 +41,7 @@ enum shotgun_e
};
LINK_ENTITY_TO_CLASS( weapon_shotgun, CShotgun )
LINK_ENTITY_TO_CLASS( weapon_barneyshotgun, CShotgun )
void CShotgun::Spawn()
{
@ -55,7 +56,7 @@ void CShotgun::Spawn()
void CShotgun::Precache( void )
{
PRECACHE_MODEL( "models/v_shotgun.mdl" );
PRECACHE_MODEL( "models/v_barneyshotgun.mdl" );
PRECACHE_MODEL( "models/w_shotgun.mdl" );
PRECACHE_MODEL( "models/p_shotgun.mdl" );
@ -110,7 +111,7 @@ int CShotgun::GetItemInfo( ItemInfo *p )
BOOL CShotgun::Deploy()
{
return DefaultDeploy( "models/v_shotgun.mdl", "models/p_shotgun.mdl", SHOTGUN_DRAW, "shotgun" );
return DefaultDeploy( "models/v_barneyshotgun.mdl", "models/p_shotgun.mdl", SHOTGUN_DRAW, "shotgun" );
}
void CShotgun::PrimaryAttack()

View File

@ -30,6 +30,7 @@ struct skilldata_t
float apacheHealth;
float barneyHealth;
float kateHealth; // alex for Kate support
float bigmommaHealthFactor; // Multiply each node's health by this
float bigmommaDmgSlash; // melee attack damage
@ -64,6 +65,13 @@ struct skilldata_t
float slaveDmgClawrake;
float slaveDmgZap;
// Alex begin
float pantherHealth;
float pantherDmgClaw;
float pantherDmgClawRake;
float pantherDmgZap;
// Alex end
float ichthyosaurHealth;
float ichthyosaurDmgShake;
@ -84,6 +92,12 @@ struct skilldata_t
float snarkDmgBite;
float snarkDmgPop;
// Alex begin
float toadHealth;
float toadDmgBite;
float toadDmgPop;
// Alex end
float zombieHealth;
float zombieDmgOneSlash;
float zombieDmgBothSlash;
@ -110,6 +124,13 @@ struct skilldata_t
float plrDmgSatchel;
float plrDmgTripmine;
// Alex begin
float plrDmgM41A;
float plrDmgPoolstick;
float plrDmgBeretta;
float plrDmgM41AGrenade;
// Alex end
// weapons shared by monsters
float monDmg9MM;
float monDmgMP5;

View File

@ -980,6 +980,80 @@ void CEnvSound::Spawn()
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
@ -993,7 +1067,7 @@ typedef struct sentenceg
unsigned char rgblru[CSENTENCE_LRU_MAX];
} SENTENCEG;
#define CSENTENCEG_MAX 200 // max number of sentence groups
#define CSENTENCEG_MAX 500 // max number of sentence groups
// globals
SENTENCEG rgsentenceg[CSENTENCEG_MAX];

View File

@ -56,6 +56,10 @@ const char *CTalkMonster::m_szFriends[TLK_CFRIENDS] =
"monster_barney",
"monster_scientist",
"monster_sitting_scientist",
"monster_barniel",
"monster_hevbarn",
"monster_kate",
"monster_worker"
};
//=========================================================

View File

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

View File

@ -169,6 +169,8 @@ void DecalGunshot( TraceResult *pTrace, int iBulletType )
case BULLET_MONSTER_MP5:
case BULLET_PLAYER_BUCKSHOT:
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 ) );
@ -308,6 +310,9 @@ void W_Precache( void )
// crowbar
UTIL_PrecacheOtherWeapon( "weapon_crowbar" );
// poolstick
UTIL_PrecacheOtherWeapon( "weapon_poolstick" ); // alex
// glock
UTIL_PrecacheOtherWeapon( "weapon_9mmhandgun" );
UTIL_PrecacheOther( "ammo_9mmclip" );
@ -317,6 +322,14 @@ void W_Precache( void )
UTIL_PrecacheOther( "ammo_9mmAR" );
UTIL_PrecacheOther( "ammo_ARgrenades" );
// begin Alex
// m41a
UTIL_PrecacheOtherWeapon( "weapon_9mmm41a" );
// beretta
UTIL_PrecacheOtherWeapon( "weapon_beretta" );
// end Alex
// 9mm ammo box
UTIL_PrecacheOther( "ammo_9mmbox" );
@ -352,6 +365,9 @@ void W_Precache( void )
// squeak grenade
UTIL_PrecacheOtherWeapon( "weapon_snark" );
// toad
UTIL_PrecacheOtherWeapon( "weapon_toad" ); // Alex
// hornetgun
UTIL_PrecacheOtherWeapon( "weapon_hornetgun" );

View File

@ -78,6 +78,13 @@ public:
#define WEAPON_TRIPMINE 13
#define WEAPON_SATCHEL 14
#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
//end Alex
#define WEAPON_ALLWEAPONS (~(1<<WEAPON_SUIT))
@ -102,6 +109,8 @@ public:
#define SNARK_WEIGHT 5
#define SATCHEL_WEIGHT -10
#define TRIPMINE_WEIGHT -10
#define TOAD_WEIGHT 10 // Alex
#define KMEDKIT_WEIGHT 10 // Alex
// weapon clip/carry ammo capacities
#define URANIUM_MAX_CARRY 100
@ -116,6 +125,8 @@ public:
#define SNARK_MAX_CARRY 15
#define HORNET_MAX_CARRY 8
#define M203_GRENADE_MAX_CARRY 10
#define TOAD_MAX_CARRY 250 // Alex
#define KMEDKIT_MAX_CARRY 250 // Alex
// the maximum amount of ammo each weapon's clip can hold
#define WEAPON_NOCLIP -1
@ -135,6 +146,8 @@ public:
#define SATCHEL_MAX_CLIP WEAPON_NOCLIP
#define TRIPMINE_MAX_CLIP WEAPON_NOCLIP
#define SNARK_MAX_CLIP WEAPON_NOCLIP
#define BERETTA_MAX_CLIP 15
#define KMEDKIT_MAX_CLIP 1
// the default amount of ammo that comes with each gun when it spawns
#define GLOCK_DEFAULT_GIVE 17
@ -152,6 +165,8 @@ public:
#define TRIPMINE_DEFAULT_GIVE 1
#define SNARK_DEFAULT_GIVE 5
#define HIVEHAND_DEFAULT_GIVE 8
#define BERETTA_DEFAULT_GIVE 15 // Alex
#define KMEDKIT_DEFAULT_GIVE 1 // Alex
// The amount of ammo given to a player by an ammo item.
#define AMMO_URANIUMBOX_GIVE 20
@ -172,13 +187,17 @@ typedef enum
BULLET_NONE = 0,
BULLET_PLAYER_9MM, // glock
BULLET_PLAYER_MP5, // mp5
BULLET_PLAYER_M41A, // M41A, Alex
BULLET_PLAYER_357, // python
BULLET_PLAYER_BUCKSHOT, // shotgun
BULLET_PLAYER_CROWBAR, // crowbar swipe
BULLET_PLAYER_BERETTA, //Alex, beretta
BULLET_PLAYER_POOLSTICK, // Alex, poolstick
BULLET_MONSTER_9MM,
BULLET_MONSTER_MP5,
BULLET_MONSTER_12MM
BULLET_MONSTER_12MM,
BULLET_MONSTER_M41A // M41A
} Bullet;
#define ITEM_FLAG_SELECTONEMPTY 1
@ -1003,4 +1022,160 @@ public:
private:
unsigned short m_usSnarkFire;
};
// Added by Alex
class CKMedkit : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 2; }
int GetItemInfo(ItemInfo *p);
void PrimaryAttack( void );
void SecondaryAttack( void );
void KMedkitFire( float flSpread, float flCycleTime, BOOL fUseAutoAim );
BOOL Deploy( void );
void Reload( void );
void WeaponIdle( void );
virtual BOOL UseDecrement( void )
{
#if defined( CLIENT_WEAPONS )
return TRUE;
#else
return FALSE;
#endif
}
private:
unsigned short m_usUseKMedkit;
};
// end
// Added by Alex
class CBeretta : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 2; }
int GetItemInfo(ItemInfo *p);
void PrimaryAttack( void );
void SecondaryAttack( void );
void BerettaFire( float flSpread, float flCycleTime, BOOL fUseAutoAim );
BOOL Deploy( void );
void Reload( void );
void WeaponIdle( void );
virtual BOOL UseDecrement( void )
{
#if defined( CLIENT_WEAPONS )
return TRUE;
#else
return FALSE;
#endif
}
private:
int m_iShell;
unsigned short m_usFireBeretta1;
unsigned short m_usFireBeretta2;
};
// end
// Alex begin
class CPoolstick : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 1; }
void EXPORT SwingAgain( void );
void EXPORT Smack( void );
int GetItemInfo(ItemInfo *p);
void PrimaryAttack( void );
int Swing( int fFirst );
BOOL Deploy( void );
void Holster( int skiplocal = 0 );
int m_iSwing;
TraceResult m_trHit;
virtual BOOL UseDecrement( void )
{
#if defined( CLIENT_WEAPONS )
return TRUE;
#else
return FALSE;
#endif
}
private:
unsigned short m_usPoolstick;
};
// Alex end
// Added by Alex
class CM41A : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 3; }
int GetItemInfo(ItemInfo *p);
int AddToPlayer( CBasePlayer *pPlayer );
void PrimaryAttack( void );
void SecondaryAttack( void );
int SecondaryAmmoIndex( void );
BOOL Deploy( void );
void Reload( void );
void WeaponIdle( void );
float m_flNextAnimTime;
int m_iShell;
virtual BOOL UseDecrement( void )
{
#if defined( CLIENT_WEAPONS )
return TRUE;
#else
return FALSE;
#endif
}
private:
unsigned short m_usM41A;
unsigned short m_usM41A2;
};
// end
// alex
class CToad : public CBasePlayerWeapon
{
public:
void Spawn( void );
void Precache( void );
int iItemSlot( void ) { return 5; }
int GetItemInfo(ItemInfo *p);
void PrimaryAttack( void );
void SecondaryAttack( void );
BOOL Deploy( void );
void Holster( int skiplocal = 0 );
void WeaponIdle( void );
int m_fJustThrown;
virtual BOOL UseDecrement( void )
{
#if defined( CLIENT_WEAPONS )
return TRUE;
#else
return FALSE;
#endif
}
private:
unsigned short m_usToadFire;
};
// alex
#endif // WEAPONS_H

View File

@ -64,6 +64,7 @@ public:
};
LINK_ENTITY_TO_CLASS( monster_zombie, CZombie )
LINK_ENTITY_TO_CLASS( monster_zbarney, CZombie )
const char *CZombie::pAttackHitSounds[] =
{
@ -265,8 +266,11 @@ void CZombie::HandleAnimEvent( MonsterEvent_t *pEvent )
void CZombie::Spawn()
{
Precache();
if( FClassnameIs( pev, "monster_zombie" ) )
SET_MODEL( ENT( pev ), "models/zombie.mdl" );
else
SET_MODEL( ENT( pev ), "models/zbarnie.mdl" );
SET_MODEL( ENT( pev ), "models/zombie.mdl" );
UTIL_SetSize( pev, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
pev->solid = SOLID_SLIDEBOX;
@ -288,7 +292,10 @@ void CZombie::Precache()
{
size_t i;
PRECACHE_MODEL( "models/zombie.mdl" );
if( FClassnameIs( pev, "monster_zombie" ) )
PRECACHE_MODEL( "models/zombie.mdl" );
else
PRECACHE_MODEL( "models/zbarnie.mdl" );
for( i = 0; i < ARRAYSIZE( pAttackHitSounds ); i++ )
PRECACHE_SOUND( pAttackHitSounds[i] );