From 9602325bbb3396414597fc8546966b5cd2cc6e27 Mon Sep 17 00:00:00 2001 From: 1upD <1upderek@gmail.com> Date: Sun, 7 Oct 2018 16:29:47 -0400 Subject: [PATCH] Shadow Walker: Added default 'custom melee weapon'. If no weapons are supplied, the Shadow Walker will spawn with a crowbar with a custom model applied. --- sp/game/mod_episodic/halloween.fgd | 5 +- sp/src/game/server/mod/npc_shadow_walker.cpp | 77 +++++++++++++++++--- 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/sp/game/mod_episodic/halloween.fgd b/sp/game/mod_episodic/halloween.fgd index 880928f2..93bf8c79 100644 --- a/sp/game/mod_episodic/halloween.fgd +++ b/sp/game/mod_episodic/halloween.fgd @@ -15,8 +15,9 @@ //------------------------------------------------------------------------- @NPCClass base(BaseNPC) studioprop() = npc_shadow_walker : "Shadow Walker" [ - additionalequipment(choices) : "Weapons" : "weapon_crowbar" : "It is recommended that the Shadow Walker be equipped with a melee weapon such as the crowbar or stunstick. The shotgun and Annabelle also work surprisingly well, but firing patterns have not been set up for automatic weapons." = + additionalequipment(choices) : "Weapons" : "0" : "It is recommended that the Shadow Walker be equipped with a melee weapon such as the crowbar or stunstick. The shotgun and Annabelle also work surprisingly well, but firing patterns have not been set up for automatic weapons." = [ + "0" : "Custom Melee Weapon" "weapon_crowbar" : "Crow Bar" "weapon_stunstick" : "Stun Stick" "weapon_shotgun" : "Shotgun" @@ -25,10 +26,10 @@ "weapon_ar2" : "AR2" "weapon_smg1" : "SMG1" "weapon_alyxgun" : "Alyx Gun" - "0" : "Nothing" ] model(studio) : "World Model" : "models/monster/subject.mdl" : "You may specify any model for this NPC. However, the NPC was written with standard human animations in mind. Missing animations may cause errors. Be aware the animations of the model you choose will affect the NPC's behavior." + WeaponModel(studio) : "Weapon Model Override" : "models/props_canal/mattpipe.mdl" : "If the Shadow Walker is set to use 'Custom Melee Weapon', you may supply a world model to use. I would recommend using the pipe model, the crowbar model, or the stunstick model." Health(integer) : "Health" : 75 : "Starting health of the NPC." diff --git a/sp/src/game/server/mod/npc_shadow_walker.cpp b/sp/src/game/server/mod/npc_shadow_walker.cpp index 27c29488..0f46b322 100644 --- a/sp/src/game/server/mod/npc_shadow_walker.cpp +++ b/sp/src/game/server/mod/npc_shadow_walker.cpp @@ -24,6 +24,7 @@ #include "engine/IEngineSound.h" #include "basehlcombatweapon_shared.h" #include "ai_squadslot.h" +#include "weapon_crowbar.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" @@ -45,7 +46,7 @@ public: virtual int SelectAlertSchedule(); virtual int SelectCombatSchedule(); virtual bool CanPickkUpWeapons() { return true; } - Activity NPC_TranslateActivity(Activity eNewActivity); + Activity NPC_TranslateActivity(Activity eNewActivity); // Sounds virtual void PlaySound(string_t soundname, bool optional); @@ -56,9 +57,14 @@ public: virtual void FearSound(void) { PlaySound(m_iszFearSound, false); }; virtual void LostEnemySound(void) { PlaySound(m_iszLostEnemySound, false); }; virtual void FoundEnemySound(void) { PlaySound(m_iszFoundEnemySound, false); }; + + void Activate(); + void FixupWeapon(); DECLARE_DATADESC(); + string_t m_iszWeaponModelName; // Path/filename of model to override weapon model. + string_t m_iszFearSound; // Path/filename of WAV file to play. string_t m_iszDeathSound; // Path/filename of WAV file to play. string_t m_iszIdleSound; // Path/filename of WAV file to play. @@ -87,7 +93,8 @@ IMPLEMENT_CUSTOM_AI( npc_citizen,CNPC_ShadowWalker ); //--------------------------------------------------------- // Save/Restore //--------------------------------------------------------- -BEGIN_DATADESC( CNPC_ShadowWalker ) +BEGIN_DATADESC(CNPC_ShadowWalker) + DEFINE_KEYFIELD(m_iszWeaponModelName, FIELD_STRING, "WeaponModel"), DEFINE_KEYFIELD(m_iHealth, FIELD_INTEGER, "Health"), DEFINE_KEYFIELD(m_iszFearSound, FIELD_SOUNDNAME, "FearSound"), DEFINE_KEYFIELD(m_iszDeathSound, FIELD_SOUNDNAME, "DeathSound"), @@ -112,6 +119,18 @@ void CNPC_ShadowWalker::InitCustomSchedules(void) INIT_CUSTOM_AI(CNPC_ShadowWalker); } +//----------------------------------------------------------------------------- +// Purpose: Inner class for default weapon +// TODO: Merge this with the Matt weapon in npc_citizen +//----------------------------------------------------------------------------- +class CWeaponCustomMelee : public CWeaponCrowbar +{ + DECLARE_CLASS(CWeaponCustomMelee, CWeaponCrowbar); + + const char *GetWorldModel() const { return GetModelName().ToCStr(); } + void SetPickupTouch(void) { /* do nothing */ } +}; + //----------------------------------------------------------------------------- // Purpose: // @@ -125,14 +144,18 @@ void CNPC_ShadowWalker::Precache( void ) SetModelName(MAKE_STRING("models/monster/subject.mdl")); } + if (&m_iszWeaponModelName && m_iszWeaponModelName != MAKE_STRING("")) { + PrecacheModel(STRING(m_iszWeaponModelName)); + } + PrecacheModel(STRING(GetModelName())); - PrecacheNPCSoundScript(&m_iszFearSound, MAKE_STRING("NPC_Shadow_Walker.Fear")); - PrecacheNPCSoundScript(&m_iszIdleSound, MAKE_STRING("NPC_Shadow_Walker.Idle")); - PrecacheNPCSoundScript(&m_iszAlertSound, MAKE_STRING("NPC_Shadow_Walker.Alert")); - PrecacheNPCSoundScript(&m_iszPainSound, MAKE_STRING("NPC_Shadow_Walker.Pain")); - PrecacheNPCSoundScript(&m_iszLostEnemySound, MAKE_STRING("NPC_Shadow_Walker.LostEnemy")); - PrecacheNPCSoundScript(&m_iszFoundEnemySound, MAKE_STRING("NPC_Shadow_Walker.FoundEnemy")); - PrecacheNPCSoundScript(&m_iszDeathSound, MAKE_STRING("NPC_Shadow_Walker.Death")); + PrecacheNPCSoundScript(&m_iszFearSound, MAKE_STRING("NPC_ShadowWalker.Fear")); + PrecacheNPCSoundScript(&m_iszIdleSound, MAKE_STRING("NPC_ShadowWalker.Idle")); + PrecacheNPCSoundScript(&m_iszAlertSound, MAKE_STRING("NPC_ShadowWalker.Alert")); + PrecacheNPCSoundScript(&m_iszPainSound, MAKE_STRING("NPC_ShadowWalker.Pain")); + PrecacheNPCSoundScript(&m_iszLostEnemySound, MAKE_STRING("NPC_ShadowWalker.LostEnemy")); + PrecacheNPCSoundScript(&m_iszFoundEnemySound, MAKE_STRING("NPC_ShadowWalker.FoundEnemy")); + PrecacheNPCSoundScript(&m_iszDeathSound, MAKE_STRING("NPC_ShadowWalker.Death")); m_bWanderToggle = false; @@ -187,6 +210,40 @@ void CNPC_ShadowWalker::Spawn( void ) NPCInit(); } +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CNPC_ShadowWalker::FixupWeapon() +{ + // If no weapons supplied, give a crowbar + CBaseCombatWeapon *pWeapon = GetActiveWeapon(); + if (pWeapon == NULL) { + pWeapon = (CBaseCombatWeapon *)CREATE_UNSAVED_ENTITY(CWeaponCustomMelee, "weapon_crowbar"); + + // Apply weapon model override + if (&m_iszWeaponModelName && m_iszWeaponModelName != MAKE_STRING("")) { + pWeapon->SetModel(STRING(m_iszWeaponModelName)); + } + else { + pWeapon->SetModel("models/props_canal/mattpipe.mdl"); + } + + DispatchSpawn(pWeapon); + Weapon_Equip(pWeapon); + } + + +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- + +void CNPC_ShadowWalker::Activate() +{ + BaseClass::Activate(); + FixupWeapon(); +} + + //----------------------------------------------------------------------------- // Purpose: Choose a schedule after schedule failed //----------------------------------------------------------------------------- @@ -464,8 +521,6 @@ bool CNPC_ShadowWalker::HasRangedWeapon() Activity CNPC_ShadowWalker::NPC_TranslateActivity(Activity activity) { switch (activity) { - case ACT_MELEE_ATTACK1: - return ACT_MELEE_ATTACK_SWING; case ACT_RUN_AIM_SHOTGUN: return ACT_RUN_AIM_RIFLE; case ACT_WALK_AIM_SHOTGUN: