2 /***************************************************************************
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
9 ***************************************************************************/
11 /* December 28, 2003 - January 1st, 2004 */
13 /* leveleditor.c - A built-in level editor for SuperTux
14 by Ricardo Cruz <rick2@aeiou.pt> */
22 #include <SDL_image.h>
23 #include "leveleditor.h"
35 /* definitions to aid development */
36 #define DONE_LEVELEDITOR 1
38 #define DONE_CHANGELEVEL 3
40 /* definitions that affect gameplay */
41 #define KEY_CURSOR_SPEED 32
42 #define KEY_CURSOR_FASTSPEED 64
44 #define CURSOR_LEFT_MARGIN 96
45 #define CURSOR_RIGHT_MARGIN 512
46 /* right_margin should noticed that the cursor is 32 pixels,
47 so it should subtract that value */
49 #define MOUSE_LEFT_MARGIN 32
50 #define MOUSE_RIGHT_MARGIN 608
51 #define MOUSE_POS_SPEED 32
57 sprintf(str, "Editing Level %s", levelfilename);
58 drawcenteredtext(str, 200, letters_red, NO_UPDATE, 1);
60 sprintf(str, "%s", levelname);
61 drawcenteredtext(str, 224, letters_gold, NO_UPDATE, 1);
68 /* gameloop funcs declerations */
70 void loadshared(void);
71 void unloadshared(void);
73 /* own declerations */
76 void le_change(float x, float y, unsigned char c);
78 void le_set_defaults(void);
79 void le_activate_bad_guys(void);
81 /* global variables (based on the gameloop ones) */
84 st_level current_level;
85 char level_subset[100];
88 texture_type selection;
89 int last_time, now_time;
96 texture_free(&selection);
99 void le_activate_bad_guys(void)
103 /* Activate bad guys: */
105 /* as oposed to the gameloop.c func, this one doesn't remove
106 the badguys from tiles */
108 for (y = 0; y < 15; ++y)
109 for (x = 0; x < current_level.width; ++x)
110 if (current_level.tiles[y][x] >= '0' && current_level.tiles[y][x] <= '9')
111 add_bad_guy(x * 32, y * 32, current_level.tiles[y][x] - '0');
114 void le_set_defaults()
118 if(current_level.time_left == 0)
119 current_level.time_left = 255;
122 /* FIXME: Needs to be implemented. It should ask the user for the level(file)name and then let him create a new level based on this. */
126 /* FIXME: It should let select the user a level, which is in the leveldirectory and then load it. */
132 char str[LEVEL_NAME_MAX];
134 int x, y, i; /* for cicles */
135 int pos_x, cursor_x, cursor_y, fire;
140 strcpy(level_subset,"default");
145 menumenu = MENU_LEVELEDITOR;
148 frame = 0; /* support for frames in some tiles, like waves and bad guys */
155 loadlevel(¤t_level,"default",level);
156 loadlevelgfx(¤t_level);
158 le_activate_bad_guys();
161 texture_load(&selection,DATA_PREFIX "/images/leveleditor/select.png", USE_ALPHA);
169 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
173 clearscreen(current_level.bkgd_red, current_level.bkgd_green, current_level.bkgd_blue);
175 last_time = SDL_GetTicks();
178 keymod = SDL_GetModState();
180 while(SDL_PollEvent(&event))
182 // testing SDL_KEYDOWN, SDL_KEYUP and SDL_QUIT events
185 case SDL_KEYDOWN: // key pressed
186 key = event.key.keysym.sym;
196 cursor_x -= KEY_CURSOR_SPEED;
198 cursor_x -= KEY_CURSOR_FASTSPEED;
205 cursor_x += KEY_CURSOR_SPEED;
207 cursor_x += KEY_CURSOR_FASTSPEED;
209 if(cursor_x > (current_level.width*32) - 1)
210 cursor_x = (current_level.width*32) - 1;
214 cursor_y -= KEY_CURSOR_SPEED;
216 cursor_y -= KEY_CURSOR_FASTSPEED;
223 cursor_y += KEY_CURSOR_SPEED;
225 cursor_y += KEY_CURSOR_FASTSPEED;
227 if(cursor_y > screen->h-32)
228 cursor_y = screen->h-32;
240 cursor_x = (current_level.width * 32) - 32;
243 le_change(cursor_x, cursor_y, '.');
246 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
247 le_change(cursor_x, cursor_y, 'A');
249 le_change(cursor_x, cursor_y, 'a');
252 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
253 le_change(cursor_x, cursor_y, 'B');
256 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
257 le_change(cursor_x, cursor_y, 'C');
259 le_change(cursor_x, cursor_y, 'c');
262 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
263 le_change(cursor_x, cursor_y, 'D');
265 le_change(cursor_x, cursor_y, 'd');
268 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
269 le_change(cursor_x, cursor_y, 'E');
271 le_change(cursor_x, cursor_y, 'e');
274 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
275 le_change(cursor_x, cursor_y, 'F');
277 le_change(cursor_x, cursor_y, 'f');
280 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
281 le_change(cursor_x, cursor_y, 'G');
283 le_change(cursor_x, cursor_y, 'g');
286 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
287 le_change(cursor_x, cursor_y, 'H');
289 le_change(cursor_x, cursor_y, 'h');
292 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
293 le_change(cursor_x, cursor_y, 'I');
295 le_change(cursor_x, cursor_y, 'i');
298 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
299 le_change(cursor_x, cursor_y, 'J');
301 le_change(cursor_x, cursor_y, 'j');
304 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
305 le_change(cursor_x, cursor_y, 'X');
307 le_change(cursor_x, cursor_y, 'x');
310 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
311 le_change(cursor_x, cursor_y, 'Y');
313 le_change(cursor_x, cursor_y, 'y');
315 case SDLK_LEFTBRACKET:
316 le_change(cursor_x, cursor_y, '[');
318 case SDLK_RIGHTBRACKET:
319 le_change(cursor_x, cursor_y, ']');
323 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
324 le_change(cursor_x, cursor_y, '#');
328 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
329 le_change(cursor_x, cursor_y, '$');
332 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
333 le_change(cursor_x, cursor_y, '|');
335 le_change(cursor_x, cursor_y, '\\');
338 le_change(cursor_x, cursor_y, '^');
342 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
343 le_change(cursor_x, cursor_y, '&');
347 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
348 le_change(cursor_x, cursor_y, '=');
349 else /* let's add a bad guy */
350 le_change(cursor_x, cursor_y, '0');
352 add_bad_guy((((int)cursor_x/32)*32), (((int)cursor_y/32)*32), BAD_BSOD);
355 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
356 le_change(cursor_x, cursor_y, '!');
357 else /* let's add a bad guy */
358 le_change(cursor_x, cursor_y, '1');
360 add_bad_guy((((int)cursor_x/32)*32), (((int)cursor_y/32)*32), BAD_LAPTOP);
363 le_change(cursor_x, cursor_y, '2');
365 add_bad_guy((((int)cursor_x/32)*32), (((int)cursor_y/32)*32), BAD_MONEY);
368 if(keymod == KMOD_LSHIFT || keymod == KMOD_RSHIFT || keymod == KMOD_CAPS)
369 le_change(cursor_x, cursor_y, '*');
375 case SDL_KEYUP: // key released
376 switch(event.key.keysym.sym)
391 /* case SDL_MOUSEBUTTONDOWN:
392 if(event.button.button == SDL_BUTTON_LEFT)
394 This will draw current tile in the cursor position, when the interface is done.
397 case SDL_MOUSEMOTION:
403 cursor_x = ((int)(pos_x + x) / 32) * 32;
404 cursor_y = ((int) y / 32) * 32;
407 case SDL_QUIT: // window closed
415 /* mouse movements */
416 /* x = event.motion.x;
417 if(x < MOUSE_LEFT_MARGIN)
418 pos_x -= MOUSE_POS_SPEED;
419 else if(x > MOUSE_RIGHT_MARGIN)
420 pos_x += MOUSE_POS_SPEED;*/
423 if(cursor_x < pos_x + CURSOR_LEFT_MARGIN)
424 pos_x = cursor_x - CURSOR_LEFT_MARGIN;
426 if(cursor_x > pos_x + CURSOR_RIGHT_MARGIN)
427 pos_x = cursor_x - CURSOR_RIGHT_MARGIN;
431 if(pos_x > (current_level.width * 32) - screen->w)
432 pos_x = (current_level.width * 32) - screen->w;
434 for (y = 0; y < 15; ++y)
435 for (x = 0; x < 21; ++x)
436 drawshape(x * 32, y * 32, current_level.tiles[y][x + (pos_x / 32)]);
438 /* Draw the Bad guys: */
439 for (i = 0; i < num_bad_guys; ++i)
441 /* printf("\nbad_guys[%i].alive = %i", i, bad_guys[i].alive); */
442 if(bad_guys[i].base.alive == NO)
444 /* to support frames: img_bsod_left[(frame / 5) % 4] */
445 if(bad_guys[i].kind == BAD_BSOD)
446 texture_draw(&img_bsod_left[(frame / 5) % 4], ((int)(bad_guys[i].base.x - pos_x)/32)*32, bad_guys[i].base.y, NO_UPDATE);
447 else if(bad_guys[i].kind == BAD_LAPTOP)
448 texture_draw(&img_laptop_left[(frame / 5) % 3], ((int)(bad_guys[i].base.x - pos_x)/32)*32, bad_guys[i].base.y, NO_UPDATE);
449 else if (bad_guys[i].kind == BAD_MONEY)
450 texture_draw(&img_money_left[(frame / 5) % 2], ((int)(bad_guys[i].base.x - pos_x)/32)*32, bad_guys[i].base.y, NO_UPDATE);
454 texture_draw(&selection, ((int)(cursor_x - pos_x)/32)*32, cursor_y, NO_UPDATE);
456 sprintf(str, "%d", current_level.time_left);
457 drawtext("TIME", 324, 0, letters_blue, NO_UPDATE, 1);
458 drawtext(str, 404, 0, letters_gold, NO_UPDATE, 1);
460 sprintf(str, "%s", current_level.name);
461 drawtext("NAME", 0, 0, letters_blue, NO_UPDATE, 1);
462 drawtext(str, 80, 0, letters_gold, NO_UPDATE, 1);
464 drawtext("F1 for Help", 10, 430, letters_blue, NO_UPDATE, 1);
475 if(done == DONE_QUIT)
482 now_time = SDL_GetTicks();
483 if (now_time < last_time + FPS)
484 SDL_Delay(last_time + FPS - now_time); /* delay some time */
492 void le_change(float x, float y, unsigned char c)
497 level_change(¤t_level,x,y,c);
502 /* if there is a bad guy over there, remove it */
503 for(i = 0; i < num_bad_guys; ++i)
504 if (bad_guys[i].base.alive)
505 if(xx == bad_guys[i].base.x/32 && yy == bad_guys[i].base.y/32)
506 bad_guys[i].base.alive = NO;
509 /* Save data for this level: */
517 /* Save data file: */
519 filename = (char *) malloc(sizeof(char) * (strlen(DATA_PREFIX) + 20) + strlen(level_subset));
520 sprintf(filename, "%s/levels/%s/level%d.dat", DATA_PREFIX, level_subset, level);
521 fi = fopen(filename, "w");
532 /* sptrinf("# Level created by SuperTux built-in editor", fi); */
534 fputs(current_level.name, fi);
536 fputs(current_level.theme, fi);
538 sprintf(str, "%d\n", current_level.time_left); /* time */
540 fputs(current_level.song_title, fi); /* song filename */
541 sprintf(str, "\n%d\n", current_level.bkgd_red); /* red background color */
543 sprintf(str, "%d\n", current_level.bkgd_green); /* green background color */
545 sprintf(str, "%d\n", current_level.bkgd_blue); /* blue background color */
547 sprintf(str, "%d\n", current_level.width); /* level width */
550 for(y = 0; y < 15; ++y)
552 fputs(current_level.tiles[y], fi);
558 drawcenteredtext("SAVED!", 240, letters_gold, NO_UPDATE, 1);
587 "./Del - Remove tile",
591 drawcenteredtext("- Help -", 30, letters_red, NO_UPDATE, 2);
592 drawtext("Keys:", 80, 60, letters_gold, NO_UPDATE, 1);
595 for(i = 0; i < sizeof(text)/sizeof(char *); i++)
596 drawtext(text[i], 40, 90+(i*16), letters_blue, NO_UPDATE, 1);
598 drawcenteredtext("Press Any Key to Continue", 460, letters_gold, NO_UPDATE, 1);
605 while(SDL_PollEvent(&event))
608 case SDL_MOUSEBUTTONDOWN: // mouse pressed
609 case SDL_KEYDOWN: // key pressed