diff --git a/changelog.txt b/changelog.txt index 170a174d..9a414c8b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,5 @@ -11-may-2010 - 10-may-2010 - adelikat - Loadstate updates input display +12-may-2010 - adelikat - Movies now have a "finished" option. If a playback stops the movie isn't cleared from memory, and can be replayed or a state loaded. Similar functionality as DeSmuME and GENS rerecording +11-may-2010 - adelikat - Loadstate updates input display 11-may-2010 - ugetab - Win32 - Added Ram Search hotkeys for the first 6 search types in the list. 10-may-2010 - ugetab - Added gui.getpixel() which gets any gui.pixel() set pixel colors, and possibly other functions. Added emu.getscreenpixel() which gets the RGB and Palette of any pixel on the screen. 08-may-2010 - ugetab - Added savestate.object() which is savestate.create() with intuitive numbering under windows diff --git a/src/drawing.cpp b/src/drawing.cpp index 87da2a1d..c0296ed5 100644 --- a/src/drawing.cpp +++ b/src/drawing.cpp @@ -336,7 +336,7 @@ void FCEU_DrawRecordingStatus(uint8* XBuf) drawstatus(XBuf-ClipSidesOffset,2,28,0); hasPlayRecIcon = true; } - else if(FCEUMOV_Mode(MOVIEMODE_PLAY)) + else if(FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_FINISHED)) { drawstatus(XBuf-ClipSidesOffset,1,28,0); hasPlayRecIcon = true; diff --git a/src/drivers/win/window.cpp b/src/drivers/win/window.cpp index 8a248e04..90963470 100644 --- a/src/drivers/win/window.cpp +++ b/src/drivers/win/window.cpp @@ -1237,14 +1237,14 @@ LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) hfceuxcontext = LoadMenu(fceu_hInstance,"FCEUCONTEXTMENUS"); //If There is a movie loaded in read only - if (GameInfo && FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD) && movie_readonly) + if (GameInfo && FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD|MOVIEMODE_FINISHED) && movie_readonly) { hfceuxcontextsub = GetSubMenu(hfceuxcontext,0); whichContext = 0; // Game+Movie+readonly } //If there is a movie loaded in read+write - else if (GameInfo && FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD) && !movie_readonly) + else if (GameInfo && FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD|MOVIEMODE_FINISHED) && !movie_readonly) { hfceuxcontextsub = GetSubMenu(hfceuxcontext,3); whichContext = 3; // Game+Movie+readwrite @@ -2484,7 +2484,7 @@ void FCEUD_AviRecordTo(void) aviDirectory.append("\\"); //if directory override has no \ then add one //if we are playing a movie, construct the filename from the current movie. - if(FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD)) + if(FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD)) //adelikat: TOOD: Think about this. I think MOVIEMODE_FINISHED shouldn't not be included here. Am I wrong? { tempFilename = GetMfn(); //get movie filename tempFilename.erase(0,1); //remove dot diff --git a/src/fceu.cpp b/src/fceu.cpp index 0c05a940..d61fd73f 100644 --- a/src/fceu.cpp +++ b/src/fceu.cpp @@ -611,7 +611,7 @@ void AutoFire(void) //doesn't get screwed up when loading. if(FCEUMOV_Mode(MOVIEMODE_RECORD | MOVIEMODE_PLAY)) { - rapidAlternator= AutoFirePattern[(AutoFireOffset + FCEUMOV_GetFrame())%AutoFirePatternLength]; + rapidAlternator= AutoFirePattern[(AutoFireOffset + FCEUMOV_GetFrame())%AutoFirePatternLength]; //adelikat: TODO: Think through this, MOVIEMODE_FINISHED should not use movie data for auto-fire? } else { @@ -1032,7 +1032,7 @@ bool FCEU_IsValidUI(EFCEUI ui) case FCEUI_STOPMOVIE: case FCEUI_PLAYFROMBEGINNING: - return FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD); + return (FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD|MOVIEMODE_FINISHED)); case FCEUI_STOPAVI: return FCEUI_AviIsRecording(); @@ -1043,7 +1043,7 @@ bool FCEU_IsValidUI(EFCEUI ui) case FCEUI_RESET: if(!GameInfo) return false; - if(FCEUMOV_Mode(MOVIEMODE_TASEDIT|MOVIEMODE_PLAY)) return false; + if(FCEUMOV_Mode(MOVIEMODE_FINISHED|MOVIEMODE_TASEDIT|MOVIEMODE_PLAY)) return false; break; case FCEUI_POWER: diff --git a/src/lua-engine.cpp b/src/lua-engine.cpp index 3a51f328..4b2cdec8 100644 --- a/src/lua-engine.cpp +++ b/src/lua-engine.cpp @@ -2161,7 +2161,7 @@ static int zapper_read(lua_State *L){ int z = 0; extern void GetMouseData(uint32 (&md)[3]); //adelikat: shouldn't this be ifdef'ed for Win32? int x,y,click; - if (/*FCEUMOV_IsPlaying()*/ FCEUMOV_Mode(MOVIEMODE_PLAY)) + if (FCEUMOV_Mode(MOVIEMODE_PLAY)) { if (!currFrameCounter) z = 0; @@ -2580,10 +2580,12 @@ int emu_emulating(lua_State *L) { // string movie.mode() // -// "record", "playback" or nil +// "record", "playback", "finished", or nil int movie_mode(lua_State *L) { if (FCEUMOV_IsRecording()) lua_pushstring(L, "record"); + else if (FCEUMOV_IsFinished()) + lua_pushstring(L, "finished"); //Note: this comes before plaback since playback checks for finished as well else if (FCEUMOV_IsPlaying()) lua_pushstring(L, "playback"); else diff --git a/src/movie.cpp b/src/movie.cpp index 742d7979..5e690e0a 100644 --- a/src/movie.cpp +++ b/src/movie.cpp @@ -721,7 +721,7 @@ void FCEUI_StopMovie() if(suppressMovieStop) return; - if(movieMode == MOVIEMODE_PLAY) + if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_FINISHED) StopPlayback(); else if(movieMode == MOVIEMODE_RECORD) StopRecording(); @@ -834,7 +834,7 @@ bool FCEUI_LoadMovie(const char *fname, bool _read_only, bool tasedit, int _paus assert(fname); //mbg 6/10/08 - we used to call StopMovie here, but that cleared curMovieFilename and gave us crashes... - if(movieMode == MOVIEMODE_PLAY) + if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_FINISHED) StopPlayback(); else if(movieMode == MOVIEMODE_RECORD) StopRecording(); @@ -978,6 +978,14 @@ void FCEUI_SaveMovie(const char *fname, EMOVIE_FLAG flags, std::wstring author) static int _currCommand = 0; + +// Stop movie playback without closing the movie. +static void FinishPlayback() +{ + FCEU_DispMessage("Movie finished playing."); + movieMode = MOVIEMODE_FINISHED; +} + //the main interaction point between the emulator and the movie system. //either dumps the current joystick state or loads one state from the movie void FCEUMOV_AddInputState() @@ -1009,9 +1017,9 @@ void FCEUMOV_AddInputState() else if(movieMode == MOVIEMODE_PLAY) { //stop when we run out of frames - if(currFrameCounter == currMovieData.records.size()) + if(currFrameCounter == (int)currMovieData.records.size()) { - StopPlayback(); + FinishPlayback(); } else { @@ -1099,6 +1107,8 @@ void FCEU_DrawMovies(uint8 *XBuf) sprintf(counterbuf,"%d/%d",currFrameCounter,currMovieData.records.size()); else if(movieMode == MOVIEMODE_RECORD) sprintf(counterbuf,"%d",currMovieData.records.size()); + else if (movieMode == MOVIEMODE_FINISHED) + sprintf(counterbuf,"%d/%d (finished)",currFrameCounter,currMovieData.records.size()); else sprintf(counterbuf,"%d (no movie)",currFrameCounter); @@ -1127,7 +1137,7 @@ void FCEU_DrawLagCounter(uint8 *XBuf) int FCEUMOV_WriteState(std::ostream* os) { //we are supposed to dump the movie data into the savestate - if(movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY) + if(movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_FINISHED) return currMovieData.dump(os, true); else return 0; } @@ -1151,7 +1161,7 @@ bool FCEUMOV_ReadState(std::istream* is, uint32 size) is->seekg((uint32)curr+size); extern bool FCEU_state_loading_old_format; if(FCEU_state_loading_old_format) { - if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_RECORD) { + if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_FINISHED) { FCEUI_StopMovie(); FCEU_PrintError("You have tried to use an old savestate while playing a movie. This is unsupported (since the old savestate has old-format movie data in it which can't be converted on the fly)"); } @@ -1178,7 +1188,7 @@ bool FCEUMOV_ReadState(std::istream* is, uint32 size) // then, we must discard this movie and just load the savestate - if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_RECORD) + if(movieMode == MOVIEMODE_PLAY || movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_FINISHED) { //handle moviefile mismatch if(tempMovieData.guid != currMovieData.guid) @@ -1203,8 +1213,10 @@ bool FCEUMOV_ReadState(std::istream* is, uint32 size) //if the frame counter is longer than our current movie, then error if(currFrameCounter > (int)currMovieData.records.size()) { - FCEU_PrintError("Savestate is from a frame (%d) after the final frame in the movie (%d). This is not permitted.", currFrameCounter, currMovieData.records.size()-1); - return false; + FinishPlayback(); + //TODO: turn frame counter to red to get attention + //FCEU_PrintError("Savestate is from a frame (%d) after the final frame in the movie (%d). This is not permitted.", currFrameCounter, currMovieData.records.size()-1); + //return false; } movieMode = MOVIEMODE_PLAY; } diff --git a/src/movie.h b/src/movie.h index eb18a9be..6dff0dbb 100644 --- a/src/movie.h +++ b/src/movie.h @@ -58,7 +58,8 @@ enum EMOVIEMODE MOVIEMODE_INACTIVE = 1, MOVIEMODE_RECORD = 2, MOVIEMODE_PLAY = 4, - MOVIEMODE_TASEDIT = 8 + MOVIEMODE_TASEDIT = 8, + MOVIEMODE_FINISHED = 16 }; enum EMOVIECMD @@ -72,8 +73,9 @@ enum EMOVIECMD EMOVIEMODE FCEUMOV_Mode(); bool FCEUMOV_Mode(EMOVIEMODE modemask); bool FCEUMOV_Mode(int modemask); -inline bool FCEUMOV_IsPlaying() { return FCEUMOV_Mode(MOVIEMODE_PLAY); } +inline bool FCEUMOV_IsPlaying() { return (FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_FINISHED)); } inline bool FCEUMOV_IsRecording() { return FCEUMOV_Mode(MOVIEMODE_RECORD); } +inline bool FCEUMOV_IsFinished() { return FCEUMOV_Mode(MOVIEMODE_FINISHED);} bool FCEUMOV_ShouldPause(void); int FCEUMOV_GetFrame(void); diff --git a/src/state.cpp b/src/state.cpp index 675e5cf1..cd9a14c7 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -284,7 +284,7 @@ static bool ReadStateChunks(std::istream* is, int32 totalsize) read_snd=1; break; case 6: - if(FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD)) + if(FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD|MOVIEMODE_FINISHED)) { if(!ReadStateChunk(is,FCEUMOV_STATEINFO,size)) ret=false; } @@ -372,7 +372,7 @@ bool FCEUSS_SaveMS(std::ostream* outstream, int compressionLevel) totalsize+=WriteStateChunk(os,31,FCEU_NEWPPU_STATEINFO); totalsize+=WriteStateChunk(os,4,FCEUCTRL_STATEINFO); totalsize+=WriteStateChunk(os,5,FCEUSND_STATEINFO); - if(FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD)) + if(FCEUMOV_Mode(MOVIEMODE_PLAY|MOVIEMODE_RECORD|MOVIEMODE_FINISHED)) { totalsize+=WriteStateChunk(os,6,FCEUMOV_STATEINFO); @@ -776,7 +776,7 @@ bool FCEUSS_Load(const char *fname) //Update input display if movie is loaded extern uint32 cur_input_display; extern uint8 FCEU_GetJoyJoy(void); - if (FCEUMOV_Mode(MOVIEMODE_RECORD) || FCEUMOV_Mode(MOVIEMODE_PLAY)) //adelikat: just doing GetJoyJoy regardless should work, but I just felt conceptually movies should be relying on movie data. There might be some fringe cases where this is necessary. + if (FCEUMOV_Mode(MOVIEMODE_RECORD|MOVIEMODE_PLAY|MOVIEMODE_FINISHED)) //adelikat: just doing GetJoyJoy regardless should work, but I just felt conceptually movies should be relying on movie data. There might be some fringe cases where this is necessary. memcpy(&cur_input_display,currMovieData.records[currFrameCounter-1].joysticks.data,4); else cur_input_display = FCEU_GetJoyJoy();