By the way, in what consists your idea?henke37 wrote:I doubt that he is skilled enough at asm to pull off my crazy idea, but he sure is free to try. He is most definitely mad enough since he did this already.
bsnes v0.039 released
-
- ZSNES Shake Shake Prinny
- Posts: 5632
- Joined: Wed Jul 28, 2004 4:15 pm
- Location: PAL50, dood !
You forgot 'profit!!' right there...creaothceann wrote:Depends on what can be turned into threads.
- GUI (main program)
- SNES CPU
- SNES PPU
- SNES APU (sound)
- cartridge chips (Super FX / SA-1 / ...)
- graphics filters
- ?
皆黙って俺について来い!!
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
Code: Select all
<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
-
- Seen it all
- Posts: 2302
- Joined: Mon Jan 03, 2005 5:04 pm
- Location: Germany
- Contact:
Shhh! Can't have Big N know about No$snes. 

vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
bsnes launcher with recent files list
If he posts it here, it will show up on emulator sites and probably become more popular than the official version. Just fair warning. You guys should pm each other, work something out.byuu wrote:If he wants to post it here, I don't mind. Kind of curious how he managed to state machine all ~150kb of relevant code -- it's incredibly monotonous making those things. But I really don't want to see it end up on every emulator site ala Snes9X forks if at all possible.
-
- Rookie
- Posts: 35
- Joined: Fri Feb 20, 2009 3:49 am
It's a tweak to the cothreading library mainly.Chester wrote:By the way, in what consists your idea?
You add support to save and load stacks. Yes, those that the return address and such is stored in. It involves reading debugging symbols, remapping pointers to storeable values, and both parsing and generating stackframes.
The details can be read in another topic in this forum.
It's a highly advanced solution that will lock savestates to a specific build of the emulator, but it is theoretically possible. Just like it is theoretically possible to make a snes emulator in c++. But it is quite difficult.
New WIP.
Added fix for OAM Yflip overflow bug pointed out by Jonas Quinn.
Re-added QGroupBox controls as per discussion with jensbw, the frame issue should be fixed with Qt 4.5.
Config file now omits " #" marker when there is no item description.
Main window resizes itself a bit better before showing itself on Linux for the first time. Not a problem at all on Windows.
Using _wgetcwd instead of getcwd for Windows UTF-8 support.
Finished Cartridge class revisions: load_foo returns boolean success, unload() doesn't need one so that was removed, dropped redundant bsx_cart_loaded() as you can tell via mode() == ModeBsx. Still need bsx_flash_loaded() for register mapping purposes.
Fixed hiro port to compile again.
I also rewrote much of the Xv driver. It now properly finds modes via XvListImageFormats(), and I added support for more modes. It used to be YUY2 only, now it supports RGB32, RGB24, RGB16, RGB15, YUY2 and UYVY (chooses the driver mode in that order.)
Unfortunately I was only able to test YUY2 and UYVY with my driver, so no idea if the RGB modes even work or not. I know RGB16/RGB15 will have problems, forgot to mask the blue channel before uploading: for line 344 and 359, (p >> 3) needs to be ((p >> 3) & 0x1f).
To test each mode, the optimal ones would have to be manually disabled since there's no external way to select the preferred driver. And the RGB32 copy is sub-optimal, I'll probably allow direct rendering to its surface in a future revision.
Added fix for OAM Yflip overflow bug pointed out by Jonas Quinn.
Re-added QGroupBox controls as per discussion with jensbw, the frame issue should be fixed with Qt 4.5.
Config file now omits " #" marker when there is no item description.
Main window resizes itself a bit better before showing itself on Linux for the first time. Not a problem at all on Windows.
Using _wgetcwd instead of getcwd for Windows UTF-8 support.
Finished Cartridge class revisions: load_foo returns boolean success, unload() doesn't need one so that was removed, dropped redundant bsx_cart_loaded() as you can tell via mode() == ModeBsx. Still need bsx_flash_loaded() for register mapping purposes.
Fixed hiro port to compile again.
I also rewrote much of the Xv driver. It now properly finds modes via XvListImageFormats(), and I added support for more modes. It used to be YUY2 only, now it supports RGB32, RGB24, RGB16, RGB15, YUY2 and UYVY (chooses the driver mode in that order.)
Unfortunately I was only able to test YUY2 and UYVY with my driver, so no idea if the RGB modes even work or not. I know RGB16/RGB15 will have problems, forgot to mask the blue channel before uploading: for line 344 and 359, (p >> 3) needs to be ((p >> 3) & 0x1f).
To test each mode, the optimal ones would have to be manually disabled since there's no external way to select the preferred driver. And the RGB32 copy is sub-optimal, I'll probably allow direct rendering to its surface in a future revision.
rightThere are only 2 threads, so more cores won't help.
No, it's not necessary. I am not interested to maintain an emulator for a user base. I don't have any experience in finding emulation bugs, making test roms for the real snes and so on. It's a really time consuming job. My motivation is to understand how the code works and building it my way. I have used too much time reading and understanding bsnes source, in particular the DSP code (don't understand the gauss interpolation) The main cause to show my work now is to find out by other emulator developers, in particular byuu, if something is wrong in my idea with the bus accurate state machine.If he posts it here, it will show up on emulator sites and probably become more popular than the official version. Just fair warning. You guys should pm each other, work something out.
I have began to read your source code in that time where each cpu and smp opcode was splitted into cycles. So I don't have rebuild that cycle accuracy. What I have done to get bus accuracy as a statemachine is following:That sounds about right to what I was getting when I had the S-CPU / S-SMP cores encoded with state machines for each cycle. You must've found some clever workaround to get the bus hold delays supported properly without another state machine for each read/write cycle, then ... not bad. Especially for the S-CPU DMA, tons of cycle access functions there where they call several levels deep to simplify the code.
The Cpu and DMA approach is the same like in bsnes. The exception are the stp and wai opcodes.
Code: Select all
#define _implied_stp(code)
\
void Cpu::op##code() {
\
if(!state_stop) { cpu_io(); state_stop = true; } \
if(state_stop) { cpu_io(); }}
_implied_stp(db)
#undef _implied_stp
#define _implied_wai(code)
\
void Cpu::op##code() {
\
state_wait = true;
\
if(state_wait) { check_for_interrupts(); cpu_io(); } \
if(!state_wait) cpu_io(); }
_implied_wai(cb)
#undef _implied_wai
The cpu opcode execution is like that:
void Cpu::execute_opcode()
{
if(state_wait) (this->*opcodes[0xcb])();
else if(state_stop) (this->*opcodes[0xdb])();
else {
reg_mdr = read_mem(reg_pc_d);
reg_pc_w++;
(this->*opcodes[reg_mdr])();
}
}
other opcodes are not cycled with a switch/case for example:
#define _absolute_indexed_with_x(flag, instr, code) \
void Cpu::op##code() { \
rd_pc(aa_l); \
rd_pc(aa_h); \
cpu_io_con_4(reg_x_w); \
if(reg_p_##flag) check_for_interrupts(); \
rd_dbr(aa_w + reg_x_w, data_l); \
if(reg_p_##flag) { instr(l); return; } \
check_for_interrupts(); \
rd_dbr(aa_w + reg_x_w + 1, data_h); \
instr(w); }
_absolute_indexed_with_x(m, adc, 7d)
_absolute_indexed_with_x(m, and, 3d)
_absolute_indexed_with_x(m, bit, 3c)
_absolute_indexed_with_x(m, cmp, dd)
_absolute_indexed_with_x(m, eor, 5d)
_absolute_indexed_with_x(m, lda, bd)
_absolute_indexed_with_x(x, ldy, bc)
_absolute_indexed_with_x(m, ora, 1d)
_absolute_indexed_with_x(m, sbc, fd)
#undef _absolute_indexed_with_x
Code: Select all
void Smp::add_clocks(u8 clock_cycles)
{
cpu.add_smp_clocks(clock_cycles);
if(cpu.get_clocks() > 480000000000) sync_to_cpu = true;
smp_dsp_clock -= clock_cycles * (u64)Dsp_Freq;
if(smp_dsp_clock < 0) dsp.run();
}
bool Smp::sync_cpu(u16 addr, u8 value, u8* target, u8 job)
{
if(cpu.get_clocks() >= 0)
{
sync_to_cpu = true;
scheduler.job = job;
scheduler.value = value;
scheduler.addr = addr;
scheduler.target = target;
return true;
}
return false;
}
void Smp::run()
{
if (scheduler.job != none)
{
if (scheduler.job == cpu_read) busread(scheduler.addr, scheduler.target, true);
else if (scheduler.job == cpu_write) buswrite(scheduler.addr, scheduler.value,
true);
scheduler.job = none;
}
while(!sync_to_cpu)
{
if (cycle_pos) (this->*opcodes[opcode])();
else
{
busread(reg_pc++, &opcode);
cycle_pos = 1;
}
}
sync_to_cpu = false;
}
void Smp::busread(u16 addr, u8* target, bool no_sync)
{
if (!no_sync) add_clocks(12);
if((addr & 0xfff0) == 0x00f0) //0x00f0->0x00ff
{
switch(addr)
{
case 0xf0: //TEST -- write-only register
*target = 0x00;
break;
case 0xf1: //CONTROL -- write-only register
*target = 0x00;
break;
case 0xf2: //DSPADDR
*target = dsp_addr;
break;
case 0xf3: //DSPDATA
*target = dsp.read(dsp_addr & 0x7f);
break;
case 0xf4: //CPUIO0
case 0xf5: //CPUIO1
case 0xf6: //CPUIO2
case 0xf7: //CPUIO3
if (!no_sync) { if (sync_cpu(addr, 0, target, cpu_read)) return;
}
*target = cpu.port_read(addr & 3);
break;
case 0xf8: //???
*target = smp_f8;
break;
case 0xf9: //???
*target = smp_f9;
break;
case 0xfa: //T0TARGET
case 0xfb: //T1TARGET
case 0xfc: //T2TARGET -- write-only registers
*target = 0x00;
break;
case 0xfd: //T0OUT -- 4-bit counter value
*target = t0.stage3_ticks & 15;
t0.stage3_ticks = 0;
break;
case 0xfe: //T1OUT -- 4-bit counter value
*target = t1.stage3_ticks & 15;
t1.stage3_ticks = 0;
break;
case 0xff: //T2OUT -- 4-bit counter value
*target = t2.stage3_ticks & 15;
t2.stage3_ticks = 0;
break;
}
}
else if(addr < 0xffc0) *target = spcram[addr];
else
{
if(iplrom_enabled) *target = iplrom[addr & 0x3f];
else *target = spcram[addr];
}
add_clocks(12);
set_timers();
}
void Smp::buswrite(u16 addr, u8 value, bool no_sync)
{
if (!no_sync) add_clocks(24);
if((addr & 0xfff0) == 0x00f0)
{
if(mmio_disabled) { set_timers(); return; }
switch(addr)
{
case 0xf0: //TEST
if(reg_p_p) break;
mmio_disabled = !!(value & 0x04);
ram_writable = !!(value & 0x02);
break;
case 0xf1: //CONTROL
iplrom_enabled = !!(value & 0x80);
if(value & 0x30)
{
if (!no_sync) { if (sync_cpu(addr, value, 0, cpu_write))
return; }
if(value & 0x20) { cpu.port_write(2, 0x00);
cpu.port_write(3, 0x00); }
if(value & 0x10) { cpu.port_write(0, 0x00);
cpu.port_write(1, 0x00); }
}
//0->1 transistion resets timers
if(!t2.enabled && (value & 0x04)) t2.stage2_ticks =
t2.stage3_ticks = 0;
t2.enabled = !!(value & 0x04);
if(!t1.enabled && (value & 0x02)) t1.stage2_ticks =
t1.stage3_ticks = 0;
t1.enabled = !!(value & 0x02);
if(!t0.enabled && (value & 0x01)) t0.stage2_ticks =
t0.stage3_ticks = 0;
t0.enabled = !!(value & 0x01);
break;
case 0xf2: //DSPADDR
dsp_addr = value;
break;
case 0xf3: //DSPDATA
if(!(dsp_addr & 0x80)) dsp.write(dsp_addr & 0x7f, value);
break;
case 0xf4: //CPUIO0
case 0xf5: //CPUIO1
case 0xf6: //CPUIO2
case 0xf7: //CPUIO3
if (!no_sync) { if (sync_cpu(addr, value, 0, cpu_write)) return;
}
port_write(addr & 3, value);
break;
case 0xf8: //???
smp_f8 = value;
break;
case 0xf9: //???
smp_f9 = value;
break;
case 0xfa: //T0TARGET
t0.target = value;
break;
case 0xfb: //T1TARGET
t1.target = value;
break;
case 0xfc: //T2TARGET
t2.target = value;
break;
case 0xfd: //T0OUT
case 0xfe: //T1OUT
case 0xff: //T2OUT -- read-only registers
break;
}
}
if(ram_writable) spcram[addr] = value;
set_timers();
}
Code: Select all
//memory access
#define _read_pc(target) busread(reg_pc++, &target);
#define _read_dp(addr, target) busread((u16(reg_p_p) << 8) + (addr & 0xFF), &target);
#define _write_dp(addr, value) buswrite((u16(reg_p_p) << 8) + (addr & 0xFF), value);
#define _read_addr(addr, target) busread(addr & 0xFFFF, &target);
#define _write_addr(addr, value) buswrite(addr & 0xFFFF, value);
#define _read_stack(target) busread(0x0100 | ++reg_s, &target);
#define _write_stack(value) buswrite(0x0100 | reg_s--, value);
//logic
#define zero(_r) reg_p_z = (_r == 0)
#define neg(_r) reg_p_n = !!(_r & 0x80)
u8 Smp::_adc(u8 x, u8 y)
{
u16 tmp = x + y + reg_p_c;
neg(tmp);
zero(u8(tmp));
reg_p_c = (tmp > 0xff);
reg_p_v = !!(~(x ^ y) & (x ^ (u8)tmp) & 0x80);
reg_p_h = !!((x ^ y ^ (u8)tmp) & 0x10);
return u8(tmp);
}
#define adc(x, y, res) res = _adc(x, y);
#define sbc(x, y, res) res = _adc(x, y ^ 0xff);
#define addw(x, y) \
reg_p_c = 0; \
u16 tmp; \
tmp = _adc(x & 0xFF, y & 0xFF); \
tmp |= _adc(x >> 8, y >> 8) << 8; \
zero(tmp); \
reg_ya = tmp;
#define subw(x, y) \
reg_p_c = 1; \
u16 tmp; \
tmp = _adc(x & 0xFF, (y & 0xFF) ^ 0xFF); \
tmp |= _adc(x >> 8, (y >> 8) ^ 0xFF) << 8; \
zero(tmp); \
reg_ya = tmp;
#define and(x, y, res) res = x & y; zero(res); neg(res);
#define cmp(x, y, res) i16 tmp = x - y; zero(u8(tmp)); neg(tmp); reg_p_c = (tmp >= 0);
#define cmpw(x, y) i32 tmp = x - y; zero(u16(tmp)); reg_p_n = !!(tmp & 0x8000); reg_p_c = (tmp
>= 0);
#define eor(x, y, res) res = x ^ y; zero(res); neg(res);
#define or(x, y, res) res = x | y; zero(res); neg(res);
#define inc(x) x++; zero(x); neg(x);
#define dec(x) x--; zero(x); neg(x);
#define asl(x) reg_p_c = !!(x & 0x80); x <<= 1; zero(x); neg(x);
#define lsr(x) reg_p_c = !!(x & 0x01); x >>= 1; zero(x); neg(x);
#define rol(x) bool tmp = !!(x & 0x80); x <<= 1; x |= u8(reg_p_c); reg_p_c = tmp; zero(x);
neg(x);
#define ror(x) bool tmp = x & 1; x >>= 1; x |= reg_p_c << 7; reg_p_c = tmp; zero(x); neg(x);
//1 Register, Immediate -- A,#i; X,#i; Y,#i
#define _immediate(reg, instr, code) \
void Smp::op##code() { \
switch(cycle_pos++) { \
case 1: \
_read_pc(data) \
break; \
case 2: \
cycle_pos = 0; \
instr(reg_##reg, data, reg_##reg) \
break; } }
_immediate(a, adc, 88)
_immediate(a, and, 28)
_immediate(a, cmp, 68)
_immediate(x, cmp, c8)
_immediate(y, cmp, ad)
_immediate(a, eor, 48)
_immediate(a, or, 08)
_immediate(a, sbc, a8)
#undef _immediate
#define _mov_immediate(dest, code) \
void Smp::op##code() { \
switch(cycle_pos++) { \
case 1: \
_read_pc(reg_##dest) \
break; \
case 2: \
cycle_pos = 0; \
neg(reg_##dest); \
zero(reg_##dest); \
break; } }
//6 Register, Indexed Indirect -- A,[d+X]
#define _indexed_indirect(instr, code) \
void Smp::op##code() { \
switch(cycle_pos++) { \
case 1: \
_read_pc(_do) \
break; \
case 2: \
smp_io(); \
_do += reg_x; \
_read_dp(_do, aa_l) \
break; \
case 3: \
_read_dp(_do+1, aa_h) \
break; \
case 4: \
_read_addr(aa_w, data) \
break; \
case 5: \
cycle_pos = 0; \
instr(reg_a, data, reg_a) \
break; } }
_indexed_indirect(adc, 87)
_indexed_indirect(and, 27)
_indexed_indirect(cmp, 67)
_indexed_indirect(eor, 47)
_indexed_indirect(or, 07)
_indexed_indirect(sbc, a7)
#undef _indexed_indirect
New WIP.
- added hardware settings group to advanced panel. Lets you control hardware region and base unit.
- added descriptive tooltips to video and audio settings.
- revised documentation to list filetypes, mention BS-X issues and generalize unsupported special chip notes
- improved handling of paths: core now keeps track of cartridge path rather than relying on the current working directory; export data path now works the same as SRAM / cheats / etc when not selected
- fixed XvRGB15/16 blue color channel glitch; testing would be much appreciated
- I now set the drivers to "None" when they fail to initialize and give a warning. Before the app would just crash on cart load if this failed
- added more options to the config file: allow invalid input, analog axis resistance, and for the first time ever -- CPU, PPU1 and PPU2 version configuration
Really not happy with the overall look and feel of the advanced panel. I don't think the group boxes are working there. Also, the filetype descriptions are very terse, but I like them that way. Don't really care if someone doesn't know what 'non-volatile' means, that's why god made Google. Complain and I'll make the complex terms hyperlinks to Wikipedia :P
I'll look into the fullscreen menubar thing again in a few days or something.
I can certainly see why others get so upset with me on this, but having each module cleanly separated is, to me, more important than savestates. That it's somewhat faster here is just an added bonus. I'm sure you can appreciate my S-SMP op_*.b files over those state machines for maintenance, too ;)
As for your work on rewriting all the S-SMP opcodes, I wish you would've mentioned this to me earlier ... the cycle labels in those .b files are used to create the exact same switch(cycle) {} code you wrote automatically, you just have to use a different generator. Given I dropped that generator back at ~v017, it should be easy to update / rewrite. The downside is that they don't directly support the bus hold delays.
Still overall, really really impressive stuff. Kudos on making something so cool :D
- added hardware settings group to advanced panel. Lets you control hardware region and base unit.
- added descriptive tooltips to video and audio settings.
- revised documentation to list filetypes, mention BS-X issues and generalize unsupported special chip notes
- improved handling of paths: core now keeps track of cartridge path rather than relying on the current working directory; export data path now works the same as SRAM / cheats / etc when not selected
- fixed XvRGB15/16 blue color channel glitch; testing would be much appreciated
- I now set the drivers to "None" when they fail to initialize and give a warning. Before the app would just crash on cart load if this failed
- added more options to the config file: allow invalid input, analog axis resistance, and for the first time ever -- CPU, PPU1 and PPU2 version configuration
Really not happy with the overall look and feel of the advanced panel. I don't think the group boxes are working there. Also, the filetype descriptions are very terse, but I like them that way. Don't really care if someone doesn't know what 'non-volatile' means, that's why god made Google. Complain and I'll make the complex terms hyperlinks to Wikipedia :P
I'll look into the fullscreen menubar thing again in a few days or something.
Heheh, I bet someone looking at STP without being aware of how the cothreads work would gasp in horror :DThe Cpu and DMA approach is the same like in bsnes. The exception are the stp and wai opcodes.
Yeah, I know it's possible with enslavement to only make the simpler processor a state machine. In our case, the S-SMP. That's how SNEeSe does it. I just really hate the idea of enslavement.You are right it's really hard to jump back from doing a nested hdma transfer within a dma. But with my approach such an action is not needed.
I can certainly see why others get so upset with me on this, but having each module cleanly separated is, to me, more important than savestates. That it's somewhat faster here is just an added bonus. I'm sure you can appreciate my S-SMP op_*.b files over those state machines for maintenance, too ;)
As for your work on rewriting all the S-SMP opcodes, I wish you would've mentioned this to me earlier ... the cycle labels in those .b files are used to create the exact same switch(cycle) {} code you wrote automatically, you just have to use a different generator. Given I dropped that generator back at ~v017, it should be easy to update / rewrite. The downside is that they don't directly support the bus hold delays.
Still overall, really really impressive stuff. Kudos on making something so cool :D
Haven't tried SNEeSe, is the smp <> cpu communication in SNEeSe bus accurate?Yeah, I know it's possible with enslavement to only make the simpler processor a state machine. In our case, the S-SMP. That's how SNEeSe does it. I just really hate the idea of enslavement.
Like you, I like the accuracy and hate countless hacks, of which you can never say for sure it's the last one needed. But I wouldn't sacrifice savestates against a more logical design of an emulator. I could finish a lot of games to the end only with savestates, not with cheats. There are situations, where cheats don't help. I would agree with you, if there is only a really complex way possible to build a statemachine with current accuracy. In such a case, it would introduce a lot of hard to spot coding errors.I can certainly see why others get so upset with me on this, but having each module cleanly separated is, to me, more important than savestates.
Yes I know your generator. In the beginning I have adapted it. Later I have decided for the preprocessor style. The preprocessor style gives the same execution speed like automatic generation, but debugging isn't fun. I haven't fully trusted the automatic generation, so I checked each line two or three times.Given I dropped that generator back at ~v017, it should be easy to update / rewrite. The downside is that they don't directly support the bus hold delays.
Thank you, so your source code was the motivation in trying to understand how it works. Not the hard to read asm stuff, found in other emulators.Still overall, really really impressive stuff. Kudos on making something so cool
I don't believe so. Hell, mine's probably not exactly right, either. It's modeled off of the S-CPU bus, which we can observe thanks to the latch counters and such.Haven't tried SNEeSe, is the smp <> cpu communication in SNEeSe bus accurate?
It's hard to measure on real hardware since the actual crystal clocks of the two chips vary slightly per hardware unit. Thus, it's probably not terribly important. If it's causing a large speed it, making it cycle accurate should be more than enough without losing any compatibility.
Definitely for some games, yeah. Like Drac X PSP's Stage 5' lower path. Holy shit.I could finish a lot of games to the end only with savestates, not with cheats. There are situations, where cheats don't help.
Not saying it's a good thing I'm missing a feature, but it is kind of nice not having them for a change. My overall skill has improved from having to play without them.
I believe it to be a language problem -- C++ is just a purely imperative call-based language, designed around the idea of one single thing happening at a time. Just need a domain-specific language that makes state machines as transparent as possible.I would agree with you, if there is only a really complex way possible to build a statemachine with current accuracy.
Okay, so for the advanced configuration panel:

