diff --git a/_posts/2024-02-29-creating-the-perfect-modding-language.md b/_posts/2024-02-29-creating-the-perfect-modding-language.md
index 0a449a5..275e926 100644
--- a/_posts/2024-02-29-creating-the-perfect-modding-language.md
+++ b/_posts/2024-02-29-creating-the-perfect-modding-language.md
@@ -157,6 +157,8 @@ helper_spawn_sparkles() {
The `helper_spawn_sparkles` function is a helper function, which the game can't call, but the `on_` functions in this file can.
+For a full example, I recommend downloading/cloning the [grug terminal game repository](https://github.com/MyNameIsTrez/grug-terminal-game) locally, so you can step through the code of the game and grug.c with a debugger.
+
## The game can allow grug entities to edit each other's data
The game could be responsible for giving every entity a map (think hash maps/Lua tables/JavaScript objects/Python dictionaries), where mods can then read from and write to each other's maps:
@@ -230,157 +232,6 @@ There are three test categories:
A fuzzer is basically a neural network that generates a random string, throws it into the fuzzed program, and gets a reward if it walked a new path through the fuzzed program's code. If it got a reward, it uses the knowledge that there is a good chance it'll get more rewards if it tries similar strings. In this manner it quickly finds most possible paths through the fuzzed program's code, also finding a few inputs that crashed `grug.c`, which I of course patched.
-## How a game developer might use grug
-
-The below snippets are based on the [grug terminal game repository](https://github.com/MyNameIsTrez/grug-terminal-game), so if anything confuses you, feel free to check out the full program.
-
-Games typically have an update loop, so by calling `grug_regenerate_modified_mods()` in there you can tell grug to recompile any modified mods, where the function returns `true` if there was an error:
-
-```bettercpp
-int main() {
- while (true) {
- if (grug_regenerate_modified_mods()) {
- if (grug_error.has_changed) {
- printf(
- "%s:%d: %s (detected in grug.c:%d)\n",
- grug_error.path,
- grug_error.line_number,
- grug_error.msg,
- grug_error.grug_c_line_number
- );
- }
- continue;
- }
-
- if (grug_mod_had_runtime_error()) {
- fprintf(stderr, "Runtime error: %s\n", grug_get_runtime_error_reason());
- fprintf(
- stderr,
- "Error occurred when the game called %s(), from %s\n",
- grug_on_fn_name,
- grug_on_fn_path
- );
- continue;
- }
-
- static bool initialized = false;
- if (!initialized) {
- initialized = true;
- init();
- }
-
- reload_modified_entities();
-
- // Since this is a terminal game, there are no PNGs/MP3s/etc.
- // reload_modified_resources();
-
- update();
- }
-}
-```
-
-The call to `reload_modified_entities()` in the main function loops over all regenerated mods, reinitializing the tool's globals and using the new `on_` fns:
-
-```bettercpp
-void reload_modified_entities() {
- // For every reloaded grug file
- for (size_t reload_idx = 0; reload_idx < grug_reloads_size; reload_idx++) {
- struct grug_modified reload = grug_reloads[reload_idx];
-
- // For the player and opponent tools
- for (size_t i = 0; i < 2; i++) {
-
- // If the reloaded grug file has the same tool type
- if (reload.old_dll == data.tool_dlls[i]) {
- data.tool_dlls[i] = reload.new_dll;
-
- // Reinitialize the tool's globals
- free(data.tool_globals[i]);
- data.tool_globals[i] = malloc(reload.globals_size);
- reload.init_globals_fn(data.tool_globals[i]);
-
- // Use the new on fns
- data.tools[i].on_fns = reload.on_fns;
- }
- }
- }
-}
-```
-
-The call to `init()` in the main function gives the player tool 0, and the opponent tool 1 from the `mods/` directory:
-
-```bettercpp
-void init() {
- pick_tool(0, PLAYER_INDEX);
- pick_tool(1, OPPONENT_INDEX);
-}
-
-void pick_tool(size_t chosen_tool_index, size_t human_index) {
- struct grug_file *tool_files = get_type_files("tool");
-
- struct grug_file file = tool_files[chosen_tool_index];
-
- // This calls the grug file's define fn, which calls our game_fn_define_tool()
- file.define_fn();
-
- // The previous file.define_fn() line caused tool_definition to be filled
- tool tool = tool_definition;
-
- tool.on_fns = file.on_fns;
-
- data.tools[human_index] = tool;
- data.tool_dlls[human_index] = file.dll;
-
- // Initialize the tool's globals
- free(data.tool_globals[human_index]);
- data.tool_globals[human_index] = malloc(file.globals_size);
- file.init_globals_fn(data.tool_globals[human_index]);
-}
-
-struct tool tool_definition;
-
-// This gets called by the define() function in grug mods
-void game_fn_define_tool(string name, i32 damage) {
- tool_definition = (struct tool){
- .name = name,
- .damage = damage,
- };
-}
-```
-
-Finally, the call to `update()` in the main function is the gameplay logic. The most important line is `use(player_tool_globals, PLAYER_INDEX);`, which calls the tool's `on_use()` grug function:
-
-```bettercpp
-void update() {
- void *player_tool_globals = data.tool_globals[PLAYER_INDEX];
- void *opponent_tool_globals = data.tool_globals[OPPONENT_INDEX];
-
- tool *player_tool = &data.tools[PLAYER_INDEX];
- tool *opponent_tool = &data.tools[OPPONENT_INDEX];
-
- printf("You have %d health\n", player->health);
- printf("The opponent has %d health\n\n", opponent->health);
-
- printf("You use your %s against your opponent\n", player_tool->name);
- typeof(on_tool_use) *use = player_tool->on_fns->use;
- use(player_tool_globals, PLAYER_INDEX);
-
- if (opponent->health <= 0) {
- printf("The opponent died!\n");
- exit(0);
- }
-
- printf("The opponent uses their %s against the player\n", opponent_tool->name);
- use = opponent_tool->on_fns->use;
- use(opponent_tool_globals, OPPONENT_INDEX);
-
- if (player->health <= 0) {
- printf("You died!\n");
- exit(0);
- }
-}
-```
-
## Why grug
Like any good programming language, grug was born from frustration. Specifically, over 4 years of frustration keeping the configuration and Lua files of nearly 200 old Cortex Command mods up-to-date with the game.