Preparation fo Mystery rolling
This commit is contained in:
153
ALttPRandomizer/Model/MysterySettings.cs
Normal file
153
ALttPRandomizer/Model/MysterySettings.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
namespace ALttPRandomizer.Model {
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Microsoft.OpenApi;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
public class MysterySettings {
|
||||
public RandomizableWeights<Mode> Mode { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<Weapons> Weapons { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<Goal> Goal { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<EntryRequirement> CrystalsGanon { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<BossRequirement> BossesGanon { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<TriforceRequirement> TriforcePieces { get; set; } = new();
|
||||
|
||||
[YamlMember(Alias = "crystals_gt")]
|
||||
public RandomizableWeights<EntryRequirement> CrystalsGT { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<GanonItem> GanonItem { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<EntranceShuffle> EntranceShuffle { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<OverworldMapDungeons> OverworldMapDungeons { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<LinksHouse> LinksHouse { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<SkullWoodsShuffle> SkullWoods { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<LinkedDrops> LinkedDrops { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<BossShuffle> BossShuffle { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<EnemyShuffle> EnemyShuffle { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<DamageTableShuffle> DamageTableShuffle { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<KeyLocations> SmallKeys { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<DungeonItemLocations> BigKeys { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<DungeonItemLocations> Maps { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<DungeonItemLocations> Compasses { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<ShowLoot> ShowLoot { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<ShowLootHud> ShowLootHud { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<ShowMap> ShowMap { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<ShopShuffle> ShopShuffle { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<DropShuffle> DropShuffle { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<PotShuffle> PotShuffle { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<PrizeShuffle> PrizeShuffle { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<BootsSettings> Boots { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<FluteSettings> Flute { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<DarkRoomSettings> DarkRooms { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<BombSettings> Bombs { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<BookSettings> Book { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<MirrorSettings> Mirror { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<DoorShuffle> DoorShuffle { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<DoorLobbies> Lobbies { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<DoorTypeMode> DoorTypeMode { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<TrapDoorMode> TrapDoorMode { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<ExtraKeysMode> ExtraKeys { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<FollowerShuffle> FollowerShuffle { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<FluteShuffle> FluteShuffle { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<OverworldLayout> OverworldLayout { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<OverworldWorldLayouts> OverworldWorldLayouts { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<OverworldLayoutTerrain> OverworldLayoutTerrain { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<OverworldLayoutEdges> OverworldLayoutEdges { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<OverworldMapFog> OverworldMapFog { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<TileSwap> TileSwap { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<DamageChallengeMode> DamageChallenge { get; set; } = new();
|
||||
|
||||
public RandomizableWeights<Hints> Hints { get; set; } = new();
|
||||
}
|
||||
|
||||
public class DefaultMysterySettingsFilter : IOperationFilter {
|
||||
private readonly MysterySettings exampleMystery;
|
||||
private readonly JsonNode? exampleMysteryJson;
|
||||
|
||||
public DefaultMysterySettingsFilter() {
|
||||
this.exampleMystery = new MysterySettings();
|
||||
|
||||
var mysteryFields = typeof(MysterySettings).GetProperties();
|
||||
|
||||
foreach (var field in mysteryFields) {
|
||||
var type = field.PropertyType;
|
||||
|
||||
if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(RandomizableWeights<>)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Type itemType = type.GetGenericArguments()[0];
|
||||
Type innerType = typeof(RandomizableWeights<>).MakeGenericType(itemType)!;
|
||||
|
||||
var weights = innerType.GetProperty("EqualAll")?.GetValue(null);
|
||||
|
||||
if (weights != null) {
|
||||
field.SetValue(this.exampleMystery, weights);
|
||||
}
|
||||
}
|
||||
|
||||
this.exampleMysteryJson = JsonSerializer.SerializeToNode(this.exampleMystery, JsonOptions.Default);
|
||||
}
|
||||
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context) {
|
||||
foreach (var description in context.ApiDescription.ParameterDescriptions) {
|
||||
if (description.Type != typeof(MysterySettings)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (description.Source.Id == "Body") {
|
||||
if (operation.RequestBody != null && operation.RequestBody.Content != null) {
|
||||
foreach ((_, var value) in operation.RequestBody.Content) {
|
||||
value.Example = this.exampleMysteryJson;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
ALttPRandomizer/Model/RandomizableWeights.cs
Normal file
80
ALttPRandomizer/Model/RandomizableWeights.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
namespace ALttPRandomizer.Model {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
public interface IRandomizableWeights {
|
||||
public bool IsEmpty { get; }
|
||||
|
||||
public object? Roll();
|
||||
}
|
||||
|
||||
public class RandomizableWeights<T> : IRandomizableWeights where T : struct, Enum {
|
||||
private static readonly Random random = new();
|
||||
|
||||
public ImmutableList<(T Item, int Weight)> Options { get; }
|
||||
public int TotalWeights { get; }
|
||||
|
||||
public RandomizableWeights(IList<(T Item, int Weight)>? items = null) {
|
||||
if (items == null) {
|
||||
this.TotalWeights = 0;
|
||||
this.Options = ImmutableList<(T, int)>.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
int totalWeight = 0;
|
||||
var builder = new List<(T, int)>();
|
||||
foreach (var pair in items) {
|
||||
if (pair.Weight < 0) {
|
||||
throw new ArgumentException("Weights must be non-negative", $"items[{pair.Item}]");
|
||||
}
|
||||
|
||||
if (pair.Weight > 0) {
|
||||
builder.Add(pair);
|
||||
totalWeight += pair.Weight;
|
||||
}
|
||||
}
|
||||
|
||||
this.TotalWeights = totalWeight;
|
||||
this.Options = builder.ToImmutableList();
|
||||
}
|
||||
|
||||
public static RandomizableWeights<T> EmptyWeights => new();
|
||||
|
||||
public static RandomizableWeights<T> EqualAll {
|
||||
get => RandomizableWeights<T>.FromDictionary(Enum.GetValues<T>().ToDictionary(v => v, v => 1));
|
||||
}
|
||||
|
||||
public static RandomizableWeights<T> ConstantWeights(T value) {
|
||||
return new(new List<(T, int)> { (value, 100) });
|
||||
}
|
||||
|
||||
public static RandomizableWeights<T> FromDictionary(IDictionary<T, int> dict) {
|
||||
return new(dict.Select(kvp => (kvp.Key, kvp.Value)).ToList());
|
||||
}
|
||||
|
||||
public bool IsEmpty { get => this.Options.Count == 0; }
|
||||
|
||||
public T? Roll() {
|
||||
if (this.TotalWeights <= 0) {
|
||||
return default;
|
||||
}
|
||||
|
||||
int value = random.Next(this.TotalWeights);
|
||||
|
||||
foreach (var (item, weight) in this.Options) {
|
||||
value -= weight;
|
||||
|
||||
if (value < 0) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
// should never reach
|
||||
return default;
|
||||
}
|
||||
|
||||
object? IRandomizableWeights.Roll() => Roll();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace ALttPRandomizer.Model {
|
||||
using ALttPRandomizer.Settings;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using YamlDotNet.Serialization;
|
||||
using static ALttPRandomizer.Model.RandomizerInstance;
|
||||
|
||||
public class SeedSettings {
|
||||
@@ -541,7 +541,7 @@
|
||||
|
||||
public enum DamageChallengeMode {
|
||||
Normal,
|
||||
OHKO,
|
||||
[JsonStringEnumMemberName("ohko")] OHKO,
|
||||
Gloom,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user