Lua API

Current Revision: Mar 18th, 2018
Applies to ATH version: 0.36 (pending)

Getting started with Lua

Scripts for ATH are created using the Lua programming language version 5.1. For anything related to the language itself, refer to the plentiful Lua Reference Manual, please (in this document referred to as 'LRM').

Lua 5.1 Reference Manual

Since learning to code is mainly done by reading and writing code, it's a good idea to look at some existing scripts and try to understand what they do:

Up-to-date Official Scripts Collection of old Scripts

Prependix

This documentation gives a complete overview over the ATH Lua API. It contains all custom types, namespaces and methods that can be used in scripts.
If you miss anything or have found an error, please let us know on our IRC-Channel or Discord-Server.

For every method in this documentation you will find a pseudo-cpp-like-style function header. These are only there to show which types the methods return or expect and have nothing to do with the syntax used for scripting.
Example:

void HSplitBottom(float Offset, out UIRect Top, out UIRect Bottom) [const]
void means that the function does not return anything
float hints that a decimal number is allowed here (int would hint that only whole numbers are allowed)
out tells you that the variable you pass here will be changed by the function to contain the result of the operation
UIRect is the type of the variable that you must pass here
[const] denotes that this methods does not change any of the object's attributes. This only applies to custom types.

Security

Permissions

There are a few things that you have to explicitly request from the client if you want to use them in your script. This is a security measure to let users know when a script wants to use possibly risky things.
Because these special things don't have to used commonly, it's kind of cumbersome to use. The following syntax has to be used at the very top of your script if you need one of these things:

Usage:
--[[#!
    #io
    #os
    #debug
    #package      -- this on is pretty useless but included for completeness
]]--#

