Sider 3 Lua Module Programmers Guide
====================================
For sider.dll version: 3.5.1
June 12, 2017



1. Introduction
~~~~~~~~~~~~~~~

The main idea here is to provide a safe and flexible way to
extend Sider functionality. It will (eventually) allow modders to
alter many aspects of the game, load all sorts of extra content
and even do gameplay tweaks.

Instead of offering a C interface, where the programmers would need
to write a DLL, i'm a taking a different approach here and trying to
design a system, where extension modules are written in Lua. A module
would typically initialize itself by registering for certain events,
and then Sider will call the module functions, when those events
occur later in the game.

Lua is by now a well-established language of choice for scripting
support in games, used all over the gaming industry. Most famous
example is probably WarCraft.

To boost the performance, Sider uses a just-in-time compiler for Lua
called LuaJIT, written by Mike Pall. LuaJIT is a truly brilliant piece
of software. It is 100% compatible with Lua 5.1, and also implements
some features of Lua 5.2, but more importantly it is blazingly fast,
often approaching the speed of C code.
( More information here: https://luajit.org )

After reading this guide, the next step is to study the example (and
non-example) modules, which are provided with this release of Sider.
Find them in the "modules" directory.



2. Module structure
~~~~~~~~~~~~~~~~~~~

If you are familiar with Lua and how modules are typically organized
then this will make full sense to you. If are you new to Lua, i would
strongly recommend reading "Programming in Lua" by Roberto Ierusalimschy.
2nd edition covers Lua 5.1, which is the version of the language used
by Sider. However, any other edition of the book will be just as helpful.

In any case, the module organization is pretty simple:

a) Your need to create a new table
b) Provide an "init" function in that table, where you need to
do any initialization logic for the module and register for the events
your module is interested in.
c) Return that table as the last statement

Example module:

-----------------------------
local m = {}

function m.init(ctx)
    log("Hello, world!")
end

return m
-----------------------------


As you have already guessed, this module doesn't really do much. But it
is a valid module, and can be loaded by Sider. For that you need to save
it as <something>.lua file in the "modules" folder, inside sider. Let's
assume that you named it: test.lua. Then, you must also enable it in
sider.ini, like this:

lua.module = "test.lua"

**************************************************************************
**************************************************************************
VERY IMPORTANT: File encoding must be UTF-8. This is vital, if you are
using non-latin characters in the strings in the module code - for example,
in paths. If you only have latin-1 chars, then ANSI is ok too.
**************************************************************************
**************************************************************************

If you now run the game, your module will get loaded by Sider, and then
the "init" function will be called, so you should see a "Hello, world!"
message in sider.log.

If you made a mistake and your module has a syntax error, for example,
or some other problem, then you should see an error message in sider.log,
explaining where (on which line of the script) the problem occurred.

Let's now see how you can make a more useful module. First step for that
is to understand the context object (ctx).



3. Context object
~~~~~~~~~~~~~~~~~

Context object is what Sider "knows" about the current state
of the game. As more scripts/modules are created by the community
the context object will probably also change, and include more and more
information about the game.

As of 3.5.1 release, this is what the context object has:

ctx.home_team  - id of the home team of the current match, after
                 it is selected in the exhibition match, or the next
                 match is determined in the league mode.

ctx.away_team  - id of the away team of the current match, after
                 it is selected in the exhibition match, or the next
                 match is determined in the league mode.

ctx.tournament_id  -  numeric id of the current tournament. See
                      tournaments.txt file for the list ids for some
                      of the tournaments.

ctx.match_id   - some sort of number, which seems to indicate where
                 in the season you currently are. However, the exact
                 meaning of this id is unclear. Maybe you can figure
                 it out and tell me ;-)

ctx.match_leg  - set to 1 or 2, if this is 1st leg or 2nd leg of
                 a two-legged knock-out match.

