Exemplo n.º 1
0
void AppCleanup()
{
	StopReplay();
	WaveLogStop();

	AppExit();
}
Exemplo n.º 2
0
////////////////////////////////////////////////////////////////
// デストラクタ
////////////////////////////////////////////////////////////////
REPLAY::~REPLAY( void )
{
	switch( RepST ){
	case REP_RECORD:	StopRecord(); break;
	case REP_REPLAY:	StopReplay(); break;
	}
	if( Matrix ) delete [] Matrix;
	if( Ini ) delete Ini;
}
Exemplo n.º 3
0
int DrvExit()
{
	if (bDrvOkay) {
		StopReplay();

		VidExit();

		InvalidateRect(hScrnWnd, NULL, 1);
		UpdateWindow(hScrnWnd);			// Blank screen window

		DestroyWindow(hInpdDlg);		// Make sure the Input Dialog is exited
		DestroyWindow(hInpDIPSWDlg);	// Make sure the DipSwitch Dialog is exited
		DestroyWindow(hInpCheatDlg);	// Make sure the Cheat Dialog is exited

		if (nBurnDrvActive < nBurnDrvCount) {
			MemCardEject();				// Eject memory card if present

			if (bSaveRAM) {
				StatedAuto(1);			// Save NV (or full) RAM
				bSaveRAM = false;
			}

			ConfigGameSave(bSaveInputs);

			GameInpExit();				// Exit game input
			
			BurnDrvExit();				// Exit the driver
		}
	}

	BurnExtLoadRom = NULL;

	bDrvOkay = 0;					// Stop using the BurnDrv functions

	bRunPause = 0;					// Don't pause when exitted

	if (bAudOkay) {
		// Write silence into the sound buffer on exit, and for drivers which don't use pBurnSoundOut
		memset(nAudNextSound, 0, nAudSegLen << 2);
	}
	
	CDEmuExit();

	BurnExtCartridgeSetupCallback = NULL;

	nBurnDrvActive = ~0U;			// no driver selected

	return 0;
}
Exemplo n.º 4
0
void CReplayManager::CleanUp()
{
	StopHighlights();
	StopReplay();

	while (m_Snapshots.Count() > 0)
	{
		if (m_Snapshots[0]->replayCount == 0)
			delete m_Snapshots[0];

		m_Snapshots.Remove(0);
	}

	m_MatchEvents.PurgeAndDeleteElements();
}
Exemplo n.º 5
0
////////////////////////////////////////////////////////////////
// リプレイ1フレーム読込み
//
// 引数:	mt		キーマトリクスポインタ
// 返値:	bool	true:成功 false:失敗
////////////////////////////////////////////////////////////////
bool REPLAY::ReplayReadFrame( BYTE *mt )
{
	char stren[16],strva[256];
	
	if( ( RepST != REP_REPLAY ) || !mt || !Ini ) return false;
	
	sprintf( stren, "%08lX", RepFrm );
	if( Ini->GetString( "REPLAY", stren, strva, "" ) ){
		int stl = strlen( strva ) / 2;
		for( int i=0; i<stl; i++ ){
			char dt[3] = "FF";
			strncpy( dt, &strva[i*2], 2 );
			Matrix[i] = strtol( dt, NULL, 16 );
		}
		memcpy( mt, Matrix, MSize );
	}
	
	if( ++RepFrm >= EndFrm ){
		// データ終端に達したらリプレイ終了
		StopReplay();
	}
	
	return true;
}
Exemplo n.º 6
0
static void onCommand(HWND hDlg, int id, HWND /*hwndCtl*/, UINT codeNotify)
{
    if (bLoading) {
        return;
    }

    switch (id) {
    case MENU_LOAD:
        HK_openGame(0);
        break;

    case MENU_LOAD_QUICK:
        HK_quickOpenGame(0);
        break;

    case MENU_QUIT:
        HK_exitGame(0);
        break;

    case MENU_EXIT:
        StopReplay();
        AviStop();
        FBA_KailleraEnd();
        PostQuitMessage(0);

        menuSync(MENUT_ALL);
        return;

    case MENU_PAUSE:
        HK_pause(0);
        break;

    case MENU_CARTR_MOUNT:
        mountCartridge(true);
        menuSync(MENUT_FILE);
        break;

    case MENU_CARTR_UNMOUNT:
        mountCartridge(false);
        menuSync(MENUT_FILE);
        break;

    case MENU_STARTNET:
        if (!kNetGame) {
            InputSetCooperativeLevel(false, !bAlwaysProcessKey);
            audio.blank();
            SplashDestroy(1);
            StopReplay();
            AviStop();
            BurnerDrvExit();
            // load kaillera.dll
            if (FBA_KailleraInit()) {
                DoNetGame();
            }
            menuSync(MENUT_ALL);
            InputSetCooperativeLevel(false, !bAlwaysProcessKey);
        }
        break;

    case MENU_STARTREPLAY:
        HK_playRec(0);
        break;
    case MENU_STARTRECORD:
        HK_startRec(0);
        break;
    case MENU_STOPREPLAY:
        HK_stopRec(0);
        break;

    case MENU_AVISTART:
        HK_startAvi(0);
        break;
    case MENU_AVISTOP:
        HK_stopAvi(0);
        break;
    case MENU_AVIINTAUD:
        nAviIntAudio = !nAviIntAudio;
        menuSync(MENUT_FILE);
        break;

    case MENU_MEMCARD_CREATE:
        if (useDialogs() && bDrvOkay && !kNetGame
                && (BurnDrvGetHardwareCode() & HARDWARE_PUBLIC_MASK) == HARDWARE_SNK_NEOGEO) {
            InputSetCooperativeLevel(false, !bAlwaysProcessKey);
            audio.blank();
            MemCardEject();
            MemCardCreate();
            MemCardInsert();
            menuSync(MENUT_FILE);
            GameInpCheckMouse();
        }
        break;
    case MENU_MEMCARD_SELECT:
        if (useDialogs() && bDrvOkay && !kNetGame
                && (BurnDrvGetHardwareCode() & HARDWARE_PUBLIC_MASK) == HARDWARE_SNK_NEOGEO) {
            InputSetCooperativeLevel(false, !bAlwaysProcessKey);
            audio.blank();
            MemCardEject();
            MemCardSelect();
            MemCardInsert();
            menuSync(MENUT_FILE);
            GameInpCheckMouse();
        }
        break;
    case MENU_MEMCARD_INSERT:
        if (bDrvOkay && !kNetGame
                && (BurnDrvGetHardwareCode() & HARDWARE_PUBLIC_MASK) == HARDWARE_SNK_NEOGEO) {
            MemCardInsert();
        }
        break;
    case MENU_MEMCARD_EJECT:
        if (bDrvOkay && !kNetGame
                && (BurnDrvGetHardwareCode() & HARDWARE_PUBLIC_MASK) == HARDWARE_SNK_NEOGEO) {
            MemCardEject();
        }
        break;

    case MENU_MEMCARD_TOGGLE:
        if (bDrvOkay && !kNetGame
                && (BurnDrvGetHardwareCode() & HARDWARE_PUBLIC_MASK) == HARDWARE_SNK_NEOGEO) {
            MemCardToggle();
        }
        break;

    case MENU_STATE_LOAD_DIALOG:
        HK_loadStateDialog(0);
        break;
    case MENU_STATE_SAVE_DIALOG:
        HK_saveStateDialog(0);
        return;
    case MENU_STATE_PREVSLOT:
        HK_prevState(0);
        break;
    case MENU_STATE_NEXTSLOT:
        HK_nextState(0);
        break;
    case MENU_STATE_LOAD_SLOT:
        HK_loadCurState(0);
        break;
    case MENU_STATE_SAVE_SLOT:
        HK_saveCurState(0);
        break;

    case MENU_STATE_ALLRAM:
        bDrvSaveAll = !bDrvSaveAll;
        menuSync(MENUT_FILE);
        break;

    case MENU_WLOGSTART:
        audio.blank();
        waveLogStart();
        break;
    case MENU_WLOGEND:
        audio.blank();
        waveLogStop();
        break;

    case MENU_NOSTRETCH:
        bVidCorrectAspect = 0;
        bVidFullStretch = 0;
        simpleReinitScrn(false);
        menuSync(MENUT_SETTING);
        break;
    case MENU_STRETCH:
        bVidFullStretch = 1;
        bVidCorrectAspect = 0;
        simpleReinitScrn(false);
        menuSync(MENUT_SETTING);
        break;
    case MENU_ASPECT:
        bVidCorrectAspect = 1;
        bVidFullStretch = 0;
        simpleReinitScrn(false);
        menuSync(MENUT_SETTING);
        break;

    case MENU_FULL:
        HK_fullscreen(0);
        return;

    case MENU_AUTOSIZE:
        if (nWindowSize != 0) {
            nWindowSize = 0;
            simpleReinitScrn(false);
            menuSync(MENUT_SETTING);
        }
        break;
    case MENU_WINDOWSIZE1X:
        HK_windowSize(1);
        break;
    case MENU_WINDOWSIZE2X:
        HK_windowSize(2);
        break;
    case MENU_WINDOWSIZE3X:
        HK_windowSize(3);
        break;
    case MENU_WINDOWSIZE4X:
        HK_windowSize(4);
        break;
    case MENU_WINDOWSIZEMAX:
        HK_windowSizeMax(0);
        break;

    case MENU_HOTKEYS:
        MHkeysCreate(hDlg);
        break;

    case MENU_INPUT:
        HK_configPad(0);
        break;

    case MENU_DIPSW:
        HK_setDips(0);
        break;

    case MENU_SETCPUCLOCK:
        audio.blank();
        CPUClockDialog(hDlg);
        menuSync(MENUT_GAME);
        GameInpCheckMouse();
        break;
    case MENU_RESETCPUCLOCK:
        nBurnCPUSpeedAdjust = 0x0100;
        menuSync(MENUT_GAME);
        break;

    // ==> rom save
    case MENU_SAVEC:
        bsavedecryptedcs = !bsavedecryptedcs;
        menuSync(MENUT_GAME);
        break;
    case MENU_SAVEP:
        bsavedecryptedps = !bsavedecryptedps;
        menuSync(MENUT_GAME);
        break;
    case MENU_SAVES:
        bsavedecrypteds1 = !bsavedecrypteds1;
        menuSync(MENUT_GAME);
        break;
    case MENU_SAVEV:
        bsavedecryptedvs = !bsavedecryptedvs;
        menuSync(MENUT_GAME);
        break;
    case MENU_SAVEM:
        bsavedecryptedm1 = !bsavedecryptedm1;
        menuSync(MENUT_GAME);
        break;
    case MENU_SAVEXOR:
        bsavedecryptedxor = !bsavedecryptedxor;
        menuSync(MENUT_GAME);
        break;
    case MENU_SAVEDPROM:
        bsavedecryptedprom = !bsavedecryptedprom;
        menuSync(MENUT_GAME);
        break;
    // <== rom save

    case MENU_LANGUAGE_SELECT:
        if (useDialogs()) {
            if (!FBALocaliseLoad()) {
                menuReinit();
            }
        }
        break;
    case MENU_LANGUAGE_UNLOAD:
        _tcsncpy(szLanguage, _T(""), sizearray(szLanguage));
        FBALocaliseExit();
        menuReinit();
        break;

    case MENU_GAMELIST_SELECT:
        if (useDialogs()) {
            loadGamelist();
        }
        break;
    case MENU_GAMELIST_EXPORT:
        if (useDialogs()) {
            createGamelist();
        }
        break;

    case MENU_MISCDIR_EDIT:
        if (useDialogs()) {
            pathSheetCreate(hDlg);
        }
        break;
    case MENU_ROMDIR_EDIT:
        if (useDialogs()) {
            RomsDirCreate(hDlg);
        }
        break;

    case MENU_ENABLECHEAT:
        HK_cheatEditor(0);
        break;

#ifndef NO_CHEATSEARCH
    case MENU_CHEATSEARCH:
        HK_cheatSearch(0);
        break;
#endif

    // ==> simple jukebox, added by regret
    case MENU_JUKEBOX:
        if (useDialogs()) {
            jukeCreate();
            InputSetCooperativeLevel(false, !bAlwaysProcessKey);
        }
        break;
    // <== simple jukebox

    case MENU_DEBUG:
        if (useDialogs()) {
            InputSetCooperativeLevel(false, !bAlwaysProcessKey);
            DebugCreate();
        }
        break;

    case MENU_SAVESNAP: {
        HK_screenShot(0);
        break;
    }
    case MENU_SNAPFACT:
        HK_shotFactory(0);
        break;

    case MENU_SKIN_SELECT:
        if (useDialogs()) {
            if (selectSkin() == 0) {
                simpleReinitScrn(true);
            }
        }
        break;
    case MENU_SKIN_UNLOAD:
        _tcsncpy(szPlaceHolder, _T(""), sizearray(szPlaceHolder));
        simpleReinitScrn(true);
        break;

    case MENU_CLRMAMEPRO_XML:
        if (useDialogs()) {
            createDatfileWindows(1);
        }
        break;
    case MENU_CLRMAME_PRO:
        if (useDialogs()) {
            createDatfileWindows(0);
        }
        break;

    case MENU_SAVESET:
        configAppSaveXml();
        break;
    case MENU_LOADSET:
        configAppLoadXml();
        POST_INITIALISE_MESSAGE;
        break;

    case MENU_ABOUT:
        if (useDialogs()) {
            InputSetCooperativeLevel(false, !bAlwaysProcessKey);
            audio.blank();
            AboutCreate(hDlg);
            GameInpCheckMouse();
        }
        break;
    case MENU_SYSINFO:
        if (useDialogs()) {
            InputSetCooperativeLevel(false, !bAlwaysProcessKey);
            audio.blank();
            SystemInfoCreate(hDlg);
            GameInpCheckMouse();
        }
        break;

    case MENU_CONTENTS: {
        if (useDialogs()) {
            FILE* fp = _tfopen(_T("readme.txt"), _T("r"));
            if (fp) {
                fclose(fp);
                ShellExecute(NULL, _T("open"), _T("readme.txt"), NULL, NULL, SW_SHOWNORMAL);
            }
        }
        break;
    }

    case MENU_WWW_HOME:
        ShellExecute(NULL, _T("open"), _T("http://www.barryharris.me.uk/"), NULL, NULL, SW_SHOWNORMAL);
        break;
    case MENU_WWW_FORUM:
        ShellExecute(NULL, _T("open"), _T("http://neosource.1emulation.com/forums/"), NULL, NULL, SW_SHOWNORMAL);
        break;
    case MENU_WWW_FORUM1:
        ShellExecute(NULL, _T("open"), _T("http://www.egcg.com.cn/bbs/"), NULL, NULL, SW_SHOWNORMAL);
        break;

    // filters
    case MENU_SOFT_NONE:
        vidUseFilter = 0;
        nVidFilter = 0;
        VidReinit();
        menuSync(MENUT_SETTING);
        break;

    case MENU_SOFT_EPXB:
    case MENU_SOFT_EPXC:
    case MENU_SOFT_SCALE2X:
    case MENU_SOFT_SCALE3X:
    case MENU_SOFT_2XSAI:
    case MENU_SOFT_SUPER2XSAI:
    case MENU_SOFT_SUPEREAGLE:
    case MENU_SOFT_2XPMHQ:
    case MENU_SOFT_HQ2X:
    case MENU_SOFT_HQ2XS:
    case MENU_SOFT_HQ2XBOLD:
    case MENU_SOFT_HQ3X:
    case MENU_SOFT_HQ3XS:
    case MENU_SOFT_HQ3XBOLD:
    case MENU_SOFT_SCANLINE:
    case MENU_SOFT_SCANLINE50:
    case MENU_SOFT_SCANLINE25:
    case MENU_SOFT_INTERSCANLINE:
    case MENU_SOFT_INTERSCANLINE50:
    case MENU_SOFT_INTERSCANLINE25:
        vidUseFilter = 1;
        nVidFilter = id - MENU_SOFT_NONE;
        scrnSize();
        VidSwitchFilter(nVidFilter);
        menuSync(MENUT_SETTING);
        break;

    case MENU_FILTER_AUTOSIZE:
        vidForceFilterSize = !vidForceFilterSize;
        simpleReinitScrn(true);
        menuSync(MENUT_SETTING);
        break;

    // Options for blitters
    case MENU_FILTER_POINT:
        if (vidFilterLinear) {
            vidFilterLinear = 0;
            VidReinit();
            menuSync(MENUT_SETTING);
        }
        break;
    case MENU_FILTER_LINEAR:
        if (!vidFilterLinear) {
            vidFilterLinear = 1;
            VidReinit();
            menuSync(MENUT_SETTING);
        }
        break;

    case MENU_CONFIGALL:
        if (useDialogs()) {
            preferenceCreate(hDlg);
            setWindowAspect();
            menuReinit();
            simpleReinitScrn(true);
            mediaReInitAudio();
        }
        break;
    case MENU_VIDEOCONFIG:
        if (useDialogs()) {
            prefVideoCreate(hDlg);
            setWindowAspect();
            simpleReinitScrn(true);
        }
        break;
    case MENU_AUDIOCONFIG:
        if (useDialogs()) {
            prefAudioCreate(hDlg);
            mediaReInitAudio();
        }
        break;
    case MENU_MISCCONFIG:
        if (useDialogs()) {
            prefMiscCreate(hDlg);
            menuReinit();
            VidReinit();
        }
        break;

//		default:
//			printf("  * Command %i sent.\n");
    }

    if (ChatActivated()) {
        switch (codeNotify) {
        case EN_CHANGE: {
            bEditTextChanged = true;
            SendMessage(GetChatWindow(), WM_GETTEXT, (WPARAM)MAX_CHAT_SIZE + 1, (LPARAM)EditText);
            break;
        }
        case EN_KILLFOCUS: {
            ActivateChat();
            break;
        }
        case EN_MAXTEXT: {
            VidSNewShortMsg(FBALoadStringEx(IDS_NETPLAY_TOOMUCH), 0xFF3F3F);
            break;
        }
        }
    }
}
Exemplo n.º 7
0
void CReplayManager::StopHighlights()
{
	StopReplay();
}
Exemplo n.º 8
0
void CReplayManager::RestoreSnapshot()
{
	float watchDuration = gpGlobals->curtime - m_flReplayStartTime;

	if (watchDuration > m_flRunDuration)
	{
		if (m_nReplayRunIndex < m_nMaxReplayRuns - 1)
		{
			m_nReplayRunIndex += 1;
			m_bIsReplayStart = true;
		}
		else if (m_bIsHighlightReplay)
		{
			m_nReplayIndex = FindNextHighlightReplayIndex(m_nReplayIndex + 1, SDKGameRules()->State_Get());

			if (m_nReplayIndex == -1)
			{
				StopReplay();
				return;
			}

			m_nReplayRunIndex = 0;
			m_bIsReplayStart = true;
			m_bIsHighlightStart = true;
		}
		else
		{
			StopReplay();
			return;
		}
	}

	MatchEvent *pMatchEvent = m_MatchEvents[m_nReplayIndex];

	if (m_bIsReplayStart)
	{
		m_bIsReplayStart = false;
		m_bAtMinGoalPos = pMatchEvent->atMinGoalPos;
		m_bIsReplaying = true;
		m_bReplayIsPending = false;
		CalcMaxReplayRunsAndDuration(pMatchEvent, gpGlobals->curtime);
		watchDuration = 0;

		if (m_bIsHighlightReplay && m_bIsHighlightStart)
		{
			m_bIsHighlightStart = false;

			if (pMatchEvent->matchEventType == MATCH_EVENT_GOAL)
			{
				IGameEvent *pEvent = gameeventmanager->CreateEvent("highlight_goal");
				if (pEvent)
				{
					pEvent->SetInt("second", pMatchEvent->second);
					pEvent->SetInt("match_period", pMatchEvent->matchPeriod);
					pEvent->SetInt("scoring_team", pMatchEvent->team);
					pEvent->SetString("scorer", pMatchEvent->pPlayer1Data ? pMatchEvent->pPlayer1Data->m_szName : "");
					pEvent->SetString("first_assister", pMatchEvent->pPlayer2Data ? pMatchEvent->pPlayer2Data->m_szName : "");
					pEvent->SetString("second_assister", pMatchEvent->pPlayer3Data ? pMatchEvent->pPlayer3Data->m_szName : "");
					gameeventmanager->FireEvent(pEvent);
				}
			}
			else if (pMatchEvent->matchEventType == MATCH_EVENT_OWNGOAL)
			{
				IGameEvent *pEvent = gameeventmanager->CreateEvent("highlight_owngoal");
				if (pEvent)
				{
					pEvent->SetInt("second", pMatchEvent->second);
					pEvent->SetInt("match_period", pMatchEvent->matchPeriod);
					pEvent->SetInt("scoring_team", pMatchEvent->team);
					pEvent->SetString("scorer", pMatchEvent->pPlayer1Data ? pMatchEvent->pPlayer1Data->m_szName : "");
					gameeventmanager->FireEvent(pEvent);
				}
			}
			else if (pMatchEvent->matchEventType == MATCH_EVENT_MISS)
			{
				IGameEvent *pEvent = gameeventmanager->CreateEvent("highlight_miss");
				if (pEvent)
				{
					pEvent->SetInt("second", pMatchEvent->second);
					pEvent->SetInt("match_period", pMatchEvent->matchPeriod);
					pEvent->SetInt("finishing_team", pMatchEvent->team);
					pEvent->SetString("finisher", pMatchEvent->pPlayer1Data ? pMatchEvent->pPlayer1Data->m_szName : "");
					pEvent->SetString("first_assister", pMatchEvent->pPlayer2Data ? pMatchEvent->pPlayer2Data->m_szName : "");
					pEvent->SetString("second_assister", pMatchEvent->pPlayer3Data ? pMatchEvent->pPlayer3Data->m_szName : "");
					gameeventmanager->FireEvent(pEvent);
				}
			}
			else if (pMatchEvent->matchEventType == MATCH_EVENT_KEEPERSAVE)
			{
				IGameEvent *pEvent = gameeventmanager->CreateEvent("highlight_keepersave");
				if (pEvent)
				{
					pEvent->SetInt("second", pMatchEvent->second);
					pEvent->SetInt("match_period", pMatchEvent->matchPeriod);
					pEvent->SetInt("keeper_team", pMatchEvent->team);
					pEvent->SetString("keeper", pMatchEvent->pPlayer1Data ? pMatchEvent->pPlayer1Data->m_szName : "");
					pEvent->SetString("finisher", pMatchEvent->pPlayer2Data ? pMatchEvent->pPlayer2Data->m_szName : "");
					gameeventmanager->FireEvent(pEvent);
				}
			}
			else if (pMatchEvent->matchEventType == MATCH_EVENT_REDCARD)
			{
				IGameEvent *pEvent = gameeventmanager->CreateEvent("highlight_redcard");
				if (pEvent)
				{
					pEvent->SetInt("second", pMatchEvent->second);
					pEvent->SetInt("match_period", pMatchEvent->matchPeriod);
					pEvent->SetInt("fouling_team", pMatchEvent->team);
					pEvent->SetString("fouling_player", pMatchEvent->pPlayer1Data ? pMatchEvent->pPlayer1Data->m_szName : "");
					gameeventmanager->FireEvent(pEvent);
				}
			}
		}
	}

	CBall *pRealBall = GetMatchBall();
	if (pRealBall && !(pRealBall->GetEffects() & EF_NODRAW))
	{
		pRealBall->AddEffects(EF_NODRAW);
		pRealBall->AddSolidFlags(FSOLID_NOT_SOLID);
	}

	for (int i = 1; i <= gpGlobals->maxClients; i++)
	{
		CSDKPlayer *pRealPl = ToSDKPlayer(UTIL_PlayerByIndex(i));
		if (!CSDKPlayer::IsOnField(pRealPl))
			continue;

		if (!(pRealPl->GetEffects() & EF_NODRAW))
		{
			pRealPl->AddEffects(EF_NODRAW);
			pRealPl->DoServerAnimationEvent(PLAYERANIMEVENT_CANCEL);
			pRealPl->AddSolidFlags(FSOLID_NOT_SOLID);
			pRealPl->SetMoveType(MOVETYPE_NONE);
		}
		
		if (pRealPl->GetPlayerBall() && !(pRealPl->GetPlayerBall()->GetEffects() & EF_NODRAW))
		{
			pRealPl->GetPlayerBall()->AddEffects(EF_NODRAW);
			pRealPl->GetPlayerBall()->AddSolidFlags(FSOLID_NOT_SOLID);
		}
	}

	float normalRunDuration = m_flRunDuration - m_flSlowMoDuration;

	if (watchDuration > normalRunDuration)
		watchDuration = normalRunDuration + m_flSlowMoCoeff * (watchDuration - normalRunDuration);

	// To find the correct snapshot calculate the time passed since we started watching the replay and match it to the right snapshot in our recording list

	Snapshot *pNextSnap = NULL;
	Snapshot *pSnap = NULL;
	float snapDuration = 0;

	// Traverse backwards looking for a recorded snapshot matching the time since replay start
	for (int i = pMatchEvent->snapshots.Count() - 1; i >= 0; i--)
	{
		// Save the snapshot of the previous iteration, so we have a snapshot to interpolate to when we found our target snapshot
		pNextSnap = pSnap;

		// Save the current snapshot
		pSnap = pMatchEvent->snapshots[i];

		// Snapshots have absolute match times, so calculate the relative time span between the first recorded snapshot and the current snapshot
		snapDuration = pSnap->snaptime - pMatchEvent->snapshots[0]->snaptime - m_flReplayStartTimeOffset;

		// We usually only play the last x seconds of a replay instead of the whole thing, so subtract the start time offset from the time since the first snapshot.
		// The first snapshot which time span is equal or shorter than the duration since replay start is the one which should be shown next.
		if (snapDuration <= watchDuration)
			break;
	}

	// No snapshots in the list
	if (!pSnap)
		return;

	float nextSnapDuration;

	if (pNextSnap)
		nextSnapDuration = pNextSnap->snaptime - pMatchEvent->snapshots[0]->snaptime - m_flReplayStartTimeOffset;
	else
		nextSnapDuration = 0;

	BallSnapshot *pBallSnap = pSnap->pBallSnapshot;

	if (pBallSnap)
	{
		if (!m_pBall)
		{
			m_pBall = (CReplayBall *)CreateEntityByName("replayball");
			m_pBall->Spawn();
		}

		if (Q_strcmp(m_pBall->m_szSkinName, GetMatchBall()->GetSkinName()))
			Q_strncpy(m_pBall->m_szSkinName.GetForModify(), GetMatchBall()->GetSkinName(), MAX_KITNAME_LENGTH);

		m_pBall->VPhysicsGetObject()->SetPosition(pBallSnap->pos, pBallSnap->ang, false);
		m_pBall->VPhysicsGetObject()->SetVelocity(&pBallSnap->vel, &pBallSnap->rot);
	}
	else
	{
		UTIL_Remove(m_pBall);
		m_pBall = NULL;
	}

	float frac;

	if (pNextSnap)
	{
		// Calc fraction between both snapshots
		frac = clamp((watchDuration - snapDuration) / (nextSnapDuration - snapDuration), 0.0f, 1.0f);
	}
	else
	{
		// Exact snapshot time matched or no next snapshot to interpolate to
		frac = 0.0f;
	}

	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 11; j++)
		{
			PlayerSnapshot *pPlSnap = pSnap->pPlayerSnapshot[i][j];
			if (!pPlSnap)
			{
				UTIL_Remove(m_pPlayers[i][j]);
				m_pPlayers[i][j] = NULL;
				continue;
			}

			if (!m_pPlayers[i][j])
			{
				m_pPlayers[i][j] = (CReplayPlayer *)CreateEntityByName("replayplayer");
				m_pPlayers[i][j]->Spawn();
				m_pPlayers[i][j]->SetNumAnimOverlays(NUM_LAYERS_WANTED);
			}

			CReplayPlayer *pPl = m_pPlayers[i][j];

			pPl->m_nTeamNumber = pPlSnap->teamNumber;
			pPl->m_nTeamPosIndex = pPlSnap->teamPosIndex;
			pPl->m_bIsKeeper = pPlSnap->isKeeper;
			pPl->m_nShirtNumber = pPlSnap->shirtNumber;

			if (Q_strcmp(pPl->m_szPlayerName, pPlSnap->pPlayerData->m_szName))
				Q_strncpy(pPl->m_szPlayerName.GetForModify(), pPlSnap->pPlayerData->m_szName, MAX_PLAYER_NAME_LENGTH);

			if (Q_strcmp(pPl->m_szShirtName, pPlSnap->pPlayerData->m_szShirtName))
				Q_strncpy(pPl->m_szShirtName.GetForModify(), pPlSnap->pPlayerData->m_szShirtName, MAX_PLAYER_NAME_LENGTH);

			pPl->m_nSkinIndex = pPlSnap->skinIndex;
			pPl->m_nBody = pPlSnap->body;

			PlayerSnapshot *pNextPlSnap = NULL;

			if (pNextSnap)
				pNextPlSnap = pNextSnap->pPlayerSnapshot[i][j];

			if (frac > 0.0f && pNextPlSnap)
			{
				pPl->SetLocalOrigin(Lerp( frac, pPlSnap->pos, pNextPlSnap->pos  ));
				//pPl->SetLocalVelocity(Lerp( frac, pPlSnap->vel, pNextPlSnap->vel  ));
				pPl->SetLocalAngles(Lerp( frac, pPlSnap->ang, pNextPlSnap->ang ));
			}
			else
			{
				pPl->SetLocalOrigin(pPlSnap->pos);
				//pPl->SetLocalVelocity(pPlSnap->vel);
				pPl->SetLocalAngles(pPlSnap->ang);
			}

			bool interpolationAllowed;

			if (frac > 0.0f && pNextPlSnap && pPlSnap->masterSequence == pNextPlSnap->masterSequence)
			{
				// If the master state changes, all layers will be invalid too, so don't interp (ya know, interp barely ever happens anyway)
				interpolationAllowed = true;
			}
			else
				interpolationAllowed = false;

			// First do the master settings
			if (interpolationAllowed)
			{
				pPl->SetSequence( Lerp( frac, pPlSnap->masterSequence, pNextPlSnap->masterSequence ) );
				pPl->SetCycle( Lerp( frac, pPlSnap->masterCycle, pNextPlSnap->masterCycle ) );

				if( pPlSnap->masterCycle > pNextPlSnap->masterCycle )
				{
					// the older record is higher in frame than the newer, it must have wrapped around from 1 back to 0
					// add one to the newer so it is lerping from .9 to 1.1 instead of .9 to .1, for example.
					float newCycle = Lerp( frac, pPlSnap->masterCycle, pNextPlSnap->masterCycle + 1 );
					pPl->SetCycle(newCycle < 1 ? newCycle : newCycle - 1 );// and make sure .9 to 1.2 does not end up 1.05
				}
				else
				{
					pPl->SetCycle( Lerp( frac, pPlSnap->masterCycle, pNextPlSnap->masterCycle ) );
				}

				pPl->SetPoseParameter(pPl->GetModelPtr(), 4, Lerp(frac, pPlSnap->moveX, pNextPlSnap->moveX));
				pPl->SetPoseParameter(pPl->GetModelPtr(), 3, Lerp(frac, pPlSnap->moveY, pNextPlSnap->moveY));
			}
			else
			{
				pPl->SetSequence(pPlSnap->masterSequence);
				pPl->SetCycle(pPlSnap->masterCycle);
				pPl->SetPoseParameter(pPl->GetModelPtr(), 4, pPlSnap->moveX);
				pPl->SetPoseParameter(pPl->GetModelPtr(), 3, pPlSnap->moveY);
			}

			// Now do all the layers
			for (int layerIndex = 0; layerIndex < NUM_LAYERS_WANTED; layerIndex++)
			{
				CAnimationLayer *pTargetLayer = pPl->GetAnimOverlay(layerIndex);
				if(!pTargetLayer)
					continue;

				LayerRecord *pSourceLayer = &pPlSnap->layerRecords[layerIndex];

				pTargetLayer->m_nOrder = pSourceLayer->order;
				pTargetLayer->m_nSequence = pSourceLayer->sequence;
				pTargetLayer->m_flPlaybackRate = pSourceLayer->playbackRate;
				pTargetLayer->m_fFlags = pSourceLayer->flags;
				pTargetLayer->m_bLooping = pSourceLayer->looping;
				pTargetLayer->m_bSequenceFinished = pSourceLayer->sequenceFinished;
				pTargetLayer->m_nPriority = pSourceLayer->priority;
				pTargetLayer->m_nActivity = pSourceLayer->activity;
				pTargetLayer->m_flLastAccess = pSourceLayer->lastAccess;
				pTargetLayer->m_flLastEventCheck = pSourceLayer->lastEventCheck;

				if (interpolationAllowed)
				{
					LayerRecord *pNextSourceLayer = &pNextPlSnap->layerRecords[layerIndex];

					if(pSourceLayer->order == pNextSourceLayer->order && pSourceLayer->sequence == pNextSourceLayer->sequence)
					{
						// We can't interpolate across a sequence or order change
						if( pSourceLayer->cycle > pNextSourceLayer->cycle )
						{
							// the older record is higher in frame than the newer, it must have wrapped around from 1 back to 0
							// add one to the newer so it is lerping from .9 to 1.1 instead of .9 to .1, for example.
							float newCycle = Lerp( frac, pSourceLayer->cycle, pNextSourceLayer->cycle + 1 );
							pTargetLayer->m_flCycle = newCycle < 1 ? newCycle : newCycle - 1;// and make sure .9 to 1.2 does not end up 1.05
						}
						else
						{
							pTargetLayer->m_flCycle = Lerp(frac, pSourceLayer->cycle, pNextSourceLayer->cycle);
						}

						pTargetLayer->m_flWeight = Lerp(frac, pSourceLayer->weight, pNextSourceLayer->weight);
						pTargetLayer->m_flLayerAnimtime = Lerp(frac, pSourceLayer->layerAnimtime, pNextSourceLayer->layerAnimtime);
						pTargetLayer->m_flBlendIn = Lerp(frac, pSourceLayer->blendIn, pNextSourceLayer->blendIn);
						pTargetLayer->m_flBlendOut = Lerp(frac, pSourceLayer->blendOut, pNextSourceLayer->blendOut);
						pTargetLayer->m_flPrevCycle = Lerp(frac, pSourceLayer->prevCycle, pNextSourceLayer->prevCycle);
						pTargetLayer->m_flKillDelay = Lerp(frac, pSourceLayer->killDelay, pNextSourceLayer->killDelay);
						pTargetLayer->m_flKillRate = Lerp(frac, pSourceLayer->killRate, pNextSourceLayer->killRate);
						pTargetLayer->m_flLayerFadeOuttime = Lerp(frac, pSourceLayer->layerFadeOuttime, pNextSourceLayer->layerFadeOuttime);
					}
				}
				else
				{
					//Either no interp, or interp failed.  Just use record.
					pTargetLayer->m_flCycle = pSourceLayer->cycle;
					pTargetLayer->m_flWeight = pSourceLayer->weight;
					pTargetLayer->m_flLayerAnimtime = pSourceLayer->layerAnimtime;
					pTargetLayer->m_flBlendIn = pSourceLayer->blendIn;
					pTargetLayer->m_flBlendOut = pSourceLayer->blendOut;
					pTargetLayer->m_flPrevCycle = pSourceLayer->prevCycle;
					pTargetLayer->m_flKillDelay = pSourceLayer->killDelay;
					pTargetLayer->m_flKillRate = pSourceLayer->killRate;
					pTargetLayer->m_flLayerFadeOuttime = pSourceLayer->layerFadeOuttime;
				}
			}
		}
	}
}