-- Use whatever you need, you don't have to list them all
-- (it's actually good practice to use none whenever possible)

Sandboxing

This section is to a certain extend also significant for people who solely use scripts, but not write them.
ATH has mechanism's to ensure that no script can do damage to your system or yourself as a Teeworlds player (we can not be hold liable if that happens anyhow, though).
The main security measure is protecting the user's filesystem by only allowing scripts access to one folder (and its subfolders) that the client provides specifically for this one script. We call this folder the 'lua filesystem sandbox', or for short just sandbox. Every script gets its own folder when it requests io permissions, and the name of this folder is the filename of the script. All these folders live in %APPDATA%\Teeworlds\lua_sandbox on Windows or ~/.teeworlds/lua_sandbox on Linux. The client enforces all io operations a script could make to be redirected to this folder, and it is not possible to escape out of it.
A second, less crucial, countermeasure against nasty scripts is deliberately limiting what scripts can do to/with the client. The first and foremost principle here is: it should not be possible to crash the client using Lua. It's just annoying and may irritate some people into thinking ATH was buggy (dat sarcasm tho…). Jokes aside, this second countermeasure also results in certain limits to the API, for example is it the reason for the absence of e.g. a function that lets a script execute F1 commands.
If you're the kind of person that lives by the motto of "If it ain't broken, break it!", I would really much appreciate you report any exploits to this system, if you find some (we've done a thorough investigation already though, so it should be fairly safe).

Builtin-replacement

For security reasons, certain builtins of Lua have been removed or replaced with custom functions that provide similar or slightly adapted functionality. Here is a list of these builtins, so don't be confused if you read about them in the Lua Reference Manual but they don't seem to work in ATH.

Removed Functions
require io.popen os.exit debug.getregistry
module io.input os.execute collectgarbage
load io.output os.remove
loadfile io.stdin os.rename
loadstring os.setlocale os.getenv

Replaced Functions
print

the only relevant change is: print() will NOT auto-convert to string values, but raise an error when given a non-string value. This should force scripters to write their code more explicitly to help less experienced people catch mistakes in their scripts more easily. Use tostring() if you want to print non-string values.

dofile

has been replaced with Import, thus does exactly the same.

io.open

The functionality of io.open has been improved and tailored to obey sandboxing rules. The definition of io.open was changed to:
io.open(string filename [, string openmode [, bool shared]]) -> file|`nil`, string
You have only access to your script's sandbox, or to the shared sandbox if 'shared' is given and true. If the file is to be opened in write mode, io.open will automatically create the path to the file for you if it doesn't exist.
Another change is that io.open now returns two values instead of one. The first is exactly the same as denoted in the LRM; the second return value is a string containing the path of the file ATH tried opening.
The basic operation of io.open is exactly the same though, as the builtin is actually being used behind the scenes, so refer the the LRM for further information.

Custom types

vec2

A two-dimensional vector (x and y coordinates). Commonly used for positions and directions.
All vector classes implement lua's standard operators +, -, *, /, ==, ~=, tostring.


Attributes:
x / u – x-part of the vector
y / v – y-part of the vector
Usage:

-- defining a vector
MyVec = vec2(20.4, 30.6)

-- outputting the vector as a human-readable string
tostring(MyVec)  -- >  (20.4000|30.6000)

-- doing arithmetics on the vector
MyVec + vec2(1,2)  -- >  (21.4000|32.6000)  // addition – translating the vector
MyVec - vec2(1,2)  -- >  (20.4000|30.6000)  // subtraction – equal to `MyVec + vec2(-1,-2)`
MyVec * 2          -- >  (40.8000|61.2000)  // multiplication – upscaling the vector
MyVec / 2          -- >  (10.2000|15.3000)  // division – downscaling the vector

-- comparing vectors
if MyVec == vec2(20.4, 30.6) then print("equal!") end      -- >  'equal!'
if MyVec ~= vec2(13.3, 73.8) then print("not equal!") end  -- >  'not equal!'

-- accessing attributes
print(MyVec.x)  -- >  20,39999961853
print(MyVec.y)  -- >  30,60000038147
-- // note that these values are so fucked up due to floating point error! (google it)
                                        

Note:

All these operators are implemented into the other types of vectors (vec3 and vec4) either.
As such, they will not be explained again in the following sections.

vec3

A three-dimenstional vector, in Teeworlds commonly used for colors


Attributes:
x / r / h – x-part of the vector / the red-part of the RGB-color / the hue-part of the HSL-color
y / g / s – y-part of the vector / the green-part of the RGB-color / the saturation-part of the HSL-color
z / b / l – z-part of the vector / the blue-part of the RGB-color / the lighting-part of the HSL-color

Usage:

MyVec = vec3(20.4, 30.6, 40.8)
print(Vector3.x, Vector3.y, Vector3.z)  -- >  20,39999961853    30,60000038147    40,799999237061
print(Vector3.r, Vector3.g, Vector3.b)  -- >  20,39999961853    30,60000038147    40,799999237061
print(Vector3.h, Vector3.s, Vector3.l)  -- >  20,39999961853    30,60000038147    40,799999237061
-- // again floating-point-error!

MyVec.x = 1
MyVec.g = 2
MyVec.l = 3
print(Vector3.x, Vector3.y, Vector3.z)  -- >  1    2    3
print(Vector3.r, Vector3.g, Vector3.b)  -- >  1    2    3
print(Vector3.h, Vector3.s, Vector3.l)  -- >  1    2    3

vec4

A four-dimensional vector, commonly used for RGBA-colors (other rare use case: three dimensional vector with time)


Attributes:
r / x – red-part of the RGBA-colors / the x-part of the four-dimensional vector
g / y – green-part of the RGBA-colors / the y-part of the four-dimensional vector
b / z – blue-part of the RGBA-colors / the z-part of the four-dimensional vector
a / w – alpha-part of the RGBA-colors / the time-part of the four-dimensional vector

Usage:

Vector4 = vec4(20.4, 30.6, 40.8, 50.1)

-- To get the data of a vec4 simply do this with:
print(Vector4.x,Vector4.y,Vector4.z)  -- >  20,39999961853    30,60000038147    40,799999237061
print(Vector4.r,Vector4.g,Vector4.b,Vector4.a)  -- >  20,39999961853    30,60000038147    40,799999237061    50,099998474121
-- I don't know if i used this rightly.
print(Vector4.w,Vector4.u,Vector4.v)  -- >  50,099998474121    40,799999237061    50,099998474121
-- I don't know why its returning such unrounded values.

UIRect

Represents a rectangle used for user interface rendering


Attributes:
x – the x-coordinate
y – the y-coordinate
w – the width
h – the height

Methods:
HSplitMid splits the rect horizontally in the middle, putting the resulting parts into Top and Bottom
void HSplitMid(out UIRect Top, out UIRect Bottom) [const]
HSplitTop splits the rect horizontally at Offset units from the top, putting the resulting parts into Top and Bottom
void HSplitTop(float Offset, out UIRect Top, out UIRect Bottom> [const]
HSplitBottom splits the rect horizontally at Offset units from the bottom, putting the resulting parts into Top and Bottom
void HSplitBottom(float Offset, out UIRect Top, out UIRect Bottom) [const]
VSplitMid splits the rect vertically in the middle, putting the resulting parts into Left and Right
void VSplitMid(out UIRect Left, out UIRect Right) [const]
VSplitLeft splits the rect vertically at Offset units from the left, putting the resulting parts into Left and Right
void VSplitLeft(float Offset, out UIRect Left, out UIRect Right) [const]
VSplitRight splits the rect vertically at Offset units from the right, putting the resulting parts into Left and Right
void VSplitRight(float Offset, out UIRect Left, out UIRect Right) [const]
HMargin cuts away Offset units from both the top and the bottom of the rect, and stores the result in Dest
void HMargin(float Offset, out UIRect Dest) [const]
VMargin cuts away Offset units from both the right and the left of the rect, and stores the result in Dest
void VMargin(float Offset, out UIRect Dest) [const]
Margin cuts away Offset units from all sides of the rect and stores the result in Dest
void Margin(float Offset, out UIRect Dest) [const]
copy creates a new UIRect that is equal to the current one, and returns a reference to this new copy
UIRect copy() [const]

Usage:

NewRect = UIRect(0,0,0,0) -- UIRect(x, y, width, height)

-- To get an UIRect which is as large as the entire screen (=teeworlds window), use:
Screen = Game.Ui:Screen()
-- IMPORTANT! If you want to COPY a rect use:
Screen2 = Screen:copy()
-- insteed of:
Screen2 = Screen
-- Using the copy function is necessary because otherwise Screen2 and Screen would both point to the same UIRect, thus chaning one would change the other!

-- Output (without copy):
local Screen = Game.Ui:Screen()
local MainView = Screen
print(MainView.x,MainView.y,MainView.h,MainView.w)  -- >  0    0    600    960
MainView.x = 100
print(MainView.x,MainView.y,MainView.h,MainView.w)  -- >  100    0    600    960 
print(Screen.x,Screen.y,Screen.h,Screen.w)  -- >  100    0    600    960 

-- Output (with copy):
local Screen = Game.Ui:Screen()
local MainView = Screen:copy()
print(MainView.x,MainView.y,MainView.h,MainView.w)  -- >  0    0    600    960
MainView.x = 100
print(MainView.x,MainView.y,MainView.h,MainView.w)  -- >  100    0    600    960 
print(Screen.x,Screen.y,Screen.h,Screen.w)  -- >  0    0    600    960 

-- Now the complicated things about the UIRect... :)
-- To split a rect horizontally, defining a margin from top, you can use:
NewRect = UIRect(0,0,100,100)
local NewRect1 = UIRect(0,0,0,0)
local NewRect2 = UIRect(0,0,0,0)
NewRect:HSplitTop(10,NewRect1,NewRect2) -- Splits NewRect by 10 pixel from TOP in NewRect1 and NewRect2
print(NewRect1.x,NewRect1.y,NewRect1.w,NewRect1.h)  -- >  0    0    100    10  -- This is the top part which's size you've defined (here 10)
print(NewRect2.x,NewRect2.y,NewRect2.w,NewRect2.h)  -- >  0    10    100    90  -- This is the rest of the old rect, thus the bottom part
-- You can also split rects with: NewRect:HSplitBottom(N,UIRect1,UIRect2) and NewRect:HSplitMid(N,UIRect1,UIRect2) the principe is the same. (N = pixels, UIRect1 = 1st UIRect, UIRect2 = 2nd UIRect)

-- To split a rect vertically, defining a margin from the right, you can use:
NewRect = UIRect(0,0,100,100)
local NewRect1 = UIRect(0,0,0,0)
local NewRect2 = UIRect(0,0,0,0)
NewRect:VSplitRight(10,NewRect1,NewRect2) -- Splits NewRect by 10 pixel from the right in NewRect1 and NewRect2
print(NewRect1.x,NewRect1.y,NewRect1.w,NewRect1.h)  -- >  0    0    90    100  -- This is now right part of the old rect
print(NewRect2.x,NewRect2.y,NewRect2.w,NewRect2.h)  -- >  90    0    10    100  -- This is the rest of the old rect
-- You can also split rects with: NewRect:VSplitLeft(N,UIRect1,UIRect2) and NewRect:VSplitMid(N,UIRect1,UIRect2) the principe is the same. (N = pixels, UIRect1 = 1st UIRect, UIRect2 = 2nd UIRect)

-- You can also cut away a margin at multiple sides of the rect, spacing it out evenly:
-- For a margin all around the rect:
NewRect = UIRect(0,0,100,100)
NewRect:Margin(10,NewRect) -- Modifies 'NewRect' to contain the result
print(NewRect.x,NewRect.y,NewRect.w,NewRect.h)  -- >  10    10    80    80

-- For a margin from the right and left:
NewRect = UIRect(0,0,100,100)
NewRect:VMargin(10,NewRect) -- Returns the new Rect in NewRect
print(NewRect.x,NewRect.y,NewRect.w,NewRect.h) -- >  10    0    80    100

-- And for a margin from the top and bottom:
NewRect = UIRect(0,0,100,100)
NewRect:HMargin(10,NewRect) -- Returns the new Rect in NewRect
print(NewRect.x,NewRect.y,NewRect.w,NewRect.h)  -- >  0    10    100    80		

See also:
Game.Ui:Screen
Game.RenderTools:DrawUIRect

Common mistake

Assigning one UIRect variable to another one will just copy the reference, not the object!
That means both variables will actually point to the same UIRect, thus modifing one will also modify the other.

To avoid this, use the copy method.

QuadItem

The QuadItem is used for drawing quads (geometric shapes with 4 corners).

Usage:
MyQuad = QuadItem(0,0,200,400) -- QuadItem(x,y,width,height)
-- Prepares a quad at the coordinates x and y with the given width and height.
-- It's not possible to change a QuadItem after it has been created.

LineItem

The LineItem is used for drawing lines. Like the QuadItem, the LineItem don't have any functions or data.

Usage:
MyLine = LineItem(0,0,200,400) -- LineItem(x1,y1,x2,y2)
-- Prepares a line from coordinates (x1|y1) to (x2|y2).
-- It's not possible to change a LineItem after it has been created.

ButtonContainer

ButtonContainer's are used to uniquely identify buttons.

Usage:
MyBC = ButtonContainer()

Useful Tip:

ButtonContainer's are not meant to be used directly. We've written the handy containers lib to make your lifes easier.

EditboxContainer

EditboxContainer's are used to uniquely identify editboxes and hold their text.

Usage:
MyEBC = EditboxContainer()
-- To get the current string of an editbox use:
print(MyEBC:GetString())  -- >    (Its empty :3)

-- To modify the string use:
MyEBC = EditboxContainer()
print(MyEBC:GetString())  -- >
MyEBC:SetString("Hello World")  
print(MyEBC:GetString())  -- >  Hello World

Useful Tip:

The containers lib can also handle EditboxContainer's.

TeeRenderInfo

TeeRenderInfo keeps all information necessary to render a tee.

Usage:
MyTee = TeeRenderInfo() -- no parameters!
MyTee.Texture = Game.Players(Game.LocalCID).RenderInfo.Texture
MyTee.ColorBody = Game.Players(Game.LocalCID).RenderInfo.ColorBody
MyTee.ColorFeet = Game.Players(Game.LocalCID).RenderInfo.ColorFeet
MyTee.Size = Game.Players(Game.LocalCID).RenderInfo.Size
MyTee.GotAirJump = Game.Players(Game.LocalCID).RenderInfo.GotAirJump

Custom Functions and Data

ATH's Lua API is organized in so-called 'blocks' of which each provides you with variables and functions of one specific part of the client.
These blocks are defined in the client's source code – if you take a look at it you'll see why we call it blocks :)

