Repository: RetroAchievements/RAIntegration
Pull request #837 (2021-11-29 03:39:19)

hook up pause on reset/trigger and debug highlights for nested triggers


Patch:
diff --git a/src/Exports.cpp b/src/Exports.cpp
index 92439bc0..2136d314 100644
--- a/src/Exports.cpp
+++ b/src/Exports.cpp
@@ -520,6 +520,97 @@ static void ProcessAchievements()
                 pOverlayManager.RemoveScoreTracker(pChange.nId);
                 break;
             }
+
+            case ra::services::AchievementRuntime::ChangeType::LeaderboardStartReset:
+            {
+                /* ASSERT: this event is only raised if the leaderboard is watching for it */
+                const auto* pLeaderboard = pGameContext.Assets().FindLeaderboard(pChange.nId);
+                if (pLeaderboard)
+                {
+                    auto& pFrameEventQueue = ra::services::ServiceLocator::GetMutable<ra::services::FrameEventQueue>();
+                    pFrameEventQueue.QueuePauseOnReset(L"Start: " + pLeaderboard->GetName());
+                }
+
+                break;
+            }
+
+            case ra::services::AchievementRuntime::ChangeType::LeaderboardSubmitReset:
+            {
+                /* ASSERT: this event is only raised if the leaderboard is watching for it */
+                const auto* pLeaderboard = pGameContext.Assets().FindLeaderboard(pChange.nId);
+                if (pLeaderboard)
+                {
+                    auto& pFrameEventQueue = ra::services::ServiceLocator::GetMutable<ra::services::FrameEventQueue>();
+                    pFrameEventQueue.QueuePauseOnReset(L"Submit: " + pLeaderboard->GetName());
+                }
+
+                break;
+            }
+
+            case ra::services::AchievementRuntime::ChangeType::LeaderboardCancelReset:
+            {
+                /* ASSERT: this event is only raised if the leaderboard is watching for it */
+                const auto* pLeaderboard = pGameContext.Assets().FindLeaderboard(pChange.nId);
+                if (pLeaderboard)
+                {
+                    auto& pFrameEventQueue = ra::services::ServiceLocator::GetMutable<ra::services::FrameEventQueue>();
+                    pFrameEventQueue.QueuePauseOnReset(L"Cancel: " + pLeaderboard->GetName());
+                }
+
+                break;
+            }
+
+            case ra::services::AchievementRuntime::ChangeType::LeaderboardValueReset:
+            {
+                /* ASSERT: this event is only raised if the leaderboard is watching for it */
+                const auto* pLeaderboard = pGameContext.Assets().FindLeaderboard(pChange.nId);
+                if (pLeaderboard)
+                {
+                    auto& pFrameEventQueue = ra::services::ServiceLocator::GetMutable<ra::services::FrameEventQueue>();
+                    pFrameEventQueue.QueuePauseOnReset(L"Value: " + pLeaderboard->GetName());
+                }
+
+                break;
+            }
+
+            case ra::services::AchievementRuntime::ChangeType::LeaderboardStartTriggered:
+            {
+                /* ASSERT: this event is only raised if the leaderboard is watching for it */
+                const auto* pLeaderboard = pGameContext.Assets().FindLeaderboard(pChange.nId);
+                if (pLeaderboard)
+                {
+                    auto& pFrameEventQueue = ra::services::ServiceLocator::GetMutable<ra::services::FrameEventQueue>();
+                    pFrameEventQueue.QueuePauseOnTrigger(L"Start: " + pLeaderboard->GetName());
+                }
+
+                break;
+            }
+
+            case ra::services::AchievementRuntime::ChangeType::LeaderboardSubmitTriggered:
+            {
+                /* ASSERT: this event is only raised if the leaderboard is watching for it */
+                const auto* pLeaderboard = pGameContext.Assets().FindLeaderboard(pChange.nId);
+                if (pLeaderboard)
+                {
+                    auto& pFrameEventQueue = ra::services::ServiceLocator::GetMutable<ra::services::FrameEventQueue>();
+                    pFrameEventQueue.QueuePauseOnTrigger(L"Submit: " + pLeaderboard->GetName());
+                }
+
+                break;
+            }
+
+            case ra::services::AchievementRuntime::ChangeType::LeaderboardCancelTriggered:
+            {
+                /* ASSERT: this event is only raised if the leaderboard is watching for it */
+                const auto* pLeaderboard = pGameContext.Assets().FindLeaderboard(pChange.nId);
+                if (pLeaderboard)
+                {
+                    auto& pFrameEventQueue = ra::services::ServiceLocator::GetMutable<ra::services::FrameEventQueue>();
+                    pFrameEventQueue.QueuePauseOnTrigger(L"Cancel: " + pLeaderboard->GetName());
+                }
+
+                break;
+            }
         }
     }
 }
