3 #include "core/advdumper.hpp"
4 #include "core/command.hpp"
5 #include "core/controller.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/instance.hpp"
12 #include "core/inthread.hpp"
13 #include "core/keymapper.hpp"
14 #include "core/mainloop.hpp"
15 #include "core/memorymanip.hpp"
16 #include "core/memorywatch.hpp"
17 #include "core/messages.hpp"
18 #include "core/moviedata.hpp"
19 #include "core/moviefile.hpp"
20 #include "core/multitrack.hpp"
21 #include "core/project.hpp"
22 #include "core/queue.hpp"
23 #include "core/random.hpp"
24 #include "core/rom.hpp"
25 #include "core/settings.hpp"
26 #include "core/window.hpp"
27 #include "interface/callbacks.hpp"
28 #include "interface/c-interface.hpp"
29 #include "interface/romtype.hpp"
30 #include "library/framebuffer.hpp"
31 #include "library/settingvar.hpp"
32 #include "library/string.hpp"
33 #include "library/zip.hpp"
34 #include "lua/lua.hpp"
44 #define QUIT_MAGIC 0x5a8c4bef
46 #define SPECIAL_FRAME_START 0
47 #define SPECIAL_FRAME_VIDEO 1
48 #define SPECIAL_SAVEPOINT 2
49 #define SPECIAL_NONE 3
51 void update_movie_state();
53 settingvar::supervariable
<settingvar::model_bool
<settingvar::yes_no
>> jukebox_dflt_binary(lsnes_setgrp
,
54 "jukebox-default-binary", "Movie‣Saving‣Saveslots binary", true);
55 settingvar::supervariable
<settingvar::model_bool
<settingvar::yes_no
>> movie_dflt_binary(lsnes_setgrp
,
56 "movie-default-binary", "Movie‣Saving‣Movies binary", false);
57 settingvar::supervariable
<settingvar::model_bool
<settingvar::yes_no
>> save_dflt_binary(lsnes_setgrp
,
58 "savestate-default-binary", "Movie‣Saving‣Savestates binary", false);
62 settingvar::supervariable
<settingvar::model_int
<0,999999>> SET_advance_timeout_first(lsnes_setgrp
,
63 "advance-timeout", "Delays‣First frame advance", 500);
64 settingvar::supervariable
<settingvar::model_int
<0,999999>> SET_advance_timeout_subframe(lsnes_setgrp
,
65 "advance-subframe-timeout", "Delays‣Subframe advance", 100);
66 settingvar::supervariable
<settingvar::model_bool
<settingvar::yes_no
>> SET_pause_on_end(lsnes_setgrp
,
67 "pause-on-end", "Movie‣Pause on end", false);
68 settingvar::supervariable
<settingvar::model_int
<0,999999999>> SET_jukebox_size(lsnes_setgrp
, "jukebox-size",
69 "Movie‣Number of save slots", 12);
73 ADVANCE_INVALID
, //In case someone trashes this.
74 ADVANCE_QUIT
, //Quit the emulator.
75 ADVANCE_AUTO
, //Normal (possibly slowed down play).
76 ADVANCE_LOAD
, //Loading a state.
77 ADVANCE_FRAME
, //Frame advance.
78 ADVANCE_SUBFRAME
, //Subframe advance.
79 ADVANCE_SKIPLAG
, //Skip lag (oneshot, reverts to normal).
80 ADVANCE_SKIPLAG_PENDING
, //Activate skip lag mode at next frame.
81 ADVANCE_PAUSE
, //Unconditional pause.
82 ADVANCE_BREAK_PAUSE
, //Break pause.
85 //Flags related to repeating advance.
88 //Emulator advance mode. Detemines pauses at start of frame / subframe, etc..
89 enum advance_mode amode
;
90 enum advance_mode old_mode
;
91 //Mode and filename of pending load, one of LOAD_* constants.
94 std::string pending_load
;
95 std::string pending_new_project
;
96 //Queued saves (all savestates).
97 std::set
<std::pair
<std::string
, int>> queued_saves
;
99 size_t save_jukebox_pointer
;
100 //Special subframe location. One of SPECIAL_* constants.
101 int location_special
;
103 bool do_unsafe_rewind
= false;
104 void* unsafe_rewind_obj
= NULL
;
106 bool stop_at_frame_active
= false;
107 uint64_t stop_at_frame
= 0;
116 if(amode
== ADVANCE_QUIT
&& quit_magic
== QUIT_MAGIC
)
118 if(amode
== ADVANCE_INVALID
|| (amode
== ADVANCE_QUIT
&& quit_magic
!= QUIT_MAGIC
) ||
119 amode
> ADVANCE_BREAK_PAUSE
) {
121 if(lsnes_instance
.mlogic
)
122 emerg_save_movie(lsnes_instance
.mlogic
->get_mfile(),
123 lsnes_instance
.mlogic
->get_rrdata());
124 messages
<< "WARNING: Emulator runmode undefined, invoked movie dump." << std::endl
;
125 amode
= ADVANCE_PAUSE
;
130 std::string
save_jukebox_name(size_t i
)
132 return (stringfmt() << "$SLOT:" << (i
+ 1)).str();
136 void mainloop_signal_need_rewind(void* ptr
)
140 amode
= ADVANCE_LOAD
;
142 do_unsafe_rewind
= true;
143 unsafe_rewind_obj
= ptr
;
146 controller_frame
movie_logic::update_controls(bool subframe
) throw(std::bad_alloc
, std::runtime_error
)
149 if(core
.lua2
->requests_subframe_paint
)
150 core
.fbuf
->redraw_framebuffer();
153 if(amode
== ADVANCE_SUBFRAME
) {
154 if(!cancel_advance
) {
156 platform::wait(SET_advance_timeout_first(*core
.settings
) * 1000);
158 platform::wait(SET_advance_timeout_subframe(*core
.settings
) * 1000);
159 advanced_once
= true;
162 stop_at_frame_active
= false;
163 amode
= ADVANCE_PAUSE
;
164 cancel_advance
= false;
166 platform::set_paused(amode
== ADVANCE_PAUSE
);
167 } else if(amode
== ADVANCE_FRAME
) {
170 if(amode
== ADVANCE_SKIPLAG
) {
171 stop_at_frame_active
= false;
172 amode
= ADVANCE_PAUSE
;
174 platform::set_paused(amode
== ADVANCE_PAUSE
);
175 cancel_advance
= false;
177 location_special
= SPECIAL_NONE
;
178 update_movie_state();
180 if(amode
== ADVANCE_SKIPLAG_PENDING
)
181 amode
= ADVANCE_SKIPLAG
;
182 if(amode
== ADVANCE_FRAME
|| amode
== ADVANCE_SUBFRAME
) {
183 if(!cancel_advance
) {
186 wait
= SET_advance_timeout_first(*core
.settings
) * 1000;
187 else if(amode
== ADVANCE_SUBFRAME
)
188 wait
= SET_advance_timeout_subframe(*core
.settings
) * 1000;
190 wait
= core
.framerate
->to_wait_frame(framerate_regulator::get_utime());
191 platform::wait(wait
);
192 advanced_once
= true;
195 stop_at_frame_active
= false;
196 amode
= ADVANCE_PAUSE
;
197 cancel_advance
= false;
199 platform::set_paused(amode
== ADVANCE_PAUSE
);
200 } else if(amode
== ADVANCE_AUTO
&& core
.mlogic
->get_movie().readonly_mode() &&
201 SET_pause_on_end(*core
.settings
) && !stop_at_frame_active
) {
202 if(core
.mlogic
->get_movie().get_current_frame() ==
203 core
.mlogic
->get_movie().get_frame_count()) {
204 stop_at_frame_active
= false;
205 amode
= ADVANCE_PAUSE
;
206 platform::set_paused(true);
208 } else if(amode
== ADVANCE_AUTO
&& stop_at_frame_active
) {
209 if(core
.mlogic
->get_movie().get_current_frame() >= stop_at_frame
) {
210 stop_at_frame_active
= false;
211 amode
= ADVANCE_PAUSE
;
212 platform::set_paused(true);
215 platform::set_paused((amode
== ADVANCE_PAUSE
));
216 cancel_advance
= false;
218 location_special
= SPECIAL_FRAME_START
;
219 update_movie_state();
221 platform::flush_command_queue();
222 controller_frame tmp
= core
.controls
->get(core
.mlogic
->get_movie().get_current_frame());
223 core
.rom
->rtype
->pre_emulate_frame(tmp
); //Preset controls, the lua will override if needed.
224 core
.lua2
->callback_do_input(tmp
, subframe
);
225 core
.mteditor
->process_frame(tmp
);
226 core
.controls
->commit(tmp
);
233 //Do pending load (automatically unpauses).
234 void mark_pending_load(std::string filename
, int lmode
)
236 //Convert break pause to ordinary pause.
237 if(amode
== ADVANCE_BREAK_PAUSE
)
238 amode
= ADVANCE_PAUSE
;
240 pending_load
= filename
;
242 amode
= ADVANCE_LOAD
;
243 platform::cancel_wait();
244 platform::set_paused(false);
247 void mark_pending_save(std::string filename
, int smode
, int binary
)
251 if(smode
== SAVE_MOVIE
) {
252 //Just do this immediately.
253 do_save_movie(filename
, binary
);
254 core
.slotcache
->flush(translate_name_mprefix(filename
, tmp
, -1));
257 if(location_special
== SPECIAL_SAVEPOINT
) {
258 //We can save immediately here.
259 do_save_state(filename
, binary
);
260 core
.slotcache
->flush(translate_name_mprefix(filename
, tmp
, -1));
263 queued_saves
.insert(std::make_pair(filename
, binary
));
264 messages
<< "Pending save on '" << filename
<< "'" << std::endl
;
267 struct jukebox_size_listener
: public settingvar::listener
269 jukebox_size_listener(settingvar::group
& _grp
) : grp(_grp
) { grp
.add_listener(*this); }
270 ~jukebox_size_listener() throw() { grp
.remove_listener(*this); };
271 void on_setting_change(settingvar::group
& _grp
, const settingvar::base
& val
)
273 if(val
.get_iname() == "jukebox-size") {
274 if(save_jukebox_pointer
>= (size_t)SET_jukebox_size(_grp
))
275 save_jukebox_pointer
= 0;
277 update_movie_state();
280 settingvar::group
& grp
;
284 void update_movie_state()
287 auto p
= core
.project
->get();
288 bool readonly
= false;
291 core
.rom
->region
->fill_framerate_magic(magic
);
293 core
.commentary
->frame_number(core
.mlogic
->get_movie().get_current_frame(),
294 1.0 * magic
[1] / magic
[0]);
296 core
.commentary
->frame_number(0, 60.0); //Default.
298 auto& _status
= core
.status
->get_write();
300 if(*core
.mlogic
&& !system_corrupt
) {
301 _status
.movie_valid
= true;
302 _status
.curframe
= core
.mlogic
->get_movie().get_current_frame();
303 _status
.length
= core
.mlogic
->get_movie().get_frame_count();
304 _status
.lag
= core
.mlogic
->get_movie().get_lag_frames();
305 if(location_special
== SPECIAL_FRAME_START
)
306 _status
.subframe
= 0;
307 else if(location_special
== SPECIAL_SAVEPOINT
)
308 _status
.subframe
= _lsnes_status::subframe_savepoint
;
309 else if(location_special
== SPECIAL_FRAME_VIDEO
)
310 _status
.subframe
= _lsnes_status::subframe_video
;
312 _status
.subframe
= core
.mlogic
->get_movie().next_poll_number();
314 _status
.movie_valid
= false;
315 _status
.curframe
= 0;
318 _status
.subframe
= 0;
320 _status
.dumping
= (core
.mdumper
->get_dumper_count() > 0);
321 if(amode
== ADVANCE_BREAK_PAUSE
)
322 _status
.pause
= _lsnes_status::pause_break
;
323 else if(amode
== ADVANCE_PAUSE
)
324 _status
.pause
= _lsnes_status::pause_normal
;
326 _status
.pause
= _lsnes_status::pause_none
;
328 auto& mo
= core
.mlogic
->get_movie();
329 readonly
= mo
.readonly_mode();
334 else if(mo
.get_frame_count() >= mo
.get_current_frame())
339 if(SET_jukebox_size(*core
.settings
) > 0) {
340 _status
.saveslot_valid
= true;
342 std::string sfilen
= translate_name_mprefix(save_jukebox_name(save_jukebox_pointer
), tmp
, -1);
343 _status
.saveslot
= save_jukebox_pointer
+ 1;
344 _status
.slotinfo
= utf8::to32(core
.slotcache
->get(sfilen
));
346 _status
.saveslot_valid
= false;
348 _status
.branch_valid
= (p
!= NULL
);
349 if(p
) _status
.branch
= utf8::to32(p
->get_branch_string());
351 std::string cur_branch
= *core
.mlogic
? core
.mlogic
->get_mfile().current_branch() :
353 _status
.mbranch_valid
= (cur_branch
!= "");
354 _status
.mbranch
= utf8::to32(cur_branch
);
356 _status
.speed
= (unsigned)(100 * core
.framerate
->get_realized_multiplier() + 0.5);
358 if(*core
.mlogic
&& !system_corrupt
) {
359 time_t timevalue
= static_cast<time_t>(core
.mlogic
->get_mfile().rtc_second
);
360 struct tm
* time_decompose
= gmtime(&timevalue
);
361 char datebuffer
[512];
362 strftime(datebuffer
, 511, "%Y%m%d(%a)T%H%M%S", time_decompose
);
363 _status
.rtc
= utf8::to32(datebuffer
);
364 _status
.rtc_valid
= true;
366 _status
.rtc_valid
= false;
369 auto mset
= core
.controls
->active_macro_set();
371 std::ostringstream mss
;
373 if(!mfirst
) mss
<< ",";
377 _status
.macros
= utf8::to32(mss
.str());
380 if(!core
.mteditor
->any_records())
381 c
= core
.mlogic
->get_movie().get_controls();
383 c
= core
.controls
->get_committed();
384 _status
.inputs
.clear();
385 for(unsigned i
= 0;; i
++) {
386 auto pindex
= core
.controls
->lcid_to_pcid(i
);
387 if(pindex
.first
< 0 || !core
.controls
->is_present(pindex
.first
, pindex
.second
))
389 char32_t buffer
[MAX_DISPLAY_LENGTH
];
390 c
.display(pindex
.first
, pindex
.second
, buffer
);
391 std::u32string _buffer
= buffer
;
392 if(readonly
&& core
.mteditor
->is_enabled()) {
393 multitrack_edit::state st
= core
.mteditor
->get(pindex
.first
, pindex
.second
);
394 if(st
== multitrack_edit::MT_PRESERVE
)
395 _buffer
+= U
" (keep)";
396 else if(st
== multitrack_edit::MT_OVERWRITE
)
397 _buffer
+= U
" (rewrite)";
398 else if(st
== multitrack_edit::MT_OR
)
400 else if(st
== multitrack_edit::MT_XOR
)
401 _buffer
+= U
" (XOR)";
403 _buffer
+= U
" (\?\?\?)";
405 _status
.inputs
.push_back(_buffer
);
408 _status
.lvars
= core
.lua2
->get_watch_vars();
410 _status
.mvars
= core
.mwatch
->get_window_vars();
412 _status
.valid
= true;
415 core
.status
->put_write();
416 core
.dispatch
->status_update();
419 struct lsnes_callbacks
: public emucore_callbacks
422 ~lsnes_callbacks() throw()
426 int16_t get_input(unsigned port
, unsigned index
, unsigned control
)
430 x
= core
.mlogic
->input_poll(port
, index
, control
);
431 core
.lua2
->callback_snoop_input(port
, index
, control
, x
);
435 int16_t set_input(unsigned port
, unsigned index
, unsigned control
, int16_t value
)
438 if(!core
.mlogic
->get_movie().readonly_mode()) {
439 controller_frame f
= core
.mlogic
->get_movie().get_controls();
440 f
.axis3(port
, index
, control
, value
);
441 core
.mlogic
->get_movie().set_controls(f
);
443 return core
.mlogic
->get_movie().next_input(port
, index
, control
);
446 void notify_latch(std::list
<std::string
>& args
)
448 CORE().lua2
->callback_do_latch(args
);
451 void timer_tick(uint32_t increment
, uint32_t per_second
)
456 auto& m
= core
.mlogic
->get_mfile();
457 m
.rtc_subsecond
+= increment
;
458 while(m
.rtc_subsecond
>= per_second
) {
460 m
.rtc_subsecond
-= per_second
;
464 std::string
get_firmware_path()
466 return CORE().setcache
->get("firmwarepath");
469 std::string
get_base_path()
471 return CORE().rom
->msu1_base
;
477 return *core
.mlogic
? core
.mlogic
->get_mfile().rtc_second
: 0;
480 time_t get_randomseed()
482 return CORE().random_seed_value
;
485 void output_frame(framebuffer::raw
& screen
, uint32_t fps_n
, uint32_t fps_d
)
488 core
.lua2
->callback_do_frame_emulated();
489 location_special
= SPECIAL_FRAME_VIDEO
;
490 core
.fbuf
->redraw_framebuffer(screen
, false, true);
491 auto rate
= core
.rom
->rtype
->get_audio_rate();
492 uint32_t gv
= gcd(fps_n
, fps_d
);
493 uint32_t ga
= gcd(rate
.first
, rate
.second
);
494 core
.mdumper
->on_rate_change(rate
.first
/ ga
, rate
.second
/ ga
);
495 core
.mdumper
->on_frame(screen
, fps_n
/ gv
, fps_d
/ gv
);
498 void action_state_updated()
500 CORE().dispatch
->action_update();
503 void memory_read(uint64_t addr
, uint64_t value
)
505 CORE().dbg
->do_callback_read(addr
, value
);
508 void memory_write(uint64_t addr
, uint64_t value
)
510 CORE().dbg
->do_callback_write(addr
, value
);
513 void memory_execute(uint64_t addr
, uint64_t proc
)
515 CORE().dbg
->do_callback_exec(addr
, proc
);
518 void memory_trace(uint64_t proc
, const char* str
, bool insn
)
520 CORE().dbg
->do_callback_trace(proc
, str
, insn
);
526 lsnes_callbacks lsnes_callbacks_obj
;
527 command::fnptr
<> CMD_segfault(lsnes_cmds
, "segfault", "Trigger SIGSEGV",
528 "segfault\nTrigger segmentation fault",
529 []() throw(std::bad_alloc
, std::runtime_error
) {
530 char* ptr
= (char*)0x1234;
534 command::fnptr
<> CMD_div0(lsnes_cmds
, "divide-by-0", "Do div0", "divide-by-0\nDo divide by 0",
535 []() throw(std::bad_alloc
, std::runtime_error
) {
541 command::fnptr
<const std::string
&> CMD_test4(lsnes_cmds
, "test4", "test", "test",
542 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
544 std::list
<std::string
> _args
;
545 std::string args2
= args
;
546 for(auto& sym
: token_iterator_foreach(args
, {" ", "\t"}))
547 _args
.push_back(sym
);
548 core
.lua2
->callback_do_latch(_args
);
550 command::fnptr
<> CMD_count_rerecords(lsnes_cmds
, "count-rerecords", "Count rerecords",
551 "Syntax: count-rerecords\nCounts rerecords.\n",
552 []() throw(std::bad_alloc
, std::runtime_error
) {
553 std::vector
<char> tmp
;
554 uint64_t x
= CORE().mlogic
->get_rrdata().write(tmp
);
555 messages
<< x
<< " rerecord(s)" << std::endl
;
558 command::fnptr
<const std::string
&> CMD_quit_emulator(lsnes_cmds
, "quit-emulator", "Quit the emulator",
559 "Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n",
560 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
561 amode
= ADVANCE_QUIT
;
562 quit_magic
= QUIT_MAGIC
;
563 platform::set_paused(false);
564 platform::cancel_wait();
567 command::fnptr
<> CMD_unpause_emulator(lsnes_cmds
, "unpause-emulator", "Unpause the emulator",
568 "Syntax: unpause-emulator\nUnpauses the emulator.\n",
569 []() throw(std::bad_alloc
, std::runtime_error
) {
570 amode
= ADVANCE_AUTO
;
571 platform::set_paused(false);
572 platform::cancel_wait();
575 command::fnptr
<> CMD_pause_emulator(lsnes_cmds
, "pause-emulator", "(Un)pause the emulator",
576 "Syntax: pause-emulator\n(Un)pauses the emulator.\n",
577 []() throw(std::bad_alloc
, std::runtime_error
) {
578 if(amode
!= ADVANCE_AUTO
) {
579 amode
= ADVANCE_AUTO
;
580 platform::set_paused(false);
581 platform::cancel_wait();
583 platform::cancel_wait();
584 cancel_advance
= false;
585 stop_at_frame_active
= false;
586 amode
= ADVANCE_PAUSE
;
590 command::fnptr
<> CMD_save_jukebox_prev(lsnes_cmds
, "cycle-jukebox-backward", "Cycle save jukebox backwards",
591 "Syntax: cycle-jukebox-backward\nCycle save jukebox backwards\n",
592 []() throw(std::bad_alloc
, std::runtime_error
) {
593 size_t jbsize
= SET_jukebox_size(*CORE().settings
);
596 if(save_jukebox_pointer
== 0)
597 save_jukebox_pointer
= jbsize
- 1;
599 save_jukebox_pointer
--;
600 if(save_jukebox_pointer
>= (size_t)jbsize
)
601 save_jukebox_pointer
= 0;
602 update_movie_state();
605 command::fnptr
<> CMD_save_jukebox_next(lsnes_cmds
, "cycle-jukebox-forward", "Cycle save jukebox forwards",
606 "Syntax: cycle-jukebox-forward\nCycle save jukebox forwards\n",
607 []() throw(std::bad_alloc
, std::runtime_error
) {
608 size_t jbsize
= SET_jukebox_size(*CORE().settings
);
611 if(save_jukebox_pointer
+ 1 >= (size_t)jbsize
)
612 save_jukebox_pointer
= 0;
614 save_jukebox_pointer
++;
615 if(save_jukebox_pointer
>= (size_t)jbsize
)
616 save_jukebox_pointer
= 0;
617 update_movie_state();
620 command::fnptr
<const std::string
&> CMD_save_jukebox_set(lsnes_cmds
, "set-jukebox-slot", "Set jukebox slot",
621 "Syntax: set-jukebox-slot\nSet jukebox slot\n", [](const std::string
& args
)
622 throw(std::bad_alloc
, std::runtime_error
) {
623 if(!regex_match("[1-9][0-9]{0,8}", args
))
624 throw std::runtime_error("Bad slot number");
625 uint32_t slot
= parse_value
<uint32_t>(args
);
626 if(slot
>= (size_t)SET_jukebox_size(*CORE().settings
))
627 throw std::runtime_error("Bad slot number");
628 save_jukebox_pointer
= slot
- 1;
629 update_movie_state();
632 command::fnptr
<> CMD_load_jukebox(lsnes_cmds
, "load-jukebox", "Load save from jukebox",
633 "Syntax: load-jukebox\nLoad save from jukebox\n",
634 []() throw(std::bad_alloc
, std::runtime_error
) {
635 if(SET_jukebox_size(*CORE().settings
) == 0)
636 throw std::runtime_error("No slot selected");
637 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_CURRENT
);
640 command::fnptr
<> CMD_load_jukebox_readwrite(lsnes_cmds
, "load-jukebox-readwrite", "Load save from jukebox in"
641 " recording mode", "Syntax: load-jukebox-readwrite\nLoad save from jukebox in recording mode\n",
642 []() throw(std::bad_alloc
, std::runtime_error
) {
643 if(SET_jukebox_size(*CORE().settings
) == 0)
644 throw std::runtime_error("No slot selected");
645 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_RW
);
648 command::fnptr
<> CMD_load_jukebox_readonly(lsnes_cmds
, "load-jukebox-readonly", "Load save from jukebox in "
649 "playback mode", "Syntax: load-jukebox-readonly\nLoad save from jukebox in playback mode\n",
650 []() throw(std::bad_alloc
, std::runtime_error
) {
651 if(SET_jukebox_size(*CORE().settings
) == 0)
652 throw std::runtime_error("No slot selected");
653 mark_pending_load(save_jukebox_name(save_jukebox_pointer
), LOAD_STATE_RO
);
656 command::fnptr
<> CMD_load_jukebox_preserve(lsnes_cmds
, "load-jukebox-preserve", "Load save from jukebox, "
657 "preserving input", "Syntax: load-jukebox-preserve\nLoad save from jukebox, preserving input\n",
658 []() throw(std::bad_alloc
, std::runtime_error
) {
659 if(SET_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_PRESERVE
);
664 command::fnptr
<> CMD_load_jukebox_movie(lsnes_cmds
, "load-jukebox-movie", "Load save from jukebox as movie",
665 "Syntax: load-jukebox-movie\nLoad save from jukebox as movie\n",
666 []() throw(std::bad_alloc
, std::runtime_error
) {
667 if(SET_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_MOVIE
);
672 command::fnptr
<> CMD_save_jukebox_c(lsnes_cmds
, "save-jukebox", "Save save to jukebox",
673 "Syntax: save-jukebox\nSave save to jukebox\n",
674 []() throw(std::bad_alloc
, std::runtime_error
) {
675 if(SET_jukebox_size(*CORE().settings
) == 0)
676 throw std::runtime_error("No slot selected");
677 mark_pending_save(save_jukebox_name(save_jukebox_pointer
), SAVE_STATE
, -1);
680 command::fnptr
<> CMD_padvance_frame(lsnes_cmds
, "+advance-frame", "Advance one frame",
681 "Syntax: +advance-frame\nAdvances the emulation by one frame.\n",
682 []() throw(std::bad_alloc
, std::runtime_error
) {
683 amode
= ADVANCE_FRAME
;
684 cancel_advance
= false;
685 advanced_once
= false;
686 platform::cancel_wait();
687 platform::set_paused(false);
690 command::fnptr
<> CMD_nadvance_frame(lsnes_cmds
, "-advance-frame", "Advance one frame",
691 "No help available\n",
692 []() throw(std::bad_alloc
, std::runtime_error
) {
693 cancel_advance
= true;
694 platform::cancel_wait();
695 platform::set_paused(false);
698 command::fnptr
<> CMD_padvance_poll(lsnes_cmds
, "+advance-poll", "Advance one subframe",
699 "Syntax: +advance-poll\nAdvances the emulation by one subframe.\n",
700 []() throw(std::bad_alloc
, std::runtime_error
) {
701 amode
= ADVANCE_SUBFRAME
;
702 cancel_advance
= false;
703 advanced_once
= false;
704 platform::cancel_wait();
705 platform::set_paused(false);
708 command::fnptr
<> CMD_nadvance_poll(lsnes_cmds
, "-advance-poll", "Advance one subframe",
709 "No help available\n",
710 []() throw(std::bad_alloc
, std::runtime_error
) {
711 if(amode
== ADVANCE_BREAK_PAUSE
)
712 amode
= ADVANCE_PAUSE
;
713 cancel_advance
= true;
714 platform::cancel_wait();
715 platform::set_paused(false);
718 command::fnptr
<> CMD_advance_skiplag(lsnes_cmds
, "advance-skiplag", "Skip to next poll",
719 "Syntax: advance-skiplag\nAdvances the emulation to the next poll.\n",
720 []() throw(std::bad_alloc
, std::runtime_error
) {
721 amode
= ADVANCE_SKIPLAG_PENDING
;
722 platform::cancel_wait();
723 platform::set_paused(false);
726 command::fnptr
<> CMD_reset_c(lsnes_cmds
, "reset", "Reset the system",
727 "Syntax: reset\nReset\nResets the system in beginning of the next frame.\n",
728 []() throw(std::bad_alloc
, std::runtime_error
) {
730 int sreset_action
= core
.rom
->rtype
->reset_action(false);
731 if(sreset_action
< 0) {
732 platform::error_message("Core does not support resets");
733 messages
<< "Emulator core does not support resets" << std::endl
;
736 core
.rom
->rtype
->execute_action(sreset_action
, std::vector
<interface_action_paramval
>());
739 command::fnptr
<> CMD_hreset_c(lsnes_cmds
, "reset-hard", "Reset the system",
740 "Syntax: reset-hard\nReset-hard\nHard resets the system in beginning of the next frame.\n",
741 []() throw(std::bad_alloc
, std::runtime_error
) {
743 int hreset_action
= core
.rom
->rtype
->reset_action(true);
744 if(hreset_action
< 0) {
745 platform::error_message("Core does not support hard resets");
746 messages
<< "Emulator core does not support hard resets" << std::endl
;
749 core
.rom
->rtype
->execute_action(hreset_action
, std::vector
<interface_action_paramval
>());
752 command::fnptr
<command::arg_filename
> CMD_load_c(lsnes_cmds
, "load", "Load savestate (current mode)",
753 "Syntax: load <file>\nLoads SNES state from <file> in current mode\n",
754 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
755 mark_pending_load(args
, LOAD_STATE_CURRENT
);
758 command::fnptr
<command::arg_filename
> CMD_load_smart_c(lsnes_cmds
, "load-smart",
759 "Load savestate (heuristic mode)",
760 "Syntax: load <file>\nLoads SNES state from <file> in heuristic mode\n",
761 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
762 mark_pending_load(args
, LOAD_STATE_DEFAULT
);
765 command::fnptr
<command::arg_filename
> CMD_load_state_c(lsnes_cmds
, "load-state", "Load savestate (R/W)",
766 "Syntax: load-state <file>\nLoads SNES state from <file> in Read/Write mode\n",
767 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
768 mark_pending_load(args
, LOAD_STATE_RW
);
771 command::fnptr
<command::arg_filename
> CMD_load_readonly(lsnes_cmds
, "load-readonly", "Load savestate (RO)",
772 "Syntax: load-readonly <file>\nLoads SNES state from <file> in playback mode\n",
773 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
774 mark_pending_load(args
, LOAD_STATE_RO
);
777 command::fnptr
<command::arg_filename
> CMD_load_preserve(lsnes_cmds
, "load-preserve",
778 "Load savestate (preserve input)",
779 "Syntax: load-preserve <file>\nLoads SNES state from <file> preserving input\n",
780 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
781 mark_pending_load(args
, LOAD_STATE_PRESERVE
);
784 command::fnptr
<command::arg_filename
> CMD_load_movie_c(lsnes_cmds
, "load-movie", "Load movie",
785 "Syntax: load-movie <file>\nLoads SNES movie from <file>\n",
786 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
787 mark_pending_load(args
, LOAD_STATE_MOVIE
);
790 command::fnptr
<command::arg_filename
> CMD_load_allbr_c(lsnes_cmds
, "load-allbranches", "Load savestate "
791 "(all branches)", "Syntax: load-allbranches <file>\nLoads SNES state from <file> with all "
793 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
794 mark_pending_load(args
, LOAD_STATE_ALLBRANCH
);
797 command::fnptr
<command::arg_filename
> CMD_save_state(lsnes_cmds
, "save-state", "Save state",
798 "Syntax: save-state <file>\nSaves SNES state to <file>\n",
799 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
800 mark_pending_save(args
, SAVE_STATE
, -1);
803 command::fnptr
<command::arg_filename
> CMD_save_state2(lsnes_cmds
, "save-state-binary", "Save state (binary)",
804 "Syntax: save-state-binary <file>\nSaves binary state to <file>\n",
805 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
806 mark_pending_save(args
, SAVE_STATE
, 1);
809 command::fnptr
<command::arg_filename
> CMD_save_state3(lsnes_cmds
, "save-state-zip", "Save state (zip)",
810 "Syntax: save-state-zip <file>\nSaves zip state to <file>\n",
811 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
812 mark_pending_save(args
, SAVE_STATE
, 0);
815 command::fnptr
<command::arg_filename
> CMD_save_movie(lsnes_cmds
, "save-movie", "Save movie",
816 "Syntax: save-movie <file>\nSaves SNES movie to <file>\n",
817 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
818 mark_pending_save(args
, SAVE_MOVIE
, -1);
821 command::fnptr
<command::arg_filename
> CMD_save_movie2(lsnes_cmds
, "save-movie-binary", "Save movie (binary)",
822 "Syntax: save-movie-binary <file>\nSaves binary movie to <file>\n",
823 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
824 mark_pending_save(args
, SAVE_MOVIE
, 1);
827 command::fnptr
<command::arg_filename
> CMD_save_movie3(lsnes_cmds
, "save-movie-zip", "Save movie (zip)",
828 "Syntax: save-movie-zip <file>\nSaves zip movie to <file>\n",
829 [](command::arg_filename args
) throw(std::bad_alloc
, std::runtime_error
) {
830 mark_pending_save(args
, SAVE_MOVIE
, 0);
833 command::fnptr
<> CMD_set_rwmode(lsnes_cmds
, "set-rwmode", "Switch to recording mode",
834 "Syntax: set-rwmode\nSwitches to recording mode\n",
835 []() throw(std::bad_alloc
, std::runtime_error
) {
837 core
.lua2
->callback_movie_lost("readwrite");
838 core
.mlogic
->get_movie().readonly_mode(false);
839 core
.dispatch
->mode_change(false);
840 core
.lua2
->callback_do_readwrite();
841 update_movie_state();
844 command::fnptr
<> CMD_set_romode(lsnes_cmds
, "set-romode", "Switch to playback mode",
845 "Syntax: set-romode\nSwitches to playback mode\n",
846 []() throw(std::bad_alloc
, std::runtime_error
) {
848 core
.mlogic
->get_movie().readonly_mode(true);
849 core
.dispatch
->mode_change(true);
850 update_movie_state();
853 command::fnptr
<> CMD_toggle_rwmode(lsnes_cmds
, "toggle-rwmode", "Toggle recording mode",
854 "Syntax: toggle-rwmode\nToggles recording mode\n",
855 []() throw(std::bad_alloc
, std::runtime_error
) {
857 bool c
= core
.mlogic
->get_movie().readonly_mode();
859 core
.lua2
->callback_movie_lost("readwrite");
860 core
.mlogic
->get_movie().readonly_mode(!c
);
861 core
.dispatch
->mode_change(!c
);
863 core
.lua2
->callback_do_readwrite();
864 update_movie_state();
867 command::fnptr
<> CMD_repaint(lsnes_cmds
, "repaint", "Redraw the screen",
868 "Syntax: repaint\nRedraws the screen\n",
869 []() throw(std::bad_alloc
, std::runtime_error
) {
870 CORE().fbuf
->redraw_framebuffer();
873 command::fnptr
<> CMD_tpon(lsnes_cmds
, "toggle-pause-on-end", "Toggle pause on end", "Toggle pause on end\n",
874 []() throw(std::bad_alloc
, std::runtime_error
) {
876 bool tmp
= SET_pause_on_end(*core
.settings
);
877 SET_pause_on_end(*core
.settings
, !tmp
);
878 messages
<< "Pause-on-end is now " << (tmp
? "OFF" : "ON") << std::endl
;
881 command::fnptr
<> CMD_spon(lsnes_cmds
, "set-pause-on-end", "Set pause on end", "Set pause on end\n",
882 []() throw(std::bad_alloc
, std::runtime_error
) {
883 SET_pause_on_end(*CORE().settings
, true);
884 messages
<< "Pause-on-end is now ON" << std::endl
;
887 command::fnptr
<> CMD_cpon(lsnes_cmds
, "clear-pause-on-end", "Clear pause on end", "Clear pause on end\n",
888 []() throw(std::bad_alloc
, std::runtime_error
) {
889 SET_pause_on_end(*CORE().settings
, false);
890 messages
<< "Pause-on-end is now OFF" << std::endl
;
893 command::fnptr
<> CMD_rewind_movie(lsnes_cmds
, "rewind-movie", "Rewind movie to the beginning",
894 "Syntax: rewind-movie\nRewind movie to the beginning\n",
895 []() throw(std::bad_alloc
, std::runtime_error
) {
896 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_BEGINNING
);
899 command::fnptr
<> CMD_cancel_save(lsnes_cmds
, "cancel-saves", "Cancel all pending saves", "Syntax: "
900 "cancel-save\nCancel pending saves\n",
901 []() throw(std::bad_alloc
, std::runtime_error
) {
902 queued_saves
.clear();
903 messages
<< "Pending saves canceled." << std::endl
;
906 command::fnptr
<> CMD_flushslots(lsnes_cmds
, "flush-slotinfo", "Flush slotinfo cache",
907 "Flush slotinfo cache\n",
908 []() throw(std::bad_alloc
, std::runtime_error
) {
909 CORE().slotcache
->flush();
912 command::fnptr
<> CMD_mhold1(lsnes_cmds
, "+hold-macro", "Hold macro (hold)",
913 "Hold macros enable\n", []() throw(std::bad_alloc
, std::runtime_error
) {
917 command::fnptr
<> CMD_mhold2(lsnes_cmds
, "-hold-macro", "Hold macro (hold)",
918 "Hold macros disable\n", []() throw(std::bad_alloc
, std::runtime_error
) {
919 macro_hold_1
= false;
922 command::fnptr
<> CMD_mhold3(lsnes_cmds
, "hold-macro", "Hold macro (toggle)",
923 "Hold macros toggle\n", []() throw(std::bad_alloc
, std::runtime_error
) {
924 macro_hold_2
= !macro_hold_2
;
926 messages
<< "Macros are held for next frame." << std::endl
;
928 messages
<< "Macros are not held for next frame." << std::endl
;
931 keyboard::invbind_info
IBIND_imhold1(lsnes_invbinds
, "+hold-macro", "Macro‣Hold all macros");
932 keyboard::invbind_info
IBIND_imhold2(lsnes_invbinds
, "hold-macro", "Macro‣Hold all macros (typed)");
933 keyboard::invbind_info
IBIND_ipause_emulator(lsnes_invbinds
, "pause-emulator", "Speed‣(Un)pause");
934 keyboard::invbind_info
IBIND_ijback(lsnes_invbinds
, "cycle-jukebox-backward", "Slot select‣Cycle backwards");
935 keyboard::invbind_info
IBIND_ijforward(lsnes_invbinds
, "cycle-jukebox-forward", "Slot select‣Cycle forwards");
936 keyboard::invbind_info
IBIND_iloadj(lsnes_invbinds
, "load-jukebox", "Load‣Selected slot");
937 keyboard::invbind_info
IBIND_iloadjrw(lsnes_invbinds
, "load-jukebox-readwrite",
938 "Load‣Selected slot (recording mode)");
939 keyboard::invbind_info
IBIND_iloadjro(lsnes_invbinds
, "load-jukebox-readonly",
940 "Load‣Selected slot (playback mode)");
941 keyboard::invbind_info
IBIND_iloadjp(lsnes_invbinds
, "load-jukebox-preserve",
942 "Load‣Selected slot (preserve input)");
943 keyboard::invbind_info
IBIND_iloadjm(lsnes_invbinds
, "load-jukebox-movie", "Load‣Selected slot (as movie)");
944 keyboard::invbind_info
IBIND_isavej(lsnes_invbinds
, "save-jukebox", "Save‣Selected slot");
945 keyboard::invbind_info
IBIND_iadvframe(lsnes_invbinds
, "+advance-frame", "Speed‣Advance frame");
946 keyboard::invbind_info
IBIND_iadvsubframe(lsnes_invbinds
, "+advance-poll", "Speed‣Advance subframe");
947 keyboard::invbind_info
IBIND_iskiplag(lsnes_invbinds
, "advance-skiplag", "Speed‣Advance poll");
948 keyboard::invbind_info
IBIND_ireset(lsnes_invbinds
, "reset", "System‣Reset");
949 keyboard::invbind_info
IBIND_iset_rwmode(lsnes_invbinds
, "set-rwmode", "Movie‣Switch to recording");
950 keyboard::invbind_info
IBIND_itoggle_romode(lsnes_invbinds
, "set-romode", "Movie‣Switch to playback");
951 keyboard::invbind_info
IBIND_itoggle_rwmode(lsnes_invbinds
, "toggle-rwmode", "Movie‣Toggle playback");
952 keyboard::invbind_info
IBIND_irepaint(lsnes_invbinds
, "repaint", "System‣Repaint screen");
953 keyboard::invbind_info
IBIND_itogglepause(lsnes_invbinds
, "toggle-pause-on-end", "Movie‣Toggle pause-on-end");
954 keyboard::invbind_info
IBIND_irewind_movie(lsnes_invbinds
, "rewind-movie", "Movie‣Rewind movie");
955 keyboard::invbind_info
IBIND_icancel_saves(lsnes_invbinds
, "cancel-saves", "Save‣Cancel pending saves");
956 keyboard::invbind_info
IBIND_iload1(lsnes_invbinds
, "load $SLOT:1", "Load‣Slot 1");
957 keyboard::invbind_info
IBIND_iload2(lsnes_invbinds
, "load $SLOT:2", "Load‣Slot 2");
958 keyboard::invbind_info
IBIND_iload3(lsnes_invbinds
, "load $SLOT:3", "Load‣Slot 3");
959 keyboard::invbind_info
IBIND_iload4(lsnes_invbinds
, "load $SLOT:4", "Load‣Slot 4");
960 keyboard::invbind_info
IBIND_iload5(lsnes_invbinds
, "load $SLOT:5", "Load‣Slot 5");
961 keyboard::invbind_info
IBIND_iload6(lsnes_invbinds
, "load $SLOT:6", "Load‣Slot 6");
962 keyboard::invbind_info
IBIND_iload7(lsnes_invbinds
, "load $SLOT:7", "Load‣Slot 7");
963 keyboard::invbind_info
IBIND_iload8(lsnes_invbinds
, "load $SLOT:8", "Load‣Slot 8");
964 keyboard::invbind_info
IBIND_iload9(lsnes_invbinds
, "load $SLOT:9", "Load‣Slot 9");
965 keyboard::invbind_info
IBIND_iload10(lsnes_invbinds
, "load $SLOT:10", "Load‣Slot 10");
966 keyboard::invbind_info
IBIND_iload11(lsnes_invbinds
, "load $SLOT:11", "Load‣Slot 11");
967 keyboard::invbind_info
IBIND_iload12(lsnes_invbinds
, "load $SLOT:12", "Load‣Slot 12");
968 keyboard::invbind_info
IBIND_iload13(lsnes_invbinds
, "load $SLOT:13", "Load‣Slot 13");
969 keyboard::invbind_info
IBIND_iload14(lsnes_invbinds
, "load $SLOT:14", "Load‣Slot 14");
970 keyboard::invbind_info
IBIND_iload15(lsnes_invbinds
, "load $SLOT:15", "Load‣Slot 15");
971 keyboard::invbind_info
IBIND_iload16(lsnes_invbinds
, "load $SLOT:16", "Load‣Slot 16");
972 keyboard::invbind_info
IBIND_iload17(lsnes_invbinds
, "load $SLOT:17", "Load‣Slot 17");
973 keyboard::invbind_info
IBIND_iload18(lsnes_invbinds
, "load $SLOT:18", "Load‣Slot 18");
974 keyboard::invbind_info
IBIND_iload19(lsnes_invbinds
, "load $SLOT:19", "Load‣Slot 19");
975 keyboard::invbind_info
IBIND_iload20(lsnes_invbinds
, "load $SLOT:20", "Load‣Slot 20");
976 keyboard::invbind_info
IBIND_iload21(lsnes_invbinds
, "load $SLOT:21", "Load‣Slot 21");
977 keyboard::invbind_info
IBIND_iload22(lsnes_invbinds
, "load $SLOT:22", "Load‣Slot 22");
978 keyboard::invbind_info
IBIND_iload23(lsnes_invbinds
, "load $SLOT:23", "Load‣Slot 23");
979 keyboard::invbind_info
IBIND_iload24(lsnes_invbinds
, "load $SLOT:24", "Load‣Slot 24");
980 keyboard::invbind_info
IBIND_iload25(lsnes_invbinds
, "load $SLOT:25", "Load‣Slot 25");
981 keyboard::invbind_info
IBIND_iload26(lsnes_invbinds
, "load $SLOT:26", "Load‣Slot 26");
982 keyboard::invbind_info
IBIND_iload27(lsnes_invbinds
, "load $SLOT:27", "Load‣Slot 27");
983 keyboard::invbind_info
IBIND_iload28(lsnes_invbinds
, "load $SLOT:28", "Load‣Slot 28");
984 keyboard::invbind_info
IBIND_iload29(lsnes_invbinds
, "load $SLOT:29", "Load‣Slot 29");
985 keyboard::invbind_info
IBIND_iload30(lsnes_invbinds
, "load $SLOT:30", "Load‣Slot 30");
986 keyboard::invbind_info
IBIND_iload31(lsnes_invbinds
, "load $SLOT:31", "Load‣Slot 31");
987 keyboard::invbind_info
IBIND_iload32(lsnes_invbinds
, "load $SLOT:32", "Load‣Slot 32");
988 keyboard::invbind_info
IBIND_isave1(lsnes_invbinds
, "save-state $SLOT:1", "Save‣Slot 1");
989 keyboard::invbind_info
IBIND_isave2(lsnes_invbinds
, "save-state $SLOT:2", "Save‣Slot 2");
990 keyboard::invbind_info
IBIND_isave3(lsnes_invbinds
, "save-state $SLOT:3", "Save‣Slot 3");
991 keyboard::invbind_info
IBIND_isave4(lsnes_invbinds
, "save-state $SLOT:4", "Save‣Slot 4");
992 keyboard::invbind_info
IBIND_isave5(lsnes_invbinds
, "save-state $SLOT:5", "Save‣Slot 5");
993 keyboard::invbind_info
IBIND_isave6(lsnes_invbinds
, "save-state $SLOT:6", "Save‣Slot 6");
994 keyboard::invbind_info
IBIND_isave7(lsnes_invbinds
, "save-state $SLOT:7", "Save‣Slot 7");
995 keyboard::invbind_info
IBIND_isave8(lsnes_invbinds
, "save-state $SLOT:8", "Save‣Slot 8");
996 keyboard::invbind_info
IBIND_isave9(lsnes_invbinds
, "save-state $SLOT:9", "Save‣Slot 9");
997 keyboard::invbind_info
IBIND_isave10(lsnes_invbinds
, "save-state $SLOT:10", "Save‣Slot 10");
998 keyboard::invbind_info
IBIND_isave11(lsnes_invbinds
, "save-state $SLOT:11", "Save‣Slot 11");
999 keyboard::invbind_info
IBIND_isave12(lsnes_invbinds
, "save-state $SLOT:12", "Save‣Slot 12");
1000 keyboard::invbind_info
IBIND_isave13(lsnes_invbinds
, "save-state $SLOT:13", "Save‣Slot 13");
1001 keyboard::invbind_info
IBIND_isave14(lsnes_invbinds
, "save-state $SLOT:14", "Save‣Slot 14");
1002 keyboard::invbind_info
IBIND_isave15(lsnes_invbinds
, "save-state $SLOT:15", "Save‣Slot 15");
1003 keyboard::invbind_info
IBIND_isave16(lsnes_invbinds
, "save-state $SLOT:16", "Save‣Slot 16");
1004 keyboard::invbind_info
IBIND_isave17(lsnes_invbinds
, "save-state $SLOT:17", "Save‣Slot 17");
1005 keyboard::invbind_info
IBIND_isave18(lsnes_invbinds
, "save-state $SLOT:18", "Save‣Slot 18");
1006 keyboard::invbind_info
IBIND_isave19(lsnes_invbinds
, "save-state $SLOT:19", "Save‣Slot 19");
1007 keyboard::invbind_info
IBIND_isave20(lsnes_invbinds
, "save-state $SLOT:20", "Save‣Slot 20");
1008 keyboard::invbind_info
IBIND_isave21(lsnes_invbinds
, "save-state $SLOT:21", "Save‣Slot 21");
1009 keyboard::invbind_info
IBIND_isave22(lsnes_invbinds
, "save-state $SLOT:22", "Save‣Slot 22");
1010 keyboard::invbind_info
IBIND_isave23(lsnes_invbinds
, "save-state $SLOT:23", "Save‣Slot 23");
1011 keyboard::invbind_info
IBIND_isave24(lsnes_invbinds
, "save-state $SLOT:24", "Save‣Slot 24");
1012 keyboard::invbind_info
IBIND_isave25(lsnes_invbinds
, "save-state $SLOT:25", "Save‣Slot 25");
1013 keyboard::invbind_info
IBIND_isave26(lsnes_invbinds
, "save-state $SLOT:26", "Save‣Slot 26");
1014 keyboard::invbind_info
IBIND_isave27(lsnes_invbinds
, "save-state $SLOT:27", "Save‣Slot 27");
1015 keyboard::invbind_info
IBIND_isave28(lsnes_invbinds
, "save-state $SLOT:28", "Save‣Slot 28");
1016 keyboard::invbind_info
IBIND_isave29(lsnes_invbinds
, "save-state $SLOT:29", "Save‣Slot 29");
1017 keyboard::invbind_info
IBIND_isave30(lsnes_invbinds
, "save-state $SLOT:30", "Save‣Slot 30");
1018 keyboard::invbind_info
IBIND_isave31(lsnes_invbinds
, "save-state $SLOT:31", "Save‣Slot 31");
1019 keyboard::invbind_info
IBIND_isave32(lsnes_invbinds
, "save-state $SLOT:32", "Save‣Slot 32");
1020 keyboard::invbind_info
IBIND_islot1(lsnes_invbinds
, "set-jukebox-slot 1", "Slot select‣Slot 1");
1021 keyboard::invbind_info
IBIND_islot2(lsnes_invbinds
, "set-jukebox-slot 2", "Slot select‣Slot 2");
1022 keyboard::invbind_info
IBIND_islot3(lsnes_invbinds
, "set-jukebox-slot 3", "Slot select‣Slot 3");
1023 keyboard::invbind_info
IBIND_islot4(lsnes_invbinds
, "set-jukebox-slot 4", "Slot select‣Slot 4");
1024 keyboard::invbind_info
IBIND_islot5(lsnes_invbinds
, "set-jukebox-slot 5", "Slot select‣Slot 5");
1025 keyboard::invbind_info
IBIND_islot6(lsnes_invbinds
, "set-jukebox-slot 6", "Slot select‣Slot 6");
1026 keyboard::invbind_info
IBIND_islot7(lsnes_invbinds
, "set-jukebox-slot 7", "Slot select‣Slot 7");
1027 keyboard::invbind_info
IBIND_islot8(lsnes_invbinds
, "set-jukebox-slot 8", "Slot select‣Slot 8");
1028 keyboard::invbind_info
IBIND_islot9(lsnes_invbinds
, "set-jukebox-slot 9", "Slot select‣Slot 9");
1029 keyboard::invbind_info
IBIND_islot10(lsnes_invbinds
, "set-jukebox-slot 10", "Slot select‣Slot 10");
1030 keyboard::invbind_info
IBIND_islot11(lsnes_invbinds
, "set-jukebox-slot 11", "Slot select‣Slot 11");
1031 keyboard::invbind_info
IBIND_islot12(lsnes_invbinds
, "set-jukebox-slot 12", "Slot select‣Slot 12");
1032 keyboard::invbind_info
IBIND_islot13(lsnes_invbinds
, "set-jukebox-slot 13", "Slot select‣Slot 13");
1033 keyboard::invbind_info
IBIND_islot14(lsnes_invbinds
, "set-jukebox-slot 14", "Slot select‣Slot 14");
1034 keyboard::invbind_info
IBIND_islot15(lsnes_invbinds
, "set-jukebox-slot 15", "Slot select‣Slot 15");
1035 keyboard::invbind_info
IBIND_islot16(lsnes_invbinds
, "set-jukebox-slot 16", "Slot select‣Slot 16");
1036 keyboard::invbind_info
IBIND_islot17(lsnes_invbinds
, "set-jukebox-slot 17", "Slot select‣Slot 17");
1037 keyboard::invbind_info
IBIND_islot18(lsnes_invbinds
, "set-jukebox-slot 18", "Slot select‣Slot 18");
1038 keyboard::invbind_info
IBIND_islot19(lsnes_invbinds
, "set-jukebox-slot 19", "Slot select‣Slot 19");
1039 keyboard::invbind_info
IBIND_islot20(lsnes_invbinds
, "set-jukebox-slot 20", "Slot select‣Slot 20");
1040 keyboard::invbind_info
IBIND_islot21(lsnes_invbinds
, "set-jukebox-slot 21", "Slot select‣Slot 21");
1041 keyboard::invbind_info
IBIND_islot22(lsnes_invbinds
, "set-jukebox-slot 22", "Slot select‣Slot 22");
1042 keyboard::invbind_info
IBIND_islot23(lsnes_invbinds
, "set-jukebox-slot 23", "Slot select‣Slot 23");
1043 keyboard::invbind_info
IBIND_islot24(lsnes_invbinds
, "set-jukebox-slot 24", "Slot select‣Slot 24");
1044 keyboard::invbind_info
IBIND_islot25(lsnes_invbinds
, "set-jukebox-slot 25", "Slot select‣Slot 25");
1045 keyboard::invbind_info
IBIND_islot26(lsnes_invbinds
, "set-jukebox-slot 26", "Slot select‣Slot 26");
1046 keyboard::invbind_info
IBIND_islot27(lsnes_invbinds
, "set-jukebox-slot 27", "Slot select‣Slot 27");
1047 keyboard::invbind_info
IBIND_islot28(lsnes_invbinds
, "set-jukebox-slot 28", "Slot select‣Slot 28");
1048 keyboard::invbind_info
IBIND_islot29(lsnes_invbinds
, "set-jukebox-slot 29", "Slot select‣Slot 29");
1049 keyboard::invbind_info
IBIND_islot30(lsnes_invbinds
, "set-jukebox-slot 30", "Slot select‣Slot 30");
1050 keyboard::invbind_info
IBIND_islot31(lsnes_invbinds
, "set-jukebox-slot 31", "Slot select‣Slot 31");
1051 keyboard::invbind_info
IBIND_islot32(lsnes_invbinds
, "set-jukebox-slot 32", "Slot select‣Slot 32");
1053 class mywindowcallbacks
: public master_dumper::notifier
1056 mywindowcallbacks(emulator_dispatch
& dispatch
)
1058 closenotify
.set(dispatch
.close
, [this]() {
1060 amode
= ADVANCE_QUIT
;
1061 quit_magic
= QUIT_MAGIC
;
1062 platform::set_paused(false);
1063 platform::cancel_wait();
1068 ~mywindowcallbacks() throw() {}
1069 void dump_status_change() throw()
1071 update_movie_state();
1074 struct dispatch::target
<> closenotify
;
1077 //If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
1081 auto& core
= CORE();
1082 std::string old_project
= *core
.mlogic
? core
.mlogic
->get_mfile().projectid
: "";
1084 if(do_unsafe_rewind
&& unsafe_rewind_obj
) {
1087 uint64_t t
= framerate_regulator::get_utime();
1088 std::vector
<char> s
;
1089 core
.lua2
->callback_do_unsafe_rewind(s
, 0, 0, core
.mlogic
->get_movie(), unsafe_rewind_obj
);
1090 core
.dispatch
->mode_change(false);
1091 do_unsafe_rewind
= false;
1092 core
.mlogic
->get_mfile().is_savestate
= true;
1093 location_special
= SPECIAL_SAVEPOINT
;
1094 update_movie_state();
1095 messages
<< "Rewind done in " << (framerate_regulator::get_utime() - t
) << " usec."
1099 if(pending_new_project
!= "") {
1100 std::string id
= pending_new_project
;
1101 pending_new_project
= "";
1102 project_info
* old
= core
.project
->get();
1103 if(old
&& old
->id
== id
)
1106 auto& p
= core
.project
->load(id
);
1107 core
.project
->set(&p
);
1108 if(core
.project
->get() != old
)
1110 core
.slotcache
->flush(); //Wrong movie may be stale.
1112 } catch(std::exception
& e
) {
1113 platform::error_message(std::string("Can't switch projects: ") + e
.what());
1114 messages
<< "Can't switch projects: " << e
.what() << std::endl
;
1119 platform::set_paused(amode
== ADVANCE_PAUSE
);
1120 platform::flush_command_queue();
1121 if(amode
== ADVANCE_LOAD
)
1125 if(pending_load
!= "") {
1126 bool system_was_corrupt
= system_corrupt
;
1127 system_corrupt
= false;
1129 if(loadmode
!= LOAD_STATE_BEGINNING
&& loadmode
!= LOAD_STATE_ROMRELOAD
&&
1130 !do_load_state(pending_load
, loadmode
)) {
1131 if(system_was_corrupt
)
1132 system_corrupt
= system_was_corrupt
;
1136 if(loadmode
== LOAD_STATE_BEGINNING
)
1138 if(loadmode
== LOAD_STATE_ROMRELOAD
)
1140 } catch(std::exception
& e
) {
1141 if(!system_corrupt
&& system_was_corrupt
)
1142 system_corrupt
= true;
1143 platform::error_message(std::string("Load failed: ") + e
.what());
1144 messages
<< "Load failed: " << e
.what() << std::endl
;
1147 amode
= load_paused
? ADVANCE_PAUSE
: ADVANCE_AUTO
;
1148 platform::set_paused(load_paused
);
1149 load_paused
= false;
1150 if(!system_corrupt
) {
1151 location_special
= SPECIAL_SAVEPOINT
;
1152 update_movie_state();
1153 platform::flush_command_queue();
1156 if(amode
== ADVANCE_LOAD
)
1159 if(old_project
!= (*core
.mlogic
? core
.mlogic
->get_mfile().projectid
: ""))
1160 core
.slotcache
->flush(); //Wrong movie may be stale.
1166 //If there are pending saves, perform them.
1169 auto& core
= CORE();
1172 if(!queued_saves
.empty() || (do_unsafe_rewind
&& !unsafe_rewind_obj
)) {
1173 core
.rom
->rtype
->runtosave();
1174 for(auto i
: queued_saves
) {
1175 do_save_state(i
.first
, i
.second
);
1177 core
.slotcache
->flush(translate_name_mprefix(i
.first
, tmp
, -1));
1179 if(do_unsafe_rewind
&& !unsafe_rewind_obj
) {
1180 uint64_t t
= framerate_regulator::get_utime();
1181 std::vector
<char> s
= core
.rom
->save_core_state(true);
1182 uint64_t secs
= core
.mlogic
->get_mfile().rtc_second
;
1183 uint64_t ssecs
= core
.mlogic
->get_mfile().rtc_subsecond
;
1184 core
.lua2
->callback_do_unsafe_rewind(s
, secs
, ssecs
, core
.mlogic
->get_movie(),
1186 do_unsafe_rewind
= false;
1187 messages
<< "Rewind point set in " << (framerate_regulator::get_utime() - t
)
1188 << " usec." << std::endl
;
1191 queued_saves
.clear();
1194 bool handle_corrupt()
1198 while(system_corrupt
) {
1199 platform::set_paused(true);
1200 platform::flush_command_queue();
1209 void init_main_callbacks()
1211 ecore_callbacks
= &lsnes_callbacks_obj
;
1214 void main_loop(struct loaded_rom
& rom
, struct moviefile
& initial
, bool load_has_to_succeed
) throw(std::bad_alloc
,
1217 lsnes_instance
.emu_thread
= threads::id();
1218 auto& core
= CORE();
1219 mywindowcallbacks
mywcb(*core
.dispatch
);
1220 core
.iqueue
->system_thread_available
= true;
1221 //Basic initialization.
1222 jukebox_size_listener
jlistener(*core
.settings
);
1223 core
.commentary
->init();
1224 core
.fbuf
->init_special_screens();
1226 init_main_callbacks();
1227 initialize_all_builtin_c_cores();
1228 core_core::install_all_handlers();
1230 //Load our given movie.
1231 bool first_round
= false;
1232 bool just_did_loadstate
= false;
1235 do_load_state(initial
, LOAD_STATE_INITIAL
, used
);
1236 location_special
= SPECIAL_SAVEPOINT
;
1237 update_movie_state();
1238 first_round
= core
.mlogic
->get_mfile().is_savestate
;
1239 just_did_loadstate
= first_round
;
1240 } catch(std::bad_alloc
& e
) {
1242 } catch(std::exception
& e
) {
1245 platform::error_message(std::string("Can't load initial state: ") + e
.what());
1246 messages
<< "ERROR: Can't load initial state: " << e
.what() << std::endl
;
1247 if(load_has_to_succeed
) {
1248 messages
<< "FATAL: Can't load movie" << std::endl
;
1251 system_corrupt
= true;
1252 core
.fbuf
->redraw_framebuffer(emu_framebuffer::screen_corrupt
);
1255 platform::set_paused(initial
.start_paused
);
1256 amode
= initial
.start_paused
? ADVANCE_PAUSE
: ADVANCE_AUTO
;
1257 stop_at_frame_active
= false;
1259 core
.lua2
->run_startup_scripts();
1261 while(!is_quitting() || !queued_saves
.empty()) {
1262 if(handle_corrupt()) {
1263 first_round
= *core
.mlogic
&& core
.mlogic
->get_mfile().is_savestate
;
1264 just_did_loadstate
= first_round
;
1267 core
.framerate
->ack_frame_tick(framerate_regulator::get_utime());
1268 if(amode
== ADVANCE_SKIPLAG_PENDING
)
1269 amode
= ADVANCE_SKIPLAG
;
1272 core
.controls
->reset_framehold();
1273 if(!macro_hold_1
&& !macro_hold_2
) {
1274 core
.controls
->advance_macros();
1276 macro_hold_2
= false;
1277 core
.mlogic
->get_movie().get_pollcounters().set_framepflag(false);
1278 core
.mlogic
->new_frame_starting(amode
== ADVANCE_SKIPLAG
);
1279 core
.mlogic
->get_movie().get_pollcounters().set_framepflag(true);
1280 if(is_quitting() && queued_saves
.empty())
1284 if(queued_saves
.empty())
1286 if(r
> 0 || system_corrupt
) {
1287 core
.mlogic
->get_movie().get_pollcounters().set_framepflag(
1288 core
.mlogic
->get_mfile().is_savestate
);
1289 first_round
= core
.mlogic
->get_mfile().is_savestate
;
1291 amode
= ADVANCE_PAUSE
;
1294 stop_at_frame_active
= false;
1295 just_did_loadstate
= first_round
;
1296 core
.controls
->reset_framehold();
1297 core
.dbg
->do_callback_frame(core
.mlogic
->get_movie().get_current_frame(), true);
1300 //Not exactly desriable, but this at least won't desync.
1301 stop_at_frame_active
= false;
1304 amode
= ADVANCE_PAUSE
;
1307 if(just_did_loadstate
) {
1308 //If we just loadstated, we are up to date.
1311 platform::set_paused(amode
== ADVANCE_PAUSE
);
1312 platform::flush_command_queue();
1313 //We already have done the reset this frame if we are going to do one at all.
1314 core
.mlogic
->get_movie().set_controls(core
.mlogic
->update_controls(true));
1315 core
.mlogic
->get_movie().set_all_DRDY();
1316 just_did_loadstate
= false;
1318 core
.dbg
->do_callback_frame(core
.mlogic
->get_movie().get_current_frame(), false);
1319 core
.rom
->rtype
->emulate();
1320 random_mix_timing_entropy();
1321 if(amode
== ADVANCE_AUTO
)
1322 platform::wait(core
.framerate
->to_wait_frame(framerate_regulator::get_utime()));
1323 first_round
= false;
1324 core
.lua2
->callback_do_frame();
1327 core
.mdumper
->end_dumps();
1328 core_core::uninstall_all_handlers();
1329 core
.commentary
->kill();
1330 core
.iqueue
->system_thread_available
= false;
1331 //Kill some things to avoid crashes.
1332 core
.dbg
->core_change();
1333 core
.project
->set(NULL
, true);
1334 core
.mwatch
->clear_multi(core
.mwatch
->enumerate());
1337 void set_stop_at_frame(uint64_t frame
)
1339 stop_at_frame
= frame
;
1340 stop_at_frame_active
= (frame
!= 0);
1341 amode
= ADVANCE_AUTO
;
1342 platform::set_paused(false);
1345 void do_flush_slotinfo()
1347 CORE().slotcache
->flush();
1350 void switch_projects(const std::string
& newproj
)
1352 pending_new_project
= newproj
;
1353 amode
= ADVANCE_LOAD
;
1354 old_mode
= ADVANCE_PAUSE
;
1355 platform::cancel_wait();
1356 platform::set_paused(false);
1359 void load_new_rom(const romload_request
& req
)
1361 if(_load_new_rom(req
)) {
1362 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
1366 void reload_current_rom()
1368 if(reload_active_rom()) {
1369 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
1375 if(load_null_rom()) {
1377 mark_pending_load("SOME NONBLANK NAME", LOAD_STATE_ROMRELOAD
);
1381 void do_break_pause()
1383 amode
= ADVANCE_BREAK_PAUSE
;
1384 update_movie_state();
1385 while(amode
== ADVANCE_BREAK_PAUSE
) {
1386 platform::set_paused(true);
1387 platform::flush_command_queue();
1391 void convert_break_to_pause()
1393 if(amode
== ADVANCE_BREAK_PAUSE
) {
1394 amode
= ADVANCE_PAUSE
;
1395 update_movie_state();
1399 void debug_trash_memory(uint8_t* addr
, uint8_t byte
)