static int getLevelFromScreenX_MM(int sx)
{
-#if 0
int level_xsize = level.native_mm_level->fieldx;
int full_xsize = level_xsize * TILESIZE_VAR;
sx -= (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0);
-#endif
int px = sx - SX;
- int lx = px / TILESIZE_VAR;
+ int lx = (px + TILESIZE_VAR) / TILESIZE_VAR - 1;
return lx;
}
static int getLevelFromScreenY_MM(int sy)
{
-#if 0
int level_ysize = level.native_mm_level->fieldy;
int full_ysize = level_ysize * TILESIZE_VAR;
sy -= (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0);
-#endif
int py = sy - SY;
- int ly = py / TILESIZE_VAR;
+ int ly = (py + TILESIZE_VAR) / TILESIZE_VAR - 1;
return ly;
}
draw_border_function);
redraw_mask &= ~fade_mask;
+
+ ClearEventQueue();
}
static void SetScreenStates_BeforeFadingIn()
static int dxsize_last = -1, dysize_last = -1;
static int vx_last = -1, vy_last = -1;
static int vxsize_last = -1, vysize_last = -1;
+static int ex_last = -1, ey_last = -1;
+static int exsize_last = -1, eysize_last = -1;
boolean CheckIfGlobalBorderHasChanged()
{
vxsize_last != VXSIZE || vysize_last != VYSIZE)
return TRUE;
+ // redraw if position or size of editor area has changed
+ if (ex_last != EX || ey_last != EY ||
+ exsize_last != EXSIZE || eysize_last != EYSIZE)
+ return TRUE;
+
return FALSE;
}
redraw_mask = REDRAW_ALL;
}
+#define ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED 0
+
static void RedrawGlobalBorderIfNeeded()
{
+#if ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED
if (game_status == game_status_last)
return;
+#endif
// copy current draw buffer to later copy back areas that have not changed
if (game_status_last != GAME_MODE_TITLE)
BlitBitmap(backbuffer, bitmap_db_store_1, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+#if ONLY_REDRAW_GLOBAL_BORDER_IF_NEEDED
if (CheckIfGlobalBorderRedrawIsNeeded())
+#endif
{
// redraw global screen border (or clear, if defined to be empty)
RedrawGlobalBorderFromBitmap(global_border_bitmap);
+ if (game_status == GAME_MODE_EDITOR)
+ DrawSpecialEditorDoor();
+
// copy previous playfield and door areas, if they are defined on both
// previous and current screen and if they still have the same size
BlitBitmap(bitmap_db_store_1, backbuffer,
dx_last, dy_last, DXSIZE, DYSIZE, DX, DY);
- if (vx_last != -1 && vy_last != -1 &&
- VX != -1 && VY != -1 &&
- vxsize_last == VXSIZE && vysize_last == VYSIZE)
- BlitBitmap(bitmap_db_store_1, backbuffer,
- vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
+ if (game_status != GAME_MODE_EDITOR)
+ {
+ if (vx_last != -1 && vy_last != -1 &&
+ VX != -1 && VY != -1 &&
+ vxsize_last == VXSIZE && vysize_last == VYSIZE)
+ BlitBitmap(bitmap_db_store_1, backbuffer,
+ vx_last, vy_last, VXSIZE, VYSIZE, VX, VY);
+ }
+ else
+ {
+ if (ex_last != -1 && ey_last != -1 &&
+ EX != -1 && EY != -1 &&
+ exsize_last == EXSIZE && eysize_last == EYSIZE)
+ BlitBitmap(bitmap_db_store_1, backbuffer,
+ ex_last, ey_last, EXSIZE, EYSIZE, EX, EY);
+ }
redraw_mask = REDRAW_ALL;
}
vy_last = VY;
vxsize_last = VXSIZE;
vysize_last = VYSIZE;
+ ex_last = EX;
+ ey_last = EY;
+ exsize_last = EXSIZE;
+ eysize_last = EYSIZE;
}
void ClearField()
{
struct GraphicInfo *g = &graphic_info[graphic];
+ // if no graphics defined at all, use fallback graphics
+ if (g->bitmaps == NULL)
+ *g = graphic_info[IMG_CHAR_EXCLAM];
+
// if no in-game graphics defined, always use standard graphic size
if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
tilesize = TILESIZE;
SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
}
+
+ ClearEventQueue();
}
void ShowEnvelope(int envelope_nr)
SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
}
+
+ ClearEventQueue();
}
void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
}
}
+void DrawPreviewPlayers()
+{
+ if (game_status != GAME_MODE_MAIN)
+ return;
+
+ if (!network.enabled && !setup.team_mode)
+ return;
+
+ boolean player_found[MAX_PLAYERS];
+ int num_players = 0;
+ int i, x, y;
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ player_found[i] = FALSE;
+
+ /* check which players can be found in the level (simple approach) */
+ for (x = 0; x < lev_fieldx; x++)
+ {
+ for (y = 0; y < lev_fieldy; y++)
+ {
+ int element = level.field[x][y];
+
+ if (ELEM_IS_PLAYER(element))
+ {
+ int player_nr = GET_PLAYER_NR(element);
+
+ player_nr = MIN(MAX(0, player_nr), MAX_PLAYERS - 1);
+
+ if (!player_found[player_nr])
+ num_players++;
+
+ player_found[player_nr] = TRUE;
+ }
+ }
+ }
+
+ struct TextPosInfo *pos = &menu.main.preview_players;
+ int tile_size = pos->tile_size;
+ int border_size = pos->border_size;
+ int player_xoffset_raw = (pos->vertical ? 0 : tile_size + border_size);
+ int player_yoffset_raw = (pos->vertical ? tile_size + border_size : 0);
+ int player_xoffset = (pos->xoffset != -1 ? pos->xoffset : player_xoffset_raw);
+ int player_yoffset = (pos->yoffset != -1 ? pos->yoffset : player_yoffset_raw);
+ int max_players_width = (MAX_PLAYERS - 1) * player_xoffset + tile_size;
+ int max_players_height = (MAX_PLAYERS - 1) * player_yoffset + tile_size;
+ int all_players_width = (num_players - 1) * player_xoffset + tile_size;
+ int all_players_height = (num_players - 1) * player_yoffset + tile_size;
+ int max_xpos = SX + ALIGNED_XPOS(pos->x, max_players_width, pos->align);
+ int max_ypos = SY + ALIGNED_YPOS(pos->y, max_players_height, pos->valign);
+ int xpos = SX + ALIGNED_XPOS(pos->x, all_players_width, pos->align);
+ int ypos = SY + ALIGNED_YPOS(pos->y, all_players_height, pos->valign);
+
+ /* clear area in which the players will be drawn */
+ ClearRectangleOnBackground(drawto, max_xpos, max_ypos,
+ max_players_width, max_players_height);
+
+ /* only draw players if level is suited for team mode */
+ if (num_players < 2)
+ return;
+
+ /* draw all players that were found in the level */
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (player_found[i])
+ {
+ int graphic = el2img(EL_PLAYER_1 + i);
+
+ DrawSizedGraphicThruMaskExt(drawto, xpos, ypos, graphic, 0, tile_size);
+
+ xpos += player_xoffset;
+ ypos += player_yoffset;
+ }
+ }
+}
+
void DrawPreviewLevelInitial()
{
DrawPreviewLevelExt(TRUE);
+ DrawPreviewPlayers();
}
void DrawPreviewLevelAnimation()
DrawPreviewLevelExt(FALSE);
}
+static void DrawNetworkPlayer(int x, int y, int player_nr, int tile_size,
+ int border_size, int font_nr)
+{
+ int graphic = el2img(EL_PLAYER_1 + player_nr);
+ int font_height = getFontHeight(font_nr);
+ int player_height = MAX(tile_size, font_height);
+ int xoffset_text = tile_size + border_size;
+ int yoffset_text = (player_height - font_height) / 2;
+ int yoffset_graphic = (player_height - tile_size) / 2;
+ char *player_name = getNetworkPlayerName(player_nr + 1);
+
+ DrawSizedGraphicThruMaskExt(drawto, x, y + yoffset_graphic, graphic, 0,
+ tile_size);
+ DrawText(x + xoffset_text, y + yoffset_text, player_name, font_nr);
+}
+
+void DrawNetworkPlayersExt(boolean force)
+{
+ if (game_status != GAME_MODE_MAIN)
+ return;
+
+ if (!network.connected && !force)
+ return;
+
+ int num_players = 0;
+ int i;
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ if (stored_player[i].connected_network)
+ num_players++;
+
+ struct TextPosInfo *pos = &menu.main.network_players;
+ int tile_size = pos->tile_size;
+ int border_size = pos->border_size;
+ int xoffset_text = tile_size + border_size;
+ int font_nr = pos->font;
+ int font_width = getFontWidth(font_nr);
+ int font_height = getFontHeight(font_nr);
+ int player_height = MAX(tile_size, font_height);
+ int player_yoffset = player_height + border_size;
+ int max_players_width = xoffset_text + MAX_PLAYER_NAME_LEN * font_width;
+ int max_players_height = MAX_PLAYERS * player_yoffset - border_size;
+ int all_players_height = num_players * player_yoffset - border_size;
+ int max_xpos = SX + ALIGNED_XPOS(pos->x, max_players_width, pos->align);
+ int max_ypos = SY + ALIGNED_YPOS(pos->y, max_players_height, pos->valign);
+ int ypos = SY + ALIGNED_YPOS(pos->y, all_players_height, pos->valign);
+
+ ClearRectangleOnBackground(drawto, max_xpos, max_ypos,
+ max_players_width, max_players_height);
+
+ /* first draw local network player ... */
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (stored_player[i].connected_network &&
+ stored_player[i].connected_locally)
+ {
+ char *player_name = getNetworkPlayerName(i + 1);
+ int player_width = xoffset_text + getTextWidth(player_name, font_nr);
+ int xpos = SX + ALIGNED_XPOS(pos->x, player_width, pos->align);
+
+ DrawNetworkPlayer(xpos, ypos, i, tile_size, border_size, font_nr);
+
+ ypos += player_yoffset;
+ }
+ }
+
+ /* ... then draw all other network players */
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (stored_player[i].connected_network &&
+ !stored_player[i].connected_locally)
+ {
+ char *player_name = getNetworkPlayerName(i + 1);
+ int player_width = xoffset_text + getTextWidth(player_name, font_nr);
+ int xpos = SX + ALIGNED_XPOS(pos->x, player_width, pos->align);
+
+ DrawNetworkPlayer(xpos, ypos, i, tile_size, border_size, font_nr);
+
+ ypos += player_yoffset;
+ }
+ }
+}
+
+void DrawNetworkPlayers()
+{
+ DrawNetworkPlayersExt(FALSE);
+}
+
+void ClearNetworkPlayers()
+{
+ DrawNetworkPlayersExt(TRUE);
+}
+
inline static void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
int graphic, int sync_frame,
int mask_mode)
break;
case KSYM_Return:
+ case KSYM_y:
#if defined(TARGET_SDL2)
+ case KSYM_Y:
case KSYM_Select:
case KSYM_Menu:
#if defined(KSYM_Rewind)
break;
case KSYM_Escape:
+ case KSYM_n:
#if defined(TARGET_SDL2)
+ case KSYM_N:
case KSYM_Back:
#if defined(KSYM_FastForward)
case KSYM_FastForward: /* for Amazon Fire TV remote */
}
if (req_state & REQ_PLAYER)
- result = 0;
+ {
+ int old_player_nr = setup.network_player_nr;
+
+ if (result != -1)
+ result = old_player_nr + 1;
+
+ switch (key)
+ {
+ case KSYM_space:
+ result = old_player_nr + 1;
+ break;
+
+ case KSYM_Up:
+ case KSYM_1:
+ result = 1;
+ break;
+
+ case KSYM_Right:
+ case KSYM_2:
+ result = 2;
+ break;
+
+ case KSYM_Down:
+ case KSYM_3:
+ result = 3;
+ break;
+
+ case KSYM_Left:
+ case KSYM_4:
+ result = 4;
+ break;
+
+ default:
+ break;
+ }
+ }
break;
}
case SDL_CONTROLLER_BUTTON_A:
case SDL_CONTROLLER_BUTTON_X:
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
+ case SDL_CONTROLLER_BUTTON_LEFTSTICK:
result = 1;
break;
case SDL_CONTROLLER_BUTTON_B:
case SDL_CONTROLLER_BUTTON_Y:
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
+ case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
case SDL_CONTROLLER_BUTTON_BACK:
result = 0;
break;
}
if (req_state & REQ_PLAYER)
- result = 0;
+ {
+ int old_player_nr = setup.network_player_nr;
+
+ if (result != -1)
+ result = old_player_nr + 1;
+
+ switch (event.cbutton.button)
+ {
+ case SDL_CONTROLLER_BUTTON_DPAD_UP:
+ case SDL_CONTROLLER_BUTTON_Y:
+ result = 1;
+ break;
+
+ case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
+ case SDL_CONTROLLER_BUTTON_B:
+ result = 2;
+ break;
+
+ case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
+ case SDL_CONTROLLER_BUTTON_A:
+ result = 3;
+ break;
+
+ case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
+ case SDL_CONTROLLER_BUTTON_X:
+ result = 4;
+ break;
+
+ default:
+ break;
+ }
+ }
break;
else if (joy & JOY_BUTTON_2)
result = 0;
}
+ else if (AnyJoystick())
+ {
+ int joy = AnyJoystick();
+
+ if (req_state & REQ_PLAYER)
+ {
+ if (joy & JOY_UP)
+ result = 1;
+ else if (joy & JOY_RIGHT)
+ result = 2;
+ else if (joy & JOY_DOWN)
+ result = 3;
+ else if (joy & JOY_LEFT)
+ result = 4;
+ }
+ }
if (level_solved)
{
SetMouseCursor(CURSOR_DEFAULT);
-#if defined(NETWORK_AVALIABLE)
/* pause network game while waiting for request to answer */
- if (options.network &&
+ if (network.enabled &&
game_status == GAME_MODE_PLAYING &&
req_state & REQUEST_WAIT_FOR_INPUT)
SendToServer_PausePlaying();
-#endif
old_door_state = GetDoorState();
SetDrawBackgroundMask(REDRAW_FIELD);
}
-#if defined(NETWORK_AVALIABLE)
/* continue network game after request */
- if (options.network &&
+ if (network.enabled &&
game_status == GAME_MODE_PLAYING &&
req_state & REQUEST_WAIT_FOR_INPUT)
SendToServer_ContinuePlaying();
-#endif
/* restore deactivated drawing when quick-loading level tape recording */
if (tape.playing && tape.deactivate_display)
SetMouseCursor(CURSOR_DEFAULT);
-#if defined(NETWORK_AVALIABLE)
/* pause network game while waiting for request to answer */
- if (options.network &&
+ if (network.enabled &&
game_status == GAME_MODE_PLAYING &&
req_state & REQUEST_WAIT_FOR_INPUT)
SendToServer_PausePlaying();
-#endif
/* simulate releasing mouse button over last gadget, if still pressed */
if (button_status)
SetDrawBackgroundMask(REDRAW_FIELD);
}
-#if defined(NETWORK_AVALIABLE)
/* continue network game after request */
- if (options.network &&
+ if (network.enabled &&
game_status == GAME_MODE_PLAYING &&
req_state & REQUEST_WAIT_FOR_INPUT)
SendToServer_ContinuePlaying();
-#endif
/* restore deactivated drawing when quick-loading level tape recording */
if (tape.playing && tape.deactivate_display)
{
/* wait for specified door action post delay */
if (door_state & DOOR_ACTION_1 && door_state & DOOR_ACTION_2)
- Delay(MAX(door_1.post_delay, door_2.post_delay));
+ door_delay_value = MAX(door_1.post_delay, door_2.post_delay);
else if (door_state & DOOR_ACTION_1)
- Delay(door_1.post_delay);
+ door_delay_value = door_1.post_delay;
else if (door_state & DOOR_ACTION_2)
- Delay(door_2.post_delay);
+ door_delay_value = door_2.post_delay;
+
+ while (!DelayReached(&door_delay, door_delay_value))
+ BackToFront();
}
}
DrawMaskedBorder(REDRAW_DOOR_1);
DrawMaskedBorder(REDRAW_DOOR_2);
+ ClearEventQueue();
+
return (door1 | door2);
}
for (i = 0; i < NUM_TOOL_BUTTONS; i++)
{
- struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
+ int graphic = toolbutton_info[i].graphic;
+ struct GraphicInfo *gfx = &graphic_info[graphic];
struct TextPosInfo *pos = toolbutton_info[i].pos;
struct GadgetInfo *gi;
Bitmap *deco_bitmap = None;
int gd_y = gfx->src_y;
int gd_xp = gfx->src_x + gfx->pressed_xoffset;
int gd_yp = gfx->src_y + gfx->pressed_yoffset;
+ int x = pos->x;
+ int y = pos->y;
int id = i;
if (global.use_envelope_request)
+ {
setRequestPosition(&dx, &dy, TRUE);
+ // check if request buttons are outside of envelope and fix, if needed
+ if (x < 0 || x + gfx->width > request.width ||
+ y < 0 || y + gfx->height > request.height)
+ {
+ if (id == TOOL_CTRL_ID_YES)
+ {
+ x = 0;
+ y = request.height - 2 * request.border_size - gfx->height;
+ }
+ else if (id == TOOL_CTRL_ID_NO)
+ {
+ x = request.width - 2 * request.border_size - gfx->width;
+ y = request.height - 2 * request.border_size - gfx->height;
+ }
+ else if (id == TOOL_CTRL_ID_CONFIRM)
+ {
+ x = (request.width - 2 * request.border_size - gfx->width) / 2;
+ y = request.height - 2 * request.border_size - gfx->height;
+ }
+ else if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
+ {
+ int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
+
+ x = (request.width - 2 * request.border_size - gfx->width) / 2;
+ y = request.height - 2 * request.border_size - gfx->height * 2;
+
+ x += (player_nr == 3 ? -1 : player_nr == 1 ? +1 : 0) * gfx->width;
+ y += (player_nr == 0 ? -1 : player_nr == 2 ? +1 : 0) * gfx->height;
+ }
+ }
+ }
+
if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
{
int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
}
gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_IMAGE_ID, graphic,
GDI_INFO_TEXT, toolbutton_info[i].infotext,
- GDI_X, dx + GDI_ACTIVE_POS(pos->x),
- GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
+ GDI_X, dx + x,
+ GDI_Y, dy + y,
GDI_WIDTH, gfx->width,
GDI_HEIGHT, gfx->height,
GDI_TYPE, GD_TYPE_NORMAL_BUTTON,