> For the complete documentation index, see [llms.txt](https://mole-resource.gitbook.io/mole-resource-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mole-resource.gitbook.io/mole-resource-docs/scripts/tic-tac-toe/installation.md).

# Installation

## 1. Drop the resources

Place both resources in your server:

```
resources/
├── mr_tictactoe        # the script
└── mr_tictactoe_3d     # the streamed models (board + marks)
```

## 2. Import the database

Import [`sql.sql`](broken://pages/4d53201e10b063b9c583b8f5bca6f9531b0f29b3) into your database. It creates the `tictactoe_boards` table:

```sql
CREATE TABLE IF NOT EXISTS `tictactoe_boards` (
    `id`       INT(11)      NOT NULL AUTO_INCREMENT,
    `x`        FLOAT        NOT NULL,
    `y`        FLOAT        NOT NULL,
    `z`        FLOAT        NOT NULL,
    `rotation` FLOAT        NOT NULL DEFAULT 0,
    `grid`     CHAR(9)      NOT NULL DEFAULT '---------',
    `turn`     CHAR(1)      NOT NULL DEFAULT 'X',
    `instance` VARCHAR(64)  DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
```

## 3. Start order

The model resource must start **before** the script. In your `server.cfg`:

```cfg
ensure mr_tictactoe_3d
ensure mr_tictactoe
```

## 4. Add the inventory item

Add an item named `tictactoe` (or whatever you set in `Config.ItemName`).

{% tabs %}
{% tab title="ox\_inventory" %}
In `ox_inventory/data/items.lua`:

```lua
['tictactoe'] = {
    label = 'Tic-Tac-Toe',
    weight = 500,
    stack = false,
    close = true,
    -- Required for ox: this is how the item triggers placement
    client = { event = 'mr_tictactoe:PlaceBoard' },
},
```

> ⚠️ Under **ox**, the script does **not** register a usable-item callback — placement is wired through the item's `client.event`. Without the line above, using the item does nothing.
> {% endtab %}

{% tab title="qb-core" %}
In `qb-core/shared/items.lua`:

```lua
['tictactoe'] = {
    name = 'tictactoe', label = 'Tic-Tac-Toe',
    weight = 500, type = 'item', image = 'tictactoe.png',
    unique = false, useable = true, shouldClose = true, description = 'Place a board'
},
```

The script registers the usable item automatically for qb.
{% endtab %}

{% tab title="es\_extended" %}
Register the item in your `items` table / database. The script registers it as usable automatically for esx.
{% endtab %}
{% endtabs %}

## 5. Configure the framework

Open [`config.lua`](broken://pages/7d32272a584b02b6a9671858417e50ab3af0d195) and set at minimum:

```lua
Config.Framework = "ox"        -- "ox" | "qb" | "esx"
Config.ItemName  = "tictactoe"
Config.Target    = "ox_target" -- "none" | "ox_target" | "sleepless_interact"
Config.Notify    = "ox_lib"    -- "ESX" | "ox_lib" | "mythic_notify" | "QB-Core"
```

## 6. Set the model names

Model names live at the top of [`client.lua`](broken://pages/59e8ff5a2605575596e03ef25fb48a3080802d30) (they are client-only streamed objects):

```lua
Config.Base  = "mr_tictactoe_board"
Config.Marks = {
    ["X"] = "mr_tictactoe_xmark",
    ["O"] = "mr_tictactoe_omark",
}
```

These **must match** the model names inside `mr_tictactoe_3d`. Calibrate mark position/rotation with `/tictacbones` and check bone coordinates with `/tictaccoords` (both require `Config.Debug = true`) — see [Configuration](broken://pages/afc4f9c104601f6d45d7acbb8a6e7277c747fbda#gameplay--placement).

## 7. Add the mark-placement sound

Drop an `.ogg` file at `html/place.ogg` — it's already listed in `fxmanifest.lua`'s `files{}`. Without this file present, placing a mark won't play any sound (silently — check the client console for a `place.ogg` load error if you're unsure it's missing).

## 8. Restart

```
refresh
ensure mr_tictactoe_3d
ensure mr_tictactoe
```

Give a player the item, use it, and place your first board.

## Before going live

* Set `Config.Debug = false`.
* Replace the Discord webhook with your own (never publish the one shipped in the config).
* Remove `CLAUDE.md` and the `.claude/` folder from the resource if present.
* Confirm `html/place.ogg` exists — the resource ships no default sound file.
