Posts for nitsuja


Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
Nice. I knew the old run had lots of mistakes, and now I don't have to fix them. One small thing though,
andymac wrote:
then in the first small room, I jump straight from the entry to the exit of the level, instead of jumping on an intermediate platform
This actually looked slower, and comparing the frame counts, your way took 84 frames (10294 - 10378) where mine took 81 frames (11618 - 11699).
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
Temporal definitely deserves a mention here. Not only can you travel back in time to a specific time of your choice, but you can directly interact with your past selves (like push them around or jump on their heads) and they can interact with each other. Each one is just playing back its old input track, so you can get desyncs and usually you want to avoid that, but you can also do incredibly tricky things where you record input that doesn't make any sense yet and guess/plan where your future self will lend a hand to turn that input into meaningful actions. The game allows but penalizes time paradoxes, where you prevent your other selves from returning to the past, but it's also possible to change what they did in such a way that the resulting alternate reality still isn't a paradox. I think it's even possible to kill yourself in the past and then go back in time again and rescue yourself from your other self. That probably isn't the best description of its gameplay, but this game is quite challenging, a real mind-bender. And it has many things that remind one of the tools used to make TASes (more than I've described here).
Post subject: Re: Lock on Tails
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
Gens already has the code in it to keep the camera on Sonic in Sonic 2, it's disabled but you can enable it by uncommenting the following lines in hackdefs.h
#define SONICCAMHACK // enables camhack (see Sonic offscreen) in sonic games, and hitbox/solidity display
#define S2 // specifies that the sonic game being used is Sonic 2-based
and you might want to enable these too if you want it to look otherwise normal besides the camera position:
#define SONICNOHITBOXES // disables hitbox display of SONICCAMHACK
#define SONICNOSOLIDITYDISPLAY // disables solidity display of SONICCAMHACK
Then since you want to look at Tails instead of Sonic, there's a line in SonicHackSuite.cpp you can change:
#elif defined S2
	const unsigned int P1OFFSET = 0xFFB000;
