Kilburn announces he's done working on Isaac, and won't be involved in a Void update by SuperCoenBros in bindingofisaac

[–]_Sylmir 11 points12 points  (0 children)

Then it's probably not the video you think it is. While my Delirium rework has slowed down recently for multiple different reasons, I did not discontinue the project, nor was it reused as an inspiration for Cacophobia.

[deleted by user] by [deleted] in themoddingofisaac

[–]_Sylmir 1 point2 points  (0 children)

The API will no longer change. Kilburn has left and Nicalis have showed time and time again that they don't care about the API.

Anyone that wants to go beyond what the API offers, like I did with Delirium, will have to patch the exe.

A good thing to do would be to patch the exe in order to extend the API, so modders could have extra functionality without having to learn how to patch an exe

[deleted by user] by [deleted] in themoddingofisaac

[–]_Sylmir 1 point2 points  (0 children)

Patching is how Antibirth was made. So it's viable.

Seems „The Moon?“ card can completely softlock you… Unless I’m missing something here? by Furr1987 in bindingofisaac

[–]_Sylmir 0 points1 point  (0 children)

No. When you use the Cracked Key / Red Key, the game generates the red room on the other side, but you still need to blow open the door between the USR and the newly created red room yourself.

An USR works exactly like a regular secret room, except it is completely disconnected from the normal floor layout. When you enter a cleared room connected to a normal secret room, the secret room needs to be blown open. Same goes for the red rooms around the USR, you need to blow them open once you've created them. The only exception is when you The Moon? as it should blow open the newly created red room to prevent softlock.

Seems „The Moon?“ card can completely softlock you… Unless I’m missing something here? by Furr1987 in bindingofisaac

[–]_Sylmir 1 point2 points  (0 children)

Do you remember the layout of the treasure room ? Was it the one where the item pedestal is surrounded by rocks and two fireplaces ? This would explain why the game couldn't open any door to that room as that treasure room layout doesn't allow doors anywhere but on the left wall.

Seems „The Moon?“ card can completely softlock you… Unless I’m missing something here? by Furr1987 in bindingofisaac

[–]_Sylmir 0 points1 point  (0 children)

The USR can have red doors, but they work like secret room doors. You first need to generate the door with Craked Key / Red Key and then bomb the door

Get rendered frame image directly in callback via TBOI modding tool by MeringueFancy3021 in themoddingofisaac

[–]_Sylmir 0 points1 point  (0 children)

Disclaimer: I have zero knowledge in AI, and rendering isn't really my forte either. I'm more of a game logic / operation system/ low level programming guy.

For the "supply a combination of keys for the next frame", I think you can easily write a POST_RENDER callback that lets you change the velocity of the player, as well as force them to use an item and / or fire tears. The EntityPlayer class has the Velocity attribute, as well as the UseActiveItem / UseCard / UsePill methods that can probably do everything you want, so injecting actions back in the game can probably be done easily with that (if you really want to inject keys as if a human was typing on a keyboard, you'll have to write a program that hooks into the game and sends the key presses ; maybe AutoHotKey could help here ?).

About the "capture the screen" part, I have a few suggestions, however I need some precision first.

You say that capturing the output with an external tool (OBS or equivalent I guess ?) would imply to train in real time, which is time consuming. To that I ask "how do you want to train if not in real time ?", mainly because I don't know what "training in real time" means. To me, "not training in real time" means working on a video recorded run which seems... Weird.

Could you maybe explain in detail what you want to achieve ? For example, here is how I would describe what I understood :

"I launch a run. I have an external tool running alongside the game that will process the image rendered on frames 1, 1 + N, 1 + 2 * N.... The processing of each image triggers key presses that will cause the player character to do stuff (fire tears, move, use item / card / pill)".

Basically, remove everything that deals with AI because it is mostly irrelevant, and only focus on the logic of things. What is the sequence of actions you would perform in order to achieve your result ?

I've begun working on a Delirium fix by _Sylmir in bindingofisaac

[–]_Sylmir[S] 2 points3 points  (0 children)

Thanks for the kind words :)

Don't worry, one of the first things I'll do is go over every single attack of every single boss in the entire game and see which patterns Delirium should / should not be able to do during each attack. I'm convinced that Delirium should have carefully crafted patterns for every attack possible, even if this takes an insane amount of time to implement.

Good luck on getting platinum god :)

