-
Notifications
You must be signed in to change notification settings - Fork 0
Demon Builder
This is far and away the most complex part of the site. Everything feel a little weird if you're new to big web platforms like Angular, but Demon Builder is wholly my own creation and thus much more jumbled and less thought out. Couple that with how difficult recursive call stacks can be to wrap your mind around already, and you get something quite impenetrable. I know that every time I come back to the project the DemonBuilder is something I have to sit down and read through again to understand what's going on.
I'm going to try to explain the general flow here in English to hopefully make the code itself easier to understand.
If you have never played an SMT game before, or haven't played one with inheritance, I imagine the Demon Builder is going to be pretty difficult to understand.
In SMT you recruit demons to fight for you. Once you have recruited at least two demons, you can 'fuse' them together to create an entirely different demon. In a lot of the games this resultant demon will inherit properties from it's sources. Now when you recruit yet another demon, you can fuse that with your resultant demon, and get a new demon that now can have properties of it's parent and it's grandparents. This can be done several times, and in some games it can be done ad infinitum.
In some games these fusions are completely deterministic, and can thus be calculated given a few parameters. The goal of the Demon Builder is to perform these calculations and give the users lists of fusions that can result in a desired demon with desired properties.
See app/shared/smt-tools.types.ts
for for more information and type definitions.
This is the largest unit of data in the DemonBuilder. It contains all the information necessary to create a resultant demon with the desired properties.
A single step of a fusion chain. Contains demons that will be fused (the sources
) and the resultant demon (the result
) as well as what properties are inherited in the fusion.
Fusions can be thought of as a multiplication problem where the two demons that fuse together are the factors and the resulting demon is the product. Demon A x Demon B = Demon C
Because of the deterministic nature of fusions, it is possible to calculate every single fusion that will result in a given demon. These fusions that result in a specific demon are called it's fissions
. For example: Say we have 5 demons. They are called Demon A through Demon E. Demon A + B = Demon E and Demon C + Demon D = Demon E. Demon E is the resultant demon and the pairs Demon A and B and Demon C and D are it's fissions.
You can think of fissions as finding all the factors that make up a product.
For our purposes, fissions can be thought of as a subset of fusions, because they can be represented with the Fusion data type.
There's a lot of hidden stuff in the SMT games that seasoned players might not even be aware. These concepts are not documented in the games, at least the one's I've played, and don't really have a strong bearing on gameplay unless you're really trying to break things.
This one is probably quite obvious to anyone who's played more than Persona 5. There are demons that cannot be fused together, only recruited. These demons are usually rare and have a lot of skills that can be very useful. In Persona 5 these are called Treasure Demons.
There is strikingly little information about this on the web, the best I found was a GameFAQs thread from a while back.
Skill inheritance types return in P5. Each persona has a hidden inheritance type that determines what skills it can receive during fusion based on the skills' elements. These restrictions apply to both the guillotine and gallows, but can be bypassed through use of skill cards. Furthermore, unique skills cannot be passed on irregardless of inheritance type. There are a total of twelve inheritance types with the following restrictions:
My algorithm is not build with standard methods as I want to view the data as it processes. So instead I use RXJs to emit the data as it is calculated. Because of this all of my top-level methods are void. Instead of returning data, they emit through the RXJs subjects so the listeners can pass it on to the DOM.
There are two primaries paths I take when trying to build a demon, and they depend on if I am given a specific demon to fuse to or not.