/*** * * 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. */ #ifdef THREEWAVE #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; } }; #endif