3 #include "core/command.hpp"
4 #include "core/controller.hpp"
5 #include "core/command.hpp"
6 #include "core/debug.hpp"
7 #include "core/dispatch.hpp"
8 #include "core/emustatus.hpp"
9 #include "core/framebuffer.hpp"
10 #include "core/framerate.hpp"
11 #include "core/inthread.hpp"
12 #include "core/keymapper.hpp"
13 #include "core/multitrack.hpp"
14 #include "lua/lua.hpp"
15 #include "library/string.hpp"
16 #include "core/mainloop.hpp"
17 #include "core/instance.hpp"
18 #include "core/moviedata.hpp"
19 #include "core/moviefile.hpp"
20 #include "core/memorymanip.hpp"
21 #include "core/memorywatch.hpp"
22 #include "core/project.hpp"
23 #include "core/random.hpp"
24 #include "core/rom.hpp"
25 #include "core/romloader.hpp"
26 #include "core/settings.hpp"
27 #include "core/window.hpp"
28 #include "interface/c-interface.hpp"
29 #include "interface/callbacks.hpp"
30 #include "interface/romtype.hpp"
31 #include "library/framebuffer.hpp"
32 #include "library/zip.hpp"
42 #define QUIT_MAGIC 0x5a8c4bef
44 #define SPECIAL_FRAME_START 0
45 #define SPECIAL_FRAME_VIDEO 1
46 #define SPECIAL_SAVEPOINT 2
47 #define SPECIAL_NONE 3
49 void update_movie_state();
50 time_t random_seed_value
= 0;
52 settingvar::supervariable
<settingvar::model_bool
<settingvar::yes_no
>> jukebox_dflt_binary(lsnes_setgrp
,
53 "jukebox-default-binary", "Movie‣Saving‣Saveslots binary", true);
54 settingvar::supervariable
<settingvar::model_bool
<settingvar::yes_no
>> movie_dflt_binary(lsnes_setgrp
,
55 "movie-default-binary", "Movie‣Saving‣Movies binary", false);
56 settingvar::supervariable
<settingvar::model_bool
<settingvar::yes_no
>> save_dflt_binary(lsnes_setgrp
,
57 "savestate-default-binary", "Movie‣Saving‣Savestates binary", false);
61 settingvar::supervariable
<settingvar::model_int
<0,999999>> advance_timeout_first(lsnes_setgrp
,
62 "advance-timeout", "Delays‣First frame advance", 500);
63 settingvar::supervariable
<settingvar::model_int
<0,999999>> advance_timeout_subframe(lsnes_setgrp
,
64 "advance-subframe-timeout", "Delays‣Subframe advance", 100);
65 settingvar::supervariable
<settingvar::model_bool
<settingvar::yes_no
>> pause_on_end(lsnes_setgrp
,
66 "pause-on-end", "Movie‣Pause on end", false);
67 settingvar::supervariable
<settingvar::model_int
<0,999999999>> jukebox_size(lsnes_setgrp
, "jukebox-size",
68 "Movie‣Number of save slots", 12);
72 ADVANCE_INVALID
, //In case someone trashes this.
73 ADVANCE_QUIT
, //Quit the emulator.
74 ADVANCE_AUTO
, //Normal (possibly slowed down play).
75 ADVANCE_LOAD
, //Loading a state.
76 ADVANCE_FRAME
, //Frame advance.
77 ADVANCE_SUBFRAME
, //Subframe advance.
78 ADVANCE_SKIPLAG
, //Skip lag (oneshot, reverts to normal).
79 ADVANCE_SKIPLAG_PENDING
, //Activate skip lag mode at next frame.
80 ADVANCE_PAUSE
, //Unconditional pause.
81 ADVANCE_BREAK_PAUSE
, //Break pause.
85 threads::id emulation_thread
;
86 //Flags related to repeating advance.
89 //Emulator advance mode. Detemines pauses at start of frame / subframe, etc..
90 enum advance_mode amode
;
91 enum advance_mode old_mode
;
92 //Mode and filename of pending load, one of LOAD_* constants.
95 std::string pending_load
;
96 std::string pending_new_project
;
97 //Queued saves (all savestates).
98 std::set
<std::pair
<std::string
, int>> queued_saves
;
100 size_t save_jukebox_pointer
;
101 //Special subframe location. One of SPECIAL_* constants.
102 int location_special
;
104 bool do_unsafe_rewind
= false;
105 void* unsafe_rewind_obj
= NULL
;
107 bool stop_at_frame_active
= false;
108 uint64_t stop_at_frame
= 0;
117 if(amode
== ADVANCE_QUIT
&& quit_magic
== QUIT_MAGIC
)
119 if(amode
== ADVANCE_INVALID
|| (amode
== ADVANCE_QUIT
&& quit_magic
!= QUIT_MAGIC
) ||
120 amode
> ADVANCE_BREAK_PAUSE
) {
122 if(lsnes_instance
.mlogic
)
123 emerg_save_movie(lsnes_instance
.mlogic
.get_mfile(),
124 lsnes_instance
.mlogic
.get_rrdata());
125 messages
<< "WARNING: Emulator runmode undefined, invoked movie dump." << std::endl
;
126 amode
= ADVANCE_PAUSE
;
131 std::string
save_jukebox_name(size_t i
)
133 return (stringfmt() << "$SLOT:" << (i
+ 1)).str();
136 std::map
<std::string
, std::string
> slotinfo_cache
;
138 std::string
vector_to_string(const std::vector
<char>& x
)
140 std::string
y(x
.begin(), x
.end());
141 while(y
.length() > 0 && y
[y
.length() - 1] < 32)
142 y
= y
.substr(0, y
.length() - 1);
146 std::string
get_slotinfo(const std::string
& _filename
)
148 std::string filename
= resolve_relative_path(_filename
);
149 if(!slotinfo_cache
.count(filename
)) {
150 std::ostringstream out
;
152 moviefile::brief_info
info(filename
);
155 else if(CORE().mlogic
.get_mfile().projectid
== info
.projectid
)
156 out
<< info
.rerecords
<< "R/" << info
.current_frame
<< "F";
158 out
<< "Wrong movie";
160 out
<< "Nonexistent";
162 slotinfo_cache
[filename
] = out
.str();
164 return slotinfo_cache
[filename
];
167 void flush_slotinfo(const std::string
& filename
)
169 slotinfo_cache
.erase(resolve_relative_path(filename
));
172 void flush_slotinfo()
174 slotinfo_cache
.clear();
178 void mainloop_signal_need_rewind(void* ptr
)
182 amode
= ADVANCE_LOAD
;
184 do_unsafe_rewind
= true;
185 unsafe_rewind_obj
= ptr
;
188 controller_frame
movie_logic::update_controls(bool subframe
) throw(std::bad_alloc
, std::runtime_error
)
190 if(lua_requests_subframe_paint
)
191 redraw_framebuffer();
194 if(amode
== ADVANCE_SUBFRAME
) {
195 if(!cancel_advance
) {
197 platform::wait(advance_timeout_first(CORE().settings
) * 1000);
199 platform::wait(advance_timeout_subframe(CORE().settings
) * 1000);
200 advanced_once
= true;
203 stop_at_frame_active
= false;
204 amode
= ADVANCE_PAUSE
;
205 cancel_advance
= false;
207 platform::set_paused(amode
== ADVANCE_PAUSE
);
208 } else if(amode
== ADVANCE_FRAME
) {
211 if(amode
== ADVANCE_SKIPLAG
) {
212 stop_at_frame_active
= false;
213 amode
= ADVANCE_PAUSE
;
215 platform::set_paused(amode
== ADVANCE_PAUSE
);
216 cancel_advance
= false;
218 location_special
= SPECIAL_NONE
;
219 update_movie_state();
221 if(amode
== ADVANCE_SKIPLAG_PENDING
)
222 amode
= ADVANCE_SKIPLAG
;
223 if(amode
== ADVANCE_FRAME
|| amode
== ADVANCE_SUBFRAME
) {
224 if(!cancel_advance
) {
227 wait
= advance_timeout_first(CORE().settings
) * 1000;
228 else if(amode
== ADVANCE_SUBFRAME
)
229 wait
= advance_timeout_subframe(CORE().settings
) * 1000;
231 wait
= to_wait_frame(get_utime());
232 platform::wait(wait
);
233 advanced_once
= true;
236 stop_at_frame_active
= false;
237 amode
= ADVANCE_PAUSE
;
238 cancel_advance
= false;
240 platform::set_paused(amode
== ADVANCE_PAUSE
);
241 } else if(amode
== ADVANCE_AUTO
&& CORE().mlogic
.get_movie().readonly_mode() &&
242 pause_on_end(CORE().settings
) && !stop_at_frame_active
) {
243 if(CORE().mlogic
.get_movie().get_current_frame() ==
244 CORE().mlogic
.get_movie().get_frame_count()) {
245 stop_at_frame_active
= false;
246 amode
= ADVANCE_PAUSE
;
247 platform::set_paused(true);
249 } else if(amode
== ADVANCE_AUTO
&& stop_at_frame_active
) {
250 if(CORE().mlogic
.get_movie().get_current_frame() >= stop_at_frame
) {
251 stop_at_frame_active
= false;
252 amode
= ADVANCE_PAUSE
;
253 platform::set_paused(true);
256 platform::set_paused((amode
== ADVANCE_PAUSE
));
257 cancel_advance
= false;
259 location_special
= SPECIAL_FRAME_START
;
260 update_movie_state();
262 platform::flush_command_queue();
263 controller_frame tmp
= CORE().controls
.get(CORE().mlogic
.get_movie().get_current_frame());
264 our_rom
.rtype
->pre_emulate_frame(tmp
); //Preset controls, the lua will override if needed.
265 lua_callback_do_input(tmp
, subframe
);
266 CORE().mteditor
.process_frame(tmp
);
267 CORE().controls
.commit(tmp
);
274 //Do pending load (automatically unpauses).
275 void mark_pending_load(std::string filename
, int lmode
)
277 //Convert break pause to ordinary pause.
278 if(amode
== ADVANCE_BREAK_PAUSE
)
279 amode
= ADVANCE_PAUSE
;
281 pending_load
= filename
;
283 amode
= ADVANCE_LOAD
;
284 platform::cancel_wait();
285 platform::set_paused(false);
288 void mark_pending_save(std::string filename
, int smode
, int binary
)
291 if(smode
== SAVE_MOVIE
) {
292 //Just do this immediately.
293 do_save_movie(filename
, binary
);
294 flush_slotinfo(translate_name_mprefix(filename
, tmp
, -1));
297 if(location_special
== SPECIAL_SAVEPOINT
) {
298 //We can save immediately here.
299 do_save_state(filename
, binary
);
300 flush_slotinfo(translate_name_mprefix(filename
, tmp
, -1));
303 queued_saves
.insert(std::make_pair(filename
, binary
));
304 messages
<< "Pending save on '" << filename
<< "'" << std::endl
;
307 struct jukebox_size_listener
: public settingvar::listener
309 jukebox_size_listener(settingvar::group
& _grp
) : grp(_grp
) { grp
.add_listener(*this); }
310 ~jukebox_size_listener() throw() { grp
.remove_listener(*this); };
311 void on_setting_change(settingvar::group
& _grp
, const settingvar::base
& val
)
313 if(val
.get_iname() == "jukebox-size") {
314 if(save_jukebox_pointer
>= (size_t)jukebox_size(_grp
))
315 save_jukebox_pointer
= 0;
317 update_movie_state();
320 settingvar::group
& grp
;
324 void update_movie_state()
326 auto p
= CORE().project
.get();
327 bool readonly
= false;
330 our_rom
.region
->fill_framerate_magic(magic
);
332 CORE().commentary
.frame_number(CORE().mlogic
.get_movie().get_current_frame(),
333 1.0 * magic
[1] / magic
[0]);
335 CORE().commentary
.frame_number(0, 60.0); //Default.
337 auto& _status
= CORE().status
.get_write();
339 if(CORE().mlogic
&& !system_corrupt
) {
340 _status
.movie_valid
= true;
341 _status
.curframe
= CORE().mlogic
.get_movie().get_current_frame();
342 _status
.length
= CORE().mlogic
.get_movie().get_frame_count();
343 _status
.lag
= CORE().mlogic
.get_movie().get_lag_frames();
344 if(location_special
== SPECIAL_FRAME_START
)
345 _status
.subframe
= 0;
346 else if(location_special
== SPECIAL_SAVEPOINT
)
347 _status
.subframe
= _lsnes_status::subframe_savepoint
;
348 else if(location_special
== SPECIAL_FRAME_VIDEO
)
349 _status
.subframe
= _lsnes_status::subframe_video
;
351 _status
.subframe
= CORE().mlogic
.get_movie().next_poll_number();
353 _status
.movie_valid
= false;
354 _status
.curframe
= 0;
357 _status
.subframe
= 0;
359 _status
.dumping
= (information_dispatch::get_dumper_count() > 0);
360 if(amode
== ADVANCE_BREAK_PAUSE
)
361 _status
.pause
= _lsnes_status::pause_break
;
362 else if(amode
== ADVANCE_PAUSE
)
363 _status
.pause
= _lsnes_status::pause_normal
;
365 _status
.pause
= _lsnes_status::pause_none
;
367 auto& mo
= CORE().mlogic
.get_movie();
368 readonly
= mo
.readonly_mode();
373 else if(mo
.get_frame_count() >= mo
.get_current_frame())
378 if(jukebox_size(CORE().settings
) > 0) {
379 _status
.saveslot_valid
= true;
381 std::string sfilen
= translate_name_mprefix(save_jukebox_name(save_jukebox_pointer
), tmp
, -1);
382 _status
.saveslot
= save_jukebox_pointer
+ 1;
383 _status
.slotinfo
= utf8::to32(get_slotinfo(sfilen
));
385 _status
.saveslot_valid
= false;
387 _status
.branch_valid
= (p
!= NULL
);
388 if(p
) _status
.branch
= utf8::to32(p
->get_branch_string());
390 std::string cur_branch
= CORE().mlogic
? CORE().mlogic
.get_mfile().current_branch() :
392 _status
.mbranch_valid
= (cur_branch
!= "");
393 _status
.mbranch
= utf8::to32(cur_branch
);
395 _status
.speed
= (unsigned)(100 * get_realized_multiplier() + 0.5);
397 if(CORE().mlogic
&& !system_corrupt
) {
398 time_t timevalue
= static_cast<time_t>(CORE().mlogic
.get_mfile().rtc_second
);
399 struct tm
* time_decompose
= gmtime(&timevalue
);
400 char datebuffer
[512];
401 strftime(datebuffer
, 511, "%Y%m%d(%a)T%H%M%S", time_decompose
);
402 _status
.rtc
= utf8::to32(datebuffer
);
403 _status
.rtc_valid
= true;
405 _status
.rtc_valid
= false;
408 auto mset
= CORE().controls
.active_macro_set();
410 std::ostringstream mss
;
412 if(!mfirst
) mss
<< ",";
416 _status
.macros
= utf8::to32(mss
.str());
419 if(!CORE().mteditor
.any_records())
420 c
= CORE().mlogic
.get_movie().get_controls();
422 c
= CORE().controls
.get_committed();
423 _status
.inputs
.clear();
424 for(unsigned i
= 0;; i
++) {
425 auto pindex
= CORE().controls
.lcid_to_pcid(i
);
426 if(pindex
.first
< 0 || !CORE().controls
.is_present(pindex
.first
, pindex
.second
))
428 char32_t buffer
[MAX_DISPLAY_LENGTH
];
429 c
.display(pindex
.first
, pindex
.second
, buffer
);
430 std::u32string _buffer
= buffer
;
431 if(readonly
&& CORE().mteditor
.is_enabled()) {
432 multitrack_edit::state st
= CORE().mteditor
.get(pindex
.first
, pindex
.second
);
433 if(st
== multitrack_edit::MT_PRESERVE
)
434 _buffer
+= U
" (keep)";
435 else if(st
== multitrack_edit::MT_OVERWRITE
)
436 _buffer
+= U
" (rewrite)";
437 else if(st
== multitrack_edit::MT_OR
)
439 else if(st
== multitrack_edit::MT_XOR
)
440 _buffer
+= U
" (XOR)";
442 _buffer
+= U
" (\?\?\?)";
444 _status
.inputs
.push_back(_buffer
);
447 _status
.lvars
= get_lua_watch_vars();
449 _status
.mvars
= CORE().mwatch
.get_window_vars();
451 _status
.valid
= true;
454 CORE().status
.put_write();
455 notify_status_update();
458 uint64_t audio_irq_time
;
459 uint64_t controller_irq_time
;
460 uint64_t frame_irq_time
;
463 struct lsnes_callbacks
: public emucore_callbacks
466 ~lsnes_callbacks() throw()
470 int16_t get_input(unsigned port
, unsigned index
, unsigned control
)
473 x
= CORE().mlogic
.input_poll(port
, index
, control
);
474 lua_callback_snoop_input(port
, index
, control
, x
);
478 int16_t set_input(unsigned port
, unsigned index
, unsigned control
, int16_t value
)
480 if(!CORE().mlogic
.get_movie().readonly_mode()) {
481 controller_frame f
= CORE().mlogic
.get_movie().get_controls();
482 f
.axis3(port
, index
, control
, value
);
483 CORE().mlogic
.get_movie().set_controls(f
);
485 return CORE().mlogic
.get_movie().next_input(port
, index
, control
);
488 void notify_latch(std::list
<std::string
>& args
)
490 lua_callback_do_latch(args
);
493 void timer_tick(uint32_t increment
, uint32_t per_second
)
497 auto& m
= CORE().mlogic
.get_mfile();
498 m
.rtc_subsecond
+= increment
;
499 while(m
.rtc_subsecond
>= per_second
) {
501 m
.rtc_subsecond
-= per_second
;
505 std::string
get_firmware_path()
507 return CORE().setcache
.get("firmwarepath");
510 std::string
get_base_path()
512 return our_rom
.msu1_base
;
517 return CORE().mlogic
? CORE().mlogic
.get_mfile().rtc_second
: 0;
520 time_t get_randomseed()
522 return random_seed_value
;
525 void output_frame(framebuffer::raw
& screen
, uint32_t fps_n
, uint32_t fps_d
)
527 lua_callback_do_frame_emulated();
528 location_special
= SPECIAL_FRAME_VIDEO
;
529 redraw_framebuffer(screen
, false, true);
530 uint32_t g
= gcd(fps_n
, fps_d
);
533 information_dispatch::do_frame(screen
, fps_n
, fps_d
);
536 void action_state_updated()
538 graphics_driver_action_updated();
541 void memory_read(uint64_t addr
, uint64_t value
)
543 debug_fire_callback_read(addr
, value
);
546 void memory_write(uint64_t addr
, uint64_t value
)
548 debug_fire_callback_write(addr
, value
);
551 void memory_execute(uint64_t addr
, uint64_t proc
)
553 debug_fire_callback_exec(addr
, proc
);
556 void memory_trace(uint64_t proc
, const char* str
, bool insn
)
558 debug_fire_callback_trace(proc
, str
, insn
);
564 lsnes_callbacks lsnes_callbacks_obj
;
566 command::fnptr
<const std::string
&> test4(lsnes_cmds
, "test4", "test", "test",
567 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
568 std::list
<std::string
> _args
;
569 std::string args2
= args
;
570 for(auto& sym
: token_iterator_foreach(args
, {" ", "\t"}))
571 _args
.push_back(sym
);
572 lua_callback_do_latch(_args
);
574 command::fnptr
<> count_rerecords(lsnes_cmds
, "count-rerecords", "Count rerecords",
575 "Syntax: count-rerecords\nCounts rerecords.\n",
576 []() throw(std::bad_alloc
, std::runtime_error
) {
577 std::vector
<char> tmp
;
578 uint64_t x
= CORE().mlogic
.get_rrdata().write(tmp
);
579 messages
<< x
<< " rerecord(s)" << std::endl
;
582 command::fnptr
<const std::string
&> quit_emulator(lsnes_cmds
, "quit-emulator", "Quit the emulator",
583 "Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n",
584 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
585 amode
= ADVANCE_QUIT
;
586 quit_magic
= QUIT_MAGIC
;
587 platform::set_paused(false);
588 platform::cancel_wait();
591 command::fnptr
<> unpause_emulator(lsnes_cmds
, "unpause-emulator", "Unpause the emulator",
592 "Syntax: unpause-emulator\nUnpauses the emulator.\n",
593 []() throw(std::bad_alloc
, std::runtime_error
) {
594 amode
= ADVANCE_AUTO
;
595 platform::set_paused(false);
596 platform::cancel_wait();
599 command::fnptr
<> pause_emulator(lsnes_cmds
, "pause-emulator", "(Un)pause the emulator",
600 "Syntax: pause-emulator\n(Un)pauses the emulator.\n",
601 []() throw(std::bad_alloc
, std::runtime_error
) {
602 if(amode
!= ADVANCE_AUTO
) {
603 amode
= ADVANCE_AUTO
;
604 platform::set_paused(false);
605 platform::cancel_wait();
607 platform::cancel_wait();
608 cancel_advance
= false;
609 stop_at_frame_active
= false;
610 amode
= ADVANCE_PAUSE
;
614 command::fnptr
<> save_jukebox_prev(lsnes_cmds
, "cycle-jukebox-backward", "Cycle save jukebox backwards",
615 "Syntax: cycle-jukebox-backward\nCycle save jukebox backwards\n",
616 []() throw(std::bad_alloc
, std::runtime_error
) {
617 size_t jbsize
= jukebox_size(CORE().settings
);
620 if(save_jukebox_pointer
== 0)
621 save_jukebox_pointer
= jbsize
- 1;
623 save_jukebox_pointer
--;
624 if(save_jukebox_pointer
>= (size_t)jbsize
)
625 save_jukebox_pointer
= 0;
626 update_movie_state();
629 command::fnptr
<> save_jukebox_next(lsnes_cmds
, "cycle-jukebox-forward", "Cycle save jukebox forwards",
630 "Syntax: cycle-jukebox-forward\nCycle save jukebox forwards\n",
631 []() throw(std::bad_alloc
, std::runtime_error
) {
632 size_t jbsize
= jukebox_size(CORE().settings
);
635 if(save_jukebox_pointer
+ 1 >= (size_t)jbsize
)
636 save_jukebox_pointer
= 0;
638 save_jukebox_pointer
++;
639 if(save_jukebox_pointer
>= (size_t)jbsize
)
640 save_jukebox_pointer
= 0;
641 update_movie_state();
644 command::fnptr
<const std::string
&> save_jukebox_set(lsnes_cmds
, "set-jukebox-slot", "Set jukebox slot",
645 "Syntax: set-jukebox-slot\nSet jukebox slot\n", [](const std::string
& args
)
646 throw(std::bad_alloc
, std::runtime_error
) {
647 if(!regex_match("[1-9][0-9]{0,8}", args
))
648 throw std::runtime_error("Bad slot number");
649 uint32_t slot
= parse_value
<uint32_t>(args
);
650 if(slot
>= (size_t)jukebox_size(CORE().settings
))
651 throw std::runtime_error("Bad slot number");
652 save_jukebox_pointer
= slot
- 1;
653 update_movie_state();
656 command::fnptr
<> load_jukebox(lsnes_cmds
, "load-jukebox", "Load save from jukebox",
657 "Syntax: load-jukebox\nLoad save from jukebox\n",
658 []() throw(std::bad_alloc
, std::runtime_error
) {
659 if(jukebox_size(CORE().settings
) == 0)
660 throw std::runtime_error("No slot selected");
661 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_CURRENT
);
664 command::fnptr
<> load_jukebox_readwrite(lsnes_cmds
, "load-jukebox-readwrite", "Load save from jukebox in"
665 " recording mode", "Syntax: load-jukebox-readwrite\nLoad save from jukebox in recording mode\n",
666 []() throw(std::bad_alloc
, std::runtime_error
) {
667 if(jukebox_size(CORE().settings
) == 0)
668 throw std::runtime_error("No slot selected");
669 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_RW
);
672 command::fnptr
<> load_jukebox_readonly(lsnes_cmds
, "load-jukebox-readonly", "Load save from jukebox in "
673 "playback mode", "Syntax: load-jukebox-readonly\nLoad save from jukebox in playback mode\n",
674 []() throw(std::bad_alloc
, std::runtime_error
) {
675 if(jukebox_size(CORE().settings
) == 0)
676 throw std::runtime_error("No slot selected");
677 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_RO
);
680 command::fnptr
<> load_jukebox_preserve(lsnes_cmds
, "load-jukebox-preserve", "Load save from jukebox, "
681 "preserving input", "Syntax: load-jukebox-preserve\nLoad save from jukebox, preserving input\n",
682 []() throw(std::bad_alloc
, std::runtime_error
) {
683 if(jukebox_size(CORE().settings
) == 0)
684 throw std::runtime_error("No slot selected");
685 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_PRESERVE
);
688 command::fnptr
<> load_jukebox_movie(lsnes_cmds
, "load-jukebox-movie", "Load save from jukebox as movie",
689 "Syntax: load-jukebox-movie\nLoad save from jukebox as movie\n",
690 []() throw(std::bad_alloc
, std::runtime_error
) {
691 if(jukebox_size(CORE().settings
) == 0)
692 throw std::runtime_error("No slot selected");
693 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_MOVIE
);
696 command::fnptr
<> save_jukebox_c(lsnes_cmds
, "save-jukebox", "Save save to jukebox",
697 "Syntax: save-jukebox\nSave save to jukebox\n",
698 []() throw(std::bad_alloc
, std::runtime_error
) {
699 if(jukebox_size(CORE().settings
) == 0)
700 throw std::runtime_error("No slot selected");
701 mark_pending_save(save_jukebox_name(save_jukebox_pointer
), SAVE_STATE
, -1);
704 command::fnptr
<> padvance_frame(lsnes_cmds
, "+advance-frame", "Advance one frame",
705 "Syntax: +advance-frame\nAdvances the emulation by one frame.\n",
706 []() throw(std::bad_alloc
, std::runtime_error
) {
707 amode
= ADVANCE_FRAME
;
708 cancel_advance
= false;
709 advanced_once
= false;
710 platform::cancel_wait();
711 platform::set_paused(false);
714 command::fnptr
<> nadvance_frame(lsnes_cmds
, "-advance-frame", "Advance one frame",
715 "No help available\n",
716 []() throw(std::bad_alloc
, std::runtime_error
) {
717 cancel_advance
= true;
718 platform::cancel_wait();
719 platform::set_paused(false);
722 command::fnptr
<> padvance_poll(lsnes_cmds
, "+advance-poll", "Advance one subframe",
723 "Syntax: +advance-poll\nAdvances the emulation by one subframe.\n",
724 []() throw(std::bad_alloc
, std::runtime_error
) {
725 amode
= ADVANCE_SUBFRAME
;
726 cancel_advance
= false;
727 advanced_once
= false;
728 platform::cancel_wait();
729 platform::set_paused(false);
732 command::fnptr
<> nadvance_poll(lsnes_cmds
, "-advance-poll", "Advance one subframe",
733 "No help available\n",
734 []() throw(std::bad_alloc
, std::runtime_error
) {
735 if(amode
== ADVANCE_BREAK_PAUSE
)
736 amode
= ADVANCE_PAUSE
;
737 cancel_advance
= true;
738 platform::cancel_wait();
739 platform::set_paused(false);
742 command::fnptr
<> advance_skiplag(lsnes_cmds
, "advance-skiplag", "Skip to next poll",
743 "Syntax: advance-skiplag\nAdvances the emulation to the next poll.\n",
744 []() throw(std::bad_alloc
, std::runtime_error
) {
745 amode
= ADVANCE_SKIPLAG_PENDING
;
746 platform::cancel_wait();
747 platform::set_paused(false);
750 command::fnptr
<> reset_c(lsnes_cmds
, "reset", "Reset the system",
751 "Syntax: reset\nReset\nResets the system in beginning of the next frame.\n",
752 []() throw(std::bad_alloc
, std::runtime_error
) {
753 int sreset_action
= our_rom
.rtype
->reset_action(false);
754 if(sreset_action
< 0) {
755 platform::error_message("Core does not support resets");
756 messages
<< "Emulator core does not support resets" << std::endl
;
759 our_rom
.rtype
->execute_action(sreset_action
, std::vector
<interface_action_paramval
>());
762 command::fnptr
<> hreset_c(lsnes_cmds
, "reset-hard", "Reset the system",
763 "Syntax: reset-hard\nReset-hard\nHard resets the system in beginning of the next frame.\n",
764 []() throw(std::bad_alloc
, std::runtime_error
) {
765 int hreset_action
= our_rom
.rtype
->reset_action(true);
766 if(hreset_action
< 0) {
767 platform::error_message("Core does not support hard resets");
768 messages
<< "Emulator core does not support hard resets" << std::endl
;
771 our_rom
.rtype
->execute_action(hreset_action
, std::vector
<interface_action_paramval
>());
774 command::fnptr
<command::arg_filename
> load_c(lsnes_cmds
, "load", "Load savestate (current mode)",
775 "Syntax: load <file>\nLoads SNES state from <file> in current mode\n",
776 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
777 mark_pending_load(args
, LOAD_STATE_CURRENT
);
780 command::fnptr
<command::arg_filename
> load_smart_c(lsnes_cmds
, "load-smart",
781 "Load savestate (heuristic mode)",
782 "Syntax: load <file>\nLoads SNES state from <file> in heuristic mode\n",
783 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
784 mark_pending_load(args
, LOAD_STATE_DEFAULT
);
787 command::fnptr
<command::arg_filename
> load_state_c(lsnes_cmds
, "load-state", "Load savestate (R/W)",
788 "Syntax: load-state <file>\nLoads SNES state from <file> in Read/Write mode\n",
789 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
790 mark_pending_load(args
, LOAD_STATE_RW
);
793 command::fnptr
<command::arg_filename
> load_readonly(lsnes_cmds
, "load-readonly", "Load savestate (RO)",
794 "Syntax: load-readonly <file>\nLoads SNES state from <file> in playback mode\n",
795 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
796 mark_pending_load(args
, LOAD_STATE_RO
);
799 command::fnptr
<command::arg_filename
> load_preserve(lsnes_cmds
, "load-preserve", "Load savestate (preserve "
800 "input)", "Syntax: load-preserve <file>\nLoads SNES state from <file> preserving input\n",
801 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
802 mark_pending_load(args
, LOAD_STATE_PRESERVE
);
805 command::fnptr
<command::arg_filename
> load_movie_c(lsnes_cmds
, "load-movie", "Load movie",
806 "Syntax: load-movie <file>\nLoads SNES movie from <file>\n",
807 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
808 mark_pending_load(args
, LOAD_STATE_MOVIE
);
811 command::fnptr
<command::arg_filename
> load_allbr_c(lsnes_cmds
, "load-allbranches", "Load savestate "
812 "(all branches)", "Syntax: load-allbranches <file>\nLoads SNES state from <file> with all "
814 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
815 mark_pending_load(args
, LOAD_STATE_ALLBRANCH
);
818 command::fnptr
<command::arg_filename
> save_state(lsnes_cmds
, "save-state", "Save state",
819 "Syntax: save-state <file>\nSaves SNES state to <file>\n",
820 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
821 mark_pending_save(args
, SAVE_STATE
, -1);
824 command::fnptr
<command::arg_filename
> save_state2(lsnes_cmds
, "save-state-binary", "Save state (binary)",
825 "Syntax: save-state-binary <file>\nSaves binary state to <file>\n",
826 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
827 mark_pending_save(args
, SAVE_STATE
, 1);
830 command::fnptr
<command::arg_filename
> save_state3(lsnes_cmds
, "save-state-zip", "Save state (zip)",
831 "Syntax: save-state-zip <file>\nSaves zip state to <file>\n",
832 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
833 mark_pending_save(args
, SAVE_STATE
, 0);
836 command::fnptr
<command::arg_filename
> save_movie(lsnes_cmds
, "save-movie", "Save movie",
837 "Syntax: save-movie <file>\nSaves SNES movie to <file>\n",
838 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
839 mark_pending_save(args
, SAVE_MOVIE
, -1);
842 command::fnptr
<command::arg_filename
> save_movie2(lsnes_cmds
, "save-movie-binary", "Save movie (binary)",
843 "Syntax: save-movie-binary <file>\nSaves binary movie to <file>\n",
844 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
845 mark_pending_save(args
, SAVE_MOVIE
, 1);
848 command::fnptr
<command::arg_filename
> save_movie3(lsnes_cmds
, "save-movie-zip", "Save movie (zip)",
849 "Syntax: save-movie-zip <file>\nSaves zip movie to <file>\n",
850 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
851 mark_pending_save(args
, SAVE_MOVIE
, 0);
854 command::fnptr
<> set_rwmode(lsnes_cmds
, "set-rwmode", "Switch to recording mode",
855 "Syntax: set-rwmode\nSwitches to recording mode\n",
856 []() throw(std::bad_alloc
, std::runtime_error
) {
857 lua_callback_movie_lost("readwrite");
858 CORE().mlogic
.get_movie().readonly_mode(false);
859 notify_mode_change(false);
860 lua_callback_do_readwrite();
861 update_movie_state();
864 command::fnptr
<> set_romode(lsnes_cmds
, "set-romode", "Switch to playback mode",
865 "Syntax: set-romode\nSwitches to playback mode\n",
866 []() throw(std::bad_alloc
, std::runtime_error
) {
867 CORE().mlogic
.get_movie().readonly_mode(true);
868 notify_mode_change(true);
869 update_movie_state();
872 command::fnptr
<> toggle_rwmode(lsnes_cmds
, "toggle-rwmode", "Toggle recording mode",
873 "Syntax: toggle-rwmode\nToggles recording mode\n",
874 []() throw(std::bad_alloc
, std::runtime_error
) {
875 bool c
= CORE().mlogic
.get_movie().readonly_mode();
877 lua_callback_movie_lost("readwrite");
878 CORE().mlogic
.get_movie().readonly_mode(!c
);
879 notify_mode_change(!c
);
881 lua_callback_do_readwrite();
882 update_movie_state();
885 command::fnptr
<> repaint(lsnes_cmds
, "repaint", "Redraw the screen",
886 "Syntax: repaint\nRedraws the screen\n",
887 []() throw(std::bad_alloc
, std::runtime_error
) {
888 redraw_framebuffer();
891 command::fnptr
<> tpon(lsnes_cmds
, "toggle-pause-on-end", "Toggle pause on end", "Toggle pause on end\n",
892 []() throw(std::bad_alloc
, std::runtime_error
) {
893 bool tmp
= pause_on_end(CORE().settings
);
894 pause_on_end(CORE().settings
, !tmp
);
895 messages
<< "Pause-on-end is now " << (tmp
? "OFF" : "ON") << std::endl
;
898 command::fnptr
<> spon(lsnes_cmds
, "set-pause-on-end", "Set pause on end", "Set pause on end\n",
899 []() throw(std::bad_alloc
, std::runtime_error
) {
900 pause_on_end(CORE().settings
, true);
901 messages
<< "Pause-on-end is now ON" << std::endl
;
904 command::fnptr
<> cpon(lsnes_cmds
, "clear-pause-on-end", "Clear pause on end", "Clear pause on end\n",
905 []() throw(std::bad_alloc
, std::runtime_error
) {
906 pause_on_end(CORE().settings
, false);
907 messages
<< "Pause-on-end is now OFF" << std::endl
;
910 command::fnptr
<> rewind_movie(lsnes_cmds
, "rewind-movie", "Rewind movie to the beginning",
911 "Syntax: rewind-movie\nRewind movie to the beginning\n",
912 []() throw(std::bad_alloc
, std::runtime_error
) {
913 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_BEGINNING
);
916 command::fnptr
<> cancel_save(lsnes_cmds
, "cancel-saves", "Cancel all pending saves", "Syntax: "
917 "cancel-save\nCancel pending saves\n",
918 []() throw(std::bad_alloc
, std::runtime_error
) {
919 queued_saves
.clear();
920 messages
<< "Pending saves canceled." << std::endl
;
923 command::fnptr
<> flushslots(lsnes_cmds
, "flush-slotinfo", "Flush slotinfo cache",
924 "Flush slotinfo cache\n",
925 []() throw(std::bad_alloc
, std::runtime_error
) {
929 command::fnptr
<> mhold1(lsnes_cmds
, "+hold-macro", "Hold macro (hold)",
930 "Hold macros enable\n", []() throw(std::bad_alloc
, std::runtime_error
) {
934 command::fnptr
<> mhold2(lsnes_cmds
, "-hold-macro", "Hold macro (hold)",
935 "Hold macros disable\n", []() throw(std::bad_alloc
, std::runtime_error
) {
936 macro_hold_1
= false;
939 command::fnptr
<> mhold3(lsnes_cmds
, "hold-macro", "Hold macro (toggle)",
940 "Hold macros toggle\n", []() throw(std::bad_alloc
, std::runtime_error
) {
941 macro_hold_2
= !macro_hold_2
;
943 messages
<< "Macros are held for next frame." << std::endl
;
945 messages
<< "Macros are not held for next frame." << std::endl
;
948 keyboard::invbind_info
imhold1(lsnes_invbinds
, "+hold-macro", "Macro‣Hold all macros");
949 keyboard::invbind_info
imhold2(lsnes_invbinds
, "hold-macro", "Macro‣Hold all macros (typed)");
950 keyboard::invbind_info
ipause_emulator(lsnes_invbinds
, "pause-emulator", "Speed‣(Un)pause");
951 keyboard::invbind_info
ijback(lsnes_invbinds
, "cycle-jukebox-backward", "Slot select‣Cycle backwards");
952 keyboard::invbind_info
ijforward(lsnes_invbinds
, "cycle-jukebox-forward", "Slot select‣Cycle forwards");
953 keyboard::invbind_info
iloadj(lsnes_invbinds
, "load-jukebox", "Load‣Selected slot");
954 keyboard::invbind_info
iloadjrw(lsnes_invbinds
, "load-jukebox-readwrite",
955 "Load‣Selected slot (recording mode)");
956 keyboard::invbind_info
iloadjro(lsnes_invbinds
, "load-jukebox-readonly",
957 "Load‣Selected slot (playback mode)");
958 keyboard::invbind_info
iloadjp(lsnes_invbinds
, "load-jukebox-preserve",
959 "Load‣Selected slot (preserve input)");
960 keyboard::invbind_info
iloadjm(lsnes_invbinds
, "load-jukebox-movie", "Load‣Selected slot (as movie)");
961 keyboard::invbind_info
isavej(lsnes_invbinds
, "save-jukebox", "Save‣Selected slot");
962 keyboard::invbind_info
iadvframe(lsnes_invbinds
, "+advance-frame", "Speed‣Advance frame");
963 keyboard::invbind_info
iadvsubframe(lsnes_invbinds
, "+advance-poll", "Speed‣Advance subframe");
964 keyboard::invbind_info
iskiplag(lsnes_invbinds
, "advance-skiplag", "Speed‣Advance poll");
965 keyboard::invbind_info
ireset(lsnes_invbinds
, "reset", "System‣Reset");
966 keyboard::invbind_info
iset_rwmode(lsnes_invbinds
, "set-rwmode", "Movie‣Switch to recording");
967 keyboard::invbind_info
itoggle_romode(lsnes_invbinds
, "set-romode", "Movie‣Switch to playback");
968 keyboard::invbind_info
itoggle_rwmode(lsnes_invbinds
, "toggle-rwmode", "Movie‣Toggle playback");
969 keyboard::invbind_info
irepaint(lsnes_invbinds
, "repaint", "System‣Repaint screen");
970 keyboard::invbind_info
itogglepause(lsnes_invbinds
, "toggle-pause-on-end", "Movie‣Toggle pause-on-end");
971 keyboard::invbind_info
irewind_movie(lsnes_invbinds
, "rewind-movie", "Movie‣Rewind movie");
972 keyboard::invbind_info
icancel_saves(lsnes_invbinds
, "cancel-saves", "Save‣Cancel pending saves");
973 keyboard::invbind_info
iload1(lsnes_invbinds
, "load $SLOT:1", "Load‣Slot 1");
974 keyboard::invbind_info
iload2(lsnes_invbinds
, "load $SLOT:2", "Load‣Slot 2");
975 keyboard::invbind_info
iload3(lsnes_invbinds
, "load $SLOT:3", "Load‣Slot 3");
976 keyboard::invbind_info
iload4(lsnes_invbinds
, "load $SLOT:4", "Load‣Slot 4");
977 keyboard::invbind_info
iload5(lsnes_invbinds
, "load $SLOT:5", "Load‣Slot 5");
978 keyboard::invbind_info
iload6(lsnes_invbinds
, "load $SLOT:6", "Load‣Slot 6");
979 keyboard::invbind_info
iload7(lsnes_invbinds
, "load $SLOT:7", "Load‣Slot 7");
980 keyboard::invbind_info
iload8(lsnes_invbinds
, "load $SLOT:8", "Load‣Slot 8");
981 keyboard::invbind_info
iload9(lsnes_invbinds
, "load $SLOT:9", "Load‣Slot 9");
982 keyboard::invbind_info
iload10(lsnes_invbinds
, "load $SLOT:10", "Load‣Slot 10");
983 keyboard::invbind_info
iload11(lsnes_invbinds
, "load $SLOT:11", "Load‣Slot 11");
984 keyboard::invbind_info
iload12(lsnes_invbinds
, "load $SLOT:12", "Load‣Slot 12");
985 keyboard::invbind_info
iload13(lsnes_invbinds
, "load $SLOT:13", "Load‣Slot 13");
986 keyboard::invbind_info
iload14(lsnes_invbinds
, "load $SLOT:14", "Load‣Slot 14");
987 keyboard::invbind_info
iload15(lsnes_invbinds
, "load $SLOT:15", "Load‣Slot 15");
988 keyboard::invbind_info
iload16(lsnes_invbinds
, "load $SLOT:16", "Load‣Slot 16");
989 keyboard::invbind_info
iload17(lsnes_invbinds
, "load $SLOT:17", "Load‣Slot 17");
990 keyboard::invbind_info
iload18(lsnes_invbinds
, "load $SLOT:18", "Load‣Slot 18");
991 keyboard::invbind_info
iload19(lsnes_invbinds
, "load $SLOT:19", "Load‣Slot 19");
992 keyboard::invbind_info
iload20(lsnes_invbinds
, "load $SLOT:20", "Load‣Slot 20");
993 keyboard::invbind_info
iload21(lsnes_invbinds
, "load $SLOT:21", "Load‣Slot 21");
994 keyboard::invbind_info
iload22(lsnes_invbinds
, "load $SLOT:22", "Load‣Slot 22");
995 keyboard::invbind_info
iload23(lsnes_invbinds
, "load $SLOT:23", "Load‣Slot 23");
996 keyboard::invbind_info
iload24(lsnes_invbinds
, "load $SLOT:24", "Load‣Slot 24");
997 keyboard::invbind_info
iload25(lsnes_invbinds
, "load $SLOT:25", "Load‣Slot 25");
998 keyboard::invbind_info
iload26(lsnes_invbinds
, "load $SLOT:26", "Load‣Slot 26");
999 keyboard::invbind_info
iload27(lsnes_invbinds
, "load $SLOT:27", "Load‣Slot 27");
1000 keyboard::invbind_info
iload28(lsnes_invbinds
, "load $SLOT:28", "Load‣Slot 28");
1001 keyboard::invbind_info
iload29(lsnes_invbinds
, "load $SLOT:29", "Load‣Slot 29");
1002 keyboard::invbind_info
iload30(lsnes_invbinds
, "load $SLOT:30", "Load‣Slot 30");
1003 keyboard::invbind_info
iload31(lsnes_invbinds
, "load $SLOT:31", "Load‣Slot 31");
1004 keyboard::invbind_info
iload32(lsnes_invbinds
, "load $SLOT:32", "Load‣Slot 32");
1005 keyboard::invbind_info
isave1(lsnes_invbinds
, "save-state $SLOT:1", "Save‣Slot 1");
1006 keyboard::invbind_info
isave2(lsnes_invbinds
, "save-state $SLOT:2", "Save‣Slot 2");
1007 keyboard::invbind_info
isave3(lsnes_invbinds
, "save-state $SLOT:3", "Save‣Slot 3");
1008 keyboard::invbind_info
isave4(lsnes_invbinds
, "save-state $SLOT:4", "Save‣Slot 4");
1009 keyboard::invbind_info
isave5(lsnes_invbinds
, "save-state $SLOT:5", "Save‣Slot 5");
1010 keyboard::invbind_info
isave6(lsnes_invbinds
, "save-state $SLOT:6", "Save‣Slot 6");
1011 keyboard::invbind_info
isave7(lsnes_invbinds
, "save-state $SLOT:7", "Save‣Slot 7");
1012 keyboard::invbind_info
isave8(lsnes_invbinds
, "save-state $SLOT:8", "Save‣Slot 8");
1013 keyboard::invbind_info
isave9(lsnes_invbinds
, "save-state $SLOT:9", "Save‣Slot 9");
1014 keyboard::invbind_info
isave10(lsnes_invbinds
, "save-state $SLOT:10", "Save‣Slot 10");
1015 keyboard::invbind_info
isave11(lsnes_invbinds
, "save-state $SLOT:11", "Save‣Slot 11");
1016 keyboard::invbind_info
isave12(lsnes_invbinds
, "save-state $SLOT:12", "Save‣Slot 12");
1017 keyboard::invbind_info
isave13(lsnes_invbinds
, "save-state $SLOT:13", "Save‣Slot 13");
1018 keyboard::invbind_info
isave14(lsnes_invbinds
, "save-state $SLOT:14", "Save‣Slot 14");
1019 keyboard::invbind_info
isave15(lsnes_invbinds
, "save-state $SLOT:15", "Save‣Slot 15");
1020 keyboard::invbind_info
isave16(lsnes_invbinds
, "save-state $SLOT:16", "Save‣Slot 16");
1021 keyboard::invbind_info
isave17(lsnes_invbinds
, "save-state $SLOT:17", "Save‣Slot 17");
1022 keyboard::invbind_info
isave18(lsnes_invbinds
, "save-state $SLOT:18", "Save‣Slot 18");
1023 keyboard::invbind_info
isave19(lsnes_invbinds
, "save-state $SLOT:19", "Save‣Slot 19");
1024 keyboard::invbind_info
isave20(lsnes_invbinds
, "save-state $SLOT:20", "Save‣Slot 20");
1025 keyboard::invbind_info
isave21(lsnes_invbinds
, "save-state $SLOT:21", "Save‣Slot 21");
1026 keyboard::invbind_info
isave22(lsnes_invbinds
, "save-state $SLOT:22", "Save‣Slot 22");
1027 keyboard::invbind_info
isave23(lsnes_invbinds
, "save-state $SLOT:23", "Save‣Slot 23");
1028 keyboard::invbind_info
isave24(lsnes_invbinds
, "save-state $SLOT:24", "Save‣Slot 24");
1029 keyboard::invbind_info
isave25(lsnes_invbinds
, "save-state $SLOT:25", "Save‣Slot 25");
1030 keyboard::invbind_info
isave26(lsnes_invbinds
, "save-state $SLOT:26", "Save‣Slot 26");
1031 keyboard::invbind_info
isave27(lsnes_invbinds
, "save-state $SLOT:27", "Save‣Slot 27");
1032 keyboard::invbind_info
isave28(lsnes_invbinds
, "save-state $SLOT:28", "Save‣Slot 28");
1033 keyboard::invbind_info
isave29(lsnes_invbinds
, "save-state $SLOT:29", "Save‣Slot 29");
1034 keyboard::invbind_info
isave30(lsnes_invbinds
, "save-state $SLOT:30", "Save‣Slot 30");
1035 keyboard::invbind_info
isave31(lsnes_invbinds
, "save-state $SLOT:31", "Save‣Slot 31");
1036 keyboard::invbind_info
isave32(lsnes_invbinds
, "save-state $SLOT:32", "Save‣Slot 32");
1037 keyboard::invbind_info
islot1(lsnes_invbinds
, "set-jukebox-slot 1", "Slot select‣Slot 1");
1038 keyboard::invbind_info
islot2(lsnes_invbinds
, "set-jukebox-slot 2", "Slot select‣Slot 2");
1039 keyboard::invbind_info
islot3(lsnes_invbinds
, "set-jukebox-slot 3", "Slot select‣Slot 3");
1040 keyboard::invbind_info
islot4(lsnes_invbinds
, "set-jukebox-slot 4", "Slot select‣Slot 4");
1041 keyboard::invbind_info
islot5(lsnes_invbinds
, "set-jukebox-slot 5", "Slot select‣Slot 5");
1042 keyboard::invbind_info
islot6(lsnes_invbinds
, "set-jukebox-slot 6", "Slot select‣Slot 6");
1043 keyboard::invbind_info
islot7(lsnes_invbinds
, "set-jukebox-slot 7", "Slot select‣Slot 7");
1044 keyboard::invbind_info
islot8(lsnes_invbinds
, "set-jukebox-slot 8", "Slot select‣Slot 8");
1045 keyboard::invbind_info
islot9(lsnes_invbinds
, "set-jukebox-slot 9", "Slot select‣Slot 9");
1046 keyboard::invbind_info
islot10(lsnes_invbinds
, "set-jukebox-slot 10", "Slot select‣Slot 10");
1047 keyboard::invbind_info
islot11(lsnes_invbinds
, "set-jukebox-slot 11", "Slot select‣Slot 11");
1048 keyboard::invbind_info
islot12(lsnes_invbinds
, "set-jukebox-slot 12", "Slot select‣Slot 12");
1049 keyboard::invbind_info
islot13(lsnes_invbinds
, "set-jukebox-slot 13", "Slot select‣Slot 13");
1050 keyboard::invbind_info
islot14(lsnes_invbinds
, "set-jukebox-slot 14", "Slot select‣Slot 14");
1051 keyboard::invbind_info
islot15(lsnes_invbinds
, "set-jukebox-slot 15", "Slot select‣Slot 15");
1052 keyboard::invbind_info
islot16(lsnes_invbinds
, "set-jukebox-slot 16", "Slot select‣Slot 16");
1053 keyboard::invbind_info
islot17(lsnes_invbinds
, "set-jukebox-slot 17", "Slot select‣Slot 17");
1054 keyboard::invbind_info
islot18(lsnes_invbinds
, "set-jukebox-slot 18", "Slot select‣Slot 18");
1055 keyboard::invbind_info
islot19(lsnes_invbinds
, "set-jukebox-slot 19", "Slot select‣Slot 19");
1056 keyboard::invbind_info
islot20(lsnes_invbinds
, "set-jukebox-slot 20", "Slot select‣Slot 20");
1057 keyboard::invbind_info
islot21(lsnes_invbinds
, "set-jukebox-slot 21", "Slot select‣Slot 21");
1058 keyboard::invbind_info
islot22(lsnes_invbinds
, "set-jukebox-slot 22", "Slot select‣Slot 22");
1059 keyboard::invbind_info
islot23(lsnes_invbinds
, "set-jukebox-slot 23", "Slot select‣Slot 23");
1060 keyboard::invbind_info
islot24(lsnes_invbinds
, "set-jukebox-slot 24", "Slot select‣Slot 24");
1061 keyboard::invbind_info
islot25(lsnes_invbinds
, "set-jukebox-slot 25", "Slot select‣Slot 25");
1062 keyboard::invbind_info
islot26(lsnes_invbinds
, "set-jukebox-slot 26", "Slot select‣Slot 26");
1063 keyboard::invbind_info
islot27(lsnes_invbinds
, "set-jukebox-slot 27", "Slot select‣Slot 27");
1064 keyboard::invbind_info
islot28(lsnes_invbinds
, "set-jukebox-slot 28", "Slot select‣Slot 28");
1065 keyboard::invbind_info
islot29(lsnes_invbinds
, "set-jukebox-slot 29", "Slot select‣Slot 29");
1066 keyboard::invbind_info
islot30(lsnes_invbinds
, "set-jukebox-slot 30", "Slot select‣Slot 30");
1067 keyboard::invbind_info
islot31(lsnes_invbinds
, "set-jukebox-slot 31", "Slot select‣Slot 31");
1068 keyboard::invbind_info
islot32(lsnes_invbinds
, "set-jukebox-slot 32", "Slot select‣Slot 32");
1070 bool on_quit_prompt
= false;
1071 class mywindowcallbacks
: public information_dispatch
1074 mywindowcallbacks() : information_dispatch("mainloop-window-callbacks")
1076 closenotify
.set(notify_close
, [this]() {
1077 if(on_quit_prompt
) {
1078 amode
= ADVANCE_QUIT
;
1079 quit_magic
= QUIT_MAGIC
;
1080 platform::set_paused(false);
1081 platform::cancel_wait();
1084 on_quit_prompt
= true;
1086 amode
= ADVANCE_QUIT
;
1087 quit_magic
= QUIT_MAGIC
;
1088 platform::set_paused(false);
1089 platform::cancel_wait();
1092 on_quit_prompt
= false;
1095 ~mywindowcallbacks() throw() {}
1096 void on_new_dumper(const std::string
& n
)
1098 update_movie_state();
1100 void on_destroy_dumper(const std::string
& n
)
1102 update_movie_state();
1105 struct dispatch::target
<> closenotify
;
1108 //If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
1112 std::string old_project
= CORE().mlogic
? CORE().mlogic
.get_mfile().projectid
: "";
1114 if(do_unsafe_rewind
&& unsafe_rewind_obj
) {
1117 uint64_t t
= get_utime();
1118 std::vector
<char> s
;
1119 lua_callback_do_unsafe_rewind(s
, 0, 0, CORE().mlogic
.get_movie(), unsafe_rewind_obj
);
1120 notify_mode_change(false);
1121 do_unsafe_rewind
= false;
1122 CORE().mlogic
.get_mfile().is_savestate
= true;
1123 location_special
= SPECIAL_SAVEPOINT
;
1124 update_movie_state();
1125 messages
<< "Rewind done in " << (get_utime() - t
) << " usec." << std::endl
;
1128 if(pending_new_project
!= "") {
1129 std::string id
= pending_new_project
;
1130 pending_new_project
= "";
1131 project_info
* old
= CORE().project
.get();
1132 if(old
&& old
->id
== id
)
1135 auto& p
= CORE().project
.load(id
);
1136 CORE().project
.set(&p
);
1137 if(CORE().project
.get() != old
)
1139 flush_slotinfo(); //Wrong movie may be stale.
1141 } catch(std::exception
& e
) {
1142 platform::error_message(std::string("Can't switch projects: ") + e
.what());
1143 messages
<< "Can't switch projects: " << e
.what() << std::endl
;
1148 platform::set_paused(amode
== ADVANCE_PAUSE
);
1149 platform::flush_command_queue();
1150 if(amode
== ADVANCE_LOAD
)
1154 if(pending_load
!= "") {
1155 bool system_was_corrupt
= system_corrupt
;
1156 system_corrupt
= false;
1158 if(loadmode
!= LOAD_STATE_BEGINNING
&& loadmode
!= LOAD_STATE_ROMRELOAD
&&
1159 !do_load_state(pending_load
, loadmode
)) {
1160 if(system_was_corrupt
)
1161 system_corrupt
= system_was_corrupt
;
1165 if(loadmode
== LOAD_STATE_BEGINNING
)
1167 if(loadmode
== LOAD_STATE_ROMRELOAD
)
1169 } catch(std::exception
& e
) {
1170 if(!system_corrupt
&& system_was_corrupt
)
1171 system_corrupt
= true;
1172 platform::error_message(std::string("Load failed: ") + e
.what());
1173 messages
<< "Load failed: " << e
.what() << std::endl
;
1176 amode
= load_paused
? ADVANCE_PAUSE
: ADVANCE_AUTO
;
1177 platform::set_paused(load_paused
);
1178 load_paused
= false;
1179 if(!system_corrupt
) {
1180 location_special
= SPECIAL_SAVEPOINT
;
1181 update_movie_state();
1182 platform::flush_command_queue();
1185 if(amode
== ADVANCE_LOAD
)
1188 if(old_project
!= (CORE().mlogic
? CORE().mlogic
.get_mfile().projectid
: ""))
1189 flush_slotinfo(); //Wrong movie may be stale.
1195 //If there are pending saves, perform them.
1200 if(!queued_saves
.empty() || (do_unsafe_rewind
&& !unsafe_rewind_obj
)) {
1201 our_rom
.rtype
->runtosave();
1202 for(auto i
: queued_saves
) {
1203 do_save_state(i
.first
, i
.second
);
1205 flush_slotinfo(translate_name_mprefix(i
.first
, tmp
, -1));
1207 if(do_unsafe_rewind
&& !unsafe_rewind_obj
) {
1208 uint64_t t
= get_utime();
1209 std::vector
<char> s
= our_rom
.save_core_state(true);
1210 uint64_t secs
= CORE().mlogic
.get_mfile().rtc_second
;
1211 uint64_t ssecs
= CORE().mlogic
.get_mfile().rtc_subsecond
;
1212 lua_callback_do_unsafe_rewind(s
, secs
, ssecs
, CORE().mlogic
.get_movie(),
1214 do_unsafe_rewind
= false;
1215 messages
<< "Rewind point set in " << (get_utime() - t
) << " usec." << std::endl
;
1218 queued_saves
.clear();
1221 bool handle_corrupt()
1225 while(system_corrupt
) {
1226 platform::set_paused(true);
1227 platform::flush_command_queue();
1236 void init_main_callbacks()
1238 ecore_callbacks
= &lsnes_callbacks_obj
;
1241 void main_loop(struct loaded_rom
& rom
, struct moviefile
& initial
, bool load_has_to_succeed
) throw(std::bad_alloc
,
1244 lsnes_instance
.emu_thread
= threads::id();
1245 CORE().system_thread_available
= true;
1246 //Basic initialization.
1247 dispatch_set_error_streams(&messages
.getstream());
1248 emulation_thread
= threads::this_id();
1249 jukebox_size_listener
jlistener(CORE().settings
);
1250 CORE().commentary
.init();
1251 init_special_screens();
1253 init_main_callbacks();
1254 initialize_all_builtin_c_cores();
1255 core_core::install_all_handlers();
1257 //Load our given movie.
1258 bool first_round
= false;
1259 bool just_did_loadstate
= false;
1262 do_load_state(initial
, LOAD_STATE_INITIAL
, used
);
1263 location_special
= SPECIAL_SAVEPOINT
;
1264 update_movie_state();
1265 first_round
= CORE().mlogic
.get_mfile().is_savestate
;
1266 just_did_loadstate
= first_round
;
1267 } catch(std::bad_alloc
& e
) {
1269 } catch(std::exception
& e
) {
1272 platform::error_message(std::string("Can't load initial state: ") + e
.what());
1273 messages
<< "ERROR: Can't load initial state: " << e
.what() << std::endl
;
1274 if(load_has_to_succeed
) {
1275 messages
<< "FATAL: Can't load movie" << std::endl
;
1278 system_corrupt
= true;
1279 redraw_framebuffer(screen_corrupt
);
1282 platform::set_paused(initial
.start_paused
);
1283 amode
= initial
.start_paused
? ADVANCE_PAUSE
: ADVANCE_AUTO
;
1284 stop_at_frame_active
= false;
1286 lua_run_startup_scripts();
1288 uint64_t time_x
= get_utime();
1289 while(!is_quitting() || !queued_saves
.empty()) {
1290 if(handle_corrupt()) {
1291 first_round
= CORE().mlogic
&& CORE().mlogic
.get_mfile().is_savestate
;
1292 just_did_loadstate
= first_round
;
1295 ack_frame_tick(get_utime());
1296 if(amode
== ADVANCE_SKIPLAG_PENDING
)
1297 amode
= ADVANCE_SKIPLAG
;
1300 CORE().controls
.reset_framehold();
1301 if(!macro_hold_1
&& !macro_hold_2
) {
1302 CORE().controls
.advance_macros();
1304 macro_hold_2
= false;
1305 CORE().mlogic
.get_movie().get_pollcounters().set_framepflag(false);
1306 CORE().mlogic
.new_frame_starting(amode
== ADVANCE_SKIPLAG
);
1307 CORE().mlogic
.get_movie().get_pollcounters().set_framepflag(true);
1308 if(is_quitting() && queued_saves
.empty())
1312 if(queued_saves
.empty())
1314 if(r
> 0 || system_corrupt
) {
1315 CORE().mlogic
.get_movie().get_pollcounters().set_framepflag(
1316 CORE().mlogic
.get_mfile().is_savestate
);
1317 first_round
= CORE().mlogic
.get_mfile().is_savestate
;
1319 amode
= ADVANCE_PAUSE
;
1322 stop_at_frame_active
= false;
1323 just_did_loadstate
= first_round
;
1324 CORE().controls
.reset_framehold();
1325 debug_fire_callback_frame(CORE().mlogic
.get_movie().get_current_frame(),
1329 //Not exactly desriable, but this at least won't desync.
1330 stop_at_frame_active
= false;
1333 amode
= ADVANCE_PAUSE
;
1336 if(just_did_loadstate
) {
1337 //If we just loadstated, we are up to date.
1340 platform::set_paused(amode
== ADVANCE_PAUSE
);
1341 platform::flush_command_queue();
1342 //We already have done the reset this frame if we are going to do one at all.
1343 CORE().mlogic
.get_movie().set_controls(CORE().mlogic
.update_controls(true));
1344 CORE().mlogic
.get_movie().set_all_DRDY();
1345 just_did_loadstate
= false;
1347 frame_irq_time
= get_utime() - time_x
;
1348 debug_fire_callback_frame(CORE().mlogic
.get_movie().get_current_frame(), false);
1349 our_rom
.rtype
->emulate();
1350 random_mix_timing_entropy();
1351 time_x
= get_utime();
1352 if(amode
== ADVANCE_AUTO
)
1353 platform::wait(to_wait_frame(get_utime()));
1354 first_round
= false;
1355 lua_callback_do_frame();
1358 information_dispatch::do_dump_end();
1359 core_core::uninstall_all_handlers();
1360 CORE().commentary
.kill();
1361 CORE().system_thread_available
= false;
1362 //Kill some things to avoid crashes.
1363 debug_core_change();
1364 CORE().project
.set(NULL
, true);
1365 CORE().mwatch
.clear_multi(CORE().mwatch
.enumerate());
1368 void set_stop_at_frame(uint64_t frame
)
1370 stop_at_frame
= frame
;
1371 stop_at_frame_active
= (frame
!= 0);
1372 amode
= ADVANCE_AUTO
;
1373 platform::set_paused(false);
1376 void do_flush_slotinfo()
1381 void switch_projects(const std::string
& newproj
)
1383 pending_new_project
= newproj
;
1384 amode
= ADVANCE_LOAD
;
1385 old_mode
= ADVANCE_PAUSE
;
1386 platform::cancel_wait();
1387 platform::set_paused(false);
1390 void load_new_rom(const romload_request
& req
)
1392 if(_load_new_rom(req
)) {
1393 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
1397 void reload_current_rom()
1399 if(reload_active_rom()) {
1400 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
1406 if(load_null_rom()) {
1408 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
1412 void do_break_pause()
1414 amode
= ADVANCE_BREAK_PAUSE
;
1415 update_movie_state();
1416 while(amode
== ADVANCE_BREAK_PAUSE
) {
1417 platform::set_paused(true);
1418 platform::flush_command_queue();
1422 void convert_break_to_pause()
1424 if(amode
== ADVANCE_BREAK_PAUSE
) {
1425 amode
= ADVANCE_PAUSE
;
1426 update_movie_state();
1430 void debug_trash_memory(uint8_t* addr
, uint8_t byte
)