I believe Tails is at 0xFFB040 instead of 0xFFB000. It should also be easy to change it into something non-constant if you want to be able to switch back and forth. For a really quick example that I think would work but isn't necessarily the best way to do it:
#elif defined S2
	//const unsigned int P1OFFSET = 0xFFB000; // <-- disabled
	// Focus on Tails if caps lock is on, or Sonic if caps lock is off
	#define P1OFFSET (GetKeyState(VK_CAPITAL) ? 0xFFB040 : 0xFFB000)
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
moozooh wrote:
Wait, doesn't machinegun prevent the best ending?
Nope, you can beat Ballos while in possession of the machinegun.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
I really doubt Snake could save more time overall than the machinegun, which allows at least the following timesavers: - Flying before getting the booster, so you can take much more direct routes and/or bypass waiting in several places - Falling extra-fast - Higher-precision control over jumps - Faster horizontal travel through water in some places (by not touching the ground) - Trajectory changes with the booster that are otherwise impossible (for faster and more fluid movement) - A water current track-changing shortcut or two - Two shortcuts through otherwise one-way air currents (that I can remember) The Snake is more out of the way as well, and being able to shoot through walls only helps in a select few places that I know of. Even if it saves a lot of time in those places I don't think it compares.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
Iji is pretty cool too. There's a nice trailer for it here. It's kind of underwhelming at first, but it really escalates. About Cave Story, I've been wondering, what exactly would an any% run get? The machinegun is obvious, that thing has tons of potential to save time especially in a speedrun/TAS setting. I'm not sure about the missiles... they're quite strong when powered up but they might not make up the time overall compared to skipping the missiles (and sword spamming instead). Similarly, health pickups could save time, but they take long enough to get (and enough enemies do damage you can survive with only 3 HP) that it might be faster to ignore them all.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
It still works in Gens11a, yes.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
ZeXr0 wrote:
It could be nice if the error was more explicit.
If that's what the error is, it would be even nicer if it just worked instead. Programs that use SSE2 are supposed to detect it and switch to a fallback implementation if it isn't available, instead of assuming it's present and crashing if it isn't. There shouldn't need to be a whole separate executable for non-SSE2. EDIT: Of course, there are probably lots of more important things to fix. I'm just pointing out how I think it can (and ideally should) work.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
(Maybe klmz just hinted at this, but...) Don't forget the bugs with character stats: - leveling up while morphed gives you a big stat boost (depending on the morph) that's permanent until the next level up or restart - you can get the effect of equipping 3 accessories at the same time (despite only having 2 slots) if the 3rd one is a stats-booster, by leaving the menu with the start button while selecting the item to equip I saw these mentioned on SDA, although I already knew about the first one since it's really easy to run across it in normal play. I think the stat gains are always absolute amounts (like +40 STR) so these will help more if the character is going to be relatively underleveld.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
I'm glad this movie was submitted, it's a major contribution to have DS TASing possible. I don't know about it being published, though... it's nice to promote the site, but rushing the creation and/or publication of a movie is exactly opposite of what this site seems to be about, so it might send a wrong message.
upthorn wrote:
That's interesting, because, having played the game, I have difficulty seeing an optimized TAS looking too much more entertaining than this.
Well, I remember it feeling pretty fast and easy to go out of control when trying to go at top speed, so I was surprised it looks so sluggish in a TAS. The only time it didn't feel slow was with the invincibility stars, which happened too infrequently to make up for everything else. Maybe it's mostly the game's fault, but since it's the first run of any game on the same system, and the game emulates very slowly and savestates are probably slow too (testing patience more than usual) and not many savestates were used (probably as a result), I think there must be room for improvement here.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
Tompa wrote:
Also, while making a test video I loaded a save state and the screen turned like this. It has happened me twice now....
Exactly which emulator version were you using when that happened? 1.43rv92? 1.51rv60? Something else? Is it just a 1-frame glitch or does it freeze like that even when you unpause? Anyway, it seems this is a FastROM game, and Snes9x 1.43 had a bug where the memory speed is not initialized on startup of such games. That would explain why it sometimes syncs differently on starting to play a movie, and why different movies you recorded will desync under different conditions. The only workaround for the emulator version you were originally using is to make sure you always start playing the movie after the emulation reaches a certain frame number (in other words, whatever part of the game you were at when you chose "record movie", that's where you should be when you choose "play movie" later if you want the playback to even have a chance of synchronizing properly). That bug has been fixed with a new recording sync option (called "clean fastrom setting") to initialize that memory in the newest 1.43 version. Also, when using that option, it means the movie will sync as if you had started playing the movie immediately after opening Snes9x for the first time, which means people who launch Snes9x and play the movie from the commandline will actually have an easier time playing movies that use that option, even if they have a much older version of the emulator. I'm not sure about this, but I think using any version of 1.51 avoids that problem completely.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
I found this really boring to watch with the exception of a few bits close to the end. But, having played the game, I find it hard to believe that could be the game's fault. (And, the low re-record count suggests something.) So I hope this movie gets repeatedly obsoleted with more and more interesting movies. Maybe that was part of the point of it being submitted, anyway.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
I read what you're talking about on the Chrono Trigger submission and that really surprised me... Movies recorded with these versions should still sync on the official versions (including on Unix or Mac OS, in the case of 1.51). If they don't, I'd say it's a bug. On the other hand, there can be good reasons for requiring moving forward, for instance if the old version was randomly changing the timing on emulation startup (which is actually pretty close to what was really happening for some games on the 1.43 branch). I wasn't aware of any fixes like that in the 1.51 branch though, but then again I haven't been following the development of these versions that closely. Maybe it's a difference that only happens when recording many resets. In any case, it should be easy to verify whether a movie syncs on both versions before getting too far into making it. Also, I believe shinydoofy has made a Unix patch for the newest 1.51 version (although I only noticed it just now and so haven't even looked at yet).
Post subject: Re: Return of the Jedi issues
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
You could try using the latest Snes9x intermediate revision (from here, revision 92 or newer). That version should have no desyncs in this game (or any other game for that matter). As for the weird sound, well I haven't looked into that but maybe if you actually use Snes9x 1.51 instead of 1.43 (so, from here instead, revision 60 or newer which should also have no desyncs), and also make sure Sync Sound with CPU is checked, it might sound better. Do make sure "volume envelope reading" is off and "fake mute fix" is on, though. Those might actually be a part of the reason why the sound is so weird, but currently I think they can still cause desyncs in some games if you don't set them that way. Also, if a movie you've been working on desyncs reliably now with everything set up like this on the newest version, then unfortunately that probably means your movie has a desync recorded into it, which is better fixed by starting over than by fiddling with options. (By the way, I'm not just suggesting these versions because I think it might fix the desync problem. I'm fairly certain that they do fix it. I found a bunch of desync problems in the savestate and initialization code recently and addressed them all and verified that in this game in particular (and several other games), even if I save and load a savestate every single frame, it doesn't desync, even if I count "one byte somewhere in the emulation state changed invisibly" as a desync.)
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
I'm a little surprised this still hasn't been done... anyway, this game has some hard-to-draw collision hitboxes, but I finally figured it out: red = vital part blue = highly shielded yellow or green = super vulnerable the outline colors don't mean anything the numbers are the remaining hit points of that piece EDIT: the Lua script is here: http://code.google.com/p/tastools/source/browse/trunk/Lua/Snes9x/MetalCombat/mc.lua
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
Uh, I got kind of distracted from this. Right now the wood golem boss is dead about 7 minutes into the run, and I'm still trying to figure out the fastest way to get the necessary gold for the boomerang and fire breath. Disregarding the gold bullions I'm not allowed to sell, there's only 1 gold bullion I can get reasonably fast (in 380 frames, probably worth it at 1.3 gold/frame), and 3 more gold bullions I could get in 2300 frames total (probably not worth it, 0.65 gold/frame). The best enemy group I've found so far early on gives 280 gold in 160 frames (1.75 gold/frame) but I don't think I encounter it more than once, and everything else is more like 1.1 gold/frame, but all slightly different. I only need to find 1100 gold before Goradus, but then I need 3000 more by Icycal... Probably I'll have to fully optimize every possible place I can get gold at a rate of 1 gold/frame or better, then redo it all with the slowest few cut out. I wish I could skip the fire breath to avoid having to collect all that gold, but every boss fight I don't have it on will take about 10 times longer than normal. I've also done some tests on the other bosses and found that some of them are going to be fantastically difficult to TAS properly thanks to the boomerang (although that's the part I'm looking forward to the most). EDIT: I think I've found the optimal gold route:
  • Start with 400 gold
  • Get 500G from rescuing Nami
  • Get 240G from killing a group of 3 bats in the Wind Cave
  • Get 280G from killing an ogre and one-eyed-bat at the Hot Springs entrance
  • Get 360G from killing a group of two one-eyed bats in Deviant Den
  • Get 150G from selling Mail's Short Sword
  • Get 500G from selling one Gold Bullion
  • Spend 2000G to buy a Boomerang for Mail
  • Acquire 4 Gold Bullions in the Mine (1 to make up for the one sold earlier, and 3 for selling later) (a trick that avoids riding the platforms up again makes the extra 3 worth the time)
  • Get 720G from killing two groups of animal warrior + fireball chain in the Zoth Shrine
  • Get 200G from killing one two-sworded enemy in Icycal
  • Get 150G from selling Gaw's Fire Ball
  • Get 1500G from selling 3 Gold Bullions
  • Spend 3000G to buy Fire Breath for Gaw
