Because apparently "think about BM infrastructure" is my brain's current idle loop.
This is a very high-level thought dump; I haven't looked at the actual implementation details this would have to interact with in ages, and remember nothing of what I may have seen. I'm a big fan of getting one's abstractions sorted early on, though.
Conceptually, containers are a unified framework for dealing with skills that work at the recipe level. The advantage of having a framework is that, in theory, it'll minimize the required tinkering with the game engine each time we add another one, and help keep their interactions well-behaved. The disadvantages are that it's a bigger pile of work at the front end, we already have two skills implemented that futz with recipes, and that while, in theory, there is no difference between theory and practice, in practice there usually is.
Anyway, the basic idea is that a button recipe consists of one or more containers. At the start of the game, and after each lost round, they are "opened", and add dice to the player's active dice, getting the player to make any necessary decisions in the process. (Or they open every round, but the decisions are locked in unless you've lost. This may be entirely theoretical, but I suspect it'll end up mattering.) The active dice are what you actually fight with.
Syntax:
A container is written as TN[dice], where T is the encoding of the container's type. (or skill, or power, but those terms are already in use. Of course, type may be a reserved word. We'll think of something.)
Most types are just going to be a letter. In theory, we can share with the skills. In practice, that's going to cause confusion. Plasma, however, is a list of comma-separated skills surrounded by braces.
N is an optional positive integer. Not all container types need this, but if we're generalizing hard enough, most of them can find a use. If it is not present, it is 1.
The dice are wrapped in a set of brackets to make the extent of the container clear, both to the reader and to the parser.
We may need to work on the syntax to make parsing easier, but that's what I'm using here.
Postfix notation ([dice]TN) is probably easier to parse, and solves one problem, but it's harder for the reader to follow.
Allowing either pre- or postfix, like we do for dice, is probably the best choice, if we ignore that it's the hardest to parse. (Extra complexity: unlike dice and skills, a container may have at most one type. (If you want multiple, just nest them))
Semantics:
A basic button is just a single container: [n(4) (8) (12) n(20) X] for instance. A basic container does nothing but add its contents to the active dice. The player has no decisions to make, so it's transparent to them. (The outermost container may or may not exist in practice; I'm assuming it does.)
Take N containers contain N or more dice. When opened, you choose N of the dice to add to the active dice.
T5[4 4 6 6 10 12 20 30]
T2[10 10 16 16]
A plasma die is a container that, when opened, gives the contained die or dice a set of skills. If there's a choice, the player chooses at opening time.
For instance:
{z,sp}[(20)] -- simple plasma die. Choose speed or shadow poison for your d20
{#,t}[4 20] -- two linked plasma dice. Choose the same skill for each.
{p, t, n}[16] -- three choices
{z}[6 8 10] -- no-choice plasma. All three dice are speed. There's not much reason to do this, but I see no reason to stop it.
You will note that the example plasma containers are not the full recipe. This is because containers are recursive: when you open a container, it opens any containers within itself.
{p,v}[{z,s}[(30)] {t,g}[(4)]] -- the 30 and 4 are both either poison or value.
This is not often going to be a thing, I admit.
Since recursive containers add additional hairiness and potentially arbitrary levels of player decision-making, we may not want to have them. One extant button may need them (see below). On the other hand, lack of them restricts things that ought to work, like plasma dice in Take N pools.
The sticking points:
Reserve: By all rights, reserve ought to be a container type: it works on the level of the recipe, it involves decisions made after losing a round. However, there are button specials in the Sailor Moon buttons (and perhaps Tenchi as well) that interact with reserve dice, and they'd probably be a lot harder to deal with if reserve were in the container paradigm. More importantly, we already have a working implementation of reserve as a die skill, and I'm not all that willing to fix what isn't broken just to have a cleaner implementation.
Auxiliary: Again, we have an implementation of Aux. However, it's got some issues and unsettled questions that pulling it into the container model might help sort out. It's a bit of a weird fit either way: it affects the recipe, but it's a start-of-game only decision, and it mucks with your opponent's recipe as well. My thought is to define under the hood that all buttons have an empty Auxiliary container in addition to the primary recipe container, and that if an Aux container is empty at game start, it auto-copies your opponent's Aux container. (There are still unresolved questions about multiple aux dice/containers.)
Gryphon: Or, more specifically, Gr(Y){p,h,o,n}. We already got him to change his fanatic recipe back when we decided braces were sufficient for plasma. Breaking it entirely would be rude. (And possibly extra awkward for me, since he's my brother.) This touches on both the nature of reserve and the structuring of container syntax. {G}[[r[(Y)]{p,h,o,n}]] is workable, but so, so, ugly. (Also, IIRC, the button has other reserves, but I don't have the recipe handy right now, so it may not be workable after all.) If reserve remains a die skill, it's not so bad at [Gr(Y)]{p,h,o,n} If we don't allow postfix notation, I don't see how to make it work at all.
The UI: getting the player to make multiple nested decisions about their button recipe is going to be a huge pain in the ass. (Storing the intermediate state likely also will be.) I think we're going to want some sort of generalized interface, since reinventing the wheel for plasma, select, etc, etc, will be worse. It ought to be possible (but not necessarily a good idea) to generate and send the decision tree all at once and let the front end present them with the necessary choices. (This avoids saving intermediate state and allows them to change their previous decisions, at the cost of being Way Hairier to write.)
(Also, in case it isn't obvious, a container has to open all its subcontainers before it does its thing. The question thus have to be asked from the innermost containers outward.)
Mood and Turbo: Someone will totally want to add mood or turbo to a container. It will not work well. (An extra attribute that makes the container choice random totally would, though, and I think there's even one button that needs it.)
Because apparently "think about BM infrastructure" is my brain's current idle loop.
This is a very high-level thought dump; I haven't looked at the actual implementation details this would have to interact with in ages, and remember nothing of what I may have seen. I'm a big fan of getting one's abstractions sorted early on, though.
Conceptually, containers are a unified framework for dealing with skills that work at the recipe level. The advantage of having a framework is that, in theory, it'll minimize the required tinkering with the game engine each time we add another one, and help keep their interactions well-behaved. The disadvantages are that it's a bigger pile of work at the front end, we already have two skills implemented that futz with recipes, and that while, in theory, there is no difference between theory and practice, in practice there usually is.
Anyway, the basic idea is that a button recipe consists of one or more containers. At the start of the game, and after each lost round, they are "opened", and add dice to the player's active dice, getting the player to make any necessary decisions in the process. (Or they open every round, but the decisions are locked in unless you've lost. This may be entirely theoretical, but I suspect it'll end up mattering.) The active dice are what you actually fight with.
Syntax:
A container is written as TN[dice], where T is the encoding of the container's type. (or skill, or power, but those terms are already in use. Of course, type may be a reserved word. We'll think of something.)
Most types are just going to be a letter. In theory, we can share with the skills. In practice, that's going to cause confusion. Plasma, however, is a list of comma-separated skills surrounded by braces.
N is an optional positive integer. Not all container types need this, but if we're generalizing hard enough, most of them can find a use. If it is not present, it is 1.
The dice are wrapped in a set of brackets to make the extent of the container clear, both to the reader and to the parser.
We may need to work on the syntax to make parsing easier, but that's what I'm using here.
Postfix notation ([dice]TN) is probably easier to parse, and solves one problem, but it's harder for the reader to follow.
Allowing either pre- or postfix, like we do for dice, is probably the best choice, if we ignore that it's the hardest to parse. (Extra complexity: unlike dice and skills, a container may have at most one type. (If you want multiple, just nest them))
Semantics:
A basic button is just a single container: [n(4) (8) (12) n(20) X] for instance. A basic container does nothing but add its contents to the active dice. The player has no decisions to make, so it's transparent to them. (The outermost container may or may not exist in practice; I'm assuming it does.)
Take N containers contain N or more dice. When opened, you choose N of the dice to add to the active dice. T5[4 4 6 6 10 12 20 30] T2[10 10 16 16]
A plasma die is a container that, when opened, gives the contained die or dice a set of skills. If there's a choice, the player chooses at opening time.
For instance: {z,sp}[(20)] -- simple plasma die. Choose speed or shadow poison for your d20
{#,t}[4 20] -- two linked plasma dice. Choose the same skill for each.
{p, t, n}[16] -- three choices
{z}[6 8 10] -- no-choice plasma. All three dice are speed. There's not much reason to do this, but I see no reason to stop it.
You will note that the example plasma containers are not the full recipe. This is because containers are recursive: when you open a container, it opens any containers within itself.
{p,v}[{z,s}[(30)] {t,g}[(4)]] -- the 30 and 4 are both either poison or value.
This is not often going to be a thing, I admit.
Since recursive containers add additional hairiness and potentially arbitrary levels of player decision-making, we may not want to have them. One extant button may need them (see below). On the other hand, lack of them restricts things that ought to work, like plasma dice in Take N pools.
The sticking points:
Reserve: By all rights, reserve ought to be a container type: it works on the level of the recipe, it involves decisions made after losing a round. However, there are button specials in the Sailor Moon buttons (and perhaps Tenchi as well) that interact with reserve dice, and they'd probably be a lot harder to deal with if reserve were in the container paradigm. More importantly, we already have a working implementation of reserve as a die skill, and I'm not all that willing to fix what isn't broken just to have a cleaner implementation.
Auxiliary: Again, we have an implementation of Aux. However, it's got some issues and unsettled questions that pulling it into the container model might help sort out. It's a bit of a weird fit either way: it affects the recipe, but it's a start-of-game only decision, and it mucks with your opponent's recipe as well. My thought is to define under the hood that all buttons have an empty Auxiliary container in addition to the primary recipe container, and that if an Aux container is empty at game start, it auto-copies your opponent's Aux container. (There are still unresolved questions about multiple aux dice/containers.)
Gryphon: Or, more specifically, Gr(Y){p,h,o,n}. We already got him to change his fanatic recipe back when we decided braces were sufficient for plasma. Breaking it entirely would be rude. (And possibly extra awkward for me, since he's my brother.) This touches on both the nature of reserve and the structuring of container syntax. {G}[[r[(Y)]{p,h,o,n}]] is workable, but so, so, ugly. (Also, IIRC, the button has other reserves, but I don't have the recipe handy right now, so it may not be workable after all.) If reserve remains a die skill, it's not so bad at [Gr(Y)]{p,h,o,n} If we don't allow postfix notation, I don't see how to make it work at all.
The UI: getting the player to make multiple nested decisions about their button recipe is going to be a huge pain in the ass. (Storing the intermediate state likely also will be.) I think we're going to want some sort of generalized interface, since reinventing the wheel for plasma, select, etc, etc, will be worse. It ought to be possible (but not necessarily a good idea) to generate and send the decision tree all at once and let the front end present them with the necessary choices. (This avoids saving intermediate state and allows them to change their previous decisions, at the cost of being Way Hairier to write.)
(Also, in case it isn't obvious, a container has to open all its subcontainers before it does its thing. The question thus have to be asked from the innermost containers outward.)