Skip to content

Augment.Class#

Augment.Class subclasses C++ actor types from Luau.

Loading#

local Class = require("Augment.Class")
import * as Class from "Augment.Class"

API#

Class.extend(baseType, name, proc) -> SubclassHandle#

Creates a new subclass that inherits from a C++ base type.

Parameter Type Description
baseType string C++ base type name (such as "daCow_c")
name string Name of the subclass
proc string | number Enum name from ProcName or a number representing the actor profile

Returns a subclass handle.

Spawning instances#

SubclassHandle.new(x, y, z, room?, params?) -> NativePtr#

Spawns a new instance of this subclass in the world.

Parameter Type Description
x, y, z number Spawn coordinates
room number? Room number (defaults to -1)
params number? Spawn parameters (defaults to 0)

Returns the raw pointer to the spawned actor.


Defining Methods#

Define methods on the subclass by assigning functions directly to the subclass handle.

Lifecycle Slots#

Standard lifecycle methods map to specific engine slots:

  • Create
  • Execute
  • Draw
  • Delete
  • IsDelete
local MyNpc = Class.extend("d_a_npc_yg", "MyNpc", "PROC_NPC_YG")

function MyNpc:Create()
    -- Called after the base class Create returns COMPLETE
end

function MyNpc:Execute()
    -- Called during actor execution
    -- Return true/1 or false/0 to control return status
end
const MyNpc = Class.extend("d_a_npc_yg", "MyNpc", "PROC_NPC_YG")

MyNpc.Create = function (self)
    -- Called after the base class Create returns COMPLETE
end

MyNpc.Execute = function (self)
    -- Called during actor execution
    -- Return true/1 or false/0 to control return status
end

If a lifecycle method is defined, it runs when the slot is executed. - Create automatically runs the base class initialization first. If the base class does not return COMPLETE (value 4), execution of the subclass Create is deferred. - Other methods replace the base implementation. Return values are converted to integers (returning true or a number greater than 0 resolves to 1).

Custom Methods#

Assigning a function name that does not match a lifecycle slot automatically registers it as an after hook on the C++ base class method (BaseType::MethodName). This hook only runs on instances of this specific subclass.

function MyNpc:talk()
    -- Automatically registered as an after hook for d_a_npc_yg::talk
    -- Only runs when talk is called on instances of MyNpc
end
MyNpc.talk = function (self)
    -- Automatically registered as an after hook for d_a_npc_yg::talk
    -- Only runs when talk is called on instances of MyNpc
end

The self Instance#

Inside subclass methods, the first parameter (self) acts as a proxy to the C++ actor instance:

  • self.__ptr returns the raw actor pointer.
  • Reads and writes to standard C++ fields of the base type are forwarded to the C++ struct view.
  • Non-C++ fields can be read and written directly on self to store custom state variables in Luau.
  • Call base class lifecycle methods using self.super_<Slot> (where <Slot> is one of Create, Execute, Draw, Delete, or IsDelete).
local CustomLink = Class.extend("daAlink_c", "CustomLink", "PROC_PLAYER")

function CustomLink:Execute()
    -- Read a C++ field from the base class
    local pos = self.position

    -- Store custom Luau state
    if not self.my_timer then
        self.my_timer = 100
    end

    -- Call base class method
    self.super_Execute()
end
const CustomLink = Class.extend("daAlink_c", "CustomLink", "PROC_PLAYER")

CustomLink.Execute = function (self)
    // Read a C++ field from the base class
    const pos = self.position

    // Store custom Luau state
    if (!self.my_timer) {
        self.my_timer = 100
    }

    // Call base class method
    self.super_Execute()
end

Full Example#

This mod defines a custom subclass of daCow_c that scales cows up to eight times their normal size. Pressing the P key spawns a giant cow above the player.

local Class  = require("Augment.Class")
local Player = require("Courage.Player")
local Mixin  = require("Augment.Mixin")

local SCALE = 8.0
local KEY_P = 19

local BigCow = Class.extend("daCow_c", "BigCow", "PROC_COW")

function BigCow:Execute()
    self:super_Execute()
    self.scale.x = SCALE
    self.scale.y = SCALE
    self.scale.z = SCALE
end

print("[bigcow] BigCow class registered")

local Mod = mod("bigcow")

local prevSc  = 0
local pending = false

function Mod:init()
    self:after("crInput_setLastScancode", function(ctx)
        local sc = Mixin.arg(0, "i32")
        if sc == KEY_P and prevSc ~= KEY_P then pending = true end
        prevSc = sc
    end)
    print("[bigcow] loaded - press P in-game to spawn a giant cow")
end

function Mod:tick()
    if not pending then return end
    pending = false
    local x, y, z = Player.get_position()
    if x == 0 and y == 0 and z == 0 then
        print("[bigcow] keypress seen but no player in-game yet")
        return
    end
    local id = BigCow.new(x, y + 80.0, z)
    print(string.format("[bigcow] spawned giant cow id=%s", tostring(id)))
end

return Mod
import * as Class from "Augment.Class"
import * as Player from "Courage.Player"
import * as Mixin from "Augment.Mixin"

const SCALE = 8.0
const KEY_P = 19

const BigCow = Class.extend("daCow_c", "BigCow", "PROC_COW")

BigCow.Execute = function (self) {
    self.super_Execute()
    self.scale.x = SCALE
    self.scale.y = SCALE
    self.scale.z = SCALE
}

print("[bigcow] BigCow class registered")

declare function mod(name: string): any
const Mod = mod("bigcow")

let prevSc = 0
let pending = false

Mod.init = function (this: any) {
    this.after("crInput_setLastScancode", (ctx: any) => {
        const sc = Mixin.arg(0, "i32") as number
        if (sc === KEY_P && prevSc !== KEY_P) {
            pending = true
        }
        prevSc = sc
    })
    print("[bigcow] loaded - press P in-game to spawn a giant cow")
}

Mod.tick = function () {
    if (!pending) return
    pending = false
    const [x, y, z] = Player.get_position()
    if (x === 0 && y === 0 && z === 0) {
        print("[bigcow] keypress seen but no player in-game yet")
        return
    }
    const id = BigCow.new(x, y + 80.0, z)
    print(`[bigcow] spawned giant cow id=${id}`)
}

export = Mod