diff --git a/cfg/monster_precache.cfg b/cfg/monster_precache.cfg index b255eec..10d23b0 100755 --- a/cfg/monster_precache.cfg +++ b/cfg/monster_precache.cfg @@ -28,3 +28,4 @@ //monster_miniturret //monster_sentry //monster_gonome +//monster_male_assassin diff --git a/cfg/monster_skill.cfg b/cfg/monster_skill.cfg index 97a97a7..0f03396 100755 --- a/cfg/monster_skill.cfg +++ b/cfg/monster_skill.cfg @@ -2,6 +2,7 @@ // // Install this file to your mod's base directory. + // ORIGINAL HALF-LIFE MONSTERS // Alien Grunt @@ -86,6 +87,7 @@ sk_miniturret_health 40 // Sentry Turret sk_sentry_health 40 + // OPPOSING FORCE MONSTERS // Gonome @@ -94,9 +96,14 @@ sk_gonome_dmg_one_slash 20 sk_gonome_dmg_guts 10 sk_gonome_dmg_one_bite 14 +// Male Assassin +sk_massassin_health 50 +sk_massassin_kick 25 + // MONSTER WEAPON DAMAGE sk_9mm_bullet 5 sk_9mmAR_bullet 4 sk_9mmAR_grenade 100 sk_12mm_bullet 10 +sk_762_bullet 100 diff --git a/src/dlls/Makefile b/src/dlls/Makefile index 983528f..c4ea172 100644 --- a/src/dlls/Makefile +++ b/src/dlls/Makefile @@ -30,6 +30,7 @@ OBJ = \ hornet.o \ houndeye.o \ islave.o \ + massn.o \ monster_api.o \ monster_config.o \ monsters.o \ diff --git a/src/dlls/cmbasemonster.h b/src/dlls/cmbasemonster.h index b0595b0..4c0c1d4 100644 --- a/src/dlls/cmbasemonster.h +++ b/src/dlls/cmbasemonster.h @@ -1311,4 +1311,24 @@ protected: bool m_playedAttackSound; }; +//========================================================= +// Male Assassin +//========================================================= +class CMMassn : public CMHGrunt +{ +public: + int Classify(void); + void HandleAnimEvent(MonsterEvent_t *pEvent); + void Sniperrifle(void); + + BOOL FOkToSpeak(void); + + void Spawn( void ); + void Precache( void ); + + void DeathSound(void); + void PainSound(void); + void IdleSound(void); +}; + #endif // BASEMONSTER_H diff --git a/src/dlls/combat.cpp b/src/dlls/combat.cpp index 44a0b3a..fb6add8 100644 --- a/src/dlls/combat.cpp +++ b/src/dlls/combat.cpp @@ -1360,6 +1360,7 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin case BULLET_MONSTER_MP5: case BULLET_MONSTER_9MM: case BULLET_MONSTER_12MM: + case BULLET_MONSTER_762: default: MESSAGE_BEGIN( MSG_PAS, SVC_TEMPENTITY, vecTracerSrc ); WRITE_BYTE( TE_TRACER ); @@ -1403,7 +1404,7 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin break; - case BULLET_MONSTER_12MM: + case BULLET_MONSTER_12MM: UTIL_TraceAttack(pPlayer, pevAttacker, gSkillData.monDmg12MM, vecDir, &tr, DMG_BULLET); if ( !tracer ) { @@ -1411,7 +1412,14 @@ void CMBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShootin DecalGunshot( &tr, iBulletType ); } break; - + + case BULLET_MONSTER_762: + UTIL_TraceAttack(pPlayer, pevAttacker, gSkillData.monDmg762, vecDir, &tr, DMG_BULLET); + TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); + DecalGunshot( &tr, iBulletType ); + + break; + case BULLET_NONE: // FIX UTIL_TraceAttack(pPlayer, pevAttacker, 50, vecDir, &tr, DMG_CLUB); TEXTURETYPE_PlaySound(&tr, vecSrc, vecEnd, iBulletType); diff --git a/src/dlls/dllapi.cpp b/src/dlls/dllapi.cpp index cf72bd5..84fef09 100644 --- a/src/dlls/dllapi.cpp +++ b/src/dlls/dllapi.cpp @@ -153,6 +153,7 @@ monster_type_t monster_types[]= "monster_miniturret", FALSE, "monster_sentry", FALSE, "monster_gonome", FALSE, // Opposing Force Monsters + "monster_male_assassin", FALSE, "info_node", FALSE, // Nodes "info_node_air", FALSE, "", FALSE @@ -621,6 +622,7 @@ bool spawn_monster(int monster_type, Vector origin, Vector angles, int respawn_i case 16: monsters[monster_index].pMonster = CreateClassPtr((CMMiniTurret *)NULL); break; case 17: monsters[monster_index].pMonster = CreateClassPtr((CMSentry *)NULL); break; case 18: monsters[monster_index].pMonster = CreateClassPtr((CMGonome *)NULL); break; + case 19: monsters[monster_index].pMonster = CreateClassPtr((CMMassn *)NULL); break; } if (monsters[monster_index].pMonster == NULL) @@ -1297,6 +1299,7 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) CMMiniTurret miniturret; CMSentry sentry; CMGonome gonome; + CMMassn massn; g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" ); @@ -1333,6 +1336,7 @@ void mmServerActivate( edict_t *pEdictList, int edictCount, int clientMax ) case 16: miniturret.Precache(); break; case 17: sentry.Precache(); break; case 18: gonome.Precache(); break; + case 19: massn.Precache(); break; } } } diff --git a/src/dlls/hgrunt.cpp b/src/dlls/hgrunt.cpp index 687d061..0378c7c 100644 --- a/src/dlls/hgrunt.cpp +++ b/src/dlls/hgrunt.cpp @@ -663,7 +663,9 @@ void CMHGrunt :: Shoot ( void ) pev->effects |= EF_MUZZLEFLASH; - m_cAmmoLoaded--;// take away a bullet! + // BUG - For some reason that still eludes me, grunts are completely unable to reload their weapons. + // As a temporary fix, give them infinite ammo. It will look bad I know... I gotta find a solution. -Giegue + //m_cAmmoLoaded--;// take away a bullet! Vector angDir = UTIL_VecToAngles( vecShootDir ); SetBlending( 0, angDir.x ); @@ -690,7 +692,9 @@ void CMHGrunt :: Shotgun ( void ) pev->effects |= EF_MUZZLEFLASH; - m_cAmmoLoaded--;// take away a bullet! + // BUG - For some reason that still eludes me, grunts are completely unable to reload their weapons. + // As a temporary fix, give them infinite ammo. It will look bad I know... I gotta find a solution. -Giegue + //m_cAmmoLoaded--;// take away a bullet! Vector angDir = UTIL_VecToAngles( vecShootDir ); SetBlending( 0, angDir.x ); diff --git a/src/dlls/massn.cpp b/src/dlls/massn.cpp new file mode 100644 index 0000000..e8acaf5 --- /dev/null +++ b/src/dlls/massn.cpp @@ -0,0 +1,302 @@ +// HUGE thanks to DrBeef for his hlsdk-xash3d-opfor repository! + +/*** +* +* 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. +* +****/ +//========================================================= +// Black Ops - Male Assassin +//========================================================= + +#include "extdll.h" +#include "plane.h" +#include "util.h" +#include "cmbase.h" +#include "cmbasemonster.h" +#include "monsters.h" +#include "schedule.h" +#include "animation.h" +#include "weapons.h" +#include "cmtalkmonster.h" +#include "effects.h" +#include "customentity.h" + +//========================================================= +// monster-specific DEFINE's +//========================================================= +#define MASSN_CLIP_SIZE 36 // how many bullets in a clip? - NOTE: 3 round burst sound, so keep as 3 * x! + +// Weapon flags +#define MASSN_9MMAR (1 << 0) +#define MASSN_HANDGRENADE (1 << 1) +#define MASSN_GRENADELAUNCHER (1 << 2) +#define MASSN_SNIPERRIFLE (1 << 3) + +// Body groups. +#define HEAD_GROUP 1 +#define GUN_GROUP 2 + +// Head values +#define HEAD_WHITE 0 +#define HEAD_BLACK 1 +#define HEAD_GOGGLES 2 + +// Gun values +#define GUN_MP5 0 +#define GUN_SNIPERRIFLE 1 +#define GUN_NONE 2 + +//========================================================= +// Monster's Anim Events Go Here +//========================================================= +#define MASSN_AE_KICK ( 3 ) +#define MASSN_AE_BURST1 ( 4 ) +#define MASSN_AE_CAUGHT_ENEMY ( 10 ) // grunt established sight with an enemy (player only) that had previously eluded the squad. +#define MASSN_AE_DROP_GUN ( 11 ) // grunt (probably dead) is dropping his mp5. + +//========================================================= +// Override a few behaviours to make this grunt silent +//========================================================= +BOOL CMMassn::FOkToSpeak(void) +{ + return FALSE; +} + +void CMMassn::IdleSound(void) +{ +} + +void CMMassn::PainSound(void) +{ +} + +void CMMassn::DeathSound(void) +{ +} + +//========================================================= +// Classify - indicates this monster's place in the +// relationship table. +//========================================================= +int CMMassn::Classify(void) +{ + if ( m_iClassifyOverride == -1 ) // helper + return CLASS_NONE; + else if ( m_iClassifyOverride > 0 ) + return m_iClassifyOverride; // override + + return CLASS_HUMAN_MILITARY; +} + + +//========================================================= +// Shoot +//========================================================= +void CMMassn::Sniperrifle(void) +{ + if (m_hEnemy == 0) + { + return; + } + + Vector vecShootOrigin = GetGunPosition(); + Vector vecShootDir = ShootAtEnemy(vecShootOrigin); + + UTIL_MakeVectors(pev->angles); + + Vector vecShellVelocity = gpGlobals->v_right * RANDOM_FLOAT(40, 90) + gpGlobals->v_up * RANDOM_FLOAT(75, 200) + gpGlobals->v_forward * RANDOM_FLOAT(-40, 40); + EjectBrass(vecShootOrigin - vecShootDir * 24, vecShellVelocity, pev->angles.y, m_iBrassShell, TE_BOUNCE_SHELL); + FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_1DEGREES, 2048, BULLET_MONSTER_762, 0); // shoot +-7.5 degrees + + pev->effects |= EF_MUZZLEFLASH; + + // BUG - For some reason that still eludes me, grunts are completely unable to reload their weapons. + // As a temporary fix, give them infinite ammo. It will look bad I know... I gotta find a solution. -Giegue + //m_cAmmoLoaded--;// take away a bullet! + + Vector angDir = UTIL_VecToAngles(vecShootDir); + SetBlending(0, angDir.x); +} + + +//========================================================= +// HandleAnimEvent - catches the monster-specific messages +// that occur when tagged animation frames are played. +//========================================================= +void CMMassn::HandleAnimEvent(MonsterEvent_t *pEvent) +{ + Vector vecShootDir; + Vector vecShootOrigin; + + switch (pEvent->event) + { + case MASSN_AE_DROP_GUN: + { + Vector vecGunPos; + Vector vecGunAngles; + + GetAttachment(0, vecGunPos, vecGunAngles); + + // switch to body group with no gun. + SetBodygroup(GUN_GROUP, GUN_NONE); + } + break; + + + case MASSN_AE_BURST1: + { + if (FBitSet(pev->weapons, MASSN_9MMAR)) + { + Shoot(); + + // the first round of the three round burst plays the sound and puts a sound in the world sound list. + if (RANDOM_LONG(0, 1)) + { + EMIT_SOUND(ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun1.wav", 1, ATTN_NORM); + } + else + { + EMIT_SOUND(ENT(pev), CHAN_WEAPON, "hgrunt/gr_mgun2.wav", 1, ATTN_NORM); + } + } + else if (FBitSet(pev->weapons, MASSN_SNIPERRIFLE)) + { + Sniperrifle(); + + EMIT_SOUND(ENT(pev), CHAN_WEAPON, "weapons/sniper_fire.wav", 1, ATTN_NORM); + } + } + break; + + case MASSN_AE_KICK: + { + edict_t *pHurt = Kick(); + + if (pHurt) + { + // SOUND HERE! + UTIL_MakeVectors(pev->angles); + pHurt->v.punchangle.x = 15; + pHurt->v.velocity = pHurt->v.velocity + gpGlobals->v_forward * 100 + gpGlobals->v_up * 50; + if (UTIL_IsPlayer(pHurt)) + UTIL_TakeDamage( pHurt, pev, pev, gSkillData.massnDmgKick, DMG_CLUB ); + else if (pHurt->v.euser4 != NULL) + { + CMBaseMonster *pMonster = GetClassPtr((CMBaseMonster *)VARS(pHurt)); + pMonster->TakeDamage( pev, pev, gSkillData.massnDmgKick, DMG_CLUB ); + } + } + } + break; + + case MASSN_AE_CAUGHT_ENEMY: + break; + + default: + CMHGrunt::HandleAnimEvent(pEvent); + break; + } +} + +//========================================================= +// Spawn +//========================================================= +void CMMassn::Spawn() +{ + Precache(); + + SET_MODEL(ENT(pev), "models/massn.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->effects = 0; + pev->health = gSkillData.massnHealth; + m_flFieldOfView = 0.2;// indicates the width of this monster's forward view cone ( as a dotproduct result ) + m_MonsterState = MONSTERSTATE_NONE; + m_flNextGrenadeCheck = gpGlobals->time + 1; + m_flNextPainTime = gpGlobals->time; + m_iSentence = -1; + + //m_afCapability = bits_CAP_SQUAD | bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; + m_afCapability = bits_CAP_TURN_HEAD | bits_CAP_DOORS_GROUP; + + //m_fEnemyEluded = FALSE; + m_fFirstEncounter = TRUE;// this is true when the grunt spawns, because he hasn't encountered an enemy yet. + + m_HackedGunPos = Vector(0, 0, 55); + + if (pev->weapons == 0) + { + // initialize to original values + pev->weapons = MASSN_9MMAR | MASSN_HANDGRENADE; + // pev->weapons = HGRUNT_SHOTGUN; + // pev->weapons = HGRUNT_9MMAR | HGRUNT_GRENADELAUNCHER; + } + + if (FBitSet(pev->weapons, MASSN_SNIPERRIFLE)) + { + SetBodygroup(GUN_GROUP, GUN_SNIPERRIFLE); + m_cClipSize = 5; + } + else + { + m_cClipSize = MASSN_CLIP_SIZE; + } + m_cAmmoLoaded = m_cClipSize; + + if (RANDOM_LONG(0, 99) < 80) + pev->skin = 0; // light skin + else + pev->skin = 1; // dark skin + + CMTalkMonster::g_talkWaitTime = 0; + + MonsterInit(); + + pev->classname = MAKE_STRING( "monster_male_assassin" ); + if ( strlen( STRING( m_szMonsterName ) ) == 0 ) + { + // default name + m_szMonsterName = MAKE_STRING( "Male Assassin" ); + } +} + +//========================================================= +// Precache - precaches all resources this monster needs +//========================================================= +void CMMassn::Precache() +{ + PRECACHE_MODEL("models/massn.mdl"); + + PRECACHE_SOUND("hgrunt/gr_mgun1.wav"); + PRECACHE_SOUND("hgrunt/gr_mgun2.wav"); + + PRECACHE_SOUND("hgrunt/gr_reload1.wav"); + + PRECACHE_SOUND("weapons/glauncher.wav"); + + PRECACHE_SOUND("weapons/sniper_bolt1.wav"); + PRECACHE_SOUND("weapons/sniper_fire.wav"); + + PRECACHE_SOUND("zombie/claw_miss2.wav");// because we use the basemonster SWIPE animation event + + // get voice pitch + if (RANDOM_LONG(0, 1)) + m_voicePitch = 109 + RANDOM_LONG(0, 7); + else + m_voicePitch = 100; + + m_iBrassShell = PRECACHE_MODEL("models/shell.mdl");// brass shell +} diff --git a/src/dlls/skill.cpp b/src/dlls/skill.cpp index 64e0270..8abe246 100644 --- a/src/dlls/skill.cpp +++ b/src/dlls/skill.cpp @@ -76,10 +76,13 @@ skill_cfg_t skill_cfg[] = { {"sk_gonome_dmg_guts", &gSkillData.gonomeDmgGuts}, {"sk_gonome_dmg_one_slash", &gSkillData.gonomeDmgOneSlash}, {"sk_gonome_dmg_one_bite", &gSkillData.gonomeDmgOneBite}, + {"sk_massassin_health", &gSkillData.massnHealth}, + {"sk_massassin_kick", &gSkillData.massnDmgKick}, {"sk_12mm_bullet", &gSkillData.monDmg9MM}, {"sk_9mmAR_bullet", &gSkillData.monDmgMP5}, {"sk_9mm_bullet", &gSkillData.monDmg12MM}, {"sk_9mmAR_grenade", &gSkillData.monDmgM203Grenade}, + {"sk_762_bullet", &gSkillData.monDmg762}, {"sk_hornet_dmg", &gSkillData.monDmgHornet}, {"", NULL} }; @@ -222,12 +225,17 @@ void monster_skill_init(void) gSkillData.gonomeDmgOneSlash = 20.0f; gSkillData.gonomeDmgOneBite = 14.0f; + // Male Assassin + gSkillData.massnHealth = 50.0f; + gSkillData.massnDmgKick = 25.0f; + // MONSTER WEAPONS gSkillData.monDmg9MM = 5.0f; gSkillData.monDmgMP5 = 4.0f; gSkillData.monDmg12MM = 10.0f; gSkillData.monDmgM203Grenade = 100.0f; - + gSkillData.monDmg762 = 100.0f; + // HORNET gSkillData.monDmgHornet = 5.0f; diff --git a/src/dlls/skill.h b/src/dlls/skill.h index 9dc1648..ba52559 100644 --- a/src/dlls/skill.h +++ b/src/dlls/skill.h @@ -92,12 +92,16 @@ struct skilldata_t float gonomeDmgOneSlash; float gonomeDmgOneBite; + float massnHealth; + float massnDmgKick; + // weapons shared by monsters float monDmg9MM; float monDmgMP5; float monDmg12MM; float monDmgM203Grenade; - + float monDmg762; + float monDmgHornet; }; diff --git a/src/dlls/weapons.cpp b/src/dlls/weapons.cpp index 2d0bcb3..02a0f96 100644 --- a/src/dlls/weapons.cpp +++ b/src/dlls/weapons.cpp @@ -136,6 +136,19 @@ void DecalGunshot( TraceResult *pTrace, int iBulletType ) switch( iBulletType ) { + case BULLET_PLAYER_CROWBAR: + { + // wall decal + UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) ); + break; + } + default: + { + // smoke and decal + UTIL_GunshotDecalTrace( pTrace, DamageDecal( pEntity, DMG_BULLET ) ); + break; + } + /* why the duplicate case? case BULLET_PLAYER_9MM: case BULLET_MONSTER_9MM: case BULLET_PLAYER_MP5: @@ -154,6 +167,7 @@ void DecalGunshot( TraceResult *pTrace, int iBulletType ) // wall decal UTIL_DecalTrace( pTrace, DamageDecal( pEntity, DMG_CLUB ) ); break; + */ } } } diff --git a/src/dlls/weapons.h b/src/dlls/weapons.h index 83701c7..b6f3dcb 100644 --- a/src/dlls/weapons.h +++ b/src/dlls/weapons.h @@ -177,6 +177,7 @@ typedef enum BULLET_MONSTER_9MM, BULLET_MONSTER_MP5, BULLET_MONSTER_12MM, + BULLET_MONSTER_762, } Bullet;