A downloadable tool

Get this tool and 3 more for $17.99 USD
View bundle
Buy Now$11.99 USD or more

Make your stats react!

At some point you decide your game needs modifiable stats. Move speed, attack damage, jump height, whatever. And at first it's fine, you just have a variable and you add to it.

Then you need a buff that lasts five seconds. So you add a timer. Then you need another buff that lasts 10 seconds. So you start to build out a whole timer system. Then you need a debuff that shouldn't stack with another debuff of the same type. So now you have a flag. Then someone asks for a gear comparison screen. And suddenly you're staring at a pile of variables and conditionals that are a buggy, hard to extend, make further development painful rather than fun and limit your ideas to things your half-built system can easily handle. I've been through that enough times that I got fed up and built Catalyst instead.

Catalyst lets you: 

Write clean modifiers with add, multiply, conditional, timed, stacking...all handled with a single line of code easily.

Scale safely with layers, families, derived bases, post-processing, tags for bulk removal, on-change callbacks.

Preview freely, see what a modifier would do before applying it, without touching the stat.


Get the Ignition Kit bundle, featuring Pulse, Catalyst AND Statement for a discount!

Or get the Full Suite Pass bundle to get all current and future tools for one low price (price will increase each time a new tool launches, so get in early for substantial savings!)

A purchase of Catalyst gives you a copy of Echo free!


The core pattern

hp_max = new CatalystStatistic(50).SetName("HP Max");
var _mod = new CatalystModifier(3, eCatMathOps.ADD);
hp_max.AddModifier(_mod);
var _hp_max = hp_max.GetValue(); // 53

That's it at its simplest. Create a stat, attach a modifier, get the value. Catalyst handles the evaluation and returns the correct number. And that alone will save you time. But it's what's underneath that makes it worth using on a real project.


Key features

Catalyst has two math operations: ADD and MULTIPLY. ADD modifiers sum together before MULTIPLY modifiers compound, so two +50% multipliers give you 125% rather than 100% or 225% depending on which mistake you would have made. FORCE_MIN and FORCE_MAX sit at the end of the evaluation pipeline and set hard floors or ceilings after everything else has been applied.

Five built-in evaluation layers (BASE_BONUS, EQUIPMENT, AUGMENTS, TEMP, GLOBAL) control when each modifier runs relative to the others, so base bonuses apply before gear bonuses before buffs without you managing the ordering manually. Timed modifiers pass a duration in ticks and self-remove when they expire, driven by a single CatalystModCountdown() call in your controller step, no per-object timers needed.

The family system lets you group modifiers under a key and pick a stacking mode: HIGHEST applies only the strongest modifier in that family, LOWEST applies only the weakest, STACK_ALL applies them all normally. "Only the best sprint buff counts" or "only the worst slow stacks through" is one line of setup rather than bespoke de-duplication logic every time.

PreviewChange and PreviewChanges evaluate a stat with hypothetical extra modifiers included without mutating anything, so gear comparison screens and talent previews are a single non-destructive call. SetBaseFunc makes a stat's base value a computed formula that recalculates automatically whenever its inputs change. SetPostProcess runs after all modifiers and clamping for anything that needs to happen last, like soft caps or unusual rounding.

Modifiers can be tagged with arbitrary strings, so "remove all debuffs" is one call to RemoveModifiersByTag("debuff"). Source labels and source IDs let you find and remove modifiers by where they came from, which is useful when an ability or item needs to clean up after itself without you holding a reference to every modifier it applied. On-change callbacks fire when the cached value changes and only on context-free calls, so previews don't trigger them by accident. DebugDescribe() logs the full state of a stat and every attached modifier without mutating anything.


Conditional modifiers: making stats react dynamically

Probably the most interesting part of Catalyst is the conditional modifier system. Any modifier can have a condition attached. The condition is evaluated every time the stat's value is requested with a context provided, and the modifier only applies if it returns true. You pass a context struct into GetValue() and the condition reads whatever it needs from that context.

// +50% damage, but only against frozen targets
var _mod = new CatalystModifier(0.5, eCatMathOps.MULTIPLY);
_mod.SetCondition(function(_stat, _ctx) {
    return _ctx[$ "target_is_frozen"];
});
attack_damage.AddModifier(_mod);

"+30% damage to burning enemies", "extra move speed when below 25% health", "bonus armor only while standing still" -- all of these are just one modifier with a condition. No flags, no separate handling, no updating anything when game state changes. You ask for the value with the current context, you get the right answer.

Stack counts can also be driven by context. SetStackFunc computes the effective stack count from the context at evaluation time, so "move speed +5% per burning enemy nearby" is a single modifier that scales automatically with the game state, no counters to maintain.


Why you need Catalyst

Because at some point, every game with any kind of progression ends up needing modifiable stats. You start with a move speed variable and some simple additions. Two weeks later you have if (has_boots && !is_slowed && sprint_timer > 0 && fire_debuff_stacks < 3) scattered across six different objects, and a bug that only happens when the player gets the potion, equips the ring, and then gets hit by the exact enemy type that resets the sprint timer. Catalyst is here to stop that.


Echo debug logger included

Catalyst includes Echo, a lightweight debug logging framework and debug UI builder for GameMaker, entirely for free. Level based logs, tag filters, optional stack traces, rolling history with file dump. You don't need to buy Echo separately if you own Catalyst.


Documentation

Full online documentation including a complete API reference, quickstart guide, and common patterns ready to drop into your project.

Catalyst Documentation


Requirements

GameMaker 2.3 or later (structs and methods required).

Echo requires 2024.8+ (uses gpu_set_scissor()).


Support and feedback

If you run into issues or have ideas for improvements:


Part of the RefresherTowel Games Toolkits

Part of a growing suite of GameMaker tools designed to play nicely together. If you like this style of tooling, you might also want:

  • Whisper - make your narrative dynamic and reactive, like Hades or Crusader Kings III.
  • Pulse - a signals and events framework (supporting queries that allow you to ask questions instead of just broadcast signals!)
  • Statement - a state machine framework (with a fully visual in-game debugger).
  • Quill - a FREE text box creator that automatically gives you advanced features like a right click context menu, proper text selection, multi-line text boxes, plus more!
  • Fate - a FREE weighted drop system with an easy to use beginner setup, but with a huge amount of advanced features hiding in the weeds.
  • Echo - advanced debug logging (level filtering, tags, optional stack traces, history dumps) that now comes with an advanced, yet easy to use debug UI builder!

Get Pulse, Catalyst, Statement and Echo in the Ignition Kit bundle for a discount! Or buy the Full Suite Pass bundle (get access to all past and future tools) in one go!

Purchase

Get this tool and 3 more for $17.99 USD
View bundle
Buy Now$11.99 USD or more

In order to download this tool you must purchase it at or above the minimum price of $11.99 USD. You will get access to the following files:

Catalyst v1.0.0 401 kB
Catalyst v1.1.0 494 kB

Development log

Leave a comment

Log in with itch.io to leave a comment.