<html>
<head>
<title>ETPub Lua API Documentation</title>
<style type="text/css">
dt {
font-weight: bold;
}
body {
font: x-small sans-serif;
color: black;
}
h1, h2, h3, h4, h5, h6 {
color: black;
background: none;
font-weight: normal;
margin: 0;
padding-top: .5em;
padding-bottom: .17em;
border-bottom: 1px solid #aaa;
}
h1 { font-size: 188%; }
h2 { font-size: 150%; }
h3, h4, h5, h6 {
border-bottom: none;
font-weight: bold;
}
h3 { font-size: 132%; }
h4 { font-size: 116%; }
h5 { font-size: 100%; }
h6 {
font-size: 80%;
color: #2f6fab;
margin-left: .5em;
margin-top: 20px;
}
b {
font-weight: normal;
color: #b00;
}
i.diff {
border-bottom: 1px dashed #b00;
}
pre {
font-size: 9pt;
margin-top: 0;
padding: 1em;
border: 1px dashed #2f6fab;
color: black;
background-color: #f9f9f9;
line-height: 1.1em;
margin-bottom: 20px;
}
table.border {
margin-top: 0;
padding: 1em;
border: 1px dashed #2f6fab;
color: black;
background-color: #f9f9f9;
line-height: 1.1em;
margin-bottom: 20px;
}
.list th {
font-family: monospace;
font-size: 9pt;
color: white;
padding: 0px 10px;
text-align: left;
}
.list td {
font-family: monospace;
font-size: 9pt;
padding: 0px 10px;
color: black;
}
</style>
</head>
<body>
<h2>ETPUB LUA API DOCUMENTATION</h2>
<p>etpub's Lua API is aiming to be fully compatible to etpro's Lua API. Differences between etpub's and etpro's Lua API are described in this documentation.</p>
<p><b>*</b><i class="diff">Marks differences between etpub's and etpro's Lua API</i></p>
<a name="commands"></a><h2>LUA RESOURCES</h2>
<ul>
<li>The Programming Language Lua: <a href="http://www.lua.org/">http://www.lua.org/</a></li>
<li>etpro's Lua API documentation: <a href="http://wolfwiki.anime.net/index.php/Lua_Mod_API">http://wolfwiki.anime.net/index.php/Lua_Mod_API</a></li>
</ul>
<a name="commands"></a><h2>COMMANDS</h2>
<a name="client_commands"></a><h3>Client Commands</h3>
<a name="lua_status"></a><p><strong>lua_status</strong></p>
<dl>
<dd>Lists all currently loaded lua modules.</dd>
<dd> </dd>
<dd><i>Lua modules cannot override this client command.</i></dd>
</dl>
<a name="server_commands"></a><h3>Server Commands</h3>
<a name="lua_status2"></a><p><strong>lua_status</strong></p>
<dl>
<dd>Lists all currently loaded lua modules.</dd>
</dl>
<a name="cvars"></a><h2>CVARS</h2>
<a name="server_cvars"></a><h3>Server Cvars</h3>
<a name="lua_modules"></a><p><strong>lua_modules</strong></p>
<dl>
<dd>Space separated list of lua modules for ETPub to load. Modules will be run in the order listed.</dd>
<dd> </dd>
<dd><i>Default is "" (Disabled)</i></dd>
</dl>
<a name="lua_allowedmodules"></a><p><strong>lua_allowedModules</strong></p>
<dl>
<dd>If set, only lua modules with the matching sha1 signatures listed in this cvar will be allowed to load.</dd>
<dd> </dd>
<dd><i>Default is "" (Disabled)</i></dd>
</dl>
<p>Changing either cvar will cause all currently loaded modules to quit and be unloaded until the next <i>map_restart</i>, <i>reset_match</i> or map change.</p>
<a name="et_library_calls"></a><h2>ET LIBRARY CALLS</h2>
<a name="clients"></a><h3>Clients</h3>
<p><p><b>*</b><i class="diff"><strong>clientnum</strong> = et.G_ClientNumberFromString( <strong>string</strong> )</i></p>
<dl>
<dd>Searches for one partial match with <strong>string</strong>. If one is found the <strong>clientnum</strong> is returned. If there is none or more than one match <strong>-1</strong> is returned.</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>-- get number from client with partial name match 'ETPla'
clientnum = et.G_ClientNumberFromString("ETPla")</pre></dd>
</dl>
<a name="et_filesystem"></a><h3>ET Filesystem</h3>
<p><strong>fd</strong>, <strong>len</strong> = et.trap_FS_FOpenFile( <strong>filename</strong>, <strong>mode</strong> )</p>
<dl>
<dd>Attempts to open the file <strong>filename</strong> with the access mode <strong>mode</strong> (see <a href="#predefined_constants">et.FS_* constants</a>). Returns the filedescriptor <strong>fd</strong> and file length <strong>len</strong>. On error, <strong>len</strong> returns -1.</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>fd, len = et.trap_FS_FOpenFile("mymodule.log", et.FS_READ)</pre></dd>
</dl>
<p><strong>filedata</strong> = et.trap_FS_Read( <strong>fd</strong>, <strong>count</strong> )</p>
<dl>
<dd>Reads <strong>count</strong> bytes from filedescriptor <strong>fd</strong>.</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>fd, len = et.trap_FS_FOpenFile("mymodule.log", et.FS_READ)
if len ~= -1 then
filedata = et.trap_FS_Read(fd, len)
end
et.trap_FS_FCloseFile(fd)</pre></dd>
</dl>
<p><strong>count</strong> = et.trap_FS_Write( <strong>filedata</strong>, <strong>count</strong>, <strong>fd</strong> )</p>
<dl>
<dd>Attempts to write <strong>count</strong> bytes of <strong>filedata</strong> to filedescriptor <strong>fd</strong>. Returns number of bytes (<strong>count</strong>) successfully written.</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>fd, len = et.trap_FS_FOpenFile("mymodule.log", et.FS_APPEND)
content = "MODEVENT: X Y: Player X does something with player Y.\n"
if len ~= -1 then
count = et.trap_FS_Write(content, string.len(content), fd)
end
et.trap_FS_FCloseFile(fd)</pre></dd>
</dl>
<p>et.trap_FS_Rename( <strong>oldname</strong>, <strong>newname</strong> )</p>
<dl>
<dd>Renames file <strong>oldname</strong> to <strong>newname</strong>.</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>et.trap_FS_Rename("mymodule.log", "mymodule.bak")</pre></dd>
</dl>
<p>et.trap_FS_FCloseFile( <strong>fd</strong> )</p>
<dl>
<dd>Closes filedescriptor <strong>fd</strong>.</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>fd, len = et.trap_FS_FOpenFile("mymodule.log", et.FS_READ)
-- read file content here
et.trap_FS_FCloseFile(fd)</pre></dd>
</dl>
<a name="sound"></a><h3>Sound</h3>
<p><p><b>*</b><i class="diff">et.G_ClientSound( <strong>clientnum</strong>, <strong>soundindex</strong> )</i></p>
<dl>
<dd>Plays the sound <strong>soundindex</strong> for the client with <strong>clientnum</strong> only.</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>-- play a sound for client #3 only
soundindex = et.G_SoundIndex("sound/world/alarm_01.wav")
et.G_ClientSound(3, soundindex)</pre></dd>
</dl>
<a name="miscellaneous"></a><h3>Miscellaneous</h3>
<p><strong>milliseconds</strong> = et.trap_Milliseconds()</p>
<dl>
<dd>Returns a number (<strong>milliseconds</strong>) indicating the current server time in milliseconds.</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>milliseconds = et.trap_Milliseconds()</pre></dd>
</dl>
<p>et.G_Damage( <strong>target</strong>, <strong>inflictor</strong>, <strong>attacker</strong>, <strong>damage</strong>, <strong>dflags</strong>, <strong>mod</strong> )</p>
<dl>
<dd>Does amount of <strong>damage</strong> on <strong>target</strong> inflicted by <strong>inflictor</strong> and cased by <strong>attacker</strong>.</dd>
<dd> </dd>
<dd>- <strong>target</strong>, <strong>inflictor</strong> and <strong>attacker</strong> are entity numbers.</dd>
<dd>- <strong>dflags</strong> is a bitflag number to decide how the damage is inflicted.</dd>
<dd>- <strong>mod</strong> is a number from 0 up to <b>*</b><i class="diff">69</i> to set the type of damage.</dd>
<dd> </dd>
<dd>Damage flags are bitflags with the following available bits.</dd>
<dd><h6>DFLAGS AVAILABLE BITS</h6>
<table class="border">
<tr><td>
<table border='0' class="list">
<tr bgcolor='#888888'><th width="50">Bit</th><th width="200">Type</th><th>Description</th></tr>
<tr><td>1</td><td>DAMAGE_RADIUS</td><td>damage was indirect</td></tr>
<tr bgcolor="#d7d7d7"><td>2</td><td>DAMAGE_HALF_KNOCKBACK</td><td>do less knockback</td></tr>
<tr><td>8</td><td>DAMAGE_NO_KNOCKBACK</td><td>do not affect velocity, just view angles</td></tr>
<tr bgcolor="#d7d7d7"><td>16</td><td>DAMAGE_NO_TEAM_PROTECTION</td><td>armor, shields, invulnerability, and godmode have no effect</td></tr>
<tr><td>32</td><td>DAMAGE_NO_PROTECTION</td><td>armor, shields, invulnerability, and godmode have no effect</td></tr>
<tr bgcolor="#d7d7d7"><td>64</td><td>DAMAGE_DISTANCEFALLOFF</td><td>distance falloff</td></tr>
</table>
</td></tr>
</table>
</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>-- do 50 damage with no protection (dflags = 32) on client #0
-- with MOD_UNKNOWN (mod = 0) as <world> entity (inflictor, attacker = 1022)
et.G_Damage(0, 1022, 1022, 50, 32, 0)</pre></dd>
</dl>
<p><b>*</b><i class="diff"><strong>flooding</strong> = et.ClientIsFlooding( <strong>clientnum</strong> )</i></p>
<dl>
<dd>Checks if client <strong>clientnum</strong> is <strong>flooding</strong> (1) or not (0).</dd>
<dd> </dd>
<dd>Note: There will be done no update to the flood protect behaviour on running this library call. ETPub only checks on <i>callvote</i>, <i>say</i>, <i>m</i>, <i>mt</i>, <i>ma</i>, <i>say_team</i>, <i>vsay</i>, <i>vsay_team</i>, <i>say_buddy</i>, <i>vsay_buddy</i>, <i>fireteam</i>, <i>rconAuth</i>, <i>ready</i>, <i>say_teamnl</i>, <i>specinvite</i>, <i>readyteam</i> client commands for flooding.</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>if et.ClientIsFlooding(clientnum) == 1 then
-- client is flooding, do something
end</pre></dd>
</dl>
<p><b>*</b><i class="diff">et.G_AddSkillPoints( <strong>ent</strong>, <strong>skill</strong>, <strong>points</strong> )</i></p>
<dl>
<dd>Note: To remove skill points you can also use negative <strong>points</strong> values.</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>-- add 100.5 points to heavy weapons skill (skill = 5) of client #0
et.G_AddSkillPoints(0, 5, 100.5)</pre></dd>
</dl>
<p><b>*</b><i class="diff">et.G_LoseSkillPoints( <strong>ent</strong>, <strong>skill</strong>, <strong>points</strong> )</i></p>
<dl>
<dd><h6>LUA CODE EXAMPLE</h6><pre>-- remove 100.5 points from heavy weapons skill (skill = 5) of client #0
et.G_LoseSkillPoints(0, 5, 100.5)</pre></dd>
</dl>
<a name="entities"></a><h3>Entities</h3>
<p><strong>(variable)</strong> = et.gentity_get ( <strong>entnum</strong>, <strong>fieldname</strong><i>, <strong>arrayindex</strong></i> )</p>
<dl>
<dd>Gets the value of <strong>fieldname</strong> from entity <strong>entnum</strong> out of the g_entity struct. For NULL entities, <i>nil</i> is returned.</dd>
<dd><i><strong>arrayindex</strong></i> is used to specify which element of an array entity field to get. It is required when accessing array type fields. Entity field array indexes start at 0.</dd>
</dl>
<p>et.gentity_set( <strong>entnum</strong>, <strong>fieldname</strong><i>, <strong>arrayindex</strong></i>, <strong>value</strong> )</p>
<dl>
<dd>Sets the value of <strong>fieldname</strong> from entity <strong>entnum</strong> in the g_entity struct to <strong>value</strong>.</dd>
<dd><i><strong>arrayindex</strong></i> is used to specify which element of an array entity field to set.</dd>
</dl>
<a name="shrubbot"></a><h3>Shrubbot</h3>
<p><b>*</b><i class="diff"><strong>permission</strong> = et.G_shrubbot_permission( <strong>ent</strong>, <strong>flag</strong> )</i></p>
<dl>
<dd>Checks if client <strong>ent</strong> has <strong>permission</strong> (1) for <strong>flag</strong> or not (0).</dd>
<dd> </dd>
<dd>Note: Use <i>nil</i> or <i>-1</i> to check permission for console (Console always returns 1!).</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>-- check if client #1 has permission for flag "C"
if et.G_shrubbot_permission(1, "C") == 1 then
-- client has permission, do something
end</pre></dd>
</dl>
<p><b>*</b><i class="diff"><strong>level</strong> = et.G_shrubbot_level( <strong>ent</strong> )</i></p>
<dl>
<dd>Returns the <strong>level</strong> for client <strong>ent</strong>.</dd>
<dd> </dd>
<dd>Note: Use <i>nil</i> or <i>-1</i> to get the level for console.</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>-- get shrubbot level for client #2
level = et.G_shrubbot_level(2)</pre></dd>
</dl>
<a name="callbacks"></a><h2>CALLBACKS</h2>
<a name="qagame_execution"></a><h3>qagame Execution</h3>
<a name="client_management"></a><h3>Client Management</h3>
<p>et_ClientSpawn( <strong>clientNum</strong>, <strong>revived</strong>, <b>*</b><i class="diff"><strong>teamChange</strong></i>, <b>*</b><i class="diff"><strong>restoreHealth</strong></i> )</p>
<!--<dl>
<dd>Called when a client is spawned. <b>clientNum</b> is the client slot id. <b>revived</b> is 1 if the client was spawned by being revived.</dd>
</dl>-->
<a name="commands"></a><h3>Commands</h3>
<p><strong>intercepted</strong> = et_ClientCommand( <strong>clientNum</strong>, <strong>command</strong> )</p>
<!--<dl>
<dd>Called when a command is received from a client. <b>clientNum</b> is the client slot id. <b>command</b> is the command. The mod should return 1 if the command was intercepted by the mod, and 0 if the command was ignored by the mod and should be passed through to the server (and other mods in the chain).</dd>
<dd>The actual command can be accessed through the <a href="#argument_handling" title="">argument handling</a> functions, as seen in the <a href="/index.php/ETPro:Lua_Sample_Code" title="ETPro:Lua Sample Code">ETPro:Lua Sample Code</a>.</dd>
</dl>-->
<p><strong>intercepted</strong> = et_ConsoleCommand( <b>*</b><i class="diff"><strong>command</strong></i> )</p>
<!--<dl>
<dd>Called when a command is entered on the server console. The mod should return 1 if the command was intercepted by the mod, and 0 if the command was ignored by the mod and should be passed through to the server (and other mods in the chain).</dd>
<dd>The actual command can be accessed through the <a href="#argument_handling" title="">argument handling</a> functions, as seen in the <a href="/index.php/ETPro:Lua_Sample_Code" title="ETPro:Lua Sample Code">ETPro:Lua Sample Code</a>.</dd>
</dl>-->
<a name="miscellaneous2"></a><h3>Miscellaneous</h3>
<p>(<strong>customObit</strong>) = et_Obituary( <strong>victim</strong>, <strong>killer</strong>, <strong>meansOfDeath</strong> )</p>
<dl>
<dd>Called whenever a player is killed. <b>*</b><i class="diff">Modules should return a string (<strong>customObit</strong>) to override the default obituary or <strong>nil</strong> to leave it as it is.</i></dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>function et_Obituary(victim, killer, meansOfDeath)
if victim == killer and meansOfDeath == 26 then
customObit = "%s ^7had an ^1EXPLOSIVE ^7relationship with his dynamite."
return string.format(customObit, et.gentity_get(victim, "pers.netname"))
end
end</pre></dd>
</dl>
<a name="predefined_constants"></a><h2>PREDEFINED CONSTANTS</h2>
<p><b>*</b><i class="diff">et.CS_PLAYERS</i><br />
et.EXEC_NOW<br />
et.EXEC_INSERT<br />
et.EXEC_APPEND<br />
et.FS_READ<br />
et.FS_WRITE<br />
et.FS_APPEND<br />
et.FS_APPEND_SYNC<br />
et.SAY_ALL<br />
et.SAY_TEAM<br />
et.SAY_BUDDY<br />
et.SAY_TEAMNL<br />
<br />
et.HOSTARCH</p>
<dl>
<dd>Set to WIN32 or UNIX depending on the host architecture qagame is running on.</dd>
</dl>
<p><b>*</b><i class="diff">LUA_PATH</i></p>
<dl>
<dd>Set to <i>fs_homepath/fs_game/?.lua;fs_homepath/fs_game/lualibs/?.lua</i> in order to ease use of the <a href="http://www.lua.org/pil/8.1.html" title="http://www.lua.org/pil/8.1.html" rel="nofollow" target="_blank">require</a> function. Depending on the configuration <i>fs_basepath/fs_game/?.lua;fs_basepath/fs_game/lualibs/?.lua</i> will be added to the LUA_PATH.</dd>
</dl>
<p><b>*</b><i class="diff">LUA_CPATH</i></p>
<dl>
<dd>Set to <i>fs_homepath/fs_game/lualibs/?.(so|dll)</i> in order to ease use of the <a href="http://www.lua.org/pil/8.1.html" title="http://www.lua.org/pil/8.1.html" rel="nofollow" target="_blank">require</a> function. Depending on the configuration <i>fs_basepath/fs_game/lualibs/?.(so|dll)</i> will be added to the LUA_CPATH.</dd>
</dl>
<p><b>*</b><i class="diff">LUA_DIRSEP</i></p>
<dl>
<dd>Set to \ or / depending on the host architecture qagame is running on.</dd>
</dl>
<a name="config"></a><h2>CONFIG</h2>
<p> </p>
<a name="et_variable_types"></a><h2>ET VARIABLE TYPES</h2>
<a name="vec3"></a><h3>vec3</h3>
<dl>
<dd>A <strong>vec3</strong> is a 3-element array of numbers. It is usually used to store and
process coordinates in 3D space. In lua a vector is an array (table indexed by integers)
containing 3 numbers. It can be accessed by doing:</dd>
<dd><h6>LUA CODE EXAMPLE</h6><pre>origin = et.gentity_get(entNum, "origin")
x, y, z = origin[1], origin[2], origin[3]</pre></dd>
</dl>
<a name="trajectory"></a><h3>trajectory</h3>
<dl>
<dd>A