debug_battleDat.cs 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Runtime.InteropServices;
  6. using Microsoft.Xna.Framework;
  7. using Microsoft.Xna.Framework.Graphics;
  8. namespace FF8
  9. {
  10. public class Debug_battleDat
  11. {
  12. int id;
  13. readonly EntityType entityType;
  14. byte[] buffer;
  15. /// <summary>
  16. /// V is the scale dividor. For now in Battle and World modules I'm dividing native f16 to 2048f
  17. /// </summary>
  18. public const float V = 2048.0f;
  19. public struct DatFile
  20. {
  21. public uint cSections;
  22. public uint[] pSections;
  23. public uint eof;
  24. }
  25. public DatFile datFile;
  26. #region section 1 Skeleton
  27. [StructLayout(LayoutKind.Sequential,Pack = 1,Size =16)]
  28. public struct Skeleton
  29. {
  30. public ushort cBones;
  31. public ushort scale;
  32. public ushort unk2;
  33. public ushort unk3;
  34. public ushort unk4;
  35. public ushort unk5;
  36. public ushort unk6;
  37. public ushort unk7;
  38. public Bone[] bones;
  39. public Vector3 GetScale => new Vector3(scale/V*12, scale/V*12, scale/V*12);
  40. }
  41. [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 48)]
  42. public struct Bone
  43. {
  44. public ushort parentId;
  45. public short boneSize;
  46. private short unk1; //360
  47. private short unk2; //360
  48. private short unk3; //360
  49. private short unk4;
  50. private short unk5;
  51. private short unk6;
  52. [MarshalAs(UnmanagedType.ByValArray,SizeConst = 28 )]
  53. public byte[] Unk;
  54. public float Size { get => boneSize / V; }
  55. public float Unk1 { get => unk1 / 4096.0f * 360.0f; }
  56. public float Unk2 { get => unk2 / 4096.0f * 360.0f; }
  57. public float Unk3 { get => unk3 / 4096.0f * 360.0f; }
  58. public float Unk4 { get => unk4 / 4096.0f; }
  59. public float Unk5 { get => unk5 / 4096.0f; }
  60. public float Unk6 { get => unk6 / 4096.0f; }
  61. }
  62. /// <summary>
  63. /// Skeleton data section
  64. /// </summary>
  65. /// <param name="v"></param>
  66. /// <param name="ms"></param>
  67. /// <param name="br"></param>
  68. private void ReadSection1(uint v, MemoryStream ms, BinaryReader br)
  69. {
  70. ms.Seek(v, SeekOrigin.Begin);
  71. #if _WINDOWS //looks like Linux Mono doesn't like marshalling structure with LPArray to Bone[]
  72. skeleton = Extended.ByteArrayToStructure<Skeleton>(br.ReadBytes(16));
  73. #else
  74. skeleton = new Skeleton()
  75. {
  76. cBones = br.ReadUInt16(),
  77. scale = br.ReadUInt16(),
  78. unk2 = br.ReadUInt16(),
  79. unk3 = br.ReadUInt16(),
  80. unk4 = br.ReadUInt16(),
  81. unk5 = br.ReadUInt16(),
  82. unk6 = br.ReadUInt16(),
  83. unk7 = br.ReadUInt16()
  84. };
  85. #endif
  86. skeleton.bones = new Bone[skeleton.cBones];
  87. for (int i = 0; i < skeleton.cBones; i++)
  88. skeleton.bones[i] = Extended.ByteArrayToStructure<Bone>(br.ReadBytes(48));
  89. return;
  90. }
  91. public Skeleton skeleton;
  92. #endregion
  93. #region section 2 Geometry
  94. public struct Geometry
  95. {
  96. public uint cObjects;
  97. public uint[] pObjects;
  98. public Object[] objects;
  99. public uint cTotalVert;
  100. }
  101. public struct Object
  102. {
  103. public ushort cVertices;
  104. public VerticeData[] verticeData;
  105. public ushort cTriangles;
  106. public ushort cQuads;
  107. public ulong padding;
  108. public Triangle[] triangles;
  109. public Quad[] quads;
  110. }
  111. public struct VerticeData
  112. {
  113. public ushort boneId;
  114. public ushort cVertices;
  115. public Vertex[] vertices;
  116. }
  117. [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 8)]
  118. public struct Vertex
  119. {
  120. public short x;
  121. public short y;
  122. public short z;
  123. public Vector3 GetVector => new Vector3(-x/ V, -z/V, -y/V);
  124. }
  125. [StructLayout(LayoutKind.Sequential, Pack =1, Size =16)]
  126. public struct Triangle
  127. {
  128. private ushort A;
  129. private ushort B;
  130. private ushort C;
  131. public UV vta;
  132. public UV vtb;
  133. public ushort texUnk;
  134. public UV vtc;
  135. public ushort u;
  136. public ushort A1 { get => (ushort)(A & 0xFFF); set => A = value; }
  137. public ushort B1 { get => (ushort)(B & 0xFFF); set => B = value; }
  138. public ushort C1 { get => (ushort)(C & 0xFFF); set => C = value; }
  139. public byte textureIndex { get => (byte)((texUnk >> 6) & 0b111); }
  140. }
  141. [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 20)]
  142. public struct Quad
  143. {
  144. private ushort A;
  145. private ushort B;
  146. private ushort C;
  147. private ushort D;
  148. public UV vta;
  149. public ushort texUnk;
  150. public UV vtb;
  151. public ushort u;
  152. public UV vtc;
  153. public UV vtd;
  154. public ushort A1 { get => (ushort)(A & 0xFFF); set => A = value; }
  155. public ushort B1 { get => (ushort)(B & 0xFFF); set => B = value; }
  156. public ushort C1 { get => (ushort)(C & 0xFFF); set => C = value; }
  157. public ushort D1 { get => (ushort)(D & 0xFFF); set => D = value; }
  158. public byte textureIndex { get => (byte)((texUnk >> 6) & 0b111); }
  159. }
  160. [StructLayout(LayoutKind.Sequential, Pack =1,Size =2)]
  161. public struct UV
  162. {
  163. public byte U;
  164. public byte V;
  165. public float U1(float h=128f) { return U / h; }
  166. public float V1(float w=128f) { return V > 128 ? //if bigger than 128, then multitexture index to odd
  167. (V - 128f)/w
  168. : w==32 ? //if equals 32, then it's weapon texture and should be in range of 96-128
  169. (V-96)/w
  170. : V/w; } //if none of these cases, then divide by resolution;
  171. public override string ToString()
  172. {
  173. return $"{U};{U1()};{V};{V1()}";
  174. }
  175. }
  176. public Geometry geometry;
  177. /// <summary>
  178. /// Geometry section
  179. /// </summary>
  180. /// <param name="v"></param>
  181. /// <param name="ms"></param>
  182. /// <param name="br"></param>
  183. private void ReadSection2(uint v, MemoryStream ms, BinaryReader br)
  184. {
  185. ms.Seek(v, SeekOrigin.Begin);
  186. geometry = new Geometry { cObjects = br.ReadUInt32() };
  187. geometry.pObjects = new uint[geometry.cObjects];
  188. for (int i = 0; i < geometry.cObjects; i++)
  189. geometry.pObjects[i] = br.ReadUInt32();
  190. geometry.objects = new Object[geometry.cObjects];
  191. for (int i = 0; i < geometry.cObjects; i++)
  192. geometry.objects[i] = ReadGeometryObject(v+geometry.pObjects[i], ms, br);
  193. geometry.cTotalVert = br.ReadUInt32();
  194. }
  195. private Object ReadGeometryObject(uint v, MemoryStream ms, BinaryReader br)
  196. {
  197. ms.Seek(v, SeekOrigin.Begin);
  198. Object @object = new Object { cVertices = br.ReadUInt16() };
  199. @object.verticeData = new VerticeData[@object.cVertices];
  200. if (ms.Position + @object.cVertices * 6 >= ms.Length)
  201. return @object;
  202. for (int n = 0; n < @object.cVertices; n++){
  203. @object.verticeData[n].boneId = br.ReadUInt16();
  204. @object.verticeData[n].cVertices = br.ReadUInt16();
  205. @object.verticeData[n].vertices = new Vertex[@object.verticeData[n].cVertices];
  206. for (int i = 0; i < @object.verticeData[n].cVertices; i++)
  207. @object.verticeData[n].vertices[i] = Extended.ByteArrayToStructure<Vertex>(br.ReadBytes(6));}
  208. ms.Seek(4-(ms.Position%4 == 0 ? 4 : ms.Position%4), SeekOrigin.Current);
  209. @object.cTriangles = br.ReadUInt16();
  210. @object.cQuads = br.ReadUInt16();
  211. @object.padding = br.ReadUInt64();
  212. @object.triangles = new Triangle[@object.cTriangles];
  213. if (@object.cTriangles == 0 && @object.cQuads == 0)
  214. return @object;
  215. @object.quads = new Quad[@object.cQuads];
  216. for (int i = 0; i < @object.cTriangles; i++)
  217. @object.triangles[i] = Extended.ByteArrayToStructure<Triangle>(br.ReadBytes(16));
  218. for (int i = 0; i < @object.cQuads; i++)
  219. @object.quads[i] = Extended.ByteArrayToStructure<Quad>(br.ReadBytes(20));
  220. return @object;
  221. }
  222. /// <summary>
  223. /// This method returns geometry data AFTER animation matrix translations, local position/rotation translations. This is the final step of calculation.
  224. /// This data should be used only by Renderer. Any translations/vertices manipulation should happen inside this method or earlier
  225. /// </summary>
  226. /// <param name="objectId">Monsters can have more than one object. Treat it like multi-model geometry. They are all needed to build whole model</param>
  227. /// <param name="position">a Vector3 to set global position</param>
  228. /// <param name="rotation">a Quaternion to set the correct rotation. 1=90, 2=180 ... </param>
  229. /// <param name="animationId">an animation pointer. Animation 0 is always idle</param>
  230. /// <param name="animationFrame">an animation frame from animation id. You should pass incrementing frame and reset to 0 when frameCount max is hit</param>
  231. /// <param name="step">FEATURE: This float (0.0 - 1.0) is used in Linear interpolation in animation frames blending. 0.0 means frameN, 1.0 means FrameN+1. Usually this should be a result of deltaTime to see if computer is capable of rendering smooth animations rather than constant 15 FPS</param>
  232. /// <returns></returns>
  233. public Tuple<VertexPositionTexture[],byte[]> GetVertexPositions(int objectId, Vector3 position,Quaternion rotation, int animationId, int animationFrame, float step)
  234. {
  235. Object obj = geometry.objects[objectId];
  236. if (animationFrame >= animHeader.animations[animationId].animationFrames.Length || animationFrame<0)
  237. animationFrame = 0;
  238. AnimationFrame frame = animHeader.animations[animationId].animationFrames[animationFrame];
  239. AnimationFrame nextFrame = animationFrame +1 >= animHeader.animations[animationId].animationFrames.Length
  240. ? animHeader.animations[animationId].animationFrames[0]
  241. : animHeader.animations[animationId].animationFrames[animationFrame+1];
  242. List<VertexPositionTexture> vpt = new List<VertexPositionTexture>();
  243. List<Tuple<Vector3, int>> verts = new List<Tuple<Vector3, int>>();
  244. int i = 0;
  245. foreach (var a in obj.verticeData)
  246. foreach (var b in a.vertices)
  247. verts.Add(CalculateFrame(new Tuple<Vector3, int>(b.GetVector, a.boneId),frame,nextFrame, step));
  248. byte[] texturePointers = new byte[obj.cTriangles + obj.cQuads*2];
  249. Vector3 snapToGround = Vector3.Zero;
  250. FixScaleYOffset(out snapToGround);
  251. Vector3 translationPosition = position + Vector3.SmoothStep(frame.Position, nextFrame.Position, step) + snapToGround;
  252. for (;i<obj.cTriangles; i++ )
  253. {
  254. ///=/=/=/=/==/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=
  255. ///
  256. ////////////////////=============VERTEX C========\\\\\\\\\\\\\\\\\\\\\
  257. Tuple<Vector3, int> VerticeC = verts[ obj.triangles[i].C1];
  258. Vector3 VerticeDataC = VerticeC.Item1;
  259. VerticeDataC = Vector3.Transform(VerticeDataC, Matrix.CreateFromQuaternion(rotation));
  260. VerticeDataC = Vector3.Transform(VerticeDataC, Matrix.CreateTranslation(translationPosition));
  261. ////////////////////=============VERTEX A========\\\\\\\\\\\\\\\\\\\\\
  262. Tuple<Vector3, int> VerticeA = verts[obj.triangles[i].A1];
  263. Vector3 VerticeDataA = VerticeA.Item1;
  264. VerticeDataA = Vector3.Transform(VerticeDataA, Matrix.CreateFromQuaternion(rotation));
  265. VerticeDataA = Vector3.Transform(VerticeDataA, Matrix.CreateTranslation(translationPosition));
  266. ////////////////////=============VERTEX B========\\\\\\\\\\\\\\\\\\\\\
  267. Tuple<Vector3, int> VerticeB = verts[obj.triangles[i].B1];
  268. Vector3 VerticeDataB = VerticeB.Item1;
  269. VerticeDataB = Vector3.Transform(VerticeDataB, Matrix.CreateFromQuaternion(rotation));
  270. VerticeDataB = Vector3.Transform(VerticeDataB, Matrix.CreateTranslation(translationPosition));
  271. ///
  272. ///=/=/=/=/==/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=/=
  273. var prevarTexT = textures.textures[obj.triangles[i].textureIndex];
  274. vpt.Add(new VertexPositionTexture(VerticeDataC, new Vector2(obj.triangles[i].vta.U1(prevarTexT.Width), obj.triangles[i].vta.V1(prevarTexT.Height))));
  275. vpt.Add(new VertexPositionTexture(VerticeDataA, new Vector2(obj.triangles[i].vtb.U1(prevarTexT.Width), obj.triangles[i].vtb.V1(prevarTexT.Height))));
  276. vpt.Add(new VertexPositionTexture(VerticeDataB, new Vector2(obj.triangles[i].vtc.U1(prevarTexT.Width), obj.triangles[i].vtc.V1(prevarTexT.Height))));
  277. texturePointers[i] = obj.triangles[i].textureIndex;
  278. }
  279. for (i = 0; i < obj.cQuads; i++)
  280. {
  281. ////////////////////=============VERTEX A========\\\\\\\\\\\\\\\\\\\\\
  282. Tuple<Vector3, int> VerticeA = verts[obj.quads[i].A1];
  283. Vector3 VerticeDataA = VerticeA.Item1;
  284. VerticeDataA = Vector3.Transform(VerticeDataA, Matrix.CreateFromQuaternion(rotation));
  285. VerticeDataA = Vector3.Transform(VerticeDataA, Matrix.CreateTranslation(translationPosition));
  286. ////////////////////=============VERTEX B========\\\\\\\\\\\\\\\\\\\\\
  287. Tuple<Vector3, int> VerticeB = verts[obj.quads[i].B1];
  288. Vector3 VerticeDataB = VerticeB.Item1;
  289. VerticeDataB = Vector3.Transform(VerticeDataB, Matrix.CreateFromQuaternion(rotation));
  290. VerticeDataB = Vector3.Transform(VerticeDataB, Matrix.CreateTranslation(translationPosition));
  291. ////////////////////=============VERTEX C========\\\\\\\\\\\\\\\\\\\\\
  292. Tuple<Vector3, int> VerticeC = verts[obj.quads[i].C1];
  293. Vector3 VerticeDataC = VerticeC.Item1;
  294. VerticeDataC = Vector3.Transform(VerticeDataC, Matrix.CreateFromQuaternion(rotation));
  295. VerticeDataC = Vector3.Transform(VerticeDataC, Matrix.CreateTranslation(translationPosition));
  296. ////////////////////=============VERTEX D========\\\\\\\\\\\\\\\\\\\\\
  297. Tuple<Vector3, int> VerticeD = verts[obj.quads[i].D1];
  298. Vector3 VerticeDataD = VerticeD.Item1;
  299. VerticeDataD = Vector3.Transform(VerticeDataD, Matrix.CreateFromQuaternion(rotation));
  300. VerticeDataD = Vector3.Transform(VerticeDataD, Matrix.CreateTranslation(translationPosition));
  301. ///
  302. var preVarTex = textures.textures[obj.quads[i].textureIndex];
  303. vpt.Add(new VertexPositionTexture(VerticeDataA, new Vector2(obj.quads[i].vta.U1(preVarTex.Width), obj.quads[i].vta.V1(preVarTex.Height))));
  304. vpt.Add(new VertexPositionTexture(VerticeDataB, new Vector2(obj.quads[i].vtb.U1(preVarTex.Width), obj.quads[i].vtb.V1(preVarTex.Height))));
  305. vpt.Add(new VertexPositionTexture(VerticeDataD, new Vector2(obj.quads[i].vtd.U1(preVarTex.Width), obj.quads[i].vtd.V1(preVarTex.Height))));
  306. vpt.Add(new VertexPositionTexture(VerticeDataA, new Vector2(obj.quads[i].vta.U1(preVarTex.Width), obj.quads[i].vta.V1(preVarTex.Height))));
  307. vpt.Add(new VertexPositionTexture(VerticeDataC, new Vector2(obj.quads[i].vtc.U1(preVarTex.Width), obj.quads[i].vtc.V1(preVarTex.Height))));
  308. vpt.Add(new VertexPositionTexture(VerticeDataD, new Vector2(obj.quads[i].vtd.U1(preVarTex.Width), obj.quads[i].vtd.V1(preVarTex.Height))));
  309. texturePointers[obj.cTriangles+i*2] = obj.quads[i].textureIndex;
  310. texturePointers[obj.cTriangles + i * 2+1] = obj.quads[i].textureIndex;
  311. }
  312. return new Tuple<VertexPositionTexture[], byte[]>(vpt.ToArray(), texturePointers);
  313. }
  314. /// <summary>
  315. /// Lazy class to fix Y axis of entities because due to scalling some appeared above or below the stage.
  316. /// Those entities that have so far unknown Y axis are vurnable to DEBUGframe variable
  317. /// </summary>
  318. /// <param name="snapToGround"></param>
  319. private void FixScaleYOffset(out Vector3 snapToGround)
  320. {
  321. //snapToGround = Vector3.Zero;
  322. //return;
  323. float fScaleResolver = skeleton.GetScale.Y;
  324. float y = 0f;
  325. switch(entityType)
  326. {
  327. case EntityType.Monster:
  328. switch (GetId)
  329. {
  330. case 68:
  331. y = -300f;
  332. break;
  333. case 21:
  334. case 18:
  335. y = -125;
  336. break;
  337. case 125:
  338. y = -120;
  339. break;
  340. case 25:
  341. y = -100;
  342. break;
  343. case 113:
  344. y = -90;
  345. break;
  346. case 54:
  347. y = -57;
  348. break;
  349. case 119:
  350. case 136:
  351. y = -50;
  352. break;
  353. case 88:
  354. case 100:
  355. y = -30;
  356. break;
  357. case 55:
  358. y = -28;
  359. break;
  360. case 82:
  361. case 142:
  362. y = -27;
  363. break;
  364. case 85:
  365. case 86:
  366. case 87:
  367. case 128:
  368. case 71:
  369. case 73:
  370. case 76:
  371. case 108:
  372. case 15:
  373. case 134:
  374. case 143:
  375. case 17:
  376. y = -25;
  377. break;
  378. case 75:
  379. y = -23;
  380. break;
  381. case 28:
  382. case 29:
  383. case 78:
  384. case 79:
  385. case 120:
  386. case 137:
  387. case 14:
  388. y = -20;
  389. break;
  390. case 60:
  391. y = -19;
  392. break;
  393. case 31:
  394. y = -18;
  395. break;
  396. case 64:
  397. case 72:
  398. case 74:
  399. case 135:
  400. y = -17;
  401. break;
  402. case 4:
  403. case 46:
  404. case 56:
  405. case 59:
  406. case 13:
  407. y = -14;
  408. break;
  409. case 39:
  410. case 40:
  411. y = -12;
  412. break;
  413. case 42:
  414. y = -11;
  415. break;
  416. case 69:
  417. y = -10;
  418. break;
  419. case 57:
  420. y = -6;
  421. break;
  422. case 129:
  423. y = -4;
  424. break;
  425. case 62:
  426. case 23:
  427. case 80:
  428. case 81:
  429. y = -3;
  430. break;
  431. case 96:
  432. y = -2;
  433. break;
  434. case 33:
  435. case 95:
  436. case 37:
  437. case 99:
  438. case 48:
  439. case 124:
  440. break; //f default 0, so no need to explicitely write it again
  441. case 53:
  442. y = 2;
  443. break;
  444. case 19:
  445. y = 3;
  446. break;
  447. case 32:
  448. case 93:
  449. y = 4;
  450. break;
  451. case 52:
  452. y = 5;
  453. break;
  454. case 121:
  455. case 22:
  456. y = 6;
  457. break;
  458. case 9:
  459. case 27:
  460. case 65:
  461. case 35:
  462. case 36:
  463. case 50:
  464. case 12:
  465. case 11:
  466. y = 10;
  467. break;
  468. case 7:
  469. case 16:
  470. y = 15;
  471. break;
  472. case 45:
  473. y = 18;
  474. break;
  475. case 6:
  476. case 43:
  477. case 3:
  478. case 8:
  479. y = 20;
  480. break;
  481. case 1:
  482. y = 24;
  483. break;
  484. case 63:
  485. y = 25;
  486. break;
  487. case 41:
  488. case 24:
  489. y = 30;
  490. break;
  491. case 115:
  492. y = 32;
  493. break;
  494. case 20:
  495. case 10:
  496. case 133:
  497. y = 40;
  498. break;
  499. case 38:
  500. case 49:
  501. y = 50;
  502. break;
  503. case 61:
  504. case 114:
  505. y = 60;
  506. break;
  507. case 89:
  508. case 97:
  509. case 98:
  510. case 111:
  511. y = 62;
  512. break;
  513. case 90:
  514. y = 90;
  515. break;
  516. case 51:
  517. y = 72;
  518. break;
  519. case 66:
  520. y = 80;
  521. break;
  522. case 112:
  523. y = 85;
  524. break;
  525. case 130:
  526. y = 90;
  527. break;
  528. case 5:
  529. case 26:
  530. case 77:
  531. case 30:
  532. case 92:
  533. y = 100;
  534. break;
  535. case 67:
  536. case 132:
  537. y = 150;
  538. break;
  539. case 131:
  540. y = 160;
  541. break;
  542. case 122:
  543. case 84:
  544. y = 180;
  545. break;
  546. case 109:
  547. y = 240;
  548. break;
  549. case 118:
  550. case 140:
  551. case 138:
  552. case 141:
  553. y = 250;
  554. break;
  555. default:
  556. y = Module_battle_debug.DEBUGframe;
  557. break;
  558. }
  559. break;
  560. case EntityType.Character:
  561. case EntityType.Weapon:
  562. switch(GetId)
  563. {
  564. case 0:
  565. y = -30;
  566. break;
  567. case 1:
  568. case 2:
  569. case 8:
  570. y = -32;
  571. break;
  572. case 3:
  573. y = -64;
  574. break;
  575. case 4:
  576. y = -66;
  577. break;
  578. case 5:
  579. y = -60;
  580. break;
  581. case 6:
  582. y = -26;
  583. break;
  584. case 7:
  585. y = -24;
  586. break;
  587. case 9:
  588. y = -36;
  589. break;
  590. case 10:
  591. y = 0;
  592. break;
  593. default:
  594. y = Module_battle_debug.DEBUGframe;
  595. break;
  596. }
  597. break;
  598. }
  599. y = fScaleResolver+ y/10f;
  600. snapToGround = new Vector3(0, y, 0);
  601. }
  602. /// <summary>
  603. /// Complex function that provides linear interpolation between two matrices of actual to-render animation frame and next frame data for blending
  604. /// </summary>
  605. /// <param name="tuple">the tuple that contains bone identificator and vertex</param>
  606. /// <param name="frame">current animation frame to render</param>
  607. /// <param name="nextFrame">animation frame to render that is AFTER the actual one. If last frame, then usually 0 is the 'next' frame</param>
  608. /// <param name="step">step is variable used to determinate the progress for linear interpolation. I.e. 0 for current frame and 1 for next frame; 0.5 for blend of two frames</param>
  609. /// <returns></returns>
  610. private Tuple<Vector3, int> CalculateFrame(Tuple<Vector3, int> tuple, AnimationFrame frame,AnimationFrame nextFrame, float step)
  611. {
  612. Matrix matrix = frame.boneRot.Item3[tuple.Item2]; //get's bone matrix
  613. Vector3 rootFramePos = new Vector3(
  614. matrix.M11 * tuple.Item1.X + matrix.M41 + matrix.M12 * tuple.Item1.Z + matrix.M13 * -tuple.Item1.Y,
  615. matrix.M21 * tuple.Item1.X + matrix.M42 + matrix.M22 * tuple.Item1.Z + matrix.M23 * -tuple.Item1.Y,
  616. matrix.M31 * tuple.Item1.X + matrix.M43 + matrix.M32 * tuple.Item1.Z + matrix.M33 * -tuple.Item1.Y);
  617. matrix = nextFrame.boneRot.Item3[tuple.Item2];
  618. Vector3 nextFramePos = new Vector3(
  619. matrix.M11 * tuple.Item1.X + matrix.M41 + matrix.M12 * tuple.Item1.Z + matrix.M13 * -tuple.Item1.Y,
  620. matrix.M21 * tuple.Item1.X + matrix.M42 + matrix.M22 * tuple.Item1.Z + matrix.M23 * -tuple.Item1.Y,
  621. matrix.M31 * tuple.Item1.X + matrix.M43 + matrix.M32 * tuple.Item1.Z + matrix.M33 * -tuple.Item1.Y);
  622. rootFramePos = Vector3.Transform(rootFramePos, Matrix.CreateScale(skeleton.GetScale));
  623. nextFramePos = Vector3.Transform(nextFramePos, Matrix.CreateScale(skeleton.GetScale));
  624. rootFramePos = Vector3.SmoothStep(rootFramePos, nextFramePos, step);
  625. return new Tuple<Vector3, int>(rootFramePos, tuple.Item2);
  626. }
  627. #endregion
  628. #region section 3 Animation
  629. public struct AnimationData
  630. {
  631. public uint cAnimations;
  632. public uint[] pAnimations;
  633. public Animation[] animations;
  634. }
  635. public struct Animation
  636. {
  637. public byte cFrames;
  638. public AnimationFrame[] animationFrames;
  639. }
  640. public struct AnimationFrame
  641. {
  642. private Vector3 position;
  643. public Tuple<Vector3[], ShortVector[],Matrix[]> boneRot;
  644. public Vector3 Position { get => position; set => position = value; }
  645. }
  646. public struct ShortVector
  647. {
  648. public short x;
  649. public short y;
  650. public short z;
  651. }
  652. /// <summary>
  653. /// Animation section
  654. /// </summary>
  655. /// <param name="v"></param>
  656. /// <param name="ms"></param>
  657. /// <param name="br"></param>
  658. private void ReadSection3(uint v, MemoryStream ms, BinaryReader br)
  659. {
  660. ms.Seek(v, SeekOrigin.Begin);
  661. animHeader = new AnimationData() {cAnimations = br.ReadUInt32() };
  662. animHeader.pAnimations = new uint[animHeader.cAnimations];
  663. for (int i = 0; i < animHeader.cAnimations; i++)
  664. animHeader.pAnimations[i] = br.ReadUInt32();
  665. animHeader.animations = new Animation[animHeader.cAnimations];
  666. for (int i = 0; i < animHeader.cAnimations; i++) //animation
  667. {
  668. ms.Seek(v + animHeader.pAnimations[i], SeekOrigin.Begin);
  669. animHeader.animations[i] = new Animation() {cFrames = br.ReadByte() };
  670. animHeader.animations[i].animationFrames = new AnimationFrame[animHeader.animations[i].cFrames];
  671. ExtapathyExtended.BitReader bitReader = new ExtapathyExtended.BitReader(ms);
  672. for(int n = 0; n<animHeader.animations[i].cFrames; n++) //frames
  673. {
  674. float x = bitReader.ReadPositionType()*.01f;
  675. float y = bitReader.ReadPositionType() * .01f * -1f;
  676. float z = bitReader.ReadPositionType() * .01f;
  677. animHeader.animations[i].animationFrames[n] = n == 0
  678. ? new AnimationFrame()
  679. {Position = new Vector3(x,y,z)}
  680. : new AnimationFrame()
  681. {Position = new Vector3(
  682. animHeader.animations[i].animationFrames[n - 1].Position.X + x,
  683. animHeader.animations[i].animationFrames[n - 1].Position.Y + y,
  684. animHeader.animations[i].animationFrames[n - 1].Position.Z + z)};
  685. bitReader.ReadBits(1); //padding byte;
  686. animHeader.animations[i].animationFrames[n].boneRot = new Tuple<Vector3[], ShortVector[], Matrix[]>(new Vector3[skeleton.cBones], new ShortVector[skeleton.cBones], new Matrix[skeleton.cBones]);
  687. for (int k = 0; k < skeleton.cBones; k++) //bones iterator
  688. {
  689. if (n != 0)
  690. {
  691. animHeader.animations[i].animationFrames[n].boneRot.Item2[k] = new ShortVector() { x = bitReader.ReadRotationType(), y = bitReader.ReadRotationType(), z = bitReader.ReadRotationType() };
  692. var grabber = animHeader.animations[i].animationFrames[n - 1].boneRot.Item2[k];
  693. var adder = animHeader.animations[i].animationFrames[n].boneRot.Item2[k];
  694. animHeader.animations[i].animationFrames[n].boneRot.Item2[k] = new ShortVector() { x = (short)(grabber.x + adder.x), y = (short)(grabber.y + adder.y), z = (short)(grabber.z + adder.z) };
  695. animHeader.animations[i].animationFrames[n].boneRot.Item1[k] = new Vector3(
  696. (animHeader.animations[i].animationFrames[n].boneRot.Item2[k].x) * 360f / 4096f,
  697. (animHeader.animations[i].animationFrames[n].boneRot.Item2[k].y) * 360f / 4096f,
  698. (animHeader.animations[i].animationFrames[n].boneRot.Item2[k].z) * 360f / 4096f);
  699. }
  700. else
  701. {
  702. animHeader.animations[i].animationFrames[n].boneRot.Item2[k] = new ShortVector() { x = bitReader.ReadRotationType(), y = bitReader.ReadRotationType(), z = bitReader.ReadRotationType() };
  703. animHeader.animations[i].animationFrames[n].boneRot.Item1[k] = new Vector3(
  704. (animHeader.animations[i].animationFrames[n].boneRot.Item2[k].x * 360f / 4096f),
  705. (animHeader.animations[i].animationFrames[n].boneRot.Item2[k].y * 360f / 4096f),
  706. (animHeader.animations[i].animationFrames[n].boneRot.Item2[k].z * 360f / 4096f));
  707. }
  708. }
  709. for(int k = 0; k<skeleton.cBones; k++)
  710. {
  711. var rad = animHeader.animations[i].animationFrames[n].boneRot.Item1[k];
  712. Matrix xRot = Extended.GetRotationMatrixX(-rad.X);
  713. Matrix yRot = Extended.GetRotationMatrixY(-rad.Y);
  714. Matrix zRot = Extended.GetRotationMatrixZ(-rad.Z);
  715. var MatrixZ = Extended.MatrixMultiply_transpose(yRot, xRot);
  716. MatrixZ = Extended.MatrixMultiply_transpose(zRot, MatrixZ);
  717. if (skeleton.bones[k].parentId == 0xFFFF)
  718. {
  719. //I'm leaving the code below, because there might be some issue with M4 dimension for position translation for bone0 only
  720. //Matrix rt = Matrix.CreateTranslation(animHeader.animations[i].animationFrames[n].Position);
  721. //MatrixZ.M41 = rt.M42;
  722. //MatrixZ.M42 = rt.M41; //up/down
  723. //MatrixZ.M43 = rt.M43;
  724. //MatrixZ.M44 = 1;
  725. MatrixZ.M43 = animHeader.animations[i].animationFrames[n].Position.Z + 2;
  726. }
  727. else
  728. {
  729. Matrix prevBone = animHeader.animations[i].animationFrames[n].boneRot.Item3[skeleton.bones[k].parentId];
  730. MatrixZ.M43 = skeleton.bones[skeleton.bones[k].parentId].Size;
  731. Matrix rMatrix = Matrix.Multiply(prevBone, MatrixZ);
  732. rMatrix.M41 = prevBone.M11 * MatrixZ.M41 + prevBone.M12 * MatrixZ.M42 + prevBone.M13 * MatrixZ.M43 + prevBone.M41;
  733. rMatrix.M42 = prevBone.M21 * MatrixZ.M41 + prevBone.M22 * MatrixZ.M42 + prevBone.M23 * MatrixZ.M43 + prevBone.M42;
  734. rMatrix.M43 = prevBone.M31 * MatrixZ.M41 + prevBone.M32 * MatrixZ.M42 + prevBone.M33 * MatrixZ.M43 + prevBone.M43;
  735. MatrixZ = rMatrix;
  736. }
  737. animHeader.animations[i].animationFrames[n].boneRot.Item3[k] = MatrixZ;
  738. }
  739. }
  740. }
  741. }
  742. public AnimationData animHeader;
  743. public int frame;
  744. public float frameperFPS = 0.0f;
  745. #endregion
  746. #region section 7 Information
  747. [StructLayout(LayoutKind.Sequential, Pack =1, Size =380)]
  748. public struct Information
  749. {
  750. [MarshalAs(UnmanagedType.ByValArray,SizeConst =24)]
  751. private char[] monsterName;
  752. public uint hp;
  753. public uint str;
  754. public uint vit;
  755. public uint mag;
  756. public uint spr;
  757. public uint spd;
  758. public uint eva;
  759. public Abilities abilitiesLow;
  760. public Abilities abilitiesMed;
  761. public Abilities abilitiesHigh;
  762. public byte medLevelStart;
  763. public byte highLevelStart;
  764. public byte unk;
  765. public byte bitSwitch;
  766. public byte cardLow;
  767. public byte cardMed;
  768. public byte cardHigh;
  769. public byte devourLow;
  770. public byte devourMed;
  771. public byte devourHigh;
  772. public byte bitSwitch2;
  773. public byte unk2;
  774. public ushort extraExp;
  775. public ushort exp;
  776. public ulong drawLow;
  777. public ulong drawMed;
  778. public ulong drawHigh;
  779. public ulong mugLow;
  780. public ulong mugMed;
  781. public ulong mugHigh;
  782. public ulong dropLow;
  783. public ulong dropMed;
  784. public ulong dropHigh;
  785. public byte mugRate;
  786. public byte dropRate;
  787. public byte padding;
  788. public byte ap;
  789. [MarshalAs(UnmanagedType.ByValArray, SizeConst =16)]
  790. public byte[] unk3;
  791. public byte fireResistance;
  792. public byte iceResistance;
  793. public byte thunderResistance;
  794. public byte earthResistance;
  795. public byte poisonResistance;
  796. public byte windResistance;
  797. public byte waterResistance;
  798. public byte holyResistance;
  799. public byte deathResistanceMental;
  800. public byte poisonResistanceMental;
  801. public byte petrifyResistanceMental;
  802. public byte darknessResistanceMental;
  803. public byte silenceResistanceMental;
  804. public byte berserkResistanceMental;
  805. public byte zombieResistanceMental;
  806. public byte sleepResistanceMental;
  807. public byte hasteResistanceMental;
  808. public byte slowResistanceMental;
  809. public byte stopResistanceMental;
  810. public byte regenResistanceMental;
  811. public byte reflectResistanceMental;
  812. public byte doomResistanceMental;
  813. public byte slowPetrifyResistanceMental;
  814. public byte floatResistanceMental;
  815. public byte confuseResistanceMental;
  816. public byte drainResistanceMental;
  817. public byte explusionResistanceMental;
  818. public byte unkResistanceMental;
  819. public string GetNameNormal => new string(monsterName);
  820. }
  821. public struct Abilities
  822. {
  823. public byte kernelId; //0x2 magic, 0x4 item, 0x8 mosterAbility;
  824. public byte unk;
  825. public ushort abilityId;
  826. }
  827. private void ReadSection7(uint v, MemoryStream ms, BinaryReader br)
  828. {
  829. ms.Seek(v, SeekOrigin.Begin);
  830. }
  831. public Information information;
  832. #endregion
  833. #region section 11 Textures
  834. public struct Textures
  835. {
  836. public uint cTims;
  837. public uint[] pTims;
  838. public uint Eof;
  839. public Texture2D[] textures;
  840. }
  841. private void ReadSection11(uint v, MemoryStream ms, BinaryReader br)
  842. {
  843. ms.Seek(v, SeekOrigin.Begin);
  844. textures = new Textures() { cTims = br.ReadUInt32() };
  845. textures.pTims = new uint[textures.cTims];
  846. for (int i = 0; i < textures.cTims; i++)
  847. textures.pTims[i] = br.ReadUInt32();
  848. textures.Eof = br.ReadUInt32();
  849. textures.textures = new Texture2D[textures.cTims];
  850. for(int i = 0; i<textures.cTims; i++)
  851. {
  852. ms.Seek(v + textures.pTims[i], SeekOrigin.Begin);
  853. TIM2 tm = new TIM2(buffer, (uint)ms.Position); //broken
  854. textures.textures[i] = new Texture2D(Memory.graphics.GraphicsDevice, tm.GetWidth, tm.GetHeight, false,
  855. SurfaceFormat.Color);
  856. textures.textures[i].SetData(tm.CreateImageBuffer(tm.GetClutColors(0), true)); //??
  857. tm.KillStreams();
  858. }
  859. }
  860. public Textures textures;
  861. #endregion
  862. public enum EntityType
  863. {
  864. Monster,
  865. Character,
  866. Weapon
  867. };
  868. /// <summary>
  869. /// Creates new instance of DAT class that provides every sections parsed into structs and helper functions for renderer
  870. /// </summary>
  871. /// <param name="fileId">This number is used in c0m(fileId) or d(fileId)cXYZ</param>
  872. /// <param name="entityType">Supply Monster, character or weapon (0,1,2)</param>
  873. /// <param name="additionalFileId">Used only in character or weapon to supply for d(fileId)[c/w](additionalFileId)</param>
  874. public Debug_battleDat(int fileId, EntityType entityType, int additionalFileId = -1, Debug_battleDat skeletonReference = null)
  875. {
  876. id = fileId;
  877. Console.WriteLine($"DEBUG: Creating new BattleDat with {fileId},{entityType},{additionalFileId}");
  878. ArchiveWorker aw = new ArchiveWorker(Memory.Archives.A_BATTLE);
  879. string fileName = entityType == EntityType.Monster ? $"c0m{id.ToString("D03")}" :
  880. entityType == EntityType.Character ? $"d{fileId.ToString("x")}c{additionalFileId.ToString("D03")}" :
  881. entityType == EntityType.Weapon ? $"d{fileId.ToString("x")}w{additionalFileId.ToString("D03")}" : string.Empty;
  882. this.entityType = entityType;
  883. if (string.IsNullOrEmpty(fileName))
  884. return;
  885. string path = aw.GetListOfFiles().First(x => x.ToLower().Contains(fileName));
  886. buffer = ArchiveWorker.GetBinaryFile(Memory.Archives.A_BATTLE, path);
  887. #if _WINDOWS
  888. try
  889. {
  890. string targetdir = @"d:\";
  891. if (Directory.Exists(targetdir))
  892. {
  893. var drivei = DriveInfo.GetDrives().Where(x => x.Name.IndexOf(Path.GetPathRoot(targetdir),StringComparison.OrdinalIgnoreCase)>=0).ToArray();
  894. var di = new DirectoryInfo(targetdir);
  895. if(!di.Attributes.HasFlag(FileAttributes.ReadOnly) && drivei.Count()==1 && drivei[0].DriveType == DriveType.Fixed)
  896. Extended.DumpBuffer(buffer, Path.Combine(targetdir,"out.dat"));
  897. }
  898. }
  899. catch(IOException)
  900. {
  901. }
  902. #endif
  903. using (MemoryStream ms = new MemoryStream(buffer))
  904. using (BinaryReader br = new BinaryReader(ms))
  905. {
  906. datFile = new DatFile { cSections = br.ReadUInt32()};
  907. datFile.pSections = new uint[datFile.cSections];
  908. for (int i = 0; i < datFile.cSections; i++)
  909. datFile.pSections[i] = br.ReadUInt32();
  910. datFile.eof = br.ReadUInt32();
  911. switch (this.entityType)
  912. {
  913. case EntityType.Monster:
  914. if (id == 127) return;
  915. ReadSection1(datFile.pSections[0], ms, br);
  916. ReadSection3(datFile.pSections[2], ms, br);
  917. ReadSection2(datFile.pSections[1], ms, br);
  918. //ReadSection4(datFile.pSections[3]);
  919. //ReadSection5(datFile.pSections[4]);
  920. //ReadSection6(datFile.pSections[5]);
  921. ReadSection7(datFile.pSections[6], ms, br);
  922. //ReadSection8(datFile.pSections[7]);
  923. //ReadSection9(datFile.pSections[8]);
  924. //ReadSection10(datFile.pSections[9]);
  925. ReadSection11(datFile.pSections[10], ms, br);
  926. break;
  927. case EntityType.Character:
  928. ReadSection1(datFile.pSections[0], ms, br);
  929. ReadSection3(datFile.pSections[2], ms, br);
  930. ReadSection2(datFile.pSections[1], ms, br);
  931. if(fileId==7 && entityType==EntityType.Character)
  932. ReadSection11(datFile.pSections[8], ms, br);
  933. else
  934. ReadSection11(datFile.pSections[5], ms, br);
  935. break;
  936. case EntityType.Weapon:
  937. if (skeletonReference == null)
  938. {
  939. ReadSection1(datFile.pSections[0], ms, br);
  940. ReadSection3(datFile.pSections[2], ms, br);
  941. ReadSection2(datFile.pSections[1], ms, br);
  942. ReadSection11(datFile.pSections[6], ms, br);
  943. }
  944. else
  945. {
  946. skeleton = skeletonReference.skeleton;
  947. animHeader = skeletonReference.animHeader;
  948. ReadSection2(datFile.pSections[0], ms, br);
  949. ReadSection11(datFile.pSections[4], ms, br);
  950. }
  951. break;
  952. }
  953. }
  954. }
  955. public int GetId => id;
  956. }
  957. }