bsnes v0.039 released

Archived bsnes development news, feature requests and bug reports. Forum is now located at http://board.byuu.org/
Locked
Chester
New Member
Posts: 3
Joined: Tue Feb 17, 2009 3:46 pm
Location: Italy

Post by Chester »

Anyway, PiCiJi, show us the code! I'm really curious too.
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. :twisted:
By the way, in what consists your idea?
grinvader
ZSNES Shake Shake Prinny
Posts: 5632
Joined: Wed Jul 28, 2004 4:15 pm
Location: PAL50, dood !

Post by grinvader »

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
- ?
You forgot 'profit!!' right there...
皆黙って俺について来い!!

Code: Select all

<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
creaothceann
Seen it all
Posts: 2302
Joined: Mon Jan 03, 2005 5:04 pm
Location: Germany
Contact:

Post by creaothceann »

Shhh! Can't have Big N know about No$snes. :wink:
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
FitzRoy
Veteran
Posts: 861
Joined: Wed Aug 04, 2004 5:43 pm
Location: Sloop

Post by FitzRoy »

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.
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.
Gleasonator
Rookie
Posts: 35
Joined: Fri Feb 20, 2009 3:49 am

Post by Gleasonator »

Is there a way to make this run in full screen stretched? I have "correct aspect ratio" unticked, but I still get thick black bars on either side of my monitor when in full screen mode.
henke37
Lurker
Posts: 152
Joined: Tue Apr 10, 2007 4:30 pm
Location: Sweden
Contact:

Post by henke37 »

Chester wrote:By the way, in what consists your idea?
It's a tweak to the cothreading library mainly.

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.
byuu

Post by byuu »

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.
belegdol
Hazed
Posts: 68
Joined: Tue Dec 07, 2004 10:24 am

Post by belegdol »

I just checked and wip18 builds with gcc-4.4.
PiCiJi
New Member
Posts: 7
Joined: Fri Dec 30, 2005 11:42 pm

Post by PiCiJi »

There are only 2 threads, so more cores won't help.
right
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.
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.
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.
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:

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
now to smp core:

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();
	}
I had to rewrite all smp opcodes, an example:

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
All smp opcodes are switch/case. But the cases are not the smp cycles. I need a new case, when the smp consumes cycles, so I have the chance to jump back to the cpu. You could say the smp is a slave of the cpu. Have a carefull look at the busread/buswrite function.For example busread (CPUIO(0-3)): To obtain bus accuracy, the port read had to be delayed till the cpu processing is synced. I check for this. If the cpu is behind, then the scheduler is saving this action, in order to do it later when the cpu catches up. When the cpu gives control back to the smp, the first step is to look if there is an action to do before the next smp opcode case executes. So it's much asier to make the smp a cpu slave and not vice versa. 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. If you are interested please give me a possibiliy where I can upload source+binary.
byuu

Post by byuu »

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.
The Cpu and DMA approach is the same like in bsnes. The exception are the stp and wai opcodes.
Heheh, I bet someone looking at STP without being aware of how the cothreads work would gasp in horror :D
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.
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.

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
PiCiJi
New Member
Posts: 7
Joined: Fri Dec 30, 2005 11:42 pm

Post by PiCiJi »

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.
Haven't tried SNEeSe, is the smp <> cpu communication in SNEeSe bus accurate?
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.
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.
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.
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.
Still overall, really really impressive stuff. Kudos on making something so cool :D
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.
byuu

Post by byuu »

Haven't tried SNEeSe, is the smp <> cpu communication in SNEeSe bus accurate?
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.

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.
I could finish a lot of games to the end only with savestates, not with cheats. There are situations, where cheats don't help.
Definitely for some games, yeah. Like Drac X PSP's Stage 5' lower path. Holy shit.

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 would agree with you, if there is only a really complex way possible to build a statemachine with current accuracy.
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.
odditude
Official tech support dood
Posts: 2118
Joined: Wed Jan 25, 2006 7:57 am

Post by odditude »

byuu wrote:Drac X PSP's Stage 5' lower path
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.

/me loves his castlevania ;)
Why yes, my shift key *IS* broken.
byuu

Post by byuu »

Okay, so for the advanced configuration panel:
Image

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]
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.
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.

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.
grinvader
ZSNES Shake Shake Prinny
Posts: 5632
Joined: Wed Jul 28, 2004 4:15 pm
Location: PAL50, dood !

Post by grinvader »

/me hydrostorms
皆黙って俺について来い!!

Code: Select all

<jmr> bsnes has the most accurate wiki page but it takes forever to load (or something)
Pantheon: Gideon Zhi | CaitSith2 | Nach | kode54
odditude
Official tech support dood
Posts: 2118
Joined: Wed Jan 25, 2006 7:57 am

Post by odditude »

byuu wrote:clock
ewww. never use it (except where necessary to get an item).
byuu wrote:downstairs
my bad. i don't remember having any problems at all with that part, but i might have done it with maria.
Why yes, my shift key *IS* broken.
FitzRoy
Veteran
Posts: 861
Joined: Wed Aug 04, 2004 5:43 pm
Location: Sloop

Post by FitzRoy »

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.
I could finish a lot of games to the end only with savestates, not with cheats. There are situations, where cheats don't help.
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.
adventure_of_link
Locksmith of Hyrule
Posts: 3634
Joined: Sun Aug 08, 2004 7:49 am
Location: 255.255.255.255
Contact:

Post by adventure_of_link »

FitzRoy wrote:They're also useful for long games that have no SRAM, pretty common in the era we're dealing with.
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?

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.
Gil_Hamilton
Buzzkill Gil
Posts: 4294
Joined: Wed Jan 12, 2005 7:14 pm

Post by Gil_Hamilton »

adventure_of_link wrote:
FitzRoy wrote:They're also useful for long games that have no SRAM, pretty common in the era we're dealing with.
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?

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.
I state-save passwords to spare me the effort of typing them back in.

20 random alphanumeric characters isn't any fun.
FitzRoy
Veteran
Posts: 861
Joined: Wed Aug 04, 2004 5:43 pm
Location: Sloop

Post by FitzRoy »

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.
adventure_of_link
Locksmith of Hyrule
Posts: 3634
Joined: Sun Aug 08, 2004 7:49 am
Location: 255.255.255.255
Contact:

Post by adventure_of_link »

Gil_Hamilton wrote:
adventure_of_link wrote:
FitzRoy wrote:They're also useful for long games that have no SRAM, pretty common in the era we're dealing with.
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?

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.
I state-save passwords to spare me the effort of typing them back in.

20 random alphanumeric characters isn't any fun.
consider bsnes doesn't have savestates

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.
h4tred

Post by h4tred »

Think of it this way:

* The SNES did not have savestates at all
* BSNES doesnt have savestates

Thus, one could say BSNES is more accurate because of this lack of savestates. :P
gllt
NO VOWELS >:[
Posts: 753
Joined: Sun Aug 31, 2008 12:59 pm
Location: ALABAMA
Contact:

Post by gllt »

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
byuu

Post by byuu »

I'm not arguing that savestates are in any way a bad thing. I'd love to have them if I could.
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
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.
creaothceann
Seen it all
Posts: 2302
Joined: Mon Jan 03, 2005 5:04 pm
Location: Germany
Contact:

Post by creaothceann »

FitzRoy wrote:If I have to go somewhere before I finish, taking a savestate is better than leaving my computer on all night.
In that case you can pause bsnes and start the PC's hibernate mode.
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
Locked