mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2025-02-14 07:48:49 +03:00
Lost Soul: Added new NPC based on manhack. Inspired by Doom
This commit is contained in:
parent
86bb8f7c7e
commit
4e56c1205b
381
sp/src/game/server/mod/npc_lost_soul.cpp
Normal file
381
sp/src/game/server/mod/npc_lost_soul.cpp
Normal file
@ -0,0 +1,381 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
// This is a skeleton file for use when creating a new
|
||||
// NPC. Copy and rename this file for the new
|
||||
// NPC and add the copy to the build.
|
||||
//
|
||||
// Leave this file in the build until we ship! Allowing
|
||||
// this file to be rebuilt with the rest of the game ensures
|
||||
// that it stays up to date with the rest of the NPC code.
|
||||
//
|
||||
// Replace occurances of CNPC_ShadowWalker with the new NPC's
|
||||
// classname. Don't forget the lower-case occurance in
|
||||
// LINK_ENTITY_TO_CLASS()
|
||||
//
|
||||
//
|
||||
// ASSUMPTIONS MADE:
|
||||
//
|
||||
// You're making a character based on CAI_BaseNPC. If this
|
||||
// is not true, make sure you replace all occurances
|
||||
// of 'CAI_BaseNPC' in this file with the appropriate
|
||||
// parent class.
|
||||
//
|
||||
// You're making a human-sized NPC that walks.
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "soundenvelope.h"
|
||||
#include "npc_manhack.h"
|
||||
#include "ai_default.h"
|
||||
#include "ai_node.h"
|
||||
#include "ai_navigator.h"
|
||||
#include "ai_pathfinder.h"
|
||||
#include "ai_moveprobe.h"
|
||||
#include "ai_memory.h"
|
||||
#include "ai_squad.h"
|
||||
#include "ai_route.h"
|
||||
#include "explode.h"
|
||||
#include "basegrenade_shared.h"
|
||||
#include "ndebugoverlay.h"
|
||||
#include "decals.h"
|
||||
#include "gib.h"
|
||||
#include "game.h"
|
||||
#include "ai_interactions.h"
|
||||
#include "IEffects.h"
|
||||
#include "vstdlib/random.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "movevars_shared.h"
|
||||
#include "npcevent.h"
|
||||
#include "props.h"
|
||||
#include "te_effect_dispatch.h"
|
||||
#include "ai_squadslot.h"
|
||||
#include "world.h"
|
||||
#include "smoke_trail.h"
|
||||
#include "func_break.h"
|
||||
#include "physics_impact_damage.h"
|
||||
#include "weapon_physcannon.h"
|
||||
#include "physics_prop_ragdoll.h"
|
||||
#include "soundent.h"
|
||||
#include "ammodef.h"
|
||||
#include "EntityFlame.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//=========================================================
|
||||
// Private activities
|
||||
//=========================================================
|
||||
//int ACT_MYCUSTOMACTIVITY = -1;
|
||||
|
||||
//=========================================================
|
||||
// Custom schedules
|
||||
//=========================================================
|
||||
//enum
|
||||
//{
|
||||
// SCHED_MYCUSTOMSCHEDULE = LAST_SHARED_SCHEDULE,
|
||||
//};
|
||||
|
||||
//=========================================================
|
||||
// Custom tasks
|
||||
//=========================================================
|
||||
//enum
|
||||
//{
|
||||
// TASK_MYCUSTOMTASK = LAST_SHARED_TASK,
|
||||
//};
|
||||
|
||||
|
||||
//=========================================================
|
||||
// Custom Conditions
|
||||
//=========================================================
|
||||
//enum
|
||||
//{
|
||||
// COND_MYCUSTOMCONDITION = LAST_SHARED_CONDITION,
|
||||
//};
|
||||
|
||||
|
||||
ConVar sk_lostsoul_health("sk_lostsoul_health", "0");
|
||||
ConVar sk_lostsoul_melee_dmg("sk_lostsoul_melee_dmg", "0");
|
||||
|
||||
#define MANHACK_NOISEMOD_HIDE 5000
|
||||
//=========================================================
|
||||
//=========================================================
|
||||
class CNPC_LostSoul : public CNPC_Manhack
|
||||
{
|
||||
DECLARE_CLASS( CNPC_LostSoul, CNPC_Manhack);
|
||||
|
||||
public:
|
||||
void Precache( void );
|
||||
void Spawn( void );
|
||||
Class_T Classify( void );
|
||||
|
||||
virtual void DeathSound(const CTakeDamageInfo &info);
|
||||
virtual bool ShouldGib(const CTakeDamageInfo &info);
|
||||
|
||||
void BladesInit();
|
||||
void SoundInit(void);
|
||||
void PlayFlySound(void);
|
||||
void StartEye(void);
|
||||
|
||||
void Slice(CBaseEntity *pHitEntity, float flInterval, trace_t &tr);
|
||||
//void Bump(CBaseEntity *pHitEntity, float flInterval, trace_t &tr);
|
||||
//void Splash(const Vector &vecSplashPos);
|
||||
|
||||
virtual int OnTakeDamage_Alive(const CTakeDamageInfo &info);
|
||||
|
||||
void Ignite(float flFlameLifetime, bool bNPCOnly, float flSize, bool bCalledByLevelDesigner) { return; }
|
||||
|
||||
DECLARE_DATADESC();
|
||||
|
||||
|
||||
DEFINE_CUSTOM_AI;
|
||||
};
|
||||
|
||||
|
||||
LINK_ENTITY_TO_CLASS( npc_lost_soul, CNPC_LostSoul );
|
||||
IMPLEMENT_CUSTOM_AI( npc_manhack,CNPC_LostSoul );
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Save/Restore
|
||||
//---------------------------------------------------------
|
||||
BEGIN_DATADESC( CNPC_LostSoul )
|
||||
|
||||
//DEFINE_FIELD(m_bHasWeapon, FIELD_BOOLEAN),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Initialize the custom schedules
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_LostSoul::InitCustomSchedules(void)
|
||||
{
|
||||
INIT_CUSTOM_AI(CNPC_LostSoul);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_LostSoul::Precache( void )
|
||||
{
|
||||
PrecacheModel( "models/skeleton/skeleton_torso3.mdl" ); // Replace this with setting from Hammer
|
||||
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_LostSoul::Spawn( void )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
|
||||
Precache();
|
||||
|
||||
SetModel("models/skeleton/skeleton_torso3.mdl");
|
||||
SetHullType(HULL_HUMAN); // I guess?
|
||||
SetHullSizeNormal();
|
||||
|
||||
SetSolid(SOLID_BBOX);
|
||||
AddSolidFlags(FSOLID_NOT_STANDABLE);
|
||||
|
||||
if (HasSpawnFlags(SF_MANHACK_CARRIED))
|
||||
{
|
||||
AddSolidFlags(FSOLID_NOT_SOLID);
|
||||
SetMoveType(MOVETYPE_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetMoveType(MOVETYPE_VPHYSICS);
|
||||
}
|
||||
|
||||
m_iHealth = sk_lostsoul_health.GetFloat();
|
||||
SetViewOffset(Vector(0, 0, 10)); // Position of the eyes relative to NPC's origin.
|
||||
m_flFieldOfView = VIEW_FIELD_FULL;
|
||||
m_NPCState = NPC_STATE_NONE;
|
||||
|
||||
if (m_spawnflags & SF_MANHACK_USE_AIR_NODES)
|
||||
{
|
||||
SetNavType(NAV_FLY);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetNavType(NAV_GROUND);
|
||||
}
|
||||
|
||||
AddEFlags(EFL_NO_DISSOLVE | EFL_NO_MEGAPHYSCANNON_RAGDOLL);
|
||||
AddEffects(EF_NOSHADOW);
|
||||
|
||||
SetBloodColor(BLOOD_COLOR_RED);
|
||||
SetCurrentVelocity(vec3_origin);
|
||||
|
||||
CapabilitiesAdd(bits_CAP_INNATE_MELEE_ATTACK1 | bits_CAP_MOVE_FLY | bits_CAP_SQUAD);
|
||||
|
||||
// Set the noise mod to huge numbers right now, in case this manhack starts out waiting for a script
|
||||
// for instance, we don't want him to bob whilst he's waiting for a script. This allows designers
|
||||
// to 'hide' manhacks in small places. (sjb)
|
||||
SetNoiseMod(MANHACK_NOISEMOD_HIDE, MANHACK_NOISEMOD_HIDE, MANHACK_NOISEMOD_HIDE);
|
||||
|
||||
m_fHeadYaw = 0;
|
||||
|
||||
NPCInit();
|
||||
|
||||
// Manhacks are designed to slam into things, so don't take much damage from it!
|
||||
SetImpactEnergyScale(0.001);
|
||||
|
||||
// Manhacks get 30 seconds worth of free knowledge.
|
||||
GetEnemies()->SetFreeKnowledgeDuration(30.0);
|
||||
|
||||
// don't be an NPC, we want to collide with debris stuff
|
||||
SetCollisionGroup(COLLISION_GROUP_NONE);
|
||||
|
||||
CEntityFlame *pFlame = CEntityFlame::Create(this);
|
||||
if (pFlame)
|
||||
{
|
||||
pFlame->SetLifetime(HUGE_VAL);
|
||||
//AddFlag(FL_ONFIRE);
|
||||
SetEffectEntity(pFlame);
|
||||
pFlame->SetSize(8);
|
||||
pFlame->SetDamage(0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
int CNPC_LostSoul::OnTakeDamage_Alive(const CTakeDamageInfo &info)
|
||||
{
|
||||
// Don't take burning damage!
|
||||
if (info.GetDamageType() & 8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return BaseClass::OnTakeDamage_Alive(info);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_LostSoul::DeathSound(const CTakeDamageInfo &info)
|
||||
{
|
||||
StopSound("NPC_Lost_Soul.Stunned");
|
||||
CPASAttenuationFilter filter2(this, "NPC_Lost_Soul.Die");
|
||||
EmitSound(filter2, entindex(), "NPC_Lost_Soul.Die");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNPC_LostSoul::ShouldGib(const CTakeDamageInfo &info)
|
||||
{
|
||||
// TODO: Add gibs to lost soul
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Overloads Manhack method. Lost Souls have no blades
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_LostSoul::BladesInit()
|
||||
{
|
||||
SetActivity(ACT_FLY);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Overloads manhack engine sound.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_LostSoul::SoundInit(void)
|
||||
{
|
||||
// Just don't even worry about it.
|
||||
}
|
||||
|
||||
void CNPC_LostSoul::PlayFlySound(void)
|
||||
{
|
||||
// Shhh, don't do anything.
|
||||
}
|
||||
|
||||
void CNPC_LostSoul::StartEye(void)
|
||||
{
|
||||
// No eyes
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: We've touched something that we can hurt. Slice it!
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
#define MANHACK_SMASH_TIME 0.35 // How long after being thrown from a physcannon that a manhack is eligible to die from impact
|
||||
void CNPC_LostSoul::Slice(CBaseEntity *pHitEntity, float flInterval, trace_t &tr)
|
||||
{
|
||||
// Don't hurt the player if I'm in water
|
||||
if (GetWaterLevel() > 0 && pHitEntity->IsPlayer())
|
||||
return;
|
||||
|
||||
if (pHitEntity->m_takedamage == DAMAGE_NO)
|
||||
return;
|
||||
|
||||
// Damage must be scaled by flInterval so framerate independent
|
||||
float flDamage = sk_lostsoul_melee_dmg.GetFloat() * flInterval;
|
||||
|
||||
if (pHitEntity->IsPlayer())
|
||||
{
|
||||
flDamage *= 1.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<CBreakableProp*>(pHitEntity)) {
|
||||
dynamic_cast<CBreakableProp*>(pHitEntity)->Ignite(10.0f, false);
|
||||
}
|
||||
|
||||
else if (pHitEntity->IsNPC())
|
||||
{
|
||||
dynamic_cast<CAI_BaseNPC*>(pHitEntity)->Ignite(2.0f);
|
||||
}
|
||||
|
||||
if (flDamage < 1.0f)
|
||||
{
|
||||
flDamage = 1.0f;
|
||||
}
|
||||
|
||||
CTakeDamageInfo info(this, this, flDamage, DMG_SLASH);
|
||||
|
||||
// check for actual "ownership" of damage
|
||||
CBasePlayer *pPlayer = HasPhysicsAttacker(MANHACK_SMASH_TIME);
|
||||
if (pPlayer)
|
||||
{
|
||||
info.SetAttacker(pPlayer);
|
||||
}
|
||||
|
||||
Vector dir = (tr.endpos - tr.startpos);
|
||||
if (dir == vec3_origin)
|
||||
{
|
||||
dir = tr.m_pEnt->GetAbsOrigin() - GetAbsOrigin();
|
||||
}
|
||||
CalculateMeleeDamageForce(&info, dir, tr.endpos);
|
||||
pHitEntity->TakeDamage(info);
|
||||
|
||||
// Play burning sound
|
||||
EmitSound("NPC_LostSoul.Burn");
|
||||
|
||||
// Pop back a little bit after hitting the player
|
||||
// ComputeSliceBounceVelocity(pHitEntity, tr);
|
||||
|
||||
// Save off when we last hit something
|
||||
m_flLastDamageTime = gpGlobals->curtime;
|
||||
|
||||
// Reset our state and give the player time to react
|
||||
// StopBurst(true);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//
|
||||
//
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
Class_T CNPC_LostSoul::Classify( void )
|
||||
{
|
||||
return CLASS_HEADCRAB;
|
||||
}
|
@ -204,6 +204,12 @@ int CNPC_ShadowWalker::SelectFailSchedule(int failedSchedule, int failedTask, AI
|
||||
case SCHED_TAKE_COVER_FROM_ENEMY:
|
||||
// I can't take cover, so I need to run away!
|
||||
return SCHED_RUN_FROM_ENEMY;
|
||||
case SCHED_CHASE_ENEMY:
|
||||
// I can't run away, so I will just run randomly!
|
||||
return SCHED_CHASE_ENEMY_FAILED;
|
||||
case SCHED_RUN_FROM_ENEMY:
|
||||
// I can't run away, so I will just run randomly!
|
||||
return SCHED_RUN_RANDOM;
|
||||
}
|
||||
|
||||
return BaseClass::SelectFailSchedule(failedSchedule, failedTask, taskFailCode);
|
||||
@ -235,22 +241,6 @@ int CNPC_ShadowWalker::SelectScheduleRetrieveItem()
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_ShadowWalker::SelectSchedule()
|
||||
{
|
||||
int schedule;
|
||||
// Top priority - If there is a weapon available, grab it!
|
||||
//schedule = SelectScheduleRetrieveItem();
|
||||
//if (schedule != SCHED_NONE)
|
||||
// return schedule;
|
||||
|
||||
// Can I see the enemy?
|
||||
//if (HasCondition(COND_SEE_ENEMY) && HasCondition(COND_ENEMY_FACING_ME))
|
||||
//{
|
||||
// // Enemy can't see me
|
||||
// if (!HasCondition(COND_HAVE_ENEMY_LOS)) {
|
||||
// return SCHED_CHASE_ENEMY;
|
||||
// }
|
||||
//
|
||||
// return SCHED_RUN_FROM_ENEMY;
|
||||
//}
|
||||
switch (m_NPCState)
|
||||
{
|
||||
case NPC_STATE_IDLE:
|
||||
@ -261,8 +251,8 @@ int CNPC_ShadowWalker::SelectSchedule()
|
||||
AssertMsgOnce(GetEnemy() == NULL, "NPC has enemy but is not in combat state?");
|
||||
return SelectAlertSchedule();
|
||||
|
||||
//case NPC_STATE_COMBAT:
|
||||
//return SelectCombatSchedule();
|
||||
case NPC_STATE_COMBAT:
|
||||
return SelectCombatSchedule();
|
||||
|
||||
default:
|
||||
return BaseClass::SelectSchedule();
|
||||
@ -357,7 +347,7 @@ int CNPC_ShadowWalker::SelectCombatSchedule()
|
||||
|
||||
// If I'm scared of this enemy and he's looking at me, run away
|
||||
// If in a squad, all but one Shadow walker must be afraid of the player
|
||||
if (IRelationType(GetEnemy()) == D_FR || !OccupyStrategySlotRange(SQUAD_SLOT_ATTACK1))
|
||||
if (IRelationType(GetEnemy()) == D_FR || !OccupyStrategySlotRange(SQUAD_SLOT_ATTACK1, SQUAD_SLOT_ATTACK2))
|
||||
{
|
||||
if (HasCondition(COND_SEE_ENEMY) && HasCondition(COND_ENEMY_FACING_ME) && HasCondition(COND_HAVE_ENEMY_LOS))
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user