rnd-20000722-1-src
[rocksndiamonds.git] / src / tape.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  tape.c                                                  *
12 ***********************************************************/
13
14 #include "tape.h"
15 #include "misc.h"
16 #include "game.h"
17 #include "buttons.h"
18 #include "tools.h"
19 #include "files.h"
20 #include "network.h"
21
22 /* tape button identifiers */
23 #define TAPE_CTRL_ID_EJECT              0
24 #define TAPE_CTRL_ID_STOP               1
25 #define TAPE_CTRL_ID_PAUSE              2
26 #define TAPE_CTRL_ID_RECORD             3
27 #define TAPE_CTRL_ID_PLAY               4
28
29 #define NUM_TAPE_BUTTONS                5
30
31 /* forward declaration for internal use */
32 static void HandleTapeButtons(struct GadgetInfo *);
33
34 static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS];
35
36 void TapeStartRecording()
37 {
38   time_t zeit1 = time(NULL);
39   struct tm *zeit2 = localtime(&zeit1);
40   int i;
41
42   if (!TAPE_IS_STOPPED(tape))
43     TapeStop();
44
45   tape.level_nr = level_nr;
46   tape.length = 0;
47   tape.counter = 0;
48   tape.pos[tape.counter].delay = 0;
49   tape.recording = TRUE;
50   tape.playing = FALSE;
51   tape.pausing = FALSE;
52   tape.changed = TRUE;
53   tape.date = 10000*(zeit2->tm_year%100) + 100*zeit2->tm_mon + zeit2->tm_mday;
54   tape.random_seed = InitRND(NEW_RANDOMIZE);
55
56   for(i=0; i<MAX_PLAYERS; i++)
57     tape.player_participates[i] = FALSE;
58
59   DrawVideoDisplay(VIDEO_STATE_REC_ON, 0);
60   DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
61   DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
62 }
63
64 void TapeStopRecording()
65 {
66   int i;
67
68   if (!tape.recording)
69     return;
70
71   for(i=0; i<MAX_PLAYERS; i++)
72     tape.pos[tape.counter].action[i] = 0;
73
74   tape.counter++;
75   tape.length = tape.counter;
76   tape.length_seconds = GetTapeLength();
77   tape.recording = FALSE;
78   tape.pausing = FALSE;
79   DrawVideoDisplay(VIDEO_STATE_REC_OFF, 0);
80 }
81
82 void TapeRecordAction(byte joy[MAX_PLAYERS])
83 {
84   int i;
85
86   if (!tape.recording || tape.pausing)
87     return;
88
89   if (tape.counter >= MAX_TAPELEN-1)
90   {
91     TapeStopRecording();
92     return;
93   }
94
95   for(i=0; i<MAX_PLAYERS; i++)
96     tape.pos[tape.counter].action[i] = joy[i];
97
98   tape.counter++;
99   tape.pos[tape.counter].delay = 0;
100 }
101
102 void TapeRecordDelay()
103 {
104   int i;
105
106   if (!tape.recording || tape.pausing)
107     return;
108
109   if (tape.counter >= MAX_TAPELEN)
110   {
111     TapeStopRecording();
112     return;
113   }
114
115   tape.pos[tape.counter].delay++;
116
117   if (tape.pos[tape.counter].delay >= 255)
118   {
119     for(i=0; i<MAX_PLAYERS; i++)
120       tape.pos[tape.counter].action[i] = 0;
121
122     tape.counter++;
123     tape.pos[tape.counter].delay = 0;
124   }
125 }
126
127 void TapeTogglePause()
128 {
129   unsigned long state;
130
131   if (!tape.recording && !tape.playing)
132     return;
133
134   tape.pausing = !tape.pausing;
135   tape.fast_forward = FALSE;
136   tape.pause_before_death = FALSE;
137
138   state = (tape.pausing ? VIDEO_STATE_PAUSE_ON : VIDEO_STATE_PAUSE_OFF);
139   if (tape.playing)
140     state |= VIDEO_STATE_PBEND_OFF;
141
142   DrawVideoDisplay(state, 0);
143 }
144
145 void TapeStartPlaying()
146 {
147   if (TAPE_IS_EMPTY(tape))
148     return;
149
150   if (!TAPE_IS_STOPPED(tape))
151     TapeStop();
152
153   tape.counter = 0;
154   tape.delay_played = 0;
155   tape.pause_before_death = FALSE;
156   tape.recording = FALSE;
157   tape.playing = TRUE;
158   tape.pausing = FALSE;
159   tape.fast_forward = FALSE;
160   InitRND(tape.random_seed);
161
162   DrawVideoDisplay(VIDEO_STATE_PLAY_ON, 0);
163   DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
164   DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
165 }
166
167 void TapeStopPlaying()
168 {
169   if (!tape.playing)
170     return;
171
172   tape.playing = FALSE;
173   tape.pausing = FALSE;
174   DrawVideoDisplay(VIDEO_STATE_PLAY_OFF, 0);
175 }
176
177 byte *TapePlayAction()
178 {
179   static byte joy[MAX_PLAYERS];
180   int i;
181
182   if (!tape.playing || tape.pausing)
183     return(NULL);
184
185   if (tape.counter >= tape.length)
186   {
187     TapeStop();
188     return(NULL);
189   }
190
191   if (tape.delay_played == tape.pos[tape.counter].delay)
192   {
193     tape.delay_played = 0;
194     tape.counter++;
195
196     for(i=0; i<MAX_PLAYERS; i++)
197       joy[i] = tape.pos[tape.counter-1].action[i];
198   }
199   else
200   {
201     for(i=0; i<MAX_PLAYERS; i++)
202       joy[i] = 0;
203   }
204
205   return(joy);
206 }
207
208 boolean TapePlayDelay()
209 {
210   if (!tape.playing || tape.pausing)
211     return(FALSE);
212
213   if (tape.pause_before_death)  /* STOP 10s BEFORE PLAYER GETS KILLED... */
214   {
215     if (!(FrameCounter % 20))
216     {
217       if ((FrameCounter / 20) % 2)
218         DrawVideoDisplay(VIDEO_STATE_PBEND_ON, VIDEO_DISPLAY_LABEL_ONLY);
219       else
220         DrawVideoDisplay(VIDEO_STATE_PBEND_OFF, VIDEO_DISPLAY_LABEL_ONLY);
221     }
222
223     if (TimePlayed > tape.length_seconds - PAUSE_SECONDS_BEFORE_DEATH)
224     {
225       TapeTogglePause();
226       return(FALSE);
227     }
228   }
229
230   if (tape.counter >= tape.length)
231   {
232     TapeStop();
233     return(TRUE);
234   }
235
236   if (tape.delay_played < tape.pos[tape.counter].delay)
237   {
238     tape.delay_played++;
239     return(TRUE);
240   }
241   else
242     return(FALSE);
243 }
244
245 void TapeStop()
246 {
247   TapeStopRecording();
248   TapeStopPlaying();
249
250   DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
251   if (tape.date && tape.length)
252   {
253     DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
254     DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds);
255   }
256 }
257
258 void TapeErase()
259 {
260   tape.length = 0;
261 }
262
263 unsigned int GetTapeLength()
264 {
265   unsigned int tape_length = 0;
266   int i;
267
268   if (TAPE_IS_EMPTY(tape))
269     return(0);
270
271   for(i=0;i<tape.length;i++)
272     tape_length += tape.pos[i].delay;
273
274   return(tape_length * GAME_FRAME_DELAY / 1000);
275 }
276
277 /* ---------- new tape button stuff ---------------------------------------- */
278
279 /* graphic position values for tape buttons */
280 #define TAPE_BUTTON_XSIZE       18
281 #define TAPE_BUTTON_YSIZE       18
282 #define TAPE_BUTTON_XPOS        5
283 #define TAPE_BUTTON_YPOS        77
284
285 #define TAPE_BUTTON_EJECT_XPOS  (TAPE_BUTTON_XPOS + 0 * TAPE_BUTTON_XSIZE)
286 #define TAPE_BUTTON_STOP_XPOS   (TAPE_BUTTON_XPOS + 1 * TAPE_BUTTON_XSIZE)
287 #define TAPE_BUTTON_PAUSE_XPOS  (TAPE_BUTTON_XPOS + 2 * TAPE_BUTTON_XSIZE)
288 #define TAPE_BUTTON_RECORD_XPOS (TAPE_BUTTON_XPOS + 3 * TAPE_BUTTON_XSIZE)
289 #define TAPE_BUTTON_PLAY_XPOS   (TAPE_BUTTON_XPOS + 4 * TAPE_BUTTON_XSIZE)
290
291 static struct
292 {
293   int x, y;
294   int gadget_id;
295   char *infotext;
296 } tapebutton_info[NUM_TAPE_BUTTONS] =
297 {
298   {
299     TAPE_BUTTON_EJECT_XPOS,     TAPE_BUTTON_YPOS,
300     TAPE_CTRL_ID_EJECT,
301     "eject tape"
302   },
303   {
304     TAPE_BUTTON_STOP_XPOS,      TAPE_BUTTON_YPOS,
305     TAPE_CTRL_ID_STOP,
306     "stop tape"
307   },
308   {
309     TAPE_BUTTON_PAUSE_XPOS,     TAPE_BUTTON_YPOS,
310     TAPE_CTRL_ID_PAUSE,
311     "pause tape"
312   },
313   {
314     TAPE_BUTTON_RECORD_XPOS,    TAPE_BUTTON_YPOS,
315     TAPE_CTRL_ID_RECORD,
316     "record tape"
317   },
318   {
319     TAPE_BUTTON_PLAY_XPOS,      TAPE_BUTTON_YPOS,
320     TAPE_CTRL_ID_PLAY,
321     "play tape"
322   }
323 };
324
325 void CreateTapeButtons()
326 {
327   int i;
328
329   for (i=0; i<NUM_TAPE_BUTTONS; i++)
330   {
331     Bitmap gd_bitmap = pix[PIX_DOOR];
332     struct GadgetInfo *gi;
333     int gd_xoffset, gd_yoffset;
334     int gd_x1, gd_x2, gd_y;
335     int id = i;
336
337     gd_xoffset = tapebutton_info[i].x;
338     gd_yoffset = tapebutton_info[i].y;
339     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
340     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
341     gd_y  = DOOR_GFX_PAGEY2 + gd_yoffset;
342
343     gi = CreateGadget(GDI_CUSTOM_ID, id,
344                       GDI_INFO_TEXT, tapebutton_info[i].infotext,
345                       GDI_X, VX + gd_xoffset,
346                       GDI_Y, VY + gd_yoffset,
347                       GDI_WIDTH, TAPE_BUTTON_XSIZE,
348                       GDI_HEIGHT, TAPE_BUTTON_YSIZE,
349                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
350                       GDI_STATE, GD_BUTTON_UNPRESSED,
351                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
352                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
353                       GDI_EVENT_MASK, GD_EVENT_RELEASED,
354                       GDI_CALLBACK_ACTION, HandleTapeButtons,
355                       GDI_END);
356
357     if (gi == NULL)
358       Error(ERR_EXIT, "cannot create gadget");
359
360     tape_gadget[id] = gi;
361   }
362 }
363
364 void MapTapeButtons()
365 {
366   int i;
367
368   for (i=0; i<NUM_TAPE_BUTTONS; i++)
369     MapGadget(tape_gadget[i]);
370 }
371
372 void UnmapTapeButtons()
373 {
374   int i;
375
376   for (i=0; i<NUM_TAPE_BUTTONS; i++)
377     UnmapGadget(tape_gadget[i]);
378 }
379
380 static void HandleTapeButtons(struct GadgetInfo *gi)
381 {
382   int id = gi->custom_id;
383
384   if (game_status != MAINMENU && game_status != PLAYING)
385     return;
386
387   switch (id)
388   {
389     case TAPE_CTRL_ID_EJECT:
390       TapeStop();
391       if (TAPE_IS_EMPTY(tape))
392       {
393         LoadTape(level_nr);
394         if (TAPE_IS_EMPTY(tape))
395           Request("No tape for this level !", REQ_CONFIRM);
396       }
397       else
398       {
399         if (tape.changed)
400           SaveTape(tape.level_nr);
401         TapeErase();
402       }
403       DrawCompleteVideoDisplay();
404       break;
405
406     case TAPE_CTRL_ID_STOP:
407       TapeStop();
408       break;
409
410     case TAPE_CTRL_ID_PAUSE:
411       TapeTogglePause();
412       break;
413
414     case TAPE_CTRL_ID_RECORD:
415       if (TAPE_IS_STOPPED(tape))
416       {
417         TapeStartRecording();
418
419 #ifndef MSDOS
420         if (options.network)
421           SendToServer_StartPlaying();
422         else
423 #endif
424         {
425           game_status = PLAYING;
426           InitGame();
427         }
428       }
429       else if (tape.pausing)
430       {
431         if (tape.playing)       /* PLAYING -> PAUSING -> RECORDING */
432         {
433           tape.pos[tape.counter].delay = tape.delay_played;
434           tape.playing = FALSE;
435           tape.recording = TRUE;
436           tape.changed = TRUE;
437
438           DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON,0);
439         }
440         else
441           TapeTogglePause();
442       }
443       break;
444
445     case TAPE_CTRL_ID_PLAY:
446       if (TAPE_IS_EMPTY(tape))
447         break;
448
449       if (TAPE_IS_STOPPED(tape))
450       {
451         TapeStartPlaying();
452
453         game_status = PLAYING;
454         InitGame();
455       }
456       else if (tape.playing)
457       {
458         if (tape.pausing)                       /* PAUSE -> PLAY */
459           TapeTogglePause();
460         else if (!tape.fast_forward)            /* PLAY -> FAST FORWARD PLAY */
461         {
462           tape.fast_forward = TRUE;
463           DrawVideoDisplay(VIDEO_STATE_FFWD_ON, 0);
464         }
465         else if (!tape.pause_before_death)      /* FFWD PLAY -> + AUTO PAUSE */
466         {
467           tape.pause_before_death = TRUE;
468           DrawVideoDisplay(VIDEO_STATE_PBEND_ON, VIDEO_DISPLAY_LABEL_ONLY);
469         }
470         else                                    /* -> NORMAL PLAY */
471         {
472           tape.fast_forward = FALSE;
473           tape.pause_before_death = FALSE;
474           DrawVideoDisplay(VIDEO_STATE_FFWD_OFF | VIDEO_STATE_PBEND_OFF, 0);
475         }
476       }
477       break;
478
479     default:
480       break;
481   }
482 }