Global functions

SetScriptTitle(string NewTitle)

Sets the title of this script to the given string. The script title will be displayed in the right section of the Lua settings menu when your script is selected.

Usage:
SetScriptTitle("Really Cool Script")
function MyButtonWasClicked()
    -- imagine this function gets called on a button press
    SetScriptTitle("Much Cooler Script!")
end

SetScriptInfo(string NewInfo)

Sets the info of this script to the given string. The script info will be displayed in the right section of the Lua settings menu below the title when your script is selected.

Usage:
SetScriptInfo("This script is cooler than you'd believe!")
function MyButtonWasClicked()
    -- imagine this function gets called on a button press
    SetScriptInfo("HOLY SHIT IT JUST GOT EEEVEN COOLER DAMN!!1!")
end

The old method

SetScriptTitle and SetScriptInfo were introduced in ATH 0.36 (3600) and are not available in older versions, that's why this note is here.

The old way of doing it was by assigning your title/info to a variable with the name 'g_ScriptTitle' bzw 'g_ScriptInfo' at the very top of your script, but this way it was not possible to change it dynamically after the script had been loaded.
It is still possible to use the old method, but mainly for compatibility with older scripts. It has been marked as deprecated and will most likely be removed in a future version.

Possible confusion

If you persist on using the old method, note that it will take precedence over the new method! That means, if you assign anything to e.g. g_ScriptTitle, that will be the script title regardless of any SetScriptTitle calls in the global scope!

CheckVersion(int MinVersion [, int MaxVersion])

Will raise an error if the client's version is not within MinVersion and MaxVersion. (MaxVersion is actually optional; if it's not given we will only check for the minimum version).
The version must be given in numerical version notation, that is, just leave the dots and the leading zero out and pad it to 4 digits with zeros at the end.
Example:
0.33 → 3300
0.34 → 3400
0.34.1 → 3410
0.36.3.1 → 3631 (this only appears in the case of fixup-releases)

Usage:
CheckVersion(3600) -- check if SetScriptTitle is available
SetScriptTitle("Script that only runs on ATH >= 0.36")
throw(string ErrorMessage)

This does the same as Lua's builtin error function, but continues execution instead of jumping out. This allows you to add for example warnings to your script's exceptions list without actually breaking the script.

Usage:
if SomeValue != SomeOtherValue then
    throw("WARNING: 'this' does not equals 'that'. 42 will be unavailable.")
end
print("This print will still get executed")
Import(string what) -> bool [, string]

Import allows you to integrate external scripts into your script. It is most commonly used to import ATH-lua-libs, but you can import any '.lua' file that is available to ATH (see 'Sandboxing'). Import() will do its best to find what you asked for, so it's quite easy to use. You can even omit the '.lua' file extension! :)

First, Import() will look in the folder that your script is in. If it doesn't find it there, it will look for a ATH-lua-lib with the given name. If that doesn't exist either, it will look into the lua root directory (<path_to_your_AllTheHaxx>/lua). If that fails too, it will return false.
If Import() happens to find a lua file matching your request though, it will link it into the execution environment of the calling script. This makes all global variables of the imported script available to your script (only the really global ones, not the script-local variables!). When the imported script has finished execution of its global scope, Import() will return true and the path of the file it just imported.

Usage:
if not Import("containers") then  -- ATH-lua-lib
    error("failed to load containers lib!")
end
if not Import("stringutils")  -- another ATH-lua lib
    error("failed to load stringutils lib")
end
if not Import("./MyCustomFile.lua") then  -- a custom external file to be included in your script
    error("failed to import MyCustomFile.lua")
end
print("everything went flawlessly!")
KillScript()

Calling this function does the equivalent of clicking the "Deactivate" button of your script: it will deactivate it. Note that the OnScriptUnload function will be called.

Usage:
if EverythingIsBoring then
    KillScript()
end
Listdir(string directory, string/function callback)

Using this function you can discover all the contents of the given directory. Note that this is subject to sandboxing rules.

Usage:
Some
lua
code
EnterFullscreen

Description here! EnterFullscreen

Usage:
Some
lua
code
ExitFullscreen

Description here! ExitFullscreen

Usage:
Some
lua
code
ScriptPath

Description here! ScriptPath

Usage:
Some
lua
code
StrIsNetAddr

Description here! StrIsNetAddr

Usage:
Some
lua
code

Game.Client

Game.Client.Tick read-only

Game.Client.Tick is a variable that always contains the current tick. You can convert it to seconds by dividing by Game.Client.TickSpeed.

