Initial SMWE revision.

This commit is contained in:
Michael Scire
2016-11-22 00:36:08 -08:00
parent a46c6690ca
commit e033bf2491
2 changed files with 207 additions and 132 deletions

View File

@@ -124,6 +124,7 @@ private void Menu_Exit_Click(object sender, EventArgs e)
}
private void formClosing(object sender, FormClosingEventArgs e)
{
if (Config == null) return;
var g = Config.GARCGameText;
string[][] files = Config.GameTextStrings;
Invoke((Action)(() => new TextEditor(files, "gametext").ShowDialog()));
@@ -528,7 +529,7 @@ private void B_Wild_Click(object sender, EventArgs e)
else return;
break;
case 7:
files = new [] { "encdata", "zonedata" };
files = new [] { "encdata", "zonedata", "worlddata" };
action = () => new SMWE().ShowDialog();
break;
default:

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Windows.Forms;
@@ -23,6 +24,22 @@ public SMWE()
for (int i = 0; i < locationList.Length; i++)
locationList[i] = locationList[i].Replace("\r", "");
var metSM_00000 = locationList;
var metSM_00000_good = (string[])metSM_00000.Clone();
for (int i = 0; i < metSM_00000.Length; i += 2)
{
var nextLoc = metSM_00000[i + 1];
if (!string.IsNullOrWhiteSpace(nextLoc) && nextLoc[0] != '[')
metSM_00000_good[i] += $" ({nextLoc})";
if (i > 0 && !string.IsNullOrWhiteSpace(metSM_00000_good[i]) && metSM_00000_good.Take(i - 1).Contains(metSM_00000_good[i]))
metSM_00000_good[i] += $" ({metSM_00000_good.Take(i - 1).Count(s => s == metSM_00000_good[i]) + 1})";
}
metSM_00000_good.CopyTo(metSM_00000, 0);
metSM_00000.CopyTo(locationList, 0);
nup_spec = new[]
{NUP_Forme1, NUP_Forme2, NUP_Forme3, NUP_Forme4, NUP_Forme5, NUP_Forme6, NUP_Forme7, NUP_Forme8, NUP_Forme9, NUP_Forme10};
cb_spec = new[]
@@ -35,16 +52,39 @@ public SMWE()
foreach (var l in rate_spec)
l.Text = "0%";
worldData = File.ReadAllBytes(zdpaths[0]); // 1.bin
zoneData = File.ReadAllBytes(zdpaths[1]); // dec_0.bin
Zones = new Zone[zoneData.Length / 0x54];
var Worlds = wdpaths.Select(f => mini.unpackMini(File.ReadAllBytes(f), "WD")[0]).ToArray();
for (int i = 0; i < Zones.Length; i++)
{
Zones[i] = new Zone(i);
Zones[i].WorldIndex = BitConverter.ToUInt16(worldData, i * 0x2);
var World = Worlds[Zones[i].WorldIndex];
var mappingOffset = BitConverter.ToInt32(World, 0x8);
for (var ofs = mappingOffset; ofs < World.Length; ofs += 4)
{
if (BitConverter.ToUInt16(World, ofs) == i)
{
Zones[i].AreaIndex = BitConverter.ToUInt16(World, ofs + 2);
break;
}
}
}
LoadData("encdata");
}
private Map[] Maps;
private Area[] Areas;
private Zone[] Zones;
public static readonly string[] speciesList = Main.getText(TextName.SpeciesNames);
public static readonly string[] locationList = Main.getText(TextName.metlist_000000);
public static readonly string[] zdpaths = Directory.GetFiles("zonedata");
public static readonly string[] wdpaths = Directory.GetFiles("worlddata");
public static byte[] zoneData;
public static byte[] worldData;
private readonly NumericUpDown[] nup_spec;
private readonly ComboBox[] cb_spec;
@@ -58,35 +98,38 @@ public void LoadData(string dir)
{
loadingdata = true;
var files = (new DirectoryInfo(dir).GetFiles());
var NumMaps = files.Length/11;
Maps = new Map[NumMaps];
var numNames = new Dictionary<string, int>();
for (int i = 0; i < NumMaps; i++)
var numAreas = files.Length / 11;
Areas = new Area[numAreas];
for (int i = 0; i < numAreas; i++)
{
Maps[i] = new Map();
Maps[i].Name = locationList[BitConverter.ToUInt32(zoneData, 0x1C+i*0x54)];
if (numNames.ContainsKey(Maps[i].Name))
Areas[i] = new Area();
Areas[i].FullPath = files[9 + 11 * i].FullName;
Areas[i].Zones = Zones.Where(z => z.AreaIndex == i).ToArray();
var md = File.ReadAllBytes(Areas[i].FullPath);
if (md.Length > 0)
{
numNames[Maps[i].Name] += 1;
Maps[i].Name += $" ({numNames[Maps[i].Name]})";
}
else
numNames[Maps[i].Name] = 1;
Maps[i].Name = $"{i.ToString("000")} - {Maps[i].Name}";
Maps[i].FullPath = files[9 + 11*i].FullName;
byte[][] Tables = mini.unpackMini(File.ReadAllBytes(Maps[i].FullPath), "EA");
Maps[i].HasTables = Tables.Any(t => t.Length > 0);
if (Maps[i].HasTables)
{
foreach (var Table in Tables)
byte[][] Tables = mini.unpackMini(md, "EA");
Areas[i].HasTables = Tables.Any(t => t.Length > 0);
if (Areas[i].HasTables)
{
Maps[i].Tables.Add(new EncounterTable(Table));
foreach (var Table in Tables)
{
var DayTable = Table.Skip(4).Take(0x164).ToArray();
var NightTable = Table.Skip(0x168).ToArray();
Areas[i].Tables.Add(new EncounterTable(DayTable));
Areas[i].Tables.Add(new EncounterTable(NightTable));
}
}
}
else
{
Areas[i].HasTables = false;
}
}
Areas = Areas.OrderBy(a => a.Zones[0].Name).ToArray();
CB_LocationID.Items.Clear();
CB_LocationID.Items.AddRange(Maps.Select(m => m.Name).ToArray());
CB_LocationID.Items.AddRange(Areas.Select(a => a.Name).ToArray());
foreach (Control ctrl in Controls)
{
@@ -94,6 +137,7 @@ public void LoadData(string dir)
}
B_Randomize.Enabled = false; // TODO: Randomization
CB_LocationID.SelectedIndex = 0;
loadingdata = false;
updateMap(null, null);
@@ -107,7 +151,7 @@ private void DumpTables(object sender, EventArgs e)
if (sfd.ShowDialog() != DialogResult.OK)
return;
var sb = new StringBuilder();
foreach (var Map in Maps)
foreach (var Map in Areas)
sb.Append(Map.ToString());
File.WriteAllText(sfd.FileName, sb.ToString());
}
@@ -117,7 +161,7 @@ private void updateMap(object sender, EventArgs e)
{
loadingdata = true;
CB_TableID.Items.Clear();
CB_TableID.Items.AddRange(Enumerable.Range(1, Math.Max(Maps[CB_LocationID.SelectedIndex].Tables.Count, 1)).Select(i => i.ToString()).ToArray());
CB_TableID.Items.AddRange(Enumerable.Range(1, Math.Max(Areas[CB_LocationID.SelectedIndex].Tables.Count, 1)).Select(i => i.ToString()).ToArray());
CB_TableID.SelectedIndex = 0;
CB_SlotType.SelectedIndex = 0;
loadingdata = false;
@@ -129,7 +173,7 @@ private void updatePanel(object sender, EventArgs e)
if (loadingdata)
return;
loadingdata = true;
var Map = Maps[CB_LocationID.SelectedIndex];
var Map = Areas[CB_LocationID.SelectedIndex];
GB_Encounters.Enabled = Map.HasTables;
if (!Map.HasTables)
{
@@ -190,154 +234,184 @@ private void updateSpeciesForm(object sender, EventArgs e)
private void B_Save_Click(object sender, EventArgs e)
{
CurrentTable.Write();
Maps[CB_LocationID.SelectedIndex].Tables[CB_TableID.SelectedIndex] = CurrentTable;
Areas[CB_LocationID.SelectedIndex].Tables[CB_TableID.SelectedIndex] = CurrentTable;
}
private void B_Export_Click(object sender, EventArgs e)
{
B_Save_Click(sender, e);
foreach (var Map in Maps)
foreach (var Map in Areas)
{
var packed = mini.packMini(Map.Tables.Select(t => t.Data).ToArray(), "EA");
byte[][] tabs = new byte[Map.Tables.Count / 2][];
for (int i = 0; i < Map.Tables.Count; i += 2)
{
tabs[i] = new byte[4].Concat(Map.Tables[i].Data).Concat(Map.Tables[i + 1].Data).ToArray();
}
var packed = mini.packMini(tabs, "EA");
File.WriteAllBytes(Map.FullPath, packed);
}
MessageBox.Show("Exported all tables!");
}
}
internal class Map
{
public string Name;
public string FullPath;
public bool HasTables;
public List<EncounterTable> Tables;
public Map()
internal class Area
{
Tables = new List<EncounterTable>();
}
public string Name => string.Join(" / ", Zones.Select(z => z.Name));
public string FullPath;
public bool HasTables;
public List<EncounterTable> Tables;
public Zone[] Zones;
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine("==========");
sb.AppendLine($"Map: {Name}");
sb.AppendLine($"Tables: {Tables.Count}");
for (int i = 0; i < Tables.Count; i++)
public Area()
{
sb.AppendLine($"Table {i+1}:");
sb.AppendLine(Tables[i].ToString());
Tables = new List<EncounterTable>();
}
sb.AppendLine("==========");
return sb.ToString();
}
}
internal class EncounterTable
{
public int MinLevel;
public int MaxLevel;
public int[] Rates;
public Encounter[][] Encounters;
public byte[] Data;
public EncounterTable(byte[] t)
{
// Tables are stored twice. Validate. Throw error if I need more research
for (var ofs = 0; ofs < 0x150; ofs += 4)
public override string ToString()
{
if (BitConverter.ToUInt32(t, ofs) != BitConverter.ToUInt32(t, 0x164+ofs))
throw new ArgumentException("Mismatched duplicate table. More research is needed. Contact SciresM at ProjectPokemon.org.");
}
Rates = new int[10];
Encounters = new Encounter[8][];
MinLevel = t[4];
MaxLevel = t[5];
for (int i = 0; i < Rates.Length; i++)
Rates[i] = t[6 + i];
for (int i = 0; i < Encounters.Length; i++)
{
Encounters[i] = new Encounter[10];
var ofs = 0x10 + i*4*Encounters[i].Length;
for (int j = 0; j < Encounters[i].Length; j++)
var sb = new StringBuilder();
sb.AppendLine("==========");
sb.AppendLine($"Map: {Name}");
sb.AppendLine($"Tables: {Tables.Count / 2}");
for (int i = 0; i < Tables.Count / 2; i++)
{
Encounters[i][j] = new Encounter(BitConverter.ToUInt32(t, ofs + 4 * j));
sb.AppendLine($"Table {(i + 1)} (Day):");
sb.AppendLine(Tables[i * 2].ToString());
sb.AppendLine($"Table {(i + 1)} (Night):");
sb.AppendLine(Tables[i * 2 + 1].ToString());
}
sb.AppendLine("==========");
return sb.ToString();
}
Data = (byte[])t.Clone();
}
public void Write()
internal class Zone
{
Data[4] = (byte) MinLevel;
Data[5] = (byte) MaxLevel;
// TODO: Rate Editing?
for (int i = 0; i < Encounters.Length; i++)
private byte[] Data;
public int index;
public int WorldIndex;
public int AreaIndex;
public string Name => $"{index.ToString("000")} - {locationList[BitConverter.ToUInt32(Data, 0x1C)]}";
public Zone(int i)
{
var ofs = 0x10 + i*4*Encounters[i].Length;
for (int j = 0; j < Encounters[i].Length; j++)
{
BitConverter.GetBytes(Encounters[i][j].RawValue).CopyTo(Data, ofs + 4*j);
}
Data = new byte[0x54];
Array.Copy(zoneData, i * 0x54, Data, 0, 0x54);
index = i;
}
// Duplicate table.
Array.Copy(Data, 0, Data, 0x164, 0x150);
}
public override string ToString()
internal class EncounterTable
{
var sb = new StringBuilder();
for (int i = 0; i < Encounters.Length; i++)
public int MinLevel;
public int MaxLevel;
public int[] Rates;
public Encounter[][] Encounters;
public Encounter[] AdditionalSOS;
public byte[] Data;
public EncounterTable(byte[] t)
{
sb.Append($"Slot Type {i + 1} (Levels {MinLevel}-{MaxLevel}): ");
var specToRate = new Dictionary<uint, int>();
var distincts = new List<Encounter>();
for(int j = 0; j < Encounters[i].Length; j++)
Rates = new int[10];
Encounters = new Encounter[8][];
MinLevel = t[0];
MaxLevel = t[1];
for (int i = 0; i < Rates.Length; i++)
Rates[i] = t[2 + i];
for (int i = 0; i < Encounters.Length; i++)
{
var encounter = Encounters[i][j];
if (!specToRate.ContainsKey(encounter.RawValue))
Encounters[i] = new Encounter[10];
var ofs = 0xC + i * 4 * Encounters[i].Length;
for (int j = 0; j < Encounters[i].Length; j++)
{
specToRate[encounter.RawValue] = 0;
distincts.Add(encounter);
Encounters[i][j] = new Encounter(BitConverter.ToUInt32(t, ofs + 4 * j));
}
specToRate[encounter.RawValue] += Rates[j];
}
distincts = distincts.OrderBy(e => specToRate[e.RawValue]).Reverse().ToList();
sb.AppendLine(string.Join(", ", distincts.Select(e => $"{e.ToString()} ({specToRate[e.RawValue]}%)")));
AdditionalSOS = new Encounter[6];
for (var i = 0; i < AdditionalSOS.Length; i++)
{
AdditionalSOS[i] = new Encounter(BitConverter.ToUInt32(t, 0x14C + 4 * i));
}
Data = (byte[])t.Clone();
}
return sb.ToString();
}
}
public void Write()
{
Data[0] = (byte)MinLevel;
Data[1] = (byte)MaxLevel;
// TODO: Rate Editing?
for (int i = 0; i < Encounters.Length; i++)
{
var ofs = 0xC + i * 4 * Encounters[i].Length;
for (int j = 0; j < Encounters[i].Length; j++)
{
BitConverter.GetBytes(Encounters[i][j].RawValue).CopyTo(Data, ofs + 4 * j);
}
}
for (int i = 0; i < AdditionalSOS.Length; i++)
BitConverter.GetBytes(AdditionalSOS[i].RawValue).CopyTo(Data, 0x14C + 4 * i);
}
internal class Encounter
{
public uint Species;
public uint Forme;
public override string ToString()
{
var sb = new StringBuilder();
for (int i = 0; i < Encounters.Length; i++)
{
var tn = "Encounters";
if (i != 0)
tn = "SOS Slot " + (i);
sb.Append($"{tn} (Levels {MinLevel}-{MaxLevel}): ");
var specToRate = new Dictionary<uint, int>();
var distincts = new List<Encounter>();
for (int j = 0; j < Encounters[i].Length; j++)
{
var encounter = Encounters[i][j];
if (!specToRate.ContainsKey(encounter.RawValue))
{
specToRate[encounter.RawValue] = 0;
distincts.Add(encounter);
}
specToRate[encounter.RawValue] += Rates[j];
}
distincts = distincts.OrderBy(e => specToRate[e.RawValue]).Reverse().ToList();
sb.AppendLine(string.Join(", ", distincts.Select(e => $"{e.ToString()} ({specToRate[e.RawValue]}%)")));
}
sb.Append("Additional SOS encounters: ");
sb.AppendLine(string.Join(", ", AdditionalSOS.Select(e => e.RawValue).Distinct().Select(e => new Encounter(e)).Select(e => e.ToString())));
public uint RawValue => Species | (Forme << 11);
public Encounter()
{
Species = 0;
Forme = 0;
return sb.ToString();
}
}
public Encounter(uint val)
internal class Encounter
{
Species = val & 0x7FF;
Forme = (val >> 11) & 0x1F;
}
public uint Species;
public uint Forme;
public override string ToString()
{
var sb = new StringBuilder();
sb.Append(SMWE.speciesList[Species]);
if (Forme != 0)
sb.Append($" (Forme {Forme})");
return sb.ToString();
public uint RawValue => Species | (Forme << 11);
public Encounter()
{
Species = 0;
Forme = 0;
}
public Encounter(uint val)
{
Species = val & 0x7FF;
Forme = (val >> 11) & 0x1F;
}
public override string ToString()
{
var sb = new StringBuilder();
sb.Append(speciesList[Species]);
if (Forme != 0)
sb.Append($" (Forme {Forme})");
return sb.ToString();
}
}
}
}