Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

421 lines
11 KiB

/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
/*
***************************************
****************************************
RUNES
****************************************
***************************************/
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "player.h"
#include "weapons.h"
#include "gamerules.h"
#include "threewave_gamerules.h"
#include "runes.h"
extern bool g_bSpawnedRunes;
/*----------------------------------------------------------------------
The Rune Game modes
Rune 1 - Earth Magic
resistance
Rune 2 - Black Magic
strength
Rune 3 - Hell Magic
haste
Rune 4 - Elder Magic
regeneration
----------------------------------------------------------------------*/
BOOL IsRuneSpawnPointValid( CBaseEntity *pSpot )
{
CBaseEntity *ent = NULL;
while( ( ent = UTIL_FindEntityInSphere( ent, pSpot->pev->origin, 128 ) ) != NULL )
{
//Try not to spawn it near other runes.
if( ent->Classify() == CLASS_RUNE )
return FALSE;
}
return TRUE;
}
edict_t *RuneSelectSpawnPoint()
{
CBaseEntity *pSpot = NULL;
// Randomize the start spot
for( int i = RANDOM_LONG( 1, 5 ); i > 0; i-- )
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
if( !pSpot ) // skip over the null point
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
CBaseEntity *pFirstSpot = pSpot;
do
{
if( pSpot )
{
if( IsRuneSpawnPointValid( pSpot ) )
{
if( pSpot->pev->origin == g_vecZero )
{
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
continue;
}
// if so, go to pSpot
goto ReturnSpot;
}
}
// increment pSpot
pSpot = UTIL_FindEntityByClassname( pSpot, "info_player_deathmatch" );
} while ( pSpot != pFirstSpot ); // loop if we're not back to the start
// we haven't found a place to spawn yet, so kill any guy at the first spawn point and spawn there
if( pSpot )
goto ReturnSpot;
// If startspot is set, (re)spawn there.
if( FStringNull( gpGlobals->startspot ) || !strlen( STRING( gpGlobals->startspot ) ) )
{
pSpot = UTIL_FindEntityByClassname( NULL, "info_player_start" );
}
else
{
pSpot = UTIL_FindEntityByTargetname( NULL, STRING( gpGlobals->startspot ) );
}
ReturnSpot:
if( !pSpot )
{
ALERT( at_error, "PutClientInServer: no info_player_start on level" );
return INDEXENT( 0 );
}
return pSpot->edict();
}
void VectorScale( const float *in, float scale, float *out )
{
out[0] = in[0] * scale;
out[1] = in[1] * scale;
out[2] = in[2] * scale;
}
void G_ProjectSource( vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result )
{
result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2];
}
#define VectorSet(v, x, y, z) (v[0]=(x), v[1]=(y), v[2]=(z))
void DropRune( CBasePlayer *pPlayer )
{
TraceResult tr;
// do they even have a rune?
if( pPlayer->m_iRuneStatus == 0 )
return;
// Make Sure there's enough room to drop the rune here
// This is so hacky ( the reason why we are doing this), and I hate it to death.
UTIL_MakeVectors( pPlayer->pev->v_angle );
Vector vecSrc = pPlayer->GetGunPosition( );
Vector vecEnd = vecSrc + gpGlobals->v_forward * 32;
UTIL_TraceHull( vecSrc, vecEnd, dont_ignore_monsters, human_hull, ENT( pPlayer->pev ), &tr );
if( tr.flFraction != 1 )
{
ClientPrint( pPlayer->pev, HUD_PRINTCENTER, "Not enough room to drop the rune here." );
return;
}
if( pPlayer->m_iRuneStatus )
{
CItemRune *pRune = (CItemRune*)CBaseEntity::Create( g_RuneEntityName[pPlayer->m_iRuneStatus], pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() );
if( pRune )
pRune->dropped = true;
if( pPlayer->m_iRuneStatus == ITEM_RUNE3_FLAG )
g_engfuncs.pfnSetClientMaxspeed( ENT( pPlayer->pev ), PLAYER_MAX_SPEED ); // Reset Haste player speed to normal
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_%s\"\n",
STRING(pPlayer->pev->netname),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
pPlayer->m_szTeamName,
g_RuneName[pPlayer->m_iRuneStatus] );
pPlayer->m_iRuneStatus = 0;
}
MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pPlayer->pev );
WRITE_BYTE( pPlayer->m_iRuneStatus );
MESSAGE_END();
}
void CItemRune::Spawn()
{
m_bTouchable = FALSE;
dropped = false;
pev->movetype = MOVETYPE_TOSS;
pev->solid = SOLID_TRIGGER;
vec3_t forward, right, up;
Vector vecAngles;
UTIL_SetSize( pev, Vector( -15, -15, -15 ), Vector( 15, 15, 15 ) );
pev->angles.z = pev->angles.x = 0;
pev->angles.y = RANDOM_LONG ( 0, 360 );
//If we got an owner, it means we are either dropping the flag or diying and letting it go.
if( pev->owner )
vecAngles = pev->owner->v.angles;
else
vecAngles = pev->angles;
g_engfuncs.pfnAngleVectors( vecAngles, forward, right, up );
UTIL_SetOrigin( pev, pev->origin );
pev->velocity = ( forward * 400 ) + ( up * 200 );
if( pev->owner == NULL )
{
pev->origin.z += 16;
pev->velocity.z = 300;
}
pev->owner = NULL;
SetTouch( &CItemRune::RuneTouch );
pev->nextthink = gpGlobals->time + 1; // if no one touches it in two minutes,
// respawn it somewhere else, so inaccessible
// ones will come 'back'
SetThink( &CItemRune::MakeTouchable );
}
void CItemRune::MakeTouchable()
{
m_bTouchable = TRUE;
pev->nextthink = gpGlobals->time + 120; // if no one touches it in two minutes,
// respawn it somewhere else, so inaccessible
// ones will come 'back'
SetThink( &CItemRune::RuneRespawn );
}
void CItemRune::RuneTouch( CBaseEntity *pOther )
{
// No toucher?
if( !pOther )
return;
// Not a player?
if( !pOther->IsPlayer() )
return;
// DEAD?!
if( pOther->pev->health <= 0 )
return;
// Spectating?
if( pOther->pev->movetype == MOVETYPE_NOCLIP )
return;
CBasePlayer *pPlayer = (CBasePlayer*)pOther;
// Only one per customer
if( pPlayer->m_iRuneStatus )
{
ClientPrint( pPlayer->pev, HUD_PRINTCENTER, "You already have a rune!\n" );
return;
}
if( !m_bTouchable )
return;
pPlayer->m_iRuneStatus = m_iRuneFlag; //Add me the rune flag
PrintTouchMessage( pPlayer );
EMIT_SOUND( ENT( pev ), CHAN_ITEM, "weapons/lock4.wav", 1, ATTN_NORM );
//Update my client side rune hud thingy.
MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pOther->pev );
WRITE_BYTE( pPlayer->m_iRuneStatus );
MESSAGE_END();
// And Remove this entity
UTIL_Remove( this );
}
void CItemRune::RuneRespawn()
{
edict_t *pentSpawnSpot;
vec3_t vOrigin;
pentSpawnSpot = RuneSelectSpawnPoint();
vOrigin = VARS( pentSpawnSpot )->origin;
UTIL_SetOrigin( pev, vOrigin );
if( dropped )
PrintRespawnMessage();
Spawn();
}
void CResistRune::PrintTouchMessage( CBasePlayer *pPlayer )
{
ClientPrint( pPlayer->pev, HUD_PRINTCENTER, "You got the rune of Resistance!\n" );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Found_ResistRune\"\n",
STRING(pPlayer->pev->netname),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
pPlayer->m_szTeamName );
}
void CResistRune::PrintRespawnMessage()
{
UTIL_LogPrintf( "\"<-1><><>\" triggered \"Respawn_ResistRune\"\n" );
}
void CResistRune::Spawn()
{
SET_MODEL( ENT( pev ), "models/rune_resist.mdl" );
m_iRuneFlag = ITEM_RUNE1_FLAG;
CItemRune::Spawn();
}
LINK_ENTITY_TO_CLASS( item_rune1, CResistRune );
void CStrengthRune::PrintTouchMessage( CBasePlayer *pPlayer )
{
ClientPrint( pPlayer->pev, HUD_PRINTCENTER, "You got the rune of Strength!\n" );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Found_StrengthRune\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
pPlayer->m_szTeamName );
}
void CStrengthRune::PrintRespawnMessage()
{
UTIL_LogPrintf( "\"<-1><><>\" triggered \"Respawn_StrengthRune\"\n" );
}
void CStrengthRune::Spawn()
{
SET_MODEL( ENT( pev ), "models/rune_strength.mdl" );
m_iRuneFlag = ITEM_RUNE2_FLAG;
CItemRune::Spawn();
}
LINK_ENTITY_TO_CLASS( item_rune2, CStrengthRune )
void CHasteRune::PrintTouchMessage( CBasePlayer *pPlayer )
{
ClientPrint( pPlayer->pev, HUD_PRINTCENTER, "You got the rune of Haste!\n" );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Found_HasteRune\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
pPlayer->m_szTeamName );
g_engfuncs.pfnSetClientMaxspeed( ENT( pPlayer->pev ), ( PLAYER_MAX_SPEED * 1.25 ) ); // 25% more speed
}
void CHasteRune::PrintRespawnMessage()
{
UTIL_LogPrintf( "\"<-1><><>\" triggered triggered \"Respawn_HasteRune\"\n" );
}
void CHasteRune::Spawn()
{
SET_MODEL( ENT( pev ), "models/rune_haste.mdl" );
m_iRuneFlag = ITEM_RUNE3_FLAG;
CItemRune::Spawn();
}
LINK_ENTITY_TO_CLASS( item_rune3, CHasteRune )
void CRegenRune::PrintTouchMessage( CBasePlayer *pPlayer )
{
ClientPrint( pPlayer->pev, HUD_PRINTCENTER, "You got the rune of Regeneration!\n" );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Found_RegenRune\"\n",
STRING( pPlayer->pev->netname ),
GETPLAYERUSERID( pPlayer->edict() ),
GETPLAYERAUTHID( pPlayer->edict() ),
pPlayer->m_szTeamName );
}
void CRegenRune::PrintRespawnMessage()
{
UTIL_LogPrintf( "\"<-1><><>\" triggered triggered \"Respawn_RegenRune\"\n" );
}
void CRegenRune::Spawn()
{
SET_MODEL( ENT( pev ), "models/rune_regen.mdl" );
m_iRuneFlag = ITEM_RUNE4_FLAG;
CItemRune::Spawn();
}
LINK_ENTITY_TO_CLASS( item_rune4, CRegenRune )
/*
================
SpawnRunes
spawn all the runes
self is the entity that was created for us, we remove it
================
*/
void SpawnRunes()
{
if( g_bSpawnedRunes )
return;
edict_t *pentSpawnSpot;
pentSpawnSpot = RuneSelectSpawnPoint();
CBaseEntity::Create( "item_rune1", VARS(pentSpawnSpot)->origin, VARS( pentSpawnSpot )->angles, NULL );
pentSpawnSpot = RuneSelectSpawnPoint();
CBaseEntity::Create( "item_rune2", VARS(pentSpawnSpot)->origin, VARS( pentSpawnSpot )->angles, NULL );
pentSpawnSpot = RuneSelectSpawnPoint();
CBaseEntity::Create( "item_rune3", VARS(pentSpawnSpot)->origin, VARS( pentSpawnSpot )->angles, NULL );
pentSpawnSpot = RuneSelectSpawnPoint();
CBaseEntity::Create( "item_rune4", VARS(pentSpawnSpot)->origin, VARS( pentSpawnSpot )->angles, NULL );
g_bSpawnedRunes = TRUE;
}