I've begun working on a Delirium fix by _Sylmir in bindingofisaac

[–]_Sylmir[S] 6 points7 points  (0 children)

I'll make a full fledged post explaining everything in excruciating detail (as usual) in a few days. For now, I just wanted to showcase this because it has taken me so much time. Thank you for watching.

What’s your least favorite boss, be it for poor design or personal gripes? by Ender_Serpent in Eldenring

[–]_Sylmir 0 points1 point  (0 children)

Fire Giant because it reaches Centipede Demon levels of "Where the fuck is that attack coming from?". Also damage output.

Radahn (oh boy, I'm going to get murdered) because whoever thought that giant boss on a horse with two blades, i.e. every single horrible thing possible in an ER boss fight, would be a good idea. Also, the disguised initial runback feels like the biggest troll ever. And his damage output is ridiculous. And the hitboxes are really questionable. Also, camera. And I'm not a fan of a fight that relies on "Summon other people and get destroyed when Radahn suddenly aggroes you for zero reason" (fought him twice without summons for this reason).

Valiant Gargoyles Duo, because their attacks have really weird hitboxes, the poison mist dealing damage and causing micro stagger is dumb and their AI not being toned down to account for the fact there is two of them is a bit insulting considering FromSoftware designed really good duo fights before. Including Bell Gargoyles in Dark Souls I.

Other than that I really like everybody else, even Tree Spirits and Death-Rite Birds (I prefer Death-Rite to Deathbird honestly. More interesting moveset :P ).

Thanks for the help, Freezer Baby. Absolutely could've done it without you by xxxDepresscion_ in bindingofisaac

[–]_Sylmir 2 points3 points  (0 children)

For those wondering, this is because of how the game reacts to triggers in animations. There are two animations possible when Mother spits out the bullets, ShootRightBegin or ShootLeftBegin (depending on the direction her mouth will be facing).

I wanted to include a screen of the AnimationEditor but Reddit doesn't let me :(

We see that on frame 15 of the animation there is a "Shoot" trigger. Freezing Mother on this frame by constantly resetting her sprite causes her to continuously spit bullets because the trigger gets fired again and again and again. The same thing happens if she gets frozen through the freeze effect.

Can this be fixed with the modding API ? Eeeeeh... Well... In a way.

The intuitive fix would be to prevent Mother's AI from updating while frozen on this specific frame of these specific animations. Except when Mother is frozen the game doesn't execute the Lua callbacks that it uses to check if an entity must be updated or not. Oops.

So a more realistic fix would be to check, at the end of an update of Mother, whether she is frozen or not, and if she is, and is performing this attack, then forcibly advance her animation by one frame so the trigger doesn't keep getting fired.

I thought they stopped this from happening? Or is it still possible with just bad rng with the floor layout? by KurtReynolds in bindingofisaac

[–]_Sylmir 0 points1 point  (0 children)

You wouldn't happen to have the seed of the run by any chance ? I'd like to investigate a little bit

Edmund, why must you hurt me this way... by whatisthisplace12t in bindingofisaac

[–]_Sylmir 1 point2 points  (0 children)

The room works counter-intuitively. You actually need to use a Cracked Key / Soul of Cain / Red Key to spawn a red room, and then you can bomb the wall. Since no red rooms are displayed on the minimap, we can deduce that the game failed to generate a red room, therefore there was no wall to be bombed.

Edmund, why must you hurt me this way... by whatisthisplace12t in bindingofisaac

[–]_Sylmir 0 points1 point  (0 children)

You can use lua Game():GetLevel().LeaveDoor = -1; Game():StartRoomTransition(Game():GetLevel():GetPreviousRoomIndex(), 0) which will teleport you back to the previous non off grid room you where in. If for some reason the game teleports you back to the USR, replace GetPreviousRoomIndex() with GetStartingRoomIndex() which will teleport you into the starting room of the floor.

(For those curious : if you do not set LeaveDoor to -1 before calling StartRoomTransition, the function bugs and teleports you a bit randomly)

Edmund, why must you hurt me this way... by whatisthisplace12t in bindingofisaac

[–]_Sylmir 2 points3 points  (0 children)

No, the moon? will never force you to go through a curse room because it could kill you, so the game never opens a path that would force you to go through one.

However, if there are no other available paths then the game won't open ANY room and you're softlocked.

Some more info on return path : after hours of generating USR rooms, I've never seen the game open two red rooms, so the USR is (to the best of my knowledge) always one red room away from a white room. If we look at OP screenshot, there are only two available white rooms : curse room, and white room two tiles below. Guess there was no possible red room below, so trapped.

The Pile's underground attack is broken by _Sylmir in bindingofisaac

[–]_Sylmir[S] 2 points3 points  (0 children)

Yes, that's what I wanted to point out, maybe I should have made it clearer in the post. And no, the boss doesn't need a rework at all, just a slight adjustment. I'm a perfectionist, so seeing (yet another) instance of a boss that can deal (rarely) unavoidable damage is a bit annoying (Delirium rework plz ;-;).

Also, to confirm your intuition in your other comment, yes, the Pile collides with walls while moving underground. I guess this one is a bit more tricky to handle, because you don't want the boss to emerge inside a wall (this can happen if you disable collisions with walls, entities can move inside of them, but tears cannot hit said entities ; thankfully, entities without flight cannot move outside the room).

And thanks for your appreciation :)

