Previous Thread
Next Thread
Print Thread
Page 27 of 78 1 2 25 26 27 28 29 77 78
Joined: Feb 2014
Posts: 852
Likes: 48
G
Senior Member
Online Content
Senior Member
G
Joined: Feb 2014
Posts: 852
Likes: 48
Hi Anoid,

I thought I'd give the HERO woz a spin and sure enough, it doesn't work properly, dropping dynamite every time you land (until you run out of dynamite, of course). According to the atari 2600 manual for hero, when you pull the stick down its supposed to put down some dynamite. So that must be what's happening.

When I was playing with the joystick calibration values, I would just put some different values in and with trial and error and much recompiling I came up with some good values. Waiting for the compile and link became intolerable. So then I thought, what if I could change the calibration "on the fly" while mame was running.

I thought a slider would be cool, but that would mean messing about in the sliders with ui.cpp.

WARNING: HORRIBLE HACK ALERT!

I did a terrible hack of luaengine.cpp and the apple2.cpp, a terrible terrible hack but it seems to work. (For proof of concept)


So I added m_x_calibration, and m_y_calibration to the save_item list:

Code
	save_item(NAME(m_an0));
	save_item(NAME(m_an1));
	save_item(NAME(m_an2));
	save_item(NAME(m_an3));
	save_item(NAME(m_anykeydown));
        save_item(NAME(m_x_calibration));
        save_item(NAME(m_y_calibration));



And then did a horrible hack of emu.item, adding readasdouble and writeasdouble:

Code

*
 * emu.item(item_index)
 * item.size - size of the raw data type
 * item.count - number of entries
 * item:read(offset) - read entry value by index
 * item:read_block(offset, count) - read a block of entry values as a string (byte addressing)
 * item:write(offset, value) - write entry value by index
 */

	emu.new_usertype<save_item>("item", sol::call_constructor, sol::initializers([this](save_item &item, int index) {
					if(!machine().save().indexed_item(index, item.base, item.size, item.count))
					{
						item.base = nullptr;
						item.size = 0;
						item.count= 0;
					}
				}),
			"size", sol::readonly(&save_item::size),
			"count", sol::readonly(&save_item::count),
			"read", [this](save_item &item, int offset) -> sol::object {
					uint64_t ret = 0;
					if(!item.base || (offset > item.count))
						return sol::make_object(sol(), sol::nil);
					switch(item.size)
					{
						case 1:
						default:
							ret = ((uint8_t *)item.base)[offset];
							break;
						case 2:
							ret = ((uint16_t *)item.base)[offset];
							break;
						case 4:
							ret = ((uint32_t *)item.base)[offset];
							break;
						case 8:
							ret = ((uint64_t *)item.base)[offset];
							break;
					}
					return sol::make_object(sol(), ret);
				},
			"readasdouble", [this](save_item &item, int offset) -> sol::object {
					uint64_t ret = 0;
                                        double retfloat = 0;					
					if(!item.base || (offset > item.count))
						return sol::make_object(sol(), sol::nil);
					switch(item.size)
					{
						case 1:
						default:
							ret = ((uint8_t *)item.base)[offset];
							break;
						case 2:
							ret = ((uint16_t *)item.base)[offset];
							break;
						case 4:
							ret = ((uint32_t *)item.base)[offset];
							break;
						case 8:
							ret = ((uint64_t *)item.base)[offset];
							break;
					}
                                        retfloat = (*(double *) &ret);                         // get the return value as a float
					return sol::make_object(sol(), retfloat);
				},	

			"read_block", [](save_item &item, int offset, sol::buffer *buff) {
					if(!item.base || ((offset + buff->get_len()) > (item.size * item.count)))
						buff->set_len(0);
					else
						memcpy(buff->get_ptr(), (uint8_t *)item.base + offset, buff->get_len());
					return buff;
				},
			"write", [](save_item &item, int offset, uint64_t value) {
					if(!item.base || (offset > item.count))
						return;
					switch(item.size)
					{
						case 1:
						default:
							((uint8_t *)item.base)[offset] = (uint8_t)value;
							break;
						case 2:
							((uint16_t *)item.base)[offset] = (uint16_t)value;
							break;
						case 4:
							((uint32_t *)item.base)[offset] = (uint32_t)value;
							break;
						case 8:
							((uint64_t *)item.base)[offset] = (uint64_t)value;
							break;
					}
				},
			"writeasdouble", [](save_item &item, int offset, double value) {
					if(!item.base || (offset > item.count))
						return;
					switch(item.size)
					{
						case 1:
						default:
							((uint8_t *)item.base)[offset] = (uint8_t)value;
							break;
						case 2:
							((uint16_t *)item.base)[offset] = (uint16_t)value;
							break;
						case 4:
							((uint32_t *)item.base)[offset] = (uint32_t)value;
							break;
						case 8:
							((double *)item.base)[offset] = value;        // write the double value
							break;
					}
				});





