1function game_load(suspended)
2	scrollfactor = 0
3	backgroundcolor = {}
4	backgroundcolor[1] = {92, 148, 252}
5	backgroundcolor[2] = {0, 0, 0}
6	backgroundcolor[3] = {32, 56, 236}
7	love.graphics.setBackgroundColor(backgroundcolor[1])
8
9	scrollingstart = 12 --when the scrolling begins to set in (Both of these take the player who is the farthest on the left)
10	scrollingcomplete = 10 --when the scrolling will be as fast as mario can run
11	scrollingleftstart = 6 --See above, but for scrolling left, and it takes the player on the right-estest.
12	scrollingleftcomplete = 4
13	superscroll = 100
14
15	--LINK STUFF
16
17	mariocoincount = 0
18	marioscore = 0
19
20	--get mariolives
21	mariolivecount = 3
22	if love.filesystem.exists("mappacks/" .. mappack .. "/settings.txt") then
23		local s = love.filesystem.read( "mappacks/" .. mappack .. "/settings.txt" )
24		local s1 = s:split("\n")
25		for j = 1, #s1 do
26			local s2 = s1[j]:split("=")
27			if s2[1] == "lives" then
28				mariolivecount = tonumber(s2[2])
29			end
30		end
31	end
32
33	if mariolivecount == 0 then
34		mariolivecount = false
35	end
36
37	mariolives = {}
38	for i = 1, players do
39		mariolives[i] = mariolivecount
40	end
41
42	mariosizes = {}
43	for i = 1, players do
44		mariosizes[i] = 1
45	end
46
47	autoscroll = true
48
49	inputs = { "door", "groundlight", "wallindicator", "cubedispenser", "walltimer", "notgate", "laser", "lightbridge"}
50	inputsi = {28, 29, 30, 43, 44, 45, 46, 47, 48, 67, 74, 84, 52, 53, 54, 55, 36, 37, 38, 39}
51
52	outputs = { "button", "laserdetector", "box", "pushbutton", "walltimer", "notgate"}
53	outputsi = {40, 56, 57, 58, 59, 20, 68, 69, 74, 84}
54
55	enemies = { "goomba", "koopa", "hammerbro", "plant", "lakito", "bowser", "cheep", "squid", "flyingfish", "goombahalf", "koopahalf", "cheepwhite", "cheepred", "koopared", "kooparedhalf", "koopa", "kooparedflying", "beetle", "beetlehalf", "spikey", "spikeyhalf"}
56
57	jumpitems = { "mushroom", "oneup" }
58
59	marioworld = 1
60	mariolevel = 1
61	mariosublevel = 0
62	respawnsublevel = 0
63
64	objects = nil
65	if suspended == true then
66		continuegame()
67	elseif suspended then
68		marioworld = suspended
69	end
70
71	--remove custom sprites
72	for i = smbtilecount+portaltilecount+1, #tilequads do
73		tilequads[i] = nil
74	end
75
76	for i = smbtilecount+portaltilecount+1, #rgblist do
77		rgblist[i] = nil
78	end
79
80	--add custom tiles
81	local bla = love.timer.getTime()
82	if love.filesystem.exists("mappacks/" .. mappack .. "/tiles.png") then
83		customtiles = true
84		customtilesimg = love.graphics.newImage("mappacks/" .. mappack .. "/tiles.png")
85		local imgwidth, imgheight = customtilesimg:getWidth(), customtilesimg:getHeight()
86		local width = math.floor(imgwidth/17)
87		local height = math.floor(imgheight/17)
88		local imgdata = love.image.newImageData("mappacks/" .. mappack .. "/tiles.png")
89
90		for y = 1, height do
91			for x = 1, width do
92				table.insert(tilequads, quad:new(customtilesimg, imgdata, x, y, imgwidth, imgheight))
93				local r, g, b = getaveragecolor(imgdata, x, y)
94				table.insert(rgblist, {r, g, b})
95			end
96		end
97		customtilecount = width*height
98	else
99		customtiles = false
100		customtilecount = 0
101	end
102	print("Custom tileset loaded in: " .. round(love.timer.getTime()-bla, 5))
103
104	smbspritebatch = {}
105	portalspritebatch = {}
106	customspritebatch = {}
107	spritebatchX = {}
108	for i = 1, players do
109		smbspritebatch[i] = love.graphics.newSpriteBatch( smbtilesimg, 1000 )
110		portalspritebatch[i] = love.graphics.newSpriteBatch( portaltilesimg, 1000 )
111		if customtiles then
112			customspritebatch[i] = love.graphics.newSpriteBatch( customtilesimg, 1000 )
113		end
114		spritebatchX[i] = 0
115	end
116
117	custommusic = false
118	if love.filesystem.exists("mappacks/" .. mappack .. "/music.ogg") then
119		custommusic = "mappacks/" .. mappack .. "/music.ogg"
120		music:load(custommusic)
121	elseif love.filesystem.exists("mappacks/" .. mappack .. "/music.mp3") then
122		custommusic = "mappacks/" .. mappack .. "/music.mp3"
123		music:load(custommusic)
124	end
125	print(custommusic)
126
127	--FINALLY LOAD THE DAMN LEVEL
128	levelscreen_load("initial")
129end
130
131function game_update(dt)
132
133	--------
134	--GAME--
135	--------
136
137	--earthquake reset
138	if earthquake > 0 then
139		earthquake = math.max(0, earthquake-dt*earthquake*2-0.001)
140		sunrot = sunrot + dt
141	end
142
143	--pausemenu
144	if pausemenuopen then
145		return
146	end
147
148	--coinanimation
149	coinanimation = coinanimation + dt*6.75
150	while coinanimation > 6 do
151		coinanimation = coinanimation - 5
152	end
153
154	if math.floor(coinanimation) == 4 then
155		coinframe = 2
156	elseif math.floor(coinanimation) == 5 then
157		coinframe = 1
158	else
159		coinframe = math.floor(coinanimation)
160	end
161
162	--SCROLLING SCORES
163	local delete = {}
164
165	for i, v in pairs(scrollingscores) do
166		if scrollingscores[i]:update(dt) == true then
167			table.insert(delete, i)
168		end
169	end
170
171	table.sort(delete, function(a,b) return a>b end)
172
173	for i, v in pairs(delete) do
174		table.remove(scrollingscores, v) --remove
175	end
176
177	--If everyone's dead, just update the players and coinblock timer.
178	if everyonedead then
179		for i, v in pairs(objects["player"]) do
180			v:update(dt)
181		end
182
183		return
184	end
185
186	--timer
187	if editormode == false then
188		--get if any player has their controls disabled
189		local notime = false
190		for i = 1, players do
191			if (objects["player"][i].controlsenabled == false and objects["player"][i].dead == false) then
192				notime = true
193			end
194		end
195
196		if notime == false and infinitetime == false and mariotime ~= 0 then
197			mariotime = mariotime - 2.5*dt
198
199			if mariotime > 0 and mariotime + 2.5*dt >= 99 and mariotime < 99 then
200				love.audio.stop()
201				playsound(lowtime)
202			end
203
204			if mariotime > 0 and mariotime + 2.5*dt >= 99-7.5 and mariotime < 99-7.5 then
205				local star = false
206				for i = 1, players do
207					if objects["player"][i].starred then
208						star = true
209					end
210				end
211
212				if not star then
213					playmusic()
214				else
215					music:play("starmusic")
216				end
217			end
218
219			if mariotime <= 0 then
220				mariotime = 0
221				for i, v in pairs(objects["player"]) do
222					v:die("time")
223				end
224			end
225		end
226	end
227
228	--check if updates are blocked for whatever reason
229	if noupdate then
230		for i, v in pairs(objects["player"]) do
231			v:update(dt)
232		end
233		return
234	end
235
236	--portalgundelay
237	for i = 1, players do
238		if portaldelay[i] > 0 then
239			portaldelay[i] = math.max(0, portaldelay[i] - dt/speed)
240		end
241	end
242
243	--coinblockanimation
244	local delete = {}
245
246	for i, v in pairs(coinblockanimations) do
247		if coinblockanimations[i]:update(dt) == true then
248			table.insert(delete, i)
249		end
250	end
251
252	table.sort(delete, function(a,b) return a>b end)
253
254	for i, v in pairs(delete) do
255		table.remove(coinblockanimations, v) --remove
256	end
257
258	--nothing to see here
259	local delete = {}
260
261	for i, v in pairs(rainbooms) do
262		if v:update(dt) == true then
263			table.insert(delete, i)
264		end
265	end
266
267	table.sort(delete, function(a,b) return a>b end)
268
269	for i, v in pairs(delete) do
270		table.remove(rainbooms, v) --remove
271	end
272
273	--userects
274	local delete = {}
275
276	for i, v in pairs(userects) do
277		if v.delete == true then
278			table.insert(delete, i)
279		end
280	end
281
282	table.sort(delete, function(a,b) return a>b end)
283
284	for i, v in pairs(delete) do
285		table.remove(userects, v) --remove
286	end
287
288	--blockbounce
289	local delete = {}
290
291	for i, v in pairs(blockbouncetimer) do
292		if blockbouncetimer[i] < blockbouncetime then
293			blockbouncetimer[i] = blockbouncetimer[i] + dt
294			if blockbouncetimer[i] > blockbouncetime then
295				blockbouncetimer[i] = blockbouncetime
296				if blockbouncecontent then
297					item(blockbouncecontent[i], blockbouncex[i], blockbouncey[i], blockbouncecontent2[i])
298				end
299				table.insert(delete, i)
300			end
301		end
302	end
303
304	table.sort(delete, function(a,b) return a>b end)
305
306	for i, v in pairs(delete) do
307		table.remove(blockbouncetimer, v)
308		table.remove(blockbouncex, v)
309		table.remove(blockbouncey, v)
310		table.remove(blockbouncecontent, v)
311		table.remove(blockbouncecontent2, v)
312	end
313
314	if #delete >= 1 then
315		generatespritebatch()
316	end
317
318	--coinblocktimer things
319	for i, v in pairs(coinblocktimers) do
320		if v[3] > 0 then
321			v[3] = v[3] - dt
322		end
323	end
324
325	--blockdebris
326	local delete = {}
327
328	for i, v in pairs(blockdebristable) do
329		if v:update(dt) == true then
330			table.insert(delete, i)
331		end
332	end
333
334	table.sort(delete, function(a,b) return a>b end)
335
336	for i, v in pairs(delete) do
337		table.remove(blockdebristable, v) --remove
338	end
339
340	--gelcannon
341	if objects["player"][mouseowner] and playertype == "gelcannon" and objects["player"][mouseowner].controlsenabled then
342		if gelcannontimer > 0 then
343			gelcannontimer = gelcannontimer - dt
344			if gelcannontimer < 0 then
345				gelcannontimer = 0
346			end
347		else
348			if love.mouse.isDown("l") then
349				gelcannontimer = gelcannondelay
350				objects["player"][mouseowner]:shootgel(1)
351			elseif love.mouse.isDown("r") then
352				gelcannontimer = gelcannondelay
353				objects["player"][mouseowner]:shootgel(2)
354			end
355		end
356	end
357
358	--seesaws
359	for i, v in pairs(seesaws) do
360		v:update(dt)
361	end
362
363	--platformspawners
364	for i, v in pairs(platformspawners) do
365		v:update(dt)
366	end
367
368	--Bubbles
369	local delete = {}
370
371	for i, v in pairs(bubbles) do
372		if v:update(dt) == true then
373			table.insert(delete, i)
374		end
375	end
376
377	table.sort(delete, function(a,b) return a>b end)
378
379	for i, v in pairs(delete) do
380		table.remove(bubbles, v) --remove
381	end
382
383	--Miniblocks
384	local delete = {}
385
386	for i, v in pairs(miniblocks) do
387		if v:update(dt) == true then
388			table.insert(delete, i)
389		end
390	end
391
392	table.sort(delete, function(a,b) return a>b end)
393
394	for i, v in pairs(delete) do
395		table.remove(miniblocks, v) --remove
396	end
397
398	--Fireworks
399	local delete = {}
400
401	for i, v in pairs(fireworks) do
402		if v:update(dt) == true then
403			table.insert(delete, i)
404		end
405	end
406
407	table.sort(delete, function(a,b) return a>b end)
408
409	for i, v in pairs(delete) do
410		table.remove(fireworks, v) --remove
411	end
412
413	--EMANCIPATION GRILLS
414	local delete = {}
415	for i, v in pairs(emancipationgrills) do
416		if v:update(dt) then
417			table.insert(delete, i)
418		end
419	end
420
421	table.sort(delete, function(a,b) return a>b end)
422
423	for i, v in pairs(delete) do
424		table.remove(emancipationgrills, v)
425	end
426
427	--BULLET BILL LAUNCHERS
428	local delete = {}
429	for i, v in pairs(rocketlaunchers) do
430		if v:update(dt) then
431			table.insert(delete, i)
432		end
433	end
434
435	table.sort(delete, function(a,b) return a>b end)
436
437	for i, v in pairs(delete) do
438		table.remove(rocketlaunchers, v)
439	end
440
441	--UPDATE OBJECTS
442	for i, v in pairs(objects) do
443		if i ~= "tile" and i ~= "portalwall" and i ~= "screenboundary" then
444			delete = {}
445
446			for j, w in pairs(v) do
447				if w.update and w:update(dt) then
448					table.insert(delete, j)
449				elseif w.autodelete then
450					if w.x < xscroll - width or w.y > 16 then
451						table.insert(delete,j)
452					end
453				end
454			end
455
456			if #delete > 0 then
457				table.sort(delete, function(a,b) return a>b end)
458
459				for j, w in pairs(delete) do
460					table.remove(v, w)
461				end
462			end
463		end
464	end
465
466	local oldscroll = splitxscroll[1]
467
468	if autoscroll and minimapdragging == false then
469		local splitwidth = width/#splitscreen
470		for split = 1, #splitscreen do
471			local oldscroll = splitxscroll[split]
472			--scrolling
473			--LEFT
474			local i = 1
475			while i <= players and objects["player"][i].dead do
476				i = i + 1
477			end
478			local fastestplayer = objects["player"][i]
479
480			if fastestplayer then
481				for i = 1, players do
482					if not objects["player"][i].dead and objects["player"][i].x > fastestplayer.x then
483						fastestplayer = objects["player"][i]
484					end
485				end
486
487				local oldscroll = splitxscroll[split]
488
489				if fastestplayer.x < splitxscroll[split] + scrollingleftstart and splitxscroll[split] > 0 then
490
491					if fastestplayer.x < splitxscroll[split] + scrollingleftstart and fastestplayer.speedx < 0 then
492						if fastestplayer.speedx < -scrollrate then
493							splitxscroll[split] = splitxscroll[split] - scrollrate*dt
494						else
495							splitxscroll[split] = splitxscroll[split] + fastestplayer.speedx*dt
496						end
497					end
498
499					if fastestplayer.x < splitxscroll[split] + scrollingleftcomplete then
500						if fastestplayer.x > splitxscroll[split] + scrollingleftcomplete - 1/16 then
501							splitxscroll[split] = splitxscroll[split] - scrollrate*dt
502						else
503							splitxscroll[split] = splitxscroll[split] - superscrollrate*dt
504						end
505					end
506
507					if splitxscroll[split] < 0 then
508						splitxscroll[split] = 0
509					end
510				end
511
512				--RIGHT
513
514				if fastestplayer.x > splitxscroll[split] + width - scrollingstart and splitxscroll[split] < mapwidth - width then
515					if fastestplayer.x > splitxscroll[split] + width - scrollingstart and fastestplayer.speedx > 0.3 then
516						if fastestplayer.speedx > scrollrate then
517							splitxscroll[split] = splitxscroll[split] + scrollrate*dt
518						else
519							splitxscroll[split] = splitxscroll[split] + fastestplayer.speedx*dt
520						end
521					end
522
523					if fastestplayer.x > splitxscroll[split] + width - scrollingcomplete then
524						if fastestplayer.x > splitxscroll[split] + width - scrollingcomplete then
525							splitxscroll[split] = splitxscroll[split] + scrollrate*dt
526							if splitxscroll[split] > fastestplayer.x - (width - scrollingcomplete) then
527								splitxscroll[split] = fastestplayer.x - (width - scrollingcomplete)
528							end
529						else
530							splitxscroll[split] = fastestplayer.x - (width - scrollingcomplete)
531						end
532					end
533				end
534
535				--just force that shit
536				if not levelfinished then
537					if fastestplayer.x > splitxscroll[split] + width - scrollingcomplete then
538						splitxscroll[split] = splitxscroll[split] + superscroll*dt
539						if fastestplayer.x < splitxscroll[split] + width - scrollingcomplete then
540							splitxscroll[split] = fastestplayer.x - width + scrollingcomplete
541						end
542						--splitxscroll[split] = fastestplayer.x + width - scrollingcomplete - width
543					end
544				end
545
546				if splitxscroll[split] > mapwidth-width then
547					splitxscroll[split] = math.max(0, mapwidth-width)
548					hitrightside()
549				end
550
551				if (axex and splitxscroll[split] > axex-width and axex >= width) then
552					splitxscroll[split] = axex-width
553					hitrightside()
554				end
555			end
556		end
557
558	end
559
560	if players == 2 then
561		--updatesplitscreen()
562	end
563
564	--SPRITEBATCH UPDATE and CASTLEREPEATS
565	if math.floor(splitxscroll[1]) ~= spritebatchX[1] then
566		if not editormode then
567			for currentx = lastrepeat+1, math.floor(splitxscroll[1])+2 do
568				lastrepeat = math.floor(currentx)
569				--castlerepeat?
570				--get mazei
571				local mazei = 0
572
573				for j = 1, #mazeends do
574					if mazeends[j] < currentx+width then
575						mazei = j
576					end
577				end
578
579				--check if maze was solved!
580				for i = 1, players do
581					if objects["player"][i].mazevar == mazegates[mazei] then
582						local actualmaze = 0
583						for j = 1, #mazestarts do
584							if objects["player"][i].x > mazestarts[j] then
585								actualmaze = j
586							end
587						end
588						mazesolved[actualmaze] = true
589						for j = 1, players do
590							objects["player"][j].mazevar = 0
591						end
592						break
593					end
594				end
595
596				if not mazesolved[mazei] or mazeinprogress then --get if inside maze
597					if not mazesolved[mazei] then
598						mazeinprogress = true
599					end
600
601					local x = math.ceil(currentx)+width
602
603					if repeatX == 0 then
604						repeatX = mazestarts[mazei]
605					end
606
607					table.insert(map, x, {{1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}})
608					for y = 1, 15 do
609						for j = 1, #map[repeatX][y] do
610							map[x][y][j] = map[repeatX][y][j]
611						end
612						map[x][y]["gels"] = {}
613
614						for cox = mapwidth, x, -1 do
615							--move objects
616							if objects["tile"][cox .. "-" .. y] then
617								objects["tile"][cox + 1 .. "-" .. y] = tile:new(cox, y-1, 1, 1, true)
618								objects["tile"][cox .. "-" .. y] = nil
619							end
620						end
621
622						--create object for block
623						if tilequads[map[repeatX][y][1]].collision == true then
624							objects["tile"][x .. "-" .. y] = tile:new(x-1, y-1, 1, 1, true)
625						end
626					end
627					mapwidth = mapwidth + 1
628					repeatX = repeatX + 1
629					if flagx then
630						flagx = flagx + 1
631						flagimgx = flagimgx + 1
632						objects["screenboundary"]["flag"].x = objects["screenboundary"]["flag"].x + 1
633					end
634
635					if axex then
636						axex = axex + 1
637						objects["screenboundary"]["axe"].x = objects["screenboundary"]["axe"].x + 1
638					end
639
640					if firestartx then
641						firestartx = firestartx + 1
642					end
643
644					objects["screenboundary"]["right"].x = objects["screenboundary"]["right"].x + 1
645
646					--move mazestarts and ends
647					for i = 1, #mazestarts do
648						mazestarts[i] = mazestarts[i]+1
649						mazeends[i] = mazeends[i]+1
650					end
651
652					--check for endblock
653					local x = math.ceil(currentx)+width
654					for y = 1, 15 do
655						if map[x][y][2] and entityquads[map[x][y][2]].t == "mazeend" then
656							if mazesolved[mazei] then
657								repeatX = mazestarts[mazei+1]
658							end
659							mazeinprogress = false
660						end
661					end
662
663					--reset thingie
664
665					local x = math.ceil(currentx)+width-1
666					for y = 1, 15 do
667						if map[x][y][2] and entityquads[map[x][y][2]].t == "mazeend" then
668							for j = 1, players do
669								objects["player"][j].mazevar = 0
670							end
671						end
672					end
673				end
674			end
675		end
676
677		generatespritebatch()
678		spritebatchX[1] = math.floor(splitxscroll[1])
679
680		if editormode == false and splitxscroll[1] < mapwidth-width then
681			for x = math.ceil(oldscroll)+width+1, math.floor(splitxscroll[1])+width+1 do
682				for y = 1, 15 do
683					spawnenemy(x, y)
684				end
685				if goombaattack then
686					local randomtable = {}
687					for y = 1, 15 do
688						table.insert(randomtable, y)
689					end
690					while #randomtable > 0 do
691						local rand = math.random(#randomtable)
692						if tilequads[map[x][randomtable[rand]][1]].collision then
693							table.remove(randomtable, rand)
694						else
695							table.insert(objects["goomba"], goomba:new(x-.5, math.random(13)))
696							break
697						end
698					end
699				end
700			end
701		end
702	end
703
704	--portal animation
705	portalanimationtimer = portalanimationtimer + dt
706	while portalanimationtimer > portalanimationdelay do
707		portalanimationtimer = 0
708		portalanimation = portalanimation + 1
709		if portalanimation > portalanimationcount then
710			portalanimation = 1
711		end
712	end
713
714	--portal particles
715	portalparticletimer = portalparticletimer + dt
716	while portalparticletimer > portalparticletime do
717		portalparticletimer = portalparticletimer - portalparticletime
718
719		for i, v in pairs(objects["player"]) do
720			if v.portal1facing ~= nil then
721				local x1, y1
722
723				if v.portal1facing == "up" then
724					x1 = v.portal1X + math.random(1, 30)/16 -1
725					y1 = v.portal1Y-1
726				elseif v.portal1facing == "down" then
727					x1 = v.portal1X + math.random(1, 30)/16-2
728					y1 = v.portal1Y
729				elseif v.portal1facing == "left" then
730					x1 = v.portal1X-1
731					y1 = v.portal1Y + math.random(1, 30)/16-2
732				elseif v.portal1facing == "right" then
733					x1 = v.portal1X
734					y1 = v.portal1Y + math.random(1, 30)/16-1
735				end
736
737				local color
738				if players == 1 then
739					color = {157, 222, 254}
740				else
741					color = v.portal1color
742				end
743
744				table.insert(portalparticles, portalparticle:new(x1, y1, color, v.portal1facing))
745			end
746
747			if v.portal2facing ~= nil then
748				local x2, y2
749
750				if v.portal2facing == "up" then
751					x2 = v.portal2X + math.random(1, 30)/16 -1
752					y2 = v.portal2Y-1
753				elseif v.portal2facing == "down" then
754					x2 = v.portal2X + math.random(1, 30)/16-2
755					y2 = v.portal2Y
756				elseif v.portal2facing == "left" then
757					x2 = v.portal2X-1
758					y2 = v.portal2Y + math.random(1, 30)/16-2
759				elseif v.portal2facing == "right" then
760					x2 = v.portal2X
761					y2 = v.portal2Y + math.random(1, 30)/16-1
762				end
763
764				local color
765				if players == 1 then
766					color = {255, 122, 66}
767				else
768					color = v.portal2color
769				end
770
771				table.insert(portalparticles, portalparticle:new(x2, y2, color, v.portal2facing))
772			end
773		end
774	end
775
776	delete = {}
777
778	for i, v in pairs(portalparticles) do
779		if v:update(dt) == true then
780			table.insert(delete, i)
781		end
782	end
783
784	table.sort(delete, function(a,b) return a>b end)
785
786	for i, v in pairs(delete) do
787		table.remove(portalparticles, v) --remove
788	end
789
790	--PORTAL PROJECTILES
791	delete = {}
792
793	for i, v in pairs(portalprojectiles) do
794		if v:update(dt) == true then
795			table.insert(delete, i)
796		end
797	end
798
799	table.sort(delete, function(a,b) return a>b end)
800
801	for i, v in pairs(delete) do
802		table.remove(portalprojectiles, v) --remove
803	end
804
805	--FIRE SPAWNING
806	if not levelfinished and firestarted and (not objects["bowser"][1] or (objects["bowser"][1].backwards == false and objects["bowser"][1].shot == false and objects["bowser"][1].fall == false)) then
807		firetimer = firetimer + dt
808		while firetimer > firedelay do
809			firetimer = firetimer - firedelay
810			firedelay = math.random(4)
811			table.insert(objects["fire"], fire:new(splitxscroll[1] + width, math.random(3)+7))
812		end
813	end
814
815	--FLYING FISH
816	if not levelfinished and flyingfishstarted then
817		flyingfishtimer = flyingfishtimer + dt
818		while flyingfishtimer > flyingfishdelay do
819			flyingfishtimer = flyingfishtimer - flyingfishdelay
820			flyingfishdelay = math.random(6, 20)/10
821			table.insert(objects["flyingfish"], flyingfish:new())
822		end
823	end
824
825	--BULLET BILL
826	if not levelfinished and bulletbillstarted then
827		bulletbilltimer = bulletbilltimer + dt
828		while bulletbilltimer > bulletbilldelay do
829			bulletbilltimer = bulletbilltimer - bulletbilldelay
830			bulletbilldelay = math.random(5, 40)/10
831			table.insert(objects["bulletbill"], bulletbill:new(splitxscroll[1]+width+2, math.random(4, 12), "left"))
832		end
833	end
834
835	--minecraft stuff
836	if breakingblockX then
837		breakingblockprogress = breakingblockprogress + dt
838		if breakingblockprogress > minecraftbreaktime then
839			breakblock(breakingblockX, breakingblockY)
840			breakingblockX = nil
841		end
842	end
843
844	--Editor
845	if editormode then
846		editor_update(dt)
847	end
848
849	--PHYSICS
850	physicsupdate(dt)
851end
852
853function game_draw()
854	for split = 1, #splitscreen do
855		love.graphics.translate((split-1)*width*16*scale/#splitscreen, yoffset*scale)
856
857		--This is just silly
858		if earthquake > 0 then
859			local colortable = {{242, 111, 51}, {251, 244, 174}, {95, 186, 76}, {29, 151, 212}, {101, 45, 135}, {238, 64, 68}}
860			for i = 1, backgroundstripes do
861				local r, g, b = unpack(colortable[math.mod(i-1, 6)+1])
862				local a = earthquake/rainboomearthquake*255
863
864				love.graphics.setColor(r, g, b, a)
865
866				local alpha = math.rad((i/backgroundstripes + math.mod(sunrot/5, 1)) * 360)
867				local point1 = {width*8*scale+300*scale*math.cos(alpha), 112*scale+300*scale*math.sin(alpha)}
868
869				local alpha = math.rad(((i+1)/backgroundstripes + math.mod(sunrot/5, 1)) * 360)
870				local point2 = {width*8*scale+300*scale*math.cos(alpha), 112*scale+300*scale*math.sin(alpha)}
871
872				love.graphics.polygon("fill", width*8*scale, 112*scale, point1[1], point1[2], point2[1], point2[2])
873			end
874		end
875
876		love.graphics.setColor(255, 255, 255, 255)
877		--tremoooor!
878		if earthquake > 0 then
879			tremorx = (math.random()-.5)*2*earthquake
880			tremory = (math.random()-.5)*2*earthquake
881
882			love.graphics.translate(round(tremorx), round(tremory))
883		end
884
885		local currentscissor = {(split-1)*width*16*scale/#splitscreen, 0, width*16*scale/#splitscreen, 15*16*scale}
886		love.graphics.setScissor(unpack(currentscissor))
887		xscroll = splitxscroll[split]
888
889		love.graphics.setColor(255, 255, 255, 255)
890
891		local xtodraw
892		if mapwidth < width+1 then
893			xtodraw = math.ceil(mapwidth/#splitscreen)
894		else
895			if mapwidth > width and xscroll < mapwidth-width then
896				xtodraw = width+1
897			else
898				xtodraw = width
899			end
900		end
901
902		--custom background
903		if custombackground then
904			for i = #custombackgroundimg, 1, -1  do
905				local xscroll = xscroll / (i * scrollfactor + 1)
906				if reversescrollfactor() == 1 then
907					xscroll = 0
908				end
909				for y = 1, math.ceil(15/custombackgroundheight[i]) do
910					for x = 1, math.ceil(width/custombackgroundwidth[i])+1 do
911						love.graphics.draw(custombackgroundimg[i], math.floor(((x-1)*custombackgroundwidth[i])*16*scale) - math.floor(math.mod(xscroll, custombackgroundwidth[i])*16*scale), (y-1)*custombackgroundheight[i]*16*scale, 0, scale, scale)
912					end
913				end
914			end
915		end
916
917		--Mushroom under tiles
918		for j, w in pairs(objects["mushroom"]) do
919			w:draw()
920		end
921
922		--Flowers under tiles
923		for j, w in pairs(objects["flower"]) do
924			w:draw()
925		end
926
927		--Oneupunder tiles
928		for j, w in pairs(objects["oneup"]) do
929			w:draw()
930		end
931
932		--star tiles
933		for j, w in pairs(objects["star"]) do
934			w:draw()
935		end
936
937		--castleflag
938		if levelfinished and levelfinishtype == "flag" and not custombackground then
939			love.graphics.draw(castleflagimg, math.floor((flagx+6-xscroll)*16*scale), 106*scale+castleflagy*16*scale, 0, scale, scale)
940		end
941
942		--TILES
943		love.graphics.draw(smbspritebatch[split], math.floor(-math.mod(xscroll, 1)*16*scale), 0)
944		love.graphics.draw(portalspritebatch[split], math.floor(-math.mod(xscroll, 1)*16*scale), 0)
945		if customtiles then
946			love.graphics.draw(customspritebatch[split], math.floor(-math.mod(xscroll, 1)*16*scale), 0)
947		end
948
949		local lmap = map
950
951		for y = 1, 15 do
952			for x = 1, xtodraw do
953				local bounceyoffset = 0
954				for i, v in pairs(blockbouncex) do
955					if blockbouncex[i] == math.floor(xscroll)+x and blockbouncey[i] == y then
956						if blockbouncetimer[i] < blockbouncetime/2 then
957							bounceyoffset = blockbouncetimer[i] / (blockbouncetime/2) * blockbounceheight
958						else
959							bounceyoffset = (2 - blockbouncetimer[i] / (blockbouncetime/2)) * blockbounceheight
960						end
961					end
962				end
963
964				local t = lmap[math.floor(xscroll)+x][y]
965
966				local tilenumber = t[1]
967				if tilequads[tilenumber].coinblock and tilequads[tilenumber].invisible == false then --coinblock
968					love.graphics.drawq(coinblockimage, coinblockquads[spriteset][coinframe], math.floor((x-1-math.mod(xscroll, 1))*16*scale), ((y-1-bounceyoffset)*16-8)*scale, 0, scale, scale)
969				elseif tilequads[tilenumber].coin then --coin
970					love.graphics.drawq(coinimage, coinquads[spriteset][coinframe], math.floor((x-1-math.mod(xscroll, 1))*16*scale), ((y-1-bounceyoffset)*16-8)*scale, 0, scale, scale)
971				elseif bounceyoffset ~= 0 then
972					if tilequads[tilenumber].invisible == false or editormode then
973						love.graphics.drawq(tilequads[tilenumber].image, tilequads[tilenumber].quad, math.floor((x-1-math.mod(xscroll, 1))*16*scale), ((y-1-bounceyoffset)*16-8)*scale, 0, scale, scale)
974					end
975				end
976
977				--Gel overlays!
978				if t["gels"] then
979					for i = 1, 4 do
980						local dir = "top"
981						local r = 0
982						if i == 2 then
983							dir = "right"
984							r = math.pi/2
985						elseif i == 3 then
986							dir = "bottom"
987							r = math.pi
988						elseif i == 4 then
989							dir = "left"
990							r = math.pi*1.5
991						end
992
993						if t["gels"][dir] == 1 then
994							love.graphics.draw(gel1ground, math.floor((x-.5-math.mod(xscroll, 1))*16*scale), ((y-1-bounceyoffset)*16)*scale, r, scale, scale, 8, 8)
995						elseif t["gels"][dir] == 2 then
996							love.graphics.draw(gel2ground, math.floor((x-.5-math.mod(xscroll, 1))*16*scale), ((y-1-bounceyoffset)*16)*scale, r, scale, scale, 8, 8)
997						elseif t["gels"][dir] == 3 then
998							love.graphics.draw(gel3ground, math.floor((x-.5-math.mod(xscroll, 1))*16*scale), ((y-1-bounceyoffset)*16)*scale, r, scale, scale, 8, 8)
999						end
1000					end
1001				end
1002
1003				if editormode then
1004					if tilequads[t[1]].invisible and t[1] ~= 1 then
1005						love.graphics.drawq(tilequads[t[1]].image, tilequads[t[1]].quad, math.floor((x-1-math.mod(xscroll, 1))*16*scale), ((y-1)*16-8)*scale, 0, scale, scale)
1006					end
1007
1008					if #t > 1 and t[2] ~= "link" then
1009						tilenumber = t[2]
1010						love.graphics.setColor(255, 255, 255, 150)
1011						love.graphics.drawq(entityquads[tilenumber].image, entityquads[tilenumber].quad, math.floor((x-1-math.mod(xscroll, 1))*16*scale), ((y-1)*16-8)*scale, 0, scale, scale)
1012						love.graphics.setColor(255, 255, 255, 255)
1013					end
1014				end
1015			end
1016		end
1017
1018		---UI
1019		love.graphics.setColor(255, 255, 255)
1020		love.graphics.translate(0, -yoffset*scale)
1021		if yoffset < 0 then
1022			love.graphics.translate(0, yoffset*scale)
1023		end
1024
1025		properprint("mario", uispace*.5 - 24*scale, 8*scale)
1026		properprint(addzeros(marioscore, 6), uispace*0.5-24*scale, 16*scale)
1027
1028		properprint("*", uispace*1.5-8*scale, 16*scale)
1029
1030		love.graphics.drawq(coinanimationimage, coinanimationquads[spriteset][coinframe], uispace*1.5-16*scale, 16*scale, 0, scale, scale)
1031		properprint(addzeros(mariocoincount, 2), uispace*1.5-0*scale, 16*scale)
1032
1033		properprint("world", uispace*2.5 - 20*scale, 8*scale)
1034		properprint(marioworld .. "-" .. mariolevel, uispace*2.5 - 12*scale, 16*scale)
1035
1036		properprint("time", uispace*3.5 - 16*scale, 8*scale)
1037		if editormode then
1038			if linktool then
1039				properprint("link", uispace*3.5 - 16*scale, 16*scale)
1040			else
1041				properprint("edit", uispace*3.5 - 16*scale, 16*scale)
1042			end
1043		else
1044			properprint(addzeros(math.ceil(mariotime), 3), uispace*3.5-8*scale, 16*scale)
1045		end
1046
1047		if players > 1 then
1048			for i = 1, players do
1049				local x = (width*16)/players/2 + (width*16)/players*(i-1)
1050				if mariolivecount ~= false then
1051					properprint("p" .. i .. " * " .. mariolives[i], (x-string.len("p" .. i .. " * " .. mariolives[i])*4+4)*scale, 25*scale)
1052					love.graphics.setColor(mariocolors[i][1])
1053					love.graphics.rectangle("fill", (x-string.len("p" .. i .. " * " .. mariolives[i])*4-3)*scale, 25*scale, 7*scale, 7*scale)
1054					love.graphics.setColor(255, 255, 255, 255)
1055				end
1056			end
1057		end
1058
1059		love.graphics.setColor(255, 255, 255)
1060		--vines
1061		for j, w in pairs(objects["vine"]) do
1062			w:draw()
1063		end
1064
1065		love.graphics.setColor(255, 255, 255)
1066		--warpzonetext
1067		if displaywarpzonetext then
1068			properprint("welcome to warp zone!", (mapwidth-14-1/16-xscroll)*16*scale, 88*scale)
1069			for i, v in pairs(warpzonenumbers) do
1070				properprint(v[3], math.floor((v[1]-xscroll-1-9/16)*16*scale), (v[2]-3)*16*scale)
1071			end
1072		end
1073
1074		love.graphics.setColor(255, 255, 255)
1075		--platforms
1076		for j, w in pairs(objects["platform"]) do
1077			w:draw()
1078		end
1079
1080		love.graphics.setColor(255, 255, 255)
1081		--platforms
1082		for j, w in pairs(objects["seesawplatform"]) do
1083			w:draw()
1084		end
1085
1086		love.graphics.setColor(255, 255, 255)
1087		--seesaws
1088		for j, w in pairs(seesaws) do
1089			w:draw()
1090		end
1091
1092		love.graphics.setColor(255, 255, 255)
1093		--springs
1094		for j, w in pairs(objects["spring"]) do
1095			w:draw()
1096		end
1097
1098		love.graphics.setColor(255, 255, 255)
1099		--flag
1100		if flagx then
1101			love.graphics.draw(flagimg, math.floor((flagimgx-1-xscroll)*16*scale), ((flagimgy)*16-8)*scale, 0, scale, scale)
1102			if levelfinishtype == "flag" then
1103				properprint2(flagscore, math.floor((flagimgx+4/16-xscroll)*16*scale), ((14-flagimgy)*16-8)*scale, 0, scale, scale)
1104			end
1105		end
1106
1107		love.graphics.setColor(255, 255, 255)
1108		--axe
1109		if axex then
1110			love.graphics.drawq(axeimg, axequads[coinframe], math.floor((axex-1-xscroll)*16*scale), (axey-1.5)*16*scale, 0, scale, scale)
1111
1112			if marioworld ~= 8 then
1113				love.graphics.draw(toadimg, math.floor((mapwidth-7-xscroll)*16*scale), 177*scale, 0, scale, scale)
1114			else
1115				love.graphics.draw(peachimg, math.floor((mapwidth-7-xscroll)*16*scale), 177*scale, 0, scale, scale)
1116			end
1117		end
1118
1119		love.graphics.setColor(255, 255, 255)
1120		--levelfinish text and toad
1121		if levelfinished and levelfinishtype == "castle" then
1122			if levelfinishedmisc2 == 1 then
1123				if levelfinishedmisc >= 1 then
1124					properprint("thank you mario!", math.floor(((mapwidth-12-xscroll)*16-1)*scale), 72*scale)
1125				end
1126				if levelfinishedmisc == 2 then
1127					properprint("but our princess is in", math.floor(((mapwidth-13.5-xscroll)*16-1)*scale), 104*scale) --say what
1128					properprint("another castle!", math.floor(((mapwidth-13.5-xscroll)*16-1)*scale), 120*scale) --bummer.
1129				end
1130			else
1131				if levelfinishedmisc >= 1 then
1132					properprint("thank you mario!", math.floor(((mapwidth-12-xscroll)*16-1)*scale), 72*scale)
1133				end
1134				if levelfinishedmisc >= 2 then
1135					properprint("your quest is over.", math.floor(((mapwidth-12.5-xscroll)*16-1)*scale), 96*scale)
1136				end
1137				if levelfinishedmisc >= 3 then
1138					properprint("we present you a new quest.", math.floor(((mapwidth-14.5-xscroll)*16-1)*scale), 112*scale)
1139				end
1140				if levelfinishedmisc >= 4 then
1141					properprint("push button b", math.floor(((mapwidth-11-xscroll)*16-1)*scale), 136*scale)
1142				end
1143				if levelfinishedmisc == 5 then
1144					properprint("to play as steve", math.floor(((mapwidth-12-xscroll)*16-1)*scale), 152*scale)
1145				end
1146			end
1147
1148			if marioworld ~= 8 then
1149				love.graphics.draw(toadimg, math.floor((mapwidth-7-xscroll)*16*scale), 177*scale, 0, scale, scale)
1150			else
1151				love.graphics.draw(peachimg, math.floor((mapwidth-7-xscroll)*16*scale), 177*scale, 0, scale, scale)
1152			end
1153		end
1154
1155		love.graphics.setColor(255, 255, 255)
1156		--Fireworks
1157		for j, w in pairs(fireworks) do
1158			w:draw()
1159		end
1160
1161		love.graphics.setColor(255, 255, 255)
1162		--Buttons
1163		for j, w in pairs(objects["button"]) do
1164			w:draw()
1165		end
1166
1167		love.graphics.setColor(255, 255, 255)
1168		--Upfires
1169		for j, w in pairs(objects["upfire"]) do
1170			w:draw()
1171		end
1172
1173		love.graphics.setColor(255, 255, 255)
1174		--Pushbuttons
1175		for j, w in pairs(objects["pushbutton"]) do
1176			w:draw()
1177		end
1178
1179		love.graphics.setColor(255, 255, 255)
1180		--hardlight bridges
1181		for j, w in pairs(objects["lightbridgebody"]) do
1182			w:draw()
1183		end
1184
1185		love.graphics.setColor(255, 255, 255)
1186		--laser
1187		for j, w in pairs(objects["laser"]) do
1188			w:draw()
1189		end
1190
1191		love.graphics.setColor(255, 255, 255)
1192		--laserdetector
1193		for j, w in pairs(objects["laserdetector"]) do
1194			w:draw()
1195		end
1196
1197		love.graphics.setColor(255, 255, 255)
1198		--lightbridge
1199
1200		for j, w in pairs(objects["lightbridge"]) do
1201			w:draw()
1202		end
1203
1204		love.graphics.setColor(255, 255, 255)
1205		--Groundlights
1206		for j, w in pairs(objects["groundlight"]) do
1207			w:draw()
1208		end
1209
1210		love.graphics.setColor(255, 255, 255)
1211		--Faithplates
1212		for j, w in pairs(objects["faithplate"]) do
1213			w:draw()
1214		end
1215
1216		love.graphics.setColor(255, 255, 255)
1217		--Bubbles
1218		for j, w in pairs(bubbles) do
1219			w:draw()
1220		end
1221
1222		love.graphics.setColor(255, 255, 255)
1223		--miniblocks
1224		for i, v in pairs(miniblocks) do
1225			v:draw()
1226		end
1227
1228		--OBJECTS
1229		for j, w in pairs(objects) do
1230			if j ~= "tile" then
1231				for i, v in pairs(w) do
1232					if v.drawable then
1233						love.graphics.setColor(255, 255, 255)
1234						local dirscale
1235
1236						if j == "player" then
1237							if v.pointingangle > 0 then
1238								dirscale = -scale
1239							else
1240								dirscale = scale
1241							end
1242							if bigmario then
1243								dirscale = dirscale * scalefactor
1244							end
1245						else
1246							if v.animationdirection == "left" then
1247								dirscale = -scale
1248							else
1249								dirscale = scale
1250							end
1251						end
1252
1253						local horscale = scale
1254						if v.shot then
1255							horscale = -scale
1256						end
1257
1258						if j == "player" and bigmario then
1259							horscale = horscale * scalefactor
1260						end
1261
1262						local ply, portaly = insideportal(v.x, v.y, v.width, v.height)
1263						local entryX, entryY, entryfacing, exitX, exitY, exitfacing
1264
1265						--SCISSOR FOR ENTRY
1266						if v.static then
1267							if v.customscissor then
1268								love.graphics.setScissor(math.floor((v.customscissor[1]-xscroll)*16*scale), math.floor((v.customscissor[2]-.5)*16*scale), v.customscissor[3]*16*scale, v.customscissor[4]*16*scale)
1269							end
1270						end
1271
1272						if v.static == false and v.portalable ~= false then
1273							if v.customscissor then
1274								love.graphics.setScissor(math.floor((v.customscissor[1]-xscroll)*16*scale), math.floor((v.customscissor[2]-.5)*16*scale), v.customscissor[3]*16*scale, v.customscissor[4]*16*scale)
1275							elseif ply ~= false and (v.active or v.portaloverride) then
1276								if portaly == 1 then
1277									entryX, entryY, entryfacing = objects["player"][ply].portal1X, objects["player"][ply].portal1Y, objects["player"][ply].portal1facing
1278									exitX, exitY, exitfacing = objects["player"][ply].portal2X, objects["player"][ply].portal2Y, objects["player"][ply].portal2facing
1279								else
1280									entryX, entryY, entryfacing = objects["player"][ply].portal2X, objects["player"][ply].portal2Y, objects["player"][ply].portal2facing
1281									exitX, exitY, exitfacing = objects["player"][ply].portal1X, objects["player"][ply].portal1Y, objects["player"][ply].portal1facing
1282								end
1283
1284								if entryfacing == "right" then
1285									love.graphics.setScissor(math.floor((entryX-xscroll)*16*scale), math.floor(((entryY-3.5)*16)*scale), 64*scale, 96*scale)
1286								elseif entryfacing == "left" then
1287									love.graphics.setScissor(math.floor((entryX-xscroll-5)*16*scale), math.floor(((entryY-4.5)*16)*scale), 64*scale, 96*scale)
1288								elseif entryfacing == "up" then
1289									love.graphics.setScissor(math.floor((entryX-xscroll-3)*16*scale), math.floor(((entryY-5.5)*16)*scale), 96*scale, 64*scale)
1290								elseif entryfacing == "down" then
1291									love.graphics.setScissor(math.floor((entryX-xscroll-4)*16*scale), math.floor(((entryY-0.5)*16)*scale), 96*scale, 64*scale)
1292								end
1293							end
1294						end
1295
1296						if type(v.graphic) == "table" then
1297							for k = 1, #v.graphic do
1298								if v.colors[k] then
1299									love.graphics.setColor(v.colors[k])
1300								else
1301									love.graphics.setColor(255, 255, 255)
1302								end
1303								love.graphics.drawq(v.graphic[k], v.quad, math.floor(((v.x-xscroll)*16+v.offsetX)*scale), math.floor((v.y*16-v.offsetY)*scale), v.rotation, dirscale, horscale, v.quadcenterX, v.quadcenterY)
1304							end
1305
1306							if v.drawhat and hatoffsets[v.animationstate] then
1307								local offsets = {}
1308								if v.graphic == v.biggraphic or v.animationstate == "grow" then
1309									if v.animationstate == "grow" then
1310										offsets = hatoffsets["grow"]
1311									elseif v.fireanimationtimer < fireanimationtime then
1312										offsets = bighatoffsets["fire"]
1313									elseif underwater and (v.animationstate == "jumping" or v.animationstate == "falling") then
1314										offsets = bighatoffsets["swimming"][v.swimframe]
1315									elseif v.ducking then
1316										offsets = bighatoffsets["ducking"]
1317									elseif v.animationstate == "running" or v.animationstate == "falling"  then
1318										offsets = bighatoffsets["running"][v.runframe]
1319									elseif v.animationstate == "climbing" then
1320										offsets = bighatoffsets["climbing"][v.climbframe]
1321									else
1322										offsets = bighatoffsets[v.animationstate]
1323									end
1324								else
1325									if underwater and (v.animationstate == "jumping" or v.animationstate == "falling") then
1326										offsets = hatoffsets["swimming"][v.swimframe]
1327									elseif v.animationstate == "running" or v.animationstate == "falling"  then
1328										offsets = hatoffsets["running"][v.runframe]
1329									elseif v.animationstate == "climbing" then
1330										offsets = hatoffsets["climbing"][v.climbframe]
1331									else
1332										offsets = hatoffsets[v.animationstate]
1333									end
1334								end
1335
1336								if #v.hats > 0 then
1337									local yadd = 0
1338									for i = 1, #v.hats do
1339										if v.hats[i] == 1 then
1340											love.graphics.setColor(v.colors[1])
1341										else
1342											love.graphics.setColor(255, 255, 255)
1343										end
1344										if v.graphic == v.biggraphic or v.animationstate == "grow" then
1345											love.graphics.draw(bighat[v.hats[i]].graphic, math.floor(((v.x-xscroll)*16+v.offsetX)*scale), math.floor(((v.y)*16-v.offsetY)*scale), v.rotation, dirscale, horscale, v.quadcenterX - bighat[v.hats[i]].x + offsets[1], v.quadcenterY - bighat[v.hats[i]].y + offsets[2] + yadd)
1346											yadd = yadd + bighat[v.hats[i]].height
1347										else
1348											love.graphics.draw(hat[v.hats[i]].graphic, math.floor(((v.x-xscroll)*16+v.offsetX)*scale), math.floor(((v.y)*16-v.offsetY)*scale), v.rotation, dirscale, horscale, v.quadcenterX - hat[v.hats[i]].x + offsets[1], v.quadcenterY - hat[v.hats[i]].y + offsets[2] + yadd)
1349											yadd = yadd + hat[v.hats[i]].height
1350										end
1351									end
1352								end
1353							end
1354
1355							if v.graphic[0] then
1356								love.graphics.setColor(255, 255, 255)
1357								love.graphics.drawq(v.graphic[0], v.quad, math.floor(((v.x-xscroll)*16+v.offsetX)*scale), math.floor((v.y*16-v.offsetY)*scale), v.rotation, dirscale, horscale, v.quadcenterX, v.quadcenterY)
1358							end
1359						else
1360							if v.graphic and v.quad then
1361								love.graphics.drawq(v.graphic, v.quad, math.floor(((v.x-xscroll)*16+v.offsetX)*scale), math.floor((v.y*16-v.offsetY)*scale), v.rotation, dirscale, horscale, v.quadcenterX, v.quadcenterY)
1362							end
1363						end
1364
1365						--portal duplication
1366						if v.static == false and (v.active or v.portaloverride) and v.portalable ~= false then
1367							if v.customscissor then
1368
1369							elseif ply ~= false then
1370								love.graphics.setScissor(unpack(currentscissor))
1371								local px, py, pw, ph, pr, pad = v.x, v.y, v.width, v.height, v.rotation, v.animationdirection
1372								px, py, d, d, pr, pad = portalcoords(px, py, 0, 0, pw, ph, pr, pad, entryX, entryY, entryfacing, exitX, exitY, exitfacing)
1373
1374								if pad ~= v.animationdirection then
1375									dirscale = -dirscale
1376								end
1377
1378								horscale = scale
1379								if v.shot then
1380									horscale = -scale
1381								end
1382
1383								if exitfacing == "right" then
1384									love.graphics.setScissor(math.floor((exitX-xscroll)*16*scale), math.floor(((exitY-3.5)*16)*scale), 64*scale, 96*scale)
1385								elseif exitfacing == "left" then
1386									love.graphics.setScissor(math.floor((exitX-xscroll-5)*16*scale), math.floor(((exitY-4.5)*16)*scale), 64*scale, 96*scale)
1387								elseif exitfacing == "up" then
1388									love.graphics.setScissor(math.floor((exitX-xscroll-3)*16*scale), math.floor(((exitY-5.5)*16)*scale), 96*scale, 64*scale)
1389								elseif exitfacing == "down" then
1390									love.graphics.setScissor(math.floor((exitX-xscroll-4)*16*scale), math.floor(((exitY-0.5)*16)*scale), 96*scale, 64*scale)
1391								end
1392
1393								if type(v.graphic) == "table" then
1394									for k = 1, #v.graphic do
1395										if v.colors[k] then
1396											love.graphics.setColor(v.colors[k])
1397										else
1398											love.graphics.setColor(255, 255, 255)
1399										end
1400										love.graphics.drawq(v.graphic[k], v.quad, math.ceil(((px-xscroll)*16+v.offsetX)*scale), math.ceil((py*16-v.offsetY)*scale), pr, dirscale, horscale, v.quadcenterX, v.quadcenterY)
1401									end
1402
1403									if v.drawhat and hatoffsets[v.animationstate] then
1404										local offsets = {}
1405										if v.graphic == v.biggraphic or v.animationstate == "grow" then
1406											if v.animationstate == "grow" then
1407												offsets = hatoffsets["grow"]
1408											elseif v.fireanimationtimer < fireanimationtime then
1409												offsets = bighatoffsets["fire"]
1410											elseif underwater and (v.animationstate == "jumping" or v.animationstate == "falling") then
1411												offsets = bighatoffsets["swimming"][v.swimframe]
1412											elseif v.ducking then
1413												offsets = bighatoffsets["ducking"]
1414											elseif v.animationstate == "running" or v.animationstate == "falling"  then
1415												offsets = bighatoffsets["running"][v.runframe]
1416											elseif v.animationstate == "climbing" then
1417												offsets = bighatoffsets["climbing"][v.climbframe]
1418											else
1419												offsets = bighatoffsets[v.animationstate]
1420											end
1421										else
1422											if underwater and (v.animationstate == "jumping" or v.animationstate == "falling") then
1423												offsets = hatoffsets["swimming"][v.swimframe]
1424											elseif v.animationstate == "running" or v.animationstate == "falling"  then
1425												offsets = hatoffsets["running"][v.runframe]
1426											elseif v.animationstate == "climbing" then
1427												offsets = hatoffsets["climbing"][v.climbframe]
1428											else
1429												offsets = hatoffsets[v.animationstate]
1430											end
1431										end
1432
1433										if #v.hats > 0 then
1434											local yadd = 0
1435											for i = 1, #v.hats do
1436												if v.hats[i] == 1 then
1437													love.graphics.setColor(v.colors[1])
1438												else
1439													love.graphics.setColor(255, 255, 255)
1440												end
1441												if v.graphic == v.biggraphic or v.animationstate == "grow" then
1442													love.graphics.draw(bighat[v.hats[i]].graphic, math.floor(((px-xscroll)*16+v.offsetX)*scale), math.floor(((py)*16-v.offsetY)*scale), pr, dirscale, horscale, v.quadcenterX - bighat[v.hats[i]].x + offsets[1], v.quadcenterY - bighat[v.hats[i]].y + offsets[2] + yadd)
1443													yadd = yadd + bighat[v.hats[i]].height
1444												else
1445													love.graphics.draw(hat[v.hats[i]].graphic, math.floor(((px-xscroll)*16+v.offsetX)*scale), math.floor(((py)*16-v.offsetY)*scale), pr, dirscale, horscale, v.quadcenterX - hat[v.hats[i]].x + offsets[1], v.quadcenterY - hat[v.hats[i]].y + offsets[2] + yadd)
1446													yadd = yadd + hat[v.hats[i]].height
1447												end
1448											end
1449										end
1450									end
1451
1452									if v.graphic[0] then
1453										love.graphics.setColor(255, 255, 255)
1454										love.graphics.drawq(v.graphic[0], v.quad, math.floor(((px-xscroll)*16+v.offsetX)*scale), math.floor((py*16-v.offsetY)*scale), pr, dirscale, horscale, v.quadcenterX, v.quadcenterY)
1455									end
1456								else
1457									love.graphics.drawq(v.graphic, v.quad, math.ceil(((px-xscroll)*16+v.offsetX)*scale), math.ceil((py*16-v.offsetY)*scale), pr, dirscale, horscale, v.quadcenterX, v.quadcenterY)
1458								end
1459							end
1460						end
1461						love.graphics.setScissor(unpack(currentscissor))
1462					end
1463				end
1464			end
1465		end
1466
1467		love.graphics.setColor(255, 255, 255)
1468
1469		--bowser
1470		for j, w in pairs(objects["bowser"]) do
1471			w:draw()
1472		end
1473
1474		--lakito
1475		for j, w in pairs(objects["lakito"]) do
1476			w:draw()
1477		end
1478
1479		--Geldispensers
1480		for j, w in pairs(objects["geldispenser"]) do
1481			w:draw()
1482		end
1483
1484		--Cubedispensers
1485		for j, w in pairs(objects["cubedispenser"]) do
1486			w:draw()
1487		end
1488
1489		--Emancipationgrills
1490		for j, w in pairs(emancipationgrills) do
1491			w:draw()
1492		end
1493
1494		--Doors
1495		for j, w in pairs(objects["door"]) do
1496			w:draw()
1497		end
1498
1499		--Wallindicators
1500		for j, w in pairs(objects["wallindicator"]) do
1501			w:draw()
1502		end
1503
1504		--Walltimers
1505		for j, w in pairs(objects["walltimer"]) do
1506			w:draw()
1507		end
1508
1509		--Notgates
1510		for j, w in pairs(objects["notgate"]) do
1511			w:draw()
1512		end
1513
1514		--particles
1515		for j, w in pairs(portalparticles) do
1516			w:draw()
1517		end
1518
1519		--portals
1520		for i = 1, players do
1521			if objects["player"][i].portal1X ~= false then
1522				local rotation = 0
1523				local offsetx, offsety = 8, -3
1524				if objects["player"][i].portal1facing == "right" then
1525					rotation = math.pi/2
1526					offsetx, offsety = 11, 0
1527				elseif objects["player"][i].portal1facing == "down" then
1528					rotation = math.pi
1529					offsety = 3
1530				elseif objects["player"][i].portal1facing == "left" then
1531					rotation = math.pi*1.5
1532					offsetx, offsety = 5, 0
1533				end
1534
1535				local portalframe = portalanimation
1536				local glowalpha = 100
1537				if objects["player"][i].portal2X == false then
1538
1539				else
1540					love.graphics.setColor(255, 255, 255, 80 - math.abs(portalframe-3)*10)
1541					love.graphics.draw(portalglow, math.floor(((objects["player"][i].portal1X-1-xscroll)*16+offsetx)*scale), math.floor(((objects["player"][i].portal1Y-1)*16+offsety)*scale), rotation, scale, scale, 8, 20)
1542					love.graphics.setColor(255, 255, 255, 255)
1543				end
1544
1545				love.graphics.setColor(unpack(objects["player"][i].portal1color))
1546				love.graphics.drawq(portalimage, portal1quad[portalframe], math.floor(((objects["player"][i].portal1X-1-xscroll)*16+offsetx)*scale), math.floor(((objects["player"][i].portal1Y-1)*16+offsety)*scale), rotation, scale, scale, 8, 8)
1547			end
1548
1549			if objects["player"][i].portal2X ~= false then
1550				rotation = 0
1551				offsetx, offsety = 8, -3
1552				if objects["player"][i].portal2facing == "right" then
1553					rotation = math.pi/2
1554					offsetx, offsety = 11, 0
1555				elseif objects["player"][i].portal2facing == "down" then
1556					rotation = math.pi
1557					offsety = 3
1558				elseif objects["player"][i].portal2facing == "left" then
1559					rotation = math.pi*1.5
1560					offsetx, offsety = 5, 0
1561				end
1562
1563				local portalframe = portalanimation
1564				if objects["player"][i].portal1X == false then
1565
1566				else
1567					love.graphics.setColor(255, 255, 255, 80 - math.abs(portalframe-3)*10)
1568					love.graphics.draw(portalglow, math.floor(((objects["player"][i].portal2X-1-xscroll)*16+offsetx)*scale), math.floor(((objects["player"][i].portal2Y-1)*16+offsety)*scale), rotation, scale, scale, 8, 20)
1569					love.graphics.setColor(255, 255, 255, 255)
1570				end
1571
1572				love.graphics.setColor(unpack(objects["player"][i].portal2color))
1573				love.graphics.drawq(portalimage, portal2quad[portalframe], math.floor(((objects["player"][i].portal2X-1-xscroll)*16+offsetx)*scale), math.floor(((objects["player"][i].portal2Y-1)*16+offsety)*scale), rotation, scale, scale, 8, 8)
1574			end
1575		end
1576
1577		love.graphics.setColor(255, 255, 255)
1578
1579		--COINBLOCKANIMATION
1580		for i, v in pairs(coinblockanimations) do
1581			love.graphics.drawq(coinblockanimationimage, coinblockanimationquads[coinblockanimations[i].frame], math.floor((coinblockanimations[i].x - xscroll)*16*scale), math.floor((coinblockanimations[i].y*16-8)*scale), 0, scale, scale, 4, 54)
1582		end
1583
1584		--SCROLLING SCORE
1585		for i, v in pairs(scrollingscores) do
1586			if type(scrollingscores[i].i) == "number" then
1587				properprint2(scrollingscores[i].i, math.floor((scrollingscores[i].x-0.4)*16*scale), math.floor((scrollingscores[i].y-1.5-scrollingscoreheight*(scrollingscores[i].timer/scrollingscoretime))*16*scale))
1588			elseif scrollingscores[i].i == "1up" then
1589				love.graphics.draw(oneuptextimage, math.floor((scrollingscores[i].x)*16*scale), math.floor((scrollingscores[i].y-1.5-scrollingscoreheight*(scrollingscores[i].timer/scrollingscoretime))*16*scale), 0, scale, scale)
1590			end
1591		end
1592
1593		--BLOCK DEBRIS
1594		for i, v in pairs(blockdebristable) do
1595			v:draw()
1596		end
1597
1598		local minex, miney, minecox, minecoy
1599
1600		--PORTAL UI STUFF
1601		if levelfinished == false then
1602			for pl = 1, players do
1603				if objects["player"][pl].controlsenabled and objects["player"][pl].t == "portal" and objects["player"][pl].vine == false then
1604					local sourcex, sourcey = objects["player"][pl].x+6/16, objects["player"][pl].y+6/16
1605					local cox, coy, side, tend, x, y = traceline(sourcex, sourcey, objects["player"][pl].pointingangle)
1606
1607					local portalpossible = true
1608					if cox == false or getportalposition(1, cox, coy, side, tend) == false then
1609						portalpossible = false
1610					end
1611
1612					love.graphics.setColor(255, 255, 255, 255)
1613
1614					local dist = math.sqrt(((x-xscroll)*16*scale - (sourcex-xscroll)*16*scale)^2 + ((y-.5)*16*scale - (sourcey-.5)*16*scale)^2)/16/scale
1615
1616					for i = 1, dist/portaldotsdistance+1 do
1617						if((i-1+objects["player"][pl].portaldotstimer/portaldotstime)/(dist/portaldotsdistance)) < 1 then
1618							local xplus = ((x-xscroll)*16*scale - (sourcex-xscroll)*16*scale)*((i-1+objects["player"][pl].portaldotstimer/portaldotstime)/(dist/portaldotsdistance))
1619							local yplus = ((y-.5)*16*scale - (sourcey-.5)*16*scale)*((i-1+objects["player"][pl].portaldotstimer/portaldotstime)/(dist/portaldotsdistance))
1620
1621							local dotx = (sourcex-xscroll)*16*scale + xplus
1622							local doty = (sourcey-.5)*16*scale + yplus
1623
1624							local radius = math.sqrt(xplus^2 + yplus^2)/scale
1625
1626							local alpha = 255
1627							if radius < portaldotsouter then
1628								alpha = (radius-portaldotsinner) * (255/(portaldotsouter-portaldotsinner))
1629								if alpha < 0 then
1630									alpha = 0
1631								end
1632							end
1633
1634
1635							if portalpossible == false then
1636								love.graphics.setColor(255, 0, 0, alpha)
1637							else
1638								love.graphics.setColor(0, 255, 0, alpha)
1639							end
1640
1641							love.graphics.draw(portaldotimg, math.floor(dotx-0.25*scale), math.floor(doty-0.25*scale), 0, scale, scale)
1642						end
1643					end
1644
1645					love.graphics.setColor(255, 255, 255, 255)
1646
1647					if cox ~= false then
1648						if portalpossible == false then
1649							love.graphics.setColor(255, 0, 0)
1650						else
1651							love.graphics.setColor(0, 255, 0)
1652						end
1653
1654						local rotation = 0
1655						if side == "right" then
1656							rotation = math.pi/2
1657						elseif side == "down" then
1658							rotation = math.pi
1659						elseif side == "left" then
1660							rotation = math.pi/2*3
1661						end
1662						love.graphics.draw(portalcrosshairimg, math.floor((x-xscroll)*16*scale), math.floor((y-.5)*16*scale), rotation, scale, scale, 4, 8)
1663					end
1664				end
1665			end
1666		end
1667
1668		--Portal projectile
1669		for i, v in pairs(portalprojectiles) do
1670			v:draw()
1671		end
1672
1673		love.graphics.setColor(255, 255, 255)
1674
1675		--nothing to see here
1676		for i, v in pairs(rainbooms) do
1677			v:draw()
1678		end
1679
1680		--Minecraft
1681		--black border
1682		if objects["player"][mouseowner] and playertype == "minecraft" and not levelfinished then
1683			local v = objects["player"][mouseowner]
1684			local sourcex, sourcey = v.x+6/16, v.y+6/16
1685			local cox, coy, side, tend, x, y = traceline(sourcex, sourcey, v.pointingangle)
1686
1687			if cox then
1688				local dist = math.sqrt((v.x+v.width/2 - x)^2 + (v.y+v.height/2 - y)^2)
1689				if dist <= minecraftrange then
1690					love.graphics.setColor(0, 0, 0, 170)
1691					love.graphics.rectangle("line", math.floor((cox-1-xscroll)*16*scale)-.5, (coy-1-.5)*16*scale-.5, 16*scale, 16*scale)
1692
1693					if breakingblockX and (cox ~= breakingblockX or coy ~= breakingblockY) then
1694						breakingblockX = cox
1695						breakingblockY = coy
1696						breakingblockprogress = 0
1697					elseif not breakingblockX and love.mouse.isDown("l") then
1698						breakingblockX = cox
1699						breakingblockY = coy
1700						breakingblockprogress = 0
1701					end
1702				elseif love.mouse.isDown("l") then
1703					breakingblockX = cox
1704					breakingblockY = coy
1705					breakingblockprogress = 0
1706				end
1707			else
1708				breakingblockX = nil
1709			end
1710			--break animation
1711			if breakingblockX then
1712				love.graphics.setColor(255, 255, 255, 255)
1713				local frame = math.ceil((breakingblockprogress/minecraftbreaktime)*10)
1714				if frame ~= 0 then
1715					love.graphics.drawq(minecraftbreakimg, minecraftbreakquad[frame], (breakingblockX-1-xscroll)*16*scale, (breakingblockY-1.5)*16*scale, 0, scale, scale)
1716				end
1717			end
1718			love.graphics.setColor(255, 255, 255, 255)
1719
1720			--gui
1721			love.graphics.draw(minecraftgui, (width*8-91)*scale, 202*scale, 0, scale, scale)
1722
1723			love.graphics.setColor(255, 255, 255, 200)
1724			for i = 1, 9 do
1725				local t = inventory[i].t
1726
1727				if t ~= nil then
1728					local img = customtilesimg
1729					if t <= smbtilecount then
1730						img = smbtilesimg
1731					elseif t <= smbtilecount+portaltilecount then
1732						img = portaltilesimg
1733					end
1734					love.graphics.drawq(img, tilequads[t].quad, (width*8-88+(i-1)*20)*scale, 205*scale, 0, scale, scale)
1735				end
1736			end
1737
1738			love.graphics.setColor(255, 255, 255, 255)
1739			love.graphics.draw(minecraftselected, (width*8-92+(mccurrentblock-1)*20)*scale, 201*scale, 0, scale, scale)
1740
1741			for i = 1, 9 do
1742				if inventory[i].t ~= nil then
1743					local count = inventory[i].count
1744					properprint(count, (width*8-72+(i-1)*20-string.len(count)*8)*scale, 205*scale)
1745				end
1746			end
1747		end
1748
1749		love.graphics.translate(-(split-1)*width*16*scale/#splitscreen, 0)
1750	end
1751	love.graphics.setScissor()
1752
1753	if earthquake > 0 then
1754		love.graphics.translate(-round(tremorx), -round(tremory))
1755	end
1756
1757	for i = 2, #splitscreen do
1758		love.graphics.line((i-1)*width*16*scale/#splitscreen, 0, (i-1)*width*16*scale/#splitscreen, 15*16*scale)
1759	end
1760
1761	if editormode then
1762		editor_draw()
1763	end
1764
1765	--speed gradient
1766	if speed < 1 then
1767		love.graphics.setColor(255, 255, 255, 255-255*speed)
1768		love.graphics.draw(gradientimg, 0, 0, 0, scale, scale)
1769	end
1770
1771	if yoffset < 0 then
1772		love.graphics.translate(0, -yoffset*scale)
1773	end
1774	love.graphics.translate(0, yoffset*scale)
1775
1776	if testlevel then
1777		love.graphics.setColor(255, 0, 0)
1778		properprint("testing level - press esc to return to editor", 0, 0)
1779	end
1780
1781	--pause menu
1782	if pausemenuopen then
1783		love.graphics.setColor(0, 0, 0, 100)
1784		love.graphics.rectangle("fill", 0, 0, width*16*scale, 224*scale)
1785
1786		love.graphics.setColor(0, 0, 0)
1787		love.graphics.rectangle("fill", (width*8*scale)-50*scale, (112*scale)-75*scale, 100*scale, 150*scale)
1788		love.graphics.setColor(255, 255, 255)
1789		drawrectangle(width*8-49, 112-74, 98, 148)
1790
1791		for i = 1, #pausemenuoptions do
1792			love.graphics.setColor(100, 100, 100, 255)
1793			if pausemenuselected == i and not menuprompt and not desktopprompt then
1794				love.graphics.setColor(255, 255, 255, 255)
1795				properprint(">", (width*8*scale)-45*scale, (112*scale)-60*scale+(i-1)*25*scale)
1796			end
1797			properprint(pausemenuoptions[i], (width*8*scale)-35*scale, (112*scale)-60*scale+(i-1)*25*scale)
1798			properprint(pausemenuoptions2[i], (width*8*scale)-35*scale, (112*scale)-50*scale+(i-1)*25*scale)
1799
1800			if pausemenuoptions[i] == "volume" then
1801				drawrectangle((width*8)-34, 68+(i-1)*25, 74, 1)
1802				drawrectangle((width*8)-34, 65+(i-1)*25, 1, 7)
1803				drawrectangle((width*8)+40, 65+(i-1)*25, 1, 7)
1804				love.graphics.draw(volumesliderimg, math.floor(((width*8)-35+74*volume)*scale), (112*scale)-47*scale+(i-1)*25*scale, 0, scale, scale)
1805			end
1806		end
1807
1808		if menuprompt then
1809			love.graphics.setColor(0, 0, 0, 255)
1810			love.graphics.rectangle("fill", (width*8*scale)-100*scale, (112*scale)-25*scale, 200*scale, 50*scale)
1811			love.graphics.setColor(255, 255, 255, 255)
1812			drawrectangle((width*8)-99, 112-24, 198, 48)
1813			properprint("quit to menu?", (width*8*scale)-string.len("quit to menu?")*4*scale, (112*scale)-10*scale)
1814			if pausemenuselected2 == 1 then
1815				properprint(">", (width*8*scale)-51*scale, (112*scale)+4*scale)
1816				love.graphics.setColor(255, 255, 255, 255)
1817				properprint("yes", (width*8*scale)-44*scale, (112*scale)+4*scale)
1818				love.graphics.setColor(100, 100, 100, 255)
1819				properprint("no", (width*8*scale)+28*scale, (112*scale)+4*scale)
1820			else
1821				properprint(">", (width*8*scale)+20*scale, (112*scale)+4*scale)
1822				love.graphics.setColor(100, 100, 100, 255)
1823				properprint("yes", (width*8*scale)-44*scale, (112*scale)+4*scale)
1824				love.graphics.setColor(255, 255, 255, 255)
1825				properprint("no", (width*8*scale)+28*scale, (112*scale)+4*scale)
1826			end
1827		end
1828
1829		if desktopprompt then
1830			love.graphics.setColor(0, 0, 0, 255)
1831			love.graphics.rectangle("fill", (width*8*scale)-100*scale, (112*scale)-25*scale, 200*scale, 50*scale)
1832			love.graphics.setColor(255, 255, 255, 255)
1833			drawrectangle((width*8)-99, 112-24, 198, 48)
1834			properprint("quit to desktop?", (width*8*scale)-string.len("quit to desktop?")*4*scale, (112*scale)-10*scale)
1835			if pausemenuselected2 == 1 then
1836				properprint(">", (width*8*scale)-51*scale, (112*scale)+4*scale)
1837				love.graphics.setColor(255, 255, 255, 255)
1838				properprint("yes", (width*8*scale)-44*scale, (112*scale)+4*scale)
1839				love.graphics.setColor(100, 100, 100, 255)
1840				properprint("no", (width*8*scale)+28*scale, (112*scale)+4*scale)
1841			else
1842				properprint(">", (width*8*scale)+20*scale, (112*scale)+4*scale)
1843				love.graphics.setColor(100, 100, 100, 255)
1844				properprint("yes", (width*8*scale)-44*scale, (112*scale)+4*scale)
1845				love.graphics.setColor(255, 255, 255, 255)
1846				properprint("no", (width*8*scale)+28*scale, (112*scale)+4*scale)
1847			end
1848		end
1849
1850		if suspendprompt then
1851			love.graphics.setColor(0, 0, 0, 255)
1852			love.graphics.rectangle("fill", (width*8*scale)-100*scale, (112*scale)-25*scale, 200*scale, 50*scale)
1853			love.graphics.setColor(255, 255, 255, 255)
1854			drawrectangle((width*8)-99, 112-24, 198, 48)
1855			properprint("suspend game? this can", (width*8*scale)-string.len("suspend game? this can")*4*scale, (112*scale)-20*scale)
1856			properprint("only be loaded once!", (width*8*scale)-string.len("only be loaded once!")*4*scale, (112*scale)-10*scale)
1857			if pausemenuselected2 == 1 then
1858				properprint(">", (width*8*scale)-51*scale, (112*scale)+4*scale)
1859				love.graphics.setColor(255, 255, 255, 255)
1860				properprint("yes", (width*8*scale)-44*scale, (112*scale)+4*scale)
1861				love.graphics.setColor(100, 100, 100, 255)
1862				properprint("no", (width*8*scale)+28*scale, (112*scale)+4*scale)
1863			else
1864				properprint(">", (width*8*scale)+20*scale, (112*scale)+4*scale)
1865				love.graphics.setColor(100, 100, 100, 255)
1866				properprint("yes", (width*8*scale)-44*scale, (112*scale)+4*scale)
1867				love.graphics.setColor(255, 255, 255, 255)
1868				properprint("no", (width*8*scale)+28*scale, (112*scale)+4*scale)
1869			end
1870		end
1871	end
1872end
1873
1874function updatesplitscreen()
1875	if players == 2 and netplay == false then
1876		if #splitscreen == 1 then
1877			if math.abs(objects["player"][1].x - objects["player"][2].x) > width - scrollingstart - scrollingleftstart then
1878				if objects["player"][1].x < objects["player"][2].x then
1879					splitscreen = {{1}, {2}}
1880				else
1881					splitscreen = {{2}, {1}}
1882				end
1883
1884				splitxscroll = {xscroll, xscroll+width/2}
1885				generatespritebatch()
1886			end
1887		else
1888			if splitxscroll[2] <= splitxscroll[1]+width/2 then
1889				splitscreen = {{1, 2}}
1890
1891				xscroll = splitxscroll[1]
1892				generatespritebatch()
1893			end
1894		end
1895	end
1896end
1897
1898function startlevel(level)
1899	skipupdate = true
1900	love.audio.stop()
1901
1902	local sublevel = false
1903	if type(level) == "number" then
1904		sublevel = true
1905	end
1906
1907	if sublevel then
1908		prevsublevel = mariosublevel
1909		mariosublevel = level
1910		if level ~= 0 then
1911			level = marioworld .. "-" .. mariolevel .. "_" .. level
1912		else
1913			level = marioworld .. "-" .. mariolevel
1914		end
1915	else
1916		mariosublevel = 0
1917		prevsublevel = false
1918		mariotime = 400
1919	end
1920
1921	--MISC VARS
1922	everyonedead = false
1923	levelfinished = false
1924	coinanimation = 1
1925	flagx = false
1926	levelfinishtype = nil
1927	firestartx = false
1928	firestarted = false
1929	firedelay = math.random(4)
1930	flyingfishdelay = 1
1931	flyingfishstarted = false
1932	flyingfishstartx = false
1933	flyingfishendx = false
1934	bulletbilldelay = 1
1935	bulletbillstarted = false
1936	bulletbillstartx = false
1937	bulletbillendx = false
1938	firetimer = firedelay
1939	flyingfishtimer = flyingfishdelay
1940	bulletbilltimer = bulletbilldelay
1941	axex = false
1942	axey = false
1943	lakitoendx = false
1944	lakitoend = false
1945	noupdate = false
1946	xscroll = 0
1947	splitscreen = {{}}
1948	checkpoints = {}
1949	checkpointpoints = {}
1950	repeatX = 0
1951	lastrepeat = 0
1952	displaywarpzonetext = false
1953	for i = 1, players do
1954		table.insert(splitscreen[1], i)
1955	end
1956	checkpointi = 0
1957	mazestarts = {}
1958	mazeends = {}
1959	mazesolved = {}
1960	mazesolved[0] = true
1961	mazeinprogress = false
1962	earthquake = 0
1963	sunrot = 0
1964	gelcannontimer = 0
1965	pausemenuselected = 1
1966	coinblocktimers = {}
1967
1968	portaldelay = {}
1969	for i = 1, players do
1970		portaldelay[i] = 0
1971	end
1972
1973	--Minecraft
1974	breakingblockX = false
1975	breakingblockY = false
1976	breakingblockprogress = 0
1977
1978	--class tables
1979	coinblockanimations = {}
1980	scrollingscores = {}
1981	portalparticles = {}
1982	portalprojectiles = {}
1983	emancipationgrills = {}
1984	platformspawners = {}
1985	rocketlaunchers = {}
1986	userects = {}
1987	blockdebristable = {}
1988	fireworks = {}
1989	seesaws = {}
1990	bubbles = {}
1991	rainbooms = {}
1992	miniblocks = {}
1993	inventory = {}
1994	for i = 1, 9 do
1995		inventory[i] = {}
1996	end
1997	mccurrentblock = 1
1998
1999	blockbouncetimer = {}
2000	blockbouncex = {}
2001	blockbouncey = {}
2002	blockbouncecontent = {}
2003	blockbouncecontent2 = {}
2004	warpzonenumbers = {}
2005
2006	objects = {}
2007	objects["player"] = {}
2008	objects["portalwall"] = {}
2009	objects["tile"] = {}
2010	objects["goomba"] = {}
2011	objects["koopa"] = {}
2012	objects["mushroom"] = {}
2013	objects["flower"] = {}
2014	objects["oneup"] = {}
2015	objects["star"] = {}
2016	objects["vine"] = {}
2017	objects["box"] = {}
2018	objects["door"] = {}
2019	objects["button"] = {}
2020	objects["groundlight"] = {}
2021	objects["wallindicator"] = {}
2022	objects["walltimer"] = {}
2023	objects["notgate"] = {}
2024	objects["lightbridge"] = {}
2025	objects["lightbridgebody"] = {}
2026	objects["faithplate"] = {}
2027	objects["laser"] = {}
2028	objects["laserdetector"] = {}
2029	objects["gel"] = {}
2030	objects["geldispenser"] = {}
2031	objects["cubedispenser"] = {}
2032	objects["pushbutton"] = {}
2033	objects["bulletbill"] = {}
2034	objects["hammerbro"] = {}
2035	objects["hammer"] = {}
2036	objects["fireball"] = {}
2037	objects["platform"] = {}
2038	objects["platformspawner"] = {}
2039	objects["plant"] = {}
2040	objects["castlefire"] = {}
2041	objects["castlefirefire"] = {}
2042	objects["fire"] = {}
2043	objects["bowser"] = {}
2044	objects["spring"] = {}
2045	objects["cheep"] = {}
2046	objects["flyingfish"] = {}
2047	objects["upfire"] = {}
2048	objects["seesawplatform"] = {}
2049	objects["lakito"] = {}
2050	objects["squid"] = {}
2051
2052	objects["screenboundary"] = {}
2053	objects["screenboundary"]["left"] = screenboundary:new(0)
2054
2055	splitxscroll = {0}
2056
2057	startx = 3
2058	starty = 13
2059	pipestartx = nil
2060	pipestarty = nil
2061	animation = nil
2062
2063	enemiesspawned = {}
2064
2065	intermission = false
2066	haswarpzone = false
2067	underwater = false
2068	bonusstage = false
2069	custombackground = false
2070	mariotimelimit = 400
2071	spriteset = 1
2072	--LOAD THE MAP
2073	if loadmap(level) == false then --make one up
2074		mapwidth = width
2075		map = {}
2076		for x = 1, width do
2077			map[x] = {}
2078			for y = 1, 15 do
2079				if y > 13 then
2080					map[x][y] = {2}
2081					objects["tile"][x .. "-" .. y] = tile:new(x-1, y-1, 1, 1, true)
2082					map[x][y]["gels"] = {}
2083				else
2084					map[x][y] = {1}
2085					map[x][y]["gels"] = {}
2086				end
2087			end
2088		end
2089	else
2090		if sublevel == false and mariosublevel ~= 0 then
2091			level = marioworld .. "-" .. mariolevel
2092			mariosublevel = 0
2093			loadmap(level)
2094		end
2095	end
2096
2097	objects["screenboundary"]["right"] = screenboundary:new(mapwidth)
2098
2099	if flagx then
2100		objects["screenboundary"]["flag"] = screenboundary:new(flagx+6/16)
2101	end
2102
2103	if axex then
2104		objects["screenboundary"]["axe"] = screenboundary:new(axex+1)
2105	end
2106
2107	if intermission then
2108		animation = "intermission"
2109	end
2110
2111	if not sublevel then
2112		mariotime = mariotimelimit
2113	end
2114
2115	--Maze setup
2116	--check every block between every start/end pair to see how many gates it contains
2117	if #mazestarts == #mazeends then
2118		mazegates = {}
2119		for i = 1, #mazestarts do
2120			local maxgate = 1
2121			for x = mazestarts[i], mazeends[i] do
2122				for y = 1, 15 do
2123					if map[x][y][2] and entityquads[map[x][y][2]].t == "mazegate" then
2124						if tonumber(map[x][y][3]) > maxgate then
2125							maxgate = tonumber(map[x][y][3])
2126						end
2127					end
2128				end
2129			end
2130			mazegates[i] = maxgate
2131		end
2132	else
2133		print("Mazenumber doesn't fit!")
2134	end
2135
2136	--background
2137	love.graphics.setBackgroundColor(backgroundcolor[background])
2138
2139	--check if it's a bonusstage (boooooooonus!)
2140	if bonusstage then
2141		animation = "vinestart"
2142	end
2143
2144	--set startx to checkpoint
2145	if checkpointx and checkcheckpoint then
2146		startx = checkpointx
2147		starty = checkpointpoints[checkpointx] or 13
2148
2149		--clear enemies from spawning near
2150		for y = 1, 15 do
2151			for x = startx-8, startx+8 do
2152				if inmap(x, y) and #map[x][y] > 1 then
2153					if tablecontains(enemies, entityquads[map[x][y][2]].t) then
2154						table.insert(enemiesspawned, {x, y})
2155					end
2156				end
2157			end
2158		end
2159
2160		--find which i it is
2161		for i = 1, #checkpoints do
2162			if checkpointx == checkpoints[i] then
2163				checkpointi = i
2164			end
2165		end
2166	end
2167
2168	--set startx to pipestart
2169	if pipestartx then
2170		startx = pipestartx-1
2171		starty = pipestarty
2172		--check if startpos is a colliding block
2173		if tilequads[map[startx][starty][1]].collision then
2174			animation = "pipeup"
2175		end
2176	end
2177
2178	splitxscroll = {startx-scrollingleftcomplete-2}
2179	if splitxscroll[1] > mapwidth - width then
2180		splitxscroll[1] = mapwidth - width
2181	end
2182
2183	if splitxscroll[1] < 0 then
2184		splitxscroll[1] = 0
2185	end
2186
2187	--ADD ENEMIES ON START SCREEN
2188	if editormode == false then
2189		local xtodo = width+1
2190		if mapwidth < width+1 then
2191			xtodo = mapwidth
2192		end
2193
2194		for x = math.floor(splitxscroll[1]), math.floor(splitxscroll[1])+xtodo do
2195			for y = 1, 15 do
2196				spawnenemy(x, y)
2197			end
2198		end
2199	end
2200
2201	--add the players
2202	local mul = 0.5
2203	if mariosublevel ~= 0 or prevsublevel ~= false then
2204		mul = 2/16
2205	end
2206
2207	objects["player"] = {}
2208	for i = 1, players do
2209		if startx then
2210			objects["player"][i] = mario:new(startx + (i-1)*mul-6/16, starty-1, i, animation, mariosizes[i], playertype)
2211		else
2212			objects["player"][i] = mario:new(1.5 + (i-1)*mul-6/16+1.5, 13, i, animation, mariosizes[i], playertype)
2213		end
2214	end
2215
2216	--PLAY BGM
2217	if intermission == false then
2218		playmusic()
2219	else
2220		playsound(intermissionsound)
2221	end
2222
2223	--load editor
2224	editor_load()
2225
2226	--Do stuff
2227	for i, v in pairs(objects["laser"]) do
2228		v:updaterange()
2229	end
2230	for i, v in pairs(objects["lightbridge"]) do
2231		v:updaterange()
2232	end
2233
2234	generatespritebatch()
2235end
2236
2237function loadmap(filename)
2238	print("Loading " .. "mappacks/" .. mappack .. "/" .. filename .. ".txt")
2239	if love.filesystem.exists("mappacks/" .. mappack .. "/" .. filename .. ".txt") == false then
2240		print("mappacks/" .. mappack .. "/" .. filename .. ".txt not found!")
2241		return false
2242	end
2243	local s = love.filesystem.read( "mappacks/" .. mappack .. "/" .. filename .. ".txt" )
2244	local s2 = s:split(";")
2245
2246	--MAP ITSELF
2247	local t = s2[1]:split(",")
2248
2249	if math.mod(#t, 15) ~= 0 then
2250		print("Incorrect number of entries: " .. #t)
2251		return false
2252	end
2253
2254	mapwidth = #t/15
2255
2256	map = {}
2257	unstatics = {}
2258
2259	for x = 1, #t/15 do
2260		map[x] = {}
2261		for y = 1, 15 do
2262			map[x][y] = {}
2263			map[x][y]["gels"] = {}
2264
2265			local r = tostring(t[(y-1)*(#t/15)+x]):split("-")
2266
2267			if tonumber(r[1]) > smbtilecount+portaltilecount+customtilecount then
2268				r[1] = 1
2269			end
2270
2271			for i = 1, #r do
2272				if r[i] ~= "link" then
2273					map[x][y][i] = tonumber(r[i])
2274				else
2275					map[x][y][i] = r[i]
2276				end
2277			end
2278
2279			--create object for block
2280			if tilequads[tonumber(r[1])].collision == true then
2281				objects["tile"][x .. "-" .. y] = tile:new(x-1, y-1, 1, 1, true)
2282			end
2283		end
2284	end
2285
2286	for y = 1, 15 do
2287		for x = 1, #t/15 do
2288			local r = map[x][y]
2289			if #r > 1 then
2290				local t = entityquads[r[2]].t
2291				if t == "spawn" then
2292					startx = x
2293					starty = y
2294
2295				elseif not editormode then
2296					if t == "warppipe" then
2297						table.insert(warpzonenumbers, {x, y, r[3]})
2298
2299					elseif t == "manycoins" then
2300						map[x][y][3] = 7
2301
2302					elseif t == "flag" then
2303						flagx = x-1
2304						flagy = y
2305
2306					elseif t == "pipespawn" and (prevsublevel == r[3] or (mariosublevel == r[3] and blacktime == sublevelscreentime)) then
2307						pipestartx = x
2308						pipestarty = y
2309
2310					elseif t == "emancehor" then
2311						table.insert(emancipationgrills, emancipationgrill:new(x, y, "hor"))
2312					elseif t == "emancever" then
2313						table.insert(emancipationgrills, emancipationgrill:new(x, y, "ver"))
2314
2315					elseif t == "doorver" then
2316						table.insert(objects["door"], door:new(x, y, r, "ver"))
2317					elseif t == "doorhor" then
2318						table.insert(objects["door"], door:new(x, y, r, "hor"))
2319
2320					elseif t == "button" then
2321						table.insert(objects["button"], button:new(x, y))
2322
2323					elseif t == "pushbuttonleft" then
2324						table.insert(objects["pushbutton"], pushbutton:new(x, y, "left"))
2325					elseif t == "pushbuttonright" then
2326						table.insert(objects["pushbutton"], pushbutton:new(x, y, "right"))
2327
2328					elseif t == "wallindicator" then
2329						table.insert(objects["wallindicator"], wallindicator:new(x, y, r))
2330
2331					elseif t == "groundlightver" then
2332						table.insert(objects["groundlight"], groundlight:new(x, y, 1, r))
2333					elseif t == "groundlighthor" then
2334						table.insert(objects["groundlight"], groundlight:new(x, y, 2, r))
2335					elseif t == "groundlightupright" then
2336						table.insert(objects["groundlight"], groundlight:new(x, y, 3, r))
2337					elseif t == "groundlightrightdown" then
2338						table.insert(objects["groundlight"], groundlight:new(x, y, 4, r))
2339					elseif t == "groundlightdownleft" then
2340						table.insert(objects["groundlight"], groundlight:new(x, y, 5, r))
2341					elseif t == "groundlightleftup" then
2342						table.insert(objects["groundlight"], groundlight:new(x, y, 6, r))
2343
2344					elseif t == "faithplateup" then
2345						table.insert(objects["faithplate"], faithplate:new(x, y, "up"))
2346					elseif t == "faithplateright" then
2347						table.insert(objects["faithplate"], faithplate:new(x, y, "right"))
2348					elseif t == "faithplateleft" then
2349						table.insert(objects["faithplate"], faithplate:new(x, y, "left"))
2350
2351					elseif t == "laserright" then
2352						table.insert(objects["laser"], laser:new(x, y, "right", r))
2353					elseif t == "laserdown" then
2354						table.insert(objects["laser"], laser:new(x, y, "down", r))
2355					elseif t == "laserleft" then
2356						table.insert(objects["laser"], laser:new(x, y, "left", r))
2357					elseif t == "laserup" then
2358						table.insert(objects["laser"], laser:new(x, y, "up", r))
2359
2360					elseif t == "lightbridgeright" then
2361						table.insert(objects["lightbridge"], lightbridge:new(x, y, "right", r))
2362					elseif t == "lightbridgeleft" then
2363						table.insert(objects["lightbridge"], lightbridge:new(x, y, "left", r))
2364					elseif t == "lightbridgedown" then
2365						table.insert(objects["lightbridge"], lightbridge:new(x, y, "down", r))
2366					elseif t == "lightbridgeup" then
2367						table.insert(objects["lightbridge"], lightbridge:new(x, y, "up", r))
2368
2369					elseif t == "laserdetectorright" then
2370						table.insert(objects["laserdetector"], laserdetector:new(x, y, "right"))
2371					elseif t == "laserdetectordown" then
2372						table.insert(objects["laserdetector"], laserdetector:new(x, y, "down"))
2373					elseif t == "laserdetectorleft" then
2374						table.insert(objects["laserdetector"], laserdetector:new(x, y, "left"))
2375					elseif t == "laserdetectorup" then
2376						table.insert(objects["laserdetector"], laserdetector:new(x, y, "up"))
2377
2378					elseif t == "boxtube" then
2379						table.insert(objects["cubedispenser"], cubedispenser:new(x, y, r))
2380
2381					elseif t == "timer" then
2382						table.insert(objects["walltimer"], walltimer:new(x, y, r[3], r))
2383					elseif t == "notgate" then
2384						table.insert(objects["notgate"], notgate:new(x, y, r))
2385
2386					elseif t == "platformspawnerup" then
2387						table.insert(platformspawners, platformspawner:new(x, y, "up", r[3]))
2388					elseif t == "platformspawnerdown" then
2389						table.insert(platformspawners, platformspawner:new(x, y, "down", r[3]))
2390
2391					elseif t == "box" then
2392						table.insert(objects["box"], box:new(x, y))
2393
2394					elseif t == "firestart" then
2395						firestartx = x
2396
2397					elseif t == "flyingfishstart" then
2398						flyingfishstartx = x
2399					elseif t == "flyingfishend" then
2400						flyingfishendx = x
2401
2402					elseif t == "bulletbillstart" then
2403						bulletbillstartx = x
2404					elseif t == "bulletbillend" then
2405						bulletbillendx = x
2406
2407					elseif t == "axe" then
2408						axex = x
2409						axey = y
2410
2411					elseif t == "lakitoend" then
2412						lakitoendx = x
2413
2414					elseif t == "spring" then
2415						table.insert(objects["spring"], spring:new(x, y))
2416
2417					elseif t == "seesaw" then
2418						table.insert(seesaws, seesaw:new(x, y, r[3]))
2419
2420					elseif t == "checkpoint" then
2421						if not tablecontains(checkpoints, x) then
2422							table.insert(checkpoints, x)
2423							checkpointpoints[x] = y
2424						end
2425					elseif t == "mazestart" then
2426						if not tablecontains(mazestarts, x) then
2427							table.insert(mazestarts, x)
2428						end
2429
2430					elseif t == "mazeend" then
2431						if not tablecontains(mazeends, x) then
2432							table.insert(mazeends, x)
2433						end
2434
2435					elseif t == "geltop" then
2436						if tilequads[map[x][y][1]].collision then
2437							map[x][y]["gels"]["top"] = r[3]
2438						end
2439					elseif t == "gelleft" then
2440						if tilequads[map[x][y][1]].collision then
2441							map[x][y]["gels"]["left"] = r[3]
2442						end
2443					elseif t == "gelbottom" then
2444						if tilequads[map[x][y][1]].collision then
2445							map[x][y]["gels"]["bottom"] = r[3]
2446						end
2447					elseif t == "gelright" then
2448						if tilequads[map[x][y][1]].collision then
2449							map[x][y]["gels"]["right"] = r[3]
2450						end
2451					end
2452				end
2453			end
2454		end
2455	end
2456
2457	--sort checkpoints
2458	table.sort(checkpoints)
2459
2460	--Add links
2461	for i, v in pairs(objects) do
2462		for j, w in pairs(v) do
2463			if w.link then
2464				w:link()
2465			end
2466		end
2467	end
2468
2469	if flagx then
2470		flagimgx = flagx+8/16
2471		flagimgy = 3+1/16
2472	end
2473
2474	for x = 0, -30, -1 do
2475		map[x] = {}
2476		for y = 1, 13 do
2477			map[x][y] = {1}
2478		end
2479
2480		for y = 14, 15 do
2481			map[x][y] = {2}
2482			objects["tile"][x .. "-" .. y] = tile:new(x-1, y-1, 1, 1, true)
2483		end
2484	end
2485
2486	--MORE STUFF
2487	for i = 2, #s2 do
2488		s3 = s2[i]:split("=")
2489		if s3[1] == "background" then
2490			background = tonumber(s3[2])
2491		elseif s3[1] == "spriteset" then
2492			spriteset = tonumber(s3[2])
2493		elseif s3[1] == "intermission" then
2494			intermission = true
2495		elseif s3[1] == "haswarpzone" then
2496			haswarpzone = true
2497		elseif s3[1] == "underwater" then
2498			underwater = true
2499		elseif s3[1] == "music" then
2500			musici = tonumber(s3[2])
2501		elseif s3[1] == "bonusstage" then
2502			bonusstage = true
2503		elseif s3[1] == "custombackground" or s3[1] == "portalbackground" then
2504			custombackground = true
2505		elseif s3[1] == "timelimit" then
2506			mariotimelimit = tonumber(s3[2])
2507		elseif s3[1] == "scrollfactor" then
2508			scrollfactor = tonumber(s3[2])
2509		end
2510	end
2511
2512	if custombackground then
2513		loadcustombackground()
2514	end
2515
2516	return true
2517end
2518
2519function changemapwidth(width)
2520	if width > mapwidth then
2521		for x = mapwidth+1, width do
2522			map[x] = {}
2523			for y = 1, 13 do
2524				map[x][y] = {1}
2525				map[x][y]["gels"] = {}
2526			end
2527
2528			for y = 14, 15 do
2529				map[x][y] = {2}
2530				objects["tile"][x .. "-" .. y] = tile:new(x-1, y-1, 1, 1, true)
2531				map[x][y]["gels"] = {}
2532			end
2533		end
2534	end
2535
2536	mapwidth = width
2537	objects["screenboundary"]["right"].x = mapwidth
2538
2539	if objects["player"][1].x > mapwidth then
2540		objects["player"][1].x = mapwidth-1
2541	end
2542end
2543
2544function generatespritebatch()
2545	for split = 1, #splitscreen do
2546		local smbmsb = smbspritebatch[split]
2547		local portalmsb = portalspritebatch[split]
2548		local custommsb
2549		if customtiles then
2550			custommsb = customspritebatch[split]
2551		end
2552		smbmsb:clear()
2553		portalmsb:clear()
2554		if customtiles then
2555			custommsb:clear()
2556		end
2557
2558		local xtodraw
2559		if mapwidth < width+1 then
2560			xtodraw = math.ceil(mapwidth/#splitscreen)
2561		else
2562			if mapwidth > width and splitxscroll[split] < mapwidth-width then
2563				xtodraw = width+1
2564			else
2565				xtodraw = width
2566			end
2567		end
2568
2569		local lmap = map
2570
2571		for y = 1, 15 do
2572			for x = 1, xtodraw do
2573				local bounceyoffset = 0
2574
2575				local draw = true
2576				for i, v in pairs(blockbouncex) do
2577					if blockbouncex[i] == math.floor(splitxscroll[split])+x and blockbouncey[i] == y then
2578						draw = false
2579					end
2580				end
2581				if draw == true then
2582					local t = lmap[math.floor(splitxscroll[split])+x][y]
2583
2584					local tilenumber = t[1]
2585					if tilenumber ~= 0 and tilequads[tilenumber].invisible == false and tilequads[tilenumber].coinblock == false and tilequads[tilenumber].coin == false then
2586						if tilenumber <= smbtilecount then
2587							smbmsb:addq( tilequads[tilenumber].quad, (x-1)*16*scale, ((y-1)*16-8)*scale, 0, scale, scale )
2588						elseif tilenumber <= smbtilecount+portaltilecount then
2589							portalmsb:addq( tilequads[tilenumber].quad, (x-1)*16*scale, ((y-1)*16-8)*scale, 0, scale, scale )
2590						elseif tilenumber <= smbtilecount+portaltilecount+customtilecount then
2591							custommsb:addq( tilequads[tilenumber].quad, (x-1)*16*scale, ((y-1)*16-8)*scale, 0, scale, scale )
2592						end
2593					end
2594				end
2595			end
2596		end
2597	end
2598end
2599
2600function game_keypressed(key, unicode)
2601	if pausemenuopen then
2602		if menuprompt then
2603			if (key == "left" or key == "a") then
2604				pausemenuselected2 = 1
2605			elseif (key == "right" or key == "d") then
2606				pausemenuselected2 = 2
2607			elseif (key == "return" or key == "enter" or key == "kpenter" or key == " ") then
2608				if pausemenuselected2 == 1 then
2609					love.audio.stop()
2610					pausemenuopen = false
2611					menuprompt = false
2612					menu_load()
2613				else
2614					menuprompt = false
2615				end
2616			elseif key == "escape" then
2617				menuprompt = false
2618			end
2619			return
2620		elseif desktopprompt then
2621			if (key == "left" or key == "a") then
2622				pausemenuselected2 = 1
2623			elseif (key == "right" or key == "d") then
2624				pausemenuselected2 = 2
2625			elseif (key == "return" or key == "enter" or key == "kpenter" or key == " ") then
2626				if pausemenuselected2 == 1 then
2627					love.audio.stop()
2628					love.event.quit()
2629				else
2630					desktopprompt = false
2631				end
2632			elseif key == "escape" then
2633				desktopprompt = false
2634			end
2635			return
2636		elseif suspendprompt then
2637			if (key == "left" or key == "a") then
2638				pausemenuselected2 = 1
2639			elseif (key == "right" or key == "d") then
2640				pausemenuselected2 = 2
2641			elseif (key == "return" or key == "enter" or key == "kpenter" or key == " ") then
2642				if pausemenuselected2 == 1 then
2643					love.audio.stop()
2644					suspendgame()
2645					suspendprompt = false
2646					pausemenuopen = false
2647				else
2648					suspendprompt = false
2649				end
2650			elseif key == "escape" then
2651				suspendprompt = false
2652			end
2653			return
2654		end
2655		if (key == "down" or key == "s") then
2656			if pausemenuselected < #pausemenuoptions then
2657				pausemenuselected = pausemenuselected + 1
2658			end
2659		elseif (key == "up" or key == "w") then
2660			if pausemenuselected > 1 then
2661				pausemenuselected = pausemenuselected - 1
2662			end
2663		elseif (key == "return" or key == "enter" or key == "kpenter" or key == " ") then
2664			if pausemenuoptions[pausemenuselected] == "resume" then
2665				pausemenuopen = false
2666				love.audio.resume()
2667			elseif pausemenuoptions[pausemenuselected] == "suspend" then
2668				suspendprompt = true
2669				pausemenuselected2 = 1
2670			elseif pausemenuoptions2[pausemenuselected] == "menu" then
2671				menuprompt = true
2672				pausemenuselected2 = 1
2673			elseif pausemenuoptions2[pausemenuselected] == "desktop" then
2674				desktopprompt = true
2675				pausemenuselected2 = 1
2676			end
2677		elseif key == "escape" then
2678			pausemenuopen = false
2679			love.audio.resume()
2680		elseif (key == "right" or key == "d") then
2681			if pausemenuoptions[pausemenuselected] == "volume" then
2682				if volume < 1 then
2683					volume = volume + 0.1
2684					love.audio.setVolume( volume )
2685					soundenabled = true
2686					playsound(coinsound)
2687				end
2688			end
2689
2690		elseif (key == "left" or key == "a") then
2691			if pausemenuoptions[pausemenuselected] == "volume" then
2692				volume = math.max(volume - 0.1, 0)
2693				love.audio.setVolume( volume )
2694				if volume == 0 then
2695					soundenabled = false
2696				end
2697				playsound(coinsound)
2698			end
2699		end
2700
2701		return
2702	end
2703
2704	if endpressbutton then
2705		endpressbutton = false
2706		endgame()
2707		return
2708	end
2709
2710	for i = 1, players do
2711		if controls[i]["jump"][1] == key then
2712			objects["player"][i]:jump()
2713		elseif controls[i]["run"][1] == key then
2714			objects["player"][i]:fire()
2715		elseif controls[i]["reload"][1] == key then
2716			objects["player"][i]:removeportals()
2717		elseif controls[i]["use"][1] == key then
2718			objects["player"][i]:use()
2719		elseif controls[i]["left"][1] == key then
2720			objects["player"][i]:leftkey()
2721		elseif controls[i]["right"][1] == key then
2722			objects["player"][i]:rightkey()
2723		end
2724
2725		if controls[i]["portal1"][i] == key then
2726			shootportal(i, 1, objects["player"][i].x+6/16, objects["player"][i].y+6/16, objects["player"][i].pointingangle)
2727			return
2728		end
2729
2730		if controls[i]["portal2"][i] == key then
2731			shootportal(i, 2, objects["player"][i].x+6/16, objects["player"][i].y+6/16, objects["player"][i].pointingangle)
2732			return
2733		end
2734	end
2735
2736	if key == "escape" then
2737		if not editormode and testlevel then
2738			marioworld = testlevelworld
2739			mariolevel = testlevellevel
2740			testlevel = false
2741			editormode = true
2742			startlevel(marioworld .. "-" .. mariolevel)
2743			return
2744		elseif not editormode and not everyonedead then
2745			pausemenuopen = true
2746			love.audio.pause()
2747			playsound(pausesound)
2748		end
2749	end
2750
2751	if editormode then
2752		editor_keypressed(key)
2753	end
2754end
2755
2756function game_keyreleased(key, unicode)
2757	for i = 1, players do
2758		if controls[i]["jump"][1] == key then
2759			objects["player"][i]:stopjump()
2760		end
2761	end
2762end
2763
2764function createportal(plnumber, i, cox, coy, side, tendency, x, y)
2765	if cox ~= false then
2766		local otheri = 1
2767		if i == 1 then
2768			otheri = 2
2769		end
2770
2771		moveoutportal(i)
2772
2773		--remove the portal temporarily so that it doesn't obstruct itself
2774		local oldx, oldy, oldfacing
2775		if i == 1 then
2776			oldx, oldy, oldfacing = objects["player"][plnumber].portal1X, objects["player"][plnumber].portal1Y, objects["player"][plnumber].portal1facing
2777			objects["player"][plnumber].portal1X, objects["player"][plnumber].portal1Y = false, false
2778		else
2779			oldx, oldy, oldfacing = objects["player"][plnumber].portal2X, objects["player"][plnumber].portal2Y, objects["player"][plnumber].portal2facing
2780			objects["player"][plnumber].portal2X, objects["player"][plnumber].portal2Y = false, false
2781		end
2782
2783		local newx, newy = getportalposition(i, cox, coy, side, tendency)
2784
2785		if newx and (newx ~= oldx or newy ~= oldy or side ~= oldfacing) then
2786			if i == 1 then
2787				objects["player"][plnumber].portal1X = newx
2788				objects["player"][plnumber].portal1Y = newy
2789				objects["player"][plnumber].portal1facing = side
2790			else
2791				objects["player"][plnumber].portal2X = newx
2792				objects["player"][plnumber].portal2Y = newy
2793				objects["player"][plnumber].portal2facing = side
2794			end
2795
2796			--physics
2797			--Recreate old hole
2798			if oldfacing == "up" then
2799				modifyportaltiles(oldx, oldy, 1, 0, plnumber, i, "add")
2800			elseif oldfacing == "down" then
2801				modifyportaltiles(oldx, oldy, -1, 0, plnumber, i, "add")
2802			elseif oldfacing == "left" then
2803				modifyportaltiles(oldx, oldy, 0, -1, plnumber, i, "add")
2804			elseif oldfacing == "right" then
2805				modifyportaltiles(oldx, oldy, 0, 1, plnumber, i, "add")
2806			end
2807
2808			--Create and remove new stuff
2809			if side == "up" then
2810				objects["portalwall"][plnumber .. "-" .. i .. "-1"] = portalwall:new(newx-1, newy, 2, 0, true)
2811				objects["portalwall"][plnumber .. "-" .. i .. "-2"] = portalwall:new(newx-1, newy-1, 0, 1, true)
2812				objects["portalwall"][plnumber .. "-" .. i .. "-3"] = portalwall:new(newx+1, newy-1, 0, 1, true)
2813
2814				modifyportaltiles(newx, newy, 1, 0, plnumber, i, "remove")
2815			elseif side == "down" then
2816				objects["portalwall"][plnumber .. "-" .. i .. "-1"] = portalwall:new(newx-2, newy-1, 2, 0, true)
2817				objects["portalwall"][plnumber .. "-" .. i .. "-2"] = portalwall:new(newx-2, newy-1, 0, 1, true)
2818				objects["portalwall"][plnumber .. "-" .. i .. "-3"] = portalwall:new(newx, newy-1, 0, 1, true)
2819
2820				modifyportaltiles(newx, newy, -1, 0, plnumber, i, "remove")
2821			elseif side == "left" then
2822				objects["portalwall"][plnumber .. "-" .. i .. "-1"] = portalwall:new(newx, newy-2, 0, 2, true)
2823				objects["portalwall"][plnumber .. "-" .. i .. "-2"] = portalwall:new(newx-1, newy-2, 1, 0, true)
2824				objects["portalwall"][plnumber .. "-" .. i .. "-3"] = portalwall:new(newx-1, newy, 1, 0, true)
2825
2826				modifyportaltiles(newx, newy, 0, -1, plnumber, i, "remove")
2827			elseif side == "right" then
2828				objects["portalwall"][plnumber .. "-" .. i .. "-1"] = portalwall:new(newx-1, newy-1, 0, 2, true)
2829				objects["portalwall"][plnumber .. "-" .. i .. "-2"] = portalwall:new(newx-1, newy-1, 1, 0, true)
2830				objects["portalwall"][plnumber .. "-" .. i .. "-3"] = portalwall:new(newx-1, newy+1, 1, 0, true)
2831
2832				modifyportaltiles(newx, newy, 0, 1, plnumber, i, "remove")
2833			end
2834
2835			if oldx == false then --Remove blocks from other portal
2836				local x, y, side
2837				if otheri == 1 then
2838					side = objects["player"][plnumber].portal1facing
2839					x, y = objects["player"][plnumber].portal1X, objects["player"][plnumber].portal1Y
2840				else
2841					side = objects["player"][plnumber].portal2facing
2842					x, y = objects["player"][plnumber].portal2X, objects["player"][plnumber].portal2Y
2843				end
2844
2845				if side == "up" then
2846					modifyportaltiles(x, y, 1, 0, plnumber, otheri, "remove")
2847				elseif side == "down" then
2848					modifyportaltiles(x, y, -1, 0, plnumber, otheri, "remove")
2849				elseif side == "left" then
2850					modifyportaltiles(x, y, 0, -1, plnumber, otheri, "remove")
2851				elseif side == "right" then
2852					modifyportaltiles(x, y, 0, 1, plnumber, otheri, "remove")
2853				end
2854			end
2855
2856			objects["player"][plnumber].lastportal = i
2857
2858			if i == 1 then
2859				playsound(portal1opensound)
2860			else
2861				playsound(portal2opensound)
2862			end
2863
2864
2865			for i, v in pairs(objects["lightbridge"]) do
2866				v:updaterange()
2867			end
2868
2869			for i, v in pairs(objects["laser"]) do
2870				v:updaterange()
2871			end
2872		else
2873			--recreate the temporarily removed portal
2874			if i == 1 then
2875				objects["player"][plnumber].portal1X, objects["player"][plnumber].portal1Y = oldx, oldy
2876			else
2877				objects["player"][plnumber].portal2X, objects["player"][plnumber].portal2Y = oldx, oldy
2878			end
2879		end
2880	end
2881end
2882
2883function shootportal(plnumber, i, sourcex, sourcey, direction)
2884	--box
2885	if objects["player"][plnumber].pickup then
2886		return
2887	end
2888	--portalgun delay
2889	if portaldelay[plnumber] > 0 then
2890		return
2891	else
2892		portaldelay[plnumber] = portalgundelay
2893	end
2894
2895	local otheri = 1
2896	local color = objects["player"][plnumber].portal2color
2897	if i == 1 then
2898		otheri = 2
2899		color = objects["player"][plnumber].portal1color
2900	end
2901
2902	local cox, coy, side, tendency, x, y = traceline(sourcex, sourcey, direction)
2903	table.insert(portalprojectiles, portalprojectile:new(sourcex, sourcey, x, y, color, true, {plnumber, i, cox, coy, side, tendency, x, y}))
2904end
2905
2906function game_mousepressed(x, y, button)
2907	if pausemenuopen then
2908		return
2909	end
2910	if editormode and editorstate ~= "portalgun" then
2911		editor_mousepressed(x, y, button)
2912	else
2913		if editormode then
2914			editor_mousepressed(x, y, button)
2915		end
2916
2917		if not noupdate and objects["player"][mouseowner] and objects["player"][mouseowner].controlsenabled and objects["player"][mouseowner].vine == false then
2918
2919			if button == "l" or button == "r" and objects["player"][mouseowner] then
2920				--knockback
2921				if portalknockback then
2922					local xadd = math.sin(objects["player"][mouseowner].pointingangle)*30
2923					local yadd = math.cos(objects["player"][mouseowner].pointingangle)*30
2924					objects["player"][mouseowner].speedx = objects["player"][mouseowner].speedx + xadd
2925					objects["player"][mouseowner].speedy = objects["player"][mouseowner].speedy + yadd
2926					objects["player"][mouseowner].falling = true
2927					objects["player"][mouseowner].animationstate = "falling"
2928					objects["player"][mouseowner]:setquad()
2929				end
2930			end
2931
2932			if button == "l" then
2933				if playertype == "portal" then
2934					local sourcex = objects["player"][mouseowner].x+6/16
2935					local sourcey = objects["player"][mouseowner].y+6/16
2936					local direction = objects["player"][mouseowner].pointingangle
2937
2938					shootportal(mouseowner, 1, sourcex, sourcey, direction)
2939				elseif playertype == "minecraft" then
2940					local v = objects["player"][mouseowner]
2941					local sourcex, sourcey = v.x+6/16, v.y+6/16
2942					local cox, coy, side, tend, x, y = traceline(sourcex, sourcey, v.pointingangle)
2943
2944					if cox then
2945						local dist = math.sqrt((v.x+v.width/2 - x)^2 + (v.y+v.height/2 - y)^2)
2946						if dist <= minecraftrange then
2947							breakingblockX = cox
2948							breakingblockY = coy
2949							breakingblockprogress = 0
2950						end
2951					end
2952				end
2953
2954			elseif button == "r" then
2955				if playertype == "portal" then
2956					local sourcex = objects["player"][mouseowner].x+6/16
2957					local sourcey = objects["player"][mouseowner].y+6/16
2958					local direction = objects["player"][mouseowner].pointingangle
2959
2960					shootportal(mouseowner, 2, sourcex, sourcey, direction)
2961				elseif playertype == "minecraft" then
2962					local v = objects["player"][mouseowner]
2963					local sourcex, sourcey = v.x+6/16, v.y+6/16
2964					local cox, coy, side, tend, x, y = traceline(sourcex, sourcey, v.pointingangle)
2965
2966					if cox then
2967						local dist = math.sqrt((v.x+v.width/2 - x)^2 + (v.y+v.height/2 - y)^2)
2968						if dist <= minecraftrange then
2969							placeblock(cox, coy, side)
2970						end
2971					end
2972				end
2973			end
2974		end
2975
2976		if button == "wd" then
2977			if playertype == "minecraft" then
2978				mccurrentblock = mccurrentblock + 1
2979				if mccurrentblock >= 10 then
2980					mccurrentblock = 1
2981				end
2982			elseif bullettime then
2983				speedtarget = speedtarget - 0.1
2984				if speedtarget < 0.1 then
2985					speedtarget = 0.1
2986				end
2987			end
2988		elseif button == "wu" then
2989			if playertype == "minecraft" then
2990				mccurrentblock = mccurrentblock - 1
2991				if mccurrentblock <= 0 then
2992					mccurrentblock = 9
2993				end
2994			elseif bullettime then
2995				speedtarget = speedtarget + 0.1
2996				if speedtarget > 1 then
2997					speedtarget = 1
2998				end
2999			end
3000		end
3001	end
3002end
3003
3004function modifyportalwalls()
3005	--Create and remove new stuff
3006	if side == "up" then
3007		if getTile(newx-1, newy, nil, true, side) == false then
3008			objects["portalwall"][plnumber .. "-" .. i .. "-1"] = portalwall:new(newx-1, newy-1, 0, 1, true)
3009		end
3010		if getTile(newx, newy+1, nil, true, side) == false then
3011			objects["portalwall"][plnumber .. "-" .. i .. "-2"] = portalwall:new(newx-1, newy, 1, 0, true)
3012		end
3013		if getTile(newx+1, newy+1, nil, true, side) == false then
3014			objects["portalwall"][plnumber .. "-" .. i .. "-3"] = portalwall:new(newx, newy, 1, 0, true)
3015		end
3016		if getTile(newx+2, newy, nil, true, side) == false then
3017			objects["portalwall"][plnumber .. "-" .. i .. "-4"] = portalwall:new(newx+1, newy-1, 0, 1, true)
3018		end
3019
3020		modifyportaltiles(newx, newy, 1, 0, plnumber, i, "remove")
3021	elseif side == "down" then
3022		objects["portalwall"][plnumber .. "-" .. i .. "-1"] = portalwall:new(newx-2, newy-1, 2, 0, true)
3023		objects["portalwall"][plnumber .. "-" .. i .. "-2"] = portalwall:new(newx-2, newy-1, 0, 1, true)
3024		objects["portalwall"][plnumber .. "-" .. i .. "-3"] = portalwall:new(newx, newy-1, 0, 1, true)
3025
3026		modifyportaltiles(newx, newy, -1, 0, plnumber, i, "remove")
3027	elseif side == "left" then
3028		objects["portalwall"][plnumber .. "-" .. i .. "-1"] = portalwall:new(newx, newy-2, 0, 2, true)
3029		objects["portalwall"][plnumber .. "-" .. i .. "-2"] = portalwall:new(newx-1, newy-2, 1, 0, true)
3030		objects["portalwall"][plnumber .. "-" .. i .. "-3"] = portalwall:new(newx-1, newy, 1, 0, true)
3031
3032		modifyportaltiles(newx, newy, 0, -1, plnumber, i, "remove")
3033	elseif side == "right" then
3034		objects["portalwall"][plnumber .. "-" .. i .. "-1"] = portalwall:new(newx-1, newy-1, 0, 2, true)
3035		objects["portalwall"][plnumber .. "-" .. i .. "-2"] = portalwall:new(newx-1, newy-1, 1, 0, true)
3036		objects["portalwall"][plnumber .. "-" .. i .. "-3"] = portalwall:new(newx-1, newy+1, 1, 0, true)
3037
3038		modifyportaltiles(newx, newy, 0, 1, plnumber, i, "remove")
3039	end
3040end
3041
3042function modifyportaltiles(x, y, xplus, yplus, plnumber, i, mode)
3043	if i == 1 then
3044		if objects["player"][plnumber].portal2facing ~= nil then
3045			if mode == "add" then
3046				objects["tile"][x .. "-" .. y] = tile:new(x-1, y-1, 1, 1, true)
3047				objects["tile"][x+xplus .. "-" .. y+yplus] = tile:new(x-1+xplus, y-1+yplus, 1, 1, true)
3048			else
3049				objects["tile"][x .. "-" .. y] = nil
3050				objects["tile"][x+xplus .. "-" .. y+yplus] = nil
3051			end
3052		end
3053	else
3054		if objects["player"][plnumber].portal1facing ~= nil then
3055			if mode == "add" then
3056				objects["tile"][x .. "-" .. y] = tile:new(x-1, y-1, 1, 1, true)
3057				objects["tile"][x+xplus .. "-" .. y+yplus] = tile:new(x-1+xplus, y-1+yplus, 1, 1, true)
3058			else
3059				objects["tile"][x .. "-" .. y] = nil
3060				objects["tile"][x+xplus .. "-" .. y+yplus] = nil
3061			end
3062		end
3063	end
3064end
3065
3066function getportalposition(i, x, y, side, tendency) --returns the "optimal" position according to the parsed arguments (or false if no possible position was found)
3067	local xplus, yplus = 0, 0
3068	if side == "up" then
3069		yplus = -1
3070	elseif side == "right" then
3071		xplus = 1
3072	elseif side == "down" then
3073		yplus = 1
3074	elseif side == "left" then
3075		xplus = -1
3076	end
3077
3078	if side == "up" or side == "down" then
3079		if tendency == -1 then
3080			if getTile(x-1, y, true, true, side) == true and getTile(x, y, true, true, side) == true and getTile(x-1, y+yplus, nil, false, side) == false and getTile(x, y+yplus, nil, false, side) == false then
3081				if side == "up" then
3082					return x-1, y
3083				else
3084					return x, y
3085				end
3086			elseif getTile(x, y, true, true, side) == true and getTile(x+1, y, true, true, side) == true and getTile(x, y+yplus, nil, false, side) == false and getTile(x+1, y+yplus, nil, false, side) == false then
3087				if side == "up" then
3088					return x, y
3089				else
3090					return x+1, y
3091				end
3092			end
3093		else
3094			if getTile(x, y, true, true, side) == true and getTile(x+1, y, true, true, side) == true and getTile(x, y+yplus, nil, false, side) == false and getTile(x+1, y+yplus, nil, false, side) == false then
3095				if side == "up" then
3096					return x, y
3097				else
3098					return x+1, y
3099				end
3100			elseif getTile(x-1, y, true, true, side) == true and getTile(x, y, true, true, side) == true and getTile(x-1, y+yplus, nil, false, side) == false and getTile(x, y+yplus, nil, false, side) == false then
3101				if side == "up" then
3102					return x-1, y
3103				else
3104					return x, y
3105				end
3106			end
3107		end
3108	else
3109		if tendency == -1 then
3110			if getTile(x, y-1, true, true, side) == true and getTile(x, y, true, true, side) == true and getTile(x+xplus, y-1, nil, false, side) == false and getTile(x+xplus, y, nil, false, side) == false then
3111				if side == "right" then
3112					return x, y-1
3113				else
3114					return x, y
3115				end
3116			elseif getTile(x, y, true, true, side) == true and getTile(x, y+1, true, true, side) == true and getTile(x+xplus, y, nil, false, side) == false and getTile(x+xplus, y+1, nil, false, side) == false then
3117				if side == "right" then
3118					return x, y
3119				else
3120					return x, y+1
3121				end
3122			end
3123		else
3124			if getTile(x, y, true, true, side) == true and getTile(x, y+1, true, true, side) == true and getTile(x+xplus, y, nil, false, side) == false and getTile(x+xplus, y+1, nil, false, side) == false then
3125				if side == "right" then
3126					return x, y
3127				else
3128					return x, y+1
3129				end
3130			elseif getTile(x, y-1, true, true, side) == true and getTile(x, y, true, true, side) == true and getTile(x+xplus, y-1, nil, false, side) == false and getTile(x+xplus, y, nil, false, side) == false then
3131				if side == "right" then
3132					return x, y-1
3133				else
3134					return x, y
3135				end
3136			end
3137		end
3138	end
3139
3140	return false
3141end
3142
3143function getTile(x, y, portalable, portalcheck, facing) --returns masktable value of block (As well as the ID itself as second return parameter) also includes a portalcheck and returns false if a portal is on that spot.
3144	--Portal on same tile doesn't work so well yet (collision code, of course), so:
3145	--facing = nil
3146
3147	if portalcheck then
3148		for i, v in pairs(objects["player"]) do
3149			--Get the extra block of each portal
3150			local portal1xplus, portal1yplus, portal2xplus, portal2yplus = 0, 0, 0, 0
3151			if v.portal1facing == "up" then
3152				portal1xplus = 1
3153			elseif v.portal1facing == "right" then
3154				portal1yplus = 1
3155			elseif v.portal1facing == "down" then
3156				portal1xplus = -1
3157			elseif v.portal1facing == "left" then
3158				portal1yplus = -1
3159			end
3160
3161			if v.portal2facing == "up" then
3162				portal2xplus = 1
3163			elseif v.portal2facing == "right" then
3164				portal2yplus = 1
3165			elseif v.portal2facing == "down" then
3166				portal2xplus = -1
3167			elseif v.portal2facing == "left" then
3168				portal2yplus = -1
3169			end
3170
3171			if v.portal1X ~= false then
3172				if (x == v.portal1X or x == v.portal1X+portal1xplus) and (y == v.portal1Y or y == v.portal1Y+portal1yplus) then--and (facing == nil or v.portal1facing == facing) then
3173					return false
3174				end
3175			end
3176
3177			if v.portal2X ~= false then
3178				if (x == v.portal2X or x == v.portal2X+portal2xplus) and (y == v.portal2Y or y == v.portal2Y+portal2yplus) then--and (facing == nil or v.portal2facing == facing) then
3179					return false
3180				end
3181			end
3182		end
3183	end
3184
3185	--check for tubes
3186	for i, v in pairs(objects["geldispenser"]) do
3187		if (x == v.cox or x == v.cox+1) and (y == v.coy or y == v.coy+1) then
3188			if portalcheck then
3189				return false
3190			else
3191				return true
3192			end
3193		end
3194	end
3195
3196	for i, v in pairs(objects["cubedispenser"]) do
3197		if (x == v.cox or x == v.cox+1) and (y == v.coy or y == v.coy+1) then
3198			if portalcheck then
3199				return false
3200			else
3201				return true
3202			end
3203		end
3204	end
3205
3206	--bonusstage thing for keeping it from fucking up.
3207	if bonusstage then
3208		if y == 15 and (x == 4 or x == 6) then
3209			if portalcheck then
3210				return false
3211			else
3212				return true
3213			end
3214		end
3215	end
3216
3217	if x <= 0 or y <= 0 or y >= 16 or x > mapwidth then
3218		return false, 1
3219	end
3220
3221	if tilequads[map[x][y][1]].invisible then
3222		return false
3223	end
3224
3225	if portalcheck then
3226		local side
3227		if facing == "up" then
3228			side = "top"
3229		elseif facing == "right" then
3230			side = "right"
3231		elseif facing == "down" then
3232			side = "bottom"
3233		elseif facing == "left" then
3234			side = "left"
3235		end
3236
3237		--To stop people from portalling under the vine, which caused problems, but was fixed elsewhere (and betterer)
3238		--[[for i, v in pairs(objects["vine"]) do
3239			if x == v.cox and y == v.coy and side == "top" then
3240				return false, 1
3241			end
3242		end--]]
3243
3244
3245		if map[x][y]["gels"][side] == 3 then
3246			return true, map[x][y][1]
3247		else
3248			return tilequads[map[x][y][1]].collision and tilequads[map[x][y][1]].portalable, map[x][y][1]
3249		end
3250	else
3251		return tilequads[map[x][y][1]].collision, map[x][y][1]
3252	end
3253end
3254
3255function getPortal(x, y) --returns the block where you'd come out when you'd go in the argument's block
3256	for i, v in pairs(objects["player"]) do
3257		if v.portal1X ~= false and v.portal2X ~= false then
3258			--Get the extra block of each portal
3259			local portal1xplus, portal1yplus, portal2xplus, portal2yplus = 0, 0, 0, 0
3260			if v.portal1facing == "up" then
3261				portal1xplus = 1
3262			elseif v.portal1facing == "right" then
3263				portal1yplus = 1
3264			elseif v.portal1facing == "down" then
3265				portal1xplus = -1
3266			elseif v.portal1facing == "left" then
3267				portal1yplus = -1
3268			end
3269
3270			if v.portal2facing == "up" then
3271				portal2xplus = 1
3272			elseif v.portal2facing == "right" then
3273				portal2yplus = 1
3274			elseif v.portal2facing == "down" then
3275				portal2xplus = -1
3276			elseif v.portal2facing == "left" then
3277				portal2yplus = -1
3278			end
3279
3280			if v.portal1X ~= false then
3281				if (x == v.portal1X or x == v.portal1X+portal1xplus) and (y == v.portal1Y or y == v.portal1Y+portal1yplus) and (facing == nil or v.portal1facing == facing) then
3282					if v.portal1facing ~= v.portal2facing then
3283						local xplus, yplus = 0, 0
3284						if v.portal1facing == "left" or v.portal1facing == "right" then
3285							if y == v.portal1Y then
3286								if v.portal2facing == "left" or v.portal2facing == "right" then
3287									yplus = portal2yplus
3288								else
3289									xplus = portal2xplus
3290								end
3291							end
3292
3293							return v.portal2X+xplus, v.portal2Y+yplus, v.portal2facing, v.portal1facing
3294						else
3295							if x == v.portal1X then
3296								if v.portal2facing == "left" or v.portal2facing == "right" then
3297									yplus = portal2yplus
3298								else
3299									xplus = portal2xplus
3300								end
3301							end
3302
3303							return v.portal2X+xplus, v.portal2Y+yplus, v.portal2facing, v.portal1facing
3304						end
3305					else
3306						return v.portal2X+(x-v.portal1X), v.portal2Y+(y-v.portal1Y), v.portal2facing, v.portal1facing
3307					end
3308				end
3309			end
3310
3311			if v.portal2X ~= false then
3312				if (x == v.portal2X or x == v.portal2X+portal2xplus) and (y == v.portal2Y or y == v.portal2Y+portal2yplus) and (facing == nil or v.portal2facing == facing) then
3313					if v.portal1facing ~= v.portal2facing then
3314						local xplus, yplus = 0, 0
3315						if v.portal2facing == "left" or v.portal2facing == "right" then
3316							if y == v.portal2Y then
3317								if v.portal1facing == "left" or v.portal1facing == "right" then
3318									yplus = portal1yplus
3319								else
3320									xplus = portal1xplus
3321								end
3322							end
3323
3324							return v.portal1X+xplus, v.portal1Y+yplus, v.portal1facing, v.portal2facing
3325						else
3326							if x == v.portal2X then
3327								if v.portal1facing == "left" or v.portal1facing == "right" then
3328									yplus = portal1yplus
3329								else
3330									xplus = portal1xplus
3331								end
3332							end
3333
3334							return v.portal1X+xplus, v.portal1Y+yplus, v.portal1facing, v.portal2facing
3335						end
3336					else
3337						return v.portal1X+(x-v.portal2X), v.portal1Y+(y-v.portal2Y), v.portal1facing, v.portal2facing
3338					end
3339				end
3340			end
3341		end
3342	end
3343
3344	return false
3345end
3346
3347function insideportal(x, y, width, height) --returns whether an object is in, and which, portal.
3348	if width == nil then
3349		width = 12/16
3350	end
3351	if height == nil then
3352		height = 12/16
3353	end
3354	for i, v in pairs(objects["player"]) do
3355		if v.portal1X ~= false and v.portal2X ~= false then
3356			for j = 1, 2 do
3357				local portalx, portaly, portalfacing
3358				if j == 1 then
3359					portalx = v.portal1X
3360					portaly = v.portal1Y
3361					portalfacing = v.portal1facing
3362				else
3363					portalx = v.portal2X
3364					portaly = v.portal2Y
3365					portalfacing = v.portal2facing
3366				end
3367
3368				if portalfacing == "up" then
3369					xplus = 1
3370				elseif portalfacing == "down" then
3371					xplus = -1
3372				elseif portalfacing == "left" then
3373					yplus = -1
3374				end
3375
3376				if portalfacing == "right" then
3377					if (math.floor(y) == portaly or math.floor(y) == portaly-1) and inrange(x, portalx-width, portalx, false) then
3378						return i, j
3379					end
3380				elseif portalfacing == "left" then
3381					if (math.floor(y) == portaly-1 or math.floor(y) == portaly-2) and inrange(x, portalx-1-width, portalx-1, false) then
3382						return i, j
3383					end
3384				elseif portalfacing == "up" then
3385					if inrange(y, portaly-height-1, portaly-1, false) and inrange(x, portalx-1.5-.2, portalx+.5+.2, true) then
3386						return i, j
3387					end
3388				elseif portalfacing == "down" then
3389					if inrange(y, portaly-height, portaly, false) and inrange(x, portalx-2, portalx-.5, true) then
3390						return i, j
3391					end
3392				end
3393
3394				--widen rect by 3 pixels?
3395
3396			end
3397		end
3398	end
3399
3400	return false
3401end
3402
3403function moveoutportal(p0) --pushes objects out of the portal i in.
3404	for i, v in pairs(objects) do
3405		if i ~= "tile" and i ~= "portalwall" then
3406			for j, w in pairs(v) do
3407				if w.active and w.static == false then
3408					local p1, p2 = insideportal(w.x, w.y, w.width, w.height)
3409
3410					if p1 ~= false and p2 == p0 then
3411						local portalfacing, portalx, portaly
3412						if p2 == 1 then
3413							portalfacing = objects["player"][p1].portal1facing
3414							portalx = objects["player"][p1].portal1X
3415							portaly = objects["player"][p1].portal1Y
3416						else
3417							portalfacing = objects["player"][p1].portal2facing
3418							portalx = objects["player"][p1].portal2X
3419							portaly = objects["player"][p1].portal2Y
3420						end
3421
3422						if portalfacing == "right" then
3423							w.x = portalx
3424						elseif portalfacing == "left" then
3425							w.x = portalx - 1 - w.width
3426						elseif portalfacing == "up" then
3427							w.y = portaly - 1 - w.height
3428						elseif portalfacing == "down" then
3429							w.y = portaly
3430						end
3431					end
3432				end
3433			end
3434		end
3435	end
3436end
3437
3438function nextlevel()
3439	love.audio.stop()
3440	mariolevel = mariolevel + 1
3441	if mariolevel > 4 then
3442		mariolevel = 1
3443		marioworld = marioworld + 1
3444	end
3445	levelscreen_load("next")
3446end
3447
3448function warpzone(i)
3449	love.audio.stop()
3450	mariolevel = 1
3451	marioworld = i
3452	mariosublevel = 0
3453	prevsublevel = false
3454
3455	-- minus 1 world glitch just because I can.
3456	if not displaywarpzonetext and i == 4 then
3457		marioworld = "M"
3458	end
3459
3460	levelscreen_load("next")
3461end
3462
3463function game_mousereleased(x, y, button)
3464	if button == "l" then
3465		if playertype == "minecraft" then
3466			breakingblockX = false
3467		end
3468	end
3469
3470	if editormode then
3471		editor_mousereleased(x, y, button)
3472	end
3473end
3474
3475function getMouseTile(x, y)
3476	local xout = math.floor((x+xscroll*16*scale)/(16*scale))+1
3477	local yout = math.floor((y-yoffset*scale)/(16*scale))+1
3478	return xout, yout
3479end
3480
3481function savemap(filename)
3482	local s = ""
3483	for y = 1, 15 do
3484		for x = 1, mapwidth do
3485			if y ~= 15 or x ~= mapwidth then
3486				for i = 1, #map[x][y] do
3487					s = s .. tostring(map[x][y][i])
3488					if i ~= #map[x][y] then
3489						s = s .. "-"
3490					end
3491				end
3492				s = s .. ","
3493			else
3494				for i = 1, #map[x][y] do
3495					s = s .. tostring(map[x][y][i])
3496					if i ~= #map[x][y] then
3497						s = s .. "-"
3498					end
3499				end
3500			end
3501		end
3502	end
3503
3504	--options
3505	s = s .. ";background=" .. background
3506	s = s .. ";spriteset=" .. spriteset
3507	s = s .. ";music=" .. musici
3508	if intermission then
3509		s = s .. ";intermission"
3510	end
3511	if bonusstage then
3512		s = s .. ";bonusstage"
3513	end
3514	if haswarpzone then
3515		s = s .. ";haswarpzone"
3516	end
3517	if underwater then
3518		s = s .. ";underwater"
3519	end
3520	if custombackground then
3521		s = s .. ";custombackground"
3522	end
3523	s = s .. ";timelimit=" .. mariotimelimit
3524	s = s .. ";scrollfactor=" .. scrollfactor
3525
3526	--tileset
3527
3528	love.filesystem.mkdir( "mappacks" )
3529	love.filesystem.mkdir( "mappacks/" .. mappack )
3530
3531	love.filesystem.write("mappacks/" .. mappack .. "/" .. filename .. ".txt", s)
3532	print("Map saved as " .. "mappacks/" .. filename .. ".txt")
3533end
3534
3535function savelevel()
3536	if mariosublevel == 0 then
3537		savemap(marioworld .. "-" .. mariolevel)
3538	else
3539		savemap(marioworld .. "-" .. mariolevel .. "_" .. mariosublevel)
3540	end
3541end
3542
3543function traceline(sourcex, sourcey, radians)
3544	local currentblock = {}
3545	local x, y = sourcex, sourcey
3546	currentblock[1] = math.floor(x)
3547	currentblock[2] = math.floor(y+1)
3548
3549	local emancecollide = false
3550	for i, v in pairs(emancipationgrills) do
3551		if v:getTileInvolved(currentblock[1]+1, currentblock[2]) then
3552			emancecollide = true
3553		end
3554	end
3555
3556	local doorcollide = false
3557	for i, v in pairs(objects["door"]) do
3558		if v.dir == "hor" then
3559			if v.open == false and (v.cox == currentblock[1] or v.cox == currentblock[1]+1) and v.coy == currentblock[2] then
3560				doorcollide = true
3561			end
3562		else
3563			if v.open == false and v.cox == currentblock[1]+1 and (v.coy == currentblock[2] or v.coy == currentblock[2]+1) then
3564				doorcollide = true
3565			end
3566		end
3567	end
3568
3569	if emancecollide or doorcollide then
3570		return false, false, false, false, x, y
3571	end
3572
3573	local side
3574
3575	while currentblock[1]+1 > 0 and currentblock[1]+1 <= mapwidth and (flagx == false or currentblock[1]+1 <= flagx) and (axex == false or currentblock[1]+1 <= axex) and (currentblock[2] > 0 or currentblock[2] >= math.floor(sourcey+0.5)) and currentblock[2] < 16 do --while in map range
3576		local oldy = y
3577		local oldx = x
3578
3579		--calculate X and Y diff..
3580		local ydiff, xdiff
3581		local side1, side2
3582
3583		if inrange(radians, -math.pi/2, math.pi/2, true) then --up
3584			ydiff = (y-(currentblock[2]-1)) / math.cos(radians)
3585			y = currentblock[2]-1
3586			side1 = "down"
3587		else
3588			ydiff = (y-(currentblock[2])) / math.cos(radians)
3589			y = currentblock[2]
3590			side1 = "up"
3591		end
3592
3593		if inrange(radians, 0, math.pi, true) then --left
3594			xdiff = (x-(currentblock[1])) / math.sin(radians)
3595			x = currentblock[1]
3596			side2 = "right"
3597		else
3598			xdiff = (x-(currentblock[1]+1)) / math.sin(radians)
3599			x = currentblock[1]+1
3600			side2 = "left"
3601		end
3602
3603		--smaller diff wins
3604
3605		if xdiff < ydiff then
3606			y = oldy - math.cos(radians)*xdiff
3607			side = side2
3608		else
3609			x = oldx - math.sin(radians)*ydiff
3610			side = side1
3611		end
3612
3613		if side == "down" then
3614			currentblock[2] = currentblock[2]-1
3615		elseif side == "up" then
3616			currentblock[2] = currentblock[2]+1
3617		elseif side == "left" then
3618			currentblock[1] = currentblock[1]+1
3619		elseif side == "right" then
3620			currentblock[1] = currentblock[1]-1
3621		end
3622
3623		local collide, tileno = getTile(currentblock[1]+1, currentblock[2])
3624		local emancecollide = false
3625		for i, v in pairs(emancipationgrills) do
3626			if v:getTileInvolved(currentblock[1]+1, currentblock[2]) then
3627				emancecollide = true
3628			end
3629		end
3630
3631		local doorcollide = false
3632		for i, v in pairs(objects["door"]) do
3633			if v.dir == "hor" then
3634				if v.open == false and (v.cox == currentblock[1] or v.cox == currentblock[1]+1) and v.coy == currentblock[2] then
3635					doorcollide = true
3636				end
3637			else
3638				if v.open == false and v.cox == currentblock[1]+1 and (v.coy == currentblock[2] or v.coy == currentblock[2]+1) then
3639					doorcollide = true
3640				end
3641			end
3642		end
3643
3644		if collide == true then
3645			break
3646		elseif emancecollide or doorcollide then
3647			return false, false, false, false, x, y
3648		elseif x > xscroll + width or x < xscroll then
3649			return false, false, false, false, x, y
3650		end
3651	end
3652
3653	if currentblock[1]+1 > 0 and currentblock[1]+1 <= mapwidth and (currentblock[2] > 0 or currentblock[2] >= math.floor(sourcey+0.5))  and currentblock[2] < 16 and currentblock[1] ~= nil then
3654		local tendency
3655
3656		--get tendency
3657		if side == "down" or side == "up" then
3658			if math.mod(x, 1) > 0.5 then
3659				tendency = 1
3660			else
3661				tendency = -1
3662			end
3663		elseif side == "left" or side == "right" then
3664			if math.mod(y, 1) > 0.5 then
3665				tendency = 1
3666			else
3667				tendency = -1
3668			end
3669		end
3670
3671		return currentblock[1]+1, currentblock[2], side, tendency, x, y
3672	else
3673		return false, false, false, false, x, y
3674	end
3675end
3676
3677function spawnenemy(x, y)
3678	if not inmap(x, y) then
3679		return
3680	end
3681
3682	for i = 1, #enemiesspawned do
3683		if x == enemiesspawned[i][1] and y == enemiesspawned[i][2] then
3684			return
3685		end
3686	end
3687
3688	local t = map[x][y]
3689	if #t > 1 then
3690		local enemy = true
3691		local i = entityquads[t[2]].t
3692		if i == "goomba" then
3693			table.insert(objects["goomba"], goomba:new(x-0.5, y-1/16))
3694		elseif i == "goombahalf" then
3695			table.insert(objects["goomba"], goomba:new(x, y-1/16))
3696		elseif i == "koopa" then
3697			table.insert(objects["koopa"], koopa:new(x-0.5, y-1/16))
3698		elseif i == "koopahalf" then
3699			table.insert(objects["koopa"], koopa:new(x, y-1/16))
3700		elseif i == "koopared" then
3701			table.insert(objects["koopa"], koopa:new(x-0.5, y-1/16, "red"))
3702		elseif i == "kooparedhalf" then
3703			table.insert(objects["koopa"], koopa:new(x, y-1/16, "red"))
3704		elseif i == "beetle" then
3705			table.insert(objects["koopa"], koopa:new(x-0.5, y-1/16, "beetle"))
3706		elseif i == "beetlehalf" then
3707			table.insert(objects["koopa"], koopa:new(x, y-1/16, "beetle"))
3708		elseif i == "kooparedflying" then
3709			table.insert(objects["koopa"], koopa:new(x-.5, y-1/16, "redflying"))
3710		elseif i == "koopaflying" then
3711			table.insert(objects["koopa"], koopa:new(x-.5, y-1/16, "flying"))
3712		elseif i == "bowser" then
3713			objects["bowser"][1] = bowser:new(x, y-1/16)
3714		elseif i == "cheepred" then
3715			table.insert(objects["cheep"], cheepcheep:new(x-.5, y-1/16, 1))
3716		elseif i == "cheepwhite" then
3717			table.insert(objects["cheep"], cheepcheep:new(x-.5, y-1/16, 2))
3718		elseif i == "spikey" then
3719			table.insert(objects["goomba"], goomba:new(x-0.5, y-1/16, "spikey"))
3720		elseif i == "spikeyhalf" then
3721			table.insert(objects["goomba"], goomba:new(x, y-1/16, "spikey"))
3722		elseif i == "lakito" then
3723			table.insert(objects["lakito"], lakito:new(x, y-1/16))
3724		elseif i == "squid" then
3725			table.insert(objects["squid"], squid:new(x, y-1/16))
3726
3727		elseif i == "platformup" then
3728			table.insert(objects["platform"], platform:new(x, y, "up", t[3])) --Platform right
3729		elseif i == "platformright" then
3730			table.insert(objects["platform"], platform:new(x, y, "right", t[3])) --Platform up
3731
3732		elseif i == "platformfall" then
3733			table.insert(objects["platform"], platform:new(x, y, "fall", t[3])) --Platform up
3734
3735		elseif i == "platformbonus" then
3736			table.insert(objects["platform"], platform:new(x, y, "justright", 3))
3737
3738		elseif i == "plant" then
3739			table.insert(objects["plant"], plant:new(x, y))
3740
3741		elseif i == "castlefirecw" then
3742			table.insert(objects["castlefire"], castlefire:new(x, y, tonumber(t[3]), "cw"))
3743
3744		elseif i == "castlefireccw" then
3745			table.insert(objects["castlefire"], castlefire:new(x, y, tonumber(t[3]), "ccw"))
3746
3747		elseif i == "hammerbro" then
3748			table.insert(objects["hammerbro"], hammerbro:new(x, y))
3749
3750		elseif i == "whitegeldown" then
3751			table.insert(objects["geldispenser"], geldispenser:new(x, y, 3, "down"))
3752		elseif i == "whitegelright" then
3753			table.insert(objects["geldispenser"], geldispenser:new(x, y, 3, "right"))
3754		elseif i == "whitegelleft" then
3755			table.insert(objects["geldispenser"], geldispenser:new(x, y, 3, "left"))
3756
3757		elseif i == "bulletbill" then
3758			table.insert(rocketlaunchers, rocketlauncher:new(x, y))
3759
3760		elseif i == "bluegeldown" then
3761			table.insert(objects["geldispenser"], geldispenser:new(x, y, 1, "down"))
3762		elseif i == "bluegelright" then
3763			table.insert(objects["geldispenser"], geldispenser:new(x, y, 1, "right"))
3764		elseif i == "bluegelleft" then
3765			table.insert(objects["geldispenser"], geldispenser:new(x, y, 1, "left"))
3766
3767		elseif i == "orangegeldown" then
3768			table.insert(objects["geldispenser"], geldispenser:new(x, y, 2, "down"))
3769		elseif i == "orangegelright" then
3770			table.insert(objects["geldispenser"], geldispenser:new(x, y, 2, "right"))
3771		elseif i == "orangegelleft" then
3772			table.insert(objects["geldispenser"], geldispenser:new(x, y, 2, "left"))
3773
3774		elseif i == "upfire" then
3775			table.insert(objects["upfire"], upfire:new(x, y))
3776		else
3777
3778			enemy = false
3779		end
3780
3781		if enemy then
3782			table.insert(enemiesspawned, {x, y})
3783
3784			--spawn enemies in 5x1 line so they spawn as a unit and not alone.
3785			spawnenemy(x-2, y)
3786			spawnenemy(x-1, y)
3787			spawnenemy(x+1, y)
3788			spawnenemy(x+2, y)
3789		end
3790	end
3791end
3792
3793function item(i, x, y, size)
3794	if i == "mushroom" then
3795		if size and size > 1 then
3796			table.insert(objects["flower"], flower:new(x-0.5, y-2/16))
3797		else
3798			table.insert(objects["mushroom"], mushroom:new(x-0.5, y-2/16))
3799		end
3800
3801	elseif i == "oneup" then
3802		table.insert(objects["oneup"], oneup:new(x-0.5, y-2/16))
3803	elseif i == "star" then
3804		table.insert(objects["star"], star:new(x-0.5, y-2/16))
3805	elseif i == "vine" then
3806		table.insert(objects["vine"], vine:new(x, y))
3807	end
3808end
3809
3810function addpoints(i, x, y)
3811	if i > 0 then
3812		marioscore = marioscore + i
3813		if x ~= nil and y ~= nil then
3814			table.insert(scrollingscores, scrollingscore:new(i, x, y))
3815		end
3816	else
3817		table.insert(scrollingscores, scrollingscore:new(-i, x, y))
3818	end
3819end
3820
3821function addzeros(s, i)
3822	for j = string.len(s)+1, i do
3823		s = "0" .. s
3824	end
3825	return s
3826end
3827
3828function properprint2(s, x, y)
3829	for i = 1, string.len(tostring(s)) do
3830		if fontquads[string.sub(s, i, i)] then
3831			love.graphics.drawq(fontimage2, font2quads[string.sub(s, i, i)], x+((i-1)*4)*scale, y, 0, scale, scale)
3832		end
3833	end
3834end
3835
3836function playsound(sound)
3837	if soundenabled then
3838		sound:stop()
3839		sound:rewind()
3840		sound:play()
3841	end
3842end
3843
3844function runkey(i)
3845	local s = controls[i]["run"]
3846	return checkkey(s)
3847end
3848
3849function rightkey(i)
3850	local s = controls[i]["right"]
3851	return checkkey(s)
3852end
3853
3854function leftkey(i)
3855	local s = controls[i]["left"]
3856	return checkkey(s)
3857end
3858
3859function downkey(i)
3860	local s = controls[i]["down"]
3861	return checkkey(s)
3862end
3863
3864function upkey(i)
3865	local s = controls[i]["up"]
3866	return checkkey(s)
3867end
3868
3869function checkkey(s)
3870	if s[1] == "joy" then
3871		if s[3] == "hat" then
3872			if love.joystick.getHat(s[2], s[4]) == s[5] then
3873				return true
3874			else
3875				return false
3876			end
3877		elseif s[3] == "but" then
3878			if love.joystick.isDown(s[2], s[4]) then
3879				return true
3880			else
3881				return false
3882			end
3883		elseif s[3] == "axe" then
3884			if s[5] == "pos" then
3885				if love.joystick.getAxis(s[2], s[4]) > joystickdeadzone then
3886					return true
3887				else
3888					return false
3889				end
3890			else
3891				if love.joystick.getAxis(s[2], s[4]) < -joystickdeadzone then
3892					return true
3893				else
3894					return false
3895				end
3896			end
3897		end
3898	else
3899		if love.keyboard.isDown(s[1]) then
3900			return true
3901		else
3902			return false
3903		end
3904	end
3905end
3906
3907function game_joystickpressed( joystick, button )
3908	if pausemenuopen then
3909		return
3910	end
3911	if endpressbutton then
3912		endgame()
3913		return
3914	end
3915
3916	for i = 1, players do
3917		if not noupdate and objects["player"][i].controlsenabled and not objects["player"][i].vine then
3918			local s1 = controls[i]["jump"]
3919			local s2 = controls[i]["run"]
3920			local s3 = controls[i]["reload"]
3921			local s4 = controls[i]["use"]
3922			local s5 = controls[i]["left"]
3923			local s6 = controls[i]["right"]
3924			if s1[1] == "joy" and joystick == tonumber(s1[2]) and s1[3] == "but" and button == tonumber(s1[4]) then
3925				objects["player"][i]:jump()
3926				return
3927			elseif s2[1] == "joy" and joystick == s2[2] and s2[3] == "but" and button == s2[4] then
3928				objects["player"][i]:fire()
3929				return
3930			elseif s3[1] == "joy" and joystick == s3[2] and s3[3] == "but" and button == s3[4] then
3931				objects["player"][i]:removeportals()
3932				return
3933			elseif s4[1] == "joy" and joystick == s4[2] and s4[3] == "but" and button == s4[4] then
3934				objects["player"][i]:use()
3935				return
3936			elseif s5[1] == "joy" and joystick == s5[2] and s5[3] == "but" and button == s5[4] then
3937				objects["player"][i]:leftkey()
3938				return
3939			elseif s6[1] == "joy" and joystick == s6[2] and s6[3] == "but" and button == s6[4] then
3940				objects["player"][i]:rightkey()
3941				return
3942			end
3943
3944			local s = controls[i]["portal1"]
3945			if s and s[1] == "joy" then
3946				if s[3] == "but" then
3947					if joystick == s[2] and button == s[4] then
3948						shootportal(i, 1, objects["player"][i].x+6/16, objects["player"][i].y+6/16, objects["player"][i].pointingangle)
3949						return
3950					end
3951				end
3952			end
3953
3954			local s = controls[i]["portal2"]
3955			if s and s[1] == "joy" then
3956				if s[3] == "but" then
3957					if joystick == tonumber(s[2]) and button == tonumber(s[4]) then
3958						shootportal(i, 2, objects["player"][i].x+6/16, objects["player"][i].y+6/16, objects["player"][i].pointingangle)
3959						return
3960					end
3961				end
3962			end
3963		end
3964	end
3965end
3966
3967function game_joystickreleased( joystick, button )
3968	for i = 1, players do
3969		local s = controls[i]["jump"]
3970		if s[1] == "joy" then
3971			if s[3] == "but" then
3972				if joystick == tonumber(s[2]) and button == tonumber(s[4]) then
3973					objects["player"][i]:stopjump()
3974					return
3975				end
3976			end
3977		end
3978	end
3979end
3980
3981function inrange(i, a, b, include)
3982	if a > b then
3983		b, a = a, b
3984	end
3985
3986	if include then
3987		if i >= a and i <= b then
3988			return true
3989		else
3990			return false
3991		end
3992	else
3993		if i > a and i < b then
3994			return true
3995		else
3996			return false
3997		end
3998	end
3999end
4000
4001function adduserect(x, y, width, height, callback)
4002	local t = {}
4003	t.x = x
4004	t.y = y
4005	t.width = width
4006	t.height = height
4007	t.callback = callback
4008	t.delete = false
4009
4010	table.insert(userects, t)
4011	return t
4012end
4013
4014function userect(x, y, width, height)
4015	local outtable = {}
4016
4017	for i, v in pairs(userects) do
4018		if aabb(x, y, width, height, v.x, v.y, v.width, v.height) then
4019			table.insert(outtable, v.callback)
4020		end
4021	end
4022
4023	return outtable
4024end
4025
4026function drawrectangle(x, y, width, height)
4027	love.graphics.rectangle("fill", x*scale, y*scale, width*scale, scale)
4028	love.graphics.rectangle("fill", x*scale, y*scale, scale, height*scale)
4029	love.graphics.rectangle("fill", x*scale, (y+height-1)*scale, width*scale, scale)
4030	love.graphics.rectangle("fill", (x+width-1)*scale, y*scale, scale, height*scale)
4031end
4032
4033function inmap(x, y)
4034	if not x or not y then
4035		return false
4036	end
4037	if x >= 1 and x <= mapwidth and y >= 1 and y <= 15 then
4038		return true
4039	else
4040		return false
4041	end
4042end
4043
4044function playmusic()
4045	if musici == 7 and custommusic then
4046		music:play(custommusic)
4047	elseif musici ~= 1 then
4048		if mariotime < 100 and mariotime > 0 then
4049			music:playIndex(musici-1, true)
4050		else
4051			music:playIndex(musici-1)
4052		end
4053	end
4054end
4055
4056function stopmusic()
4057	if musici ~= 1 then
4058		if mariotime < 100 and mariotime > 0 then
4059			music:stopIndex(musici-1, true)
4060		else
4061			music:stopIndex(musici-1)
4062		end
4063	end
4064end
4065
4066function updatesizes()
4067	mariosizes = {}
4068	if not objects then
4069		for i = 1, players do
4070			mariosizes[i] = 1
4071		end
4072	else
4073		for i = 1, players do
4074			mariosizes[i] = objects["player"][i].size
4075		end
4076	end
4077end
4078
4079function hitrightside()
4080	if haswarpzone then
4081		objects["plant"] = {}
4082		displaywarpzonetext = true
4083	end
4084end
4085
4086function getclosestplayer(x)
4087	closestplayer = 1
4088	for i = 2, players do
4089		if math.abs(objects["player"][closestplayer].x+6/16-x) < math.abs(objects["player"][i].x+6/16-x) then
4090			closestplayer = i
4091		end
4092	end
4093
4094	return closestplayer
4095end
4096
4097function endgame()
4098	love.audio.stop()
4099	playertype = "minecraft"
4100	playertypei = 2
4101	gamefinished = true
4102	saveconfig()
4103	menu_load()
4104end
4105
4106--Minecraft stuff
4107
4108function placeblock(x, y, side)
4109	if side == "up" then
4110		y = y - 1
4111	elseif side == "down" then
4112		y = y + 1
4113	elseif side == "left" then
4114		x = x - 1
4115	elseif side == "right" then
4116		x = x + 1
4117	end
4118
4119	if not inmap(x, y) then
4120		return false
4121	end
4122
4123	--get block
4124	local tileno
4125	if inventory[mccurrentblock].t ~= nil then
4126		tileno = inventory[mccurrentblock].t
4127	else
4128		return false
4129	end
4130
4131	if #checkrect(x-1, y-1, 1, 1, "all") == 0 then
4132		map[x][y][1] = tileno
4133		objects["tile"][x .. "-" .. y] = tile:new(x-1, y-1, 1, 1, true)
4134		generatespritebatch()
4135
4136		inventory[mccurrentblock].count = inventory[mccurrentblock].count - 1
4137
4138		if inventory[mccurrentblock].count == 0 then
4139			inventory[mccurrentblock].t = nil
4140		end
4141
4142		return true
4143	else
4144		return false
4145	end
4146end
4147
4148function collectblock(i)
4149	local success = false
4150	for j = 1, 9 do
4151		if inventory[j].t == i and inventory[j].count < 64 then
4152			inventory[j].count = inventory[j].count+1
4153			success = true
4154			break
4155		end
4156	end
4157
4158	if not success then
4159		for j = 1, 9 do
4160			if inventory[j].t == nil then
4161				inventory[j].count = 1
4162				inventory[j].t = i
4163				success = true
4164				break
4165			end
4166		end
4167	end
4168
4169	return success
4170end
4171
4172function breakblock(x, y)
4173	--create a cute block
4174	table.insert(miniblocks, miniblock:new(x-.5, y-.2, map[x][y][1]))
4175
4176	map[x][y][1] = 1
4177	map[x][y]["gels"] = {}
4178	objects["tile"][x .. "-" .. y] = nil
4179
4180	generatespritebatch()
4181end
4182
4183function respawnplayers()
4184	if mariolivecount == false then
4185		return
4186	end
4187	for i = 1, players do
4188		if mariolives[i] == 1 and objects["player"].dead then
4189			objects["player"][i]:respawn()
4190		end
4191	end
4192end
4193