From 0535fe0ae40275ffc717b29396ab005f850120cf Mon Sep 17 00:00:00 2001 From: Night Owl Date: Sat, 14 Apr 2018 05:00:39 +0500 Subject: [PATCH] Merge original "ThreeWave" source code. --- cl_dll/3wave/CTF_FlagStatus.cpp | 256 +++ cl_dll/3wave/CTF_HudMessage.cpp | 195 ++ cl_dll/ev_hldm.cpp | 195 ++ cl_dll/quake/quake_events.cpp | 10 + dlls/3wave/threewave_gamerules.cpp | 3269 ++++++++++++++++++++++++++++ dlls/3wave/threewave_gamerules.h | 232 ++ dlls/CMakeLists.txt | 3 +- dlls/client.cpp | 58 +- dlls/dmc/quake_weapons_all.cpp | 71 +- dlls/multiplay_gamerules.cpp | 54 +- dlls/player.h | 39 + 11 files changed, 4363 insertions(+), 19 deletions(-) create mode 100644 cl_dll/3wave/CTF_FlagStatus.cpp create mode 100644 cl_dll/3wave/CTF_HudMessage.cpp create mode 100644 dlls/3wave/threewave_gamerules.cpp create mode 100644 dlls/3wave/threewave_gamerules.h diff --git a/cl_dll/3wave/CTF_FlagStatus.cpp b/cl_dll/3wave/CTF_FlagStatus.cpp new file mode 100644 index 00000000..ea8cee41 --- /dev/null +++ b/cl_dll/3wave/CTF_FlagStatus.cpp @@ -0,0 +1,256 @@ +/*** +* +* 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. +* +****/ + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "entity_types.h" +#include "usercmd.h" +#include "pm_defs.h" +#include "pm_materials.h" +#include "ref_params.h" +#include +#include "vgui_viewport.h" +#include "vgui_ScorePanel.h" + +#define RED_FLAG_STOLE 1 +#define BLUE_FLAG_STOLE 2 +#define RED_FLAG_LOST 3 +#define BLUE_FLAG_LOST 4 +#define RED_FLAG_ATBASE 5 +#define BLUE_FLAG_ATBASE 6 + +#define ITEM_RUNE1_FLAG 1 +#define ITEM_RUNE2_FLAG 2 +#define ITEM_RUNE3_FLAG 3 +#define ITEM_RUNE4_FLAG 4 + +DECLARE_MESSAGE(m_FlagStat, FlagStat) +DECLARE_MESSAGE(m_FlagStat, RuneStat) +DECLARE_MESSAGE(m_FlagStat, FlagCarrier) + +int CHudFlagStatus::Init(void) +{ + HOOK_MESSAGE( FlagStat ); + HOOK_MESSAGE( RuneStat ); + HOOK_MESSAGE( FlagCarrier ); + + m_iFlags |= HUD_ACTIVE; + + gHUD.AddHudElem(this); + + Reset(); + + return 1; +}; + +int CHudFlagStatus::VidInit(void) +{ + m_iBlueAtBaseIndex = gHUD.GetSpriteIndex( "blue_atbase" ); + m_iBlueLostIndex = gHUD.GetSpriteIndex( "blue_lost" ); + m_iBlueStolenIndex = gHUD.GetSpriteIndex( "blue_stolen" ); + + m_iRedAtBaseIndex = gHUD.GetSpriteIndex( "red_atbase" ); + m_iRedLostIndex = gHUD.GetSpriteIndex( "red_lost" ); + m_iRedStolenIndex = gHUD.GetSpriteIndex( "red_stolen" ); + + m_iRune1Index = gHUD.GetSpriteIndex( "rune1" ); + m_iRune2Index = gHUD.GetSpriteIndex( "rune2" ); + m_iRune3Index = gHUD.GetSpriteIndex( "rune3" ); + m_iRune4Index = gHUD.GetSpriteIndex( "rune4" ); + + m_hBlueAtBase = gHUD.GetSprite( m_iBlueAtBaseIndex ); + m_hBlueLost = gHUD.GetSprite( m_iBlueLostIndex ); + m_hBlueStolen = gHUD.GetSprite( m_iBlueStolenIndex ); + + m_hRedAtBase = gHUD.GetSprite( m_iRedAtBaseIndex ); + m_hRedLost = gHUD.GetSprite( m_iRedLostIndex ); + m_hRedStolen = gHUD.GetSprite( m_iRedStolenIndex ); + + m_hRune1 = gHUD.GetSprite( m_iRune1Index ); + m_hRune2 = gHUD.GetSprite( m_iRune2Index ); + m_hRune3 = gHUD.GetSprite( m_iRune3Index ); + m_hRune4 = gHUD.GetSprite( m_iRune4Index ); + + // Load sprites here + m_iBlueFlagIndex = gHUD.GetSpriteIndex( "b_flag_c" ); + m_iRedFlagIndex = gHUD.GetSpriteIndex( "r_flag_c" ); + + m_hBlueFlag = gHUD.GetSprite( m_iBlueFlagIndex ); + m_hRedFlag = gHUD.GetSprite( m_iRedFlagIndex ); + + return 1; +} + +void CHudFlagStatus :: Reset( void ) +{ + return; +} + + +int CHudFlagStatus ::Draw(float flTime ) +{ + + if ( !iDrawStatus ) + return 1; + + int x, y; + int r,g,b; + + r = g = b = 255; + + x = 20; + y = ( ScreenHeight - gHUD.m_iFontHeight ) - ( gHUD.m_iFontHeight / 2 ) - 40; + + + switch ( iBlueFlagStatus ) + { + case BLUE_FLAG_STOLE: + SPR_Set( m_hBlueStolen, r, g, b ); + SPR_DrawHoles( 1, x, y, NULL ); + break; + case BLUE_FLAG_LOST: + SPR_Set( m_hBlueLost, r, g, b ); + SPR_DrawHoles( 1, x, y, NULL ); + break; + case BLUE_FLAG_ATBASE: + SPR_Set( m_hBlueAtBase, r, g, b ); + SPR_DrawHoles( 1, x, y, NULL ); + break; + } + + x = 50; + + if ( iBlueTeamScore < 10) + { + x += 3; + gHUD.DrawHudNumber( x, y + 4, DHN_DRAWZERO, iBlueTeamScore, 255, 255, 255 ); + } + else if ( iBlueTeamScore >= 10 && iBlueTeamScore < 100 ) + gHUD.DrawHudNumber( x, y + 4, DHN_2DIGITS | DHN_DRAWZERO, iBlueTeamScore, 255, 255, 255 ); + + x = 20; + y = ( ScreenHeight - gHUD.m_iFontHeight ) - ( gHUD.m_iFontHeight / 2 ) - 75; + + switch ( iRedFlagStatus ) + { + case RED_FLAG_STOLE: + SPR_Set( m_hRedStolen, r, g, b ); + SPR_DrawHoles( 1, x, y, NULL ); + break; + case RED_FLAG_LOST: + SPR_Set( m_hRedLost, r, g, b ); + SPR_DrawHoles( 1, x, y, NULL ); + break; + case RED_FLAG_ATBASE: + SPR_Set( m_hRedAtBase, r, g, b ); + SPR_DrawHoles( 1, x, y, NULL ); + break; + } + + x = 50; + if ( iRedTeamScore < 10) + { + x += 3; + gHUD.DrawHudNumber( x, y + 4, DHN_DRAWZERO, iRedTeamScore, 255, 255, 255 ); + } + else if ( iBlueTeamScore >= 10 && iBlueTeamScore < 100 ) + gHUD.DrawHudNumber( x, y + 4, DHN_2DIGITS | DHN_DRAWZERO, iRedTeamScore, 255, 255, 255 ); + + x = 20; + y = ( ScreenHeight - gHUD.m_iFontHeight ) - ( gHUD.m_iFontHeight / 2 ) - 110; + + switch ( m_iRuneStat ) + { + case ITEM_RUNE1_FLAG: + SPR_Set( m_hRune1, r, g, b ); + SPR_Draw( 1, x, y, NULL ); + break; + + case ITEM_RUNE2_FLAG: + SPR_Set( m_hRune2, r, g, b ); + SPR_Draw( 1, x, y, NULL ); + break; + + case ITEM_RUNE3_FLAG: + SPR_Set( m_hRune3, r, g, b ); + SPR_Draw( 1, x, y, NULL ); + break; + + case ITEM_RUNE4_FLAG: + SPR_Set( m_hRune4, r, g, b ); + SPR_Draw( 1, x, y, NULL ); + break; + } + + return 1; +} + +int CHudFlagStatus::MsgFunc_FlagStat(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + iDrawStatus = READ_BYTE(); + iRedFlagStatus = READ_BYTE(); + iBlueFlagStatus = READ_BYTE(); + + iRedTeamScore = READ_BYTE(); + iBlueTeamScore = READ_BYTE(); + + return 1; +} + +int CHudFlagStatus::MsgFunc_RuneStat(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + m_iRuneStat = READ_BYTE(); + + return 1; +} + +int CHudFlagStatus::MsgFunc_FlagCarrier(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + int index = READ_BYTE(); + + bool bRedFlag = false; + bool bBlueFlag = false; + + g_PlayerExtraInfo[ index ].iHasFlag = READ_BYTE(); + + for ( int i = 1; i < MAX_PLAYERS + 1; i++ ) + { + if ( g_PlayerExtraInfo[ i ].iHasFlag ) + { + if ( g_PlayerExtraInfo[ i ].teamnumber == 1 ) + bRedFlag = true; + else if ( g_PlayerExtraInfo[ i ].teamnumber == 2 ) + bBlueFlag = true; + } + } + + if ( !bRedFlag ) + gViewPort->m_pScoreBoard->m_pImages[ 5 ]->setVisible( false ); + if ( !bBlueFlag ) + gViewPort->m_pScoreBoard->m_pImages[ 4 ]->setVisible( false ); + + return 1; +} diff --git a/cl_dll/3wave/CTF_HudMessage.cpp b/cl_dll/3wave/CTF_HudMessage.cpp new file mode 100644 index 00000000..0d0aa284 --- /dev/null +++ b/cl_dll/3wave/CTF_HudMessage.cpp @@ -0,0 +1,195 @@ +/*** +* +* 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. +* +****/ + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "entity_types.h" +#include "usercmd.h" +#include "pm_defs.h" +#include "pm_materials.h" +#include "ref_params.h" +#include + + +#define MAX_BONUS 10 + +#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_HUD 9 +#define BLUE_FLAG_LOST_HUD 10 + + + +char *sBonusStrings[] = +{ + "", + "\\w stole the \\rRED\\w Flag!", + "\\w stole the \\bBLUE\\w Flag!", + "\\w captured the \\rRED\\w Flag", + "\\w captured the \\bBLUE\\w Flag", + "\\w returned the \\rRED\\w Flag", + "\\w returned the \\bBLUE\\w Flag", + "\\wThe \\rRED\\w Flag has Returned", + "\\wThe \\bBLUE\\w Flag has Returned", + "\\w lost the \\rRED\\w Flag!", + "\\w lost the \\bBLUE\\w Flag!", +}; + +DECLARE_MESSAGE(m_Bonus, Bonus) + +struct bonus_info_t +{ + int iSlot; + int iType; + bool bActive; + float flBonusTime; + char sPlayerName[64]; +}; + +bonus_info_t g_PlayerBonus[MAX_BONUS+1]; + +int CHudBonus::Init(void) +{ + HOOK_MESSAGE( Bonus ); + + m_iFlags |= HUD_ACTIVE; + + gHUD.AddHudElem(this); + + Reset(); + + return 1; +}; + +int CHudBonus::VidInit(void) +{ + return 1; +} + +void CHudBonus :: Reset( void ) +{ + m_iFlags |= HUD_ACTIVE; + + for ( int reset = 0; reset < MAX_BONUS; reset++) + { + g_PlayerBonus[ reset ].flBonusTime = 0.0; + g_PlayerBonus[ reset ].iSlot = 0; + g_PlayerBonus[ reset ].iType = 0; + g_PlayerBonus[ reset ].bActive = false; + m_bUsedSlot[ reset ] = false; + strcpy ( g_PlayerBonus[ reset ].sPlayerName, "" ); + } +} + +int CHudBonus ::Draw(float flTime ) +{ + for (int index = 1; index < MAX_BONUS + 1; index++) + { + //Just activated + if ( g_PlayerBonus[ index ].bActive && !g_PlayerBonus[ index ].flBonusTime ) + { + g_PlayerBonus[ index ].flBonusTime = flTime + 5.0; + + for ( int i = 1; i < MAX_BONUS + 1; i++ ) + { + if ( m_bUsedSlot[ i ] == false ) //found one thats not used + { + m_bUsedSlot[ i ] = true; //use it! + g_PlayerBonus[ index ].iSlot = i; + break; + } + } + } + + if ( g_PlayerBonus[ index ].flBonusTime > flTime ) + { + int YPos; + int iMod = gHUD.ReturnStringPixelLength( "\\w\\r\\w" ); + + YPos = ( ( ScreenHeight - gHUD.m_iFontHeight ) - ( gHUD.m_iFontHeight / 2 ) + 3 ) - ( 30 * g_PlayerBonus[ index ].iSlot ); + + int XPos = 75; + + char szText[256]; + + strcpy ( szText, g_PlayerBonus[ index ].sPlayerName ); + strcat ( szText, sBonusStrings[ g_PlayerBonus[ index ].iType ] ); + + if ( gHUD.m_FlagStat.iBlueTeamScore >= 10 ) + gHUD.DrawHudStringCTF( XPos + 20, YPos, 640, szText, 255, 255, 255 ); + else + gHUD.DrawHudStringCTF( XPos , YPos, 320, szText, 255, 255, 255 ); + + } + + if ( g_PlayerBonus[ index ].flBonusTime < flTime ) + { + g_PlayerBonus[ index ].bActive = false; + m_bUsedSlot[ g_PlayerBonus[ index ].iSlot ] = false; + g_PlayerBonus[ index ].iSlot = 0; + strcpy ( g_PlayerBonus[ index ].sPlayerName, "" ); + } + } + + return 1; +} + +int CHudBonus::MsgFunc_Bonus(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + for ( int index = 1; index < MAX_BONUS + 1; index++) + { + //Find wich one is not used + if ( g_PlayerBonus[ index ].bActive == false ) + break; //Not using this one?, then we shall use this. + } + + g_PlayerBonus[ index ].bActive = true; + g_PlayerBonus[ index ].flBonusTime = 0.0; + g_PlayerBonus[ index ].iType = READ_BYTE(); + strcpy ( g_PlayerBonus[ index ].sPlayerName, READ_STRING() ); + + switch ( g_PlayerBonus[ index ].iType ) + { + case RED_FLAG_STOLEN: + case BLUE_FLAG_STOLEN: + PlaySound( "ctf/flagtk.wav", 1 ); + break; + case RED_FLAG_CAPTURED: + case BLUE_FLAG_CAPTURED: + PlaySound( "ctf/flagcap.wav", 1 ); + break; + case RED_FLAG_RETURNED_PLAYER: + case BLUE_FLAG_RETURNED_PLAYER: + case RED_FLAG_RETURNED: + case BLUE_FLAG_RETURNED: + PlaySound( "ctf/flagret.wav", 1 ); + break; + } + + return 1; +} diff --git a/cl_dll/ev_hldm.cpp b/cl_dll/ev_hldm.cpp index e5863812..ce224696 100644 --- a/cl_dll/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -60,6 +60,11 @@ void EV_DMC_DoorGoDown( struct event_args_s *args ); void EV_DMC_DoorHitTop( struct event_args_s *args ); void EV_DMC_DoorHitBottom( struct event_args_s *args ); +void EV_Hook( event_args_t *args ); +void EV_Cable( struct event_args_s *args ); +void EV_FollowCarrier( struct event_args_s *args ); +void EV_FlagSpawn( struct event_args_s *args ); + void EV_TrainPitchAdjust( struct event_args_s *args ); } @@ -644,6 +649,196 @@ void EV_FireAxeSwing( event_args_t *args ) gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/ax1.wav", 1.0, ATTN_NORM, 0, 100 ); } +void EV_Hook( event_args_t *args ) +{ + return; +} + +void EV_Cable( event_args_t *args ) +{ + int idx, attached, team, modelIndex; + + float r, g, b; + + idx = args->entindex; + attached = args->iparam1; + team = args->iparam2; + + modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/smoke.spr" ); + + if( !modelIndex ) + return; + + if( team == 1 ) + { + r = 500; + g = 0; + b = 0; + } + else if( team == 2 ) + { + r = 0; + g = 0; + b = 500; + } + + if( args->bparam1 == 1 ) + gEngfuncs.pEfxAPI->R_BeamKill( attached ); + else + gEngfuncs.pEfxAPI->R_BeamEnts( idx, attached, modelIndex, 9999, 1, 0.001, 0.8, 0.0, 0.0, 0.0, r, g, b ); +} + +void EV_GenericParticleCallback( struct particle_s *particle, float frametime ) +{ + int i; + + for( i = 0; i < 3; i++ ) + { + particle->org[i] += particle->vel[i] * frametime; + } +} + +void EV_TrailCallback( struct tempent_s *ent, float frametime, float currenttime ) +{ + // If the Player is not on our PVS, then go back + if( !CheckPVS( ent->clientIndex ) ) + return; + + dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight( 0 ); + + cl_entity_t *player = gEngfuncs.GetEntityByIndex( ent->clientIndex ); + + if( !player ) + return; + + VectorCopy( player->origin, dl->origin ); + + dl->radius = 240; + dl->die = gEngfuncs.GetClientTime() + 0.001; // Kill it right away + + if( ent->entity.baseline.movetype == 2 ) + { + dl->color.r = 240; + dl->color.g = 25; + dl->color.b = 25; + } + else + { + dl->color.r = 25; + dl->color.g = 25; + dl->color.b = 240; + } + + // I know what you are thinking and yes, this was the only place I could find on where to put the timer + // Hacky; Yes, Works; Yes!. + if( ent->entity.baseline.animtime > gEngfuncs.GetClientTime() ) + return; + + for( int i = 0; i < 4; i++ ) + { + particle_t *bPart = gEngfuncs.pEfxAPI->R_AllocParticle( EV_GenericParticleCallback ); + + if( bPart ) + { + VectorCopy( ent->entity.origin, bPart->org ); + bPart->org[0] += gEngfuncs.pfnRandomFloat( -2, 2 ); + bPart->org[1] += gEngfuncs.pfnRandomFloat( -2, 2 ); + bPart->org[2] += gEngfuncs.pfnRandomFloat( -2, 2 ); + bPart->vel[0] = gEngfuncs.pfnRandomFloat( -50, 50 ); + bPart->vel[1] = gEngfuncs.pfnRandomFloat( -50, 50 ); + bPart->vel[2] = gEngfuncs.pfnRandomFloat( 75, 80 ); + + //Check team and color the particle correctly + if( ent->entity.baseline.movetype == 2 ) + bPart->color = 70; + else + bPart->color = 43; + + bPart->type = pt_slowgrav; + bPart->die = gEngfuncs.GetClientTime() + 0.5; + } + } + + ent->entity.baseline.animtime = gEngfuncs.GetClientTime() + 0.3; +} + + +void EV_FollowCarrier( event_args_t *args ) +{ + int iEntIndex = args->iparam1; + int iTeam = args->iparam2; + float r, g, b; + + int modelIndex; + const char *model = "sprites/smoke.spr"; + + modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( model ); + + if( iTeam == 2 ) + { + r = 500; + g = 0; + b = 0; + } + else if( iTeam == 1 ) + { + r = 0; + g = 0; + b = 500; + } + + if( args->bparam1 == 1 ) + gEngfuncs.pEfxAPI->R_KillAttachedTents( iEntIndex ); + else + { + TEMPENTITY *pTrailSpawner = NULL; + pTrailSpawner = gEngfuncs.pEfxAPI->R_TempModel( args->origin, args->velocity, args->angles, 9999, modelIndex, TE_BOUNCE_NULL ); + + if( pTrailSpawner != NULL ) + { + pTrailSpawner->flags |= ( FTENT_PLYRATTACHMENT | FTENT_PERSIST | FTENT_NOMODEL | FTENT_CLIENTCUSTOM ); + pTrailSpawner->clientIndex = iEntIndex; + + pTrailSpawner->entity.baseline.movetype = iTeam; // Hack to store the team number on this temp ent. + pTrailSpawner->entity.baseline.animtime = gEngfuncs.GetClientTime() + 0.3; + pTrailSpawner->callback = EV_TrailCallback; + } + } +} + +void EV_FlagSpawn( event_args_t *args ) +{ + vec3_t origin; + VectorCopy( args->origin, origin ); + + gEngfuncs.pEfxAPI->R_Implosion( origin, 50, 20, 0.5 ); + + for( int i = 0; i < 20; i++ ) + { + particle_t *bPart = gEngfuncs.pEfxAPI->R_AllocParticle( EV_GenericParticleCallback ); + + if( bPart ) + { + VectorCopy ( args->origin, bPart->org); + bPart->org[0] += gEngfuncs.pfnRandomFloat( -4, 4 ); + bPart->org[1] += gEngfuncs.pfnRandomFloat( -4, 4 ); + bPart->org[2] += gEngfuncs.pfnRandomFloat( -4, 4 ); + bPart->vel[0] = gEngfuncs.pfnRandomFloat( -50, 50 ); + bPart->vel[1] = gEngfuncs.pfnRandomFloat( -50, 50 ); + bPart->vel[2] = gEngfuncs.pfnRandomFloat( 250, 350 ); + + //Check team and color the particle correctly + if( args->iparam1 == 1 ) + bPart->color = 70; + else + bPart->color = 43; + + bPart->type = pt_grav; + bPart->die = gEngfuncs.GetClientTime() + 3; + } + } +} + void EV_PowerupCallback( struct tempent_s *ent, float frametime, float currenttime ) { //If the Player is not on our PVS, then go back diff --git a/cl_dll/quake/quake_events.cpp b/cl_dll/quake/quake_events.cpp index 6925bbf9..5fbea81d 100644 --- a/cl_dll/quake/quake_events.cpp +++ b/cl_dll/quake/quake_events.cpp @@ -39,6 +39,11 @@ void EV_DMC_DoorGoDown( struct event_args_s *args ); void EV_DMC_DoorHitTop( struct event_args_s *args ); void EV_DMC_DoorHitBottom( struct event_args_s *args ); +void EV_Hook( event_args_t *args ); +void EV_Cable( struct event_args_s *args ); +void EV_FollowCarrier( struct event_args_s *args ); +void EV_FlagSpawn( struct event_args_s *args ); + // HLDM void EV_TrainPitchAdjust( struct event_args_s *args ); } @@ -79,5 +84,10 @@ void Game_HookEvents( void ) gEngfuncs.pfnHookEvent( "events/door/doorhittop.sc", EV_DMC_DoorHitTop ); gEngfuncs.pfnHookEvent( "events/door/doorhitbottom.sc", EV_DMC_DoorHitBottom ); + gEngfuncs.pfnHookEvent( "events/hook.sc", EV_Hook ); + gEngfuncs.pfnHookEvent( "events/cable.sc", EV_Cable ); + gEngfuncs.pfnHookEvent( "events/follow.sc", EV_FollowCarrier ); + gEngfuncs.pfnHookEvent( "events/flagspawn.sc", EV_FlagSpawn ); + gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); } diff --git a/dlls/3wave/threewave_gamerules.cpp b/dlls/3wave/threewave_gamerules.cpp new file mode 100644 index 00000000..78699b0c --- /dev/null +++ b/dlls/3wave/threewave_gamerules.cpp @@ -0,0 +1,3269 @@ +/*** +* +* Copyright (c) 2001, 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_gamerules.cpp ======================================================== + + This contains all the gamerules for the ThreeWave CTF Gamemode. + It also contains the Flag entity information. + +*/ + +#define NUM_TEAMS 2 + +char *sTeamNames[] = +{ + "SPECTATOR", + "RED", + "BLUE", +}; + +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "gamerules.h" +#include "skill.h" +#include "game.h" +#include "items.h" +#include "threewave_gamerules.h" + +extern int gmsgCTFMsgs; +extern int gmsgShowMenu; +extern int gmsgFlagStatus; +extern int gmsgRuneStatus; +extern int gmsgFlagCarrier; +extern int gmsgScoreInfo; + +extern unsigned short g_usHook; +extern unsigned short g_usCable; +extern unsigned short g_usCarried; +extern unsigned short g_usFlagSpawn; + + +static char team_names[MAX_TEAMS][MAX_TEAMNAME_LENGTH]; +static int team_scores[MAX_TEAMS]; +static int num_teams = 0; + +bool g_bSpawnedRunes; +void SpawnRunes( void ); + +extern edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer, bool bCheckDM ); +extern edict_t *RuneSelectSpawnPoint( void ); + +// 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 + + + +class CThreeWaveGameMgrHelper : public IVoiceGameMgrHelper +{ +public: + virtual bool CanPlayerHearPlayer(CBasePlayer *pPlayer1, CBasePlayer *pPlayer2) + { + return stricmp(pPlayer1->TeamID(), pPlayer2->TeamID()) == 0; + } +}; +static CThreeWaveGameMgrHelper g_GameMgrHelper; + + + +extern DLL_GLOBAL BOOL g_fGameOver; + +char* GetTeamName( int team ) +{ + if ( team < 0 || team > NUM_TEAMS ) + team = 0; + + return sTeamNames[ team ]; +} + +CThreeWave :: CThreeWave() +{ + // CHalfLifeMultiplay already initialized it - just override its helper callback. + m_VoiceGameMgr.SetHelper(&g_GameMgrHelper); + + m_DisableDeathMessages = FALSE; + m_DisableDeathPenalty = FALSE; + + memset( team_names, 0, sizeof(team_names) ); + memset( team_scores, 0, sizeof(team_scores) ); + num_teams = 0; + + iBlueTeamScore = iRedTeamScore = 0; + g_bSpawnedRunes = FALSE; + + // Copy over the team from the server config + m_szTeamList[0] = 0; + + // Cache this because the team code doesn't want to deal with changing this in the middle of a game + strncpy( m_szTeamList, teamlist.string, TEAMPLAY_TEAMLISTLENGTH ); + + edict_t *pWorld = INDEXENT(0); + if ( pWorld && pWorld->v.team ) + { + if ( teamoverride.value ) + { + const char *pTeamList = STRING(pWorld->v.team); + if ( pTeamList && strlen(pTeamList) ) + { + strncpy( m_szTeamList, pTeamList, TEAMPLAY_TEAMLISTLENGTH ); + } + } + } + // Has the server set teams + if ( strlen( m_szTeamList ) ) + m_teamLimit = TRUE; + else + m_teamLimit = FALSE; + + RecountTeams(); +} + + +BOOL CThreeWave::ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) +{ + return CHalfLifeMultiplay::ClientConnected(pEntity, pszName, pszAddress, szRejectReason); +} + + +extern cvar_t timeleft, fragsleft; + +void CThreeWave :: Think ( void ) +{ + m_VoiceGameMgr.Update(gpGlobals->frametime); + + ///// Check game rules ///// + static int last_frags; + static int last_time; + + int frags_remaining = 0; + int time_remaining = 0; + + if ( g_fGameOver ) // someone else quit the game already + { + CHalfLifeMultiplay::Think(); + return; + } + + float flTimeLimit = CVAR_GET_FLOAT("mp_timelimit") * 60; + + time_remaining = (int)(flTimeLimit ? ( flTimeLimit - gpGlobals->time ) : 0); + + if ( flTimeLimit != 0 && gpGlobals->time >= flTimeLimit ) + { + GoToIntermission(); + return; + } + + float flFragLimit = fraglimit.value; + if ( flFragLimit ) + { + int bestfrags = 9999; + int remain; + + // check if any team is over the frag limit + for ( int i = 0; i < num_teams; i++ ) + { + if ( team_scores[i] >= flFragLimit ) + { + GoToIntermission(); + return; + } + + remain = flFragLimit - team_scores[i]; + if ( remain < bestfrags ) + { + bestfrags = remain; + } + } + frags_remaining = bestfrags; + } + + if ( !g_bSpawnedRunes ) + SpawnRunes(); + + if ( m_flFlagStatusTime && m_flFlagStatusTime <= gpGlobals->time ) + GetFlagStatus( NULL ); + + // Updates when frags change + if ( frags_remaining != last_frags ) + { + g_engfuncs.pfnCvar_DirectSet( &fragsleft, UTIL_VarArgs( "%i", frags_remaining ) ); + } + + // Updates once per second + if ( timeleft.value != last_time ) + { + g_engfuncs.pfnCvar_DirectSet( &timeleft, UTIL_VarArgs( "%i", time_remaining ) ); + } + + last_frags = frags_remaining; + last_time = time_remaining; +} + +void CThreeWave :: JoinTeam ( CBasePlayer *pPlayer, int iTeam ) +{ + if ( pPlayer->pev->team == iTeam ) + return; + + if ( pPlayer->m_flNextTeamChange > gpGlobals->time ) + return; + + pPlayer->m_flNextTeamChange = gpGlobals->time + 5; + + if ( pPlayer->pev->team == 0 ) + { + ChangePlayerTeam( pPlayer, iTeam ); + RecountTeams(); + + pPlayer->Spawn(); + } + else + { + ChangePlayerTeam( pPlayer, iTeam ); + RecountTeams(); + } +} + +int CThreeWave::TeamWithFewestPlayers( void ) +{ + + CBaseEntity *pPlayer = NULL; + CBasePlayer *player = NULL; + + int iNumRed, iNumBlue; + + int iTeam; + + // Initialize the player counts.. + iNumRed = iNumBlue = 0; + + pPlayer = UTIL_FindEntityByClassname ( pPlayer, "player" ); + + while ( (pPlayer != NULL) && (!FNullEnt(pPlayer->edict())) ) + { + if (pPlayer->pev->flags != FL_DORMANT) + { + player = GetClassPtr((CBasePlayer *)pPlayer->pev); + + + if ( player->pev->team == RED ) + iNumRed += 1; + + else if ( player->pev->team == BLUE ) + iNumBlue += 1; + + } + pPlayer = UTIL_FindEntityByClassname ( pPlayer, "player" ); + } + + if ( iNumRed == iNumBlue ) + { + switch ( RANDOM_LONG( 0, 1 ) ) + { + case 0: iTeam = RED; break; + case 1: iTeam = BLUE; break; + } + } + else if ( iNumRed == 0 && iNumBlue == 0) + { + switch ( RANDOM_LONG( 0, 1 ) ) + { + case 0: iTeam = RED; break; + case 1: iTeam = BLUE; break; + } + } + + else if ( iNumRed > iNumBlue ) + iTeam = BLUE; + + else if ( iNumRed < iNumBlue ) + iTeam = RED; + + return iTeam; + +} + +void DropRune ( CBasePlayer *pPlayer ); +//========================================================= +// ClientCommand +// the user has typed a command which is unrecognized by everything else; +// this check to see if the gamerules knows anything about the command +//========================================================= +BOOL CThreeWave :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) +{ + if( m_VoiceGameMgr.ClientCommand( pPlayer, pcmd ) ) + return TRUE; + + if ( FStrEq( pcmd, "menuselect" ) ) + { + if ( CMD_ARGC() < 2 ) + return TRUE; + + int slot = atoi( CMD_ARGV(1) ); + + // select the item from the current menu + switch( pPlayer->m_iMenu ) + { + case Team_Menu: + + switch ( slot ) + { + case 1: + JoinTeam( pPlayer, RED ); + break; + case 2: + JoinTeam( pPlayer, BLUE ); + break; + case 5: + JoinTeam( pPlayer, TeamWithFewestPlayers() ); + break; + } + + break; + + case Team_Menu_IG: + + switch ( slot ) + { + case 1: + JoinTeam( pPlayer, RED ); + break; + case 2: + JoinTeam( pPlayer, BLUE ); + break; + case 5: + JoinTeam( pPlayer, TeamWithFewestPlayers() ); + break; + default: + return TRUE; + } + + break; + } + + return TRUE; + } + else if ( FStrEq( pcmd, "droprune" ) ) + { + DropRune( pPlayer ); + + return TRUE; + } + else if ( FStrEq( pcmd, "changeteam" ) ) + { + if ( pPlayer->pev->team != 0 ) + { + pPlayer->ShowMenu( 1 + 2 + 16 + 512, -1, FALSE, "#Team_Menu_Join_IG" ); + pPlayer->m_iMenu = Team_Menu_IG; + } + + return TRUE; + } + + return FALSE; +} + +extern int gmsgGameMode; +extern int gmsgSayText; +extern int gmsgTeamInfo; + +void CThreeWave :: UpdateGameMode( CBasePlayer *pPlayer ) +{ + MESSAGE_BEGIN( MSG_ONE, gmsgGameMode, NULL, pPlayer->edict() ); + WRITE_BYTE( 1 ); // game mode teamplay + MESSAGE_END(); +} + +edict_t *CThreeWave::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) +{ + edict_t *pentSpawnSpot; + + if ( FBitSet( pPlayer->m_afPhysicsFlags, PFLAG_OBSERVER ) || pPlayer->pev->team == 0 ) + pentSpawnSpot = EntSelectSpawnPoint( pPlayer, FALSE ); + else + { + if ( RANDOM_LONG ( 1, 7 ) < 3 ) + pentSpawnSpot= EntSelectSpawnPoint( pPlayer, TRUE ); + else + pentSpawnSpot= EntSelectSpawnPoint( pPlayer, FALSE ); + } + + if ( IsMultiplayer() && pentSpawnSpot->v.target ) + { + FireTargets( STRING(pentSpawnSpot->v.target), pPlayer, pPlayer, USE_TOGGLE, 0 ); + } + + pPlayer->pev->origin = VARS(pentSpawnSpot)->origin + Vector(0,0,1); + pPlayer->pev->v_angle = g_vecZero; + pPlayer->pev->velocity = g_vecZero; + pPlayer->pev->angles = VARS(pentSpawnSpot)->angles; + pPlayer->pev->punchangle = g_vecZero; + pPlayer->pev->fixangle = TRUE; + + return pentSpawnSpot; +} + +void CThreeWave :: PlayerTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) +{ + if ( !pAttacker->IsPlayer() ) + return; + + if ( pPlayer->pev->team == pAttacker->pev->team ) + return; + + if ( pPlayer->m_bHasFlag ) + { + pPlayer->pCarrierHurter = (CBasePlayer *)pAttacker; + pPlayer->m_flCarrierHurtTime = gpGlobals->time + TEAM_CAPTURE_CARRIER_DANGER_PROTECT_TIMEOUT; + } + +} + +void CThreeWave :: PlayerSpawn( CBasePlayer *pPlayer ) +{ + BOOL addDefault; + CBaseEntity *pWeaponEntity = NULL; + + if ( pPlayer->pev->team == 0 ) + { + pPlayer->pev->takedamage = DAMAGE_NO; + pPlayer->pev->solid = SOLID_NOT; + pPlayer->pev->movetype = MOVETYPE_NOCLIP; + pPlayer->pev->effects |= EF_NODRAW; + pPlayer->pev->flags |= FL_NOTARGET; + pPlayer->m_afPhysicsFlags |= PFLAG_OBSERVER; + pPlayer->m_iHideHUD |= HIDEHUD_WEAPONS | HIDEHUD_FLASHLIGHT | HIDEHUD_HEALTH; + + pPlayer->m_flFlagStatusTime = gpGlobals->time + 0.1; + } + else + { + pPlayer->pev->weapons |= (1<Touch( pPlayer ); + addDefault = FALSE; + } + + if ( addDefault ) + { + pPlayer->m_bHasFlag = FALSE; + + pPlayer->m_iHideHUD &= ~HIDEHUD_WEAPONS; + pPlayer->m_iHideHUD &= ~HIDEHUD_FLASHLIGHT; + pPlayer->m_iHideHUD &= ~HIDEHUD_HEALTH; + pPlayer->m_afPhysicsFlags &= ~PFLAG_OBSERVER; + + // Start with init ammoload + pPlayer->m_iAmmoShells = 25; + + // Start with shotgun and axe + pPlayer->GiveNamedItem( "weapon_quakegun" ); + pPlayer->m_iQuakeItems |= ( IT_SHOTGUN | IT_AXE | IT_EXTRA_WEAPON ); + pPlayer->m_iQuakeWeapon = pPlayer->W_BestWeapon(); + pPlayer->W_SetCurrentAmmo(); + + pPlayer->m_flFlagStatusTime = gpGlobals->time + 0.1; + } + } + +/* MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pPlayer->pev); + WRITE_BYTE( pPlayer->m_iRuneStatus ); + MESSAGE_END();*/ +} + +void CBasePlayer::ShowMenu ( int bitsValidSlots, int nDisplayTime, BOOL fNeedMore, char *pszText ) +{ + MESSAGE_BEGIN( MSG_ONE, gmsgShowMenu, NULL, pev); + WRITE_SHORT( bitsValidSlots); + WRITE_CHAR( nDisplayTime ); + WRITE_BYTE( fNeedMore ); + WRITE_STRING (pszText); + MESSAGE_END(); +} + +//========================================================= +// InitHUD +//========================================================= +void CThreeWave::InitHUD( CBasePlayer *pPlayer ) +{ + CHalfLifeMultiplay::InitHUD( pPlayer ); + + int clientIndex = pPlayer->entindex(); + // update this player with all the other players team info + // loop through all active players and send their team info to the new client + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *plr = UTIL_PlayerByIndex( i ); + if ( plr ) + { + MESSAGE_BEGIN( MSG_ONE, gmsgTeamInfo, NULL, pPlayer->edict() ); + WRITE_BYTE( plr->entindex() ); + WRITE_STRING( plr->TeamID() ); + MESSAGE_END(); + + if ( ((CBasePlayer *)plr)->m_bHasFlag ) + { + MESSAGE_BEGIN( MSG_ONE, gmsgFlagCarrier, NULL, pPlayer->edict() ); + WRITE_BYTE( plr->entindex() ); + WRITE_BYTE( 1 ); + MESSAGE_END(); + } + } + } + + //Remove Rune icon if we have one. + MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pPlayer->pev); + WRITE_BYTE( 0 ); + MESSAGE_END(); + + if ( pPlayer->pev->team == 0) + { + pPlayer->ShowMenu( 1 + 2 + 16, -1, FALSE, "#Team_Menu_Join" ); + pPlayer->m_iMenu = Team_Menu; + } +} + + +void CThreeWave::ChangePlayerTeam( CBasePlayer *pPlayer, int iTeam ) +{ + int damageFlags = DMG_GENERIC; + int clientIndex = pPlayer->entindex(); + + if ( pPlayer->pev->team != 0 ) + { + damageFlags |= DMG_ALWAYSGIB; + + // kill the player, remove a death, and let them start on the new team + m_DisableDeathMessages = TRUE; + m_DisableDeathPenalty = TRUE; + + entvars_t *pevWorld = VARS( INDEXENT(0) ); + pPlayer->TakeDamage( pevWorld, pevWorld, 900, damageFlags ); + + m_DisableDeathMessages = FALSE; + m_DisableDeathPenalty = FALSE; + } + + int oldTeam = pPlayer->pev->team; + pPlayer->pev->team = iTeam; + + if ( pPlayer->pev->team == RED ) + { + strncpy( pPlayer->m_szTeamName, "RED", TEAM_NAME_LENGTH ); + g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", "red" ); + g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "topcolor", UTIL_VarArgs( "%d", 255 ) ); + } + else if ( pPlayer->pev->team == BLUE ) + { + strncpy( pPlayer->m_szTeamName, "BLUE", TEAM_NAME_LENGTH ); + g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", "blue" ); + g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "topcolor", UTIL_VarArgs( "%d", 153 ) ); + } + + // notify everyone's HUD of the team change + MESSAGE_BEGIN( MSG_ALL, gmsgTeamInfo ); + WRITE_BYTE( clientIndex ); + WRITE_STRING( pPlayer->m_szTeamName ); + MESSAGE_END(); + + MESSAGE_BEGIN( MSG_ALL, gmsgScoreInfo ); + WRITE_BYTE( ENTINDEX(pPlayer->edict()) ); + WRITE_SHORT( pPlayer->pev->frags ); + WRITE_SHORT( pPlayer->m_iDeaths ); + WRITE_SHORT( pPlayer->pev->team ); + MESSAGE_END(); + + // log the change + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" joined team \"%s\"\n", + STRING(pPlayer->pev->netname), + GETPLAYERUSERID( pPlayer->edict() ), + GETPLAYERAUTHID( pPlayer->edict() ), + GetTeamName( oldTeam ), + pPlayer->m_szTeamName ); +} + + +//========================================================= +// ClientUserInfoChanged +//========================================================= +void CThreeWave::ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ) +{ + + int clientIndex = pPlayer->entindex(); + + if ( pPlayer->pev->team == RED ) + { + g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "topcolor", UTIL_VarArgs( "%d", 255 ) ); + g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", "red" ); + } + else if ( pPlayer->pev->team == BLUE ) + { + g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "topcolor", UTIL_VarArgs( "%d", 153 ) ); + g_engfuncs.pfnSetClientKeyValue( clientIndex, g_engfuncs.pfnGetInfoKeyBuffer( pPlayer->edict() ), "model", "blue" ); + } + +} + +extern int gmsgDeathMsg; + +//========================================================= +// Deathnotice. +//========================================================= +void CThreeWave::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ) +{ + if ( m_DisableDeathMessages ) + return; + + if ( pVictim && pKiller && pKiller->flags & FL_CLIENT ) + { + CBasePlayer *pk = (CBasePlayer*) CBaseEntity::Instance( pKiller ); + + if ( pk ) + { + if ( (pk != pVictim) && (PlayerRelationship( pVictim, pk ) == GR_TEAMMATE) ) + { + MESSAGE_BEGIN( MSG_ALL, gmsgDeathMsg ); + WRITE_BYTE( ENTINDEX(ENT(pKiller)) ); // the killer + WRITE_BYTE( ENTINDEX(pVictim->edict()) ); // the victim + WRITE_STRING( "teammate" ); // flag this as a teammate kill + MESSAGE_END(); + return; + } + } + } + + CHalfLifeMultiplay::DeathNotice( pVictim, pKiller, pevInflictor ); +} + +//========================================================= +//========================================================= +void CThreeWave :: ClientDisconnected( edict_t *pClient ) +{ + if ( pClient ) + { + CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( pClient ); + + if ( pPlayer ) + { + //We have the flag, spawn it + if ( pPlayer->m_bHasFlag ) + { + CBaseEntity *pEnt; + + //We have the BLUE flag, Spawn it + if ( pPlayer->pev->team == RED ) + { + pEnt = CBaseEntity::Create( "item_flag_team2", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() ); + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_Blue_Flag\"\n", + STRING( pPlayer->pev->netname ), + GETPLAYERUSERID( pPlayer->edict() ), + GETPLAYERAUTHID( pPlayer->edict() ), + GetTeamName( pPlayer->pev->team ) ); + } + //We have the RED flag, Spawn it + else if ( pPlayer->pev->team == BLUE ) + { + pEnt = CBaseEntity::Create( "item_flag_team1", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() ); + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_Red_Flag\"\n", + STRING( pPlayer->pev->netname ), + GETPLAYERUSERID( pPlayer->edict() ), + GETPLAYERAUTHID( pPlayer->edict() ), + GetTeamName( pPlayer->pev->team ) ); + } + + pEnt->pev->velocity = pPlayer->pev->velocity * 1.2; + pEnt->pev->angles.x = 0; + + CItemFlag *pFlag = (CItemFlag *)pEnt; + pFlag->Dropped = TRUE; + pFlag->m_flDroppedTime = gpGlobals->time + TEAM_CAPTURE_FLAG_RETURN_TIME; + + 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 ); + + MESSAGE_BEGIN ( MSG_ALL, gmsgCTFMsgs, NULL ); + if ( pPlayer->pev->team == RED ) + WRITE_BYTE( BLUE_FLAG_LOST ); + else if ( pPlayer->pev->team == BLUE ) + WRITE_BYTE( RED_FLAG_LOST ); + + WRITE_STRING( STRING(pPlayer->pev->netname) ); + MESSAGE_END(); + + m_flFlagStatusTime = gpGlobals->time + 0.1; + + pPlayer->m_bHasFlag = FALSE; + } + + // drop any runes the player has + CBaseEntity *pRune; + char * runeName; + + switch ( pPlayer->m_iRuneStatus ) + { + case ITEM_RUNE1_FLAG: + + pRune = CBaseEntity::Create( "item_rune1", pPlayer->pev->origin, pPlayer->pev->angles, NULL ); + + pRune->pev->velocity = pPlayer->pev->velocity * 1.5; + pRune->pev->angles.x = 0; + ((CResistRune*)pRune)->dropped = true; + + runeName = "ResistRune"; + + break; + + case ITEM_RUNE2_FLAG: + + pRune = CBaseEntity::Create( "item_rune2", pPlayer->pev->origin, pPlayer->pev->angles, NULL ); + + pRune->pev->velocity = pPlayer->pev->velocity * 1.5; + pRune->pev->angles.x = 0; + ((CStrengthRune*)pRune)->dropped = true; + + runeName = "StrengthRune"; + + break; + + case ITEM_RUNE3_FLAG: + + pRune = CBaseEntity::Create( "item_rune3", pPlayer->pev->origin, pPlayer->pev->angles, NULL ); + + pRune->pev->velocity = pPlayer->pev->velocity * 1.5; + pRune->pev->angles.x = 0; + ((CHasteRune*)pRune)->dropped = true; + + runeName = "HasteRune"; + + break; + + case ITEM_RUNE4_FLAG: + + pRune = CBaseEntity::Create( "item_rune4", pPlayer->pev->origin, pPlayer->pev->angles, NULL ); + + pRune->pev->velocity = pPlayer->pev->velocity * 1.5; + pRune->pev->angles.x = 0; + ((CRegenRune*)pRune)->dropped = true; + + runeName = "RegenRune"; + + break; + + default: + + runeName = "Unknown"; + + break; + } + + if ( pPlayer->m_iRuneStatus ) + { + pPlayer->m_iRuneStatus = 0; + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_%s\"\n", + STRING(pPlayer->pev->netname), + GETPLAYERUSERID( pPlayer->edict() ), + GETPLAYERAUTHID( pPlayer->edict() ), + pPlayer->m_szTeamName, + runeName ); + } + + FireTargets( "game_playerleave", pPlayer, pPlayer, USE_TOGGLE, 0 ); + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" disconnected\n", + STRING( pPlayer->pev->netname ), + GETPLAYERUSERID( pPlayer->edict() ), + GETPLAYERAUTHID( pPlayer->edict() ), + GetTeamName( pPlayer->pev->team ) ); + + pPlayer->RemoveAllItems( TRUE );// destroy all of the players weapons and items + } + } +} + +void CThreeWave :: PlayerThink( CBasePlayer *pPlayer ) +{ + if ( g_fGameOver ) + { + // check for button presses + if ( pPlayer->m_afButtonPressed & ( IN_DUCK | IN_ATTACK | IN_ATTACK2 | IN_USE | IN_JUMP ) ) + m_iEndIntermissionButtonHit = TRUE; + + // clear attack/use commands from player + pPlayer->m_afButtonPressed = 0; + pPlayer->pev->button = 0; + pPlayer->m_afButtonReleased = 0; + } + + if ( pPlayer->pFlagCarrierKiller ) + { + if ( pPlayer->m_flFlagCarrierKillTime <= gpGlobals->time ) + pPlayer->pFlagCarrierKiller = NULL; + } + + if ( pPlayer->pFlagReturner ) + { + if ( pPlayer->m_flFlagReturnTime <= gpGlobals->time ) + pPlayer->pFlagReturner = NULL; + } + + if ( pPlayer->pCarrierHurter ) + { + if ( pPlayer->m_flCarrierHurtTime <= gpGlobals->time ) + pPlayer->pCarrierHurter = NULL; + } + + if ( pPlayer->m_iRuneStatus == ITEM_RUNE4_FLAG) + { + if ( pPlayer->m_flRegenTime <= gpGlobals->time) + { + + + if ( pPlayer->pev->health < 150 ) + { + pPlayer->pev->health += 5; + + if ( pPlayer->pev->health > 150) + pPlayer->pev->health = 150; + + pPlayer->m_flRegenTime = gpGlobals->time + 1; + + EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "rune/rune4.wav", 1, ATTN_NORM); + } + if ( pPlayer->pev->armorvalue < 150 && pPlayer->pev->armorvalue ) + { + pPlayer->pev->armorvalue += 5; + + if ( pPlayer->pev->armorvalue > 150) + pPlayer->pev->armorvalue = 150; + + pPlayer->m_flRegenTime = gpGlobals->time + 1; + + EMIT_SOUND(ENT(pPlayer->pev), CHAN_ITEM, "rune/rune4.wav", 1, ATTN_NORM); + } + } + } + + if ( pPlayer->m_bOn_Hook ) + pPlayer->Service_Grapple(); + + if ( pPlayer->m_flFlagStatusTime && pPlayer->m_flFlagStatusTime <= gpGlobals->time ) + GetFlagStatus( pPlayer ); +} + +//========================================================= +//========================================================= +void CThreeWave :: PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ) +{ + CBasePlayer *pk = NULL; + + if ( pKiller ) + { + CBaseEntity *pTemp = CBaseEntity::Instance( pKiller ); + + if ( pTemp->IsPlayer() ) + pk = (CBasePlayer*)pTemp; + } + + //Only award a bonus if the Flag carrier had the flag for more than 2 secs + //Prevents from people waiting for the flag carrier to grab the flag and then killing him + //Instead of actually defending the flag. + if ( pVictim->m_bHasFlag ) + { + if ( pk ) + { + if ( pVictim->pev->team != pk->pev->team ) + { + if ( pVictim->m_flCarrierPickupTime <= gpGlobals->time ) + pk->AddPoints( TEAM_CAPTURE_FRAG_CARRIER_BONUS, TRUE ); + + if ( pk->pev->team == RED ) + { + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pk->pev->netname ) ); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " fragged " ); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "BLUE" ); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "'s flag carrier!\n" ); + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Killed_Enemy_Flag_Carrier\"\n", + STRING( pk->pev->netname ), + GETPLAYERUSERID( pk->edict() ), + GETPLAYERAUTHID( pk->edict() ), + GetTeamName( pk->pev->team ) ); + + if ( 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->pFlagCarrierKiller = pk; + pTeamMate->m_flFlagCarrierKillTime = gpGlobals->time + TEAM_CAPTURE_FRAG_CARRIER_ASSIST_TIMEOUT; + } + } + } + } + } + + if ( pk->pev->team == BLUE ) + { + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pk->pev->netname ) ); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " fragged " ); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "RED" ); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "'s flag carrier!\n" ); + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Killed_Enemy_Flag_Carrier\"\n", + STRING( pk->pev->netname ), + GETPLAYERUSERID( pk->edict() ), + GETPLAYERAUTHID( pk->edict() ), + GetTeamName( pk->pev->team ) ); + + if ( 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->pFlagCarrierKiller = pk; + pTeamMate->m_flFlagCarrierKillTime = gpGlobals->time + TEAM_CAPTURE_FRAG_CARRIER_ASSIST_TIMEOUT; + } + } + } + } + } + } + } + + + CBaseEntity *pEnt; + + //We have the BLUE flag, Spawn it + if ( pVictim->pev->team == RED ) + { + pEnt = CBaseEntity::Create( "item_flag_team2", pVictim->pev->origin, pVictim->pev->angles, pVictim->edict() ); + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_Blue_Flag\"\n", + STRING( pVictim->pev->netname ), + GETPLAYERUSERID( pVictim->edict() ), + GETPLAYERAUTHID( pVictim->edict() ), + GetTeamName( pVictim->pev->team ) ); + } + else if ( pVictim->pev->team == BLUE ) + { + pEnt = CBaseEntity::Create( "item_flag_team1", pVictim->pev->origin, pVictim->pev->angles, pVictim->edict() ); + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_Red_Flag\"\n", + STRING( pVictim->pev->netname ), + GETPLAYERUSERID( pVictim->edict() ), + GETPLAYERAUTHID( pVictim->edict() ), + GetTeamName( pVictim->pev->team ) ); + } + + pEnt->pev->velocity = pVictim->pev->velocity * 1.2; + pEnt->pev->angles.x = 0; + + CItemFlag *pFlag = (CItemFlag *)pEnt; + pFlag->Dropped = TRUE; + + PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, + pVictim->edict(), g_usCarried, 0, (float *)&g_vecZero, (float *)&g_vecZero, + 0.0, 0.0, pVictim->entindex(), pVictim->pev->team, 1, 0 ); + + pFlag->m_flDroppedTime = gpGlobals->time + TEAM_CAPTURE_FLAG_RETURN_TIME; + + MESSAGE_BEGIN ( MSG_ALL, gmsgCTFMsgs, NULL ); + if ( pVictim->pev->team == RED ) + WRITE_BYTE( BLUE_FLAG_LOST ); + else if ( pVictim->pev->team == BLUE ) + WRITE_BYTE( RED_FLAG_LOST ); + + WRITE_STRING( STRING(pVictim->pev->netname) ); + MESSAGE_END(); + + pVictim->m_bHasFlag = FALSE; + + m_flFlagStatusTime = gpGlobals->time + 0.1; + } + else + { + if ( pk ) + { + if ( pk->pev->team == RED ) + { + if ( iBlueFlagStatus == BLUE_FLAG_STOLEN ) + { + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer *pTeamMate = (CBasePlayer *)UTIL_PlayerByIndex( i ); + + if ( pTeamMate && pTeamMate != pk ) + { + if ( pTeamMate->pev->team == pk->pev->team ) + { + if ( pTeamMate->m_bHasFlag ) + { + if ( pTeamMate->pCarrierHurter ) + { + if ( pTeamMate->pCarrierHurter == pVictim ) + { + if ( pTeamMate->m_flCarrierHurtTime > gpGlobals->time ) + { + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pk->pev->netname ) ); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " defends "); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "RED" ); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "'s flag carrier against an agressive enemy\n"); + + pk->AddPoints( TEAM_CAPTURE_CARRIER_DANGER_PROTECT_BONUS, TRUE ); + } + } + } + } + } + } + } + } + } + + if ( pk->pev->team == BLUE ) + { + if ( iRedFlagStatus == RED_FLAG_STOLEN ) + { + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer *pTeamMate = (CBasePlayer *)UTIL_PlayerByIndex( i ); + + if ( pTeamMate && pTeamMate != pk ) + { + if ( pTeamMate->pev->team == pk->pev->team ) + { + if ( pTeamMate->m_bHasFlag ) + { + if ( pTeamMate->pCarrierHurter ) + { + if ( pTeamMate->pCarrierHurter == pVictim ) + { + if ( pTeamMate->m_flCarrierHurtTime > gpGlobals->time ) + { + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING( pk->pev->netname ) ); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " defends "); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "BLUE" ); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "'s flag carrier against an agressive enemy\n"); + + pk->AddPoints( TEAM_CAPTURE_CARRIER_DANGER_PROTECT_BONUS, TRUE ); + } + } + } + } + } + } + } + } + } + } + + } + + // Find if this guy is near our flag or our flag carrier + CBaseEntity *ent = NULL; + float Dist; + + if ( pk ) + { + if ( pk->pev->team == RED ) + { + while((ent = UTIL_FindEntityByClassname( ent, "item_flag_team1")) != NULL) + { + //Do not defend a invisible flag + if ( ent->pev->effects & EF_NODRAW ) + break; + + Dist = (pk->pev->origin - ent->pev->origin).Length(); + + if ( Dist <= TEAM_CAPTURE_TARGET_PROTECT_RADIUS ) + { + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING ( pk->pev->netname )); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " defends the "); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "RED"); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " flag\n"); + + pk->AddPoints( TEAM_CAPTURE_FLAG_DEFENSE_BONUS, TRUE ); + break; + } + } + + if ( iBlueFlagStatus == BLUE_FLAG_STOLEN ) + { + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer *pTeamMate = (CBasePlayer *)UTIL_PlayerByIndex( i ); + + if ( pTeamMate && pTeamMate != pk ) + { + if ( pTeamMate->pev->team == pk->pev->team ) + { + if ( pTeamMate->m_bHasFlag ) + { + Dist = (pk->pev->origin - pTeamMate->pev->origin).Length(); + + if ( Dist <= TEAM_CAPTURE_TARGET_PROTECT_RADIUS ) + { + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING ( pk->pev->netname )); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " defends "); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "RED"); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "'s flag carrier\n"); + + pk->AddPoints( TEAM_CAPTURE_CARRIER_PROTECT_BONUS, TRUE ); + } + } + } + } + } + } + + } + else if ( pk->pev->team == BLUE ) + { + while((ent = UTIL_FindEntityByClassname( ent, "item_flag_team2")) != NULL) + { + //Do not defend a invisible flag + if ( ent->pev->effects & EF_NODRAW ) + break; + + Dist = (pk->pev->origin - ent->pev->origin).Length(); + + if ( Dist <= TEAM_CAPTURE_TARGET_PROTECT_RADIUS ) + { + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING ( pk->pev->netname )); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " defends the "); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "RED"); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " flag\n"); + + pk->AddPoints( TEAM_CAPTURE_FLAG_DEFENSE_BONUS, TRUE ); + break; + } + } + + if ( iRedFlagStatus == RED_FLAG_STOLEN ) + { + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBasePlayer *pTeamMate = (CBasePlayer *)UTIL_PlayerByIndex( i ); + + if ( pTeamMate && pTeamMate != pk ) + { + if ( pTeamMate->pev->team == pk->pev->team ) + { + if ( pTeamMate->m_bHasFlag ) + { + Dist = (pk->pev->origin - pTeamMate->pev->origin).Length(); + + if ( Dist <= TEAM_CAPTURE_TARGET_PROTECT_RADIUS ) + { + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, STRING ( pk->pev->netname )); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, " defends "); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "RED"); + UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "'s flag carrier\n"); + + pk->AddPoints( TEAM_CAPTURE_CARRIER_PROTECT_BONUS, TRUE ); + } + } + } + } + } + } + + } + } + + CBaseEntity *pRune; + char * runeName; + + switch ( pVictim->m_iRuneStatus ) + { + case ITEM_RUNE1_FLAG: + + pRune = CBaseEntity::Create( "item_rune1", pVictim->pev->origin, pVictim->pev->angles, NULL ); + + pRune->pev->velocity = pVictim->pev->velocity * 1.5; + pRune->pev->angles.x = 0; + ((CResistRune*)pRune)->dropped = true; + + runeName = "ResistRune"; + + break; + + case ITEM_RUNE2_FLAG: + + pRune = CBaseEntity::Create( "item_rune2", pVictim->pev->origin, pVictim->pev->angles, NULL ); + + pRune->pev->velocity = pVictim->pev->velocity * 1.5; + pRune->pev->angles.x = 0; + ((CStrengthRune*)pRune)->dropped = true; + + runeName = "StrengthRune"; + + break; + + case ITEM_RUNE3_FLAG: + + pRune = CBaseEntity::Create( "item_rune3", pVictim->pev->origin, pVictim->pev->angles, NULL ); + + pRune->pev->velocity = pVictim->pev->velocity * 1.5; + pRune->pev->angles.x = 0; + ((CHasteRune*)pRune)->dropped = true; + + runeName = "HasteRune"; + + break; + + case ITEM_RUNE4_FLAG: + + pRune = CBaseEntity::Create( "item_rune4", pVictim->pev->origin, pVictim->pev->angles, NULL ); + + pRune->pev->velocity = pVictim->pev->velocity * 1.5; + pRune->pev->angles.x = 0; + ((CRegenRune*)pRune)->dropped = true; + + runeName = "RegenRune"; + + break; + + default: + + runeName = "Unknown"; + + break; + } + + if ( pVictim->m_iRuneStatus ) + { + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_%s\"\n", + STRING(pVictim->pev->netname), + GETPLAYERUSERID( pVictim->edict() ), + GETPLAYERAUTHID( pVictim->edict() ), + pVictim->m_szTeamName, + runeName ); + } + + if ( pVictim->m_ppHook ) + (( CGrapple *)pVictim->m_ppHook)->Reset_Grapple(); + + pVictim->m_iRuneStatus = 0; + + MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pVictim->pev); + WRITE_BYTE( pVictim->m_iRuneStatus ); + MESSAGE_END(); + + if ( !m_DisableDeathPenalty ) + { + CHalfLifeMultiplay::PlayerKilled( pVictim, pKiller, pInflictor ); + RecountTeams(); + } +} + + +//========================================================= +// IsTeamplay +//========================================================= +BOOL CThreeWave::IsTeamplay( void ) +{ + return TRUE; +} + +BOOL CThreeWave::FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ) +{ + if ( pAttacker && PlayerRelationship( pPlayer, pAttacker ) == GR_TEAMMATE ) + { + // my teammate hit me. + if ( (CVAR_GET_FLOAT("mp_friendlyfire") == 0) && (pAttacker != pPlayer) ) + { + // friendly fire is off, and this hit came from someone other than myself, then don't get hurt + return FALSE; + } + } + + return CHalfLifeMultiplay::FPlayerCanTakeDamage( pPlayer, pAttacker ); +} + +//========================================================= +//========================================================= +int CThreeWave::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) +{ + // half life multiplay has a simple concept of Player Relationships. + // you are either on another player's team, or you are not. + if ( !pPlayer || !pTarget || !pTarget->IsPlayer() ) + return GR_NOTTEAMMATE; + + //As simple as this + if ( pPlayer->pev->team == pTarget->pev->team ) + { + return GR_TEAMMATE; + } + + return GR_NOTTEAMMATE; +} + +//========================================================= +//========================================================= +BOOL CThreeWave::ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ) +{ + // always autoaim, unless target is a teammate + CBaseEntity *pTgt = CBaseEntity::Instance( target ); + if ( pTgt && pTgt->IsPlayer() ) + { + if ( PlayerRelationship( pPlayer, pTgt ) == GR_TEAMMATE ) + return FALSE; // don't autoaim at teammates + } + + return CHalfLifeMultiplay::ShouldAutoAim( pPlayer, target ); +} + +//========================================================= +//========================================================= +int CThreeWave::IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ) +{ + if ( !pKilled ) + return 0; + + if ( !pAttacker ) + return 1; + + if ( pAttacker != pKilled && PlayerRelationship( pAttacker, pKilled ) == GR_TEAMMATE ) + return -1; + + return 1; +} + +//========================================================= +//========================================================= +const char *CThreeWave::GetTeamID( CBaseEntity *pEntity ) +{ + if ( pEntity == NULL || pEntity->pev == NULL ) + return ""; + + // return their team name + return pEntity->TeamID(); +} + + +int CThreeWave::GetTeamIndex( const char *pTeamName ) +{ + if ( pTeamName && *pTeamName != 0 ) + { + // try to find existing team + for ( int tm = 0; tm < num_teams; tm++ ) + { + if ( !stricmp( team_names[tm], pTeamName ) ) + return tm; + } + } + + return -1; // No match +} + + +const char *CThreeWave::GetIndexedTeamName( int teamIndex ) +{ + if ( teamIndex < 0 || teamIndex >= num_teams ) + return ""; + + return team_names[ teamIndex ]; +} + + +BOOL CThreeWave::IsValidTeam( const char *pTeamName ) +{ + if ( !m_teamLimit ) // Any team is valid if the teamlist isn't set + return TRUE; + + return ( GetTeamIndex( pTeamName ) != -1 ) ? TRUE : FALSE; +} + + +void CThreeWave::GetFlagStatus( CBasePlayer *pPlayer ) +{ + + CBaseEntity *pFlag = NULL; + int iFoundCount = 0; + int iDropped = 0; + + while((pFlag = UTIL_FindEntityByClassname( pFlag, "carried_flag_team1")) != NULL) + { + if ( pFlag && !FBitSet( pFlag->pev->flags, FL_KILLME) ) + iFoundCount++; + } + + if ( iFoundCount >= 1 ) + iRedFlagStatus = RED_FLAG_STOLEN; + + if ( !iFoundCount ) + { + while((pFlag = UTIL_FindEntityByClassname( pFlag, "item_flag_team1")) != NULL) + { + if ( pFlag ) + { + if ( ((CItemFlag *)pFlag)->Dropped ) + iDropped++; + + iFoundCount++; + } + } + + if ( iFoundCount > 1 && iDropped == 1 ) + iRedFlagStatus = RED_FLAG_DROPPED; + else if ( iFoundCount >= 1 && iDropped == 0 ) + iRedFlagStatus = RED_FLAG_ATBASE; + } + + iDropped = iFoundCount = 0; + + while((pFlag = UTIL_FindEntityByClassname( pFlag, "carried_flag_team2")) != NULL) + { + if ( pFlag && !FBitSet( pFlag->pev->flags, FL_KILLME) ) + iFoundCount++; + } + + if ( iFoundCount >= 1 ) + iBlueFlagStatus = BLUE_FLAG_STOLEN; + + if ( !iFoundCount ) + { + + while((pFlag = UTIL_FindEntityByClassname( pFlag, "item_flag_team2")) != NULL) + { + if ( pFlag ) + { + if ( ((CItemFlag *)pFlag)->Dropped ) + iDropped++; + + iFoundCount++; + } + } + + if ( iFoundCount > 1 && iDropped == 1 ) + iBlueFlagStatus = BLUE_FLAG_DROPPED; + else if ( iFoundCount >= 1 && iDropped == 0 ) + iBlueFlagStatus = BLUE_FLAG_ATBASE; + } + + if ( pPlayer ) + { + if ( pPlayer->pev->team == 0 ) + { + MESSAGE_BEGIN( MSG_ONE, gmsgFlagStatus, NULL, pPlayer->edict() ); + WRITE_BYTE( 0 ); + WRITE_BYTE( iRedFlagStatus ); + WRITE_BYTE( iBlueFlagStatus ); + WRITE_BYTE( iRedTeamScore ); + WRITE_BYTE( iBlueTeamScore ); + MESSAGE_END(); + } + else + { + MESSAGE_BEGIN( MSG_ONE, gmsgFlagStatus, NULL, pPlayer->edict() ); + WRITE_BYTE( 1 ); + WRITE_BYTE( iRedFlagStatus ); + WRITE_BYTE( iBlueFlagStatus ); + WRITE_BYTE( iRedTeamScore ); + WRITE_BYTE( iBlueTeamScore ); + MESSAGE_END(); + } + + pPlayer->m_flFlagStatusTime = 0.0; + } + else + { + MESSAGE_BEGIN( MSG_ALL, gmsgFlagStatus, NULL ); + WRITE_BYTE( 1 ); + WRITE_BYTE( iRedFlagStatus ); + WRITE_BYTE( iBlueFlagStatus ); + WRITE_BYTE( iRedTeamScore ); + WRITE_BYTE( iBlueTeamScore ); + MESSAGE_END(); + + m_flFlagStatusTime = 0.0; + } + + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *plr = UTIL_PlayerByIndex( i ); + if ( plr ) + { + if ( ((CBasePlayer *)plr)->m_bHasFlag ) + { + MESSAGE_BEGIN( MSG_ALL, gmsgFlagCarrier, NULL ); + WRITE_BYTE( plr->entindex() ); + WRITE_BYTE( 1 ); + MESSAGE_END(); + } + else + { + MESSAGE_BEGIN( MSG_ALL, gmsgFlagCarrier, NULL ); + WRITE_BYTE( plr->entindex() ); + WRITE_BYTE( 0 ); + MESSAGE_END(); + } + } + } +} + + +//========================================================= +//========================================================= +void CThreeWave::RecountTeams( void ) +{ + char *pName; + char teamlist[TEAMPLAY_TEAMLISTLENGTH]; + + // loop through all teams, recounting everything + num_teams = 0; + + // Copy all of the teams from the teamlist + // make a copy because strtok is destructive + strcpy( teamlist, m_szTeamList ); + pName = teamlist; + pName = strtok( pName, ";" ); + while ( pName != NULL && *pName ) + { + if ( GetTeamIndex( pName ) < 0 ) + { + strcpy( team_names[num_teams], pName ); + num_teams++; + } + pName = strtok( NULL, ";" ); + } + + if ( num_teams < 2 ) + { + num_teams = 0; + m_teamLimit = FALSE; + } + + // Sanity check + memset( team_scores, 0, sizeof(team_scores) ); + + // loop through all clients + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseEntity *plr = UTIL_PlayerByIndex( i ); + + if ( plr ) + { + const char *pTeamName = plr->TeamID(); + // try add to existing team + int tm = GetTeamIndex( pTeamName ); + + if ( tm < 0 ) // no team match found + { + if ( !m_teamLimit ) + { + // add to new team + tm = num_teams; + num_teams++; + team_scores[tm] = 0; + strncpy( team_names[tm], pTeamName, MAX_TEAMNAME_LENGTH ); + } + } + + if ( tm >= 0 ) + { + team_scores[tm] += plr->pev->frags; + } + } + } +} + +/***************************************************** +****************************************************** + THREEWAVE CTF FLAG CODE +****************************************************** +*****************************************************/ + +enum Flag_Anims +{ + ON_GROUND = 0, + NOT_CARRIED, + CARRIED, + WAVE_IDLE, + FLAG_POSITION +}; + + +void CItemFlag::Spawn ( void ) +{ + 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( FlagThink ); + SetTouch( 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 if ( !Dropped ) + { + //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( void ) +{ + 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( FlagTouch ); + SetThink( 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( void ) +{ + 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( void ) +{ + 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( void ) + { + pev->team = RED; + CItemFlag::Spawn( ); + } +}; + +class CItemFlagTeam2 : public CItemFlag +{ + void Spawn( void ) + { + pev->team = BLUE; + CItemFlag::Spawn( ); + } +}; + +LINK_ENTITY_TO_CLASS( item_flag_team1, CItemFlagTeam1 ); +LINK_ENTITY_TO_CLASS( item_flag_team2, 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; + + m_iOwnerOldVel = 0; + + SetThink( 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; + + //Remove if owner is death + if (!Owner->IsAlive()) + UTIL_Remove( this ); + + //If owner lost flag, remove + if ( !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( void ) + { + pev->team = RED; + + CCarriedFlag::Spawn( ); + } +}; + +class CCarriedFlagTeam2 : public CCarriedFlag +{ + void Spawn( void ) + { + pev->team = BLUE; + + CCarriedFlag::Spawn( ); + } +}; + +LINK_ENTITY_TO_CLASS( carried_flag_team1, CCarriedFlagTeam1 ); +LINK_ENTITY_TO_CLASS( carried_flag_team2, CCarriedFlagTeam2 ); + + +/*************************************** +**************************************** + RUNES +**************************************** +***************************************/ + +/*---------------------------------------------------------------------- + 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 ( !strcmp( STRING( ent->pev->classname ), "item_rune1") || + !strcmp( STRING( ent->pev->classname ), "item_rune2") || + !strcmp( STRING( ent->pev->classname ), "item_rune3") || + !strcmp( STRING( ent->pev->classname ), "item_rune4") ) + return FALSE; + } + + return TRUE; +} + +edict_t *RuneSelectSpawnPoint( void ) +{ + CBaseEntity *pSpot; + + 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 == Vector( 0, 0, 0 ) ) + { + 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"); + if ( pSpot ) + goto ReturnSpot; + } + else + { + pSpot = UTIL_FindEntityByTargetname( NULL, STRING(gpGlobals->startspot) ); + if ( pSpot ) + goto ReturnSpot; + } + +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; + } + + CBaseEntity *pRune = NULL; + char * runeName; + + if ( pPlayer->m_iRuneStatus == ITEM_RUNE1_FLAG ) + { + pRune = CBaseEntity::Create( "item_rune1", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() ); + runeName = "ResistRune"; + + if ( pRune ) + ((CResistRune*)pRune)->dropped = true; + } + else if ( pPlayer->m_iRuneStatus == ITEM_RUNE2_FLAG ) + { + pRune = CBaseEntity::Create( "item_rune2", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() ); + runeName = "StrengthRune"; + + if ( pRune ) + ((CStrengthRune*)pRune)->dropped = true; + } + else if ( pPlayer->m_iRuneStatus == ITEM_RUNE3_FLAG ) + { + pRune = CBaseEntity::Create( "item_rune3", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() ); + runeName = "HasteRune"; + + if ( pRune ) + ((CHasteRune*)pRune)->dropped = true; + } + else if ( pPlayer->m_iRuneStatus == ITEM_RUNE4_FLAG ) + { + pRune = CBaseEntity::Create( "item_rune4", pPlayer->pev->origin, pPlayer->pev->angles, pPlayer->edict() ); + runeName = "RegenRune"; + + if ( pRune ) + ((CRegenRune*)pRune)->dropped = true; + } + else + { + runeName = "Unknown"; + } + + if ( pPlayer->m_iRuneStatus == ITEM_RUNE3_FLAG ) + g_engfuncs.pfnSetClientMaxspeed( ENT( pPlayer->pev ), PLAYER_MAX_SPEED ); //Reset Haste player speed to normal + + pPlayer->m_iRuneStatus = 0; + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Dropped_%s\"\n", + STRING(pPlayer->pev->netname), + GETPLAYERUSERID( pPlayer->edict() ), + GETPLAYERAUTHID( pPlayer->edict() ), + pPlayer->m_szTeamName, + runeName ); + + MESSAGE_BEGIN( MSG_ONE, gmsgRuneStatus, NULL, pPlayer->pev); + WRITE_BYTE( pPlayer->m_iRuneStatus ); + MESSAGE_END(); +} + + +void CResistRune::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; + + //Only one per customer + if ( ((CBasePlayer *)pOther)->m_iRuneStatus ) + { + ClientPrint( pOther->pev, HUD_PRINTCENTER, "You already have a rune!\n" ); + return; + } + + if ( !m_bTouchable ) + return; + + ((CBasePlayer *)pOther)->m_iRuneStatus = m_iRuneFlag; //Add me the rune flag + + ClientPrint( pOther->pev, HUD_PRINTCENTER, "You got the rune of Resistance!\n" ); + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Found_ResistRune\"\n", + STRING(pOther->pev->netname), + GETPLAYERUSERID( pOther->edict() ), + GETPLAYERAUTHID( pOther->edict() ), + ((CBasePlayer *)pOther)->m_szTeamName ); + + 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( ((CBasePlayer *)pOther)->m_iRuneStatus ); + MESSAGE_END(); + + //And Remove this entity + UTIL_Remove( this ); +} + + +void CResistRune::RuneRespawn ( void ) +{ + edict_t *pentSpawnSpot; + vec3_t vOrigin; + + pentSpawnSpot = RuneSelectSpawnPoint(); + vOrigin = VARS(pentSpawnSpot)->origin; + + UTIL_SetOrigin( pev, vOrigin ); + + if ( dropped ) + UTIL_LogPrintf( "\"<-1><><>\" triggered triggered \"Respawn_ResistRune\"\n" ); + + Spawn(); +} + +void CResistRune::MakeTouchable ( void ) +{ + 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 ( RuneRespawn ); +} + +void CResistRune::Spawn ( void ) +{ + SET_MODEL( ENT(pev), "models/rune_resist.mdl"); + + m_bTouchable = FALSE; + + m_iRuneFlag = ITEM_RUNE1_FLAG; + + dropped = false; + + pev->movetype = MOVETYPE_TOSS; + pev->solid = SOLID_TRIGGER; + + vec3_t forward, right, up; + + 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 ) + g_engfuncs.pfnAngleVectors ( pev->owner->v.angles, forward, right, up ); + else + g_engfuncs.pfnAngleVectors ( pev->angles, 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( RuneTouch ); + + pev->nextthink = gpGlobals->time + 1; + SetThink ( MakeTouchable ); +} + + +LINK_ENTITY_TO_CLASS( item_rune1, CResistRune ); + + +void CStrengthRune::MakeTouchable ( void ) +{ + 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 ( RuneRespawn ); +} + +void CStrengthRune::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; + + //Only one per customer + if ( ((CBasePlayer *)pOther)->m_iRuneStatus ) + { + ClientPrint( pOther->pev, HUD_PRINTCENTER, "You already have a rune!\n" ); + return; + } + + if ( !m_bTouchable ) + return; + + ((CBasePlayer *)pOther)->m_iRuneStatus = m_iRuneFlag; //Add me the rune flag + + ClientPrint( pOther->pev, HUD_PRINTCENTER, "You got the rune of Strength!\n" ); + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Found_StrengthRune\"\n", + STRING(pOther->pev->netname), + GETPLAYERUSERID( pOther->edict() ), + GETPLAYERAUTHID( pOther->edict() ), + ((CBasePlayer *)pOther)->m_szTeamName ); + + 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( ((CBasePlayer *)pOther)->m_iRuneStatus ); + MESSAGE_END(); + + //And Remove this entity + UTIL_Remove( this ); +} + +void CStrengthRune::RuneRespawn ( void ) +{ + edict_t *pentSpawnSpot; + vec3_t vOrigin; + + pentSpawnSpot = RuneSelectSpawnPoint(); + vOrigin = VARS(pentSpawnSpot)->origin; + + UTIL_SetOrigin( pev, vOrigin ); + + if ( dropped ) + UTIL_LogPrintf( "\"<-1><><>\" triggered triggered \"Respawn_StrengthRune\"\n" ); + + Spawn(); +} + + +void CStrengthRune::Spawn ( void ) +{ + SET_MODEL( ENT(pev), "models/rune_strength.mdl"); + + m_bTouchable = FALSE; + + m_iRuneFlag = ITEM_RUNE2_FLAG; + + dropped = false; + + pev->movetype = MOVETYPE_TOSS; + pev->solid = SOLID_TRIGGER; + + vec3_t forward, right, up; + + 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 ) + g_engfuncs.pfnAngleVectors ( pev->owner->v.angles, forward, right, up); + else + g_engfuncs.pfnAngleVectors ( pev->angles, 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( RuneTouch ); + + pev->nextthink = gpGlobals->time + 1; + SetThink ( MakeTouchable ); +} + + +LINK_ENTITY_TO_CLASS( item_rune2, CStrengthRune ); + +void CHasteRune::MakeTouchable ( void ) +{ + 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 ( RuneRespawn ); +} + + +void CHasteRune::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; + + //Only one per customer + if ( ((CBasePlayer *)pOther)->m_iRuneStatus ) + { + ClientPrint( pOther->pev, HUD_PRINTCENTER, "You already have a rune!\n" ); + return; + } + + if ( !m_bTouchable ) + return; + + ((CBasePlayer *)pOther)->m_iRuneStatus = m_iRuneFlag; //Add me the rune flag + + ClientPrint( pOther->pev, HUD_PRINTCENTER, "You got the rune of Haste!\n" ); + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Found_HasteRune\"\n", + STRING(pOther->pev->netname), + GETPLAYERUSERID( pOther->edict() ), + GETPLAYERAUTHID( pOther->edict() ), + ((CBasePlayer *)pOther)->m_szTeamName ); + + g_engfuncs.pfnSetClientMaxspeed( ENT( pOther->pev ), ( PLAYER_MAX_SPEED * 1.25 ) ); //25% more speed + + 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( ((CBasePlayer *)pOther)->m_iRuneStatus ); + MESSAGE_END(); + + //And Remove this entity + UTIL_Remove( this ); +} + +void CHasteRune::RuneRespawn ( void ) +{ + edict_t *pentSpawnSpot; + vec3_t vOrigin; + + pentSpawnSpot = RuneSelectSpawnPoint(); + vOrigin = VARS(pentSpawnSpot)->origin; + + UTIL_SetOrigin( pev, vOrigin ); + + if ( dropped ) + UTIL_LogPrintf( "\"<-1><><>\" triggered triggered \"Respawn_HasteRune\"\n" ); + + Spawn(); +} + + +void CHasteRune::Spawn ( void ) +{ + SET_MODEL( ENT(pev), "models/rune_haste.mdl"); + + m_bTouchable = FALSE; + + m_iRuneFlag = ITEM_RUNE3_FLAG; + + dropped = false; + + pev->movetype = MOVETYPE_TOSS; + pev->solid = SOLID_TRIGGER; + + vec3_t forward, right, up; + + 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 ) + g_engfuncs.pfnAngleVectors ( pev->owner->v.angles, forward, right, up); + else + g_engfuncs.pfnAngleVectors ( pev->angles, 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( 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 ( MakeTouchable ); +} + + +LINK_ENTITY_TO_CLASS( item_rune3, CHasteRune ); + + +void CRegenRune::MakeTouchable ( void ) +{ + 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 ( RuneRespawn ); +} + +void CRegenRune::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; + + //Only one per customer + if ( ((CBasePlayer *)pOther)->m_iRuneStatus ) + { + ClientPrint( pOther->pev, HUD_PRINTCENTER, "You already have a rune!\n" ); + return; + } + + if ( !m_bTouchable ) + return; + + ((CBasePlayer *)pOther)->m_iRuneStatus = m_iRuneFlag; //Add me the rune flag + + ClientPrint( pOther->pev, HUD_PRINTCENTER, "You got the rune of Regeneration!\n" ); + + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"Found_RegenRune\"\n", + STRING(pOther->pev->netname), + GETPLAYERUSERID( pOther->edict() ), + GETPLAYERAUTHID( pOther->edict() ), + ((CBasePlayer *)pOther)->m_szTeamName ); + + 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( ((CBasePlayer *)pOther)->m_iRuneStatus ); + MESSAGE_END(); + + //And Remove this entity + UTIL_Remove( this ); +} + +void CRegenRune::RuneRespawn ( void ) +{ + edict_t *pentSpawnSpot; + vec3_t vOrigin; + + pentSpawnSpot = RuneSelectSpawnPoint(); + vOrigin = VARS(pentSpawnSpot)->origin; + + UTIL_SetOrigin( pev, vOrigin ); + + if ( dropped ) + UTIL_LogPrintf( "\"<-1><><>\" triggered triggered \"Respawn_RegenRune\"\n" ); + + Spawn(); +} + + +void CRegenRune::Spawn ( void ) +{ + + SET_MODEL( ENT(pev), "models/rune_regen.mdl" ); + + m_bTouchable = FALSE; + + m_iRuneFlag = ITEM_RUNE4_FLAG; + + dropped = false; + + pev->movetype = MOVETYPE_TOSS; + pev->solid = SOLID_TRIGGER; + + vec3_t forward, right, up; + + 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 ) + g_engfuncs.pfnAngleVectors ( pev->owner->v.angles, forward, right, up); + else + g_engfuncs.pfnAngleVectors ( pev->angles, 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( 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 ( MakeTouchable ); +} + + +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( void ) +{ + 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; +} + + +/*********************************************** +************************************************ + GRAPPLE +************************************************ +***********************************************/ + +void CGrapple::Reset_Grapple ( void ) +{ + CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner ); + + ((CBasePlayer *)pOwner)->m_bOn_Hook = FALSE; + ((CBasePlayer *)pOwner)->m_bHook_Out = FALSE; + + PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, + ((CBasePlayer *)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( ((CBasePlayer *)pOwner)->edict(), CHAN_WEAPON, "weapons/grfire.wav" ); + STOP_SOUND( ((CBasePlayer *)pOwner)->edict(), CHAN_WEAPON, "weapons/grpull.wav" ); + + ((CBasePlayer *)pOwner)->m_ppHook = NULL; + pev->enemy = NULL; + + UTIL_Remove ( this ); +} + +void CGrapple::GrappleTouch ( CBaseEntity *pOther ) +{ + CBaseEntity *pOwner = 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 ( FClassnameIs( pOther->pev, "grenade" )|| + FClassnameIs( pOther->pev, "spike" ) || + FClassnameIs( pOther->pev, "hook" ) ) + return; + + if ( FClassnameIs( pOther->pev, "player" ) ) + { + // 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 = Vector(0,0,0); + UTIL_SetOrigin( pev, pOther->pev->origin); + } + else if ( !FClassnameIs( pOther->pev, "player" ) ) + { + // 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 = Vector(0,0,0); + + 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 ( ((CBasePlayer*)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'); + } + + ((CBasePlayer*)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( ((CBasePlayer *)pOwner)->edict(), CHAN_WEAPON, "weapons/grfire.wav" ); + + pev->enemy = pOther->edict();// remember this guy! + SetThink ( 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 ( void ) +{ + CBaseEntity *pOwner = CBaseEntity::Instance( pev->owner ); + CBaseEntity *pEnemy = CBaseEntity::Instance( pev->enemy ); + + // Release dead targets + if ( FClassnameIs( pEnemy->pev, "player" ) && pEnemy->pev->health <= 0) + Reset_Grapple(); + + + // drop the hook if owner is dead or has released the button + if ( !((CBasePlayer*)pOwner)->m_bOn_Hook|| ((CBasePlayer*)pOwner)->pev->health <= 0) + { + Reset_Grapple(); + return; + } + + if ( !(pOwner->pev->button & IN_ATTACK) ) + { + if ( ((CBasePlayer*)pOwner)->m_iQuakeWeapon == IT_EXTRA_WEAPON ) + { + Reset_Grapple(); + return; + } + } + + // bring the pAiN! + if ( FClassnameIs( pEnemy->pev, "player" ) ) + { + 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. + if ( !FClassnameIs( pEnemy->pev, "player" ) ) + pev->velocity = pEnemy->pev->velocity; + + pev->nextthink = gpGlobals->time + 0.1; +}; + +void CBasePlayer::Service_Grapple ( void ) +{ + 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 ) + { + ((CGrapple *)m_ppHook)->Reset_Grapple(); + return; + } + } + + if ( m_ppHook->pev->enemy != NULL ) + { + // If hooked to a player, track them directly! + if ( FClassnameIs( pEnemy->pev, "player" ) ) + { + pEnemy = CBaseEntity::Instance( pev->enemy ); + hook_dir = ( pEnemy->pev->origin - pev->origin ); + } + // else, track to hook + else if ( !FClassnameIs( pEnemy->pev, "player" ) ) + hook_dir = ( m_ppHook->pev->origin - pev->origin ); + + pev->velocity = ( (hook_dir).Normalize() * 750 ); + pev->speed = 750; + + if ( ((CGrapple *)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); + + ((CGrapple *)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 ( ((CGrapple *)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); + ((CGrapple *)m_ppHook)->m_flNextIdleTime = gpGlobals->time + RANDOM_LONG( 1, 3 ); + } + + } +}; + +void CGrapple::OnAirThink ( void ) +{ + 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 ( void ) +{ + pev->movetype = MOVETYPE_FLYMISSILE; + pev->solid = SOLID_BBOX; + + SET_MODEL ( ENT(pev),"models/hook.mdl"); + + SetTouch ( GrappleTouch ); + SetThink ( OnAirThink ); + + pev->nextthink = gpGlobals->time + 0.1; +} + +LINK_ENTITY_TO_CLASS( hook, CGrapple ); + +void CBasePlayer::Throw_Grapple ( void ) +{ + if ( m_bHook_Out ) + return; + + CBaseEntity *pHookCBEnt = NULL; + + pHookCBEnt = 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, Vector(0,0,0) , Vector(0,0,0) ); + + 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; + } +}; diff --git a/dlls/3wave/threewave_gamerules.h b/dlls/3wave/threewave_gamerules.h new file mode 100644 index 00000000..450a2d8c --- /dev/null +++ b/dlls/3wave/threewave_gamerules.h @@ -0,0 +1,232 @@ +/*** +* +* 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. +* +****/ + +#define BLUE 2 +#define RED 1 + + +#include "voice_gamemgr.h" + + + +//========================================================= +// Flags +//========================================================= +class CItemFlag : public CBaseEntity +{ +public: + void Spawn( void ); + + BOOL Dropped; + float m_flDroppedTime; + + void EXPORT FlagThink( void ); + +private: + void Precache ( void ); + void Capture(CBasePlayer *pPlayer, int iTeam ); + void ResetFlag( int iTeam ); + void Materialize( void ); + void EXPORT FlagTouch( CBaseEntity *pOther ); + // BOOL MyTouch( CBasePlayer *pPlayer ); + +}; + +class CCarriedFlag : public CBaseEntity +{ +public: + void Spawn( void ); + + CBasePlayer *Owner; + + int m_iOwnerOldVel; + +private: + void Precache ( void ); + void EXPORT FlagThink( void ); +}; + + +class CResistRune : public CBaseEntity +{ +private: + + void EXPORT RuneRespawn ( void ); + +public: + + void EXPORT RuneTouch ( CBaseEntity *pOther ); + void Spawn( void ); + + void EXPORT MakeTouchable ( void ); + + int m_iRuneFlag; + bool m_bTouchable; + bool dropped; +}; + +class CStrengthRune : public CBaseEntity +{ + +private: + void EXPORT RuneRespawn ( void ); + +public: + + void EXPORT RuneTouch ( CBaseEntity *pOther ); + void Spawn( void ); + + void EXPORT MakeTouchable ( void ); + + int m_iRuneFlag; + bool m_bTouchable; + bool dropped; +}; + + +class CHasteRune : public CBaseEntity +{ + +private: + void EXPORT RuneRespawn ( void ); +public: + + void EXPORT RuneTouch ( CBaseEntity *pOther ); + + void EXPORT MakeTouchable ( void ); + void Spawn( void ); + + int m_iRuneFlag; + bool m_bTouchable; + bool dropped; +}; + + +class CRegenRune : public CBaseEntity +{ + +private: + void EXPORT RuneRespawn ( void ); + +public: + + void EXPORT RuneTouch ( CBaseEntity *pOther ); + void Spawn( void ); + + void EXPORT MakeTouchable ( void ); + + int m_iRuneFlag; + bool m_bTouchable; + bool dropped; +}; + +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 ( void ); + void EXPORT OnAirThink ( void ); + void EXPORT GrappleTouch ( CBaseEntity *pOther ); + void Reset_Grapple ( void ); + void EXPORT Grapple_Track ( void ); + + float m_flNextIdleTime; + +}; + + + +#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 + + +#define MAX_TEAMNAME_LENGTH 16 +#define MAX_TEAMS 32 + +#define TEAMPLAY_TEAMLISTLENGTH MAX_TEAMS*MAX_TEAMNAME_LENGTH + +class CThreeWave : public CHalfLifeMultiplay +{ +public: + CThreeWave(); + + virtual BOOL ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ); + virtual BOOL ClientCommand( CBasePlayer *pPlayer, const char *pcmd ); + virtual void ClientUserInfoChanged( CBasePlayer *pPlayer, char *infobuffer ); + virtual BOOL IsTeamplay( void ); + virtual BOOL FPlayerCanTakeDamage( CBasePlayer *pPlayer, CBaseEntity *pAttacker ); + virtual int PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ); + virtual const char *GetTeamID( CBaseEntity *pEntity ); + virtual BOOL ShouldAutoAim( CBasePlayer *pPlayer, edict_t *target ); + virtual int IPointsForKill( CBasePlayer *pAttacker, CBasePlayer *pKilled ); + virtual void InitHUD( CBasePlayer *pl ); + virtual void DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pevInflictor ); + virtual const char *GetGameDescription( void ) { return "3Wave CTF"; } // this is the game name that gets seen in the server browser + virtual void UpdateGameMode( CBasePlayer *pPlayer ); // the client needs to be informed of the current game mode + virtual void PlayerKilled( CBasePlayer *pVictim, entvars_t *pKiller, entvars_t *pInflictor ); + virtual void Think ( void ); + virtual int GetTeamIndex( const char *pTeamName ); + virtual const char *GetIndexedTeamName( int teamIndex ); + virtual BOOL IsValidTeam( const char *pTeamName ); + virtual void ChangePlayerTeam( CBasePlayer *pPlayer, int iTeam ); + virtual void PlayerSpawn( CBasePlayer *pPlayer ); + void JoinTeam ( CBasePlayer *pPlayer, int iTeam ); + int TeamWithFewestPlayers ( void ); + virtual void ClientDisconnected( edict_t *pClient ); + void GetFlagStatus( CBasePlayer *pPlayer ); + + virtual edict_t *GetPlayerSpawnSpot( CBasePlayer *pPlayer ); + + virtual void PlayerThink( CBasePlayer *pPlayer ); + + void PlayerTakeDamage( CBasePlayer *pPlayer , CBaseEntity *pAttacker ); + + int iBlueFlagStatus; + int iRedFlagStatus; + + int iBlueTeamScore; + int iRedTeamScore; + + float m_flFlagStatusTime; + +private: + void RecountTeams( void ); + + BOOL m_DisableDeathMessages; + BOOL m_DisableDeathPenalty; + BOOL m_teamLimit; // This means the server set only some teams as valid + char m_szTeamList[TEAMPLAY_TEAMLISTLENGTH]; +}; diff --git a/dlls/CMakeLists.txt b/dlls/CMakeLists.txt index 2764a824..8a6fba3f 100644 --- a/dlls/CMakeLists.txt +++ b/dlls/CMakeLists.txt @@ -37,6 +37,7 @@ else() endif() set (SVDLL_SOURCES + 3wave/threewave_gamerules.cpp aghl/agarena.cpp aghl/agglobal.cpp aghl/aglms.cpp @@ -151,7 +152,7 @@ set (SVDLL_SOURCES ../pm_shared/pm_shared.c ) -include_directories (. wpn_shared ../common ../engine ../pm_shared ../game_shared ../public dmc aghl .. ) +include_directories (. wpn_shared ../common ../engine ../pm_shared ../game_shared ../public dmc aghl 3wave .. ) if(USE_VOICEMGR) set(SVDLL_SOURCES diff --git a/dlls/client.cpp b/dlls/client.cpp index e523111f..229d30f7 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -50,6 +50,8 @@ extern DLL_GLOBAL BOOL g_fGameOver; extern DLL_GLOBAL int g_iSkillLevel; extern DLL_GLOBAL ULONG g_ulFrameCount; +const char* GetTeamName( int team ); + extern bool g_bHaveMOTD; extern void CopyToBodyQue( entvars_t* pev ); @@ -65,6 +67,11 @@ extern unsigned short g_sTrail; extern unsigned short g_sExplosion; extern unsigned short g_usPowerUp; +extern unsigned short g_usHook; +extern unsigned short g_usCable; +extern unsigned short g_usCarried; +extern unsigned short g_usFlagSpawn; + extern int g_teamplay; extern cvar_t bhopcap; @@ -217,6 +224,8 @@ void ClientPutInServer( edict_t *pEntity ) pPlayer->pev->iuser2 = 0; } +#include "threewave_gamerules.h" + #ifndef NO_VOICEGAMEMGR #include "voice_gamemgr.h" extern CVoiceGameMgr g_VoiceGameMgr; @@ -444,7 +453,14 @@ void Host_Say( edict_t *pEntity, int teamonly ) temp = "say"; // team match? - if( g_teamplay ) + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" %s \"%s\"\n", + STRING( pEntity->v.netname ), + GETPLAYERUSERID( pEntity ), + GETPLAYERAUTHID( pEntity ), + GetTeamName( pEntity->v.team ), + temp, + p ); + /*if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" %s \"%s\"\n", STRING( pEntity->v.netname ), @@ -463,7 +479,7 @@ void Host_Say( edict_t *pEntity, int teamonly ) GETPLAYERUSERID( pEntity ), temp, p ); - } + }*/ } /* @@ -548,7 +564,7 @@ void ClientCommand( edict_t *pEntity ) //-- Martin Webrant pPlayer->m_bHadFirstSpawn = true; - pPlayer->Spawn(); + // pPlayer->Spawn(); } } else if( FStrEq( pcmd, "lastinv" ) ) @@ -819,6 +835,13 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) } // team match? + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed name to \"%s\"\n", + STRING( pEntity->v.netname ), + GETPLAYERUSERID( pEntity ), + GETPLAYERAUTHID( pEntity ), + GetTeamName( pEntity->v.team ), + g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); + /* if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed name to \"%s\"\n", @@ -836,7 +859,7 @@ void ClientUserInfoChanged( edict_t *pEntity, char *infobuffer ) GETPLAYERAUTHID( pEntity ), GETPLAYERUSERID( pEntity ), g_engfuncs.pfnInfoKeyValue( infobuffer, "name" ) ); - } + }*/ } // QUAKECLASSIC @@ -1105,6 +1128,32 @@ void ClientPrecache( void ) PRECACHE_SOUND( "player/plyrjmp8.wav" ); + PRECACHE_MODEL( "models/rune_resist.mdl" ); + PRECACHE_MODEL( "models/rune_haste.mdl" ); + PRECACHE_MODEL( "models/rune_regen.mdl" ); + PRECACHE_MODEL( "models/rune_strength.mdl" ); + + PRECACHE_SOUND( "rune/rune1.wav" ); + PRECACHE_SOUND( "rune/rune2.wav" ); + PRECACHE_SOUND( "rune/rune22.wav" ); // Quad + Strength Rune. + PRECACHE_SOUND( "rune/rune3.wav" ); + PRECACHE_SOUND( "rune/rune4.wav" ); + + PRECACHE_MODEL( "models/hook.mdl" ); + + PRECACHE_MODEL( "sprites/rope.spr" ); + + PRECACHE_SOUND( "weapons/grfire.wav" ); + PRECACHE_SOUND( "weapons/grhang.wav" ); + PRECACHE_SOUND( "weapons/grhit.wav" ); + PRECACHE_SOUND( "weapons/grpull.wav" ); + PRECACHE_SOUND( "weapons/grreset.wav" ); + + g_usHook = PRECACHE_EVENT( 1, "events/hook.sc" ); + g_usCable = PRECACHE_EVENT( 1, "events/cable.sc" ); + g_usCarried = PRECACHE_EVENT( 1, "events/follow.sc" ); + g_usFlagSpawn = PRECACHE_EVENT( 1, "events/flagspawn.sc" ); + ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_crowbar.mdl" ); ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_light.mdl" ); ENGINE_FORCE_UNMODIFIED( force_exactfile, Vector( 0, 0, 0 ), Vector( 0, 0, 0 ), "models/p_nail.mdl" ); @@ -1994,6 +2043,7 @@ void UpdateClientData( const struct edict_s *ent, int sendweapons, struct client cd->fuser1 = (float)pl->m_iQuakeWeapon; cd->iuser4 = gpGlobals->deathmatch; cd->fuser2 = pl->m_iNailOffset > 0 ? 1.0 : 0.0; + cd->fuser3 = (float)pl->m_iRuneStatus; cd->iuser3 = pl->m_iQuakeItems; diff --git a/dlls/dmc/quake_weapons_all.cpp b/dlls/dmc/quake_weapons_all.cpp index feb7116c..9c43e35a 100644 --- a/dlls/dmc/quake_weapons_all.cpp +++ b/dlls/dmc/quake_weapons_all.cpp @@ -31,6 +31,10 @@ char gszQ_DeathType[128]; DLL_GLOBAL short g_sModelIndexNail; +extern unsigned short g_usHook; +extern unsigned short g_usCable; +extern unsigned short g_usCarried; + #ifdef CLIENT_DLL #include "cl_entity.h" struct cl_entity_s *GetViewEntity( void ); @@ -105,6 +109,8 @@ void QuakeClassicPrecache( void ) PRECACHE_SOUND("weapons/pkup.wav"); PRECACHE_SOUND("items/itembk2.wav"); PRECACHE_MODEL("models/backpack.mdl"); + + PRECACHE_MODEL("models/v_grapple.mdl"); } //================================================================================================ @@ -208,6 +214,13 @@ void CBasePlayer::W_SetCurrentAmmo( int sendanim /* = 1 */ ) m_iQuakeItems |= IT_CELLS; szAnimExt = "gauss"; } + else if( m_iQuakeWeapon == IT_EXTRA_WEAPON ) + { + m_pCurrentAmmo = NULL; + viewmodel = "models/v_grapple.mdl"; + iszViewModel = MAKE_STRING( viewmodel ); + szAnimExt = "crowbar"; + } else { m_pCurrentAmmo = NULL; @@ -298,6 +311,9 @@ BOOL CBasePlayer::W_CheckNoAmmo() if ( m_iQuakeWeapon == IT_AXE ) return TRUE; + if( m_iQuakeWeapon == IT_EXTRA_WEAPON ) + return TRUE; + if ( m_iQuakeWeapon == IT_LIGHTNING ) { PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usLightning, 0, (float *)&pev->origin, (float *)&pev->angles, 0.0, 0.0, 0, 1, 0, 0 ); @@ -372,6 +388,10 @@ void CBasePlayer::W_ChangeWeapon( int iWeaponNumber ) if (m_iAmmoCells < 1) bHaveAmmo = FALSE; } + else if (iWeaponNumber == 9) + { + iWeapon = IT_EXTRA_WEAPON; + } // Have the weapon? if ( !(m_iQuakeItems & iWeapon) ) @@ -745,6 +765,23 @@ void CBasePlayer::W_FireShotgun( int iQuadSound ) Q_FireBullets(6, vecDir, Vector(0.04, 0.04, 0) ); } +void CBasePlayer::W_FireHook( void ) +{ + PLAYBACK_EVENT_FULL( FEV_NOTHOST | FEV_GLOBAL, edict(), g_usHook, 0, (float *)&pev->origin, (float *)&pev->angles, 0.0, 0.0, 0, 0, 0, 0 ); + + Throw_Grapple(); +} + +#ifdef CLIENT_DLL +unsigned short g_usCable; +unsigned short g_usHook; +unsigned short g_usCarried; + +void CBasePlayer::Throw_Grapple( void ) +{ +} +#endif + // Double barrel shotgun void CBasePlayer::W_FireSuperShotgun( int iQuadSound ) { @@ -935,7 +972,10 @@ void CBasePlayer::W_Attack( int iQuadSound ) if (m_iQuakeWeapon == IT_AXE) { - m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + if( m_iRuneStatus == ITEM_RUNE3_FLAG ) + m_flNextAttack = UTIL_WeaponTimeBase() + 0.3; + else + m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; PLAYBACK_EVENT_FULL( FEV_NOTHOST, edict(), m_usAxeSwing, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, iQuadSound, 0, 0, 0 ); @@ -947,18 +987,24 @@ void CBasePlayer::W_Attack( int iQuadSound ) } else if (m_iQuakeWeapon == IT_SHOTGUN) { - m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + if( m_iRuneStatus == ITEM_RUNE3_FLAG ) + m_flNextAttack = UTIL_WeaponTimeBase() + 0.3; + else + m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; W_FireShotgun( iQuadSound ); } else if (m_iQuakeWeapon == IT_SUPER_SHOTGUN) { - m_flNextAttack = UTIL_WeaponTimeBase() + 0.7; + if( m_iRuneStatus == ITEM_RUNE3_FLAG ) + m_flNextAttack = UTIL_WeaponTimeBase() + 0.4; + else + m_flNextAttack = UTIL_WeaponTimeBase() + 0.7; W_FireSuperShotgun( iQuadSound ); } else if (m_iQuakeWeapon == IT_NAILGUN) - { + { m_flNextAttack = UTIL_WeaponTimeBase() + 0.1; W_FireSpikes( iQuadSound ); @@ -970,13 +1016,19 @@ void CBasePlayer::W_Attack( int iQuadSound ) } else if (m_iQuakeWeapon == IT_GRENADE_LAUNCHER) { - m_flNextAttack = UTIL_WeaponTimeBase() + 0.6; + if( m_iRuneStatus == ITEM_RUNE3_FLAG ) + m_flNextAttack = UTIL_WeaponTimeBase() + 0.3; + else + m_flNextAttack = UTIL_WeaponTimeBase() + 0.6; W_FireGrenade( iQuadSound ); } else if (m_iQuakeWeapon == IT_ROCKET_LAUNCHER) { - m_flNextAttack = UTIL_WeaponTimeBase() + 0.8; + if( m_iRuneStatus == ITEM_RUNE3_FLAG ) + m_flNextAttack = UTIL_WeaponTimeBase() + 0.4; + else + m_flNextAttack = UTIL_WeaponTimeBase() + 0.8; W_FireRocket( iQuadSound ); } @@ -990,6 +1042,13 @@ void CBasePlayer::W_Attack( int iQuadSound ) W_FireLightning( iQuadSound ); } + else if( m_iQuakeWeapon == IT_EXTRA_WEAPON ) + { + if( !m_bHook_Out ) + W_FireHook(); + + m_flNextAttack = UTIL_WeaponTimeBase() + 0.1; + } // Make player attack if ( pev->health >= 0 ) diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 55564e85..83c612aa 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -42,6 +42,8 @@ extern int g_teamplay; bool g_bHaveMOTD; +const char *GetTeamName( int team ); + #define INTERMISSION_TIME 60 #define ITEM_RESPAWN_TIME 30 #define WEAPON_RESPAWN_TIME 20 @@ -467,6 +469,12 @@ void CHalfLifeMultiplay::InitHUD( CBasePlayer *pl ) ( pl->pev->netname && ( STRING( pl->pev->netname ) )[0] != 0 ) ? STRING( pl->pev->netname ) : "unconnected" ) ); // team match? + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" entered the game\n", + STRING( pl->pev->netname ), + GETPLAYERUSERID( pl->edict() ), + GETPLAYERAUTHID( pl->edict() ), + GetTeamName( pl->pev->team ) ); + /* if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" entered the game\n", @@ -482,7 +490,7 @@ void CHalfLifeMultiplay::InitHUD( CBasePlayer *pl ) GETPLAYERUSERID( pl->edict() ), GETPLAYERAUTHID( pl->edict() ), GETPLAYERUSERID( pl->edict() ) ); - } + }*/ UpdateGameMode( pl ); @@ -543,7 +551,13 @@ void CHalfLifeMultiplay::ClientDisconnected( edict_t *pClient ) FireTargets( "game_playerleave", pPlayer, pPlayer, USE_TOGGLE, 0 ); // team match? - if( g_teamplay ) + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" disconnected\n", + STRING( pPlayer->pev->netname ), + GETPLAYERUSERID( pPlayer->edict() ), + GETPLAYERAUTHID( pPlayer->edict() ), + GetTeamName( pPlayer->pev->team ) ); + + /*if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" disconnected\n", STRING( pPlayer->pev->netname ), @@ -558,7 +572,7 @@ void CHalfLifeMultiplay::ClientDisconnected( edict_t *pClient ) GETPLAYERUSERID( pPlayer->edict() ), GETPLAYERAUTHID( pPlayer->edict() ), GETPLAYERUSERID( pPlayer->edict() ) ); - } + }*/ pPlayer->RemoveAllItems( TRUE );// destroy all of the players weapons and items } @@ -856,6 +870,13 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, // killed self // team match? + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n", + STRING( pVictim->pev->netname ), + GETPLAYERUSERID( pVictim->edict() ), + GETPLAYERAUTHID( pVictim->edict() ), + GetTeamName( pVictim->pev->team ), + killer_weapon_name ); + /* if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n", @@ -873,12 +894,22 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, GETPLAYERAUTHID( pVictim->edict() ), GETPLAYERUSERID( pVictim->edict() ), killer_weapon_name ); - } + }*/ } else if( pKiller->flags & FL_CLIENT ) { // team match? - if( g_teamplay ) + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n", + STRING( pKiller->netname ), + GETPLAYERUSERID( ENT(pKiller) ), + GETPLAYERAUTHID( ENT(pKiller) ), + GetTeamName( pKiller->team ), + STRING( pVictim->pev->netname ), + GETPLAYERUSERID( pVictim->edict() ), + GETPLAYERAUTHID( pVictim->edict() ), + GetTeamName( pVictim->pev->team ), + killer_weapon_name ); + /*if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n", STRING( pKiller->netname ), @@ -903,14 +934,21 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, GETPLAYERAUTHID( pVictim->edict() ), GETPLAYERUSERID( pVictim->edict() ), killer_weapon_name ); - } + }*/ } else { // killed by the world // team match? - if( g_teamplay ) + UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\" (world)\n", + STRING( pVictim->pev->netname ), + GETPLAYERUSERID( pVictim->edict() ), + GETPLAYERAUTHID( pVictim->edict() ), + GetTeamName( pVictim->pev->team ), + killer_weapon_name ); + + /*if( g_teamplay ) { UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\" (world)\n", STRING( pVictim->pev->netname ), @@ -927,7 +965,7 @@ void CHalfLifeMultiplay::DeathNotice( CBasePlayer *pVictim, entvars_t *pKiller, GETPLAYERAUTHID( pVictim->edict() ), GETPLAYERUSERID( pVictim->edict() ), killer_weapon_name ); - } + }*/ } MESSAGE_BEGIN( MSG_SPEC, SVC_DIRECTOR ); diff --git a/dlls/player.h b/dlls/player.h index 780779cc..9854beb2 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -71,6 +71,11 @@ typedef enum PLAYER_ATTACK1 } PLAYER_ANIM; +enum Player_Menu { + Team_Menu, + Team_Menu_IG +}; + #define MAX_ID_RANGE 2048 #define SBAR_STRING_SIZE 128 @@ -441,6 +446,35 @@ public: bool Spectate_HLTV(); bool m_bSentBhopcap; // If false, the player just joined and needs a bhopcap message. //-- Martin Webrant + + int m_bHasFlag; + void ShowMenu( int bitsValidSlots, int nDisplayTime, BOOL fNeedMore, char *pszText ); + int m_iMenu; + + float m_flNextTeamChange; + + CBasePlayer *pFlagCarrierKiller; + CBasePlayer *pFlagReturner; + CBasePlayer *pCarrierHurter; + + float m_flCarrierHurtTime; + float m_flCarrierPickupTime; + float m_flFlagCarrierKillTime; + float m_flFlagReturnTime; + float m_flFlagStatusTime; + + float m_flRegenTime; + + int m_iRuneStatus; + + void W_FireHook(); + void Throw_Grapple(); + + bool m_bHook_Out; + bool m_bOn_Hook; + CBaseEntity *m_ppHook; + + void Service_Grapple(); }; //++ BulliT @@ -513,6 +547,11 @@ inline bool CBasePlayer::IsProxy() #define IT_SUIT (1 << 21) #define IT_QUAD (1 << 22) +#define ITEM_RUNE1_FLAG 1 +#define ITEM_RUNE2_FLAG 2 +#define ITEM_RUNE3_FLAG 3 +#define ITEM_RUNE4_FLAG 4 + #define AUTOAIM_2DEGREES 0.0348994967025 #define AUTOAIM_5DEGREES 0.08715574274766 #define AUTOAIM_8DEGREES 0.1391731009601