+2006-02-06
+ * improved screen redraw for EMC graphics engine (faster and smoother)
+ * when not scrolling, do not redraw the whole playfield if not needed
+
+2006-02-03
+ * added multi-player mode for EMC game engine (with up to four players)
+
2006-01-28
* added android (can clone elements) from EMC engine to R'n'D engine
-#define COMPILE_DATE_STRING "[2006-02-03 19:01]"
+#define COMPILE_DATE_STRING "[2006-02-07 01:20]"
};
struct LevelInfo_EM *level_em = level->native_em_level;
struct LEVEL *lev = level_em->lev;
- struct PLAYER *ply1 = level_em->ply1;
- struct PLAYER *ply2 = level_em->ply2;
+ struct PLAYER **ply = level_em->ply;
int i, j, x, y;
+#if 0
+ printf("::: A\n");
+ for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+ for (j = 0; j < 8; j++)
+ printf("::: ball %d, %d: %d\n", i, j,
+ level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
lev->width = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
map_element_RND_to_EM(level->
ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#if 0
+ for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+ for (j = 0; j < 8; j++)
+ printf("::: ball %d, %d: %d\n", i, j,
+ level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
map_android_clone_elements_RND_to_EM(level);
#if 0
level_em->cave[x + 1][y + 1] = new_element;
}
+#if 1
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ ply[i]->x_initial = 0;
+ ply[i]->y_initial = 0;
+ }
+
+#else
+
ply1->x_initial = 0;
ply1->y_initial = 0;
ply2->x_initial = 0;
ply2->y_initial = 0;
+#endif
+
/* initialize player positions and delete players from the playfield */
for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
{
+
+#if 1
+
+ if (ELEM_IS_PLAYER(level->field[x][y]))
+ {
+ int player_nr = GET_PLAYER_NR(level->field[x][y]);
+
+ ply[player_nr]->x_initial = x + 1;
+ ply[player_nr]->y_initial = y + 1;
+
+ level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
+ }
+
+#else
+
#if 1
/* !!! CURRENTLY ONLY SUPPORT FOR ONE PLAYER !!! */
if (ELEM_IS_PLAYER(level->field[x][y]))
level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
}
#endif
+
+#endif
+
}
}
};
struct LevelInfo_EM *level_em = level->native_em_level;
struct LEVEL *lev = level_em->lev;
- struct PLAYER *ply1 = level_em->ply1;
- struct PLAYER *ply2 = level_em->ply2;
+ struct PLAYER **ply = level_em->ply;
int i, j, x, y;
level->fieldx = MIN(lev->width, MAX_LEV_FIELDX);
level->wind_direction_initial =
map_direction_EM_to_RND(lev->wind_direction_initial);
+#if 0
+ printf("::: foo\n");
+ for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+ for (j = 0; j < 8; j++)
+ printf("::: ball %d, %d: %d\n", i, j,
+ level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
for (j = 0; j < 8; j++)
level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
map_element_EM_to_RND(lev->ball_array[i][j]);
+#if 0
+ printf("::: bar\n");
+ for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+ for (j = 0; j < 8; j++)
+ printf("::: ball %d, %d: %d\n", i, j,
+ level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
map_android_clone_elements_EM_to_RND(level);
#if 0
level->field[x][y] = new_element;
}
+#if 0
+ printf("::: bar 0\n");
+ for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+ for (j = 0; j < 8; j++)
+ printf("::: ball %d, %d: %d\n", i, j,
+ level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
+#if 1
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ /* in case of all players set to the same field, use the first player */
+ int nr = MAX_PLAYERS - i - 1;
+ int jx = ply[nr]->x_initial - 1;
+ int jy = ply[nr]->y_initial - 1;
+
+#if 0
+ printf("::: player %d: %d, %d\n", nr, jx, jy);
+#endif
+
+ if (jx != -1 && jy != -1)
+ level->field[jx][jy] = EL_PLAYER_1 + nr;
+ }
+
+#else
+
/* in case of both players set to the same field, use the first player */
level->field[ply2->x_initial - 1][ply2->y_initial - 1] = EL_PLAYER_2;
level->field[ply1->x_initial - 1][ply1->y_initial - 1] = EL_PLAYER_1;
+#endif
+
#if 0
printf("::: native Emerald Mine file version: %d\n", level_em->file_version);
#endif
+
+#if 0
+ printf("::: bar 2\n");
+ for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+ for (j = 0; j < 8; j++)
+ printf("::: ball %d, %d: %d\n", i, j,
+ level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
}
static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
{
+
+#if 0
+ {
+ static int ball_xy[8][2] =
+ {
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 0 },
+ { 0, 1 },
+ { 2, 1 },
+ { 0, 2 },
+ { 1, 2 },
+ { 2, 2 },
+ };
+ int i, j;
+
+ printf("::: A6\n");
+ for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+ for (j = 0; j < 8; j++)
+ printf("::: ball %d, %d: %d\n", i, j,
+ level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+ }
+#endif
+
if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
CopyNativeLevel_EM_to_RND(level);
}
#endif
static void HandleElementChange(int, int, int);
+static void ExecuteCustomElementAction(int, int, int, int);
+static boolean ChangeElement(int, int, int, int);
static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int);
#define CheckTriggeredElementChange(x, y, e, ev) \
static void ResetGfxAnimation(int x, int y)
{
+#if 0
+ int element, graphic;
+#endif
+
GfxFrame[x][y] = 0;
GfxAction[x][y] = ACTION_DEFAULT;
GfxDir[x][y] = MovDir[x][y];
+
+#if 0
+ element = Feld[x][y];
+ graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (graphic_info[graphic].anim_global_sync)
+ GfxFrame[x][y] = FrameCounter;
+ else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+ GfxFrame[x][y] = CustomValue[x][y];
+ else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+ GfxFrame[x][y] = element_info[element].collect_score;
+#endif
}
void InitMovingField(int x, int y, int direction)
{
int element = Feld[x][y];
+#if 0
+ int graphic;
+#endif
int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
int newx = x + dx;
GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ?
ACTION_FALLING : ACTION_MOVING);
+#if 0
+ graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (graphic_info[graphic].anim_global_sync)
+ GfxFrame[x][y] = FrameCounter;
+ else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+ GfxFrame[x][y] = CustomValue[x][y];
+ else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+ GfxFrame[x][y] = element_info[element].collect_score;
+#endif
+
/* this is needed for CEs with property "can move" / "not moving" */
if (getElementMoveStepsize(x, y) != 0) /* moving or being moved */
static void TurnRound(int x, int y)
{
int direction = MovDir[x][y];
+#if 1
+ int element, graphic;
+#endif
TurnRoundExt(x, y);
if (MovDelay[x][y])
GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_TO_BIT(direction);
+
+#if 1
+ element = Feld[x][y];
+ graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (graphic_info[graphic].anim_global_sync)
+ GfxFrame[x][y] = FrameCounter;
+ else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+ GfxFrame[x][y] = CustomValue[x][y];
+ else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+ GfxFrame[x][y] = element_info[element].collect_score;
+#endif
}
static boolean JustBeingPushed(int x, int y)
TestIfElementTouchesCustomElement(x, y); /* empty or new element */
+#if 0
+ if (ChangePage[newx][newy] != -1) /* delayed change */
+ {
+ int page = ChangePage[newx][newy];
+ struct ElementChangeInfo *change = &ei->change_page[page];
+
+ ChangePage[newx][newy] = -1;
+
+ if (change->can_change)
+ {
+ if (ChangeElement(newx, newy, element, page))
+ {
+ if (change->post_change_function)
+ change->post_change_function(newx, newy);
+ }
+ }
+
+ if (change->has_action)
+ ExecuteCustomElementAction(newx, newy, element, page);
+ }
+#endif
+
TestIfElementHitsCustomElement(newx, newy, direction);
TestIfPlayerTouchesCustomElement(newx, newy);
TestIfElementTouchesCustomElement(newx, newy);
CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO);
CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X);
+
+#if 0
+ printf("::: RESULT: %d, %d\n", Feld[x][y], ChangePage[x][y]);
+#endif
}
#endif
element = Feld[x][y];
}
- if (Feld[x][y] != element) /* check if element has already changed */
+#if 0
+ /* check if element has already changed */
+ if (Feld[x][y] != element)
return FALSE;
+#else
+ /* check if element has already changed or is about to change after moving */
+ if ((game.engine_version < VERSION_IDENT(3,2,0,7) &&
+ Feld[x][y] != element) ||
+
+ (game.engine_version >= VERSION_IDENT(3,2,0,7) &&
+ (ChangeCount[x][y] >= game.max_num_changes_per_frame ||
+ ChangePage[x][y] != -1)))
+ return FALSE;
+#endif
for (p = 0; p < element_info[element].num_change_pages; p++)
{
native_em_level.file_version = FILE_VERSION_EM_ACTUAL;
native_em_level.lev = &lev;
- native_em_level.ply1 = &ply1;
- native_em_level.ply2 = &ply2;
+ for (i = 0; i < MAX_PLAYERS; i++)
+ native_em_level.ply[i] = &ply[i];
lev.width = 64;
lev.height = 32;
- ply1.x_initial = 0;
- ply1.y_initial = 0;
-
- ply2.x_initial = 0;
- ply2.y_initial = 0;
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ ply[i].x_initial = 0;
+ ply[i].y_initial = 0;
+ }
lev.lenses_cnt_initial = 0;
lev.magnify_cnt_initial = 0;
for (i = 0; i < TILE_MAX; i++)
lev.android_array[i] = Xblank;
- lev.home_initial = 2; /* initial number of players in this level */
+#if 1
+ /* initial number of players in this level */
+ lev.home_initial = 0;
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ ply[i].exists = 0;
+ ply[i].alive_initial = FALSE;
+ }
+#else
+ /* initial number of players in this level */
+ lev.home_initial = (setup.team_mode ? 2 : 1);
- ply1.alive_initial = (lev.home_initial >= 1);
- ply2.alive_initial = (lev.home_initial >= 2);
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ ply[i].exists = 0;
+ ply[i].alive_initial = (lev.home_initial > i ? TRUE : FALSE);
+ }
+#endif
}
lev.required_initial = src[0x82F];
- temp = src[0x830] << 8 | src[0x831];
- ply1.x_initial = (temp & 63) + 1;
- ply1.y_initial = (temp >> 6 & 31) + 1;
- temp = src[0x832] << 8 | src[0x833];
- ply2.x_initial = (temp & 63) + 1;
- ply2.y_initial = (temp >> 6 & 31) + 1;
+ for (i = 0; i < 2; i++)
+ {
+ temp = src[0x830 + i * 2] << 8 | src[0x831 + i * 2];
+ ply[i].x_initial = (temp & 63) + 1;
+ ply[i].y_initial = (temp >> 6 & 31) + 1;
+ }
temp = (src[0x834] << 8 | src[0x835]) * 28;
if (temp > 9999)
native_em_level.cave[x + 1][y + 1] = remap_emerald[src[temp++]];
/* at last, set the two players at their positions in the playfield */
- if (ply1.alive_initial)
- native_em_level.cave[ply1.x_initial][ply1.y_initial] = Zplayer;
- if (ply2.alive_initial)
- native_em_level.cave[ply2.x_initial][ply2.y_initial] = Zplayer;
+ /* (native EM[C] levels always have exactly two players in a level) */
+#if 1
+ for (i = 0; i < 2; i++)
+ native_em_level.cave[ply[i].x_initial][ply[i].y_initial] = Zplayer;
+#else
+ for (i = 0; i < 2; i++)
+ if (ply[i].alive_initial)
+ native_em_level.cave[ply[i].x_initial][ply[i].y_initial] = Zplayer;
+#endif
native_em_level.file_version = file_version;
}
void prepare_em_level(void)
{
- unsigned int x, y;
+ unsigned int i, x, y;
+ int players_left;
/* reset all runtime variables to their initial values */
lev.wonderwall_state = lev.wonderwall_state_initial;
lev.wonderwall_time = lev.wonderwall_time_initial;
+ lev.killed_out_of_time = FALSE;
+
+ /* determine number of players in this level */
+ lev.home_initial = 0;
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ ply[i].exists = 0;
+ ply[i].alive_initial = FALSE;
+
+ if (ply[i].x_initial > 0 && ply[i].y_initial > 0)
+ {
+ ply[i].exists = 1;
+
+ lev.home_initial++;
+ }
+ }
+
+ if (!setup.team_mode)
+ lev.home_initial = MIN(lev.home_initial, 1);
+
lev.home = lev.home_initial;
+ players_left = lev.home_initial;
- lev.killed_out_of_time = FALSE;
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (ply[i].exists)
+ {
+ if (players_left)
+ {
+ ply[i].alive_initial = TRUE;
+ players_left--;
+ }
+ else
+ {
+ native_em_level.cave[ply[i].x_initial][ply[i].y_initial] = Xblank;
+ }
+ }
+ }
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ ply[i].num = i;
+ ply[i].alive = ply[i].alive_initial;
+ ply[i].dynamite = 0;
+ ply[i].dynamite_cnt = 0;
+ ply[i].keys = 0;
+ ply[i].anim = 0;
+ ply[i].oldx = ply[i].x = ply[i].x_initial;
+ ply[i].oldy = ply[i].y = ply[i].y_initial;
+ ply[i].last_move_dir = MV_NONE;
+ ply[i].joy_n = ply[i].joy_e = ply[i].joy_s = ply[i].joy_w = 0;
+ ply[i].joy_snap = ply[i].joy_drop = 0;
+ ply[i].joy_stick = ply[i].joy_spin = 0;
- ply1.num = 0;
- ply1.alive = ply1.alive_initial;
- ply1.dynamite = 0;
- ply1.dynamite_cnt = 0;
- ply1.keys = 0;
- ply1.anim = 0;
- ply1.oldx = ply1.x = ply1.x_initial;
- ply1.oldy = ply1.y = ply1.y_initial;
- ply1.last_move_dir = MV_NONE;
- ply1.joy_n = ply1.joy_e = ply1.joy_s = ply1.joy_w = 0;
- ply1.joy_snap = ply1.joy_drop = 0;
- ply1.joy_stick = ply1.joy_spin = 0;
-
- ply2.num = 1;
- ply2.alive = ply2.alive_initial;
- ply2.dynamite = 0;
- ply2.dynamite_cnt = 0;
- ply2.keys = 0;
- ply2.anim = 0;
- ply2.oldx = ply2.x = ply2.x_initial;
- ply2.oldy = ply2.y = ply2.y_initial;
- ply2.last_move_dir = MV_NONE;
- ply2.joy_n = ply2.joy_e = ply2.joy_s = ply2.joy_w = 0;
- ply2.joy_snap = ply1.joy_drop = 0;
- ply2.joy_stick = ply2.joy_spin = 0;
+#if 0
+ printf("player %d: x/y == %d/%d, alive == %d\n",
+ i, ply[i].x_initial, ply[i].y_initial, ply[i].alive);
+#endif
+ }
}
extern struct GlobalInfo_EM global_em_info;
extern struct LevelInfo_EM native_em_level;
extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8];
-extern struct GraphicInfo_EM graphic_info_em_player[2][SPR_MAX][8];
+extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8];
extern void em_open_all();
extern void em_close_all();
void close_all(void);
#if 1
-void readjoy(byte, int);
+void readjoy(byte, struct PLAYER *);
#else
void readjoy(byte);
#endif
static unsigned int screentiles[MAX_BUF_YSIZE][MAX_BUF_XSIZE];
static unsigned int crumbled_state[MAX_BUF_YSIZE][MAX_BUF_XSIZE];
+static boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
+
/* copy the entire screen to the window at the scroll position
*
void blitscreen(void)
{
+#if 1
+
+ static boolean scrolling_last = FALSE;
+ unsigned int left = screen_x / TILEX;
+ unsigned int top = screen_y / TILEY;
+ boolean scrolling = (screen_x % TILEX != 0 || screen_y % TILEY != 0);
+ int x, y;
+
+ SyncDisplay();
+
+ if (redraw_tiles > REDRAWTILES_THRESHOLD || scrolling || scrolling_last)
+ {
+ /* blit all (up to four) parts of the scroll buffer to the backbuffer */
+ BlitScreenToBitmap_EM(backbuffer);
+
+ /* blit the completely updated backbuffer to the window (in one blit) */
+ BlitBitmap(backbuffer, window, SX, SY, SXSIZE, SYSIZE, SX, SY);
+ }
+ else
+ {
+ for (x = 0; x < SCR_FIELDX; x++)
+ {
+ for (y = 0; y < SCR_FIELDY; y++)
+ {
+ int xx = (left + x) % MAX_BUF_XSIZE;
+ int yy = (top + y) % MAX_BUF_YSIZE;
+
+ if (redraw[xx][yy])
+ BlitBitmap(screenBitmap, window,
+ xx * TILEX, yy * TILEY, TILEX, TILEY,
+ SX + x * TILEX, SY + y * TILEY);
+ }
+ }
+ }
+
+ for (x = 0; x < MAX_BUF_XSIZE; x++)
+ for (y = 0; y < MAX_BUF_YSIZE; y++)
+ redraw[x][y] = FALSE;
+ redraw_tiles = 0;
+
+ scrolling_last = scrolling;
+
+#else
+
+ /* blit all (up to four) parts of the scroll buffer to the window */
BlitScreenToBitmap_EM(window);
+
+#endif
}
static void DrawLevelField_EM(int x, int y, int sx, int sy,
{
unsigned int x, y, i;
unsigned int left = screen_x / TILEX;
- unsigned int top = screen_y / TILEY;
+ unsigned int top = screen_y / TILEY;
static int xy[4][2] =
{
{ 0, -1 },
screentiles[sy][sx] = obj;
crumbled_state[sy][sx] = crm;
+
+ redraw[sx][sy] = TRUE;
+ redraw_tiles++;
}
}
}
void game_initscreen(void)
{
unsigned int x,y;
+ int dynamite_state = ply[0].dynamite; /* !!! ONLY PLAYER 1 !!! */
+ int all_keys_state = ply[0].keys | ply[1].keys | ply[2].keys | ply[3].keys;
frame = 6;
screen_x = 0;
}
#if 1
- DrawAllGameValues(lev.required, ply1.dynamite, lev.score,
- lev.time, ply1.keys | ply2.keys);
+ DrawAllGameValues(lev.required, dynamite_state, lev.score,
+ lev.time, all_keys_state);
#else
DrawAllGameValues(lev.required, ply1.dynamite, lev.score,
DISPLAY_TIME(lev.time + 4), ply1.keys | ply2.keys);
void RedrawPlayfield_EM()
{
- unsigned int x,y;
+ unsigned int i, x, y;
- x = (frame * ply1.oldx + (8 - frame) * ply1.x) * TILEX / 8
+ /* !!! FIX THIS (CENTERED TO PLAYER 1) !!! */
+ x = (frame * ply[0].oldx + (8 - frame) * ply[0].x) * TILEX / 8
+ ((SCR_FIELDX - 1) * TILEX) / 2;
- y = (frame * ply1.oldy + (8 - frame) * ply1.y) * TILEY / 8
+ y = (frame * ply[0].oldy + (8 - frame) * ply[0].y) * TILEY / 8
+ ((SCR_FIELDY - 1) * TILEY) / 2;
if (x > lev.width * TILEX)
screen_y = y - (SCR_FIELDY - 1) * TILEY;
animscreen();
- blitplayer(&ply1);
- blitplayer(&ply2);
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ blitplayer(&ply[i]);
+
blitscreen();
FlushDisplay();
void DrawGameDoorValues_EM()
{
+ int dynamite_state = ply[0].dynamite; /* !!! ONLY PLAYER 1 !!! */
+ int all_keys_state = ply[0].keys | ply[1].keys | ply[2].keys | ply[3].keys;
+
#if 1
- DrawAllGameValues(lev.required, ply1.dynamite, lev.score,
- lev.time, ply1.keys | ply2.keys);
+ DrawAllGameValues(lev.required, dynamite_state, lev.score,
+ lev.time, all_keys_state);
#else
DrawAllGameValues(lev.required, ply1.dynamite, lev.score,
DISPLAY_TIME(lev.time), ply1.keys | ply2.keys);
unsigned long RandomEM;
-struct PLAYER ply1;
-struct PLAYER ply2;
struct LEVEL lev;
+struct PLAYER ply[MAX_PLAYERS];
unsigned short **Boom;
unsigned short **Cave;
frame = (frame - 1) & 7;
- for (i = 0; i < 2; i++)
- readjoy(action[i], i);
+ for (i = 0; i < MAX_PLAYERS; i++)
+ readjoy(action[i], &ply[i]);
UpdateEngineValues(screen_x / TILEX, screen_y / TILEY);
#if 1
-void readjoy(byte action, int player_nr)
+void readjoy(byte action, struct PLAYER *ply)
{
unsigned int north = 0, east = 0, south = 0, west = 0;
unsigned int snap = 0, drop = 0;
if (action & JOY_BUTTON_2)
drop = 1;
- if (player_nr == 0)
- {
- ply1.joy_snap = snap;
- ply1.joy_drop = drop;
- if (ply1.joy_stick || (north | east | south | west))
- {
- ply1.joy_n = north;
- ply1.joy_e = east;
- ply1.joy_s = south;
- ply1.joy_w = west;
- }
- }
- else
+ ply->joy_snap = snap;
+ ply->joy_drop = drop;
+
+ if (ply->joy_stick || (north | east | south | west))
{
- ply2.joy_snap = snap;
- ply2.joy_drop = drop;
- if (ply2.joy_stick || (north | east | south | west))
- {
- ply2.joy_n = north;
- ply2.joy_e = east;
- ply2.joy_s = south;
- ply2.joy_w = west;
- }
+ ply->joy_n = north;
+ ply->joy_e = east;
+ ply->joy_s = south;
+ ply->joy_w = west;
}
}
#define WIDTH EM_MAX_CAVE_WIDTH
#define HEIGHT EM_MAX_CAVE_HEIGHT
-#if 0
-
-struct LEVEL
-{
- unsigned int home; /* number of players that have to go home */
- /* 0 == all players home */
-
- unsigned int width; /* world width */
- unsigned int height; /* world height */
- unsigned int time; /* time remaining */
- unsigned int required; /* emeralds needed */
- unsigned int score; /* score */
-
- /* fill in all below /every/ time you read a level */
- unsigned int alien_score; /* alien popped by stone/spring score */
- unsigned int amoeba_time; /* amoeba speed */
- unsigned int android_move_cnt; /* android move time counter */
- unsigned int android_move_time; /* android move reset time */
- unsigned int android_clone_cnt; /* android clone time counter */
- unsigned int android_clone_time; /* android clone reset time */
- unsigned int ball_cnt; /* ball time counter */
- unsigned int ball_pos; /* ball array pos counter */
- unsigned int ball_random; /* ball is random flag */
- unsigned int ball_state; /* ball currently on flag */
- unsigned int ball_time; /* ball reset time */
- unsigned int bug_score; /* bug popped by stone/spring score */
- unsigned int diamond_score; /* diamond collect score */
- unsigned int dynamite_score; /* dynamite collect scoer*/
- unsigned int eater_pos; /* eater array pos */
- unsigned int eater_score; /* eater popped by stone/spring score */
- unsigned int emerald_score; /* emerald collect score */
- unsigned int exit_score; /* exit score */
- unsigned int key_score; /* key collect score */
- unsigned int lenses_cnt; /* lenses time counter */
- unsigned int lenses_score; /* lenses collect score */
- unsigned int lenses_time; /* lenses reset time */
- unsigned int magnify_cnt; /* magnify time counter */
- unsigned int magnify_score; /* magnify collect score */
- unsigned int magnify_time; /* magnify reset time */
- unsigned int nut_score; /* nut crack score */
- unsigned int shine_cnt; /* shine counter for emerald/diamond */
- unsigned int slurp_score; /* slurp alien score */
- unsigned int tank_score; /* tank popped by stone/spring */
- unsigned int wheel_cnt; /* wheel time counter */
- unsigned int wheel_x; /* wheel x pos */
- unsigned int wheel_y; /* wheel y pos */
- unsigned int wheel_time; /* wheel reset time */
- unsigned int wind_cnt; /* wind time counter */
- unsigned int wind_direction; /* wind direction */
- unsigned int wind_time; /* wind reset time */
- unsigned int wonderwall_state; /* wonderwall currently on flag */
- unsigned int wonderwall_time; /* wonderwall time */
- unsigned short eater_array[8][9]; /* eater data */
- unsigned short ball_array[8][8]; /* ball data */
- unsigned short android_array[TILE_MAX]; /* android clone table */
-};
-
-struct PLAYER
-{
- unsigned int num;
- unsigned int alive;
- unsigned int dynamite;
- unsigned int dynamite_cnt;
- unsigned int keys;
- unsigned int anim;
- unsigned int x;
- unsigned int y;
- unsigned int oldx;
- unsigned int oldy;
-
- unsigned joy_n:1;
- unsigned joy_e:1;
- unsigned joy_s:1;
- unsigned joy_w:1;
- unsigned joy_snap:1;
- unsigned joy_drop:1;
- unsigned joy_stick:1;
- unsigned joy_spin:1;
-};
-
-#endif
-
extern unsigned long RandomEM;
-extern struct PLAYER ply1;
-extern struct PLAYER ply2;
extern struct LEVEL lev;
+extern struct PLAYER ply[MAX_PLAYERS];
extern struct LevelInfo_EM native_em_level;
extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8];
-extern struct GraphicInfo_EM graphic_info_em_player[2][SPR_MAX][8];
+extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8];
extern unsigned short **Boom;
extern unsigned short **Cave;
struct PLAYER
{
unsigned int num;
+ unsigned int exists;
unsigned int alive_initial;
unsigned int alive;
unsigned short cave[EM_MAX_CAVE_WIDTH][EM_MAX_CAVE_HEIGHT];
struct LEVEL *lev;
- struct PLAYER *ply1, *ply2;
+ struct PLAYER *ply[MAX_PLAYERS];
};
struct GraphicInfo_EM
void synchro_1(void)
{
- /* must test for death and actually kill separately */
+#if 1
+
+ int start_check_nr;
+ int i;
+
+ /* must test for death and actually kill separately */
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ boolean ply_kill = player_killed(&ply[i]);
+
+ if (ply[i].alive && ply_kill)
+ kill_player(&ply[i]);
+ }
+
+#else
+
+ /* must test for death and actually kill separately */
boolean ply1_kill = player_killed(&ply1);
boolean ply2_kill = player_killed(&ply2);
if (ply2.alive && ply2_kill)
kill_player(&ply2);
+#endif
+
#if 0
ply1.alive = 1; /* debugging */
#endif
+#if 1
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ ply[i].oldx = ply[i].x;
+ ply[i].oldy = ply[i].y;
+ ply[i].anim = SPR_still;
+ }
+
+ start_check_nr = (RandomEM & 128 ? 0 : 1) * 2 + (RandomEM & 256 ? 0 : 1);
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ int check_nr = (start_check_nr + i) % MAX_PLAYERS;
+
+ if (ply[check_nr].alive)
+ check_player(&ply[check_nr]);
+ }
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (!ply[i].alive)
+ continue;
+
+ if (Cave[ply[i].oldy][ply[i].oldx] == Zplayer)
+ {
+ Cave[ply[i].oldy][ply[i].oldx] = Xblank;
+ Next[ply[i].oldy][ply[i].oldx] = Xblank;
+ }
+
+ if (Cave[ply[i].y][ply[i].x] == Xblank)
+ {
+ Cave[ply[i].y][ply[i].x] = Zplayer;
+ Next[ply[i].y][ply[i].x] = Zplayer;
+ }
+ }
+
+#else
+
ply1.oldx = ply1.x;
ply1.oldy = ply1.y;
ply1.anim = SPR_still;
Next[ply2.y][ply2.x] = Zplayer;
}
}
+
+#endif
}
static boolean player_killed(struct PLAYER *ply)
register unsigned int x = ply->x;
register unsigned int y = ply->y;
+#if 0
+ printf("::: %d: %d, %d\n", ply->num, x, y);
+#endif
+
if (!ply->alive)
return FALSE;
#define RANDOM (random = random << 31 | random >> 1)
+static void set_nearest_player_xy(int x, int y, int *dx, int *dy)
+{
+ int distance, distance_shortest = EM_MAX_CAVE_WIDTH + EM_MAX_CAVE_HEIGHT;
+ int i;
+
+ /* default values if no players are alive anymore */
+ *dx = 0;
+ *dy = 0;
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (!ply[i].alive)
+ continue;
+
+ distance = ABS(ply[i].x - x) + ABS(ply[i].y - y);
+
+ if (distance < distance_shortest)
+ {
+ *dx = ply[i].x;
+ *dy = ply[i].y;
+
+ distance_shortest = distance;
+ }
+ }
+}
+
void synchro_2(void)
{
register unsigned int x = 0;
Cave[y+1][x+1] == Zplayer)
goto android_still;
+#if 1
+
+ set_nearest_player_xy(x, y, &dx, &dy);
+
+#else
+
if (ply1.alive && ply2.alive)
{
if ((ply1.x > x ? ply1.x - x : x - ply1.x) +
dy = 0;
}
+#endif
+
Next[y][x] = Xblank; /* assume we will move */
temp = ((x < dx) + 1 - (x > dx)) + ((y < dy) + 1 - (y > dy)) * 3;
/* --------------------------------------------------------------------- */
case Xalien:
+
+#if 1
+
+ if (lev.wheel_cnt)
+ {
+ dx = lev.wheel_x;
+ dy = lev.wheel_y;
+ }
+ else
+ {
+ set_nearest_player_xy(x, y, &dx, &dy);
+ }
+
+#else
+
if (lev.wheel_cnt)
{
dx = lev.wheel_x;
dy = 0;
}
+#endif
+
if (RANDOM & 1)
{
if (y > dy)
done:
- if (ply1.alive || ply2.alive)
- lev.score += score; /* only get a score if someone is alive */
+ if (ply[0].alive || ply[1].alive || ply[2].alive || ply[3].alive)
+ lev.score += score; /* only add a score if someone is alive */
RandomEM = random;
struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8];
/* map player number, frames and action to graphic info */
-struct GraphicInfo_EM graphic_info_em_player[2][SPR_MAX][8];
+struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8];
void create_tab(int *invert, unsigned char *array)
{
{
int i, j, k;
- for (i = 0; i < 2; i++)
+ for (i = 0; i < MAX_PLAYERS; i++)
{
for (j = 0; j < SPR_MAX; j++)
{
for (k = 0; k < 8; k++)
{
struct GraphicInfo_EM *g = &graphic_info_em_player[i][j][k];
- int spr = map_spr[i][k][j];
+ int spr = map_spr[i % 2][k][j];
g->bitmap = sprBitmap;
g->src_x = (spr / 8) * TILEX;
{
"key_1",
"key",
- "red key"
+ "key 1"
},
{
"key_2",
"key",
- "yellow key"
+ "key 2"
},
{
"key_3",
"key",
- "green key"
+ "key 3"
},
{
"key_4",
"key",
- "blue key"
+ "key 4"
},
{
"gate_1",
"gate",
- "red door"
+ "door 1"
},
{
"gate_2",
"gate",
- "yellow door"
+ "door 2"
},
{
"gate_3",
"gate",
- "green door"
+ "door 3"
},
{
"gate_4",
"gate",
- "blue door"
+ "door 4"
},
{
"gate_1_gray",
"gate",
- "gray door (opened by red key)"
+ "gray door (opened by key 1)"
},
{
"gate_2_gray",
"gate",
- "gray door (opened by yellow key)"},
+ "gray door (opened by key 2)"
+ },
{
"gate_3_gray",
"gate",
- "gray door (opened by green key)"},
+ "gray door (opened by key 3)"
+ },
{
"gate_4_gray",
"gate",
- "gray door (opened by blue key)"},
+ "gray door (opened by key 4)"
+ },
{
"dynamite",
"dynamite",
{
"player_1",
"player",
- "yellow player"
+ "player 1"
},
{
"player_2",
"player",
- "red player"
+ "player 2"
},
{
"player_3",
"player",
- "green player"
+ "player 3"
},
{
"player_4",
"player",
- "blue player"
+ "player 4"
},
{
"bug.right",
{
"em_gate_1",
"gate",
- "red door (EM style)"
+ "door 1 (EM style)"
},
{
"em_gate_2",
"gate",
- "yellow door (EM style)"
+ "door 2 (EM style)"
},
{
"em_gate_3",
"gate",
- "green door (EM style)"
+ "door 3 (EM style)"
},
{
"em_gate_4",
"gate",
- "blue door (EM style)"
+ "door 4 (EM style)"
},
{
"em_key_2_file_obsolete",
{
"em_gate_1_gray",
"gate",
- "gray door (EM style, red key)"
+ "gray door (EM style, key 1)"
},
{
"em_gate_2_gray",
"gate",
- "gray door (EM style, yellow key)"
+ "gray door (EM style, key 2)"
},
{
"em_gate_3_gray",
"gate",
- "gray door (EM style, green key)"
+ "gray door (EM style, key 3)"
},
{
"em_gate_4_gray",
"gate",
- "gray door (EM style, blue key)"
+ "gray door (EM style, key 4)"
},
{
"unused_254",
{
"conveyor_belt_1_left",
"conveyor_belt",
- "red conveyor belt (left)"
+ "conveyor belt 1 (left)"
},
{
"conveyor_belt_1_middle",
"conveyor_belt",
- "red conveyor belt (middle)"
+ "conveyor belt 1 (middle)"
},
{
"conveyor_belt_1_right",
"conveyor_belt",
- "red conveyor belt (right)"
+ "conveyor belt 1 (right)"
},
{
"conveyor_belt_1_switch_left",
"conveyor_belt_switch",
- "switch for red conveyor belt (left)"
+ "switch for conveyor belt 1 (left)"
},
{
"conveyor_belt_1_switch_middle",
"conveyor_belt_switch",
- "switch for red conveyor belt (middle)"
+ "switch for conveyor belt 1 (middle)"
},
{
"conveyor_belt_1_switch_right",
"conveyor_belt_switch",
- "switch for red conveyor belt (right)"
+ "switch for conveyor belt 1 (right)"
},
{
"conveyor_belt_2_left",
"conveyor_belt",
- "yellow conveyor belt (left)"
+ "conveyor belt 2 (left)"
},
{
"conveyor_belt_2_middle",
"conveyor_belt",
- "yellow conveyor belt (middle)"
+ "conveyor belt 2 (middle)"
},
{
"conveyor_belt_2_right",
"conveyor_belt",
- "yellow conveyor belt (right)"
+ "conveyor belt 2 (right)"
},
{
"conveyor_belt_2_switch_left",
"conveyor_belt_switch",
- "switch for yellow conveyor belt (left)"
+ "switch for conveyor belt 2 (left)"
},
{
"conveyor_belt_2_switch_middle",
"conveyor_belt_switch",
- "switch for yellow conveyor belt (middle)"
+ "switch for conveyor belt 2 (middle)"
},
{
"conveyor_belt_2_switch_right",
"conveyor_belt_switch",
- "switch for yellow conveyor belt (right)"
+ "switch for conveyor belt 2 (right)"
},
{
"conveyor_belt_3_left",
"conveyor_belt",
- "green conveyor belt (left)"
+ "conveyor belt 3 (left)"
},
{
"conveyor_belt_3_middle",
"conveyor_belt",
- "green conveyor belt (middle)"
+ "conveyor belt 3 (middle)"
},
{
"conveyor_belt_3_right",
"conveyor_belt",
- "green conveyor belt (right)"
+ "conveyor belt 3 (right)"
},
{
"conveyor_belt_3_switch_left",
"conveyor_belt_switch",
- "switch for green conveyor belt (left)"
+ "switch for conveyor belt 3 (left)"
},
{
"conveyor_belt_3_switch_middle",
"conveyor_belt_switch",
- "switch for green conveyor belt (middle)"
+ "switch for conveyor belt 3 (middle)"
},
{
"conveyor_belt_3_switch_right",
"conveyor_belt_switch",
- "switch for green conveyor belt (right)"
+ "switch for conveyor belt 3 (right)"
},
{
"conveyor_belt_4_left",
"conveyor_belt",
- "blue conveyor belt (left)"
+ "conveyor belt 4 (left)"
},
{
"conveyor_belt_4_middle",
"conveyor_belt",
- "blue conveyor belt (middle)"
+ "conveyor belt 4 (middle)"
},
{
"conveyor_belt_4_right",
"conveyor_belt",
- "blue conveyor belt (right)"
+ "conveyor belt 4 (right)"
},
{
"conveyor_belt_4_switch_left",
"conveyor_belt_switch",
- "switch for blue conveyor belt (left)"
+ "switch for conveyor belt 4 (left)"
},
{
"conveyor_belt_4_switch_middle",
"conveyor_belt_switch",
- "switch for blue conveyor belt (middle)"
+ "switch for conveyor belt 4 (middle)"
},
{
"conveyor_belt_4_switch_right",
"conveyor_belt_switch",
- "switch for blue conveyor belt (right)"
+ "switch for conveyor belt 4 (right)"
},
{
"landmine",
{
"em_key_1",
"key",
- "red key (EM style)"
+ "key 1 (EM style)"
},
{
"em_key_2",
"key",
- "yellow key (EM style)"
+ "key 2 (EM style)"
},
{
"em_key_3",
"key",
- "green key (EM style)"
+ "key 3 (EM style)"
},
{
"em_key_4",
"key",
- "blue key (EM style)"
+ "key 4 (EM style)"
},
{
"envelope_1",
return;
}
- if (level.native_em_level->ply1->alive == 0 &&
- level.native_em_level->ply2->alive == 0) /* all dead */
+ if (level.native_em_level->ply[0]->alive == 0 &&
+ level.native_em_level->ply[1]->alive == 0 &&
+ level.native_em_level->ply[2]->alive == 0 &&
+ level.native_em_level->ply[3]->alive == 0) /* all dead */
AllPlayersGone = TRUE;
if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
SPR_still, 1,
EL_PLAYER_2, ACTION_DEFAULT, -1,
},
+ {
+ SPR_walk + 0, 2,
+ EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
+ },
+ {
+ SPR_walk + 1, 2,
+ EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
+ },
+ {
+ SPR_walk + 2, 2,
+ EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
+ },
+ {
+ SPR_walk + 3, 2,
+ EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
+ },
+ {
+ SPR_push + 0, 2,
+ EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
+ },
+ {
+ SPR_push + 1, 2,
+ EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
+ },
+ {
+ SPR_push + 2, 2,
+ EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
+ },
+ {
+ SPR_push + 3, 2,
+ EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
+ },
+ {
+ SPR_spray + 0, 2,
+ EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
+ },
+ {
+ SPR_spray + 1, 2,
+ EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
+ },
+ {
+ SPR_spray + 2, 2,
+ EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
+ },
+ {
+ SPR_spray + 3, 2,
+ EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
+ },
+ {
+ SPR_walk + 0, 3,
+ EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
+ },
+ {
+ SPR_walk + 1, 3,
+ EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
+ },
+ {
+ SPR_walk + 2, 3,
+ EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
+ },
+ {
+ SPR_walk + 3, 3,
+ EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
+ },
+ {
+ SPR_push + 0, 3,
+ EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
+ },
+ {
+ SPR_push + 1, 3,
+ EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
+ },
+ {
+ SPR_push + 2, 3,
+ EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
+ },
+ {
+ SPR_push + 3, 3,
+ EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
+ },
+ {
+ SPR_spray + 0, 3,
+ EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
+ },
+ {
+ SPR_spray + 1, 3,
+ EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
+ },
+ {
+ SPR_spray + 2, 3,
+ EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
+ },
+ {
+ SPR_spray + 3, 3,
+ EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
+ },
+ {
+ SPR_still, 2,
+ EL_PLAYER_3, ACTION_DEFAULT, -1,
+ },
+ {
+ SPR_still, 3,
+ EL_PLAYER_4, ACTION_DEFAULT, -1,
+ },
{
-1, -1,
void InitGraphicInfo_EM(void)
{
struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
- struct Mapping_EM_to_RND_player player_mapping[2][SPR_MAX];
+ struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
int i, j, p;
#if DEBUG_EM_GFX
}
/* always start with reliable default values */
- for (p = 0; p < 2; p++)
+ for (p = 0; p < MAX_PLAYERS; p++)
{
for (i = 0; i < SPR_MAX; i++)
{
g_em->height = TILEY - cy * step;
}
+#if 1
+ /* create unique graphic identifier to decide if tile must be redrawn */
+ /* bit 31 - 16 (16 bit): EM style graphic
+ bit 15 - 12 ( 4 bit): EM style frame
+ bit 11 - 6 ( 6 bit): graphic width
+ bit 5 - 0 ( 6 bit): graphic height */
+ g_em->unique_identifier =
+ (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
+#else
/* create unique graphic identifier to decide if tile must be redrawn */
/* bit 31 - 16 (16 bit): EM style element
bit 15 - 12 ( 4 bit): EM style frame
bit 5 - 0 ( 6 bit): graphic height */
g_em->unique_identifier =
(i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
+#endif
+
+#if 0
+ if (effective_element == EL_ROCK)
+ printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
+ effective_action, j, graphic, frame, g_em->unique_identifier);
+#endif
#if DEBUG_EM_GFX
}
}
- for (p = 0; p < 2; p++)
+ for (p = 0; p < MAX_PLAYERS; p++)
{
for (i = 0; i < SPR_MAX; i++)
{