/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "ags/shared/ac/common.h" #include "ags/engine/ac/game_setup.h" #include "ags/engine/ac/draw.h" #include "ags/engine/ac/game_setup.h" #include "ags/shared/ac/game_setup_struct.h" #include "ags/engine/ac/game_state.h" #include "ags/engine/ac/global_game.h" #include "ags/engine/ac/global_screen.h" #include "ags/engine/ac/runtime_defines.h" #include "ags/engine/ac/screen.h" #include "ags/engine/debugging/debug_log.h" #include "ags/engine/main/game_run.h" #include "ags/engine/media/audio/audio.h" #include "ags/engine/platform/base/ags_platform_driver.h" #include "ags/engine/gfx/graphics_driver.h" #include "ags/shared/gfx/bitmap.h" namespace AGS3 { using namespace AGS::Shared; using namespace AGS::Engine; void FlipScreen(int amount) { if ((amount < 0) || (amount > 3)) quit("!FlipScreen: invalid argument (0-3)"); _GP(play).screen_flipped = amount; } void ShakeScreen(int severe) { EndSkippingUntilCharStops(); if (_GP(play).fast_forward) return; severe = data_to_game_coord(severe); // TODO: support shaking room viewport separately // TODO: rely on game speed setting? and/or provide frequency and duration args // TODO: unify blocking and non-blocking shake update _GP(play).shakesc_length = 10; _GP(play).shakesc_delay = 2; _GP(play).shakesc_amount = severe; _GP(play).mouse_cursor_hidden++; // FIXME: we have to sync audio here explicitly, because ShakeScreen // does not call any game update function while it works sync_audio_playback(); if (_G(gfxDriver)->RequiresFullRedrawEachFrame()) { for (int hh = 0; hh < 40; hh++) { _G(loopcounter)++; _G(platform)->Delay(50); render_graphics(); update_polled_stuff(); } } else { // Optimized variant for software render: create game scene once and shake it construct_game_scene(); _G(gfxDriver)->RenderToBackBuffer(); for (int hh = 0; hh < 40; hh++) { _G(platform)->Delay(50); const int yoff = hh % 2 == 0 ? 0 : severe; _GP(play).shake_screen_yoff = yoff; render_to_screen(); update_polled_stuff(); } clear_letterbox_borders(); render_to_screen(); } sync_audio_playback(); _GP(play).mouse_cursor_hidden--; _GP(play).shakesc_length = 0; _GP(play).shakesc_delay = 0; _GP(play).shakesc_amount = 0; } void ShakeScreenBackground(int delay, int amount, int length) { if (delay < 2) quit("!ShakeScreenBackground: invalid delay parameter"); amount = data_to_game_coord(amount); if (amount < _GP(play).shakesc_amount) { // from a bigger to smaller shake, clear up the borders clear_letterbox_borders(); } _GP(play).shakesc_amount = amount; _GP(play).shakesc_delay = delay; _GP(play).shakesc_length = length; } void TintScreen(int red, int grn, int blu) { if ((red < 0) || (grn < 0) || (blu < 0) || (red > 100) || (grn > 100) || (blu > 100)) quit("!TintScreen: RGB values must be 0-100"); invalidate_screen(); if ((red == 0) && (grn == 0) && (blu == 0)) { _GP(play).screen_tint = -1; return; } red = (red * 25) / 10; grn = (grn * 25) / 10; blu = (blu * 25) / 10; _GP(play).screen_tint = red + (grn << 8) + (blu << 16); } void FadeOut(int sppd) { EndSkippingUntilCharStops(); if (_GP(play).fast_forward) { _GP(play).screen_is_faded_out = 1; return; } // FIXME: we have to sync audio here explicitly, because FadeOut // does not call any game update function while it works sync_audio_playback(); fadeout_impl(sppd); sync_audio_playback(); // Older engines did not mark the screen as "faded out" specifically for // the 8-bit games, for unknown reasons. There's at least one game where // this was accidentally useful, as it did not run FadeIn after FadeOut. if ((_G(loaded_game_file_version) < kGameVersion_361) && _GP(game).color_depth == 1) { _GP(play).screen_is_faded_out = 0; } } void fadeout_impl(int spdd) { if (_GP(play).screen_is_faded_out == 0) { _G(gfxDriver)->FadeOut(spdd, _GP(play).fade_to_red, _GP(play).fade_to_green, _GP(play).fade_to_blue, RENDER_SHOT_SKIP_ON_FADE); _GP(play).screen_is_faded_out = 1; } } void SetScreenTransition(int newtrans) { if ((newtrans < 0) || (newtrans > FADE_LAST)) quit("!SetScreenTransition: invalid transition type"); _GP(play).fade_effect = newtrans; debug_script_log("Screen transition changed"); } void SetNextScreenTransition(int newtrans) { if ((newtrans < 0) || (newtrans > FADE_LAST)) quit("!SetNextScreenTransition: invalid transition type"); _GP(play).next_screen_transition = newtrans; debug_script_log("SetNextScreenTransition engaged"); } void SetFadeColor(int red, int green, int blue) { if ((red < 0) || (red > 255) || (green < 0) || (green > 255) || (blue < 0) || (blue > 255)) quit("!SetFadeColor: Red, Green and Blue must be 0-255"); _GP(play).fade_to_red = red; _GP(play).fade_to_green = green; _GP(play).fade_to_blue = blue; } void FadeIn(int sppd) { EndSkippingUntilCharStops(); if (_GP(play).fast_forward) { _GP(play).screen_is_faded_out = 0; return; } // Update drawables, prepare them for the transition-in // in case this is called after the game state change but before any update was run SyncDrawablesState(); // FIXME: we have to sync audio here explicitly, because FadeIn // does not call any game update function while it works sync_audio_playback(); fadein_impl(_G(palette), sppd); sync_audio_playback(); } } // namespace AGS3