ctx.match_info - meaning of this field varies, depending on the type
                 of tournament:
                     league: number of league matches already played
                     cup/play-off:
                         51 - quaterfinal,
                         52 - semifinal,
                         53 - final
                 You can use this together with ctx.tournament_id to
                 identify a final match of a particular tournament.

ctx.stadium    - numeric id of the stadium that will be used (or was
                 last used, if the stadium for the next match hasn't
                 been chosen yet by the game logic)

ctx.stadium_choice - This field is set when the game is in one of the
                     exhibition modes, and the stadium is allowed to
                     be selected via the menu. Once the actual final
                     selection of the stadium is made (right after the
                     "set_stadium" event fires), the "stadium_choice"
                     field get removed from the context.
                     Special values:
                          253 - home stadium,
                          254 - random stadium.

ctx.timeofday  - The values are: 0 - Day, 1 - Night. Same as with
                 stadium, it represents the time of day of the coming
                 match, or the last one, if the stadium isn't set yet
                 for the next match.

ctx.season     - The values are: 0 - Summer, 1 - Winter.

ctx.weather    - The values are: 0 - Fine, 1 - Rainy

ctx.weather_effects - The known values are: 
                        2 - enforce weather effects (rain falling)

ctx.match_time - Duration of the match in minutes.

ctx.is_edit_mode  -  The field gets set to true, when the game enters
                     the Edit mode. When the player returns back to
                     main menu, the field is set to nil

ctx.is_replay_gallery - This flag gets set to true, when the user enters
                        the Replay Gallery. When the players returns back
                        to main menu, the field is set to nil

ctx.replay_tournament_type - While showing replays from Replay Gallery,
                             this field contains an id, which identifies
                             the game mode that the replay was recorded in.

     NOTE that this is different from tournament_id.
     You will need to experiment to see the full set
     of values that this field can take.
     Some examples are:
        8 - Exhibition
        10 - Cup
        15 - UEFA Champions League
        16 - UEFA Europa League
        18 - League
        21 - UEFA Champions League Exhibition
        22 - UEFA Europa League Exhbition


The context is a simple Lua table, so you can change the values as you
wish. However, doing so does not really make much sense, because it will
not affect the game in any way. To actually meaningfully modify these
settings, you will need to register for game events, which are described
further down, and then have your handler functions return appropriate
values.

The context object also contains a register function, which has the
following signature:

ctx.register(event_name, handler_function)

The event_name parameter is a string, which identifies a particular
event. The handler_function should be a function in your Lua module,
which will be called when the corresponding event happens. Parameters
vary depending on the event - see the next section for details on all
supported events and their handler signatures

The idea of the context object is that in your handler functions, your
code will make decisions on what to do, using the information in the
context.



4. Supported events
~~~~~~~~~~~~~~~~~~~


- Event name: "livecpk_make_key"
Handler function: f(ctx, filename)
Return value is expected to be a string or nil.

This event occurs when the game needs to find out some information
about the file, specified by relative filename. Maybe the game needs
to create a buffer, or it needs to determine the filesize, or something
else. Your handler function is expected to return a string key that
will be used for caching of "livecpk_get_filepath". You can just
return filename as the key, without any changes, or return nil -
which will result in the same outcome. But sometimes, you need to make
a different key, because the context has some additional information
that is important. A good example is the trophy-server module (trophy.lua):
it returns a key that has tournament id in it, which allows
it to later load some files for tournament A and other files for
tournament B.

IMPORTANT: This event can fire a lot of times for a given filename,
so try to avoid doing expensive computations in the handler function,
because it may affect your frame rate.


- Event name: "livecpk_get_filepath"
Handler function: f(ctx, filename, key)
Return value is expected to be a string or nil.

This event is related to "livecpk_make_key".
It works like this: after the key is returned by livecpk_make_key
handler, sider needs to know which actual file (absolute path) needs
to be loaded for this key. So your handler function is expected to
return a full absolute filename. Sider will cache this absolute filename
using the key returned by livecpk_make_key, and the next time this file
is needed, the livecpk_get_filepath event will NOT fire. (This is
again done for performance reasons so that we don't unnecessarily seek
the disk). See trophy.lua for an example usage of this event.


