1 /* File edit.c */
2 /***************************************************************************
3 *  Copyright 2003 -   Steven Shipway <steve@cheshire.demon.co.uk>          *
4 *                     Put "nospam" in subject to avoid spam filter         *
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               *
19 *  02111-1307, USA.                                                        *
20 ***************************************************************************/
21 
22 
23 #include <stdlib.h>
24 #include "wand_head.h"
25 
26 extern char *playscreen();
27 extern void helpme();
28 extern int inform_me();
29 
30 extern int debug_disp;
31 extern char *edit_screen;
32 extern char screen[NOOFROWS][ROWLEN+1];
33 extern char *edit_memory;
34 extern char *memory_end;
35 extern char screen_name[61];
36 
37 static char *inst[] = { "    O  Boulder",
38                         "  < >  Arrows",
39                         "    ^  Balloon",
40                         "    :  Earth",
41                         "    !  Landmine",
42                         "    *  Treasure",
43                         "  / \\  Deflectors",
44                         "    +  Cage",
45                         "_ = #  Rock (# indestructable)",
46                         "    T  Teleport",
47                         "    A  Arrival (1 max)",
48                         "    X  Exit (always 1)",
49                         "    @  Start (always 1)",
50                         "    M  Big Monster (1 max)",
51                         "    S  Baby Monster",
52                         "    -  Alternative space",
53                         "    C  Time Capsule",
54                         "    ~  Thingy",
55                         "    B  Bomb",
56                         NULL };
57 
58 /*********************************************************
59 *                      check_legality                    *
60 *   this will check: baby monster vs cage numbers,       *
61 *                    teleport, large monster,            *
62 *                    exit and player numbers,            *
63 *                    hanging boulders/arrows etc         *
64 **********************************************************/
check_legality()65 check_legality()
66 {
67 int ercount,cages,hanging,bmons,tele,arrival,you,mons,exits;
68 int x, y;
69 char buf[80];
70 ercount = hanging = cages = bmons = tele = arrival = you = mons = exits = 0;
71 
72 move(20,0);
73 addstr("Checking screen legality..."); refresh();
74 for( x = 0 ; x < ROWLEN ; x++)
75     for( y = 0 ; y < NOOFROWS ; y++) {
76         move(y+1,x+1); addch('?'); refresh();
77         switch(screen[y][x]) {
78           case '+': cages++; break;
79           case 'S': bmons++; break;
80           case 'T': tele++; break;
81           case 'A': arrival++; break;
82           case '@': you++; break;
83           case 'M': mons++; break;
84           case 'X': exits++; break;
85           case '-':
86           case ' ': if((screen[y-1][x] == 'O')&&(y>0)) hanging++;
87                     if((screen[y+1][x] == '^')&&(y<NOOFROWS)) hanging++;
88                     if((screen[y][x-1] == '>')&&(x>0)) hanging++;
89                     if((screen[y][x+1] == '<')&&(x<ROWLEN)) hanging++;
90                     break;
91           default : break;
92         }
93         move(y+1,x+1); addch(screen[y][x]);
94     }
95 move(20,0); addstr("                         ");
96 if(cages != bmons) {
97         ercount++;
98         if( cages < bmons )
99             sprintf(buf,"++++ Warning: %d cage(s), %d baby monster(s).",cages,bmons);
100         else
101             sprintf(buf,"**** Cage imbalance: %d cage(s), %d baby monster(s).",cages,bmons);
102         if(inform_me(buf,1)) return;
103 }
104 if(tele > 1) {
105         ercount++;
106         if(inform_me("++++ Warning: Too many teleports",1)) return;
107 }
108 if(arrival > ((tele>0)?1:0)) {
109         ercount++;
110         if(tele == 0) {
111             if(inform_me("**** No arrivals without teleports.",1)) return;
112         } else if(inform_me("**** Too many arrivals.",1)) return;
113 }
114 if(( arrival == 0 ) && ( tele > 0 )) {
115         ercount++;
116         if(inform_me("**** No arrival for teleport.",1)) return;
117 }
118 if( you != 1 ) {
119         ercount++;
120         if( you == 0 ) {
121             if(inform_me("**** No start position.",1)) return;
122         } else if(inform_me("**** Too many start positions.",1))return;
123 }
124 if( mons > 1 ) {
125         ercount++;
126         if(inform_me("**** Too many monsters.",1))return;
127 }
128 if( exits != 1 ) {
129         ercount++;
130         if( exits == 0 ) {
131             if(inform_me("**** No exit to screen.",1))return;
132         } else if(inform_me("++++ Warning: Too many exits.",1))return;
133 }
134 if( hanging > 0 ) {
135         sprintf(buf,"++++ Warning: %d hanging boulders/arrows/balloons.",hanging);
136         if(inform_me(buf,1)) return;
137 }
138 ercount += hanging;
139 move(19,0);
140 if( ercount == 0 ) inform_me("---- Screen OK.",0);
141 else {
142     sprintf(buf,"---- Total errors: %d",ercount);
143     inform_me(buf,0);
144 }
145 refresh();
146 }
147 
148 /**************************************************************
149 *                          readstring                         *
150 ***************************************************************/
readstring(str,size)151 void readstring(str,size)
152     char *str;
153     int size;
154 {
155   int count = 0;
156   char ch;
157   for(;;) {
158     ch = getch();
159     if( ch == '\n' ) {
160         *str = '\0';
161         break;
162     }
163     if(( ch == '\010') || ( ch == '\177' )) {
164         if(count == 0)
165                 continue;
166         str--; count--;
167         addstr("\b \b");
168         refresh();
169         continue;
170     }
171     if(count == size) {
172         printf("\007");
173         continue;
174     }
175     addch(ch);
176     *str = ch;
177     str++; count++;
178     refresh();
179   }
180 }
181 
clearbottom()182 clearbottom()
183 {
184 move(20,0);
185 addstr("                                                                            \n");
186 addstr("                                                                            \n");
187 addstr("                                                                            ");
188 }
189 
190 /*****************************************
191 *                 instruct               *
192 *  Print instructions around the screen  *
193 ******************************************/
instruct()194 void instruct()
195 {
196 int loop;
197 for(loop = 0; inst[loop] ; loop++)
198     {
199     move(loop,45);
200     addstr(inst[loop]);
201     }
202 move(21,0);
203 addstr("c: change name, m: change moves, q: save and exit, n/p: play game\n");
204 addstr("Press '?' for full editor instructions. Use wanderer keys to move.");
205 }
206 
207 
208 /************************************************
209 *                     noins                     *
210 *************************************************/
noins()211 void noins()
212 {
213 int loop;
214 for(loop =0; inst[loop] ; loop++)
215     {
216     move(loop,45);
217     addstr("                              ");
218     }
219 clearbottom();
220 }
221 
222 /********************************
223 *          screen_save          *
224 *  save and restore screen data *
225 *********************************/
screen_save(maxmoves)226 screen_save(maxmoves)
227 int maxmoves;
228 {
229 char file[90];
230 char *oldname;
231 int y;
232 
233 clearbottom();
234 move(20,0);
235 addstr("Filename to write to? :");
236 if(edit_screen)
237     addstr(edit_screen);
238 else
239     addstr("./screen");
240 move(20,23); refresh();
241 addstr("                                   "); move(20,23);
242 readstring(file,89);
243 move(20,0);
244 addstr("                                                                           "); refresh();
245 oldname = edit_screen;
246 if( file[0] ) edit_screen = file;
247 for(y = 0; y<=NOOFROWS;y++)        /* make sure screen written */
248     if(screen[y][ROWLEN-1] == ' ') /* correctly...             */
249         screen[y][ROWLEN-1] = '-';
250 wscreen(0,maxmoves);
251 for(y = 0; y<=NOOFROWS;y++)
252     if(screen[y][ROWLEN-1] == '-')
253         screen[y][ROWLEN-1] = ' ';
254 edit_screen = oldname;
255 }
256 
257 /*********************************************
258 *                 screen_read                *
259 **********************************************/
screen_read(maxmoves)260 screen_read(maxmoves)
261     int *maxmoves;
262 {
263     static char file[90];
264     int y;
265 
266     clearbottom();
267     move(20,0);
268     addstr("Filename to read from? :");
269     addstr("Forget it");
270     move(20,24); refresh();
271     addstr("                                   "); move(20,24);
272     readstring(file,89);
273     move(20,0);
274     addstr("                                                                           "); refresh();
275     if( ! file[0] ) return;
276     edit_screen = file;
277     rscreen(0,maxmoves);
278     for(y = 0; y<=NOOFROWS;y++)
279         if(screen[y][ROWLEN-1] == '-')
280             screen[y][ROWLEN-1] = ' ';
281 }
282 
283 
284 /*************************************
285 *              edit_save             *
286 *  save and restore edit memory data *
287 **************************************/
edit_save()288 edit_save()
289 {
290     char file[90];
291     int i = 0,fd;
292 
293     clearbottom();
294     move(20,0);
295     addstr("Filename to save? :"); refresh();
296     readstring(file,89);
297     move(20,0); addstr("                                                                           "); refresh();
298     if(( fd = open(file,O_WRONLY|O_CREAT|O_TRUNC,0644)) == -1 ) {
299         inform_me("File cannot be opened for writing.",0);
300     } else {
301         i = write(fd, edit_memory, (int)(memory_end - edit_memory));
302     if( i < 0 ) inform_me("Write error on file.",0);
303     }
304     instruct();
305 }
306 
307 /*******************************************
308 *                edit_restore              *
309 ********************************************/
edit_restore()310 edit_restore()
311 {
312 char file[90];
313 int i = 0,fd;
314 
315 clearbottom();
316 move(20,0);
317 addstr("Filename to load? :"); refresh();
318 readstring(file,89);
319 move(20,0); addstr("                                                                           "); refresh();
320 move(19,0);
321 if(( fd = open(file,O_RDONLY)) == -1 ) {
322     inform_me("File cannot be opened for reading.",0);
323 } else {
324     i = read(fd, edit_memory, EMSIZE);
325     if( i < 0 ) inform_me("Read error on file.",0);
326     if( i == 0 ) inform_me("File empty.",0);
327     if( i > 0 ) {
328         sprintf(file,"Read in %d moves.",i);
329         inform_me(file,0);
330         memory_end = edit_memory + i;
331     }
332 }
333 instruct();
334 }
335 
336 /*************************
337 *       editscreen       *
338 *  Actual edit function  *
339 **************************/
editscreen(num,score,bell,maxmoves,keys)340 void editscreen(num,score,bell,maxmoves,keys)
341     int num;
342     int maxmoves, *bell, *score;
343     char keys[10];
344 {
345     int  mmbkup,x,y,sx=0,sy=0,quit=0,nx,ny,nosave =0;
346     char (*frow)[ROWLEN+1] = screen,
347          ch;
348     char buffer[50];
349     char *howdead;
350     char *storage;
351 
352     if((storage = (char *) malloc(sizeof(screen)))== NULL) {
353         addstr("OOps... cant malloc a backup screen!\n\n");
354         return;
355     }
356 
357     for(x=0;x<=ROWLEN;x++)
358         for(y=0;y<NOOFROWS;y++)
359         {
360             if(screen[y][x] == '@')
361             {
362                 sx = x;
363                 sy = y;
364             }
365             if(screen[y][x] == '-')
366                 screen[y][x] = ' ';
367         };
368     x=sx;
369     y=sy;
370     if(maxmoves != 0)
371         (void) sprintf(buffer,"Moves   : %d        ",maxmoves);
372     else
373         (void) strcpy(buffer,"Moves   : Unlimited");
374     debug_disp=1;
375     map(frow);
376     move(18,0);
377     addstr(buffer);
378     move(19,0);
379     addstr("                                                                          ");
380     move(19,0);
381     addstr("Name    : ");
382     addstr(screen_name);
383 
384 /* ACTUAL EDIT FUNCTION */
385 
386     instruct();
387 /* HERE */
388 /* Beginning of long while loop */
389 while(!quit)
390 {
391     move(y+1,x+1);
392     refresh();
393     ch = (char)getchar();
394 
395     nx=x;
396     ny=y;
397 
398     if(ch == keys[3]||ch == keys[2]||ch == keys[1]||ch == keys[0])
399     {
400         if(ch == keys[3])
401            nx++;
402         if(ch == keys[2])
403                 nx--;
404         if(ch == keys[1])
405             ny++;
406         if(ch == keys[0])
407             ny--;
408     }
409     else if(ch == 'q')
410     {
411         clearbottom();
412         break;
413     }
414     else if(ch == 'x')
415     {
416         clearbottom();
417         move(20,0);
418         addstr("You will lose any changes made this session - are you sure? (y/n)");
419         refresh();
420         ch = getch();
421         if(ch != 'y')
422         {
423             noins();
424             instruct();
425             refresh();
426             }
427         else
428         {
429             nosave = 1;
430             addstr("\n");
431             refresh();
432             break;
433             }
434     }
435     else if(ch == 'm')         /* change to number of moves for the screen */
436     {
437         clearbottom();
438         move(21,0);
439         addstr("How many moves for this screen? :");
440         refresh();echo();
441         scanf("%d",&maxmoves);noecho();
442         if(maxmoves < 0 ) maxmoves = 0;
443         if(maxmoves != 0)
444             (void) sprintf(buffer,"Moves   : %d        ",maxmoves);
445         else
446             (void) strcpy(buffer,"Moves   : Unlimited ");
447         instruct();
448         move(18,0);
449         addstr(buffer);
450         refresh();        /* for some reason, this seems to add a '.' to */
451                               /* the map... Ive no idea why yet... */
452         }
453     else if(ch == 'c') {        /* change name */
454         clearbottom();
455         move(21,0);
456         addstr("New name: ");
457         refresh();
458         readstring(screen_name,58);
459         screen_name[61] = '\0';
460         instruct();
461         move(19,0);
462         addstr("                                                                          ");
463         move(19,0);
464         addstr("Name    : ");
465         addstr(screen_name);
466         refresh();
467     }
468     else if(ch == 'p' || ch == 'n')       /* play the game (test) */
469     {
470             noins();
471             mmbkup = maxmoves;
472             bcopy(screen,storage,sizeof(screen));
473             if(ch == 'p')
474         {
475                 debug_disp = 0;
476                 clear();
477         }
478             *score = 0;
479             howdead = playscreen(&num,score,bell,maxmoves,keys);
480             move(20,0);
481             if(howdead!=0)
482                 addstr(howdead);
483             else
484                 addstr("DONE!");
485             printw("; hit any key to continue\n");
486             refresh();
487             ch = (char)getchar();
488             clear();
489             bcopy(storage,screen,sizeof(screen));
490             maxmoves = mmbkup;
491             debug_disp = 1;
492             map(frow);
493             if(maxmoves != 0)
494                 (void) sprintf(buffer,"Moves   : %d        \n",maxmoves);
495             else
496                 (void) strcpy(buffer,"Moves   : Unlimited\n");
497             move(18,0);
498             addstr(buffer);
499             addstr("Name    : ");
500             addstr(screen_name);
501             instruct();
502     }
503     else if(ch == 18) {  /* ctrl r -- read memory data */
504         edit_restore();
505     }
506     else if( ch == 23) { /* ctrl w -- write memory data */
507         edit_save();
508     }
509     else if( ch == 7 ) { /* ctrl g -- read screen */
510         screen_read(&maxmoves);
511         map(frow);
512         instruct();
513     }
514     else if( ch == 16 ) { /* ctrl p -- write screen */
515         screen_save(maxmoves);
516         instruct();
517     }
518     else if( ch == 12 ) { /* ctrl l -- redraw screen  */
519         clear();
520         map(frow);
521         if(maxmoves != 0)
522                 (void) sprintf(buffer,"Moves   : %d        \n",maxmoves);
523         else
524             (void) strcpy(buffer,"Moves   : Unlimited\n");
525         move(18,0);
526         addstr(buffer);
527         addstr("Name    : ");
528         addstr(screen_name);
529         instruct();
530     }
531     else if( ch == 'L' ) {
532         clearbottom();
533         check_legality();
534         instruct();
535     }
536     else if(ch == '?' ) {
537         helpme(0);
538         if(maxmoves != 0)
539             (void) sprintf(buffer,"Moves   : %d        \n",maxmoves);
540         else
541                 (void) strcpy(buffer,"Moves   : Unlimited\n");
542         map(frow);
543     }
544     else if((ch == 127)||(ch == 8)) {  /* delete key */
545         if(--nx < 0)
546             {
547             nx = ROWLEN -1;
548             if(--ny < 0 ) ny = NOOFROWS -1;
549         }
550         screen[ny][nx] = ' ';
551         move(ny+1,nx+1);
552         addch(' ');
553     }
554     else
555     {
556         if(ch >= 'a' && ch <= 'z') ch = ch - 'a' + 'A';
557         if(ch == '"') ch = (char)getchar();
558         if( ! (ch < ' ') )
559             {
560             screen[y][x] = ch;
561                    move(y+1,x+1);
562             addch(ch);
563             nx++;
564         }
565         }
566     if(nx < 0)
567         {
568         nx = ROWLEN-1;
569         ny--;
570         }
571     if(nx >= ROWLEN)
572         {
573         nx = 0;
574         ny++;
575         }
576     if(ny < 0) ny = NOOFROWS-1;
577     if(ny >= NOOFROWS) ny = 0;
578     move(ny+1,nx+1);
579     x=nx;
580     y=ny;
581     }
582     /* End of while loop */
583 
584     noins();
585     move(20,0);
586     refresh();
587 
588     if(! nosave)
589         {
590         for(y = 0; y<=NOOFROWS;y++) /* certain editors - eg ded - have a */
591                                     /* habit of truncating trailing spaces*/
592                                             /* so this should stop them! */
593             if(screen[y][ROWLEN-1] == ' ')
594                 screen[y][ROWLEN-1] = '-';
595         wscreen(num,maxmoves);
596         }
597 }
598