#include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 skipto = -1; int layer = 1; // which layer we are editting, either 1 or 2 int main (int argc, char **argv) { Uint8 *keys; char filename[BUFLEN]; int i; int mb,mx,my; curlevelnum = 1; levelbg = NULL; /* 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); } skipto = atoi(argv[i]); printf("Skipping to level %d.\n",skipto); } else { usage(); exit(1); } } } if (loadlevellist()) { printf("Error loading level list from levels.dat.\n"); return 1; } // is we're skipping to a level, do so now if (skipto >= 0) { for (i = 0; i < numlevels; i++) { if (levelentry[i].id == skipto) { curlevelnum = i; } } } /* 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 /* init tiles */ if (loadtiletypes("green.tiles")) { printf("Cannot initialise tiles\n"); exit(1); } 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("newtiles/land.png"); fakeblock.numframes = 1; fakeblock.next = NULL; fakeblock.prev = NULL; /* load fonts */ TTF_Init(); sprintf(filename, "gamefont.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) { if (isplacabletile(tt->id)) { // 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++) { if (isplacablesprite(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); if (layer == 1) { curlevel->map[y*LEVELW+x] = seltile->uniqid; curlevel->tileframe[y*LEVELW+x] = 0; } else { // if there's nothing at layer1, it goes there //if (curlevel->map[y*LEVELW+x] == T_BLANK) { // printf("falling to layer 1\n"); // curlevel->map[y*LEVELW+x] = seltile->uniqid; // curlevel->tileframe[y*LEVELW+x] = 0; //} else { curlevel->map2[y*LEVELW+x] = seltile->uniqid; //} } // 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 */ // can only have one player/powerup pos if ((selsprite == P_PLAYER) || (selsprite == P_POWERUPPOS)) { /* does a player start pos already exist? */ sprite_t *s; for (s = sprite ; s ; s = s->next) { if (s->id == selsprite) { // 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(); drawsprites(); } } } 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) { if (toggletimer == 0) { /* place selected sprite at mouse position (locked to a tile) */ if (selsprite == P_HELP) { addsprite(selsprite, x*TILEW+(TILEW/2),y*TILEH+TILEH,"FILL ME IN" ); } else { addsprite(selsprite, x*TILEW+(TILEW/2),y*TILEH+TILEH,"something" ); } printf("added a sprite\n"); toggletimer = 30; modified = B_TRUE; drawsprites(); } } } } } /* check for keys */ SDL_PumpEvents(); keys = SDL_GetKeyState(NULL); if (keys[SDLK_1]) { // toggle layer if (toggletimer == 0) { layer = 3 - layer; printf("Now editting layer %d\n",layer); toggletimer = 30; } } 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) { clearlevel(); toggletimer = 30; } } /* exit direction */ if (toggletimer == 0) { if (keys[SDLK_h]) { printf("Exit direction set to LEFT.\n"); curlevel->exitdir = D_LEFT; toggletimer = 30; modified = B_TRUE; } if (keys[SDLK_j]) { printf("Exit direction set to DOWN.\n"); curlevel->exitdir = D_DOWN; toggletimer = 30; modified = B_TRUE; } if (keys[SDLK_k]) { printf("Exit direction set to UP.\n"); curlevel->exitdir = D_UP; toggletimer = 30; modified = B_TRUE; } if (keys[SDLK_l]) { printf("Exit direction set to RIGHT.\n"); curlevel->exitdir = D_RIGHT; toggletimer = 30; modified = B_TRUE; } } /* next level */ if (keys[SDLK_RIGHT]) { if (toggletimer == 0) { printf("Skipping to next level.\n"); curlevelnum++; if ((curlevelnum >= numlevels) || loadlevel(curworld,curlevelnum)) { char tempbuf[BUFLEN]; clearlevel(); numlevels++; sprintf(tempbuf,"new_level%d.dat",curlevelnum); levelentry[curlevelnum].filename = strdup(tempbuf); sprintf(tempbuf,"NEW LEVEL"); levelentry[curlevelnum].desc = strdup(tempbuf); printf("created new level '%s'\n",levelentry[curlevelnum].filename); } draweditorlevel(); drawsprites(); toggletimer = 30; } } /* prev level */ if (keys[SDLK_LEFT]) { if (toggletimer == 0) { if (curlevelnum > 1) { printf("Skipping to previous level.\n"); curlevelnum--; if (loadlevel(curworld,curlevelnum)) { printf("creating new level\n"); clearlevel(); } 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) { if (isplacabletile(tt->id)) { /* 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; if (isplacablesprite(p)) { /* 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/%s",wnum,levelentry[lnum].filename); f = fopen(filename,"wt"); if (!f) { printf("can't open level file '%s'\n",filename); return B_TRUE; } fprintf(f, "bgfile %s\n",level->bgfile); 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"); /* exit dir */ fprintf(f, "exitdir %d\n",curlevel->exitdir); /* 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"); } fprintf(f, "layer2\n"); /* 2nd layer data - only where needed */ for (y = 0; y < LEVELH; y++) { for (x = 0; x < LEVELW; x++) { if (level->map2[y*LEVELW+x] != T_BLANK) { // x,y,tileid fprintf(f, "%d,%d,%d\n",x,y,level->map2[y*LEVELW+x]); } } } fclose(f); printf("Level saved to '%s'\n",filename); return 0; } void clearlevel(void) { 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; } curlevel->map2[offset] = T_BLANK; drawtile(screen,x,y); } } modified = B_TRUE; } int isplacabletile(int tid) { switch (tid) { case T_TRAMPDOWN: return B_FALSE; } return B_TRUE; } int isplacablesprite(int sid) { switch (sid) { case P_SPEED: case P_NUMNETS: case P_BIGNET: case P_CLOUD: case P_SPIT: case P_PUFF: case P_SMASH: case P_BOXING: case P_GLOVE: case P_DIAMOND: case P_FTODIAMOND: case P_FTOGEM: case P_BOMB: case P_SHIELD: case P_MACEPOWERUP: case P_MACE: case P_GEMRED: case P_GEMYELLOW: case P_GEMPURPLE: return B_FALSE; } return B_TRUE; }