- Event name: "livecpk_rewrite"
Handler function: f(ctx, filename)
Return value is expected to be a string or nil.

Allows the filename to be rewritten to another. This is a very
powerful, but also quite dangerous function, if you are not careful.
If you rewrite the filename to something that does not exist in
LiveCPK roots or in download/data CPKs, then the game will be unable
to load the file, which can lead to different behaviours, depending
on type of file being loaded. If it's a DDS texture, then usually
nothing bad happens - you just get a white texture. But if it is
some sort of model file - you will get an endless loop, where
loading indicator will keep spinning forever, or the game can just
crash. So, be careful, and don't rewrite blindly ;-)

See "kpr2nd.lua" module for an example of rewrite usage: it is
another example of trying to load GK 2nd kit for an away team
goalkeeper. You will find out that its behaviour is slightly
different from the "keeper2nd.lua" module.


- Event name: "tournament_check_for_trophy"
Handler function: f(ctx, tournament_id)
Return value is expected to be a number.

This event occurs when the game checks the tournament id in order
to decide which entrance scene to use or which trophy celebration
to show at the end of the match. It is a very specific event and
probably is not of much use, other than for the trophy-server module.


- Event name: "set_home_team"
Handler function: f(ctx, team_id)
Return value expected: nil

This event fires after the home team is determined - either during
the team selection in exhibition game, or when the next match becomes
known in a league or a cup mode (League, Master League, UCL, etc.)
The team id is also set as "home_team" field in the context object
so that it can be used later, if needed.


- Event name: "set_away_team"
Handler function: f(ctx, team_id)
Return value expected: nil

This event fires after the away team is determined - either during
the team selection in exhibition game, or when the next match becomes
known in a league or a cup mode (League, Master League, UCL, etc.)
The team id is also set as "away_team" field in the context object
so that it can be used later, if needed.


- Event name: "set_match_time"
Handler function: f(ctx, minutes)
Return value expected: nil or integer

This event occurs, when the game sets the mach duration. If your handler
function returns an integer, then this value will be used as the match
time in minutes. This way you can accelerate or slow down the matches
beyound the allowed 5-30 minute range. See timeaccel.lua - for an example
of such script.


- Event name: "set_tournament_id"
Handler function: f(ctx, tournament_id)
Return value expected: nil

This event occurs, when the tournament id is determined. Your module
cannot change this value.


- Event name: "set_stadium_choice"
Handler function: f(ctx, stadium_id, initial)
Return value expected: nil

This is a notification-type event that fires in two situations:
1) when the game is about to present the pre-game menu, where the
stadium selection enabled. In this case, the "stadium_id" will be
the previously chosen stadium, and the "initial" flag will be true.
2) If the user enters the stadium selection menu, then when they
exit it, this event will fire again, with updated choice of
stadium, and the "initial" flag will be false this time.

In addition to the actual id of the stadium chosen, the "stadium_id"
parameter may have the following special values:
    253 : "home stadium"
    254 : "random stadium"

NOTE: the final stadium selection isn't actually made, until after the
"set_stadium" event. So, if you want to change stadium, or see what
was chosen as random/home stadium, then you will need to also register
for the "set_stadium" event.


- Event name: "set_stadium"
Handler function: f(ctx, options)
Return value expected: nil or number or table

This event fires, when the stadium settings are chosen for the upcoming
match. The "options" parameter is a Lua table which contains the following
keys: "stadium", "timeofday", "weather", "weather_effects", "season".
Each of these has an integer value, as the game uses:
for stadium - it is the id of the stadium,
for timeofday: 0 - means Day, 1 - means Night;
for weather: 0 - Fine (sunny), 1 - Rain;
for weather_effects: 2 - means enforce rain falling, other values - unknown
for season: 0 - Summer, 1 - Winter

