cbf6e1da2fe9551137e2c827795085d4cb61e545
[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
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       Delay(10000);             /* don't use all CPU time when idle */
70     }
71
72     XSync(display,FALSE);
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_joystick_mapping = 0;
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_joystick_mapping = 0;
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   int key_status = (event->type == KeyPress ? KEY_PRESSED : KEY_RELEASED);
193   unsigned int event_state = (game_status != PLAYING ? event->state : 0);
194   KeySym key = XLookupKeysym(event, event_state);
195
196   HandleKey(key, key_status);
197 }
198
199 void HandleFocusEvent(int focus_status)
200 {
201   static int old_joystick_status = -1;
202
203   if (focus_status==FOCUS_OUT)
204   {
205     XAutoRepeatOn(display);
206     old_joystick_status = joystick_status;
207     joystick_status = JOYSTICK_OFF;
208   }
209   else
210   {
211     if (game_status == PLAYING)
212       XAutoRepeatOff(display);
213     if (old_joystick_status != -1)
214       joystick_status = old_joystick_status;
215   }
216 }
217
218 void HandleButton(int mx, int my, int button)
219 {
220   static int old_mx = 0, old_my = 0;
221
222   if (mx<0 || my<0)
223   {
224     mx = old_mx;
225     my = old_my;
226   }
227   else
228   {
229     old_mx = mx;
230     old_my = my;
231
232     HandleVideoButtons(mx,my,button);
233     HandleSoundButtons(mx,my,button);
234     HandleGameButtons(mx,my,button);
235   }
236
237   switch(game_status)
238   {
239     case MAINMENU:
240       HandleMainMenu(mx,my,0,0,button);
241       break;
242     case TYPENAME:
243       HandleTypeName(0,XK_Return);
244       break;
245     case CHOOSELEVEL:
246       HandleChooseLevel(mx,my,0,0,button);
247       break;
248     case HALLOFFAME:
249       HandleHallOfFame(button);
250       break;
251     case LEVELED:
252       LevelEd(mx,my,button);
253       break;
254     case HELPSCREEN:
255       HandleHelpScreen(button);
256       break;
257     case SETUP:
258       HandleSetupScreen(mx,my,0,0,button);
259       break;
260     case PLAYING:
261       HandleGameActions();
262       break;
263     default:
264       break;
265   }
266 }
267
268 int Gamespeed = 4;
269 int Movemethod = 0;
270 int Movespeed[2] = { 10, 3 };
271
272 void HandleKey(KeySym key, int key_status)
273 {
274   int joy = 0;
275
276   /* Map cursor keys to joystick directions */
277
278   switch(key)
279   {
280     case XK_Left:               /* normale Richtungen */
281 #ifdef XK_KP_Left
282     case XK_KP_Left:
283 #endif
284     case XK_KP_4:
285     case XK_J:
286     case XK_j:
287       joy |= JOY_LEFT;
288       break;
289     case XK_Right:
290 #ifdef XK_KP_Right
291     case XK_KP_Right:
292 #endif
293     case XK_KP_6:
294     case XK_K:
295     case XK_k:
296       joy |= JOY_RIGHT;
297       break;
298     case XK_Up:
299 #ifdef XK_KP_Up
300     case XK_KP_Up:
301 #endif
302     case XK_KP_8:
303     case XK_I:
304     case XK_i:
305       joy |= JOY_UP;
306       break;
307     case XK_Down:
308 #ifdef XK_KP_Down
309     case XK_KP_Down:
310 #endif
311     case XK_KP_2:
312     case XK_M:
313     case XK_m:
314       joy |= JOY_DOWN;
315       break;
316 #ifdef XK_KP_Home
317     case XK_KP_Home:            /* Diagonalrichtungen */
318 #endif
319     case XK_KP_7:
320       joy |= JOY_UP | JOY_LEFT;
321       break;
322 #ifdef XK_KP_Page_Up
323     case XK_KP_Page_Up:
324 #endif
325     case XK_KP_9:
326       joy = JOY_UP | JOY_RIGHT;
327       break;
328 #ifdef XK_KP_End
329     case XK_KP_End:
330 #endif
331     case XK_KP_1:
332       joy |= JOY_DOWN | JOY_LEFT;
333       break;
334 #ifdef XK_KP_Page_Down
335     case XK_KP_Page_Down:
336 #endif
337     case XK_KP_3:
338       joy |= JOY_DOWN | JOY_RIGHT;
339       break;
340     case XK_S:                  /* Feld entfernen */
341     case XK_s:
342       joy |= JOY_BUTTON_1 | JOY_LEFT;
343       break;
344     case XK_D:
345     case XK_d:
346       joy |= JOY_BUTTON_1 | JOY_RIGHT;
347       break;
348     case XK_E:
349     case XK_e:
350       joy |= JOY_BUTTON_1 | JOY_UP;
351       break;
352     case XK_X:
353     case XK_x:
354       joy |= JOY_BUTTON_1 | JOY_DOWN;
355       break;
356     case XK_Shift_L:            /* Linker Feuerknopf */
357       joy |= JOY_BUTTON_1;
358       break;
359     case XK_Shift_R:            /* Rechter Feuerknopf */
360     case XK_B:                  /* (Bombe legen) */
361     case XK_b:
362       joy |= JOY_BUTTON_2;
363       break;
364     default:
365       break;
366   }
367
368   if (joy)
369   {
370     if (key_status == KEY_PRESSED)
371       key_joystick_mapping |= joy;
372     else
373       key_joystick_mapping &= ~joy;
374
375     HandleJoystick();
376
377     if (game_status != PLAYING)
378       key_joystick_mapping = 0;
379   }
380
381   if (key_status == KEY_RELEASED)
382     return;
383
384   if (key==XK_Escape && game_status!=MAINMENU)  /* quick quit to MAINMENU */
385   {
386     CloseDoor(DOOR_CLOSE_1 | DOOR_NO_DELAY);
387     game_status = MAINMENU;
388     DrawMainMenu();
389     return;
390   }
391
392   if (game_status==PLAYING && (tape.playing || tape.pausing))
393     return;
394
395   switch(game_status)
396   {
397     case TYPENAME:
398       HandleTypeName(0,key);
399       break;
400     case MAINMENU:
401     case CHOOSELEVEL:
402     case SETUP:
403     {
404       switch(key)
405       {
406         case XK_Return:
407           if (game_status==MAINMENU)
408             HandleMainMenu(0,0,0,0,MB_MENU_CHOICE);
409           else if (game_status==CHOOSELEVEL)
410             HandleChooseLevel(0,0,0,0,MB_MENU_CHOICE);
411           else if (game_status==SETUP)
412             HandleSetupScreen(0,0,0,0,MB_MENU_CHOICE);
413           break;
414         default:
415           break;
416       }
417       break;
418     }
419     case HELPSCREEN:
420       HandleHelpScreen(MB_RELEASED);
421       break;
422     case HALLOFFAME:
423       switch(key)
424       {
425         case XK_Return:
426           game_status = MAINMENU;
427           DrawMainMenu();
428           BackToFront();
429           break;
430         default:
431           break;
432       }
433       break;
434     case LEVELED:
435       LevelNameTyping(key);
436       break;
437     case PLAYING:
438     {
439       switch(key)
440       {
441
442 #ifdef DEBUG
443         case XK_0:
444         case XK_1:
445         case XK_2:
446         case XK_3:
447         case XK_4:
448         case XK_5:
449         case XK_6:
450         case XK_7:
451         case XK_8:
452         case XK_9:
453           Movespeed[Movemethod] = (Movemethod == 0 ? 4 : 0) + (key - XK_0);
454           printf("method == %d, speed == %d\n",
455                  Movemethod, Movespeed[Movemethod]);
456           break;
457
458         case XK_a:
459           Movemethod = !Movemethod;
460           printf("method == %d, speed == %d\n",
461                  Movemethod, Movespeed[Movemethod]);
462           break;
463
464         case XK_f:
465           Gamespeed = 2;
466           printf("gamespeed == %d\n", Gamespeed);
467           break;
468         case XK_g:
469           Gamespeed = 3;
470           printf("gamespeed == %d\n", Gamespeed);
471           break;
472         case XK_h:
473           Gamespeed = 4;
474           printf("gamespeed == %d\n", Gamespeed);
475           break;
476         case XK_l:
477           Gamespeed = 10;
478           printf("gamespeed == %d\n", Gamespeed);
479           break;
480
481         case XK_Q:
482         case XK_q:
483           Dynamite = 1000;
484           break;
485 #endif
486
487         case XK_x:
488           /*
489           {
490             int i,j,k, num_steps = 4, step_size = TILEX / num_steps;
491
492             for(i=0;i<10;i++)
493             {
494               for(j=0;j<SCR_FIELDX;j++)
495               {
496                 for(k=0;k<num_steps;k++)
497                 {
498                   int xxx = j*TILEX+k*step_size;
499
500                   XCopyArea(display,backbuffer,window,gc,
501                             REAL_SX+xxx,REAL_SY,
502                             FULL_SXSIZE-xxx,FULL_SYSIZE,
503                             REAL_SX,REAL_SY);
504                   XCopyArea(display,backbuffer,window,gc,
505                             REAL_SX,REAL_SY,
506                             xxx,FULL_SYSIZE,
507                             REAL_SX+FULL_SXSIZE-xxx,REAL_SY);
508
509                   XFlush(display);
510                   XSync(display,FALSE);
511                   Delay(120000 / num_steps);
512                 }
513               }
514             }
515           }
516           */
517           break;
518
519         default:
520           break;
521       }
522       break;
523     }
524     default:
525       break;
526   }
527 }
528
529 void HandleNoXEvent()
530 {
531   if (button_status && game_status!=PLAYING)
532   {
533     HandleButton(-1,-1,button_status);
534     return;
535   }
536
537   switch(game_status)
538   {
539     case MAINMENU:
540     case CHOOSELEVEL:
541     case HALLOFFAME:
542     case HELPSCREEN:
543     case SETUP:
544       HandleJoystick();
545       break;
546     case PLAYING:
547       HandleJoystick();
548       HandleGameActions();
549       break;
550     default:
551       break;
552   }
553 }
554
555 void HandleJoystick()
556 {
557   int joystick  = Joystick();
558   int keyboard  = key_joystick_mapping;
559   int joy       = (tape.playing ? TapePlayAction() : (joystick | keyboard));
560   int left      = joy & JOY_LEFT;
561   int right     = joy & JOY_RIGHT;
562   int up        = joy & JOY_UP;
563   int down      = joy & JOY_DOWN;
564   int button    = joy & JOY_BUTTON;
565   int button1   = joy & JOY_BUTTON_1;
566   int button2   = joy & JOY_BUTTON_2;
567   int newbutton = (JoystickButton() == JOY_BUTTON_NEW_PRESSED);
568   int dx        = (left ? -1    : right ? 1     : 0);
569   int dy        = (up   ? -1    : down  ? 1     : 0);
570
571   switch(game_status)
572   {
573     case MAINMENU:
574     case CHOOSELEVEL:
575     case SETUP:
576     {
577       static long joystickmove_delay = 0;
578
579       if (joystick && !button && !DelayReached(&joystickmove_delay,15))
580         break;
581
582       if (game_status==MAINMENU)
583         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
584       else if (game_status==CHOOSELEVEL)
585         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
586       else if (game_status==SETUP)
587         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
588       break;
589     }
590     case HALLOFFAME:
591       HandleHallOfFame(!newbutton);
592       break;
593     case HELPSCREEN:
594       HandleHelpScreen(!newbutton);
595       break;
596     case PLAYING:
597     {
598       BOOL moved = FALSE, snapped = FALSE, bombed = FALSE;
599
600       if (tape.pausing)
601         joy = 0;
602
603       if (!joy)
604       {
605         DigField(0,0,0,0,DF_NO_PUSH);
606         SnapField(0,0);
607         break;
608       }
609
610       if (GameOver && newbutton)
611       {
612         CloseDoor(DOOR_CLOSE_1);
613         game_status = MAINMENU;
614         DrawMainMenu();
615         return;
616       }
617
618       if (button1)
619         snapped = SnapField(dx,dy);
620       else
621       {
622         if (button2)
623           bombed = PlaceBomb();
624         moved = MoveFigure(dx,dy);
625       }
626
627       if (tape.recording && (moved || snapped || bombed))
628       {
629         if (bombed && !moved)
630           joy &= JOY_BUTTON;
631         TapeRecordAction(joy);
632       }
633       else if (tape.playing && snapped)
634         SnapField(0,0);                 /* stop snapping */
635
636       break;
637     }
638     default:
639       break;
640   }
641 }