]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/mapEditor.cpp
Prevent a segmentation fault when using the -map option without specifying a map.
[quix0rs-blobwars.git] / src / mapEditor.cpp
1 /*
2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14 See the GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 */
21
22 #include "mapEditor.h"
23
24 MedalServer medalServer;
25 Config config;
26 ReplayData replayData;
27
28 void drawMap(int mapX, int mapY)
29 {
30         SDL_Rect r;
31         int tile = 0;
32
33         for (int x = 0 ; x < 20 ; x++)
34         {
35                 for (int y = 0 ; y < 15 ; y++)
36                 {
37                         r.x = x * BRICKSIZE;
38                         r.y = y * BRICKSIZE;
39                         r.w = r.h = BRICKSIZE - 1;
40                         
41                         tile = map.data[x + mapX][y + mapY];
42                         
43                         if (tile == MAP_WATERANIM)
44                         {
45                                 tile = graphics.getWaterAnim();
46                         }
47
48                         if (tile > 0)
49                         {
50                                 graphics.blit(graphics.tile[tile], r.x, r.y, graphics.screen, false);
51                                 
52                                 if ((tile >= MAP_NORESET) && (tile < MAP_DECORATION))
53                                 {
54                                         graphics.drawRect(r.x, r.y, 32, 4, graphics.yellow, graphics.screen);
55                                 }
56                         }
57                 }
58         }
59 }
60
61 void showMap(int *mapX, int *mapY)
62 {
63         SDL_FillRect(graphics.screen, NULL, graphics.black);
64
65         engine.keyState[SDL_SCANCODE_SPACE] = 0;
66         int moveTimer = 0;
67
68         while (true)
69         {
70                 graphics.updateScreen();
71                 engine.getInput();
72                 config.populate();
73
74                 if (engine.keyState[SDL_SCANCODE_SPACE])
75                         break;
76                         
77                 for (int x = 0 ; x < MAPWIDTH ; x++)
78                 {
79                         for (int y = 0 ; y < MAPHEIGHT ; y++)
80                         {
81                                 switch (map.data[x][y])
82                                 {
83                                         case 0:
84                                                 graphics.putPixel(x, y, 9, graphics.screen);
85                                                 break;
86                                         case 1:
87                                                 graphics.putPixel(x, y,graphics.blue, graphics.screen);
88                                                 break;
89                                         case 2:
90                                                 graphics.putPixel(x, y, graphics.green, graphics.screen);
91                                                 break;
92                                         case 3:
93                                                 graphics.putPixel(x, y, graphics.red, graphics.screen);
94                                                 break;
95                                         default:
96                                                 graphics.putPixel(x, y, graphics.white, graphics.screen);
97                                                 break;
98                                 }
99                         }
100                 }
101
102                 if (moveTimer == 0)
103                 {
104                         if (engine.keyState[SDL_SCANCODE_LEFT])
105                                 *mapX -= 1;
106
107                         if (engine.keyState[SDL_SCANCODE_RIGHT])
108                                 *mapX += 1;
109
110                         if (engine.keyState[SDL_SCANCODE_UP])
111                                 *mapY -= 1;
112
113                         if (engine.keyState[SDL_SCANCODE_DOWN])
114                                 *mapY += 1;
115                 }
116
117                 moveTimer--;
118                 Math::limitInt(&moveTimer, 0, 60);
119
120                 graphics.drawRect(*mapX, *mapY, 20, 1, graphics.green, graphics.screen);
121                 graphics.drawRect(*mapX, *mapY, 1, 15, graphics.green, graphics.screen);
122                 graphics.drawRect(*mapX, *mapY + 15, 20, 1, graphics.green, graphics.screen);
123                 graphics.drawRect(*mapX + 20, *mapY, 1, 15, graphics.green, graphics.screen);
124
125                 SDL_Delay(16);
126         }
127
128         engine.keyState[SDL_SCANCODE_SPACE] = 0;
129 }
130
131 int nextBlock(int current, int dir)
132 {
133         if ((current + dir) > 255)
134                 return current;
135
136         if ((current + dir) < 0)
137                 return current;
138
139         int wanted = current;
140
141         while (true)
142         {
143                 wanted += dir;
144
145                 if (wanted < 0) return current;
146                 if (wanted > 255) return current;
147
148                 if (graphics.tile[wanted])
149                         return wanted;
150         }
151 }
152
153 void drawEnemies()
154 {
155         Entity *enemy = (Entity*)map.enemyList.getHead();
156
157         int x, y, absX, absY;
158
159         while (enemy->next != NULL)
160         {
161                 enemy = (Entity*)enemy->next;
162
163                 if (enemy->owner != enemy)
164                 {
165                         enemy->face = enemy->owner->face;
166                         (enemy->face == 0) ? enemy->x = enemy->owner->x + enemy->tx : enemy->x = enemy->owner->x + -enemy->tx;
167                         enemy->y = enemy->owner->y + enemy->ty;
168                 }
169
170                 x = (int)(enemy->x - engine.playerPosX);
171                 y = (int)(enemy->y - engine.playerPosY);
172
173                 absX = abs(x);
174                 absY = abs(y);
175
176                 if ((absX < 800) && (absY < 600))
177                 {
178                         graphics.blit(enemy->getFaceImage(), x, y, graphics.screen, false);
179                         enemy->animate();
180
181                         if ((!(enemy->flags & ENT_WEIGHTLESS)) && (!(enemy->flags & ENT_FLIES)) && (!(enemy->flags & ENT_SWIMS)))
182                                 enemy->applyGravity();
183                 }
184         }
185 }
186
187 void deleteEnemy(int x, int y)
188 {
189         x *= BRICKSIZE;
190         y *= BRICKSIZE;
191
192         Entity *enemy = (Entity*)map.enemyList.getHead();
193         Entity *previous = enemy;
194
195         while (enemy->next != NULL)
196         {
197                 enemy = (Entity*)enemy->next;
198
199                 if ((enemy->x == x) && (enemy->y == y))
200                 {
201                         map.enemyList.remove(previous, enemy);
202                         enemy = previous;
203                 }
204                 else
205                 {
206                         previous = enemy;
207                 }
208         }
209 }
210
211 void saveMap(const char *name)
212 {
213         FILE *fp = fopen(name, "wb");
214         Entity *enemy = (Entity*)map.enemyList.getHead();
215         String *str;
216
217         if (fp)
218         {
219                 for (int y = 0 ; y < MAPHEIGHT ; y++)
220                 {
221                         for (int x = 0 ; x < MAPWIDTH ; x++)
222                         {
223                                 fprintf(fp, "%d ", map.data[x][y]);
224                         }
225                         fprintf(fp, "\n");
226                 }
227
228                 str = stringHead->next;
229                 while (str != NULL)
230                 {
231                         fprintf(fp, "%s", str->string);
232                         str = str->next;
233                 }
234                 
235                 while (enemy->next != NULL)
236                 {
237                         enemy = (Entity*)enemy->next;
238                         fprintf(fp, "EMH ENEMY \"%s\" %d %d\n", enemy->name, (int)enemy->x, (int)enemy->y);
239                 }
240
241                 fprintf(fp, "@EOF@\n");
242
243                 fclose(fp);
244         }
245         
246         printf("Saved %s (%d)\n", name, SDL_GetTicks());
247 }
248
249 void collectMapData()
250 {
251         FILE *fp = fopen(game.mapName, "rb");
252         if (!fp)
253                 return;
254
255         char string[1024];
256         String *str;
257
258         for (int y = 0 ; y < 300 ; y++)
259                 fgets(string, 1024, fp);
260
261         while (true)
262         {
263                 fgets(string, 1024, fp);
264                 printf("Read: %s", string);
265
266                 if (strstr(string, "@EOF@"))
267                         break;
268
269                 if (!strstr(string, " ENEMY \""))
270                 {
271                         str = new String;
272                         strlcpy(str->string, string, sizeof str->string);
273                         stringTail->next = str;
274                         stringTail = str;
275                 }
276                 
277                 if (strstr(string, "TILESET gfx/ancient"))
278                 {
279                         for (int x = 0 ; x < MAPWIDTH ; x++)
280                         {
281                                 for (int y = 0 ; y < MAPHEIGHT ; y++)
282                                 {
283                                         if ((map.data[x][y] >= 9) && (map.data[x][y] <= 20) && ((Math::prand() % 2) == 0))
284                                                 map.data[x][y] = Math::rrand(9, 20);
285                                 }
286                         }
287                 }
288                 
289                 if (strstr(string, "TILESET gfx/caves"))
290                 {
291                         for (int x = 0 ; x < MAPWIDTH ; x++)
292                         {
293                                 for (int y = 0 ; y < MAPHEIGHT ; y++)
294                                 {
295                                         if ((map.data[x][y] >= 9) && (map.data[x][y] <= 20))
296                                                 map.data[x][y] = Math::rrand(9, 12);
297                                 }
298                         }
299                 }
300         }
301
302         fclose(fp);
303 }
304
305 void newMap(const char *name)
306 {
307         FILE *fp = fopen(name, "wb");
308
309         if (fp)
310         {
311                 for (int y = 0 ; y < MAPHEIGHT ; y++)
312                 {
313                         for (int x = 0 ; x < MAPWIDTH ; x++)
314                         {
315                                 fprintf(fp, "%d ", map.data[x][y]);
316                         }
317                         fprintf(fp, "\n");
318                 }
319                 
320                 fprintf(fp, "EMH STAGENAME \"unnamed\"\n");
321
322                 fprintf(fp, "EMH TILESET gfx/grasslands\n");
323                 fprintf(fp, "EMH BACKGROUND gfx/grasslands/stone.jpg\n");
324                 fprintf(fp, "EMH MUSIC music/tunnel\n");
325
326                 fprintf(fp, "EMH ALPHATILES 1 2 3 200 201 202 203 204 244 245 246 -1\n");
327
328                 fprintf(fp, "EMH START 10 10\n");
329
330                 fprintf(fp, "@EOF@\n");
331                 
332                 fclose(fp);
333         }
334         else
335         {
336                 exit(1);
337         }
338 }
339
340 void addTileDecoration()
341 {
342         printf("Adding Tile Decoration...\n");
343
344         for (int y = 1 ; y < MAPHEIGHT ; y++)
345         {
346                 for (int x = 0 ; x < MAPWIDTH ; x++)
347                 {
348                         if ((map.data[x][y] == 9) && (map.data[x][y - 1] == MAP_AIR))
349                         {
350                                 if (Math::prand() % 4)
351                                         map.data[x][y - 1] = 241;
352                         }
353                 }
354         }
355
356         for (int y = 0 ; y < MAPHEIGHT ; y++)
357         {
358                 for (int x = 0 ; x < MAPWIDTH ; x++)
359                 {
360                         if (map.data[x][y] == 241)
361                         {
362                                 if ((Math::prand() % 3) == 0)
363                                         map.data[x][y] = 242;
364                         }
365                 }
366         }
367         
368         engine.keyState[SDL_SCANCODE_F1] = 0;
369 }
370
371 void fillHorizontal(int block, int x, int y)
372 {
373         bool moveLeft = true;
374         bool moveRight = true;
375         bool ok = true;
376         
377         int left = x;
378         int right = x;
379         
380         if (map.data[x][y] == 0)
381         {
382                 map.data[x][y] = block;
383                 
384                 while (ok)
385                 {
386                         if (moveLeft)
387                         {
388                                 left--;
389                                 if (left < 0) 
390                                 {
391                                         left = 0;
392                                 }
393                         }
394                         
395                         if (map.data[left][y] == 0)
396                         {
397                                 map.data[left][y] = block;
398                         }
399                         else
400                         {
401                                 moveLeft = false;
402                         }
403                         
404                         if (moveRight)
405                         {
406                                 right++;
407                                 
408                                 if (right >= MAPWIDTH)
409                                 {
410                                         right = MAPWIDTH - 1;
411                                 }
412                         }
413                         
414                         if (map.data[right][y] == 0)
415                         {
416                                 map.data[right][y] = block;
417                         }
418                         else
419                         {
420                                 moveRight = false;
421                         }
422                         
423                         if ((!moveLeft) && (!moveRight))
424                         {
425                                 ok = false;
426                         }
427                 }
428         }
429 }
430
431 int main(int argc, char *argv[])
432 {
433         if (argc < 2)
434         {
435                 printf("Usage: mapeditor <filename>\n\n");
436                 exit(1);
437         }
438
439         config.engine = &engine;
440
441         replayData.reset();
442
443         atexit(cleanup);
444         
445         engine.useAudio = 0;
446
447         initSystem();
448
449         FILE *fp = fopen(argv[1], "rb");
450         if (!fp)
451                 newMap(argv[1]);
452         else
453                 fclose(fp);
454         
455         game.setMapName(argv[1]);
456         
457         loadResources();
458         
459         collectMapData();
460         
461         int mapX, mapY, allowMove, x, y;
462         mapX = mapY = allowMove = x = y = 0;
463         
464         int editing = 0;
465         int currentMonster = 0;
466         int currentItem = 0;
467         int currentBlock = 1;
468
469         SDL_Rect r;
470
471         int MOVESPEED = 5;
472         
473         char string[255];
474         
475         unsigned int frameLimit = SDL_GetTicks() + 16;
476
477         while (true)
478         {
479                 engine.getInput();
480                 config.populate();
481                 config.doPause();
482                 engine.doFrameLoop();
483
484                 graphics.updateScreen();
485                 graphics.animateSprites();
486                 graphics.drawBackground();
487
488                 engine.setPlayerPosition((mapX * 32) + 320, (mapY * 32) + 240, map.limitLeft, map.limitRight, map.limitUp, map.limitDown);
489
490                 drawMap(mapX, mapY);
491                 doTrains();
492                 doSwitches();
493                 doItems();
494                 doBullets();
495                 doMIAs();
496                 drawEnemies();
497                 doObstacles();
498                 doEffects();
499                 doParticles();
500                 doTeleporters();
501                 doLineDefs();
502                 doTraps();
503
504                 x = engine.getMouseX();
505                 y = engine.getMouseY();
506
507                 x /= BRICKSIZE;
508                 y /= BRICKSIZE;
509
510                 r.x = x * BRICKSIZE;
511                 r.y = y * BRICKSIZE;
512                 r.w = BRICKSIZE;
513                 r.h = BRICKSIZE;
514
515                 switch (editing)
516                 {
517                         case 0:
518                                 graphics.drawRect(r.x - 1, r.y - 1, 34, 1, graphics.yellow, graphics.screen);
519                                 graphics.drawRect(r.x - 1, r.y - 1, 1, 34, graphics.yellow, graphics.screen);
520                                 graphics.drawRect(r.x + 32, r.y - 1, 1, 34, graphics.yellow, graphics.screen);
521                                 graphics.drawRect(r.x - 1, r.y + 32, 34, 1, graphics.yellow, graphics.screen);
522                                 graphics.blit(graphics.tile[currentBlock], r.x, r.y, graphics.screen, false);
523                                 if (engine.mouseLeft)
524                                         map.data[mapX + x][mapY + y] = currentBlock;
525                                 break;
526                         case 1:
527                                 graphics.blit(defEnemy[currentMonster].getFaceImage(), r.x, r.y, graphics.screen, false);
528                                 if (engine.mouseLeft)
529                                 {
530                                         addEnemy(defEnemy[currentMonster].name, (mapX + x) * BRICKSIZE, (mapY + y) * BRICKSIZE, 0);
531                                         engine.mouseLeft = 0;
532                                 }
533                                 break;
534                         case 2:
535                                 graphics.blit(defItem[currentItem].getFaceImage(), r.x, r.y, graphics.screen, false);
536                                 if (engine.mouseLeft)
537                                 {
538                                         addItem(defItem[currentItem].id, defItem[currentItem].name, (mapX + x) * BRICKSIZE, (mapY + y) * BRICKSIZE, defItem[currentItem].sprite[0]->name, 0, defItem[currentItem].value, 0, true);
539                                         engine.mouseLeft = 0;
540                                 }
541                                 break;
542                 }
543
544                 if (engine.mouseRight)
545                 {
546                         if (editing == 0) map.data[mapX + x][mapY + y] = MAP_AIR;
547                         if (editing == 1) deleteEnemy(mapX + x, mapY + y);
548                 }
549
550                 allowMove--;
551                 if (allowMove < 1) allowMove = 0;
552
553                 if (allowMove == 0)
554                 {
555                         if (engine.keyState[SDL_SCANCODE_UP]) {mapY--; allowMove = MOVESPEED;}
556                         if (engine.keyState[SDL_SCANCODE_DOWN]) {mapY++; allowMove = MOVESPEED;}
557                         if (engine.keyState[SDL_SCANCODE_LEFT]) {mapX--; allowMove = MOVESPEED;}
558                         if (engine.keyState[SDL_SCANCODE_RIGHT]) {mapX++; allowMove = MOVESPEED;}
559
560                         if (engine.keyState[SDL_SCANCODE_PAGEDOWN]) {mapY += 10; allowMove = MOVESPEED;}
561                         if (engine.keyState[SDL_SCANCODE_PAGEUP]) {mapY -= 10; allowMove = MOVESPEED;}
562
563                         if (engine.keyState[SDL_SCANCODE_1]) editing = 0;
564                         if (engine.keyState[SDL_SCANCODE_2]) editing = 1;
565                         if (engine.keyState[SDL_SCANCODE_3]) editing = 2;
566                         
567                         if (engine.keyState[SDL_SCANCODE_0]) fillHorizontal(currentBlock, mapX + x, mapY + y);
568
569                         if (engine.keyState[SDL_SCANCODE_F1]) addTileDecoration();
570
571                         if (engine.keyState[SDL_SCANCODE_ESCAPE]) break;
572                 }
573
574                 if (engine.keyState[SDL_SCANCODE_PERIOD])
575                 {
576                         switch (editing)
577                         {
578                                 case 0:
579                                         currentBlock = nextBlock(currentBlock, 1);
580                                         break;
581                                 case 1:
582                                         currentMonster++;
583                                         break;
584                                 case 2:
585                                         currentItem++;
586                                         break;
587                         }
588
589                         engine.keyState[SDL_SCANCODE_PERIOD] = 0;
590                 }
591
592                 if (engine.keyState[SDL_SCANCODE_COMMA])
593                 {
594                         switch (editing)
595                         {
596                                 case 0:
597                                         currentBlock = nextBlock(currentBlock, -1);
598                                         break;
599                                 case 1:
600                                         currentMonster--;
601                                         break;
602                                 case 2:
603                                         currentItem--;
604                                         break;
605                         }
606
607                         engine.keyState[SDL_SCANCODE_COMMA] = 0;
608                 }
609
610                 Math::limitInt(&currentMonster, 0, MAX_ENEMIES - 1);
611                 Math::limitInt(&currentItem, 0, MAX_ITEMS - 1);
612
613                 if (defEnemy[currentMonster].sprite[0] == NULL)
614                         currentMonster = 0;
615                         
616                 if (defItem[currentItem].sprite[0] == NULL)
617                         currentItem = 0;
618
619                 if (engine.keyState[SDL_SCANCODE_SPACE]) {showMap(&mapX, &mapY);}
620
621                 if (engine.keyState[SDL_SCANCODE_S]) {saveMap(game.mapName); engine.keyState[SDL_SCANCODE_S] = 0;}
622
623                 if (mapX < 0) mapX = 0;
624                 if (mapY < 0) mapY = 0;
625                 if (mapX > MAPWIDTH - 40) mapX = MAPWIDTH - 40;
626                 if (mapY > MAPHEIGHT - 30) mapY = MAPHEIGHT - 30;
627
628                 if (editing == 0)
629                         snprintf(string, sizeof string, "Index : %d:%d ; Screen %d:%d ; Tile %d", mapX + x, mapY + y, (mapX + x) * BRICKSIZE, (mapY + y) * BRICKSIZE, currentBlock);
630                 else if (editing == 1)
631                         snprintf(string, sizeof string, "Index : %d:%d ; Screen %d:%d ; %s", mapX + x, mapY + y, (mapX + x) * BRICKSIZE, (mapY + y) * BRICKSIZE, defEnemy[currentMonster].name);
632                 else if (editing == 2)
633                         snprintf(string, sizeof string, "Index : %d:%d ; Screen %d:%d ; %s", mapX + x, mapY + y, (mapX + x) * BRICKSIZE, (mapY + y) * BRICKSIZE, defItem[currentItem].name);
634
635                 r.x = 0;
636                 r.w = 640;
637                 r.h = 20;
638
639                 if (mapY < MAPHEIGHT - 30)
640                         r.y = 460;
641                 else
642                         r.y = 0;
643
644                 SDL_FillRect(graphics.screen, &r, graphics.black);
645
646                 graphics.drawString(string, 320, r.y + 5, true, graphics.screen);
647                 
648                 engine.delay(frameLimit);
649                 frameLimit = SDL_GetTicks() + 16;
650         }
651
652         String *str = stringHead->next;
653         String *str2;
654         while (str != NULL)
655         {
656                 str2 = str;
657                 printf("Deleting %s", str->string);
658                 str = str->next;
659                 delete str2;
660         }
661
662         return 0;
663 }