diff --git a/src/data/models/LeaderboardModel.cpp b/src/data/models/LeaderboardModel.cpp
index def4a6b1..9ee2f48d 100644
--- a/src/data/models/LeaderboardModel.cpp
+++ b/src/data/models/LeaderboardModel.cpp
@@ -16,6 +16,8 @@ const IntModelProperty LeaderboardModel::SubmitTriggerProperty("LeaderboardModel
 const IntModelProperty LeaderboardModel::CancelTriggerProperty("LeaderboardModel", "CancelTrigger", 0);
 const IntModelProperty LeaderboardModel::ValueDefinitionProperty("LeaderboardModel", "ValueDefinition", 0);
 const IntModelProperty LeaderboardModel::ValueFormatProperty("LeaderboardModel", "ValueFormat", ra::etoi(ValueFormat::Value));
+const IntModelProperty LeaderboardModel::PauseOnResetProperty("LeaderboardModel", "PauseOnReset", ra::etoi(LeaderboardModel::LeaderboardParts::None));
+const IntModelProperty LeaderboardModel::PauseOnTriggerProperty("LeaderboardModel", "PauseOnTrigger", ra::etoi(LeaderboardModel::LeaderboardParts::None));
 const BoolModelProperty LeaderboardModel::LowerIsBetterProperty("LeaderboardModel", "LowerIsBetter", false);
 
 LeaderboardModel::LeaderboardModel() noexcept
diff --git a/src/data/models/LeaderboardModel.hh b/src/data/models/LeaderboardModel.hh
index 310ffff4..27295951 100644
--- a/src/data/models/LeaderboardModel.hh
+++ b/src/data/models/LeaderboardModel.hh
@@ -16,37 +16,46 @@ class LeaderboardModel : public AssetModelBase
 {
 public:
     LeaderboardModel() noexcept;
-/*
+
+    enum class LeaderboardParts
+    {
+        None = 0x00,
+        Start = 0x01,
+        Submit = 0x02,
+        Cancel = 0x04,
+        Value = 0x08
+    };
+
     /// <summary>
     /// The <see cref="ModelProperty" /> for whether or not the emulator should be paused when the trigger is reset.
     /// </summary>
-    static const BoolModelProperty PauseOnResetProperty;
+    static const IntModelProperty PauseOnResetProperty;
 
     /// <summary>
-    /// Gets whether or not the emulator should be paused when the trigger is reset.
+    /// Sets whether or not the emulator should be paused when the trigger is reset.
     /// </summary>
-    bool IsPauseOnReset() const { return GetValue(PauseOnResetProperty); }
+    LeaderboardParts GetPauseOnReset() const { return ra::itoe<LeaderboardParts>(GetValue(PauseOnResetProperty)); }
 
     /// <summary>
     /// Sets whether or not the emulator should be paused when the trigger is reset.
     /// </summary>
-    void SetPauseOnReset(bool nValue) { SetValue(PauseOnResetProperty, nValue); }
+    void SetPauseOnReset(LeaderboardParts nValue) { SetValue(PauseOnResetProperty, ra::etoi(nValue)); }
 
     /// <summary>
-    /// The <see cref="ModelProperty" /> for whether or not the emulator should be paused when the achievement triggers.
+    /// The <see cref="ModelProperty" /> for whether or not the emulator should be paused when a part triggers.
     /// </summary>
-    static const BoolModelProperty PauseOnTriggerProperty;
+    static const IntModelProperty PauseOnTriggerProperty;
 
     /// <summary>
-    /// Gets whether or not the emulator should be paused when the achievement triggers.
+    /// Gets whether or not the emulator should be paused when a part triggers.
     /// </summary>
-    bool IsPauseOnTrigger() const { return GetValue(PauseOnTriggerProperty); }
+    LeaderboardParts GetPauseOnTrigger() const { return ra::itoe<LeaderboardParts>(GetValue(PauseOnTriggerProperty)); }
 
     /// <summary>
-    /// Sets whether or not the emulator should be paused when the achievement triggers.
+    /// Sets whether or not the emulator should be paused when a part triggers.
     /// </summary>
-    void SetPauseOnTrigger(bool nValue) { SetValue(PauseOnTriggerProperty, nValue); }
-*/
+    void SetPauseOnTrigger(LeaderboardParts nValue) { SetValue(PauseOnTriggerProperty, ra::etoi(nValue)); }
+
     /// <summary>
     /// The <see cref="ModelProperty" /> for the start trigger version.
     /// </summary>
diff --git a/src/ra_utility.h b/src/ra_utility.h
index 97a236ea..bf72b67b 100644
--- a/src/ra_utility.h
+++ b/src/ra_utility.h
@@ -180,6 +180,12 @@ _CONSTANT_FN& operator&=(_Inout_ Enum& a, _In_ Enum b) noexcept
 {
     return (a = a & b);
 }
+
+template<typename Enum, typename = std::enable_if_t<std::is_enum_v<Enum>>>
+_NODISCARD _CONSTANT_FN operator~(_In_ Enum a) noexcept
+{
+    return (itoe<Enum>(~etoi(a)));
+}
 } // namespace bitwise_ops
 
 namespace arith_ops {
diff --git a/src/services/AchievementRuntime.cpp b/src/services/AchievementRuntime.cpp
index e4526e81..4ba45dfc 100644
--- a/src/services/AchievementRuntime.cpp
+++ b/src/services/AchievementRuntime.cpp
@@ -270,15 +270,146 @@ static void map_event_to_change(const rc_runtime_event_t* pRuntimeEvent)
     g_pChanges->emplace_back(AchievementRuntime::Change{ nChangeType, pRuntimeEvent->id, pRuntimeEvent->value });
 }
 
+typedef struct LeaderboardPauseFlags
+{
+    ra::LeaderboardID nID;
+    ra::data::models::LeaderboardModel::LeaderboardParts nPauseOnReset;
+    ra::data::models::LeaderboardModel::LeaderboardParts nPauseOnTrigger;
+} LeaderboardPauseFlags;
+
+static void GetLeaderboardPauseFlags(std::vector<LeaderboardPauseFlags>& vLeaderboardPauseFlags, const rc_runtime_t* pRuntime)
+{
+    const auto& vAssets = ra::services::ServiceLocator::Get<ra::data::context::GameContext>().Assets();
+    for (gsl::index i = 0; i < gsl::narrow_cast<gsl::index>(vAssets.Count()); ++i)
+    {
+        const auto* pLeaderboard = dynamic_cast<const ra::data::models::LeaderboardModel*>(vAssets.GetItemAt(i));
+        if (pLeaderboard != nullptr)
+        {
+            LeaderboardPauseFlags pLeaderboardPauseFlags;
+            pLeaderboardPauseFlags.nPauseOnReset = pLeaderboard->GetPauseOnReset();
+            pLeaderboardPauseFlags.nPauseOnTrigger = pLeaderboard->GetPauseOnTrigger();
+            if (pLeaderboardPauseFlags.nPauseOnReset != ra::data::models::LeaderboardModel::LeaderboardParts::None ||
+                pLeaderboardPauseFlags.nPauseOnTrigger != ra::data::models::LeaderboardModel::LeaderboardParts::None)
+            {
+                pLeaderboardPauseFlags.nID = pLeaderboard->GetID();
+
+                const auto* pLBoard = rc_runtime_get_lboard(pRuntime, pLeaderboardPauseFlags.nID);
+                if (pLBoard != nullptr)
+                {
+                    using namespace ra::bitwise_ops;
+
+                    if (pLeaderboardPauseFlags.nPauseOnReset != ra::data::models::LeaderboardModel::LeaderboardParts::None)
+                    {
+                        if (!pLBoard->start.has_hits)
+                            pLeaderboardPauseFlags.nPauseOnReset &= ~ra::data::models::LeaderboardModel::LeaderboardParts::Start;
+                        if (!pLBoard->submit.has_hits)
+                            pLeaderboardPauseFlags.nPauseOnReset &= ~ra::data::models::LeaderboardModel::LeaderboardParts::Submit;
+                        if (!pLBoard->cancel.has_hits)
+                            pLeaderboardPauseFlags.nPauseOnReset &= ~ra::data::models::LeaderboardModel::LeaderboardParts::Cancel;
+                        if (!pLBoard->value.value.value)
+                            pLeaderboardPauseFlags.nPauseOnReset &= ~ra::data::models::LeaderboardModel::LeaderboardParts::Value;
+                    }
+
+                    if (pLeaderboardPauseFlags.nPauseOnTrigger != ra::data::models::LeaderboardModel::LeaderboardParts::None)
+                    {
+                        if (pLBoard->start.state == RC_TRIGGER_STATE_TRIGGERED)
+                            pLeaderboardPauseFlags.nPauseOnTrigger &= ~ra::data::models::LeaderboardModel::LeaderboardParts::Start;
+                        if (pLBoard->submit.state == RC_TRIGGER_STATE_TRIGGERED)
+                            pLeaderboardPauseFlags.nPauseOnTrigger &= ~ra::data::models::LeaderboardModel::LeaderboardParts::Submit;
+                        if (pLBoard->cancel.state == RC_TRIGGER_STATE_TRIGGERED)
+                            pLeaderboardPauseFlags.nPauseOnTrigger &= ~ra::data::models::LeaderboardModel::LeaderboardParts::Cancel;
+                    }
+
+                    const auto nMonitorFlags = pLeaderboardPauseFlags.nPauseOnReset | pLeaderboardPauseFlags.nPauseOnTrigger;
+                    if (nMonitorFlags != ra::data::models::LeaderboardModel::LeaderboardParts::None)
+                        vLeaderboardPauseFlags.push_back(pLeaderboardPauseFlags);
+                }
+            }
+        }
+    }
+}
+
+static void CheckForLeaderboardPauseChanges(const std::vector<LeaderboardPauseFlags>& vLeaderboardPauseFlags,
+    const rc_runtime_t* pRuntime, std::vector<AchievementRuntime::Change>& changes)
+{
+    for (const auto& pLeaderboardPauseFlags : vLeaderboardPauseFlags)
+    {
+        const auto* pLBoard = rc_runtime_get_lboard(pRuntime, pLeaderboardPauseFlags.nID);
+        if (pLBoard != nullptr)
+        {
+            using namespace ra::bitwise_ops;
+
+            if (!pLBoard->start.has_hits &&
+                (pLeaderboardPauseFlags.nPauseOnReset & ra::data::models::LeaderboardModel::LeaderboardParts::Start) != ra::data::models::LeaderboardModel::LeaderboardParts::None)
+            {
+                changes.emplace_back(AchievementRuntime::Change
+                    { AchievementRuntime::ChangeType::LeaderboardStartReset, pLeaderboardPauseFlags.nID, 0 });
+            }
+
+            if (!pLBoard->submit.has_hits &&
+                (pLeaderboardPauseFlags.nPauseOnReset & ra::data::models::LeaderboardModel::LeaderboardParts::Submit) != ra::data::models::LeaderboardModel::LeaderboardParts::None)
+            {
+                changes.emplace_back(AchievementRuntime::Change
+                    { AchievementRuntime::ChangeType::LeaderboardSubmitReset, pLeaderboardPauseFlags.nID, 0 });
+            }
+
+            if (!pLBoard->cancel.has_hits &&
+                (pLeaderboardPauseFlags.nPauseOnReset & ra::data::models::LeaderboardModel::LeaderboardParts::Cancel) != ra::data::models::LeaderboardModel::LeaderboardParts::None)
+            {
+                changes.emplace_back(AchievementRuntime::Change
+                    { AchievementRuntime::ChangeType::LeaderboardCancelReset, pLeaderboardPauseFlags.nID, 0 });
+            }
+
+            if (!pLBoard->value.value.value &&
+                (pLeaderboardPauseFlags.nPauseOnReset & ra::data::models::LeaderboardModel::LeaderboardParts::Value) != ra::data::models::LeaderboardModel::LeaderboardParts::None)
+            {
+                changes.emplace_back(AchievementRuntime::Change
+                    { AchievementRuntime::ChangeType::LeaderboardValueReset, pLeaderboardPauseFlags.nID, 0 });
+            }
+
+            if (pLBoard->start.state == RC_TRIGGER_STATE_TRIGGERED &&
+                (pLeaderboardPauseFlags.nPauseOnTrigger & ra::data::models::LeaderboardModel::LeaderboardParts::Start) != ra::data::models::LeaderboardModel::LeaderboardParts::None)
+            {
+                changes.emplace_back(AchievementRuntime::Change
+                    { AchievementRuntime::ChangeType::LeaderboardStartTriggered, pLeaderboardPauseFlags.nID, 0 });
+            }
+
+            if (pLBoard->submit.state == RC_TRIGGER_STATE_TRIGGERED &&
+                (pLeaderboardPauseFlags.nPauseOnTrigger & ra::data::models::LeaderboardModel::LeaderboardParts::Submit) != ra::data::models::LeaderboardModel::LeaderboardParts::None)
+            {
+                changes.emplace_back(AchievementRuntime::Change
+                    { AchievementRuntime::ChangeType::LeaderboardSubmitTriggered, pLeaderboardPauseFlags.nID, 0 });
+            }
+
+            if (pLBoard->cancel.state == RC_TRIGGER_STATE_TRIGGERED &&
+                (pLeaderboardPauseFlags.nPauseOnTrigger & ra::data::models::LeaderboardModel::LeaderboardParts::Cancel) != ra::data::models::LeaderboardModel::LeaderboardParts::None)
+            {
+                changes.emplace_back(AchievementRuntime::Change
+                    { AchievementRuntime::ChangeType::LeaderboardCancelTriggered, pLeaderboardPauseFlags.nID, 0 });
+            }
+        }
+    }
+}
+
 _Use_decl_annotations_ void AchievementRuntime::Process(std::vector<Change>& changes)
 {
     if (!m_bInitialized || m_bPaused)
         return;
 
-    std::lock_guard<std::mutex> pLock(m_pMutex);
-    g_pChanges = &changes;
-    rc_runtime_do_frame(&m_pRuntime, map_event_to_change, rc_peek_callback, nullptr, nullptr);
-    g_pChanges = nullptr;
+    std::vector<LeaderboardPauseFlags> vLeaderboardPauseFlags;
+    if (m_pRuntime.lboard_count > 0)
+        GetLeaderboardPauseFlags(vLeaderboardPauseFlags, &m_pRuntime);
+
+    {
+        std::lock_guard<std::mutex> pLock(m_pMutex);
+
+        g_pChanges = &changes;
+        rc_runtime_do_frame(&m_pRuntime, map_event_to_change, rc_peek_callback, nullptr, nullptr);
+        g_pChanges = nullptr;
+    }
+
+    if (!vLeaderboardPauseFlags.empty())
+        CheckForLeaderboardPauseChanges(vLeaderboardPauseFlags, &m_pRuntime, changes);
 }
 
 _NODISCARD static _CONSTANT_FN ComparisonSizeToPrefix(_In_ char nSize) noexcept
diff --git a/src/services/AchievementRuntime.hh b/src/services/AchievementRuntime.hh
index 160ad0c2..c2061648 100644
--- a/src/services/AchievementRuntime.hh
+++ b/src/services/AchievementRuntime.hh
@@ -170,6 +170,15 @@ public:
         AchievementPrimed,
         AchievementActivated,
         AchievementUnprimed,
+
+        // runtime only changes
+        LeaderboardStartReset,
+        LeaderboardSubmitReset,
+        LeaderboardCancelReset,
+        LeaderboardValueReset,
+        LeaderboardStartTriggered,
+        LeaderboardSubmitTriggered,
+        LeaderboardCancelTriggered,
     };
 
     struct Change
