63856e59f6480535de10aa9de2440577df04db7c
[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     drawto_field = 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     drawto_field = window;
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 = 0;
267 int Movespeed[2] = { 10, 3 };
268
269 void HandleKey(KeySym key, int key_status)
270 {
271   int joy = 0;
272
273   /* Map cursor keys to joystick directions */
274
275   switch(key)
276   {
277     case XK_Left:               /* normale Richtungen */
278 #ifdef XK_KP_Left
279     case XK_KP_Left:
280 #endif
281     case XK_KP_4:
282     case XK_J:
283     case XK_j:
284       joy |= JOY_LEFT;
285       break;
286     case XK_Right:
287 #ifdef XK_KP_Right
288     case XK_KP_Right:
289 #endif
290     case XK_KP_6:
291     case XK_K:
292     case XK_k:
293       joy |= JOY_RIGHT;
294       break;
295     case XK_Up:
296 #ifdef XK_KP_Up
297     case XK_KP_Up:
298 #endif
299     case XK_KP_8:
300     case XK_I:
301     case XK_i:
302       joy |= JOY_UP;
303       break;
304     case XK_Down:
305 #ifdef XK_KP_Down
306     case XK_KP_Down:
307 #endif
308     case XK_KP_2:
309     case XK_M:
310     case XK_m:
311       joy |= JOY_DOWN;
312       break;
313 #ifdef XK_KP_Home
314     case XK_KP_Home:            /* Diagonalrichtungen */
315 #endif
316     case XK_KP_7:
317       joy |= JOY_UP | JOY_LEFT;
318       break;
319 #ifdef XK_KP_Page_Up
320     case XK_KP_Page_Up:
321 #endif
322     case XK_KP_9:
323       joy = JOY_UP | JOY_RIGHT;
324       break;
325 #ifdef XK_KP_End
326     case XK_KP_End:
327 #endif
328     case XK_KP_1:
329       joy |= JOY_DOWN | JOY_LEFT;
330       break;
331 #ifdef XK_KP_Page_Down
332     case XK_KP_Page_Down:
333 #endif
334     case XK_KP_3:
335       joy |= JOY_DOWN | JOY_RIGHT;
336       break;
337     case XK_S:                  /* Feld entfernen */
338     case XK_s:
339       joy |= JOY_BUTTON_1 | JOY_LEFT;
340       break;
341     case XK_D:
342     case XK_d:
343       joy |= JOY_BUTTON_1 | JOY_RIGHT;
344       break;
345     case XK_E:
346     case XK_e:
347       joy |= JOY_BUTTON_1 | JOY_UP;
348       break;
349     case XK_X:
350     case XK_x:
351       joy |= JOY_BUTTON_1 | JOY_DOWN;
352       break;
353     case XK_Shift_L:            /* Linker Feuerknopf */
354       joy |= JOY_BUTTON_1;
355       break;
356     case XK_Shift_R:            /* Rechter Feuerknopf */
357     case XK_B:                  /* (Bombe legen) */
358     case XK_b:
359       joy |= JOY_BUTTON_2;
360       break;
361     default:
362       break;
363   }
364
365   if (joy)
366   {
367     if (key_status == KEY_PRESSED)
368       key_joystick_mapping |= joy;
369     else
370       key_joystick_mapping &= ~joy;
371
372     HandleJoystick();
373
374     if (game_status != PLAYING)
375       key_joystick_mapping = 0;
376   }
377
378   if (key_status == KEY_RELEASED)
379     return;
380
381   if (key==XK_Return && game_status==PLAYING && GameOver)
382   {
383     CloseDoor(DOOR_CLOSE_1);
384     game_status = MAINMENU;
385     DrawMainMenu();
386     return;
387   }
388
389   if (key==XK_Escape && game_status!=MAINMENU)  /* quick quit to MAINMENU */
390   {
391     CloseDoor(DOOR_CLOSE_1 | DOOR_NO_DELAY);
392     game_status = MAINMENU;
393     DrawMainMenu();
394     return;
395   }
396
397   if (game_status==PLAYING && (tape.playing || tape.pausing))
398     return;
399
400   switch(game_status)
401   {
402     case TYPENAME:
403       HandleTypeName(0,key);
404       break;
405     case MAINMENU:
406     case CHOOSELEVEL:
407     case SETUP:
408     {
409       switch(key)
410       {
411         case XK_Return:
412           if (game_status==MAINMENU)
413             HandleMainMenu(0,0,0,0,MB_MENU_CHOICE);
414           else if (game_status==CHOOSELEVEL)
415             HandleChooseLevel(0,0,0,0,MB_MENU_CHOICE);
416           else if (game_status==SETUP)
417             HandleSetupScreen(0,0,0,0,MB_MENU_CHOICE);
418           break;
419         default:
420           break;
421       }
422       break;
423     }
424     case HELPSCREEN:
425       HandleHelpScreen(MB_RELEASED);
426       break;
427     case HALLOFFAME:
428       switch(key)
429       {
430         case XK_Return:
431           game_status = MAINMENU;
432           DrawMainMenu();
433           BackToFront();
434           break;
435         default:
436           break;
437       }
438       break;
439     case LEVELED:
440       LevelNameTyping(key);
441       break;
442     case PLAYING:
443     {
444       switch(key)
445       {
446
447 #ifdef DEBUG
448         case XK_0:
449         case XK_1:
450         case XK_2:
451         case XK_3:
452         case XK_4:
453         case XK_5:
454         case XK_6:
455         case XK_7:
456         case XK_8:
457         case XK_9:
458           Movespeed[Movemethod] = (Movemethod == 0 ? 4 : 0) + (key - XK_0);
459           printf("method == %d, speed == %d\n",
460                  Movemethod, Movespeed[Movemethod]);
461           break;
462
463         case XK_a:
464           Movemethod = !Movemethod;
465           printf("method == %d, speed == %d\n",
466                  Movemethod, Movespeed[Movemethod]);
467           break;
468
469         case XK_f:
470           Gamespeed = 2;
471           printf("gamespeed == %d\n", Gamespeed);
472           break;
473         case XK_g:
474           Gamespeed = 3;
475           printf("gamespeed == %d\n", Gamespeed);
476           break;
477         case XK_h:
478           Gamespeed = 4;
479           printf("gamespeed == %d\n", Gamespeed);
480           break;
481         case XK_l:
482           Gamespeed = 10;
483           printf("gamespeed == %d\n", Gamespeed);
484           break;
485
486         case XK_Q:
487         case XK_q:
488           Dynamite = 1000;
489           break;
490 #endif
491
492         case XK_x:
493           /*
494           {
495             int i,j,k, num_steps = 4, step_size = TILEX / num_steps;
496
497             for(i=0;i<10;i++)
498             {
499               for(j=0;j<SCR_FIELDX;j++)
500               {
501                 for(k=0;k<num_steps;k++)
502                 {
503                   int xxx = j*TILEX+k*step_size;
504
505                   XCopyArea(display,backbuffer,window,gc,
506                             REAL_SX+xxx,REAL_SY,
507                             FULL_SXSIZE-xxx,FULL_SYSIZE,
508                             REAL_SX,REAL_SY);
509                   XCopyArea(display,backbuffer,window,gc,
510                             REAL_SX,REAL_SY,
511                             xxx,FULL_SYSIZE,
512                             REAL_SX+FULL_SXSIZE-xxx,REAL_SY);
513
514                   XFlush(display);
515                   XSync(display,FALSE);
516                   Delay(120000 / num_steps);
517                 }
518               }
519             }
520           }
521           */
522           break;
523
524         default:
525           break;
526       }
527       break;
528     }
529     default:
530       break;
531   }
532 }
533
534 void HandleNoXEvent()
535 {
536   if (button_status && game_status!=PLAYING)
537   {
538     HandleButton(-1,-1,button_status);
539     return;
540   }
541
542   switch(game_status)
543   {
544     case MAINMENU:
545     case CHOOSELEVEL:
546     case HALLOFFAME:
547     case HELPSCREEN:
548     case SETUP:
549       HandleJoystick();
550       break;
551     case PLAYING:
552       HandleJoystick();
553       HandleGameActions();
554       break;
555     default:
556       break;
557   }
558 }
559
560 void HandleJoystick()
561 {
562   int joystick  = Joystick();
563   int keyboard  = key_joystick_mapping;
564   int joy       = (tape.playing ? TapePlayAction() : (joystick | keyboard));
565   int left      = joy & JOY_LEFT;
566   int right     = joy & JOY_RIGHT;
567   int up        = joy & JOY_UP;
568   int down      = joy & JOY_DOWN;
569   int button    = joy & JOY_BUTTON;
570   int button1   = joy & JOY_BUTTON_1;
571   int button2   = joy & JOY_BUTTON_2;
572   int newbutton = (JoystickButton() == JOY_BUTTON_NEW_PRESSED);
573   int dx        = (left ? -1    : right ? 1     : 0);
574   int dy        = (up   ? -1    : down  ? 1     : 0);
575
576   if (game_status==PLAYING && (tape.playing || keyboard))
577     newbutton = ((joy & JOY_BUTTON) != 0);
578
579   switch(game_status)
580   {
581     case MAINMENU:
582     case CHOOSELEVEL:
583     case SETUP:
584     {
585       static long joystickmove_delay = 0;
586
587       if (joystick && !button && !DelayReached(&joystickmove_delay,15))
588         newbutton = dx = dy = 0;
589
590       if (game_status==MAINMENU)
591         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
592       else if (game_status==CHOOSELEVEL)
593         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
594       else if (game_status==SETUP)
595         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
596       break;
597     }
598     case HALLOFFAME:
599       HandleHallOfFame(!newbutton);
600       break;
601     case HELPSCREEN:
602       HandleHelpScreen(!newbutton);
603       break;
604     case PLAYING:
605     {
606       BOOL moved = FALSE, snapped = FALSE, bombed = FALSE;
607
608       if (GameOver && newbutton)
609       {
610         CloseDoor(DOOR_CLOSE_1);
611         game_status = MAINMENU;
612         DrawMainMenu();
613         return;
614       }
615
616       if (tape.pausing || PlayerGone)
617         joy = 0;
618
619       if (joy)
620       {
621         if (button1)
622           snapped = SnapField(dx,dy);
623         else
624         {
625           if (button2)
626             bombed = PlaceBomb();
627           moved = MoveFigure(dx,dy);
628         }
629
630         if (tape.recording && (moved || snapped || bombed))
631         {
632           if (bombed && !moved)
633             joy &= JOY_BUTTON;
634           TapeRecordAction(joy);
635         }
636         else if (tape.playing && snapped)
637           SnapField(0,0);                       /* stop snapping */
638       }
639       else
640       {
641         DigField(0,0,0,0,DF_NO_PUSH);
642         SnapField(0,0);
643         PlayerFrame = 0;
644       }
645
646       if (tape.playing && !tape.pausing && !joy && tape.counter<tape.length)
647       {
648         int next_joy =
649           tape.pos[tape.counter].joystickdata & (JOY_LEFT|JOY_RIGHT);
650
651         if (next_joy == JOY_LEFT || next_joy == JOY_RIGHT)
652         {
653           int dx = (next_joy == JOY_LEFT ? -1 : +1);
654
655           if (IN_LEV_FIELD(JX+dx,JY) && IS_PUSHABLE(Feld[JX+dx][JY]))
656           {
657             int el = Feld[JX+dx][JY];
658             int push_delay = (IS_SB_ELEMENT(el) || el==EL_SONDE ? 2 : 10);
659
660             if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
661             {
662               PlayerMovDir = next_joy;
663               PlayerFrame = FrameCounter % 4;
664               PlayerPushing = TRUE;
665             }
666           }
667         }
668       }
669
670       DrawPlayerField();
671
672       break;
673     }
674     default:
675       break;
676   }
677 }