/* * This file is part of NSMB Editor 5. * * NSMB Editor 5 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * NSMB Editor 5 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with NSMB Editor 5. If not, see . */ using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Windows.Forms; using System.Net; using System.Xml; namespace NSMBe4 { public class SpriteData { public static Dictionary datas = new Dictionary(); public static Dictionary datas2 = new Dictionary(); public static List spriteNames = new List(); public static List categoryIds = new List(); public static List categories = new List(); public static Dictionary> spritesInCategory = new Dictionary>(); public static string directory = System.IO.Path.GetDirectoryName(Application.ExecutablePath); public static string path = System.IO.Path.Combine(directory, "spritedata.xml"); int spriteID; int categoryID; string name; string notes; public List fields = new List(); public static string DownloadWebPage(string Url) { // Open a connection HttpWebRequest WebRequestObject = (HttpWebRequest)HttpWebRequest.Create(Url); // You can also specify additional header values like // the user agent or the referer: WebRequestObject.UserAgent = "NSMBe/5.2"; WebRequestObject.Referer = ""; // Request response: WebResponse Response = WebRequestObject.GetResponse(); // Open data stream: Stream WebStream = Response.GetResponseStream(); // Create reader object: StreamReader Reader = new StreamReader(WebStream); // Read the entire stream content: string PageContent = Reader.ReadToEnd(); // Cleanup Reader.Close(); WebStream.Close(); Response.Close(); return PageContent; } public static void update() { try { string data = DownloadWebPage("http://nsmbhd.net/spritexml.php"); if (data.Trim() == "") throw new Exception("Got empty data"); if (!Directory.Exists(directory)) Directory.CreateDirectory(directory); FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None); StreamWriter sw = new StreamWriter(fs); sw.Write(data); sw.Close(); fs.Close(); MessageBox.Show(LanguageManager.Get("SpriteData", "Updated")); } catch (Exception e) { MessageBox.Show(String.Format(LanguageManager.Get("SpriteData", "ErrorUpdate"), e.Message), LanguageManager.Get("SpriteData", "ErrorTitle"), MessageBoxButtons.OK, MessageBoxIcon.Error); } } public static void Load() { datas = new Dictionary(); datas2 = new Dictionary(); if (!File.Exists(path)) { if (MessageBox.Show(LanguageManager.Get("SpriteData", "Prompt"), LanguageManager.Get("SpriteData", "PromptTitle"), MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) update(); else return; } try { FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); XmlReader xmlr = XmlReader.Create(fs); xmlr.ReadToFollowing("category"); do { int id = int.Parse(xmlr.GetAttribute("id")); categoryIds.Add(id); categories.Add(xmlr.ReadElementContentAsString()); spritesInCategory.Add(id, new List()); } while (xmlr.ReadToNextSibling("category")); while (xmlr.ReadToFollowing("sprite")) { SpriteData d = readFromStream(xmlr); if (d != null) datas2.Add(d.spriteID, d); } for (int i = 0; i < datas2.Count; i++) { int ActorID = (int)ROM.GetClassIDFromTable(i); datas.Add(i, datas2[ActorID]); } datas2.Clear(); xmlr.Close(); fs.Close(); } catch (Exception e) { MessageBox.Show(LanguageManager.Get("SpriteData", "ErrorParse"), LanguageManager.Get("SpriteData", "ErrorTitle"), MessageBoxButtons.OK, MessageBoxIcon.Error); datas.Clear(); datas2.Clear(); } } public static SpriteData readFromStream(XmlReader xmlr) { SpriteData sd = new SpriteData(); sd.spriteID = int.Parse(xmlr.GetAttribute("id")); //sd.spriteID = (int)ROM.GetClassIDFromTable(sd.spriteID); xmlr.ReadToFollowing("name"); sd.name = xmlr.ReadElementContentAsString(); spriteNames.Add(sd.name); xmlr.ReadToFollowing("category"); sd.categoryID = int.Parse(xmlr.GetAttribute("id")); spritesInCategory[sd.categoryID].Add(sd.spriteID); xmlr.ReadToFollowing("notes"); sd.notes = xmlr.ReadElementContentAsString(); while (xmlr.ReadToNextSibling("field")) { SpriteDataField f = new SpriteDataField(); f.display = xmlr.GetAttribute("type"); f.name = xmlr.GetAttribute("name"); f.notes = xmlr.GetAttribute("notes"); string nybbles = xmlr.GetAttribute("id"); if (nybbles.Contains("-")) { string[] nybbles2 = nybbles.Split('-'); f.startNibble = int.Parse(nybbles2[0]); f.endNibble = int.Parse(nybbles2[1]); } else f.startNibble = f.endNibble = int.Parse(nybbles); string values = xmlr.GetAttribute("values"); switch (f.display) { case "list": string[] items = values.Split(','); f.values = new int[items.Length]; f.strings = new string[items.Length]; for (int j = 0; j < items.Length; j++) { string[] lulz = items[j].Split(new char[] { '=' }); f.values[j] = Int32.Parse(lulz[0]); f.strings[j] = lulz[1]; } break; case "signedvalue": if (values.Trim() == "") f.data = 0; else f.data = Int32.Parse(values); break; case "value": if (values.Trim() == "") f.data = 0; else f.data = Int32.Parse(values); break; case "checkbox": if (values.Trim() == "") f.data = 1; else f.data = Int32.Parse(values); break; } sd.fields.Add(f); } return sd; } public class SpriteDataField { public string name; public string notes; public string display; public int startNibble; public int endNibble; //For list public int[] values; public string[] strings; //For values and checkboxes public int data; public int getBitCount() { return (endNibble - startNibble + 1)*4; } public int getMin() { int value = 0; if (display == "signedvalue") value = -((1 << (getBitCount()) - 1)); if (display == "value" || display == "signedvalue") value += this.data; return value; } public int getMax() { int value = (1 << (getBitCount())) - 1; if (display == "signedvalue") value = (1 << (getBitCount() - 1)) - 1; if (display == "value" || display == "signedvalue") value += this.data; return value; } public int getValue(byte[] data) { byte[] nibbles = new byte[12]; for (int i = 0; i < 6; i++) { nibbles[2 * i] = (byte)(data[i] >> 4); nibbles[2 * i + 1] = (byte)(data[i] & 0xF); } int res = 0; for (int i = startNibble; i <= endNibble; i++) { res = res << 4 | nibbles[i]; } if (display == "signedvalue" && res > getMax()) { res -= (1 << getBitCount()); } if (display == "value" || display == "signedvalue") res += this.data; if (display == "checkbox") res /= this.data; return res; } public void setValue(int b, byte[] data) { byte[] nibbles = new byte[12]; for (int i = 0; i < 6; i++) { nibbles[2 * i] = (byte)(data[i] >> 4); nibbles[2 * i + 1] = (byte)(data[i] & 0xF); } if (display == "value" || display == "signedvalue") b -= this.data; if (display == "checkbox") b *= this.data; for (int i = endNibble; i >= startNibble; i--) { nibbles[i] = (byte)(b & 0xF); b = b >> 4; } for (int i = 0; i < 6; i++) { data[i] = (byte)(nibbles[2*i] << 4 | nibbles[2*i+1]); } } } public class SpriteDataEditor : TableLayoutPanel { Dictionary controls = new Dictionary(); List sprites; NSMBSprite s; SpriteData sd; LevelEditorControl EdControl; public bool updating = false; public SpriteDataEditor(List sprites, SpriteData sd, LevelEditorControl EdControl) { this.SizeChanged += new EventHandler(this_SizeChanged); updating = true; this.ColumnCount = 3; //Talbe layout panel doesn't automatically create row or column styles this.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); this.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F)); this.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F)); this.RowCount = sd.fields.Count; for (int l = 0; l < this.RowCount; l++) this.RowStyles.Add(new RowStyle(SizeType.Absolute)); this.AutoSize = true; this.AutoSizeMode = AutoSizeMode.GrowAndShrink; this.sprites = sprites; foreach (LevelItem obj in sprites) if (obj is NSMBSprite) { s = obj as NSMBSprite; break; } this.sd = sd; this.Dock = DockStyle.Fill; this.EdControl = EdControl; int row = 0; foreach (SpriteDataField v in sd.fields) { Control c = CreateControlFor(v); c.Anchor = AnchorStyles.Left | AnchorStyles.Right; if (c is CheckBox || c is Label) { c.Font = new System.Drawing.Font(c.Font.FontFamily, c.Font.Size * 0.9F); this.Controls.Add(c, 0, row); this.RowStyles[row].Height = 25; if (v.notes == "") this.SetColumnSpan(c, 3); else { NotesCtrl note = new NotesCtrl(); this.Controls.Add(note, 2, row); note.Text = v.notes; } } else { this.Controls.Add(c, 1, row); Label l = new Label(); l.Text = v.name; l.Font = new System.Drawing.Font(l.Font.FontFamily, l.Font.Size * 0.9F); l.TextAlign = System.Drawing.ContentAlignment.MiddleRight; l.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom; this.Controls.Add(l, 0, row); this.RowStyles[row].Height = 25; if (v.notes == "") this.SetColumnSpan(c, 2); else { NotesCtrl note = new NotesCtrl(); this.Controls.Add(note, 2, row); note.Text = v.notes; } } row++; controls.Add(v, c); } updating = false; } public void this_SizeChanged(object sender, EventArgs e) { // Console.Out.WriteLine(this.Width.ToString()); if (this.Width != 200) for (int l = 0; l < this.RowCount; l++) { Control ctrl = this.GetControlFromPosition(0, l); if (ctrl is Label) { ctrl.MaximumSize = new System.Drawing.Size(this.Width / 2, 0); this.RowStyles[l].Height = Math.Max(ctrl.PreferredSize.Height, this.GetControlFromPosition(1, l).Height) + 4; } } } public void UpdateData() { updating = true; foreach (SpriteDataField v in sd.fields) updateValue(v); updating = false; } private Control CreateControlFor(SpriteDataField v) { // Console.WriteLine(v.display + " " + v.name); if (v.display == "checkbox") { CheckBox c = new CheckBox(); c.Checked = v.getValue(s.Data) == 1; c.Text = v.name; c.CheckedChanged += new EventHandler(saveData); return c; } else if (v.display == "list") { ComboBox c = new ComboBox(); c.DropDownStyle = ComboBoxStyle.DropDownList; c.Items.AddRange(v.strings); try { c.SelectedIndex = Array.IndexOf(v.values, v.getValue(s.Data)); } catch (ArgumentOutOfRangeException) { } //just in case //c.SelectedIndexChanged += new EventHandler(saveData); c.SelectionChangeCommitted += new EventHandler(saveData); //c.DropDownClosed += new EventHandler(saveData); return c; } else if (v.display == "label") { Label c = new Label(); c.Text = v.name; return c; } else if (v.display == "binary") { BinaryEdit c = new BinaryEdit(); c.CheckBoxCount = v.getBitCount(); c.value = v.getValue(s.Data); c.ValueChanged += new EventHandler(saveData); return c; } else { NumericUpDown c = new NumericUpDown(); c.Minimum = v.getMin(); c.Maximum = v.getMax(); c.Value = v.getValue(s.Data); c.ValueChanged += new EventHandler(saveData); return c; } } public void updateValue(SpriteDataField v) { Control c = controls[v]; int value = v.getValue(s.Data); if (c is CheckBox) (c as CheckBox).Checked = value == 1; if (c is ComboBox) (c as ComboBox).SelectedIndex = Array.IndexOf(v.values, value); if (c is BinaryEdit) (c as BinaryEdit).value = value; if (c is NumericUpDown) (c as NumericUpDown).Value = value; } public void saveData(object sender, EventArgs e) { byte[] d = s.Data.Clone() as byte[]; int index = 0; foreach(SpriteDataField sv in controls.Keys) { int val = 0; if (controls[sv] is NumericUpDown) val = (int)(controls[sv] as NumericUpDown).Value; else if (controls[sv] is ComboBox) { int se = (controls[sv] as ComboBox).SelectedIndex; if (se == -1) val = 0; else val = sd.fields[index].values[(controls[sv] as ComboBox).SelectedIndex]; } else if (controls[sv] is CheckBox) val = (controls[sv] as CheckBox).Checked ? 1 : 0; else if (controls[sv] is BinaryEdit) val = (controls[sv] as BinaryEdit).value; sv.setValue(val, d); index++; } if (!updating && sender != null) { EdControl.UndoManager.Do(new ChangeSpriteDataAction(sprites, d)); } } } } }