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