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