This route collects precisely 5000G (the minimum necessary), and spends roughly 54 seconds (in total) on collecting that amount of gold. Now it should be fairly straightforward to make this TAS, or at least, no further planning should be necessary.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
Dammit wrote:
nitsuja wrote:
savestate.registersave(function(slotnumber)
	-- save out the arrays
	return Xvalue,Yvalue
end)
savestate.registerload(function(slotnumber,x,y)
	-- load in the arrays
	Xvalue,Yvalue = x,y
end)
Hm, now I get an error on the first line after gui.register: Xvalue is a nil at that point. I guess that means savestate.registerload didn't plug in the values? How does registerload know what "slotnumber," "x" and "y" are?
slotnumber is the save slot number, Gens always passes that in first (in your case you don't care what it is, but in other cases it's important to know which save slot is being saved or loaded) so it must be listed first. The rest of the arguments are the same things that were returned by the registersave callback the last time the savestate got saved, in the same order they got returned. I picked x and y for their names arbitrarily, but anything else would work too as long as it's not exactly the same name as the variables you're loading into. If you try to load a savestate that was saved without that registersave callback active, then x and y will be nil, which would cause the error you saw. To fix that you could change the registerload callback function to do some error checking like this:
savestate.registerload(function(slotnumber,x,y)
  if x and y then
    -- load in the arrays
    Xvalue,Yvalue = x,y
  else
    -- x or y is nil, so we failed to load them, so clear the arrays instead
    Xvalue,Yvalue = {},{}
  end
end)
Or, to do basically the same thing in less lines of code:
savestate.registerload(function(slotnumber,x,y)
  Xvalue = x or {}
  Yvalue = y or {}
end)
EDIT: Sorry to fill up the movie thread with so much Lua stuff, but the submission does link to a Lua script which links back to this thread as presumably the place to discuss it... Maybe this discussion should move to PMs if it's going to continue though.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
Dammit, I am replying to an implied question in your Lua script:
--local function saveXarray()
--		return Xvalue --store values with savestate: I don't know how this is supposed to work
--end
--savestate.registersave(saveXarray)

