rnd-20020314-1-src
[rocksndiamonds.git] / src / tape.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2001 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tape.c                                                   *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "tape.h"
17 #include "game.h"
18 #include "tools.h"
19 #include "files.h"
20 #include "network.h"
21 #include "cartoons.h"
22
23 /* tape button identifiers */
24 #define TAPE_CTRL_ID_EJECT              0
25 #define TAPE_CTRL_ID_STOP               1
26 #define TAPE_CTRL_ID_PAUSE              2
27 #define TAPE_CTRL_ID_RECORD             3
28 #define TAPE_CTRL_ID_PLAY               4
29
30 #define NUM_TAPE_BUTTONS                5
31
32 /* forward declaration for internal use */
33 static void HandleTapeButtons(struct GadgetInfo *);
34
35 static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS];
36
37
38 /* ========================================================================= */
39 /* video tape definitions                                                    */
40 /* ========================================================================= */
41
42 /* some positions in the video tape control window */
43 #define VIDEO_DATE_LABEL_XPOS   (VIDEO_DISPLAY1_XPOS)
44 #define VIDEO_DATE_LABEL_YPOS   (VIDEO_DISPLAY1_YPOS)
45 #define VIDEO_DATE_LABEL_XSIZE  (VIDEO_DISPLAY_XSIZE)
46 #define VIDEO_DATE_LABEL_YSIZE  (VIDEO_DISPLAY_YSIZE)
47 #define VIDEO_DATE_XPOS         (VIDEO_DISPLAY1_XPOS + 1)
48 #define VIDEO_DATE_YPOS         (VIDEO_DISPLAY1_YPOS + 14)
49 #define VIDEO_DATE_XSIZE        (VIDEO_DISPLAY_XSIZE)
50 #define VIDEO_DATE_YSIZE        16
51 #define VIDEO_REC_LABEL_XPOS    (VIDEO_DISPLAY2_XPOS)
52 #define VIDEO_REC_LABEL_YPOS    (VIDEO_DISPLAY2_YPOS)
53 #define VIDEO_REC_LABEL_XSIZE   20
54 #define VIDEO_REC_LABEL_YSIZE   12
55 #define VIDEO_REC_SYMBOL_XPOS   (VIDEO_DISPLAY2_XPOS + 20)
56 #define VIDEO_REC_SYMBOL_YPOS   (VIDEO_DISPLAY2_YPOS)
57 #define VIDEO_REC_SYMBOL_XSIZE  16
58 #define VIDEO_REC_SYMBOL_YSIZE  16
59 #define VIDEO_PLAY_LABEL_XPOS   (VIDEO_DISPLAY2_XPOS + 65)
60 #define VIDEO_PLAY_LABEL_YPOS   (VIDEO_DISPLAY2_YPOS)
61 #define VIDEO_PLAY_LABEL_XSIZE  22
62 #define VIDEO_PLAY_LABEL_YSIZE  12
63 #define VIDEO_PLAY_SYMBOL_XPOS  (VIDEO_DISPLAY2_XPOS + 52)
64 #define VIDEO_PLAY_SYMBOL_YPOS  (VIDEO_DISPLAY2_YPOS)
65 #define VIDEO_PLAY_SYMBOL_XSIZE 11
66 #define VIDEO_PLAY_SYMBOL_YSIZE 13
67 #define VIDEO_PAUSE_LABEL_XPOS  (VIDEO_DISPLAY2_XPOS)
68 #define VIDEO_PAUSE_LABEL_YPOS  (VIDEO_DISPLAY2_YPOS + 20)
69 #define VIDEO_PAUSE_LABEL_XSIZE 35
70 #define VIDEO_PAUSE_LABEL_YSIZE 8
71 #define VIDEO_PAUSE_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS + 35)
72 #define VIDEO_PAUSE_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS)
73 #define VIDEO_PAUSE_SYMBOL_XSIZE 17
74 #define VIDEO_PAUSE_SYMBOL_YSIZE 13
75 #define VIDEO_TIME_XPOS         (VIDEO_DISPLAY2_XPOS + 38)
76 #define VIDEO_TIME_YPOS         (VIDEO_DISPLAY2_YPOS + 14)
77 #define VIDEO_TIME_XSIZE        50
78 #define VIDEO_TIME_YSIZE        16
79
80 /* special */
81 #define VIDEO_PBEND_LABEL_XPOS  5
82 #define VIDEO_PBEND_LABEL_YPOS  220
83 #define VIDEO_PBEND_LABEL_XSIZE 35
84 #define VIDEO_PBEND_LABEL_YSIZE 30
85
86 #define VIDEO_STATE_OFF         (VIDEO_STATE_PLAY_OFF   |       \
87                                  VIDEO_STATE_REC_OFF    |       \
88                                  VIDEO_STATE_PAUSE_OFF  |       \
89                                  VIDEO_STATE_FFWD_OFF   |       \
90                                  VIDEO_STATE_PBEND_OFF  |       \
91                                  VIDEO_STATE_DATE_OFF   |       \
92                                  VIDEO_STATE_TIME_OFF)
93 #define VIDEO_PRESS_OFF         (VIDEO_PRESS_PLAY_OFF   |       \
94                                  VIDEO_PRESS_REC_OFF    |       \
95                                  VIDEO_PRESS_PAUSE_OFF  |       \
96                                  VIDEO_PRESS_STOP_OFF   |       \
97                                  VIDEO_PRESS_EJECT_OFF)
98 #define VIDEO_ALL_OFF           (VIDEO_STATE_OFF | VIDEO_PRESS_OFF)
99
100 #define VIDEO_STATE_ON          (VIDEO_STATE_PLAY_ON    |       \
101                                  VIDEO_STATE_REC_ON     |       \
102                                  VIDEO_STATE_PAUSE_ON   |       \
103                                  VIDEO_STATE_FFWD_ON    |       \
104                                  VIDEO_STATE_PBEND_ON   |       \
105                                  VIDEO_STATE_DATE_ON    |       \
106                                  VIDEO_STATE_TIME_ON)
107 #define VIDEO_PRESS_ON          (VIDEO_PRESS_PLAY_ON    |       \
108                                  VIDEO_PRESS_REC_ON     |       \
109                                  VIDEO_PRESS_PAUSE_ON   |       \
110                                  VIDEO_PRESS_STOP_ON    |       \
111                                  VIDEO_PRESS_EJECT_ON)
112 #define VIDEO_ALL_ON            (VIDEO_STATE_ON | VIDEO_PRESS_ON)
113
114 #define VIDEO_STATE             (VIDEO_STATE_ON | VIDEO_STATE_OFF)
115 #define VIDEO_PRESS             (VIDEO_PRESS_ON | VIDEO_PRESS_OFF)
116 #define VIDEO_ALL               (VIDEO_ALL_ON | VIDEO_ALL_OFF)
117
118
119 /* ========================================================================= */
120 /* video display functions                                                   */
121 /* ========================================================================= */
122
123 void DrawVideoDisplay(unsigned long state, unsigned long value)
124 {
125   int i;
126   int part_label = 0, part_symbol = 1;
127   int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
128   static char *monatsname[12] =
129   {
130     "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
131     "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
132   };
133   static int video_pos[5][2][4] =
134   {
135     {{ VIDEO_PLAY_LABEL_XPOS, VIDEO_PLAY_LABEL_YPOS,
136        VIDEO_PLAY_LABEL_XSIZE,VIDEO_PLAY_LABEL_YSIZE },
137      { VIDEO_PLAY_SYMBOL_XPOS, VIDEO_PLAY_SYMBOL_YPOS,
138        VIDEO_PLAY_SYMBOL_XSIZE,VIDEO_PLAY_SYMBOL_YSIZE }},
139
140     {{ VIDEO_REC_LABEL_XPOS, VIDEO_REC_LABEL_YPOS,
141        VIDEO_REC_LABEL_XSIZE,VIDEO_REC_LABEL_YSIZE },
142      { VIDEO_REC_SYMBOL_XPOS, VIDEO_REC_SYMBOL_YPOS,
143        VIDEO_REC_SYMBOL_XSIZE,VIDEO_REC_SYMBOL_YSIZE }},
144
145     {{ VIDEO_PAUSE_LABEL_XPOS, VIDEO_PAUSE_LABEL_YPOS,
146        VIDEO_PAUSE_LABEL_XSIZE,VIDEO_PAUSE_LABEL_YSIZE },
147      { VIDEO_PAUSE_SYMBOL_XPOS, VIDEO_PAUSE_SYMBOL_YPOS,
148        VIDEO_PAUSE_SYMBOL_XSIZE,VIDEO_PAUSE_SYMBOL_YSIZE }},
149
150     {{ VIDEO_DATE_LABEL_XPOS, VIDEO_DATE_LABEL_YPOS,
151        VIDEO_DATE_LABEL_XSIZE,VIDEO_DATE_LABEL_YSIZE },
152      { VIDEO_DATE_XPOS, VIDEO_DATE_YPOS,
153        VIDEO_DATE_XSIZE,VIDEO_DATE_YSIZE }},
154
155     {{ 0,0,
156        0,0 },
157      { VIDEO_TIME_XPOS, VIDEO_TIME_YPOS,
158        VIDEO_TIME_XSIZE,VIDEO_TIME_YSIZE }}
159   };
160
161   if (state & VIDEO_STATE_PBEND_OFF)
162   {
163     int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
164
165     BlitBitmap(pix[PIX_DOOR], drawto,
166                cx + VIDEO_REC_LABEL_XPOS,
167                cy + VIDEO_REC_LABEL_YPOS,
168                VIDEO_PBEND_LABEL_XSIZE,
169                VIDEO_PBEND_LABEL_YSIZE,
170                VX + VIDEO_REC_LABEL_XPOS,
171                VY + VIDEO_REC_LABEL_YPOS);
172   }
173
174   for(i=0;i<10;i++)
175   {
176     if (state & (1<<i))
177     {
178       int pos = i/2, cx, cy = DOOR_GFX_PAGEY2;
179
180       if (i%2)                  /* i ungerade => STATE_ON / PRESS_OFF */
181         cx = DOOR_GFX_PAGEX4;
182       else
183         cx = DOOR_GFX_PAGEX3;   /* i gerade => STATE_OFF / PRESS_ON */
184
185       if (video_pos[pos][part_label][0] && value != VIDEO_DISPLAY_SYMBOL_ONLY)
186         BlitBitmap(pix[PIX_DOOR], drawto,
187                    cx + video_pos[pos][part_label][xpos],
188                    cy + video_pos[pos][part_label][ypos],
189                    video_pos[pos][part_label][xsize],
190                    video_pos[pos][part_label][ysize],
191                    VX + video_pos[pos][part_label][xpos],
192                    VY + video_pos[pos][part_label][ypos]);
193       if (video_pos[pos][part_symbol][0] && value != VIDEO_DISPLAY_LABEL_ONLY)
194         BlitBitmap(pix[PIX_DOOR], drawto,
195                    cx + video_pos[pos][part_symbol][xpos],
196                    cy + video_pos[pos][part_symbol][ypos],
197                    video_pos[pos][part_symbol][xsize],
198                    video_pos[pos][part_symbol][ysize],
199                    VX + video_pos[pos][part_symbol][xpos],
200                    VY + video_pos[pos][part_symbol][ypos]);
201     }
202   }
203
204   if (state & VIDEO_STATE_FFWD_ON)
205   {
206     int cx = DOOR_GFX_PAGEX4, cy = DOOR_GFX_PAGEY2;
207
208     BlitBitmap(pix[PIX_DOOR], drawto,
209                cx + VIDEO_PLAY_SYMBOL_XPOS,
210                cy + VIDEO_PLAY_SYMBOL_YPOS,
211                VIDEO_PLAY_SYMBOL_XSIZE - 2,
212                VIDEO_PLAY_SYMBOL_YSIZE,
213                VX + VIDEO_PLAY_SYMBOL_XPOS - 9,
214                VY + VIDEO_PLAY_SYMBOL_YPOS);
215   }
216
217   if (state & VIDEO_STATE_PBEND_ON)
218   {
219     int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
220
221     BlitBitmap(pix[PIX_DOOR], drawto,
222                cx + VIDEO_PBEND_LABEL_XPOS,
223                cy + VIDEO_PBEND_LABEL_YPOS,
224                VIDEO_PBEND_LABEL_XSIZE,
225                VIDEO_PBEND_LABEL_YSIZE,
226                VX + VIDEO_REC_LABEL_XPOS,
227                VY + VIDEO_REC_LABEL_YPOS);
228   }
229
230   if (state & VIDEO_STATE_DATE_ON)
231   {
232     int tag = value % 100;
233     int monat = (value/100) % 100;
234     int jahr = (value/10000);
235
236     DrawText(VX+VIDEO_DATE_XPOS,VY+VIDEO_DATE_YPOS,
237              int2str(tag,2),FS_SMALL,FC_SPECIAL1);
238     DrawText(VX+VIDEO_DATE_XPOS+27,VY+VIDEO_DATE_YPOS,
239              monatsname[monat],FS_SMALL,FC_SPECIAL1);
240     DrawText(VX+VIDEO_DATE_XPOS+64,VY+VIDEO_DATE_YPOS,
241              int2str(jahr,2),FS_SMALL,FC_SPECIAL1);
242   }
243
244   if (state & VIDEO_STATE_TIME_ON)
245   {
246     int min = value / 60;
247     int sec = value % 60;
248
249     DrawText(VX+VIDEO_TIME_XPOS,VY+VIDEO_TIME_YPOS,
250              int2str(min,2),FS_SMALL,FC_SPECIAL1);
251     DrawText(VX+VIDEO_TIME_XPOS+27,VY+VIDEO_TIME_YPOS,
252              int2str(sec,2),FS_SMALL,FC_SPECIAL1);
253   }
254
255   if (state & VIDEO_STATE_DATE)
256     redraw_mask |= REDRAW_VIDEO_1;
257   if ((state & ~VIDEO_STATE_DATE) & VIDEO_STATE)
258     redraw_mask |= REDRAW_VIDEO_2;
259   if (state & VIDEO_PRESS)
260     redraw_mask |= REDRAW_VIDEO_3;
261 }
262
263 void DrawCompleteVideoDisplay()
264 {
265   BlitBitmap(pix[PIX_DOOR], drawto, DOOR_GFX_PAGEX3, DOOR_GFX_PAGEY2,
266              gfx.vxsize, gfx.vysize, gfx.vx, gfx.vy);
267   BlitBitmap(pix[PIX_DOOR], drawto,
268              DOOR_GFX_PAGEX4 + VIDEO_CONTROL_XPOS,
269              DOOR_GFX_PAGEY2 + VIDEO_CONTROL_YPOS,
270              VIDEO_CONTROL_XSIZE, VIDEO_CONTROL_YSIZE,
271              gfx.vx + VIDEO_CONTROL_XPOS, gfx.vy + VIDEO_CONTROL_YPOS);
272
273   DrawVideoDisplay(VIDEO_ALL_OFF, 0);
274   if (tape.date && tape.length)
275   {
276     DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
277     DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds);
278   }
279
280   BlitBitmap(drawto, pix[PIX_DB_DOOR], gfx.vx, gfx.vy, gfx.vxsize, gfx.vysize,
281              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
282 }
283
284
285 /* ========================================================================= */
286 /* tape control functions                                                    */
287 /* ========================================================================= */
288
289 void TapeStartRecording()
290 {
291   time_t zeit1 = time(NULL);
292   struct tm *zeit2 = localtime(&zeit1);
293   int i;
294
295   if (!TAPE_IS_STOPPED(tape))
296     TapeStop();
297
298   tape.level_nr = level_nr;
299   tape.length = 0;
300   tape.counter = 0;
301   tape.pos[tape.counter].delay = 0;
302   tape.recording = TRUE;
303   tape.playing = FALSE;
304   tape.pausing = FALSE;
305   tape.changed = TRUE;
306   tape.date = 10000*(zeit2->tm_year%100) + 100*zeit2->tm_mon + zeit2->tm_mday;
307   tape.random_seed = InitRND(NEW_RANDOMIZE);
308
309   for(i=0; i<MAX_PLAYERS; i++)
310     tape.player_participates[i] = FALSE;
311
312   DrawVideoDisplay(VIDEO_STATE_REC_ON, 0);
313   DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
314   DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
315 }
316
317 void TapeStopRecording()
318 {
319 #if 0
320   int i;
321 #endif
322
323   if (!tape.recording)
324     return;
325
326 #if 0
327   for(i=0; i<MAX_PLAYERS; i++)
328     tape.pos[tape.counter].action[i] = 0;
329 #endif
330
331   tape.counter++;
332   tape.length = tape.counter;
333   tape.length_seconds = GetTapeLength();
334   tape.recording = FALSE;
335   tape.pausing = FALSE;
336   DrawVideoDisplay(VIDEO_STATE_REC_OFF, 0);
337 }
338
339 #if 0
340 void TapeRecordAction(byte joy[MAX_PLAYERS])
341 {
342   int i;
343
344   if (!tape.recording || tape.pausing)
345     return;
346
347   if (tape.counter >= MAX_TAPELEN-1)
348   {
349     TapeStopRecording();
350     return;
351   }
352
353   for(i=0; i<MAX_PLAYERS; i++)
354     tape.pos[tape.counter].action[i] = joy[i];
355
356   tape.counter++;
357   tape.pos[tape.counter].delay = 0;
358 }
359
360 #else
361
362 void TapeRecordAction(byte action[MAX_PLAYERS])
363 {
364   int i;
365
366   if (!tape.recording || tape.pausing)
367     return;
368
369   if (tape.counter >= MAX_TAPELEN-1)
370   {
371     TapeStopRecording();
372     return;
373   }
374
375   if (tape.pos[tape.counter].delay > 0)         /* already stored action */
376   {
377     boolean changed_events = FALSE;
378
379     for(i=0; i<MAX_PLAYERS; i++)
380       if (tape.pos[tape.counter].action[i] != action[i])
381         changed_events = TRUE;
382
383     if (changed_events || tape.pos[tape.counter].delay >= 255)
384     {
385       tape.counter++;
386       tape.pos[tape.counter].delay = 0;
387     }
388     else
389       tape.pos[tape.counter].delay++;
390   }
391
392   if (tape.pos[tape.counter].delay == 0)        /* store new action */
393   {
394     for(i=0; i<MAX_PLAYERS; i++)
395       tape.pos[tape.counter].action[i] = action[i];
396
397     tape.pos[tape.counter].delay++;
398   }
399 }
400 #endif
401
402 #if 0
403 void TapeRecordDelay()
404 {
405   int i;
406
407   if (!tape.recording || tape.pausing)
408     return;
409
410   if (tape.counter >= MAX_TAPELEN)
411   {
412     TapeStopRecording();
413     return;
414   }
415
416   tape.pos[tape.counter].delay++;
417
418   if (tape.pos[tape.counter].delay >= 255)
419   {
420     for(i=0; i<MAX_PLAYERS; i++)
421       tape.pos[tape.counter].action[i] = 0;
422
423     tape.counter++;
424     tape.pos[tape.counter].delay = 0;
425   }
426 }
427
428 #else
429
430 void TapeRecordDelay()
431 {
432 }
433 #endif
434
435 void TapeTogglePause()
436 {
437   unsigned long state;
438
439   if (!tape.recording && !tape.playing)
440     return;
441
442   tape.pausing = !tape.pausing;
443   tape.fast_forward = FALSE;
444   tape.pause_before_death = FALSE;
445
446   state = (tape.pausing ? VIDEO_STATE_PAUSE_ON : VIDEO_STATE_PAUSE_OFF);
447   if (tape.playing)
448     state |= VIDEO_STATE_PBEND_OFF;
449
450   DrawVideoDisplay(state, 0);
451 }
452
453 void TapeStartPlaying()
454 {
455   if (TAPE_IS_EMPTY(tape))
456     return;
457
458   if (!TAPE_IS_STOPPED(tape))
459     TapeStop();
460
461   tape.counter = 0;
462   tape.delay_played = 0;
463   tape.pause_before_death = FALSE;
464   tape.recording = FALSE;
465   tape.playing = TRUE;
466   tape.pausing = FALSE;
467   tape.fast_forward = FALSE;
468   InitRND(tape.random_seed);
469
470   DrawVideoDisplay(VIDEO_STATE_PLAY_ON, 0);
471   DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
472   DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
473 }
474
475 void TapeStopPlaying()
476 {
477   if (!tape.playing)
478     return;
479
480   tape.playing = FALSE;
481   tape.pausing = FALSE;
482   DrawVideoDisplay(VIDEO_STATE_PLAY_OFF, 0);
483 }
484
485 #if 0
486 byte *TapePlayAction()
487 {
488   static byte joy[MAX_PLAYERS];
489   int i;
490
491   if (!tape.playing || tape.pausing)
492     return(NULL);
493
494   if (tape.counter >= tape.length)
495   {
496     TapeStop();
497     return(NULL);
498   }
499
500   if (tape.delay_played == tape.pos[tape.counter].delay)
501   {
502     tape.delay_played = 0;
503     tape.counter++;
504
505     for(i=0; i<MAX_PLAYERS; i++)
506       joy[i] = tape.pos[tape.counter-1].action[i];
507   }
508   else
509   {
510     for(i=0; i<MAX_PLAYERS; i++)
511       joy[i] = 0;
512   }
513
514   return(joy);
515 }
516
517 #else
518
519 byte *TapePlayAction()
520 {
521   static byte action[MAX_PLAYERS];
522   int i;
523
524   if (!tape.playing || tape.pausing)
525     return NULL;
526
527   if (tape.pause_before_death)  /* STOP 10s BEFORE PLAYER GETS KILLED... */
528   {
529     if (!(FrameCounter % 20))
530     {
531       if ((FrameCounter / 20) % 2)
532         DrawVideoDisplay(VIDEO_STATE_PBEND_ON, VIDEO_DISPLAY_LABEL_ONLY);
533       else
534         DrawVideoDisplay(VIDEO_STATE_PBEND_OFF, VIDEO_DISPLAY_LABEL_ONLY);
535     }
536
537     if (TimePlayed > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH)
538     {
539       TapeTogglePause();
540       return NULL;
541     }
542   }
543
544   if (tape.counter >= tape.length)
545   {
546     TapeStop();
547     return NULL;
548   }
549
550   for(i=0; i<MAX_PLAYERS; i++)
551     action[i] = tape.pos[tape.counter].action[i];
552
553   tape.delay_played++;
554   if (tape.delay_played >= tape.pos[tape.counter].delay)
555   {
556     tape.counter++;
557     tape.delay_played = 0;
558   }
559
560   return action;
561 }
562 #endif
563
564 #if 0
565 boolean TapePlayDelay()
566 {
567   if (!tape.playing || tape.pausing)
568     return(FALSE);
569
570   if (tape.pause_before_death)  /* STOP 10s BEFORE PLAYER GETS KILLED... */
571   {
572     if (!(FrameCounter % 20))
573     {
574       if ((FrameCounter / 20) % 2)
575         DrawVideoDisplay(VIDEO_STATE_PBEND_ON, VIDEO_DISPLAY_LABEL_ONLY);
576       else
577         DrawVideoDisplay(VIDEO_STATE_PBEND_OFF, VIDEO_DISPLAY_LABEL_ONLY);
578     }
579
580     if (TimePlayed > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH)
581     {
582       TapeTogglePause();
583       return(FALSE);
584     }
585   }
586
587   if (tape.counter >= tape.length)
588   {
589     TapeStop();
590     return(TRUE);
591   }
592
593   if (tape.delay_played < tape.pos[tape.counter].delay)
594   {
595     tape.delay_played++;
596     return(TRUE);
597   }
598   else
599     return(FALSE);
600 }
601
602 #else
603
604 boolean TapePlayDelay()
605 {
606   return TRUE|FALSE;    /* ...it doesn't matter at all */
607 }
608 #endif
609
610 void TapeStop()
611 {
612   TapeStopRecording();
613   TapeStopPlaying();
614
615   DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
616   if (tape.date && tape.length)
617   {
618     DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
619     DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds);
620   }
621 }
622
623 void TapeErase()
624 {
625   tape.length = 0;
626 }
627
628 unsigned int GetTapeLength()
629 {
630   unsigned int tape_length = 0;
631   int i;
632
633   if (TAPE_IS_EMPTY(tape))
634     return(0);
635
636   for(i=0;i<tape.length;i++)
637     tape_length += tape.pos[i].delay;
638
639   return(tape_length * GAME_FRAME_DELAY / 1000);
640 }
641
642 /* ---------- new tape button stuff ---------------------------------------- */
643
644 /* graphic position values for tape buttons */
645 #define TAPE_BUTTON_XSIZE       18
646 #define TAPE_BUTTON_YSIZE       18
647 #define TAPE_BUTTON_XPOS        5
648 #define TAPE_BUTTON_YPOS        77
649
650 #define TAPE_BUTTON_EJECT_XPOS  (TAPE_BUTTON_XPOS + 0 * TAPE_BUTTON_XSIZE)
651 #define TAPE_BUTTON_STOP_XPOS   (TAPE_BUTTON_XPOS + 1 * TAPE_BUTTON_XSIZE)
652 #define TAPE_BUTTON_PAUSE_XPOS  (TAPE_BUTTON_XPOS + 2 * TAPE_BUTTON_XSIZE)
653 #define TAPE_BUTTON_RECORD_XPOS (TAPE_BUTTON_XPOS + 3 * TAPE_BUTTON_XSIZE)
654 #define TAPE_BUTTON_PLAY_XPOS   (TAPE_BUTTON_XPOS + 4 * TAPE_BUTTON_XSIZE)
655
656 static struct
657 {
658   int x, y;
659   int gadget_id;
660   char *infotext;
661 } tapebutton_info[NUM_TAPE_BUTTONS] =
662 {
663   {
664     TAPE_BUTTON_EJECT_XPOS,     TAPE_BUTTON_YPOS,
665     TAPE_CTRL_ID_EJECT,
666     "eject tape"
667   },
668   {
669     TAPE_BUTTON_STOP_XPOS,      TAPE_BUTTON_YPOS,
670     TAPE_CTRL_ID_STOP,
671     "stop tape"
672   },
673   {
674     TAPE_BUTTON_PAUSE_XPOS,     TAPE_BUTTON_YPOS,
675     TAPE_CTRL_ID_PAUSE,
676     "pause tape"
677   },
678   {
679     TAPE_BUTTON_RECORD_XPOS,    TAPE_BUTTON_YPOS,
680     TAPE_CTRL_ID_RECORD,
681     "record tape"
682   },
683   {
684     TAPE_BUTTON_PLAY_XPOS,      TAPE_BUTTON_YPOS,
685     TAPE_CTRL_ID_PLAY,
686     "play tape"
687   }
688 };
689
690 void CreateTapeButtons()
691 {
692   int i;
693
694   for (i=0; i<NUM_TAPE_BUTTONS; i++)
695   {
696     Bitmap *gd_bitmap = pix[PIX_DOOR];
697     struct GadgetInfo *gi;
698     int gd_xoffset, gd_yoffset;
699     int gd_x1, gd_x2, gd_y;
700     int id = i;
701
702     gd_xoffset = tapebutton_info[i].x;
703     gd_yoffset = tapebutton_info[i].y;
704     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
705     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
706     gd_y  = DOOR_GFX_PAGEY2 + gd_yoffset;
707
708     gi = CreateGadget(GDI_CUSTOM_ID, id,
709                       GDI_INFO_TEXT, tapebutton_info[i].infotext,
710                       GDI_X, VX + gd_xoffset,
711                       GDI_Y, VY + gd_yoffset,
712                       GDI_WIDTH, TAPE_BUTTON_XSIZE,
713                       GDI_HEIGHT, TAPE_BUTTON_YSIZE,
714                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
715                       GDI_STATE, GD_BUTTON_UNPRESSED,
716                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
717                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
718                       GDI_EVENT_MASK, GD_EVENT_RELEASED,
719                       GDI_CALLBACK_ACTION, HandleTapeButtons,
720                       GDI_END);
721
722     if (gi == NULL)
723       Error(ERR_EXIT, "cannot create gadget");
724
725     tape_gadget[id] = gi;
726   }
727 }
728
729 void MapTapeButtons()
730 {
731   int i;
732
733   for (i=0; i<NUM_TAPE_BUTTONS; i++)
734     MapGadget(tape_gadget[i]);
735 }
736
737 void UnmapTapeButtons()
738 {
739   int i;
740
741   for (i=0; i<NUM_TAPE_BUTTONS; i++)
742     UnmapGadget(tape_gadget[i]);
743 }
744
745 static void HandleTapeButtons(struct GadgetInfo *gi)
746 {
747   int id = gi->custom_id;
748
749   if (game_status != MAINMENU && game_status != PLAYING)
750     return;
751
752   switch (id)
753   {
754     case TAPE_CTRL_ID_EJECT:
755       TapeStop();
756       if (TAPE_IS_EMPTY(tape))
757       {
758         LoadTape(level_nr);
759         if (TAPE_IS_EMPTY(tape))
760           Request("No tape for this level !", REQ_CONFIRM);
761       }
762       else
763       {
764         if (tape.changed)
765           SaveTape(tape.level_nr);
766         TapeErase();
767       }
768       DrawCompleteVideoDisplay();
769       break;
770
771     case TAPE_CTRL_ID_STOP:
772       TapeStop();
773       break;
774
775     case TAPE_CTRL_ID_PAUSE:
776       TapeTogglePause();
777       break;
778
779     case TAPE_CTRL_ID_RECORD:
780       if (TAPE_IS_STOPPED(tape))
781       {
782         TapeStartRecording();
783
784 #if defined(PLATFORM_UNIX)
785         if (options.network)
786           SendToServer_StartPlaying();
787         else
788 #endif
789         {
790           game_status = PLAYING;
791           StopAnimation();
792           InitGame();
793         }
794       }
795       else if (tape.pausing)
796       {
797         if (tape.playing)       /* PLAYING -> PAUSING -> RECORDING */
798         {
799           tape.pos[tape.counter].delay = tape.delay_played;
800           tape.playing = FALSE;
801           tape.recording = TRUE;
802           tape.changed = TRUE;
803
804           DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON,0);
805         }
806         else
807           TapeTogglePause();
808       }
809       break;
810
811     case TAPE_CTRL_ID_PLAY:
812       if (TAPE_IS_EMPTY(tape))
813         break;
814
815       if (TAPE_IS_STOPPED(tape))
816       {
817         TapeStartPlaying();
818
819         game_status = PLAYING;
820         StopAnimation();
821         InitGame();
822       }
823       else if (tape.playing)
824       {
825         if (tape.pausing)                       /* PAUSE -> PLAY */
826           TapeTogglePause();
827         else if (!tape.fast_forward)            /* PLAY -> FAST FORWARD PLAY */
828         {
829           tape.fast_forward = TRUE;
830           DrawVideoDisplay(VIDEO_STATE_FFWD_ON, 0);
831         }
832         else if (!tape.pause_before_death)      /* FFWD PLAY -> + AUTO PAUSE */
833         {
834           tape.pause_before_death = TRUE;
835           DrawVideoDisplay(VIDEO_STATE_PBEND_ON, VIDEO_DISPLAY_LABEL_ONLY);
836         }
837         else                                    /* -> NORMAL PLAY */
838         {
839           tape.fast_forward = FALSE;
840           tape.pause_before_death = FALSE;
841           DrawVideoDisplay(VIDEO_STATE_FFWD_OFF | VIDEO_STATE_PBEND_OFF, 0);
842         }
843       }
844       break;
845
846     default:
847       break;
848   }
849 }