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