1 /*
2 editor.c
3
4 Copyright (C) 2010-2019 Amf
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 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 #include <stdio.h>
22 #include <string.h>
23 #include <time.h>
24 #include <libintl.h>
25 #include <locale.h>
26
27 #include "chroma.h"
28 #include "level.h"
29 #include "menu.h"
30 #include "display.h"
31 #include "util.h"
32
33 void export(struct level*, int);
34
35 int editor_verify(struct level*);
36 struct level* editor_options(struct level* plevel);
37
38 extern int move_x[];
39 extern int move_y[];
40 extern char* piece_name[];
41 extern struct level* plevelcurrent;
42 extern int options_debug;
43
44 #ifdef XOR_COMPATIBILITY
45 extern int options_xor_options;
46 #endif
47 #ifdef ENIGMA_COMPATIBILITY
48 extern int options_enigma_options;
49 #endif
50
51 int editor_pieces_chroma[] = {
52 PIECE_SPACE,
53 PIECE_WALL,
54 PIECE_PLAYER_ONE,
55 PIECE_PLAYER_TWO,
56 PIECE_DOTS,
57 PIECE_ARROW_RED_LEFT,
58 PIECE_ARROW_RED_UP,
59 PIECE_ARROW_RED_RIGHT,
60 PIECE_ARROW_RED_DOWN,
61 PIECE_BOMB_RED_LEFT,
62 PIECE_BOMB_RED_UP,
63 PIECE_BOMB_RED_RIGHT,
64 PIECE_BOMB_RED_DOWN,
65 PIECE_ARROW_GREEN_LEFT,
66 PIECE_ARROW_GREEN_UP,
67 PIECE_ARROW_GREEN_RIGHT,
68 PIECE_ARROW_GREEN_DOWN,
69 PIECE_BOMB_GREEN_LEFT,
70 PIECE_BOMB_GREEN_UP,
71 PIECE_BOMB_GREEN_RIGHT,
72 PIECE_BOMB_GREEN_DOWN,
73 PIECE_ARROW_BLUE_LEFT,
74 PIECE_ARROW_BLUE_UP,
75 PIECE_ARROW_BLUE_RIGHT,
76 PIECE_ARROW_BLUE_DOWN,
77 PIECE_BOMB_BLUE_LEFT,
78 PIECE_BOMB_BLUE_UP,
79 PIECE_BOMB_BLUE_RIGHT,
80 PIECE_BOMB_BLUE_DOWN,
81 PIECE_CIRCLE,
82 PIECE_STAR,
83 PIECE_DOOR,
84 PIECE_GONE
85 };
86
87 #ifdef XOR_COMPATIBILITY
88 int editor_pieces_xor[] = {
89 PIECE_SPACE,
90 PIECE_WALL,
91 PIECE_PLAYER_ONE,
92 PIECE_PLAYER_TWO,
93 PIECE_DOTS_X,
94 PIECE_DOTS_Y,
95 PIECE_ARROW_RED_DOWN,
96 PIECE_ARROW_RED_LEFT,
97 PIECE_BOMB_RED_DOWN,
98 PIECE_BOMB_RED_LEFT,
99 PIECE_STAR,
100 PIECE_DOOR,
101 PIECE_CIRCLE,
102 PIECE_TELEPORT,
103 PIECE_SWITCH,
104 PIECE_MAP_TOP_LEFT,
105 PIECE_MAP_TOP_RIGHT,
106 PIECE_MAP_BOTTOM_LEFT,
107 PIECE_MAP_BOTTOM_RIGHT,
108 PIECE_GONE
109 };
110 #endif
111
112 #ifdef ENIGMA_COMPATIBILITY
113 int editor_pieces_enigma[] = {
114 PIECE_SPACE,
115 PIECE_WALL,
116 PIECE_PLAYER_ONE,
117 PIECE_DOTS,
118 PIECE_DOTS_DOUBLE,
119 PIECE_ARROW_RED_LEFT,
120 PIECE_ARROW_RED_UP,
121 PIECE_ARROW_RED_RIGHT,
122 PIECE_ARROW_RED_DOWN,
123 PIECE_BOMB_RED_LEFT,
124 PIECE_BOMB_RED_UP,
125 PIECE_BOMB_RED_RIGHT,
126 PIECE_BOMB_RED_DOWN,
127 PIECE_STAR,
128 PIECE_DOOR,
129 PIECE_CIRCLE,
130 PIECE_CIRCLE_DOUBLE,
131 PIECE_GONE
132 };
133 #endif
134
135 int *editor_piece_maps[] =
136 {
137 editor_pieces_chroma,
138 #ifdef XOR_COMPATIBILITY
139 editor_pieces_xor,
140 #endif
141 #ifdef ENIGMA_COMPATIBILITY
142 editor_pieces_enigma,
143 #endif
144 NULL
145 };
146
editor()147 void editor()
148 {
149 char filename[FILENAME_MAX];
150 char directory[FILENAME_MAX];
151 struct level* plevelload;
152 struct level* pleveltest;
153 struct menu* pmenu;
154 struct menu* pmenuconfirm;
155 struct menuentry* pentryno;
156 int ok;
157 int result;
158
159 plevelcurrent = NULL;
160
161 ok = 0;
162 while(!ok)
163 {
164 pmenu = menu_new(gettext("Editing Menu"));
165
166 if(plevelcurrent == NULL)
167 menuentry_new(pmenu, gettext("Return to Main Menu"), 'Q', 0);
168 else
169 {
170 menuentry_new(pmenu, gettext("Return to Editor"), 'Q', 0);
171 menuentry_new(pmenu, gettext("Abort Editor and Return to Main Menu"), 'A', 0);
172 }
173 menuentry_new(pmenu, "", 0, MENU_SPACE);
174
175 menuentry_new(pmenu, gettext("Load Level"), 'L', 0);
176 menuentry_new(pmenu, gettext("Save Level"), 'S', plevelcurrent == NULL ? MENU_GREY : 0);
177 menuentry_new(pmenu, gettext("Export Level"), 'E', plevelcurrent == NULL ? MENU_GREY : 0);
178 menuentry_new(pmenu, gettext("Test Level"), 'T', plevelcurrent == NULL ? MENU_GREY : 0);
179 menuentry_new(pmenu, gettext("Verify Level"), 'V', plevelcurrent == NULL ? MENU_GREY : 0);
180
181 menuentry_new(pmenu, "", 0, MENU_SPACE);
182
183 menuentry_new(pmenu, gettext("Level Options"), 'O', plevelcurrent == NULL ? MENU_GREY : 0);
184 menuentry_new(pmenu, "", 0, MENU_SPACE);
185
186 menuentry_new(pmenu, gettext("Display Options"), 'D', 0);
187
188 menuentry_new(pmenu, gettext("Currently editing:"), 0, MENU_NOTE);
189
190 if(plevelcurrent != NULL)
191 {
192 if(plevelcurrent->title == NULL || strcmp(plevelcurrent->title, "") == 0)
193 menuentry_new(pmenu, gettext("[untitled level]"), 0, MENU_NOTE | MENU_RIGHT);
194 else
195 menuentry_new(pmenu, gettext(plevelcurrent->title), 0, MENU_NOTE | MENU_RIGHT);
196 }
197 else
198 menuentry_new(pmenu, gettext("** NO LEVEL LOADED **"), 0, MENU_NOTE | MENU_RIGHT);
199
200 result = menu_process(pmenu);
201
202 if(result == MENU_SELECT && pmenu->entry_selected != NULL)
203 {
204 switch(pmenu->entry_selected->key)
205 {
206 case 'A':
207 ok = 1;
208 break;
209
210 case 'S':
211 getfilename("construct", directory, 1, 0);
212 if(menu_levelselector(directory, filename, gettext("Save Level"), LEVELMENU_RETURN | LEVELMENU_NEW | LEVELMENU_DELETE | LEVELMENU_FILENAMES) == MENU_SELECT)
213 {
214
215 if(strcmp(filename, "") == 0)
216 {
217 /* Create new file */
218 snprintf(filename, sizeof(filename), "%s/%x.chroma", directory, (int)time(NULL));
219 level_save(plevelcurrent, filename, 1);
220 }
221 else
222 {
223 /* Check file we're trying to save over */
224 pleveltest = level_load(filename, 1);
225
226 if(pleveltest != NULL && pleveltest->title != NULL)
227 {
228 if(plevelcurrent->title == NULL || strcmp(plevelcurrent->title, pleveltest->title) != 0)
229 {
230 pmenuconfirm = menu_new(gettext("Confirm Save"));
231
232 menuentry_new(pmenuconfirm, gettext("Do you wish to overwrite:"), 0, MENU_GREY);
233
234 if(pleveltest->title == NULL || strcmp(pleveltest->title, "") == 0)
235 menuentry_new(pmenuconfirm, gettext("[untitled level]"), 0, MENU_GREY | MENU_RIGHT);
236 else
237 menuentry_new(pmenuconfirm, pleveltest->title, 0, MENU_GREY | MENU_RIGHT);
238 menuentry_new(pmenuconfirm, gettext("with:"), 0, MENU_GREY);
239
240 if(plevelcurrent->title == NULL || strcmp(plevelcurrent->title, "") == 0)
241 menuentry_new(pmenuconfirm, gettext("[untitled level]"), 0, MENU_GREY | MENU_RIGHT);
242 else
243 menuentry_new(pmenuconfirm, plevelcurrent->title, 0, MENU_GREY | MENU_RIGHT);
244
245 menuentry_new(pmenuconfirm, "", 0, MENU_SPACE);
246
247 pentryno = menuentry_new(pmenuconfirm, gettext("No"), 'N', 0);
248 menuentry_new(pmenuconfirm, gettext("Yes"), 'Y', 0);
249
250 pmenuconfirm->entry_selected = pentryno;
251
252 result = menu_process(pmenuconfirm);
253 if(result == MENU_SELECT && pmenuconfirm->entry_selected != NULL && pmenuconfirm->entry_selected->key == 'Y')
254 level_save(plevelcurrent, filename, 1);
255
256 menu_delete(pmenuconfirm);
257
258 }
259 else
260 level_save(plevelcurrent, filename, 1);
261 }
262 else
263 level_save(plevelcurrent, filename, 1);
264
265 level_delete(pleveltest);
266 }
267 }
268 break;
269
270 case 'L':
271 getfilename("construct", directory, 1, 0);
272 if(menu_levelselector(directory, filename, gettext("Load Level"), LEVELMENU_RETURN | LEVELMENU_CREATE | LEVELMENU_DELETE | LEVELMENU_FILENAMES | LEVELMENU_IMPORT) == MENU_SELECT)
273 {
274 /* Create new level */
275 if(strcmp(filename, "") == 0)
276 plevelload = level_create(32, 23);
277 /* Load existing level */
278 else
279 plevelload = level_load(filename, 0);
280
281 if(plevelload != NULL)
282 {
283 level_delete(plevelcurrent);
284
285 plevelcurrent = plevelload;
286
287 /* Set editor position */
288 plevelcurrent->player_x[2] = 0;
289 plevelcurrent->player_y[2] = 0;
290 }
291 }
292 break;
293
294 case 'E':
295 export(plevelcurrent, 0);
296 break;
297
298 case 'T':
299 pleveltest = level_copy(plevelcurrent);
300 level_fix(pleveltest);
301 pleveltest->flags |= LEVELFLAG_TESTING;
302 display_play(pleveltest, NULL);
303 level_delete(pleveltest);
304 break;
305
306 case 'O':
307 plevelcurrent = editor_options(plevelcurrent);
308 break;
309
310 case 'D':
311 display_options();
312 break;
313
314 case 'V':
315 if(editor_verify(plevelcurrent))
316 result = MENU_QUIT;
317 break;
318
319 case 'Q':
320 result = MENU_QUIT;
321 break;
322
323 }
324 }
325
326 if(result == MENU_QUIT)
327 {
328 if(plevelcurrent != NULL)
329 display_edit(plevelcurrent);
330 else
331 ok = 1;
332 }
333
334 menu_delete(pmenu);
335
336 }
337
338 if(plevelcurrent != NULL)
339 level_delete(plevelcurrent);
340 plevelcurrent = NULL;
341 }
342
editor_verify(struct level * plevel)343 int editor_verify(struct level* plevel)
344 {
345 struct menu* pmenu;
346 struct menuentry* pentry;
347 int result;
348 int ok;
349 int x, y;
350 int p, p2;
351 int d;
352 int errors;
353 int i;
354 int count_playerone, count_playertwo, count_exit, count_teleport;
355 int count_map_tl, count_map_tr, count_map_bl, count_map_br;
356 int entries;
357 char buffer[4096];
358 int piece_ok[PIECE_MAX];
359
360 pmenu = menu_new(gettext("Verify Level"));
361
362 menuentry_new(pmenu, gettext("Return to Previous Menu"), 'Q', 0);
363
364 menuentry_new(pmenu, "", 0, MENU_SPACE);
365
366 errors = 0;
367 count_playerone = 0;
368 count_playertwo = 0;
369 count_exit = 0;
370 count_teleport = 0;
371 count_map_tl = 0;
372 count_map_tr = 0;
373 count_map_bl = 0;
374 count_map_br = 0;
375
376 for(i = 0; i < PIECE_MAX; i ++)
377 piece_ok[i] = 0;
378
379 i = 0;
380 while(editor_piece_maps[plevel->mode][i] != PIECE_GONE)
381 {
382 piece_ok[editor_piece_maps[plevel->mode][i]] = 1;
383 i ++;
384 }
385
386 for(y = 0; y < plevel->size_y; y ++)
387 {
388 for(x = 0; x < plevel->size_x; x ++)
389 {
390 p = level_piece(plevel, x, y);
391
392 if(p == PIECE_PLAYER_ONE)
393 count_playerone ++;
394 if(p == PIECE_PLAYER_TWO)
395 count_playertwo ++;
396 if(p == PIECE_DOOR)
397 count_exit ++;
398 #ifdef XOR_COMPATIBILITY
399 if(p == PIECE_TELEPORT)
400 count_teleport ++;
401 if(p == PIECE_MAP_TOP_LEFT)
402 count_map_tl ++;
403 if(p == PIECE_MAP_TOP_RIGHT)
404 count_map_tr ++;
405 if(p == PIECE_MAP_BOTTOM_LEFT)
406 count_map_bl ++;
407 if(p == PIECE_MAP_BOTTOM_RIGHT)
408 count_map_br ++;
409 #endif
410
411 if(!piece_ok[p])
412 {
413 sprintf(buffer, gettext("Invalid piece %s at (%d,%d)"), gettext(piece_name[p]), x, y);
414 pentry = menuentry_new(pmenu, buffer, 0, 0);
415 sprintf(buffer, "%d %d", x, y);
416 menuentry_value(pentry, buffer);
417 errors ++;
418 }
419
420 if(p >= PIECE_MOVERS_FIRST && p <= PIECE_MOVERS_LAST)
421 {
422 d = p % 4;
423 p2 = level_piece(plevel, x + move_x[d], y + move_y[d]);
424
425 if(canfall(p, p2, d))
426 {
427 sprintf(buffer, gettext("Unsupported %s resting on %s at (%d,%d)"), gettext(piece_name[p]), gettext(piece_name[p2]), x, y);
428 pentry = menuentry_new(pmenu, buffer, 0, 0);
429 sprintf(buffer, "%d %d", x, y);
430 menuentry_value(pentry, buffer);
431 errors ++;
432 }
433 }
434 }
435 }
436
437 if(count_playerone == 0)
438 {
439 sprintf(buffer, gettext("No %s"), gettext(piece_name[PIECE_PLAYER_ONE]));
440 pentry = menuentry_new(pmenu, buffer, 0, 0);
441 errors ++;
442 }
443
444 if(count_playertwo == 0)
445 {
446 #ifdef ENIGMA_COMPATIBILITY
447 if(plevel->mode != MODE_ENIGMA)
448 {
449 #endif
450 sprintf(buffer, gettext("No %s"), gettext(piece_name[PIECE_PLAYER_TWO]));
451 pentry = menuentry_new(pmenu, buffer, 0, 0);
452 errors ++;
453 #ifdef ENIGMA_COMPATIBILITY
454 }
455 #endif
456 }
457
458 if(count_exit == 0)
459 {
460 sprintf(buffer, gettext("No %s"), gettext(piece_name[PIECE_DOOR]));
461 pentry = menuentry_new(pmenu, buffer, 0, 0);
462 errors ++;
463 }
464
465 if(count_playerone > 1)
466 {
467 sprintf(buffer, gettext("Too many %s"), gettext(piece_name[PIECE_PLAYER_ONE]));
468 pentry = menuentry_new(pmenu, buffer, 0, 0);
469 errors ++;
470 }
471
472 if(count_playertwo > 1)
473 {
474 sprintf(buffer, gettext("Too many %s"), gettext(piece_name[PIECE_PLAYER_TWO]));
475 pentry = menuentry_new(pmenu, buffer, 0, 0);
476 errors ++;
477 }
478
479 #ifdef XOR_COMPATIBILITY
480 if(plevel->mode == MODE_XOR)
481 {
482 if(count_teleport != 0 && count_teleport != 2)
483 {
484 sprintf(buffer, gettext("Too many %s"), gettext(piece_name[PIECE_TELEPORT]));
485 pentry = menuentry_new(pmenu, buffer, 0, 0);
486 errors ++;
487 }
488
489 if(count_map_tl != 1)
490 {
491 if(count_map_tl == 0)
492 sprintf(buffer, gettext("No %s"), gettext(piece_name[PIECE_MAP_TOP_LEFT]));
493 else
494 sprintf(buffer, gettext("Too many %s"), gettext(piece_name[PIECE_MAP_TOP_LEFT]));
495 pentry = menuentry_new(pmenu, buffer, 0, 0);
496 errors ++;
497 }
498
499 if(count_map_tr != 1)
500 {
501 if(count_map_tr == 0)
502 sprintf(buffer, gettext("No %s"), gettext(piece_name[PIECE_MAP_TOP_RIGHT]));
503 else
504 sprintf(buffer, gettext("Too many %s"), gettext(piece_name[PIECE_MAP_TOP_RIGHT]));
505 pentry = menuentry_new(pmenu, buffer, 0, 0);
506 errors ++;
507 }
508
509 if(count_map_bl != 1)
510 {
511 if(count_map_bl == 0)
512 sprintf(buffer, gettext("No %s"), gettext(piece_name[PIECE_MAP_BOTTOM_LEFT]));
513 else
514 sprintf(buffer, gettext("Too many %s"), gettext(piece_name[PIECE_MAP_BOTTOM_LEFT]));
515 pentry = menuentry_new(pmenu, buffer, 0, 0);
516 errors ++;
517 }
518
519 if(count_map_br != 1)
520 {
521 if(count_map_br == 0)
522 sprintf(buffer, gettext("No %s"), gettext(piece_name[PIECE_MAP_BOTTOM_RIGHT]));
523 else
524 sprintf(buffer, gettext("Too many %s"), gettext(piece_name[PIECE_MAP_BOTTOM_RIGHT]));
525 pentry = menuentry_new(pmenu, buffer, 0, 0);
526 errors ++;
527 }
528 }
529 #endif
530
531 entries = 1;
532 pentry = pmenu->entry_first;
533 while(pentry != NULL && entries < 11)
534 {
535 if(pentry->key == 0 && !(pentry->flags & (MENU_GREY | MENU_NOTE | MENU_SPACE)))
536 {
537 pentry->key = '0' + (entries % 10);
538 entries ++;
539 }
540
541 pentry = pentry->next;
542 }
543
544 if(errors == 1)
545 sprintf(buffer, gettext("%d error found"), errors);
546 else
547 sprintf(buffer, gettext("%d errors found"), errors);
548 menuentry_new(pmenu, buffer, 0, MENU_NOTE | MENU_CENTRE);
549
550 ok = 0;
551 while(!ok)
552 {
553 result = menu_process(pmenu);
554
555 if(result == MENU_SELECT && pmenu->entry_selected != NULL)
556 {
557 if(pmenu->entry_selected->value != NULL)
558 {
559 i = sscanf(pmenu->entry_selected->value, "%d %d", &x, &y);
560 if(i == 2)
561 {
562 plevel->player_x[2] = x;
563 plevel->player_y[2] = y;
564 ok = 2;
565 }
566 }
567 else
568 ok = 1;
569 }
570
571 if(result == MENU_QUIT)
572 ok = 1;
573 }
574
575 menu_delete(pmenu);
576
577 if(ok == 2)
578 return 1;
579
580 return 0;
581 }
582
editor_options(struct level * plevel)583 struct level* editor_options(struct level* plevel)
584 {
585 struct level* plevel_new;
586 struct menu* pmenu;
587 struct menuentry* pentry_mode;
588 struct menuentry* pentry_left;
589 struct menuentry* pentry_right;
590 struct menuentry* pentry_top;
591 struct menuentry* pentry_bottom;
592 struct menuentry* pentry_width;
593 struct menuentry* pentry_height;
594 struct menuentry* pentry_rotate;
595 struct menuentry* pentry_title;
596 int result;
597 int padding_left;
598 int padding_right;
599 int padding_top;
600 int padding_bottom;
601 int width, height;
602 int delta_left, delta_right, delta_top, delta_bottom;
603 int x, y;
604 int ok;
605 int rotate = 0;
606 int p, d;
607 char buffer[256];
608
609 pmenu = menu_new(gettext("Level Options"));
610
611 padding_left = 0; ok = 1;
612 for(x = 1; x <= plevel->size_x - 2; x ++)
613 {
614 for(y = 1; y <= plevel->size_y - 2; y ++)
615 {
616 if(level_piece(plevel, x, y) != PIECE_SPACE)
617 ok = 0;
618 }
619 if(ok == 1)
620 padding_left ++;
621 else
622 break;
623 }
624
625 padding_right = 0; ok = 1;
626 for(x = plevel->size_x -2 ; x >= 1; x --)
627 {
628 for(y = 1; y <= plevel->size_y - 2; y ++)
629 {
630 if(level_piece(plevel, x, y) != PIECE_SPACE)
631 ok = 0;
632 }
633 if(ok == 1)
634 padding_right ++;
635 else
636 break;
637 }
638
639 padding_top = 0; ok = 1;
640 for(y = 1; y <= plevel->size_y - 2; y ++)
641 {
642 for(x = 1; x <= plevel->size_x - 2; x ++)
643 {
644 if(level_piece(plevel, x, y) != PIECE_SPACE)
645 ok = 0;
646 }
647 if(ok == 1)
648 padding_top ++;
649 else
650 break;
651 }
652
653 padding_bottom = 0; ok = 1;
654 for(y = plevel->size_y -2 ; y >= 1; y --)
655 {
656 for(x = 1; x <= plevel->size_x - 2; x ++)
657 {
658 if(level_piece(plevel, x, y) != PIECE_SPACE)
659 ok = 0;
660 }
661 if(ok == 1)
662 padding_bottom ++;
663 else
664 break;
665 }
666
667 width = plevel->size_x;
668 height = plevel->size_y;
669
670 delta_left = 0;
671 delta_right = 0;
672 delta_top = 0;
673 delta_bottom = 0;
674
675 /* Create menu entries */
676 menuentry_new(pmenu, gettext("Return to previous menu"), 'Q', 0);
677 menuentry_new(pmenu, "", 0, MENU_SPACE);
678
679 pentry_title = menuentry_new(pmenu, gettext("Title"), 'I', MENU_DOUBLE | MENU_EDITABLE);
680 if(plevel->title != NULL)
681 menuentry_extratext(pentry_title, NULL, NULL, plevel->title);
682 else
683 menuentry_extratext(pentry_title, NULL, NULL, "");
684
685 menuentry_new(pmenu, "", 0, MENU_SPACE);
686
687 if(MODE_CHROMA == MODE_MAX - 1)
688 pentry_mode = NULL;
689 else
690 {
691 pentry_mode = menuentry_new(pmenu, gettext("Level Mode"), 'M', MENU_SCROLLABLE);
692 menuentry_new(pmenu, "", 0, MENU_SPACE);
693 }
694
695 pentry_width = menuentry_new(pmenu, gettext("Level width"), 0, MENU_GREY);
696 pentry_left = menuentry_new(pmenu, gettext("Padding on left edge"), 'L', MENU_SCROLLABLE);
697 pentry_right = menuentry_new(pmenu, gettext("Padding on right edge"), 'R', MENU_SCROLLABLE);
698 menuentry_new(pmenu, "", 0, MENU_SPACE);
699
700 pentry_height = menuentry_new(pmenu, gettext("Level height"), 0, MENU_GREY);
701 pentry_top = menuentry_new(pmenu, gettext("Padding on top edge"), 'T', MENU_SCROLLABLE);
702 pentry_bottom = menuentry_new(pmenu, gettext("Padding on bottom edge"), 'B', MENU_SCROLLABLE);
703 menuentry_new(pmenu, "", 0, MENU_SPACE);
704
705 pentry_rotate = menuentry_new(pmenu, gettext("Rotate"), 'O', MENU_SCROLLABLE);
706 menuentry_new(pmenu, "", 0, MENU_SPACE);
707
708 /* Menu loop */
709 ok = 0;
710 while(ok == 0)
711 {
712 if(plevel->mode == MODE_CHROMA)
713 pentry_rotate->flags &= ~MENU_GREY;
714 else
715 pentry_rotate->flags |= MENU_GREY;
716
717 /* Fill in values for menu entries */
718 switch(plevel->mode)
719 {
720 case MODE_CHROMA:
721 if(pentry_mode != NULL)
722 menuentry_extratext(pentry_mode, gettext("Chroma"), NULL, NULL);
723 if(width != 32)
724 menuentry_text(pentry_width, gettext("Level width (Chroma standard is 32)"));
725 else
726 menuentry_text(pentry_width, gettext("Level width"));
727
728 if(height != 23)
729 menuentry_text(pentry_height, gettext("Level height (Chroma standard is 23)"));
730 else
731 menuentry_text(pentry_height, gettext("Level height"));
732 break;
733
734 #ifdef XOR_COMPATIBILITY
735 case MODE_XOR:
736 menuentry_extratext(pentry_mode, gettext("XOR"), NULL, NULL);
737
738 if(width != 32)
739 menuentry_text(pentry_width, gettext("Level width (XOR standard is 32)"));
740 else
741 menuentry_text(pentry_width, gettext("Level width"));
742
743 if(height != 32)
744 menuentry_text(pentry_height, gettext("Level height (XOR standard is 32)"));
745 else
746 menuentry_text(pentry_height, gettext("Level height"));
747
748 break;
749 #endif
750
751 #ifdef ENIGMA_COMPATIBILITY
752 case MODE_ENIGMA:
753 menuentry_extratext(pentry_mode, gettext("Enigma"), NULL, NULL);
754
755 if(width != 36)
756 menuentry_text(pentry_width, gettext("Level width (Enigma standard is 36)"));
757 else
758 menuentry_text(pentry_width, gettext("Level width"));
759
760 if(height != 20)
761 menuentry_text(pentry_height, gettext("Level height (Enigma standard is 20)"));
762 else
763 menuentry_text(pentry_height, gettext("Level height"));
764
765 break;
766 #endif
767
768 }
769
770 sprintf(buffer, "%d", width);
771 menuentry_extratext(pentry_width, buffer, NULL, NULL);
772
773 sprintf(buffer, "%d", padding_left);
774 menuentry_extratext(pentry_left, buffer, NULL, NULL);
775
776 sprintf(buffer, "%d", padding_right);
777 menuentry_extratext(pentry_right, buffer, NULL, NULL);
778
779 sprintf(buffer, "%d", height);
780 menuentry_extratext(pentry_height, buffer, NULL, NULL);
781
782 sprintf(buffer, "%d", padding_top);
783 menuentry_extratext(pentry_top, buffer, NULL, NULL);
784
785 sprintf(buffer, "%d", padding_bottom);
786 menuentry_extratext(pentry_bottom, buffer, NULL, NULL);
787
788 if(plevel->mode == MODE_CHROMA)
789 {
790 sprintf(buffer, gettext("%d degrees"), rotate * 90);
791 menuentry_extratext(pentry_rotate, buffer, NULL, NULL);
792 }
793 else
794 menuentry_extratext(pentry_rotate, gettext("(only for Chroma levels)"), NULL, NULL);
795
796 /* Display menu */
797 result = menu_process(pmenu);
798
799 /* Process results */
800 if(result == MENU_QUIT)
801 ok = 1;
802
803 if(result == MENU_SELECT && pmenu->entry_selected != NULL)
804 {
805 switch(pmenu->entry_selected->key)
806 {
807 case 'Q':
808 ok = 1;
809 break;
810 }
811 }
812
813 if(result == MENU_SCROLLLEFT && pmenu->entry_selected != NULL)
814 {
815 switch(pmenu->entry_selected->key)
816 {
817 case 'M':
818 plevel->mode --;
819 if(plevel->mode < 0)
820 plevel->mode = MODE_MAX - 1;
821 #ifdef XOR_COMPATIBILITY
822 if(plevel->mode == MODE_XOR)
823 options_xor_options = 1;
824 #endif
825 #ifdef ENIGMA_COMPATIBILITY
826 if(plevel->mode == MODE_ENIGMA)
827 options_enigma_options = 1;
828 #endif
829 pentry_height->redraw = 1;
830 pentry_width->redraw = 1;
831 pentry_mode->redraw = 1;
832 pentry_rotate->redraw = 1;
833 break;
834
835 case 'L':
836 if(width > 2)
837 {
838 delta_left --;
839 padding_left --;
840 width --;
841
842 pentry_left->redraw = 1;
843 pentry_width->redraw = 1;
844 }
845 break;
846
847 case 'R':
848 if(width > 2)
849 {
850 delta_right --;
851 padding_right --;
852 width --;
853
854 pentry_right->redraw = 1;
855 pentry_width->redraw = 1;
856 }
857 break;
858
859 case 'T':
860 if(height > 2)
861 {
862 delta_top --;
863 padding_top --;
864 height --;
865
866 pentry_top->redraw = 1;
867 pentry_height->redraw = 1;
868 }
869 break;
870
871 case 'B':
872 if(height > 2)
873 {
874 delta_bottom --;
875 padding_bottom --;
876 height --;
877
878 pentry_bottom->redraw = 1;
879 pentry_height->redraw = 1;
880 }
881 break;
882
883 case 'O':
884 rotate -= 1;
885 if(rotate == -1)
886 rotate = 3;
887 break;
888
889 }
890
891 }
892
893 if(result == MENU_SCROLLRIGHT && pmenu->entry_selected != NULL)
894 {
895 switch(pmenu->entry_selected->key)
896 {
897 case 'M':
898 plevel->mode ++;
899 if(plevel->mode == MODE_MAX)
900 plevel->mode = 0;
901 #ifdef XOR_COMPATIBILITY
902 if(plevel->mode == MODE_XOR)
903 options_xor_options = 1;
904 #endif
905 #ifdef ENIGMA_COMPATIBILITY
906 if(plevel->mode == MODE_ENIGMA)
907 options_enigma_options = 1;
908 #endif
909 pentry_height->redraw = 1;
910 pentry_width->redraw = 1;
911 pentry_mode->redraw = 1;
912 pentry_rotate->redraw = 1;
913 break;
914
915 case 'L':
916 if(width < 256)
917 {
918 delta_left ++;
919 padding_left ++;
920 width ++;
921
922 pentry_left->redraw = 1;
923 pentry_width->redraw = 1;
924 }
925 break;
926
927 case 'R':
928 if(width < 256)
929 {
930 delta_right ++;
931 padding_right ++;
932 width ++;
933
934 pentry_right->redraw = 1;
935 pentry_width->redraw = 1;
936 }
937 break;
938
939 case 'T':
940 if(height < 256)
941 {
942 delta_top ++;
943 padding_top ++;
944 height ++;
945
946 pentry_top->redraw = 1;
947 pentry_height->redraw = 1;
948 }
949 break;
950
951 case 'B':
952 if(height < 256)
953 {
954 delta_bottom ++;
955 padding_bottom ++;
956 height ++;
957
958 pentry_bottom->redraw = 1;
959 pentry_height->redraw = 1;
960 }
961 break;
962
963 case 'O':
964 rotate += 1;
965 if(rotate == 4)
966 rotate = 0;
967 break;
968 }
969 }
970 }
971
972 /* Set new title */
973 if(pentry_title->text4 != NULL)
974 {
975 level_settitle(plevel, pentry_title->text4);
976 /* Easier than editing the configuration file! */
977 if(strcmp(pentry_title->text4, "debug") == 0)
978 options_debug |= DEBUG_MENU;
979 }
980
981 /* Resize the level if necessary */
982 if(delta_left != 0 || delta_right != 0 || delta_top != 0 || delta_bottom != 0 )
983 {
984
985 /* Create a new level */
986 plevel_new = level_create(width, height);
987
988 /* Copy pieces into it */
989 for(x = 1; x <= plevel->size_x - 2; x ++)
990 {
991 for(y = 1; y <= plevel->size_y - 2; y ++)
992 {
993 level_setpiece(plevel_new, x + delta_left, y + delta_top, level_piece(plevel, x, y));
994 }
995 }
996
997 /* Force borders */
998 for(x = 0; x<= plevel_new->size_x - 1; x ++)
999 {
1000 level_setpiece(plevel_new, x, 0, PIECE_WALL);
1001 level_setpiece(plevel_new, x, plevel_new->size_y - 1, PIECE_WALL);
1002 }
1003 for(y = 0; y<= plevel_new->size_y - 1; y ++)
1004 {
1005 level_setpiece(plevel_new, 0, y, PIECE_WALL);
1006 level_setpiece(plevel_new, plevel_new->size_x - 1, y, PIECE_WALL);
1007 }
1008
1009 /* If the original padding on any edge was zero, add a wall */
1010 if(padding_left - delta_left == 0)
1011 {
1012 for(y = 1; y <= plevel->size_y - 2; y ++)
1013 {
1014 level_setpiece(plevel_new, padding_left, y, PIECE_WALL);
1015 }
1016 }
1017 if(padding_right - delta_right == 0)
1018 {
1019 for(y = 1; y <= plevel->size_y - 2; y ++)
1020 {
1021 level_setpiece(plevel_new, plevel_new->size_x - 1 - padding_right, y, PIECE_WALL);
1022 }
1023 }
1024 if(padding_top - delta_top == 0)
1025 {
1026 for(x = 1; x <= plevel->size_x - 2; x ++)
1027 {
1028 level_setpiece(plevel_new, x, padding_top, PIECE_WALL);
1029 }
1030 }
1031 if(padding_bottom - delta_bottom == 0)
1032 {
1033 for(x = 1; x <= plevel->size_x - 2; x ++)
1034 {
1035 level_setpiece(plevel_new, x, plevel_new->size_y - 1 - padding_bottom, PIECE_WALL);
1036 }
1037 }
1038
1039 /* Copy level options */
1040 plevel_new->mode = plevel->mode;
1041 level_settitle(plevel_new, plevel->title);
1042
1043 /* Delete old level */
1044 level_delete(plevel);
1045 plevel = plevel_new;
1046 }
1047
1048 /* Rotate the level if necessary */
1049 if(rotate != 0)
1050 {
1051 if(rotate == 2)
1052 {
1053 width = plevel->size_x;
1054 height = plevel->size_y;
1055 }
1056 else
1057 {
1058 width = plevel->size_y;
1059 height = plevel->size_x;
1060 }
1061
1062 /* Create a new level */
1063 plevel_new = level_create(width, height);
1064
1065 /* Copy pieces into it */
1066 for(x = 1; x <= plevel_new->size_x - 2; x ++)
1067 {
1068 for(y = 1; y <= plevel_new->size_y - 2; y ++)
1069 {
1070 switch(rotate)
1071 {
1072 case 1:
1073 p = level_piece(plevel, y, plevel->size_y - 1 - x);
1074 break;
1075 case 2:
1076 p = level_piece(plevel, plevel->size_x - 1 - x, plevel->size_y - 1 - y);
1077 break;
1078 case 3:
1079 p = level_piece(plevel, plevel->size_x - 1 - y, x);
1080 break;
1081 default:
1082 p = level_piece(plevel, x, y);
1083 break;
1084 }
1085 if(p >= PIECE_MOVERS_FIRST && p <= PIECE_MOVERS_LAST)
1086 {
1087 d = p % 4;
1088 p = p - d + ((d + rotate) % 4);
1089 }
1090 level_setpiece(plevel_new, x, y, p);
1091 }
1092 }
1093
1094 /* Force borders */
1095 for(x = 0; x<= plevel_new->size_x - 1; x ++)
1096 {
1097 level_setpiece(plevel_new, x, 0, PIECE_WALL);
1098 level_setpiece(plevel_new, x, plevel_new->size_y - 1, PIECE_WALL);
1099 }
1100 for(y = 0; y<= plevel_new->size_y - 1; y ++)
1101 {
1102 level_setpiece(plevel_new, 0, y, PIECE_WALL);
1103 level_setpiece(plevel_new, plevel_new->size_x - 1, y, PIECE_WALL);
1104 }
1105
1106 /* Copy level options */
1107 plevel_new->mode = plevel->mode;
1108
1109 level_settitle(plevel_new, plevel->title);
1110
1111 /* Delete old level */
1112 level_delete(plevel);
1113 plevel = plevel_new;
1114 }
1115
1116 return plevel;
1117 }
1118
1119