3 #include "core/command.hpp"
4 #include "core/controller.hpp"
5 #include "core/dispatch.hpp"
6 #include "core/framebuffer.hpp"
7 #include "core/framerate.hpp"
8 #include "core/inthread.hpp"
10 #include "library/string.hpp"
11 #include "core/mainloop.hpp"
12 #include "core/movie.hpp"
13 #include "core/moviedata.hpp"
14 #include "core/moviefile.hpp"
15 #include "core/memorymanip.hpp"
16 #include "core/memorywatch.hpp"
17 #include "core/rom.hpp"
18 #include "core/rrdata.hpp"
19 #include "core/settings.hpp"
20 #include "core/window.hpp"
21 #include "interface/callbacks.hpp"
22 #include "interface/romtype.hpp"
23 #include "library/framebuffer.hpp"
24 #include "library/pixfmt-lrgb.hpp"
25 #include "library/zip.hpp"
35 #define SPECIAL_FRAME_START 0
36 #define SPECIAL_FRAME_VIDEO 1
37 #define SPECIAL_SAVEPOINT 2
38 #define SPECIAL_NONE 3
40 void update_movie_state();
41 time_t random_seed_value
= 0;
46 setting_var
<setting_var_model_int
<0,999999>> advance_timeout_first(lsnes_vset
, "advance-timeout",
47 "Delays‣First frame advance", 500);
48 setting_var
<setting_var_model_int
<0,999999>> advance_timeout_subframe(lsnes_vset
, "advance-subframe-timeout",
49 "Delays‣Subframe advance", 100);
50 setting_var
<setting_var_model_bool
> pause_on_end(lsnes_vset
, "pause-on-end", "Movie‣Pause on end", false);
51 setting_var
<setting_var_model_int
<0,999>> jukebox_size(lsnes_vset
, "jukebox-size",
52 "Movie‣Number of save slots", 12);
56 ADVANCE_QUIT
, //Quit the emulator.
57 ADVANCE_AUTO
, //Normal (possibly slowed down play).
58 ADVANCE_LOAD
, //Loading a state.
59 ADVANCE_FRAME
, //Frame advance.
60 ADVANCE_SUBFRAME
, //Subframe advance.
61 ADVANCE_SKIPLAG
, //Skip lag (oneshot, reverts to normal).
62 ADVANCE_SKIPLAG_PENDING
, //Activate skip lag mode at next frame.
63 ADVANCE_PAUSE
, //Unconditional pause.
67 threadid_class emulation_thread
;
68 //Flags related to repeating advance.
71 //Emulator advance mode. Detemines pauses at start of frame / subframe, etc..
72 enum advance_mode amode
;
73 //Mode and filename of pending load, one of LOAD_* constants.
75 std::string pending_load
;
76 //Queued saves (all savestates).
77 std::set
<std::string
> queued_saves
;
79 size_t save_jukebox_pointer
;
80 //Special subframe location. One of SPECIAL_* constants.
83 bool last_hires
= false;
84 bool last_interlace
= false;
86 bool do_unsafe_rewind
= false;
87 void* unsafe_rewind_obj
= NULL
;
89 bool stop_at_frame_active
= false;
90 uint64_t stop_at_frame
= 0;
92 enum advance_mode old_mode
;
94 std::string
save_jukebox_name(size_t i
)
96 return (stringfmt() << "${project}" << (i
+ 1) << ".lsmv").str();
99 std::map
<std::string
, std::string
> slotinfo_cache
;
101 std::string
vector_to_string(const std::vector
<char>& x
)
103 std::string
y(x
.begin(), x
.end());
104 while(y
.length() > 0 && y
[y
.length() - 1] < 32)
105 y
= y
.substr(0, y
.length() - 1);
109 std::string
get_slotinfo(const std::string
& _filename
)
111 std::string filename
= resolve_relative_path(_filename
);
112 if(!slotinfo_cache
.count(filename
)) {
113 std::ostringstream out
;
115 std::string projid
= vector_to_string(read_file_relative(filename
+ "/projectid",
117 std::string rerecords
= vector_to_string(read_file_relative(filename
+ "/rerecords",
119 std::string frame
= vector_to_string(read_file_relative(filename
+ "/saveframe", ""));
120 if(our_movie
.projectid
== projid
)
121 out
<< rerecords
<< "R/" << frame
<< "F";
123 out
<< "Wrong movie";
125 out
<< "Nonexistent";
127 slotinfo_cache
[filename
] = out
.str();
129 return slotinfo_cache
[filename
];
132 void flush_slotinfo(const std::string
& filename
)
134 slotinfo_cache
.erase(resolve_relative_path(filename
));
137 void flush_slotinfo()
139 slotinfo_cache
.clear();
142 class _lsnes_pflag_handler
: public movie::poll_flag
145 ~_lsnes_pflag_handler()
150 return our_rom
->rtype
->get_pflag();
152 void set_pflag(int flag
)
154 our_rom
->rtype
->set_pflag(flag
);
156 } lsnes_pflag_handler
;
159 void mainloop_signal_need_rewind(void* ptr
)
163 amode
= ADVANCE_LOAD
;
165 do_unsafe_rewind
= true;
166 unsafe_rewind_obj
= ptr
;
169 controller_frame
movie_logic::update_controls(bool subframe
) throw(std::bad_alloc
, std::runtime_error
)
171 if(lua_requests_subframe_paint
)
172 redraw_framebuffer();
175 if(amode
== ADVANCE_SUBFRAME
) {
176 if(!cancel_advance
) {
178 platform::wait(advance_timeout_first
* 1000);
180 platform::wait(advance_timeout_subframe
* 1000);
181 advanced_once
= true;
184 stop_at_frame_active
= false;
185 amode
= ADVANCE_PAUSE
;
186 cancel_advance
= false;
188 platform::set_paused(amode
== ADVANCE_PAUSE
);
189 } else if(amode
== ADVANCE_FRAME
) {
192 if(amode
== ADVANCE_SKIPLAG
) {
193 stop_at_frame_active
= false;
194 amode
= ADVANCE_PAUSE
;
196 platform::set_paused(amode
== ADVANCE_PAUSE
);
197 cancel_advance
= false;
199 location_special
= SPECIAL_NONE
;
200 update_movie_state();
202 if(amode
== ADVANCE_SKIPLAG_PENDING
)
203 amode
= ADVANCE_SKIPLAG
;
204 if(amode
== ADVANCE_FRAME
|| amode
== ADVANCE_SUBFRAME
) {
205 if(!cancel_advance
) {
208 wait
= advance_timeout_first
* 1000;
209 else if(amode
== ADVANCE_SUBFRAME
)
210 wait
= advance_timeout_subframe
* 1000;
212 wait
= to_wait_frame(get_utime());
213 platform::wait(wait
);
214 advanced_once
= true;
217 stop_at_frame_active
= false;
218 amode
= ADVANCE_PAUSE
;
219 cancel_advance
= false;
221 platform::set_paused(amode
== ADVANCE_PAUSE
);
222 } else if(amode
== ADVANCE_AUTO
&& movb
.get_movie().readonly_mode() && pause_on_end
&&
223 !stop_at_frame_active
) {
224 if(movb
.get_movie().get_current_frame() == movb
.get_movie().get_frame_count()) {
225 stop_at_frame_active
= false;
226 amode
= ADVANCE_PAUSE
;
227 platform::set_paused(true);
229 } else if(amode
== ADVANCE_AUTO
&& stop_at_frame_active
) {
230 if(movb
.get_movie().get_current_frame() >= stop_at_frame
) {
231 stop_at_frame_active
= false;
232 amode
= ADVANCE_PAUSE
;
233 platform::set_paused(true);
236 platform::set_paused((amode
== ADVANCE_PAUSE
));
237 cancel_advance
= false;
239 location_special
= SPECIAL_FRAME_START
;
240 update_movie_state();
243 information_dispatch::do_status_update();
244 platform::flush_command_queue();
245 controller_frame tmp
= controls
.get(movb
.get_movie().get_current_frame());
246 our_rom
->rtype
->pre_emulate_frame(tmp
); //Preset controls, the lua will override if needed.
247 lua_callback_do_input(tmp
, subframe
);
248 controls
.commit(tmp
);
255 //Do pending load (automatically unpauses).
256 void mark_pending_load(const std::string
& filename
, int lmode
)
259 pending_load
= filename
;
261 amode
= ADVANCE_LOAD
;
262 platform::cancel_wait();
263 platform::set_paused(false);
266 void mark_pending_save(const std::string
& filename
, int smode
)
268 if(smode
== SAVE_MOVIE
) {
269 //Just do this immediately.
270 do_save_movie(filename
);
271 flush_slotinfo(translate_name_mprefix(filename
, true));
274 if(location_special
== SPECIAL_SAVEPOINT
) {
275 //We can save immediately here.
276 do_save_state(filename
);
277 flush_slotinfo(translate_name_mprefix(filename
, true));
280 queued_saves
.insert(filename
);
281 messages
<< "Pending save on '" << filename
<< "'" << std::endl
;
284 bool reload_rom(const std::string
& filename
)
286 std::string filenam
= filename
;
288 filenam
= our_rom
->load_filename
;
290 messages
<< "No ROM loaded" << std::endl
;
294 messages
<< "Loading ROM " << filenam
<< std::endl
;
295 loaded_rom
newrom(filenam
);
297 for(size_t i
= 0; i
< sizeof(our_rom
->romimg
)/sizeof(our_rom
->romimg
[0]); i
++) {
298 our_movie
.romimg_sha256
[i
] = our_rom
->romimg
[i
].sha_256
;
299 our_movie
.romxml_sha256
[i
] = our_rom
->romxml
[i
].sha_256
;
301 } catch(std::exception
& e
) {
302 messages
<< "Can't reload ROM: " << e
.what() << std::endl
;
305 messages
<< "Using core: " << our_rom
->rtype
->get_core_identifier() << std::endl
;
306 information_dispatch::do_core_change();
310 struct jukebox_size_listener
: public setting_var_listener
312 jukebox_size_listener() { lsnes_vset
.add_listener(*this); }
313 ~jukebox_size_listener() throw() {lsnes_vset
.remove_listener(*this); };
314 void on_setting_change(setting_var_group
& grp
, const setting_var_base
& val
)
316 if(val
.get_iname() == "jukebox-size") {
317 if(save_jukebox_pointer
>= jukebox_size
)
318 save_jukebox_pointer
= 0;
321 if(emulation_thread
== this_thread_id())
322 update_movie_state();
324 runemufn([]() { update_movie_state(); });
325 information_dispatch::do_status_update();
330 void update_movie_state()
332 static unsigned last_controllers
= 0;
335 our_rom
->region
->fill_framerate_magic(magic
);
336 voice_frame_number(movb
.get_movie().get_current_frame(), 1.0 * magic
[1] / magic
[0]);
338 auto& _status
= platform::get_emustatus();
339 if(!system_corrupt
) {
340 _status
.set("!frame", (stringfmt() << movb
.get_movie().get_current_frame()).str());
341 _status
.set("!length", (stringfmt() << movb
.get_movie().get_frame_count()).str());
342 _status
.set("!lag", (stringfmt() << movb
.get_movie().get_lag_frames()).str());
343 if(location_special
== SPECIAL_FRAME_START
)
344 _status
.set("!subframe", "0");
345 else if(location_special
== SPECIAL_SAVEPOINT
)
346 _status
.set("!subframe", "S");
347 else if(location_special
== SPECIAL_FRAME_VIDEO
)
348 _status
.set("!subframe", "V");
350 _status
.set("!subframe", (stringfmt() << movb
.get_movie().next_poll_number()).str());
352 _status
.set("!frame", "N/A");
353 _status
.set("!length", "N/A");
354 _status
.set("!lag", "N/A");
355 _status
.set("!subframe", "N/A");
358 _status
.set("!dumping", (information_dispatch::get_dumper_count() ? "Y" : ""));
359 auto& mo
= movb
.get_movie();
361 _status
.set("!mode", "C");
362 else if(!mo
.readonly_mode())
363 _status
.set("!mode", "R");
364 else if(mo
.get_frame_count() >= mo
.get_current_frame())
365 _status
.set("!mode", "P");
367 _status
.set("!mode", "F");
369 if(jukebox_size
> 0) {
370 std::string sfilen
= translate_name_mprefix(save_jukebox_name(save_jukebox_pointer
), true);
371 _status
.set("!saveslot", (stringfmt() << (save_jukebox_pointer
+ 1)).str());
372 _status
.set("!saveslotinfo", get_slotinfo(sfilen
));
374 _status
.erase("!saveslot");
375 _status
.erase("!saveslotinfo");
377 _status
.set("!speed", (stringfmt() << (unsigned)(100 * get_realized_multiplier() + 0.5)).str());
379 if(!system_corrupt
) {
380 time_t timevalue
= static_cast<time_t>(our_movie
.rtc_second
);
381 struct tm
* time_decompose
= gmtime(&timevalue
);
382 char datebuffer
[512];
383 strftime(datebuffer
, 511, "%Y%m%d(%a)T%H%M%S", time_decompose
);
384 _status
.set("RTC", datebuffer
);
386 _status
.set("RTC", "N/A");
391 if(movb
.get_movie().readonly_mode())
392 c
= movb
.get_movie().get_controls();
394 c
= controls
.get_committed();
395 for(unsigned i
= 0;; i
++) {
396 auto pindex
= controls
.lcid_to_pcid(i
);
397 if(pindex
.first
< 0 || !controls
.is_present(pindex
.first
, pindex
.second
)) {
398 for(unsigned j
= i
; j
< last_controllers
; j
++)
399 _status
.erase((stringfmt() << "P" << (j
+ 1)).str());
400 last_controllers
= i
;
403 char32_t buffer
[MAX_DISPLAY_LENGTH
];
404 c
.display(pindex
.first
, pindex
.second
, buffer
);
405 _status
.set((stringfmt() << "P" << (i
+ 1)).str(), buffer
);
409 uint64_t audio_irq_time
;
410 uint64_t controller_irq_time
;
411 uint64_t frame_irq_time
;
413 struct lsnes_callbacks
: public emucore_callbacks
416 ~lsnes_callbacks() throw()
420 int16_t get_input(unsigned port
, unsigned index
, unsigned control
)
423 x
= movb
.input_poll(port
, index
, control
);
424 lua_callback_snoop_input(port
, index
, control
, x
);
428 int16_t set_input(unsigned port
, unsigned index
, unsigned control
, int16_t value
)
430 if(!movb
.get_movie().readonly_mode()) {
431 controller_frame f
= movb
.get_movie().get_controls();
432 f
.axis3(port
, index
, control
, value
);
433 movb
.get_movie().set_controls(f
);
435 return movb
.get_movie().next_input(port
, index
, control
);
438 void timer_tick(uint32_t increment
, uint32_t per_second
)
440 our_movie
.rtc_subsecond
+= increment
;
441 while(our_movie
.rtc_subsecond
>= per_second
) {
442 our_movie
.rtc_second
++;
443 our_movie
.rtc_subsecond
-= per_second
;
447 std::string
get_firmware_path()
449 return lsnes_vset
["firmwarepath"].str();
452 std::string
get_base_path()
454 return our_rom
->msu1_base
;
459 return our_movie
.rtc_second
;
462 time_t get_randomseed()
464 return random_seed_value
;
467 void output_frame(framebuffer_raw
& screen
, uint32_t fps_n
, uint32_t fps_d
)
469 lua_callback_do_frame_emulated();
470 location_special
= SPECIAL_FRAME_VIDEO
;
471 update_movie_state();
472 redraw_framebuffer(screen
, false, true);
473 uint32_t g
= gcd(fps_n
, fps_d
);
476 information_dispatch::do_frame(screen
, fps_n
, fps_d
);
482 function_ptr_command
<> count_rerecords(lsnes_cmd
, "count-rerecords", "Count rerecords",
483 "Syntax: count-rerecords\nCounts rerecords.\n",
484 []() throw(std::bad_alloc
, std::runtime_error
) {
485 std::vector
<char> tmp
;
486 uint64_t x
= rrdata::write(tmp
);
487 messages
<< x
<< " rerecord(s)" << std::endl
;
490 function_ptr_command
<const std::string
&> quit_emulator(lsnes_cmd
, "quit-emulator", "Quit the emulator",
491 "Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n",
492 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
493 amode
= ADVANCE_QUIT
;
494 platform::set_paused(false);
495 platform::cancel_wait();
498 function_ptr_command
<> unpause_emulator(lsnes_cmd
, "unpause-emulator", "Unpause the emulator",
499 "Syntax: unpause-emulator\nUnpauses the emulator.\n",
500 []() throw(std::bad_alloc
, std::runtime_error
) {
501 amode
= ADVANCE_AUTO
;
502 platform::set_paused(false);
503 platform::cancel_wait();
504 messages
<< "Unpaused" << std::endl
;
507 function_ptr_command
<> pause_emulator(lsnes_cmd
, "pause-emulator", "(Un)pause the emulator",
508 "Syntax: pause-emulator\n(Un)pauses the emulator.\n",
509 []() throw(std::bad_alloc
, std::runtime_error
) {
510 if(amode
!= ADVANCE_AUTO
) {
511 amode
= ADVANCE_AUTO
;
512 platform::set_paused(false);
513 platform::cancel_wait();
514 messages
<< "Unpaused" << std::endl
;
516 platform::cancel_wait();
517 cancel_advance
= false;
518 stop_at_frame_active
= false;
519 amode
= ADVANCE_PAUSE
;
520 messages
<< "Paused" << std::endl
;
524 function_ptr_command
<> save_jukebox_prev(lsnes_cmd
, "cycle-jukebox-backward", "Cycle save jukebox backwards",
525 "Syntax: cycle-jukebox-backward\nCycle save jukebox backwards\n",
526 []() throw(std::bad_alloc
, std::runtime_error
) {
527 if(jukebox_size
== 0)
529 if(save_jukebox_pointer
== 0)
530 save_jukebox_pointer
= jukebox_size
- 1;
532 save_jukebox_pointer
--;
533 if(save_jukebox_pointer
>= jukebox_size
)
534 save_jukebox_pointer
= 0;
535 update_movie_state();
536 information_dispatch::do_status_update();
539 function_ptr_command
<> save_jukebox_next(lsnes_cmd
, "cycle-jukebox-forward", "Cycle save jukebox forwards",
540 "Syntax: cycle-jukebox-forward\nCycle save jukebox forwards\n",
541 []() throw(std::bad_alloc
, std::runtime_error
) {
542 if(jukebox_size
== 0)
544 if(save_jukebox_pointer
>= jukebox_size
- 1)
545 save_jukebox_pointer
= 0;
547 save_jukebox_pointer
++;
548 if(save_jukebox_pointer
>= jukebox_size
)
549 save_jukebox_pointer
= 0;
550 update_movie_state();
551 information_dispatch::do_status_update();
554 function_ptr_command
<> load_jukebox(lsnes_cmd
, "load-jukebox", "Load save from jukebox",
555 "Syntax: load-jukebox\nLoad save from jukebox\n",
556 []() throw(std::bad_alloc
, std::runtime_error
) {
557 if(jukebox_size
== 0)
558 throw std::runtime_error("No slot selected");
559 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_CURRENT
);
562 function_ptr_command
<> load_jukebox_readwrite(lsnes_cmd
, "load-jukebox-readwrite", "Load save from jukebox in"
563 " read-write mode", "Syntax: load-jukebox-readwrite\nLoad save from jukebox in read-write mode\n",
564 []() throw(std::bad_alloc
, std::runtime_error
) {
565 if(jukebox_size
== 0)
566 throw std::runtime_error("No slot selected");
567 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_RW
);
570 function_ptr_command
<> load_jukebox_readonly(lsnes_cmd
, "load-jukebox-readonly", "Load save from jukebox in "
571 "read-only mode", "Syntax: load-jukebox-readonly\nLoad save from jukebox in read-only mode\n",
572 []() throw(std::bad_alloc
, std::runtime_error
) {
573 if(jukebox_size
== 0)
574 throw std::runtime_error("No slot selected");
575 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_RO
);
578 function_ptr_command
<> load_jukebox_preserve(lsnes_cmd
, "load-jukebox-preserve", "Load save from jukebox, "
579 "preserving input", "Syntax: load-jukebox-preserve\nLoad save from jukebox, preserving input\n",
580 []() throw(std::bad_alloc
, std::runtime_error
) {
581 if(jukebox_size
== 0)
582 throw std::runtime_error("No slot selected");
583 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_PRESERVE
);
586 function_ptr_command
<> load_jukebox_movie(lsnes_cmd
, "load-jukebox-movie", "Load save from jukebox as movie",
587 "Syntax: load-jukebox-movie\nLoad save from jukebox as movie\n",
588 []() throw(std::bad_alloc
, std::runtime_error
) {
589 if(jukebox_size
== 0)
590 throw std::runtime_error("No slot selected");
591 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_MOVIE
);
594 function_ptr_command
<> save_jukebox_c(lsnes_cmd
, "save-jukebox", "Save save to jukebox",
595 "Syntax: save-jukebox\nSave save to jukebox\n",
596 []() throw(std::bad_alloc
, std::runtime_error
) {
597 if(jukebox_size
== 0)
598 throw std::runtime_error("No slot selected");
599 mark_pending_save(save_jukebox_name(save_jukebox_pointer
), SAVE_STATE
);
602 function_ptr_command
<> padvance_frame(lsnes_cmd
, "+advance-frame", "Advance one frame",
603 "Syntax: +advance-frame\nAdvances the emulation by one frame.\n",
604 []() throw(std::bad_alloc
, std::runtime_error
) {
605 amode
= ADVANCE_FRAME
;
606 cancel_advance
= false;
607 advanced_once
= false;
608 platform::cancel_wait();
609 platform::set_paused(false);
612 function_ptr_command
<> nadvance_frame(lsnes_cmd
, "-advance-frame", "Advance one frame",
613 "No help available\n",
614 []() throw(std::bad_alloc
, std::runtime_error
) {
615 cancel_advance
= true;
616 platform::cancel_wait();
617 platform::set_paused(false);
620 function_ptr_command
<> padvance_poll(lsnes_cmd
, "+advance-poll", "Advance one subframe",
621 "Syntax: +advance-poll\nAdvances the emulation by one subframe.\n",
622 []() throw(std::bad_alloc
, std::runtime_error
) {
623 amode
= ADVANCE_SUBFRAME
;
624 cancel_advance
= false;
625 advanced_once
= false;
626 platform::cancel_wait();
627 platform::set_paused(false);
630 function_ptr_command
<> nadvance_poll(lsnes_cmd
, "-advance-poll", "Advance one subframe",
631 "No help available\n",
632 []() throw(std::bad_alloc
, std::runtime_error
) {
633 cancel_advance
= true;
634 platform::cancel_wait();
635 platform::set_paused(false);
638 function_ptr_command
<> advance_skiplag(lsnes_cmd
, "advance-skiplag", "Skip to next poll",
639 "Syntax: advance-skiplag\nAdvances the emulation to the next poll.\n",
640 []() throw(std::bad_alloc
, std::runtime_error
) {
641 amode
= ADVANCE_SKIPLAG_PENDING
;
642 platform::cancel_wait();
643 platform::set_paused(false);
646 function_ptr_command
<const std::string
&> reset_c(lsnes_cmd
, "reset", "Reset the system",
647 "Syntax: reset\nReset <delay>\nResets the system in beginning of the next frame.\n",
648 [](const std::string
& x
) throw(std::bad_alloc
, std::runtime_error
) {
649 if(!our_rom
->rtype
->get_reset_support()) {
650 messages
<< "Emulator core does not support resets" << std::endl
;
653 if((our_rom
->rtype
->get_reset_support() & 3) < 2 && x
!= "") {
654 messages
<< "Emulator core does not support delayed resets" << std::endl
;
658 our_rom
->rtype
->request_reset(0, false);
660 our_rom
->rtype
->request_reset(parse_value
<uint32_t>(x
), false);
663 function_ptr_command
<const std::string
&> hreset_c(lsnes_cmd
, "reset-hard", "Reset the system",
664 "Syntax: reset-hard\nReset-hard <delay>\nHard resets the system in beginning of the next frame.\n",
665 [](const std::string
& x
) throw(std::bad_alloc
, std::runtime_error
) {
666 if((our_rom
->rtype
->get_reset_support() & 4) == 0) {
667 messages
<< "Emulator core does not support hard resets" << std::endl
;
670 if((our_rom
->rtype
->get_reset_support() & 3) < 2 && x
!= "") {
671 messages
<< "Emulator core does not support delayed hard resets" << std::endl
;
675 our_rom
->rtype
->request_reset(0, true);
677 our_rom
->rtype
->request_reset(parse_value
<uint32_t>(x
), true);
680 function_ptr_command
<arg_filename
> load_c(lsnes_cmd
, "load", "Load savestate (current mode)",
681 "Syntax: load <file>\nLoads SNES state from <file> in current mode\n",
682 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
683 mark_pending_load(args
, LOAD_STATE_CURRENT
);
686 function_ptr_command
<arg_filename
> load_smart_c(lsnes_cmd
, "load-smart", "Load savestate (heuristic mode)",
687 "Syntax: load <file>\nLoads SNES state from <file> in heuristic mode\n",
688 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
689 mark_pending_load(args
, LOAD_STATE_DEFAULT
);
692 function_ptr_command
<arg_filename
> load_state_c(lsnes_cmd
, "load-state", "Load savestate (R/W)",
693 "Syntax: load-state <file>\nLoads SNES state from <file> in Read/Write mode\n",
694 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
695 mark_pending_load(args
, LOAD_STATE_RW
);
698 function_ptr_command
<arg_filename
> load_readonly(lsnes_cmd
, "load-readonly", "Load savestate (RO)",
699 "Syntax: load-readonly <file>\nLoads SNES state from <file> in read-only mode\n",
700 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
701 mark_pending_load(args
, LOAD_STATE_RO
);
704 function_ptr_command
<arg_filename
> load_preserve(lsnes_cmd
, "load-preserve", "Load savestate (preserve "
705 "input)", "Syntax: load-preserve <file>\nLoads SNES state from <file> preserving input\n",
706 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
707 mark_pending_load(args
, LOAD_STATE_PRESERVE
);
710 function_ptr_command
<arg_filename
> load_movie_c(lsnes_cmd
, "load-movie", "Load movie",
711 "Syntax: load-movie <file>\nLoads SNES movie from <file>\n",
712 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
713 mark_pending_load(args
, LOAD_STATE_MOVIE
);
717 function_ptr_command
<arg_filename
> save_state(lsnes_cmd
, "save-state", "Save state",
718 "Syntax: save-state <file>\nSaves SNES state to <file>\n",
719 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
720 mark_pending_save(args
, SAVE_STATE
);
723 function_ptr_command
<arg_filename
> save_movie(lsnes_cmd
, "save-movie", "Save movie",
724 "Syntax: save-movie <file>\nSaves SNES movie to <file>\n",
725 [](arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
726 mark_pending_save(args
, SAVE_MOVIE
);
729 function_ptr_command
<> set_rwmode(lsnes_cmd
, "set-rwmode", "Switch to read/write mode",
730 "Syntax: set-rwmode\nSwitches to read/write mode\n",
731 []() throw(std::bad_alloc
, std::runtime_error
) {
732 movb
.get_movie().readonly_mode(false);
733 information_dispatch::do_mode_change(false);
734 lua_callback_do_readwrite();
735 update_movie_state();
736 information_dispatch::do_status_update();
739 function_ptr_command
<> set_romode(lsnes_cmd
, "set-romode", "Switch to read-only mode",
740 "Syntax: set-romode\nSwitches to read-only mode\n",
741 []() throw(std::bad_alloc
, std::runtime_error
) {
742 movb
.get_movie().readonly_mode(true);
743 information_dispatch::do_mode_change(true);
744 update_movie_state();
745 information_dispatch::do_status_update();
748 function_ptr_command
<> toggle_rwmode(lsnes_cmd
, "toggle-rwmode", "Toggle read/write mode",
749 "Syntax: toggle-rwmode\nToggles read/write mode\n",
750 []() throw(std::bad_alloc
, std::runtime_error
) {
751 bool c
= movb
.get_movie().readonly_mode();
752 movb
.get_movie().readonly_mode(!c
);
753 information_dispatch::do_mode_change(!c
);
755 lua_callback_do_readwrite();
756 update_movie_state();
757 information_dispatch::do_status_update();
760 function_ptr_command
<> repaint(lsnes_cmd
, "repaint", "Redraw the screen",
761 "Syntax: repaint\nRedraws the screen\n",
762 []() throw(std::bad_alloc
, std::runtime_error
) {
763 redraw_framebuffer();
766 function_ptr_command
<> tpon(lsnes_cmd
, "toggle-pause-on-end", "Toggle pause on end", "Toggle pause on end\n",
767 []() throw(std::bad_alloc
, std::runtime_error
) {
768 bool tmp
= pause_on_end
;
769 pause_on_end
.set(!tmp
);
770 messages
<< "Pause-on-end is now " << (tmp
? "OFF" : "ON") << std::endl
;
773 function_ptr_command
<> spon(lsnes_cmd
, "set-pause-on-end", "Set pause on end", "Set pause on end\n",
774 []() throw(std::bad_alloc
, std::runtime_error
) {
775 pause_on_end
.set(true);
776 messages
<< "Pause-on-end is now ON" << std::endl
;
779 function_ptr_command
<> cpon(lsnes_cmd
, "clear-pause-on-end", "Clear pause on end", "Clear pause on end\n",
780 []() throw(std::bad_alloc
, std::runtime_error
) {
781 pause_on_end
.set(false);
782 messages
<< "Pause-on-end is now OFF" << std::endl
;
785 function_ptr_command
<> rewind_movie(lsnes_cmd
, "rewind-movie", "Rewind movie to the beginning",
786 "Syntax: rewind-movie\nRewind movie to the beginning\n",
787 []() throw(std::bad_alloc
, std::runtime_error
) {
788 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_BEGINNING
);
791 function_ptr_command
<const std::string
&> reload_rom2(lsnes_cmd
, "reload-rom", "Reload the ROM image",
792 "Syntax: reload-rom [<file>]\nReload the ROM image from <file>\n",
793 [](const std::string
& filename
) throw(std::bad_alloc
, std::runtime_error
) {
794 if(reload_rom(filename
))
795 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
798 function_ptr_command
<> cancel_save(lsnes_cmd
, "cancel-saves", "Cancel all pending saves", "Syntax: "
799 "cancel-save\nCancel pending saves\n",
800 []() throw(std::bad_alloc
, std::runtime_error
) {
801 queued_saves
.clear();
802 messages
<< "Pending saves canceled." << std::endl
;
805 function_ptr_command
<> flushslots(lsnes_cmd
, "flush-slotinfo", "Flush slotinfo cache",
806 "Flush slotinfo cache\n",
807 []() throw(std::bad_alloc
, std::runtime_error
) {
811 inverse_bind
ipause_emulator(lsnes_mapper
, "pause-emulator", "Speed‣(Un)pause");
812 inverse_bind
ijback(lsnes_mapper
, "cycle-jukebox-backward", "Slot select‣Cycle backwards");
813 inverse_bind
ijforward(lsnes_mapper
, "cycle-jukebox-forward", "Slot select‣Cycle forwards");
814 inverse_bind
iloadj(lsnes_mapper
, "load-jukebox", "Load‣Selected slot");
815 inverse_bind
iloadjrw(lsnes_mapper
, "load-jukebox-readwrite", "Load‣Selected slot (readwrite mode)");
816 inverse_bind
iloadjro(lsnes_mapper
, "load-jukebox-readonly", "Load‣Selected slot (readonly mode)");
817 inverse_bind
iloadjp(lsnes_mapper
, "load-jukebox-preserve", "Load‣Selected slot (preserve input)");
818 inverse_bind
iloadjm(lsnes_mapper
, "load-jukebox-movie", "Load‣Selected slot (as movie)");
819 inverse_bind
isavej(lsnes_mapper
, "save-jukebox", "Save‣Selected slot");
820 inverse_bind
iadvframe(lsnes_mapper
, "+advance-frame", "Speed‣Advance frame");
821 inverse_bind
iadvsubframe(lsnes_mapper
, "+advance-poll", "Speed‣Advance subframe");
822 inverse_bind
iskiplag(lsnes_mapper
, "advance-skiplag", "Speed‣Advance poll");
823 inverse_bind
ireset(lsnes_mapper
, "reset", "System‣Reset");
824 inverse_bind
iset_rwmode(lsnes_mapper
, "set-rwmode", "Movie‣Switch to read/write");
825 inverse_bind
itoggle_romode(lsnes_mapper
, "set-romode", "Movie‣Switch to read-only");
826 inverse_bind
itoggle_rwmode(lsnes_mapper
, "toggle-rwmode", "Movie‣Toggle read-only");
827 inverse_bind
irepaint(lsnes_mapper
, "repaint", "System‣Repaint screen");
828 inverse_bind
itogglepause(lsnes_mapper
, "toggle-pause-on-end", "Movie‣Toggle pause-on-end");
829 inverse_bind
irewind_movie(lsnes_mapper
, "rewind-movie", "Movie‣Rewind movie");
830 inverse_bind
icancel_saves(lsnes_mapper
, "cancel-saves", "Save‣Cancel pending saves");
831 inverse_bind
iload1(lsnes_mapper
, "load ${project}1.lsmv", "Load‣Slot 1");
832 inverse_bind
iload2(lsnes_mapper
, "load ${project}2.lsmv", "Load‣Slot 2");
833 inverse_bind
iload3(lsnes_mapper
, "load ${project}3.lsmv", "Load‣Slot 3");
834 inverse_bind
iload4(lsnes_mapper
, "load ${project}4.lsmv", "Load‣Slot 4");
835 inverse_bind
iload5(lsnes_mapper
, "load ${project}5.lsmv", "Load‣Slot 5");
836 inverse_bind
iload6(lsnes_mapper
, "load ${project}6.lsmv", "Load‣Slot 6");
837 inverse_bind
iload7(lsnes_mapper
, "load ${project}7.lsmv", "Load‣Slot 7");
838 inverse_bind
iload8(lsnes_mapper
, "load ${project}8.lsmv", "Load‣Slot 8");
839 inverse_bind
iload9(lsnes_mapper
, "load ${project}9.lsmv", "Load‣Slot 9");
840 inverse_bind
iload10(lsnes_mapper
, "load ${project}10.lsmv", "Load‣Slot 10");
841 inverse_bind
iload11(lsnes_mapper
, "load ${project}11.lsmv", "Load‣Slot 11");
842 inverse_bind
iload12(lsnes_mapper
, "load ${project}12.lsmv", "Load‣Slot 12");
843 inverse_bind
iload13(lsnes_mapper
, "load ${project}13.lsmv", "Load‣Slot 13");
844 inverse_bind
iload14(lsnes_mapper
, "load ${project}14.lsmv", "Load‣Slot 14");
845 inverse_bind
iload15(lsnes_mapper
, "load ${project}15.lsmv", "Load‣Slot 15");
846 inverse_bind
iload16(lsnes_mapper
, "load ${project}16.lsmv", "Load‣Slot 16");
847 inverse_bind
iload17(lsnes_mapper
, "load ${project}17.lsmv", "Load‣Slot 17");
848 inverse_bind
iload18(lsnes_mapper
, "load ${project}18.lsmv", "Load‣Slot 18");
849 inverse_bind
iload19(lsnes_mapper
, "load ${project}19.lsmv", "Load‣Slot 19");
850 inverse_bind
iload20(lsnes_mapper
, "load ${project}20.lsmv", "Load‣Slot 20");
851 inverse_bind
iload21(lsnes_mapper
, "load ${project}21.lsmv", "Load‣Slot 21");
852 inverse_bind
iload22(lsnes_mapper
, "load ${project}22.lsmv", "Load‣Slot 22");
853 inverse_bind
iload23(lsnes_mapper
, "load ${project}23.lsmv", "Load‣Slot 23");
854 inverse_bind
iload24(lsnes_mapper
, "load ${project}24.lsmv", "Load‣Slot 24");
855 inverse_bind
iload25(lsnes_mapper
, "load ${project}25.lsmv", "Load‣Slot 25");
856 inverse_bind
iload26(lsnes_mapper
, "load ${project}26.lsmv", "Load‣Slot 26");
857 inverse_bind
iload27(lsnes_mapper
, "load ${project}27.lsmv", "Load‣Slot 27");
858 inverse_bind
iload28(lsnes_mapper
, "load ${project}28.lsmv", "Load‣Slot 28");
859 inverse_bind
iload29(lsnes_mapper
, "load ${project}29.lsmv", "Load‣Slot 29");
860 inverse_bind
iload30(lsnes_mapper
, "load ${project}30.lsmv", "Load‣Slot 30");
861 inverse_bind
iload31(lsnes_mapper
, "load ${project}31.lsmv", "Load‣Slot 31");
862 inverse_bind
iload32(lsnes_mapper
, "load ${project}32.lsmv", "Load‣Slot 32");
863 inverse_bind
isave1(lsnes_mapper
, "save-state ${project}1.lsmv", "Save‣Slot 1");
864 inverse_bind
isave2(lsnes_mapper
, "save-state ${project}2.lsmv", "Save‣Slot 2");
865 inverse_bind
isave3(lsnes_mapper
, "save-state ${project}3.lsmv", "Save‣Slot 3");
866 inverse_bind
isave4(lsnes_mapper
, "save-state ${project}4.lsmv", "Save‣Slot 4");
867 inverse_bind
isave5(lsnes_mapper
, "save-state ${project}5.lsmv", "Save‣Slot 5");
868 inverse_bind
isave6(lsnes_mapper
, "save-state ${project}6.lsmv", "Save‣Slot 6");
869 inverse_bind
isave7(lsnes_mapper
, "save-state ${project}7.lsmv", "Save‣Slot 7");
870 inverse_bind
isave8(lsnes_mapper
, "save-state ${project}8.lsmv", "Save‣Slot 8");
871 inverse_bind
isave9(lsnes_mapper
, "save-state ${project}9.lsmv", "Save‣Slot 9");
872 inverse_bind
isave10(lsnes_mapper
, "save-state ${project}10.lsmv", "Save‣Slot 10");
873 inverse_bind
isave11(lsnes_mapper
, "save-state ${project}11.lsmv", "Save‣Slot 11");
874 inverse_bind
isave12(lsnes_mapper
, "save-state ${project}12.lsmv", "Save‣Slot 12");
875 inverse_bind
isave13(lsnes_mapper
, "save-state ${project}13.lsmv", "Save‣Slot 13");
876 inverse_bind
isave14(lsnes_mapper
, "save-state ${project}14.lsmv", "Save‣Slot 14");
877 inverse_bind
isave15(lsnes_mapper
, "save-state ${project}15.lsmv", "Save‣Slot 15");
878 inverse_bind
isave16(lsnes_mapper
, "save-state ${project}16.lsmv", "Save‣Slot 16");
879 inverse_bind
isave17(lsnes_mapper
, "save-state ${project}17.lsmv", "Save‣Slot 17");
880 inverse_bind
isave18(lsnes_mapper
, "save-state ${project}18.lsmv", "Save‣Slot 18");
881 inverse_bind
isave19(lsnes_mapper
, "save-state ${project}19.lsmv", "Save‣Slot 19");
882 inverse_bind
isave20(lsnes_mapper
, "save-state ${project}20.lsmv", "Save‣Slot 20");
883 inverse_bind
isave21(lsnes_mapper
, "save-state ${project}21.lsmv", "Save‣Slot 21");
884 inverse_bind
isave22(lsnes_mapper
, "save-state ${project}22.lsmv", "Save‣Slot 22");
885 inverse_bind
isave23(lsnes_mapper
, "save-state ${project}23.lsmv", "Save‣Slot 23");
886 inverse_bind
isave24(lsnes_mapper
, "save-state ${project}24.lsmv", "Save‣Slot 24");
887 inverse_bind
isave25(lsnes_mapper
, "save-state ${project}25.lsmv", "Save‣Slot 25");
888 inverse_bind
isave26(lsnes_mapper
, "save-state ${project}26.lsmv", "Save‣Slot 26");
889 inverse_bind
isave27(lsnes_mapper
, "save-state ${project}27.lsmv", "Save‣Slot 27");
890 inverse_bind
isave28(lsnes_mapper
, "save-state ${project}28.lsmv", "Save‣Slot 28");
891 inverse_bind
isave29(lsnes_mapper
, "save-state ${project}29.lsmv", "Save‣Slot 29");
892 inverse_bind
isave30(lsnes_mapper
, "save-state ${project}30.lsmv", "Save‣Slot 30");
893 inverse_bind
isave31(lsnes_mapper
, "save-state ${project}31.lsmv", "Save‣Slot 31");
894 inverse_bind
isave32(lsnes_mapper
, "save-state ${project}32.lsmv", "Save‣Slot 32");
896 bool on_quit_prompt
= false;
897 class mywindowcallbacks
: public information_dispatch
900 mywindowcallbacks() : information_dispatch("mainloop-window-callbacks") {}
901 void on_new_dumper(const std::string
& n
)
903 update_movie_state();
905 void on_destroy_dumper(const std::string
& n
)
907 update_movie_state();
909 void on_close() throw()
912 amode
= ADVANCE_QUIT
;
913 platform::set_paused(false);
914 platform::cancel_wait();
917 on_quit_prompt
= true;
919 amode
= ADVANCE_QUIT
;
920 platform::set_paused(false);
921 platform::cancel_wait();
924 on_quit_prompt
= false;
928 //If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
932 if(do_unsafe_rewind
&& unsafe_rewind_obj
) {
933 uint64_t t
= get_utime();
935 lua_callback_do_unsafe_rewind(s
, 0, 0, movb
.get_movie(), unsafe_rewind_obj
);
936 information_dispatch::do_mode_change(false);
937 do_unsafe_rewind
= false;
938 our_movie
.is_savestate
= true;
939 location_special
= SPECIAL_SAVEPOINT
;
940 update_movie_state();
941 messages
<< "Rewind done in " << (get_utime() - t
) << " usec." << std::endl
;
944 if(pending_load
!= "") {
945 std::string old_project
= our_movie
.projectid
;
946 system_corrupt
= false;
947 if(loadmode
!= LOAD_STATE_BEGINNING
&& loadmode
!= LOAD_STATE_ROMRELOAD
&&
948 !do_load_state(pending_load
, loadmode
)) {
949 movb
.get_movie().set_pflag_handler(&lsnes_pflag_handler
);
954 if(loadmode
== LOAD_STATE_BEGINNING
)
955 do_load_beginning(false);
956 if(loadmode
== LOAD_STATE_ROMRELOAD
)
957 do_load_beginning(true);
958 } catch(std::exception
& e
) {
959 messages
<< "Load failed: " << e
.what() << std::endl
;
961 movb
.get_movie().set_pflag_handler(&lsnes_pflag_handler
);
963 amode
= ADVANCE_AUTO
;
964 platform::cancel_wait();
965 platform::set_paused(false);
966 if(!system_corrupt
) {
967 location_special
= SPECIAL_SAVEPOINT
;
968 update_movie_state();
969 information_dispatch::do_status_update();
970 platform::flush_command_queue();
972 if(old_project
!= our_movie
.projectid
)
973 flush_slotinfo(); //Wrong movie may be stale.
979 //If there are pending saves, perform them.
982 if(!queued_saves
.empty() || (do_unsafe_rewind
&& !unsafe_rewind_obj
)) {
983 our_rom
->rtype
->runtosave();
984 for(auto i
: queued_saves
) {
986 flush_slotinfo(translate_name_mprefix(i
, true));
988 if(do_unsafe_rewind
&& !unsafe_rewind_obj
) {
989 uint64_t t
= get_utime();
990 std::vector
<char> s
= our_rom
->save_core_state(true);
991 uint64_t secs
= our_movie
.rtc_second
;
992 uint64_t ssecs
= our_movie
.rtc_subsecond
;
993 lua_callback_do_unsafe_rewind(s
, secs
, ssecs
, movb
.get_movie(), NULL
);
994 do_unsafe_rewind
= false;
995 messages
<< "Rewind point set in " << (get_utime() - t
) << " usec." << std::endl
;
998 queued_saves
.clear();
1001 bool handle_corrupt()
1005 while(system_corrupt
) {
1006 platform::cancel_wait();
1007 platform::set_paused(true);
1008 platform::flush_command_queue();
1010 if(amode
== ADVANCE_QUIT
)
1017 void main_loop(struct loaded_rom
& rom
, struct moviefile
& initial
, bool load_has_to_succeed
) throw(std::bad_alloc
,
1020 //Basic initialization.
1021 emulation_thread
= this_thread_id();
1022 jukebox_size_listener jlistener
;
1024 init_special_screens();
1026 lsnes_callbacks lsnes_callbacks_obj
;
1027 ecore_callbacks
= &lsnes_callbacks_obj
;
1028 movb
.get_movie().set_pflag_handler(&lsnes_pflag_handler
);
1029 core_core::install_all_handlers();
1031 //Load our given movie.
1032 bool first_round
= false;
1033 bool just_did_loadstate
= false;
1035 do_load_state(initial
, LOAD_STATE_INITIAL
);
1036 location_special
= SPECIAL_SAVEPOINT
;
1037 update_movie_state();
1038 first_round
= our_movie
.is_savestate
;
1039 just_did_loadstate
= first_round
;
1040 } catch(std::bad_alloc
& e
) {
1042 } catch(std::exception
& e
) {
1043 messages
<< "ERROR: Can't load initial state: " << e
.what() << std::endl
;
1044 if(load_has_to_succeed
) {
1045 messages
<< "FATAL: Can't load movie" << std::endl
;
1046 platform::fatal_error();
1048 system_corrupt
= true;
1049 update_movie_state();
1050 redraw_framebuffer(screen_corrupt
);
1053 movb
.get_movie().set_pflag_handler(&lsnes_pflag_handler
);
1054 lua_callback_startup();
1056 platform::set_paused(initial
.start_paused
);
1057 amode
= initial
.start_paused
? ADVANCE_PAUSE
: ADVANCE_AUTO
;
1058 stop_at_frame_active
= false;
1059 uint64_t time_x
= get_utime();
1060 while(amode
!= ADVANCE_QUIT
|| !queued_saves
.empty()) {
1061 if(handle_corrupt()) {
1062 first_round
= our_movie
.is_savestate
;
1063 just_did_loadstate
= first_round
;
1066 ack_frame_tick(get_utime());
1067 if(amode
== ADVANCE_SKIPLAG_PENDING
)
1068 amode
= ADVANCE_SKIPLAG
;
1071 controls
.reset_framehold();
1072 movb
.new_frame_starting(amode
== ADVANCE_SKIPLAG
);
1073 if(amode
== ADVANCE_QUIT
&& queued_saves
.empty())
1077 if(queued_saves
.empty())
1079 if(r
> 0 || system_corrupt
) {
1080 first_round
= our_movie
.is_savestate
;
1082 amode
= ADVANCE_PAUSE
;
1085 stop_at_frame_active
= false;
1086 just_did_loadstate
= first_round
;
1087 controls
.reset_framehold();
1090 //Not exactly desriable, but this at least won't desync.
1091 stop_at_frame_active
= false;
1092 amode
= ADVANCE_PAUSE
;
1095 if(just_did_loadstate
) {
1096 //If we just loadstated, we are up to date.
1097 if(amode
== ADVANCE_QUIT
)
1099 platform::cancel_wait();
1100 platform::set_paused(amode
== ADVANCE_PAUSE
);
1101 platform::flush_command_queue();
1102 //We already have done the reset this frame if we are going to do one at all.
1103 movb
.get_movie().set_controls(movb
.update_controls(true));
1104 movb
.get_movie().set_all_DRDY();
1105 just_did_loadstate
= false;
1107 frame_irq_time
= get_utime() - time_x
;
1108 our_rom
->rtype
->emulate();
1109 time_x
= get_utime();
1110 if(amode
== ADVANCE_AUTO
)
1111 platform::wait(to_wait_frame(get_utime()));
1112 first_round
= false;
1113 lua_callback_do_frame();
1115 information_dispatch::do_dump_end();
1116 core_core::uninstall_all_handlers();
1120 void set_stop_at_frame(uint64_t frame
)
1122 stop_at_frame
= frame
;
1123 stop_at_frame_active
= (frame
!= 0);
1124 amode
= ADVANCE_AUTO
;
1125 platform::set_paused(false);