diff --git a/src/ui/viewmodels/AssetEditorViewModel.cpp b/src/ui/viewmodels/AssetEditorViewModel.cpp
index 7d4ceffe..d1e5c88d 100644
--- a/src/ui/viewmodels/AssetEditorViewModel.cpp
+++ b/src/ui/viewmodels/AssetEditorViewModel.cpp
@@ -7,6 +7,7 @@
 #include "services\IConfiguration.hh"
 #include "services\ServiceLocator.hh"
 
+#include "ui\EditorTheme.hh"
 #include "ui\ImageReference.hh"
 #include "ui\viewmodels\FileDialogViewModel.hh"
 #include "ui\viewmodels\MessageBoxViewModel.hh"
@@ -31,6 +32,7 @@ const BoolModelProperty AssetEditorViewModel::LowerIsBetterProperty("AssetEditor
 const StringModelProperty AssetEditorViewModel::FormattedValueProperty("AssetEditorViewModel", "FormattedValue", L"0");
 const BoolModelProperty AssetEditorViewModel::PauseOnResetProperty("AssetEditorViewModel", "PauseOnReset", false);
 const BoolModelProperty AssetEditorViewModel::PauseOnTriggerProperty("AssetEditorViewModel", "PauseOnTrigger", false);
+const BoolModelProperty AssetEditorViewModel::IsTriggerProperty("AssetEditorViewModel", "IsTrigger", true);
 const BoolModelProperty AssetEditorViewModel::DebugHighlightsEnabledProperty("AssetEditorViewModel", "DebugHighlightsEnabled", false);
 const BoolModelProperty AssetEditorViewModel::DecimalPreferredProperty("AssetEditorViewModel", "DecimalPreferred", false);
 const BoolModelProperty AssetEditorViewModel::IsAssetLoadedProperty("AssetEditorViewModel", "IsAssetLoaded", false);
@@ -41,6 +43,7 @@ const StringModelProperty AssetEditorViewModel::AssetValidationWarningProperty("
 const BoolModelProperty AssetEditorViewModel::HasMeasuredProperty("AssetEditorViewModel", "HasMeasured", false);
 const StringModelProperty AssetEditorViewModel::MeasuredValueProperty("AssetEditorViewModel", "MeasuredValue", L"[Not Active]");
 const StringModelProperty AssetEditorViewModel::WaitingLabelProperty("AssetEditorViewModel", "WaitingLabel", L"Active");
+const IntModelProperty AssetEditorViewModel::LeaderboardPartViewModel::ColorProperty("LeaderboardPartViewModel", "Color", 0);
 
 AssetEditorViewModel::AssetEditorViewModel() noexcept
 {
@@ -56,8 +59,8 @@ AssetEditorViewModel::AssetEditorViewModel() noexcept
     m_vFormats.Add(ra::etoi(ra::data::ValueFormat::Minutes), L"Minutes");
 
     m_vLeaderboardParts.Add(ra::etoi(LeaderboardPart::Start), L"Start");
-    m_vLeaderboardParts.Add(ra::etoi(LeaderboardPart::Submit), L"Submit");
     m_vLeaderboardParts.Add(ra::etoi(LeaderboardPart::Cancel), L"Cancel");
+    m_vLeaderboardParts.Add(ra::etoi(LeaderboardPart::Submit), L"Submit");
     m_vLeaderboardParts.Add(ra::etoi(LeaderboardPart::Value), L"Value");
     m_vLeaderboardParts.GetItemAt(0)->SetSelected(true);
     m_vLeaderboardParts.AddNotifyTarget(*this);
@@ -162,6 +165,7 @@ void AssetEditorViewModel::LoadAsset(ra::data::models::AssetModelBase* pAsset)
             SetWindowTitle(L"Achievement Editor");
             SetValue(IsLeaderboardProperty, false);
             SetValue(IsAchievementProperty, true);
+            SetValue(IsTriggerProperty, true);
 
             const auto* pAchievement = dynamic_cast<ra::data::models::AchievementModel*>(pAsset);
             if (pAchievement != nullptr)
@@ -222,24 +226,57 @@ void AssetEditorViewModel::LoadAsset(ra::data::models::AssetModelBase* pAsset)
     }
 }
 
+static constexpr ra::data::models::LeaderboardModel::LeaderboardParts LeaderboardPartToParts(AssetEditorViewModel::LeaderboardPart nPart) noexcept
+{
+    switch (nPart)
+    {
+        case AssetEditorViewModel::LeaderboardPart::Start:
+            return ra::data::models::LeaderboardModel::LeaderboardParts::Start;
+        case AssetEditorViewModel::LeaderboardPart::Submit:
+            return ra::data::models::LeaderboardModel::LeaderboardParts::Submit;
+        case AssetEditorViewModel::LeaderboardPart::Cancel:
+            return ra::data::models::LeaderboardModel::LeaderboardParts::Cancel;
+        case AssetEditorViewModel::LeaderboardPart::Value:
+            return ra::data::models::LeaderboardModel::LeaderboardParts::Value;
+        default:
+            return ra::data::models::LeaderboardModel::LeaderboardParts::None;
+    }
+}
+
 void AssetEditorViewModel::UpdateLeaderboardTrigger()
 {
     const auto nPart = GetSelectedLeaderboardPart();
     if (nPart == LeaderboardPart::Value)
     {
+        SetValue(IsTriggerProperty, false);
         SetValue(GroupsHeaderProperty, L"Max of:");
         Trigger().SetIsValue(true);
     }
     else
     {
+        SetValue(IsTriggerProperty, true);
         SetValue(GroupsHeaderProperty, GroupsHeaderProperty.GetDefaultValue());
         Trigger().SetIsValue(false);
     }
 
+    const auto* pLeaderboard = dynamic_cast<ra::data::models::LeaderboardModel*>(m_pAsset);
+    if (pLeaderboard != nullptr)
+    {
+        using namespace ra::bitwise_ops;
+
+        SetPauseOnReset((pLeaderboard->GetPauseOnReset() & LeaderboardPartToParts(nPart)) != ra::data::models::LeaderboardModel::LeaderboardParts::None);
+        SetPauseOnTrigger((pLeaderboard->GetPauseOnTrigger() & LeaderboardPartToParts(nPart)) != ra::data::models::LeaderboardModel::LeaderboardParts::None);
+    }
+    else
+    {
+        SetPauseOnReset(false);
+        SetPauseOnTrigger(false);
+    }
+
     const auto* pLeaderboardDefinition = ra::services::ServiceLocator::Get<ra::services::AchievementRuntime>().GetLeaderboardDefinition(m_pAsset->GetID());
     if (pLeaderboardDefinition != nullptr)
     {
-        switch (GetSelectedLeaderboardPart())
+        switch (nPart)
         {
             case LeaderboardPart::Start:
                 Trigger().InitializeFrom(pLeaderboardDefinition->start);
@@ -257,28 +294,24 @@ void AssetEditorViewModel::UpdateLeaderboardTrigger()
                 break;
         }
     }
-    else
+    else if (pLeaderboard != nullptr)
     {
-        const auto* pLeaderboard = dynamic_cast<ra::data::models::LeaderboardModel*>(m_pAsset);
-        if (pLeaderboard != nullptr)
+        switch (nPart)
         {
-            switch (GetSelectedLeaderboardPart())
-            {
-                case LeaderboardPart::Start:
-                    Trigger().InitializeFrom(pLeaderboard->GetStartTrigger(), pLeaderboard->GetStartCapturedHits());
-                    return;
-                case LeaderboardPart::Submit:
-                    Trigger().InitializeFrom(pLeaderboard->GetSubmitTrigger(), pLeaderboard->GetSubmitCapturedHits());
-                    return;
-                case LeaderboardPart::Cancel:
-                    Trigger().InitializeFrom(pLeaderboard->GetCancelTrigger(), pLeaderboard->GetCancelCapturedHits());
-                    return;
-                case LeaderboardPart::Value:
-                    Trigger().InitializeFrom(pLeaderboard->GetValueDefinition(), pLeaderboard->GetValueCapturedHits());
-                    return;
-                default:
-                    break;
-            }
+            case LeaderboardPart::Start:
+                Trigger().InitializeFrom(pLeaderboard->GetStartTrigger(), pLeaderboard->GetStartCapturedHits());
+                return;
+            case LeaderboardPart::Submit:
+                Trigger().InitializeFrom(pLeaderboard->GetSubmitTrigger(), pLeaderboard->GetSubmitCapturedHits());
+                return;
+            case LeaderboardPart::Cancel:
+                Trigger().InitializeFrom(pLeaderboard->GetCancelTrigger(), pLeaderboard->GetCancelCapturedHits());
+                return;
+            case LeaderboardPart::Value:
+                Trigger().InitializeFrom(pLeaderboard->GetValueDefinition(), pLeaderboard->GetValueCapturedHits());
+                return;
+            default:
+                break;
         }
     }
 
@@ -371,7 +404,35 @@ void AssetEditorViewModel::OnValueChanged(const BoolModelProperty::ChangeArgs& a
         if (pLeaderboard != nullptr)
         {
             if (args.Property == LowerIsBetterProperty)
+            {
                 pLeaderboard->SetLowerIsBetter(args.tNewValue);
+            }
+            else if (args.Property == PauseOnResetProperty)
+            {
+                using namespace ra::bitwise_ops;
+
+                auto nPauseOnResetParts = pLeaderboard->GetPauseOnReset();
+                const auto nSelectedPart = LeaderboardPartToParts(GetSelectedLeaderboardPart());
+                if (args.tNewValue)
+                    nPauseOnResetParts |= nSelectedPart;
+                else
+                    nPauseOnResetParts &= ~nSelectedPart;
+
+                pLeaderboard->SetPauseOnReset(nPauseOnResetParts);
+            }
+            else if (args.Property == PauseOnTriggerProperty)
+            {
+                using namespace ra::bitwise_ops;
+
+                auto nPauseOnTriggerParts = pLeaderboard->GetPauseOnTrigger();
+                const auto nSelectedPart = LeaderboardPartToParts(GetSelectedLeaderboardPart());
+                if (args.tNewValue)
+                    nPauseOnTriggerParts |= nSelectedPart;
+                else
+                    nPauseOnTriggerParts &= ~nSelectedPart;
+
+                pLeaderboard->SetPauseOnTrigger(nPauseOnTriggerParts);
+            }
         }
     }
 
@@ -703,6 +764,87 @@ void AssetEditorViewModel::UpdateAssetFrameValues()
     UpdateMeasuredValue();
 }
 
+static void UpdateLeaderboardPartColor(AssetEditorViewModel::LeaderboardPartViewModel& pPart,
+    const rc_trigger_t& pTrigger, const ra::ui::EditorTheme& pTheme, const ra::ui::Color nDefaultColor)
+{
+    switch (pTrigger.state)
+    {
+        case RC_TRIGGER_STATE_PAUSED:
+            pPart.SetColor(pTheme.ColorTriggerPauseTrue());
+            break;
+        case RC_TRIGGER_STATE_TRIGGERED:
+            pPart.SetColor(pTheme.ColorTriggerIsTrue());
+            break;
+        default:
+            if (pPart.m_nPreviousHits)
+            {
+                if (!pTrigger.has_hits)
+                    pPart.SetColor(pTheme.ColorTriggerResetTrue());
+                else
+                    pPart.SetColor(nDefaultColor);
+            }
+            else
+            {
+                pPart.SetColor(nDefaultColor);
+            }
+            break;
+    }
+
+    pPart.m_nPreviousHits = pTrigger.has_hits;
+}
+
+static bool AreAllLeaderboardValuesPaused(const rc_condset_t* pValue) noexcept
+{
+    for (; pValue != nullptr; pValue = pValue->next)
+    {
+        if (!pValue->has_pause)
+            return false;
+        if (!pValue->is_paused)
+            return false;
+    }
+
+    return true;
+}
+
+static void UpdateLeaderboardPartColors(ViewModelCollection<AssetEditorViewModel::LeaderboardPartViewModel>& vLeaderboardParts, const rc_lboard_t* pLeaderboard)
+{
+    const auto nDefaultColor = ra::ui::Color(ra::to_unsigned(AssetEditorViewModel::LeaderboardPartViewModel::ColorProperty.GetDefaultValue()));
+
+    if (pLeaderboard == nullptr)
+    {
+        // no leaderboard, or leaderboard not active, disable highlights
+        for (gsl::index i = 0; i < gsl::narrow_cast<gsl::index>(vLeaderboardParts.Count()); ++i)
+        {
+            auto* pLeaderboardPart = vLeaderboardParts.GetItemAt(i);
+            if (pLeaderboardPart != nullptr)
+                pLeaderboardPart->SetColor(nDefaultColor);
+        }
+
+        return;
+    }
+
+    const auto& pTheme = ra::services::ServiceLocator::Get<ra::ui::EditorTheme>();
+    if (pLeaderboard->state == RC_LBOARD_STATE_STARTED)
+        UpdateLeaderboardPartColor(*vLeaderboardParts.GetItemAt(0), pLeaderboard->start, pTheme, pTheme.ColorTriggerWasTrue());
+    else
+        UpdateLeaderboardPartColor(*vLeaderboardParts.GetItemAt(0), pLeaderboard->start, pTheme, nDefaultColor);
+
+    UpdateLeaderboardPartColor(*vLeaderboardParts.GetItemAt(1), pLeaderboard->submit, pTheme, nDefaultColor);
+    UpdateLeaderboardPartColor(*vLeaderboardParts.GetItemAt(2), pLeaderboard->cancel, pTheme, nDefaultColor);
+
+    GSL_SUPPRESS_CON4
+    {
+        auto nValueColor = nDefaultColor;
+        if (pLeaderboard->value.conditions != nullptr)
+        {
+            if (AreAllLeaderboardValuesPaused(pLeaderboard->value.conditions))
+                nValueColor = pTheme.ColorTriggerPauseTrue();
+        }
+
+        vLeaderboardParts.GetItemAt(3)->SetColor(nValueColor);
+    }
+}
+
 void AssetEditorViewModel::UpdateDebugHighlights()
 {
     const auto& pRuntime = ra::services::ServiceLocator::Get<ra::services::AchievementRuntime>();
@@ -720,6 +862,8 @@ void AssetEditorViewModel::UpdateDebugHighlights()
             if (pLeaderboardDefinition == nullptr)
                 break;
 
+            UpdateLeaderboardPartColors(m_vLeaderboardParts, pLeaderboardDefinition);
+
             switch (GetSelectedLeaderboardPart())
             {
                 case LeaderboardPart::Start:
diff --git a/src/ui/viewmodels/AssetEditorViewModel.hh b/src/ui/viewmodels/AssetEditorViewModel.hh
index e0073c9a..72bc021c 100644
--- a/src/ui/viewmodels/AssetEditorViewModel.hh
+++ b/src/ui/viewmodels/AssetEditorViewModel.hh
@@ -271,11 +271,28 @@ public:
         Value
     };
 
+    class LeaderboardPartViewModel : public LookupItemViewModel
+    {
+    public:
+        LeaderboardPartViewModel(int nId, const std::wstring& sLabel) noexcept
+            : LookupItemViewModel(nId, sLabel)
+        {
+        }
+
+        LeaderboardPart GetLeaderboardPart() const { return ra::itoe<LeaderboardPart>(GetValue(IDProperty)); }
+
+        static const IntModelProperty ColorProperty;
+        Color GetColor() const { return Color(ra::to_unsigned(GetValue(ColorProperty))); }
+        void SetColor(Color value) { SetValue(ColorProperty, ra::to_signed(value.ARGB)); }
+
+        bool m_nPreviousHits = false;
+    };
+
     /// <summary>
     /// Gets the list of leaderboard parts.
     /// </summary>
-    const LookupItemViewModelCollection& LeaderboardParts() const noexcept { return m_vLeaderboardParts; }
-    LookupItemViewModelCollection& LeaderboardParts() noexcept { return m_vLeaderboardParts; }
+    const ViewModelCollection<LeaderboardPartViewModel>& LeaderboardParts() const noexcept { return m_vLeaderboardParts; }
+    ViewModelCollection<LeaderboardPartViewModel>& LeaderboardParts() noexcept { return m_vLeaderboardParts; }
 
     /// <summary>
     /// The <see cref="ModelProperty" /> for the selected leaderboard part.
@@ -329,6 +346,16 @@ public:
     /// </summary>
     void SetPauseOnTrigger(bool nValue) { SetValue(PauseOnTriggerProperty, nValue); }
 
+    /// <summary>
+    /// The <see cref="ModelProperty" /> for whether or not a trigger is being edited.
+    /// </summary>
+    static const BoolModelProperty IsTriggerProperty;
+
+    /// <summary>
+    /// Gets whether or not a trigger is being edited.
+    /// </summary>
+    bool IsTrigger() const { return GetValue(IsTriggerProperty); }
+
     /// <summary>
     /// The <see cref="ModelProperty" /> for whether or not condition truthiness should be color-highlighted.
     /// </summary>
@@ -424,7 +451,7 @@ protected:
     bool m_bIgnoreTriggerUpdate = false;
 
     LookupItemViewModelCollection m_vFormats;
-    LookupItemViewModelCollection m_vLeaderboardParts;
+    ViewModelCollection<LeaderboardPartViewModel> m_vLeaderboardParts;
 };
 
 } // namespace viewmodels
