1mario = class:new()
2
3function mario:init(x, y, i, animation, size, t)
4	self.playernumber = i or 1
5	if bigmario then
6		self.size = 1
7	else
8		self.size = size or 1
9	end
10	self.t = t or "portal"
11
12	--PHYSICS STUFF
13	self.speedx = 0
14	self.speedy = 0
15	self.x = x
16	self.width = 12/16
17	self.height = 12/16
18
19	if bigmario then
20		self.width = self.width*scalefactor
21		self.height = self.height*scalefactor
22	end
23
24	self.y = y+1-self.height
25	self.static = false
26	self.active = true
27	self.category = 3
28	self.mask = {	true,
29					false, true, false, false, false,
30					false, true, false, false, false,
31					false, true, false, false, false,
32					false, false, false, false, false,
33					false, false, false, false, false,
34					false, false, false, false, false}
35
36	if playercollisions then
37		self.mask[3] = false
38	end
39
40	self.emancipatecheck = true
41
42	--IMAGE STUFF
43	self.smallgraphic = {}
44	if playertype == "minecraft" then
45		for j = 0, 3 do
46			self.smallgraphic[j] = minecraftanimations[j]
47		end
48	else
49		for j = 0, 3 do
50			self.smallgraphic[j] = marioanimations[j]
51		end
52	end
53
54	self.biggraphic = {}
55	if playertype == "minecraft" then
56		for j = 0, 3 do
57			self.biggraphic[j] = bigminecraftanimations[j]
58		end
59	else
60		for j = 0, 3 do
61			self.biggraphic[j] = bigmarioanimations[j]
62		end
63	end
64
65	self.drawable = true
66	self.quad = marioidle[3]
67	self.colors = mariocolors[self.playernumber]
68	if self.size == 1 then
69		self.offsetX = 6
70		self.offsetY = 3
71		self.quadcenterX = 11
72		self.quadcenterY = 10
73
74		self.graphic = self.smallgraphic
75	else
76		self.graphic = self.biggraphic
77
78		self.quadcenterY = 20
79		self.quadcenterX = 9
80		self.offsetY = -3
81		self.offsetX = 6
82
83		self.y = self.y - 12/16
84		self.height = 24/16
85
86		if self.size == 3 then
87			self.colors = flowercolor
88		end
89	end
90
91	if bigmario then
92		self.offsetX = self.offsetX*scalefactor
93		self.offsetY = self.offsetY*-scalefactor
94	end
95
96	--hat
97	self.hats = mariohats[self.playernumber]
98	self.drawhat = true
99
100	--Change height according to hats
101
102	--for i = 1, #self.hats do
103		--self.height = self.height + (hat[self.hats[i]].height/16)
104		--self.y = self.y - (hat[self.hats[i]].height/16)
105		--self.offsetY = self.offsetY - hat[self.hats[i]].height
106	--end
107
108	self.customscissor = nil
109
110
111	if players == 1 then
112		self.portal1color = {60, 188, 252}
113		self.portal2color = {232, 130, 30}
114	else
115		self.portal1color = portalcolor[self.playernumber][1]
116		self.portal2color = portalcolor[self.playernumber][2]
117	end
118
119	--OTHER STUFF!
120	self.controlsenabled = true
121
122	self.runframe = 3
123	self.swimframe = 1
124	self.climbframe = 1
125	self.runanimationprogress = 1
126	self.swimanimationprogress = 1
127	self.animationstate = "idle" --idle, running, jumping, falling, swimming, sliding, climbing, dead
128	self.animationdirection = "right" --left, right. duh
129	self.platform = false
130	self.combo = 1
131	self.portal1X = false
132	self.portal1Y = false
133	self.portal2X = false
134	self.portal2Y = false
135	self.portal1facing = nil
136	self.portal2facing = nil
137	self.rotation = 0 --for portals
138	self.portaldotstimer = 0
139	self.pointingangle = -math.pi/2
140	self.passivemoved = false
141	self.ducking = false
142	self.invincible = false
143	self.rainboomallowed = true
144
145	self.animation = animation --pipedown, piperight, pipeup, flag, vine, intermission
146	self.animationx = nil
147	self.animationy = nil
148	self.animationtimer = 0
149
150	self.falling = false
151	self.jumping = false
152	self.starred = false
153	self.dead = false
154	self.vine = false
155	self.spring = false
156	self.startimer = mariostarduration
157	self.starblinktimer = mariostarblinkrate
158	self.starcolori = 1
159	self.fireballcount = 0
160	self.fireanimationtimer = fireanimationtime
161
162	self.mazevar = 0
163
164	self.bubbletimer = 0
165	self.bubbletime = bubblestime[math.random(#bubblestime)]
166
167	if underwater then
168		self.gravity = uwgravity
169	end
170
171	self.controlsoverwrite = {}
172
173	if self.animation == "intermission" and editormode then
174		self.animation = nil
175	end
176
177	if mariolivecount ~= false and mariolives[self.playernumber] <= 0 then
178		self.dead = true
179		self.drawable = false
180		self.active = false
181		self.static = true
182		self.controlsenabled = false
183		self.animation = nil
184	end
185
186	if self.animation == "pipeup" then
187		self.controlsenabled = false
188		self.active = false
189		self.animationx = x
190		self.animationy = y
191		self.customscissor = {x-2.5, y-4, 6, 4}
192		self.y = self.animationy + 20/16
193
194		self.animationstate = "idle"
195		self:setquad()
196
197		if self.size > 1 then
198			self.animationy = y - 12/16
199		end
200	elseif self.animation == "intermission" then
201		self.controlsenabled = false
202		self.active = true
203		self.gravity = mariogravity
204		self.animationstate = "running"
205		self.speedx = 2.61
206		self.pointingangle = -math.pi/2
207	elseif self.animation == "vinestart" then
208		self.controlsenabled = false
209		self.active = false
210		self.pointingangle = -math.pi/2
211		self.climbframe = 2
212		self.animationstate = "climbing"
213		self:setquad()
214		self.x = 4-3/16
215		self.y = 15+0.4*(self.playernumber-1)
216		self.vineanimationclimb = false
217		self.vineanimationdropoff = false
218		self.vinemovetimer = 0
219		playsound(vinesound)
220
221		if #objects["vine"] == 0 then
222			table.insert(objects["vine"], vine:new(5, 16, "start"))
223		end
224	end
225
226	self:setquad()
227end
228
229function mario:update(dt)
230	self.passivemoved = false
231	--rotate back to 0 (portals)
232	self.rotation = math.mod(self.rotation, math.pi*2)
233
234	if self.rotation < -math.pi then
235		self.rotation = self.rotation + math.pi*2
236	elseif self.rotation > math.pi then
237		self.rotation = self.rotation - math.pi*2
238	end
239
240	if self.rotation > 0 then
241		self.rotation = self.rotation - portalrotationalignmentspeed*dt
242		if self.rotation < 0 then
243			self.rotation = 0
244		end
245	elseif self.rotation < 0 then
246		self.rotation = self.rotation + portalrotationalignmentspeed*dt
247		if self.rotation > 0 then
248			self.rotation = 0
249		end
250	end
251
252	if self.startimer < mariostarduration and not self.dead then
253		self.startimer = self.startimer + dt
254		self.starblinktimer = self.starblinktimer + dt
255
256		local lmariostarblinkrate = mariostarblinkrate
257		if self.startimer >= mariostarduration-mariostarrunout then
258			lmariostarblinkrate = mariostarblinkrateslow
259		end
260
261		while self.starblinktimer > lmariostarblinkrate do
262			self.starcolori = self.starcolori + 1
263			if self.starcolori > 4 then
264				self.starcolori = self.starcolori - 4
265			end
266			self.colors = starcolors[self.starcolori]
267
268			self.starblinktimer = self.starblinktimer - lmariostarblinkrate
269		end
270
271		if self.startimer >= mariostarduration-mariostarrunout and self.startimer-dt < mariostarduration-mariostarrunout then
272			--check if another starman is playing
273			local starstill = false
274			for i = 1, players do
275				if i ~= self.playernumber and objects["player"][i].starred then
276					starstill = true
277				end
278			end
279
280			if not starstill and not levelfinished then
281				playmusic()
282				music:stop("starmusic")
283			end
284		end
285
286		if self.startimer >= mariostarduration then
287			if self.size == 3 then --flower colors
288				self.colors = flowercolor
289			else
290				self.colors = mariocolors[self.playernumber]
291			end
292			self.starred = false
293			self.startimer = mariostarduration
294		end
295	end
296
297	--ANIMATIONS
298	if self.animation == "pipedown" then
299		self.animationtimer = self.animationtimer + dt
300		if self.animationtimer < pipeanimationtime then
301			self.y = self.animationy - 28/16 + self.animationtimer/pipeanimationtime*pipeanimationdistancedown
302		else
303			self.y = self.animationy - 28/16 + pipeanimationdistancedown
304
305			if self.animationtimer >= pipeanimationtime+pipeanimationdelay then
306				updatesizes()
307				if type(self.animationmisc) == "number" then --sublevel
308					levelscreen_load("sublevel", self.animationmisc)
309				else --warpzone
310					warpzone(tonumber(string.sub(self.animationmisc, 5, 5)))
311				end
312			end
313		end
314		return
315	elseif self.animation == "pipeup" then
316		self.animationtimer = self.animationtimer + dt
317		if self.animationtimer < pipeupdelay then
318
319		elseif self.animationtimer < pipeanimationtime+pipeupdelay then
320			self.y = self.animationy + 20/16 - (self.animationtimer-pipeupdelay)/pipeanimationtime*pipeanimationdistancedown
321		else
322			self.y = self.animationy + 20/16 - pipeanimationdistancedown
323
324			if self.animationtimer >= pipeanimationtime then
325				self.active = true
326				self.controlsenabled = true
327				self.animation = nil
328				self.customscissor = nil
329			end
330		end
331		return
332	elseif self.animation == "piperight" then
333		self.animationtimer = self.animationtimer + dt
334		if self.animationtimer < pipeanimationtime then
335			self.x = self.animationx - 28/16 + self.animationtimer/pipeanimationtime*pipeanimationdistanceright
336
337			--Run animation
338			if self.animationstate == "running" then
339				self.runanimationprogress = self.runanimationprogress + (math.abs(pipeanimationrunspeed)+4)/5*dt*7
340				while self.runanimationprogress >= 4 do
341					self.runanimationprogress = self.runanimationprogress - 3
342				end
343				self.runframe = math.floor(self.runanimationprogress)
344				self:setquad()
345			end
346		else
347			self.x = self.animationx - 28/16 + pipeanimationdistanceright
348
349			if self.animationtimer >= pipeanimationtime+pipeanimationdelay then
350				updatesizes()
351				if type(self.animationmisc) == "number" then --sublevel
352					levelscreen_load("sublevel", self.animationmisc)
353				else --warpzone
354					warpzone(tonumber(string.sub(self.animationmisc, 5, 5)))
355				end
356			end
357		end
358		return
359	elseif self.animation == "flag" then
360		if self.animationtimer < flagdescendtime then
361			flagimgy = 49/16 + flagydistance * (self.animationtimer/flagdescendtime)
362			self.y = self.y + flagydistance/flagdescendtime * dt
363
364			self.animationtimer = self.animationtimer + dt
365
366			if self.y > 68/16 + flagydistance-self.height then
367				self.y = 68/16 + flagydistance-self.height
368				self.climbframe = 2
369			else
370				if math.mod(self.animationtimer, flagclimbframedelay*2) >= flagclimbframedelay then
371					self.climbframe = 1
372				else
373					self.climbframe = 2
374				end
375			end
376
377			self.animationstate = "climbing"
378			self:setquad()
379
380			if self.animationtimer >= flagdescendtime then
381				flagimgy = 49/16 + flagydistance
382				self.pointingangle = math.pi/2
383				self.x = flagx + 6/16
384			end
385			return
386		elseif self.animationtimer < flagdescendtime+flaganimationdelay then
387			self.animationtimer = self.animationtimer + dt
388
389			if self.animationtimer >= flagdescendtime+flaganimationdelay then
390				self.active = true
391				self.gravity = mariogravity
392				self.animationstate = "running"
393				self.speedx = 4.27
394				self.pointingangle = -math.pi/2
395			end
396		else
397			self.animationtimer = self.animationtimer + dt
398		end
399
400		local add = 6
401
402		if self.x >= flagx + add and self.active then
403			self.drawable = false
404			self.active = false
405			if mariotime > 0 then
406				playsound(scoreringsound)
407				subtractscore = true
408				subtracttimer = 0
409			else
410				castleflagmove = true
411			end
412		end
413
414		if subtractscore == true and mariotime >= 0 then
415			subtracttimer = subtracttimer + dt
416			while subtracttimer > scoresubtractspeed do
417				subtracttimer = subtracttimer - scoresubtractspeed
418				if mariotime > 0 then
419					mariotime = math.ceil(mariotime - 1)
420					marioscore = marioscore + 50
421				end
422
423				if mariotime <= 0 then
424					subtractscore = false
425					scoreringsound:stop()
426					castleflagmove = true
427					mariotime = 0
428				end
429			end
430		end
431
432		if castleflagmove then
433			if self.animationtimer < castlemintime then
434				castleflagtime = self.animationtimer
435				return
436			end
437			castleflagy = castleflagy - castleflagspeed*dt
438
439			if castleflagy <= 0 then
440				castleflagy = 0
441				castleflagmove = false
442				firework = true
443				castleflagtime = self.animationtimer
444			end
445		end
446
447		if firework then
448			local timedelta = self.animationtimer - castleflagtime
449			for i = 1, fireworkcount do
450				local fireworktime = i*fireworkdelay
451				if timedelta >= fireworktime and timedelta - dt < fireworktime then
452					table.insert(fireworks, fireworkboom:new(flagx+6))
453				end
454			end
455
456			if timedelta > fireworkcount*fireworkdelay+endtime then
457				nextlevel()
458				return
459			end
460		end
461
462		--500 points per firework, appear at 1 3 and 6 (Who came up with this?)
463
464		--Run animation
465		if self.animationstate == "running" then
466			self.runanimationprogress = self.runanimationprogress + (math.abs(self.speedx)+4)/5*dt*runanimationspeed
467			while self.runanimationprogress >= 4 do
468				self.runanimationprogress = self.runanimationprogress - 3
469			end
470			self.runframe = math.floor(self.runanimationprogress)
471
472			self:setquad()
473		end
474		return
475
476	elseif self.animation == "axe" then
477		self.animationtimer = self.animationtimer + dt
478
479		if not bowserfall and self.animationtimer - dt < castleanimationchaindisappear and self.animationtimer >= castleanimationchaindisappear then
480			bridgedisappear = true
481		end
482
483		if bridgedisappear then
484			local v = objects["bowser"][1]
485			if v then
486				v.walkframe = round(math.mod(self.animationtimer, castleanimationbowserframedelay*2)*(1/(castleanimationbowserframedelay*2)))+1
487			end
488			self.animationtimer2 = self.animationtimer2 + dt
489			while self.animationtimer2 > castleanimationbridgedisappeardelay do
490				self.animationtimer2 = self.animationtimer2 - castleanimationbridgedisappeardelay
491				if inmap(self.animationbridgex, self.animationbridgey) and map[self.animationbridgex][self.animationbridgey][1] == 11 then
492					map[self.animationbridgex][self.animationbridgey][1] = 1
493					objects["tile"][self.animationbridgex .. "-" .. self.animationbridgey] = nil
494					if map[self.animationbridgex][self.animationbridgey-1][1] == 10 then
495						map[self.animationbridgex][self.animationbridgey-1][1] = 1
496					end
497					generatespritebatch()
498					playsound(bridgebreaksound)
499					self.animationbridgex = self.animationbridgex - 1
500				else
501					bowserfall = true
502					bridgedisappear = false
503				end
504			end
505		end
506
507		if bowserfall then
508			local v = objects["bowser"][1]
509			if v and not v.fall then
510				v.fall = true
511				v.speedx = 0
512				v.speedy = 0
513				v.active = true
514				v.gravity = 27.5
515				playsound(bowserfallsound)
516				self.animationtimer = 0
517				return
518			end
519		end
520
521		if bowserfall and self.animationtimer - dt < castleanimationmariomove and self.animationtimer >= castleanimationmariomove then
522			self.active = true
523			self.gravity = mariogravity
524			self.animationstate = "running"
525			self.speedx = 4.27
526			self.pointingangle = -math.pi/2
527
528			love.audio.stop()
529			playsound(castleendsound)
530		end
531
532		if self.speedx > 0 and self.x >= mapwidth - 8 then
533			self.x = mapwidth - 8
534			self.animationstate = "idle"
535			self:setquad()
536			self.speedx = 0
537		end
538
539		if levelfinishedmisc2 == 1 then
540			if self.animationtimer - dt < castleanimationtextfirstline and self.animationtimer >= castleanimationtextfirstline then
541				levelfinishedmisc = 1
542			end
543
544			if self.animationtimer - dt < castleanimationtextsecondline and self.animationtimer >= castleanimationtextsecondline then
545				levelfinishedmisc = 2
546			end
547
548			if self.animationtimer - dt < castleanimationnextlevel and self.animationtimer >= castleanimationnextlevel then
549				nextlevel()
550			end
551		else
552			if self.animationtimer - dt < endanimationtextfirstline and self.animationtimer >= endanimationtextfirstline then
553				levelfinishedmisc = 1
554			end
555
556			if self.animationtimer - dt < endanimationtextsecondline and self.animationtimer >= endanimationtextsecondline then
557				levelfinishedmisc = 2
558				love.audio.stop()
559				music:play("princessmusic")
560			end
561
562			if self.animationtimer - dt < endanimationtextthirdline and self.animationtimer >= endanimationtextthirdline then
563				levelfinishedmisc = 3
564			end
565
566			if self.animationtimer - dt < endanimationtextfourthline and self.animationtimer >= endanimationtextfourthline then
567				levelfinishedmisc = 4
568			end
569
570			if self.animationtimer - dt < endanimationtextfifthline and self.animationtimer >= endanimationtextfifthline then
571				levelfinishedmisc = 5
572			end
573
574			if self.animationtimer - dt < endanimationend and self.animationtimer >= endanimationend then
575				endpressbutton = true
576			end
577		end
578
579		--Run animation
580		if self.animationstate == "running" and self.animationtimer >= castleanimationmariomove then
581			self.runanimationprogress = self.runanimationprogress + (math.abs(self.speedx)+4)/5*dt*runanimationspeed
582			while self.runanimationprogress >= 4 do
583				self.runanimationprogress = self.runanimationprogress - 3
584			end
585			self.runframe = math.floor(self.runanimationprogress)
586
587			self:setquad()
588		end
589		return
590
591	elseif self.animation == "death" or self.animation == "deathpit" then
592		self.animationtimer = self.animationtimer + dt
593		self.animationstate = "dead"
594		self:setquad()
595
596		if self.animation == "death" then
597			if self.animationtimer > deathanimationjumptime then
598				if self.animationtimer - dt < deathanimationjumptime then
599					self.speedy = -deathanimationjumpforce
600				end
601				self.speedy = self.speedy + deathgravity*dt
602				self.y = self.y + self.speedy*dt
603			end
604		end
605
606		if self.animationtimer > deathtotaltime then
607			if self.animationmisc == "everyonedead" then
608				levelscreen_load("death")
609			elseif not everyonedead then
610				self:respawn()
611			end
612		end
613
614		return
615	elseif self.animation == "intermission" then
616		--Run animation
617		if self.animationstate == "running" then
618			self.runanimationprogress = self.runanimationprogress + (math.abs(pipeanimationrunspeed)+4)/5*dt*7
619			while self.runanimationprogress >= 4 do
620				self.runanimationprogress = self.runanimationprogress - 3
621			end
622			self.runframe = math.floor(self.runanimationprogress)
623			self:setquad()
624		end
625
626		return
627
628	elseif self.animation == "vine" then
629		self.y = self.y - vinemovespeed*dt
630
631		self.vinemovetimer = self.vinemovetimer + dt
632
633		self.climbframe = math.ceil(math.mod(self.vinemovetimer, vineframedelay*2)/vineframedelay)
634		self.climbframe = math.max(self.climbframe, 1)
635		self:setquad()
636
637		if self.y < -4 then
638			levelscreen_load("vine", self.animationmisc)
639		end
640		return
641	elseif self.animation == "vinestart" then
642		self.animationtimer = self.animationtimer + dt
643		if self.vineanimationdropoff == false and self.animationtimer - dt <= vineanimationmariostart and self.animationtimer > vineanimationmariostart then
644			self.vineanimationclimb = true
645		end
646
647		if self.vineanimationclimb then
648			self.vinemovetimer = self.vinemovetimer + dt
649
650			self.climbframe = math.ceil(math.mod(self.vinemovetimer, vineframedelay*2)/vineframedelay)
651			self.climbframe = math.max(self.climbframe, 1)
652
653			self.y = self.y - vinemovespeed*dt
654			if self.y <= 15-vineanimationgrowheight+vineanimationstop+0.4*(self.playernumber-1) then
655				self.vineanimationclimb = false
656				self.vineanimationdropoff = true
657				self.animationtimer = 0
658				self.y = 15-vineanimationgrowheight+vineanimationstop+0.4*(self.playernumber-1)
659				self.climbframe = 2
660				self.pointingangle = math.pi/2
661				self.x = self.x+9/16
662			end
663			self:setquad()
664		end
665
666		if self.vineanimationdropoff and self.animationtimer - dt <= vineanimationdropdelay and self.animationtimer > vineanimationdropdelay then
667			self.active = true
668			self.controlsenabled = true
669			self.x = self.x + 7/16
670			self.animation = false
671		end
672
673		return
674
675	elseif self.animation == "shrink" then
676		self.animationtimer = self.animationtimer + dt
677		--set frame lol
678		local frame = math.ceil(math.mod(self.animationtimer, growframedelay*3)/shrinkframedelay)
679		self:updateangle()
680
681		if frame == 1 then
682			self.graphic = self.biggraphic
683			self:setquad("idle", 2)
684			self.quadcenterY = 32
685			self.quadcenterX = 9
686			self.offsetY = -3
687			self.animationstate = "idle"
688		else
689			self.graphic = self.smallgraphic
690			self.quadcenterX = 11
691			self.offsetY = 3
692			if frame == 2 then
693				self.animationstate = "grow"
694				self:setquad("grow")
695				self.quadcenterY = 16
696			else
697				self.animationstate = "idle"
698				self:setquad()
699				self.quadcenterY = 10
700			end
701		end
702
703		local invis = math.ceil(math.mod(self.animationtimer, invicibleblinktime*2)/invicibleblinktime)
704
705		if invis == 1 then
706			self.drawable = true
707		else
708			self.drawable = false
709		end
710
711		if self.animationtimer - dt < shrinktime and self.animationtimer > shrinktime then
712			self.animationstate = self.animationmisc
713			self.animation = "invincible"
714			self.invincible = true
715			noupdate = false
716			self.quadcenterY = 10
717			self.graphic = self.smallgraphic
718			self.animationtimer = 0
719			self.quadcenterX = 11
720			self.offsetY = 3
721			self.drawable = true
722		end
723		return
724	elseif self.animation == "invincible" then
725		self.animationtimer = self.animationtimer + dt
726
727		local invis = math.ceil(math.mod(self.animationtimer, invicibleblinktime*2)/invicibleblinktime)
728
729		if invis == 1 then
730			self.drawable = true
731		else
732			self.drawable = false
733		end
734
735		if self.animationtimer - dt < invincibletime and self.animationtimer > invincibletime then
736			self.animation = false
737			self.invincible = false
738			self.drawable = true
739		end
740
741	elseif self.animation == "grow1" then
742		self.animationtimer = self.animationtimer + dt
743		--set frame lol
744		local frame = math.ceil(math.mod(self.animationtimer, growframedelay*3)/growframedelay)
745		self:updateangle()
746
747		if frame == 3 then
748			self.animationstate = "idle"
749			self.graphic = self.biggraphic
750			self:setquad("idle")
751			self.quadcenterY = 20
752			self.quadcenterX = 9
753			self.offsetY = -3
754		else
755			self.graphic = self.smallgraphic
756			self.quadcenterX = 11
757			self.offsetY = 3
758			if frame == 2 then
759				self.animationstate = "grow"
760				self:setquad("grow", 1)
761				self.quadcenterY = 4
762			else
763				self.animationstate = "idle"
764				self:setquad(nil, 1)
765				self.quadcenterY = -2
766			end
767		end
768
769		if self.animationtimer - dt < growtime and self.animationtimer > growtime then
770			self.animationstate = self.animationmisc
771			self.animation = false
772			noupdate = false
773			self.quadcenterY = 20
774			self.graphic = self.biggraphic
775			self.animationtimer = 0
776			self.quadcenterX = 9
777			self.offsetY = -3
778		end
779		return
780
781	elseif self.animation == "grow2" then
782		self.animationtimer = self.animationtimer + dt
783		--set frame lol
784		local frame = math.ceil(math.mod(self.animationtimer, growframedelay*3)/growframedelay)
785		self:updateangle()
786
787		self.colors = starcolors[frame]
788
789		if self.animationtimer - dt < growtime and self.animationtimer > growtime then
790			self.animation = false
791			noupdate = false
792			self.animationtimer = 0
793		end
794		return
795	end
796
797	if noupdate then
798		return
799	end
800
801	if self.fireanimationtimer < fireanimationtime then
802		self.fireanimationtimer = self.fireanimationtimer + dt
803		if self.fireanimationtimer > fireanimationtime then
804			self.fireanimationtimer = fireanimationtime
805		end
806	end
807
808	--vine controls and shit
809	if self.vine then
810
811		self.animationstate = "climbing"
812		if upkey(self.playernumber) then
813			self.vinemovetimer = self.vinemovetimer + dt
814
815			self.climbframe = math.ceil(math.mod(self.vinemovetimer, vineframedelay*2)/vineframedelay)
816			self.climbframe = math.max(self.climbframe, 1)
817
818			self.y = self.y-vinemovespeed*dt
819
820			local t = checkrect(self.x, self.y, self.width, self.height, {"tile", "portalwall"})
821			if #t ~= 0 then
822				self.y = objects[t[1]][t[2]].y + objects[t[1]][t[2]].height
823				self.climbframe = 2
824			end
825		elseif downkey(self.playernumber) then
826			self.vinemovetimer = self.vinemovetimer + dt
827
828			self.climbframe = math.ceil(math.mod(self.vinemovetimer, vineframedelaydown*2)/vineframedelaydown)
829			self.climbframe = math.max(self.climbframe, 1)
830
831			checkportalHOR(self, self.y+vinemovedownspeed*dt)
832
833			self.y = self.y+vinemovedownspeed*dt
834
835			local t = checkrect(self.x, self.y, self.width, self.height, {"tile", "portalwall"})
836			if #t ~= 0 then
837				self.y = objects[t[1]][t[2]].y - self.height
838				self.climbframe = 2
839			end
840		else
841			self.climbframe = 2
842			self.vinemovetimer = 0
843		end
844
845		if self.y+self.height <= vineanimationstart then
846			self:vineanimation()
847		end
848
849		--check if still on vine
850		local t = checkrect(self.x, self.y, self.width, self.height, {"vine"})
851		if #t == 0 then
852			self:dropvine(self.vineside)
853		end
854
855		self:setquad()
856		return
857	end
858
859	--springs
860	if self.spring then
861		self.x = self.springx
862		self.springtimer = self.springtimer + dt
863		self.y = self.springy - self.height - 31/16 + springytable[self.springb.frame]
864		if self.springtimer > springtime then
865			self:leavespring()
866		end
867		return
868	end
869
870	--coins
871	if not editormode then
872		local x = math.floor(self.x+self.width/2)+1
873		local y = math.floor(self.y+self.height)+1
874		if inmap(x, y) and tilequads[map[x][y][1]].coin then
875			collectcoin(x, y)
876		end
877		local y = math.floor(self.y+self.height/2)+1
878		if inmap(x, y) and tilequads[map[x][y][1]].coin then
879			collectcoin(x, y)
880		end
881		if self.size > 1 then
882			if inmap(x, y-1) and tilequads[map[x][y-1][1]].coin then
883				collectcoin(x, y-1)
884			end
885		end
886	end
887
888	--mazegate
889	local x = math.floor(self.x+self.width/2)+1
890	local y = math.floor(self.y+self.height/2)+1
891	if inmap(x, y) and map[x][y][2] and entityquads[map[x][y][2]].t == "mazegate" then
892		if map[x][y][3] == self.mazevar + 1 then
893			self.mazevar = self.mazevar + 1
894		elseif map[x][y][3] == self.mazevar then
895
896		else
897			self.mazevar = 0
898		end
899	end
900
901	--axe
902	local x = math.floor(self.x+self.width/2)+1
903	local y = math.floor(self.y+self.height/2)+1
904
905	if axex and x == axex and y == axey then
906		self:axe()
907	end
908
909	if self.controlsenabled then
910		if self.jumping then
911			if underwater then
912				self.gravity = uwyaccelerationjumping
913			else
914				self.gravity = yaccelerationjumping
915			end
916
917			if self.speedy > 0 then
918				self.jumping = false
919				self.falling = true
920			end
921		else
922			if underwater then
923				self.gravity = uwyacceleration
924			else
925				self.gravity = yacceleration
926			end
927		end
928
929		--check for pipe pipe pipe�
930		if inmap(math.floor(self.x+30/16), math.floor(self.y+self.height+20/16)) and downkey(self.playernumber) and self.falling == false and self.jumping == false then
931			local t2 = map[math.floor(self.x+30/16)][math.floor(self.y+self.height+20/16)][2]
932			if t2 and entityquads[t2].t == "pipe" then
933				self:pipe(math.floor(self.x+30/16), math.floor(self.y+self.height+20/16), "down", tonumber(map[math.floor(self.x+30/16)][math.floor(self.y+self.height+20/16)][3]))
934				return
935			elseif t2 and entityquads[t2].t == "warppipe" then
936				self:pipe(math.floor(self.x+30/16), math.floor(self.y+self.height+20/16), "down", "pipe" .. map[math.floor(self.x+30/16)][math.floor(self.y+self.height+20/16)][3])
937				return
938			end
939		end
940
941		self:updateangle()
942
943		--Portaldots
944		self.portaldotstimer = self.portaldotstimer + dt
945		while self.portaldotstimer > portaldotstime do
946			self.portaldotstimer = self.portaldotstimer - portaldotstime
947		end
948
949		if self.falling == false and self.jumping == false and self.size > 1 then
950			if downkey(self.playernumber) then
951				if self.ducking == false then
952					self:duck(true)
953				end
954			else
955				if self.ducking then
956					self:duck(false)
957				end
958			end
959		end
960
961		if not underwater then
962			self:movement(dt)
963		else
964			self:underwatermovement(dt)
965		end
966
967		if self.y >= 15 then
968			self:die("pit")
969		elseif flagx and self.x+self.width >= flagx+6/16 and self.y > 2.2 then
970			self:flag()
971		end
972
973		if firestartx and self.x >= firestartx - 1 then
974			firestarted = true
975		end
976
977		if flyingfishstartx and self.x >= flyingfishstartx - 1 then
978			flyingfishstarted = true
979		end
980
981		if flyingfishendx and self.x >= flyingfishendx - 1 then
982			flyingfishstarted = false
983		end
984
985		if bulletbillstartx and self.x >= bulletbillstartx - 1 then
986			bulletbillstarted = true
987		end
988
989		if bulletbillendx and self.x >= bulletbillendx - 1 then
990			bulletbillstarted = false
991		end
992
993		if lakitoendx and self.x >= lakitoendx then
994			lakitoend = true
995		end
996	end
997
998	--checkpoints
999	local checkx = checkpoints[checkpointi+1]
1000	if checkx then
1001		if self.x > checkx then
1002			checkpointi = checkpointi + 1
1003			checkpointx = checkpoints[checkpointi]
1004		end
1005	end
1006
1007	--drains
1008	local x = math.floor(self.x+self.width/2)+1
1009
1010	if inmap(x, 15) and #map[x][15] > 1 and entityquads[map[x][15][2]].t == "drain" then
1011		if self.speedy < drainmax then
1012			self.speedy = math.min( drainmax, self.speedy + drainspeed*dt)
1013		end
1014	end
1015
1016	self:setquad()
1017end
1018
1019function mario:updateangle()
1020	--UPDATE THE PLAYER ANGLE
1021	if self.playernumber == mouseowner then
1022		local scale = scale
1023		if shaders and shaders.scale then scale = shaders.scale end
1024		self.pointingangle = math.atan2(self.x+6/16-xscroll-(love.mouse.getX()/16/scale), (self.y+6/16-.5)-(love.mouse.getY()/16/scale))
1025	elseif #controls[self.playernumber]["aimx"] > 0 then
1026		local x, y
1027
1028		local s = controls[self.playernumber]["aimx"]
1029		if s[1] == "joy" then
1030			x = -love.joystick.getAxis(s[2], s[4])
1031			if s[5] == "neg" then
1032				x = -x
1033			end
1034		end
1035
1036		s = controls[self.playernumber]["aimy"]
1037		if s[1] == "joy" then
1038			y = -love.joystick.getAxis(s[2], s[4])
1039			if s[5] == "neg" then
1040				y = -y
1041			end
1042		end
1043
1044		if not x or not y then
1045			return
1046		end
1047
1048		if math.abs(x) > joystickaimdeadzone or math.abs(y) > joystickaimdeadzone then
1049			self.pointingangle = math.atan2(x, y)
1050			if self.pointingangle == 0 then
1051				self.pointingangle = 0 --this is really silly, but will crash the game if I don't do this. It's because it's -0 or something. I'm not good with computers.
1052			end
1053		end
1054	end
1055end
1056
1057function mario:movement(dt)
1058	local maxrunspeed = maxrunspeed
1059	local maxwalkspeed = maxwalkspeed
1060	local runacceleration = runacceleration
1061	local walkacceleration = walkacceleration
1062	--Orange gel
1063	--not in air
1064	if self.falling == false and self.jumping == false then
1065		--bottom on grid
1066		if math.mod(self.y+self.height, 1) == 0 then
1067			local x = round(self.x+self.width/2+.5)
1068			local y = self.y+self.height+1
1069			--x and y in map
1070			if inmap(x, y) then
1071				--top of block orange
1072				if map[x][y]["gels"]["top"] == 2 then
1073					maxrunspeed = gelmaxrunspeed
1074					maxwalkspeed = gelmaxwalkspeed
1075					runacceleration = gelrunacceleration
1076					walkacceleration = gelwalkacceleration
1077				end
1078			end
1079		end
1080	end
1081
1082	--Run animation
1083	if self.animationstate == "running" then
1084		self.runanimationprogress = self.runanimationprogress + (math.abs(self.speedx)+4)/5*dt*runanimationspeed
1085		while self.runanimationprogress >= 4 do
1086			self.runanimationprogress = self.runanimationprogress - 3
1087		end
1088		self.runframe = math.floor(self.runanimationprogress)
1089	end
1090
1091	--HORIZONTAL MOVEMENT
1092	if runkey(self.playernumber) then --RUNNING
1093		if rightkey(self.playernumber) then --MOVEMENT RIGHT
1094			if self.jumping or self.falling then --IN AIR
1095				if self.speedx < maxwalkspeed then
1096					if self.speedx < 0 then
1097						self.speedx = self.speedx + runaccelerationair*dt*airslidefactor
1098					else
1099						self.speedx = self.speedx + runaccelerationair*dt
1100					end
1101
1102					if self.speedx > maxwalkspeed then
1103						self.speedx = maxwalkspeed
1104					end
1105				elseif self.speedx > maxwalkspeed and self.speedx < maxrunspeed then
1106					if self.speedx < 0 then
1107						self.speedx = self.speedx + runaccelerationair*dt*airslidefactor
1108					else
1109						self.speedx = self.speedx + runaccelerationair*dt
1110					end
1111
1112					if self.speedx > maxrunspeed then
1113						self.speedx = maxrunspeed
1114					end
1115				end
1116
1117			elseif self.ducking == false then --ON GROUND
1118				if self.speedx < 0 then
1119					if self.speedx > maxrunspeed then
1120						self.speedx = self.speedx + superfriction*dt + runacceleration*dt
1121					else
1122						self.speedx = self.speedx + friction*dt + runacceleration*dt
1123					end
1124					self.animationstate = "sliding"
1125					self.animationdirection = "right"
1126				else
1127					self.speedx = self.speedx + runacceleration*dt
1128					self.animationstate = "running"
1129					self.animationdirection = "right"
1130				end
1131
1132				if self.speedx > maxrunspeed then
1133					self.speedx = maxrunspeed
1134				end
1135			end
1136
1137		elseif leftkey(self.playernumber) then --MOVEMENT LEFT
1138			if self.jumping or self.falling then --IN AIR
1139				if self.speedx > -maxwalkspeed then
1140					if self.speedx > 0 then
1141						self.speedx = self.speedx - runaccelerationair*dt*airslidefactor
1142					else
1143						self.speedx = self.speedx - runaccelerationair*dt
1144					end
1145
1146					if self.speedx < -maxwalkspeed then
1147						self.speedx = -maxwalkspeed
1148					end
1149				elseif self.speedx < -maxwalkspeed and self.speedx > -maxrunspeed then
1150					if self.speedx > 0 then
1151						self.speedx = self.speedx - runaccelerationair*dt*airslidefactor
1152					else
1153						self.speedx = self.speedx - runaccelerationair*dt
1154					end
1155
1156					if self.speedx < -maxrunspeed then
1157						self.speedx = -maxrunspeed
1158					end
1159				end
1160
1161			elseif self.ducking == false then --ON GROUND
1162				if self.speedx > 0 then
1163					if self.speedx < -maxrunspeed then
1164						self.speedx = self.speedx - superfriction*dt - runacceleration*dt
1165					else
1166						self.speedx = self.speedx - friction*dt - runacceleration*dt
1167					end
1168					self.animationstate = "sliding"
1169					self.animationdirection = "left"
1170				else
1171					self.speedx = self.speedx - runacceleration*dt
1172					self.animationstate = "running"
1173					self.animationdirection = "left"
1174				end
1175
1176				if self.speedx < -maxrunspeed then
1177					self.speedx = -maxrunspeed
1178				end
1179			end
1180
1181		end
1182		if (not rightkey(self.playernumber) and not leftkey(self.playernumber)) or (self.ducking and self.falling == false and self.jumping == false) then  --NO MOVEMENT
1183			if self.jumping or self.falling then
1184				if self.speedx > 0 then
1185					self.speedx = self.speedx - frictionair*dt
1186					if self.speedx < minspeed then
1187						self.speedx = 0
1188						self.runframe = 1
1189					end
1190				else
1191					self.speedx = self.speedx + frictionair*dt
1192					if self.speedx > -minspeed then
1193						self.speedx = 0
1194						self.runframe = 1
1195					end
1196				end
1197			else
1198				if self.speedx > 0 then
1199					if self.speedx > maxrunspeed then
1200						self.speedx = self.speedx - superfriction*dt
1201					else
1202						self.speedx = self.speedx - friction*dt
1203					end
1204					if self.speedx < minspeed then
1205						self.speedx = 0
1206						self.runframe = 1
1207						self.animationstate = "idle"
1208					end
1209				else
1210					if self.speedx < -maxrunspeed then
1211						self.speedx = self.speedx + superfriction*dt
1212					else
1213						self.speedx = self.speedx + friction*dt
1214					end
1215					if self.speedx > -minspeed then
1216						self.speedx = 0
1217						self.runframe = 1
1218						self.animationstate = "idle"
1219					end
1220				end
1221			end
1222		end
1223
1224	else --WALKING
1225
1226		if rightkey(self.playernumber) then --MOVEMENT RIGHT
1227			if self.jumping or self.falling then --IN AIR
1228				if self.speedx < maxwalkspeed then
1229					if self.speedx < 0 then
1230						self.speedx = self.speedx + walkaccelerationair*dt*airslidefactor
1231					else
1232						self.speedx = self.speedx + walkaccelerationair*dt
1233					end
1234
1235					if self.speedx > maxwalkspeed then
1236						self.speedx = maxwalkspeed
1237					end
1238				end
1239			elseif self.ducking == false then --ON GROUND
1240				if self.speedx < maxwalkspeed then
1241					if self.speedx < 0 then
1242						if self.speedx < -maxrunspeed then
1243							self.speedx = self.speedx + superfriction*dt + runacceleration*dt
1244						else
1245							self.speedx = self.speedx + friction*dt + runacceleration*dt
1246						end
1247						self.animationstate = "sliding"
1248						self.animationdirection = "right"
1249					else
1250						self.speedx = self.speedx + walkacceleration*dt
1251						self.animationstate = "running"
1252						self.animationdirection = "right"
1253					end
1254
1255					if self.speedx > maxwalkspeed then
1256						self.speedx = maxwalkspeed
1257					end
1258				else
1259					self.speedx = self.speedx - friction*dt
1260					if self.speedx < maxwalkspeed then
1261						self.speedx = maxwalkspeed
1262					end
1263				end
1264			end
1265
1266		elseif leftkey(self.playernumber) then --MOVEMENT LEFT
1267			if self.jumping or self.falling then --IN AIR
1268				if self.speedx > -maxwalkspeed then
1269					if self.speedx > 0 then
1270						self.speedx = self.speedx - walkaccelerationair*dt*airslidefactor
1271					else
1272						self.speedx = self.speedx - walkaccelerationair*dt
1273					end
1274
1275					if self.speedx < -maxwalkspeed then
1276						self.speedx = -maxwalkspeed
1277					end
1278				end
1279			elseif self.ducking == false then --ON GROUND
1280				if self.speedx > -maxwalkspeed then
1281					if self.speedx > 0 then
1282						if self.speedx > maxrunspeed then
1283							self.speedx = self.speedx - superfriction*dt - runacceleration*dt
1284						else
1285							self.speedx = self.speedx - friction*dt - runacceleration*dt
1286						end
1287						self.animationstate = "sliding"
1288						self.animationdirection = "left"
1289					else
1290						self.speedx = self.speedx - walkacceleration*dt
1291						self.animationstate = "running"
1292						self.animationdirection = "left"
1293					end
1294
1295					if self.speedx < -maxwalkspeed then
1296						self.speedx = -maxwalkspeed
1297					end
1298				else
1299					self.speedx = self.speedx + friction*dt
1300					if self.speedx > -maxwalkspeed then
1301						self.speedx = -maxwalkspeed
1302					end
1303				end
1304			end
1305
1306		end
1307		if (not rightkey(self.playernumber) and not leftkey(self.playernumber)) or (self.ducking and self.falling == false and self.jumping == false) then --no movement
1308			if self.jumping or self.falling then
1309				if self.speedx > 0 then
1310					self.speedx = self.speedx - frictionair*dt
1311					if self.speedx < 0 then
1312						self.speedx = 0
1313						self.runframe = 1
1314					end
1315				else
1316					self.speedx = self.speedx + frictionair*dt
1317					if self.speedx > 0 then
1318						self.speedx = 0
1319						self.runframe = 1
1320					end
1321				end
1322			else
1323				if self.speedx > 0 then
1324					if self.speedx > maxrunspeed then
1325						self.speedx = self.speedx - superfriction*dt
1326					else
1327						self.speedx = self.speedx - friction*dt
1328					end
1329					if self.speedx < 0 then
1330						self.speedx = 0
1331						self.runframe = 1
1332						self.animationstate = "idle"
1333					end
1334				else
1335					if self.speedx < -maxrunspeed then
1336						self.speedx = self.speedx + superfriction*dt
1337					else
1338						self.speedx = self.speedx + friction*dt
1339					end
1340					if self.speedx > 0 then
1341						self.speedx = 0
1342						self.runframe = 1
1343						self.animationstate = "idle"
1344					end
1345				end
1346			end
1347		end
1348	end
1349end
1350
1351function mario:underwatermovement(dt)
1352	if self.jumping or self.falling then
1353		--Swim animation
1354		if self.animationstate == "jumping" or self.animationstate == "falling" then
1355			self.swimanimationprogress = self.swimanimationprogress + runanimationspeed*dt
1356			while self.swimanimationprogress >= 3 do
1357				self.swimanimationprogress = self.swimanimationprogress - 2
1358			end
1359			self.swimframe = math.floor(self.swimanimationprogress)
1360		end
1361	else
1362		--Run animation
1363		if self.animationstate == "running" then
1364			self.runanimationprogress = self.runanimationprogress + (math.abs(self.speedx)+4)/5*dt*runanimationspeed
1365			while self.runanimationprogress >= 4 do
1366				self.runanimationprogress = self.runanimationprogress - 3
1367			end
1368			self.runframe = math.floor(self.runanimationprogress)
1369		end
1370	end
1371
1372	--bubbles
1373	self.bubbletimer = self.bubbletimer + dt
1374	while self.bubbletimer > self.bubbletime do
1375		self.bubbletimer = self.bubbletimer - self.bubbletime
1376		self.bubbletime = bubblestime[math.random(#bubblestime)]
1377		table.insert(bubbles, bubble:new(self.x+8/12, self.y+2/12))
1378	end
1379
1380	--HORIZONTAL MOVEMENT
1381	if rightkey(self.playernumber) then --MOVEMENT RIGHT
1382		if self.jumping or self.falling then --IN AIR
1383			if self.speedx < uwmaxairwalkspeed then
1384				if self.speedx < 0 then
1385					self.speedx = self.speedx + uwwalkaccelerationair*dt*uwairslidefactor
1386				else
1387					self.speedx = self.speedx + uwwalkaccelerationair*dt
1388				end
1389
1390				if self.speedx > uwmaxairwalkspeed then
1391					self.speedx = uwmaxairwalkspeed
1392				end
1393			end
1394		elseif self.ducking == false then --ON GROUND
1395			if self.speedx < uwmaxwalkspeed then
1396				if self.speedx < 0 then
1397					if self.speedx < -uwmaxrunspeed then
1398						self.speedx = self.speedx + uwsuperfriction*dt + uwrunacceleration*dt
1399					else
1400						self.speedx = self.speedx + uwfriction*dt + uwrunacceleration*dt
1401					end
1402					self.animationstate = "sliding"
1403					self.animationdirection = "right"
1404				else
1405					self.speedx = self.speedx + uwwalkacceleration*dt
1406					self.animationstate = "running"
1407					self.animationdirection = "right"
1408				end
1409
1410				if self.speedx > uwmaxwalkspeed then
1411					self.speedx = uwmaxwalkspeed
1412				end
1413			else
1414				self.speedx = self.speedx - uwfriction*dt
1415				if self.speedx < uwmaxwalkspeed then
1416					self.speedx = uwmaxwalkspeed
1417				end
1418			end
1419		end
1420
1421	elseif leftkey(self.playernumber) then --MOVEMENT LEFT
1422		if self.jumping or self.falling then --IN AIR
1423			if self.speedx > -uwmaxairwalkspeed then
1424				if self.speedx > 0 then
1425					self.speedx = self.speedx - uwwalkaccelerationair*dt*uwairslidefactor
1426				else
1427					self.speedx = self.speedx - uwwalkaccelerationair*dt
1428				end
1429
1430				if self.speedx < -uwmaxairwalkspeed then
1431					self.speedx = -uwmaxairwalkspeed
1432				end
1433			end
1434		elseif self.ducking == false then --ON GROUND
1435			if self.speedx > -uwmaxwalkspeed then
1436				if self.speedx > 0 then
1437					if self.speedx > uwmaxrunspeed then
1438						self.speedx = self.speedx - uwsuperfriction*dt - uwrunacceleration*dt
1439					else
1440						self.speedx = self.speedx - uwfriction*dt - uwrunacceleration*dt
1441					end
1442					self.animationstate = "sliding"
1443					self.animationdirection = "left"
1444				else
1445					self.speedx = self.speedx - uwwalkacceleration*dt
1446					self.animationstate = "running"
1447					self.animationdirection = "left"
1448				end
1449
1450				if self.speedx < -uwmaxwalkspeed then
1451					self.speedx = -uwmaxwalkspeed
1452				end
1453			else
1454				self.speedx = self.speedx + uwfriction*dt
1455				if self.speedx > -uwmaxwalkspeed then
1456					self.speedx = -uwmaxwalkspeed
1457				end
1458			end
1459		end
1460
1461	else --NO MOVEMENT
1462		if self.jumping or self.falling then
1463			if self.speedx > 0 then
1464				self.speedx = self.speedx - uwfrictionair*dt
1465				if self.speedx < 0 then
1466					self.speedx = 0
1467					self.runframe = 1
1468				end
1469			else
1470				self.speedx = self.speedx + uwfrictionair*dt
1471				if self.speedx > 0 then
1472					self.speedx = 0
1473					self.runframe = 1
1474				end
1475			end
1476		else
1477			if self.speedx > 0 then
1478				if self.speedx > uwmaxrunspeed then
1479					self.speedx = self.speedx - uwsuperfriction*dt
1480				else
1481					self.speedx = self.speedx - uwfriction*dt
1482				end
1483				if self.speedx < 0 then
1484					self.speedx = 0
1485					self.runframe = 1
1486					self.animationstate = "idle"
1487				end
1488			else
1489				if self.speedx < -uwmaxrunspeed then
1490					self.speedx = self.speedx + uwsuperfriction*dt
1491				else
1492					self.speedx = self.speedx + uwfriction*dt
1493				end
1494				if self.speedx > 0 then
1495					self.speedx = 0
1496					self.runframe = 1
1497					self.animationstate = "idle"
1498				end
1499			end
1500		end
1501	end
1502
1503	if self.y+self.height < uwmaxheight then
1504		self.speedy = uwpushdownspeed
1505	end
1506end
1507
1508function mario:setquad(anim, s)
1509	local angleframe = getAngleFrame(self.pointingangle+self.rotation)
1510
1511	local animationstate = anim or self.animationstate
1512	local size = s or self.size
1513
1514	if size == 1 then
1515		if underwater and (self.animationstate == "jumping" or self.animationstate == "falling") then
1516			self.quad = marioswim[angleframe][self.swimframe]
1517		elseif animationstate == "running" or animationstate == "falling" then
1518			self.quad = mariorun[angleframe][self.runframe]
1519		elseif animationstate == "idle" then
1520			self.quad = marioidle[angleframe]
1521		elseif animationstate == "sliding" then
1522			self.quad = marioslide[angleframe]
1523		elseif animationstate == "jumping" then
1524			self.quad = mariojump[angleframe]
1525		elseif animationstate == "climbing" then
1526			self.quad = marioclimb[angleframe][self.climbframe]
1527		elseif animationstate == "dead" then
1528			self.quad = mariodie[angleframe]
1529		elseif animationstate == "grow" then
1530			self.quad = mariogrow[angleframe]
1531		end
1532	elseif size > 1 then
1533		if underwater and (self.animationstate == "jumping" or self.animationstate == "falling") then
1534			self.quad = bigmarioswim[angleframe][self.swimframe]
1535		elseif self.ducking then
1536			self.quad = bigmarioduck[angleframe]
1537		elseif self.fireanimationtimer < fireanimationtime then
1538			self.quad = bigmariofire[angleframe]
1539		else
1540			if animationstate == "running" or animationstate == "falling" then
1541				self.quad = bigmariorun[angleframe][self.runframe]
1542			elseif animationstate == "idle" then
1543				self.quad = bigmarioidle[angleframe]
1544			elseif animationstate == "sliding" then
1545				self.quad = bigmarioslide[angleframe]
1546			elseif animationstate == "climbing" then
1547				self.quad = bigmarioclimb[angleframe][self.climbframe]
1548			elseif animationstate == "jumping" then
1549				self.quad = bigmariojump[angleframe]
1550			end
1551		end
1552	end
1553end
1554
1555function mario:jump()
1556	if not noupdate and self.controlsenabled then
1557		if not underwater then
1558			if self.spring then
1559				self.springhigh = true
1560				return
1561			end
1562
1563			if self.falling == false then
1564				if self.size == 1 then
1565					playsound(jumpsound)
1566				else
1567					playsound(jumpbigsound)
1568				end
1569
1570				local force = -jumpforce - (math.abs(self.speedx) / maxrunspeed)*jumpforceadd
1571				force = math.max(-jumpforce - jumpforceadd, force)
1572
1573				self.speedy = force
1574				self.jumping = true
1575				self.animationstate = "jumping"
1576				self:setquad()
1577			end
1578		else
1579			if self.ducking then
1580				self:duck(false)
1581			end
1582			playsound(swimsound)
1583
1584			self.speedy = -uwjumpforce - (math.abs(self.speedx) / maxrunspeed)*uwjumpforceadd
1585			self.jumping = true
1586			self.animationstate = "jumping"
1587			self:setquad()
1588		end
1589	end
1590end
1591
1592function mario:stopjump()
1593	if self.controlsenabled then
1594		if self.jumping == true then
1595			self.jumping = false
1596			self.falling = true
1597		end
1598	end
1599end
1600
1601function mario:rightkey()
1602	if self.controlsenabled and self.vine then
1603		if self.vineside == "left" then
1604			self.x = self.x + 8/16
1605			self.pointingangle = math.pi/2
1606			self.vineside = "right"
1607		else
1608			self:dropvine("right")
1609		end
1610	end
1611end
1612
1613function mario:leftkey()
1614	if self.controlsenabled and self.vine then
1615		if self.vineside == "right" then
1616			self.x = self.x - 8/16
1617			self.pointingangle = -math.pi/2
1618			self.vineside = "left"
1619		else
1620			self:dropvine("left")
1621		end
1622	end
1623end
1624
1625function mario:grow()
1626	self.animationmisc = self.animationstate
1627	if self.animation and self.animation ~= "invincible" then
1628		return
1629	end
1630	addpoints(1000, self.x+self.width/2, self.y)
1631	playsound(mushroomeatsound)
1632
1633	if bigmario then
1634		return
1635	end
1636
1637	if self.size > 2 then
1638
1639	else
1640		self.size = self.size + 1
1641		if self.size == 2 then
1642			self.y = self.y - 12/16
1643			self.height = 24/16
1644		elseif self.size == 3 then
1645			self.colors = flowercolor
1646		end
1647
1648		if self.size == 2 then
1649			self.animation = "grow1"
1650		else
1651			self.animation = "grow2"
1652		end
1653
1654		self.drawable = true
1655		self.invincible = false
1656		self.animationtimer = 0
1657		noupdate = true
1658	end
1659end
1660
1661function mario:shrink()
1662	self.animationmisc = self.animationstate
1663	if self.animation then
1664		return
1665	end
1666	if self.ducking then
1667		self:duck(false)
1668	end
1669	playsound(shrinksound)
1670
1671	self.size = 1
1672
1673	self.colors = mariocolors[self.playernumber]
1674
1675	self.animation = "shrink"
1676	self.drawable = true
1677	self.invincible = true
1678	self.animationtimer = 0
1679
1680	self.y = self.y + 12/16
1681	self.height = 12/16
1682
1683	noupdate = true
1684end
1685
1686function mario:floorcollide(a, b)
1687	self.rainboomallowed = true
1688	if self.jumping and (a == "platform" or a == "seesawplatform") and self.speedy < -jumpforce + 0.1 then
1689		return false
1690	end
1691
1692	local anim = self.animationstate
1693	local jump = self.jumping
1694	local fall = self.falling
1695
1696	if self:globalcollide(a, b) then
1697		return false
1698	end
1699
1700	if a == "spring" then
1701		self:hitspring(b)
1702		return false
1703	end
1704
1705	if self.speedx == 0 then
1706		self.animationstate = "idle"
1707	else
1708		if self.animationstate ~= "sliding" then
1709			self.animationstate = "running"
1710		end
1711	end
1712	self:setquad()
1713
1714	if a == "tile" then
1715		local x, y = b.cox, b.coy
1716		if bigmario and self.speedy > 2 then
1717			destroyblock(x, y)
1718			self.speedy = self.speedy/10
1719		end
1720
1721		--check for invisible block
1722		if tilequads[map[x][y][1]].invisible then
1723			self.jumping = jump
1724			self.falling = fall
1725			self.animationstate = anim
1726			return false
1727		end
1728	end
1729
1730	--star logic
1731	if self.starred or bigmario then
1732		if self:starcollide(a, b) then
1733			return false
1734		end
1735	end
1736
1737	self.falling = false
1738	self.jumping = false
1739
1740	--Make mario snap to runspeed if at walkspeed.
1741	--[[if leftkey(self.playernumber) then
1742		if runkey(self.playernumber) then
1743			if self.speedx <= -maxwalkspeed then
1744				self.speedx = -maxrunspeed
1745				self.animationdirection = "left"
1746			end
1747		end
1748	elseif rightkey(self.playernumber) then
1749		if runkey(self.playernumber) then
1750			if self.speedx >= maxwalkspeed then
1751				self.speedx = maxrunspeed
1752				self.animationdirection = "right"
1753			end
1754		end
1755	end--]]
1756
1757	if a == "mushroom" or a == "oneup" or a == "star" or a == "flower" then
1758		self.falling = true
1759		return false
1760	elseif (a == "goomba" and b.t == "goomba") or a == "bulletbill" or a == "flyingfish" or a == "lakito" or a == "hammerbro" or a == "koopa" then
1761		self:stompenemy(a, b)
1762		return false
1763	elseif a == "tile" then
1764		local x, y = b.cox, b.coy
1765
1766		if map[x][y]["gels"] then
1767			if downkey(self.playernumber) == false and map[x][y]["gels"]["top"] == 1 and self.speedy > gdt*yacceleration*10 then
1768				self.speedy = -self.speedy
1769				self.falling = true
1770				self.animationstate = "jumping"
1771				self:setquad()
1772				self.speedy = self.speedy + self.gravity*gdt
1773
1774				return false
1775			end
1776		end
1777	elseif a == "plant" or a == "bowser" or a == "cheep" or a == "upfire" or (a == "goomba" and b.t ~= "goomba") or a == "squid" or a == "hammer" then --KILL
1778		if self.invincible then
1779			self.jumping = jump
1780			self.falling = fall
1781			self.animationstate = anim
1782			return false
1783		else
1784			self:die("Enemy (floorcollide)")
1785			return false
1786		end
1787	elseif a == "castlefirefire" or a == "fire" then
1788		if self.invincible then
1789			self.jumping = jump
1790			self.falling = fall
1791			self.animationstate = anim
1792			return false
1793		else
1794			self:die("castlefirefire")
1795			return false
1796		end
1797	end
1798
1799	self.combo = 1
1800end
1801
1802function mario:stompenemy(a, b)
1803	local bounce = false
1804	if a == "koopa" then
1805		if b.small then
1806			playsound(shotsound)
1807			if b.speedx == 0 then
1808				addpoints(500, b.x, b.y)
1809				self.combo = 1
1810			end
1811		else
1812			playsound(stompsound)
1813		end
1814
1815		b:stomp(self.x, self)
1816
1817		if b.speedx == 0 or ((b.t == "redflying" or b.t == "flying") and b.small == false) then
1818			addpoints(mariocombo[self.combo], self.x, self.y)
1819			if self.combo < #mariocombo then
1820				self.combo = self.combo + 1
1821			end
1822
1823			local grav = self.gravity or yacceleration
1824
1825			local bouncespeed = math.sqrt(2*grav*bounceheight)
1826
1827			self.speedy = -bouncespeed
1828
1829			self.falling = true
1830			self.animationstate = "jumping"
1831			self:setquad()
1832			self.y = b.y - self.height-1/16
1833		elseif b.x > self.x then
1834			b.x = self.x + b.width + self.speedx*gdt + 0.05
1835			local col = checkrect(b.x, b.y, b.width, b.height, {"tile"})
1836			if #col > 1 then
1837				b.x = objects[col[1]][col[2]].x-b.width
1838				bounce = true
1839			end
1840		else
1841			b.x = self.x - b.width + self.speedx*gdt - 0.05
1842			local col = checkrect(b.x, b.y, b.width, b.height, {"tile"})
1843			if #col > 1 then
1844				b.x = objects[col[1]][col[2]].x+1
1845				bounce = true
1846			end
1847		end
1848	else
1849		b:stomp()
1850		if self.combo < #mariocombo then
1851			addpoints(mariocombo[self.combo], self.x, self.y)
1852			if a ~= "bulletbill" then
1853				self.combo = self.combo + 1
1854			end
1855		else
1856			if mariolivecount ~= false then
1857				mariolives[self.playernumber] = mariolives[self.playernumber]+1
1858			end
1859			table.insert(scrollingscores, scrollingscore:new("1up", self.x, self.y))
1860			playsound(oneupsound)
1861		end
1862		playsound(stompsound)
1863
1864		bounce = true
1865	end
1866
1867	if bounce then
1868		local grav = self.gravity or yacceleration
1869
1870		local bouncespeed = math.sqrt(2*grav*bounceheight)
1871
1872		self.animationstate = "jumping"
1873		self.falling = true
1874		self:setquad()
1875		self.speedy = -bouncespeed
1876	end
1877end
1878
1879function mario:rightcollide(a, b)
1880	if self:globalcollide(a, b) then
1881		return false
1882	end
1883
1884	--star logic
1885	if self.starred or bigmario then
1886		if self:starcollide(a, b) then
1887			return false
1888		end
1889	end
1890
1891	if a == "mushroom" or a == "oneup" or a == "star" or a == "flower" or (a == "platform" and (b.dir == "right" or b.dir == "justright")) then
1892		return false
1893	elseif self.speedy > 2 and ((a == "goomba" and b.t == "goomba") or a == "bulletbill" or a == "flyingfish" or a == "lakito" or a == "hammerbro" or a == "koopa") then
1894		self:stompenemy(a, b)
1895		return false
1896	elseif a == "castlefirefire" or a == "fire" or a == "koopa" or a == "goomba" or a == "bulletbill" or a == "plant" or a == "bowser" or a == "cheep" or a == "flyingfish" or a == "upfire" or a == "lakito" or a == "squid" or a == "hammer" or a == "hammerbro" then --KILLS
1897		if self.invincible then
1898			if a == "koopa" and b.small and b.speedx == 0 then
1899				b:stomp(self.x)
1900				playsound(shotsound)
1901				addpoints(500, b.x, b.y)
1902			end
1903			return false
1904		else
1905			if a == "koopa" and b.small and b.speedx == 0 then
1906				b:stomp(self.x)
1907				playsound(shotsound)
1908				addpoints(500, b.x, b.y)
1909				return false
1910			end
1911
1912			self:die("Enemy (rightcollide)")
1913			return false
1914		end
1915	elseif a == "tile" then
1916		local x, y = b.cox, b.coy
1917
1918		if map[x][y]["gels"] then
1919			if downkey(self.playernumber) == false and map[x][y]["gels"]["left"] == 1 and (self.falling or self.jumping) then
1920				if self.speedx > horbounceminspeedx then
1921					self.speedx = math.min(-horbouncemaxspeedx, -self.speedx*horbouncemul)
1922					self.speedy = math.min(self.speedy, -horbouncespeedy)
1923
1924					return false
1925				end
1926			end
1927		end
1928
1929		--check for invisible block
1930		if tilequads[map[x][y][1]].invisible then
1931			return false
1932		end
1933
1934		--Check if it's a pipe with pipe pipe.
1935		if self.falling == false and self.jumping == false and (rightkey(self.playernumber) or intermission) then --but only on ground and rightkey
1936			local t2 = map[x][y][2]
1937			if t2 and entityquads[t2].t == "pipe" then
1938				self:pipe(x, y, "right", tonumber(map[x][y][3]))
1939				return
1940			else
1941				if inmap(x, y+1) then
1942					t2 = map[x][y+1][2]
1943					if t2 and entityquads[t2].t == "pipe" then
1944						self:pipe(x, y+1, "right", tonumber(map[x][y+1][3]))
1945						return
1946					end
1947				end
1948			end
1949		end
1950
1951		--Check if mario should run across a gap.
1952		if inmap(x, y-1) and tilequads[map[x][y-1][1]].collision == false and self.speedy > 0 and self.y+self.height+1 < y+spacerunroom then
1953			self.y = b.y - self.height
1954			self.speedy = 0
1955			self.x = b.x-self.width+0.0001
1956			self.falling = false
1957			self.animationstate = "running"
1958			self:setquad()
1959			return false
1960		end
1961
1962		if bigmario then
1963			destroyblock(x, y)
1964			return false
1965		end
1966	elseif a == "box" then
1967		if self.speedx > maxwalkspeed/2 then
1968			self.speedx = self.speedx - self.speedx * 6 * gdt
1969		end
1970
1971		--check if box can even move
1972		local out = checkrect(b.x+self.speedx*gdt, b.y, b.width, b.height, {"exclude", b}, true)
1973		if #out == 0 then
1974			b.speedx = self.speedx
1975			return false
1976		end
1977	elseif a == "button" then
1978		self.y = b.y - self.height
1979		self.x = b.x - self.width+0.001
1980		if self.speedy > 0 then
1981			self.speedy = 0
1982		end
1983		return false
1984	end
1985
1986	if self.falling == false and self.jumping == false then
1987		self.animationstate = "idle"
1988		self:setquad()
1989	end
1990end
1991
1992function mario:leftcollide(a, b)
1993	if self:globalcollide(a, b) then
1994		return false
1995	end
1996
1997	--star logic
1998	if self.starred or bigmario then
1999		if self:starcollide(a, b) then
2000			return false
2001		end
2002	end
2003
2004	if a == "mushroom" or a == "oneup" or a == "star" or a == "flower" or (a == "platform" and (b.dir == "right" or b.dir == "justright")) then --NOTHING
2005		return false
2006	elseif self.speedy > 2 and ((a == "goomba" and b.t == "goomba") or a == "bulletbill" or a == "flyingfish" or a == "lakito" or a == "hammerbro" or a == "koopa") then
2007		self:stompenemy(a, b)
2008		return false
2009	elseif a == "castlefirefire" or a == "fire" or a == "koopa" or a == "goomba" or a == "bulletbill" or a == "plant" or a == "bowser" or a == "cheep" or a == "flyingfish" or a == "upfire" or a == "lakito" or a == "squid" or a == "hammer" or a == "hammerbro" then --KILLS
2010		if self.invincible then
2011			if a == "koopa" and b.small and b.speedx == 0 then
2012				b:stomp(self.x)
2013				playsound(shotsound)
2014				addpoints(500, b.x, b.y)
2015			end
2016			return false
2017		else
2018			if a == "koopa" and b.small and b.speedx == 0 then
2019				b:stomp(self.x)
2020				playsound(shotsound)
2021				addpoints(500, b.x, b.y)
2022				return false
2023			end
2024
2025			self:die("Enemy (leftcollide)")
2026			return false
2027		end
2028	elseif a == "tile" then
2029		local x, y = b.cox, b.coy
2030
2031		if map[x][y]["gels"] then
2032			if downkey(self.playernumber) == false and map[x][y]["gels"]["right"] == 1 and (self.falling or self.jumping) then
2033				if self.speedx < -horbounceminspeedx then
2034					self.speedx = math.min(horbouncemaxspeedx, -self.speedx*horbouncemul)
2035					self.speedy = math.min(self.speedy, -horbouncespeedy)
2036
2037					return false
2038				end
2039			end
2040		end
2041
2042		--check for invisible block
2043		if tilequads[map[x][y][1]].invisible then
2044			return false
2045		end
2046
2047		if inmap(x, y-1) and tilequads[map[x][y-1][1]].collision == false and self.speedy > 0 and self.y+1+self.height < y+spacerunroom then
2048			self.y = b.y - self.height
2049			self.speedy = 0
2050			self.x = b.x+1-0.0001
2051			self.falling = false
2052			self.animationstate = "running"
2053			self:setquad()
2054			return false
2055		end
2056
2057		if bigmario then
2058			destroyblock(x, y)
2059			return false
2060		end
2061	elseif a == "box" then
2062		if self.speedx < -maxwalkspeed/2 then
2063			self.speedx = self.speedx - self.speedx * 6 * gdt
2064		end
2065
2066		--check if box can even move
2067		local out = checkrect(b.x+self.speedx*gdt, b.y, b.width, b.height, {"exclude", b}, true)
2068		if #out == 0 then
2069			b.speedx = self.speedx
2070			return false
2071		end
2072	elseif a == "button" then
2073		self.y = b.y - self.height
2074		self.x = b.x + b.width - 0.001
2075		if self.speedy > 0 then
2076			self.speedy = 0
2077		end
2078		return false
2079	end
2080
2081	if self.falling == false and self.jumping == false then
2082		self.animationstate = "idle"
2083		self:setquad()
2084	end
2085end
2086
2087function mario:ceilcollide(a, b)
2088	if self:globalcollide(a, b) then
2089		return false
2090	end
2091
2092	--star logic
2093	if self.starred or bigmario then
2094		if self:starcollide(a, b) then
2095			return false
2096		end
2097	end
2098
2099	if a == "mushroom" or a == "oneup" or a == "star" or a == "flower" then --STUFF THAT SHOULDN'T DO SHIT
2100		return false
2101	elseif a == "castlefirefire" or a == "fire" or a == "plant" or a == "goomba" or a == "koopa" or a == "bulletbill" or a == "bowser" or a == "cheep" or a == "flyingfish" or a == "upfire" or a == "lakito" or a == "squid" or a == "hammer" or a == "hammerbro" then --STUFF THAT KILLS
2102		if self.invincible then
2103			return false
2104		else
2105			self:die("Enemy (Ceilcollided)")
2106			return false
2107		end
2108	elseif a == "tile" then
2109		local x, y = b.cox, b.coy
2110		local r = map[x][y]
2111
2112		--check if it's an invisible block
2113		if tilequads[map[x][y][1]].invisible then
2114			if self.y-self.speedy <= y-1 then
2115				return false
2116			end
2117		else
2118			if bigmario then
2119				destroyblock(x, y)
2120				return false
2121			end
2122
2123			--Check if it should bounce the block next to it, or push mario instead (Hello, devin hitch!)
2124
2125			if self.x < x-22/16 then
2126				--check if block left of it is a better fit
2127				if x > 1 and tilequads[map[x-1][y][1]].collision == true then
2128					x = x - 1
2129				else
2130					local col = checkrect(x-28/16, self.y, self.width, self.height, {"exclude", self}, true)
2131					if #col == 0 then
2132						self.x = x-28/16
2133						if self.speedx > 0 then
2134							self.speedx = 0
2135						end
2136						return false
2137					end
2138				end
2139			elseif self.x > x-6/16 then
2140				--check if block right of it is a better fit
2141				if x < mapwidth and tilequads[map[x+1][y][1]].collision == true then
2142					x = x + 1
2143				else
2144					local col = checkrect(x, self.y, self.width, self.height, {"exclude", self}, true)
2145					if #col == 0 then
2146						self.x = x
2147						if self.speedx < 0 then
2148							self.speedx = 0
2149						end
2150						return false
2151					end
2152				end
2153			end
2154		end
2155
2156		hitblock(x, y, self)
2157	end
2158
2159	self.jumping = false
2160	self.falling = true
2161	self.speedy = headforce
2162end
2163
2164function mario:globalcollide(a, b)
2165	if a == "screenboundary" then
2166		if self.x+self.width/2 > b.x then
2167			self.x = b.x
2168		else
2169			self.x = b.x-self.width
2170		end
2171		self.speedx = 0
2172		return true
2173	elseif a == "vine" then
2174		if self.vine == false then
2175			self:grabvine(b)
2176		end
2177
2178		return true
2179	end
2180end
2181
2182function mario:passivecollide(a, b)
2183	if self:globalcollide(a, b) then
2184		return false
2185	end
2186
2187	if a == "platform" or a == "seesawplatform" or a == "portalwall" then
2188		return false
2189	elseif a == "box" then
2190		if self.speedx < 0 then
2191			if self.speedx < -maxwalkspeed/2 then
2192				self.speedx = self.speedx - self.speedx * 0.1
2193			end
2194
2195			--check if box can even move
2196			local out = checkrect(b.x+self.speedx*gdt, b.y, b.width, b.height, {"exclude", b})
2197			if #out == 0 then
2198				b.speedx = self.speedx
2199				return false
2200			end
2201		else
2202			if self.speedx > maxwalkspeed/2 then
2203				self.speedx = self.speedx - self.speedx * 6 * gdt
2204			end
2205
2206			--check if box can even move
2207			local out = checkrect(b.x+self.speedx*gdt, b.y, b.width, b.height, {"exclude", b})
2208			if #out == 0 then
2209				b.speedx = self.speedx
2210				return false
2211			end
2212		end
2213	end
2214	if self.passivemoved == false then
2215		self.passivemoved = true
2216		if a == "tile" then
2217			local x, y = b.cox, b.coy
2218
2219			--check for invisible block
2220			if inmap(x, y) and tilequads[map[x][y][1]].invisible then
2221				return false
2222			end
2223
2224			if self.pointingangle < 0 then
2225				self.x = self.x - passivespeed*gdt
2226			else
2227				self.x = self.x + passivespeed*gdt
2228			end
2229			self.speedx = 0
2230		else
2231			--nothing, lol.
2232		end
2233	end
2234
2235
2236	self:rightcollide(a, b)
2237end
2238
2239function mario:starcollide(a, b)
2240	--enemies that die
2241	if a == "goomba" or a == "koopa" or a == "plant" or a == "bowser" or a == "squid" or a == "cheep" or a == "hammerbro" or a == "lakito" or a == "bulletbill" or a == "flyingfish" then
2242		b:shotted("right")
2243		if a ~= "bowser" then
2244			addpoints(firepoints[a], self.x, self.y)
2245		end
2246		return true
2247	--enemies (and stuff) that don't do shit
2248	elseif a == "upfire" or a == "fire" or a == "hammer" or a == "fireball" or a == "castlefirefire" then
2249		return true
2250	end
2251end
2252
2253function mario:hitspring(b)
2254	b:hit()
2255	self.springb = b
2256	self.springx = self.x
2257	self.springy = b.coy
2258	self.speedy = 0
2259	self.spring = true
2260	self.springhigh = false
2261	self.springtimer = 0
2262	self.gravity = 0
2263	self.mask[19] = true
2264	self.animationstate = "idle"
2265	self:setquad()
2266end
2267
2268function mario:leavespring()
2269	self.y = self.springy - self.height-31/16
2270	if self.springhigh then
2271		self.speedy = -springhighforce
2272	else
2273		self.speedy = -springforce
2274	end
2275	self.animationstate = "falling"
2276	self:setquad()
2277	self.gravity = yacceleration
2278	self.falling = true
2279	self.spring = false
2280	self.mask[19] = false
2281end
2282
2283function mario:dropvine(dir)
2284	if dir == "right" then
2285		self.x = self.x + 7/16
2286	else
2287		self.x = self.x - 7/16
2288	end
2289	self.animationstate = "falling"
2290	self:setquad()
2291	self.gravity = mariogravity
2292	self.vine = false
2293	self.mask[18] = false
2294end
2295
2296function mario:grabvine(b)
2297	self.ducking = false
2298	if insideportal(self.x, self.y, self.width, self.height) then
2299		return
2300	end
2301	self.mask[18] = true
2302	self.vine = true
2303	self.gravity = 0
2304	self.speedx = 0
2305	self.speedy = 0
2306	self.animationstate = "climbing"
2307	self.climbframe = 2
2308	self.vinemovetimer = 0
2309	self:setquad()
2310	self.vinex = b.cox
2311	self.viney = b.coy
2312	if b.x > self.x then --left of vine
2313		self.x = b.x+b.width/2-self.width+2/16
2314		self.pointingangle = -math.pi/2
2315		self.vineside = "left"
2316	else --right
2317		self.x = b.x+b.width/2 - 2/16
2318		self.pointingangle = math.pi/2
2319		self.vineside = "right"
2320	end
2321end
2322
2323function hitblock(x, y, t)
2324	for i = 1, players do
2325		local x1 = objects["player"][i].portal1X
2326		local y1 = objects["player"][i].portal1Y
2327
2328		local x2 = objects["player"][i].portal2X
2329		local y2 = objects["player"][i].portal2Y
2330
2331		local x3 = x1
2332		local y3 = y1
2333
2334		if objects["player"][i].portal1facing == "up" then
2335			x3 = x3+1
2336		elseif objects["player"][i].portal1facing == "right" then
2337			y3 = y3+1
2338		elseif objects["player"][i].portal1facing == "down" then
2339			x3 = x3-1
2340		elseif objects["player"][i].portal1facing == "left" then
2341			y3 = y3-1
2342		end
2343
2344		local x4 = x2
2345		local y4 = y2
2346
2347		if objects["player"][i].portal2facing == "up" then
2348			y4 = y4-1
2349		elseif objects["player"][i].portal2facing == "right" then
2350			x4 = x4+1
2351		elseif objects["player"][i].portal2facing == "down" then
2352			y4 = y4+1
2353		elseif objects["player"][i].portal2facing == "left" then
2354			x4 = x4-1
2355		end
2356
2357		if (x == x1 and y == y1) or (x == x2 and y == y2) or (x == x3 and y == y3) or (x == x4 and y == y4) then
2358			return
2359		end
2360	end
2361
2362
2363	if editormode then
2364		return
2365	end
2366
2367	if not inmap(x, y) then
2368		return
2369	end
2370
2371	local r = map[x][y]
2372	playsound(blockhitsound)
2373
2374	if tilequads[r[1]].breakable == true or tilequads[r[1]].coinblock == true then --Block should bounce!
2375		table.insert(blockbouncetimer, 0.000000001) --yeah it's a cheap solution to a problem but screw it.
2376		table.insert(blockbouncex, x)
2377		table.insert(blockbouncey, y)
2378		generatespritebatch()
2379		if #r > 1 and entityquads[r[2]].t ~= "manycoins" then --block contained something!
2380			table.insert(blockbouncecontent, entityquads[r[2]].t)
2381			table.insert(blockbouncecontent2, t.size)
2382			if tilequads[r[1]].invisible then
2383				if spriteset == 1 then
2384					map[x][y][1] = 113
2385				elseif spriteset == 2 then
2386					map[x][y][1] = 118
2387				else
2388					map[x][y][1] = 112
2389				end
2390			else
2391				if spriteset == 1 then
2392					map[x][y][1] = 113
2393				elseif spriteset == 2 then
2394					map[x][y][1] = 114
2395				else
2396					map[x][y][1] = 117
2397				end
2398			end
2399			if entityquads[r[2]].t == "vine" then
2400				playsound(vinesound)
2401			else
2402				playsound(mushroomappearsound)
2403			end
2404		else
2405			table.insert(blockbouncecontent, false)
2406			table.insert(blockbouncecontent2, t.size)
2407
2408			if t and t.size > 1 and tilequads[r[1]].coinblock == false and (#r == 1 or entityquads[r[2]].t ~= "manycoins") then --destroy block!
2409				destroyblock(x, y)
2410			end
2411		end
2412
2413		if #r == 1 and tilequads[r[1]].coinblock then --coinblock
2414			playsound(coinsound)
2415			if tilequads[r[1]].invisible then
2416				if spriteset == 1 then
2417					map[x][y][1] = 113
2418				elseif spriteset == 2 then
2419					map[x][y][1] = 118
2420				else
2421					map[x][y][1] = 112
2422				end
2423			else
2424				if spriteset == 1 then
2425					map[x][y][1] = 113
2426				elseif spriteset == 2 then
2427					map[x][y][1] = 114
2428				else
2429					map[x][y][1] = 117
2430				end
2431			end
2432			if #r == 1 then
2433				table.insert(coinblockanimations, coinblockanimation:new(x-0.5, y-1))
2434				mariocoincount = mariocoincount + 1
2435				if mariocoincount == 100 then
2436					if mariolivecount ~= false then
2437						for i = 1, players do
2438							mariolives[i] = mariolives[i] + 1
2439							respawnplayers()
2440						end
2441					end
2442					mariocoincount = 0
2443					playsound(oneupsound)
2444				end
2445				addpoints(200)
2446			end
2447		end
2448
2449		if #r > 1 and entityquads[r[2]].t == "manycoins" then --block with many coins inside! yay $_$
2450			playsound(coinsound)
2451			table.insert(coinblockanimations, coinblockanimation:new(x-0.5, y-1))
2452			mariocoincount = mariocoincount + 1
2453
2454			if mariocoincount == 100 then
2455				if mariolivecount ~= false then
2456					for i = 1, players do
2457						mariolives[i] = mariolives[i] + 1
2458						respawnplayers()
2459					end
2460				end
2461				mariocoincount = 0
2462				playsound(oneupsound)
2463			end
2464			addpoints(200)
2465
2466			local exists = false
2467			for i = 1, #coinblocktimers do
2468				if x == coinblocktimers[i][1] and y == coinblocktimers[i][2] then
2469					exists = i
2470				end
2471			end
2472
2473			if not exists then
2474				table.insert(coinblocktimers, {x, y, coinblocktime})
2475			elseif coinblocktimers[exists][3] <= 0 then
2476				if spriteset == 1 then
2477					map[x][y][1] = 113
2478				elseif spriteset == 2 then
2479					map[x][y][1] = 114
2480				else
2481					map[x][y][1] = 117
2482				end
2483			end
2484		end
2485
2486		--kill enemies on top
2487		for i, v in pairs(enemies) do
2488			if objects[v] then
2489				for j, w in pairs(objects[v]) do
2490					local centerX = w.x + w.width/2
2491					if inrange(centerX, x-1, x, true) and y-1 == w.y+w.height then
2492						--get dir
2493						local dir = "right"
2494						if w.x+w.width/2 < x-0.5 then
2495							dir = "left"
2496						end
2497
2498						if w.shotted then
2499							w:shotted(dir)
2500							addpoints(100, w.x+w.width/2, w.y)
2501						end
2502					end
2503				end
2504			end
2505		end
2506
2507		--make items jump
2508		for i, v in pairs(jumpitems) do
2509			for j, w in pairs(objects[v]) do
2510				local centerX = w.x + w.width/2
2511				if inrange(centerX, x-1, x, true) and y-1 == w.y+w.height then
2512					if w.jump then
2513						w:jump(x)
2514					end
2515				end
2516			end
2517		end
2518
2519		--check for coin on top
2520		if inmap(x, y-1) and tilequads[map[x][y-1][1]].coin then
2521			collectcoin(x, y-1)
2522			table.insert(coinblockanimations, coinblockanimation:new(x-0.5, y-1))
2523		end
2524	end
2525end
2526
2527function destroyblock(x, y)
2528	for i = 1, players do
2529		local x1 = objects["player"][i].portal1X
2530		local y1 = objects["player"][i].portal1Y
2531
2532		local x2 = objects["player"][i].portal2X
2533		local y2 = objects["player"][i].portal2Y
2534
2535		local x3 = x1
2536		local y3 = y1
2537
2538		if objects["player"][i].portal1facing == "up" then
2539			x3 = x3+1
2540		elseif objects["player"][i].portal1facing == "right" then
2541			y3 = y3+1
2542		elseif objects["player"][i].portal1facing == "down" then
2543			x3 = x3-1
2544		elseif objects["player"][i].portal1facing == "left" then
2545			y3 = y3-1
2546		end
2547
2548		local x4 = x2
2549		local y4 = y2
2550
2551		if objects["player"][i].portal2facing == "up" then
2552			y4 = y4-1
2553		elseif objects["player"][i].portal2facing == "right" then
2554			x4 = x4+1
2555		elseif objects["player"][i].portal2facing == "down" then
2556			y4 = y4+1
2557		elseif objects["player"][i].portal2facing == "left" then
2558			x4 = x4-1
2559		end
2560
2561		if (x == x1 and y == y1) or (x == x2 and y == y2) or (x == x3 and y == y3) or (x == x4 and y == y4) then
2562			return
2563		end
2564	end
2565
2566	map[x][y][1] = 1
2567	objects["tile"][x .. "-" .. y] = nil
2568	map[x][y]["gels"] = {}
2569	playsound(blockbreaksound)
2570	addpoints(50)
2571
2572	table.insert(blockdebristable, blockdebris:new(x-.5, y-.5, 3.5, -23))
2573	table.insert(blockdebristable, blockdebris:new(x-.5, y-.5, -3.5, -23))
2574	table.insert(blockdebristable, blockdebris:new(x-.5, y-.5, 3.5, -14))
2575	table.insert(blockdebristable, blockdebris:new(x-.5, y-.5, -3.5, -14))
2576
2577	generatespritebatch()
2578end
2579
2580function mario:faithplate(dir)
2581	self.animationstate = "jumping"
2582	self.falling = true
2583	self:setquad()
2584end
2585
2586function mario:startfall()
2587	if self.falling == false then
2588		self.falling = true
2589		self.animationstate = "falling"
2590		self:setquad()
2591	end
2592end
2593
2594function mario:die(how)
2595	print("Death cause: " .. how)
2596
2597	if how ~= "pit" and how ~= "time" then
2598		if self.size > 1 then
2599			self:shrink()
2600			return
2601		end
2602	elseif how ~= "time" then
2603		if bonusstage then
2604			levelscreen_load("sublevel", 0)
2605			return
2606		end
2607	end
2608
2609	if editormode then
2610		self.y = 0
2611		self.speedy = 0
2612		return
2613	end
2614	self.dead = true
2615
2616	everyonedead = true
2617	for i = 1, players do
2618		if not objects["player"][i].dead then
2619			everyonedead = false
2620		end
2621	end
2622
2623	self.animationmisc = nil
2624	if everyonedead then
2625		self.animationmisc = "everyonedead"
2626		love.audio.stop()
2627	end
2628
2629	playsound(deathsound)
2630
2631	if how == "time" then
2632		noupdate = false
2633		self.quadcenterY = 10
2634		self.graphic = self.smallgraphic
2635		self.size = 1
2636		self.quadcenterX = 11
2637		self.offsetY = 3
2638		self.drawable = true
2639	end
2640
2641	if how == "pit" then
2642		self.animation = "deathpit"
2643		self.size = 1
2644		self.drawable = false
2645		self.invincible = false
2646	else
2647		self.animation = "death"
2648		self.drawable = true
2649		self.invincible = false
2650		self.animationstate = "dead"
2651		self:setquad()
2652		self.speedy = 0
2653	end
2654
2655	self.y = self.y - 1/16
2656
2657	self.animationx = self.x
2658	self.animationy = self.y
2659	self.animationtimer = 0
2660	self.controlsenabled = false
2661	self.active = false
2662	prevsublevel = nil
2663
2664	if not levelfinished and not testlevel and not infinitelives and mariolivecount ~= false then
2665		mariolives[self.playernumber] = mariolives[self.playernumber] - 1
2666	end
2667
2668	return
2669end
2670
2671function mario:laser(dir)
2672	if self.pickup then
2673		if dir == "right" and self.pointingangle < 0 then
2674			return
2675		elseif dir == "left" and self.pointingangle > 0 then
2676			return
2677		elseif dir == "up" and self.pointingangle > -math.pi/2 and self.pointingangle < math.pi/2 then
2678			return
2679		elseif dir == "down" and (self.pointingangle > math.pi/2 or self.pointingangle < -math.pi/2) then
2680			return
2681		end
2682	end
2683	self:die("Laser")
2684end
2685
2686function getAngleFrame(angle)
2687	local mouseabs = math.abs(angle)
2688	local angleframe
2689
2690	if mouseabs < math.pi/8 then
2691		angleframe = 1
2692	elseif mouseabs >= math.pi/8 and mouseabs < math.pi/8*3 then
2693		angleframe = 2
2694	elseif mouseabs >= math.pi/8*3 and mouseabs < math.pi/8*5 then
2695		angleframe = 3
2696	elseif mouseabs >= math.pi/8*5 and mouseabs < math.pi/8*7 then
2697		angleframe = 4
2698	elseif mouseabs >= math.pi/8*7 then
2699		angleframe = 4
2700	end
2701
2702	return angleframe
2703end
2704
2705function mario:emancipate(a)
2706	self:removeportals()
2707
2708	local delete = {}
2709
2710	for i, v in pairs(portalprojectiles) do
2711		if v.payload[1] == self.playernumber then
2712			table.insert(delete, i)
2713		end
2714	end
2715
2716	table.sort(delete, function(a,b) return a>b end)
2717
2718	for i, v in pairs(delete) do
2719		table.remove(portalprojectiles, v) --remove
2720	end
2721end
2722
2723function mario:removeportals(i)
2724	if self.portal1X or self.portal2X then
2725		playsound(portalfizzlesound)
2726	end
2727
2728	moveoutportal(1)
2729	moveoutportal(2)
2730
2731	if i ~= 2 then
2732
2733		if self.portal1facing == "up" then
2734			modifyportaltiles(self.portal1X, self.portal1Y, 1, 0, self.playernumber, 1, "add")
2735		elseif self.portal1facing == "down" then
2736			modifyportaltiles(self.portal1X, self.portal1Y, -1, 0, self.playernumber, 1, "add")
2737		elseif self.portal1facing == "left" then
2738			modifyportaltiles(self.portal1X, self.portal1Y, 0, -1, self.playernumber, 1, "add")
2739		elseif self.portal1facing == "right" then
2740			modifyportaltiles(self.portal1X, self.portal1Y, 0, 1, self.playernumber, 1, "add")
2741		end
2742		self.portal1X, self.portal1Y = false, false
2743
2744		objects["portalwall"][self.playernumber .. "-1-1"] = nil
2745		objects["portalwall"][self.playernumber .. "-1-2"] = nil
2746		objects["portalwall"][self.playernumber .. "-1-3"] = nil
2747	end
2748
2749	if i ~= 1 then
2750
2751		if self.portal2facing == "up" then
2752			modifyportaltiles(self.portal2X, self.portal2Y, 1, 0, self.playernumber, 2, "add")
2753		elseif self.portal2facing == "down" then
2754			modifyportaltiles(self.portal2X, self.portal2Y, -1, 0, self.playernumber, 2, "add")
2755		elseif self.portal2facing == "left" then
2756			modifyportaltiles(self.portal2X, self.portal2Y, 0, -1, self.playernumber, 2, "add")
2757		elseif self.portal2facing == "right" then
2758			modifyportaltiles(self.portal2X, self.portal2Y, 0, 1, self.playernumber, 2, "add")
2759		end
2760		self.portal2X, self.portal2Y  = false, false
2761
2762		objects["portalwall"][self.playernumber .. "-2-1"] = nil
2763		objects["portalwall"][self.playernumber .. "-2-2"] = nil
2764		objects["portalwall"][self.playernumber .. "-2-3"] = nil
2765	end
2766
2767	if i ~= 2 then
2768		self.portal1facing = nil
2769	end
2770	if i ~= 1 then
2771		self.portal2facing = nil
2772	end
2773
2774	for i, v in pairs(objects["lightbridge"]) do
2775		v:updaterange()
2776	end
2777
2778	for i, v in pairs(objects["laser"]) do
2779		v:updaterange()
2780	end
2781end
2782
2783function mario:use()
2784	if self.pickup then
2785		if self.pickup.destroying then
2786			self.pickup = false
2787		else
2788			self:dropbox()
2789			return
2790		end
2791	end
2792	local xcenter = self.x + 6/16 - math.sin(self.pointingangle)*userange
2793	local ycenter = self.y + 6/16 - math.cos(self.pointingangle)*userange
2794
2795	local col = userect(xcenter-usesquaresize/2, ycenter-usesquaresize/2, usesquaresize, usesquaresize)
2796	if #col > 0 then
2797		col[1]:used(self.playernumber)
2798	end
2799end
2800
2801function mario:pickupbox(box)
2802	self.pickup = box
2803end
2804
2805function mario:dropbox()
2806	self.pickup:dropped()
2807
2808	local set = false
2809
2810	local boxx = self.x+math.sin(-self.pointingangle)*0.3
2811	local boxy = self.y-math.cos(-self.pointingangle)*0.3
2812
2813	if self.pointingangle < 0 then
2814		if #checkrect(self.x+self.width, self.y+self.height-12/16, 12/16, 12/16, {"exclude", self.pickup}, true) == 0 then
2815			self.pickup.x = self.x+self.width
2816			self.pickup.y = self.y+self.height-12/16
2817			set = true
2818		end
2819	else
2820		if #checkrect(self.x-12/16, self.y+self.height-12/16, 12/16, 12/16, {"exclude", self.pickup}, true) == 0 then
2821			self.pickup.x = self.x-12/16
2822			self.pickup.y = self.y+self.height-12/16
2823			set = true
2824		end
2825	end
2826
2827	if set == false then
2828		if #checkrect(self.x+self.width, self.y+self.height-12/16, 12/16, 12/16, {"exclude", self.pickup}, true) == 0 then
2829			self.pickup.x = self.x+self.width
2830			self.pickup.y = self.y+self.height-12/16
2831		elseif #checkrect(self.x-12/16, self.y+self.height-12/16, 12/16, 12/16, {"exclude", self.pickup}, true) == 0 then
2832			self.pickup.x = self.x-12/16
2833			self.pickup.y = self.y+self.height-12/16
2834		elseif #checkrect(self.x, self.y+self.height, 12/16, 12/16, {"exclude", self.pickup}, true) == 0 then
2835			self.pickup.x = self.x
2836			self.pickup.y = self.y+self.height
2837		elseif #checkrect(self.x, self.y-12/16, 12/16, 12/16, {"exclude", self.pickup}, true) == 0 then
2838			self.pickup.x = self.x
2839			self.pickup.y = self.y-12/16
2840		else
2841			self.pickup.x = self.x
2842			self.pickup.y = self.y
2843		end
2844	end
2845
2846	for h, u in pairs(emancipationgrills) do
2847		if u.dir == "hor" then
2848			if inrange(self.pickup.x+6/16, u.startx-1, u.endx, true) and inrange(u.y-14/16, boxy, self.pickup.y, true) then
2849				self.pickup:emancipate(h)
2850			end
2851		else
2852			if inrange(self.pickup.y+6/16, u.starty-1, u.endy, true) and inrange(u.x-14/16, boxx, self.pickup.x, true) then
2853				self.pickup:emancipate(h)
2854			end
2855		end
2856	end
2857	self.pickup = nil
2858end
2859
2860function mario:cubeemancipate()
2861	self.pickup = nil
2862end
2863
2864function mario:duck(ducking) --goose
2865	self.ducking = ducking
2866	if self.ducking then
2867		self.y = self.y + 12/16
2868		self.height = 12/16
2869		self.quadcenterY = 22
2870		self.offsetY = 7
2871	else
2872		self.y = self.y - 12/16
2873		self.height = 24/16
2874		self.quadcenterY = 20
2875		self.offsetY = -3
2876	end
2877end
2878
2879function mario:pipe(x, y, dir, i)
2880	self.active = false
2881	self.animation = "pipe" .. dir
2882	self.invincible = false
2883	self.drawable = true
2884	self.animationx = x
2885	self.animationy = y
2886	self.animationtimer = 0
2887	self.animationmisc = i
2888	self.controlsenabled = false
2889	playsound(pipesound)
2890
2891	if intermission then
2892		respawnsublevel = i
2893	end
2894
2895	if dir == "down" then
2896		if self.size > 1 then
2897			self.animationy = y - self.height + 12/16
2898		end
2899		self.animationstate = "idle"
2900		self.customscissor = {x-2, y-3, 2, 2}
2901	else
2902		if self.size == 1 then
2903			self.y = self.animationy-1/16 - self.height
2904		else
2905			self.y = self.animationy-1/16 - self.height
2906		end
2907		self.animationstate = "running"
2908		self.customscissor = {x-2, y-3, 1, 4}
2909	end
2910
2911	self:setquad()
2912end
2913
2914function mario:flag()
2915	if levelfinished then
2916		return
2917	end
2918	self.ducking = false
2919	self.animation = "flag"
2920	self.invincible = false
2921	self.drawable = true
2922	self.controlsenabled = false
2923	self.animationstate = "climbing"
2924	self.pointingangle = -math.pi/2
2925	self.animationtimer = 0
2926	self.speedx = 0
2927	self.speedy = 0
2928	self.x = flagx-2/16
2929	self.gravity = 0
2930	self.climbframe = 2
2931	self.active = false
2932	self:setquad()
2933	levelfinished = true
2934	levelfinishtype = "flag"
2935	subtractscore = false
2936	firework = false
2937	castleflagy = castleflagstarty
2938	objects["screenboundary"]["flag"].active = false
2939
2940	--get score
2941	flagscore = flagscores[1]
2942	for i = 1, #flagvalues do
2943		if self.y < flagvalues[i] then
2944			flagscore = flagscores[i+1]
2945		else
2946			break
2947		end
2948	end
2949
2950	addpoints(flagscore)
2951
2952	--get firework count
2953	fireworkcount = tonumber(string.sub(math.ceil(mariotime), -1, -1))
2954	if fireworkcount ~= 1 and fireworkcount ~= 3 and fireworkcount ~= 6 then
2955		fireworkcount = 0
2956	end
2957
2958	if portalbackground then
2959		fireworkcount = 0
2960	end
2961
2962	love.audio.stop()
2963
2964
2965	playsound(levelendsound)
2966end
2967
2968function mario:axe()
2969	if levelfinished then
2970		return
2971	end
2972	self.ducking = false
2973	for i = 1, players do
2974		objects["player"][i]:removeportals()
2975	end
2976
2977	for i, v in pairs(objects["platform"]) do
2978		objects["platform"][i] = nil
2979	end
2980
2981	self.animation = "axe"
2982	self.invincible = false
2983	self.drawable = true
2984	self.animationx = axex
2985	self.animationy = axey
2986	self.animationbridgex = axex-1
2987	self.animationbridgey = axey+2
2988	self.controlsenabled = false
2989	self.animationtimer = 0
2990	self.speedx = 0
2991	self.speedy = 0
2992	self.gravity = 0
2993	self.active = false
2994	levelfinished = true
2995	levelfinishtype = "castle"
2996	levelfinishedmisc = 0
2997	levelfinishedmisc2 = 1
2998	if marioworld == 8 then
2999		levelfinishedmisc2 = 2
3000	end
3001	bridgedisappear = false
3002	self.animationtimer2 = castleanimationbridgedisappeardelay
3003	bowserfall = false
3004	objects["screenboundary"]["axe"] = nil
3005
3006	if objects["bowser"][1] and not objects["bowser"][1].shot then
3007		local v = objects["bowser"][1]
3008		v.speedx = 0
3009		v.speedy = 0
3010		v.active = false
3011		v.gravity = 0
3012		v.category = 1
3013	else
3014		self.animationtimer = castleanimationmariomove
3015		self.active = true
3016		self.gravity = mariogravity
3017		self.animationstate = "running"
3018		self.speedx = 4.27
3019		self.pointingangle = -math.pi/2
3020
3021		love.audio.stop()
3022		playsound(castleendsound)
3023	end
3024
3025	axex = false
3026	axey = false
3027end
3028
3029function mario:vineanimation()
3030	self.animation = "vine"
3031	self.invincible = false
3032	self.drawable = true
3033	self.controlsenabled = false
3034	self.animationx = self.x
3035	self.animationy = vineanimationstart
3036	self.animationmisc = map[self.vinex][self.viney][3]
3037	self.active = false
3038	self.vine = false
3039end
3040
3041function mario:star()
3042	addpoints(1000)
3043	self.startimer = 0
3044	self.colors = starcolors[1]
3045	self.starred = true
3046	stopmusic()
3047	music:play("starmusic")
3048end
3049
3050function mario:fire()
3051	if not noupdate and self.controlsenabled and self.size == 3 and self.ducking == false then
3052		if self.fireballcount < maxfireballs then
3053			local dir = "right"
3054			if self.pointingangle > 0 then
3055				dir = "left"
3056			end
3057			table.insert(objects["fireball"], fireball:new(self.x+.5, self.y, dir, self))
3058			self.fireballcount = self.fireballcount + 1
3059			self.fireanimationtimer = 0
3060			self:setquad()
3061			playsound(fireballsound)
3062		end
3063	end
3064end
3065
3066function mario:fireballcallback()
3067	self.fireballcount = self.fireballcount - 1
3068end
3069
3070function collectcoin(x, y)
3071	map[x][y][1] = 1
3072	addpoints(200)
3073	playsound(coinsound)
3074	mariocoincount = mariocoincount + 1
3075	if mariocoincount == 100 then
3076		if mariolivecount ~= false then
3077			for i = 1, players do
3078				mariolives[i] = mariolives[i] + 1
3079				respawnplayers()
3080			end
3081		end
3082		mariocoincount = 0
3083		playsound(oneupsound)
3084	end
3085end
3086
3087function mario:portaled(dir)
3088	if self.pickup then
3089		self.pickup:portaled()
3090	end
3091	if not sonicrainboom or not self.rainboomallowed then
3092		return
3093	end
3094
3095	local didrainboom = false
3096
3097	if dir == "up" then
3098		if self.speedy < -rainboomspeed then
3099			didrainboom = true
3100		end
3101	elseif dir == "left" then
3102		if self.speedx < -rainboomspeed then
3103			didrainboom = true
3104		end
3105	elseif dir == "right" then
3106		if self.speedx > rainboomspeed then
3107			didrainboom = true
3108		end
3109	end
3110
3111	if didrainboom then
3112		table.insert(rainbooms, rainboom:new(self.x+self.width/2, self.y+self.height/2, dir))
3113		earthquake = rainboomearthquake
3114		self.rainboomallowed = false
3115		playsound(rainboomsound)
3116
3117		for i, v in pairs(enemies) do
3118			if objects[v] then
3119				for j, w in pairs(objects[v]) do
3120					w:shotted()
3121					if v ~= "bowser" then
3122						addpoints(firepoints[v], w.x, w.y)
3123					else
3124						for i = 1, 6 do
3125							w:shotted()
3126						end
3127					end
3128				end
3129			end
3130		end
3131
3132		self.hats = {33}
3133	end
3134end
3135
3136function mario:shootgel(i)
3137	table.insert(objects["gel"], gel:new(self.x+self.width/2+8/16, self.y+self.height/2+6/16, i))
3138
3139	local xspeed = math.cos(-self.pointingangle-math.pi/2)*gelcannonspeed
3140	local yspeed = math.sin(-self.pointingangle-math.pi/2)*gelcannonspeed
3141
3142	objects["gel"][#objects["gel"]].speedy = yspeed
3143	objects["gel"][#objects["gel"]].speedx = xspeed
3144end
3145
3146function mario:respawn()
3147	if mariolivecount ~= false and (mariolives[self.playernumber] == 0 or levelfinished) then
3148		return
3149	end
3150
3151	local i = 1
3152	while i <= players and (objects["player"][i].dead or self.playernumber == i) do
3153		i = i + 1
3154	end
3155
3156	fastestplayer = objects["player"][i]
3157
3158	for i = 2, players do
3159		if objects["player"][i].x > fastestplayer.x and not objects["player"][i].dead then
3160			fastestplayer = objects["player"][i]
3161		end
3162	end
3163
3164	self.colors = mariocolors[self.playernumber]
3165	self.speedy = 0
3166	self.speedx = 0
3167	self.dead = false
3168	self.quadcenterY = 10
3169	self.height = 12/16
3170	self.graphic = self.smallgraphic
3171	self.size = 1
3172	self.quadcenterX = 11
3173	self.offsetY = 3
3174	self.drawable = true
3175	self.animationstate = "idle"
3176	self:setquad()
3177
3178	self.animation = "invincible"
3179	self.invincible = true
3180	self.animationtimer = 0
3181
3182	self.y = fastestplayer.y + fastestplayer.height-12/16
3183	self.x = fastestplayer.x
3184
3185	self.jumping = false
3186	self.falling = true
3187
3188	self.controlsenabled = true
3189	self.active = true
3190end
3191