diff --git a/src/app/app.cpp b/src/app/app.cpp
index 74cc7e6b..c2264cf8 100644
--- a/src/app/app.cpp
+++ b/src/app/app.cpp
@@ -137,13 +137,6 @@ CApplication::CApplication(CSystemUtils* systemUtils)
     m_absTime = 0.0f;
     m_relTime = 0.0f;
 
-    m_baseTimeStamp = m_systemUtils->CreateTimeStamp();
-    m_curTimeStamp = m_systemUtils->CreateTimeStamp();
-    m_lastTimeStamp = m_systemUtils->CreateTimeStamp();
-
-    m_manualFrameLast = m_systemUtils->CreateTimeStamp();
-    m_manualFrameTime = m_systemUtils->CreateTimeStamp();
-
 
     m_joystickEnabled = false;
 
@@ -161,13 +154,6 @@ CApplication::CApplication(CSystemUtils* systemUtils)
 
 CApplication::~CApplication()
 {
-    m_systemUtils->DestroyTimeStamp(m_baseTimeStamp);
-    m_systemUtils->DestroyTimeStamp(m_curTimeStamp);
-    m_systemUtils->DestroyTimeStamp(m_lastTimeStamp);
-
-    m_systemUtils->DestroyTimeStamp(m_manualFrameLast);
-    m_systemUtils->DestroyTimeStamp(m_manualFrameTime);
-
     m_joystickEnabled = false;
 
     m_controller.reset();
@@ -674,7 +660,7 @@ bool CApplication::Create()
         {
             GetLogger()->Error("Unknown graphics device: %s\n", graphics.c_str());
             GetLogger()->Info("Changing to default device\n");
-            m_systemUtils->SystemDialog(SDT_ERROR, "Graphics initialization error", "You have selected invalid graphics device with -graphics switch. Game will use default OpenGL device instead.");
+            m_systemUtils->SystemDialog(SystemDialogType::ERROR, "Graphics initialization error", "You have selected invalid graphics device with -graphics switch. Game will use default OpenGL device instead.");
             m_device = Gfx::CreateDevice(m_deviceConfig, "opengl");
         }
     }
@@ -1057,9 +1043,9 @@ int CApplication::Run()
 
     MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start
 
-    SystemTimeStamp *previousTimeStamp = m_systemUtils->CreateTimeStamp();
-    SystemTimeStamp *currentTimeStamp = m_systemUtils->CreateTimeStamp();
-    SystemTimeStamp *interpolatedTimeStamp = m_systemUtils->CreateTimeStamp();
+    SystemTimeStamp previousTimeStamp{};
+    SystemTimeStamp currentTimeStamp{};
+    SystemTimeStamp interpolatedTimeStamp{};
 
     while (true)
     {
@@ -1163,11 +1149,11 @@ int CApplication::Run()
             // If game speed is increased then we do extra ticks per loop iteration to improve physics accuracy.
             int numTickSlices = static_cast<int>(GetSimulationSpeed());
             if(numTickSlices < 1) numTickSlices = 1;
-            m_systemUtils->CopyTimeStamp(previousTimeStamp, m_curTimeStamp);
-            m_systemUtils->GetCurrentTimeStamp(currentTimeStamp);
+            previousTimeStamp = m_curTimeStamp;
+            currentTimeStamp = m_systemUtils->GetCurrentTimeStamp();
             for(int tickSlice = 0; tickSlice < numTickSlices; tickSlice++)
             {
-                m_systemUtils->InterpolateTimeStamp(interpolatedTimeStamp, previousTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast<float>(numTickSlices));
+                interpolatedTimeStamp = m_systemUtils->TimeStampLerp(previousTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast<float>(numTickSlices));
                 Event event = CreateUpdateEvent(interpolatedTimeStamp);
                 if (event.type != EVENT_NULL && m_controller != nullptr)
                 {
@@ -1198,9 +1184,6 @@ int CApplication::Run()
     }
 
 end:
-    m_systemUtils->DestroyTimeStamp(previousTimeStamp);
-    m_systemUtils->DestroyTimeStamp(currentTimeStamp);
-    m_systemUtils->DestroyTimeStamp(interpolatedTimeStamp);
 
     return m_exitCode;
 }
@@ -1539,17 +1522,15 @@ void CApplication::StartLoadingMusic()
     std::thread{[this]()
     {
         GetLogger()->Debug("Cache sounds...\n");
-        SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp();
-        m_systemUtils->GetCurrentTimeStamp(musicLoadStart);
+        SystemTimeStamp musicLoadStart{m_systemUtils->GetCurrentTimeStamp()};
 
         m_sound->Reset();
         m_sound->CacheAll();
 
-        SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp();
-        m_systemUtils->GetCurrentTimeStamp(musicLoadEnd);
-        float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC);
+        SystemTimeStamp musicLoadEnd{m_systemUtils->GetCurrentTimeStamp()};
+        float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, SystemTimeUnit::MILLISECONDS);
         GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
-    }).detach();
+    }}.detach();
 }
 
 bool CApplication::GetSimulationSuspended() const
