PageRenderTime 88ms CodeModel.GetById 78ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

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