You handler function can either return nil, which means that other modules
can receive the event and process it. Or, the handler can return an stadium
id - an integer - to switch the stadium to another one. Be careful though:
sider doesn't check for correctness of values, so if you switch to a
non-existent stadium, the game will probably crash or go into infinite
"loading" loop. For an example usage - see stadium.lua module.

( For backwards compatibility, returning a table like this:
{ stadium = <stadium-id> } is also supported. However, any other keys in
that table will be ignored. )

To change weather, timeofday and season - use a new event, called:
"set_conditions", which is documented further down in this document.


- Event name: "set_conditions"
Handler function: f(ctx, options)
Return value expected: nil or table

This event fires, when the stadium settings are chosen for the upcoming
match. The "options" parameter is a Lua table which contains the following
keys: "stadium", "timeofday", "weather", "weather_effects", "season".
Each of these has an integer value, as the game uses:
for stadium - it is the id of the stadium,
for timeofday: 0 - means Day, 1 - means Night;
for weather: 0 - Fine (sunny), 1 - Rain;
for weather_effects: 2 - means enforce rain falling, other values - unknown
for season: 0 - Summer, 1 - Winter

You handler function can either return nil, which means that other modules
can receive the event and process it. Or, the handler can return a table
of options, which are either modified or not. Returning a table of options
stops further propagation of the event. You cannot change the stadium id -
for that use "set_stadium" event. But you can change any of the other
three settings: just assign them different values.
For an example usage - see stadium.lua module.


- Event name: "after_set_conditions"
Handler function: f(ctx)
Return value expected: nil

This event fires after "set_conditions". It doesn't allow the handler
to change anything, but it does provide the context object so that the
modules can react in whatever way they want.


- Event name: "set_stadium_for_replay"
Handler function: f(ctx, options)
Return value expected: nil or number or table

This event fires before the stadium is loaded for replay watching.
Same behaviour as with "set_stadium" event. If you return a stadium id
or a table with "stadium" key, then this stadium will be used for replay
instead of the one saved in the replay file.


- Event name: "set_conditions_for_replay"
Handler function: f(ctx, options)
Return value expected: nil or table

This event fires before the stadium is loaded for replay watching, but
right after "set_stadium_for_replay". Same behaviour as with "set_conditions"
event. If you return a table with values, then you can modify the weather,
season, and timeofday of the replay. Return nil, if you don't want to
modify any of those.


- Event name: "after_set_conditions"
Handler function: f(ctx)
Return value expected: nil

This event fires after "set_conditions_for_replay". It doesn't
allow the handler to change anything, but it does provide the context
object so that the modules can react in whatever way they want.


-- Event name: "get_ball_name"
Handler function: f(ctx, ballname)
Return value expected: nil or string

This event fires, when the game prepares to display the ball name.
Your handler function can change it, if it returns a string instead of nil.
The string needs to be in UTF-8 encoding to correctly render non-ASCII
characters.


-- Event name: "get_stadium_name"
Handler function: f(ctx, stadium_name, stadium_id)
Return value expected: nil or string

This event fires, when the game prepares to display the stadium name.
You handler function can change it, if it returns a string instead of nil.
The string needs to be in UTF-8 encoding to correctly render non-ASCII
characters.

NOTE: If the stadium was switched earlier to a stadium id that the
game does not know about (for example, by stadium-server module, which
serves files from its own root), then stadium_name will be an empty
string and stadium_id will be 0. However, it is still ok to return a
new name in this scenario, and the new name will be used for display.


-- Event name: "enter_edit_mode"
Handler function: f(ctx)
Return value expected: nil

This event fires when user enters the game's Edit Mode. There is also
a boolean field in the context object that is set to true: "is_edit_mode".


-- Event name: "exit_edit_mode"
Handler function: f(ctx)
Return value expected: nil

This event fires when user exits the game's Edit Mode. The boolean
field "is_edit_mode" is removed from the context (set to nil).


-- Event name: "enter_replay_gallery"
Handler function: f(ctx)
Return value expected: nil

