/lib/core/tiles.simba

http://github.com/Drags111/Reflection_Dev · Unknown · 622 lines · 481 code · 141 blank · 0 comment · 0 complexity · 468d429787a9957bc464d23b8515eda5 MD5 · raw file

  1. (*
  2. Tiles
  3. =====
  4. This file relates to Map and Screen locations and converting them to Tiles. The
  5. methods and formulas here relate to hooks into the Runescape Client's rendering
  6. system, and therefore a brief description about how those work will help a lot.
  7. The Runescape world is laid out on a large grid. A coordinate on this grid is
  8. called a Tile. The origin (0,0) is somewhere in the South Western corner of the
  9. world, and the coordinates increase in the North Easternly direction.
  10. A loading area is a smaller grid 104x104 tiles in size whose bounds can be
  11. variable. The origin of the loading area is stored in the client as the global
  12. tile position (BaseX, BaseY), therefore your local Tile position is your global
  13. Tile position minux the origin of the loading area.
  14. A tile is rendered as 512x512 pixels. Most positions in the renderer data are
  15. measured in pixels. This means the loading area is 13312x13312 pixels in size.
  16. to convert a local Tile into a pixel measurement, simply multiply the local Tile
  17. coordinates by 512.
  18. Each corner of a tile has a height stored in a 2D array in the current Plane
  19. object. To calculate the average height of a tile, simply average the height of
  20. its corners.
  21. The client provides a rotation matrix, offset, and scaling values to transform
  22. a "world" pixel coordinate into a "screen" coordinate. The formula for doing
  23. this is found in the TileToMSEx function. Since one often requires sub tile
  24. accuracy, offset values in the range of [0,1] are provided. (0.5,0.5) would be
  25. the center, and (0,0) would be the south-west corner of the tile.
  26. The minimap is simply a perfectly verticle view of the ground as if it were
  27. perfectly flat. Tiles here have a size of 4x4 pixels, and the map is rotated
  28. around your current position by an angle stored in MapAngle. The angle is in
  29. the range [0,16384], with 0 being North and increasing counter-clockwise. The
  30. math for converting a Tile into a "minimap" coordinate is provided in TileToMM.
  31. *)
  32. function R_GetPlaneIndex : Integer;
  33. begin
  34. Result := SmartGetFieldInt(0, hook_static_LoadedPlane);
  35. end;
  36. (*
  37. R_UpdateRenderInfo
  38. ~~~~~~~~~~~~~~~~~~
  39. .. code-block:: pascal
  40. procedure R_UpdateRenderInfo(var Render : TRender; var RenderData : TRenderData);
  41. Fills a pair of TRender and TRenderData structures with data.
  42. .. note::
  43. by Benland100
  44. *)
  45. procedure R_UpdateRenderInfo(var Render : TRender; var RenderData : TRenderData);
  46. var
  47. tk, vp, t: Integer;
  48. begin
  49. MarkTime(t);
  50. while ((RenderData.zX <= 0) and (RenderData.zY <= 0) and (TimeFromMark(t) < 10000)) do
  51. begin
  52. tk := SmartGetFieldObject(0, hook_static_Toolkit);
  53. vp := SmartGetFieldObject(tk, hook_sdtoolkit_Viewport);
  54. with RenderData do
  55. begin
  56. xOff := SmartGetFieldFloat(vp,hook_sdviewport_xOff);
  57. xX := SmartGetFieldFloat(vp,hook_sdviewport_xX);
  58. xY := SmartGetFieldFloat(vp,hook_sdviewport_xY);
  59. xZ := SmartGetFieldFloat(vp,hook_sdviewport_xZ);
  60. yOff := SmartGetFieldFloat(vp,hook_sdviewport_yOff);
  61. yX := SmartGetFieldFloat(vp,hook_sdviewport_yX);
  62. yY := SmartGetFieldFloat(vp,hook_sdviewport_yY);
  63. yZ := SmartGetFieldFloat(vp,hook_sdviewport_yZ);
  64. zOff := SmartGetFieldFloat(vp,hook_sdviewport_zoff);
  65. zX := SmartGetFieldFloat(vp,hook_sdviewport_zX);
  66. zY := SmartGetFieldFloat(vp,hook_sdviewport_zY);
  67. zZ := SmartGetFieldFloat(vp,hook_sdviewport_zZ);
  68. end;
  69. with Render do
  70. begin
  71. xScale := SmartGetFieldInt(tk, hook_sdtoolkit_xScale);
  72. yScale := SmartGetFieldInt(tk, hook_sdtoolkit_yScale);
  73. xMin := SmartGetFieldInt(tk, hook_sdtoolkit_xMin);
  74. xMax := SmartGetFieldInt(tk, hook_sdtoolkit_xMax);
  75. yMin := SmartGetFieldInt(tk, hook_sdtoolkit_yMin);
  76. yMax := SmartGetFieldInt(tk, hook_sdtoolkit_yMax);
  77. zMin := SmartGetFieldInt(tk, hook_sdtoolkit_zMin);
  78. zMax := SmartGetFieldInt(tk, hook_sdtoolkit_zMax);
  79. end;
  80. SmartFreeObject(tk);
  81. SmartFreeObject(vp);
  82. end;
  83. end;
  84. (*
  85. R_EmptyRenderInfo
  86. ~~~~~~~~~~~~~~~~~
  87. .. code-block:: pascal
  88. procedure R_EmptyRenderInfo(var Render : TRender; var RenderData : TRenderData);
  89. Empties a pair of TRender and TRenderData structures.
  90. .. note::
  91. by Drags111
  92. *)
  93. procedure R_EmptyRenderInfo(var Render : TRender; var RenderData : TRenderData);
  94. begin
  95. with RenderData do
  96. begin
  97. xOff := NULL_INT;
  98. xX := NULL_INT;
  99. xY := NULL_INT;
  100. xZ := NULL_INT;
  101. yOff := NULL_INT;
  102. yX := NULL_INT;
  103. yY := NULL_INT;
  104. yZ := NULL_INT;
  105. zOff := NULL_INT;
  106. zX := NULL_INT;
  107. zY := NULL_INT;
  108. zZ := NULL_INT;
  109. end;
  110. with Render do
  111. begin
  112. xScale := NULL_INT;
  113. yScale := NULL_INT;
  114. xMin := NULL_INT;
  115. xMax := NULL_INT;
  116. yMin := NULL_INT;
  117. yMax := NULL_INT;
  118. zMin := NULL_INT;
  119. zMax := NULL_INT;
  120. end;
  121. end;
  122. (*
  123. R_GetTileHeight
  124. ~~~~~~~~~~~~~~~
  125. .. code-block:: pascal
  126. function R_GetTileHeight(tile: TTile) : integer;
  127. Finds the average height of the global tile provided the tile is in the current
  128. loading area and on a loaded plane.
  129. .. note::
  130. by BenLand100
  131. *)
  132. function R_GetTileHeight(tile: TTile) : integer;
  133. var
  134. x, y, CurPlane, GroundSetting, PlaneInstance : integer;
  135. begin
  136. x := tile.x - SmartGetFieldInt(0, hook_static_BaseX);
  137. y := tile.y - SmartGetFieldInt(0, hook_static_BaseY);
  138. if ((x < 0) or (x > 104) or (y < 0) or (y > 104)) then
  139. begin
  140. result := 0;
  141. exit;
  142. end;
  143. CurPlane := SmartGetFieldInt(0, hook_static_LoadedPlane);
  144. GroundSetting := SmartGetFieldArray3DByte(0, hook_static_GroundSettingsArray, 1, X, Y);
  145. if ((CurPlane < 3) and ((GroundSetting and 2) <> 0)) then
  146. CurPlane:= CurPlane + 1;
  147. PlaneInstance := SmartGetFieldArrayObject(0, hook_static_PlaneArray, CurPlane);
  148. result:= (SmartGetFieldArray2DInt(PlaneInstance, hook_sdplane_TileHeights, x, y) +
  149. SmartGetFieldArray2DInt(PlaneInstance, hook_sdplane_TileHeights, x + 1, y) +
  150. SmartGetFieldArray2DInt(PlaneInstance, hook_sdplane_TileHeights, x, y + 1) +
  151. SmartGetFieldArray2DInt(PlaneInstance, hook_sdplane_TileHeights, x + 1, y + 1)) / 4;
  152. if(Result = -1)then
  153. writeln('****************TileHight hooks are incorrect.*****************');
  154. SmartFreeObject(PlaneInstance);
  155. end;
  156. (*
  157. R_World3DToScreen
  158. ~~~~~~~~~~~~~~~~~
  159. .. code-block:: pascal
  160. function R_World3DToScreen(xx, yy, zz: Extended): TPoint;
  161. Converts a RS 3D point to a coordinate on the screen.
  162. .. note::
  163. by Benland100
  164. *)
  165. function R_World3DToScreen(xx, yy, zz: Extended): TPoint;
  166. var
  167. rd : TRenderData;
  168. r : TRender;
  169. x, y, z: extended;
  170. tries: integer;
  171. label
  172. ProcStart;
  173. begin;
  174. ProcStart:
  175. R_EmptyRenderInfo(r, rd);
  176. x := 0;
  177. y := 0;
  178. z := 0;
  179. Inc(tries);
  180. result:= point(-1,-1);
  181. R_UpdateRenderInfo(r,rd);
  182. z:= rd.zOff + (rd.zX * xx + rd.zY * yy + rd.zZ * zz);
  183. if ((z < r.zMin) or (z > r.zMax)) then
  184. exit;
  185. x:= r.xScale * (rd.xOff + (rd.xX * xx + rd.xY * yy + rd.xZ * zz)) / z;
  186. y:= r.yScale * (rd.yOff + (rd.yX * xx + rd.yY * yy + rd.yZ * zz)) / z;
  187. if ((x >= r.xMin) and (x <= r.xMax) and (y >= r.yMin) and (y <= r.yMax)) then
  188. begin
  189. result.x:= Round((x - r.xMin)+4);
  190. result.y:= Round((y - r.yMin)+4);
  191. end else
  192. begin
  193. if (tries > 30)then Exit;
  194. goto ProcStart;
  195. end;
  196. end;
  197. (*
  198. R_TileToMSEx
  199. ~~~~~~~~~~~~
  200. .. code-block:: pascal
  201. function R_TileToMSEx(tile: TTile; offx, offy : extended; height : integer) : TPoint;
  202. Converts the global tile position, a position on that tile in the range
  203. [(0,0), (1,1)] with (0.5, 0.5) being center and a height above ground level to
  204. a screen location on the main screen, taking camera position and rotation into
  205. account.
  206. .. note::
  207. by Benland100
  208. *)
  209. function R_TileToMSEx(tile: TTile; offx, offy : extended; height : integer) : TPoint;
  210. var
  211. pixelX, pixelY, pixelZ: extended;
  212. begin
  213. pixelX:= (tile.x - SmartGetFieldInt(0, hook_static_BaseX) + offX) * 512.0;
  214. pixelY:= R_GetTileHeight(tile) - height;
  215. pixelZ:= (tile.y - SmartGetFieldInt(0, hook_static_BaseY) + offY) * 512.0;
  216. Result := R_World3DToScreen(pixelX, pixelY, pixelZ);
  217. if not PointInBox(Result, IntToBox(MSX1, MSY1, MSX2, MSY2))then
  218. begin
  219. Result.x := -1;
  220. Result.y := -1;
  221. end;
  222. end;
  223. (*
  224. R_TileToMS
  225. ~~~~~~~~~~
  226. .. code-block:: pascal
  227. function R_TileToMS(tile: TTile; height : integer): TPoint;
  228. Converts the center of a global tile position and a height above ground level
  229. to a screen location on the main screen, taking camera position and rotation
  230. into account.
  231. .. note::
  232. by BenLand100
  233. *)
  234. function R_TileToMS(TheTile: TTile; height : integer) : TPoint;
  235. begin
  236. result:= R_TileToMSEx(TheTile, 0.5, 0.5, height);
  237. end;
  238. (*
  239. R_TileOnMS
  240. ~~~~~~~~~~
  241. .. code-block:: pascal
  242. function R_TileOnMS(TheTile: TTile; Height : Integer) : Boolean;
  243. Results true if the Tile is on the MS.
  244. .. note::
  245. by Drags111
  246. *)
  247. function R_TileOnMS(TheTile: TTile; Height : Integer) : Boolean;
  248. begin
  249. Result := PointInBox(R_TileToMS(TheTile, Height), IntToBox(MSX1, MSY1, MSX2, MSY2));
  250. end;
  251. (*
  252. R_TileOnMSEx
  253. ~~~~~~~~~~~~
  254. .. code-block:: pascal
  255. function R_TileOnMSEx(T: TTile; offX, offY: extended; Height : Integer) : Boolean;
  256. Results true if the Tile is on the MS.
  257. .. note::
  258. by Drags111
  259. *)
  260. function R_TileOnMSEx(T: TTile; offX, offY: extended; Height : Integer) : Boolean;
  261. begin
  262. Result := PointInBox(R_TileToMSEx(T, offX, offY, Height),
  263. IntToBox(MSX1, MSY1, MSX2, MSY2));
  264. end;
  265. (*
  266. R_TileBoxOnMSEx
  267. ~~~~~~~~~~~~
  268. .. code-block:: pascal
  269. function R_TileBoxOnMSEx(Box: TBox; Height : Integer) : Boolean;
  270. Results true if the whole box of tiles with the given Height is on the MS.
  271. .. note::
  272. by mormonman
  273. *)
  274. function R_TileBoxOnMSEx(Box: TBox; Height : Integer) : Boolean;
  275. begin
  276. Result := R_TileOnMS(Point(Box.X1, Box.Y1), Height) and
  277. R_TileOnMS(Point(Box.X2, Box.Y2), Height);
  278. end;
  279. (*
  280. R_TileBoxOnMS
  281. ~~~~~~~~~~~~
  282. .. code-block:: pascal
  283. function R_TileBoxOnMS(Box: TBox) : Boolean;
  284. Results true if the whole box of tiles is on the MS.
  285. .. note::
  286. by mormonman
  287. *)
  288. function R_TileBoxOnMS(Box: TBox) : Boolean;
  289. begin
  290. Result := R_TileBoxOnMSEx(Box, 0);
  291. end;
  292. (*
  293. R_TileInBox
  294. ~~~~~~~~~~~
  295. .. code-block:: pascal
  296. function R_TileInBox(Bounds: TBox; T: TTile): boolean;
  297. Results true if the tile is in the box. TOP LEFT TO BOTTOM RIGHT.
  298. .. note::
  299. by Drags111
  300. *)
  301. function R_TileInBox(Bounds: TBox; T: TTile): boolean;
  302. var
  303. tx, ty, x1, y1, x2, y2: integer;
  304. begin
  305. x1 := Bounds.X1; y1 := Bounds.Y1;
  306. x2 := Bounds.X2; y2 := Bounds.Y2;
  307. tx := T.X; ty := T.Y;
  308. Result := ((tx >= x1) and (tx <= x2) and (ty <= y1) and (ty >= y2));
  309. end;
  310. (*
  311. R_SelfInBox
  312. ~~~~~~~~~~~
  313. .. code-block:: pascal
  314. function R_SelfInBox(Bounds: TBox): boolean;
  315. Results true if your char is in the box of tiles. TOP LEFT TO BOTTOM RIGHT.
  316. .. note::
  317. by Drags111
  318. *)
  319. function R_SelfInBox(Bounds: TBox): boolean;
  320. var
  321. tx, ty, x1, y1, x2, y2: integer;
  322. T: TTile;
  323. begin
  324. T := R_GetMyPos;
  325. x1 := Bounds.X1; y1 := Bounds.Y1;
  326. x2 := Bounds.X2; y2 := Bounds.Y2;
  327. tx := T.X; ty := T.Y;
  328. Result := ((tx >= x1) and (tx <= x2) and (ty <= y1) and (ty >= y2));
  329. end;
  330. (*
  331. R_GetMidTile
  332. ~~~~~~~~~~~~
  333. .. code-block:: pascal
  334. function R_GetMidTile(Tile1, Tile2: TTile): TTile;
  335. Returns the midway point of the 2 given tiles.
  336. .. note::
  337. by Drags111
  338. *)
  339. function R_GetMidTile(Tile1, Tile2: TTile): TTile;
  340. begin
  341. Result := Point((Tile1.x+Tile2.x)/2, (Tile1.y+Tile2.y)/2);
  342. end;
  343. (*
  344. R_GetCollisionMap
  345. ~~~~~~~~~~~~~~~~~
  346. .. code-block:: pascal
  347. function R_GetCollisionMap(var Blocks: array of TIntegerArray): Boolean;
  348. Returns a 2-dimensional array of the information stored in each tile in
  349. a loaded plane. Used to calculate if a tile is reachable or not.
  350. .. note::
  351. by Drags111
  352. *)
  353. function R_GetCollisionMap(var CollisionMap: array of TIntegerArray): Boolean;
  354. var
  355. X, Y: Integer;
  356. GroundDataArray, MyPlayer, Plane, GroundData, BlocksObj: Integer;
  357. begin
  358. GroundDataArray := SmartGetFieldObject(0, hook_static_GroundDataArray);
  359. MyPlayer := SmartGetFieldObject(0, hook_static_MyPlayer);
  360. Plane := SmartGetFieldByte(MyPlayer, hook_animable_Plane);
  361. if(SmartGetFieldArraySize(GroundDataArray, '', 1) < Plane)then
  362. begin
  363. Result := False;
  364. SmartFreeObject(GroundDataArray);
  365. SmartFreeObject(MyPlayer);
  366. R_Debug('GroundDataArray Length is less than Plane', 'R_GetCollisionMap');
  367. Exit;
  368. end;
  369. GroundData := SmartGetFieldArrayObject(GroundDataArray, '', Plane);
  370. BlocksObj := SmartGetFieldObject(GroundData, hook_grounddata_CollisionFlags);
  371. if(GroundData = 0) or (BlocksObj = 0)then
  372. begin
  373. Result := False;
  374. SmartFreeObject(GroundDataArray);
  375. SmartFreeObject(MyPlayer);
  376. SmartFreeObject(GroundData);
  377. SmartFreeObject(BlocksObj);
  378. R_Debug('GroundData or BlocksObj is null', 'R_GetCollisionMap');
  379. Exit;
  380. end;
  381. Result := True;
  382. SetLength(CollisionMap, 104);
  383. for X := 0 to 103 do
  384. begin
  385. SetLength(CollisionMap[X], 104);
  386. for Y := 0 to 103 do
  387. begin
  388. CollisionMap[X][Y] := SmartGetFieldArray2DInt(BlocksObj, '', X, Y);
  389. end;
  390. end;
  391. SmartFreeObject(GroundDataArray);
  392. SmartFreeObject(MyPlayer);
  393. SmartFreeObject(GroundData);
  394. SmartFreeObject(BlocksObj);
  395. end;
  396. (*
  397. R_PathLengthBetweenEx
  398. ~~~~~~~~~~~~~~~~~~~~~
  399. .. code-block:: pascal
  400. function R_PathLengthBetweenEx(Start, Dest: TTile; IsObject: Boolean; Blocks: array of TIntegerArray): Integer;
  401. Returns the length between 2 tiles via path distance. (Going around objects and
  402. such).
  403. .. note::
  404. by Drags111
  405. *)
  406. function R_PathLengthBetweenEx(Start, Dest: TTile; IsObject: Boolean; CollisionMap: array of TIntegerArray): Integer;
  407. var
  408. BaseX, BaseY: Integer;
  409. x1, y1, x2, y2: Integer;
  410. begin
  411. try
  412. BaseX := SmartGetFieldInt(0, hook_static_BaseX);
  413. BaseY := SmartGetFieldInt(0, hook_static_BaseY);
  414. x1 := Start.X - BaseX;
  415. y1 := Start.Y - BaseY;
  416. x2 := Dest.X - BaseX;
  417. y2 := Dest.Y - BaseY;
  418. Result := DijkstraDist(x1, y1, x2, y2, isObject, CollisionMap); // From the plugin
  419. except
  420. Result := -1;
  421. end;
  422. end;
  423. (*
  424. R_PathLengthBetween
  425. ~~~~~~~~~~~~~~~~~~~~~
  426. .. code-block:: pascal
  427. function R_PathLengthBetween(Start, Dest: TTile; IsObject: Boolean): Integer;
  428. Returns the length between 2 tiles via path distance. (Going around objects and
  429. such).
  430. .. note::
  431. by Drags111
  432. *)
  433. function R_PathLengthBetween(Start, Dest: TTile; IsObject: Boolean): Integer;
  434. var
  435. CollisionMap: array of TIntegerArray;
  436. begin
  437. try
  438. if not R_GetCollisionMap(CollisionMap)then
  439. begin
  440. R_Debug('Unable to retrieve collision map.', 'R_PathLengthBetween');
  441. Exit;
  442. end;
  443. Result := R_PathLengthBetweenEx(Start, Dest, IsObject, CollisionMap);
  444. except
  445. Result := -1;
  446. end;
  447. end;
  448. (*
  449. R_PathLengthBetween
  450. ~~~~~~~~~~~~~~~~~~~~~
  451. .. code-block:: pascal
  452. function R_CanReachEx(Tile: TTile; IsObject: Boolean; CollisionMap: array of TIntegerArray): Boolean;
  453. Returns true if a tile is reachable from your current position.
  454. .. note::
  455. by Drags111
  456. *)
  457. function R_CanReachEx(Tile: TTile; IsObject: Boolean; CollisionMap: array of TIntegerArray): Boolean;
  458. begin
  459. try
  460. Result := R_PathLengthBetweenEx(R_GetMyPos, Tile, IsObject, CollisionMap) <> -1;
  461. except
  462. Result := False;
  463. end;
  464. end;
  465. (*
  466. R_PathLengthBetween
  467. ~~~~~~~~~~~~~~~~~~~~~
  468. .. code-block:: pascal
  469. function R_CanReach(Tile: TTile; IsObject: Boolean): Boolean;
  470. Returns true if a tile is reachable from your current position.
  471. .. note::
  472. by Drags111
  473. *)
  474. function R_CanReach(Tile: TTile; IsObject: Boolean): Boolean;
  475. begin
  476. try
  477. Result := R_PathLengthBetween(R_GetMyPos, Tile, IsObject) <> -1;
  478. except
  479. Result := False;
  480. end;
  481. end;