and I also made a new device method to return all of items in the item list: allitems

Why did I do that? Because the items in the apple2 state are inaccessible. I can see them in the Memory Window in the debugger, but not with lua.

If I execute this lua one-liner, my x and y calibration don't show up in the device list.

for devname,devdevice in pairs(manager:machine().devices) do print (devname,devdevice) for i,j in pairs(devdevice.items) do print(i,j) end end

But device.items[] iterates through the whole list, checking the devicetag to match, why not just make a variation called allitems that will just add them all.
So it you look below, it just has an if (1).

Code

/* machine.devices[device_tag]
 * device:name() - device long name
 * device:shortname() - device short name
 * device:tag() - device tree tag
 * device:owner() - device parent tag
 * device:debug() - debug interface, cpus only
 * device.spaces[] - device address spaces table
 * device.state[] - device state entries table
 * device.items[] - device save state items table (item name is key, item index is value)
 */

	sol().registry().new_usertype<device_t>("device", "new", sol::no_constructor,
			"name", &device_t::name,
			"shortname", &device_t::shortname,
			"tag", &device_t::tag,
			"owner", &device_t::owner,
			"debug", [this](device_t &dev) -> sol::object {
					if(!(dev.machine().debug_flags & DEBUG_FLAG_ENABLED) || !dynamic_cast<cpu_device *>(&dev)) // debugger not enabled or not cpu
						return sol::make_object(sol(), sol::nil);
					return sol::make_object(sol(), dev.debug());
				},
			"spaces", sol::property([this](device_t &dev) {
					device_memory_interface *memdev = dynamic_cast<device_memory_interface *>(&dev);
					sol::table sp_table = sol().create_table();
					if(!memdev)
						return sp_table;
					for(int sp = 0; sp < memdev->max_space_count(); ++sp)
					{
						if(memdev->has_space(sp))
							sp_table[memdev->space(sp).name()] = addr_space(memdev->space(sp), *memdev);
					}
					return sp_table;
				}),
			"state", sol::property([this](device_t &dev) {
					sol::table st_table = sol().create_table();
					if(!dynamic_cast<device_state_interface *>(&dev))
						return st_table;
					// XXX: refrain from exporting non-visible entries?
					for(auto &s : dev.state().state_entries())
						st_table[s->symbol()] = s.get();
					return st_table;
				}),
			"items", sol::property([this](device_t &dev) {
					sol::table table = sol().create_table();
					std::string tag = dev.tag();
					// 10000 is enough?
					for(int i = 0; i < 10000; i++)
					{
						std::string name;
						const char *item;
						unsigned int size, count;
						void *base;
						item = dev.machine().save().indexed_item(i, base, size, count);
						if(!item)
							break;
						name = &(strchr(item, '/')[1]);
						if(name.substr(0, name.find("/")) == tag)
						{
							name = name.substr(name.find("/") + 1, std::string::npos);
							table[name] = i;
						}
					}
					return table;
				}),

			"allitems", sol::property([this](device_t &dev) {
					sol::table table = sol().create_table();
					std::string tag = dev.tag();
					// 10000 is enough?
					for(int i = 0; i < 10000; i++)
					{
						std::string name;
						const char *item;
						unsigned int size, count;
						void *base;
						item = dev.machine().save().indexed_item(i, base, size, count);
						if(!item)
							break;
						name = &(strchr(item, '/')[1]);
					//if(name.substr(0, name.find("/")) == tag)
					if(1)
						{
							name = name.substr(name.find("/") + 1, std::string::npos);
							table[name] = i;
						}
					}
					return table;
				})

			);



so once that's done I can do this:

emu.item(manager:machine().devices[":maincpu"].allitems["0/m_y_calibration"]):writeasdouble(0,9800e-9)
emu.item(manager:machine().devices[":maincpu"].allitems["0/m_y_calibration"]):writeasdouble(0,9800e-9)


If you read it as an integer, it is nonsense.

print(emu.item(manager:machine().devices[":maincpu"].allitems["0/m_x_calibration"]):read(0))
4533201175231652948

You want to use my new function readasdouble:

print(emu.item(manager:machine().devices[":maincpu"].allitems["0/m_x_calibration"]):readasdouble(0))
1.2e-05


[MAME]> function printt(a) for i,j in pairs(a) do print(i,j) end end
[MAME]>
[MAME]> printt(manager:machine().devices[":maincpu"].allitems)
m_lastcoin 610
10/m_stored_vector 351
0/TMP 319
0/m_last_update_time.attoseconds 264
31/m_stored_vector 456
21/m_stored_vector 405
41/m_stored_vector 507
2E/m_curstate 442
1E/m_curstate 391
0/m_y_calibration 234
0/m_totalcycles 341
0/m_step_samples 308
... etc



