1--[[ 2 PHYSICS LIBRARY THING 3 WRITTEN BY MAURICE GU�GAN FOR MARI0 4 DON'T STEAL MY SHIT 5 Licensed under the same license as the game itself. 6]]-- 7 8--MASK REFERENCE LIST 9---1: *ALWAYS NOT COLLIDE* 10 11---2: WORLD 12---3: MARIO 13---4: GOOMBA 14---5: KOOPA 15---6: MUSHROOM/ONEUP/FLOWER/STAR 16 17---7: GEL DISPENSER 18---8: GEL 19---9: BOX 20--10: SCREENBOUNDARIES 21--11: BULLETBILL 22 23--12: PORTALWALLS 24--13: FIREBALLS 25--14: HAMMERS 26--15: PLATFORMS/SEESAWS 27--16: BOWSER 28 29--17: FIRE 30--18: VINE 31--19: SPRING 32--20: HAMMERBROS 33--21: LAKITO 34 35--22: BUTTON --Not used anymore 36--23: CASTLEFIRE 37--24: CHEEP CHEEP 38--25: DOOR 39--26: FAITHPLATE 40 41--27: FLYINGFISH 42--28: LIGHTBRIDGE 43--29: PLANT 44--30: SQUID 45--31: UPFIRE 46 47function physicsupdate(dt) 48 local lobjects = objects 49 50 for j, w in pairs(lobjects) do 51 if j ~= "tile" then 52 for i, v in pairs(w) do 53 if v.static == false and v.active then 54 --GRAVITY 55 v.speedy = v.speedy + (v.gravity or yacceleration)*dt 56 if v.speedy > maxyspeed then 57 v.speedy = maxyspeed 58 end 59 60 --PORTALS LOL 61 local passed = false 62 if v.portalable ~= false then 63 if not checkportalVER(v, v.x+v.speedx*dt) then 64 if checkportalHOR(v, v.y+v.speedy*dt) then 65 passed = true 66 end 67 else 68 passed = true 69 end 70 71 if passed and j == "player" then 72 playsound(portalentersound) 73 end 74 end 75 76 --COLLISIONS ROFL 77 local horcollision = false 78 local vercollision = false 79 80 --VS OTHER OBJECTS --but not portalwall 81 for h, u in pairs(lobjects) do 82 if h ~= "tile" and h ~= "portalwall" then 83 local hor, ver = handlegroup(i, h, u, v, j, dt, passed) 84 if hor then 85 horcollision = true 86 end 87 if ver then 88 vercollision = true 89 end 90 end 91 end 92 93 --VS TILES (Because I only wanna check close ones) 94 local xstart = math.floor(v.x+v.speedx*dt-2/16)+1 95 local ystart = math.floor(v.y+v.speedy*dt-2/16)+1 96 97 local xfrom = xstart 98 local xto = xstart+math.ceil(v.width) 99 local dir = 1 100 101 if v.speedx < 0 then 102 xfrom, xto = xto, xfrom 103 dir = -1 104 end 105 106 for x = xfrom, xto, dir do 107 for y = ystart, ystart+math.ceil(v.height) do 108 --check if invisible block 109 if inmap(x, y) and (not tilequads[map[x][y][1]].invisible or j == "player") then 110 local t = lobjects["tile"][x .. "-" .. y] 111 if t then 112 -- Same object Active Not masked 113 if (i ~= g or j ~= h) and t.active and v.mask[t.category] ~= true then 114 local collision1, collision2 = checkcollision(v, t, "tile", x .. "-" .. y, j, i, dt, passed) 115 if collision1 then 116 horcollision = true 117 elseif collision2 then 118 vercollision = true 119 end 120 end 121 end 122 end 123 end 124 end 125 126 --VS PORTALWALL 127 local h = "portalwall" 128 local u = objects["portalwall"] 129 local hor, ver = handlegroup(i, h, u, v, j, dt, passed) 130 if hor then 131 horcollision = true 132 end 133 if ver then 134 vercollision = true 135 end 136 137 --Check for emancipation grill 138 if v.emancipatecheck then 139 for h, u in pairs(emancipationgrills) do 140 if u.dir == "hor" then 141 if inrange(v.x+6/16, u.startx-1, u.endx, true) and inrange(u.y-14/16, v.y, v.y+v.speedy*dt, true) then 142 v:emancipate(h) 143 end 144 else 145 if inrange(v.y+6/16, u.starty-1, u.endy, true) and inrange(u.x-14/16, v.x, v.x+v.speedx*dt, true) then 146 v:emancipate(h) 147 end 148 end 149 end 150 end 151 152 --Move the object 153 if vercollision == false then 154 v.y = v.y + v.speedy*dt 155 if v.gravity then 156 if v.speedy == v.gravity*dt and v.startfall then 157 v:startfall(i) 158 end 159 else 160 if v.speedy == yacceleration*dt and v.startfall then 161 v:startfall(i) 162 end 163 end 164 end 165 166 if horcollision == false then 167 v.x = v.x + v.speedx*dt 168 end 169 170 --check if object is inside portal 171 if v.portalable ~= false then 172 inportal(v) 173 end 174 end 175 end 176 end 177 end 178end 179 180function handlegroup(i, h, u, v, j, dt, passed) 181 local horcollision = false 182 local vercollision = false 183 for g, t in pairs(u) do 184 -- Same object? Active Not masked 185 if (i ~= g or j ~= h) and t.active and (v.mask == nil or v.mask[t.category] ~= true) and (t.mask == nil or t.mask[v.category] ~= true) then 186 local collision1, collision2 = checkcollision(v, t, h, g, j, i, dt, passed) 187 if collision1 then 188 horcollision = true 189 elseif collision2 then 190 vercollision = true 191 end 192 end 193 end 194 195 return horcollision, vercollision 196end 197 198function checkcollision(v, t, h, g, j, i, dt, passed) --v: b1table | t: b2table | h: b2type | g: b2id | j: b1type | i: b1id 199 local hadhorcollision = false 200 local hadvercollision = false 201 202 if math.abs(v.x-t.x) < math.max(v.width, t.width)+1 and math.abs(v.y-t.y) < math.max(v.height, t.height)+1 then 203 --check if it's a passive collision (Object is colliding anyway) 204 if not passed and aabb(v.x, v.y, v.width, v.height, t.x, t.y, t.width, t.height) then --passive collision! (oh noes!) 205 if passivecollision(v, t, h, g, j, i, dt) then 206 hadvercollision = true 207 end 208 209 elseif aabb(v.x + v.speedx*dt, v.y + v.speedy*dt, v.width, v.height, t.x, t.y, t.width, t.height) then 210 if aabb(v.x + v.speedx*dt, v.y, v.width, v.height, t.x, t.y, t.width, t.height) then --Collision is horizontal! 211 if horcollision(v, t, h, g, j, i, dt) then 212 hadhorcollision = true 213 end 214 215 elseif aabb(v.x, v.y+v.speedy*dt, v.width, v.height, t.x, t.y, t.width, t.height) then --Collision is vertical! 216 if vercollision(v, t, h, g, j, i, dt) then 217 hadvercollision = true 218 end 219 220 else 221 --We're fucked, it's a diagonal collision! run! 222 --Okay actually let's take this slow okay. Let's just see if we're moving faster horizontally than vertically, aight? 223 local grav = yacceleration 224 if self and self.gravity then 225 grav = self.gravity 226 end 227 if math.abs(v.speedy-grav*dt) < math.abs(v.speedx) then 228 --vertical collision it is. 229 if vercollision(v, t, h, g, j, i, dt) then 230 hadvercollision = true 231 end 232 else 233 --okay so we're moving mainly vertically, so let's just pretend it was a horizontal collision? aight cool. 234 if horcollision(v, t, h, g, j, i, dt) then 235 hadhorcollision = true 236 end 237 end 238 end 239 end 240 end 241 242 return hadhorcollision, hadvercollision 243end 244 245function passivecollision(v, t, h, g, j, i, dt) 246 if v.passivecollide then 247 v:passivecollide(h, t) 248 if t.passivecollide then 249 t:passivecollide(j, v) 250 end 251 else 252 if v.floorcollide then 253 if v:floorcollide(h, t, dt) ~= false then 254 if v.speedy > 0 then 255 v.speedy = 0 256 end 257 v.y = t.y - v.height 258 return true 259 end 260 else 261 if v.speedy > 0 then 262 v.speedy = 0 263 end 264 v.y = t.y - v.height 265 return true 266 end 267 end 268 269 return false 270end 271 272function horcollision(v, t, h, g, j, i, dt) 273 if v.speedx < 0 then 274 --move object RIGHT (because it was moving left) 275 276 if t.rightcollide then 277 if t:rightcollide(j, v) ~= false then 278 if t.speedx and t.speedx > 0 then 279 t.speedx = 0 280 end 281 end 282 else 283 if t.speedx and t.speedx > 0 then 284 t.speedx = 0 285 end 286 end 287 if v.leftcollide then 288 if v:leftcollide(h, t) ~= false then 289 if v.speedx < 0 then 290 v.speedx = 0 291 end 292 v.x = t.x + t.width 293 return true 294 end 295 else 296 if v.speedx < 0 then 297 v.speedx = 0 298 end 299 v.x = t.x + t.width 300 return true 301 end 302 else 303 --move object LEFT (because it was moving right) 304 305 if t.leftcollide then 306 if t:leftcollide(j, v) ~= false then 307 if t.speedx and t.speedx < 0 then 308 t.speedx = 0 309 end 310 end 311 else 312 if t.speedx and t.speedx < 0 then 313 t.speedx = 0 314 end 315 end 316 317 if v.rightcollide then 318 if v:rightcollide(h, t) ~= false then 319 if v.speedx > 0 then 320 v.speedx = 0 321 end 322 v.x = t.x - v.width 323 return true 324 end 325 else 326 if v.speedx > 0 then 327 v.speedx = 0 328 end 329 v.x = t.x - v.width 330 return true 331 end 332 end 333 334 return false 335end 336 337function vercollision(v, t, h, g, j, i, dt) 338 if v.speedy < 0 then 339 --move object DOWN (because it was moving up) 340 if t.floorcollide then 341 if t:floorcollide(j, v) ~= false then 342 if t.speedy and t.speedy > 0 then 343 t.speedy = 0 344 end 345 end 346 else 347 if t.speedy and t.speedy > 0 then 348 t.speedy = 0 349 end 350 end 351 352 if v.ceilcollide then 353 if v:ceilcollide(h, t) ~= false then 354 if v.speedy < 0 then 355 v.speedy = 0 356 end 357 v.y = t.y + t.height 358 return true 359 end 360 else 361 if v.speedy < 0 then 362 v.speedy = 0 363 end 364 v.y = t.y + t.height 365 return true 366 end 367 else 368 if t.ceilcollide then 369 if t:ceilcollide(j, v) ~= false then 370 if t.speedy and t.speedy < 0 then 371 t.speedy = 0 372 end 373 end 374 else 375 if t.speedy and t.speedy < 0 then 376 t.speedy = 0 377 end 378 end 379 if v.floorcollide then 380 if v:floorcollide(h, t, dt) ~= false then 381 if v.speedy > 0 then 382 v.speedy = 0 383 end 384 v.y = t.y - v.height 385 return true 386 end 387 else 388 if v.speedy > 0 then 389 v.speedy = 0 390 end 391 v.y = t.y - v.height 392 return true 393 end 394 end 395 return false 396end 397 398function aabb(ax, ay, awidth, aheight, bx, by, bwidth, bheight) 399 return ax+awidth > bx and ax < bx+bwidth and ay+aheight > by and ay < by+bheight 400end 401 402function checkrect(x, y, width, height, list, statics) 403 local out = {} 404 405 local inobj 406 407 if type(list) == "table" and list[1] == "exclude" then 408 inobj = list[2] 409 list = "all" 410 end 411 412 for i, v in pairs(objects) do 413 local contains = false 414 415 if list and list ~= "all" then 416 for j = 1, #list do 417 if list[j] == i then 418 contains = true 419 end 420 end 421 end 422 423 if list == "all" or contains then 424 for j, w in pairs(v) do 425 if statics or w.static ~= true or list ~= "all" then 426 local skip = false 427 if inobj then 428 if w.x == inobj.x and w.y == inobj.y then 429 skip = true 430 end 431 --masktable 432 if (inobj.mask ~= nil and inobj.mask[w.category] == true) or (w.mask ~= nil and w.mask[inobj.category] == true) then 433 skip = true 434 end 435 end 436 if not skip then 437 if w.active then 438 if aabb(x, y, width, height, w.x, w.y, w.width, w.height) then 439 table.insert(out, i) 440 table.insert(out, j) 441 end 442 end 443 end 444 end 445 end 446 end 447 end 448 449 return out 450end 451 452function inportal(self) 453 if self.mask[2] then 454 return 455 end 456 for i, v in pairs(objects["player"]) do 457 if v.portal1X ~= false and v.portal2X ~= false then 458 local portal1xplus = 0 459 local portal2xplus = 0 460 local portal1Y = v.portal1Y 461 local portal2Y = v.portal2Y 462 local portal1yplus = 0 463 local portal2yplus = 0 464 local portal1X = v.portal1X 465 local portal2X = v.portal2X 466 467 --Get the extra block of each portal 468 if v.portal1facing == "up" then 469 portal1xplus = 1 470 elseif v.portal1facing == "down" then 471 portal1xplus = -1 472 end 473 474 if v.portal2facing == "up" then 475 portal2xplus = 1 476 elseif v.portal2facing == "down" then 477 portal2xplus = -1 478 end 479 480 if v.portal1facing == "right" then 481 portal1yplus = 1 482 elseif v.portal1facing == "left" then 483 portal1yplus = -1 484 end 485 486 if v.portal2facing == "right" then 487 portal2yplus = 1 488 elseif v.portal2facing == "left" then 489 portal2yplus = -1 490 end 491 492 local x = math.floor(self.x+self.width/2)+1 493 local y = math.floor(self.y+self.height/2)+1 494 495 if (x == portal1X or x == portal1X + portal1xplus) and (y == portal1Y or y == portal1Y + portal1yplus) then 496 local entryportalX = v.portal1X 497 local entryportalY = v.portal1Y 498 local entryportalfacing = v.portal1facing 499 500 local exitportalX = v.portal2X 501 local exitportalY = v.portal2Y 502 local exitportalfacing = v.portal2facing 503 504 self.x, self.y, self.speedx, self.speedy, self.rotation = portalcoords(self.x, self.y, self.speedx, self.speedy, self.width, self.height, self.rotation, self.animationdirection, entryportalX, entryportalY, entryportalfacing, exitportalX, exitportalY, exitportalfacing, self, true) 505 506 elseif (x == portal2X or x == portal2X + portal2xplus) and (y == portal2Y or y == portal2Y + portal2yplus) then 507 local entryportalX = v.portal2X 508 local entryportalY = v.portal2Y 509 local entryportalfacing = v.portal2facing 510 511 local exitportalX = v.portal1X 512 local exitportalY = v.portal1Y 513 local exitportalfacing = v.portal1facing 514 515 self.x, self.y, self.speedx, self.speedy, self.rotation = portalcoords(self.x, self.y, self.speedx, self.speedy, self.width, self.height, self.rotation, self.animationdirection, entryportalX, entryportalY, entryportalfacing, exitportalX, exitportalY, exitportalfacing, self) 516 517 end 518 end 519 end 520 521 return false 522end 523 524function checkportalHOR(self, nextY) --handles horizontal (up- and down facing) portal teleportation 525 for i, v in pairs(objects["player"]) do 526 if v.portal1X ~= false and v.portal2X ~= false then 527 528 local portal1xplus = 0 529 local portal2xplus = 0 530 local portal1Y = v.portal1Y 531 local portal2Y = v.portal2Y 532 533 --Get the extra block of each portal 534 if v.portal1facing == "up" then 535 portal1xplus = 1 536 portal1Y = portal1Y - 1 537 elseif v.portal1facing == "down" then 538 portal1xplus = -1 539 end 540 541 if v.portal2facing == "up" then 542 portal2xplus = 1 543 portal2Y = portal2Y - 1 544 elseif v.portal2facing == "down" then 545 portal2xplus = -1 546 end 547 548 --first part checks whether object is in the portal's x range, second part whether object just moved through the portal's Y value 549 if ((v.portal1X == math.floor(self.x+1) or v.portal1X+portal1xplus == math.floor(self.x+1)) and inrange(portal1Y, self.y+self.height/2, nextY+self.height/2)) 550 or ((v.portal2X == math.floor(self.x+1) or v.portal2X+portal2xplus == math.floor(self.x+1)) and inrange(portal2Y, self.y+self.height/2, nextY+self.height/2)) then 551 552 --check which portal is entry 553 local entryportalX, entryportalY, entryportalfacing 554 local exitportalX, exitportalY, exitportalfacing 555 local entryportalxplus, entryportalyplus, exitportalxplus, exitportalyplus 556 if (v.portal1X == math.floor(self.x+1) or v.portal1X+portal1xplus == math.floor(self.x+1)) and inrange(portal1Y, self.y+self.height/2, nextY+self.height/2) then 557 entryportalX = v.portal1X 558 entryportalY = v.portal1Y 559 entryportalfacing = v.portal1facing 560 entryportalxplus = portal1xplus 561 562 exitportalX = v.portal2X 563 exitportalY = v.portal2Y 564 exitportalfacing = v.portal2facing 565 exitportalxplus = portal2xplus 566 else 567 entryportalX = v.portal2X 568 entryportalY = v.portal2Y 569 entryportalfacing = v.portal2facing 570 entryportalxplus = portal2xplus 571 572 exitportalX = v.portal1X 573 exitportalY = v.portal1Y 574 exitportalfacing = v.portal1facing 575 exitportalxplus = portal1xplus 576 end 577 578 --check if movement makes that portal even a possibility 579 if entryportalfacing == "up" then 580 if self.speedy < 0 then 581 return false 582 end 583 elseif entryportalfacing == "down" then 584 if self.speedy > 0 then 585 return false 586 end 587 end 588 589 if entryportalfacing == "left" or entryportalfacing == "right" then 590 return false 591 end 592 593 local testx, testy, testspeedx, testspeedy, testrotation = portalcoords(self.x, self.y, self.speedx, self.speedy, self.width, self.height, self.rotation, self.animationdirection, entryportalX, entryportalY, entryportalfacing, exitportalX, exitportalY, exitportalfacing, self, true) 594 595 if #checkrect(testx, testy, self.width, self.height, {"exclude", self}) == 0 then 596 self.x, self.y, self.speedx, self.speedy, self.rotation = testx, testy, testspeedx, testspeedy, testrotation 597 else 598 self.speedy = -self.speedy*0.95 599 if math.abs(self.speedy) < 2 then 600 if self.speedy > 0 then 601 self.speedy = 2 602 else 603 self.speedy = -2 604 end 605 end 606 end 607 608 609 if (entryportalfacing == "down" and exitportalfacing == "up") or (entryportalfacing == "up" and exitportalfacing == "down") then 610 611 else 612 self.jumping = false 613 self.falling = true 614 end 615 616 if self.portaled then 617 self:portaled(exitportalfacing) 618 end 619 620 return true 621 end 622 end 623 end 624 return false 625end 626 627function checkportalVER(self, nextX) --handles vertical (left- and right facing) portal teleportation 628 for i, v in pairs(objects["player"]) do 629 if v.portal1X ~= false and v.portal2X ~= false then 630 local portal1yplus = 0 631 local portal2yplus = 0 632 local portal1X = v.portal1X 633 local portal2X = v.portal2X 634 635 --Get the extra block of each portal 636 if v.portal1facing == "right" then 637 portal1yplus = 1 638 elseif v.portal1facing == "left" then 639 portal1yplus = -1 640 portal1X = portal1X - 1 641 end 642 643 if v.portal2facing == "right" then 644 portal2yplus = 1 645 elseif v.portal2facing == "left" then 646 portal2yplus = -1 647 portal2X = portal2X - 1 648 end 649 650 if ((v.portal1Y == math.floor(self.y+1) or v.portal1Y+portal1yplus == math.floor(self.y+1)) and inrange(portal1X, self.x+self.width/2, nextX+self.width/2)) 651 or ((v.portal2Y == math.floor(self.y+1) or v.portal2Y+portal2yplus == math.floor(self.y+1)) and inrange(portal2X, self.x+self.width/2, nextX+self.width/2)) then 652 --check which portal is entry 653 local entryportalX, entryportalY, entryportalfacing 654 local exitportalX, exitportalY, exitportalfacing 655 local entryportalxplus, entryportalyplus, exitportalxplus, exitportalyplus 656 if (v.portal1Y == math.floor(self.y+1) or v.portal1Y+portal1yplus == math.floor(self.y+1)) and inrange(portal1X, self.x+self.width/2, nextX+self.width/2) then 657 entryportalX = v.portal1X 658 entryportalY = v.portal1Y 659 entryportalfacing = v.portal1facing 660 entryportalyplus = portal1yplus 661 662 exitportalX = v.portal2X 663 exitportalY = v.portal2Y 664 exitportalfacing = v.portal2facing 665 exitportalyplus = portal2yplus 666 else 667 entryportalX = v.portal2X 668 entryportalY = v.portal2Y 669 entryportalfacing = v.portal2facing 670 entryportalyplus = portal2yplus 671 672 exitportalX = v.portal1X 673 exitportalY = v.portal1Y 674 exitportalfacing = v.portal1facing 675 exitportalyplus = portal1yplus 676 end 677 678 --check if movement makes that portal even a possibility 679 if entryportalfacing == "right" then 680 if self.speedx > 0 then 681 return false 682 end 683 elseif entryportalfacing == "left" then 684 if self.speedx < 0 then 685 return false 686 end 687 end 688 689 if entryportalfacing == "up" or entryportalfacing == "down" then 690 return false 691 end 692 693 local testx, testy, testspeedx, testspeedy, testrotation = portalcoords(self.x, self.y, self.speedx, self.speedy, self.width, self.height, self.rotation, self.animationdirection, entryportalX, entryportalY, entryportalfacing, exitportalX, exitportalY, exitportalfacing, self, true) 694 695 if #checkrect(testx, testy, self.width, self.height, {"exclude", self}) == 0 then 696 self.x, self.y, self.speedx, self.speedy, self.rotation = testx, testy, testspeedx, testspeedy, testrotation 697 else 698 self.speedx = -self.speedx 699 end 700 701 self.jumping = false 702 self.falling = true 703 704 if self.portaled then 705 self:portaled(exitportalfacing) 706 end 707 708 return true 709 end 710 end 711 end 712 return false 713end 714 715function portalcoords(x, y, speedx, speedy, width, height, rotation, animationdirection, entryportalX, entryportalY, entryportalfacing, exitportalX, exitportalY, exitportalfacing, self, live) 716 --uuuuuuuuuuuuuh 717 --rewrite this so it takes the CENTER of shit and makes stuff according to that, also relative offsets 718 x = x + width/2 719 y = y + height/2 720 721 local directrange --vector orthogonal to portal vector T 722 local relativerange --vector symmetrical to portal vector = 723 724 if entryportalfacing == "up" then 725 directrange = entryportalY - y - 1 726 if width == 2 then 727 relativerange = 0 728 else 729 relativerange = ((x-width/2) - entryportalX + 1) / (2-width) 730 end 731 elseif entryportalfacing == "right" then 732 directrange = x - entryportalX 733 if height == 2 then 734 relativerange = 0 735 else 736 relativerange = ((y-height/2) - entryportalY + 1) / (2-height) 737 end 738 elseif entryportalfacing == "down" then 739 directrange = y - entryportalY 740 if width == 2 then 741 relativerange = 0 742 else 743 relativerange = ((x-width/2) - entryportalX + 2) / (2-width) 744 end 745 elseif entryportalfacing == "left" then 746 directrange = entryportalX - x - 1 747 if height == 2 then 748 relativerange = 0 749 else 750 relativerange = ((y-height/2) - entryportalY + 2) / (2-height) 751 end 752 end 753 754 if entryportalfacing == "up" and exitportalfacing == "up" then --up -> up 755 newx = x + (exitportalX - entryportalX) 756 newy = exitportalY + directrange - 1 757 speedy = -speedy 758 759 rotation = rotation - math.pi 760 761 if live then 762 local grav = yacceleration 763 if self and self.gravity then 764 grav = self.gravity 765 end 766 767 --keep it from bugging out by having a minimum exit speed 768 769 local minspeed = math.sqrt(2*grav*(height)) 770 771 if speedy > -minspeed then 772 speedy = -minspeed 773 end 774 end 775 elseif (entryportalfacing == "down" and exitportalfacing == "down") then --down -> down 776 newx = x + (exitportalX - entryportalX) 777 newy = exitportalY - directrange 778 speedy = -speedy 779 780 rotation = rotation - math.pi 781 782 elseif entryportalfacing == "up" and exitportalfacing == "right" then --up -> right 783 newy = exitportalY - relativerange*(2-height) - height/2 + 1 784 newx = exitportalX - directrange 785 786 speedx, speedy = speedy, -speedx 787 788 rotation = rotation - math.pi/2 789 790 elseif entryportalfacing == "up" and exitportalfacing == "left" then --up -> left 791 newy = exitportalY + relativerange*(2-height) + height/2 - 2 792 newx = exitportalX + directrange - 1 793 794 speedx, speedy = -speedy, speedx 795 796 rotation = rotation + math.pi/2 797 798 elseif (entryportalfacing == "up" and exitportalfacing == "down") then --up -> down 799 newx = x + (exitportalX - entryportalX) - 1 800 newy = exitportalY - directrange 801 802 803 --prevent low-fps bugs in a cheap way: 804 if entryportalY > exitportalY then 805 while newy+.5 + speedy*gdt > entryportalY do 806 newy = newy - 0.01 807 end 808 809 while newy+.5 < exitportalY do 810 newy = newy + 0.01 811 end 812 end 813 814 --prevent porting into block by limiting X, yo 815 if newx <= exitportalX - 2 + width/2 then 816 newx = exitportalX - 2 + width/2 817 elseif newx > exitportalX - width/2 then 818 newx = exitportalX - width/2 819 end 820 821 elseif (entryportalfacing == "down" and exitportalfacing == "up") then --down -> up 822 newx = x + (exitportalX - entryportalX) + 1 823 newy = exitportalY + directrange - 1 824 825 elseif (entryportalfacing == "down" and exitportalfacing == "left") then --down -> left 826 newy = exitportalY - relativerange*(2-height) - height/2 827 newx = exitportalX + directrange - 1 828 829 speedx, speedy = speedy, -speedx 830 831 rotation = rotation - math.pi/2 832 833 elseif (entryportalfacing == "down" and exitportalfacing == "right") then --down -> right 834 newy = exitportalY + relativerange*(2-height) + height/2 - 1 835 newx = exitportalX - directrange 836 837 speedx, speedy = -speedy, speedx 838 839 rotation = rotation + math.pi/2 840 841 --LEFT/RIGHT CODE! 842 elseif (entryportalfacing == "left" and exitportalfacing == "right") then --left -> right 843 newx = exitportalX - directrange 844 newy = y + (exitportalY - entryportalY)+1 845 elseif (entryportalfacing == "right" and exitportalfacing == "left") then --right -> left 846 newx = exitportalX + directrange - 1 847 newy = y + (exitportalY - entryportalY)-1 848 elseif (entryportalfacing == "right" and exitportalfacing == "right") then --right -> right 849 newx = exitportalX - directrange 850 newy = y + (exitportalY - entryportalY) 851 852 speedx = -speedx 853 if animationdirection == "left" then 854 animationdirection = "right" 855 elseif animationdirection == "right" then 856 animationdirection = "left" 857 end 858 859 elseif (entryportalfacing == "left" and exitportalfacing == "left") then --left -> left 860 newx = exitportalX + directrange - 1 861 newy = y + (exitportalY - entryportalY) 862 863 speedx = -speedx 864 if animationdirection == "left" then 865 animationdirection = "right" 866 elseif animationdirection == "right" then 867 animationdirection = "left" 868 end 869 870 elseif (entryportalfacing == "left" and exitportalfacing == "up") then --left -> up 871 newx = exitportalX + relativerange*(2-width) + width/2 - 1 872 newy = exitportalY + directrange - 1 873 874 speedx, speedy = speedy, -speedx 875 876 rotation = rotation - math.pi/2 877 878 if live then 879 --keep it from bugging out by having a minimum exit speed 880 local grav = yacceleration 881 if self and self.gravity then 882 grav = self.gravity 883 end 884 885 local minspeed = math.sqrt(2*grav*(height)) 886 887 if speedy > -minspeed then 888 speedy = -minspeed 889 end 890 end 891 892 elseif (entryportalfacing == "right" and exitportalfacing == "up") then --right -> up 893 newx = exitportalX - relativerange*(2-width) - width/2 + 1 894 newy = exitportalY + directrange - 1 895 896 speedx, speedy = -speedy, speedx 897 898 rotation = rotation + math.pi/2 899 900 if live then 901 --keep it from bugging out by having a minimum exit speed 902 local grav = yacceleration 903 if self and self.gravity then 904 grav = self.gravity 905 end 906 907 local minspeed = math.sqrt(2*grav*(height)) 908 909 if speedy > -minspeed then 910 speedy = -minspeed 911 end 912 end 913 914 elseif (entryportalfacing == "left" and exitportalfacing == "down") then --left -> down 915 newx = exitportalX - relativerange*(2-width) - width/2 916 newy = exitportalY - directrange 917 918 speedx, speedy = -speedy, speedx 919 920 rotation = rotation + math.pi/2 921 922 elseif (entryportalfacing == "right" and exitportalfacing == "down") then --right -> down 923 newx = exitportalX + relativerange*(2-width) + width/2 - 2 924 newy = exitportalY - directrange 925 926 speedx, speedy = speedy, -speedx 927 928 rotation = rotation - math.pi/2 929 end 930 931 newx = newx - width/2 932 newy = newy - height/2 933 934 return newx, newy, speedx, speedy, rotation, animationdirection 935end