nxengine / nxengine-evo

nxengine refactoring
https://discord.gg/jnwmA7DhQh
GNU General Public License v3.0
479 stars 81 forks source link

Inconsistencies #26

Closed isage closed 5 years ago

isage commented 6 years ago

I'm pretty sure there's ton of inconsistencies between nxengine and original. Enemy behaviour, damage, physics, etc. It would be nice if someone took upon a task of comparing original freeware version and nxengine. Pull requests are welcome too, but with detailed description of inconsistency.

nlburgin commented 6 years ago

I've been playing it a while (currently at Last Cave) and for the most part it feels solidly identical.

However it's been a while since I last played the original, so that makes the comparison a bit harder.

One thing I've noticed is that the lvl3 sword (King's ghost attack) seems more effective against bosses than I remember. Although that could very easily just be my imagination.

An interesting way to non-subjectively test for identicality, though, might be to take an old TAS of the original, and somehow convert the Hourglass input movie into a format that could be played back on Nxengine.

It certainly wouldn't be the easiest way to test it, but it would be a very robust test because it takes the human element out of play and provides a way to compare how the two versions respond to the exact same inputs on the exact same frames. Every time it desyncs, you've uncovered a new bug!

Easier said than done, of course, so it would be quite understandable if you didn't want to do it, but it's just a thought I had.

isage commented 6 years ago

Yeah, i was thinking about something like that. Hourglass format seems easy enough, guess i'll slap together some player for it.

isage commented 6 years ago

Ugh. It seems like i'll need to build the player into engine, because SDL uses raw evdev input and completely ignores Xorg events.

isage commented 6 years ago

Oh. okay. i've kinda implemented separate player for hourglass records. And found first inconsistency right on atart: speeding up dialogs by mashing Z X doesn't work as in original. Also, i've only found one movie: speedrun by nitsuja. Are there any others?

nlburgin commented 6 years ago

SDL uses raw evdev

At the risk of introducing a new dependency, I know evdev is scriptable through python; it's possible that could simplify matters as long as it's not too slow to keep up with the game.

I was aware of this, because I use a Wii Remote driver that's based on it, called CWiid.


i've only found one movie: speedrun by nitsuja. Are there any others?

I've found it surprisingly difficult to find any.

I found some things for Cave Story+, and some things for Jenka's Nightmare (an old mod that won't readily run in Nxengine due to how heavily altered it is), but I doubt either of those would help.

What few other TASes I've found for the original cave story were just simple tests, and I can't seem to find the original hourglass file for any of them.

I have an old Windows XP setup in Virtualbox that I could theoretically use to record some new ones, if you want. They could begin from save files (normally a no-no in the tas community) so that it could test later parts of the game without needing it to sync perfectly through the earlier parts.

Although, Nitsuja's TAS alone seems like a pretty good stress test for finding differences in obscure, non-obvious behaviors of the engine, seeing as it abuses so many of them ;-)


If you're actually going through with this, another question of potential interest: Does Nx currently go out of the way to use the same RNG as the original?

Because if it's not using the same RNG, that could cause discrepancies a human player would never notice, like when the TAS manipulates item drops.

And even if it's using the same RNG, in order to load a TAS movie there would need to be a way to ensure it's started with the same exact seed. AFAIK, Hourglass does this by manipulating the System Time seen by the target program, under the assumption that the RNG will be seeded with that.

isage commented 6 years ago

At the risk of introducing a new dependency, I know evdev is scriptable through python;

Nah, i've already solved this with "player", that creates a virtual keyboard device through uevent and sends keys from hourglass movie. And a hook library to sync with frames.

I've found it surprisingly difficult to find any.

Oh well. I do have an old notebook with windows, so i can probably record some replays myself.

Does Nx currently go out of the way to use the same RNG as the original?

Original nxengine uses self-implemented RNG (i guess the same as in original game), nxengine-evo, however uses system RNG. I guess i can revert this, and monkey-patch to use seed from replay.

