// example serialized pokemon: // // 50 Butterfree (31)@"Silk Powder" // - "Stun Spore" // - "Super Sonic" // - "Aerial Ace" // - "Silver Wind" public IStreamRun DeserializeRun(string content, ModelDelta token) { var lines = content.Split(Environment.NewLine).Select(line => line.Trim()).ToArray(); // step 1: parse it into some data containers var data = new TeamData(ModelCacheScope.GetCache(model), lines); // step 2: figure out what I need based on the data var elementLength = data.MovesIncluded ? 16 : 8; var totalLength = elementLength * data.Pokemon.Count; var workingRun = this; if (totalLength > workingRun.Length) { workingRun = (TrainerPokemonTeamRun)model.RelocateForExpansion(token, workingRun, totalLength); } // step 3: write the run data WriteData(token, workingRun.Start, data); // step 4: write the parent data var structType = (data.ItemsIncluded ? INCLUDE_ITEM : 0) ^ (data.MovesIncluded ? INCLUDE_MOVES : 0); UpdateParents(token, structType, data.Pokemon.Count, workingRun.PointerSources); return(new TrainerPokemonTeamRun(model, workingRun.Start, workingRun.PointerSources)); }
public PLMRun(IDataModel dataModel, int start) { model = dataModel; var moveNames = ModelCacheScope.GetCache(dataModel).GetOptions(EggMoveRun.MoveNamesTable); Start = start; for (int i = Start; i < model.Count; i += 2) { var value = model.ReadMultiByteValue(i, 2); if (value == 0xFFFF) { Length = i - Start + 2; break; } // validate value var(level, move) = SplitToken(value); if (level > 101 || level < 1) { break; } if (move > moveNames.Count) { break; } } }
public IStreamRun DeserializeRun(string content, ModelDelta token) { var cache = ModelCacheScope.GetCache(model); var cachedPokenames = cache.GetOptions(PokemonNameTable); var cachedMovenames = cache.GetOptions(MoveNamesTable); var data = new List<int>(); var pokemonNames = cachedPokenames.Select(name => $"{GroupStart}{name.Trim('"').ToLower()}{GroupEnd}").ToList(); var moveNames = cachedMovenames.Select(name => name.Trim('"').ToLower()).ToList(); var lines = content.ToLower().Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { var index = pokemonNames.IndexOf(line); if (index != -1) { data.Add(index + MagicNumber); continue; } index = moveNames.IndexOf(line); if (index != -1) { data.Add(index); continue; } // didn't find an exact match... look for a partial pokemon match var matchFound = false; for (int i = 0; i < pokemonNames.Count; i++) { if (pokemonNames[i].Contains(line)) { data.Add(i + MagicNumber); matchFound = true; break; } } if (matchFound) continue; // look for a partial move match for (int i = 0; i < moveNames.Count; i++) { if (moveNames[i].Contains(line)) { data.Add(i); break; } } } var run = model.RelocateForExpansion(token, this, data.Count * 2 + 2); for (int i = 0; i < data.Count; i++) model.WriteMultiByteValue(run.Start + i * 2, 2, token, data[i]); model.WriteMultiByteValue(run.Start + data.Count * 2, 2, token, EndStream); // write the new end token for (int i = data.Count + 2; i < Length / 2; i++) model.WriteMultiByteValue(run.Start + i * 2, 2, token, EndStream); // fill any remaining old space with FF return new EggMoveRun(model, run.Start); }
public int GetMoveNumber(string input) { var cache = ModelCacheScope.GetCache(model); var cachedMovenames = cache.GetOptions(MoveNamesTable); input = input.Trim('"').ToLower(); var names = cachedMovenames.Select(name => name.Trim('"').ToLower()).ToList(); return names.IndexOfPartial(input); }
public IEnumerable<string> GetAutoCompleteOptions() { var cache = ModelCacheScope.GetCache(model); var cachedPokenames = cache.GetOptions(PokemonNameTable); var cachedMovenames = cache.GetOptions(MoveNamesTable); var pokenames = cachedPokenames.Select(name => $"{GroupStart}{name}{GroupEnd}"); // closing brace, so no space needed var movenames = cachedMovenames.Select(name => name + " "); // autocomplete needs to complete after selection, so add a space return pokenames.Concat(movenames); }
public int GetPokemonNumber(string input) { var cache = ModelCacheScope.GetCache(model); var cachedPokenames = cache.GetOptions(PokemonNameTable); if (input.StartsWith(GroupStart)) input = input.Substring(1, input.Length - 2); input = input.ToLower(); var names = cachedPokenames.Select(name => name.Trim('"').ToLower()).ToList(); return names.IndexOfPartial(input); }
public static bool TrySearch(IDataModel data, ModelDelta changeToken, string originalFormat, out ArrayRun self, Func <IFormattedRun, bool> runFilter = null) { self = null; var format = originalFormat; var allowPointersToEntries = format.StartsWith(AnchorStart.ToString()); if (allowPointersToEntries) { format = format.Substring(1); } var closeArray = format.LastIndexOf(ArrayEnd.ToString()); if (!format.StartsWith(ArrayStart.ToString()) || closeArray == -1) { throw new ArrayRunParseException($"Array Content must be wrapped in {ArrayStart}{ArrayEnd}"); } var segments = format.Substring(1, closeArray - 1); var length = format.Substring(closeArray + 1); var elementContent = ParseSegments(segments, data); if (elementContent.Count == 0) { return(false); } var elementLength = elementContent.Sum(e => e.Length); using (ModelCacheScope.CreateScope(data)) { if (string.IsNullOrEmpty(length)) { var bestAddress = StandardSearch(data, elementContent, elementLength, out int bestLength, runFilter); if (bestAddress == Pointer.NULL) { return(false); } self = new ArrayRun(data, originalFormat + bestLength, string.Empty, bestAddress, bestLength, elementContent, data.GetNextRun(bestAddress).PointerSources, null); } else { var bestAddress = KnownLengthSearch(data, elementContent, elementLength, length, out int bestLength, runFilter); if (bestAddress == Pointer.NULL) { return(false); } var lengthFromAnchor = int.TryParse(length, out var _) ? string.Empty : length; self = new ArrayRun(data, originalFormat, lengthFromAnchor, bestAddress, bestLength, elementContent, data.GetNextRun(bestAddress).PointerSources, null); } } if (allowPointersToEntries) { self = self.AddSourcesPointingWithinArray(changeToken); } return(true); }
public static ErrorInfo TryParse(IDataModel data, string format, int start, IReadOnlyList <int> pointerSources, out ArrayRun self) { try { using (ModelCacheScope.CreateScope(data)) { self = new ArrayRun(data, format, start, pointerSources); } } catch (ArrayRunParseException e) { self = null; return(new ErrorInfo(e.Message)); } return(ErrorInfo.NoError); }
public string SerializeRun() { var cache = ModelCacheScope.GetCache(model); var buffer = new StringBuilder(); for (int i = 0; i < ElementCount; i++) { var start = Start + ElementLength * i; var ivSpread = model.ReadMultiByteValue(start + 0, 2); if (!showFullIVByteRange) { ivSpread = (int)Math.Round(ivSpread * IV_Cap / 255.0); } var level = model.ReadMultiByteValue(start + 2, 2); var pokeID = model.ReadMultiByteValue(start + 4, 2); var pokemonNames = cache.GetOptions(HardcodeTablesModel.PokemonNameTable); var pokemon = pokemonNames.Count > pokeID ? pokemonNames[pokeID] : pokeID.ToString(); start += 6; var item = string.Empty; if ((StructType & INCLUDE_ITEM) != 0) { var itemID = model.ReadMultiByteValue(start, 2); var itemNames = cache.GetOptions(HardcodeTablesModel.ItemsTableName); item = itemNames.Count > itemID ? itemNames[itemID] : itemID.ToString(); item = "@" + item; start += 2; } buffer.AppendLine($"{level} {pokemon} (IVs={ivSpread}){item}"); if ((StructType & INCLUDE_MOVES) != 0) { var moveNames = cache.GetOptions(HardcodeTablesModel.MoveNamesTable); for (int j = 0; j < 4; j++) { var moveID = model.ReadMultiByteValue(start + j * 2, 2); var move = moveNames.Count > moveID ? moveNames[moveID] : moveID.ToString(); buffer.AppendLine($"- {move}"); } } else { buffer.AppendLine(); } if (i + 1 < ElementCount) { buffer.AppendLine(); } } return(buffer.ToString()); }
public IDataFormat CreateDataFormat(IDataModel data, int index) { Debug.Assert(data == model); var moveNames = ModelCacheScope.GetCache(model).GetOptions(EggMoveRun.MoveNamesTable); var position = index - Start; var groupStart = position % 2 == 1 ? position - 1 : position; position -= groupStart; var value = data.ReadMultiByteValue(Start + groupStart, 2); var(level, move) = SplitToken(value); var moveName = moveNames.Count > move ? moveNames[move] : move.ToString(); return(new PlmItem(groupStart + Start, position, level, move, moveName)); }
public IStreamRun DeserializeRun(string content, ModelDelta token) { var data = new List <int>(); var moveNames = ModelCacheScope.GetCache(model).GetOptions(EggMoveRun.MoveNamesTable); moveNames = moveNames.Select(name => name.Trim('"').ToLower()).ToList(); var lines = content.ToLower().Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { var parts = line.Split(new[] { ' ' }, 2); if (!int.TryParse(parts[0], out var level)) { level = 0; } var moveName = parts.Length == 1 ? "0" : parts[1]; moveName = moveName.Trim().Trim('"'); var index = moveNames.IndexOf(moveName); if (index != -1) { data.Add(CombineToken(level, index)); continue; } // look for a partial move match for (int i = 0; i < moveNames.Count; i++) { if (moveNames[i].MatchesPartial(moveName)) { data.Add(CombineToken(level, i)); break; } } } var run = model.RelocateForExpansion(token, this, data.Count * 2 + 2); for (int i = 0; i < data.Count; i++) { model.WriteMultiByteValue(run.Start + i * 2, 2, token, data[i]); } model.WriteMultiByteValue(run.Start + data.Count * 2, 2, token, EggMoveRun.EndStream); // write the new end token for (int i = data.Count + 2; i < Length / 2; i++) { model.WriteMultiByteValue(run.Start + i * 2, 2, token, EggMoveRun.EndStream); // fill any remaining old space with FF } return(new PLMRun(model, run.Start)); }
public string SerializeRun() { var moveNames = ModelCacheScope.GetCache(model).GetOptions(EggMoveRun.MoveNamesTable); var builder = new StringBuilder(); for (int i = 0; i < Length - 2; i += 2) { var address = Start + i; var(level, move) = SplitToken(model.ReadMultiByteValue(address, 2)); var moveName = moveNames.Count > move ? moveNames[move] : move.ToString(); builder.Append($"{level} {moveName}"); if (i < Length - 4) { builder.AppendLine(); } } return(builder.ToString()); }
public string SerializeRun() { var cache = ModelCacheScope.GetCache(model); var cachedPokenames = cache.GetOptions(PokemonNameTable); var cachedMovenames = cache.GetOptions(MoveNamesTable); var builder = new StringBuilder(); for (int i = 0; i < Length - 2; i += 2) { var address = Start + i; var value = model.ReadMultiByteValue(address, 2); if (value >= MagicNumber) { value -= MagicNumber; builder.Append($"{GroupStart}{cachedPokenames[value].Trim('"')}{GroupEnd}"); } else { builder.Append(cachedMovenames[value].Trim('"')); } if (i < Length - 4) builder.AppendLine(); } return builder.ToString(); }
public bool TryGetMoveNumber(string moveName, out int move) { moveName = moveName.Trim('"').ToLower(); var moveNames = ModelCacheScope.GetCache(model).GetOptions(EggMoveRun.MoveNamesTable); var names = moveNames.Select(name => name.Trim('"').ToLower()).ToList(); // perfect match? move = names.IndexOf(moveName); if (move != -1) { return(true); } // partial match? move = names.IndexOfPartial(moveName); // last try: numeric match return(move != -1 || int.TryParse(moveName, out move)); }
public void AppendTo(IDataModel model, StringBuilder text, int start, int length, bool deep) { var cache = ModelCacheScope.GetCache(model); var cachedPokenames = cache.GetOptions(PokemonNameTable); var cachedMovenames = cache.GetOptions(MoveNamesTable); while (length > 0 && start < Start + Length) { var value = model.ReadMultiByteValue(start, 2); if (value == EndStream) { text.Append($"{GroupStart}{GroupEnd}"); } else if (value >= MagicNumber) { value -= MagicNumber; if (value >= cachedPokenames.Count) text.Append($"{GroupStart}{value}{GroupEnd}"); else text.Append($"{GroupStart}{cachedPokenames[value].Trim('"')}{GroupEnd}"); } else { if (value >= cachedMovenames.Count) text.Append($"{value}"); else text.Append($"{cachedMovenames[value]}"); } start += 2; length -= 2; if (length > 0 && start < Start + Length) text.Append(" "); } }
public override IDataFormat CreateDataFormat(IDataModel data, int dataIndex) { Debug.Assert(data == model); var cache = ModelCacheScope.GetCache(data); var cachedPokenames = cache.GetOptions(PokemonNameTable); var cachedMovenames = cache.GetOptions(MoveNamesTable); var position = dataIndex - Start; var groupStart = position % 2 == 1 ? position - 1 : position; position -= groupStart; var value = data.ReadMultiByteValue(Start + groupStart, 2); if (value >= MagicNumber) { value -= MagicNumber; string content = cachedPokenames.Count > value ? cachedPokenames[value] : value.ToString(); if (value == EndStream - MagicNumber) content = string.Empty; if (content.StartsWith("\"")) content = content.Substring(1); if (content.EndsWith("\"")) content = content.Substring(0, content.Length - 1); return new EggSection(groupStart + Start, position, $"{GroupStart}{content}{GroupEnd}"); } else { string content = cachedMovenames.Count > value ? cachedMovenames[value] : value.ToString(); return new EggItem(groupStart + Start, position, content); } }
public TeamData(ModelCacheScope cache, string[] lines) { var currentPokemonMoveCount = 0; var moveNames = cache.GetOptions(HardcodeTablesModel.MoveNamesTable); var itemNames = cache.GetOptions(HardcodeTablesModel.ItemsTableName); var pokemonNames = cache.GetOptions(HardcodeTablesModel.PokemonNameTable); foreach (var line in lines) { if (line.Trim() is "") { continue; } if (line.StartsWith("-")) { if (pokemons.Count == 0) { continue; } if (currentPokemonMoveCount > 3) { continue; } MovesIncluded = true; var move = line.Substring(1).Trim(); var moveIndex = moveNames.IndexOfPartial(move); if (moveIndex < 0) { moveIndex = 0; } moves[(pokemons.Count - 1) * 4 + currentPokemonMoveCount] = moveIndex; currentPokemonMoveCount++; } else { if (pokemons.Count == 6) { continue; } var levelTokenized = line.Split(new[] { ' ' }, 2); if (levelTokenized.Length != 2) { continue; } if (!int.TryParse(levelTokenized[0], out int level)) { continue; } levels.Add(level); var itemTokenized = levelTokenized[1].Split(new[] { '@' }, 2); AddItem(itemNames, items, itemTokenized); var ivTokenized = itemTokenized[0].Split(new[] { '(' }, 2); AddIV(ivs, ivTokenized); var pokemon = ivTokenized[0].Trim(); var pokemonIndex = pokemonNames.IndexOfPartial(pokemon); if (pokemonIndex < 0) { pokemonIndex = 0; } pokemons.Add(pokemonIndex); moves.AddRange(new[] { 0, 0, 0, 0 }); currentPokemonMoveCount = 0; } } }
public IEnumerable <string> GetAutoCompleteOptions(string header) { var moveNames = ModelCacheScope.GetCache(model).GetOptions(EggMoveRun.MoveNamesTable); return(moveNames.Select(name => $"{header} {name}" + (name.EndsWith("\"") ? "" : " "))); // autocomplete needs to complete after selection, so add a space if there's no quotes }
private static (ElementContentType format, int formatLength, int segmentLength) ExtractSingleFormat(string segments, IDataModel model) { if (segments.Length >= 2 && segments.Substring(0, 2) == PCSRun.SharedFormatString) { var format = ElementContentType.PCS; var formatLength = 2; while (formatLength < segments.Length && char.IsDigit(segments[formatLength])) { formatLength++; } if (int.TryParse(segments.Substring(2, formatLength - 2), out var segmentLength)) { return(format, formatLength, segmentLength); } } else if (segments.StartsWith(DoubleByteIntegerFormat + string.Empty + DoubleByteIntegerFormat)) { return(ElementContentType.Integer, 2, 4); } else if (segments.StartsWith(DoubleByteIntegerFormat + string.Empty + SingleByteIntegerFormat) || segments.StartsWith(".:")) { return(ElementContentType.Integer, 2, 3); } else if (segments.StartsWith(DoubleByteIntegerFormat.ToString())) { return(ElementContentType.Integer, 1, 2); } else if (segments.StartsWith(SingleByteIntegerFormat.ToString())) { return(ElementContentType.Integer, 1, 1); } else if (segments.Length > 0 && segments[0] == PointerRun.PointerStart) { var openCount = 1; var endIndex = 1; while (openCount > 0 && endIndex < segments.Length) { if (segments[endIndex] == PointerRun.PointerStart) { openCount += 1; } else if (segments[endIndex] == PointerRun.PointerEnd) { openCount -= 1; } endIndex += 1; } if (openCount > 0) { return(ElementContentType.Unknown, 0, 0); } return(ElementContentType.Pointer, endIndex, 4); } else if (segments.StartsWith(BitArray.SharedFormatString)) { var endIndex = BitArray.SharedFormatString.Length; while (segments.Length > endIndex && char.IsLetterOrDigit(segments[endIndex])) { endIndex++; } var format = segments.Substring(0, endIndex); var name = format.Substring(BitArray.SharedFormatString.Length); var options = ModelCacheScope.GetCache(model).GetBitOptions(name); var count = options?.Count ?? 8; return(ElementContentType.BitArray, format.Length, (int)Math.Ceiling(count / 8.0)); } return(ElementContentType.Unknown, 0, 0); }