Scripting for dummies Eng-Ru

If you are programmer and read IdolNinja's article "How to run a custom SRIV gameplay script", maybe you got more that enough information how to create new cool scripts.
But if you're just a dummy like me, maybe you only understand how to activate the dynamic time of day after the end of the story missions. So I write this article for you

Warning: I studied only turbo basic in school and my knowledge of English is lame, the knowledge of the scripting is obtained by studying the code of other mods

To begin with, we need
Notepad++ with setting Language - Lua
fully unpacked game for examples (recommended)
Full list of functions for Saints row the third

Why for the third? Because unfortunately Volition did not provide the same list for the 4th . The most functions work, some require different arguments, some do not work at all.

NOTE: in Saints row 4 argument "#PLAYER1#" was changed to LOCAL_PLAYER, and "#PLAYER2#" to REMOTE_PLAYER

Saints row IV is using a simple scripting language for programming named LUA, the language is not difficult for beginners and it can be learned even on the official site https://www.lua.org/ but with utilizing the gained knowledge for creating mods there can be some problems.

The minimum set of knowledge for modding SR4

NOTE: better read article on wiki or somewhere else than my stupid explanation

Variable
It's a cell, a memory area with some name where you can write and read information, the information that is written into it is divided into types
  • number, yeah simple number
    Code:
    my_number_varible = 777
  • string with a text, the text is quoted
    Code:
    my_string_variable ="This is my string variable"
  • and a Boolean variable, it can have only two values true or false
    Code:
    my_boolean_variable = true
variables can be global or local. We don't want your variable to affect some code outside your script so always write local before creating a variable local my_variable = "is right"
Function
it's a piece of code that can be repeatedly called, the function always starts with the word function, then the name of the function comes, which can also be anything after the name there are parentheses ()inside we write some arguments that the function is accepts if there are none leave the field blank. Ends the function with the word end. Between the parentheses and end, you can enter any code, for example:

Code:
function gameplay_dynamic_tod_init()
   dynamic_tod_enable(true)
end
dynamic_tod_enable(true) -call the built-in SR4 function with argument (true)
Statement
These words and constructions built into the programming language that perform certain tasks, there are relatively few of them and we will use only a couple
  • if then else
    This is a switch if after an if condition we put some check and result of this checking will be true code after then will be executed if not the code will be executed after else
    Code:
    if 1>0 then
        print("Ok")
    else
        print("mathematic is wrong")
    end
    If you want to check several conditions after the first if you need to put ifelse
    Code:
         local my_variable =777
         if my_variable == 0 then
          print("zero")
        elseif op == 2 then
          print("not so much")
        elseif op == 3 then
          print("so so")
        elseif op == 4 then
          print ("enough")
        else
          print("you typing something wrong")
        end
    print - this is a function that display a value to the console, in SR4 it does not work
    else and code after it is optional
  • while
    if we need to execute some code repeatedly before reaching some condition, then we need a loop. After while we set the condition, if it is true then the code after do will be executed
    Code:
    local i = 1
        while a[i] do
          print(a[i])
          i = i + 1
      end
    if the conditions are set to an unchanged and true value that we get an infinite cycle
    Code:
    while true do
       print("infinity")
    end
  • logical operators not or and
    OPERATORLER_clip_image002_0000.jpg
    see here
Thread
it's easiest to imagine it as a place in the queue, the processor processes each operation in turn and for the constant execution of some code you need your place with the name

CREATION OF GAMEPLAY SCRIPT

STEP 1:
Create thread variable
Code:
local My_Thread_Handle = INVALID_THREAD_HANDLE
My_Thread_Handle - this is variable
INVALID_THREAD_HANDLE - this is some null value for the thread variable that set type of the variable to thread (my guess)

STEP 2:
Create function that will start thread when gameplay script will be running
Code:
function gameplay_my_code_init()
    My_Thread_Handle = thread_new("my_thread_manager")
end
function gameplay_my_code_init() - function with the prefix gameplay and suffix init, it will be runing by the game
My_Thread_Handle = thread_new("my_thread_manager") - assign new thread to the thread variable, that thread will be run the function my_thread_manager

STEP 3:

Create function my_thread_manager, it
Code:
function my_thread_manager()
    while true do
        function_with_my_code()
        delay(1)
    end
