mirror of
https://github.com/haven1433/HexManiacAdvance.git
synced 2026-05-16 09:17:05 -05:00
commit
5ef7df15c3
|
|
@ -21,7 +21,7 @@ lt=1011 @ < less than (signed)
|
|||
gt=1100 @ > greater than (signed)
|
||||
le=1101 @ <= less than or equal (signed)
|
||||
al=1110 @ always
|
||||
ne=1111 @ never
|
||||
nv=1111 @ never
|
||||
|
||||
@ opcodes and args
|
||||
0000000000000000 | nop @ does nothing
|
||||
|
|
|
|||
|
|
@ -259,7 +259,9 @@ namespace HavenSoft.HexManiac.Core.Models {
|
|||
// wild pokemon
|
||||
source = Find("0348048009E00000FFFF0000");
|
||||
string table(int length) => $"<[rate:: list<[low. high. species:pokenames]{length}>]1>";
|
||||
AddTable(source, WildTableName, $"[bank. map. unused: grass{table(12)} surf{table(5)} tree{table(5)} fish{table(10)}]");
|
||||
using (ModelCacheScope.CreateScope(this)) { // cares about pokenames
|
||||
AddTable(source, WildTableName, $"[bank. map. unused: grass{table(12)} surf{table(5)} tree{table(5)} fish{table(10)}]");
|
||||
}
|
||||
|
||||
// specials
|
||||
switch (gameCode) {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ namespace HavenSoft.HexManiac.Core.ViewModels.QuickEditItems {
|
|||
var (getTutorMove, canPokemonLearnTutorMove, getTutorMove_Length, canPokemonLearnTutorMove_Length) = GetOffsets(viewPort, gameCode);
|
||||
var specialsAddress = model.GetAddressFromAnchor(token, -1, HardcodeTablesModel.SpecialsTable);
|
||||
var tutorSpecial = model.ReadPointer(specialsAddress + 397 * 4); // Emerald tutors is actually special 477, but we don't need to edit it so it doesn't matter.
|
||||
tutorSpecial -= 1; // the pointer is to thumb code, so it's off by one.
|
||||
|
||||
var tutormoves = model.GetAddressFromAnchor(viewPort.CurrentChange, -1, MoveTutors);
|
||||
var tutorcompatibility = model.GetAddressFromAnchor(viewPort.CurrentChange, -1, TutorCompatibility);
|
||||
|
|
@ -139,11 +140,18 @@ namespace HavenSoft.HexManiac.Core.ViewModels.QuickEditItems {
|
|||
private void UpdateRoutine_TutorSpecial(ViewPort viewPort, int tutorSpecial, string gameCode) {
|
||||
if (gameCode == Emerald) return; // Emerald's tutor special doesn't have a limiter, so it doesn't need to be updated.
|
||||
|
||||
// change the code from 'branch-hi' to 'branch-never' so that the standard codepath is taken for tutorID>14
|
||||
const int instructionIndex = 5;
|
||||
const int instructionWidth = 2;
|
||||
// change the code from 'branch-hi' to 'nop' so that the standard codepath is taken for tutorID>14
|
||||
int instructionIndex = 5;
|
||||
int instructionWidth = 2;
|
||||
var branchOffset = tutorSpecial + instructionIndex * instructionWidth;
|
||||
viewPort.CurrentChange.ChangeData(viewPort.Model, branchOffset, 0xDF);
|
||||
viewPort.Model.WriteMultiByteValue(branchOffset, 2, viewPort.CurrentChange, 0x0000);
|
||||
|
||||
// a separate routine several layers down also needs to be updated
|
||||
// change the code from 'branch-hi' to 'nop' so that the standard codepath is taken for tutorID>14
|
||||
instructionIndex = 20;
|
||||
branchOffset = (gameCode == FireRed) ? 0x11F430 : 0x11F408; // FireRed / LeafGreen
|
||||
branchOffset += instructionIndex * instructionWidth;
|
||||
viewPort.Model.WriteMultiByteValue(branchOffset, 2, viewPort.CurrentChange, 0x0000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using System.Collections.ObjectModel;
|
|||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
|
@ -899,6 +900,11 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
|
|||
results.AddRange(Search(searchBytes).Select(result => (result, result + 3)));
|
||||
}
|
||||
|
||||
// it might be a bl command
|
||||
if (cleanedSearchString.StartsWith("BL ") && cleanedSearchString.Contains("<") && cleanedSearchString.EndsWith(">")) {
|
||||
results.AddRange(FindBranchLink(cleanedSearchString));
|
||||
}
|
||||
|
||||
// attempt to parse the search string fully
|
||||
if (TryParseSearchString(searchBytes, cleanedSearchString, errorOnParseError: results.Count == 0)) {
|
||||
// find matches
|
||||
|
|
@ -915,6 +921,46 @@ namespace HavenSoft.HexManiac.Core.ViewModels {
|
|||
return results;
|
||||
}
|
||||
|
||||
private IEnumerable<(int start, int end)> FindBranchLink(string command) {
|
||||
var addressStart = command.IndexOf(" <") + 2;
|
||||
var addressEnd = command.LastIndexOf(">");
|
||||
if (addressEnd < addressStart) yield break;
|
||||
var addressText = command.Substring(addressStart, addressEnd - addressStart);
|
||||
if (!int.TryParse(addressText, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int address)) {
|
||||
address = Model.GetAddressFromAnchor(CurrentChange, -1, addressText);
|
||||
if (address < 0 || address >= Model.Count) yield break;
|
||||
}
|
||||
|
||||
// I want to know, for any given point in the raw data, if it's possible a branch-link command pointing to `address`
|
||||
// branch link commands are always 4 bytes and have the following format:
|
||||
// 11111 #11 11110 #11, where #=pc+#*2+4
|
||||
// note that this command is 4 bytes long, stored byte reversed. So in the data, it's:
|
||||
// 8 bits: bits 11-18 of a 22 bit signed offset
|
||||
// 8 bits:
|
||||
// the low 3 bits are bits 19-21 of a 22 bit signed offset
|
||||
// the high 5 bits are always 11110
|
||||
// 8 bits: bits 0-7 of a 22 bit signed offset
|
||||
// 8 bits:
|
||||
// the low 3 bits are bits 8-10 of a 22 bit signed offset
|
||||
// the high 5 bits are always 11111
|
||||
// the command is always 2-byte aligned
|
||||
//
|
||||
// bit order is really weird (11-18, 19-21, 0-7, 8-10) because BL is made of **2** instructions,
|
||||
// and each instruction is stored little-endian
|
||||
|
||||
// start as early as possible in the file: maximum offset, or offset for source=0
|
||||
int offset = Math.Min(0b0111111111111111111111, (address - 4) / 2);
|
||||
for (; true; offset--) { // traveling down the offsets means traveling up the source options
|
||||
int source = address - 4 - offset * 2;
|
||||
if (source + 4 > Model.RawData.Length) break;
|
||||
if (Model.RawData[source + 2] != (byte)offset) continue; // check source+2 first because it's the simplest, and thus fastest
|
||||
if (Model.RawData[source + 0] != (byte)(offset >> 11)) continue;
|
||||
if (Model.RawData[source + 3] != (0b11111000 | (0b111 & offset >> 8))) continue;
|
||||
if (Model.RawData[source + 1] != (0b11110000 | (0b111 & offset >> 19))) continue;
|
||||
yield return (source, source + 3);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<(int start, int end)> FindUnquotedText(string cleanedSearchString, List<ISearchByte> searchBytes) {
|
||||
var pcsBytes = PCSString.Convert(cleanedSearchString);
|
||||
pcsBytes.RemoveAt(pcsBytes.Count - 1); // remove the 0xFF that was added, since we're searching for a string segment instead of a whole string.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using HavenSoft.HexManiac.Core.Models;
|
||||
using HavenSoft.HexManiac.Core.Models.Runs;
|
||||
using HavenSoft.HexManiac.Core.ViewModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Input;
|
||||
|
|
@ -335,6 +336,21 @@ namespace HavenSoft.HexManiac.Tests {
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanSearchForBranchLink() {
|
||||
var test = new BaseViewModelTestClass();
|
||||
var command1 = test.ViewPort.Tools.CodeTool.Parser.Compile(test.Model, 0x0010, "bl <000060>").ToArray();
|
||||
var command2 = test.ViewPort.Tools.CodeTool.Parser.Compile(test.Model, 0x0100, "bl <000060>").ToArray();
|
||||
Array.Copy(command1, 0, test.Model.RawData, 0x0010, command1.Length);
|
||||
Array.Copy(command2, 0, test.Model.RawData, 0x0100, command2.Length);
|
||||
|
||||
var results = test.ViewPort.Find("bl <000060>").ToList();
|
||||
|
||||
Assert.Equal(2, results.Count);
|
||||
Assert.Equal(0x010, results[0].start);
|
||||
Assert.Equal(0x100, results[1].start);
|
||||
}
|
||||
|
||||
private void StandardSetup(out byte[] data, out PokemonModel model, out ViewPort viewPort) {
|
||||
data = Enumerable.Repeat((byte)0xFF, 0x200).ToArray();
|
||||
model = new PokemonModel(data);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user