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 #define DEBUG_TAPE_WHEN_PLAYING FALSE
24 /* tape button identifiers */
25 #define TAPE_CTRL_ID_EJECT 0
26 #define TAPE_CTRL_ID_EXTRA 1
27 #define TAPE_CTRL_ID_STOP 2
28 #define TAPE_CTRL_ID_PAUSE 3
29 #define TAPE_CTRL_ID_RECORD 4
30 #define TAPE_CTRL_ID_PLAY 5
32 #define NUM_TAPE_BUTTONS 6
34 /* values for tape handling */
35 #define TAPE_PAUSE_SECONDS_BEFORE_DEATH 5
37 /* forward declaration for internal use */
38 static void HandleTapeButtons(struct GadgetInfo *);
39 static void TapeStopWarpForward();
41 static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS];
44 /* ========================================================================= */
45 /* video tape definitions */
46 /* ========================================================================= */
48 /* some positions in the video tape control window */
49 #define VIDEO_DATE_LABEL_XPOS (VIDEO_DISPLAY1_XPOS)
50 #define VIDEO_DATE_LABEL_YPOS (VIDEO_DISPLAY1_YPOS)
51 #define VIDEO_DATE_LABEL_XSIZE (VIDEO_DISPLAY_XSIZE)
52 #define VIDEO_DATE_LABEL_YSIZE (VIDEO_DISPLAY_YSIZE)
53 #define VIDEO_DATE_XPOS (VIDEO_DISPLAY1_XPOS + 2)
54 #define VIDEO_DATE_YPOS (VIDEO_DISPLAY1_YPOS + 14)
55 #define VIDEO_DATE_XSIZE (VIDEO_DISPLAY_XSIZE)
56 #define VIDEO_DATE_YSIZE 16
57 #define VIDEO_REC_LABEL_XPOS (VIDEO_DISPLAY2_XPOS)
58 #define VIDEO_REC_LABEL_YPOS (VIDEO_DISPLAY2_YPOS)
59 #define VIDEO_REC_LABEL_XSIZE 20
60 #define VIDEO_REC_LABEL_YSIZE 12
61 #define VIDEO_REC_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS + 20)
62 #define VIDEO_REC_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS)
63 #define VIDEO_REC_SYMBOL_XSIZE 16
64 #define VIDEO_REC_SYMBOL_YSIZE 16
65 #define VIDEO_PLAY_LABEL_XPOS (VIDEO_DISPLAY2_XPOS + 65)
66 #define VIDEO_PLAY_LABEL_YPOS (VIDEO_DISPLAY2_YPOS)
67 #define VIDEO_PLAY_LABEL_XSIZE 22
68 #define VIDEO_PLAY_LABEL_YSIZE 12
69 #define VIDEO_PLAY_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS + 52)
70 #define VIDEO_PLAY_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS)
71 #define VIDEO_PLAY_SYMBOL_XSIZE 11
72 #define VIDEO_PLAY_SYMBOL_YSIZE 13
73 #define VIDEO_PAUSE_LABEL_XPOS (VIDEO_DISPLAY2_XPOS)
74 #define VIDEO_PAUSE_LABEL_YPOS (VIDEO_DISPLAY2_YPOS + 20)
75 #define VIDEO_PAUSE_LABEL_XSIZE 35
76 #define VIDEO_PAUSE_LABEL_YSIZE 8
77 #define VIDEO_PAUSE_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS + 35)
78 #define VIDEO_PAUSE_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS)
79 #define VIDEO_PAUSE_SYMBOL_XSIZE 17
80 #define VIDEO_PAUSE_SYMBOL_YSIZE 13
81 #define VIDEO_TIME_XPOS (VIDEO_DISPLAY2_XPOS + 39)
82 #define VIDEO_TIME_YPOS (VIDEO_DISPLAY2_YPOS + 14)
83 #define VIDEO_TIME_XSIZE 50
84 #define VIDEO_TIME_YSIZE 16
86 /* some default values for tape labels and symbols */
87 #define VIDEO_LABEL_XPOS 5
88 #define VIDEO_LABEL_YPOS 42
89 #define VIDEO_LABEL_XSIZE 40
90 #define VIDEO_LABEL_YSIZE 28
91 #define VIDEO_SYMBOL_XPOS 39
92 #define VIDEO_SYMBOL_YPOS 42
93 #define VIDEO_SYMBOL_XSIZE 56
94 #define VIDEO_SYMBOL_YSIZE 13
96 /* values for certain tape labels and symbols */
97 #define VIDEO_FFWD_LABEL_XPOS VIDEO_LABEL_XPOS
98 #define VIDEO_FFWD_LABEL_YPOS 193
99 #define VIDEO_FFWD_LABEL_XSIZE VIDEO_LABEL_XSIZE
100 #define VIDEO_FFWD_LABEL_YSIZE VIDEO_LABEL_YSIZE
101 #define VIDEO_FFWD_SYMBOL_XPOS VIDEO_SYMBOL_XPOS
102 #define VIDEO_FFWD_SYMBOL_YPOS 193
103 #define VIDEO_FFWD_SYMBOL_XSIZE 27
104 #define VIDEO_FFWD_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE
106 #define VIDEO_PBEND_LABEL_XPOS VIDEO_LABEL_XPOS
107 #define VIDEO_PBEND_LABEL_YPOS 221
108 #define VIDEO_PBEND_LABEL_XSIZE VIDEO_LABEL_XSIZE
109 #define VIDEO_PBEND_LABEL_YSIZE VIDEO_LABEL_YSIZE
110 #define VIDEO_PBEND_SYMBOL_XPOS VIDEO_SYMBOL_XPOS
111 #define VIDEO_PBEND_SYMBOL_YPOS 221
112 #define VIDEO_PBEND_SYMBOL_XSIZE 27
113 #define VIDEO_PBEND_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE
115 #define VIDEO_WARP_LABEL_XPOS VIDEO_LABEL_XPOS
116 #define VIDEO_WARP_LABEL_YPOS 165
117 #define VIDEO_WARP_LABEL_XSIZE VIDEO_LABEL_XSIZE
118 #define VIDEO_WARP_LABEL_YSIZE VIDEO_LABEL_YSIZE
119 #define VIDEO_WARP_SYMBOL_XPOS VIDEO_SYMBOL_XPOS
120 #define VIDEO_WARP_SYMBOL_YPOS 165
121 #define VIDEO_WARP_SYMBOL_XSIZE 27
122 #define VIDEO_WARP_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE
123 #define VIDEO_WARP2_SYMBOL_XPOS VIDEO_SYMBOL_XPOS
124 #define VIDEO_WARP2_SYMBOL_YPOS 152
125 #define VIDEO_WARP2_SYMBOL_XSIZE 27
126 #define VIDEO_WARP2_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE
128 #define VIDEO_1STEP_SYMBOL_XPOS (VIDEO_SYMBOL_XPOS + 18)
129 #define VIDEO_1STEP_SYMBOL_YPOS 139
130 #define VIDEO_1STEP_SYMBOL_XSIZE (VIDEO_SYMBOL_XSIZE - 18)
131 #define VIDEO_1STEP_SYMBOL_YSIZE VIDEO_SYMBOL_YSIZE
133 #define PG_X3(x) (DOOR_GFX_PAGEX3 + (x))
134 #define PG_X4(x) (DOOR_GFX_PAGEX4 + (x))
135 #define PG_X5(x) (DOOR_GFX_PAGEX5 + (x))
136 #define PG_X6(x) (DOOR_GFX_PAGEX6 + (x))
138 #define PG_Y1(y) (DOOR_GFX_PAGEY1 + (y))
139 #define PG_Y2(y) (DOOR_GFX_PAGEY2 + (y))
141 #define VIDEO_INFO_OFF (VIDEO_STATE_DATE_OFF | \
142 VIDEO_STATE_TIME_OFF)
143 #define VIDEO_STATE_OFF (VIDEO_STATE_PLAY_OFF | \
144 VIDEO_STATE_REC_OFF | \
145 VIDEO_STATE_PAUSE_OFF | \
146 VIDEO_STATE_FFWD_OFF | \
147 VIDEO_STATE_PBEND_OFF | \
148 VIDEO_STATE_1STEP_OFF)
149 #define VIDEO_PRESS_OFF (VIDEO_PRESS_PLAY_OFF | \
150 VIDEO_PRESS_REC_OFF | \
151 VIDEO_PRESS_PAUSE_OFF | \
152 VIDEO_PRESS_STOP_OFF | \
153 VIDEO_PRESS_EJECT_OFF)
154 #define VIDEO_ALL_OFF (VIDEO_INFO_OFF | \
158 #define VIDEO_INFO_ON (VIDEO_STATE_DATE_ON | \
160 #define VIDEO_STATE_ON (VIDEO_STATE_PLAY_ON | \
161 VIDEO_STATE_REC_ON | \
162 VIDEO_STATE_PAUSE_ON | \
163 VIDEO_STATE_FFWD_ON | \
164 VIDEO_STATE_PBEND_ON | \
165 VIDEO_STATE_1STEP_ON)
166 #define VIDEO_PRESS_ON (VIDEO_PRESS_PLAY_ON | \
167 VIDEO_PRESS_REC_ON | \
168 VIDEO_PRESS_PAUSE_ON | \
169 VIDEO_PRESS_STOP_ON | \
170 VIDEO_PRESS_EJECT_ON)
171 #define VIDEO_ALL_ON (VIDEO_INFO_ON | \
175 #define VIDEO_INFO (VIDEO_INFO_ON | VIDEO_INFO_OFF)
176 #define VIDEO_STATE (VIDEO_STATE_ON | VIDEO_STATE_OFF)
177 #define VIDEO_PRESS (VIDEO_PRESS_ON | VIDEO_PRESS_OFF)
178 #define VIDEO_ALL (VIDEO_ALL_ON | VIDEO_ALL_OFF)
180 #define NUM_TAPE_FUNCTIONS 10
181 #define NUM_TAPE_FUNCTION_PARTS 2
182 #define NUM_TAPE_FUNCTION_STATES 2
185 /* ========================================================================= */
186 /* video display functions */
187 /* ========================================================================= */
189 static void DrawVideoDisplay_Graphics(unsigned int state, unsigned int value)
198 video_pos[NUM_TAPE_FUNCTIONS][NUM_TAPE_FUNCTION_PARTS] =
201 { IMG_TAPE_LABEL_GFX_PLAY, &tape.label.play },
202 { IMG_TAPE_SYMBOL_GFX_PLAY, &tape.symbol.play },
205 { IMG_TAPE_LABEL_GFX_RECORD, &tape.label.record },
206 { IMG_TAPE_SYMBOL_GFX_RECORD, &tape.symbol.record },
209 { IMG_TAPE_LABEL_GFX_PAUSE, &tape.label.pause },
210 { IMG_TAPE_SYMBOL_GFX_PAUSE, &tape.symbol.pause },
213 { IMG_TAPE_LABEL_GFX_DATE, &tape.label.date },
217 { IMG_TAPE_LABEL_GFX_TIME, &tape.label.time },
221 { IMG_TAPE_LABEL_GFX_FAST_FORWARD, &tape.label.fast_forward },
222 { IMG_TAPE_SYMBOL_GFX_FAST_FORWARD, &tape.symbol.fast_forward },
225 { IMG_TAPE_LABEL_GFX_PAUSE_BEFORE_END, &tape.label.pause_before_end },
226 { IMG_TAPE_SYMBOL_GFX_PAUSE_BEFORE_END, &tape.symbol.pause_before_end },
229 { IMG_TAPE_LABEL_GFX_WARP_FORWARD_BLIND, &tape.label.warp_forward_blind},
230 { IMG_TAPE_SYMBOL_GFX_WARP_FORWARD_BLIND, &tape.symbol.warp_forward_blind},
233 { IMG_TAPE_LABEL_GFX_WARP_FORWARD, &tape.label.warp_forward },
234 { IMG_TAPE_SYMBOL_GFX_WARP_FORWARD, &tape.symbol.warp_forward },
237 { IMG_TAPE_LABEL_GFX_SINGLE_STEP, &tape.label.single_step },
238 { IMG_TAPE_SYMBOL_GFX_SINGLE_STEP, &tape.symbol.single_step },
242 for (k = 0; k < NUM_TAPE_FUNCTION_STATES; k++) /* on or off states */
244 for (i = 0; i < NUM_TAPE_FUNCTIONS; i++) /* record, play, ... */
246 for (j = 0; j < NUM_TAPE_FUNCTION_PARTS; j++) /* label or symbol */
248 if (video_pos[i][j].graphic == -1 ||
249 video_pos[i][j].pos->x < 0 ||
250 video_pos[i][j].pos->y < 0)
253 if (state & (1 << (i * 2 + k)))
255 struct GraphicInfo *gfx_bg = &graphic_info[IMG_BACKGROUND_TAPE];
256 struct GraphicInfo *gfx = &graphic_info[video_pos[i][j].graphic];
257 struct Rect *pos = video_pos[i][j].pos;
261 (j == 0 ? VIDEO_DISPLAY_SYMBOL_ONLY : VIDEO_DISPLAY_LABEL_ONLY);
263 if (value == skip_value)
268 gd_bitmap = gfx->bitmap;
274 gd_bitmap = gfx_bg->bitmap;
275 gd_x = gfx_bg->src_x + pos->x;
276 gd_y = gfx_bg->src_y + pos->y;
279 /* some tape graphics may be undefined -- only draw if defined */
280 if (gd_bitmap != NULL)
281 BlitBitmap(gd_bitmap, drawto, gd_x, gd_y, gfx->width, gfx->height,
282 VX + pos->x, VY + pos->y);
290 #define DATETIME_NONE (0)
292 #define DATETIME_DATE_YYYY (1 << 0)
293 #define DATETIME_DATE_YY (1 << 1)
294 #define DATETIME_DATE_MON (1 << 2)
295 #define DATETIME_DATE_MM (1 << 3)
296 #define DATETIME_DATE_DD (1 << 4)
298 #define DATETIME_TIME_HH (1 << 5)
299 #define DATETIME_TIME_MIN (1 << 6)
300 #define DATETIME_TIME_MM (1 << 7)
301 #define DATETIME_TIME_SS (1 << 8)
303 #define DATETIME_XOFFSET_1 (1 << 9)
304 #define DATETIME_XOFFSET_2 (1 << 10)
306 #define DATETIME_DATE (DATETIME_DATE_YYYY | \
308 DATETIME_DATE_MON | \
312 #define DATETIME_TIME (DATETIME_TIME_HH | \
313 DATETIME_TIME_MIN | \
317 #define MAX_DATETIME_STRING_SIZE 32
319 static void DrawVideoDisplay_DateTime(unsigned int state, unsigned int value)
323 static char *month_shortnames[] =
341 struct TextPosInfo *pos;
346 { &tape.text.date, DATETIME_DATE_DD },
347 { &tape.text.date, DATETIME_DATE_MON | DATETIME_XOFFSET_1 },
348 { &tape.text.date, DATETIME_DATE_YY | DATETIME_XOFFSET_2 },
349 { &tape.text.date_yyyy, DATETIME_DATE_YYYY },
350 { &tape.text.date_yy, DATETIME_DATE_YY },
351 { &tape.text.date_mon, DATETIME_DATE_MON },
352 { &tape.text.date_mm, DATETIME_DATE_MM },
353 { &tape.text.date_dd, DATETIME_DATE_DD },
355 { &tape.text.time, DATETIME_TIME_MIN },
356 { &tape.text.time, DATETIME_TIME_SS | DATETIME_XOFFSET_1 },
357 { &tape.text.time_hh, DATETIME_TIME_HH },
358 { &tape.text.time_mm, DATETIME_TIME_MM },
359 { &tape.text.time_ss, DATETIME_TIME_SS },
361 { NULL, DATETIME_NONE },
364 for (i = 0; datetime_info[i].pos != NULL; i++)
366 struct TextPosInfo *pos = datetime_info[i].pos;
367 int type = datetime_info[i].type;
374 xpos = VX + pos->x + (type & DATETIME_XOFFSET_1 ? pos->xoffset :
375 type & DATETIME_XOFFSET_2 ? pos->xoffset2 : 0);
378 if ((type & DATETIME_DATE) && (state & VIDEO_STATE_DATE_ON))
380 char s[MAX_DATETIME_STRING_SIZE];
381 int year2 = value / 10000;
382 int year4 = (year2 < 70 ? 2000 + year2 : 1900 + year2);
383 int month_index = (value / 100) % 100;
384 int month = month_index + 1;
385 int day = value % 100;
387 strcpy(s, (type & DATETIME_DATE_YYYY ? int2str(year4, 4) :
388 type & DATETIME_DATE_YY ? int2str(year2, 2) :
389 type & DATETIME_DATE_MON ? month_shortnames[month_index] :
390 type & DATETIME_DATE_MM ? int2str(month, 2) :
391 type & DATETIME_DATE_DD ? int2str(day, 2) : ""));
393 DrawText(xpos, ypos, s, pos->font);
395 else if ((type & DATETIME_TIME) && (state & VIDEO_STATE_TIME_ON))
397 char s[MAX_DATETIME_STRING_SIZE];
398 int hh = (value / 3600) % 100;
399 int min = value / 60;
400 int mm = (value / 60) % 60;
403 strcpy(s, (type & DATETIME_TIME_HH ? int2str(hh, 2) :
404 type & DATETIME_TIME_MIN ? int2str(min, 2) :
405 type & DATETIME_TIME_MM ? int2str(mm, 2) :
406 type & DATETIME_TIME_SS ? int2str(ss, 2) : ""));
408 DrawText(xpos, ypos, s, pos->font);
413 void DrawVideoDisplay(unsigned int state, unsigned int value)
415 DrawVideoDisplay_Graphics(state, value);
416 DrawVideoDisplay_DateTime(state, value);
418 redraw_mask |= REDRAW_DOOR_2;
421 void DrawCompleteVideoDisplay()
423 struct GraphicInfo *g_tape = &graphic_info[IMG_BACKGROUND_TAPE];
425 /* draw tape background */
426 BlitBitmap(g_tape->bitmap, drawto, g_tape->src_x, g_tape->src_y,
427 gfx.vxsize, gfx.vysize, gfx.vx, gfx.vy);
429 /* draw tape buttons (forced) */
433 DrawVideoDisplay(VIDEO_ALL_OFF, 0);
437 DrawVideoDisplay(VIDEO_STATE_REC_ON, 0);
438 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
439 DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds);
442 DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0);
444 else if (tape.playing)
446 DrawVideoDisplay(VIDEO_STATE_PLAY_ON, 0);
447 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
448 DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
451 DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0);
453 else if (tape.date && tape.length)
455 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
456 DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds);
459 BlitBitmap(drawto, bitmap_db_door_2, gfx.vx, gfx.vy, gfx.vxsize, gfx.vysize,
463 void TapeDeactivateDisplayOn()
465 SetDrawDeactivationMask(REDRAW_FIELD);
466 audio.sound_deactivated = TRUE;
469 void TapeDeactivateDisplayOff(boolean redraw_display)
471 SetDrawDeactivationMask(REDRAW_NONE);
472 audio.sound_deactivated = FALSE;
476 RedrawPlayfield(TRUE, 0,0,0,0);
477 DrawGameDoorValues();
482 /* ========================================================================= */
483 /* tape control functions */
484 /* ========================================================================= */
486 void TapeSetDateFromEpochSeconds(time_t epoch_seconds)
488 struct tm *lt = localtime(&epoch_seconds);
490 tape.date = 10000 * (lt->tm_year % 100) + 100 * lt->tm_mon + lt->tm_mday;
493 void TapeSetDateFromNow()
495 TapeSetDateFromEpochSeconds(time(NULL));
504 tape.length_seconds = 0;
506 if (leveldir_current)
507 setString(&tape.level_identifier, leveldir_current->identifier);
509 tape.level_nr = level_nr;
510 tape.pos[tape.counter].delay = 0;
513 tape.random_seed = InitRND(level.random_seed);
515 tape.file_version = FILE_VERSION_ACTUAL;
516 tape.game_version = GAME_VERSION_ACTUAL;
517 tape.engine_version = level.game_version;
519 TapeSetDateFromNow();
521 for (i = 0; i < MAX_PLAYERS; i++)
522 tape.player_participates[i] = FALSE;
524 tape.centered_player_nr_next = -1;
525 tape.set_centered_player = FALSE;
528 static void TapeRewind()
531 tape.delay_played = 0;
532 tape.pause_before_death = FALSE;
533 tape.recording = FALSE;
534 tape.playing = FALSE;
535 tape.fast_forward = FALSE;
536 tape.warp_forward = FALSE;
537 tape.deactivate_display = FALSE;
538 tape.auto_play = (global.autoplay_leveldir != NULL);
539 tape.auto_play_level_solved = FALSE;
540 tape.quick_resume = FALSE;
541 tape.single_step = FALSE;
543 tape.centered_player_nr_next = -1;
544 tape.set_centered_player = FALSE;
546 InitRND(tape.random_seed);
549 static void TapeSetRandomSeed(int random_seed)
551 tape.random_seed = InitRND(random_seed);
554 void TapeStartRecording(int random_seed)
556 if (!TAPE_IS_STOPPED(tape))
561 TapeSetRandomSeed(random_seed);
563 tape.recording = TRUE;
565 DrawVideoDisplay(VIDEO_STATE_REC_ON, 0);
566 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
567 DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
571 SetDrawDeactivationMask(REDRAW_NONE);
572 audio.sound_deactivated = FALSE;
575 static void TapeStartGameRecording()
577 TapeStartRecording(level.random_seed);
579 #if defined(NETWORK_AVALIABLE)
582 SendToServer_StartPlaying();
591 static void TapeAppendRecording()
593 if (!tape.playing || !tape.pausing)
596 tape.pos[tape.counter].delay = tape.delay_played;
597 tape.playing = FALSE;
598 tape.recording = TRUE;
601 TapeSetDateFromNow();
603 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
604 DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON, 0);
606 UpdateAndDisplayGameControlValues();
609 void TapeHaltRecording()
615 tape.pos[tape.counter].delay = 0;
617 tape.length = tape.counter;
618 tape.length_seconds = GetTapeLength();
621 void TapeStopRecording()
625 tape.recording = FALSE;
626 tape.pausing = FALSE;
628 DrawVideoDisplay(VIDEO_STATE_REC_OFF, 0);
629 MapTapeEjectButton();
632 void TapeRecordAction(byte action_raw[MAX_PLAYERS])
634 byte action[MAX_PLAYERS];
637 if (!tape.recording) /* (record action even when tape is paused) */
640 if (tape.counter >= MAX_TAPE_LEN - 1)
646 for (i = 0; i < MAX_PLAYERS; i++)
647 action[i] = action_raw[i];
649 if (tape.set_centered_player)
651 for (i = 0; i < MAX_PLAYERS; i++)
652 if (tape.centered_player_nr_next == i ||
653 tape.centered_player_nr_next == -1)
654 action[i] |= KEY_SET_FOCUS;
656 tape.set_centered_player = FALSE;
659 if (tape.pos[tape.counter].delay > 0) /* already stored action */
661 boolean changed_events = FALSE;
663 for (i = 0; i < MAX_PLAYERS; i++)
664 if (tape.pos[tape.counter].action[i] != action[i])
665 changed_events = TRUE;
667 if (changed_events || tape.pos[tape.counter].delay >= 255)
670 tape.pos[tape.counter].delay = 0;
673 tape.pos[tape.counter].delay++;
676 if (tape.pos[tape.counter].delay == 0) /* store new action */
678 for (i = 0; i < MAX_PLAYERS; i++)
679 tape.pos[tape.counter].action[i] = action[i];
681 tape.pos[tape.counter].delay++;
685 void TapeTogglePause(boolean toggle_manual)
689 if (tape.pause_before_death)
690 state |= VIDEO_STATE_PBEND_OFF;
691 else if (tape.fast_forward)
692 state |= VIDEO_STATE_FFWD_OFF;
694 tape.pausing = !tape.pausing;
695 tape.fast_forward = FALSE;
696 tape.pause_before_death = FALSE;
698 if (tape.single_step && toggle_manual)
699 tape.single_step = FALSE;
701 state |= (tape.pausing ? VIDEO_STATE_PAUSE_ON : VIDEO_STATE_PAUSE_OFF);
703 state |= VIDEO_STATE_PLAY_ON;
705 state |= (tape.single_step ? VIDEO_STATE_1STEP_ON : VIDEO_STATE_1STEP_OFF);
707 DrawVideoDisplay(state, 0);
709 if (tape.warp_forward)
711 TapeStopWarpForward();
713 if (tape.quick_resume)
715 tape.quick_resume = FALSE;
717 TapeAppendRecording();
719 if (!CheckEngineSnapshot())
720 SaveEngineSnapshot();
725 void TapeStartPlaying()
727 if (TAPE_IS_EMPTY(tape))
730 if (!TAPE_IS_STOPPED(tape))
737 DrawVideoDisplay(VIDEO_STATE_PLAY_ON, 0);
738 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
739 DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
743 SetDrawDeactivationMask(REDRAW_NONE);
744 audio.sound_deactivated = FALSE;
747 static void TapeStartGamePlaying()
754 void TapeStopPlaying()
756 tape.playing = FALSE;
757 tape.pausing = FALSE;
759 if (tape.warp_forward)
760 TapeStopWarpForward();
762 DrawVideoDisplay(VIDEO_STATE_PLAY_OFF, 0);
763 MapTapeEjectButton();
766 byte *TapePlayAction()
768 static byte action[MAX_PLAYERS];
771 if (!tape.playing || tape.pausing)
774 if (tape.pause_before_death) /* stop 10 seconds before player gets killed */
776 if (!(FrameCounter % 20))
778 if ((FrameCounter / 20) % 2)
779 DrawVideoDisplay(VIDEO_STATE_PBEND_ON, VIDEO_DISPLAY_LABEL_ONLY);
781 DrawVideoDisplay(VIDEO_STATE_PBEND_OFF, VIDEO_DISPLAY_LABEL_ONLY);
784 if (tape.warp_forward)
786 if (tape.deactivate_display)
787 DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
789 DrawVideoDisplay(VIDEO_STATE_WARP2_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
792 if (TapeTime > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH)
794 TapeTogglePause(TAPE_TOGGLE_MANUAL);
799 else if (tape.fast_forward)
801 if ((FrameCounter / 20) % 2)
802 DrawVideoDisplay(VIDEO_STATE_FFWD_ON, VIDEO_DISPLAY_LABEL_ONLY);
804 DrawVideoDisplay(VIDEO_STATE_FFWD_OFF, VIDEO_DISPLAY_LABEL_ONLY);
806 if (tape.warp_forward)
808 if (tape.deactivate_display)
809 DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
811 DrawVideoDisplay(VIDEO_STATE_WARP2_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
816 /* !!! this makes things much slower !!! */
817 else if (tape.warp_forward)
819 if ((FrameCounter / 20) % 2)
820 DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_LABEL_ONLY);
822 DrawVideoDisplay(VIDEO_STATE_WARP_OFF, VIDEO_DISPLAY_LABEL_ONLY);
824 DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
828 if (tape.counter >= tape.length) /* end of tape reached */
830 if (tape.warp_forward && !tape.auto_play)
831 TapeTogglePause(TAPE_TOGGLE_MANUAL);
838 for (i = 0; i < MAX_PLAYERS; i++)
839 action[i] = tape.pos[tape.counter].action[i];
841 #if DEBUG_TAPE_WHEN_PLAYING
842 printf("%05d", FrameCounter);
843 for (i = 0; i < MAX_PLAYERS; i++)
844 printf(" %08x", action[i]);
848 tape.set_centered_player = FALSE;
849 tape.centered_player_nr_next = -999;
851 for (i = 0; i < MAX_PLAYERS; i++)
853 if (action[i] & KEY_SET_FOCUS)
855 tape.set_centered_player = TRUE;
856 tape.centered_player_nr_next =
857 (tape.centered_player_nr_next == -999 ? i : -1);
860 action[i] &= ~KEY_SET_FOCUS;
864 if (tape.delay_played >= tape.pos[tape.counter].delay)
867 tape.delay_played = 0;
878 DrawVideoDisplay(VIDEO_STATE_OFF, 0);
880 if (tape.date && tape.length)
882 DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
883 DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds);
887 unsigned int GetTapeLength()
889 unsigned int tape_length = 0;
892 if (TAPE_IS_EMPTY(tape))
895 for (i = 0; i < tape.length; i++)
896 tape_length += tape.pos[i].delay;
898 return(tape_length * GAME_FRAME_DELAY / 1000);
901 static void TapeStartWarpForward()
903 tape.warp_forward = TRUE;
905 if (!tape.fast_forward && !tape.pause_before_death)
907 tape.pausing = FALSE;
908 tape.deactivate_display = TRUE;
910 TapeDeactivateDisplayOn();
913 if (tape.fast_forward || tape.pause_before_death)
914 DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
916 DrawVideoDisplay(VIDEO_STATE_WARP_ON, 0);
919 static void TapeStopWarpForward()
921 int state = (tape.pausing ? VIDEO_STATE_PAUSE_ON : VIDEO_STATE_PAUSE_OFF);
923 tape.warp_forward = FALSE;
924 tape.deactivate_display = FALSE;
926 TapeDeactivateDisplayOff(game_status == GAME_MODE_PLAYING);
928 if (tape.pause_before_death)
929 state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_PBEND_ON;
930 else if (tape.fast_forward)
931 state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_FFWD_ON;
933 state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_PLAY_ON;
935 DrawVideoDisplay(state, 0);
938 static void TapeSingleStep()
944 TapeTogglePause(TAPE_TOGGLE_MANUAL);
946 tape.single_step = !tape.single_step;
948 DrawVideoDisplay((tape.single_step ? VIDEO_STATE_1STEP_ON :
949 VIDEO_STATE_1STEP_OFF), 0);
954 if (game_status == GAME_MODE_MAIN)
956 Request("No game that can be saved!", REQ_CONFIRM);
961 if (game_status != GAME_MODE_PLAYING)
965 TapeHaltRecording(); /* prepare tape for saving on-the-fly */
967 if (TAPE_IS_EMPTY(tape))
969 Request("No tape that can be saved!", REQ_CONFIRM);
974 if (SaveTapeChecked(tape.level_nr))
975 SaveEngineSnapshot();
980 char *filename = getTapeFilename(level_nr);
982 if (!fileExists(filename))
984 Request("No tape for this level!", REQ_CONFIRM);
989 if (tape.recording && !Request("Stop recording and load tape?",
990 REQ_ASK | REQ_STAY_CLOSED))
992 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
997 if (game_status != GAME_MODE_PLAYING && game_status != GAME_MODE_MAIN)
1000 if (CheckEngineSnapshot())
1002 TapeStartGamePlaying();
1004 LoadEngineSnapshot();
1006 DrawCompleteVideoDisplay();
1008 tape.playing = TRUE;
1009 tape.pausing = TRUE;
1011 TapeStopWarpForward();
1012 TapeAppendRecording();
1014 if (FrameCounter > 0)
1023 if (!TAPE_IS_EMPTY(tape))
1025 TapeStartGamePlaying();
1026 TapeStartWarpForward();
1028 tape.quick_resume = TRUE;
1030 else /* this should not happen (basically checked above) */
1032 int reopen_door = (game_status == GAME_MODE_PLAYING ? REQ_REOPEN : 0);
1034 Request("No tape for this level!", REQ_CONFIRM | reopen_door);
1038 void InsertSolutionTape()
1040 if (!TAPE_IS_EMPTY(tape))
1043 LoadSolutionTape(level_nr);
1045 if (TAPE_IS_EMPTY(tape))
1046 Request("No solution tape for this level!", REQ_CONFIRM);
1048 DrawCompleteVideoDisplay();
1052 /* ------------------------------------------------------------------------- *
1053 * tape autoplay functions
1054 * ------------------------------------------------------------------------- */
1058 static LevelDirTree *autoplay_leveldir = NULL;
1059 static boolean autoplay_initialized = FALSE;
1060 static int autoplay_level_nr = -1;
1061 static int num_levels_played = 0;
1062 static int num_levels_solved = 0;
1063 static int num_tape_missing = 0;
1064 static boolean level_failed[MAX_TAPES_PER_SET];
1067 if (autoplay_initialized)
1069 /* just finished auto-playing tape */
1070 printf("%s.\n", tape.auto_play_level_solved ? "solved" : "NOT SOLVED");
1072 num_levels_played++;
1074 if (tape.auto_play_level_solved)
1075 num_levels_solved++;
1076 else if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
1077 level_failed[level_nr] = TRUE;
1081 DrawCompleteVideoDisplay();
1082 audio.sound_enabled = FALSE;
1084 autoplay_leveldir = getTreeInfoFromIdentifier(leveldir_first,
1085 global.autoplay_leveldir);
1087 if (autoplay_leveldir == NULL)
1088 Error(ERR_EXIT, "no such level identifier: '%s'",
1089 global.autoplay_leveldir);
1091 leveldir_current = autoplay_leveldir;
1093 if (autoplay_leveldir->first_level < 0)
1094 autoplay_leveldir->first_level = 0;
1095 if (autoplay_leveldir->last_level >= MAX_TAPES_PER_SET)
1096 autoplay_leveldir->last_level = MAX_TAPES_PER_SET - 1;
1098 autoplay_level_nr = autoplay_leveldir->first_level;
1100 printf_line("=", 79);
1101 printf("Automatically playing level tapes\n");
1102 printf_line("-", 79);
1103 printf("Level series identifier: '%s'\n", autoplay_leveldir->identifier);
1104 printf("Level series name: '%s'\n", autoplay_leveldir->name);
1105 printf("Level series author: '%s'\n", autoplay_leveldir->author);
1106 printf("Number of levels: %d\n", autoplay_leveldir->levels);
1107 printf_line("=", 79);
1110 for (i = 0; i < MAX_TAPES_PER_SET; i++)
1111 level_failed[i] = FALSE;
1113 autoplay_initialized = TRUE;
1116 while (autoplay_level_nr <= autoplay_leveldir->last_level)
1118 level_nr = autoplay_level_nr++;
1120 if (!global.autoplay_all && !global.autoplay_level[level_nr])
1125 printf("Level %03d: ", level_nr);
1127 LoadLevel(level_nr);
1128 if (level.no_valid_file)
1130 printf("(no level)\n");
1135 /* ACTIVATE THIS FOR LOADING/TESTING OF LEVELS ONLY */
1136 printf("(only testing level)\n");
1140 LoadSolutionTape(level_nr);
1142 if (tape.no_valid_file)
1146 printf("(no tape)\n");
1151 printf("playing tape ... ");
1153 TapeStartGamePlaying();
1154 TapeStartWarpForward();
1160 printf_line("=", 79);
1161 printf("Number of levels played: %d\n", num_levels_played);
1162 printf("Number of levels solved: %d (%d%%)\n", num_levels_solved,
1163 (num_levels_played ? num_levels_solved * 100 / num_levels_played :0));
1164 printf_line("-", 79);
1165 printf("Summary (for automatic parsing by scripts):\n");
1166 printf("LEVELDIR '%s', SOLVED %d/%d (%d%%)",
1167 autoplay_leveldir->identifier, num_levels_solved, num_levels_played,
1168 (num_levels_played ? num_levels_solved * 100 / num_levels_played :0));
1170 if (num_levels_played != num_levels_solved)
1172 printf(", FAILED:");
1173 for (i = 0; i < MAX_TAPES_PER_SET; i++)
1174 if (level_failed[i])
1179 printf_line("=", 79);
1185 /* ---------- new tape button stuff ---------------------------------------- */
1193 } tapebutton_info[NUM_TAPE_BUTTONS] =
1196 IMG_TAPE_BUTTON_GFX_EJECT, &tape.button.eject,
1197 TAPE_CTRL_ID_EJECT, "eject tape"
1200 /* (same position as "eject" button) */
1201 IMG_TAPE_BUTTON_GFX_EXTRA, &tape.button.eject,
1202 TAPE_CTRL_ID_EXTRA, "extra functions"
1205 IMG_TAPE_BUTTON_GFX_STOP, &tape.button.stop,
1206 TAPE_CTRL_ID_STOP, "stop tape"
1209 IMG_TAPE_BUTTON_GFX_PAUSE, &tape.button.pause,
1210 TAPE_CTRL_ID_PAUSE, "pause tape"
1213 IMG_TAPE_BUTTON_GFX_RECORD, &tape.button.record,
1214 TAPE_CTRL_ID_RECORD, "record tape"
1217 IMG_TAPE_BUTTON_GFX_PLAY, &tape.button.play,
1218 TAPE_CTRL_ID_PLAY, "play tape"
1222 void CreateTapeButtons()
1226 for (i = 0; i < NUM_TAPE_BUTTONS; i++)
1228 struct GraphicInfo *gfx = &graphic_info[tapebutton_info[i].graphic];
1229 struct Rect *pos = tapebutton_info[i].pos;
1230 struct GadgetInfo *gi;
1231 int gd_x = gfx->src_x;
1232 int gd_y = gfx->src_y;
1233 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
1234 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
1237 gi = CreateGadget(GDI_CUSTOM_ID, id,
1238 GDI_INFO_TEXT, tapebutton_info[i].infotext,
1241 GDI_WIDTH, gfx->width,
1242 GDI_HEIGHT, gfx->height,
1243 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
1244 GDI_STATE, GD_BUTTON_UNPRESSED,
1245 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
1246 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
1247 GDI_DIRECT_DRAW, FALSE,
1248 GDI_EVENT_MASK, GD_EVENT_RELEASED,
1249 GDI_CALLBACK_ACTION, HandleTapeButtons,
1253 Error(ERR_EXIT, "cannot create gadget");
1255 tape_gadget[id] = gi;
1259 void FreeTapeButtons()
1263 for (i = 0; i < NUM_TAPE_BUTTONS; i++)
1264 FreeGadget(tape_gadget[i]);
1267 void MapTapeEjectButton()
1269 UnmapGadget(tape_gadget[TAPE_CTRL_ID_EXTRA]);
1270 MapGadget(tape_gadget[TAPE_CTRL_ID_EJECT]);
1273 void MapTapeWarpButton()
1275 UnmapGadget(tape_gadget[TAPE_CTRL_ID_EJECT]);
1276 MapGadget(tape_gadget[TAPE_CTRL_ID_EXTRA]);
1279 void MapTapeButtons()
1283 for (i = 0; i < NUM_TAPE_BUTTONS; i++)
1284 if (i != TAPE_CTRL_ID_EXTRA)
1285 MapGadget(tape_gadget[i]);
1287 if (tape.recording || tape.playing)
1288 MapTapeWarpButton();
1290 if (tape.show_game_buttons)
1294 void UnmapTapeButtons()
1298 for (i = 0; i < NUM_TAPE_BUTTONS; i++)
1299 UnmapGadget(tape_gadget[i]);
1301 if (tape.show_game_buttons)
1305 static void HandleTapeButtonsExt(int id)
1307 if (game_status != GAME_MODE_MAIN && game_status != GAME_MODE_PLAYING)
1312 case TAPE_CTRL_ID_EJECT:
1315 if (TAPE_IS_EMPTY(tape))
1319 if (TAPE_IS_EMPTY(tape))
1320 Request("No tape for this level!", REQ_CONFIRM);
1325 SaveTapeChecked(tape.level_nr);
1330 DrawCompleteVideoDisplay();
1333 case TAPE_CTRL_ID_EXTRA:
1336 if (!tape.warp_forward) /* PLAY -> WARP FORWARD PLAY */
1338 TapeStartWarpForward();
1340 else /* WARP FORWARD PLAY -> PLAY */
1342 TapeStopWarpForward();
1345 else if (tape.recording)
1350 case TAPE_CTRL_ID_STOP:
1354 case TAPE_CTRL_ID_PAUSE:
1355 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1358 case TAPE_CTRL_ID_RECORD:
1359 if (TAPE_IS_STOPPED(tape))
1360 TapeStartGameRecording();
1361 else if (tape.pausing)
1363 if (tape.playing) /* PLAY -> PAUSE -> RECORD */
1364 TapeAppendRecording();
1366 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1370 case TAPE_CTRL_ID_PLAY:
1371 if (TAPE_IS_EMPTY(tape))
1374 if (TAPE_IS_STOPPED(tape))
1376 TapeStartGamePlaying();
1378 else if (tape.playing)
1380 if (tape.pausing) /* PAUSE -> PLAY */
1382 TapeTogglePause(TAPE_TOGGLE_MANUAL);
1384 else if (!tape.fast_forward) /* PLAY -> FAST FORWARD PLAY */
1386 tape.fast_forward = TRUE;
1387 DrawVideoDisplay(VIDEO_STATE_FFWD_ON, 0);
1389 else if (!tape.pause_before_death) /* FFWD PLAY -> AUTO PAUSE */
1391 tape.pause_before_death = TRUE;
1392 DrawVideoDisplay(VIDEO_STATE_FFWD_OFF | VIDEO_STATE_PBEND_ON, 0);
1394 else /* AUTO PAUSE -> NORMAL PLAY */
1396 if (tape.warp_forward)
1397 TapeStopWarpForward();
1399 tape.fast_forward = FALSE;
1400 tape.pause_before_death = FALSE;
1402 DrawVideoDisplay(VIDEO_STATE_PBEND_OFF | VIDEO_STATE_PLAY_ON, 0);
1412 static void HandleTapeButtons(struct GadgetInfo *gi)
1414 HandleTapeButtonsExt(gi->custom_id);
1417 void HandleTapeButtonKeys(Key key)
1419 boolean eject_button_is_active = TAPE_IS_STOPPED(tape);
1420 boolean extra_button_is_active = !eject_button_is_active;
1422 if (key == setup.shortcut.tape_eject && eject_button_is_active)
1423 HandleTapeButtonsExt(TAPE_CTRL_ID_EJECT);
1424 else if (key == setup.shortcut.tape_extra && extra_button_is_active)
1425 HandleTapeButtonsExt(TAPE_CTRL_ID_EXTRA);
1426 else if (key == setup.shortcut.tape_stop)
1427 HandleTapeButtonsExt(TAPE_CTRL_ID_STOP);
1428 else if (key == setup.shortcut.tape_pause)
1429 HandleTapeButtonsExt(TAPE_CTRL_ID_PAUSE);
1430 else if (key == setup.shortcut.tape_record)
1431 HandleTapeButtonsExt(TAPE_CTRL_ID_RECORD);
1432 else if (key == setup.shortcut.tape_play)
1433 HandleTapeButtonsExt(TAPE_CTRL_ID_PLAY);