rnd-19980827
[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(1000);              /* 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   if (soft_scrolling_on && game_status==PLAYING)
164     XCopyArea(display,fieldbuffer,backbuffer,gc,
165               FX,FY, SXSIZE,SYSIZE,
166               SX,SY);
167
168   XCopyArea(display,drawto,window,gc, x,y, width,height, x,y);
169
170   XFlush(display);
171 }
172
173 void HandleButtonEvent(XButtonEvent *event)
174 {
175   motion_status = FALSE;
176
177   if (event->type==ButtonPress)
178     button_status = event->button;
179   else
180     button_status = MB_RELEASED;
181
182   HandleButton(event->x, event->y, button_status);
183 }
184
185 void HandleMotionEvent(XMotionEvent *event)
186 {
187   motion_status = TRUE;
188
189   HandleButton(event->x, event->y, button_status);
190 }
191
192 void HandleKeyEvent(XKeyEvent *event)
193 {
194   int key_status = (event->type == KeyPress ? KEY_PRESSED : KEY_RELEASED);
195   unsigned int event_state = (game_status != PLAYING ? event->state : 0);
196   KeySym key = XLookupKeysym(event, event_state);
197
198   HandleKey(key, key_status);
199 }
200
201 void HandleFocusEvent(XFocusChangeEvent *event)
202 {
203   static int old_joystick_status = -1;
204
205   if (event->type == FocusOut)
206   {
207     XAutoRepeatOn(display);
208     old_joystick_status = joystick_status;
209     joystick_status = JOYSTICK_OFF;
210     key_joystick_mapping = 0;
211   }
212   else if (event->type == FocusIn)
213   {
214     if (game_status == PLAYING)
215       XAutoRepeatOff(display);
216     if (old_joystick_status != -1)
217       joystick_status = old_joystick_status;
218   }
219 }
220
221 void HandleButton(int mx, int my, int button)
222 {
223   static int old_mx = 0, old_my = 0;
224
225   if (mx<0 || my<0)
226   {
227     mx = old_mx;
228     my = old_my;
229   }
230   else
231   {
232     old_mx = mx;
233     old_my = my;
234
235     HandleVideoButtons(mx,my,button);
236     HandleSoundButtons(mx,my,button);
237     HandleGameButtons(mx,my,button);
238   }
239
240   switch(game_status)
241   {
242     case MAINMENU:
243       HandleMainMenu(mx,my,0,0,button);
244       break;
245     case TYPENAME:
246       HandleTypeName(0,XK_Return);
247       break;
248     case CHOOSELEVEL:
249       HandleChooseLevel(mx,my,0,0,button);
250       break;
251     case HALLOFFAME:
252       HandleHallOfFame(button);
253       break;
254     case LEVELED:
255       LevelEd(mx,my,button);
256       break;
257     case HELPSCREEN:
258       HandleHelpScreen(button);
259       break;
260     case SETUP:
261       HandleSetupScreen(mx,my,0,0,button);
262       break;
263     case PLAYING:
264       HandleGameActions();
265       break;
266     default:
267       break;
268   }
269 }
270
271 int GameSpeed = 2;
272 int MoveSpeed = 8;
273
274 void HandleKey(KeySym key, int key_status)
275 {
276   int joy = 0;
277
278   /* Map cursor keys to joystick directions */
279
280   switch(key)
281   {
282     case XK_Left:               /* normale Richtungen */
283 #ifdef XK_KP_Left
284     case XK_KP_Left:
285 #endif
286     case XK_KP_4:
287     case XK_J:
288     case XK_j:
289       joy |= JOY_LEFT;
290       break;
291     case XK_Right:
292 #ifdef XK_KP_Right
293     case XK_KP_Right:
294 #endif
295     case XK_KP_6:
296     case XK_K:
297     case XK_k:
298       joy |= JOY_RIGHT;
299       break;
300     case XK_Up:
301 #ifdef XK_KP_Up
302     case XK_KP_Up:
303 #endif
304     case XK_KP_8:
305     case XK_I:
306     case XK_i:
307       joy |= JOY_UP;
308       break;
309     case XK_Down:
310 #ifdef XK_KP_Down
311     case XK_KP_Down:
312 #endif
313     case XK_KP_2:
314     case XK_M:
315     case XK_m:
316       joy |= JOY_DOWN;
317       break;
318 #ifdef XK_KP_Home
319     case XK_KP_Home:            /* Diagonalrichtungen */
320 #endif
321     case XK_KP_7:
322       joy |= JOY_UP | JOY_LEFT;
323       break;
324 #ifdef XK_KP_Page_Up
325     case XK_KP_Page_Up:
326 #endif
327     case XK_KP_9:
328       joy = JOY_UP | JOY_RIGHT;
329       break;
330 #ifdef XK_KP_End
331     case XK_KP_End:
332 #endif
333     case XK_KP_1:
334       joy |= JOY_DOWN | JOY_LEFT;
335       break;
336 #ifdef XK_KP_Page_Down
337     case XK_KP_Page_Down:
338 #endif
339     case XK_KP_3:
340       joy |= JOY_DOWN | JOY_RIGHT;
341       break;
342     case XK_S:                  /* Feld entfernen */
343     case XK_s:
344       joy |= JOY_BUTTON_1 | JOY_LEFT;
345       break;
346     case XK_D:
347     case XK_d:
348       joy |= JOY_BUTTON_1 | JOY_RIGHT;
349       break;
350     case XK_E:
351     case XK_e:
352       joy |= JOY_BUTTON_1 | JOY_UP;
353       break;
354     case XK_X:
355     case XK_x:
356       joy |= JOY_BUTTON_1 | JOY_DOWN;
357       break;
358     case XK_Shift_L:            /* Linker Feuerknopf */
359     case XK_Control_L:
360     case XK_Alt_L:
361     case XK_Meta_L:
362       joy |= JOY_BUTTON_1;
363       break;
364     case XK_Shift_R:            /* Rechter Feuerknopf */
365     case XK_Control_R:
366     case XK_Alt_R:
367     case XK_Meta_R:
368     case XK_Mode_switch:
369     case XK_Multi_key:
370     case XK_B:                  /* (Bombe legen) */
371     case XK_b:
372       joy |= JOY_BUTTON_2;
373       break;
374     default:
375       break;
376   }
377
378   if (joy)
379   {
380     if (key_status == KEY_PRESSED)
381       key_joystick_mapping |= joy;
382     else
383       key_joystick_mapping &= ~joy;
384
385     HandleJoystick();
386   }
387
388   if (game_status != PLAYING)
389     key_joystick_mapping = 0;
390
391   if (key_status == KEY_RELEASED)
392     return;
393
394   if (key==XK_Return && game_status==PLAYING && GameOver)
395   {
396     CloseDoor(DOOR_CLOSE_1);
397     game_status = MAINMENU;
398     DrawMainMenu();
399     return;
400   }
401
402   if (key==XK_Escape && game_status!=MAINMENU)  /* quick quit to MAINMENU */
403   {
404     CloseDoor(DOOR_CLOSE_1 | DOOR_NO_DELAY);
405     game_status = MAINMENU;
406     DrawMainMenu();
407     return;
408   }
409
410   if (game_status==PLAYING && (tape.playing || tape.pausing))
411     return;
412
413   switch(game_status)
414   {
415     case TYPENAME:
416       HandleTypeName(0,key);
417       break;
418     case MAINMENU:
419     case CHOOSELEVEL:
420     case SETUP:
421     {
422       switch(key)
423       {
424         case XK_Return:
425           if (game_status==MAINMENU)
426             HandleMainMenu(0,0,0,0,MB_MENU_CHOICE);
427           else if (game_status==CHOOSELEVEL)
428             HandleChooseLevel(0,0,0,0,MB_MENU_CHOICE);
429           else if (game_status==SETUP)
430             HandleSetupScreen(0,0,0,0,MB_MENU_CHOICE);
431           break;
432         default:
433           break;
434       }
435       break;
436     }
437     case HELPSCREEN:
438       HandleHelpScreen(MB_RELEASED);
439       break;
440     case HALLOFFAME:
441       switch(key)
442       {
443         case XK_Return:
444           game_status = MAINMENU;
445           DrawMainMenu();
446           BackToFront();
447           break;
448         default:
449           break;
450       }
451       break;
452     case LEVELED:
453       LevelNameTyping(key);
454       break;
455     case PLAYING:
456     {
457       switch(key)
458       {
459
460 #ifdef DEBUG
461         case XK_0:
462         case XK_1:
463         case XK_2:
464         case XK_3:
465         case XK_4:
466         case XK_5:
467         case XK_6:
468         case XK_7:
469         case XK_8:
470         case XK_9:
471           /*
472           MoveSpeed = key - XK_0;
473           printf("speed == %d\n", MoveSpeed);
474           break;
475           */
476
477           if (key == XK_0)
478             GameSpeed = 50;
479           else
480             GameSpeed = key - XK_0;
481           printf("GameSpeed == %d\n", GameSpeed);
482           break;
483
484         case XK_a:
485           if (ScrollSteps == TILEX/4)
486             ScrollSteps = TILEX/8;
487           else
488             ScrollSteps = TILEX/4;
489           break;
490
491         case XK_f:
492           GameSpeed = 2;
493           printf("GameSpeed == %d\n", GameSpeed);
494           break;
495         case XK_g:
496           GameSpeed = 3;
497           printf("GameSpeed == %d\n", GameSpeed);
498           break;
499         case XK_h:
500           GameSpeed = 4;
501           printf("GameSpeed == %d\n", GameSpeed);
502           break;
503         case XK_l:
504           GameSpeed = 50;
505           printf("GameSpeed == %d\n", GameSpeed);
506           break;
507
508         case XK_Q:
509         case XK_q:
510           Dynamite = 1000;
511           break;
512
513         case XK_x:
514
515           {
516             int i,j,k, num_steps = 8, step_size = TILEX / num_steps;
517             static long scroll_delay=0;
518             long scroll_delay_value = 4*4 / num_steps;
519
520             printf("Scroll test\n");
521
522             for(i=0;i<3;i++)
523             {
524               for(j=0;j<SCR_FIELDX;j++)
525               {
526                 for(k=0;k<num_steps;k++)
527                 {
528                   int xxx = j*TILEX+k*step_size;
529                   int done = 0;
530
531                   while(!done)
532                   {
533                     if (DelayReached(&scroll_delay, scroll_delay_value))
534                     {
535                       XCopyArea(display,fieldbuffer,window,gc,
536                                 SX+xxx,SY,
537                                 SXSIZE-xxx,SYSIZE,
538                                 SX,SY);
539                       XCopyArea(display,fieldbuffer,window,gc,
540                                 SX,SY,
541                                 xxx,SYSIZE,
542                                 SX+SXSIZE-xxx,SY);
543   
544                       XFlush(display);
545                       XSync(display,FALSE);
546
547                       done = 1;
548                     }
549                     else
550                     {
551                       Delay(1000);
552                     }
553                   }
554   
555                   /*
556                   Delay(160000 / num_steps);
557                   */
558                   /*
559                   Delay(120000 / num_steps);
560                   */
561                 }
562               }
563             }
564           }
565
566           break;
567
568         case XK_y:
569           {
570             printf("FX = %d, FY = %d\n", FX,FY);
571
572             XCopyArea(display,fieldbuffer,window,gc,
573                       0,0,
574                       MIN(WIN_XSIZE,FXSIZE),MIN(WIN_YSIZE,FYSIZE),
575                       0,0);
576             XFlush(display);
577             XSync(display,FALSE);
578             Delay(1000000);
579           }
580
581           break;
582 #endif
583
584         default:
585           break;
586       }
587       break;
588     }
589     default:
590       break;
591   }
592 }
593
594 void HandleNoXEvent()
595 {
596   if (button_status && game_status != PLAYING)
597   {
598     HandleButton(-1,-1,button_status);
599     return;
600   }
601
602   switch(game_status)
603   {
604     case MAINMENU:
605     case CHOOSELEVEL:
606     case HALLOFFAME:
607     case HELPSCREEN:
608     case SETUP:
609       HandleJoystick();
610       break;
611     case PLAYING:
612       HandleJoystick();
613       HandleGameActions();
614       break;
615     default:
616       break;
617   }
618 }
619
620 void HandleJoystick()
621 {
622   int joystick  = Joystick();
623   int keyboard  = key_joystick_mapping;
624   int joy       = (tape.playing ? TapePlayAction() : (joystick | keyboard));
625   int left      = joy & JOY_LEFT;
626   int right     = joy & JOY_RIGHT;
627   int up        = joy & JOY_UP;
628   int down      = joy & JOY_DOWN;
629   int button    = joy & JOY_BUTTON;
630   int button1   = joy & JOY_BUTTON_1;
631   int button2   = joy & JOY_BUTTON_2;
632   int newbutton = (JoystickButton() == JOY_BUTTON_NEW_PRESSED);
633   int dx        = (left ? -1    : right ? 1     : 0);
634   int dy        = (up   ? -1    : down  ? 1     : 0);
635
636   if (game_status==PLAYING && (tape.playing || keyboard))
637     newbutton = ((joy & JOY_BUTTON) != 0);
638
639   switch(game_status)
640   {
641     case MAINMENU:
642     case CHOOSELEVEL:
643     case SETUP:
644     {
645       static long joystickmove_delay = 0;
646
647       if (joystick && !button && !DelayReached(&joystickmove_delay,15))
648         newbutton = dx = dy = 0;
649
650       if (game_status==MAINMENU)
651         HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
652       else if (game_status==CHOOSELEVEL)
653         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
654       else if (game_status==SETUP)
655         HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
656       break;
657     }
658     case HALLOFFAME:
659       HandleHallOfFame(!newbutton);
660       break;
661     case HELPSCREEN:
662       HandleHelpScreen(!newbutton);
663       break;
664     case PLAYING:
665     {
666       BOOL moved = FALSE, snapped = FALSE, bombed = FALSE;
667
668       if (GameOver && newbutton)
669       {
670         CloseDoor(DOOR_CLOSE_1);
671         game_status = MAINMENU;
672         DrawMainMenu();
673         return;
674       }
675
676       if (tape.pausing || PlayerGone)
677         joy = 0;
678
679       if (joy)
680       {
681         if (button1)
682           snapped = SnapField(dx,dy);
683         else
684         {
685           if (button2)
686             bombed = PlaceBomb();
687           moved = MoveFigure(dx,dy);
688         }
689
690         if (tape.recording && (moved || snapped || bombed))
691         {
692           if (bombed && !moved)
693             joy &= JOY_BUTTON;
694           TapeRecordAction(joy);
695         }
696         else if (tape.playing && snapped)
697           SnapField(0,0);                       /* stop snapping */
698       }
699       else
700       {
701         DigField(0,0,0,0,DF_NO_PUSH);
702         SnapField(0,0);
703         PlayerFrame = 0;
704       }
705
706       if (tape.playing && !tape.pausing && !joy && tape.counter<tape.length)
707       {
708         int next_joy =
709           tape.pos[tape.counter].joystickdata & (JOY_LEFT|JOY_RIGHT);
710
711         if (next_joy == JOY_LEFT || next_joy == JOY_RIGHT)
712         {
713           int dx = (next_joy == JOY_LEFT ? -1 : +1);
714
715           if (IN_LEV_FIELD(JX+dx,JY) && IS_PUSHABLE(Feld[JX+dx][JY]))
716           {
717             int el = Feld[JX+dx][JY];
718             int push_delay = (IS_SB_ELEMENT(el) || el==EL_SONDE ? 2 : 10);
719
720             if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
721             {
722               PlayerMovDir = next_joy;
723               PlayerFrame = FrameCounter % 4;
724               PlayerPushing = TRUE;
725             }
726           }
727         }
728       }
729       break;
730     }
731     default:
732       break;
733   }
734 }