Skip to content

Courage.Save#

require("Courage.Save") has functions to check, load, modify, and save progress in the active save file.

Event flags and variables are on the Flags and Variables tabs of the TP Ultimate Spreadsheet. Item pickup functions are on the Functions tab.

API#

Function Returns Description
Save.has_active_save() boolean Returns true if there is a save file loaded and active.
Save.file_no() number Returns the active save file index (such as 1, 2, or 3).
Save.file_name() string Returns the absolute path of the active save file on disk.
Save.get_stage(stageNo) (none) Load the save data for stage number stageNo into memory.
Save.put_stage(stageNo) (none) Commit stage number stageNo changes back to the save data buffer.
Save.event_bits() lightuserdata? Pointer to the active event flags byte array.
Save.grant_item(itemId) (none) Grant itemId using standard item-get logic.
Save.item_resource(itemId) table? Returns visual resource table for itemId, or nil if invalid.
Save.equip_clothes(itemId) (none) Set the equipped tunic/clothes item.
Save.equip_shield(itemId) (none) Set the equipped shield item.
Save.set_event_bit(flag) (none) Set a single event flag by its u16 value.
Save.set_transform_level(level) (none) Set the wolf-transform tier (0-7). Level 3 makes Midna appear in her true form.
Save.set_boot_stage(stage, point, room, layer?) (none) Override the stage the next boot loads into. Consumed once.
Save.is_dungeon_boss_cleared(levelIndex) boolean Returns true if the dungeon boss for the given level index (0-8) has been cleared.
Save.clear_dungeon_boss_cleared(levelIndex) (none) Clears the dungeon boss cleared flag for the given level index (0-8).

Resource table fields#

Save.item_resource returns a table with these fields:

  • arc: Archive filename string.
  • bmd: BMD resource name string.
  • btk: BTK resource name string.
  • bpk: BPK resource name string.
  • bck: BCK resource name string.
  • bxa: BXA resource name string.
  • brk: BRK resource name string.
  • btp: BTP resource name string.

Examples#

Check and grant items#

This example grants an item using the standard game item-get logic.

local Save = require("Courage.Save")

if Save.has_active_save() then
    -- Grant an item by ID
    Save.grant_item(itemId)
end
import * as Save from "Courage.Save"

if (Save.has_active_save()) {
    // Grant an item by ID
    Save.grant_item(itemId)
}

Write event bits directly#

Using Augment.Mixin to read and write event flags at specific offsets.

local Save = require("Courage.Save")
local Mixin = require("Augment.Mixin")

local function getEventBit(offset, flag)
    local base = Save.event_bits()
    if not base then return false end
    local byte = Mixin.read(base, offset, "u8")
    return bit32.band(byte, flag) ~= 0
end

local function setEventBit(offset, flag)
    local base = Save.event_bits()
    if not base then return end
    local byte = Mixin.read(base, offset, "u8")
    Mixin.write(base, offset, "u8", bit32.bor(byte, flag))
end
import * as Save from "Courage.Save"
import * as Mixin from "Augment.Mixin"

function getEventBit(offset: number, flag: number): boolean {
    const base = Save.event_bits()
    if (!base) return false
    const byte = Mixin.read(base, offset, "u8") as number
    return (byte & flag) !== 0
}

function setEventBit(offset: number, flag: number): void {
    const base = Save.event_bits()
    if (!base) return
    const byte = Mixin.read(base, offset, "u8") as number
    Mixin.write(base, offset, "u8", byte | flag)
}

Set a single event flag by value#

set_event_bit calls dComIfGs_onEventBit directly with the flag value from the spreadsheet.

local Save = require("Courage.Save")

-- Set an event flag by value from spreadsheet
Save.set_event_bit(flagValue)
import * as Save from "Courage.Save"

Save.set_event_bit(flagValue)

Equip tunic and shield#

local Save = require("Courage.Save")

Save.equip_clothes(clothesItemId)
Save.equip_shield(shieldItemId)
import * as Save from "Courage.Save"

Save.equip_clothes(clothesItemId)
Save.equip_shield(shieldItemId)

Override the boot stage#

set_boot_stage is consumed once by the next Load boot.

local Save = require("Courage.Save")

-- Next boot starts at Hyrule Castle Town (spawn 0)
Save.set_boot_stage("D_MN09", 0, 0, 0)
import * as Save from "Courage.Save"

Save.set_boot_stage("D_MN09", 0, 0, 0)

Dungeon boss clear state#

levelIndex maps 0 = Forest Temple, 1 = Goron Mines, 2 = Lakebed Temple, 3 = Arbiter's Grounds, 4 = Snowpeak Ruins, 5 = Temple of Time, 6 = City in the Sky.

local Save = require("Courage.Save")

-- Check if Forest Temple boss (Diababa) was cleared
if Save.is_dungeon_boss_cleared(0) then
    print("Diababa cleared")
end

-- Reset it
Save.clear_dungeon_boss_cleared(0)
import * as Save from "Courage.Save"

if (Save.is_dungeon_boss_cleared(0)) {
    console.log("Diababa cleared")
}
Save.clear_dungeon_boss_cleared(0)

Midna true form / transform level#

set_transform_level(3) is the value that enables Midna's true form appearance.

local Save = require("Courage.Save")

Save.set_transform_level(3) -- Midna true form
import * as Save from "Courage.Save"

Save.set_transform_level(3)