static void STEP_CORRUPT(bool _isRewinding, bool _isFastForwarding, bool _isPaused) { if (DisableRTC) { return; } if (!_isRewinding && !_isPaused) { if (RTC_PipeEngine.ProcessOnStep) { RTC_PipeEngine.ExecutePipes(); } } if (_isRewinding || _isFastForwarding || _isPaused) { return; } CPU_STEP_Count++; if (RTC_Core.AutoCorrupt && CPU_STEP_Count >= RTC_Core.ErrorDelay) { CPU_STEP_Count = 0; BlastLayer bl = RTC_Core.Blast(null, RTC_MemoryDomains.SelectedDomains); if (bl != null) { bl.Apply(); } } }
//Generates or applies a blast layer using one of the multiple BlastRadius algorithms public static BlastLayer Blast(BlastLayer _layer, string[] _selectedDomains) { string Domain = null; long MaxAddress = -1; long RandomAddress = -1; BlastUnit bu; BlastLayer bl; try { if (_layer != null) { _layer.Apply(); //If the BlastLayer was provided, there's no need to generate a new one. return(_layer); } else if (RTC_Core.SelectedEngine == CorruptionEngine.EXTERNALROM) { //External ROM Plugin: Bypasses domains and uses an alternative algorithm to fetch corruption. //It will query a BlastLayer generated from a differential between an original and corrupted rom. bl = RTC_ExternalRomPlugin.GetBlastLayer(); if (bl == null) { return(null); } else { return(bl); } } else { bl = new BlastLayer(); if (_selectedDomains == null || _selectedDomains.Count() == 0) { return(null); } // Age distortion BlastBytes if (RTC_Core.SelectedEngine == CorruptionEngine.DISTORTION && RTC_DistortionEngine.CurrentAge < RTC_DistortionEngine.MaxAge) { RTC_DistortionEngine.CurrentAge++; } //Run Pipes on Corrupt Step if required if (RTC_Core.SelectedEngine == CorruptionEngine.PIPE && !RTC_PipeEngine.ProcessOnStep) { RTC_PipeEngine.ExecutePipes(); } // Capping intensity at engine-specific maximums int _Intensity = Intensity; //general RTC intensity if ((RTC_Core.SelectedEngine == CorruptionEngine.HELLGENIE || RTC_Core.SelectedEngine == CorruptionEngine.FREEZE) && _Intensity > RTC_HellgenieEngine.MaxCheats) { _Intensity = RTC_HellgenieEngine.MaxCheats; //Capping for cheat max } if (RTC_Core.SelectedEngine == CorruptionEngine.PIPE && _Intensity > RTC_PipeEngine.MaxPipes) { _Intensity = RTC_PipeEngine.MaxPipes; //Capping for pipe max } switch (Radius) //Algorithm branching { case BlastRadius.SPREAD: //Randomly spreads all corruption bytes to all selected domains for (int i = 0; i < _Intensity; i++) { Domain = _selectedDomains[RND.Next(_selectedDomains.Length)]; MaxAddress = RTC_MemoryDomains.getInterface(Domain).Size; RandomAddress = RTC_Core.RND.RandomLong(MaxAddress - 1); bu = getBlastUnit(Domain, RandomAddress); if (bu != null) { bl.Layer.Add(bu); } } break; case BlastRadius.CHUNK: //Randomly spreads the corruption bytes in one randomly selected domain Domain = _selectedDomains[RND.Next(_selectedDomains.Length)]; MaxAddress = RTC_MemoryDomains.getInterface(Domain).Size; for (int i = 0; i < _Intensity; i++) { RandomAddress = RTC_Core.RND.RandomLong(MaxAddress - 1); bu = getBlastUnit(Domain, RandomAddress); if (bu != null) { bl.Layer.Add(bu); } } break; case BlastRadius.BURST: // 10 shots of 10% chunk for (int j = 0; j < 10; j++) { Domain = _selectedDomains[RND.Next(_selectedDomains.Length)]; MaxAddress = RTC_MemoryDomains.getInterface(Domain).Size; for (int i = 0; i < (int)((double)_Intensity / 10); i++) { RandomAddress = RTC_Core.RND.RandomLong(MaxAddress - 1); bu = getBlastUnit(Domain, RandomAddress); if (bu != null) { bl.Layer.Add(bu); } } } break; case BlastRadius.NORMALIZED: // Blasts based on the size of the largest selected domain. Intensity = Intensity / (domainSize[largestdomain]/domainSize[currentdomain]) //Find the smallest domain and base our normalization around it //Domains aren't IComparable so I used keys long[] domainSize = new long [_selectedDomains.Length]; for (int i = 0; i < _selectedDomains.Length; i++) { Domain = _selectedDomains[i]; domainSize[i] = RTC_MemoryDomains.getInterface(Domain).Size; } //Sort the arrays Array.Sort(domainSize, _selectedDomains); for (int i = 0; i < _selectedDomains.Length; i++) { Domain = _selectedDomains[i]; //Get the intensity divider. The size of the largest domain divided by the size of the current domain long normalized = ((domainSize[_selectedDomains.Length - 1] / (domainSize[i]))); for (int j = 0; j < (_Intensity / normalized); j++) { MaxAddress = RTC_MemoryDomains.getInterface(Domain).Size; RandomAddress = RTC_Core.RND.RandomLong(MaxAddress - 1); bu = getBlastUnit(Domain, RandomAddress); if (bu != null) { bl.Layer.Add(bu); } } } break; case BlastRadius.PROPORTIONAL: //Blasts proportionally based on the total size of all selected domains long totalSize = _selectedDomains.Select(it => RTC_MemoryDomains.getInterface(it).Size).Sum(); //Gets the total size of all selected domains long[] normalizedIntensity = new long[_selectedDomains.Length]; //matches the index of selectedDomains for (int i = 0; i < _selectedDomains.Length; i++) { //calculates the proportionnal normalized Intensity based on total selected domains size double proportion = (double)RTC_MemoryDomains.getInterface(_selectedDomains[i]).Size / (double)totalSize; normalizedIntensity[i] = Convert.ToInt64((double)_Intensity * proportion); } for (int i = 0; i < _selectedDomains.Length; i++) { Domain = _selectedDomains[i]; for (int j = 0; j < normalizedIntensity[i]; j++) { MaxAddress = RTC_MemoryDomains.getInterface(Domain).Size; RandomAddress = RTC_Core.RND.RandomLong(MaxAddress - 1); bu = getBlastUnit(Domain, RandomAddress); if (bu != null) { bl.Layer.Add(bu); } } } break; case BlastRadius.EVEN: //Evenly distributes the blasts through all selected domains for (int i = 0; i < _selectedDomains.Length; i++) { Domain = _selectedDomains[i]; for (int j = 0; j < (_Intensity / _selectedDomains.Length); j++) { MaxAddress = RTC_MemoryDomains.getInterface(Domain).Size; RandomAddress = RTC_Core.RND.RandomLong(MaxAddress - 1); bu = getBlastUnit(Domain, RandomAddress); if (bu != null) { bl.Layer.Add(bu); } } } break; case BlastRadius.NONE: //Shouldn't ever happen but handled anyway return(null); } if (bl.Layer.Count == 0) { return(null); } else { return(bl); } } } catch (Exception ex) { DialogResult dr = MessageBox.Show("Something went wrong in the RTC Core. \n" + "This is not a BizHawk error so you should probably send a screenshot of this to the devs\n\n" + "If you know the steps to reproduce this error it would be greatly appreaciated.\n\n" + (RTC_Core.coreForm.AutoCorrupt ? ">> STOP AUTOCORRUPT ?.\n\n" : "") + $"domain:{Domain.ToString()} maxaddress:{MaxAddress.ToString()} randomaddress:{RandomAddress.ToString()} \n\n" + ex.ToString(), "Error", (RTC_Core.coreForm.AutoCorrupt ? MessageBoxButtons.YesNo : MessageBoxButtons.OK)); if (dr == DialogResult.Yes || dr == DialogResult.OK) { RTC_Core.coreForm.AutoCorrupt = false; } return(null); } }