diff --git a/src/ui/win32/AssetEditorDialog.cpp b/src/ui/win32/AssetEditorDialog.cpp
index a64d64b1..58a63e1a 100644
--- a/src/ui/win32/AssetEditorDialog.cpp
+++ b/src/ui/win32/AssetEditorDialog.cpp
@@ -677,6 +677,7 @@ AssetEditorDialog::AssetEditorDialog(AssetEditorViewModel& vmAssetEditor)
     m_bindWindow.BindLabel(IDC_RA_MEASURED, AssetEditorViewModel::MeasuredValueProperty);
     m_bindWindow.BindVisible(IDC_RA_LBL_MEASURED, AssetEditorViewModel::HasMeasuredProperty);
     m_bindWindow.BindVisible(IDC_RA_MEASURED, AssetEditorViewModel::HasMeasuredProperty);
+    m_bindWindow.BindEnabled(IDC_RA_CHK_PAUSE_ON_TRIGGER, AssetEditorViewModel::IsTriggerProperty);
 
     // achievement only fields
     m_bindBadge.BindText(AssetEditorViewModel::BadgeProperty);
@@ -714,6 +715,7 @@ AssetEditorDialog::AssetEditorDialog(AssetEditorViewModel& vmAssetEditor)
     m_bindLeaderboardParts.BindColumn(0, std::move(pPartColumn));
     m_bindLeaderboardParts.BindIsSelected(ra::ui::viewmodels::LookupItemViewModel::IsSelectedProperty);
     m_bindLeaderboardParts.BindItems(vmAssetEditor.LeaderboardParts());
