## ETPUB LUA API DOCUMENTATION

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.

*Marks differences between etpub's and etpro's Lua API

## LUA RESOURCES

- The Programming Language Lua: http://www.lua.org/
- etpro's Lua API documentation: http://wolfwiki.anime.net/index.php/Lua_Mod_API

## COMMANDS

### Client Commands

lua_status

  Lists all currently loaded lua modules.
  Lua modules cannot override this client command.

### Server Commands

lua_status

  Lists all currently loaded lua modules.

## CVARS

### Server Cvars

lua_modules

  Space separated list of lua modules for ETPub to load. Modules will be run in the order listed.
  Default is "" (Disabled)

lua_allowedModules

  If set, only lua modules with the matching sha1 signatures listed in this cvar will be allowed to load.
  Default is "" (Disabled)

Changing either cvar will cause all currently loaded modules to quit and be unloaded until the next map_restart, reset_match or map change.

## ET LIBRARY CALLS

### Clients

*clientnum = et.G_ClientNumberFromString( string )

  Searches for one partial match with string. If one is found the clientnum is returned. If there is none or more than one match -1 is returned.

  ###### LUA CODE EXAMPLE

      -- get number from client with partial name match 'ETPla'
      clientnum = et.G_ClientNumberFromString("ETPla")

### ET Filesystem

fd, len = et.trap_FS_FOpenFile( filename, mode )

  Attempts to open the file filename with the access mode mode (see et.FS_* constants). Returns the filedescriptor fd and file length len. On error, len returns -1.

  ###### LUA CODE EXAMPLE

      fd, len = et.trap_FS_FOpenFile("mymodule.log", et.FS_READ)

filedata = et.trap_FS_Read( fd, count )

  Reads count bytes from filedescriptor fd.

  ###### LUA CODE EXAMPLE

      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)

count = et.trap_FS_Write( filedata, count, fd )

  Attempts to write count bytes of filedata to filedescriptor fd. Returns number of bytes (count) successfully written.

  ###### LUA CODE EXAMPLE

      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)

et.trap_FS_Rename( oldname, newname )

  Renames file oldname to newname.

  ###### LUA CODE EXAMPLE

      et.trap_FS_Rename("mymodule.log", "mymodule.bak")

et.trap_FS_FCloseFile( fd )

  Closes filedescriptor fd.

  ###### LUA CODE EXAMPLE

      fd, len = et.trap_FS_FOpenFile("mymodule.log", et.FS_READ)

      -- read file content here

      et.trap_FS_FCloseFile(fd)

### Sound

*et.G_ClientSound( clientnum, soundindex )

  Plays the sound soundindex for the client with clientnum only.

  ###### LUA CODE EXAMPLE

      -- play a sound for client #3 only
      soundindex = et.G_SoundIndex("sound/world/alarm_01.wav")
      et.G_ClientSound(3, soundindex)

### Miscellaneous

milliseconds = et.trap_Milliseconds()

  Returns a number (milliseconds) indicating the current server time in milliseconds.

  ###### LUA CODE EXAMPLE

      milliseconds = et.trap_Milliseconds()

et.G_Damage( target, inflictor, attacker, damage, dflags, mod )

  Does amount of damage on target inflicted by inflictor and cased by attacker.
  - target, inflictor and attacker are entity numbers.
  - dflags is a bitflag number to decide how the damage is inflicted.
  - mod is a number from 0 up to *69 to set the type of damage.

  ###### LUA CODE EXAMPLE

      -- 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)

  ###### DFLAGS LIST

      DAMAGE_RADIUS                  1 // damage was indirect
      DAMAGE_HALF_KNOCKBACK          2 // do less knockback
      DAMAGE_NO_KNOCKBACK            8 // do not affect velocity, just view angles
      DAMAGE_NO_TEAM_PROTECTION     16 // armor, shields, invulnerability, and godmode have no effect
      DAMAGE_NO_PROTECTION          32 // armor, shields, invulnerability, and godmode have no effect
      DAMAGE_DISTANCEFALLOFF        64 // distance falloff

