/* * This file is part of the Atomiks project * Copyright (C) Mateusz Viste 2013, 2014, 2015 * * Level editor for Atomiks * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include /* atoi(), malloc(), free() */ #include #include "atomcore.h" #include "data.h" #include "drv_gra.h" static void savelevel(struct atomixgame *game, int level) { char levelfile[64]; FILE *fd; int x, y; sprintf(levelfile, "lev/lev%04d.dat", level); fd = fopen(levelfile, "wb"); if (fd == NULL) return; /* write initial playfield */ for (y = 0; y < 16; y++) { for (x = 0; x < 16; x++) { fputc(game->field[x][y], fd); } } /* write solution */ for (y = 0; y < 16; y++) { for (x = 0; x < 16; x++) { fputc(game->solution[x][y], fd); } } /* write the timer */ fputc((game->duration >> 8) & 0xFF, fd); fputc(game->duration & 0xFF, fd); /* write level descriptions */ for (x = 0; x < 15; x++) fputc(game->level_desc_line1[x], fd); for (x = 0; x < 15; x++) fputc(game->level_desc_line2[x], fd); /* write the cursor type */ fputc(game->cursortype, fd); /* write the bg id */ fputc(game->bg, fd); fclose(fd); } static int sdlk2char(int sdlkey) { switch (sdlkey) { case SDLK_a: return('A'); case SDLK_b: return('B'); case SDLK_c: return('C'); case SDLK_d: return('D'); case SDLK_e: return('E'); case SDLK_f: return('F'); case SDLK_g: return('G'); case SDLK_h: return('H'); case SDLK_i: return('I'); case SDLK_j: return('J'); case SDLK_k: return('K'); case SDLK_l: return('L'); case SDLK_m: return('M'); case SDLK_n: return('N'); case SDLK_o: return('O'); case SDLK_p: return('P'); case SDLK_q: return('Q'); case SDLK_r: return('R'); case SDLK_s: return('S'); case SDLK_t: return('T'); case SDLK_u: return('U'); case SDLK_v: return('V'); case SDLK_w: return('W'); case SDLK_x: return('X'); case SDLK_y: return('Y'); case SDLK_z: return('Z'); case SDLK_PERIOD: return('.'); default: return(' '); } } int main(int argc, char **argv) { int x, y, level, exitflag = 0; int viewmode = 0; /* 0 = edit level / 1 = edit solution */ int cursorx = 0, cursory = 0; int selectedline = 1, selectedchar = 0; int lastitem = 0; struct atomixgame *game; struct gra_sprite *bg[3], *wall[19], *empty, *atom[64], *tile, *cursor[3], *font[16], *font3[64]; if (argc != 2) { puts("Usage: editor levelnum"); return(1); } level = atoi(argv[1]); game = malloc(sizeof(struct atomixgame)); if (game == NULL) { puts("Error: out of memory"); return(2); } atomix_loadgame(game, level, ATOMIX_SRC_FILE, NULL); gra_init(640, 480, 0, "editor", NULL, 0); /* Preload all graphics */ /* load the 'empty space' tile */ loadSpriteSheet(&empty, 16, 16, 1, img_empty_bmp_gz, img_empty_bmp_gz_len); /* load backgrounds */ loadSpriteSheet(&bg[0], 320, 240, 3, img_bg_bmp_gz, img_bg_bmp_gz_len); /* load atoms sprites */ loadSpriteSheet(&atom[0], 16, 16, 49, img_atoms_bmp_gz, img_atoms_bmp_gz_len); /* load walls sprites */ loadSpriteSheet(&wall[0], 16, 16, 19, img_walls_bmp_gz, img_walls_bmp_gz_len); /* load cursor sprites */ loadSpriteSheet(&cursor[0], 16, 16, 3, img_cursors_bmp_gz, img_cursors_bmp_gz_len); /* load timer font */ loadSpriteSheet(&font[0], 14, 15, 11, img_font2_bmp_gz, img_font2_bmp_gz_len); /* load generic font */ loadSpriteSheet(&font3[0], 7, 7, 26, img_font3_bmp_gz, img_font3_bmp_gz_len); for (;;) { SDL_Event event; int rect_x, rect_y, rect_w, rect_h, keybuff; gra_drawsprite(bg[game->bg], 0, 0); /* draw the background */ /* Draw the timer */ rect_x = 260; rect_y = 20; gra_drawsprite(font[game->duration / 60], rect_x, rect_y); rect_x += gra_getspritewidth(font[0]); gra_drawsprite(font[10], rect_x, rect_y); rect_x += gra_getspritewidth(font[0]); gra_drawsprite(font[(game->duration % 60) / 10], rect_x, rect_y); rect_x += gra_getspritewidth(font[0]); gra_drawsprite(font[game->duration % 10], rect_x, rect_y); /* Draw the descriptions */ rect_x = 210; rect_y = 220; rect_w = gra_getspritewidth(font3[0]) * 2; rect_h = gra_getspriteheight(font3[0]) * 2; for (x = 0; x < 15; x++) { if ((selectedline == 1) && (selectedchar == x)) { gra_drawrect(rect_x * 2, rect_y * 2, rect_w, rect_h, 255, 0, 0, 255, 1); } else { gra_drawrect(rect_x * 2, rect_y * 2, rect_w, rect_h, 0x30, 0x30, 0x30, 255, 1); } if ((game->level_desc_line1[x] <= 'Z') && (game->level_desc_line1[x] >= 'A')) { gra_drawsprite(font3[game->level_desc_line1[x] - 'A'], rect_x, rect_y); } rect_x += gra_getspritewidth(font3[0]); } rect_x = 210; rect_y += gra_getspriteheight(font3[0]) + 2; for (x = 0; x < 15; x++) { if ((selectedline == 2) && (selectedchar == x)) { gra_drawrect(rect_x * 2, rect_y * 2, rect_w, rect_h, 255, 0, 0, 255, 1); } else { gra_drawrect(rect_x * 2, rect_y * 2, rect_w, rect_h, 0x30, 0x30, 0x30, 255, 1); } if ((game->level_desc_line2[x] <= 'Z') && (game->level_desc_line2[x] >= 'A')) { gra_drawsprite(font3[game->level_desc_line2[x] - 'A'], rect_x, rect_y); } rect_x += gra_getspritewidth(font3[0]); } /* Draw the playfield or solution (depends of the current mode) */ if (viewmode == 0) { /* draw playfield */ for (y = 0; y < 64; y++) { for (x = 0; x < 64; x++) { if ((game->field[x][y] & field_type) == field_atom) { tile = atom[game->field[x][y] & field_index]; } else if ((game->field[x][y] & field_type) == field_wall) { tile = wall[game->field[x][y] & field_index]; } else if ((game->field[x][y] & field_type) == field_free) { tile = empty; } else { tile = NULL; } if (tile != NULL) { rect_x = 32 + (x * gra_getspritewidth(tile)); rect_y = 32 + (y * gra_getspriteheight(tile)); gra_drawsprite(empty, rect_x, rect_y); gra_drawsprite(tile, rect_x, rect_y); } } } } else { /* draw solution */ for (y = 0; y < 32; y++) { for (x = 0; x < 32; x++) { if ((game->solution[x][y] & field_type) == field_atom) { tile = atom[game->solution[x][y] & field_index]; } else if ((game->solution[x][y] & field_type) == field_wall) { tile = wall[game->field[x][y] & field_index]; } else if ((game->solution[x][y] & field_type) == field_free) { tile = empty; } else { tile = NULL; } if (tile != NULL) { rect_x = 32 + (x * gra_getspritewidth(tile)); rect_y = 32 + (y * gra_getspriteheight(tile)); gra_drawsprite(empty, rect_x, rect_y); gra_drawsprite(tile, rect_x, rect_y); } } } } /* draw the cursor type */ rect_x = 300; rect_y = 130; gra_drawsprite(cursor[game->cursortype], rect_x, rect_y); /* draw the cursor */ rect_x = 32 + (cursorx * gra_getspritewidth(cursor[0])); rect_y = 32 + (cursory * gra_getspriteheight(cursor[0])); gra_drawsprite(cursor[0], rect_x, rect_y); /* Refresh the screen */ gra_refresh(); /* Wait for next event */ SDL_WaitEvent(&event); if (event.type == SDL_QUIT) { exitflag = 1; } else if (event.type == SDL_KEYDOWN) { switch (event.key.keysym.sym) { case SDLK_ESCAPE: exitflag = 1; break; case SDLK_LEFT: if (cursorx > 0) cursorx -= 1; break; case SDLK_RIGHT: if (cursorx < 63) cursorx += 1; break; case SDLK_UP: if (cursory > 0) cursory -= 1; break; case SDLK_DOWN: if (cursory < 63) cursory += 1; break; case SDLK_SPACE: if (viewmode == 0) { /* if current view is on playfield... */ if ((game->field[cursorx][cursory] & field_type) == field_atom) { game->field[cursorx][cursory] &= field_index; /* zero out the tile type */ game->field[cursorx][cursory] += 1; if (game->field[cursorx][cursory] > 48) game->field[cursorx][cursory] = 0; game->field[cursorx][cursory] |= field_atom; lastitem = game->field[cursorx][cursory]; } else if ((game->field[cursorx][cursory] & field_type) == field_wall) { game->field[cursorx][cursory] &= field_index; /* zero out the tile type */ game->field[cursorx][cursory] += 1; if (game->field[cursorx][cursory] > 18) game->field[cursorx][cursory] = 0; game->field[cursorx][cursory] |= field_wall; lastitem = game->field[cursorx][cursory]; } } else { /* otherwise we are editing the solution */ if ((game->solution[cursorx][cursory] & field_type) == field_atom) { game->solution[cursorx][cursory] &= field_index; /* zero out the tile type */ game->solution[cursorx][cursory] += 1; if (game->solution[cursorx][cursory] > 48) { game->solution[cursorx][cursory] = 0; } else { game->solution[cursorx][cursory] |= field_atom; } lastitem = game->solution[cursorx][cursory]; } else { game->solution[cursorx][cursory] = field_atom; lastitem = game->solution[cursorx][cursory]; } } break; case SDLK_INSERT: /* repeat the last item */ if (viewmode == 0) { /* if current view is on playfield... */ game->field[cursorx][cursory] = lastitem; } else { /* otherwise we are editing the solution */ game->solution[cursorx][cursory] = lastitem; } break; case SDLK_RETURN: if (viewmode == 0) { /* only if editing field */ if ((game->field[cursorx][cursory] & field_type) == field_free) { game->field[cursorx][cursory] = field_wall; } else if ((game->field[cursorx][cursory] & field_type) == field_wall) { game->field[cursorx][cursory] = field_atom; } else if ((game->field[cursorx][cursory] & field_type) == field_atom) { game->field[cursorx][cursory] = 0; } else { game->field[cursorx][cursory] = field_free; } lastitem = game->field[cursorx][cursory]; } break; case SDLK_DELETE: if (viewmode == 0) { game->field[cursorx][cursory] = 0; } else { game->solution[cursorx][cursory] = 0; } break; case SDLK_TAB: viewmode = 1 - viewmode; break; case SDLK_KP_MINUS: if (game->duration > 0) game->duration -= 1; break; case SDLK_KP_PLUS: if (game->duration < 3600) game->duration += 1; break; case SDLK_F1: selectedchar++; if (selectedchar >= 15) { selectedline = 3 - selectedline; selectedchar = 0; } break; case SDLK_F2: game->cursortype += 1; if (game->cursortype > 2) game->cursortype = 1; break; case SDLK_F3: game->bg += 1; if (game->bg > 2) game->bg = 0; break; case SDLK_F5: savelevel(game, level); puts("SAVED"); break; default: /* text input */ keybuff = sdlk2char(event.key.keysym.sym); if (((keybuff >= 'A') && (keybuff <= 'Z')) || (keybuff == '.')) { if (selectedline == 1) { if (keybuff == '.') { game->level_desc_line1[selectedchar] = 0; } else { game->level_desc_line1[selectedchar] = keybuff; } } else { if (keybuff == '.') { game->level_desc_line2[selectedchar] = 0; } else { game->level_desc_line2[selectedchar] = keybuff; } } } break; } } if (exitflag != 0) break; } free(game); return(0); }