rnd-19980812
[rocksndiamonds.git] / src / events.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  ©1995 Artsoft Development                               *
5 *        Holger Schemel                                    *
6 *        33659 Bielefeld-Senne                             *
7 *        Telefon: (0521) 493245                            *
8 *        eMail: aeglos@valinor.owl.de                      *
9 *               aeglos@uni-paderborn.de                    *
10 *               q99492@pbhrzx.uni-paderborn.de             *
11 *----------------------------------------------------------*
12 *  events.c                                                *
13 ***********************************************************/
14
15 #include "events.h"
16 #include "screens.h"
17 #include "tools.h"
18 #include "game.h"
19 #include "editor.h"
20 #include "misc.h"
21 #include "tape.h"
22 #include "joystick.h"
23
24 void EventLoop(void)
25 {
26   while(1)
27   {
28     if (XPending(display))      /* got an event */
29     {
30       XEvent event;
31
32       XNextEvent(display, &event);
33
34       switch(event.type)
35       {
36         case Expose:
37           HandleExposeEvent((XExposeEvent *) &event);
38           break;
39         case UnmapNotify:
40           SleepWhileUnmapped();
41           break;
42         case ButtonPress:
43         case ButtonRelease:
44           HandleButtonEvent((XButtonEvent *) &event);
45           break;
46         case MotionNotify:
47           HandleMotionEvent((XMotionEvent *) &event);
48           break;
49         case KeyPress:
50         case KeyRelease:
51           HandleKeyEvent((XKeyEvent *) &event);
52           break;
53         case FocusIn:
54         case FocusOut:
55           HandleFocusEvent((XFocusChangeEvent *) &event);
56           break;
57         default:
58           break;
59       }
60     }
61     else                        /* got no event, but don't be lazy... */
62     {
63       HandleNoXEvent();
64       Delay(10000);             /* don't use all CPU time when idle */
65     }
66
67     XSync(display,FALSE);
68
69     if (game_status==EXITGAME)
70       return;
71   }
72 }
73
74 void ClearEventQueue()
75 {
76   while(XPending(display))
77   {
78     XEvent event;
79
80     XNextEvent(display, &event);
81
82     switch(event.type)
83     {
84       case Expose:
85         HandleExposeEvent((XExposeEvent *) &event);
86         break;
87       case UnmapNotify:
88         SleepWhileUnmapped();
89         break;
90       case ButtonRelease:
91         button_status = MB_RELEASED;
92         break;
93       case KeyRelease:
94         key_joystick_mapping = 0;
95         break;
96       case FocusIn:
97       case FocusOut:
98         HandleFocusEvent((XFocusChangeEvent *) &event);
99         break;
100       default:
101         break;
102     }
103   }
104 }
105
106 void SleepWhileUnmapped()
107 {
108   BOOL window_unmapped = TRUE;
109
110   XAutoRepeatOn(display);
111
112   while(window_unmapped)
113   {
114     XEvent event;
115
116     XNextEvent(display, &event);
117
118     switch(event.type)
119     {
120       case Expose:
121         HandleExposeEvent((XExposeEvent *) &event);
122         break;
123       case ButtonRelease:
124         button_status = MB_RELEASED;
125         break;
126       case KeyRelease:
127         key_joystick_mapping = 0;
128         break;
129       case MapNotify:
130         window_unmapped = FALSE;
131         break;
132       default:
133         break;
134     }
135   }
136
137   if (game_status==PLAYING)
138     XAutoRepeatOff(display);
139 }
140
141 void HandleExposeEvent(XExposeEvent *event)
142 {
143   int x = event->x, y = event->y;
144   int width = event->width, height = event->height;
145
146   if (direct_draw_on && game_status==PLAYING)
147   {
148     int xx,yy;
149     int x1 = (x-SX)/TILEX, y1 = (y-SY)/TILEY;
150     int x2 = (x-SX+width)/TILEX, y2 = (y-SY+height)/TILEY;
151
152     SetDrawtoField(DRAW_BACKBUFFER);
153
154     for(xx=0;xx<SCR_FIELDX;xx++)
155       for(yy=0;yy<SCR_FIELDY;yy++)
156         if (xx>=x1 && xx<=x2 && yy>=y1 && yy<=y2)
157           DrawScreenField(xx,yy);
158     DrawPlayerField();
159
160     SetDrawtoField(DRAW_DIRECT);
161   }
162
163   XCopyArea(display,drawto,window,gc, x,y, width,height, x,y);
164
165   XFlush(display);
166 }
167
168 void HandleButtonEvent(XButtonEvent *event)
169 {
170   motion_status = FALSE;
171
172   if (event->type==ButtonPress)
173     button_status = event->button;
174   else
175     button_status = MB_RELEASED;
176
177   HandleButton(event->x, event->y, button_status);
178 }
179
180 void HandleMotionEvent(XMotionEvent *event)
181 {
182   motion_status = TRUE;
183
184   HandleButton(event->x, event->y, button_status);
185 }
186
187 void HandleKeyEvent(XKeyEvent *event)
188 {
189   int key_status = (event->type == KeyPress ? KEY_PRESSED : KEY_RELEASED);
190   unsigned int event_state = (game_status != PLAYING ? event->state : 0);
191   KeySym key = XLookupKeysym(event, event_state);
192
193   HandleKey(key, key_status);
194 }
195
196 void HandleFocusEvent(XFocusChangeEvent *event)
197 {
198   static int old_joystick_status = -1;
199
200   if (event->type == FocusOut)
201   {
202     XAutoRepeatOn(display);
203     old_joystick_status = joystick_status;
204     joystick_status = JOYSTICK_OFF;
205   }
206   else if (event->type == FocusIn)
207   {
208     if (game_status == PLAYING)
209       XAutoRepeatOff(display);
210     if (old_joystick_status != -1)
211       joystick_status = old_joystick_status;
212   }
213 }
214
215 void HandleButton(int mx, int my, int button)
216 {
217   static int old_mx = 0, old_my = 0;
218
219   if (mx<0 || my<0)
220   {
221     mx = old_mx;
222     my = old_my;
223   }
224   else
225   {
226     old_mx = mx;
227     old_my = my;
228
229     HandleVideoButtons(mx,my,button);
230     HandleSoundButtons(mx,my,button);
231     HandleGameButtons(mx,my,button);
232   }
233
234   switch(game_status)
235   {
236     case MAINMENU:
237       HandleMainMenu(mx,my,0,0,button);
238       break;
239     case TYPENAME:
240       HandleTypeName(0,XK_Return);
241       break;
242     case CHOOSELEVEL:
243       HandleChooseLevel(mx,my,0,0,button);
244       break;
245     case HALLOFFAME:
246       HandleHallOfFame(button);
247       break;
248     case LEVELED:
249       LevelEd(mx,my,button);
250       break;
251     case HELPSCREEN:
252       HandleHelpScreen(button);
253       break;
254     case SETUP:
255       HandleSetupScreen(mx,my,0,0,button);
256       break;
257     case PLAYING:
258       HandleGameActions();
259       break;
260     default:
261       break;
262   }
263 }
264
265 int Gamespeed = 4;
266 int Movemethod = 1;
267 int Movespeed[2] = { 10, 4 };
268 char *Movespeed_text[2] = { "asynchron", "syncron" };
269
270 void HandleKey(KeySym key, int key_status)
271 {
272   int joy = 0;
273
274   /* Map cursor keys to joystick directions */
275
276   switch(key)
277   {
278     case XK_Left:               /* normale Richtungen */
279 #ifdef XK_KP_Left
280     case XK_KP_Left:
281 #endif
282     case XK_KP_4:
283     case XK_J:
284     case XK_j:
285       joy |= JOY_LEFT;
286       break;
287     case XK_Right:
288 #ifdef XK_KP_Right
289     case XK_KP_Right:
290 #endif
291     case XK_KP_6:
292     case XK_K:
293     case XK_k:
294       joy |= JOY_RIGHT;
295       break;
296     case XK_Up:
297 #ifdef XK_KP_Up
298     case XK_KP_Up:
299 #endif
300     case XK_KP_8:
301     case XK_I:
302     case XK_i:
303       joy |= JOY_UP;
304       break;
305     case XK_Down:
306 #ifdef XK_KP_Down
307     case XK_KP_Down:
308 #endif
309     case XK_KP_2:
310     case XK_M:
311     case XK_m:
312       joy |= JOY_DOWN;
313       break;
314 #ifdef XK_KP_Home
315     case XK_KP_Home:            /* Diagonalrichtungen */
316 #endif
317     case XK_KP_7:
318       joy |= JOY_UP | JOY_LEFT;
319       break;
320 #ifdef XK_KP_Page_Up
321     case XK_KP_Page_Up:
322 #endif
323     case XK_KP_9:
324       joy = JOY_UP | JOY_RIGHT;
325       break;
326 #ifdef XK_KP_End
327     case XK_KP_End:
328 #endif
329     case XK_KP_1:
330       joy |= JOY_DOWN | JOY_LEFT;
331       break;
332 #ifdef XK_KP_Page_Down
333     case XK_KP_Page_Down:
334 #endif
335     case XK_KP_3:
336       joy |= JOY_DOWN | JOY_RIGHT;
337       break;
338     case XK_S:                  /* Feld entfernen */
339     case XK_s:
340       joy |= JOY_BUTTON_1 | JOY_LEFT;
341       break;
342     case XK_D:
343     case XK_d:
344       joy |= JOY_BUTTON_1 | JOY_RIGHT;
345       break;
346     case XK_E:
347     case XK_e:
348       joy |= JOY_BUTTON_1 | JOY_UP;
349       break;
350     case XK_X:
351     case XK_x:
352       joy |= JOY_BUTTON_1 | JOY_DOWN;
353       break;
354     case XK_Shift_L:            /* Linker Feuerknopf */
355     case XK_Control_L:
356     case XK_Alt_L:
357     case XK_Meta_L:
358       joy |= JOY_BUTTON_1;
359       break;
360     case XK_Shift_R:            /* Rechter Feuerknopf */
361     case XK_Control_R:
362     case XK_Alt_R:
363     case XK_Meta_R:
364     case XK_Mode_switch:
365     case XK_Multi_key:
366     case XK_B:                  /* (Bombe legen) */
367     case XK_b:
368       joy |= JOY_BUTTON_2;
369       break;
370     default:
371       break;
372   }
373
374   if (joy)
375   {
376     if (key_status == KEY_PRESSED)
377       key_joystick_mapping |= joy;
378     else
379       key_joystick_mapping &= ~joy;
380
381     HandleJoystick();
382   }
383
384   if (game_status != PLAYING)
385     key_joystick_mapping = 0;
386
387   if (key_status == KEY_RELEASED)
388     return;
389
390   if (key==XK_Return && game_status==PLAYING && GameOver)
391   {
392     CloseDoor(DOOR_CLOSE_1);
393     game_status = MAINMENU;
394     DrawMainMenu();
395     return;
396   }
397
398   if (key==XK_Escape && game_status!=MAINMENU)  /* quick quit to MAINMENU */
399   {
400     CloseDoor(DOOR_CLOSE_1 | DOOR_NO_DELAY);
401     game_status = MAINMENU;
402     DrawMainMenu();
403     return;
404   }
405
406   if (game_status==PLAYING && (tape.playing || tape.pausing))
407     return;
408
409   switch(game_status)
410   {
411     case TYPENAME:
412       HandleTypeName(0,key);
413       break;
414     case MAINMENU:
415     case CHOOSELEVEL:
416     case SETUP:
417     {
418       switch(key)
419       {
420         case XK_Return:
421           if (game_status==MAINMENU)
422             HandleMainMenu(0,0,0,0,MB_MENU_CHOICE);
423           else if (game_status==CHOOSELEVEL)
424             HandleChooseLevel(0,0,0,0,MB_MENU_CHOICE);
425           else if (game_status==SETUP)
426             HandleSetupScreen(0,0,0,0,MB_MENU_CHOICE);
427           break;
428         default:
429           break;
430       }
431       break;
432     }
433     case HELPSCREEN:
434       HandleHelpScreen(MB_RELEASED);
435       break;
436     case HALLOFFAME:
437       switch(key)
438       {
439         case XK_Return:
440           game_status = MAINMENU;
441           DrawMainMenu();
442           BackToFront();
443           break;
444         default:
445           break;
446       }
447       break;
448     case LEVELED:
449       LevelNameTyping(key);
450       break;
451     case PLAYING:
452     {
453       switch(key)
454       {
455
456 #ifdef DEBUG
457         case XK_0:
458         case XK_1:
459         case XK_2:
460         case XK_3:
461         case XK_4:
462         case XK_5:
463         case XK_6:
464         case XK_7:
465         case XK_8:
466         case XK_9:
467           Movespeed[Movemethod] = (Movemethod == 0 ? 4 : 0) + (key - XK_0);
468           printf("method == %d, speed == %d (%s)\n",
469                  Movemethod, Movespeed[Movemethod],
470                  Movespeed_text[Movemethod]);
471           break;
472
473         case XK_a:
474           Movemethod = !Movemethod;
475           printf("method == %d, speed == %d (%s)\n",
476                  Movemethod, Movespeed[Movemethod],
477                  Movespeed_text[Movemethod]);
478           break;
479
480         case XK_f:
481           Gamespeed = 2;
482           printf("gamespeed == %d\n", Gamespeed);
483           break;
484         case XK_g:
485           Gamespeed = 3;
486           printf("gamespeed == %d\n", Gamespeed);
487           break;
488         case XK_h:
489           Gamespeed = 4;
490           printf("gamespeed == %d\n", Gamespeed);
491           break;
492         case XK_l:
493           Gamespeed = 50;
494           printf("gamespeed == %d\n", Gamespeed);
495           break;
496
497         case XK_Q:
498         case XK_q:
499           Dynamite = 1000;
500           break;
501
502         case XK_x:
503
504           {
505             int i,j,k, num_steps = 16, step_size = TILEX / num_steps;
506             static long scroll_delay=0;
507             long scroll_delay_value = 4*4 / num_steps;
508
509             printf("Scroll test\n");
510
511             for(i=0;i<10;i++)
512             {
513               for(j=0;j<SCR_FIELDX;j++)
514               {
515                 for(k=0;k<num_steps;k++)
516                 {
517                   int xxx = j*TILEX+k*step_size;
518                   int done = 0;
519
520                   while(!done)
521                   {
522                     if (DelayReached(&scroll_delay, scroll_delay_value))
523                     {
524                       XCopyArea(display,fieldbuffer,window,gc,
525                                 SX+xxx,SY,
526                                 SXSIZE-xxx,SYSIZE,
527                                 SX,SY);
528                       XCopyArea(display,fieldbuffer,window,gc,
529                                 SX,SY,
530                                 xxx,SYSIZE,
531                                 SX+SXSIZE-xxx,SY);
532   
533                       XFlush(display);
534                       XSync(display,FALSE);
535
536                       done = 1;
537                     }
538                     else
539                     {
540                       Delay(1000);
541                     }
542                   }
543   
544                   /*
545                   Delay(160000 / num_steps);
546                   */
547                   /*
548                   Delay(120000 / num_steps);
549                   */
550                 }
551               }
552             }
553           }
554
555           break;
556
557         case XK_y:
558           {
559             printf("FX = %d, FY = %d\n", FX,FY);
560
561             XCopyArea(display,fieldbuffer,window,gc,
562                       0,0,
563                       MIN(WIN_XSIZE,FXSIZE),MIN(WIN_YSIZE,FYSIZE),
564                       0,0);
565             XFlush(display);
566             XSync(display,FALSE);
567             Delay(1000000);
568           }
569
570           break;
571 #endif
572
573         default:
574           break;
575       }
576       break;
577     }
578     default:
579       break;
580   }
581 }
582
583 void HandleNoXEvent()
584 {
585   if (button_status && game_status != PLAYING)
586   {
587     HandleButton(-1,-1,button_status);
588     return;
589   }
590
591   switch(game_status)
592   {
593     case MAINMENU:
594     case CHOOSELEVEL:
595     case HALLOFFAME:
596     case HELPSCREEN:
597     case SETUP:
598       HandleJoystick();
599       break;
600     case PLAYING:
601       HandleJoystick();
602       HandleGameActions();
603       break;
604     default:
605       break;
606   }
607 }
608
609 void HandleJoystick()
610 {
611   int joystick  = Joystick();
612   int keyboard  = key_joystick_mapping;
613   int joy       = (tape.playing ? TapePlayAction() : (joystick | keyboard));
614   int left      = joy & JOY_LEFT;
615   int right     = joy & JOY_RIGHT;
616   int up        = joy & JOY_UP;
617   int down      = joy & JOY_DOWN;
618   int button    = joy & JOY_BUTTON;
619   int button1   = joy & JOY_BUTTON_1;
620   int button2   = joy & JOY_BUTTON_2;
621   int newbutton = (JoystickButton() == JOY_BUTTON_NEW_PRESSED);
622   int dx        = (left ? -1    : right ? 1     : 0);
623   int dy        = (up   ? -1    : down  ? 1     : 0);
624
625   if (game_status==PLAYING && (tape.playing || keyboard))
626     newbutton = ((joy & JOY_BUTTON) != 0);
627
628   switch(game_status)
629   {
630     case MAINMENU:
631     case CHOOSELEVEL:
632     case SETUP:
633     {
634       static long joystickmove_delay = 0;
635
636       if (joystick && !button && !DelayReached(&joystickmove_delay,15))
637         newbutton = dx = dy = 0;
638
639       if (game_status==MAINMENU)
640         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
641       else if (game_status==CHOOSELEVEL)
642         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
643       else if (game_status==SETUP)
644         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
645       break;
646     }
647     case HALLOFFAME:
648       HandleHallOfFame(!newbutton);
649       break;
650     case HELPSCREEN:
651       HandleHelpScreen(!newbutton);
652       break;
653     case PLAYING:
654     {
655       BOOL moved = FALSE, snapped = FALSE, bombed = FALSE;
656
657       if (GameOver && newbutton)
658       {
659         CloseDoor(DOOR_CLOSE_1);
660         game_status = MAINMENU;
661         DrawMainMenu();
662         return;
663       }
664
665
666 #if 0
667       if (PlayerMovPos)
668       {
669         ScrollFigure(0);
670         /*
671         BackToFront();
672         */
673       }
674 #endif
675
676
677       if (tape.pausing || PlayerGone)
678         joy = 0;
679
680       if (joy)
681       {
682         if (button1)
683           snapped = SnapField(dx,dy);
684         else
685         {
686           if (button2)
687             bombed = PlaceBomb();
688           moved = MoveFigure(dx,dy);
689         }
690
691         if (tape.recording && (moved || snapped || bombed))
692         {
693           if (bombed && !moved)
694             joy &= JOY_BUTTON;
695           TapeRecordAction(joy);
696         }
697         else if (tape.playing && snapped)
698           SnapField(0,0);                       /* stop snapping */
699       }
700       else
701       {
702         DigField(0,0,0,0,DF_NO_PUSH);
703         SnapField(0,0);
704         PlayerFrame = 0;
705       }
706
707       if (tape.playing && !tape.pausing && !joy && tape.counter<tape.length)
708       {
709         int next_joy =
710           tape.pos[tape.counter].joystickdata & (JOY_LEFT|JOY_RIGHT);
711
712         if (next_joy == JOY_LEFT || next_joy == JOY_RIGHT)
713         {
714           int dx = (next_joy == JOY_LEFT ? -1 : +1);
715
716           if (IN_LEV_FIELD(JX+dx,JY) && IS_PUSHABLE(Feld[JX+dx][JY]))
717           {
718             int el = Feld[JX+dx][JY];
719             int push_delay = (IS_SB_ELEMENT(el) || el==EL_SONDE ? 2 : 10);
720
721             if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
722             {
723               PlayerMovDir = next_joy;
724               PlayerFrame = FrameCounter % 4;
725               PlayerPushing = TRUE;
726             }
727           }
728         }
729       }
730
731
732       /*
733       DrawPlayerField();
734       */
735
736
737       break;
738     }
739     default:
740       break;
741   }
742 }