Strings.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. namespace FF8
  7. {
  8. public class Stringfile
  9. {
  10. #region Fields
  11. public Dictionary<uint, List<uint>> sPositions;
  12. public List<Loc> subPositions;
  13. #endregion Fields
  14. #region Constructors
  15. public Stringfile(Dictionary<uint, List<uint>> sPositions, List<Loc> subPositions)
  16. {
  17. this.sPositions = sPositions;
  18. this.subPositions = subPositions;
  19. }
  20. /// <summary>
  21. /// do not use this.
  22. /// </summary>
  23. private Stringfile()
  24. {
  25. this.sPositions = null;
  26. this.subPositions = null;
  27. }
  28. #endregion Constructors
  29. }
  30. /// <summary>
  31. /// Loads strings from FF8 files
  32. /// </summary>
  33. internal class Strings
  34. {
  35. #region Fields
  36. private readonly string[] filenames = new string[] { "mngrp.bin", "mngrphd.bin", "areames.dc1", "namedic.bin", "kernel.bin" };
  37. private string ArchiveString;
  38. private ArchiveWorker aw;
  39. //temp storage for locations isn't kept long term.
  40. private Dictionary<uint, uint> BinMSG;
  41. private Dictionary<uint, List<uint>> ComplexStr;
  42. private Dictionary<FileID, Stringfile> files;
  43. private FileID last;
  44. private BinaryReader localbr;
  45. private MemoryStream localms;
  46. /// <summary>
  47. /// Colly's list of string pointers. Adapted. Some strings might be missing.
  48. /// </summary>
  49. /// <see cref="http://www.balamb.pl/qh/kernel-pointers.htm"/>
  50. private Dictionary<uint, Tuple<uint, uint, uint>> LocSTR;
  51. private bool opened = false;
  52. private uint[] StringsLoc;
  53. private uint[] StringsPadLoc;
  54. #endregion Fields
  55. #region Constructors
  56. public Strings() => init();
  57. #endregion Constructors
  58. #region Enums
  59. /// <summary>
  60. /// filenames of files with strings and id's for structs that hold the data.
  61. /// </summary>
  62. public enum FileID : uint
  63. {
  64. MNGRP = 0,
  65. /// <summary>
  66. /// only used as holder for the mngrp's map filename
  67. /// </summary>
  68. MNGRP_MAP = 1,
  69. AREAMES = 2,
  70. NAMEDIC = 3,
  71. KERNEL = 4,
  72. }
  73. /// <summary>
  74. /// Todo make an enum to id every section.
  75. /// </summary>
  76. public enum SectionID : uint
  77. {
  78. tkmnmes1 = 0,
  79. tkmnmes2 = 1,
  80. tkmnmes3 = 2,
  81. }
  82. #endregion Enums
  83. #region Methods
  84. public void Close()
  85. {
  86. if (opened)
  87. {
  88. localbr.Close();
  89. localbr.Dispose();
  90. opened = false;
  91. }
  92. }
  93. public void Dump(FileID fileID, string path)
  94. {
  95. GetAW(fileID);
  96. using (FileStream fs = File.Create(path))
  97. using (BinaryWriter bw = new BinaryWriter(fs))
  98. using (MemoryStream ms = new MemoryStream(aw.GetBinaryFile(
  99. aw.GetListOfFiles().First(x => x.IndexOf(filenames[(int)fileID], StringComparison.OrdinalIgnoreCase) >= 0))))
  100. using (BinaryReader br = new BinaryReader(ms))
  101. {
  102. uint last = 0;
  103. foreach (KeyValuePair<uint, List<uint>> s in files[fileID].sPositions)
  104. {
  105. Loc fpos = files[fileID].subPositions[(int)s.Key];
  106. if (s.Key == 0)
  107. {
  108. last = s.Key;
  109. bw.Write(Encoding.UTF8.GetBytes($"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n<file id={s.Key} seek={fpos.seek} length={fpos.length}>\n"));
  110. }
  111. else
  112. {
  113. last = s.Key;
  114. bw.Write(Encoding.UTF8.GetBytes($"</file>\n<file id={s.Key} seek={fpos.seek} length={fpos.length}>\n"));
  115. }
  116. for (int j = 0; j < s.Value.Count; j++)
  117. {
  118. byte[] b = Font.DumpDirtyString(Read(br, fileID, s.Value[j]));
  119. if (b != null)
  120. {
  121. bw.Write(Encoding.UTF8.GetBytes($"\t<string id={j} seek={s.Value[j]}>"));
  122. bw.Write(b);
  123. bw.Write(Encoding.UTF8.GetBytes("</string>\n"));
  124. }
  125. }
  126. }
  127. bw.Write(Encoding.UTF8.GetBytes($"</file>"));
  128. }
  129. }
  130. public void GetAW(FileID fileID, bool force = false)
  131. {
  132. switch (fileID)
  133. {
  134. case FileID.MNGRP:
  135. case FileID.MNGRP_MAP:
  136. case FileID.AREAMES:
  137. default:
  138. ArchiveString = Memory.Archives.A_MENU;
  139. break;
  140. case FileID.NAMEDIC:
  141. case FileID.KERNEL:
  142. ArchiveString = Memory.Archives.A_MAIN;
  143. break;
  144. }
  145. if (aw == null || aw.GetPath() != ArchiveString || force)
  146. aw = new ArchiveWorker(ArchiveString);
  147. }
  148. public void Open(FileID fileID)
  149. {
  150. if (opened)
  151. throw new Exception("Must close before opening again");
  152. GetAW(fileID);
  153. try
  154. {
  155. localms = new MemoryStream(aw.GetBinaryFile(
  156. aw.GetListOfFiles().First(x => x.IndexOf(filenames[(int)fileID], StringComparison.OrdinalIgnoreCase) >= 0)));
  157. }
  158. catch
  159. {
  160. GetAW(fileID, true);
  161. localms = new MemoryStream(aw.GetBinaryFile(
  162. aw.GetListOfFiles().First(x => x.IndexOf(filenames[(int)fileID], StringComparison.OrdinalIgnoreCase) >= 0)));
  163. }
  164. localbr = new BinaryReader(localms);
  165. opened = true;
  166. last = fileID;
  167. }
  168. //public byte[] Read(FileID fileID, SectionID sectionID, int stringID) => Read(fileID, (int)sectionID, stringID);
  169. /// <summary>
  170. /// Remember to Close() if done using
  171. /// </summary>
  172. /// <param name="fileID"></param>
  173. /// <param name="sectionID"></param>
  174. /// <param name="stringID"></param>
  175. /// <returns></returns>
  176. public FF8String Read(FileID fileID, int sectionID, int stringID)
  177. {
  178. switch (fileID)
  179. {
  180. case FileID.MNGRP_MAP:
  181. throw new Exception("map file has no string");
  182. case FileID.MNGRP:
  183. case FileID.AREAMES:
  184. default:
  185. return Read(fileID, files[fileID].sPositions[(uint)sectionID][stringID]);
  186. }
  187. }
  188. private void init()
  189. {
  190. files = new Dictionary<FileID, Stringfile>(2);
  191. GetAW(FileID.MNGRP, true);
  192. mngrp_init();
  193. GetAW(FileID.AREAMES);
  194. simple_init(FileID.AREAMES);
  195. GetAW(FileID.NAMEDIC, true);
  196. simple_init(FileID.NAMEDIC);
  197. GetAW(FileID.KERNEL);
  198. Kernel_init(FileID.KERNEL);
  199. }
  200. /// <summary>
  201. /// Fetch strings from kernel.bin
  202. /// </summary>
  203. /// <param name="fileID">Should be FileID.KERNEL</param>
  204. /// <see cref="http://www.balamb.pl/qh/kernel-pointers.htm"/>
  205. private void Kernel_init(FileID fileID)
  206. {
  207. files[fileID] = new Stringfile(new Dictionary<uint, List<uint>>(56), new List<Loc>(56));
  208. using (MemoryStream ms = new MemoryStream(aw.GetBinaryFile(
  209. aw.GetListOfFiles().First(x => x.IndexOf(filenames[(int)fileID], StringComparison.OrdinalIgnoreCase) >= 0))))
  210. using (BinaryReader br = new BinaryReader(ms))
  211. {
  212. uint count = br.ReadUInt32();
  213. while (count-- > 0)
  214. {
  215. Loc l = new Loc { seek = br.ReadUInt32() };
  216. if (count <= 0) l.length = (uint)ms.Length - l.seek;
  217. else
  218. {
  219. l.length = br.ReadUInt32() - l.seek;
  220. ms.Seek(-4, SeekOrigin.Current);
  221. }
  222. files[fileID].subPositions.Add(l);
  223. }
  224. LocSTR = new Dictionary<uint, Tuple<uint, uint, uint>> {
  225. //working
  226. {0, new Tuple<uint, uint, uint>(31,2,4) },
  227. {1, new Tuple<uint, uint, uint>(32,2,56) },
  228. {2, new Tuple<uint, uint, uint>(33,2,128) },
  229. {3, new Tuple<uint, uint, uint>(34,1,18) },//38,58,178, or 78
  230. {4, new Tuple<uint, uint, uint>(35,1,10) },
  231. {5, new Tuple<uint, uint, uint>(36,2,20) },
  232. {6, new Tuple<uint, uint, uint>(37,1,34) },//+1interval 70 //character names here.
  233. {7, new Tuple<uint, uint, uint>(38,2,20) },
  234. {8, new Tuple<uint, uint, uint>(39,1,0) },
  235. {9, new Tuple<uint, uint, uint>(40,1,18) },
  236. {11, new Tuple<uint, uint, uint>(41,2,4) },
  237. {12, new Tuple<uint, uint, uint>(42,2,4) },
  238. {13, new Tuple<uint, uint, uint>(43,2,4) },
  239. {14, new Tuple<uint, uint, uint>(44,2,4) },
  240. {15, new Tuple<uint, uint, uint>(45,2,4) },
  241. {16, new Tuple<uint, uint, uint>(46,2,4) },
  242. {17, new Tuple<uint, uint, uint>(47,2,4) },
  243. {18, new Tuple<uint, uint, uint>(48,2,20) },
  244. {19, new Tuple<uint, uint, uint>(49,2,12) },
  245. {21, new Tuple<uint, uint, uint>(50,2,20) },
  246. {22, new Tuple<uint, uint, uint>(51,2,28) },
  247. {24, new Tuple<uint, uint, uint>(52,2,4) },
  248. {25, new Tuple<uint, uint, uint>(53,1,18) },
  249. {28, new Tuple<uint, uint, uint>(54,1,10) },
  250. {30, new Tuple<uint, uint, uint>(55,1,0) },
  251. };
  252. for (uint key = 0; key < files[fileID].subPositions.Count; key++)
  253. {
  254. Loc fpos = files[fileID].subPositions[(int)key];
  255. bool pad = (Array.IndexOf(StringsPadLoc, key) >= 0);
  256. //if (pad || Array.IndexOf(StringsLoc, key) >= 0)
  257. // mngrp_get_string_offsets(br, fileID, key, pad);
  258. //else
  259. if (LocSTR.ContainsKey(key))
  260. {
  261. mngrp_get_string_BinMSG(br, fileID, key, files[fileID].subPositions[(int)(LocSTR[key].Item1)].seek, LocSTR[key].Item2, LocSTR[key].Item3);
  262. }
  263. //else if (ComplexStr.ContainsKey(key))
  264. //{
  265. // Mngrp_get_string_ComplexStr(br, fileID, key, ComplexStr[key]);
  266. //}
  267. }
  268. }
  269. }
  270. private void mngrp_get_string_BinMSG(BinaryReader br, FileID fileID, uint key, uint msgPos, uint grab = 0, uint skip = 0)
  271. {
  272. Loc fpos = files[fileID].subPositions[(int)key];
  273. br.BaseStream.Seek(fpos.seek, SeekOrigin.Begin);
  274. if (files[fileID].sPositions.ContainsKey(key))
  275. {
  276. }
  277. else
  278. {
  279. ushort b = 0;
  280. ushort last = b;
  281. files[fileID].sPositions.Add(key, new List<uint>());
  282. uint g = 1;
  283. while (br.BaseStream.Position < fpos.max)
  284. {
  285. b = br.ReadUInt16();
  286. if (last > b)
  287. break;
  288. else
  289. {
  290. if (b != 0xFFFF)
  291. {
  292. files[fileID].sPositions[key].Add(b + msgPos);
  293. last = b;
  294. }
  295. if (grab > 0 && ++g > grab)
  296. {
  297. br.BaseStream.Seek(skip, SeekOrigin.Current);
  298. g = 1;
  299. }
  300. }
  301. }
  302. }
  303. }
  304. private void Mngrp_get_string_ComplexStr(BinaryReader br, FileID fileID, uint key, List<uint> list)
  305. {
  306. uint[] fPaddings;
  307. fPaddings = mngrp_read_padding(br, files[fileID].subPositions[(int)key], 1);
  308. files[fileID].sPositions.Add(key, new List<uint>());
  309. for (uint p = 0; p < fPaddings.Length; p += 2)
  310. {
  311. key = list[(int)fPaddings[(int)p + 1]];
  312. Loc fpos = files[fileID].subPositions[(int)key];
  313. uint fpad = fPaddings[p] + fpos.seek;
  314. br.BaseStream.Seek(fpad, SeekOrigin.Begin);
  315. if (!files[fileID].sPositions.ContainsKey(key))
  316. files[fileID].sPositions.Add(key, new List<uint>());
  317. br.BaseStream.Seek(fpad + 6, SeekOrigin.Begin);
  318. //byte[] UNK = br.ReadBytes(6);
  319. ushort len = br.ReadUInt16();
  320. uint stop = (uint)(br.BaseStream.Position + len - 9); //6 for UNK, 2 for len 1, for end null
  321. files[fileID].sPositions[key].Add((uint)br.BaseStream.Position);
  322. //entry contains possible more than one string so I am scanning for null
  323. while (br.BaseStream.Position + 1 < stop)
  324. {
  325. byte b = br.ReadByte();
  326. if (b == 0) files[fileID].sPositions[key].Add((uint)br.BaseStream.Position);
  327. }
  328. }
  329. }
  330. /// <summary>
  331. /// TODO: make this work with more than one file.
  332. /// </summary>
  333. /// <param name="br"></param>
  334. /// <param name="spos"></param>
  335. /// <param name="key"></param>
  336. /// <param name="pad"></param>
  337. private void mngrp_get_string_offsets(BinaryReader br, FileID fileID, uint key, bool pad = false)
  338. {
  339. Loc fpos = files[fileID].subPositions[(int)key];
  340. uint[] fPaddings = pad ? mngrp_read_padding(br, fpos) : (new uint[] { 1 });
  341. files[fileID].sPositions.Add(key, new List<uint>());
  342. for (uint p = 0; p < fPaddings.Length; p++)
  343. {
  344. if (fPaddings[p] <= 0) continue;
  345. uint fpad = pad ? fPaddings[p] + fpos.seek : fpos.seek;
  346. br.BaseStream.Seek(fpad, SeekOrigin.Begin);
  347. if (br.BaseStream.Position + 4 < br.BaseStream.Length)
  348. {
  349. int count = br.ReadUInt16();
  350. for (int i = 0; i < count && br.BaseStream.Position + 2 < br.BaseStream.Length; i++)
  351. {
  352. uint c = br.ReadUInt16();
  353. if (c < br.BaseStream.Length && c != 0)
  354. {
  355. c += fpad;
  356. files[fileID].sPositions[key].Add(c);
  357. }
  358. }
  359. }
  360. }
  361. }
  362. private void mngrp_GetFileLocations()
  363. {
  364. FileID fileID = FileID.MNGRP;
  365. using (MemoryStream ms = new MemoryStream(aw.GetBinaryFile(
  366. aw.GetListOfFiles().First(x => x.IndexOf(filenames[(int)FileID.MNGRP_MAP], StringComparison.OrdinalIgnoreCase) >= 0))))
  367. using (BinaryReader br = new BinaryReader(ms))
  368. {
  369. while (ms.Position < ms.Length)
  370. {
  371. Loc loc = new Loc() { seek = br.ReadUInt32(), length = br.ReadUInt32() };
  372. if (loc.seek != 0xFFFFFFFF && loc.length != 0x00000000)
  373. {
  374. loc.seek--;
  375. files[fileID].subPositions.Add(loc);
  376. }
  377. }
  378. }
  379. }
  380. private void mngrp_init()
  381. {
  382. FileID fileID = FileID.MNGRP;
  383. files[fileID] = new Stringfile(new Dictionary<uint, List<uint>>(118), new List<Loc>(118));
  384. mngrp_GetFileLocations();
  385. using (MemoryStream ms = new MemoryStream(aw.GetBinaryFile(
  386. aw.GetListOfFiles().First(x => x.IndexOf(filenames[(int)FileID.MNGRP], StringComparison.OrdinalIgnoreCase) >= 0))))
  387. using (BinaryReader br = new BinaryReader(ms))
  388. {
  389. //string contain padding values at start of file
  390. //then location data before strings
  391. StringsPadLoc = new uint[] { (uint)SectionID.tkmnmes1, (uint)SectionID.tkmnmes2, (uint)SectionID.tkmnmes3 };
  392. //only location data before strings
  393. StringsLoc = new uint[] { 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
  394. 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87, 88, 116};
  395. //complexstr has locations in first file,
  396. //and they have 8 bytes of stuff at the start of each entry, 6 bytes UNK and ushort length?
  397. //also can have multiple null ending strings per entry.
  398. ComplexStr = new Dictionary<uint, List<uint>> { { 74, new List<uint> { 75, 76, 77, 78, 79, 80 } } };
  399. //these files come in pairs. the bin has string offsets and 6 bytes of other data
  400. //msg is where the strings are.
  401. BinMSG = new Dictionary<uint, uint>
  402. {{106,111},{107,112},{108,113},{109,114},{110,115}};
  403. for (uint key = 0; key < files[fileID].subPositions.Count; key++)
  404. {
  405. Loc fpos = files[fileID].subPositions[(int)key];
  406. bool pad = (Array.IndexOf(StringsPadLoc, key) >= 0);
  407. if (pad || Array.IndexOf(StringsLoc, key) >= 0)
  408. mngrp_get_string_offsets(br, fileID, key, pad);
  409. else if (BinMSG.ContainsKey(key))
  410. {
  411. mngrp_get_string_BinMSG(br, fileID, key, files[fileID].subPositions[(int)BinMSG[key]].seek, 1, 6);
  412. }
  413. else if (ComplexStr.ContainsKey(key))
  414. {
  415. Mngrp_get_string_ComplexStr(br, fileID, key, ComplexStr[key]);
  416. }
  417. }
  418. }
  419. }
  420. private uint[] mngrp_read_padding(BinaryReader br, Loc fpos, int type = 0)
  421. {
  422. uint[] fPaddings = null;
  423. br.BaseStream.Seek(fpos.seek, SeekOrigin.Begin);
  424. uint size = type == 0 ? br.ReadUInt16() : br.ReadUInt32();
  425. fPaddings = new uint[type == 0 ? size : size * type * 2];
  426. for (int i = 0; i < fPaddings.Length; i += 1 + type)
  427. {
  428. fPaddings[i] = br.ReadUInt16();
  429. if (type == 0 && fPaddings[i] + fpos.seek >= fpos.max)
  430. fPaddings[i] = 0;
  431. //if (fPaddings[i] != 0)
  432. // fPaddings[i] += fpos.seek;
  433. for (int j = 1; j < type + 1; j++)
  434. {
  435. fPaddings[i + j] = br.ReadUInt16();
  436. }
  437. }
  438. return fPaddings;
  439. }
  440. private FF8String Read(FileID fileID, uint pos)
  441. {
  442. //switching archive make sure we are closed before opening another.
  443. if (aw != null || aw.GetPath() != ArchiveString || last != fileID)
  444. Close();
  445. if (!opened)
  446. Open(fileID);
  447. return Read(localbr, fileID, pos);
  448. }
  449. private FF8String Read(BinaryReader br, FileID fid, uint pos)
  450. {
  451. if (pos < br.BaseStream.Length)
  452. using (MemoryStream os = new MemoryStream(50))
  453. {
  454. br.BaseStream.Seek(pos, SeekOrigin.Begin);
  455. int c = 0;
  456. byte b = 0;
  457. do
  458. {
  459. if (br.BaseStream.Position > br.BaseStream.Length) break;
  460. //sometimes strings start with 00 or 01. But there is another 00 at the end.
  461. //I think it's for SeeD test like 1 is right and 0 is wrong. for now i skip them.
  462. b = br.ReadByte();
  463. if (b != 0 && b != 1)
  464. {
  465. os.WriteByte(b);
  466. }
  467. c++;
  468. }
  469. while (b != 0 || c == 0);
  470. if (os.Length > 0)
  471. return os.ToArray();
  472. }
  473. return null;
  474. }
  475. private void simple_init(FileID fileID)
  476. {
  477. string[] list = aw.GetListOfFiles();
  478. string index = list.First(x => x.IndexOf(filenames[(int)fileID], StringComparison.OrdinalIgnoreCase) >= 0);
  479. using (MemoryStream ms = new MemoryStream(aw.GetBinaryFile(index)))
  480. using (BinaryReader br = new BinaryReader(ms))
  481. {
  482. if (!files.ContainsKey(fileID))
  483. files[fileID] = new Stringfile(new Dictionary<uint, List<uint>>(1), new List<Loc>(1) { new Loc { seek = 0, length = uint.MaxValue } });
  484. mngrp_get_string_offsets(br, fileID, 0);
  485. }
  486. }
  487. public FF8String GetName(Faces.ID id, Saves.Data d = null )
  488. {
  489. if (d == null)
  490. d = Memory.State;
  491. switch (id)
  492. {
  493. case Faces.ID.Squall_Leonhart:
  494. return d.Squallsname;
  495. case Faces.ID.Rinoa_Heartilly:
  496. return d.Rinoasname;
  497. case Faces.ID.Angelo:
  498. return d.Angelosname;
  499. case Faces.ID.Boko:
  500. return d.Bokosname;
  501. case Faces.ID.Zell_Dincht:
  502. case Faces.ID.Irvine_Kinneas:
  503. case Faces.ID.Quistis_Trepe:
  504. return Read(FileID.KERNEL, 6, (int)id - 1);
  505. case Faces.ID.Selphie_Tilmitt:
  506. case Faces.ID.Seifer_Almasy:
  507. case Faces.ID.Edea_Kramer:
  508. case Faces.ID.Laguna_Loire:
  509. case Faces.ID.Kiros_Seagill:
  510. case Faces.ID.Ward_Zabac:
  511. return Read(FileID.KERNEL, 6, (int)id - 2);
  512. case Faces.ID.Quezacotl:
  513. case Faces.ID.Shiva:
  514. case Faces.ID.Ifrit:
  515. case Faces.ID.Siren:
  516. case Faces.ID.Brothers:
  517. case Faces.ID.Diablos:
  518. case Faces.ID.Carbuncle:
  519. case Faces.ID.Leviathan:
  520. case Faces.ID.Pandemona:
  521. case Faces.ID.Cerberus:
  522. case Faces.ID.Alexander:
  523. case Faces.ID.Doomtrain:
  524. case Faces.ID.Bahamut:
  525. case Faces.ID.Cactuar:
  526. case Faces.ID.Tonberry:
  527. case Faces.ID.Eden:
  528. return d.GFs[(int)id - 16].Name;
  529. case Faces.ID.Griever:
  530. return d.Grieversname;
  531. case Faces.ID.MiniMog:
  532. return Read(FileID.KERNEL, 0, 72); // also in KERNEL, 12, 36
  533. default:
  534. return new FF8String();
  535. }
  536. }
  537. #endregion Methods
  538. //private byte[] Read(FileID fid, uint pos)
  539. //{
  540. // try
  541. // {
  542. // Open(fid);
  543. // return Read(localbr, fid, pos);
  544. // }
  545. // finally
  546. // {
  547. // Close();
  548. // }
  549. //}
  550. //private void readfile()
  551. //{
  552. // //text is prescrabbled and is ready to draw to screen using font renderer
  553. // //based on what I see here some parts of menu ignore \n and some will not //example when
  554. // you highlight a item to refine it will only show only on one line up above. // 1 will
  555. // refine into 20 Thundaras //and when you select it the whole string will show. // Coral
  556. // Fragment: // 1 will refine // into 20 Thundaras
  557. // //m000.msg = 104 strings //example = Coral Fragment:\n1 will refine \ninto 20 Thundaras\0
  558. // //I think this one is any item that turns into magic //___ Mag-RF items? except for
  559. // upgrade abilities
  560. // //m001.msg = 145 strings //same format differnt items //example = Tent:\n4 will refine
  561. // into \n1 Mega-Potion\0 //I think this one is any item that turns into another item //___
  562. // Med-RF items? except for upgrade abilities //guessing Ammo-RF is in here too.
  563. // //m002.msg = 10 strings //same format differnt items //example = Fire:\n5 will refine
  564. // \ninto 1 Fira\0 //this one is magic tha turns into higher level magic //first 4 are Mid
  565. // Mag-RF //last 6 are High Mag-RF
  566. // //m003.msg = 12 strings //same format differnt items //example = Elixer:\n10 will refine
  567. // \ninto 1 Megalixir\0 //this one is Med items tha turns into higher level Med items //all
  568. // 12 are Med LV Up
  569. // //m004.msg = 110 strings //same format differnt items //example = Geezard Card:\n1 will
  570. // refine \ninto 5 Screws\0 //this one is converts cards into items //all 110 are Card Mod
  571. // //mwepon.msg = 34 strings //all strings are " " or " " kinda a odd file.
  572. // //pet_exp.msg = 18 strings //format: ability name\0description\0 //{0x0340} = Angelo's
  573. // name //example: {0x0340} Rush\0 Damage one enemy\0 //list of Angelo's attack names and descriptions
  574. // //namedic.bin 32 strings
  575. // //Seems to be location names.
  576. // //start of file
  577. // // UIint16 Count
  578. // // UIint16[Count]Location
  579. // //at each location
  580. // // Byte[Count][Bytes to null]
  581. //}
  582. }
  583. }