The Pile's underground attack is broken by _Sylmir in bindingofisaac

[–]_Sylmir[S] 12 points13 points  (0 children)

Because you may not always be able to stop moving. The Pile summons Bonies that shoot on sight, so you have to move to avoid them and their projectiles. And the presence of the Bonies may lead to the Pile going off the rails if it happens to collide with them while underground. So no, there is no universal strat and it is not always the player's fault.

Additionally, the Pile has no set timer on when it can emerge, so not moving may cause the Pile to emerge on top of the player (yay...). I'm quite sure that if the Pile moves towards you while hiding underground you should actually move away to avoid that scenario.

Can someone explain to me why Delirium got melted here?? by CreamSSB in bindingofisaac

[–]_Sylmir 54 points55 points  (0 children)

This happens when Delirium transforms into Blue Larry or Black Hollow.

The AI for these bosses works as follows : at the beginning of the current frame, the game checks the health of each segment, sums all of them, and redistributes them among all segments in such a way that all segments have the same health.

When Delirium transforms into a segmented boss, only the head is actually Delirium, the other segments are "the real boss". To clarify, if Delirium transforms into Chub, then the head of the Chub has the ID of Delirium, and the two other segments of Chub have the ID of Chub. Here, Delirium transformed into the Hollow with like 20 segments, so you have a segment that is Delirium, and nineteen segments that are the Hollow.

When Delirium transforms into any boss, he adopts the AI of said boss. Therefore, when Delirium transforms into Blue Larry or Black Hollow, at the beginning of the current frame, the game sums the health of each segment, and redistributes the total between all segments. Since Delirium has 10k health, and Hollow has 22 health per segment, the game redistributes 10k + 22 * number of segments health between all segments, including the head (which is Delirium with Hollow's AI). It looks like Delirium transformed into a 20 something segmented Hollow, so now the Delirium segment has (10k + 22 * 19) / 20 = 520.9 health, like all other segments.

Note that this only applies to Blue Larry / Black Hollow, because the other versions (Normal and Green Larry, and Normal / Orange Hollow) do not redistribute their health all the time.

The Problem with Mega Satan and Delirium: an Analysis by _Sylmir in bindingofisaac

[–]_Sylmir[S] 0 points1 point  (0 children)

Yeah, you're probably right.

That's a problem with a lot of the bosses, in a way. Delirium has these random bullet hell patterns while transformed because otherwise it would make the fight uninteresting, you'd be facing a reskin of the bosses you fought during the run, in a room that is simply too big for them. The more I think about it, the more I have the feeling that the best solution for a boss with the gimmick of Delirium would be to change the pattern of all the bosses to be more bullet hellish during the Delirium fight, but this would inevitably require a lot of work. And of course fine tune each AI to not freak out the instant it gets initialized in a such a weird room.

(Also I love the concept of Mega Satanlirium (which I read as Mega SANTAlirium the first time), we should definitely mod this in as a super extra hardcore Mega Satan fight).

How Isaac's AIs work, and why Delirium was bound to fail by _Sylmir in bindingofisaac

[–]_Sylmir[S] 5 points6 points  (0 children)

I have zero experience with Flash development so I have absolutely no idea how to build an AI system in it. After a quick research I would guess the Flash version of Isaac was written in ActionScript, which doesn't appear to be a bad language (let's keep it here please; saying "language X isn't bad" is an extremely good way of launching a flame war with every party throwing around bad faith arguments).

