Night Owl
7 years ago
19 changed files with 2147 additions and 2611 deletions
@ -0,0 +1,570 @@
@@ -0,0 +1,570 @@
|
||||
/***
|
||||
* |
||||
* 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. |
||||
* |
||||
****/ |
||||
/*****************************************************
|
||||
****************************************************** |
||||
THREEWAVE CTF FLAG CODE |
||||
****************************************************** |
||||
*****************************************************/ |
||||
|
||||
#include "extdll.h" |
||||
#include "util.h" |
||||
#include "cbase.h" |
||||
#include "player.h" |
||||
#include "weapons.h" |
||||
#include "gamerules.h" |
||||
#include "items.h" |
||||
#include "threewave_gamerules.h" |
||||
#include "flags.h" |
||||
|
||||
unsigned short g_usCarried; |
||||
unsigned short g_usFlagSpawn; |
||||
enum Flag_Anims |
||||
{ |
||||
ON_GROUND = 0, |
||||
NOT_CARRIED, |
||||
CARRIED, |
||||
WAVE_IDLE, |
||||
FLAG_POSITION |
||||
}; |
||||
|
||||
void CItemFlag::Spawn() |
||||
{ |
||||
Precache(); |
||||
SET_MODEL( ENT( pev ), "models/flag.mdl" ); |
||||
|
||||
pev->movetype = MOVETYPE_TOSS; |
||||
pev->solid = SOLID_TRIGGER; |
||||
UTIL_SetOrigin( pev, pev->origin ); |
||||
UTIL_SetSize( pev, Vector( -16, -16, 0 ), Vector( 16, 16, 16 ) ); |
||||
|
||||
SetThink( &CItemFlag::FlagThink ); |
||||
SetTouch( &CItemFlag::FlagTouch ); |
||||
|
||||
pev->nextthink = gpGlobals->time + 0.3; |
||||
|
||||
//Set the Skin based on the team.
|
||||
pev->skin = pev->team; |
||||
|
||||
Dropped = FALSE; |
||||
m_flDroppedTime = 0.0; |
||||
|
||||
pev->sequence = NOT_CARRIED; |
||||
pev->framerate = 1.0; |
||||
|
||||
// if( !DROP_TO_FLOOR( ENT( pev ) ) )
|
||||
// ResetFlag( pev->team );
|
||||
} |
||||
|
||||
void CItemFlag::FlagTouch( CBaseEntity *pToucher ) |
||||
{ |
||||
if( !pToucher ) |
||||
return; |
||||
|
||||
if( !pToucher->IsPlayer() ) |
||||
return; |
||||
|
||||
if( FBitSet( pev->effects, EF_NODRAW ) ) |
||||
return; |
||||
|
||||
if( pToucher->pev->health <= 0 ) |
||||
return; |
||||
|
||||
if( pToucher->pev->team == 0 ) |
||||
return; |
||||
|
||||
CBasePlayer *pPlayer = (CBasePlayer *)pToucher; |
||||
|
||||
//Same team as the flag
|
||||
if( pev->team == pToucher->pev->team ) |
||||
{ |
||||
//Flag is dropped, let's return it
|
||||
if( Dropped ) |
||||
{ |
||||
Dropped = FALSE; |
||||
|
||||
pPlayer->AddPoints( TEAM_CAPTURE_RECOVERY_BONUS, TRUE ); |
||||
|
||||
if( pPlayer->pev->team == RED ) |
||||
{ |
||||
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Returned_Red_Flag\"\n", |
||||
STRING( pPlayer->pev->netname ), |
||||
GETPLAYERUSERID( pPlayer->edict() ), |
||||
GETPLAYERAUTHID( pPlayer->edict() ), |
||||
GetTeamName( pPlayer->pev->team ) ); |
||||
|
||||
if( ( (CThreeWave*)g_pGameRules )->iBlueFlagStatus == BLUE_FLAG_STOLEN ) |
||||
{ |
||||
for( int i = 1; i <= gpGlobals->maxClients; i++ ) |
||||
{ |
||||
CBasePlayer *pTeamMate = (CBasePlayer*)UTIL_PlayerByIndex( i ); |
||||
|
||||
if( pTeamMate ) |
||||
{ |
||||
if( pTeamMate->m_bHasFlag ) |
||||
{ |
||||
pTeamMate->pFlagReturner = pPlayer; |
||||
pTeamMate->m_flFlagReturnTime = gpGlobals->time + TEAM_CAPTURE_RETURN_FLAG_ASSIST_TIMEOUT; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
if( pPlayer->pev->team == BLUE ) |
||||
{ |
||||
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Returned_Blue_Flag\"\n", |
||||
STRING( pPlayer->pev->netname ), |
||||
GETPLAYERUSERID( pPlayer->edict() ), |
||||
GETPLAYERAUTHID( pPlayer->edict() ), |
||||
GetTeamName( pPlayer->pev->team ) ); |
||||
|
||||
if( ( (CThreeWave*)g_pGameRules )->iRedFlagStatus == RED_FLAG_STOLEN ) |
||||
{ |
||||
for( int i = 1; i <= gpGlobals->maxClients; i++ ) |
||||
{ |
||||
CBasePlayer *pTeamMate = (CBasePlayer*)UTIL_PlayerByIndex( i ); |
||||
|
||||
if( pTeamMate ) |
||||
{ |
||||
if( pTeamMate->m_bHasFlag ) |
||||
{ |
||||
pTeamMate->pFlagReturner = pPlayer; |
||||
pTeamMate->m_flFlagReturnTime = gpGlobals->time + TEAM_CAPTURE_RETURN_FLAG_ASSIST_TIMEOUT; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
//Back at home!
|
||||
ResetFlag( pev->team ); |
||||
|
||||
MESSAGE_BEGIN( MSG_ALL, gmsgCTFMsgs, NULL ); |
||||
if( pev->team == RED ) |
||||
WRITE_BYTE( RED_FLAG_RETURNED_PLAYER ); |
||||
else if( pev->team == BLUE ) |
||||
WRITE_BYTE( BLUE_FLAG_RETURNED_PLAYER ); |
||||
WRITE_STRING( STRING( pToucher->pev->netname ) ); |
||||
MESSAGE_END(); |
||||
|
||||
// Remove this one
|
||||
UTIL_Remove( this ); |
||||
return; |
||||
} |
||||
// Not Dropped, means it's the one in our base
|
||||
else |
||||
{ |
||||
// We have the enemy flag!
|
||||
// Capture it!
|
||||
if( pPlayer->m_bHasFlag ) |
||||
{ |
||||
if( pev->team == RED ) |
||||
Capture( pPlayer, BLUE ); |
||||
else if( pev->team == BLUE ) |
||||
Capture( pPlayer, RED ); |
||||
|
||||
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, |
||||
pPlayer->edict(), g_usCarried, 0, (float*)&g_vecZero, (float*)&g_vecZero, |
||||
0.0, 0.0, pPlayer->entindex(), pPlayer->pev->team, 1, 0 ); |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
if( Dropped ) |
||||
{ |
||||
MESSAGE_BEGIN( MSG_ALL, gmsgCTFMsgs, NULL ); |
||||
if( pev->team == RED ) |
||||
WRITE_BYTE( RED_FLAG_STOLEN ); |
||||
else if( pev->team == BLUE ) |
||||
WRITE_BYTE( BLUE_FLAG_STOLEN ); |
||||
WRITE_STRING( STRING( pToucher->pev->netname ) ); |
||||
MESSAGE_END(); |
||||
|
||||
pPlayer->m_bHasFlag = TRUE; |
||||
|
||||
CBaseEntity *pEnt = NULL; |
||||
|
||||
if( pev->team == RED ) |
||||
{ |
||||
pEnt = CBaseEntity::Create( "carried_flag_team1", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() ); |
||||
|
||||
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Picked_Up_Red_Flag\"\n", |
||||
STRING( pPlayer->pev->netname ), |
||||
GETPLAYERUSERID( pPlayer->edict() ), |
||||
GETPLAYERAUTHID( pPlayer->edict() ), |
||||
GetTeamName( pPlayer->pev->team ) ); |
||||
} |
||||
else if( pev->team == BLUE ) |
||||
{ |
||||
pEnt = CBaseEntity::Create( "carried_flag_team2", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() ); |
||||
|
||||
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Picked_Up_Blue_Flag\"\n", |
||||
STRING( pPlayer->pev->netname ), |
||||
GETPLAYERUSERID( pPlayer->edict() ), |
||||
GETPLAYERAUTHID( pPlayer->edict() ), |
||||
GetTeamName( pPlayer->pev->team ) ); |
||||
} |
||||
|
||||
CCarriedFlag *pCarriedFlag = (CCarriedFlag *)pEnt; |
||||
pCarriedFlag->Owner = pPlayer; |
||||
|
||||
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, |
||||
pPlayer->edict(), g_usCarried, 0, (float*)&g_vecZero, (float*)&g_vecZero, |
||||
0.0, 0.0, pPlayer->entindex(), pPlayer->pev->team, 0, 0 ); |
||||
|
||||
UTIL_Remove( this ); |
||||
} |
||||
else |
||||
{ |
||||
pev->effects |= EF_NODRAW; |
||||
MESSAGE_BEGIN( MSG_ALL, gmsgCTFMsgs, NULL ); |
||||
if( pev->team == RED ) |
||||
WRITE_BYTE( RED_FLAG_STOLEN ); |
||||
else if( pev->team == BLUE ) |
||||
WRITE_BYTE( BLUE_FLAG_STOLEN ); |
||||
WRITE_STRING( STRING( pToucher->pev->netname ) ); |
||||
MESSAGE_END(); |
||||
|
||||
pPlayer->m_bHasFlag = TRUE; |
||||
pPlayer->m_flCarrierPickupTime = gpGlobals->time + TEAM_CAPTURE_CARRIER_FLAG_SINCE_TIMEOUT; |
||||
|
||||
CBaseEntity *pEnt = NULL; |
||||
|
||||
if( pev->team == RED ) |
||||
{ |
||||
pEnt = CBaseEntity::Create( "carried_flag_team1", pev->origin, pev->angles, pPlayer->edict() ); |
||||
|
||||
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Stole_Red_Flag\"\n", |
||||
STRING( pPlayer->pev->netname ), |
||||
GETPLAYERUSERID( pPlayer->edict() ), |
||||
GETPLAYERAUTHID( pPlayer->edict() ), |
||||
GetTeamName( pPlayer->pev->team ) ); |
||||
} |
||||
else if( pev->team == BLUE ) |
||||
{ |
||||
pEnt = CBaseEntity::Create( "carried_flag_team2", pev->origin, pev->angles, pPlayer->edict() ); |
||||
|
||||
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Stole_Blue_Flag\"\n", |
||||
STRING( pPlayer->pev->netname ), |
||||
GETPLAYERUSERID( pPlayer->edict() ), |
||||
GETPLAYERAUTHID( pPlayer->edict() ), |
||||
GetTeamName( pPlayer->pev->team ) ); |
||||
} |
||||
|
||||
CCarriedFlag *pCarriedFlag = (CCarriedFlag *)pEnt; |
||||
pCarriedFlag->Owner = pPlayer; |
||||
|
||||
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, |
||||
pPlayer->edict(), g_usCarried, 0, (float*)&g_vecZero, (float*)&g_vecZero, |
||||
0.0, 0.0, pPlayer->entindex(), pPlayer->pev->team, 0, 0 ); |
||||
} |
||||
|
||||
( (CThreeWave*)g_pGameRules )->m_flFlagStatusTime = gpGlobals->time + 0.1; |
||||
} |
||||
} |
||||
|
||||
void CItemFlag::Capture( CBasePlayer *pPlayer, int iTeam ) |
||||
{ |
||||
CBaseEntity *pFlag1 = NULL; |
||||
|
||||
MESSAGE_BEGIN( MSG_ALL, gmsgCTFMsgs, NULL ); |
||||
if( iTeam == RED ) |
||||
WRITE_BYTE( RED_FLAG_CAPTURED ); |
||||
else if ( iTeam == BLUE ) |
||||
WRITE_BYTE( BLUE_FLAG_CAPTURED ); |
||||
WRITE_STRING( STRING( pPlayer->pev->netname ) ); |
||||
MESSAGE_END(); |
||||
|
||||
if( pPlayer->pFlagCarrierKiller ) |
||||
{ |
||||
if( pPlayer->m_flFlagCarrierKillTime > gpGlobals->time ) |
||||
{ |
||||
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pPlayer->pFlagCarrierKiller->pev->netname ) ); |
||||
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " gets an assist for fragging the flag carrier!\n" ); |
||||
|
||||
pPlayer->pFlagCarrierKiller->AddPoints( TEAM_CAPTURE_FRAG_CARRIER_ASSIST_BONUS, TRUE ); |
||||
pPlayer->pFlagCarrierKiller = NULL; |
||||
pPlayer->m_flFlagCarrierKillTime = 0.0; |
||||
} |
||||
} |
||||
|
||||
if( pPlayer->pFlagReturner ) |
||||
{ |
||||
if( pPlayer->m_flFlagReturnTime > gpGlobals->time ) |
||||
{ |
||||
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pPlayer->pFlagReturner->pev->netname ) ); |
||||
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " gets an assist for returning his flag!\n"); |
||||
|
||||
pPlayer->pFlagReturner->AddPoints( TEAM_CAPTURE_RETURN_FLAG_ASSIST_BONUS, TRUE ); |
||||
pPlayer->pFlagReturner = NULL; |
||||
pPlayer->m_flFlagReturnTime = 0.0; |
||||
} |
||||
} |
||||
|
||||
if( iTeam != pPlayer->pev->team ) |
||||
{ |
||||
if( iTeam == RED ) |
||||
{ |
||||
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Captured_Red_Flag\"\n", |
||||
STRING( pPlayer->pev->netname ), |
||||
GETPLAYERUSERID( pPlayer->edict() ), |
||||
GETPLAYERAUTHID( pPlayer->edict() ), |
||||
GetTeamName( pPlayer->pev->team ) ); |
||||
} |
||||
else |
||||
{ |
||||
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Captured_Blue_Flag\"\n", |
||||
STRING( pPlayer->pev->netname ), |
||||
GETPLAYERUSERID( pPlayer->edict() ), |
||||
GETPLAYERAUTHID( pPlayer->edict() ), |
||||
GetTeamName( pPlayer->pev->team ) ); |
||||
} |
||||
} |
||||
|
||||
if( iTeam == RED ) |
||||
{ |
||||
( (CThreeWave *)g_pGameRules )->iBlueTeamScore++; |
||||
|
||||
while( ( pFlag1 = UTIL_FindEntityByClassname( pFlag1, "carried_flag_team1" ) ) != NULL ) |
||||
{ |
||||
if( pFlag1 ) |
||||
UTIL_Remove( pFlag1 ); |
||||
} |
||||
} |
||||
else if( iTeam == BLUE ) |
||||
{ |
||||
( (CThreeWave*)g_pGameRules )->iRedTeamScore++; |
||||
|
||||
while( ( pFlag1 = UTIL_FindEntityByClassname( pFlag1, "carried_flag_team2" ) ) != NULL ) |
||||
{ |
||||
if ( pFlag1 ) |
||||
UTIL_Remove( pFlag1 ); |
||||
} |
||||
} |
||||
|
||||
pPlayer->m_bHasFlag = FALSE; |
||||
pPlayer->AddPoints( TEAM_CAPTURE_CAPTURE_BONUS, TRUE ); |
||||
|
||||
for( int i = 1; i <= gpGlobals->maxClients; i++ ) |
||||
{ |
||||
CBaseEntity *pTeamMate = UTIL_PlayerByIndex( i ); |
||||
|
||||
if( pTeamMate ) |
||||
{ |
||||
if( pTeamMate->pev->team == pPlayer->pev->team ) |
||||
pTeamMate->AddPoints( TEAM_CAPTURE_TEAM_BONUS, TRUE ); |
||||
} |
||||
} |
||||
|
||||
ResetFlag( iTeam ); |
||||
} |
||||
|
||||
void CItemFlag::Materialize() |
||||
{ |
||||
if ( pev->effects & EF_NODRAW ) |
||||
{ |
||||
pev->effects &= ~EF_NODRAW; |
||||
pev->effects |= EF_MUZZLEFLASH; |
||||
} |
||||
|
||||
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, |
||||
edict(), g_usFlagSpawn, 0, (float*)&g_vecZero, (float*)&g_vecZero, |
||||
0.0, 0.0, pev->team, 0, 0, 0 ); |
||||
|
||||
Dropped = FALSE; |
||||
|
||||
SetTouch( &CItemFlag::FlagTouch ); |
||||
SetThink( &CItemFlag::FlagThink ); |
||||
} |
||||
|
||||
void CItemFlag::ResetFlag( int iTeam ) |
||||
{ |
||||
CBaseEntity *pFlag1 = NULL; |
||||
|
||||
if( iTeam == BLUE ) |
||||
{ |
||||
while( ( pFlag1 = UTIL_FindEntityByClassname( pFlag1, "item_flag_team2" ) ) != NULL ) |
||||
{ |
||||
CItemFlag *pFlag2 = (CItemFlag*)pFlag1; |
||||
|
||||
if( pFlag2->Dropped ) |
||||
continue; |
||||
|
||||
if( pFlag2->pev->effects & EF_NODRAW ) |
||||
pFlag2->Materialize(); |
||||
} |
||||
} |
||||
else if( iTeam == RED ) |
||||
{ |
||||
while( ( pFlag1 = UTIL_FindEntityByClassname( pFlag1, "item_flag_team1" ) ) != NULL ) |
||||
{ |
||||
CItemFlag *pFlag2 = (CItemFlag*)pFlag1; |
||||
|
||||
if( pFlag2->Dropped ) |
||||
continue; |
||||
|
||||
if( pFlag2->pev->effects & EF_NODRAW ) |
||||
pFlag2->Materialize(); |
||||
} |
||||
} |
||||
|
||||
( (CThreeWave*)g_pGameRules )->m_flFlagStatusTime = gpGlobals->time + 0.1; |
||||
} |
||||
|
||||
void CItemFlag::FlagThink() |
||||
{ |
||||
if( Dropped ) |
||||
{ |
||||
if( m_flDroppedTime <= gpGlobals->time ) |
||||
{ |
||||
ResetFlag( pev->team ); |
||||
MESSAGE_BEGIN( MSG_ALL, gmsgCTFMsgs, NULL ); |
||||
if( pev->team == RED ) |
||||
WRITE_BYTE( RED_FLAG_RETURNED ); |
||||
else if( pev->team == BLUE ) |
||||
WRITE_BYTE( BLUE_FLAG_RETURNED ); |
||||
WRITE_STRING( "" ); |
||||
MESSAGE_END(); |
||||
|
||||
UTIL_Remove( this ); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
//Using 0.2 just in case we might lag the server.
|
||||
pev->nextthink = gpGlobals->time + 0.2; |
||||
} |
||||
|
||||
void CItemFlag::Precache() |
||||
{ |
||||
PRECACHE_MODEL( "models/flag.mdl" ); |
||||
PRECACHE_SOUND( "ctf/flagcap.wav" ); |
||||
PRECACHE_SOUND( "ctf/flagtk.wav" ); |
||||
PRECACHE_SOUND( "ctf/flagret.wav" ); |
||||
} |
||||
|
||||
class CItemFlagTeam1 : public CItemFlag |
||||
{ |
||||
void Spawn() |
||||
{ |
||||
pev->classname = MAKE_STRING( "item_flag_team1" ); |
||||
pev->team = RED; |
||||
CItemFlag::Spawn(); |
||||
} |
||||
}; |
||||
|
||||
class CItemFlagTeam2 : public CItemFlag |
||||
{ |
||||
void Spawn() |
||||
{ |
||||
pev->classname = MAKE_STRING( "item_flag_team2" ); |
||||
pev->team = BLUE; |
||||
CItemFlag::Spawn(); |
||||
} |
||||
}; |
||||
|
||||
LINK_ENTITY_TO_CLASS( item_flag_team1, CItemFlagTeam1 ) |
||||
LINK_ENTITY_TO_CLASS( ctf_redflag, CItemFlagTeam1 ) |
||||
LINK_ENTITY_TO_CLASS( item_flag_team2, CItemFlagTeam2 ) |
||||
LINK_ENTITY_TO_CLASS( ctf_blueflag, CItemFlagTeam2 ) |
||||
|
||||
void CCarriedFlag::Spawn() |
||||
{ |
||||
Precache(); |
||||
|
||||
SET_MODEL( ENT( pev ), "models/flag.mdl" ); |
||||
UTIL_SetOrigin( pev, pev->origin ); |
||||
|
||||
pev->movetype = MOVETYPE_NONE; |
||||
pev->solid = SOLID_NOT; |
||||
pev->effects |= EF_NODRAW; |
||||
pev->sequence = WAVE_IDLE; |
||||
pev->framerate = 1.0; |
||||
|
||||
/*
|
||||
if( pev->team == RED ) |
||||
pev->skin = 1; |
||||
else if( pev->team == BLUE ) |
||||
pev->skin = 2;*/ |
||||
pev->skin = pev->team; |
||||
|
||||
m_iOwnerOldVel = 0; |
||||
|
||||
SetThink( &CCarriedFlag::FlagThink ); |
||||
pev->nextthink = gpGlobals->time + 0.1; |
||||
} |
||||
|
||||
void CCarriedFlag::Precache() |
||||
{ |
||||
PRECACHE_MODEL( "models/flag.mdl" ); |
||||
} |
||||
|
||||
void CCarriedFlag::FlagThink() |
||||
{ |
||||
// Make it visible
|
||||
pev->effects &= ~EF_NODRAW; |
||||
|
||||
// And let if follow
|
||||
pev->aiment = ENT( Owner->pev ); |
||||
pev->movetype = MOVETYPE_FOLLOW; |
||||
|
||||
// If owner is death or lost flag, remove
|
||||
if( !Owner->IsAlive() || !Owner->m_bHasFlag ) |
||||
UTIL_Remove( this ); |
||||
else |
||||
{ |
||||
// If owners speed is low, go in idle mode
|
||||
if( Owner->pev->velocity.Length() <= 75 && pev->sequence != WAVE_IDLE ) |
||||
{ |
||||
pev->sequence = WAVE_IDLE; |
||||
} |
||||
// Else let the flag go wild
|
||||
else if( Owner->pev->velocity.Length() >= 75 && pev->sequence != CARRIED ) |
||||
{ |
||||
pev->sequence = CARRIED; |
||||
} |
||||
|
||||
pev->frame += pev->framerate; |
||||
|
||||
if( pev->frame < 0.0 || pev->frame >= 256.0 ) |
||||
{ |
||||
pev->frame -= (int)( pev->frame / 256.0 ) * 256.0; |
||||
} |
||||
pev->nextthink = gpGlobals->time + 0.1; |
||||
} |
||||
} |
||||
|
||||
class CCarriedFlagTeam1 : public CCarriedFlag |
||||
{ |
||||
void Spawn() |
||||
{ |
||||
pev->team = RED; |
||||
CCarriedFlag::Spawn(); |
||||
} |
||||
}; |
||||
|
||||
class CCarriedFlagTeam2 : public CCarriedFlag |
||||
{ |
||||
void Spawn() |
||||
{ |
||||
pev->team = BLUE; |
||||
CCarriedFlag::Spawn(); |
||||
} |
||||
}; |
||||
|
||||
LINK_ENTITY_TO_CLASS( carried_flag_team1, CCarriedFlagTeam1 ) |
||||
LINK_ENTITY_TO_CLASS( carried_flag_team2, CCarriedFlagTeam2 ) |
@ -0,0 +1,107 @@
@@ -0,0 +1,107 @@
|
||||
/***
|
||||
* |
||||
* 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. |
||||
* |
||||
****/ |
||||
//=========================================================
|
||||
// Flags
|
||||
//=========================================================
|
||||
#pragma once |
||||
#ifndef FLAGS_H |
||||
#define FLAGS_H |
||||
|
||||
#define STEAL_SOUND 1 |
||||
#define CAPTURE_SOUND 2 |
||||
#define RETURN_SOUND 3 |
||||
|
||||
#define RED_FLAG_STOLEN 1 |
||||
#define BLUE_FLAG_STOLEN 2 |
||||
#define RED_FLAG_CAPTURED 3 |
||||
#define BLUE_FLAG_CAPTURED 4 |
||||
#define RED_FLAG_RETURNED_PLAYER 5 |
||||
#define BLUE_FLAG_RETURNED_PLAYER 6 |
||||
#define RED_FLAG_RETURNED 7 |
||||
#define BLUE_FLAG_RETURNED 8 |
||||
#define RED_FLAG_LOST 9 |
||||
#define BLUE_FLAG_LOST 10 |
||||
|
||||
#define RED_FLAG_STOLEN 1 |
||||
#define BLUE_FLAG_STOLEN 2 |
||||
#define RED_FLAG_DROPPED 3 |
||||
#define BLUE_FLAG_DROPPED 4 |
||||
#define RED_FLAG_ATBASE 5 |
||||
#define BLUE_FLAG_ATBASE 6 |
||||
|
||||
// Standard Scoring
|
||||
#define TEAM_CAPTURE_CAPTURE_BONUS 5 // what you get for capture
|
||||
#define TEAM_CAPTURE_TEAM_BONUS 10 // what your team gets for capture
|
||||
#define TEAM_CAPTURE_RECOVERY_BONUS 1 // what you get for recovery
|
||||
#define TEAM_CAPTURE_FLAG_BONUS 0 // what you get for picking up enemy flag
|
||||
#define TEAM_CAPTURE_FRAG_CARRIER_BONUS 2 // what you get for fragging a enemy flag carrier
|
||||
#define TEAM_CAPTURE_FLAG_RETURN_TIME 40 // seconds until auto return
|
||||
|
||||
// bonuses
|
||||
#define TEAM_CAPTURE_CARRIER_DANGER_PROTECT_BONUS 2 // bonus for fraggin someone
|
||||
// who has recently hurt your flag carrier
|
||||
#define TEAM_CAPTURE_CARRIER_PROTECT_BONUS 1 // bonus for fraggin someone while
|
||||
// either you or your target are near your flag carrier
|
||||
#define TEAM_CAPTURE_FLAG_DEFENSE_BONUS 1 // bonus for fraggin someone while
|
||||
// either you or your target are near your flag
|
||||
#define TEAM_CAPTURE_RETURN_FLAG_ASSIST_BONUS 1 // awarded for returning a flag that causes a
|
||||
// capture to happen almost immediately
|
||||
#define TEAM_CAPTURE_FRAG_CARRIER_ASSIST_BONUS 2 // award for fragging a flag carrier if a
|
||||
// capture happens almost immediately
|
||||
|
||||
// Radius
|
||||
#define TEAM_CAPTURE_TARGET_PROTECT_RADIUS 550 // the radius around an object being
|
||||
// defended where a target will be worth extra frags
|
||||
#define TEAM_CAPTURE_ATTACKER_PROTECT_RADIUS 550 // the radius around an object being
|
||||
// defended where an attacker will get extra frags when making kills
|
||||
|
||||
// timeouts
|
||||
#define TEAM_CAPTURE_CARRIER_DANGER_PROTECT_TIMEOUT 4 |
||||
#define TEAM_CAPTURE_CARRIER_FLAG_SINCE_TIMEOUT 2 |
||||
#define TEAM_CAPTURE_FRAG_CARRIER_ASSIST_TIMEOUT 6 |
||||
#define TEAM_CAPTURE_RETURN_FLAG_ASSIST_TIMEOUT 4 |
||||
|
||||
extern const char *GetTeamName( int team ); |
||||
|
||||
class CItemFlag : public CBaseEntity |
||||
{ |
||||
public: |
||||
void Spawn(); |
||||
BOOL Dropped; |
||||
float m_flDroppedTime; |
||||
void EXPORT FlagThink(); |
||||
|
||||
private: |
||||
void Precache(); |
||||
void Capture( CBasePlayer *pPlayer, int iTeam ); |
||||
void ResetFlag( int iTeam ); |
||||
void Materialize(); |
||||
void EXPORT FlagTouch( CBaseEntity *pOther ); |
||||
// BOOL MyTouch( CBasePlayer *pPlayer );
|
||||
}; |
||||
|
||||
class CCarriedFlag : public CBaseEntity |
||||
{ |
||||
public: |
||||
void Spawn(); |
||||
CBasePlayer *Owner; |
||||
int m_iOwnerOldVel; |
||||
|
||||
private: |
||||
void Precache(); |
||||
void EXPORT FlagThink(); |
||||
}; |
||||
|
||||
#endif // FLAGS_H
|
@ -0,0 +1,351 @@
@@ -0,0 +1,351 @@
|
||||
/***
|
||||
* |
||||
* 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. |
||||
* |
||||
****/ |
||||
/***********************************************
|
||||
************************************************ |
||||
GRAPPLE |
||||
************************************************ |
||||
***********************************************/ |
||||
|
||||
#include "extdll.h" |
||||
#include "util.h" |
||||
#include "cbase.h" |
||||
#include "player.h" |
||||
#include "weapons.h" |
||||
#include "grapple.h" |
||||
|
||||
unsigned short g_usHook; |
||||
unsigned short g_usCable; |
||||
|
||||
void CGrapple::Reset_Grapple() |
||||
{ |
||||
CBasePlayer *pOwner = (CBasePlayer *)CBaseEntity::Instance( pev->owner ); |
||||
|
||||
pOwner->m_bOn_Hook = FALSE; |
||||
pOwner->m_bHook_Out = FALSE; |
||||
|
||||
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, |
||||
pOwner->edict(), g_usCable, 0, (float*)&g_vecZero, (float*)&g_vecZero, |
||||
0.0, 0.0, entindex(), pev->team, 1, 0 ); |
||||
|
||||
STOP_SOUND( edict(), CHAN_WEAPON, "weapons/grhang.wav" ); |
||||
STOP_SOUND( pOwner->edict(), CHAN_WEAPON, "weapons/grfire.wav" ); |
||||
STOP_SOUND( pOwner->edict(), CHAN_WEAPON, "weapons/grpull.wav" ); |
||||
|
||||
pOwner->m_ppHook = NULL; |
||||
pev->enemy = NULL; |
||||
|
||||
UTIL_Remove( this ); |
||||
} |
||||
|
||||
void CGrapple::GrappleTouch( CBaseEntity *pOther ) |
||||
{ |
||||
CBasePlayer *pOwner = (CBasePlayer *)CBaseEntity::Instance( pev->owner ); |
||||
|
||||
if( pOther == pOwner ) |
||||
return; |
||||
|
||||
// DO NOT allow the grapple to hook to any projectiles, no matter WHAT!
|
||||
// if you create new types of projectiles, make sure you use one of the
|
||||
// classnames below or write code to exclude your new classname so
|
||||
// grapples will not stick to them.
|
||||
if( pOther->Classify() == CLASS_PROJECTILE ) |
||||
return; |
||||
|
||||
if( pOther->IsPlayer() ) |
||||
{ |
||||
// glance off of teammates
|
||||
if( pOther->pev->team == pOwner->pev->team ) |
||||
return; |
||||
|
||||
// sound( self, CHAN_WEAPON, "player/axhit1.wav", 1, ATTN_NORM );
|
||||
// TakeDamage( pOther->pev, pOwner->pev, 10, DMG_GENERIC );
|
||||
|
||||
// make hook invisible since we will be pulling directly
|
||||
// towards the player the hook hit. Quakeworld makes it
|
||||
// too quirky to try to match hook's velocity with that of
|
||||
// the client that it hit.
|
||||
// setmodel( self, "");
|
||||
pev->velocity = g_vecZero; |
||||
UTIL_SetOrigin( pev, pOther->pev->origin ); |
||||
} |
||||
else |
||||
{ |
||||
// sound( self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM );
|
||||
|
||||
// One point of damage inflicted upon impact. Subsequent
|
||||
// damage will only be done to PLAYERS... this way secret
|
||||
// doors and triggers will only be damaged once.
|
||||
if( pOther->pev->takedamage ) |
||||
TakeDamage( pOther->pev, pOwner->pev, 1, DMG_GENERIC ); |
||||
|
||||
pev->velocity = g_vecZero; |
||||
EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/grhit.wav", 1, ATTN_NORM ); |
||||
|
||||
// No sparks underwater
|
||||
if( pev->waterlevel == 0 ) |
||||
UTIL_Sparks( pev->origin ); |
||||
} |
||||
|
||||
// conveniently clears the sound channel of the CHAIN1 sound,
|
||||
// which is a looping sample and would continue to play. Tink1 is
|
||||
// the least offensive choice, ass NULL.WAV loops and clogs the
|
||||
// channel with silence
|
||||
// sound (self.owner, CHAN_NO_PHS_ADD+CHAN_WEAPON, "weapons/tink1.wav", 1, ATTN_NORM);
|
||||
|
||||
if( !( pOwner->pev->button & IN_ATTACK ) ) |
||||
{ |
||||
if( pOwner->m_bOn_Hook ) |
||||
{ |
||||
Reset_Grapple(); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
if( pOwner->pev->flags & FL_ONGROUND ) |
||||
{ |
||||
pOwner->pev->flags &= ~FL_ONGROUND; |
||||
// setorigin(self.owner,self.owner.origin + '0 0 1');
|
||||
} |
||||
|
||||
pOwner->m_bOn_Hook = TRUE; |
||||
|
||||
// sound( self.owner, CHAN_WEAPON, "weapons/chain2.wav", 1, ATTN_NORM );
|
||||
|
||||
// CHAIN2 is a looping sample. Use LEFTY as a flag so that client.qc
|
||||
// will know to only play the tink sound ONCE to clear the weapons
|
||||
// sound channel. (Lefty is a leftover from AI.QC, so I reused it to
|
||||
// avoid adding a field)
|
||||
//self.owner.lefty = TRUE;
|
||||
|
||||
STOP_SOUND( pOwner->edict(), CHAN_WEAPON, "weapons/grfire.wav" ); |
||||
|
||||
pev->enemy = pOther->edict();// remember this guy!
|
||||
SetThink( &CGrapple::Grapple_Track ); |
||||
pev->nextthink = gpGlobals->time; |
||||
m_flNextIdleTime = gpGlobals->time + 0.1; |
||||
pev->solid = SOLID_NOT; |
||||
SetTouch( NULL ); |
||||
} |
||||
|
||||
bool CanSee( CBaseEntity *pEnemy, CBaseEntity *pOwner ) |
||||
{ |
||||
TraceResult tr; |
||||
|
||||
UTIL_TraceLine( pOwner->pev->origin, pEnemy->pev->origin, ignore_monsters, ENT( pOwner->pev ), &tr ); |
||||
if( tr.flFraction == 1 ) |
||||
return TRUE; |
||||
|
||||
UTIL_TraceLine( pOwner->pev->origin, pEnemy->pev->origin + Vector( 15, 15, 0 ), ignore_monsters, ENT( pOwner->pev ), &tr ); |
||||
if( tr.flFraction == 1 ) |
||||
return TRUE; |
||||
|
||||
UTIL_TraceLine( pOwner->pev->origin, pEnemy->pev->origin + Vector( -15, -15, 0 ), ignore_monsters, ENT( pOwner->pev ), &tr ); |
||||
if( tr.flFraction == 1 ) |
||||
return TRUE; |
||||
|
||||
UTIL_TraceLine( pOwner->pev->origin, pEnemy->pev->origin + Vector( -15, 15, 0 ), ignore_monsters, ENT( pOwner->pev ), &tr ); |
||||
if( tr.flFraction == 1 ) |
||||
return TRUE; |
||||
|
||||
UTIL_TraceLine( pOwner->pev->origin, pEnemy->pev->origin + Vector( 15, -15, 0 ), ignore_monsters, ENT( pOwner->pev ), &tr ); |
||||
if( tr.flFraction == 1 ) |
||||
return TRUE; |
||||
|
||||
return FALSE; |
||||
} |
||||
|
||||
void CGrapple::Grapple_Track() |
||||
{ |
||||
CBasePlayer *pOwner = (CBasePlayer*)CBaseEntity::Instance( pev->owner ); |
||||
CBaseEntity *pEnemy = CBaseEntity::Instance( pev->enemy ); |
||||
|
||||
// Release dead targets
|
||||
if( pEnemy->IsPlayer() && pEnemy->pev->health <= 0 ) |
||||
Reset_Grapple(); |
||||
|
||||
// drop the hook if owner is dead or has released the button
|
||||
if( !pOwner->m_bOn_Hook || pOwner->pev->health <= 0 ) |
||||
{ |
||||
Reset_Grapple(); |
||||
return; |
||||
} |
||||
|
||||
if( !( pOwner->pev->button & IN_ATTACK ) ) |
||||
{ |
||||
if( pOwner->m_iQuakeWeapon == IT_EXTRA_WEAPON ) |
||||
{ |
||||
Reset_Grapple(); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
// bring the pAiN!
|
||||
if( pEnemy->IsPlayer() ) |
||||
{ |
||||
if( !CanSee( pEnemy, pOwner ) ) |
||||
{ |
||||
Reset_Grapple(); |
||||
return; |
||||
} |
||||
|
||||
// move the hook along with the player. It's invisible, but
|
||||
// we need this to make the sound come from the right spot
|
||||
UTIL_SetOrigin( pev, pEnemy->pev->origin ); |
||||
|
||||
// sound( self, CHAN_WEAPON, "blob/land1.wav", 1, ATTN_NORM );
|
||||
|
||||
SpawnBlood( pEnemy->pev->origin, BLOOD_COLOR_RED, 1 ); |
||||
( (CBasePlayer *)pEnemy )->TakeDamage( pev, pOwner->pev, 1, DMG_GENERIC ); |
||||
} |
||||
|
||||
// If the hook is not attached to the player, constantly copy
|
||||
// copy the target's velocity. Velocity copying DOES NOT work properly
|
||||
// for a hooked client.
|
||||
else |
||||
pev->velocity = pEnemy->pev->velocity; |
||||
|
||||
pev->nextthink = gpGlobals->time + 0.1; |
||||
} |
||||
|
||||
void CBasePlayer::Service_Grapple() |
||||
{ |
||||
Vector hook_dir; |
||||
CBaseEntity *pEnemy = CBaseEntity::Instance( pev->enemy ); |
||||
|
||||
// drop the hook if player lets go of button
|
||||
if( !( pev->button & IN_ATTACK ) ) |
||||
{ |
||||
if( m_iQuakeWeapon == IT_EXTRA_WEAPON ) |
||||
{ |
||||
m_ppHook->Reset_Grapple(); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
if( m_ppHook->pev->enemy != NULL ) |
||||
{ |
||||
// If hooked to a player, track them directly!
|
||||
if( pEnemy->IsPlayer() ) |
||||
{ |
||||
pEnemy = CBaseEntity::Instance( pev->enemy ); |
||||
hook_dir = ( pEnemy->pev->origin - pev->origin ); |
||||
} |
||||
// else, track to hook
|
||||
else |
||||
hook_dir = ( m_ppHook->pev->origin - pev->origin ); |
||||
|
||||
pev->speed = 750; |
||||
pev->velocity = ( hook_dir.Normalize() * pev->speed ); |
||||
|
||||
if( m_ppHook->m_flNextIdleTime <= gpGlobals->time && hook_dir.Length() <= 50 ) |
||||
{ |
||||
//No sparks underwater
|
||||
if( m_ppHook->pev->waterlevel == 0 ) |
||||
UTIL_Sparks( m_ppHook->pev->origin ); |
||||
|
||||
STOP_SOUND( edict(), CHAN_WEAPON, "weapons/grpull.wav" ); |
||||
EMIT_SOUND( ENT( m_ppHook->pev ), CHAN_WEAPON, "weapons/grhang.wav", 1, ATTN_NORM ); |
||||
|
||||
m_ppHook->m_flNextIdleTime = gpGlobals->time + RANDOM_LONG( 1, 3 ); |
||||
|
||||
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, |
||||
edict(), g_usCable, 0, (float *)&g_vecZero, (float *)&g_vecZero, |
||||
0.0, 0.0, m_ppHook->entindex(), pev->team, 1, 0 ); |
||||
} |
||||
else if( m_ppHook->m_flNextIdleTime <= gpGlobals->time ) |
||||
{ |
||||
// No sparks underwater
|
||||
if( m_ppHook->pev->waterlevel == 0 ) |
||||
UTIL_Sparks( m_ppHook->pev->origin ); |
||||
|
||||
STOP_SOUND( edict(), CHAN_WEAPON, "weapons/grfire.wav" ); |
||||
EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/grpull.wav", 1, ATTN_NORM ); |
||||
m_ppHook->m_flNextIdleTime = gpGlobals->time + RANDOM_LONG( 1, 3 ); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void CGrapple::OnAirThink() |
||||
{ |
||||
TraceResult tr; |
||||
|
||||
CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner ); |
||||
|
||||
if( !( pOwner->pev->button & IN_ATTACK ) ) |
||||
{ |
||||
Reset_Grapple(); |
||||
return; |
||||
} |
||||
|
||||
UTIL_TraceLine( pev->origin, pOwner->pev->origin, ignore_monsters, ENT( pev ), &tr ); |
||||
|
||||
if( tr.flFraction < 1.0 ) |
||||
{ |
||||
Reset_Grapple(); |
||||
return; |
||||
} |
||||
|
||||
pev->nextthink = gpGlobals->time + 0.5; |
||||
} |
||||
|
||||
void CGrapple::Spawn() |
||||
{ |
||||
pev->movetype = MOVETYPE_FLYMISSILE; |
||||
pev->solid = SOLID_BBOX; |
||||
|
||||
SET_MODEL( ENT( pev ),"models/hook.mdl" ); |
||||
|
||||
SetTouch( &CGrapple::GrappleTouch ); |
||||
SetThink( &CGrapple::OnAirThink ); |
||||
|
||||
pev->nextthink = gpGlobals->time + 0.1; |
||||
} |
||||
|
||||
LINK_ENTITY_TO_CLASS( hook, CGrapple ); |
||||
|
||||
void CBasePlayer::Throw_Grapple() |
||||
{ |
||||
if( m_bHook_Out ) |
||||
return; |
||||
|
||||
CGrapple *pHookCBEnt = NULL; |
||||
pHookCBEnt = (CGrapple*)CBaseEntity::Create( "hook", pev->origin, pev->angles, NULL ); |
||||
|
||||
if( pHookCBEnt ) |
||||
{ |
||||
m_ppHook = pHookCBEnt; |
||||
|
||||
m_ppHook->pev->owner = edict(); |
||||
|
||||
UTIL_MakeVectors( pev->v_angle ); |
||||
|
||||
UTIL_SetOrigin( m_ppHook->pev, pev->origin + gpGlobals->v_forward * 16 + Vector( 0, 0, 16 ) ); |
||||
UTIL_SetSize( m_ppHook->pev, g_vecZero, g_vecZero ); |
||||
|
||||
EMIT_SOUND( ENT( pev ), CHAN_WEAPON, "weapons/grfire.wav", 1, ATTN_NORM ); |
||||
|
||||
// Make if fly forward
|
||||
m_ppHook->pev->velocity = gpGlobals->v_forward * 1000; |
||||
// And make the hook face forward too!
|
||||
m_ppHook->pev->angles = UTIL_VecToAngles( gpGlobals->v_forward ); |
||||
m_ppHook->pev->fixangle = TRUE; |
||||
|
||||
PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, |
||||
edict(), g_usCable, 0, (float*)&g_vecZero, (float*)&g_vecZero, |
||||
0.0, 0.0, m_ppHook->entindex(), pev->team, 0, 0 ); |
||||
|
||||
m_bHook_Out = TRUE; |
||||
} |
||||
} |
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
/***
|
||||
* |
||||
* 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. |
||||
* |
||||
****/ |
||||
#pragma once |
||||
#ifndef GRAPPLE_H |
||||
#define GRAPPLE_H |
||||
class CGrapple : public CBaseEntity |
||||
{ |
||||
public: |
||||
//Yes, I have no imagination so I use standard touch, spawn and think function names.
|
||||
//Sue me! =P.
|
||||
void Spawn(); |
||||
int Classify() { return CLASS_PROJECTILE; }; |
||||
void EXPORT OnAirThink(); |
||||
void EXPORT GrappleTouch( CBaseEntity *pOther ); |
||||
void Reset_Grapple(); |
||||
void EXPORT Grapple_Track(); |
||||
|
||||
float m_flNextIdleTime; |
||||
}; |
||||
#endif // GRAPPLE_H
|
@ -0,0 +1,420 @@
@@ -0,0 +1,420 @@
|
||||
/***
|
||||
* |
||||
* 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; |
||||
} |
@ -0,0 +1,85 @@
@@ -0,0 +1,85 @@
|
||||
/***
|
||||
* |
||||
* 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. |
||||
* |
||||
****/ |
||||
#pragma once |
||||
#ifndef RUNES_H |
||||
#define RUNES_H |
||||
|
||||
static const char *g_RuneEntityName[] = |
||||
{ |
||||
"", |
||||
"item_rune1", |
||||
"item_rune2", |
||||
"item_rune3", |
||||
"item_rune4" |
||||
}; |
||||
|
||||
static const char *g_RuneName[] = |
||||
{ |
||||
"Unknown", |
||||
"ResistRune", |
||||
"StrengthRune", |
||||
"HasteRune", |
||||
"RegenRune" |
||||
}; |
||||
|
||||
class CItemRune : public CBaseEntity |
||||
{ |
||||
private: |
||||
void EXPORT RuneRespawn(); |
||||
public: |
||||
void EXPORT RuneTouch( CBaseEntity *pOther ); |
||||
void Spawn(); |
||||
int Classify() { return CLASS_RUNE; }; |
||||
void EXPORT MakeTouchable(); |
||||
virtual void PrintTouchMessage( CBasePlayer *pPlayer ){} |
||||
virtual void PrintRespawnMessage(){} |
||||
|
||||
int m_iRuneFlag; |
||||
bool m_bTouchable; |
||||
bool dropped; |
||||
}; |
||||
|
||||
class CResistRune : public CItemRune |
||||
{ |
||||
public: |
||||
void Spawn(); |
||||
void PrintTouchMessage( CBasePlayer *pPlayer ); |
||||
void PrintRespawnMessage(); |
||||
}; |
||||
|
||||
class CStrengthRune : public CItemRune |
||||
{ |
||||
public: |
||||
void Spawn(); |
||||
void PrintTouchMessage( CBasePlayer *pPlayer ); |
||||
void PrintRespawnMessage(); |
||||
}; |
||||
|
||||
class CHasteRune : public CItemRune |
||||
{ |
||||
public: |
||||
void Spawn(); |
||||
void PrintTouchMessage( CBasePlayer *pPlayer ); |
||||
void PrintRespawnMessage(); |
||||
}; |
||||
|
||||
class CRegenRune : public CItemRune |
||||
{ |
||||
public: |
||||
void Spawn(); |
||||
void PrintTouchMessage( CBasePlayer *pPlayer ); |
||||
void PrintRespawnMessage(); |
||||
}; |
||||
#endif // RUNES_H
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue