+2006-03-14
+ * added player focus switching to level tape recording and re-playing
+
2006-03-13
* fixed some bugs in player focus switching in EMC and RND game engine
-#define COMPILE_DATE_STRING "[2006-03-13 02:03]"
+#define COMPILE_DATE_STRING "[2006-03-14 01:37]"
/* functions and definitions exported from main program to game_em */
/* ========================================================================= */
+#include "game.h"
+
extern void SetBitmaps_EM(Bitmap **);
extern void UpdateEngineValues(int, int);
extern void DrawAllGameValues(int, int, int, int, int);
+#if 0
extern void setCenteredPlayerNr_EM(int);
extern int getCenteredPlayerNr_EM();
extern void setSetCenteredPlayer_EM(boolean);
extern boolean getSetCenteredPlayer_EM();
+#endif
+
extern int getNumActivePlayers_EM();
extern int getGameFrameDelay_EM(int);
{
#ifdef DEBUG
if (is_string_suffix(cheat_input, ".q"))
- for (i = 0; i < MAX_INVENTORY_SIZE; i++)
- if (local_player->inventory_size < MAX_INVENTORY_SIZE)
- local_player->inventory_element[local_player->inventory_size++] =
- EL_DYNAMITE;
+ DEBUG_SetMaximumDynamite();
#endif
}
else if (game_status == GAME_MODE_EDITOR)
{
game.centered_player_nr_next = centered_player_nr_next;
game.set_centered_player = TRUE;
+
+ if (tape.recording)
+ {
+ tape.centered_player_nr_next = game.centered_player_nr_next;
+ tape.set_centered_player = TRUE;
+ }
}
}
static void MapGameButtons();
static void HandleGameButtons(struct GadgetInfo *);
+int AmoebeNachbarNr(int, int);
+void AmoebeUmwandeln(int, int);
+void ContinueMoving(int, int);
+void Bang(int, int);
+void InitMovDir(int, int);
+void InitAmoebaNr(int, int);
+int NewHiScore(void);
+
+void TestIfGoodThingHitsBadThing(int, int, int);
+void TestIfBadThingHitsGoodThing(int, int, int);
+void TestIfPlayerTouchesBadThing(int, int);
+void TestIfPlayerRunsIntoBadThing(int, int, int);
+void TestIfBadThingTouchesPlayer(int, int);
+void TestIfBadThingRunsIntoPlayer(int, int, int);
+void TestIfFriendTouchesBadThing(int, int);
+void TestIfBadThingTouchesFriend(int, int);
+void TestIfBadThingTouchesOtherBadThing(int, int);
+
+void KillPlayer(struct PlayerInfo *);
+void BuryPlayer(struct PlayerInfo *);
+void RemovePlayer(struct PlayerInfo *);
+
+boolean SnapField(struct PlayerInfo *, int, int);
+boolean DropElement(struct PlayerInfo *);
+
+
static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
(x) >= 0 && (x) <= lev_fieldx - 1; \
(x) += playfield_scan_delta_x) \
+#ifdef DEBUG
+void DEBUG_SetMaximumDynamite()
+{
+ int i;
+
+ for (i = 0; i < MAX_INVENTORY_SIZE; i++)
+ if (local_player->inventory_size < MAX_INVENTORY_SIZE)
+ local_player->inventory_element[local_player->inventory_size++] =
+ EL_DYNAMITE;
+}
+#endif
+
static void InitPlayfieldScanModeVars()
{
if (game.use_reverse_scan_direction)
/* special case for sleeping Murphy when leaning against non-free tile */
if (!IN_LEV_FIELD(player->jx - 1, player->jy) ||
- Feld[player->jx - 1][player->jy] != EL_EMPTY)
+ (Feld[player->jx - 1][player->jy] != EL_EMPTY &&
+ !IS_MOVING(player->jx - 1, player->jy)))
move_dir = MV_LEFT;
else if (!IN_LEV_FIELD(player->jx + 1, player->jy) ||
- Feld[player->jx + 1][player->jy] != EL_EMPTY)
+ (Feld[player->jx + 1][player->jy] != EL_EMPTY &&
+ !IS_MOVING(player->jx + 1, player->jy)))
move_dir = MV_RIGHT;
else
player->is_sleeping = FALSE;
InitPlayfieldScanModeVars();
+#if 0
if (game.set_centered_player)
{
boolean all_players_fit_to_screen = checkIfAllPlayersFitToScreen_RND();
game.set_centered_player = FALSE;
}
+#endif
#if USE_ONE_MORE_CHANGE_PER_FRAME
if (game.engine_version >= VERSION_IDENT(3,2,0,7))
recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
+#if 1
+ if (tape.set_centered_player)
+ {
+ game.centered_player_nr_next = tape.centered_player_nr_next;
+ game.set_centered_player = TRUE;
+ }
+
+ if (game.set_centered_player)
+ {
+ boolean all_players_fit_to_screen = checkIfAllPlayersFitToScreen_RND();
+
+ /* switching to "all players" only possible if all players fit to screen */
+ if (game.centered_player_nr_next == -1 && !all_players_fit_to_screen)
+ {
+ game.centered_player_nr_next = game.centered_player_nr;
+ game.set_centered_player = FALSE;
+ }
+
+ /* do not switch focus to non-existing (or non-active) player */
+ if (game.centered_player_nr_next >= 0 &&
+ !stored_player[game.centered_player_nr_next].active)
+ {
+ game.centered_player_nr_next = game.centered_player_nr;
+ game.set_centered_player = FALSE;
+ }
+ }
+
+ if (game.set_centered_player &&
+ ScreenMovPos == 0) /* screen currently aligned at tile position */
+ {
+#if 0
+ struct PlayerInfo *player;
+ int player_nr = game.centered_player_nr_next;
+#endif
+ int sx, sy;
+
+ if (game.centered_player_nr_next == -1)
+ {
+ setScreenCenteredToAllPlayers(&sx, &sy);
+ }
+ else
+ {
+ sx = stored_player[game.centered_player_nr_next].jx;
+ sy = stored_player[game.centered_player_nr_next].jy;
+ }
+
+#if 0
+ player = &stored_player[player_nr];
+
+ if (!player->active)
+ game.centered_player_nr_next = game.centered_player_nr;
+
+ sx = player->jx;
+ sy = player->jy;
+#endif
+
+#if 0
+ if (game.centered_player_nr != game.centered_player_nr_next)
+#endif
+ {
+#if 1
+ DrawRelocateScreen(sx, sy, MV_NONE, TRUE, setup.quick_switch);
+#else
+ DrawRelocatePlayer(player, setup.quick_switch);
+#endif
+
+ game.centered_player_nr = game.centered_player_nr_next;
+ }
+
+ game.set_centered_player = FALSE;
+ }
+#endif
+
#if 1
/* !!! CHECK THIS (tape.pausing is always FALSE here!) !!! */
if (recorded_player_action == NULL && tape.pausing)
#ifndef GAME_H
#define GAME_H
-#include "main.h"
+
+#define MAX_INVENTORY_SIZE 1000
+#define STD_NUM_KEYS 4
+#define MAX_NUM_KEYS 8
+
+
+struct GameInfo
+{
+ /* values for engine initialization */
+ int default_push_delay_fixed;
+ int default_push_delay_random;
+
+ /* constant within running game */
+ int engine_version;
+ int emulation;
+ int initial_move_delay;
+ int initial_move_delay_value;
+ int initial_push_delay_value;
+
+ /* flags to handle bugs in and changes between different engine versions */
+ /* (for the latest engine version, these flags should always be "FALSE") */
+ boolean use_change_when_pushing_bug;
+ boolean use_block_last_field_bug;
+ boolean max_num_changes_per_frame;
+ boolean use_reverse_scan_direction;
+
+ /* variable within running game */
+ int yamyam_content_nr;
+ boolean magic_wall_active;
+ int magic_wall_time_left;
+ int light_time_left;
+ int timegate_time_left;
+ int belt_dir[4];
+ int belt_dir_nr[4];
+ int switchgate_pos;
+ int wind_direction;
+ boolean gravity;
+ boolean explosions_delayed;
+ boolean envelope_active;
+
+#if 1
+ /* values for the new EMC elements */
+ int lenses_time_left;
+ int magnify_time_left;
+ boolean ball_state;
+ int ball_content_nr;
+#endif
+
+ /* values for player idle animation (no effect on engine) */
+ int player_boring_delay_fixed;
+ int player_boring_delay_random;
+ int player_sleeping_delay_fixed;
+ int player_sleeping_delay_random;
+
+ /* values for special game initialization control */
+ boolean restart_level;
+
+ /* values for special game control */
+ int centered_player_nr;
+ int centered_player_nr_next;
+ boolean set_centered_player;
+};
+
+struct PlayerInfo
+{
+ boolean present; /* player present in level playfield */
+ boolean connected; /* player connected (locally or via network) */
+ boolean active; /* player present and connected */
+
+ int index_nr; /* player number (0 to 3) */
+ int index_bit; /* player number bit (1 << 0 to 1 << 3) */
+ int element_nr; /* element (EL_PLAYER_1 to EL_PLAYER_4) */
+ int client_nr; /* network client identifier */
+
+ byte action; /* action from local input device */
+ byte effective_action; /* action acknowledged from network server
+ or summarized over all configured input
+ devices when in single player mode */
+ byte programmed_action; /* action forced by game itself (like moving
+ through doors); overrides other actions */
+
+ int jx, jy, last_jx, last_jy;
+ int MovDir, MovPos, GfxDir, GfxPos;
+ int Frame, StepFrame;
+
+ int GfxAction;
+
+ boolean use_murphy;
+ int artwork_element;
+
+ boolean block_last_field;
+ int block_delay_adjustment; /* needed for different engine versions */
+
+ boolean can_fall_into_acid;
+
+ boolean LevelSolved, GameOver;
+
+ int last_move_dir;
+
+ boolean is_waiting;
+ boolean is_moving;
+ boolean is_auto_moving;
+ boolean is_digging;
+ boolean is_snapping;
+ boolean is_collecting;
+ boolean is_pushing;
+ boolean is_switching;
+ boolean is_dropping;
+ boolean is_dropping_pressed;
+
+ boolean is_bored;
+ boolean is_sleeping;
+
+ boolean cannot_move;
+
+ int frame_counter_bored;
+ int frame_counter_sleeping;
+
+ int anim_delay_counter;
+ int post_delay_counter;
+
+ int dir_waiting;
+ int action_waiting, last_action_waiting;
+ int special_action_bored;
+ int special_action_sleeping;
+
+ int num_special_action_bored;
+ int num_special_action_sleeping;
+
+ int switch_x, switch_y;
+ int drop_x, drop_y;
+
+ int show_envelope;
+
+ int move_delay;
+ int move_delay_value;
+ int move_delay_value_next;
+ int move_delay_reset_counter;
+
+ int push_delay;
+ int push_delay_value;
+
+ unsigned long actual_frame_counter;
+
+ int drop_delay;
+ int drop_pressed_delay;
+
+ int step_counter;
+
+ int score;
+ int gems_still_needed;
+ int sokobanfields_still_needed;
+ int lights_still_needed;
+ int friends_still_needed;
+ int key[MAX_NUM_KEYS];
+ int dynabomb_count, dynabomb_size, dynabombs_left, dynabomb_xl;
+ int shield_normal_time_left;
+ int shield_deadly_time_left;
+
+ int inventory_element[MAX_INVENTORY_SIZE];
+ int inventory_infinite_element;
+ int inventory_size;
+};
+
+
+extern struct GameInfo game;
+extern struct PlayerInfo stored_player[], *local_player;
+
+
+#ifdef DEBUG
+void DEBUG_SetMaximumDynamite();
+#endif
void GetPlayerConfig(void);
void InitGame(void);
void UpdateEngineValues(int, int);
-
-void InitMovDir(int, int);
-void InitAmoebaNr(int, int);
void GameWon(void);
-int NewHiScore(void);
void InitPlayerGfxAnimation(struct PlayerInfo *, int, int);
-void InitMovingField(int, int, int);
void Moving2Blocked(int, int, int *, int *);
void Blocked2Moving(int, int, int *, int *);
-int MovingOrBlocked2Element(int, int);
-void RemoveMovingField(int, int);
void DrawDynamite(int, int);
-void CheckDynamite(int, int);
-void Explode(int, int, int, int);
-void DynaExplode(int, int);
-void Bang(int, int);
-void Blurb(int, int);
-void Impact(int, int);
-void StartMoving(int, int);
-void ContinueMoving(int, int);
-int AmoebeNachbarNr(int, int);
-void AmoebeUmwandeln(int, int);
-void AmoebeUmwandelnBD(int, int, int);
-void AmoebeWaechst(int, int);
-void AmoebeAbleger(int, int);
-void Life(int, int);
-void Ablenk(int, int);
-void Blubber(int, int);
-void NussKnacken(int, int);
-void SiebAktivieren(int, int, int);
-void AusgangstuerPruefen(int, int);
-void AusgangstuerOeffnen(int, int);
-void AusgangstuerBlinken(int, int);
-void EdelsteinFunkeln(int, int);
-void MauerWaechst(int, int);
-void MauerAbleger(int, int);
void GameActions(void);
void ScrollLevel(int, int);
-void TestIfGoodThingHitsBadThing(int, int, int);
-void TestIfBadThingHitsGoodThing(int, int, int);
-void TestIfPlayerTouchesBadThing(int, int);
-void TestIfPlayerRunsIntoBadThing(int, int, int);
-void TestIfBadThingTouchesPlayer(int, int);
-void TestIfBadThingRunsIntoPlayer(int, int, int);
-void TestIfFriendTouchesBadThing(int, int);
-void TestIfBadThingTouchesFriend(int, int);
-void TestIfBadThingTouchesOtherBadThing(int, int);
-void KillPlayer(struct PlayerInfo *);
-void BuryPlayer(struct PlayerInfo *);
-void RemovePlayer(struct PlayerInfo *);
-boolean SnapField(struct PlayerInfo *, int, int);
-boolean DropElement(struct PlayerInfo *);
-
void InitPlayLevelSound();
void PlayLevelSound_EM(int, int, int, int);
#define SYSIZE (SCR_FIELDY * TILEY)
#if 1
+
+#if 0
#define FRAMES_PER_SECOND 50
+#endif
#define ROUNDED_DIVIDE(x, y) (((x) + (y) - 1) / (y))
static boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
+#if 0
#if 1
int centered_player_nr;
#else
static int centered_player_nr;
#endif
+#endif
/* copy the entire screen to the window at the scroll position */
frame = 6;
- centered_player_nr = getCenteredPlayerNr_EM();
+#if 0
+ game.centered_player_nr = getCenteredPlayerNr_EM();
+#endif
- player_nr = (centered_player_nr != -1 ? centered_player_nr : 0);
+ player_nr = (game.centered_player_nr != -1 ? game.centered_player_nr : 0);
screen_x = VALID_SCREEN_X(PLAYER_SCREEN_X(player_nr));
screen_y = VALID_SCREEN_Y(PLAYER_SCREEN_Y(player_nr));
#if 0
boolean scrolling = (screen_x % TILEX != 0 || screen_y % TILEY != 0);
#endif
- boolean set_centered_player = getSetCenteredPlayer_EM();
- int centered_player_nr_next = getCenteredPlayerNr_EM();
+#if 0
+ boolean game.set_centered_player = getSetCenteredPlayer_EM();
+ int game.centered_player_nr_next = getCenteredPlayerNr_EM();
+#endif
int offset = (setup.scroll_delay ? 3 : 0) * TILEX;
int offset_x = offset;
int offset_y = offset;
int x, y, sx, sy;
int i;
- if (set_centered_player)
+ if (game.set_centered_player)
{
boolean all_players_fit_to_screen = checkIfAllPlayersFitToScreen();
/* switching to "all players" only possible if all players fit to screen */
- if (centered_player_nr_next == -1 && !all_players_fit_to_screen)
+ if (game.centered_player_nr_next == -1 && !all_players_fit_to_screen)
{
- centered_player_nr_next = centered_player_nr;
- setCenteredPlayerNr_EM(centered_player_nr);
-
- set_centered_player = FALSE;
- setSetCenteredPlayer_EM(FALSE);
+ game.centered_player_nr_next = game.centered_player_nr;
+ game.set_centered_player = FALSE;
}
/* do not switch focus to non-existing (or non-active) player */
- if (centered_player_nr_next >= 0 && !ply[centered_player_nr_next].alive)
+ if (game.centered_player_nr_next >= 0 &&
+ !ply[game.centered_player_nr_next].alive)
{
- centered_player_nr_next = centered_player_nr;
- setCenteredPlayerNr_EM(centered_player_nr);
-
- set_centered_player = FALSE;
- setSetCenteredPlayer_EM(FALSE);
+ game.centered_player_nr_next = game.centered_player_nr;
+ game.set_centered_player = FALSE;
}
}
#endif
{
#if 1
- if (set_centered_player)
+ if (game.set_centered_player)
#else
- if (centered_player_nr != centered_player_nr_next)
+ if (game.centered_player_nr != game.centered_player_nr_next)
#endif
{
- centered_player_nr = centered_player_nr_next;
+ game.centered_player_nr = game.centered_player_nr_next;
draw_new_player_location = TRUE;
force_redraw = TRUE;
- setSetCenteredPlayer_EM(FALSE);
+ game.set_centered_player = FALSE;
}
}
- if (centered_player_nr == -1)
+ if (game.centered_player_nr == -1)
{
if (draw_new_player_location)
{
}
else
{
- sx = PLAYER_SCREEN_X(centered_player_nr);
- sy = PLAYER_SCREEN_Y(centered_player_nr);
+ sx = PLAYER_SCREEN_X(game.centered_player_nr);
+ sy = PLAYER_SCREEN_Y(game.centered_player_nr);
}
if (draw_new_player_location && quick_relocation)
}
/* prevent scrolling away from the other players when focus on all players */
- if (centered_player_nr == -1)
+ if (game.centered_player_nr == -1)
{
#if 1
/* check if all players are still visible with new scrolling position */
#include "display.h"
+#if 0
extern int centered_player_nr;
+#endif
+
extern boolean checkIfAllPlayersFitToScreen();
static void check_player(struct PLAYER *);
ply->x = x;
ply->y = y;
- can_move = (centered_player_nr != -1 || checkIfAllPlayersFitToScreen());
+ can_move = (game.centered_player_nr != -1 ||
+ checkIfAllPlayersFitToScreen());
ply->x = oldx;
ply->y = oldy;
#define BUTTON_1 4
#define BUTTON_2 5
+/* values for special "focus player" bitmasks */
+#define BIT_SET_FOCUS 6
+
/* values for move directions and special "button" key bitmasks */
#define MV_NONE 0
#define MV_LEFT (1 << MV_BIT_LEFT)
#define KEY_BUTTON (KEY_BUTTON_1 | KEY_BUTTON_2)
#define KEY_ACTION (KEY_MOTION | KEY_BUTTON)
+#define SET_FOCUS (1 << BIT_SET_FOCUS)
+
#define MV_DIR_FROM_BIT(x) ((x) < NUM_DIRECTIONS ? 1 << (x) : \
(x) == MV_BIT_UPLEFT ? MV_UPLEFT : \
(x) == MV_BIT_UPRIGHT ? MV_UPRIGHT : \
#define CURSOR_DEFAULT 0
#define CURSOR_PLAYFIELD 1
+/* fundamental game speed values */
+#define ONE_SECOND_DELAY 1000 /* delay value for one second */
+#define GAME_FRAME_DELAY 20 /* frame delay in milliseconds */
+#define FFWD_FRAME_DELAY 10 /* 200% speed for fast forward */
+#define FRAMES_PER_SECOND (ONE_SECOND_DELAY / GAME_FRAME_DELAY)
/* maximum playfield size supported by libgame functions */
#define MAX_PLAYFIELD_WIDTH 128
#include "main.h"
#include "init.h"
#include "game.h"
+#include "tape.h"
#include "events.h"
#include "config.h"
#define EL_NAME(e) ((e) >= 0 ? element_info[e].token_name : "(?)")
/* fundamental game speed values */
-#define ONE_SECOND_DELAY 1000 /* delay value for one second */
-#define GAME_FRAME_DELAY 20 /* frame delay in milliseconds */
-#define FFWD_FRAME_DELAY 10 /* 200% speed for fast forward */
-#define FRAMES_PER_SECOND (ONE_SECOND_DELAY / GAME_FRAME_DELAY)
#define MICROLEVEL_SCROLL_DELAY 50 /* delay for scrolling micro level */
#define MICROLEVEL_LABEL_DELAY 250 /* delay for micro level label */
#define MAX_LEVEL_NAME_LEN 32
#define MAX_LEVEL_AUTHOR_LEN 32
#define MAX_ELEMENT_NAME_LEN 32
-#define MAX_TAPE_LEN (1000 * FRAMES_PER_SECOND) /* max.time x fps */
#define MAX_TAPES_PER_SET 1024
#define MAX_SCORE_ENTRIES 100
#define MAX_NUM_AMOEBA 100
+#if 0 /* game.h */
#define MAX_INVENTORY_SIZE 1000
#define STD_NUM_KEYS 4
#define MAX_NUM_KEYS 8
+#endif
#define NUM_BELTS 4
#define NUM_BELT_PARTS 3
#define MIN_ENVELOPE_XSIZE 1
int e[3][3];
};
-struct PlayerInfo
-{
- boolean present; /* player present in level playfield */
- boolean connected; /* player connected (locally or via network) */
- boolean active; /* player present and connected */
-
- int index_nr; /* player number (0 to 3) */
- int index_bit; /* player number bit (1 << 0 to 1 << 3) */
- int element_nr; /* element (EL_PLAYER_1 to EL_PLAYER_4) */
- int client_nr; /* network client identifier */
-
- byte action; /* action from local input device */
- byte effective_action; /* action acknowledged from network server
- or summarized over all configured input
- devices when in single player mode */
- byte programmed_action; /* action forced by game itself (like moving
- through doors); overrides other actions */
-
- int jx, jy, last_jx, last_jy;
- int MovDir, MovPos, GfxDir, GfxPos;
- int Frame, StepFrame;
-
- int GfxAction;
-
- boolean use_murphy;
- int artwork_element;
-
- boolean block_last_field;
- int block_delay_adjustment; /* needed for different engine versions */
-
- boolean can_fall_into_acid;
-
- boolean LevelSolved, GameOver;
-
- int last_move_dir;
-
- boolean is_waiting;
- boolean is_moving;
- boolean is_auto_moving;
- boolean is_digging;
- boolean is_snapping;
- boolean is_collecting;
- boolean is_pushing;
- boolean is_switching;
- boolean is_dropping;
- boolean is_dropping_pressed;
-
- boolean is_bored;
- boolean is_sleeping;
-
- boolean cannot_move;
-
- int frame_counter_bored;
- int frame_counter_sleeping;
-
- int anim_delay_counter;
- int post_delay_counter;
-
- int dir_waiting;
- int action_waiting, last_action_waiting;
- int special_action_bored;
- int special_action_sleeping;
-
- int num_special_action_bored;
- int num_special_action_sleeping;
-
- int switch_x, switch_y;
- int drop_x, drop_y;
-
- int show_envelope;
-
- int move_delay;
- int move_delay_value;
- int move_delay_value_next;
- int move_delay_reset_counter;
-
- int push_delay;
- int push_delay_value;
-
- unsigned long actual_frame_counter;
-
- int drop_delay;
- int drop_pressed_delay;
-
- int step_counter;
-
- int score;
- int gems_still_needed;
- int sokobanfields_still_needed;
- int lights_still_needed;
- int friends_still_needed;
- int key[MAX_NUM_KEYS];
- int dynabomb_count, dynabomb_size, dynabombs_left, dynabomb_xl;
- int shield_normal_time_left;
- int shield_deadly_time_left;
-
- int inventory_element[MAX_INVENTORY_SIZE];
- int inventory_infinite_element;
- int inventory_size;
-};
-
struct LevelSetInfo
{
int music[MAX_LEVELS];
boolean changed; /* set when level was changed in the editor */
};
-struct TapeInfo
-{
- int file_version; /* file format version the tape is stored with */
- int game_version; /* game release version the tape was created with */
- int engine_version; /* game engine version the tape was recorded with */
-
- char *level_identifier;
- int level_nr;
- unsigned long random_seed;
- unsigned long date;
- unsigned long counter;
- unsigned long length;
- unsigned long length_seconds;
- unsigned int delay_played;
- boolean pause_before_death;
- boolean recording, playing, pausing;
- boolean fast_forward;
- boolean warp_forward;
- boolean deactivate_display;
- boolean auto_play;
- boolean auto_play_level_solved;
- boolean quick_resume;
- boolean single_step;
- boolean changed;
- boolean player_participates[MAX_PLAYERS];
- int num_participating_players;
-
- struct
- {
- byte action[MAX_PLAYERS];
- byte delay;
- } pos[MAX_TAPE_LEN];
-
- boolean no_valid_file; /* set when tape file missing or invalid */
-};
-
-struct GameInfo
-{
- /* values for engine initialization */
- int default_push_delay_fixed;
- int default_push_delay_random;
-
- /* constant within running game */
- int engine_version;
- int emulation;
- int initial_move_delay;
- int initial_move_delay_value;
- int initial_push_delay_value;
-
- /* flags to handle bugs in and changes between different engine versions */
- /* (for the latest engine version, these flags should always be "FALSE") */
- boolean use_change_when_pushing_bug;
- boolean use_block_last_field_bug;
- boolean max_num_changes_per_frame;
- boolean use_reverse_scan_direction;
-
- /* variable within running game */
- int yamyam_content_nr;
- boolean magic_wall_active;
- int magic_wall_time_left;
- int light_time_left;
- int timegate_time_left;
- int belt_dir[4];
- int belt_dir_nr[4];
- int switchgate_pos;
- int wind_direction;
- boolean gravity;
- boolean explosions_delayed;
- boolean envelope_active;
-
-#if 1
- /* values for the new EMC elements */
- int lenses_time_left;
- int magnify_time_left;
- boolean ball_state;
- int ball_content_nr;
-#endif
-
- /* values for player idle animation (no effect on engine) */
- int player_boring_delay_fixed;
- int player_boring_delay_random;
- int player_sleeping_delay_fixed;
- int player_sleeping_delay_random;
-
- /* values for special game initialization control */
- boolean restart_level;
-
- /* values for special game control */
- int centered_player_nr;
- int centered_player_nr_next;
- boolean set_centered_player;
-};
-
struct GlobalInfo
{
char *autoplay_leveldir;
extern struct LevelSetInfo levelset;
extern struct LevelInfo level, level_template;
-extern struct PlayerInfo stored_player[], *local_player;
extern struct HiScore highscore[];
extern struct TapeInfo tape;
-extern struct GameInfo game;
extern struct GlobalInfo global;
extern struct MenuInfo menu;
extern struct DoorInfo door_1, door_2;
recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
+#if 1
+ if (tape.set_centered_player)
+ {
+ game.centered_player_nr_next = tape.centered_player_nr_next;
+ game.set_centered_player = TRUE;
+ }
+#endif
+
#if 1
/* !!! CHECK THIS (tape.pausing is always FALSE here!) !!! */
if (recorded_player_action == NULL && tape.pausing)
for (i = 0; i < MAX_PLAYERS; i++)
tape.player_participates[i] = FALSE;
+
+ tape.centered_player_nr_next = -1;
+ tape.set_centered_player = FALSE;
}
static void TapeRewind()
tape.quick_resume = FALSE;
tape.single_step = FALSE;
+ tape.centered_player_nr_next = -1;
+ tape.set_centered_player = FALSE;
+
InitRND(tape.random_seed);
}
MapTapeEjectButton();
}
-void TapeRecordAction(byte action[MAX_PLAYERS])
+void TapeRecordAction(byte action_raw[MAX_PLAYERS])
{
+ byte action[MAX_PLAYERS];
int i;
if (!tape.recording) /* (record action even when tape is paused) */
return;
}
+ for (i = 0; i < MAX_PLAYERS; i++)
+ action[i] = action_raw[i];
+
+ if (tape.set_centered_player)
+ {
+ for (i = 0; i < MAX_PLAYERS; i++)
+ if (tape.centered_player_nr_next == i ||
+ tape.centered_player_nr_next == -1)
+ action[i] |= SET_FOCUS;
+
+ tape.set_centered_player = FALSE;
+ }
+
if (tape.pos[tape.counter].delay > 0) /* already stored action */
{
boolean changed_events = FALSE;
for (i = 0; i < MAX_PLAYERS; i++)
action[i] = tape.pos[tape.counter].action[i];
+ tape.set_centered_player = FALSE;
+ tape.centered_player_nr_next = -999;
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (action[i] & SET_FOCUS)
+ {
+ tape.set_centered_player = TRUE;
+ tape.centered_player_nr_next =
+ (tape.centered_player_nr_next == -999 ? i : -1);
+ }
+
+ action[i] &= ~SET_FOCUS;
+ }
+
tape.delay_played++;
if (tape.delay_played >= tape.pos[tape.counter].delay)
{
#ifndef TAPE_H
#define TAPE_H
-#include "main.h"
-
/* values for TapeTogglePause() */
#define TAPE_TOGGLE_MANUAL TRUE
#define TAPE_TOGGLE_AUTOMATIC FALSE
+/* values for tape properties */
+#define MAX_TAPE_LEN (1000 * FRAMES_PER_SECOND) /* max.time x fps */
+
/* some positions in the video tape control window */
#define VIDEO_DISPLAY1_XPOS 5
#define VIDEO_DISPLAY1_YPOS 5
#define VIDEO_DISPLAY_SYMBOL_ONLY -2
+struct TapeInfo
+{
+ int file_version; /* file format version the tape is stored with */
+ int game_version; /* game release version the tape was created with */
+ int engine_version; /* game engine version the tape was recorded with */
+
+ char *level_identifier;
+ int level_nr;
+ unsigned long random_seed;
+ unsigned long date;
+ unsigned long counter;
+ unsigned long length;
+ unsigned long length_seconds;
+ unsigned int delay_played;
+ boolean pause_before_death;
+ boolean recording, playing, pausing;
+ boolean fast_forward;
+ boolean warp_forward;
+ boolean deactivate_display;
+ boolean auto_play;
+ boolean auto_play_level_solved;
+ boolean quick_resume;
+ boolean single_step;
+ boolean changed;
+ boolean player_participates[MAX_PLAYERS];
+ int num_participating_players;
+ int centered_player_nr_next;
+ boolean set_centered_player;
+
+ struct
+ {
+ byte action[MAX_PLAYERS];
+ byte delay;
+ } pos[MAX_TAPE_LEN];
+
+ boolean no_valid_file; /* set when tape file missing or invalid */
+};
+
+
void DrawVideoDisplay(unsigned long, unsigned long);
void DrawCompleteVideoDisplay(void);
return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
}
+#if 0
void setCenteredPlayerNr_EM(int centered_player_nr)
{
game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
{
return game.set_centered_player;
}
+#endif
int getNumActivePlayers_EM()
{
#define TOOLS_H
#include "main.h"
+#include "game.h"
/* for SetDrawtoField */
#define DRAW_DIRECT 0