+    m_bindLeaderboardParts.BindRowColor(AssetEditorViewModel::LeaderboardPartViewModel::ColorProperty);
 
     m_bindDebugHighlights.BindCheck(AssetEditorViewModel::DebugHighlightsEnabledProperty);
     m_bindPauseOnReset.BindCheck(AssetEditorViewModel::PauseOnResetProperty);


Test patch:
diff --git a/tests/Exports_Tests.cpp b/tests/Exports_Tests.cpp
index 55369e99..e4469e8a 100644
--- a/tests/Exports_Tests.cpp
+++ b/tests/Exports_Tests.cpp
@@ -735,6 +735,188 @@ public:
         Assert::IsNull(pScore);
     }
 
+    TEST_METHOD(TestDoAchievementsFrameLeaderboardStartPauseOnReset)
+    {
+        DoAchievementsFrameHarness harness;
+        harness.MockAchievement(1U);
+        auto& pLeaderboard = harness.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(1U);
+        pLeaderboard.SetName(L"Title");
+        harness.mockRuntime.QueueChange(ra::services::AchievementRuntime::ChangeType::LeaderboardStartReset, 1U);
+        bool bWasPaused = false;
+        harness.mockEmulatorContext.SetPauseFunction([&bWasPaused] { bWasPaused = true; });
+
+        bool bMessageSeen = false;
+        harness.mockDesktop.ExpectWindow<ra::ui::viewmodels::MessageBoxViewModel>([&bMessageSeen](ra::ui::viewmodels::MessageBoxViewModel& vmMessageBox)
+        {
+            bMessageSeen = true;
+            Assert::AreEqual(std::wstring(L"The following triggers have been reset:\n* Start: Title"), vmMessageBox.GetMessage());
+            return ra::ui::DialogResult::OK;
+        });
+
+        _RA_DoAchievementsFrame();
+        harness.mockFrameEventQueue.DoFrame(); // UpdateUIForFrameChange isn't called in the unit test build
+
+        Assert::IsTrue(bMessageSeen);
+        Assert::IsTrue(bWasPaused);
+    }
+
+    TEST_METHOD(TestDoAchievementsFrameLeaderboardSubmitPauseOnReset)
+    {
+        DoAchievementsFrameHarness harness;
+        harness.MockAchievement(1U);
+        auto& pLeaderboard = harness.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(1U);
+        pLeaderboard.SetName(L"Title");
+        harness.mockRuntime.QueueChange(ra::services::AchievementRuntime::ChangeType::LeaderboardSubmitReset, 1U);
+        bool bWasPaused = false;
+        harness.mockEmulatorContext.SetPauseFunction([&bWasPaused] { bWasPaused = true; });
+
+        bool bMessageSeen = false;
+        harness.mockDesktop.ExpectWindow<ra::ui::viewmodels::MessageBoxViewModel>([&bMessageSeen](ra::ui::viewmodels::MessageBoxViewModel& vmMessageBox)
+        {
+            bMessageSeen = true;
+            Assert::AreEqual(std::wstring(L"The following triggers have been reset:\n* Submit: Title"), vmMessageBox.GetMessage());
+            return ra::ui::DialogResult::OK;
+        });
+
+        _RA_DoAchievementsFrame();
+        harness.mockFrameEventQueue.DoFrame(); // UpdateUIForFrameChange isn't called in the unit test build
+
+        Assert::IsTrue(bMessageSeen);
+        Assert::IsTrue(bWasPaused);
+    }
+
+    TEST_METHOD(TestDoAchievementsFrameLeaderboardCancelPauseOnReset)
+    {
+        DoAchievementsFrameHarness harness;
+        harness.MockAchievement(1U);
+        auto& pLeaderboard = harness.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(1U);
+        pLeaderboard.SetName(L"Title");
+        harness.mockRuntime.QueueChange(ra::services::AchievementRuntime::ChangeType::LeaderboardCancelReset, 1U);
+        bool bWasPaused = false;
+        harness.mockEmulatorContext.SetPauseFunction([&bWasPaused] { bWasPaused = true; });
+
+        bool bMessageSeen = false;
+        harness.mockDesktop.ExpectWindow<ra::ui::viewmodels::MessageBoxViewModel>([&bMessageSeen](ra::ui::viewmodels::MessageBoxViewModel& vmMessageBox)
+        {
+            bMessageSeen = true;
+            Assert::AreEqual(std::wstring(L"The following triggers have been reset:\n* Cancel: Title"), vmMessageBox.GetMessage());
+            return ra::ui::DialogResult::OK;
+        });
+
+        _RA_DoAchievementsFrame();
+        harness.mockFrameEventQueue.DoFrame(); // UpdateUIForFrameChange isn't called in the unit test build
+
+        Assert::IsTrue(bMessageSeen);
+        Assert::IsTrue(bWasPaused);
+    }
+
+    TEST_METHOD(TestDoAchievementsFrameLeaderboardValuePauseOnReset)
+    {
+        DoAchievementsFrameHarness harness;
+        harness.MockAchievement(1U);
+        auto& pLeaderboard = harness.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(1U);
+        pLeaderboard.SetName(L"Title");
+        harness.mockRuntime.QueueChange(ra::services::AchievementRuntime::ChangeType::LeaderboardValueReset, 1U);
+        bool bWasPaused = false;
+        harness.mockEmulatorContext.SetPauseFunction([&bWasPaused] { bWasPaused = true; });
+
+        bool bMessageSeen = false;
+        harness.mockDesktop.ExpectWindow<ra::ui::viewmodels::MessageBoxViewModel>([&bMessageSeen](ra::ui::viewmodels::MessageBoxViewModel& vmMessageBox)
+        {
+            bMessageSeen = true;
+            Assert::AreEqual(std::wstring(L"The following triggers have been reset:\n* Value: Title"), vmMessageBox.GetMessage());
+            return ra::ui::DialogResult::OK;
+        });
+
+        _RA_DoAchievementsFrame();
+        harness.mockFrameEventQueue.DoFrame(); // UpdateUIForFrameChange isn't called in the unit test build
+
+        Assert::IsTrue(bMessageSeen);
+        Assert::IsTrue(bWasPaused);
+    }
+
+    TEST_METHOD(TestDoAchievementsFrameLeaderboardStartPauseOnTriggered)
+    {
+        DoAchievementsFrameHarness harness;
+        harness.MockAchievement(1U);
+        auto& pLeaderboard = harness.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(1U);
+        pLeaderboard.SetName(L"Title");
+        harness.mockRuntime.QueueChange(ra::services::AchievementRuntime::ChangeType::LeaderboardStartTriggered, 1U);
+        bool bWasPaused = false;
+        harness.mockEmulatorContext.SetPauseFunction([&bWasPaused] { bWasPaused = true; });
+
+        bool bMessageSeen = false;
+        harness.mockDesktop.ExpectWindow<ra::ui::viewmodels::MessageBoxViewModel>([&bMessageSeen](ra::ui::viewmodels::MessageBoxViewModel& vmMessageBox)
+        {
+            bMessageSeen = true;
+            Assert::AreEqual(std::wstring(L"The following triggers have triggered:\n* Start: Title"), vmMessageBox.GetMessage());
+            return ra::ui::DialogResult::OK;
+        });
+
+        _RA_DoAchievementsFrame();
+        harness.mockFrameEventQueue.DoFrame(); // UpdateUIForFrameChange isn't called in the unit test build
+
+        Assert::IsTrue(bMessageSeen);
+        Assert::IsTrue(bWasPaused);
+    }
+
+    TEST_METHOD(TestDoAchievementsFrameLeaderboardSubmitPauseOnTriggered)
+    {
+        DoAchievementsFrameHarness harness;
+        harness.MockAchievement(1U);
+        auto& pLeaderboard = harness.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(1U);
+        pLeaderboard.SetName(L"Title");
+        harness.mockRuntime.QueueChange(ra::services::AchievementRuntime::ChangeType::LeaderboardSubmitTriggered, 1U);
+        bool bWasPaused = false;
+        harness.mockEmulatorContext.SetPauseFunction([&bWasPaused] { bWasPaused = true; });
+
+        bool bMessageSeen = false;
+        harness.mockDesktop.ExpectWindow<ra::ui::viewmodels::MessageBoxViewModel>([&bMessageSeen](ra::ui::viewmodels::MessageBoxViewModel& vmMessageBox)
+        {
+            bMessageSeen = true;
+            Assert::AreEqual(std::wstring(L"The following triggers have triggered:\n* Submit: Title"), vmMessageBox.GetMessage());
+            return ra::ui::DialogResult::OK;
+        });
+
+        _RA_DoAchievementsFrame();
+        harness.mockFrameEventQueue.DoFrame(); // UpdateUIForFrameChange isn't called in the unit test build
+
+        Assert::IsTrue(bMessageSeen);
+        Assert::IsTrue(bWasPaused);
+    }
+
+    TEST_METHOD(TestDoAchievementsFrameLeaderboardCancelPauseOnTriggered)
+    {
+        DoAchievementsFrameHarness harness;
+        harness.MockAchievement(1U);
+        auto& pLeaderboard = harness.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(1U);
+        pLeaderboard.SetName(L"Title");
+        harness.mockRuntime.QueueChange(ra::services::AchievementRuntime::ChangeType::LeaderboardCancelTriggered, 1U);
+        bool bWasPaused = false;
+        harness.mockEmulatorContext.SetPauseFunction([&bWasPaused] { bWasPaused = true; });
+
+        bool bMessageSeen = false;
+        harness.mockDesktop.ExpectWindow<ra::ui::viewmodels::MessageBoxViewModel>([&bMessageSeen](ra::ui::viewmodels::MessageBoxViewModel& vmMessageBox)
+        {
+            bMessageSeen = true;
+            Assert::AreEqual(std::wstring(L"The following triggers have triggered:\n* Cancel: Title"), vmMessageBox.GetMessage());
+            return ra::ui::DialogResult::OK;
+        });
+
+        _RA_DoAchievementsFrame();
+        harness.mockFrameEventQueue.DoFrame(); // UpdateUIForFrameChange isn't called in the unit test build
+
+        Assert::IsTrue(bMessageSeen);
+        Assert::IsTrue(bWasPaused);
+    }
+
     TEST_METHOD(TestDoAchievementsFrameMultiple)
     {
         DoAchievementsFrameHarness harness;
diff --git a/tests/data/DataAsserts.hh b/tests/data/DataAsserts.hh
index d6818d2e..0fa69661 100644
--- a/tests/data/DataAsserts.hh
+++ b/tests/data/DataAsserts.hh
@@ -132,6 +132,26 @@ std::wstring ToString<ra::data::ValueFormat>(const ra::data::ValueFormat& nForma
     }
 }
 
