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.
420 lines
11 KiB
420 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; |
|
}
|
|
|