nlburgin commented 6 years ago

Original nxengine uses self-implemented RNG (i guess the same as in original game), nxengine-evo, however uses system RNG. I guess i can revert this, and monkey-patch to use seed from replay.

I have a mild suspicion that the original cave story probably used the system RNG from windows, though this may not be compatible with Linux, OSX, or even more recent Windows.

Hourglass, for its part, I think is pretty much exclusive to WinXP, since its hacky methods for encapsulating and manipulating game processes are non-portable even amongst different versions of Windows, so if it uses system RNG, that's probably what the TAS was targeting.

Although, Pixel being Pixel, I wouldn't put it past him to have written his own RNG instead of using the standard library, that too is entirely possible.

Either way, if the original NxEngine had its own RNG instead of using the standard library, I'm guessing it was probably meant as a compatibility thing, though I can't vouch for how well it actually succeeded at being compatible.

I do know that PySolFC, a solitaire suite, successfully implemented a clone of old Windows default RNG, which it only uses for relatively low seed values, solely for the purpose of replicating the shuffle & deal results of MS Freecell's "game numbers"

isage commented 6 years ago

Original engine just uses windows system srand/rand. NXEngine implemented it, but it looks like slightly incorrectly. I'll revert my changes and fix rand to be the same as on windows.

isage commented 6 years ago

Ugh. nitsuja's replay seems impossible. Engine needs to be frame-perfect for this and right now it gets 5-10 frames faster to the point, where you can actually control Quote. Either stage transitions are faster or fadeins/fadeouts. Or both. And i'm not sure i really want it to be frame-perfect. However, i guess i can still test using hourglass and playing slowly. Also, nitsuja's comments for replay are pointing out some mechanics i wasn't aware of (like that max walking speed actually oscillates)

nlburgin commented 6 years ago

Also, nitsuja's comments for replay are pointing out some mechanics i wasn't aware of (like that max walking speed actually oscillates)

Interesting. It could be that you might more easily get consistency fixes from reading the commentary, than from actually trying to play back the TAS.

And i'm not sure i really want it to be frame-perfect. However, i guess i can still test using hourglass and playing slowly.

Hmm... I guess there's no harm in not replicating some of the more obscure and unexpected behaviors of the original engine, especially if it's some crazy corner case that Pixel likely never intended.

On that note, an Hourglass recording of someone playing like a normal person might indeed be more helpful than an actual super-optimized TAS.

nlburgin commented 6 years ago

I just found a couple inconsistencies through manual testing.

I loaded my save I'd been using on Nx in the original, which is currently at the Balcony.

In Nx, you can stand on the Igor's (I think that's what the larger rabid mimiga is called, though that may just be the boss version in egg corridor) head as well as the smaller one.

In the original, contact with the top of the Igor does damage, while the smaller one can still be stood on.

Also in Nx, the limit on how much damage Misery can take before she turns invincible and teleports seems to be much laxer.

In Nx, I can wipe her out instantly with rapid-fire super missiles at the start of the fight. In the original, I can't do that. Also, the amount of damage I can do with the Snake before she disappears is much higher, about 2-3x.

I didn't notice that happening in any earlier boss fights, but I may just not have been paying attention. I don't know if it's specific to Misery, or if there's a general issue in how bosses close off their weak points.

I think even if there's a general issue, though, I think it must be much worse for Misery. I know the Core wasn't nearly such a pushover to super missiles, since it would actually shut its eye after getting hit with a couple like it's supposed to.

nlburgin commented 6 years ago

Okay, I think the reason it was so noticeable with Misery, was there were two issues happening at once.

One issue is, Misery doesn't turn invincible and teleport early after taking a certain amount of damage the way she's supposed to. I don't think any other bosses have this issue.

The other issue is, the Super Missile Launcher is just doing way too much damage. I think this is the actual reason why I thought some of the other bosses might have had a lesser version of Misery's issue.