+template<>
+std::wstring ToString<ra::data::models::LeaderboardModel::LeaderboardParts>(const ra::data::models::LeaderboardModel::LeaderboardParts& nParts)
+{
+    switch (nParts)
+    {
+        case ra::data::models::LeaderboardModel::LeaderboardParts::None:
+            return L"None";
+        case ra::data::models::LeaderboardModel::LeaderboardParts::Start:
+            return L"Start";
+        case ra::data::models::LeaderboardModel::LeaderboardParts::Submit:
+            return L"Submit";
+        case ra::data::models::LeaderboardModel::LeaderboardParts::Cancel:
+            return L"Cancel";
+        case ra::data::models::LeaderboardModel::LeaderboardParts::Value:
+            return L"Value";
+        default:
+            return std::to_wstring(static_cast<int>(nParts));
+    }
+}
+
 #pragma warning(pop)
 
 } // namespace CppUnitTestFramework
diff --git a/tests/services/AchievementRuntime_Tests.cpp b/tests/services/AchievementRuntime_Tests.cpp
index 01a988a9..0b5ef390 100644
--- a/tests/services/AchievementRuntime_Tests.cpp
+++ b/tests/services/AchievementRuntime_Tests.cpp
@@ -949,6 +949,289 @@ public:
 
         Assert::AreEqual(std::wstring(L"Parse error -6 (line 5): Invalid operator"), runtime.GetRichPresenceDisplayString());
     }