end
Now the script will endlessly execute function_with_my_code () where we will write some check and code, which will be executed.
delay(1) - function which sets a pause between each cycle (in seconds), without delay, even the simplest cycle can freeze the game

STEP 4:
Create function function_with_my_code() You can put there any code, but for us the main thing is to create a switch that performs some gameplay function from the list but for testing purposes we display some message, and set our check to true
Code:
function function_with_my_code()
  if true then
   mission_help_table("hello world", LOCAL_PLAYER)
  end
end
function mission_help_table displays a text message on the left on the screen, the first argument is the message text LOCAL_PLAYER - to whom this message will be displayed LOCAL_PLAYER is the host.

If this code
Code:
local My_Thread_Handle = INVALID_THREAD_HANDLE

function function_with_my_code()
  if true then
   mission_help_table("hello world", LOCAL_PLAYER)
  end
end

function gameplay_my_code_init()
    My_Thread_Handle = thread_new("my_thread_manager")
end

function my_thread_manager()
    while true do
        function_with_my_code()
        delay(1)
    end
end
save to lua format and pack it with saints row workshop upload tool then we get some result

NOTE: the name of LUA file must match the name of gameplay init function,for example: function gameplay_my_code_init() - gameplay_my_code.lua

0x15Sbi.jpg
Every second (probably) the message "Hello World" will be displayed but it's useless, right? Here we need to add some sort of checking of some condition the trigger which will launch our messages.

And here we come to the most sad part unfortunately the checking functions for some action in the SR4 are quite limited, for example we can not assign actions to firing from a specific weapon or simply create an invisible area button (but you can move an existing one) and it seems to me that creating your own menu also will not work.

IdolNinja created complex key combinations, Flow754 checked the music on the radio, FanofSaints checked the speed of the car. I basically check if a certain weapon is equipped.

To do this, we need the function inv_item_is_equipped Let's make a check if any weapon is equipped, for example dubstep gun, code with our message will be running. For doing this we need to find out the name of this weapon in the game you will find it in misc_tables.vpp_pc / weapons.xtbl. The name of this weapon in the game files is Special-Dubstep. Now our code looks like this
Code:
local My_Thread_Handle = INVALID_THREAD_HANDLE

function function_with_my_code()
  if inv_item_is_equipped("Special-Dubstep", LOCAL_PLAYER) then
   mission_help_table("hello world", LOCAL_PLAYER)
  end
end

function gameplay_my_code_init()
    My_Thread_Handle = thread_new("my_thread_manager")
end

function my_thread_manager()
    while true do
        function_with_my_code()
        delay(1)
    end
end
The message Hello World will be displayed only if the dubstep gun is equipped. But this is also boring, this is just a message, let's make the player dance for this we need the action_play function. Do not panic we only need two arguments
Code:
action_play(LOCAL_PLAYER,"Dance")
LOCAL_PLAYER - The character to which the animation will be apply
"Dance" - The name of the animation, taken from misc_tables.vpp_pc/anim_states.xtbl
Code:
local My_Thread_Handle = INVALID_THREAD_HANDLE

function function_with_my_code()
  if inv_item_is_equipped("Special-Dubstep", LOCAL_PLAYER) then
    action_play(LOCAL_PLAYER, "Dance")
  end
end

function gameplay_my_code_init()
    My_Thread_Handle = thread_new("my_thread_manager")
end

function my_thread_manager()
    while true do
        function_with_my_code()
        delay(1)
    end
end
Sw3SQV6.gif
Now everything is fine, but the animation is played uninterruptedly, we need to fix it, for this we need to add one more check and variable
Code:
local My_Thread_Handle = INVALID_THREAD_HANDLE
local Is_Dubstep_Gun_Equiped = false

function function_with_my_code()
  if inv_item_is_equipped("Special-Dubstep", LOCAL_PLAYER) and Is_Dubstep_Gun_Equiped == false then
   action_play(LOCAL_PLAYER,"Dance")
   Is_Dubstep_Gun_Equiped = true
  elseif not inv_item_is_equipped("Special-Dubstep", LOCAL_PLAYER) and Is_Dubstep_Gun_Equiped == true then
   Is_Dubstep_Gun_Equiped = false
  end
end

function gameplay_my_code_init()
    My_Thread_Handle = thread_new("my_thread_manager")
end

