Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
PortalHelper.cs
Go to the documentation of this file.
1using System;
4using Terraria.ID;
5
7
8public class PortalHelper
9{
10 public const int PORTALS_PER_PERSON = 2;
11
12 private static int[,] FoundPortals;
13
14 private static int[] PortalCooldownForPlayers;
15
16 private static int[] PortalCooldownForNPCs;
17
18 private static readonly Vector2[] EDGES;
19
20 private static readonly Vector2[] SLOPE_EDGES;
21
22 private static readonly Point[] SLOPE_OFFSETS;
23
24 private static bool anyPortalAtAll;
25
26 static PortalHelper()
27 {
28 FoundPortals = new int[256, 2];
29 PortalCooldownForPlayers = new int[256];
30 PortalCooldownForNPCs = new int[200];
31 EDGES = new Vector2[4]
32 {
33 new Vector2(0f, 1f),
34 new Vector2(0f, -1f),
35 new Vector2(1f, 0f),
36 new Vector2(-1f, 0f)
37 };
38 SLOPE_EDGES = new Vector2[4]
39 {
40 new Vector2(1f, -1f),
41 new Vector2(-1f, -1f),
42 new Vector2(1f, 1f),
43 new Vector2(-1f, 1f)
44 };
45 SLOPE_OFFSETS = new Point[4]
46 {
47 new Point(1, -1),
48 new Point(-1, -1),
49 new Point(1, 1),
50 new Point(-1, 1)
51 };
52 anyPortalAtAll = false;
53 for (int i = 0; i < SLOPE_EDGES.Length; i++)
54 {
55 SLOPE_EDGES[i].Normalize();
56 }
57 for (int j = 0; j < FoundPortals.GetLength(0); j++)
58 {
59 FoundPortals[j, 0] = -1;
60 FoundPortals[j, 1] = -1;
61 }
62 }
63
64 public static void UpdatePortalPoints()
65 {
66 anyPortalAtAll = false;
67 for (int i = 0; i < FoundPortals.GetLength(0); i++)
68 {
69 FoundPortals[i, 0] = -1;
70 FoundPortals[i, 1] = -1;
71 }
72 for (int j = 0; j < PortalCooldownForPlayers.Length; j++)
73 {
75 {
77 }
78 }
79 for (int k = 0; k < PortalCooldownForNPCs.Length; k++)
80 {
81 if (PortalCooldownForNPCs[k] > 0)
82 {
84 }
85 }
86 for (int l = 0; l < 1000; l++)
87 {
88 Projectile projectile = Main.projectile[l];
89 if (projectile.active && projectile.type == 602 && projectile.ai[1] >= 0f && projectile.ai[1] <= 1f && projectile.owner >= 0 && projectile.owner <= 255)
90 {
91 FoundPortals[projectile.owner, (int)projectile.ai[1]] = l;
92 if (FoundPortals[projectile.owner, 0] != -1 && FoundPortals[projectile.owner, 1] != -1)
93 {
94 anyPortalAtAll = true;
95 }
96 }
97 }
98 }
99
101 {
102 if (!anyPortalAtAll)
103 {
104 return;
105 }
106 float collisionPoint = 0f;
107 _ = ent.velocity;
108 int width = ent.width;
109 int height = ent.height;
110 int num = 1;
111 if (ent is Player)
112 {
113 num = (int)((Player)ent).gravDir;
114 }
115 for (int i = 0; i < FoundPortals.GetLength(0); i++)
116 {
117 if (FoundPortals[i, 0] == -1 || FoundPortals[i, 1] == -1 || (ent is Player && (i >= PortalCooldownForPlayers.Length || PortalCooldownForPlayers[i] > 0)) || (ent is NPC && (i >= PortalCooldownForNPCs.Length || PortalCooldownForNPCs[i] > 0)))
118 {
119 continue;
120 }
121 for (int j = 0; j < 2; j++)
122 {
123 Projectile projectile = Main.projectile[FoundPortals[i, j]];
124 GetPortalEdges(projectile.Center, projectile.ai[0], out var start, out var end);
125 if (!Collision.CheckAABBvLineCollision(ent.position + ent.velocity, ent.Size, start, end, 2f, ref collisionPoint))
126 {
127 continue;
128 }
130 float num2 = ent.Hitbox.Distance(projectile.Center);
131 int bonusX;
132 int bonusY;
134 Vector2 vector2 = Vector2.UnitX * 16f;
135 if (Collision.TileCollision(vector - vector2, vector2, width, height, fallThrough: true, fall2: true, num) != vector2)
136 {
137 continue;
138 }
139 vector2 = -Vector2.UnitX * 16f;
140 if (Collision.TileCollision(vector - vector2, vector2, width, height, fallThrough: true, fall2: true, num) != vector2)
141 {
142 continue;
143 }
144 vector2 = Vector2.UnitY * 16f;
145 if (Collision.TileCollision(vector - vector2, vector2, width, height, fallThrough: true, fall2: true, num) != vector2)
146 {
147 continue;
148 }
149 vector2 = -Vector2.UnitY * 16f;
150 if (Collision.TileCollision(vector - vector2, vector2, width, height, fallThrough: true, fall2: true, num) != vector2)
151 {
152 continue;
153 }
154 float num3 = 0.1f;
155 if (bonusY == -num)
156 {
157 num3 = 0.1f;
158 }
159 if (ent.velocity == Vector2.Zero)
160 {
161 ent.velocity = (projectile.ai[0] - (float)Math.PI / 2f).ToRotationVector2() * num3;
162 }
163 if (ent.velocity.Length() < num3)
164 {
165 ent.velocity.Normalize();
166 ent.velocity *= num3;
167 }
169 if (vector3.HasNaNs() || vector3 == Vector2.Zero)
170 {
171 vector3 = Vector2.UnitX * ent.direction;
172 }
173 ent.velocity = vector3 * ent.velocity.Length();
174 if ((bonusY == -num && Math.Sign(ent.velocity.Y) != -num) || Math.Abs(ent.velocity.Y) < 0.1f)
175 {
176 ent.velocity.Y = (float)(-num) * 0.1f;
177 }
178 int num4 = (int)((float)(projectile2.owner * 2) + projectile2.ai[1]);
179 int lastPortalColorIndex = num4 + ((num4 % 2 == 0) ? 1 : (-1));
180 if (ent is Player)
181 {
182 Player player = (Player)ent;
183 player.lastPortalColorIndex = lastPortalColorIndex;
184 player.Teleport(vector, 4, num4);
185 if (Main.netMode == 1)
186 {
187 NetMessage.SendData(96, -1, -1, null, player.whoAmI, vector.X, vector.Y, num4);
188 NetMessage.SendData(13, -1, -1, null, player.whoAmI);
189 }
191 }
192 else if (ent is NPC)
193 {
194 NPC nPC = (NPC)ent;
195 nPC.lastPortalColorIndex = lastPortalColorIndex;
196 nPC.Teleport(vector, 4, num4);
197 if (Main.netMode == 2)
198 {
199 NetMessage.SendData(100, -1, -1, null, nPC.whoAmI, vector.X, vector.Y, num4);
200 NetMessage.SendData(23, -1, -1, null, nPC.whoAmI);
201 }
203 if (bonusY == -1 && ent.velocity.Y > -3f)
204 {
205 ent.velocity.Y = -3f;
206 }
207 }
208 return;
209 }
210 }
211 }
212
214 {
215 Vector2 vector = velocity / velocity.Length();
216 Point position = FindCollision(theBolt.position, theBolt.position + velocity + vector * 32f).ToTileCoordinates();
217 Tile tile = Main.tile[position.X, position.Y];
218 Vector2 vector2 = new Vector2(position.X * 16 + 8, position.Y * 16 + 8);
219 if (!WorldGen.SolidOrSlopedTile(tile))
220 {
221 return -1;
222 }
223 int num = tile.slope();
224 bool flag = tile.halfBrick();
225 for (int i = 0; i < (flag ? 2 : EDGES.Length); i++)
226 {
227 if (Vector2.Dot(EDGES[i], vector) > 0f && FindValidLine(position, (int)EDGES[i].Y, (int)(0f - EDGES[i].X), out var bestPosition))
228 {
229 vector2 = new Vector2(bestPosition.X * 16 + 8, bestPosition.Y * 16 + 8);
230 return AddPortal(theBolt, vector2 - EDGES[i] * (flag ? 0f : 8f), (float)Math.Atan2(EDGES[i].Y, EDGES[i].X) + (float)Math.PI / 2f, (int)theBolt.ai[0], theBolt.direction);
231 }
232 }
233 if (num != 0)
234 {
235 Vector2 value = SLOPE_EDGES[num - 1];
236 if (Vector2.Dot(value, -vector) > 0f && FindValidLine(position, -SLOPE_OFFSETS[num - 1].Y, SLOPE_OFFSETS[num - 1].X, out var bestPosition2))
237 {
238 vector2 = new Vector2(bestPosition2.X * 16 + 8, bestPosition2.Y * 16 + 8);
239 return AddPortal(theBolt, vector2, (float)Math.Atan2(value.Y, value.X) - (float)Math.PI / 2f, (int)theBolt.ai[0], theBolt.direction);
240 }
241 }
242 return -1;
243 }
244
245 private static bool FindValidLine(Point position, int xOffset, int yOffset, out Point bestPosition)
246 {
247 bestPosition = position;
248 if (IsValidLine(position, xOffset, yOffset))
249 {
250 return true;
251 }
252 Point point = new Point(position.X - xOffset, position.Y - yOffset);
253 if (IsValidLine(point, xOffset, yOffset))
254 {
255 bestPosition = point;
256 return true;
257 }
258 Point point2 = new Point(position.X + xOffset, position.Y + yOffset);
259 if (IsValidLine(point2, xOffset, yOffset))
260 {
262 return true;
263 }
264 return false;
265 }
266
267 private static bool IsValidLine(Point position, int xOffset, int yOffset)
268 {
269 Tile tile = Main.tile[position.X, position.Y];
270 Tile tile2 = Main.tile[position.X - xOffset, position.Y - yOffset];
271 Tile tile3 = Main.tile[position.X + xOffset, position.Y + yOffset];
272 if (BlockPortals(Main.tile[position.X + yOffset, position.Y - xOffset]) || BlockPortals(Main.tile[position.X + yOffset - xOffset, position.Y - xOffset - yOffset]) || BlockPortals(Main.tile[position.X + yOffset + xOffset, position.Y - xOffset + yOffset]))
273 {
274 return false;
275 }
276 if (CanPlacePortalOn(tile) && CanPlacePortalOn(tile2) && CanPlacePortalOn(tile3) && tile2.HasSameSlope(tile) && tile3.HasSameSlope(tile))
277 {
278 return true;
279 }
280 return false;
281 }
282
283 private static bool CanPlacePortalOn(Tile t)
284 {
286 {
287 return false;
288 }
289 return WorldGen.SolidOrSlopedTile(t);
290 }
291
292 private static bool DoesTileTypeSupportPortals(ushort tileType)
293 {
294 if (tileType == 496)
295 {
296 return false;
297 }
298 return true;
299 }
300
301 private static bool BlockPortals(Tile t)
302 {
304 {
305 return true;
306 }
307 return false;
308 }
309
311 {
312 int lastX = 0;
313 int lastY = 0;
314 Utils.PlotLine(startPosition.ToTileCoordinates(), stopPosition.ToTileCoordinates(), delegate(int x, int y)
315 {
316 lastX = x;
317 lastY = y;
318 return !WorldGen.SolidOrSlopedTile(x, y);
319 }, jump: false);
320 return new Vector2((float)lastX * 16f, (float)lastY * 16f);
321 }
322
323 private static int AddPortal(Projectile sourceProjectile, Vector2 position, float angle, int form, int direction)
324 {
325 if (!SupportedTilesAreFine(position, angle))
326 {
327 return -1;
328 }
331 int num = Projectile.NewProjectile(Projectile.InheritSource(sourceProjectile), position.X, position.Y, 0f, 0f, 602, 0, 0f, Main.myPlayer, angle, form);
332 Main.projectile[num].direction = direction;
333 Main.projectile[num].netUpdate = true;
334 return num;
335 }
336
337 private static void RemoveMyOldPortal(int form)
338 {
339 for (int i = 0; i < 1000; i++)
340 {
341 Projectile projectile = Main.projectile[i];
342 if (projectile.active && projectile.type == 602 && projectile.owner == Main.myPlayer && projectile.ai[1] == (float)form)
343 {
344 projectile.Kill();
345 break;
346 }
347 }
348 }
349
350 private static void RemoveIntersectingPortals(Vector2 position, float angle)
351 {
352 GetPortalEdges(position, angle, out var start, out var end);
353 for (int i = 0; i < 1000; i++)
354 {
355 Projectile projectile = Main.projectile[i];
356 if (!projectile.active || projectile.type != 602)
357 {
358 continue;
359 }
360 GetPortalEdges(projectile.Center, projectile.ai[0], out var start2, out var end2);
361 if (Collision.CheckLinevLine(start, end, start2, end2).Length != 0)
362 {
363 if (projectile.owner != Main.myPlayer && Main.netMode != 2)
364 {
365 NetMessage.SendData(95, -1, -1, null, projectile.owner, (int)projectile.ai[1]);
366 }
367 projectile.Kill();
368 }
369 }
370 }
371
372 public static Color GetPortalColor(int colorIndex)
373 {
374 return GetPortalColor(colorIndex / 2, colorIndex % 2);
375 }
376
377 public static Color GetPortalColor(int player, int portal)
378 {
380 if (Main.netMode == 0)
381 {
382 white = ((portal != 0) ? Main.hslToRgb(0.52f, 1f, 0.6f) : Main.hslToRgb(0.12f, 1f, 0.5f));
383 }
384 else
385 {
386 float num = 0.08f;
387 white = Main.hslToRgb((0.5f + (float)player * (num * 2f) + (float)portal * num) % 1f, 1f, 0.5f);
388 }
389 white.A = 66;
390 return white;
391 }
392
393 private static void GetPortalEdges(Vector2 position, float angle, out Vector2 start, out Vector2 end)
394 {
395 Vector2 vector = angle.ToRotationVector2();
396 start = position + vector * -22f;
397 end = position + vector * 22f;
398 }
399
401 {
402 int num = (int)Math.Round(MathHelper.WrapAngle(portalAngle) / ((float)Math.PI / 4f));
403 switch (num)
404 {
405 case -2:
406 case 2:
407 bonusX = ((num != 2) ? 1 : (-1));
408 bonusY = 0;
409 return portalPosition + new Vector2((num == 2) ? (0f - objectSize.X) : 0f, (0f - objectSize.Y) / 2f);
410 case 0:
411 case 4:
412 bonusX = 0;
413 bonusY = ((num == 0) ? 1 : (-1));
414 return portalPosition + new Vector2((0f - objectSize.X) / 2f, (num == 0) ? 0f : (0f - objectSize.Y));
415 case -3:
416 case 3:
417 bonusX = ((num == -3) ? 1 : (-1));
418 bonusY = -1;
419 return portalPosition + new Vector2((num == -3) ? 0f : (0f - objectSize.X), 0f - objectSize.Y);
420 case -1:
421 case 1:
422 bonusX = ((num == -1) ? 1 : (-1));
423 bonusY = 1;
424 return portalPosition + new Vector2((num == -1) ? 0f : (0f - objectSize.X), 0f);
425 default:
426 bonusX = 0;
427 bonusY = 0;
428 return portalPosition;
429 }
430 }
431
433 {
435 for (int i = 0; i < 1000; i++)
436 {
437 Projectile projectile = Main.projectile[i];
438 if (!projectile.active || (projectile.type != 602 && projectile.type != 601))
439 {
440 continue;
441 }
442 Vector2 center = projectile.Center;
443 int sectionX = Netplay.GetSectionX((int)(center.X / 16f));
444 int sectionY = Netplay.GetSectionY((int)(center.Y / 16f));
445 for (int j = sectionX - fluff; j < sectionX + fluff + 1; j++)
446 {
447 for (int k = sectionY - fluff; k < sectionY + fluff + 1; k++)
448 {
449 if (j >= 0 && j < Main.maxSectionsX && k >= 0 && k < Main.maxSectionsY && !Netplay.Clients[plr].TileSections[j, k] && !dontInclude.Contains(new Point(j, k)))
450 {
451 portalSections.Add(new Point(j, k));
452 }
453 }
454 }
455 }
456 }
457
459 {
460 for (int i = 0; i < 255; i++)
461 {
462 if (Main.player[i].active)
463 {
465 }
466 }
467 }
468
470 {
471 Point point = portalCenter.ToTileCoordinates();
472 int num = (int)Math.Round(MathHelper.WrapAngle(portalAngle) / ((float)Math.PI / 4f));
473 int num2;
474 int num3;
475 switch (num)
476 {
477 case -2:
478 case 2:
479 num2 = ((num != 2) ? 1 : (-1));
480 num3 = 0;
481 break;
482 case 0:
483 case 4:
484 num2 = 0;
485 num3 = ((num == 0) ? 1 : (-1));
486 break;
487 case -3:
488 case 3:
489 num2 = ((num == -3) ? 1 : (-1));
490 num3 = -1;
491 break;
492 case -1:
493 case 1:
494 num2 = ((num == -1) ? 1 : (-1));
495 num3 = 1;
496 break;
497 default:
498 Main.NewText("Broken portal! (over4s = " + num + " , " + portalAngle + ")");
499 return false;
500 }
501 if (num2 != 0 && num3 != 0)
502 {
503 int num4 = 3;
504 if (num2 == -1 && num3 == 1)
505 {
506 num4 = 5;
507 }
508 if (num2 == 1 && num3 == -1)
509 {
510 num4 = 2;
511 }
512 if (num2 == 1 && num3 == 1)
513 {
514 num4 = 4;
515 }
516 num4--;
517 if (SupportedSlope(point.X, point.Y, num4) && SupportedSlope(point.X + num2, point.Y - num3, num4))
518 {
519 return SupportedSlope(point.X - num2, point.Y + num3, num4);
520 }
521 return false;
522 }
523 if (num2 != 0)
524 {
525 if (num2 == 1)
526 {
527 point.X--;
528 }
529 if (SupportedNormal(point.X, point.Y) && SupportedNormal(point.X, point.Y - 1))
530 {
531 return SupportedNormal(point.X, point.Y + 1);
532 }
533 return false;
534 }
535 if (num3 != 0)
536 {
537 if (num3 == 1)
538 {
539 point.Y--;
540 }
541 if (!SupportedNormal(point.X, point.Y) || !SupportedNormal(point.X + 1, point.Y) || !SupportedNormal(point.X - 1, point.Y))
542 {
543 if (SupportedHalfbrick(point.X, point.Y) && SupportedHalfbrick(point.X + 1, point.Y))
544 {
545 return SupportedHalfbrick(point.X - 1, point.Y);
546 }
547 return false;
548 }
549 return true;
550 }
551 return true;
552 }
553
554 private static bool SupportedSlope(int x, int y, int slope)
555 {
556 Tile tile = Main.tile[x, y];
557 if (tile != null && tile.nactive() && !Main.tileCut[tile.type] && !TileID.Sets.BreakableWhenPlacing[tile.type] && Main.tileSolid[tile.type] && tile.slope() == slope)
558 {
559 return DoesTileTypeSupportPortals(tile.type);
560 }
561 return false;
562 }
563
564 private static bool SupportedHalfbrick(int x, int y)
565 {
566 Tile tile = Main.tile[x, y];
567 if (tile != null && tile.nactive() && !Main.tileCut[tile.type] && !TileID.Sets.BreakableWhenPlacing[tile.type] && Main.tileSolid[tile.type] && tile.halfBrick())
568 {
569 return DoesTileTypeSupportPortals(tile.type);
570 }
571 return false;
572 }
573
574 private static bool SupportedNormal(int x, int y)
575 {
576 Tile tile = Main.tile[x, y];
577 if (tile != null && tile.nactive() && !Main.tileCut[tile.type] && !TileID.Sets.BreakableWhenPlacing[tile.type] && Main.tileSolid[tile.type] && !TileID.Sets.NotReallySolid[tile.type] && !tile.halfBrick() && tile.slope() == 0)
578 {
579 return DoesTileTypeSupportPortals(tile.type);
580 }
581 return false;
582 }
583}
static float WrapAngle(float angle)
Definition MathHelper.cs:87
bool ICollection< KeyValuePair< TKey, TValue > >. Contains(KeyValuePair< TKey, TValue > keyValuePair)
void Add(TKey key, TValue value)
static double Atan2(double y, double x)
static decimal Round(decimal d)
Definition Math.cs:1096
static double Abs(double value)
const double PI
Definition Math.cs:16
static int Sign(decimal value)
Definition Math.cs:1202
static Vector2[] CheckLinevLine(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2)
Definition Collision.cs:40
static bool CheckAABBvLineCollision(Vector2 aabbPosition, Vector2 aabbDimensions, Vector2 lineStart, Vector2 lineEnd)
Definition Collision.cs:198
static Vector2 TileCollision(Vector2 Position, Vector2 Velocity, int Width, int Height, bool fallThrough=false, bool fall2=false, int gravDir=1)
Vector2 Center
Definition Entity.cs:43
static void RemoveMyOldPortal(int form)
static readonly Point[] SLOPE_OFFSETS
static bool DoesTileTypeSupportPortals(ushort tileType)
static Color GetPortalColor(int player, int portal)
static Color GetPortalColor(int colorIndex)
static int AddPortal(Projectile sourceProjectile, Vector2 position, float angle, int form, int direction)
static bool SupportedHalfbrick(int x, int y)
static int TryPlacingPortal(Projectile theBolt, Vector2 velocity, Vector2 theCrashVelocity)
static bool CanPlacePortalOn(Tile t)
static bool SupportedSlope(int x, int y, int slope)
static void RemoveIntersectingPortals(Vector2 position, float angle)
static Vector2 GetPortalOutingPoint(Vector2 objectSize, Vector2 portalPosition, float portalAngle, out int bonusX, out int bonusY)
static Vector2 FindCollision(Vector2 startPosition, Vector2 stopPosition)
static readonly Vector2[] EDGES
static bool FindValidLine(Point position, int xOffset, int yOffset, out Point bestPosition)
static bool IsValidLine(Point position, int xOffset, int yOffset)
static void GetPortalEdges(Vector2 position, float angle, out Vector2 start, out Vector2 end)
static void SyncPortalSections(Vector2 portalPosition, int fluff)
static void TryGoingThroughPortals(Entity ent)
static void SyncPortalsOnPlayerJoin(int plr, int fluff, List< Point > dontInclude, out List< Point > portalSections)
static bool SupportedTilesAreFine(Vector2 portalCenter, float portalAngle)
static bool SupportedNormal(int x, int y)
static readonly Vector2[] SLOPE_EDGES
static bool[] BreakableWhenPlacing
Definition TileID.cs:277
static bool[] NotReallySolid
Definition TileID.cs:257
static int maxSectionsY
Definition Main.cs:1124
static bool[] tileCut
Definition Main.cs:1433
static int myPlayer
Definition Main.cs:1801
static int netMode
Definition Main.cs:2095
static void NewText(string newText, byte R=byte.MaxValue, byte G=byte.MaxValue, byte B=byte.MaxValue)
Definition Main.cs:61429
static bool[] tileSolid
Definition Main.cs:1471
static Tile[,] tile
Definition Main.cs:1675
static Projectile[] projectile
Definition Main.cs:1691
static Microsoft.Xna.Framework.Color hslToRgb(Vector3 hslVector)
Definition Main.cs:44913
static Player[] player
Definition Main.cs:1803
static void SendData(int msgType, int remoteClient=-1, int ignoreClient=-1, NetworkText text=null, int number=0, float number2=0f, float number3=0f, float number4=0f, int number5=0, int number6=0, int number7=0)
Definition NetMessage.cs:88
static RemoteClient[] Clients
Definition Netplay.cs:37
static int GetSectionX(int x)
Definition Netplay.cs:774
static int GetSectionY(int y)
Definition Netplay.cs:779
void Teleport(Vector2 newPos, int Style=0, int extraInfo=0)
Definition Player.cs:35567
static IEntitySource InheritSource(Projectile projectile)
static int NewProjectile(IEntitySource spawnSource, Vector2 position, Vector2 velocity, int Type, int Damage, float KnockBack, int Owner=-1, float ai0=0f, float ai1=0f, float ai2=0f)
static void CheckSection(int playerIndex, Vector2 position, int fluff=1)
bool nactive()
Definition Tile.cs:257
ushort type
Definition Tile.cs:8
bool active()
Definition Tile.cs:565
byte slope()
Definition Tile.cs:684
bool halfBrick()
Definition Tile.cs:650
static bool PlotLine(Point16 p0, Point16 p1, TileActionAttempt plot, bool jump=true)
Definition Utils.cs:1566
static bool SolidOrSlopedTile(Tile tile)
static float Dot(Vector2 value1, Vector2 value2)
Definition Vector2.cs:121