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