1 #include "editor.h"
2 #include "export.h"
3 #include "gfx/gfx.h"
4 #include "gfx/font.h"
5 #include "gui/toolutil.h"
6 #include <stdio.h>
7 #include <math.h>
8 #include <stdlib.h>
9 #include <strings.h>
10 
11 #define LIBCONFIG_STATIC
12 
13 #include <libconfig.h>
14 
15 #define MAGICK_LAYER MAX_LAYERS
16 #define BRUSH_LAYER MAX_LAYERS+1
17 #define CLIPBOARDSIZE 32
18 
19 enum
20 {
21 	EM_LEVEL,
22 	EM_EVENTS
23 };
24 
25 Level level;
26 int screen_width = 640, screen_height = 480, screen_scale;
27 int pf_width = 640, pf_height = 480;
28 int saved_layer = 0;
29 int current_layer = 0;
30 int selected_tile = 0;
31 int selected_param = 0;
32 int scroll_x = 0, scroll_y = 0;
33 int drag_x = -1, drag_y = -1, drag_event = -1, selected_event = -1;
34 int edit_mode = EM_LEVEL;
35 int ev_drag_start_x, ev_drag_start_y, drag_start_x, drag_start_y;
36 Uint32 bg_color = 0;
37 GfxDomain *domain = NULL;
38 Font font;
39 GfxSurface *gfx = NULL;
40 
41 typedef enum { EVPAR_INT, EVPAR_ENUM } EvParType;
42 
43 typedef struct
44 {
45 	const char *name;
46 	EvParType type;
47 	const char **enums;
48 	int int_min, int_max;
49 	int default_val;
50 } EvParDesc;
51 
52 typedef struct
53 {
54 	const char *name;
55 	Uint32 color;
56 	EvParDesc param[EV_PARAMS];
57 } EvDesc;
58 
59 static EvDesc *ev_desc = NULL;
60 static int n_ev_desc = 0;
61 
62 static const char *tileset = "";
63 TileDescriptor *descriptor;
64 config_t cfg;
65 
load_dialog()66 void load_dialog()
67 {
68 	FILE *f = open_dialog("rb", "Load level", "lev", domain, gfx, &font, &font, NULL);
69 	if (f)
70 	{
71 
72 		level_load(&level, f);
73 		fclose(f);
74 
75 		for (int i = 0 ; i < MAX_LAYERS+2 ; ++i)
76 		{
77 			level.layer[i].tiles = descriptor;
78 		}
79 	}
80 }
81 
82 
load_level(const char * path)83 void load_level(const char *path)
84 {
85 	FILE *f = fopen(path, "rb");
86 	if (f)
87 	{
88 
89 		level_load(&level, f);
90 		fclose(f);
91 
92 		for (int i = 0 ; i < MAX_LAYERS+2 ; ++i)
93 		{
94 			level.layer[i].tiles = descriptor;
95 		}
96 	}
97 }
98 
99 
load_defs(const char * fn)100 void load_defs(const char *fn)
101 {
102 	FILE *f = fn ? fopen(fn, "r") : open_dialog("r", "Load project defs", "cfg", domain, gfx, &font, &font, NULL);
103 	if (f)
104 	{
105 		int r = config_read(&cfg, f);
106 
107 		fclose(f);
108 
109 		if (r)
110 		{
111 			if (!config_lookup_string(&cfg, "tileset", &tileset))
112 				warning("No tileset defined");
113 			if (!config_lookup_int(&cfg, "bg_color", (Sint32*)&bg_color))
114 				warning("No bg_color defined");
115 			config_lookup_int(&cfg, "screen.width", &screen_width);
116 			config_lookup_int(&cfg, "screen.height", &screen_height);
117 			config_lookup_int(&cfg, "screen.scale", &screen_scale);
118 			config_lookup_int(&cfg, "playfield.width", &pf_width);
119 			config_lookup_int(&cfg, "playfield.height", &pf_height);
120 
121 			config_setting_t *e = config_lookup(&cfg, "events");
122 			if (e)
123 			{
124 				n_ev_desc = config_setting_length(e);
125 				ev_desc = calloc(n_ev_desc, sizeof(ev_desc[0]));
126 
127 				for (int i = 0 ; i < n_ev_desc ; ++i)
128 				{
129 					config_setting_t *elem = config_setting_get_elem(e, i);
130 					config_setting_lookup_string(elem, "name", &ev_desc[i].name);
131 					config_setting_t *params = config_setting_get_member(elem, "params");
132 
133 					EvDesc *ed = &ev_desc[i];
134 
135 					ed->color = 0x00ff00;
136 
137 					config_setting_lookup_int(elem, "color", (Sint32*)&ev_desc[i].color);
138 
139 					if (params && config_setting_type(params) == CONFIG_TYPE_LIST)
140 					{
141 						int n_p = config_setting_length(params);
142 
143 						for (int i = 0 ; i < n_p && i < EV_PARAMS - 3 ; ++i)
144 						{
145 							EvParDesc *p = &ed->param[i + 1];
146 
147 							config_setting_t *elem = config_setting_get_elem(params, i);
148 							config_setting_lookup_string(elem, "name", &p->name);
149 							config_setting_t *enums = config_setting_get_member(elem, "enum");
150 
151 							if (enums && config_setting_type(enums) == CONFIG_TYPE_ARRAY)
152 							{
153 								p->type = EVPAR_ENUM;
154 								p->int_min = 0;
155 								p->int_max = config_setting_length(enums);
156 								p->enums = calloc(p->int_max, sizeof(p->enums[0]));
157 								for (int e = 0 ; e < p->int_max ; ++e)
158 								{
159 									p->enums[e] = config_setting_get_string_elem(enums, e);
160 								}
161 
162 								p->int_max--;
163 							}
164 							else
165 							{
166 								p->type = EVPAR_INT;
167 								config_setting_t *range = config_setting_get_member(elem, "range");
168 								if (range && config_setting_type(range) == CONFIG_TYPE_ARRAY)
169 								{
170 									p->int_min = config_setting_get_int_elem(range, 0);
171 									p->int_max = config_setting_get_int_elem(range, 1);
172 								}
173 								else
174 								{
175 									p->int_min = 0;
176 									p->int_max = 65535;
177 								}
178 							}
179 						}
180 					}
181 				}
182 			}
183 			else
184 			{
185 				warning("No events defined");
186 			}
187 		}
188 		else
189 		{
190 			warning("Could not read config: (%d) %s", config_error_line(&cfg), config_error_text(&cfg));
191 		}
192 	}
193 	else
194 	{
195 		warning("cfgfile not found");
196 	}
197 }
198 
199 
save_dialog()200 int save_dialog()
201 {
202 	FILE *f = open_dialog("wb", "Save level", "lev", domain, gfx, &font, &font, NULL);
203 	if (f)
204 	{
205 		level.n_layers = MAX_LAYERS;
206 
207 		level_save(&level, f);
208 		fclose(f);
209 
210 		return 1;
211 	}
212 	else
213 	{
214 		return 0;
215 	}
216 }
217 
draw_rect(GfxDomain * s,int x1,int y1,int x2,int y2,Uint32 color)218 void draw_rect(GfxDomain *s, int x1, int y1, int x2, int y2, Uint32 color)
219 {
220 
221 	if (x1 > x2) { int temp = x2; x2 = x1; x1 = temp; }
222 	if (y1 > y2) { int temp = y2; y2 = y1; y1 = temp; }
223 
224 	{
225 		SDL_Rect rect = {x1, y1, x2-x1, 1};
226 		gfx_rect(s, &rect, color);
227 	}
228 
229 	{
230 		SDL_Rect rect = {x1, y2, x2-x1, 1};
231 		gfx_rect(s, &rect, color);
232 	}
233 
234 	{
235 		SDL_Rect rect = {x1, y1, 1, y2-y1};
236 		gfx_rect(s, &rect, color);
237 	}
238 
239 	{
240 		SDL_Rect rect = {x2, y1, 1, y2-y1};
241 		gfx_rect(s, &rect, color);
242 	}
243 }
244 
245 
vector(GfxDomain * screen,int x0,int y0,int x1,int y1,Uint32 color)246 void vector(GfxDomain *screen, int x0, int y0, int x1, int y1, Uint32 color)
247 {
248 	gfx_line(screen, x0, y0, x1, y1, color);
249 
250 	int dx = (x0 - x1);
251 	int dy = (y0 - y1);
252 	int d = sqrt(dx*dx+dy*dy);
253 	if (d == 0) return;
254 	dx = dx*16/d;
255 	dy = dy*16/d;
256 
257 	gfx_line(screen, x1, y1, x1 + dy + dx, y1 - dx + dy, color);
258 	gfx_line(screen, x1, y1, x1 - dy + dx, y1 + dx + dy, color);
259 }
260 
261 
draw(GfxDomain * screen,int mouse_x,int mouse_y,int draw_all)262 void draw(GfxDomain *screen, int mouse_x, int mouse_y, int draw_all)
263 {
264 	if (draw_all)
265 	{
266 		for (int i = 0 ; i < MAX_LAYERS ; ++i)
267 		{
268 			if (level.layer[i].flags & BG_PARALLAX)
269 				bg_draw(screen, NULL, &level.layer[i], scroll_x / my_max(1, level.layer[i].prx_mlt_x), scroll_y / my_max(1, level.layer[i].prx_mlt_y));
270 			else
271 				bg_draw(screen, NULL, &level.layer[i], scroll_x, scroll_y);
272 		}
273 	}
274 	else
275 	{
276 		int _scroll_x = scroll_x;
277 		int _scroll_y = scroll_y;
278 		int _drag_x = drag_x;
279 		int _drag_y = drag_y;
280 
281 		if (current_layer >= MAGICK_LAYER)
282 		{
283 			_scroll_x = my_max(0, my_min(scroll_x, level.layer[current_layer].w * CELLSIZE - screen_width));
284 			_scroll_y = my_max(0, my_min(scroll_y, level.layer[current_layer].h * CELLSIZE - screen_height));
285 		}
286 
287 		mouse_x = (mouse_x + ((_scroll_x) & (CELLSIZE-1))) / CELLSIZE;
288 		mouse_y = (mouse_y + ((_scroll_y) & (CELLSIZE-1))) / CELLSIZE;
289 		_drag_x = (_drag_x + ((_scroll_x) & (CELLSIZE-1))) / CELLSIZE;
290 		_drag_y = (_drag_y + ((_scroll_y) & (CELLSIZE-1))) / CELLSIZE;
291 
292 		bg_draw(screen, NULL, &level.layer[current_layer], _scroll_x, _scroll_y);
293 		draw_rect(screen, -_scroll_x-1, -_scroll_y-1, -_scroll_x + level.layer[current_layer].w*CELLSIZE, -_scroll_y + level.layer[current_layer].h*CELLSIZE, 0xffffff);
294 
295 		if (edit_mode == EM_LEVEL)
296 		{
297 			if (drag_x != -1)
298 			{
299 				draw_rect(screen, (_drag_x)*CELLSIZE - ((_scroll_x) & (CELLSIZE-1)), (_drag_y)*CELLSIZE - ((_scroll_y) & (CELLSIZE-1)),
300 					(mouse_x+1)*CELLSIZE - ((_scroll_x) & (CELLSIZE-1)), (mouse_y+1)*CELLSIZE - ((_scroll_y) & (CELLSIZE-1)), 0xffffff);
301 			}
302 			else
303 			{
304 				draw_rect(screen, (mouse_x)*CELLSIZE - ((_scroll_x) & (CELLSIZE-1)), (mouse_y)*CELLSIZE - ((_scroll_y) & (CELLSIZE-1)),
305 					(mouse_x+level.layer[BRUSH_LAYER].w)*CELLSIZE - ((_scroll_x) & (CELLSIZE-1)), (mouse_y+level.layer[BRUSH_LAYER].h)*CELLSIZE - ((_scroll_y) & (CELLSIZE-1)), 0xffffff);
306 			}
307 		}
308 		else
309 		{
310 			for (int i = 0 ; i < level.n_events ; ++i)
311 			{
312 				for (int s = 0 ; s < 4 ; s+=2)
313 				draw_rect(screen, s + level.event[i].x * CELLSIZE - _scroll_x, s + level.event[i].y * CELLSIZE - _scroll_y,
314 				  level.event[i].w * CELLSIZE + level.event[i].x * CELLSIZE - _scroll_x - s, level.event[i].h * CELLSIZE + level.event[i].y * CELLSIZE - _scroll_y - s, i == selected_event ? 0xffffff : ev_desc[level.event[i].param[0]].color);
315 
316 				if (level.event[i].param[EV_NEXT] != -1 && level.event[i].param[EV_NEXT] < level.n_events)
317 				{
318 					vector(screen, level.event[i].x * CELLSIZE + level.event[i].w*CELLSIZE/2 - _scroll_x, level.event[i].y * CELLSIZE + level.event[i].h*CELLSIZE/2 - _scroll_y,
319 						level.event[level.event[i].param[EV_NEXT]].x * CELLSIZE + level.event[level.event[i].param[EV_NEXT]].w*CELLSIZE/2 - _scroll_x, level.event[level.event[i].param[EV_NEXT]].y * CELLSIZE + level.event[level.event[i].param[EV_NEXT]].h*CELLSIZE/2 - _scroll_y, 0xffffff);
320 				}
321 
322 				if (level.event[i].param[EV_TRGPARENT] != -1 && level.event[i].param[EV_TRGPARENT] < level.n_events)
323 				{
324 					vector(screen, 	level.event[level.event[i].param[EV_TRGPARENT]].x * CELLSIZE - _scroll_x, level.event[level.event[i].param[EV_TRGPARENT]].y * CELLSIZE - _scroll_y,
325 						level.event[i].x * CELLSIZE - _scroll_x, level.event[i].y * CELLSIZE - _scroll_y, 0xff0000);
326 				}
327 			}
328 		}
329 	}
330 
331 	if (current_layer < MAGICK_LAYER)
332 		draw_rect(screen, screen->screen_w / 2 - pf_width / 2, screen->screen_h / 2 - pf_height / 2, screen->screen_w / 2 + pf_width / 2, screen->screen_h / 2 + pf_height / 2, 0xa0a040);
333 }
334 
335 
set_flags(int flip)336 void set_flags(int flip)
337 {
338 	if (current_layer < MAGICK_LAYER)
339 		level.layer[current_layer].flags ^= flip;
340 }
341 
342 
resize_layer(int w,int h)343 void resize_layer(int w, int h)
344 {
345 	if (current_layer == MAGICK_LAYER) return;
346 
347 	Background *layer = &level.layer[current_layer];
348 
349 	if (w <= 0 || h <= 0)
350 	{
351 		layer->w = my_max(0, layer->w);
352 		layer->h = my_max(0, layer->h);
353 		if (layer->data) free (layer->data);
354 		layer->data = NULL;
355 	}
356 
357 	BgCell * temp = layer->data;
358 
359 	layer->data = malloc(sizeof(BgCell)*w*h);
360 	memset(layer->data, 0, sizeof(BgCell)*w*h);
361 
362 	if (temp)
363 	{
364 		for (int y = 0 ; y < h && y < layer->h ; ++y)
365 		{
366 			for (int x = 0 ; x < w && x < layer->w ; ++x)
367 			{
368 				memcpy(&layer->data[w*y+x], &temp[x+y*layer->w], sizeof(layer->data[0]));
369 			}
370 		}
371 		free(temp);
372 	}
373 
374 	layer->w = w;
375 	layer->h = h;
376 
377 
378 
379 }
380 
get_tile(int x,int y)381 void get_tile(int x, int y)
382 {
383 	if (current_layer != MAGICK_LAYER)
384 	{
385 		x += scroll_x;
386 		y += scroll_y;
387 	}
388 
389 	x /= CELLSIZE;
390 	y /= CELLSIZE;
391 
392 	if (saved_layer == BRUSH_LAYER || current_layer == BRUSH_LAYER)
393 	{
394 		if (!(x >= level.layer[current_layer].w || x < 0 || y >= level.layer[current_layer].h || y < 0));
395 			selected_tile = level.layer[current_layer].data[x + y*level.layer[current_layer].w].tile;
396 
397 		return;
398 	}
399 
400 	if (level.layer[current_layer].flags & BG_REPEAT_X)
401 		x = (x % level.layer[current_layer].w + level.layer[current_layer].w) % level.layer[current_layer].w;
402 
403 	if (level.layer[current_layer].flags & BG_REPEAT_Y)
404 		y = (y % level.layer[current_layer].h + level.layer[current_layer].h) % level.layer[current_layer].h;
405 
406 	if (!(x >= level.layer[current_layer].w || x < 0 || y >= level.layer[current_layer].h || y < 0))
407 	{
408 		int temp = current_layer;
409 		current_layer = BRUSH_LAYER;
410 		resize_layer(1,1);
411 		current_layer = temp;
412 		selected_tile = level.layer[BRUSH_LAYER].data[0].tile = level.layer[current_layer].data[x+y*level.layer[current_layer].w].tile;
413 	}
414 }
415 
416 
set_tile(int ax,int ay)417 void set_tile(int ax, int ay)
418 {
419 	if (current_layer == MAGICK_LAYER) return;
420 
421 	if (current_layer == BRUSH_LAYER)
422 	{
423 		ax /= CELLSIZE;
424 		ay /= CELLSIZE;
425 
426 		if (!(ax >= level.layer[current_layer].w || ax < 0 || ay >= level.layer[current_layer].h || ay < 0))
427 			level.layer[current_layer].data[ax + ay*level.layer[current_layer].w].tile = selected_tile;
428 
429 		return;
430 	}
431 
432 
433 	ax += scroll_x;
434 	ay += scroll_y;
435 
436 	int fx = ax < 0;
437 	int fy = ay < 0;
438 
439 
440 	ax /= CELLSIZE;
441 	ay /= CELLSIZE;
442 
443 	for (int y = 0 ; y < level.layer[BRUSH_LAYER].h ; ++y)
444 	{
445 		for (int x = 0 ; x < level.layer[BRUSH_LAYER].w ; ++x)
446 		{
447 			int _x = x+ax-fx, _y = y+ay-fy;
448 
449 			if (level.layer[current_layer].flags & BG_REPEAT_X)
450 				_x = (_x % level.layer[current_layer].w + level.layer[current_layer].w) % level.layer[current_layer].w;
451 
452 			if (level.layer[current_layer].flags & BG_REPEAT_Y)
453 				_y = (_y % level.layer[current_layer].h + level.layer[current_layer].h) % level.layer[current_layer].h;
454 
455 			if (!(_x >= level.layer[current_layer].w || _x < 0 || _y >= level.layer[current_layer].h || _y < 0))
456 				level.layer[current_layer].data[_x + _y*level.layer[current_layer].w].tile = level.layer[BRUSH_LAYER].data[x+y*level.layer[BRUSH_LAYER].w].tile;
457 		}
458 	}
459 }
460 
461 
has_pixels(TileDescriptor * desc)462 int has_pixels(TileDescriptor *desc)
463 {
464 	my_lock(desc->surface->surface);
465 
466 	int result = 0;
467 
468 #if SDL_VERSION_ATLEAST(1,3,0)
469 	Uint32 key;
470 	SDL_GetColorKey(desc->surface->surface, &key);
471 #else
472 	const Uint32 key = desc->surface->surface->format->colorkey;
473 #endif
474 
475 	for (int y = 0 ; y < desc->rect.h ; ++y)
476 	{
477 		Uint8 *p = (Uint8 *)desc->surface->surface->pixels + ((int)desc->rect.y + y) * desc->surface->surface->pitch + (int)desc->rect.x * desc->surface->surface->format->BytesPerPixel;
478 
479 		for (int x = 0 ; x < desc->rect.w ; ++x)
480 		{
481 			//printf("%08x", *(Uint32*)p);
482 			if ((*((Uint32*)p)&0xffffff) != key)
483 			{
484 				++result;
485 			}
486 
487 			p+=desc->surface->surface->format->BytesPerPixel;
488 		}
489 	}
490 
491 	my_unlock(desc->surface->surface);
492 
493 	return result;
494 }
495 
496 
init_magic_layer(int w,int h,TileDescriptor * desc,int tiles)497 void init_magic_layer(int w, int h, TileDescriptor *desc, int tiles)
498 {
499 	level.layer[BRUSH_LAYER].w = 1;
500 	level.layer[BRUSH_LAYER].h = 1;
501 	level.layer[BRUSH_LAYER].data = malloc(level.layer[BRUSH_LAYER].w*level.layer[BRUSH_LAYER].h*sizeof(level.layer[BRUSH_LAYER].data[0]));
502 	memset(level.layer[BRUSH_LAYER].data, 0, level.layer[BRUSH_LAYER].w*level.layer[BRUSH_LAYER].h*sizeof(level.layer[BRUSH_LAYER].data[0]));
503 	level.layer[BRUSH_LAYER].data[0].tile = selected_tile;
504 
505 	level.layer[MAGICK_LAYER].w = w / CELLSIZE;
506 	level.layer[MAGICK_LAYER].h = h / CELLSIZE;
507 	level.layer[MAGICK_LAYER].data = malloc(level.layer[MAGICK_LAYER].w*level.layer[MAGICK_LAYER].h*sizeof(level.layer[MAGICK_LAYER].data[0]));
508 	memset(level.layer[MAGICK_LAYER].data, 0, level.layer[MAGICK_LAYER].w*level.layer[MAGICK_LAYER].h*sizeof(level.layer[MAGICK_LAYER].data[0]));
509 
510 	for (int i = 0 ; i < tiles ; ++i)
511 	{
512 		int x = desc[i].rect.x / CELLSIZE;
513 		int y = desc[i].rect.y / CELLSIZE;
514 		level.layer[MAGICK_LAYER].data[x+y*level.layer[MAGICK_LAYER].w].tile = has_pixels(&desc[i]) ? i+1 : 0;
515 	}
516 }
517 
clear_layer()518 void clear_layer()
519 {
520 	if (current_layer >= MAGICK_LAYER) return;
521 	memset(level.layer[current_layer].data, 0, level.layer[current_layer].w*level.layer[current_layer].h*sizeof(level.layer[current_layer].data[0]));
522 }
523 
524 
get_brush(int x1,int y1,int x2,int y2)525 void get_brush(int x1, int y1, int x2, int y2)
526 {
527 	if (current_layer == BRUSH_LAYER) return;
528 
529 	if (current_layer < MAGICK_LAYER)
530 	{
531 		x1 += scroll_x;
532 		y1 += scroll_y;
533 		x2 += scroll_x;
534 		y2 += scroll_y;
535 	}
536 
537 	x1 /= CELLSIZE;
538 	y1 /= CELLSIZE;
539 	x2 /= CELLSIZE;
540 	y2 /= CELLSIZE;
541 
542 	if (x1 > x2) { int temp = x2; x2 = x1; x1 = temp; }
543 	if (y1 > y2) { int temp = y2; y2 = y1; y1 = temp; }
544 
545 	free(level.layer[BRUSH_LAYER].data);
546 	level.layer[BRUSH_LAYER].w = x2 - x1 + 1;
547 	level.layer[BRUSH_LAYER].h = y2 - y1 + 1;
548 	level.layer[BRUSH_LAYER].data = malloc(level.layer[BRUSH_LAYER].w * level.layer[BRUSH_LAYER].h * sizeof(level.layer[BRUSH_LAYER].data[0]));
549 	memset(level.layer[BRUSH_LAYER].data, 0, level.layer[BRUSH_LAYER].w * level.layer[BRUSH_LAYER].h * sizeof(level.layer[BRUSH_LAYER].data[0]));
550 
551 	for (int y = 0 ; y < level.layer[BRUSH_LAYER].h ; ++y)
552 	{
553 		for (int x = 0 ; x < level.layer[BRUSH_LAYER].w ; ++x)
554 		{
555 			int _x = x + x1;
556 			int _y = y + y1;
557 
558 			if (level.layer[current_layer].flags & BG_REPEAT_X)
559 				_x = (_x % level.layer[current_layer].w + level.layer[current_layer].w) % level.layer[current_layer].w;
560 			else if (_x >= level.layer[current_layer].w) break;
561 
562 			if (level.layer[current_layer].flags & BG_REPEAT_Y)
563 				_y = (_y % level.layer[current_layer].h + level.layer[current_layer].h) % level.layer[current_layer].h;
564 			else if (_y >= level.layer[current_layer].h) break;
565 
566 			level.layer[BRUSH_LAYER].data[x+y*level.layer[BRUSH_LAYER].w].tile =
567 				level.layer[current_layer].data[_x+_y*level.layer[current_layer].w].tile;
568 		}
569 	}
570 }
571 
swap(void * a,void * b,size_t size)572 void swap(void *a, void *b, size_t size)
573 {
574 	void * ptr = malloc(size);
575 	memcpy(ptr, a, size);
576 	memcpy(a, b, size);
577 	memcpy(b, ptr, size);
578 	free(ptr);
579 }
580 
581 
get_event(int x,int y)582 int get_event(int x, int y)
583 {
584 	x += scroll_x;
585 	y += scroll_y;
586 
587 	if (x < 0) x-=CELLSIZE;
588 	if (y < 0) y-=CELLSIZE;
589 
590 	x /= CELLSIZE;
591 	y /= CELLSIZE;
592 
593 	// check for clicks on border
594 
595 	const int border = 1;
596 
597 	for (int i = 0 ; i < level.n_events ; ++i)
598 	{
599 		if (((int)level.event[i].x <= x && (int)level.event[i].y <= y && (int)level.event[i].x+(int)level.event[i].w > x && (int)level.event[i].y+(int)level.event[i].h > y ) &&
600 			!((int)level.event[i].x + border <= x && (int)level.event[i].y + border <= y && (int)level.event[i].x+(int)level.event[i].w - border > x && (int)level.event[i].y+(int)level.event[i].h - border > y ))
601 			return i;
602 	}
603 
604 	// check for clicks inside the full area
605 
606 	for (int i = 0 ; i < level.n_events ; ++i)
607 	{
608 		if ((int)level.event[i].x <= x && (int)level.event[i].y <= y && (int)level.event[i].x+(int)level.event[i].w > x && (int)level.event[i].y+(int)level.event[i].h > y )
609 			return i;
610 	}
611 
612 	return -1;
613 }
614 
615 
move_ev_pos(int x,int y)616 void move_ev_pos(int x, int y)
617 {
618 	if (drag_event == -1) return;
619 
620 	level.event[drag_event].x+=x;
621 	level.event[drag_event].y+=y;
622 }
623 
624 
add_event(int x,int y)625 void add_event(int x, int y)
626 {
627 	level.event = realloc(level.event, (level.n_events + 1) * sizeof(*level.event));
628 
629 	x += scroll_x;
630 	y += scroll_y;
631 
632 	x /= CELLSIZE;
633 	y /= CELLSIZE;
634 
635 	level.event[level.n_events].x = x;
636 	level.event[level.n_events].y = y;
637 	level.event[level.n_events].w = 1;
638 	level.event[level.n_events].h = 1;
639 
640 
641 	if (drag_event != -1)
642 	{
643 		level.event[level.n_events].w = level.event[drag_event].w;
644 		level.event[level.n_events].h = level.event[drag_event].h;
645 		memcpy(&level.event[level.n_events].param, &level.event[drag_event].param, sizeof(level.event[drag_event].param));
646 	}
647 	else
648 	{
649 		if (n_ev_desc > 0)
650 		{
651 			for (int i = 0; i < EV_PARAMS ; ++i)
652 				level.event[level.n_events].param[i] = ev_desc[0].param[i].default_val;
653 		}
654 		level.event[level.n_events].param[EV_NEXT] = -1;
655 		level.event[level.n_events].param[EV_TRGPARENT] = -1;
656 	}
657 
658 	selected_event = level.n_events;
659 
660 	++level.n_events;
661 }
662 
663 
delete_event()664 void delete_event()
665 {
666 	if (selected_event == -1) return;
667 
668 	memcpy(&level.event[selected_event], &level.event[selected_event+1], (level.n_events - selected_event) * sizeof(*level.event));
669 
670 	--level.n_events;
671 
672 	for (int i = 0 ; i < level.n_events ; ++i)
673 	{
674 		if (level.event[i].param[EV_NEXT] == selected_event)
675 		{
676 			level.event[i].param[EV_NEXT] = -1;
677 		}
678 		else if (level.event[i].param[EV_NEXT] > selected_event)
679 		{
680 			--level.event[i].param[EV_NEXT];
681 		}
682 
683 		if (level.event[i].param[EV_TRGPARENT] == selected_event)
684 		{
685 			level.event[i].param[EV_TRGPARENT] = -1;
686 		}
687 		else if (level.event[i].param[EV_TRGPARENT] > selected_event)
688 		{
689 			--level.event[i].param[EV_TRGPARENT];
690 		}
691 	}
692 
693 	if (selected_event >= level.n_events) --selected_event;
694 }
695 
696 
shift_layer(int dx,int dy)697 void shift_layer(int dx, int dy)
698 {
699 	int w = level.layer[current_layer].w;
700 	int h = level.layer[current_layer].h;
701 
702 	BgCell *temp = malloc(sizeof(BgCell)*w*h);
703 
704 	for (int y = 0 ; y < h ; ++y)
705 		for (int x = 0 ; x < w ; ++x)
706 		{
707 			memcpy(&temp[(x + dx + w) % w + ((y + dy + h) % h) * w], &level.layer[current_layer].data[x+y*w], sizeof(BgCell));
708 		}
709 
710 	memcpy(level.layer[current_layer].data, temp, w * h * sizeof(BgCell));
711 
712 	free(temp);
713 }
714 
715 
shift_events(int dx,int dy)716 void shift_events(int dx,int dy)
717 {
718 	for (int i = 0 ; i < level.n_events ; ++i)
719 	{
720 		level.event[i].x += dx;
721 		level.event[i].y += dy;
722 	}
723 }
724 
725 
double_layer()726 void double_layer()
727 {
728 	int w = level.layer[current_layer].w;
729 	int h = level.layer[current_layer].h;
730 
731 	BgCell *temp = malloc(sizeof(BgCell) * (w * 2) * (h * 2));
732 
733 	for (int y = 0 ; y < h * 2 ; ++y)
734 		for (int x = 0 ; x < w * 2 ; ++x)
735 		{
736 			memcpy(&temp[x + y * (w * 2)], &level.layer[current_layer].data[(x / 2) + (y / 2) * w], sizeof(BgCell));
737 		}
738 
739 	BgCell *temp2 = level.layer[current_layer].data;
740 	level.layer[current_layer].data = temp;
741 
742 	level.layer[current_layer].w *= 2;
743 	level.layer[current_layer].h *= 2;
744 
745 	free(temp2);
746 }
747 
748 
insert_rowcol(int sx,int sy,int dx,int dy)749 void insert_rowcol(int sx, int sy, int dx, int dy)
750 {
751 	debug("Inserting row/col at %d,%d", sx, sy);
752 	resize_layer(level.layer[current_layer].w + dx, level.layer[current_layer].h + dy);
753 
754 	for (int x = level.layer[current_layer].w - 1 ; x >= sx + dx ; --x)
755 	{
756 		for (int y = 0 ; y < level.layer[current_layer].h ; ++y)
757 		{
758 			level.layer[current_layer].data[x + y * level.layer[current_layer].w].tile =
759 				level.layer[current_layer].data[x + y * level.layer[current_layer].w - dx].tile;
760 		}
761 	}
762 
763 	for (int x = 0 ; x < level.layer[current_layer].w ; ++x)
764 	{
765 		for (int y = level.layer[current_layer].h - 1 ; y >= sy + dy ; --y)
766 		{
767 			level.layer[current_layer].data[x + y * level.layer[current_layer].w].tile =
768 				level.layer[current_layer].data[x + (y - dy) * level.layer[current_layer].w].tile;
769 		}
770 	}
771 
772 }
773 
774 
resize_event(int dx,int dy)775 void resize_event(int dx,int dy)
776 {
777 	if (selected_event == -1) return;
778 
779 	if (dx < 0 && level.event[selected_event].w > 1) level.event[selected_event].w += dx;
780 	if (dy < 0 && level.event[selected_event].h > 1) level.event[selected_event].h += dy;
781 	if (dx > 0 && level.event[selected_event].w < 65535) level.event[selected_event].w += dx;
782 	if (dy > 0 && level.event[selected_event].h < 65535) level.event[selected_event].h += dy;
783 }
784 
785 #undef main
786 
main(int argc,char ** argv)787 int main(int argc, char **argv)
788 {
789 	SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE);
790 	atexit(SDL_Quit);
791 
792 	domain = gfx_create_domain("Editor", 0, 640, 480, 1);
793 	domain->screen_w = 640;
794 	domain->screen_h = 480;
795 	domain->fps = 20;
796 	domain->scale = 1;
797 	gfx_domain_update(domain, true);
798 
799 	gfx = gfx_load_surface(domain, "bevel.bmp", GFX_KEYED);
800 	font_load_file(domain, &font, "8x8.fnt");
801 
802 	config_init(&cfg);
803 
804 	load_defs(argc > 1 ? argv[1] : NULL);
805 
806 	if (strcmp(tileset,"") == 0)
807 	{
808 		fatal("no tileset specified");
809 		return 1;
810 	}
811 
812 	if (argc > 2) load_level(argv[2]);
813 
814 	domain->screen_w = screen_width;
815 	domain->screen_h = screen_height;
816 	domain->scale = screen_scale;
817 	gfx_domain_update(domain, true);
818 
819 	GfxSurface *tiles = gfx_load_surface(domain, tileset, GFX_KEYED);
820 
821 	if (!tiles)
822 	{
823 		fatal("tileset not found");
824 		return 2;
825 	}
826 
827 	descriptor = gfx_build_tiledescriptor(tiles, CELLSIZE, CELLSIZE, NULL);
828 
829 	for (int i = 0 ; i < MAX_LAYERS+2 ; ++i)
830 	{
831 		level.layer[i].tiles = descriptor;
832 	}
833 
834 	level.n_layers = MAX_LAYERS;
835 
836 	init_magic_layer(tiles->surface->w, tiles->surface->h, descriptor, (tiles->surface->w/CELLSIZE) * (tiles->surface->h/CELLSIZE));
837 
838 	int done = 0;
839 
840 	while (1)
841 	{
842 		SDL_Event e;
843 
844 		int got_event = 0;
845 
846 		while (SDL_PollEvent(&e))
847 		{
848 			got_event = 1;
849 			switch (e.type)
850 			{
851 				case SDL_QUIT:
852 					done = 1;
853 				break;
854 
855 				case SDL_MOUSEMOTION:
856 				{
857 					if (e.motion.state & SDL_BUTTON(SDL_BUTTON_RIGHT))
858 					{
859 						scroll_x -= e.motion.x/domain->scale - drag_start_x;
860 						scroll_y -= e.motion.y/domain->scale - drag_start_y;
861 						drag_start_x = e.button.x / domain->scale;
862 						drag_start_y = e.button.y / domain->scale;
863 					}
864 
865 
866 					if (edit_mode == EM_LEVEL && e.motion.state & SDL_BUTTON(SDL_BUTTON_LEFT) && drag_x == -1)
867 					{
868 						set_tile(e.motion.x / domain->scale, e.motion.y / domain->scale);
869 					}
870 					else if (edit_mode == EM_EVENTS && e.motion.state & SDL_BUTTON(SDL_BUTTON_LEFT) && drag_event != -1)
871 					{
872 						move_ev_pos(e.motion.x / CELLSIZE / domain->scale - ev_drag_start_x, e.motion.y / CELLSIZE / domain->scale - ev_drag_start_y);
873 						ev_drag_start_x = e.motion.x / CELLSIZE / domain->scale;
874 						ev_drag_start_y = e.motion.y / CELLSIZE / domain->scale;
875 					}
876 				}
877 				break;
878 
879 				case SDL_MOUSEBUTTONUP:
880 				{
881 					if (edit_mode == EM_LEVEL && drag_x != -1)
882 					{
883 						get_brush(drag_x, drag_y, e.button.x / domain->scale, e.button.y / domain->scale);
884 						drag_x = -1;
885 						selected_event = drag_event = -1;
886 					}
887 					else if (edit_mode == EM_EVENTS && drag_event != -1)
888 					{
889 						drag_event = -1;
890 					}
891 				}
892 				break;
893 
894 				case SDL_MOUSEBUTTONDOWN:
895 					drag_start_x = e.button.x / domain->scale;
896 					drag_start_y = e.button.y / domain->scale;
897 					if (edit_mode == EM_LEVEL)
898 					{
899 						selected_event = drag_event = -1;
900 						if (e.button.button == (SDL_BUTTON_LEFT))
901 						{
902 							const Uint8 * keys = SDL_GetKeyboardState(NULL);
903 							if (keys[SDL_SCANCODE_LSHIFT]||keys[SDL_SCANCODE_RSHIFT])
904 							{
905 								drag_x = e.button.x / domain->scale;
906 								drag_y = e.button.y / domain->scale;
907 							}
908 							else
909 							{
910 								set_tile(e.button.x / domain->scale, e.button.y / domain->scale);
911 							}
912 						}
913 						if ((e.button.button == (SDL_BUTTON_LEFT) && current_layer == MAGICK_LAYER))
914 						{
915 							get_tile(e.button.x / domain->scale, e.button.y / domain->scale);
916 						}
917 					}
918 					else
919 					{
920 						const Uint8 * keys = SDL_GetKeyboardState(NULL);
921 						if (selected_event != -1 && (keys[SDL_SCANCODE_LCTRL]||keys[SDL_SCANCODE_RCTRL]))
922 						{
923 							level.event[selected_event].param[(keys[SDL_SCANCODE_LSHIFT]||keys[SDL_SCANCODE_RSHIFT])?EV_TRGPARENT:EV_NEXT] = get_event(e.button.x / domain->scale, e.button.y / domain->scale);
924 						}
925 						else
926 						{
927 							drag_event = selected_event = get_event(e.button.x / domain->scale, e.button.y / domain->scale);
928 							ev_drag_start_x = e.button.x / CELLSIZE / domain->scale;
929 							ev_drag_start_y = e.button.y / CELLSIZE / domain->scale;
930 						}
931 					}
932 				break;
933 
934 
935 				case SDL_KEYDOWN:
936 
937 					if ((e.key.keysym.mod & KMOD_SHIFT) && (e.key.keysym.mod & KMOD_CTRL))
938 					{
939 						if (e.key.keysym.sym == SDLK_i)
940 						{
941 							int x,y;
942 							SDL_GetMouseState(&x, &y);
943 							insert_rowcol((x / domain->scale + scroll_x) / CELLSIZE, (y / domain->scale + scroll_y) / CELLSIZE, 1, 0);
944 						}
945 						else if (edit_mode == EM_EVENTS)
946 						{
947 							switch (e.key.keysym.sym)
948 							{
949 								default:break;
950 								case SDLK_UP:
951 
952 								shift_events(0,-1);
953 
954 								break;
955 
956 								case SDLK_DOWN:
957 
958 								shift_events(0,1);
959 
960 								break;
961 
962 								case SDLK_LEFT:
963 
964 								shift_events(-1,0);
965 
966 								break;
967 
968 								case SDLK_RIGHT:
969 
970 								shift_events(1,0);
971 
972 								break;
973 							}
974 						}
975 						else
976 						{
977 							switch (e.key.keysym.sym)
978 							{
979 								default:break;
980 								case SDLK_UP:
981 
982 								shift_layer(0,-1);
983 
984 								break;
985 
986 								case SDLK_DOWN:
987 
988 								shift_layer(0,1);
989 
990 								break;
991 
992 								case SDLK_LEFT:
993 
994 								shift_layer(-1,0);
995 
996 								break;
997 
998 								case SDLK_RIGHT:
999 
1000 								shift_layer(1,0);
1001 
1002 								break;
1003 							}
1004 						}
1005 					}
1006 					else if (e.key.keysym.mod & KMOD_CTRL)
1007 					{
1008 						if (e.key.keysym.sym == SDLK_F9)
1009 							level_export(&level);
1010 						else if (e.key.keysym.sym == SDLK_s)
1011 							save_dialog();
1012 						else if (e.key.keysym.sym == SDLK_o)
1013 							load_dialog();
1014 						else if (e.key.keysym.sym == SDLK_i)
1015 						{
1016 							int x,y;
1017 							SDL_GetMouseState(&x, &y);
1018 							insert_rowcol((x / domain->scale + scroll_x) / CELLSIZE, (y / domain->scale + scroll_y) / CELLSIZE, 0, 1);
1019 						}
1020 						else if (edit_mode == EM_EVENTS)
1021 						{
1022 							switch (e.key.keysym.sym)
1023 							{
1024 								default:break;
1025 								case SDLK_UP:
1026 
1027 								resize_event(0,-1);
1028 
1029 								break;
1030 
1031 								case SDLK_DOWN:
1032 
1033 								resize_event(0,1);
1034 
1035 								break;
1036 
1037 								case SDLK_LEFT:
1038 
1039 								resize_event(-1,0);
1040 
1041 								break;
1042 
1043 								case SDLK_RIGHT:
1044 
1045 								resize_event(1,0);
1046 
1047 								break;
1048 							}
1049 						}
1050 						else
1051 						{
1052 							switch (e.key.keysym.sym)
1053 							{
1054 								case SDLK_UP:
1055 
1056 								if (level.layer[current_layer].h > 0)
1057 									resize_layer(level.layer[current_layer].w, level.layer[current_layer].h-1);
1058 
1059 								break;
1060 
1061 								case SDLK_DOWN:
1062 
1063 								resize_layer(level.layer[current_layer].w, level.layer[current_layer].h+1);
1064 
1065 								break;
1066 
1067 								case SDLK_LEFT:
1068 
1069 								if (level.layer[current_layer].w > 0)
1070 									resize_layer(level.layer[current_layer].w-1, level.layer[current_layer].h);
1071 
1072 								break;
1073 
1074 								case SDLK_RIGHT:
1075 
1076 								resize_layer(level.layer[current_layer].w+1, level.layer[current_layer].h);
1077 
1078 								break;
1079 
1080 								case SDLK_F10:
1081 								clear_layer();
1082 								break;
1083 
1084 								default:
1085 								break;
1086 							}
1087 						}
1088 					}
1089 					else
1090 					{
1091 						if (edit_mode == EM_LEVEL)
1092 						{
1093 							switch (e.key.keysym.sym)
1094 							{
1095 								case SDLK_h:
1096 									double_layer();
1097 								break;
1098 
1099 								case SDLK_PAGEUP:
1100 								{
1101 									if (current_layer > 0)
1102 									{
1103 										swap(&level.layer[current_layer], &level.layer[current_layer-1], sizeof(level.layer[current_layer]));
1104 										--current_layer;
1105 									}
1106 								}
1107 								break;
1108 
1109 								case SDLK_PAGEDOWN:
1110 								{
1111 									if (current_layer < MAX_LAYERS - 1)
1112 									{
1113 										swap(&level.layer[current_layer], &level.layer[current_layer+1], sizeof(level.layer[current_layer]));
1114 										++current_layer;
1115 									}
1116 								}
1117 								break;
1118 
1119 								case SDLK_e:
1120 									edit_mode = edit_mode == EM_LEVEL ? EM_EVENTS : EM_LEVEL;
1121 								break;
1122 
1123 								case SDLK_1:
1124 								case SDLK_2:
1125 								case SDLK_3:
1126 								case SDLK_4:
1127 								case SDLK_5:
1128 								case SDLK_6:
1129 								case SDLK_7:
1130 								case SDLK_8:
1131 
1132 								current_layer = e.key.keysym.sym-SDLK_1;
1133 
1134 								break;
1135 
1136 								case SDLK_b:
1137 
1138 								current_layer = BRUSH_LAYER;
1139 
1140 								break;
1141 
1142 								case SDLK_RALT:
1143 								case SDLK_LALT:
1144 									if (e.key.repeat)
1145 										break;
1146 									saved_layer = current_layer;
1147 									current_layer = MAGICK_LAYER;
1148 								break;
1149 
1150 								case SDLK_UP:
1151 
1152 								scroll_y -= 4;
1153 
1154 								break;
1155 
1156 								case SDLK_DOWN:
1157 
1158 								scroll_y += 4;
1159 
1160 								break;
1161 
1162 								case SDLK_LEFT:
1163 
1164 								scroll_x -= 4;
1165 
1166 								break;
1167 
1168 								case SDLK_RIGHT:
1169 
1170 								scroll_x += 4;
1171 
1172 								break;
1173 
1174 								case SDLK_m:
1175 
1176 								level.layer[current_layer].prx_mlt_x = (level.layer[current_layer].prx_mlt_x + 1) % 17;
1177 
1178 								break;
1179 
1180 								case SDLK_n:
1181 
1182 								level.layer[current_layer].prx_mlt_y = (level.layer[current_layer].prx_mlt_y + 1) % 17;
1183 
1184 								break;
1185 
1186 								case SDLK_p:
1187 
1188 								set_flags(BG_PARALLAX);
1189 
1190 								break;
1191 
1192 								case SDLK_x:
1193 
1194 								set_flags(BG_REPEAT_X);
1195 
1196 								break;
1197 
1198 								case SDLK_y:
1199 
1200 								set_flags(BG_REPEAT_Y);
1201 
1202 								break;
1203 
1204 								default: break;
1205 							}
1206 						}
1207 						else
1208 						{
1209 
1210 							{
1211 								switch (e.key.keysym.sym)
1212 								{
1213 									case SDLK_e:
1214 										edit_mode = edit_mode == EM_LEVEL ? EM_EVENTS : EM_LEVEL;
1215 									break;
1216 
1217 									case SDLK_INSERT:
1218 									{
1219 										int x,y;
1220 										SDL_GetMouseState(&x, &y);
1221 										add_event(x / domain->scale, y / domain->scale);
1222 									}
1223 									break;
1224 
1225 									case SDLK_DELETE:
1226 
1227 									delete_event();
1228 
1229 									break;
1230 
1231 
1232 									case SDLK_PERIOD:
1233 									case SDLK_COMMA:
1234 										if (selected_event == -1) break;
1235 
1236 										level.event[selected_event].param[selected_param] += e.key.keysym.sym == SDLK_COMMA ? -1 : 1;
1237 
1238 										if (selected_param == 0)
1239 										{
1240 											level.event[selected_event].param[selected_param] = my_max(0, my_min(n_ev_desc - 1,level.event[selected_event].param[selected_param]));
1241 
1242 											for (int i = 1 ; i < EV_PARAMS - 2 ; ++i)
1243 												level.event[selected_event].param[i] = my_max(ev_desc[level.event[selected_event].param[0]].param[i].int_min,
1244 													my_min(ev_desc[level.event[selected_event].param[0]].param[i].int_max ,level.event[selected_event].param[i]));
1245 										}
1246 										else
1247 										{
1248 											if (selected_param != EV_NEXT && selected_param != EV_TRGPARENT)
1249 												level.event[selected_event].param[selected_param] = my_max(ev_desc[level.event[selected_event].param[0]].param[selected_param].int_min,
1250 													my_min(ev_desc[level.event[selected_event].param[0]].param[selected_param].int_max ,level.event[selected_event].param[selected_param]));
1251 										}
1252 									break;
1253 
1254 									case SDLK_PAGEUP:
1255 										selected_param = (selected_param - 1) & (EV_PARAMS-1);
1256 									break;
1257 
1258 									case SDLK_PAGEDOWN:
1259 										selected_param = (selected_param + 1) & (EV_PARAMS-1);
1260 									break;
1261 
1262 									case SDLK_UP:
1263 
1264 									scroll_y -= 4;
1265 
1266 									break;
1267 
1268 									case SDLK_DOWN:
1269 
1270 									scroll_y += 4;
1271 
1272 									break;
1273 
1274 									case SDLK_LEFT:
1275 
1276 									scroll_x -= 4;
1277 
1278 									break;
1279 
1280 									case SDLK_RIGHT:
1281 
1282 									scroll_x += 4;
1283 
1284 									break;
1285 
1286 									default: break;
1287 								}
1288 							}
1289 						}
1290 					}
1291 
1292 				break;
1293 
1294 				case SDL_KEYUP:
1295 					if(edit_mode == EM_LEVEL)
1296 					{
1297 						switch (e.key.keysym.sym)
1298 						{
1299 
1300 							case SDLK_RALT:
1301 							case SDLK_LALT:
1302 								current_layer = saved_layer;
1303 							break;
1304 
1305 							default: break;
1306 						}
1307 					}
1308 				break;
1309 			}
1310 		}
1311 
1312 		if (got_event)
1313 		{
1314 
1315 			const Uint8 * keys = SDL_GetKeyboardState(NULL);
1316 			int x,y;
1317 			SDL_GetMouseState(&x, &y);
1318 
1319 			int show_all_layers = keys[SDL_SCANCODE_A];
1320 
1321 			gfx_rect(domain, NULL, bg_color);
1322 			draw(domain, x / domain->scale, y / domain->scale, show_all_layers);
1323 
1324 			static const char *layer_names[] =
1325 			{
1326 				"Tiles",
1327 				"Brush"
1328 			};
1329 
1330 
1331 			char text[100], si[10];
1332 			SDL_Rect textpos = {domain->screen_w - 400,0, 1000, 1000};
1333 
1334 			if (edit_mode == EM_LEVEL)
1335 			{
1336 				//if (current_layer < MAGICK_LAYER)
1337 				{
1338 					sprintf(si, "%d", current_layer);
1339 					sprintf(text, "[L %s] prx(%s) pos(%d,%d) size(%dx%d,%dx%d)\n", show_all_layers?"All":(current_layer>=MAGICK_LAYER?layer_names[current_layer-MAGICK_LAYER]:si), level.layer[current_layer].flags&BG_PARALLAX?"ON":"OFF", scroll_x/CELLSIZE, scroll_y/CELLSIZE, level.layer[current_layer].w, level.layer[current_layer].prx_mlt_x, level.layer[current_layer].h, level.layer[current_layer].prx_mlt_y);
1340 
1341 					font_write(&font, domain, &textpos, text);
1342 					textpos.y += font.h;
1343 				}
1344 			}
1345 			else
1346 			{
1347 				if (selected_event == -1)
1348 				{
1349 					sprintf(text, "[EV] pos(%d,%d)\n", scroll_x/CELLSIZE, scroll_y/CELLSIZE);
1350 					font_write(&font, domain, &textpos, text);
1351 					textpos.y += font.h;
1352 				}
1353 				else
1354 				{
1355 					sprintf(text, "[EV:%02x(%d,%d %d,%d)] pos(%d,%d)\n", selected_event, level.event[selected_event].x, level.event[selected_event].y, level.event[selected_event].w, level.event[selected_event].h, scroll_x/CELLSIZE, scroll_y/CELLSIZE);
1356 					font_write(&font, domain, &textpos, text);
1357 					textpos.y += font.h;
1358 
1359 					for (int i = 0 ; i < EV_PARAMS ; ++i)
1360 					{
1361 						char s = ' ';
1362 
1363 						if (i == selected_param) s = '�';
1364 
1365 						if (i == 0)
1366 						{
1367 							snprintf(text, 100, "%-9s: %s", "Type", ev_desc[level.event[selected_event].param[i]].name);
1368 						}
1369 						else if (i == EV_TRGPARENT)
1370 						{
1371 							snprintf(text, 100, "%-9s: %4d", "TrgParent", level.event[selected_event].param[i]);
1372 						}
1373 						else if (i == EV_NEXT)
1374 						{
1375 							snprintf(text, 100, "%-9s: %4d", "Next", level.event[selected_event].param[i]);
1376 						}
1377 						else
1378 						{
1379 							if (ev_desc[level.event[selected_event].param[0]].param[i].type == EVPAR_ENUM)
1380 								snprintf(text, 100, "%-9s: %s", ev_desc[level.event[selected_event].param[0]].param[i].name, ev_desc[level.event[selected_event].param[0]].param[i].enums[level.event[selected_event].param[i]]);
1381 							else
1382 								snprintf(text, 100, "%-9s: %4d", ev_desc[level.event[selected_event].param[0]].param[i].name, level.event[selected_event].param[i]);
1383 						}
1384 
1385 						font_write_args(&font, domain, &textpos, "%c%s", s, text);
1386 						textpos.y += font.h;
1387 					}
1388 				}
1389 
1390 
1391 			}
1392 
1393 			gfx_domain_flip(domain);
1394 		}
1395 		else
1396 		{
1397 			SDL_Delay(1);
1398 		}
1399 
1400 		if (done)
1401 		{
1402 			int r = confirm_ync(domain, gfx, &font, "Save level?");
1403 
1404 			if (r == 0) done = 0;
1405 			if (r == -1) goto out;
1406 			if (r == 1) { if (!save_dialog()) done = 0; else break; }
1407 		}
1408 	}
1409 
1410 	out:
1411 
1412 	font_destroy(&font);
1413 	config_destroy(&cfg);
1414 	free(ev_desc);
1415 
1416 	return 0;
1417 }
1418