Stat

stat( n )
Returns information about the current runtime environment.
n

The ID of the information to return. (See below.)

The `stat()` function returns information about the current runtime environment. Each kind of information has an ID (a number), described below.

You can display this metric on the game screen with `print()`, write it to the console with `printh()`, or perhaps use it some other way to adjust the behavior of your program.

Note that any ID values not listed below are unknown or have no defined meaning, returning 0.

## {0…2} Memory and CPU usage

`stat(0)` returns the memory usage:

* This number is in KiB. 1 would represent 1024 bytes allocated. The fractional portion is accurate, so 1.875 would represent 1920 bytes.
* Accounts for all Lua data, such as variables and tables.
* Ranges from 0 to 2048. (As of 0.1.11g, Lua is allowed up to 2 MiB of data.)
* Does not include `peek()`/`poke()`-able RAM such as sprite or video RAM.
* Does not include cartridge ROM.

`stat(1)` returns the total CPU usage:

* Begins at 0 at the start of the first `\_update()` after the most recent `\_draw()`.
* Progresses towards 1 as it nears time for the next frame to begin. Therefore, 1 would represent 1/30s elapsed when using `\_update()`, or 1/60s for `\_update60()`.
* A value higher than 1 indicates that the program has gone over its processing budget for code and drawing this frame. Frames may be dropped to compensate, or overall execution may be slowed.

`stat(2)` returns the system CPU usage:

* This number uses the same range and behavior as `stat(1)`.
* This number only increases while work is being done in unseen code. For instance, clearing the screen about 70 times would push `stat(2)` past 1.0. Almost all of the work would be done inside of calls to `cls()`, which is a system call. However, spending the whole frame calculating pi wouldn't budge `stat(2)`, because it wouldn't involve any system calls.

## {3} Current Display

`stat(3)` returns the current display being accessed (set by `_map_display(n)`), ranging from 0-3.

## {4} Clipboard contents

The system clipboard contents can be found in `stat(4)`, as a string.

See Clipboard for full details on usage and limitations.

## {5} PICO-8 version

The running PICO-8 version ID can be found in `stat(5)`, as a number.

This is the same number as the "version" ID in the .p8 file. (e.g. 33 for 0.2.3)

## {6} Parameter string from a third-party load

When a cart calls `load()` to load another cart, it can provide an arbitrary string as the third argument. This string is accessible to the loaded cart by calling `stat(6)`. If PICO-8 is run from the command line, the -p flag can be used to provide this argument instead.

If the load() call also included a breadcrumb string, the loaded cart can access this with `stat(100)`.

## {7} Frame rate

`stat(7)` returns the current frame rate, as the number of frames rendered per second.

Specifically, the frame rate is the number of times per second PICO-8 is able to call the game's `\_draw()` function in the game loop (if provided), or the number of times the game calls `flip()`. When using the game loop, the expected frame rate is 30 frames per second (fps) with an `\_update()` function or 60 fps with an `_update60()` function, but may be fewer if the draw or update functions take too long and PICO-8 skips `_draw()` calls to catch up. This makes frame rate an interesting measure of game performance for games that do a lot of calculation between frames.

## {8} Target frame rate

`stat(8)` returns the intended frame rate of the system, currently either 30 or 60. See `\_update()` for more details on how to choose one or the other.

## {9} PICO-8 frame rate

`stat(9)` appears to return the number of times the PICO-8 application itself has updated in the last second. This will tend to be similar to the refresh rate of the physical display, but may vary with system load. It is independent of the current game's update rate. If you configure PICO-8 to show an FPS indicator, this is the value being shown.

## {10} Unknown

`stat(10)` returns a number, 0 at the time of writing, whose purpose is unknown.

## {11} Number of displays

`stat(11)` returns the number of enabled displays, ranging from 1-4.

## {12…15} Pause menu location

