diff --git a/dlls/client.cpp b/dlls/client.cpp index ffc83b94..d6804daf 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -670,13 +670,25 @@ void PlayerPostThink( edict_t *pEntity ) pPlayer->PostThink( ); } - - +void CoopClearData( void ); +void CoopClearWeaponList( void ); void ParmsNewLevel( void ) { + // retrieve the pointer to the save data + SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; + + if ( pSaveData ) + pSaveData->connectionCount = BuildChangeList( pSaveData->levelList, MAX_LEVEL_CONNECTIONS ); + else + if( mp_coop_changelevel.value ) + { + CoopClearData(); + CoopClearWeaponList(); + } } + void ParmsChangeLevel( void ) { // retrieve the pointer to the save data @@ -684,6 +696,13 @@ void ParmsChangeLevel( void ) if ( pSaveData ) pSaveData->connectionCount = BuildChangeList( pSaveData->levelList, MAX_LEVEL_CONNECTIONS ); + else + if( mp_coop_changelevel.value ) + { + CoopClearData(); + CoopClearWeaponList(); + } + } diff --git a/dlls/gamerules.cpp b/dlls/gamerules.cpp index ee1e6d8b..08ca7596 100644 --- a/dlls/gamerules.cpp +++ b/dlls/gamerules.cpp @@ -57,6 +57,9 @@ BOOL CGameRules::CanHaveAmmo( CBasePlayer *pPlayer, const char *pszAmmoName, int return FALSE; } +bool CoopGetSpawnPoint( Vector *point, Vector *angles); + +bool CoopRestorePlayerCoords(CBaseEntity *player, Vector *origin, Vector *angles ); //========================================================= //========================================================= @@ -72,6 +75,8 @@ edict_t *CGameRules::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) pPlayer->pev->velocity = g_vecZero; pPlayer->pev->angles = VARS( pentSpawnSpot )->angles; pPlayer->pev->punchangle = g_vecZero; + if( mp_coop_changelevel.value && !CoopRestorePlayerCoords( pPlayer, &pPlayer->pev->origin, &pPlayer->pev->angles )) + CoopGetSpawnPoint( &pPlayer->pev->origin, &pPlayer->pev->angles ); pPlayer->pev->fixangle = TRUE; return pentSpawnSpot; diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index f9817cf6..b4388334 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -84,8 +84,17 @@ public: for(int i = 0; i < m_iWeapons;i++) player->GiveNamedItem(weapons[i]); } + void Clear() + { + m_iWeapons = 0; + } } g_WeaponList; +void CoopClearWeaponList( void ) +{ + g_WeaponList.Clear(); +} + //********************************************************* // Rules for the half-life multiplayer game. //********************************************************* diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index 762fe2ac..105b8e3b 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -1445,6 +1445,92 @@ void CChangeLevel::UseChangeLevel( CBaseEntity *pActivator, CBaseEntity *pCaller ChangeLevelNow( pActivator ); } +struct SavedCoords +{ + char ip[32][32]; + Vector origin[32]; + Vector angles[32]; + char landmark[32]; + Vector triggerorigin; + Vector triggerangles; + Vector offset; + int iCount; + bool valid; + bool validoffset; + bool validspawnpoint; +} g_SavedCoords; +void CoopClearData( void ) +{ + // nullify + SavedCoords l_SavedCoords = {}; + g_SavedCoords = l_SavedCoords; +} + +static void validateoffset( void ) +{ + if( !g_SavedCoords.validoffset) + { + edict_t *landmark = CChangeLevel::FindLandmark(g_SavedCoords.landmark); + if(landmark) + g_SavedCoords.offset = landmark->v.origin - g_SavedCoords.offset; + else + g_SavedCoords.offset = g_vecZero; + g_SavedCoords.validoffset = true; + } +} + +bool CoopRestorePlayerCoords(CBaseEntity *player, Vector *origin, Vector *angles ) +{ + if(!g_SavedCoords.valid) + return false; + validateoffset(); + // compute player by IQ + char *ip = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( player->edict() ), "ip" ); + for( int i = 0;i < g_SavedCoords.iCount;i++) + { + if(!strcmp(ip, g_SavedCoords.ip[i])) + { + TraceResult tr; + Vector point = g_SavedCoords.origin[i] + g_SavedCoords.offset; + + UTIL_TraceHull( point, point, missile, human_hull, NULL, &tr ); + g_SavedCoords.ip[i][0] = 0; + + if( tr.fStartSolid ) + return false; + *origin = point; + *angles = g_SavedCoords.angles[i]; + return true; + } + } + return false; +} + +bool CoopGetSpawnPoint( Vector *point, Vector *angles) +{ + if(!g_SavedCoords.valid) + return false; + validateoffset(); + *point = g_SavedCoords.triggerorigin + g_SavedCoords.offset; + *angles = g_SavedCoords.triggerangles; + if( !g_SavedCoords.validspawnpoint ) + { + TraceResult tr; + Vector angle; + UTIL_MakeVectorsPrivate( *angles, (float*)&angle, NULL, NULL ); + UTIL_TraceHull( *point, *point + angle * 100, missile, human_hull, NULL, &tr ); + if( !tr.fStartSolid ) + { + g_SavedCoords.triggerorigin = tr.vecEndPos; + g_SavedCoords.validspawnpoint = true; + } + else + g_SavedCoords.valid = false; + } + + return true; +} + void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) { edict_t *pentLandmark; @@ -1454,9 +1540,11 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) if(mp_coop_changelevel.value) { + SavedCoords l_SavedCoords = {}; // if not activated by touch, do not count players if( !m_bUsed ) { + m_uTouchCount |= ENTINDEX( pActivator->edict() ); unsigned int count1 = m_uTouchCount; unsigned int count2 = 0; @@ -1475,6 +1563,17 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) if( plr ) { count2++; + char *ip = g_engfuncs.pfnInfoKeyValue( g_engfuncs.pfnGetInfoKeyBuffer( plr->edict() ), "ip" ); + + // player touched trigger, save it's coordinates + if( m_uTouchCount & (i - 1) ) + { + strcpy(l_SavedCoords.ip[l_SavedCoords.iCount], ip ); + l_SavedCoords.origin[l_SavedCoords.iCount] = plr->pev->origin; + l_SavedCoords.angles[l_SavedCoords.iCount] = plr->pev->angles; + l_SavedCoords.iCount++; + } + } } @@ -1495,7 +1594,13 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) if( count1 == 1 && count2 == 2 ) return; + g_SavedCoords.triggerangles = pActivator->pev->angles; + g_SavedCoords.triggerorigin = pActivator->pev->origin; + g_SavedCoords.valid = true; } + g_SavedCoords = l_SavedCoords; + + } // Don't work in deathmatch else if( g_pGameRules->IsDeathmatch() ) @@ -1544,7 +1649,8 @@ void CChangeLevel::ChangeLevelNow( CBaseEntity *pActivator ) if( !FNullEnt( pentLandmark ) ) { strcpy( st_szNextSpot, m_szLandmarkName ); - gpGlobals->vecLandmarkOffset = VARS( pentLandmark )->origin; + strcpy( g_SavedCoords.landmark, m_szLandmarkName ); + g_SavedCoords.offset = gpGlobals->vecLandmarkOffset = VARS( pentLandmark )->origin; } //ALERT( at_console, "Level touches %d levels\n", ChangeList( levels, 16 ) ); ALERT( at_console, "CHANGE LEVEL: %s %s\n", st_szNextMap, st_szNextSpot ); diff --git a/dlls/util.cpp b/dlls/util.cpp index b6eaee70..48d39d8e 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -1585,11 +1585,11 @@ void UTIL_CleanSpawnPoint( Vector origin, float dist ) { if( ent->IsPlayer() ) { - TraceResult tr = {0}; + TraceResult tr; UTIL_TraceHull( ent->pev->origin + Vector( 0, 0, 36), ent->pev->origin + Vector( RANDOM_FLOAT( -150, 150 ), RANDOM_FLOAT( -150, 150 ), 0 ), dont_ignore_monsters, human_hull, ent->edict(), &tr); //UTIL_TraceModel( ent->pev->origin + Vector( 0, 0, 36), ent->pev->origin + Vector( RANDOM_FLOAT( -150, 150 ), RANDOM_FLOAT( -150, 150 ), 0 ), 0, ent->edict(), &tr); - - UTIL_SetOrigin(ent->pev, tr.vecEndPos); + if( !tr.fAllSolid ) + UTIL_SetOrigin(ent->pev, tr.vecEndPos); } } }