Tick = Game.Client.Tick
-- To get the seconds from it:
Secs = Tick/Game.Client.TickSpeed
Game.Client.TickSpeed read-only

Game.Client.TickSpeed gives the number of ticks per second.

TickSpeed = Game.Client.TickSpeed
Game.Client.IntraGameTick read-only

Game.Client.IntraGameTick is used for prediction.

IntraGameTick = Game.Client.IntraGameTick
Game.Client.PredIntraGameTick read-only

Game.Client.PredIntraGameTick is used for prediction.

PredIntraGameTick = Game.Client.PredIntraGameTick
Game.Client.PredGameTick read-only

Game.Client.PredGameTick is used for prediction.

PredGameTick = Game.Client.PredGameTick
Game.Client.LocalTime read-only

Game.Client.LocalTime is the time in seconds how long AllTheHaxx is running.

LocalTime = Game.Client.LocalTime
Game.Client.ConnTime read-only

Game.Client.ConnTime is the time in seconds how long you are connected to the current server. It starts at 0 on startup and gets reset everytime you join a server.

ConnTime = Game.Client.ConnTime
Game.Client:Connect(string IP)

Game.Client:Connect(string IP) connects you to the given ip (as string)

Game.Client:Connect("127.0.0.1")
-- Would be localhost! If you host your own server locally, it should work
Game.Client:Disconnect()

Game.Client:Disconnect() disconnects you from the current server. If you are not connected to any server, this does nothing.

Game.Client:Disconnect()
Game.Client:DummyConnect()

Game.Client:DummyConnect() connects your dummy to your current server. If you are not connected to any server, this does nothing.

Game.Client:DummyConnect()
-- Tip: useful in combination with "Game.Client:DummyConnected()" and "Game.Client:DummyConnecting()"
Game.Client:DummyDisconnect(string Reason)

Game.Client:DummyDisconnect(string Reason) disconnects your dummy from the server with the given Reason. If the dummy is not connected, this does nothing.

Game.Client:DummyDisconnect()
-- Tip: useful in combination with "Game.Client:DummyConnected()" and "Game.Client:DummyDisconnect()"
Game.Client:SendInfo(bool Start)

Game.Client:SendInfo(bool Start) sends your info to the server. Usually the passed argument must be false or it won't work.

Game.Client:SendInfo(false)
-- Some very old server might also accept:
Game.Client:SendInfo(true)
Game.Client:RconAuth(string Username, string Password)

Game.Client:RconAuth(string Username, string Password) tries to auth you in the rcon (F2) with the given Username and Password. Most servers other than recent DDNet will ignore the username.

Game.Client:RconAuth("","MySeCrEtPaSSworD")
-- If you're a moderator on DDNet, you might want to use something like:
Game.Client:RconAuth("Admin","MySeCrEtPaSSworD")
-- The correct parameters for this are defined in your server's configuration.
Game.Client:RconAuthed() -> bool

Game.Client:RconAuthed() return a bool that indicates whether you are authed (logged in to rcon).

Authed = Game.Client:RconAuthed()
-- true or false
Game.Client:RconSend(string Command)

Game.Client:RconSend(string Command) sends a command to the rcon. Obvisouly this will only work when you are authed.

Game.Client:RconSend("kick dennis adminabuse")
-- If it doesn't work, make sure to be authed! This code will check that:
if Game.Client:RconAuthed() then -- Only send a command if we are authed
	Game.Client:RconSend("echo Wohoo, I have rcon access!")
else
    error("tried to send an rcon command while not being authed") -- otherwise, give us an error
end
Game.Client.FPS read-only

Game.Client.FPS is the current number of frames per second.

MyFPS = Game.Client.FPS
-- This value is accurate and will fluctuate rapidly (every frame!). The fps you see displayed at the bottom right in your client is just an average.
Game.Client.State read-only

Game.Client.State is the current state of the client. Here is a list of all possible states (they are defined in the twdata lib)

Import("twdata")
MyState = Game.Client.State
if MyState == STATE_OFFLINE then
    -- we are offline, i.e. not connected to a server
elseif MyState == STATE_CONNECTING then
    -- we are currently connecting to a server
elseif MyState == STATE_LOADING then
    -- the client is loading the map (the duration of this state is usually rather short)
elseif MyState == STATE_ONLINE then
    -- we are online, i.e. on a server
elseif MyState == STATE_DEMOPLAYBACK then
    -- we are playing/watching a demo
elseif MyState == STATE_QUITING then
    -- the user has requested the client to quit and it is about to close itself
end
Game.Client:DemoStart(string Filename, bool WithTimestamp, int Recorder)

This function starts the demo recorder with the given id and record to a file with the given name. If WithTimestamp is true, the current date and time will be added to the filename automatically.
Demo recorder IDs are defined in the twdata lib

Import("twdata")
Game.Client:DemoStart("YoungFlyme_Race_Pro_2k17", false, DEMORECORDER_MANUAL)
-- There are 3 demo recorders in the client: manual, auto and race.
Game.Client:DemoStart("YoungFlyme_Race_Pro_2k17_in_teh_race", false, DEMORECORDER_RACE) -- Changed recorder id will open another recorder which records too! If you change the name too you can save 2 records which recorded the same.
Game.Client:DemoStop(int Recorder)

Game.Client:DemoStop(int Recorder) stops the demo recorder with the given id. If the recorder is currently recording, it will save everything it has recorded.

Import("twdata")
Game.Client:DemoStop(DEMORECORDER_AUTO)
Game.Client:DemoStop(DEMORECORDER_RACE)

Game.Ui

Useful Tip:

Don't give up on this too quickly. The Teeworlds UI is a bit complicated, but once you know how it works, you will love it :P
Be sure to have read through the UIRect and Containers sections for better understanding.

Important:

All UI elements have to be drawn in an appropriate render event or they might not appear on the screen!

Game.Ui:DoLabel(UIRect Rect, string Text, int Size, int Align, int MaxWidth, string Highlight)

Game.Ui:DoLabel(UIRect Rect, string Text, int Size, int Align, int MaxWidth, string Highlight) displays a label (text) in the given Rect with the given parameters

Import("ui")
Rect = Game.Ui:Screen() -- For demontrations we simply use the entire screen
Text = "This is my awesome text"
FontSize = 20 -- Font size in pixel
Align = ALIGN_CENTER -- defined in the 'ui' lib
MaxWidth = Rect.w-5 -- The text will be wrapped when its width surpasses MaxWidth
Highlight = "awesome text" -- This will highlight the given substring in a other color
Game.Ui:DoLabel(Rect, Text, FontSize, Align, MaxWidth, Highlight)

Warning:

Using this function is discouraged as it doesn't scale the text to the user's resolution! Only use it if you know what you're doing, otherwise use DoLabelScaled.

Game.Ui:DoLabelScaled(UIRect Rect, string Text, int Size, int Align, int MaxWidth, string Highlight)

this function does the same as Game.Ui:DoLabel, but automatically adjusts the label (text) to the current screen scale (ui_scale setting in F1)

