This is a pure banger feature, one of the best usability improvements of the new Castagne. State Calls were a huge feature in the previous version, and you could use it to create behavior either by extending a state or through composition. Interally both were the same, but I added warnings and _Helper() to distinguish between the two. You could alter internal defines, but it was a bit janky.
First off, there’s a new syntax for state names, which immediately distinguishes between the two: StateName is a regular state, while StateName() is a helper state. Both can be called without issues by using !StateName (equivalent to Call(StateName) in the old version), that part doesn’t change. What is new is that you can now add parameters to that, which are treated as local variables! Here’s a long snippet showcasing the new abilities:
:HelperState(var X int(), var Y bool() = true):
# You have access to both X and Y here.
# A is a local variable that you can't set from the outside.
var A int() = 10
V Y:
Add(A, X)
!OtherHelper(A)
endif
:OtherHelper(var Z int = 5):
# This has only got access to Z, even when called from HelperState.
# These are copies, so even if called through !OtherHelper(X), it can't change X
# You can call parent with arguments too
!!(10)
:RegularState:
# You can specify parameters with or without defaults
!HelperState(5)
!HelperState(5, false)
# If there are no parameters, these are equivalent
!OtherHelper
!OtherHelper()
# Hooks also work! The parameter list will resolve when needed.
!SuperState?(10, true)
So now you’re either super hype or super confused. This is a core feature of the engine that allows many mechanics and tools to be made inside of CASP in an efficient manner. Let me illustrate the difference with the old Castagne with some examples:
!AirStep(5000) to make the behavior easily readable and contained!!OnLevelUp?. Compared to before, you don’t need to create the state immediately, it will only be used in the characters that want it.!IMPACT or !IMPACT(120) can now take care of everything!!TransitionIfHeld(M, 6, OverdriveMove) to automatically handle moving to OverdriveMove if M is held for the first 6 frames? Easy QoL on something that’s a bit too niche for the modules!FlagCarryover(F) for example, it’s just FlagNext(F) in an L branch. You could make functions like that for your own use in minutes! It’s not as optimized, but that’s easily done later, and you can get started with it faster.This is already super useful, but when you’ll combine it with the upcoming MechMods (!!? is specifically superb in this context, as it allows needed modularity) and Varspec (which can understand when it’s seen from a state call), it will be incredible. These three features are the ones that will bring the editor to a new level and I can’t wait for that!
Slight design musings to finish, since this post is already super long:
Transition(CoolState(500)) or something, but I think it would be a bit overkill in complexity and we can hold variables in memory for that. Maybe I could add a variable tag for that.var X int is valid. The variable tags are optional (the () in int(), which isn’t used for anything right now nor was it before, always a planned feature), and you don’t need to specify a default. In fact, some variable types don’t accept defaults, such as state or flag (semantic types in general), but you may use them in state calls.AttackParam internally. I don’t think this would be for the best however, as it would complexify the docs and make it more confusing to follow. Allowing the ! to become optional would fix that but introduce confusion instead. Making them as CASP functions would allow overriding module functions, which is another can of worms. I’m probably going to introduce module functions as macros to implement that.What’s next is a bit tricky to choose, but I think I’ll start working on the modules again. Logically, I won’t be actually able to implement the MechMods without having something to put in them! Varspec will probably be the very last core feature to be added, since it’s so dependant on the rest.