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