2017-07-25 07:28:43 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
namespace PKHeX.Core
|
|
|
|
|
{
|
2017-07-30 19:31:17 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Miscellaneous setup utility for legality checking <see cref="IEncounterable"/> data sources.
|
|
|
|
|
/// </summary>
|
2017-07-25 07:28:43 +00:00
|
|
|
|
internal static class EncounterUtil
|
|
|
|
|
{
|
2017-07-30 19:31:17 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the relevant <see cref="EncounterStatic"/> objects that appear in the relevant game.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="source">Table of valid encounters that appear for the game pairing</param>
|
|
|
|
|
/// <param name="game">Game to filter for</param>
|
2020-05-31 19:12:07 +00:00
|
|
|
|
/// <returns>Array of encounter objects that can be encountered in the input game</returns>
|
2017-07-30 19:31:17 +00:00
|
|
|
|
internal static EncounterStatic[] GetStaticEncounters(IEnumerable<EncounterStatic> source, GameVersion game)
|
2017-07-25 07:28:43 +00:00
|
|
|
|
{
|
2017-07-30 19:31:17 +00:00
|
|
|
|
return source.Where(s => s.Version.Contains(game)).ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Direct fetch for <see cref="EncounterArea"/> data; can also be used to fetch supplementary encounter streams.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="ident">Unpacking identification ASCII characters (first two bytes of binary)</param>
|
|
|
|
|
/// <param name="resource">Resource name (will be prefixed with "encounter_"</param>
|
|
|
|
|
/// <returns>Array of encounter areas</returns>
|
2019-09-12 05:06:24 +00:00
|
|
|
|
internal static T[] GetEncounterTables<T>(string ident, string resource) where T : EncounterArea32, new()
|
2017-07-25 07:28:43 +00:00
|
|
|
|
{
|
|
|
|
|
byte[] mini = Util.GetBinaryResource($"encounter_{resource}.pkl");
|
2020-03-20 22:18:59 +00:00
|
|
|
|
return EncounterArea32.GetArray<T>(BinLinker.Unpack(mini, ident));
|
2017-07-25 07:28:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-28 06:46:14 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Direct fetch for <see cref="EncounterArea"/> data; can also be used to fetch supplementary encounter streams.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="ident">Unpacking identification ASCII characters (first two bytes of binary)</param>
|
2020-05-31 19:12:07 +00:00
|
|
|
|
/// <param name="resource">Resource name (will be prefixed with "encounter_")</param>
|
2019-11-28 06:46:14 +00:00
|
|
|
|
/// <returns>Array of encounter areas</returns>
|
|
|
|
|
internal static T[] GetEncounterTables8<T>(string ident, string resource) where T : EncounterAreaSH, new()
|
|
|
|
|
{
|
|
|
|
|
byte[] mini = Util.GetBinaryResource($"encounter_{resource}.pkl");
|
2020-03-20 22:18:59 +00:00
|
|
|
|
return EncounterAreaSH.GetArray<T>(BinLinker.Unpack(mini, ident));
|
2019-11-28 06:46:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-30 19:31:17 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Combines <see cref="EncounterArea"/> slot arrays with the same <see cref="EncounterArea.Location"/>.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="tables">Input encounter areas to combine</param>
|
|
|
|
|
/// <returns>Combined Array of encounter areas. No duplicate location IDs will be present.</returns>
|
2019-09-12 05:06:24 +00:00
|
|
|
|
internal static T[] AddExtraTableSlots<T>(params T[][] tables) where T : EncounterArea, new()
|
2017-07-25 07:28:43 +00:00
|
|
|
|
{
|
|
|
|
|
return tables.SelectMany(s => s).GroupBy(l => l.Location)
|
|
|
|
|
.Select(t => t.Count() == 1
|
|
|
|
|
? t.First() // only one table, just return the area
|
2019-09-12 05:06:24 +00:00
|
|
|
|
: new T { Location = t.Key, Slots = t.SelectMany(s => s.Slots).ToArray() })
|
2017-07-25 07:28:43 +00:00
|
|
|
|
.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-30 19:31:17 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Marks Encounter Slots for party lead's ability slot influencing.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>Magnet Pull attracts Steel type slots, and Static attracts Electric</remarks>
|
2020-05-31 19:12:07 +00:00
|
|
|
|
/// <param name="areas">Encounter Area array for game</param>
|
2017-07-30 19:31:17 +00:00
|
|
|
|
/// <param name="t">Personal data for use with a given species' type</param>
|
2020-05-31 19:12:07 +00:00
|
|
|
|
internal static void MarkEncountersStaticMagnetPull(IEnumerable<EncounterArea> areas, PersonalTable t)
|
2017-07-25 07:28:43 +00:00
|
|
|
|
{
|
2020-05-31 19:12:07 +00:00
|
|
|
|
foreach (EncounterArea area in areas)
|
2018-08-03 03:11:42 +00:00
|
|
|
|
{
|
2020-05-31 19:12:07 +00:00
|
|
|
|
foreach (var grp in area.Slots.GroupBy(z => z.Type))
|
2018-08-03 03:11:42 +00:00
|
|
|
|
MarkEncountersStaticMagnetPull(grp, t);
|
|
|
|
|
}
|
2017-12-03 20:20:49 +00:00
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2017-12-03 20:20:49 +00:00
|
|
|
|
internal static void MarkEncountersStaticMagnetPull(IEnumerable<EncounterSlot> grp, PersonalTable t)
|
|
|
|
|
{
|
|
|
|
|
GetStaticMagnet(t, grp, out List<EncounterSlot> s, out List<EncounterSlot> m);
|
|
|
|
|
for (var i = 0; i < s.Count; i++)
|
2017-07-25 07:28:43 +00:00
|
|
|
|
{
|
2017-12-03 20:20:49 +00:00
|
|
|
|
var slot = s[i];
|
|
|
|
|
slot.Permissions.StaticIndex = i;
|
|
|
|
|
slot.Permissions.StaticCount = s.Count;
|
|
|
|
|
}
|
|
|
|
|
for (var i = 0; i < m.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var slot = m[i];
|
|
|
|
|
slot.Permissions.MagnetPullIndex = i;
|
2017-12-14 00:17:02 +00:00
|
|
|
|
slot.Permissions.MagnetPullCount = m.Count;
|
2017-12-03 20:20:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2017-12-03 20:20:49 +00:00
|
|
|
|
internal static void MarkEncountersStaticMagnetPullPermutation(IEnumerable<EncounterSlot> grp, PersonalTable t, List<EncounterSlot> permuted)
|
|
|
|
|
{
|
|
|
|
|
GetStaticMagnet(t, grp, out List<EncounterSlot> s, out List<EncounterSlot> m);
|
|
|
|
|
|
|
|
|
|
// Apply static/magnet values; if any permutation has a unique slot combination, add it to the slot list.
|
|
|
|
|
for (int i = 0; i < s.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var slot = s[i];
|
|
|
|
|
if (slot.Permissions.StaticIndex >= 0) // already has unique data
|
2017-07-25 07:28:43 +00:00
|
|
|
|
{
|
2017-12-03 20:20:49 +00:00
|
|
|
|
if (slot.IsMatchStatic(i, s.Count))
|
|
|
|
|
continue; // same values, no permutation
|
|
|
|
|
if (permuted.Any(z => z.SlotNumber == slot.SlotNumber && z.IsMatchStatic(i, s.Count) && z.Species == slot.Species))
|
|
|
|
|
continue; // same values, previously permuted
|
|
|
|
|
|
|
|
|
|
s[i] = slot = slot.Clone();
|
|
|
|
|
permuted.Add(slot);
|
2017-07-25 07:28:43 +00:00
|
|
|
|
}
|
2017-12-03 20:20:49 +00:00
|
|
|
|
slot.Permissions.StaticIndex = i;
|
|
|
|
|
slot.Permissions.StaticCount = s.Count;
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < m.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var slot = m[i];
|
|
|
|
|
if (slot.Permissions.MagnetPullIndex >= 0) // already has unique data
|
2017-07-25 07:28:43 +00:00
|
|
|
|
{
|
2017-12-03 20:20:49 +00:00
|
|
|
|
if (slot.IsMatchStatic(i, m.Count))
|
|
|
|
|
continue; // same values, no permutation
|
|
|
|
|
if (permuted.Any(z => z.SlotNumber == slot.SlotNumber && z.IsMatchMagnet(i, m.Count) && z.Species == slot.Species))
|
|
|
|
|
continue; // same values, previously permuted
|
|
|
|
|
|
|
|
|
|
m[i] = slot = slot.Clone();
|
|
|
|
|
permuted.Add(slot);
|
2017-07-25 07:28:43 +00:00
|
|
|
|
}
|
2017-12-03 20:20:49 +00:00
|
|
|
|
slot.Permissions.MagnetPullIndex = i;
|
|
|
|
|
slot.Permissions.MagnetPullCount = m.Count;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2017-12-03 20:20:49 +00:00
|
|
|
|
private static void GetStaticMagnet(PersonalTable t, IEnumerable<EncounterSlot> grp, out List<EncounterSlot> s, out List<EncounterSlot> m)
|
|
|
|
|
{
|
|
|
|
|
const int steel = (int)MoveType.Steel;
|
|
|
|
|
const int electric = (int)MoveType.Electric + 1; // offset by 1 in gen3/4 for the ??? type
|
|
|
|
|
s = new List<EncounterSlot>();
|
|
|
|
|
m = new List<EncounterSlot>();
|
|
|
|
|
foreach (EncounterSlot Slot in grp)
|
|
|
|
|
{
|
2018-03-25 20:53:48 +00:00
|
|
|
|
var p = t[Slot.Species];
|
|
|
|
|
if (p.IsType(steel))
|
2017-12-03 20:20:49 +00:00
|
|
|
|
m.Add(Slot);
|
2018-03-25 20:53:48 +00:00
|
|
|
|
if (p.IsType(electric))
|
2017-12-03 20:20:49 +00:00
|
|
|
|
s.Add(Slot);
|
2017-07-25 07:28:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-30 19:31:17 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sets the <see cref="EncounterSlot1.Version"/> value, for use in determining split-generation origins.
|
|
|
|
|
/// </summary>
|
2018-10-31 20:52:09 +00:00
|
|
|
|
/// <remarks>Only used for Gen 1 & 2, as <see cref="PKM.Version"/> data is not present.</remarks>
|
2020-05-31 19:12:07 +00:00
|
|
|
|
/// <param name="areas">In-game encounter data</param>
|
|
|
|
|
/// <param name="game">Version ID to set</param>
|
|
|
|
|
internal static void MarkEncountersVersion(IEnumerable<EncounterArea> areas, GameVersion game)
|
2017-07-25 07:28:43 +00:00
|
|
|
|
{
|
2020-05-31 19:12:07 +00:00
|
|
|
|
foreach (EncounterArea area in areas)
|
2018-08-03 03:11:42 +00:00
|
|
|
|
{
|
2020-05-31 19:12:07 +00:00
|
|
|
|
foreach (var Slot in area.Slots)
|
|
|
|
|
Slot.Version = game;
|
2018-08-03 03:11:42 +00:00
|
|
|
|
}
|
2017-07-25 07:28:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-30 19:31:17 +00:00
|
|
|
|
/// <summary>
|
2020-05-17 19:32:28 +00:00
|
|
|
|
/// Sets the <see cref="IGenerationSet.Generation"/> value.
|
2017-07-30 19:31:17 +00:00
|
|
|
|
/// </summary>
|
2020-05-31 19:12:07 +00:00
|
|
|
|
/// <param name="generation">Generation number to set</param>
|
|
|
|
|
/// <param name="encounters">In-game encounter data</param>
|
|
|
|
|
internal static void MarkEncountersGeneration(int generation, params IEnumerable<IGenerationSet>[] encounters)
|
2017-07-25 07:28:43 +00:00
|
|
|
|
{
|
2020-05-31 19:12:07 +00:00
|
|
|
|
foreach (var table in encounters)
|
|
|
|
|
MarkEncountersGeneration(generation, table);
|
2017-12-19 00:17:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2020-05-17 19:32:28 +00:00
|
|
|
|
/// Sets the <see cref="IGenerationSet.Generation"/> value, for use in determining split-generation origins.
|
2017-12-19 00:17:21 +00:00
|
|
|
|
/// </summary>
|
2020-05-31 19:12:07 +00:00
|
|
|
|
/// <param name="generation">Generation number to set</param>
|
|
|
|
|
/// <param name="areas">In-game encounter data</param>
|
|
|
|
|
internal static void MarkEncountersGeneration(int generation, params IEnumerable<EncounterArea>[] areas)
|
2017-12-19 00:17:21 +00:00
|
|
|
|
{
|
2020-05-31 19:12:07 +00:00
|
|
|
|
foreach (var table in areas)
|
2018-08-03 03:11:42 +00:00
|
|
|
|
{
|
|
|
|
|
foreach (var area in table)
|
2020-05-31 19:12:07 +00:00
|
|
|
|
MarkEncountersGeneration(generation, area.Slots);
|
2018-08-03 03:11:42 +00:00
|
|
|
|
}
|
2017-12-19 00:17:21 +00:00
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2020-05-31 19:12:07 +00:00
|
|
|
|
private static void MarkEncountersGeneration(int generation, IEnumerable<IGenerationSet> encounters)
|
2017-12-19 00:17:21 +00:00
|
|
|
|
{
|
2020-05-31 19:12:07 +00:00
|
|
|
|
foreach (var enc in encounters)
|
|
|
|
|
enc.Generation = generation;
|
2017-07-25 07:28:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-30 19:31:17 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Groups areas by location id, raw data has areas with different slots but the same location id.
|
|
|
|
|
/// </summary>
|
2019-09-12 05:06:24 +00:00
|
|
|
|
/// <remarks>Similar to <see cref="AddExtraTableSlots{T}"/>, this method combines a single array.</remarks>
|
2017-07-30 19:31:17 +00:00
|
|
|
|
/// <param name="Areas">Ingame encounter data</param>
|
2019-09-12 05:06:24 +00:00
|
|
|
|
internal static void ReduceAreasSize<T>(ref T[] Areas) where T : EncounterArea, new()
|
2017-07-25 07:28:43 +00:00
|
|
|
|
{
|
2019-09-12 05:06:24 +00:00
|
|
|
|
Areas = Areas.GroupBy(a => a.Location).Select(a => new T
|
2017-07-25 07:28:43 +00:00
|
|
|
|
{
|
2017-12-19 00:17:21 +00:00
|
|
|
|
Location = a.Key,
|
2017-07-25 07:28:43 +00:00
|
|
|
|
Slots = a.SelectMany(m => m.Slots).ToArray()
|
|
|
|
|
}).ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-18 15:37:40 +00:00
|
|
|
|
internal static T[] ConcatAll<T>(params IEnumerable<T>[] arr) => arr.SelectMany(z => z).ToArray();
|
2017-11-26 02:16:50 +00:00
|
|
|
|
|
2019-09-12 05:06:24 +00:00
|
|
|
|
internal static void MarkEncounterAreaArray<T>(params T[][] areas) where T : EncounterArea
|
2017-07-25 07:28:43 +00:00
|
|
|
|
{
|
2017-11-26 02:16:50 +00:00
|
|
|
|
foreach (var area in areas)
|
|
|
|
|
MarkEncounterAreas(area);
|
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2019-09-12 05:06:24 +00:00
|
|
|
|
private static void MarkEncounterAreas<T>(params T[] areas) where T : EncounterArea
|
2017-11-26 02:16:50 +00:00
|
|
|
|
{
|
|
|
|
|
foreach (var area in areas)
|
2018-08-03 03:11:42 +00:00
|
|
|
|
{
|
|
|
|
|
foreach (var slot in area.Slots)
|
|
|
|
|
slot.Area = area;
|
|
|
|
|
}
|
2017-07-25 07:28:43 +00:00
|
|
|
|
}
|
2018-03-09 05:18:32 +00:00
|
|
|
|
|
|
|
|
|
internal static EncounterStatic Clone(this EncounterStatic s, int location)
|
|
|
|
|
{
|
|
|
|
|
var result = s.Clone();
|
|
|
|
|
result.Location = location;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2018-03-09 05:18:32 +00:00
|
|
|
|
internal static EncounterStatic[] Clone(this EncounterStatic s, int[] locations)
|
|
|
|
|
{
|
|
|
|
|
EncounterStatic[] Encounters = new EncounterStatic[locations.Length];
|
|
|
|
|
for (int i = 0; i < locations.Length; i++)
|
|
|
|
|
Encounters[i] = s.Clone(locations[i]);
|
|
|
|
|
return Encounters;
|
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2018-03-09 05:18:32 +00:00
|
|
|
|
internal static IEnumerable<EncounterStatic> DreamRadarClone(this EncounterStatic s)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < 8; i++)
|
2018-08-03 03:11:42 +00:00
|
|
|
|
yield return s.DreamRadarClone((5 * i) + 5); // Level from 5->40 depends on the number of badges
|
2018-03-09 05:18:32 +00:00
|
|
|
|
}
|
2018-08-03 03:11:42 +00:00
|
|
|
|
|
2018-03-09 05:18:32 +00:00
|
|
|
|
private static EncounterStatic DreamRadarClone(this EncounterStatic s, int level)
|
|
|
|
|
{
|
|
|
|
|
var result = s.Clone(level);
|
|
|
|
|
result.Level = level;
|
|
|
|
|
result.Location = 30015;// Pokemon Dream Radar
|
|
|
|
|
result.Gift = true; // Only
|
|
|
|
|
result.Ball = 25; // Dream Ball
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2018-03-27 05:23:11 +00:00
|
|
|
|
|
2020-07-18 20:36:30 +00:00
|
|
|
|
internal static void MarkEncounterTradeStrings<T>(T[] table, string[][] strings) where T : EncounterTrade
|
2018-03-27 05:23:11 +00:00
|
|
|
|
{
|
|
|
|
|
int half = strings[1].Length / 2;
|
PKHeX.Core Nullable cleanup (#2401)
* Handle some nullable cases
Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data)
Make some classes have explicit constructors instead of { } initialization
* Handle bits more obviously without null
* Make SaveFile.BAK explicitly readonly again
* merge constructor methods to have readonly fields
* Inline some properties
* More nullable handling
* Rearrange box actions
define straightforward classes to not have any null properties
* Make extrabyte reference array immutable
* Move tooltip creation to designer
* Rearrange some logic to reduce nesting
* Cache generated fonts
* Split mystery gift album purpose
* Handle more tooltips
* Disallow null setters
* Don't capture RNG object, only type enum
* Unify learnset objects
Now have readonly properties which are never null
don't new() empty learnsets (>800 Learnset objects no longer created,
total of 2400 objects since we also new() a move & level array)
optimize g1/2 reader for early abort case
* Access rewrite
Initialize blocks in a separate object, and get via that object
removes a couple hundred "might be null" warnings since blocks are now readonly getters
some block references have been relocated, but interfaces should expose all that's needed
put HoF6 controls in a groupbox, and disable
* Readonly personal data
* IVs non nullable for mystery gift
* Explicitly initialize forced encounter moves
* Make shadow objects readonly & non-null
Put murkrow fix in binary data resource, instead of on startup
* Assign dex form fetch on constructor
Fixes legality parsing edge cases
also handle cxd parse for valid; exit before exception is thrown in FrameGenerator
* Remove unnecessary null checks
* Keep empty value until init
SetPouch sets the value to an actual one during load, but whatever
* Readonly team lock data
* Readonly locks
Put locked encounters at bottom (favor unlocked)
* Mail readonly data / offset
Rearrange some call flow and pass defaults
Add fake classes for SaveDataEditor mocking
Always party size, no need to check twice in stat editor
use a fake save file as initial data for savedata editor, and for
gamedata (wow i found a usage)
constrain eventwork editor to struct variable types (uint, int, etc),
thus preventing null assignment errors
2019-10-17 01:47:31 +00:00
|
|
|
|
for (int i = 0; i < half; i++)
|
2018-03-27 05:23:11 +00:00
|
|
|
|
{
|
|
|
|
|
var t = table[i];
|
|
|
|
|
t.Nicknames = getNames(i, strings);
|
|
|
|
|
t.TrainerNames = getNames(i + half, strings);
|
|
|
|
|
}
|
PKHeX.Core Nullable cleanup (#2401)
* Handle some nullable cases
Refactor MysteryGift into a second abstract class (backed by a byte array, or fake data)
Make some classes have explicit constructors instead of { } initialization
* Handle bits more obviously without null
* Make SaveFile.BAK explicitly readonly again
* merge constructor methods to have readonly fields
* Inline some properties
* More nullable handling
* Rearrange box actions
define straightforward classes to not have any null properties
* Make extrabyte reference array immutable
* Move tooltip creation to designer
* Rearrange some logic to reduce nesting
* Cache generated fonts
* Split mystery gift album purpose
* Handle more tooltips
* Disallow null setters
* Don't capture RNG object, only type enum
* Unify learnset objects
Now have readonly properties which are never null
don't new() empty learnsets (>800 Learnset objects no longer created,
total of 2400 objects since we also new() a move & level array)
optimize g1/2 reader for early abort case
* Access rewrite
Initialize blocks in a separate object, and get via that object
removes a couple hundred "might be null" warnings since blocks are now readonly getters
some block references have been relocated, but interfaces should expose all that's needed
put HoF6 controls in a groupbox, and disable
* Readonly personal data
* IVs non nullable for mystery gift
* Explicitly initialize forced encounter moves
* Make shadow objects readonly & non-null
Put murkrow fix in binary data resource, instead of on startup
* Assign dex form fetch on constructor
Fixes legality parsing edge cases
also handle cxd parse for valid; exit before exception is thrown in FrameGenerator
* Remove unnecessary null checks
* Keep empty value until init
SetPouch sets the value to an actual one during load, but whatever
* Readonly team lock data
* Readonly locks
Put locked encounters at bottom (favor unlocked)
* Mail readonly data / offset
Rearrange some call flow and pass defaults
Add fake classes for SaveDataEditor mocking
Always party size, no need to check twice in stat editor
use a fake save file as initial data for savedata editor, and for
gamedata (wow i found a usage)
constrain eventwork editor to struct variable types (uint, int, etc),
thus preventing null assignment errors
2019-10-17 01:47:31 +00:00
|
|
|
|
string[] getNames(int i, IEnumerable<string[]> names) => names.Select(z => z.Length > i ? z[i] : string.Empty).ToArray();
|
2018-03-27 05:23:11 +00:00
|
|
|
|
}
|
2018-03-30 23:31:40 +00:00
|
|
|
|
|
2020-05-20 04:46:05 +00:00
|
|
|
|
internal static void MarkEncounterGame<T>(IEnumerable<T> table, GameVersion version) where T: IVersion, IVersionSet
|
2018-03-30 23:31:40 +00:00
|
|
|
|
{
|
2020-05-20 04:46:05 +00:00
|
|
|
|
foreach (var t in table.Where(z => ((IVersion)z).Version == GameVersion.Any))
|
|
|
|
|
((IVersionSet)t).Version = version;
|
2018-03-30 23:31:40 +00:00
|
|
|
|
}
|
2017-07-25 07:28:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|