1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
12 #include "libgame/libgame.h"
22 /* tape button identifiers */
23 #define TAPE_CTRL_ID_EJECT 0
24 #define TAPE_CTRL_ID_EXTRA 1
25 #define TAPE_CTRL_ID_STOP 2
26 #define TAPE_CTRL_ID_PAUSE 3
27 #define TAPE_CTRL_ID_RECORD 4
28 #define TAPE_CTRL_ID_PLAY 5
30 #define NUM_TAPE_BUTTONS 6
32 /* values for tape handling */
33 #define TAPE_PAUSE_SECONDS_BEFORE_DEATH 5
35 /* forward declaration for internal use */
36 static void HandleTapeButtons(struct GadgetInfo *);
37 static void TapeStopWarpForward();
39 static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS];
42 /* ========================================================================= */
43 /* video tape definitions */
44 /* ========================================================================= */
46 /* some positions in the video tape control window */
47 #define VIDEO_DATE_LABEL_XPOS (VIDEO_DISPLAY1_XPOS)
48 #define VIDEO_DATE_LABEL_YPOS (VIDEO_DISPLAY1_YPOS)
49 #define VIDEO_DATE_LABEL_XSIZE (VIDEO_DISPLAY_XSIZE)
50 #define VIDEO_DATE_LABEL_YSIZE (VIDEO_DISPLAY_YSIZE)
51 #define VIDEO_DATE_XPOS (VIDEO_DISPLAY1_XPOS + 2)
52 #define VIDEO_DATE_YPOS (VIDEO_DISPLAY1_YPOS + 14)
53 #define VIDEO_DATE_XSIZE (VIDEO_DISPLAY_XSIZE)
54 #define VIDEO_DATE_YSIZE 16
55 #define VIDEO_REC_LABEL_XPOS (VIDEO_DISPLAY2_XPOS)
56 #define VIDEO_REC_LABEL_YPOS (VIDEO_DISPLAY2_YPOS)
57 #define VIDEO_REC_LABEL_XSIZE 20
58 #define VIDEO_REC_LABEL_YSIZE 12
59 #define VIDEO_REC_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS + 20)
60 #define VIDEO_REC_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS)
61 #define VIDEO_REC_SYMBOL_XSIZE 16
62 #define VIDEO_REC_SYMBOL_YSIZE 16
63 #define VIDEO_PLAY_LABEL_XPOS (VIDEO_DISPLAY2_XPOS + 65)
64 #define VIDEO_PLAY_LABEL_YPOS (VIDEO_DISPLAY2_YPOS)
65 #define VIDEO_PLAY_LABEL_XSIZE 22
66 #define VIDEO_PLAY_LABEL_YSIZE 12
67 #define VIDEO_PLAY_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS + 52)
68 #define VIDEO_PLAY_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS)
69 #define VIDEO_PLAY_SYMBOL_XSIZE 11
70 #define VIDEO_PLAY_SYMBOL_YSIZE 13
71 #define VIDEO_PAUSE_LABEL_XPOS (VIDEO_DISPLAY2_XPOS)
72 #define VIDEO_PAUSE_LABEL_YPOS (VIDEO_DISPLAY2_YPOS + 20)
73 #define VIDEO_PAUSE_LABEL_XSIZE 35
74 #define VIDEO_PAUSE_LABEL_YSIZE 8
75 #define VIDEO_PAUSE_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS + 35)
76 #define VIDEO_PAUSE_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS)
77 #define VIDEO_PAUSE_SYMBOL_XSIZE 17
78 #define VIDEO_PAUSE_SYMBOL_YSIZE 13
79 #define VIDEO_TIME_XPOS (VIDEO_DISPLAY2_XPOS + 39)
80 #define VIDEO_TIME_YPOS (VIDEO_DISPLAY2_YPOS + 14)
81 #define VIDEO_TIME_XSIZE 50
82 #define VIDEO_TIME_YSIZE 16
84 /* some default values for tape labels and symbols */
85 #define VIDEO_LABEL_XPOS 5
86 #define VIDEO_LABEL_YPOS 42
87 #define VIDEO_LABEL_XSIZE 40
88 #define VIDEO_LABEL_YSIZE 28
89 #define VIDEO_SYMBOL_XPOS 39
90 #define VIDEO_SYMBOL_YPOS 42
91 #define VIDEO_SYMBOL_XSIZE 56
92 #define VIDEO_SYMBOL_YSIZE 13
94 /* values for certain tape labels and symbols */
95 #define VIDEO_FFWD_LABEL_XPOS VIDEO_LABEL_XPOS
96 #define VIDEO_FFWD_LABEL_YPOS 193
97 #define VIDEO_FFWD_LABEL_XSIZE VIDEO_LABEL_XSIZE
98 #define VIDEO_FFWD_LABEL_YSIZE VIDEO_LABEL_YSIZE
99 #define VIDEO_FFWD_SYMBOL_XPOS VIDEO_SYMBOL_XPOS
100 #define VIDEO_FFWD_SYMBOL_YPOS 193
101 #define VIDEO_FFWD_SYMBOL_XSIZE 27
102 #define VIDEO_FFWD_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE
104 #define VIDEO_PBEND_LABEL_XPOS VIDEO_LABEL_XPOS
105 #define VIDEO_PBEND_LABEL_YPOS 221
106 #define VIDEO_PBEND_LABEL_XSIZE VIDEO_LABEL_XSIZE
107 #define VIDEO_PBEND_LABEL_YSIZE VIDEO_LABEL_YSIZE
108 #define VIDEO_PBEND_SYMBOL_XPOS VIDEO_SYMBOL_XPOS
109 #define VIDEO_PBEND_SYMBOL_YPOS 221
110 #define VIDEO_PBEND_SYMBOL_XSIZE 27
111 #define VIDEO_PBEND_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE
113 #define VIDEO_WARP_LABEL_XPOS VIDEO_LABEL_XPOS
114 #define VIDEO_WARP_LABEL_YPOS 165
115 #define VIDEO_WARP_LABEL_XSIZE VIDEO_LABEL_XSIZE
116 #define VIDEO_WARP_LABEL_YSIZE VIDEO_LABEL_YSIZE
117 #define VIDEO_WARP_SYMBOL_XPOS VIDEO_SYMBOL_XPOS
118 #define VIDEO_WARP_SYMBOL_YPOS 165
119 #define VIDEO_WARP_SYMBOL_XSIZE 27
120 #define VIDEO_WARP_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE
121 #define VIDEO_WARP2_SYMBOL_XPOS VIDEO_SYMBOL_XPOS
122 #define VIDEO_WARP2_SYMBOL_YPOS 152
123 #define VIDEO_WARP2_SYMBOL_XSIZE 27
124 #define VIDEO_WARP2_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE
126 #define VIDEO_1STEP_SYMBOL_XPOS (VIDEO_SYMBOL_XPOS + 18)
127 #define VIDEO_1STEP_SYMBOL_YPOS 139
128 #define VIDEO_1STEP_SYMBOL_XSIZE (VIDEO_SYMBOL_XSIZE - 18)
129 #define VIDEO_1STEP_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE
131 #define PG_X3(x) (DOOR_GFX_PAGEX3 + (x))
132 #define PG_X4(x) (DOOR_GFX_PAGEX4 + (x))
133 #define PG_X5(x) (DOOR_GFX_PAGEX5 + (x))
134 #define PG_X6(x) (DOOR_GFX_PAGEX6 + (x))
136 #define PG_Y1(y) (DOOR_GFX_PAGEY1 + (y))
137 #define PG_Y2(y) (DOOR_GFX_PAGEY2 + (y))
139 #define VIDEO_INFO_OFF (VIDEO_STATE_DATE_OFF | \
140 VIDEO_STATE_TIME_OFF)
141 #define VIDEO_STATE_OFF (VIDEO_STATE_PLAY_OFF | \
142 VIDEO_STATE_REC_OFF | \
143 VIDEO_STATE_PAUSE_OFF | \
144 VIDEO_STATE_FFWD_OFF | \
145 VIDEO_STATE_PBEND_OFF | \
146 VIDEO_STATE_1STEP_OFF)
147 #define VIDEO_PRESS_OFF (VIDEO_PRESS_PLAY_OFF | \
148 VIDEO_PRESS_REC_OFF | \
149 VIDEO_PRESS_PAUSE_OFF | \
150 VIDEO_PRESS_STOP_OFF | \
151 VIDEO_PRESS_EJECT_OFF)
152 #define VIDEO_ALL_OFF (VIDEO_INFO_OFF | \
156 #define VIDEO_INFO_ON (VIDEO_STATE_DATE_ON | \
158 #define VIDEO_STATE_ON (VIDEO_STATE_PLAY_ON | \
159 VIDEO_STATE_REC_ON | \
160 VIDEO_STATE_PAUSE_ON | \
161 VIDEO_STATE_FFWD_ON | \
162 VIDEO_STATE_PBEND_ON | \
163 VIDEO_STATE_1STEP_ON)
164 #define VIDEO_PRESS_ON (VIDEO_PRESS_PLAY_ON | \
165 VIDEO_PRESS_REC_ON | \
166 VIDEO_PRESS_PAUSE_ON | \
167 VIDEO_PRESS_STOP_ON | \
168 VIDEO_PRESS_EJECT_ON)
169 #define VIDEO_ALL_ON (VIDEO_INFO_ON | \
173 #define VIDEO_INFO (VIDEO_INFO_ON | VIDEO_INFO_OFF)
174 #define VIDEO_STATE (VIDEO_STATE_ON | VIDEO_STATE_OFF)
175 #define VIDEO_PRESS (VIDEO_PRESS_ON | VIDEO_PRESS_OFF)
176 #define VIDEO_ALL (VIDEO_ALL_ON | VIDEO_ALL_OFF)
178 #define NUM_TAPE_FUNCTIONS 10
179 #define NUM_TAPE_FUNCTION_PARTS 2
180 #define NUM_TAPE_FUNCTION_STATES 2
183 /* ========================================================================= */
184 /* video display functions */
185 /* ========================================================================= */
187 void DrawVideoDisplay(unsigned int state, unsigned int value)
190 static char *monatsname[12] =
192 "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
193 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
201 video_pos[NUM_TAPE_FUNCTIONS][NUM_TAPE_FUNCTION_PARTS] =
204 { IMG_TAPE_LABEL_GFX_PLAY, &tape.label.play },
205 { IMG_TAPE_SYMBOL_GFX_PLAY, &tape.symbol.play },
208 { IMG_TAPE_LABEL_GFX_RECORD, &tape.label.record },
209 { IMG_TAPE_SYMBOL_GFX_RECORD, &tape.symbol.record },
212 { IMG_TAPE_LABEL_GFX_PAUSE, &tape.label.pause },
213 { IMG_TAPE_SYMBOL_GFX_PAUSE, &tape.symbol.pause },
216 { IMG_TAPE_LABEL_GFX_DATE, &tape.label.date },
220 { IMG_TAPE_LABEL_GFX_TIME, &tape.label.time },
224 { IMG_TAPE_LABEL_GFX_FAST_FORWARD, &tape.label.fast_forward },
225 { IMG_TAPE_SYMBOL_GFX_FAST_FORWARD, &tape.symbol.fast_forward },
228 { IMG_TAPE_LABEL_GFX_PAUSE_BEFORE_END, &tape.label.pause_before_end },
229 { IMG_TAPE_SYMBOL_GFX_PAUSE_BEFORE_END, &tape.symbol.pause_before_end },
232 { IMG_TAPE_LABEL_GFX_WARP_FORWARD_BLIND, &tape.label.warp_forward_blind},
233 { IMG_TAPE_SYMBOL_GFX_WARP_FORWARD_BLIND, &tape.symbol.warp_forward_blind},
236 { IMG_TAPE_LABEL_GFX_WARP_FORWARD, &tape.label.warp_forward },
237 { IMG_TAPE_SYMBOL_GFX_WARP_FORWARD, &tape.symbol.warp_forward },
240 { IMG_TAPE_LABEL_GFX_SINGLE_STEP, &tape.label.single_step },
241 { IMG_TAPE_SYMBOL_GFX_SINGLE_STEP, &tape.symbol.single_step },
245 for (k = 0; k < NUM_TAPE_FUNCTION_STATES; k++) /* on or off states */
247 for (i = 0; i < NUM_TAPE_FUNCTIONS; i++) /* record, play, ... */
249 for (j = 0; j < NUM_TAPE_FUNCTION_PARTS; j++) /* label or symbol */
251 if (video_pos[i][j].graphic == -1 ||
252 video_pos[i][j].pos->x < 0 ||
253 video_pos[i][j].pos->y < 0)
256 if (state & (1 << (i * 2 + k)))
258 struct GraphicInfo *gfx_bg = &graphic_info[IMG_BACKGROUND_TAPE];
259 struct GraphicInfo *gfx = &graphic_info[video_pos[i][j].graphic];
260 struct Rect *pos = video_pos[i][j].pos;
264 (j == 0 ? VIDEO_DISPLAY_SYMBOL_ONLY : VIDEO_DISPLAY_LABEL_ONLY);
266 if (value == skip_value)
271 gd_bitmap = gfx->bitmap;
277 gd_bitmap = gfx_bg->bitmap;
278 gd_x = gfx_bg->src_x + pos->x;
279 gd_y = gfx_bg->src_y + pos->y;
282 /* some tape graphics may be undefined -- only draw if defined */
283 if (gd_bitmap != NULL)
284 BlitBitmap(gd_bitmap, drawto, gd_x, gd_y, gfx->width, gfx->height,
285 VX + pos->x, VY + pos->y);
291 if (state & VIDEO_STATE_DATE_ON)
293 struct TextPosInfo *pos = &tape.text.date;
294 int tag = value % 100;
295 int monat = (value/100) % 100;
296 int jahr = (value/10000);
298 DrawText(VX + pos->x, VY + pos->y, int2str(tag, 2), pos->font);
299 DrawText(VX + pos->x + 27, VY + pos->y, monatsname[monat], pos->font);
300 DrawText(VX + pos->x + 64, VY + pos->y, int2str(jahr, 2), pos->font);
303 if (state & VIDEO_STATE_TIME_ON)
305 struct TextPosInfo *pos = &tape.text.time;
306 int min = value / 60;
307 int sec = value % 60;
309 DrawText(VX + pos->x, VY + pos->y, int2str(min, 2), pos->font);
310 DrawText(VX + pos->x + 27, VY + pos->y, int2str(sec, 2), pos->font);
313 redraw_mask |= REDRAW_DOOR_2;
316 void DrawCompleteVideoDisplay()
318 struct GraphicInfo *g_tape = &graphic_info[IMG_BACKGROUND_TAPE];
320 /* draw tape background */
321 BlitBitmap(g_tape->bitmap, drawto, g_tape->src_x, g_tape->src_y,
322 gfx.vxsize, gfx.vysize, gfx.vx, gfx.vy);
324 /* draw tape buttons (forced) */
328 DrawVideoDisplay(VIDEO_ALL_OFF, 0);
332 DrawVideoDisplay(VIDEO_STATE_REC_ON, 0);
333 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
334 DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds);
337 DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0);
339 else if (tape.playing)
341 DrawVideoDisplay(VIDEO_STATE_PLAY_ON, 0);
342 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
343 DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
346 DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0);
348 else if (tape.date && tape.length)
350 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
351 DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds);
354 BlitBitmap(drawto, bitmap_db_door_2, gfx.vx, gfx.vy, gfx.vxsize, gfx.vysize,
358 void TapeDeactivateDisplayOn()
360 SetDrawDeactivationMask(REDRAW_FIELD);
361 audio.sound_deactivated = TRUE;
364 void TapeDeactivateDisplayOff(boolean redraw_display)
366 SetDrawDeactivationMask(REDRAW_NONE);
367 audio.sound_deactivated = FALSE;
371 RedrawPlayfield(TRUE, 0,0,0,0);
372 DrawGameDoorValues();
377 /* ========================================================================= */
378 /* tape control functions */
379 /* ========================================================================= */
381 void TapeSetDateFromEpochSeconds(time_t epoch_seconds)
383 struct tm *lt = localtime(&epoch_seconds);
385 tape.date = 10000 * (lt->tm_year % 100) + 100 * lt->tm_mon + lt->tm_mday;
388 void TapeSetDateFromNow()
390 TapeSetDateFromEpochSeconds(time(NULL));
399 tape.length_seconds = 0;
401 if (leveldir_current)
402 setString(&tape.level_identifier, leveldir_current->identifier);
404 tape.level_nr = level_nr;
405 tape.pos[tape.counter].delay = 0;
408 tape.random_seed = InitRND(level.random_seed);
410 tape.file_version = FILE_VERSION_ACTUAL;
411 tape.game_version = GAME_VERSION_ACTUAL;
412 tape.engine_version = level.game_version;
414 TapeSetDateFromNow();
416 for (i = 0; i < MAX_PLAYERS; i++)
417 tape.player_participates[i] = FALSE;
419 tape.centered_player_nr_next = -1;
420 tape.set_centered_player = FALSE;
423 static void TapeRewind()
426 tape.delay_played = 0;
427 tape.pause_before_death = FALSE;
428 tape.recording = FALSE;
429 tape.playing = FALSE;
430 tape.fast_forward = FALSE;
431 tape.warp_forward = FALSE;
432 tape.deactivate_display = FALSE;
433 tape.auto_play = (global.autoplay_leveldir != NULL);
434 tape.auto_play_level_solved = FALSE;
435 tape.quick_resume = FALSE;
436 tape.single_step = FALSE;
438 tape.centered_player_nr_next = -1;
439 tape.set_centered_player = FALSE;
441 InitRND(tape.random_seed);
444 static void TapeSetRandomSeed(int random_seed)
446 tape.random_seed = InitRND(random_seed);
449 void TapeStartRecording(int random_seed)
451 if (!TAPE_IS_STOPPED(tape))
456 TapeSetRandomSeed(random_seed);
458 tape.recording = TRUE;
460 DrawVideoDisplay(VIDEO_STATE_REC_ON, 0);
461 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
462 DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
466 SetDrawDeactivationMask(REDRAW_NONE);
467 audio.sound_deactivated = FALSE;
470 static void TapeStartGameRecording()
472 TapeStartRecording(level.random_seed);
474 #if defined(NETWORK_AVALIABLE)
477 SendToServer_StartPlaying();
486 static void TapeAppendRecording()
488 if (!tape.playing || !tape.pausing)
491 tape.pos[tape.counter].delay = tape.delay_played;
492 tape.playing = FALSE;
493 tape.recording = TRUE;
496 TapeSetDateFromNow();
498 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
499 DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON, 0);
501 UpdateAndDisplayGameControlValues();
504 void TapeHaltRecording()
510 tape.pos[tape.counter].delay = 0;
512 tape.length = tape.counter;
513 tape.length_seconds = GetTapeLength();
516 void TapeStopRecording()
520 tape.recording = FALSE;
521 tape.pausing = FALSE;
523 DrawVideoDisplay(VIDEO_STATE_REC_OFF, 0);
524 MapTapeEjectButton();
527 void TapeRecordAction(byte action_raw[MAX_PLAYERS])
529 byte action[MAX_PLAYERS];
532 if (!tape.recording) /* (record action even when tape is paused) */
535 if (tape.counter >= MAX_TAPE_LEN - 1)
541 for (i = 0; i < MAX_PLAYERS; i++)
542 action[i] = action_raw[i];
544 if (tape.set_centered_player)
546 for (i = 0; i < MAX_PLAYERS; i++)
547 if (tape.centered_player_nr_next == i ||
548 tape.centered_player_nr_next == -1)
549 action[i] |= KEY_SET_FOCUS;
551 tape.set_centered_player = FALSE;
554 if (tape.pos[tape.counter].delay > 0) /* already stored action */
556 boolean changed_events = FALSE;
558 for (i = 0; i < MAX_PLAYERS; i++)
559 if (tape.pos[tape.counter].action[i] != action[i])
560 changed_events = TRUE;
562 if (changed_events || tape.pos[tape.counter].delay >= 255)
565 tape.pos[tape.counter].delay = 0;
568 tape.pos[tape.counter].delay++;
571 if (tape.pos[tape.counter].delay == 0) /* store new action */
573 for (i = 0; i < MAX_PLAYERS; i++)
574 tape.pos[tape.counter].action[i] = action[i];
576 tape.pos[tape.counter].delay++;
580 void TapeTogglePause(boolean toggle_manual)
584 if (tape.pause_before_death)
585 state |= VIDEO_STATE_PBEND_OFF;
586 else if (tape.fast_forward)
587 state |= VIDEO_STATE_FFWD_OFF;
589 tape.pausing = !tape.pausing;
590 tape.fast_forward = FALSE;
591 tape.pause_before_death = FALSE;
593 if (tape.single_step && toggle_manual)
594 tape.single_step = FALSE;
596 state |= (tape.pausing ? VIDEO_STATE_PAUSE_ON : VIDEO_STATE_PAUSE_OFF);
598 state |= VIDEO_STATE_PLAY_ON;
600 state |= (tape.single_step ? VIDEO_STATE_1STEP_ON : VIDEO_STATE_1STEP_OFF);
602 DrawVideoDisplay(state, 0);
604 if (tape.warp_forward)
606 TapeStopWarpForward();
608 if (tape.quick_resume)
610 tape.quick_resume = FALSE;
612 TapeAppendRecording();
614 if (!CheckEngineSnapshot())
615 SaveEngineSnapshot();
620 void TapeStartPlaying()
622 if (TAPE_IS_EMPTY(tape))
625 if (!TAPE_IS_STOPPED(tape))
632 DrawVideoDisplay(VIDEO_STATE_PLAY_ON, 0);
633 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
634 DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
638 SetDrawDeactivationMask(REDRAW_NONE);
639 audio.sound_deactivated = FALSE;
642 static void TapeStartGamePlaying()
649 void TapeStopPlaying()
651 tape.playing = FALSE;
652 tape.pausing = FALSE;
654 if (tape.warp_forward)
655 TapeStopWarpForward();
657 DrawVideoDisplay(VIDEO_STATE_PLAY_OFF, 0);
658 MapTapeEjectButton();
661 byte *TapePlayAction()
663 static byte action[MAX_PLAYERS];
666 if (!tape.playing || tape.pausing)
669 if (tape.pause_before_death) /* stop 10 seconds before player gets killed */
671 if (!(FrameCounter % 20))
673 if ((FrameCounter / 20) % 2)
674 DrawVideoDisplay(VIDEO_STATE_PBEND_ON, VIDEO_DISPLAY_LABEL_ONLY);
676 DrawVideoDisplay(VIDEO_STATE_PBEND_OFF, VIDEO_DISPLAY_LABEL_ONLY);
679 if (tape.warp_forward)
681 if (tape.deactivate_display)
682 DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
684 DrawVideoDisplay(VIDEO_STATE_WARP2_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
687 if (TapeTime > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH)
689 TapeTogglePause(TAPE_TOGGLE_MANUAL);
694 else if (tape.fast_forward)
696 if ((FrameCounter / 20) % 2)
697 DrawVideoDisplay(VIDEO_STATE_FFWD_ON, VIDEO_DISPLAY_LABEL_ONLY);
699 DrawVideoDisplay(VIDEO_STATE_FFWD_OFF, VIDEO_DISPLAY_LABEL_ONLY);
701 if (tape.warp_forward)
703 if (tape.deactivate_display)
704 DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
706 DrawVideoDisplay(VIDEO_STATE_WARP2_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
711 /* !!! this makes things much slower !!! */
712 else if (tape.warp_forward)
714 if ((FrameCounter / 20) % 2)
715 DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_LABEL_ONLY);
717 DrawVideoDisplay(VIDEO_STATE_WARP_OFF, VIDEO_DISPLAY_LABEL_ONLY);
719 DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
723 if (tape.counter >= tape.length) /* end of tape reached */
725 if (tape.warp_forward && !tape.auto_play)
726 TapeTogglePause(TAPE_TOGGLE_MANUAL);
733 for (i = 0; i < MAX_PLAYERS; i++)
734 action[i] = tape.pos[tape.counter].action[i];
736 tape.set_centered_player = FALSE;
737 tape.centered_player_nr_next = -999;
739 for (i = 0; i < MAX_PLAYERS; i++)
741 if (action[i] & KEY_SET_FOCUS)
743 tape.set_centered_player = TRUE;
744 tape.centered_player_nr_next =
745 (tape.centered_player_nr_next == -999 ? i : -1);
748 action[i] &= ~KEY_SET_FOCUS;
752 if (tape.delay_played >= tape.pos[tape.counter].delay)
755 tape.delay_played = 0;
766 DrawVideoDisplay(VIDEO_STATE_OFF, 0);
768 if (tape.date && tape.length)
770 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
771 DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds);
775 unsigned int GetTapeLength()
777 unsigned int tape_length = 0;
780 if (TAPE_IS_EMPTY(tape))
783 for (i = 0; i < tape.length; i++)
784 tape_length += tape.pos[i].delay;
786 return(tape_length * GAME_FRAME_DELAY / 1000);
789 static void TapeStartWarpForward()
791 tape.warp_forward = TRUE;
793 if (!tape.fast_forward && !tape.pause_before_death)
795 tape.pausing = FALSE;
796 tape.deactivate_display = TRUE;
798 TapeDeactivateDisplayOn();
801 if (tape.fast_forward || tape.pause_before_death)
802 DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
804 DrawVideoDisplay(VIDEO_STATE_WARP_ON, 0);
807 static void TapeStopWarpForward()
809 int state = (tape.pausing ? VIDEO_STATE_PAUSE_ON : VIDEO_STATE_PAUSE_OFF);
811 tape.warp_forward = FALSE;
812 tape.deactivate_display = FALSE;
814 TapeDeactivateDisplayOff(game_status == GAME_MODE_PLAYING);
816 if (tape.pause_before_death)
817 state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_PBEND_ON;
818 else if (tape.fast_forward)
819 state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_FFWD_ON;
821 state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_PLAY_ON;
823 DrawVideoDisplay(state, 0);
826 static void TapeSingleStep()
832 TapeTogglePause(TAPE_TOGGLE_MANUAL);
834 tape.single_step = !tape.single_step;
836 DrawVideoDisplay((tape.single_step ? VIDEO_STATE_1STEP_ON :
837 VIDEO_STATE_1STEP_OFF), 0);
842 if (game_status == GAME_MODE_MAIN)
844 Request("No game that can be saved!", REQ_CONFIRM);
849 if (game_status != GAME_MODE_PLAYING)
853 TapeHaltRecording(); /* prepare tape for saving on-the-fly */
855 if (TAPE_IS_EMPTY(tape))
857 Request("No tape that can be saved!", REQ_CONFIRM);
862 if (SaveTapeChecked(tape.level_nr))
863 SaveEngineSnapshot();
868 char *filename = getTapeFilename(level_nr);
870 if (!fileExists(filename))
872 Request("No tape for this level!", REQ_CONFIRM);
877 if (tape.recording && !Request("Stop recording and load tape?",
878 REQ_ASK | REQ_STAY_CLOSED))
880 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
885 if (game_status != GAME_MODE_PLAYING && game_status != GAME_MODE_MAIN)
888 if (CheckEngineSnapshot())
890 TapeStartGamePlaying();
892 LoadEngineSnapshot();
894 DrawCompleteVideoDisplay();
899 TapeStopWarpForward();
900 TapeAppendRecording();
902 if (FrameCounter > 0)
911 if (!TAPE_IS_EMPTY(tape))
913 TapeStartGamePlaying();
914 TapeStartWarpForward();
916 tape.quick_resume = TRUE;
918 else /* this should not happen (basically checked above) */
920 int reopen_door = (game_status == GAME_MODE_PLAYING ? REQ_REOPEN : 0);
922 Request("No tape for this level!", REQ_CONFIRM | reopen_door);
926 void InsertSolutionTape()
928 if (!TAPE_IS_EMPTY(tape))
931 LoadSolutionTape(level_nr);
933 if (TAPE_IS_EMPTY(tape))
934 Request("No solution tape for this level!", REQ_CONFIRM);
936 DrawCompleteVideoDisplay();
940 /* ------------------------------------------------------------------------- *
941 * tape autoplay functions
942 * ------------------------------------------------------------------------- */
946 static LevelDirTree *autoplay_leveldir = NULL;
947 static boolean autoplay_initialized = FALSE;
948 static int autoplay_level_nr = -1;
949 static int num_levels_played = 0;
950 static int num_levels_solved = 0;
951 static int num_tape_missing = 0;
952 static boolean level_failed[MAX_TAPES_PER_SET];
955 if (autoplay_initialized)
957 /* just finished auto-playing tape */
958 printf("%s.\n", tape.auto_play_level_solved ? "solved" : "NOT SOLVED");
962 if (tape.auto_play_level_solved)
964 else if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
965 level_failed[level_nr] = TRUE;
969 DrawCompleteVideoDisplay();
970 audio.sound_enabled = FALSE;
972 autoplay_leveldir = getTreeInfoFromIdentifier(leveldir_first,
973 global.autoplay_leveldir);
975 if (autoplay_leveldir == NULL)
976 Error(ERR_EXIT, "no such level identifier: '%s'",
977 global.autoplay_leveldir);
979 leveldir_current = autoplay_leveldir;
981 if (autoplay_leveldir->first_level < 0)
982 autoplay_leveldir->first_level = 0;
983 if (autoplay_leveldir->last_level >= MAX_TAPES_PER_SET)
984 autoplay_leveldir->last_level = MAX_TAPES_PER_SET - 1;
986 autoplay_level_nr = autoplay_leveldir->first_level;
988 printf_line("=", 79);
989 printf("Automatically playing level tapes\n");
990 printf_line("-", 79);
991 printf("Level series identifier: '%s'\n", autoplay_leveldir->identifier);
992 printf("Level series name: '%s'\n", autoplay_leveldir->name);
993 printf("Level series author: '%s'\n", autoplay_leveldir->author);
994 printf("Number of levels: %d\n", autoplay_leveldir->levels);
995 printf_line("=", 79);
998 for (i = 0; i < MAX_TAPES_PER_SET; i++)
999 level_failed[i] = FALSE;
1001 autoplay_initialized = TRUE;
1004 while (autoplay_level_nr <= autoplay_leveldir->last_level)
1006 level_nr = autoplay_level_nr++;
1008 if (!global.autoplay_all && !global.autoplay_level[level_nr])
1013 printf("Level %03d: ", level_nr);
1015 LoadLevel(level_nr);
1016 if (level.no_valid_file)
1018 printf("(no level)\n");
1023 /* ACTIVATE THIS FOR LOADING/TESTING OF LEVELS ONLY */
1024 printf("(only testing level)\n");
1028 LoadSolutionTape(level_nr);
1030 if (tape.no_valid_file)
1034 printf("(no tape)\n");
1039 printf("playing tape ... ");
1041 TapeStartGamePlaying();
1042 TapeStartWarpForward();
1048 printf_line("=", 79);
1049 printf("Number of levels played: %d\n", num_levels_played);
1050 printf("Number of levels solved: %d (%d%%)\n", num_levels_solved,
1051 (num_levels_played ? num_levels_solved * 100 / num_levels_played :0));
1052 printf_line("-", 79);
1053 printf("Summary (for automatic parsing by scripts):\n");
1054 printf("LEVELDIR '%s', SOLVED %d/%d (%d%%)",
1055 autoplay_leveldir->identifier, num_levels_solved, num_levels_played,
1056 (num_levels_played ? num_levels_solved * 100 / num_levels_played :0));
1058 if (num_levels_played != num_levels_solved)
1060 printf(", FAILED:");
1061 for (i = 0; i < MAX_TAPES_PER_SET; i++)
1062 if (level_failed[i])
1067 printf_line("=", 79);
1073 /* ---------- new tape button stuff ---------------------------------------- */
1081 } tapebutton_info[NUM_TAPE_BUTTONS] =
1084 IMG_TAPE_BUTTON_GFX_EJECT, &tape.button.eject,
1085 TAPE_CTRL_ID_EJECT, "eject tape"
1088 /* (same position as "eject" button) */
1089 IMG_TAPE_BUTTON_GFX_EXTRA, &tape.button.eject,
1090 TAPE_CTRL_ID_EXTRA, "extra functions"
1093 IMG_TAPE_BUTTON_GFX_STOP, &tape.button.stop,
1094 TAPE_CTRL_ID_STOP, "stop tape"
1097 IMG_TAPE_BUTTON_GFX_PAUSE, &tape.button.pause,
1098 TAPE_CTRL_ID_PAUSE, "pause tape"
1101 IMG_TAPE_BUTTON_GFX_RECORD, &tape.button.record,
1102 TAPE_CTRL_ID_RECORD, "record tape"
1105 IMG_TAPE_BUTTON_GFX_PLAY, &tape.button.play,
1106 TAPE_CTRL_ID_PLAY, "play tape"
1110 void CreateTapeButtons()
1114 for (i = 0; i < NUM_TAPE_BUTTONS; i++)
1116 struct GraphicInfo *gfx = &graphic_info[tapebutton_info[i].graphic];
1117 struct Rect *pos = tapebutton_info[i].pos;
1118 struct GadgetInfo *gi;
1119 int gd_x = gfx->src_x;
1120 int gd_y = gfx->src_y;
1121 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
1122 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
1125 gi = CreateGadget(GDI_CUSTOM_ID, id,
1126 GDI_INFO_TEXT, tapebutton_info[i].infotext,
1129 GDI_WIDTH, gfx->width,
1130 GDI_HEIGHT, gfx->height,
1131 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
1132 GDI_STATE, GD_BUTTON_UNPRESSED,
1133 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
1134 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
1135 GDI_DIRECT_DRAW, FALSE,
1136 GDI_EVENT_MASK, GD_EVENT_RELEASED,
1137 GDI_CALLBACK_ACTION, HandleTapeButtons,
1141 Error(ERR_EXIT, "cannot create gadget");
1143 tape_gadget[id] = gi;
1147 void FreeTapeButtons()
1151 for (i = 0; i < NUM_TAPE_BUTTONS; i++)
1152 FreeGadget(tape_gadget[i]);
1155 void MapTapeEjectButton()
1157 UnmapGadget(tape_gadget[TAPE_CTRL_ID_EXTRA]);
1158 MapGadget(tape_gadget[TAPE_CTRL_ID_EJECT]);
1161 void MapTapeWarpButton()
1163 UnmapGadget(tape_gadget[TAPE_CTRL_ID_EJECT]);
1164 MapGadget(tape_gadget[TAPE_CTRL_ID_EXTRA]);
1167 void MapTapeButtons()
1171 for (i = 0; i < NUM_TAPE_BUTTONS; i++)
1172 if (i != TAPE_CTRL_ID_EXTRA)
1173 MapGadget(tape_gadget[i]);
1175 if (tape.recording || tape.playing)
1176 MapTapeWarpButton();
1178 if (tape.show_game_buttons)
1182 void UnmapTapeButtons()
1186 for (i = 0; i < NUM_TAPE_BUTTONS; i++)
1187 UnmapGadget(tape_gadget[i]);
1190 static void HandleTapeButtonsExt(int id)
1192 if (game_status != GAME_MODE_MAIN && game_status != GAME_MODE_PLAYING)
1197 case TAPE_CTRL_ID_EJECT:
1200 if (TAPE_IS_EMPTY(tape))
1204 if (TAPE_IS_EMPTY(tape))
1205 Request("No tape for this level!", REQ_CONFIRM);
1210 SaveTapeChecked(tape.level_nr);
1215 DrawCompleteVideoDisplay();
1218 case TAPE_CTRL_ID_EXTRA:
1221 if (!tape.warp_forward) /* PLAY -> WARP FORWARD PLAY */
1223 TapeStartWarpForward();
1225 else /* WARP FORWARD PLAY -> PLAY */
1227 TapeStopWarpForward();
1230 else if (tape.recording)
1235 case TAPE_CTRL_ID_STOP:
1239 case TAPE_CTRL_ID_PAUSE:
1240 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1243 case TAPE_CTRL_ID_RECORD:
1244 if (TAPE_IS_STOPPED(tape))
1245 TapeStartGameRecording();
1246 else if (tape.pausing)
1248 if (tape.playing) /* PLAY -> PAUSE -> RECORD */
1249 TapeAppendRecording();
1251 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1255 case TAPE_CTRL_ID_PLAY:
1256 if (TAPE_IS_EMPTY(tape))
1259 if (TAPE_IS_STOPPED(tape))
1261 TapeStartGamePlaying();
1263 else if (tape.playing)
1265 if (tape.pausing) /* PAUSE -> PLAY */
1267 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1269 else if (!tape.fast_forward) /* PLAY -> FAST FORWARD PLAY */
1271 tape.fast_forward = TRUE;
1272 DrawVideoDisplay(VIDEO_STATE_FFWD_ON, 0);
1274 else if (!tape.pause_before_death) /* FFWD PLAY -> AUTO PAUSE */
1276 tape.pause_before_death = TRUE;
1277 DrawVideoDisplay(VIDEO_STATE_FFWD_OFF | VIDEO_STATE_PBEND_ON, 0);
1279 else /* AUTO PAUSE -> NORMAL PLAY */
1281 if (tape.warp_forward)
1282 TapeStopWarpForward();
1284 tape.fast_forward = FALSE;
1285 tape.pause_before_death = FALSE;
1287 DrawVideoDisplay(VIDEO_STATE_PBEND_OFF | VIDEO_STATE_PLAY_ON, 0);
1297 static void HandleTapeButtons(struct GadgetInfo *gi)
1299 HandleTapeButtonsExt(gi->custom_id);
1302 void HandleTapeButtonKeys(Key key)
1304 boolean eject_button_is_active = TAPE_IS_STOPPED(tape);
1305 boolean extra_button_is_active = !eject_button_is_active;
1307 if (key == setup.shortcut.tape_eject && eject_button_is_active)
1308 HandleTapeButtonsExt(TAPE_CTRL_ID_EJECT);
1309 else if (key == setup.shortcut.tape_extra && extra_button_is_active)
1310 HandleTapeButtonsExt(TAPE_CTRL_ID_EXTRA);
1311 else if (key == setup.shortcut.tape_stop)
1312 HandleTapeButtonsExt(TAPE_CTRL_ID_STOP);
1313 else if (key == setup.shortcut.tape_pause)
1314 HandleTapeButtonsExt(TAPE_CTRL_ID_PAUSE);
1315 else if (key == setup.shortcut.tape_record)
1316 HandleTapeButtonsExt(TAPE_CTRL_ID_RECORD);
1317 else if (key == setup.shortcut.tape_play)
1318 HandleTapeButtonsExt(TAPE_CTRL_ID_PLAY);