This event fires when user enters the game's Replay Gallery. There is also
a boolean field in the context that is set to true: "is_replay_gallery".


-- Event name: "exit_replay_gallery"
Handler function: f(ctx)
Return value expected: nil

This event fires when user exits the game's Replay Gallery. The boolean
field "is_replay_gallery" is removed from the context (set to nil).


NOTE: Some events can fire multiple times for the same "action".
That is normal, it's just how the game works internally. Typically, you
do not need to worry about it, but just be aware of this fact, when
writing your handler functions.



5. Logging
~~~~~~~~~~

Sider provides a function called "log". This can be used to print
out any information you want into the sider.log file.
You can use string.format to format your message in a way similar
to what you would do with C printf:

log(string.format("My value is: %0.5f", math.pi))

In sider.log it will appear with a module name prefix, like as:

[<modulename>.lua] My value is: 3.14159



6. Module environment
~~~~~~~~~~~~~~~~~~~~~

Each module runs in its own environment. For detailed explanation
on what an environment is - read about Lua environments in the Lua
manual online, or in Programming in Lua book. What is important
here is that a module has access to a limited set of globals:

Standard Lua:
    assert, ipairs, pairs, tostring, tonumber, table,
    string, math, unpack, type, error, io, os, _VERSION, _G
Sider:
    log, memory, gameplay, gfx, _FILE

You can also enable "ffi" and "bit" modules, which are LuaJIT
extensions. By default, they are disabled. To enable, modify your
sider.ini like this:

luajit.ext.enabled = 1

By the way, your module can "investigate" and find out what exactly
is available for it to use - this is not hard, and is left as an
exercise for the reader ;-) Or... you can cheat, and look at env.lua
module.



7. Memory library
~~~~~~~~~~~~~~~~~

The "memory" library provides a set of low-level functions that
may prove useful if you're doing some advanced modding.

For example, you need some game state info that is not available in
sider's context object and isn't communicated through events either.
Or you want to modify some bytes in memory, because you feel really
adventurous.


**********************************************************************
**********************************************************************
IMPORTANT WARNING: PLEASE USE THIS LIBRARY WITH CARE AND CAUTION,
AND IF AND ONLY IF YOU KNOW WHAT YOU'RE DOING. REALLY.

THESE ARE POWERFUL TOOLS, BUT THERE ARE ALSO DANGEROUS, BECAUSE
WRITING INTO A WRONG PLACE IN MEMORY CAN HAVE DISASTROUS CONSEQUENCES.
ALWAYS TRY TO HAVE A BACKUP COPY OF YOUR EDIT DATA AND SAVEGAME FILES.
**********************************************************************
**********************************************************************


memory.read(addr, n)

This function reads (n) bytes at memory address (addr).
Return value: string of n bytes at given memory address


memory.write(addr, str)

This function writes the string of bytes (str) at the address (addr).
Return value: nil


memory.search(str, start_addr, end_addr)

This function searches for the string of bytes (str), in the range
of memory addresses between start_addr and end_addr.
Return value: address, at which the string of bytes was found
              or nil, if the string was not found.


memory.pack(format, number)

This function converts a Lua number into one of the supported binary
formats (little endian). The "format" parameter is a string that should
have one of the following values:
"f"  : 32-bit float,
"d"  : 64-bit double-precision float,
"i"  : 32-bit signed integer,
"s"  : 16-bit signed integer,
"ui" : 32-bit unsigned integer,
"us" : 16-bit unsigned integer
Return value: string of bytes, representing the number in the format
specified by the "format" parameter


memory.unpack(format, str)

This function converts a string of bytes (str) into a Lua number, using
the format parameter to interpret the binary spec. The same values are
supported for "format" param as in memory.pack function.
Return value: a Lua number, converted from binary representation

These last two functions (memory.pack/memory.unpack) are useful, when
used together with memory.read and memory.write, when you need to read
and modify values in RAM and you know what binary formats are used for
those values. See modules/packunpack.lua - as the example module that
demonstrates the usage.



