Proper boss fight detection
This commit is contained in:
		
							parent
							
								
									66afa7e2cb
								
							
						
					
					
						commit
						4e0c6ab197
					
				
							
								
								
									
										163
									
								
								rabi_splitter_WPF/BossFightConfig.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								rabi_splitter_WPF/BossFightConfig.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,163 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| 
 | ||||
| namespace rabi_splitter_WPF | ||||
| { | ||||
|     // The descriptions of all the boss fights are listed here. | ||||
|     // Fields can be omitted to keep them unspecified. | ||||
|     public partial class BossFight | ||||
|     { | ||||
|         public static BossFight UNKNOWN = | ||||
|             new BossFight ( | ||||
|                 displayName: "UNKNOWN" | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Cocoa1 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Cocoa1", | ||||
|                 music: Music.GET_ON_WITH_IT, | ||||
|                 map: Map.SouthernWoodland, | ||||
|                 startingBosses: new[] {Boss.Cocoa} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Ribbon = | ||||
|             new BossFight ( | ||||
|                 displayName: "Ribbon", | ||||
|                 music: Music.GET_ON_WITH_IT, | ||||
|                 map: Map.SouthernWoodland, | ||||
|                 startingBosses: new[] {Boss.Ribbon} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Ashuri1 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Ashuri1", | ||||
|                 music: Music.GET_ON_WITH_IT, | ||||
|                 map: Map.WesternCoast, | ||||
|                 startingBosses: new[] {Boss.Ashuri} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Ashuri2 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Ashuri2", | ||||
|                 music: Music.BRAWL_BREAKS_VER_2, | ||||
|                 map: Map.EasternHighlands, | ||||
|                 startingBosses: new[] {Boss.Ashuri} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight BigBox = | ||||
|             new BossFight ( | ||||
|                 displayName: "Big Box", | ||||
|                 music: Music.MIDBOSS_BATTLE, | ||||
|                 map: Map.EasternHighlands, | ||||
|                 startingBosses: new[] {Boss.BigBox} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight RainbowMaid = | ||||
|             new BossFight ( | ||||
|                 displayName: "Rainbow Maid", | ||||
|                 music: Music.MIDBOSS_BATTLE, | ||||
|                 map: Map.EasternHighlands, | ||||
|                 startingBosses: new[] {Boss.RainbowMaid} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Seana1 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Seana1", | ||||
|                 music: Music.KITTY_ATTACK, | ||||
|                 map: Map.NorthernTundra, | ||||
|                 startingBosses: new[] {Boss.Seana} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Seana2 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Seana2", | ||||
|                 music: Music.BOUNCE_BOUNCE, | ||||
|                 map: Map.IslandCore, | ||||
|                 startingBosses: new[] {Boss.Seana} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Kotri1 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Kotri1", | ||||
|                 music: Music.BRAWL_BREAKS, | ||||
|                 map: Map.IslandCore, | ||||
|                 startingBosses: new[] {Boss.Kotri} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Kotri2 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Kotri2", | ||||
|                 music: Music.BRAWL_BREAKS, | ||||
|                 map: Map.WesternCoast, | ||||
|                 startingBosses: new[] {Boss.Kotri} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Kotri3 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Kotri3", | ||||
|                 music: Music.BRAWL_BREAKS, | ||||
|                 map: Map.SubterraneanArea, | ||||
|                 startingBosses: new[] {Boss.Kotri} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Alius1 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Alius1", | ||||
|                 music: Music.SUDDEN_DEATH, | ||||
|                 map: Map.WarpDestination, | ||||
|                 startingBosses: new[] {Boss.IllusionAlius} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Alius2 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Alius2", | ||||
|                 music: Music.SUDDEN_DEATH, | ||||
|                 map: Map.WarpDestination, | ||||
|                 startingBosses: new[] {Boss.Noah1, Boss.IllusionAlius} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Alius3 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Alius3", | ||||
|                 music: Music.SUDDEN_DEATH, | ||||
|                 map: Map.WarpDestination, | ||||
|                 startingBosses: new[] {Boss.Noah1} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Miru = | ||||
|             new BossFight ( | ||||
|                 displayName: "Miru", | ||||
|                 music: Music.M_R_, | ||||
|                 map: Map.WarpDestination, | ||||
|                 startingBosses: new[] {Boss.Miru} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Noah1 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Noah1", | ||||
|                 music: Music.THE_TRUTH_NEVER_SPOKEN, | ||||
|                 map: Map.WarpDestination, | ||||
|                 startingBosses: new[] {Boss.Noah1} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight Noah3 = | ||||
|             new BossFight ( | ||||
|                 displayName: "Noah3", | ||||
|                 music: Music.RFN_III, | ||||
|                 map: Map.WarpDestination, | ||||
|                 startingBosses: new[] {Boss.Noah3} | ||||
|             ); | ||||
| 
 | ||||
|         public static BossFight SideChapter = | ||||
|             new BossFight ( | ||||
|                 displayName: "Side Chapter", | ||||
|                 music: Music.GET_ON_WITH_IT, | ||||
|                 map: Map.RabiRabiTown, | ||||
|                 extraCondition: (startingBosses, music, map) => { | ||||
|                     return startingBosses.Count == 3; | ||||
|                 } | ||||
|             ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										99
									
								
								rabi_splitter_WPF/BossFightEnum.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								rabi_splitter_WPF/BossFightEnum.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Reflection; | ||||
| 
 | ||||
| namespace rabi_splitter_WPF | ||||
| { | ||||
|     /// <summary> | ||||
|     /// enum | ||||
|     /// </summary> | ||||
|     public partial class BossFight | ||||
|     { | ||||
|         // Do not make these properties public. | ||||
|         private static int nextAvailableValue = 0; | ||||
|         private readonly int _value; | ||||
|         private static BossFight[] _bossFights; | ||||
| 
 | ||||
|         // Do not make these properties static. | ||||
|         public readonly string displayName; | ||||
|         public readonly Music? music; | ||||
|         public readonly Map? map; | ||||
|         public readonly HashSet<Boss> startingBosses; | ||||
|         public readonly Func<HashSet<Boss>, Music, Map, bool> extraCondition; | ||||
| 
 | ||||
|         private BossFight(string displayName = null, | ||||
|                             Music? music = null, | ||||
|                             Map? map = null, | ||||
|                             Boss[] startingBosses = null, | ||||
|                             Func<HashSet<Boss>, Music, Map, bool> extraCondition = null) | ||||
|         { | ||||
|             _value = nextAvailableValue++; | ||||
|             this.displayName = displayName; | ||||
|             this.music = music; | ||||
|             this.map = map; | ||||
|             this.startingBosses = (startingBosses != null) ? new HashSet<Boss>(startingBosses) : null; | ||||
|             this.extraCondition = extraCondition; | ||||
|         } | ||||
|          | ||||
|         public int Value | ||||
|         { | ||||
|             get { return _value; } | ||||
|         } | ||||
|          | ||||
|         public override string ToString() | ||||
|         { | ||||
|             return displayName; | ||||
|         } | ||||
| 
 | ||||
|         private static BossFight[] GetAllBossFights() | ||||
|         { | ||||
|             var type = typeof(BossFight); | ||||
|             var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); | ||||
| 
 | ||||
|             var bossFights = new List<BossFight>(); | ||||
|             foreach (var info in fields) | ||||
|             { | ||||
|                 var instance = new BossFight(); | ||||
|                 var locatedValue = info.GetValue(instance) as BossFight; | ||||
| 
 | ||||
|                 if (locatedValue != null && locatedValue != BossFight.UNKNOWN) | ||||
|                 { | ||||
|                     bossFights.Add(locatedValue); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return bossFights.ToArray(); | ||||
|         } | ||||
| 
 | ||||
|         public static IEnumerable<BossFight> GetBossFights() | ||||
|         { | ||||
|             if (_bossFights == null) _bossFights = GetAllBossFights(); | ||||
| 
 | ||||
|             foreach (var bossFight in _bossFights) | ||||
|             { | ||||
|                 yield return bossFight; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public override bool Equals(object obj) | ||||
|         { | ||||
|             var otherValue = obj as BossFight; | ||||
| 
 | ||||
|             if (otherValue == null) | ||||
|             { | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             var typeMatches = GetType().Equals(obj.GetType()); | ||||
|             var valueMatches = _value.Equals(otherValue.Value); | ||||
| 
 | ||||
|             return typeMatches && valueMatches; | ||||
|         } | ||||
| 
 | ||||
|         public override int GetHashCode() | ||||
|         { | ||||
|             return _value.GetHashCode(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										84
									
								
								rabi_splitter_WPF/BossFightIdentifier.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								rabi_splitter_WPF/BossFightIdentifier.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| 
 | ||||
| namespace rabi_splitter_WPF | ||||
| { | ||||
|     public static partial class BossFightIdentifier | ||||
|     { | ||||
|         private static ILookup<Tuple<Music, Map>, BossFight> _matchMusicAndMap; | ||||
|         private static ILookup<Music, BossFight> _matchMusic; | ||||
|         private static ILookup<Map, BossFight> _matchMap; | ||||
|         private static BossFight[] _remainingDescriptions; | ||||
| 
 | ||||
|         static BossFightIdentifier() | ||||
|         { | ||||
|             // Build dictionaries here. | ||||
|             var specifiedMusicAndMap = new List<BossFight>(); | ||||
|             var specifiedMusicOnly = new List<BossFight>(); | ||||
|             var specifiedMapOnly = new List<BossFight>(); | ||||
|             var specifiedNeither = new List<BossFight>(); | ||||
|              | ||||
|             foreach (var bossFight in BossFight.GetBossFights()) | ||||
|             { | ||||
|                 //if (bossFight == null) continue; | ||||
|                 if (bossFight.music != null) | ||||
|                 { | ||||
|                     if (bossFight.map != null) specifiedMusicAndMap.Add(bossFight); | ||||
|                     else specifiedMusicOnly.Add(bossFight); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if (bossFight.map != null) specifiedMapOnly.Add(bossFight); | ||||
|                     else specifiedNeither.Add(bossFight); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             _matchMusicAndMap = specifiedMusicAndMap.ToLookup(bossFight => new Tuple<Music, Map>(bossFight.music.Value, bossFight.map.Value), bossFight => bossFight); | ||||
|             _matchMusic = specifiedMusicOnly.ToLookup(bossFight => bossFight.music.Value, bossFight => bossFight); | ||||
|             _matchMap = specifiedMapOnly.ToLookup(bossFight => bossFight.map.Value, bossFight => bossFight); | ||||
|             _remainingDescriptions = specifiedNeither.ToArray(); | ||||
|         } | ||||
| 
 | ||||
|         private static bool Matches(BossFight bossFight, HashSet<Boss> startingBosses, Music music, Map map) | ||||
|         { | ||||
|             if (bossFight.startingBosses != null && !bossFight.startingBosses.SetEquals(startingBosses)) return false; | ||||
|             if (bossFight.extraCondition == null) return true; | ||||
|             return bossFight.extraCondition(startingBosses, music, map); | ||||
|         } | ||||
| 
 | ||||
|         public static BossFight IdentifyBossFight(MemorySnapshot snapshot) | ||||
|         { | ||||
|             Music? music_ = StaticData.GetMusic(snapshot.musicid); | ||||
|             Map? map_ = StaticData.GetMap(snapshot.mapid); | ||||
|             if (music_ == null || map_ == null) return BossFight.UNKNOWN; | ||||
| 
 | ||||
|             var music = music_.Value; | ||||
|             var map = map_.Value; | ||||
|             var startingBosses = new HashSet<Boss>(snapshot.bossList | ||||
|                 .Select(bossStats => StaticData.GetBoss(bossStats.id)) | ||||
|                 .Where(boss => boss != null) | ||||
|                 .Select(boss => boss.Value) | ||||
|             ); | ||||
|              | ||||
|             foreach (var bossFight in _matchMusicAndMap[new Tuple<Music, Map>(music, map)]) | ||||
|             { | ||||
|                 if (Matches(bossFight, startingBosses, music, map)) return bossFight; | ||||
|             } | ||||
| 
 | ||||
|             foreach (var bossFight in _matchMusic[music]) | ||||
|             { | ||||
|                 if (Matches(bossFight, startingBosses, music, map)) return bossFight; | ||||
|             } | ||||
| 
 | ||||
|             foreach (var bossFight in _matchMap[map]) | ||||
|             { | ||||
|                 if (Matches(bossFight, startingBosses, music, map)) return bossFight; | ||||
|             } | ||||
| 
 | ||||
|             return _remainingDescriptions.FirstOrDefault(bossFight => Matches(bossFight, startingBosses, music, map)) ?? BossFight.UNKNOWN; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
| @ -6,7 +6,7 @@ using System.Text; | ||||
| 
 | ||||
| namespace rabi_splitter_WPF | ||||
| { | ||||
|     struct BossStats | ||||
|     public struct BossStats | ||||
|     { | ||||
|         public int entityArrayIndex; | ||||
|         public int id; | ||||
| @ -15,7 +15,7 @@ namespace rabi_splitter_WPF | ||||
|         public int maxHp; | ||||
|     } | ||||
| 
 | ||||
|     class MemorySnapshot | ||||
|     public class MemorySnapshot | ||||
|     { | ||||
|         public readonly int t_playtime; | ||||
|         public readonly int playtime; | ||||
|  | ||||
| @ -94,7 +94,8 @@ namespace rabi_splitter_WPF | ||||
|                 DebugLog($"Minimap Shift! {prevSnapshot.minimapPosition} -> {snapshot.minimapPosition}"); | ||||
|                 if (snapshot.minimapPosition == 1) | ||||
|                 { | ||||
|                     DebugLog($"Fighting Boss: {string.Join(", ", snapshot.bossList.Select(boss => StaticData.GetBossName(boss.id)))}"); | ||||
|                     DebugLog($"BOSS FIGHT: {BossFightIdentifier.IdentifyBossFight(snapshot).displayName}"); | ||||
|                     DebugLog($"Fighting Bosses: {string.Join(", ", snapshot.bossList.Select(boss => StaticData.GetBossName(boss.id)))}"); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|  | ||||
| @ -55,6 +55,9 @@ | ||||
|       <Generator>MSBuild:Compile</Generator> | ||||
|       <SubType>Designer</SubType> | ||||
|     </ApplicationDefinition> | ||||
|     <Compile Include="BossFightIdentifier.cs" /> | ||||
|     <Compile Include="BossFightConfig.cs" /> | ||||
|     <Compile Include="BossFightEnum.cs" /> | ||||
|     <Compile Include="InGameState.cs" /> | ||||
|     <Compile Include="RabiEnums.cs" /> | ||||
|     <Compile Include="MemorySnapshot.cs" /> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user