mirror of https://github.com/FWGS/hlsdk-xash3d
Merge @Alex3474247's patches for "Azure Sheep".
This commit is contained in:
parent
bc1bb3e358
commit
de17a74a3a
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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" );
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
@ -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.
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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 );
|
||||
|
|
|
@ -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 )
|
||||
|
|
118
dlls/game.cpp
118
dlls/game.cpp
|
@ -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"};
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
21
dlls/skill.h
21
dlls/skill.h
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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"
|
||||
};
|
||||
|
||||
//=========================================================
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#define bit_saidHeard (1<<6)
|
||||
#define bit_saidSmelled (1<<7)
|
||||
|
||||
#define TLK_CFRIENDS 3
|
||||
#define TLK_CFRIENDS 7
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
|
|
@ -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" );
|
||||
|
||||
|
|
177
dlls/weapons.h
177
dlls/weapons.h
|
@ -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
|
||||
|
|
|
@ -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] );
|
||||
|
|
Loading…
Reference in New Issue