Fix for the problem that SDL applications exited
[AROS-Contrib.git] / Games / lbreakout2 / client / editor.c
blobe182081f2e20860b83571768d1afabfcd7229128
1 /***************************************************************************
2 editor.c - description
3 -------------------
4 begin : Fri Oct 12 2001
5 copyright : (C) 2001 by Michael Speck
6 email : kulkanie@gmx.net
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 #include "lbreakout.h"
19 #include "../game/game.h"
20 #include "game.h"
21 #include "config.h"
22 #include "bricks.h"
23 #include "frame.h"
24 #include "editor.h"
26 SDL_Surface *sel_frame = 0, *buttons = 0;
27 SDL_Surface *editor_bkgnd = 0; /* background (black with frame) of editor */
28 char edit_file_name[512]; /* full path of edited file */
29 Level *edit_levels[MAX_LEVELS]; /* editor levels */
30 char edit_version[16]; /* version of edited set */
31 int edit_level_count; /* how many levels currently used? */
32 int edit_cur_level_id;
33 Level *edit_cur_level; /* current level modified */
34 enum { EDITOR_BRICK, EDITOR_EXTRA };
35 int edit_sel_type; /* type of selected tile */
36 int edit_sel_id; /* brick or extra id */
37 int edit_sel_x, edit_sel_y; /* position in map of selected tile */
38 int edit_tile_x = 1, edit_tile_y = 20, edit_tile_w = MAP_WIDTH - 2, edit_tile_h = 3; /* part where either bricks ro bonuses
39 are displayed */
40 int extra_vis; /* extras currently shown? blinks. */
41 int first_swap_level = -1; /* if not -1 this and the current level will be swapped
42 next time the button is pressed */
43 enum {
44 /* tiles */
45 BUTTON_NONE = 0,
46 BUTTON_FIRST_BRICK,
47 BUTTON_LAST_BRICK = BUTTON_FIRST_BRICK + ( BRICK_COUNT_REGULAR ),
48 BUTTON_FIRST_EXTRA,
49 BUTTON_LAST_EXTRA = BUTTON_FIRST_EXTRA + ( EX_NUMBER -1 ),
50 BUTTON_EDIT,
51 BUTTON_EDIT_AUTHOR,
52 BUTTON_EDIT_NAME,
53 /* buttons */
54 BUTTON_FIRST,
55 BUTTON_NEXT,
56 BUTTON_PREV,
57 BUTTON_CLEAR,
58 BUTTON_SWAP,
59 BUTTON_ADD,
60 BUTTON_INSERT,
61 BUTTON_DELETE,
62 BUTTON_VERSION,
63 BUTTON_LOAD,
64 BUTTON_SAVE,
65 BUTTON_PLAY
67 int edit_buttons[MAP_WIDTH][MAP_HEIGHT]; /* an action is assigned to each map tile */
68 /* externals */
69 extern SDL_Surface *stk_display;
70 extern SDL_Surface *frame;
71 extern SDL_Surface *extra_pic;
72 extern SDL_Surface *brick_pic;
73 extern StkFont *mfont; /* use menu's font to draw status */
74 extern StkFont *font; /* use game's font to confirm */
75 extern Config config;
76 extern int stk_quit_request;
78 /* extra conversion table may be found in bricks.c */
79 extern Extra_Conv extra_conv_table[EX_NUMBER];
80 extern Brick_Conv brick_conv_table[BRICK_COUNT];
83 ====================================================================
84 Locals
85 ====================================================================
89 ====================================================================
90 We had a right click into the tile region so check and change the
91 bricks displayed there. We select the first new tile and set
92 edit_sel_id, edit_sel_x, edit_sel_y. The full update is initated
93 by editor_handle_click().
94 ====================================================================
96 void editor_switch_tiles()
98 int x_off = 2, y_off = 20, len = MAP_WIDTH - x_off * 2; /* offset in map of tiles, len is the number of tiles in one line */
99 int i, j;
100 /* clear edit buttons */
101 for ( i = edit_tile_x; i < edit_tile_x + edit_tile_w; i++ )
102 for ( j = edit_tile_y; j < edit_tile_y + edit_tile_h; j++ )
103 edit_buttons[i][j] = BUTTON_NONE;
104 /* clear this part of the editor bkjgnd */
105 stk_surface_fill( editor_bkgnd,
106 edit_tile_x * BRICK_WIDTH, edit_tile_y * BRICK_HEIGHT,
107 edit_tile_w * BRICK_WIDTH, edit_tile_h * BRICK_HEIGHT, 0x0 );
108 /* switch */
109 if ( edit_sel_type == EDITOR_BRICK ) {
110 /* flag */
111 edit_sel_type = EDITOR_EXTRA;
112 /* button map & background */
113 i = 0; j = 0;
114 while ( i + j * len < EX_NUMBER ) {
115 edit_buttons[x_off + i][y_off + j] = BUTTON_FIRST_EXTRA + i + j * len;
116 stk_surface_blit( extra_pic, ( i + j * len ) * BRICK_WIDTH, 0,
117 BRICK_WIDTH, BRICK_HEIGHT,
118 editor_bkgnd, ( i + x_off ) * BRICK_WIDTH, ( j + y_off ) * BRICK_HEIGHT );
119 i++;
120 if ( i == len ) {
121 i = 0;
122 j++;
125 /* select first tile */
126 edit_sel_id = 0;
127 edit_sel_x = x_off;
128 edit_sel_y = y_off;
130 else {
131 /* flag */
132 edit_sel_type = EDITOR_BRICK;
133 /* button map & background */
134 i = 0; j = 0;
135 while ( i + j * len < BRICK_COUNT_REGULAR ) {
136 edit_buttons[x_off + i][y_off + j] = BUTTON_FIRST_BRICK + i + j * len;
137 stk_surface_blit( brick_pic, ( i + j * len ) * BRICK_WIDTH, 0,
138 BRICK_WIDTH, BRICK_HEIGHT,
139 editor_bkgnd, ( i + x_off ) * BRICK_WIDTH, ( j + y_off ) * BRICK_HEIGHT );
140 i++;
141 if ( i == len ) {
142 i = 0;
143 j++;
146 /* select first tile */
147 edit_sel_id = 0;
148 edit_sel_x = x_off;
149 edit_sel_y = y_off;
154 ====================================================================
155 Draw a helping grid.
156 ====================================================================
158 void editor_draw_grid()
160 SDL_Surface *buffer;
161 int i, alpha;
162 buffer = stk_surface_create( SDL_SWSURFACE, EDIT_WIDTH * BRICK_WIDTH, 1 );
163 stk_surface_fill( buffer, 0,0,-1,-1, 0xffffff );
164 stk_surface_blit( buffer, 0,0,-1,-1, editor_bkgnd, BRICK_WIDTH, BRICK_HEIGHT );
165 stk_surface_blit( buffer, 0,0,-1,-1, editor_bkgnd, BRICK_WIDTH,
166 ( EDIT_HEIGHT + 1 ) * BRICK_HEIGHT - 1 );
167 for ( i = 0; i < EDIT_HEIGHT - 1; i++ ) {
168 if ( i == EDIT_HEIGHT / 2 - 1 )
169 alpha = 192;
170 else
171 if ( i % (EDIT_HEIGHT/4) == 0 )
172 alpha = 128;
173 else
174 alpha = 64;
175 stk_surface_alpha_blit( buffer, 0,0,-1,-1, editor_bkgnd,
176 BRICK_WIDTH, ( i + 1 ) * BRICK_HEIGHT + BRICK_HEIGHT - 1,
177 alpha );
179 SDL_FreeSurface( buffer );
180 buffer = stk_surface_create( SDL_SWSURFACE, 1, EDIT_HEIGHT * BRICK_HEIGHT );
181 stk_surface_fill( buffer, 0,0,-1,-1, 0xffffff );
182 stk_surface_blit( buffer, 0,0,-1,-1, editor_bkgnd, BRICK_WIDTH, BRICK_HEIGHT );
183 stk_surface_blit( buffer, 0,0,-1,-1, editor_bkgnd,
184 ( EDIT_WIDTH + 1 ) * BRICK_WIDTH - 1, BRICK_HEIGHT );
185 for ( i = 0; i < EDIT_WIDTH - 1; i++ ) {
186 if ( i == EDIT_WIDTH / 2 - 1 )
187 alpha = 192;
188 else
189 if ( i % (EDIT_WIDTH/4) == 0 )
190 alpha = 128;
191 else
192 alpha = 64;
193 stk_surface_alpha_blit( buffer, 0,0,-1,-1, editor_bkgnd,
194 ( i + 1 ) * BRICK_WIDTH + BRICK_WIDTH- 1, BRICK_HEIGHT,
195 alpha );
197 SDL_FreeSurface( buffer );
201 ====================================================================
202 Translate the saved character strings into extra and brick indices
203 for the editor.
204 ====================================================================
206 enum { INDICES_2_CHAR, CHAR_2_INDICES };
207 void editor_translate_level( Level *level, int type )
209 int i, j, k;
210 if ( type == CHAR_2_INDICES ) {
211 for ( i = 0; i < EDIT_WIDTH; i++ )
212 for ( j = 0; j < EDIT_HEIGHT; j++ ) {
213 /* bricks */
214 for ( k = 0; k < BRICK_COUNT; k++ )
215 if ( brick_conv_table[k].c == level->bricks[i][j] ) {
216 level->bricks[i][j] = brick_conv_table[k].id;
217 break;
219 if ( k == BRICK_COUNT ) level->bricks[i][j] = -1;
220 /* extras */
221 for ( k = 0; k < EX_NUMBER; k++ )
222 if ( extra_conv_table[k].c == level->extras[i][j] ) {
223 level->extras[i][j] = extra_conv_table[k].type;
224 break;
226 if ( k == EX_NUMBER ) level->extras[i][j] = EX_NONE;
229 else {
230 /* indices to characters */
231 for ( i = 0; i < EDIT_WIDTH; i++ )
232 for ( j = 0; j < EDIT_HEIGHT; j++ ) {
233 /* bricks */
234 if ( level->bricks[i][j] == -1 )
235 level->bricks[i][j] = '.';
236 else
237 for ( k = 0; k < BRICK_COUNT; k++ )
238 if ( level->bricks[i][j] == brick_conv_table[k].id ) {
239 level->bricks[i][j] = brick_conv_table[k].c;
240 break;
242 /* extras */
243 if ( level->extras[i][j] == EX_NONE )
244 level->extras[i][j] = '.';
245 else
246 for ( k = 0; k < EX_NUMBER; k++ )
247 if ( level->extras[i][j] == extra_conv_table[k].type ) {
248 level->extras[i][j] = extra_conv_table[k].c;
249 break;
255 ====================================================================
256 Draw name of set file, current level, current count, remaining
257 levels, and other info stuff.
258 ====================================================================
260 void editor_draw_status()
262 char str[512];
263 int x = BRICK_WIDTH, y = ( MAP_HEIGHT - 1 ) * BRICK_HEIGHT - 2;
264 int height = 10;
265 /* locartion */
266 sprintf( str, _("Location: %s"), edit_file_name );
267 mfont->align = STK_FONT_ALIGN_LEFT | STK_FONT_ALIGN_TOP;
268 stk_font_write( mfont, stk_display, x, y, STK_OPAQUE, str );
269 /* current level */
270 sprintf( str, _("Current Level: %i/%i (Free: %i)"), edit_cur_level_id + 1, edit_level_count, MAX_LEVELS - edit_level_count );
271 mfont->align = STK_FONT_ALIGN_LEFT | STK_FONT_ALIGN_TOP;
272 stk_font_write( mfont, stk_display, x, y + height, STK_OPAQUE, str );
273 /* swap */
274 mfont->align = STK_FONT_ALIGN_RIGHT | STK_FONT_ALIGN_TOP;
275 if ( first_swap_level != -1 ) {
276 sprintf( str, _("*** Level %i Marked For Swap ***"), first_swap_level + 1 );
277 stk_font_write( mfont, stk_display, stk_display->w - BRICK_WIDTH, y + height, STK_OPAQUE, str );
279 else {
280 /* version */
281 sprintf( str, _("Version: %s "), edit_version );
282 stk_font_write( mfont, stk_display, stk_display->w - BRICK_WIDTH, y + height, STK_OPAQUE, str );
284 /* name and author */
285 mfont->align = STK_FONT_ALIGN_LEFT | STK_FONT_ALIGN_TOP;
286 sprintf( str, _("Title: %s"), edit_cur_level->name );
287 stk_font_write( mfont, stk_display, BRICK_WIDTH + 2, ( MAP_HEIGHT - 5 ) * BRICK_HEIGHT + 5, STK_OPAQUE, str );
288 mfont->align = STK_FONT_ALIGN_RIGHT | STK_FONT_ALIGN_TOP;
289 sprintf( str, _("Author: %s"), edit_cur_level->author );
290 stk_font_write( mfont, stk_display, stk_display->w - BRICK_WIDTH - 2, ( MAP_HEIGHT - 5 ) * BRICK_HEIGHT + 5, STK_OPAQUE, str );
293 ====================================================================
294 Draw brick and extra (if any) from screen map pos
295 so it fits the editable field (no frame, no bottom).
296 ====================================================================
298 void editor_draw_brick( int edit_map_x, int edit_map_y )
300 /* brick */
301 if ( edit_cur_level->bricks[edit_map_x][edit_map_y] != -1 ) {
302 if ( edit_cur_level->bricks[edit_map_x][edit_map_y] != INVIS_BRICK_ID )
303 stk_surface_blit( brick_pic,
304 edit_cur_level->bricks[edit_map_x][edit_map_y] * BRICK_WIDTH, 0,
305 BRICK_WIDTH, BRICK_HEIGHT,
306 stk_display, (edit_map_x + 1) * BRICK_WIDTH, (edit_map_y + 1) * BRICK_HEIGHT );
307 else
308 stk_surface_fill( stk_display,
309 (edit_map_x + 1) * BRICK_WIDTH, (edit_map_y + 1) * BRICK_HEIGHT,
310 BRICK_WIDTH, BRICK_HEIGHT, 0x777777 );
312 else {
313 stk_surface_blit( editor_bkgnd,
314 (edit_map_x + 1) * BRICK_WIDTH, (edit_map_y + 1) * BRICK_HEIGHT,
315 BRICK_WIDTH, BRICK_HEIGHT, stk_display,
316 (edit_map_x + 1) * BRICK_WIDTH, (edit_map_y + 1) * BRICK_HEIGHT );
318 /* extra */
319 if ( ( extra_vis || edit_sel_type == EDITOR_EXTRA ) && edit_cur_level->extras[edit_map_x][edit_map_y] != EX_NONE) {
320 stk_surface_blit( extra_pic,
321 ( edit_cur_level->extras[edit_map_x][edit_map_y] ) * BRICK_WIDTH, 0,
322 BRICK_WIDTH, BRICK_HEIGHT,
323 stk_display, (edit_map_x + 1) * BRICK_WIDTH, (edit_map_y + 1) * BRICK_HEIGHT );
325 stk_display_store_drect();
328 ====================================================================
329 Redraw and refresh full screen
330 ====================================================================
332 void editor_full_update()
334 int i, j;
335 /* background */
336 stk_surface_blit( editor_bkgnd, 0,0,-1,-1, stk_display, 0,0 );
337 /* bricks&extras */
338 for ( i = 0; i < EDIT_WIDTH; i++ )
339 for ( j = 0; j < EDIT_HEIGHT; j++ )
340 editor_draw_brick( i, j );
341 /* selection frame */
342 stk_surface_blit( sel_frame, 0,0,-1,-1,
343 stk_display, edit_sel_x * BRICK_WIDTH, edit_sel_y * BRICK_HEIGHT );
344 /* status */
345 editor_draw_status();
346 /* refresh */
347 stk_display_update( STK_UPDATE_ALL );
350 ====================================================================
351 Do only redraw and refresh those bricks with an extra
352 ====================================================================
354 void editor_update_extra_bricks()
356 int i, j;
357 for ( i = 0; i < EDIT_WIDTH; i++ )
358 for ( j = 0; j < EDIT_HEIGHT; j++ )
359 if ( edit_cur_level->extras[i][j] != EX_NONE )
360 editor_draw_brick( i, j );
361 stk_display_update( STK_UPDATE_RECTS );
364 ====================================================================
365 Free all editor levels
366 ====================================================================
368 void editor_clear_levels()
370 int i;
371 for ( i = 0; i < MAX_LEVELS; i++ )
372 if ( edit_levels[i] ) level_delete( edit_levels[i] );
373 memset( edit_levels, 0, sizeof( Level* ) * MAX_LEVELS );
374 edit_level_count = 0;
377 ====================================================================
378 Save/load levels to/from editor file.
379 ====================================================================
381 void editor_load_levels()
383 int i, version, update;
384 Level *level;
385 FILE *file = 0;
386 /* clear levels first */
387 editor_clear_levels();
388 /* read levels while there are some in it */
389 edit_level_count = 0;
390 if ( ( file = fopen( edit_file_name, "rb" ) ) != 0 ) {
391 levelset_get_version( file, &version, &update );
392 sprintf( edit_version, "%i.%02i", version, update );
393 while ( ( level = level_load( file ) ) != 0 )
394 edit_levels[edit_level_count++] = level;
395 fclose( file );
397 /* if we got no level at all create an empty one */
398 if ( edit_level_count == 0 ) {
399 edit_level_count = 1;
400 edit_levels[0] = level_create_empty( _("noname"), _("untitled") );
402 /* translate the character strings to editor info */
403 for ( i = 0; i < edit_level_count; i++ )
404 editor_translate_level( edit_levels[i], CHAR_2_INDICES );
406 void editor_save_levels()
408 FILE *file = 0;
409 int i, j, k;
410 Level *level = 0;
411 /* convert */
412 for ( i = 0; i < edit_level_count; i++ )
413 editor_translate_level( edit_levels[i], INDICES_2_CHAR );
414 /* save */
415 if ( ( file = fopen( edit_file_name, "w" ) ) != 0 ) {
416 fprintf( file, "Version: %s\n", edit_version );
417 for ( i = 0; i < edit_level_count; i++ ) {
418 level = edit_levels[i];
419 /* save level */
420 fprintf( file, "Level:\n%s\n%s\nBricks:\n", level->author, level->name );
421 for ( j = 0; j < EDIT_HEIGHT; j++ ) {
422 for ( k = 0; k < EDIT_WIDTH; k++ )
423 fprintf( file, "%c", level->bricks[k][j] );
424 fprintf( file, "\n" );
426 fprintf( file, "Bonus:\n" );
427 for ( j = 0; j < EDIT_HEIGHT; j++ ) {
428 for ( k = 0; k < EDIT_WIDTH; k++ )
429 fprintf( file, "%c", level->extras[k][j] );
430 fprintf( file, "\n" );
433 fclose( file );
435 /* convert back */
436 for ( i = 0; i < edit_level_count; i++ )
437 editor_translate_level( edit_levels[i], CHAR_2_INDICES );
440 ====================================================================
441 Handle button action
442 ====================================================================
444 void editor_handle_button( int type, int *full_update ) {
445 Level *dummy_ptr;
446 int old_pos;
447 int version, update;
448 char *name, *author;
449 int i;
450 switch ( type ) {
451 case BUTTON_FIRST:
452 edit_cur_level_id = 0;
453 edit_cur_level = edit_levels[0];
454 *full_update = 1;
455 break;
456 case BUTTON_NEXT:
457 edit_cur_level_id++;
458 if ( edit_cur_level_id == edit_level_count ) edit_cur_level_id = 0;
459 edit_cur_level = edit_levels[edit_cur_level_id];
460 *full_update = 1;
461 break;
462 case BUTTON_PREV:
463 edit_cur_level_id--;
464 if ( edit_cur_level_id == -1 ) edit_cur_level_id = edit_level_count - 1;
465 edit_cur_level = edit_levels[edit_cur_level_id];
466 *full_update = 1;
467 break;
468 case BUTTON_SWAP:
469 if ( first_swap_level == -1 ) {
470 first_swap_level = edit_cur_level_id;
471 *full_update = 1;
473 else {
474 /* swap current and marked level */
475 dummy_ptr = edit_levels[first_swap_level];
476 edit_levels[first_swap_level] = edit_levels[edit_cur_level_id];
477 edit_levels[edit_cur_level_id] = dummy_ptr;
478 edit_cur_level = edit_levels[edit_cur_level_id];
479 first_swap_level = -1;
480 *full_update = 1;
482 break;
483 case BUTTON_LOAD:
484 if ( !confirm( font, _("Discard All Changes? y/n"), CONFIRM_YES_NO ) ) break;
485 /* load levels and reset position if level doesn't exist */
486 old_pos = edit_cur_level_id;
487 editor_load_levels();
488 if ( old_pos >= edit_level_count ) edit_cur_level_id = 0;
489 edit_cur_level = edit_levels[edit_cur_level_id];
490 first_swap_level = -1;
491 *full_update = 1;
492 break;
493 case BUTTON_SAVE:
494 if ( !confirm( font, _("Save Changes? y/n"), CONFIRM_YES_NO ) ) break;
495 editor_save_levels();
496 break;
497 case BUTTON_CLEAR:
498 if ( !confirm( font, _("Clear Level? y/n"), CONFIRM_YES_NO ) ) break;
499 author = strdup( edit_cur_level->author );
500 name = strdup( edit_cur_level->name );
501 level_delete( edit_levels[edit_cur_level_id] );
502 edit_levels[edit_cur_level_id] = level_create_empty( author, name );
503 edit_cur_level = edit_levels[edit_cur_level_id];
504 free( name ); free( author );
505 *full_update = 1;
506 break;
507 case BUTTON_ADD:
508 if ( edit_level_count == MAX_LEVELS ) break;
509 if ( !confirm( font, _("Add Level? y/n"), CONFIRM_YES_NO ) ) break;
510 edit_levels[edit_level_count] = level_create_empty( edit_levels[edit_level_count - 1]->author, edit_levels[edit_level_count - 1]->name );
511 edit_level_count++;
512 *full_update = 1;
513 break;
514 case BUTTON_INSERT:
515 if ( edit_level_count == MAX_LEVELS ) break;
516 if ( !confirm( font, _("Insert Level? y/n"), CONFIRM_YES_NO ) ) break;
517 for ( i = edit_level_count; i > edit_cur_level_id; i-- )
518 edit_levels[i] = edit_levels[i - 1];
519 edit_level_count++;
520 edit_levels[edit_cur_level_id] = level_create_empty( edit_cur_level->author, edit_cur_level->name );
521 edit_cur_level = edit_levels[edit_cur_level_id];
522 *full_update = 1;
523 break;
524 case BUTTON_DELETE:
525 if ( edit_level_count == 1 ) break; /* last level may not be removed */
526 if ( !confirm( font, _("Delete Level? y/n"), CONFIRM_YES_NO ) ) break;
527 level_delete( edit_levels[edit_cur_level_id] );
528 for ( i = edit_cur_level_id; i < edit_level_count - 1; i++ )
529 edit_levels[i] = edit_levels[i + 1];
530 edit_levels[i] = 0;
531 edit_level_count--;
532 if ( edit_cur_level_id >= edit_level_count )
533 edit_cur_level_id = edit_level_count - 1;
534 edit_cur_level = edit_levels[edit_cur_level_id];
535 *full_update = 1;
536 break;
537 case BUTTON_PLAY:
538 stk_display_fade( STK_FADE_OUT, STK_FADE_DEFAULT_TIME );
539 /* translate */
540 editor_translate_level( edit_cur_level, INDICES_2_CHAR );
541 /* run */
542 client_game_test_level( edit_cur_level );
543 /* translate back */
544 editor_translate_level( edit_cur_level, CHAR_2_INDICES );
545 *full_update = 1;
546 break;
547 case BUTTON_VERSION:
548 if ( enter_string( font, _("Levelset Version:"), edit_version, 8 ) ) {
549 parse_version( edit_version, &version, &update );
550 sprintf( edit_version, "%i.%02i", version, update );
551 *full_update = 1;
553 break;
557 ====================================================================
558 Handle a click on a map tile.
559 If set is False a remove action was requested (only for
560 editing)
561 ====================================================================
563 int near_grow_brick( int x, int y ) {
564 int i, j;
565 for ( i = x - 1; i <= x + 1; i++ )
566 for ( j = y - 1; j <= y + 1; j++ )
567 if ( i != x || j != y )
568 if ( i >= 0 && j >= 0 && i < EDIT_WIDTH && j < EDIT_HEIGHT )
569 if ( edit_cur_level->bricks[i][j] == GROW_BRICK_ID )
570 return 1;
571 return 0;
573 void editor_handle_click( int x, int y, int set, int *full_update )
575 int sel = 0;
576 int edit_x, edit_y;
577 char str[32];
578 /* if !set and within the tile field we perform a switch */
579 if ( !set ) {
580 if ( x >= edit_tile_x && y >= edit_tile_y && x < edit_tile_x + edit_tile_w && y < edit_tile_y + edit_tile_h ) {
581 editor_switch_tiles();
582 *full_update = 1;
583 return;
586 /* the remaining stuff requires a tile at the position */
587 if ( edit_buttons[x][y] == BUTTON_NONE ) return; /* no action */
588 /* bricks */
589 if ( edit_buttons[x][y] >= BUTTON_FIRST_BRICK && edit_buttons[x][y] <= BUTTON_LAST_BRICK ) {
590 sel = 1;
591 edit_sel_type = EDITOR_BRICK;
592 edit_sel_id = edit_buttons[x][y] - BUTTON_FIRST_BRICK;
594 /* extras */
595 if ( edit_buttons[x][y] >= BUTTON_FIRST_EXTRA && edit_buttons[x][y] <= BUTTON_LAST_EXTRA ) {
596 sel = 1;
597 edit_sel_type = EDITOR_EXTRA;
598 edit_sel_id = edit_buttons[x][y] - BUTTON_FIRST_EXTRA;
600 /* edit field */
601 if ( edit_buttons[x][y] == BUTTON_EDIT ) {
602 edit_x = x - 1;
603 edit_y = y - 1;
604 if ( edit_sel_type == EDITOR_BRICK ) {
605 if ( set ) {
606 /* set brick */
607 edit_cur_level->bricks[edit_x][edit_y] = edit_sel_id;
608 *full_update = 1;
610 else {
611 /* remove brick and extra if any */
612 if ( edit_cur_level->bricks[edit_x][edit_y] != -1 ) {
613 edit_cur_level->bricks[edit_x][edit_y] = -1;
614 edit_cur_level->extras[edit_x][edit_y] = EX_NONE;
615 *full_update = 1;
619 else {
620 if ( set ) {
621 /* set extra - must be on a brick or beside a grow brick */
622 if ( edit_cur_level->bricks[edit_x][edit_y] != -1 || near_grow_brick( edit_x, edit_y ) ) {
623 edit_cur_level->extras[edit_x][edit_y] = edit_sel_id;
624 *full_update = 1;
627 else {
628 /* remove extra */
629 if ( edit_cur_level->extras[edit_x][edit_y] != EX_NONE ) {
630 edit_cur_level->extras[edit_x][edit_y] = EX_NONE;
631 *full_update = 1;
636 /* buttons */
637 editor_handle_button( edit_buttons[x][y], full_update );
638 /* name&author */
639 strcpy( str, "" );
640 if ( edit_buttons[x][y] == BUTTON_EDIT_AUTHOR )
641 if ( enter_string( font, _("Author's Name:"), str, 24 ) ) {
642 snprintf( edit_cur_level->author, 31, "%s", str );
643 *full_update = 1;
645 if ( edit_buttons[x][y] == BUTTON_EDIT_NAME )
646 if ( enter_string( font, _("Title:"), str, 24 ) ) {
647 snprintf( edit_cur_level->name, 31, "%s", str );
648 *full_update = 1;
650 /* sel frame tile position */
651 if ( sel ) {
652 edit_sel_x = x;
653 edit_sel_y = y;
654 *full_update = 1;
659 ====================================================================
660 Publics
661 ====================================================================
664 ====================================================================
665 Create/delete editor resources
666 ====================================================================
668 void editor_create()
670 int i, j;
671 /* clear all level pointers */
672 memset( edit_levels, 0, sizeof( Level* ) * MAX_LEVELS );
673 /* load sel frame */
674 sel_frame = stk_surface_load( SDL_SWSURFACE, "sel_frame.png" );
675 /* load buttons */
676 buttons = stk_surface_load( SDL_SWSURFACE, "buttons.png" );
677 /* background is black + frame */
678 editor_bkgnd = stk_surface_create( SDL_SWSURFACE, stk_display->w, stk_display->h );
679 SDL_SetColorKey( editor_bkgnd, 0, 0 );
680 stk_surface_fill( editor_bkgnd, 0,0,-1,-1, 0x0 );
681 /* add helping grid */
682 editor_draw_grid();
683 /* set actions */
684 /* editable part */
685 for ( i = 0; i < EDIT_WIDTH; i++ )
686 for ( j = 0; j < EDIT_HEIGHT; j++ )
687 edit_buttons[i + 1][j + 1] = BUTTON_EDIT;
688 /* buttons */
689 for ( i = 0; i < 11; i++ )
690 edit_buttons[0][MAP_HEIGHT - 11 + i] = BUTTON_FIRST + i;
691 edit_buttons[MAP_WIDTH - 1][MAP_HEIGHT - 1] = BUTTON_PLAY;
692 /* name&author */
693 for ( i = 1; i < MAP_WIDTH / 2; i++ )
694 edit_buttons[i][MAP_HEIGHT - 5] = BUTTON_EDIT_NAME;
695 for ( i = MAP_WIDTH / 2; i < MAP_WIDTH - 1; i++ )
696 edit_buttons[i][MAP_HEIGHT - 5] = BUTTON_EDIT_AUTHOR;
697 /* draw buttons */
698 for ( i = 0; i < 11; i++ ) {
699 stk_surface_blit( buttons, i * BRICK_WIDTH, 0,
700 BRICK_WIDTH, BRICK_HEIGHT,
701 editor_bkgnd, 0, ( MAP_HEIGHT - 11 + i ) * BRICK_HEIGHT );
703 stk_surface_blit( buttons, 11 * BRICK_WIDTH, 0,
704 BRICK_WIDTH, BRICK_HEIGHT,
705 editor_bkgnd,
706 ( MAP_WIDTH - 1 ) * BRICK_WIDTH,
707 ( MAP_HEIGHT - 1 ) * BRICK_HEIGHT );
709 void editor_delete()
711 stk_surface_free( &editor_bkgnd );
712 stk_surface_free( &sel_frame );
713 stk_surface_free( &buttons );
716 ====================================================================
717 Initiate and clear stuff for each editor call.
718 file_name is the name of the edited file in home directory.
719 ====================================================================
721 int editor_init( char *file_name )
723 FILE *file = 0;
724 /* set full file name */
725 snprintf( edit_file_name, sizeof(edit_file_name)-1, "%s/%s/lbreakout2-levels/%s", (getenv( "HOME" )?getenv( "HOME" ):"."), CONFIG_DIR_NAME, file_name );
726 /* test this file for write access. use append to keep contents */
727 if ( ( file = fopen( edit_file_name, "a" ) ) == 0 ) {
728 fprintf( stderr, "Permission to write to file '%s' denied.\n", edit_file_name );
729 return 0;
731 else
732 fclose( file );
733 /* load levels */
734 editor_load_levels();
735 /* select first level */
736 edit_cur_level_id = 0;
737 edit_cur_level = edit_levels[0];
738 /* select first brick */
739 edit_sel_type = EDITOR_EXTRA;
740 editor_switch_tiles();
741 /* clear other flags */
742 extra_vis = 0;
743 first_swap_level = -1;
744 return 1;
746 void editor_clear()
748 /* free all levels */
749 editor_clear_levels();
752 ====================================================================
753 Run the editor
754 ====================================================================
756 void editor_run()
758 SDL_Event event;
759 int leave = 0;
760 int ms;
761 int last_switch_time = 0;
762 int full_update = 0, set;
763 int x, y, xoff,yoff;
764 Uint8 buttonstate;
766 /* reset any alpha keys */
767 SDL_SetAlpha( extra_pic, 0,0 );
768 /* draw first time */
769 editor_full_update();
770 /* main loop */
771 stk_timer_reset();
772 while ( !leave && !stk_quit_request ) {
773 if ( SDL_PollEvent( &event ) ) {
774 switch ( event.type ) {
775 case SDL_QUIT: leave = 1; stk_quit_request = 1; break;
776 case SDL_MOUSEBUTTONDOWN:
777 editor_handle_click( event.button.x / BRICK_WIDTH,
778 event.button.y / BRICK_HEIGHT,
779 (event.button.button == STK_BUTTON_LEFT),
780 &full_update );
781 break;
782 case SDL_KEYDOWN:
783 switch ( event.key.keysym.sym ) {
784 case SDLK_ESCAPE:
785 if ( confirm( font, _("Quit Editor? y/n"), CONFIRM_YES_NO ) ) leave = 1;
786 break;
787 case SDLK_LEFT: editor_handle_button( BUTTON_PREV, &full_update ); break;
788 case SDLK_RIGHT: editor_handle_button( BUTTON_NEXT, &full_update ); break;
789 case SDLK_UP: editor_handle_button( BUTTON_FIRST, &full_update ); break;
790 case SDLK_f:
791 config.fullscreen = !config.fullscreen;
792 stk_display_apply_fullscreen( config.fullscreen );
793 full_update = 1;
794 break;
795 default: break;
797 break;
798 default: break;
801 /* mouse motion is handled directly */
802 buttonstate = SDL_GetRelativeMouseState( &xoff, &yoff );
803 if ( (xoff || yoff) && buttonstate ) {
804 buttonstate = SDL_GetMouseState( &x, &y );
805 set = 0; if ( buttonstate & SDL_BUTTON(1) ) set = 1;
806 editor_handle_click( x / BRICK_WIDTH, y / BRICK_HEIGHT, set, &full_update );
808 ms = stk_timer_get_time();
809 if ( ( last_switch_time -= ms ) <= 0 ) {
810 extra_vis = !extra_vis;
811 last_switch_time = 500;
812 editor_update_extra_bricks();
814 /* full update? */
815 if ( full_update ) {
816 editor_full_update();
817 full_update = 0;
819 /* don't consume all CPU time */
820 SDL_Delay( 5 );