Changeset - f1d4569c0495
[Not reviewed]
default
0 4 0
Tess Snider (Malkyne) - 3 years ago 2021-07-24 10:26:20
this@malkyne.org
3 way reactions should now allow you to change the position of the buffer
reagent from first to last.
4 files changed with 178 insertions and 39 deletions:
0 comments (0 inline, 0 general)
Models/ReactionTest.cs
Show inline comments
...
 
@@ -19,39 +19,61 @@ namespace DesertPaintCodex.Models
 
            ClippedResult,
 
            GoodResult,
 
            Saved
 
        }
 

	
 
        public Reagent Reagent1 { get; }
 
        public Reagent Reagent2 { get; }
 

	
 
        private Reagent? _bufferReagent;
 
        public Reagent? BufferReagent
 
        private Reagent? _bufferReagentFirst;
 
        public Reagent? BufferReagentFirst
 
        {
 
            get => _bufferReagentFirst;
 
            set
 
        {
 
            get => _bufferReagent;
 
                if (_bufferReagentFirst == value) return;
 
                _bufferReagentFirst = value;
 
                
 
                UpdateRecipe();
 
                
 
                NotifyPropertyChanged(nameof(BufferReagentFirst));
 
                NotifyPropertyChanged(nameof(CanScan));
 
            }
 
        }
 
        
 
        private Reagent? _bufferReagentLast;
 
        public Reagent? BufferReagentLast
 
        {
 
            get => _bufferReagentLast;
 
            set
 
            {
 
                if (_bufferReagent == value) return;
 
                _bufferReagent = value;
 
                _recipe.Clear();
 
                if (_bufferReagent == null)
 
                {
 
                    _recipe.AddReagent(Reagent1.Name);
 
                    _recipe.AddReagent(Reagent2.Name);
 
                if (_bufferReagentLast == value) return;
 
                _bufferReagentLast = value;
 

	
 
                UpdateRecipe();
 

	
 
                NotifyPropertyChanged(nameof(BufferReagentLast));
 
                NotifyPropertyChanged(nameof(CanScan));
 
            }
 
                }
 
                else
 

	
 
        private bool _useFirstBuffer;
 

	
 
        public bool UseFirstBuffer
 
                {
 
                    _recipe.AddReagent(_bufferReagent.Name);
 
                    _recipe.AddReagent(Reagent1.Name);
 
                    _recipe.AddReagent(Reagent2.Name);
 
                }
 
                NotifyPropertyChanged(nameof(BufferReagent));
 
            get => _useFirstBuffer;
 
            set
 
            {
 
                _useFirstBuffer = value;
 
                UpdateRecipe();
 
                NotifyPropertyChanged(nameof(UseFirstBuffer));
 
                NotifyPropertyChanged(nameof(CanScan));
 
                UpdateHypotheticalColor();
 
                NotifyPropertyChanged(nameof(ShowFirstBuffer));
 
                NotifyPropertyChanged(nameof(ShowLastBuffer));
 
            }
 
        }
 

	
 
        private ClipType _clipType;
 
        public ClipType Clipped {
 
            get => _clipType;
 
            set
 
            {
...
 
@@ -85,54 +107,61 @@ namespace DesertPaintCodex.Models
 
                NotifyPropertyChanged(nameof(CanScan));
 
                NotifyPropertyChanged(nameof(IsScanning));
 
                NotifyPropertyChanged(nameof(HasResults));
 
                NotifyPropertyChanged(nameof(HasReaction));
 
                NotifyPropertyChanged(nameof(CanClear));
 
                NotifyPropertyChanged(nameof(CanSave));
 
                NotifyPropertyChanged(nameof(NoLab));
 
                NotifyPropertyChanged(nameof(CanPickBuffer));
 
                NotifyPropertyChanged(nameof(ShowFirstBuffer));
 
                NotifyPropertyChanged(nameof(ShowLastBuffer));
 
            }
 
        }
 

	
 
        public bool Requires3Way =>
 
            (State == TestState.ClippedResult) || IsAllCatalysts;
 

	
 
        public bool CanScan => (State is TestState.Untested or TestState.LabNotFound) || ((State == TestState.ClippedResult) && (BufferReagent != null));
 
        public bool CanScan => (State is TestState.Untested or TestState.LabNotFound) || ((State == TestState.ClippedResult) && BufferIsSelected);
 
        
 
        public bool IsScanning => State == TestState.Scanning;
 

	
 
        public bool HasResults => (ObservedColor != null) && (State is TestState.ClippedResult or TestState.GoodResult or TestState.LabNotFound);
 

	
 
        public bool HasReaction => State is TestState.ClippedResult or TestState.GoodResult or TestState.Saved;
 
        
 
        public bool CanClear => State is TestState.ClippedResult or TestState.GoodResult or TestState.Saved;
 
        
 
        public bool CanSave => State == TestState.GoodResult;
 

	
 
        public bool NoLab => State == TestState.LabNotFound;
 

	
 
        public bool CanPickBuffer => (State == TestState.ClippedResult) || IsAllCatalysts;
 

	
 
        public bool ShowFirstBuffer => Requires3Way && UseFirstBuffer;
 

	
 
        public bool ShowLastBuffer => Requires3Way && !UseFirstBuffer;
 

	
 

	
 
        private PaintColor? _hypotheticalColor;
 
        public PaintColor? HypotheticalColor { get => _hypotheticalColor; set { _hypotheticalColor = value; NotifyPropertyChanged(nameof(HypotheticalColor)); } }
 

	
 
        private PaintColor? _observedColor;
 
        public PaintColor? ObservedColor { get => _observedColor; set { _observedColor = value; NotifyPropertyChanged(nameof(ObservedColor)); } }
 

	
 
        private readonly PaintRecipe _recipe = new();
 

	
 
        public bool IsStub { get; }
 

	
 

	
 
        public ReactionTest(Reagent reagent1, Reagent reagent2, Reaction? reaction, ClipType clipType, bool isStub = false)
 
        {
 
            Reagent1 = reagent1;
 
            Reagent2 = reagent2;
 
            UseFirstBuffer = true;
 
            IsAllCatalysts = reagent1.IsCatalyst && reagent2.IsCatalyst;
 
            Clipped = clipType;
 
            Reaction = reaction;
 
            State = (reaction != null) ? TestState.Saved :
 
                (clipType == ClipType.None) ? TestState.Untested : TestState.ClippedResult;
 
            _recipe.AddReagent(reagent1.Name);
 
            _recipe.AddReagent(reagent2.Name);
 
            IsStub = isStub;
...
 
@@ -149,16 +178,17 @@ namespace DesertPaintCodex.Models
 
            BadReaction = null;
 
            State = TestState.Scanning;
 
            bool foundLab = await ReactionScannerService.Instance.CaptureReactionAsync(this);
 
            if (foundLab)
 
            {
 
                ObservedColor = ReactionScannerService.Instance.RecordedColor;
 
                if (_observedColor != null)
 
                {
 
                    // Handle the normal case.
 
                    Clipped = _observedColor.Red switch
 
                        {
 
                            0   => ClipType.RedLow,
 
                            255 => ClipType.RedHigh,
 
                            _   => ClipType.None
 
                        }
 
                        | _observedColor.Green switch
 
                        {
...
 
@@ -238,29 +268,79 @@ namespace DesertPaintCodex.Models
 
        #region Internals
 

	
 
        private Reaction? CalculateReaction()
 
        {
 
            if (ProfileManager.CurrentProfile == null) return null;
 
            if (HypotheticalColor == null) return null;
 
            if (ObservedColor == null) return null;
 

	
 
            if (BufferReagent != null)
 
            if (_useFirstBuffer)
 
            {
 
                if (BufferReagentFirst != null)
 
            {
 
                return ReactionScannerService.Calculate3WayReaction(ProfileManager.CurrentProfile, HypotheticalColor,
 
                    ObservedColor, BufferReagent, Reagent1, Reagent2);
 
                        ObservedColor, BufferReagentFirst, Reagent1, Reagent2, true);
 
                }
 
            }
 
            else
 
            {
 
                if (BufferReagentLast != null)
 
                {
 
                    return ReactionScannerService.Calculate3WayReaction(ProfileManager.CurrentProfile, HypotheticalColor,
 
                        ObservedColor, Reagent1, Reagent2, BufferReagentLast, false);
 
                }
 
            }
 
            
 
            return ReactionScannerService.CalculateReaction(HypotheticalColor, ObservedColor);
 
        }
 

	
 

	
 
        private void UpdateHypotheticalColor()
 
        {
 
            HypotheticalColor = null;
 
            HypotheticalColor = (IsAllCatalysts && (BufferReagent == null)) ? null : _recipe.BaseColor;
 
            HypotheticalColor = (IsAllCatalysts && !BufferIsSelected) ? null : _recipe.BaseColor;
 
        }
 

	
 
        private bool BufferIsSelected => UseFirstBuffer ? (BufferReagentFirst != null) : (BufferReagentLast != null);
 

	
 

	
 
        private void UpdateRecipe()
 
        {
 
            _recipe.Clear();
 
            if (_useFirstBuffer)
 
            {
 
                if (_bufferReagentFirst == null)
 
                {
 
                    _recipe.AddReagent(Reagent1.Name);
 
                    _recipe.AddReagent(Reagent2.Name);
 
                }
 
                else
 
                {
 
                    _recipe.AddReagent(_bufferReagentFirst.Name);
 
                    _recipe.AddReagent(Reagent1.Name);
 
                    _recipe.AddReagent(Reagent2.Name);
 
                } 
 
            }
 
            else
 
            {
 
                if (_bufferReagentLast == null)
 
                {
 
                    _recipe.AddReagent(Reagent1.Name);
 
                    _recipe.AddReagent(Reagent2.Name);
 
                }
 
                else
 
                {
 
                    _recipe.AddReagent(Reagent1.Name);
 
                    _recipe.AddReagent(Reagent2.Name);
 
                    _recipe.AddReagent(_bufferReagentLast.Name);
 
                }                
 
            }
 
            
 
            UpdateHypotheticalColor();
 
        }
 
        
 
        #endregion
 
        
 
        
 

	
 
        #region Interface Implementations
 
        
Services/ReactionScannerService.cs
Show inline comments
...
 
@@ -468,21 +468,32 @@ namespace DesertPaintCodex.Services
 
                    }
 
                    WriteLog(LogVerbosity.Excessive, "False-positive patch of color {0},{1},{2} at {3},{4}", patchColor.R, patchColor.G, patchColor.B, roughX, roughY);
 
                }
 
            }
 
            return false;
 
        }
 

	
 

	
 
        public static Reaction Calculate3WayReaction(PlayerProfile profile, PaintColor expectedColor, PaintColor reactedColor, Reagent reagent0, Reagent reagent1, Reagent reagent2)
 
        public static Reaction Calculate3WayReaction(PlayerProfile profile, PaintColor expectedColor, PaintColor reactedColor, Reagent reagent0, Reagent reagent1, Reagent reagent2, bool firstBuffer)
 
        {
 
            // A 3-reagent reaction.
 
            Reaction? reaction1 = profile.FindReaction(reagent0, reagent1);
 
            Reaction? reaction2 = profile.FindReaction(reagent0, reagent2);
 
            Reaction? reaction1;
 
            Reaction? reaction2;
 

	
 
            if (firstBuffer)
 
            {
 
                reaction1 = profile.FindReaction(reagent0, reagent1);
 
                reaction2 = profile.FindReaction(reagent0, reagent2);                
 
            }
 
            else
 
            {
 
                 reaction1 = profile.FindReaction(reagent0, reagent2);
 
                 reaction2 = profile.FindReaction(reagent1, reagent2);               
 
            }
 

	
 
            Debug.Assert(reaction1 != null);
 
            Debug.Assert(reaction2 != null);
 

	
 
            int r = reactedColor.Red   - expectedColor.Red   - reaction1.Red   - reaction2.Red;
 
            int g = reactedColor.Green - expectedColor.Green - reaction1.Green - reaction2.Green;
 
            int b = reactedColor.Blue  - expectedColor.Blue  - reaction1.Blue  - reaction2.Blue;
 
            
ViewModels/ReactionTestViewModel.cs
Show inline comments
...
 
@@ -19,18 +19,18 @@ namespace DesertPaintCodex.ViewModels
 
        public ReactionTest ReactionTest
 
        {
 
            get => _reactionTest;
 
            set => this.RaiseAndSetIfChanged(ref _reactionTest, value);
 
        }
 

	
 
        private readonly List<Reagent> _allPigmentList = new();
 
        private readonly List<Reagent> _allReagentList = new();
 
        public ObservableCollection<Reagent> BufferList { get; } = new();
 

	
 
        public ObservableCollection<Reagent> FirstBufferList { get; } = new();
 
        public ObservableCollection<Reagent> LastBufferList { get; } = new();
 

	
 
        public ReactionTestViewModel()
 
        {
 
            List<string> reagentNames = ReagentService.Names;
 
            
 
            foreach (var reagent in reagentNames.Select(ReagentService.GetReagent))
 
            {
 
                if (!reagent.IsCatalyst)
...
 
@@ -66,26 +66,34 @@ namespace DesertPaintCodex.ViewModels
 
        }
 

	
 
        private void FilterBufferPigments()
 
        {
 
            // Avalonia doesn't really have proper filtering for listy controls yet.
 
            PlayerProfile? profile = ProfileManager.CurrentProfile;
 
            if (profile == null) return;
 
            ReactionSet reactions = profile.Reactions;
 
            BufferList.Clear();
 
            List<Reagent> bufferList = ReactionTest.IsAllCatalysts ? _allPigmentList : _allReagentList;
 
            foreach (Reagent pigment in bufferList)
 
            foreach (Reagent buffer in bufferList)
 
            {
 
                if (pigment == ReactionTest.Reagent1) continue;
 
                if (pigment == ReactionTest.Reagent2) continue;
 
                if (reactions.Find(pigment, ReactionTest.Reagent1) == null) continue;
 
                if (reactions.Find(pigment, ReactionTest.Reagent2) == null) continue;
 
                if (buffer == ReactionTest.Reagent1) continue;
 
                if (buffer == ReactionTest.Reagent2) continue;
 

	
 
                
 
                BufferList.Add(pigment);
 
                if ((reactions.Find(buffer, ReactionTest.Reagent1) != null)
 
                    && (reactions.Find(buffer, ReactionTest.Reagent2) != null))
 
                {
 
                    FirstBufferList.Add(buffer);
 
                }
 

	
 
                if ((reactions.Find(ReactionTest.Reagent1, buffer) != null)
 
                    && (reactions.Find(ReactionTest.Reagent2, buffer) != null))
 
                {
 
                    LastBufferList.Add(buffer);
 
                }
 
            }
 

	
 
            // BufferPigmentList.AddRange(_allPigmentList.Where(pigment =>
 
            //         pigment != ReactionTest.Reagent1 && pigment != ReactionTest.Reagent2));
 
        }
 

	
 
        public async void Analyze()
 
        {
...
 
@@ -116,16 +124,26 @@ namespace DesertPaintCodex.ViewModels
 
            await ShowScreenSettingsDialog.Handle(new ScreenSettingsViewModel());
 
        }
 

	
 
        public async Task ShowClipInfo()
 
        {
 
            await ShowInfoBox("Clipped Reactions", "The Pigment Lab is only capable of displaying color channel values in the 0-255 range. However, sometimes, your reactions will push one or more channels outside of that range. When that happens, the value will be clamped either to 0 or 255. In this case, we say that the reaction was \"Clipped.\"\n\nThis is nothing to panic about, though. We solve this issue by using a third (buffer) reagent to offset the extreme value, so that it falls within measurable range, similar to how we test Catalyst+Catalyst reactions. Desert Paint Codex will automatically do the math for this, but it does move clipped reactions towards the end of your test list, because you'll want any reactions between the buffer reagent and your two test reagents already known, prior to running your buffered test.");
 
        }
 

	
 
        public void UseFirstBuffer()
 
        {
 
            ReactionTest.UseFirstBuffer = true;
 
        }
 

	
 
        public void UseLastBuffer()
 
        {
 
            ReactionTest.UseFirstBuffer = false;
 
        }
 

	
 
        private void Test()
 
        {
 
            Debug.WriteLine("Test complete");
 
        }
 
        
 
        public Interaction<ScreenSettingsViewModel, Unit> ShowScreenSettingsDialog { get; }
 

	
 
        public ReactiveCommand<Unit, Unit> ClearReaction { get; }
Views/ReactionTestView.axaml
Show inline comments
...
 
@@ -15,16 +15,20 @@
 

	
 
    <UserControl.Styles>
 
        <Style Selector="StackPanel.ReagentRow">
 
            <Setter Property="Orientation" Value="Horizontal"/>
 
            <Setter Property="Spacing" Value="10"/>
 
            <Setter Property="Height" Value="30"/>
 
        </Style>
 
        
 
        <Style Selector="StackPanel.ReagentLabel">
 
            <Setter Property="Width" Value="80"/>
 
        </Style>
 
        
 
        <Style Selector="TextBlock.ReagentLabel">
 
            <Setter Property="VerticalAlignment" Value="Center"/>
 
            <Setter Property="TextAlignment" Value="Right"/>
 
            <Setter Property="Width" Value="80"/>
 
        </Style>
 
        
 
        <Style Selector="TextBlock.ReagentName">
 
            <Setter Property="VerticalAlignment" Value="Center"/>
...
 
@@ -32,44 +36,70 @@
 
        </Style>
 
    </UserControl.Styles>
 

	
 
    <StackPanel Spacing="20" Margin="20 0 0 0">
 
        <StackPanel DockPanel.Dock="Top" Orientation="Vertical" Spacing="5">
 
            <TextBlock Classes="BlockHeader">REAGENTS</TextBlock>
 
            <Border Classes="ThinFrame">
 
                <StackPanel Orientation="Vertical" Spacing="10">
 
                    <StackPanel Classes="ReagentRow" IsVisible="{Binding ReactionTest.Requires3Way}">
 
                        <TextBlock Classes="ReagentLabel">Buffer:</TextBlock>
 
                        <TextBlock Classes="ReagentName" Text="{Binding ReactionTest.BufferReagent.Name, FallbackValue=[Unknown]}" IsVisible="{Binding !ReactionTest.CanPickBuffer}"/>
 
                        <ComboBox Items="{Binding BufferList}"
 
                    <StackPanel Classes="ReagentRow" IsVisible="{Binding ReactionTest.ShowFirstBuffer}">
 
                        <StackPanel Orientation="Horizontal" Classes="ReagentLabel" Spacing="10">
 
                            <Button Height="24" Width="24" Margin="8 0 0 0" Command="{Binding UseLastBuffer}">
 
                                <TextBlock VerticalAlignment="Center">▼</TextBlock>
 
                            </Button>
 
                            <TextBlock Classes="ReagentName">Buffer:</TextBlock>
 
                        </StackPanel>
 
                        <TextBlock Classes="ReagentName" Text="{Binding ReactionTest.BufferReagentFirst.Name, FallbackValue=[Unknown]}" IsVisible="{Binding !ReactionTest.CanPickBuffer}"/>
 
                        <ComboBox Items="{Binding FirstBufferList}"
 
                                  IsVisible="{Binding ReactionTest.CanPickBuffer}"
 
                                  SelectedItem="{Binding ReactionTest.BufferReagent}"
 
                                  SelectedItem="{Binding ReactionTest.BufferReagentFirst}"
 
                                  PlaceholderText="Choose" Width="120" Height="30">
 
                            <ComboBox.ItemTemplate>
 
                                <DataTemplate>
 
                                    <TextBlock Text="{Binding Name}" />
 
                                </DataTemplate>
 
                            </ComboBox.ItemTemplate>
 
                        </ComboBox>
 
                        <Border Classes="ReagentSwatch"
 
                            Background="{Binding ReactionTest.BufferReagent.Color, Converter={StaticResource paintToBrush}, FallbackValue=#00000000}" />
 
                            Background="{Binding ReactionTest.BufferReagentFirst.Color, Converter={StaticResource paintToBrush}, FallbackValue=#00000000}" />
 
                    </StackPanel>
 
                    <StackPanel Classes="ReagentRow">
 
                        <TextBlock Classes="ReagentLabel">Reagent #1:</TextBlock>
 
                        <TextBlock Classes="ReagentName" Text="{Binding ReactionTest.Reagent1.Name}" />
 
                        <Border Classes="ReagentSwatch"
 
                            Background="{Binding ReactionTest.Reagent1.Color, Converter={StaticResource paintToBrush}, FallbackValue=#00000000}" />
 
                    </StackPanel>
 
                    <StackPanel Classes="ReagentRow">
 
                        <TextBlock Classes="ReagentLabel">Reagent #2:</TextBlock>
 
                        <TextBlock Classes="ReagentName" Text="{Binding ReactionTest.Reagent2.Name}" />
 
                        <Border Classes="ReagentSwatch"
 
                            Background="{Binding ReactionTest.Reagent2.Color, Converter={StaticResource paintToBrush}, FallbackValue=#00000000}" />
 
                    </StackPanel>
 
                    <StackPanel Classes="ReagentRow" IsVisible="{Binding ReactionTest.ShowLastBuffer}">
 
                        <StackPanel Orientation="Horizontal" Classes="ReagentLabel" Spacing="10">
 
                            <Button Height="24" Width="24" Margin="8 0 0 0" Command="{Binding UseFirstBuffer}">
 
                                <TextBlock VerticalAlignment="Center">▲</TextBlock>
 
                            </Button>
 
                            <TextBlock Classes="ReagentName">Buffer:</TextBlock>
 
                        </StackPanel>
 
                        <TextBlock Classes="ReagentName" Text="{Binding ReactionTest.BufferReagentLast.Name, FallbackValue=[Unknown]}" IsVisible="{Binding !ReactionTest.CanPickBuffer}"/>
 
                        <ComboBox Items="{Binding LastBufferList}"
 
                                  IsVisible="{Binding ReactionTest.CanPickBuffer}"
 
                                  SelectedItem="{Binding ReactionTest.BufferReagentLast}"
 
                                  PlaceholderText="Choose" Width="120" Height="30">
 
                            <ComboBox.ItemTemplate>
 
                                <DataTemplate>
 
                                    <TextBlock Text="{Binding Name}" />
 
                                </DataTemplate>
 
                            </ComboBox.ItemTemplate>
 
                        </ComboBox>
 
                        <Border Classes="ReagentSwatch"
 
                                Background="{Binding ReactionTest.BufferReagentLast.Color, Converter={StaticResource paintToBrush}, FallbackValue=#00000000}" />
 
                    </StackPanel>                    
 
                </StackPanel>
 
            </Border>
 
        </StackPanel>
 

	
 
        <StackPanel DockPanel.Dock="Top" Orientation="Vertical" Spacing="5">
 
            <TextBlock Classes="BlockHeader">HYPOTHETICAL COLOR</TextBlock>
 
            <views:PaintSwatchView ShowName="False" Color="{Binding ReactionTest.HypotheticalColor}"/>
 
        </StackPanel>
0 comments (0 inline, 0 general)