8. Gameplay library
~~~~~~~~~~~~~~~~~~~

While it is possible (and not hard) to make gameplay edits by just using
the "memory" library, several specific gameplay properties have been
organized into an easy-to-use library called "gameplay".

In your Lua modules, you can change gameplay by simply reading and
assigning values to the following keys of gameplay library:


gameplay.ball_weight

Default value: 1000.0
Smaller values make the ball heavier, larger - lighter.


gameplay.ball_physics

Default value: 0.4
Well, to be absolutely honest, i haven't tried changing this much,
and i don't know exactly what part of ball physics is affected. But
since Nesa found it, it's included.


gameplay.ball_bounce

Default value: 1.0
Changing this will change the way the ball bounces. And some other
stuff too... you'll see.


gameplay.ball_friction

Default value: -0.5
Affects the way the ball is slowed down by friction: either in the air
or on the ground. Negative values smaller than -0.5 make the ball stop
quicker. Positive values actually make the ball accelerate as it moves,
which is fun, but totally unrealistic.


gameplay.ball_magnus

Default value: 0.1086859330534935
"Magnus effect" for the ball: sideways movement in the air, due to
rotation. This also seems to have effect when the ball is passed on
the ground.


gameplay.ball_scale_x
gameplay.ball_scale_y
gameplay.ball_scale_z

Default values: 1.0, 1.0, 1.0
Scaling matrix for the ball. Normal size is all three values set to 1.0.
You can make the ball smaller/larger by setting all three settings to
the same value: <1 - smaller, >1 - larger ball. Setting one parameter
to a different value from the other two gives a rugby-type ball.


gameplay.shooting_power

Default value: 0.85
Smaller values - less shot power, larger values - more power.


gameplay.speed

Default value: 0.2
Affects the speed of players. Even small changes are quite noticeable.
However, i have seen some strange artifacts: like players unable to
trap a simple pass, as the ball approaches them. So, i dunno...
maybe we need a better understanding of what this does exactly.


gameplay.speed_global

Default value: 5.0
It appears that "speed" and "speed_global" are used together. The game
apparently multiplies them at some point, and yet they each have their
own purpose too, because even though 0.2*5 = 0.02*50, these two
scenarios do not result in the same gameplay.


**********************************************************************
IMPORTANT WARNING: ALL THESE GAMEPLAY CONTROLS ARE EXPERIMENTAL AND
CONSTITUE OUR GUESSES AT HOW THE GAME WORKS. AS YOU WILL SEE, SOME
OF THEM HAVE WEIRD SIDE-EFFECTS. SOME OF THE VALUES ARE VERY
SENSITIVE TO CHANGES. ANYWAYS, HAVE FUN!
**********************************************************************


See modules/gameplay.lua - for the simplest example of how gameplay library
can be used. The modules/gameplay2.lua - is a slightly more advanced
example, but not much more complicated: it uses an ini-file, which is
read every time a new set of teams in selected. This allows you to modify
the gameplay for each new match, without exiting the game (if you change
the values in gameplay.ini)



9. Graphics Effects ("gfx") library
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Some subtle and not so subtle visual effects are possible with this
new library:


gfx.brightness

Default value: 1.0
Brightness of the full screen


gfx.sharpness

Default value: 0.166
Sharpness of the picture during gameplay


gfx.shadow_softness

Default value: 0.5
This parameter appears to affect the softness/hardness of shadows that
players cast onto themselves. Try experimenting with the values.


gfx.reflection

Default value: 1.0
Specifies how reflective/shiny the players are. Negative values seem
to provide more refection. (Try setting it to -10000.
A side-effect of this: disappearance of spectators from the stadium.)


See modules/gfx.lua - for a simple example of how gfx library
can be used: every time a set of teams is selected for a match or time
is advanced to next match in league/cup modes, a gfx.ini file is read,
and graphics effects settings are applied.