function my_thread_manager()
    while true do
        function_with_my_code()
        delay(1)
    end
end
local Is_Dubstep_Gun_Equiped = false -A new Boolean variable that will be responsible for switching

and Is_Dubstep_Gun_Equiped == false
- An additional check, whether the variable is equal to false, if equal, we run the function that will play the animation.

Is_Dubstep_Gun_Equiped = true - After playing the animation, we change the value of the variable, now the animation will not start until the dubstep gun is equipped

elseif not inv_item_is_equipped("Special-Dubstep", LOCAL_PLAYER)
- If dubstep gun is not equipped

and Is_Dubstep_Gun_Equiped == true And was already equipped

Is_Dubstep_Gun_Equiped = false change the value of the variable, now the function with the animation will start if the dubstep gun is equipped

That all, you managed to create a gameplay script, the further result depends only on your experiments and LUA knowledge. In notepad ++ there is a search function for files with filter extensions, I recommend you check each function from the list to check Ctr + Shift + F on all lua files of the game[/SPOILER]
Если вы программист и прочитали статью IdolNinja "How to run a custom SRIV gameplay script", наверно, вы поняли все. Если же вы простой чайник как и я, то поняли только как активировать смену погоды после окончания сюжетных миссий. Вот именно для вас я и пишу эту статью.

Для начала нам понадобится
Notepad++ с настройкой Синтаксис - Lua
Желательно, полностью распакованная игра (для примеров)
Список функций для Saints row the third.

Почему для него? Потому, что к сожалению Volition не предоставили такой же для 4й части. Большинство функций работает, для некоторых нужны другие аргументы, некоторые не работают вовсе.

ВАЖНО: в Saints row 4 аргумент "#PLAYER1#" заменен на LOCAL_PLAYER, а "#PLAYER2#" на REMOTE_PLAYER

Saints row IV использует простой скриптовый язык программирования LUA, он не сложен для новичков и обучится ему можно даже на официальном сайте https://www.lua.org/ но вот с применением полученных знаний для модов могут возникнуть проблемы.

Минимальный набор знаний для моддинга SR4

Переменная
это ячейка, область памяти с именем куда можно записать и считать информацию, название переменной может быть любым, а вот информация, что в нее записывается делится на типы
  • число, да просто число
    Code:
    my_number_varible = 777
  • строка с текстом, текст выделяется в кавычки
    Code:
    my_string_variable ="This is my string variable"
  • ну и бульевая переменная, может иметь только два значения true или false
    Code:
    my_boolean_variable = true
Функция
это некий кусок кода, что можно многократно вызывать, начинается функция всегда со слова function, затем идет имя функции, что так же может быть любым, после имени идут скобки (), в них запизывают некие переменные, что функция принимает, если таковых нет, оставляем поле пустым. Заканчивается функция словом end. Между скобками и end можно вписать любой код, например

Code:
function gameplay_dynamic_tod_init()
   dynamic_tod_enable(true)
end
dynamic_tod_enable(true) - вызов встроенной в SR4 функции с параметром (true)
Оператор
это встроенные в язык программирования слова и конструкции, что выполняют определенные задачи, их относительно немного и мы будем использовать всего пару
  • if then else
    конструкция, что является переключателем , если после if поставить некое условие, то если оно соблюдается код после then будет выполнен, если же нет, то будет выполнен код после else
    Code:
    if 1>0 then
        print("Ok")
    else
        print("mathematic is wrong")
    end
    если нужно проверить несколько условий после первого if нужно ставить ifelse
    Code:
         local my_variable =777
         if my_variable == 0 then
          print("zero")
        elseif op == 2 then
          print("not so much")
        elseif op == 3 then
          print("so so")
        elseif op == 4 then
          print ("enough")
        else
          print("you typing something wrong")
        end
    print - это функция что выводит значение в консоль, в SR4 не работает
    писать else и код после него не обязательно
  • while
    если нужно выполнять какой-то код многократно, до соблюдение некоего условия то нам понадобится цикл. После while мы ставим условие, если оно соблюдено, то код после do будет исполнятся
    Code:
    local i = 1
        while a[i] do
          print(a[i])
          i = i + 1
      end
    если в условия поставить неизменное и правдивое значение, что мы получим бесконечный цикл

    Code:
    while true do
       print("infinity")
    end
  • Логические операторы not or and