I was playing around with the rabid mimigas on the Balcony, and in the original, the max amount of damage I could do with a single firing of the Lvl3 SML, with all 3 missiles hitting cleanly, was 38. In Nx, I could do up to 66.

nlburgin commented 6 years ago

I made a video demonstrating the issue. "Gaahhh" indeed.

simplescreenrecorder-2018-02-25_00.13.22.mkv.zip

isage commented 6 years ago

Hm, Misery should teleport out when being hit for >=80hp. But supermissile damage is indeed seems off.

isage commented 6 years ago

The problem with missiles (and supermissiles) is that they deal splash damage: they spawn blasts and each blast deals some damage. However, arms table in original only sets damage for blasts (and damage for missiles is set to 0). And all guides on the internet only list cumulative damage, ugh. Back to the disasm for me, i guess.

isage commented 6 years ago

Hm, yep. Although Misery should teleport out when receiving 80 damage, i can deal 132 with machingun until she do (and 84 in original). This is strange.

isage commented 6 years ago

Oh, i found (and fixed) stupid bug in Misery AI. Now she indeed teleports when receiving 84dmg from machingun.

isage commented 6 years ago

I've created separate issues for Missile Launcher and For Igor

nlburgin commented 6 years ago

Just built from git master (was previously using source release 2.6.2), and I can confirm that Misery now no longer just sits there and lets you obliterate her.

isage commented 6 years ago

Ping @Clownacy Sorry to bother you, but is it possible to add drawing of hitboxes of npcs and bullets to your mod loader? Basically, function for checking if bullet hit an npc is at 0x471D50, but i'm not that good with asm (e.g. not good at all) to figure out how to insert a custom function call somewhere in-between. Do i need to replace it altogether?

UPD: Nevermind, looks like i figured it out.

Clownacy commented 6 years ago

So, do you still need a hitbox drawer?

isage commented 6 years ago

Nah, i've already implemented it. Sorry for bothering. (also, i can send a PR, but my method currently conflicts with widescreen mod. and i'm not sure if someone besides me even needs it)

isage commented 6 years ago

So, found two more bugs, while testing missile damage: 1) Second form of Monster X doesn't show floating damage numbers (fixed) 2) Floating damage sometimes shows more damage, that actual NPC hp: lv3 rocketlauncher vs gaudis shows 16 dmg, while gaudi hp is 15. However, that might be only for gaudis, because their hp in npc.tbl is actually 1000 (?!). Need to test some more. I probably won't fix that, as it's purely cosmetical. UPD: nope, that happens only with rockets. Probably because of how they do damage. To fix this i should deal cumulative damage (and kill) to an npc at the end of the frame.

I'm still not sure what to do about missiles. For now i've re-implemented original buggy way of handling bullets (not committed yet, need to test some more). However, i'm not really liking that solution.

Clownacy commented 6 years ago

I've heard the 1000HP thing is a trick in the original engine. There's no way to change an enemy's death behaviour, so instead the game basically cheats, and gives the enemy a ludicrously high amount of health. Then the enemy itself checks if its health is below 980HP or so, and then kills itself with a custom death sequence.

isage commented 6 years ago

Eh, okay. Latest (rather large) commit should fix missile damage/behaviour/hitboxes/etc.. And even almost correctly displays damage that's more than npc hp. I really hope i haven't broken anything else

isage commented 6 years ago

I've put (back) in correct implementation of windows RNG.

nlburgin commented 6 years ago

It's less inaccurate than before, but I can still sometimes do up to 40 dmg with a single super missile firing, so it's not perfect.

simplescreenrecorder-2018-03-09_11.23.05.mkv.zip

isage commented 6 years ago

That's actually right damage. Lv3 super missile launcher deals 36-40 dmg depending on when first and second/third missile hit target (and you can actually do 42 by manipulating bullet queue with another weapon and some luck). But, there may be something off with missiles pattern/acceleration, so they hit with another order/timings that original.

Yukitty commented 6 years ago