Okay, so back to HERO:

Just trying some different values I can get the joystick to work properly and not drop the dynamite:


9800 nsec seems to work:

[MAME]> print(emu.item(manager:machine().devices[":maincpu"].allitems["0/m_x_calibration"]):writeasdouble(0,9800e-9))

[MAME]> print(emu.item(manager:machine().devices[":maincpu"].allitems["0/m_y_calibration"]):writeasdouble(0,9800e-9))


[MAME]> print(emu.item(manager:machine().devices[":maincpu"].allitems["0/m_x_calibration"]):readasdouble(0))
9.8e-06
[MAME]> print(emu.item(manager:machine().devices[":maincpu"].allitems["0/m_y_calibration"]):readasdouble(0))
9.8e-06


Actually, 10800 nsec works too (I forgot that I was using the old 12 msec values to start with)

print(emu.item(manager:machine().devices[":maincpu"].allitems["0/m_x_calibration"]):writeasdouble(0,10800e-9))
print(emu.item(manager:machine().devices[":maincpu"].allitems["0/m_y_calibration"]):writeasdouble(0,10800e-9))



Last edited by Golden Child; 02/17/19 04:01 AM.
Joined: Feb 2014
Posts: 852
Likes: 48
G
Senior Member
Online Content
Senior Member
G
Joined: Feb 2014
Posts: 852
Likes: 48
Horrible hack part #2 - finding the optimum value for the Apple IIGS and Stellar 7 on fast cpu mode.

I added the m_x_calibration and m_y_calibration to the save item list in the apple2gs.cpp driver.


So I located the joystick read routine for Stellar 7 by putting a watchpoint on C064 (analog paddle 0 read)

[Linked Image]

then I put some breakpoints on every RTS from the read joystick subroutine that would print out the joystick return values:

wp c064,1,r

bp 7ca1,1,{printf "x=%02x y=%02x",x,y;g}
bp 7cb2,1,{printf "x=%02x y=%02x",x,y;g}
bp 7cc3,1,{printf "x=%02x y=%02x",x,y;g}

wpdis 1

[Linked Image]


then I could fine-tune my joystick calibration values with some lua commands in real time:

print(emu.item(manager:machine().devices[":maincpu"].allitems["0/m_x_calibration"]):writeasdouble(0,2500e-9)) -- maximum is 3E

print(emu.item(manager:machine().devices[":maincpu"].allitems["0/m_x_calibration"]):writeasdouble(0,4800e-9)) -- maximum is 7e, half 3c

print(emu.item(manager:machine().devices[":maincpu"].allitems["0/m_x_calibration"]):writeasdouble(0,5150e-9)) -- maximum is 7F, half is 40
print(emu.item(manager:machine().devices[":maincpu"].allitems["0/m_y_calibration"]):writeasdouble(0,5150e-9))


So it looks like the "perfect" calibration for Stellar 7 running in fast mode is 5150 nsec.


Last edited by Golden Child; 02/17/19 04:12 AM.
Joined: Jul 2007
Posts: 37
Member
Offline
Member
Joined: Jul 2007
Posts: 37
Golden Child,

Thanks for the information. I guess that the fix Arbee did earlier may actually fix the problem in HERO by changing to 10800 nsec.

I do remember manually centering the joysticks on the Apple II back in the day...

A-Noid

Joined: Feb 2014
Posts: 852
Likes: 48
G
Senior Member
Online Content
Senior Member
G
Joined: Feb 2014
Posts: 852
Likes: 48
Horrible hack part #3:

I wanted to see if I could create a function under the emu table that would give me all of the items:

Code
// New function emu["items"]

	emu["items"] = [this](){ 	sol::table table = sol().create_table();
					// 10000 is enough?
					for(int i = 0; i < 10000; i++)
					{
						std::string name;
						const char *item;
						unsigned int size, count;
						void *base;
						item = machine().save().indexed_item(i, base, size, count);
						if(!item) break;
						//name = &(strchr(item, '/')[1]);
						name = item;
						table[name] = i;
						
					}
					return table;
				};


Now I can do this:

Code
print(emu.item(emu.items()["Apple //e/:/0/m_y_calibration"]):readasdouble(0))
1.3e-05


If I uncomment the //name = &(strchr(item, '/')[1]); it will strip off the leading part up to the first / but I kind of like having the full name. It also matches the names that show up in the Debug: Memory View.


function printt(a) for i,j in pairs(a) do print(i,j) end end
function printto(a) local b={} for i,j in pairs(a) do b[j]=i end printt(b) end