@@ -1561,20 +1542,20 @@ void CApplication::SetSimulationSpeed(float speed)
 {
     m_simulationSpeed = speed;
 
-    m_systemUtils->CopyTimeStamp(m_baseTimeStamp, m_curTimeStamp);
+    m_baseTimeStamp = m_curTimeStamp;
     m_realAbsTimeBase = m_realAbsTime;
     m_absTimeBase = m_exactAbsTime;
 
     GetLogger()->Info("Simulation speed = %.2f\n", speed);
 }
 
-Event CApplication::CreateUpdateEvent(SystemTimeStamp *newTimeStamp)
+Event CApplication::CreateUpdateEvent(SystemTimeStamp newTimeStamp)
 {
     if (m_simulationSuspended)
         return Event(EVENT_NULL);
 
-    m_systemUtils->CopyTimeStamp(m_lastTimeStamp, m_curTimeStamp);
-    m_systemUtils->CopyTimeStamp(m_curTimeStamp, newTimeStamp);
+    m_lastTimeStamp = m_curTimeStamp;
+    m_curTimeStamp = newTimeStamp;
 
     long long absDiff = m_systemUtils->TimeStampExactDiff(m_baseTimeStamp, m_curTimeStamp);
     long long newRealAbsTime = m_realAbsTimeBase + absDiff;
diff --git a/src/app/app.h b/src/app/app.h
index 02e12124..60d11c42 100644
--- a/src/app/app.h
+++ b/src/app/app.h
@@ -297,7 +297,7 @@ protected:
     //! If applicable, creates a virtual event to match the changed state as of new event
     Event       CreateVirtualEvent(const Event& sourceEvent);
     //! Prepares a simulation update event
-    TEST_VIRTUAL Event CreateUpdateEvent(SystemTimeStamp *newTimeStamp);
+    TEST_VIRTUAL Event CreateUpdateEvent(SystemTimeStamp newTimeStamp);
     //! Logs debug data for event
     void        LogEvent(const Event& event);
 
diff --git a/src/app/main.cpp b/src/app/main.cpp
index 1cb8171a..002bd4f8 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -177,7 +177,7 @@ int main(int argc, char *argv[])
     ParseArgsStatus status = app.ParseArguments(argc, argv);
     if (status == PARSE_ARGS_FAIL)
     {
-        systemUtils->SystemDialog(SDT_ERROR, "COLOBOT - Fatal Error", "Invalid commandline arguments!\n");
+        systemUtils->SystemDialog(SystemDialogType::ERROR, "COLOBOT - Fatal Error", "Invalid commandline arguments!\n");
         return app.GetExitCode();
     }
     else if (status == PARSE_ARGS_HELP)
@@ -190,7 +190,7 @@ int main(int argc, char *argv[])
         code = app.GetExitCode();
         if (code != 0 && !app.GetErrorMessage().empty())
         {
-            systemUtils->SystemDialog(SDT_ERROR, "COLOBOT - Fatal Error", app.GetErrorMessage());
+            systemUtils->SystemDialog(SystemDialogType::ERROR, "COLOBOT - Fatal Error", app.GetErrorMessage());
         }
         logger.Info("Didn't run main loop. Exiting with code %d\n", code);
         return code;
diff --git a/src/app/signal_handlers.cpp b/src/app/signal_handlers.cpp
index 1558f4be..99c04d5d 100644
--- a/src/app/signal_handlers.cpp
+++ b/src/app/signal_handlers.cpp
@@ -162,7 +162,7 @@ void CSignalHandlers::ReportError(const std::string& errorMessage)
 
     std::cerr << std::endl << msg.str() << std::endl;
 
-    m_systemUtils->SystemDialog(SDT_ERROR, "Unhandled exception occurred!", msg.str());
+    m_systemUtils->SystemDialog(SystemDialogType::ERROR, "Unhandled exception occurred!", msg.str());
 
     if (canSave && !triedSaving)
     {
@@ -172,13 +172,13 @@ void CSignalHandlers::ReportError(const std::string& errorMessage)
         msg << std::endl;
         msg << "Do you want to try saving now?";
 
-        SystemDialogResult result = m_systemUtils->SystemDialog(SDT_YES_NO, "Try to save?", msg.str());
-        if (result == SDR_YES)
+        SystemDialogResult result = m_systemUtils->SystemDialog(SystemDialogType::YES_NO, "Try to save?", msg.str());
+        if (result == SystemDialogResult::YES)
         {
             triedSaving = true;
             CResourceManager::CreateNewDirectory("crashsave");
             robotMain->IOWriteScene("crashsave/data.sav", "crashsave/cbot.run", "crashsave/screen.png", "Backup at the moment of a crash", true);
-            m_systemUtils->SystemDialog(SDT_INFO, "Try to save?", "Saving finished.\nPlease restart the game now");
+            m_systemUtils->SystemDialog(SystemDialogType::INFO, "Try to save?", "Saving finished.\nPlease restart the game now");
         }
     }
 
diff --git a/src/common/system/system.cpp b/src/common/system/system.cpp
index 46fa81e2..d007fcb1 100644
--- a/src/common/system/system.cpp
+++ b/src/common/system/system.cpp
@@ -61,17 +61,17 @@ SystemDialogResult CSystemUtils::ConsoleSystemDialog(SystemDialogType type, cons
 {
     switch (type)
     {
-        case SDT_INFO:
+        case SystemDialogType::INFO:
             std::cout << "INFO: ";
             break;
-        case SDT_WARNING:
+        case SystemDialogType::WARNING:
             std::cout << "WARNING:";
             break;
-        case SDT_ERROR:
+        case SystemDialogType::ERROR:
             std::cout << "ERROR: ";
             break;
-        case SDT_YES_NO:
-        case SDT_OK_CANCEL:
+        case SystemDialogType::YES_NO:
+        case SystemDialogType::OK_CANCEL:
             std::cout << "QUESTION: ";
             break;
     }
@@ -80,24 +80,24 @@ SystemDialogResult CSystemUtils::ConsoleSystemDialog(SystemDialogType type, cons
 
     std::string line;
 
-    SystemDialogResult result = SDR_OK;
+    auto result = SystemDialogResult::OK;
 
     bool done = false;
     while (!done)
     {
         switch (type)
         {
-            case SDT_INFO:
-            case SDT_WARNING:
-            case SDT_ERROR:
+            case SystemDialogType::INFO:
+            case SystemDialogType::WARNING:
+            case SystemDialogType::ERROR:
                 std::cout << "Press ENTER to continue";
                 break;
 
-            case SDT_YES_NO:
+            case SystemDialogType::YES_NO:
                 std::cout << "Type 'Y' for Yes or 'N' for No";
                 break;
 
-            case SDT_OK_CANCEL:
+            case SystemDialogType::OK_CANCEL:
                 std::cout << "Type 'O' for OK or 'C' for Cancel";
                 break;
         }
@@ -106,35 +106,35 @@ SystemDialogResult CSystemUtils::ConsoleSystemDialog(SystemDialogType type, cons
 
         switch (type)
         {
-            case SDT_INFO:
-            case SDT_WARNING:
-            case SDT_ERROR:
+            case SystemDialogType::INFO:
+            case SystemDialogType::WARNING:
+            case SystemDialogType::ERROR:
                 done = true;
                 break;
 
-            case SDT_YES_NO:
+            case SystemDialogType::YES_NO:
                 if (line == "Y" || line == "y")
                 {
-                    result = SDR_YES;
+                    result = SystemDialogResult::YES;
                     done = true;
                 }
                 else if (line == "N" || line == "n")
                 {
-                    result = SDR_NO;
+                    result = SystemDialogResult::NO;
                     done = true;
                 }
                 break;
 
-            case SDT_OK_CANCEL:
+            case SystemDialogType::OK_CANCEL:
                 if (line == "O" || line == "o")
                 {
                     done = true;
-                    result = SDR_OK;
+                    result = SystemDialogResult::OK;
                 }
                 else if (line == "C" || line == "c")
                 {
                     done = true;
-                    result = SDR_CANCEL;
+                    result = SystemDialogResult::CANCEL;
                 }
                 break;
         }
@@ -148,6 +148,11 @@ SystemTimeStamp CSystemUtils::GetCurrentTimeStamp()
     return std::chrono::high_resolution_clock::now();
 }
 
+SystemTimeStamp CSystemUtils::TimeStampLerp(SystemTimeStamp a, SystemTimeStamp b, float t)
+{
+    return a + std::chrono::duration_cast<SystemTimeStamp::duration>((b - a) * t);
+}
+
 long long CSystemUtils::TimeStampExactDiff(SystemTimeStamp before, SystemTimeStamp after)
 {
     return std::chrono::duration_cast<std::chrono::nanoseconds>(after - before).count();
@@ -158,11 +163,11 @@ float CSystemUtils::TimeStampDiff(SystemTimeStamp before, SystemTimeStamp after,
     long long exact = TimeStampExactDiff(before, after);
 
     float result = 0.0f;
-    if (unit == STU_SEC)
+    if (unit == SystemTimeUnit::SECONDS)
         result = exact * 1e-9;
-    else if (unit == STU_MSEC)
+    else if (unit == SystemTimeUnit::MILLISECONDS)
         result = exact * 1e-6;
-    else if (unit == STU_USEC)
+    else if (unit == SystemTimeUnit::MICROSECONDS)
         result = exact * 1e-3;
     else
         assert(false);
diff --git a/src/common/system/system.h b/src/common/system/system.h
index 2f7fd146..1d0b31eb 100644
--- a/src/common/system/system.h
+++ b/src/common/system/system.h
@@ -35,18 +35,18 @@
  * \enum SystemDialogType
  * \brief Type of system dialog
  */
-enum SystemDialogType
+enum class SystemDialogType
 {
     //! Information message
-    SDT_INFO,
+    INFO,
     //! Warning message
-    SDT_WARNING,
+    WARNING,
     //! Error message
-    SDT_ERROR,
+    ERROR,
     //! Yes/No question
-    SDT_YES_NO,
+    YES_NO,
     //! Ok/Cancel question
-    SDT_OK_CANCEL
+    OK_CANCEL
 };
 
 /**
@@ -55,26 +55,23 @@ enum SystemDialogType
  *
  * Means which button was pressed.
  */
-enum SystemDialogResult
+enum class SystemDialogResult
 {
-    SDR_OK,
-    SDR_CANCEL,
-    SDR_YES,
-    SDR_NO
+    OK,
+    CANCEL,
+    YES,
+    NO
 };
 
 /**
  * \enum SystemTimeUnit
  * \brief Time unit
  */
-enum SystemTimeUnit
+enum class SystemTimeUnit
 {
-    //! seconds
-    STU_SEC,
-    //! milliseconds
-    STU_MSEC,
-    //! microseconds
-    STU_USEC
+    SECONDS,
+    MILLISECONDS,
+    MICROSECONDS
 };
 
 using SystemTimeStamp = std::chrono::time_point<std::chrono::high_resolution_clock>;
@@ -103,20 +100,23 @@ public:
     //! Displays a fallback system dialog using console
     TEST_VIRTUAL SystemDialogResult ConsoleSystemDialog(SystemDialogType type, const std::string& title, const std::string& message);
 
-    //! Interpolates between two timestamps. If i=0 then dst=a. If i=1 then dst=b. If i=0.5 then dst is halfway between.
-    virtual void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) = 0;
-
     //! Returns a time stamp associated with current time
     TEST_VIRTUAL SystemTimeStamp GetCurrentTimeStamp();
 
+    //! Linearly interpolates between two timestamps.
+    SystemTimeStamp TimeStampLerp(SystemTimeStamp a, SystemTimeStamp b, float t);
+
     //! Returns a difference between two timestamps in given time unit
     /** The difference is \a after - \a before. */
-    float TimeStampDiff(SystemTimeStamp before, SystemTimeStamp after, SystemTimeUnit unit = STU_SEC);
+    float TimeStampDiff(SystemTimeStamp before, SystemTimeStamp after, SystemTimeUnit unit = SystemTimeUnit::SECONDS);
 
     //! Returns the exact (in nanosecond units) difference between two timestamps
     /** The difference is \a after - \a before. */
     long long TimeStampExactDiff(SystemTimeStamp before, SystemTimeStamp after);
 
+    //! Returns the path where the executable binary is located (ends with the path separator)
+    virtual std::string GetBasePath();
+
     //! Returns the data path (containing textures, levels, helpfiles, etc)
     virtual std::string GetDataPath();
 
diff --git a/src/common/system/system_linux.cpp b/src/common/system/system_linux.cpp
index 9f738aa9..056e34ad 100644
--- a/src/common/system/system_linux.cpp
+++ b/src/common/system/system_linux.cpp
@@ -46,20 +46,20 @@ SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const
     std::string options = "";
     switch (type)
     {
-        case SDT_INFO:
+        case SystemDialogType::INFO:
         default:
             options = "--info";
             break;
-        case SDT_WARNING:
+        case SystemDialogType::WARNING:
             options = "--warning";
             break;
-        case SDT_ERROR:
+        case SystemDialogType::ERROR:
             options = "--error";
             break;
-        case SDT_YES_NO:
+        case SystemDialogType::YES_NO:
             options = "--question --ok-label=\"Yes\" --cancel-label=\"No\"";
             break;
-        case SDT_OK_CANCEL:
+        case SystemDialogType::OK_CANCEL:
             options = "--question --ok-label=\"OK\" --cancel-label=\"Cancel\"";
             break;
     }
@@ -67,14 +67,14 @@ SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const
     std::string command = "zenity " + options + " --text=\"" + message + "\" --title=\"" + title + "\"";
     int code = system(command.c_str());
 
-    SystemDialogResult result = SDR_OK;
+    SystemDialogResult result = SystemDialogResult::OK;
     switch (type)
     {
-        case SDT_YES_NO:
-            result = code ? SDR_NO : SDR_YES;
+        case SystemDialogType::YES_NO:
+            result = code ? SystemDialogResult::NO : SystemDialogResult::YES;
             break;
-        case SDT_OK_CANCEL:
-            result = code ? SDR_CANCEL : SDR_OK;
+        case SystemDialogType::OK_CANCEL:
+            result = code ? SystemDialogResult::CANCEL : SystemDialogResult::OK;
             break;
         default:
             break;
@@ -83,19 +83,6 @@ SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const
     return result;
 }
 
-void CSystemUtilsLinux::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i)
-{
-    long long delta = TimeStampExactDiff(a, b);
-    delta *= i; // truncates
-    dst->clockTime.tv_sec = a->clockTime.tv_sec + delta / 1000000000;
-    dst->clockTime.tv_nsec = a->clockTime.tv_nsec + delta % 1000000000;
-    if(dst->clockTime.tv_nsec >= 1000000000)
-    {
-        dst->clockTime.tv_nsec -= 1000000000;
-        dst->clockTime.tv_sec++;
-    }
-}
-
 void CSystemUtilsLinux::GetCurrentTimeStamp(SystemTimeStamp *stamp)
 {
     clock_gettime(CLOCK_MONOTONIC_RAW, &stamp->clockTime);
diff --git a/src/common/system/system_linux.h b/src/common/system/system_linux.h
index 93a0c8ba..8a1e60ec 100644
--- a/src/common/system/system_linux.h
+++ b/src/common/system/system_linux.h
@@ -24,8 +24,6 @@
 
 #include "common/system/system.h"
 
-#include <sys/time.h>
-
 //@colobot-lint-exclude UndefinedFunctionRule
 
 class CSystemUtilsLinux : public CSystemUtils
@@ -35,8 +33,6 @@ public:
 
     SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
 
-    void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override;
-
     std::string GetSaveDir() override;
 
     std::string GetEnvVar(const std::string& name) override;
diff --git a/src/common/system/system_windows.cpp b/src/common/system/system_windows.cpp
index 1d3c9b1e..3f2bb171 100644
--- a/src/common/system/system_windows.cpp
+++ b/src/common/system/system_windows.cpp
@@ -37,20 +37,24 @@ SystemDialogResult CSystemUtilsWindows::SystemDialog(SystemDialogType type, cons
 
     switch (type)
     {
-        case SDT_INFO:
+        case SystemDialogType::INFO:
         default:
             windowsType = MB_ICONINFORMATION|MB_OK;
             break;
-        case SDT_WARNING:
+        case SystemDialogType::WARNING:
             windowsType = MB_ICONWARNING|MB_OK;
             break;
-        case SDT_ERROR:
+// windows.h defines ERROR which collides with the enum name
+#pragma push_macro("ERROR")
+#undef ERROR
+        case SystemDialogType::ERROR:
+#pragma pop_macro("ERROR")
             windowsType = MB_ICONERROR|MB_OK;
             break;
-        case SDT_YES_NO:
+        case SystemDialogType::YES_NO:
             windowsType = MB_ICONQUESTION|MB_YESNO;
             break;
-        case SDT_OK_CANCEL:
+        case SystemDialogType::OK_CANCEL:
             windowsType = MB_ICONWARNING|MB_OKCANCEL;
             break;
     }
@@ -58,18 +62,18 @@ SystemDialogResult CSystemUtilsWindows::SystemDialog(SystemDialogType type, cons
     switch (MessageBoxW(nullptr, windowsMessage.c_str(), windowsTitle.c_str(), windowsType))
     {
         case IDOK:
-            return SDR_OK;
+            return SystemDialogResult::OK;
         case IDCANCEL:
-            return SDR_CANCEL;
+            return SystemDialogResult::CANCEL;
         case IDYES:
-            return SDR_YES;
+            return SystemDialogResult::YES;
         case IDNO:
-            return SDR_NO;
+            return SystemDialogResult::NO;
         default:
             break;
     }
 
-    return SDR_OK;
+    return SystemDialogResult::OK;
 }
 
 //! Converts a wide Unicode string to an UTF8 string
diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp
index 19df60f8..72cc69b4 100644
--- a/src/graphics/engine/engine.cpp
+++ b/src/graphics/engine/engine.cpp
@@ -3168,7 +3168,7 @@ void CEngine::Render()
     m_fpsCounter++;
 
     m_currentFrameTime = m_systemUtils->GetCurrentTimeStamp();
-    float diff = m_systemUtils->TimeStampDiff(m_lastFrameTime, m_currentFrameTime, STU_SEC);
+    float diff = m_systemUtils->TimeStampDiff(m_lastFrameTime, m_currentFrameTime, SystemTimeUnit::SECONDS);
     if (diff > 1.0f)
     {
         m_lastFrameTime = m_currentFrameTime;
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index f0eaecd9..bcf187d0 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -1,10 +1,3 @@
-# Platform-dependent tests
-if(PLATFORM_WINDOWS)
-    set(PLATFORM_TESTS common/system/system_windows_test.cpp)
-elseif(PLATFORM_LINUX)
-    set(PLATFORM_TESTS common/system/system_linux_test.cpp)
-endif()
-
 set(TEST_FILES
     common/colobot.ini
 )
@@ -21,6 +14,7 @@ add_executable(colobot_ut
     CBot/CBotToken_test.cpp
     CBot/CBot_test.cpp
     common/config_file_test.cpp
+    common/system/system_test.cpp
     graphics/engine/lightman_test.cpp
     math/func_test.cpp
     math/geometry_test.cpp
@@ -28,13 +22,6 @@ add_executable(colobot_ut
     math/vector_test.cpp
 )
 
-# Platform-dependent tests
-if(PLATFORM_WINDOWS)
-    target_sources(colobot_ut PRIVATE common/system/system_windows_test.cpp)
-elseif(PLATFORM_LINUX)
-    target_sources(colobot_ut PRIVATE common/system/system_linux_test.cpp)
-endif()
-
 target_include_directories(colobot_ut PRIVATE
     common
     math
diff --git a/test/unit/app/app_test.cpp b/test/unit/app/app_test.cpp
index 3b9443db..22fc3eb4 100644
--- a/test/unit/app/app_test.cpp
+++ b/test/unit/app/app_test.cpp
@@ -47,7 +47,7 @@ public:
         SDL_Quit();
     }
 
-    Event CreateUpdateEvent(SystemTimeStamp *timestamp) override
+    Event CreateUpdateEvent(SystemTimeStamp timestamp) override
     {
         return CApplication::CreateUpdateEvent(timestamp);
     }
@@ -117,8 +117,7 @@ void CApplicationUT::TestCreateUpdateEvent(long long relTimeExact, long long abs
                                            float relTime, float absTime,
                                            long long relTimeReal, long long absTimeReal)
 {
-    SystemTimeStamp *now = CreateTimeStamp();
-    GetCurrentTimeStamp(now);
+    SystemTimeStamp now = GetCurrentTimeStamp();
     Event event = m_app->CreateUpdateEvent(now);
     EXPECT_EQ(EVENT_FRAME, event.type);
     EXPECT_FLOAT_EQ(relTime, event.rTime);
@@ -135,9 +134,7 @@ TEST_F(CApplicationUT, UpdateEventTimeCalculation_SimulationSuspended)
 {
     m_app->SuspendSimulation();
 
-    SystemTimeStamp *now = CreateTimeStamp();
-    GetCurrentTimeStamp(now);
-    Event event = m_app->CreateUpdateEvent(now);
+    Event event = m_app->CreateUpdateEvent(GetCurrentTimeStamp());
 
     EXPECT_EQ(EVENT_NULL, event.type);
 }
@@ -190,9 +187,7 @@ TEST_F(CApplicationUT, UpdateEventTimeCalculation_NegativeTimeOperation)
 
     NextInstant(-1111);
 
-    SystemTimeStamp *now = CreateTimeStamp();
-    GetCurrentTimeStamp(now);
-    Event event = m_app->CreateUpdateEvent(now);
+    Event event = m_app->CreateUpdateEvent(GetCurrentTimeStamp());
     EXPECT_EQ(EVENT_NULL, event.type);
 }
 
diff --git a/test/unit/common/system/system_linux_test.cpp b/test/unit/common/system/system_linux_test.cpp
deleted file mode 100644
index 6a503c18..00000000
--- a/test/unit/common/system/system_linux_test.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * This file is part of the Colobot: Gold Edition source code
- * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
- * http://epsitec.ch; http://colobot.info; http://github.com/colobot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see http://gnu.org/licenses
- */
-
-#include "common/system/system.h"
-#include "common/system/system_linux.h"
-
-#include <gtest/gtest.h>
-
-class CSystemUtilsLinuxUT : public testing::Test
-{
-protected:
-    static const long long SEC = 1000000000;
-
-    CSystemUtilsLinux m_systemUtils;
-};
-
-
-TEST_F(CSystemUtilsLinuxUT, TimeStampDiff)
-{
-    SystemTimeStamp before, after;
-
-    before.clockTime.tv_sec = 1;
-    before.clockTime.tv_nsec = 100;
-
-    after.clockTime.tv_sec = 1;
-    after.clockTime.tv_nsec = 900;
-
-    long long tDiff = m_systemUtils.TimeStampExactDiff(&before, &after);
-    EXPECT_EQ( 800, tDiff);
-
-    tDiff = m_systemUtils.TimeStampExactDiff(&after, &before);
-    EXPECT_EQ(-800, tDiff);
-
-    // -------
-
-    before.clockTime.tv_sec = 2;
-    before.clockTime.tv_nsec = 200;
-
-    after.clockTime.tv_sec = 3;
-    after.clockTime.tv_nsec = 500;
-
-    tDiff = m_systemUtils.TimeStampExactDiff(&before, &after);
-    EXPECT_EQ( SEC + 300, tDiff);
-
-    tDiff = m_systemUtils.TimeStampExactDiff(&after, &before);
-    EXPECT_EQ(-SEC - 300, tDiff);
-
-    // -------
-
-    before.clockTime.tv_sec = 3;
-    before.clockTime.tv_nsec = 200;
-
-    after.clockTime.tv_sec = 4;
-    after.clockTime.tv_nsec = 100;
-
-    tDiff = m_systemUtils.TimeStampExactDiff(&before, &after);
-    EXPECT_EQ( SEC - 100, tDiff);
-
-    tDiff = m_systemUtils.TimeStampExactDiff(&after, &before);
-    EXPECT_EQ(-SEC + 100, tDiff);
-}
diff --git a/test/unit/common/system/system_test.cpp b/test/unit/common/system/system_test.cpp
index 60447dd7..f78a4f98 100644
--- a/test/unit/common/system/system_test.cpp
+++ b/test/unit/common/system/system_test.cpp
@@ -21,11 +21,13 @@
 
 #include <gtest/gtest.h>
 
-struct SystemTest : ::testing::Test {
+struct SystemTest : ::testing::Test
+{
     CSystemUtilsOther system;
 };
 
-TEST_F(SystemTest, TimeStampExactDiff) {
+TEST_F(SystemTest, TimeStampExactDiff)
+{
     auto epoch = SystemTimeStamp{};
     EXPECT_EQ(system.TimeStampExactDiff(epoch, epoch), 0);
 
@@ -35,3 +37,43 @@ TEST_F(SystemTest, TimeStampExactDiff) {
     EXPECT_EQ(system.TimeStampExactDiff(before, after), std::chrono::nanoseconds{duration}.count());
     EXPECT_EQ(system.TimeStampExactDiff(after, before), -std::chrono::nanoseconds{duration}.count());
 }
+
+constexpr auto TIMESTAMP_START = SystemTimeStamp{std::chrono::nanoseconds{300}};
+constexpr auto TIMESTAMP_MID = SystemTimeStamp{std::chrono::nanoseconds{600}};
+constexpr auto TIMESTAMP_END = SystemTimeStamp{std::chrono::nanoseconds{900}};
+
+constexpr auto LERP_PARAM_ZERO = 0.0f;
+constexpr auto LERP_PARAM_HALF = 0.5f;
+constexpr auto LERP_PARAM_ONE = 1.0f;
+
+TEST_F(SystemTest, TimeStampLerpReturnsStartWhenLerpParameterIsZero)
+{
+    EXPECT_EQ(TIMESTAMP_START, system.TimeStampLerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_ZERO));
+}
+
+TEST_F(SystemTest, TimeStampLerpReturnsEndWhenLerpParameterIsOne)
+{
+    EXPECT_EQ(TIMESTAMP_END, system.TimeStampLerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_ONE));
+}
+
+TEST_F(SystemTest, TimeStampLerpReturnsValueBetweenStartAndEndWhenLerpParameterIsBetweenZeroAndOne)
+{
+    EXPECT_EQ(TIMESTAMP_MID, system.TimeStampLerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_HALF));
+}
+
+TEST_F(SystemTest, TimeStampLerpIsMonotonic)
+{
+    constexpr auto deltaLerpParam = 0.1f;
+    auto earlierTimeStamp = system.TimeStampLerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_HALF - deltaLerpParam);
+    auto laterTimeStamp = system.TimeStampLerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_HALF + deltaLerpParam);
+    EXPECT_TRUE(earlierTimeStamp < laterTimeStamp);
+}
+
+TEST_F(SystemTest, TimeStampLerpIsConsistent)
+{
+    auto timeStamp = TIMESTAMP_START;
+    EXPECT_EQ(timeStamp, system.TimeStampLerp(timeStamp, timeStamp, LERP_PARAM_ZERO));
+    EXPECT_EQ(timeStamp, system.TimeStampLerp(timeStamp, timeStamp, LERP_PARAM_HALF));
+    EXPECT_EQ(timeStamp, system.TimeStampLerp(timeStamp, timeStamp, LERP_PARAM_ONE));
+}
+
diff --git a/test/unit/common/system/system_windows_test.cpp b/test/unit/common/system/system_windows_test.cpp
deleted file mode 100644
index eb959ff0..00000000
--- a/test/unit/common/system/system_windows_test.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * This file is part of the Colobot: Gold Edition source code
- * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam
- * http://epsitec.ch; http://colobot.info; http://github.com/colobot
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see http://gnu.org/licenses
- */
-
-#include "common/system/system.h"
-#include "common/system/system_windows.h"
-
-#include <gtest/gtest.h>
-
-class CSystemUtilsWindowsWrapper : public CSystemUtilsWindows
-{
-public:
-    void SetFrequency(long long frequency)
-    {
-        m_counterFrequency = frequency;
-    }
-};
-
-class CSystemUtilsWindowsUT : public testing::Test
-{
-protected:
-    static const long long SEC = 1000000000;
-
-    CSystemUtilsWindowsWrapper m_systemUtils;
-};
-
-TEST_F(CSystemUtilsWindowsUT, TimeStampDiff)
-{
-    m_systemUtils.SetFrequency(SEC);
-
-    SystemTimeStamp before, after;
-
-    before.counterValue = 100;
-    after.counterValue = 200;
-
-    long long tDiff = m_systemUtils.TimeStampExactDiff(&before, &after);
-    EXPECT_EQ( 100, tDiff);
-
-    tDiff = m_systemUtils.TimeStampExactDiff(&after, &before);
-    EXPECT_EQ(-100, tDiff);
-
-    // -------
-
-    m_systemUtils.SetFrequency(SEC/3);
-
-    before.counterValue = 200;
-    after.counterValue = 400;
-
-    tDiff = m_systemUtils.TimeStampExactDiff(&before, &after);
-    EXPECT_EQ( 200*3, tDiff);
-
-    tDiff = m_systemUtils.TimeStampExactDiff(&after, &before);
-    EXPECT_EQ(-200*3, tDiff);
-}