DinkC Reference

website·Indexed 31 days ago

https://dinkcreference.netlify.app/

A comprehensive reference for DinkC scripting functions used in Dink, Freedink, DinkHD, and YeDink. Includes documentation for sprite manipulation (sp_x, sp_y, sp_seq), dialogue systems (say_xy, say_stop_npc), and game state controls.

Tokens
46K
Snippets
290
Records
332
Agent score
75%

What's inside DinkC

  1. Overview of DinkC scripting language

    DinkC is the scripting language used to create D-Mods and add-ons for Dink Smallwood. It is designed to be accessible to those with experience in scripted or compiled languages like BASIC or Pascal, and does not require knowledge of C. The language is highly versatile, allowing for a wide range of custom behaviors within the game engine.
  2. Overview of the DinkC scripting language

    DinkC is a procedural scripting language used to power game-related logic in Dink Smallwood, including conversations, cutscenes, and enemy behavior. Its syntax superficially resembles C/C++. Key features include:

    • Support for procedural structure.
    • Local and global dynamic variable creation with custom names (global variables are automatically saved with the player data file).
    • The ability to attach scripts to objects, persons, monsters, or screens.
  3. Create a Caster enemy

    Casters are enemies that randomly cast spells or perform actions. This is typically implemented using set_callback_random() to trigger a custom function at random intervals. For advanced casters (like dragons), setting sp_brain() to 10 causes the enemy to call its attack procedures randomly based on sp_attack_wait(), regardless of whether a target is in range.
    // magicpil.c
    void main(void)
    {
        sp_base_walk(&current_sprite, 130);
        sp_speed(&current_sprite, 1);
        sp_brain(&current_sprite, 9);
        sp_touch_damage(&current_sprite, 4);
        sp_hitpoints(&current_sprite, 10);
        sp_exp(&current_sprite, 5);
    
        sp_target(&current_sprite, 1);
    
        // Call "harm" function randomly every 1 to 3 seconds
        set_callback_random("harm", 1000, 2000);
    }
    
    void harm(void)
    {
        say("`%<Casts Harm>", &current_sprite);
        hurt(1, 2);
    }
  4. Make a sprite follow another sprite using sp_follow

    The sp_follow(active_sprite, target_active_sprite) function causes the active_sprite to move toward the target_active_sprite until it is within 40 pixels. The following constraints apply:

    • Brain Requirements: The function only affects sprites with a sp_brain() value of 0, 3, 5, 7, 9, 10, or 16.
    • Speed Requirements: The sprite must have a sp_speed() value greater than 0.
    • Movement: The sprite moves toward the target but cannot maneuver around obstacles.
    • Diagonal Movement: By default, sprites move in cardinal directions (up, down, left, right). If set_smooth_follow() is set to 1, the sprite will also use diagonal movement.
    • Version Note: In version 1.07, set_smooth_follow() is unavailable, and sprites only move in cardinal directions.
    int sp_follow(int active_sprite, int target_active_sprite);
  5. Call other scripts using external() and spawn()

    Scripts can trigger the execution of other scripts using two different methods:

    1. external(): Synchronous call. The caller script pauses and waits for the called script to finish before continuing.
    2. spawn(): Asynchronous call. Creates a new script instance that runs independently. Spawned scripts persist until they are explicitly terminated using kill_this_task().
    // Example of external() - Caller waits
    void main(void)
    {
        external("grocery", "main");
        // This line runs only after grocery.c finishes
    }
    
    // Example of spawn() - Spawner continues immediately
    void main(void)
    {
        spawn("grocery");
        // Spawner continues while grocery.c runs in parallel
        kill_this_task();
    }
  6. Create loops using goto

    Since DinkC lacks while or for loops, loops are created by placing a label before a block of code and using goto to jump back to that label based on a condition.

    Warning: Infinite loops without a pause will freeze the game. To prevent this, include a wait() statement within the loop to allow other game events and player input to process.

    void talk(void)
    {
        freeze(1);
        int &counter = 0;
    
        loop:
        say_stop("I'm going to say this 10 times!", 1);
        &counter += 1;
        if (&counter < 10)
        {
            goto loop;
        }
        
        // Example of a non-freezing infinite loop
        // loop_forever:
        // say("I won't freeze the game!", 1);
        // wait(100);
        // goto loop_forever;
    
        say_stop("Whew, glad I'm done with that!", 1);
        unfreeze(1);
    }
  7. Create and call custom procedures

    Custom procedures allow you to organize code into reusable blocks. Unlike predefined procedures, they are not called by the engine and must be invoked manually. You can call a custom procedure within the same script or from an external script using the external() function.
    // Example 1: Calling a procedure in the same script
    void main(void)
    {
        say_banana();
    }
    
    void say_banana(void)
    {
        say("Banana!", 1);
    }
    
    // Example 2: Calling a procedure in a different script
    // In banana2.c
    void main(void)
    {
        external("bananax", "say_banana");
    }
    
    // In bananax.c
    void say_banana(void)
    {
        say("Banana!", 1);
    }
  8. Implement a plot system using global state variables

    To create a plot or quest in a D-Mod, use a global integer variable to track the current state of the story. This allows characters to respond differently based on the player's progress. Initialize the variable in main.c using make_global_int and update its value as the player completes specific goals.
    // excerpt from main.c
    void main(void)
    {
        // Initialize story state
        make_global_int("&story", 0);
        // 0 – Nothing happened
        // 1 – Person 1 asked Dink to tell Person 2 to shut up
        // 2 – Dink told Person 2 to shut up
        // 3 – Dink rewarded by Person 1
    }
  9. Implement item and magic script lifecycles

    Item and magic behavior is controlled via scripts. The engine calls specific procedures based on the item's state. To give a player an item, use add_item() or add_magic().

    Procedure Lifecycle:

    1. pickup(): Called immediately after add_item() or add_magic(). Use this for effects that trigger simply by possessing the item.
    2. arm(): Called when the player arms the item. Use this to modify player stats (e.g., increasing strength) or change attack animations.
    3. armmovie(): Called when the player manually arms the weapon (not called if arm_weapon() is used). Use this for dialogue or visual cues.
    4. disarm(): Called when the item is disarmed. You must include kill_this_task() at the end of this procedure to ensure the script terminates.

    Special Case: Loading Games When load_game() is called, the engine runs disarm() followed by arm() for the currently equipped weapon and magic. armmovie() is not executed during a game load.

  10. Perform jumps using goto and labels

    DinkC supports jumping to different parts of a script using the goto statement. This is the primary way to implement complex logic (like OR conditions) since standard logical operators are not supported.

    To use a jump:

    1. Define a label in the script by writing a name followed by a colon (e.g., healthy:).
    2. Use goto labelname; to immediately move execution to that label.
    void talk(void)
    {
        if (&life == &lifemax)
        {
            goto healthy;
        }
    
        if (&strength > 10)
        {
            goto healthy;
        }
    
        say_stop("I'm not feeling so good, Jack.", 1);
        goto done;
    
        healthy:
        say_stop("I'm healthy as a horse!", 1);
    
        done:
        say_stop("I will say this no matter what.", 1);
    }
  11. Display a BMP image over the screen background using copy_bmp_to_screen

    The copy_bmp_to_screen(string bmpfile) function copies a specified BMP image onto the screen, covering the background area (including the status bar and tiles). Sprites remain visible and function normally.

    Requirements and Constraints:

    • Resolution: The BMP must be exactly 640px x 480px.
    • Palette: The image should use the current palette unless the game is running in true-color mode. If a different palette is used in non-true-color mode, the game will switch to that palette (similar to load_palette).
    • Removal: Calling draw_background will remove the BMP and revert the screen to the original tiles.

    Caveats:

    • In the original Dink engine, loading a save file after a palette change via this function causes tiles to revert to the Dink palette, while sprites retain the new palette. Subsequent palette changes may not take effect.
    void main(void)
    {
        // Copies "tester.bmp" from the tiles folder to the screen
        copy_bmp_to_screen("tiles/tester.bmp");
    }
  12. Create a Toucher enemy

    Touchers are basic enemies that harm the player only upon physical contact. They typically use a sp_brain() value of 9 to ensure constant movement. Key configuration functions include sp_touch_damage() for contact damage, sp_hitpoints() for health, and sp_exp() for experience granted upon death.
    // pillbug.c
    void main(void)
    {
        sp_base_walk(&current_sprite, 130);
        sp_speed(&current_sprite, 1);
        sp_brain(&current_sprite, 9);
    
        // Harm Dink for at most 4 hitpoints on touch
        sp_touch_damage(&current_sprite, 4);
    
        // Die after 10 hitpoints of damage
        sp_hitpoints(&current_sprite, 10);
    
        // Give Dink 5 experience points
        sp_exp(&current_sprite, 5);
    }
    
    void die(void)
    {
        // Respawn in 5 minutes
        int &editor_sprite = sp_editor_num(&current_sprite);
        if (&editor_sprite != 0)
            editor_type(&editor_sprite, 6);
    
        // Randomly create a small powerup using emake.c
        &save_x = sp_x(&current_sprite, -1);
        &save_y = sp_y(&current_sprite, -1);
        external("emake","small");
    }