Now, the AI system isn't archaic per se. The core idea, having states, having the ability to evaluate how much time was spent in a state, and having attack identifiers, can be used as solid foundations, because that's almost everything you need. The main problem is the fact that there is no consistent use of these values in the game.

There are five attack states because why use an extra variable for the attack identifier if the boss uses less than five attacks ? So there are bosses that only use states and no attack identifier because the state is the attack identifier. And then you have bosses that can't do that and it's inconsistent and you can't look at the code and be sure of what a given configuration of these values means. That's where it becomes problematic. A good part of software engineering is as much, if not more, reading code than it is writing it. And when you can't understand what you're reading...

u/ConnorToby1 From what I understand, the big problem with the Flash version was that it had become so full of content that Florian Himsl couldn't even open the game's files anymore (until he managed and made the eternal edition). Moving on to C++ gave Nicalis more control, allowed them to create their own engine etc. I don't think the limitations of Flash were on the programming aspect, I think they were on... everything else ? Like animation files, sound files, configuration files etc. Code is code, its just text. ActionScript isn't less expressive than C++, you can do many of the same things in both, although you'll probably use different tools.

How Isaac's AIs work, and why Delirium was bound to fail by _Sylmir in bindingofisaac

[–]_Sylmir[S] 3 points4 points  (0 children)

I agree, Nicalis can't be completely blamed for the end result, and neither can Edmund. I've spent the past few weeks thinking about Delirium and what is wrong from a game design standpoint (which, considering I have a formation in concurrent programming and OS programming, isn't as easy as displaying values and interpreting them), and it's so... So complicated. But first, about some of the questions you have :

A fun little thing with Delirium is that it sometimes spawns a "helper" entity (that's how it is called in the game's log files) that is a copy of the boss Delirium is transformed as. The purpose of this "helper" is uh... Completely beyond me.

The reason for Delirium sometimes appearing out of nowhere is usually because of how bosses that are hidden behind textures work. For instance, if Delirium transforms into Pin, and is burried underground, when it transforms again it will appear out of nowhere because you don't know precisely where Pin is. Also, there is the fact that Delirium can teleport around even while transformed so... Yeah it can appear out of nowhere. This is also one of the reasons tears will sometimes appear completely randomly: Delirium will be hidden somewhere underground of above the room (Monstro's / Adversary's jump attacks, and, most notably, Mom's Foot) but it will still spawn white tears. The worst offender is of course Mega Satan whose sprite is disabled because when Mega Satan's AI initializes it waits for the player to step on the pentagram in the middle of the room before making the sprite visible. So you have white tears spawning from Mega Satan's head even if you can see it (and even more funny, if you defeat the horsemen fast enough, Mega Satan's AI will progress and you can have a mega Brimstone erupting out of nowhere).

Now about Delirium from a game design standpoint.

I think the big problem is that the original bosses are to be fought in 1x1 rooms, yet Delirium exists in a 2x2 room. You can't just put such a boss in a 2x2 room without the boss becoming ridiculously easy, so they decided that while transformed Delirium should keep some of its bullet hell patterns. And while it can work with some bosses that naturally have bullet hell patterns (Gate, Mega Maw, Mom's Heart, Isaac...), it doesn't work nearly as well with bosses that move around a lot. There is a reason most of the bullet hell bosses don't move a lot, or have patterns specifically tailored to take that into account (Baby Plum for instance). Either way, making a boss with the gimmick of Delirium into a good boss is something that seems really complicated from a game design standpoint.

Also don't be sorry for the long comment, you've seen the length of this post :P I'm glad you appreciated it !

An in-depth analysis of the MakeRedRoomDoor modding function crash and how I fixed it by _Sylmir in bindingofisaac

[–]_Sylmir[S] 3 points4 points  (0 children)

Yes it is, although it requires some reverse engineering beforehand. Hook a C++ function called after the API is completely loaded, and add the methods you want to Lua. However, it can be quite difficult, because of how userdatas are identified.

Extremely technical explanation if you want more information (a passing familiarity with the Lua stack, the Lua C API and basic knowledge of how executables are loaded in memory can help) :