Тред(поток)
легче всего представить себе его как место в очереди, процессор обрабатывает каждую операцию по очереди и для постоянного выполнение некоего кода нужно свое место с именем

Код в примере IdolNinja к сожалению плохо подходит для примера, потому, что он выполняет код лишь раз и только в начале игры, геймлей же состоит из множества кнопок, нажимая которые мир меняется. Для создания гейплейного скрипта нам подобится поток и цикл, что будет выполнятся в этом потоке

СОЗДАНИЕ ГЕМПЛЕЙНОГО СКРИПТА

STEP 1:
Создаем переменную потока
Code:
local My_Thread_Handle = INVALID_THREAD_HANDLE
My_Thread_Handle - это переменная
INVALID_THREAD_HANDLE - пустое значение для переменной отвечающей за поток

STEP 2:
Создаем функцию, что запустит поток при старте скрипта
Code:
function gameplay_my_code_init()
    My_Thread_Handle = thread_new("my_thread_manager")
end
function gameplay_my_code_init() - функция с префиксом gameplay и суффиксом init, ее запустит игра
My_Thread_Handle = thread_new("my_thread_manager") - присваиваем переменной потока, поток, что запустит функцию my_thread_manager

STEP 3:

Создаем функцию my_thread_manager, она состоит из бесконечного цикла
Code:
function selfie_cam_thread_manager()
    while true do
        function_with_my_code()
        delay(1)
    end
end
Теперь скрипт будет бесконечно выполнять function_with_my_code(), куда мы и запишем проверку и код, что будет выполнятся.
delay(1) - функция, что задает паузу между каждым циклом(в секундах), без задержки даже самый простой цикл может привести к торможению в игре

STEP 4:
Создаем функцию function_with_my_code() код в ней может быть совершенно любой, но для нас главное создать переключатель выполняющий какую либо геймплейную функцию из списка, например, для начала выведем на экран сообщения
Code:
function function_with_my_code()
  if true then
   mission_help_table("hello world", LOCAL_PLAYER)
  end
end
функция mission_help_table выводит текстовое сообщение слева на экране, первый аргумент - это текст сообщения, LOCAL_PLAYER - кому это сообщение будет выведено, LOCAL_PLAYER - это хост.

Если код
Code:
local My_Thread_Handle = INVALID_THREAD_HANDLE

function function_with_my_code()
  if 1>0 then
   mission_help_table("hello world", LOCAL_PLAYER)
  end
end

function gameplay_my_code_init()
    My_Thread_Handle = thread_new("my_thread_manager")
end

function my_thread_manager()
    while true do
        function_with_my_code()
        delay(1)
    end
end
сохранить в формате lua и запаковать saints row workshop upload tool то мы получим такой результат

ВАЖНО: имя LUA файла должно совпадать с именем gameplay init функции, например: function gameplay_my_code_init() - gameplay_my_code.lua

0x15Sbi.jpg
Каждую секунду(наверное) будет бесприрывно выводится сообщение "Hello World", но это же бесполезно, верно? Сюда нужно добавить некую проверку какого либо условия, триггер, что запустит наше сообщения.

И вот здесь мы подходим к самому грустному, к сожалению, функции проверки чего-то у SR4 довольно ограничены, например мы не можем назначить действия на стрельбу из определенного оружия, или просто создать невидимую кнопку(но можно передвинуть существующую) и мне кажется, что создать собственное меню тоже не получится.

IdolNinja создавал сложные комбинации клавиш, Flow754 проверял музыку на радио, Fan of Saints проверял скорость автомобиля. Я же в основном проверяю экипировано ли определенное оружие.

Для этого нужна функция inv_item_is_equipped Сделаем проверку, экипировано ли какое-то оружие, например дабстеп ган, для этого нам нужно узнать имя этого оружия в игре, вы найдете его в misc_tables.vpp_pc/weapon_costumes.xtbl. Имя этого оружия в файлах игры - Special-Dubstep. Теперь наш код выглядит так
Code:
local My_Thread_Handle = INVALID_THREAD_HANDLE

function function_with_my_code()
  if inv_item_is_equipped("Special-Dubstep", LOCAL_PLAYER) then
   mission_help_table("hello world", LOCAL_PLAYER)
  end
end

function gameplay_my_code_init()
    My_Thread_Handle = thread_new("my_thread_manager")