`stat(12)` through `stat(15)` represents the coordinate position of the pause menu if the player were to pause the game at that moment, as the X and Y coordinates of the upper left corner and bottom right corner, respectively.

Various things determine the contents of the pause menu dynamically, including `menuitem()` calls, `load()` parameters, whether the game was loaded with Splore, and possible future extensions. PICO-8 calculates the size and position of the menu based on its contents.

## {16…26} Sound and music status (deprecated)

*0.2.4+: These are deprecated; use the more stat(46..56). stat(16..26) returns the same information as stat(46..56), but stat(16..26) are calculated with less precision.*

**Caution:** There is a bug in `stat(24)` in PICO-8 versions prior to 0.1.12: If no music is currently playing, an ID of 0 will be returned instead of -1, but this does not mean music pattern 0 is actively playing. In affected versions, workarounds like checking `stat(25)` are necessary to detect whether music is actually playing.

## {27} Unknown

`stat(27)` return values 0 at the time of writing, whose purposes are unknown.

## {28} Raw keyboard

`stat(28,scan*code*)` returns true if key with scan code *scancode* is pressed. See SDL documentation (or SDL\_scancode.h) for numeric values.

The following code tests all 256 raw keycodes:

```
function \_init()
  poke(0x5f2d,1)
end
function \_draw()
  cls()
  for y=0,15 do
    for x=0,15 do
      circfill(4+x\*8,4+y\*8,3,
          stat(28,x+y\*16) and 7 or 1)
    end
  end
end

```

## {29} Unknown

`stat(29)` return values 0 at the time of writing, whose purposes are unknown

## {30…39} Mouse and Keyboard

From inside a cart, an experimental mode can be enabled for platforms that have mouse and keyboard attached:

```
-- enables mouse and keyboard via devkit mode
poke(0x5f2d, flags)
-- flags is a bitfield where:
-- 0x1 enable
-- 0x2 mouse buttons trigger btn(4)..btn(6)
-- 0x4 pointer lock (use stat 38..39 to read movements)
-- for example, poke(0x5f2d,3) will enable, and trigger btn()

```

Once enabled, `stat(...)` can be used to read mouse and keyboard values:

* `stat(30)` -> a *boolean* value representing if a keypress has occurred
* `stat(31)` -> *string* name of the keypress when `stat(30)` is `true`
	+ note: stat(31) returns a second value, which seems to always be 0 (meaning unknown). This will cause problems if you try to call `ord(stat(31))` directly, because ord takes 2 arguments
* `stat(32)` -> mouse **X**
* `stat(33)` -> mouse **Y**
* `stat(34)` -> mouse buttons *bitfield*
	+ `0x1`: left button
	+ `0x2`: right button
	+ `0x4`: middle button

* `stat(35)` -> *number* representing a horizontal mouse wheel or two-finger-swipe event.
	+ The value returned is in pixels: swiping left returns a positive value, swiping right returns a negative value.
* `stat(36)` -> *number* representing a mouse wheel event. Possible values are:
	+ `1` roll up
	+ `0` no roll
	+ `-1` roll down
* `stat(37)` -> *number* ranging from `0-4` seeming to represent the **mouse acceleration delta.**
	+ Sets to 4 on mouse click only.

***The next two `stat` results will only return if bit*** `0x4` ***has been set in the flags***

* `stat(38)` -> relative **x** movement in host desktop pixels
* `stat(39)` -> relative **y** movement in host desktop pixels

Here's a helpful example function allowing you to dynamically set the appropriate mouse/keyboard flags for your Pico-8 project.

```
-- enable = enables devkit mode with mouse and keyboard
-- btn\_emu = left,right,middle mouse buttons -> btn(❎),btn(🅾️),btn(6)
-- ptr\_lock = enable pointer lock
function mkb\_init(enable, btn\_emu, ptr\_lock)
  -- pass args as bitfield into hardware register
  poke(0x5f2d,(enable   and 1 or 0)
end

-- initialize the mouse/keyboard with desired flags
function \_init()
  mkb\_init(true,false,true) -- enabled, no button emulation, locked
end

```