I'm not sure, since this is one of those RNG-based things, but it seems to me like Jenka (NPC in Sand Zone) seems to be shaking her head a LOT more often than I'm used to, sometimes it looks like she's spasming uncomfortably.

Yukitty commented 6 years ago

I am noticing the Missile Launcher seems to get reordered to the end of the weapon whenever you pick up Max Missiles upgrades. That's not normal, is it?

Yukitty commented 6 years ago

Monster X makes no pain noises. Edit: I should be more specific. The four green balls you have to break to even begin to damage Monster X do make pain noises. But once you start damaging the boss itself, no more pain noises until the death animation.

Yukitty commented 6 years ago

The "shutters" and "lift" (but not the primary blast door) in the map Core are completely silent. If I recall, the Sun Stones in Sand Zone were also silent. And shouldn't be.

I think a LOT of the inconsistencies are actually just random missing sound effects related to AI actions because the primary set of sound effects, bounding boxes, etc. are set in the external data files it reads from the original source anyway.

Yukitty commented 6 years ago

The dummy player object (which is used for things like teleporting) does not change for Mimiga Mask.

Yukitty commented 6 years ago

When Kazuma catches you for the normal ending or mimiga mask ending, Sue is nowhere to be seen. Did she just plummet to her death, or are you missing connected-object AI for Sue being carried by her scruff in the dragon's maw?

isage commented 6 years ago

The "shutters" and "lift" (but not the primary blast door) in the map Core are completely silent. If I recall, the Sun Stones in Sand Zone were also silent. And shouldn't be.

Hm. I've checked, and in original game shutters and lift are also silent. Sun blocks should make noise.

isage commented 6 years ago

Checked sunstones, and they do make sound.

isage commented 6 years ago

And Sue's fixed now. I'll separate what's left into different issues.

isage commented 6 years ago

Hm, comment about Mr. Little is somehow gone. Is that a valid bug? He should pop up, yes, if you beat the game with best ending and him still in the inventory

Yukitty commented 6 years ago

No, sorry, Mr. Little works as intended, I was just getting the wrong ending for him to care. ¯\_(ツ)_/¯ I've been having that problem a lot, doing things like reading Sue's letter and wondering why the Jail escape block doesn't open, when you actually have to talk to Mahin again, etc.

Yukitty commented 6 years ago

screenshot from 2018-07-04 16-24-53

isage commented 6 years ago

Yeah, you need to copy over new sprites.sif.

Yukitty commented 6 years ago

Oh, dur. Silly me.

Yukitty commented 6 years ago

Things that don't feel right to me, but I still need to research more thuroughly:

Yukitty commented 6 years ago

The Whimsical Star doesn't seem as "reactive" to player movement as in the original. If you go through a door (so the stars kind of reset to a tight orbit around you) and then start walking, they generally would start swinging out in front and behind you without going upwards until you jump.

Also you can currently "stand on air" over the edge of a cliff without falling since the blockd is so wide.

isage commented 5 years ago

That's a long list of zxin's complaints, which needs cleanup and splitting into separate bugs, ugh:

isage commented 5 years ago

I've cleaned/split the list above into different issues.

B4rabbas commented 5 years ago

Hi there, if needed I've made a correction of the french translation : there was few grammatical errror but a lot of misprint (just look my repo if you want to implement it).

I've also an auto quit at the start of credits,

ayuusweetfish commented 5 years ago

In nxengine-evo, Life Capsules refill player's health, but in the original PC version it only increases remaining health by the capsule's value. I haven't purchased CS+ so I'm not sure how it behaves there.

Should there be a change? A 1+/1- will do.

https://github.com/nxengine/nxengine-evo/blob/5025ad1f3c84928b779ca01ec0390f3d360e8d6a/src/tsc.cpp#L881

isage commented 5 years ago

In nxengine-evo, Life Capsules refill player's health, but in the original PC version it only increases remaining health by the capsule's value. I haven't purchased CS+ so I'm not sure how it behaves there.

Yeah, you're right. Fixed.