#=============================================================================== # Native In-Engine Video Playback for Pokemon Essentials v21.1 # Uses MKXP-Z's built-in Graphics.play_movie function # Supports OGV (Ogg Theora) format for true in-engine playback # Curated from Claude Sonnet 4 by Illiterally #=============================================================================== class InGameVideoPlayer def self.find_video_file(filename) # Primary format for MKXP-Z native playback possible_paths = [ "Graphics/Movies/#{filename}", "Graphics/Pictures/#{filename}", "Data/Movies/#{filename}", "Movies/#{filename}", filename ] # Add extensions - prioritize OGV for native playback if !filename.include?(".") # OGV first for native support, then fallbacks extensions = [".ogv", ".mp4", ".avi", ".wmv", ".webm"] extended_paths = [] possible_paths.each do |path| extensions.each { |ext| extended_paths << path + ext } end possible_paths = extended_paths + possible_paths end # Find the first existing file possible_paths.each do |path| return path if FileTest.exist?(path) end return nil end def self.play_video_native(video_path) # MKXP-Z native video playback - plays directly in engine! begin Graphics.play_movie(video_path) return true rescue => e puts "Native video playback failed: #{e.message}" return false end end def self.play_video_with_controls(video_path, skippable = true) # Enhanced native playback with user controls begin if skippable # Create a thread to monitor for skip input skip_thread = Thread.new do loop do Input.update if Input.trigger?(Input::USE) || Input.trigger?(Input::BACK) || Input.trigger?(Input::ACTION) # Note: There's no direct way to stop Graphics.play_movie mid-playback # This is a limitation of the current MKXP-Z implementation break end sleep(0.016) # ~60 FPS check end end end # Play the video natively in the game engine Graphics.play_movie(video_path) # Clean up thread if it was created skip_thread.kill if skip_thread && skip_thread.alive? return true rescue => e puts "Native video playback failed: #{e.message}" skip_thread.kill if skip_thread && skip_thread.alive? return false end end # Fallback external player method (FIXED Win32API syntax) def self.play_video_external(video_path, fullscreen = true) begin # Try to load Win32API for external playback - FIXED SYNTAX shell_execute = Win32API.new('shell32', 'ShellExecuteA', ['L','P','P','P','P','L'], 'L') # Try Windows Media Player first wmp_paths = [ "C:\\Program Files\\Windows Media Player\\wmplayer.exe", "C:\\Program Files (x86)\\Windows Media Player\\wmplayer.exe" ] player_path = wmp_paths.find { |path| File.exist?(path) } if player_path args = "\"#{video_path}\"" args += " /fullscreen" if fullscreen result = shell_execute.call(0, "open", player_path, args, nil, 1) return result > 32 else # Fallback to default association result = shell_execute.call(0, "open", video_path, nil, nil, 1) return result > 32 end rescue => e puts "External video playback failed: #{e.message}" return false end end end # Main interface method - tries native first, then external def pbPlayMovie(filename, options = {}) video_path = InGameVideoPlayer.find_video_file(filename) unless video_path if defined?(pbMessage) pbMessage(_INTL("Video file not found: {1}", filename)) pbMessage("Supported formats: OGV (recommended), MP4, AVI, WMV") pbMessage("Place videos in Graphics/Movies/ folder") end return false end skippable = options[:skippable] != false # Try native MKXP-Z playback first (OGV files) if video_path.end_with?(".ogv") puts "Playing #{filename} with native MKXP-Z engine..." if InGameVideoPlayer.play_video_with_controls(video_path, skippable) return true else puts "Native playback failed, falling back to external player..." end end # Fallback to external player for non-OGV files or if native fails Graphics.freeze begin if InGameVideoPlayer.play_video_external(File.expand_path(video_path), options[:fullscreen] != false) if defined?(pbMessage) pbMessage("Video is playing externally. Press OK when finished.") end return true else if defined?(pbMessage) pbMessage(_INTL("Could not play video: {1}", filename)) pbMessage("Make sure a media player is installed or convert to OGV format.") end return false end ensure Graphics.transition(0) end end # Convenience methods def pbPlayMovieFullscreen(filename) pbPlayMovie(filename, fullscreen: true, skippable: true) end def pbPlayMovieSkippable(filename, skippable = true) pbPlayMovie(filename, skippable: skippable) end # Test and info methods def pbTestVideoSystem puts "=== Pokemon Essentials Video System Test ===" # Check if Graphics.play_movie is available (MKXP-Z native support) has_native = false begin Graphics.method(:play_movie) has_native = true puts "✓ MKXP-Z native video support detected!" puts " For best results, use OGV (Ogg Theora) format" rescue puts "✗ Native video support not available" end # Check video directories dirs = ["Graphics/Movies", "Movies", "Data/Movies", "Graphics/Pictures"] existing_dirs = dirs.select { |dir| Dir.exist?(dir) } if existing_dirs.empty? puts "⚠ No video directories found" puts " Create Graphics/Movies/ folder for your videos" else puts "✓ Video directories: #{existing_dirs.join(', ')}" end # Check for sample videos sample_formats = [".ogv", ".mp4", ".avi", ".wmv"] found_videos = [] existing_dirs.each do |dir| sample_formats.each do |ext| pattern = "#{dir}/*#{ext}" videos = Dir.glob(pattern) found_videos.concat(videos) unless videos.empty? end end if found_videos.empty? puts "⚠ No video files found" else puts "✓ Found videos: #{found_videos.take(3).join(', ')}#{found_videos.length > 3 ? '...' : ''}" end # Display recommendations in game if defined?(pbMessage) if has_native pbMessage("✓ Native in-engine video support available!") pbMessage("Use OGV format for best in-engine playback.") pbMessage("Other formats will play in external window.") else pbMessage("Using external video player mode.") pbMessage("Videos will open in separate window.") end if existing_dirs.empty? pbMessage("Create Graphics/Movies/ folder and place videos there.") end end end def pbVideoFormatInfo info = <<~INFO === Video Format Guide for Pokemon Essentials === IN-ENGINE PLAYBACK (Recommended): • Format: OGV (Ogg Theora) • Resolution: 640x480 or smaller • Frame rate: 30fps or lower • Bitrate: Keep moderate (avoid high bitrates) • Plays directly inside the game window! EXTERNAL PLAYBACK (Fallback): • Formats: MP4, AVI, WMV, WebM • Resolution: Higher quality/resolution OK • Opens in separate media player window CONVERSION TIPS: • Use FFmpeg: ffmpeg -i input.mp4 -c:v libtheora -c:a libvorbis output.ogv • Keep file sizes reasonable for smooth playback • Test with different bitrates if you experience lag INFO puts info pbMessage("Check the console for detailed video format information!") if defined?(pbMessage) end # Example usage: # pbPlayMovieFullscreen("intro.ogv") # Native in-engine playback # pbPlayMovieFullscreen("intro.mp4") # External player fallback # pbTestVideoSystem # Test your setup # pbVideoFormatInfo # Show format guide