local function loadarrays()
	for n=#Xvalue,0,-1 do
		table.remove(Xvalue,n) --wipe out the current data cuz I don't know how to get it from the save data
	end
	readX()
	for n=#Yvalue,0,-1 do
		table.remove(Yvalue,n)
	end
	readY()
end
savestate.registerload(loadarrays)
Replace all of that code with this and it will actually work, you'll see how simple it is...:
savestate.registersave(function(slotnumber)
	-- save out the arrays
	return Xvalue,Yvalue
end)
savestate.registerload(function(slotnumber,x,y)
	-- load in the arrays
	Xvalue,Yvalue = x,y
end)
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
The PAL version is a different ROM cartridge. Usually, if it's PAL, it'll be in a ROM file with a filename that ends with "(E)", in which case you should find a ROM that ends with "(U)" instead.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
It's very different depending on the game. First you'll want to start by figuring out how to draw a simple point or same-sized box at the position of each object/enemy, which tends to be more similar between games than drawing a full hitbox. Basically you have to find where the relevant position values are stored by using whatever RAM search functionality is available. It's probably best to start with drawing something at the main character's position, and hopefully you'll find that the same method automatically works for all the other enemies and objects onscreen with a slight address change (for example in Sonic 1 and 2 you can add 0x40 to the address to go to the next object, and the player is always the first object). You may have to find the position of the camera too unless the position values are already in screen coordinates, but that's usually the easiest part. (One of the Lua samples with Gens shows how to draw a box at the player position in Sonic 1, including taking the camera into account.) Once that's done, now all that's left is to figure out how big the box should be for each object. In the best case, if the game stores all its information about objects together, you can find the hitbox width and height values close in memory to the position values. (It tends to be that easy with Sonic games, for example.) In that case I guess you'd usually check for something like 2 consecutive values each between 8 and 64 (a wild guess but that's the normal range of size values I've seen so far). In the worst case, every type of thing in the game has its own routine that does its own collision checking where the size is hardcoded in the routine and there is no general way of knowing the size of an object. In that case, maybe the best you can reasonably do is figure out where the object type ID is stored, then make a big table of approximate hitbox sizes for all the object types you know about, and use the type ID to choose the size from the table. An in-between case is if the game keeps a table of all object sizes somewhere in ROM or RAM, but only keeps indirect pointers or indices into that table in the objects themselves. In that case, it can take some serious analysis (or at least a good disassembler) to figure out where that size data is stored and how to use it, although of course you can always use the previous method of making a list of sizes manually instead as a last resort. Best best case: all objects in the game are the same size and you're already done as soon as you know where they are. Worst worst case: the game's collision shapes aren't even boxes, and you'll have to figure out how to calculate it and draw circles or rotated rectangles or multi-polygonal shapes, if the aim is to accurately represent the collision.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
I think my favorite part was that jump onto the side of the rotating walkway in Rusty Bucket Bay. Those times like in Mad Monster Mansion where you did things so fast that maybe 4 things that normally only happen individually were happening all at once in a cacophony of audio+dialog were pretty fun, too.
eternaljwh wrote:
Same issue of not taking direct line after completing Rusty Bucket Bay (~1:46:00/190500, two rooms with odd swim lines). ...
----Surface---
             /
            /