*flooding = et.ClientIsFlooding( clientnum )

  Checks if client clientnum is flooding (1) or not (0).
  Note: There will be done no update to the flood protect behaviour on running this library call. ETPub only checks on callvote, say, m, mt, ma, say_team, vsay, vsay_team, say_buddy, vsay_buddy, fireteam, rconAuth, ready, say_teamnl, specinvite, readyteam client commands for flooding.

  ###### LUA CODE EXAMPLE

      if et.ClientIsFlooding(clientnum) == 1 then
      	-- client is flooding, do something
      end

*et.G_AddSkillPoints( ent, skill, points )

  Note: To remove skill points you can also use negative points values.

  ###### LUA CODE EXAMPLE

      -- add 100.5 points to heavy weapons skill (skill = 5) of client #0
      et.G_AddSkillPoints(0, 5, 100.5)

*et.G_LoseSkillPoints( ent, skill, points )

  ###### LUA CODE EXAMPLE

      -- remove 100.5 points from heavy weapons skill (skill = 5) of client #0
      et.G_LoseSkillPoints(0, 5, 100.5)

### Entities

(variable) = et.gentity_get ( entnum, fieldname, arrayindex )

  Gets the value of fieldname from entity entnum out of the g_entity struct. For NULL entities, nil is returned.
  arrayindex 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.

et.gentity_set( entnum, fieldname, arrayindex, value )

  Sets the value of fieldname from entity entnum in the g_entity struct to value.
  arrayindex is used to specify which element of an array entity field to set.

### Shrubbot

*permission = et.G_shrubbot_permission( ent, flag )

  Checks if client ent has permission (1) for flag or not (0).
  Note: Use nil or -1 to check permission for console (Console always returns 1!).

  ###### LUA CODE EXAMPLE

      -- check if client #1 has permission for flag "C"
      if et.G_shrubbot_permission(1, "C") == 1 then
      	-- client has permission, do something
      end

*level = et.G_shrubbot_level( ent )

  Returns the level for client ent.
  Note: Use nil or -1 to get the level for console.

  ###### LUA CODE EXAMPLE

      -- get shrubbot level for client #2
      level = et.G_shrubbot_level(2)

## CALLBACKS

### qagame Execution

### Client Management

et_ClientSpawn( clientNum, revived, *teamChange, *restoreHealth )

### Commands

intercepted = et_ClientCommand( clientNum, command )

intercepted = et_ConsoleCommand( *command )

### Miscellaneous

(customObit) = et_Obituary( victim, killer, meansOfDeath )

  Called whenever a player is killed. *Modules should return a string (customObit) to override the default obituary or nil to leave it as it is.

  ###### LUA CODE EXAMPLE

      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

## PREDEFINED CONSTANTS

*et.CS_PLAYERS
et.EXEC_NOW
et.EXEC_INSERT
et.EXEC_APPEND
et.FS_READ
et.FS_WRITE
et.FS_APPEND
et.FS_APPEND_SYNC
et.SAY_ALL
et.SAY_TEAM
et.SAY_BUDDY
et.SAY_TEAMNL
et.HOSTARCH

  Set to WIN32 or UNIX depending on the host architecture qagame is running on.

*LUA_PATH

  Set to fs_homepath/fs_game/?.lua;fs_homepath/fs_game/lualibs/?.lua in order to ease use of the require function. Depending on the configuration fs_basepath/fs_game/?.lua;fs_basepath/fs_game/lualibs/?.lua will be added to the LUA_PATH.

*LUA_CPATH

  Set to fs_homepath/fs_game/lualibs/?.(so|dll) in order to ease use of the require function. Depending on the configuration fs_basepath/fs_game/lualibs/?.(so|dll) will be added to the LUA_CPATH.

*LUA_DIRSEP

  Set to \ or / depending on the host architecture qagame is running on.

## CONFIG

## CAVEATS

Like qagame, lua modules are unloaded and reloaded on map_restart and map changes. This means that all global variables and other information is lost. Modules may choose to store persistent data in cvars or external files.

## FAQ

Q: OMG I hate the libary prefix et.* on everything!
A: Use the following code to remove the prefix:

  ###### LUA CODE EXAMPLE

      table.foreach(et, function(func, value) _G[func] = value; end)

Q: How do I reload my lua module without restarting the whole server?
A: Use map_restart, reset_match or simply change the map.

Q: OMG my lua module doesn't work!
A: Make sure you added your module's filename to the lua_modules cvar (e.g. set lua_modules "mymodule.lua").