Lunatic User Manual =================== Helixhorned :max-width: 56em :numbered: :icons: Introduction ------------ Language -------- :Lua51: http://www.lua.org/about.html :Lua51Ref: http://www.lua.org/manual/5.1/ :PiL: http://www.lua.org/docs.html :LuaJIT: http://luajit.org :LuaJIText: http://luajit.org/extensions.html The base language for writing Lunatic user code is {Lua51}[Lua 5.1]. It is extensively documented in a {Lua51Ref}[Reference Manual], as well as described more broadly and accessibly in the {PiL}[Programming in Lua] books. // TODO: describe Lua a bit // TODO: give hints which PiL to read / how Because Lunatic is implemented using {LuaJIT}[LuaJIT], a just-in-time compiler for the Lua language, some {LuaJIText}[extensions] to the core language are automatically available. They may be used if no compatibility with Rio Lua 5.1 is desired.footnote:[Not all extensions from LuaJIT are available, since some like the FFI are targeted at C programmers rather than scripting coders.] NOTE: The length operator (`#`) for table arguments should be taken to be defined by the http://www.lua.org/manual/5.2/manual.html#3.4.6[stricter wording of Lua 5.2]. Environment and Usage --------------------- Lunatic aims to provide a _safe_ scripting environment for EDuke32. Thus, not all of Lua's functionality is available in Lunatic, and some is slightly altered to play well with being embedded into a game, or to prevent commonly occurring mistakes. .Differences from default Lua environment - Creating new global variables in the global environment is forbidden. - In module context, referencing a non-existent variable (i.e. one that has value *nil*) is an error. EDuke32 can load multiple Lunatic _modules_ when starting up. This is always done after translating CON code to Lua and loading it. Such modules must be named `*.lua` (case-sensitive) and should be passed directly, without any option letters, at the command line. Directory separators must be forward slashes. .Invocation example ==================== `eduke32 -nologo MYTC.CON -mx addition.con test.lua weapons/nuke.lua -v1 -l1` ==================== Global Environment ------------------ When a Lua module is loaded, its global environment contains both selected functions from core Lua, as well as Lunatic's own pre-defined variables. These allow access and manipulation of EDuke32 engine and game data. [icon="icons/din_w_explosive.png"] CAUTION: If an attempt is made to create a new variable in the global environment or to assign any value to an existing variable, the behavior is undefined. Lua functions ~~~~~~~~~~~~~ The following base Lua functions are available in Lunatic's global environment: `assert`, *`error`*, `ipairs`, `pairs`, `pcall`, *`print`*, *`module`*, `next`, *`require`*, `select`, `tostring`, `tonumber`, `type`, `unpack`, `xpcall`. The bold ones add functionality or behave slightly differently, described below. Additionally, `printf` is provided for convenience. [[error]] *`error(message [, level])`*:: In Lunatic, errors also print to the on-screen display (OSD) and are written to the log (unless a maximum error count is exceeded). These also have a _backtrace_ added. Additionally, errors not caught by a `pcall` result a permanent message to appear on the screen, containing the source file name and line number. *`print(...)`*:: The messages are printed to the OSD and the log. Color codes available in EDuke32 (e.g. `^10` for dark red) are interpreted. Overriding `tostring` has no effect on Lunatic's `print` as it uses the initial, built-in `tostring` function instead of looking it up in the global environment. *`printf(fmt, ...)`*:: Calls `print` with the result of `string.format(fmt, ...)`. Writing and using modules ~~~~~~~~~~~~~~~~~~~~~~~~~ In Lunatic, like in Lua, a _module_ is a conceptually a sort of package that unites related bits of functionality. Language-wise, it is simply a Lua table holding its contents, as described and motivated at length in _Programming in Lua_. The ``creation'' and ``usage'' sides of the modularity concept are reflected in two functions known from Lua 5.1, `module` and `require`. The former is a convenient way of separating the _import_, potential _gamevar_, and main body sections when writing a package. It is not required to use `module`, but it is the only way to declare _game variables_, that is, variables that EDuke32 stores within savegames, recreating their values when they are loaded. The other side of the coin, `require`, is also used like in Lua: ``including'' a named module is requested by passing its name to `require`. This searches for a matching module, loading and running it if the request happens for the first time. ==== The function `require(modname, ...)` Attempts to find a Lua or Lunatic module named `modname`. The name can refer to a _built-in_ module, of which the following ones are allowed: * The http://bitop.luajit.org/[`bit`] module for bitwise operations * `math`, `string` and `table`, base modules from Lua * Lua's `os` module, containing a single function, `clock`. Like the <>, it should only be used to profile bits of code. * Modules provided by Lunatic, which will be described in <>. If `modname` does not designate a built-in module, Lunatic first replaces every dot contained in it with a directory separator. Then, it looks for a file with that base name suffixed with `.lua` in the EDuke32 search path (virtual file system, GRP, ZIP). Using directory separators directly is not allowed. The loaded module is protected so that write accesses to its table yield errors. Unlike in Lua, our `require` does not return *true* when a module is requested that has not yet finished loading (that is, the inclusion chain contains a loop). Instead, an error is raised. Lunatic's `require` allows passing additional arguments to the module to load. On the module side, they can be obtained by examining the vararg expression ``++\...++'' at file scope. Given a definition of `args` as `{...}`, its first element `args[1]` would contain `modname` and the following entries the values passed in addition to `require`. This feature is useful for parametrizing a module: for example, it could provide a way alter the starting tile number of an actor it defines. Issuing `require` for ```end_gamevars`'' has a special meaning that is described below. A `require` for ```CON.DEFS`'' returns a table mapping labels ++define++d from CON to their values, except for `NO`. ==== The `module()` function Initiates a _module_ environment by creating a new empty table and setting it as the global environment of the chunk. Unlike Lua 5.1, our `module` takes neither a name argument nor ``option'' varargs. A Lunatic file may have at most one call to `module`, which (if there is one) *must* be called at file scope. ===== Game variables Lunatic has a special mechanism to mark variables that represent persistent state and whose values should be stored in savegames. If such variables are desired, they must be initialized between the `module` call in a Lua file and a closing `require("end_gamevars")`.footnote:[The reason that the initialization has to happen between the `module` and the `require('end_gamevars')` is that on savegame loading, gamevars are restored from the latter.] These variables may also be *`local`*. Game variables may take on only values of types that Lunatic knows how to serialize into savegames. These are the following: * Booleans, numbers, and strings, collectively called the _basic types_ * Custom Lunatic types that are labeled _serializeable_ in their documentation * Tables, but with the following restrictions on their contents: ** A table key may only be of basic type. ** A table value may be (a reference to) any serializeable object, but tables or Lunatic objects that are so referenced *must* have originated in the same module. Beyond that, there are no restrictions on the table topology. // [icon="icons/din_w_collapse.png"] // TODO: example? // TODO: the rest The ``gv'' variable ~~~~~~~~~~~~~~~~~~~ Some constants, global C variables, and miscellaneous functions and structures are accessible via the global `gv` variable. Constants ^^^^^^^^^ `gv.MAXSECTORS`, `gv.MAXWALLS`, `gv.MAXSPRITES`:: The hard engine limits on the number of sectors, walls, and sprites. These constants *must* be used instead of any literal numeric values because they can change depending on how EDuke32 was configured and built. ////////// `gv.MAXSTATUS`, `gv.MAXTILES`, `gv.MAXSPRITESONSCREEN`:: TODO `gv.MAXBUNCHES`, `gv.CEILING`, `gv.FLOOR`:: TODO ////////// `gv.CLIPMASK0`:: A clipping (collision detection) mask specifying to consider only _blocking_ walls and sprites. `gv.CLIPMASK1`:: A clipping (collision detection) mask specifying to consider only _hitscan sensitive_ walls and sprites. // Game-side `gv.*` inventory indices:: `GET_STEROIDS`, `GET_SHIELD`, `GET_SCUBA`, `GET_HOLODUKE`, `GET_JETPACK`, `GET_DUMMY1`, `GET_ACCESS`, `GET_HEATS`, `GET_DUMMY2`, `GET_FIRSTAID`, `GET_BOOTS`. `GET_MAX`. `gv.*` weapon indices:: `KNEE_WEAPON`, `PISTOL_WEAPON`, `SHOTGUN_WEAPON`, `CHAINGUN_WEAPON`, `RPG_WEAPON`, `HANDBOMB_WEAPON`, `SHRINKER_WEAPON`, `DEVISTATOR_WEAPON`, `TRIPBOMB_WEAPON`, `FREEZE_WEAPON`, `HANDREMOTE_WEAPON`, `GROW_WEAPON`. `MAX_WEAPONS`. // TODO: the others, like EVENT_*. ////////// [[gv_STAT]] `gv.*` sprite status numbers:: `STAT_DEFAULT`, `STAT_ACTOR`, `STAT_ZOMBIEACTOR`, `STAT_EFFECTOR`, `STAT_PROJECTILE`, `STAT_MISC`, `STAT_STANDABLE`, `STAT_LOCATOR`, `STAT_ACTIVATOR`, `STAT_TRANSPORT`, `STAT_PLAYER`, `STAT_FX`, `STAT_FALLER`, `STAT_DUMMYPLAYER`, `STAT_LIGHT`. ////////// ////////// `gv.MAXPLAYERS`:: TODO ////////// Variables ^^^^^^^^^ `gv.totalclock` (read-only):: The current value of the engine timer that increments at a rate of 120 per second under default settings. (Thus, one game tic corresponds to four `totalclock` increments.) When staying within one ``mode'' such as in-menu or in-game, it is guaranteed to not decrease. However, going from one mode to another may produce discontinuities. `gv.screenpeek` (read-only):: The player index of the player from whose position the scene is being displayed. `gv.hudweap`:: A structure containing information about the currently displayed HUD weapon. Contains the following members, which are set from C before entering `EVENT_DISPLAYWEAPONS`: `cur`, `count`, `gunposx`, `gunposy`, `lookhalfang`, `lookhoriz`, `shade`. // TODO: describe `gv.cam`:: A structure that, prior to entering `EVENT_DISPLAYROOMS`, is populated with the position and orientation of the ``camera'' from which the scene would be drawn. Contains the following members: `pos`, `dist`, `clock`, `ang`, `horiz`, `sect`. // TODO: describe // TODO: g_logoFlags, g_RETURN? Functions ^^^^^^^^^ [[timing_funcs]] `gv.getticks()`, `gv.gethiticksms()`:: Each of these functions return a number that increases at a rate of 1 per millisecond. Their only intended application is to profile bits of code; they should not be used to control the game world. The two functions differ in their precision: `getticks()` always returns integral values, while the result of `gethiticksms()` also has an unspecified precision in the fractional part. (It can be expected to give a time precision of at least one microsecond.) `gv.doQuake(gametics [, snd])`:: Requests from the game to perform the ``quake'' effect that shakes the screen etc. for the next `gametics` game tics. If a sound index `snd` is passed, also start playing that sound. // TODO: Play sound how? ("globalsound") ////////// `gv.currentEpisode()`:: TODO `gv.currentLevel()`:: TODO `gv.currentRenderMode()`:: TODO ////////// Lunatic structures ~~~~~~~~~~~~~~~~~~ The primary means of effecting game state in Lunatic is via _composite variables_ defined in the global environment. These provide direct, but restricted, access to C _structure arrays_ of the EDuke32 engine or game. [icon="icons/din_w_toxic.png"] CAUTION: If an attempt is made to access any composite variable outside of event or actor code, the behavior is undefined. Composite variables can be used in various ways. All of them allow indexing with an integer value from `0` to some maximum (sometimes the size of the array minus one, but occasionally less). For example, the code snippet ---------- local sec = sector[0] ---------- gets a _reference_ to the first sector of the loaded map into the local `sec`. This reference can then be used to both read and write its members. Various structures also provide _methods_ in Lunatic to modify their state, usable with Lua's `v:func(args...)` syntax. Building on the previous example, ---------- local cz = sec:ceilingzat(wall[sec.wallptr]) ---------- would get into `cz` the ceiling z position at the first sector's first wall-point. Finally, some composite variables offer _static data_, which can contain functions or tables of constants. These are accessed using the dot notation on the composite variable, *not* its constituents. For instance, the following can be used to change the sector number of the sprite with index `i` manually: ---------- sprite.changesect(i, sectnum) ---------- Type of structure members ^^^^^^^^^^^^^^^^^^^^^^^^^ In the following, some structure members will be annotated with their _integer type_, for example _`i16`_ or _`u8`_. The letter _`i`_ denotes a _signed_ integer whereas a _`u`_ designates an _unsigned_ one. The number following that letter indicates the _bit width_ of that integer. .Representable values * A member of signed integer type and bit width _B_ can contain any whole number from --2^_B_--1^ to 2^_B_--1^--1. + * A member of unsigned integer type and bit width _B_ can contain any whole number from 0 to 2^_B_^--1. [[int_assignment]] .Assignment * If an assignment to a member having signed integer type is made, the ``right-hand side'' value must be a number in the closed interval [--2^31^ .. 2^31^--1]. * If an assignment to a member having unsigned integer type and bit width _B_ is made, the ``right-hand side'' value must be in the closed interval [--2^31^ .. 2^31^--1] if _B_ is less than 32, or in [0 .. 2^32^--1] otherwise. * If the appropriate requirements hold, an assignment from a Lua number to a member having integer type begins by discarding the fractional part (``truncation''). Otherwise, the behavior is undefined. + * If the truncated value is outside the range of representable values for the corresponding integer type of bit width _B_, the final value is obtained by successively adding or subtracting 2^B^, until the value falls inside that range. ////////// NOTE to self: this is stricter than C99 (which has first truncation, then range check). Also, it may be tempting to assign 0x80000000 to an int32_t to mean INT32_MIN, but this is wrong because it's out of range. Also see: http://lua-users.org/lists/lua-l/2011-09/msg00534.html ////////// .Examples 1. Assignments to _`u8`_ member `visibility` * `sec.visibility=3.94159` results the member to contain the integer `3` * `sec.visibility=1/0` is undefined (attempt to assign an infinity) * `sec.visibility=-1` results the member to contain the integer `255` 2. Assignments to _`i16`_ member `lotag` * `sec.lotag=32768` results the member to contain `-32768` * `sec.lotag=2^32` is undefined Bit fields ^^^^^^^^^^ Some structures contain members that represent a collection of _flags_, for example `sprite[].cstat` or `actor[].flags`. These flags can be toggled by setting or clearing their respective _bits_ (integer numbers that are powers of two). For convenience, Lunatic provides alternative names for some of these members, together with methods to examine or modify any number of bits of such a member in one expression. Whenever there is such an alternative name available, it is declared as having type _`bitfield`_ in the listings of the structure members. ===== methods of the _`bitfield`_ type `bf:set(bits)`:: _Sets_ (toggles to an ``on'' state in a boolean sense) those bits of `bf` that are set in `bits`. `bf:clear(bits)`:: _Clears_ (toggles to an ``off'' state in a boolean sense) those bits of `bf` that are set in `bits`. `bf:flip(bits)`:: _Flips_ those bits of `bf` that are set in `bits`, that is, reverses their boolean state. `bf:test(bits)`:: Returns a boolean that indicates whether `bf` has *any* of the bits set in `bits` set. .Examples ========== After the lines setting sprite `i` to 33% translucent and blocking, ---------- local CS = sprite.CSTAT local spr = sprite[i] spr.cstat = CS.TRANS1 + CS.BLOCK ---------- one could proceed as follows for the sake of example: * `spr.cstatbits:set(CS.TRANS2)`, make the sprite 66% translucent now * `spr.cstatbits:flip(CS.BLOCK + CS.HITSCAN)`, make it hitscan-sensitive but not blocking * `spr.cstatbits:test(CS.FLIP_BITMASK)`, check whether it is flipped (no) ========== Engine-side ^^^^^^^^^^^ The composite variables described in this subsection provide access to engine-side structures. The first three, `sector`, `wall`, and `sprite`, are part of a BUILD map saved to disk. The other ones only exist when running the game. ===== `sector` Accessible from `0` to `gv.numsectors-1`. Each element has the following members: `wallptr`, `wallnum` (read-only):: The index of the sector's first wall and the number of walls in the sector, respectively. _`u8`_ `visibility`:: Determines the amount of distance fading. In the range [`0` .. `239`], the ``darkening'' increases with rising values. The range [`240` .. `255`] should be thought of as [`-16` .. `-1`]. // TODO: better wording? _`i16`_ `lotag`, `hitag`, `extra`:: General-purpose ``tags'' provided for game programming. They may be used by various EDuke32 sector effects, so it's not recommended to use them in scripting code. In addition to the members described above, each sector has two sets of members for its ceiling and floor. A sector reference can be indexed with the strings `ceiling` or `floor` to get references to the respective ``parts'', or one can access the consituent members by prefixing `ceiling` or `floor` to the base member names given below. .Different ways of accessing the same member ========== After the code lines ---------- local sec = sector[0] local ceil = sec.ceiling ---------- the following expressions all denote the same location, both if read or written to: `sec.ceilingheinum`, `ceil.heinum`, `sector[0].ceiling.heinum`, `sector[0].ceilingheinum`. ========== In the following, `cf` will stand for a ceiling or floor reference, while `sec` will label a sector reference. `cf.picnum` (read-only):: The tile number of the ceiling or floor. [[cf_stat]] _`u16`_ `cf.stat`, {nbsp} _`bitfield`_ `cf.statbits`:: A bit field holding various flags about how the ceiling or floor shoud be displayed, how collision detection should be handled, etc. The <> object should be used to obtain the values for applicable flags. _`i16`_ `cf.heinum`:: If `cf.stat` has bit `sector.STAT.SLOPE` set, the tangent of the slope angle multiplied by 4096. Positive values make the ceiling or floor slope towards the floor, negative ones slope upward. [[cf_z]] _`i32`_ `cf.z`:: The BUILD z coordinate (scaled by 16 compared to the x and y directions) of the pivoting line of the ceiling or floor. `cf.bunch` (read-only):: The ``bunch'' number of the ceiling or floor used for True Room over Room. One bunch comprises _N_ ceilings and _M_ floors (_N_ ≥ 1, _M_ ≥ 1) such that each set covers the same planar, connected area. _`i8`_ `cf.shade`:: The shade of the ceiling or floor. Larger values mean a more darker appearance. _`u8`_ `cf.pal`:: The ``palette swap'' index of the ceiling or floor. _`u8`_ `cf.xpanning`, `cf.ypanning`:: The panning values of the ceiling or floor. One full cycle is covered by values from `0` to `255`. ===== `sector` methods `sec:set_ceilingpicnum(tilenum)`, `sec:set_floorpicnum(tilenum)`:: Set the tile number of the ceiling or floor. `sec:ceilingzat(pos)`, `sec:floorzat(pos)`:: Return the z coordinate of sector `sec`'s ceiling or floor at position `pos`, which can be anything indexable with the strings `x` and `y`. ////////// `zrangeat(pos, walldist, cliptype)`:: TODO ////////// ===== `sector` static data [[sector_STAT]] `sector.STAT`:: Provides a mapping of symbolic names to values applicable to <>. These name single bits: `PARALLAX`, `SLOPE`, `SWAPXY`, `SMOOSH`, `FLIPX`, `FLIPY`, `RELATIVE`, `MASK`, `TRANS1`, `TRANS2`, `BLOCK`, `HITSCAN`, while the following denote _bit masks_: `FLIP_BITMASK`, `ORIENT_BITMASK`, `TRANS_BITMASK`. ''' [[wall]] ===== `wall` Accessible from `0` to `gv.numwalls-1`. Each element has the following members: `x`, `y`:: The 2D coordinates or this wall point. Should not be set directly. `z` (read-only):: Always yields `0`. The primary purpose of this field is to make wall references permissible as arguments to <> operations. `point2` (read-only):: The index of the second wall point. `nextwall`, `nextsector` (read-only):: If the wall is ``white'', these members equal `-1`. For ``red'' walls, they contain the wall and sector indices (respectively) of the wall on the other side. `upwall`, `dnwall` (read-only):: For walls constrained by TROR extension, the upper and lower neighbor walls, respectively. Any of them may be `-1`, meaning that the wall is not attached to a neighbor in this direction. [[wall_cstat]] _`u16`_ `cstat`, {nbsp} _`bitfield`_ `cstatbits`:: A bit field holding various flags about how the wall shoud be displayed, how collision detection should be handled, etc. The <> object should be used to obtain the values for applicable flags. [[wall_picnum]]`picnum` (read-only):: The tile number of the non-masked portion of the wall. If `wall.CSTAT.BOTTOMSWAP` is set on this wall's `.cstat`, it is only displayed in the upper portion. (The lower portion takes it from this wall's `.nextwall` then; this will be labeled _use-other-bottom_ in the following.) `overpicnum` (read-only):: The tile number of the masked portion of the wall, i.e. that which is drawn if this wall's `.cstat` has bit `wall.CSTAT.MASK` or `wall.CSTAT.ONEWAY` set. _`i8`_ `shade` (<>):: The shade of the wall for both non-masked and masked portions. Larger values mean a more darker appearance. _`u8`_ `pal` (<>):: The ``palette swap'' index of the wall. _`u8`_ `xrepeat`, `yrepeat`:: Values that are proportional to the number of times that the wall's texture repeats in each direction per given wall length/height. A value of `8` renders 64 texels across a length of 1024 x/y map units or a height of 16384 z units. _`u8`_ `xpanning`, `ypanning` (<>):: The panning values of both masked and non-masked portions of the wall. One full cycle is covered by values from `0` to `255`. _`i16`_ `lotag`, `hitag`, `extra`:: General-purpose ``tags'' provided for game programming. They may be used by various EDuke32 effects internally, so it is advised to do some research before claiming them for oneself. ===== `wall` methods `wal:set_picnum(tilenum)`, `wal:set_overpicnum(tilenum)`:: Set the tile number of the wall or its masked portion. ===== `wall` static functions `wall.dragto(i, pos)`:: Set the position of the point of the wall with index `i` to `pos`, which can be anything indexable with `x` and `y`. This function is the preferred way of changing wall coordinates, since it takes care to reposition dependent wall points, too. ===== `wall` static data [[wall_CSTAT]] `wall.CSTAT`:: Provides a mapping of symbolic names to values applicable to <>. These name single bits: `BLOCK`, `BOTTOMSWAP`, `ALIGNBOTTOM`, `FLIPX`, `MASK`, `ONEWAY`, `HITSCAN`, `TRANS1`, `FLIPY`, `TRANS2`, while the following denote _bit masks_: `FLIP_BITMASK`, `TRANS_BITMASK`. ''' ===== `sprite` The `sprite` composite is accessible with indices from `0` to `gv.MAXSPRITES-1`, but accesses to sprites that do not exist in the game world have no meaning. Each element has the following members: `x`, `y`, `z`:: The BUILD coordinates of the sprite. It is not advisable to set these directly. ////////// _`i16`_ `ang`:: TODO (make set_ang() out of that which always ANDs with 2047?) ////////// [[sprite_cstat]] _`u16`_ `cstat`, {nbsp} _`bitfield`_ `cstatbits`:: A bit field holding various flags about how the sprite shoud be displayed, how collision detection should be handled, etc. The <> object should be used to obtain the values for applicable flags. `picnum` (read-only):: The tile number of the sprite, also used to determine which _actor_ code is run if this sprite has a `statnum` of `actor.STAT.ACTOR`. _`i8`_ `shade`:: The shade of the sprite. This may not be the shade that this sprite is ultimately drawn with, though. _`u8`_ `pal`:: The ``palette swap'' index of the sprite. This may not be the palette swap that this sprite is ultimately drawn with, though. _`u8`_ `clipdist`:: If this sprite is _view-aligned_, controls the distance at which another moving object is considered to be in collision with this *stationary* sprite. (It does not control the inverse case.) More precisely, it designates half the side-length of the bounding square divided by 4. Thus, a value of `255` keeps moving objects away from this one at a max-norm distance footnote:[The max-norm distance between points _p_~1~=(x~1~, y~1~) and _p_~2~=(x~2~, y~2~) is defined as max(abs(x~2~ -- x~1~), abs(y~2~ -- y~1~)).] of at least 1020 BUILD x/y units. _`u8`_ `xrepeat`, `yrepeat`:: The size of the sprite in each dimension. For wall- and floor- aligned sprites, a value of `64` means a width of 16 x/y BUILD units or a height of 256 z BUILD units per texel. `sectnum` (read-only):: The index of the sector that this sprite is currently contained in. [[sprite_statnum]] `statnum` (read-only):: The current _status number_ of this sprite. Applicable values are contained in <>. `owner` (read-only):: The index of the sprite from which this sprite was spawned. If this sprite is not a ``child'' of another one, then `owner` is the index of this sprite itself. //Occasionally, game effects may use this member for their particular purposes, //so research is recommended before claiming it for oneself. _`i16`_ `xvel`, `zvel`:: For _actors_ and other moving sprite types, the horizontal and vertical components of the current velocity. //It is not advisable to set these directly //unless one knows how they are processed. //`yvel` (read-only):: //A general-purpose member of which the game has exclusive control. _`i16`_ `lotag`, `hitag`, `extra`:: General-purpose ``tags'' provided for game programming. They may be used by hard-coded actors internally, so it is advised to do some research before claiming them for oneself. ===== `sprite` methods `spr:set_picnum(tilenum)`:: Set the tile number of the sprite. ===== `sprite` static functions `sprite.changesect(i, sectnum)`:: Allows to manually change the sector number of the sprite with index `i` to `sectnum`. `sprite.changestat(i, statnum)`:: Allows to manually change the status number of the sprite with index `i` to `statnum`. ===== `sprite` overridden operators [[sprite_power]] `spr^zofs`:: Returns an <> object that contains the position of this sprite, diminished by `zofs` in the z direction. Because in BUILD, z coordinates increase toward the floor, the `^` can be thought of as ``raise the sprite by `zofs` units''. ===== `sprite` static data [[sprite_CSTAT]] `sprite.CSTAT`:: Provides a mapping of symbolic names to values applicable to <>. These name single bits: `BLOCK`, `TRANS1`, `XFLIP`, `YFLIP`, `ALIGNWALL`, `ALIGNFLOOR`, `ONESIDE`, `CENTER`, `HITSCAN`, `TRANS2`, while the following denote _bit masks_: `ALIGN_BITMASK`, `TRANS_BITMASK`. ===== `spriteext` ===== `atsprite` Game-side ^^^^^^^^^ ===== `actor` ===== `actor` methods ===== `actor` static data [[actor_STAT]] `actor.STAT`:: Provides a mapping of symbolic names to values applicable as sprite <>. + `DEFAULT`, `ACTOR`, `ZOMBIEACTOR`, `EFFECTOR`, `PROJECTILE`, `MISC`, `STANDABLE`, `LOCATOR`, `ACTIVATOR`, `TRANSPORT`, `PLAYER`, `FX`, `FALLER`, `DUMMYPLAYER`, `LIGHT`. [[actor_FLAGS]] `actor.FLAGS`:: Contains symbolic names of values applicable to <>'s `flags` input argument, most of which are described there. + `SHADOW`, `NVG`, `NOSHADE`, `NOPAL`, `NOEVENTS`, `NOLIGHT`, `USEACTIVATOR`, `NOCLIP`, `SMOOTHMOVE`, `NOTELEPORT`. //`BADGUY`, ===== `player` ===== `player` methods `ps:fadecol(fadefrac, r, g, b [, speed [, prio]])`:: Initiates a tinting that linearly fades over time and is blended with the whole screen contents whenever player `ps`'s view is displayed.footnote:[The behavior is unspecified should more than one player's view be displayed at one time.] The first argument `fadefrac` specifies the starting blending coefficient; `r`, `g` and `b` specify the intensities of the red, green and blue color components, respectively. + Both `fadefrac` and the component intensities are first clamped to the range [0.0 .. 1.0]. The resulting values are interpreted as a fraction, 0.0 meaning no blending/no color and 1.0 meaning full blending/full color.footnote:[Currently, for implementation reasons, a value of 1.0 results in only _almost_ full blending or presence of the specified color component.] + The fourth, optional argument `speed` controls the rate at which the tinting diminishes. At a value of `1` (the default), a tint with a `fadefrac` of 0.5 finishes in approximately one second. + The last, optional argument `prio` must be an integer in the range [`-128` .. `127`], the default being `0`. When a `fadecol` is issued in the presence of another tint fading in progress, and the `prio` given by the arriving `fadecol` is greater or equal than the `prio` of the ongoing one, the latter is canceled and the arriving fading is initiated in its place. (There is no support for tint fades that overlap in time.) + [icon="icons/din_w_crushing.png"] CAUTION: If Lunatic code that uses `fadecol` is loaded together with CON code that writes to the player's `pals` members directly at any point, the behavior is undefined. ===== `projectile` ===== `g_tile` ===== `g_tile` static data `g_tile.sizx`, {nbsp} `g_tile.sizy`:: Arrays indexable with tile numbers [`0` .. `gv.MAXTILES-1`] that hold the horizontal and vertical texel sizes of each tile. Lunatic functions ~~~~~~~~~~~~~~~~~ Engine-side ^^^^^^^^^^^ ===== Iterators +*for* w *in* wallsofsect(sectnum)+:: Iterates over the indices of all walls of the sector with index `sectnum`. +*for* s *in* spritesofstat(statnum)+:: Iterates over the indices of all sprites with status number `statnum`. +*for* s *in* spritesofsect(sectnum)+:: Iterates over the indices of all sprites contained in the sector with index `sectnum`. cansee hitscan inside neartag sectorsofbunch updatesector updatesectorbreadth updatesectorz Customizing the game ^^^^^^^^^^^^^^^^^^^^ In Lunatic, there are two main ways of customizing the game's behavior. Both involve the user providing functions that are _called back_ at certain points in the execution of EDuke32. Game _actors_ are simply sprites that run a particular piece of code based on their tile number each game tic, unless they are in a ``dormant'' state. Game _events_ are invoked at predetermined points in the program flow. To register custom actor and event code with the game (and define additional actor information), Lunatic provides two functions in the global environment, `gameactor` and `gameevent`. As their sole argument, they take a table containing the appropriate data. [[gameactor]] ===== The function `gameactor{tilenum [, ...], func}` Registers custom code for the actor given by tile number `tilenum`. For each non-sleeping actor, the function `func` is called every game tic with three input arguments: `func(aci, pli, dist)`. * `aci`: the sprite number of the actor invoking `func` * `pli`: the index of the player that is nearest to this actor * `dist`: the 3D Manhattan distance footnoteref:[mhdist_def,The Manhattan distance between points _p_~1~=(x~1~, y~1~, z~1~) and _p_~2~=(x~2~, y~2~, z~2~) is defined as abs(x~2~ -- x~1~) + abs(y~2~ -- y~1~) + abs(z~2~ -- z~1~).] between actor `aci` and player `pli` // NOTE: , is the comma; the footnote would be truncated at it otherwise. // For a related issue, see // http://www.methods.co.nz/asciidoc/faq.html#_why_am_i_having_trouble_getting_nested_macros_to_work Additionally, `gameactor` accepts optional input arguments. They can be specifyed positionally by following `tilenum`, or be given as values to string keys of the argument table. Each such input argument may be provided in at most one of these two forms. Furthermore, `func` may be provided as value to the key `'func'` as well. `[2] flags`:: A number that controls both certain aspects of the `gameactor` call as well as the run-time behavior of the actor itself. A couple of bits for the latter type are listed in <>, abbreviated `AF` in the following. + These values describe the ``type'' of the actor: `AF.enemy`, `AF.enemystayput` and `AF.rotfixed`. Except for `enemystayput`, they name single bits (`enemystayput` implies `enemy`). + In Lunatic, game actors can be _chained_, that is, a callback function can be either appended to the end of an already registered one, or prefixed at its front. In this case, a previous `gameactor` call must have taken place for that actor (this may have happened from a CON `useractor` block, which gets translated to `gameactor`). Moreover, this mechanism allows to add run-time flags to the actor in question. + Several flags in `AF` are provided to control how a `gameactor` invocation handles chaining. + * `AF.replace_hard`: Completely replace the actor's callback function and run-time flags. This is the default. * `AF.replace_soft`: Replace the callback function, but bitwise-OR the existing run-time flags with the provided ones. This is the way CON's `useractor` behaves. * `AF.chain_beg`: Prepend the provided `func` to the exising callback function, bitwise-OR in flags. * `AF.chain_end`: Append the provided `func` to the exising callback function, bitwise-OR in flags. `[3] strength`:: The initial strength or health of the actor. Default: `0`. `[4] action`:: `[5] move`:: `[6] movflags`:: TODO ===== The function `gameevent{evtlabel [, flags], func}` :wiki: http://wiki.eduke32.com :wiki_eventlist: http://wiki.eduke32.com/wiki/EDuke32_event_list Registers custom code to be run at specific points in the program. The first argument `evtlabel` should be a string naming the event. A complete {wiki_eventlist}[list of events] can be found at the {wiki}[EDuke32 wiki]. The label may be stripped of the leading ```EVENT_`'', so that e.g. `EVENT_JUMP` and simply `JUMP` denote the same event. The arguments `flags` and `func` can alternatively be passed as values to the same-named keys of the input argument table to `gameevent`. Like with `gameactor`, each may be provided in at most one of the two forms. The callback `func` is invoked with the same arguments and meaning as for <>, but certain events are run in contexts where no meaningful `aci` and/or `pli` value can be assigned. In this case, `func` receives `-1` for the respective input arguments. Like with actors, game events may be chained or replaced by passing an appropriate `flags` value. However, it is not necessary for an event to be already defined when chaining is requested. In that case, it is simply registered initially. Permissible values for these flags are provided in `actor.FLAGS` as well (abbreviated `AF` here): * `AF.replace`: Replace any previously defined event code with the given one. * `AF.chain_beg`: Prepend the provided `func` to the exising callback function. This is the behavior of CON's `onevent`. * `AF.chain_end`: Append the provided `func` to the exising callback function. This is the default. // TODO: RETURN handling... [[ext_api]] Extended API (Lunatic modules) ------------------------------ The `xmath` module ~~~~~~~~~~~~~~~~~~ Mathematical functions ^^^^^^^^^^^^^^^^^^^^^^ Lunatic, being a Lua-based scripting system, provides the user with a single numeric data type that variables can contain on the Lua side -- double-precision floating point.footnote:[In LuaJIT, variables additionaly can take on ``boxed'' 64-bit integer numeric types, but these should not be used for numeric calculations.] However, since BUILD, and in turn, EDuke32, almost exclusively use integer types to represent quantities such as angles or carry out e.g. trigonometrical calculations, there is a need for convenient interoperability between the two ``worlds''. Two pairs of functions calculate the trigonometric sine and cosine, both accepting a BUILD angle as input argument, but differing in the scaling of their result. Using these functions is recommended over Lua's `math.sin` or `math.cos` in cases where the argument is a BUILD angle in the first place, for example because it is read from an engine or game structure. The computation is both faster (because it is essentially only a bitwise-AND operation followed by a table lookup) and the results have the symmetry expected from the mathematical counterparts. `xmath.sinb(bang)`, {nbsp} `xmath.cosb(bang)`:: Returns the sine/cosine of the given BUILD angle `bang`, which can be any whole number in [--2^31^ .. 2^31^--1]. In BUILD, one full cycle is covered by values from 0 to 2047; in other words, an angle of 2048 corresponds to 360 degrees. + The `sinb` and `cosb` functions return values in the range [--1 .. 1], just like their mathematical counterparts. + The following guarantees are made for `sinb` whereever its argument expression is permissible: + * `sinb(-a) == -sinb(a)` (point symmetry around the origin) * `sinb(a + i*2048) == sinb(a)`, where `i` is any whole number (periodicity) * `sinb(1024 - a) == sinb(a)` (mirror symmetry around `a`=512) * `sinb(a - 1024) == -sinb(a)` (point symmetry around `a`=1024) * The value for `cosb(a)` is derived as `sinb(a + 512)`. `xmath.ksin(bang)`, {nbsp} `xmath.kcos(bang)`:: Returns the sine/cosine of the given BUILD angle `bang`, multiplied with 16384 and rounded towards zero. The same guarantees as for the `sinb`/`cosb` pair apply. `xmath.dist(pos1, pos2)`:: Returns an approximation of the 3D Euclidean distance between points `pos1` and `pos2`, both of which can be any object indexable with `x`, `y` and `z`. <> are assumed. `xmath.ldist(pos1, pos2)`:: Returns an approximation of the 2D Euclidean distance between points `pos1` and `pos2`, both of which can be any object indexable with `x` and `y`. [[vector_types]] The types `xmath.vec3` and `xmath.ivec3` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Another purpose of the `xmath` module is to provide _vector_ types that allow writing concise and clear code involving geometrical calculations. There are two types, both containing three components (`x`, `y` and `z`), but differing in their numeric type. For the most part, `vec3` should be used, whose components are Lua numbers, i.e. floating point. The other type, `ivec3`, is part of some game structures, and consequently uses 32-bit integers for its components. With minor differences, the `vec3` and `ivec3` types share the same operations and methods. The constructors of the vector types can be called in several ways. In the following, they are only described for `vec3`. The conventions for `ivec3` are completely analogous, but since their creation involves a number type conversion, the rules about <> apply. `v = xmath.vec3([x [, y [, z]]])`:: Create a 3-element vector `v` by passing the `x`, `y` and `z` components separately. Trailing components can be omitted, in which case they are initialized to 0. `v = xmath.vec3(t)`:: Create a 3-element vector `v` by passing `t`, which can be any variable indexable with the strings `x`, `y` and `z` (and yielding numbers for these lookups). For example, `t` can be another (`i`)`vec3`, a `sprite` or even <> reference, as each of them can be indexed with these three keys. Since the vector types are compound objects, they are always passed around by reference. For example, consider executing ---------- v = xmath.vec3(0, 1) w = v w.y = 2 ---------- After this code, the expression `v.x` yields `2` instead of `v`'s initial value `1`. ===== Operations for `vec3` and `ivec3` In the following, `v` denotes a `vec3` or `ivec3` object reference while `t` denotes any object indexable with `x`, `y` and `z`. Note that for binary operations, Lua looks for overridden operators in the left operand first and the right one next. So, where `t` appears on the left hand side of an arithmetic expression, it is assumed that `t`'s type does not overload the corresponding operation or provides the same semantics. Arithmetic operations always return a (reference to a) new `vec3` object, even if any or both of the operands have `ivec3` type. `v + t`, {nbsp} `t + v`:: Returns a new `vec3` object whose components are the sum of the respective components of `v` and `t`. `v - t`, {nbsp} `t - v`:: Returns a new `vec3` object whose components are the difference of the respective components of `v` and `t` (in the first case) or `t` and `v` (in the second case). `-v`:: Returns a new `vec3` object with the components of `v` negated. `a*v`, {nbsp} `v*a`:: For a scalar number `a`, returns a new `vec3` object whose components are those of `v` mutiplied with `a`. `v/a`:: For a scalar number `a`, returns a new `vec3` object whose components are those of `v` divided by `a`. `v^zofs`:: Returns an object of the same type as `v` and with the same components, except that `v.z` is diminished by `zofs`. Also see the <> for `sprite` objects. `tostring(v)`:: Returns a string representation of `v` for display purposes: ```vec3`'' or ```ivec3`'', followed by the components of `v` in parentheses. ===== Methods for `vec3` and `ivec3` `v:len()`:: Returns the Euclidean length of `v` in three dimensions. `v:lensq()`:: Returns the squared Euclidean length of `v` in three dimensions. `v:len2()`:: Returns the Euclidean length of `v`, taking only the `x` and `y` components into account. `v:len2sq()`:: Returns the squared Euclidean length of `v`, taking only the `x` and `y` components into account. `v:mhlen()`:: Returns the length of `v` calculated using the Manhattan distance footnoteref:[mhdist_def] in three dimensions between the origin and the endpoint. `v:toivec3()`:: Returns a new `ivec3` object with the same components as `v`, but converted <>. `v:touniform()`:: Returns a new vector of the same type as `v` which has the same `x` and `y` components as `v`, but the `z` element divided by 16 (if `v` is a `vec3`) or arithmetically right-shifted by 4 (if `v` is an `ivec3`).footnote:[Right-shifting by 4 can be seen as a division by 16 with subsequent rounding to an integer towards negative infinity.] Also see the description of the ceiling/floor <>. `v:tobuild()`:: Returns a new vector of the same type as `v` which has the same `x` and `y` components as `v`, but the `z` element multiplied with 16.