Import("ui")
Rect = Game.Ui:Screen() -- For demontrations we simply use the entire screen
Text = "This is my awesome text"
FontSize = 20 -- Font size in pixel
Align = ALIGN_CENTER -- defined in the 'ui' lib
MaxWidth = Rect.w-5 -- The text will be wrapped when its width surpasses MaxWidth
Highlight = "awesome text" -- This will highlight the given substring in a other color
Game.Ui:DoLabel(Rect, Text, FontSize, Align, MaxWidth, Highlight)
Game.Ui:Scale() -> float

Game.Ui:Scale() returns the scale of the Ui (RealScale / 100)

MyScale = Game.Ui:Scale()
print(MyScale) -- > 1.00
-- if the scale was set to 100 in the settings
Game.Ui:Screen() -> UIRect

Game.Ui:Screen() returns a UIRect that represents the dimensions of the entire screen. 'Screen' here means the Teeworlds window, but note that the resulting dimensions of this rect are virtually arbitrary and have nothing to do with the set resolution! (so just think of this rect as your screen, but don't actually look at the values)

Screen = Game.Ui:Screen()
print(Screen.x,Screen.y,Screen.w,Screen.h) -- > 0    0    1066.6666259766    600
Game.Ui:MouseX()
Game.Ui:MouseY()

Game.Ui:MouseX() and Game.Ui:MouseY() return the position of the UI cursor.

MousePos = vec2(Game.Ui:MouseX(), Game.Ui:MouseY())
Game.Ui:MouseWorldX()
Game.Ui:MouseWorldY()

Game.Ui:MouseWorldX() and Game.Ui:MouseWorldY() seems to be the same as Game.Ui:MouseX() and Game.Ui:MouseY().

Game.Ui:MouseButton(int Button) -> {0,1}

Game.Ui:MouseButton(int Button) return 0 or 1 depending on whether the given button is currently pressed. All button are displayed in the code below

function OnTick()
    print( Game.Ui:MouseButton(0) ) -- 0 = Left button
end
-- If we would now be pressing the left mouse button it would return 1, otherwise 0
Game.Ui:MouseButtonClicked(int Button) -> {0,1}

Game.Ui:MouseButtonClicked(int Button) return 1 only the first time after the button was pressed down, after that it will return 0 until the button is released and clicked again.

function OnTick()
    print( Game.Ui:MouseButton(1) ) -- 1 = Right button
end
-- Exactly when we click it is 1, after this or if we not clicked it is 0!

Possible values

Possible values for Game.Ui:MouseButton and Game.Ui:MouseButtonClicked are:
0 → left mouse button
1 → right mouse button
2 → middle mouse button

Game.Ui:MouseInside(UIRect Rect)

Game.Ui:MouseInside(UIRect Rect) returns 1 when the ui cursor is inside the given Rect, otherwise 0.

MouseInsideScreen = Game.Ui:MouseInside(Game.Ui:Screen()) -- would be 1 everytime but yeah why not ^^

-- By YoungFlyme. Dec 1st, 2017
Game.Ui:ClipEnable(UIRect Rect)

Game.Ui:ClipEnable(UIRect Rect) limits the region in which rendering is possible to the given rect until Game.Ui:ClipDisable() gets called.

Screen = Game.Ui:Screen()
AllowedRegion = UIRect(Screen.w/2-50, Screen.h/2-50, 100, 100)
Game.Ui:ClipEnable(AllowedRegion) -- Clip everything but the middle of the screen
Game.RenderTools:DrawUIRect(Screen, vec4(1,0,1,1), 0, 0) -- draws a pink rect all over the screen, but watch what happens!
Game.Ui:ClipDisable() -- Disable clipping! If you don't do this, the whole game will look pretty fucked up.
Game.Ui:ClipDisable()

Game.Ui:ClipDisable() disables the latest instruction command and roll back to the clipping instruction that has been issued before this, if there is any. That means, for every ClipEnable you have to have a ClipDisable!

Remember!

Don't forget to call Game.Ui:ClipDisable() before your script returns from the render event, or it will break all further rendering while the script is running!

Game.RenderTools

Game.RenderTools:SelectSprite(int Id, int Flags, int x, int y)
Game.RenderTools:DrawSprite(int x, int y, int Size)

Game.RenderTools:SelectSprite(int Id, int Flags, int x, int y) selects the given sprite from the loaded texture. To draw this you have to use Game.RenderTools:DrawSprite(int x, int y, int Size).

This doesn't work without a Engine.Graphics:QuadsBegin() and Engine.Graphics:TextureSet(int Texture)

Import("sprites") -- Needed library for all sprites, have a look at it's code!

Engine.Graphics:LoadTexture("data/textures/game/".. Config.tex_game ..".png",-1,-1,1) -- Load the game texture for this
										
Engine.Graphics:TextureSet(Tex)
Engine.Graphics:QuadsBegin()
	Game.RenderTools:SelectSprite(SPRITE_WEAPON_RIFLE_PROJ,0,0,0) -- Select a sprite 
	Game.RenderTools:DrawSprite(10,10,32) -- just for tests!
Engine.Graphics:QuadsEnd()
Game.RenderTools:DrawRoundRect(float x, float y, float Width, float Height, float Radius)

Game.RenderTools:DrawRoundRect(float x, float y, float Width, float Height, float Radius) draws a round rectangle with the given parameters.

This doesn't work without a Engine.Graphics:QuadsBegin() and Engine.Graphics:TextureSet(int Texture)

x = 10
y = 10
Width = 100
Height = 300
Radius = 20
Engine.Graphics:TextureSet(-1)
Engine.Graphics:QuadsBegin()
	Game.RenderTools:DrawRoundRect(x, y, Width, Height, Radius)
Engine.Graphics:QuadsEnd()
Game.RenderTools:DrawRoundRectExt(float x, float y, float Width, float Height, float Radius, int Corners)

Game.RenderTools:DrawRoundRectExt(float x, float y, float Width, float Height, float Radius, int Corners) do exactly the same like DrawRoundRect() but here you can set the Corners too!

This doesn't work without a Engine.Graphics:QuadsBegin() and Engine.Graphics:TextureSet(int Texture)

Import("ui") -- contains all the _CUI.* variables

x = 10
y = 10
Width = 100
Height = 300
Radius = 20
Engine.Graphics:TextureSet(-1)
Engine.Graphics:QuadsBegin()
	Game.RenderTools:DrawRoundRectExt(x, y, Width, Height, Radius,_CUI.CORNER_ALL)
	--[[
		Possible corners:
		_CUI.CORNER_ALL -- All corners
		
		_CUI.CORNER_T -- Both Top corners
		_CUI.CORNER_B -- Both Bottom corners
		_CUI.CORNER_L -- Both Left corners
		_CUI.CORNER_R -- Both Right corners
		
		_CUI.CORNER_TR -- Top-Right corner
		_CUI.CORNER_BR -- Bottom-Right corner
		_CUI.CORNER_TL -- Top-Left corner
		_CUI.CORNER_BL -- Bottom-Left corner
		
		_CUI.CORNER_NONE -- No corners
	]]
Engine.Graphics:QuadsEnd()
Game.RenderTools:DrawUIRect(UIRect Rect, vec4 Color, int Corners, float Rounding)

Game.RenderTools:DrawUIRect(UIRect Rect, vec4 Color, int Corners, float Rounding) draws the given Rect when the given color and corners. Userfull for debug drawing!

This doesn't work without a Engine.Graphics:QuadsBegin() and Engine.Graphics:TextureSet(int Texture)

Import("ui") -- Needed for all _CUI.* variables
Rect = UIRect(10,10,250,300)
Color = vec4(1,0,0,1) -- vec4(red,green,blue,all) (0-1 not 0-255!)
Rounding = 7 -- 7 pixel
Engine.Graphics:TextureSet(-1)
Engine.Graphics:QuadsBegin()
	Game.RenderTools:DrawUIRect(Rect, Color, _CUI.CORNER_ALL, Rounding)
	--[[
		Possible corners:
		_CUI.CORNER_ALL -- All corners
		
		_CUI.CORNER_T -- Both Top corners
		_CUI.CORNER_B -- Both Bottom corners
		_CUI.CORNER_L -- Both Left corners
		_CUI.CORNER_R -- Both Right corners
		
		_CUI.CORNER_TR -- Top-Right corner
		_CUI.CORNER_BR -- Bottom-Right corner
		_CUI.CORNER_TL -- Top-Left corner
		_CUI.CORNER_BL -- Bottom-Left corner
		
		_CUI.CORNER_NONE -- No corner
	]]
Engine.Graphics:QuadsEnd()
Game.RenderTools:DrawCircle(float x, float y, float Radius, int Segments)

Game.RenderTools:DrawCircle(float x, float y, float Radius, int Segments) draws a circle with the given parameter

This doesn't work without a Engine.Graphics:QuadsBegin() and Engine.Graphics:TextureSet(int Texture)


Game.RenderTools:RenderTee(int Emote,TeeRenderInfo TeeInfo, vec2 Dir, vec2 Pos, bool UseTeeAlpha, float AlphaLimit)

Game.RenderTools:RenderTee(int Emote,TeeRenderInfo TeeInfo, vec2 Dir, vec2 Pos, bool UseTeeAlpha, float AlphaLimit) renders a tee with the given parameters!

MyTee = TeeRenderInfo()
MyTee.Texture = Game.Players(Game.LocalCID).RenderInfo.Texture
MyTee.ColorBody = Game.Players(Game.LocalCID).RenderInfo.ColorBody
MyTee.ColorFeet = Game.Players(Game.LocalCID).RenderInfo.ColorFeet
MyTee.Size = Game.Players(Game.LocalCID).RenderInfo.Size
MyTee.GotAirJump = Game.Players(Game.LocalCID).RenderInfo.GotAirJump
Game.RenderTools:RenderTee( Game.CharSnap(Game.LocalCID).Cur.Emote, MyTee, vec2(0,0), vec2(50,50), false, 0)

Game.Chat

Game.Chat:Say(int Team, string Text, bool NoTranslator)

Game.Chat:Say(int Team, string Text, bool NoTranslator) writes the given text in the chat.

Team = 0 -- 0 = Allchat  1 = Teamchat
Text = "I didn't write this!"
NoTranslator = true -- don't let the translator try to translate it :3
Game.Chat:Say(Team, Text, NoTranslator)
-- If Team is not 1 or 0 nothing will happen!
Game.Chat:Print(int ClientID, int Team, string Text, bool Hidden)

Game.Chat:Print(int ClientID, int Team, string Text, bool Hidden) prints a line into the chat (only you can see it) with the given parameters

ClinetId = -2 -- [*Lua*] output (red)
--[[
	Custom ID's:
		-2 (or smaller) == [*Lua*]: [Text]
		-1 == *** [Text]
]]
Team = 0 -- 0 = Allchat  1 = Teamchat
Text = "Script Started"
Hidden = false -- true == changed color when a PlayerId wrotes smth (0 or above)| false == no color changes

Game.Chat:Print(ClientID, Team, Text, Hidden)
Game.Chat:AddLine(int ClientID, int Team, string Text, bool Hidden)

Game.Chat:AddLine(int ClientID, int Team, string Text, bool Hidden) does exactly the same like Game.Chat:Print()

Game.Chat.Mode

Game.Chat.Mode returns the current chat mode. All modes are listed in the code below

MyMode = Game.Chat.Mode 
--[[
	Modes:
		MODE_NONE = 0
		MODE_ALL = 1
		MODE_TEAM = 2
		MODE_HIDDEN = 3
		MODE_CRYPT = 4
]]

Game.Console

Game.Console:Print(int Level, string From, string Text, bool Highlighted)

Game.Console:Print(int Level, string From, string Text, bool Highlighted) prints a line into the console.

Level = 0 -- text will only show up if this is less than console_output_level in f1
From = "MyScript"
Text = "This is a debug console output!"
Highlighted = false -- true = red console output | false = normal color output
Game.Console:Print(Level, From, Text, Highlighted)
Game.Console:LineIsValid(string Text) -> bool

Game.Console:LineIsValid(string Text) returns a bool indication whether the given string is a valid console command (f1)

print(tostring(Game.Console:LineIsValid("Hello"))) -- > false
print(tostring(Game.Console:LineIsValid("cl_antiping"))) -- > true

Game.IRC

Game.IRC:SendMsg(string To, string Message)

Game.IRC:SendMsg(string To, string Message) send the given Text to the given User or Channel

Server = "#AllTheHaxx"
User = "YoungFlyme"
Text = "Hello ATH community ^^"
TextToUser = "Hello YoungFlyme thx for the Docs."

Game.IRC:SendMsg(Server, Text) -- Send this into the channel (name must start with a #)
Game.IRC:SendMsg(User, TextToUser) -- Send this to the user (without the #)

-- By YoungFlyme. Dec 1st, 2017
Game.IRC:JoinTo(string Server, string Password)

Game.IRC:JoinTo(string Server, string Password) joines to the given server with the given passowrd

Game.IRC:JoinTo("#MyChannel","ChannelPW") -- channel names always begin with '#'
Game.IRC:GetNick()

Game.IRC:GetNick() returns your IRC nickname

print(Game.IRC:GetNick()) -- > YoungFlyme

-- By YoungFlyme. Dec 1st, 2017

Game.Sound

Game.Sound:PlaySound()

Game.Sound:PlaySound() -------// TODO!


Game.Sound:StopSound()

Game.Sound:StopSound() -------// TODO!


Game.Sound:StopAllSounds()

Game.Sound:StopAllSounds() -------// TODO!


Game.Sound:SetChannel(int ChannelID, float Volume, float Panning)

Game.Sound:SetChannel(int ChannelID, float Volume, float Panning) -------// TODO!


Game.Sound:LoadSoundOpus()

Game.Sound:LoadSoundOpus() -------// TODO!


Game.Sound:LoadSoundWave()

Game.Sound:LoadSoundWave() -------// TODO!


Game.Sound:LoadSoundOpusMemory()

Game.Sound:LoadSoundOpusMemory() -------// TODO!


Game.Sound:LoadSoundWaveMemory()

Game.Sound:LoadSoundWaveMemory() -------// TODO!


Game.Sound:UnloadSound()

Game.Sound:UnloadSound() -------// TODO!


Game.Sound:MaxDuration()

Game.Sound:MaxDuration() -------// TODO!


Game.Emote

Game.Emote:Send(const char *pCmd)

Game.Emote:Send(const char *pCmd) -------// TODO!


Game.Emote:SendEye()

Game.Emote:SendEye() -------// TODO!


Game.Emote.Active

Game.Emote.Active -------// TODO!


Game.Collision

Game.Collision.GetMapWidth

Game.Collision.GetMapWidth -------// TODO!


Game.Collision.GetMapHeight

Game.Collision.GetMapHeight -------// TODO!


Game.Collision:Distance(vec2 s, vec2 e)

Game.Collision:Distance(vec2 s, vec2 e) -------// TODO!


Game.Collision:Normalize(vec2 v)

Game.Collision:Normalize(vec2 v) -------// TODO!


Game.Collision:ClosestPointOnLine(vec2 s, vec2 e, vec2 v)

Game.Collision:ClosestPointOnLine(vec2 s, vec2 e, vec2 v) -------// TODO!


Game.Collision:GetTile(float x, float y)

Game.Collision:GetTile(float x, float y) -------// TODO!


Game.Collision:CheckPoint(float x, float y)

Game.Collision:CheckPoint(float x, float y) -------// TODO!


Game.Collision:IntersectLine(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision)

Game.Collision:IntersectLine(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision) -------// TODO!


Game.Collision:IntersectLineTeleHook(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision, int *pTeleNr)

Game.Collision:IntersectLineTeleHook(vec2 Pos0, vec2 Pos1, vec2 *pOutCollision, vec2 *pOutBeforeCollision, int *pTeleNr) -------// TODO!


Game.Collision:MovePoint(vec2 *pInoutPos, vec2 *pInoutVel, float Elasticity, int *pBounces)

Game.Collision:MovePoint(vec2 *pInoutPos, vec2 *pInoutVel, float Elasticity, int *pBounces) -------// TODO!


Game.Collision:MoveBox(vec2 *pInoutPos, vec2 *pInoutVel, vec2 Size, float Elasticity)

Game.Collision:MoveBox(vec2 *pInoutPos, vec2 *pInoutVel, vec2 Size, float Elasticity) -------// TODO!


Game.Collision:TestBox(vec2 Pos, vec2 Size)

Game.Collision:TestBox(vec2 Pos, vec2 Size) -------// TODO!


Game.HUD

Game.HUD:PushNotification(const char *pMsg, vec4 Color = vec4(1,1,1,1))

Game.HUD:PushNotification(const char *pMsg, vec4 Color = vec4(1,1,1,1)) -------// TODO!


Game.Menus

Game.Menus.Active

Game.Menus.Active -------// TODO!


Game.Menus.ActivePage

Game.Menus.ActivePage -------// TODO!


Game.Menus.MousePos

Game.Menus.MousePos -------// TODO!


Game.Menus:ButtonColorMul(CButtonContainer *pBC)

Game.Menus:ButtonColorMul(CButtonContainer *pBC) -------// TODO!


Game.Menus:DoButton_Menu(CButtonContainer *pBC, const char *pText, int Checked, const CUIRect *pRect, const char *pTooltip = 0, int Corner = CUI::CORNER_ALL, vec4 Color = vec4(1,1,1,0.5f))

Game.Menus:DoButton_Menu(CButtonContainer *pBC, const char *pText, int Checked, const CUIRect *pRect, const char *pTooltip = 0, int Corner = CUI::CORNER_ALL, vec4 Color = vec4(1,1,1,0.5f)) -------// TODO!


Game.Menus:DoButton_MenuTab(CButtonContainer *pBC, const char *pText, int Checked, const CUIRect *pRect, int Corners, vec4 ColorActive = ms_ColorTabbarActive, vec4 ColorInactive = ms_ColorTabbarInactive, const char *pTooltip = 0)

Game.Menus:DoButton_MenuTab(CButtonContainer *pBC, const char *pText, int Checked, const CUIRect *pRect, int Corners, vec4 ColorActive = ms_ColorTabbarActive, vec4 ColorInactive = ms_ColorTabbarInactive, const char *pTooltip = 0) -------// TODO!


Game.Menus:DoButton_CheckBox(CButtonContainer *pBC, const char *pText, const char *pBoxText, const CUIRect *pRect, const char *pTooltip = 0, bool Checked = false, int Corner = CUI::CORNER_ALL)

Game.Menus:DoButton_CheckBox(CButtonContainer *pBC, const char *pText, const char *pBoxText, const CUIRect *pRect, const char *pTooltip = 0, bool Checked = false, int Corner = CUI::CORNER_ALL) -------// TODO!


Game.Menus:DoButton_Toggle(CButtonContainer *pBC, int Checked, const CUIRect *pRect, bool Active, const char *pTooltip = 0)

Game.Menus:DoButton_Toggle(CButtonContainer *pBC, int Checked, const CUIRect *pRect, bool Active, const char *pTooltip = 0) -------// TODO!


Game.Menus:DoButton_CheckBox_Number(CButtonContainer *pBC, const char *pText, int Checked, const CUIRect *pRect, const char *pTooltip = 0, int Corner = CUI::CORNER_ALL)

Game.Menus:DoButton_CheckBox_Number(CButtonContainer *pBC, const char *pText, int Checked, const CUIRect *pRect, const char *pTooltip = 0, int Corner = CUI::CORNER_ALL) -------// TODO!


Game.Menus:DoButton_Sprite(CButtonContainer *pBC, int ImageID, int SpriteID, int Checked, const CUIRect *pRect, int Corners, const char *pTooltip = 0)

Game.Menus:DoButton_Sprite(CButtonContainer *pBC, int ImageID, int SpriteID, int Checked, const CUIRect *pRect, int Corners, const char *pTooltip = 0) -------// TODO!


Game.Menus:DoScrollbarV(CButtonContainer *pBC, const CUIRect *pRect, float Current, const char *pTooltip = 0, int Value = ~0, int LenPercent = ~0)

Game.Menus:DoScrollbarV(CButtonContainer *pBC, const CUIRect *pRect, float Current, const char *pTooltip = 0, int Value = ~0, int LenPercent = ~0) -------// TODO!


Game.Menus:DoScrollbarH(CButtonContainer *pBC, const CUIRect *pRect, float Current, const char *pTooltip = 0, int Value = ~0, int LenPercent = ~0)

Game.Menus:DoScrollbarH(CButtonContainer *pBC, const CUIRect *pRect, float Current, const char *pTooltip = 0, int Value = ~0, int LenPercent = ~0) -------// TODO!


Game.Menus:DoEditbox()

Game.Menus:DoEditbox() -------// TODO!


Game.Menus:DoColorPicker(const CButtonContainer *pBC1, const CButtonContainer *pBC2, const CUIRect *pView, vec3 *pColorHSV)

Game.Menus:DoColorPicker(const CButtonContainer *pBC1, const CButtonContainer *pBC2, const CUIRect *pView, vec3 *pColorHSV) -------// TODO!


Game.Voting

Game.Voting:CallvoteSpectate(int ClientID, const char *pReason, bool ForceVote = false)

Game.Voting:CallvoteSpectate(int ClientID, const char *pReason, bool ForceVote = false) -------// TODO!


Game.Voting:CallvoteKick(int ClientID, const char *pReason, bool ForceVote = false)

Game.Voting:CallvoteKick(int ClientID, const char *pReason, bool ForceVote = false) -------// TODO!


Game.Voting:CallvoteOption(int OptionID, const char *pReason, bool ForceVote = false)

Game.Voting:CallvoteOption(int OptionID, const char *pReason, bool ForceVote = false) -------// TODO!


Game.Voting:Vote(IConsole::IResult *pResult, void *pUserData)

Game.Voting:Vote(IConsole::IResult *pResult, void *pUserData) -------// TODO!


Game.Voting:VoteYes()

Game.Voting:VoteYes() -------// TODO!


Game.Voting:VoteNo()

Game.Voting:VoteNo() -------// TODO!


Game.Voting.VoteDescription

Game.Voting.VoteDescription -------// TODO!


Game.Voting.VoteReason

Game.Voting.VoteReason -------// TODO!


Game.Voting.SecondsLeft

Game.Voting.SecondsLeft -------// TODO!


Game.Voting.IsVoting

Game.Voting.IsVoting -------// TODO!


Game.Voting.TakenChoice

Game.Voting.TakenChoice -------// TODO!


Game.Voting.Yes

Game.Voting.Yes -------// TODO!


Game.Voting.No

Game.Voting.No -------// TODO!


Game.Voting.Pass

Game.Voting.Pass -------// TODO!


Game.Voting.Total

Game.Voting.Total -------// TODO!


Game.CharSnap(ID).Cur

Game.CharSnap(ID).Cur.example

Game.CharSnap(ID).Cur.example example



-- By YoungFlyme. Dec 1st, 2017
Game.CharSnap(ID).Cur.example

Game.CharSnap(ID).Cur.example example



-- By YoungFlyme. Dec 1st, 2017
Game.CharSnap(ID).Cur.example

Game.CharSnap(ID).Cur.example example



-- By YoungFlyme. Dec 1st, 2017
Game.CharSnap(ID).Cur.example

Game.CharSnap(ID).Cur.example example



-- By YoungFlyme. Dec 1st, 2017
Game.CharSnap(ID).Cur.example

Game.CharSnap(ID).Cur.example example



-- By YoungFlyme. Dec 1st, 2017
Game.CharSnap(ID).Cur.example

Game.CharSnap(ID).Cur.example example



-- By YoungFlyme. Dec 1st, 2017
Game.CharSnap(ID).Cur.example

Game.CharSnap(ID).Cur.example example



-- By YoungFlyme. Dec 1st, 2017

Game.Snap:PlayerInfos(ID)

Game.Snap:PlayerInfos(ID).example

Game.Snap:PlayerInfos(ID).example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:PlayerInfos(ID).example

Game.Snap:PlayerInfos(ID).example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:PlayerInfos(ID).example

Game.Snap:PlayerInfos(ID).example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:PlayerInfos(ID).example

Game.Snap:PlayerInfos(ID).example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:PlayerInfos(ID).example

Game.Snap:PlayerInfos(ID).example example



-- By YoungFlyme. Dec 1st, 2017

Game.Players(ID).Tee

and

Game.LocalTee

Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee.example and Game.LocalTee.example

Game.Snap:PlayerInfos(ID).example and Game.LocalTee.example example



-- By YoungFlyme. Dec 1st, 2017
Game.Snap:Players(ID).Tee:example() and Game.LocalTee:example()

Game.Snap:PlayerInfos(ID):example() and Game.LocalTee:example() example



-- By YoungFlyme. Dec 1st, 2017

Game.Tuning()

Game.Tuning().example

Game.Snap:PlayerInfos(ID):example() and Game.LocalTee:example() example



-- By YoungFlyme. Dec 1st, 2017

Game.Input

Game.ServerInfo

Game.Snap

Game.CharSnap(ID)

Game.SpecInfo

Game.Players(ID)

Engine.Input

Engine.Curl

Engine.Graphics

Engine.TextRender

Engine.Storage

Callouts

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo.

Aenean imperdiet

Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium <code> , Nemo enim ipsam voluptatem quia voluptas link example sit aspernatur aut odit aut fugit.

Morbi posuere

Nunc hendrerit odio quis dignissim efficitur. Proin ut finibus libero. Morbi posuere fringilla felis eget sagittis. Fusce sem orci, cursus in tortor link example tellus vel diam viverra elementum.

Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Link example aenean commodo ligula eget dolor.

Interdum et malesuada

Morbi eget interdum sapien. Donec sed turpis sed nulla lacinia accumsan vitae ut tellus. Aenean vestibulum Link example maximus ipsum vel dignissim. Morbi ornare elit sit amet massa feugiat, viverra dictum ipsum pellentesque.

Tables

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis.

Basic Table
# First Name Last Name Username
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter
Bordered Table
# First Name Last Name Username
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter
Striped Table
# First Name Last Name Username
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter

Buttons

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi nec imperdiet turpis. Curabitur aliquet pulvinar ultrices. Etiam at posuere leo. Proin ultrices ex et dapibus feugiat link example aenean purus leo, faucibus at elit vel, aliquet scelerisque dui. Etiam quis elit euismod, imperdiet augue sit amet, imperdiet odio. Aenean sem erat, hendrerit eu gravida id, dignissim ut ante. Nam consequat porttitor libero euismod congue.

Icons

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi nec imperdiet turpis. Curabitur aliquet pulvinar ultrices. Etiam at posuere leo. Proin ultrices ex et dapibus feugiat link example aenean purus leo, faucibus at elit vel, aliquet scelerisque dui. Etiam quis elit euismod, imperdiet augue sit amet, imperdiet odio. Aenean sem erat, hendrerit eu gravida id, dignissim ut ante. Nam consequat porttitor libero euismod congue.

Elegant Icon Font
elegant icons
FontAwesome Icon Font
fontawesome

AppKit - Bootstrap Angular Admin Theme for Developers

AppKit Theme

Love this free documentation theme?

Check out AppKit - an Angular admin theme I created with my developer friend Tom Najdek for developers. AppKit uses modern front-end technologies and is packed with useful components and widgets to speed up your app development.

[Tip for developers]: If your project is Open Source, you can use this area to promote your other projects or hold third party adverts like Bootstrap and FontAwesome do!