When the user presses one or more keys, PICO-8 sets `stat(30)` to `true`, and then sets `stat(31)` to the next keypress to be read. When the application sees `stat(30)` is `true` and reads the keypress via `stat(31)`, PICO-8 will then refresh the value of both stats, based on whether or not there are more keypresses remaining to be reported. This can be checked multiple times per frame to fully read all keys pressed since last frame.

An example of reading the keyboard:

```
function \_update()
  while stat(30) do
    handle\_keypress(stat(31))
  end
end

```

Some special keys can be detected using these standard Lua escape sequences:

**Modifier keys:**

The `Shift` key is not reported separately. Instead, it changes the character that is returned from `stat(31)`. For instance, if the player presses `Shift`+`H`, a double-wide heart character will be returned. Other modifier keys are invisible to PICO-8 programs.

**Usage notes:**

Conceptually, PICO-8 is a small game console, similar to an NES or GameBoy. It may be running on a machine without a keyboard or mouse connected, such as a game cabinet with only game controllers, or even a small system-on-a-chip implementation with integrated controls. For that reason, this is referred to as "devkit mode", intended for debugging and tools. It's not forbidden to write games that use this mode, but games that do may find a limited audience.

If PICO-8 is running in a context where mouse and keyboard cannot be safely relied on (for instance, on the BBS), it will display a notice that devkit mode has been enabled. This is so the user will not be confused if they cannot control the game. This notice will come up the first time a relevant `stat()` is read; this knowledge can be used to make sure the notice will not obscure something important at a bad time.

## {46…56} Sound and music status

`stat(46)` through `stat(56)` return audio status. These are the newer versions (0.2.4+) of `stat(16)` through `stat(26)`, which return the same data with less precision.

* `stat(46)` through `stat(49)` return the index of the sound effect currently playing on the four channels, respectively.
	+ If no sound is playing on the channel, `stat()` returns -1.
* `stat(50)` through `stat(53)` return the note number (0 through 31) of the sound effect currently playing on the four channels, respectively.
	+ If no sound is playing on the channel, `stat()` returns -1.
* `stat(54)` is the music pattern ID currently being played, as a result of the most recent call to `music()`.
* `stat(55)` is the number of music patterns played since the most recent call to `music()`.
* `stat(56)` is the number of ticks (notes or rests) played on the current pattern.

Notes from zep on precision:

* stat(16..26): "Note that the row number may not be very precise depending on what is going on with the host operating system's audio mixer. Also in the case of the web player which needs to have a large mixing buffer, the result is often slightly earlier that what is audible." - zep
* stat(46..56): "It's still not perfect, but requires less to work to get pretty good sync going." - zep

## {57…71} Unknown

* `stat(57..63)` -> 0?
* `stat(64..71)` -> nil?

## {80…85,90…95} Time of day

A PICO-8 cart can access the current time of day, in the host system's local time zone:

* `stat(90)` -> year, e.g. 2018
* `stat(91)` -> month of year, 1-12
* `stat(92)` -> day of month, 1-31
* `stat(93)` -> hour of day, 0-23
* `stat(94)` -> minute of hour, 0-59
* `stat(95)` -> second, 0-61 (usually 0-59, see note below)

A corresponding set of values, but in UTC time, are available at `stat(80)` through `stat(85)`.

*Note: PICO-8 and/or Lua appear to be using the standard C `tm_time` interface to provide these values, and as such, you should be aware that the current second is allowed to go past 59, to 60 or 61, in the event of leap seconds occurring.*

## {99} Garbage Collection (Raw)

While `stat(0)` performs garbage collection in order to obtain a *meaningful result*, `stat(99)` returns the *raw value* of the same.

## {100…102} BBS information

The following are not officially documented but appear to be related to BBS functionality:

* `stat(100)` -> Returns breadcrumb label.

* `stat(101)` -> For BBS carts, `stat(101)` returns the current BBS ID. (per zep on Twitter)

* `stat(102)` -> For BBS carts, returns site (e.g. `"www.lexaloffle.com"`). For local carts, returns `0`.

## {103…107} Unknown

The following are mostly unknown, but may be related to BBS functionality, the PCM audio channel, or something else entirely:

* `stat(103)` -> Unknown, returns some kind of SHA1 hash (known to be affected by cart contents)

* `stat(104)` -> Unknown, returns `false` in limited testing.

* `stat(105)` -> Unknown, returns `0` in limited testing.

* `stat(106)` -> Unknown, returns some kind of SHA1 hash. (known to be affected by cart contents & load parameter)

* `stat(107)` -> Unknown, returns `0` in limited testing.

(If you know more details about any of these, please update this section.)

## {108…109} 5kHz PCM Audio

By writing to the undocumented `0x808` serial port, you can output PCM audio samples.

Specifically, up to 2048 bytes of unsigned 8-bit 5512.5 Hz audio can be buffered by using `serial(0x808,address,length)`; more info here.

* `stat(108)` -> Returns the number of PCM sample bytes currently buffered for output. Ranges from 0 to 2047.

* `stat(109)` -> Returns the PICO-8 app's audio buffer size divided by 4. Generally, the PCM buffer must be filled by *at least* `stat(109)-stat(108)` samples to reduce CPU usage as much as possible while resulting in little amounts of crackling.

## {110} Frame-by-frame mode flag

This stat is zero under normal conditions, and non-zero when PICO-8 is in frame-by-frame mode.

Frame-by-frame mode is engaged by using "." at the command prompt, which effectively calls `resume` to continue execution and then `stop()` before the next frame begins. It may be used repeatedly to advance a game frame-by-frame.

This is an example of how `stat(110)` might be used to insert extra breakpoints before the next frame:

```
function \_update()
  ⋮
  if(stat(110)>0) stop("before move: " .. player.x .. "," .. player.y)
  move\_player()
  if(stat(110)>0) stop("after move: " .. player.x .. "," .. player.y)
  ⋮
end

```

## {111…119} Unknown

`stat(111…119)` return a number, 0 at the time of writing, whose purpose is unknown.

## {120...121} Bytestream Availability

Boolean values used with the GPIO functionality of Pico-8. `stat(120)` and `stat(121)` will return a value of `false` unless data is available to be transferred between Pico-8 and the host operating system. They are not useful in many situations, such as while running carts on the BBS or running exported carts.

To obtain the bytestreams necessary to make use of these two results, you would use the `serial()` function.

* `stat(120)` -> returns `true` when data is available for a dropped file (obtained with `serial()` at channel `0x800`)

* `stat(121)` -> returns `true` when data is available for a dropped image (obtained with `serial()` at channel `0x802`)

## {122…123} Unknown

* `stat(122)` -> Returns `false`. Possibly related to `serial()` bytestreams.
On the EDU version, returns the string `"www.pico-8-edu.com"`.

* `stat(123)` -> Returns 0, but may not always return 0 under other circumstances, needs investigating.

## {124} Current path

* `stat(124)` -> Returns current path relative to PICO-8's root folder.

## {125…???} Unknown

(If you know more details about any of these, please update this section.)

### {10001} BBS Registration Passcode

Returns a long string of hexadecimal characters, the first 8 of which are a valid registration passcode. It is only available in what appears to be a special build used by the registration page and returns nothing on all other versions.

## Examples

```
function \_update()
  -- game update code...
end

function \_draw()
  cls()

  -- game draw code...

  print('mem:'..stat(0), 0, 0, 7)
  print('cpu:'..stat(1), 0, 6, 7)
end

```

## See also

* `\_draw()`
* `flip()`
* `load()`
* `\_update()`