+
+    TEST_METHOD(TestProcessLeaderboardStartPauseOnReset)
+    {
+        std::array<unsigned char, 2> memory{ 0x00, 0x00 };
+
+        AchievementRuntimeHarness runtime;
+        runtime.mockEmulatorContext.MockMemory(memory);
+        std::vector<AchievementRuntime::Change> vChanges;
+        auto* pDefinition = "STA:0xH0000=0_0xH0000=9_R:0xH0001=1::SUB:0xH0000=1::CAN:0xH0000=2::VAL:0xH0000";
+
+        auto& pLeaderboard = runtime.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(6U);
+
+        runtime.ActivateLeaderboard(6U, pDefinition);
+        const auto* pLboard = runtime.GetLeaderboardDefinition(6U);
+        runtime.Process(vChanges);
+        Assert::IsTrue(pLboard->start.has_hits);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        memory.at(1) = 1;
+        runtime.Process(vChanges);
+        Assert::IsFalse(pLboard->start.has_hits);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        pLeaderboard.SetPauseOnReset(ra::data::models::LeaderboardModel::LeaderboardParts::Start);
+
+        memory.at(1) = 0;
+        runtime.Process(vChanges);
+        Assert::IsTrue(pLboard->start.has_hits);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        memory.at(1) = 1;
+        runtime.Process(vChanges);
+        Assert::IsFalse(pLboard->start.has_hits);
+
+        runtime.Process(vChanges);
+        Assert::AreEqual({ 1U }, vChanges.size());
+        AssertChange(vChanges, AchievementRuntime::ChangeType::LeaderboardStartReset, 6U);
+    }
+
+    TEST_METHOD(TestProcessLeaderboardSubmitPauseOnReset)
+    {
+        std::array<unsigned char, 2> memory{ 0x00, 0x00 };
+
+        AchievementRuntimeHarness runtime;
+        runtime.mockEmulatorContext.MockMemory(memory);
+        std::vector<AchievementRuntime::Change> vChanges;
+        auto* pDefinition = "STA:0xH0000=1::SUB:0xH0000=0_0xH0000=9_R:0xH0001=1::CAN:0xH0000=2::VAL:0xH0000";
+
+        auto& pLeaderboard = runtime.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(6U);
+
+        runtime.ActivateLeaderboard(6U, pDefinition);
+        const auto* pLboard = runtime.GetLeaderboardDefinition(6U);
+        runtime.Process(vChanges);
+        Assert::IsTrue(pLboard->submit.has_hits);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        memory.at(1) = 1;
+        runtime.Process(vChanges);
+        Assert::IsFalse(pLboard->submit.has_hits);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        pLeaderboard.SetPauseOnReset(ra::data::models::LeaderboardModel::LeaderboardParts::Submit);
+
+        memory.at(1) = 0;
+        runtime.Process(vChanges);
+        Assert::IsTrue(pLboard->submit.has_hits);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        memory.at(1) = 1;
+        runtime.Process(vChanges);
+        Assert::IsFalse(pLboard->submit.has_hits);
+
+        runtime.Process(vChanges);
+        Assert::AreEqual({ 1U }, vChanges.size());
+        AssertChange(vChanges, AchievementRuntime::ChangeType::LeaderboardSubmitReset, 6U);
+    }
+
+    TEST_METHOD(TestProcessLeaderboardCancelPauseOnReset)
+    {
+        std::array<unsigned char, 2> memory{ 0x00, 0x00 };
+
+        AchievementRuntimeHarness runtime;
+        runtime.mockEmulatorContext.MockMemory(memory);
+        std::vector<AchievementRuntime::Change> vChanges;
+        auto* pDefinition = "STA:0xH0000=1::SUB:0xH0000=2::CAN:0xH0000=0_0xH0000=9_R:0xH0001=1::VAL:0xH0000";
+
+        auto& pLeaderboard = runtime.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(6U);
+
+        runtime.ActivateLeaderboard(6U, pDefinition);
+        const auto* pLboard = runtime.GetLeaderboardDefinition(6U);
+        runtime.Process(vChanges);
+        Assert::IsTrue(pLboard->cancel.has_hits);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        memory.at(1) = 1;
+        runtime.Process(vChanges);
+        Assert::IsFalse(pLboard->cancel.has_hits);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        pLeaderboard.SetPauseOnReset(ra::data::models::LeaderboardModel::LeaderboardParts::Cancel);
+
+        memory.at(1) = 0;
+        runtime.Process(vChanges);
+        Assert::IsTrue(pLboard->cancel.has_hits);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        memory.at(1) = 1;
+        runtime.Process(vChanges);
+        Assert::IsFalse(pLboard->cancel.has_hits);
+
+        runtime.Process(vChanges);
+        Assert::AreEqual({ 1U }, vChanges.size());
+        AssertChange(vChanges, AchievementRuntime::ChangeType::LeaderboardCancelReset, 6U);
+    }
+
+    TEST_METHOD(TestProcessLeaderboardValuePauseOnReset)
+    {
+        std::array<unsigned char, 2> memory{ 0x05, 0x00 };
+
+        AchievementRuntimeHarness runtime;
+        runtime.mockEmulatorContext.MockMemory(memory);
+        std::vector<AchievementRuntime::Change> vChanges;
+        auto* pDefinition = "STA:0xH0000=0::SUB:0xH0000=2::CAN:0xH0000=3::VAL:Q:0xH0001=0_M:0xH0000";
+
+        auto& pLeaderboard = runtime.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(6U);
+
+        runtime.ActivateLeaderboard(6U, pDefinition);
+        auto* pLboard = runtime.GetLeaderboardDefinition(6U);
+        pLboard->state = RC_LBOARD_STATE_STARTED; // value not calculated if not started
+        runtime.Process(vChanges);
+        Assert::AreEqual(5U, pLboard->value.value.value);
+        Assert::AreEqual({ 1U }, vChanges.size());
+        AssertChange(vChanges, AchievementRuntime::ChangeType::LeaderboardUpdated, 6U);
+        vChanges.clear();
+
+        memory.at(1) = 1;
+        runtime.Process(vChanges);
+        Assert::AreEqual(0U, pLboard->value.value.value);
+        Assert::AreEqual({ 1U }, vChanges.size());
+        AssertChange(vChanges, AchievementRuntime::ChangeType::LeaderboardUpdated, 6U);
+        vChanges.clear();
+
+        pLeaderboard.SetPauseOnReset(ra::data::models::LeaderboardModel::LeaderboardParts::Value);
+
+        memory.at(1) = 0;
+        runtime.Process(vChanges);
+        Assert::AreEqual(5U, pLboard->value.value.value);
+        Assert::AreEqual({ 1U }, vChanges.size());
+        AssertChange(vChanges, AchievementRuntime::ChangeType::LeaderboardUpdated, 6U);
+        vChanges.clear();
+
+        memory.at(1) = 1;
+        runtime.Process(vChanges);
+        Assert::AreEqual(0U, pLboard->value.value.value);
+
+        runtime.Process(vChanges);
+        Assert::AreEqual({ 2U }, vChanges.size());
+        AssertChange(vChanges, AchievementRuntime::ChangeType::LeaderboardUpdated, 6U);
+        AssertChange(vChanges, AchievementRuntime::ChangeType::LeaderboardValueReset, 6U);
+    }
+
+    TEST_METHOD(TestProcessLeaderboardStartPauseOnTrigger)
+    {
+        std::array<unsigned char, 2> memory{ 0x00, 0x00 };
+
+        AchievementRuntimeHarness runtime;
+        runtime.mockEmulatorContext.MockMemory(memory);
+        std::vector<AchievementRuntime::Change> vChanges;
+        auto* pDefinition = "STA:0xH0000=1::SUB:0xH0000=2::CAN:0xH0000=3::VAL:0xH0001";
+
+        auto& pLeaderboard = runtime.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(6U);
+
+        runtime.ActivateLeaderboard(6U, pDefinition);
+        const auto* pLboard = runtime.GetLeaderboardDefinition(6U);
+        runtime.Process(vChanges);
+        Assert::AreEqual((int)RC_TRIGGER_STATE_ACTIVE, (int)pLboard->start.state);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        memory.at(0) = 1;
+        runtime.Process(vChanges);
+        Assert::AreEqual((int)RC_TRIGGER_STATE_TRIGGERED, (int)pLboard->start.state);
+        Assert::AreEqual({ 1U }, vChanges.size());
+        AssertChange(vChanges, AchievementRuntime::ChangeType::LeaderboardStarted, 6U);
+        vChanges.clear();
+
+        pLeaderboard.SetPauseOnTrigger(ra::data::models::LeaderboardModel::LeaderboardParts::Start);
+
+        memory.at(0) = 0;
+        runtime.Process(vChanges);
+        Assert::AreEqual((int)RC_TRIGGER_STATE_ACTIVE, (int)pLboard->start.state);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        memory.at(0) = 1;
+        runtime.Process(vChanges);
+        Assert::AreEqual((int)RC_TRIGGER_STATE_TRIGGERED, (int)pLboard->start.state);
+
+        runtime.Process(vChanges);
+        Assert::AreEqual({ 1U }, vChanges.size());
+        AssertChange(vChanges, AchievementRuntime::ChangeType::LeaderboardStartTriggered, 6U);
+    }
+
+    TEST_METHOD(TestProcessLeaderboardSubmitPauseOnTrigger)
+    {
+        std::array<unsigned char, 2> memory{ 0x00, 0x00 };
+
+        AchievementRuntimeHarness runtime;
+        runtime.mockEmulatorContext.MockMemory(memory);
+        std::vector<AchievementRuntime::Change> vChanges;
+        auto* pDefinition = "STA:0xH0000=1::SUB:0xH0000=2::CAN:0xH0000=3::VAL:0xH0001";
+
+        auto& pLeaderboard = runtime.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(6U);
+
+        runtime.ActivateLeaderboard(6U, pDefinition);
+        const auto* pLboard = runtime.GetLeaderboardDefinition(6U);
+        runtime.Process(vChanges);
+        Assert::AreEqual((int)RC_TRIGGER_STATE_ACTIVE, (int)pLboard->submit.state);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        memory.at(0) = 2;
+        runtime.Process(vChanges);
+        Assert::AreEqual((int)RC_TRIGGER_STATE_TRIGGERED, (int)pLboard->submit.state);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        pLeaderboard.SetPauseOnTrigger(ra::data::models::LeaderboardModel::LeaderboardParts::Submit);
+
+        memory.at(0) = 0;
+        runtime.Process(vChanges);
+        Assert::AreEqual((int)RC_TRIGGER_STATE_ACTIVE, (int)pLboard->submit.state);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        memory.at(0) = 2;
+        runtime.Process(vChanges);
+        Assert::AreEqual((int)RC_TRIGGER_STATE_TRIGGERED, (int)pLboard->submit.state);
+
+        runtime.Process(vChanges);
+        Assert::AreEqual({ 1U }, vChanges.size());
+        AssertChange(vChanges, AchievementRuntime::ChangeType::LeaderboardSubmitTriggered, 6U);
+    }
+
+    TEST_METHOD(TestProcessLeaderboardCancelPauseOnTrigger)
+    {
+        std::array<unsigned char, 2> memory{ 0x00, 0x00 };
+
+        AchievementRuntimeHarness runtime;
+        runtime.mockEmulatorContext.MockMemory(memory);
+        std::vector<AchievementRuntime::Change> vChanges;
+        auto* pDefinition = "STA:0xH0000=1::SUB:0xH0000=2::CAN:0xH0000=3::VAL:0xH0001";
+
+        auto& pLeaderboard = runtime.mockGameContext.Assets().NewLeaderboard();
+        pLeaderboard.SetID(6U);
+
+        runtime.ActivateLeaderboard(6U, pDefinition);
+        const auto* pLboard = runtime.GetLeaderboardDefinition(6U);
+        runtime.Process(vChanges);
+        Assert::AreEqual((int)RC_TRIGGER_STATE_ACTIVE, (int)pLboard->cancel.state);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        memory.at(0) = 3;
+        runtime.Process(vChanges);
+        Assert::AreEqual((int)RC_TRIGGER_STATE_TRIGGERED, (int)pLboard->cancel.state);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        pLeaderboard.SetPauseOnTrigger(ra::data::models::LeaderboardModel::LeaderboardParts::Cancel);
+
+        memory.at(0) = 0;
+        runtime.Process(vChanges);
+        Assert::AreEqual((int)RC_TRIGGER_STATE_ACTIVE, (int)pLboard->cancel.state);
+        Assert::AreEqual({ 0U }, vChanges.size());
+
+        memory.at(0) = 3;
+        runtime.Process(vChanges);
+        Assert::AreEqual((int)RC_TRIGGER_STATE_TRIGGERED, (int)pLboard->cancel.state);
+
+        runtime.Process(vChanges);
+        Assert::AreEqual({ 1U }, vChanges.size());
+        AssertChange(vChanges, AchievementRuntime::ChangeType::LeaderboardCancelTriggered, 6U);
+    }
 };
 
 } // namespace tests
diff --git a/tests/ui/viewmodels/AssetEditorViewModel_Tests.cpp b/tests/ui/viewmodels/AssetEditorViewModel_Tests.cpp
index 95b22460..6a014897 100644
--- a/tests/ui/viewmodels/AssetEditorViewModel_Tests.cpp
+++ b/tests/ui/viewmodels/AssetEditorViewModel_Tests.cpp
@@ -103,6 +103,7 @@ public:
         Assert::AreEqual(std::wstring(L"[Not Active]"), editor.GetMeasuredValue());
         Assert::IsTrue(editor.IsAchievement());
         Assert::IsFalse(editor.IsLeaderboard());
+        Assert::IsTrue(editor.IsTrigger());
         Assert::AreEqual((int)AssetEditorViewModel::LeaderboardPart::Start, (int)editor.GetSelectedLeaderboardPart());
         Assert::AreEqual(ra::data::ValueFormat::Value, editor.GetValueFormat());
 
@@ -123,10 +124,10 @@ public:
         Assert::AreEqual({ 4U }, editor.LeaderboardParts().Count());
         Assert::AreEqual((int)AssetEditorViewModel::LeaderboardPart::Start, editor.LeaderboardParts().GetItemAt(0)->GetId());
         Assert::AreEqual(std::wstring(L"Start"), editor.LeaderboardParts().GetItemAt(0)->GetLabel());
