Thanks to #dustforce for the help with writing this!
The game runs at 60 fps in a proprietary engine. It's available as a freestanding .exe from the Humble Indie Bundle, but I'm not sure if it works in Hourglass. Aside from that I know almost nothing about the technical aspect.
Game mechanics:
Goals include SS All Levels (100%)
Any% All Levels NG+ (Any% done from a completed save)
Low% All Levels NG+ (lowest dust collected possible on each level, determined by the combo meter, segmented run of this is currently in progress by myself)
SS rank (necessary in every level for 100% run) is accomplished by clearing (via attacking or running over) all dust objects in a level. These can include:
- dust on floors, walls and ceilings
- free-floating dust clumps
- enemies
- destructible blocks that are treated as ground for ~6 frames (falling onto these from a certain height can instantly destroy them rather than causing you to stand on them, this depends on character and will be noted in character stats)
Clearing all dust must be done without resetting your combo gauge. The combo gauge is not visible but lasts ~300 frames. With a well-optimized route this requirement should be trivial. There is a separate super meter which fills as your combo increases, visible at the lower left of the screen.
Super is gained after gathering 100 dust, An enemy hitting you will give 5 dust each hit (some enemies can multi hit several times to charge up a super in any% very quickly)
It is faster to exit every level via the pause menu the frame it is completed (as soon as the level timer stops). Also it is technically faster to exit worlds by mouse-clicking "exit level" rather than choosing "main nexus" from the pause menu but this time cannot be saved using the current build of hourglass.
Controls are as follows:
z to jump
- all characters can double jump. Jumping in midair uses up your midair action, so if you double-jump you cannot midair dash and vice versa. Dustkid can perform a triple jump but her jump height is very low.
Jump takes 8 frames, speed decreases over these frames, By jumping on the very last frame(s) you are on a ledge (and about to run off of it) you can cancel these frames and save speed in midair. Called Ledge-Jumping
Jumping uses up 1 air-charge (Killing an enemy replenishes aircharges to maximum, Supering also recharges to maximum, Dustkid has 2 aircharges all other characters have 1)
x to weak attack
- when you clean an object with a weak or strong attack it keeps your speed and refreshes your jump or dash. While you hit something with an attack animation you shift a few pixels up and continue moving slowly in the direction you were while initiating the attack, for the duration of the attack animation.
- Light attacks deal 1 damage, can be spaced out instead of spammed to preserve hang time in the air and clear large gaps easier.
- Killing an enemy gains you a few pixels of vertical height
c to strong attack
- Enemies or objects defeated with strong attack will scatter dust along nearby (non-spiked) walls. This is used to maintain combos but removing the scattered dust may take time.
- Heavy Attacks deal 3 damage, will scatter dust onto surfaces
- Heavy and light attacks can be cancelled via dashing and jumping to end the animation cooldown early and initiating a new attack after jumping/dashing, can be used to heavy attack roughly twice as fast (but of course you are then jumping and dashing in between each attack, so you must position carefully)
- By pressing all 4 (jump, dash, light, and heavy) buttons on the same frame after a heavy attack, you can ground-dash cancel the heavy attack and will heavy attack afterwards, based on timing. Ground-dash cancelling heavy attacks is otherwise impossible. Writeup on this here: https://docs.google.com/document/d/1RPyZryeTh7ADiWP6-S5q8Y7Ofb5KIA91U7kPptgj95c/edit?usp=sharing
x+c to super attack
- The super attack can be used with a full combo bar. It cleans all destructible blocks and floor dust within its radius instantaneously (does not clear floor dust you have no line of sight to) and defeats enemies in the radius in one or two hits. All cleaned dust goes to refilling your next super. A unique property of the super is that it refreshes your jump and dash even if it doesn't clean any object.
See these videos for more information:
Link to videoLink to video
- Supers on 1 enemy takes 0.7ish sec, adding 0.116 for each additional enemy.
lctrl to dash
- dashing sets velocity to maximum running velocity. Constantly dashing across flat surfaces is the same speed as max velocity running if you dash on the first possible frame. It also maintains velocity gained from slope or ground boosts (see below)
- It is possible to dash in midair once per jump/fall.
- Dashing on Dustworth does not take to maximum run speed, have to dash once and then let him run to gain speed. Dashing uses 1 aircharge, Dashing to maintain boosts is done roughly 4 and a half times a second, with 12 frames in between each dash.
-Wall jumping or dashing does not use an aircharge
- Can press Dash and Jump on the same frame to reverse momentum in midair to dash speed instantly, Can only be done at near 0 Y speeds.
up to wall-run
- while holding up you can run up walls and even on ceilings for a brief period. from a wall-run animation you can double-jump.
down to fastfall/slide down slopes
- during a falling animation your max velocity is higher.
- you can attain very high speed by holding down while sliding down a slope. This velocity can be retained after exiting the slope with constant dashing before you land and resume running at normal velocity.
- fastfalling can be used to fit through very close sets of spikes, since spikes do not stick out from the edges of a tile.
Glitches/exploits:
- groundboosting
Hitting the ground at above a certain velocity will give you a small speed boost that you can keep by dashing on the first possible frame after touching the ground.
- Ground boosting can be done from higher heights the more speed you have (including boost speed) want X and Y speed values to be roughly the same to achieve boost. Boost is approximately a 50% speed increase over dash/run speed.
- hit canceling
dashing or jumping while attacking will reset any active attack animations allowing you to attack several times in rapid succession.
- ledge canceling
when wall-running up a ledge, if you have the ability to air-dash, do so immediately after you clear the edge of the ledge. if not, downdash and dash upon hitting the ground. when in the air and not keeping velocity from a slope or ground boost, you move relatively slowly and this should be avoided whenever possible.
- spike jumps
there are certain ways to land on spikes and not die. landing on the edge will just barely put you on solid ground outside of the spike hitbox
Link to video landing on a 45 degree downwards spike row if you have already double-jumped is also survivable if you are holding down+jump the frame you hit the spike. it will count you as on the ground before you are killed. you can see this used many times in IL runs.
- Landing on the very edge pixel of spikes is possible (can also hit this pixel on walls and non-90 degree walls as well) landing on the very edge pixel of a dust block/dust tile will not destroy that tile until you move (can be used in low% to avoid picking up dust tiles but still being able to land on them)
- dashjumping
pressing dash and jump at the same frame in midair will cause you to execute both actions at the same time. you can quickly reverse momentum with this and can keep high speed while jumping after clearing an object in midair.
- acute angle clipping
walljumping while stuck in a corner oriented like |\ or /| will occasionally send you through the corner. i'm not sure about the exact mechanics of this but it comes in handy sometimes, more on it later
- Clipping can be done in several geometric configurations. The one used in the Grass Cave Best Time IL takes 7 jumps to clip through the wall. must dash into a 45 degree configuration to clip through (seen in Core Temple Best Time IL)
- wiring glitch
it is possible to get an ss rank in the wiring hall stage without cleaning certain pieces of dust. refer to the segmented run for info
- Jumping from a 45 degree slope going to the right is faster then dash/run speed, Going to the left however is slower. (includes spikejumps)
misc unsorted:
- Ceiling slides are faster then dash/run speed initially, but reduces over time of the cling, release cling early for small speed boost.
-Attack hitboxes of Down and Up heavys can reach through walls/floors/ceilnigs etc. See Firefly Forest SS
-Jump and attacks are disabled at the start of the tutorial level.
-"spikejumping" on 45 degree dust tiles will not destroy the dust tile, can be used to skip dust in low%
-porcupines shoot spines which can be deflected into enemies to instantly kill them, overlapping enemy hitboxes can result in 1 spine killing 2 enemies.
-Wall slides downward are quite slow, instead use "superdrops", freefalling slightly off of the wall and using attacks while falling to clean the dust on the wall (Night Temple SS)
-Attacking spines shot by porcupines will gather dust (Grass cave SS used to get a 2nd super)These function like apples, so heavy attacking all 3 spines+the porcupine itself will give 10 dust, from a 1 hp enemy(not including any dust spread onto surface)
-Enemies who fall into deathzones are considered killed/cleaned for the purpose of SS ranks, Skipping them to save time if they will fall into a deathzone is possible and still get SS rank.
-Because heavy attacks are slow, light attacking an enemy so he will be in range for you to heavy attack it and another enemy can save time (1 light+1 heavy=faster then 2 heavys)
-Light attacking with Dustkid is faster then heavy attacking
For all other characters 2 light attacks are faster then 1 heavy attack (useful on 5 hp enemies)
-Ingame replays are available for all IL's for any% and SS, can be used as an excellent place to start getting an idea for routes and improvements.
-Occasionally an enemy will not be tied to the goal flag and does not need to be killed for any% (though it might be faster to with a super rather then waste time avoiding it)
-Spikestand can be done on angled surfaces(concrete temple best time) 1 tile above is 5 pixels of width, 2 tiles of height above it becomes impossible due to you sliding on the sloped floor.
-by jumping repeatedly very fast on 26 degree walls, you can infinitely climb them
-Checkpoints can be used to deathwarp (Moon temple best time, peta difficult best time) useful for any% and low%
-lower left part of character hitbox will not be killed by spikes. Can be used to jump and ledge climb over spiked surfaces.
-Dustman and Dustgirl cannot get up the wall from Knight hall to Tower
-Dustworth has the fastest groundboost speed
-Rooted slimes can be hit into a sling animation and killed with 2 lights, normally would take 4
-Wiring SS is based off of specific "fake" dust patches, and specific "real" dust patches, not based on a # of dust collected etc.
-Dustkid and Dustworth have a slower maximum fall speed
-Character will potentially unload (softlock of the level, must restart from beginning) if too far outside of camera. Camera nodes are wonky.
Playable characters:
Dustman: Standard character, same attack animation length as dustgirl though different hitboxes. block breaking height: 6 blocks with downdash, 8 without
Dustgirl: As dustguy but reaches terminal velocity on slopes slightly faster, keeps more speed during wall runs/jumps. Starts falling one frame faster during jumps. block breaking height: same as dustman
Dustkid: Low jump height, can triple jump, fast attack speed but short range. block breaking height: 3 with downdash, 5 without
Dustworth: Very good jump height, large attack hitbox but slow attack speed. Moves very slightly slower (1 frame slower over 8 seconds) than other characters. block breaking height: 4 with downdash, 6 without
- Block breaking height is roughly 80% of terminal velocity. Tile #'s should be accurate.
- I believe dustgirls fall start is actually 3 frames faster then dustman. Does not reach terminal velocity faster (and not only on slopes) instead just starts the fall sooner. Keeps more speed during wall runs is something I have not heard and is confirmed, would need testing.
Character hitboxes: http://imgur.com/a/Qad21
WRs:
Any% (single segment (outdated):
Link to video
100% (SS):
Link to video
100% (segmented) (outdated):
Link to video
(compilation of best IL times and semi-optimized stage order)
I've been informed that this doesn't and likely never will work in Hourglass unless mouse support is added in the astronomically slim chance of a future revision. (There are also some other, game-specific issues of it not accepting input for some unidentified reason.)
So this is on indefinite hold unfortunately.
Yeah, I see there's been no word from nitsuja for quite some time now. I think I need to be more comfortable with this game RTA to consider TASing it, though, so it not working is kind of a lucky break, hehe.
Joined: 3/2/2010
Posts: 2174
Location: A little to the left of nowhere (Sweden)
nitsuja disappeared last year, but I have seen people saying that he did promise to come back. We just have to be patient and wait, whatever reason he had to disappear it was surely a good one.
I have tried to improve Hourglass a bit for fun but the code is a nightmare to work with and I don't have the same knowledge about this stuff as nitsuja does so it is a very exhausting and slow process. I might manage to figure out how to add mouse-recording at some point but I will not promise anything.
nitsuja disappeared last year, but I have seen people saying that he did promise to come back. We just have to be patient and wait, whatever reason he had to disappear it was surely a good one.
I have tried to improve Hourglass a bit for fun but the code is a nightmare to work with and I don't have the same knowledge about this stuff as nitsuja does so it is a very exhausting and slow process. I might manage to figure out how to add mouse-recording at some point but I will not promise anything.
I've tried this too and ran into the same problem. I might try again some time soon and document my findings as good as I can. That might just help some people out.
Since the necessary mouse input is so simple (click "Guest" once the game opens) would it be possible to work around it using some sort of mouse macro? How possible is it to make Hourglass run two programs at once, or run a program that itself runs another program?
According to Atma, who was the only person to dump the file into Hourglass and test it, there's much more than the issue of mouse input to deal with. Apparently Hourglass doesn't acknowledge the method that the Dustforce engine uses to accept input, so it basically can't read input. Since I don't know the engine's specs, I'd have to ask Hitbox Team themselves for more concrete info.
I think I might, in fact. They might be flattered to see this game TAS'ed.
Since I don't know the engine's specs, I'd have to ask Hitbox Team themselves for more concrete info.
I think I might, in fact. They might be flattered to see this game TAS'ed.
That sounds wonderful. It would be nice to also get the low-down from them regarding things like the frequency of input/physics processing, so we know what to set the Hourglass framerate to. And maybe even some hints that will point us in the right direction for ramwatch values? Like whether their positioning info uses floating point values or fixed-point/subpixel values.
Though of course, even if we get information about what isn't working, we'll still need somebody who can make the necessary fixes to Hourglass to get it actually working. I'd love to help, but Hourglass's inner workings are much lower-level than anything I've worked with.
Hello there and thanks for making such a solid game, guys! I recently got the idea of starting off a TAS of Dustforce for TASvideos (I might collaborate on an SS All Levels TAS or a Fastest Completion/any% TAS). There's a utility called Hourglass which people use to TAS windows games, allowing for things like frame advance, save states, and watching memory addresses.
I had a member of the TASvideos community recently check to see if Dustforce can be dumped and can work successfully. It turns out that it boots successfully but cannot render keyboard input, and requires mouse input to initialize a file, which Hourglass is incapable of supporting and playing back. The larger issue of the game not accepting keyboard input, however, is based on your game engine. I suspect the method you use to accept input is one that Hourglass's code does not detect.
To give us an idea of how to mod Hourglass for compatibility and get the TASing started, we will need a bit of information on the game's programming. Hourglass works by injecting code before calls to certain functions in the game's code (rand() to read the game's randomness state, sleep() to allow frame advance, etc) and allowing the user to control the activation of these functions. If a function is not in the list of functions that Hourglass can hook, nothing related to that function can be controlled.
I suspect that the way Dustforce gets keyboard input uses a function not on the accepted list for Hourglass. If you could let us know what API/functions the game uses to detect keyboard input at the lowest level (and, for that matter, how many fps it checks input and performs physics calculations) we may be able to modify Hourglass's code and solve the bulk of the compatibility issue.
We would also like to have an idea of how your engine stores speed and positioning values. TAS producers monitor these values closely to allow for speed optimizations and precise positioning. It might be helpful to give us an idea of whether you use floating-point or subpixel speed values.
If successful, this project would join Cave Story and Rozenkreuzstilette on the list of PC games that have been TASed, and might help to bring your game a broader audience and attract more speedrunners. I hope you would also enjoy watching the results!
Best regards,
elitist_jerk
I suck at technical language. Please revise this with any relevant information about Hourglass and any terminology you or Hitbox Team might understand. Thanks in advance!
This information should help:
-Hourglass works by hooking (injecting a piece of code before every call to) many, many functions that do keyboard input, display graphics on screen, system calls, calls to rand() and so on. This way it can give keyboard input exactly as often as needed, freeze the process at consistent intervals for deterministic feedback, etc. However, if a function is not hooked by Hourglass it does not exist, and the full list of functions it hooks can be seen by examining its source code on google code.
--In particular, this means that the needed information is - what API/functions does Dustforce to get keyboard input on the lowest level?
-Hourglass does not currently support any networking or internet stuff 1) because it would be too difficult to make deterministic for playback, hard to make an input format for, etc 2) someone has to code it, anyway.
-It also doesn't support mouse input, but this isn't due to technical limitations, it's just because it hasn't been implemented, e.g. it would take a while but nothing prevents it otherwise.
For some kind of reference, unless they added a patch for a non drm version (ie. the HiB version), any changes would be of no help anyway, since games that utilise the steam api don't run in hourglass.
The HiB version doesn't use steam_api.dll, is that what you mean? As far as I know, if you sign in as a guest and the internet is disconnected, it won't try to connect to the leaderboards.
I'll edit my post in a sec with the new info and you guys can tell me what you think.
The HiB version doesn't use steam_api.dll, is that what you mean? As far as I know, if you sign in as a guest and the internet is disconnected, it won't try to connect to the leaderboards.
I'll edit my post in a sec with the new info and you guys can tell me what you think.
I just checked, and I've confirmed that the HiB version runs just fine with no internet connection. I was somewhat surprised to learn that it still saves game data locally when logged in as a guest... that could be somewhat annoying if it saves in a way that Hourglass doesn't manage to interrupt, since having doors already unlocked would cause desync. It may help to look into that as well, I'm going to try to find where save data is stored.
Thanks for doing the footwork! I think save data is stored in Appdata/Dustforce. Deleting that folder might stop desync.
Known issues:
- Using esc to pause saves time. Due to Hourglass's controls this is problematic.
- Mouse input is absolutely required to play.
- There may be larger input-reading issues but since we can't render any input until passing the loading screen, we don't know yet if this is the case.
I can ask Hitbox team about what functions they use to save data and render input, but I think most of the work aside from that just involves adding mouse support/doing a mouse macro if running programs in parallel is indeed possible. We also might need to find a way to remap Hourglass's keybindings because having esc pause the console is very annoying.
We also might need to find a way to remap Hourglass's keybindings because having esc pause the console is very annoying.
Hourglass is really flexible in that respect. You can both remap the shortcuts that hourglass uses and also what keys map to what in game terms; e.g. you could make it so that pressing Q maps to ctrl and W maps to esc to avoid potential hotkey conflicts. It's also useful if your keyboard has a hard time registering certain combinations of keys.
Oh, so just like every other emulator. That's good news!
Aside from waiting on mouse support (even rudimentary mouse support would work since we need it for about 5 frames total and it only clicks in 2 locations) and talking to the devs I actually think this game is pretty close to fully working.
Email has been sent, but I also wonder if the game is compatible with savestate support or not. Is that something that universally works for all games that run or is it dependant on the engine's programming?
Joined: 3/2/2010
Posts: 2174
Location: A little to the left of nowhere (Sweden)
Thanks for this information, gonna see what I can do with it. Currently mouse-input is a bit of low priority for me but I do have plans to add it after a couple of save-state and movie-structure improvements.
The function Dustforce uses to read keys is this Windows API function: SHORT WINAPI GetAsyncKeyState(_In_ int vKey); ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms646293(v=vs.85).aspx )
Hooking this may get tricky as it feels like it can be VERY desync-prone. (In playback we'll "press" the key when the function is called but not executed yet)
When TASing I think an FPS of 60 would be accurate, since the game will read input 60 times per second.
Joined: 3/2/2010
Posts: 2174
Location: A little to the left of nowhere (Sweden)
Warepire wrote:
Thanks for this information, gonna see what I can do with it. Currently mouse-input is a bit of low priority for me but I do have plans to add it after a couple of save-state and movie-structure improvements.
The function Dustforce uses to read keys is this Windows API function: SHORT WINAPI GetAsyncKeyState(_In_ int vKey); ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms646293(v=vs.85).aspx )
Hooking this may get tricky as it feels like it can be VERY desync-prone. (In playback we'll "press" the key when the function is called but not executed yet)
When TASing I think an FPS of 60 would be accurate, since the game will read input 60 times per second.
I checked the code again, this function is hooked, and IWBG uses the same input method for the keyboard, so keyboard input for Dustforce should be recorded. This is very interesting, can you supply a log and a movie file of attempting to TAS Dustforce on build r81?
You can PM the link to me if you don't want it shared publicly.
It'll take me a while to set up a VM and get Hourglass running, but sure. I'm not sure how much of a movie file it would be, though, since I still won't be able to bypass Guest.
Also I love you dude, thanks for being willing to help/translate this.
When TASing I think an FPS of 60 would be accurate, since the game will read input 60 times per second.
The description also leads me to think that the "frame advance skips lag frames" option should definitely be disabled, at least during levels. It sounds like physics steps are run every 1/60th of a second regardless of the actual framerate, so in the case that the frame rate drops below 60 FPS input will continue affecting the gameplay whether or not the screen actually appears to change. (Note that he says "the game step happens 0-n times per rendered frame", implying that the lower limit is 0 rather than 1.)
Also his description of the use of GetAsyncKeyState() implies to me that it only checks if a key is "up" or "down" once a frame, so it won't register something like a key being released and pressed again in less than 1/60th of a second. As such there isn't a possibility of a technique coming up involving mashing a button faster than 30hz, and so we won't need to do something like set Hourglass to something higher than 60 FPS to allow for it.
Unfortunately this isn't all that helpful in terms of the features Hourglass will need in order to accommodate Dustforce, but it should help work out the necessary settings once we actually begin work on the run proper.