rnd-19980810
[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 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_B:                  /* (Bombe legen) */
365     case XK_b:
366       joy |= JOY_BUTTON_2;
367       break;
368     default:
369       break;
370   }
371
372   if (joy)
373   {
374     if (key_status == KEY_PRESSED)
375       key_joystick_mapping |= joy;
376     else
377       key_joystick_mapping &= ~joy;
378
379     HandleJoystick();
380
381     if (game_status != PLAYING)
382       key_joystick_mapping = 0;
383   }
384
385   if (key_status == KEY_RELEASED)
386     return;
387
388   if (key==XK_Return && game_status==PLAYING && GameOver)
389   {
390     CloseDoor(DOOR_CLOSE_1);
391     game_status = MAINMENU;
392     DrawMainMenu();
393     return;
394   }
395
396   if (key==XK_Escape && game_status!=MAINMENU)  /* quick quit to MAINMENU */
397   {
398     CloseDoor(DOOR_CLOSE_1 | DOOR_NO_DELAY);
399     game_status = MAINMENU;
400     DrawMainMenu();
401     return;
402   }
403
404   if (game_status==PLAYING && (tape.playing || tape.pausing))
405     return;
406
407   switch(game_status)
408   {
409     case TYPENAME:
410       HandleTypeName(0,key);
411       break;
412     case MAINMENU:
413     case CHOOSELEVEL:
414     case SETUP:
415     {
416       switch(key)
417       {
418         case XK_Return:
419           if (game_status==MAINMENU)
420             HandleMainMenu(0,0,0,0,MB_MENU_CHOICE);
421           else if (game_status==CHOOSELEVEL)
422             HandleChooseLevel(0,0,0,0,MB_MENU_CHOICE);
423           else if (game_status==SETUP)
424             HandleSetupScreen(0,0,0,0,MB_MENU_CHOICE);
425           break;
426         default:
427           break;
428       }
429       break;
430     }
431     case HELPSCREEN:
432       HandleHelpScreen(MB_RELEASED);
433       break;
434     case HALLOFFAME:
435       switch(key)
436       {
437         case XK_Return:
438           game_status = MAINMENU;
439           DrawMainMenu();
440           BackToFront();
441           break;
442         default:
443           break;
444       }
445       break;
446     case LEVELED:
447       LevelNameTyping(key);
448       break;
449     case PLAYING:
450     {
451       switch(key)
452       {
453
454 #ifdef DEBUG
455         case XK_0:
456         case XK_1:
457         case XK_2:
458         case XK_3:
459         case XK_4:
460         case XK_5:
461         case XK_6:
462         case XK_7:
463         case XK_8:
464         case XK_9:
465           Movespeed[Movemethod] = (Movemethod == 0 ? 4 : 0) + (key - XK_0);
466           printf("method == %d, speed == %d (%s)\n",
467                  Movemethod, Movespeed[Movemethod],
468                  Movespeed_text[Movemethod]);
469           break;
470
471         case XK_a:
472           Movemethod = !Movemethod;
473           printf("method == %d, speed == %d (%s)\n",
474                  Movemethod, Movespeed[Movemethod],
475                  Movespeed_text[Movemethod]);
476           break;
477
478         case XK_f:
479           Gamespeed = 2;
480           printf("gamespeed == %d\n", Gamespeed);
481           break;
482         case XK_g:
483           Gamespeed = 3;
484           printf("gamespeed == %d\n", Gamespeed);
485           break;
486         case XK_h:
487           Gamespeed = 4;
488           printf("gamespeed == %d\n", Gamespeed);
489           break;
490         case XK_l:
491           Gamespeed = 10;
492           printf("gamespeed == %d\n", Gamespeed);
493           break;
494
495         case XK_Q:
496         case XK_q:
497           Dynamite = 1000;
498           break;
499 #endif
500
501         case XK_x:
502
503           {
504             int i,j,k, num_steps = 16, step_size = TILEX / num_steps;
505             static long scroll_delay=0;
506             long scroll_delay_value = 4*4 / num_steps;
507
508             printf("Scroll test\n");
509
510             for(i=0;i<10;i++)
511             {
512               for(j=0;j<SCR_FIELDX;j++)
513               {
514                 for(k=0;k<num_steps;k++)
515                 {
516                   int xxx = j*TILEX+k*step_size;
517                   int done = 0;
518
519                   while(!done)
520                   {
521                     if (DelayReached(&scroll_delay, scroll_delay_value))
522                     {
523                       XCopyArea(display,backbuffer,window,gc,
524                                 SX+xxx,SY,
525                                 SXSIZE-xxx,SYSIZE,
526                                 SX,SY);
527                       XCopyArea(display,backbuffer,window,gc,
528                                 SX,SY,
529                                 xxx,SYSIZE,
530                                 SX+SXSIZE-xxx,SY);
531   
532                       XFlush(display);
533                       XSync(display,FALSE);
534
535                       done = 1;
536                     }
537                     else
538                     {
539                       Delay(1000);
540                     }
541                   }
542   
543                   /*
544                   Delay(160000 / num_steps);
545                   */
546                   /*
547                   Delay(120000 / num_steps);
548                   */
549                 }
550               }
551             }
552           }
553
554           break;
555
556         default:
557           break;
558       }
559       break;
560     }
561     default:
562       break;
563   }
564 }
565
566 void HandleNoXEvent()
567 {
568   if (button_status && game_status!=PLAYING)
569   {
570     HandleButton(-1,-1,button_status);
571     return;
572   }
573
574   switch(game_status)
575   {
576     case MAINMENU:
577     case CHOOSELEVEL:
578     case HALLOFFAME:
579     case HELPSCREEN:
580     case SETUP:
581       HandleJoystick();
582       break;
583     case PLAYING:
584       HandleJoystick();
585       HandleGameActions();
586       break;
587     default:
588       break;
589   }
590 }
591
592 void HandleJoystick()
593 {
594   int joystick  = Joystick();
595   int keyboard  = key_joystick_mapping;
596   int joy       = (tape.playing ? TapePlayAction() : (joystick | keyboard));
597   int left      = joy & JOY_LEFT;
598   int right     = joy & JOY_RIGHT;
599   int up        = joy & JOY_UP;
600   int down      = joy & JOY_DOWN;
601   int button    = joy & JOY_BUTTON;
602   int button1   = joy & JOY_BUTTON_1;
603   int button2   = joy & JOY_BUTTON_2;
604   int newbutton = (JoystickButton() == JOY_BUTTON_NEW_PRESSED);
605   int dx        = (left ? -1    : right ? 1     : 0);
606   int dy        = (up   ? -1    : down  ? 1     : 0);
607
608   if (game_status==PLAYING && (tape.playing || keyboard))
609     newbutton = ((joy & JOY_BUTTON) != 0);
610
611   switch(game_status)
612   {
613     case MAINMENU:
614     case CHOOSELEVEL:
615     case SETUP:
616     {
617       static long joystickmove_delay = 0;
618
619       if (joystick && !button && !DelayReached(&joystickmove_delay,15))
620         newbutton = dx = dy = 0;
621
622       if (game_status==MAINMENU)
623         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
624       else if (game_status==CHOOSELEVEL)
625         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
626       else if (game_status==SETUP)
627         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
628       break;
629     }
630     case HALLOFFAME:
631       HandleHallOfFame(!newbutton);
632       break;
633     case HELPSCREEN:
634       HandleHelpScreen(!newbutton);
635       break;
636     case PLAYING:
637     {
638       BOOL moved = FALSE, snapped = FALSE, bombed = FALSE;
639
640       if (GameOver && newbutton)
641       {
642         CloseDoor(DOOR_CLOSE_1);
643         game_status = MAINMENU;
644         DrawMainMenu();
645         return;
646       }
647
648
649
650       if (PlayerMovPos)
651         ScrollFigure(0);
652
653
654
655       if (tape.pausing || PlayerGone)
656         joy = 0;
657
658       if (joy)
659       {
660         if (button1)
661           snapped = SnapField(dx,dy);
662         else
663         {
664           if (button2)
665             bombed = PlaceBomb();
666           moved = MoveFigure(dx,dy);
667         }
668
669         if (tape.recording && (moved || snapped || bombed))
670         {
671           if (bombed && !moved)
672             joy &= JOY_BUTTON;
673           TapeRecordAction(joy);
674         }
675         else if (tape.playing && snapped)
676           SnapField(0,0);                       /* stop snapping */
677       }
678       else
679       {
680         DigField(0,0,0,0,DF_NO_PUSH);
681         SnapField(0,0);
682         PlayerFrame = 0;
683       }
684
685       if (tape.playing && !tape.pausing && !joy && tape.counter<tape.length)
686       {
687         int next_joy =
688           tape.pos[tape.counter].joystickdata & (JOY_LEFT|JOY_RIGHT);
689
690         if (next_joy == JOY_LEFT || next_joy == JOY_RIGHT)
691         {
692           int dx = (next_joy == JOY_LEFT ? -1 : +1);
693
694           if (IN_LEV_FIELD(JX+dx,JY) && IS_PUSHABLE(Feld[JX+dx][JY]))
695           {
696             int el = Feld[JX+dx][JY];
697             int push_delay = (IS_SB_ELEMENT(el) || el==EL_SONDE ? 2 : 10);
698
699             if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
700             {
701               PlayerMovDir = next_joy;
702               PlayerFrame = FrameCounter % 4;
703               PlayerPushing = TRUE;
704             }
705           }
706         }
707       }
708
709       DrawPlayerField();
710
711       break;
712     }
713     default:
714       break;
715   }
716 }