1-- GunFu Deadlands
2-- Copyright 2009-2011 Christiaan Janssen, September 2009-October 2011
3--
4-- This file is part of GunFu Deadlands.
5--
6--     GunFu Deadlands is free software: you can redistribute it and/or modify
7--     it under the terms of the GNU General Public License as published by
8--     the Free Software Foundation, either version 3 of the License, or
9--     (at your option) any later version.
10--
11--     GunFu Deadlands is distributed in the hope that it will be useful,
12--     but WITHOUT ANY WARRANTY; without even the implied warranty of
13--     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14--     GNU General Public License for more details.
15--
16--     You should have received a copy of the GNU General Public License
17--     along with GunFu Deadlands.  If not, see <http://www.gnu.org/licenses/>.
18
19Editor = {}
20
21function Editor.load()
22	Editor.enabled = false
23
24	Editor.versionstring="GunFuDeadlandsV1.00"
25
26	Editor.defaultmode = 4
27
28	Editor.former_mode = Editor.mode
29	Editor.current_element_index = 2
30	Editor.num_elements = table.getn(Entities.entitystrings)
31	Editor.current_element = Entities.new_element( Editor.current_element_index )
32	Editor.currentfilename=""
33	Editor.deletefilename = ""
34	Editor.slots={}
35	Editor.listingfilename="listing.gfd"
36	Editor.listingtable={}
37	Editor.listingoffset = 0
38	Editor.listinglength = 10
39	Editor.listingbox={20,60}
40	Editor.fileerror_timer = 0
41	Editor.resetting=false
42	Editor.showprogress = false
43end
44
45function Editor.init()
46	Editor.enabled = true
47	Editor.mode = Editor.defaultmode
48	Editor.dragging = false
49	Editor.dragging_from = {0,0}
50	Editor.shiftpressed = false
51	Editor.mouseposdiff = {0,0}
52
53	-- clear level
54	Level.init()
55
56	Player.pos = {320,240}
57	Player.starting_pos = { 320, 240 }
58	Level.reset_player()
59
60	Editor.firststart = false
61	Editor.wiping = false
62	Editor.resetting=false
63	Editor.showprogress = false
64
65	Editor.loadslotfile( 11 )
66	Editor.fileerror_timer = 0
67
68	Editor.reset_undo()
69end
70
71function Editor.draw()
72
73	if Editor.mode ==  6 then
74		Editor.showprogress = true
75	else
76		Editor.showprogress = false
77	end
78
79	if Editor.mode == 1 -- help
80	then
81		local line1="f1 - This screen\n"
82		local line2="f2 - Save current level into a file (delete with double-rightclick)\n"
83		local line3="f3 - Load level file into editor\n"
84		local line4="f4 - Move: Drag buildings and enemies around with the mouse.\n      Erase elements with right click.\n"
85		local line5="f5 - Add:  mousewheel or cursor up/down to select element, leftclick \n        for inserting new element, drag mouse for fences\n"
86		local line6="f6 - Test:  Play current level\n"
87		local line7="f7 - Restart level (resets player and enemies)\n"
88		local line8="f8 - Change level options\n"
89		local line9="f10 - Wipe:  erase level completely\n"
90		local line10="0..9 / shift+0..9 - quickload / quicksave\n"
91		local line11="Z / shift+Z - undo/redo\n"
92		local line12="ESC - Exit editor and return to main menu\n"
93		love.graphics.setColor(Colors.dark_black)
94		Graphics.drawtext(line1..line2..line3..line4..line5..line6..line7..line8..line9..line10..line11..line12, 30, 30)
95
96		love.graphics.draw(Graphics.images.f1help, 300, 5)
97		return
98	end
99
100
101
102	if Editor.mode==5 then
103		Graphics.draw()
104
105		if Editor.current_element_index >= Entities.entitylist.barrier_horiz
106			and Editor.current_element_index <= Entities.entitylist.fence_vert and
107			Editor.dragging then
108				Graphics.draw_building( Entities.new_element( Editor.current_element_index, Editor.itemcenter, Editor.itemlength ) )
109		else
110			Editor.drawelement({love.mouse.getX(), love.mouse.getY()})
111		end
112
113		love.graphics.draw(Graphics.images.f5add, 300, 5)
114	end
115
116	if Editor.mode==4 then
117		Graphics.draw()
118		love.graphics.draw(Graphics.images.f4move, 300, 5)
119	end
120
121	-- load & save: show files
122	if Editor.mode==2 or Editor.mode==3 then
123		Editor.showFileListing()
124	end
125
126	if Editor.mode==2 then
127		love.graphics.draw(Graphics.images.f2save, 300, 5)
128	end
129
130	if Editor.mode==3 then
131		love.graphics.draw(Graphics.images.f3load, 300, 5)
132	end
133
134	if Editor.mode==4 and Editor.dragging then
135		Editor.drawelement({love.mouse.getX()+Editor.mouseposdiff[1], love.mouse.getY()+Editor.mouseposdiff[2]})
136
137	end
138
139	if Editor.mode==6 then
140		-- test
141		Graphics.draw()
142		love.graphics.draw(Graphics.images.f6test, 300, 5)
143	end
144
145	if Editor.mode==7 then
146		-- options
147		local ecs="No"
148		if not Level.enemiescanshoot then ecs="Yes" end
149		local ninja="No"
150		if Level.ninjamode then ninja="Yes" end
151		local turns="No"
152		if Level.autoturns then turns="Yes" end
153		local onebullet="No"
154		if Level.onebullet then onebullet="Yes" end
155		love.graphics.setColor(Colors.dark_black)
156		Graphics.drawtext("Click to change:",40,50)
157		Graphics.drawtext("Enemies with no bullets ...... "..ecs, 40,100)
158		Graphics.drawtext("<Thieves in the shadows> mode .... "..ninja, 40,150)
159		Graphics.drawtext("Instantaneous turns .... "..turns, 40, 200)
160		Graphics.drawtext("One bullet per enemy .... "..onebullet, 40, 250)
161
162		love.graphics.draw(Graphics.images.f8opts, 300, 5)
163	end
164
165	if Editor.resetting then
166		love.graphics.draw(Graphics.images.f7reset, 300, 5)
167	end
168
169	if Editor.wiping then
170		love.graphics.draw(Graphics.images.f10wipe, 300, 5)
171	end
172
173end
174
175function Editor.drawelement(position)
176	if Editor.current_element.isbuilding then
177		Editor.current_element.pos = {position[1], position[2]}
178		Graphics.draw_building( Editor.current_element )
179	else
180		Graphics.drawCentered( Editor.current_element.sprite , love.mouse.getX(), love.mouse.getY() )
181	end
182end
183
184
185function Editor.showFileListing()
186
187	local x, y = Editor.listingbox[1],Editor.listingbox[2]
188	love.graphics.setColor(Colors.dark_black)
189	local firstline = "File <"..Editor.currentfilename.."> "
190
191	Graphics.drawtext(love.filesystem.getSaveDirectory( ), x, y-30 )
192	if Editor.fileerror_timer > 0 then
193		if Editor.mode == 2 then
194			firstline = "Error trying to save file"
195		end
196		if Editor.mode == 3 then
197			firstline = "Error loading file"
198		end
199	end
200
201	Graphics.drawtext(firstline,x,y)
202
203	if Editor.listingoffset > 0 then
204		Graphics.drawtext("(UP)",x,y+30)
205	end
206
207	local tolimit = Editor.listinglength
208	local tablelen = table.getn(Editor.listingtable)
209	if tolimit > tablelen then
210		tolimit = tablelen
211	end
212
213	for i=1,tolimit do
214		local fname = Editor.listingtable[i+Editor.listingoffset]
215		Graphics.drawtext(fname, x, y+i*30+30 )
216	end
217
218	if Editor.listinglength+Editor.listingoffset < tablelen then
219		Graphics.drawtext("(DOWN)",x,y+(Editor.listinglength+2)*30)
220	end
221
222	love.graphics.setLine(1,"rough")
223	love.graphics.line(0,y,screensize[1],y)
224	love.graphics.line(0,y+25,screensize[1],y+25)
225	love.graphics.line(0,y+(Editor.listinglength+2)*30+25,screensize[1],y+(Editor.listinglength+2)*30+25)
226
227	local myf = "F2"
228	if Editor.mode==3 then myf="F3" end
229	Graphics.drawtext("Type filename or double click file in the list. Press "..myf.." to scan dir again.",x,y+(Editor.listinglength+3)*30)
230end
231
232function Editor.update(dt)
233	if Editor.fileerror_timer>0 then
234		Editor.fileerror_timer = Editor.fileerror_timer - dt
235	end
236
237	if Editor.mode == 5 and Editor.dragging then
238		Editor.dragging_to = { love.mouse.getX(), love.mouse.getY() }
239		if Editor.current_element_index >= Entities.entitylist.barrier_horiz
240			and Editor.current_element_index <= Entities.entitylist.fence_vert  then
241			local dx = math.abs(Editor.dragging_to[1] - Editor.dragging_from[1])
242			local dy = math.abs(Editor.dragging_to[2] - Editor.dragging_from[2])
243
244			if dx > dy then
245				if Editor.current_element_index == Entities.entitylist.barrier_horiz or Editor.current_element_index == Entities.entitylist.barrier_vert then
246					Editor.current_element_index = Entities.entitylist.barrier_horiz
247					Editor.itemlength = math.floor(dx/31) + 1
248					Editor.itemcenter = { math.floor((Editor.dragging_from[1] + Editor.dragging_to[1])/2), Editor.dragging_from[2] }
249				else
250					Editor.current_element_index = Entities.entitylist.fence_horiz
251					Editor.itemlength = math.floor(dx/14) + 1
252					Editor.itemcenter = { math.floor((Editor.dragging_from[1] + Editor.dragging_to[1])/2), Editor.dragging_from[2] }
253				end
254			else
255				if Editor.current_element_index == Entities.entitylist.barrier_horiz or Editor.current_element_index == Entities.entitylist.barrier_vert then
256					Editor.current_element_index = Entities.entitylist.barrier_vert
257					Editor.itemlength = math.floor(dy/32) + 1
258					Editor.itemcenter = { Editor.dragging_from[1], math.floor((Editor.dragging_from[2] + Editor.dragging_to[2])/2) }
259				else
260					Editor.current_element_index = Entities.entitylist.fence_vert
261					Editor.itemlength = math.floor(dy/18) + 1
262					Editor.itemcenter = { Editor.dragging_from[1], math.floor((Editor.dragging_from[2] + Editor.dragging_to[2])/2) }
263				end
264			end
265		end
266
267	end
268
269
270	-- mode = 6, normal update
271	-- other modes... nothing to do I think
272	if Editor.mode == 6 then
273		Game.update(dt)
274	end
275
276	if Editor.mode == 2 or Editor.mode == 3 then
277
278	end
279end
280
281
282
283function Editor.keypressed(key)
284	local oldmode = Editor.mode
285  -- mode selection
286	if key == "f1" then
287		-- help
288		Editor.mode = 1
289	end
290
291	if key == "f2" then
292		-- save
293		if Editor.mode == 2 then
294		-- pressed again: refresh
295			Editor.refreshList()
296			Editor.listingtable = Editor.getFileList()
297		end
298		Editor.mode = 2
299	end
300
301	if key == "f3" then
302		-- load
303		if Editor.mode == 3 then
304		-- pressed again: refresh
305			Editor.refreshList()
306			Editor.listingtable = Editor.getFileList()
307		end
308		Editor.mode = 3
309	end
310
311	if key == "f4" then
312		-- move
313		Editor.mode = 4
314	end
315
316	if key == "f5" then
317		-- add
318		Editor.mode = 5
319	end
320
321	if key == "f6" then
322		-- test
323		Editor.mode = 6
324	end
325
326	if key == "f8" then
327		-- options
328		Editor.mode = 7
329	end
330
331	if key == "escape" then
332		Editor.saveslotfile( 11 )
333		Editor.mode = Editor.defaultmode
334		Game.titlescreen()
335    end
336
337	if key == "f7" then
338			Editor.resetting=true
339			Level.restart()
340	end
341
342	if key == "f10" then
343		Editor.wiping = true
344		Level.init() -- wipeout
345		Level.restart()
346		Editor.firststart = true
347		Editor.reset_undo()
348	end
349
350	if key == "lshift"  or key == "rshift" then
351		Editor.shiftpressed = true
352	end
353
354	if Editor.mode == 5 and key == "up" then
355		Editor.current_element_index = (Editor.current_element_index - 2) % Editor.num_elements + 1
356		-- special= skip element 1 (player)
357		if Editor.current_element_index == 1 then Editor.current_element_index = Editor.num_elements end
358		-- special = skip vertical fences
359		if Editor.current_element_index == Entities.entitylist.barrier_vert or
360			Editor.current_element_index == Entities.entitylist.fence_vert then
361				Editor.current_element_index = Editor.current_element_index - 1
362		end
363		Editor.current_element = Entities.new_element( Editor.current_element_index )
364	end
365	if Editor.mode == 5 and key == "down" then
366		Editor.current_element_index = Editor.current_element_index % Editor.num_elements + 1
367		-- special = skip vertical fences
368		if Editor.current_element_index == Entities.entitylist.barrier_vert or
369			Editor.current_element_index == Entities.entitylist.fence_vert then
370				Editor.current_element_index = Editor.current_element_index + 1
371		end
372
373		if Editor.current_element_index > Editor.num_elements then Editor.current_element_index = 1 end
374		if Editor.current_element_index == 1 then Editor.current_element_index = 2 end
375		Editor.current_element = Entities.new_element( Editor.current_element_index )
376	end
377
378	if Editor.mode == 4 or Editor.mode == 5 then
379		if key == "z" then
380			if Editor.shiftpressed then
381				Editor.redo()
382			else
383				Editor.undo()
384			end
385		end
386	end
387
388	-- slots
389	if not (Editor.mode == 2 or Editor.mode==3) then
390		local slot=nil
391		if key=="1" then slot = 1 end
392		if key=="2" then slot = 2 end
393		if key=="3" then slot = 3 end
394		if key=="4" then slot = 4 end
395		if key=="5" then slot = 5 end
396		if key=="6" then slot = 6 end
397		if key=="7" then slot = 7 end
398		if key=="8" then slot = 8 end
399		if key=="9" then slot = 9 end
400		if key=="0" then slot = 10 end
401		if slot then
402			if Editor.shiftpressed then
403				Editor.saveslotfile(slot)
404			else
405				Editor.loadslotfile(slot)
406			end
407		end
408	end
409
410	-- type in filename
411	if Editor.mode == 2 or Editor.mode == 3 then
412		local k = Editor.keyboard_input(key)
413		if k=="back" then
414			if string.len(Editor.currentfilename)>0 then
415				Editor.currentfilename = string.sub(Editor.currentfilename,1,-2)
416			end
417		elseif k=="return" then
418			-- confirm
419			if Editor.fileerror_timer <= 0 and string.len(Editor.currentfilename)>0 then
420				if Editor.mode == 3 then
421					Editor.trytoloadcurrent()
422				else
423					Editor.trytosavecurrent()
424				end
425			end
426		elseif k~="" then
427			Editor.currentfilename = Editor.currentfilename..k
428		end
429	end
430
431	if Editor.mode == 6 then
432		Game.keypressed(key)
433	end
434
435	if Editor.mode ~= oldmode then
436		Editor.fileerror_timer = 0
437
438		-- reload current element when switching state
439		if Editor.current_element_index == Entities.entitylist.barrier_vert then
440			Editor.current_element_index = Entities.entitylist.barrier_horiz
441		end
442		if Editor.current_element_index == Entities.entitylist.fence_vert then
443			Editor.current_element_index = Entities.entitylist.fence_horiz
444		end
445		if Editor.current_element_index == Entities.entitylist.player then
446			Editor.current_element_index = Entities.entitylist.blue_bandit
447		end
448		Editor.current_element = Entities.new_element( Editor.current_element_index )
449
450
451		-- switching to testmode
452		if Editor.mode ==  6 then
453			-- make sure that the "enemyless" flag is correct
454			Level.enemylessmode = (table.getn( Level.enemies ) == 0)
455			if Level.end_time<=0 then Level.end_time = 3 end
456			if Editor.firststart then
457				Level.restart()
458				Editor.firststart = false
459			end
460			-- activate
461			Editor.showprogress = true
462		else
463			Editor.showprogress = false
464		end
465
466		if Editor.mode == 2 or Editor.mode == 3 then
467			-- switching to file mode (load & save)
468			Editor.listingtable = Editor.getFileList()
469			Editor.currentfilename = ""
470			Editor.deletefilename = ""
471			Editor.listingoffset = 0
472		end
473	end
474-- building selection
475end
476
477function Editor.keyboard_input(key)
478	retval = ""
479	if key=="a" then retval = "A" end
480	if key=="b" then retval = "B" end
481	if key=="c" then retval = "C" end
482	if key=="d" then retval = "D" end
483	if key=="e" then retval = "E" end
484	if key=="f" then retval = "F" end
485	if key=="g" then retval = "G" end
486	if key=="h" then retval = "H" end
487	if key=="i" then retval = "I" end
488	if key=="j" then retval = "J" end
489	if key=="k" then retval = "K" end
490	if key=="l" then retval = "L" end
491	if key=="m" then retval = "M" end
492	if key=="n" then retval = "N" end
493	if key=="o" then retval = "O" end
494	if key=="p" then retval = "P" end
495	if key=="q" then retval = "Q" end
496	if key=="r" then retval = "R" end
497	if key=="s" then retval = "S" end
498	if key=="t" then retval = "T" end
499	if key=="u" then retval = "U" end
500	if key=="v" then retval = "V" end
501	if key=="w" then retval = "W" end
502	if key=="x" then retval = "X" end
503	if key=="y" then retval = "Y" end
504	if key=="z" then retval = "Z" end
505	if key=="0" then retval = "0" end
506	if key=="1" then retval = "1" end
507	if key=="2" then retval = "2" end
508	if key=="3" then retval = "3" end
509	if key=="4" then retval = "4" end
510	if key=="5" then retval = "5" end
511	if key=="6" then retval = "6" end
512	if key=="7" then retval = "7" end
513	if key=="8" then retval = "8" end
514	if key=="9" then retval = "9" end
515	if key=="minus" then retval = "-" end
516	if key=="backspace" then retval="back" end
517	if key=="return" then retval="return" end
518	if not Editor.shiftpressed then
519		retval = string.lower(retval)
520	end
521	return retval
522end
523
524function Editor.keyreleased(key)
525	if key == "f7" then
526		Editor.resetting=false
527	end
528
529	if key == "f10" then
530		Editor.wiping = false
531	end
532
533	if key == "lshift" or key == "rshift"  then
534		Editor.shiftpressed = false
535	end
536
537	if Editor.mode == 6 then
538		Game.keyreleased(key)
539	end
540
541end
542
543function Editor.mousepressed(x, y, button)
544	if Editor.mode == 4 and button == "l" then
545		local dr = Editor.findfor_substract(x,y)
546		local elem = Editor.substract(x,y)
547		if elem then
548			Editor.register_remove(dr[1],dr[2],dr[3],dr[4],dr[5],1)
549			Editor.dragging = true
550			Editor.current_element = elem
551			Editor.current_element_index = elem.id
552			Editor.current_element_original_pos = {Editor.current_element.pos[1],Editor.current_element.pos[2]}
553			Editor.mouseposdiff = { elem.pos[1] - x, elem.pos[2] - y }
554		end
555	end
556
557	if Editor.mode == 4 and button == "r" then
558		local dr = Editor.findfor_substract(x,y)
559		local elem =Editor.substract(x,y)
560		if elem then
561			Editor.register_remove(dr[1],dr[2],dr[3],dr[4],dr[5])
562		end
563	end
564
565	if Editor.mode == 5 and button == 'wu' then
566		Editor.current_element_index = (Editor.current_element_index - 2) % Editor.num_elements + 1
567		-- special= skip element 1 (player)
568		if Editor.current_element_index == 1 then Editor.current_element_index = Editor.num_elements end
569		-- special = skip vertical fences
570		if Editor.current_element_index == Entities.entitylist.barrier_vert or
571			Editor.current_element_index == Entities.entitylist.fence_vert then
572				Editor.current_element_index = Editor.current_element_index - 1
573		end
574		Editor.current_element = Entities.new_element( Editor.current_element_index )
575	end
576	if Editor.mode == 5 and button == 'wd' then
577		Editor.current_element_index = Editor.current_element_index % Editor.num_elements + 1
578		-- special = skip vertical fences
579		if Editor.current_element_index == Entities.entitylist.barrier_vert or
580			Editor.current_element_index == Entities.entitylist.fence_vert then
581				Editor.current_element_index = Editor.current_element_index + 1
582		end
583
584		if Editor.current_element_index > Editor.num_elements then Editor.current_element_index = 1 end
585		if Editor.current_element_index == 1 then Editor.current_element_index = 2 end
586		Editor.current_element = Entities.new_element( Editor.current_element_index )
587	end
588
589	if Editor.mode == 5 and button == "l" then
590	-- special cases: barrier and fence
591		if Editor.current_element_index >= Entities.entitylist.barrier_horiz
592		and Editor.current_element_index <= Entities.entitylist.fence_vert then
593			Editor.dragging = true
594			Editor.dragging_from = {x,y}
595		else
596			Editor.add_element({x,y})
597		end
598
599	end
600
601	if Editor.mode==2 or Editor.mode==3 then
602		if button == "l" then
603			if y>Editor.listingbox[2] and y<Editor.listingbox[2]+(Editor.listinglength+2)*30+25 then
604				local index = math.floor((y-Editor.listingbox[2])/30)
605
606				if index>0 then Editor.fileerror_timer = 0 end
607				-- up
608				if index==1 and Editor.listingoffset>0 then
609					Editor.listingoffset = Editor.listingoffset-1
610				end
611
612				-- down
613				if index==(Editor.listinglength+2) and Editor.listingoffset+Editor.listinglength < table.getn(Editor.listingtable) then
614					Editor.listingoffset = Editor.listingoffset+1
615				end
616
617				-- select file
618				if index>=2 and index<=Editor.listinglength+1 then
619					local newindex = index - 1 + Editor.listingoffset
620					if newindex<=table.getn(Editor.listingtable) then
621						local candidatefilename = Editor.listingtable[newindex]
622						-- double click
623						if Editor.currentfilename==candidatefilename then
624							-- load level
625							if Editor.mode == 3 then
626								Editor.trytoloadcurrent()
627							end
628							if Editor.mode == 2 then
629								Editor.trytosavecurrent()
630							end
631						else
632						-- single click
633							Editor.currentfilename = candidatefilename
634						end
635					end
636				end
637
638				-- confirm
639				if index==0 and Editor.fileerror_timer <= 0 and string.len(Editor.currentfilename)>0 then
640					if Editor.mode == 3 then
641						Editor.trytoloadcurrent()
642					else
643						Editor.trytosavecurrent()
644					end
645				end
646			end
647		elseif button == "r" then
648			-- esborrar
649			if y>Editor.listingbox[2] and y<Editor.listingbox[2]+(Editor.listinglength+2)*30+25 then
650				local index = math.floor((y-Editor.listingbox[2])/30)
651
652				if index>0 then Editor.fileerror_timer = 0 end
653
654				-- select file
655				if index>=2 and index<=Editor.listinglength+1 then
656					local newindex = index - 1 + Editor.listingoffset
657					if newindex<=table.getn(Editor.listingtable) then
658						local candidatefilename = Editor.listingtable[newindex]
659						-- double click
660						if Editor.deletefilename==candidatefilename then
661							if Editor.mode == 2 then
662								Editor.deletefile(Editor.deletefilename)
663							end
664						else
665						-- single click
666							Editor.deletefilename = candidatefilename
667						end
668					end
669				end
670
671
672			end
673		elseif button == "wu" and Editor.listingoffset>0 then
674		-- scroll up
675			Editor.listingoffset = Editor.listingoffset-1
676		elseif button == l"wd" and Editor.listingoffset+Editor.listinglength < table.getn(Editor.listingtable)then
677		-- scroll down
678			Editor.listingoffset = Editor.listingoffset+1
679		end
680	end
681
682	if Editor.mode==7 then
683		if x>40 and x<300 and y>75 and y<125 then Level.enemiescanshoot = not Level.enemiescanshoot end
684		if x>40 and x<340 and y>125 and y<175 then Level.ninjamode = not Level.ninjamode end
685		if x>40 and x<250 and y>175 and y<225 then Level.autoturns = not Level.autoturns end
686		if x>40 and x<262 and y>225 and y<275 then Level.onebullet = not Level.onebullet end
687	end
688
689	if Editor.mode == 6 then
690		Game.mousepressed(x, y, button)
691	end
692end
693
694function Editor.add_element(point,len)
695	local x,y = point[1],point[2]
696	-- check collisions!
697	local valid = true
698	if Editor.current_element_index < 6 then -- enemy
699		local enemybox = { x-9, y-11, x+9, y+11 }
700		for i,building in ipairs(Level.buildings) do
701			if mymath.check_boxinbuilding( enemybox, building ) then
702				valid = false
703				break
704			end
705		end
706		-- collision with player
707
708		if valid then
709			local plx,ply = Player.starting_pos[1],Player.starting_pos[2]
710			if Editor.current_element_index ~=Entities.entitylist.player and
711				mymath.check_boxes( enemybox, { plx-9, ply-11, plx+9, ply+11 } ) then
712				valid = false
713			end
714		end
715		-- collision of player
716		if valid and Editor.current_element_index == Entities.entitylist.player then
717			local plx,ply = point[1],point[2]
718			for i,enemy in ipairs(Level.enemies) do
719				local cx,cy = enemy.starting_pos[1],enemy.starting_pos[2]
720				local dx,dy = enemy.spritesize[1]/2, enemy.spritesize[2]/2
721				enemybox = { cx-dx,cy-dy,cx+dx,cy+dy }
722				if mymath.check_boxes( enemybox, { plx-9, ply-11, plx+9, ply+11 } ) then
723					valid = false
724					break
725				end
726			end
727		end
728
729	else -- building
730		local building = Entities.new_element( Editor.current_element_index, {x,y}, len )
731		for i,enemy in ipairs(Level.enemies) do
732			local cx,cy = enemy.starting_pos[1],enemy.starting_pos[2]
733			local dx,dy = enemy.spritesize[1]/2, enemy.spritesize[2]/2
734			local enemybox = { cx-dx,cy-dy,cx+dx,cy+dy }
735			if mymath.check_boxinbuilding( enemybox, building ) then
736				valid = false
737				break
738			end
739		end
740		-- collision with player
741		local plx,ply = Player.starting_pos[1],Player.starting_pos[2]
742		if valid and mymath.check_boxinbuilding( { plx-9, ply-11, plx+9, ply+11 }, building ) then
743			valid = false
744		end
745	end
746	if valid then
747		Entities.add_element( Editor.current_element_index, {x,y}, len )
748
749		-- get index in table from class
750		local itemindex = 1
751		if Editor.current_element_index == 1 then
752			itemindex = 1
753		elseif Editor.current_element_index >= Entities.entitylist.blue_bandit and
754			Editor.current_element_index <= Entities.entitylist.yellow_bandit then
755			itemindex = table.getn(Level.enemies)
756		else
757			itemindex = table.getn(Level.buildings)
758		end
759
760		if Editor.mode==5 then
761			Editor.register_add(itemindex, Editor.current_element_index, x, y, len)
762		elseif Editor.mode == 4 and Editor.dragging then
763			Editor.register_add(itemindex, Editor.current_element_index, x, y, len, 1)
764		end
765	end
766	return valid
767end
768
769
770function Editor.mousereleased(x, y, button)
771	if Editor.mode == 4 and button == "l" and Editor.dragging then
772		local len = 1
773		if Editor.current_element.len then len = Editor.current_element.len[2] end
774		if not Editor.add_element( {x+Editor.mouseposdiff[1],y+Editor.mouseposdiff[2]}, len )
775		then Editor.add_element( Editor.current_element_original_pos, len ) end
776	end
777
778	if Editor.mode ==5 and Editor.dragging and Editor.current_element_index >= Entities.entitylist.barrier_horiz
779	and Editor.current_element_index <= Entities.entitylist.fence_vert then
780		Editor.add_element(Editor.itemcenter, Editor.itemlength)
781	end
782
783	Editor.dragging = false
784	if Editor.mode == 6 then
785		Game.mousereleased(x, y, button)
786	end
787end
788
789function Editor.findfor_substract(x,y)
790
791	for i,building in ipairs(Level.buildings) do
792		if mymath.check_pointinbox( {x,y},
793			{building.pos[1]-building.sprite:getWidth()/2,building.pos[2]-building.sprite:getHeight()/2,
794			 building.pos[1]+building.sprite:getWidth()/2,building.pos[2]+building.sprite:getHeight()/2} )
795		then
796			if building.id >= Entities.entitylist.barrier_horiz and
797				building.id<= Entities.entitylist.fence_vert then
798				return {i,building.id, building.pos[1], building.pos[2], building.len[2]}
799			else
800				return {i,building.id, building.pos[1], building.pos[2], 1}
801			end
802		end
803	end
804
805	-- find if it's a fence
806	for i,building in ipairs(Level.buildings) do
807		if mymath.check_pointinbuilding( {x,y}, building )
808		then
809			if building.id >= Entities.entitylist.barrier_horiz and
810				building.id<= Entities.entitylist.fence_vert then
811				return {i,building.id, building.pos[1], building.pos[2], building.len[2]}
812			else
813				return {i,building.id, building.pos[1], building.pos[2], 1}
814			end
815		end
816	end
817
818	-- find if it's an enemy
819	for i,enemy in ipairs(Level.enemies) do
820		if mymath.check_pointinbox( {x,y},
821			{enemy.pos[1]-enemy.spritesize[1]/2,enemy.pos[2]-enemy.spritesize[2]/2,
822			 enemy.pos[1]+enemy.spritesize[1]/2,enemy.pos[2]+enemy.spritesize[2]/2} )
823		then
824			return {i,enemy.id, enemy.starting_pos[1], enemy.starting_pos[2], 1}
825		end
826	end
827
828
829	-- find if it's the player
830	if mymath.check_pointinbox( {x,y},
831		{Player.pos[1]-Player.spritesize[1]/2,Player.pos[2]-Player.spritesize[2]/2,
832		 Player.pos[1]+Player.spritesize[1]/2,Player.pos[2]+Player.spritesize[2]/2} )
833	then
834		return {i,1, Player.starting_pos[1], Player.starting_pos[2], 1}
835	end
836
837end
838
839function Editor.substract(x,y)
840	-- returns a reference to the first entity (building or enemy or player) that corresponds to (x,y)
841	-- the thing is that in moving mode, when you click on an entity, it floats on top of the list, becoming
842	-- the last.  So if you click repeatedly in the same point where several buildings are overlapping, this
843	-- should always bring the last one on top.
844
845	-- find if it's a building (using the whole sprite, not the regular collision)
846	for i,building in ipairs(Level.buildings) do
847		if mymath.check_pointinbox( {x,y},
848			{building.pos[1]-building.sprite:getWidth()/2,building.pos[2]-building.sprite:getHeight()/2,
849			 building.pos[1]+building.sprite:getWidth()/2,building.pos[2]+building.sprite:getHeight()/2} )
850		then
851			table.remove(Level.buildings,i)
852			return building
853		end
854	end
855
856	-- find if it's a fence
857	for i,building in ipairs(Level.buildings) do
858		if mymath.check_pointinbuilding( {x,y}, building )
859		then
860			table.remove(Level.buildings,i)
861			return building
862		end
863	end
864
865	-- find if it's an enemy
866	for i,enemy in ipairs(Level.enemies) do
867		if mymath.check_pointinbox( {x,y},
868			{enemy.pos[1]-enemy.spritesize[1]/2,enemy.pos[2]-enemy.spritesize[2]/2,
869			 enemy.pos[1]+enemy.spritesize[1]/2,enemy.pos[2]+enemy.spritesize[2]/2} )
870		then
871			table.remove(Level.enemies,i)
872			return enemy
873		end
874	end
875
876
877	-- find if it's the player
878	if mymath.check_pointinbox( {x,y},
879		{Player.pos[1]-Player.spritesize[1]/2,Player.pos[2]-Player.spritesize[2]/2,
880		 Player.pos[1]+Player.spritesize[1]/2,Player.pos[2]+Player.spritesize[2]/2} )
881	then
882		return Player
883	end
884
885end
886
887function Editor.undo()
888	if Editor.undo_point == Editor.undo_begin then
889		return
890	end
891
892	Editor.rewind_undo_pointer()
893
894	local move = (Editor.undo_list[Editor.undo_point][2]==1)
895
896	-- do the oposite
897	if Editor.undo_list[Editor.undo_point][1] == 1 then
898		-- add, so remove
899		local d = Editor.undo_list[Editor.undo_point]
900		Editor.apply_remove( {d[3], d[4], d[5], d[6], d[7]} )
901	else
902		-- remove, so add
903		local d = Editor.undo_list[Editor.undo_point]
904		Editor.apply_add( {d[3], d[4], d[5], d[6], d[7]} )
905
906	end
907
908
909	if move then
910		Editor.rewind_undo_pointer()
911
912		if Editor.undo_list[Editor.undo_point][1] == 1 then
913		-- add, so remove
914			local d = Editor.undo_list[Editor.undo_point]
915			Editor.apply_remove( {d[3], d[4], d[5], d[6], d[7]} )
916		else
917			-- remove, so add
918			local d = Editor.undo_list[Editor.undo_point]
919			Editor.apply_add( {d[3], d[4], d[5], d[6], d[7]} )
920		end
921
922	end
923
924end
925
926function Editor.redo()
927
928
929
930	if Editor.undo_point == Editor.undo_end then
931		return
932	end
933
934
935	local move = (Editor.undo_list[Editor.undo_point][2]==1)
936
937	-- do the oposite
938	if Editor.undo_list[Editor.undo_point][1] == 1 then
939		-- add
940		local d = Editor.undo_list[Editor.undo_point]
941		Editor.apply_add( {d[3], d[4], d[5], d[6], d[7]} )
942	else
943		-- remove
944		local d = Editor.undo_list[Editor.undo_point]
945		Editor.apply_remove( {d[3], d[4], d[5], d[6], d[7]} )
946	end
947
948	Editor.advance_undo_pointer()
949
950
951	if move then
952
953
954		-- do the oposite
955		if Editor.undo_list[Editor.undo_point][1] == 1 then
956			-- add
957			local d = Editor.undo_list[Editor.undo_point]
958			Editor.apply_add( {d[3], d[4], d[5], d[6], d[7]} )
959		else
960			-- remove
961			local d = Editor.undo_list[Editor.undo_point]
962			Editor.apply_remove( {d[3], d[4], d[5], d[6], d[7]} )
963		end
964
965		Editor.advance_undo_pointer()
966
967	end
968
969end
970
971function Editor.apply_add( datalist )
972	local itemindex, classindex, x, y, len = datalist[1],datalist[2],datalist[3], datalist[4], datalist[5]
973
974	if classindex == 1 then
975		Entities.add_element( 1,{x,y},1 )
976	elseif classindex >= Entities.entitylist.blue_bandit and classindex <= Entities.entitylist.yellow_bandit then
977		table.insert( Level.enemies, itemindex, Entities.new_element( classindex, {x,y} ) )
978	else
979		table.insert( Level.buildings, itemindex, Entities.new_element( classindex, {x,y} , len ) )
980	end
981
982end
983
984function Editor.apply_remove( datalist )
985	local itemindex, classindex, x, y, len = datalist[1],datalist[2],datalist[3], datalist[4], datalist[5]
986	if classindex==1 then
987		-- player .. ignore
988	elseif classindex >= Entities.entitylist.blue_bandit and classindex <= Entities.entitylist.yellow_bandit then
989		table.remove(Level.enemies, itemindex )
990	else -- building
991		table.remove(Level.buildings, itemindex )
992	end
993end
994
995-- undo/redo: three types of actions, add, remove, move (que es remove+add)
996function Editor.register_add( itemindex, classindex, x, y, len, move )
997	if move==nil then move = 0 end
998
999	Editor.undo_list[Editor.undo_point] = {
1000		1, -- add
1001		move,
1002		itemindex,
1003		classindex,
1004		x,
1005		y,
1006		len }
1007	Editor.push_undo_pointer()
1008end
1009
1010function Editor.register_remove( itemindex, classindex, x, y, len, move )
1011	if move==nil then move = 0 end
1012
1013	Editor.undo_list[Editor.undo_point] = {
1014		2, -- remove
1015		move, -- no move
1016		itemindex,
1017		classindex,
1018		x,
1019		y,
1020		len }
1021	Editor.push_undo_pointer()
1022end
1023
1024function Editor.push_undo_pointer()
1025	Editor.undo_point = Editor.undo_point + 1
1026	if Editor.undo_point > Editor.undo_max then
1027		Editor.undo_point = 1
1028	end
1029	if Editor.undo_begin == Editor.undo_point then
1030		Editor.undo_begin = Editor.undo_begin + 1
1031		if Editor.undo_begin > Editor.undo_max then
1032			Editor.undo_begin = 1
1033		end
1034	end
1035	Editor.undo_end = Editor.undo_point
1036end
1037
1038function Editor.advance_undo_pointer()
1039	if Editor.undo_point == Editor.undo_end then
1040		return
1041	end
1042
1043	Editor.undo_point = Editor.undo_point + 1
1044	if Editor.undo_point == Editor.undo_max then
1045		Editor.undo_point = 1
1046	end
1047end
1048
1049function Editor.rewind_undo_pointer()
1050	if Editor.undo_point == Editor.undo_begin then
1051		return
1052	end
1053
1054	Editor.undo_point = Editor.undo_point - 1
1055	if Editor.undo_point == 0 then
1056		Editor.undo_point = Editor.undo_max
1057	end
1058end
1059
1060function Editor.reset_undo()
1061-- undo
1062	Editor.undo_list = {}
1063	Editor.undo_point = 1
1064	Editor.undo_max = 400 -- 400 undo actions
1065	Editor.undo_begin = 1
1066	Editor.undo_end = 1
1067end
1068