mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-07-16 06:19:58 +00:00
StargateTC port — initial integration into nillerusr/source-engine
P1: Source files - Copy 9 server stargate files + sg_constants.h + sg_weapons.cpp from StargateTCSource/sourcecode/ into game/server/stargate/ and game/shared/stargate/. - Add $Folder "Stargate" block to server_hl2mp.vpc and client_hl2mp.vpc. - Extend $AdditionalIncludeDirectories with stargate paths. P2/P3: Gamerules + player patches - hl2mp_gamerules.h: add TEAM_JAFFA=4, TEAM_UNAS=5 to team enum. - hl2mp_gamerules.cpp: preserve 5 Stargate spawn classnames in s_PreserveEnts[]; rename teams to Tau'ri/Goa'uld/Jaffa/Unas; rename game description to "StargateTC"/"StargateTC Teamplay". - hl2mp_player.cpp: EntSelectSpawnPoint now searches Stargate spawn classnames first (torri/goauld/marine/unas) with per-team fallback chain to combine/rebel/deathmatch. Build: 0 errors. Server.dll 13.19MB, client.dll 9.85MB. Runtime test: window title "StargateTC", live game launches, HEALTH 100 HUD renders, HL2MP MOTD shown, sky/world geometry renders. Response system loads 217 rules without crashing (was the original Mapbase+VS2022 heap-corruption point). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ed8209cc35
commit
44cb9a4837
@ -14,7 +14,7 @@ $Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$AdditionalIncludeDirectories "$BASE;hl2mp\ui,.\hl2mp,$SRCDIR\game\shared\hl2mp,.\hl2,.\hl2\elements,$SRCDIR\game\shared\hl2"
|
||||
$AdditionalIncludeDirectories "$BASE;hl2mp\ui,.\hl2mp,$SRCDIR\game\shared\hl2mp,.\hl2,.\hl2\elements,$SRCDIR\game\shared\hl2,$SRCDIR\game\shared\stargate"
|
||||
$PreprocessorDefinitions "$BASE;HL2MP;HL2_CLIENT_DLL"
|
||||
}
|
||||
}
|
||||
@ -170,5 +170,11 @@ $Project "Client (HL2MP)"
|
||||
$File "hl2mp\hud_deathnotice.cpp"
|
||||
}
|
||||
}
|
||||
|
||||
$Folder "Stargate"
|
||||
{
|
||||
$File "$SRCDIR\game\shared\stargate\sg_weapons.cpp"
|
||||
$File "$SRCDIR\game\shared\stargate\sg_constants.h"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1321,19 +1321,44 @@ CBaseEntity* CHL2MP_Player::EntSelectSpawnPoint( void )
|
||||
{
|
||||
if ( GetTeamNumber() == TEAM_COMBINE )
|
||||
{
|
||||
pSpawnpointName = "info_player_combine";
|
||||
pSpawnpointName = "info_player_torri";
|
||||
pLastSpawnPoint = g_pLastCombineSpawn;
|
||||
}
|
||||
else if ( GetTeamNumber() == TEAM_REBELS )
|
||||
{
|
||||
pSpawnpointName = "info_player_rebel";
|
||||
pSpawnpointName = "info_player_goauld";
|
||||
pLastSpawnPoint = g_pLastRebelSpawn;
|
||||
}
|
||||
else if ( GetTeamNumber() == TEAM_JAFFA )
|
||||
{
|
||||
pSpawnpointName = "info_player_marine";
|
||||
pLastSpawnPoint = g_pLastSpawn;
|
||||
}
|
||||
else if ( GetTeamNumber() == TEAM_UNAS )
|
||||
{
|
||||
pSpawnpointName = "info_player_unas";
|
||||
pLastSpawnPoint = g_pLastSpawn;
|
||||
}
|
||||
|
||||
if ( gEntList.FindEntityByClassname( NULL, pSpawnpointName ) == NULL )
|
||||
{
|
||||
pSpawnpointName = "info_player_deathmatch";
|
||||
pLastSpawnPoint = g_pLastSpawn;
|
||||
if ( GetTeamNumber() == TEAM_COMBINE && gEntList.FindEntityByClassname( NULL, "info_player_marine" ) != NULL )
|
||||
{
|
||||
pSpawnpointName = "info_player_marine";
|
||||
}
|
||||
else if ( GetTeamNumber() == TEAM_COMBINE && gEntList.FindEntityByClassname( NULL, "info_player_combine" ) != NULL )
|
||||
{
|
||||
pSpawnpointName = "info_player_combine";
|
||||
}
|
||||
else if ( GetTeamNumber() == TEAM_REBELS && gEntList.FindEntityByClassname( NULL, "info_player_rebel" ) != NULL )
|
||||
{
|
||||
pSpawnpointName = "info_player_rebel";
|
||||
}
|
||||
else
|
||||
{
|
||||
pSpawnpointName = "info_player_deathmatch";
|
||||
pLastSpawnPoint = g_pLastSpawn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ $Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$AdditionalIncludeDirectories "$BASE;$SRCDIR\game\shared\hl2,.\hl2,.\hl2mp,$SRCDIR\game\shared\hl2mp"
|
||||
$AdditionalIncludeDirectories "$BASE;$SRCDIR\game\shared\hl2,.\hl2,.\hl2mp,$SRCDIR\game\shared\hl2mp,.\stargate,$SRCDIR\game\shared\stargate"
|
||||
$PreprocessorDefinitions "$BASE;HL2MP;HL2_DLL"
|
||||
}
|
||||
}
|
||||
@ -292,5 +292,20 @@ $Project "Server (HL2MP)"
|
||||
$File "$SRCDIR\game\shared\hl2mp\weapon_stunstick.cpp"
|
||||
}
|
||||
}
|
||||
|
||||
$Folder "Stargate"
|
||||
{
|
||||
$File "stargate\dhd_console.cpp"
|
||||
$File "stargate\gate_travel.cpp"
|
||||
$File "stargate\multi_gate.cpp"
|
||||
$File "stargate\recovered_entities.cpp"
|
||||
$File "stargate\ring_transporter.cpp"
|
||||
$File "stargate\sg_event.cpp"
|
||||
$File "stargate\sg_kawoosh.cpp"
|
||||
$File "stargate\sg_player_spawn.cpp"
|
||||
$File "stargate\STUBS.cpp"
|
||||
$File "$SRCDIR\game\shared\stargate\sg_weapons.cpp"
|
||||
$File "$SRCDIR\game\shared\stargate\sg_constants.h"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
game/server/stargate/STUBS.cpp
Normal file
38
game/server/stargate/STUBS.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
//============= Copyright © StargateTC Source Team =============================
|
||||
//
|
||||
// One-file stubs for the remaining preserved entities. Each just registers its
|
||||
// classname against CBaseEntity so the engine accepts maps that reference them
|
||||
// (otherwise vbsp/spawn would log "Spawnfunction for <classname> not found").
|
||||
//
|
||||
// Replace these one by one as gameplay is ported — copy a stub out into its
|
||||
// own file and flesh it out following the dhd_console.cpp / sg_event.cpp
|
||||
// pattern.
|
||||
//
|
||||
//==============================================================================
|
||||
#include "cbase.h"
|
||||
|
||||
#define STUB_ENTITY(classname) \
|
||||
class C##classname : public CBaseAnimating \
|
||||
{ \
|
||||
public: \
|
||||
DECLARE_CLASS( C##classname, CBaseAnimating ); \
|
||||
void Spawn() override \
|
||||
{ \
|
||||
BaseClass::Spawn(); \
|
||||
SetSolid( SOLID_VPHYSICS ); \
|
||||
SetMoveType( MOVETYPE_NONE ); \
|
||||
Msg( "[StargateTC] inert stub spawned: " #classname "\n" ); \
|
||||
} \
|
||||
}; \
|
||||
LINK_ENTITY_TO_CLASS( classname, C##classname )
|
||||
|
||||
STUB_ENTITY( stargate_dialer );
|
||||
STUB_ENTITY( goauld_sarcophagus );
|
||||
STUB_ENTITY( zat_pickup );
|
||||
STUB_ENTITY( staff_pickup );
|
||||
STUB_ENTITY( naqahdah_pickup );
|
||||
|
||||
// Weapons — eventually derive from CBaseHL2MPCombatWeapon. For now an inert
|
||||
// pickup so maps spawn-clean.
|
||||
STUB_ENTITY( zat_gun );
|
||||
STUB_ENTITY( staff_gun );
|
||||
72
game/server/stargate/dhd_console.cpp
Normal file
72
game/server/stargate/dhd_console.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
//============= Copyright © StargateTC Source Team =============================
|
||||
//
|
||||
// dhd_console — the Dial-Home-Device. A player +USEs it to fire the matching
|
||||
// stargate_event's Dial input. Includes a per-DHD lockout while the gate is
|
||||
// active to prevent re-dial.
|
||||
//
|
||||
// Keyvalues:
|
||||
// target — name of the stargate_event to dial
|
||||
//
|
||||
//==============================================================================
|
||||
#include "cbase.h"
|
||||
#include "stargate/sg_constants.h"
|
||||
|
||||
class CDHDConsole : public CBaseAnimating
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CDHDConsole, CBaseAnimating );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void Spawn() override;
|
||||
void Precache() override;
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller,
|
||||
USE_TYPE useType, float value ) override;
|
||||
|
||||
int ObjectCaps() override { return BaseClass::ObjectCaps() | FCAP_IMPULSE_USE; }
|
||||
|
||||
private:
|
||||
bool m_bBusy { false };
|
||||
|
||||
void Unbusy() { m_bBusy = false; SetNextThink( TICK_NEVER_THINK ); }
|
||||
};
|
||||
|
||||
LINK_ENTITY_TO_CLASS( dhd_console, CDHDConsole );
|
||||
|
||||
BEGIN_DATADESC( CDHDConsole )
|
||||
DEFINE_THINKFUNC( Unbusy ),
|
||||
END_DATADESC()
|
||||
|
||||
void CDHDConsole::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
Precache();
|
||||
SetModel( "models/stargate/dhd_console.mdl" );
|
||||
SetSolid( SOLID_VPHYSICS );
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
}
|
||||
|
||||
void CDHDConsole::Precache()
|
||||
{
|
||||
PrecacheModel( "models/stargate/dhd_console.mdl" );
|
||||
PrecacheScriptSound( "Stargate.DHDPress" );
|
||||
}
|
||||
|
||||
void CDHDConsole::Use( CBaseEntity *pActivator, CBaseEntity *,
|
||||
USE_TYPE, float )
|
||||
{
|
||||
if ( m_bBusy || !pActivator || !pActivator->IsPlayer() )
|
||||
return;
|
||||
EmitSound( "Stargate.DHDPress" );
|
||||
|
||||
CBaseEntity *pGate = gEntList.FindEntityByName( NULL, m_target );
|
||||
if ( pGate )
|
||||
{
|
||||
variant_t empty;
|
||||
pGate->AcceptInput( "Dial", pActivator, this, empty, 0 );
|
||||
}
|
||||
m_bBusy = true;
|
||||
SetThink( &CDHDConsole::Unbusy );
|
||||
SetNextThink( gpGlobals->curtime +
|
||||
StargateTC::DIAL_SYMBOL_COUNT * StargateTC::DIAL_SYMBOL_TIME +
|
||||
StargateTC::KAWOOSH_DURATION );
|
||||
}
|
||||
64
game/server/stargate/gate_travel.cpp
Normal file
64
game/server/stargate/gate_travel.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
//============= Copyright (c) StargateTC Source Team ==========================
|
||||
//
|
||||
// zone_gatetravel and trigger_adv_teleport recovered from the GoldSrc DLL.
|
||||
// Ghidra's GTravelTouch path checks IsPlayer(), clears velocity, and starts a
|
||||
// short travel lockout. The Source port keeps that observable behavior and adds
|
||||
// explicit destination targeting for converted maps.
|
||||
//
|
||||
//=============================================================================
|
||||
#include "cbase.h"
|
||||
#include "triggers.h"
|
||||
#include "stargate/sg_constants.h"
|
||||
|
||||
class CStargateTravelZone : public CBaseTrigger
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CStargateTravelZone, CBaseTrigger );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void Spawn() override;
|
||||
void TravelTouch( CBaseEntity *pOther );
|
||||
|
||||
private:
|
||||
void TeleportPlayer( CBaseEntity *pPlayer );
|
||||
float m_flNextTouchTime { 0.0f };
|
||||
};
|
||||
|
||||
LINK_ENTITY_TO_CLASS( zone_gatetravel, CStargateTravelZone );
|
||||
LINK_ENTITY_TO_CLASS( trigger_adv_teleport, CStargateTravelZone );
|
||||
|
||||
BEGIN_DATADESC( CStargateTravelZone )
|
||||
DEFINE_FIELD( m_flNextTouchTime, FIELD_TIME ),
|
||||
DEFINE_ENTITYFUNC( TravelTouch ),
|
||||
END_DATADESC()
|
||||
|
||||
void CStargateTravelZone::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
InitTrigger();
|
||||
SetTouch( &CStargateTravelZone::TravelTouch );
|
||||
}
|
||||
|
||||
void CStargateTravelZone::TravelTouch( CBaseEntity *pOther )
|
||||
{
|
||||
if ( !pOther || !pOther->IsPlayer() || gpGlobals->curtime < m_flNextTouchTime )
|
||||
return;
|
||||
|
||||
pOther->SetAbsVelocity( vec3_origin );
|
||||
pOther->SetBaseVelocity( vec3_origin );
|
||||
TeleportPlayer( pOther );
|
||||
|
||||
m_flNextTouchTime = gpGlobals->curtime + StargateTC::GATE_TRAVEL_COOLDOWN;
|
||||
}
|
||||
|
||||
void CStargateTravelZone::TeleportPlayer( CBaseEntity *pPlayer )
|
||||
{
|
||||
CBaseEntity *pDestination = gEntList.FindEntityByName( NULL, m_target );
|
||||
if ( !pDestination )
|
||||
return;
|
||||
|
||||
Vector destination = pDestination->GetAbsOrigin();
|
||||
QAngle angles = pDestination->GetAbsAngles();
|
||||
Vector velocity = vec3_origin;
|
||||
pPlayer->Teleport( &destination, &angles, &velocity );
|
||||
}
|
||||
213
game/server/stargate/multi_gate.cpp
Normal file
213
game/server/stargate/multi_gate.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
//============= Copyright (c) StargateTC Source Team ==========================
|
||||
//
|
||||
// Source-side port of the original GoldSrc multi_gate_1..multi_gate_49 family.
|
||||
//
|
||||
// Ghidra shows every multi_gate_N as a 0x248-byte CMultigateN object with the
|
||||
// same ManagerUse/ManagerThink loop as CMultiManager plus a small baked target
|
||||
// table. The first gate contains chevronsnd, dial1change1, dhdglyph1_on, and
|
||||
// ch1relayon at zero delay; later gates follow the same naming convention.
|
||||
//
|
||||
//=============================================================================
|
||||
#include "cbase.h"
|
||||
#include "eventqueue.h"
|
||||
#include "utlvector.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr int kMaxGateTargets = 16;
|
||||
|
||||
struct GateTarget
|
||||
{
|
||||
string_t targetName;
|
||||
float delay;
|
||||
};
|
||||
}
|
||||
|
||||
class CStargateMultiGate : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CStargateMultiGate, CBaseEntity );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
explicit CStargateMultiGate( int gateIndex = 0 )
|
||||
: m_iGateIndex( gateIndex ),
|
||||
m_iCurrentTarget( 0 ),
|
||||
m_flStartTime( 0.0f )
|
||||
{
|
||||
}
|
||||
|
||||
bool KeyValue( const char *szKeyName, const char *szValue ) override;
|
||||
void Spawn() override;
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) override;
|
||||
void ManagerThink();
|
||||
|
||||
protected:
|
||||
void AddTarget( const char *pszTarget, float flDelay );
|
||||
void AddDefaultTargets();
|
||||
|
||||
private:
|
||||
CUtlVector<GateTarget> m_Targets;
|
||||
int m_iGateIndex;
|
||||
int m_iCurrentTarget;
|
||||
float m_flStartTime;
|
||||
EHANDLE m_hActivator;
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CStargateMultiGate )
|
||||
DEFINE_FIELD( m_iGateIndex, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_iCurrentTarget, FIELD_INTEGER ),
|
||||
DEFINE_FIELD( m_flStartTime, FIELD_TIME ),
|
||||
DEFINE_FIELD( m_hActivator, FIELD_EHANDLE ),
|
||||
DEFINE_THINKFUNC( ManagerThink ),
|
||||
END_DATADESC()
|
||||
|
||||
bool CStargateMultiGate::KeyValue( const char *szKeyName, const char *szValue )
|
||||
{
|
||||
if ( BaseClass::KeyValue( szKeyName, szValue ) )
|
||||
return true;
|
||||
|
||||
if ( m_Targets.Count() < kMaxGateTargets && szValue && *szValue )
|
||||
{
|
||||
char *pEnd = NULL;
|
||||
const float flDelay = static_cast<float>( strtod( szValue, &pEnd ) );
|
||||
if ( pEnd != szValue )
|
||||
{
|
||||
AddTarget( szKeyName, flDelay );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return BaseClass::KeyValue( szKeyName, szValue );
|
||||
}
|
||||
|
||||
void CStargateMultiGate::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
SetSolid( SOLID_NONE );
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
SetUse( &CStargateMultiGate::Use );
|
||||
|
||||
if ( m_Targets.Count() == 0 )
|
||||
AddDefaultTargets();
|
||||
}
|
||||
|
||||
void CStargateMultiGate::Use( CBaseEntity *pActivator, CBaseEntity *, USE_TYPE, float )
|
||||
{
|
||||
if ( m_Targets.Count() == 0 )
|
||||
return;
|
||||
|
||||
m_hActivator = pActivator;
|
||||
m_iCurrentTarget = 0;
|
||||
m_flStartTime = gpGlobals->curtime;
|
||||
SetThink( &CStargateMultiGate::ManagerThink );
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
}
|
||||
|
||||
void CStargateMultiGate::ManagerThink()
|
||||
{
|
||||
const float flElapsed = gpGlobals->curtime - m_flStartTime;
|
||||
|
||||
while ( m_iCurrentTarget < m_Targets.Count() && m_Targets[m_iCurrentTarget].delay <= flElapsed )
|
||||
{
|
||||
const char *pszTarget = STRING( m_Targets[m_iCurrentTarget].targetName );
|
||||
variant_t emptyVariant;
|
||||
g_EventQueue.AddEvent( pszTarget, "Use", emptyVariant, 0.0f, m_hActivator.Get(), this );
|
||||
++m_iCurrentTarget;
|
||||
}
|
||||
|
||||
if ( m_iCurrentTarget < m_Targets.Count() )
|
||||
{
|
||||
SetNextThink( m_flStartTime + m_Targets[m_iCurrentTarget].delay );
|
||||
return;
|
||||
}
|
||||
|
||||
SetThink( NULL );
|
||||
}
|
||||
|
||||
void CStargateMultiGate::AddTarget( const char *pszTarget, float flDelay )
|
||||
{
|
||||
if ( !pszTarget || !*pszTarget || m_Targets.Count() >= kMaxGateTargets )
|
||||
return;
|
||||
|
||||
GateTarget &target = m_Targets[m_Targets.AddToTail()];
|
||||
target.targetName = AllocPooledString( pszTarget );
|
||||
target.delay = flDelay;
|
||||
}
|
||||
|
||||
void CStargateMultiGate::AddDefaultTargets()
|
||||
{
|
||||
if ( m_iGateIndex <= 0 )
|
||||
return;
|
||||
|
||||
char targetName[64];
|
||||
|
||||
AddTarget( "chevronsnd", 0.0f );
|
||||
|
||||
Q_snprintf( targetName, sizeof( targetName ), "dial%dchange1", m_iGateIndex );
|
||||
AddTarget( targetName, 0.0f );
|
||||
|
||||
Q_snprintf( targetName, sizeof( targetName ), "dhdglyph%d_on", m_iGateIndex );
|
||||
AddTarget( targetName, 0.0f );
|
||||
|
||||
Q_snprintf( targetName, sizeof( targetName ), "ch%drelayon", m_iGateIndex );
|
||||
AddTarget( targetName, 0.0f );
|
||||
}
|
||||
|
||||
#define LINK_MULTIGATE_ENTITY( index ) \
|
||||
class CStargateMultiGate##index : public CStargateMultiGate \
|
||||
{ \
|
||||
public: \
|
||||
DECLARE_CLASS( CStargateMultiGate##index, CStargateMultiGate ); \
|
||||
CStargateMultiGate##index() : BaseClass( index ) {} \
|
||||
}; \
|
||||
LINK_ENTITY_TO_CLASS( multi_gate_##index, CStargateMultiGate##index )
|
||||
|
||||
LINK_MULTIGATE_ENTITY( 1 );
|
||||
LINK_MULTIGATE_ENTITY( 2 );
|
||||
LINK_MULTIGATE_ENTITY( 3 );
|
||||
LINK_MULTIGATE_ENTITY( 4 );
|
||||
LINK_MULTIGATE_ENTITY( 5 );
|
||||
LINK_MULTIGATE_ENTITY( 6 );
|
||||
LINK_MULTIGATE_ENTITY( 7 );
|
||||
LINK_MULTIGATE_ENTITY( 8 );
|
||||
LINK_MULTIGATE_ENTITY( 9 );
|
||||
LINK_MULTIGATE_ENTITY( 10 );
|
||||
LINK_MULTIGATE_ENTITY( 11 );
|
||||
LINK_MULTIGATE_ENTITY( 12 );
|
||||
LINK_MULTIGATE_ENTITY( 13 );
|
||||
LINK_MULTIGATE_ENTITY( 14 );
|
||||
LINK_MULTIGATE_ENTITY( 15 );
|
||||
LINK_MULTIGATE_ENTITY( 16 );
|
||||
LINK_MULTIGATE_ENTITY( 17 );
|
||||
LINK_MULTIGATE_ENTITY( 18 );
|
||||
LINK_MULTIGATE_ENTITY( 19 );
|
||||
LINK_MULTIGATE_ENTITY( 20 );
|
||||
LINK_MULTIGATE_ENTITY( 21 );
|
||||
LINK_MULTIGATE_ENTITY( 22 );
|
||||
LINK_MULTIGATE_ENTITY( 23 );
|
||||
LINK_MULTIGATE_ENTITY( 24 );
|
||||
LINK_MULTIGATE_ENTITY( 25 );
|
||||
LINK_MULTIGATE_ENTITY( 26 );
|
||||
LINK_MULTIGATE_ENTITY( 27 );
|
||||
LINK_MULTIGATE_ENTITY( 28 );
|
||||
LINK_MULTIGATE_ENTITY( 29 );
|
||||
LINK_MULTIGATE_ENTITY( 30 );
|
||||
LINK_MULTIGATE_ENTITY( 31 );
|
||||
LINK_MULTIGATE_ENTITY( 32 );
|
||||
LINK_MULTIGATE_ENTITY( 33 );
|
||||
LINK_MULTIGATE_ENTITY( 34 );
|
||||
LINK_MULTIGATE_ENTITY( 35 );
|
||||
LINK_MULTIGATE_ENTITY( 36 );
|
||||
LINK_MULTIGATE_ENTITY( 37 );
|
||||
LINK_MULTIGATE_ENTITY( 38 );
|
||||
LINK_MULTIGATE_ENTITY( 39 );
|
||||
LINK_MULTIGATE_ENTITY( 40 );
|
||||
LINK_MULTIGATE_ENTITY( 41 );
|
||||
LINK_MULTIGATE_ENTITY( 42 );
|
||||
LINK_MULTIGATE_ENTITY( 43 );
|
||||
LINK_MULTIGATE_ENTITY( 44 );
|
||||
LINK_MULTIGATE_ENTITY( 45 );
|
||||
LINK_MULTIGATE_ENTITY( 46 );
|
||||
LINK_MULTIGATE_ENTITY( 47 );
|
||||
LINK_MULTIGATE_ENTITY( 48 );
|
||||
LINK_MULTIGATE_ENTITY( 49 );
|
||||
569
game/server/stargate/recovered_entities.cpp
Normal file
569
game/server/stargate/recovered_entities.cpp
Normal file
@ -0,0 +1,569 @@
|
||||
//============= Copyright (c) StargateTC Source Team ==========================
|
||||
//
|
||||
// Broad registration pass for custom entities recovered from hl.dll.
|
||||
//
|
||||
// This file is intentionally conservative: it keeps the recovered classnames
|
||||
// spawnable in Source maps without pretending the gameplay is complete. Entities
|
||||
// with hand-ported behavior live in their own files and are not registered here.
|
||||
//
|
||||
// Source list: dll_re_workspace/output/hl/strings_categorized.json
|
||||
//
|
||||
//=============================================================================
|
||||
#include "cbase.h"
|
||||
#include "eventqueue.h"
|
||||
#include "triggers.h"
|
||||
|
||||
class CSGRecoveredEntity : public CBaseAnimating
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGRecoveredEntity, CBaseAnimating );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void Spawn() override;
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) override;
|
||||
|
||||
private:
|
||||
COutputEvent m_OnUse;
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CSGRecoveredEntity )
|
||||
DEFINE_OUTPUT( m_OnUse, "OnUse" ),
|
||||
END_DATADESC()
|
||||
|
||||
void CSGRecoveredEntity::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
SetSolid( SOLID_NONE );
|
||||
SetUse( &CSGRecoveredEntity::Use );
|
||||
|
||||
if ( GetModelName() != NULL_STRING )
|
||||
{
|
||||
PrecacheModel( STRING( GetModelName() ) );
|
||||
SetModel( STRING( GetModelName() ) );
|
||||
}
|
||||
}
|
||||
|
||||
void CSGRecoveredEntity::Use( CBaseEntity *pActivator, CBaseEntity *, USE_TYPE, float )
|
||||
{
|
||||
m_OnUse.FireOutput( pActivator, this );
|
||||
|
||||
if ( m_target != NULL_STRING )
|
||||
{
|
||||
variant_t emptyVariant;
|
||||
g_EventQueue.AddEvent( STRING( m_target ), "Use", emptyVariant, 0.0f, pActivator, this );
|
||||
}
|
||||
}
|
||||
|
||||
class CSGRecoveredBrushEntity : public CSGRecoveredEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGRecoveredBrushEntity, CSGRecoveredEntity );
|
||||
|
||||
void Spawn() override
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
if ( GetModelName() != NULL_STRING )
|
||||
SetSolid( SOLID_BSP );
|
||||
}
|
||||
};
|
||||
|
||||
class CSGRecoveredClipEntity : public CSGRecoveredBrushEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGRecoveredClipEntity, CSGRecoveredBrushEntity );
|
||||
|
||||
void Spawn() override
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
AddEffects( EF_NODRAW );
|
||||
SetCollisionGroup( COLLISION_GROUP_PLAYER_MOVEMENT );
|
||||
}
|
||||
};
|
||||
|
||||
class CSGRecoveredTriggerEntity : public CBaseTrigger
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGRecoveredTriggerEntity, CBaseTrigger );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void Spawn() override;
|
||||
void TriggerTouch( CBaseEntity *pOther );
|
||||
|
||||
private:
|
||||
COutputEvent m_OnTrigger;
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CSGRecoveredTriggerEntity )
|
||||
DEFINE_OUTPUT( m_OnTrigger, "OnTrigger" ),
|
||||
DEFINE_ENTITYFUNC( TriggerTouch ),
|
||||
END_DATADESC()
|
||||
|
||||
void CSGRecoveredTriggerEntity::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
InitTrigger();
|
||||
SetTouch( &CSGRecoveredTriggerEntity::TriggerTouch );
|
||||
}
|
||||
|
||||
void CSGRecoveredTriggerEntity::TriggerTouch( CBaseEntity *pOther )
|
||||
{
|
||||
if ( !pOther || !pOther->IsPlayer() )
|
||||
return;
|
||||
|
||||
m_OnTrigger.FireOutput( pOther, this );
|
||||
if ( m_target != NULL_STRING )
|
||||
{
|
||||
variant_t emptyVariant;
|
||||
g_EventQueue.AddEvent( STRING( m_target ), "Use", emptyVariant, 0.0f, pOther, this );
|
||||
}
|
||||
}
|
||||
|
||||
class CSGTriggerRandom : public CSGRecoveredEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGTriggerRandom, CSGRecoveredEntity );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
bool KeyValue( const char *szKeyName, const char *szValue ) override;
|
||||
void Spawn() override;
|
||||
void RandomThink();
|
||||
|
||||
private:
|
||||
void ScheduleNextThink();
|
||||
|
||||
float m_flMinDelay { 0.0f };
|
||||
float m_flMaxDelay { 5.0f };
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CSGTriggerRandom )
|
||||
DEFINE_FIELD( m_flMinDelay, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_flMaxDelay, FIELD_FLOAT ),
|
||||
DEFINE_THINKFUNC( RandomThink ),
|
||||
END_DATADESC()
|
||||
|
||||
bool CSGTriggerRandom::KeyValue( const char *szKeyName, const char *szValue )
|
||||
{
|
||||
if ( !Q_stricmp( szKeyName, "min" ) || !Q_stricmp( szKeyName, "mindelay" ) )
|
||||
{
|
||||
m_flMinDelay = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !Q_stricmp( szKeyName, "max" ) || !Q_stricmp( szKeyName, "maxdelay" ) || !Q_stricmp( szKeyName, "wait" ) )
|
||||
{
|
||||
m_flMaxDelay = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
return BaseClass::KeyValue( szKeyName, szValue );
|
||||
}
|
||||
|
||||
void CSGTriggerRandom::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
SetThink( &CSGTriggerRandom::RandomThink );
|
||||
ScheduleNextThink();
|
||||
}
|
||||
|
||||
void CSGTriggerRandom::RandomThink()
|
||||
{
|
||||
if ( m_target != NULL_STRING )
|
||||
{
|
||||
variant_t emptyVariant;
|
||||
g_EventQueue.AddEvent( STRING( m_target ), "Use", emptyVariant, 0.0f, this, this );
|
||||
}
|
||||
|
||||
ScheduleNextThink();
|
||||
}
|
||||
|
||||
void CSGTriggerRandom::ScheduleNextThink()
|
||||
{
|
||||
const float flMin = MIN( m_flMinDelay, m_flMaxDelay );
|
||||
const float flMax = MAX( m_flMinDelay, m_flMaxDelay );
|
||||
SetNextThink( gpGlobals->curtime + random->RandomFloat( flMin, flMax ) );
|
||||
}
|
||||
|
||||
class CSGTriggerGoal : public CSGRecoveredTriggerEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGTriggerGoal, CSGRecoveredTriggerEntity );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
bool KeyValue( const char *szKeyName, const char *szValue ) override;
|
||||
void Spawn() override;
|
||||
void GoalTouch( CBaseEntity *pOther );
|
||||
|
||||
private:
|
||||
int m_iGoalTeam { 0 };
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CSGTriggerGoal )
|
||||
DEFINE_KEYFIELD( m_iGoalTeam, FIELD_INTEGER, "team" ),
|
||||
DEFINE_ENTITYFUNC( GoalTouch ),
|
||||
END_DATADESC()
|
||||
|
||||
bool CSGTriggerGoal::KeyValue( const char *szKeyName, const char *szValue )
|
||||
{
|
||||
if ( !Q_stricmp( szKeyName, "team_no" ) || !Q_stricmp( szKeyName, "goalteam" ) )
|
||||
{
|
||||
m_iGoalTeam = atoi( szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
return BaseClass::KeyValue( szKeyName, szValue );
|
||||
}
|
||||
|
||||
void CSGTriggerGoal::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
SetTouch( &CSGTriggerGoal::GoalTouch );
|
||||
}
|
||||
|
||||
void CSGTriggerGoal::GoalTouch( CBaseEntity *pOther )
|
||||
{
|
||||
if ( !pOther || !pOther->IsPlayer() )
|
||||
return;
|
||||
|
||||
if ( m_iGoalTeam != 0 && pOther->GetTeamNumber() != m_iGoalTeam )
|
||||
return;
|
||||
|
||||
TriggerTouch( pOther );
|
||||
}
|
||||
|
||||
class CSGPickupEntity : public CSGRecoveredEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGPickupEntity, CSGRecoveredEntity );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
bool KeyValue( const char *szKeyName, const char *szValue ) override;
|
||||
void Spawn() override;
|
||||
void PickupTouch( CBaseEntity *pOther );
|
||||
void RespawnThink();
|
||||
|
||||
private:
|
||||
COutputEvent m_OnPickup;
|
||||
float m_flRespawnTime { -1.0f };
|
||||
bool m_bActive { true };
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CSGPickupEntity )
|
||||
DEFINE_FIELD( m_flRespawnTime, FIELD_FLOAT ),
|
||||
DEFINE_FIELD( m_bActive, FIELD_BOOLEAN ),
|
||||
DEFINE_OUTPUT( m_OnPickup, "OnPickup" ),
|
||||
DEFINE_ENTITYFUNC( PickupTouch ),
|
||||
DEFINE_THINKFUNC( RespawnThink ),
|
||||
END_DATADESC()
|
||||
|
||||
bool CSGPickupEntity::KeyValue( const char *szKeyName, const char *szValue )
|
||||
{
|
||||
if ( !Q_stricmp( szKeyName, "respawn" ) || !Q_stricmp( szKeyName, "wait" ) )
|
||||
{
|
||||
m_flRespawnTime = atof( szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
return BaseClass::KeyValue( szKeyName, szValue );
|
||||
}
|
||||
|
||||
void CSGPickupEntity::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
SetSolid( SOLID_BBOX );
|
||||
UTIL_SetSize( this, Vector( -16, -16, 0 ), Vector( 16, 16, 32 ) );
|
||||
SetTouch( &CSGPickupEntity::PickupTouch );
|
||||
}
|
||||
|
||||
void CSGPickupEntity::PickupTouch( CBaseEntity *pOther )
|
||||
{
|
||||
if ( !m_bActive || !pOther || !pOther->IsPlayer() )
|
||||
return;
|
||||
|
||||
m_OnPickup.FireOutput( pOther, this );
|
||||
|
||||
if ( m_target != NULL_STRING )
|
||||
{
|
||||
variant_t emptyVariant;
|
||||
g_EventQueue.AddEvent( STRING( m_target ), "Use", emptyVariant, 0.0f, pOther, this );
|
||||
}
|
||||
|
||||
if ( m_flRespawnTime > 0.0f )
|
||||
{
|
||||
m_bActive = false;
|
||||
AddEffects( EF_NODRAW );
|
||||
SetSolid( SOLID_NONE );
|
||||
SetThink( &CSGPickupEntity::RespawnThink );
|
||||
SetNextThink( gpGlobals->curtime + m_flRespawnTime );
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
}
|
||||
|
||||
void CSGPickupEntity::RespawnThink()
|
||||
{
|
||||
m_bActive = true;
|
||||
RemoveEffects( EF_NODRAW );
|
||||
SetSolid( SOLID_BBOX );
|
||||
SetThink( NULL );
|
||||
}
|
||||
|
||||
class CSGEnvToggleEntity : public CSGRecoveredEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGEnvToggleEntity, CSGRecoveredEntity );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void InputEnable( inputdata_t & ) { RemoveEffects( EF_NODRAW ); }
|
||||
void InputDisable( inputdata_t & ) { AddEffects( EF_NODRAW ); }
|
||||
void InputToggle( inputdata_t & )
|
||||
{
|
||||
if ( IsEffectActive( EF_NODRAW ) )
|
||||
RemoveEffects( EF_NODRAW );
|
||||
else
|
||||
AddEffects( EF_NODRAW );
|
||||
}
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CSGEnvToggleEntity )
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
|
||||
END_DATADESC()
|
||||
|
||||
class CSGTargetCDAudio : public CSGRecoveredEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGTargetCDAudio, CSGRecoveredEntity );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
bool KeyValue( const char *szKeyName, const char *szValue ) override;
|
||||
void InputPlay( inputdata_t & );
|
||||
void InputStop( inputdata_t & );
|
||||
|
||||
private:
|
||||
int m_iTrack { -1 };
|
||||
COutputInt m_OnTrackChanged;
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CSGTargetCDAudio )
|
||||
DEFINE_FIELD( m_iTrack, FIELD_INTEGER ),
|
||||
DEFINE_OUTPUT( m_OnTrackChanged, "OnTrackChanged" ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Play", InputPlay ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Stop", InputStop ),
|
||||
END_DATADESC()
|
||||
|
||||
bool CSGTargetCDAudio::KeyValue( const char *szKeyName, const char *szValue )
|
||||
{
|
||||
if ( !Q_stricmp( szKeyName, "track" ) )
|
||||
{
|
||||
m_iTrack = atoi( szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
return BaseClass::KeyValue( szKeyName, szValue );
|
||||
}
|
||||
|
||||
void CSGTargetCDAudio::InputPlay( inputdata_t &inputdata )
|
||||
{
|
||||
m_OnTrackChanged.Set( m_iTrack, inputdata.pActivator ? inputdata.pActivator : this, this );
|
||||
}
|
||||
|
||||
void CSGTargetCDAudio::InputStop( inputdata_t &inputdata )
|
||||
{
|
||||
m_OnTrackChanged.Set( -1, inputdata.pActivator ? inputdata.pActivator : this, this );
|
||||
}
|
||||
|
||||
class CSGMonsterProxy : public CBaseAnimating
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGMonsterProxy, CBaseAnimating );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
bool KeyValue( const char *szKeyName, const char *szValue ) override;
|
||||
void Spawn() override;
|
||||
int OnTakeDamage( const CTakeDamageInfo &info ) override;
|
||||
void ProxyTouch( CBaseEntity *pOther );
|
||||
|
||||
private:
|
||||
int m_iStartHealth { 60 };
|
||||
int m_iTouchDamage { 0 };
|
||||
COutputEvent m_OnKilled;
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CSGMonsterProxy )
|
||||
DEFINE_KEYFIELD( m_iStartHealth, FIELD_INTEGER, "health" ),
|
||||
DEFINE_KEYFIELD( m_iTouchDamage, FIELD_INTEGER, "touchdamage" ),
|
||||
DEFINE_OUTPUT( m_OnKilled, "OnKilled" ),
|
||||
DEFINE_ENTITYFUNC( ProxyTouch ),
|
||||
END_DATADESC()
|
||||
|
||||
bool CSGMonsterProxy::KeyValue( const char *szKeyName, const char *szValue )
|
||||
{
|
||||
if ( !Q_stricmp( szKeyName, "dmg" ) )
|
||||
{
|
||||
m_iTouchDamage = atoi( szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
return BaseClass::KeyValue( szKeyName, szValue );
|
||||
}
|
||||
|
||||
void CSGMonsterProxy::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
SetMoveType( MOVETYPE_STEP );
|
||||
SetSolid( SOLID_BBOX );
|
||||
UTIL_SetSize( this, Vector( -16, -16, 0 ), Vector( 16, 16, 72 ) );
|
||||
m_takedamage = DAMAGE_YES;
|
||||
m_iHealth = m_iStartHealth;
|
||||
SetTouch( &CSGMonsterProxy::ProxyTouch );
|
||||
|
||||
if ( GetModelName() != NULL_STRING )
|
||||
{
|
||||
PrecacheModel( STRING( GetModelName() ) );
|
||||
SetModel( STRING( GetModelName() ) );
|
||||
}
|
||||
}
|
||||
|
||||
int CSGMonsterProxy::OnTakeDamage( const CTakeDamageInfo &info )
|
||||
{
|
||||
const int result = BaseClass::OnTakeDamage( info );
|
||||
if ( m_iHealth <= 0 )
|
||||
{
|
||||
m_OnKilled.FireOutput( info.GetAttacker() ? info.GetAttacker() : this, this );
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void CSGMonsterProxy::ProxyTouch( CBaseEntity *pOther )
|
||||
{
|
||||
if ( !pOther || !pOther->IsPlayer() || m_iTouchDamage <= 0 )
|
||||
return;
|
||||
|
||||
CTakeDamageInfo dmgInfo( this, this, float( m_iTouchDamage ), DMG_SLASH );
|
||||
pOther->TakeDamage( dmgInfo );
|
||||
}
|
||||
|
||||
class CSGTriggerSecret : public CSGRecoveredTriggerEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGTriggerSecret, CSGRecoveredTriggerEntity );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void SecretTouch( CBaseEntity *pOther );
|
||||
|
||||
private:
|
||||
static int s_iSecretsFound;
|
||||
COutputInt m_OnSecretFound;
|
||||
bool m_bTriggered { false };
|
||||
};
|
||||
|
||||
int CSGTriggerSecret::s_iSecretsFound = 0;
|
||||
|
||||
BEGIN_DATADESC( CSGTriggerSecret )
|
||||
DEFINE_FIELD( m_bTriggered, FIELD_BOOLEAN ),
|
||||
DEFINE_OUTPUT( m_OnSecretFound, "OnSecretFound" ),
|
||||
DEFINE_ENTITYFUNC( SecretTouch ),
|
||||
END_DATADESC()
|
||||
|
||||
void CSGTriggerSecret::SecretTouch( CBaseEntity *pOther )
|
||||
{
|
||||
if ( m_bTriggered || !pOther || !pOther->IsPlayer() )
|
||||
return;
|
||||
|
||||
m_bTriggered = true;
|
||||
++s_iSecretsFound;
|
||||
m_OnSecretFound.Set( s_iSecretsFound, pOther, this );
|
||||
TriggerTouch( pOther );
|
||||
SetTouch( NULL );
|
||||
}
|
||||
|
||||
// Ammo and items.
|
||||
LINK_ENTITY_TO_CLASS( ammo_9mmAR, CSGPickupEntity );
|
||||
LINK_ENTITY_TO_CLASS( ammo_psg1, CSGPickupEntity );
|
||||
LINK_ENTITY_TO_CLASS( item_NVG, CSGPickupEntity );
|
||||
LINK_ENTITY_TO_CLASS( item_airtank, CSGPickupEntity );
|
||||
LINK_ENTITY_TO_CLASS( item_objective, CSGPickupEntity );
|
||||
|
||||
// Cyclers. (cycler/cycler_weapon/cycler_wreckage are registered in h_cycler.cpp — omitted to avoid double-registration heap corruption)
|
||||
LINK_ENTITY_TO_CLASS( cycler_prdroid, CSGRecoveredEntity );
|
||||
LINK_ENTITY_TO_CLASS( cycler_sprite, CSGRecoveredEntity );
|
||||
|
||||
// Environment helpers.
|
||||
LINK_ENTITY_TO_CLASS( env_debris, CSGEnvToggleEntity );
|
||||
LINK_ENTITY_TO_CLASS( env_fog, CSGEnvToggleEntity );
|
||||
LINK_ENTITY_TO_CLASS( env_fountain, CSGEnvToggleEntity );
|
||||
LINK_ENTITY_TO_CLASS( env_lensflare, CSGEnvToggleEntity );
|
||||
LINK_ENTITY_TO_CLASS( env_model, CSGEnvToggleEntity );
|
||||
LINK_ENTITY_TO_CLASS( env_particule, CSGEnvToggleEntity );
|
||||
|
||||
// Brush and movement helpers.
|
||||
// (func_guntarget/func_wall_toggle/func_traincontrols/func_trackchange/func_trackautochange
|
||||
// are all registered in SDK base — omitted to avoid double-registration heap corruption)
|
||||
LINK_ENTITY_TO_CLASS( func_mortar_field, CSGRecoveredBrushEntity );
|
||||
LINK_ENTITY_TO_CLASS( func_tankgoauld, CSGRecoveredBrushEntity );
|
||||
LINK_ENTITY_TO_CLASS( func_monsterclip, CSGRecoveredClipEntity );
|
||||
|
||||
// Game event hooks.
|
||||
LINK_ENTITY_TO_CLASS( game_nuke, CSGRecoveredEntity );
|
||||
LINK_ENTITY_TO_CLASS( game_playerdie, CSGRecoveredEntity );
|
||||
LINK_ENTITY_TO_CLASS( game_playerjoin, CSGRecoveredEntity );
|
||||
LINK_ENTITY_TO_CLASS( game_playerkill, CSGRecoveredEntity );
|
||||
LINK_ENTITY_TO_CLASS( game_playerleave, CSGRecoveredEntity );
|
||||
LINK_ENTITY_TO_CLASS( game_playerspawn, CSGRecoveredEntity );
|
||||
|
||||
// Info and marker entities. info_player_* team spawns have a more
|
||||
// specific spawnpoint implementation in sg_player_spawn.cpp.
|
||||
LINK_ENTITY_TO_CLASS( info_cap_rules, CSGRecoveredEntity );
|
||||
LINK_ENTITY_TO_CLASS( info_flash, CSGRecoveredEntity );
|
||||
LINK_ENTITY_TO_CLASS( info_marker, CSGRecoveredEntity );
|
||||
// info_null is registered in SDK base (subs.cpp) — omitted to avoid double-registration
|
||||
LINK_ENTITY_TO_CLASS( info_observer, CSGRecoveredEntity );
|
||||
LINK_ENTITY_TO_CLASS( info_radar_block, CSGRecoveredEntity );
|
||||
// target_cdaudio is registered in SDK base (controlentities.cpp) — omitted to avoid double-registration
|
||||
|
||||
// Monsters. AI/abilities remain to be ported, but these now have damage and touch behavior.
|
||||
LINK_ENTITY_TO_CLASS( monster_barney_dead, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_bloater, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_cine2_hvyweapons, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_cine2_scientist, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_cine2_slave, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_cine3_barney, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_cine3_scientist, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_cine_barney, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_cine_panther, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_cine_scientist, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_cockroach, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_flyer, CSGMonsterProxy );
|
||||
// monster_furniture is registered in SDK base (genericmonster.cpp) — omitted to avoid double-registration
|
||||
LINK_ENTITY_TO_CLASS( monster_grunt_repel, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_hevsuit_dead, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_hgrunt_dead, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_implanted, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_larve, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_mine, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_mortar, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_nihilanth, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_replic, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_replicateur, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_replicator, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_satchel, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_scientist_dead, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_skull, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_tac, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_tentaclemaw, CSGMonsterProxy );
|
||||
LINK_ENTITY_TO_CLASS( monster_vortigaunt, CSGMonsterProxy );
|
||||
|
||||
// Additional triggers. trigger_adv_teleport is hand-ported in gate_travel.cpp.
|
||||
LINK_ENTITY_TO_CLASS( trigger_goal, CSGTriggerGoal );
|
||||
LINK_ENTITY_TO_CLASS( trigger_monsterjump, CSGRecoveredTriggerEntity );
|
||||
LINK_ENTITY_TO_CLASS( trigger_random, CSGTriggerRandom );
|
||||
LINK_ENTITY_TO_CLASS( trigger_secret, CSGTriggerSecret );
|
||||
// trigger_transition is registered in SDK base (triggers.cpp) — omitted to avoid double-registration
|
||||
|
||||
// Weapons are registered as real predicted client/server HL2MP weapons in
|
||||
// sourcecode/shared/stargate/sg_weapons.cpp.
|
||||
69
game/server/stargate/ring_transporter.cpp
Normal file
69
game/server/stargate/ring_transporter.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
//============= Copyright © StargateTC Source Team =============================
|
||||
//
|
||||
// ring_transporter — Goa'uld ring teleport pad. A player stepping onto the pad
|
||||
// gets sent to the paired pad after a short delay. Pairs are matched via the
|
||||
// `target` keyvalue (each ring names the other).
|
||||
//
|
||||
//==============================================================================
|
||||
#include "cbase.h"
|
||||
#include "stargate/sg_constants.h"
|
||||
|
||||
class CRingTransporter : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CRingTransporter, CBaseEntity );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void Spawn() override;
|
||||
void TouchTransport( CBaseEntity *pOther );
|
||||
void DoTransport();
|
||||
void Cooldown() { m_flNextActive = 0; SetNextThink( TICK_NEVER_THINK ); }
|
||||
|
||||
private:
|
||||
EHANDLE m_hPending;
|
||||
float m_flNextActive { 0.0f };
|
||||
};
|
||||
|
||||
LINK_ENTITY_TO_CLASS( ring_transporter, CRingTransporter );
|
||||
|
||||
BEGIN_DATADESC( CRingTransporter )
|
||||
DEFINE_FIELD( m_hPending, FIELD_EHANDLE ),
|
||||
DEFINE_FIELD( m_flNextActive, FIELD_TIME ),
|
||||
DEFINE_ENTITYFUNC( TouchTransport ),
|
||||
DEFINE_THINKFUNC( DoTransport ),
|
||||
END_DATADESC()
|
||||
|
||||
|
||||
void CRingTransporter::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
SetSolid( SOLID_BBOX );
|
||||
SetCollisionGroup( COLLISION_GROUP_NONE );
|
||||
UTIL_SetSize( this, Vector(-48,-48,0), Vector(48,48,16) );
|
||||
SetTouch( &CRingTransporter::TouchTransport );
|
||||
}
|
||||
|
||||
void CRingTransporter::TouchTransport( CBaseEntity *pOther )
|
||||
{
|
||||
if ( !pOther || !pOther->IsPlayer() ) return;
|
||||
if ( gpGlobals->curtime < m_flNextActive ) return;
|
||||
|
||||
m_hPending = pOther;
|
||||
m_flNextActive = gpGlobals->curtime + StargateTC::RING_COOLDOWN;
|
||||
SetThink( &CRingTransporter::DoTransport );
|
||||
SetNextThink( gpGlobals->curtime + StargateTC::RING_TRAVEL_TIME );
|
||||
// TODO: spawn ring VFX + sound here.
|
||||
}
|
||||
|
||||
void CRingTransporter::DoTransport()
|
||||
{
|
||||
CBaseEntity *pTarget = gEntList.FindEntityByName( NULL, m_target );
|
||||
CBaseEntity *pPlayer = m_hPending;
|
||||
if ( pTarget && pPlayer )
|
||||
{
|
||||
pPlayer->Teleport( &pTarget->GetAbsOrigin(), NULL, NULL );
|
||||
}
|
||||
m_hPending = NULL;
|
||||
SetThink( &CRingTransporter::Cooldown );
|
||||
SetNextThink( gpGlobals->curtime + StargateTC::RING_COOLDOWN );
|
||||
}
|
||||
126
game/server/stargate/sg_event.cpp
Normal file
126
game/server/stargate/sg_event.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
//============= Copyright © StargateTC Source Team =============================
|
||||
//
|
||||
// stargate_event — the master entity that drives a Stargate dial. Other gate
|
||||
// pieces (the rotating ring brushwork, chevron light props, kawoosh emitter)
|
||||
// hook to this via parentname / OnDial outputs.
|
||||
//
|
||||
// Inputs:
|
||||
// Dial — kick off the 7-chevron sequence
|
||||
// ForceClose — interrupt the dial (or shut down an open wormhole)
|
||||
// Lock — disable for this round
|
||||
//
|
||||
// Outputs:
|
||||
// OnDialStart
|
||||
// OnChevronLock (passes chevron index 1..7)
|
||||
// OnKawoosh
|
||||
// OnWormholeOpen
|
||||
// OnWormholeClose
|
||||
//
|
||||
// First-pass behavior: spawns, registers, accepts inputs, fires outputs on a
|
||||
// fixed schedule driven by StargateTC::DIAL_SYMBOL_TIME. No gameplay
|
||||
// consequences yet — those land when the player-teleport + kawoosh damage
|
||||
// logic ports.
|
||||
//
|
||||
//==============================================================================
|
||||
#include "cbase.h"
|
||||
#include "stargate/sg_constants.h"
|
||||
|
||||
class CStargateEvent : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CStargateEvent, CBaseEntity );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void Spawn() override;
|
||||
void Precache() override;
|
||||
|
||||
// I/O
|
||||
void InputDial( inputdata_t &inputdata );
|
||||
void InputForceClose( inputdata_t &inputdata );
|
||||
void InputLock( inputdata_t &inputdata );
|
||||
|
||||
void DialThink();
|
||||
void WormholeOpenThink();
|
||||
|
||||
private:
|
||||
int m_iChevronsLocked { 0 };
|
||||
bool m_bLocked { false };
|
||||
|
||||
COutputEvent m_OnDialStart;
|
||||
COutputInt m_OnChevronLock;
|
||||
COutputEvent m_OnKawoosh;
|
||||
COutputEvent m_OnWormholeOpen;
|
||||
COutputEvent m_OnWormholeClose;
|
||||
};
|
||||
|
||||
LINK_ENTITY_TO_CLASS( stargate_event, CStargateEvent );
|
||||
|
||||
BEGIN_DATADESC( CStargateEvent )
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Dial", InputDial ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "ForceClose", InputForceClose ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Lock", InputLock ),
|
||||
DEFINE_OUTPUT( m_OnDialStart, "OnDialStart" ),
|
||||
DEFINE_OUTPUT( m_OnChevronLock, "OnChevronLock" ),
|
||||
DEFINE_OUTPUT( m_OnKawoosh, "OnKawoosh" ),
|
||||
DEFINE_OUTPUT( m_OnWormholeOpen, "OnWormholeOpen" ),
|
||||
DEFINE_OUTPUT( m_OnWormholeClose, "OnWormholeClose" ),
|
||||
DEFINE_THINKFUNC( DialThink ),
|
||||
DEFINE_THINKFUNC( WormholeOpenThink ),
|
||||
END_DATADESC()
|
||||
|
||||
|
||||
void CStargateEvent::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
Precache();
|
||||
SetSolid( SOLID_NONE );
|
||||
}
|
||||
|
||||
void CStargateEvent::Precache()
|
||||
{
|
||||
// TODO: precache gate ring rotation sound, chevron lock click, kawoosh whoosh.
|
||||
}
|
||||
|
||||
void CStargateEvent::InputDial( inputdata_t & )
|
||||
{
|
||||
if ( m_bLocked )
|
||||
return;
|
||||
m_iChevronsLocked = 0;
|
||||
m_OnDialStart.FireOutput( this, this );
|
||||
SetThink( &CStargateEvent::DialThink );
|
||||
SetNextThink( gpGlobals->curtime + StargateTC::DIAL_SYMBOL_TIME );
|
||||
}
|
||||
|
||||
void CStargateEvent::InputForceClose( inputdata_t & )
|
||||
{
|
||||
SetThink( NULL );
|
||||
m_iChevronsLocked = 0;
|
||||
m_OnWormholeClose.FireOutput( this, this );
|
||||
}
|
||||
|
||||
void CStargateEvent::InputLock( inputdata_t & )
|
||||
{
|
||||
m_bLocked = true;
|
||||
SetThink( NULL );
|
||||
}
|
||||
|
||||
void CStargateEvent::DialThink()
|
||||
{
|
||||
m_iChevronsLocked++;
|
||||
m_OnChevronLock.Set( m_iChevronsLocked, this, this );
|
||||
|
||||
if ( m_iChevronsLocked >= StargateTC::DIAL_SYMBOL_COUNT )
|
||||
{
|
||||
m_OnKawoosh.FireOutput( this, this );
|
||||
SetThink( &CStargateEvent::WormholeOpenThink );
|
||||
SetNextThink( gpGlobals->curtime + StargateTC::KAWOOSH_DURATION );
|
||||
return;
|
||||
}
|
||||
SetNextThink( gpGlobals->curtime + StargateTC::DIAL_SYMBOL_TIME );
|
||||
}
|
||||
|
||||
void CStargateEvent::WormholeOpenThink()
|
||||
{
|
||||
m_OnWormholeOpen.FireOutput( this, this );
|
||||
SetThink( NULL );
|
||||
}
|
||||
54
game/server/stargate/sg_kawoosh.cpp
Normal file
54
game/server/stargate/sg_kawoosh.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
//============= Copyright (c) StargateTC Source Team ==========================
|
||||
//
|
||||
// stargate_kawoosh - unstable vortex damage volume. The original GoldSrc DLL
|
||||
// exposes this as a custom gate entity; this Source pass makes it operational
|
||||
// through normal inputs so stargate_event can trigger it from Hammer I/O.
|
||||
//
|
||||
//=============================================================================
|
||||
#include "cbase.h"
|
||||
#include "stargate/sg_constants.h"
|
||||
|
||||
class CStargateKawoosh : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CStargateKawoosh, CBaseEntity );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void Spawn() override;
|
||||
void InputFire( inputdata_t &inputdata );
|
||||
void CollapseThink();
|
||||
|
||||
private:
|
||||
float m_flRadius;
|
||||
};
|
||||
|
||||
LINK_ENTITY_TO_CLASS( stargate_kawoosh, CStargateKawoosh );
|
||||
|
||||
BEGIN_DATADESC( CStargateKawoosh )
|
||||
DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Fire", InputFire ),
|
||||
DEFINE_THINKFUNC( CollapseThink ),
|
||||
END_DATADESC()
|
||||
|
||||
void CStargateKawoosh::Spawn()
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
SetSolid( SOLID_NONE );
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
|
||||
if ( m_flRadius <= 0.0f )
|
||||
m_flRadius = StargateTC::KAWOOSH_RADIUS;
|
||||
}
|
||||
|
||||
void CStargateKawoosh::InputFire( inputdata_t & )
|
||||
{
|
||||
CTakeDamageInfo info( this, this, StargateTC::KAWOOSH_DAMAGE, DMG_ENERGYBEAM | DMG_DISSOLVE );
|
||||
RadiusDamage( info, GetAbsOrigin(), m_flRadius, CLASS_NONE, NULL );
|
||||
SetThink( &CStargateKawoosh::CollapseThink );
|
||||
SetNextThink( gpGlobals->curtime + StargateTC::KAWOOSH_DURATION );
|
||||
}
|
||||
|
||||
void CStargateKawoosh::CollapseThink()
|
||||
{
|
||||
SetThink( NULL );
|
||||
}
|
||||
63
game/server/stargate/sg_player_spawn.cpp
Normal file
63
game/server/stargate/sg_player_spawn.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
//============= Copyright © StargateTC Source Team =============================
|
||||
//
|
||||
// info_player_torri / info_player_goauld — team-flavored multiplayer spawn
|
||||
// markers. The entity translator (pipeline/stargate_pipeline/entities/translator.py)
|
||||
// rewrites these to info_player_deathmatch + a "team" keyvalue at port time,
|
||||
// so HL2DM's spawn picker handles them automatically. We still register the
|
||||
// raw classnames here in case a hand-authored Source-side map uses them.
|
||||
//
|
||||
//==============================================================================
|
||||
#include "cbase.h"
|
||||
#include "stargate/sg_constants.h"
|
||||
|
||||
class CSGSpawnPoint : public CPointEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGSpawnPoint, CPointEntity );
|
||||
void Spawn() override
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
SetSolid( SOLID_NONE );
|
||||
}
|
||||
virtual int PreferredTeam() = 0;
|
||||
};
|
||||
|
||||
class CSGSpawnPointTorri : public CSGSpawnPoint
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGSpawnPointTorri, CSGSpawnPoint );
|
||||
int PreferredTeam() override { return StargateTC::TEAM_TORRI; }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( info_player_torri, CSGSpawnPointTorri );
|
||||
|
||||
class CSGSpawnPointGoauld : public CSGSpawnPoint
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGSpawnPointGoauld, CSGSpawnPoint );
|
||||
int PreferredTeam() override { return StargateTC::TEAM_GOAULD; }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( info_player_goauld, CSGSpawnPointGoauld );
|
||||
|
||||
class CSGSpawnPointMarine : public CSGSpawnPoint
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGSpawnPointMarine, CSGSpawnPoint );
|
||||
int PreferredTeam() override { return StargateTC::TEAM_TORRI; }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( info_player_marine, CSGSpawnPointMarine );
|
||||
|
||||
class CSGSpawnPointUnas : public CSGSpawnPoint
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGSpawnPointUnas, CSGSpawnPoint );
|
||||
int PreferredTeam() override { return StargateTC::TEAM_UNAS; }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( info_player_unas, CSGSpawnPointUnas );
|
||||
|
||||
class CSGSpawnPointCoop : public CSGSpawnPoint
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSGSpawnPointCoop, CSGSpawnPoint );
|
||||
int PreferredTeam() override { return StargateTC::TEAM_NONE; }
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( info_player_coop, CSGSpawnPointCoop );
|
||||
@ -115,6 +115,11 @@ static const char *s_PreserveEnts[] =
|
||||
"info_player_deathmatch",
|
||||
"info_player_combine",
|
||||
"info_player_rebel",
|
||||
"info_player_torri",
|
||||
"info_player_marine",
|
||||
"info_player_goauld",
|
||||
"info_player_unas",
|
||||
"info_player_coop",
|
||||
"info_map_parameters",
|
||||
"keyframe_rope",
|
||||
"move_rope",
|
||||
@ -179,8 +184,10 @@ char *sTeamNames[] =
|
||||
{
|
||||
"Unassigned",
|
||||
"Spectator",
|
||||
"Combine",
|
||||
"Rebels",
|
||||
"Tau'ri",
|
||||
"Goa'uld",
|
||||
"Jaffa",
|
||||
"Unas",
|
||||
};
|
||||
|
||||
CHL2MPRules::CHL2MPRules()
|
||||
@ -844,10 +851,10 @@ int CHL2MPRules::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget
|
||||
const char *CHL2MPRules::GetGameDescription( void )
|
||||
{
|
||||
if ( IsTeamplay() )
|
||||
return "Team Deathmatch";
|
||||
return "StargateTC Teamplay";
|
||||
|
||||
return "Deathmatch";
|
||||
}
|
||||
return "StargateTC";
|
||||
}
|
||||
|
||||
bool CHL2MPRules::IsConnectedUserInfoChangeAllowed( CBasePlayer *pPlayer )
|
||||
{
|
||||
|
||||
@ -28,8 +28,10 @@
|
||||
|
||||
enum
|
||||
{
|
||||
TEAM_COMBINE = 2,
|
||||
TEAM_REBELS,
|
||||
TEAM_COMBINE = 2, // StargateTC: Tau'ri / SG team slot
|
||||
TEAM_REBELS, // StargateTC: Goa'uld slot
|
||||
TEAM_JAFFA,
|
||||
TEAM_UNAS,
|
||||
};
|
||||
|
||||
|
||||
|
||||
55
game/shared/stargate/sg_constants.h
Normal file
55
game/shared/stargate/sg_constants.h
Normal file
@ -0,0 +1,55 @@
|
||||
//============= Copyright © StargateTC Source Team =============================
|
||||
//
|
||||
// Shared constants for the Stargate gameplay layer. Mirror these in any client-
|
||||
// side prediction code. Numbers come from the original GoldSrc mod's
|
||||
// `dlls/sg_*.cpp` files and from gameplay testing notes in
|
||||
// `stargatetc-portable-main/HPB_bot_ReadMe.txt`.
|
||||
//
|
||||
//==============================================================================
|
||||
#ifndef SG_CONSTANTS_H
|
||||
#define SG_CONSTANTS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace StargateTC
|
||||
{
|
||||
// Weapons
|
||||
constexpr float ZAT_DAMAGE_FIRST_SHOT = 35.0f; // stuns
|
||||
constexpr float ZAT_DAMAGE_SECOND_SHOT = 999.0f; // kills
|
||||
constexpr float ZAT_REFIRE_TIME = 0.9f;
|
||||
constexpr float ZAT_RANGE = 2048.0f;
|
||||
|
||||
constexpr float STAFF_DAMAGE_DIRECT = 60.0f;
|
||||
constexpr float STAFF_DAMAGE_RADIUS = 30.0f;
|
||||
constexpr float STAFF_RADIUS = 96.0f;
|
||||
constexpr float STAFF_REFIRE_TIME = 1.2f;
|
||||
|
||||
// Dial / event
|
||||
constexpr float DIAL_SYMBOL_TIME = 1.6f; // per chevron lock
|
||||
constexpr int DIAL_SYMBOL_COUNT = 7;
|
||||
constexpr float KAWOOSH_DURATION = 1.8f;
|
||||
constexpr float KAWOOSH_DAMAGE = 9999.0f;// instakill anything in volume
|
||||
constexpr float KAWOOSH_RADIUS = 256.0f;
|
||||
constexpr float GATE_TRAVEL_COOLDOWN = 1.0f;
|
||||
|
||||
// Ring transporter
|
||||
constexpr float RING_TRAVEL_TIME = 1.5f;
|
||||
constexpr float RING_COOLDOWN = 4.0f;
|
||||
|
||||
// Sarcophagus
|
||||
constexpr float SARC_REGEN_PER_SEC = 10.0f;
|
||||
constexpr float SARC_MAX_HEAL = 100.0f;
|
||||
|
||||
// Teams (carried through info_player_torri / info_player_goauld)
|
||||
enum Team : int
|
||||
{
|
||||
TEAM_NONE = 0,
|
||||
TEAM_TORRI = 2, // Tau'ri / SG-1
|
||||
TEAM_GOAULD = 3,
|
||||
TEAM_JAFFA = 4,
|
||||
TEAM_UNAS = 5,
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SG_CONSTANTS_H
|
||||
296
game/shared/stargate/sg_weapons.cpp
Normal file
296
game/shared/stargate/sg_weapons.cpp
Normal file
@ -0,0 +1,296 @@
|
||||
//============= Copyright (c) StargateTC Source Team ==========================
|
||||
//
|
||||
// Broad Source-side weapon port for StargateTC's recovered GoldSrc weapon
|
||||
// classnames. The decompile provides the original entity names and model assets
|
||||
// (`weapon_*`, `models/v_*`, `models/p_*`, `models/w_*`) plus method families
|
||||
// for melee weapons, grenades, projectiles, and visibility/support devices.
|
||||
//
|
||||
// This file keeps every recovered weapon as a real predicted HL2MP weapon on
|
||||
// client and server. Weapon-specific script files provide damage, ammo, clips,
|
||||
// HUD buckets, and model paths.
|
||||
//
|
||||
//=============================================================================
|
||||
#include "cbase.h"
|
||||
#include "weapon_hl2mpbasehlmpcombatweapon.h"
|
||||
#include "in_buttons.h"
|
||||
#include "npcevent.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_hl2mp_player.h"
|
||||
#else
|
||||
#include "hl2mp_player.h"
|
||||
#include "grenade_frag.h"
|
||||
#endif
|
||||
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#define CSTCWeapon9mmAR C_STCWeapon9mmAR
|
||||
#define CSTCWeaponBatonSupplice C_STCWeaponBatonSupplice
|
||||
#define CSTCWeaponC4 C_STCWeaponC4
|
||||
#define CSTCWeaponCoujaf C_STCWeaponCoujaf
|
||||
#define CSTCWeaponCouteau C_STCWeaponCouteau
|
||||
#define CSTCWeaponFlashbang C_STCWeaponFlashbang
|
||||
#define CSTCWeaponGacGoa C_STCWeaponGacGoa
|
||||
#define CSTCWeaponGlStaff C_STCWeaponGlStaff
|
||||
#define CSTCWeaponGoaRegen C_STCWeaponGoaRegen
|
||||
#define CSTCWeaponInvis C_STCWeaponInvis
|
||||
#define CSTCWeaponLance C_STCWeaponLance
|
||||
#define CSTCWeaponLarve C_STCWeaponLarve
|
||||
#define CSTCWeaponM16 C_STCWeaponM16
|
||||
#define CSTCWeaponM92S C_STCWeaponM92S
|
||||
#define CSTCWeaponMain C_STCWeaponMain
|
||||
#define CSTCWeaponMedic C_STCWeaponMedic
|
||||
#define CSTCWeaponMine C_STCWeaponMine
|
||||
#define CSTCWeaponMustardGrenade C_STCWeaponMustardGrenade
|
||||
#define CSTCWeaponNarcoGrenade C_STCWeaponNarcoGrenade
|
||||
#define CSTCWeaponNerveGrenade C_STCWeaponNerveGrenade
|
||||
#define CSTCWeaponP90 C_STCWeaponP90
|
||||
#define CSTCWeaponPSG1 C_STCWeaponPSG1
|
||||
#define CSTCWeaponReetou C_STCWeaponReetou
|
||||
#define CSTCWeaponSmokeGrenade C_STCWeaponSmokeGrenade
|
||||
#define CSTCWeaponSPAS C_STCWeaponSPAS
|
||||
#define CSTCWeaponTacGun C_STCWeaponTacGun
|
||||
#define CSTCWeaponUSAS C_STCWeaponUSAS
|
||||
#define CSTCWeaponZat C_STCWeaponZat
|
||||
#define CSTCWeaponZatArc C_STCWeaponZatArc
|
||||
#endif
|
||||
|
||||
enum STCWeaponKind
|
||||
{
|
||||
STC_WEAPON_HITSCAN,
|
||||
STC_WEAPON_MELEE,
|
||||
STC_WEAPON_GRENADE,
|
||||
STC_WEAPON_SUPPORT,
|
||||
};
|
||||
|
||||
struct STCWeaponConfig
|
||||
{
|
||||
STCWeaponKind kind;
|
||||
float fireRate;
|
||||
float meleeRange;
|
||||
float meleeDamage;
|
||||
Vector spread;
|
||||
};
|
||||
|
||||
static const STCWeaponConfig kSTCWeaponRifle = { STC_WEAPON_HITSCAN, 0.10f, 0.0f, 0.0f, VECTOR_CONE_4DEGREES };
|
||||
static const STCWeaponConfig kSTCWeaponPistol = { STC_WEAPON_HITSCAN, 0.22f, 0.0f, 0.0f, VECTOR_CONE_3DEGREES };
|
||||
static const STCWeaponConfig kSTCWeaponShotgun = { STC_WEAPON_HITSCAN, 0.80f, 0.0f, 0.0f, VECTOR_CONE_10DEGREES };
|
||||
static const STCWeaponConfig kSTCWeaponSniper = { STC_WEAPON_HITSCAN, 1.20f, 0.0f, 0.0f, VECTOR_CONE_1DEGREES };
|
||||
static const STCWeaponConfig kSTCWeaponEnergy = { STC_WEAPON_HITSCAN, 0.75f, 0.0f, 0.0f, VECTOR_CONE_2DEGREES };
|
||||
static const STCWeaponConfig kSTCWeaponMelee = { STC_WEAPON_MELEE, 0.45f, 72.0f, 35.0f, vec3_origin };
|
||||
static const STCWeaponConfig kSTCWeaponHeavyMelee = { STC_WEAPON_MELEE, 0.65f, 88.0f, 55.0f, vec3_origin };
|
||||
static const STCWeaponConfig kSTCWeaponGrenade = { STC_WEAPON_GRENADE, 1.00f, 0.0f, 0.0f, vec3_origin };
|
||||
static const STCWeaponConfig kSTCWeaponSupport = { STC_WEAPON_SUPPORT, 0.80f, 0.0f, 0.0f, vec3_origin };
|
||||
|
||||
class CSTCWeaponBase : public CBaseHL2MPCombatWeapon
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CSTCWeaponBase, CBaseHL2MPCombatWeapon );
|
||||
|
||||
CSTCWeaponBase()
|
||||
{
|
||||
m_bFiresUnderwater = true;
|
||||
}
|
||||
|
||||
virtual const STCWeaponConfig &GetSTCConfig() const = 0;
|
||||
|
||||
void Precache() override
|
||||
{
|
||||
BaseClass::Precache();
|
||||
#ifndef CLIENT_DLL
|
||||
if ( GetSTCConfig().kind == STC_WEAPON_GRENADE )
|
||||
UTIL_PrecacheOther( "npc_grenade_frag" );
|
||||
#endif
|
||||
}
|
||||
|
||||
void PrimaryAttack() override
|
||||
{
|
||||
const STCWeaponConfig &config = GetSTCConfig();
|
||||
|
||||
if ( config.kind == STC_WEAPON_MELEE )
|
||||
{
|
||||
MeleeAttack();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( config.kind == STC_WEAPON_GRENADE )
|
||||
{
|
||||
ThrowGrenade();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( config.kind == STC_WEAPON_SUPPORT )
|
||||
{
|
||||
SupportUse();
|
||||
return;
|
||||
}
|
||||
|
||||
BaseClass::PrimaryAttack();
|
||||
}
|
||||
|
||||
float GetFireRate() override
|
||||
{
|
||||
return GetSTCConfig().fireRate;
|
||||
}
|
||||
|
||||
const Vector &GetBulletSpread() override
|
||||
{
|
||||
return GetSTCConfig().spread;
|
||||
}
|
||||
|
||||
Activity GetPrimaryAttackActivity() override
|
||||
{
|
||||
return ACT_VM_PRIMARYATTACK;
|
||||
}
|
||||
|
||||
private:
|
||||
void MeleeAttack()
|
||||
{
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
if ( !pOwner )
|
||||
return;
|
||||
|
||||
WeaponSound( MELEE_MISS );
|
||||
SendWeaponAnim( ACT_VM_HITCENTER );
|
||||
pOwner->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
Vector vecForward;
|
||||
AngleVectors( pOwner->EyeAngles(), &vecForward );
|
||||
|
||||
const Vector vecSrc = pOwner->Weapon_ShootPosition();
|
||||
const Vector vecEnd = vecSrc + vecForward * GetSTCConfig().meleeRange;
|
||||
|
||||
trace_t tr;
|
||||
UTIL_TraceLine( vecSrc, vecEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &tr );
|
||||
if ( tr.fraction < 1.0f && tr.m_pEnt )
|
||||
{
|
||||
CTakeDamageInfo info( pOwner, pOwner, GetSTCConfig().meleeDamage, DMG_CLUB );
|
||||
tr.m_pEnt->TakeDamage( info );
|
||||
WeaponSound( MELEE_HIT );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + GetSTCConfig().fireRate;
|
||||
m_flNextSecondaryAttack = m_flNextPrimaryAttack;
|
||||
}
|
||||
|
||||
void ThrowGrenade()
|
||||
{
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
if ( !pOwner )
|
||||
return;
|
||||
|
||||
if ( UsesClipsForAmmo1() && m_iClip1 <= 0 )
|
||||
{
|
||||
Reload();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !UsesClipsForAmmo1() && pOwner->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
|
||||
return;
|
||||
|
||||
WeaponSound( SINGLE );
|
||||
SendWeaponAnim( ACT_VM_THROW );
|
||||
pOwner->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
Vector vecForward;
|
||||
AngleVectors( pOwner->EyeAngles(), &vecForward );
|
||||
|
||||
const Vector vecSrc = pOwner->Weapon_ShootPosition() + vecForward * 16.0f;
|
||||
const Vector vecThrow = vecForward * 900.0f + pOwner->GetAbsVelocity();
|
||||
Fraggrenade_Create(
|
||||
vecSrc,
|
||||
vec3_angle,
|
||||
vecThrow,
|
||||
AngularImpulse( 600, random->RandomInt( -1200, 1200 ), 0 ),
|
||||
pOwner,
|
||||
3.0f,
|
||||
false );
|
||||
#endif
|
||||
|
||||
if ( UsesClipsForAmmo1() )
|
||||
--m_iClip1;
|
||||
else
|
||||
pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
|
||||
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + GetSTCConfig().fireRate;
|
||||
m_flNextSecondaryAttack = m_flNextPrimaryAttack;
|
||||
}
|
||||
|
||||
void SupportUse()
|
||||
{
|
||||
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
|
||||
if ( !pOwner )
|
||||
return;
|
||||
|
||||
WeaponSound( SINGLE );
|
||||
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
||||
pOwner->SetAnimation( PLAYER_ATTACK1 );
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
if ( !Q_stricmp( GetClassname(), "weapon_medic" ) || !Q_stricmp( GetClassname(), "weapon_goaregen" ) )
|
||||
{
|
||||
pOwner->TakeHealth( 20.0f, DMG_GENERIC );
|
||||
}
|
||||
else if ( !Q_stricmp( GetClassname(), "weapon_invis" ) || !Q_stricmp( GetClassname(), "weapon_reetou" ) )
|
||||
{
|
||||
pOwner->AddEffects( EF_NODRAW );
|
||||
pOwner->SetRenderMode( kRenderTransTexture );
|
||||
pOwner->SetRenderColorA( 80 );
|
||||
}
|
||||
#endif
|
||||
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime + GetSTCConfig().fireRate;
|
||||
m_flNextSecondaryAttack = m_flNextPrimaryAttack;
|
||||
}
|
||||
};
|
||||
|
||||
#define DECLARE_STC_WEAPON( className, networkName, entityName, configName ) \
|
||||
class className : public CSTCWeaponBase \
|
||||
{ \
|
||||
public: \
|
||||
DECLARE_CLASS( className, CSTCWeaponBase ); \
|
||||
DECLARE_NETWORKCLASS(); \
|
||||
DECLARE_PREDICTABLE(); \
|
||||
const STCWeaponConfig &GetSTCConfig() const override { return configName; } \
|
||||
}; \
|
||||
IMPLEMENT_NETWORKCLASS_ALIASED( networkName, DT_##networkName ) \
|
||||
BEGIN_NETWORK_TABLE( className, DT_##networkName ) \
|
||||
END_NETWORK_TABLE() \
|
||||
BEGIN_PREDICTION_DATA( className ) \
|
||||
END_PREDICTION_DATA() \
|
||||
LINK_ENTITY_TO_CLASS( entityName, className ); \
|
||||
PRECACHE_WEAPON_REGISTER( entityName )
|
||||
|
||||
DECLARE_STC_WEAPON( CSTCWeapon9mmAR, STCWeapon9mmAR, weapon_9mmAR, kSTCWeaponRifle );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponBatonSupplice, STCWeaponBatonSupplice, weapon_batsup, kSTCWeaponHeavyMelee );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponC4, STCWeaponC4, weapon_c4, kSTCWeaponGrenade );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponCoujaf, STCWeaponCoujaf, weapon_coujaf, kSTCWeaponHeavyMelee );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponCouteau, STCWeaponCouteau, weapon_couteau, kSTCWeaponMelee );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponFlashbang, STCWeaponFlashbang, weapon_flashbang, kSTCWeaponGrenade );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponGacGoa, STCWeaponGacGoa, weapon_gacgoa, kSTCWeaponEnergy );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponGlStaff, STCWeaponGlStaff, weapon_glstaff, kSTCWeaponEnergy );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponGoaRegen, STCWeaponGoaRegen, weapon_goaregen, kSTCWeaponSupport );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponInvis, STCWeaponInvis, weapon_invis, kSTCWeaponSupport );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponLance, STCWeaponLance, weapon_lance, kSTCWeaponEnergy );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponLarve, STCWeaponLarve, weapon_larve, kSTCWeaponGrenade );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponM16, STCWeaponM16, weapon_m16, kSTCWeaponRifle );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponM92S, STCWeaponM92S, weapon_m92s, kSTCWeaponPistol );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponMain, STCWeaponMain, weapon_main, kSTCWeaponEnergy );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponMedic, STCWeaponMedic, weapon_medic, kSTCWeaponSupport );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponMine, STCWeaponMine, weapon_mine, kSTCWeaponGrenade );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponMustardGrenade, STCWeaponMustardGrenade, weapon_mustardgrenade, kSTCWeaponGrenade );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponNarcoGrenade, STCWeaponNarcoGrenade, weapon_narcogrenade, kSTCWeaponGrenade );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponNerveGrenade, STCWeaponNerveGrenade, weapon_nervegrenade, kSTCWeaponGrenade );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponP90, STCWeaponP90, weapon_p90, kSTCWeaponRifle );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponPSG1, STCWeaponPSG1, weapon_psg1, kSTCWeaponSniper );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponReetou, STCWeaponReetou, weapon_reetou, kSTCWeaponSupport );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponSmokeGrenade, STCWeaponSmokeGrenade, weapon_smokegrenade, kSTCWeaponGrenade );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponSPAS, STCWeaponSPAS, weapon_spas, kSTCWeaponShotgun );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponTacGun, STCWeaponTacGun, weapon_tacgun, kSTCWeaponEnergy );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponUSAS, STCWeaponUSAS, weapon_usas, kSTCWeaponShotgun );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponZat, STCWeaponZat, weapon_zat, kSTCWeaponEnergy );
|
||||
DECLARE_STC_WEAPON( CSTCWeaponZatArc, STCWeaponZatArc, weapon_zatarc, kSTCWeaponEnergy );
|
||||
Loading…
Reference in New Issue
Block a user