I was thinking we drop all the groupboxes. Remove the "driver config" line entirely, screw it. Maybe put the "requires restart" below the combo boxes. Then put a spacer.
After that, the rest will have a text label with the radio boxes below that can expand with window size, eg:
But downstairs to the L. Vampire (fought her in stage 7 bad ending anyway; yes, I also cleared the good ending) ... it's like the upper floor, but on moving / dropping platforms with spiked walls and projectiles everywhere, where you drop to your death and start over.

I was thinking we drop all the groupboxes. Remove the "driver config" line entirely, screw it. Maybe put the "requires restart" below the combo boxes. Then put a spacer.
After that, the rest will have a text label with the radio boxes below that can expand with window size, eg:
Code: Select all
Video driver: Audio driver: Input driver: [^]
[ ] [ ] [ ] |-|
|-|
Hardware region: | |
[ ] Auto-detect [ ] NTSC [ ] PAL | |
| |
Expansion port: | |
[ ] Satellaview [ ] None | |
| |
When main window does not have focus: |-|
[ ] Pause emulation [ ] Ignore input [ ] Allow input [v]
That's the upper path. The hydra's not hard to get to with the clock, and his second form has a massive AI hole. Kill the blue head on the left and then just stand at the right and pick off the red ones repeatedly.patience, byuu. thou shalt advance slowly and kill one enemy at a time, and then maul the second phase of Hydra in < 10 seconds with item crashes.
But downstairs to the L. Vampire (fought her in stage 7 bad ending anyway; yes, I also cleared the good ending) ... it's like the upper floor, but on moving / dropping platforms with spiked walls and projectiles everywhere, where you drop to your death and start over.
-
- ZSNES Shake Shake Prinny
- Posts: 5632
- Joined: Wed Jul 28, 2004 4:15 pm
- Location: PAL50, dood !
/me hydrostorms
皆黙って俺について来い!!
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
Code: Select all
<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
You could try using a notification box when a driver setting is changed. I'd suggest putting it in documentation, but it wouldn't fit in your categories.
Savestates can make excessively hard or unforgiving games fun. I don't think I'd still be playing King's Field if I had no savestates at my disposal. I've probably died 200 times so far. They're also useful for long games that have no SRAM, pretty common in the era we're dealing with.I could finish a lot of games to the end only with savestates, not with cheats. There are situations, where cheats don't help.
-
- Locksmith of Hyrule
- Posts: 3634
- Joined: Sun Aug 08, 2004 7:49 am
- Location: 255.255.255.255
- Contact:
As grinvader once said, a majority of those games can be conquered in ~3 hours. Barring that if there's a password system, is it that hard to take a screenshot of the password (assuming bsnes has a screenshot button) or perhaps a prntscrn+mspaint shot and save it for later?FitzRoy wrote:They're also useful for long games that have no SRAM, pretty common in the era we're dealing with.
That said, I think in the SNES era, those non-saving games that Fitz was talking about, there weren't as many as say, the NES era.
<Nach> so why don't the two of you get your own room and leave us alone with this stupidity of yours?
NSRT here.
NSRT here.
-
- Buzzkill Gil
- Posts: 4295
- Joined: Wed Jan 12, 2005 7:14 pm
I state-save passwords to spare me the effort of typing them back in.adventure_of_link wrote:As grinvader once said, a majority of those games can be conquered in ~3 hours. Barring that if there's a password system, is it that hard to take a screenshot of the password (assuming bsnes has a screenshot button) or perhaps a prntscrn+mspaint shot and save it for later?FitzRoy wrote:They're also useful for long games that have no SRAM, pretty common in the era we're dealing with.
That said, I think in the SNES era, those non-saving games that Fitz was talking about, there weren't as many as say, the NES era.
20 random alphanumeric characters isn't any fun.
Yes, savestates are better than tediously saving and typing in a password. Also, I don't know how long a game is going to be. If I have to go somewhere before I finish, taking a savestate is better than leaving my computer on all night. Or maybe I just can't pass a certain stage and it's pissing me off to the point that I want to come back to it without having to get there again. Sure, they can be very convenient.
-
- Locksmith of Hyrule
- Posts: 3634
- Joined: Sun Aug 08, 2004 7:49 am
- Location: 255.255.255.255
- Contact:
consider bsnes doesn't have savestatesGil_Hamilton wrote:I state-save passwords to spare me the effort of typing them back in.adventure_of_link wrote:As grinvader once said, a majority of those games can be conquered in ~3 hours. Barring that if there's a password system, is it that hard to take a screenshot of the password (assuming bsnes has a screenshot button) or perhaps a prntscrn+mspaint shot and save it for later?FitzRoy wrote:They're also useful for long games that have no SRAM, pretty common in the era we're dealing with.
That said, I think in the SNES era, those non-saving games that Fitz was talking about, there weren't as many as say, the NES era.
20 random alphanumeric characters isn't any fun.
consider that we're trying to discuss ways to wean ourselves off of them
profit
<Nach> so why don't the two of you get your own room and leave us alone with this stupidity of yours?
NSRT here.
NSRT here.
Well, unless I'm nuts, there was a device similar to a gamegenie or whatever that allowed you to kind of "save states" in games on the snes, I think
in that idea, could we not create a "plugin" or "wrapper" for save stating
though for it to be efficient I guess bsnes would have to have an interface to the external application and that would be interfering with the true to snes-ness
in that idea, could we not create a "plugin" or "wrapper" for save stating
though for it to be efficient I guess bsnes would have to have an interface to the external application and that would be interfering with the true to snes-ness
I'm not arguing that savestates are in any way a bad thing. I'd love to have them if I could.
Some copiers did that. They worked ~30% of the time, and half of those times you got lots of graphical corruption and/or no sound.gllt wrote:Well, unless I'm nuts, there was a device similar to a gamegenie or whatever that allowed you to kind of "save states" in games on the snes, I think
-
- Seen it all
- Posts: 2302
- Joined: Mon Jan 03, 2005 5:04 pm
- Location: Germany
- Contact:
In that case you can pause bsnes and start the PC's hibernate mode.FitzRoy wrote:If I have to go somewhere before I finish, taking a savestate is better than leaving my computer on all night.
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
bsnes launcher with recent files list