editor: #undef O after use
[0verkill.git] / editor.c
blob7151e2b460d78f607331806714a79e308a7c5d5f
1 #include <signal.h>
2 #include <errno.h>
3 #include <unistd.h>
4 #include <stdio.h>
5 #include <stdlib.h>
7 #include "sprite.h"
8 #include "console.h"
9 #include "blit.h"
10 #include "data.h"
11 #include "cfg.h"
12 #include "hash.h"
13 #include "time.h"
14 #include "error.h"
16 /* defines for help */
17 #define HELP_WIDTH 78
18 #define HELP_HEIGHT 22
19 #define HELP_X ((SCREEN_X-2-HELP_WIDTH)>>1)
20 #define HELP_Y ((SCREEN_Y-2-HELP_HEIGHT)>>1)
23 unsigned long id; /* id of last object */
24 int xoffset=0,yoffset=0; /* coordinates of upper left corner of the screen */
25 int x=0,y=0; /* cursor coordinates on the screen */
26 int oldx=0,oldy=0; /* old cursor position */
28 struct object_list objects;
29 struct object_list *last_obj;
30 int level_number;
33 void catch_signal(int sig_num)
35 c_shutdown();
36 exit(sig_num);
40 void catch_sigsegv(int sig_num)
42 c_shutdown();
43 raise(SIGSEGV);
44 exit(sig_num);
48 void set_sigint(void)
50 struct sigaction sa_old;
51 struct sigaction sa_new;
53 sa_new.sa_handler = catch_signal;
54 sigemptyset(&sa_new.sa_mask);
55 sa_new.sa_flags = 0;
56 sigaction(SIGINT,&sa_new,&sa_old);
57 sigaction(SIGQUIT,&sa_new,&sa_old);
58 sigaction(SIGTERM,&sa_new,&sa_old);
59 sigaction(SIGABRT,&sa_new,&sa_old);
60 sigaction(SIGILL,&sa_new,&sa_old);
61 sigaction(SIGFPE,&sa_new,&sa_old);
62 sigaction(SIGBUS,&sa_new,&sa_old);
64 sa_new.sa_handler = catch_sigsegv;
65 sigemptyset(&sa_new.sa_mask);
66 sa_new.sa_flags = 0;
67 sigaction(SIGSEGV,&sa_new,&sa_old);
71 /* shows the help window */
72 void help(void)
74 draw_frame(HELP_X,HELP_Y,HELP_WIDTH,HELP_HEIGHT,14);
75 print2screen(HELP_X+((HELP_WIDTH-4)>>1),HELP_Y+1,12,"HELP");
76 print2screen(HELP_X+((HELP_WIDTH-9)>>1),HELP_Y+3,11,"SCROLLING");
78 /* cursor moving help */
79 print2screen(HELP_X+8,HELP_Y+4,4,"CURSOR MOVING:");
80 print2screen(HELP_X+13,HELP_Y+5,8,"UP");
81 print2screen(HELP_X+12,HELP_Y+6,8,"[/\\]");
82 print2screen(HELP_X+2,HELP_Y+7,8,"LEFT [<-] [\\/] [->] RIGHT");
83 print2screen(HELP_X+12,HELP_Y+8,8,"DOWN");
85 /* screen moving help */
86 print2screen(HELP_X+31,HELP_Y+4,4,"SCROLLING (NUMPAD!):");
87 print2screen(HELP_X+39,HELP_Y+5,8,"UP");
88 print2screen(HELP_X+39,HELP_Y+6,8,"[8]");
89 print2screen(HELP_X+31,HELP_Y+7,8,"LEFT [4] [6] RIGHT");
90 print2screen(HELP_X+39,HELP_Y+8,8,"[2]");
91 print2screen(HELP_X+38,HELP_Y+9,8,"DOWN");
93 /* item moving help */
94 print2screen(HELP_X+60,HELP_Y+4,4,"ITEM MOVING:");
95 print2screen(HELP_X+65,HELP_Y+5,8,"UP");
96 print2screen(HELP_X+64,HELP_Y+6,8,"[W]");
97 print2screen(HELP_X+55,HELP_Y+7,8,"LEFT [A] [S] [D] RIGHT");
98 print2screen(HELP_X+64,HELP_Y+8,8,"DOWN");
100 /* now the keys */
101 print2screen(HELP_X+((HELP_WIDTH-4)>>1),HELP_Y+11,11,"KEYS");
102 print2screen(HELP_X+((HELP_WIDTH-11)>>1),HELP_Y+12,8,"BUILD - [N]");
103 print2screen(HELP_X+((HELP_WIDTH-12)>>1),HELP_Y+13,8,"DELETE - [X]");
104 print2screen(HELP_X+((HELP_WIDTH-19)>>1),HELP_Y+14,8,"TYPE CHANGE - [TAB], [T] (+ [SHIFT] =reverse)");
105 print2screen(HELP_X+((HELP_WIDTH-11)>>1),HELP_Y+15,8,"SAVE - [F2]");
106 print2screen(HELP_X+((HELP_WIDTH-11)>>1),HELP_Y+16,8,"HELP - [F1]");
107 print2screen(HELP_X+((HELP_WIDTH-26)>>1),HELP_Y+17,8,"ITEM CHANGE - ([+] and [-])");
109 blit_screen(1);
110 sleep(2);
115 /* load static data */
116 void load_room(char * filename)
118 FILE * stream;
119 static char line[1024];
120 char *p,*q,*name;
121 int n,x,y,t;
123 if (!(stream=fopen(filename,"rb")))
125 char msg[256];
126 snprintf(msg,sizeof(msg),"Can't open file \"%s\"!\n",filename);
127 ERROR(msg);
128 EXIT(1);
130 while(fgets(line,1024,stream))
132 p=line;
133 _skip_ws(&p);
134 for (name=p;(*p)!=' '&&(*p)!=9&&(*p)!=10&&(*p);p++);
135 if (!(*p))continue;
136 *p=0;p++;
137 _skip_ws(&p);
138 t=*p;
139 p++;
140 _skip_ws(&p);
141 x=strtol(p,&q,0);
142 _skip_ws(&q);
143 y=strtol(q,&p,0);
144 if (find_sprite(name,&n))
146 char msg[256];
147 snprintf(msg,sizeof(msg),"Unknown bitmap name \"%s\"!\n",name);
148 ERROR(msg);
149 EXIT(1);
151 new_obj(id,t,0,n,0,0,x,y,0,0,0);
152 id++;
154 fclose(stream);
159 /* draw view */
160 void draw_scene(void)
162 struct object_list *p;
164 for(p=&objects;p->next;p=p->next)
167 p->next->member.anim_pos++;
168 p->next->member.anim_pos%=sprites[p->next->member.sprite].n_steps;
169 put_sprite(
170 p->next->member.x-xoffset,
171 p->next->member.y-yoffset,
172 sprites[p->next->member.sprite].positions+sprites[p->next->member.sprite].steps[p->next->member.anim_pos],0
178 /* find object under cursor */
179 struct it * find_object(void)
181 struct object_list *p;
183 #define O p->next->member
184 for(p=&objects;p->next;p=p->next)
186 if (
187 O.x<=x+xoffset&&
188 O.x+sprites[O.sprite].positions[0].lines[0].len-1>=x+xoffset&&
189 O.y<=y+yoffset&&
190 O.y+sprites[O.sprite].positions[0].n-1>=y+yoffset
192 return &(p->next->member);
194 #undef O
196 return 0;
200 /* next type when 't' is pressed */
201 int next_type(int type)
203 /* static objects: b, f, j, i, w */
204 /* dynamic objects: N, F, B, S, U, R, 1, 2, 3, 4, 5, M, A, I, K */
205 switch(type)
207 case 'b': return 'f';
208 case 'f': return 'j';
209 case 'j': return 'i';
210 case 'i': return 'w';
211 case 'w': return 'N';
212 case 'N': return 'F';
213 case 'F': return 'B';
214 case 'B': return 'S';
215 case 'S': return 'U';
216 case 'U': return 'R';
217 case 'R': return '1';
218 case '1': return '2';
219 case '2': return '3';
220 case '3': return '4';
221 case '4': return '5';
222 case '5': return 'M';
223 case 'M': return 'A';
224 case 'A': return 'I';
225 case 'I': return 'K';
227 default: return 'b';
232 /* prev type when 'T' is pressed */
233 int prev_type(int type)
235 /* static objects: b, f, j, i, w */
236 /* dynamic objects: N, F, B, S, U, R, 1, 2, 3, 4, 5, M, A, I, K */
237 /* but now in reverse order */
238 switch(type)
240 case 'b': return 'K';
241 case 'f': return 'b';
242 case 'j': return 'f';
243 case 'i': return 'j';
244 case 'w': return 'i';
245 case 'N': return 'w';
246 case 'F': return 'N';
247 case 'B': return 'F';
248 case 'S': return 'B';
249 case 'U': return 'S';
250 case 'R': return 'U';
251 case '1': return 'R';
252 case '2': return '1';
253 case '3': return '2';
254 case '4': return '3';
255 case '5': return '4';
256 case 'M': return '5';
257 case 'A': return 'M';
258 case 'I': return 'A';
260 default: return 'I';
265 /* save level */
266 void save_data(void)
268 FILE *data, *dynamic;
269 struct object_list *p;
270 static char txt[1024];
271 char *LEVEL=load_level(level_number);
273 snprintf(txt,1024,"%s%s%s",DATA_PATH,LEVEL,STATIC_DATA_SUFFIX);
274 data=fopen(txt,"w");
275 if (!data)
277 char msg[256];
278 snprintf(msg,256,"Can't create file \"%s\"\n",txt);
279 ERROR(msg);
280 EXIT(1);
283 snprintf(txt,1024,"%s%s%s",DATA_PATH,LEVEL,DYNAMIC_DATA_SUFFIX);
284 mem_free(LEVEL);
285 dynamic=fopen(txt,"w");
286 if (!dynamic)
288 char msg[256];
289 snprintf(msg,256,"Can't create file \"%s\"\n",txt);
290 ERROR(msg);
291 EXIT(1);
294 #define O p->next->member
295 for(p=&objects;p->next;p=p->next)
297 snprintf(txt,sizeof(txt),"%s %c %d %d\n",sprite_names[O.sprite],O.type,O.x,O.y);
298 switch (O.type)
300 case 'b':
301 case 'w':
302 case 'i':
303 case 'j':
304 case 'f':
305 fputs(txt,data);
306 break;
308 default:
309 fputs(txt,dynamic);
310 break;
313 #undef O
315 fclose(data);
316 fclose(dynamic);
321 /* change size of the screen */
322 void sigwinch_handler(int signum)
324 signum=signum;
325 resize_screen();
326 #ifdef WIN32
327 c_shutdown();
328 c_init(SCREEN_X,SCREEN_Y);
329 #endif
330 c_cls();
331 c_refresh();
332 #ifndef WIN32
333 #ifdef SIGWINCH
334 signal(SIGWINCH,sigwinch_handler);
335 #endif
336 #endif
340 void clear_memory(void)
342 struct object_list *o;
344 for (o=&objects;o->next;)
345 delete_obj(o->next->member.id);
347 free_area();
348 free_sprites(0);
349 shutdown_sprites();
353 int main(int argc, char**argv)
355 int update=1;
356 unsigned char bg=' ';
357 unsigned char color=0;
359 unsigned int cur_obj=0;
360 unsigned char cur_type='w';
362 struct it* obj=0;
363 char txt[256];
364 unsigned long_long last_time;
365 char *LEVEL;
367 chdir_to_data_files();
368 set_sigint();
370 while(1)
372 int a;
373 char *c;
375 a=getopt(argc, argv, "hl:");
376 switch(a)
378 case EOF:
379 goto done;
381 case '?':
382 case ':':
383 exit(1);
385 case 'h':
386 printf(
387 "0verkill editor\n"
388 "Usage: editor [-h] [-l <level number>]\n"
390 exit(0);
392 case 'l':
393 level_number=strtoul(optarg,&c,10);
394 if (*c){ERROR("Error: Not a number.\n");EXIT(1);}
395 if (errno==ERANGE)
397 if (!level_number){ERROR("Error: Number underflow.\n");EXIT(1);}
398 else {ERROR("Error: Number overflow.\n");EXIT(1);}
400 break;
403 done:
405 last_obj=&objects;
407 #ifdef SIGWINCH
408 signal(SIGWINCH,sigwinch_handler);
409 #endif
410 c_get_size(&SCREEN_X,&SCREEN_Y);
411 hash_table_init();
412 init_sprites();
413 init_area();
414 LEVEL=load_level(level_number);
415 if (!LEVEL){fprintf(stderr,"Can't load level number %d\n",level_number);exit(1);}
416 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,LEVEL_SPRITES_SUFFIX);
417 load_sprites(txt);
418 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,STATIC_DATA_SUFFIX);
419 load_room(txt);
420 snprintf(txt,256,"%s%s%s",DATA_PATH,LEVEL,DYNAMIC_DATA_SUFFIX);
421 mem_free(LEVEL);
422 load_room(txt);
424 c_init(SCREEN_X,SCREEN_Y);
425 c_cursor(C_HIDE);
426 update=1;
427 again:
428 last_time=get_time();
430 clear_screen();
431 draw_scene();
432 blit_screen(1);
434 if (!update)
436 c_goto(oldx,oldy);
437 c_setcolor(color);
438 c_putc(bg?bg:' ');
440 color=screen_a[x+y*SCREEN_X];
441 bg=screen[x+y*SCREEN_X];
443 c_goto(x,y);
444 c_setcolor(15);
445 c_print("+");
447 obj=find_object();
448 c_clear(0,SCREEN_Y-1,SCREEN_X-2,SCREEN_Y-1);
449 c_goto(0,SCREEN_Y-1);
450 c_setcolor(11);
451 c_print("X: ");
452 snprintf(txt,sizeof(txt),"% 4d ",x+xoffset);
453 c_setcolor(7);
454 c_print(txt);
455 c_setcolor(11);
456 c_print("Y: ");
457 snprintf(txt,sizeof(txt),"% 4d ",y+yoffset);
458 c_setcolor(7);
459 c_print(txt);
460 c_setcolor(11);
461 c_print("OBJECT: ");
462 snprintf(txt,sizeof(txt),"%-.20s ",obj?(char*)(sprite_names[obj->sprite]):"----");
463 c_setcolor(7);
464 c_print(txt);
465 c_setcolor(11);
466 c_print("TYPE: ");
467 snprintf(txt,sizeof(txt),"%c ",obj?obj->type:'-');
468 c_setcolor(7);
469 c_print(txt);
470 update=0;
471 oldx=x;
472 oldy=y;
473 c_refresh();
475 c_update_kbd();
477 if (c_pressed(K_NUM4)||c_pressed('4'))
479 xoffset-=SCREEN_X>>2;
480 if (xoffset<0)xoffset=0;
481 else update=1;
484 if (c_pressed(K_NUM6)||c_pressed('6'))
486 xoffset+=SCREEN_X>>2;
487 if (xoffset>AREA_X-1-(SCREEN_X>>1))xoffset=AREA_X-1-(SCREEN_X>>1);
488 update=1;
491 if (c_pressed(K_NUM8)||c_pressed('8'))
493 yoffset-=SCREEN_Y>>2;
494 if (yoffset<0)yoffset=0;
495 update=1;
498 if (c_pressed(K_NUM2)||c_pressed('2'))
500 yoffset+=SCREEN_Y>>2;
501 if (yoffset>AREA_Y-1-(SCREEN_Y>>1))yoffset=AREA_Y-1-(SCREEN_Y>>1);
502 update=1;
505 if (c_pressed('q')||c_pressed(K_ESCAPE))
507 c_shutdown();
508 clear_memory();
509 check_memory_leaks();
510 exit(0);
513 if (c_pressed(K_RIGHT))
515 x++;
516 if (x>SCREEN_X-1||x+xoffset>AREA_X-1)x=0;
519 if (c_pressed(K_LEFT))
521 x--;
522 if (x<0)x=SCREEN_X-1;
523 if (x+xoffset>AREA_X-1)x=AREA_X-1-xoffset;
526 if (c_pressed(K_DOWN))
528 y++;
529 if (y>SCREEN_Y-1||y+yoffset>AREA_Y-1)y=0;
532 if (c_pressed(K_UP))
534 y--;
535 if (y<0)y=SCREEN_Y-1;
536 if (y+yoffset>AREA_Y-1)y=AREA_Y-1-yoffset;
539 if (c_pressed(K_F1))
541 help();
542 clear_screen();
543 draw_scene();
544 blit_screen(1);
547 if (c_was_pressed('x'))
548 if (obj)
550 delete_obj(obj->id);
551 update=1;
554 if (c_was_pressed('=')||c_was_pressed(K_NUM_PLUS)|c_was_pressed(K_PGUP))
555 if (obj)
557 obj->sprite++;
558 cur_obj=obj->sprite;
559 obj->sprite%=n_sprites;
560 update=1;
563 if (c_was_pressed('a')||((c_pressed(K_LEFT_SHIFT)||c_pressed(K_RIGHT_SHIFT))&&c_pressed('a')))
564 if (obj)
566 obj->x--;
567 x--;
568 if (obj->x<0)obj->x=0;
569 update=1;
572 if (c_was_pressed('d')||((c_pressed(K_LEFT_SHIFT)||c_pressed(K_RIGHT_SHIFT))&&c_pressed('d')))
573 if (obj)
575 obj->x++;
576 x++;
577 if (obj->x>AREA_X-1)obj->x=AREA_X-1;
578 update=1;
581 if (c_was_pressed('w')||((c_pressed(K_LEFT_SHIFT)||c_pressed(K_RIGHT_SHIFT))&&c_pressed('w')))
582 if (obj)
584 obj->y--;
585 y--;
586 if (obj->y<0)obj->y=0;
587 update=1;
590 if (c_was_pressed('s')||((c_pressed(K_LEFT_SHIFT)||c_pressed(K_RIGHT_SHIFT))&&c_pressed('s')))
591 if (obj)
593 obj->y++;
594 y++;
595 if (obj->y>AREA_Y-1)obj->y=AREA_Y-1;
596 update=1;
599 if (c_was_pressed('-')||c_was_pressed(K_NUM_MINUS)||c_was_pressed(K_PGDOWN))
600 if (obj)
602 if (!obj->sprite)obj->sprite=n_sprites-1;
603 else obj->sprite--;
604 cur_obj=obj->sprite;
605 update=1;
608 if ((c_pressed(K_LEFT_SHIFT)||c_pressed(K_RIGHT_SHIFT))&&(c_was_pressed('t')||c_was_pressed(K_TAB)))
609 if (obj)
611 obj->type=prev_type(obj->type);
612 cur_type=obj->type;
613 update=1;
616 if (!c_pressed(K_LEFT_SHIFT)&&!c_pressed(K_RIGHT_SHIFT)&&(c_was_pressed('t')||c_was_pressed(K_TAB)))
617 if (obj)
619 obj->type=next_type(obj->type);
620 cur_type=obj->type;
621 update=1;
624 if (c_was_pressed('n')||c_was_pressed(K_ENTER))
626 new_obj(id,cur_type,0,cur_obj,0,0,x+xoffset,y+yoffset,0,0,0);
627 id++;
628 update=1;
631 if (c_was_pressed(K_F2))
632 save_data();
634 sleep_until(last_time+1000000/35);
635 goto again;