823 lines
31 KiB
C
823 lines
31 KiB
C
/***************************************************************************
|
|
editor.c - description
|
|
-------------------
|
|
begin : Fri Oct 12 2001
|
|
copyright : (C) 2001 by Michael Speck
|
|
email : kulkanie@gmx.net
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "lbreakout.h"
|
|
#include "../game/game.h"
|
|
#include "game.h"
|
|
#include "config.h"
|
|
#include "bricks.h"
|
|
#include "frame.h"
|
|
#include "editor.h"
|
|
|
|
SDL_Surface *sel_frame = 0, *buttons = 0;
|
|
SDL_Surface *editor_bkgnd = 0; /* background (black with frame) of editor */
|
|
char edit_file_name[512]; /* full path of edited file */
|
|
Level *edit_levels[MAX_LEVELS]; /* editor levels */
|
|
char edit_version[16]; /* version of edited set */
|
|
int edit_level_count; /* how many levels currently used? */
|
|
int edit_cur_level_id;
|
|
Level *edit_cur_level; /* current level modified */
|
|
enum { EDITOR_BRICK, EDITOR_EXTRA };
|
|
int edit_sel_type; /* type of selected tile */
|
|
int edit_sel_id; /* brick or extra id */
|
|
int edit_sel_x, edit_sel_y; /* position in map of selected tile */
|
|
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
|
|
are displayed */
|
|
int extra_vis; /* extras currently shown? blinks. */
|
|
int first_swap_level = -1; /* if not -1 this and the current level will be swapped
|
|
next time the button is pressed */
|
|
enum {
|
|
/* tiles */
|
|
BUTTON_NONE = 0,
|
|
BUTTON_FIRST_BRICK,
|
|
BUTTON_LAST_BRICK = BUTTON_FIRST_BRICK + ( BRICK_COUNT ),
|
|
BUTTON_FIRST_EXTRA,
|
|
BUTTON_LAST_EXTRA = BUTTON_FIRST_EXTRA + ( EX_NUMBER -1 ),
|
|
BUTTON_EDIT,
|
|
BUTTON_EDIT_AUTHOR,
|
|
BUTTON_EDIT_NAME,
|
|
/* buttons */
|
|
BUTTON_FIRST,
|
|
BUTTON_NEXT,
|
|
BUTTON_PREV,
|
|
BUTTON_CLEAR,
|
|
BUTTON_SWAP,
|
|
BUTTON_ADD,
|
|
BUTTON_INSERT,
|
|
BUTTON_DELETE,
|
|
BUTTON_VERSION,
|
|
BUTTON_LOAD,
|
|
BUTTON_SAVE,
|
|
BUTTON_PLAY
|
|
};
|
|
int edit_buttons[MAP_WIDTH][MAP_HEIGHT]; /* an action is assigned to each map tile */
|
|
/* externals */
|
|
extern SDL_Surface *stk_display;
|
|
extern SDL_Surface *frame;
|
|
extern SDL_Surface *extra_pic;
|
|
extern SDL_Surface *brick_pic;
|
|
extern StkFont *mfont; /* use menu's font to draw status */
|
|
extern StkFont *font; /* use game's font to confirm */
|
|
extern Config config;
|
|
extern int stk_quit_request;
|
|
|
|
/* extra conversion table may be found in bricks.c */
|
|
extern Extra_Conv extra_conv_table[EX_NUMBER];
|
|
extern Brick_Conv brick_conv_table[BRICK_COUNT];
|
|
|
|
/*
|
|
====================================================================
|
|
Locals
|
|
====================================================================
|
|
*/
|
|
|
|
/*
|
|
====================================================================
|
|
We had a right click into the tile region so check and change the
|
|
bricks displayed there. We select the first new tile and set
|
|
edit_sel_id, edit_sel_x, edit_sel_y. The full update is initated
|
|
by editor_handle_click().
|
|
====================================================================
|
|
*/
|
|
void editor_switch_tiles()
|
|
{
|
|
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 */
|
|
int i, j;
|
|
/* clear edit buttons */
|
|
for ( i = edit_tile_x; i < edit_tile_x + edit_tile_w; i++ )
|
|
for ( j = edit_tile_y; j < edit_tile_y + edit_tile_h; j++ )
|
|
edit_buttons[i][j] = BUTTON_NONE;
|
|
/* clear this part of the editor bkjgnd */
|
|
stk_surface_fill( editor_bkgnd,
|
|
edit_tile_x * BRICK_WIDTH, edit_tile_y * BRICK_HEIGHT,
|
|
edit_tile_w * BRICK_WIDTH, edit_tile_h * BRICK_HEIGHT, 0x0 );
|
|
/* switch */
|
|
if ( edit_sel_type == EDITOR_BRICK ) {
|
|
/* flag */
|
|
edit_sel_type = EDITOR_EXTRA;
|
|
/* button map & background */
|
|
i = 0; j = 0;
|
|
while ( i + j * len < EX_NUMBER ) {
|
|
edit_buttons[x_off + i][y_off + j] = BUTTON_FIRST_EXTRA + i + j * len;
|
|
stk_surface_blit( extra_pic, ( i + j * len ) * BRICK_WIDTH, 0,
|
|
BRICK_WIDTH, BRICK_HEIGHT,
|
|
editor_bkgnd, ( i + x_off ) * BRICK_WIDTH, ( j + y_off ) * BRICK_HEIGHT );
|
|
i++;
|
|
if ( i == len ) {
|
|
i = 0;
|
|
j++;
|
|
}
|
|
}
|
|
/* select first tile */
|
|
edit_sel_id = 0;
|
|
edit_sel_x = x_off;
|
|
edit_sel_y = y_off;
|
|
}
|
|
else {
|
|
/* flag */
|
|
edit_sel_type = EDITOR_BRICK;
|
|
/* button map & background */
|
|
i = 0; j = 0;
|
|
while ( i + j * len < BRICK_COUNT ) {
|
|
edit_buttons[x_off + i][y_off + j] = BUTTON_FIRST_BRICK + i + j * len;
|
|
stk_surface_blit( brick_pic, ( i + j * len ) * BRICK_WIDTH, 0,
|
|
BRICK_WIDTH, BRICK_HEIGHT,
|
|
editor_bkgnd, ( i + x_off ) * BRICK_WIDTH, ( j + y_off ) * BRICK_HEIGHT );
|
|
i++;
|
|
if ( i == len ) {
|
|
i = 0;
|
|
j++;
|
|
}
|
|
}
|
|
/* select first tile */
|
|
edit_sel_id = 0;
|
|
edit_sel_x = x_off;
|
|
edit_sel_y = y_off;
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================================================================
|
|
Draw a helping grid.
|
|
====================================================================
|
|
*/
|
|
void editor_draw_grid()
|
|
{
|
|
SDL_Surface *buffer;
|
|
int i, alpha;
|
|
buffer = stk_surface_create( SDL_SWSURFACE, EDIT_WIDTH * BRICK_WIDTH, 1 );
|
|
stk_surface_fill( buffer, 0,0,-1,-1, 0xffffff );
|
|
stk_surface_blit( buffer, 0,0,-1,-1, editor_bkgnd, BRICK_WIDTH, BRICK_HEIGHT );
|
|
stk_surface_blit( buffer, 0,0,-1,-1, editor_bkgnd, BRICK_WIDTH,
|
|
( EDIT_HEIGHT + 1 ) * BRICK_HEIGHT - 1 );
|
|
for ( i = 0; i < EDIT_HEIGHT - 1; i++ ) {
|
|
if ( i == EDIT_HEIGHT / 2 - 1 )
|
|
alpha = 192;
|
|
else
|
|
if ( i % (EDIT_HEIGHT/4) == 0 )
|
|
alpha = 128;
|
|
else
|
|
alpha = 64;
|
|
stk_surface_alpha_blit( buffer, 0,0,-1,-1, editor_bkgnd,
|
|
BRICK_WIDTH, ( i + 1 ) * BRICK_HEIGHT + BRICK_HEIGHT - 1,
|
|
alpha );
|
|
}
|
|
SDL_FreeSurface( buffer );
|
|
buffer = stk_surface_create( SDL_SWSURFACE, 1, EDIT_HEIGHT * BRICK_HEIGHT );
|
|
stk_surface_fill( buffer, 0,0,-1,-1, 0xffffff );
|
|
stk_surface_blit( buffer, 0,0,-1,-1, editor_bkgnd, BRICK_WIDTH, BRICK_HEIGHT );
|
|
stk_surface_blit( buffer, 0,0,-1,-1, editor_bkgnd,
|
|
( EDIT_WIDTH + 1 ) * BRICK_WIDTH - 1, BRICK_HEIGHT );
|
|
for ( i = 0; i < EDIT_WIDTH - 1; i++ ) {
|
|
if ( i == EDIT_WIDTH / 2 - 1 )
|
|
alpha = 192;
|
|
else
|
|
if ( i % (EDIT_WIDTH/4) == 0 )
|
|
alpha = 128;
|
|
else
|
|
alpha = 64;
|
|
stk_surface_alpha_blit( buffer, 0,0,-1,-1, editor_bkgnd,
|
|
( i + 1 ) * BRICK_WIDTH + BRICK_WIDTH- 1, BRICK_HEIGHT,
|
|
alpha );
|
|
}
|
|
SDL_FreeSurface( buffer );
|
|
}
|
|
|
|
/*
|
|
====================================================================
|
|
Translate the saved character strings into extra and brick indices
|
|
for the editor.
|
|
====================================================================
|
|
*/
|
|
enum { INDICES_2_CHAR, CHAR_2_INDICES };
|
|
void editor_translate_level( Level *level, int type )
|
|
{
|
|
int i, j, k;
|
|
if ( type == CHAR_2_INDICES ) {
|
|
for ( i = 0; i < EDIT_WIDTH; i++ )
|
|
for ( j = 0; j < EDIT_HEIGHT; j++ ) {
|
|
/* bricks */
|
|
for ( k = 0; k < BRICK_COUNT; k++ )
|
|
if ( brick_conv_table[k].c == level->bricks[i][j] ) {
|
|
level->bricks[i][j] = brick_conv_table[k].id;
|
|
break;
|
|
}
|
|
if ( k == BRICK_COUNT ) level->bricks[i][j] = -1;
|
|
/* extras */
|
|
for ( k = 0; k < EX_NUMBER; k++ )
|
|
if ( extra_conv_table[k].c == level->extras[i][j] ) {
|
|
level->extras[i][j] = extra_conv_table[k].type;
|
|
break;
|
|
}
|
|
if ( k == EX_NUMBER ) level->extras[i][j] = EX_NONE;
|
|
}
|
|
}
|
|
else {
|
|
/* indices to characters */
|
|
for ( i = 0; i < EDIT_WIDTH; i++ )
|
|
for ( j = 0; j < EDIT_HEIGHT; j++ ) {
|
|
/* bricks */
|
|
if ( level->bricks[i][j] == -1 )
|
|
level->bricks[i][j] = '.';
|
|
else
|
|
for ( k = 0; k < BRICK_COUNT; k++ )
|
|
if ( level->bricks[i][j] == brick_conv_table[k].id ) {
|
|
level->bricks[i][j] = brick_conv_table[k].c;
|
|
break;
|
|
}
|
|
/* extras */
|
|
if ( level->extras[i][j] == EX_NONE )
|
|
level->extras[i][j] = '.';
|
|
else
|
|
for ( k = 0; k < EX_NUMBER; k++ )
|
|
if ( level->extras[i][j] == extra_conv_table[k].type ) {
|
|
level->extras[i][j] = extra_conv_table[k].c;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
====================================================================
|
|
Draw name of set file, current level, current count, remaining
|
|
levels, and other info stuff.
|
|
====================================================================
|
|
*/
|
|
void editor_draw_status()
|
|
{
|
|
char str[512];
|
|
int x = BRICK_WIDTH, y = ( MAP_HEIGHT - 1 ) * BRICK_HEIGHT - 2;
|
|
int height = 10;
|
|
/* locartion */
|
|
sprintf( str, _("Location: %s"), edit_file_name );
|
|
mfont->align = STK_FONT_ALIGN_LEFT | STK_FONT_ALIGN_TOP;
|
|
stk_font_write( mfont, stk_display, x, y, STK_OPAQUE, str );
|
|
/* current level */
|
|
sprintf( str, _("Current Level: %i/%i (Free: %i)"), edit_cur_level_id + 1, edit_level_count, MAX_LEVELS - edit_level_count );
|
|
mfont->align = STK_FONT_ALIGN_LEFT | STK_FONT_ALIGN_TOP;
|
|
stk_font_write( mfont, stk_display, x, y + height, STK_OPAQUE, str );
|
|
/* swap */
|
|
mfont->align = STK_FONT_ALIGN_RIGHT | STK_FONT_ALIGN_TOP;
|
|
if ( first_swap_level != -1 ) {
|
|
sprintf( str, _("*** Level %i Marked For Swap ***"), first_swap_level + 1 );
|
|
stk_font_write( mfont, stk_display, stk_display->w - BRICK_WIDTH, y + height, STK_OPAQUE, str );
|
|
}
|
|
else {
|
|
/* version */
|
|
sprintf( str, _("Version: %s "), edit_version );
|
|
stk_font_write( mfont, stk_display, stk_display->w - BRICK_WIDTH, y + height, STK_OPAQUE, str );
|
|
}
|
|
/* name and author */
|
|
mfont->align = STK_FONT_ALIGN_LEFT | STK_FONT_ALIGN_TOP;
|
|
sprintf( str, _("Title: %s"), edit_cur_level->name );
|
|
stk_font_write( mfont, stk_display, BRICK_WIDTH + 2, ( MAP_HEIGHT - 5 ) * BRICK_HEIGHT + 5, STK_OPAQUE, str );
|
|
mfont->align = STK_FONT_ALIGN_RIGHT | STK_FONT_ALIGN_TOP;
|
|
sprintf( str, _("Author: %s"), edit_cur_level->author );
|
|
stk_font_write( mfont, stk_display, stk_display->w - BRICK_WIDTH - 2, ( MAP_HEIGHT - 5 ) * BRICK_HEIGHT + 5, STK_OPAQUE, str );
|
|
}
|
|
/*
|
|
====================================================================
|
|
Draw brick and extra (if any) from screen map pos
|
|
so it fits the editable field (no frame, no bottom).
|
|
====================================================================
|
|
*/
|
|
void editor_draw_brick( int edit_map_x, int edit_map_y )
|
|
{
|
|
/* brick */
|
|
if ( edit_cur_level->bricks[edit_map_x][edit_map_y] != -1 ) {
|
|
if ( edit_cur_level->bricks[edit_map_x][edit_map_y] != INVIS_BRICK_ID )
|
|
stk_surface_blit( brick_pic,
|
|
edit_cur_level->bricks[edit_map_x][edit_map_y] * BRICK_WIDTH, 0,
|
|
BRICK_WIDTH, BRICK_HEIGHT,
|
|
stk_display, (edit_map_x + 1) * BRICK_WIDTH, (edit_map_y + 1) * BRICK_HEIGHT );
|
|
else
|
|
stk_surface_fill( stk_display,
|
|
(edit_map_x + 1) * BRICK_WIDTH, (edit_map_y + 1) * BRICK_HEIGHT,
|
|
BRICK_WIDTH, BRICK_HEIGHT, 0x777777 );
|
|
}
|
|
else {
|
|
stk_surface_blit( editor_bkgnd,
|
|
(edit_map_x + 1) * BRICK_WIDTH, (edit_map_y + 1) * BRICK_HEIGHT,
|
|
BRICK_WIDTH, BRICK_HEIGHT, stk_display,
|
|
(edit_map_x + 1) * BRICK_WIDTH, (edit_map_y + 1) * BRICK_HEIGHT );
|
|
}
|
|
/* extra */
|
|
if ( ( extra_vis || edit_sel_type == EDITOR_EXTRA ) && edit_cur_level->extras[edit_map_x][edit_map_y] != EX_NONE) {
|
|
stk_surface_blit( extra_pic,
|
|
( edit_cur_level->extras[edit_map_x][edit_map_y] ) * BRICK_WIDTH, 0,
|
|
BRICK_WIDTH, BRICK_HEIGHT,
|
|
stk_display, (edit_map_x + 1) * BRICK_WIDTH, (edit_map_y + 1) * BRICK_HEIGHT );
|
|
}
|
|
stk_display_store_drect();
|
|
}
|
|
/*
|
|
====================================================================
|
|
Redraw and refresh full screen
|
|
====================================================================
|
|
*/
|
|
void editor_full_update()
|
|
{
|
|
int i, j;
|
|
/* background */
|
|
stk_surface_blit( editor_bkgnd, 0,0,-1,-1, stk_display, 0,0 );
|
|
/* bricks&extras */
|
|
for ( i = 0; i < EDIT_WIDTH; i++ )
|
|
for ( j = 0; j < EDIT_HEIGHT; j++ )
|
|
editor_draw_brick( i, j );
|
|
/* selection frame */
|
|
stk_surface_blit( sel_frame, 0,0,-1,-1,
|
|
stk_display, edit_sel_x * BRICK_WIDTH, edit_sel_y * BRICK_HEIGHT );
|
|
/* status */
|
|
editor_draw_status();
|
|
/* refresh */
|
|
stk_display_update( STK_UPDATE_ALL );
|
|
}
|
|
/*
|
|
====================================================================
|
|
Do only redraw and refresh those bricks with an extra
|
|
====================================================================
|
|
*/
|
|
void editor_update_extra_bricks()
|
|
{
|
|
int i, j;
|
|
for ( i = 0; i < EDIT_WIDTH; i++ )
|
|
for ( j = 0; j < EDIT_HEIGHT; j++ )
|
|
if ( edit_cur_level->extras[i][j] != EX_NONE )
|
|
editor_draw_brick( i, j );
|
|
stk_display_update( STK_UPDATE_RECTS );
|
|
}
|
|
/*
|
|
====================================================================
|
|
Free all editor levels
|
|
====================================================================
|
|
*/
|
|
void editor_clear_levels()
|
|
{
|
|
int i;
|
|
for ( i = 0; i < MAX_LEVELS; i++ )
|
|
if ( edit_levels[i] ) level_delete( edit_levels[i] );
|
|
memset( edit_levels, 0, sizeof( Level* ) * MAX_LEVELS );
|
|
edit_level_count = 0;
|
|
}
|
|
/*
|
|
====================================================================
|
|
Save/load levels to/from editor file.
|
|
====================================================================
|
|
*/
|
|
void editor_load_levels()
|
|
{
|
|
int i, version, update;
|
|
Level *level;
|
|
FILE *file = 0;
|
|
/* clear levels first */
|
|
editor_clear_levels();
|
|
/* read levels while there are some in it */
|
|
edit_level_count = 0;
|
|
if ( ( file = fopen( edit_file_name, "rb" ) ) != 0 ) {
|
|
levelset_get_version( file, &version, &update );
|
|
sprintf( edit_version, "%i.%02i", version, update );
|
|
while ( ( level = level_load( file ) ) != 0 )
|
|
edit_levels[edit_level_count++] = level;
|
|
fclose( file );
|
|
}
|
|
/* if we got no level at all create an empty one */
|
|
if ( edit_level_count == 0 ) {
|
|
edit_level_count = 1;
|
|
edit_levels[0] = level_create_empty( _("noname"), _("untitled") );
|
|
}
|
|
/* translate the character strings to editor info */
|
|
for ( i = 0; i < edit_level_count; i++ )
|
|
editor_translate_level( edit_levels[i], CHAR_2_INDICES );
|
|
}
|
|
void editor_save_levels()
|
|
{
|
|
FILE *file = 0;
|
|
int i, j, k;
|
|
Level *level = 0;
|
|
/* convert */
|
|
for ( i = 0; i < edit_level_count; i++ )
|
|
editor_translate_level( edit_levels[i], INDICES_2_CHAR );
|
|
/* save */
|
|
if ( ( file = fopen( edit_file_name, "w" ) ) != 0 ) {
|
|
fprintf( file, "Version: %s\n", edit_version );
|
|
for ( i = 0; i < edit_level_count; i++ ) {
|
|
level = edit_levels[i];
|
|
/* save level */
|
|
fprintf( file, "Level:\n%s\n%s\nBricks:\n", level->author, level->name );
|
|
for ( j = 0; j < EDIT_HEIGHT; j++ ) {
|
|
for ( k = 0; k < EDIT_WIDTH; k++ )
|
|
fprintf( file, "%c", level->bricks[k][j] );
|
|
fprintf( file, "\n" );
|
|
}
|
|
fprintf( file, "Bonus:\n" );
|
|
for ( j = 0; j < EDIT_HEIGHT; j++ ) {
|
|
for ( k = 0; k < EDIT_WIDTH; k++ )
|
|
fprintf( file, "%c", level->extras[k][j] );
|
|
fprintf( file, "\n" );
|
|
}
|
|
}
|
|
fclose( file );
|
|
}
|
|
/* convert back */
|
|
for ( i = 0; i < edit_level_count; i++ )
|
|
editor_translate_level( edit_levels[i], CHAR_2_INDICES );
|
|
}
|
|
/*
|
|
====================================================================
|
|
Handle button action
|
|
====================================================================
|
|
*/
|
|
void editor_handle_button( int type, int *full_update ) {
|
|
Level *dummy_ptr;
|
|
int old_pos;
|
|
int version, update;
|
|
char *name, *author;
|
|
int i;
|
|
switch ( type ) {
|
|
case BUTTON_FIRST:
|
|
edit_cur_level_id = 0;
|
|
edit_cur_level = edit_levels[0];
|
|
*full_update = 1;
|
|
break;
|
|
case BUTTON_NEXT:
|
|
edit_cur_level_id++;
|
|
if ( edit_cur_level_id == edit_level_count ) edit_cur_level_id = 0;
|
|
edit_cur_level = edit_levels[edit_cur_level_id];
|
|
*full_update = 1;
|
|
break;
|
|
case BUTTON_PREV:
|
|
edit_cur_level_id--;
|
|
if ( edit_cur_level_id == -1 ) edit_cur_level_id = edit_level_count - 1;
|
|
edit_cur_level = edit_levels[edit_cur_level_id];
|
|
*full_update = 1;
|
|
break;
|
|
case BUTTON_SWAP:
|
|
if ( first_swap_level == -1 ) {
|
|
first_swap_level = edit_cur_level_id;
|
|
*full_update = 1;
|
|
}
|
|
else {
|
|
/* swap current and marked level */
|
|
dummy_ptr = edit_levels[first_swap_level];
|
|
edit_levels[first_swap_level] = edit_levels[edit_cur_level_id];
|
|
edit_levels[edit_cur_level_id] = dummy_ptr;
|
|
edit_cur_level = edit_levels[edit_cur_level_id];
|
|
first_swap_level = -1;
|
|
*full_update = 1;
|
|
}
|
|
break;
|
|
case BUTTON_LOAD:
|
|
if ( !confirm( font, _("Discard All Changes? y/n"), CONFIRM_YES_NO ) ) break;
|
|
/* load levels and reset position if level doesn't exist */
|
|
old_pos = edit_cur_level_id;
|
|
editor_load_levels();
|
|
if ( old_pos >= edit_level_count ) edit_cur_level_id = 0;
|
|
edit_cur_level = edit_levels[edit_cur_level_id];
|
|
first_swap_level = -1;
|
|
*full_update = 1;
|
|
break;
|
|
case BUTTON_SAVE:
|
|
if ( !confirm( font, _("Save Changes? y/n"), CONFIRM_YES_NO ) ) break;
|
|
editor_save_levels();
|
|
break;
|
|
case BUTTON_CLEAR:
|
|
if ( !confirm( font, _("Clear Level? y/n"), CONFIRM_YES_NO ) ) break;
|
|
author = strdup( edit_cur_level->author );
|
|
name = strdup( edit_cur_level->name );
|
|
level_delete( edit_levels[edit_cur_level_id] );
|
|
edit_levels[edit_cur_level_id] = level_create_empty( author, name );
|
|
edit_cur_level = edit_levels[edit_cur_level_id];
|
|
free( name ); free( author );
|
|
*full_update = 1;
|
|
break;
|
|
case BUTTON_ADD:
|
|
if ( edit_level_count == MAX_LEVELS ) break;
|
|
if ( !confirm( font, _("Add Level? y/n"), CONFIRM_YES_NO ) ) break;
|
|
edit_levels[edit_level_count] = level_create_empty( edit_levels[edit_level_count - 1]->author, edit_levels[edit_level_count - 1]->name );
|
|
edit_level_count++;
|
|
*full_update = 1;
|
|
break;
|
|
case BUTTON_INSERT:
|
|
if ( edit_level_count == MAX_LEVELS ) break;
|
|
if ( !confirm( font, _("Insert Level? y/n"), CONFIRM_YES_NO ) ) break;
|
|
for ( i = edit_level_count; i > edit_cur_level_id; i-- )
|
|
edit_levels[i] = edit_levels[i - 1];
|
|
edit_level_count++;
|
|
edit_levels[edit_cur_level_id] = level_create_empty( edit_cur_level->author, edit_cur_level->name );
|
|
edit_cur_level = edit_levels[edit_cur_level_id];
|
|
*full_update = 1;
|
|
break;
|
|
case BUTTON_DELETE:
|
|
if ( edit_level_count == 1 ) break; /* last level may not be removed */
|
|
if ( !confirm( font, _("Delete Level? y/n"), CONFIRM_YES_NO ) ) break;
|
|
level_delete( edit_levels[edit_cur_level_id] );
|
|
for ( i = edit_cur_level_id; i < edit_level_count - 1; i++ )
|
|
edit_levels[i] = edit_levels[i + 1];
|
|
edit_levels[i] = 0;
|
|
edit_level_count--;
|
|
if ( edit_cur_level_id >= edit_level_count )
|
|
edit_cur_level_id = edit_level_count - 1;
|
|
edit_cur_level = edit_levels[edit_cur_level_id];
|
|
*full_update = 1;
|
|
break;
|
|
case BUTTON_PLAY:
|
|
stk_display_fade( STK_FADE_OUT, STK_FADE_DEFAULT_TIME );
|
|
/* translate */
|
|
editor_translate_level( edit_cur_level, INDICES_2_CHAR );
|
|
/* run */
|
|
client_game_test_level( edit_cur_level );
|
|
/* translate back */
|
|
editor_translate_level( edit_cur_level, CHAR_2_INDICES );
|
|
*full_update = 1;
|
|
break;
|
|
case BUTTON_VERSION:
|
|
if ( enter_string( font, _("Levelset Version:"), edit_version, 8 ) ) {
|
|
parse_version( edit_version, &version, &update );
|
|
sprintf( edit_version, "%i.%02i", version, update );
|
|
*full_update = 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
====================================================================
|
|
Handle a click on a map tile.
|
|
If set is False a remove action was requested (only for
|
|
editing)
|
|
====================================================================
|
|
*/
|
|
int near_grow_brick( int x, int y ) {
|
|
int i, j;
|
|
for ( i = x - 1; i <= x + 1; i++ )
|
|
for ( j = y - 1; j <= y + 1; j++ )
|
|
if ( i != x || j != y )
|
|
if ( i >= 0 && j >= 0 && i < EDIT_WIDTH && j < EDIT_HEIGHT )
|
|
if ( edit_cur_level->bricks[i][j] == GROW_BRICK_ID )
|
|
return 1;
|
|
return 0;
|
|
}
|
|
void editor_handle_click( int x, int y, int set, int *full_update )
|
|
{
|
|
int sel = 0;
|
|
int edit_x, edit_y;
|
|
char str[32];
|
|
/* if !set and within the tile field we perform a switch */
|
|
if ( !set ) {
|
|
if ( x >= edit_tile_x && y >= edit_tile_y && x < edit_tile_x + edit_tile_w && y < edit_tile_y + edit_tile_h ) {
|
|
editor_switch_tiles();
|
|
*full_update = 1;
|
|
return;
|
|
}
|
|
}
|
|
/* the remaining stuff requires a tile at the position */
|
|
if ( edit_buttons[x][y] == BUTTON_NONE ) return; /* no action */
|
|
/* bricks */
|
|
if ( edit_buttons[x][y] >= BUTTON_FIRST_BRICK && edit_buttons[x][y] <= BUTTON_LAST_BRICK ) {
|
|
sel = 1;
|
|
edit_sel_type = EDITOR_BRICK;
|
|
edit_sel_id = edit_buttons[x][y] - BUTTON_FIRST_BRICK;
|
|
}
|
|
/* extras */
|
|
if ( edit_buttons[x][y] >= BUTTON_FIRST_EXTRA && edit_buttons[x][y] <= BUTTON_LAST_EXTRA ) {
|
|
sel = 1;
|
|
edit_sel_type = EDITOR_EXTRA;
|
|
edit_sel_id = edit_buttons[x][y] - BUTTON_FIRST_EXTRA;
|
|
}
|
|
/* edit field */
|
|
if ( edit_buttons[x][y] == BUTTON_EDIT ) {
|
|
edit_x = x - 1;
|
|
edit_y = y - 1;
|
|
if ( edit_sel_type == EDITOR_BRICK ) {
|
|
if ( set ) {
|
|
/* set brick */
|
|
edit_cur_level->bricks[edit_x][edit_y] = edit_sel_id;
|
|
*full_update = 1;
|
|
}
|
|
else {
|
|
/* remove brick and extra if any */
|
|
if ( edit_cur_level->bricks[edit_x][edit_y] != -1 ) {
|
|
edit_cur_level->bricks[edit_x][edit_y] = -1;
|
|
edit_cur_level->extras[edit_x][edit_y] = EX_NONE;
|
|
*full_update = 1;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if ( set ) {
|
|
/* set extra - must be on a brick or beside a grow brick */
|
|
if ( edit_cur_level->bricks[edit_x][edit_y] != -1 || near_grow_brick( edit_x, edit_y ) ) {
|
|
edit_cur_level->extras[edit_x][edit_y] = edit_sel_id;
|
|
*full_update = 1;
|
|
}
|
|
}
|
|
else {
|
|
/* remove extra */
|
|
if ( edit_cur_level->extras[edit_x][edit_y] != EX_NONE ) {
|
|
edit_cur_level->extras[edit_x][edit_y] = EX_NONE;
|
|
*full_update = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* buttons */
|
|
editor_handle_button( edit_buttons[x][y], full_update );
|
|
/* name&author */
|
|
strcpy( str, "" );
|
|
if ( edit_buttons[x][y] == BUTTON_EDIT_AUTHOR )
|
|
if ( enter_string( font, _("Author's Name:"), str, 24 ) ) {
|
|
snprintf( edit_cur_level->author, 31, "%s", str );
|
|
*full_update = 1;
|
|
}
|
|
if ( edit_buttons[x][y] == BUTTON_EDIT_NAME )
|
|
if ( enter_string( font, _("Title:"), str, 24 ) ) {
|
|
snprintf( edit_cur_level->name, 31, "%s", str );
|
|
*full_update = 1;
|
|
}
|
|
/* sel frame tile position */
|
|
if ( sel ) {
|
|
edit_sel_x = x;
|
|
edit_sel_y = y;
|
|
*full_update = 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================================================================
|
|
Publics
|
|
====================================================================
|
|
*/
|
|
/*
|
|
====================================================================
|
|
Create/delete editor resources
|
|
====================================================================
|
|
*/
|
|
void editor_create()
|
|
{
|
|
int i, j;
|
|
/* clear all level pointers */
|
|
memset( edit_levels, 0, sizeof( Level* ) * MAX_LEVELS );
|
|
/* load sel frame */
|
|
sel_frame = stk_surface_load( SDL_SWSURFACE, "sel_frame.png" );
|
|
/* load buttons */
|
|
buttons = stk_surface_load( SDL_SWSURFACE, "buttons.png" );
|
|
/* background is black + frame */
|
|
editor_bkgnd = stk_surface_create( SDL_SWSURFACE, stk_display->w, stk_display->h );
|
|
SDL_SetColorKey( editor_bkgnd, 0, 0 );
|
|
stk_surface_fill( editor_bkgnd, 0,0,-1,-1, 0x0 );
|
|
/* add helping grid */
|
|
editor_draw_grid();
|
|
/* set actions */
|
|
/* editable part */
|
|
for ( i = 0; i < EDIT_WIDTH; i++ )
|
|
for ( j = 0; j < EDIT_HEIGHT; j++ )
|
|
edit_buttons[i + 1][j + 1] = BUTTON_EDIT;
|
|
/* buttons */
|
|
for ( i = 0; i < 11; i++ )
|
|
edit_buttons[0][MAP_HEIGHT - 11 + i] = BUTTON_FIRST + i;
|
|
edit_buttons[MAP_WIDTH - 1][MAP_HEIGHT - 1] = BUTTON_PLAY;
|
|
/* name&author */
|
|
for ( i = 1; i < MAP_WIDTH / 2; i++ )
|
|
edit_buttons[i][MAP_HEIGHT - 5] = BUTTON_EDIT_NAME;
|
|
for ( i = MAP_WIDTH / 2; i < MAP_WIDTH - 1; i++ )
|
|
edit_buttons[i][MAP_HEIGHT - 5] = BUTTON_EDIT_AUTHOR;
|
|
/* draw buttons */
|
|
for ( i = 0; i < 11; i++ ) {
|
|
stk_surface_blit( buttons, i * BRICK_WIDTH, 0,
|
|
BRICK_WIDTH, BRICK_HEIGHT,
|
|
editor_bkgnd, 0, ( MAP_HEIGHT - 11 + i ) * BRICK_HEIGHT );
|
|
}
|
|
stk_surface_blit( buttons, 11 * BRICK_WIDTH, 0,
|
|
BRICK_WIDTH, BRICK_HEIGHT,
|
|
editor_bkgnd,
|
|
( MAP_WIDTH - 1 ) * BRICK_WIDTH,
|
|
( MAP_HEIGHT - 1 ) * BRICK_HEIGHT );
|
|
}
|
|
void editor_delete()
|
|
{
|
|
stk_surface_free( &editor_bkgnd );
|
|
stk_surface_free( &sel_frame );
|
|
stk_surface_free( &buttons );
|
|
}
|
|
/*
|
|
====================================================================
|
|
Initiate and clear stuff for each editor call.
|
|
file_name is the name of the edited file in home directory.
|
|
====================================================================
|
|
*/
|
|
int editor_init( char *file_name )
|
|
{
|
|
FILE *file = 0;
|
|
/* set full file name */
|
|
snprintf( edit_file_name, sizeof(edit_file_name)-1, "%s/%s/lbreakout2-levels/%s", (getenv( "HOME" )?getenv( "HOME" ):"."), CONFIG_DIR_NAME, file_name );
|
|
/* test this file for write access. use append to keep contents */
|
|
if ( ( file = fopen( edit_file_name, "a" ) ) == 0 ) {
|
|
fprintf( stderr, "Permission to write to file '%s' denied.\n", edit_file_name );
|
|
return 0;
|
|
}
|
|
else
|
|
fclose( file );
|
|
/* load levels */
|
|
editor_load_levels();
|
|
/* select first level */
|
|
edit_cur_level_id = 0;
|
|
edit_cur_level = edit_levels[0];
|
|
/* select first brick */
|
|
edit_sel_type = EDITOR_EXTRA;
|
|
editor_switch_tiles();
|
|
/* clear other flags */
|
|
extra_vis = 0;
|
|
first_swap_level = -1;
|
|
return 1;
|
|
}
|
|
void editor_clear()
|
|
{
|
|
/* free all levels */
|
|
editor_clear_levels();
|
|
}
|
|
/*
|
|
====================================================================
|
|
Run the editor
|
|
====================================================================
|
|
*/
|
|
void editor_run()
|
|
{
|
|
SDL_Event event;
|
|
int leave = 0;
|
|
int ms;
|
|
int last_switch_time = 0;
|
|
int full_update = 0, set;
|
|
int x, y, xoff,yoff;
|
|
Uint8 buttonstate;
|
|
|
|
/* reset any alpha keys */
|
|
SDL_SetAlpha( extra_pic, 0,0 );
|
|
/* draw first time */
|
|
editor_full_update();
|
|
/* main loop */
|
|
stk_timer_reset();
|
|
while ( !leave && !stk_quit_request ) {
|
|
if ( SDL_PollEvent( &event ) ) {
|
|
switch ( event.type ) {
|
|
case SDL_QUIT: leave = 1; stk_quit_request = 1; break;
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
editor_handle_click( event.button.x / BRICK_WIDTH,
|
|
event.button.y / BRICK_HEIGHT,
|
|
(event.button.button == STK_BUTTON_LEFT),
|
|
&full_update );
|
|
break;
|
|
case SDL_KEYDOWN:
|
|
switch ( event.key.keysym.sym ) {
|
|
case SDLK_ESCAPE:
|
|
if ( confirm( font, _("Quit Editor? y/n"), CONFIRM_YES_NO ) ) leave = 1;
|
|
break;
|
|
case SDLK_LEFT: editor_handle_button( BUTTON_PREV, &full_update ); break;
|
|
case SDLK_RIGHT: editor_handle_button( BUTTON_NEXT, &full_update ); break;
|
|
case SDLK_UP: editor_handle_button( BUTTON_FIRST, &full_update ); break;
|
|
case SDLK_f:
|
|
config.fullscreen = !config.fullscreen;
|
|
stk_display_apply_fullscreen( config.fullscreen );
|
|
full_update = 1;
|
|
break;
|
|
default: break;
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
/* mouse motion is handled directly */
|
|
buttonstate = SDL_GetRelativeMouseState( &xoff, &yoff );
|
|
if ( (xoff || yoff) && buttonstate ) {
|
|
buttonstate = SDL_GetMouseState( &x, &y );
|
|
set = 0; if ( buttonstate & SDL_BUTTON(1) ) set = 1;
|
|
editor_handle_click( x / BRICK_WIDTH, y / BRICK_HEIGHT, set, &full_update );
|
|
}
|
|
ms = stk_timer_get_time();
|
|
if ( ( last_switch_time -= ms ) <= 0 ) {
|
|
extra_vis = !extra_vis;
|
|
last_switch_time = 500;
|
|
editor_update_extra_bricks();
|
|
}
|
|
/* full update? */
|
|
if ( full_update ) {
|
|
editor_full_update();
|
|
full_update = 0;
|
|
}
|
|
/* don't consume all CPU time */
|
|
SDL_Delay( 5 );
|
|
}
|
|
}
|