LUA Scripting Guide

This is a short documentation on the various parts of LUA scripting in Dota 2. You can refer to the API documentation for specific functions/game events etc.

Addon Initialization

When the server starts up and loads your game mode, it will first execute addon_init.lua. In the bootstrapped addon, addon_init.lua will require util, physics, and finally your game mode lua file at the end of the script.

Next, when the server is ready to create your game mode instance, it will execute addon_game_mode.lua, which, in the bootstrapper, will simply call InitGameMode() on your game mode defined in gamemode.lua.

Lua Scope

Any variables defined in the root of the script, without the local tag, will be considered global and accessible anywhere in any lua file loaded into the Dota 2 Lua VM.

You will generally want to use the local tag before variables so you don’t pollute the global scope.

Game Mode Class

Game modes are Lua objects/tables, defined as such:

TeamFightGameMode = {}
TeamFightGameMode.szEntityGameMode = "gamemode"
TeamFightGameMode.szNativeClassName = "dota_base_game_mode"
TeamFightGameMode.__index = TeamFightGameMode

This definition block occurs in gamemode.lua, which will be named according to your mod’s name.

Next, the functions that the mode requires are defined on the game mode table/object, for example:

function TeamFightGameMode:InitGameMode()

Registering Hooks

Most of the logic in the lua game mode code revolves around hooking into the game’s standard events.

For example, to perform some logic when a player says something, register the hook in the game mode init:

ListenToGameEvent('player_say', Dynamic_Wrap(TeamFightGameMode, 'PlayerSay'), self)

Here, we ask the Lua engine to call TeamFightGameMode:PlayerSay(keys) when the player_say game event is fired.

Next, define your implementation:

function TeamFightGameMode:PlayerSay(keys)
  local ply = self.vUserIds[keys.userid]

In this case, keys is a table/object with relevant data to the say event, such as the text of the message.

You can view the full API in the API docs sections.


To put off execution of some code into some seconds in the future, you can register a timer with a unique ID generated by DoUniqueString:

TeamFightGameMode:CreateTimer(DoUniqueString("dothislater"), {
  endTime = GameRules:GetGameTime() + 3,
  useGameTime = true,
  callback = function(teamfight, args)
    Log("Three... seconds... later...")

Here, you pass in the ID of the timer (a unique string starting with dothislater, which can be any unique string) and an object with options. In this case, the callback will be called when the game time is greater than endTime, which is set to the current game time plus three seconds. Game time or server time can be used, where server time based timers will tick even while the game is paused.