From b55f4aeeb0787a82a462990e0ccedfcdabe3fe07 Mon Sep 17 00:00:00 2001 From: mittorn Date: Thu, 25 Oct 2018 04:51:23 +0700 Subject: [PATCH] Get rid of old SavedCoords struct, rewrite transition code to new system --- dlls/coop.cpp | 182 ++++++++------------------- dlls/coop_util.h | 37 ++---- dlls/gamerules.cpp | 45 ------- dlls/gravgunmod.cpp | 13 +- dlls/gravgunmod.h | 2 +- dlls/multiplay_gamerules.cpp | 41 +++--- dlls/player.cpp | 9 +- dlls/triggers.cpp | 234 +++++++++++++++++------------------ 8 files changed, 212 insertions(+), 351 deletions(-) diff --git a/dlls/coop.cpp b/dlls/coop.cpp index 52f34619..2c127fc8 100644 --- a/dlls/coop.cpp +++ b/dlls/coop.cpp @@ -5,9 +5,6 @@ #include "coop_util.h" #include "gravgunmod.h" - -struct SavedCoords g_SavedCoords, s_SavedCoords; - static float msglimittime1, msglimittime2; cvar_t mp_coop = { "mp_coop", "0", FCVAR_SERVER }; @@ -42,21 +39,6 @@ edict_t *COOP_FindLandmark( const char *pLandmarkName ) return NULL; } - -void COOP_ValidateOffset( void ) -{ - if( !g_SavedCoords.validoffset ) - { - edict_t *landmark = COOP_FindLandmark( g_SavedCoords.landmark ); - if(landmark) - g_SavedCoords.offset = landmark->v.origin - g_SavedCoords.offset; - else - g_SavedCoords.offset = g_vecZero - g_SavedCoords.offset; - g_SavedCoords.validoffset = true; - } -} - - void UTIL_CoopPlayerMessage( CBaseEntity *pPlayer, int channel, float time, unsigned int color1, unsigned int color2, float x, float y, const char *format, ... ) { if( !pPlayer ) @@ -158,57 +140,22 @@ void UTIL_CleanSpawnPoint( Vector origin, float dist ) } -Vector COOP_FixupSpawnPoint(Vector spawn) +Vector COOP_FixupSpawnPoint( Vector vecOrigin, bool fDuck ) { int i = 0; // predict that spawn point is almost correct while( i < 2 ) // 2 player heights { - Vector point = spawn + Vector( 0, 0, 36 * i ); + Vector point = vecOrigin + Vector( 0, 0, 36 * i ); TraceResult tr; - UTIL_TraceHull( point, point, ignore_monsters, (mp_unduck.value&&g_fSavedDuck)?head_hull:human_hull, NULL, &tr ); + UTIL_TraceHull( point, point, ignore_monsters, (mp_unduck.value&&fDuck)?head_hull:human_hull, NULL, &tr ); if( !tr.fStartSolid && !tr.fAllSolid ) return point; i = -i; if( i >= 0 ) i++; } - return spawn; -} - -void UTIL_CoopSaveTrain( CBaseEntity *pPlayer, SavedCoords *coords) -{ - if( coords->trainsaved ) - return; - - CBaseEntity *train = UTIL_CoopGetPlayerTrain(pPlayer); - if( !train ) - { - ALERT( at_console, "^1NO TRAIN!\n"); - return; - } - ALERT( at_console, "^1TRAIN IS %s\n", STRING( train->pev->classname ) ); - - if( !pPlayer->IsPlayer() ) - { - // it is trainnitself, try find player on it - CBaseEntity *pList; - Vector mins = pPlayer->pev->absmin; - Vector maxs = pPlayer->pev->absmax; - maxs.z += 72; - int count = UTIL_EntitiesInBox( &pList, 1, mins, maxs, FL_ONGROUND ); - if( count && pList && pList->IsPlayer() ) - pPlayer = pList; - else - { - ALERT( at_console, "Train without players\n" ); - return; - } - } - - strcpy( coords->trainglobal, STRING(train->pev->globalname) ); - coords->trainoffset = pPlayer->pev->origin - VecBModelOrigin(train->pev); - coords->trainsaved = true; + return vecOrigin; } void UTIL_BecomeSpectator( CBasePlayer *pPlayer ) @@ -247,14 +194,13 @@ void UTIL_SpawnPlayer( CBasePlayer *pPlayer ) } -char * UTIL_CoopPlayerName( CBaseEntity *pPlayer ) +char *UTIL_CoopPlayerName( CBaseEntity *pPlayer ) { if( !pPlayer ) return (char*)"unnamed(NULL)"; return (char*)( ( pPlayer->pev->netname && STRING( pPlayer->pev->netname )[0] != 0 ) ? STRING( pPlayer->pev->netname ) : "unconnected" ); } -bool g_fSavedDuck; char *badlist[256] = { "player", // does not even can set own name @@ -319,29 +265,19 @@ bool UTIL_CoopIsBadPlayer( CBaseEntity *plr ) return false; } - +bool g_fPause; void COOP_ClearData( void ) { - // nullify - SavedCoords l_SavedCoords = {0}; - g_SavedCoords = l_SavedCoords; + g_fPause = false; msglimittime1 = msglimittime2 = 0; } -bool g_fPause; + void COOP_ApplyData( void ) { - if( s_SavedCoords.valid ) - { - struct SavedCoords null1 = {0}; - g_SavedCoords = s_SavedCoords; - s_SavedCoords = null1; - g_fSavedDuck = g_SavedCoords.fDuck; - } - g_fPause = false; ALERT( at_console, "^2CoopApplyData()\n" ); msglimittime1 = msglimittime2 = 0; - + g_fPause = false; } // use this to translate GGMMapOffset during changelevel @@ -351,6 +287,9 @@ struct GGMLandmarkTransition char targetMap[32]; char landmarkName[32]; Vector vecLandmark; + bool fTriggerUsed; + bool fSavedPos; + GGMPosition pos; }; @@ -373,12 +312,43 @@ struct GGMMapState GGMMapState *g_pMapStates; GGMMapState *g_pCurrentMap; GGMLandmarkTransition g_landmarkTransition; +struct GGMCoopState +{ + struct GGMPosition savedPos; + bool fSaved; +} g_CoopState; edict_t *COOP_FindLandmark( const char *pLandmarkName ); + +void COOP_MarkTriggers( void ) +{ + CBaseEntity *pTrigger = NULL; + + while( pTrigger = UTIL_FindEntityByClassname( pTrigger, "trigger_changelevel" ) ) + { + struct COOPChangelevelData *pData = COOP_GetTriggerData( pTrigger ); + pData->fIsBack = !strcmp( pData->pszMapName, g_landmarkTransition.sourceMap ); + // if( gpGlobals->startspot && STRING(gpGlobals->startspot) && !strcmp(STRING(gpGlobals->startspot), m_szLandmarkName) ) + // m_coopData.fIsBack = true; + + pTrigger->pev->renderamt = 127; + pTrigger->pev->effects &= ~EF_NODRAW; + pTrigger->pev->rendermode = kRenderTransColor; + pTrigger->pev->rendercolor = g_vecZero; + if( pData->fIsBack ) + pTrigger->pev->rendercolor.z = 255; + else + pTrigger->pev->rendercolor.y = 255; + } +} + bool COOP_ProcessTransition( void ) { bool fAddCurrent = true; edict_t *landmark; + g_CoopState.savedPos = g_landmarkTransition.pos; + g_CoopState.fSaved = g_landmarkTransition.fSavedPos; + if( !mp_coop.value ) return false; @@ -416,16 +386,22 @@ bool COOP_ProcessTransition( void ) return true; } -void COOP_SetupLandmarkTransition( const char *szNextMap, const char *szNextSpot, Vector vecLandmarkOffset ) +void COOP_SetupLandmarkTransition( const char *szNextMap, const char *szNextSpot, Vector vecLandmarkOffset, struct GGMPosition *pPos ) { strncpy(g_landmarkTransition.sourceMap, STRING(gpGlobals->mapname), 31 ); strncpy(g_landmarkTransition.targetMap, szNextMap, 31 ); strncpy(g_landmarkTransition.landmarkName, szNextSpot, 31 ); g_landmarkTransition.vecLandmark = vecLandmarkOffset; + if( pPos ) + { + g_landmarkTransition.pos = *pPos; + g_landmarkTransition.fSavedPos = true; + } } void COOP_ServerActivate( void ) { + COOP_MarkTriggers(); if( !COOP_ProcessTransition() ) { ALERT( at_console, "Transition failed, new game started\n"); @@ -463,7 +439,7 @@ void COOP_ServerActivate( void ) } } } - g_landmarkTransition.landmarkName[0] = false; + memset( &g_landmarkTransition, 0, sizeof( GGMLandmarkTransition ) ); } bool COOP_GetOrigin( Vector *pvecNewOrigin, const Vector &vecOrigin, const char *pszMapName ) @@ -624,63 +600,13 @@ bool COOP_PlayerDeath( CBasePlayer *pPlayer ) return false; } -bool UTIL_CoopGetSpawnPoint( Vector *origin, Vector *angles) +bool COOP_SetDefaultSpawnPosition( CBasePlayer *pPlayer ) { - if(!g_SavedCoords.valid) + if( !g_CoopState.fSaved ) return false; - - // spawn on elevator or train - if( g_SavedCoords.trainsaved ) - { - CBaseEntity *train = UTIL_FindEntityByString( NULL, "globalname", g_SavedCoords.trainglobal ); - if( !train ) train = UTIL_FindEntityByString( NULL, "classname", g_SavedCoords.trainglobal ); - if( train && ( !g_SavedCoords.trainuser1 || train->pev->iuser1 == g_SavedCoords.trainuser1 ) ) - { - *angles = g_SavedCoords.triggerangles; - *origin = VecBModelOrigin(train->pev) + g_SavedCoords.trainoffset; - g_SavedCoords.trainuser1 = train->pev->iuser1; - return true; - } - ALERT( at_console, "Failed to get train %s (map design error?)\n", g_SavedCoords.trainglobal ); - } - Vector point = g_SavedCoords.triggerorigin; - *angles = g_SavedCoords.triggerangles; - if( !g_SavedCoords.validspawnpoint ) - { - TraceResult tr; - Vector angle; - UTIL_MakeVectorsPrivate( *angles, (float*)&angle, NULL, NULL ); - COOP_ValidateOffset(); - point = point + g_SavedCoords.offset; - //UTIL_TraceHull( point, point, ignore_monsters, human_hull, NULL, &tr ); - - if( mp_unduck.value && g_fSavedDuck && !g_SavedCoords.fUsed ) - UTIL_TraceHull( point, point + angle * 100, missile, head_hull, NULL, &tr ); - else - UTIL_TraceHull( point, point + angle * 100, ignore_monsters, human_hull, NULL, &tr ); - - if( !tr.fStartSolid && !tr.fAllSolid || ENTINDEX( tr.pHit ) && ENTINDEX( tr.pHit ) <= gpGlobals->maxClients ) - { - //g_SavedCoords.triggerorigin = tr.vecEndPos; - //g_SavedCoords.validspawnpoint = true; - if( tr.pHit && FClassnameIs( tr.pHit, "func_door" ) ) - tr.pHit->v.solid = SOLID_NOT; - ALERT( at_console, "CoopGetSpawnPoint: ^2offset set\n"); - - } - else - { - //g_SavedCoords.valid = false; - ALERT( at_console, "CoopGetSpawnPoint: ^2trace failed\n"); - return false; - } - } - *origin = point; - - return true; + return GGM_RestorePosition( pPlayer, &g_CoopState.savedPos ); } - CBaseEntity *UTIL_CoopGetPlayerTrain( CBaseEntity *pPlayer) { CBaseEntity *train = NULL; diff --git a/dlls/coop_util.h b/dlls/coop_util.h index 0d4bae83..7510bf73 100644 --- a/dlls/coop_util.h +++ b/dlls/coop_util.h @@ -1,5 +1,6 @@ #ifndef COOP_UTIL_H #define COOP_UTIL_H +#include "gravgunmod.h" extern cvar_t mp_gravgun_players; extern cvar_t mp_coop; extern cvar_t mp_coop_nofriendlyfire; @@ -20,35 +21,24 @@ extern cvar_t materials_txt; extern bool g_fSavedDuck; extern bool g_fPause; -struct SavedCoords +struct COOPChangelevelData { - char landmark[32]; - Vector triggerorigin; - Vector triggerangles; - Vector offset; - int iCount; - bool valid; - bool validoffset; - bool validspawnpoint; - int changeback; - bool trainsaved; - Vector trainoffset; - char trainglobal[256]; - int trainuser1; + bool fIsBack; + bool fSkipSpawnCheck; + struct GGMPosition savedPosition; + bool fSpawnSaved; bool fUsed; - bool fDuck; + unsigned int bitsTouchCount; + float flRepeatTimer; + const char *pszMapName; + bool fValid; }; - - -void COOP_ValidateOffset( void ); void UTIL_CleanSpawnPoint( Vector origin, float radius ); char *UTIL_CoopPlayerName( CBaseEntity *pPlayer ); -bool UTIL_CoopGetSpawnPoint( Vector *point, Vector *angles); - -void UTIL_CoopSaveTrain( CBaseEntity *pPlayer, SavedCoords *coords); -Vector COOP_FixupSpawnPoint(Vector spawn); +bool COOP_SetDefaultSpawnPosition( CBasePlayer *pPlayer ); +Vector COOP_FixupSpawnPoint( Vector vecOrigin, bool fDuck ); void COOP_ClearData( void ); void COOP_ApplyData( void ); void UTIL_CoopPrintMessage( const char *format, ... ); @@ -83,7 +73,6 @@ public: extern CWeaponList g_WeaponList; -extern struct SavedCoords g_SavedCoords, s_SavedCoords; - +struct COOPChangelevelData *COOP_GetTriggerData( CBaseEntity *pTrigger ); #endif // COOP_UTIL_H diff --git a/dlls/gamerules.cpp b/dlls/gamerules.cpp index 443a3b91..bc08dcca 100644 --- a/dlls/gamerules.cpp +++ b/dlls/gamerules.cpp @@ -65,58 +65,13 @@ extern EHANDLE g_pLastSpawn; edict_t *CGameRules::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) { edict_t *pentSpawnSpot = EntSelectSpawnPoint( pPlayer ); - if( pPlayer->gravgunmod_data.m_state == STATE_POINT_SELECT ) - { - pPlayer->gravgunmod_data.m_state = STATE_SPAWNED; - pPlayer->pev->effects &= ~EF_NODRAW; - pPlayer->pev->takedamage = DAMAGE_YES; - pPlayer->pev->flags &= ~FL_SPECTATOR; - pPlayer->pev->movetype = MOVETYPE_WALK; - CLIENT_COMMAND( pPlayer->edict(), "touch_show _coopm*\n" ); - - return NULL; - } - - if( mp_coop.value ) - UTIL_CleanSpawnPoint( pentSpawnSpot->v.origin, 100 ); - - if( g_pLastSpawn ) 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; - if( !(pPlayer->pev->flags & FL_SPECTATOR ) ) - if( mp_coop.value ) - if( !UTIL_CoopGetSpawnPoint( &pPlayer->pev->origin, &pPlayer->pev->angles ) ) - { - if( !g_pLastSpawn ) - { - hudtextparms_t params = {}; - params.fadeinTime = 0.5; - params.fadeoutTime = .5; - params.holdTime = 10; - params.channel = 0; - params.x = params.y = -1; - params.r2 = params.g2 = params.b2 = params.a2 = params.r1 = params.g1 = params.b1 = params.a1 = 255; - - - UTIL_HudMessage( pPlayer, params, "Server cannot select a spawnpoint\nplease fly to it manually\nand press attack button" ); - // select spawn point - pPlayer->gravgunmod_data.m_state = STATE_POINT_SELECT; - pPlayer->m_afButtonPressed = 0; - - if(pPlayer->pev->origin.Length() > 8192) - pPlayer->pev->origin = g_vecZero; - - - } - } pPlayer->pev->fixangle = TRUE; - pPlayer->pev->origin = COOP_FixupSpawnPoint( pPlayer->pev->origin ); - if( g_fSavedDuck ) - pPlayer->pev->flags |= FL_DUCKING; return pentSpawnSpot; } diff --git a/dlls/gravgunmod.cpp b/dlls/gravgunmod.cpp index 3bdae56f..45bb8777 100644 --- a/dlls/gravgunmod.cpp +++ b/dlls/gravgunmod.cpp @@ -961,8 +961,9 @@ bool GGM_RestorePosition( CBasePlayer *pPlayer, struct GGMPosition *pos ) } if( mp_coop.value && !fOriginSet ) { - g_pGameRules->GetPlayerSpawnSpot( pPlayer ); - if( pPlayer->gravgunmod_data.m_state = STATE_POINT_SELECT ) + if( !COOP_SetDefaultSpawnPosition( pPlayer ) ) + g_pGameRules->GetPlayerSpawnSpot( pPlayer ); + if( pPlayer->gravgunmod_data.m_state == STATE_POINT_SELECT ) return false; } @@ -973,6 +974,7 @@ bool GGM_RestorePosition( CBasePlayer *pPlayer, struct GGMPosition *pos ) UTIL_SetSize( pPlayer->pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX ); } pPlayer->pev->angles = pos->vecAngles; + pPlayer->pev->fixangle = TRUE; return true; } @@ -1033,7 +1035,7 @@ bool GGM_PlayerSpawn( CBasePlayer *pPlayer ) return true; } - if( mp_spectator.value && pPlayer->gravgunmod_data.m_state == STATE_CONNECTED || !pPlayer->gravgunmod_data.pState ) + if( ( mp_coop.value || mp_spectator.value ) && pPlayer->gravgunmod_data.m_state == STATE_CONNECTED || !pPlayer->gravgunmod_data.pState ) { if( !pPlayer->gravgunmod_data.pState ) GGM_ChatPrintf( pPlayer, "This nickname busy! Please login or change nickname\n" ); @@ -1041,6 +1043,8 @@ bool GGM_PlayerSpawn( CBasePlayer *pPlayer ) pPlayer->gravgunmod_data.m_state = STATE_SPECTATOR_BEGIN; pPlayer->RemoveAllItems( TRUE ); UTIL_BecomeSpectator( pPlayer ); + if( !COOP_SetDefaultSpawnPosition( pPlayer ) ) + g_pGameRules->GetPlayerSpawnSpot( pPlayer ); return true; } @@ -1090,7 +1094,8 @@ bool GGM_PlayerSpawn( CBasePlayer *pPlayer ) { } - g_pGameRules->GetPlayerSpawnSpot( pPlayer ); + if( !COOP_SetDefaultSpawnPosition( pPlayer ) ) + g_pGameRules->GetPlayerSpawnSpot( pPlayer ); } else { diff --git a/dlls/gravgunmod.h b/dlls/gravgunmod.h index f44e90ce..0ec8a84a 100644 --- a/dlls/gravgunmod.h +++ b/dlls/gravgunmod.h @@ -185,6 +185,6 @@ void GGM_SaveState( CBasePlayer *pPlayer ); bool GGM_PlayerSpawn( CBasePlayer *pPlayer ); const char *GGM_GetAuthID( CBasePlayer *pPlayer ); void GGM_ServerActivate( void ); -void COOP_SetupLandmarkTransition( const char *szNextMap, const char *szNextSpot, Vector vecLandmarkOffset ); +void COOP_SetupLandmarkTransition( const char *szNextMap, const char *szNextSpot, Vector vecLandmarkOffset, struct GGMPosition *pPos ); #endif // GRAVGUNMOD_H diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 4b971a2b..921d098d 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -613,30 +613,31 @@ void CHalfLifeMultiplay::PlayerSpawn( CBasePlayer *pPlayer ) addDefault = FALSE; } - if( addDefault ) + if( !mp_coop.value ) { - pPlayer->GiveNamedItem( "weapon_crowbar" ); - pPlayer->GiveNamedItem( "weapon_9mmhandgun" ); - pPlayer->GiveAmmo( 68, "9mm", _9MM_MAX_CARRY );// 4 full reloads - } + if( addDefault ) + { + pPlayer->GiveNamedItem( "weapon_crowbar" ); + pPlayer->GiveNamedItem( "weapon_9mmhandgun" ); + pPlayer->GiveAmmo( 68, "9mm", _9MM_MAX_CARRY );// 4 full reloads + } - if( (int)cvar_allow_gravgun.value == 2 ) - pPlayer->GiveNamedItem( "weapon_gravgun" ); - if( (int)cvar_allow_ar2.value == 2 ) - pPlayer->GiveNamedItem( "weapon_ar2" ); - if( !cvar_ar2_mp5.value ) - { - pPlayer->GiveAmmo( cvar_ar2_bullets.value, "AR2", 120 ); - pPlayer->GiveAmmo( cvar_ar2_balls.value, "AR2grenades", 3 ); + if( (int)cvar_allow_gravgun.value == 2 ) + pPlayer->GiveNamedItem( "weapon_gravgun" ); + if( (int)cvar_allow_ar2.value == 2 ) + pPlayer->GiveNamedItem( "weapon_ar2" ); + if( !cvar_ar2_mp5.value ) + { + pPlayer->GiveAmmo( cvar_ar2_bullets.value, "AR2", 120 ); + pPlayer->GiveAmmo( cvar_ar2_balls.value, "AR2grenades", 3 ); + } + if( (int)cvar_allow_bigcock.value == 2 ) + pPlayer->GiveNamedItem( "weapon_big_cock" ); + if( (int)cvar_allow_gateofbabylon.value == 2 ) + pPlayer->GiveNamedItem( "weapon_gateofbabylon" ); } - if( (int)cvar_allow_bigcock.value == 2 ) - pPlayer->GiveNamedItem( "weapon_big_cock" ); - if( (int)cvar_allow_gateofbabylon.value == 2 ) - pPlayer->GiveNamedItem( "weapon_gateofbabylon" ); - - if( mp_coop.value ) + else { -// pPlayer->GiveNamedItem( "item_suit" ); g_WeaponList.GiveToPlayer(pPlayer); } } diff --git a/dlls/player.cpp b/dlls/player.cpp index 14f8ddf7..193a1beb 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -2858,7 +2858,7 @@ edict_t *EntSelectSpawnPoint( CBaseEntity *pPlayer ) if( !FStrEq( STRING( pSpot->pev->netname ), STRING( gpGlobals->mapname ) ) ) continue; // check if it is placed in wall - UTIL_TraceHull( pSpot->pev->origin, pSpot->pev->origin , missile, (mp_unduck.value&&g_fSavedDuck)?head_hull:human_hull, NULL, &tr ); + UTIL_TraceHull( pSpot->pev->origin, pSpot->pev->origin , missile, human_hull, NULL, &tr ); if( tr.fStartSolid || tr.fAllSolid ) continue; // trace down to find if there is no floor @@ -3116,13 +3116,6 @@ int CBasePlayer::Restore( CRestore &restore ) m_flNextAttack = UTIL_WeaponTimeBase(); #endif - // restored player has some bugs untill respawned - if( mp_coop.value ) - { - gravgunmod_data.m_state = STATE_CONNECTED; - SetThink( &CBasePlayer::Spawn ); - pev->nextthink = gpGlobals->time + 0.5; - } return status; } diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index e2fd939c..9e77b7ad 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -1326,7 +1326,6 @@ public: void EXPORT TriggerChangeLevel( void ); void EXPORT ExecuteChangeLevel( void ); void EXPORT TouchChangeLevel( CBaseEntity *pOther ); - void EXPORT UpdateColor(); void ChangeLevelNow( CBaseEntity *pActivator ); static edict_t *FindLandmark( const char *pLandmarkName ); @@ -1343,14 +1342,7 @@ public: char m_szLandmarkName[cchMapNameMost]; // trigger_changelevel only: landmark on next map string_t m_changeTarget; float m_changeTargetDelay; - unsigned int m_uTouchCount; - bool m_bUsed; - Vector m_vecSpawnOrigin; - Vector m_vecSpawnAngles; - bool m_fSpawnSaved; - bool m_fIsBack; - bool m_fSkipSpawnCheck; // skip 30 seconds check when called by multimanager or trigger_once - float m_flRepeatTimer; + struct COOPChangelevelData m_coopData; }; LINK_ENTITY_TO_CLASS( trigger_changelevel, CChangeLevel ) @@ -1366,6 +1358,14 @@ TYPEDESCRIPTION CChangeLevel::m_SaveData[] = IMPLEMENT_SAVERESTORE( CChangeLevel, CBaseTrigger ) +struct COOPChangelevelData *COOP_GetTriggerData( CBaseEntity *pTrigger ) +{ + CChangeLevel *pChangeLevel = (CChangeLevel*)pTrigger; + pChangeLevel->m_coopData.pszMapName = pChangeLevel->m_szMapName; + + return &pChangeLevel->m_coopData; +} + // // Cache user-entity-field values until spawn is called. // @@ -1404,8 +1404,8 @@ When the player touches this, he gets sent to the map listed in the "map" variab */ void CChangeLevel::Spawn( void ) { - m_uTouchCount = 0; - m_bUsed = false; + m_coopData.bitsTouchCount = 0; + m_coopData.fUsed = false; if( FStrEq( m_szMapName, "" ) ) ALERT( at_console, "a trigger_changelevel doesn't have a map" ); @@ -1418,25 +1418,7 @@ void CChangeLevel::Spawn( void ) } InitTrigger(); if( !( pev->spawnflags & SF_CHANGELEVEL_USEONLY ) ) - { SetTouch( &CChangeLevel::TouchChangeLevel ); - if( mp_coop.value ) - { - if( gpGlobals->startspot && STRING(gpGlobals->startspot) && !strcmp(STRING(gpGlobals->startspot), m_szLandmarkName) ) - m_fIsBack = true; - // set color (got from XDM) - if( m_fIsBack ) - pev->rendercolor.z = 255; - else - pev->rendercolor.y = 255; - pev->renderamt = 127; - - pev->effects &= ~EF_NODRAW; - pev->rendermode = kRenderTransColor; - SetThink( &CChangeLevel::UpdateColor ); - pev->nextthink = gpGlobals->time + 2; - } - } //ALERT( at_console, "TRANSITION: %s (%s)\n", m_szMapName, m_szLandmarkName ); } @@ -1479,11 +1461,11 @@ edict_t *CChangeLevel::FindLandmark( const char *pLandmarkName ) void CChangeLevel::UseChangeLevel( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { // if not activated by touch, do not count players - m_bUsed = true; + m_coopData.fUsed = true; if( pCaller && FClassnameIs( pCaller->edict(), "multi_manager" ) || FClassnameIs( pCaller->edict(), "trigger_once" ) ) - m_fSkipSpawnCheck = true; + m_coopData.fSkipSpawnCheck = true; else - m_fSkipSpawnCheck = false; + m_coopData.fSkipSpawnCheck = false; const char *classname = NULL; if( pCaller && pCaller->pev->classname ) classname = STRING( pCaller->pev->classname ); @@ -1491,27 +1473,6 @@ void CChangeLevel::UseChangeLevel( CBaseEntity *pActivator, CBaseEntity *pCaller ChangeLevelNow( pActivator ); } - -void CChangeLevel::UpdateColor( void ) -{ - Vector origin = VecBModelOrigin(pev); - Vector point, angles; - CBaseEntity *pPlayer; - pev->nextthink = gpGlobals->time + 30; - - /*if( !m_fIsBack && (pPlayer = UTIL_FindEntityByClassname( NULL, "info_player_start" )) ) - if( (origin - pPlayer->pev->origin).Length() < 500 ) - m_fIsBack = true;*/ - if( !m_fIsBack && UTIL_CoopGetSpawnPoint( &point, &angles ) ) - if( (origin - point).Length() < 500 ) - m_fIsBack = true; - pev->rendercolor = g_vecZero; - if( m_fIsBack ) - pev->rendercolor.z = 255; - else - pev->rendercolor.y = 255; -} - // If some player is on train with global state, save id CBaseEntity *FindTriggerTransition( char *pVolumeName ) @@ -1537,46 +1498,97 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) { edict_t *pentLandmark; - LEVELLIST levels[16]; + // LEVELLIST levels[16]; hudtextparms_t params = {}; params.fadeinTime = 0.5; params.fadeoutTime = .5; params.holdTime = 10; params.r2 = params.g2 = params.b2 = params.a2 = params.r1 = params.g1 = params.b1 = params.a1 = 255; - bool valid = false; ASSERT( !FStrEq( m_szMapName, "" ) ); - if( s_SavedCoords.valid ) + if( m_coopData.fValid ) return; //already pending // forget touch by some fool if( gpGlobals->time - pev->dmgtime > 30) + m_coopData.bitsTouchCount = 0; + + // find best candidate for default spawn point + if( !m_coopData.fSpawnSaved ) { - m_uTouchCount = 0; - pev->nextthink = gpGlobals->time + 30; + CBasePlayer *pRealActivator = NULL; + + if( pActivator ) + { + // trigger touch + if( pActivator->IsNetClient() ) + pRealActivator = (CBasePlayer*)pActivator; + + + // activate by path track? + if( !pRealActivator && pActivator->IsBSPModel() ) + { + for( int i = 1; i < gpGlobals->maxClients; i++ ) + { + CBaseEntity *plr = UTIL_PlayerByIndex( i ); + if( plr && plr->IsNetClient() && plr->pev->groundentity == pActivator->edict() ) + { + pRealActivator = (CBasePlayer*)plr; + break; + } + } + } + + // activate by something other, player nearest to transition volume center + if( !pRealActivator && m_coopData.fUsed ) + { + CBaseEntity *pTransition = FindTriggerTransition( m_szLandmarkName ); + + if( pTransition ) + { + Vector vecOrigin = VecBModelOrigin( pTransition->pev ); + float dist = 9999; + + for( int i = 1; i < gpGlobals->maxClients; i++ ) + { + CBaseEntity *plr = UTIL_PlayerByIndex( i ); + if( plr && plr->IsNetClient() && pTransition->Intersects( plr ) ) + { + float diff = (vecOrigin - plr->pev->origin).Length(); + if( dist > diff ) + { + dist = diff; + pRealActivator = (CBasePlayer *)plr; + break; + } + } + } + } + } + } + + if( pRealActivator ) + { + GGM_SavePosition(pRealActivator, &m_coopData.savedPosition); + m_hActivator = pRealActivator; + m_coopData.fSpawnSaved = true; + } } if(mp_coop.value) { - SavedCoords l_SavedCoords = {}; // if not activated by touch, do not count players - if( !m_bUsed ) + if( !m_coopData.fUsed ) { - m_uTouchCount |= 1 << ( ENTINDEX( pActivator->edict() ) - 1); + CBaseEntity *pActTrain = UTIL_CoopGetPlayerTrain(m_hActivator); - // Keep first toucher coords to save correct spawn angles - if( !m_fSpawnSaved && pActivator->IsPlayer() ) - { - m_vecSpawnOrigin = pActivator->pev->origin; - m_vecSpawnAngles = pActivator->pev->angles; - m_fSpawnSaved = true; - UTIL_CoopSaveTrain( pActivator, &l_SavedCoords ); - } - unsigned int count1 = 0; - unsigned int count2 = 0; + unsigned int count1 = 0; // players that touched + unsigned int count2 = 0; // all players unsigned int i = 0; + m_coopData.bitsTouchCount |= 1 << ( ENTINDEX( pActivator->edict() ) - 1); + // loop through all clients, count number of players for( i = 1; i <= gpGlobals->maxClients; i++ ) { @@ -1586,37 +1598,32 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) if( !pTrain && UTIL_CoopIsBadPlayer( plr ) ) continue; + // refuse + if( plr && (pTrain != pActTrain) ) + return; + // count only players spawned more 30 seconds ago if( plr && plr->IsPlayer() && (pTrain || (gpGlobals->time -((CBasePlayer*)plr)->gravgunmod_data.m_flSpawnTime ) > 30 ) && plr->pev->modelindex ) { count2++; - // player touched trigger, save it's coordinates - if( m_uTouchCount & (1<<(i - 1)) ) - { + // player touched trigger, count it + if( m_coopData.bitsTouchCount & (1<<(i - 1)) ) count1++; - if( InTransitionVolume( plr, m_szLandmarkName )) - { - l_SavedCoords.fDuck |= !!(plr->pev->flags & FL_DUCKING); - UTIL_CoopSaveTrain( plr, &l_SavedCoords ); - l_SavedCoords.iCount++; - } - } - } } i = 0; - if( !l_SavedCoords.trainsaved ) + if( !pActTrain ) { if( !count2 ) { - if( pActivator && pActivator->IsPlayer() && m_flRepeatTimer - gpGlobals->time < -1 ) + if( pActivator && pActivator->IsPlayer() && m_coopData.flRepeatTimer - gpGlobals->time < -1 ) { CBasePlayer *pPlayer = (CBasePlayer*)pActivator; //UTIL_CoopPrintMessage("%s^7 trying activate changelevel too early\n", UTIL_CoopPlayerName( pPlayer )); UTIL_CleanSpawnPoint( pPlayer->pev->origin, 50 ); - m_flRepeatTimer = gpGlobals->time; + m_coopData.flRepeatTimer = gpGlobals->time; pPlayer->gravgunmod_data.m_iLocalConfirm = -2; } @@ -1624,8 +1631,6 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) return; } - if( count1 > 1 && count1 < count2 / 3 ) - i = count1 - count1 < count2 / 3; if( count1 > 1 && count1 < count2 / 3 ) i = 1; @@ -1637,7 +1642,7 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) if( count2 ) { pev->rendercolor.x = count1 * 255 / count2; - if( m_fIsBack ) + if( m_coopData.fIsBack ) pev->rendercolor.z = 255 - pev->rendercolor.x; else pev->rendercolor.y = 255 - pev->rendercolor.x; @@ -1645,40 +1650,22 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) ALERT( at_console, "^3CHANGELEVEL:^7 %d %d\n", count2, count1 ); - if( !m_fIsBack && count1 > 1 && count1 < count2 / 3 ) + if( !m_coopData.fIsBack && count1 > 1 && count1 < count2 / 3 ) return; //if( count1 <= 1 && count2 == 2 ) // return; - if( m_fIsBack ) + if( m_coopData.fIsBack ) if( !COOP_ConfirmMenu( this, pActivator, count2, m_szMapName ) ) return; } - if( m_fSpawnSaved ) - { - l_SavedCoords.triggerangles = m_vecSpawnAngles; - l_SavedCoords.triggerorigin = m_vecSpawnOrigin; - valid = true; - } - ALERT( at_console, "^2CHANGELEVEL:^7 %d %d %d\n", count2, count1, (int)m_fIsBack); + ALERT( at_console, "^2CHANGELEVEL:^7 %d %d %d\n", count2, count1, (int)m_coopData.fIsBack); } else { - l_SavedCoords.fDuck = false; - // Get current player's coordinates - if( pActivator && pActivator->IsPlayer() ) - { - l_SavedCoords.triggerangles = pActivator->pev->angles; - l_SavedCoords.triggerorigin = pActivator->pev->origin; - valid = true; - l_SavedCoords.fDuck |= !!(pActivator->pev->flags & FL_DUCKING); - } - } - UTIL_CoopSaveTrain( pActivator, &l_SavedCoords ); - s_SavedCoords = l_SavedCoords; @@ -1687,8 +1674,8 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) else if( g_pGameRules->IsDeathmatch() ) return; - m_uTouchCount = 0; - m_bUsed = false; + m_coopData.bitsTouchCount = 0; + m_coopData.fUsed = false; // Some people are firing these multiple times in a frame, disable if( gpGlobals->time == pev->dmgtime ) return; @@ -1706,7 +1693,7 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) { CBaseEntity *plr = UTIL_PlayerByIndex( i ); - if( plr && plr->IsPlayer() && ( !FindTriggerTransition( m_szLandmarkName ) || (gpGlobals->time -((CBasePlayer*)plr)->gravgunmod_data.m_flSpawnTime ) > 30 || m_fSkipSpawnCheck ) ) + if( plr && plr->IsPlayer() && ( !FindTriggerTransition( m_szLandmarkName ) || (gpGlobals->time -((CBasePlayer*)plr)->gravgunmod_data.m_flSpawnTime ) > 30 || m_coopData.fSkipSpawnCheck ) ) { if( InTransitionVolume( plr, m_szLandmarkName )) { @@ -1726,13 +1713,17 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) } else if( ( (gpGlobals->time -((CBasePlayer*)pPlayer)->gravgunmod_data.m_flSpawnTime ) < 30 ) && FindTriggerTransition( m_szLandmarkName ) || !InTransitionVolume( pPlayer, m_szLandmarkName ) ) { - ALERT( at_console, "Player isn't in the transition volume %s, aborting\n", m_szLandmarkName ); - if( !m_fSkipSpawnCheck ) + if( !m_coopData.fSkipSpawnCheck ) + { + ALERT( at_console, "Player isn't in the transition volume %s, aborting\n", m_szLandmarkName ); return; + } + else + ALERT( at_console, "Player isn't in the transition volume %s, but changelevel forced\n", m_szLandmarkName ); } else ALERT( at_console, "Player is in the transition volume %s, changing level now\n", m_szLandmarkName ); - UTIL_CoopPrintMessage( "%s^7 activated changelevel, spawncheck is %d\n", UTIL_CoopPlayerName( pPlayer ), (int)!m_fSkipSpawnCheck ); + UTIL_CoopPrintMessage( "%s^7 activated changelevel, spawncheck is %d\n", UTIL_CoopPlayerName( pPlayer ), (int)!m_coopData.fSkipSpawnCheck ); // This object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory strcpy( st_szNextMap, m_szMapName ); @@ -1746,10 +1737,10 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) if( !FNullEnt( pentLandmark ) ) { strcpy( st_szNextSpot, m_szLandmarkName ); - strcpy( s_SavedCoords.landmark, m_szLandmarkName ); - s_SavedCoords.offset = gpGlobals->vecLandmarkOffset = VARS( pentLandmark )->origin; + gpGlobals->vecLandmarkOffset = VARS( pentLandmark )->origin; } + // Create an entity to fire the changetarget if( m_changeTarget ) { @@ -1769,6 +1760,8 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) } } + m_coopData.fValid = true; + //ALERT( at_console, "Level touches %d levels\n", ChangeList( levels, 16 ) ); ALERT( at_console, "CHANGE LEVEL: %s %s\n", st_szNextMap, st_szNextSpot ); COOP_ResetVote(); @@ -1793,9 +1786,8 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) } g_fPause = true; } - s_SavedCoords.fUsed = m_bUsed; - s_SavedCoords.valid = valid; - COOP_SetupLandmarkTransition( st_szNextMap, st_szNextSpot, gpGlobals->vecLandmarkOffset ); + + COOP_SetupLandmarkTransition( st_szNextMap, st_szNextSpot, gpGlobals->vecLandmarkOffset, m_coopData.fSpawnSaved?&m_coopData.savedPosition:NULL ); // wait 5 frames to make sure all players are in reconnected state if( mp_coop_reconnect_hack.value ) @@ -1812,7 +1804,7 @@ void CChangeLevel::TouchChangeLevel( CBaseEntity *pOther ) if( !FClassnameIs( pOther->pev, "player" ) ) return; - m_fSkipSpawnCheck = false; + m_coopData.fSkipSpawnCheck = false; ChangeLevelNow( pOther ); }