User:Monster Iestyn/Lua Tutorial

From SRB2 Wiki
Jump to navigation Jump to search
This article or section is incomplete. It doesn't have all of the necessary core information on this topic. Please help the SRB2 Wiki by finishing this article.

Introduction

This tutorial assumes you are at the least familiar with SOC, and have either little to no experience or knowledge of programming.

Everything SOC can do and more!

...well, in the case of directly handling Object types, states, and sounds, yes, this is true of Lua; one can create custom types of Objects in Lua just as SOC can. Even so, there are some major differences in formatting to make clear first:

SOC's formatting largely works by setting values for parameters under "headers", as done here for declaring new freeslots, for example:

Freeslot
MT_OBJECTTYPE
Mt_oBjEcTtYpE2
S_STATENAME
s_stateNAME2
SPR_CUST
Spr_cuTW
sfx_custom
SFX_CUSTM2

Within SOCs, words, names and text are generally considered to be case-insensitive (i.e. FREESLOT, Freeslot, FrEeSlOt would be all all totally acceptable for the above example's header), as they will normally be converted to all-uppercase when loaded into SRB2 itself.

For Lua however, neither of these things apply at all: Lua largely depends on code being defined in functions or otherwise as variables independent of a header, and – in contrast to SOCs – words, names and other text in Lua scripts are nearly always case-sensitive – they are explicitly meant to be written in the right case for them to be recognised properly.

Lua's method of declaring new freeslots meanwhile is formatted as such:

freeslot(
	"MT_OBJECTTYPE",
	"MT_OBJECTTYPE2",
	"S_STATENAME",
	"S_STATENAME2",
	"SPR_CUST",
	"SPR_CUTW",
	"sfx_custom",
	"sfx_custm2"
)

As shown above, Lua instead requires freeslot names to be declared via the freeslot() function, which must be written in all-lowercase to work correctly. Object type, state and sprite prefix names must be in all-uppercase, and sound names must be in all-lowercase. Note that the freeslot names are enclosed in quotation marks ("); these denote that the text in-between is what is referred to as a "string"; i.e text that the game itself must read explicitly as text, rather than a name representing a number (as these new names would become later in a script).

Also note that all the names are separated by commas (,) so as to treat each freeslot as a separate argument or parameter in the function. As a bonus these allow the freeslot() function to be formatted differently to the above:

freeslot("MT_OBJECTTYPE", "MT_OBJECTTYPE2", "S_STATENAME", "S_STATENAME2", "SPR_CUST", "SPR_CUTW", "sfx_custom", "sfx_custm2")

Or, if the freeslots should be organised by type (or having them all on a single line is too long):

freeslot("MT_OBJECTTYPE", "MT_OBJECTTYPE2",
	"S_STATENAME", "S_STATENAME2",
	"SPR_CUST", "SPR_CUTW",
	"sfx_custom", "sfx_custm2")

These arguments can be arranged in any fashion you wish, provided the commas are kept on the same line of each, and they are still in-between freeslot( and ).

Info-tables

Now to move onto creating new Object info-tables:

mobjinfo[MT_PLAYER] = {
	doomednum = -1,
	spawnstate = S_PLAY_STND,
	spawnhealth = 1,
	seestate = S_PLAY_RUN1,
	seesound = sfx_None,
	reactiontime = 0,
	attacksound = sfx_thok,
	painstate = S_PLAY_PAIN,
	painchance = MT_THOK,
	painsound = sfx_None,
	meleestate = S_NULL,
	missilestate = S_PLAY_ATK1,
	deathstate = S_PLAY_DIE,
	xdeathstate = S_NULL,
	deathsound = sfx_None,
	speed = 1,
	radius = 16*FRACUNIT,
	height = 48*FRACUNIT,
	dispoffset = 0,
	mass = 1000,
	damage = MT_THOK,
	activesound = sfx_None,
	flags = MF_SOLID|MF_SHOOTABLE,
	raisestate = MT_THOK,
}

The above example is of MT_PLAYER's own Object info-table (see Object#SOC definition for the SOC equivalent). To make clear what is going on here, "mobjinfo" is the name given to the table or array containing Object info-tables for all Object types – mobjinfo[MT_PLAYER] for instance is the info-table for MT_PLAYER, one of many entries or keys within the table mobjinfo. This can be done for any entry mobjinfo[n], n representing a number (preferably an Object type name in this instance).

The important point of note here is there are no functions being used; instead the entry mobjinfo[MT_PLAYER] is given a new table of data – this is known as assignment, where a variable is given a new value, such as in this case mobjinfo[MT_PLAYER] being set to a newly created table (denoted by the usage of { and } around the info-table's contents). Assignment also is shown within the table itself, such as the entry doomednum being assigned a value of -1, spawnstate being assigned a value of S_PLAY_STND and flags being assigned a value of MF_SOLID|MF_SHOOTABLE. In general assignment is expected to be in the format of variable = value, with a single equals sign (=) being used as the symbol for an assignment operation.

Do note that the above formatting is the "long-hand" method of assigning a new table to a mobjinfo entry, which means the names of each variable (doomednum, spawnstate, etc) have to be written out and given a value. One advantage though is that not all of these variables have to be included, as defaults are given to any undefined variables if not set. Another is that they can be defined in any order you wish, not being restricted to the ordering of the above example.

There is also an alternative, "short-hand" method of assigning this data to mobjinfo[MT_PLAYER] however:

mobjinfo[MT_PLAYER] = {
	-1,
	S_PLAY_STND,
	1,
	S_PLAY_RUN1,
	sfx_None,
	0,
	sfx_thok,
	S_PLAY_PAIN,
	MT_THOK,
	sfx_None,
	S_NULL,
	S_PLAY_ATK1,
	S_PLAY_DIE,
	S_NULL,
	sfx_None,
	1,
	16*FRACUNIT,
	48*FRACUNIT,
	0,
	1000,
	MT_THOK,
	sfx_None,
	MF_SOLID|MF_SHOOTABLE,
	MT_THOK
}

Here the variable names doomednum, spawnstate etc do not have to be included, but at a price of being able to recognise which variable is which, and also that the variables are expected to be in the specific order already shown in the above example. None of the variables can be missed out either, otherwise the next variables' values would be taken to be for the missed out variables. For these reasons the long-hand variant of the formatting is greatly favored over the short-hand one.

You could also display the variables of the table all on a single line for either case, but this would be excessively long with all the variables included, and so isn't recommended.

As you would expect after going over mobjinfo for Objects, states and sounds also have equivalent tables for doing the same as in SOC:

states[] is used for state info-tables (see State#SOC definition for SOC version):

states[S_FLAMEJETFLAMEB1] = {
	sprite = SPR_DFLM,
	frame = FF_FULLBRIGHT|TR_TRANS40|B,
	tics = 1,
	action = A_MoveRelative,
	var1 = 0,
	var2 = 5,
	nextstate = S_FLAMEJETFLAMEB2
}

For a state to have no action, it can be set to the value nil, which in Lua represents a non-existant non-zero value.

sfxinfo[] (also known as S_sfx[]) is used for sound info-tables (See Sound#SOC definition for SOC version):

sfxinfo[sfx_rumble] = {
	singular = 0,
	priority = 64,
	flags = SF_X4AWAYSOUND|SF_X8AWAYSOUND
}

These tables can also be written in short-hand form, just as with the Object info-table assigned to mobjinfo in the earlier examples, with the listed variables ordered as shown above.

How not to rewrite whole info-tables

One thing to note however with the method of declaring info-table properties already displayed above: these completely rewrite the whole info-table, so any variables left out are set to default values instead. This is not always wanted in some cases, such as when you modify only one or two properties of a previously existing info-table – e.g modifying MT_BLUECRAWLA's spawnhealth property to have 2 health points for instance. In this situation we instead do this:

mobjinfo[MT_BLUECRAWLA].spawnhealth = 2

Note how instead of assigning mobjinfo[MT_BLUECRAWLA] itself to a newly created table of variables, we are assigning mobjinfo[MT_BLUECRAWLA].spawnhealth's value to become 2. This allows only this value to be modified and nothing else. Same works for any other Object info-table variables like doomednum and spawnstate and seesound etc, provided they are formatted as infotable.variable with the "." signifying that variable is a variable for infotable.

Some further examples using mobjinfo[] and various Object types:

mobjinfo[MT_GFZFLOWER1].doomednum = -1
mobjinfo[MT_THOK].spawnstate = S_PARTICLE
mobjinfo[MT_ROCKET].seesound = sfx_thok

This also works with states[] and sfxinfo[] and their respective variables:

states[S_POSS_STND].sprite = SPR_FISH
states[S_CCOMMAND1].var1 = 1
states[S_PLAY_RUN1].action = A_GhostMe
sfxinfo[sfx_thok].singular = 1
sfxinfo[sfx_ding].priority = 96
sfxinfo[sfx_menu1].flags = SF_OUTSIDESOUND

This also works with hudinfo[], the table containing HUD item info-tables. The "re-write the whole info-table" method is not usable with hudinfo[], though it is not needed anyway (there are only two variables to modify – x and y for x/y screen coordinates).

hudinfo[HUD_LIVESNAME].x = 16
hudinfo[HUD_LIVESNAME].y = 166