[MAME]> printto(emu.items())
1 5.25" single density floppy drive/:sl6:diskiing:0:525/0/m_clock
2 5.25" single density floppy drive/:sl6:diskiing:0:525/0/m_clock_scale
...
142 Apple //e/:/0/m_x_calibration
143 Apple //e/:/0/m_xirq
144 Apple //e/:/0/m_xy
145 Apple //e/:/0/m_y0
146 Apple //e/:/0/m_y0edge
147 Apple //e/:/0/m_y1
148 Apple //e/:/0/m_y_calibration
149 Apple //e/:/0/m_yirq
...
828 timer/sound_manager::update/0/m_start.attoseconds
829 timer/sound_manager::update/0/m_start.seconds

Joined: Feb 2014
Posts: 852
Likes: 48
G
Senior Member
Online Content
Senior Member
G
Joined: Feb 2014
Posts: 852
Likes: 48
More hacking on luaengine:

why not just directly get the item?

If I create this function (it's horribly inefficient but proof of concept:) I can just go ahead and get an item directly from a string:
Code
      emu["getitem"] = [this](const char* itemname){ 	sol::table table = sol().create_table();
					// 10000 is enough?
					int index = -1;
					save_item return_item;
					if (!(itemname == 0))					
					for(int i = 0; i < 10000; i++)
					{
						std::string name;
						const char *item;
						unsigned int size, count;
						void *base;
						item = machine().save().indexed_item(i, base, size, count);
						if(!item) break;
						//name = &(strchr(item, '/')[1]);
						name = item;
						table[name] = i;
                                                if (itemname == name) index = i;						
					}
				if (index == -1 || !machine().save().indexed_item(index, return_item.base, return_item.size, return_item.count))	
					{	return_item.base = nullptr;
						return_item.size = 0;
						return_item.count= 0;
					};
					return return_item;
				};



Code
[MAME]> print(emu.item(emu.items()["Apple //e/:/0/m_y_calibration"]):readasdouble(0))
1.3e-05
[MAME]> print(emu.getitem("Apple //e/:/0/m_y_calibration"):readasdouble(0))
1.3e-05
[MAME]> print(emu.getitem("Apple //e/:/0/m_x_calibration"):readasdouble(0))
1.2e-05
[MAME]> print(emu.getitem("Apple misspelled"):readasdouble(0))
nil
[MAME]> print(emu.getitem("doesnt exist"):readasdouble(0))
nil
[MAME]> print(emu.getitem():readasdouble(0))
nil



Joined: Jun 2014
Posts: 90
P
Member
Offline
Member
P
Joined: Jun 2014
Posts: 90
It's funny about Joust. I never tested it in MAME, apparently.
I've known about Serpentine for ages. I thought that I submitted the fix for it, but clearly not.
A couple of other games had the same requirement.
I think that Pooyan and Lady Tut also rely on uninitialised memory, but the effects aren't detrimental.

Yes, Hero is very sensitive to the joystick calibration.

Joined: Jul 2007
Posts: 37
Member
Offline
Member
Joined: Jul 2007
Posts: 37
A couple more...

Congo Bongo (WOZ) won't boot in MAME, but the crack works from the software list.

I've noticed longer delays in Drol (WOZ) when loading the 3rd level (snakes) and winning cut scene after 3rd level. Levels 1 and 2 seem to have load times similar to cracked version.

A-Noid

Joined: Mar 2001
Posts: 16,921
Likes: 57
R
Very Senior Member
Online Content
Very Senior Member
R
Joined: Mar 2001
Posts: 16,921
Likes: 57
Regarding load times, originals oftentimes will take longer because they're doing a protection check instead of just loading the data.

Peter: does Congo Bongo use weak bits?

Joined: Jun 2014
Posts: 90
P
Member
Offline
Member
P
Joined: Jun 2014
Posts: 90
RB: yes, along with Bruce Lee and Mr. Do.

Joined: Jun 2014
Posts: 90
P
Member
Offline
Member
P
Joined: Jun 2014
Posts: 90
Regarding Drol, those two sections are huge compared to the other two, and the protection is alternating quarter-track, so it's very slow to load.
Try our Lode Runner crack vs the original for extreme speed difference! :-)

Page 27 of 78 1 2 25 26 27 28 29 77 78

Link Copied to Clipboard
Who's Online Now
2 members (Dam0, 1 invisible), 21 guests, and 3 robots.
Key: Admin, Global Mod, Mod
ShoutChat
Comment Guidelines: Do post respectful and insightful comments. Don't flame, hate, spam.
Forum Statistics
Forums9
Topics9,100
Posts119,241
Members5,019
Most Online890
Jan 17th, 2020
Our Sponsor
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!

Superior Solitaire
Forum hosted by www.retrogamesformac.com