1laser = class:new()
2
3function laser:init(x, y, dir, r)
4	self.cox = x
5	self.coy = y
6	self.dir = dir
7	self.r = r
8
9	self.blocked = false
10	self.lasertable = {}
11	self.outtable = {}
12
13	self.framestart = 0
14
15	self.enabled = true
16end
17
18function laser:link()
19	self.outtable = {}
20	if #self.r > 2 then
21		for j, w in pairs(outputs) do
22			for i, v in pairs(objects[w]) do
23				if tonumber(self.r[4]) == v.cox and tonumber(self.r[5]) == v.coy then
24					v:addoutput(self)
25					self.enabled = false
26				end
27			end
28		end
29	end
30end
31
32function laser:input(t)
33	if t == "on" then
34		self.enabled = true
35		self:updaterange()
36	elseif t == "off" then
37		self.enabled = false
38		self:updaterange()
39	else
40		self.enabled = not self.enabled
41		self:updaterange()
42	end
43end
44
45function laser:update(dt)
46	if self.framestart < 2 then
47		self.framestart = self.framestart + 1
48		return
49	end
50	local x, y, width, height
51	local col = false
52
53	for i = 1, #self.lasertable, 5 do
54		if self.lasertable[i] == "left" then
55
56			x = self.lasertable[i+1]-1+self.lasertable[i+3]
57			y = self.lasertable[i+2]-0.5625
58			width = -self.lasertable[i+3]+1
59			height = 2/16
60
61			local rectcol = checkrect(x, y, width, height, {"player", "box", "goomba", "koopa"})
62
63			if #rectcol > 0 then
64				col = true
65				self.blocked = true
66
67				local biggestx = -1
68				local biggesti
69
70				for j = 1, #rectcol, 2 do
71					if objects[rectcol[j]][rectcol[j+1]].x > biggestx then
72						biggestx = objects[rectcol[j]][rectcol[j+1]].x
73						biggesti = j
74					end
75				end
76
77				obj = objects[rectcol[biggesti]][rectcol[biggesti+1]]
78
79				if obj.laser then
80					obj:laser("right")
81				end
82
83				local newtable = {}
84				for k = 1, i*5 do
85					table.insert(newtable, self.lasertable[k])
86				end
87
88				newtable[i+3] = obj.x - newtable[i+1] + obj.width+1
89
90				self.lasertable = newtable
91
92				self:updateoutputs()
93				break
94			end
95
96		elseif self.lasertable[i] == "right" then
97
98			x = self.lasertable[i+1]-1
99			y = self.lasertable[i+2]-0.5625
100			width = self.lasertable[i+3]+1
101			height = 2/16
102
103			local rectcol = checkrect(x, y, width, height, {"player", "box", "goomba", "koopa"})
104
105			if #rectcol > 0 then
106				col = true
107				self.blocked = true
108
109				local smallestx = mapwidth+1
110				local smallesti
111
112				for j = 1, #rectcol, 2 do
113					if objects[rectcol[j]][rectcol[j+1]].x < smallestx then
114						smallestx = objects[rectcol[j]][rectcol[j+1]].x
115						smallesti = j
116					end
117				end
118
119				obj = objects[rectcol[smallesti]][rectcol[smallesti+1]]
120
121				if obj.laser then
122					obj:laser("left")
123				end
124
125				local newtable = {}
126				for k = 1, i*5 do
127					table.insert(newtable, self.lasertable[k])
128				end
129
130				newtable[i+3] = obj.x - newtable[i+1]
131
132				self.lasertable = newtable
133
134				self:updateoutputs()
135				break
136			end
137
138		elseif self.lasertable[i] == "up" then
139
140			x = self.lasertable[i+1]-0.5625
141			y = self.lasertable[i+2]+self.lasertable[i+4]-1
142			width = 2/16
143			height = -self.lasertable[i+4]+1
144
145			local rectcol = checkrect(x, y, width, height, {"player", "box", "goomba", "koopa"})
146
147			if #rectcol > 0 then
148				col = true
149				self.blocked = true
150
151				local biggesty = 0
152				local biggesti
153
154				for j = 1, #rectcol, 2 do
155					if objects[rectcol[j]][rectcol[j+1]].y > biggesty then
156						biggesty = objects[rectcol[j]][rectcol[j+1]].y
157						biggesti = j
158					end
159				end
160
161				obj = objects[rectcol[biggesti]][rectcol[biggesti+1]]
162
163				if obj.laser then
164					obj:laser("down")
165				end
166
167				local newtable = {}
168				for k = 1, i*5 do
169					table.insert(newtable, self.lasertable[k])
170				end
171
172				newtable[i+4] = obj.y - newtable[i+2]+1
173
174				self.lasertable = newtable
175
176				self:updateoutputs()
177				break
178			end
179
180		elseif self.lasertable[i] == "down" then
181
182			x = self.lasertable[i+1]-0.5625
183			y = self.lasertable[i+2]-1
184			width = 2/16
185			height = self.lasertable[i+4]+1
186
187			local rectcol = checkrect(x, y, width, height, {"player", "box", "goomba", "koopa"})
188
189			if #rectcol > 0 then
190				col = true
191				self.blocked = true
192
193				local smallesty = 16
194				local smallesti
195
196				for j = 1, #rectcol, 2 do
197					if objects[rectcol[j]][rectcol[j+1]].y < smallesty then
198						smallesty = objects[rectcol[j]][rectcol[j+1]].y
199						smallesti = j
200					end
201				end
202
203				obj = objects[rectcol[smallesti]][rectcol[smallesti+1]]
204
205				if obj.laser then
206					obj:laser("up")
207				end
208
209				local newtable = {}
210				for k = 1, i*5 do
211					table.insert(newtable, self.lasertable[k])
212				end
213
214				newtable[i+4] = obj.y - newtable[i+2] + 1 - obj.height+1-1
215
216				self.lasertable = newtable
217
218				self:updateoutputs()
219				break
220			end
221		end
222	end
223
224	self:updateoutputs()
225
226	if col == false and self.blocked == true then
227		self.blocked = false
228		self:updaterange()
229	end
230end
231
232function laser:updateoutputs()
233	for i = 1, #self.lasertable, 5 do
234		if self.lasertable[i] == "left" then
235			for x = self.lasertable[i+1], math.ceil(self.lasertable[i+1]+self.lasertable[i+3])-1, -1 do
236				local y = self.lasertable[i+2]
237				self:checktile(x, y)
238			end
239		elseif self.lasertable[i] == "right" then
240			for x = self.lasertable[i+1], math.floor(self.lasertable[i+1]+self.lasertable[i+3])+1 do
241				local y = self.lasertable[i+2]
242				self:checktile(x, y)
243			end
244		elseif self.lasertable[i] == "up" then
245			for y = self.lasertable[i+2], self.lasertable[i+2]+self.lasertable[i+4]-1, -1 do
246				local x = self.lasertable[i+1]
247				self:checktile(x, y)
248			end
249		elseif self.lasertable[i] == "down" then
250			for y = self.lasertable[i+2], self.lasertable[i+2]+self.lasertable[i+4]+1 do
251				local x = self.lasertable[i+1]
252				self:checktile(x, y)
253			end
254		end
255	end
256
257	for i, v in pairs(self.outtable) do
258		v:clear()
259	end
260end
261
262function laser:checktile(x, y)
263	--check if block is a detector
264	for i, v in pairs(objects["laserdetector"]) do
265		if x == v.cox and y == v.coy and (v.cox ~= self.r[4] or v.coy ~= self.r[5]) then
266			table.insert(self.outtable, v)
267			v:input("on")
268		end
269	end
270end
271
272function laser:draw()
273	for i = 1, #self.lasertable, 5 do
274		if self.lasertable[i] == "left" then
275			love.graphics.setScissor(math.floor((self.lasertable[i+1]+self.lasertable[i+3]-xscroll-1)*16*scale), (self.lasertable[i+2]-1.5)*16*scale, math.max((-self.lasertable[i+3]+1)*16*scale, 0), 16*scale)
276			for x = self.lasertable[i+1], math.floor(self.lasertable[i+1]+self.lasertable[i+3])-1, -1 do
277				love.graphics.draw(laserimg, math.floor((x-xscroll-1)*16*scale), (self.lasertable[i+2]-20/16)*16*scale, 0, scale, scale)
278			end
279		elseif self.lasertable[i] == "right" then
280			love.graphics.setScissor(math.floor((self.lasertable[i+1]-xscroll-1)*16*scale), (self.lasertable[i+2]-1.5)*16*scale, math.max((self.lasertable[i+3]+1)*16*scale, 0), 16*scale)
281			for x = self.lasertable[i+1], math.ceil(self.lasertable[i+1]+self.lasertable[i+3])+1 do
282				love.graphics.draw(laserimg, math.floor((x-xscroll-1)*16*scale), (self.lasertable[i+2]-20/16)*16*scale, 0, scale, scale)
283			end
284		elseif self.lasertable[i] == "up" then
285			for y = self.lasertable[i+2], self.lasertable[i+2]+self.lasertable[i+4], -1 do
286				love.graphics.draw(laserimg, math.floor((self.lasertable[i+1]-xscroll-5/16)*16*scale), (y-1)*16*scale, math.pi/2, scale, scale, 8, 1)
287			end
288		elseif self.lasertable[i] == "down" then
289			for y = self.lasertable[i+2], self.lasertable[i+2]+self.lasertable[i+4] do
290				love.graphics.draw(laserimg, math.floor((self.lasertable[i+1]-xscroll-5/16)*16*scale), (y-1)*16*scale, math.pi/2, scale, scale, 8, 1)
291			end
292		end
293
294		love.graphics.setScissor()
295	end
296
297	local rot = 0
298	if self.dir == "up" then
299		rot = math.pi*1.5
300	elseif self.dir == "down" then
301		rot = math.pi*0.5
302	elseif self.dir == "left" then
303		rot = math.pi
304	end
305
306	love.graphics.draw(lasersideimg, math.floor((self.cox-xscroll-.5)*16*scale), (self.coy-1)*16*scale, rot, scale, scale, 8, 8)
307end
308
309function laser:updaterange()
310	self.lasertable = {}
311	if self.enabled == false then
312		self:updateoutputs()
313		return
314	end
315
316	local dir = self.dir
317	local startx, starty = self.cox, self.coy
318	local rangex, rangey = 0, 0
319	local x, y = self.cox, self.coy
320
321	local firstcheck = true
322	local quit = false
323	while x >= 1 and x <= mapwidth and y >= 1 and y <= 15 and tilequads[map[x][y][1]].collision == false and (x ~= startx or y ~= starty or dir ~= self.dir or firstcheck == true) and quit == false do
324		firstcheck = false
325
326		if dir == "right" then
327			x = x + 1
328			rangex = rangex + 1
329		elseif dir == "left" then
330			x = x - 1
331			rangex = rangex - 1
332		elseif dir == "up" then
333			y = y - 1
334			rangey = rangey - 1
335		elseif dir == "down" then
336			y = y + 1
337			rangey = rangey + 1
338		end
339
340		--check if current block is a portal
341		local portalx, portaly, portalfacing, infacing = getPortal(x, y)
342
343		if portalx ~= false and ((dir == "left" and infacing == "right") or (dir == "right" and infacing == "left") or (dir == "up" and infacing == "down") or (dir == "down" and infacing == "up")) then
344
345			if dir == "right" then
346				x = x - 1
347				rangex = rangex - 1
348			elseif dir == "left" then
349				x = x + 1
350				rangex = rangex + 1
351			elseif dir == "up" then
352				y = y + 1
353				rangey = rangey + 1
354			elseif dir == "down" then
355				y = y - 1
356				rangey = rangey - 1
357			end
358
359			table.insert(self.lasertable, dir)
360			table.insert(self.lasertable, x-rangex)
361			table.insert(self.lasertable, y-rangey)
362			table.insert(self.lasertable, rangex)
363			table.insert(self.lasertable, rangey)
364
365			x, y = portalx, portaly
366			dir = portalfacing
367
368			rangex, rangey = 0, 0
369
370			if dir == "right" then
371				x = portalx + 1
372			elseif dir == "left" then
373				x = portalx - 1
374				rangex = 0
375			elseif dir == "up" then
376				y = portaly - 1
377			elseif dir == "down" then
378				y = portaly + 1
379			end
380		end
381
382		--doors
383		for i, v in pairs(objects["door"]) do
384			if v.active then
385				if v.dir == "ver" then
386					if x == v.cox and (y == v.coy or y == v.coy-1) then
387						quit = true
388					end
389				elseif v.dir == "hor" then
390					if y == v.coy and (x == v.cox or x == v.cox+1) then
391						quit = true
392					end
393				end
394			end
395		end
396	end
397
398	if dir == "right" then
399		x = x - 1
400		rangex = rangex - 1
401	elseif dir == "left" then
402		x = x + 1
403		rangex = rangex + 1
404	elseif dir == "up" then
405		y = y + 1
406		rangey = rangey + 1
407	elseif dir == "down" then
408		y = y - 1
409		rangey = rangey - 1
410	end
411
412	table.insert(self.lasertable, dir)
413	table.insert(self.lasertable, x-rangex)
414	table.insert(self.lasertable, y-rangey)
415	table.insert(self.lasertable, rangex)
416	table.insert(self.lasertable, rangey)
417
418	self:update()
419end