-        Assert::AreEqual((int)AssetEditorViewModel::LeaderboardPart::Submit, editor.LeaderboardParts().GetItemAt(1)->GetId());
-        Assert::AreEqual(std::wstring(L"Submit"), editor.LeaderboardParts().GetItemAt(1)->GetLabel());
-        Assert::AreEqual((int)AssetEditorViewModel::LeaderboardPart::Cancel, editor.LeaderboardParts().GetItemAt(2)->GetId());
-        Assert::AreEqual(std::wstring(L"Cancel"), editor.LeaderboardParts().GetItemAt(2)->GetLabel());
+        Assert::AreEqual((int)AssetEditorViewModel::LeaderboardPart::Cancel, editor.LeaderboardParts().GetItemAt(1)->GetId());
+        Assert::AreEqual(std::wstring(L"Cancel"), editor.LeaderboardParts().GetItemAt(1)->GetLabel());
+        Assert::AreEqual((int)AssetEditorViewModel::LeaderboardPart::Submit, editor.LeaderboardParts().GetItemAt(2)->GetId());
+        Assert::AreEqual(std::wstring(L"Submit"), editor.LeaderboardParts().GetItemAt(2)->GetLabel());
         Assert::AreEqual((int)AssetEditorViewModel::LeaderboardPart::Value, editor.LeaderboardParts().GetItemAt(3)->GetId());
         Assert::AreEqual(std::wstring(L"Value"), editor.LeaderboardParts().GetItemAt(3)->GetLabel());
     }
@@ -158,6 +159,9 @@ public:
         Assert::IsFalse(editor.IsPauseOnReset());
         Assert::IsFalse(editor.IsPauseOnTrigger());
         Assert::IsTrue(editor.IsAssetLoaded());
+        Assert::IsTrue(editor.IsAchievement());
+        Assert::IsFalse(editor.IsLeaderboard());
+        Assert::IsTrue(editor.IsTrigger());
         Assert::IsFalse(editor.HasMeasured());
         Assert::IsFalse(editor.HasAssetValidationError());
         Assert::IsFalse(editor.HasAssetValidationWarning());
@@ -176,6 +180,9 @@ public:
         Assert::IsFalse(editor.IsPauseOnReset());
         Assert::IsFalse(editor.IsPauseOnTrigger());
         Assert::IsFalse(editor.IsAssetLoaded());
+        Assert::IsTrue(editor.IsAchievement());
+        Assert::IsFalse(editor.IsLeaderboard());
+        Assert::IsTrue(editor.IsTrigger());
         Assert::IsFalse(editor.HasMeasured());
         Assert::IsFalse(editor.HasAssetValidationError());
         Assert::IsFalse(editor.HasAssetValidationWarning());
@@ -478,6 +485,9 @@ public:
         Assert::IsFalse(editor.IsPauseOnReset());
         Assert::IsFalse(editor.IsPauseOnTrigger());
         Assert::IsTrue(editor.IsAssetLoaded());
+        Assert::IsFalse(editor.IsAchievement());
+        Assert::IsTrue(editor.IsLeaderboard());
+        Assert::IsTrue(editor.IsTrigger());
         Assert::IsTrue(editor.HasMeasured());
         Assert::IsFalse(editor.HasAssetValidationError());
         Assert::IsFalse(editor.HasAssetValidationWarning());
@@ -851,6 +861,110 @@ public:
         Assert::IsFalse(achievement.IsPauseOnTrigger());
     }
 
+    TEST_METHOD(TestSyncPauseOnResetLeaderboardStart)
+    {
+        AssetEditorViewModelHarness editor;
+        LeaderboardModel leaderboard;
+        leaderboard.SetPauseOnReset(LeaderboardModel::LeaderboardParts::Start);
+        leaderboard.CreateServerCheckpoint();
+        leaderboard.CreateLocalCheckpoint();
+
+        editor.LoadAsset(&leaderboard);
+        editor.SetSelectedLeaderboardPart(AssetEditorViewModel::LeaderboardPart::Start);
+        Assert::IsTrue(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::Start, leaderboard.GetPauseOnReset());
+
+        editor.SetPauseOnReset(false);
+        Assert::IsFalse(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::None, leaderboard.GetPauseOnReset());
+
+        editor.SetPauseOnReset(true);
+        Assert::IsTrue(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::Start, leaderboard.GetPauseOnReset());
+
+        editor.SetPauseOnReset(false);
+        Assert::IsFalse(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::None, leaderboard.GetPauseOnReset());
+    }
+
+    TEST_METHOD(TestSyncPauseOnResetLeaderboardSubmit)
+    {
+        AssetEditorViewModelHarness editor;
+        LeaderboardModel leaderboard;
+        leaderboard.SetPauseOnReset(LeaderboardModel::LeaderboardParts::Submit);
+        leaderboard.CreateServerCheckpoint();
+        leaderboard.CreateLocalCheckpoint();
+
+        editor.LoadAsset(&leaderboard);
+        editor.SetSelectedLeaderboardPart(AssetEditorViewModel::LeaderboardPart::Submit);
+        Assert::IsTrue(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::Submit, leaderboard.GetPauseOnReset());
+
+        editor.SetPauseOnReset(false);
+        Assert::IsFalse(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::None, leaderboard.GetPauseOnReset());
+
+        editor.SetPauseOnReset(true);
+        Assert::IsTrue(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::Submit, leaderboard.GetPauseOnReset());
+
+        editor.SetPauseOnReset(false);
+        Assert::IsFalse(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::None, leaderboard.GetPauseOnReset());
+    }
+
+    TEST_METHOD(TestSyncPauseOnResetLeaderboardCancel)
+    {
+        AssetEditorViewModelHarness editor;
+        LeaderboardModel leaderboard;
+        leaderboard.SetPauseOnReset(LeaderboardModel::LeaderboardParts::Cancel);
+        leaderboard.CreateServerCheckpoint();
+        leaderboard.CreateLocalCheckpoint();
+
+        editor.LoadAsset(&leaderboard);
+        editor.SetSelectedLeaderboardPart(AssetEditorViewModel::LeaderboardPart::Cancel);
+        Assert::IsTrue(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::Cancel, leaderboard.GetPauseOnReset());
+
+        editor.SetPauseOnReset(false);
+        Assert::IsFalse(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::None, leaderboard.GetPauseOnReset());
+
+        editor.SetPauseOnReset(true);
+        Assert::IsTrue(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::Cancel, leaderboard.GetPauseOnReset());
+
+        editor.SetPauseOnReset(false);
+        Assert::IsFalse(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::None, leaderboard.GetPauseOnReset());
+    }
+
+    TEST_METHOD(TestSyncPauseOnResetLeaderboardValue)
+    {
+        AssetEditorViewModelHarness editor;
+        LeaderboardModel leaderboard;
+        leaderboard.SetPauseOnReset(LeaderboardModel::LeaderboardParts::Value);
+        leaderboard.CreateServerCheckpoint();
+        leaderboard.CreateLocalCheckpoint();
+
+        editor.LoadAsset(&leaderboard);
+        editor.SetSelectedLeaderboardPart(AssetEditorViewModel::LeaderboardPart::Value);
+        Assert::IsTrue(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::Value, leaderboard.GetPauseOnReset());
+
+        editor.SetPauseOnReset(false);
+        Assert::IsFalse(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::None, leaderboard.GetPauseOnReset());
+
+        editor.SetPauseOnReset(true);
+        Assert::IsTrue(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::Value, leaderboard.GetPauseOnReset());
+
+        editor.SetPauseOnReset(false);
+        Assert::IsFalse(editor.IsPauseOnReset());
+        Assert::AreEqual(LeaderboardModel::LeaderboardParts::None, leaderboard.GetPauseOnReset());
+    }
+
     TEST_METHOD(TestSyncOneRecordAtATime)
     {
         AssetEditorViewModelHarness editor;
@@ -1541,30 +1655,35 @@ public:
         Assert::AreEqual(std::string("0xH1234=6.1."), editor.Trigger().Serialize());
         Assert::AreEqual(std::wstring(L"Groups:"), editor.GetGroupsHeaderLabel());
         Assert::IsFalse(editor.Trigger().IsValue());
+        Assert::IsTrue(editor.IsTrigger());
         Assert::IsFalse(leaderboard.IsModified());
 
         editor.SetSelectedLeaderboardPart(AssetEditorViewModel::LeaderboardPart::Submit);
         Assert::AreEqual(std::string("0xH2345!=99"), editor.Trigger().Serialize());
         Assert::AreEqual(std::wstring(L"Groups:"), editor.GetGroupsHeaderLabel());
         Assert::IsFalse(editor.Trigger().IsValue());
+        Assert::IsTrue(editor.IsTrigger());
         Assert::IsFalse(leaderboard.IsModified());
 
         editor.SetSelectedLeaderboardPart(AssetEditorViewModel::LeaderboardPart::Cancel);
         Assert::AreEqual(std::string("0xH3456>3"), editor.Trigger().Serialize());
         Assert::AreEqual(std::wstring(L"Groups:"), editor.GetGroupsHeaderLabel());
         Assert::IsFalse(editor.Trigger().IsValue());
+        Assert::IsTrue(editor.IsTrigger());
         Assert::IsFalse(leaderboard.IsModified());
 
         editor.SetSelectedLeaderboardPart(AssetEditorViewModel::LeaderboardPart::Value);
         Assert::AreEqual(std::string("M:0xH4444"), editor.Trigger().Serialize());
         Assert::AreEqual(std::wstring(L"Max of:"), editor.GetGroupsHeaderLabel());
         Assert::IsTrue(editor.Trigger().IsValue());
+        Assert::IsFalse(editor.IsTrigger());
         Assert::IsFalse(leaderboard.IsModified());
 
         editor.SetSelectedLeaderboardPart(AssetEditorViewModel::LeaderboardPart::Start);
         Assert::AreEqual(std::string("0xH1234=6.1."), editor.Trigger().Serialize());
         Assert::AreEqual(std::wstring(L"Groups:"), editor.GetGroupsHeaderLabel());
         Assert::IsFalse(editor.Trigger().IsValue());
+        Assert::IsTrue(editor.IsTrigger());
         Assert::IsFalse(leaderboard.IsModified());
     }
 };