├── .gitattributes
├── .gitignore
├── MM2RandoHost
├── App.config
├── App.xaml
├── App.xaml.cs
├── Converters
│ ├── BoolToRedGreenBrushConverter.cs
│ ├── BoolToVisibilityConverter.cs
│ └── InverseBooleanConverter.cs
├── MM2RandoHost.csproj
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Resources
│ ├── Brushes
│ │ └── BrushesDark.xaml
│ ├── SpriteImages
│ │ ├── sprite_bass.png
│ │ ├── sprite_proto.png
│ │ ├── sprite_rock.png
│ │ └── sprite_roll.png
│ ├── Styles
│ │ └── MainStyles.xaml
│ └── header.png
├── ViewModels
│ └── MainWindowViewModel.cs
└── Views
│ └── Primitives
│ └── CustomWindow.cs
├── MM2RandoLib
├── Enums
│ ├── EColorsHex.cs
│ ├── EDmgVsBoss.cs
│ ├── EDmgVsEnemy.cs
│ ├── EEnemyID.cs
│ ├── EItemNumber.cs
│ ├── EItemStageAddress.cs
│ ├── EMiscAddresses.cs
│ ├── EMusicID.cs
│ ├── ERMPortraitAddress.cs
│ ├── ERMPortraitText.cs
│ ├── ERMStageClearAddress.cs
│ ├── ERMStageSelect.cs
│ ├── ERMStageWeaponAddress.cs
│ ├── ERMWeaponValue.cs
│ ├── ESoundID.cs
│ └── EStageID.cs
├── MM2RandoLib.csproj
├── ObservableBase.cs
├── Patcher
│ ├── ByteChangeRecord.cs
│ └── Patch.cs
├── Properties
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── RandoSettings.cs
├── RandomMM2.cs
├── Randomizers
│ ├── Colors
│ │ ├── ColorSet.cs
│ │ └── RColors.cs
│ ├── Enemies
│ │ ├── EnemyInstance.cs
│ │ ├── EnemyType.cs
│ │ ├── REnemies.cs
│ │ ├── REnemyWeaknesses.cs
│ │ ├── Room.cs
│ │ └── SpriteBankRoomGroup.cs
│ ├── IRandomizer.cs
│ ├── RBossAI.cs
│ ├── RBossRoom.cs
│ ├── RItemGet.cs
│ ├── RMusic.cs
│ ├── RTeleporters.cs
│ ├── RText.cs
│ ├── RTilemap.cs
│ ├── RWeaknesses.cs
│ ├── RWeaponBehavior.cs
│ ├── RWeaponGet.cs
│ └── Stages
│ │ ├── Components
│ │ ├── EnemyComponent.cs
│ │ └── LevelComponent.cs
│ │ ├── RStages.cs
│ │ └── StageFromSelect.cs
├── Resources
│ ├── SpritePatches
│ │ ├── SpriteSwap_Bass.ips
│ │ ├── SpriteSwap_Proto.ips
│ │ └── SpriteSwap_Roll.ips
│ ├── bossnames.csv
│ ├── companynames.csv
│ ├── countrylist.csv
│ ├── creditstext.csv
│ ├── enemylist.csv
│ ├── enemyweakness.csv
│ ├── level_components.json
│ ├── mm2rng_musicpatch.ips
│ ├── mm2rng_prepatch.ips
│ └── music.txt
├── Utilities
│ ├── MiscHacks.cs
│ └── SeedConvert.cs
├── WeaponTable.cs
└── packages.config
├── MM2Randomizer.sln
└── readme.txt
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | # NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | # DNX
42 | project.lock.json
43 | artifacts/
44 |
45 | *_i.c
46 | *_p.c
47 | *_i.h
48 | *.ilk
49 | *.meta
50 | *.obj
51 | *.pch
52 | *.pdb
53 | *.pgc
54 | *.pgd
55 | *.rsp
56 | *.sbr
57 | *.tlb
58 | *.tli
59 | *.tlh
60 | *.tmp
61 | *.tmp_proj
62 | *.log
63 | *.vspscc
64 | *.vssscc
65 | .builds
66 | *.pidb
67 | *.svclog
68 | *.scc
69 |
70 | # Chutzpah Test files
71 | _Chutzpah*
72 |
73 | # Visual C++ cache files
74 | ipch/
75 | *.aps
76 | *.ncb
77 | *.opensdf
78 | *.sdf
79 | *.cachefile
80 |
81 | # Visual Studio profiler
82 | *.psess
83 | *.vsp
84 | *.vspx
85 |
86 | # TFS 2012 Local Workspace
87 | $tf/
88 |
89 | # Guidance Automation Toolkit
90 | *.gpState
91 |
92 | # ReSharper is a .NET coding add-in
93 | _ReSharper*/
94 | *.[Rr]e[Ss]harper
95 | *.DotSettings.user
96 |
97 | # JustCode is a .NET coding add-in
98 | .JustCode
99 |
100 | # TeamCity is a build add-in
101 | _TeamCity*
102 |
103 | # DotCover is a Code Coverage Tool
104 | *.dotCover
105 |
106 | # NCrunch
107 | _NCrunch_*
108 | .*crunch*.local.xml
109 |
110 | # MightyMoose
111 | *.mm.*
112 | AutoTest.Net/
113 |
114 | # Web workbench (sass)
115 | .sass-cache/
116 |
117 | # Installshield output folder
118 | [Ee]xpress/
119 |
120 | # DocProject is a documentation generator add-in
121 | DocProject/buildhelp/
122 | DocProject/Help/*.HxT
123 | DocProject/Help/*.HxC
124 | DocProject/Help/*.hhc
125 | DocProject/Help/*.hhk
126 | DocProject/Help/*.hhp
127 | DocProject/Help/Html2
128 | DocProject/Help/html
129 |
130 | # Click-Once directory
131 | publish/
132 |
133 | # Publish Web Output
134 | *.[Pp]ublish.xml
135 | *.azurePubxml
136 | ## TODO: Comment the next line if you want to checkin your
137 | ## web deploy settings but do note that will include unencrypted
138 | ## passwords
139 | #*.pubxml
140 |
141 | *.publishproj
142 |
143 | # NuGet Packages
144 | *.nupkg
145 | # The packages folder can be ignored because of Package Restore
146 | **/packages/*
147 | # except build/, which is used as an MSBuild target.
148 | !**/packages/build/
149 | # Uncomment if necessary however generally it will be regenerated when needed
150 | #!**/packages/repositories.config
151 |
152 | # Windows Azure Build Output
153 | csx/
154 | *.build.csdef
155 |
156 | # Windows Store app package directory
157 | AppPackages/
158 |
159 | # Visual Studio cache files
160 | # files ending in .cache can be ignored
161 | *.[Cc]ache
162 | # but keep track of directories ending in .cache
163 | !*.[Cc]ache/
164 |
165 | # Others
166 | ClientBin/
167 | [Ss]tyle[Cc]op.*
168 | ~$*
169 | *~
170 | *.dbmdl
171 | *.dbproj.schemaview
172 | *.pfx
173 | *.publishsettings
174 | node_modules/
175 | orleans.codegen.cs
176 |
177 | # RIA/Silverlight projects
178 | Generated_Code/
179 |
180 | # Backup & report files from converting an old project file
181 | # to a newer Visual Studio version. Backup files are not needed,
182 | # because we have git ;-)
183 | _UpgradeReport_Files/
184 | Backup*/
185 | UpgradeLog*.XML
186 | UpgradeLog*.htm
187 |
188 | # SQL Server files
189 | *.mdf
190 | *.ldf
191 |
192 | # Business Intelligence projects
193 | *.rdl.data
194 | *.bim.layout
195 | *.bim_*.settings
196 |
197 | # Microsoft Fakes
198 | FakesAssemblies/
199 |
200 | # Node.js Tools for Visual Studio
201 | .ntvs_analysis.dat
202 |
203 | # Visual Studio 6 build log
204 | *.plg
205 |
206 | # Visual Studio 6 workspace options file
207 | *.opt
208 |
209 | # LightSwitch generated files
210 | GeneratedArtifacts/
211 | _Pvt_Extensions/
212 | ModelManifest.xml
213 | /MM2Randomizer/u_backup.dat
214 |
--------------------------------------------------------------------------------
/MM2RandoHost/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/MM2RandoHost/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/MM2RandoHost/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace MM2RandoHost
4 | {
5 | ///
6 | /// Interaction logic for App.xaml
7 | ///
8 | public partial class App : Application
9 | {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/MM2RandoHost/Converters/BoolToRedGreenBrushConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 | using System.Windows.Data;
9 | using System.Windows.Media;
10 |
11 | namespace MM2RandoHost.Converters
12 | {
13 | public class BoolToRedGreenBrushConverter : IValueConverter
14 | {
15 | private static readonly Brush red = new SolidColorBrush(Colors.Red);
16 | private static readonly Brush green = new SolidColorBrush(Color.FromArgb(255, 125, 255, 128));
17 |
18 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
19 | {
20 | if (!(value is bool myBool))
21 | {
22 | return red;
23 | }
24 |
25 | return myBool ? green : red;
26 | }
27 |
28 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
29 | {
30 | return false;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/MM2RandoHost/Converters/BoolToVisibilityConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 | using System.Windows.Data;
9 |
10 | namespace MM2RandoHost.Converters
11 | {
12 | public class BoolToVisibilityConverter : IValueConverter
13 | {
14 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
15 | {
16 | return (bool)value ? Visibility.Visible : Visibility.Hidden;
17 | }
18 |
19 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
20 | {
21 | throw new NotImplementedException();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/MM2RandoHost/Converters/InverseBooleanConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Data;
3 |
4 | namespace MM2RandoHost.Converters
5 | {
6 | [ValueConversion(typeof(bool), typeof(bool))]
7 | public class InverseBooleanConverter : IValueConverter
8 | {
9 | #region IValueConverter Members
10 |
11 | public object Convert(object value, Type targetType, object parameter,
12 | System.Globalization.CultureInfo culture)
13 | {
14 | if (targetType != typeof(bool))
15 | throw new InvalidOperationException("The target must be a boolean");
16 |
17 | return !(bool)value;
18 | }
19 |
20 | public object ConvertBack(object value, Type targetType, object parameter,
21 | System.Globalization.CultureInfo culture)
22 | {
23 | throw new NotSupportedException();
24 | }
25 |
26 | #endregion
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/MM2RandoHost/MM2RandoHost.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {F12A49E8-C7A7-4FDE-BB7C-EA80451D5B96}
8 | WinExe
9 | Properties
10 | MM2RandoHost
11 | MM2RandoHost
12 | v4.7.2
13 | 512
14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 | 4
16 | true
17 |
18 | false
19 | publish\
20 | true
21 | Disk
22 | false
23 | Foreground
24 | 7
25 | Days
26 | false
27 | false
28 | true
29 | 0
30 | 0.1.2.%2a
31 | false
32 | true
33 |
34 |
35 | AnyCPU
36 | true
37 | full
38 | false
39 | bin\
40 | TRACE;DEBUG
41 | prompt
42 | 4
43 | false
44 |
45 |
46 | AnyCPU
47 | pdbonly
48 | true
49 | bin\
50 | TRACE
51 | prompt
52 | 4
53 | false
54 |
55 |
56 | true
57 | bin\x64\Debug\
58 | DEBUG;TRACE
59 | full
60 | x64
61 | prompt
62 | MinimumRecommendedRules.ruleset
63 | false
64 |
65 |
66 | bin\x64\Release\
67 | TRACE
68 | true
69 | pdbonly
70 | x64
71 | prompt
72 | MinimumRecommendedRules.ruleset
73 | false
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | 4.0
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | MSBuild:Compile
91 | Designer
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | MSBuild:Compile
100 | Designer
101 |
102 |
103 | App.xaml
104 | Code
105 |
106 |
107 | MainWindow.xaml
108 | Code
109 |
110 |
111 | Designer
112 | MSBuild:Compile
113 |
114 |
115 | Designer
116 | MSBuild:Compile
117 |
118 |
119 |
120 |
121 | Code
122 |
123 |
124 | True
125 | True
126 | Resources.resx
127 |
128 |
129 | True
130 | Settings.settings
131 | True
132 |
133 |
134 | ResXFileCodeGenerator
135 | Resources.Designer.cs
136 |
137 |
138 | SettingsSingleFileGenerator
139 | Settings.Designer.cs
140 |
141 |
142 |
143 |
144 |
145 | Designer
146 |
147 |
148 |
149 |
150 | False
151 | Microsoft .NET Framework 4 %28x86 and x64%29
152 | true
153 |
154 |
155 | False
156 | .NET Framework 3.5 SP1
157 | false
158 |
159 |
160 | False
161 | Windows Installer 4.5
162 | true
163 |
164 |
165 |
166 |
167 | {2f96fe8d-29dc-46f3-9d26-fc85dc2225c8}
168 | MM2RandoLib
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
194 |
--------------------------------------------------------------------------------
/MM2RandoHost/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Windows.Media;
6 | using System.Windows.Input;
7 | using Microsoft.Win32;
8 |
9 | using MM2Randomizer;
10 | using MM2Randomizer.Utilities;
11 |
12 | using MM2RandoHost.ViewModels;
13 | using MM2RandoHost.Views.Primitives;
14 |
15 | namespace MM2RandoHost
16 | {
17 | ///
18 | /// Interaction logic for MainWindow.xaml
19 | ///
20 | public partial class MainWindow : CustomWindow
21 | {
22 | // TODO Remove
23 | MainWindowViewModel ViewModel;
24 |
25 | public MainWindow()
26 | {
27 | InitializeComponent();
28 |
29 | // TODO Remove
30 | ViewModel = DataContext as MainWindowViewModel;
31 | }
32 |
33 | private void btnCreateROM_Click(object sender, RoutedEventArgs e)
34 | {
35 | int seed = -1;
36 |
37 | // Check if textbox contains a valid seed string
38 | if (!String.IsNullOrEmpty(tbxSeed.Text))
39 | {
40 | try
41 | {
42 | // Use the provided seed so that a specific ROM may be generated.
43 | seed = SeedConvert.ConvertBase26To10(tbxSeed.Text);
44 | }
45 | catch (Exception ex)
46 | {
47 | Debug.WriteLine("Exception in parsing Seed. Using random seed. Message:/n" + ex.ToString());
48 | seed = -1;
49 | }
50 | }
51 |
52 | // Perform randomization based on settings, then generate the ROM.
53 | ViewModel.PerformRandomization(seed, Keyboard.IsKeyDown(Key.LeftShift));
54 | }
55 |
56 | private void btnCreateRandom_Click(object sender, RoutedEventArgs e)
57 | {
58 | ViewModel.PerformRandomization(-1, Keyboard.IsKeyDown(Key.LeftShift));
59 | }
60 |
61 | private void btnOpenFolder_Click(object sender, RoutedEventArgs e)
62 | {
63 | if (RandomMM2.RecentlyCreatedFileName != "")
64 | {
65 | try
66 | {
67 | Process.Start("explorer.exe", string.Format("/select,\"{0}\"", RandomMM2.RecentlyCreatedFileName));
68 | }
69 | catch (Exception ex)
70 | {
71 | Debug.WriteLine(ex.ToString());
72 | Process.Start("explorer.exe", string.Format("/select,\"{0}\"", System.Reflection.Assembly.GetExecutingAssembly().Location));
73 | }
74 | }
75 | else
76 | {
77 | Process.Start("explorer.exe", string.Format("/select,\"{0}\"", System.Reflection.Assembly.GetExecutingAssembly().Location));
78 | }
79 | }
80 |
81 | private void btnBrowse_Click(object sender, RoutedEventArgs e)
82 | {
83 | OpenFileDialog dlg = new OpenFileDialog();
84 | dlg.Filter = "ROM image (.nes)|*.nes";
85 | dlg.Title = "Open Mega Man 2 (U) NES ROM File";
86 |
87 | // Call the ShowDialog method to show the dialog box.
88 | string exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
89 | string exeDir = Path.GetDirectoryName(exePath);
90 | dlg.InitialDirectory = exeDir;
91 |
92 | bool? userClickedOK = dlg.ShowDialog();
93 |
94 | // Process input if the user clicked OK.
95 | if (userClickedOK == true)
96 | {
97 | TryFile(dlg.FileName);
98 | SetTextBoxFocusToEnd();
99 | }
100 | }
101 |
102 | private void tbxSource_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
103 | {
104 | if (ViewModel != null)
105 | TryFile(ViewModel.RandoSettings.SourcePath);
106 | }
107 |
108 | private void Window_Drop(object sender, DragEventArgs e)
109 | {
110 | if (e.Data.GetDataPresent(DataFormats.FileDrop))
111 | {
112 | string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
113 | TryFile(files[0]);
114 | SetTextBoxFocusToEnd();
115 | }
116 | BorderShowHandler(false, e);
117 | }
118 |
119 | private void TextBox_Drop(object sender, DragEventArgs e)
120 | {
121 | if (e.Data.GetDataPresent(DataFormats.FileDrop))
122 | {
123 | string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
124 | TryFile(files[0]);
125 | SetTextBoxFocusToEnd();
126 | }
127 | BorderShowHandler(false, e);
128 | }
129 |
130 | private void Window_DragEnter(object sender, DragEventArgs e)
131 | {
132 | BorderShowHandler(true, e);
133 | }
134 |
135 | private void Window_DragLeave(object sender, DragEventArgs e)
136 | {
137 | BorderShowHandler(false, e);
138 | }
139 |
140 | private void TextBox_PreviewDragOver(object sender, DragEventArgs e)
141 | {
142 | e.Handled = true;
143 | BorderShowHandler(true, e);
144 | }
145 |
146 | private void BorderShowHandler(bool show, DragEventArgs e)
147 | {
148 | if (!show)
149 | {
150 | border.BorderBrush = new SolidColorBrush(Colors.Transparent);
151 | return;
152 | }
153 |
154 | if (e.Data.GetDataPresent(DataFormats.FileDrop))
155 | {
156 | border.BorderBrush = new SolidColorBrush(Colors.Red);
157 | }
158 | else
159 | {
160 | new SolidColorBrush(Colors.Transparent);
161 | }
162 | }
163 |
164 | private void SetTextBoxFocusToEnd()
165 | {
166 | tbxSource.Focus();
167 | tbxSource.SelectionStart = tbxSource.Text.Length;
168 | }
169 |
170 | private void TryFile(string filename)
171 | {
172 | ViewModel.IsShowingHint = false;
173 | ViewModel.RandoSettings.ValidateFile(filename);
174 | }
175 |
176 | private void chkBurstChaser_Checked(object sender, RoutedEventArgs e)
177 | {
178 | MessageBox.Show("Caution: The randomizer is not balanced for Burst Chaser mode.\nIf it is your first time playing, consider using the default settings.");
179 | }
180 |
181 | private void CustonWindow_MouseDown(object sender, MouseButtonEventArgs e)
182 | {
183 | if (e.ChangedButton == System.Windows.Input.MouseButton.Left)
184 | this.DragMove();
185 | }
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/MM2RandoHost/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("MM2RandoHost")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("duckfist")]
14 | [assembly: AssemblyProduct("MM2RandoHost")]
15 | [assembly: AssemblyCopyright("duckfist")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("0.5.0.*")]
55 | [assembly: AssemblyFileVersion("0.5.0.0")]
56 |
--------------------------------------------------------------------------------
/MM2RandoHost/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace MM2RandoHost.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MM2RandoHost.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized resource of type System.Drawing.Bitmap.
65 | ///
66 | internal static System.Drawing.Bitmap header {
67 | get {
68 | object obj = ResourceManager.GetObject("header", resourceCulture);
69 | return ((System.Drawing.Bitmap)(obj));
70 | }
71 | }
72 |
73 | ///
74 | /// Looks up a localized resource of type System.Drawing.Bitmap.
75 | ///
76 | internal static System.Drawing.Bitmap sprite_bass {
77 | get {
78 | object obj = ResourceManager.GetObject("sprite_bass", resourceCulture);
79 | return ((System.Drawing.Bitmap)(obj));
80 | }
81 | }
82 |
83 | ///
84 | /// Looks up a localized resource of type System.Drawing.Bitmap.
85 | ///
86 | internal static System.Drawing.Bitmap sprite_proto {
87 | get {
88 | object obj = ResourceManager.GetObject("sprite_proto", resourceCulture);
89 | return ((System.Drawing.Bitmap)(obj));
90 | }
91 | }
92 |
93 | ///
94 | /// Looks up a localized resource of type System.Drawing.Bitmap.
95 | ///
96 | internal static System.Drawing.Bitmap sprite_rock {
97 | get {
98 | object obj = ResourceManager.GetObject("sprite_rock", resourceCulture);
99 | return ((System.Drawing.Bitmap)(obj));
100 | }
101 | }
102 |
103 | ///
104 | /// Looks up a localized resource of type System.Drawing.Bitmap.
105 | ///
106 | internal static System.Drawing.Bitmap sprite_roll {
107 | get {
108 | object obj = ResourceManager.GetObject("sprite_roll", resourceCulture);
109 | return ((System.Drawing.Bitmap)(obj));
110 | }
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/MM2RandoHost/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | ..\Resources\header.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
123 |
124 |
125 | ..\Resources\SpriteImages\sprite_bass.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
126 |
127 |
128 | ..\Resources\SpriteImages\sprite_proto.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
129 |
130 |
131 | ..\Resources\SpriteImages\sprite_rock.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
132 |
133 |
134 | ..\Resources\SpriteImages\sprite_roll.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
135 |
136 |
--------------------------------------------------------------------------------
/MM2RandoHost/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace MM2RandoHost.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/MM2RandoHost/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/MM2RandoHost/Resources/Brushes/BrushesDark.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | #FFE8EDF9
36 | #FFC5CBF9
37 |
38 |
--------------------------------------------------------------------------------
/MM2RandoHost/Resources/SpriteImages/sprite_bass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckfist/MM2Random/178a4cb7649b194782b94caf9b54379e52914c0d/MM2RandoHost/Resources/SpriteImages/sprite_bass.png
--------------------------------------------------------------------------------
/MM2RandoHost/Resources/SpriteImages/sprite_proto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckfist/MM2Random/178a4cb7649b194782b94caf9b54379e52914c0d/MM2RandoHost/Resources/SpriteImages/sprite_proto.png
--------------------------------------------------------------------------------
/MM2RandoHost/Resources/SpriteImages/sprite_rock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckfist/MM2Random/178a4cb7649b194782b94caf9b54379e52914c0d/MM2RandoHost/Resources/SpriteImages/sprite_rock.png
--------------------------------------------------------------------------------
/MM2RandoHost/Resources/SpriteImages/sprite_roll.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckfist/MM2Random/178a4cb7649b194782b94caf9b54379e52914c0d/MM2RandoHost/Resources/SpriteImages/sprite_roll.png
--------------------------------------------------------------------------------
/MM2RandoHost/Resources/header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckfist/MM2Random/178a4cb7649b194782b94caf9b54379e52914c0d/MM2RandoHost/Resources/header.png
--------------------------------------------------------------------------------
/MM2RandoHost/ViewModels/MainWindowViewModel.cs:
--------------------------------------------------------------------------------
1 | using MM2Randomizer;
2 | using MM2Randomizer.Utilities;
3 |
4 | using System.IO;
5 | using System.Reflection;
6 | using System.Diagnostics;
7 |
8 | namespace MM2RandoHost.ViewModels
9 | {
10 | public class MainWindowViewModel : ObservableBase
11 | {
12 | private RandoSettings _randoSettings;
13 | private bool _isShowingHint = true;
14 | private bool _hasGeneratedAROM = false;
15 |
16 | public MainWindowViewModel()
17 | {
18 | RandoSettings = new RandoSettings();
19 | RandomMM2.Settings = RandoSettings;
20 |
21 | // Try to load "MM2.nes" if one is in the local directory already to save time
22 | string tryLocalpath = Path.Combine(
23 | Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
24 | "MM2.nes");
25 |
26 | if (File.Exists(tryLocalpath))
27 | {
28 | RandoSettings.ValidateFile(tryLocalpath);
29 | IsShowingHint = false;
30 | }
31 | }
32 |
33 | public RandoSettings RandoSettings
34 | {
35 | get => _randoSettings;
36 | set => SetProperty(ref _randoSettings, value);
37 | }
38 |
39 | public bool IsShowingHint
40 | {
41 | get => _isShowingHint;
42 | set => SetProperty(ref _isShowingHint, value);
43 | }
44 |
45 | public bool HasGeneratedAROM
46 | {
47 | get => _hasGeneratedAROM;
48 | set => SetProperty(ref _hasGeneratedAROM, value);
49 | }
50 |
51 | public bool IsCoreModulesChecked
52 | {
53 | get => RandoSettings.Is8StagesRandom &&
54 | RandoSettings.IsWeaponsRandom &&
55 | RandoSettings.IsTeleportersRandom;
56 | }
57 |
58 | public void PerformRandomization(int seed, bool tryCreateLogFile)
59 | {
60 | // Perform randomization based on settings, then generate the ROM.
61 | RandomMM2.RandomizerCreate(true, seed);
62 |
63 | // Get A-Z representation of seed
64 | string seedAlpha = SeedConvert.ConvertBase10To26(RandomMM2.Seed);
65 | RandoSettings.SeedString = seedAlpha;
66 | Debug.WriteLine("\nSeed: " + seedAlpha + "\n");
67 |
68 | // Create log file if left shift is pressed while clicking
69 | if (tryCreateLogFile && !RandoSettings.IsSpoilerFree)
70 | {
71 | string logFileName = $"MM2RNG-{seedAlpha}.log";
72 | using (StreamWriter sw = new StreamWriter(logFileName, false))
73 | {
74 | sw.WriteLine("Mega Man 2 Randomizer");
75 | sw.WriteLine($"Version {RandoSettings.AssemblyVersion.ToString()}");
76 | sw.WriteLine($"Seed {seedAlpha}\n");
77 | sw.WriteLine(RandomMM2.randomStages.ToString());
78 | sw.WriteLine(RandomMM2.randomWeaponBehavior.ToString());
79 | sw.WriteLine(RandomMM2.randomEnemyWeakness.ToString());
80 | sw.WriteLine(RandomMM2.randomWeaknesses.ToString());
81 | sw.Write(RandomMM2.Patch.GetStringSortedByAddress());
82 | }
83 | }
84 |
85 | // Flag UI as having created a ROM, enabling the "open folder" button
86 | HasGeneratedAROM = true;
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/MM2RandoHost/Views/Primitives/CustomWindow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Input;
9 |
10 | namespace MM2RandoHost.Views.Primitives
11 | {
12 | public class CustomWindow : Window
13 | {
14 | public Action OnMaximizeOrRestore { get; set; }
15 |
16 | protected void TitleBarClick(object sender, MouseButtonEventArgs e)
17 | {
18 | if (e.ClickCount == 2)
19 | {
20 | if (WindowState == WindowState.Normal)
21 | WindowMaximize();
22 | else
23 | WindowRestore();
24 | }
25 | }
26 |
27 | protected void MinimizeClick(object sender, RoutedEventArgs e)
28 | {
29 | WindowState = WindowState.Minimized;
30 | }
31 |
32 | protected void RestoreClick(object sender, RoutedEventArgs e)
33 | {
34 | if (WindowState == WindowState.Normal)
35 | WindowMaximize();
36 | else
37 | WindowRestore();
38 | }
39 |
40 | protected void CloseClick(object sender, RoutedEventArgs e)
41 | {
42 | Close();
43 | }
44 |
45 | public override void OnApplyTemplate()
46 | {
47 | System.Windows.Shapes.Rectangle hitArea = GetTemplateChild("windowTitleBarClickRegion") as System.Windows.Shapes.Rectangle;
48 | if (hitArea != null)
49 | hitArea.MouseLeftButtonDown += TitleBarClick;
50 |
51 | Button restoreButton = GetTemplateChild("restoreButton") as Button;
52 | if (restoreButton != null)
53 | restoreButton.Click += MinimizeClick;
54 |
55 | Button closeButton = GetTemplateChild("closeButton") as Button;
56 | if (closeButton != null)
57 | closeButton.Click += CloseClick;
58 |
59 | base.OnApplyTemplate();
60 | }
61 |
62 | public void WindowMaximize()
63 | {
64 | WindowState = WindowState.Maximized;
65 | if (OnMaximizeOrRestore != null) OnMaximizeOrRestore.Invoke();
66 | }
67 | public void WindowRestore()
68 | {
69 | WindowState = WindowState.Normal;
70 | if (OnMaximizeOrRestore != null) OnMaximizeOrRestore.Invoke();
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/EColorsHex.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Enums
7 | {
8 | public enum EColorsHex
9 | {
10 | //Attempted to translate colors to HTML like colors. This is off because nothing matches exactly.
11 |
12 | ///Section 0x0?
13 | Gray = 0x00,
14 | RoyalBlue = 0x01,
15 | DarkBlue= 0x02,
16 | RoyalPurple = 0x03,
17 | DarkMagenta = 0x04,
18 | Crimson= 0x05,
19 | Red = 0x06,
20 | DarkRed= 0x07,
21 | Brown = 0x08,
22 | Kelp= 0x09,
23 | ForestGreen= 0x0A,
24 | DarkGreen= 0x0B,
25 | DarkTeal= 0x0C,
26 | Black = 0x0D,
27 | Black1 = 0x0E,
28 | Black2 = 0x0F,
29 |
30 | //Section 0x1?
31 | LightGray= 0x10,
32 | MediumBlue= 0x11,
33 | Blue= 0x12,
34 | Purple= 0x13,
35 | Magenta= 0x14,
36 | VioletRed= 0x15,
37 | Orange= 0x16,
38 | Tangerine= 0x17,
39 | GoldenRod= 0x18,
40 | Grass= 0x19,
41 | Green= 0x1A,
42 | Moss= 0x1B,
43 | Teal= 0x1C,
44 | Black3= 0x1D,
45 | Black4= 0x1E,
46 | Black5= 0x1F,
47 |
48 | //Section 0x2?
49 | NearWhite= 0x20,
50 | LightBlue= 0x21,
51 | SoftBlue = 0x22,
52 | LightPurple= 0x23,
53 | LightPink= 0x24,
54 | LightVioletRed= 0x25,
55 | LightOrange= 0x26,
56 | YellowOrange= 0x27,
57 | Yellow= 0x28,
58 | Lemon= 0x29,
59 | LightGreen= 0x2A,
60 | Lime= 0x2B,
61 | LightCyan= 0x2C,
62 | MediumGray= 0x2D,
63 | Black6= 0x2E,
64 | Black7= 0x2F,
65 |
66 | //Section 0x3?
67 | White= 0x30,
68 | PastelBlue= 0x31,
69 | PaleBlue= 0x32,
70 | PastelPurple= 0x33,
71 | PastelPink= 0x34,
72 | PastelVioletRed= 0x35,
73 | Taupe= 0x36,
74 | Beige= 0x37,
75 | PastelYellow= 0x38,
76 | PastelLemon= 0x39,
77 | PastelGreen= 0x3A,
78 | PastelCyan= 0x3B,
79 | Cyan= 0x3C,
80 | BabyPink= 0x3D,
81 | Black8= 0x3E,
82 | Black9= 0x3F
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/EDmgVsBoss.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace MM2Randomizer.Enums
4 | {
5 | public sealed class EDmgVsBoss
6 | {
7 | public string WeaponName
8 | {
9 | get; private set;
10 | }
11 |
12 | public int Address
13 | {
14 | get; private set;
15 | }
16 |
17 | public int Index
18 | {
19 | get; private set;
20 | }
21 |
22 | public static Dictionary Addresses;
23 |
24 | //Japanese
25 | public static readonly EDmgVsBoss Buster = new EDmgVsBoss(0, 0x02E933, "Buster");
26 | public static readonly EDmgVsBoss AtomicFire = new EDmgVsBoss(1, 0x02E941, "Atomic Fire");
27 | public static readonly EDmgVsBoss AirShooter = new EDmgVsBoss(2, 0x02E94F, "Air Shooter");
28 | public static readonly EDmgVsBoss LeafShield = new EDmgVsBoss(3, 0x02E95D, "Leaf Shield");
29 | public static readonly EDmgVsBoss BubbleLead = new EDmgVsBoss(4, 0x02E96B, "Bubble Lead");
30 | public static readonly EDmgVsBoss QuickBoomerang = new EDmgVsBoss(5, 0x02E979, "Quick Boomerang");
31 | public static readonly EDmgVsBoss TimeStopper = new EDmgVsBoss(6, 0x02C049, "Time Stopper");
32 | public static readonly EDmgVsBoss MetalBlade = new EDmgVsBoss(7, 0x02E995, "Metal Blade");
33 | public static readonly EDmgVsBoss ClashBomber = new EDmgVsBoss(8, 0x02E987, "Clash Bomber");
34 |
35 | //English
36 | public static readonly EDmgVsBoss U_DamageP = new EDmgVsBoss(0, 0x2e952, "Buster");
37 | public static readonly EDmgVsBoss U_DamageH = new EDmgVsBoss(1, 0x2e960, "Atomic Fire");
38 | public static readonly EDmgVsBoss U_DamageA = new EDmgVsBoss(2, 0x2e96e, "Air Shooter");
39 | public static readonly EDmgVsBoss U_DamageW = new EDmgVsBoss(3, 0x2e97c, "Leaf Shield");
40 | public static readonly EDmgVsBoss U_DamageB = new EDmgVsBoss(4, 0x2e98a, "Bubble Lead");
41 | public static readonly EDmgVsBoss U_DamageQ = new EDmgVsBoss(5, 0x2e998, "Quick Boomerang");
42 | public static readonly EDmgVsBoss U_DamageF = new EDmgVsBoss(6, 0x2C049, "Time Stopper");
43 | public static readonly EDmgVsBoss U_DamageM = new EDmgVsBoss(7, 0x2e9b4, "Metal Blade");
44 | public static readonly EDmgVsBoss U_DamageC = new EDmgVsBoss(8, 0x2e9a6, "Clash Bomber");
45 |
46 | static EDmgVsBoss()
47 | {
48 | Addresses = new Dictionary()
49 | {
50 | { U_DamageP.Address, U_DamageP },
51 | { U_DamageH.Address, U_DamageH },
52 | { U_DamageA.Address, U_DamageA },
53 | { U_DamageW.Address, U_DamageW },
54 | { U_DamageB.Address, U_DamageB },
55 | { U_DamageQ.Address, U_DamageQ },
56 | { U_DamageF.Address, U_DamageF },
57 | { U_DamageM.Address, U_DamageM },
58 | { U_DamageC.Address, U_DamageC },
59 | };
60 | }
61 |
62 | private EDmgVsBoss(int index, int address, string name)
63 | {
64 | this.Address = address;
65 | this.WeaponName = name;
66 | this.Index = index;
67 | }
68 |
69 | public static implicit operator int (EDmgVsBoss eDmgVsBoss)
70 | {
71 | return eDmgVsBoss.Address;
72 | }
73 |
74 | public static implicit operator EDmgVsBoss (int eDmgVsBoss)
75 | {
76 | return Addresses[eDmgVsBoss];
77 | }
78 |
79 | public override string ToString()
80 | {
81 | return WeaponName;
82 | }
83 |
84 | ///
85 | /// Get a list of pointers to weapon damage tables against bosses, sorted by boss order
86 | ///
87 | ///
88 | ///
89 | ///
90 | public static List GetTables(bool includeBuster, bool includeTimeStopper)
91 | {
92 | List tables = new List();
93 | if (includeBuster) tables.Add(U_DamageP);
94 | tables.Add(U_DamageH);
95 | tables.Add(U_DamageA);
96 | tables.Add(U_DamageW);
97 | tables.Add(U_DamageB);
98 | tables.Add(U_DamageQ);
99 | if (includeTimeStopper) tables.Add(U_DamageF);
100 | tables.Add(U_DamageM);
101 | tables.Add(U_DamageC);
102 | return tables;
103 | }
104 |
105 | ///
106 | ///
107 | ///
108 | public class Offset
109 | {
110 | public string Name
111 | {
112 | get; private set;
113 | }
114 |
115 | public int Value
116 | {
117 | get; private set;
118 | }
119 |
120 | public static Dictionary Offsets;
121 |
122 | public static readonly Offset Dragon = new Offset(0x08, "Dragon");
123 | public static readonly Offset Guts = new Offset(0x0A, "Guts");
124 | public static readonly Offset Machine = new Offset(0x0C, "Machine");
125 | public static readonly Offset Alien = new Offset(0x0D, "Alien");
126 | public static readonly Offset Heat = new Offset(0x00, "Heat");
127 | public static readonly Offset Air = new Offset(0x01, "Air");
128 | public static readonly Offset Wood = new Offset(0x02, "Wood");
129 | public static readonly Offset Bubble = new Offset(0x03, "Bubble");
130 | public static readonly Offset Quick = new Offset(0x04, "Quick");
131 | public static readonly Offset Flash = new Offset(0x05, "Flash");
132 | public static readonly Offset Metal = new Offset(0x06, "Metal");
133 | public static readonly Offset Clash = new Offset(0x07, "Clash");
134 |
135 | static Offset()
136 | {
137 | Offsets = new Dictionary()
138 | {
139 | { Dragon.Value , Dragon },
140 | { Guts.Value , Guts },
141 | { Machine.Value , Machine },
142 | { Alien.Value , Alien },
143 | { Heat.Value , Heat },
144 | { Air.Value , Air },
145 | { Wood.Value , Wood },
146 | { Bubble.Value , Bubble },
147 | { Quick.Value , Quick },
148 | { Flash.Value , Flash },
149 | { Metal.Value , Metal },
150 | { Clash.Value , Clash },
151 | };
152 | }
153 |
154 | private Offset(int offset, string name)
155 | {
156 | this.Name = name;
157 | this.Value = offset;
158 | }
159 |
160 | public static implicit operator int (Offset offset)
161 | {
162 | return offset.Value;
163 | }
164 |
165 | public static implicit operator Offset(int offset)
166 | {
167 | return Offsets[offset];
168 | }
169 |
170 | public override string ToString()
171 | {
172 | return Name;
173 | }
174 | }
175 |
176 |
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/EDmgVsEnemy.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace MM2Randomizer.Enums
4 | {
5 | ///
6 | ///
7 | ///
8 | public sealed class EDmgVsEnemy
9 | {
10 | public int Address
11 | {
12 | get; private set;
13 | }
14 |
15 | public string WeaponName
16 | {
17 | get; private set;
18 | }
19 |
20 | public static Dictionary Addresses { get; set; }
21 |
22 | public static readonly EDmgVsEnemy DamageP = new EDmgVsEnemy(0x03E9A8, "Buster");
23 | public static readonly EDmgVsEnemy DamageH = new EDmgVsEnemy(0x03EA24, "Atomic Fire");
24 | public static readonly EDmgVsEnemy DamageA = new EDmgVsEnemy(0x03EA9C, "Air Shooter");
25 | public static readonly EDmgVsEnemy DamageW = new EDmgVsEnemy(0x03EB14, "Leaf Shield");
26 | public static readonly EDmgVsEnemy DamageB = new EDmgVsEnemy(0x03EB8C, "Bubble Lead");
27 | public static readonly EDmgVsEnemy DamageQ = new EDmgVsEnemy(0x03EC04, "Quick Boomerang");
28 | public static readonly EDmgVsEnemy DamageM = new EDmgVsEnemy(0x03ECF4, "Metal Blade");
29 | public static readonly EDmgVsEnemy DamageC = new EDmgVsEnemy(0x03EC7C, "Clash Bomber");
30 |
31 | static EDmgVsEnemy()
32 | {
33 | Addresses = new Dictionary()
34 | {
35 | { DamageP.Address, DamageP },
36 | { DamageH.Address, DamageH },
37 | { DamageA.Address, DamageA },
38 | { DamageW.Address, DamageW },
39 | { DamageB.Address, DamageB },
40 | { DamageQ.Address, DamageQ },
41 | { DamageM.Address, DamageM },
42 | { DamageC.Address, DamageC },
43 | };
44 | }
45 |
46 | private EDmgVsEnemy(int address, string name)
47 | {
48 | this.Address = address;
49 | this.WeaponName = name;
50 | }
51 |
52 | public static implicit operator int (EDmgVsEnemy eDmgVsEnemy)
53 | {
54 | return eDmgVsEnemy.Address;
55 | }
56 |
57 | public static implicit operator EDmgVsEnemy(int eDmgVsEnemy)
58 | {
59 | return Addresses[eDmgVsEnemy];
60 | }
61 |
62 | public static bool operator ==(EDmgVsEnemy a, EDmgVsEnemy b)
63 | {
64 | return (a.Address == b.Address);
65 | }
66 |
67 | public static bool operator !=(EDmgVsEnemy a, EDmgVsEnemy b)
68 | {
69 | return (a.Address != b.Address);
70 | }
71 | public static bool operator ==(int a, EDmgVsEnemy b)
72 | {
73 | return (a == b.Address);
74 | }
75 |
76 | public static bool operator !=(int a, EDmgVsEnemy b)
77 | {
78 | return (a != b.Address);
79 | }
80 |
81 | public override bool Equals(object obj)
82 | {
83 | return base.Equals(obj);
84 | }
85 |
86 | public override int GetHashCode()
87 | {
88 | return base.GetHashCode();
89 | }
90 |
91 | ///
92 | ///
93 | ///
94 | ///
95 | public static List GetTables(bool includeBuster)
96 | {
97 | List list = new List()
98 | {
99 | DamageH,
100 | DamageA,
101 | DamageW,
102 | DamageB,
103 | DamageQ,
104 | DamageM,
105 | DamageC,
106 | };
107 |
108 | if (includeBuster)
109 | {
110 | list.Insert(0, DamageP);
111 | }
112 |
113 | return list;
114 | }
115 |
116 | ///
117 | ///
118 | ///
119 | public class Offset
120 | {
121 | public int Value
122 | {
123 | get; private set;
124 | }
125 |
126 | public static readonly Offset PicopicoKun;
127 | public static readonly Offset Press;
128 | public static readonly Offset ClashBarrier_Other;
129 | public static readonly Offset ClashBarrier_W4;
130 | public static readonly Offset Buebeam;
131 |
132 | static Offset()
133 | {
134 | ClashBarrier_Other = new Offset(0x2D);
135 | Press = new Offset(0x30);
136 | ClashBarrier_W4 = new Offset(0x57);
137 | PicopicoKun = new Offset(0x6A);
138 | Buebeam = new Offset(0x6D);
139 | }
140 |
141 | private Offset(int offset)
142 | {
143 | this.Value = offset;
144 | }
145 |
146 | public static implicit operator int (Offset offset)
147 | {
148 | return offset.Value;
149 | }
150 |
151 | public static bool operator ==(Offset a, Offset b)
152 | {
153 | return (a.Value == b.Value);
154 | }
155 |
156 | public static bool operator !=(Offset a, Offset b)
157 | {
158 | return (a.Value != b.Value);
159 | }
160 |
161 | public static bool operator ==(int a, Offset b)
162 | {
163 | return (a == b.Value);
164 | }
165 |
166 | public static bool operator !=(int a, Offset b)
167 | {
168 | return (a != b.Value);
169 | }
170 |
171 | public override bool Equals(object obj)
172 | {
173 | return base.Equals(obj);
174 | }
175 |
176 | public override int GetHashCode()
177 | {
178 | return base.GetHashCode();
179 | }
180 | }
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/EEnemyID.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Enums
7 | {
8 | public enum EEnemyID
9 | {
10 | Shrink = 0x00,
11 | Shrink_Angler = 0x01,
12 | Shrink_Spawner = 0x02,
13 | M445_Activator = 0x03,
14 | M445_Instance = 0x04,
15 | M445_Deactivator = 0x05,
16 | Claw_Activator = 0x07,
17 | Claw_Instance = 0x08,
18 | Claw_Deactivator = 0x09,
19 | Tanishi = 0x0A,
20 | Kerog = 0x0C,
21 | Kerog_Small = 0x0D,
22 | QuickLaser = 0x14,
23 | Batton = 0x16,
24 | Robbit = 0x17,
25 | Monking = 0x1D,
26 | Kukku_Activator = 0x1E,
27 | Kukku_Deactivator = 0x20,
28 | Telly = 0x21,
29 | ChangkeyMaker = 0x23,
30 | QuickDarkPalette = 0x25,
31 | QuickNormalPalette = 0x27,
32 | Pierrobot = 0x29,
33 | FlyBoy = 0x2B,
34 | ClashBarrier = 0x2D,
35 | Press = 0x30,
36 | Blocky = 0x31,
37 | NeoMetall = 0x34,
38 | Matasaburo = 0x36,
39 | Pipi_Activator = 0x37,
40 | Pipi_Deactivator = 0x39,
41 | LightningGoro = 0x3E,
42 | Springer = 0x46,
43 | Mole_Activator = 0x47,
44 | Mole_Deactivator = 0x4A,
45 | Shotman_Left = 0x4B,
46 | Shotman_Right = 0x4C,
47 | SniperArmor = 0x4E,
48 | SniperJoe = 0x4F,
49 | Scworm = 0x50,
50 | BigFish = 0x71,
51 | Drip1 = 0x72,
52 | Drip2 = 0x73,
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/EItemNumber.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Enums
7 | {
8 | public enum EItemNumber
9 | {
10 | None = 0,
11 | One = 1,
12 | Two = 2,
13 | Three = 4
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/EItemStageAddress.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Enums
7 | {
8 | public enum EItemStageAddress
9 | {
10 | // 0x03C291 - Item # from Heat Man
11 | // 0x03C292 - Item # from Air Man
12 | // 0x03C293 - Item # from Wood Man
13 | // 0x03C294 - Item # from Bubble Man
14 | // 0x03C295 - Item # from Quick Man
15 | // 0x03C296 - Item # from Flash Man
16 | // 0x03C297 - Item # from Metal Man
17 | // 0x03C298 - Item # from Crash Man
18 |
19 | HeatMan = 0x03C291,
20 | AirMan = 0x03C292,
21 | WoodMan = 0x03C293,
22 | BubbleMan = 0x03C294,
23 | QuickMan = 0x03C295,
24 | FlashMan = 0x03C296,
25 | MetalMan = 0x03C297,
26 | CrashMan = 0x03C298
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/EMiscAddresses.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Enums
7 | {
8 | public enum EMiscAddresses
9 | {
10 | WarpXCoordinateStartAddress = 0x038280,
11 | WarpYCoordinateStartAddress = 0x038278
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/EMusicID.cs:
--------------------------------------------------------------------------------
1 | namespace MM2Randomizer.Enums
2 | {
3 | public enum EMusicID
4 | {
5 | Flash = 0x00,
6 | Wood = 0x01,
7 | Clash = 0x02,
8 | Heat = 0x03,
9 | Air = 0x04,
10 | Metal = 0x05,
11 | Quick = 0x06,
12 | Bubble = 0x07,
13 | Wily12 = 0x08,
14 | Wily345 = 0x09,
15 | Boss = 0x0B,
16 | StageSelectWily5 = 0x0C,
17 | Nothing = 0xFF,
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/ERMPortraitAddress.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Enums
7 | {
8 | public enum ERMPortraitAddress
9 | {
10 | // StageSelect Address Value
11 | // -----------------------------
12 | // Bubble Man 0x034670 3
13 | // Air Man 0x034671 1
14 | // Quick Man 0x034672 4
15 | // Wood Man 0x034673 2
16 | // Crash Man 0x034674 7
17 | // Flash Man 0x034675 5
18 | // Metal Man 0x034676 6
19 | // Heat Man 0x034677 0
20 |
21 | HeatMan = 0x034677,
22 |
23 | AirMan = 0x034671,
24 |
25 | WoodMan = 0x034673,
26 |
27 | BubbleMan = 0x034670,
28 |
29 | QuickMan = 0x034672,
30 |
31 | FlashMan = 0x034675,
32 |
33 | MetalMan = 0x034676,
34 |
35 | CrashMan = 0x034674
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/ERMPortraitText.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Enums
7 | {
8 | public enum ERMPortraitText
9 | {
10 | HeatMan = 0x02F035,
11 | AirMan = 0x02EF3D,
12 | WoodMan = 0x02F045,
13 | BubbleMan = 0x02EF35,
14 | QuickMan = 0x02EF45,
15 | FlashMan = 0x02F13D,
16 | MetalMan = 0x02F135,
17 | CrashMan = 0x02F145
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/ERMStageClearAddress.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Enums
7 | {
8 | public enum ERMStageClearAddress
9 | {
10 | HeatMan = 0x03C289,
11 | AirMan = 0x03C28A,
12 | WoodMan = 0x03C28B,
13 | BubbleMan = 0x03C28C,
14 | QuickMan = 0x03C28D,
15 | FlashMan = 0x03C28E,
16 | MetalMan = 0x03C28F,
17 | CrashMan = 0x03C290,
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/ERMStageSelect.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Enums
7 | {
8 | public enum ERMStageSelect
9 | {
10 | //Not sure what the stage select order is but this is the starting Mem
11 | FirstStageInMemory = 0x0346E1
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/ERMStageWeaponAddress.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Enums
7 | {
8 | public enum ERMStageWeaponAddress
9 | {
10 | // StageBeat Address Value
11 | // -----------------------------
12 | // Heat Man 0x03C289 1
13 | // Air Man 0x03C28A 2
14 | // Wood Man 0x03C28B 4
15 | // Bubble Man 0x03C28C 8
16 | // Quick Man 0x03C28D 16
17 | // Flash Man 0x03C28E 32
18 | // Metal Man 0x03C28F 64
19 | // Crash Man 0x03C290 128
20 |
21 | HeatMan = 0x03C289,
22 |
23 | AirMan = 0x03C28A,
24 |
25 | WoodMan = 0x03C28B,
26 |
27 | BubbleMan = 0x03C28C,
28 |
29 | QuickMan = 0x03C28D,
30 |
31 | FlashMan = 0x03C28E,
32 |
33 | MetalMan = 0x03C28F,
34 |
35 | CrashMan = 0x03C290,
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/ERMWeaponValue.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Enums
7 | {
8 | public enum ERMWeaponValueBit
9 | {
10 | // StageBeat Address Value
11 | // -----------------------------
12 | // Heat Man 0x03C289 1
13 | // Air Man 0x03C28A 2
14 | // Wood Man 0x03C28B 4
15 | // Bubble Man 0x03C28C 8
16 | // Quick Man 0x03C28D 16
17 | // Flash Man 0x03C28E 32
18 | // Metal Man 0x03C28F 64
19 | // Crash Man 0x03C290 128
20 | HeatMan = 0x01,
21 | AirMan = 0x02,
22 | WoodMan = 0x04,
23 | BubbleMan = 0x08,
24 | QuickMan = 0x10,
25 | FlashMan = 0x20,
26 | MetalMan = 0x40,
27 | CrashMan = 0x80
28 | }
29 |
30 | public enum EWeaponIndex
31 | {
32 | Heat = 0x01,
33 | Air = 0x02,
34 | Wood = 0x03,
35 | Bubble = 0x04,
36 | Quick = 0x05,
37 | Clash = 0x06,
38 | Metal = 0x07,
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/ESoundID.cs:
--------------------------------------------------------------------------------
1 | namespace MM2Randomizer.Enums
2 | {
3 | public enum ESoundID
4 | {
5 | WeaponF = 0x21,
6 | HeatmanUnused = 0x22,
7 | WeaponM = 0x23,
8 | WeaponP = 0x24,
9 | Shotman = 0x25,
10 | TakeDamage = 0x26,
11 | QuickBeam = 0x27,
12 | Refill = 0x28,
13 | MegaLand = 0x29,
14 | WilyDefeat = 0x2A, // no
15 | DamageEnemy = 0x2B,
16 | Dragon = 0x2C,
17 | Tink = 0x2D,
18 | ClashAttach = 0x2E,
19 | Cursor = 0x2F,
20 | TeleportIn = 0x30,
21 | WeaponW = 0x31,
22 | Pause = 0x32,
23 | Unknown0 = 0x33, // no
24 | BossDoor = 0x34, // no
25 | WeaponH_Charge0 = 0x35, // yes, but randomize the 3
26 | WeaponH_Charge1 = 0x36,
27 | WeaponH_Charge2 = 0x37,
28 | WeaponH_Shoot = 0x38,
29 | FlyBoy = 0x39,
30 | TeleportOut = 0x3A,
31 | Splash = 0x3B,
32 | Yoku = 0x3C,
33 | Droplet1 = 0x3D,
34 | Droplet2 = 0x3E, // no
35 | WeaponA = 0x3F,
36 | Unknown1 = 0x40, // yes. weird fuzz sound?
37 | Death = 0x41,
38 | OneUp = 0x42,
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/MM2RandoLib/Enums/EStageID.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Enums
7 | {
8 | public enum EStageID
9 | {
10 | HeatW1 = 0x00,
11 | AirW2 = 0x01,
12 | WoodW3 = 0x02,
13 | BubbleW4 = 0x03,
14 | QuickW5 = 0x04,
15 | FlashW6 = 0x05,
16 | Metal = 0x06,
17 | Clash = 0x07
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/MM2RandoLib/MM2RandoLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.0
4 | True
5 | MM2RandoLib
6 | 0.5.0
7 | Copyright 2019 duckfist
8 | .NET library that can generate a randomized ROM patch for Mega Man 2.
9 | duckfist
10 | https://github.com/duckfist/MM2Random/blob/master/LICENSE
11 | https://github.com/duckfist/MM2Random/
12 | https://github.com/duckfist/MM2Random/
13 |
14 | migrated to .netstandard 2.0
15 | 0.5.0.*
16 | 0.5.0.0
17 | false
18 | en-US
19 | AnyCPU;x64
20 |
21 |
22 | DEBUG;TRACE
23 | full
24 | true
25 |
26 |
27 | DEBUG;TRACE
28 | full
29 | true
30 |
31 |
32 |
33 |
34 |
35 |
36 | True
37 | True
38 | Resources.resx
39 |
40 |
41 |
42 |
43 | PublicResXFileCodeGenerator
44 | Resources.Designer.cs
45 | MM2Randomizer.Properties
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/MM2RandoLib/ObservableBase.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.ComponentModel;
3 | using System.Runtime.CompilerServices;
4 |
5 | namespace MM2Randomizer
6 | {
7 | /// Provides an implementation for the interface.
8 | public abstract class ObservableBase : INotifyPropertyChanged
9 | {
10 | /// Occurs when a property value cahnges.
11 | public event PropertyChangedEventHandler PropertyChanged;
12 |
13 | /// Raises the property changed event.
14 | /// The property name.
15 | protected void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
16 | {
17 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
18 | }
19 |
20 | ///
21 | /// Set the value of a property, firing NotifyPropertyChanged if the value is new. This is used
22 | /// for a cleaner implementation of ViewModel properties, so they have fewer lines of code.
23 | ///
24 | /// The type of the property being changed.
25 | /// The property's backing field.
26 | /// The property's new value to set.
27 | /// The name of the property (leave blank to use the caller's name)
28 | /// True if the property has changed, false if it is still the same value.
29 | protected bool SetProperty(
30 | ref T privateField,
31 | T newValue,
32 | [CallerMemberName]string propertyName = null,
33 | params string[] additionalProperties)
34 | {
35 | // If value hasn't changed, just return false
36 | if (EqualityComparer.Default.Equals(privateField, newValue)) return false;
37 |
38 | // Value has changed, invoke propertychanged and return true
39 | privateField = newValue;
40 | NotifyPropertyChanged(propertyName);
41 |
42 | // Notify any additional properties that might depend on this one
43 | foreach (string additionalProperty in additionalProperties)
44 | NotifyPropertyChanged(additionalProperty);
45 |
46 | return true;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/MM2RandoLib/Patcher/ByteChangeRecord.cs:
--------------------------------------------------------------------------------
1 | namespace MM2Randomizer.Patcher
2 | {
3 | public class ChangeByteRecord
4 | {
5 | public int Address { get; set; }
6 | public byte Value { get; set; }
7 | public string Note { get; set; }
8 |
9 | public ChangeByteRecord(int address, byte value, string note = "")
10 | {
11 | Address = address;
12 | Value = value;
13 | Note = note;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/MM2RandoLib/Patcher/Patch.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | namespace MM2Randomizer.Patcher
8 | {
9 | public class Patch
10 | {
11 | public Dictionary Bytes { get; set; }
12 |
13 | public Patch()
14 | {
15 | Bytes = new Dictionary();
16 | }
17 |
18 | ///
19 | /// TODO
20 | ///
21 | ///
22 | ///
23 | ///
24 | public void Add(int address, byte value, string note = "")
25 | {
26 | ChangeByteRecord newByte = new ChangeByteRecord(address, value, note);
27 |
28 | // Either replace the byte at the given address, or add it if it doesn't exist
29 | if (Bytes.ContainsKey(address))
30 | {
31 | Bytes[address] = newByte;
32 | }
33 | else
34 | {
35 | Bytes.Add(address, newByte);
36 | }
37 | }
38 |
39 | ///
40 | /// TODO
41 | ///
42 | ///
43 | public void ApplyRandoPatch(string filename)
44 | {
45 | using (var stream = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite))
46 | {
47 | //GetStringSortedByAddress();
48 |
49 | foreach (KeyValuePair kvp in Bytes)
50 | {
51 | stream.Position = kvp.Key;
52 | stream.WriteByte(kvp.Value.Value);
53 | }
54 | }
55 | }
56 | public string GetStringSortedByAddress()
57 | {
58 | var sortDict = from kvp in Bytes orderby kvp.Key ascending select kvp;
59 | return ConvertDictToString(sortDict);
60 | }
61 |
62 | public string GetString()
63 | {
64 | return ConvertDictToString((IOrderedEnumerable>)Bytes);
65 | }
66 |
67 | ///
68 | /// TODO
69 | ///
70 | ///
71 | ///
72 | private string ConvertDictToString(IOrderedEnumerable> dict)
73 | {
74 | StringBuilder sb = new StringBuilder();
75 | foreach (KeyValuePair kvp in dict)
76 | {
77 | ChangeByteRecord b = kvp.Value;
78 | sb.Append($"0x{b.Address:X6}\t{b.Value:X2}\t{b.Note}");
79 | sb.Append(Environment.NewLine);
80 | }
81 | return sb.ToString();
82 | }
83 |
84 | ///
85 | /// TODO
86 | ///
87 | ///
88 | ///
89 | public void ApplyIPSPatch(string romname, byte[] patchBytes)
90 | {
91 | // Noobish Noobsicle wrote this IPS patching code
92 | // romname is the original ROM, patchname is the patch to apply
93 | FileStream romstream = new FileStream(romname, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
94 | int lint = patchBytes.Length;
95 | byte[] ipsbyte = patchBytes;
96 | byte[] rombyte = new byte[romstream.Length];
97 | IAsyncResult romresult;
98 | int ipson = 5;
99 | int totalrepeats = 0;
100 | int offset = 0;
101 | bool keepgoing = true;
102 | while (keepgoing == true)
103 | {
104 | offset = ipsbyte[ipson] * 0x10000 + ipsbyte[ipson + 1] * 0x100 + ipsbyte[ipson + 2];
105 | ipson++;
106 | ipson++;
107 | ipson++;
108 | if (ipsbyte[ipson] * 256 + ipsbyte[ipson + 1] == 0)
109 | {
110 | ipson++;
111 | ipson++;
112 | totalrepeats = ipsbyte[ipson] * 256 + ipsbyte[ipson + 1];
113 | ipson++;
114 | ipson++;
115 | byte[] repeatbyte = new byte[totalrepeats];
116 | for (int ontime = 0; ontime < totalrepeats; ontime++)
117 | repeatbyte[ontime] = ipsbyte[ipson];
118 | romstream.Seek(offset, SeekOrigin.Begin);
119 | romresult = romstream.BeginWrite(repeatbyte, 0, totalrepeats, null, null);
120 | romstream.EndWrite(romresult);
121 | ipson++;
122 | }
123 | else
124 | {
125 | totalrepeats = ipsbyte[ipson] * 256 + ipsbyte[ipson + 1];
126 | ipson++;
127 | ipson++;
128 | romstream.Seek(offset, SeekOrigin.Begin);
129 | romresult = romstream.BeginWrite(ipsbyte, ipson, totalrepeats, null, null);
130 | romstream.EndWrite(romresult);
131 | ipson = ipson + totalrepeats;
132 | }
133 | if (ipsbyte[ipson] == 69 && ipsbyte[ipson + 1] == 79 && ipsbyte[ipson + 2] == 70)
134 | keepgoing = false;
135 | }
136 | romstream.Close();
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/MM2RandoLib/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | ..\Resources\bossnames.csv;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252
123 |
124 |
125 | ..\Resources\companynames.csv;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252
126 |
127 |
128 | ..\Resources\countrylist.csv;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252
129 |
130 |
131 | ..\Resources\creditstext.csv;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
132 |
133 |
134 | ..\Resources\enemylist.csv;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252
135 |
136 |
137 | ..\Resources\enemyweakness.csv;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252
138 |
139 |
140 | ..\Resources\mm2rng_prepatch.ips;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
141 |
142 |
143 | ..\Resources\music.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8
144 |
145 |
146 | ..\Resources\mm2rng_musicpatch.ips;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
147 |
148 |
149 | ..\Resources\level_components.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252
150 |
151 |
152 | ..\Resources\SpritePatches\SpriteSwap_Bass.ips;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
153 |
154 |
155 | ..\Resources\SpritePatches\SpriteSwap_Proto.ips;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
156 |
157 |
158 | ..\Resources\SpritePatches\SpriteSwap_Roll.ips;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
159 |
160 |
--------------------------------------------------------------------------------
/MM2RandoLib/RandoSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace MM2Randomizer
8 | {
9 | public class RandoSettings : ObservableBase
10 | {
11 | private string seedString;
12 | private string sourcePath;
13 | private bool isSourcePathValid;
14 | private bool isSeedValid;
15 | private bool isSourcePathAndSeedValid;
16 | private string hashStringMD5;
17 | private string hashStringSHA256;
18 | private string hashValidationMessage;
19 | private bool isHashValid;
20 | private bool isSpoilerFree;
21 |
22 | private PlayerSprite _selectedPlayer;
23 |
24 | public readonly string[] ExpectedMD5s = new string[]
25 | {
26 | "caaeb9ee3b52839de261fd16f93103e6", // Mega Man 2 (U)
27 | "8e4bc5b03ffbd4ef91400e92e50dd294", // Mega Man 2 (USA)
28 | };
29 |
30 | public readonly string[] ExpectedSHA256s = new string[]
31 | {
32 | "27b5a635df33ed57ed339dfc7fd62fc603b39c1d1603adb5cdc3562a0b0d555b", // Mega Man 2 (U)
33 | "49136b412ff61beac6e40d0bbcd8691a39a50cd2744fdcdde3401eed53d71edf", // Mega Man 2 (USA)
34 | };
35 |
36 | public RandoSettings()
37 | {
38 | // Rando assembly state variables
39 | SeedString = "";
40 | SourcePath = "";
41 | IsSeedValid = false;
42 | IsSourcePathValid = false;
43 | IsSourcePathAndSeedValid = false;
44 | HashStringMD5 = "";
45 | HashStringSHA256 = "";
46 | HashValidationMessage = "";
47 | IsHashValid = false;
48 |
49 | // Flags for Rando Core Modules (Interdependent, cannot be changed from UI)
50 | Is8StagesRandom = true;
51 | IsWeaponsRandom = true;
52 | IsTeleportersRandom = true;
53 |
54 | // Flags for Rando Gameplay Modules
55 | IsWeaponBehaviorRandom = true;
56 | IsWeaknessRandom = true;
57 | IsBossInBossRoomRandom = true;
58 | IsBossAIRandom = true;
59 | IsItemsRandom = true;
60 | IsEnemiesRandom = true;
61 | IsEnemyWeaknessRandom = true;
62 | IsTilemapChangesEnabled = true;
63 |
64 | // Flags for Rando Cosmetic Modules
65 | IsWeaponNamesRandom = true;
66 | IsColorsRandom = true;
67 | IsBGMRandom = true;
68 | SelectedPlayer = PlayerSprite.Rockman;
69 |
70 | // Flags for Optional Gameplay Modules
71 | FastText = true;
72 | BurstChaserMode = false;
73 | IsSpoilerFree = false;
74 | }
75 |
76 | #region Meta Properties
77 |
78 | ///
79 | /// Alphabetical string representation of the RandomMM2.Seed integer of the most
80 | /// recently generated ROM.
81 | ///
82 | public string SeedString
83 | {
84 | get => seedString;
85 | set
86 | {
87 | value = value.ToUpper();
88 | if (seedString != value)
89 | {
90 | seedString = value;
91 | NotifyPropertyChanged();
92 |
93 | // TODO: Check for better validity of seed
94 | IsSeedValid = (seedString == "") ? false : true;
95 | IsSourcePathAndSeedValid = IsSourcePathValid && IsSeedValid;
96 | }
97 | }
98 | }
99 |
100 | ///
101 | /// Full path to user-provided ROM to apply patch.
102 | ///
103 | public string SourcePath
104 | {
105 | get => sourcePath;
106 | set => SetProperty(ref sourcePath, value);
107 | }
108 |
109 | public bool IsSourcePathValid
110 | {
111 | get => isSourcePathValid;
112 | set => SetProperty(ref isSourcePathValid, value);
113 | }
114 |
115 | public bool IsSeedValid
116 | {
117 | get => isSeedValid;
118 | set => SetProperty(ref isSeedValid, value);
119 | }
120 |
121 | // TODO need this?
122 | public bool IsSourcePathAndSeedValid
123 | {
124 | get => isSourcePathAndSeedValid;
125 | set => SetProperty(ref isSourcePathAndSeedValid, value);
126 | }
127 |
128 | public bool IsSpoilerFree
129 | {
130 | get => isSpoilerFree;
131 | set => SetProperty(ref isSpoilerFree, value);
132 | }
133 |
134 | public string HashStringMD5
135 | {
136 | get => hashStringMD5;
137 | set => SetProperty(ref hashStringMD5, value);
138 | }
139 |
140 | public string HashStringSHA256
141 | {
142 | get => hashStringSHA256;
143 | set => SetProperty(ref hashStringSHA256, value);
144 | }
145 |
146 | public string HashValidationMessage
147 | {
148 | get => hashValidationMessage;
149 | set => SetProperty(ref hashValidationMessage, value);
150 | }
151 |
152 | public bool IsHashValid
153 | {
154 | get => isHashValid;
155 | set => SetProperty(ref isHashValid, value);
156 | }
157 |
158 | ///
159 | /// Get this assembly version as a bindable property.
160 | ///
161 | public Version AssemblyVersion
162 | {
163 | get
164 | {
165 | return Assembly.GetAssembly(typeof(RandomMM2)).GetName().Version;
166 | }
167 | }
168 |
169 | #endregion
170 |
171 | #region Randomizer Flags
172 |
173 | ///
174 | /// If True, the Robot Master stages will be shuffled and will not be indicated by the
175 | /// portraits on the Stage Select screen.
176 | ///
177 | public bool Is8StagesRandom { get; set; }
178 |
179 | ///
180 | /// If True, the weapons awarded from each Robot Master is shuffled.
181 | ///
182 | public bool IsWeaponsRandom { get; set; }
183 |
184 | ///
185 | /// If True, Items 1, 2, and 3 will be awarded from random Robot Masters.
186 | ///
187 | public bool IsItemsRandom { get; set; }
188 |
189 | ///
190 | /// If true, in Wily 5, the Robot Master locations in each teleporter is randomized.
191 | ///
192 | public bool IsTeleportersRandom { get; set; }
193 |
194 | ///
195 | /// If True, the damage each weapon does against each Robot Master is changed. The manner in
196 | /// which it is changed depends on if IsWeaknessEasy is True or if IsWeaknessHard is True.
197 | ///
198 | public bool IsWeaknessRandom { get; set; }
199 |
200 | ///
201 | ///
202 | ///
203 | public bool IsBossAIRandom { get; set; }
204 |
205 | ///
206 | /// TODO
207 | ///
208 | public bool IsColorsRandom { get; set; }
209 |
210 | ///
211 | /// TODO
212 | ///
213 | public bool IsEnemiesRandom { get; set; }
214 |
215 | public bool IsEnemyWeaknessRandom { get; set; }
216 |
217 | public bool IsBossInBossRoomRandom { get; set; }
218 |
219 | ///
220 | ///
221 | ///
222 | public bool IsTilemapChangesEnabled { get; set; }
223 |
224 | ///
225 | /// TODO
226 | ///
227 | public bool IsBGMRandom { get; set; }
228 |
229 | ///
230 | /// Change this value to set Mega Man's sprite graphic.
231 | ///
232 | public PlayerSprite SelectedPlayer
233 | {
234 | get => _selectedPlayer;
235 | set => SetProperty(ref _selectedPlayer, value);
236 | }
237 |
238 | ///
239 | ///
240 | ///
241 | public bool IsWeaponNamesRandom { get; set; }
242 |
243 | ///
244 | /// TODO
245 | ///
246 | public bool FastText { get; set; }
247 |
248 | public bool IsStageNameHidden { get; set; }
249 |
250 | ///
251 | /// TODO
252 | ///
253 | public bool BurstChaserMode { get; set; }
254 |
255 | public bool IsWeaponBehaviorRandom { get; set; }
256 |
257 | #endregion
258 |
259 | public string GetFlagsString()
260 | {
261 | StringBuilder sb = new StringBuilder();
262 | if (Is8StagesRandom && IsWeaponsRandom && IsTeleportersRandom)
263 | sb.Append('!'); else sb.Append(' ');
264 | //if (Is8StagesRandom) sb.Append('A'); else sb.Append(' ');
265 | //if (IsWeaponsRandom) sb.Append('B'); else sb.Append(' ');
266 | //if (IsTeleportersRandom) sb.Append('C'); else sb.Append(' ');
267 | if (IsWeaponBehaviorRandom) sb.Append('A'); else sb.Append(' ');
268 | if (IsWeaknessRandom) sb.Append('B'); else sb.Append(' ');
269 | if (IsBossInBossRoomRandom) sb.Append('C'); else sb.Append(' ');
270 | if (IsBossAIRandom) sb.Append('D'); else sb.Append(' ');
271 | if (IsItemsRandom) sb.Append('E'); else sb.Append(' ');
272 | if (IsEnemiesRandom) sb.Append('F'); else sb.Append(' ');
273 | if (IsEnemyWeaknessRandom) sb.Append('G'); else sb.Append(' ');
274 | if (IsTilemapChangesEnabled) sb.Append('H'); else sb.Append(' ');
275 |
276 | if (IsWeaponNamesRandom) sb.Append('1'); else sb.Append(' ');
277 | if (IsColorsRandom) sb.Append('2'); else sb.Append(' ');
278 | if (IsBGMRandom) sb.Append('3'); else sb.Append(' ');
279 |
280 | if (FastText) sb.Append('t'); else sb.Append(' ');
281 | if (BurstChaserMode) sb.Append('©'); else sb.Append(' ');
282 | if (IsStageNameHidden) sb.Append('?'); else sb.Append(' ');
283 | return sb.ToString();
284 | }
285 |
286 | ///
287 | /// This method checks that a file exists and then compares its checksum with known good Mega Man 2 ROMs.
288 | /// If it fails any of this, the method returns false.
289 | ///
290 | ///
291 | ///
292 | public bool ValidateFile(string path)
293 | {
294 | // Check if file even exists
295 | SourcePath = path;
296 | IsSourcePathValid = System.IO.File.Exists(SourcePath);
297 | IsSourcePathAndSeedValid = IsSourcePathValid && IsSeedValid;
298 |
299 | if (!IsSourcePathValid)
300 | {
301 | HashValidationMessage = "File does not exist.";
302 | IsHashValid = false;
303 | return false;
304 | }
305 |
306 | // Ensure file size is small so that we can take the hash
307 | var info = new System.IO.FileInfo(path);
308 | long size = info.Length;
309 | if (size > 2000000)
310 | {
311 | decimal MB = (size / (decimal)(1024d * 1024d));
312 | HashValidationMessage = $"File is {MB:0.00} MB, clearly not a NES ROM. WTF are you doing?";
313 | IsSourcePathValid = false;
314 | IsHashValid = false;
315 | return false;
316 | }
317 |
318 | // Calculate the file's hash
319 | string hashStrMd5 = "";
320 | string hashStrSha256 = "";
321 |
322 | // SHA256
323 | using (var sha = new System.Security.Cryptography.SHA256Managed())
324 | {
325 | using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
326 | {
327 | byte[] hashSha256 = sha.ComputeHash(fs);
328 | hashStrSha256 = BitConverter.ToString(hashSha256).Replace("-", String.Empty).ToLowerInvariant();
329 | }
330 | }
331 |
332 | // MD5
333 | using (var md5 = System.Security.Cryptography.MD5.Create())
334 | {
335 | using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
336 | {
337 | var hashMd5 = md5.ComputeHash(fs);
338 | hashStrMd5 = BitConverter.ToString(hashMd5).Replace("-", "").ToLowerInvariant();
339 | }
340 | }
341 |
342 | // Update hash strings
343 | HashStringSHA256 = hashStrSha256;
344 | HashStringMD5 = hashStrMd5;
345 |
346 | // Check that the hash matches a supported hash
347 | List md5s = new List(ExpectedMD5s);
348 | List sha256s = new List(ExpectedSHA256s);
349 | IsHashValid = (md5s.Contains(HashStringMD5) && sha256s.Contains(HashStringSHA256));
350 | if (IsHashValid)
351 | {
352 | HashValidationMessage = "ROM checksum is valid, good to go!";
353 | }
354 | else
355 | {
356 | HashValidationMessage = "Wrong file checksum. Please try another ROM, or it may not work.";
357 | return false;
358 | }
359 |
360 | // If we made it this far, the file looks good!
361 | return true;
362 | }
363 | }
364 |
365 | public enum PlayerSprite
366 | {
367 | Rockman,
368 | Protoman,
369 | Roll,
370 | Bass
371 | }
372 | }
373 |
--------------------------------------------------------------------------------
/MM2RandoLib/RandomMM2.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Diagnostics;
5 |
6 | using MM2Randomizer.Patcher;
7 | using MM2Randomizer.Randomizers;
8 | using MM2Randomizer.Randomizers.Enemies;
9 | using MM2Randomizer.Randomizers.Colors;
10 | using MM2Randomizer.Randomizers.Stages;
11 | using MM2Randomizer.Randomizers.Stages.Components;
12 | using MM2Randomizer.Utilities;
13 |
14 | namespace MM2Randomizer
15 | {
16 | public static class RandomMM2
17 | {
18 | public static int Seed = -1;
19 | public static Random Random;
20 | public static Random RNGCosmetic;
21 | public static Patch Patch;
22 | public static RandoSettings Settings;
23 | public static readonly string TempFileName = "temp.nes";
24 | public static string RecentlyCreatedFileName = "";
25 |
26 | public static RStages randomStages;
27 | public static RWeaponGet randomWeaponGet;
28 | public static RWeaponBehavior randomWeaponBehavior;
29 | public static RWeaknesses randomWeaknesses;
30 | public static RBossAI randomBossAI;
31 | public static RItemGet randomItemGet;
32 | public static RTeleporters randomTeleporters;
33 | public static REnemies randomEnemies;
34 | public static REnemyWeaknesses randomEnemyWeakness;
35 | public static RBossRoom randomBossInBossRoom;
36 | public static RTilemap randomTilemap;
37 | public static RColors randomColors;
38 | public static RMusic randomMusic;
39 | public static RText rWeaponNames;
40 | public static List Randomizers;
41 | public static List CosmeticRandomizers;
42 |
43 | ///
44 | /// Perform the randomization based on the seed and user-provided settings, and then
45 | /// generate the new ROM.
46 | ///
47 | public static string RandomizerCreate(bool fromClientApp, int seed)
48 | {
49 | Seed = seed;
50 |
51 | // List of randomizer modules to use; will add modules based on checkbox states
52 | Randomizers = new List();
53 | CosmeticRandomizers = new List();
54 |
55 |
56 | ///==========================
57 | /// "CORE" MODULES
58 | ///==========================
59 | // NOTE: Just in case, link RStages, RWeaponGet, and RTeleporter into one "Core Randomizer" module
60 | // Their interdependencies are too risky to separate as options, and likely nobody will want to customize this part anyways.
61 | // Random portrait locations on stage select
62 | randomStages = new RStages();
63 | // Random weapon awarded from each stage
64 | // WARNING: May be dependent on RTeleporters, verify?
65 | // WARNING: May be dependent on RStages
66 | randomWeaponGet = new RWeaponGet();
67 | // Random teleporter destinations in Wily 5
68 | randomTeleporters = new RTeleporters();
69 |
70 |
71 | ///==========================
72 | /// "GAMEPLAY SEED" MODULES
73 | ///==========================
74 | // Caution: RWeaknesses depends on this
75 | randomWeaponBehavior = new RWeaponBehavior();
76 |
77 | // Depends on RWeaponBehavior (ammo), can use default values
78 | randomWeaknesses = new RWeaknesses();
79 |
80 | // Caution: RText depends on this, but default values will be used if not enabled.
81 | randomBossInBossRoom = new RBossRoom();
82 |
83 | // Independent
84 | randomBossAI = new RBossAI();
85 |
86 | // Independent
87 | randomItemGet = new RItemGet();
88 |
89 | // Independent
90 | randomEnemies = new REnemies();
91 |
92 | // Independent
93 | randomEnemyWeakness = new REnemyWeaknesses();
94 |
95 | // Independent
96 | randomTilemap = new RTilemap();
97 |
98 |
99 | ///==========================
100 | /// "COSMETIC SEED" MODULES
101 | ///==========================
102 | // Caution: Depends on RBossRoom, but can use default values if its not enabled.
103 | rWeaponNames = new RText();
104 |
105 | // Independent
106 | randomColors = new RColors();
107 |
108 | // Independent
109 | randomMusic = new RMusic();
110 |
111 |
112 |
113 |
114 |
115 | // Add randomizers according to each flag
116 | ///==========================
117 | /// "GAMEPLAY SEED" MODULES
118 | ///==========================
119 | if (Settings.Is8StagesRandom)
120 | {
121 | Randomizers.Add(randomStages);
122 | }
123 | if (Settings.IsWeaponsRandom)
124 | {
125 | Randomizers.Add(randomWeaponGet);
126 | }
127 | if (Settings.IsWeaponBehaviorRandom)
128 | {
129 | Randomizers.Add(randomWeaponBehavior);
130 | }
131 | if (Settings.IsWeaknessRandom)
132 | {
133 | Randomizers.Add(randomWeaknesses);
134 | }
135 | if (Settings.IsBossAIRandom)
136 | {
137 | Randomizers.Add(randomBossAI);
138 | }
139 | if (Settings.IsItemsRandom)
140 | {
141 | Randomizers.Add(randomItemGet);
142 | }
143 | if (Settings.IsTeleportersRandom)
144 | {
145 | Randomizers.Add(randomTeleporters);
146 | }
147 | if (Settings.IsEnemiesRandom)
148 | {
149 | Randomizers.Add(randomEnemies);
150 | }
151 | if (Settings.IsEnemyWeaknessRandom)
152 | {
153 | Randomizers.Add(randomEnemyWeakness);
154 | }
155 | if (Settings.IsBossInBossRoomRandom)
156 | {
157 | Randomizers.Add(randomBossInBossRoom);
158 | }
159 | if (Settings.IsTilemapChangesEnabled)
160 | {
161 | Randomizers.Add(randomTilemap);
162 | }
163 |
164 | ///==========================
165 | /// "COSMETIC SEED" MODULES
166 | ///==========================
167 | if (Settings.IsColorsRandom)
168 | {
169 | CosmeticRandomizers.Add(randomColors);
170 | }
171 | if (Settings.IsBGMRandom)
172 | {
173 | CosmeticRandomizers.Add(randomMusic);
174 | }
175 | if (Settings.IsWeaponNamesRandom)
176 | {
177 | CosmeticRandomizers.Add(rWeaponNames);
178 | }
179 |
180 |
181 | // Instantiate RNG object r based on RandomMM2.Seed
182 | InitializeSeed();
183 |
184 | // Create randomization patch
185 | Patch = new Patch();
186 |
187 | // In tournament mode, offset the seed by 1 call, making seeds mode-dependent
188 | if (Settings.IsSpoilerFree)
189 | {
190 | Random.Next();
191 | RNGCosmetic.Next();
192 | }
193 |
194 | // Conduct randomization of Gameplay Modules
195 | foreach (IRandomizer randomizer in Randomizers)
196 | {
197 | randomizer.Randomize(Patch, Random);
198 | Debug.WriteLine(randomizer);
199 | }
200 |
201 | // Conduct randomization of Cosmetic Modules
202 | foreach (IRandomizer cosmetic in CosmeticRandomizers)
203 | {
204 | cosmetic.Randomize(Patch, RNGCosmetic);
205 | Debug.WriteLine(cosmetic);
206 | }
207 |
208 | // Apply additional required incidental modifications
209 | if (Settings.Is8StagesRandom || Settings.IsWeaponsRandom)
210 | {
211 | MiscHacks.FixPortraits(Patch, Settings.Is8StagesRandom, randomStages, Settings.IsWeaponsRandom, randomWeaponGet);
212 | MiscHacks.FixWeaponLetters(Patch, randomWeaponGet, randomStages, rWeaponNames);
213 | }
214 | if (Settings.IsEnemiesRandom)
215 | {
216 | MiscHacks.FixM445PaletteGlitch(Patch);
217 | }
218 |
219 | // Apply final optional gameplay modifications
220 | if (Settings.FastText)
221 | {
222 | MiscHacks.SetFastWeaponGetText(Patch);
223 | MiscHacks.SetFastReadyText(Patch);
224 | MiscHacks.SetFastWilyMap(Patch);
225 | MiscHacks.SkipItemGetPages(Patch);
226 | }
227 | if (Settings.BurstChaserMode)
228 | {
229 | MiscHacks.SetBurstChaser(Patch);
230 | }
231 | MiscHacks.DrawTitleScreenChanges(Patch, Seed, Settings);
232 | MiscHacks.SetWily5NoMusicChange(Patch);
233 | MiscHacks.NerfDamageValues(Patch);
234 | MiscHacks.SetETankKeep(Patch);
235 | MiscHacks.PreventETankUseAtFullLife(Patch);
236 | MiscHacks.SetFastBossDefeatTeleport(Patch);
237 |
238 | // Create file name based on seed and game region
239 | string seedAlpha = SeedConvert.ConvertBase10To26(Seed);
240 | string newfilename = $"MM2-RNG-{seedAlpha}.nes";
241 |
242 | // Apply patch and deliver the ROM; different routine for client vs. web app
243 | if (fromClientApp)
244 | {
245 | //File.Copy(Settings.SourcePath, TempFileName, true);
246 | //using (Stream stream = assembly.GetManifestResourceStream("MM2Randomizer.Resources.MM2.nes"))
247 | // Load user provided ROM
248 | using (Stream stream = new FileStream(Settings.SourcePath, FileMode.Open, FileAccess.Read))
249 | {
250 | using (Stream output = File.OpenWrite(TempFileName))
251 | {
252 | stream.CopyTo(output);
253 | }
254 | }
255 |
256 | // Apply pre-patch changes via IPS patch (manual title screen, stage select, stage changes, player sprite)
257 | Patch.ApplyIPSPatch(TempFileName, Properties.Resources.mm2rng_musicpatch);
258 | Patch.ApplyIPSPatch(TempFileName, Properties.Resources.mm2rng_prepatch);
259 | MiscHacks.SetNewMegaManSprite(Patch, TempFileName, Settings.SelectedPlayer);
260 |
261 | // Apply patch with randomized content
262 | Patch.ApplyRandoPatch(TempFileName);
263 |
264 | // If a file of the same seed already exists, delete it
265 | if (File.Exists(newfilename))
266 | {
267 | File.Delete(newfilename);
268 | }
269 |
270 | // Finish the copy/rename and open Explorer at that location
271 | File.Move(TempFileName, newfilename);
272 | RecentlyCreatedFileName = newfilename;
273 | Settings.HashValidationMessage = "Successfully copied and patched! File: " + newfilename;
274 | return newfilename;
275 | }
276 | else
277 | {
278 | //File.Copy(Settings.SourcePath, TempFileName, true);
279 | string serverDir = $@"C:\mm2rng\{seedAlpha}";
280 | Directory.CreateDirectory(serverDir);
281 |
282 | string serverPathTemp = Path.Combine(serverDir, TempFileName);
283 | string serverPathNew = Path.Combine(serverDir, newfilename);
284 | using (Stream stream = new FileStream("MM2.nes", FileMode.Open))
285 | {
286 | using (Stream output = File.OpenWrite(serverPathTemp))
287 | {
288 | stream.CopyTo(output);
289 | }
290 | }
291 |
292 | // Apply pre-patch changes via IPS patch (manual title screen, stage select, and stage changes)
293 | Patch.ApplyIPSPatch(serverPathTemp, Properties.Resources.mm2rng_musicpatch);
294 | Patch.ApplyIPSPatch(serverPathTemp, Properties.Resources.mm2rng_prepatch);
295 |
296 | // Apply patch with randomized content
297 | Patch.ApplyRandoPatch(serverPathTemp);
298 |
299 | // If a file of the same seed already exists, delete it
300 | if (File.Exists(serverPathNew))
301 | {
302 | File.Delete(serverPathNew);
303 | }
304 |
305 | // Finish the copy/rename and open Explorer at that location
306 | File.Move(serverPathTemp, serverPathNew);
307 | RecentlyCreatedFileName = serverPathNew;
308 | return serverPathNew;
309 | }
310 | }
311 |
312 | ///
313 | /// Create a random seed or use the user-provided seed.
314 | ///
315 | private static void InitializeSeed()
316 | {
317 | if (Seed < 0)
318 | {
319 | Random rndSeed = new Random();
320 | Seed = rndSeed.Next(int.MaxValue);
321 | }
322 | Random = new Random(Seed);
323 | RNGCosmetic = new Random(Seed);
324 | }
325 |
326 | ///
327 | /// Shuffle the elements of the provided list.
328 | ///
329 | /// The Type of the elements in the list.
330 | /// The object to be shuffled.
331 | /// The seed used to perform the shuffling.
332 | /// A reference to the shuffled list.
333 | public static IList Shuffle(this IList list, Random rng)
334 | {
335 | int n = list.Count;
336 | while (n > 1)
337 | {
338 | n--;
339 | int k = rng.Next(n + 1);
340 | T value = list[k];
341 | list[k] = list[n];
342 | list[n] = value;
343 | }
344 | return list;
345 | }
346 | }
347 | }
348 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/Colors/ColorSet.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using MM2Randomizer.Enums;
5 | using MM2Randomizer.Patcher;
6 |
7 | namespace MM2Randomizer.Randomizers.Colors
8 | {
9 | public class ColorSet
10 | {
11 | public int[] addresses;
12 | public List ColorBytes;
13 | public int Index;
14 |
15 | public ColorSet()
16 | {
17 | ColorBytes = new List();
18 | Index = 0;
19 | }
20 |
21 | public void RandomizeAndWrite(Patch patch, Random rand, int setNumber)
22 | {
23 | Index = rand.Next(ColorBytes.Count);
24 |
25 | for (int i = 0; i < addresses.Length; i++)
26 | {
27 | patch.Add(addresses[i], (byte)ColorBytes[Index][i], String.Format("Color Set {0} (Index Chosen: {1}) Value #{2}", setNumber, Index, i));
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/Enemies/EnemyInstance.cs:
--------------------------------------------------------------------------------
1 | using MM2Randomizer.Enums;
2 |
3 | namespace MM2Randomizer.Randomizers.Enemies
4 | {
5 | public class EnemyInstance
6 | {
7 | public bool HasIDChanged
8 | {
9 | get { return EnemyID != EnemyIDPrev; }
10 | }
11 |
12 | public int Offset { get; set; }
13 | public int StageNum { get; set; }
14 | public int RoomNum { get; set; }
15 | public int ScreenNum { get; set; }
16 | public bool IsActive { get; set; }
17 | public int EnemyID { get; set; }
18 | public int EnemyIDPrev { get; set; } // for reference only
19 | public int X { get; set; }
20 | public int YOriginal { get; set; } // for reference only
21 | public int YAir { get; set; }
22 | public int YGround { get; set; }
23 | public bool IsFaceRight { get; set; }
24 |
25 | //public bool IsRandomiziable { get; set; }
26 | //public List PatternTableAddresses { get; set; }
27 | //public List SpriteBankRows { get; set; }
28 |
29 | public EnemyInstance(int offset, int stage, int room, int screen, bool isActive, int id, int xOriginal, int yOriginal, int yAir, int yGround, bool faceRight)
30 | {
31 | Offset = offset;
32 | StageNum = stage;
33 | RoomNum = room;
34 | ScreenNum = screen;
35 | IsActive = isActive;
36 | EnemyID = id;
37 | EnemyIDPrev = id;
38 | X = xOriginal;
39 | YOriginal = yOriginal;
40 | YAir = yAir;
41 | YGround = yGround;
42 | IsFaceRight = faceRight;
43 | }
44 |
45 | public bool HasNewActivator()
46 | {
47 | if (!HasIDChanged) return false;
48 |
49 | switch ((EEnemyID)EnemyID)
50 | {
51 | case EEnemyID.Pipi_Activator:
52 | return true;
53 | case EEnemyID.Mole_Activator:
54 | return true;
55 | case EEnemyID.Claw_Activator:
56 | return true;
57 | case EEnemyID.Kukku_Activator:
58 | return true;
59 | case EEnemyID.M445_Activator:
60 | return true;
61 | default: return false;
62 | }
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/Enemies/EnemyType.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | using MM2Randomizer.Enums;
4 |
5 | namespace MM2Randomizer.Randomizers.Enemies
6 | {
7 | public class EnemyType
8 | {
9 | public EEnemyID ID { get; set; }
10 | public List PatternTableAddresses { get; set; }
11 | public List SpriteBankRows { get; set; }
12 | public bool IsYPosAir { get; set; }
13 | public bool IsActivator { get; set; }
14 |
15 | ///
16 | /// Helps determine y-position adjustment for spawning. If height = 0, it can spawn at the top
17 | /// of the screen (pipis, deactivators, etc.)
18 | ///
19 | public int YAdjust { get; set; }
20 |
21 | public EnemyType(EEnemyID id, List patternTableAddresses, List spriteBankRows, bool isActivator, bool isYPosAir = false, int yAdjust = 0)
22 | {
23 | ID = id;
24 | PatternTableAddresses = patternTableAddresses;
25 | SpriteBankRows = spriteBankRows;
26 | IsActivator = isActivator;
27 | IsYPosAir = isYPosAir;
28 | YAdjust = yAdjust;
29 | }
30 |
31 | public static EEnemyID GetCorrespondingDeactivator(EEnemyID activator)
32 | {
33 | switch (activator)
34 | {
35 | case EEnemyID.Pipi_Activator:
36 | return EEnemyID.Pipi_Deactivator;
37 | case EEnemyID.Mole_Activator:
38 | return EEnemyID.Mole_Deactivator;
39 | case EEnemyID.Claw_Activator:
40 | return EEnemyID.Claw_Deactivator;
41 | case EEnemyID.Kukku_Activator:
42 | return EEnemyID.Kukku_Deactivator;
43 | case EEnemyID.M445_Activator:
44 | return EEnemyID.M445_Deactivator;
45 | default: return activator;
46 | }
47 | }
48 |
49 | public static EEnemyID GetCorrespondingDeactivator(int deactivatorID)
50 | {
51 | return GetCorrespondingDeactivator((EEnemyID)deactivatorID);
52 | }
53 |
54 | public static bool CheckIsActivator(int enemyID)
55 | {
56 | switch ((EEnemyID)enemyID)
57 | {
58 | case EEnemyID.Pipi_Activator:
59 | return true;
60 | case EEnemyID.Mole_Activator:
61 | return true;
62 | case EEnemyID.Claw_Activator:
63 | return true;
64 | case EEnemyID.Kukku_Activator:
65 | return true;
66 | case EEnemyID.M445_Activator:
67 | return true;
68 | default: return false;
69 | }
70 | }
71 |
72 | public static bool CheckIsDeactivator(int enemyID)
73 | {
74 | switch ((EEnemyID)enemyID)
75 | {
76 | case EEnemyID.Pipi_Deactivator:
77 | return true;
78 | case EEnemyID.Mole_Deactivator:
79 | return true;
80 | case EEnemyID.Claw_Deactivator:
81 | return true;
82 | case EEnemyID.Kukku_Deactivator:
83 | return true;
84 | case EEnemyID.M445_Deactivator:
85 | return true;
86 | default: return false;
87 | }
88 | }
89 |
90 |
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/Enemies/REnemyWeaknesses.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using MM2Randomizer.Patcher;
6 |
7 | namespace MM2Randomizer.Randomizers.Enemies
8 | {
9 | public class REnemyWeaknesses : IRandomizer
10 | {
11 | private readonly static int EnemyDamageAddressP = 0x03E9A8;
12 | private readonly static int EnemyDamageAddressH = 0x03EA24;
13 | private readonly static int EnemyDamageAddressA = 0x03EA9C;
14 | private readonly static int EnemyDamageAddressW = 0x03EB14;
15 | private readonly static int EnemyDamageAddressB = 0x03EB8C;
16 | private readonly static int EnemyDamageAddressQ = 0x03EC04;
17 | private readonly static int EnemyDamageAddressC = 0x03EC7C;
18 | private readonly static int EnemyDamageAddressM = 0x03ECF4;
19 |
20 | // NOTE: Will have to change these indices if enemies are added/removed from enemyweaknesses.csv!
21 | private readonly static int EnemyIndexInShotArray_Friender = 8;
22 |
23 | private StringBuilder debug = new StringBuilder();
24 | private List enemyNames = new List();
25 | private List offsets = new List();
26 | private List shotP = new List();
27 | private List shotH = new List();
28 | private List shotA = new List();
29 | private List shotW = new List();
30 | private List shotB = new List();
31 | private List shotQ = new List();
32 | private List shotC = new List();
33 | private List shotM = new List();
34 |
35 | public REnemyWeaknesses() { }
36 |
37 | public override string ToString()
38 | {
39 | return debug.ToString();
40 | }
41 |
42 | public void Randomize(Patch p, Random r)
43 | {
44 | string[] lines = Properties.Resources.enemyweakness.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
45 | foreach (string line in lines)
46 | {
47 | if (line.StartsWith("#")) continue; // Ignore comment lines
48 |
49 | string[] cols = line.Split(new char[] { ',' });
50 |
51 | enemyNames.Add(cols[0]); // Enemy name
52 | offsets.Add(Convert.ToInt32(cols[1], 16)); // Offset
53 | shotP.Add(byte.Parse(cols[2])); // Buster
54 | shotH.Add(byte.Parse(cols[3])); // Heat
55 | shotA.Add(byte.Parse(cols[4])); // Air
56 | shotW.Add(byte.Parse(cols[5])); // Wood
57 | shotB.Add(byte.Parse(cols[6])); // Bubble
58 | shotQ.Add(byte.Parse(cols[7])); // Quick
59 | shotC.Add(byte.Parse(cols[8])); // Clash
60 | shotM.Add(byte.Parse(cols[9])); // Metal
61 | }
62 |
63 | shotP.Shuffle(r);
64 | shotH.Shuffle(r);
65 | shotA.Shuffle(r);
66 | shotW.Shuffle(r);
67 | shotB.Shuffle(r);
68 | shotQ.Shuffle(r);
69 | shotC.Shuffle(r);
70 | shotM.Shuffle(r);
71 |
72 | // Force Buster to always do 1 damage to minibosses
73 | shotP[EnemyIndexInShotArray_Friender] = 0x01;
74 |
75 | // To each enemy...
76 | for (int i = 0; i < offsets.Count; i++)
77 | {
78 | // ...apply each weapon's damage
79 | p.Add(EnemyDamageAddressP + offsets[i], shotP[i], $"{enemyNames[i]} damage from P");
80 | p.Add(EnemyDamageAddressH + offsets[i], shotH[i], $"{enemyNames[i]} damage from H");
81 | p.Add(EnemyDamageAddressA + offsets[i], shotA[i], $"{enemyNames[i]} damage from A");
82 | p.Add(EnemyDamageAddressW + offsets[i], shotW[i], $"{enemyNames[i]} damage from W");
83 | p.Add(EnemyDamageAddressB + offsets[i], shotB[i], $"{enemyNames[i]} damage from B");
84 | p.Add(EnemyDamageAddressQ + offsets[i], shotQ[i], $"{enemyNames[i]} damage from Q");
85 | p.Add(EnemyDamageAddressC + offsets[i], shotC[i], $"{enemyNames[i]} damage from C");
86 | p.Add(EnemyDamageAddressM + offsets[i], shotM[i], $"{enemyNames[i]} damage from M");
87 |
88 | // Furthermore, there are 3 enemy types that need a second array of damage values
89 | // - Shrink (instance vs. spawner)
90 | // - Mole (moving up vs. moving down)
91 | // - Shotman (facing left vs. facing right)
92 | // The corresponding auxiliary types are omitted from the shuffle.
93 | // Instead, assign common weaknesses for a more consistent playing experience.
94 | // Each auxiliary type occurs at the next offset, offsets[i] + 1
95 |
96 | // Shrink 0x00 apply same damage to Shrink Spawner 0x01
97 | // Mole (Up) 0x48 apply same damage to Mole (Down) 0x49
98 | // Shotman (Left) 0x4B apply same damage to Shotman (Right) 0x4C
99 | if (offsets[i] == 0x00 || offsets[i] == 0x48 || offsets[i] == 0x4B)
100 | {
101 | p.Add(EnemyDamageAddressP + offsets[i] + 1, shotP[i], $"{enemyNames[i]} damage from P");
102 | p.Add(EnemyDamageAddressH + offsets[i] + 1, shotH[i], $"{enemyNames[i]} damage from H");
103 | p.Add(EnemyDamageAddressA + offsets[i] + 1, shotA[i], $"{enemyNames[i]} damage from A");
104 | p.Add(EnemyDamageAddressW + offsets[i] + 1, shotW[i], $"{enemyNames[i]} damage from W");
105 | p.Add(EnemyDamageAddressB + offsets[i] + 1, shotB[i], $"{enemyNames[i]} damage from B");
106 | p.Add(EnemyDamageAddressQ + offsets[i] + 1, shotQ[i], $"{enemyNames[i]} damage from Q");
107 | p.Add(EnemyDamageAddressC + offsets[i] + 1, shotC[i], $"{enemyNames[i]} damage from C");
108 | p.Add(EnemyDamageAddressM + offsets[i] + 1, shotM[i], $"{enemyNames[i]} damage from M");
109 | }
110 | }
111 |
112 | // Format nice debug table
113 | debug.AppendLine("Enemy Weaknesses:");
114 | debug.AppendLine("\t\t\t\t\t\tP\tH\tA\tW\tB\tQ\tM\tC:");
115 | debug.AppendLine("--------------------------------------------------------");
116 | for (int i = 0; i < offsets.Count; i++)
117 | {
118 | debug.AppendLine($"{enemyNames[i]}\t{shotP[i]}\t{shotH[i]}\t{shotA[i]}\t{shotW[i]}\t{shotB[i]}\t{shotQ[i]}\t{shotC[i]}\t{shotM[i]}");
119 | }
120 | debug.Append(Environment.NewLine);
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/Enemies/Room.cs:
--------------------------------------------------------------------------------
1 | using MM2Randomizer.Enums;
2 | using System.Collections.Generic;
3 |
4 | namespace MM2Randomizer.Randomizers.Enemies
5 | {
6 | public class Room
7 | {
8 | public List EnemyInstances { get; set; }
9 | public int RoomNum { get; set; }
10 |
11 | public Room(int roomNum)
12 | {
13 | RoomNum = roomNum;
14 | EnemyInstances = new List();
15 | }
16 |
17 | public EEnemyID? GetActivatorIfOneHasBeenAdded()
18 | {
19 | foreach (EnemyInstance enemy in EnemyInstances)
20 | {
21 | // This instance hasn't been replaced; keep old activator type if one is there
22 | if (!enemy.HasIDChanged) continue;
23 |
24 | EEnemyID id = (EEnemyID)enemy.EnemyID;
25 | if (id == EEnemyID.Pipi_Activator ||
26 | id == EEnemyID.Mole_Activator ||
27 | id == EEnemyID.Claw_Activator ||
28 | id == EEnemyID.M445_Activator ||
29 | id == EEnemyID.Kukku_Activator)
30 | {
31 | return id;
32 | }
33 | }
34 | return null;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/Enemies/SpriteBankRoomGroup.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | using MM2Randomizer.Enums;
4 |
5 | namespace MM2Randomizer.Randomizers.Enemies
6 | {
7 | public class SpriteBankRoomGroup
8 | {
9 | public EStageID Stage { get; set; }
10 |
11 | ///
12 | /// Room numbers in the stage that this sprite bank applies to. Will always be sorted from least to greatest.
13 | ///
14 | public List Rooms { get; set; }
15 | public int PatternAddressStart { get; set; }
16 | public List NewEnemyTypes { get; set; }
17 |
18 | public bool IsSpriteRestricted { get; set; }
19 | public List SpriteBankRowsRestriction { get; set; }
20 | public List PatternTableAddressesRestriction { get; set; }
21 |
22 | public SpriteBankRoomGroup (EStageID stage, int patternAddressStart, int[] roomNums)
23 | {
24 | this.Stage = stage;
25 | this.PatternAddressStart = patternAddressStart;
26 |
27 | Rooms = new List();
28 | for (int i = 0; i < roomNums.Length; i++)
29 | {
30 | Rooms.Add(new Room(roomNums[i]));
31 | }
32 |
33 | //EnemyInstances = new List();
34 | NewEnemyTypes = new List();
35 | IsSpriteRestricted = false;
36 | }
37 |
38 | public SpriteBankRoomGroup (EStageID stage, int patternAddressStart, int[] roomNums, int[] spriteBankRowsRestriction, byte[] patternTableAddressesRestriction/*, params EnemyInstance[] enemyInstances*/)
39 | : this(stage, patternAddressStart, roomNums)
40 | {
41 | SpriteBankRowsRestriction = new List(spriteBankRowsRestriction);
42 | PatternTableAddressesRestriction = new List(patternTableAddressesRestriction);
43 | IsSpriteRestricted = true;
44 | }
45 |
46 | public bool ContainsRoom(int roomNum)
47 | {
48 | foreach (Room room in Rooms)
49 | {
50 | if (room.RoomNum == roomNum)
51 | {
52 | return true;
53 | }
54 | }
55 | return false;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/IRandomizer.cs:
--------------------------------------------------------------------------------
1 | using MM2Randomizer.Patcher;
2 | using System;
3 |
4 | namespace MM2Randomizer.Randomizers
5 | {
6 | public interface IRandomizer
7 | {
8 | void Randomize(Patch p, Random r);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/RBossRoom.cs:
--------------------------------------------------------------------------------
1 | using MM2Randomizer.Enums;
2 | using MM2Randomizer.Patcher;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 |
8 | namespace MM2Randomizer.Randomizers
9 | {
10 | public class RBossRoom : IRandomizer
11 | {
12 | public class BossRoomRandomComponent
13 | {
14 | // This seems to be every table necessary to shuffle for getting a boss
15 | // to function and display properly in a different boss room.
16 | public byte IntroValue { get; set; } // 0F 0F 0B 05 09 07 05 03
17 | public byte AIPtrByte1 { get; set; } // C5 E3 FB 56 9E 56 20 C3
18 | public byte AIPtrByte2 { get; set; } // 80 82 84 86 87 89 8B 8C
19 | public byte GfxFix1 { get; set; } // 50 66 6C 60 54 5A 63 69
20 | public byte GfxFix2 { get; set; } // 51 67 6D 61 55 5C 64 6A
21 | public byte YPosFix1 { get; set; } // 09 0C 0F 0A 09 09 08 08
22 | public byte YPosFix2 { get; set; } // 0C 10 10 0C 0C 0C 0C 0C
23 | public byte[] SpriteBankSlotRowsBytes { get; set; }
24 | public int OriginalBossIndex { get; set; }
25 | // ...and maybe room layout???
26 |
27 | public BossRoomRandomComponent(int original, byte introValue, byte aiPtr1, byte aiPtr2, byte gfxfix1, byte gfxfix2, byte yFix1, byte yFix2, byte[] spriteBankSlotRows)
28 | {
29 | this.IntroValue = introValue;
30 | this.AIPtrByte1 = aiPtr1;
31 | this.AIPtrByte2 = aiPtr2;
32 | this.GfxFix1 = gfxfix1;
33 | this.GfxFix2 = gfxfix2;
34 | this.YPosFix1 = yFix1;
35 | this.YPosFix2 = yFix2;
36 | this.SpriteBankSlotRowsBytes = spriteBankSlotRows;
37 | this.OriginalBossIndex = original;
38 | }
39 | }
40 |
41 | public RBossRoom()
42 | {
43 | // Initialize BossRoomRandomComponents, and add to "Components" list.
44 | // This list is still needed even if this module isn't enabled; it just won't get shuffled.
45 | BossRoomRandomComponent HeatManComponent = new BossRoomRandomComponent(
46 | original: 0,
47 | introValue: 0x0F, // 0x02C15E
48 | aiPtr1: 0xC5, // 0x02C057
49 | aiPtr2: 0x80, // 0x02C065
50 | gfxfix1: 0x50, // 0x02E4E9
51 | gfxfix2: 0x51, // 0x02C166
52 | yFix1: 0x09, // 0x02C14E
53 | yFix2: 0x0C, // 0x02C156
54 | spriteBankSlotRows: new byte[] {
55 | 0x98, 0x06,
56 | 0x99, 0x06,
57 | 0x9A, 0x06,
58 | 0x9B, 0x06,
59 | 0x9C, 0x06,
60 | 0x9D, 0x06,
61 | });
62 |
63 | BossRoomRandomComponent AirManComponent = new BossRoomRandomComponent(
64 | original: 1,
65 | introValue: 0x0F,
66 | aiPtr1: 0xE3,
67 | aiPtr2: 0x82,
68 | gfxfix1: 0x66,
69 | gfxfix2: 0x67,
70 | yFix1: 0x0C,
71 | yFix2: 0x10,
72 | spriteBankSlotRows: new byte[] {
73 | 0xAB, 0x05,
74 | 0xAC, 0x05,
75 | 0xAD, 0x05,
76 | 0xAA, 0x06,
77 | 0xAB, 0x06,
78 | 0xAC, 0x06,
79 | });
80 |
81 | BossRoomRandomComponent WoodManComponent = new BossRoomRandomComponent(
82 | original: 2,
83 | introValue: 0x0B,
84 | aiPtr1: 0xFB,
85 | aiPtr2: 0x84,
86 | gfxfix1: 0x6C,
87 | gfxfix2: 0x6D,
88 | yFix1: 0x0F,
89 | yFix2: 0x10,
90 | spriteBankSlotRows: new byte[] {
91 | 0xAC, 0x06,
92 | 0xAD, 0x06,
93 | 0xAE, 0x06,
94 | 0xAF, 0x06,
95 | 0xB0, 0x06,
96 | 0xB1, 0x06,
97 | });
98 |
99 | BossRoomRandomComponent BubbleManComponent = new BossRoomRandomComponent(
100 | original: 3,
101 | introValue: 0x05,
102 | aiPtr1: 0x56,
103 | aiPtr2: 0x86,
104 | gfxfix1: 0x60,
105 | gfxfix2: 0x61,
106 | yFix1: 0x0A,
107 | yFix2: 0x0C,
108 | spriteBankSlotRows: new byte[] {
109 | 0x98, 0x07,
110 | 0x99, 0x07,
111 | 0x9A, 0x07,
112 | 0x9B, 0x07,
113 | 0x9C, 0x07,
114 | 0x9D, 0x07,
115 | });
116 |
117 | BossRoomRandomComponent QuickManComponent = new BossRoomRandomComponent(
118 | original: 4,
119 | introValue: 0x09,
120 | aiPtr1: 0x9E,
121 | aiPtr2: 0x87,
122 | gfxfix1: 0x54,
123 | gfxfix2: 0x55,
124 | yFix1: 0x09,
125 | yFix2: 0x0C,
126 | spriteBankSlotRows: new byte[] {
127 | 0x90, 0x07,
128 | 0x91, 0x07,
129 | 0x92, 0x07,
130 | 0x93, 0x07,
131 | 0x94, 0x07,
132 | 0x95, 0x07,
133 | });
134 |
135 | BossRoomRandomComponent FlashManComponent = new BossRoomRandomComponent(
136 | original: 5,
137 | introValue: 0x07,
138 | aiPtr1: 0x56,
139 | aiPtr2: 0x89,
140 | gfxfix1: 0x5A,
141 | gfxfix2: 0x5C,
142 | yFix1: 0x09,
143 | yFix2: 0x0C,
144 | spriteBankSlotRows: new byte[] {
145 | 0x9E, 0x06,
146 | 0x9F, 0x06,
147 | 0x96, 0x07,
148 | 0x97, 0x07,
149 | 0x9E, 0x07,
150 | 0x9F, 0x07,
151 | });
152 |
153 | BossRoomRandomComponent MetalManComponent = new BossRoomRandomComponent(
154 | original: 6,
155 | introValue: 0x05,
156 | aiPtr1: 0x20,
157 | aiPtr2: 0x8B,
158 | gfxfix1: 0x63,
159 | gfxfix2: 0x64,
160 | yFix1: 0x08,
161 | yFix2: 0x0C,
162 | spriteBankSlotRows: new byte[] {
163 | 0xB0, 0x03,
164 | 0xB1, 0x03,
165 | 0xB2, 0x03,
166 | 0xB3, 0x03,
167 | 0xAA, 0x05,
168 | 0xAB, 0x05,
169 | });
170 |
171 | BossRoomRandomComponent ClashManComponent = new BossRoomRandomComponent(
172 | original: 7,
173 | introValue: 0x03,
174 | aiPtr1: 0xC3,
175 | aiPtr2: 0x8C,
176 | gfxfix1: 0x69,
177 | gfxfix2: 0x6A,
178 | yFix1: 0x08,
179 | yFix2: 0x0C,
180 | spriteBankSlotRows: new byte[] {
181 | 0xAE, 0x05,
182 | 0xAF, 0x05,
183 | 0xB0, 0x05,
184 | 0xB1, 0x05,
185 | 0xB2, 0x05,
186 | 0xB3, 0x05,
187 | }
188 | );
189 |
190 | Components = new List
191 | {
192 | HeatManComponent,
193 | AirManComponent,
194 | WoodManComponent,
195 | BubbleManComponent,
196 | QuickManComponent,
197 | FlashManComponent,
198 | MetalManComponent,
199 | ClashManComponent,
200 | };
201 | }
202 |
203 | public List Components { get; set; }
204 |
205 | ///
206 | /// Shuffle which Robot Master awards which weapon.
207 | ///
208 | public void Randomize(Patch Patch, Random r)
209 | {
210 | Components.Shuffle(r);
211 | //DEBUG test a boss in a particular boss room, also comment out the corresponding boss from the Components list above
212 | //Components.Insert(3, BubbleManComponent);
213 |
214 | // Write in new boss positions
215 | for (int i = 0; i < 8; i++)
216 | {
217 | var bossroom = Components[i];
218 | Patch.Add(0x02C15E + i, bossroom.IntroValue, $"Boss Intro Value for Boss Room {i}");
219 | Patch.Add(0x02C057 + i, bossroom.AIPtrByte1, $"Boss AI Ptr Byte1 for Boss Room {i}");
220 | Patch.Add(0x02C065 + i, bossroom.AIPtrByte2, $"Boss AI Ptr Byte2 for Boss Room {i}");
221 | Patch.Add(0x02E4E9 + i, bossroom.GfxFix1, $"Boss GFX Fix 1 for Boss Room {i}");
222 | Patch.Add(0x02C166 + i, bossroom.GfxFix1, $"Boss GFX Fix 2 for Boss Room {i}");
223 | Patch.Add(0x02C14E + i, bossroom.YPosFix1, $"Boss Y-Pos Fix1 for Boss Room {i}");
224 | Patch.Add(0x02C156 + i, bossroom.YPosFix2, $"Boss Y-Pos Fix2 for Boss Room {i}");
225 | }
226 |
227 | // Adjust sprite banks for each boss room
228 | int[] spriteBankBossRoomAddresses = new int[]
229 | {
230 | 0x0034A6, // Heat room
231 | 0x0074A6, // Air room
232 | 0x00B4DC, // Wood room
233 | 0x00F4A6, // Bubble room
234 | 0x0134B8, // Quick room
235 | 0x0174A6, // Flash room
236 | 0x01B494, // Metal room
237 | 0x01F4DC, // Clash room
238 | };
239 | for (int i = 0; i < spriteBankBossRoomAddresses.Length; i++)
240 | {
241 | for (int j = 0; j < Components[i].SpriteBankSlotRowsBytes.Length; j++)
242 | {
243 | Patch.Add(spriteBankBossRoomAddresses[i] + j,
244 | Components[i].SpriteBankSlotRowsBytes[j],
245 | $"Boss Room {i} Sprite Bank Swap {j}");
246 | }
247 | }
248 |
249 | // Undo shuffling of damage values for each boss room
250 | int contactDmgTbl = 0x2E9C2;
251 | byte[] originalDmgVals = new byte[] { 08,08,08,04,04,04,06,04 };
252 | byte[] newDmgVals = new byte[8];
253 | for (int i = 0; i < Components.Count; i++)
254 | {
255 | newDmgVals[i] = originalDmgVals[Components[i].OriginalBossIndex];
256 | Patch.Add(contactDmgTbl + i, newDmgVals[i]);
257 | }
258 | }
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/RItemGet.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using MM2Randomizer.Patcher;
5 | using MM2Randomizer.Enums;
6 |
7 | namespace MM2Randomizer.Randomizers
8 | {
9 | public class RItemGet : IRandomizer
10 | {
11 | public RItemGet() { }
12 |
13 | ///
14 | /// Shuffle which Robot Master awards Items 1, 2, and 3.
15 | ///
16 | public void Randomize(Patch patch, Random r)
17 | {
18 | // 0x03C291 - Item # from Heat Man
19 | // 0x03C292 - Item # from Air Man
20 | // 0x03C293 - Item # from Wood Man
21 | // 0x03C294 - Item # from Bubble Man
22 | // 0x03C295 - Item # from Quick Man
23 | // 0x03C296 - Item # from Flash Man
24 | // 0x03C297 - Item # from Metal Man
25 | // 0x03C298 - Item # from Crash Man
26 |
27 | List newItemOrder = new List();
28 | for (byte i = 0; i < 5; i++) newItemOrder.Add(EItemNumber.None);
29 | newItemOrder.Add(EItemNumber.One);
30 | newItemOrder.Add(EItemNumber.Two);
31 | newItemOrder.Add(EItemNumber.Three);
32 | newItemOrder.Shuffle(r);
33 |
34 | for (int i = 0; i < 8; i++)
35 | {
36 | patch.Add((int)EItemStageAddress.HeatMan + i, (byte)newItemOrder[i], String.Format("{0}man Item Get", ((EDmgVsBoss.Offset)i).ToString()));
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/RTeleporters.cs:
--------------------------------------------------------------------------------
1 | using MM2Randomizer.Enums;
2 | using MM2Randomizer.Patcher;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace MM2Randomizer.Randomizers
7 | {
8 | public class RTeleporters : IRandomizer
9 | {
10 | public RTeleporters() { }
11 |
12 | public void Randomize(Patch patch, Random r)
13 | {
14 | // Create list of default teleporter position values
15 | List coords = new List
16 | {
17 | new byte[]{ 0x20, 0x3B }, // Teleporter X, Y (top-left)
18 | new byte[]{ 0x20, 0x7B },
19 | new byte[]{ 0x20, 0xBB },
20 | new byte[]{ 0x70, 0xBB },
21 | new byte[]{ 0x90, 0xBB },
22 | new byte[]{ 0xE0, 0x3B },
23 | new byte[]{ 0xE0, 0x7B },
24 | new byte[]{ 0xE0, 0xBB }
25 | };
26 |
27 | // Randomize them
28 | coords.Shuffle(r);
29 |
30 | // Write the new x-coordinates
31 | for (int i = 0; i < coords.Count; i++)
32 | {
33 | byte[] location = coords[i];
34 | patch.Add((int)(EMiscAddresses.WarpXCoordinateStartAddress + i), location[0], String.Format("Teleporter {0} X-Pos", i));
35 | }
36 |
37 | // Write the new y-coordinates
38 | for (int i = 0; i < coords.Count; i++)
39 | {
40 | byte[] location = coords[i];
41 | patch.Add((int)(EMiscAddresses.WarpYCoordinateStartAddress + i), location[1], String.Format("Teleporter {0} Y-Pos", i));
42 | }
43 |
44 | // These values will be copied over to $04b0 (y) and $0470 (x), which will be checked
45 | // for in real time to determine where Mega will teleport to
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/RTilemap.cs:
--------------------------------------------------------------------------------
1 | using MM2Randomizer.Patcher;
2 | using MM2Randomizer.Randomizers.Stages.Components;
3 | using Newtonsoft.Json;
4 | using System;
5 |
6 | namespace MM2Randomizer.Randomizers
7 | {
8 | public class RTilemap : IRandomizer
9 | {
10 | public RTilemap() { }
11 |
12 |
13 | public void Randomize(Patch p, Random r)
14 | {
15 | //ReadLevelComponentJSON(p, r);
16 |
17 | ChangeW4FloorsBeforeSpikes(p, r);
18 | ChangeW4FloorsSpikePit(p, r);
19 | }
20 |
21 | private void ReadLevelComponentJSON(Patch p, Random r)
22 | {
23 | ComponentManager component = JsonConvert.DeserializeObject(Properties.Resources.level_components);
24 |
25 | foreach (var levelComponent in component.LevelComponents)
26 | {
27 | // Get a random variation
28 | var variation = levelComponent.Variations[r.Next(levelComponent.Variations.Count)];
29 |
30 | // Add patch for each element of the tsamap
31 | int startAddress = Convert.ToInt32(levelComponent.StartAddress, 16);
32 | for (int i = 0; i < variation.TsaMap.Length; i++)
33 | {
34 | // Parse hex string
35 | byte tsaVal = Convert.ToByte(variation.TsaMap[i], 16);
36 |
37 | p.Add(startAddress + i, tsaVal, $"Tilemap data for {levelComponent.Name} variation \"{variation.Name}\"");
38 | }
39 | }
40 |
41 | Console.WriteLine(component.LevelComponents);
42 | }
43 |
44 | private static void ChangeW4FloorsBeforeSpikes(Patch Patch, Random r)
45 | {
46 | // Choose 2 of the 5 32x32 tiles to be fake
47 | int tileA = r.Next(5);
48 | int tileB = r.Next(4);
49 |
50 | // Make sure 2nd tile chosen is different
51 | if (tileB == tileA) tileB++;
52 |
53 | for (int i = 0; i < 5; i++)
54 | {
55 | if (i == tileA || i == tileB)
56 | {
57 | Patch.Add(0x00CB5C + i * 8, 0x94, String.Format("Wily 4 Room 4 Tile {0} (fake)", i));
58 | }
59 | else
60 | {
61 | Patch.Add(0x00CB5C + i * 8, 0x85, String.Format("Wily 4 Room 4 Tile {0} (solid)", i));
62 | }
63 | }
64 | }
65 |
66 | private static void ChangeW4FloorsSpikePit(Patch Patch, Random r)
67 | {
68 | // 5 tiles, but since two adjacent must construct a gap, 4 possible gaps. Choose 1 random gap.
69 | int gap = r.Next(4);
70 | for (int i = 0; i < 4; i++)
71 | {
72 | if (i == gap)
73 | {
74 | Patch.Add(0x00CB9A + i * 8, 0x9B, String.Format("Wily 4 Room 5 Tile {0} (gap on right)", i));
75 | Patch.Add(0x00CB9A + i * 8 + 8, 0x9C, String.Format("Wily 4 Room 5 Tile {0} (gap on left)", i));
76 | ++i; // skip next tile since we just drew it
77 | }
78 | else
79 | {
80 | Patch.Add(0x00CB9A + i * 8, 0x9D, String.Format("Wily 4 Room 5 Tile {0} (solid)", i));
81 | }
82 | }
83 | }
84 |
85 |
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/RWeaponGet.cs:
--------------------------------------------------------------------------------
1 | using MM2Randomizer.Enums;
2 | using MM2Randomizer.Patcher;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 |
7 | namespace MM2Randomizer.Randomizers
8 | {
9 | public class RWeaponGet : IRandomizer
10 | {
11 | private List NewWeaponOrder;
12 |
13 | public RWeaponGet()
14 | {
15 | NewWeaponOrder = new List()
16 | {
17 | ERMWeaponValueBit.HeatMan,
18 | ERMWeaponValueBit.AirMan,
19 | ERMWeaponValueBit.WoodMan,
20 | ERMWeaponValueBit.BubbleMan,
21 | ERMWeaponValueBit.QuickMan,
22 | ERMWeaponValueBit.FlashMan,
23 | ERMWeaponValueBit.MetalMan,
24 | ERMWeaponValueBit.CrashMan
25 | }.Select(s => s).ToList();
26 | }
27 |
28 | ///
29 | /// Shuffle which Robot Master awards which weapon.
30 | ///
31 | public void Randomize(Patch Patch, Random r)
32 | {
33 | // StageBeat Address Value
34 | // -----------------------------
35 | // Heat Man 0x03C289 1
36 | // Air Man 0x03C28A 2
37 | // Wood Man 0x03C28B 4
38 | // Bubble Man 0x03C28C 8
39 | // Quick Man 0x03C28D 16
40 | // Flash Man 0x03C28E 32
41 | // Metal Man 0x03C28F 64
42 | // Crash Man 0x03C290 128
43 | NewWeaponOrder.Shuffle(r);
44 |
45 | // Create table for which weapon is awarded by which robot master
46 | // This also affects which portrait is blacked out on the stage select
47 | // This also affects which teleporter deactivates after defeating a Wily 5 refight boss
48 | for (int i = 0; i < 8; i++)
49 | {
50 | Patch.Add((int)(ERMStageWeaponAddress.HeatMan + i), (byte)NewWeaponOrder[i], $"{(EDmgVsBoss.Offset)i} Weapon Get");
51 | }
52 |
53 | // Create a copy of the default weapon order table to be used by teleporter function
54 | // This is needed to fix teleporters breaking from the new weapon order.
55 | // Unused space at end of bank
56 | Patch.Add(0x03f310, (byte)ERMWeaponValueBit.HeatMan, "Custom Array of Default Weapon Order");
57 | Patch.Add(0x03f311, (byte)ERMWeaponValueBit.AirMan, "Custom Array of Default Weapon Order");
58 | Patch.Add(0x03f312, (byte)ERMWeaponValueBit.WoodMan, "Custom Array of Default Weapon Order");
59 | Patch.Add(0x03f313, (byte)ERMWeaponValueBit.BubbleMan, "Custom Array of Default Weapon Order");
60 | Patch.Add(0x03f314, (byte)ERMWeaponValueBit.QuickMan, "Custom Array of Default Weapon Order");
61 | Patch.Add(0x03f315, (byte)ERMWeaponValueBit.FlashMan, "Custom Array of Default Weapon Order");
62 | Patch.Add(0x03f316, (byte)ERMWeaponValueBit.MetalMan, "Custom Array of Default Weapon Order");
63 | Patch.Add(0x03f317, (byte)ERMWeaponValueBit.CrashMan, "Custom Array of Default Weapon Order");
64 |
65 | // Change function to call $f300 instead of $c279 when looking up defeated refight boss to
66 | // get our default weapon table, fixing the teleporter softlock
67 | Patch.Add(0x03843b, 0x00, "Teleporter Fix Custom Function Call Byte 1");
68 | Patch.Add(0x03843c, 0xf3, "Teleporter Fix Custom Function Call Byte 2");
69 |
70 | // Create table for which stage is selectable on the stage select screen (independent of it being blacked out)
71 | for (int i = 0; i < 8; i++)
72 | {
73 | Patch.Add((int)(ERMStageSelect.FirstStageInMemory + i), (byte)NewWeaponOrder[i], "Selectable Stage Fix for Random Weapon Get");
74 | }
75 | }
76 |
77 | public void FixPortraits(ref byte[] portraitBG_x, ref byte[] portraitBG_y)
78 | {
79 | // Since the acquired-weapons table's elements are powers of two, get a new array of their 0-7 index
80 | int[] newWeaponIndex = GetShuffleIndexPermutation();
81 |
82 | // Permute portrait x/y values via the shuffled acquired-weapons array
83 | byte[] cpy = new byte[8];
84 | for (int i = 0; i < 8; i++)
85 | cpy[newWeaponIndex[i]] = portraitBG_y[i];
86 | Array.Copy(cpy, portraitBG_y, 8);
87 |
88 | for (int i = 0; i < 8; i++)
89 | cpy[newWeaponIndex[i]] = portraitBG_x[i];
90 | Array.Copy(cpy, portraitBG_x, 8);
91 | }
92 |
93 | ///
94 | /// Get an array of the shuffled acquired-weapons' 0-7 index, since the original table's elements are bitwise/powers of 2.
95 | /// Uses the field . Must be called after .
96 | ///
97 | /// An array of the new locations of the 8 awarded weapons. The index represents the original robot master index,
98 | /// in the order H A W B Q F M C. The value represents the index of the new location.
99 | ///
100 | public int[] GetShuffleIndexPermutation()
101 | {
102 | int[] newWeaponIndex = new int[8];
103 | for (int i = 0; i < 8; i++)
104 | {
105 | int j = 0;
106 | byte val = (byte)NewWeaponOrder[i];
107 | while (val != 0)
108 | {
109 | val = (byte)(val >> 1);
110 | j++;
111 | }
112 | newWeaponIndex[i] = j - 1;
113 | }
114 | return newWeaponIndex;
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/Stages/Components/EnemyComponent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Randomizers.Stages.Components
7 | {
8 | class EnemyComponent
9 | {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/Stages/Components/LevelComponent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace MM2Randomizer.Randomizers.Stages.Components
7 | {
8 | public class LevelComponent
9 | {
10 | public string Name { get; set; }
11 | public string StartAddress { get; set; }
12 | public string EndAddress { get; set; }
13 | public IList Variations { get; set; }
14 | }
15 |
16 | public class LevelComponentVariation
17 | {
18 | public string Name { get; set; }
19 | public string[] TsaMap { get; set; }
20 | public string Sprites { get; set; }
21 | }
22 |
23 | public class ComponentManager
24 | {
25 | public IList LevelComponents { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/Stages/RStages.cs:
--------------------------------------------------------------------------------
1 | using MM2Randomizer.Enums;
2 | using MM2Randomizer.Patcher;
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | namespace MM2Randomizer.Randomizers.Stages
9 | {
10 | public class RStages : IRandomizer
11 | {
12 | private List StageSelect;
13 | private StringBuilder debug = new StringBuilder();
14 |
15 | public RStages() { }
16 |
17 | public override string ToString()
18 | {
19 | return debug.ToString();
20 | }
21 |
22 | public void FixPortraits(ref byte[] portraitBG_x, ref byte[] portraitBG_y)
23 | {
24 | // Get the new stage order
25 | int[] newOrder = new int[8];
26 | foreach (StageFromSelect stage in StageSelect)
27 | newOrder[stage.PortraitDestinationOriginal] = stage.PortraitDestinationNew;
28 |
29 | // Permute portrait x/y values via the shuffled stage-order array
30 | byte[] cpy = new byte[8];
31 | for (int i = 0; i < 8; i++)
32 | cpy[newOrder[i]] = portraitBG_y[i];
33 | Array.Copy(cpy, portraitBG_y, 8);
34 |
35 | for (int i = 0; i < 8; i++)
36 | cpy[newOrder[i]] = portraitBG_x[i];
37 | Array.Copy(cpy, portraitBG_x, 8);
38 | }
39 |
40 | ///
41 | /// Shuffle the Robot Master stages. This shuffling will not be indicated by the Robot Master portraits.
42 | ///
43 | public void Randomize(Patch Patch, Random r)
44 | {
45 | // StageSelect Address Value
46 | // -----------------------------
47 | // Bubble Man 0x034670 3
48 | // Air Man 0x034671 1
49 | // Quick Man 0x034672 4
50 | // Wood Man 0x034673 2
51 | // Crash Man 0x034674 7
52 | // Flash Man 0x034675 5
53 | // Metal Man 0x034676 6
54 | // Heat Man 0x034677 0
55 |
56 | StageSelect = new List();
57 |
58 | StageSelect.Add(new StageFromSelect()
59 | {
60 | PortraitName = "Bubble Man",
61 | PortraitAddress = ERMPortraitAddress.BubbleMan,
62 | PortraitDestinationOriginal = 3,
63 | PortraitDestinationNew = 3,
64 | StageClearAddress = ERMStageClearAddress.BubbleMan,
65 | StageClearDestinationOriginal = 8,
66 | StageClearDestinationNew = 8,
67 | TextAddress = ERMPortraitText.BubbleMan,
68 | TextValues = "BUBBLE",
69 | });
70 | StageSelect.Add(new StageFromSelect()
71 | {
72 | PortraitName = "Air Man",
73 | PortraitAddress = ERMPortraitAddress.AirMan,
74 | PortraitDestinationOriginal = 1,
75 | PortraitDestinationNew = 1,
76 | StageClearAddress = ERMStageClearAddress.AirMan,
77 | StageClearDestinationOriginal = 2,
78 | StageClearDestinationNew = 2,
79 | TextAddress = ERMPortraitText.AirMan,
80 | TextValues = "fAIRfff"
81 | });
82 | StageSelect.Add(new StageFromSelect()
83 | {
84 | PortraitName = "Quick Man",
85 | PortraitAddress = ERMPortraitAddress.QuickMan,
86 | PortraitDestinationOriginal = 4,
87 | PortraitDestinationNew = 4,
88 | StageClearAddress = ERMStageClearAddress.QuickMan,
89 | StageClearDestinationOriginal = 16,
90 | StageClearDestinationNew = 16,
91 | TextAddress = ERMPortraitText.QuickMan,
92 | TextValues = "QUICKf"
93 | });
94 | StageSelect.Add(new StageFromSelect()
95 | {
96 | PortraitName = "Wood Man",
97 | PortraitAddress = ERMPortraitAddress.WoodMan,
98 | PortraitDestinationOriginal = 2,
99 | PortraitDestinationNew = 2,
100 | StageClearAddress = ERMStageClearAddress.WoodMan,
101 | StageClearDestinationOriginal = 4,
102 | StageClearDestinationNew = 4,
103 | TextAddress = ERMPortraitText.WoodMan,
104 | TextValues = "WOODff",
105 | });
106 | StageSelect.Add(new StageFromSelect()
107 | {
108 | PortraitName = "Clash Man",
109 | PortraitAddress = ERMPortraitAddress.CrashMan,
110 | PortraitDestinationOriginal = 7,
111 | PortraitDestinationNew = 7,
112 | StageClearAddress = ERMStageClearAddress.CrashMan,
113 | StageClearDestinationOriginal = 128,
114 | StageClearDestinationNew = 128,
115 | TextAddress = ERMPortraitText.CrashMan,
116 | TextValues = "CRASHf",
117 | });
118 | StageSelect.Add(new StageFromSelect()
119 | {
120 | PortraitName = "Flash Man",
121 | PortraitAddress = ERMPortraitAddress.FlashMan,
122 | PortraitDestinationOriginal = 5,
123 | PortraitDestinationNew = 5,
124 | StageClearAddress = ERMStageClearAddress.FlashMan,
125 | StageClearDestinationOriginal = 32,
126 | StageClearDestinationNew = 32,
127 | TextAddress = ERMPortraitText.FlashMan,
128 | TextValues = "FLASHf",
129 | });
130 | StageSelect.Add(new StageFromSelect()
131 | {
132 | PortraitName = "Metal Man",
133 | PortraitAddress = ERMPortraitAddress.MetalMan,
134 | PortraitDestinationOriginal = 6,
135 | PortraitDestinationNew = 6,
136 | StageClearAddress = ERMStageClearAddress.MetalMan,
137 | StageClearDestinationOriginal = 64,
138 | StageClearDestinationNew = 64,
139 | TextAddress = ERMPortraitText.MetalMan,
140 | TextValues = "METALf",
141 | });
142 | StageSelect.Add(new StageFromSelect()
143 | {
144 | PortraitName = "Heat Man",
145 | PortraitAddress = ERMPortraitAddress.HeatMan,
146 | PortraitDestinationOriginal = 0,
147 | PortraitDestinationNew = 0, // 4 = quick
148 | StageClearAddress = ERMStageClearAddress.HeatMan,
149 | StageClearDestinationOriginal = 1,
150 | StageClearDestinationNew = 1,
151 | TextAddress = ERMPortraitText.HeatMan,
152 | TextValues = "HEATff",
153 | });
154 |
155 |
156 | List newStageOrder = new List();
157 | for (byte i = 0; i < 8; i++) newStageOrder.Add(i);
158 |
159 | newStageOrder.Shuffle(r);
160 |
161 | debug.AppendLine("Stage Select:");
162 | for (int i = 0; i < 8; i++)
163 | {
164 | StageFromSelect stage = StageSelect[i];
165 |
166 | // Change portrait destination
167 | stage.PortraitDestinationNew = StageSelect[newStageOrder[i]].PortraitDestinationOriginal;
168 |
169 | // Erase the portrait text if StageNameHidden flag is set
170 | if (RandomMM2.Settings.IsStageNameHidden)
171 | {
172 | for (int k = 0; k < 6; k++)
173 | {
174 | // Write in a blank space at each letter ('f' by my cipher)
175 | Patch.Add((int)stage.TextAddress + k, RText.CreditsCipher['f'], $"Hide Stage Select Portrait Text");
176 | }
177 |
178 | for (int k = 0; k < 3; k++)
179 | {
180 | // Write in a blank space over "MAN"; 32 8-pixel tiles until the next row, 3 tiles until "MAN" text
181 | Patch.Add((int)stage.TextAddress + 32 + 3 + k, RText.CreditsCipher['f'], $"Hide Stage Select Portrait Text");
182 | }
183 | }
184 | // Change portrait text to match new destination
185 | else
186 | {
187 | string newlabel = StageSelect[newStageOrder[i]].TextValues;
188 | for (int j = 0; j < newlabel.Length; j++)
189 | {
190 | char c = newlabel[j];
191 | Patch.Add((int)stage.TextAddress + j, RText.CreditsCipher[c], $"Stage Select Portrait Text");
192 | }
193 | }
194 |
195 | debug.AppendLine($"{Enum.GetName(typeof(EStageID), stage.PortraitDestinationOriginal)}'s portrait -> {Enum.GetName(typeof(EStageID), StageSelect[i].PortraitDestinationNew)} stage");
196 | }
197 |
198 | foreach (StageFromSelect stage in StageSelect)
199 | {
200 | Patch.Add((int)stage.PortraitAddress, (byte)stage.PortraitDestinationNew, $"Stage Select {stage.PortraitName} Destination");
201 | }
202 | }
203 | }
204 |
205 | }
206 |
--------------------------------------------------------------------------------
/MM2RandoLib/Randomizers/Stages/StageFromSelect.cs:
--------------------------------------------------------------------------------
1 | using MM2Randomizer.Enums;
2 |
3 | namespace MM2Randomizer.Randomizers.Stages
4 | {
5 | ///
6 | /// This object encapsulates the relevant ROM offsets for properties of each
7 | /// selectable Robot Master portrait on the Stage Select screen.
8 | ///
9 | public class StageFromSelect
10 | {
11 | public string PortraitName;
12 | public ERMPortraitText TextAddress;
13 | public string TextValues;
14 | public ERMPortraitAddress PortraitAddress;
15 | public int PortraitDestinationOriginal;
16 | public int PortraitDestinationNew;
17 | public ERMStageClearAddress StageClearAddress;
18 | public int StageClearDestinationOriginal;
19 | public int StageClearDestinationNew;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/MM2RandoLib/Resources/SpritePatches/SpriteSwap_Bass.ips:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckfist/MM2Random/178a4cb7649b194782b94caf9b54379e52914c0d/MM2RandoLib/Resources/SpritePatches/SpriteSwap_Bass.ips
--------------------------------------------------------------------------------
/MM2RandoLib/Resources/SpritePatches/SpriteSwap_Proto.ips:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckfist/MM2Random/178a4cb7649b194782b94caf9b54379e52914c0d/MM2RandoLib/Resources/SpritePatches/SpriteSwap_Proto.ips
--------------------------------------------------------------------------------
/MM2RandoLib/Resources/SpritePatches/SpriteSwap_Roll.ips:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckfist/MM2Random/178a4cb7649b194782b94caf9b54379e52914c0d/MM2RandoLib/Resources/SpritePatches/SpriteSwap_Roll.ips
--------------------------------------------------------------------------------
/MM2RandoLib/Resources/bossnames.csv:
--------------------------------------------------------------------------------
1 | # Also randomize the "Dr. WILY"?
2 | # DR. COSSACK
3 | # DR. LIGHT
4 | # MR. X
5 | # BREAK MAN
6 | # DOC ROBOT
7 | # BASS
8 | #
9 | # Misc
10 | CLASH
11 | WILY
12 | PROTO
13 | BREAK
14 | ROCK
15 | DARK
16 | ENKER
17 | QUINT
18 | PUNK
19 | BALLADE
20 | #
21 | # Mega Man
22 | CUT
23 | ELEC
24 | ICE
25 | FIRE
26 | BOMB
27 | GUTS
28 | #
29 | # Mega Man 2
30 | BUBBLE
31 | HEAT
32 | METAL
33 | AIR
34 | FLASH
35 | QUICK
36 | WOOD
37 | CRASH
38 | #
39 | # MEGA MAN 3
40 | TOP
41 | GEMINI
42 | SHADOW
43 | NEEDLE
44 | HARD
45 | MAGNET
46 | SNAKE
47 | SPARK
48 | #
49 | # MEGA MAN 4
50 | PHARAOH
51 | BRIGHT
52 | RING
53 | DUST
54 | SKULL
55 | DIVE
56 | DRILL
57 | TOAD
58 | #
59 | # MEGA MAN 5
60 | STAR
61 | GRAVITY
62 | GYRO
63 | CRYSTAL
64 | NAPALM
65 | STONE
66 | CHARGE
67 | WAVE
68 | #
69 | # MEGA MAN 6
70 | WIND
71 | FLAME
72 | BLIZZARD
73 | PLANT
74 | TOMAHAWK
75 | YAMATO
76 | KNIGHT
77 | CENTAUR
78 | # MEGA MAN 7
79 | FREEZE
80 | CLOUD
81 | BURST
82 | JUNK
83 | SHADE
84 | TURBO
85 | SPRING
86 | SLASH
87 | #
88 | # MEGA MAN 8
89 | SEARCH
90 | FROST
91 | GRENADE
92 | AQUA
93 | SWORD
94 | CLOWN
95 | TENGU
96 | ASTRO
97 | #
98 | # ROCKMAN AND FORTE
99 | DYNAMO
100 | COLD
101 | GROUND
102 | PIRATE
103 | BURNER
104 | MAGIC
105 | #TENGU
106 | #ASTRO
107 | #
108 | # MEGA MAN 9
109 | CONCRETE
110 | MAGMA
111 | GALAXY
112 | HORNET
113 | JEWEL
114 | TORNADO
115 | PLUG
116 | SPLASH
117 | #
118 | # MEGA MAN 10
119 | PUMP
120 | SOLAR
121 | CHILL
122 | NITRO
123 | BLADE
124 | COMMANDO
125 | STRIKE
126 | SHEEP
--------------------------------------------------------------------------------
/MM2RandoLib/Resources/companynames.csv:
--------------------------------------------------------------------------------
1 | HUDSON SOFT
2 | NINTENDO
3 | TREASURE
4 | KONAMI
5 | DATA EAST
6 | SNK PLAYMORE
7 | ACTIVISION
8 | JALECO
9 | TECMO
10 | SUNSOFT
11 | TAITO
12 | SONY
13 | SEGA CO.LTD
14 | IREM
15 | COMPILE
16 | KOEI
17 | TENGEN
18 | KEMCO
19 | RARE
20 | ATLUS
21 | HALKEN
22 | LUCASARTS
23 | WESTWOOD
24 | INTERPLAY
25 | TOSE CO.LTD
26 | NAMCO LTD.
27 | NATSUME
28 | SQUARE CO.LTD
29 | COMCEPT
30 | INTI CREATES
31 | RAINBOW ARTS
32 | OCEAN LTD.
33 | FACTOR 5
34 | VIC TOKAI
35 | ASCII
36 | THQ
37 | QUINTET
38 | ENIX
39 | MINDSCAPE
--------------------------------------------------------------------------------
/MM2RandoLib/Resources/countrylist.csv:
--------------------------------------------------------------------------------
1 | AFGHANISTAN
2 | ALBANIA
3 | ALGERIA
4 | ANDORRA
5 | ANGOLA
6 | ANTIGUA AND BARBUDA
7 | ARGENTINA
8 | ARMENIA
9 | ARUBA
10 | AUSTRALIA
11 | AUSTRIA
12 | AZERBAIJAN
13 | ANTARCTICA
14 | THE BAHAMAS
15 | BAHRAIN
16 | BANGLADESH
17 | BARBADOS
18 | BELARUS
19 | BELGIUM
20 | BELIZE
21 | BENIN
22 | BHUTAN
23 | BOLIVIA
24 | BOSNIA AND HERZEGOVINA
25 | BOTSWANA
26 | BRAZIL
27 | BRUNEI
28 | BULGARIA
29 | BURKINA FASO
30 | BURMA
31 | BURUNDI
32 | CAMBODIA
33 | CAMEROON
34 | CANADA
35 | CABO VERDE
36 | CENTRAL AFRICAN REPUBLIC
37 | CHAD
38 | CHILE
39 | CHINA
40 | COLOMBIA
41 | THE CONGO
42 | COSTA RICA
43 | CROATIA
44 | CUBA
45 | CURACAO
46 | CYPRUS
47 | CZECH REPUBLIC
48 | DENMARK
49 | DJIBOUTI
50 | DOMINICA
51 | DOMINICAN REPUBLIC
52 | ECUADOR
53 | EGYPT
54 | EL SALVADOR
55 | EQUATORIAL GUINEA
56 | ERITREA
57 | ESTONIA
58 | ETHIOPIA
59 | FIJI
60 | FINLAND
61 | FRANCE
62 | GABON
63 | THE GAMBIA
64 | GEORGIA
65 | GERMANY
66 | GHANA
67 | GREECE
68 | GRENADA
69 | GUATEMALA
70 | GUINEA
71 | GUINEA BISSAU
72 | GUYANA
73 | HAITI
74 | HONDURAS
75 | HONG KONG
76 | HUNGARY
77 | ICELAND
78 | INDIA
79 | INDONESIA
80 | IRAN
81 | IRAQ
82 | IRELAND
83 | ISRAEL
84 | ITALY
85 | JAMAICA
86 | JAPAN
87 | JORDAN
88 | KAZAKHSTAN
89 | KENYA
90 | KIRIBATI
91 | KOSOVO
92 | KUWAIT
93 | KYRGYZSTAN
94 | LAOS
95 | LATVIA
96 | LEBANON
97 | LESOTHO
98 | LIBERIA
99 | LIBYA
100 | LIECHTENSTEIN
101 | LITHUANIA
102 | LUXEMBOURG
103 | MACAU
104 | MACEDONIA
105 | MADAGASCAR
106 | MALAWI
107 | MALAYSIA
108 | MALDIVES
109 | MALI
110 | MALTA
111 | MARSHALL ISLANDS
112 | MAURITANIA
113 | MAURITIUS
114 | MEXICO
115 | MICRONESIA
116 | MOLDOVA
117 | MONACO
118 | MONGOLIA
119 | MONTENEGRO
120 | MOZAMBIQUE
121 | NAMIBIA
122 | NAURU
123 | NEPAL
124 | NETHERLANDS
125 | NEW ZEALAND
126 | NICARAGUA
127 | NIGER
128 | NIGERIA
129 | NORTH KOREA
130 | NORWAY
131 | OMAN
132 | PAKISTAN
133 | PALAU
134 | PALESTINIAN TERRITORIES
135 | PANAMA
136 | PAPUA NEW GUINEA
137 | PARAGUAY
138 | PERU
139 | PHILIPPINES
140 | POLAND
141 | PORTUGAL
142 | QATAR
143 | ROMANIA
144 | RUSSIA
145 | RWANDA
146 | SAINT KITTS AND NEVIS
147 | SAINT LUCIA
148 | SAINT VINCENT
149 | SAMOA
150 | SAN MARINO
151 | SAO TOME AND PRINCIPE
152 | SAUDI ARABIA
153 | SENEGAL
154 | SERBIA
155 | SEYCHELLES
156 | SIERRA LEONE
157 | SINGAPORE
158 | SLOVAKIA
159 | SLOVENIA
160 | SOLOMON ISLANDS
161 | SOMALIA
162 | SOUTH AFRICA
163 | SOUTH KOREA
164 | SOUTH SUDAN
165 | SPAIN
166 | SRI LANKA
167 | SUDAN
168 | SURINAME
169 | SWAZILAND
170 | SWEDEN
171 | SWITZERLAND
172 | SYRIA
173 | TAIWAN
174 | TAJIKISTAN
175 | TANZANIA
176 | THAILAND
177 | TIMOR LESTE
178 | TOGO
179 | TONGA
180 | TRINIDAD AND TOBAGO
181 | TUNISIA
182 | TURKEY
183 | TURKMENISTAN
184 | TUVALU
185 | UGANDA
186 | UKRAINE
187 | UNITED ARAB EMIRATES
188 | UNITED KINGDOM
189 | UNITED STATES
190 | URUGUAY
191 | UZBEKISTAN
192 | VANUATU
193 | VENEZUELA
194 | VIETNAM
195 | YEMEN
196 | ZAMBIA
197 | ZIMBABWE
--------------------------------------------------------------------------------
/MM2RandoLib/Resources/creditstext.csv:
--------------------------------------------------------------------------------
1 | 14|09|MM2 RANDOMIZER
2 | 13|2A|ROBOT MASTERS
3 | 01|61|f
4 | 17|AB|P H A W B Q F M C
5 | 25|E3|HEATMAN 2 3 1 2
6 | 24|24|AIRMAN 1 2 1 2 4
7 | 25|63|WOODMAN 1 1 1 3 2
8 | 27|A1|BUBBLEMAN 2 4 1 1 3 1
9 | 26|E2|QUICKMAN 1 5 1 1 1 2
10 | 26|22|FLASHMAN 1 2 1 1 3 1
11 | 26|62|METALMAN 1 2 1 2 1 1 1
12 | 26|A2|CLASHMAN 1 2 2 3 1
13 | 01|E1|f
14 | 01|21|f
15 | 11|6B|WILY BOSSES
16 | 01|A1|f
17 | 15|2C|P H A W B Q M C
18 | 22|65|DRAGON
19 | 24|A3|PICOPICO
20 | 20|E7|GUTS
21 | 23|24|BOOBEAM
22 | 23|64|MACHINE
23 | 21|A6|ALIEN X X X 2 X X X X
24 | 01|E1|f
25 | 01|21|f
26 | 01|61|f
27 | 01|A1|f
28 | 01|E1|f
29 | 01|21|f
30 | 01|61|f
31 | 01|A1|f
32 | 12|2A|RANDOMIZER BY
33 | 08|6C|DUCKFIST
34 | 01|A1|f
35 | 01|E1|f
36 | 01|21|f
37 | 01|61|f
38 | 01|A1|f
39 | 01|E1|f
40 | 01|21|f
41 | 21|66|SPECIAL THANKS TO THE
42 | 14|A9|ROCKMAN 2 TEAM
43 | 01|A1|f
44 | 12|8A|PRESENTED BY
--------------------------------------------------------------------------------
/MM2RandoLib/Resources/enemylist.csv:
--------------------------------------------------------------------------------
1 | #Index,StageNum,RoomNum,ScreenNum,IsActive,EnemyID,XPosOriginal,YPosOriginal,YPosAir,YPosGround,FaceRight
2 | ###
3 | ### Heat Man / Wily 1 Stage
4 | ###
5 | 00,00,00,01,true,2B,70,10,24,A4,false
6 | 01,00,00,01,true,2B,F0,10,24,A4,false
7 | 02,00,00,02,true,2B,90,10,28,A4,false
8 | 03,00,00,02,true,21,A8,58,58,58,false
9 | 04,00,00,02,true,21,E8,78,78,78,false
10 | 05,00,00,03,true,21,48,48,48,48,false
11 | 06,00,00,03,true,21,88,68,68,68,false
12 | 07,00,00,03,true,21,D8,98,98,98,false
13 | 08,00,00,04,true,21,28,58,58,58,false
14 | 09,00,00,04,true,21,88,58,58,58,false
15 | 0A,00,00,04,true,21,E8,38,38,38,false
16 | 0B,00,00,05,true,21,48,58,58,58,false
17 | 0C,00,00,05,true,21,C8,58,58,58,false
18 | 0D,00,00,07,true,46,78,98,94,94,false
19 | 0E,00,00,07,true,46,98,58,94,94,false
20 | 0F,00,01,08,true,46,48,C8,C4,C4,true
21 | 10,00,01,08,false,53,68,37,0,0,false
22 | 11,00,01,08,false,55,78,57,0,0,false
23 | 12,00,01,08,false,54,A8,47,0,0,false
24 | 13,00,01,08,false,53,A8,77,0,0,false
25 | 14,00,02,09,true,21,B8,58,58,B4,false
26 | 15,00,02,09,true,21,E8,78,78,B4,false
27 | 16,00,02,0A,false,53,38,A7,0,0,false
28 | 17,00,02,0A,true,21,58,48,44,44,false
29 | 18,00,02,0A,false,54,A8,67,0,0,false
30 | 19,00,02,0A,false,53,A8,97,0,0,false
31 | 1A,00,02,0B,true,21,08,88,88,B4,false
32 | 1B,00,02,0B,true,21,38,78,78,B4,false
33 | 1C,00,02,0B,true,21,68,48,48,B4,false
34 | 1D,00,02,0B,false,53,A8,A7,0,0,false
35 | 1E,00,02,0B,true,21,D8,48,48,B4,false
36 | 1F,00,02,0C,false,55,48,77,0,0,false
37 | 20,00,02,0C,false,53,48,A7,0,0,false
38 | 21,00,02,0C,true,21,98,48,48,B4,false
39 | 22,00,02,0C,false,53,D8,B7,0,0,false
40 | 23,00,02,0E,true,46,68,B8,74,B4,false
41 | 24,00,02,0E,false,53,E8,77,0,0,false
42 | 25,00,02,0F,false,53,18,77,0,0,false
43 | 26,00,02,0F,false,54,48,47,0,0,false
44 | 27,00,02,0F,false,53,48,77,0,0,false
45 | 28,00,02,0F,false,53,78,47,0,0,false
46 | 29,00,02,0F,false,53,A8,77,0,0,false
47 | 2A,00,02,0F,false,54,D8,47,0,0,false
48 | 2B,00,02,0F,false,53,D8,77,0,0,false
49 | 2C,00,02,10,false,53,08,47,0,0,false
50 | 2D,00,02,10,false,53,38,47,0,0,false
51 | 2E,00,02,10,false,53,68,67,0,0,false
52 | 2F,00,02,10,false,53,98,67,0,0,false
53 | 30,00,02,10,false,53,C8,67,0,0,false
54 | 31,00,02,10,false,53,F8,67,0,0,false
55 | 32,00,02,11,false,53,28,67,0,0,false
56 | 33,00,02,11,false,53,58,77,0,0,false
57 | 34,00,02,11,false,53,88,67,0,0,false
58 | 35,00,02,11,false,53,B8,57,0,0,false
59 | 36,00,02,11,false,53,E8,47,0,0,false
60 | 37,00,02,12,false,53,18,97,0,0,false
61 | 38,00,02,12,false,53,48,97,0,0,false
62 | 39,00,02,12,false,54,78,67,0,0,false
63 | 3A,00,02,12,false,53,78,97,0,0,false
64 | 3B,00,02,12,false,53,A8,77,0,0,false
65 | 3C,00,02,12,false,53,D8,67,0,0,false
66 | 3D,00,03,14,true,4E,50,94,64,A4,true
67 | 3E,00,07,18,true,39,08,30,30,B4,true
68 | 3F,00,07,19,true,37,10,30,30,A4,false
69 | 40,00,07,19,true,00,A0,30,30,A4,false
70 | 41,00,07,1A,true,00,A0,30,30,A4,false
71 | 42,00,07,1B,true,37,20,30,30,A4,false
72 | 43,00,07,1C,true,39,30,30,30,B4,false
73 | 44,00,07,1D,true,50,48,BC,B4,B4,false
74 | 45,00,07,1D,true,50,B8,AC,A4,A4,false
75 | 46,00,07,1E,true,50,48,9C,94,94,false
76 | 47,00,07,1E,true,50,A8,AC,A4,A4,false
77 | 48,00,07,1E,true,50,E8,9C,94,94,false
78 | 49,00,07,1F,true,50,F0,BC,B4,B4,false
79 | 4A,00,07,20,true,50,6C,5C,44,54,true
80 | 4B,00,08,21,true,4F,4C,64,34,64,true
81 | 4C,00,09,22,true,4F,44,74,44,74,true
82 | 4D,00,0A,23,true,46,98,B8,54,B4,false
83 | 4E,00,0C,25,true,21,10,38,38,38,true
84 | 4F,00,0C,25,true,21,10,88,88,88,true
85 | 50,00,0D,2A,false,63,28,98,0,0,false
86 | 51,00,0E,2A,false,63,68,98,0,0,false
87 | 52,00,0E,2A,false,63,98,88,0,0,false
88 | 53,00,0E,2A,false,63,D8,88,0,0,false
89 | 54,00,0E,2A,false,64,FF,98,0,0,false
90 | ###
91 | ### Air Man / Wily 2 Stage
92 | ###
93 | #Index,StageNum,RoomNum,ScreenNum,IsActive,EnemyID,XPosOriginal,YPosOriginal,YPosAir,YPosGround,FaceRight
94 | 00,01,00,01,true,40,48,9B,10,64,false
95 | 01,01,00,01,true,41,F8,AB,10,74,false
96 | 02,01,00,02,true,40,98,6B,10,34,false
97 | 03,01,00,03,true,41,48,8B,10,54,false
98 | 04,01,00,03,true,40,E8,8B,10,54,false
99 | # Lightning Goros
100 | 05,01,00,04,true,3E,C0,20,10,54,false
101 | 06,01,00,05,true,3E,60,60,10,74,false
102 | 07,01,00,06,true,3E,00,38,10,94,false
103 | 08,01,00,06,true,3E,60,40,10,94,false
104 | 09,01,00,06,false,39,B0,08,10,74,false
105 | 0A,01,00,06,true,3E,E0,40,10,74,false
106 | # Pipi Spawner and Despawner
107 | 0B,01,00,07,true,37,70,30,20,74,false
108 | 0C,01,00,07,true,00,C0,20,20,74,false
109 | # Checkpoint room
110 | 0D,01,00,08,true,00,38,20,20,74,false
111 | 0E,01,00,08,true,00,B0,20,20,74,false
112 | 0F,01,00,09,true,00,60,20,20,74,false
113 | 10,01,01,0A,true,50,38,5C,20,54,true
114 | 11,01,01,0A,true,50,B8,9C,94,94,false
115 | 12,01,02,0C,true,40,48,9B,10,64,false
116 | 13,01,02,0C,true,41,B8,7B,10,44,false
117 | 14,01,02,0E,true,39,00,08,20,74,false
118 | 15,01,02,0E,true,36,80,50,54,54,false
119 | 16,01,02,0F,true,37,10,30,20,74,false
120 | 17,01,02,0F,true,00,E0,20,20,74,false
121 | 18,01,02,10,true,36,F0,50,54,54,false
122 | 19,01,02,11,true,36,60,30,34,34,false
123 | 1A,01,02,12,true,00,30,20,20,54,false
124 | 1B,01,02,12,true,37,E0,30,20,34,false
125 | 1C,01,02,13,true,39,C0,08,10,74,false
126 | 1D,01,05,17,true,2B,10,10,10,64,false
127 | 1E,01,05,17,true,2B,98,10,10,84,false
128 | 1F,01,05,18,true,2B,10,10,10,A4,false
129 | 20,01,07,1D,true,4C,74,24,24,24,true
130 | 21,01,07,1D,true,4B,9C,64,64,64,false
131 | 22,01,09,1F,true,4A,90,80,94,94,false
132 | 23,01,09,20,true,47,60,80,94,94,false
133 | 24,01,09,20,true,47,F0,80,94,94,false
134 | 25,01,09,22,true,4A,00,80,94,94,false
135 | 26,01,09,22,true,30,40,6C,6C,A4,false
136 | 27,01,09,22,true,30,90,0C,10,34,false
137 | 28,01,09,23,true,30,30,0C,10,34,false
138 | 29,01,09,23,true,30,B0,0C,10,34,false
139 | 2A,01,09,23,true,30,E0,0C,10,34,false
140 | ###
141 | ### Wood Man / Wily 3 Stage
142 | ###
143 | 00,02,00,01,true,16,08,48,48,A4,false
144 | 01,02,00,01,true,16,50,68,86,B4,false
145 | 02,02,00,01,true,16,98,48,48,A4,false
146 | 03,02,00,01,true,17,D0,90,48,A4,false
147 | 04,02,00,01,true,16,F8,18,18,94,false
148 | 05,02,00,02,true,16,38,18,18,94,false
149 | 06,02,00,02,true,16,88,28,28,94,false
150 | 07,02,00,02,true,17,F0,A0,A4,A4,false
151 | 08,02,00,03,true,16,50,68,68,B4,false
152 | 09,02,00,03,true,16,B8,48,48,B4,false
153 | 0A,02,00,04,true,16,18,48,48,B4,false
154 | 0B,02,00,04,true,17,80,B0,B4,B4,false
155 | 0C,02,00,04,true,16,98,48,48,B4,false
156 | 0D,02,01,05,true,16,38,78,78,B4,true
157 | 0E,02,01,05,true,16,60,88,88,A4,true
158 | 0F,02,01,05,true,16,80,68,68,A4,true
159 | 10,02,02,06,false,1C,AC,08,0,0,false
160 | 11,02,03,07,false,1C,AC,08,0,0,false
161 | 12,02,04,08,false,1C,CC,08,0,0,false
162 | 13,02,06,0A,true,16,50,48,48,A4,true
163 | 14,02,06,0A,true,16,78,68,68,B4,true
164 | 15,02,07,0C,true,39,30,08,48,74,false
165 | 16,02,07,0C,true,1D,70,E0,28,74,false
166 | 17,02,07,0C,true,1D,F0,E0,10,54,false
167 | 18,02,07,0D,true,37,40,30,20,54,false
168 | 19,02,07,0D,true,37,B0,30,20,54,false
169 | 1A,02,07,0D,true,1D,E0,E0,20,54,false
170 | 1B,02,07,0E,true,1D,70,E0,10,74,false
171 | 1C,02,07,0E,true,39,F0,08,10,34,false
172 | 1D,02,08,10,true,17,48,B0,68,B4,true
173 | 1E,02,09,11,true,17,C0,B0,68,B4,false
174 | 1F,02,0A,12,true,17,30,B0,68,B4,true
175 | 20,02,0B,13,true,20,80,08,20,B4,false
176 | 21,02,0B,14,true,1E,10,08,20,94,false
177 | 22,02,0B,14,true,1E,B0,08,10,74,false
178 | 23,02,0B,15,true,20,C0,08,10,74,false
179 | 24,02,10,1A,true,0A,BC,C4,C4,C4,false
180 | 25,02,11,1C,true,00,F0,10,10,94,false
181 | 26,02,11,1D,true,71,60,E0,10,94,false
182 | 27,02,11,1D,true,71,F0,E0,10,94,false
183 | 28,02,16,25,true,4B,2C,B4,88,B4,false
184 | 29,02,16,25,true,4B,CC,B4,88,B4,false
185 | 2A,02,16,26,true,4B,5C,B4,88,B4,false
186 | 2B,02,15,23,false,56,80,80,0,0,false
187 | 00,03,00,01,true,0C,50,70,20,74,false
188 | 01,03,00,01,true,0C,D0,50,20,54,false
189 | 02,03,00,02,true,0C,B0,50,20,54,false
190 | 03,03,00,02,false,13,F0,88,0,0,false
191 | 04,03,00,03,false,13,20,78,0,0,false
192 | 05,03,00,03,false,13,60,68,0,0,false
193 | 06,03,00,03,false,13,A0,78,0,0,false
194 | 07,03,00,03,false,13,D0,58,0,0,false
195 | 08,03,01,05,true,0A,5C,34,34,34,false
196 | 09,03,01,05,true,0A,6C,94,94,94,false
197 | 0A,03,01,05,true,0A,B4,64,64,64,false
198 | 0B,03,03,07,true,0A,44,34,34,34,false
199 | 0C,03,03,07,true,0A,7C,74,74,74,false
200 | 0D,03,03,07,true,0A,8C,A4,A4,A4,false
201 | 0E,03,04,09,true,00,08,58,58,B4,false
202 | 0F,03,04,09,true,00,50,70,70,B4,false
203 | 10,03,04,09,true,00,68,48,48,B4,false
204 | 11,03,04,09,true,00,C8,98,98,B4,false
205 | 12,03,04,09,true,05,38,08,40,B4,false
206 | 13,03,04,0A,true,03,D0,08,60,94,false
207 | 14,03,04,0B,true,00,D8,38,38,54,false
208 | 15,03,04,0C,true,03,70,08,60,74,false
209 | 16,03,04,0D,true,05,80,08,10,B4,false
210 | 17,03,04,0E,true,00,00,68,68,B4,false
211 | 18,03,04,0E,true,00,18,88,88,B4,false
212 | 19,03,04,0E,true,00,88,38,38,B4,false
213 | 1A,03,05,0F,true,0C,90,90,60,94,false
214 | 1B,03,05,10,true,0C,30,70,74,74,false
215 | 1C,03,05,10,true,09,A0,08,74,74,false
216 | 1D,03,05,11,true,07,C0,08,10,64,false
217 | 1E,03,05,12,true,07,90,08,10,64,false
218 | 1F,03,05,13,true,09,88,08,10,34,false
219 | 20,03,09,17,true,34,C8,98,94,94,false
220 | 21,03,0A,18,true,34,78,B8,74,B4,true
221 | 22,03,0D,1B,true,34,90,78,30,74,false
222 | 23,03,0D,1B,true,34,B8,B8,70,B4,false
223 | 24,03,0F,1E,true,21,10,58,54,54,true
224 | 25,03,0F,1E,true,21,10,98,94,94,true
225 | 26,03,0F,1E,false,12,D8,88,0,0,false
226 | 27,03,0F,1E,true,21,F0,A8,A4,A4,false
227 | 28,03,10,1F,false,12,48,28,0,0,false
228 | 29,03,11,20,true,21,10,38,34,34,true
229 | 2A,03,11,20,true,21,10,B8,B4,B4,true
230 | 2B,03,11,20,false,12,38,48,0,0,false
231 | 2C,03,11,20,true,21,F0,B8,B4,B4,false
232 | 2D,03,12,21,false,12,58,58,0,0,false
233 | 2E,03,13,22,true,4E,F0,A4,50,B4,false
234 | 2F,03,13,23,true,4F,9C,B4,B4,B4,false
235 | 30,03,13,24,true,4E,B0,A4,50,B4,false
236 | 31,03,13,25,true,4F,AC,B4,B4,B4,false
237 | 00,04,01,01,true,50,50,BC,50,B4,true
238 | 01,04,01,01,true,50,90,9C,40,94,true
239 | 02,04,03,03,true,46,68,B8,30,B4,true
240 | 03,04,03,03,false,14,80,80,0,0,false
241 | 04,04,04,04,false,14,80,80,0,0,false
242 | 05,04,05,05,false,14,80,80,0,0,false
243 | 06,04,05,05,true,46,98,A8,A4,A4,false
244 | 07,04,07,08,true,25,00,08,30,94,false
245 | 08,04,07,08,true,23,60,70,30,74,false
246 | 09,04,07,09,true,23,10,90,50,94,false
247 | 0A,04,07,09,true,00,60,50,50,74,false
248 | 0B,04,07,0A,true,23,10,90,70,94,false
249 | 0C,04,07,0A,true,25,60,08,70,94,false
250 | 0D,04,07,0B,true,27,80,08,70,74,false
251 | 0E,04,08,0C,false,14,80,80,0,0,false
252 | 0F,04,09,0D,false,14,80,80,0,0,false
253 | 10,04,0A,0E,false,14,80,80,0,0,false
254 | 11,04,0B,0F,false,14,80,80,0,0,false
255 | 12,04,0C,10,false,14,80,80,0,0,false
256 | 13,04,0D,11,false,14,80,80,0,0,false
257 | 14,04,0E,12,false,14,80,80,0,0,false
258 | 15,04,0F,13,true,00,A0,50,50,B4,false
259 | 16,04,0F,13,true,4E,F8,A4,50,B4,false
260 | 17,04,0F,14,true,4E,E8,A4,70,B4,false
261 | 00,05,00,02,true,4B,84,C4,C4,C4,false
262 | 01,05,00,03,true,4B,9C,94,C4,C4,false
263 | 02,05,00,03,true,4C,EC,94,94,94,false
264 | 03,05,00,04,true,4B,24,34,C4,C4,false
265 | 04,05,00,04,true,4B,CC,94,60,94,false
266 | 05,05,00,06,true,4C,44,94,60,94,true
267 | 06,05,01,07,true,4E,40,84,30,94,true
268 | 07,05,02,08,true,4B,68,84,60,84,false
269 | 08,05,04,0A,true,50,50,9C,60,94,false
270 | 09,05,04,0A,true,50,D8,6C,40,64,false
271 | 0A,05,05,0B,true,31,88,B0,90,C4,false
272 | 0B,05,06,0C,true,4E,68,B4,94,C4,true
273 | 0C,05,07,0D,true,4E,F8,B4,34,34,false
274 | 0D,05,07,0E,true,00,D8,20,20,34,false
275 | 0E,05,07,0F,true,4E,38,B4,60,C4,false
276 | 0F,05,07,0F,true,00,C0,20,20,C4,false
277 | 10,05,07,11,true,4E,08,84,60,94,false
278 | 11,05,0F,1A,false,72,18,34,0,0,false
279 | 12,05,0F,1A,false,73,58,44,0,0,false
280 | 13,05,0F,1A,false,72,B0,24,0,0,false
281 | 14,05,0F,1A,false,73,D0,44,0,0,false
282 | 15,05,0F,1B,false,72,28,24,0,0,false
283 | 16,05,0F,1B,false,73,48,34,0,0,false
284 | 17,05,0F,1B,false,72,70,44,0,0,false
285 | 18,05,0F,1B,false,73,B0,34,0,0,false
286 | 19,05,0F,1B,false,72,E8,54,0,0,false
287 | 1A,05,0F,1C,false,73,28,64,0,0,false
288 | 1B,05,0F,1C,false,72,78,64,0,0,false
289 | 1C,05,0F,1C,false,73,A0,64,0,0,false
290 | 1D,05,0F,1C,false,72,C8,64,0,0,false
291 | 1E,05,0F,1D,false,73,68,64,0,0,false
292 | 1F,05,0F,1D,false,72,90,64,0,0,false
293 | 20,05,0F,1D,false,73,B8,64,0,0,false
294 | 21,05,0F,1E,false,72,30,64,0,0,false
295 | 22,05,0F,1E,false,73,78,44,0,0,false
296 | 23,05,0F,1E,false,72,B0,44,0,0,false
297 | 00,06,00,02,true,30,70,38,40,84,false
298 | 01,06,00,02,true,30,D0,38,40,84,false
299 | 02,06,00,03,true,30,30,28,30,84,false
300 | 03,06,00,03,true,30,70,28,30,84,false
301 | 04,06,00,03,true,30,B0,38,40,84,false
302 | 05,06,00,04,true,4A,38,50,50,B4,false
303 | 06,06,00,04,true,47,E0,08,50,B4,false
304 | 07,06,00,05,true,47,F0,08,50,74,false
305 | 08,06,00,06,true,00,78,50,50,74,false
306 | 09,06,00,07,true,4A,18,08,50,A4,false
307 | 0A,06,02,0C,true,29,60,40,40,A4,false
308 | 0B,06,02,0C,true,29,C8,48,48,74,false
309 | 0C,06,02,0D,true,29,E0,58,58,A4,false
310 | 0D,06,02,0E,true,29,60,48,48,A4,false
311 | 0E,06,02,0F,true,29,10,38,38,A4,false
312 | 0F,06,02,0F,true,31,58,78,28,94,false
313 | 10,06,02,10,true,31,18,48,20,64,false
314 | 11,06,02,10,true,31,E8,18,10,34,false
315 | 12,06,02,11,true,46,B8,B8,20,B4,false
316 | 13,06,02,12,true,46,38,98,20,94,false
317 | 14,06,02,12,true,46,A8,98,20,94,false
318 | 15,06,02,13,true,46,38,88,20,74,false
319 | 16,06,02,13,true,46,98,88,20,74,false
320 | 00,07,00,00,true,21,38,78,80,B4,true
321 | 01,07,00,00,true,21,60,28,10,34,true
322 | 02,07,00,00,true,21,D0,48,60,74,false
323 | 03,07,01,01,true,21,30,68,10,54,true
324 | 04,07,01,01,true,21,A8,58,50,64,false
325 | 05,07,01,01,true,21,D0,B8,A4,A4,false
326 | 06,07,02,02,true,34,C8,98,60,94,false
327 | 07,07,02,03,true,34,48,88,40,84,false
328 | 08,07,02,03,true,34,88,78,40,74,false
329 | 09,07,03,04,true,21,10,38,38,38,true
330 | 0A,07,03,04,true,21,10,68,68,B4,true
331 | 0B,07,03,04,false,12,D8,48,0,0,false
332 | 0C,07,03,04,true,21,F0,68,68,B4,false
333 | 0D,07,04,05,true,21,10,78,78,B4,true
334 | 0E,07,04,05,false,12,D8,48,0,0,false
335 | 0F,07,04,05,true,21,F0,48,48,48,false
336 | 10,07,04,05,true,21,F0,70,70,B4,false
337 | 11,07,05,06,true,21,08,68,68,B4,true
338 | 12,07,05,06,false,12,D8,48,0,0,false
339 | 13,07,05,06,true,21,F0,38,38,38,false
340 | 14,07,05,06,true,21,F0,68,68,B4,false
341 | 15,07,06,08,true,31,18,90,40,B4,false
342 | 16,07,06,08,true,00,68,70,70,B4,false
343 | 17,07,08,0A,false,56,20,20,0,0,false
344 | 18,07,08,0A,true,34,48,58,54,54,true
345 | 19,07,09,0B,false,56,20,20,0,0,false
346 | 1A,07,09,0B,true,34,A8,B8,20,B4,false
347 | 1B,07,0A,0C,false,56,20,20,0,0,false
348 | 1C,07,0A,0C,true,37,A0,30,30,74,false
349 | 1D,07,0B,0D,true,37,30,30,20,54,true
350 | 1E,07,0C,0E,true,37,20,30,30,30,true
351 | 1F,07,0C,0E,true,4B,6C,64,30,64,true
352 | 20,07,0E,10,true,2B,E0,10,10,64,false
353 | 21,07,0E,11,true,2B,40,10,10,B4,false
354 | 22,07,0E,11,true,2B,A8,10,10,74,false
--------------------------------------------------------------------------------
/MM2RandoLib/Resources/enemyweakness.csv:
--------------------------------------------------------------------------------
1 | #EnemyName,#OffsetHex,#P,#H,#A,#W,#B,#Q,#C,#M
2 | Shrink ,00,7,20,0,10,20,7,10,10
3 | #Shrink(From Angler) ,01,7,20,0,10,20,7,10,10
4 | M445(Instance) ,04,20,20,20,20,0,20,20,20
5 | Claw(Instance) ,08,20,20,10,10,20,7,10,10
6 | Tanishi ,0A,10,20,0,10,0,4,10,4
7 | Kerog ,0C,2,20,0,0,4,4,0,2
8 | Kerog(Small) ,0D,20,20,10,10,20,20,10,10
9 | Batton ,16,10,20,10,10,0,10,10,20
10 | Robbit ,17,2,20,0,20,7,4,20,4
11 | Friender(Instance) ,19,1,20,0,20,0,2,0,2
12 | Monking ,1D,7,20,0,20,0,7,20,7
13 | Cook(Instance) ,1F,2,20,0,20,0,2,20,0
14 | Telly(Instance) ,22,20,20,10,20,0,20,20,20
15 | Pierobot ,29,6,20,0,7,0,7,20,0
16 | Pierobot(Clown) ,2A,20,20,20,20,0,7,20,20
17 | Fly Boy(Instance) ,2C,4,20,20,7,0,4,20,20
18 | Press ,30,0,0,0,0,0,0,0,0
19 | Blocky ,31,10,20,0,0,0,10,20,10
20 | Neo Metall ,34,20,20,0,20,20,20,20,20
21 | Matasaburo ,36,4,0,0,7,7,4,7,4
22 | Pipi(Instance) ,38,20,20,20,20,0,20,20,20
23 | Lightning Goro ,3D,7,0,20,20,20,7,20,7
24 | Springer ,46,0,20,0,20,7,7,7,0
25 | Mole(Instance Up) ,48,4,20,7,20,0,4,4,7
26 | #Mole(Instance Down) ,49,4,20,7,20,0,4,4,7
27 | Shotman(Facing Left) ,4B,4,20,7,20,2,4,4,4
28 | #Shotman(Facing Right),4C,4,20,7,20,2,4,4,4
29 | Sniper Armor ,4E,1,20,7,7,0,4,4,0
30 | Sniper Joe ,4F,2,20,4,7,4,4,2,2
31 | Scworm ,50,4,20,20,20,7,4,4,20
--------------------------------------------------------------------------------
/MM2RandoLib/Resources/level_components.json:
--------------------------------------------------------------------------------
1 | {
2 | "LevelComponents": [
3 | {
4 | "Name": "flash_room0_screen2",
5 | "StartAddress": "14590",
6 | "EndAddress": "145CF",
7 | "Variations": [
8 | {
9 | "Name": "default",
10 | "TsaMap": [
11 | "59","2A","28","01","01","23","58","59",
12 | "6B","33","25","1B","03","25","45","67",
13 | "59","60","30","09","03","75","78","03",
14 | "59","23","2D","10","03","17","09","71",
15 | "61","29","22","0D","03","33","0B","03",
16 | "0F","2B","30","1A","03","21","0D","38",
17 | "0F","31","2C","10","03","22","18","69",
18 | "2F","3A","31","0C","03","30","14","69"],
19 | "Sprites": "asdf"
20 | },
21 | {
22 | "Name": "opened up",
23 | "TsaMap": [
24 | "59","2A","28","01","01","75","78","69",
25 | "6B","33","25","0F","0F","0F","09","38",
26 | "59","60","30","0F","0F","0F","1B","03",
27 | "59","23","2D","0F","0F","0F","09","71",
28 | "61","29","22","0F","0F","0F","0B","03",
29 | "0F","2B","30","0F","0F","0F","0D","38",
30 | "0F","31","2C","10","03","22","18","69",
31 | "2F","3A","31","0C","03","30","14","69"],
32 | "Sprites": "asdf"
33 | },
34 | {
35 | "Name": "1 tile platforms",
36 | "TsaMap": [
37 | "59", "2A", "28","01","01","75","78","69",
38 | "6B", "33", "25","0F","0F","0F","09","38",
39 | "59", "60", "30","0F","0F","17","1B","03",
40 | "59", "23", "2D","0F","0F","0F","09","71",
41 | "61", "29", "0F","0F","27","06","0B","03",
42 | "0F", "2B", "0F","0F","0A","03","0D","38",
43 | "0F", "31", "0F","0F","0F","0F","18","69",
44 | "2F", "22", "0F","10","03","30","14","69"],
45 | "Sprites": "asdf"
46 | }
47 | ]
48 | },
49 | ]
50 | }
--------------------------------------------------------------------------------
/MM2RandoLib/Resources/mm2rng_musicpatch.ips:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckfist/MM2Random/178a4cb7649b194782b94caf9b54379e52914c0d/MM2RandoLib/Resources/mm2rng_musicpatch.ips
--------------------------------------------------------------------------------
/MM2RandoLib/Resources/mm2rng_prepatch.ips:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/duckfist/MM2Random/178a4cb7649b194782b94caf9b54379e52914c0d/MM2RandoLib/Resources/mm2rng_prepatch.ips
--------------------------------------------------------------------------------
/MM2RandoLib/Utilities/SeedConvert.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace MM2Randomizer.Utilities
6 | {
7 | public static class SeedConvert
8 | {
9 | public static string ConvertBase10To26(int n)
10 | {
11 | string hexavigesimal = IntToString(n,
12 | Enumerable.Range('A', 26).Select(x => (char)x).ToArray());
13 | return hexavigesimal;
14 | }
15 |
16 | public static int ConvertBase26To10(string n)
17 | {
18 | int base10 = StringToInt(n,
19 | Enumerable.Range('A', 26).Select(x => (char)x).ToArray());
20 | return base10;
21 | }
22 |
23 | public static string IntToString(int value, char[] baseChars)
24 | {
25 | string result = string.Empty;
26 | int targetBase = baseChars.Length;
27 |
28 | do
29 | {
30 | result = baseChars[value % targetBase] + result;
31 | value = value / targetBase;
32 | }
33 | while (value > 0);
34 |
35 | return result;
36 | }
37 |
38 | public static int StringToInt(string value, char[] baseChars)
39 | {
40 | int result = 0;
41 | int targetBase = baseChars.Length;
42 | List baseCharsList = new List(baseChars);
43 | char[] valueChars = value.ToCharArray();
44 |
45 | for (int i = 0; i < valueChars.Length; i++)
46 | {
47 | // Starting from the right of the string, get the index of the character
48 | int index = baseCharsList.IndexOf(valueChars[valueChars.Length - 1 - i]);
49 |
50 | // Add the product of each digit with its place value
51 | result = result + index * (int)Math.Pow(targetBase, i);
52 | }
53 | return result;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/MM2RandoLib/WeaponTable.cs:
--------------------------------------------------------------------------------
1 | using MM2Randomizer.Enums;
2 |
3 | namespace MM2Randomizer
4 | {
5 | ///
6 | /// This object encapsulates
7 | ///
8 | public class WeaponTable
9 | {
10 | ///
11 | /// The name of the weapon.
12 | ///
13 | public string Name { get; set; }
14 |
15 | ///
16 | /// The unique ID of the weapon, which is referred to by the rest of the ROM.
17 | ///
18 | public int ID { get; set; }
19 |
20 | ///
21 | /// Pointer to the damage table for this weapon. This exact address refers to the
22 | /// damage done by this weapon against Heat Man, with the subsequent addresses
23 | /// referring to the next Robot Masters.
24 | /// Address + 0: Heat
25 | /// Address + 1: Air
26 | /// Address + 2: Wood
27 | /// Address + 3: Bubble
28 | /// Address + 4: Quick
29 | /// Address + 5: Flash
30 | /// Address + 6: Metal
31 | /// Address + 7: Clash
32 | ///
33 | public EDmgVsBoss Address { get; set; }
34 |
35 | ///
36 | /// The damage values used by this weapon against each Robot Master. They will be
37 | /// inserted into the offset provided by "Address".
38 | /// [0] = Heat
39 | /// [1] = Air
40 | /// [2] = Wood
41 | /// [3] = Bubble
42 | /// [4] = Quick
43 | /// [5] = Flash
44 | /// [6] = Metal
45 | /// [7] = Clash
46 | ///
47 | public int[] RobotMasters { get; set; }
48 |
49 |
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/MM2RandoLib/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/MM2Randomizer.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27004.2002
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MM2RandoHost", "MM2RandoHost\MM2RandoHost.csproj", "{F12A49E8-C7A7-4FDE-BB7C-EA80451D5B96}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MM2RandoLib", "MM2RandoLib\MM2RandoLib.csproj", "{2F96FE8D-29DC-46F3-9D26-FC85DC2225C8}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|x64 = Debug|x64
14 | Release|Any CPU = Release|Any CPU
15 | Release|x64 = Release|x64
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {F12A49E8-C7A7-4FDE-BB7C-EA80451D5B96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {F12A49E8-C7A7-4FDE-BB7C-EA80451D5B96}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {F12A49E8-C7A7-4FDE-BB7C-EA80451D5B96}.Debug|x64.ActiveCfg = Debug|x64
21 | {F12A49E8-C7A7-4FDE-BB7C-EA80451D5B96}.Debug|x64.Build.0 = Debug|x64
22 | {F12A49E8-C7A7-4FDE-BB7C-EA80451D5B96}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {F12A49E8-C7A7-4FDE-BB7C-EA80451D5B96}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {F12A49E8-C7A7-4FDE-BB7C-EA80451D5B96}.Release|x64.ActiveCfg = Release|x64
25 | {F12A49E8-C7A7-4FDE-BB7C-EA80451D5B96}.Release|x64.Build.0 = Release|x64
26 | {2F96FE8D-29DC-46F3-9D26-FC85DC2225C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {2F96FE8D-29DC-46F3-9D26-FC85DC2225C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {2F96FE8D-29DC-46F3-9D26-FC85DC2225C8}.Debug|x64.ActiveCfg = Debug|x64
29 | {2F96FE8D-29DC-46F3-9D26-FC85DC2225C8}.Debug|x64.Build.0 = Debug|x64
30 | {2F96FE8D-29DC-46F3-9D26-FC85DC2225C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {2F96FE8D-29DC-46F3-9D26-FC85DC2225C8}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {2F96FE8D-29DC-46F3-9D26-FC85DC2225C8}.Release|x64.ActiveCfg = Release|x64
33 | {2F96FE8D-29DC-46F3-9D26-FC85DC2225C8}.Release|x64.Build.0 = Release|x64
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | GlobalSection(ExtensibilityGlobals) = postSolution
39 | SolutionGuid = {0A433506-4D6A-42A1-AD39-F9AF55A48934}
40 | EndGlobalSection
41 | EndGlobal
42 |
--------------------------------------------------------------------------------