end

function my_thread_manager()
    while true do
        function_with_my_code()
        delay(1)
    end
end
Сообщение Hello World выводится только если дабстеп ган экипирован. Но это тоже скучно, это же всего лишь сообщение, давайте заставим игрока танцевать, для проигрывания, нам нужна функция action_play. Не паникуйте, нам нужны только два аргумента
Code:
action_play(LOCAL_PLAYER,"Dance")
LOCAL_PLAYER - персонаж к которому будет применима анимация
"Dance" - название анимации, взято из misc_tables.vpp_pc/anim_states.xtbl
Code:
local My_Thread_Handle = INVALID_THREAD_HANDLE

function function_with_my_code()
  if inv_item_is_equipped("Special-Dubstep", LOCAL_PLAYER) then
    action_play(LOCAL_PLAYER, "Dance")
  end
end

function gameplay_my_code_init()
    My_Thread_Handle = thread_new("my_thread_manager")
end

function my_thread_manager()
    while true do
        function_with_my_code()
        delay(1)
    end
end
Sw3SQV6.gif
Теперь все хорошо, но анимация проигрывается бесприрывно, надо бы это исправить, для этого нам надо ввести еще одно условие и переменную
Code:
local My_Thread_Handle = INVALID_THREAD_HANDLE
local Is_Dubstep_Gun_Equiped = false

function function_with_my_code()
  if inv_item_is_equipped("Special-Dubstep", LOCAL_PLAYER) and Is_Dubstep_Gun_Equiped == false then
   action_play(LOCAL_PLAYER,"Dance")
   Is_Dubstep_Gun_Equiped = true
  elseif not inv_item_is_equipped("Special-Dubstep", LOCAL_PLAYER) and Is_Dubstep_Gun_Equiped == true then
   Is_Dubstep_Gun_Equiped = false
  end
end

function gameplay_my_code_init()
    My_Thread_Handle = thread_new("my_thread_manager")
end

function my_thread_manager()
    while true do
        function_with_my_code()
        delay(1)
    end
end
local Is_Dubstep_Gun_Equiped = false - новая бульевая переменная, что будет отвечать за переключение

and Is_Dubstep_Gun_Equiped == false
- дополнительная проверка, ровняется ли переменная false, если ровняется, мы запускаем функцию, что будет проигрывать анимацию.

Is_Dubstep_Gun_Equiped = true - после проигрывания анимации мы меняем значение переменной, теперь анимация не запустится, пока дабстеп ган экипирован

elseif not inv_item_is_equipped("Special-Dubstep", LOCAL_PLAYER)
- если дабстеп ган не экипирован

and Is_Dubstep_Gun_Equiped == true и уже был экипирован

Is_Dubstep_Gun_Equiped = false меняем значение переменной, теперь функция с анимацией запустится если дабстеп ган экипировать

Все, у вас получилось создать геймплейный скрипт, дальнейший результат зависит только от ваших экспериментов и познаний в LUA. В notepad++ есть функция поиска по файлах с фильтром расширений, рекомендую вам проверять каждую функцию из списка проверять Ctr+Shift+F на всех lua файлах игры
 
Last edited:
Не за что :). Thank you I really hope more people will understand scripting and become to make gameplay mods because it's fun and easy
As you mentioned in your tutorial, it would have been very helpful if Volition had provided a list of Lua functions for SR4 like they did for SR3. I know the SR3 list wasn't 100% accurate, but it was still much better than nothing. Yes, people have figured out some of it, but it's tedious work, and if Volition already has the list, why can't they just provided it to us? I think that would have helped get more people working on workshop mods.
 
Can you make the whole script page offline-able too?
What you mean? You want pdf file with the article or lua files with scripts?
As you mentioned in your tutorial, it would have been very helpful if Volition had provided a list of Lua functions for SR4 like they did for SR3. I know the SR3 list wasn't 100% accurate, but it was still much better than nothing. Yes, people have figured out some of it, but it's tedious work, and if Volition already has the list, why can't they just provided it to us? I think that would have helped get more people working on workshop mods.
Sadly but I guess Volution's leadership on some stage lost interest in modding their old titles so even so basic stuff as list of functions almost impossible to get now.:(
 
I guess you have some collision with function name or it conflict with the game or have some typo.
You mean function name gameplay init?
 
Back
Top