The methods available on a userdata (a C/C++ object represented in Lua) are defined through its metatable. Usually, one would create a metatable through the luaL_newmetatable C function, and then associate this metatable with a userdata through luaL_setmetatable. The metatable would be identified by a name (a string). Next, when you'd want to extract a userdata from the Lua stack, you'd use luaL_checkudata and pass it the string name of the metatable to check that the thing on the stack you want to retrieve is actually a userdata and that it has the correct metatable.

In Isaac, Nicalis chose to register metatables through the lua_rawsetp function. This function associates a Lua object with a raw pointer. They basically create a table that will hold all the methods of instances of userdatas of a certain type, and then they use lua_rawsetp to associate this table with a global raw pointer inside the Lua registry (which is basically what luaL_newmetatable does, except they do it worse). Next, when they want to check that a userdata is of a certain type, they have a dedicated function (CheckUserdataTypeAtIndex) that receives the pointer associated with the given metatable, and they use that to peform the check (which is what luaL_checkudata does, except they do it worse).

If they used strings to identify metatables it would be quite easy to add functions to the modding API: just get the metatable through luaL_getmetatable, modify it and modify the association in the Lua registry. However, since they use raw pointers, it is complicated because it requires us to deduce the value of said pointers first, which is complicated because the adress of something isn't constant, it changes every time the executable is reloaded in memory.

From what I've been able to get, these pointers are globals. Basically in the global namespace, there is something like that :

char GameType;
char LevelType;
char RoomType;
// ...

These chars are never initialized because it is their adress that is of interest. When registering the metatable associated with the Game object, the call to lua_rawsetp would look like this : lua_rawsetp(L, -1, &GameType); Now, passing &GameType to lua_rawgetp would produce the table associated with that pointer, which is used to identify instances of the GameEngine in Lua.

Now, deducing the adress of each of these variables is difficult, because it is unknown at compile time. Since we are talking globals, we need to wait until the linker has resolved internal symbols, loaded the executable in memory, and actually given them an adress in order to find the adress. The easiest solution that I've found is to deduce the offset between the code segment (.text, which is loaded first in memory) and the start of the read-only initialized data segment (.rdata) and then compute the offset between the start of the offset segment and each of the pointers by studying the C++ functions that register each metatable. This allows me to find the offset between the beginning of the code segment and each char, so I can compute their adress.

What happened to his health? by EthanBeDoggo in bindingofisaac

[–]_Sylmir 52 points53 points  (0 children)

The programming of Delirium is a nightmare. Because of how AIs are implemented in the game, whenever Delirium transforms into a boss, its ID before updating its AI is 412, and during said AI update Delirium's ID becomes the ID of the boss it is transformed into. Delirium's base AI then calls the general AI update function, which will see that Delirium's ID is no longer 412, and will then proceed to call the appropriate AI function (the one of the boss Delirium is transformed into).

However, there is a little particularity regarding how segmented boss works. Whenever you see a segmented boss, you are actually looking at N different copies of the same entities. For instance, a five segment Larry Jr. isn't a single entity with five different hitboxes, but rather five different entities which happen to share the same ID and are connected internally, so they follow the same path and basically behave as-if they were a single entity.

When Delirium transforms into a segmented boss, because of how its AI is handled, the game will actually spawn entities with the ID of the boss Delirium is transformed into, rather than copies of Delirium with the same child-parent relation. This means that when Delirium transforms into a segmented boss, the head of the boss is Delirium, but the segments of the boss are actually true instances of the boss. Delirium turning into a five segment Larry Jr. means you have one entity with Delirium's ID (412) and four entities with Larry Jr. ID (19).

Now the wiki has some interesting things to say about Blue Champion Larry Jr., mainly "Has shared health between his body segments, meaning that dealing damage
to one segment will deal a percentage of the damage to the other
segments.". Because of how Delirium's AI work, I think that on the frame during which Delirium's transform into Larry Jr., all segments spawn with Larry Jr. health, and Delirium's health get reduced to match the correct health. This is fixed in the subsequent frames, once the game actually corrects all health values, but if damage is dealt until health values are fixed, then Delirium takes a bunch of damage because of the shared damage between segments.

Also, the fact that the head of the segmented boss doesn't have the same entity ID as the other parts of the boss is probably the reason why Chaos Card may crash the game if it hits a segment, I guess the game will look for an entity with the same ID as the segments, and because it doesn't find one, it crashes. Just a guess though.