Path       /
__________/
It did look odd at first to swim along the bottom and then go up, but (at least at one place inside Rusty Bucket Bay where I noticed this) it seemed like it could plausibly be faster than taking a straight line, because of the way the game apparently lets you swim forward at full speed while pushing you upward with additional velocity if you swim against an upward-angled slope. (I haven't actually tried timing the two.) I'm not sure what would justify some of the other swimming routes though, unless turning while underwater causes some weird speed changes.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
I think that image is the right size and it's really that wide on a real Genesis. Older versions of Gens made everything look way too skinny in some games. However, if you want the old behavior, you can disable "Proper Aspect Ratio in low-res mode" in the Graphics menu.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
It's to be expected, really. If a game handles characters generically enough, then your character is just another "thing" in the world, and of course you can't expect to find every thing in the world at the same memory address, because there's more than one of them. If you're lucky, it'll be at the same place every time anyway simply because the player object gets loaded first and gets assigned to the same slot in memory, but there's nothing stopping a game from putting the player in a random slot every level instead. I had a similar problem recently with a Sega CD game (Popful Mail), where the game code itself got replaced with a slightly different version of the code per level, and the data I wanted to read (hitbox dimensions) was mixed in with that code that was shifting around. So while I thought I had something already working with minimal effort, suddenly I had to figure out what exactly the game does to calculate the memory address it reads that data from. In this case, yeah, unless you have some way of scripting custom offset calculations into the memory watch tool you're using, you'll have to redo the search per level.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
Looks like that bug only happens on playback of the very last frame of a movie (and maybe only if the frame before the last input in the movie is also a lag frame). Here's my current theory of what happened: with that option on, Gens checks ahead to see if the next frame will be a lag frame before emulating it for real, so apparently it decided the movie ended while it was checking if the last frame was a lag frame, then it emulated the last frame as if no movie was active.
Emulator Coder, Experienced Forum User, Published Author, Skilled player (1301)
Joined: 12/21/2004
Posts: 2687
DDRKhat wrote:
I seem to have some bizzare issue. I've compiled this fine however when I run the created Gens.exe , whenever it applies a rendering mode (even when it's first loading up) it for some bizzare reason takes the entire width of BOTH of my screens.
This (somehow-only-shows-up-if-you-compile-it-yourself-in-VS2008) bug is fixed now on SVN. Basically the only change necessary was to replace "NONCLIENTMETRICS ncm;" with "NONCLIENTMETRICS ncm = {0};" in G_main.cpp.