579 lines
12 KiB
C
579 lines
12 KiB
C
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <SDL.h>
|
|
#include <SDL_keysym.h>
|
|
#include <SDL_rotozoom.h>
|
|
#include <SDL_ttf.h>
|
|
#include <SDL_framerate.h>
|
|
|
|
#include "defs.h"
|
|
#include "shared.h"
|
|
#include "edit.h"
|
|
|
|
|
|
/* these hold the currently selected sprite/tile types */
|
|
tiletype_t *seltile = NULL;
|
|
int selsprite = -1;
|
|
|
|
int modified = B_FALSE; // has the current level been modified since last save?
|
|
|
|
|
|
int curworld = 1;
|
|
int curlevelnum;
|
|
|
|
int main (int argc, char **argv) {
|
|
Uint8 *keys;
|
|
char filename[BUFLEN];
|
|
int i;
|
|
|
|
int mb,mx,my;
|
|
|
|
curlevelnum = 1;
|
|
|
|
/* handle arguments */
|
|
if (argc >= 2) {
|
|
for (i = 1; i < argc; i++) {
|
|
if (!strcmp(argv[i], "-fs")) {
|
|
printf("Fullscreen mode enabled.\n");
|
|
vidargs |= SDL_FULLSCREEN;
|
|
} else if (!strcmp(argv[i], "-l")) {
|
|
if (++i >= argc) {
|
|
printf("Missing level number.\n");
|
|
usage();
|
|
exit(1);
|
|
}
|
|
curlevelnum = atoi(argv[i]);
|
|
printf("Skipping to level %d.\n",curlevelnum);
|
|
} else {
|
|
usage();
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* initialise */
|
|
initglobals();
|
|
|
|
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE)==-1) {
|
|
printf("SDL_Init: %s\n", SDL_GetError());
|
|
exit(1);
|
|
}
|
|
|
|
atexit(cleanup);
|
|
|
|
#ifdef OPENGL
|
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
|
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
|
SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
|
|
screen = SDL_SetVideoMode(EDITORW,EDITORH,16,SDL_OPENGLBLIT|vidargs);
|
|
#else
|
|
screen = SDL_SetVideoMode(EDITORW,EDITORH,16,SDL_SWSURFACE|SDL_DOUBLEBUF|vidargs);
|
|
#endif
|
|
|
|
if (loadimagesets()) {
|
|
return 1;
|
|
}
|
|
|
|
fakeblock.id = T_LAND;
|
|
strcpy(fakeblock.name,"Fake");
|
|
for (i = 0; i < TILEW; i++) {
|
|
fakeblock.lowness[i] = 0;
|
|
}
|
|
fakeblock.solid = S_SOLID;
|
|
fakeblock.img[0] = IMG_Load("land.bmp");
|
|
fakeblock.numframes = 1;
|
|
fakeblock.next = NULL;
|
|
fakeblock.prev = NULL;
|
|
|
|
|
|
/* load fonts */
|
|
TTF_Init();
|
|
sprintf(filename, "verdana.ttf");
|
|
for (i = 1; i < MAXLETTERHEIGHT; i++) {
|
|
font[i] = TTF_OpenFont(filename,i);
|
|
if (!font[i]) {
|
|
printf("Error opening font: %s\n", TTF_GetError());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
if (loadlevel(curworld,curlevelnum)) {
|
|
return 1;
|
|
}
|
|
|
|
modified = B_FALSE;
|
|
|
|
seltile = tiletype;
|
|
|
|
draweditorlevel();
|
|
drawpalette();
|
|
drawsprites();
|
|
flip();
|
|
|
|
timer = 0;
|
|
|
|
//player->invuln = INVULNTIME;
|
|
//player->score = 0;
|
|
|
|
while (1) {
|
|
|
|
|
|
/* check for mouse actions */
|
|
mb = SDL_GetMouseState(&mx,&my);
|
|
if (mb & SDL_BUTTON(1)) { // lmb
|
|
if ((mx >= PALX) && (my < SPALY)) { // over tile palette
|
|
tiletype_t *tt;
|
|
int x = PALX,y = PALY;
|
|
seltile = NULL;
|
|
/* get tile number */
|
|
for (tt = tiletype; tt != NULL; tt = tt->next) {
|
|
// is mouse over this one?
|
|
if ((mx >= x) && (my >= y) && (mx <= x+TILEW-1) && (my <= y+TILEH-1)) {
|
|
seltile = tt;
|
|
selsprite = -1;
|
|
break;
|
|
} else {
|
|
// check next one
|
|
x += TILEW;
|
|
if (x >= EDITORW) {
|
|
x = PALX;
|
|
y += TILEH;
|
|
}
|
|
}
|
|
}
|
|
// redraw palette with new selection
|
|
drawpalette();
|
|
} else if ((mx >= PALX) && (my > SPALY)) { // over sprite palette
|
|
int p;
|
|
int x = SPALX, y = SPALY;
|
|
int maxh = 0;
|
|
/* get sprite id */
|
|
selsprite = -1;
|
|
|
|
for (p = 0; p < MAXPTYPES; p++) {
|
|
SDL_Surface *firstimg;
|
|
int w,h;
|
|
|
|
/* select images */
|
|
firstimg = imageset[p].img[F_WALK1];
|
|
w = firstimg->w;
|
|
h = firstimg->h;
|
|
if (h > maxh) maxh = h;
|
|
|
|
// is mouse over it?
|
|
if ((mx >= x) && (my >= y) && (mx <= x+w-1) && (my <= y+h-1)) {
|
|
selsprite = p;
|
|
seltile = NULL;
|
|
break;
|
|
} else {
|
|
// check next one
|
|
x += w;
|
|
if (x >= EDITORW-TILEW) {
|
|
x = SPALX;
|
|
y += maxh;
|
|
maxh = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
// redraw palette with new selection
|
|
drawpalette();
|
|
} else if (mx < PALX) { // over map
|
|
int x,y;
|
|
if (seltile != NULL) {
|
|
/* place selected tile at mouse pos */
|
|
x = (mx / TILEW);
|
|
y = (my / TILEH);
|
|
curlevel->map[y*LEVELW+x] = seltile->uniqid;
|
|
curlevel->tileframe[y*LEVELW+x] = 0;
|
|
// redraw tile and sprites
|
|
drawtile(screen,x,y);
|
|
drawsprites();
|
|
|
|
modified = B_TRUE;
|
|
} else if (selsprite >= 0) {
|
|
int placed = B_FALSE;
|
|
|
|
x = (mx / TILEW);
|
|
y = (my / TILEH);
|
|
|
|
/* checks */
|
|
if (toggletimer == 0) {
|
|
// can only have one player start pos
|
|
if (selsprite == P_PLAYER) {
|
|
/* does a player start pos already exist? */
|
|
sprite_t *s;
|
|
for (s = sprite ; s ; s = s->next) {
|
|
if (s->id == P_PLAYER) {
|
|
// if so, just move it
|
|
s->x = x*TILEW+(TILEW/2);
|
|
s->y = y*TILEH+TILEH;
|
|
placed = B_TRUE;
|
|
modified = B_TRUE;
|
|
// get rid of old sprite
|
|
draweditorlevel();
|
|
}
|
|
}
|
|
} else { // is there a monster already there?
|
|
sprite_t *s;
|
|
for (s = sprite ; s ; s = s->next) {
|
|
if (s->id == selsprite) {
|
|
if ((s->x == x*TILEW+(TILEW/2)) && (s->y == y*TILEH+TILEH)) {
|
|
/* don't place it */
|
|
placed = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (!placed) {
|
|
/* place selected sprite at mouse position
|
|
(locked to a til) */
|
|
if (selsprite == P_HELP) {
|
|
addsprite(selsprite, x*TILEW+(TILEW/2),y*TILEH+TILEH,"FILL ME IN", B_TRUE);
|
|
} else {
|
|
addsprite(selsprite, x*TILEW+(TILEW/2),y*TILEH+TILEH,"something", B_TRUE);
|
|
}
|
|
toggletimer = 30;
|
|
modified = B_TRUE;
|
|
drawsprites();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/* check for keys */
|
|
SDL_PumpEvents();
|
|
keys = SDL_GetKeyState(NULL);
|
|
|
|
|
|
|
|
if (keys[SDLK_x]) { // delete monster
|
|
int donesomething = B_FALSE;
|
|
sprite_t *s, *nextone;
|
|
|
|
for (s = sprite ; s ; s = nextone) {
|
|
nextone = s->next;
|
|
|
|
/* if mouse is over this sprite */
|
|
if ( (mx >= s->x - (s->img->w/2)) &&
|
|
(mx <= s->x + (s->img->w/2)) &&
|
|
(my >= s->y - s->img->h) &&
|
|
(my <= s->y )) {
|
|
// kill it
|
|
killsprite(s);
|
|
donesomething = B_TRUE;
|
|
}
|
|
}
|
|
if (donesomething) {
|
|
draweditorlevel();
|
|
drawsprites();
|
|
modified = B_TRUE;
|
|
}
|
|
}
|
|
if (keys[SDLK_c]) {
|
|
if (toggletimer == 0) {
|
|
int offset,x,y;
|
|
|
|
/* clear all sprites */
|
|
while (sprite) {
|
|
killsprite(sprite);
|
|
}
|
|
|
|
/* clear level */
|
|
for (x = 0; x < LEVELW; x++) {
|
|
for (y = 0; y < LEVELH; y++) {
|
|
offset = y*LEVELW+x;
|
|
if ((x == 0) || (x == LEVELW-1)) {
|
|
curlevel->map[offset] = T_FULL;
|
|
} else if (y == LEVELH-1) {
|
|
curlevel->map[offset] = T_LAND;
|
|
} else {
|
|
curlevel->map[offset] = T_BLANK;
|
|
}
|
|
drawtile(screen,x,y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* next level */
|
|
if (keys[SDLK_RIGHT]) {
|
|
if (toggletimer == 0) {
|
|
printf("Skipping to next level.\n");
|
|
curlevelnum++;
|
|
loadlevel(curworld,curlevelnum);
|
|
draweditorlevel();
|
|
drawsprites();
|
|
toggletimer = 30;
|
|
}
|
|
}
|
|
/* prev level */
|
|
if (keys[SDLK_LEFT]) {
|
|
if (toggletimer == 0) {
|
|
if (curlevelnum > 1) {
|
|
printf("Skipping to previous level.\n");
|
|
curlevelnum--;
|
|
loadlevel(curworld,curlevelnum);
|
|
draweditorlevel();
|
|
drawsprites();
|
|
toggletimer = 30;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (keys[SDLK_RETURN]) {
|
|
if (toggletimer == 0) {
|
|
SDL_WM_ToggleFullScreen(screen);
|
|
toggletimer = 50;
|
|
}
|
|
}
|
|
if (keys[SDLK_ESCAPE]) {
|
|
return 1;
|
|
}
|
|
|
|
/* SAVE LEVEL */
|
|
if (keys[SDLK_s]) {
|
|
if (modified) {
|
|
savelevel(curworld,curlevelnum);
|
|
modified = B_FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
flip();
|
|
if (++timer == 100) timer = 0;
|
|
if (toggletimer > 0) toggletimer--;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
void cleanup(void) {
|
|
int i;
|
|
for (i = 1; i < MAXLETTERHEIGHT; i++) {
|
|
TTF_CloseFont(font[i]);
|
|
}
|
|
TTF_Quit();
|
|
SDL_Quit();
|
|
}
|
|
|
|
|
|
|
|
void draweditorlevel(void) {
|
|
int x,y;
|
|
|
|
if (temps) {
|
|
SDL_FreeSurface(temps);
|
|
temps = NULL;
|
|
}
|
|
temps = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
|
640, 480,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask,
|
|
screen->format->Amask);
|
|
|
|
for (x = 0; x < LEVELW; x++) {
|
|
for (y = 0; y < LEVELH; y++) {
|
|
drawtile(screen,x,y);
|
|
}
|
|
}
|
|
|
|
SDL_UpdateRect(screen, 0, 0, EDITORW, EDITORH);
|
|
}
|
|
|
|
|
|
|
|
|
|
void drawsprites(void) {
|
|
sprite_t *s;
|
|
for (s = sprite; s != NULL; s = s->next) {
|
|
drawsprite(s);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
char tiletochar(int id) {
|
|
switch (id) {
|
|
case T_BLANK: return '0';
|
|
case T_LAND: return '~';
|
|
case T_SLOPEUP: return '/';
|
|
case T_SLOPEDOWN: return '\\';
|
|
case T_FULL: return '*';
|
|
case T_SKY: return '0';
|
|
case T_LADDER: return '=';
|
|
case T_LADDERTOP: return '-';
|
|
case T_RIGHT: return '>';
|
|
case T_LEFT: return '<';
|
|
case T_SPIKES: return '^';
|
|
case T_TELEPORT: return ';';
|
|
case T_TELEPORT2: return ':';
|
|
case T_TELEPORTDEST: return '.';
|
|
case T_WATER: return '}';
|
|
case T_WATERTOP: return '{';
|
|
case T_WATERSPIKES: return '|';
|
|
}
|
|
|
|
return '0';
|
|
}
|
|
*/
|
|
|
|
|
|
void usage(void) {
|
|
printf("usage: edit [-fs] [-l xx]\n");
|
|
printf(" -fs Start in full-screen mode.\n");
|
|
printf(" -l xx Edit level xx.\n");
|
|
printf("\n");
|
|
}
|
|
|
|
|
|
|
|
void drawpalette(void) {
|
|
tiletype_t *tt;
|
|
SDL_Rect area;
|
|
tiletype_t *bg = gettile(curlevel->bgtileid);
|
|
int p;
|
|
int maxheight;
|
|
|
|
/* draw all tiles */
|
|
area.x = PALX;
|
|
area.y = PALY;
|
|
area.w = TILEW;
|
|
area.h = TILEH;
|
|
for (tt = tiletype; tt != NULL; tt = tt->next) {
|
|
/* draw background */
|
|
SDL_BlitSurface(bg->img[0], NULL, screen, &area);
|
|
/* draw tile */
|
|
SDL_BlitSurface(tt->img[0], NULL, screen, &area);
|
|
/* draw selector box */
|
|
if (seltile == tt) {
|
|
drawbox16(screen,area.x,area.y,area.x+area.w-1,area.y+area.h-1,&red,NULL);
|
|
drawbox16(screen,area.x+1,area.y+1,area.x+area.w-2,area.y+area.h-2,&red,NULL);
|
|
}
|
|
/* move on to next position */
|
|
area.x += TILEW;
|
|
if (area.x >= EDITORW) {
|
|
area.x = PALX;
|
|
area.y += TILEH;
|
|
}
|
|
|
|
}
|
|
|
|
SDL_UpdateRect(screen, PALX,PALY,PALW,PALH);
|
|
|
|
/* draw all sprites */
|
|
maxheight = 0;
|
|
|
|
area.x = SPALX;
|
|
area.y = SPALY;
|
|
for (p = 0; p < MAXPTYPES; p++) {
|
|
SDL_Surface *firstimg;
|
|
|
|
/* select images */
|
|
firstimg = imageset[p].img[F_WALK1];
|
|
area.w = firstimg->w;
|
|
area.h = firstimg->h;
|
|
if (area.h > maxheight) maxheight = area.h;
|
|
|
|
/* clear bg */
|
|
drawbox16(screen,area.x,area.y,area.x+area.w,area.y+area.h,&black,&black);
|
|
/* draw sprite */
|
|
SDL_BlitSurface(firstimg, NULL, screen, &area);
|
|
/* draw selector box */
|
|
if (selsprite == p) {
|
|
drawbox16(screen,area.x,area.y, area.x+area.w-1,area.y+area.h-1,&red,NULL);
|
|
drawbox16(screen,area.x+1,area.y+1, area.x+area.w-2,area.y+area.h-2,&red,NULL);
|
|
}
|
|
|
|
/* move to next position */
|
|
area.x += area.w;
|
|
if (area.x >= EDITORW-TILEW) {
|
|
area.x = SPALX;
|
|
area.y += maxheight;
|
|
maxheight = 0;
|
|
}
|
|
|
|
}
|
|
SDL_UpdateRect(screen, SPALX,SPALY,SPALW,SPALH);
|
|
}
|
|
|
|
|
|
int savelevel(int wnum, int lnum) {
|
|
FILE *f;
|
|
int x,y;
|
|
char filename[BUFLEN];
|
|
|
|
sprite_t *s;
|
|
|
|
|
|
sprintf(filename, "world%d/level%d.dat",wnum,lnum);
|
|
f = fopen(filename,"wt");
|
|
if (!f) {
|
|
printf("can't open level file\n");
|
|
return B_TRUE;
|
|
}
|
|
|
|
fprintf(f, "tileset %s\n",level->tileset);
|
|
fprintf(f, "bg %d\n",level->bgtileid);
|
|
fprintf(f, "hurryup %d\n",level->hurryuptime);
|
|
|
|
/* no mappings */
|
|
fprintf(f, "endmaps\n");
|
|
|
|
/* help text */
|
|
fprintf(f, "help\n");
|
|
for (s = sprite; s ; s = s->next) {
|
|
if (s->id == P_HELP) {
|
|
fprintf(f,"%s\n",s->name);
|
|
}
|
|
}
|
|
fprintf(f, "endhelp\n");
|
|
|
|
/* monster defs */
|
|
fprintf(f, "monsters\n");
|
|
for (s = sprite; s ; s = s->next) {
|
|
int mx,my;
|
|
char mid;
|
|
mid = monstertochar(s->id);
|
|
mx = (s->x - (TILEW/2)) / TILEW;
|
|
my = (s->y - TILEH/2) / TILEH;
|
|
fprintf(f,"%c %d %d\n",mid,mx,my);
|
|
}
|
|
fprintf(f, "endmonsters\n");
|
|
|
|
/* level data */
|
|
for (y = 0; y < LEVELH; y++) {
|
|
for (x = 0; x < LEVELW; x++) {
|
|
fprintf(f, "%d,",level->map[y*LEVELW+x]);
|
|
}
|
|
fprintf(f, "\n");
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
printf("Level saved to '%s'\n",filename);
|
|
|
|
return 0;
|
|
}
|
|
|