module_battle_Debug.cs 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473
  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. using Microsoft.Xna.Framework.Input;
  9. namespace FF8
  10. {
  11. static class Module_battle_debug
  12. {
  13. private static uint bs_cameraPointer;
  14. private static Matrix projectionMatrix, viewMatrix, worldMatrix;
  15. private static float degrees=90, Yshift;
  16. private static readonly float camDistance = 10.0f;
  17. private static Vector3 camPosition, camTarget;
  18. private static TIM2 textureInterface;
  19. private static Texture2D[] textures;
  20. static List<EnemyInstanceInformation> EnemyInstances;
  21. static List<CharacterInstanceInformation> CharacterInstances;
  22. //skyRotating floats are hardcoded
  23. private static readonly ushort[] skyRotators = { 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x4, 0x4, 0x0, 0x0, 0x4, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x4, 0x4, 0x0, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x2, 0x0, 0x0, 0x8, 0xfffc, 0xfffc, 0x0, 0x0, 0x0, 0x4, 0x0, 0x8, 0x0, 0x4, 0x4, 0x0, 0x4, 0x0, 0x4, 0xfffc, 0x8, 0xfffc, 0xfffc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x4, 0x4, 0x0, 0x0, 0x4, 0x4, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x4, 0x4, 0x8, 0xfffc, 0x4, 0x4, 0x4, 0x4, 0x8, 0x8, 0x4, 0xfffc, 0xfffc, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0xfffc, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x8, 0xfffc, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x8, 0x0, 0x8, 0x8 };
  24. static float localRotator = 0.0f; //a rotator is a float that holds current axis rotation for sky. May be malformed by skyRotators or TimeCompression magic
  25. public static BasicEffect effect;
  26. public static AlphaTestEffect ate;
  27. private static string battlename = "a0stg000.x";
  28. private static byte[] stageBuffer;
  29. private static int battleModule = 0;
  30. //This should be enum btw
  31. private const int BATTLEMODULE_INIT = 0; //basic init stuff; renderer; core
  32. private const int BATTLEMODULE_READDATA = 1; //parses battle stage and all monsters
  33. private const int BATTLEMODULE_DRAWGEOMETRY = 2; //draw geometry also supports updateCamera
  34. private const int BATTLEMODULE_ACTIVE = 3;
  35. private const float FPS = 1000.0f / 15f; //Natively the game we are rewritting works in 15 FPS per second
  36. /// <summary>
  37. /// This is helper struct that works along with VertexPosition to provide Clut, texture page and bool to decide if it's quad or triangle
  38. /// </summary>
  39. private struct Stage_GeometryInfoSupplier
  40. {
  41. public bool bQuad;
  42. public byte clut;
  43. public byte texPage;
  44. }
  45. private struct EnemyInstanceInformation
  46. {
  47. public Debug_battleDat Data;
  48. /// <summary>
  49. /// bit position of the enemy in encounter data. Use to pair the information with encounter data
  50. /// </summary>
  51. public byte index;
  52. public bool bIsHidden;
  53. public bool bIsActive;
  54. public bool bIsUntargetable;
  55. public AnimationSystem animationSystem;
  56. }
  57. /// <summary>
  58. /// CharacterInstanceInformation should only be used for battle-exclusive data. Manipulating HP, GFs, junctions and other character-specific
  59. /// things should happen outside battle, because such information about characters is shared between almost all modules.
  60. /// This field contains information about the current status of battle rendering like animation frames/ rendering flags/ effects attached
  61. /// </summary>
  62. private struct CharacterInstanceInformation
  63. {
  64. public CharacterData Data;
  65. public int characterId; //0 is Whatever guy
  66. public bool bIsHidden; //GF sequences, magic...
  67. public AnimationSystem animationSystem;
  68. }
  69. private struct Triangle
  70. {
  71. public ushort A;
  72. public ushort B;
  73. public ushort C;
  74. public byte U1;
  75. public byte V1;
  76. public byte U2;
  77. public byte V2;
  78. public byte clut;
  79. public byte U3;
  80. public byte V3;
  81. public byte TexturePage;
  82. public byte bHide;
  83. public byte Red;
  84. public byte Green;
  85. public byte Blue;
  86. public byte GPU;
  87. }
  88. private struct Quad
  89. {
  90. public ushort A;
  91. public ushort B;
  92. public ushort C;
  93. public ushort D;
  94. public byte U1;
  95. public byte V1;
  96. public byte clut;
  97. public byte U2;
  98. public byte V2;
  99. public byte TexturePage;
  100. public byte bHide;
  101. public byte U3;
  102. public byte V3;
  103. public byte U4;
  104. public byte V4;
  105. public byte Red;
  106. public byte Green;
  107. public byte Blue;
  108. public byte GPU;
  109. }
  110. private struct MainGeometrySection
  111. {
  112. public uint Group1Pointer;
  113. public uint Group2Pointer;
  114. public uint Group3Pointer;
  115. public uint Group4Pointer;
  116. public uint TextureUNUSEDPointer;
  117. public uint TexturePointer;
  118. public uint EOF;
  119. }
  120. private struct ObjectsGroup
  121. {
  122. public uint numberOfSections;
  123. public uint settings1Pointer;
  124. public uint objectListPointer;
  125. public uint settings2Pointer;
  126. public uint relativeEOF;
  127. }
  128. private struct Vertex
  129. {
  130. public short X;
  131. public short Y;
  132. public short Z;
  133. }
  134. private struct Model
  135. {
  136. public Vertex[] vertices;
  137. public Triangle[] triangles;
  138. public Quad[] quads;
  139. }
  140. private struct ModelGroup
  141. {
  142. public Model[] models;
  143. }
  144. private static ModelGroup[] modelGroups;
  145. private static Debug_battleDat[] monstersData;
  146. private struct CharacterData
  147. {
  148. public Debug_battleDat character, weapon;
  149. };
  150. private static MemoryStream ms;
  151. private static BinaryReader br;
  152. private static byte GetTexturePage(byte texturepage) => (byte)(texturepage & 0x0F);
  153. private static byte GetClutId(ushort clut)
  154. {
  155. ushort bb = Extended.UshortLittleEndian(clut);
  156. return (byte)(((bb >> 14) & 0x03) | (bb << 2) & 0x0C);
  157. }
  158. public static void ResetState() { battleModule = BATTLEMODULE_INIT; }
  159. public static void Update()
  160. {
  161. switch (battleModule)
  162. {
  163. case BATTLEMODULE_INIT:
  164. InitBattle();
  165. break;
  166. case BATTLEMODULE_READDATA:
  167. ReadData();
  168. break;
  169. case BATTLEMODULE_DRAWGEOMETRY:
  170. //UpdateCamera();
  171. FPSCamera();
  172. break;
  173. }
  174. #if DEBUG
  175. if (Input.Button(Keys.D1))
  176. DEBUGframe += 1;
  177. if (Input.Button(Keys.D2))
  178. DEBUGframe--;
  179. if (Input.Button(Keys.D3))
  180. battleModule = BATTLEMODULE_INIT;
  181. if(Input.Button(Keys.D4))
  182. {
  183. battleModule = BATTLEMODULE_INIT;
  184. Memory.battle_encounter++;
  185. }
  186. #endif
  187. }
  188. public static void Draw()
  189. {
  190. switch (battleModule)
  191. {
  192. case BATTLEMODULE_DRAWGEOMETRY:
  193. DrawGeometry();
  194. DrawMonsters();
  195. DrawCharactersWeapons();
  196. UpdateFrames();
  197. break;
  198. }
  199. }
  200. private static void UpdateCamera()
  201. {
  202. const float V = 100f;
  203. //battleCamera.cam.startingTime = 64;
  204. float step = battleCamera.cam.startingTime / (float)battleCamera.cam.time;
  205. float camWorldX = MathHelper.Lerp(battleCamera.cam.Camera_World_X_s16[0] / V,
  206. battleCamera.cam.Camera_World_X_s16[1] / V, step) -60;
  207. float camWorldY = MathHelper.Lerp(battleCamera.cam.Camera_World_Y_s16[0] / V,
  208. battleCamera.cam.Camera_World_Y_s16[1] / V, step);
  209. float camWorldZ = MathHelper.Lerp(battleCamera.cam.Camera_World_Z_s16[0] / V,
  210. battleCamera.cam.Camera_World_Z_s16[1] / V, step) +40;
  211. float camTargetX = MathHelper.Lerp(battleCamera.cam.Camera_Lookat_X_s16[0] / V,
  212. battleCamera.cam.Camera_Lookat_X_s16[1] / V, step) -20;
  213. float camTargetY = MathHelper.Lerp(battleCamera.cam.Camera_Lookat_Y_s16[0] / V,
  214. battleCamera.cam.Camera_Lookat_Y_s16[1] / V, step) +25;
  215. float camTargetZ = MathHelper.Lerp(battleCamera.cam.Camera_Lookat_Z_s16[0] / V,
  216. battleCamera.cam.Camera_Lookat_Z_s16[1] / V, step) -20;
  217. camPosition = new Vector3(-camWorldX, camWorldY, -camWorldZ);
  218. camTarget = new Vector3(camTargetY, -camTargetX, -camTargetZ);
  219. float fovDirector = MathHelper.Lerp(battleCamera.cam.startingFOV, battleCamera.cam.endingFOV, step);
  220. viewMatrix = Matrix.CreateLookAt(camPosition, camTarget,
  221. Vector3.Up);
  222. projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
  223. MathHelper.ToRadians(fovDirector/6),
  224. Memory.graphics.GraphicsDevice.DisplayMode.AspectRatio,
  225. 1f, 1000f);
  226. //ate = new AlphaTestEffect(Memory.graphics.GraphicsDevice)
  227. //{
  228. // Projection = projectionMatrix,
  229. // View = viewMatrix,
  230. // World = worldMatrix
  231. //};
  232. if (battleCamera.cam.startingTime >= battleCamera.cam.time)
  233. return;
  234. battleCamera.cam.startingTime += 4;
  235. }
  236. /// <summary>
  237. /// Method to render characters and weapons for them
  238. /// </summary>
  239. private static void DrawCharactersWeapons()
  240. {
  241. Memory.graphics.GraphicsDevice.RasterizerState = RasterizerState.CullNone;
  242. Memory.graphics.GraphicsDevice.BlendState = BlendState.AlphaBlend;
  243. Memory.graphics.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
  244. Memory.graphics.GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
  245. ate.Projection = projectionMatrix; ate.View = viewMatrix; ate.World = worldMatrix;
  246. effect.TextureEnabled = true;
  247. //CHARACTER
  248. for (int n = 0; n < CharacterInstances.Count; n++)
  249. {
  250. CheckAnimationFrame(Debug_battleDat.EntityType.Character, n);
  251. Vector3 charaPosition = new Vector3(-40 + n * 10, 0, -40);
  252. for (int i = 0; i < CharacterInstances[n].Data.character.geometry.cObjects; i++)
  253. {
  254. var a = CharacterInstances[n].Data.character.GetVertexPositions(i,charaPosition ,Quaternion.CreateFromYawPitchRoll(3f,0,0), CharacterInstances[n].animationSystem.animationId, CharacterInstances[n].animationSystem.animationFrame, frameperFPS / FPS); //DEBUG
  255. if (a == null || a.Item1.Length == 0)
  256. return;
  257. for (int k = 0; k < a.Item1.Length / 3; k++)
  258. {
  259. ate.Texture = CharacterInstances[n].Data.character.textures.textures[a.Item2[k]];
  260. foreach (var pass in ate.CurrentTechnique.Passes)
  261. {
  262. pass.Apply();
  263. Memory.graphics.GraphicsDevice.DrawUserPrimitives(primitiveType: PrimitiveType.TriangleList,
  264. vertexData: a.Item1, vertexOffset: k*3, primitiveCount: 1);
  265. }
  266. }
  267. }
  268. DrawShadow(charaPosition, ate, .5f);
  269. }
  270. //WEAPON
  271. for (int n = 0; n < CharacterInstances.Count; n++)
  272. { if (CharacterInstances[n].Data.weapon == null)
  273. return;
  274. CheckAnimationFrame(Debug_battleDat.EntityType.Weapon, n);
  275. Vector3 weaponPosition = new Vector3(-40 + n * 10, 0+DEBUGframe, -40+1);
  276. for (int i = 0; i < CharacterInstances[n].Data.weapon.geometry.cObjects; i++)
  277. {
  278. var a = CharacterInstances[n].Data.weapon.GetVertexPositions(i, weaponPosition, Quaternion.CreateFromYawPitchRoll(3f, 0, 0), CharacterInstances[n].animationSystem.animationId, CharacterInstances[n].animationSystem.animationFrame, frameperFPS / FPS); //DEBUG
  279. if (a == null || a.Item1.Length == 0)
  280. return;
  281. for (int k = 0; k < a.Item1.Length / 3; k++)
  282. {
  283. ate.Texture = CharacterInstances[n].Data.weapon.textures.textures[a.Item2[k]];
  284. foreach (var pass in ate.CurrentTechnique.Passes)
  285. {
  286. pass.Apply();
  287. Memory.graphics.GraphicsDevice.DrawUserPrimitives(primitiveType: PrimitiveType.TriangleList,
  288. vertexData: a.Item1, vertexOffset: k*3, primitiveCount: 1);
  289. }
  290. }
  291. }
  292. }
  293. }
  294. private static void CheckAnimationFrame(Debug_battleDat.EntityType type, int n)
  295. {
  296. Debug_battleDat.Animation animationSystem;
  297. switch(type)
  298. {
  299. case Debug_battleDat.EntityType.Monster:
  300. animationSystem = EnemyInstances[n].Data.animHeader.animations[EnemyInstances[n].animationSystem.animationId];
  301. if (EnemyInstances[n].animationSystem.animationFrame >= animationSystem.cFrames)
  302. {
  303. var InstanceInformationProvider = EnemyInstances[n];
  304. InstanceInformationProvider.animationSystem.animationFrame = 0;
  305. if (EnemyInstances[n].animationSystem.AnimationQueue.Count > 0)
  306. {
  307. InstanceInformationProvider.animationSystem.animationId = EnemyInstances[n].animationSystem.AnimationQueue.First();
  308. EnemyInstances[n].animationSystem.AnimationQueue.RemoveAt(0);
  309. }
  310. EnemyInstances[n] = InstanceInformationProvider;
  311. }
  312. return;
  313. case Debug_battleDat.EntityType.Character:
  314. case Debug_battleDat.EntityType.Weapon:
  315. animationSystem = CharacterInstances[n].Data.character.animHeader.animations[CharacterInstances[n].animationSystem.animationId];
  316. if (CharacterInstances[n].animationSystem.animationFrame >= animationSystem.cFrames)
  317. {
  318. var InstanceInformationProvider = CharacterInstances[n];
  319. InstanceInformationProvider.animationSystem.animationFrame = 0;
  320. if (CharacterInstances[n].animationSystem.AnimationQueue.Count > 0)
  321. {
  322. InstanceInformationProvider.animationSystem.animationId = CharacterInstances[n].animationSystem.AnimationQueue.First();
  323. CharacterInstances[n].animationSystem.AnimationQueue.RemoveAt(0);
  324. }
  325. CharacterInstances[n] = InstanceInformationProvider;
  326. }
  327. return;
  328. default:
  329. return;
  330. }
  331. }
  332. /// <summary>
  333. /// Animation system. Decided to go for struct, so I can attach it to instance and manipulate easily grouped. It's also open for modifications
  334. /// </summary>
  335. private struct AnimationSystem
  336. {
  337. public int animationId;
  338. public int animationFrame;
  339. public bool bStopAnimation; //pertification placeholder?
  340. public List<int> AnimationQueue;
  341. }
  342. public static int DEBUGframe = 0;
  343. private static void DrawMonsters()
  344. {
  345. Memory.graphics.GraphicsDevice.RasterizerState = RasterizerState.CullNone;
  346. Memory.graphics.GraphicsDevice.BlendState = BlendState.AlphaBlend;
  347. Memory.graphics.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
  348. Memory.graphics.GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
  349. ate.Projection = projectionMatrix; ate.View = viewMatrix; ate.World = worldMatrix;
  350. effect.TextureEnabled = true;
  351. if (EnemyInstances == null)
  352. return;
  353. for (int n = 0; n < EnemyInstances.Count; n++)
  354. {
  355. if (EnemyInstances[n].Data.GetId == 127)
  356. {
  357. //TODO;
  358. continue;
  359. }
  360. CheckAnimationFrame(Debug_battleDat.EntityType.Monster, n);
  361. var enemyPosition = Memory.encounters[Memory.battle_encounter].enemyCoordinates.GetEnemyCoordinateByIndex(EnemyInstances[n].index);
  362. for (int i = 0; i < EnemyInstances[n].Data.geometry.cObjects; i++)
  363. {
  364. var a = EnemyInstances[n].Data.GetVertexPositions(
  365. objectId: i,
  366. position: enemyPosition.GetVector(),
  367. rotation: Quaternion.CreateFromYawPitchRoll(0, 0, 0),
  368. animationId: EnemyInstances[n].animationSystem.animationId,
  369. animationFrame: EnemyInstances[n].animationSystem.animationFrame,
  370. step: frameperFPS / FPS);
  371. if (a == null || a.Item1.Length == 0)
  372. return;
  373. for (int k = 0; k < a.Item1.Length / 3; k++)
  374. {
  375. ate.Texture = EnemyInstances[n].Data.textures.textures[a.Item2[k]];
  376. foreach (var pass in ate.CurrentTechnique.Passes)
  377. {
  378. pass.Apply();
  379. Memory.graphics.GraphicsDevice.DrawUserPrimitives(primitiveType: PrimitiveType.TriangleList,
  380. vertexData: a.Item1, vertexOffset: k * 3, primitiveCount: 1);
  381. }
  382. }
  383. }
  384. DrawShadow(enemyPosition.GetVector(), ate, EnemyInstances[n].Data.skeleton.GetScale.X/5);
  385. }
  386. }
  387. private static void DrawShadow(Vector3 enemyPosition, AlphaTestEffect ate, float scale)
  388. {
  389. VertexPositionTexture[] ptCopy = Memory.shadowGeometry.Clone() as VertexPositionTexture[];
  390. for(int i = 0; i<ptCopy.Length; i++)
  391. ptCopy[i].Position = Vector3.Transform(ptCopy[i].Position, Matrix.CreateScale(scale));
  392. for (int i = 0; i < ptCopy.Length; i++)
  393. ptCopy[i].Position = Vector3.Add(ptCopy[i].Position, new Vector3(enemyPosition.X, 0.1f, enemyPosition.Z));
  394. ate.Texture = Memory.shadowTexture;
  395. foreach(var pass in ate.CurrentTechnique.Passes)
  396. {
  397. pass.Apply();
  398. Memory.graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, ptCopy, 0, 8);
  399. }
  400. }
  401. /// <summary>
  402. /// Increments animation frames by N, where N is equal to int(deltaTime/FPS).
  403. /// 15FPS is one frame per ~66 miliseconds. Therefore if deltaTime hits at least:
  404. /// below 33, then frame gets interpolated
  405. /// above 122, then frame gets skipped (by x/66)
  406. /// </summary>
  407. private static void UpdateFrames()
  408. {
  409. float tick = Memory.gameTime.ElapsedGameTime.Milliseconds;
  410. frameperFPS += tick;
  411. if (frameperFPS > FPS)
  412. {
  413. for (int x = 0; x < EnemyInstances.Count; x++)
  414. {
  415. var InstanceInformationProvider = EnemyInstances[x];
  416. InstanceInformationProvider.animationSystem.animationFrame++;
  417. EnemyInstances[x] = InstanceInformationProvider;
  418. }
  419. for (int x = 0; x < CharacterInstances.Count; x++)
  420. {
  421. var InstanceInformationProvider = CharacterInstances[x];
  422. InstanceInformationProvider.animationSystem.animationFrame++;
  423. CharacterInstances[x] = InstanceInformationProvider;
  424. }
  425. frameperFPS = 0.0f;
  426. }
  427. }
  428. /// <summary>
  429. /// Plays requested animation for given entity immidiately (without waiting for current animation to stop if have any queued animations)
  430. /// </summary>
  431. /// <param name="entityType">Provide either Monster or Character/weapon</param>
  432. /// <param name="nIndex">Index of entityTypeInstance. Monster is monsterInstances, character is CharacterInstances</param>
  433. /// <param name="newAnimId">self explanatory</param>
  434. public static void PlayAnimationImmidiately(Debug_battleDat.EntityType entityType, int nIndex, int newAnimId)
  435. {
  436. switch(entityType)
  437. {
  438. case Debug_battleDat.EntityType.Monster:
  439. EnemyInstanceInformation MInstanceInformationProvider = EnemyInstances[nIndex];
  440. MInstanceInformationProvider.animationSystem.animationId = newAnimId;
  441. MInstanceInformationProvider.animationSystem.animationFrame = 0;
  442. EnemyInstances[nIndex] = MInstanceInformationProvider;
  443. return;
  444. case Debug_battleDat.EntityType.Character:
  445. case Debug_battleDat.EntityType.Weapon:
  446. CharacterInstanceInformation CInstanceInformationProvider = CharacterInstances[nIndex];
  447. CInstanceInformationProvider.animationSystem.animationId = newAnimId;
  448. CInstanceInformationProvider.animationSystem.animationFrame = 0;
  449. CharacterInstances[nIndex] = CInstanceInformationProvider;
  450. return;
  451. default:
  452. return;
  453. }
  454. }
  455. public static void AddAnimationToQueue(Debug_battleDat.EntityType entityType, int nIndex, int newAnimId)
  456. {
  457. switch (entityType)
  458. {
  459. case Debug_battleDat.EntityType.Monster:
  460. EnemyInstanceInformation MInstanceInformationProvider = EnemyInstances[nIndex];
  461. MInstanceInformationProvider.animationSystem.AnimationQueue.Add(newAnimId);
  462. EnemyInstances[nIndex] = MInstanceInformationProvider;
  463. return;
  464. case Debug_battleDat.EntityType.Character:
  465. case Debug_battleDat.EntityType.Weapon:
  466. CharacterInstanceInformation CInstanceInformationProvider = CharacterInstances[nIndex];
  467. CInstanceInformationProvider.animationSystem.AnimationQueue.Add(newAnimId);
  468. CharacterInstances[nIndex] = CInstanceInformationProvider;
  469. return;
  470. default:
  471. return;
  472. }
  473. }
  474. const float defaultmaxMoveSpeed = 1f;
  475. const float MoveSpeedChange = 1f;
  476. static float maxMoveSpeed = defaultmaxMoveSpeed;
  477. const float maxLookSpeed = 0.25f;
  478. public static void FPSCamera()
  479. {
  480. #region FPScamera
  481. //speedcontrols
  482. //+ to increase
  483. //- to decrease
  484. //* to reset
  485. if (Input.Button(Keys.OemPlus) || Input.Button(Keys.Add))
  486. {
  487. maxMoveSpeed += MoveSpeedChange;
  488. }
  489. if (Input.Button(Keys.OemMinus) || Input.Button(Keys.Subtract))
  490. {
  491. maxMoveSpeed -= MoveSpeedChange;
  492. if (maxMoveSpeed < defaultmaxMoveSpeed) maxMoveSpeed = defaultmaxMoveSpeed;
  493. }
  494. if (Input.Button(Keys.Multiply)) maxMoveSpeed = defaultmaxMoveSpeed;
  495. //speed is effected by the milliseconds between frames. so alittle goes a long way. :P
  496. float x_shift = Input.Distance(Buttons.MouseXjoy, maxLookSpeed);
  497. float y_shift = Input.Distance(Buttons.MouseYjoy, maxLookSpeed);
  498. float leftdistX = Math.Abs(Input.Distance(Buttons.LeftStickX, maxMoveSpeed));
  499. float leftdistY = Math.Abs(Input.Distance(Buttons.LeftStickY, maxMoveSpeed));
  500. x_shift += Input.Distance(Buttons.RightStickX, maxLookSpeed);
  501. y_shift += Input.Distance(Buttons.RightStickY, maxLookSpeed);
  502. Yshift -= y_shift;
  503. degrees = (degrees + (int)x_shift) % 360;
  504. Yshift = MathHelper.Clamp(Yshift, -80, 80);
  505. if (leftdistY == 0)
  506. {
  507. leftdistY = Input.Distance(maxMoveSpeed);
  508. }
  509. if (leftdistX == 0)
  510. {
  511. leftdistX = Input.Distance(maxMoveSpeed);
  512. }
  513. if (Input.Button(Buttons.Up))
  514. {
  515. camPosition.X += (float)Math.Cos(MathHelper.ToRadians(degrees)) * leftdistY / 10;
  516. camPosition.Z += (float)Math.Sin(MathHelper.ToRadians(degrees)) * leftdistY / 10;
  517. camPosition.Y -= Yshift / 50;
  518. }
  519. if (Input.Button(Buttons.Down))
  520. {
  521. camPosition.X -= (float)Math.Cos(MathHelper.ToRadians(degrees)) * leftdistY / 10;
  522. camPosition.Z -= (float)Math.Sin(MathHelper.ToRadians(degrees)) * leftdistY / 10;
  523. camPosition.Y += Yshift / 50;
  524. }
  525. if (Input.Button(Buttons.Left))
  526. {
  527. camPosition.X += (float)Math.Cos(MathHelper.ToRadians(degrees - 90)) * leftdistX / 10;
  528. camPosition.Z += (float)Math.Sin(MathHelper.ToRadians(degrees - 90)) * leftdistX / 10;
  529. }
  530. if (Input.Button(Buttons.Right))
  531. {
  532. camPosition.X += (float)Math.Cos(MathHelper.ToRadians(degrees + 90)) * leftdistX / 10;
  533. camPosition.Z += (float)Math.Sin(MathHelper.ToRadians(degrees + 90)) * leftdistX / 10;
  534. }
  535. //Input.LockMouse();
  536. camTarget.X = camPosition.X + (float)Math.Cos(MathHelper.ToRadians(degrees)) * camDistance;
  537. camTarget.Z = camPosition.Z + (float)Math.Sin(MathHelper.ToRadians(degrees)) * camDistance;
  538. camTarget.Y = camPosition.Y - Yshift / 5;
  539. viewMatrix = Matrix.CreateLookAt(camPosition, camTarget,
  540. Vector3.Up);
  541. #endregion
  542. }
  543. private static void DrawGeometry()
  544. {
  545. Memory.spriteBatch.GraphicsDevice.Clear(Color.Black);
  546. Memory.graphics.GraphicsDevice.RasterizerState = RasterizerState.CullNone;
  547. Memory.graphics.GraphicsDevice.BlendState = BlendState.AlphaBlend;
  548. Memory.graphics.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
  549. Memory.graphics.GraphicsDevice.SamplerStates[0] = SamplerState.PointClamp;
  550. ate.Projection = projectionMatrix; ate.View = viewMatrix; ate.World = worldMatrix;
  551. effect.TextureEnabled = true;
  552. for(int n = 0; n < modelGroups.Length; n++)
  553. foreach (var b in modelGroups[n].models)
  554. {
  555. var vpt = GetVertexBuffer(b);
  556. if (n == 3 && skyRotators[Memory.encounters[Memory.battle_encounter].Scenario] != 0)
  557. CreateRotation(vpt);
  558. if (vpt == null) continue;
  559. int localVertexIndex = 0;
  560. for (int i = 0; i < vpt.Item1.Length; i++)
  561. {
  562. ate.Texture = textures[vpt.Item1[i].clut]; //provide texture per-face
  563. foreach (var pass in ate.CurrentTechnique.Passes)
  564. {
  565. pass.Apply();
  566. if (vpt.Item1[i].bQuad)
  567. {
  568. Memory.graphics.GraphicsDevice.DrawUserPrimitives(primitiveType: PrimitiveType.TriangleList,
  569. vertexData: vpt.Item2, vertexOffset: localVertexIndex, primitiveCount: 2);
  570. localVertexIndex += 6;
  571. }
  572. else
  573. {
  574. Memory.graphics.GraphicsDevice.DrawUserPrimitives(primitiveType: PrimitiveType.TriangleList,
  575. vertexData: vpt.Item2, vertexOffset: localVertexIndex, primitiveCount: 1);
  576. localVertexIndex += 3;
  577. }
  578. }
  579. }
  580. }
  581. Memory.SpriteBatchStartAlpha();
  582. /*Memory.font.RenderBasicText(
  583. $"Encounter ready at: {Memory.battle_encounter}\n" +
  584. $"Debug variable: {DEBUGframe}\n" +
  585. $"1000/deltaTime milliseconds: {Math.Round((double)1000 / Memory.gameTime.ElapsedGameTime.Milliseconds,2)}",
  586. 30,20,lineSpacing: 5);*/
  587. Memory.font.RenderBasicText(new FF8String($"Encounter ready at: {Memory.battle_encounter}"), 0, 0, 1, 1, 0, 1);
  588. Memory.font.RenderBasicText(new FF8String($"Debug variable: {DEBUGframe}"), 20, 30 * 1, 1, 1, 0, 1);
  589. Memory.font.RenderBasicText(new FF8String($"1000/deltaTime milliseconds: {1000/Memory.gameTime.ElapsedGameTime.Milliseconds}"), 20, 30 * 2, 1, 1, 0, 1);
  590. Memory.font.RenderBasicText(new FF8String($"camera frame: {battleCamera.cam.startingTime}/{battleCamera.cam.time}"), 20, 30 * 3, 1, 1, 0, 1);
  591. Memory.font.RenderBasicText(new FF8String($"Camera.World.Position: {Extended.RemoveBrackets(camPosition.ToString())}"), 20, 30 * 4, 1, 1, 0, 1);
  592. Memory.font.RenderBasicText(new FF8String($"Camera.World.Target: {Extended.RemoveBrackets(camTarget.ToString())}"), 20, 30 * 5, 1, 1, 0, 1);
  593. Memory.font.RenderBasicText(new FF8String($"Camera.FOV: {MathHelper.Lerp(battleCamera.cam.startingFOV, battleCamera.cam.endingFOV, battleCamera.cam.startingTime / (float)battleCamera.cam.time)}"), 20, 30 * 6, 1, 1, 0, 1);
  594. Memory.SpriteBatchEnd();
  595. }
  596. private static void CreateRotation(Tuple<Stage_GeometryInfoSupplier[], VertexPositionTexture[]> vpt)
  597. {
  598. localRotator += (short)skyRotators[Memory.encounters[Memory.battle_encounter].Scenario]/4096f * Memory.gameTime.ElapsedGameTime.Milliseconds;
  599. if (localRotator <= 0)
  600. return;
  601. for (int i = 0; i < vpt.Item2.Length; i++)
  602. vpt.Item2[i].Position = Vector3.Transform(vpt.Item2[i].Position, Matrix.CreateRotationY(MathHelper.ToRadians(localRotator)));
  603. }
  604. /// <summary>
  605. /// Converts requested Model data (Stage group geometry) into MonoGame VertexPositionTexture
  606. /// </summary>
  607. /// <param name="model"></param>
  608. /// <returns></returns>
  609. private static Tuple<Stage_GeometryInfoSupplier[], VertexPositionTexture[]> GetVertexBuffer(Model model)
  610. {
  611. List<VertexPositionTexture> vptDynamic = new List<VertexPositionTexture>();
  612. List<Stage_GeometryInfoSupplier> bs_renderer_supplier = new List<Stage_GeometryInfoSupplier>();
  613. if (model.vertices == null) return null;
  614. for (int i = 0; i < model.triangles.Length; i++)
  615. {
  616. Vertex A = model.vertices[model.triangles[i].A];
  617. Vertex B = model.vertices[model.triangles[i].B];
  618. Vertex C = model.vertices[model.triangles[i].C];
  619. vptDynamic.Add(new VertexPositionTexture(new Vector3((float)A.X / 100, (float)A.Y / 100, (float)A.Z / 100),
  620. CalculateUV(model.triangles[i].U2, model.triangles[i].V2, model.triangles[i].TexturePage, textureInterface.GetWidth)));
  621. vptDynamic.Add(new VertexPositionTexture(new Vector3((float)B.X / 100, (float)B.Y / 100, (float)B.Z / 100),
  622. CalculateUV(model.triangles[i].U3, model.triangles[i].V3, model.triangles[i].TexturePage, textureInterface.GetWidth)));
  623. vptDynamic.Add(new VertexPositionTexture(new Vector3((float)C.X / 100, (float)C.Y / 100, (float)C.Z / 100),
  624. CalculateUV(model.triangles[i].U1, model.triangles[i].V1, model.triangles[i].TexturePage, textureInterface.GetWidth)));
  625. bs_renderer_supplier.Add(new Stage_GeometryInfoSupplier()
  626. {
  627. bQuad = false,
  628. clut = model.triangles[i].clut,
  629. texPage = model.triangles[i].TexturePage
  630. });
  631. }
  632. for (int i = 0; i < model.quads.Length; i++)
  633. {
  634. //I have to re-trangulate it. Fortunately I had been working on this lately
  635. Vertex A = model.vertices[model.quads[i].A]; //1
  636. Vertex B = model.vertices[model.quads[i].B]; //2
  637. Vertex C = model.vertices[model.quads[i].C]; //4
  638. Vertex D = model.vertices[model.quads[i].D]; //3
  639. //triangluation wing-reorder
  640. //1 2 4
  641. vptDynamic.Add(new VertexPositionTexture(new Vector3((float)A.X / 100, (float)A.Y / 100, (float)A.Z / 100),
  642. CalculateUV(model.quads[i].U1, model.quads[i].V1, model.quads[i].TexturePage, textureInterface.GetWidth)));
  643. vptDynamic.Add(new VertexPositionTexture(new Vector3((float)B.X / 100, (float)B.Y / 100, (float)B.Z / 100),
  644. CalculateUV(model.quads[i].U2, model.quads[i].V2, model.quads[i].TexturePage, textureInterface.GetWidth)));
  645. vptDynamic.Add(new VertexPositionTexture(new Vector3((float)D.X / 100, (float)D.Y / 100, (float)D.Z / 100),
  646. CalculateUV(model.quads[i].U4, model.quads[i].V4, model.quads[i].TexturePage, textureInterface.GetWidth)));
  647. //1 3 4
  648. vptDynamic.Add(new VertexPositionTexture(new Vector3((float)A.X / 100, (float)A.Y / 100, (float)A.Z / 100),
  649. CalculateUV(model.quads[i].U1, model.quads[i].V1, model.quads[i].TexturePage, textureInterface.GetWidth)));
  650. vptDynamic.Add(new VertexPositionTexture(new Vector3((float)C.X / 100, (float)C.Y / 100, (float)C.Z / 100),
  651. CalculateUV(model.quads[i].U3, model.quads[i].V3, model.quads[i].TexturePage, textureInterface.GetWidth)));
  652. vptDynamic.Add(new VertexPositionTexture(new Vector3((float)D.X / 100, (float)D.Y / 100, (float)D.Z / 100),
  653. CalculateUV(model.quads[i].U4, model.quads[i].V4, model.quads[i].TexturePage, textureInterface.GetWidth)));
  654. bs_renderer_supplier.Add(new Stage_GeometryInfoSupplier()
  655. {
  656. bQuad = true,
  657. clut = model.quads[i].clut,
  658. texPage = model.quads[i].TexturePage
  659. });
  660. }
  661. return new Tuple<Stage_GeometryInfoSupplier[], VertexPositionTexture[]>
  662. (bs_renderer_supplier.ToArray(), vptDynamic.ToArray());
  663. }
  664. private static Vector2 CalculateUV(byte U, byte V, byte texPage, int texWidth)
  665. {
  666. //old code from my wiki page
  667. //Float U = (float)U_Byte / (float)(TIM_Texture_Width * 2) + ((float)Texture_Page / (TIM_Texture_Width * 2));
  668. float fU = (float)U / texWidth + (((float)texPage * 128) / texWidth);
  669. float fV = V / 256.0f;
  670. return new Vector2(fU, fV);
  671. }
  672. private static void InitBattle()
  673. {
  674. //MakiExtended.Debugger_Spawn();
  675. //MakiExtended.Debugger_Feed(typeof(Module_battle_debug), System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
  676. Input.OverrideLockMouse=true;
  677. Input.CurrentMode = Input.MouseLockMode.Center;
  678. Init_debugger_battle.Encounter enc = Memory.encounters[Memory.battle_encounter];
  679. int stage = enc.Scenario;
  680. battlename = $"a0stg{stage.ToString("000")}.x";
  681. Console.WriteLine($"BS_DEBUG: Loading stage {battlename}");
  682. Console.WriteLine($"BS_DEBUG/ENC: Encounter: {Memory.battle_encounter}\t cEnemies: {enc.EnabledEnemy}\t Enemies: {string.Join(",", enc.BEnemies.Where(x => x != 0x00).Select(x => $"{x}").ToArray())}");
  683. //init renderer
  684. effect = new BasicEffect(Memory.graphics.GraphicsDevice);
  685. camTarget = new Vector3(41.91198f, 33.59995f, 6.372305f);
  686. camPosition = new Vector3(40.49409f, 39.70397f, -43.321299f);
  687. projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
  688. MathHelper.ToRadians(45f),
  689. Memory.graphics.GraphicsDevice.DisplayMode.AspectRatio,
  690. 1f, 1000f);
  691. viewMatrix = Matrix.CreateLookAt(camPosition, camTarget,
  692. new Vector3(0f, 1f, 0f));// Y up
  693. worldMatrix = Matrix.CreateWorld(camTarget, Vector3.
  694. Forward, Vector3.Up);
  695. battleModule++;
  696. RasterizerState rasterizerState = new RasterizerState
  697. {
  698. CullMode = CullMode.None
  699. };
  700. ate = new AlphaTestEffect(Memory.graphics.GraphicsDevice)
  701. {
  702. Projection = projectionMatrix,
  703. View = viewMatrix,
  704. World = worldMatrix
  705. };
  706. return;
  707. }
  708. #region fileParsing
  709. private static void ReadData()
  710. {
  711. ArchiveWorker aw = new ArchiveWorker(Memory.Archives.A_BATTLE);
  712. string[] test = aw.GetListOfFiles();
  713. battlename = test.First(x => x.ToLower().Contains(battlename));
  714. stageBuffer = ArchiveWorker.GetBinaryFile(Memory.Archives.A_BATTLE, battlename);
  715. ms = new MemoryStream(stageBuffer);
  716. br = new BinaryReader(ms);
  717. bs_cameraPointer = GetCameraPointer();
  718. ms.Seek(bs_cameraPointer, 0);
  719. ReadCamera();
  720. uint sectionCounter = br.ReadUInt32();
  721. if (sectionCounter != 6)
  722. {
  723. Console.WriteLine($"BS_PARSER_PRE_OBJECTSECTION: Main geometry section has no 6 pointers at: {ms.Position}");
  724. battleModule++;
  725. return;
  726. }
  727. MainGeometrySection MainSection = ReadObjectGroupPointers();
  728. ObjectsGroup[] objectsGroups = new ObjectsGroup[4]
  729. {
  730. ReadObjectsGroup(MainSection.Group1Pointer),
  731. ReadObjectsGroup(MainSection.Group2Pointer),
  732. ReadObjectsGroup(MainSection.Group3Pointer),
  733. ReadObjectsGroup(MainSection.Group4Pointer)
  734. };
  735. modelGroups = new ModelGroup[4]
  736. {
  737. ReadModelGroup(objectsGroups[0].objectListPointer),
  738. ReadModelGroup(objectsGroups[1].objectListPointer),
  739. ReadModelGroup(objectsGroups[2].objectListPointer),
  740. ReadModelGroup(objectsGroups[3].objectListPointer)
  741. };
  742. ReadTexture(MainSection.TexturePointer);
  743. br.Close();
  744. ms.Close();
  745. ms.Dispose();
  746. ReadCharacters();
  747. ReadMonster();
  748. battleModule++;
  749. }
  750. public static int DEBUG = 0;
  751. private static float frameperFPS = 0.0f;
  752. private static void ReadCharacters()
  753. {
  754. CharacterInstances = new List<CharacterInstanceInformation>
  755. {
  756. new CharacterInstanceInformation()
  757. {
  758. Data = ReadCharacterData(0,0,0),
  759. animationSystem = new AnimationSystem(){ AnimationQueue = new List<int>()},
  760. characterId = 0,
  761. },
  762. new CharacterInstanceInformation()
  763. {
  764. Data = ReadCharacterData(1,3,8),
  765. animationSystem = new AnimationSystem(){ AnimationQueue = new List<int>()},
  766. characterId = 1
  767. },
  768. new CharacterInstanceInformation()
  769. {
  770. Data = ReadCharacterData(2,6,13),
  771. animationSystem = new AnimationSystem(){ AnimationQueue = new List<int>()},
  772. characterId = 2
  773. }
  774. };
  775. }
  776. private static CharacterData ReadCharacterData(int characterId, int alternativeCostumeId, int weaponId)
  777. {
  778. var character = new Debug_battleDat(characterId, Debug_battleDat.EntityType.Character, alternativeCostumeId);
  779. Debug_battleDat weapon;
  780. if (characterId == 1 || characterId == 9)
  781. weapon = new Debug_battleDat(characterId, Debug_battleDat.EntityType.Weapon, weaponId, character);
  782. #pragma warning disable IDE0045 // Convert to conditional expression
  783. else if (weaponId != -1) weapon = new Debug_battleDat(characterId, Debug_battleDat.EntityType.Weapon, weaponId);
  784. #pragma warning restore IDE0045 // Convert to conditional expression
  785. else weapon = null;
  786. return new CharacterData()
  787. {
  788. character = character,
  789. weapon = weapon
  790. };
  791. }
  792. /// <summary>
  793. /// This method is responsible to read/parse the enemy data. It holds the result in monstersData[]
  794. /// This method was designed to read only one instance of enemy. A list called EnemyInstance holds data information for each enemy
  795. /// </summary>
  796. private static void ReadMonster()
  797. {
  798. //for(int i = 0; i<199; i++)
  799. //{
  800. // var dcd = new Debug_battleDat(i, Debug_battleDat.EntityType.Monster);
  801. // var ecd = dcd.skeleton.GetScale.Y;
  802. // Console.WriteLine($"{i}/{ecd}");
  803. //}
  804. Init_debugger_battle.Encounter enc = Memory.encounters[Memory.battle_encounter];
  805. if (enc.EnabledEnemy == 0)
  806. {
  807. monstersData = new Debug_battleDat[0];
  808. return;
  809. }
  810. var DistinctMonsterPointers = enc.BEnemies.GroupBy(x => x).ToArray();
  811. monstersData = new Debug_battleDat[DistinctMonsterPointers.Count()];
  812. for (int n = 0; n < monstersData.Length; n++)
  813. monstersData[n] = new Debug_battleDat(DistinctMonsterPointers[n].Key, Debug_battleDat.EntityType.Monster);
  814. if (monstersData == null)
  815. monstersData = new Debug_battleDat[0];
  816. EnemyInstances = new List<EnemyInstanceInformation>();
  817. for(int i = 0; i<8; i++)
  818. if (Extended.GetBit(enc.EnabledEnemy, 7-i))
  819. EnemyInstances.Add(new EnemyInstanceInformation() { Data = monstersData.Where(x => x.GetId == enc.BEnemies[i] ).First(),
  820. bIsHidden =Extended.GetBit(enc.HiddenEnemies, 7-i),
  821. bIsActive = true,
  822. index = (byte)(7-i),
  823. bIsUntargetable = Extended.GetBit(enc.UntargetableEnemy, 7-i),
  824. animationSystem = new AnimationSystem() { AnimationQueue= new List<int>()}}
  825. );
  826. }
  827. /// <summary>
  828. /// Method designed for Stage texture loading.
  829. /// </summary>
  830. /// <param name="texturePointer">Absolute pointer to TIM texture header in stageBuffer</param>
  831. private static void ReadTexture(uint texturePointer)
  832. {
  833. textureInterface = new TIM2(stageBuffer, texturePointer);
  834. textures = new Texture2D[textureInterface.GetClutCount];
  835. for (ushort i = 0; i < textureInterface.GetClutCount; i++)
  836. {
  837. byte[] b = textureInterface.CreateImageBuffer(textureInterface.GetClutColors(i));
  838. Texture2D tex = new Texture2D(Memory.spriteBatch.GraphicsDevice,
  839. textureInterface.GetWidth, textureInterface.GetHeight, false, SurfaceFormat.Color);
  840. tex.SetData(b);
  841. textures[i] = tex;
  842. }
  843. }
  844. /// <summary>
  845. /// Reads Stage model groups pointers and reads/parses them individually.
  846. /// Group0 is stage ground. It's always enabled except special sequences like GFs
  847. /// Group1 is main geometry. It's prior to Time Compression deformation
  848. /// Group2 is main/additional geometry. It's prior to Time Compression deformation
  849. /// Group3 is Sky. It's NON-prior to Time Compression, but may be modified by SkyRotators and/or TimeCompression last Stage skyRotation multiplier
  850. /// </summary>
  851. /// <param name="pointer"></param>
  852. /// <returns></returns>
  853. private static ModelGroup ReadModelGroup(uint pointer)
  854. {
  855. ms.Seek(pointer, SeekOrigin.Begin);
  856. uint modelsCount = br.ReadUInt32();
  857. Model[] models = new Model[modelsCount];
  858. uint[] modelPointers = new uint[modelsCount];
  859. for (int i = 0; i < modelsCount; i++)
  860. modelPointers[i] = pointer + br.ReadUInt32();
  861. for (int i = 0; i < modelsCount; i++)
  862. models[i] = ReadModel(modelPointers[i]);
  863. return new ModelGroup() { models = models };
  864. }
  865. /// <summary>
  866. /// This is the main class that reads given Stage geometry group. It stores the data into Model structure
  867. /// </summary>
  868. /// <param name="pointer">absolute pointer in buffer for given Stage geometry group</param>
  869. /// <returns></returns>
  870. private static Model ReadModel(uint pointer)
  871. {
  872. bool bSpecial = false;
  873. ms.Seek(pointer, System.IO.SeekOrigin.Begin);
  874. uint header = Extended.UintLittleEndian(br.ReadUInt32());
  875. if (header != 0x01000100) //those may be some switches, but I don't know what they mean
  876. {
  877. Console.WriteLine("WARNING- THIS STAGE IS DIFFERENT! It has weird object section. INTERESTING, TO REVERSE!");
  878. bSpecial = true;
  879. }
  880. ushort verticesCount = br.ReadUInt16();
  881. Vertex[] vertices = new Vertex[verticesCount];
  882. for (int i = 0; i < verticesCount; i++)
  883. vertices[i] = ReadVertex();
  884. if (bSpecial && Memory.encounters[Memory.battle_encounter].Scenario == 20)
  885. return new Model();
  886. ms.Seek((ms.Position % 4) + 4, SeekOrigin.Current);
  887. ushort trianglesCount = br.ReadUInt16();
  888. ushort quadsCount = br.ReadUInt16();
  889. ms.Seek(4, SeekOrigin.Current);
  890. Triangle[] triangles = new Triangle[trianglesCount];
  891. Quad[] quads = new Quad[quadsCount];
  892. if (trianglesCount > 0)
  893. for (int i = 0; i < trianglesCount; i++)
  894. triangles[i] = ReadTriangle();
  895. if (quadsCount > 0)
  896. for (int i = 0; i < quadsCount; i++)
  897. quads[i] = ReadQuad();
  898. return new Model()
  899. {
  900. vertices = vertices,
  901. triangles = triangles,
  902. quads = quads
  903. };
  904. }
  905. private static Triangle ReadTriangle()
  906. =>
  907. new Triangle()
  908. {
  909. A = br.ReadUInt16(),
  910. B = br.ReadUInt16(),
  911. C = br.ReadUInt16(),
  912. U1 = br.ReadByte(),
  913. V1 = br.ReadByte(),
  914. U2 = br.ReadByte(),
  915. V2 = br.ReadByte(),
  916. clut = GetClutId(br.ReadUInt16()),
  917. U3 = br.ReadByte(),
  918. V3 = br.ReadByte(),
  919. TexturePage = GetTexturePage(br.ReadByte()),
  920. bHide = br.ReadByte(),
  921. Red = br.ReadByte(),
  922. Green = br.ReadByte(),
  923. Blue = br.ReadByte(),
  924. GPU = br.ReadByte(),
  925. };
  926. private static Quad ReadQuad()
  927. => new Quad()
  928. {
  929. A = br.ReadUInt16(),
  930. B = br.ReadUInt16(),
  931. C = br.ReadUInt16(),
  932. D = br.ReadUInt16(),
  933. U1 = br.ReadByte(),
  934. V1 = br.ReadByte(),
  935. clut = GetClutId(br.ReadUInt16()),
  936. U2 = br.ReadByte(),
  937. V2 = br.ReadByte(),
  938. TexturePage = GetTexturePage(br.ReadByte()),
  939. bHide = br.ReadByte(),
  940. U3 = br.ReadByte(),
  941. V3 = br.ReadByte(),
  942. U4 = br.ReadByte(),
  943. V4 = br.ReadByte(),
  944. Red = br.ReadByte(),
  945. Green = br.ReadByte(),
  946. Blue = br.ReadByte(),
  947. GPU = br.ReadByte()
  948. };
  949. private static Vertex ReadVertex()
  950. => new Vertex()
  951. {
  952. X = br.ReadInt16(),
  953. Y = br.ReadInt16(),
  954. Z = br.ReadInt16(),
  955. };
  956. private static ObjectsGroup ReadObjectsGroup(uint pointer)
  957. {
  958. ms.Seek(pointer, System.IO.SeekOrigin.Begin);
  959. return new ObjectsGroup()
  960. {
  961. numberOfSections = br.ReadUInt32(),
  962. settings1Pointer = pointer + br.ReadUInt32(),
  963. objectListPointer = pointer + br.ReadUInt32(),
  964. settings2Pointer = pointer + br.ReadUInt32(),
  965. relativeEOF = pointer + br.ReadUInt32(),
  966. };
  967. }
  968. private static MainGeometrySection ReadObjectGroupPointers()
  969. {
  970. int basePointer = (int)ms.Position - 4;
  971. uint objectGroup_1 = (uint)basePointer + br.ReadUInt32();
  972. uint objectGroup_2 = (uint)basePointer + br.ReadUInt32();
  973. uint objectGroup_3 = (uint)basePointer + br.ReadUInt32();
  974. uint objectGroup_4 = (uint)basePointer + br.ReadUInt32();
  975. uint TextureUnused = (uint)basePointer + br.ReadUInt32();
  976. uint Texture = (uint)basePointer + br.ReadUInt32();
  977. uint EOF = (uint)basePointer + br.ReadUInt32();
  978. if (EOF != ms.Length)
  979. throw new Exception("BS_PARSER_ERROR_LENGTH: Geometry EOF pointer is other than buffered filesize");
  980. return new MainGeometrySection()
  981. {
  982. Group1Pointer = objectGroup_1,
  983. Group2Pointer = objectGroup_2,
  984. Group3Pointer = objectGroup_3,
  985. Group4Pointer = objectGroup_4,
  986. TextureUNUSEDPointer = TextureUnused,
  987. TexturePointer = Texture,
  988. EOF = EOF
  989. }; //EOF = EOF; beauty of language
  990. }
  991. /// <summary>
  992. /// Gets vanilla engine camera pointers. A team that rewrote the game into PC just left PlayStation MIPS data inside files
  993. /// and therefore their code is to skip given hardcoded data which in fact are PS compiled instructions
  994. /// This data is naturally read by PlayStation in original console release.
  995. /// </summary>
  996. /// <returns>Camera pointer (data after PlayStation MIPS)</returns>
  997. private static uint GetCameraPointer()
  998. {
  999. int[] _x5D4 = {4,5,9,12,13,14,15,21,22,23,24,26,
  1000. 29,32,33,34,35,36,39,40,50,53,55,61,62,63,64,65,66,67,68,69,70,
  1001. 71,72,73,75,78,82,83,85,86,87,88,89,90,91,94,96,97,98,99,100,105,
  1002. 106,121,122,123,124,125,126,127,135,138,141,144,145,148,149,150,
  1003. 151,158,160};
  1004. int[] _x5D8 = {
  1005. 0,1,2,3,6,7,10,11,17,18,25,27,28,38,41,42,43,47,49,57,58,59,60,74,
  1006. 76,77,80,81,84,93,95,101,102,103,104,109,110,111,112,113,114,115,116,
  1007. 117,118,119,120,128,129,130,131,132,133,134,139,140,143,146,152,153,154,
  1008. 155,156,159,161,162};
  1009. int _5d4 = _x5D4.Count(x => x == Memory.encounters[Memory.battle_encounter].Scenario);
  1010. int _5d8 = _x5D8.Count(x => x == Memory.encounters[Memory.battle_encounter].Scenario);
  1011. if (_5d4 > 0) return 0x5D4;
  1012. if (_5d8 > 0) return 0x5D8;
  1013. switch (Memory.encounters[Memory.battle_encounter].Scenario)
  1014. {
  1015. case 8:
  1016. case 48:
  1017. case 79:
  1018. return 0x618;
  1019. case 16:
  1020. return 0x628;
  1021. case 19:
  1022. return 0x644;
  1023. case 20:
  1024. return 0x61c;
  1025. case 30:
  1026. case 31:
  1027. return 0x934;
  1028. case 37:
  1029. return 0xcc0;
  1030. case 44:
  1031. case 45:
  1032. case 46:
  1033. return 0x9A4;
  1034. case 51:
  1035. case 52:
  1036. case 107:
  1037. case 108:
  1038. return 0x600;
  1039. case 54:
  1040. case 56:
  1041. return 0x620;
  1042. case 92:
  1043. return 0x83c;
  1044. case 136:
  1045. return 0x5fc;
  1046. case 137:
  1047. return 0xFDC;
  1048. case 142:
  1049. return 0x183C;
  1050. case 147:
  1051. return 0x10f0;
  1052. case 157:
  1053. return 0x638;
  1054. }
  1055. throw new Exception("0xFFF, unknown pointer!");
  1056. }
  1057. [StructLayout(LayoutKind.Sequential, Pack =1, Size =1092)]
  1058. public struct CameraStruct
  1059. {
  1060. public byte unkbyte000; //000
  1061. public byte keyframeCount;
  1062. public ushort control_word;
  1063. public ushort startingFOV; //usually ~280
  1064. public ushort endingFOV; //006
  1065. public ushort startingCameraRoll; //usually 0 unless you're aiming for some wicked animation
  1066. public ushort endingCameraRoll; //
  1067. public ushort startingTime; //usually 0, that's pretty logical
  1068. /// <summary>
  1069. /// Time is calculated from number of frames. You basically set starting position World+lookat and ending position, then mark number of frames to interpolate between them. Every frame is one drawcall and it costs 16.
  1070. /// </summary>
  1071. public ushort time; //starting time needs to be equal or higher for next animation frame to be read; If next frame==0xFFFF then it's all done
  1072. [MarshalAs(UnmanagedType.ByValArray, SizeConst =20)]
  1073. public byte[] unk; //010
  1074. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  1075. public ushort[] unkword024; //024 - start frames for each key frame?
  1076. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  1077. public short[] Camera_World_Z_s16; //064
  1078. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  1079. public short[] Camera_World_X_s16; //0A4
  1080. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  1081. public short[] Camera_World_Y_s16; //0E4
  1082. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  1083. public byte[] unkbyte124; //124
  1084. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  1085. public short[] Camera_Lookat_Z_s16; //144
  1086. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  1087. public short[] Camera_Lookat_X_s16; //184
  1088. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  1089. public short[] Camera_Lookat_Y_s16; //1C4
  1090. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
  1091. public byte[] unkbyte204; //204
  1092. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
  1093. public byte[] unkbyte224; //224
  1094. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
  1095. public byte[] unkbyte2A4; //2A4
  1096. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
  1097. public byte[] unkbyte324; //324
  1098. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
  1099. public byte[] unkbyte3A4; //3A4
  1100. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
  1101. public byte[] unkbyte424; //424
  1102. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
  1103. public byte[] unkbyte4A4; //4A4
  1104. };
  1105. /// <summary>
  1106. /// Main battle camera struct. It holds data for camera settings, camera collections and main CameraStruct used as a final result of camera parsing
  1107. /// </summary>
  1108. private struct BattleCamera
  1109. {
  1110. public BattleCameraSettings battleCameraSettings;
  1111. public BattleCameraCollection battleCameraCollection;
  1112. public CameraStruct cam;
  1113. }
  1114. private static BattleCamera battleCamera;
  1115. /// <summary>
  1116. /// Battle camera settings are about 32 bytes of unknown flags and variables used in whole stage including geometry
  1117. /// </summary>
  1118. private struct BattleCameraSettings
  1119. {
  1120. public byte[] unk;
  1121. }
  1122. /// <summary>
  1123. /// Main struct for collection of camera animations. Every BattleCameraSet hold 8 animations no matter what
  1124. /// </summary>
  1125. private struct BattleCameraCollection
  1126. {
  1127. public uint cAnimCollectionCount;
  1128. public uint pCameraEOF;
  1129. public BattleCameraSet[] battleCameraSet;
  1130. }
  1131. /// <summary>
  1132. /// Struct for battle camera animation set. Animation set always contain 8 animations.
  1133. /// This struct does not contain a data for pre-readed information. Therefore you have to call ReadAnimation(index)
  1134. /// to actually read the animation to BattleCamera.cam(CameraStruct). That is because there are extreme amount
  1135. /// of cases where the camera is changing and reading again and again not including the battle stage.
  1136. /// Also reading all camera animations is waste of time and resources
  1137. /// </summary>
  1138. private struct BattleCameraSet
  1139. {
  1140. public uint[] animPointers;
  1141. public uint globalSetPointer;
  1142. }
  1143. /// <summary>
  1144. /// Parses camera data into BattleCamera struct. Main purpouse of this function is to actually read all the offsets and pointers to human readable form of struct.
  1145. /// This function later calls ReadAnimation(n) where n is animation Id (i.e. 9 is camCollection=1 and cameraAnim=0)
  1146. /// </summary>
  1147. private static void ReadCamera()
  1148. {
  1149. uint cCameraHeaderSector = br.ReadUInt16();
  1150. uint pCameraSetting = br.ReadUInt16();
  1151. uint pCameraAnimationCollection = br.ReadUInt16();
  1152. uint sCameraDataSize = br.ReadUInt16();
  1153. //Camera settings parsing?
  1154. BattleCameraSettings bcs = new BattleCameraSettings() { unk = br.ReadBytes(24) };
  1155. //end of camera settings parsing
  1156. ms.Seek(bs_cameraPointer, 0);
  1157. ms.Seek(pCameraAnimationCollection, SeekOrigin.Current);
  1158. BattleCameraCollection bcc = new BattleCameraCollection { cAnimCollectionCount = br.ReadUInt16() };
  1159. BattleCameraSet[] bcset = new BattleCameraSet[bcc.cAnimCollectionCount];
  1160. bcc.battleCameraSet = bcset;
  1161. for (int i = 0; i < bcc.cAnimCollectionCount; i++)
  1162. bcset[i] = new BattleCameraSet() { globalSetPointer = (uint)(ms.Position + br.ReadUInt16() - i * 2 - 2) };
  1163. bcc.pCameraEOF = br.ReadUInt16();
  1164. for (int i = 0; i < bcc.cAnimCollectionCount; i++)
  1165. {
  1166. ms.Seek(bcc.battleCameraSet[i].globalSetPointer, 0);
  1167. bcc.battleCameraSet[i].animPointers = new uint[8];
  1168. for (int n = 0; n < bcc.battleCameraSet[i].animPointers.Length; n++)
  1169. bcc.battleCameraSet[i].animPointers[n] = (uint)(ms.Position + br.ReadUInt16() * 2 - n * 2);
  1170. }
  1171. CameraStruct cam = Extended.ByteArrayToStructure<CameraStruct>(new byte[Marshal.SizeOf(typeof(CameraStruct))]); //what about this kind of trick to initialize struct with a lot amount of fixed sizes in arrays?
  1172. battleCamera = new BattleCamera() { battleCameraCollection = bcc, battleCameraSettings = bcs, cam = cam };
  1173. ReadAnimation(GetRandomCameraN(Memory.encounters[Memory.battle_encounter]));
  1174. ms.Seek(bs_cameraPointer + sCameraDataSize, 0); //step out
  1175. }
  1176. /// <summary>
  1177. /// Gets random camera from available from encounter- primary or secondary
  1178. /// </summary>
  1179. /// <param name="encounter">instance of current encounter</param>
  1180. /// <returns>Either primary or alternative camera from encounter</returns>
  1181. private static int GetRandomCameraN(Init_debugger_battle.Encounter encounter)
  1182. {
  1183. int camToss = Memory.random.Next(0, 3) < 2 ? 0 : 1; //primary camera has 2/3 chance of beign selected
  1184. switch(camToss)
  1185. {
  1186. case 0:
  1187. return encounter.PrimaryCamera;
  1188. case 1:
  1189. return encounter.AlternativeCamera;
  1190. default:
  1191. goto case 0;
  1192. }
  1193. }
  1194. /// <summary>
  1195. /// Returns tuple containing camera animation set pointer and camera animation in that set
  1196. /// </summary>
  1197. /// <param name="animId">6bit variable containing camera pointer</param>
  1198. /// <returns>Tuple with CameraSetPointer, CameraSetPointer[CameraAnimationPointer]</returns>
  1199. private static Tuple<int, int> GetCameraCollectionPointers(int animId)
  1200. {
  1201. var enc = Memory.encounters[Memory.battle_encounter];
  1202. int pSet = enc.ResolveCameraSet((byte)animId);
  1203. int pAnim = enc.ResolveCameraAnimation((byte)animId);
  1204. return new Tuple<int, int>(pSet, pAnim);
  1205. }
  1206. /// <summary>
  1207. /// Method that provides reading of real animation data based on 6bit camera pointer. In future do overload on this function
  1208. /// to support GF and magic reading
  1209. /// </summary>
  1210. /// <param name="animId"></param>
  1211. private static uint ReadAnimation(int animId)
  1212. {
  1213. short local2C;
  1214. byte keyframecount =0;
  1215. ushort totalframecount = 0;
  1216. short local1C;
  1217. short local18;
  1218. short local14;
  1219. short local10;
  1220. var tpGetter = GetCameraCollectionPointers(animId);
  1221. uint cameraAnimationGlobalPointer = battleCamera.battleCameraCollection.battleCameraSet[tpGetter.Item1].animPointers[tpGetter.Item2];
  1222. ms.Seek(cameraAnimationGlobalPointer, SeekOrigin.Begin);
  1223. battleCamera.cam.control_word = br.ReadUInt16();
  1224. if (battleCamera.cam.control_word == 0xFFFF)
  1225. return 0; //return NULL
  1226. var current_position = br.ReadUInt16(); //getter for *current_position
  1227. ms.Seek(-2, SeekOrigin.Current); //roll back one WORD because no increment
  1228. switch((battleCamera.cam.control_word >> 6) & 3)
  1229. {
  1230. case 1:
  1231. battleCamera.cam.startingFOV = 0x200;
  1232. battleCamera.cam.endingFOV = 0x200;
  1233. break;
  1234. case 2:
  1235. battleCamera.cam.startingFOV = current_position;
  1236. battleCamera.cam.endingFOV = current_position;
  1237. br.ReadUInt16(); //current_position++
  1238. break;
  1239. case 3:
  1240. battleCamera.cam.startingFOV = current_position;
  1241. current_position = br.ReadUInt16();
  1242. battleCamera.cam.endingFOV = current_position;
  1243. ms.Seek(2, SeekOrigin.Current); //skipping WORD, because we already rolled back one WORD above this switch
  1244. break;
  1245. }
  1246. switch ((battleCamera.cam.control_word >> 8) & 3)
  1247. {
  1248. case 0: //TODO!!
  1249. battleCamera.cam.startingCameraRoll = 00000000; //TODO, what's ff8vars.unkword1D977A2?
  1250. battleCamera.cam.endingCameraRoll = 00000000; //same as above; cam->unkword00A = ff8vars.unkword1D977A2;
  1251. break;
  1252. case 1:
  1253. battleCamera.cam.startingCameraRoll = 0;
  1254. battleCamera.cam.endingCameraRoll = 0;
  1255. break;
  1256. case 2:
  1257. current_position = br.ReadUInt16(); //* + current_position++;
  1258. battleCamera.cam.startingCameraRoll = current_position;
  1259. battleCamera.cam.endingCameraRoll = current_position;
  1260. break;
  1261. case 3:
  1262. current_position = br.ReadUInt16(); //* + current_position++;
  1263. battleCamera.cam.startingCameraRoll = current_position;
  1264. current_position = br.ReadUInt16(); //* + current_position++;
  1265. battleCamera.cam.endingCameraRoll = current_position;
  1266. break;
  1267. }
  1268. switch (battleCamera.cam.control_word & 1)
  1269. {
  1270. case 0:
  1271. if(current_position >= 0)
  1272. {
  1273. while(true) //I'm setting this to true and breaking in code as this works on peeking on next variable via pointer and that's not possible here without unsafe block
  1274. {
  1275. battleCamera.cam.unkword024[keyframecount] = totalframecount;
  1276. current_position = br.ReadUInt16();
  1277. if ((short)current_position < 0) //reverse of *current_position >= 0, also cast to signed is important here
  1278. break;
  1279. totalframecount += (ushort)(current_position * 16); //here is increment of short*, but I already did that above
  1280. battleCamera.cam.unkbyte124[keyframecount] = (byte)(current_position = br.ReadUInt16()); //cam->unkbyte124[keyframecount] = *current_position++; - looks like we are wasting one byte due to integer sizes
  1281. battleCamera.cam.Camera_World_Z_s16[keyframecount] = (short)(current_position = br.ReadUInt16());
  1282. battleCamera.cam.Camera_World_X_s16[keyframecount] = (short)(current_position = br.ReadUInt16());
  1283. battleCamera.cam.Camera_World_Y_s16[keyframecount] = (short)(current_position = br.ReadUInt16());
  1284. battleCamera.cam.unkbyte204[keyframecount] = (byte)(current_position = br.ReadUInt16()); //m->unkbyte204[keyframecount] = *current_position++;
  1285. battleCamera.cam.Camera_Lookat_Z_s16[keyframecount] = (short)(current_position = br.ReadUInt16());
  1286. battleCamera.cam.Camera_Lookat_X_s16[keyframecount] = (short)(current_position = br.ReadUInt16());
  1287. battleCamera.cam.Camera_Lookat_Y_s16[keyframecount] = (short)(current_position = br.ReadUInt16());
  1288. keyframecount++;
  1289. }
  1290. if(keyframecount>2)
  1291. {
  1292. //ff8funcs.Sub50D010(cam->unkword024, cam->unkword064, cam->unkword0A4, cam->unkword0E4, keyframecount, cam->unkbyte224, cam->unkbyte2A4, cam->unkbyte324);
  1293. //ff8funcs.Sub50D010(cam->unkword024, cam->unkword144, cam->unkword184, cam->unkword1C4, keyframecount, cam->unkbyte3A4, cam->unkbyte424, cam->unkbyte4A4);
  1294. }
  1295. }
  1296. break;
  1297. case 1:
  1298. {
  1299. if(current_position >= 0)
  1300. {
  1301. local14 = (short)(ms.Position + 5*2); //current_position + 5; but current_position is WORD, so multiply by two
  1302. local10 = (short)(ms.Position + 6*2);
  1303. local2C = (short)(ms.Position + 7*2);
  1304. local18 = (short)(ms.Position + 1*2);
  1305. local1C = (short)(ms.Position + 2*2);
  1306. while(true)
  1307. {
  1308. battleCamera.cam.unkword024[keyframecount] = totalframecount;
  1309. current_position = br.ReadUInt16();
  1310. if ((short)current_position < 0) //reverse of *current_position >= 0, also cast to signed is important here
  1311. break;
  1312. totalframecount += (ushort)(current_position * 16);
  1313. //ff8funcs.Sub503AE0(++local18, ++local1C, ++ebx, *(BYTE*)current_position, &cam->unkword064[keyframecount], &cam->unkword0A4[keyframecount], &cam->unkword0E4[keyframecount]);
  1314. //ff8funcs.Sub503AE0(++local14, ++local10, ++local2C, *(BYTE*)(current_position + 4), &cam->unkword144[keyframecount], &cam->unkword184[keyframecount], &cam->unkword1C4[keyframecount]);
  1315. battleCamera.cam.unkbyte204[keyframecount] = 0xFB;
  1316. battleCamera.cam.unkbyte124[keyframecount] = 0xFB;
  1317. local1C += 8;
  1318. local18 += 8;
  1319. current_position += 8;
  1320. local2C += 8;
  1321. //ebx += 8;
  1322. local10 += 8;
  1323. local14 += 8;
  1324. keyframecount++;
  1325. }
  1326. }
  1327. break;
  1328. }
  1329. }
  1330. if((battleCamera.cam.control_word & 0x3E) == 0x1E)
  1331. {
  1332. //ff8funcs.Sub503300();
  1333. }
  1334. battleCamera.cam.keyframeCount = keyframecount;
  1335. battleCamera.cam.time = totalframecount;
  1336. battleCamera.cam.startingTime = 0;
  1337. return (uint)(ms.Position+2);
  1338. }
  1339. #endregion
  1340. }
  1341. }